mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-05 19:45:54 +00:00
kernel: project_onto_face, sketch curves projected onto a face as SMLib's curves
project_onto_face projects sketch segments along a direction onto the face of a body at a point through Brep::project_curves (smlib_project_curves), each projected piece the B-spline SMLib made, returned as a record curve (RationalSpline) on its interval, within a millionth of the body's size. lib.rs (coordinator): export point_path::project_onto_face. (not built: base in progress) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017itGh5fpMEousnZ91cYcVt
This commit is contained in:
@@ -155,6 +155,22 @@ pub fn edge_path(body: &Body, edge: usize) -> Result<Vec<PathSeg>> {
|
||||
curve_path(&e.curve, e.interval)
|
||||
}
|
||||
|
||||
/// The sketch segments `segs` on `plane` projected along `direction` (pointing from them toward
|
||||
/// the face) onto the face of `body` at `face_at`, as the record curves SMLib's projection makes
|
||||
/// (one per piece of the projection that stays on the face), each on its interval.
|
||||
pub fn project_onto_face(
|
||||
body: &Body,
|
||||
face_at: Vec3,
|
||||
plane: &Plane,
|
||||
segs: &[solidcraft_geom::Seg2],
|
||||
direction: Vec3,
|
||||
) -> Result<Vec<(brep::Curve, [f64; 2])>> {
|
||||
if !(face_at.is_finite() && direction.is_finite() && direction.len() > 1e-12) || segs.is_empty() || segs.len() > 4096 {
|
||||
return Err(KernelError::Invalid("curve projection: a point, a direction and 1…4096 curves".into()));
|
||||
}
|
||||
crate::smlib_sweeps::project_onto_face(body, face_at, plane, segs, direction)
|
||||
}
|
||||
|
||||
/// Most control points a record curve given to [`curve_path`] may have.
|
||||
const MAX_CURVE_POINTS: usize = 100_000;
|
||||
|
||||
|
||||
@@ -72,7 +72,8 @@ pub(crate) struct Draft {
|
||||
|
||||
#[cfg(feature = "smlib")]
|
||||
pub(crate) use imp::{
|
||||
body_from_record, curve, extrude, loft, loft_rails, loft_to_point, path_curve, revolve, screw, sphere, sweep, sweep_controlled,
|
||||
body_from_record, curve, extrude, loft, loft_rails, loft_to_point, path_curve, project_onto_face, revolve, screw, sphere, sweep,
|
||||
sweep_controlled,
|
||||
};
|
||||
|
||||
/// The error of an SMLib operation in a build without SMLib.
|
||||
@@ -91,6 +92,9 @@ mod stubs {
|
||||
pub(crate) fn sphere(_: Vec3, _: f64) -> Result<Body> {
|
||||
Err(not_built())
|
||||
}
|
||||
pub(crate) fn project_onto_face(_: &Body, _: Vec3, _: &Plane, _: &[Seg2], _: Vec3) -> Result<Vec<(solidcraft_geom::brep::Curve, [f64; 2])>> {
|
||||
Err(not_built())
|
||||
}
|
||||
pub(crate) fn extrude(_: &Plane, _: &[Piece], _: Option<&Region2>, _: f64, _: f64, _: f64, _: Option<Draft>) -> Result<Body> {
|
||||
Err(not_built())
|
||||
}
|
||||
@@ -117,7 +121,9 @@ mod stubs {
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "smlib"))]
|
||||
pub(crate) use stubs::{body_from_record, extrude, loft, loft_rails, loft_to_point, revolve, screw, sphere, sweep, sweep_controlled};
|
||||
pub(crate) use stubs::{
|
||||
body_from_record, extrude, loft, loft_rails, loft_to_point, project_onto_face, revolve, screw, sphere, sweep, sweep_controlled,
|
||||
};
|
||||
|
||||
/// Refuses what no SMLib sweep does, before any work.
|
||||
pub(crate) fn refuse(what: &str) -> KernelError {
|
||||
@@ -208,6 +214,35 @@ mod imp {
|
||||
body_of(&brep, what)
|
||||
}
|
||||
|
||||
/// The sketch segments `segs` on `plane` projected along `direction` onto the face of
|
||||
/// `body` at `face_at`: SMLib's projection (smlib_project_curves), each projected curve the
|
||||
/// B-spline SMLib made, as a record curve on its interval, within a millionth of the body's
|
||||
/// size of the true projection.
|
||||
pub(crate) fn project_onto_face(
|
||||
body: &Body,
|
||||
face_at: Vec3,
|
||||
plane: &Plane,
|
||||
segs: &[Seg2],
|
||||
direction: Vec3,
|
||||
) -> Result<Vec<(solidcraft_geom::brep::Curve, [f64; 2])>> {
|
||||
let c = segs.iter().map(|s| curve(plane, s)).collect::<Result<Vec<_>>>()?;
|
||||
let size = body.size().max(1e-9);
|
||||
let out = body.smlib()?.project_curves(p(face_at), size * 1e-3 + 1e-6, &c, p(direction), (size * 1e-6).max(1e-6)).map_err(|e| match e {
|
||||
solidcraft_smlib::Error::Empty => KernelError::Invalid("the curve projects to nothing on the face".into()),
|
||||
solidcraft_smlib::Error::NoMatch { .. } => KernelError::Invalid("no face of the body at the projection's point".into()),
|
||||
e => failed("curve projection", e),
|
||||
})?;
|
||||
out.into_iter()
|
||||
.map(|(c, interval)| match c {
|
||||
Curve::Nurbs { points, knots, .. } => {
|
||||
let homogeneous = points.iter().map(|q| [q[0] * q[3], q[1] * q[3], q[2] * q[3], q[3]]).collect();
|
||||
Ok((solidcraft_geom::brep::Curve::RationalSpline { knots, homogeneous }, interval))
|
||||
}
|
||||
_ => Err(failed("curve projection", "a projected curve is not a B-spline")),
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// SMLib's sphere about `center`, each face swept from the arc (segment 0) of the half disc
|
||||
/// a sphere revolves.
|
||||
pub(crate) fn sphere(center: Vec3, radius: f64) -> Result<Body> {
|
||||
|
||||
Reference in New Issue
Block a user