diff --git a/config/s52/cm95_s52_runtime_capabilities_web_compare_v1.json b/config/s52/cm95_s52_runtime_capabilities_web_compare_v1.json index 53caea8..cd19b7d 100644 --- a/config/s52/cm95_s52_runtime_capabilities_web_compare_v1.json +++ b/config/s52/cm95_s52_runtime_capabilities_web_compare_v1.json @@ -19,27 +19,28 @@ ] }, "RUNTIME_DEPARE": { - "status": "PREVIEW_ONLY", - "fidelity": "DEFAULT_MARINER_SETTINGS_PREVIEW", + "status": "IMPLEMENTED", + "fidelity": "ORDERED_RUNTIME_RULE_IR", "evidence": [ { - "path": "web/kyushu_compare.html", + "path": "web/s52_runtime_executor.js", "contains": [ - "runtime-preview-depare", - "runtimeDepthColorExpression" + "RuntimeExecutor", + "dynamicRules" ] } ] }, "RUNTIME_DEPCNT": { - "status": "PREVIEW_ONLY", - "fidelity": "DEFAULT_MARINER_SETTINGS_PREVIEW", + "status": "IMPLEMENTED", + "fidelity": "SAFE_LOOKUP_QUAPOS_AND_SIDE_EFFECTS", "evidence": [ { - "path": "web/kyushu_compare.html", + "path": "web/s52_runtime_executor.js", "contains": [ - "runtime-preview-depcnt", - "updateRuntimeSafetyContour" + "RuntimeExecutor", + "s52_safe_dashed_rule_chain", + "scamin:100000001" ] } ] @@ -49,22 +50,22 @@ "fidelity": "TEXT_VALUE_ONLY_NOT_S52_GLYPH_COMPOSITION", "evidence": [ { - "path": "web/kyushu_compare.html", + "path": "web/s52_runtime_executor.js", "contains": [ - "runtime-preview-soundg" + "soundingRules" ] } ] }, "RUNTIME_OBSTRN": { - "status": "PREVIEW_ONLY", - "fidelity": "POINT_SYMBOL_RUNTIME_ONLY_AREA_LINE_PENDING", + "status": "IMPLEMENTED", + "fidelity": "ORDERED_POINT_LINE_AREA_RULE_CHAIN", "evidence": [ { - "path": "web/kyushu_compare.html", + "path": "web/s52_runtime_executor.js", "contains": [ - "runtime-preview-hazard-symbols", - "runtimeHazardSymbol", + "hazardRules", + "operationFeatures", "OBSTRN04", "ISODGR51" ] @@ -72,14 +73,14 @@ ] }, "RUNTIME_WRECKS": { - "status": "PREVIEW_ONLY", - "fidelity": "POINT_SYMBOL_RUNTIME_ONLY_AREA_LINE_PENDING", + "status": "IMPLEMENTED", + "fidelity": "ORDERED_POINT_LINE_AREA_RULE_CHAIN", "evidence": [ { - "path": "web/kyushu_compare.html", + "path": "web/s52_runtime_executor.js", "contains": [ - "runtime-preview-hazard-symbols", - "runtimeHazardSymbol", + "hazardRules", + "operationFeatures", "WRECKS02" ] } diff --git a/src/cm95pbf/csp.py b/src/cm95pbf/csp.py index e73093b..a35bac2 100644 --- a/src/cm95pbf/csp.py +++ b/src/cm95pbf/csp.py @@ -620,6 +620,10 @@ def materialize_mariner_runtime_facts( ) if name in {"OBSTRN04", "WRECKS02"}: + valsou = _optional_float(attrs.get("VALSOU")) + out["s52_valsou_present"] = int(valsou is not None) + if valsou is not None: + out["s52_valsou_m"] = valsou hazard_depth = _runtime_hazard_depth( name, object_class, geometry_type, attrs, associated_depth_ranges ) @@ -634,6 +638,17 @@ def materialize_mariner_runtime_facts( out["s52_surrounding_max_drval1_m"] = max(lows) if highs: out["s52_surrounding_min_drval2_m"] = min(highs) + quality = resolve_quapnt01_instruction(attrs) + out["s52_hazard_quality_rule_chain"] = materialize_rule_ir( + quality, attrs, source="nested_csp", procedure="QUAPNT01" + ) + if name == "OBSTRN04" and attrs.get("OBJNAM") not in (None, ""): + out["s52_hazard_name_rule_chain"] = materialize_rule_ir( + "TX(OBJNAM,1,2,3,'15118',-1,-1,CHBLK,26)", + attrs, + source="nested_csp", + procedure="OBJNAM", + ) scalar_codes = { "QUAPOS": "s52_quapos_code", diff --git a/src/cm95pbf/mapping.py b/src/cm95pbf/mapping.py index 2fd682a..812ab16 100644 --- a/src/cm95pbf/mapping.py +++ b/src/cm95pbf/mapping.py @@ -56,6 +56,10 @@ DELIVERY_PROPERTY_ALLOWLIST = frozenset( "s52_display_base_promoted", "s52_hazard_depth_m", "s52_hazard_procedure", + "s52_hazard_quality_rule_chain", + "s52_hazard_name_rule_chain", + "s52_valsou_present", + "s52_valsou_m", "s52_isolated_danger", "s52_surrounding_max_drval1_m", "s52_surrounding_min_drval2_m", diff --git a/tools/cm95_s52_style_compiler.py b/tools/cm95_s52_style_compiler.py index 97bdee5..6897027 100755 --- a/tools/cm95_s52_style_compiler.py +++ b/tools/cm95_s52_style_compiler.py @@ -170,6 +170,8 @@ USAGE_VALUE_FIELDS = ( "s52_area_color", "s52_area_pattern_code", "s52_line_color", + "s52_line1_color", + "s52_line2_color", "s52_line_complex_code", "s52_text1_color", "s52_text2_color", @@ -184,6 +186,10 @@ USAGE_PRESENCE_FIELDS = ( "s52_text1_value", "s52_text2_value", "s52_text3_value", + "s52_line1_style", + "s52_line1_width", + "s52_line2_style", + "s52_line2_width", ) @@ -245,9 +251,13 @@ def _scan_pbf_usage(path: Path) -> dict[str, Any]: render_kind_counts["AP"][placement] += 1 else: geometry_ignored[("AP", layer_name, geometry_type)] += 1 - if "s52_line_color" in props: + line_slots = [ + slot for slot in (1, 2) + if f"s52_line{slot}_color" in props + ] + if line_slots or "s52_line_color" in props: if line_geometry: - render_kind_counts["LS"][placement] += 1 + render_kind_counts["LS"][placement] += max(1, len(line_slots)) else: geometry_ignored[("LS", layer_name, geometry_type)] += 1 if "s52_line_complex_code" in props: @@ -540,7 +550,7 @@ def _compile_style( materialized_priority_fields = { "AC": ("s52_area_color",), "AP": ("s52_area_pattern_code",), - "LS": ("s52_line_color",), + "LS": ("s52_line_color", "s52_line1_color", "s52_line2_color"), "LC": ("s52_line_complex_code",), "SY": ("s52_symbol_code",), "TX/TE": ("s52_text1_value", "s52_text2_value", "s52_text3_value"), @@ -578,6 +588,8 @@ def _compile_style( for field in ( "s52_area_color", "s52_line_color", + "s52_line1_color", + "s52_line2_color", "s52_text1_color", "s52_text2_color", "s52_text3_color", @@ -690,42 +702,77 @@ def _compile_style( ) compiled_placements["AP"].add((layer_name, priority)) - if ( - "line" in caps - and priority in opcode_priorities["LS"] - and _field_used(usage, layer_name, "s52_line_color", priority) - ): - _add_layer( - layers, - compiled_counts, - "LS", - { - "id": f"{prefix}-ls-{layer_id}", - "type": "line", - "source": source_id, - "source-layer": layer_name, - "filter": _base_filter( - priority=priority, - categories=categories, - required_field="s52_line_color", - ), - "paint": { - "line-color": color_line, - "line-width": [ - "to-number", - ["get", "s52_line_width"], - float(config.get("line_width_fallback", 1.0)), - ], - "line-dasharray": [ - "case", - ["==", ["get", "s52_line_style"], "DASH"], - ["literal", [4, 2]], - ["literal", [1, 0]], - ], + if "line" in caps and priority in opcode_priorities["LS"]: + for slot in (1, 2): + color_field = f"s52_line{slot}_color" + if not _field_used(usage, layer_name, color_field, priority): + continue + style_field = f"s52_line{slot}_style" + width_field = f"s52_line{slot}_width" + _add_layer( + layers, + compiled_counts, + "LS", + { + "id": f"{prefix}-ls{slot}-{layer_id}", + "type": "line", + "source": source_id, + "source-layer": layer_name, + "filter": _base_filter( + priority=priority, + categories=categories, + required_field=color_field, + ), + "layout": {"line-cap": "round"}, + "paint": { + "line-color": _color_expression( + color_field, active_colors, fallback + ), + "line-width": [ + "to-number", ["get", width_field], + float(config.get("line_width_fallback", 1.0)), + ], + "line-dasharray": [ + "match", ["get", style_field], + "DASH", ["literal", [4, 2]], + "DOTT", ["literal", [1, 2]], + ["literal", [1, 0]], + ], + }, }, - }, - ) - compiled_placements["LS"].add((layer_name, priority)) + ) + compiled_placements["LS"].add((layer_name, priority)) + + if _field_used(usage, layer_name, "s52_line_color", priority): + _add_layer( + layers, + compiled_counts, + "LS", + { + "id": f"{prefix}-ls-legacy-{layer_id}", + "type": "line", + "source": source_id, + "source-layer": layer_name, + "filter": _base_filter( + priority=priority, + categories=categories, + required_field="s52_line_color", + forbidden_field="s52_line1_color", + ), + "layout": {"line-cap": "round"}, + "paint": { + "line-color": color_line, + "line-width": ["to-number", ["get", "s52_line_width"], 1], + "line-dasharray": [ + "match", ["get", "s52_line_style"], + "DASH", ["literal", [4, 2]], + "DOTT", ["literal", [1, 2]], + ["literal", [1, 0]], + ], + }, + }, + ) + compiled_placements["LS"].add((layer_name, priority)) if ( "line" in caps and lc_mapping @@ -1172,6 +1219,8 @@ def _compile_style( for field in ( "s52_area_color", "s52_line_color", + "s52_line1_color", + "s52_line2_color", "s52_text1_color", "s52_text2_color", "s52_text3_color", diff --git a/web/kyushu_compare.html b/web/kyushu_compare.html index 6f2d269..a86c03e 100644 --- a/web/kyushu_compare.html +++ b/web/kyushu_compare.html @@ -76,6 +76,7 @@ +