Files
pbf/tools/style-visual-object

Style Visual Object Tool

目标

本工具只做一件事:

从一份 Style JSON 以及它使用的 Sprite / Glyph 中,独立提取和生成 Visual Object。

工具输出的是匿名、可比较、可审计的 Visual Object,不负责给 Visual Object 赋予 NavSea 标准 Layer 名称,也不负责解释 Provider 的业务字段。


最重要原则:先生成 Visual Object,再做语义和 Layer 对齐

本工具必须严格遵守以下顺序:

任意 Provider Style + Sprite / Glyph
        ↓
Style Visual Object Tool
        ↓
Anonymous Visual Object Catalog
        ↓
与 Standard Visual Object Catalog 比较
        ↓
MATCH / PARTIAL / UNKNOWN
        ↓
最后才允许赋予标准 Layer 名称或 Semantic

禁止走捷径

在 Visual Object 生成阶段,以下信息即使存在,也只能作为 provenance / audit 信息保存,不得用于决定 Visual Object 属于哪个标准 Layer 或 Semantic:

  • source-layer 名称
  • Style Layer id
  • Provider 名称
  • canonical_object_type
  • S-52 / CM95 对象类名称
  • S-52 symbol code 的文字含义
  • 任何看起来与 NavSea 标准 Layer 同名或相似的字段
  • 任何 Provider 私有业务字段名称

例如,某个 Provider 的 Style 中即使存在:

source-layer = navigation_marks

本工具也不得因此把该 Visual Object 定义为 NavSea 的 navigation_marks。

它只能记录:

provenance.source_layer = navigation_marks

真正的 Layer 名称必须在 Visual Object 生成完成后,通过与标准 Visual Object 的比较结果确定。


Provider-neutral

本工具必须完全独立于具体 Provider。

同一套代码应能够处理:

  • NavSea Style
  • CM95 Style
  • 未来 Provider B / C / D
  • 任意符合支持范围的 MapLibre Style

主逻辑中禁止出现类似:

if provider == "cm95"
if source_layer == "navigation_marks"
if symbol_code == "BOYCAN63" then ...

这类 Provider-specific Semantic 判断。

Provider-specific 名称可以进入 provenance,但不能进入 Visual Object 分类逻辑。


输入

第一阶段输入仅包括:

Style JSON
Sprite JSON + PNG
Glyph(Style 使用时)

Visual Object 提取本身不要求读取 PBF。

如果 Style 中使用数据驱动表达式,例如:

["get", "chart_icon_image"]

或:

["get", "s52_symbol_code"]

工具必须保留为动态视觉参数,不得为了得到具体值去读取 PBF、猜测字段含义或套用 Provider 规则。


输出

建议至少生成:

catalog.json
catalog.html
previews/
audit.json

其中每个 Visual Object 至少记录:

  • 匿名 Visual Object ID
  • geometry role
  • Style Layer 原始顺序 / z-order
  • 参与组成的 Render Components
  • icon / line / fill / pattern / circle / text
  • Sprite 实际视觉资源
  • 动态视觉参数
  • 出现条件 / Style filter
  • 组件数量与组合关系
  • Preview
  • provenance
  • 无法解析或无法确定的部分

Visual Signature

用于后续跨 Provider 比较的核心是 Visual Signature,而不是 Provider 字段名称。

Visual Signature 应主要表达:

geometry role
+
ordered render components
+
sprite visual
+
fill
+
line
+
pattern
+
text role
+
component multiplicity
+
component composition
+
style order
+
visual conditions / variants

后续 Visual Matcher 应基于这些视觉结构进行比较。

Provider 原始字段只作为辅助审计证据,不作为主要匹配依据。


source-layer 的地位

source-layer 在本工具中只具有两个作用:

  1. 帮助确定 Style Layer 的数据来源和可组合范围;
  2. 作为 provenance / debug / audit 信息输出。

它不是 Semantic,也不是最终 Layer 分类结果。

不得执行:

source-layer 名称
→ 直接得到 NavSea 标准 Layer

正确流程必须是:

Style + Sprite
→ Visual Object
→ Visual Match
→ 标准 Layer / Semantic

Standard Visual Object

NavSea 当前 Style 也必须使用同一套 Style Visual Object Tool 生成 Visual Object。

不得在 Tool 内置 NavSea Layer 规则。

NavSea 之所以成为 Standard,不是因为 Tool 对 NavSea 使用特殊逻辑,而是在 Tool 生成 Visual Object 之后,由独立的标准定义/人工确认把这些 Visual Object 与 NavSea 标准 Layer 关联起来。

