""" 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.20–0.35 — cruceros, pesqueros, ferrys.", "semi_disp": "Compromiso entre planeo y desplazamiento.\n" "Fn 0.35–0.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}")