Initial commit — QGIS S-57 Converter

This commit is contained in:
2026-05-04 23:03:19 -04:00
commit eb12a58cb7
41 changed files with 8896 additions and 0 deletions
+157
View File
@@ -0,0 +1,157 @@
"""
build_ecdis_manual.py — Reconstruye los GeoJSONs del ECDIS manual chart
desde los CSVs fuente. Funciona igual para CUALQUIER puerto.
Uso:
python build_ecdis_manual.py capas_ctg BAHÍA_DE_CARTAGENA
python build_ecdis_manual.py capas_baq BARRANQUILLA
python build_ecdis_manual.py capas_ptco BUENAVENTURA
El script:
1. Lee todos los *.csv del directorio de capas
2. Genera un GeoJSON por feat_type con atributos S-57 limpios
3. Escribe los GeoJSONs en el directorio manual del ECDIS
Reglas de datos:
- feat_type determina el archivo de salida (LIGHTS.geojson, BOYCAR.geojson...)
- SIGGRP "**" → null (limpia basura de GDAL)
- LITCHR_TXT se convierte a código S-57 si LITCHR está vacío
- COLOUR_TXT se convierte a código S-57 si COLOUR está vacío
- CATCAM y ORIENT se pasan directo al GeoJSON
- INFORM se preserva completo
"""
import csv, json, sys, argparse
from pathlib import Path
ECDIS_DATA = Path(__file__).parent.parent / "AR ECDIS" / "webecdis" / "data" / "charts" / "manual"
LITCHR_TXT = {
"f":"1","fl":"2","lfl":"3","q":"4","vq":"5","uq":"6",
"iso":"7","oc":"8","iq":"9","mo":"12","ffl":"13",
}
COLOUR_TXT = {
"white":"1","black":"2","red":"3","green":"4","blue":"5",
"yellow":"6","grey":"7","brown":"8","amber":"9","violet":"10",
"orange":"11","magenta":"12",
}
def _fval(s):
s = (s or "").strip()
if not s or all(c in "* " for c in s): return None
try: return float(s)
except: return None
def _ival(s):
s = (s or "").strip()
if not s or all(c in "* " for c in s): return None
try: return int(float(s))
except: return None
def _sval(s):
s = (s or "").strip()
return s if s and not all(c in "* " for c in s) else None
def _parse_litchr(row):
v = _ival(row.get("LITCHR", ""))
if v is not None: return v
txt = (row.get("LITCHR_TXT") or "").lower().split("(")[0].strip()
c = LITCHR_TXT.get(txt)
return int(c) if c else None
def _parse_colour(row):
v = (row.get("COLOUR") or "").strip()
if v and not all(c in "* " for c in v):
parts = [p.strip() for p in v.split(",") if p.strip().isdigit()]
if parts: return [int(p) for p in parts]
txt = (row.get("COLOUR_TXT") or "").lower().strip()
c = COLOUR_TXT.get(txt)
return [int(c)] if c else None
def build(capas_dir: Path, chart_name: str, ecdis_data: Path):
out_dir = ecdis_data / chart_name
if not out_dir.exists():
print(f"[WARN] Directorio ECDIS no existe: {out_dir}")
print(f" Creando...")
out_dir.mkdir(parents=True)
layers: dict[str, list] = {}
rcid = 1
for csv_file in sorted(capas_dir.glob("*.csv")):
default_layer = csv_file.stem.upper()
with open(csv_file, newline="", encoding="utf-8-sig") as f:
for row in csv.DictReader(f):
try:
lon = float(row.get("lon", "").strip())
lat = float(row.get("lat", "").strip())
except (ValueError, AttributeError):
continue
feat_type = (_sval(row.get("feat_type", "")) or default_layer).upper()
props = {
"RCID": rcid,
"PRIM": 1,
"GRUP": 1,
"OBJL": 75,
"RVER": 1,
"AGEN": 999,
"FIDN": rcid,
"FIDS": 1,
"LNAM": f"03E7{rcid:08X}0001",
"OBJNAM": _sval(row.get("OBJNAM", "")),
"LITCHR": _parse_litchr(row),
"COLOUR": _parse_colour(row),
"SIGGRP": _sval(row.get("SIGGRP", "")),
"SIGPER": _fval(row.get("SIGPER", "")),
"VALNMR": _fval(row.get("VALNMR", "")),
"HEIGHT": _fval(row.get("HEIGHT", "")),
"ORIENT": _fval(row.get("ORIENT", "")),
"CATCAM": _ival(row.get("CATCAM", "")),
"INFORM": _sval(row.get("INFORM", "")),
"NOBJNM": _sval(row.get("NOBJNM", "")),
}
feat = {
"type": "Feature",
"geometry": {
"coordinates": [lon, lat],
"type": "Point",
"geometries": None
},
"properties": props
}
layers.setdefault(feat_type, []).append(feat)
rcid += 1
total = 0
for layer, feats in sorted(layers.items()):
fc = {"type": "FeatureCollection", "features": feats}
out_file = out_dir / f"{layer}.geojson"
out_file.write_text(json.dumps(fc, ensure_ascii=False), encoding="utf-8")
print(f" {layer}.geojson : {len(feats)} features")
total += feats.__len__()
print(f"\nOK {total} features en {out_dir}")
return total
def main():
ap = argparse.ArgumentParser(description="Rebuild ECDIS manual GeoJSONs from CSV layers")
ap.add_argument("capas_dir", help="Directorio con los CSVs (capas_ctg, capas_baq...)")
ap.add_argument("chart_name", help="Nombre del chart en ECDIS (BAHÍA_DE_CARTAGENA, BARRANQUILLA...)")
ap.add_argument("--ecdis", default=str(ECDIS_DATA),
help=f"Ruta base de charts/manual del ECDIS [default: {ECDIS_DATA}]")
args = ap.parse_args()
capas = Path(args.capas_dir)
if not capas.exists():
print(f"ERROR: No existe {capas}")
sys.exit(1)
build(capas, args.chart_name, Path(args.ecdis))
if __name__ == "__main__":
main()