chore(task): archive 08-03-extract-building-module
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
{"file": ".trellis/spec/blender/testing.md", "reason": "Defines pure test command and bpy-layer parity expectations for validation."}
|
||||
{"file": ".trellis/spec/guides/artifact-parity-guide.md", "reason": "Defines compare contract and expected no-diff result for refactors."}
|
||||
{"file": ".trellis/spec/blender/module-structure.md", "reason": "Defines dependency direction and safe import boundaries to review after new module creation."}
|
||||
@@ -0,0 +1,68 @@
|
||||
# Design
|
||||
|
||||
## Architecture
|
||||
|
||||
`building.py` will join the bpy-layer feature modules under
|
||||
`blender/osmassets/`. It may import `MeshBatch`, `add_roof`,
|
||||
`add_wall_panel`, and `make_prism` from `osmassets.mesh`, plus
|
||||
`parse_height` from `osmassets.osm`.
|
||||
|
||||
The module will expose:
|
||||
|
||||
```python
|
||||
def assemble(ring, way_id, tag, office_overrides, collection, materials):
|
||||
...
|
||||
```
|
||||
|
||||
The function returns:
|
||||
|
||||
```python
|
||||
(added, industrial_added, ring_pts)
|
||||
```
|
||||
|
||||
This keeps `generate_scene.py`'s count and focus-point handling unchanged while
|
||||
removing building geometry construction from the entry script.
|
||||
|
||||
## Boundaries
|
||||
|
||||
- `generate_scene.py` keeps CLI parsing, OSM way dispatch, material creation,
|
||||
count accumulation, focus-point accumulation, scene custom properties, and
|
||||
stdout markers.
|
||||
- `building.py` owns only building object creation and building-specific facade
|
||||
details for a ring that has already been projected.
|
||||
- `building.py` is a bpy-layer module. It must not be imported by pure Python
|
||||
modules or pure unit tests.
|
||||
- `catalog.py` remains the material declaration source; no material entries or
|
||||
order change in this task.
|
||||
|
||||
## Data Flow
|
||||
|
||||
1. `generate_scene.py` parses `args["office_overrides"]` into a set.
|
||||
2. `generate_scene.py` creates `building_mats` from `catalog.MATERIALS`.
|
||||
3. OSM ways are projected to local-meter rings in `generate_scene.py`.
|
||||
4. For ways with a `building` tag and at least three ring points,
|
||||
`building.assemble(ring, str(way["id"]), tag, args["office_overrides"],
|
||||
buildings_c, building_mats)` creates the prism, roof, windows, custom
|
||||
properties, and bevel.
|
||||
5. `generate_scene.py` updates `counts["building_count"]`,
|
||||
`counts["industrial_count"]`, and `focus_points` from the return tuple.
|
||||
|
||||
## Compatibility
|
||||
|
||||
The move must preserve object names, mesh names, material assignments, bevel
|
||||
modifier fields, custom properties, window-band geometry, and return values.
|
||||
Cesium export consumes the resulting `.blend`, so parity should see no
|
||||
non-ignored contract difference.
|
||||
|
||||
## Trade-Offs
|
||||
|
||||
The `office_overrides` set is passed into `building.assemble()` rather than
|
||||
passing the whole `args` dict. This narrows the module contract while preserving
|
||||
behavior. A full feature registry remains deferred until building and roads are
|
||||
both isolated enough to compare safely.
|
||||
|
||||
## Rollback
|
||||
|
||||
Rollback is mechanical: move `assemble()` and its helper back into
|
||||
`generate_scene.py`, restore direct calls, remove the `building.py` import, and
|
||||
delete the module.
|
||||
@@ -0,0 +1,3 @@
|
||||
{"file": ".trellis/spec/blender/module-structure.md", "reason": "Defines bpy-layer module boundaries and feature module responsibilities for moving building assembly."}
|
||||
{"file": ".trellis/spec/blender/asset-generation.md", "reason": "Defines MeshBatch, material order, deterministic generation, and Cesium material constraints relevant to building assembly."}
|
||||
{"file": ".trellis/spec/guides/artifact-parity-guide.md", "reason": "Defines mandatory before/after parity validation for pure Blender scene refactors."}
|
||||
@@ -0,0 +1,47 @@
|
||||
# Implementation Plan
|
||||
|
||||
## Checklist
|
||||
|
||||
1. Capture a parity baseline before product-code edits.
|
||||
2. Add `blender/osmassets/building.py` with the current building assembly and
|
||||
detail helper logic.
|
||||
3. Import `building.py` in `blender/generate_scene.py`.
|
||||
4. Remove inline `_assemble_building()` and `add_building_details()` from
|
||||
`generate_scene.py`.
|
||||
5. Replace the building call site with `building.assemble(...)`, passing
|
||||
`args["office_overrides"]` instead of the full `args` dict.
|
||||
6. Run Python validation:
|
||||
- `python3 -m py_compile blender/osmassets/building.py`
|
||||
- `python3 -m py_compile blender/generate_scene.py`
|
||||
- `python3 -m unittest blender/tests/test_pure.py`
|
||||
7. Capture parity after the refactor.
|
||||
8. Compare before/after parity snapshots and inspect any non-ignored diff.
|
||||
9. Update `.trellis/spec` and `docs/changelog.md` only for durable status or
|
||||
convention changes discovered during implementation.
|
||||
10. Commit, archive the task, and record the journal entry.
|
||||
|
||||
## Validation Commands
|
||||
|
||||
```bash
|
||||
node scripts/parity.js capture building-module-before --stages blender,cesium
|
||||
python3 -m py_compile blender/osmassets/building.py
|
||||
python3 -m py_compile blender/generate_scene.py
|
||||
python3 -m unittest blender/tests/test_pure.py
|
||||
node scripts/parity.js capture building-module-after --stages blender,cesium
|
||||
node scripts/parity.js compare building-module-before building-module-after
|
||||
```
|
||||
|
||||
## Risk Points
|
||||
|
||||
- Passing `office_overrides` instead of `args` changes the function contract;
|
||||
verify `office_override` custom properties and industrial classification via
|
||||
parity.
|
||||
- `Building_<way_id>_Windows` mesh construction depends on `MeshBatch` object
|
||||
naming and `add_wall_panel()` geometry; copy it mechanically.
|
||||
- `make_prism()` can return `None` on degenerate input, but the current call
|
||||
site filters `len(ring) >= 3`. Preserve the existing behavior and return
|
||||
tuple shape.
|
||||
- Do not reorder building material creation or catalog entries; material order
|
||||
affects GLB material indices.
|
||||
- Parity is mandatory because this is a pure refactor of bpy-layer scene
|
||||
generation.
|
||||
@@ -0,0 +1,93 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"id": "extract-building-module",
|
||||
"name": "extract-building-module",
|
||||
"title": "Extract building module",
|
||||
"description": "Move building assembly out of blender/generate_scene.py into a dedicated bpy-layer module without changing generated artifacts.",
|
||||
"status": "completed",
|
||||
"dev_type": null,
|
||||
"scope": null,
|
||||
"package": null,
|
||||
"priority": "P2",
|
||||
"creator": "dingkang",
|
||||
"assignee": "dingkang",
|
||||
"createdAt": "2026-08-03",
|
||||
"completedAt": "2026-08-03",
|
||||
"branch": null,
|
||||
"base_branch": "main",
|
||||
"worktree_path": null,
|
||||
"commit": null,
|
||||
"pr_url": null,
|
||||
"subtasks": [],
|
||||
"children": [],
|
||||
"parent": null,
|
||||
"relatedFiles": [],
|
||||
"notes": "",
|
||||
"meta": {}
|
||||
}
|
||||
Reference in New Issue
Block a user