Struct truck_geometry::nurbs::BSplineCurve
source · pub struct BSplineCurve<P> { /* private fields */ }
Expand description
B-spline curve
§Examples
use truck_geometry::prelude::*;
// the knot vector
let knot_vec = KnotVec::from(
vec![0.0, 0.0, 0.0, 0.25, 0.25, 0.5, 0.5, 0.75, 0.75, 1.0, 1.0, 1.0]
);
// sign up the control points in the vector of all points
let ctrl_pts = vec![ // the vector of the indices of control points
Vector4::new(0.0, -2.0, 0.0, 2.0),
Vector4::new(1.0, -1.0, 0.0, 1.0),
Vector4::new(1.0, 0.0, 0.0, 1.0),
Vector4::new(1.0, 1.0, 0.0, 1.0),
Vector4::new(0.0, 2.0, 0.0, 2.0),
Vector4::new(-1.0, 1.0, 0.0, 1.0),
Vector4::new(-1.0, 0.0, 0.0, 1.0),
Vector4::new(-1.0, -1.0, 0.0, 1.0),
Vector4::new(0.0, -2.0, 0.0, 2.0),
];
// construct the B-spline curve
let bspline = BSplineCurve::new(knot_vec, ctrl_pts);
// This B-spline curve is a nurbs representation of the unit circle.
const N : usize = 100; // sample size in test
for i in 0..N {
let t = 1.0 / (N as f64) * (i as f64);
let v = bspline.subs(t); // We can use the instances as a function.
let c = (v[0] / v[3]).powi(2) + (v[1] / v[3]).powi(2);
assert_near2!(c, 1.0);
}
Implementations§
source§impl<P> BSplineCurve<P>
impl<P> BSplineCurve<P>
sourcepub fn new(knot_vec: KnotVec, control_points: Vec<P>) -> BSplineCurve<P>
pub fn new(knot_vec: KnotVec, control_points: Vec<P>) -> BSplineCurve<P>
sourcepub fn try_new(
knot_vec: KnotVec,
control_points: Vec<P>,
) -> Result<BSplineCurve<P>>
pub fn try_new( knot_vec: KnotVec, control_points: Vec<P>, ) -> Result<BSplineCurve<P>>
constructor.
§Arguments
knot_vec
- the knot vectorcontrol_points
- the vector of the control points
§Failures
- If there are no control points, returns
Error::EmptyControlPoint<f64>s
. - If the number of knots is more than the one of control points, returns
Error::TooShortKnotVector
. - If the range of the knot vector is zero, returns
Error::ZeroRange
.
sourcepub const fn new_unchecked(
knot_vec: KnotVec,
control_points: Vec<P>,
) -> BSplineCurve<P>
pub const fn new_unchecked( knot_vec: KnotVec, control_points: Vec<P>, ) -> BSplineCurve<P>
constructor.
§Arguments
knot_vec
- the knot vectorcontrol_points
- the vector of the control points
§Remarks
This method is prepared only for performance-critical development and is not recommended.
This method does NOT check the rules for constructing B-spline curve.
The programmer must guarantee these conditions before using this method.
sourcepub fn debug_new(knot_vec: KnotVec, control_points: Vec<P>) -> BSplineCurve<P>
pub fn debug_new(knot_vec: KnotVec, control_points: Vec<P>) -> BSplineCurve<P>
sourcepub const fn control_points(&self) -> &Vec<P>
pub const fn control_points(&self) -> &Vec<P>
Returns the reference of the control points.
sourcepub fn control_point(&self, idx: usize) -> &P
pub fn control_point(&self, idx: usize) -> &P
Returns the reference of the control point corresponding to the index idx
.
sourcepub fn control_point_mut(&mut self, idx: usize) -> &mut P
pub fn control_point_mut(&mut self, idx: usize) -> &mut P
Returns the mutable reference of the control point corresponding to index idx
.
sourcepub fn control_points_mut(&mut self) -> impl Iterator<Item = &mut P>
pub fn control_points_mut(&mut self) -> impl Iterator<Item = &mut P>
Returns the iterator on all control points
sourcepub fn transform_control_points<F: FnMut(&mut P)>(&mut self, f: F)
pub fn transform_control_points<F: FnMut(&mut P)>(&mut self, f: F)
Apply the given transformation to all control points.
sourcepub fn degree(&self) -> usize
pub fn degree(&self) -> usize
Returns the degree of B-spline curve
§Examples
use truck_geometry::prelude::*;
let knot_vec = KnotVec::bezier_knot(2);
let ctrl_pts = vec![Vector2::new(1.0, 2.0), Vector2::new(2.0, 3.0), Vector2::new(3.0, 4.0)];
let bspcurve = BSplineCurve::new(knot_vec, ctrl_pts);
assert_eq!(bspcurve.degree(), 2);
sourcepub fn invert(&mut self) -> &mut Self
pub fn invert(&mut self) -> &mut Self
Inverts a curve
§Examples
use truck_geometry::prelude::*;
let knot_vec = KnotVec::uniform_knot(2, 2);
let ctrl_pts = vec![Vector2::new(1.0, 2.0), Vector2::new(2.0, 3.0), Vector2::new(3.0, 4.0), Vector2::new(4.0, 5.0)];
let bspcurve0 = BSplineCurve::new(knot_vec, ctrl_pts);
let mut bspcurve1 = bspcurve0.clone();
bspcurve1.invert();
const N: usize = 100; // sample size
for i in 0..=N {
let t = (i as f64) / (N as f64);
assert_near2!(bspcurve0.subs(t), bspcurve1.subs(1.0 - t));
}
sourcepub fn is_clamped(&self) -> bool
pub fn is_clamped(&self) -> bool
Returns whether the knot vector is clamped or not.
sourcepub fn knot_normalize(&mut self) -> &mut Self
pub fn knot_normalize(&mut self) -> &mut Self
Normalizes the knot vector
sourcepub fn knot_translate(&mut self, x: f64) -> &mut Self
pub fn knot_translate(&mut self, x: f64) -> &mut Self
Translates the knot vector
source§impl<P: ControlPoint<f64>> BSplineCurve<P>
impl<P: ControlPoint<f64>> BSplineCurve<P>
sourcepub fn get_closure(&self) -> impl Fn(f64) -> P + '_
pub fn get_closure(&self) -> impl Fn(f64) -> P + '_
Returns the closure of substitution.
§Examples
The following test code is the same test with the one of BSplineCurve::subs()
.
use truck_geometry::prelude::*;
let knot_vec = KnotVec::from(vec![-1.0, -1.0, -1.0, 1.0, 1.0, 1.0]);
let ctrl_pts = vec![Vector2::new(-1.0, 1.0), Vector2::new(0.0, -1.0), Vector2::new(1.0, 1.0)];
let bspcurve = BSplineCurve::new(knot_vec, ctrl_pts);
const N: usize = 100; // sample size
let get_t = |i: usize| -1.0 + 2.0 * (i as f64) / (N as f64);
let res: Vec<_> = (0..=N).map(get_t).map(bspcurve.get_closure()).collect();
let ans: Vec<_> = (0..=N).map(get_t).map(|t| Vector2::new(t, t * t)).collect();
res.iter().zip(&ans).for_each(|(v0, v1)| assert_near2!(v0, v1));
sourcepub fn derivation(&self) -> BSplineCurve<P::Diff>
pub fn derivation(&self) -> BSplineCurve<P::Diff>
Returns the derived B-spline curve.
§Examples
use truck_geometry::prelude::*;
let knot_vec = KnotVec::bezier_knot(2);
let ctrl_pts = vec![Vector2::new(0.0, 0.0), Vector2::new(0.5, 0.0), Vector2::new(1.0, 1.0)];
let bspcurve = BSplineCurve::new(knot_vec, ctrl_pts);
let derived = bspcurve.derivation();
// `bpscurve = (t, t^2), derived = (1, 2t)`
const N : usize = 100; // sample size
for i in 0..=N {
let t = 1.0 / (N as f64) * (i as f64);
assert_near2!(derived.subs(t), Vector2::new(1.0, 2.0 * t));
}
source§impl<V: Homogeneous<f64>> BSplineCurve<V>
impl<V: Homogeneous<f64>> BSplineCurve<V>
sourcepub fn lift_up(curve: BSplineCurve<V::Point>) -> Self
pub fn lift_up(curve: BSplineCurve<V::Point>) -> Self
lift up control points to homogeneous coordinate.
source§impl<P: ControlPoint<f64> + Tolerance> BSplineCurve<P>
impl<P: ControlPoint<f64> + Tolerance> BSplineCurve<P>
sourcepub fn is_const(&self) -> bool
pub fn is_const(&self) -> bool
Returns whether all control points are the same or not. If the knot vector is clamped, it means whether the curve is constant or not.
§Examples
use truck_geometry::prelude::*;
let knot_vec = KnotVec::bezier_knot(2);
let pt = Vector2::new(1.0, 2.0);
let mut ctrl_pts = vec![pt.clone(), pt.clone(), pt.clone()];
let const_bspcurve = BSplineCurve::new(knot_vec.clone(), ctrl_pts.clone());
assert!(const_bspcurve.is_const());
ctrl_pts.push(Vector2::new(2.0, 3.0));
let bspcurve = BSplineCurve::new(knot_vec.clone(), ctrl_pts.clone());
assert!(!bspcurve.is_const());
§Remarks
If the knot vector is not clamped and the BSpline basis function is not partition of unity, then perhaps returns true even if the curve is not constant.
use truck_geometry::prelude::*;
let knot_vec = KnotVec::uniform_knot(1, 5);
let ctrl_pts = vec![Vector2::new(1.0, 2.0), Vector2::new(1.0, 2.0)];
let bspcurve = BSplineCurve::new(knot_vec, ctrl_pts);
// bspcurve is not constant.
assert_eq!(bspcurve.subs(0.0), Vector2::new(0.0, 0.0));
assert_ne!(bspcurve.subs(0.5), Vector2::new(0.0, 0.0));
// bspcurve.is_const() is true
assert!(bspcurve.is_const());
sourcepub fn add_knot(&mut self, x: f64) -> &mut Self
pub fn add_knot(&mut self, x: f64) -> &mut Self
Adds a knot x
, and do not change self
as a curve.
§Examples
use truck_geometry::prelude::*;
let knot_vec = KnotVec::bezier_knot(2);
let ctrl_pts = vec![Vector2::new(-1.0, 1.0), Vector2::new(0.0, -1.0), Vector2::new(1.0, 1.0)];
let mut bspcurve = BSplineCurve::new(knot_vec, ctrl_pts);
let org_curve = bspcurve.clone();
// add 4 knots
bspcurve.add_knot(0.5).add_knot(0.5).add_knot(0.25).add_knot(0.75);
assert_eq!(bspcurve.knot_vec().len(), org_curve.knot_vec().len() + 4);
// bspcurve does not change as a curve
assert!(bspcurve.near2_as_curve(&org_curve));
§Remarks
If the added knot x
is out of the range of the knot vector, then the knot vector will extended.
use truck_geometry::prelude::*;
let knot_vec = KnotVec::bezier_knot(2);
let ctrl_pts = vec![Vector2::new(-1.0, 1.0), Vector2::new(0.0, -1.0), Vector2::new(1.0, 1.0)];
let mut bspcurve = BSplineCurve::new(knot_vec, ctrl_pts);
assert_eq!(bspcurve.knot_vec().range_length(), 1.0);
assert_eq!(bspcurve.front(), Vector2::new(-1.0, 1.0));
assert_eq!(bspcurve.back(), Vector2::new(1.0, 1.0));
// add knots out of the range of the knot vectors.
bspcurve.add_knot(-1.0).add_knot(2.0);
assert_eq!(bspcurve.knot_vec().range_length(), 3.0);
assert_eq!(bspcurve.front(), Vector2::new(0.0, 0.0));
assert_eq!(bspcurve.back(), Vector2::new(0.0, 0.0));
sourcepub fn remove_knot(&mut self, idx: usize) -> &mut Self
pub fn remove_knot(&mut self, idx: usize) -> &mut Self
Removes a knot corresponding to the indices idx
, and do not change self
as a curve.
If cannot remove the knot, do not change self
and return self
.
§Examples
use truck_geometry::prelude::*;
let knot_vec = KnotVec::bezier_knot(2);
let ctrl_pts = vec![Vector2::new(-1.0, 1.0), Vector2::new(0.0, -1.0), Vector2::new(1.0, 1.0)];
let mut bspcurve = BSplineCurve::new(knot_vec, ctrl_pts);
let org_curve = bspcurve.clone();
// add knots and remove them.
bspcurve.add_knot(0.5).add_knot(0.5).add_knot(0.25).add_knot(0.75);
bspcurve.remove_knot(3).remove_knot(3).remove_knot(3).remove_knot(3);
assert!(bspcurve.near2_as_curve(&org_curve));
assert_eq!(bspcurve.knot_vec().len(), org_curve.knot_vec().len())
sourcepub fn try_remove_knot(&mut self, idx: usize) -> Result<&mut BSplineCurve<P>>
pub fn try_remove_knot(&mut self, idx: usize) -> Result<&mut BSplineCurve<P>>
Removes a knot corresponding to the indice idx
, and do not change self
as a curve.
If the knot cannot be removed, returns
Error::CannotRemoveKnot
.
§Examples
use truck_geometry::prelude::*;
use truck_geometry::errors::Error;
let knot_vec = KnotVec::bezier_knot(2);
let ctrl_pts = vec![Vector2::new(-1.0, 1.0), Vector2::new(0.0, -1.0), Vector2::new(1.0, 1.0)];
let mut bspcurve = BSplineCurve::new(knot_vec, ctrl_pts);
let org_curve = bspcurve.clone();
bspcurve.add_knot(0.5).add_knot(0.5).add_knot(0.25).add_knot(0.75);
assert!(bspcurve.try_remove_knot(3).is_ok());
assert_eq!(bspcurve.try_remove_knot(2), Err(Error::CannotRemoveKnot(2)));
sourcepub fn elevate_degree(&mut self) -> &mut Self
pub fn elevate_degree(&mut self) -> &mut Self
elevate 1 degree.
§Examples
use truck_geometry::prelude::*;
let knot_vec = KnotVec::bezier_knot(1);
let ctrl_pts = vec![Vector2::new(0.0, 0.0), Vector2::new(1.0, 1.0)];
let mut bspcurve = BSplineCurve::new(knot_vec, ctrl_pts);
bspcurve.elevate_degree();
assert_eq!(bspcurve.degree(), 2);
assert_eq!(bspcurve.knot_vec(), &KnotVec::bezier_knot(2));
assert_eq!(bspcurve.control_point(1), &Vector2::new(0.5, 0.5));
sourcepub fn clamp(&mut self) -> &mut Self
pub fn clamp(&mut self) -> &mut Self
Makes the B-spline curve clamped
§Examples
use truck_geometry::prelude::*;
let knot_vec = KnotVec::from(vec![0.0, 1.0, 2.0, 3.0, 4.0, 5.0]);
let ctrl_pts = vec![Vector2::new(0.0, 1.0), Vector2::new(1.0, 2.0), Vector2::new(2.0, 3.0)];
let mut bspcurve = BSplineCurve::new(knot_vec, ctrl_pts);
assert!(!bspcurve.is_clamped());
bspcurve.clamp();
assert!(bspcurve.is_clamped());
assert_eq!(bspcurve.knot_vec().len(), 10);
sourcepub fn optimize(&mut self) -> &mut Self
pub fn optimize(&mut self) -> &mut Self
Repeats Self::try_remove_knot()
from the back knot in turn until the knot cannot be removed.
§Examples
use truck_geometry::prelude::*;
let knot_vec = KnotVec::bezier_knot(2);
let ctrl_pts = vec![Vector2::new(1.0, 2.0), Vector2::new(2.0, 3.0), Vector2::new(3.0, 4.0)];
let mut bspcurve = BSplineCurve::new(knot_vec, ctrl_pts);
let org_curve = bspcurve.clone();
// add 4 new knots
bspcurve.add_knot(0.5).add_knot(0.5).add_knot(0.25).add_knot(0.75);
assert_eq!(bspcurve.knot_vec().len(), KnotVec::bezier_knot(2).len() + 4);
// By the optimization, added knots are removed.
bspcurve.optimize();
assert_eq!(bspcurve.knot_vec(), &KnotVec::bezier_knot(2));
assert!(bspcurve.near2_as_curve(&org_curve));
sourcepub fn syncro_degree(&mut self, other: &mut Self)
pub fn syncro_degree(&mut self, other: &mut Self)
Makes two splines having the same degrees.
§Examples
use truck_geometry::prelude::*;
let knot_vec0 = KnotVec::bezier_knot(1);
let ctrl_pts0 = vec![Vector2::new(1.0, 2.0), Vector2::new(2.0, 3.0)];
let mut bspcurve0 = BSplineCurve::new(knot_vec0, ctrl_pts0);
let knot_vec1 = KnotVec::bezier_knot(2);
let ctrl_pts1 = vec![Vector2::new(1.0, 2.0), Vector2::new(2.0, 3.0), Vector2::new(3.0, 4.0)];
let mut bspcurve1 = BSplineCurve::new(knot_vec1, ctrl_pts1);
assert_ne!(bspcurve0.degree(), bspcurve1.degree());
let org_curve0 = bspcurve0.clone();
let org_curve1 = bspcurve1.clone();
bspcurve0.syncro_degree(&mut bspcurve1);
assert_eq!(bspcurve0.degree(), bspcurve1.degree());
assert!(bspcurve0.near2_as_curve(&org_curve0));
assert!(bspcurve1.near2_as_curve(&org_curve1));
sourcepub fn syncro_knots(&mut self, other: &mut BSplineCurve<P>)
pub fn syncro_knots(&mut self, other: &mut BSplineCurve<P>)
Makes two splines having the same normalized knot vectors.
§Examples
use truck_geometry::prelude::*;
let knot_vec0 = KnotVec::from(vec![0.0, 0.0, 0.0, 0.5, 1.0, 1.0, 1.0]);
let ctrl_pts0 = vec![Vector2::new(0.0, 0.0), Vector2::new(1.0, 1.0), Vector2::new(2.0, 2.0), Vector2::new(3.0, 3.0)];
let mut bspcurve0 = BSplineCurve::new(knot_vec0, ctrl_pts0);
let mut org_curve0 = bspcurve0.clone();
let knot_vec1 = KnotVec::from(vec![0.0, 0.0, 1.0, 3.0, 4.0, 4.0]);
let ctrl_pts1 = vec![Vector2::new(0.0, 0.0), Vector2::new(1.0, 1.0), Vector2::new(2.0, 2.0), Vector2::new(3.0, 3.0)];
let mut bspcurve1 = BSplineCurve::new(knot_vec1, ctrl_pts1);
let mut org_curve1 = bspcurve1.clone();
bspcurve0.syncro_knots(&mut bspcurve1);
// The knot vectors are made the same.
assert_eq!(bspcurve0.knot_vec(), bspcurve1.knot_vec());
assert_eq!(
bspcurve0.knot_vec().as_slice(),
&[0.0, 0.0, 0.0, 0.25, 0.5, 0.75, 1.0, 1.0, 1.0]
);
// The degrees are not changed.
assert_eq!(bspcurve0.degree(), org_curve0.degree());
assert_eq!(bspcurve1.degree(), org_curve1.degree());
// The knot vector is normalized, however, the shape of curve is not changed.
assert!(bspcurve0.near2_as_curve(org_curve0.knot_normalize()));
assert!(bspcurve1.near2_as_curve(org_curve1.knot_normalize()));
sourcepub fn bezier_decomposition(&self) -> Vec<BSplineCurve<P>>
pub fn bezier_decomposition(&self) -> Vec<BSplineCurve<P>>
Separates self
into Bezier curves by each knots.
§Examples
use truck_geometry::prelude::*;
let knot_vec = KnotVec::uniform_knot(2, 2);
let ctrl_pts = vec![Vector2::new(0.0, 1.0), Vector2::new(1.0, 2.0), Vector2::new(2.0, 3.0), Vector2::new(3.0, 4.0)];
let bspcurve = BSplineCurve::new(knot_vec, ctrl_pts);
let beziers = bspcurve.bezier_decomposition();
const N: usize = 100;
for i in 0..=N {
let t = 0.5 * (i as f64) / (N as f64);
assert_near2!(bspcurve.subs(t), beziers[0].subs(t));
}
for i in 0..=N {
let t = 0.5 + 0.5 * (i as f64) / (N as f64);
assert_near2!(bspcurve.subs(t), beziers[1].subs(t));
}
sourcepub fn make_locally_injective(&mut self) -> &mut Self
pub fn make_locally_injective(&mut self) -> &mut Self
Makes the curve locally injective.
§Example
use truck_geometry::prelude::*;
const N : usize = 100; // sample size for test
let knot_vec = KnotVec::from(
vec![0.0, 0.0, 0.0, 1.0, 3.0, 4.0, 4.0, 4.0]
);
let ctrl_pts = vec![
Vector3::new(1.0, 0.0, 0.0),
Vector3::new(0.0, 1.0, 0.0),
Vector3::new(0.0, 1.0, 0.0),
Vector3::new(0.0, 1.0, 0.0),
Vector3::new(0.0, 0.0, 1.0),
];
let mut bspcurve = BSplineCurve::new(knot_vec, ctrl_pts);
let mut flag = false;
for i in 0..=N {
let t = 4.0 * (i as f64) / (N as f64);
flag = flag || bspcurve.subs(t).near(&bspcurve.subs(t + 1.0 / (N as f64)));
}
// There exists t such that bspcurve(t) == bspcurve(t + 0.01).
assert!(flag);
bspcurve.make_locally_injective().knot_normalize();
let mut flag = false;
for i in 0..=N {
let t = 1.0 * (i as f64) / (N as f64);
flag = flag || bspcurve.subs(t).near(&bspcurve.subs(t + 1.0 / (N as f64)));
}
// There does not exist t such that bspcurve(t) == bspcurve(t + 0.01).
assert!(!flag);
§Remarks
If self
is a constant curve, then does nothing.
use truck_geometry::prelude::*;
let knot_vec = KnotVec::from(vec![0.0, 0.0, 0.0, 1.0, 2.0, 2.0, 2.0]);
let ctrl_pts = vec![Vector2::new(1.0, 1.0); 4];
let mut bspcurve = BSplineCurve::new(knot_vec, ctrl_pts);
let org_curve = bspcurve.clone();
bspcurve.make_locally_injective();
assert_eq!(bspcurve, org_curve);
sourcepub fn near_as_curve(&self, other: &BSplineCurve<P>) -> bool
pub fn near_as_curve(&self, other: &BSplineCurve<P>) -> bool
Determine whether self
and other
is near as the B-spline curves or not.
Divides each knot interval into the number of degree equal parts,
and check |self(t) - other(t)| < TOLERANCE
for each end points t
.
§Examples
use truck_geometry::prelude::*;
let knot_vec = KnotVec::from(
vec![0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 4.0, 4.0, 4.0]
);
let ctrl_pts = vec![
Vector2::new(1.0, 1.0),
Vector2::new(3.0, 2.0),
Vector2::new(2.0, 3.0),
Vector2::new(4.0, 5.0),
Vector2::new(5.0, 4.0),
Vector2::new(1.0, 1.0),
];
let bspcurve0 = BSplineCurve::new(knot_vec, ctrl_pts);
let mut bspcurve1 = bspcurve0.clone();
assert!(bspcurve0.near_as_curve(&bspcurve1));
*bspcurve1.control_point_mut(1) += Vector2::new(0.01, 0.0002);
assert!(!bspcurve0.near_as_curve(&bspcurve1));
sourcepub fn near2_as_curve(&self, other: &BSplineCurve<P>) -> bool
pub fn near2_as_curve(&self, other: &BSplineCurve<P>) -> bool
Determines self
and other
is near in square order as the B-spline curves or not.
Divide each knot interval into the number of degree equal parts,
and check |self(t) - other(t)| < TOLERANCE
for each end points t
.
§Examples
use truck_geometry::prelude::*;
let eps = TOLERANCE;
let knot_vec = KnotVec::from(
vec![0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 4.0, 4.0, 4.0]
);
let ctrl_pts = vec![
Vector2::new(1.0, 1.0),
Vector2::new(3.0, 2.0),
Vector2::new(2.0, 3.0),
Vector2::new(4.0, 5.0),
Vector2::new(5.0, 4.0),
Vector2::new(1.0, 1.0),
];
let bspcurve0 = BSplineCurve::new(knot_vec, ctrl_pts);
let mut bspcurve1 = bspcurve0.clone();
assert!(bspcurve0.near_as_curve(&bspcurve1));
*bspcurve1.control_point_mut(1) += Vector2::new(eps, 0.0);
assert!(!bspcurve0.near2_as_curve(&bspcurve1));
source§impl<P> BSplineCurve<P>where
P: ControlPoint<f64> + EuclideanSpace<Scalar = f64, Diff = <P as ControlPoint<f64>>::Diff> + MetricSpace<Metric = f64> + Tolerance,
<P as ControlPoint<f64>>::Diff: InnerSpace<Scalar = f64> + Tolerance,
impl<P> BSplineCurve<P>where
P: ControlPoint<f64> + EuclideanSpace<Scalar = f64, Diff = <P as ControlPoint<f64>>::Diff> + MetricSpace<Metric = f64> + Tolerance,
<P as ControlPoint<f64>>::Diff: InnerSpace<Scalar = f64> + Tolerance,
sourcepub fn is_arc_of(&self, curve: &BSplineCurve<P>, hint: f64) -> Option<f64>
pub fn is_arc_of(&self, curve: &BSplineCurve<P>, hint: f64) -> Option<f64>
Determines whether self
is an arc of curve
by repeating applying Newton method.
The parameter hint
is the init value, required that curve.subs(hint)
is the front point of self
.
If self
is an arc of curve
, then returns Some(t)
such that curve.subs(t)
coincides with
the back point of self
. Otherwise, returns None
.
§Examples
use truck_geometry::prelude::*;
let knot_vec = KnotVec::from(
vec![0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 3.0, 3.0]
);
let ctrl_pts = vec![
Point3::new(0.0, 0.0, 0.0),
Point3::new(1.0, 0.0, 0.0),
Point3::new(1.0, 1.0, 0.0),
Point3::new(0.0, 1.0, 0.0),
Point3::new(0.0, 1.0, 1.0),
];
let bspcurve = BSplineCurve::new(knot_vec, ctrl_pts);
let mut part = bspcurve.clone().cut(0.6);
part.cut(2.8);
let t = part.is_arc_of(&bspcurve, 0.6).unwrap();
assert_near!(t, 2.8);
// hint is required the init value.
assert!(part.is_arc_of(&bspcurve, 0.7).is_none());
// normal failure
*part.control_point_mut(2) += Vector3::new(1.0, 2.0, 3.0);
assert!(part.is_arc_of(&bspcurve, 0.6).is_none());
source§impl<P: Bounded> BSplineCurve<P>
impl<P: Bounded> BSplineCurve<P>
sourcepub fn roughly_bounding_box(&self) -> BoundingBox<P>
pub fn roughly_bounding_box(&self) -> BoundingBox<P>
Returns the bounding box including all control points.
source§impl<P> BSplineCurve<P>where
P: ControlPoint<f64> + EuclideanSpace<Scalar = f64, Diff = <P as ControlPoint<f64>>::Diff> + MetricSpace<Metric = f64> + Tolerance + HashGen<f64>,
<P as ControlPoint<f64>>::Diff: InnerSpace<Scalar = f64> + Tolerance,
impl<P> BSplineCurve<P>where
P: ControlPoint<f64> + EuclideanSpace<Scalar = f64, Diff = <P as ControlPoint<f64>>::Diff> + MetricSpace<Metric = f64> + Tolerance + HashGen<f64>,
<P as ControlPoint<f64>>::Diff: InnerSpace<Scalar = f64> + Tolerance,
sourcepub fn cubic_approximation<C>(
curve: &C,
range: (f64, f64),
p_tol: f64,
d_tol: f64,
trials: usize,
) -> Option<Self>
pub fn cubic_approximation<C>( curve: &C, range: (f64, f64), p_tol: f64, d_tol: f64, trials: usize, ) -> Option<Self>
C^1-approximation for curve
by cubic Bspline curve.
§Examples
use truck_geometry::prelude::*;
use std::f64::consts::PI;
let circle = UnitCircle::<Point2>::new();
let bspcurve = BSplineCurve::cubic_approximation(&circle, (-PI, PI), 0.01, 0.01, 10).unwrap();
println!("{bspcurve:?}");
const N: usize = 100;
for i in 0..N {
let t = i as f64 / N as f64;
assert!(circle.subs(t).distance(bspcurve.subs(t)) < 0.02);
assert!((circle.der(t) - bspcurve.der(t)).magnitude() < 0.02);
}
Trait Implementations§
source§impl<P: ControlPoint<f64>> BoundedCurve for BSplineCurve<P>
impl<P: ControlPoint<f64>> BoundedCurve for BSplineCurve<P>
source§impl<P: Clone> Clone for BSplineCurve<P>
impl<P: Clone> Clone for BSplineCurve<P>
source§fn clone(&self) -> BSplineCurve<P>
fn clone(&self) -> BSplineCurve<P>
1.0.0 · source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read moresource§impl<P: ControlPoint<f64> + Tolerance> Concat<BSplineCurve<P>> for BSplineCurve<P>
impl<P: ControlPoint<f64> + Tolerance> Concat<BSplineCurve<P>> for BSplineCurve<P>
source§fn try_concat(&self, other: &BSplineCurve<P>) -> Result<Self, ConcatError<P>>
fn try_concat(&self, other: &BSplineCurve<P>) -> Result<Self, ConcatError<P>>
Concats two B-spline curves.
§Examples
use truck_geometry::prelude::*;
§Failure
If the back of the knot vector of self
does not coincides with the front of the one of other
,
use truck_geometry::prelude::*;
use truck_geotrait::traits::ConcatError;
let knot_vec0 = KnotVec::from(vec![0.0, 0.0, 1.0, 1.0]);
let ctrl_pts0 = vec![Vector2::new(0.0, 0.0), Vector2::new(1.0, 1.0)];
let mut bspcurve0 = BSplineCurve::new(knot_vec0, ctrl_pts0);
let knot_vec1 = KnotVec::from(vec![2.0, 2.0, 3.0, 3.0]);
let ctrl_pts1 = vec![Vector2::new(1.0, 1.0), Vector2::new(2.0, 2.0)];
let mut bspcurve1 = BSplineCurve::new(knot_vec1, ctrl_pts1);
assert_eq!(bspcurve0.try_concat(&mut bspcurve1), Err(ConcatError::DisconnectedParameters(1.0, 2.0)));
source§type Output = BSplineCurve<P>
type Output = BSplineCurve<P>
source§impl<P: ControlPoint<f64> + Tolerance> Cut for BSplineCurve<P>
impl<P: ControlPoint<f64> + Tolerance> Cut for BSplineCurve<P>
source§fn cut(&mut self, t: f64) -> BSplineCurve<P>
fn cut(&mut self, t: f64) -> BSplineCurve<P>
self
and returns the later curve.source§impl<P: Debug> Debug for BSplineCurve<P>
impl<P: Debug> Debug for BSplineCurve<P>
source§impl<'de, P> Deserialize<'de> for BSplineCurve<P>where
P: Deserialize<'de>,
impl<'de, P> Deserialize<'de> for BSplineCurve<P>where
P: Deserialize<'de>,
source§fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>where
D: Deserializer<'de>,
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>where
D: Deserializer<'de>,
source§impl<V: Homogeneous<f64>> From<BSplineCurve<<V as Homogeneous<f64>>::Point>> for NurbsCurve<V>
impl<V: Homogeneous<f64>> From<BSplineCurve<<V as Homogeneous<f64>>::Point>> for NurbsCurve<V>
source§fn from(bspcurve: BSplineCurve<V::Point>) -> NurbsCurve<V>
fn from(bspcurve: BSplineCurve<V::Point>) -> NurbsCurve<V>
source§impl IncludeCurve<BSplineCurve<Point2<f64>>> for BSplineSurface<Point2>
impl IncludeCurve<BSplineCurve<Point2<f64>>> for BSplineSurface<Point2>
source§impl IncludeCurve<BSplineCurve<Point3<f64>>> for BSplineSurface<Point3>
impl IncludeCurve<BSplineCurve<Point3<f64>>> for BSplineSurface<Point3>
source§impl IncludeCurve<BSplineCurve<Point3<f64>>> for NurbsSurface<Vector4>
impl IncludeCurve<BSplineCurve<Point3<f64>>> for NurbsSurface<Vector4>
source§impl IncludeCurve<BSplineCurve<Point3<f64>>> for Plane
impl IncludeCurve<BSplineCurve<Point3<f64>>> for Plane
source§impl<'a> IncludeCurve<BSplineCurve<Point3<f64>>> for RevolutedCurve<&'a BSplineCurve<Point3>>
impl<'a> IncludeCurve<BSplineCurve<Point3<f64>>> for RevolutedCurve<&'a BSplineCurve<Point3>>
source§impl<'a> IncludeCurve<BSplineCurve<Point3<f64>>> for RevolutedCurve<&'a NurbsCurve<Vector4>>
impl<'a> IncludeCurve<BSplineCurve<Point3<f64>>> for RevolutedCurve<&'a NurbsCurve<Vector4>>
source§impl IncludeCurve<BSplineCurve<Point3<f64>>> for RevolutedCurve<BSplineCurve<Point3>>
impl IncludeCurve<BSplineCurve<Point3<f64>>> for RevolutedCurve<BSplineCurve<Point3>>
source§impl IncludeCurve<BSplineCurve<Point3<f64>>> for RevolutedCurve<NurbsCurve<Vector4>>
impl IncludeCurve<BSplineCurve<Point3<f64>>> for RevolutedCurve<NurbsCurve<Vector4>>
source§impl IncludeCurve<BSplineCurve<Point3<f64>>> for Sphere
impl IncludeCurve<BSplineCurve<Point3<f64>>> for Sphere
source§impl<P: Clone> Invertible for BSplineCurve<P>
impl<P: Clone> Invertible for BSplineCurve<P>
source§impl<P> ParameterDivision1D for BSplineCurve<P>where
P: ControlPoint<f64> + EuclideanSpace<Scalar = f64, Diff = <P as ControlPoint<f64>>::Diff> + MetricSpace<Metric = f64> + HashGen<f64>,
impl<P> ParameterDivision1D for BSplineCurve<P>where
P: ControlPoint<f64> + EuclideanSpace<Scalar = f64, Diff = <P as ControlPoint<f64>>::Diff> + MetricSpace<Metric = f64> + HashGen<f64>,
source§impl<P: ControlPoint<f64>> ParameterTransform for BSplineCurve<P>
impl<P: ControlPoint<f64>> ParameterTransform for BSplineCurve<P>
source§fn parameter_transform(&mut self, scalar: f64, move: f64) -> &mut Self
fn parameter_transform(&mut self, scalar: f64, move: f64) -> &mut Self
source§fn parameter_transformed(&self, scalar: f64, move: f64) -> Self
fn parameter_transformed(&self, scalar: f64, move: f64) -> Self
source§fn parameter_normalization(&mut self) -> &mut Self
fn parameter_normalization(&mut self) -> &mut Self
(0.0, 1.0)
.source§impl<P: ControlPoint<f64>> ParametricCurve for BSplineCurve<P>
impl<P: ControlPoint<f64>> ParametricCurve for BSplineCurve<P>
source§fn subs(&self, t: f64) -> P
fn subs(&self, t: f64) -> P
Substitutes to B-spline curve.
§Examples
use truck_geometry::prelude::*;
let knot_vec = KnotVec::from(vec![-1.0, -1.0, -1.0, 1.0, 1.0, 1.0]);
let ctrl_pts = vec![Vector2::new(-1.0, 1.0), Vector2::new(0.0, -1.0), Vector2::new(1.0, 1.0)];
let bspcurve = BSplineCurve::new(knot_vec, ctrl_pts);
// bspcurve coincides with (t, t * t) in the range [-1.0..1.0].
const N: usize = 100; // sample size
for i in 0..=N {
let t = -1.0 + 2.0 * (i as f64) / (N as f64);
assert_near2!(bspcurve.subs(t), Vector2::new(t, t * t));
}
source§fn der(&self, t: f64) -> P::Diff
fn der(&self, t: f64) -> P::Diff
Substitutes to the derived B-spline curve.
§Examples
use truck_geometry::prelude::*;
let knot_vec = KnotVec::bezier_knot(2);
let ctrl_pts = vec![Vector2::new(0.0, 0.0), Vector2::new(0.5, 0.0), Vector2::new(1.0, 1.0)];
let bspcurve = BSplineCurve::new(knot_vec, ctrl_pts);
// `bpscurve = (t, t^2), derived = (1, 2t)`
const N : usize = 100; // sample size
for i in 0..=N {
let t = 1.0 / (N as f64) * (i as f64);
assert_near2!(bspcurve.der(t), Vector2::new(1.0, 2.0 * t));
}
source§fn der2(&self, t: f64) -> P::Diff
fn der2(&self, t: f64) -> P::Diff
Substitutes to the 2nd-ord derived B-spline curve.
§Examples
use truck_geometry::prelude::*;
let knot_vec = KnotVec::bezier_knot(3);
let ctrl_pts = vec![
Vector2::new(0.0, 0.0),
Vector2::new(1.0, 1.0),
Vector2::new(0.0, 1.0),
Vector2::new(1.0, 0.0),
];
let bspcurve = BSplineCurve::new(knot_vec, ctrl_pts);
// bpscurve = (4t^3 - 6t^2 + 3t, -3t^2 + 3t), derived2 = (24t - 12, -6)
const N : usize = 100; // sample size
for i in 0..=N {
let t = 1.0 / (N as f64) * (i as f64);
assert_near2!(bspcurve.der2(t), Vector2::new(24.0 * t - 12.0, -6.0));
}
source§fn parameter_range(&self) -> ParameterRange
fn parameter_range(&self) -> ParameterRange
source§impl<P: PartialEq> PartialEq for BSplineCurve<P>
impl<P: PartialEq> PartialEq for BSplineCurve<P>
source§impl<P> SearchNearestParameter<D1> for BSplineCurve<P>where
P: ControlPoint<f64> + EuclideanSpace<Scalar = f64, Diff = <P as ControlPoint<f64>>::Diff> + MetricSpace<Metric = f64> + Tolerance,
<P as ControlPoint<f64>>::Diff: InnerSpace<Scalar = f64> + Tolerance,
impl<P> SearchNearestParameter<D1> for BSplineCurve<P>where
P: ControlPoint<f64> + EuclideanSpace<Scalar = f64, Diff = <P as ControlPoint<f64>>::Diff> + MetricSpace<Metric = f64> + Tolerance,
<P as ControlPoint<f64>>::Diff: InnerSpace<Scalar = f64> + Tolerance,
source§fn search_nearest_parameter<H: Into<SPHint1D>>(
&self,
point: P,
hint: H,
trial: usize,
) -> Option<f64>
fn search_nearest_parameter<H: Into<SPHint1D>>( &self, point: P, hint: H, trial: usize, ) -> Option<f64>
Searches the parameter t
which minimize |self(t) - point| by Newton’s method with initial guess hint
.
Returns None
if the number of attempts exceeds trial
i.e. if trial == 0
, then the trial is only one time.
§Examples
use truck_geometry::prelude::*;
let knot_vec = KnotVec::from(
vec![0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 3.0, 3.0]
);
let ctrl_pts = vec![
Point3::new(0.0, 0.0, 0.0),
Point3::new(1.0, 0.0, 0.0),
Point3::new(1.0, 1.0, 0.0),
Point3::new(0.0, 1.0, 0.0),
Point3::new(0.0, 1.0, 1.0),
];
let bspcurve = BSplineCurve::new(knot_vec, ctrl_pts);
let pt = ParametricCurve::subs(&bspcurve, 1.2);
let t = bspcurve.search_nearest_parameter(pt, Some(0.8), 100).unwrap();
assert_near!(t, 1.2);
§Remarks
It may converge to a local solution depending on the hint.
use truck_geometry::prelude::*;
let knot_vec = KnotVec::from(
vec![0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 3.0, 3.0]
);
let ctrl_pts = vec![
Point3::new(0.0, 0.0, 0.0),
Point3::new(1.0, 0.0, 0.0),
Point3::new(1.0, 1.0, 0.0),
Point3::new(0.0, 1.0, 0.0),
Point3::new(0.0, 1.0, 1.0),
];
let bspcurve = BSplineCurve::new(knot_vec, ctrl_pts);
let pt = Point3::new(0.0, 0.5, 1.0);
let t = bspcurve.search_nearest_parameter(pt, Some(0.8), 100).unwrap();
let pt0 = ParametricCurve::subs(&bspcurve, t);
let pt1 = ParametricCurve::subs(&bspcurve, 3.0);
// the point corresponding the obtained parameter is not
// the globally nearest point in the curve.
assert!((pt0 - pt).magnitude() > (pt1 - pt).magnitude());
source§impl<P> SearchParameter<D1> for BSplineCurve<P>where
P: ControlPoint<f64> + EuclideanSpace<Scalar = f64, Diff = <P as ControlPoint<f64>>::Diff> + MetricSpace<Metric = f64>,
<P as ControlPoint<f64>>::Diff: InnerSpace<Scalar = f64> + Tolerance,
impl<P> SearchParameter<D1> for BSplineCurve<P>where
P: ControlPoint<f64> + EuclideanSpace<Scalar = f64, Diff = <P as ControlPoint<f64>>::Diff> + MetricSpace<Metric = f64>,
<P as ControlPoint<f64>>::Diff: InnerSpace<Scalar = f64> + Tolerance,
source§impl<P> Serialize for BSplineCurve<P>where
P: Serialize,
impl<P> Serialize for BSplineCurve<P>where
P: Serialize,
source§impl<M, P> Transformed<M> for BSplineCurve<P>where
P: EuclideanSpace,
M: Transform<P>,
impl<M, P> Transformed<M> for BSplineCurve<P>where
P: EuclideanSpace,
M: Transform<P>,
source§fn transform_by(&mut self, trans: M)
fn transform_by(&mut self, trans: M)
trans
.source§fn transformed(&self, trans: T) -> Self
fn transformed(&self, trans: T) -> Self
trans
.impl<P> StructuralPartialEq for BSplineCurve<P>
Auto Trait Implementations§
impl<P> Freeze for BSplineCurve<P>
impl<P> RefUnwindSafe for BSplineCurve<P>where
P: RefUnwindSafe,
impl<P> Send for BSplineCurve<P>where
P: Send,
impl<P> Sync for BSplineCurve<P>where
P: Sync,
impl<P> Unpin for BSplineCurve<P>where
P: Unpin,
impl<P> UnwindSafe for BSplineCurve<P>where
P: UnwindSafe,
Blanket Implementations§
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
source§unsafe fn clone_to_uninit(&self, dst: *mut T)
unsafe fn clone_to_uninit(&self, dst: *mut T)
clone_to_uninit
)