Files
osmWorkflow/.trellis/tasks/archive/2026-08/08-03-extract-road-module/design.md

2.8 KiB

Design

Architecture

roads.py will join the bpy-layer feature modules under blender/osmassets/. It may import os, json, MeshBatch, add_polyline, and geometry helpers required by current road assembly:

from osmassets.geom import clip_polygon, feature_in_bounds, geometry_rings
from osmassets.mesh import MeshBatch, add_polyline

The module will expose two functions:

def assemble_geojson_layer(path, layer_id, projector, collection, material, z):
    ...

def assemble_osm_fallback(ways, projector, collection, material):
    ...

assemble_geojson_layer() returns the same count as the current add_geojson_layer(). assemble_osm_fallback() returns no count because the current fallback also leaves road_counts unchanged.

Boundaries

  • generate_scene.py keeps catalog ownership: road_mats, ROAD_LAYERS iteration, check_layers() warnings, road_counts, scene metadata, and stdout markers.
  • roads.py owns only object/mesh construction for already chosen road inputs.
  • catalog.py and scripts/lib/scene-layers.js remain untouched; road layer collection/order is not part of this task.
  • No new pure-Python logic is introduced. Existing geometry helpers are reused.

Data Flow

  1. generate_scene.py creates road_mats from catalog.ROAD_LAYERS and catalog.road_material_specs().
  2. If geojson_dir exists, generate_scene.py runs catalog.check_layers() and prints warnings exactly as before.
  3. For each catalog.ROAD_LAYERS entry, generate_scene.py calls roads.assemble_geojson_layer(...) and stores the returned count under the layer id in road_counts.
  4. If road_counts.get("road_surface", 0) == 0, generate_scene.py calls roads.assemble_osm_fallback(...) with OSM ways and the road surface material.
  5. generate_scene.py writes road_counts into scene metadata and SCENE_DONE.

Compatibility

The move must preserve road object names, mesh names, geometry clipping, feature counting, layer iteration order, warning behavior, fallback trigger, fallback widths, z values, material assignments, and metadata JSON. Cesium export consumes the resulting .blend, so parity should see no non-ignored contract difference.

Trade-Offs

catalog.check_layers() intentionally stays in generate_scene.py. Moving it into roads.py would mix cross-language catalog validation with object assembly and increase the blast radius of this refactor.

The full feature registry remains deferred. Roads are the last high-risk assembly extraction; registry design should be evaluated after this commit when the remaining generate_scene.py responsibilities are clearer.

Rollback

Rollback is mechanical: move assemble_geojson_layer() and assemble_osm_fallback() logic back into generate_scene.py, restore the direct call sites, remove the roads.py import, and delete the module.