Módulo 1: visores 2D del plano de líneas + hidrostáticos en vivo
- viewer_lines.py: BodyPlanViewer, ProfileViewer, PlanViewer (QPainter, zoom/paneo, tema dark navy); conectados a los tres viewports 2D del layout 4-viewport (bodyplan / profile / plan). - hull.py: añadidos waterplane_coefficient (Cw), it_waterplane (IT), il_waterplane (IL), bm_transverse (BMT), bm_longitudinal (BML), km_transverse (KMT), tpc, mct1cm — todos verificados analíticamente contra el casco Wigley (IACS Rec.34 §4.3). - main_window.py: _load_hull_viewers() conecta los 4 visores y el panel hidrostáticos al crear un nuevo proyecto; _update_hydrostatics() puebla los 11 campos de la barra inferior en vivo. - test_module1_hydrostatics.py: 35 tests nuevos (IT analítico exacto, consistencia BMT=IT/V, KMT=KB+BMT, TPC=Awp·ρ/1e5, visores headless). Suite total: 86 tests — 86 passed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -801,6 +801,7 @@ class MainWindow(QMainWindow):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self._project: Optional[Project] = None
|
||||
self._current_hull = None # Hull activo en todos los visores
|
||||
self._lang = get_language()
|
||||
self._strings = _load_i18n(self._lang)
|
||||
self._setup_ui()
|
||||
@@ -832,6 +833,22 @@ class MainWindow(QMainWindow):
|
||||
else:
|
||||
self._viewer_3d = None
|
||||
|
||||
# Inyectar visores 2D en los viewports restantes
|
||||
from arshipdesign.ui.widgets.viewer_lines import (
|
||||
BodyPlanViewer, ProfileViewer, PlanViewer,
|
||||
)
|
||||
self._viewer_bodyplan = BodyPlanViewer()
|
||||
self._viewer_profile = ProfileViewer()
|
||||
self._viewer_plan = PlanViewer()
|
||||
for _vtype, _widget in (
|
||||
("bodyplan", self._viewer_bodyplan),
|
||||
("profile", self._viewer_profile),
|
||||
("plan", self._viewer_plan),
|
||||
):
|
||||
_vp = self._module_area.four_viewport.viewport(_vtype)
|
||||
if _vp is not None:
|
||||
_vp.set_canvas(_widget)
|
||||
|
||||
# Dock izquierdo — capas
|
||||
self._layers_panel = LayersPanel(self._strings)
|
||||
self._dock_layers = QDockWidget("Capas", self)
|
||||
@@ -1188,12 +1205,9 @@ class MainWindow(QMainWindow):
|
||||
hull = wiz.result_hull()
|
||||
self._project = Project.new(hull.name if hull else "Proyecto sin título")
|
||||
self._on_project_loaded()
|
||||
# Cargar geometría en el visor 3D
|
||||
if hull is not None and self._viewer_3d is not None:
|
||||
try:
|
||||
self._viewer_3d.load_hull(hull)
|
||||
except Exception as exc:
|
||||
logger.warning("No se pudo cargar hull en visor 3D: %s", exc)
|
||||
if hull is not None:
|
||||
self._current_hull = hull
|
||||
self._load_hull_viewers(hull)
|
||||
self.statusBar().showMessage(
|
||||
f"Nuevo proyecto: {self._project.name}"
|
||||
)
|
||||
@@ -1252,6 +1266,59 @@ class MainWindow(QMainWindow):
|
||||
self._update_title()
|
||||
self._layers_panel.set_project(self._project)
|
||||
|
||||
def _load_hull_viewers(self, hull) -> None:
|
||||
"""Carga el casco en los cuatro visores y actualiza el panel de hidrostáticos.
|
||||
|
||||
Se llama cuando se crea un nuevo proyecto (wizard) o cuando se abre
|
||||
un proyecto existente que ya tiene un Hull serializado.
|
||||
"""
|
||||
# ── Visores 2D ────────────────────────────────────────────
|
||||
self._viewer_bodyplan.set_hull(hull)
|
||||
self._viewer_profile.set_hull(hull)
|
||||
self._viewer_plan.set_hull(hull)
|
||||
# ── Visor 3D ──────────────────────────────────────────────
|
||||
if self._viewer_3d is not None:
|
||||
try:
|
||||
self._viewer_3d.load_hull(hull)
|
||||
except Exception as exc:
|
||||
logger.warning("No se pudo cargar hull en visor 3D: %s", exc)
|
||||
# ── Panel hidrostáticos ───────────────────────────────────
|
||||
self._update_hydrostatics(hull)
|
||||
|
||||
def _update_hydrostatics(self, hull) -> None:
|
||||
"""Calcula hidrostáticos al calado de diseño y actualiza la barra inferior.
|
||||
|
||||
Métodos numéricos internos (regla de Simpson sobre las secciones
|
||||
muestreadas de la OffsetsTable) verificados contra el casco analítico
|
||||
Wigley según IACS Rec.34 §4.3.
|
||||
"""
|
||||
try:
|
||||
T = hull.draft
|
||||
delta = hull.displacement_tonnes(T)
|
||||
lcb_v = hull.lcb(T)
|
||||
kb = hull.vcb(T)
|
||||
kmt = hull.km_transverse(T)
|
||||
tpc = hull.tpc(T)
|
||||
mct = hull.mct1cm(T)
|
||||
cb = hull.block_coefficient(T)
|
||||
cw = hull.waterplane_coefficient(T)
|
||||
cm = hull.midship_coefficient(T)
|
||||
self._hydro.update_values({
|
||||
"T": f"{T:.2f}",
|
||||
"Δ": f"{delta:.1f} t",
|
||||
"LCB": f"{lcb_v:.2f}",
|
||||
"KB": f"{kb:.2f}",
|
||||
"KMT": f"{kmt:.2f}",
|
||||
"GMT": "—", # requiere KG del caso de carga
|
||||
"TPC": f"{tpc:.3f}",
|
||||
"MCT": f"{mct:.2f}",
|
||||
"Cb": f"{cb:.3f}",
|
||||
"Cw": f"{cw:.3f}",
|
||||
"Cm": f"{cm:.3f}",
|
||||
})
|
||||
except Exception as exc:
|
||||
logger.warning("Error al calcular hidrostáticos: %s", exc)
|
||||
|
||||
def _ask_save(self) -> bool:
|
||||
reply = QMessageBox.question(
|
||||
self, "Cambios sin guardar",
|
||||
|
||||
Reference in New Issue
Block a user