feat(simulation): quarter footprint subdivision + block-tag assembly (#957)

Build the per-quarter building geometry + tags (absorbs #976's footprint
subdivision into #957 — one coherent walkable-quarter deliverable):

- subdivide_block_footprints: deterministic BSP of each 128x128-tile block into
  variable axis-aligned building plots (D-229 fast-path). Lot size + setback
  scale with D-220 density (Frontier -> few big lots/wide gaps; Compressed ->
  many small lots/shared walls); the D-233 BulkClass roofed-coverage fraction
  decides building-vs-interstitial. morphology is wired in for the D-234
  waterfront/street layer (needs Layer-1 terrain water-adjacency threaded up).
- assign_all_block_tags: subdivides + tags every non-reserved block's footprints
  via the #957 derivation helpers, populating QuarterWorldState.block_tags in the
  GenerateSkeleton plan-phase (D-230). Reserved blocks get no standard fill.
- Remove the write-only BlockSkeleton.era String stub - construction era now
  lives per-footprint on BuildingPropertyTag.era (typed ConstructionEra).

All integer-deterministic (D-010). 5 new tests. Doors stay Vec::new() (#979).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-05 23:08:19 +02:00
co-authored by Claude Opus 4.8
parent aaa94152d0
commit 728a27e1b4
3 changed files with 323 additions and 8 deletions
+11 -2
View File
@@ -31,7 +31,7 @@ use crate::atlas::attractor_matching::CityRecord;
use crate::atlas::body_world_state::BodyWorldState;
use crate::atlas::cascade::{run_cascade_from_heightmap, CascadeLayer};
use crate::atlas::heightmap::{load_heightmap_png, GRID_H, GRID_W};
use crate::atlas::skeleton_gen::generate_quarter_skeleton;
use crate::atlas::skeleton_gen::{assign_all_block_tags, generate_quarter_skeleton};
use crate::seed::SeedChain;
use crate::simulation::generator::{CityGenerationContext, QuarterWorldState};
@@ -410,12 +410,21 @@ fn run_work_item(item: &GenWorkItem) -> GenCompletion {
*founding_age_years,
*chain,
);
// Step-3 building-property tags per footprint (D-229, #957): subdivide
// each block into building plots and tag them.
let block_tags = assign_all_block_tags(
&skeleton,
context,
economic_role,
*founding_age_years,
*chain,
);
GenCompletion::SkeletonGenerated {
city_id: *city_id,
body_id: body_id.clone(),
state: Box::new(QuarterWorldState {
skeleton,
block_tags: std::collections::BTreeMap::new(),
block_tags,
}),
}
}