fix: reject degenerate boolean intersection polylines

This commit is contained in:
lillith authored and bherbruck committed 2026-10-12 08:36:40 -04:00
1 parent 970da30a99
commit ed102b5393
8 files changed
+84 -1

No files matched your search

+3
View File
@@ -7,6 +7,9 @@ are marked `SolveCraft:` in the source.
## truck-shapeops 0.4.0 (Apache-2.0, © RICOS Co. Ltd., https://github.com/ricosjp/truck)
Changes:
- `transversal/intersection_curve/mod.rs`: reject empty/single-point polylines and
collapsed or non-finite segments before endpoint indexing and normalization. A hidden
constructor re-export lets the kernel workspace tests exercise the actual vendored code.
- `transversal/integrate/mod.rs`: mesh both shells with `robust_triangulation` (faces made by
earlier booleans have boundaries that lie on their surface only within tolerance).
- `transversal/divide_face/mod.rs`: when projecting a loop onto a face's surface, fall back to
+3
View File
@@ -34,4 +34,7 @@ mod healing;
pub use healing::{RobustSplitClosedEdgesAndFaces, SplitClosedEdgesAndFaces};
mod transversal;
pub use transversal::{and, or, ShapeOpsCurve, ShapeOpsSurface};
// SolveCraft: exercised by kernel regressions in the workspace CI.
#[doc(hidden)]
pub use transversal::IntersectionCurveWithParameters;
mod alternative;
@@ -19,12 +19,21 @@ impl<S> From<IntersectionCurveWithParameters<S>> for IntersectionCurve<PolylineC
impl<S> IntersectionCurveWithParameters<S>
where S: ParametricSurface3D + SearchNearestParameter<D2, Point = Point3>
{
/// SolveCraft: construct a projected curve, returning `None` for degenerate input.
pub fn try_new(
surface0: S,
surface1: S,
poly: PolylineCurve<Point3>,
tol: f64,
) -> Option<Self> {
// SolveCraft: 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());
+3
View File
@@ -2,6 +2,9 @@ mod divide_face;
mod faces_classification;
mod integrate;
mod intersection_curve;
// SolveCraft: expose the constructor for workspace regression coverage of the vendored fix.
#[doc(hidden)]
pub use intersection_curve::IntersectionCurveWithParameters;
mod loops_store;
mod polyline_construction;
pub use integrate::{and, or, ShapeOpsCurve, ShapeOpsSurface};