From d50b127eae1f8f946b37608bbfbab5b69f1eec19 Mon Sep 17 00:00:00 2001 From: OpenAI Codex Date: Sat, 18 Apr 2026 09:43:42 +0800 Subject: [PATCH] audit full semantic extent and AOI visuals --- STEP_RECORD.md | 2856 ++++++++++++++++- navsea_full_aoi_visual_audit.py | 225 ++ navsea_geometry_native_audit.py | 368 +++ .../full_aoi_visual_audit.json | 685 ++++ .../full_aoi_visual_audit.md | 209 ++ ...geometry_native_extent_fix_2026-04-18.json | 45 + ...l_geometry_native_extent_fix_2026-04-18.md | 50 + src/pbf/navsea-compare-full-audit.html | 639 ++++ ...vSea_Full_AOI_Visual_Audit_2026-04-18.json | 37 + 9 files changed, 5113 insertions(+), 1 deletion(-) create mode 100644 navsea_full_aoi_visual_audit.py create mode 100644 navsea_geometry_native_audit.py create mode 100644 report/full_aoi_visual_audit_2026-04-18_r1/full_aoi_visual_audit.json create mode 100644 report/full_aoi_visual_audit_2026-04-18_r1/full_aoi_visual_audit.md create mode 100644 report/full_geometry_native_extent_fix_2026-04-18.json create mode 100644 report/full_geometry_native_extent_fix_2026-04-18.md create mode 100644 src/pbf/navsea-compare-full-audit.html create mode 100644 tasks/pbf/NavSea_Full_AOI_Visual_Audit_2026-04-18.json diff --git a/STEP_RECORD.md b/STEP_RECORD.md index 287bfd2..bb31953 100644 --- a/STEP_RECORD.md +++ b/STEP_RECORD.md @@ -1,6 +1,6 @@ # 项目步骤记录 -最后更新:`2026-04-08 19:32` +最后更新:`2026-04-18 10:08` 仓库:`/root/sourceserver/pbf` 远端:`ssh://git@nas:2222/tei/pbf.git` @@ -22,6 +22,160 @@ - `Style: karatsu-final-style-r15-20260402-1203` - `PBF: karatsu-final-pbf-20nm-20260402-1156-fullrefresh1` +## 2026-04-18 全国 full / semantic 逻辑审计与 AOI 图像审计启动 + +### 1. 本轮新增入口 + +- 已新增全国几何 / native 风险审计脚本: + - [`navsea_geometry_native_audit.py`](/root/sourceserver/pbf/navsea_geometry_native_audit.py) +- 已新增全国 AOI 截图 + diff 审计脚本: + - [`navsea_full_aoi_visual_audit.py`](/root/sourceserver/pbf/navsea_full_aoi_visual_audit.py) +- 已新增 AOI 配置: + - [`tasks/pbf/NavSea_Full_AOI_Visual_Audit_2026-04-18.json`](/root/sourceserver/pbf/tasks/pbf/NavSea_Full_AOI_Visual_Audit_2026-04-18.json) + +### 2. 全国人工审计页调整 + +- 已把全国人工审计页改为支持: + - `?variant=full` + - `?variant=semantic` +- 已同步部署: + - [`src/pbf/navsea-compare-full-audit.html`](/root/sourceserver/pbf/src/pbf/navsea-compare-full-audit.html) + - `/mnt/sda1/www/newpec/navsea-compare-full-audit.html` +- 这样同一张页面就可以直接做: + - 原始 `newpec vs full` + - 原始 `newpec vs semantic` + 的固定 AOI 截图审计 + +### 3. 全国 z12 extent 逻辑审计结果 + +- 当前先聚焦全国最敏感的: + - `z12` +- 抽查和目录统计确认: + - `/home/wwwroot/pbf-delivery-full-20260415` + - `/home/wwwroot/pbf-delivery-full-semantic-20260416` + 中都存在一批 `z12` 瓦片 extent 错退成 `4096` +- 修前统计: + - `full z12`: + - 总瓦片 `48556` + - `1048576`:`47366` + - `4096`:`1190` + - `semantic z12`: + - 总瓦片 `48556` + - `1048576`:`47296` + - `4096`:`1260` + +### 4. 本轮逻辑修复 + +- 已先做硬链接备份,便于快速退回: + - `/home/wwwroot/pbf-delivery-full-20260415-backup-20260418-preextentfix` + - `/home/wwwroot/pbf-delivery-full-semantic-20260416-backup-20260418-preextentfix` +- 已按原始 `newpec` 同 tile 的 source extent 回写当前错片: + - `full repaired = 1183` + - `semantic repaired = 1215` +- 修后复核: + - `full z12`:`48556 / 48556` 全部为 `1048576` + - `semantic z12`:`48556 / 48556` 全部为 `1048576` + +### 5. 当前视觉 AOI 审计结果 + +- 已跑全国固定 AOI 截图 + 图像 diff 报告: + - [`report/full_aoi_visual_audit_2026-04-18_r1/full_aoi_visual_audit.md`](/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/full_aoi_visual_audit.md) + - [`report/full_aoi_visual_audit_2026-04-18_r1/full_aoi_visual_audit.json`](/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/full_aoi_visual_audit.json) +- 当前固定 AOI: + - 博多港中心 `10nm` + - 东京湾 `10nm` + - 大阪 `10nm` + - 冲绳 `10nm` + - 唐津 `5nm` +- 当前固定 zoom: + - `10` + - `12` + +### 6. 当前视觉结论 + +- 当前差异最大的 case 不是 `semantic` 独有问题 +- 而是: + - `full` + - `semantic` + 在同一 AOI 上同时大幅偏离原始 `newpec` +- 当前 top diff 主要集中在: + - `冲绳 10nm z12` + - `唐津 5nm z12` +- 代表 changed ratio: + - `okinawa full z12 = 0.861954` + - `karatsu full z12 = 0.859021` + - `okinawa semantic z12 = 0.850170` + - `karatsu semantic z12 = 0.847223` + +### 7. 当前判断 + +- 这轮已经确认并修掉的是: + - 全国 `z12 extent` 错片问题 +- 这轮尚未收口的是: + - 全国 `full / semantic` 与原始 `newpec` 的视觉等价性 +- 且当前视觉差异更像: + - `full / semantic` 共用的主线 style / PBF 问题 + - 不只是语义版单独引入的回退 + +### 8. 下一步 + +1. 继续按当前 AOI diff 排序,从: + - `唐津 5nm z12` + - `冲绳 10nm z12` + 开始逐张定位具体 layer / 对象组差异 +2. 优先把: + - `full` 和 `semantic` 同时异常的主线问题 + 从语义版专项问题中剥离出来 +3. 每修一类问题后,直接复跑同一组 AOI 截图,直到 diff 明显收敛 + +## 2026-04-17 Karatsu 20nm final Native ParseTile 异常定位 + +### 1. 用户现象 + +- native 端出现大量: + - `MapLibre error [ParseTile]: Could not get geometries: paths outside valid range of coordinate_type` +- 同时画面出现局部几何缺失 / 轮廓异常 + +### 2. 本轮确认结果 + +- 当前问题不能只归因于 style +- `pbf-delivery-karatsu-20nm-final` 本身存在对 native 不友好的高精度几何编码: + - `z12` 瓦片 layer `extent` 普遍为 `1048576` + - 且几何仍带有约 `±20480` 的 buffer 坐标 +- 这套编码在浏览器 compare 页里仍可能勉强通过 +- 但在 MapLibre Native 下会更容易触发: + - `paths outside valid range of coordinate_type` + +### 3. 本轮顺手发现的附带问题 + +- [`build_semantic_delivery_assets.py`](/root/sourceserver/pbf/build_semantic_delivery_assets.py) + 之前对命中替换的瓦片做了: + - 解码 + - 改属性 + - 再编码 +- 若重编码时不显式带回原 layer `extent` + - 会把高 extent 瓦片直接写坏 + +### 4. 本轮代码修正 + +- 已确认 [`build_semantic_delivery_assets.py`](/root/sourceserver/pbf/build_semantic_delivery_assets.py) + 当前重写语义版瓦片时会: + - 保留 feature `id` + - 保留各 layer 原始 `extent` +- 已新增: + - [`navsea_normalize_tile_extents.py`](/root/sourceserver/pbf/navsea_normalize_tile_extents.py) +- 用途: + - 把现有高 extent 瓦片按比例归一到标准 `4096` 网格 + - 作为 native 兼容修复入口 + +### 5. 当前判断 + +- 这次“大量 ParseTile 报错”更接近: + - delivery/final PBF 几何编码口径与 native 解析器兼容性不一致 +- 下一步优先: + - 先把 `pbf-delivery-karatsu-20nm-final` 归一化到 `4096` + - 再回到 native 端复核是否还会持续抛同类 ParseTile 错误 + 当前仍使用同一张 HTML 做两个 profile: 1. 唐津 20 海里 @@ -38,6 +192,236 @@ - `style` 过滤条件写错或过宽 - 线上仍在使用较早生成的 `20nm final` 瓦片,部分关键对象没有 `class_code / display_code` +## 2026-04-16 灯弧缺失修复 + +### 1. 用户反馈 + +- 全国人工审计页右侧语义版中,灯标的光弧没有显示 +- 左侧原始 `newpec` 可见,右侧 delivery / semantic 不可见 + +### 2. 本轮排查结果 + +- 不是 `sprite-semantic` 缺图块: + - `arc-daytime-04027289` + - `arc-daytime-m1` + - `arc-daytime-m2` + - `arc-daytime-m3` + 以及: + - `light-daytime-1/2/3` + 在 `/mnt/sda1/www/newpec/sprite-semantic/sprite*.json` 中都还存在 +- 当前真正根因是 delivery style 中: + - `nav-light-arc` + 这一层被写成了: + - `"visibility": "none"` +- 且页面脚本没有再把它切回可见 +- 因此只要命中该层,最终仍会被整层隐藏 + +### 3. 本轮修复 + +- 已把以下样式中的: + - `nav-light-arc` + 从隐藏改为可见 +- 已修改: + - `src/pbf/style.navsea-delivery-full.json` + - `src/pbf/style.navsea-delivery-full-semantic.json` + - `src/pbf/style.navsea-delivery-karatsu-20nm-final.json` + - `src/pbf/style.navsea-delivery-karatsu-10nm.json` + - `src/pbf/style.navsea-delivery-kyushu.json` + +### 4. 页面版本提示 + +- 已同步更新全国人工审计页显示的语义版 style 版本号为: + - `full-semantic-style-r2-20260416-2148` + +### 5. 当前结论 + +- 这次“光的弧没有了”不是: + - `PBF` 缺字段 + - 或 `sprite` 缺资源 +- 而是 delivery style 把光弧层整层隐藏了 +- 修完后,右侧 delivery / semantic 应恢复与左侧原始版同类灯弧显示 + +## 2026-04-16 投锚注意障害物图标缺失修复 + +### 1. 用户反馈 + +- 全国人工审计页中,`p投錨注意障害物` + 的一部分右侧语义版图标缺失 +- 用户截图示例对象: + - 左侧原始版 `fid = 15002075` + - `分類番号 = 420` + +### 2. 本轮排查结果 + +- 当前问题不是: + - `sprite-semantic` 缺图 +- 已核实: + - `foul_ground` + - `symbol-daytime-420` + 在语义版 sprite 中都存在 + - 且对应图块像素完全一致 +- 同时已核实该区域 delivery / semantic `PBF` 中对象数量并未少: + - 原始 `p投錨注意障害物` 当前 tile 为 `12` 个 + - delivery `anchor_caution_hazard_point` 当前 tile 也是 `12` 个 +- 但当前 delivery 数据里这批对象的 `chart_icon_image` 仍普遍回落成: + - `symbol-daytime-428` +- 因此在当前“语义版 style + 旧编号 icon 回落数据”混用阶段, + - `anchor-hazard-points-428` 这层继续强行使用新语义 key + - 风险高于收益 + +### 3. 本轮修复 + +- 已把语义版 style 中: + - `anchor-hazard-points-428` + 这一层 +- 从语义 key 映射临时回退为原始稳定的: + - `symbol-daytime-*` + 映射 +- 这样可保证: + - 右侧语义版在这条危险物图标链上先恢复与原始版一致 + - 不继续依赖当前尚未完全收口的语义 key 图标链 + +### 4. 页面版本提示 + +- 已同步更新全国人工审计页显示的语义版 style 版本号为: + - `full-semantic-style-r3-20260416-2210` + +### 5. 当前结论 + +- 这次“图标丢失”更接近: + - 语义版危险物图标映射链在当前过渡阶段不够稳 +- 当前先按“恢复原始表现优先”处理 +- 后续若要继续推进这条危险物图标的语义 key 迁移, + - 应先把 builder / PBF 输出里的 `chart_icon_image` 也一并收口 + +## 2026-04-16 危险物图标 builder 正式修复与局部 PBF 回写 + +### 1. 本轮继续处理目标 + +- 不再只停留在 style 兜底 +- 继续把: + - `p投錨注意障害物` + - `p航行危険障害物` + 的图标问题收回到 builder / PBF 输出层 + +### 2. 当前确认的根因 + +- `navsea_tile_builder.py` 里危险物 `chart_icon_image` 的派生逻辑此前只看: + - `canonical_object_type` + - `chart_symbol_code` + - `hazard_class` +- 没有把: + - `class_code / 分類番号` + 纳入优先判定 +- 结果就是: + - `420` + - `434` + 这类对象会被粗暴回落成: + - `symbol-daytime-428` + +### 3. builder 侧正式修复 + +- 已在: + - `navsea_tile_builder.py` + 中新增危险物: + - `class_code -> icon` + 正式映射表 +- 当前 `infer_chart_icon_image()` 已改为: + - 对 `p投錨注意障害物 / p航行危険障害物` + 先按 `class_code` 精确出图标 + - 再回退旧的粗语义判断 + +### 4. 当前样本验证 + +- 直接验证 builder 推断结果已变为: + - `420 -> foul_ground` + - `428 -> fish_reef` + - `434 -> subsea_installation_outfall_intake` + +### 5. 当前 PBF 局部回写 + +- 由于全国全量危险物瓦片回写耗时过长,本轮没有继续强行等完全量收口 +- 当前先对用户截图所在区域的局部 `z12` 瓦片做了就地回写 +- 本轮实际改动到的 delivery 瓦片: + - `12/3549/1624.pbf` + - `12/3551/1622.pbf` + - `12/3551/1623.pbf` +- 与其硬链接共享的语义版目录中的对应瓦片也同步生效 + +### 6. 当前关键抽样结果 + +- 已复核: + - `/home/wwwroot/pbf-delivery-full-20260415/12/3550/1623.pbf` + - `/home/wwwroot/pbf-delivery-full-semantic-20260416/12/3550/1623.pbf` +- 当前 `anchor_caution_hazard_point` 中的图标值已变为: + - `420 -> foul_ground` + - `428 -> fish_reef` + - `434 -> subsea_installation_outfall_intake` + +### 7. 页面版本提示 + +- 已把全国人工审计页显示的语义版 `PBF` 版本号更新为: + - `full-semantic-pbf-r2-20260416-2248-hazardfix` + +### 8. 当前状态 + +- 当前: + - style 兜底已补 + - builder 正式修复已落地 + - 用户当前审计区域的局部瓦片已完成回写 +- 尚未完成的部分: + - 全国全量危险物相关瓦片的完整重放 / 回写 + +## 2026-04-16 全国语义版 PBF 缺瓦片补齐 + +### 1. 用户指出的问题 + +- 用户反馈: + - `src/pbf/style.navsea-delivery-full-semantic.json` 指向的全国语义版 `PBF` 不完整 + +### 2. 本轮排查结果 + +- 样式文件本身的 `tiles` 路径没有缺项: + - `src/pbf/style.navsea-delivery-full-semantic.json` + - 当前仍指向: + - `http://192.168.200.184/pbf-delivery-full-semantic-20260416/{z}/{x}/{y}.pbf` +- 实际缺口出在语义版全国 `PBF` 输出目录: + - 源目录 `/home/wwwroot/pbf-delivery-full-20260415` 共 `65148` 张瓦片 + - 语义目录 `/home/wwwroot/pbf-delivery-full-semantic-20260416` 共 `65145` 张瓦片 +- 当前确认缺失的 3 张瓦片: + - `12/3659/1567.pbf` + - `12/3661/1548.pbf` + - `8/223/101.pbf` + +### 3. 根因判断 + +- 当前 `build_semantic_delivery_assets.py` 的生成逻辑是: + - 先 `cp -al` 整树复制 + - 再并行重写命中旧 sprite key 的瓦片 +- 这次语义版目录里少 3 张,更像是生成过程中个别目标瓦片未最终落盘 +- 因而需要在重写完成后补一轮“输出目录完整性回填”,不能只假设整树复制一定 100% 留存 + +### 4. 本轮修复 + +- 已修改: + - `build_semantic_delivery_assets.py` +- 新增收口逻辑: + - 重写完成后,遍历源目录 + - 对输出目录中不存在的 `.pbf` 自动补硬链接 / 复制 + - 并输出: + - `tiles_backfilled` + - `tiles_total_after_backfill` +- 已把当前缺失的 3 张瓦片直接补回: + - `12/3659/1567.pbf` + - `12/3661/1548.pbf` + - `8/223/101.pbf` + +### 5. 当前状态 + +- 当前 `/home/wwwroot/pbf-delivery-full-semantic-20260416` 已与 `/home/wwwroot/pbf-delivery-full-20260415` 对齐到同样的瓦片总数: + - `65148` +- `style.navsea-delivery-full-semantic.json` 对应的全国语义版 `PBF` 现已补齐,不再少这 3 张瓦片 + ## 2026-04-02 本轮关键发现 ### 1. 航标紫色圈“又回来了”的原因 @@ -769,3 +1153,2473 @@ - 提交完成后,仓库历史中应保留一份可回溯的本地快照 - 若后续硬盘继续异常,优先再确认远端可推送与备份介质状态 + +## 2026-04-08 数据库完整备份 + +### 1. 备份原因 + +- 当前 PBF 生成链路不只依赖: + - 旧 PBF + - 代码仓库 +- 还依赖数据库中的规则与映射数据 + +## 2026-04-15 全国 PBF 全量重建启动 + +### 1. 本轮目标 + +- 用户要求: + - 把全日本海域的 PBF 都生成出来 +- 本轮执行口径: + - 沿用当前仓库可用的全国生成入口 `navsea_tile_builder.py --all-tiles` + - 同时生成全国 `delivery` 与 `engineering` + - 不覆盖 `2026-04-08` 旧候选目录,改为新日期目录 + +### 2. 启动前确认 + +- 已按仓库续接要求复读: + - `STEP_RECORD.md` + - `PROJECT_HANDOFF_2026-03-31.md` + - `NavSea_Delivery_Preflight_Audit_Spec.md` + - `NavSea_Audit_Logic_And_Evolution_2026-04-01.md` +- 已确认当前远端仍是: + - `ssh://git@nas:2222/tei/pbf.git` +- 已确认当前 builder 仍需使用: + - `--bundle-id navsea-core` + - `--fid-key thisMyWorld@2026` + +### 3. 本轮输出目录 + +- 全国 delivery: + - `/home/wwwroot/pbf-delivery-full-20260415` +- 全国 engineering: + - `/home/wwwroot/pbf-engineering-full-20260415` + +### 4. 本轮计划命令 + +- delivery: + - `.venv/bin/python navsea_tile_builder.py --all-tiles --output /home/wwwroot/pbf-delivery-full-20260415 --fid-key thisMyWorld@2026 --bundle-id navsea-core --release-minimal` +- engineering: + - `.venv/bin/python navsea_tile_builder.py --all-tiles --output /home/wwwroot/pbf-engineering-full-20260415 --fid-key thisMyWorld@2026 --bundle-id navsea-core --engineering` + +### 5. 下一步 + +1. 启动全国 delivery / engineering 全量构建 +2. 等待两条构建跑完 +3. 回填实际 tile 数、mapping audit 输出与目录状态 + +### 6. 2026-04-15 中途方向变更 + +- 用户随后要求: + - `engineering` 版本暂停 +- 已执行: + - 全国 `engineering` 构建会话已人工中断 +- 当前保留半成品目录: + - `/home/wwwroot/pbf-engineering-full-20260415` +- 中断时已写出文件数: + - `1485` +- 当前继续保留运行中的仅有: + - 全国 `delivery` 全量构建 + +### 7. 2026-04-15 delivery 转后台持续运行 + +- 由于全国 `delivery` 全量构建耗时较长,本轮没有继续占用交互会话等待收尾 +- 已把 `delivery` 改为后台进程持续运行 +- 后台父进程: + - `PID 74539` +- 实际 builder 子进程: + - `PID 74548` +- 日志文件: + - `/root/sourceserver/pbf/logs/full_delivery_20260415.log` +- 当前输出目录: + - `/home/wwwroot/pbf-delivery-full-20260415` +- 切后台并重新启动后,builder 会先清空目标目录再重建 +- 本次后台重启后首轮确认状态: + - 已开始持续写入 + - 首次复核文件数:`91` + +### 8. 当前下一步 + +1. 等后台 `delivery` 全量构建完成 +2. 复核全国 delivery 实际输出文件数 +3. 补看 `mapping_audit.json / .md` +4. 再决定是否需要全国对象保真 / render-hit 审计 + +## 2026-04-15 全国 style 指向修正 + +### 1. 本轮问题确认 + +- 用户反馈全国页面在 `zoom < 10` 时看起来“没有数据” +- 代表示例: + - `/9/441/205.pbf` +- 本轮实际核对结果: + - 新全国 delivery 目录中的该瓦片实际存在: + - `/home/wwwroot/pbf-delivery-full-20260415/9/441/205.pbf` + - 文件大小: + - `78486` + - 直接访问新目录 URL 返回: + - `HTTP 200` + - 旧 style 仍指向: + - `http://192.168.200.184/pbf-delivery-full-20260408/{z}/{x}/{y}.pbf` + - 同一路径在 `20260408` 目录下返回: + - `HTTP 404` + +### 2. 根因判断 + +- 不是全国 `delivery` 在 `zoom 10` 以下没生成 +- 而是全国 style 还连着旧的 `20260408` 候选目录 +- 因此前端请求到旧目录缺失瓦片时,会表现成低层级“没有数据” + +### 3. 本轮已完成修正 + +- 已把仓库内全国 style: + - [`src/pbf/style.navsea-delivery-full.json`](/root/sourceserver/pbf/src/pbf/style.navsea-delivery-full.json) + 的瓦片地址改为: + - `http://192.168.200.184/pbf-delivery-full-20260415/{z}/{x}/{y}.pbf` +- 已同步更新线上部署文件: + - `/mnt/sda1/www/newpec/domain/style.navsea-delivery-full.json` +- 已同步把全国单页查看入口文字从: + - `Full 20260408` + 改为: + - `Full 20260415` + +### 4. 当前说明 + +- 这次修正解决的是: + - 全国 style 与实际生成目录不一致 +- 这不等于: + - 全国严格审计已经完成 +- 全国对象保真 / render-hit / 放行结论仍需后续单独收口 +- 因用户担心硬盘风险,本轮补做数据库完整 dump 备份 + +### 2. 当前确认的数据库信息 + +- 当前项目主库: + - `pbf_analysis` +- 当前连接方式: + - `root` + - `unix_socket = /tmp/mysql.sock` +- 本轮核对到的库体量约: + - `19343.42 MB` + +### 3. 本轮备份方式 + +- 使用: + - `mysqldump --single-transaction --quick --routines --events --triggers --databases pbf_analysis` +- 输出为压缩文件: + - `gzip` +- 备份时间戳: + - `20260408_194631` + +### 4. 本轮备份落点 + +- 第一份: + - `/mnt/sda1/pbf_backup_20260408_194631/pbf_analysis_20260408_194631.sql.gz` +- 第二份: + - `/home/tei/pbf_backup_20260408_194631/pbf_analysis_20260408_194631.sql.gz` + +### 5. 校验结果 + +- 两份文件 `sha256` 一致: + - `4cdb7d5c943b6223220a92f923ac718fccb73c7bc99c1007207cd60541a6f25a` +- `gzip -t` 校验通过: + - `/mnt/sda1` 备份通过 + - `/home/tei` 备份通过 + +### 6. 当前说明 + +- 现阶段已同时保全: + - 仓库代码与文档历史 + - PBF 生成所需主数据库快照 +- 若后续还要进一步降风险,下一步可考虑: + - 再做一份离机备份 + - 额外导出数据库表清单与建表结构摘要 + +## 2026-04-09 物体统一判定与点击查询设计收口 + +### 1. 本轮目标 + +- 按当前 `NavSea` 项目真实目标,整理一份可落地的物体模型设计文档 +- 目标明确收口为三件事: + - 点击物体后能知道“这是什么”以及关键细节 + - 能和 `NewPEC` 原体系稳定对回并审计“不丢对象” + - 能渲染出与 `NewPEC` 等价的图标和文字语义 + +### 2. 本轮设计结论 + +- 不再尝试用单一字段同时承担: + - 身份追踪 + - 本体分类 + - 渲染控制 +- 统一改为三层职责: + - `identity / trace` + - `object semantics` + - `render semantics` +- `canonical_object_type` 可以作为统一语义子类名的重要字段 +- 但当前不应把它当成唯一主分类或唯一审计锚点 +- `class_code / display_code` 仍要保留,并通过映射进入 NavSea 自有分类体系 + +### 3. 本轮新增文档 + +- 新增: + - `NavSea_物体统一判定_点击查询_审计设计.md` + +### 4. 文档重点 + +- 明确了 `native MapLibre` 点击拾取的结果模型 +- 明确了 `NewPEC -> NavSea` 的码值映射思路: + - `native_code_type` + - `native_code_value` + - `object_domain` + - `object_class` + - `object_subclass` +- 明确了两条硬审计线: + - 物体不丢 + - 渲染结果一致 +- 同时补充: + - 字段完整性审计 + - 可查询性审计 + - AOI / 视觉审计 + +### 5. 下一步建议 + +1. 先把文档中的目标字段模型补进工程版 PBF 输出 +2. 再补一版交付版最小字段清单,确认哪些查询字段必须保留 +3. 为 `class_code / display_code -> NavSea object taxonomy` 建正式映射表 +4. 在现有对象保真审计和 render audit 脚本上补: + - 分类映射审计 + - 查询字段完整性审计 + +## 2026-04-09 首版语义定义草案补充 + +### 1. 本轮讨论结论 + +- 当前已经可以基于: + - `Karatsu 20nm final` 实际标准层 + - `Chart Domain v1` + 给出一版 `NavSea` 首版语义定义草案 +- 这版草案不再把问题停留在抽象层,而是直接回答: + - 当前每个标准层在业务上是什么 + - 哪些层已经接近稳定业务对象层 + - 哪些层仍属于容器层 / 支撑层 / 待收敛层 + +### 2. 本轮文档更新 + +- 已在: + - `NavSea_物体统一判定_点击查询_审计设计.md` + 中新增: + - `21. 首版语义定义草案` + +### 3. 当前首版定义重点 + +- 新增 `object_domain` 首版集合: + - `navigation_mark` + - `hazard` + - `depth` + - `clearance` + - `anchorage` + - `route` + - `facility` + - `landsea` + - `seabed` + - `toponym` + - `fishery` + - `support` + - `pending` +- 已把当前主要标准层按上述域逐层定义 + +### 4. 当前已可视为稳定业务对象层 + +- `navigation_marks` +- `navigation_hazard_point` +- `anchor_caution_hazard_point` +- `depth_contour` +- `depth_contour_overview` +- `clearance_limit_point` +- `clearance_limit_line` +- `anchorage_area` +- `anchorage_point` +- `route_outline` +- `pilot_station_point` +- `place_label_sea` +- `place_label_land` +- `seabed_text_point` +- `land_area` + +### 5. 当前仍待收敛层 + +- `baseline_area` +- `baseline_line` +- `baseline_outline` +- `facility_boundary_area` +- `facility_boundary_outline` +- `bathymetry_line` +- `hole_area` +- `depth_zone_739` +- `depth_zone_741` +- `clip_outline_754` + +### 6. 下一步建议 + +1. 先把首版语义定义落成 builder 可输出字段: + - `object_domain` + - `object_class` + - `object_subclass` +2. 再按 `source_layer + native code` 建正式 taxonomy 规则表 +3. 在审计脚本中补: + - 语义定义覆盖率审计 + - `pending/support` 漏入正式交付审计 + +## 2026-04-09 核心规则、20nm 调整判断与 pickup 消费方案 + +### 1. 本轮进一步收口的规则 + +- 对象主键继续固定为: + - `fid` +- `NewPEC fid` 与 `NavSea fid` 视为同一主键的两种编码形式 +- 当前正式口径继续坚持: + - `1 raw object -> 1 primary feature` +- pickup、CPA、安全判断与渲染继续消费同一个统一对象载荷 +- 不再为 query / CPA / render 设计三套不同对象模型 + +### 2. 当前对 20nm final 的判断 + +- 当前 `Karatsu 20nm final` 不建议推倒重写 +- 当前更适合在现有标准层和现有 style 基线上做增量调整 +- 优先补的是: + - `object_domain` + - `object_class` + - `object_subclass` +- 当前不建议拆出独立 query API 取代统一对象载荷 + +### 3. 当前对 style 的判断 + +- 当前 style 主结构不建议大改 +- compare 主视觉基线不切换 +- 若要改动,优先改: + - pickup 聚合逻辑 + - 面板展示结构 + - 左右按 `fid` 对照 + +### 4. pickup 消费方案 + +- native 端点击后应: + 1. 用小范围 `queryRenderedFeatures` + 2. 先按 `feature.id` 聚合 + 3. 再按对象优先级挑代表对象 + 4. 返回统一对象结构: + - `fid` + - 统一语义 + - 查询属性 + - 渲染命中信息 +- 当前 compare 页现有 `features[0]` 逻辑只适合临时 inspect,不适合作为正式 pickup 口径 + +### 5. 当前阻塞说明 + +- 本轮尝试直接抽样解码 `/home/wwwroot/pbf-delivery-karatsu-20nm-final` 瓦片 +- 但当前宿主缺少: + - `python` + - `python3 mapbox_vector_tile` +- 因此本轮关于 `20nm final` 字段现状的确认,主要仍依据: + - builder 输出白名单 + - style 依赖 + - 现有对象保真报告 + +## 2026-04-09 20nm final 实际瓦片字段抽样确认 + +### 1. 本轮确认方式 + +- 已改用仓库内: + - `.venv/bin/python` +- 已直接解码: + - `/home/wwwroot/pbf-delivery-karatsu-20nm-final` + 中的真实 `.pbf` 瓦片 + +### 2. 当前确认结果 + +- 当前 `20nm final` 的对象 identity 确实主要走: + - `feature.id` +- 示例: + - `baseline_area` 抽样对象: + - `id = 924902528` + - `properties = canonical_object_type, chart_fill_style, class_code` +- 当前 `properties` 明显是瘦载荷,不再保留 engineering 风格的大量 trace 字段 + +### 3. 关键对象抽样结果 + +- `navigation_marks` + - 保留: + - `canonical_object_type` + - `chart_icon_image` + - `chart_label_position_code` + - `chart_label_subtext` + - `chart_label_text` + - `chart_symbol_code` + - `chart_text_color` + - `chart_text_style` + - `display_code` + - `light_color_code` + - `light_sector_mode` + - `name_ja` +- `depth_contour` + - 保留: + - `canonical_object_type` + - `chart_label_text` + - `chart_text_color` + - `chart_text_style` + - `class_code` + - `least_depth_m` +- `anchor_caution_hazard_point` + - 保留: + - `canonical_object_type` + - `chart_icon_image` + - `chart_symbol_code` + - `class_code` +- `navigation_hazard_point` + - 保留: + - `canonical_object_type` + - `chart_icon_image` + - `chart_symbol_code` + - `class_code` +- `clearance_limit_point` + - 保留: + - `canonical_object_type` + - `chart_label_text` + - `chart_text_style` + - `class_code` + - `clearance_height_m` + - `name_ja` + +### 4. 当前结论修正 + +- 当前 `Karatsu 20nm final` 不是“仅保留 style 最低限度字段”的纯渲染壳 +- 它实际已经保留了一批: + - pickup 可直接消费的关键字段 + - 渲染所需字段 + - 关键原生码值字段 +- 但它也还没有补: + - `object_domain` + - `object_class` + - `object_subclass` + +### 5. 对后续设计的影响 + +- 当前更不建议拆出独立 query 数据源 +- 更合理的方向仍然是: + - 在现有统一对象载荷上继续增量补统一语义字段 +- native pickup 继续围绕: + - `feature.id` + - 当前 `properties` + 做聚合和解释是可行的 + +## 2026-04-09 pickup 规则字典与解释器落地 + +### 1. 本轮目标 + +- 用户明确选择: + - 不增加 PBF 容量 + - 前端基于 pickup 后拿到的 feature 信息自行判读 +- 因此本轮落地: + - 规则字典 + - 薄解释器 + +### 2. 本轮新增文件 + +- 新增: + - `src/pbf/navsea-pickup-rules.v1.json` + - `src/pbf/navsea-pickup-interpreter.js` + +### 3. 当前规则字典内容 + +- 已覆盖当前主要标准层 +- 已声明: + - `object_domain` + - 默认 `object_class` + - 主分类码字段 + - pickup 标题字段优先级 + - 明细字段 + - render 回显字段 + - `support / broad / pending` 状态 + +### 4. 当前解释器职责 + +- 输入: + - `queryRenderedFeatures` 候选数组 +- 处理: + 1. 按 `feature.id` 聚合 + 2. 按 `source_layer_std` 规则解释 + 3. 生成统一 pickup 结果 +- 输出: + - `primary` + - `candidates` + +### 5. 当前更新规则 + +- 当前已明确: + - 不是每次纯视觉微调都要改 pickup 规则字典 +- 但以下情况必须同步更新: + - PBF 标准层变化 + - 关键分类字段变化 + - style 主渲染字段依赖变化 + - 新增正式 pickup 层 + +## 2026-04-09 Native MapLibre React Native pickup 实现说明 + +### 1. 本轮目标 + +- 用户明确要求输出一份给前端团队直接实现的 Markdown 文档 +- 前端目标环境: + - `native MapLibre` + - `React Native` + +### 2. 本轮新增文档 + +- 新增: + - `NavSea_Native_Pickup_ReactNative_MapLibre_实现说明.md` + +### 3. 文档内容重点 + +- 明确当前 `native pickup` 返回三类结果: + - `object` + - `info` + - `context` +- 明确: + - 主对象层 + - 信息层 + - 默认屏蔽层 +- 明确: + - `feature.id` 作为对象主键 + - 空白水域返回深度上下文 +- 明确: + - 规则字典与解释器如何接入 RN 前端 +- 已补: + - `queryRenderedFeaturesInRect` 的官方方法参考 + +### 4. 当前实现建议 + +- RN 前端优先: + 1. 接规则字典 JSON + 2. 迁移/复用解释器 + 3. 先做对象 + 信息 pickup + 4. 再补空白水域上下文 + +### 5. 当前说明 + +- 本轮没有再改 PBF / style +- 本轮输出重点是: + - 让前端团队可按统一口径直接实现 pickup + +## 2026-04-09 pickup 规则字典 r2 与 TS 解释器补齐 + +### 1. 本轮目标 + +- 用户明确要求把前端效率再提一步: + 1. 补更适合 `React Native` 的 TS 解释器版本 + 2. 把 pickup 规则字典收成前端更容易直接消费的结构 + +### 2. 本轮已完成 + +- 已把: + - `src/pbf/navsea-pickup-rules.v1.json` + 从首版规则升级为 `r2` 结构 +- 已新增: + - `src/pbf/navsea-pickup-interpreter.ts` +- 已同步更新: + - `src/pbf/navsea-pickup-interpreter.js` + - `NavSea_Native_Pickup_ReactNative_MapLibre_实现说明.md` + - `NavSea_物体统一判定_点击查询_审计设计.md` + +### 3. 规则字典结构变化 + +- 规则字典新增: + - `render_layer_groups.primary` + - `render_layer_groups.info` + - `render_layer_groups.ignore` +- 原先较模糊的: + - `feature_priority` + 已明确改为: + - `pickup_priority` +- 同时为每个标准层补入: + - `interaction_role` + - `semantic_status` + +### 4. 当前解释器变化 + +- JS / TS 两份解释器现在统一支持: + - `getRenderLayerGroups` + - `pickup_priority` + - `interaction_role` +- 解释器仍保持“薄解释器”原则: + 1. 按 `feature.id` 聚合 + 2. 按 `source_layer_std` 匹配规则 + 3. 输出统一 pickup 结果 + +### 5. 对前端实现的直接收益 + +- RN 前端不需要再硬编码: + - 主对象层数组 + - 信息层数组 + - 默认屏蔽层数组 +- 只需读取规则字典中的: + - `render_layer_groups` +- 这样后续若 style / pickup 规则变化,前端通常只需同步规则文件,不必手改代码 + +### 6. 本轮校验情况 + +- 已通过: + - `jq . src/pbf/navsea-pickup-rules.v1.json` + - `node --check src/pbf/navsea-pickup-interpreter.js` +- 当前未能完成: + - `tsc` 编译校验 +- 原因: + - 当前环境没有可直接使用的 TypeScript 编译器,`npx tsc` 不可用 + +### 7. 当前结论 + +- 当前已可把: + - `navsea-pickup-rules.v1.json` + - `navsea-pickup-interpreter.ts` + 直接交给 `React Native + native MapLibre` 前端团队接入 +- 当前不需要为这一步再改: + - PBF + - style + +## 2026-04-10 pickup 解释器缺 layer 信息兜底修复 + +### 1. 本轮问题 + +- 用户提供了一条实际 `React Native` pickup 结果 +- 现象是: + - 对象能被拿到 + - 但 `source_layer_std = ""` + - `object_domain = unknown` + - `object_class = unknown` + - 标题退化成了泛化的: + - `灯标` + +### 2. 根因判断 + +- 当前问题不是“排序把对象拿错了” +- 真正原因是: + - RN 返回的 feature 中缺少 `sourceLayer / layer.source-layer` + - 解释器无法命中 `navigation_marks` 规则 + - 于是只能走无规则 fallback +- 在旧逻辑里,一旦无规则: + - `title` 会退到 `canonical_object_type` + - `details` 会变空 + - `interaction_role` 只能落到默认值 + +### 3. 本轮修复 + +- 已在: + - `src/pbf/navsea-pickup-interpreter.ts` + - `src/pbf/navsea-pickup-interpreter.js` + 中补入两类兜底能力 + +第一类: + +- 当 `source_layer_std` 缺失时,按属性推断标准层 +- 当前已覆盖的典型规则包括: + - `display_code / light_color_code / light_sector_mode / light_beacon` -> `navigation_marks` + - `clearance_height_m` -> `clearance_limit_point / clearance_limit_line` + - `least_depth_m / depth_value_m` -> `depth_contour / depth_contour_overview` + - 危险物常见 `canonical_object_type` -> `navigation_hazard_point` + +第二类: + +- 当没有命中 layer 规则时,不再直接退成泛化标题 +- 统一优先使用: + - `name_ja` + - `chart_label_text` + - `canonical_object_type` +- 同时补通通用: + - `details` + - `render fields` + fallback + +### 4. 当前样本修复结果 + +- 用户提供的灯标样本: + - `fid = 3305109497` + 修复后已能解释为: + - `source_layer_std = navigation_marks` + - `object_domain = navigation_mark` + - `object_class = beacon` + - `object_subclass = light_beacon` + - `title = 博多港中央航路第2号灯標` + - `primary_code_field = display_code` + - `primary_code_value = 31135102` + +### 5. 当前仍保留的说明 + +- 若 RN 侧能把原始 query 返回中的: + - `feature.layer.id` + - `feature.sourceLayer` + 完整保留传入解释器 +- 则仍优先使用原始 layer 信息 +- 当前属性推断仅作为: + - 丢 layer 信息时的兜底恢复机制 + +## 2026-04-10 可见区域 pickup 分组与精确点查方案 + +### 1. 本轮问题 + +- 用户反馈一条实际 pickup 结果: + - 当前画面上肉眼最明显的是紫色斜线渔业/渔具区域 + - 但 pickup 返回成了附近的 `beacon` +- 这说明当前问题不是对象分类本身,而是: + - 可查询 render layer 分组不合理 + - 查询流程过于偏向“小框补捞点对象” + +### 2. 根因判断 + +- 当前规则字典把: + - `fishery-areas` + 这类明显可见的业务面层放进了 `ignore` +- 同时前端文档里只建议: + - 先查 `primary` 点层 + - 再查 `info` 层 +- 结果就是: + - 用户点在渔网斜线面上 + - query 仍可能从小范围框内捞到附近灯标点 + - 于是出现“看起来像渔网,却返回灯标”的误判 + +### 3. 本轮修正 + +- 已在: + - `src/pbf/navsea-pickup-rules.v1.json` + 中新增: + - `render_layer_groups.area` +- 当前纳入的典型可见区域层包括: + - `navigation-hazard-polygons` + - `fishery-areas` + - `anchorage-areas` + - `facility-zones` + - `submerged-structures` + - `bridge-area` +- 同时把这些层从 `ignore` 口径中移出 + +### 4. 当前推荐查询流程更新 + +- 前端不应再只做“小框查主对象点层” +- 当前推荐改为: + +1. 先做精确点查: + - `area + primary + info` +2. 若精确点查未命中,再做小范围补查: + - `primary + info` +3. 最后再回落到: + - `context` + +### 5. 当前文档更新 + +- 已同步更新: + - `NavSea_Native_Pickup_ReactNative_MapLibre_实现说明.md` + - `NavSea_物体统一判定_点击查询_审计设计.md` +- 当前文档里已明确: + - 可见区域层属于正式 pickup 入口 + - `queryRenderedFeaturesAtPoint` 应先于小框补查 + +### 6. 附加调整 + +- 已补: + - `display_name_overrides.beacon = 标柱` +- 避免无名称时标题直接显示生硬英文: + - `Beacon` + +### 7. 当前结论 + +- 对海图 pickup,不能只偏向“小点符号” +- 只要用户肉眼明确看到的是: + - 渔网斜线面 + - 锚地区 + - 危险区面 + - 桥区 + 这类可见业务区域 +- 就应优先让这些区域对象进入 pickup 主候选 + +## 2026-04-10 同分候选按点击距离优先 + +### 1. 本轮问题 + +- 用户继续反馈: + - pickup 返回的对象类型看起来对 + - 但返回的中心经纬度与实际点击附近图标相差很远 +- 当前样例中出现的是: + - 同一小框内命中了多个 `beacon` + - 它们分数完全相同 + - 解释器按原始返回顺序取了第一个 + +### 2. 根因判断 + +- 当前问题不是 icon 自身做了大位移 +- `nav-marks` 图标层核对结果: + - 没有 `icon-offset` +- 真正问题是: + - 多个同分点对象同时命中时 + - 解释器缺少“离点击点最近优先”的 tie-break + +### 3. 本轮修复 + +- 已在: + - `src/pbf/navsea-pickup-interpreter.ts` + - `src/pbf/navsea-pickup-interpreter.js` + 中新增: + - `click_lnglat` 可选输入 +- 解释器现在会: + 1. 读取点击经纬度 + 2. 计算点对象与点击点的球面距离 + 3. 当两个候选 `score` 相同时,优先选距离更近者 + +### 4. 前端接入要求 + +- RN 前端在调用: + - `interpretRenderedFeatures` + 时,应同步传入: + - `click_lnglat` +- 否则对于同分候选,解释器仍只能退回到原始返回顺序 + +### 5. 本轮验证结果 + +- 已用两条同分 `beacon` 样本做本地验证 +- 当点击点位于第二个对象上时: + - 解释器已能正确优先返回更近的 `fid` +- 测试结果显示: + - 最近对象 `distance_m = 0` + - 远处对象约 `764.5m` + - 返回对象已切换为最近者 + +## 2026-04-10 pickup 独立测试页 + +### 1. 本轮目标 + +- 用户明确要求提供一个独立 `pickup test` URL +- 用于直接排查: + - exact point 命中 + - bbox 命中 + - 解释器 primary / candidates + - 点击点与返回对象点之间的距离 + +### 2. 本轮新增文件 + +- 新增: + - `src/pbf/navsea-pickup-test-karatsu-20nm.html` + +### 3. 页面特性 + +- 使用: + - `style.navsea-delivery-karatsu-20nm-final.json` + - `pbf-delivery-karatsu-20nm-final` +- 页面会同时展示: + - `exact point` 原始命中 + - `bbox` 原始命中 + - 解释器最终 `primary` + - `candidates` +- 页面会在地图上画出: + - 点击点 + - 返回对象点 + - 二者之间的连线 + +### 4. 相关部署 + +- 已部署页面: + - `/mnt/sda1/www/newpec/navsea-pickup-test-karatsu-20nm.html` +- 已同步部署依赖: + - `/mnt/sda1/www/newpec/domain/navsea-pickup-interpreter.js` + - `/mnt/sda1/www/newpec/domain/navsea-pickup-rules.v1.json` + +### 5. 当前访问 URL + +- `http://192.168.200.184/newpec/navsea-pickup-test-karatsu-20nm.html` + +### 6. 本轮校验 + +- 已通过: + - `node --check src/pbf/navsea-pickup-interpreter.js` +- 已确认部署文件存在: + - HTML + - 规则字典 JSON + - JS 解释器 + +### 7. 页面增强 + +- 已追加调试能力: + - `BBox` 半径切换 + - 屏幕上的 `BBox` 可视框 + - 未过滤 query 命中面板 +- 已补顶部摘要: + - `Exact` 数量 + - `BBox` 数量 + - `Raw` 数量 + - `Raw render layer` +- 现在能更快区分两类问题: + - 当前 `render_layer_groups` 漏层 + - 点击点/半径本身没命中任何 rendered feature + +## 2026-04-10 危险区面层白名单漏层修复 + +### 1. 本轮定位结果 + +- 用户在 pickup test 页点击某危险区可见区域后,顶部摘要显示: + - `Exact = 0` + - `BBox = 0` + - `Raw > 0` +- Raw 命中层明确包括: + - `hazard-polygons` + - `anchor-danger-outline` + - `bathymetry-support` + - `sea-area-fill` + +### 2. 结论 + +- 当前问题不是点偏 +- 也不是没有 rendered feature +- 真正根因是: + - `hazard-polygons` 没有被纳入 `render_layer_groups.area` +- 该层在 style 中对应: + - `source-layer = anchor_caution_hazard_area` + +### 3. 本轮修复 + +- 已在: + - `src/pbf/navsea-pickup-rules.v1.json` + 的 `render_layer_groups.area` 中补入: + - `hazard-polygons` +- 已同步重新部署: + - `/mnt/sda1/www/newpec/domain/navsea-pickup-rules.v1.json` + +### 4. 当前意义 + +- 这次结果进一步验证: + - pickup test 页的 `Raw` 摘要是有效的 + - 它能很快区分“白名单漏层”和“点击点没打到对象”两类问题 + +## 2026-04-10 区域面与附近点图标的优先级修正 + +### 1. 本轮用户反馈 + +- 在同一位置存在两个对象: + - `fish_reef` 鱼礁点图标 + - `anchor_caution_hazard_area` 投锚注意危险区域面 +- 用户预期是: + - 点击鱼图标附近时,应优先返回鱼礁 + - 不应被禁锚/危险区域面抢走 + +### 2. 本轮判断 + +- 单纯做“exact 命中的区域面优先”不符合海图使用直觉 +- 更合理的口径是: + - 若 `exact` 命中的是区域/次级对象 + - 但小框补查又命中了 nearby `primary` 点对象 + - 则优先返回该点对象 + +### 3. 本轮修复 + +- 已在 `pickup test` 页中补入: + - `exact secondary` 与 `bbox primary` 的优先级切换 +- 当前口径变为: + - `exact primary` 仍优先 + - `exact area/secondary` 不再压过 nearby `primary` 点图标 + +### 4. 同步补充 + +- 已为规则字典补入: + - `navigation_hazard_area` + - `anchor_caution_hazard_area` + 两个 area layer 规则 +- 避免未来点到这些区域面时仍只显示: + - `unknown` + +### 5. 当前意义 + +- pickup 现在更接近海图使用直觉: + - 小而明确的点图标优先于大范围的区域面 + - 但区域面在附近没有更具体点对象时,仍可被正常选中 + +## 2026-04-10 pickup 展示字段命名修正 + +### 1. 本轮问题 + +- 用户指出: + - `chinese_semantic` 这个字段名不对 + - 当前 PBF 原始数据并没有中文语义字段 + +### 2. 本轮结论 + +- 这个判断是对的 +- 当前 pickup 里的该字段不是 PBF 原始字段 +- 它只是规则字典中的本地展示标签 +- 因此不应继续命名为: + - `chinese_semantic` + +### 3. 本轮修复 + +- 已把 pickup 相关资产统一改为: + - `semantic_label` +- 已更新: + - `src/pbf/navsea-pickup-rules.v1.json` + - `src/pbf/navsea-pickup-interpreter.js` + - `src/pbf/navsea-pickup-interpreter.ts` + +### 4. 当前说明 + +- `semantic_label` 现在表示: + - pickup 规则字典里的本地展示标签 +- 它不表示: + - PBF 原始字段 + - NewPEC 官方字段 + - 原始日文字段 + +### 5. 同步部署 + +- 已重新部署: + - `/mnt/sda1/www/newpec/domain/navsea-pickup-interpreter.js` + - `/mnt/sda1/www/newpec/domain/navsea-pickup-rules.v1.json` + +## 2026-04-10 空白水域点击回退到深度上下文 + +### 1. 本轮用户要求 + +- 用户明确指出: + - 对这类点击,应该返回该区域的水深 +- 也就是: + - 不应只返回 `未命中对象` + - 应进入 `context` 口径 + +### 2. 本轮实现 + +- 已在: + - `src/pbf/navsea-pickup-test-karatsu-20nm.html` + 中新增: + - `Depth Context` 面板 +- 当前最小实现逻辑: + 1. 若对象 pickup 未命中 + 2. 则查询附近可见深度相关层: + - `bathymetry-depth-labels` + - `depth-contour-labels` + - `depth-contours-major-labels` + - `depth-contours` + - `depth-contours-major` + 3. 返回距离点击点最近的深度数字/等深线标签 + +### 3. 当前说明 + +- 这不是“真实底模插值” +- 当前只是: + - 基于海图当前可见表达 + - 返回最近的深度上下文 +- 但它已经比单纯的: + - `未命中对象` + 更符合海图使用逻辑 + +### 4. 当前部署 + +- 已重新部署: + - `/mnt/sda1/www/newpec/navsea-pickup-test-karatsu-20nm.html` + +## 2026-04-11 海底地形与钓鱼判读文档整理 + +### 1. 本轮用户需求 + +- 用户希望把当前 `NavSea PBF` 里和海底情况相关的辅助信息整理成一份中文 `md` +- 重点不是抽象讨论,而是回答: + - 当前 PBF 里哪些层和海底形态有关 + - 能否看出“槽、脊、坎、坑、突起” + - 对钓鱼到底有什么帮助 + +### 2. 本轮新增文档 + +- 已新增: + - [`NavSea_海底地形解读_钓鱼参考.md`](/root/sourceserver/pbf/NavSea_海底地形解读_钓鱼参考.md) + +### 3. 本轮收口结论 + +- 当前 `NavSea PBF` 没有一个现成字段直接把海底形态定义成: + - 槽 + - 脊 + - 坎 + - 坑 +- 但已经具备足够的图面表达,可以基于: + - `depth_contour` + - `depth_contour_overview` + - `bathymetry_line` + - `seabed_text_point` + - `submerged_reef_area` + 等层去做判读 + +### 4. 本轮补充说明 + +- 文档中已额外整理当前 PBF 可直接消费的相关字段: + - `least_depth_m` + - `depth_value_m` + - `chart_label_text` + - `canonical_object_type` + - `class_code` +- 并明确说明: + - `seabed_line` 目前应理解为“海底线表达” + - 不能直接等同于“只有海底电缆” + +### 5. 当前意义 + +- 这份文档可以直接作为: + - 前端做空白水域深度上下文和地形提示的说明依据 + - 后续做钓鱼结构提示时的规则输入说明 + +## 2026-04-11 pickup test 页新增海底地形解读函数与面板 + +### 1. 本轮用户要求 + +- 用户希望按当前已经确认的设计思想: + - 做一个“海底地形解读”函数 + - 再做一个对应显示 panel +- 目标是把当前图面可见的海底结构解释直接放进 pickup test 页,便于前端和业务一起看结果 + +### 2. 本轮实现 + +- 已在: + - [`src/pbf/navsea-pickup-test-karatsu-20nm.html`](/root/sourceserver/pbf/src/pbf/navsea-pickup-test-karatsu-20nm.html) + 中新增: + - `buildTerrainInterpretation(event, depthContext)` + - “当前海底地形解读” panel + +### 3. 当前函数口径 + +- 当前实现仍然是规则版解释器 +- 它不做: + - 底模插值 + - 正式地貌分类确权 +- 它只基于当前可见图面去综合判读: + - `depth-contours` + - `depth-contours-major` + - `depth-contour-labels` + - `bathymetry-support` + - `bottom-material-labels` + - `submerged-structures` + - `fishery-areas` + 等图层 + +### 4. 当前输出内容 + +- panel 当前会显示: + - 主判断 + - 结构提示 + - 深度跨度 + - 底质 + - 附近结构 + - 可信度 +- JSON 输出里会保留: + - `primary_judgement` + - `local_depth_range_m` + - `contour_density` + - `seabed_material` + - `nearby_structures` + - `hints` + +### 5. 当前判读原则 + +- 典型输出是: + - `疑似明显坡折/陡坡` + - `疑似缓到中等坡折` + - `疑似槽/沟一侧或较深落差带` + - `疑似脊/隆起一侧或浅高点边缘` + - `局部地形相对平缓` + - `疑似底质变化带` + - `礁体边缘结构位` +- 所有文案都明确保持为: + - `疑似` + - `当前图面判读` + 不冒充“系统已确认地貌对象” + +### 6. 本轮部署 + +- 已重新部署: + - `/mnt/sda1/www/newpec/navsea-pickup-test-karatsu-20nm.html` +- 页面版本已更新为: + - `pickup-test-r2-20260411-1028` + +## 2026-04-11 pickup 结果改为面向普通钓鱼人的简明解释 + +### 1. 本轮用户要求 + +- 用户进一步明确: + - 如果点击的是露出海面或海面上的具体对象 + - 例如灯塔、渔网、标识、暗礁等 + - 就直接返回这个具体东西 + - 如果点击的是海底相关信息 + - 就返回水深 + - 物体名(有的话) + - 海底形状的简单解读 +- 并强调: + - 文案要简单明了 + - 不要堆太多普通钓鱼人不熟悉的专业术语 + +### 2. 本轮实现 + +- 已在: + - [`src/pbf/navsea-pickup-test-karatsu-20nm.html`](/root/sourceserver/pbf/src/pbf/navsea-pickup-test-karatsu-20nm.html) + 中新增: + - `buildFriendlyClickInterpretation(primary, depthContext, terrainResult)` +- 并把原来偏调试口径的“当前海底地形解读” panel 改成: + - “当前点击解读” + +### 3. 当前页面口径 + +- 当前点击结果会先分成两类: + - `海面/露出物` + - `海底信息` +- 判断逻辑大致是: + - 航标、灯塔、可见渔具区、可见设施等 + - 优先按具体物体解释 + - 等深线、底质、海底线、潜礁、海底危险物等 + - 优先按海底信息解释 + +### 4. 当前海底解读文案 + +- 当前海底解读不再直接甩: + - `坡折` + - `槽` + - `脊` + 这类专业词给终端用户自己消化 +- 而是改成更口语化的话术,例如: + - `这里水底起伏比较明显,像一道坎。` + - `这里像水底一条沟的边上。` + - `这里像水底一个小包或小凸起边上。` + - `这里水底看起来比较平。` + - `这附近像礁边,鱼容易沿边活动。` + +### 5. 当前 panel 显示项 + +- 新 panel 当前显示: + - 结果类型 + - 主显示 + - 当前水深 + - 物体名 + - 水底情况 + - 补充提示 +- 同时保留 JSON: + - 上层友好解释结果 + - 底层 `terrain_debug` 调试结构 + +### 6. 本轮部署 + +- 已重新部署: + - `/mnt/sda1/www/newpec/navsea-pickup-test-karatsu-20nm.html` +- 页面版本已更新为: + - `pickup-test-r3-20260411-1056` + +## 2026-04-11 “附近”口径改为真实米制范围 + +### 1. 本轮问题 + +- 用户指出: + - 如果“附近”直接按 `px` 半径算 + - 那么它会和 `zoom` 强相关 + - 放大时实际范围变小 + - 缩小时实际范围变大 +- 这不适合做正式业务口径 + +### 2. 本轮结论 + +- 这个判断是对的 +- `px` 半径只适合调试 query 手感 +- 不适合定义: + - `100 米内算附近` + 这种稳定业务规则 + +### 3. 本轮修复 + +- 已在: + - [`src/pbf/navsea-pickup-test-karatsu-20nm.html`](/root/sourceserver/pbf/src/pbf/navsea-pickup-test-karatsu-20nm.html) + 中新增: + - `screenRadiusForMeters(lngLat, meters, minPixels)` +- 当前实现改为: + 1. 先把点击点附近 `100m` 换算成当前 zoom 下对应的屏幕半径 + 2. 用这个半径做 `queryRenderedFeatures` + 3. 再用真实 `distance_m` 二次过滤 + 4. 只有 `distance_m <= 100` 的对象,才会进入: + - `nearby_structures` + - `附近有什么` + +### 4. 当前意义 + +- 现在“附近”已经不再是: + - 模糊的像素范围 +- 而是: + - 稳定的真实距离口径 +- 即使缩放变化: + - `附近 = 100 米内` + 这个业务语义不变 + +### 5. 本轮部署 + +- 已重新部署: + - `/mnt/sda1/www/newpec/navsea-pickup-test-karatsu-20nm.html` + +## 2026-04-16 style 生成错误清理 + +### 1. 本轮判定口径 + +- 用户明确要求,若 style 中出现以下内容,一律视为生成错误: + - `background-color: #f5f1e6` 或其他浅色底 + - `raster-opacity < 1` + - `raster-saturation < 0` + - 为低 zoom 单独增加 `wash / fog / skin / overview overlay` + +### 2. 本轮已清理内容 + +- 已把命中的 style 统一修正为: + - `background-color = rgba(255,255,255,1)` + - `raster-opacity = 1` + - `raster-saturation = 0` +- 已移除各类 `depth_contour_overview` 低 zoom 概略叠层 +- 已同步处理仓库内和 `/mnt/sda1/www/newpec/domain` 下当前仍在使用或仍可能被引用的生成 style + +### 3. 本轮已修正文件 + +- 仓库内: + - `src/pbf/style.navsea-delivery-full.json` + - `src/pbf/style.navsea-delivery-karatsu-10nm.json` + - `src/pbf/style.navsea-delivery-karatsu-20nm-final.json` + - `src/pbf/style.navsea-delivery-kyushu.json` + - `src/pbf/style.navsea-engineering-karatsu-10nm.json` + - `src/pbf/style.navsea-v2.json` + - `src/pbf/style.karatsu-10nm-v2.json` + - `src/pbf/style.navsea-redesign.json` + - `src/pbf/style.navsea-semantic-only.json` +- 已部署目录: + - `/mnt/sda1/www/newpec/domain/style.navsea-delivery-full.json` + - `/mnt/sda1/www/newpec/domain/style.navsea-delivery-karatsu-10nm.json` + - `/mnt/sda1/www/newpec/domain/style.navsea-delivery-karatsu-20nm-final.json` + - `/mnt/sda1/www/newpec/domain/style.navsea-delivery-kyushu.json` + - `/mnt/sda1/www/newpec/domain/style.compare-delivery-karatsu-10nm.json` + - `/mnt/sda1/www/newpec/domain/style.domain-karatsu-10nm.json` + - `/mnt/sda1/www/newpec/domain/style.domain-land-sea-karatsu-10nm.json` + - `/mnt/sda1/www/newpec/domain/style.domain-legacy-compatible-karatsu-10nm.json` + +### 4. 复核结果 + +- 已对以下目录做规则复扫: + - `src/pbf/style*.json` + - `/mnt/sda1/www/newpec/domain/style*.json` +- 当前复扫结果: + - `TOTAL 0` +- 表示上述目录中已不存在本轮定义的四类 style 生成错误 + +### 5. 下一步 + +1. 若后续还要继续做 style 生成链路治理,应把同样规则前移到生成脚本/模板层 +2. 在你确认后,再继续处理 sprite 语义 key 重命名与裁剪 + +## 2026-04-16 BASIS=T 命名建议整理 + +### 1. 本轮目标 + +- 用户已在 sprite 审计 Excel 中对部分 `new_sprite_key` 人工填写了: + - `basis = T` +- 本轮任务是把这批人工命名再收敛一遍,整理成可审核的正式 key 建议表 + +### 2. 本轮输入 + +- 基础 Excel: + - `tasks/pbf/NavSea_Sprite_Audit_newpec_style_with_pbf_2026-04-16.xlsx` +- 过滤范围: + - `used` sheet + - `basis = T` + +### 3. 本轮输出 + +- CSV: + - `tasks/pbf/NavSea_Sprite_Basis_T_建议修正表_2026-04-16.csv` +- Markdown: + - `tasks/pbf/NavSea_Sprite_Basis_T_建议修正表_2026-04-16.md` + +### 4. 当前结论 + +- 共整理: + - `33` 条 +- 当前最主要的问题集中在: + - 空格 / 连字符未统一 + - `fille / varian / easte / sourth` 等拼写问题 + - `bang / tu_b / t_object` 这类临时 token 语义不够稳定 +- 当前建议表中已保留: + - 原写法 + - 建议正式 key + - 简短原因 + +### 5. 下一步 + +1. 由用户审核这份 `BASIS=T` 建议修正表 +2. 用户确认后,再批量回写: + - sprite key 对照表 + - sprite json / png + - style / pbf 语义 key + +## 2026-04-16 全国人工审计对比页 + +### 1. 本轮目标 + +- 用户要求两件事: + - 明确说明接下来如何审计当前这套 `pbf / style / png` + - 提供一张可直接人工对比 `newpec` 的页面 + +### 2. 本轮新增页面 + +- 仓库源码: + - `src/pbf/navsea-compare-full-audit.html` +- 已部署页面: + - `/mnt/sda1/www/newpec/navsea-compare-full-audit.html` +- 访问地址: + - `http://192.168.200.184/newpec/navsea-compare-full-audit.html` + +### 3. 页面口径 + +- 左侧固定: + - 原始 `style.json` + - 原始 `newpec` 瓦片 +- 右侧固定: + - `style.navsea-delivery-full.json` + - `/pbf-delivery-full-20260415` + - 当前 `newpec/sprite/sprite` +- 页面版本: + - `full-audit-r1-20260416-1548` + +### 4. 本轮新增文档 + +- 审计口径文档: + - `tasks/pbf/NavSea_全国_PBF_Style_Sprite_人工审计口径_2026-04-16.md` + +### 5. 当前说明 + +- 本轮没有改动主 `20nm compare` 基线页 +- 采用单独新增全国人工审计页的方式,避免影响现有视觉基线 +- 当前新页已保留: + - 双屏联动 + - 点击取数 + - HTML / Style / PBF / Sprite 版本提示 + +### 6. 下一步 + +1. 用户在新页面上做人工审计 +2. 按具体差异把问题归类到: + - `PBF` + - `style` + - `sprite` +3. 再进入正式的 sprite key 重命名与未使用 png 清理 + +## 2026-04-16 全国语义版 sprite / style 生成 + +### 1. 本轮目标 + +- 在用户确认 `BASIS=T` 建议表后,开始生成一版可直接人工审计的: + - 语义版 sprite atlas + - 语义版 style + - 语义版全国 PBF 目录 + +### 2. 本轮新增文件 + +- 生成脚本: + - `build_semantic_delivery_assets.py` +- 语义 key 对照表: + - `src/pbf/semantic_sprite_key_map_2026-04-16.json` +- 语义版 style: + - `src/pbf/style.navsea-delivery-full-semantic.json` + - `/mnt/sda1/www/newpec/domain/style.navsea-delivery-full-semantic.json` + +### 3. 本轮新增 sprite 输出 + +- 输出目录: + - `/mnt/sda1/www/newpec/sprite-semantic` +- 已生成: + - `sprite.json` + - `sprite.png` + - `sprite@2x.json` + - `sprite@2x.png` + +### 4. 当前 sprite 口径 + +- 当前语义版 atlas 已只保留“使用中 sprite 图块”的图像打包 +- 为了让语义版 style 在旧值 / 新值混用阶段也能正常显示: + - `sprite-semantic/*.json` 中同时保留: + - 新语义 key + - 与其共用同一图块坐标的旧 key alias +- 因此当前阶段: + - 图像 atlas 已做裁剪 + - key 已可双兼容过渡 + +### 5. 当前语义版全国 PBF 目录 + +- 已建立新目录: + - `/home/wwwroot/pbf-delivery-full-semantic-20260416` +- 当前做法: + - 先基于 `20260415` 全国 delivery 做整树硬链接复制 + - 再只重写命中旧 sprite key 的候选瓦片 +- 候选瓦片量级已确认约: + - `4370` + +### 6. 当前状态说明 + +- 本轮已完成并可直接使用的部分: + - 语义版 sprite + - 语义版 style + - 全国人工审计 compare 页已切到语义版 style / sprite / PBF 路径 +- 本轮尚未在本次交互内完整收口的部分: + - 全国 `PBF` 的属性级语义 key 全量重写尚未全部跑完 +- 因此当前语义版 PBF 目录虽然路径已建立、瓦片已可访问,但其中大部分瓦片暂仍保留原始旧 key 属性值 +- 由于语义版 sprite atlas 当前保留了旧 key alias: + - 页面渲染仍可正常工作 + - 可以先开始人工视觉审计 + +### 7. 当前 compare 页 + +- 页面: + - `src/pbf/navsea-compare-full-audit.html` + - `/mnt/sda1/www/newpec/navsea-compare-full-audit.html` +- 当前版本: + - `full-audit-r2-20260416-1504` +- 右侧当前指向: + - `style.navsea-delivery-full-semantic.json` + - `/pbf-delivery-full-semantic-20260416` + - `/newpec/sprite-semantic/sprite` + +### 8. 下一步 + +1. 继续完成全国语义版 PBF 的属性级重写 +2. 在重写完成后,抽样验证: + - `chart_icon_image` + - `chart_fill_pattern` + 是否已从旧 key 变为新语义 key +3. 再决定是否移除语义 sprite atlas 中的旧 key alias + +## 2026-04-16 tide 点位缺失定位 + +### 1. 现象 + +- 用户在全国 compare 页指出: + - 左侧原始版能看到 `tide` 点位 + - 右侧 delivery 缺失 + +### 2. 本轮定位结果 + +- 该对象并不来自 `newpec` 主 PBF 的原始 layer 映射 +- 原始 `newpec/style.json` 另有一条独立 source: + - `tide` + - `https://tile.mapple-on.jp/tide-mvt/{z}/{x}/{y}.pbf?ver=20251001` +- 原始图层: + - `#d#tide` + - `source = tide` + - `source-layer = tide` + - `icon-image = tidespot-daytime` +- 因此右侧缺失的根因不是: + - builder 漏接 raw layer +- 而是: + - `style.navsea-delivery-full*.json` 没有把 `tide` 外部 source 一并挂入 + +### 3. 本轮修复 + +- 已在以下 style 中补入: + - `tide` vector source + - `tide-spots` symbol layer +- 已修文件: + - `src/pbf/style.navsea-delivery-full.json` + - `src/pbf/style.navsea-delivery-full-semantic.json` +- 已同步部署: + - `/mnt/sda1/www/newpec/domain/style.navsea-delivery-full.json` + - `/mnt/sda1/www/newpec/domain/style.navsea-delivery-full-semantic.json` + +### 4. 当前结论 + +- 这类点位不应继续追到 `navsea_tile_builder.py` 的 raw layer 接入 +- 正确处理方式是: + - 在 delivery style 中保留原始 `tide-mvt` 外部 source + - 让右侧 style 与左侧原始版保持同一条潮流点位数据源 + +## 2026-04-16 sprite key 语义化迁移任务草案 + +### 1. 本轮背景 + +- 用户提出希望把当前: + - `PBF` + - `sprite.json` + - sprite 资源引用 + 统一改成“有语义的 key”,而不是继续使用: + - `symbol-daytime-410` + - `symbol-daytime-301` + 这类编号式命名。 +- 当前先不直接改代码,先出可审核的 task 文档。 + +### 2. 本轮确认的方向 + +- 迁移目标应当是: + - `PBF` 输出语义图标 key + - style 直接消费语义 key + - `sprite.json` 使用语义 key +- 其中: + - `sprite.png` 本身不是命名载体 + - 真正承载名字的是 `sprite.json` + - `sprite.png` 需要做的是按新 key 重新打包索引 + +### 3. 本轮已完成的资料核对 + +- 已复核全国候选 style: + - [`src/pbf/style.navsea-delivery-full.json`](/root/sourceserver/pbf/src/pbf/style.navsea-delivery-full.json) +- 已复核当前全国候选 PBF: + - `/home/wwwroot/pbf-delivery-full-20260415` +- 已复核线上 sprite 索引: + - `/mnt/sda1/www/newpec/sprite/sprite@2x.json` +- 已复核 builder 里当前图标派生逻辑: + - [`navsea_tile_builder.py`](/root/sourceserver/pbf/navsea_tile_builder.py) + +### 4. 本轮新增输出 + +- 已新增 task 草案: + - [`tasks/pbf/NavSea_Sprite_语义_Key_迁移任务_2026-04-16.md`](/root/sourceserver/pbf/tasks/pbf/NavSea_Sprite_语义_Key_迁移任务_2026-04-16.md) + +### 5. 当前草案内容 + +- 文档中已给出: + - 第一版迁移目标 + - 命名原则 + - 当前全国候选已用 key 的对照表 + - `pattern` 类资源的第一版对照 + - 高确认度 / 待确认项 +- 当前特意把两类内容分开: + - 已能直接落成语义 key 的对象 + - 仍需保留变体编号尾巴的对象 + +### 6. 当前下一步 + +- 先等用户审核: + - 对照表命名是否认可 + - 哪些 key 需要改名 + - 哪些变体需要先做图样人工核对 +- 待用户确认后,再决定是否进入: + - style / builder / sprite.json 的正式迁移实现 + +## 2026-04-16 sprite key 使用计数 CSV + +### 1. 本轮需求 + +- 用户要求基于当前线上: + - `/mnt/sda1/www/newpec/sprite/sprite@2x.json` + 输出一个 CSV,列为: + - `old_sprite_key` + - `new_sprite_key` + - `count` +- 其中要求: + - 以 `sprite.json` 的 key 为基表 + - 统计当前全国候选 PBF 中实际出现次数 + - `PBF` 中没有用到的图标不填写 `new_sprite_key` + +### 2. 本轮统计口径 + +- 当前使用的 PBF 目录: + - `/home/wwwroot/pbf-delivery-full-20260415` +- 当前统计方式: + - 不逐条做 feature 级 decode + - 直接扫描 `PBF` 原始字节中的 sprite key ASCII 字符串 + - 只对: + - `sprite@2x.json` 中存在的 key + 做计数 +- 该口径适合回答: + - 哪些 sprite key 当前确实进入了全国候选 PBF + - 大致进入了多少次 + +### 3. 本轮新增输出 + +- 已生成: + - [`tasks/pbf/NavSea_Sprite_Key_Usage_2026-04-16.csv`](/root/sourceserver/pbf/tasks/pbf/NavSea_Sprite_Key_Usage_2026-04-16.csv) + +### 4. 当前结果摘要 + +- `sprite@2x.json` 总 key 数: + - `476` +- 当前全国候选 PBF 中实际命中的 key 数: + - `23` +- 当前计数最高的几个 key: + - `symbol-daytime-428 = 3322` + - `symbol-daytime-301 = 2830` + - `symbol-daytime-303 = 1581` + - `symbol-daytime-405 = 1286` + - `symbol-daytime-310 = 927` + - `fill-daytime-428 = 899` + - `symbol-daytime-320 = 810` + +### 5. 当前说明 + +- 这份 CSV 主要用于帮助用户先看: + - 哪些旧 sprite key 目前真的在用 + - 哪些 key 值得优先进入语义化迁移 +- 当前未在 PBF 中出现的 key: + - `new_sprite_key` 留空 + +## 2026-04-16 sprite 审计口径修正 + +### 1. 本轮发现 + +- 用户指出: + - `arc-daytime-04022307` + 这类灯弧资源虽然在上一份 CSV 中是 `0`,但在 style 里能看到相关灯弧资源引用。 +- 这说明上一份 CSV 的统计口径只适合回答: + - `PBF` 中有没有直接出现这个 sprite key +- 但不适合回答: + - 当前 style 是否真的在使用该资源 + +### 2. 本轮口径修正 + +- 新增一份更适合审计和删图判断的联合 CSV: + - 同时统计 `style` 直接引用次数 + - 和 `PBF` 中出现次数 +- 当前使用的 style 基线: + - [`src/pbf/style.navsea-delivery-full.json`](/root/sourceserver/pbf/src/pbf/style.navsea-delivery-full.json) +- 当前使用的 PBF 基线: + - `/home/wwwroot/pbf-delivery-full-20260415` +- 当前输出字段: + - `old_sprite_key` + - `used_in_style` + - `used_in_pbf` + - `usage_note` + - `new_sprite_key` + +### 3. 本轮新增输出 + +- 已生成: + - [`tasks/pbf/NavSea_Sprite_Audit_2026-04-16.csv`](/root/sourceserver/pbf/tasks/pbf/NavSea_Sprite_Audit_2026-04-16.csv) + +### 4. 当前结果摘要 + +- `sprite.json` 总 key 数: + - `476` +- 当前 style 直接引用到的 key 数: + - `76` +- 当前 PBF 中出现过的 key 数: + - `23` +- 当前 style / PBF 任一侧命中的总 key 数: + - `81` + +### 5. 当前验证到的关键结论 + +- 灯弧资源不是“没用”,而是典型的: + - `style_only` +- 当前全国候选 style 里实际命中的灯弧 key 包括: + - `arc-daytime-04027289` + - `arc-daytime-m1` + - `arc-daytime-m2` + - `arc-daytime-m3` +- 而: + - `arc-daytime-04022307` + 当前只在 `sprite@2x.json` 中存在 + - 目前没有在当前全国候选 style 中命中 + +### 6. 当前用途 + +- 这份联合 CSV 更适合服务用户当前三个目标: + - 审计当前哪些资源真的在用 + - 判断哪些 PNG 图块可以考虑删除 + - 识别哪些仍在使用的 key 需要继续语义化迁移 + +## 2026-04-16 sprite 审计 CSV 重排与图样标记 + +### 1. 本轮需求 + +- 用户要求把联合审计 CSV 重新生成一次: + - 当前完全没有命中的 key 放到最下面 + - 通过看图识别出的语义 key 需要做标记 + +### 2. 本轮处理 + +- 已重写: + - [`tasks/pbf/NavSea_Sprite_Audit_2026-04-16.csv`](/root/sourceserver/pbf/tasks/pbf/NavSea_Sprite_Audit_2026-04-16.csv) +- 当前排序规则: + - 先放 `style` 或 `PBF` 任一侧命中的 key + - 完全未命中的 `unused_in_current_full` 放到文件尾部 + - 已命中部分再按: + - `used_in_style + used_in_pbf` 总量降序 + - 同总量下按 key 名排序 + +### 3. 图样识别标记规则 + +- 对当前主要依赖 sprite 图样外观推断语义的 key: + - 在 `new_sprite_key` 后追加: + - `[img]` +- 当前已这样标记的包括: + - `symbol-daytime-720 -> anchorage_designated [img]` + - `symbol-daytime-721 -> restriction_general [img]` + - `symbol-daytime-724 -> anchoring_prohibited [img]` + +### 4. 当前结果说明 + +- 经过这次重排后: + - CSV 顶部更适合直接做“当前在用资源”审计 + - CSV 底部更适合直接看“候选可删资源” + +## 2026-04-16 sprite 审计 Excel 输出 + +### 1. 本轮需求 + +- 用户要求把各个 sprite 图标直接放进 Excel 文件中,便于人工审核。 + +### 2. 本轮输出 + +- 已生成: + - [`tasks/pbf/NavSea_Sprite_Audit_2026-04-16.xlsx`](/root/sourceserver/pbf/tasks/pbf/NavSea_Sprite_Audit_2026-04-16.xlsx) + +### 3. 当前 Excel 内容 + +- `summary` sheet: + - 统计口径说明 + - style / PBF / sprite 基线 +- `used` sheet: + - 当前在 style 或 PBF 中命中的 key + - 含图标预览 +- `unused` sheet: + - 当前全国候选下完全未命中的 key + - 含图标预览 + +### 4. 当前生成结果 + +- Excel 已嵌入 sprite 预览图: + - `476` 张 +- 当前文件大小约: + - `2.1M` + +### 5. 当前用途 + +- 这份 Excel 适合直接用于: + - 看图核语义 + - 审核哪些 key 仍在使用 + - 判断哪些资源可进入删图候选 + +## 2026-04-16 sprite 审计 Excel 兼容版 + +### 1. 本轮问题 + +- 用户反馈原始: + - [`tasks/pbf/NavSea_Sprite_Audit_2026-04-16.xlsx`](/root/sourceserver/pbf/tasks/pbf/NavSea_Sprite_Audit_2026-04-16.xlsx) + 无法打开。 + +### 2. 本轮确认 + +- 已核实原始 Excel 并非空壳: + - 内含 `476` 张嵌入图片 + - 本机 `LibreOffice` 可正常读取与转换 +- 初步判断: + - 更可能是用户侧表格客户端对“大量嵌入图片 + 单工作簿”兼容性较差 + +### 3. 本轮新增输出 + +- 已新增兼容版: + - [`tasks/pbf/NavSea_Sprite_Audit_2026-04-16_compat.xlsx`](/root/sourceserver/pbf/tasks/pbf/NavSea_Sprite_Audit_2026-04-16_compat.xlsx) + +### 4. 兼容版处理方式 + +- 缩小预览图尺寸 +- 拆成多个 sheet: + - `used_1` + - `used_2` + - `unused_1` + - `unused_2` +- 保留 `summary` 页说明 + +### 5. 当前结果 + +- 原始版大小约: + - `2.1M` +- 兼容版大小约: + - `605K` +- 兼容版也已用本机 `LibreOffice` 验证可读 + +## 2026-04-16 Mapple 手册对位版 sprite 审计 + +### 1. 本轮输入来源 + +- 用户提供官方手册页: + - `https://info.mapple-on.jp/newpecs/manual/1-15_inlink.html` +- 已进一步解析确认: + - 该页实际加载的是 `guide115_01` 到 `guide115_11` 的 JPG 凡例页 + - 关键符号对位页主要是: + - `guide115_01` + - `guide115_02` + - `guide115_03` + - `guide115_04` + - `guide115_07_20260120` + - `guide115_08` + +### 2. 本轮新增输出 + +- 已生成手册对位版 CSV: + - [`tasks/pbf/NavSea_Sprite_Audit_2026-04-16_manual.csv`](/root/sourceserver/pbf/tasks/pbf/NavSea_Sprite_Audit_2026-04-16_manual.csv) +- 已生成手册对位版 Excel: + - [`tasks/pbf/NavSea_Sprite_Audit_2026-04-16_manual.xlsx`](/root/sourceserver/pbf/tasks/pbf/NavSea_Sprite_Audit_2026-04-16_manual.xlsx) + +### 3. 本轮新增字段 + +- 手册对位版相较原审计表,新增: + - `manual_label_ja` + - `basis` + - `source_page` + +含义: + +- `manual_label_ja` + - 来自 Mapple 凡例页的日文名称 +- `basis` + - `manual` + - `manual?` + - `style` +- `source_page` + - 对应凡例页编号 + +### 4. 本轮关键纠偏 + +- 按手册口径确认后,当前若干 key 的语义与现有 builder fallback 并不完全一致。 +- 当前已先把手册语义写入对位版表,不在本轮直接改代码。 +- 代表性条目包括: + - `symbol-daytime-719 -> 検疫錨地` + - `symbol-daytime-720 -> 錨泊(指定)地` + - `symbol-daytime-721 -> 制限区域・航路横断等禁止区域・航泊禁止区域(共通)` + - `symbol-daytime-724 -> 錨泊禁止区域` + - `symbol-daytime-428 -> 魚礁` + - `symbol-daytime-429 -> 魚礁(危険なもの)` + +### 5. 当前用途 + +- 手册对位版更适合: + - 用官方凡例口径审核 sprite 命名 + - 识别当前 style / builder 中的语义偏差 + - 作为下一步 key 语义化迁移的依据 + +## 2026-04-16 改用 newpec/style.json 重做 sprite 审计表 + +### 1. 本轮原因 + +- 用户指出此前按仓库内生成的 style 做图标预览,结果看起来可能有问题。 +- 已进一步确认: + - `/mnt/sda1/www/newpec/style.json` 声明的 sprite 不是本机 `newpec/sprite/...` + - 而是官方远端: + - `https://tile.mapple-on.jp/newpec-symbols-20251001/sprite` + +### 2. 本轮调整 + +- 当前改为直接使用: + - style 基线: + - `/mnt/sda1/www/newpec/style.json` + - sprite 基线: + - `https://tile.mapple-on.jp/newpec-symbols-20251001/sprite@2x.json` + - `https://tile.mapple-on.jp/newpec-symbols-20251001/sprite@2x.png` + +### 3. 本轮新增输出 + +- 已生成 CSV: + - [`tasks/pbf/NavSea_Sprite_Audit_newpec_style_2026-04-16.csv`](/root/sourceserver/pbf/tasks/pbf/NavSea_Sprite_Audit_newpec_style_2026-04-16.csv) +- 已生成 Excel: + - [`tasks/pbf/NavSea_Sprite_Audit_newpec_style_2026-04-16.xlsx`](/root/sourceserver/pbf/tasks/pbf/NavSea_Sprite_Audit_newpec_style_2026-04-16.xlsx) + +### 4. 当前结果 + +- 当前 `newpec/style.json` 直接命中的 sprite key 数: + - `120` +- 当前未命中的 key 数: + - `356` +- 新表中的图标预览已统一改为: + - 与 `newpec/style.json` 声明一致的官方 sprite 图集 + +### 5. 当前用途 + +- 这份新表更适合直接回答: + - `newpec/style.json` 当前到底用了哪些 sprite key + - 对应图标在官方 sprite 图集中长什么样 + +## 2026-04-16 newpec style + PBF 双列版 sprite 审计 + +### 1. 本轮补充原因 + +- 用户指出上一版: + - `NavSea_Sprite_Audit_newpec_style_2026-04-16.*` + 只有 `style` 使用列,没有把 `PBF` 使用列一并列出。 + +### 2. 本轮新增输出 + +- 已补生成 CSV: + - [`tasks/pbf/NavSea_Sprite_Audit_newpec_style_with_pbf_2026-04-16.csv`](/root/sourceserver/pbf/tasks/pbf/NavSea_Sprite_Audit_newpec_style_with_pbf_2026-04-16.csv) +- 已补生成 Excel: + - [`tasks/pbf/NavSea_Sprite_Audit_newpec_style_with_pbf_2026-04-16.xlsx`](/root/sourceserver/pbf/tasks/pbf/NavSea_Sprite_Audit_newpec_style_with_pbf_2026-04-16.xlsx) + +### 3. 当前统计口径 + +- style 基线: + - `/mnt/sda1/www/newpec/style.json` +- sprite 基线: + - `https://tile.mapple-on.jp/newpec-symbols-20251001/sprite` +- PBF 基线: + - `/home/wwwroot/pbf-delivery-full-20260415` + +### 4. 当前结果摘要 + +- `used_in_newpec_style` 命中的 key 数: + - `120` +- `used_in_pbf` 命中的 key 数: + - `23` +- 两侧任一侧命中的 key 数: + - `120` + +### 5. 当前用途 + +- 这份双列版适合直接回答: + - 哪些 key 仅 style 在用 + - 哪些 key 同时进了 style 和 PBF + - 哪些 key 当前完全没有命中 + +## 2026-04-12 15:51 红点对位测试页 + +### 1. 背景 + +- 用户提供了一组 native 点击参数: + - `gps = 130.12021422800144, 33.564027696216417` + - `screen_point = 872.12158203125, 265.0388488769531` + - `camera.center = 130.09748008398487, 33.56207182800527` + - `camera.zoom = 13.35437870025635` +- 当前目标不是继续改 pickup 逻辑,而是先做一个最小对位页: + - 在同一套 `Karatsu 20nm final` 图面上 + - 把这个 GPS 点直接画成红点 + - 方便用户亲自点击这个点,观察 web pickup 命中情况 + +### 2. 本轮新增页面 + +- 新增文件: + - `/root/sourceserver/pbf/src/pbf/navsea-click-target-karatsu-20nm.html` +- 页面特性: + - 使用 `style.navsea-delivery-karatsu-20nm-final.json` + - 使用 `pbf-delivery-karatsu-20nm-final` + - 相机固定到用户提供的 native `center/zoom` + - 目标 GPS 固定绘制为一个红色圆点 + - 页面左上角额外展示: + - 目标经纬度 + - 相机中心 + - 缩放级别 + - native 屏幕点 + +### 3. 部署 + +- 已部署到: + - `/mnt/sda1/www/newpec/navsea-click-target-karatsu-20nm.html` +- 可访问 URL: + - `http://192.168.200.184/newpec/navsea-click-target-karatsu-20nm.html` + +### 4. 用途说明 + +- 该页面是“位置对位工具页”,不是 pickup 主测试页 +- 主要用途: + - 先确认 native 给出的 GPS 点在 web 图面上的真实位置 + - 再让用户直接点这个红点,观察是否能稳定命中目标对象 + - 用于后续继续排查: + - native `queryRenderedFeaturesAtPoint` + - native `queryRenderedFeaturesInRect` + - web `queryRenderedFeatures` + 的差异 + +### 5. 本轮增强 + +- 已继续增强红点对位页: + - 点击地图后,页面右侧直接显示三组查询结果 + - 分别为: + - `Exact Point 命中 fid` + - `BBox 命中 fid` + - `Raw 命中 fid` +- 当前每组结果都会输出: + - 命中数量 + - `fid` 数组 + - 简化后的 feature 摘要 +- 同时也会在浏览器 `console.log` 打印同样内容,便于和 native 日志逐条对照 + +### 6. 当前版本 + +- 红点对位页当前版本: + - `click-target-r2-20260412-1558` + +## 2026-04-12 16:09 红点对位页切换第二组 native 参数 + +### 1. 本轮目的 + +- 用户提供了第二组 native 点击参数,要求继续使用同一个红点对位页做对照 +- 本轮没有改 pickup 判定逻辑,只替换测试输入参数 + +### 2. 本轮更新 + +- 页面: + - `/root/sourceserver/pbf/src/pbf/navsea-click-target-karatsu-20nm.html` +- 已切换为以下参数: + - `gps = 130.11327934763205, 33.55533344042364` + - `camera.center = 130.11779893907284, 33.55552020187967` + - `camera.zoom = 15.158083915710451` + - `screen_point = 447.72021484375, 467.4805908203125` + - `projected_click_point = 298.4801330566406, 311.6537170410156` + +### 3. 页面补充 + +- 左侧信息面板已补充: + - `投影屏幕点` +- 这样可以同时对照: + - native 事件里的 `screen_point` + - native 相机投影出来的 `projected_click_point` + +### 4. 当前版本 + +- 红点对位页当前版本: + - `click-target-r3-20260412-1608` + +## 2026-04-11 建筑物/地标点 pickup 主入口补全 + +### 1. 本轮问题 + +- 用户继续指出: + - 当前点击逻辑还是明显偏海底 + - 对建筑物的注意不够 + +### 2. 本轮根因 + +- 当前规则虽然已经把: + - `land-area` + - `land-structures-area` + 等面/线层拉回正式 pickup +- 但真正用于可见建筑/地标点表达的: + - `landmark-points` + - `landmark-point-fallback` + 之前没有进入 `primary` +- 这会导致: + - 用户眼前看见了建筑/地标点 + - 但 pickup 主入口没有优先命中它 + - 页面仍容易滑回海底解释 + +### 3. 本轮修复 + +- 已更新: + - [`src/pbf/navsea-pickup-rules.v1.json`](/root/sourceserver/pbf/src/pbf/navsea-pickup-rules.v1.json) +- 具体补入: + - `landmark-points` + - `landmark-point-fallback` + 到 `render_layer_groups.primary` +- 并把: + - `coast-structures-area` + 也正式补入 `render_layer_groups.area` + +### 4. 当前意义 + +- 现在可见建筑/地标点不再只是: + - style 上画出来 + - 但 pickup 不关注 +- 而是已经进入正式主点击入口 +- 页面在建筑物附近点击时,应更容易优先返回: + - 建筑物 / 地标 / 防波堤 / 栈桥 + 而不是海底兜底 + +### 5. 本轮部署 + +- 已重新部署: + - `/mnt/sda1/www/newpec/domain/navsea-pickup-rules.v1.json` + - `/mnt/sda1/www/newpec/navsea-pickup-test-karatsu-20nm.html` + +## 2026-04-11 当前 pickup 测试页状态确认 + +### 1. 当前用户反馈 + +- 用户确认: + - `现在看起来很好` + +### 2. 当前已达到的状态 + +- 当前 `pickup test` 页已经基本收口到用户可接受状态 +- 页面当前能较稳定地区分: + - 海面上/露出水面的具体对象 + - 海底信息解释 +- 对用户可见的: + - 航标 + - 灯标 + - 渔具/鱼礁 + - 危险物 + - 陆地 + - 建筑物 + - 地标点 + - 防波堤/栈桥等岸上或岸边结构 + 已经比前几轮更容易返回正确对象,而不是错误滑入海底兜底 + +### 3. 当前海底解释口径 + +- 当前海底解释已具备: + - `当前水深` + - `物体名(有的话)` + - `简单水底情况` + - `判断理由` +- 并已统一为: + - `100 米` 近邻证据口径 +- 当前文案也已收敛到偏普通钓鱼人可理解的表达,不再直接把专业术语甩给终端用户 + +### 4. 当前可作为后续实现基线 + +- 当前页面: + - `http://192.168.200.184/newpec/navsea-pickup-test-karatsu-20nm.html` + 已可作为后续前端实现 pickup 行为的测试基线 +- 当前规则字典与页面逻辑可继续作为: + - RN 前端落地参考 + - 后续解释器抽离的基础版本 + +## 2026-04-11 新增 React + MapLibre 迁移用 Codex 指令文档 + +### 1. 本轮用户需求 + +- 用户希望把当前 `pickup` 的“当前点击解读”逻辑迁移到: + - `React + MapLibre (NavSea)` +- 并要求: + - 提供一份中文 `md` + - 这份文档要能直接作为 `Codex` 执行指令使用 + +### 2. 本轮新增文档 + +- 已新增: + - [`Codex_指令_NavSea_Pickup_当前点击解读_迁移到_React_MapLibre.md`](/root/sourceserver/pbf/Codex_指令_NavSea_Pickup_当前点击解读_迁移到_React_MapLibre.md) + +### 3. 当前文档内容 + +- 这份指令文档已明确写清: + - 目标行为 + - 当前唯一参考来源文件 + - 主键与图层口径 + - `100 米` 附近口径 + - `exact + bbox` 双阶段查询 + - 当前点击解读的两种模式 + - `海面/露出物` + - `海底信息` + - 必须保留的 `判断理由` + - 不要做的事 + - 产出要求 + - 验收标准 + +### 4. 当前意义 + +- 现在不仅已有: + - pickup test 页 + - pickup 规则字典 + - pickup 解释器 +- 也已经补上一份: + - 可直接交给前端或另一个 Codex 执行的中文任务书 + +## 2026-04-11 新增可直接复制给 Codex 的纯 Prompt 版 + +### 1. 本轮用户需求 + +- 用户希望在已有详细 `md` 指令之外,再补一份: + - 可以直接复制到聊天框 + - 更短 + - 更像真正执行口令 + 的版本 + +### 2. 本轮新增文档 + +- 已新增: + - [`Codex_Prompt_版_NavSea_Pickup_当前点击解读_迁移.md`](/root/sourceserver/pbf/Codex_Prompt_版_NavSea_Pickup_当前点击解读_迁移.md) + +### 3. 当前文档作用 + +- 这份文档比详细任务书更短 +- 但仍保留了关键约束: + - 必须阅读的参考文件 + - `海面/露出物` 与 `海底信息` 两种模式 + - `100 米` 附近口径 + - `exact + bbox` 双阶段查询 + - `判断理由` + - 建筑物/地标不能被海底解释吞掉 + - 验收标准 + +## 2026-04-11 pickup test 页补入 MapLibre 调用参数 console.log + +### 1. 本轮用户要求 + +- 用户明确要求: + - 在 web 的 `console.log` 里 + - 把调用 MapLibre 的函数参数都显示出来 +- 并补充说明: + - 这里就是要改 `pickup test` 的 html + +### 2. 本轮实现 + +- 已在: + - [`src/pbf/navsea-pickup-test-karatsu-20nm.html`](/root/sourceserver/pbf/src/pbf/navsea-pickup-test-karatsu-20nm.html) + 中新增: + - `logMapLibreCall(method, payload)` + +### 3. 当前已记录的 MapLibre 调用 + +- 当前页面会在控制台输出这些调用参数: + - `new maplibregl.Map` + - `map.addSource` + - `map.addLayer` + - `source.setData` + - `map.project` + - `map.queryRenderedFeatures` + - `map.addControl` + - `map.jumpTo` + - `map.setStyle` + - `map.easeTo` + +### 4. 当前作用 + +- 现在浏览器控制台里可以直接看到: + - 每次点击到底传给了哪些 `queryRenderedFeatures` 参数 + - `100m` 是怎么换算成屏幕半径的 + - `style` 重载、地图初始化、回到默认视角时具体传了什么 +- 便于前端后续把同样的调用迁移到: + - `React + MapLibre` + +### 5. 本轮部署 + +- 已重新部署: + - `/mnt/sda1/www/newpec/navsea-pickup-test-karatsu-20nm.html` +- 页面版本已更新为: + - `pickup-test-r6-20260411-1216` +- 页面版本已更新为: + - `pickup-test-r4-20260411-1105` + +## 2026-04-11 陆地与建筑物点击误落入海底解释修复 + +### 1. 本轮问题 + +- 用户反馈: + - 陆地点击错了 + - 建筑物点击也错了 +- 实际现象是: + - 用户点击了清晰可见的陆地或陆上构造物 + - 页面却返回了: + - `海底信息` + - 或海底地形解释兜底 + +### 2. 本轮根因 + +- 当前规则字典里: + - `land-area` + - `land-structures-area` + 仍然被放在 `ignore` +- 导致这些可见对象没有进入正式 pickup 白名单 +- 页面对象未命中后,就错误掉入: + - `depth context` + - `terrain interpretation` + 的兜底路径 + +### 3. 本轮修复 + +- 已更新: + - [`src/pbf/navsea-pickup-rules.v1.json`](/root/sourceserver/pbf/src/pbf/navsea-pickup-rules.v1.json) +- 具体调整为: + - 把 + - `land-area` + - `land-structures-area` + - `land-structures-line` + - `coast-structures-line` + 从 `ignore` 调整为正式可点 `area` +- 并补了显示名覆盖: + - `land_area -> 陆地` + - `building -> 建筑物` + - `breakwater -> 防波堤` + - `floating_facility_pier -> 浮动设施/栈桥` + +### 4. 同步补强 + +- 已更新 pickup test 页逻辑: + - 新增 `shouldPreferBBoxPrimary(exactPrimary, bboxPrimary)` +- 当前规则变为: + - 对危险区这类 broad area,仍允许 nearby primary 抢回 + - 但对: + - `land_area` + - `onshore_structure_area` + - `onshore_structure_line` + - `bridge_structure` + 这类可见陆地/构造物,不再被 bbox 里的 nearby primary 轻易抢走 + +### 5. 本轮部署 + +- 已重新部署: + - `/mnt/sda1/www/newpec/domain/navsea-pickup-rules.v1.json` + - `/mnt/sda1/www/newpec/navsea-pickup-test-karatsu-20nm.html` + +## 2026-04-11 pickup 面板新增“判断理由” + +### 1. 本轮用户要求 + +- 用户指出: + - 同样一类图面,有时会显示“像一道坎” + - 有时会显示“变化但不特别强” +- 希望页面直接显示: + - 这次判断到底依据了什么 + +### 2. 本轮实现 + +- 已在: + - [`src/pbf/navsea-pickup-test-karatsu-20nm.html`](/root/sourceserver/pbf/src/pbf/navsea-pickup-test-karatsu-20nm.html) + 的“当前点击解读” panel 中新增: + - `判断理由` +- 并新增: + - `buildDecisionReasonText(terrainResult)` + +### 3. 当前展示内容 + +- 现在海底信息解释会额外显示: + - `100米内深度大约 Xm 到 Ym,跨度 Zm` + - `附近共有 N 条等深线,海底辅助线 M 条` + - `附近结构` + - `附近底质` +- 对海面/露出物点击,也会明确显示: + - `当前点击已直接命中可见对象,所以不再按海底规则兜底解释。` + +### 4. 本轮部署 + +- 已重新部署: + - `/mnt/sda1/www/newpec/navsea-pickup-test-karatsu-20nm.html` +- 页面版本已更新为: + - `pickup-test-r5-20260411-1126` + +## 2026-04-11 海底判断证据口径统一 + +### 1. 本轮问题 + +- 用户通过截图指出一个关键矛盾: + - `当前水深` 显示为 `20m` + - 但 `判断理由` 却写成: + - `100米内深度大约 25m 到 25m,跨度 0m` + - 同时还给出了: + - `这里水底看起来比较平` +- 这说明当前页面里: + - `当前水深` + - `海底形状判断` + 还不是完全使用同一套证据 + +### 2. 本轮根因 + +- `当前水深` 原先使用的是一套较宽松的可见深度 query +- `地形判断` 使用的是另一套 `100m` 近邻样本 +- 再加上“平缓”规则之前会被少量 `bathymetry-support` 误触发 +- 于是就会出现: + - 水深看起来是 20m + - 但理由统计只剩 25m 辅助线样本 + - 最终误说成“比较平” + +### 3. 本轮修复 + +- 已把 `buildDepthContext(event)` 改为同样使用: + - `NEARBY_DISTANCE_M = 100` +- 当前 `当前水深` 和 `附近/地形判断` 已统一到同一个 `100m` 口径 +- 同时收紧了“平缓”判定: + - 只有真正存在足够的等深线/标签证据时,才允许说: + - `这里水底看起来比较平` +- 如果只是少量 `bathymetry-support` 被扫到,当前会改成: + - `当前位置只有少量海底辅助线证据,暂不判断明显坎沟。` + +### 4. 当前新增说明 + +- `terrain_interpretation.contour_density` 里已补入: + - `contour_evidence` +- `判断理由` 里现在会优先显示: + - `当前水深取最近可见深度,约 Xm` + - `100米内样本深度大约 Ym 到 Zm,跨度 Wm` + - `附近共有 N 条等深线,深度标签 K 个,海底辅助线 M 条` + +### 5. 本轮部署 + +- 已重新部署: + - `/mnt/sda1/www/newpec/navsea-pickup-test-karatsu-20nm.html` diff --git a/navsea_full_aoi_visual_audit.py b/navsea_full_aoi_visual_audit.py new file mode 100644 index 0000000..75cfbe6 --- /dev/null +++ b/navsea_full_aoi_visual_audit.py @@ -0,0 +1,225 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +import argparse +import json +import subprocess +from pathlib import Path +from typing import Any +from urllib.parse import urlencode + +from PIL import Image, ImageChops, ImageStat + + +DEFAULT_COMPARE_URL = "http://192.168.200.184/newpec/navsea-compare-full-audit.html" +DEFAULT_AOI_JSON = Path("/root/sourceserver/pbf/tasks/pbf/NavSea_Full_AOI_Visual_Audit_2026-04-18.json") +DEFAULT_OUTPUT_DIR = Path("/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18") + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description="对全国 full / semantic 做 AOI 截图 + 图像 diff 审计。") + parser.add_argument("--compare-url", default=DEFAULT_COMPARE_URL) + parser.add_argument("--aoi-json", type=Path, default=DEFAULT_AOI_JSON) + parser.add_argument("--output-dir", type=Path, default=DEFAULT_OUTPUT_DIR) + parser.add_argument("--width", type=int, default=1280) + parser.add_argument("--height", type=int, default=720) + parser.add_argument("--toolbar-height", type=int, default=120) + parser.add_argument("--bottom-trim", type=int, default=30) + parser.add_argument("--timeout-sec", type=int, default=120) + parser.add_argument("--virtual-time-budget-ms", type=int, default=30000) + return parser.parse_args() + + +def run_browser_screenshot( + compare_url: str, + output_png: Path, + width: int, + height: int, + timeout_sec: int, + virtual_time_budget_ms: int, +) -> None: + cmd = [ + "timeout", + f"{timeout_sec}s", + "google-chrome", + "--headless=new", + "--disable-gpu", + "--enable-unsafe-swiftshader", + "--no-sandbox", + f"--virtual-time-budget={virtual_time_budget_ms}", + f"--window-size={width},{height}", + f"--screenshot={output_png}", + compare_url, + ] + subprocess.run(cmd, check=True, capture_output=True, text=True) + + +def compute_visual_metrics(left_img: Image.Image, right_img: Image.Image) -> dict[str, Any]: + diff = ImageChops.difference(left_img, right_img) + diff_rgb = diff.convert("RGB") + diff_gray = diff.convert("L") + stat = ImageStat.Stat(diff_rgb) + mean_abs = [round(v, 4) for v in stat.mean] + rms = [round(v, 4) for v in stat.rms] + bbox = diff_gray.getbbox() + nonzero_pixels = 0 + if bbox: + mask = diff_gray.point(lambda value: 255 if value else 0) + histogram = mask.histogram() + nonzero_pixels = histogram[255] if len(histogram) > 255 else 0 + total_pixels = left_img.size[0] * left_img.size[1] + changed_ratio = round(nonzero_pixels / total_pixels, 6) if total_pixels else 0.0 + return { + "changed_pixels": nonzero_pixels, + "total_pixels": total_pixels, + "changed_ratio": changed_ratio, + "mean_abs_rgb": mean_abs, + "rms_rgb": rms, + "diff_bbox": list(bbox) if bbox else None, + "diff_image": diff, + } + + +def crop_compare_panes(full_png: Path, left_png: Path, right_png: Path, diff_png: Path, toolbar_height: int, bottom_trim: int) -> dict[str, Any]: + image = Image.open(full_png).convert("RGBA") + usable_top = toolbar_height + usable_bottom = max(usable_top + 1, image.height - bottom_trim) + mid_x = image.width // 2 + left = image.crop((0, usable_top, mid_x, usable_bottom)) + right = image.crop((mid_x, usable_top, image.width, usable_bottom)) + left.save(left_png) + right.save(right_png) + + metrics = compute_visual_metrics(left, right) + diff_image = metrics.pop("diff_image") + diff_image.convert("RGB").point(lambda value: min(255, value * 4)).save(diff_png) + metrics["left_crop"] = [0, usable_top, mid_x, usable_bottom] + metrics["right_crop"] = [mid_x, usable_top, image.width, usable_bottom] + return metrics + + +def build_case_url(compare_url: str, variant: str, center: list[float], zoom: int | float) -> str: + query = urlencode( + { + "variant": variant, + "audit": "1", + "center": f"{center[0]},{center[1]}", + "zoom": zoom, + } + ) + separator = "&" if "?" in compare_url else "?" + return f"{compare_url}{separator}{query}" + + +def write_report(output_dir: Path, summary: dict[str, Any]) -> tuple[Path, Path]: + report_json = output_dir / "full_aoi_visual_audit.json" + report_md = output_dir / "full_aoi_visual_audit.md" + report_json.write_text(json.dumps(summary, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") + + lines = [ + "# 全国 AOI 截图对比审计", + "", + "## 总览", + "", + f"- compare page: `{summary['compare_url']}`", + f"- cases: `{len(summary['cases'])}`", + "", + "## 差异排序", + "", + ] + for case in summary["cases"]: + lines.extend( + [ + f"### {case['label']} · {case['variant']} · z{case['zoom']}", + "", + f"- changed ratio: `{case['changed_ratio']}`", + f"- changed pixels: `{case['changed_pixels']}` / `{case['total_pixels']}`", + f"- mean abs rgb: `{case['mean_abs_rgb']}`", + f"- compare url: `{case['compare_url']}`", + f"- left image: `{case['left_image']}`", + f"- right image: `{case['right_image']}`", + f"- diff image: `{case['diff_image']}`", + "", + ] + ) + report_md.write_text("\n".join(lines) + "\n", encoding="utf-8") + return report_md, report_json + + +def main() -> None: + args = parse_args() + output_dir = args.output_dir + output_dir.mkdir(parents=True, exist_ok=True) + aois = json.loads(args.aoi_json.read_text(encoding="utf-8")) + + cases: list[dict[str, Any]] = [] + for variant in ("full", "semantic"): + for aoi in aois: + for zoom in aoi["zoom_levels"]: + case_id = f"{aoi['id']}_{variant}_z{zoom}" + case_dir = output_dir / case_id + case_dir.mkdir(parents=True, exist_ok=True) + compare_url = build_case_url(args.compare_url, variant, aoi["center"], zoom) + full_png = case_dir / "compare_full.png" + left_png = case_dir / "compare_left.png" + right_png = case_dir / "compare_right.png" + diff_png = case_dir / "compare_diff.png" + + run_browser_screenshot( + compare_url=compare_url, + output_png=full_png, + width=args.width, + height=args.height, + timeout_sec=args.timeout_sec, + virtual_time_budget_ms=args.virtual_time_budget_ms, + ) + metrics = crop_compare_panes( + full_png=full_png, + left_png=left_png, + right_png=right_png, + diff_png=diff_png, + toolbar_height=args.toolbar_height, + bottom_trim=args.bottom_trim, + ) + cases.append( + { + "id": case_id, + "label": aoi["label"], + "variant": variant, + "zoom": zoom, + "center": aoi["center"], + "radius_nm": aoi["radius_nm"], + "compare_url": compare_url, + "changed_pixels": metrics["changed_pixels"], + "total_pixels": metrics["total_pixels"], + "changed_ratio": metrics["changed_ratio"], + "mean_abs_rgb": metrics["mean_abs_rgb"], + "rms_rgb": metrics["rms_rgb"], + "diff_bbox": metrics["diff_bbox"], + "left_image": str(left_png), + "right_image": str(right_png), + "diff_image": str(diff_png), + } + ) + + cases.sort(key=lambda item: item["changed_ratio"], reverse=True) + summary = { + "compare_url": args.compare_url, + "cases": cases, + } + report_md, report_json = write_report(output_dir, summary) + print( + json.dumps( + { + "report_md": str(report_md), + "report_json": str(report_json), + "top_cases": cases[:5], + }, + ensure_ascii=False, + indent=2, + ) + ) + + +if __name__ == "__main__": + main() diff --git a/navsea_geometry_native_audit.py b/navsea_geometry_native_audit.py new file mode 100644 index 0000000..862719d --- /dev/null +++ b/navsea_geometry_native_audit.py @@ -0,0 +1,368 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +import argparse +import json +import os +from collections import Counter, defaultdict +from dataclasses import dataclass +from pathlib import Path +from typing import Any + +from mapbox_vector_tile.Mapbox import vector_tile_pb2 + + +DEFAULT_SOURCE_ROOT = Path( + "/home/wwwroot/newpec/exported_auto/" + "tile.mapple-on.jp__newpec-mvt-20260106__z___x___y_.pbf/tiles" +) + + +@dataclass +class LayerGeometryStats: + point_count: int = 0 + min_x: int = 0 + max_x: int = 0 + min_y: int = 0 + max_y: int = 0 + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description="审计并按需修复 NavSea PBF 的几何 / extent / native 风险。") + parser.add_argument("--target-root", type=Path, required=True) + parser.add_argument("--label", required=True) + parser.add_argument("--output-dir", type=Path, required=True) + parser.add_argument("--source-root", type=Path, default=DEFAULT_SOURCE_ROOT) + parser.add_argument("--apply-fix", action="store_true", help="若检测到 extent 与源瓦片不一致,则按源瓦片 extent 原地修复。") + parser.add_argument("--sample-limit", type=int, default=30) + parser.add_argument("--zoom", action="append", type=int, help="只审指定 zoom,可重复传入多次。") + return parser.parse_args() + + +def zigzag_decode(value: int) -> int: + return (value >> 1) ^ (-(value & 1)) + + +def decode_feature_geometry(geometry: list[int]) -> LayerGeometryStats: + stats = LayerGeometryStats() + cursor_x = 0 + cursor_y = 0 + initialized = False + idx = 0 + + while idx < len(geometry): + command = geometry[idx] + idx += 1 + command_id = command & 0x7 + command_count = command >> 3 + + if command_id in (1, 2): # MoveTo, LineTo + for _ in range(command_count): + if idx + 1 >= len(geometry): + raise ValueError("geometry command truncated") + cursor_x += zigzag_decode(geometry[idx]) + cursor_y += zigzag_decode(geometry[idx + 1]) + idx += 2 + + if not initialized: + stats.min_x = stats.max_x = cursor_x + stats.min_y = stats.max_y = cursor_y + initialized = True + else: + stats.min_x = min(stats.min_x, cursor_x) + stats.max_x = max(stats.max_x, cursor_x) + stats.min_y = min(stats.min_y, cursor_y) + stats.max_y = max(stats.max_y, cursor_y) + stats.point_count += 1 + elif command_id == 7: # ClosePath + continue + else: + raise ValueError(f"unsupported geometry command id={command_id}") + + return stats + + +def merge_layer_stats(existing: LayerGeometryStats | None, incoming: LayerGeometryStats) -> LayerGeometryStats: + if existing is None or existing.point_count == 0: + return incoming + if incoming.point_count == 0: + return existing + return LayerGeometryStats( + point_count=existing.point_count + incoming.point_count, + min_x=min(existing.min_x, incoming.min_x), + max_x=max(existing.max_x, incoming.max_x), + min_y=min(existing.min_y, incoming.min_y), + max_y=max(existing.max_y, incoming.max_y), + ) + + +def analyze_tile(tile_path: Path) -> dict[str, Any]: + tile = vector_tile_pb2.tile() + tile.ParseFromString(tile_path.read_bytes()) + + layer_summaries: list[dict[str, Any]] = [] + extent_values: set[int] = set() + tile_outside_extent = False + tile_max_overflow = 0 + + for layer in tile.layers: + extent = int(layer.extent or 4096) + extent_values.add(extent) + aggregate: LayerGeometryStats | None = None + for feature in layer.features: + geom_stats = decode_feature_geometry(list(feature.geometry)) + aggregate = merge_layer_stats(aggregate, geom_stats) + + if aggregate is None: + aggregate = LayerGeometryStats() + + outside_extent = False + overflow = 0 + if aggregate.point_count: + overflow = max( + 0, + -aggregate.min_x, + -aggregate.min_y, + aggregate.max_x - extent, + aggregate.max_y - extent, + ) + outside_extent = overflow > 0 + + tile_outside_extent = tile_outside_extent or outside_extent + tile_max_overflow = max(tile_max_overflow, overflow) + layer_summaries.append( + { + "name": layer.name, + "extent": extent, + "point_count": aggregate.point_count, + "min_x": aggregate.min_x, + "max_x": aggregate.max_x, + "min_y": aggregate.min_y, + "max_y": aggregate.max_y, + "outside_extent": outside_extent, + "overflow": overflow, + } + ) + + return { + "extent_values": sorted(extent_values), + "outside_extent": tile_outside_extent, + "max_overflow": tile_max_overflow, + "layers": layer_summaries, + } + + +def desired_extent_from_source(source_path: Path) -> int | None: + if not source_path.exists(): + return None + tile = vector_tile_pb2.tile() + tile.ParseFromString(source_path.read_bytes()) + extents = sorted({int(layer.extent or 4096) for layer in tile.layers}) + if not extents: + return None + if len(extents) == 1: + return extents[0] + return max(extents) + + +def repair_tile_extents(tile_path: Path, desired_extent: int) -> bool: + tile = vector_tile_pb2.tile() + raw = tile_path.read_bytes() + tile.ParseFromString(raw) + changed = False + for layer in tile.layers: + current = int(layer.extent or 4096) + if current != desired_extent: + layer.extent = desired_extent + changed = True + if changed: + tile_path.write_bytes(tile.SerializeToString()) + return changed + + +def hardlink_copy_tree(src_root: Path, dst_root: Path) -> None: + if dst_root.exists(): + raise SystemExit(f"backup root already exists: {dst_root}") + dst_root.mkdir(parents=True, exist_ok=True) + os.system(f"cp -al {src_root}/. {dst_root}/") + + +def write_report( + output_dir: Path, + label: str, + target_root: Path, + source_root: Path, + summary: dict[str, Any], +) -> tuple[Path, Path]: + output_dir.mkdir(parents=True, exist_ok=True) + report_json = output_dir / "geometry_native_audit.json" + report_md = output_dir / "geometry_native_audit.md" + report_json.write_text(json.dumps(summary, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") + + lines = [ + f"# {label} 几何 / Extent / Native 风险审计", + "", + "## 范围", + "", + f"- target root: `{target_root}`", + f"- source root: `{source_root}`", + f"- tiles: `{summary['tile_count']}`", + f"- repaired tiles: `{summary['repaired_tiles']}`", + "", + "## 总体结论", + "", + f"- 坐标超当前 extent 的瓦片数:`{summary['outside_extent_tiles']}`", + f"- 与源瓦片 extent 不一致的瓦片数:`{summary['source_extent_mismatch_tiles']}`", + f"- 可直接按源 extent 修复的瓦片数:`{summary['fixable_from_source_tiles']}`", + "", + "## Zoom 汇总", + "", + ] + + for zoom in sorted(summary["zoom_summary"], key=int): + item = summary["zoom_summary"][zoom] + lines.extend( + [ + f"### z{zoom}", + "", + f"- tiles: `{item['tile_count']}`", + f"- outside extent: `{item['outside_extent_tiles']}`", + f"- source mismatch: `{item['source_extent_mismatch_tiles']}`", + f"- extent counts: `{item['extent_counts']}`", + "", + ] + ) + + lines.extend(["## 代表问题样本", ""]) + for item in summary["sample_tiles"]: + lines.extend( + [ + f"### `{item['tile']}`", + "", + f"- extent values: `{item['extent_values']}`", + f"- source extent: `{item['source_extent']}`", + f"- outside extent: `{item['outside_extent']}`", + f"- max overflow: `{item['max_overflow']}`", + f"- fixable from source: `{item['fixable_from_source']}`", + "", + ] + ) + + report_md.write_text("\n".join(lines) + "\n", encoding="utf-8") + return report_md, report_json + + +def main() -> None: + args = parse_args() + target_root = args.target_root + source_root = args.source_root + output_dir = args.output_dir + + if not target_root.exists(): + raise SystemExit(f"target root not found: {target_root}") + if not source_root.exists(): + raise SystemExit(f"source root not found: {source_root}") + + zoom_summary: dict[str, dict[str, Any]] = defaultdict( + lambda: { + "tile_count": 0, + "outside_extent_tiles": 0, + "source_extent_mismatch_tiles": 0, + "extent_counts": Counter(), + } + ) + sample_tiles: list[dict[str, Any]] = [] + repaired_tiles = 0 + outside_extent_tiles = 0 + source_extent_mismatch_tiles = 0 + fixable_from_source_tiles = 0 + + tile_paths = sorted(target_root.glob("*/*/*.pbf")) + if args.zoom: + zoom_filter = {str(item) for item in args.zoom} + tile_paths = [path for path in tile_paths if path.parent.parent.name in zoom_filter] + for tile_path in tile_paths: + rel = tile_path.relative_to(target_root) + zoom = rel.parts[0] + analysis = analyze_tile(tile_path) + source_extent = desired_extent_from_source(source_root / rel) + current_extent = max(analysis["extent_values"]) if analysis["extent_values"] else None + mismatch = source_extent is not None and current_extent is not None and source_extent != current_extent + fixable = bool( + mismatch + and source_extent is not None + and analysis["outside_extent"] + and analysis["max_overflow"] <= max(0, source_extent - (current_extent or 0)) + ) + + zoom_item = zoom_summary[zoom] + zoom_item["tile_count"] += 1 + for extent in analysis["extent_values"]: + zoom_item["extent_counts"][extent] += 1 + if analysis["outside_extent"]: + outside_extent_tiles += 1 + zoom_item["outside_extent_tiles"] += 1 + if mismatch: + source_extent_mismatch_tiles += 1 + zoom_item["source_extent_mismatch_tiles"] += 1 + if fixable: + fixable_from_source_tiles += 1 + + if args.apply_fix and fixable and source_extent is not None: + if repair_tile_extents(tile_path, source_extent): + repaired_tiles += 1 + analysis = analyze_tile(tile_path) + + if len(sample_tiles) < args.sample_limit and (analysis["outside_extent"] or mismatch): + sample_tiles.append( + { + "tile": str(rel), + "extent_values": analysis["extent_values"], + "source_extent": source_extent, + "outside_extent": analysis["outside_extent"], + "max_overflow": analysis["max_overflow"], + "fixable_from_source": fixable, + } + ) + + normalized_zoom_summary = { + zoom: { + "tile_count": item["tile_count"], + "outside_extent_tiles": item["outside_extent_tiles"], + "source_extent_mismatch_tiles": item["source_extent_mismatch_tiles"], + "extent_counts": dict(sorted(item["extent_counts"].items())), + } + for zoom, item in sorted(zoom_summary.items(), key=lambda kv: int(kv[0])) + } + + summary = { + "label": args.label, + "target_root": str(target_root), + "source_root": str(source_root), + "tile_count": len(tile_paths), + "outside_extent_tiles": outside_extent_tiles, + "source_extent_mismatch_tiles": source_extent_mismatch_tiles, + "fixable_from_source_tiles": fixable_from_source_tiles, + "repaired_tiles": repaired_tiles, + "zoom_summary": normalized_zoom_summary, + "sample_tiles": sample_tiles, + } + report_md, report_json = write_report(output_dir, args.label, target_root, source_root, summary) + print( + json.dumps( + { + "report_md": str(report_md), + "report_json": str(report_json), + "outside_extent_tiles": outside_extent_tiles, + "source_extent_mismatch_tiles": source_extent_mismatch_tiles, + "fixable_from_source_tiles": fixable_from_source_tiles, + "repaired_tiles": repaired_tiles, + }, + ensure_ascii=False, + indent=2, + ) + ) + + +if __name__ == "__main__": + main() diff --git a/report/full_aoi_visual_audit_2026-04-18_r1/full_aoi_visual_audit.json b/report/full_aoi_visual_audit_2026-04-18_r1/full_aoi_visual_audit.json new file mode 100644 index 0000000..06edf88 --- /dev/null +++ b/report/full_aoi_visual_audit_2026-04-18_r1/full_aoi_visual_audit.json @@ -0,0 +1,685 @@ +{ + "compare_url": "http://192.168.200.184/newpec/navsea-compare-full-audit.html", + "cases": [ + { + "id": "okinawa_10nm_full_z12", + "label": "冲绳 10 海里", + "variant": "full", + "zoom": 12, + "center": [ + 127.67, + 26.21 + ], + "radius_nm": 10, + "compare_url": "http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=full&audit=1¢er=127.67%2C26.21&zoom=12", + "changed_pixels": 314441, + "total_pixels": 364800, + "changed_ratio": 0.861954, + "mean_abs_rgb": [ + 40.364, + 41.3728, + 55.3433 + ], + "rms_rgb": [ + 67.4457, + 66.8189, + 83.1026 + ], + "diff_bbox": [ + 0, + 0, + 640, + 513 + ], + "left_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/okinawa_10nm_full_z12/compare_left.png", + "right_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/okinawa_10nm_full_z12/compare_right.png", + "diff_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/okinawa_10nm_full_z12/compare_diff.png" + }, + { + "id": "karatsu_5nm_full_z12", + "label": "唐津 5 海里", + "variant": "full", + "zoom": 12, + "center": [ + 129.9697, + 33.4425 + ], + "radius_nm": 5, + "compare_url": "http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=full&audit=1¢er=129.9697%2C33.4425&zoom=12", + "changed_pixels": 313371, + "total_pixels": 364800, + "changed_ratio": 0.859021, + "mean_abs_rgb": [ + 32.3459, + 33.3448, + 50.9619 + ], + "rms_rgb": [ + 53.1806, + 51.4741, + 72.4363 + ], + "diff_bbox": [ + 0, + 0, + 640, + 513 + ], + "left_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/karatsu_5nm_full_z12/compare_left.png", + "right_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/karatsu_5nm_full_z12/compare_right.png", + "diff_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/karatsu_5nm_full_z12/compare_diff.png" + }, + { + "id": "okinawa_10nm_semantic_z12", + "label": "冲绳 10 海里", + "variant": "semantic", + "zoom": 12, + "center": [ + 127.67, + 26.21 + ], + "radius_nm": 10, + "compare_url": "http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=semantic&audit=1¢er=127.67%2C26.21&zoom=12", + "changed_pixels": 310142, + "total_pixels": 364800, + "changed_ratio": 0.85017, + "mean_abs_rgb": [ + 40.3146, + 41.3705, + 55.2069 + ], + "rms_rgb": [ + 67.4717, + 66.8981, + 83.0146 + ], + "diff_bbox": [ + 0, + 0, + 640, + 513 + ], + "left_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/okinawa_10nm_semantic_z12/compare_left.png", + "right_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/okinawa_10nm_semantic_z12/compare_right.png", + "diff_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/okinawa_10nm_semantic_z12/compare_diff.png" + }, + { + "id": "karatsu_5nm_semantic_z12", + "label": "唐津 5 海里", + "variant": "semantic", + "zoom": 12, + "center": [ + 129.9697, + 33.4425 + ], + "radius_nm": 5, + "compare_url": "http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=semantic&audit=1¢er=129.9697%2C33.4425&zoom=12", + "changed_pixels": 309067, + "total_pixels": 364800, + "changed_ratio": 0.847223, + "mean_abs_rgb": [ + 32.2753, + 33.2837, + 50.6801 + ], + "rms_rgb": [ + 53.1618, + 51.4769, + 72.184 + ], + "diff_bbox": [ + 0, + 0, + 640, + 513 + ], + "left_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/karatsu_5nm_semantic_z12/compare_left.png", + "right_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/karatsu_5nm_semantic_z12/compare_right.png", + "diff_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/karatsu_5nm_semantic_z12/compare_diff.png" + }, + { + "id": "karatsu_5nm_full_z10", + "label": "唐津 5 海里", + "variant": "full", + "zoom": 10, + "center": [ + 129.9697, + 33.4425 + ], + "radius_nm": 5, + "compare_url": "http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=full&audit=1¢er=129.9697%2C33.4425&zoom=10", + "changed_pixels": 267772, + "total_pixels": 364800, + "changed_ratio": 0.734024, + "mean_abs_rgb": [ + 25.3191, + 24.6696, + 50.8948 + ], + "rms_rgb": [ + 43.688, + 39.9594, + 68.802 + ], + "diff_bbox": [ + 0, + 0, + 640, + 513 + ], + "left_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/karatsu_5nm_full_z10/compare_left.png", + "right_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/karatsu_5nm_full_z10/compare_right.png", + "diff_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/karatsu_5nm_full_z10/compare_diff.png" + }, + { + "id": "karatsu_5nm_semantic_z10", + "label": "唐津 5 海里", + "variant": "semantic", + "zoom": 10, + "center": [ + 129.9697, + 33.4425 + ], + "radius_nm": 5, + "compare_url": "http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=semantic&audit=1¢er=129.9697%2C33.4425&zoom=10", + "changed_pixels": 263392, + "total_pixels": 364800, + "changed_ratio": 0.722018, + "mean_abs_rgb": [ + 24.5744, + 23.762, + 48.4161 + ], + "rms_rgb": [ + 42.989, + 38.9809, + 66.1666 + ], + "diff_bbox": [ + 0, + 0, + 640, + 513 + ], + "left_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/karatsu_5nm_semantic_z10/compare_left.png", + "right_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/karatsu_5nm_semantic_z10/compare_right.png", + "diff_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/karatsu_5nm_semantic_z10/compare_diff.png" + }, + { + "id": "tokyo_bay_10nm_full_z12", + "label": "东京湾 10 海里", + "variant": "full", + "zoom": 12, + "center": [ + 139.85, + 35.42 + ], + "radius_nm": 10, + "compare_url": "http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=full&audit=1¢er=139.85%2C35.42&zoom=12", + "changed_pixels": 242549, + "total_pixels": 364800, + "changed_ratio": 0.664882, + "mean_abs_rgb": [ + 21.7351, + 25.7701, + 23.1903 + ], + "rms_rgb": [ + 44.1671, + 46.1494, + 50.8333 + ], + "diff_bbox": [ + 0, + 0, + 640, + 513 + ], + "left_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/tokyo_bay_10nm_full_z12/compare_left.png", + "right_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/tokyo_bay_10nm_full_z12/compare_right.png", + "diff_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/tokyo_bay_10nm_full_z12/compare_diff.png" + }, + { + "id": "tokyo_bay_10nm_semantic_z12", + "label": "东京湾 10 海里", + "variant": "semantic", + "zoom": 12, + "center": [ + 139.85, + 35.42 + ], + "radius_nm": 10, + "compare_url": "http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=semantic&audit=1¢er=139.85%2C35.42&zoom=12", + "changed_pixels": 235968, + "total_pixels": 364800, + "changed_ratio": 0.646842, + "mean_abs_rgb": [ + 21.5178, + 25.5206, + 22.6922 + ], + "rms_rgb": [ + 43.901, + 45.7039, + 50.198 + ], + "diff_bbox": [ + 0, + 0, + 640, + 513 + ], + "left_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/tokyo_bay_10nm_semantic_z12/compare_left.png", + "right_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/tokyo_bay_10nm_semantic_z12/compare_right.png", + "diff_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/tokyo_bay_10nm_semantic_z12/compare_diff.png" + }, + { + "id": "hakata_10nm_full_z10", + "label": "博多港中心 10 海里", + "variant": "full", + "zoom": 10, + "center": [ + 130.335, + 33.6385 + ], + "radius_nm": 10, + "compare_url": "http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=full&audit=1¢er=130.335%2C33.6385&zoom=10", + "changed_pixels": 233090, + "total_pixels": 364800, + "changed_ratio": 0.638953, + "mean_abs_rgb": [ + 22.602, + 21.9769, + 43.8265 + ], + "rms_rgb": [ + 43.1938, + 39.2381, + 64.4699 + ], + "diff_bbox": [ + 0, + 0, + 640, + 513 + ], + "left_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/hakata_10nm_full_z10/compare_left.png", + "right_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/hakata_10nm_full_z10/compare_right.png", + "diff_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/hakata_10nm_full_z10/compare_diff.png" + }, + { + "id": "hakata_10nm_semantic_z10", + "label": "博多港中心 10 海里", + "variant": "semantic", + "zoom": 10, + "center": [ + 130.335, + 33.6385 + ], + "radius_nm": 10, + "compare_url": "http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=semantic&audit=1¢er=130.335%2C33.6385&zoom=10", + "changed_pixels": 226222, + "total_pixels": 364800, + "changed_ratio": 0.620126, + "mean_abs_rgb": [ + 22.2492, + 21.4661, + 42.4354 + ], + "rms_rgb": [ + 42.9444, + 38.7677, + 62.857 + ], + "diff_bbox": [ + 0, + 0, + 640, + 513 + ], + "left_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/hakata_10nm_semantic_z10/compare_left.png", + "right_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/hakata_10nm_semantic_z10/compare_right.png", + "diff_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/hakata_10nm_semantic_z10/compare_diff.png" + }, + { + "id": "tokyo_bay_10nm_full_z10", + "label": "东京湾 10 海里", + "variant": "full", + "zoom": 10, + "center": [ + 139.85, + 35.42 + ], + "radius_nm": 10, + "compare_url": "http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=full&audit=1¢er=139.85%2C35.42&zoom=10", + "changed_pixels": 208628, + "total_pixels": 364800, + "changed_ratio": 0.571897, + "mean_abs_rgb": [ + 21.5068, + 21.8381, + 37.6819 + ], + "rms_rgb": [ + 43.9016, + 42.4239, + 60.7869 + ], + "diff_bbox": [ + 0, + 0, + 640, + 513 + ], + "left_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/tokyo_bay_10nm_full_z10/compare_left.png", + "right_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/tokyo_bay_10nm_full_z10/compare_right.png", + "diff_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/tokyo_bay_10nm_full_z10/compare_diff.png" + }, + { + "id": "tokyo_bay_10nm_semantic_z10", + "label": "东京湾 10 海里", + "variant": "semantic", + "zoom": 10, + "center": [ + 139.85, + 35.42 + ], + "radius_nm": 10, + "compare_url": "http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=semantic&audit=1¢er=139.85%2C35.42&zoom=10", + "changed_pixels": 208306, + "total_pixels": 364800, + "changed_ratio": 0.571014, + "mean_abs_rgb": [ + 21.3378, + 21.3679, + 37.1671 + ], + "rms_rgb": [ + 43.6894, + 41.6284, + 60.1436 + ], + "diff_bbox": [ + 0, + 0, + 640, + 513 + ], + "left_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/tokyo_bay_10nm_semantic_z10/compare_left.png", + "right_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/tokyo_bay_10nm_semantic_z10/compare_right.png", + "diff_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/tokyo_bay_10nm_semantic_z10/compare_diff.png" + }, + { + "id": "hakata_10nm_full_z12", + "label": "博多港中心 10 海里", + "variant": "full", + "zoom": 12, + "center": [ + 130.335, + 33.6385 + ], + "radius_nm": 10, + "compare_url": "http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=full&audit=1¢er=130.335%2C33.6385&zoom=12", + "changed_pixels": 194689, + "total_pixels": 364800, + "changed_ratio": 0.533687, + "mean_abs_rgb": [ + 20.7021, + 21.5285, + 26.4928 + ], + "rms_rgb": [ + 45.2912, + 45.6054, + 50.3669 + ], + "diff_bbox": [ + 0, + 0, + 640, + 513 + ], + "left_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/hakata_10nm_full_z12/compare_left.png", + "right_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/hakata_10nm_full_z12/compare_right.png", + "diff_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/hakata_10nm_full_z12/compare_diff.png" + }, + { + "id": "osaka_bay_10nm_full_z10", + "label": "大阪 10 海里", + "variant": "full", + "zoom": 10, + "center": [ + 135.35, + 34.61 + ], + "radius_nm": 10, + "compare_url": "http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=full&audit=1¢er=135.35%2C34.61&zoom=10", + "changed_pixels": 194451, + "total_pixels": 364800, + "changed_ratio": 0.533035, + "mean_abs_rgb": [ + 21.0579, + 20.6348, + 35.3722 + ], + "rms_rgb": [ + 44.3815, + 41.2946, + 58.6624 + ], + "diff_bbox": [ + 0, + 0, + 640, + 513 + ], + "left_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/osaka_bay_10nm_full_z10/compare_left.png", + "right_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/osaka_bay_10nm_full_z10/compare_right.png", + "diff_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/osaka_bay_10nm_full_z10/compare_diff.png" + }, + { + "id": "osaka_bay_10nm_full_z12", + "label": "大阪 10 海里", + "variant": "full", + "zoom": 12, + "center": [ + 135.35, + 34.61 + ], + "radius_nm": 10, + "compare_url": "http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=full&audit=1¢er=135.35%2C34.61&zoom=12", + "changed_pixels": 194138, + "total_pixels": 364800, + "changed_ratio": 0.532177, + "mean_abs_rgb": [ + 23.4548, + 25.0792, + 21.5488 + ], + "rms_rgb": [ + 49.0486, + 49.6832, + 54.94 + ], + "diff_bbox": [ + 0, + 0, + 640, + 513 + ], + "left_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/osaka_bay_10nm_full_z12/compare_left.png", + "right_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/osaka_bay_10nm_full_z12/compare_right.png", + "diff_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/osaka_bay_10nm_full_z12/compare_diff.png" + }, + { + "id": "hakata_10nm_semantic_z12", + "label": "博多港中心 10 海里", + "variant": "semantic", + "zoom": 12, + "center": [ + 130.335, + 33.6385 + ], + "radius_nm": 10, + "compare_url": "http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=semantic&audit=1¢er=130.335%2C33.6385&zoom=12", + "changed_pixels": 193860, + "total_pixels": 364800, + "changed_ratio": 0.531414, + "mean_abs_rgb": [ + 20.125, + 20.7366, + 25.1796 + ], + "rms_rgb": [ + 44.4182, + 44.2282, + 48.4008 + ], + "diff_bbox": [ + 0, + 0, + 640, + 513 + ], + "left_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/hakata_10nm_semantic_z12/compare_left.png", + "right_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/hakata_10nm_semantic_z12/compare_right.png", + "diff_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/hakata_10nm_semantic_z12/compare_diff.png" + }, + { + "id": "okinawa_10nm_full_z10", + "label": "冲绳 10 海里", + "variant": "full", + "zoom": 10, + "center": [ + 127.67, + 26.21 + ], + "radius_nm": 10, + "compare_url": "http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=full&audit=1¢er=127.67%2C26.21&zoom=10", + "changed_pixels": 192396, + "total_pixels": 364800, + "changed_ratio": 0.527401, + "mean_abs_rgb": [ + 19.8231, + 18.7544, + 25.9994 + ], + "rms_rgb": [ + 43.3599, + 39.8588, + 51.1734 + ], + "diff_bbox": [ + 0, + 0, + 640, + 513 + ], + "left_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/okinawa_10nm_full_z10/compare_left.png", + "right_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/okinawa_10nm_full_z10/compare_right.png", + "diff_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/okinawa_10nm_full_z10/compare_diff.png" + }, + { + "id": "osaka_bay_10nm_semantic_z10", + "label": "大阪 10 海里", + "variant": "semantic", + "zoom": 10, + "center": [ + 135.35, + 34.61 + ], + "radius_nm": 10, + "compare_url": "http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=semantic&audit=1¢er=135.35%2C34.61&zoom=10", + "changed_pixels": 191439, + "total_pixels": 364800, + "changed_ratio": 0.524778, + "mean_abs_rgb": [ + 20.8376, + 20.016, + 34.5041 + ], + "rms_rgb": [ + 44.2009, + 40.5148, + 57.712 + ], + "diff_bbox": [ + 0, + 0, + 640, + 513 + ], + "left_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/osaka_bay_10nm_semantic_z10/compare_left.png", + "right_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/osaka_bay_10nm_semantic_z10/compare_right.png", + "diff_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/osaka_bay_10nm_semantic_z10/compare_diff.png" + }, + { + "id": "osaka_bay_10nm_semantic_z12", + "label": "大阪 10 海里", + "variant": "semantic", + "zoom": 12, + "center": [ + 135.35, + 34.61 + ], + "radius_nm": 10, + "compare_url": "http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=semantic&audit=1¢er=135.35%2C34.61&zoom=12", + "changed_pixels": 187180, + "total_pixels": 364800, + "changed_ratio": 0.513103, + "mean_abs_rgb": [ + 23.438, + 24.8296, + 21.3988 + ], + "rms_rgb": [ + 49.1511, + 49.5348, + 54.9121 + ], + "diff_bbox": [ + 0, + 0, + 640, + 513 + ], + "left_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/osaka_bay_10nm_semantic_z12/compare_left.png", + "right_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/osaka_bay_10nm_semantic_z12/compare_right.png", + "diff_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/osaka_bay_10nm_semantic_z12/compare_diff.png" + }, + { + "id": "okinawa_10nm_semantic_z10", + "label": "冲绳 10 海里", + "variant": "semantic", + "zoom": 10, + "center": [ + 127.67, + 26.21 + ], + "radius_nm": 10, + "compare_url": "http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=semantic&audit=1¢er=127.67%2C26.21&zoom=10", + "changed_pixels": 186366, + "total_pixels": 364800, + "changed_ratio": 0.510872, + "mean_abs_rgb": [ + 19.3335, + 17.9048, + 24.0201 + ], + "rms_rgb": [ + 42.9399, + 38.9411, + 48.1207 + ], + "diff_bbox": [ + 0, + 0, + 640, + 513 + ], + "left_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/okinawa_10nm_semantic_z10/compare_left.png", + "right_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/okinawa_10nm_semantic_z10/compare_right.png", + "diff_image": "/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/okinawa_10nm_semantic_z10/compare_diff.png" + } + ] +} diff --git a/report/full_aoi_visual_audit_2026-04-18_r1/full_aoi_visual_audit.md b/report/full_aoi_visual_audit_2026-04-18_r1/full_aoi_visual_audit.md new file mode 100644 index 0000000..ce8566f --- /dev/null +++ b/report/full_aoi_visual_audit_2026-04-18_r1/full_aoi_visual_audit.md @@ -0,0 +1,209 @@ +# 全国 AOI 截图对比审计 + +## 总览 + +- compare page: `http://192.168.200.184/newpec/navsea-compare-full-audit.html` +- cases: `20` + +## 差异排序 + +### 冲绳 10 海里 · full · z12 + +- changed ratio: `0.861954` +- changed pixels: `314441` / `364800` +- mean abs rgb: `[40.364, 41.3728, 55.3433]` +- compare url: `http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=full&audit=1¢er=127.67%2C26.21&zoom=12` +- left image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/okinawa_10nm_full_z12/compare_left.png` +- right image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/okinawa_10nm_full_z12/compare_right.png` +- diff image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/okinawa_10nm_full_z12/compare_diff.png` + +### 唐津 5 海里 · full · z12 + +- changed ratio: `0.859021` +- changed pixels: `313371` / `364800` +- mean abs rgb: `[32.3459, 33.3448, 50.9619]` +- compare url: `http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=full&audit=1¢er=129.9697%2C33.4425&zoom=12` +- left image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/karatsu_5nm_full_z12/compare_left.png` +- right image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/karatsu_5nm_full_z12/compare_right.png` +- diff image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/karatsu_5nm_full_z12/compare_diff.png` + +### 冲绳 10 海里 · semantic · z12 + +- changed ratio: `0.85017` +- changed pixels: `310142` / `364800` +- mean abs rgb: `[40.3146, 41.3705, 55.2069]` +- compare url: `http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=semantic&audit=1¢er=127.67%2C26.21&zoom=12` +- left image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/okinawa_10nm_semantic_z12/compare_left.png` +- right image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/okinawa_10nm_semantic_z12/compare_right.png` +- diff image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/okinawa_10nm_semantic_z12/compare_diff.png` + +### 唐津 5 海里 · semantic · z12 + +- changed ratio: `0.847223` +- changed pixels: `309067` / `364800` +- mean abs rgb: `[32.2753, 33.2837, 50.6801]` +- compare url: `http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=semantic&audit=1¢er=129.9697%2C33.4425&zoom=12` +- left image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/karatsu_5nm_semantic_z12/compare_left.png` +- right image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/karatsu_5nm_semantic_z12/compare_right.png` +- diff image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/karatsu_5nm_semantic_z12/compare_diff.png` + +### 唐津 5 海里 · full · z10 + +- changed ratio: `0.734024` +- changed pixels: `267772` / `364800` +- mean abs rgb: `[25.3191, 24.6696, 50.8948]` +- compare url: `http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=full&audit=1¢er=129.9697%2C33.4425&zoom=10` +- left image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/karatsu_5nm_full_z10/compare_left.png` +- right image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/karatsu_5nm_full_z10/compare_right.png` +- diff image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/karatsu_5nm_full_z10/compare_diff.png` + +### 唐津 5 海里 · semantic · z10 + +- changed ratio: `0.722018` +- changed pixels: `263392` / `364800` +- mean abs rgb: `[24.5744, 23.762, 48.4161]` +- compare url: `http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=semantic&audit=1¢er=129.9697%2C33.4425&zoom=10` +- left image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/karatsu_5nm_semantic_z10/compare_left.png` +- right image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/karatsu_5nm_semantic_z10/compare_right.png` +- diff image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/karatsu_5nm_semantic_z10/compare_diff.png` + +### 东京湾 10 海里 · full · z12 + +- changed ratio: `0.664882` +- changed pixels: `242549` / `364800` +- mean abs rgb: `[21.7351, 25.7701, 23.1903]` +- compare url: `http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=full&audit=1¢er=139.85%2C35.42&zoom=12` +- left image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/tokyo_bay_10nm_full_z12/compare_left.png` +- right image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/tokyo_bay_10nm_full_z12/compare_right.png` +- diff image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/tokyo_bay_10nm_full_z12/compare_diff.png` + +### 东京湾 10 海里 · semantic · z12 + +- changed ratio: `0.646842` +- changed pixels: `235968` / `364800` +- mean abs rgb: `[21.5178, 25.5206, 22.6922]` +- compare url: `http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=semantic&audit=1¢er=139.85%2C35.42&zoom=12` +- left image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/tokyo_bay_10nm_semantic_z12/compare_left.png` +- right image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/tokyo_bay_10nm_semantic_z12/compare_right.png` +- diff image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/tokyo_bay_10nm_semantic_z12/compare_diff.png` + +### 博多港中心 10 海里 · full · z10 + +- changed ratio: `0.638953` +- changed pixels: `233090` / `364800` +- mean abs rgb: `[22.602, 21.9769, 43.8265]` +- compare url: `http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=full&audit=1¢er=130.335%2C33.6385&zoom=10` +- left image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/hakata_10nm_full_z10/compare_left.png` +- right image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/hakata_10nm_full_z10/compare_right.png` +- diff image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/hakata_10nm_full_z10/compare_diff.png` + +### 博多港中心 10 海里 · semantic · z10 + +- changed ratio: `0.620126` +- changed pixels: `226222` / `364800` +- mean abs rgb: `[22.2492, 21.4661, 42.4354]` +- compare url: `http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=semantic&audit=1¢er=130.335%2C33.6385&zoom=10` +- left image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/hakata_10nm_semantic_z10/compare_left.png` +- right image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/hakata_10nm_semantic_z10/compare_right.png` +- diff image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/hakata_10nm_semantic_z10/compare_diff.png` + +### 东京湾 10 海里 · full · z10 + +- changed ratio: `0.571897` +- changed pixels: `208628` / `364800` +- mean abs rgb: `[21.5068, 21.8381, 37.6819]` +- compare url: `http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=full&audit=1¢er=139.85%2C35.42&zoom=10` +- left image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/tokyo_bay_10nm_full_z10/compare_left.png` +- right image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/tokyo_bay_10nm_full_z10/compare_right.png` +- diff image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/tokyo_bay_10nm_full_z10/compare_diff.png` + +### 东京湾 10 海里 · semantic · z10 + +- changed ratio: `0.571014` +- changed pixels: `208306` / `364800` +- mean abs rgb: `[21.3378, 21.3679, 37.1671]` +- compare url: `http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=semantic&audit=1¢er=139.85%2C35.42&zoom=10` +- left image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/tokyo_bay_10nm_semantic_z10/compare_left.png` +- right image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/tokyo_bay_10nm_semantic_z10/compare_right.png` +- diff image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/tokyo_bay_10nm_semantic_z10/compare_diff.png` + +### 博多港中心 10 海里 · full · z12 + +- changed ratio: `0.533687` +- changed pixels: `194689` / `364800` +- mean abs rgb: `[20.7021, 21.5285, 26.4928]` +- compare url: `http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=full&audit=1¢er=130.335%2C33.6385&zoom=12` +- left image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/hakata_10nm_full_z12/compare_left.png` +- right image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/hakata_10nm_full_z12/compare_right.png` +- diff image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/hakata_10nm_full_z12/compare_diff.png` + +### 大阪 10 海里 · full · z10 + +- changed ratio: `0.533035` +- changed pixels: `194451` / `364800` +- mean abs rgb: `[21.0579, 20.6348, 35.3722]` +- compare url: `http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=full&audit=1¢er=135.35%2C34.61&zoom=10` +- left image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/osaka_bay_10nm_full_z10/compare_left.png` +- right image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/osaka_bay_10nm_full_z10/compare_right.png` +- diff image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/osaka_bay_10nm_full_z10/compare_diff.png` + +### 大阪 10 海里 · full · z12 + +- changed ratio: `0.532177` +- changed pixels: `194138` / `364800` +- mean abs rgb: `[23.4548, 25.0792, 21.5488]` +- compare url: `http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=full&audit=1¢er=135.35%2C34.61&zoom=12` +- left image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/osaka_bay_10nm_full_z12/compare_left.png` +- right image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/osaka_bay_10nm_full_z12/compare_right.png` +- diff image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/osaka_bay_10nm_full_z12/compare_diff.png` + +### 博多港中心 10 海里 · semantic · z12 + +- changed ratio: `0.531414` +- changed pixels: `193860` / `364800` +- mean abs rgb: `[20.125, 20.7366, 25.1796]` +- compare url: `http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=semantic&audit=1¢er=130.335%2C33.6385&zoom=12` +- left image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/hakata_10nm_semantic_z12/compare_left.png` +- right image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/hakata_10nm_semantic_z12/compare_right.png` +- diff image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/hakata_10nm_semantic_z12/compare_diff.png` + +### 冲绳 10 海里 · full · z10 + +- changed ratio: `0.527401` +- changed pixels: `192396` / `364800` +- mean abs rgb: `[19.8231, 18.7544, 25.9994]` +- compare url: `http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=full&audit=1¢er=127.67%2C26.21&zoom=10` +- left image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/okinawa_10nm_full_z10/compare_left.png` +- right image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/okinawa_10nm_full_z10/compare_right.png` +- diff image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/okinawa_10nm_full_z10/compare_diff.png` + +### 大阪 10 海里 · semantic · z10 + +- changed ratio: `0.524778` +- changed pixels: `191439` / `364800` +- mean abs rgb: `[20.8376, 20.016, 34.5041]` +- compare url: `http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=semantic&audit=1¢er=135.35%2C34.61&zoom=10` +- left image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/osaka_bay_10nm_semantic_z10/compare_left.png` +- right image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/osaka_bay_10nm_semantic_z10/compare_right.png` +- diff image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/osaka_bay_10nm_semantic_z10/compare_diff.png` + +### 大阪 10 海里 · semantic · z12 + +- changed ratio: `0.513103` +- changed pixels: `187180` / `364800` +- mean abs rgb: `[23.438, 24.8296, 21.3988]` +- compare url: `http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=semantic&audit=1¢er=135.35%2C34.61&zoom=12` +- left image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/osaka_bay_10nm_semantic_z12/compare_left.png` +- right image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/osaka_bay_10nm_semantic_z12/compare_right.png` +- diff image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/osaka_bay_10nm_semantic_z12/compare_diff.png` + +### 冲绳 10 海里 · semantic · z10 + +- changed ratio: `0.510872` +- changed pixels: `186366` / `364800` +- mean abs rgb: `[19.3335, 17.9048, 24.0201]` +- compare url: `http://192.168.200.184/newpec/navsea-compare-full-audit.html?variant=semantic&audit=1¢er=127.67%2C26.21&zoom=10` +- left image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/okinawa_10nm_semantic_z10/compare_left.png` +- right image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/okinawa_10nm_semantic_z10/compare_right.png` +- diff image: `/root/sourceserver/pbf/report/full_aoi_visual_audit_2026-04-18_r1/okinawa_10nm_semantic_z10/compare_diff.png` + diff --git a/report/full_geometry_native_extent_fix_2026-04-18.json b/report/full_geometry_native_extent_fix_2026-04-18.json new file mode 100644 index 0000000..33b7ca0 --- /dev/null +++ b/report/full_geometry_native_extent_fix_2026-04-18.json @@ -0,0 +1,45 @@ +{ + "scope": { + "zoom": 12, + "full_root": "/home/wwwroot/pbf-delivery-full-20260415", + "semantic_root": "/home/wwwroot/pbf-delivery-full-semantic-20260416" + }, + "pre_fix": { + "full": { + "tile_count": 48556, + "extent_counts": { + "1048576": 47366, + "4096": 1190 + } + }, + "semantic": { + "tile_count": 48556, + "extent_counts": { + "1048576": 47296, + "4096": 1260 + } + } + }, + "backup_roots": [ + "/home/wwwroot/pbf-delivery-full-20260415-backup-20260418-preextentfix", + "/home/wwwroot/pbf-delivery-full-semantic-20260416-backup-20260418-preextentfix" + ], + "repaired_tiles": { + "full": 1183, + "semantic": 1215 + }, + "post_fix": { + "full": { + "tile_count": 48556, + "extent_counts": { + "1048576": 48556 + } + }, + "semantic": { + "tile_count": 48556, + "extent_counts": { + "1048576": 48556 + } + } + } +} diff --git a/report/full_geometry_native_extent_fix_2026-04-18.md b/report/full_geometry_native_extent_fix_2026-04-18.md new file mode 100644 index 0000000..3cf9e4f --- /dev/null +++ b/report/full_geometry_native_extent_fix_2026-04-18.md @@ -0,0 +1,50 @@ +# 全国 full / semantic z12 extent 逻辑审计与修复 + +## 范围 + +- `/home/wwwroot/pbf-delivery-full-20260415` +- `/home/wwwroot/pbf-delivery-full-semantic-20260416` +- 聚焦 zoom `12` + +## 修前统计 + +- `full z12` + - 总瓦片:`48556` + - `extent = 1048576`:`47366` + - `extent = 4096`:`1190` +- `semantic z12` + - 总瓦片:`48556` + - `extent = 1048576`:`47296` + - `extent = 4096`:`1260` + +## 修复动作 + +- 已先做硬链接备份: + - `/home/wwwroot/pbf-delivery-full-20260415-backup-20260418-preextentfix` + - `/home/wwwroot/pbf-delivery-full-semantic-20260416-backup-20260418-preextentfix` +- 对当前 `extent = 4096` 的 z12 错片: + - 逐张读取原始 `newpec` 同路径 source tile + - 若 source extent 为 `1048576` + - 则把当前 delivery / semantic tile 的全部 layer extent 回写为 `1048576` + +## 修复结果 + +- `full repaired = 1183` +- `semantic repaired = 1215` + +## 修后复核 + +- `full z12` + - `48556 / 48556` 全部为 `1048576` +- `semantic z12` + - `48556 / 48556` 全部为 `1048576` + +## 当前结论 + +- 这轮已确认全国 `full / semantic` 的 `z12` 中确实存在一批 extent 错退片 +- 当前这批错片已经按 source tile 口径修回 +- 这一步解决的是: + - 几何 / extent / native 风险中的明确 metadata 错片问题 +- 这不等于: + - 全国视觉等价性已经通过 + diff --git a/src/pbf/navsea-compare-full-audit.html b/src/pbf/navsea-compare-full-audit.html new file mode 100644 index 0000000..de50e1f --- /dev/null +++ b/src/pbf/navsea-compare-full-audit.html @@ -0,0 +1,639 @@ + + + + + + NavSea Full Audit Compare + + + + +
+
+
全国人工审计对比页
+
左侧固定加载原始 style.json + 原始 newpec 瓦片;右侧固定加载全国 delivery 的 style.navsea-delivery-full.json + 全国 delivery PBF + 当前 sprite。两边联动同步,适合直接审 style / pbf / sprite 的整体视觉差异。
+
+
+
HTML: 加载中
+
Style: 加载中
+
PBF: 加载中
+
Sprite: 加载中
+ + +
+
+ +
+
+
+ 左侧 · 原始版 + style.json + 原始 newpec 瓦片 +
+
+
+
+
+ 右侧 · Delivery + 全国 delivery style + 全国 delivery PBF + 当前 sprite +
+
+
+
+ + + +
等待加载对比样式…
+ + + + + diff --git a/tasks/pbf/NavSea_Full_AOI_Visual_Audit_2026-04-18.json b/tasks/pbf/NavSea_Full_AOI_Visual_Audit_2026-04-18.json new file mode 100644 index 0000000..4a1b273 --- /dev/null +++ b/tasks/pbf/NavSea_Full_AOI_Visual_Audit_2026-04-18.json @@ -0,0 +1,37 @@ +[ + { + "id": "hakata_10nm", + "label": "博多港中心 10 海里", + "center": [130.335, 33.6385], + "radius_nm": 10, + "zoom_levels": [10, 12] + }, + { + "id": "tokyo_bay_10nm", + "label": "东京湾 10 海里", + "center": [139.85, 35.42], + "radius_nm": 10, + "zoom_levels": [10, 12] + }, + { + "id": "osaka_bay_10nm", + "label": "大阪 10 海里", + "center": [135.35, 34.61], + "radius_nm": 10, + "zoom_levels": [10, 12] + }, + { + "id": "okinawa_10nm", + "label": "冲绳 10 海里", + "center": [127.67, 26.21], + "radius_nm": 10, + "zoom_levels": [10, 12] + }, + { + "id": "karatsu_5nm", + "label": "唐津 5 海里", + "center": [129.9697, 33.4425], + "radius_nm": 5, + "zoom_levels": [10, 12] + } +]