forked from 1b-agent/opencadstudio-upstream
Place curve markers along spatial splines and polylines
This commit is contained in:
1 parent
18569687a1
commit
8979fa46c2
2 files changed
+79
-6
No files matched your search
@@ -107,6 +107,51 @@ pub fn entity_curve(entity: &EntityType) -> Option<PlanarCurve> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Exact spatial source geometry for commands that traverse nonplanar curves.
|
||||||
|
/// Curve construction and arc-length calculations remain in the kernel.
|
||||||
|
pub fn entity_spatial_measurement(entity: &EntityType) -> Option<cadkernel::space::ArcLengthCurve3> {
|
||||||
|
use cadkernel::space::{ArcLengthCurve3, NurbsCurve3, Parameterization};
|
||||||
|
let curve = match entity {
|
||||||
|
EntityType::Polyline3D(polyline) => {
|
||||||
|
if polyline.flags.spline_fit {
|
||||||
|
let degree = match polyline.smooth_type as i16 { 5 => 2, 6 => 3, _ => return None };
|
||||||
|
let controls: Vec<_> = polyline.vertices.iter().filter(|vertex| vertex.flags & 16 != 0)
|
||||||
|
.map(|vertex| [vertex.position.x, vertex.position.y, vertex.position.z]).collect();
|
||||||
|
let curve = NurbsCurve3::from_control_polygon(degree, &controls, polyline.is_closed())?;
|
||||||
|
return ArcLengthCurve3::from_nurbs(curve);
|
||||||
|
}
|
||||||
|
let points: Vec<_> = polyline.vertices.iter().map(|vertex| {
|
||||||
|
[vertex.position.x, vertex.position.y, vertex.position.z]
|
||||||
|
}).collect();
|
||||||
|
return ArcLengthCurve3::from_polyline(&points, polyline.is_closed());
|
||||||
|
}
|
||||||
|
EntityType::Spline(spline) => {
|
||||||
|
if crate::entities::spline::uses_fit_method(spline) {
|
||||||
|
let points: Vec<_> = spline.fit_points.iter().copied().map(xyz).collect();
|
||||||
|
let parameterization = match spline.knot_parameterization {
|
||||||
|
1 => Parameterization::Centripetal, 2 => Parameterization::Uniform,
|
||||||
|
_ => Parameterization::Chord,
|
||||||
|
};
|
||||||
|
if spline.flags.periodic {
|
||||||
|
NurbsCurve3::interpolate_periodic(&points, parameterization)?
|
||||||
|
} else {
|
||||||
|
if spline.flags.closed { return None; }
|
||||||
|
NurbsCurve3::interpolate_fit(&points, Some(xyz(spline.begin_tangent)),
|
||||||
|
Some(xyz(spline.end_tangent)), parameterization)?
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let controls: Vec<_> = spline.control_points.iter().copied().map(xyz).collect();
|
||||||
|
let weights = if spline.weights.is_empty() { vec![1.0; controls.len()] }
|
||||||
|
else { spline.weights.clone() };
|
||||||
|
NurbsCurve3::new_strict(spline.degree as usize, controls, spline.knots.clone(), weights)?
|
||||||
|
.with_periodicity(spline.flags.periodic)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
ArcLengthCurve3::from_nurbs(curve)
|
||||||
|
}
|
||||||
|
|
||||||
/// The plane an OCS-stored entity's coordinates are read in.
|
/// The plane an OCS-stored entity's coordinates are read in.
|
||||||
///
|
///
|
||||||
/// `elevation` is the entity's third stored coordinate — the distance along
|
/// `elevation` is the entity's third stored coordinate — the distance along
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use acadrust::{Entity, EntityType, Handle};
|
|||||||
use cadkernel::space::PlanarCurve;
|
use cadkernel::space::PlanarCurve;
|
||||||
use glam::DVec3;
|
use glam::DVec3;
|
||||||
use crate::command::{CadCommand, CmdOption, CmdResult, CurveMarker, WorkingPlane};
|
use crate::command::{CadCommand, CmdOption, CmdResult, CurveMarker, WorkingPlane};
|
||||||
use crate::entities::curve::entity_curve;
|
use crate::entities::curve::{entity_curve, entity_spatial_measurement};
|
||||||
use crate::t;
|
use crate::t;
|
||||||
const MEASURE: bool = false;
|
const MEASURE: bool = false;
|
||||||
|
|
||||||
@@ -215,9 +215,10 @@ pub fn measure_entity(entity: &EntityType, segment_length: f64) -> Vec<EntityTyp
|
|||||||
if segment_length <= 0.0 {
|
if segment_length <= 0.0 {
|
||||||
return vec![];
|
return vec![];
|
||||||
}
|
}
|
||||||
let Some((curve, total)) = measurable(entity) else {
|
let Some(curve) = entity_curve(entity) else {
|
||||||
return vec![];
|
return vec![];
|
||||||
};
|
};
|
||||||
|
let total = curve.length();
|
||||||
let mut pts = Vec::new();
|
let mut pts = Vec::new();
|
||||||
let mut walked = segment_length;
|
let mut walked = segment_length;
|
||||||
while walked < total - 1e-6 {
|
while walked < total - 1e-6 {
|
||||||
@@ -227,7 +228,7 @@ pub fn measure_entity(entity: &EntityType, segment_length: f64) -> Vec<EntityTyp
|
|||||||
pts
|
pts
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_marker(curve: &PlanarCurve, distance: f64, marker: Option<&CurveMarker>) -> EntityType {
|
fn make_marker(curve: &MeasuredCurve, distance: f64, marker: Option<&CurveMarker>) -> EntityType {
|
||||||
let pos = curve.point_at_distance(distance);
|
let pos = curve.point_at_distance(distance);
|
||||||
let Some(marker) = marker else {
|
let Some(marker) = marker else {
|
||||||
let mut point = PointEnt::new();
|
let mut point = PointEnt::new();
|
||||||
@@ -251,9 +252,36 @@ fn make_point(pos: [f64; 3]) -> EntityType {
|
|||||||
EntityType::Point(p)
|
EntityType::Point(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn measurable(entity: &EntityType) -> Option<(PlanarCurve, f64)> {
|
/// The entity's curve and its length, or `None` for anything that cannot be
|
||||||
let curve = entity_curve(entity)?;
|
/// walked along — a hatch, a block, an unbounded ray.
|
||||||
let total = curve.curve.length();
|
enum MeasuredCurve {
|
||||||
|
Planar(PlanarCurve),
|
||||||
|
Spatial(cadkernel::space::ArcLengthCurve3),
|
||||||
|
}
|
||||||
|
impl MeasuredCurve {
|
||||||
|
fn is_closed(&self) -> bool {
|
||||||
|
match self { Self::Planar(curve) => curve.is_closed(), Self::Spatial(curve) => curve.is_closed() }
|
||||||
|
}
|
||||||
|
fn point_at_distance(&self, distance: f64) -> [f64; 3] {
|
||||||
|
match self { Self::Planar(curve) => curve.point_at_distance(distance), Self::Spatial(curve) => curve.point_at_distance(distance) }
|
||||||
|
}
|
||||||
|
fn parameter_at_distance(&self, distance: f64) -> f64 {
|
||||||
|
match self { Self::Planar(curve) => curve.parameter_at_distance(distance), Self::Spatial(curve) => curve.parameter_at_distance(distance) }
|
||||||
|
}
|
||||||
|
fn tangent_at(&self, parameter: f64) -> [f64; 3] {
|
||||||
|
match self { Self::Planar(curve) => curve.tangent_at(parameter), Self::Spatial(curve) => curve.tangent_at(parameter) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn measurable(entity: &EntityType) -> Option<(MeasuredCurve, f64)> {
|
||||||
|
let (curve, total) = if let Some(curve) = entity_curve(entity) {
|
||||||
|
let total = curve.length();
|
||||||
|
(MeasuredCurve::Planar(curve), total)
|
||||||
|
} else {
|
||||||
|
let curve = entity_spatial_measurement(entity)?;
|
||||||
|
let total = curve.length();
|
||||||
|
(MeasuredCurve::Spatial(curve), total)
|
||||||
|
};
|
||||||
(total.is_finite() && total > 1e-10).then_some((curve, total))
|
(total.is_finite() && total > 1e-10).then_some((curve, total))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user