因此:

NavSea Style
→ Anonymous Visual Object Catalog
→ 标准确认
→ Standard Visual Object Catalog

其他 Provider:

Provider Style
→ Anonymous Visual Object Catalog
→ 与 Standard Visual Object Catalog 比较
→ 标准 Layer

不属于本工具的职责

本工具不负责:

  • PBF 数据读取和 Feature 实例化
  • Provider 字段翻译
  • CM95 专用判断
  • NavSea 专用判断
  • Semantic 命名
  • 标准 Layer 命名
  • Feature grouping
  • 危险性判断
  • 船舶吃水相关 Planning / Danger 判断
  • 跨 Provider 的最终匹配决策

这些属于后续独立阶段或独立 Tool。


实现约束

后续实现必须满足:

  • 未知 Style expression 必须显式标记 UNKNOWN / UNSUPPORTED,不得静默忽略;
  • 必须保留 Style 原始顺序;
  • 必须保留组件 multiplicity,不能用 set 去重破坏组合;
  • 必须保留动态表达式,不得伪造成确定值;
  • Sprite 必须根据 atlas metadata 提取真实视觉资源;
  • 不得通过坐标接近、名字相似或 Provider 字段名自动拼接/分类 Visual Object;
  • 不得因为某个 source-layer 与 NavSea 标准 Layer 同名就直接判定 MATCH;
  • Visual Object 的生成和 Visual Object 的标准匹配必须是两个独立阶段。

一句话验收标准

给工具任意一套 Style + Sprite,即使它完全不知道这是什么 Provider、也没有任何 PBF 数据,仍然能够独立生成匿名 Visual Object Catalog;只有在该 Catalog 生成完成后,才允许进入与 NavSea Standard Visual Object Catalog 的比较和 Layer 命名阶段。


NavSea Standard Visual Object Catalog 冻结规则

NavSea 的 Visual Object 与标准 Layer 名在首次完成生成、确认和命名后,应视为 Standard Visual Object Catalog 的冻结基线。

正常情况下:

NavSea Anonymous Visual Object
        ↓
人工/标准确认 Layer 名
        ↓
Standard Visual Object Catalog
        ↓
冻结

冻结后,后续 CM95、Provider B、Provider C 等只能使用该 Standard Visual Object Catalog 进行 Visual Object 匹配和 Layer 命名。

除非用户明确要求重建、重新生成、修订标准或升级 Standard Catalog 版本,否则禁止:

  • 每次处理新 Provider 时重新生成 NavSea Visual Object;
  • 自动重新计算或改变 NavSea Visual Object ID;
  • 自动改变已经确认的标准 Layer 名;
  • 因 CM95 或其他 Provider 的数据特点反向修改 NavSea Standard Catalog;
  • 用新的 Provider 匹配结果覆盖现有标准基线。

如果确实需要修改 Standard Visual Object Catalog,必须作为显式的标准升级处理,并保留旧版本,不得静默覆盖。

因此正常跨 Provider 工作流固定为:

已冻结的 NavSea Standard Visual Object Catalog
                    │
                    │ 作为只读标准
                    ▼
        Provider Anonymous Visual Object
                    │
                    ▼
              Visual Matcher
                    │
                    ▼
          标准 Layer 命名结果

一句话原则:

NavSea Standard Visual Object Catalog 是标准输入,不是每次 Provider 解析时重新生成的临时产物。


Visual Object Layer Assignment 的补充硬规则

1. Sprite 存在不等于 Style 会绘制

Sprite atlas 中存在某个资源,只能说明资源可用,不能说明当前 Style 会实际引用它。

Anonymous Visual Object Catalog 只能从 Style 的正向可达规则生成:

Style 明确允许的资源
→ 进入 Anonymous Visual Object Catalog

仅存在于 Sprite、但当前 Style 没有正向可达路径的资源
→ 不进入 Catalog

尤其不得把 !match、!= 等排除条件中的值误当成候选 Visual Object。

2. 同一视觉类可能对应多个标准 Layer

如果 NavSea Standard Visual Object Catalog 中同一实际视觉图形被多个标准 Layer 复用,则 Visual Matcher 不能仅凭图形强行选一个 Layer。

必须输出:

AMBIGUOUS
candidateStandardLayers:
  - layer_a
  - layer_b

例如危险物公共符号可以同时被多个标准 Layer 使用;这种歧义是 Standard Catalog 自身的事实,不应由 Matcher 擅自消除。

3. 禁止整个匿名 group 继承单一 Layer

