Files
AR-Shipdesign/arshipdesign/parametric/__init__.py
T
alro65 002c00aff3 feat(sprint2): wizard 'Nuevo Proyecto' + 5 generadores paramétricos de casco
Generadores paramétricos (arshipdesign/parametric/):
  - wizard_planing.py    → V-fondo, chine dura, deadrise variable AP→FP
  - wizard_cruiser.py    → Carena redonda, plan form Lackenby, Cm ajustable
  - wizard_workboat.py   → Sección cajón, pantoque duro, fondo plano
  - wizard_sailing_mono.py → Velero fin keel, sección fina, LCB a popa
  - series60.py          → Serie 60 / mercante full, Cm ~ 0.96
  - __init__.py          → API unificada generate_hull(family, lpp, beam, draft)
                           + HullFamily enum con labels, rangos Cb, descripciones

Wizard UI (arshipdesign/ui/dialogs/wizards.py):
  - NewShipWizard: QDialog 4 pasos con barra de progreso animada
  - _StepDimensions:  nombre, Lpp, B, puntal, calado + ratios L/B y B/T en vivo
  - _StepFamily:      6 FamilyCard con HullThumbnail QPainter (sección maestra)
  - _StepRefine:      sliders Cb y LCB, spinboxes discretización
  - _StepPreview:     tabla hidrostáticos completa (V, D, Cb, LCB, KB, Awp...)
  - Al aceptar → Hull cargado en visor 3D del viewport Perspectiva

MainWindow:
  - _on_new_project() abre NewShipWizard (antes creaba proyecto vacío)
  - Tras accept(): carga hull en Viewer3DWidget si disponible

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-05-27 07:52:46 -04:00

170 lines
5.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
arshipdesign.parametric — Generadores paramétricos de cascos.
Exporta la función unificada ``generate_hull`` y los constantes
de familia usados por el wizard de nuevo proyecto.
Uso rápido
----------
>>> from arshipdesign.parametric import generate_hull, HullFamily
>>> hull = generate_hull(
... family=HullFamily.DISPLACEMENT,
... lpp=15.0, beam=4.0, draft=1.60, depth=2.30,
... cb=0.55,
... )
"""
from __future__ import annotations
from enum import Enum, auto
from typing import Any
from arshipdesign.core.hull import Hull
class HullFamily(str, Enum):
"""Familia de carena disponible en el wizard."""
PLANING = "planing" # Planeador — V-fondo, chine dura
DISPLACEMENT = "displacement" # Desplazamiento — carena redonda
SEMI_DISP = "semi_disp" # Semi-desplazamiento
WORKBOAT = "workboat" # Workboat / Supply / Remolcador
SAILING = "sailing" # Velero monocasco fin keel
MERCHANT = "merchant" # Buque mercante / Serie 60
@property
def label_es(self) -> str:
return {
"planing": "Planeo",
"displacement":"Desplazamiento",
"semi_disp": "Semi-desplazamiento",
"workboat": "Workboat / Supply",
"sailing": "Velero",
"merchant": "Mercante / Supply full",
}[self.value]
@property
def cb_default(self) -> float:
return {
"planing": 0.43,
"displacement":0.55,
"semi_disp": 0.50,
"workboat": 0.67,
"sailing": 0.40,
"merchant": 0.70,
}[self.value]
@property
def cb_range(self) -> tuple[float, float]:
return {
"planing": (0.38, 0.48),
"displacement":(0.45, 0.65),
"semi_disp": (0.46, 0.58),
"workboat": (0.60, 0.75),
"sailing": (0.35, 0.46),
"merchant": (0.60, 0.82),
}[self.value]
@property
def description_es(self) -> str:
return {
"planing":
"Embarcación rápida con fondo en V y chine dura.\n"
"Fn > 0.50 — lanchas, patrulleras, RIBs.",
"displacement":
"Carena redondeada de velocidad moderada.\n"
"Fn 0.200.35 — cruceros, pesqueros, ferrys.",
"semi_disp":
"Compromiso entre planeo y desplazamiento.\n"
"Fn 0.350.55 — yates de motor, patrulleras.",
"workboat":
"Sección cajón con pantoque duro.\n"
"Fn < 0.22 — remolcadores, supply, barcazas.",
"sailing":
"Cuerpo fino con quilla de aleta.\n"
"Veleros de recreo y regata.",
"merchant":
"Formas llenas tipo Serie 60.\n"
"Fn < 0.20 — carga, RORO, buques de trabajo.",
}[self.value]
# ---------------------------------------------------------------------------
# Función unificada
# ---------------------------------------------------------------------------
def generate_hull(
family: HullFamily | str,
lpp: float,
beam: float,
draft: float,
depth: float | None = None,
name: str = "",
n_stations: int = 21,
n_waterlines: int = 11,
**kwargs: Any,
) -> Hull:
"""Genera un Hull paramétrico de la familia indicada.
Parámetros
----------
family : HullFamily
Tipo de carena (ver HullFamily).
lpp : float
Eslora entre perpendiculares [m].
beam : float
Manga máxima [m].
draft : float
Calado de diseño [m].
depth : float, optional
Puntal de trazado [m]. Si es None usa draft * 1.45.
name : str
Nombre del proyecto/casco.
n_stations : int
Número de estaciones transversales (≥ 7, default 21).
n_waterlines : int
Número de líneas de agua (≥ 5, default 11).
**kwargs
Parámetros adicionales específicos de cada familia
(p.ej. deadrise_mid para planing, cb para displacement, etc.)
Retorna
-------
Hull
"""
fam = HullFamily(family) if isinstance(family, str) else family
if depth is None:
depth = draft * 1.45
if not name:
name = f"{fam.label_es} {lpp:.0f}m"
common = dict(
name=name, lpp=lpp, beam=beam, draft=draft, depth=depth,
n_stations=n_stations, n_waterlines=n_waterlines,
)
common.update(kwargs)
if fam == HullFamily.PLANING:
from arshipdesign.parametric.wizard_planing import make_planing_hull
return make_planing_hull(**common)
elif fam in (HullFamily.DISPLACEMENT, HullFamily.SEMI_DISP):
from arshipdesign.parametric.wizard_cruiser import make_displacement_hull
if fam == HullFamily.SEMI_DISP and "cb" not in kwargs:
common.setdefault("cb", 0.50)
return make_displacement_hull(**common)
elif fam == HullFamily.WORKBOAT:
from arshipdesign.parametric.wizard_workboat import make_workboat_hull
return make_workboat_hull(**common)
elif fam == HullFamily.SAILING:
from arshipdesign.parametric.wizard_sailing_mono import make_sailing_hull
return make_sailing_hull(**common)
elif fam == HullFamily.MERCHANT:
from arshipdesign.parametric.series60 import make_merchant_hull
return make_merchant_hull(**common)
else:
raise ValueError(f"Familia de carena desconocida: {fam!r}")