From 29b15535d737f5de995471c28bb4d84e88e93ec9 Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Wed, 29 Jul 2026 21:01:40 +0300 Subject: [PATCH] fix(render): preserve shared curve endpoints Use stored topology vertices at tessellated curve boundaries so floating-point reevaluation cannot open gaps at extreme zoom. Closes #561 --- src/scene/convert/truck_tess.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/scene/convert/truck_tess.rs b/src/scene/convert/truck_tess.rs index f77bb1e97..d92a1cc1a 100644 --- a/src/scene/convert/truck_tess.rs +++ b/src/scene/convert/truck_tess.rs @@ -132,7 +132,18 @@ pub fn tessellate_edge(e: &Edge) -> TruckTessResult { // parameter_division samples adaptively: fewer points on straight segments, // more on tight curves, all within the active chord-height tolerance. // The Scene scales this with zoom so far-out arcs aren't oversampled. - let (_, pts) = curve.parameter_division((t0, t1), current_curve_tol()); + let (_, mut pts) = curve.parameter_division((t0, t1), current_curve_tol()); + // Keep the rendered endpoints bit-for-bit identical to the topology. + // Evaluating a curve again at t=0/1 can differ from its stored vertices by + // a few f64 ULPs (a straight line's end is computed as p0 + (p1-p0), for + // example). At extreme zoom that turns a shared CAD endpoint into a visible + // gap between independently tessellated entities (#561). + if let Some(first) = pts.first_mut() { + *first = e.front().point(); + } + if pts.len() > 1 { + *pts.last_mut().expect("length checked") = e.back().point(); + } let mut high: Vec<[f32; 3]> = Vec::with_capacity(pts.len()); let mut low: Vec<[f32; 3]> = Vec::with_capacity(pts.len()); for p in &pts {