Style 的一个匿名 group 可能允许多个不同视觉家族,尤其是通用 S-52 Style。

因此禁止:

group 命中一个视觉锚点
→ 整个 group 继承该 Layer

Layer Assignment 必须以单个 Visual Object / Visual Resource 为基本单位。

Group 只用于:

  • 组合范围审计;
  • Style provenance;
  • 结果分布检查。

4. Layer Assignment 状态

正式状态固定为:

MATCH
PARTIAL
AMBIGUOUS
COMPONENT
UNKNOWN

含义:

  • MATCH:实际图形基本一致,可以直接作为标准 Layer 锚点;
  • PARTIAL:不是同一完整图形,但视觉家族或组件关系足以支持唯一标准 Layer;
  • AMBIGUOUS:视觉证据只能得到多个标准 Layer 候选,禁止强行选一个;
  • COMPONENT:明确只是完整 Visual Object 的组成部分,不单独分配 Layer;可选记录组件类型;
  • UNKNOWN:当前证据不足,不命名。

未知和歧义都是合法结果,禁止为了提高覆盖率而静默猜测。


人工确认 UI:CM95 Visual Object Reviewer

最终 Layer Assignment 必须允许人工确认。项目内提供独立 Web Reviewer:

tools/style-visual-object/reviewer/
├── review_server.py
└── web/
    ├── index.html
    ├── app.js
    └── style.css

默认启动:

python3 tools/style-visual-object/reviewer/review_server.py   --host 0.0.0.0   --port 18083

人工确认单位

Reviewer 以 CM95 当前 Style 正向可达的唯一 Visual Resource 为确认单位。

当前基线为 150 个资源。一个人工决定会应用到该视觉资源在 Anonymous Catalog 中的所有 occurrence,但不会修改 Anonymous Catalog 本身。

主审查界面必须隐藏 Provider 语义信息

为了避免人工被字段名或已有 source-layer 名称带偏,主审查界面默认只能看到:

  • 匿名 Visual Object ID;
  • 实际图形;
  • component role;
  • geometry role;
  • occurrence 数;
  • NavSea Standard Visual Object 候选;
  • 标准 Layer;
  • 当前人工决定。

以下 CM95 原始信息默认隐藏:

  • resource key;
  • source-layer;
  • Style Layer id;
  • Provider provenance。

只有用户主动展开“审计信息”后才能读取这些内容。

人工状态

人工决定固定使用:

MATCH
PARTIAL
AMBIGUOUS
COMPONENT
UNKNOWN

规则:

  • MATCH / PARTIAL:必须选择且只能选择一个标准 Layer;
  • AMBIGUOUS:必须选择至少两个候选标准 Layer;
  • COMPONENT:不选择标准 Layer、不绑定 Standard Visual Object;可选记录顶标、浮标主体、立标主体、灯光、附加标记、面填充图案、线型图案、文字或其他组件;
  • UNKNOWN:不选择标准 Layer;
  • Standard Visual Object 可以选择,也可以不选择;
  • 人工确认优先于机器建议;
  • 未人工确认的项目在最终人工导出时保持 UNKNOWN,不自动继承机器建议。

人工结果保存

增量人工决定保存到:

tools/style-visual-object/output/cm95-manual-review/manual-review-v1.json

点击“生成当前人工确认结果”后生成:

tools/style-visual-object/output/cm95-manual-review/
├── reviewed-anchors-manual-v1.json
└── assignment/
    ├── cm95-layer-assignment-v1.json
    ├── cm95-layer-assignment-v1.csv
    └── cm95-layer-assignment-v1.html

人工确认过程不得覆盖:

  • navsea-standard/standard-catalog.json;
  • cm95-anonymous/anonymous-catalog.json;
  • 既有自动/辅助建议文件。

NavSea Standard Catalog 继续保持 FROZEN,只作为只读标准库使用。


Reviewer 中文名称显示规则

人工 Reviewer 中,CM95 与 NavSea Standard Visual Object 均应优先显示中文名称,帮助人工理解和确认。

中文名称来源分两类:

  1. CM95:

    • 优先读取当前 CM95 仓库中的 S-52 symbol / line / area-pattern metadata;
    • 保留 S-52 原始英文 description;
    • 生成独立的中文显示译名;
    • 中文译名属于工程 UI enrichment,不冒充 IHO 官方中文译名。
  2. NavSea Standard:

    • 依据冻结 Standard Visual Object 的语义资源键和标准 Layer 生成中文显示名;
    • 标准 Layer 同时显示中文名和原始 Layer ID。

名称补充表:

tools/style-visual-object/output/reference-name-enrichment-v1.json

固定原则:

中文名、英文说明、S-52 code 只用于 UI 显示和人工理解,不得参与 Visual Matcher、自动聚类或 Layer Assignment。

Reviewer 主界面显示优先级:

中文名称
→ 实际图形
→ 中文标准 Layer
→ 原始 code / 英文说明(辅助)

已有机器建议也必须显示:

标准对象中文名
+
标准 Layer 中文名
+
MATCH / PARTIAL / AMBIGUOUS / COMPONENT / UNKNOWN

不得只显示资源 key 或 Layer ID 让用户自行猜测。


Reviewer 宽屏固定确认布局

Reviewer 在宽屏下采用固定三栏工作区:

左:CM95 当前 Visual Object
中:NavSea Standard 候选(竖排、内部滚动)
右:人工判断(固定可见)

固定要求:

  • 主页面不得为了点击 MATCH / PARTIAL / AMBIGUOUS / COMPONENT / UNKNOWN 或保存结果而要求纵向滚动;
  • NavSea Standard 候选采用竖排列表,并在候选区域内部滚动;
  • 标准 Layer 列表在人工判断面板内部滚动;
  • 保存并下一个 / 仅保存 / 撤销 始终保持在右侧人工判断区可见;
  • 左侧 CM95 队列独立滚动;
  • 审计信息默认折叠,不抢占主要确认空间;
  • 窄屏才允许退回上下布局。

Standard Visual Object 缺失时的 Layer-only 人工命名

外部 Provider(例如 CM95 / S-52)的视觉内容可能多于当前 NavSea Standard Visual Object Catalog。 因此:

找不到对应的 NavSea Standard Visual Object,不等于无法确定标准 Layer。

人工 Reviewer 必须支持两种最终确认路径:

A. 有对应标准图标
Provider Visual Object
→ Standard Visual Object
→ Standard Layer
assignment_mode = VISUAL_OBJECT_MATCH

B. 没有对应标准图标,但所属 Layer 可以人工确定
Provider Visual Object
→ Standard Layer
assignment_mode = LAYER_ONLY
standard_resource_key = null

Layer-only 的要求:

  • 必须由人工明确选择标准 Layer;
  • 不得伪造一个不存在的 Standard Visual Object;
  • 不得因为没有对应图标就强制设为 UNKNOWN;
  • 中文名称、S-52 官方英文说明和实际视觉可以作为人工理解证据;
  • 这些名称仍不进入自动 Visual Matcher;
  • 当前 Reviewer 中,点击“没有对应标准图标,只确认所属 Layer”会清除 Standard Visual Object 绑定,并保留唯一 Layer。

状态建议:

  • 有明确对应完整图形时可使用 MATCH;
  • 无对应标准图标但 Layer 明确时使用 PARTIAL + LAYER_ONLY;
  • 只能确定多个可能 Layer 时使用 AMBIGUOUS;
  • 连 Layer 也无法确定时才使用 UNKNOWN。

COMPONENT:只作为完整 Visual Object 的组成部分

当当前显示的 S-52 / CM95 图形只是一个主体、顶标、灯光或其他附加组件时,不应强迫用户给它最终 Layer。 Reviewer 必须允许:

status = COMPONENT
assignment_mode = COMPONENT_ONLY
standard_layer = null
standard_resource_key = null

可选 component_kind:

topmark          顶标
buoy_body        浮标主体
beacon_body      立标主体
light            灯光
auxiliary_mark   附加标记
fill_pattern     面填充图案
line_pattern     线型图案
text             文字
other            其他组件

COMPONENT 与 UNKNOWN 必须区分:

  • COMPONENT:已经知道它只是完整对象的一部分;
  • UNKNOWN:当前连它的作用/归属关系也无法可靠判断。

后续 Composite Visual Object 阶段再把 COMPONENT 与其他组件组合,最终 Layer 应尽量由完整 Visual Object 确认。


Reviewer 最可能候选提示

Reviewer 的 NavSea Standard 候选可以提供一个 UI-only 的“最可能”提示,帮助人工快速判断。

综合参考只用于界面提示,来源包括:

  • Visual Matcher 的实际图形相似度;
  • CM95 中文显示名与 NavSea Standard 中文显示名的文字相似度;
  • 已有 reviewed visual suggestion 是否支持同一标准对象或同一 Layer。

界面规则:

  • 综合排序第一的候选中文名称标红;
  • 显示“最可能”标签;
  • 同时显示“视觉 xx% / 综合 xx%”;
  • 即使是第一名,综合分较低时也必须保留低分,不能隐藏不确定性;
  • 红色提示不得自动选择 Standard Visual Object;
  • 不得自动写入人工决定;
  • 不参与最终 Layer Assignment。

一句话:

红色“最可能”只是人工审查提示,不是系统确认结果。

宽屏布局同时调整为:当前 CM95 对象区域更窄,NavSea Standard 视觉候选区域更宽,右侧人工判断继续固定显示。


Provider Layer Classifier:当前工作的最终目标

当前多源 PBF 对应工作的目标不是寻找“外部 Provider 图标等于 NavSea 哪个图标”,而是:

把外部 Provider 的对象正确分类到现有 NavSea Standard Layer。

因此正式流程分成两层:

第一层:Provider-neutral Style Visual Object Tool
Style + Sprite
→ Anonymous Visual Object

第二层:Provider Layer Classifier
Anonymous Visual Object
+ Provider 官方语义资料
+ 实际视觉证据
+ 可选 Standard Visual Object 参考
→ NavSea Standard Layer
→ 人工确认

关键规则:

  1. Style Visual Object Tool 仍然不知道 NavSea Layer、CM95 语义或 Provider 私有分类,继续保持 Provider-neutral。
  2. Provider Layer Classifier 可以使用 Provider 自己的官方语义资料。CM95 当前使用 S-52 metadata 的官方英文 description,再提供中文显示译名。
  3. Provider 的 source-layer 仍不得作为分类依据,只保留 provenance/audit。
  4. Standard Visual Object 一一对应不是最终目标,也不是 Layer 命名的强制前提。
  5. 没有对应 NavSea 图标,但 Provider 语义足以确定 Layer 时,允许直接 LAYER_ONLY。
  6. 当前图形只是顶标、灯光、主体、pattern 等组件时使用 COMPONENT,不单独分配最终 Layer。
  7. 只有连 Layer 都无法可靠判断时才使用 UNKNOWN。

CM95 语义 Layer 规则

当前 CM95 分类规则独立保存:

tools/style-visual-object/cm95_semantic_layer_rules_v1.json

规则使用 S-52 官方 description 和资源类型进行声明式分类,例如:

tower, black/white, full-chart and simplified
→ 对象大类:陆上塔状构筑物
→ onshore_structure_point

beacon tower, red, full-chart
→ 对象大类:航标塔体
→ navigation_marks

topmark for buoys ...
→ COMPONENT / topmark

这些规则属于 Provider Layer Classifier,不得回写进通用 Style Visual Object extraction。

Reviewer 中间区域

Reviewer 中间主要区域现在显示 NavSea Layer 建议,综合参考:

  • S-52 官方语义;
  • 实际视觉相似度;
  • 已有 reviewed visual suggestion。

语义证据优先于“长得像”。例如普通 tower 即使视觉上很像 beacon,也应优先按 S-52 的 tower 语义归到 onshore_structure_point。

Standard Visual Object 图标被降为折叠的辅助参考区,不再作为主要任务。


Git 冻结基线与固定校验命令

CM95 v1 人工分类完成后,以下内容属于应进入 Git 的冻结基线:

  • 工具实现:style_vo_tool.py、visual_anchor_matcher.py、build_reference_names.py、apply_reviewed_layer_assignment.py;
  • Provider 分类规则:cm95_semantic_layer_rules_v1.json;
  • 人工 Reviewer:reviewer/;
  • 固定校验逻辑:validate_cm95_classification.py;
  • NavSea Frozen Standard Catalog 与 CM95 Anonymous Catalog;
  • S-52 中文名称 enrichment、视觉辅助结果;
  • 150 项人工确认;
  • 最终 occurrence 级 Layer Assignment;
  • 固定校验报告和最终中文报告。

固定校验命令:

python3 tools/style-visual-object/validate_cm95_classification.py

提交前必须满足:

RESULT: PASS

WARN 允许存在,但只能表示“人工结果与后续语义建议不同,需要时复核”;不得自动覆盖人工结果。

当前权威结果路径:

tools/style-visual-object/output/cm95-manual-review/manual-review-v1.json
tools/style-visual-object/output/cm95-manual-review/reviewed-anchors-manual-v1.json
tools/style-visual-object/output/cm95-manual-review/assignment/cm95-layer-assignment-v1.json
tools/style-visual-object/output/cm95-manual-review/validation-report-v1.json

当前最终报告:

tools/style-visual-object/output/CM95_Visual_Object_Layer命名报告_v2.md