fix(simulation): lake_margin_q normalizes per basin — full-range depth gradient (T-1188)
The PR #206 eyeball caught what every numeric gate passed: the depth signal was visually flat on both test lakes (GJ1c lmq=0 across the whole basin; GJ338Bd 0-13 of 100). Two compounding causes: a fixed absolute ceiling (one body's p90 cell depth) compressing skewed depth distributions into single digits, and heightmap-pitch depth variation being sub-texel-tiny within most basins. lake_margin_q is now depth / the basin's own maximum settled depth: HydrologyResult grows basin_max_depth_scaled (computed in solve() from existing basin_cells membership, broadcast per basin), threaded through HydrologySample.basin_max_depth, normalized in lake_from_hydrology_at with a degenerate-basin epsilon guard (a genuinely uniform pond shades flat — honest, not forced). Lake EXISTENCE (filled > original) is untouched — only tone changes. Measured at district spacing: GJ1c min=0 p50=33 max=84; GJ338Bd min=8 p50=38 max=70 — full-range shore-to-deep ramps on both. No perceptual curve added: the linear per-basin ramp is already well-quartiled. project.yaml 0.4.1 -> 0.4.2 (0.4.1-tagged canvases carrying flat-lmq semantics reached real disk caches during eyeball runs and must miss). Acceptance gates green; zero golden churn (lake_margin_q not captured by either golden shape). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -134,6 +134,14 @@ pub struct HydrologySample {
|
||||
/// water-surface height at every working-grid cell (equal to
|
||||
/// `elevation` wherever no lake exists).
|
||||
pub filled: Vec<f32>,
|
||||
/// `HydrologyResult.basin_max_depth_scaled`, rescaled back to `[0.0,
|
||||
/// 1.0]` fraction units (T-1188): the MAXIMUM settled depth anywhere in
|
||||
/// this cell's basin, broadcast to every cell in that basin, `0.0` for
|
||||
/// non-lake cells. Used to normalize `lake_margin_q` per-basin instead
|
||||
/// of against a single fixed absolute ceiling — see
|
||||
/// `district_profile::lake_from_hydrology_at`'s doc for the full
|
||||
/// rationale (the PR #206 eyeball finding that motivated this field).
|
||||
pub basin_max_depth: Vec<f32>,
|
||||
}
|
||||
|
||||
const WATER_DIST_CAP: u16 = 255;
|
||||
@@ -215,9 +223,15 @@ impl TerrainAnalysis {
|
||||
.iter()
|
||||
.map(|&s| crate::atlas::hydrology_equilibrium::scaled_to_fraction(s))
|
||||
.collect();
|
||||
let basin_max_depth: Vec<f32> = result
|
||||
.basin_max_depth_scaled
|
||||
.iter()
|
||||
.map(|&s| crate::atlas::hydrology_equilibrium::scaled_to_fraction(s))
|
||||
.collect();
|
||||
self.hydrology = Some(HydrologySample {
|
||||
elevation: elevation.to_vec(),
|
||||
filled,
|
||||
basin_max_depth,
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user