Initialize Trellis project guidelines
This commit is contained in:
164
.trellis/spec/pipeline/layer-registry.md
Normal file
164
.trellis/spec/pipeline/layer-registry.md
Normal file
@@ -0,0 +1,164 @@
|
||||
# 图层表:跨语言的单一事实源
|
||||
|
||||
> 适用:改动 osm2streets 九个渲染图层的任何一方——新增图层、删图层、调顺序、调
|
||||
> 颜色、调高度。**动手前必读**,这里的错误不会报错,只会让产物静默错栈。
|
||||
|
||||
---
|
||||
|
||||
## 一句话
|
||||
|
||||
九个图层在 **JS 和 Python 各存一份表**,两份**故意只同步"集合与顺序"、不同步颜色**,
|
||||
一致性靠运行时的 `catalog.check_layers()` 用产物文件对账。
|
||||
|
||||
---
|
||||
|
||||
## 两份表分别管什么
|
||||
|
||||
| | JS 侧 | Python 侧 |
|
||||
|---|---|---|
|
||||
| 位置 | `scripts/lib/scene-layers.js:15` `SCENE_LAYERS` | `blender/osmassets/catalog.py:28` `ROAD_LAYERS` |
|
||||
| 服务于 | 2D 调试链路:GeoJSON 拆分、GeoPackage 导入、QGIS 工程符号 | 3D 场景链路:Blender 材质与几何高度 |
|
||||
| 关键字段 | `id`、`splitKey`、`zIndex`、`title`、`fill`/`outline`(sRGB hex) | `id`、`material`、`color`(线性 RGB)、`z`(米) |
|
||||
| 消费点 | `build-osm2streets-qgis.js:91,98,109,1315`、`reimport-gpkg.js:53,63,77` | `generate_scene.py:759,844` |
|
||||
|
||||
`id` 是两侧唯一的连接键,同时也是 GeoJSON 文件名的 stem(`layerFile()` 拼
|
||||
`<id>.geojson`,见 `scene-layers.js:103`)。
|
||||
|
||||
## 这份表从前复制了四遍
|
||||
|
||||
`scene-layers.js:3-13` 的注释写明了它存在的理由:同一批图层的顺序曾同时躺在
|
||||
merged-scene 的 z_index 表、场景样式 JSON、生成的 QGIS 工程、以及 README 的手工重建
|
||||
片段里。加一个图层要同步改四处,漏一处**不报错**,只是下游 Blender/Cesium 里的场景
|
||||
悄悄错栈。
|
||||
|
||||
`catalog.py:3-7` 记录的是 Python 侧的同一个病:九个图层的绘制顺序在 JS、Blender 高度
|
||||
在一个 `layer_z` dict、颜色在一个 `road_mats` dict——两种语言三份拷贝,手工对齐。
|
||||
|
||||
**推论**:看到任何地方开始第二次枚举这九个图层,那就是 bug 的温床,改成从这两份表
|
||||
之一派生。
|
||||
|
||||
## 为什么颜色刻意不同步
|
||||
|
||||
`catalog.py:11-15` 明确列为"deliberate non-goal":
|
||||
|
||||
- `scene-layers.js` 的 `fill` 是给 **QGIS 2D 调试地图**用的 sRGB hex
|
||||
- `catalog.py` 的 `color` 是给 **Blender 3D 场景**用的线性 RGB
|
||||
- 两套值是**分别调出来的**,不存在换算关系
|
||||
|
||||
所以 `check_layers()` 只校验图层的**集合与顺序**——那是必须一致的部分——**不碰调色板**。
|
||||
|
||||
> 不要"顺手统一"两边的颜色。那不是清理重复,是把两个独立的设计意图合并成一个错的。
|
||||
|
||||
## 对账机制
|
||||
|
||||
桥梁是产物文件 `osm2streets_scene_style.json`(两侧常量都叫 `SCENE_STYLE_FILE`,
|
||||
见 `scene-layers.js:101` 与 `catalog.py:49`):
|
||||
|
||||
```
|
||||
JS 侧 sceneStyle() ──写──▶ osm2streets_scene_style.json ──读──▶ catalog.check_layers()
|
||||
scene-layers.js:126 (落在 geojson 输出目录) catalog.py:162
|
||||
```
|
||||
|
||||
写入点:`build-osm2streets-qgis.js:100`(intermediates 阶段)、
|
||||
`reimport-gpkg.js:79`(reimport 阶段)。
|
||||
读取点:`generate_scene.py:842`,每次构建场景时执行。
|
||||
|
||||
`check_layers()` 报三类问题(`catalog.py:183-194`):
|
||||
|
||||
1. style 里有、`ROAD_LAYERS` 里没有 → 该图层**到不了 3D 场景**
|
||||
2. `ROAD_LAYERS` 里有、style 里没有 → **不会有 GeoJSON 产出**给它
|
||||
3. 集合相同但顺序不同 → 打印两侧的实际顺序
|
||||
|
||||
**这是 warn 不是 fail**(`catalog.py:168-169` 写明理由):过期或缺失的输出目录不该
|
||||
阻断一次重建。所以——
|
||||
|
||||
> 构建日志里的 `Layer catalog warning:` 不是噪音。它是这套双表设计**唯一**的自动
|
||||
> 报警,被忽略就等于没有。
|
||||
|
||||
## 顺序是承重的
|
||||
|
||||
`catalog.py:16-18`:
|
||||
|
||||
- **材质创建顺序固定了导出 GLB 里的材质索引**
|
||||
- 图层顺序固定了 mesh 创建顺序
|
||||
|
||||
所以 `ROAD_LAYERS` 和 `MATERIALS` 是 **list 不是 dict**,**追加是唯一安全的编辑**。
|
||||
在中间插入一个图层会平移其后所有材质索引——GLB 结构变了,parity 校验会红,
|
||||
Cesium 侧引用的材质会错位。
|
||||
|
||||
JS 侧的 `zIndex` 同样兼作绘制顺序(`scene-layers.js:12`),**最小值先画、位于栈底**。
|
||||
它同时是写进每个 feature 的 `z_index` 属性(`mergeScene()`,`scene-layers.js:117-119`)。
|
||||
|
||||
## 派生函数:只加派生,不要加第二份枚举
|
||||
|
||||
`scene-layers.js` 导出的四个派生函数是这份表的全部合法用法:
|
||||
|
||||
| 函数 | 位置 | 用途 |
|
||||
|---|---|---|
|
||||
| `layerFile(layer)` | `:103` | `<id>.geojson` 文件名 |
|
||||
| `mergeScene(getCollection)` | `:109` | 合成 `osm2streets_scene.geojson`,逐 feature 打上 `render_layer` / `z_index` |
|
||||
| `sceneStyle()` | `:126` | 生成对账用的 style JSON |
|
||||
| `qgisRgba(hex, alpha)` | `:143` | hex → QGIS 要的 `"r,g,b,a"` 字符串 |
|
||||
|
||||
`mergeScene` 收的是**回调**而不是数组,这样 build 阶段(从内存的 split 取)和
|
||||
reimport 阶段(从磁盘读回)能共用同一套合并逻辑(`scene-layers.js:107-108`)。
|
||||
新增第三种数据来源时沿用这个模式,不要复制合并循环。
|
||||
|
||||
`outline: null` 表示无描边,QGIS 侧由 `qgisRgba` 转成全透明(`scene-layers.js:13-14,145`)。
|
||||
|
||||
Python 侧同理:`road_material_specs()`(`catalog.py:156`)把 `ROAD_LAYERS` 转成
|
||||
`MATERIALS` 形状的规格,`generate_scene.py:759` 用 `zip` 与图层配对——保持这条派生链,
|
||||
不要在 `generate_scene.py` 里另起一份材质名列表。
|
||||
|
||||
---
|
||||
|
||||
## 改动清单
|
||||
|
||||
### 新增一个图层
|
||||
|
||||
1. `scene-layers.js:SCENE_LAYERS` **末尾追加**:`id`、`splitKey`、`zIndex`(大于现有
|
||||
最大值)、`title`、`fill`、`outline`、`outlineWidth`
|
||||
2. 确认 osm2streets 的拆分结果里确实有 `splitKey` 对应的键
|
||||
(`build-osm2streets-qgis.js:92` 取 `split[layer.splitKey]`)
|
||||
3. `catalog.py:ROAD_LAYERS` **末尾追加**:`id`(与第 1 步一致)、`material`(新名字)、
|
||||
`color`(线性 RGB,独立调)、`z`(米,高于前一层避免 z-fighting)
|
||||
4. 跑一次 `intermediates` + `blender`,确认日志里**没有** `Layer catalog warning:`
|
||||
5. 该图层的 GeoPackage 导入、QGIS 符号、场景合并、reimport 全部自动跟上,**无需**再
|
||||
改 `reimport-gpkg.js` 或 QGIS 工程生成代码
|
||||
|
||||
### 删除一个图层
|
||||
|
||||
两侧同时删。只删一侧的话 `check_layers()` 会 warn,但构建**照常出产物**——一份少了
|
||||
该图层的产物。
|
||||
|
||||
### 调整顺序
|
||||
|
||||
改 `zIndex` 的同时必须把 `ROAD_LAYERS` 的**元素位置**也调成一致。注意这会移动材质
|
||||
索引,属于会改变产物的变更,**必须跑 parity 校验**,见
|
||||
[产物一致性指南](../guides/artifact-parity-guide.md)。
|
||||
|
||||
### 只调颜色
|
||||
|
||||
改一侧即可,不要同步到另一侧(见上文"为什么颜色刻意不同步")。
|
||||
|
||||
---
|
||||
|
||||
## 反模式
|
||||
|
||||
| 反模式 | 后果 |
|
||||
|---|---|
|
||||
| 在 `generate_scene.py` / QGIS 生成代码里硬编码图层名列表 | 回到"复制四份"的旧病 |
|
||||
| 从 `scene-layers.js` 的 `fill` 换算 Blender 的 `color` | 抹掉两套独立调过的配色 |
|
||||
| 在 `ROAD_LAYERS` / `MATERIALS` **中间**插入条目 | GLB 材质索引整体平移 |
|
||||
| 把 `ROAD_LAYERS` / `MATERIALS` 改成 dict | 顺序语义丢失,见 `catalog.py:16-18` |
|
||||
| 把 `check_layers()` 从 warn 改成 raise | 输出目录过期就无法重建 |
|
||||
| 忽略 `Layer catalog warning:` | 双表设计唯一的报警失效 |
|
||||
|
||||
---
|
||||
|
||||
## 相关
|
||||
|
||||
- [外部工具调用](./external-tools.md):图层如何进出 GeoPackage
|
||||
- [CLI 与阶段](./cli-and-stages.md):哪个阶段写、哪个阶段读这些文件
|
||||
- [Blender 资产生成](../blender/asset-generation.md):`MATERIALS` 的其余部分
|
||||
- [产物一致性指南](../guides/artifact-parity-guide.md):改动顺序后如何验证
|
||||
Reference in New Issue
Block a user