Files
osmWorkflow/.trellis/tasks/archive/2026-08/08-03-extract-building-module/prd.md

94 lines
4.0 KiB
Markdown

# Extract building module
## Goal
Move building assembly out of `blender/generate_scene.py` into a dedicated
bpy-layer module, keeping generated `.blend` / `.glb` / metadata structure
unchanged. This continues the documented P2 feature-module direction after
`fountain.py`.
## Background
- `.trellis/spec/guides/artifact-parity-guide.md` records P2 as partial:
`water.py`, `grass.py`, `scrub.py`, `tree.py`, and `fountain.py` are already
split out, while `building` and `roads` still live in `generate_scene.py`.
- `blender/generate_scene.py:72` defines `_assemble_building()`.
- `blender/generate_scene.py:179` defines `add_building_details()`, which
creates office / industrial window bands with `MeshBatch` and
`add_wall_panel()`.
- `blender/generate_scene.py:789` dispatches OSM ways with a `building` tag,
increments `counts["building_count"]` and `counts["industrial_count"]`, and
extends `focus_points` with the returned ring.
- `blender/generate_scene.py:710` creates `building_mats` from the existing
`catalog.MATERIALS["building_" + key]` entries.
- `blender/generate_scene.py:910` persists `office_override_way_ids` as a scene
custom property from `args["office_overrides"]`.
## Requirements
1. Add a new bpy-layer module at `blender/osmassets/building.py`.
2. Move the current building assembly behavior into the new module:
- `_assemble_building()`
- `add_building_details()`
3. Expose an `assemble(...)` function from the new module that returns the same
tuple shape currently returned by `_assemble_building()`:
`(added, industrial_added, ring_pts)`.
4. Keep `generate_scene.py` responsible for:
- parsing `--office-overrides`;
- creating `building_mats`;
- filtering OSM ways with a `building` tag and `len(ring) >= 3`;
- updating `building_count`, `industrial_count`, and `focus_points`;
- writing `scene["office_override_way_ids"]`;
- writing the existing `SCENE_DONE` JSON shape.
5. Preserve existing building object names and mesh names:
- `Building_<way_id>`
- `Building_<way_id>_Roof`
- `Building_<way_id>_Windows`
6. Preserve existing building custom properties:
- `osm_height`
- `render_height`
- `building_kind`
- `osm_building_tag`
- `office_override`
7. Preserve current height rules:
- industrial buildings use the parsed source height;
- non-industrial buildings under 30m render at 11.4m;
- source height has a 3.0m floor and `parse_height(tag, 12.0)` default.
8. Preserve current facade behavior:
- industrial buildings use one high horizontal band;
- office buildings use floor-based window bands;
- bevel modifier name, width, and segment count stay unchanged.
9. Do not introduce a full `features/` registry in this task.
10. Do not modify roads, material definitions, `MATERIALS` order,
`ROAD_LAYERS` order, stdout markers, parity ignore lists, or known
unrelated defects D1-D3.
## Acceptance Criteria
- [x] `blender/osmassets/building.py` contains building assembly behavior and
imports only bpy-layer-safe dependencies.
- [x] `blender/generate_scene.py` imports and calls the new building module; no
inline `_assemble_building()` or `add_building_details()` remains there.
- [x] Building counts, industrial counts, focus point behavior, scene custom
properties, and `SCENE_DONE` JSON keys remain unchanged.
- [x] `python3 -m py_compile blender/osmassets/building.py` passes.
- [x] `python3 -m py_compile blender/generate_scene.py` passes.
- [x] `python3 -m unittest blender/tests/test_pure.py` passes.
- [x] A before/after parity comparison is run for the Blender/Cesium stages and
any non-ignored diff is either absent or explicitly explained as
expected. For this refactor, the expected result is no contract diff.
## Out Of Scope
- Full feature registry implementation.
- Road extraction.
- Building visual redesign.
- Building material or Cesium export contract changes.
- Moving CLI parsing or `office_override_way_ids` scene metadata out of
`generate_scene.py`.
- Changing geometry helper APIs in `osmassets.mesh`.
## Open Questions
None.