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
+275
View File
@@ -0,0 +1,275 @@
"""
parse_lista_luces.py
Genera CSV de ayudas a la navegacion de Barranquilla a partir de
Lista de Luces DIMAR 2015 (ya parseada manualmente).
"""
import csv, re, sys, os
from collections import Counter
def dms_to_dd(deg, minutes):
return float(deg) + float(minutes) / 60.0
# ---- DATA ----
# (no, name, lat_deg, lat_min, lon_deg, lon_min, char, height_m, range_nm, colour, description, feat_type, orient)
records = [
# FAROS MAYORES
(13, 'Faro F1 Recalada', 11, 6.37, 74, 50.97, 'Iso G 2s', 20, 9, 'G', 'Torre naranja bandas blancas. Faro de Recalada', 'LIGHTS', ''),
(14, 'Faro F2 Recalada', 11, 6.36, 74, 51.28, 'Iso R 2s', 23, 13.4, 'R', 'Torre naranja bandas blancas. Racon B', 'LIGHTS', ''),
(32, 'Faro Morro Hermoso', 10, 57.80, 75, 1.05, 'Fl W 4s', 134, 28, 'W', 'Torre blanca bandas rojas. Giratorio', 'LIGHTS', ''),
(33, 'Faro Galerazamba', 10, 47.12, 75, 15.96, 'Fl W 4s', 14, 11, 'W', 'Torre fibra vidrio blanca bandas rojas. Giratorio', 'LIGHTS', ''),
# FAROLES X (Tajamares Bocas de Ceniza)
# Estas son balizas laterales fijas en tierra → BCNLAT (no LIGHTS).
# IALA-B: Verde = babor (CATLAM=1), Rojo = estribor (CATLAM=2).
# La luz se extrae automáticamente de LITCHR/SIGGRP/SIGPER/COLOUR.
(15, 'Faro X1', 11, 6.13, 74, 50.97, 'Q(4)G 11s', 6, 6, 'G', 'Torre verde bandas blancas', 'BCNLAT', ''),
(16, 'Faro X2', 11, 6.00, 74, 51.20, 'Q(4)R 11s', 6, 6, 'R', 'Torre roja bandas blancas', 'BCNLAT', ''),
(18, 'Faro X3', 11, 5.48, 74, 50.83, 'Q(4)G 11s', 6, 6, 'G', 'Torre verde bandas blancas', 'BCNLAT', ''),
(17, 'Faro X4', 11, 5.58, 74, 51.10, 'Q(4)R 11s', 6, 6, 'R', 'Torre roja bandas blancas', 'BCNLAT', ''),
(19, 'Faro X5', 11, 5.35, 74, 50.80, 'Q(4)G 11s', 6, 6, 'G', 'Torre verde bandas blancas', 'BCNLAT', ''),
(20, 'Faro X6', 11, 5.26, 74, 51.03, 'Q(4)R 11s', 6, 6, 'R', 'Torre roja bandas blancas', 'BCNLAT', ''),
(21, 'Faro X7', 11, 2.49, 74, 48.86, 'Q(4)G 11s', 8, 6, 'G', 'Baliza enrejado verde bandas blancas', 'BCNLAT', ''),
(22, 'Faro X8', 11, 4.90, 74, 50.95, 'Q(4)R 11s', 6, 6, 'R', 'Torre roja bandas blancas', 'BCNLAT', ''),
(23, 'Faro X9', 11, 2.15, 74, 48.29, 'Q(4)G 11s', 8, 6, 'G', 'Baliza enrejado verde bandas blancas', 'BCNLAT', ''),
(24, 'Faro X10', 11, 4.56, 74, 50.88, 'Q(4)R 11s', 6, 6, 'R', 'Torre roja bandas blancas', 'BCNLAT', ''),
(25, 'Faro X11', 11, 1.79, 74, 47.73, 'Q(4)G 11s', 8, 6, 'G', 'Baliza enrejado verde bandas blancas', 'BCNLAT', ''),
(26, 'Faro X12', 11, 3.90, 74, 50.65, 'Q(4)R 11s', 6, 6, 'R', 'Baliza enrejado roja bandas blancas', 'BCNLAT', ''),
(27, 'Faro X13', 11, 1.55, 74, 47.38, 'Q(4)G 11s', 8, 6, 'G', 'Baliza enrejado verde bandas blancas', 'BCNLAT', ''),
(28, 'Faro X14', 11, 3.47, 74, 50.37, 'Q(4)R 11s', 6, 6, 'R', 'Torre roja bandas blancas', 'BCNLAT', ''),
(30, 'Faro X15', 11, 1.37, 74, 47.13, 'Q(4)G 11s', 6, 6, 'G', 'Baliza enrejado verde bandas blancas', 'BCNLAT', ''),
(29, 'Faro X16', 11, 3.00, 74, 49.98, 'Q(4)R 11s', 6, 6, 'R', 'Torre roja bandas blancas', 'BCNLAT', ''),
(31, 'Faro X17', 11, 1.12, 74, 46.70, 'Q(4)G 11s', 6, 6, 'G', 'Baliza enrejado verde bandas blancas', 'BCNLAT', ''),
# ENFILACIONES / RANGE LIGHTS
(196, 'Enfilacion E1', 11, 6.22, 74, 50.90, 'Iso Bu 5s', 10, 13, 'W', 'Baliza enrejado naranja y blanco. Rumbo 135.7', 'LIGHTS', '135.7'),
(197, 'Enfilacion E3', 11, 6.10, 74, 50.78, 'Iso Bu 5s', 22, 9, 'W', 'Torre enrejada naranja y blanco. Rumbo 139.3', 'LIGHTS', '139.3'),
(198, 'Enfilacion E3A', 11, 6.02, 74, 50.70, 'Iso W 5s', 20, 12.3, 'W', 'Torre naranja y blanco. Rumbo 135.7', 'LIGHTS', '135.7'),
(201, 'Enfilacion E4', 11, 4.21, 74, 50.81, 'Iso R 4s', 11, 4.5, 'R', 'Baliza enrejado naranja bandas blancas. Rumbo 142.3', 'LIGHTS', '142.3'),
(203, 'Enfilacion E6', 11, 3.78, 74, 50.62, 'Iso Bu 4s', 12, 8, 'R', 'Baliza enrejado roja bandas blancas. Rumbo 167.7', 'LIGHTS', '167.7'),
(204, 'Enfilacion E8', 11, 3.51, 74, 50.51, 'Iso Bu 4s', 25, 14.5, 'W', 'Baliza enrejado naranja bandas blancas. Rumbo 167.7', 'LIGHTS', '167.7'),
(205, 'Enfilacion E10', 11, 3.59, 74, 50.50, 'Iso G 5s', 11, 10, 'G', 'Torre naranja bandas blancas. Rumbo 167.3', 'LIGHTS', '167.3'),
(206, 'Enfilacion E12', 11, 3.37, 74, 50.44, 'Iso G 5s', 22, 8, 'G', 'Baliza tablero blanco franja roja. Rumbo 167.3', 'LIGHTS', '167.3'),
(207, 'Enfilacion E14', 11, 3.37, 74, 50.44, 'Iso Bu 6s', 22, 8, 'W', 'Tablero blanco con franja roja. Rumbo 122', 'LIGHTS', '122'),
(237, 'Enfilacion E16', 11, 3.22, 74, 50.20, 'Iso Bu 6s', 12, 9, 'W', 'Baliza enrejado naranja bandas blancas. Rumbo 122', 'LIGHTS', '122'),
(238, 'Enfilacion E18', 11, 2.58, 74, 49.53, 'Fl WRG 4s', 18, 6, 'WRG', 'Torre roja bandas blancas. Sector 9 grados. Rumbo 142', 'LIGHTS', '142'),
# BOYAS LATERALES CANAL RIO MAGDALENA
(199, 'Boya No. 1', 11, 5.07, 74, 50.01, 'Fl G 3s', 4, 6, 'G', 'Castillete verde', 'BOYLAT', ''),
(200, 'Boya No. 3', 11, 4.55, 74, 50.69, 'Fl G 3s', 4, 6, 'G', 'Castillete verde', 'BOYLAT', ''),
(202, 'Boya No. 5', 11, 3.94, 74, 50.46, 'Q G 1s', 4, 6, 'G', 'Castillete verde', 'BOYLAT', ''),
(208, 'Boya No. 7', 11, 3.60, 74, 50.25, 'Fl G 3s', 4, 6, 'G', 'Castillete verde', 'BOYLAT', ''),
(209, 'Boya No. 9', 11, 2.81, 74, 49.44, 'Fl G 3s', 4, 6, 'G', 'Castillete verde', 'BOYLAT', ''),
(210, 'Boya No. 11', 11, 2.38, 74, 48.73, 'Fl G 3s', 4, 6, 'G', 'Castillete verde', 'BOYLAT', ''),
(211, 'Boya No. 12', 11, 2.23, 74, 48.81, 'Fl R 3s', 4, 6, 'R', 'Castillete roja', 'BOYLAT', ''),
(212, 'Boya No. 13', 11, 2.06, 74, 48.12, 'Fl G 3s', 4, 6, 'G', 'Castillete verde', 'BOYLAT', ''),
(213, 'Boya No. 14', 11, 1.31, 74, 47.30, 'Fl R 3s', 3, 6, 'R', 'Castillete roja', 'BOYLAT', ''),
(214, 'Boya No. 15', 11, 1.69, 74, 47.63, 'Fl G 3s', 4, 6, 'G', 'Castillete verde', 'BOYLAT', ''),
(215, 'Boya No. 16', 11, 1.64, 74, 47.85, 'Fl R 3s', 4, 6, 'R', 'Castillete roja', 'BOYLAT', ''),
(218, 'Boya No. 18', 11, 1.31, 74, 47.30, 'Fl R 3s', 4, 6, 'R', 'Castillete roja', 'BOYLAT', ''),
(219, 'Boya No. 19', 11, 1.05, 74, 46.59, 'Fl G 3s', 4, 6, 'G', 'Castillete verde', 'BOYLAT', ''),
(220, 'Boya No. 20', 11, 0.93, 74, 46.64, 'Fl R 3s', 4, 6, 'R', 'Castillete roja', 'BOYLAT', ''),
(221, 'Boya No. 21', 11, 0.84, 74, 46.32, 'Fl G 3s', 4, 6, 'G', 'Castillete verde', 'BOYLAT', ''),
(222, 'Boya No. 22', 11, 0.74, 74, 46.40, 'Q R 1s', 4, 6, 'R', 'Castillete roja', 'BOYLAT', ''),
(223, 'Boya No. 23', 10, 58.50, 74, 45.30, 'Fl G 1.3s', 3, 6, 'G', 'Castillete verde', 'BOYLAT', ''),
(224, 'Boya No. 24', 11, 0.55, 74, 46.23, 'Fl R 3s', 4, 6, 'R', 'Castillete roja', 'BOYLAT', ''),
(225, 'Boya No. 25', 11, 0.40, 74, 45.98, 'Fl G 3s', 4, 6, 'G', 'Castillete verde', 'BOYLAT', ''),
(226, 'Boya No. 26', 11, 0.35, 74, 46.10, 'Fl R 3s', 4, 6, 'R', 'Castillete roja', 'BOYLAT', ''),
(227, 'Boya No. 27', 10, 59.91, 74, 45.72, 'Fl G 3s', 4, 6, 'G', 'Castillete verde', 'BOYLAT', ''),
(228, 'Boya No. 28', 10, 59.99, 74, 45.92, 'Fl R 3s', 4, 6, 'R', 'Castillete roja', 'BOYLAT', ''),
(229, 'Boya No. 29', 10, 59.24, 74, 45.48, 'Fl G 3s', 4, 6, 'G', 'Castillete verde', 'BOYLAT', ''),
(230, 'Boya No. 30', 10, 59.24, 74, 45.64, 'Fl R 3s', 4, 6, 'R', 'Castillete roja', 'BOYLAT', ''),
(231, 'Boya No. 31', 10, 58.50, 74, 45.29, 'Fl G 3s', 4, 6, 'G', 'Castillete verde', 'BOYLAT', ''),
(232, 'Boya No. 33', 10, 57.56, 74, 45.34, 'Fl G 3s', 4, 6, 'G', 'Castillete verde', 'BOYLAT', ''),
(233, 'Boya No. 35', 10, 56.56, 74, 45.25, 'Fl G 3s', 4, 6, 'G', 'Castillete verde', 'BOYLAT', ''),
(234, 'Boya No. 36', 10, 56.49, 74, 45.40, 'Fl R 3s', 4, 6, 'R', 'Castillete roja', 'BOYLAT', ''),
(235, 'Boya Cardinal Norte', 10, 57.55, 74, 45.21, 'Fl W 1s', 4, 6, 'W', 'Castillete cardinal N negros', 'BOYCAR', ''),
(236, 'Boya Cardinal Sur', 10, 57.55, 74, 45.21, 'Fl W 15s', 4, 6, 'W', 'Castillete cardinal S negros', 'BOYCAR', ''),
(239, 'Boya de Oleaje', 11, 8.04, 74, 45.48, 'Fl Y 20s', 0.5, 4.5, 'Y', 'Esferica amarilla. Recolectora datos oceanograficos', 'BOYSPEC', ''),
(240, 'Boya Peligro Aislado', 10, 57.27, 74, 45.44, 'Fl(2) W 4s', 3.3, 3, 'W', 'Castillete roja bandas negras. Bajo rocoso', 'BOYISD', ''),
]
# ════════════════════════════════════════════════════════════════════════════
# IHO S-57 Ed.3.1 — códigos OFICIALES (no inventados)
# Ref: s57attributes.csv distribuido con GDAL/OGR
# ════════════════════════════════════════════════════════════════════════════
# COLOUR codes (ATTL 75)
colour_s57 = {
'W': '1', # White
'K': '2', # Black
'R': '3', # Red
'G': '4', # Green
'B': '5', # Blue
'Y': '6', # Yellow
'Gy': '7', # Grey
'Br': '8', # Brown
'Amb': '9', # Amber
'Vi': '10', # Violet
'Or': '11', # Orange
'Mg': '12', # Magenta
'WRG': '1,3,4', # White/Red/Green (multi-colour sectors)
'': '1', # default white
}
colour_name = {
'W': 'white', 'K': 'black', 'R': 'red', 'G': 'green',
'B': 'blue', 'Y': 'yellow', 'Gy': 'grey', 'Br': 'brown',
'Amb': 'amber','Vi': 'violet','Or': 'orange', 'Mg': 'magenta',
'WRG': 'white/red/green', '': 'white',
}
# LITCHR codes (ATTL 107) — S-57 Ed.3.1 official values
char_map = {
'F': '1', # Fixed
'Fl': '2', # Flashing
'LFl': '3', # Long flashing
'Q': '4', # Quick (50-60/min)
'VQ': '5', # Very quick (100-120/min)
'UQ': '6', # Ultra quick (≥160/min)
'Iso': '7', # Isophase
'Oc': '8', # Occulting
'IQ': '9', # Interrupted quick
'IVQ': '10', # Interrupted very quick
'IUQ': '11', # Interrupted ultra quick
'Mo': '12', # Morse code
'FFl': '13', # Fixed and flashing
'Fl+LFl': '14',
'Oc+Fl': '15',
'Al.Oc': '25',
'Al.LFl': '26',
'Al.Fl': '27',
'Al.Grp': '28',
}
# BOYSHP codes (ATTL 4)
# 1=Conical 2=Can 3=Sphere 4=Pillar 5=Spar 6=Barrel 7=Super-buoy 8=Ice buoy
# Barranquilla buoys are "castillete" → pillar (4)
BOYSHP_CASTILLETE = '4'
# BCNSHP codes (ATTL 2)
# 1=Stake 2=Withy 3=Tower 4=Lattice 5=Pile 6=Cairn 7=Buoyant beacon
# "Torre" → 3, "Baliza enrejado" / "celosía" → 4
def bcnshp_from_desc(desc):
d = desc.lower()
if 'enrejad' in d or 'celosí' in d or 'lattice' in d:
return '4' # Lattice tower
return '3' # Solid tower (default)
# CATLAM codes (ATTL 36) for IALA-B (Américas):
# Green marks = port side (left hand entering) → CATLAM=1
# Red marks = starboard side (right hand entering) → CATLAM=2
def catlam_from_colour(col_letter):
return {'G': '1', 'R': '2'}.get(col_letter, '')
# CATCAM codes (ATTL 13) for cardinal marks:
# 1=N 2=E 3=S 4=W
def catcam_from_name(name):
nl = name.lower()
if 'norte' in nl or 'north' in nl: return '1'
if 'este' in nl or 'east' in nl: return '2'
if 'sur' in nl or 'south' in nl: return '3'
if 'oeste' in nl or 'west' in nl: return '4'
return ''
def parse_char(char_str):
"""Parse human-readable light character string → (litchr_code, siggrp, sigper).
Examples: 'Q(4)G 11s' → ('4','4','11')
'Fl W 4s' → ('2','','4')
'Iso Bu 5s' → ('7','','5')
"""
# Extract base character (longest prefix match, try longest first)
base = re.split(r'[\s\(\.]', char_str)[0]
# Try compound chars first (Al.Fl, Fl+LFl …)
litchr = None
for key in sorted(char_map, key=len, reverse=True):
if char_str.startswith(key):
litchr = char_map[key]
break
if litchr is None:
litchr = char_map.get(base, '2') # default Fl if unknown
mg = re.search(r'\((\d+)\)', char_str)
siggrp = mg.group(1) if mg else ''
mp = re.search(r'([\d.]+)s', char_str)
sigper = mp.group(1) if mp else ''
return litchr, siggrp, sigper
# ────────────────────────────────────────────────────────────────────────────
# Campos del CSV de salida — usan nombres de atributos S-57 directamente
# para que el converter los recoja sin ningún mapeo adicional.
# ────────────────────────────────────────────────────────────────────────────
fields = ['no_dimar', 'OBJNAM', 'lon', 'lat', 'feat_type',
'LITCHR', 'LITCHR_TXT', 'SIGGRP', 'SIGPER',
'COLOUR', 'COLOUR_TXT', 'COLPAT',
'VALNMR', 'HEIGHT', 'ORIENT',
'CATLAM', 'CATCAM', 'BOYSHP', 'BCNSHP', 'TOPSHP',
'INFORM', '_dimar_char_raw', '_source']
out_path = r'D:\Proyectos Software\QGISS57Converter\dimar_ayudas_barranquilla.csv'
with open(out_path, 'w', newline='', encoding='utf-8') as f:
w = csv.DictWriter(f, fieldnames=fields)
w.writeheader()
for rec in records:
no, name, lat_d, lat_m, lon_d, lon_m, char, ht, rng, col, desc, ftype, orient = rec
lat = dms_to_dd(lat_d, lat_m)
lon = -dms_to_dd(lon_d, lon_m) # West = negative
litchr, siggrp, sigper = parse_char(char)
catlam = ''
catcam = ''
boyshp = ''
bcnshp = ''
topshp = ''
colpat = ''
if ftype == 'BOYLAT':
# Castillete lateral: pillar (4), with CATLAM
boyshp = BOYSHP_CASTILLETE
catlam = catlam_from_colour(col)
elif ftype == 'BCNLAT':
# Faros de orilla (X marks): shore fixed beacon with CATLAM
bcnshp = bcnshp_from_desc(desc)
catlam = catlam_from_colour(col)
elif ftype in ('BOYCAR', 'BCNCAR'):
boyshp = '4' # pillar for cardinal buoys
catcam = catcam_from_name(name)
colpat = '1' # horizontal bands (standard cardinal pattern)
elif ftype == 'BOYISD':
boyshp = '4'
colpat = '1' # horizontal bands (black over red)
elif ftype == 'BOYSAW':
boyshp = '1' # conical or spherical for safe water
colpat = '4' # vertical stripes (white/red)
elif ftype in ('BOYSPEC', 'BOYSPP'):
boyshp = '3' # sphere for special/data buoys
ftype = 'BOYSPP' # normalise to S-57 acronym
w.writerow({
'no_dimar': no,
'OBJNAM': name,
'lon': f'{lon:.6f}',
'lat': f'{lat:.6f}',
'feat_type': ftype,
'LITCHR': litchr,
'LITCHR_TXT': char.split()[0],
'SIGGRP': siggrp,
'SIGPER': sigper,
'COLOUR': colour_s57.get(col, '1'),
'COLOUR_TXT': colour_name.get(col, 'white'),
'COLPAT': colpat,
'VALNMR': rng,
'HEIGHT': ht,
'ORIENT': orient,
'CATLAM': catlam,
'CATCAM': catcam,
'BOYSHP': boyshp,
'BCNSHP': bcnshp,
'TOPSHP': topshp,
'INFORM': desc,
'_dimar_char_raw': char,
'_source': 'DIMAR Lista de Luces 2015',
})
print(f'Saved {len(records)} records -> {out_path}')
types = Counter(r[11] for r in records)
for t, c in sorted(types.items()):
print(f' {t}: {c}')