feat: AR-Shipdesign initial commit

This commit is contained in:
2026-07-03 12:23:25 -04:00
parent 588735ea64
commit 9a08526361
16 changed files with 4431 additions and 394 deletions
+549
View File
@@ -0,0 +1,549 @@
# BITÁCORA DE DESARROLLO — AR-ShipDesign
> **Propósito:** Registro técnico vivo de cada módulo funcional de la app.
> A diferencia de `CHANGELOG.md` (que registra versiones), esta bitácora documenta
> el estado interno de cada módulo: qué funciona, qué se corrigió, por qué se
> tomaron ciertas decisiones y qué queda pendiente.
>
> **Actualizar** al final de cada sesión de trabajo o al completar un feature.
---
## Convenciones de estado
| Símbolo | Significado |
|---------|-------------|
| ✅ | Implementado y verificado (tests + visual) |
| 🔧 | Implementado, pendiente verificación visual en la app |
| 🐛 | Bug conocido, no resuelto aún |
| 📋 | Planificado, no iniciado |
| ❌ | Descartado o revertido (con explicación) |
| ⚠️ | Restricción crítica — no romper |
---
## Reglas Inquebrantables (leer SIEMPRE antes de editar los visores)
### ⚠️ REGLA DE EJES — NUNCA VIOLAR
```
Vista Perfil (ProfileViewer) → nodos en EJE X (longitudinal) + EJE Z (vertical)
Vista Planta (PlanViewer) → nodos en EJE X (longitudinal) + EJE Y (transversal)
Vista Frontal (BodyPlanViewer) → nodos en EJE Y (transversal) + EJE Z (vertical)
```
Nunca bloquear nodos en ninguna vista. Nunca añadir restricciones `_hit_test` a nodos normales.
Si un cambio rompe el movimiento en alguno de estos ejes → **REVERTIR INMEDIATAMENTE**.
### ⚠️ REGLA DE SNAP
El snap de nodos de contorno (`snap_boundary_nodes_to_contours`) **solo** se ejecuta en
`_on_new_project` (wizard de creación). Nunca en `_on_offsets_edited_from_viewer` ni en
`Hull.from_dict()`. Los `x_offsets` son datos del usuario y se restauran tal cual.
---
## Sentinels de nodo especial (`viewer_lines.py`)
```python
_KEEL_IDX = -1 # nodo de quilla (keel_z[i] por estación)
_SHEER_IDX = -2 # nodo de cubierta (sheer_z[i] por estación)
_STEM_IDX = -10 # punto de control de roda
_TRANS_IDX = -20 # punto de control de espejo de popa
```
El índice `j` en `(i, j)` siendo negativo indica nodo especial, no columna de `data[i,j]`.
---
## Módulo 1 — Geometría del Casco
**Archivo clave:** `arshipdesign/core/hull.py`, `arshipdesign/core/offsets.py`
### Estructura de datos
```
Hull
├── offsets: OffsetsTable
│ ├── x_stations[n_sta] — posición X de cada estación [m]
│ ├── data[n_sta, n_wl] — semi-manga Y por (estación, LdA) [m]
│ ├── keel_z[n_sta] — Z de la quilla por estación [m]
│ ├── z_waterlines[n_wl] — Z absoluta de cada LdA [m]
│ ├── z_offsets[n_sta, n_wl] — ajuste Z local por nodo [m]
│ └── x_offsets[n_sta, n_wl] — ajuste X visual del nodo en los visores 2D [m]
├── sheer_z[n_sta] — Z de la cubierta (arrufo) por estación [m]
├── stem_ctrl[k, 2] — polígono de control de la roda (B-spline)
├── transom_ctrl[k, 2] — polígono de control del espejo de popa
└── corner_nodes: list[[i,j]] — nodos marcados como esquina (rompen suavidad)
```
### Estado ✅
- **Serialización** (`to_dict` / `from_dict`): guarda todos los arrays sin recalcular.
Al cargar, los `x_offsets` se restauran exactamente como el usuario los dejó.
- **Inserción de estaciones** (`insert_station`): interpola Y, keel_z, sheer_z y offsets.
- **Inserción de líneas de agua** (`insert_waterline`): interpola semi-mangas.
- **B-Spline de sección** (`_section_yz` en `to_mesh`): muestrea el perfil Y-Z
desde quilla → LdA de control → cubierta con grado mín(3, n-1).
- **Malla 3D** (`to_mesh`): grilla estructurada n_u × n_v interpolada entre estaciones,
triangulada para PyVista. Genera ambas bandas (estribor + babor).
- **Lazy cache** (`station_planes`, `get_sheer_z`): no recalcula si los datos no cambian.
### Bug conocido 🐛
**"Tabla en quilla"** — Si se mueve `keel_z[i]` de una sola estación muy lejos de
las vecinas, la malla 3D muestra una depresión abrupta (tabla/aleta) porque:
- Las LdA permanecen en sus Z fijos absolutas.
- La interpolación entre estaciones crea una concavidad estrecha en esa estación.
- **Workaround:** mover la quilla en varias estaciones sucesivas para distribuir el cambio.
- **Fix definitivo:** wizard de redistribución de LdA + más puntos de control de quilla.
---
## Módulo 2 — Visores 2D Interactivos
**Archivo clave:** `arshipdesign/ui/widgets/viewer_lines.py`
### Clases principales
```
_BaseViewer — zoom, paneo, drag de nodos, hit-test, HUD, fairness, selección de curva
├── BodyPlanViewer — secciones transversales Y-Z (cuadernas)
├── ProfileViewer — vista lateral X-Z (quilla, cubierta, roda, espejo)
└── PlanViewer — vista de planta X-Y (líneas de agua desde arriba)
```
### Estado 🔧
- **Drag de nodos**: todos los nodos arrastrables, sin restricciones (respeta Regla de Ejes).
- **Selección de nodo** (clic): nodo se vuelve dorado; panel `NodeInfoPanel` muestra X/Y/Z
y checkbox de esquina. Enter aplica el valor editado manualmente.
- **Selección de curva** (Shift+clic): detecta arista de la malla NURBS más cercana.
La curva completa se resalta en verde menta `#00FFB0` con 2.5 px.
- Body Plan: Shift+clic → sección completa keel→LdA→sheer (estación i)
- Perfil: Shift+clic → quilla o cubierta (curva longitudinal)
- Planta: Shift+clic → línea de agua j completa
- **Peines de curvatura** `[C]`: pelos perpendiculares a la curva.
Normalizados por max|κ| → siempre visibles aunque la curva sea casi recta.
Solo en la curva seleccionada (Shift+clic) o en todas si no hay selección.
Pelo invertido al lado opuesto = inflexión (cambio de signo de curvatura).
- **Coloreo de equidad** `[F]`: nodos coloreados verde→amarillo→rojo por |d²Y/dX²|.
- **Suavizado local** `[S]`: Laplaciano 1 paso en el nodo seleccionado.
- **Zoom**: rueda del ratón. Doble clic: fit-to-view.
- **Paneo**: botón medio o derecho + arrastrar.
- **HUD** (esquina inferior derecha): estado de [C]/[F]/[S] y nombre de la curva activa.
- **Sincronización entre vistas** (en vivo): `offsets_dragging` durante el drag,
`offsets_edited` al soltar.
- **Menú contextual** (clic derecho): insertar LdA, estación, roda, espejo, esquina.
### Historial de correcciones
| Fecha | Problema | Causa raíz | Fix aplicado |
|-------|----------|------------|--------------|
| 2026-05-28 | Nodos de borde no arrastrables en X | `_hit_test` de ProfileViewer excluía i=0 e i=n-1 para LdA normales | Revertido: loop incluye todos los nodos sin excepción |
| 2026-05-28 | Peines de curvatura invisibles | `scale = beam × 0.20` → κ≈0.02 → pelo de 2cm, invisible a escala normal | Normalizado: todos los κ ÷ max\|κ\| antes de escalar |
| 2026-05-28 | `self._selected` no existe | Nombre incorrecto del atributo | Corregido a `self._selected_idx` |
### Pendiente 📋
- Peines de curvatura en keel/sheer desde el ProfileViewer (actualmente solo en quilla/cubierta como curvas, no como Z).
- Suavizado 2D (Laplaciano transversal dentro de la cuaderna).
- Tests automatizados para fairness coloring y suavizado.
---
## Módulo 3 — Visor 3D
**Archivo clave:** `arshipdesign/ui/widgets/viewer_3d.py`
### Estado 🔧
- **Motor**: PyVista + pyvistaqt (`QtInteractor` embebido).
- **Degradación sin PyVista**: muestra `QLabel` en lugar de crashear (permite que CI pase).
- **Carga diferida**: `QtInteractor` se crea 500 ms después del arranque (evita conflicto OpenGL).
- **Tema oscuro**: fondo `#1a1d30`, casco `#3a6080`, aristas `#4da8ff`, plano de flotación `#4da8ff` al 15%.
- **Toggle mallas** (botón `⬡ Mallas` en barra superior del visor): apagado por defecto.
Llama `GetProperty().EdgeVisibilityOn/Off()` sobre el actor VTK → sin re-render.
### Historial de correcciones
| Fecha | Problema | Fix |
|-------|----------|-----|
| 2026-05-29 | Mallas siempre visibles, sin forma de apagarlas | Añadido botón toggle + `_show_edges=False` por defecto |
### Pendiente 📋
- Caras invertidas: detectar y colorear diferente (rojo/azul), comando flip.
- Capas de visualización: buttocks, waterlines, sections como actores independientes.
- Cierre de malla en AP para transom stern.
---
## Módulo 4 — Guardado y Cargado de Proyectos
**Archivos:** `arshipdesign/core/project.py`, `arshipdesign/core/hull.py`
### Formato `.arsd`
Archivo ZIP que contiene `hull.json` con formato `hull_v1`.
Incluye todos los arrays de offsets, control curves, y metadatos del buque.
### Estado ✅
- **Persistencia exacta**: todos los arrays se guardan y restauran fielmente.
- **Sin snap en carga**: `from_dict` no llama `snap_boundary_nodes_to_contours`.
### Historial de correcciones
| Fecha | Problema | Causa | Fix |
|-------|----------|-------|-----|
| 2026-05-28 | Forma diferente al recargar | `snap_boundary_nodes_to_contours` en `from_dict` recalculaba `x_offsets` | Eliminado de `from_dict` |
| 2026-05-28 | Nodos saltaban al soltar | `snap` en `_on_offsets_edited_from_viewer` sobreescribía la posición del usuario | Eliminado del handler |
---
## Módulo 5 — Hidrostáticos
**Archivos:** `arshipdesign/core/hydrostatics.py`
### Estado ✅
- Cálculo en tiempo real al modificar cualquier nodo.
- Métricas: Δ, LCB, TCB, KB, BM, GM, Cb, Cm, Cp, Cw, AWP.
- Validado contra casco analítico Wigley (IACS Rec.34 §4). Tests: 315/315 ✅
---
## Módulo 6 — Estabilidad
**Archivo:** `arshipdesign/core/stability.py`
### Estado ✅
- Curva GZ por planos de inclinación.
- Criterios IMO IS Code 2008 verificados.
---
## Módulo 7 — Generadores Paramétricos
**Archivos:** `arshipdesign/parametric/wizard_*.py`
### Familias disponibles ✅
| Familia | Archivo | Estado |
|---------|---------|--------|
| Workboat (buque de trabajo) | `wizard_workboat.py` | ✅ |
| Velero | `wizard_sailing.py` | ✅ |
| Lancha rápida | `wizard_fast.py` | ✅ |
| Remolcador | `wizard_tug.py` | ✅ |
| Ferry / pasaje | `wizard_ferry.py` | ✅ |
- **Arrufo parabólico**: `sheer_z[i] = sheer_base + camber × (1 (2x/L 1)²)`
- Snap de nodos de contorno se aplica **una sola vez** al crear el proyecto.
### Pendiente 📋
- Opción transom stern en el wizard (`has_transom: bool`, `transom_angle: float`).
- Wizard de estaciones/LdA/buttocks: definir manualmente posiciones antes de generar la malla.
---
## Módulo 8 — UI / Layout / Ribbon
**Archivos:** `arshipdesign/ui/main_window.py`, widgets varios
### Estado 🔧
- **Layout 4 viewports**: QSplitters anidados. Arriba: 3D+Perfil. Abajo: FrontalI+Planta.
- **Maximizar viewport** (botón `⬜`/`❎` o doble clic en barra de título):
oculta viewport compañero y fila opuesta. Restaurar vuelve a 50/50.
- **Ribbon**: tabs Geometría, Hidrostáticos, Estabilidad, Estructural.
Grupo "Suavizado" con botones Curvatura, Equidad, Suavizar.
- **NodeInfoPanel**: flotante, coordenadas X/Y/Z editables + checkbox esquina.
### Historial de correcciones
| Fecha | Problema | Fix |
|-------|----------|-----|
| 2026-05-28 | Enter en NodeInfoPanel no aplicaba cambio | Señal `coord_edited` no conectada | Conectada en `__init__` |
| 2026-05-29 | `QPushButton` no importado | Faltaba en bloque de imports | Añadido |
---
## Módulo 9 — Herramientas de Fairness (Equidad)
**Funciones en** `viewer_lines.py`: `_fairness_color`, `_smooth_selected_node`,
`_draw_curvature_comb`, `_curvature_comb_data`, `_dist_to_segment`
### Peines de curvatura
```
κᵢ = 2 × cross(t₁, t₂) / (l₁ + l₂) — curvatura discreta firmada
κ_normalizada = κᵢ / max|κ| — rango [-1, 1]
pelo_longitud = κ_normalizada × scale — en unidades de mundo
```
- Pelo al lado contrario de la curva = curvatura positiva (convexa).
- Pelo al mismo lado = curvatura negativa (cóncava / inflexión).
- Spine = línea que une las puntas → revela continuidad de curvatura.
### Coloreo de equidad
```
roughness = |Y[i+1] - 2·Y[i] + Y[i-1]| / (Δx²)
```
- Verde `#22cc66`: roughness < 0.005 m⁻¹
- Rojo `#e03030`: roughness > 0.150 m⁻¹
### Suavizado Laplaciano 1-paso
```
Y_new[i] = (Y[i-1] + Y[i] + Y[i+1]) / 3
```
Solo nodos interiores. Aplica a Y breadths, keel_z y sheer_z.
---
## Módulo 10 — Deshacer / Rehacer (Ctrl+Z / Ctrl+Y)
**Archivo:** `arshipdesign/ui/main_window.py`
### Estado 🔧
- **Mecanismo**: stack de snapshots `hull.to_dict()` — cada estado es una copia completa del casco serializado (arreglos numpy → listas, muy pequeño en memoria).
- **Capacidad**: 50 pasos de deshacer (`_MAX_UNDO = 50`).
- **Ctrl+Z** (`Editar → Deshacer`): restaura el estado anterior al último drag/edición.
- **Ctrl+Y** (`Editar → Rehacer`): rehace el cambio deshecho.
- Cada nueva edición **limpia el stack de redo** (rama nueva invalida el futuro).
- Al crear o abrir un proyecto, ambos stacks se limpian (`_reset_undo_history`).
- Las acciones del menú se habilitan/deshabilitan según haya pasos disponibles.
### Cómo funciona internamente
```
_last_hull_state = snapshot del hull ANTES del último edit
_undo_stack = [estado_0, estado_1, ..., estado_n] ← el más reciente al final
_redo_stack = estados deshechados disponibles
Al recibir offsets_edited:
1. push _last_hull_state → _undo_stack
2. clear _redo_stack
3. _last_hull_state = hull.to_dict() (nuevo estado actual)
Al hacer Ctrl+Z:
1. push hull.to_dict() → _redo_stack
2. hull = Hull.from_dict(_undo_stack.pop())
3. _load_hull_viewers(hull) — refresca todos los visores + hidrostáticos
```
### Qué operaciones son deshaciibles
| Operación | ¿Deshacible? |
|-----------|-------------|
| Arrastrar nodo | ✅ |
| Suavizar con [S] | ✅ (si emite offsets_edited) |
| Editar coordenada en panel | ✅ |
| Insertar estación/LdA desde menú contextual | ✅ |
| Crear nuevo proyecto | ❌ (limpia el historial) |
| Abrir proyecto | ❌ (limpia el historial) |
---
## Módulo 11 — Iconos de Ribbon (arshipdesign/ui/icons.py)
**Estado:** 🔧 Implementado — pendiente verificación visual
### Qué hace
Nuevo módulo `arshipdesign/ui/icons.py` con **50 iconos programáticos** únicos, uno por cada
botón del ribbon. Antes todos compartían el mismo icono genérico del sistema (`SP_FileDialogDetailedView`).
### Diseño técnico
- Cada icono se dibuja con `QPainter` sobre un `QPixmap(24×24)` transparente.
- Paleta coherente con el tema oscuro:
- `#c8d8e8` trazo principal
- `#4da8ff` cyan / agua
- `#00ffb0` verde mint (selección / OK)
- `#ffd060` amarillo / dorado (energía, controles)
- `#ff5555` rojo (daño, alerta)
- Función pública: `icon("clave") → QIcon` con caché `_CACHE` dict.
- Importado en `main_window.py` como `from arshipdesign.ui.icons import icon as _ico`.
### Iconos implementados por grupo
| Grupo | Claves |
|-------|--------|
| HOME / Vistas | `4views`, `lines_plan` |
| Geometría / Nuevo | `wizard`, `hull_nurbs`, `appendage` |
| Geometría / Edición NURBS | `ctrl_pts`, `extrude`, `mirror`, `lackenby` |
| Geometría / Importar | `import_offsets`, `import_dxf` |
| Geometría / Exportar | `export_iges`, `export_step`, `export_dxf` |
| Geometría / Suavizado | `smooth`, `combs`, `fairness` |
| Análisis / Hidrostática | `hydro_calc`, `hydro_curves`, `export_csv` |
| Análisis / Estabilidad | `gz_curve`, `imo`, `damage` |
| Análisis / Resistencia | `holtrop`, `savitsky`, `vpp` |
| Análisis / Seakeeping | `stf`, `spectrum` |
| Análisis / Estructura | `iso12215` |
| Tanques | `new_tank`, `model_tank`, `load_case`, `sounding`, `calc_kg` |
| Sistemas / Eléctrico | `epla` |
| Sistemas / Fluidos | `fuel`, `freshwater`, `bilge`, `firefight` |
| Sistemas / Routing 3D | `pipes`, `cables` |
| Sistemas / Clima | `hvac`, `steering` |
| Fabricación / CNC | `materials`, `nesting`, `gcode`, `postproc` |
| Fabricación / Moldes FRP | `lofting`, `laminate`, `resin`, `bom` |
### Decisiones
- Se mantienen los iconos estándar del sistema para: Nuevo, Abrir, Guardar (Archivo),
Deshacer/Rehacer (flechas del sistema), Offsets (vista de lista).
- El módulo NO importa Qt en el nivel de módulo — los QIcon solo se crean cuando se llaman,
así la importación de `icons.py` es segura antes de que exista `QApplication`.
### Corrección — Rediseño v2 (2026-05-30 sesión 2)
**Problema detectado:** La primera versión usaba trazos claros (`#c8d8e8`) sobre fondo
transparente. El ribbon de PySide6 tiene fondo blanco → los iconos eran prácticamente
invisibles (se veía solo el borde del botón).
**Solución:** Rediseño completo con estilo "flat icon":
- Relleno sólido de color por categoría + contorno oscuro `#1a2535`
- Visible en fondos claros Y oscuros
- Colores por categoría:
| Categoría | Color |
|-----------|-------|
| Geometría / Casco | Azul océano `#2a7fc8` |
| Edición NURBS | Índigo `#5548d0` |
| Suavizado | Verde vivo `#20a860` |
| Peines | Púrpura `#7040c8` + verde mint |
| Fairness | Gradiente rojo→verde |
| Análisis hidro | Teal `#1898a8` |
| Estabilidad | Azul `#2068c0` |
| Resistencia | Naranja `#d07020` |
| Tanques | Cyan `#18a0c0` |
| Sistemas eléctrico | Amarillo sobre negro |
| Fabricación | Violeta `#8838b8` |
**Estado tras rediseño:** 🔧 Pendiente verificar visualmente (requiere `python main.py`)
---
## Módulo 12 — Peines de Curvatura Mejorados
**Estado:** 🔧 Implementado — pendiente verificación visual
### Cambios en `viewer_lines.py`
**Problema:** Los peines se dibujaban usando los ~10-20 puntos crudos de la tabla de
offsets. Resultado: pelos escasos, ángulos bruscos, spine anguloso.
**Solución:** Nueva función `_resample_curve_smooth(xs, ys, n=80)`:
- Parametriza la curva por longitud de arco acumulada
- Remuestrea a **80 puntos equidistantes** usando `scipy.interpolate.CubicSpline`
- Fallback a `np.interp` (lineal) si scipy no está disponible
- Llamada al inicio de `_draw_curvature_comb` antes de calcular κ
**Resultado esperado:** 80 pelos por curva en lugar de ~10-20, spine suave.
### Regla
No aumentar más de 80 muestras sin medir impacto en FPS — la función se llama en
cada `paintEvent` (puede ser frecuente al arrastrar nodos).
---
## Módulo 13 — Visor 3D Colores Sólidos
**Estado:** 🔧 Implementado — pendiente verificación visual
### Cambios en `viewer_3d.py` — `_render_hull_mesh`
| Parámetro | Antes | Ahora | Por qué |
|-----------|-------|-------|---------|
| `smooth_shading` | `True` | `False` | Facetas planas = aspecto sólido, sin blur |
| `opacity` | `0.92` | `1.0` | Totalmente opaco = color pleno |
| `ambient` | (default ~0.2) | `0.40` | Reduce sombras duras, color más uniforme |
| `diffuse` | (default ~0.8) | `0.60` | Equilibrio iluminación |
| `specular` | (default ~0.1) | `0.05` | Sin brillos que difuminen |
| `color` | `#3a6080` | `#4a8ab0` | Tono más vivo y legible |
| `line_width` | `0.3` | `0.6` | Aristas más visibles al activar mallas |
### Nota
Si en el futuro se quiere smooth shading selectivo (solo en alta resolución),
usar `mesh.compute_normals()` primero y luego `smooth_shading=True`.
---
## Módulo 14 — Fix Freeze Curva GZ (QThread)
**Estado:** 🔧 Implementado — pendiente verificación
### Problema
`_on_show_stability``_compute_and_show_gz``compute_gz_wall_sided`
`compute_upright` (integración hidrostática pesada) → **bloqueaba el UI thread de Qt**
indefinidamente ("se trabó el programa").
### Solución
Nueva clase `_GZWorker(QObject)` con señales `finished` / `error`.
El cálculo se mueve a un `QThread`:
```
[UI thread] botón → _compute_and_show_gz()
↓ lanza QThread
[Hilo GZ] _GZWorker.run()
↓ emite finished(gz_curve, imo_result)
[UI thread] _on_gz_done() → actualiza widget + statusBar
```
### Guarda doble
Si el usuario hace clic dos veces seguidas, el segundo clic se ignora mientras el
hilo anterior sigue corriendo (`if self._gz_thread.isRunning(): return`).
### Archivos modificados
| Archivo | Cambio |
|---------|--------|
| `main_window.py` | Import `QThread, QObject`; clase `_GZWorker`; `_compute_and_show_gz` refactorizado; nuevo slot `_on_gz_done` |
---
## Roadmap Global
| Prioridad | Feature | Módulo | Estado |
|-----------|---------|--------|--------|
| 🔴 Alta | Wizard de estaciones / LdA / buttocks | Geometría | 📋 |
| 🔴 Alta | Transom stern (popa espejo) | Geometría + 3D | 📋 |
| 🟡 Media | Verificar iconos ribbon visualmente | UI | 🔧 |
| 🟡 Media | Verificar peines densidad visual | Fairness | 🔧 |
| 🟡 Media | Verificar colores sólidos 3D visual | Visor 3D | 🔧 |
| 🟡 Media | Caras invertidas 3D + flip | Visor 3D | 📋 |
| 🟡 Media | Peines de curvatura en keel/sheer (Z) | Fairness | 📋 |
| 🟡 Media | Suavizado 2D (Laplaciano transversal) | Fairness | 📋 |
| 🟢 Baja | Tests de fairness automatizados | Tests | 📋 |
| 🟢 Baja | Exportar DXF / offsets CSV | Exportación | 📋 |
| 🟢 Baja | Importar offsets desde tabla manual | Importación | 📋 |
---
## Tests y Entorno
```bash
# Ejecutar suite completa
cd "D:\Proyectos Software\AR-Shipdesign"
python -m pytest tests/ -x -q
# Lanzar la aplicación
python main.py
```
**Estado de tests:** 315/315 ✅ — Última verificación: 2026-05-30
⚠️ Tests no actualizados para GZWorker (QThread) — agregar en próxima sesión.
---
*Última actualización: 2026-05-30 (sesión 2)*
*Mantener este archivo actualizado al final de cada sesión de trabajo.*