Fix OSM multipolygon buildings

This commit is contained in:
2026-08-03 18:15:22 +08:00
parent 37fe65b7ca
commit 95f8458ad2
11 changed files with 458 additions and 18 deletions

View File

@@ -46,7 +46,7 @@
| 模块 | 层 | 职责 |
|---|---|---|
| `osm.py` | 纯 | `parse_osm()` 读 OSM XML → (bounds, ways, points)`Projector` 局部米制投影;`parse_height()``tags()` |
| `osm.py` | 纯 | `parse_osm()` 读 OSM XML → (bounds, ways, points)building multipolygon relation 会作为 synthetic way 进入 ways`Projector` 局部米制投影;`parse_height()``tags()` |
| `geom.py` | 纯 | 平面几何全家桶。**输入输出一律是投影后的米**,例外只有 `geometry_rings` / `feature_in_bounds`(收原始 GeoJSON 的经纬度) |
| `catalog.py` | 纯 | `ROAD_LAYERS``MATERIALS``road_material_specs()``check_layers()` |
| `mesh.py` | bpy | `MeshBatch``make_prism``add_roof``add_wall_panel``add_polyline`、集合管理 |
@@ -104,7 +104,8 @@ def assemble(name, x, y, collection, materials):
`len(ring) >= 3`,并且建筑要保持原始 OSM footprint 参与相机取景:
```python
def assemble(ring, way_id, tag, office_overrides, collection, materials):
def assemble(ring, way_id, tag, office_overrides, collection, materials,
inner_rings=None):
...
return added, industrial_added, ring_pts
```
@@ -114,6 +115,36 @@ def assemble(ring, way_id, tag, office_overrides, collection, materials):
`counts["industrial_count"]`,以及写 `scene["office_override_way_ids"]`
模块只负责 prism / roof / windows / bevel / building custom properties。
### Building multipolygon 与 height
`parse_osm()` 会把 `type=multipolygon` 且 relation 自身带 `building=*` 的 relation
追加为 synthetic way
```python
{
"id": relation_id,
"coords": outer_ring_lon_lat,
"inner_coords": [inner_ring_lon_lat, ...],
"tags": relation_tags,
"source": "relation",
}
```
member way 不需要带 building tagsrelation-level `height` / `building` 才是事实源。
`generate_scene.py``handle_building()` 里把 `inner_coords` 投影后传给
`building.assemble(..., inner_rings=...)``building.py` 用 Blender
`tessellate_polygon()` 生成带洞的 prism 和 roof没有 inner rings 时仍走原来的
`MeshBatch` / `make_prism` 路径。
建筑高度语义:
- relation / way 上有合法显式 `height``render_height == height`
- `building=industrial`:沿用 OSM height / 默认高度
- 普通 building 没有显式 height 且低于 tall threshold使用办公楼视觉默认 `11.4m`
不要再把有显式 `height=8` 的普通建筑压成 `11.4m`;用户手工编辑 OSM 高度时OSM
tag 是更高优先级的事实。
`roads.py` 是 road layer 装配模块,不拥有图层表或计数:
```python