refactor: drop the discarded offset from world_offset_from_centers
The function computed a median-centroid offset that is now always discarded (geometry is absolute + double-single). Rename it to cluster_extent_from_centers, return only the cluster span used for camera fit / cull, and drop the dead centroid computation. Rename the companion WORLD_OFFSET_SANE_EXTENT const to CLUSTER_SANE_EXTENT. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
04c93df2c4
commit
62c7e20f42
1 changed files with 18 additions and 28 deletions
|
|
@ -183,7 +183,7 @@ pub fn build_derived_caches(doc: &CadDocument) -> DerivedCaches {
|
||||||
centers.push(c);
|
centers.push(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let (_world_offset, local_extent_max) = world_offset_from_centers(centers, &doc.header);
|
let local_extent_max = cluster_extent_from_centers(centers, &doc.header);
|
||||||
|
|
||||||
// Default bg adaptation target at load: the model background (paper
|
// Default bg adaptation target at load: the model background (paper
|
||||||
// bg is only relevant after the user enters a paper layout, and
|
// bg is only relevant after the user enters a paper layout, and
|
||||||
|
|
@ -273,7 +273,7 @@ pub fn build_derived_caches(doc: &CadDocument) -> DerivedCaches {
|
||||||
|
|
||||||
/// Mirrors `cache::block_cache::SANE_EXTENT` — wire coords past this magnitude
|
/// Mirrors `cache::block_cache::SANE_EXTENT` — wire coords past this magnitude
|
||||||
/// are treated as corruption rather than precision-relevant geometry.
|
/// are treated as corruption rather than precision-relevant geometry.
|
||||||
const WORLD_OFFSET_SANE_EXTENT: f64 = 1.0e8;
|
const CLUSTER_SANE_EXTENT: f64 = 1.0e8;
|
||||||
|
|
||||||
/// MSPACE-membership prep shared by the world-offset centroid scan.
|
/// MSPACE-membership prep shared by the world-offset centroid scan.
|
||||||
///
|
///
|
||||||
|
|
@ -378,7 +378,7 @@ fn offset_centroid(
|
||||||
if !cx.is_finite() || !cy.is_finite() || !cz.is_finite() {
|
if !cx.is_finite() || !cy.is_finite() || !cz.is_finite() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
if cx.abs() > WORLD_OFFSET_SANE_EXTENT || cy.abs() > WORLD_OFFSET_SANE_EXTENT {
|
if cx.abs() > CLUSTER_SANE_EXTENT || cy.abs() > CLUSTER_SANE_EXTENT {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
Some([cx, cy, cz])
|
Some([cx, cy, cz])
|
||||||
|
|
@ -391,17 +391,16 @@ fn offset_centroid(
|
||||||
/// `$EXTMIN/$EXTMAX` only as a fallback when the entity scan found nothing.
|
/// `$EXTMIN/$EXTMAX` only as a fallback when the entity scan found nothing.
|
||||||
/// `centers` is gathered by the caller's single entity walk (see
|
/// `centers` is gathered by the caller's single entity walk (see
|
||||||
/// [`build_derived_caches`]) so no separate AABB pass is needed.
|
/// [`build_derived_caches`]) so no separate AABB pass is needed.
|
||||||
fn world_offset_from_centers(
|
fn cluster_extent_from_centers(
|
||||||
centers: Vec<[f64; 3]>,
|
centers: Vec<[f64; 3]>,
|
||||||
header: &acadrust::document::HeaderVariables,
|
header: &acadrust::document::HeaderVariables,
|
||||||
) -> ([f64; 3], f32) {
|
) -> f32 {
|
||||||
const SANE_EXTENT: f64 = WORLD_OFFSET_SANE_EXTENT;
|
const SANE_EXTENT: f64 = CLUSTER_SANE_EXTENT;
|
||||||
let entity_ok = !centers.is_empty();
|
let entity_ok = !centers.is_empty();
|
||||||
|
|
||||||
// Median of per-entity centroids → robust drawing center.
|
// 95th-percentile distance from the median × 2 gives the half-span of the
|
||||||
// For local_extent_max: 95th-percentile distance from the median × 2
|
// dense cluster while leaving room for legitimate outliers (sparse leaders,
|
||||||
// gives the half-span of the dense cluster while leaving room for
|
// dimensions, scattered annotations).
|
||||||
// legitimate outliers (sparse leaders, dimensions, scattered annotations).
|
|
||||||
let median = |v: &mut Vec<f64>| -> f64 {
|
let median = |v: &mut Vec<f64>| -> f64 {
|
||||||
v.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
|
v.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
|
||||||
v[v.len() / 2]
|
v[v.len() / 2]
|
||||||
|
|
@ -411,19 +410,17 @@ fn world_offset_from_centers(
|
||||||
let i = ((v.len() as f64 - 1.0) * frac).round() as usize;
|
let i = ((v.len() as f64 - 1.0) * frac).round() as usize;
|
||||||
v[i]
|
v[i]
|
||||||
};
|
};
|
||||||
let (ecx, ecy, ecz, espan_max) = if entity_ok {
|
let espan_max = if entity_ok {
|
||||||
let mut xs: Vec<f64> = centers.iter().map(|c| c[0]).collect();
|
let mut xs: Vec<f64> = centers.iter().map(|c| c[0]).collect();
|
||||||
let mut ys: Vec<f64> = centers.iter().map(|c| c[1]).collect();
|
let mut ys: Vec<f64> = centers.iter().map(|c| c[1]).collect();
|
||||||
let mut zs: Vec<f64> = centers.iter().map(|c| c[2]).collect();
|
|
||||||
let mx = median(&mut xs);
|
let mx = median(&mut xs);
|
||||||
let my = median(&mut ys);
|
let my = median(&mut ys);
|
||||||
let mz = median(&mut zs);
|
|
||||||
let mut dx: Vec<f64> = centers.iter().map(|c| (c[0] - mx).abs()).collect();
|
let mut dx: Vec<f64> = centers.iter().map(|c| (c[0] - mx).abs()).collect();
|
||||||
let mut dy: Vec<f64> = centers.iter().map(|c| (c[1] - my).abs()).collect();
|
let mut dy: Vec<f64> = centers.iter().map(|c| (c[1] - my).abs()).collect();
|
||||||
let p95 = percentile(&mut dx, 0.95).max(percentile(&mut dy, 0.95));
|
let p95 = percentile(&mut dx, 0.95).max(percentile(&mut dy, 0.95));
|
||||||
(mx, my, mz, (p95 * 2.0).max(1.0) as f32)
|
(p95 * 2.0).max(1.0) as f32
|
||||||
} else {
|
} else {
|
||||||
(0.0, 0.0, 0.0, 0.0)
|
0.0
|
||||||
};
|
};
|
||||||
|
|
||||||
// ── Header extents (fallback only) ───────────────────────────────────
|
// ── Header extents (fallback only) ───────────────────────────────────
|
||||||
|
|
@ -436,25 +433,18 @@ fn world_offset_from_centers(
|
||||||
&& hmin.y.abs() < SANE_EXTENT
|
&& hmin.y.abs() < SANE_EXTENT
|
||||||
&& hmax.y.abs() < SANE_EXTENT;
|
&& hmax.y.abs() < SANE_EXTENT;
|
||||||
|
|
||||||
// Entity-derived offset is preferred whenever it's available — the
|
// Geometry reaches the GPU as absolute coordinates (the double-single
|
||||||
// median-of-centroids ignores Ray/orphan/duplicate-block-defn outliers
|
// relative-to-eye path keeps it precise at UTM scale), so only the
|
||||||
// that the header EXTMIN/EXTMAX (a min/max midpoint) bakes in. Header
|
// cluster span — for camera fit and cull — is derived from the content.
|
||||||
// is the fallback only when the entity scan found nothing.
|
|
||||||
// world_offset is being retired: geometry now reaches the GPU as absolute
|
|
||||||
// coordinates and the double-single relative-to-eye path keeps it precise
|
|
||||||
// even at UTM scale, so there's no longer a coarse origin to subtract.
|
|
||||||
// Always return a zero offset; only `local_extent_max` (camera/cull span)
|
|
||||||
// is still derived from the content.
|
|
||||||
let _ = (ecx, ecy, ecz);
|
|
||||||
if entity_ok {
|
if entity_ok {
|
||||||
([0.0; 3], espan_max)
|
espan_max
|
||||||
} else if header_ok {
|
} else if header_ok {
|
||||||
let hw = ((hmax.x - hmin.x) * 0.5) as f32;
|
let hw = ((hmax.x - hmin.x) * 0.5) as f32;
|
||||||
let hh = ((hmax.y - hmin.y) * 0.5) as f32;
|
let hh = ((hmax.y - hmin.y) * 0.5) as f32;
|
||||||
let hz = ((hmax.z - hmin.z) * 0.5).max(1.0) as f32;
|
let hz = ((hmax.z - hmin.z) * 0.5).max(1.0) as f32;
|
||||||
([0.0; 3], hw.max(hh).max(hz) * 10.0)
|
hw.max(hh).max(hz) * 10.0
|
||||||
} else {
|
} else {
|
||||||
([0.0; 3], 1e9_f32)
|
1e9_f32
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue