Wizard: reduce default control mesh to 7x5 (DELFTship philosophy)
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 <noreply@anthropic.com>
This commit is contained in:
@@ -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}")
|
||||
|
||||
Reference in New Issue
Block a user