use truck_base::cgmath64::*; use truck_geometry::prelude::*; use truck_meshalgo::prelude::*; /// polyline base ntersection curve with parameter #[derive(Debug, Clone, derive_more::Deref, derive_more::DerefMut)] pub struct IntersectionCurveWithParameters { #[deref] #[deref_mut] ic: IntersectionCurve, S>, params0: PolylineCurve, params1: PolylineCurve, } impl From> for IntersectionCurve, S> { fn from(a: IntersectionCurveWithParameters) -> Self { a.ic } } impl IntersectionCurveWithParameters where S: ParametricSurface3D + SearchNearestParameter { /// SolidCraft: construct a projected curve, returning `None` for degenerate input. pub fn try_new( surface0: S, surface1: S, poly: PolylineCurve, tol: f64, ) -> Option { // SolidCraft: a point contact is not a curve. Reject it before indexing the // endpoints, and reject collapsed/non-finite segments before normalizing. if poly.len() < 2 || poly.windows(2).any(|p| { let length2 = (p[1] - p[0]).magnitude2(); !length2.is_finite() || length2 <= 0.0 }) { return None; } let mut polyline = PolylineCurve(Vec::new()); let mut params0 = PolylineCurve(Vec::new()); let mut params1 = PolylineCurve(Vec::new()); for p in poly.windows(2) { let n = (p[1] - p[0]).normalize(); let (q, p0, p1) = double_projection(&surface0, None, &surface1, None, p[0], n, 100)?; polyline.push(q); params0.push(p0); params1.push(p1); } let (q, p0, p1) = if poly[0].near(&poly[poly.len() - 1]) { (polyline[0], params0[0], params1[0]) } else { let n = (poly[poly.len() - 1] - poly[poly.len() - 2]).normalize(); double_projection( &surface0, None, &surface1, None, poly[poly.len() - 1], n, 100, )? }; polyline.push(q); params0.push(p0); params1.push(p1); Some(Self { ic: IntersectionCurve::new_unchecked( Box::new(surface0), Box::new(surface1), polyline, tol, ), params0, params1, }) } } impl ParametricCurve for IntersectionCurveWithParameters where S: ParametricSurface3D + SearchNearestParameter { type Point = Point3; type Vector = Vector3; #[inline(always)] fn subs(&self, t: f64) -> Point3 { self.ic.subs(t) } #[inline(always)] fn der(&self, t: f64) -> Vector3 { self.ic.der(t) } #[inline(always)] fn der2(&self, t: f64) -> Vector3 { self.ic.der2(t) } #[inline(always)] fn parameter_range(&self) -> ParameterRange { self.ic.parameter_range() } } impl BoundedCurve for IntersectionCurveWithParameters where S: ParametricSurface3D + SearchNearestParameter {} impl ParameterDivision1D for IntersectionCurveWithParameters where S: ParametricSurface3D + SearchNearestParameter { type Point = Point3; #[inline(always)] fn parameter_division(&self, range: (f64, f64), tol: f64) -> (Vec, Vec) { self.ic.parameter_division(range, tol) } } impl Cut for IntersectionCurveWithParameters where S: ParametricSurface3D + SearchNearestParameter { #[inline(always)] fn cut(&mut self, t: f64) -> Self { Self { ic: self.ic.cut(t), params0: self.params0.cut(t), params1: self.params1.cut(t), } } } impl Invertible for IntersectionCurveWithParameters { fn invert(&mut self) { self.ic.invert(); self.params0.invert(); self.params1.invert(); } } impl SearchParameter for IntersectionCurveWithParameters where S: ParametricSurface3D + SearchNearestParameter { type Point = Point3; fn search_parameter>( &self, point: Point3, hint: H, trials: usize, ) -> Option { self.ic.search_parameter(point, hint, trials) } } impl SearchNearestParameter for IntersectionCurveWithParameters where S: ParametricSurface3D + SearchNearestParameter { type Point = Point3; fn search_nearest_parameter>( &self, point: Point3, hint: H, trials: usize, ) -> Option { self.ic.search_nearest_parameter(point, hint, trials) } } pub fn intersection_curves( surface0: S, polygon0: &PolygonMesh, surface1: S, polygon1: &PolygonMesh, tol: f64, ) -> Vec<( PolylineCurve, Option>, )> where S: ParametricSurface3D + SearchNearestParameter, { let interferences = polygon0.extract_interference(polygon1); let polylines = super::polyline_construction::construct_polylines(&interferences); polylines .into_iter() .map(|polyline| { let curve = IntersectionCurveWithParameters::try_new( surface0.clone(), surface1.clone(), polyline.clone(), tol, ); (polyline, curve) }) .collect() } #[cfg(test)] mod tests;