""" Build CO4CTG01M.000 — Carta ENC S-57 de la Bahía de Cartagena. Lee todas las capas CSV de capas_ctg/ y genera un archivo S-57 válido para OpenCPN, AR ECDIS y cualquier software compatible IHO S-57. Uso: python build_cartagena.py python build_cartagena.py --out dist/MI_CARTA/MI_CARTA.000 Columnas especiales en los CSV: feat_type — acrónimo S-57 de la fila (BOYCAR, LIGHTS, etc.) CATCAM — dirección cardinal (1=N 2=E 3=S 4=W) → se escribe directo al S-57 ORIENT — rumbo de enfilación en grados → se escribe directo al S-57 _* — columnas privadas, se ignoran """ import sys import json import argparse from pathlib import Path from datetime import date sys.path.insert(0, str(Path(__file__).parent)) from converter import S57CellWriter # ── rutas ───────────────────────────────────────────────────────────────────── HERE = Path(__file__).parent CAPAS_DIR = HERE / "capas_ctg" OUTPUT = HERE / "dist" / "CO4CTG01M" / "CO4CTG01M.000" # ── orden de carga de capas (primero las estructuras, luego las luces) ──────── # El orden importa: si una fila de LIGHTS.csv tiene feat_type=LIGHTS su companion # light ya no se emite dos veces porque solo las clases _STRUCT_CLASSES generan # companion. Pero al cargar BOYCAR/BCNLAT antes que LIGHTS evitamos duplicados. LAYERS = [ # archivo CSV clase S-57 por defecto (se sobreescribe por feat_type) ("BOYCAR.csv", "BOYCAR"), ("BCNLAT.csv", "BCNLAT"), ("BOYISD.csv", "BOYISD"), ("BOYLAT.csv", "BOYLAT"), ("BOYSPEC.csv", "BOYSPP"), ("LIGHTS.csv", "LIGHTS"), ] def main(): ap = argparse.ArgumentParser() ap.add_argument("--out", default=str(OUTPUT), help="Ruta del archivo .000 de salida") args = ap.parse_args() out_path = Path(args.out) out_path.parent.mkdir(parents=True, exist_ok=True) cfg = { "cell_name": "CO4CTG01M", "cell_edition": 1, "update_number": 0, "issue_date": date.today().strftime("%Y%m%d"), "producer_code": "CO", "producer_name": "DIMAR / AR ECDIS", "data_set_name": "Bahia de Cartagena ENC", "scale": 12000, "compilation_scale":12000, "comment": "Generated by QGIS S-57 Converter from capas_ctg", "horizontal_datum": "WGS84", "vertical_datum": "MLLW", "sounding_datum": "MLLW", "attribute_mappings": {}, } print(f"Input dir : {CAPAS_DIR}") print(f"Output : {out_path}") print() writer = S57CellWriter(str(out_path), cfg) writer.open() total = 0 for csv_name, default_class in LAYERS: csv_path = CAPAS_DIR / csv_name if not csv_path.exists(): print(f" [SKIP] {csv_name} — no encontrado") continue n = writer.add_features_from_csv( csv_path, default_class, attr_map={}, x_field="lon", y_field="lat", ) print(f" {csv_name:20s} → {n:3d} feature(s)") total += n writer.close() writer.summary() size_kb = out_path.stat().st_size // 1024 print(f"\n✓ {total} feature(s) escritos") print(f" {out_path} ({size_kb} KB)") print() print("Para OpenCPN: Herramientas → Opciones → Cartas → Agregar directorio") print(f" → {out_path.parent}") if __name__ == "__main__": main()