From 588735ea64ebc536cc723a4183469b6cfdc4a48d Mon Sep 17 00:00:00 2001 From: alro1965 Date: Wed, 27 May 2026 21:08:07 -0400 Subject: [PATCH] Wizard: reduce default control mesh to 7x5 (DELFTship philosophy) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prior defaults (21 stations x 11 waterlines = 231 nodes) made it impossible to edit a hull fairly — too many degrees of freedom with no locality. DELFTship principle: start with the minimum viable mesh so each node acts as a true Bezier handle with global influence, then refine only where needed. New defaults: 7 stations x 5 waterlines = 35 nodes - 7 stations: AP + 5 intermediate + FP (clear midship at index 3) - 5 waterlines: keel + 25% + 50% + 75% + design WL - 5 points per section = cubic B-spline ≈ one Bezier handle per quadrant Range changes: - Stations: 7-81 -> 4-30 (step 1, was 2) - Waterlines: 5-31 -> 3-12 (step 1, was 2) New UI elements: - Group renamed "Malla de control (puntos Bézier)" - Italic hint explaining the fewer-is-better philosophy - Live counter "Total nodos: N (manejable / moderado / difícil)" with color feedback: green ≤50, amber ≤120, red >120 Co-Authored-By: Claude Sonnet 4.6 --- arshipdesign/ui/dialogs/wizards.py | 74 ++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 13 deletions(-) diff --git a/arshipdesign/ui/dialogs/wizards.py b/arshipdesign/ui/dialogs/wizards.py index b81dd37..310b241 100644 --- a/arshipdesign/ui/dialogs/wizards.py +++ b/arshipdesign/ui/dialogs/wizards.py @@ -468,36 +468,84 @@ class _StepRefine(QWidget): lcb_lo.addWidget(self._lcb_val_lbl, 0, Qt.AlignmentFlag.AlignHCenter) lo.addWidget(grp_lcb) - # ── Discretización ───────────────────────────────────────────── - grp_disc = QGroupBox("Discretización") + # ── Malla de control ──────────────────────────────────────────── + grp_disc = QGroupBox("Malla de control (puntos Bézier)") grp_disc.setStyleSheet(grp_cb.styleSheet()) disc_lo = QGridLayout(grp_disc) + disc_lo.setSpacing(8) - disc_lo.addWidget(QLabel("Estaciones:"), 0, 0) + # Nota filosófica: menos puntos = curvas más fáciles de afinar + hint = QLabel( + "Menos puntos → curvas naturalmente suaves y fáciles de editar.\n" + "Añade más sólo cuando necesites detalles locales." + ) + hint.setWordWrap(True) + hint.setStyleSheet(f"color:{_MUTED}; font-size:10px; font-style:italic;") + disc_lo.addWidget(hint, 0, 0, 1, 2) + + disc_lo.addWidget(QLabel("Estaciones (long.):"), 1, 0) self._n_sta = QSpinBox() - self._n_sta.setRange(7, 81) - self._n_sta.setValue(21) - self._n_sta.setSingleStep(2) + self._n_sta.setRange(4, 30) # mínimo 4 para cúbica, máximo razonable + self._n_sta.setValue(7) # 7 = como DELFTship en plantilla nueva + self._n_sta.setSingleStep(1) + self._n_sta.setToolTip( + "Número de secciones transversales del polígono de control.\n" + "7 es suficiente para la mayoría de cascos de eslora media." + ) self._n_sta.setStyleSheet( f"background:{_PANEL}; color:{_TEXT}; border:1px solid {_BORDER};" f"border-radius:4px; padding:2px 6px;" ) - disc_lo.addWidget(self._n_sta, 0, 1) + disc_lo.addWidget(self._n_sta, 1, 1) - disc_lo.addWidget(QLabel("Líneas de agua:"), 1, 0) + disc_lo.addWidget(QLabel("Líneas de agua (vert.):"), 2, 0) self._n_wl = QSpinBox() - self._n_wl.setRange(5, 31) - self._n_wl.setValue(11) - self._n_wl.setSingleStep(2) + self._n_wl.setRange(3, 12) # 3 mínimo (quilla, media, flotación) + self._n_wl.setValue(5) # 5 = quilla + 3 intermedias + flotación + self._n_wl.setSingleStep(1) + self._n_wl.setToolTip( + "Número de líneas de agua del polígono de control.\n" + "5 da una cúbica por sección con un punto a cada 25 % del calado." + ) self._n_wl.setStyleSheet(self._n_sta.styleSheet()) - disc_lo.addWidget(self._n_wl, 1, 1) + disc_lo.addWidget(self._n_wl, 2, 1) + + # Indicador en vivo del total de nodos + self._nodes_lbl = QLabel() + self._nodes_lbl.setStyleSheet(f"color:{_ACCENT}; font-size:11px; font-weight:600;") + disc_lo.addWidget(self._nodes_lbl, 3, 0, 1, 2) + self._n_sta.valueChanged.connect(self._update_nodes_lbl) + self._n_wl.valueChanged.connect(self._update_nodes_lbl) + self._update_nodes_lbl() for lbl in grp_disc.findChildren(QLabel): - lbl.setStyleSheet(f"color:{_TEXT}; font-size:11px;") + if lbl is not hint and lbl is not self._nodes_lbl: + lbl.setStyleSheet(f"color:{_TEXT}; font-size:11px;") lo.addWidget(grp_disc) lo.addStretch() + def _update_nodes_lbl(self) -> None: + n = self._n_sta.value() + wl = self._n_wl.value() + total = n * wl + # Feedback visual: color según cantidad (verde = manejable, rojo = muchos) + if total <= 50: + color = _GREEN + advice = "✓ manejable" + elif total <= 120: + color = _GOLD + advice = "⚠ moderado" + else: + color = "#d04040" + advice = "✗ difícil de afinar" + self._nodes_lbl.setText( + f"Total nodos: {total} ({advice})" + ) + self._nodes_lbl.setStyleSheet( + f"color:{color}; font-size:11px; font-weight:600;" + ) + def _cb_changed(self, val: int) -> None: cb = val / 100.0 self._cb_val_lbl.setText(f"Cb = {cb:.2f}")