feat: add Kyushu semantic icon test delivery
This commit is contained in:
147
navsea_audit_kyushu_semantic_icon_test.py
Normal file
147
navsea_audit_kyushu_semantic_icon_test.py
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""审计九州语义图标测试版是否丢失对象、几何或非图标属性。"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
from collections import Counter
|
||||||
|
from concurrent.futures import ProcessPoolExecutor
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
import mapbox_vector_tile
|
||||||
|
|
||||||
|
|
||||||
|
EXPECTED_FIELDS = {"chart_icon_image", "icon_id", "arc_id"}
|
||||||
|
|
||||||
|
|
||||||
|
def stable(value: Any) -> str:
|
||||||
|
return json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(",", ":"))
|
||||||
|
|
||||||
|
|
||||||
|
def feature_signature(feature: dict[str, Any]) -> str:
|
||||||
|
properties = dict(feature.get("properties") or {})
|
||||||
|
for field in EXPECTED_FIELDS:
|
||||||
|
properties.pop(field, None)
|
||||||
|
return stable({
|
||||||
|
"id": feature.get("id"),
|
||||||
|
"geometry": feature.get("geometry"),
|
||||||
|
"properties": properties,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
def audit_tile(args: tuple[str, str]) -> dict[str, Any]:
|
||||||
|
source_path, target_path = args
|
||||||
|
source = mapbox_vector_tile.decode(Path(source_path).read_bytes())
|
||||||
|
target = mapbox_vector_tile.decode(Path(target_path).read_bytes())
|
||||||
|
errors: list[dict[str, Any]] = []
|
||||||
|
source_layers = set(source)
|
||||||
|
target_layers = set(target)
|
||||||
|
if source_layers != target_layers:
|
||||||
|
errors.append({"kind": "layer_set", "source": sorted(source_layers), "target": sorted(target_layers)})
|
||||||
|
|
||||||
|
source_counts = Counter()
|
||||||
|
target_counts = Counter()
|
||||||
|
icon_counts = Counter()
|
||||||
|
old_prefix_counts = Counter()
|
||||||
|
for layer_name in sorted(source_layers | target_layers):
|
||||||
|
source_features = source.get(layer_name, {}).get("features", [])
|
||||||
|
target_features = target.get(layer_name, {}).get("features", [])
|
||||||
|
source_counts[layer_name] = len(source_features)
|
||||||
|
target_counts[layer_name] = len(target_features)
|
||||||
|
source_signatures = Counter(feature_signature(feature) for feature in source_features)
|
||||||
|
target_signatures = Counter(feature_signature(feature) for feature in target_features)
|
||||||
|
if source_signatures != target_signatures:
|
||||||
|
missing = source_signatures - target_signatures
|
||||||
|
extra = target_signatures - source_signatures
|
||||||
|
errors.append({
|
||||||
|
"kind": "feature_or_geometry_or_property",
|
||||||
|
"layer": layer_name,
|
||||||
|
"source_count": len(source_features),
|
||||||
|
"target_count": len(target_features),
|
||||||
|
"missing_count": sum(missing.values()),
|
||||||
|
"extra_count": sum(extra.values()),
|
||||||
|
})
|
||||||
|
for feature in target_features:
|
||||||
|
properties = feature.get("properties") or {}
|
||||||
|
for field in ("icon_id", "arc_id"):
|
||||||
|
value = properties.get(field)
|
||||||
|
if isinstance(value, str):
|
||||||
|
icon_counts[f"{field}:{value}"] += 1
|
||||||
|
for value in properties.values():
|
||||||
|
if isinstance(value, str) and (value.startswith("symbol-daytime-") or value.startswith("arc-daytime-")):
|
||||||
|
old_prefix_counts[value] += 1
|
||||||
|
return {
|
||||||
|
"tile": source_path,
|
||||||
|
"errors": errors,
|
||||||
|
"source_counts": dict(source_counts),
|
||||||
|
"target_counts": dict(target_counts),
|
||||||
|
"icon_counts": dict(icon_counts),
|
||||||
|
"old_prefix_counts": dict(old_prefix_counts),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("--source-root", type=Path, required=True)
|
||||||
|
parser.add_argument("--target-root", type=Path, required=True)
|
||||||
|
parser.add_argument("--report-dir", type=Path, required=True)
|
||||||
|
args = parser.parse_args()
|
||||||
|
pairs = []
|
||||||
|
for target in sorted(args.target_root.glob("*/*/*.pbf")):
|
||||||
|
source = args.source_root / target.relative_to(args.target_root)
|
||||||
|
if source.exists():
|
||||||
|
pairs.append((str(source), str(target)))
|
||||||
|
|
||||||
|
results: list[dict[str, Any]] = []
|
||||||
|
with ProcessPoolExecutor() as executor:
|
||||||
|
for result in executor.map(audit_tile, pairs, chunksize=16):
|
||||||
|
results.append(result)
|
||||||
|
|
||||||
|
error_rows = [error | {"tile": result["tile"]} for result in results for error in result["errors"]]
|
||||||
|
icon_counts = Counter()
|
||||||
|
old_prefix_counts = Counter()
|
||||||
|
source_features = Counter()
|
||||||
|
target_features = Counter()
|
||||||
|
for result in results:
|
||||||
|
icon_counts.update(result["icon_counts"])
|
||||||
|
old_prefix_counts.update(result["old_prefix_counts"])
|
||||||
|
source_features.update(result["source_counts"])
|
||||||
|
target_features.update(result["target_counts"])
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
"source_root": str(args.source_root),
|
||||||
|
"target_root": str(args.target_root),
|
||||||
|
"tiles_target": len(list(args.target_root.glob("*/*/*.pbf"))),
|
||||||
|
"tiles_compared": len(results),
|
||||||
|
"tiles_with_errors": len({row["tile"] for row in error_rows}),
|
||||||
|
"errors": error_rows[:200],
|
||||||
|
"source_features": dict(source_features),
|
||||||
|
"target_features": dict(target_features),
|
||||||
|
"icon_counts": dict(icon_counts),
|
||||||
|
"old_prefix_counts": dict(old_prefix_counts),
|
||||||
|
"verdict": "PASS" if not error_rows and not old_prefix_counts else "FAIL",
|
||||||
|
}
|
||||||
|
args.report_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
(args.report_dir / "object_geometry_icon_audit.json").write_text(
|
||||||
|
json.dumps(payload, ensure_ascii=False, indent=2) + "\n", encoding="utf-8"
|
||||||
|
)
|
||||||
|
lines = [
|
||||||
|
"# 九州语义图标测试版对象 / 几何 / 图标审计",
|
||||||
|
"",
|
||||||
|
f"- 来源:`{args.source_root}`",
|
||||||
|
f"- 目标:`{args.target_root}`",
|
||||||
|
f"- 目标瓦片:`{payload['tiles_target']}`,实际比较:`{payload['tiles_compared']}`",
|
||||||
|
f"- 有错误瓦片:`{payload['tiles_with_errors']}`",
|
||||||
|
f"- 旧图标前缀残留:`{sum(old_prefix_counts.values())}`",
|
||||||
|
f"- 结论:`{payload['verdict']}`",
|
||||||
|
"",
|
||||||
|
"本审计忽略预期的 `chart_icon_image`、`icon_id`、`arc_id` 字段变化,逐图层比较对象数量、ID、几何和其余属性。",
|
||||||
|
]
|
||||||
|
(args.report_dir / "object_geometry_icon_audit.md").write_text("\n".join(lines) + "\n", encoding="utf-8")
|
||||||
|
print(json.dumps(payload, ensure_ascii=False, indent=2))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
425
navsea_build_kyushu_semantic_icon_test.py
Normal file
425
navsea_build_kyushu_semantic_icon_test.py
Normal file
@@ -0,0 +1,425 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""从当前全国 Full 基线生成九州语义图标替换测试包。"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
from collections import Counter
|
||||||
|
from concurrent.futures import ProcessPoolExecutor
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
import mercantile
|
||||||
|
|
||||||
|
from navsea_tile_reencode_guard import (
|
||||||
|
assert_reencoded_tile_safe,
|
||||||
|
decode_tile_with_extents,
|
||||||
|
encode_layers_preserving_extents,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
REPO_ROOT = Path(__file__).resolve().parent
|
||||||
|
CONFIG_PATH = REPO_ROOT / "tasks/pbf/navsea_semantic_icon_map_v1.json"
|
||||||
|
SOURCE_ROOT = Path("/home/wwwroot/pbf-delivery-full-20260418-rebuild")
|
||||||
|
TARGET_ROOT = Path("/home/wwwroot/pbf-delivery-kyushu-semantic-icon-v1-20260806")
|
||||||
|
TARGET_TILE_URL = "http://192.168.200.184/pbf-delivery-kyushu-semantic-icon-v1-20260806/{z}/{x}/{y}.pbf"
|
||||||
|
KYUSHU_BBOX = (128.0, 30.0, 132.5, 34.9)
|
||||||
|
ZOOMS = tuple(range(5, 13))
|
||||||
|
|
||||||
|
SPRITE_SOURCE = Path("/mnt/sda1/www/newpec/sprite-semantic")
|
||||||
|
SPRITE_TARGET = Path("/mnt/sda1/www/newpec/sprite-kyushu-semantic-icon-v1-20260806")
|
||||||
|
SPRITE_URL = "http://192.168.200.184/newpec/sprite-kyushu-semantic-icon-v1-20260806/sprite"
|
||||||
|
|
||||||
|
STYLE_SOURCE = REPO_ROOT / "src/pbf/style.navsea-delivery-full-semantic-extentfix.json"
|
||||||
|
STYLE_OUTPUT = REPO_ROOT / "src/pbf/style.navsea-delivery-kyushu-semantic-icon-v1.json"
|
||||||
|
STYLE_DEPLOY = Path("/mnt/sda1/www/newpec/domain/style.navsea-delivery-kyushu-semantic-icon-v1.json")
|
||||||
|
|
||||||
|
NEWPEC_STYLE_SOURCE = REPO_ROOT / "src/pbf/style.json"
|
||||||
|
NEWPEC_STYLE_OUTPUT = REPO_ROOT / "src/pbf/style.navsea-newpec-kyushu-icon-test-v1.json"
|
||||||
|
NEWPEC_STYLE_DEPLOY = Path("/mnt/sda1/www/newpec/domain/style.navsea-newpec-kyushu-icon-test-v1.json")
|
||||||
|
|
||||||
|
REPORT_DIR = REPO_ROOT / "report/kyushu_semantic_icon_v1_2026-08-06"
|
||||||
|
|
||||||
|
SIMPLE_ICON_LAYERS = {
|
||||||
|
"hazard-points",
|
||||||
|
"anchorage-symbols",
|
||||||
|
"anchor-hazard-points",
|
||||||
|
"anchor-hazard-points-428",
|
||||||
|
"facility-points",
|
||||||
|
"landmark-points",
|
||||||
|
}
|
||||||
|
|
||||||
|
STYLE_EXTRA_MAP = {
|
||||||
|
"light_flare_green": "fl_G",
|
||||||
|
"light_flare_red": "fl_R",
|
||||||
|
"light_flare_yellow_white": "fl_YW",
|
||||||
|
}
|
||||||
|
|
||||||
|
CANONICAL_ICON_MAP = {
|
||||||
|
"coastal_lighthouse_over_15m": "lt_cst",
|
||||||
|
"harbor_lighthouse": "lt_hbr",
|
||||||
|
"breakwater_lighthouse": "lt_bkw",
|
||||||
|
"minor_light": "lt_min",
|
||||||
|
"light_beacon": "lt_bcn",
|
||||||
|
"light_buoy": "bu_lit",
|
||||||
|
"lattice_buoy": "bu_lat",
|
||||||
|
"pillar_buoy": "bu_pil",
|
||||||
|
"can_buoy": "bu_can",
|
||||||
|
"buoy_generic": "bu_gen",
|
||||||
|
"nav_mark_vais": "mk_vais",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def load_config() -> dict[str, Any]:
|
||||||
|
return json.loads(CONFIG_PATH.read_text(encoding="utf-8"))
|
||||||
|
|
||||||
|
|
||||||
|
def collect_tiles() -> list[tuple[int, int, int, Path]]:
|
||||||
|
tiles: list[tuple[int, int, int, Path]] = []
|
||||||
|
west, south, east, north = KYUSHU_BBOX
|
||||||
|
for z in ZOOMS:
|
||||||
|
for tile in mercantile.tiles(west, south, east, north, [z]):
|
||||||
|
rel = Path(str(tile.z)) / str(tile.x) / f"{tile.y}.pbf"
|
||||||
|
source = SOURCE_ROOT / rel
|
||||||
|
if source.exists():
|
||||||
|
tiles.append((tile.z, tile.x, tile.y, rel))
|
||||||
|
return sorted(tiles)
|
||||||
|
|
||||||
|
|
||||||
|
def copy_link(source: Path, target: Path) -> None:
|
||||||
|
target.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
if target.exists():
|
||||||
|
target.unlink()
|
||||||
|
try:
|
||||||
|
target.hardlink_to(source)
|
||||||
|
except OSError:
|
||||||
|
shutil.copy2(source, target)
|
||||||
|
|
||||||
|
|
||||||
|
def class_icon(layer_name: str, class_code: object, config: dict[str, Any]) -> str | None:
|
||||||
|
code = str(class_code)
|
||||||
|
if layer_name in {"navigation_hazard_point", "anchor_caution_hazard_point"}:
|
||||||
|
return config["hazard_class_map"].get(code)
|
||||||
|
if layer_name == "onshore_structure_point":
|
||||||
|
return config["landmark_class_map"].get(code)
|
||||||
|
if layer_name == "anchorage_point":
|
||||||
|
return config["anchorage_class_map"].get(code)
|
||||||
|
if layer_name == "facility_boundary_point":
|
||||||
|
return config["facility_class_map"].get(code)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def navigation_icon(properties: dict[str, Any], config: dict[str, Any]) -> str | None:
|
||||||
|
legacy = properties.get("chart_icon_image")
|
||||||
|
if isinstance(legacy, str):
|
||||||
|
mapped = config["sprite_key_map"].get(legacy)
|
||||||
|
if mapped:
|
||||||
|
return mapped
|
||||||
|
display_code = properties.get("display_code")
|
||||||
|
if display_code is not None:
|
||||||
|
mapped = config["display_code_map"].get(str(display_code))
|
||||||
|
if mapped:
|
||||||
|
return mapped
|
||||||
|
canonical = properties.get("canonical_object_type")
|
||||||
|
if isinstance(canonical, str):
|
||||||
|
return CANONICAL_ICON_MAP.get(canonical)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def arc_icon(properties: dict[str, Any], config: dict[str, Any]) -> str | None:
|
||||||
|
if properties.get("chart_symbol_code") != "lighthouse":
|
||||||
|
return None
|
||||||
|
if not properties.get("light_color_code"):
|
||||||
|
return None
|
||||||
|
if (
|
||||||
|
properties.get("canonical_object_type") == "coastal_lighthouse_over_15m"
|
||||||
|
and properties.get("light_sector_mode") == "sector"
|
||||||
|
):
|
||||||
|
return config["arc_rules"]["sector"]
|
||||||
|
color = str(properties.get("light_color_code"))
|
||||||
|
return config["arc_rules"].get(color, config["arc_rules"]["other"])
|
||||||
|
|
||||||
|
|
||||||
|
def rewrite_tile(
|
||||||
|
source: Path,
|
||||||
|
target: Path,
|
||||||
|
config: dict[str, Any],
|
||||||
|
*,
|
||||||
|
verify_geometry: bool = False,
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
decoded, extents = decode_tile_with_extents(source.read_bytes())
|
||||||
|
changed_features = 0
|
||||||
|
icon_counts: Counter[str] = Counter()
|
||||||
|
arc_counts: Counter[str] = Counter()
|
||||||
|
old_values: Counter[str] = Counter()
|
||||||
|
unknown_old_values: Counter[str] = Counter()
|
||||||
|
output_layers: list[dict[str, Any]] = []
|
||||||
|
|
||||||
|
for layer_name, layer in decoded.items():
|
||||||
|
output_features = []
|
||||||
|
for feature in layer["features"]:
|
||||||
|
properties = dict(feature.get("properties") or {})
|
||||||
|
before = dict(properties)
|
||||||
|
legacy = properties.get("chart_icon_image")
|
||||||
|
if isinstance(legacy, str) and (
|
||||||
|
legacy.startswith("symbol-daytime-") or legacy.startswith("arc-daytime-")
|
||||||
|
):
|
||||||
|
old_values[legacy] += 1
|
||||||
|
|
||||||
|
icon_id = class_icon(layer_name, properties.get("class_code"), config)
|
||||||
|
if layer_name == "navigation_marks":
|
||||||
|
icon_id = icon_id or navigation_icon(properties, config)
|
||||||
|
if icon_id is None and isinstance(legacy, str):
|
||||||
|
icon_id = config["sprite_key_map"].get(legacy)
|
||||||
|
|
||||||
|
if icon_id:
|
||||||
|
properties["icon_id"] = icon_id
|
||||||
|
icon_counts[icon_id] += 1
|
||||||
|
properties.pop("chart_icon_image", None)
|
||||||
|
|
||||||
|
if layer_name == "navigation_marks":
|
||||||
|
arc_id = arc_icon(properties, config)
|
||||||
|
if arc_id:
|
||||||
|
properties["arc_id"] = arc_id
|
||||||
|
arc_counts[arc_id] += 1
|
||||||
|
|
||||||
|
for value in properties.values():
|
||||||
|
if isinstance(value, str) and (
|
||||||
|
value.startswith("symbol-daytime-") or value.startswith("arc-daytime-")
|
||||||
|
):
|
||||||
|
unknown_old_values[value] += 1
|
||||||
|
|
||||||
|
if properties != before:
|
||||||
|
changed_features += 1
|
||||||
|
output_feature = {
|
||||||
|
"geometry": feature["geometry"],
|
||||||
|
"properties": properties,
|
||||||
|
}
|
||||||
|
if feature.get("id") is not None:
|
||||||
|
output_feature["id"] = feature["id"]
|
||||||
|
output_features.append(output_feature)
|
||||||
|
output_layers.append({"name": layer_name, "features": output_features})
|
||||||
|
|
||||||
|
target.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
target.write_bytes(encode_layers_preserving_extents(output_layers, extents))
|
||||||
|
if verify_geometry:
|
||||||
|
assert_reencoded_tile_safe(source, target)
|
||||||
|
return {
|
||||||
|
"changed_features": changed_features,
|
||||||
|
"icon_counts": dict(icon_counts),
|
||||||
|
"arc_counts": dict(arc_counts),
|
||||||
|
"old_values": dict(old_values),
|
||||||
|
"unknown_old_values": dict(unknown_old_values),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def rewrite_tile_job(args: tuple[str, str, dict[str, Any], bool]) -> dict[str, Any]:
|
||||||
|
source, target, config, verify_geometry = args
|
||||||
|
result = rewrite_tile(
|
||||||
|
Path(source), Path(target), config, verify_geometry=verify_geometry
|
||||||
|
)
|
||||||
|
result["source"] = source
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def transform_style(config: dict[str, Any]) -> dict[str, Any]:
|
||||||
|
style = json.loads(STYLE_SOURCE.read_text(encoding="utf-8"))
|
||||||
|
key_map = dict(config["sprite_key_map"])
|
||||||
|
key_map.update(STYLE_EXTRA_MAP)
|
||||||
|
|
||||||
|
def transform(value: Any) -> Any:
|
||||||
|
if isinstance(value, dict):
|
||||||
|
return {key: transform(item) for key, item in value.items()}
|
||||||
|
if isinstance(value, list):
|
||||||
|
return [transform(item) for item in value]
|
||||||
|
if isinstance(value, str):
|
||||||
|
if value == "chart_icon_image":
|
||||||
|
return "icon_id"
|
||||||
|
return key_map.get(value, value)
|
||||||
|
return value
|
||||||
|
|
||||||
|
style = transform(style)
|
||||||
|
style["name"] = "NavSea Kyushu Semantic Icon Test v1"
|
||||||
|
style["sprite"] = SPRITE_URL
|
||||||
|
style["metadata"] = {
|
||||||
|
"navsea_test_version": "kyushu-semantic-icon-v1-20260806",
|
||||||
|
"source_baseline": str(SOURCE_ROOT),
|
||||||
|
"icon_map": str(CONFIG_PATH),
|
||||||
|
}
|
||||||
|
style["sources"]["navsea_delivery"]["tiles"] = [TARGET_TILE_URL]
|
||||||
|
|
||||||
|
for layer in style["layers"]:
|
||||||
|
layer_id = layer.get("id")
|
||||||
|
layout = layer.get("layout") or {}
|
||||||
|
if layer_id in SIMPLE_ICON_LAYERS:
|
||||||
|
layout["icon-image"] = ["coalesce", ["get", "icon_id"], ""]
|
||||||
|
layer["layout"] = layout
|
||||||
|
elif layer_id == "nav-light-arc":
|
||||||
|
layout["icon-image"] = ["coalesce", ["get", "arc_id"], ""]
|
||||||
|
layer["layout"] = layout
|
||||||
|
return style
|
||||||
|
|
||||||
|
|
||||||
|
def write_style(style: dict[str, Any], path: Path, deploy_path: Path) -> None:
|
||||||
|
payload = json.dumps(style, ensure_ascii=False, indent=2) + "\n"
|
||||||
|
path.write_text(payload, encoding="utf-8")
|
||||||
|
deploy_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
deploy_path.write_text(payload, encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
def write_newpec_style() -> None:
|
||||||
|
style = json.loads(NEWPEC_STYLE_SOURCE.read_text(encoding="utf-8"))
|
||||||
|
style["name"] = "NavSea Newpec Kyushu Icon Test v1"
|
||||||
|
style["metadata"] = {
|
||||||
|
"navsea_test_version": "kyushu-semantic-icon-v1-20260806",
|
||||||
|
"role": "left_original_newpec_reference",
|
||||||
|
}
|
||||||
|
write_style(style, NEWPEC_STYLE_OUTPUT, NEWPEC_STYLE_DEPLOY)
|
||||||
|
|
||||||
|
|
||||||
|
def build_sprite(config: dict[str, Any]) -> dict[str, Any]:
|
||||||
|
if SPRITE_TARGET.exists():
|
||||||
|
raise RuntimeError(f"refusing to overwrite existing sprite target: {SPRITE_TARGET}")
|
||||||
|
SPRITE_TARGET.mkdir(parents=True)
|
||||||
|
source_meta: dict[str, dict[str, dict[str, Any]]] = {}
|
||||||
|
for filename in ("sprite.json", "sprite@2x.json"):
|
||||||
|
source_meta[filename] = json.loads((SPRITE_SOURCE / filename).read_text(encoding="utf-8"))
|
||||||
|
|
||||||
|
key_map = dict(config["sprite_key_map"])
|
||||||
|
key_map.update(STYLE_EXTRA_MAP)
|
||||||
|
fallback_sources = {"lm_cus": "symbol-daytime-660"}
|
||||||
|
added: dict[str, str] = {}
|
||||||
|
removed = set(key_map)
|
||||||
|
for filename, meta in source_meta.items():
|
||||||
|
# 测试包只保留新的短语键,避免把未使用的旧 symbol/arc 键继续带入 sprite。
|
||||||
|
output: dict[str, dict[str, Any]] = {}
|
||||||
|
for old_key, new_key in key_map.items():
|
||||||
|
source_key = old_key if old_key in meta else None
|
||||||
|
if source_key is None:
|
||||||
|
for candidate, candidate_new in key_map.items():
|
||||||
|
if candidate_new == new_key and candidate in meta:
|
||||||
|
source_key = candidate
|
||||||
|
break
|
||||||
|
if source_key is None:
|
||||||
|
source_key = fallback_sources.get(new_key)
|
||||||
|
if source_key and source_key in meta:
|
||||||
|
output[new_key] = dict(meta[source_key])
|
||||||
|
added[new_key] = source_key
|
||||||
|
(SPRITE_TARGET / filename).write_text(
|
||||||
|
json.dumps(output, ensure_ascii=False, indent=2) + "\n", encoding="utf-8"
|
||||||
|
)
|
||||||
|
|
||||||
|
for filename in ("sprite.png", "sprite@2x.png"):
|
||||||
|
shutil.copy2(SPRITE_SOURCE / filename, SPRITE_TARGET / filename)
|
||||||
|
return {"added": added, "fallbacks": {"lm_cus": fallback_sources["lm_cus"]}}
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
config = load_config()
|
||||||
|
tiles = collect_tiles()
|
||||||
|
if TARGET_ROOT.exists():
|
||||||
|
raise RuntimeError(f"refusing to overwrite existing PBF target: {TARGET_ROOT}")
|
||||||
|
TARGET_ROOT.mkdir(parents=True)
|
||||||
|
|
||||||
|
totals: Counter[str] = Counter()
|
||||||
|
old_values: Counter[str] = Counter()
|
||||||
|
unknown_old_values: Counter[str] = Counter()
|
||||||
|
icon_counts: Counter[str] = Counter()
|
||||||
|
arc_counts: Counter[str] = Counter()
|
||||||
|
rewritten = 0
|
||||||
|
candidate_needles = [
|
||||||
|
key.encode("utf-8") for key in config["sprite_key_map"]
|
||||||
|
] + [
|
||||||
|
b"navigation_marks",
|
||||||
|
b"navigation_hazard_point",
|
||||||
|
b"anchor_caution_hazard_point",
|
||||||
|
b"anchorage_point",
|
||||||
|
b"facility_boundary_point",
|
||||||
|
b"onshore_structure_point",
|
||||||
|
]
|
||||||
|
rewrite_jobs: list[tuple[str, str, dict[str, Any], bool]] = []
|
||||||
|
candidate_count = 0
|
||||||
|
for z, x, y, rel in tiles:
|
||||||
|
source = SOURCE_ROOT / rel
|
||||||
|
target = TARGET_ROOT / rel
|
||||||
|
raw = source.read_bytes()
|
||||||
|
if not any(needle in raw for needle in candidate_needles):
|
||||||
|
copy_link(source, target)
|
||||||
|
continue
|
||||||
|
rewrite_jobs.append(
|
||||||
|
(str(source), str(target), config, candidate_count < 3)
|
||||||
|
)
|
||||||
|
candidate_count += 1
|
||||||
|
|
||||||
|
worker_count = min(os.cpu_count() or 4, 12)
|
||||||
|
with ProcessPoolExecutor(max_workers=worker_count) as executor:
|
||||||
|
for result in executor.map(rewrite_tile_job, rewrite_jobs, chunksize=8):
|
||||||
|
if result["changed_features"]:
|
||||||
|
rewritten += 1
|
||||||
|
totals["features_changed"] += result["changed_features"]
|
||||||
|
old_values.update(result["old_values"])
|
||||||
|
unknown_old_values.update(result["unknown_old_values"])
|
||||||
|
icon_counts.update(result["icon_counts"])
|
||||||
|
arc_counts.update(result["arc_counts"])
|
||||||
|
|
||||||
|
sprite = build_sprite(config)
|
||||||
|
style = transform_style(config)
|
||||||
|
write_style(style, STYLE_OUTPUT, STYLE_DEPLOY)
|
||||||
|
write_newpec_style()
|
||||||
|
|
||||||
|
REPORT_DIR.mkdir(parents=True, exist_ok=True)
|
||||||
|
summary = {
|
||||||
|
"version": "kyushu-semantic-icon-v1-20260806",
|
||||||
|
"source_root": str(SOURCE_ROOT),
|
||||||
|
"target_root": str(TARGET_ROOT),
|
||||||
|
"bbox": KYUSHU_BBOX,
|
||||||
|
"zooms": list(ZOOMS),
|
||||||
|
"tiles": len(tiles),
|
||||||
|
"tiles_rewritten": rewritten,
|
||||||
|
"candidate_tiles": candidate_count,
|
||||||
|
**totals,
|
||||||
|
"old_values": dict(old_values),
|
||||||
|
"unknown_old_values_after_rewrite": dict(unknown_old_values),
|
||||||
|
"icon_counts": dict(icon_counts),
|
||||||
|
"arc_counts": dict(arc_counts),
|
||||||
|
"sprite": sprite,
|
||||||
|
"style": str(STYLE_OUTPUT),
|
||||||
|
"newpec_style": str(NEWPEC_STYLE_OUTPUT),
|
||||||
|
}
|
||||||
|
(REPORT_DIR / "kyushu_semantic_icon_v1.json").write_text(
|
||||||
|
json.dumps(summary, ensure_ascii=False, indent=2) + "\n", encoding="utf-8"
|
||||||
|
)
|
||||||
|
lines = [
|
||||||
|
"# 九州语义图标替换测试版 v1",
|
||||||
|
"",
|
||||||
|
f"- PBF 来源:`{SOURCE_ROOT}`",
|
||||||
|
f"- PBF 输出:`{TARGET_ROOT}`",
|
||||||
|
f"- 范围:`{KYUSHU_BBOX}`",
|
||||||
|
f"- zoom:`{ZOOMS[0]}-{ZOOMS[-1]}`",
|
||||||
|
f"- 瓦片数:`{len(tiles)}`",
|
||||||
|
f"- 重写瓦片:`{rewritten}`",
|
||||||
|
f"- 改动 feature:`{totals['features_changed']}`",
|
||||||
|
f"- sprite:`{SPRITE_TARGET}`",
|
||||||
|
f"- delivery style:`{STYLE_OUTPUT}`",
|
||||||
|
f"- newpec style:`{NEWPEC_STYLE_OUTPUT}`",
|
||||||
|
"",
|
||||||
|
"## 旧图标值",
|
||||||
|
"",
|
||||||
|
"```json",
|
||||||
|
json.dumps(dict(old_values), ensure_ascii=False, indent=2),
|
||||||
|
"```",
|
||||||
|
"",
|
||||||
|
"## 审计关注",
|
||||||
|
"",
|
||||||
|
"- `unknown_old_values_after_rewrite` 必须为空。",
|
||||||
|
"- `lm_cus` 当前使用 `symbol-daytime-660` 的临时视觉回退,需人工确认。",
|
||||||
|
"- 几何使用原 tile extent 重编码,并执行 extent 安全检查。",
|
||||||
|
]
|
||||||
|
(REPORT_DIR / "kyushu_semantic_icon_v1.md").write_text("\n".join(lines) + "\n", encoding="utf-8")
|
||||||
|
print(json.dumps(summary, ensure_ascii=False, indent=2))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,378 @@
|
|||||||
|
{
|
||||||
|
"label": "kyushu-semantic-icon-v1",
|
||||||
|
"target_root": "/home/wwwroot/pbf-delivery-kyushu-semantic-icon-v1-20260806",
|
||||||
|
"source_root": "/home/wwwroot/newpec/exported_auto/tile.mapple-on.jp__newpec-mvt-20260106__z___x___y_.pbf/tiles",
|
||||||
|
"tile_count": 4707,
|
||||||
|
"outside_extent_tiles": 4707,
|
||||||
|
"source_extent_mismatch_tiles": 0,
|
||||||
|
"fixable_from_source_tiles": 0,
|
||||||
|
"repaired_tiles": 0,
|
||||||
|
"zoom_summary": {
|
||||||
|
"5": {
|
||||||
|
"tile_count": 2,
|
||||||
|
"outside_extent_tiles": 2,
|
||||||
|
"source_extent_mismatch_tiles": 0,
|
||||||
|
"extent_counts": {
|
||||||
|
"4096": 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"6": {
|
||||||
|
"tile_count": 4,
|
||||||
|
"outside_extent_tiles": 4,
|
||||||
|
"source_extent_mismatch_tiles": 0,
|
||||||
|
"extent_counts": {
|
||||||
|
"4096": 4
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"7": {
|
||||||
|
"tile_count": 9,
|
||||||
|
"outside_extent_tiles": 9,
|
||||||
|
"source_extent_mismatch_tiles": 0,
|
||||||
|
"extent_counts": {
|
||||||
|
"4096": 9
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"8": {
|
||||||
|
"tile_count": 20,
|
||||||
|
"outside_extent_tiles": 20,
|
||||||
|
"source_extent_mismatch_tiles": 0,
|
||||||
|
"extent_counts": {
|
||||||
|
"4096": 20
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"9": {
|
||||||
|
"tile_count": 70,
|
||||||
|
"outside_extent_tiles": 70,
|
||||||
|
"source_extent_mismatch_tiles": 0,
|
||||||
|
"extent_counts": {
|
||||||
|
"4096": 70
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"10": {
|
||||||
|
"tile_count": 234,
|
||||||
|
"outside_extent_tiles": 234,
|
||||||
|
"source_extent_mismatch_tiles": 0,
|
||||||
|
"extent_counts": {
|
||||||
|
"4096": 234
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"11": {
|
||||||
|
"tile_count": 884,
|
||||||
|
"outside_extent_tiles": 884,
|
||||||
|
"source_extent_mismatch_tiles": 0,
|
||||||
|
"extent_counts": {
|
||||||
|
"4096": 884
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"12": {
|
||||||
|
"tile_count": 3484,
|
||||||
|
"outside_extent_tiles": 3484,
|
||||||
|
"source_extent_mismatch_tiles": 0,
|
||||||
|
"extent_counts": {
|
||||||
|
"1048576": 3484
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sample_tiles": [
|
||||||
|
{
|
||||||
|
"tile": "10/876/405.pbf",
|
||||||
|
"extent_values": [
|
||||||
|
4096
|
||||||
|
],
|
||||||
|
"source_extent": 4096,
|
||||||
|
"outside_extent": true,
|
||||||
|
"max_overflow": 80,
|
||||||
|
"fixable_from_source": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tile": "10/876/406.pbf",
|
||||||
|
"extent_values": [
|
||||||
|
4096
|
||||||
|
],
|
||||||
|
"source_extent": 4096,
|
||||||
|
"outside_extent": true,
|
||||||
|
"max_overflow": 80,
|
||||||
|
"fixable_from_source": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tile": "10/876/407.pbf",
|
||||||
|
"extent_values": [
|
||||||
|
4096
|
||||||
|
],
|
||||||
|
"source_extent": 4096,
|
||||||
|
"outside_extent": true,
|
||||||
|
"max_overflow": 80,
|
||||||
|
"fixable_from_source": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tile": "10/876/408.pbf",
|
||||||
|
"extent_values": [
|
||||||
|
4096
|
||||||
|
],
|
||||||
|
"source_extent": 4096,
|
||||||
|
"outside_extent": true,
|
||||||
|
"max_overflow": 80,
|
||||||
|
"fixable_from_source": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tile": "10/876/409.pbf",
|
||||||
|
"extent_values": [
|
||||||
|
4096
|
||||||
|
],
|
||||||
|
"source_extent": 4096,
|
||||||
|
"outside_extent": true,
|
||||||
|
"max_overflow": 80,
|
||||||
|
"fixable_from_source": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tile": "10/876/410.pbf",
|
||||||
|
"extent_values": [
|
||||||
|
4096
|
||||||
|
],
|
||||||
|
"source_extent": 4096,
|
||||||
|
"outside_extent": true,
|
||||||
|
"max_overflow": 80,
|
||||||
|
"fixable_from_source": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tile": "10/876/411.pbf",
|
||||||
|
"extent_values": [
|
||||||
|
4096
|
||||||
|
],
|
||||||
|
"source_extent": 4096,
|
||||||
|
"outside_extent": true,
|
||||||
|
"max_overflow": 80,
|
||||||
|
"fixable_from_source": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tile": "10/876/412.pbf",
|
||||||
|
"extent_values": [
|
||||||
|
4096
|
||||||
|
],
|
||||||
|
"source_extent": 4096,
|
||||||
|
"outside_extent": true,
|
||||||
|
"max_overflow": 80,
|
||||||
|
"fixable_from_source": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tile": "10/876/413.pbf",
|
||||||
|
"extent_values": [
|
||||||
|
4096
|
||||||
|
],
|
||||||
|
"source_extent": 4096,
|
||||||
|
"outside_extent": true,
|
||||||
|
"max_overflow": 80,
|
||||||
|
"fixable_from_source": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tile": "10/876/414.pbf",
|
||||||
|
"extent_values": [
|
||||||
|
4096
|
||||||
|
],
|
||||||
|
"source_extent": 4096,
|
||||||
|
"outside_extent": true,
|
||||||
|
"max_overflow": 80,
|
||||||
|
"fixable_from_source": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tile": "10/876/415.pbf",
|
||||||
|
"extent_values": [
|
||||||
|
4096
|
||||||
|
],
|
||||||
|
"source_extent": 4096,
|
||||||
|
"outside_extent": true,
|
||||||
|
"max_overflow": 80,
|
||||||
|
"fixable_from_source": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tile": "10/876/416.pbf",
|
||||||
|
"extent_values": [
|
||||||
|
4096
|
||||||
|
],
|
||||||
|
"source_extent": 4096,
|
||||||
|
"outside_extent": true,
|
||||||
|
"max_overflow": 80,
|
||||||
|
"fixable_from_source": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tile": "10/876/417.pbf",
|
||||||
|
"extent_values": [
|
||||||
|
4096
|
||||||
|
],
|
||||||
|
"source_extent": 4096,
|
||||||
|
"outside_extent": true,
|
||||||
|
"max_overflow": 80,
|
||||||
|
"fixable_from_source": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tile": "10/876/418.pbf",
|
||||||
|
"extent_values": [
|
||||||
|
4096
|
||||||
|
],
|
||||||
|
"source_extent": 4096,
|
||||||
|
"outside_extent": true,
|
||||||
|
"max_overflow": 80,
|
||||||
|
"fixable_from_source": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tile": "10/876/419.pbf",
|
||||||
|
"extent_values": [
|
||||||
|
4096
|
||||||
|
],
|
||||||
|
"source_extent": 4096,
|
||||||
|
"outside_extent": true,
|
||||||
|
"max_overflow": 80,
|
||||||
|
"fixable_from_source": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tile": "10/876/420.pbf",
|
||||||
|
"extent_values": [
|
||||||
|
4096
|
||||||
|
],
|
||||||
|
"source_extent": 4096,
|
||||||
|
"outside_extent": true,
|
||||||
|
"max_overflow": 80,
|
||||||
|
"fixable_from_source": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tile": "10/876/421.pbf",
|
||||||
|
"extent_values": [
|
||||||
|
4096
|
||||||
|
],
|
||||||
|
"source_extent": 4096,
|
||||||
|
"outside_extent": true,
|
||||||
|
"max_overflow": 80,
|
||||||
|
"fixable_from_source": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tile": "10/876/422.pbf",
|
||||||
|
"extent_values": [
|
||||||
|
4096
|
||||||
|
],
|
||||||
|
"source_extent": 4096,
|
||||||
|
"outside_extent": true,
|
||||||
|
"max_overflow": 80,
|
||||||
|
"fixable_from_source": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tile": "10/877/405.pbf",
|
||||||
|
"extent_values": [
|
||||||
|
4096
|
||||||
|
],
|
||||||
|
"source_extent": 4096,
|
||||||
|
"outside_extent": true,
|
||||||
|
"max_overflow": 80,
|
||||||
|
"fixable_from_source": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tile": "10/877/406.pbf",
|
||||||
|
"extent_values": [
|
||||||
|
4096
|
||||||
|
],
|
||||||
|
"source_extent": 4096,
|
||||||
|
"outside_extent": true,
|
||||||
|
"max_overflow": 80,
|
||||||
|
"fixable_from_source": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tile": "10/877/407.pbf",
|
||||||
|
"extent_values": [
|
||||||
|
4096
|
||||||
|
],
|
||||||
|
"source_extent": 4096,
|
||||||
|
"outside_extent": true,
|
||||||
|
"max_overflow": 80,
|
||||||
|
"fixable_from_source": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tile": "10/877/408.pbf",
|
||||||
|
"extent_values": [
|
||||||
|
4096
|
||||||
|
],
|
||||||
|
"source_extent": 4096,
|
||||||
|
"outside_extent": true,
|
||||||
|
"max_overflow": 80,
|
||||||
|
"fixable_from_source": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tile": "10/877/409.pbf",
|
||||||
|
"extent_values": [
|
||||||
|
4096
|
||||||
|
],
|
||||||
|
"source_extent": 4096,
|
||||||
|
"outside_extent": true,
|
||||||
|
"max_overflow": 80,
|
||||||
|
"fixable_from_source": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tile": "10/877/410.pbf",
|
||||||
|
"extent_values": [
|
||||||
|
4096
|
||||||
|
],
|
||||||
|
"source_extent": 4096,
|
||||||
|
"outside_extent": true,
|
||||||
|
"max_overflow": 80,
|
||||||
|
"fixable_from_source": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tile": "10/877/411.pbf",
|
||||||
|
"extent_values": [
|
||||||
|
4096
|
||||||
|
],
|
||||||
|
"source_extent": 4096,
|
||||||
|
"outside_extent": true,
|
||||||
|
"max_overflow": 80,
|
||||||
|
"fixable_from_source": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tile": "10/877/412.pbf",
|
||||||
|
"extent_values": [
|
||||||
|
4096
|
||||||
|
],
|
||||||
|
"source_extent": 4096,
|
||||||
|
"outside_extent": true,
|
||||||
|
"max_overflow": 80,
|
||||||
|
"fixable_from_source": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tile": "10/877/413.pbf",
|
||||||
|
"extent_values": [
|
||||||
|
4096
|
||||||
|
],
|
||||||
|
"source_extent": 4096,
|
||||||
|
"outside_extent": true,
|
||||||
|
"max_overflow": 80,
|
||||||
|
"fixable_from_source": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tile": "10/877/414.pbf",
|
||||||
|
"extent_values": [
|
||||||
|
4096
|
||||||
|
],
|
||||||
|
"source_extent": 4096,
|
||||||
|
"outside_extent": true,
|
||||||
|
"max_overflow": 80,
|
||||||
|
"fixable_from_source": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tile": "10/877/415.pbf",
|
||||||
|
"extent_values": [
|
||||||
|
4096
|
||||||
|
],
|
||||||
|
"source_extent": 4096,
|
||||||
|
"outside_extent": true,
|
||||||
|
"max_overflow": 80,
|
||||||
|
"fixable_from_source": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tile": "10/877/416.pbf",
|
||||||
|
"extent_values": [
|
||||||
|
4096
|
||||||
|
],
|
||||||
|
"source_extent": 4096,
|
||||||
|
"outside_extent": true,
|
||||||
|
"max_overflow": 80,
|
||||||
|
"fixable_from_source": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,314 @@
|
|||||||
|
# kyushu-semantic-icon-v1 几何 / Extent / Native 风险审计
|
||||||
|
|
||||||
|
## 范围
|
||||||
|
|
||||||
|
- target root: `/home/wwwroot/pbf-delivery-kyushu-semantic-icon-v1-20260806`
|
||||||
|
- source root: `/home/wwwroot/newpec/exported_auto/tile.mapple-on.jp__newpec-mvt-20260106__z___x___y_.pbf/tiles`
|
||||||
|
- tiles: `4707`
|
||||||
|
- repaired tiles: `0`
|
||||||
|
|
||||||
|
## 总体结论
|
||||||
|
|
||||||
|
- 坐标超当前 extent 的瓦片数:`4707`
|
||||||
|
- 与源瓦片 extent 不一致的瓦片数:`0`
|
||||||
|
- 可直接按源 extent 修复的瓦片数:`0`
|
||||||
|
|
||||||
|
## Zoom 汇总
|
||||||
|
|
||||||
|
### z5
|
||||||
|
|
||||||
|
- tiles: `2`
|
||||||
|
- outside extent: `2`
|
||||||
|
- source mismatch: `0`
|
||||||
|
- extent counts: `{4096: 2}`
|
||||||
|
|
||||||
|
### z6
|
||||||
|
|
||||||
|
- tiles: `4`
|
||||||
|
- outside extent: `4`
|
||||||
|
- source mismatch: `0`
|
||||||
|
- extent counts: `{4096: 4}`
|
||||||
|
|
||||||
|
### z7
|
||||||
|
|
||||||
|
- tiles: `9`
|
||||||
|
- outside extent: `9`
|
||||||
|
- source mismatch: `0`
|
||||||
|
- extent counts: `{4096: 9}`
|
||||||
|
|
||||||
|
### z8
|
||||||
|
|
||||||
|
- tiles: `20`
|
||||||
|
- outside extent: `20`
|
||||||
|
- source mismatch: `0`
|
||||||
|
- extent counts: `{4096: 20}`
|
||||||
|
|
||||||
|
### z9
|
||||||
|
|
||||||
|
- tiles: `70`
|
||||||
|
- outside extent: `70`
|
||||||
|
- source mismatch: `0`
|
||||||
|
- extent counts: `{4096: 70}`
|
||||||
|
|
||||||
|
### z10
|
||||||
|
|
||||||
|
- tiles: `234`
|
||||||
|
- outside extent: `234`
|
||||||
|
- source mismatch: `0`
|
||||||
|
- extent counts: `{4096: 234}`
|
||||||
|
|
||||||
|
### z11
|
||||||
|
|
||||||
|
- tiles: `884`
|
||||||
|
- outside extent: `884`
|
||||||
|
- source mismatch: `0`
|
||||||
|
- extent counts: `{4096: 884}`
|
||||||
|
|
||||||
|
### z12
|
||||||
|
|
||||||
|
- tiles: `3484`
|
||||||
|
- outside extent: `3484`
|
||||||
|
- source mismatch: `0`
|
||||||
|
- extent counts: `{1048576: 3484}`
|
||||||
|
|
||||||
|
## 代表问题样本
|
||||||
|
|
||||||
|
### `10/876/405.pbf`
|
||||||
|
|
||||||
|
- extent values: `[4096]`
|
||||||
|
- source extent: `4096`
|
||||||
|
- outside extent: `True`
|
||||||
|
- max overflow: `80`
|
||||||
|
- fixable from source: `False`
|
||||||
|
|
||||||
|
### `10/876/406.pbf`
|
||||||
|
|
||||||
|
- extent values: `[4096]`
|
||||||
|
- source extent: `4096`
|
||||||
|
- outside extent: `True`
|
||||||
|
- max overflow: `80`
|
||||||
|
- fixable from source: `False`
|
||||||
|
|
||||||
|
### `10/876/407.pbf`
|
||||||
|
|
||||||
|
- extent values: `[4096]`
|
||||||
|
- source extent: `4096`
|
||||||
|
- outside extent: `True`
|
||||||
|
- max overflow: `80`
|
||||||
|
- fixable from source: `False`
|
||||||
|
|
||||||
|
### `10/876/408.pbf`
|
||||||
|
|
||||||
|
- extent values: `[4096]`
|
||||||
|
- source extent: `4096`
|
||||||
|
- outside extent: `True`
|
||||||
|
- max overflow: `80`
|
||||||
|
- fixable from source: `False`
|
||||||
|
|
||||||
|
### `10/876/409.pbf`
|
||||||
|
|
||||||
|
- extent values: `[4096]`
|
||||||
|
- source extent: `4096`
|
||||||
|
- outside extent: `True`
|
||||||
|
- max overflow: `80`
|
||||||
|
- fixable from source: `False`
|
||||||
|
|
||||||
|
### `10/876/410.pbf`
|
||||||
|
|
||||||
|
- extent values: `[4096]`
|
||||||
|
- source extent: `4096`
|
||||||
|
- outside extent: `True`
|
||||||
|
- max overflow: `80`
|
||||||
|
- fixable from source: `False`
|
||||||
|
|
||||||
|
### `10/876/411.pbf`
|
||||||
|
|
||||||
|
- extent values: `[4096]`
|
||||||
|
- source extent: `4096`
|
||||||
|
- outside extent: `True`
|
||||||
|
- max overflow: `80`
|
||||||
|
- fixable from source: `False`
|
||||||
|
|
||||||
|
### `10/876/412.pbf`
|
||||||
|
|
||||||
|
- extent values: `[4096]`
|
||||||
|
- source extent: `4096`
|
||||||
|
- outside extent: `True`
|
||||||
|
- max overflow: `80`
|
||||||
|
- fixable from source: `False`
|
||||||
|
|
||||||
|
### `10/876/413.pbf`
|
||||||
|
|
||||||
|
- extent values: `[4096]`
|
||||||
|
- source extent: `4096`
|
||||||
|
- outside extent: `True`
|
||||||
|
- max overflow: `80`
|
||||||
|
- fixable from source: `False`
|
||||||
|
|
||||||
|
### `10/876/414.pbf`
|
||||||
|
|
||||||
|
- extent values: `[4096]`
|
||||||
|
- source extent: `4096`
|
||||||
|
- outside extent: `True`
|
||||||
|
- max overflow: `80`
|
||||||
|
- fixable from source: `False`
|
||||||
|
|
||||||
|
### `10/876/415.pbf`
|
||||||
|
|
||||||
|
- extent values: `[4096]`
|
||||||
|
- source extent: `4096`
|
||||||
|
- outside extent: `True`
|
||||||
|
- max overflow: `80`
|
||||||
|
- fixable from source: `False`
|
||||||
|
|
||||||
|
### `10/876/416.pbf`
|
||||||
|
|
||||||
|
- extent values: `[4096]`
|
||||||
|
- source extent: `4096`
|
||||||
|
- outside extent: `True`
|
||||||
|
- max overflow: `80`
|
||||||
|
- fixable from source: `False`
|
||||||
|
|
||||||
|
### `10/876/417.pbf`
|
||||||
|
|
||||||
|
- extent values: `[4096]`
|
||||||
|
- source extent: `4096`
|
||||||
|
- outside extent: `True`
|
||||||
|
- max overflow: `80`
|
||||||
|
- fixable from source: `False`
|
||||||
|
|
||||||
|
### `10/876/418.pbf`
|
||||||
|
|
||||||
|
- extent values: `[4096]`
|
||||||
|
- source extent: `4096`
|
||||||
|
- outside extent: `True`
|
||||||
|
- max overflow: `80`
|
||||||
|
- fixable from source: `False`
|
||||||
|
|
||||||
|
### `10/876/419.pbf`
|
||||||
|
|
||||||
|
- extent values: `[4096]`
|
||||||
|
- source extent: `4096`
|
||||||
|
- outside extent: `True`
|
||||||
|
- max overflow: `80`
|
||||||
|
- fixable from source: `False`
|
||||||
|
|
||||||
|
### `10/876/420.pbf`
|
||||||
|
|
||||||
|
- extent values: `[4096]`
|
||||||
|
- source extent: `4096`
|
||||||
|
- outside extent: `True`
|
||||||
|
- max overflow: `80`
|
||||||
|
- fixable from source: `False`
|
||||||
|
|
||||||
|
### `10/876/421.pbf`
|
||||||
|
|
||||||
|
- extent values: `[4096]`
|
||||||
|
- source extent: `4096`
|
||||||
|
- outside extent: `True`
|
||||||
|
- max overflow: `80`
|
||||||
|
- fixable from source: `False`
|
||||||
|
|
||||||
|
### `10/876/422.pbf`
|
||||||
|
|
||||||
|
- extent values: `[4096]`
|
||||||
|
- source extent: `4096`
|
||||||
|
- outside extent: `True`
|
||||||
|
- max overflow: `80`
|
||||||
|
- fixable from source: `False`
|
||||||
|
|
||||||
|
### `10/877/405.pbf`
|
||||||
|
|
||||||
|
- extent values: `[4096]`
|
||||||
|
- source extent: `4096`
|
||||||
|
- outside extent: `True`
|
||||||
|
- max overflow: `80`
|
||||||
|
- fixable from source: `False`
|
||||||
|
|
||||||
|
### `10/877/406.pbf`
|
||||||
|
|
||||||
|
- extent values: `[4096]`
|
||||||
|
- source extent: `4096`
|
||||||
|
- outside extent: `True`
|
||||||
|
- max overflow: `80`
|
||||||
|
- fixable from source: `False`
|
||||||
|
|
||||||
|
### `10/877/407.pbf`
|
||||||
|
|
||||||
|
- extent values: `[4096]`
|
||||||
|
- source extent: `4096`
|
||||||
|
- outside extent: `True`
|
||||||
|
- max overflow: `80`
|
||||||
|
- fixable from source: `False`
|
||||||
|
|
||||||
|
### `10/877/408.pbf`
|
||||||
|
|
||||||
|
- extent values: `[4096]`
|
||||||
|
- source extent: `4096`
|
||||||
|
- outside extent: `True`
|
||||||
|
- max overflow: `80`
|
||||||
|
- fixable from source: `False`
|
||||||
|
|
||||||
|
### `10/877/409.pbf`
|
||||||
|
|
||||||
|
- extent values: `[4096]`
|
||||||
|
- source extent: `4096`
|
||||||
|
- outside extent: `True`
|
||||||
|
- max overflow: `80`
|
||||||
|
- fixable from source: `False`
|
||||||
|
|
||||||
|
### `10/877/410.pbf`
|
||||||
|
|
||||||
|
- extent values: `[4096]`
|
||||||
|
- source extent: `4096`
|
||||||
|
- outside extent: `True`
|
||||||
|
- max overflow: `80`
|
||||||
|
- fixable from source: `False`
|
||||||
|
|
||||||
|
### `10/877/411.pbf`
|
||||||
|
|
||||||
|
- extent values: `[4096]`
|
||||||
|
- source extent: `4096`
|
||||||
|
- outside extent: `True`
|
||||||
|
- max overflow: `80`
|
||||||
|
- fixable from source: `False`
|
||||||
|
|
||||||
|
### `10/877/412.pbf`
|
||||||
|
|
||||||
|
- extent values: `[4096]`
|
||||||
|
- source extent: `4096`
|
||||||
|
- outside extent: `True`
|
||||||
|
- max overflow: `80`
|
||||||
|
- fixable from source: `False`
|
||||||
|
|
||||||
|
### `10/877/413.pbf`
|
||||||
|
|
||||||
|
- extent values: `[4096]`
|
||||||
|
- source extent: `4096`
|
||||||
|
- outside extent: `True`
|
||||||
|
- max overflow: `80`
|
||||||
|
- fixable from source: `False`
|
||||||
|
|
||||||
|
### `10/877/414.pbf`
|
||||||
|
|
||||||
|
- extent values: `[4096]`
|
||||||
|
- source extent: `4096`
|
||||||
|
- outside extent: `True`
|
||||||
|
- max overflow: `80`
|
||||||
|
- fixable from source: `False`
|
||||||
|
|
||||||
|
### `10/877/415.pbf`
|
||||||
|
|
||||||
|
- extent values: `[4096]`
|
||||||
|
- source extent: `4096`
|
||||||
|
- outside extent: `True`
|
||||||
|
- max overflow: `80`
|
||||||
|
- fixable from source: `False`
|
||||||
|
|
||||||
|
### `10/877/416.pbf`
|
||||||
|
|
||||||
|
- extent values: `[4096]`
|
||||||
|
- source extent: `4096`
|
||||||
|
- outside extent: `True`
|
||||||
|
- max overflow: `80`
|
||||||
|
- fixable from source: `False`
|
||||||
@@ -0,0 +1,177 @@
|
|||||||
|
{
|
||||||
|
"version": "kyushu-semantic-icon-v1-20260806",
|
||||||
|
"source_root": "/home/wwwroot/pbf-delivery-full-20260418-rebuild",
|
||||||
|
"target_root": "/home/wwwroot/pbf-delivery-kyushu-semantic-icon-v1-20260806",
|
||||||
|
"bbox": [
|
||||||
|
128.0,
|
||||||
|
30.0,
|
||||||
|
132.5,
|
||||||
|
34.9
|
||||||
|
],
|
||||||
|
"zooms": [
|
||||||
|
5,
|
||||||
|
6,
|
||||||
|
7,
|
||||||
|
8,
|
||||||
|
9,
|
||||||
|
10,
|
||||||
|
11,
|
||||||
|
12
|
||||||
|
],
|
||||||
|
"tiles": 4707,
|
||||||
|
"tiles_rewritten": 1340,
|
||||||
|
"candidate_tiles": 1343,
|
||||||
|
"features_changed": 40131,
|
||||||
|
"old_values": {
|
||||||
|
"symbol-daytime-301": 2536,
|
||||||
|
"symbol-daytime-308": 33,
|
||||||
|
"symbol-daytime-428": 13416,
|
||||||
|
"symbol-daytime-30500003": 165,
|
||||||
|
"symbol-daytime-303": 4993,
|
||||||
|
"symbol-daytime-327": 626,
|
||||||
|
"symbol-daytime-310": 1833,
|
||||||
|
"symbol-daytime-30500001": 25,
|
||||||
|
"symbol-daytime-320": 959,
|
||||||
|
"symbol-daytime-321": 290,
|
||||||
|
"symbol-daytime-429": 256,
|
||||||
|
"symbol-daytime-413": 187,
|
||||||
|
"symbol-daytime-325": 38,
|
||||||
|
"symbol-daytime-323": 77,
|
||||||
|
"symbol-daytime-30700003": 24,
|
||||||
|
"symbol-daytime-30500002": 16,
|
||||||
|
"symbol-daytime-335359": 12,
|
||||||
|
"symbol-daytime-405": 5329,
|
||||||
|
"symbol-daytime-412": 50,
|
||||||
|
"symbol-daytime-719": 54,
|
||||||
|
"symbol-daytime-410": 10
|
||||||
|
},
|
||||||
|
"unknown_old_values_after_rewrite": {},
|
||||||
|
"icon_counts": {
|
||||||
|
"lt_hbr": 2536,
|
||||||
|
"mk_lead_v": 33,
|
||||||
|
"hz_foul": 3598,
|
||||||
|
"hz_reef": 6659,
|
||||||
|
"lt_lead_c": 165,
|
||||||
|
"lm_mtn": 2059,
|
||||||
|
"hz_overfall": 912,
|
||||||
|
"lt_min": 4993,
|
||||||
|
"bu_lat": 626,
|
||||||
|
"lt_bcn": 1833,
|
||||||
|
"lm_chim": 1907,
|
||||||
|
"lm_twr": 2527,
|
||||||
|
"hz_seaweed": 470,
|
||||||
|
"lt_lead_a": 25,
|
||||||
|
"bu_lit": 959,
|
||||||
|
"lm_mar": 121,
|
||||||
|
"lm_fish": 846,
|
||||||
|
"lm_cus": 85,
|
||||||
|
"lm_mon": 42,
|
||||||
|
"bu_gen": 290,
|
||||||
|
"hz_wreck_survey": 432,
|
||||||
|
"hz_sandwave": 662,
|
||||||
|
"lm_ctrl": 28,
|
||||||
|
"bu_can": 38,
|
||||||
|
"hz_outfall": 174,
|
||||||
|
"hz_danger_clear": 26,
|
||||||
|
"bu_pil": 77,
|
||||||
|
"lm_prom": 8,
|
||||||
|
"hz_whirl": 27,
|
||||||
|
"mk_lead_c": 24,
|
||||||
|
"hz_reef_danger": 25,
|
||||||
|
"lt_lead_b": 16,
|
||||||
|
"mk_vais": 12,
|
||||||
|
"fac_fishport": 1164,
|
||||||
|
"hz_rock_awash": 1397,
|
||||||
|
"hz_rock_sub": 3932,
|
||||||
|
"hz_danger_iso": 212,
|
||||||
|
"fac_port": 261,
|
||||||
|
"hz_tower": 57,
|
||||||
|
"hz_wreck_sub": 50,
|
||||||
|
"fac_seastation": 48,
|
||||||
|
"hz_dolphin": 205,
|
||||||
|
"fac_fisherina": 11,
|
||||||
|
"fac_marina": 95,
|
||||||
|
"an_quar": 33,
|
||||||
|
"hz_wreck_hull": 10,
|
||||||
|
"hz_pile": 340,
|
||||||
|
"hz_obst": 60,
|
||||||
|
"an_restrict": 2,
|
||||||
|
"an_no_anchor": 4,
|
||||||
|
"an_desig": 15
|
||||||
|
},
|
||||||
|
"arc_counts": {
|
||||||
|
"arc_open_YW": 204,
|
||||||
|
"arc_YW": 977,
|
||||||
|
"arc_G": 610,
|
||||||
|
"arc_R": 769
|
||||||
|
},
|
||||||
|
"sprite": {
|
||||||
|
"added": {
|
||||||
|
"lt_cst": "coastal_lighthouse",
|
||||||
|
"lt_hbr": "harbor_lighthouse",
|
||||||
|
"lt_bkw": "breakwater_lighthouse",
|
||||||
|
"lt_min": "light_minor",
|
||||||
|
"lt_lead_a": "leading_light_variantt_30500001",
|
||||||
|
"lt_lead_b": "leading_light_variantt_30500002",
|
||||||
|
"lt_lead_c": "leading_light_variantt_30500003",
|
||||||
|
"lt_up_G": "symbol-daytime-30700001",
|
||||||
|
"lt_up_R": "symbol-daytime-30700002",
|
||||||
|
"mk_lead_c": "leading_mark_variantt_30700003",
|
||||||
|
"mk_lead_v": "leading_mark_variantt_308",
|
||||||
|
"lt_bcn": "light_beacon",
|
||||||
|
"bu_lit": "buoy_light",
|
||||||
|
"bu_gen": "buoy_generic",
|
||||||
|
"bu_pil": "buoy_pillar",
|
||||||
|
"bu_can": "buoy_can",
|
||||||
|
"bu_lat": "buoy_lattice",
|
||||||
|
"mk_vais": "nav_mark_vais",
|
||||||
|
"hz_rock_awash": "rock_exposed_drying_awash_group",
|
||||||
|
"hz_rock_sub": "sunken_rock",
|
||||||
|
"hz_danger_clear": "cleared_danger_object",
|
||||||
|
"hz_danger_iso": "isolated_danger",
|
||||||
|
"hz_wreck_hull": "wreck_hull_exposed",
|
||||||
|
"hz_wreck_sub": "wreck_fully_submerged_dangerous",
|
||||||
|
"hz_wreck_survey": "wreck_surveyed",
|
||||||
|
"hz_foul": "foul_ground",
|
||||||
|
"hz_sandwave": "sand_wave",
|
||||||
|
"hz_overfall": "tide_rips_overfalls",
|
||||||
|
"hz_whirl": "eddy_whirlpool",
|
||||||
|
"hz_seaweed": "seaweed",
|
||||||
|
"hz_obst": "obstruction",
|
||||||
|
"hz_reef": "fish_reef",
|
||||||
|
"hz_reef_danger": "fish_reef_dangerous",
|
||||||
|
"hz_tower": "tower_yagura_observation_platform",
|
||||||
|
"hz_pile": "bollard_pile_stake",
|
||||||
|
"hz_dolphin": "dolphin_structure",
|
||||||
|
"hz_outfall": "subsea_installation_outfall_intake",
|
||||||
|
"lm_chim": "symbol-daytime-640",
|
||||||
|
"lm_twr": "symbol-daytime-650",
|
||||||
|
"lm_mar": "symbol-daytime-660",
|
||||||
|
"lm_fish": "symbol-daytime-661",
|
||||||
|
"lm_cus": "symbol-daytime-660",
|
||||||
|
"lm_prom": "symbol-daytime-680",
|
||||||
|
"lm_mtn": "symbol-daytime-681",
|
||||||
|
"lm_ctrl": "symbol-daytime-682",
|
||||||
|
"lm_mon": "symbol-daytime-698",
|
||||||
|
"an_quar": "anchorage_quarantine",
|
||||||
|
"an_desig": "anchorage_designated",
|
||||||
|
"an_restrict": "restriction_area_group",
|
||||||
|
"an_no_anchor": "anchoring_prohibited",
|
||||||
|
"fac_port": "port_general_small_harbor_group",
|
||||||
|
"fac_fishport": "fishing_port",
|
||||||
|
"fac_marina": "marina",
|
||||||
|
"fac_fisherina": "fisherina",
|
||||||
|
"fac_seastation": "sea_station_umi_no_eki",
|
||||||
|
"fac_pilot": "pilot_station",
|
||||||
|
"tide_spot": "tidespot-daytime",
|
||||||
|
"fl_G": "light_flare_green",
|
||||||
|
"fl_R": "light_flare_red",
|
||||||
|
"fl_YW": "light_flare_yellow_white"
|
||||||
|
},
|
||||||
|
"fallbacks": {
|
||||||
|
"lm_cus": "symbol-daytime-660"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"style": "/root/sourceserver/pbf/src/pbf/style.navsea-delivery-kyushu-semantic-icon-v1.json",
|
||||||
|
"newpec_style": "/root/sourceserver/pbf/src/pbf/style.navsea-newpec-kyushu-icon-test-v1.json"
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
# 九州语义图标替换测试版 v1
|
||||||
|
|
||||||
|
- PBF 来源:`/home/wwwroot/pbf-delivery-full-20260418-rebuild`
|
||||||
|
- PBF 输出:`/home/wwwroot/pbf-delivery-kyushu-semantic-icon-v1-20260806`
|
||||||
|
- 范围:`(128.0, 30.0, 132.5, 34.9)`
|
||||||
|
- zoom:`5-12`
|
||||||
|
- 瓦片数:`4707`
|
||||||
|
- 重写瓦片:`1340`
|
||||||
|
- 改动 feature:`40131`
|
||||||
|
- sprite:`/mnt/sda1/www/newpec/sprite-kyushu-semantic-icon-v1-20260806`
|
||||||
|
- delivery style:`/root/sourceserver/pbf/src/pbf/style.navsea-delivery-kyushu-semantic-icon-v1.json`
|
||||||
|
- newpec style:`/root/sourceserver/pbf/src/pbf/style.navsea-newpec-kyushu-icon-test-v1.json`
|
||||||
|
|
||||||
|
## 旧图标值
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"symbol-daytime-301": 2536,
|
||||||
|
"symbol-daytime-308": 33,
|
||||||
|
"symbol-daytime-428": 13416,
|
||||||
|
"symbol-daytime-30500003": 165,
|
||||||
|
"symbol-daytime-303": 4993,
|
||||||
|
"symbol-daytime-327": 626,
|
||||||
|
"symbol-daytime-310": 1833,
|
||||||
|
"symbol-daytime-30500001": 25,
|
||||||
|
"symbol-daytime-320": 959,
|
||||||
|
"symbol-daytime-321": 290,
|
||||||
|
"symbol-daytime-429": 256,
|
||||||
|
"symbol-daytime-413": 187,
|
||||||
|
"symbol-daytime-325": 38,
|
||||||
|
"symbol-daytime-323": 77,
|
||||||
|
"symbol-daytime-30700003": 24,
|
||||||
|
"symbol-daytime-30500002": 16,
|
||||||
|
"symbol-daytime-335359": 12,
|
||||||
|
"symbol-daytime-405": 5329,
|
||||||
|
"symbol-daytime-412": 50,
|
||||||
|
"symbol-daytime-719": 54,
|
||||||
|
"symbol-daytime-410": 10
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 审计关注
|
||||||
|
|
||||||
|
- `unknown_old_values_after_rewrite` 必须为空。
|
||||||
|
- `lm_cus` 当前使用 `symbol-daytime-660` 的临时视觉回退,需人工确认。
|
||||||
|
- 几何使用原 tile extent 重编码,并执行 extent 安全检查。
|
||||||
@@ -0,0 +1,173 @@
|
|||||||
|
{
|
||||||
|
"source_root": "/home/wwwroot/pbf-delivery-full-20260418-rebuild",
|
||||||
|
"target_root": "/home/wwwroot/pbf-delivery-kyushu-semantic-icon-v1-20260806",
|
||||||
|
"tiles_target": 4707,
|
||||||
|
"tiles_compared": 4707,
|
||||||
|
"tiles_with_errors": 0,
|
||||||
|
"errors": [],
|
||||||
|
"source_features": {
|
||||||
|
"baseline_area": 225324,
|
||||||
|
"baseline_outline": 401949,
|
||||||
|
"hole_area": 110994,
|
||||||
|
"land_area": 65455,
|
||||||
|
"bathymetry_line": 413730,
|
||||||
|
"depth_contour": 171277,
|
||||||
|
"navigation_marks": 11627,
|
||||||
|
"bridge_structure": 7224,
|
||||||
|
"hazard_boundary_outline": 20151,
|
||||||
|
"place_label_land": 10983,
|
||||||
|
"submerged_reef_area": 770,
|
||||||
|
"place_label_sea": 12092,
|
||||||
|
"anchor_caution_hazard_point": 12932,
|
||||||
|
"baseline_line": 14640,
|
||||||
|
"fixed_fishing_gear_area": 9044,
|
||||||
|
"onshore_structure_line": 114122,
|
||||||
|
"onshore_structure_point": 7623,
|
||||||
|
"anchor_caution_hazard_area": 1809,
|
||||||
|
"anchor_caution_hazard_outline": 1815,
|
||||||
|
"clearance_limit_line": 325,
|
||||||
|
"hazard_boundary_line": 37,
|
||||||
|
"onshore_structure_area": 3640,
|
||||||
|
"depth_contour_overview": 2154,
|
||||||
|
"depth_zone_739": 181,
|
||||||
|
"route_boundary_point": 78,
|
||||||
|
"route_area": 51,
|
||||||
|
"route_outline": 161,
|
||||||
|
"depth_zone_740": 9,
|
||||||
|
"route_axis_line": 14,
|
||||||
|
"depth_zone_700": 8,
|
||||||
|
"depth_zone_725": 4,
|
||||||
|
"seabed_line": 2106,
|
||||||
|
"seabed_text_point": 33376,
|
||||||
|
"facility_boundary_point": 1579,
|
||||||
|
"navigation_hazard_point": 6316,
|
||||||
|
"depth_zone_741": 497,
|
||||||
|
"depth_zone_748": 45,
|
||||||
|
"depth_zone_749": 43,
|
||||||
|
"clearance_limit_point": 261,
|
||||||
|
"clip_outline_754": 223,
|
||||||
|
"facility_boundary_area": 449,
|
||||||
|
"navigation_hazard_outline": 48,
|
||||||
|
"anchorage_area": 55,
|
||||||
|
"anchorage_outline": 55,
|
||||||
|
"anchorage_point": 54,
|
||||||
|
"facility_boundary_outline": 233,
|
||||||
|
"pilot_station_point": 16,
|
||||||
|
"navigation_hazard_area": 24,
|
||||||
|
"leading_line_outline": 16,
|
||||||
|
"clip_outline_730": 4,
|
||||||
|
"facility_boundary_area_transparent": 4
|
||||||
|
},
|
||||||
|
"target_features": {
|
||||||
|
"baseline_area": 225324,
|
||||||
|
"baseline_outline": 401949,
|
||||||
|
"hole_area": 110994,
|
||||||
|
"land_area": 65455,
|
||||||
|
"bathymetry_line": 413730,
|
||||||
|
"depth_contour": 171277,
|
||||||
|
"navigation_marks": 11627,
|
||||||
|
"bridge_structure": 7224,
|
||||||
|
"hazard_boundary_outline": 20151,
|
||||||
|
"place_label_land": 10983,
|
||||||
|
"submerged_reef_area": 770,
|
||||||
|
"place_label_sea": 12092,
|
||||||
|
"anchor_caution_hazard_point": 12932,
|
||||||
|
"baseline_line": 14640,
|
||||||
|
"fixed_fishing_gear_area": 9044,
|
||||||
|
"onshore_structure_line": 114122,
|
||||||
|
"onshore_structure_point": 7623,
|
||||||
|
"anchor_caution_hazard_area": 1809,
|
||||||
|
"anchor_caution_hazard_outline": 1815,
|
||||||
|
"clearance_limit_line": 325,
|
||||||
|
"hazard_boundary_line": 37,
|
||||||
|
"onshore_structure_area": 3640,
|
||||||
|
"depth_contour_overview": 2154,
|
||||||
|
"depth_zone_739": 181,
|
||||||
|
"route_boundary_point": 78,
|
||||||
|
"route_area": 51,
|
||||||
|
"route_outline": 161,
|
||||||
|
"depth_zone_740": 9,
|
||||||
|
"route_axis_line": 14,
|
||||||
|
"depth_zone_700": 8,
|
||||||
|
"depth_zone_725": 4,
|
||||||
|
"seabed_line": 2106,
|
||||||
|
"seabed_text_point": 33376,
|
||||||
|
"facility_boundary_point": 1579,
|
||||||
|
"navigation_hazard_point": 6316,
|
||||||
|
"depth_zone_741": 497,
|
||||||
|
"depth_zone_748": 45,
|
||||||
|
"depth_zone_749": 43,
|
||||||
|
"clearance_limit_point": 261,
|
||||||
|
"clip_outline_754": 223,
|
||||||
|
"facility_boundary_area": 449,
|
||||||
|
"navigation_hazard_outline": 48,
|
||||||
|
"anchorage_area": 55,
|
||||||
|
"anchorage_outline": 55,
|
||||||
|
"anchorage_point": 54,
|
||||||
|
"facility_boundary_outline": 233,
|
||||||
|
"pilot_station_point": 16,
|
||||||
|
"navigation_hazard_area": 24,
|
||||||
|
"leading_line_outline": 16,
|
||||||
|
"clip_outline_730": 4,
|
||||||
|
"facility_boundary_area_transparent": 4
|
||||||
|
},
|
||||||
|
"icon_counts": {
|
||||||
|
"icon_id:lt_hbr": 2536,
|
||||||
|
"arc_id:arc_open_YW": 204,
|
||||||
|
"arc_id:arc_YW": 977,
|
||||||
|
"arc_id:arc_G": 610,
|
||||||
|
"arc_id:arc_R": 769,
|
||||||
|
"icon_id:mk_lead_v": 33,
|
||||||
|
"icon_id:hz_foul": 3598,
|
||||||
|
"icon_id:hz_reef": 6659,
|
||||||
|
"icon_id:lt_lead_c": 165,
|
||||||
|
"icon_id:lm_mtn": 2059,
|
||||||
|
"icon_id:hz_overfall": 912,
|
||||||
|
"icon_id:lt_min": 4993,
|
||||||
|
"icon_id:bu_lat": 626,
|
||||||
|
"icon_id:lt_bcn": 1833,
|
||||||
|
"icon_id:lm_chim": 1907,
|
||||||
|
"icon_id:lm_twr": 2527,
|
||||||
|
"icon_id:hz_seaweed": 470,
|
||||||
|
"icon_id:lt_lead_a": 25,
|
||||||
|
"icon_id:bu_lit": 959,
|
||||||
|
"icon_id:lm_mar": 121,
|
||||||
|
"icon_id:lm_fish": 846,
|
||||||
|
"icon_id:lm_cus": 85,
|
||||||
|
"icon_id:lm_mon": 42,
|
||||||
|
"icon_id:bu_gen": 290,
|
||||||
|
"icon_id:hz_wreck_survey": 432,
|
||||||
|
"icon_id:hz_sandwave": 662,
|
||||||
|
"icon_id:lm_ctrl": 28,
|
||||||
|
"icon_id:bu_can": 38,
|
||||||
|
"icon_id:hz_outfall": 174,
|
||||||
|
"icon_id:hz_danger_clear": 26,
|
||||||
|
"icon_id:bu_pil": 77,
|
||||||
|
"icon_id:lm_prom": 8,
|
||||||
|
"icon_id:hz_whirl": 27,
|
||||||
|
"icon_id:mk_lead_c": 24,
|
||||||
|
"icon_id:hz_reef_danger": 25,
|
||||||
|
"icon_id:lt_lead_b": 16,
|
||||||
|
"icon_id:mk_vais": 12,
|
||||||
|
"icon_id:fac_fishport": 1164,
|
||||||
|
"icon_id:hz_rock_awash": 1397,
|
||||||
|
"icon_id:hz_rock_sub": 3932,
|
||||||
|
"icon_id:hz_danger_iso": 212,
|
||||||
|
"icon_id:fac_port": 261,
|
||||||
|
"icon_id:hz_tower": 57,
|
||||||
|
"icon_id:hz_wreck_sub": 50,
|
||||||
|
"icon_id:fac_seastation": 48,
|
||||||
|
"icon_id:hz_dolphin": 205,
|
||||||
|
"icon_id:fac_fisherina": 11,
|
||||||
|
"icon_id:fac_marina": 95,
|
||||||
|
"icon_id:an_quar": 33,
|
||||||
|
"icon_id:hz_wreck_hull": 10,
|
||||||
|
"icon_id:hz_pile": 340,
|
||||||
|
"icon_id:hz_obst": 60,
|
||||||
|
"icon_id:an_restrict": 2,
|
||||||
|
"icon_id:an_no_anchor": 4,
|
||||||
|
"icon_id:an_desig": 15
|
||||||
|
},
|
||||||
|
"old_prefix_counts": {},
|
||||||
|
"verdict": "PASS"
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# 九州语义图标测试版对象 / 几何 / 图标审计
|
||||||
|
|
||||||
|
- 来源:`/home/wwwroot/pbf-delivery-full-20260418-rebuild`
|
||||||
|
- 目标:`/home/wwwroot/pbf-delivery-kyushu-semantic-icon-v1-20260806`
|
||||||
|
- 目标瓦片:`4707`,实际比较:`4707`
|
||||||
|
- 有错误瓦片:`0`
|
||||||
|
- 旧图标前缀残留:`0`
|
||||||
|
- 结论:`PASS`
|
||||||
|
|
||||||
|
本审计忽略预期的 `chart_icon_image`、`icon_id`、`arc_id` 字段变化,逐图层比较对象数量、ID、几何和其余属性。
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
{
|
||||||
|
"used_keys": [
|
||||||
|
"an_desig",
|
||||||
|
"an_no_anchor",
|
||||||
|
"an_quar",
|
||||||
|
"an_restrict",
|
||||||
|
"arc_G",
|
||||||
|
"arc_R",
|
||||||
|
"arc_YW",
|
||||||
|
"arc_open_YW",
|
||||||
|
"bu_can",
|
||||||
|
"bu_gen",
|
||||||
|
"bu_lat",
|
||||||
|
"bu_lit",
|
||||||
|
"bu_pil",
|
||||||
|
"fac_fisherina",
|
||||||
|
"fac_fishport",
|
||||||
|
"fac_marina",
|
||||||
|
"fac_port",
|
||||||
|
"fac_seastation",
|
||||||
|
"hz_danger_clear",
|
||||||
|
"hz_danger_iso",
|
||||||
|
"hz_dolphin",
|
||||||
|
"hz_foul",
|
||||||
|
"hz_obst",
|
||||||
|
"hz_outfall",
|
||||||
|
"hz_overfall",
|
||||||
|
"hz_pile",
|
||||||
|
"hz_reef",
|
||||||
|
"hz_reef_danger",
|
||||||
|
"hz_rock_awash",
|
||||||
|
"hz_rock_sub",
|
||||||
|
"hz_sandwave",
|
||||||
|
"hz_seaweed",
|
||||||
|
"hz_tower",
|
||||||
|
"hz_whirl",
|
||||||
|
"hz_wreck_hull",
|
||||||
|
"hz_wreck_sub",
|
||||||
|
"hz_wreck_survey",
|
||||||
|
"lm_chim",
|
||||||
|
"lm_ctrl",
|
||||||
|
"lm_cus",
|
||||||
|
"lm_fish",
|
||||||
|
"lm_mar",
|
||||||
|
"lm_mon",
|
||||||
|
"lm_mtn",
|
||||||
|
"lm_prom",
|
||||||
|
"lm_twr",
|
||||||
|
"lt_bcn",
|
||||||
|
"lt_hbr",
|
||||||
|
"lt_lead_a",
|
||||||
|
"lt_lead_b",
|
||||||
|
"lt_lead_c",
|
||||||
|
"lt_min",
|
||||||
|
"mk_lead_c",
|
||||||
|
"mk_lead_v",
|
||||||
|
"mk_vais"
|
||||||
|
],
|
||||||
|
"used_key_count": 55,
|
||||||
|
"sprite_key_count": 64,
|
||||||
|
"missing_keys": [],
|
||||||
|
"legacy_sprite_keys": [],
|
||||||
|
"verdict": "PASS"
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# 九州测试版 Sprite 图标闭合审计
|
||||||
|
|
||||||
|
- 使用中的 icon_id/arc_id:`55`
|
||||||
|
- sprite 键数:`64`
|
||||||
|
- 缺失键:`0`
|
||||||
|
- 旧前缀键:`0`
|
||||||
|
- 结论:`PASS`
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
{
|
||||||
|
"compare_url": "http://192.168.200.184/newpec/navsea-compare-kyushu-semantic-icon-v1.html",
|
||||||
|
"cases": [
|
||||||
|
{
|
||||||
|
"id": "karatsu_kyushu_icon_v1_semantic_z12",
|
||||||
|
"label": "唐津九州语义图标测试",
|
||||||
|
"variant": "semantic",
|
||||||
|
"zoom": 12,
|
||||||
|
"center": [
|
||||||
|
129.9697,
|
||||||
|
33.4425
|
||||||
|
],
|
||||||
|
"radius_nm": 5,
|
||||||
|
"compare_url": "http://192.168.200.184/newpec/navsea-compare-kyushu-semantic-icon-v1.html?variant=semantic&audit=1¢er=129.9697%2C33.4425&zoom=12",
|
||||||
|
"changed_pixels": 287577,
|
||||||
|
"total_pixels": 364800,
|
||||||
|
"changed_ratio": 0.788314,
|
||||||
|
"mean_abs_rgb": [
|
||||||
|
39.3424,
|
||||||
|
42.4767,
|
||||||
|
74.167
|
||||||
|
],
|
||||||
|
"rms_rgb": [
|
||||||
|
61.2913,
|
||||||
|
62.6326,
|
||||||
|
97.1048
|
||||||
|
],
|
||||||
|
"diff_bbox": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
640,
|
||||||
|
513
|
||||||
|
],
|
||||||
|
"left_image": "report/kyushu_semantic_icon_v1_2026-08-06/visual/karatsu_kyushu_icon_v1_semantic_z12/compare_left.png",
|
||||||
|
"right_image": "report/kyushu_semantic_icon_v1_2026-08-06/visual/karatsu_kyushu_icon_v1_semantic_z12/compare_right.png",
|
||||||
|
"diff_image": "report/kyushu_semantic_icon_v1_2026-08-06/visual/karatsu_kyushu_icon_v1_semantic_z12/compare_diff.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "karatsu_kyushu_icon_v1_semantic_z10",
|
||||||
|
"label": "唐津九州语义图标测试",
|
||||||
|
"variant": "semantic",
|
||||||
|
"zoom": 10,
|
||||||
|
"center": [
|
||||||
|
129.9697,
|
||||||
|
33.4425
|
||||||
|
],
|
||||||
|
"radius_nm": 5,
|
||||||
|
"compare_url": "http://192.168.200.184/newpec/navsea-compare-kyushu-semantic-icon-v1.html?variant=semantic&audit=1¢er=129.9697%2C33.4425&zoom=10",
|
||||||
|
"changed_pixels": 274296,
|
||||||
|
"total_pixels": 364800,
|
||||||
|
"changed_ratio": 0.751908,
|
||||||
|
"mean_abs_rgb": [
|
||||||
|
33.6012,
|
||||||
|
36.7804,
|
||||||
|
64.1346
|
||||||
|
],
|
||||||
|
"rms_rgb": [
|
||||||
|
56.4791,
|
||||||
|
56.9124,
|
||||||
|
89.4452
|
||||||
|
],
|
||||||
|
"diff_bbox": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
640,
|
||||||
|
513
|
||||||
|
],
|
||||||
|
"left_image": "report/kyushu_semantic_icon_v1_2026-08-06/visual/karatsu_kyushu_icon_v1_semantic_z10/compare_left.png",
|
||||||
|
"right_image": "report/kyushu_semantic_icon_v1_2026-08-06/visual/karatsu_kyushu_icon_v1_semantic_z10/compare_right.png",
|
||||||
|
"diff_image": "report/kyushu_semantic_icon_v1_2026-08-06/visual/karatsu_kyushu_icon_v1_semantic_z10/compare_diff.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "hakata_kyushu_icon_v1_semantic_z12",
|
||||||
|
"label": "博多港九州语义图标测试",
|
||||||
|
"variant": "semantic",
|
||||||
|
"zoom": 12,
|
||||||
|
"center": [
|
||||||
|
130.335,
|
||||||
|
33.6385
|
||||||
|
],
|
||||||
|
"radius_nm": 10,
|
||||||
|
"compare_url": "http://192.168.200.184/newpec/navsea-compare-kyushu-semantic-icon-v1.html?variant=semantic&audit=1¢er=130.335%2C33.6385&zoom=12",
|
||||||
|
"changed_pixels": 237978,
|
||||||
|
"total_pixels": 364800,
|
||||||
|
"changed_ratio": 0.652352,
|
||||||
|
"mean_abs_rgb": [
|
||||||
|
30.9085,
|
||||||
|
30.6867,
|
||||||
|
39.4968
|
||||||
|
],
|
||||||
|
"rms_rgb": [
|
||||||
|
55.1912,
|
||||||
|
58.1514,
|
||||||
|
67.7886
|
||||||
|
],
|
||||||
|
"diff_bbox": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
640,
|
||||||
|
513
|
||||||
|
],
|
||||||
|
"left_image": "report/kyushu_semantic_icon_v1_2026-08-06/visual/hakata_kyushu_icon_v1_semantic_z12/compare_left.png",
|
||||||
|
"right_image": "report/kyushu_semantic_icon_v1_2026-08-06/visual/hakata_kyushu_icon_v1_semantic_z12/compare_right.png",
|
||||||
|
"diff_image": "report/kyushu_semantic_icon_v1_2026-08-06/visual/hakata_kyushu_icon_v1_semantic_z12/compare_diff.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "hakata_kyushu_icon_v1_semantic_z10",
|
||||||
|
"label": "博多港九州语义图标测试",
|
||||||
|
"variant": "semantic",
|
||||||
|
"zoom": 10,
|
||||||
|
"center": [
|
||||||
|
130.335,
|
||||||
|
33.6385
|
||||||
|
],
|
||||||
|
"radius_nm": 10,
|
||||||
|
"compare_url": "http://192.168.200.184/newpec/navsea-compare-kyushu-semantic-icon-v1.html?variant=semantic&audit=1¢er=130.335%2C33.6385&zoom=10",
|
||||||
|
"changed_pixels": 236727,
|
||||||
|
"total_pixels": 364800,
|
||||||
|
"changed_ratio": 0.648923,
|
||||||
|
"mean_abs_rgb": [
|
||||||
|
31.9821,
|
||||||
|
32.9781,
|
||||||
|
55.3087
|
||||||
|
],
|
||||||
|
"rms_rgb": [
|
||||||
|
57.9478,
|
||||||
|
56.188,
|
||||||
|
83.9112
|
||||||
|
],
|
||||||
|
"diff_bbox": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
640,
|
||||||
|
513
|
||||||
|
],
|
||||||
|
"left_image": "report/kyushu_semantic_icon_v1_2026-08-06/visual/hakata_kyushu_icon_v1_semantic_z10/compare_left.png",
|
||||||
|
"right_image": "report/kyushu_semantic_icon_v1_2026-08-06/visual/hakata_kyushu_icon_v1_semantic_z10/compare_right.png",
|
||||||
|
"diff_image": "report/kyushu_semantic_icon_v1_2026-08-06/visual/hakata_kyushu_icon_v1_semantic_z10/compare_diff.png"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
# 全国 AOI 截图对比审计
|
||||||
|
|
||||||
|
## 总览
|
||||||
|
|
||||||
|
- compare page: `http://192.168.200.184/newpec/navsea-compare-kyushu-semantic-icon-v1.html`
|
||||||
|
- cases: `4`
|
||||||
|
|
||||||
|
## 差异排序
|
||||||
|
|
||||||
|
### 唐津九州语义图标测试 · semantic · z12
|
||||||
|
|
||||||
|
- changed ratio: `0.788314`
|
||||||
|
- changed pixels: `287577` / `364800`
|
||||||
|
- mean abs rgb: `[39.3424, 42.4767, 74.167]`
|
||||||
|
- compare url: `http://192.168.200.184/newpec/navsea-compare-kyushu-semantic-icon-v1.html?variant=semantic&audit=1¢er=129.9697%2C33.4425&zoom=12`
|
||||||
|
- left image: `report/kyushu_semantic_icon_v1_2026-08-06/visual/karatsu_kyushu_icon_v1_semantic_z12/compare_left.png`
|
||||||
|
- right image: `report/kyushu_semantic_icon_v1_2026-08-06/visual/karatsu_kyushu_icon_v1_semantic_z12/compare_right.png`
|
||||||
|
- diff image: `report/kyushu_semantic_icon_v1_2026-08-06/visual/karatsu_kyushu_icon_v1_semantic_z12/compare_diff.png`
|
||||||
|
|
||||||
|
### 唐津九州语义图标测试 · semantic · z10
|
||||||
|
|
||||||
|
- changed ratio: `0.751908`
|
||||||
|
- changed pixels: `274296` / `364800`
|
||||||
|
- mean abs rgb: `[33.6012, 36.7804, 64.1346]`
|
||||||
|
- compare url: `http://192.168.200.184/newpec/navsea-compare-kyushu-semantic-icon-v1.html?variant=semantic&audit=1¢er=129.9697%2C33.4425&zoom=10`
|
||||||
|
- left image: `report/kyushu_semantic_icon_v1_2026-08-06/visual/karatsu_kyushu_icon_v1_semantic_z10/compare_left.png`
|
||||||
|
- right image: `report/kyushu_semantic_icon_v1_2026-08-06/visual/karatsu_kyushu_icon_v1_semantic_z10/compare_right.png`
|
||||||
|
- diff image: `report/kyushu_semantic_icon_v1_2026-08-06/visual/karatsu_kyushu_icon_v1_semantic_z10/compare_diff.png`
|
||||||
|
|
||||||
|
### 博多港九州语义图标测试 · semantic · z12
|
||||||
|
|
||||||
|
- changed ratio: `0.652352`
|
||||||
|
- changed pixels: `237978` / `364800`
|
||||||
|
- mean abs rgb: `[30.9085, 30.6867, 39.4968]`
|
||||||
|
- compare url: `http://192.168.200.184/newpec/navsea-compare-kyushu-semantic-icon-v1.html?variant=semantic&audit=1¢er=130.335%2C33.6385&zoom=12`
|
||||||
|
- left image: `report/kyushu_semantic_icon_v1_2026-08-06/visual/hakata_kyushu_icon_v1_semantic_z12/compare_left.png`
|
||||||
|
- right image: `report/kyushu_semantic_icon_v1_2026-08-06/visual/hakata_kyushu_icon_v1_semantic_z12/compare_right.png`
|
||||||
|
- diff image: `report/kyushu_semantic_icon_v1_2026-08-06/visual/hakata_kyushu_icon_v1_semantic_z12/compare_diff.png`
|
||||||
|
|
||||||
|
### 博多港九州语义图标测试 · semantic · z10
|
||||||
|
|
||||||
|
- changed ratio: `0.648923`
|
||||||
|
- changed pixels: `236727` / `364800`
|
||||||
|
- mean abs rgb: `[31.9821, 32.9781, 55.3087]`
|
||||||
|
- compare url: `http://192.168.200.184/newpec/navsea-compare-kyushu-semantic-icon-v1.html?variant=semantic&audit=1¢er=130.335%2C33.6385&zoom=10`
|
||||||
|
- left image: `report/kyushu_semantic_icon_v1_2026-08-06/visual/hakata_kyushu_icon_v1_semantic_z10/compare_left.png`
|
||||||
|
- right image: `report/kyushu_semantic_icon_v1_2026-08-06/visual/hakata_kyushu_icon_v1_semantic_z10/compare_right.png`
|
||||||
|
- diff image: `report/kyushu_semantic_icon_v1_2026-08-06/visual/hakata_kyushu_icon_v1_semantic_z10/compare_diff.png`
|
||||||
101
src/pbf/navsea-compare-kyushu-semantic-icon-v1.html
Normal file
101
src/pbf/navsea-compare-kyushu-semantic-icon-v1.html
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
|
<title>NavSea 九州语义图标替换测试 v1</title>
|
||||||
|
<link href="https://unpkg.com/maplibre-gl@4.7.1/dist/maplibre-gl.css" rel="stylesheet" />
|
||||||
|
<style>
|
||||||
|
:root { --bg:#eef2ed; --panel:rgba(250,248,242,.95); --ink:#17232b; --muted:#667780; --line:rgba(23,35,43,.14); }
|
||||||
|
* { box-sizing:border-box; }
|
||||||
|
html,body { margin:0; width:100%; height:100%; overflow:hidden; background:var(--bg); color:var(--ink); font-family:"Avenir Next","Segoe UI","PingFang SC","Noto Sans SC",sans-serif; }
|
||||||
|
body { display:grid; grid-template-rows:auto 1fr; }
|
||||||
|
.toolbar { display:flex; align-items:center; justify-content:space-between; gap:10px; padding:8px 12px; background:var(--panel); border-bottom:1px solid var(--line); box-shadow:0 8px 20px rgba(23,35,43,.12); z-index:10; }
|
||||||
|
.title { font-size:16px; font-weight:700; }
|
||||||
|
.subtitle { margin-top:2px; color:var(--muted); font-size:11px; line-height:1.35; }
|
||||||
|
.actions { display:flex; align-items:center; justify-content:flex-end; gap:7px; flex-wrap:wrap; }
|
||||||
|
.chip { max-width:260px; padding:7px 9px; border:1px solid var(--line); border-radius:999px; background:#fffdf8; font-size:10px; font-weight:700; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
|
||||||
|
button { height:31px; padding:0 11px; border:1px solid rgba(23,35,43,.16); border-radius:8px; background:#17333f; color:#fff; font:inherit; font-size:11px; font-weight:700; cursor:pointer; }
|
||||||
|
button:disabled { opacity:.55; cursor:wait; }
|
||||||
|
.layout { min-height:0; display:grid; grid-template-columns:1fr 1fr; }
|
||||||
|
.pane { position:relative; min-width:0; border-right:1px solid var(--line); }
|
||||||
|
.pane:last-child { border-right:0; }
|
||||||
|
.map { position:absolute; inset:0; }
|
||||||
|
.tag { position:absolute; top:10px; left:10px; z-index:2; padding:8px 10px; border:1px solid var(--line); border-radius:10px; background:var(--panel); box-shadow:0 8px 18px rgba(23,35,43,.12); font-size:11px; }
|
||||||
|
.tag strong { display:block; margin-bottom:2px; font-size:12px; }
|
||||||
|
.tag span { color:var(--muted); }
|
||||||
|
.inspect { position:fixed; right:12px; bottom:12px; z-index:5; width:min(390px,calc(100vw - 24px)); max-height:42vh; overflow:auto; padding:10px 12px; border:1px solid var(--line); border-radius:12px; background:var(--panel); box-shadow:0 12px 26px rgba(23,35,43,.16); }
|
||||||
|
.inspect h3 { margin:0 0 5px; font-size:12px; }
|
||||||
|
.inspect p { margin:0 0 7px; color:var(--muted); font-size:10px; }
|
||||||
|
.inspect dl { display:grid; grid-template-columns:84px 1fr; gap:3px 7px; margin:0 0 7px; font-size:10px; }
|
||||||
|
.inspect dt { color:var(--muted); font-weight:700; }
|
||||||
|
.inspect dd { margin:0; word-break:break-word; }
|
||||||
|
.inspect pre { margin:0; padding:7px; border-radius:8px; background:#17232b; color:#eef4f7; font-size:10px; white-space:pre-wrap; word-break:break-word; }
|
||||||
|
#status { position:fixed; left:50%; bottom:12px; z-index:4; transform:translateX(-50%); max-width:calc(100vw - 430px); padding:7px 11px; border-radius:999px; background:rgba(23,35,43,.86); color:#fff; font-size:10px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
|
||||||
|
@media (max-width:900px) { .toolbar { align-items:flex-start; flex-direction:column; } .actions { justify-content:flex-start; } #status { max-width:calc(100vw - 24px); bottom:6px; } .inspect { bottom:38px; } }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header class="toolbar">
|
||||||
|
<div>
|
||||||
|
<div class="title">NavSea 九州语义图标替换测试 v1</div>
|
||||||
|
<div class="subtitle">左侧:原始 newpec;右侧:当前 Full 基线生成的九州语义图标测试版。两侧同步平移、缩放,可点击对象查看属性。</div>
|
||||||
|
</div>
|
||||||
|
<div class="actions">
|
||||||
|
<span id="version" class="chip">HTML: kyushu-semantic-icon-v1-20260806</span>
|
||||||
|
<span id="style" class="chip">Style: 加载中</span>
|
||||||
|
<button id="reload" type="button">重新加载</button>
|
||||||
|
<button id="home" type="button">回到九州</button>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main class="layout">
|
||||||
|
<section class="pane"><div class="tag"><strong style="color:#305f72">左侧 · 原始 newpec</strong><span>原始瓦片 + 原始 sprite</span></div><div id="original" class="map"></div></section>
|
||||||
|
<section class="pane"><div class="tag"><strong style="color:#8b5e34">右侧 · 语义图标测试版</strong><span>Kyushu semantic icon v1</span></div><div id="delivery" class="map"></div></section>
|
||||||
|
</main>
|
||||||
|
<aside class="inspect"><h3>点击对比</h3><p id="hint">点击左右任一地图对象,查看 source-layer、render layer 和属性。</p><dl><dt>面板</dt><dd id="side">-</dd><dt>坐标</dt><dd id="lnglat">-</dd><dt>source-layer</dt><dd id="layer">-</dd><dt>render layer</dt><dd id="render">-</dd></dl><pre id="json">{\n "message": "等待点击对象"\n}</pre></aside>
|
||||||
|
<div id="status">等待加载样式…</div>
|
||||||
|
<script src="https://unpkg.com/maplibre-gl@4.7.1/dist/maplibre-gl.js"></script>
|
||||||
|
<script>
|
||||||
|
const VERSION = "kyushu-semantic-icon-v1-20260806";
|
||||||
|
const ORIGINAL_STYLE = "./domain/style.navsea-newpec-kyushu-icon-test-v1.json";
|
||||||
|
const DELIVERY_STYLE = "./domain/style.navsea-delivery-kyushu-semantic-icon-v1.json";
|
||||||
|
const CENTER = [130.4, 32.5], ZOOM = 7.5;
|
||||||
|
const q = new URLSearchParams(location.search);
|
||||||
|
const requestedCenter = (q.get("center") || "").split(",").map(Number);
|
||||||
|
const camera = { center: requestedCenter.length === 2 && requestedCenter.every(Number.isFinite) ? requestedCenter : CENTER, zoom: Number(q.get("zoom")) || ZOOM, bearing: Number(q.get("bearing")) || 0, pitch: Number(q.get("pitch")) || 0 };
|
||||||
|
let originalMap, deliveryMap, lock = false, cacheVersion = `${VERSION}-${Date.now()}`;
|
||||||
|
const $ = (id) => document.getElementById(id);
|
||||||
|
function bust(url) { const join = url.includes("?") ? "&" : "?"; return `${url}${join}v=${encodeURIComponent(cacheVersion)}`; }
|
||||||
|
function touch(style) {
|
||||||
|
const next = structuredClone(style);
|
||||||
|
if (next.sprite) next.sprite = bust(next.sprite);
|
||||||
|
if (next.glyphs) next.glyphs = bust(next.glyphs);
|
||||||
|
for (const source of Object.values(next.sources || {})) {
|
||||||
|
if (source.tiles) source.tiles = source.tiles.map(bust);
|
||||||
|
if (source.url) source.url = bust(source.url);
|
||||||
|
}
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
async function loadStyle(url) { const response = await fetch(bust(url), { cache:"no-store" }); if (!response.ok) throw new Error(`加载样式失败: ${url}`); return touch(await response.json()); }
|
||||||
|
function sync(primary, secondary) { primary.on("move", () => { if (lock) return; lock = true; secondary.jumpTo({ center:primary.getCenter(), zoom:primary.getZoom(), bearing:primary.getBearing(), pitch:primary.getPitch() }); lock = false; }); }
|
||||||
|
function inspect(map, label) { map.on("click", (event) => { const feature = map.queryRenderedFeatures(event.point)[0]; if (!feature) { $("hint").textContent = `${label}:点击位置未命中对象。`; return; } $("hint").textContent = "已选中对象。继续点击可查看另一侧。"; $("side").textContent = label; $("lnglat").textContent = `${event.lngLat.lng.toFixed(6)}, ${event.lngLat.lat.toFixed(6)}`; $("layer").textContent = feature.sourceLayer || "-"; $("render").textContent = feature.layer?.id || "-"; $("json").textContent = JSON.stringify(feature.properties || {}, null, 2); }); }
|
||||||
|
async function start() {
|
||||||
|
$("reload").disabled = true; $("status").textContent = `正在加载九州双屏… ${VERSION}`; cacheVersion = `${VERSION}-${Date.now()}`;
|
||||||
|
try {
|
||||||
|
const [leftStyle, rightStyle] = await Promise.all([loadStyle(ORIGINAL_STYLE), loadStyle(DELIVERY_STYLE)]);
|
||||||
|
$("style").textContent = "Style: newpec 原始 / delivery semantic v1";
|
||||||
|
if (!originalMap) {
|
||||||
|
originalMap = new maplibregl.Map({ container:"original", style:leftStyle, ...camera });
|
||||||
|
deliveryMap = new maplibregl.Map({ container:"delivery", style:rightStyle, ...camera });
|
||||||
|
originalMap.addControl(new maplibregl.NavigationControl(), "top-right"); deliveryMap.addControl(new maplibregl.NavigationControl(), "top-right");
|
||||||
|
sync(originalMap, deliveryMap); sync(deliveryMap, originalMap); inspect(originalMap, "左侧原始版"); inspect(deliveryMap, "右侧语义版");
|
||||||
|
let loaded = 0; const mark = () => { loaded += 1; if (loaded === 2) $("status").textContent = `九州双屏已加载,可拖动、缩放、点击审计。${VERSION}`; }; originalMap.once("load", mark); deliveryMap.once("load", mark);
|
||||||
|
} else {
|
||||||
|
let loaded = 0; const mark = () => { loaded += 1; if (loaded === 2) { originalMap.jumpTo(camera); deliveryMap.jumpTo(camera); $("status").textContent = `九州双屏已重新加载。${VERSION}`; } }; originalMap.once("style.load", mark); deliveryMap.once("style.load", mark); originalMap.setStyle(leftStyle, { diff:false }); deliveryMap.setStyle(rightStyle, { diff:false });
|
||||||
|
}
|
||||||
|
} catch (error) { console.error(error); $("status").textContent = error.message || "加载失败"; } finally { $("reload").disabled = false; }
|
||||||
|
}
|
||||||
|
$("reload").addEventListener("click", start); $("home").addEventListener("click", () => { if (originalMap && deliveryMap) { originalMap.jumpTo(camera); deliveryMap.jumpTo(camera); } }); start();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
2680
src/pbf/style.navsea-delivery-kyushu-semantic-icon-v1.json
Normal file
2680
src/pbf/style.navsea-delivery-kyushu-semantic-icon-v1.json
Normal file
File diff suppressed because it is too large
Load Diff
5656
src/pbf/style.navsea-newpec-kyushu-icon-test-v1.json
Normal file
5656
src/pbf/style.navsea-newpec-kyushu-icon-test-v1.json
Normal file
File diff suppressed because it is too large
Load Diff
16
tasks/pbf/NavSea_Kyushu_语义图标视觉审计范围-v1.json
Normal file
16
tasks/pbf/NavSea_Kyushu_语义图标视觉审计范围-v1.json
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "hakata_kyushu_icon_v1",
|
||||||
|
"label": "博多港九州语义图标测试",
|
||||||
|
"center": [130.335, 33.6385],
|
||||||
|
"radius_nm": 10,
|
||||||
|
"zoom_levels": [10, 12]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "karatsu_kyushu_icon_v1",
|
||||||
|
"label": "唐津九州语义图标测试",
|
||||||
|
"center": [129.9697, 33.4425],
|
||||||
|
"radius_nm": 5,
|
||||||
|
"zoom_levels": [10, 12]
|
||||||
|
}
|
||||||
|
]
|
||||||
156
tasks/pbf/NavSea_语义图标替换表-v1.md
Normal file
156
tasks/pbf/NavSea_语义图标替换表-v1.md
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
# NavSea 语义图标替换表-v1
|
||||||
|
|
||||||
|
状态:设计稿,尚未写入 PBF、style 或 sprite。
|
||||||
|
|
||||||
|
基线:
|
||||||
|
|
||||||
|
- PBF:`/home/wwwroot/pbf-delivery-full-20260418-rebuild`
|
||||||
|
- style:`src/pbf/style.navsea-delivery-full-semantic-extentfix.json`
|
||||||
|
- sprite:`/mnt/sda1/www/newpec/sprite-semantic/sprite`
|
||||||
|
|
||||||
|
## 1. 统一规则
|
||||||
|
|
||||||
|
PBF、style 和 `sprite.json` 使用同一个短语 ID。PBF 中建议使用:
|
||||||
|
|
||||||
|
```text
|
||||||
|
icon_id:普通点状图标
|
||||||
|
arc_id:灯弧图标
|
||||||
|
```
|
||||||
|
|
||||||
|
`class_code` 继续保留用于对象追溯,但不再被 style 用来拼接图标名称。
|
||||||
|
|
||||||
|
颜色缩写:
|
||||||
|
|
||||||
|
| 缩写 | 含义 |
|
||||||
|
|---|---|
|
||||||
|
| `G` | 绿色 |
|
||||||
|
| `R` | 红色 |
|
||||||
|
| `Y` | 黄色 |
|
||||||
|
| `W` | 白色 |
|
||||||
|
| `B` | 蓝色 |
|
||||||
|
| `YW` | 黄/白组合 |
|
||||||
|
|
||||||
|
## 2. 灯弧
|
||||||
|
|
||||||
|
| 当前 key | 新 ID | 条件/含义 |
|
||||||
|
|---|---|---|
|
||||||
|
| `arc-daytime-m1` | `arc_G` | 绿色闭合灯弧 |
|
||||||
|
| `arc-daytime-m2` | `arc_R` | 红色闭合灯弧 |
|
||||||
|
| `arc-daytime-m3` | `arc_YW` | 黄/白闭合灯弧 |
|
||||||
|
| `arc-daytime-04027289` | `arc_open_YW` | `coastal_lighthouse_over_15m` 且 `light_sector_mode=sector` |
|
||||||
|
|
||||||
|
普通灯弧按 `light_color_code` 选择 `arc_G`、`arc_R` 或 `arc_YW`;扇弧条件优先级最高。
|
||||||
|
|
||||||
|
## 3. 航标、灯塔、浮标
|
||||||
|
|
||||||
|
| 当前 key | 新 ID | 含义 |
|
||||||
|
|---|---|---|
|
||||||
|
| `symbol-daytime-300` | `lt_cst` | 沿岸灯台 |
|
||||||
|
| `symbol-daytime-301` | `lt_hbr` | 港湾灯台 |
|
||||||
|
| `symbol-daytime-302` | `lt_bkw` | 防波堤灯台 |
|
||||||
|
| `symbol-daytime-303` | `lt_min` | 小型灯 |
|
||||||
|
| `symbol-daytime-30500001` | `lt_lead_a` | 导标变体 A |
|
||||||
|
| `symbol-daytime-30500002` | `lt_lead_b` | 导标变体 B |
|
||||||
|
| `symbol-daytime-30500003` | `lt_lead_c` | 导标变体 C |
|
||||||
|
| `symbol-daytime-30700001` | `lt_up_G` | 绿色上向灯 |
|
||||||
|
| `symbol-daytime-30700002` | `lt_up_R` | 红色上向灯 |
|
||||||
|
| `symbol-daytime-30700003` | `mk_lead_c` | 导标变体 |
|
||||||
|
| `symbol-daytime-308` | `mk_lead_v` | 导标变体 |
|
||||||
|
| `symbol-daytime-310` | `lt_bcn` | 灯标 |
|
||||||
|
| `symbol-daytime-320` | `bu_lit` | 灯浮标 |
|
||||||
|
| `symbol-daytime-321` | `bu_gen` | 普通浮标 |
|
||||||
|
| `symbol-daytime-323` | `bu_pil` | 圆柱/柱型浮标 |
|
||||||
|
| `symbol-daytime-325` | `bu_can` | 圆筒型浮标 |
|
||||||
|
| `symbol-daytime-327` | `bu_lat` | 桁架型浮标 |
|
||||||
|
| `symbol-daytime-335359` | `mk_vais` | V-AIS 航标 |
|
||||||
|
| `symbol-daytime-719` | `an_quar` | 检疫锚地 |
|
||||||
|
|
||||||
|
现有 style 中的别名也统一归并:
|
||||||
|
|
||||||
|
| 当前 key | 新 ID |
|
||||||
|
|---|---|
|
||||||
|
| `harbor_lighthouse` | `lt_hbr` |
|
||||||
|
| `breakwater_lighthouse` | `lt_bkw` |
|
||||||
|
|
||||||
|
## 4. 危险物与鱼礁
|
||||||
|
|
||||||
|
| 当前 class_code / key | 新 ID | 含义 |
|
||||||
|
|---|---|---|
|
||||||
|
| `401`、`402`、`403` / `symbol-daytime-401` | `hz_rock_awash` | 水上岩、干出岩、洗岩组 |
|
||||||
|
| `404` / `symbol-daytime-404` | `hz_rock_sub` | 暗岩 |
|
||||||
|
| `405` / `symbol-daytime-405` | `hz_danger_clear` | 扫海后的危险物 |
|
||||||
|
| `409` / `symbol-daytime-409` | `hz_danger_iso` | 孤立危险物 |
|
||||||
|
| `410` / `symbol-daytime-410` | `hz_wreck_hull` | 船体露出沉船 |
|
||||||
|
| `412` / `symbol-daytime-412` | `hz_wreck_sub` | 危险全沉没船 |
|
||||||
|
| `413`、`415` / `symbol-daytime-413` | `hz_wreck_survey` | 测量/调查后的沉船 |
|
||||||
|
| `420` / `symbol-daytime-420` | `hz_foul` | 险恶物 |
|
||||||
|
| `421` / `symbol-daytime-421` | `hz_sandwave` | 沙波 |
|
||||||
|
| `422` / `symbol-daytime-422` | `hz_overfall` | 急潮、波纹、激潮 |
|
||||||
|
| `424` / `symbol-daytime-424` | `hz_whirl` | 渦流 |
|
||||||
|
| `425` / `symbol-daytime-425` | `hz_seaweed` | 海草 |
|
||||||
|
| `427` / `symbol-daytime-427` | `hz_obst` | 障碍物 |
|
||||||
|
| `428` / `symbol-daytime-428` | `hz_reef` | 鱼礁 |
|
||||||
|
| `429` / `symbol-daytime-429` | `hz_reef_danger` | 危险鱼礁 |
|
||||||
|
| `431` / `symbol-daytime-431` | `hz_tower` | 塔、橹、测台 |
|
||||||
|
| `432` / `symbol-daytime-432` | `hz_pile` | 墩柱、桩、杭 |
|
||||||
|
| `433` / `symbol-daytime-433` | `hz_dolphin` | 系缆墩 |
|
||||||
|
| `434` / `symbol-daytime-434` | `hz_outfall` | 海底设施、排水口、取水口 |
|
||||||
|
|
||||||
|
## 5. 陆上地标
|
||||||
|
|
||||||
|
这些图标由 `onshore_structure_point` 的 `class_code` 生成,必须在重建 PBF 时直接写入 `icon_id`,不能继续由 style 动态拼接编号。
|
||||||
|
|
||||||
|
| class_code | canonical_object_type | 新 ID |
|
||||||
|
|---:|---|---|
|
||||||
|
| 640 | `chimney` | `lm_chim` |
|
||||||
|
| 650 | `tower_yagura_windmill` | `lm_twr` |
|
||||||
|
| 660 | `maritime_office` | `lm_mar` |
|
||||||
|
| 661 | `fishing_cooperative` | `lm_fish` |
|
||||||
|
| 662 | `customs_office` | `lm_cus` |
|
||||||
|
| 680 | 陆上显著物(观览车等) | `lm_prom` |
|
||||||
|
| 681 | `mountain_top` | `lm_mtn` |
|
||||||
|
| 682 | 管制信号所 | `lm_ctrl` |
|
||||||
|
| 698 | `other_landmark_monument` | `lm_mon` |
|
||||||
|
|
||||||
|
## 6. 当前 PBF 中的直接图标值
|
||||||
|
|
||||||
|
当前全国 Full PBF 实际出现的 `chart_icon_image` 值,均应落入本表:
|
||||||
|
|
||||||
|
```text
|
||||||
|
symbol-daytime-301
|
||||||
|
symbol-daytime-303
|
||||||
|
symbol-daytime-30500001
|
||||||
|
symbol-daytime-30500002
|
||||||
|
symbol-daytime-30500003
|
||||||
|
symbol-daytime-30700003
|
||||||
|
symbol-daytime-308
|
||||||
|
symbol-daytime-310
|
||||||
|
symbol-daytime-320
|
||||||
|
symbol-daytime-321
|
||||||
|
symbol-daytime-323
|
||||||
|
symbol-daytime-325
|
||||||
|
symbol-daytime-327
|
||||||
|
symbol-daytime-335359
|
||||||
|
symbol-daytime-405
|
||||||
|
symbol-daytime-410
|
||||||
|
symbol-daytime-412
|
||||||
|
symbol-daytime-413
|
||||||
|
symbol-daytime-428
|
||||||
|
symbol-daytime-429
|
||||||
|
symbol-daytime-719
|
||||||
|
```
|
||||||
|
|
||||||
|
其中 `symbol-daytime-719` 当前语义建议为:
|
||||||
|
|
||||||
|
```text
|
||||||
|
an_quar = quarantine anchorage
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. 实施约束
|
||||||
|
|
||||||
|
- 本表确认后,统一重建全部 Full PBF,不在现有 PBF 上做局部替换。
|
||||||
|
- style 的 `icon-image` 统一读取 `icon_id` 或 `arc_id`,删除 `class_code` 拼接逻辑。
|
||||||
|
- sprite JSON key 与新 ID 完全一致。
|
||||||
|
- `class_code`、FID 和 source-layer 继续保留,用于反向追溯和对象审计。
|
||||||
|
- `symbol-daytime-*`、`arc-daytime-*` 只允许出现在转换审计日志或历史映射表中,不能出现在正式 PBF、正式 style 和正式 sprite JSON 中。
|
||||||
|
- `symbol-daytime-662` 对应 `lm_cus`,需要补上海关图标素材。
|
||||||
224
tasks/pbf/navsea_semantic_icon_map_v1.json
Normal file
224
tasks/pbf/navsea_semantic_icon_map_v1.json
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
{
|
||||||
|
"version": "semantic-icon-v1",
|
||||||
|
"baseline": "full-semantic-extentfix",
|
||||||
|
"fields": {
|
||||||
|
"point_icon": "icon_id",
|
||||||
|
"light_arc": "arc_id",
|
||||||
|
"legacy_point_icon": "chart_icon_image"
|
||||||
|
},
|
||||||
|
"color_codes": {
|
||||||
|
"green": "G",
|
||||||
|
"red": "R",
|
||||||
|
"yellow": "Y",
|
||||||
|
"white": "W",
|
||||||
|
"blue": "B",
|
||||||
|
"yellow_white": "YW"
|
||||||
|
},
|
||||||
|
"sprite_key_map": {
|
||||||
|
"symbol-daytime-300": "lt_cst",
|
||||||
|
"symbol-daytime-301": "lt_hbr",
|
||||||
|
"symbol-daytime-302": "lt_bkw",
|
||||||
|
"symbol-daytime-303": "lt_min",
|
||||||
|
"symbol-daytime-30500001": "lt_lead_a",
|
||||||
|
"symbol-daytime-30500002": "lt_lead_b",
|
||||||
|
"symbol-daytime-30500003": "lt_lead_c",
|
||||||
|
"symbol-daytime-30700001": "lt_up_G",
|
||||||
|
"symbol-daytime-30700002": "lt_up_R",
|
||||||
|
"symbol-daytime-30700003": "mk_lead_c",
|
||||||
|
"symbol-daytime-308": "mk_lead_v",
|
||||||
|
"symbol-daytime-310": "lt_bcn",
|
||||||
|
"symbol-daytime-320": "bu_lit",
|
||||||
|
"symbol-daytime-321": "bu_gen",
|
||||||
|
"symbol-daytime-323": "bu_pil",
|
||||||
|
"symbol-daytime-325": "bu_can",
|
||||||
|
"symbol-daytime-327": "bu_lat",
|
||||||
|
"symbol-daytime-335359": "mk_vais",
|
||||||
|
"symbol-daytime-401": "hz_rock_awash",
|
||||||
|
"symbol-daytime-404": "hz_rock_sub",
|
||||||
|
"symbol-daytime-405": "hz_danger_clear",
|
||||||
|
"symbol-daytime-409": "hz_danger_iso",
|
||||||
|
"symbol-daytime-410": "hz_wreck_hull",
|
||||||
|
"symbol-daytime-412": "hz_wreck_sub",
|
||||||
|
"symbol-daytime-413": "hz_wreck_survey",
|
||||||
|
"symbol-daytime-420": "hz_foul",
|
||||||
|
"symbol-daytime-421": "hz_sandwave",
|
||||||
|
"symbol-daytime-422": "hz_overfall",
|
||||||
|
"symbol-daytime-424": "hz_whirl",
|
||||||
|
"symbol-daytime-425": "hz_seaweed",
|
||||||
|
"symbol-daytime-427": "hz_obst",
|
||||||
|
"symbol-daytime-428": "hz_reef",
|
||||||
|
"symbol-daytime-429": "hz_reef_danger",
|
||||||
|
"symbol-daytime-431": "hz_tower",
|
||||||
|
"symbol-daytime-432": "hz_pile",
|
||||||
|
"symbol-daytime-433": "hz_dolphin",
|
||||||
|
"symbol-daytime-434": "hz_outfall",
|
||||||
|
"symbol-daytime-640": "lm_chim",
|
||||||
|
"symbol-daytime-650": "lm_twr",
|
||||||
|
"symbol-daytime-660": "lm_mar",
|
||||||
|
"symbol-daytime-661": "lm_fish",
|
||||||
|
"symbol-daytime-662": "lm_cus",
|
||||||
|
"symbol-daytime-680": "lm_prom",
|
||||||
|
"symbol-daytime-681": "lm_mtn",
|
||||||
|
"symbol-daytime-682": "lm_ctrl",
|
||||||
|
"symbol-daytime-698": "lm_mon",
|
||||||
|
"symbol-daytime-719": "an_quar",
|
||||||
|
"symbol-daytime-720": "an_desig",
|
||||||
|
"symbol-daytime-721": "an_restrict",
|
||||||
|
"symbol-daytime-724": "an_no_anchor",
|
||||||
|
"symbol-daytime-505": "fac_port",
|
||||||
|
"symbol-daytime-520": "fac_fishport",
|
||||||
|
"symbol-daytime-530": "fac_marina",
|
||||||
|
"symbol-daytime-540": "fac_fisherina",
|
||||||
|
"symbol-daytime-550": "fac_seastation",
|
||||||
|
"harbor_lighthouse": "lt_hbr",
|
||||||
|
"breakwater_lighthouse": "lt_bkw",
|
||||||
|
"coastal_lighthouse": "lt_cst",
|
||||||
|
"light_minor": "lt_min",
|
||||||
|
"leading_light_variant_30500001": "lt_lead_a",
|
||||||
|
"leading_light_variantt_30500001": "lt_lead_a",
|
||||||
|
"leading_light_variant_30500002": "lt_lead_b",
|
||||||
|
"leading_light_variantt_30500002": "lt_lead_b",
|
||||||
|
"leading_light_variant_30500003": "lt_lead_c",
|
||||||
|
"leading_light_variantt_30500003": "lt_lead_c",
|
||||||
|
"leading_mark_variant_30700003": "mk_lead_c",
|
||||||
|
"leading_mark_variantt_30700003": "mk_lead_c",
|
||||||
|
"leading_mark_variant_308": "mk_lead_v",
|
||||||
|
"leading_mark_variantt_308": "mk_lead_v",
|
||||||
|
"light_beacon": "lt_bcn",
|
||||||
|
"buoy_light": "bu_lit",
|
||||||
|
"buoy_generic": "bu_gen",
|
||||||
|
"buoy_pillar": "bu_pil",
|
||||||
|
"buoy_can": "bu_can",
|
||||||
|
"buoy_lattice": "bu_lat",
|
||||||
|
"nav_mark_vais": "mk_vais",
|
||||||
|
"pilot_station": "fac_pilot",
|
||||||
|
"tidespot-daytime": "tide_spot",
|
||||||
|
"light-daytime-1": "fl_G",
|
||||||
|
"light-daytime-2": "fl_R",
|
||||||
|
"light-daytime-3": "fl_YW",
|
||||||
|
"arc-daytime-04027289": "arc_open_YW",
|
||||||
|
"arc-daytime-m1": "arc_G",
|
||||||
|
"arc-daytime-m2": "arc_R",
|
||||||
|
"arc-daytime-m3": "arc_YW",
|
||||||
|
"rock_exposed_drying_awash_group": "hz_rock_awash",
|
||||||
|
"sunken_rock": "hz_rock_sub",
|
||||||
|
"cleared_danger_object": "hz_danger_clear",
|
||||||
|
"isolated_danger": "hz_danger_iso",
|
||||||
|
"wreck_hull_exposed": "hz_wreck_hull",
|
||||||
|
"wreck_fully_submerged_dangerous": "hz_wreck_sub",
|
||||||
|
"wreck_surveyed": "hz_wreck_survey",
|
||||||
|
"foul_ground": "hz_foul",
|
||||||
|
"sand_wave": "hz_sandwave",
|
||||||
|
"tide_rips_overfalls": "hz_overfall",
|
||||||
|
"eddy_whirlpool": "hz_whirl",
|
||||||
|
"seaweed": "hz_seaweed",
|
||||||
|
"obstruction": "hz_obst",
|
||||||
|
"fish_reef": "hz_reef",
|
||||||
|
"fish_reef_dangerous": "hz_reef_danger",
|
||||||
|
"tower_yagura_observation_platform": "hz_tower",
|
||||||
|
"bollard_pile_stake": "hz_pile",
|
||||||
|
"dolphin_structure": "hz_dolphin",
|
||||||
|
"subsea_installation_outfall_intake": "hz_outfall",
|
||||||
|
"anchorage_quarantine": "an_quar",
|
||||||
|
"anchorage_designated": "an_desig",
|
||||||
|
"restriction_area_group": "an_restrict",
|
||||||
|
"anchoring_prohibited": "an_no_anchor",
|
||||||
|
"port_general_small_harbor_group": "fac_port",
|
||||||
|
"fishing_port": "fac_fishport",
|
||||||
|
"marina": "fac_marina",
|
||||||
|
"fisherina": "fac_fisherina",
|
||||||
|
"sea_station_umi_no_eki": "fac_seastation"
|
||||||
|
},
|
||||||
|
"hazard_class_map": {
|
||||||
|
"401": "hz_rock_awash",
|
||||||
|
"402": "hz_rock_awash",
|
||||||
|
"403": "hz_rock_awash",
|
||||||
|
"404": "hz_rock_sub",
|
||||||
|
"405": "hz_danger_clear",
|
||||||
|
"409": "hz_danger_iso",
|
||||||
|
"410": "hz_wreck_hull",
|
||||||
|
"412": "hz_wreck_sub",
|
||||||
|
"413": "hz_wreck_survey",
|
||||||
|
"415": "hz_wreck_survey",
|
||||||
|
"420": "hz_foul",
|
||||||
|
"421": "hz_sandwave",
|
||||||
|
"422": "hz_overfall",
|
||||||
|
"424": "hz_whirl",
|
||||||
|
"425": "hz_seaweed",
|
||||||
|
"427": "hz_obst",
|
||||||
|
"428": "hz_reef",
|
||||||
|
"429": "hz_reef_danger",
|
||||||
|
"431": "hz_tower",
|
||||||
|
"432": "hz_pile",
|
||||||
|
"433": "hz_dolphin",
|
||||||
|
"434": "hz_outfall"
|
||||||
|
},
|
||||||
|
"landmark_class_map": {
|
||||||
|
"640": "lm_chim",
|
||||||
|
"650": "lm_twr",
|
||||||
|
"660": "lm_mar",
|
||||||
|
"661": "lm_fish",
|
||||||
|
"662": "lm_cus",
|
||||||
|
"680": "lm_prom",
|
||||||
|
"681": "lm_mtn",
|
||||||
|
"682": "lm_ctrl",
|
||||||
|
"698": "lm_mon"
|
||||||
|
},
|
||||||
|
"anchorage_class_map": {
|
||||||
|
"719": "an_quar",
|
||||||
|
"720": "an_desig",
|
||||||
|
"721": "an_restrict",
|
||||||
|
"722": "an_restrict",
|
||||||
|
"723": "an_restrict",
|
||||||
|
"724": "an_no_anchor"
|
||||||
|
},
|
||||||
|
"facility_class_map": {
|
||||||
|
"505": "fac_port",
|
||||||
|
"510": "fac_port",
|
||||||
|
"520": "fac_fishport",
|
||||||
|
"530": "fac_marina",
|
||||||
|
"540": "fac_fisherina",
|
||||||
|
"550": "fac_seastation"
|
||||||
|
},
|
||||||
|
"display_code_map": {
|
||||||
|
"30300000": "lt_min",
|
||||||
|
"30300002": "lt_min",
|
||||||
|
"30300004": "lt_min",
|
||||||
|
"30500001": "lt_lead_a",
|
||||||
|
"30500002": "lt_lead_b",
|
||||||
|
"30500003": "lt_lead_c",
|
||||||
|
"30500004": "lt_lead_c",
|
||||||
|
"30500010": "lt_lead_c",
|
||||||
|
"30600000": "lt_min",
|
||||||
|
"30600001": "lt_min",
|
||||||
|
"30600002": "lt_min",
|
||||||
|
"30600003": "lt_min",
|
||||||
|
"30600004": "lt_min",
|
||||||
|
"30600006": "lt_min",
|
||||||
|
"30700000": "mk_lead_c",
|
||||||
|
"30700001": "lt_up_G",
|
||||||
|
"30700002": "lt_up_R",
|
||||||
|
"30700003": "mk_lead_c",
|
||||||
|
"30700004": "mk_lead_c",
|
||||||
|
"30700007": "mk_lead_c",
|
||||||
|
"30800000": "mk_lead_v",
|
||||||
|
"30900000": "lt_lead_c",
|
||||||
|
"30900002": "lt_lead_b",
|
||||||
|
"30900004": "lt_lead_c",
|
||||||
|
"30900009": "lt_lead_c",
|
||||||
|
"30900011": "lt_lead_c"
|
||||||
|
},
|
||||||
|
"arc_rules": {
|
||||||
|
"sector": "arc_open_YW",
|
||||||
|
"green": "arc_G",
|
||||||
|
"red": "arc_R",
|
||||||
|
"other": "arc_YW"
|
||||||
|
},
|
||||||
|
"fallbacks": {
|
||||||
|
"lm_cus": {
|
||||||
|
"source_sprite_key": "symbol-daytime-660",
|
||||||
|
"status": "temporary_visual_fallback",
|
||||||
|
"reason": "当前 sprite 没有 symbol-daytime-662 原图"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user