From 8d91c19f178c2e5fc8d440c123623a04c666cc6f Mon Sep 17 00:00:00 2001 From: jyviko <2501648+jyviko@users.noreply.github.com> Date: Thu, 22 Oct 2026 07:48:53 -0400 Subject: [PATCH] brep: an intersection curve's point is a function of t alone Intersection::point started its Newton solve from the last point found (a Cell holding both surfaces' parameters) when that landed near the leader, as truck took a hinted point. The answer then depended on what was evaluated before, so CurveEval was not Sync, and the clearance check, which shares a body's DistanceShape (its edges' CurveEvals) across worker threads, did not compile; with threads it would also have made the result depend on their interleaving. Each point is now solved from the leader's own point, the path the hint fell back to, and the unused trace tolerance goes with the hint. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017itGh5fpMEousnZ91cYcVt --- crates/geom/src/brep/eval.rs | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/crates/geom/src/brep/eval.rs b/crates/geom/src/brep/eval.rs index 3cb10ff592..420579fac5 100644 --- a/crates/geom/src/brep/eval.rs +++ b/crates/geom/src/brep/eval.rs @@ -14,7 +14,6 @@ use crate::Vec3; use crate::bspline::MAX_SPLINE_DEGREE; use crate::tess::uv::{self, Domain}; use crate::tess::{EvalCurve, EvalSurface, MAX_EVAL_KNOTS, MAX_EVAL_POINTS}; -use std::cell::Cell; use std::f64::consts::{FRAC_PI_2, TAU}; /// Newton steps of one intersection point. @@ -286,9 +285,6 @@ pub enum CurveEval { pub struct Intersection { surfaces: [SurfaceEval; 2], leader: CurveEval, - tolerance: f64, - /// Both surfaces' parameters of the last point found: the next point starts from them. - hint: Cell>, } impl CurveEval { @@ -300,7 +296,7 @@ impl CurveEval { Curve::Polyline { points } => CurveEval::Polyline(points.iter().copied().map(v3).collect()), Curve::Spline { knots, points } => spline(knots, points.iter().map(|p| [p[0], p[1], p[2], 1.0]).collect())?, Curve::RationalSpline { knots, homogeneous } => spline(knots, homogeneous.clone())?, - Curve::SurfaceIntersection { surfaces, leader, tolerance } => { + Curve::SurfaceIntersection { surfaces, leader, .. } => { let leader = CurveEval::new(leader)?; if !matches!(leader, CurveEval::Polyline(_) | CurveEval::Spline(_)) { return Err(Error::Invalid("intersection leader".into())); @@ -308,8 +304,6 @@ impl CurveEval { CurveEval::Intersection(Box::new(Intersection { surfaces: [SurfaceEval::new(&surfaces[0])?, SurfaceEval::new(&surfaces[1])?], leader, - tolerance: *tolerance, - hint: Cell::new(None), })) } }) @@ -380,29 +374,21 @@ fn spline(knots: &[f64], ctrl: Vec<[f64; 4]>) -> Result { } impl Intersection { - /// The point in the leader's normal plane at `t`: from the last point's parameters when that - /// lands within the trace tolerance of the leader (as truck takes a hinted point), else from - /// the leader's point alone. + /// The point in the leader's normal plane at `t`, found from the leader's point: a function + /// of `t` alone, whatever was evaluated before (and so the same on every thread). fn point(&self, t: f64) -> Option { let (lead, along) = self.leader.leader(t)?; if !(along.len2() > 0.0) { return None; } - let near = self.tolerance.max(1e-6); - let hinted = self.hint.get().and_then(|h| self.solve(lead, along, Some(h))).filter(|(x, _)| x.dist(lead) <= near); - let (x, uv) = match hinted { - Some(found) => found, - None => self.solve(lead, along, None)?, - }; - self.hint.set(Some(uv)); - Some(x) + self.solve(lead, along) } /// Newton on the planes: each surface's tangent plane at the foot of the current point, and /// the leader's normal plane, until the point stops moving. - fn solve(&self, lead: Vec3, along: Vec3, hint: Option<[[f64; 2]; 2]>) -> Option<(Vec3, [[f64; 2]; 2])> { + fn solve(&self, lead: Vec3, along: Vec3) -> Option { let mut x = lead; - let mut uv = hint; + let mut uv: Option<[[f64; 2]; 2]> = None; for _ in 0..MAX_NEWTON { let mut planes = [(Vec3::ZERO, 0.0); 2]; let mut feet = [[0.0; 2]; 2]; @@ -419,7 +405,7 @@ impl Intersection { let step = y.dist(x); x = y; if step <= 1e-12 * (1.0 + x.len()) { - return Some((x, feet)); + return Some(x); } } None