style(simulation): gate bounce — box GenCompletion::BodyAnalyzed state; clippy/fmt sweeps
BodyWorldState grew past clippy's large-enum-variant threshold when it began retaining Layer1Output (T-1170 Ruling 4b) — boxed, with the two insert sites deref'd; manual_contains x2 (drainage tests), cloned_ref_to_slice_refs x3 (river_course tests), fmt wraps. gen_queue 18/18; clippy -D warnings clean; fmt --check clean. Tickets: T-1170 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -2158,8 +2158,15 @@ mod tests {
|
|||||||
basin_dirs.insert(pos_east, BasinDirection::East);
|
basin_dirs.insert(pos_east, BasinDirection::East);
|
||||||
basin_dirs.insert(pos_south, BasinDirection::South);
|
basin_dirs.insert(pos_south, BasinDirection::South);
|
||||||
|
|
||||||
let districts =
|
let districts = derive_all_districts(
|
||||||
derive_all_districts(test_seed(), ¶ms, &ta, 8, "test_body", Some(&basin_dirs), None);
|
test_seed(),
|
||||||
|
¶ms,
|
||||||
|
&ta,
|
||||||
|
8,
|
||||||
|
"test_body",
|
||||||
|
Some(&basin_dirs),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
assert_eq!(districts[&pos_east].basin_direction, BasinDirection::East);
|
assert_eq!(districts[&pos_east].basin_direction, BasinDirection::East);
|
||||||
assert_eq!(districts[&pos_south].basin_direction, BasinDirection::South);
|
assert_eq!(districts[&pos_south].basin_direction, BasinDirection::South);
|
||||||
@@ -2423,7 +2430,17 @@ mod tests {
|
|||||||
for i in 0..20 {
|
for i in 0..20 {
|
||||||
let wx = (100 + i * 37) as f64 * dm;
|
let wx = (100 + i * 37) as f64 * dm;
|
||||||
let wy = (100 + i * 53) as f64 * dm;
|
let wy = (100 + i * 53) as f64 * dm;
|
||||||
let uncut = derive_at_metres(test_seed(), "test_body", &p, &ta, wx, wy, &climate, 0.0, &[]);
|
let uncut = derive_at_metres(
|
||||||
|
test_seed(),
|
||||||
|
"test_body",
|
||||||
|
&p,
|
||||||
|
&ta,
|
||||||
|
wx,
|
||||||
|
wy,
|
||||||
|
&climate,
|
||||||
|
0.0,
|
||||||
|
&[],
|
||||||
|
);
|
||||||
let cut = derive_at_metres(
|
let cut = derive_at_metres(
|
||||||
test_seed(),
|
test_seed(),
|
||||||
"test_body",
|
"test_body",
|
||||||
@@ -2466,8 +2483,28 @@ mod tests {
|
|||||||
for i in 0..12 {
|
for i in 0..12 {
|
||||||
let wx = (300 + i * 41) as f64 * dm * 0.1;
|
let wx = (300 + i * 41) as f64 * dm * 0.1;
|
||||||
let wy = (300 + i * 29) as f64 * dm * 0.1;
|
let wy = (300 + i * 29) as f64 * dm * 0.1;
|
||||||
let a = derive_at_metres(test_seed(), "test_body", &p, &ta, wx, wy, &climate, 1_024.0, &[]);
|
let a = derive_at_metres(
|
||||||
let b = derive_at_metres(test_seed(), "test_body", &p, &ta, wx, wy, &climate, 1_024.0, &[]);
|
test_seed(),
|
||||||
|
"test_body",
|
||||||
|
&p,
|
||||||
|
&ta,
|
||||||
|
wx,
|
||||||
|
wy,
|
||||||
|
&climate,
|
||||||
|
1_024.0,
|
||||||
|
&[],
|
||||||
|
);
|
||||||
|
let b = derive_at_metres(
|
||||||
|
test_seed(),
|
||||||
|
"test_body",
|
||||||
|
&p,
|
||||||
|
&ta,
|
||||||
|
wx,
|
||||||
|
wy,
|
||||||
|
&climate,
|
||||||
|
1_024.0,
|
||||||
|
&[],
|
||||||
|
);
|
||||||
assert_district_profiles_eq(&a, &b);
|
assert_district_profiles_eq(&a, &b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2499,8 +2536,28 @@ mod tests {
|
|||||||
for i in 0..20 {
|
for i in 0..20 {
|
||||||
let wx = (150 + i * 47) as f64 * dm;
|
let wx = (150 + i * 47) as f64 * dm;
|
||||||
let wy = (150 + i * 31) as f64 * dm;
|
let wy = (150 + i * 31) as f64 * dm;
|
||||||
let a = derive_at_metres(test_seed(), "test_body", &p, &ta, wx, wy, &climate, 4_096.0, &[]);
|
let a = derive_at_metres(
|
||||||
let b = derive_at_metres(test_seed(), "test_body", &p, &ta, wx, wy, &climate, 4_096.0, &[]);
|
test_seed(),
|
||||||
|
"test_body",
|
||||||
|
&p,
|
||||||
|
&ta,
|
||||||
|
wx,
|
||||||
|
wy,
|
||||||
|
&climate,
|
||||||
|
4_096.0,
|
||||||
|
&[],
|
||||||
|
);
|
||||||
|
let b = derive_at_metres(
|
||||||
|
test_seed(),
|
||||||
|
"test_body",
|
||||||
|
&p,
|
||||||
|
&ta,
|
||||||
|
wx,
|
||||||
|
wy,
|
||||||
|
&climate,
|
||||||
|
4_096.0,
|
||||||
|
&[],
|
||||||
|
);
|
||||||
assert_district_profiles_eq(&a, &b);
|
assert_district_profiles_eq(&a, &b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2553,10 +2610,28 @@ mod tests {
|
|||||||
for i in 0..20 {
|
for i in 0..20 {
|
||||||
let wx = (150 + i * 47) as f64 * dm;
|
let wx = (150 + i * 47) as f64 * dm;
|
||||||
let wy = (150 + i * 31) as f64 * dm;
|
let wy = (150 + i * 31) as f64 * dm;
|
||||||
let district =
|
let district = derive_at_metres(
|
||||||
derive_at_metres(test_seed(), "test_body", &p, &ta, wx, wy, &climate, 4_096.0, &[]);
|
test_seed(),
|
||||||
let quarter =
|
"test_body",
|
||||||
derive_at_metres(test_seed(), "test_body", &p, &ta, wx, wy, &climate, 1_024.0, &[]);
|
&p,
|
||||||
|
&ta,
|
||||||
|
wx,
|
||||||
|
wy,
|
||||||
|
&climate,
|
||||||
|
4_096.0,
|
||||||
|
&[],
|
||||||
|
);
|
||||||
|
let quarter = derive_at_metres(
|
||||||
|
test_seed(),
|
||||||
|
"test_body",
|
||||||
|
&p,
|
||||||
|
&ta,
|
||||||
|
wx,
|
||||||
|
wy,
|
||||||
|
&climate,
|
||||||
|
1_024.0,
|
||||||
|
&[],
|
||||||
|
);
|
||||||
if district.elev_q != quarter.elev_q
|
if district.elev_q != quarter.elev_q
|
||||||
|| district.slope_q != quarter.slope_q
|
|| district.slope_q != quarter.slope_q
|
||||||
|| district.moisture_q != quarter.moisture_q
|
|| district.moisture_q != quarter.moisture_q
|
||||||
@@ -2669,8 +2744,17 @@ mod tests {
|
|||||||
for dx in -2..2 {
|
for dx in -2..2 {
|
||||||
let wx = base_wx + dx as f64 * qm;
|
let wx = base_wx + dx as f64 * qm;
|
||||||
let wy = base_wy + dy as f64 * qm;
|
let wy = base_wy + dy as f64 * qm;
|
||||||
let prof =
|
let prof = derive_at_metres(
|
||||||
derive_at_metres(test_seed(), "test_body", &p, &ta, wx, wy, &climate, 1_024.0, &[]);
|
test_seed(),
|
||||||
|
"test_body",
|
||||||
|
&p,
|
||||||
|
&ta,
|
||||||
|
wx,
|
||||||
|
wy,
|
||||||
|
&climate,
|
||||||
|
1_024.0,
|
||||||
|
&[],
|
||||||
|
);
|
||||||
if prof.vegetation_class != VegetationClass::Marine {
|
if prof.vegetation_class != VegetationClass::Marine {
|
||||||
*tally.entry(prof.vegetation_class as u8).or_insert(0) += 1;
|
*tally.entry(prof.vegetation_class as u8).or_insert(0) += 1;
|
||||||
}
|
}
|
||||||
@@ -2783,7 +2867,17 @@ mod tests {
|
|||||||
let wx = 40.0 * dm;
|
let wx = 40.0 * dm;
|
||||||
let wy = 20.0 * dm;
|
let wy = 20.0 * dm;
|
||||||
let orbital = derive_orbital_at_metres(test_seed(), "test_body", &p, &ta, wx, wy, &climate);
|
let orbital = derive_orbital_at_metres(test_seed(), "test_body", &p, &ta, wx, wy, &climate);
|
||||||
let full = derive_at_metres(test_seed(), "test_body", &p, &ta, wx, wy, &climate, 0.0, &[]);
|
let full = derive_at_metres(
|
||||||
|
test_seed(),
|
||||||
|
"test_body",
|
||||||
|
&p,
|
||||||
|
&ta,
|
||||||
|
wx,
|
||||||
|
wy,
|
||||||
|
&climate,
|
||||||
|
0.0,
|
||||||
|
&[],
|
||||||
|
);
|
||||||
|
|
||||||
// The invented scatter is a bounded perturbation on top of the raw
|
// The invented scatter is a bounded perturbation on top of the raw
|
||||||
// envelope (detail_scatter's amplitude is capped well under 100 elev_q
|
// envelope (detail_scatter's amplitude is capped well under 100 elev_q
|
||||||
|
|||||||
@@ -1129,8 +1129,7 @@ mod tests {
|
|||||||
let rn = &result.river_network;
|
let rn = &result.river_network;
|
||||||
assert!(!rn.mouths.is_empty(), "GJ1c should have real sea mouths");
|
assert!(!rn.mouths.is_empty(), "GJ1c should have real sea mouths");
|
||||||
|
|
||||||
let mouth_set: std::collections::BTreeSet<(u16, u16)> =
|
let mouth_set: std::collections::BTreeSet<(u16, u16)> = rn.mouths.iter().copied().collect();
|
||||||
rn.mouths.iter().copied().collect();
|
|
||||||
for (i, &pos) in rn.river_cells.iter().enumerate() {
|
for (i, &pos) in rn.river_cells.iter().enumerate() {
|
||||||
let is_mouth_sentinel = rn.river_downstream[i] == RIVER_DOWNSTREAM_MOUTH;
|
let is_mouth_sentinel = rn.river_downstream[i] == RIVER_DOWNSTREAM_MOUTH;
|
||||||
let is_in_mouths_list = mouth_set.contains(&pos);
|
let is_in_mouths_list = mouth_set.contains(&pos);
|
||||||
@@ -1195,9 +1194,7 @@ mod tests {
|
|||||||
empty river_cells silently no-ops every assertion below"
|
empty river_cells silently no-ops every assertion below"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
rn.river_downstream
|
rn.river_downstream.contains(&RIVER_DOWNSTREAM_EDGE_DRAIN),
|
||||||
.iter()
|
|
||||||
.any(|&v| v == RIVER_DOWNSTREAM_EDGE_DRAIN),
|
|
||||||
"expected at least one EDGE_DRAIN-sentinel river cell (the flat-plateau case) \
|
"expected at least one EDGE_DRAIN-sentinel river cell (the flat-plateau case) \
|
||||||
on this fixture — downstream values were {:?}",
|
on this fixture — downstream values were {:?}",
|
||||||
rn.river_downstream
|
rn.river_downstream
|
||||||
@@ -1208,9 +1205,7 @@ mod tests {
|
|||||||
rn.mouths
|
rn.mouths
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
!rn.river_downstream
|
!rn.river_downstream.contains(&RIVER_DOWNSTREAM_MOUTH),
|
||||||
.iter()
|
|
||||||
.any(|&v| v == RIVER_DOWNSTREAM_MOUTH),
|
|
||||||
"an all-land world must never emit a MOUTH sentinel"
|
"an all-land world must never emit a MOUTH sentinel"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -272,7 +272,10 @@ pub enum GenCompletion {
|
|||||||
BodyAnalyzed {
|
BodyAnalyzed {
|
||||||
body_id: String,
|
body_id: String,
|
||||||
/// The computed world state, ready for `BodyWorldStateCache::insert`.
|
/// The computed world state, ready for `BodyWorldStateCache::insert`.
|
||||||
state: BodyWorldState,
|
/// Boxed: `BodyWorldState` grew past clippy's large-enum-variant
|
||||||
|
/// threshold when it began retaining `Layer1Output` (T-1170 Ruling 4b)
|
||||||
|
/// — the box keeps the enum small while the state moves by pointer.
|
||||||
|
state: Box<BodyWorldState>,
|
||||||
},
|
},
|
||||||
SkeletonGenerated {
|
SkeletonGenerated {
|
||||||
city_id: u64,
|
city_id: u64,
|
||||||
@@ -726,7 +729,7 @@ fn run_work_item(
|
|||||||
);
|
);
|
||||||
GenCompletion::BodyAnalyzed {
|
GenCompletion::BodyAnalyzed {
|
||||||
body_id: body_id.clone(),
|
body_id: body_id.clone(),
|
||||||
state: snapshot.into_body_world_state(),
|
state: Box::new(snapshot.into_body_world_state()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => GenCompletion::Failed {
|
Err(e) => GenCompletion::Failed {
|
||||||
|
|||||||
@@ -15,9 +15,7 @@ use bevy_ecs::prelude::Resource;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::atlas::body_params_reader::BodyParamsReader;
|
use crate::atlas::body_params_reader::BodyParamsReader;
|
||||||
use crate::atlas::body_world_state::{
|
use crate::atlas::body_world_state::{BodyWorldState, BodyWorldStateCache, RiverNetwork, SimTick};
|
||||||
BodyWorldState, BodyWorldStateCache, RiverNetwork, SimTick,
|
|
||||||
};
|
|
||||||
use crate::atlas::cascade::CascadeLayer;
|
use crate::atlas::cascade::CascadeLayer;
|
||||||
use crate::atlas::city_context_reader::CityContextReader;
|
use crate::atlas::city_context_reader::CityContextReader;
|
||||||
use crate::atlas::district_profile::{BodyParams, DistrictPos};
|
use crate::atlas::district_profile::{BodyParams, DistrictPos};
|
||||||
@@ -1206,7 +1204,8 @@ fn invent_courses_near_window(
|
|||||||
ta.h,
|
ta.h,
|
||||||
params.body_radius_km,
|
params.body_radius_km,
|
||||||
);
|
);
|
||||||
let chord_m = ((anchor_a.0 - anchor_b.0).powi(2) + (anchor_a.1 - anchor_b.1).powi(2)).sqrt();
|
let chord_m =
|
||||||
|
((anchor_a.0 - anchor_b.0).powi(2) + (anchor_a.1 - anchor_b.1).powi(2)).sqrt();
|
||||||
let inflate_m = chord_m * COURSE_BBOX_INFLATION_FRACTION;
|
let inflate_m = chord_m * COURSE_BBOX_INFLATION_FRACTION;
|
||||||
let (bx0, bx1) = (
|
let (bx0, bx1) = (
|
||||||
anchor_a.0.min(anchor_b.0) - inflate_m,
|
anchor_a.0.min(anchor_b.0) - inflate_m,
|
||||||
@@ -1321,8 +1320,15 @@ fn crop_course_to_window(
|
|||||||
EdgeTerminusKind::EdgeDrain => CourseTerminus::EdgeDrain,
|
EdgeTerminusKind::EdgeDrain => CourseTerminus::EdgeDrain,
|
||||||
EdgeTerminusKind::Interior => CourseTerminus::ContinuesBeyondWindow,
|
EdgeTerminusKind::Interior => CourseTerminus::ContinuesBeyondWindow,
|
||||||
EdgeTerminusKind::Mouth => {
|
EdgeTerminusKind::Mouth => {
|
||||||
match resolve_mouth_terminus(course, seed, body_id, params, ta, climate, min_wavelength_m)
|
match resolve_mouth_terminus(
|
||||||
{
|
course,
|
||||||
|
seed,
|
||||||
|
body_id,
|
||||||
|
params,
|
||||||
|
ta,
|
||||||
|
climate,
|
||||||
|
min_wavelength_m,
|
||||||
|
) {
|
||||||
Some(mouth_point) => {
|
Some(mouth_point) => {
|
||||||
// Replace the cropped course's tail with the resolved
|
// Replace the cropped course's tail with the resolved
|
||||||
// mouth point (bisected against the last land
|
// mouth point (bisected against the last land
|
||||||
@@ -1521,8 +1527,15 @@ pub fn build_district_window_layer(
|
|||||||
// delta close to the Discipline item 2 ~5% budget.
|
// delta close to the Discipline item 2 ~5% budget.
|
||||||
let step_m = granularity.spacing_m();
|
let step_m = granularity.spacing_m();
|
||||||
let window_rect = window_world_rect(center_world_m, half, side, step_m);
|
let window_rect = window_world_rect(center_world_m, half, side, step_m);
|
||||||
let invented_courses =
|
let invented_courses = invent_courses_near_window(
|
||||||
invent_courses_near_window(seed, params, ta, river_network, window_rect, granularity, min_wavelength_m);
|
seed,
|
||||||
|
params,
|
||||||
|
ta,
|
||||||
|
river_network,
|
||||||
|
window_rect,
|
||||||
|
granularity,
|
||||||
|
min_wavelength_m,
|
||||||
|
);
|
||||||
|
|
||||||
// One Rayon task per row: derive_window_cell(row, ..) for every col, then
|
// One Rayon task per row: derive_window_cell(row, ..) for every col, then
|
||||||
// scatter that row's results into the flat arrays. Row order in the
|
// scatter that row's results into the flat arrays. Row order in the
|
||||||
@@ -1624,8 +1637,15 @@ fn build_district_window_layer_serial(
|
|||||||
let mut glaciation = vec![0u8; cells];
|
let mut glaciation = vec![0u8; cells];
|
||||||
let step_m = granularity.spacing_m();
|
let step_m = granularity.spacing_m();
|
||||||
let window_rect = window_world_rect(center_world_m, half, side, step_m);
|
let window_rect = window_world_rect(center_world_m, half, side, step_m);
|
||||||
let invented_courses =
|
let invented_courses = invent_courses_near_window(
|
||||||
invent_courses_near_window(seed, params, ta, river_network, window_rect, granularity, min_wavelength_m);
|
seed,
|
||||||
|
params,
|
||||||
|
ta,
|
||||||
|
river_network,
|
||||||
|
window_rect,
|
||||||
|
granularity,
|
||||||
|
min_wavelength_m,
|
||||||
|
);
|
||||||
for row in 0..side {
|
for row in 0..side {
|
||||||
let row_cells: Vec<WindowCell> = (0..side)
|
let row_cells: Vec<WindowCell> = (0..side)
|
||||||
.map(|col| {
|
.map(|col| {
|
||||||
@@ -2783,13 +2803,37 @@ mod tests {
|
|||||||
// Two DIFFERENT window rects, both containing `mid` well inside
|
// Two DIFFERENT window rects, both containing `mid` well inside
|
||||||
// their bounds (so both windows' crop ranges include the shared
|
// their bounds (so both windows' crop ranges include the shared
|
||||||
// stretch, not just a single boundary point).
|
// stretch, not just a single boundary point).
|
||||||
let window_a = (mid.0 - 20_000.0, mid.1 - 20_000.0, mid.0 + 5_000.0, mid.1 + 5_000.0);
|
let window_a = (
|
||||||
let window_b = (mid.0 - 5_000.0, mid.1 - 5_000.0, mid.0 + 20_000.0, mid.1 + 20_000.0);
|
mid.0 - 20_000.0,
|
||||||
|
mid.1 - 20_000.0,
|
||||||
|
mid.0 + 5_000.0,
|
||||||
|
mid.1 + 5_000.0,
|
||||||
|
);
|
||||||
|
let window_b = (
|
||||||
|
mid.0 - 5_000.0,
|
||||||
|
mid.1 - 5_000.0,
|
||||||
|
mid.0 + 20_000.0,
|
||||||
|
mid.1 + 20_000.0,
|
||||||
|
);
|
||||||
|
|
||||||
let invented_a =
|
let invented_a = invent_courses_near_window(
|
||||||
invent_courses_near_window(seed, ¶ms, &ta, rn, window_a, WindowGranularity::District, 0.0);
|
seed,
|
||||||
let invented_b =
|
¶ms,
|
||||||
invent_courses_near_window(seed, ¶ms, &ta, rn, window_b, WindowGranularity::District, 0.0);
|
&ta,
|
||||||
|
rn,
|
||||||
|
window_a,
|
||||||
|
WindowGranularity::District,
|
||||||
|
0.0,
|
||||||
|
);
|
||||||
|
let invented_b = invent_courses_near_window(
|
||||||
|
seed,
|
||||||
|
¶ms,
|
||||||
|
&ta,
|
||||||
|
rn,
|
||||||
|
window_b,
|
||||||
|
WindowGranularity::District,
|
||||||
|
0.0,
|
||||||
|
);
|
||||||
|
|
||||||
let course_a = invented_a
|
let course_a = invented_a
|
||||||
.iter()
|
.iter()
|
||||||
@@ -5300,7 +5344,7 @@ mod tests {
|
|||||||
|
|
||||||
// Serve the completed state back through the proxy: the cache-hit
|
// Serve the completed state back through the proxy: the cache-hit
|
||||||
// branch must build and include the region grid.
|
// branch must build and include the region grid.
|
||||||
cache.insert(body_state);
|
cache.insert(*body_state);
|
||||||
let ready = handle_atlas_request(
|
let ready = handle_atlas_request(
|
||||||
&req("GJ1c"),
|
&req("GJ1c"),
|
||||||
&mut cache,
|
&mut cache,
|
||||||
|
|||||||
@@ -359,7 +359,7 @@ fn drain_generation_completions(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cache.insert(state);
|
cache.insert(*state);
|
||||||
}
|
}
|
||||||
GenCompletion::Failed { item, reason } => {
|
GenCompletion::Failed { item, reason } => {
|
||||||
tracing::warn!(?item, %reason, "background generation work item failed");
|
tracing::warn!(?item, %reason, "background generation work item failed");
|
||||||
|
|||||||
@@ -397,10 +397,7 @@ fn stage_a_control_path(
|
|||||||
let mut prev_offset = 0.0f64;
|
let mut prev_offset = 0.0f64;
|
||||||
for i in 1..STAGE_A_STATIONS - 1 {
|
for i in 1..STAGE_A_STATIONS - 1 {
|
||||||
let t = i as f64 / (STAGE_A_STATIONS - 1) as f64;
|
let t = i as f64 / (STAGE_A_STATIONS - 1) as f64;
|
||||||
let base = (
|
let base = (anchor_a.0 + dx * t, anchor_a.1 + dy * t);
|
||||||
anchor_a.0 + dx * t,
|
|
||||||
anchor_a.1 + dy * t,
|
|
||||||
);
|
|
||||||
// Evaluate k candidates evenly spaced across [-search_radius, +search_radius],
|
// Evaluate k candidates evenly spaced across [-search_radius, +search_radius],
|
||||||
// deterministic (no RNG draw — the "candidates" are a fixed fan, not a
|
// deterministic (no RNG draw — the "candidates" are a fixed fan, not a
|
||||||
// stochastic search, so the scoring alone decides, D-010).
|
// stochastic search, so the scoring alone decides, D-010).
|
||||||
@@ -535,7 +532,12 @@ fn warp_fbm(sx: u64, sy: u64, arc_m: f64, chord_m: f64, min_wavelength_m: f64) -
|
|||||||
// stations key on GLOBAL arc-length, never window-relative or 2D
|
// stations key on GLOBAL arc-length, never window-relative or 2D
|
||||||
// world position, so overlapping windows agree exactly on the shared
|
// world position, so overlapping windows agree exactly on the shared
|
||||||
// stretch regardless of where the window happens to be centred).
|
// stretch regardless of where the window happens to be centred).
|
||||||
let n = value_noise(sx.wrapping_add((i as u64).wrapping_mul(0x1000)), arc_m, 0.0, wl);
|
let n = value_noise(
|
||||||
|
sx.wrapping_add((i as u64).wrapping_mul(0x1000)),
|
||||||
|
arc_m,
|
||||||
|
0.0,
|
||||||
|
wl,
|
||||||
|
);
|
||||||
sum += n * amp;
|
sum += n * amp;
|
||||||
norm += amp;
|
norm += amp;
|
||||||
amp *= 0.5;
|
amp *= 0.5;
|
||||||
@@ -569,9 +571,15 @@ fn sample_polyline_at_arc_length(points: &[CoursePoint], arc_m: f64) -> (CourseP
|
|||||||
} else {
|
} else {
|
||||||
remaining / seg_len
|
remaining / seg_len
|
||||||
};
|
};
|
||||||
let pos = (w[0].0 + (w[1].0 - w[0].0) * t, w[0].1 + (w[1].1 - w[0].1) * t);
|
let pos = (
|
||||||
|
w[0].0 + (w[1].0 - w[0].0) * t,
|
||||||
|
w[0].1 + (w[1].1 - w[0].1) * t,
|
||||||
|
);
|
||||||
let tangent_len = seg_len.max(1e-9);
|
let tangent_len = seg_len.max(1e-9);
|
||||||
let tangent = ((w[1].0 - w[0].0) / tangent_len, (w[1].1 - w[0].1) / tangent_len);
|
let tangent = (
|
||||||
|
(w[1].0 - w[0].0) / tangent_len,
|
||||||
|
(w[1].1 - w[0].1) / tangent_len,
|
||||||
|
);
|
||||||
return (pos, tangent);
|
return (pos, tangent);
|
||||||
}
|
}
|
||||||
remaining -= seg_len;
|
remaining -= seg_len;
|
||||||
@@ -843,7 +851,10 @@ mod tests {
|
|||||||
|
|
||||||
let a = invent_course(seed, edge, &ta, ¶ms, 2_048.0, 0.0);
|
let a = invent_course(seed, edge, &ta, ¶ms, 2_048.0, 0.0);
|
||||||
let b = invent_course(seed, edge, &ta, ¶ms, 2_048.0, 0.0);
|
let b = invent_course(seed, edge, &ta, ¶ms, 2_048.0, 0.0);
|
||||||
assert_eq!(a.points, b.points, "course invention must be deterministic (D-010/D-227)");
|
assert_eq!(
|
||||||
|
a.points, b.points,
|
||||||
|
"course invention must be deterministic (D-010/D-227)"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -881,7 +892,10 @@ mod tests {
|
|||||||
let seed = SeedChain::root(7).derive(SeedDomain::Body, 1);
|
let seed = SeedChain::root(7).derive(SeedDomain::Body, 1);
|
||||||
let station_spacing_m = 2_048.0;
|
let station_spacing_m = 2_048.0;
|
||||||
|
|
||||||
for edge in edges.iter().filter(|e| e.terminus == EdgeTerminusKind::Interior) {
|
for edge in edges
|
||||||
|
.iter()
|
||||||
|
.filter(|e| e.terminus == EdgeTerminusKind::Interior)
|
||||||
|
{
|
||||||
let course = invent_course(seed, edge, &ta, ¶ms, station_spacing_m, 0.0);
|
let course = invent_course(seed, edge, &ta, ¶ms, station_spacing_m, 0.0);
|
||||||
let anchor_a = cell_world_m(edge.upstream, &ta, ¶ms);
|
let anchor_a = cell_world_m(edge.upstream, &ta, ¶ms);
|
||||||
let anchor_b = cell_world_m(edge.downstream, &ta, ¶ms);
|
let anchor_b = cell_world_m(edge.downstream, &ta, ¶ms);
|
||||||
@@ -933,7 +947,9 @@ mod tests {
|
|||||||
// fields' underlying warp_fbm-style noise streams (same seed, same
|
// fields' underlying warp_fbm-style noise streams (same seed, same
|
||||||
// world positions) and confirm the Pearson correlation across many
|
// world positions) and confirm the Pearson correlation across many
|
||||||
// samples is near zero, not just "not identical."
|
// samples is near zero, not just "not identical."
|
||||||
use crate::atlas::coast_invention::{body_coast_envelope, coast_character_at, coast_warp_px};
|
use crate::atlas::coast_invention::{
|
||||||
|
body_coast_envelope, coast_character_at, coast_warp_px,
|
||||||
|
};
|
||||||
use crate::atlas::district_profile::{GlaciationGrade, TectonicClass};
|
use crate::atlas::district_profile::{GlaciationGrade, TectonicClass};
|
||||||
|
|
||||||
let params = test_params();
|
let params = test_params();
|
||||||
@@ -1013,7 +1029,10 @@ mod tests {
|
|||||||
let seed = SeedChain::root(3).derive(SeedDomain::Body, 1);
|
let seed = SeedChain::root(3).derive(SeedDomain::Body, 1);
|
||||||
let a = invent_course(seed, interior[0], &ta, ¶ms, 2_048.0, 0.0);
|
let a = invent_course(seed, interior[0], &ta, ¶ms, 2_048.0, 0.0);
|
||||||
let b = invent_course(seed, interior[1], &ta, ¶ms, 2_048.0, 0.0);
|
let b = invent_course(seed, interior[1], &ta, ¶ms, 2_048.0, 0.0);
|
||||||
assert_ne!(a.points, b.points, "distinct edges must invent distinct courses");
|
assert_ne!(
|
||||||
|
a.points, b.points,
|
||||||
|
"distinct edges must invent distinct courses"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -1071,11 +1090,20 @@ mod tests {
|
|||||||
bbox,
|
bbox,
|
||||||
};
|
};
|
||||||
// On the course itself.
|
// On the course itself.
|
||||||
assert!(near_perennial_water((50.0, 0.0), &[course.clone()]));
|
assert!(near_perennial_water(
|
||||||
|
(50.0, 0.0),
|
||||||
|
std::slice::from_ref(&course)
|
||||||
|
));
|
||||||
// Within the 3 m trunk band.
|
// Within the 3 m trunk band.
|
||||||
assert!(near_perennial_water((50.0, 2.9), &[course.clone()]));
|
assert!(near_perennial_water(
|
||||||
|
(50.0, 2.9),
|
||||||
|
std::slice::from_ref(&course)
|
||||||
|
));
|
||||||
// Just outside the band.
|
// Just outside the band.
|
||||||
assert!(!near_perennial_water((50.0, 3.1), &[course.clone()]));
|
assert!(!near_perennial_water(
|
||||||
|
(50.0, 3.1),
|
||||||
|
std::slice::from_ref(&course)
|
||||||
|
));
|
||||||
// Far away entirely.
|
// Far away entirely.
|
||||||
assert!(!near_perennial_water((50.0, 500.0), &[course]));
|
assert!(!near_perennial_water((50.0, 500.0), &[course]));
|
||||||
}
|
}
|
||||||
@@ -1095,8 +1123,14 @@ mod tests {
|
|||||||
};
|
};
|
||||||
// 2.0 m: within tributary band (2.0), outside stream band (1.0).
|
// 2.0 m: within tributary band (2.0), outside stream band (1.0).
|
||||||
let probe = (50.0, 1.5);
|
let probe = (50.0, 1.5);
|
||||||
assert!(near_perennial_water(probe, &[base(1)]), "tributary band should cover 1.5 m");
|
assert!(
|
||||||
assert!(!near_perennial_water(probe, &[base(0)]), "stream band should NOT cover 1.5 m");
|
near_perennial_water(probe, &[base(1)]),
|
||||||
|
"tributary band should cover 1.5 m"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
!near_perennial_water(probe, &[base(0)]),
|
||||||
|
"stream band should NOT cover 1.5 m"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -1115,7 +1149,10 @@ mod tests {
|
|||||||
bbox,
|
bbox,
|
||||||
};
|
};
|
||||||
let district_spacing_m = 2_048.0;
|
let district_spacing_m = 2_048.0;
|
||||||
assert!(!near_perennial_water((5_000.0, district_spacing_m), &[course]));
|
assert!(!near_perennial_water(
|
||||||
|
(5_000.0, district_spacing_m),
|
||||||
|
&[course]
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Reference in New Issue
Block a user