fix: align local S-52 CSP decisions with OpenCPN
This commit is contained in:
@@ -145,13 +145,14 @@ def _optional_float(value: Any) -> float | None:
|
||||
return None
|
||||
|
||||
|
||||
def _light_color_ref(colours: list[int]) -> str:
|
||||
def _light_color_ref(colours: list[int], *, sector: bool = False) -> str:
|
||||
if len(colours) == 1:
|
||||
if 3 in colours:
|
||||
return "LITRD"
|
||||
if 4 in colours:
|
||||
return "LITGN"
|
||||
if any(code in colours for code in (1, 6, 11)):
|
||||
# OpenCPN uses orange (11) for sectors, amber (9) for flares/circles.
|
||||
if any(code in colours for code in (1, 6, 11 if sector else 9)):
|
||||
return "LITYW"
|
||||
return "CHMGD"
|
||||
if len(colours) == 2:
|
||||
@@ -193,7 +194,7 @@ _LIGHT_CHARACTER = {
|
||||
}
|
||||
|
||||
|
||||
def _light_description(attrs: dict[str, Any], *, has_sector: bool) -> str:
|
||||
def _light_description(attrs: dict[str, Any]) -> str:
|
||||
try:
|
||||
litchr = int(attrs.get("LITCHR"))
|
||||
except (TypeError, ValueError):
|
||||
@@ -201,18 +202,18 @@ def _light_description(attrs: dict[str, Any], *, has_sector: bool) -> str:
|
||||
text = _LIGHT_CHARACTER.get(litchr, "")
|
||||
two_groups = litchr in {13, 14, 15, 16, 25, 26, 27, 29}
|
||||
siggrp = str(attrs.get("SIGGRP") or "").strip()
|
||||
if siggrp:
|
||||
groups = [part for part in siggrp.replace(")(", ",").strip("()").split(",") if part]
|
||||
if two_groups and groups:
|
||||
first = groups[0]
|
||||
if " + " in text:
|
||||
left, right = text.split(" + ", 1)
|
||||
text = f"{left}({first}) + {right}"
|
||||
if len(groups) > 1 and groups[1] != "1":
|
||||
text += f"({groups[1]})"
|
||||
elif siggrp != "(1)":
|
||||
text += siggrp
|
||||
if two_groups:
|
||||
groups = [part for part in siggrp.replace("(", ")").split(")") if part]
|
||||
first = groups[0][0] if groups else "?"
|
||||
left, right = text.split(" + ", 1)
|
||||
text = f"{left}({first}) + {right}"
|
||||
if len(groups) > 1 and groups[1] != "1":
|
||||
text += f"({groups[1]})"
|
||||
elif siggrp and siggrp != "(1)":
|
||||
text += siggrp
|
||||
|
||||
# Description suppression depends on SECTR1 presence, not sector validity.
|
||||
has_sector = "SECTR1" in attrs
|
||||
if not has_sector:
|
||||
colour_codes = {1: "W", 3: "R", 4: "G", 6: "Y"}
|
||||
colours = "".join(colour_codes.get(code, "") for code in _int_list(attrs.get("COLOUR")))
|
||||
@@ -243,7 +244,7 @@ def resolve_lights05_instruction(attrs: dict[str, Any]) -> tuple[str, dict[str,
|
||||
|
||||
sectr1 = _optional_float(attrs.get("SECTR1"))
|
||||
sectr2 = _optional_float(attrs.get("SECTR2"))
|
||||
has_sector = sectr1 is not None and sectr2 is not None
|
||||
has_sector = sectr1 not in (None, -9.0) and sectr2 not in (None, -9.0)
|
||||
colours = _int_list(attrs.get("COLOUR")) or [12]
|
||||
extra: dict[str, Any] = {
|
||||
"s52_light_nominal_range_nm": float(valnmr),
|
||||
@@ -266,7 +267,7 @@ def resolve_lights05_instruction(attrs: dict[str, Any]) -> tuple[str, dict[str,
|
||||
else:
|
||||
radius = _light_radius_mm(valnmr)
|
||||
color = _light_color_ref(colours)
|
||||
radius_adjust = {"LITRD": 1.0, "LITGN": 0.0, "LITYW": 2.0, "CHMGD": 3.0}.get(color, 5.0)
|
||||
radius_adjust = {"LITRD": 1.0, "LITGN": 0.0, "LITYW": 2.0}.get(color, 3.0 if colours == [12] else 5.0)
|
||||
instruction = f"CA(OUTLW,4,{color},2,0,360,{radius + radius_adjust:.1f},0)"
|
||||
extra["s52_light_mode"] = "all_round"
|
||||
else:
|
||||
@@ -275,12 +276,12 @@ def resolve_lights05_instruction(attrs: dict[str, Any]) -> tuple[str, dict[str,
|
||||
if sweep < 1.0:
|
||||
radius = _light_radius_mm(valnmr)
|
||||
color = _light_color_ref(colours)
|
||||
radius_adjust = {"LITRD": 1.0, "LITGN": 0.0, "LITYW": 2.0, "CHMGD": 3.0}.get(color, 5.0)
|
||||
radius_adjust = {"LITRD": 1.0, "LITGN": 0.0, "LITYW": 2.0}.get(color, 3.0 if colours == [12] else 5.0)
|
||||
instruction = f"CA(OUTLW,4,{color},2,0,360,{radius + radius_adjust:.1f},0)"
|
||||
extra["s52_light_mode"] = "all_round"
|
||||
else:
|
||||
arc_radius = 10.0 if 0 < valnmr < 15.0 else 15.0 if valnmr < 30.0 else 20.0
|
||||
color = _light_color_ref(colours)
|
||||
arc_radius = 10.0 if 0 < valnmr < 15.0 else 15.0 if 15.0 <= valnmr < 30.0 else 20.0
|
||||
color = _light_color_ref(colours, sector=True)
|
||||
outline_color, outline_width, arc_width = "OUTLW", 4, 2
|
||||
litvis = _int_list(attrs.get("LITVIS"))
|
||||
if any(code in litvis for code in (3, 7, 8)):
|
||||
@@ -298,7 +299,7 @@ def resolve_lights05_instruction(attrs: dict[str, Any]) -> tuple[str, dict[str,
|
||||
"s52_sector_sweep_deg": float(sweep),
|
||||
})
|
||||
|
||||
description = _light_description(attrs, has_sector=has_sector)
|
||||
description = _light_description(attrs)
|
||||
if description:
|
||||
safe = description.replace("'", "’")
|
||||
instruction += f";TX('{safe}',3,2,3,'15110',2,0,CHBLK,23)"
|
||||
@@ -760,10 +761,16 @@ def resolve_wrecks02_instruction(
|
||||
quapos = _int_attr(attrs, "QUAPOS", 0)
|
||||
if 2 <= quapos < 10:
|
||||
line = "LC(LOWACC41)"
|
||||
elif udw or valsou is None or valsou <= 20.0:
|
||||
line = "LS(DOTT,2,CHBLK)" if udw or valsou is not None else "LS(DOTT,2,CSTLN)"
|
||||
else:
|
||||
elif udw or (valsou is not None and valsou <= 20.0):
|
||||
line = "LS(DOTT,2,CHBLK)"
|
||||
elif valsou is not None:
|
||||
line = "LS(DASH,2,CHBLK)"
|
||||
elif watlev in {1, 2}:
|
||||
line = "LS(SOLD,2,CSTLN)"
|
||||
elif watlev == 4:
|
||||
line = "LS(DASH,2,CSTLN)"
|
||||
else:
|
||||
line = "LS(DOTT,2,CSTLN)"
|
||||
instruction = line
|
||||
if valsou is not None and valsou <= 20.0:
|
||||
instruction += ";" + udw if udw else ""
|
||||
@@ -836,8 +843,9 @@ def resolve_slcons03_instruction(
|
||||
if geom == "AREA":
|
||||
instructions.append("AP(CROSSX01)")
|
||||
|
||||
if quapos_present and 2 <= quapos < 10:
|
||||
instructions.append("LC(LOWACC21)")
|
||||
if quapos_present:
|
||||
if 2 <= quapos < 10:
|
||||
instructions.append("LC(LOWACC01)")
|
||||
return ";".join(instructions)
|
||||
|
||||
condtn = _int_attr(attrs, "CONDTN", 0)
|
||||
@@ -860,13 +868,13 @@ def resolve_restrn01_instruction(attrs: dict[str, Any]) -> str:
|
||||
if not restrn:
|
||||
return ""
|
||||
if restrn & {7, 8, 14}:
|
||||
symbol = "ENTRES61" if restrn & {1, 2, 3, 4, 5, 6} else "ENTRES71" if restrn & {9, 10, 11, 12, 13, 14, 15} else "ENTRES51"
|
||||
symbol = "ENTRES61" if restrn & {1, 2, 3, 4, 5, 6} else "ENTRES71" if restrn & {9, 10, 11, 12, 13} else "ENTRES51"
|
||||
elif restrn & {1, 2}:
|
||||
symbol = "ACHRES61" if restrn & {3, 4, 5, 6} else "ACHRES71" if restrn & {9, 10, 11, 12, 13, 14, 15} else "ACHRES51"
|
||||
symbol = "ACHRES61" if restrn & {3, 4, 5, 6} else "ACHRES71" if restrn & {9, 10, 11, 12, 13} else "ACHRES51"
|
||||
elif restrn & {3, 4, 5, 6}:
|
||||
symbol = "FSHRES71" if restrn & {9, 10, 11, 12, 13, 14, 15} else "FSHRES51"
|
||||
symbol = "FSHRES71" if restrn & {9, 10, 11, 12, 13} else "FSHRES51"
|
||||
else:
|
||||
symbol = "INFARE51" if restrn & {9, 10, 11, 12, 13, 14, 15} else "RSRDEF51"
|
||||
symbol = "INFARE51" if restrn & {9, 10, 11, 12, 13} else "RSRDEF51"
|
||||
return f"SY({symbol})"
|
||||
|
||||
|
||||
@@ -878,18 +886,18 @@ def resolve_resare02_instruction(
|
||||
group_a = {1, 8, 9, 12, 14, 19, 21, 25}
|
||||
group_b = {4, 5, 6, 7, 10, 18, 20, 22, 23, 24}
|
||||
priority = False
|
||||
if restrn:
|
||||
if "RESTRN" in attrs:
|
||||
if restrn & {7, 8, 14}:
|
||||
symbol = "ENTRES61" if (restrn & {1,2,3,4,5,6} or catrea & group_a) else "ENTRES71" if (restrn & {9,10,11,12,13,14,15} or catrea & group_b) else "ENTRES51"
|
||||
symbol = "ENTRES61" if (restrn & {1,2,3,4,5,6} or catrea & group_a) else "ENTRES71" if (restrn & {9,10,11,12,13} or catrea & group_b) else "ENTRES51"
|
||||
line_code = "RESARE51"; priority = True
|
||||
elif restrn & {1, 2}:
|
||||
symbol = "ACHRES61" if (restrn & {3,4,5,6} or catrea & group_a) else "ACHRES71" if (restrn & {9,10,11,12,13,14,15} or catrea & group_b) else "RESTRN51"
|
||||
symbol = "ACHRES61" if (restrn & {3,4,5,6} or catrea & group_a) else "ACHRES71" if (restrn & {9,10,11,12,13} or catrea & group_b) else "RESTRN51"
|
||||
line_code = "RESARE51"; priority = True
|
||||
elif restrn & {3,4,5,6}:
|
||||
symbol = "FSHRES51" if catrea & group_a else "FSHRES71" if (restrn & {9,10,11,12,13,14,15} or catrea & group_b) else "FSHRES51"
|
||||
symbol = "FSHRES51" if catrea & group_a else "FSHRES71" if (restrn & {9,10,11,12,13} or catrea & group_b) else "FSHRES51"
|
||||
line_code = "FSHRES51"; priority = True
|
||||
else:
|
||||
symbol = "INFARE51" if restrn & {9,10,11,12,13,14,15} else "RSRDEF51"
|
||||
symbol = "INFARE51" if restrn & {9,10,11,12,13} else "RSRDEF51"
|
||||
line_code = "CTYARE51"
|
||||
else:
|
||||
symbol = "CTYARE71" if (catrea & group_a and catrea & group_b) else "CTYARE51" if catrea & group_a else "INFARE51" if catrea & group_b else "RSRDEF51"
|
||||
|
||||
Reference in New Issue
Block a user