Exact profiles for splines of any degree (a degree-4…7 Bézier segment kind, Seg2::Bezier, extruded as B-spline edges) and for free-form curves cut by crossings (exact sub-curves whose ends are moved to the true crossing, found by Newton; polylines only where that fails)

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
This commit is contained in:
bherbruckandClaude Opus 5.5 committed 2026-10-08 09:42:34 +00:00
1 parent f79b5c1045
commit b9bc75670c
11 files changed
+389 -34

No files matched your search

+3 -2
View File
@@ -41,7 +41,7 @@ pub(crate) fn wire(plane: &Plane, lp: &Loop2) -> Result<mt::Wire> {
builder::circle_arc(a, b, p3(plane.to_world(s.mid())))
}
}
Seg2::Cubic { .. } | Seg2::Conic { .. } => {
Seg2::Cubic { .. } | Seg2::Conic { .. } | Seg2::Bezier { .. } => {
crate::freeform::edge(plane, s, a, b).ok_or_else(|| KernelError::Invalid("profile curve".into()))?
}
};
@@ -71,6 +71,7 @@ fn region_ok(r: &Region2) -> Result<()> {
}
Seg2::Cubic { p0, p1, p2, p3 } => p0.is_finite() && p1.is_finite() && p2.is_finite() && p3.is_finite(),
Seg2::Conic { a, apex, b, w } => a.is_finite() && apex.is_finite() && b.is_finite() && w.is_finite() && w > 1e-9,
Seg2::Bezier { n, p } => (4..=solvecraft_geom::MAX_BEZIER_DEGREE as u8).contains(&n) && p.iter().all(|q| q.is_finite()),
};
if !ok {
return Err(KernelError::Invalid("non-finite profile".into()));
@@ -417,7 +418,7 @@ fn revolve_touching_axis(plane: &Plane, lp: &Loop2, axis_origin: Vec2, d: Vec2)
edges.push(match *s {
Seg2::Line { .. } => builder::line(a, b),
Seg2::Arc { .. } => builder::circle_arc(a, b, p3(plane.to_world(s.mid()))),
Seg2::Cubic { .. } | Seg2::Conic { .. } => match crate::freeform::edge(plane, s, a, b) {
Seg2::Cubic { .. } | Seg2::Conic { .. } | Seg2::Bezier { .. } => match crate::freeform::edge(plane, s, a, b) {
Some(e) => e,
None => builder::line(a, b),
},
+5 -1
View File
@@ -1,4 +1,4 @@
//! Free-form profile edges: cubic Béziers as B-spline curves and conics as rational quadratic
//! Free-form profile edges: Béziers (cubic and higher) as B-spline curves and conics as rational quadratic
//! NURBS curves (exact ellipses, parabolas and hyperbolas from sketches).
use solvecraft_geom::{Plane, Seg2};
@@ -20,6 +20,10 @@ pub(crate) fn edge(plane: &Plane, s: &Seg2, a: &mt::Vertex, b: &mt::Vertex) -> O
let curve = mt::NurbsCurve::new(mt::BSplineCurve::new(mt::KnotVec::bezier_knot(2), ctrl));
Some(mt::Edge::new(a, b, mt::Curve::NurbsCurve(curve)))
}
Seg2::Bezier { n, ref p } => {
let inner = p.get(1..(n as usize).clamp(1, solvecraft_geom::MAX_BEZIER_DEGREE))?;
Some(mt::builder::bezier(a, b, inner.iter().map(|q| p3(plane.to_world(*q))).collect()))
}
Seg2::Line { .. } | Seg2::Arc { .. } => None,
}
}