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>

source

pub fn new(knot_vec: KnotVec, control_points: Vec<P>) -> BSplineCurve<P>

constructor.

§Arguments
  • knot_vec - the knot vector
  • control_points - the vector of the control points
§Panics

Panics occurs if:

  • There are no control points.
  • The number of knots is more than the one of control points.
  • The range of the knot vector is zero.
source

pub fn try_new( knot_vec: KnotVec, control_points: Vec<P>, ) -> Result<BSplineCurve<P>>

constructor.

§Arguments
  • knot_vec - the knot vector
  • control_points - the vector of the control points
§Failures
source

pub const fn new_unchecked( knot_vec: KnotVec, control_points: Vec<P>, ) -> BSplineCurve<P>

constructor.

§Arguments
  • knot_vec - the knot vector
  • control_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.

source

pub fn debug_new(knot_vec: KnotVec, control_points: Vec<P>) -> BSplineCurve<P>

constructor.

§Arguments
  • knot_vec - the knot vector
  • control_points - the vector of the control points
§Remarks

This method checks the rules for constructing B-spline curve in the debug mode.
The programmer must guarantee these conditions before using this method.

source

pub const fn knot_vec(&self) -> &KnotVec

Returns the reference of the knot vector

source

pub fn knot(&self, idx: usize) -> f64

Returns the idxth knot

source

pub const fn control_points(&self) -> &Vec<P>

Returns the reference of the control points.

source

pub fn control_point(&self, idx: usize) -> &P

Returns the reference of the control point corresponding to the index idx.

source

pub fn control_point_mut(&mut self, idx: usize) -> &mut P

Returns the mutable reference of the control point corresponding to index idx.

source

pub fn control_points_mut(&mut self) -> impl Iterator<Item = &mut P>

Returns the iterator on all control points

source

pub fn transform_control_points<F: FnMut(&mut P)>(&mut self, f: F)

Apply the given transformation to all control points.

source

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);
source

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));
}
source

pub fn is_clamped(&self) -> bool

Returns whether the knot vector is clamped or not.

source

pub fn knot_normalize(&mut self) -> &mut Self

Normalizes the knot vector

source

pub fn knot_translate(&mut self, x: f64) -> &mut Self

Translates the knot vector

source§

impl<P: ControlPoint<f64>> BSplineCurve<P>

source

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));
source

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>

source

pub fn lift_up(curve: BSplineCurve<V::Point>) -> Self

lift up control points to homogeneous coordinate.

source§

impl<P: ControlPoint<f64> + Tolerance> BSplineCurve<P>

source

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());
source

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));
source

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())
source

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)));
source

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));
source

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);
source

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));
source

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));
source

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()));
source

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));
}
source

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);
source

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));
source

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)| < TOLERANCEfor 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,

source

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>

source

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,

source

pub fn cubic_approximation<C>( curve: &C, range: (f64, f64), p_tol: f64, d_tol: f64, trials: usize, ) -> Option<Self>
where C: ParametricCurve<Point = P, Vector = <P as EuclideanSpace>::Diff>,

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>

source§

fn range_tuple(&self) -> (f64, f64)

Return the ends of parameter_range by tuple.
source§

fn front(&self) -> Self::Point

The front end point of the curve.
source§

fn back(&self) -> Self::Point

The back end point of the curve.
source§

impl<P: Clone> Clone for BSplineCurve<P>

source§

fn clone(&self) -> BSplineCurve<P>

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl<P: ControlPoint<f64> + Tolerance> Concat<BSplineCurve<P>> for BSplineCurve<P>

source§

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>

The result of concat two curves
source§

fn concat(&self, rhs: &Rhs) -> Self::Output

Try concat two curves. Read more
source§

impl<P: ControlPoint<f64> + Tolerance> Cut for BSplineCurve<P>

source§

fn cut(&mut self, t: f64) -> BSplineCurve<P>

Cuts one curve into two curves. Assigns the former curve to self and returns the later curve.
source§

impl<P: Debug> Debug for BSplineCurve<P>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

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>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl<V: Homogeneous<f64>> From<BSplineCurve<<V as Homogeneous<f64>>::Point>> for NurbsCurve<V>

source§

fn from(bspcurve: BSplineCurve<V::Point>) -> NurbsCurve<V>

Converts to this type from the input type.
source§

impl IncludeCurve<BSplineCurve<Point2<f64>>> for BSplineSurface<Point2>

source§

fn include(&self, curve: &BSplineCurve<Point2>) -> bool

Returns whether the curve curve is included in the surface self.
source§

impl IncludeCurve<BSplineCurve<Point3<f64>>> for BSplineSurface<Point3>

source§

fn include(&self, curve: &BSplineCurve<Point3>) -> bool

Returns whether the curve curve is included in the surface self.
source§

impl IncludeCurve<BSplineCurve<Point3<f64>>> for NurbsSurface<Vector4>

source§

fn include(&self, curve: &BSplineCurve<Point3>) -> bool

Returns whether the curve curve is included in the surface self.
source§

impl IncludeCurve<BSplineCurve<Point3<f64>>> for Plane

source§

fn include(&self, curve: &BSplineCurve<Point3>) -> bool

Returns whether the curve curve is included in the surface self.
source§

impl<'a> IncludeCurve<BSplineCurve<Point3<f64>>> for RevolutedCurve<&'a BSplineCurve<Point3>>

source§

fn include(&self, curve: &BSplineCurve<Point3>) -> bool

Returns whether the curve curve is included in the surface self.
source§

impl<'a> IncludeCurve<BSplineCurve<Point3<f64>>> for RevolutedCurve<&'a NurbsCurve<Vector4>>

source§

fn include(&self, curve: &BSplineCurve<Point3>) -> bool

Returns whether the curve curve is included in the surface self.
source§

impl IncludeCurve<BSplineCurve<Point3<f64>>> for RevolutedCurve<BSplineCurve<Point3>>

source§

fn include(&self, curve: &BSplineCurve<Point3>) -> bool

Returns whether the curve curve is included in the surface self.
source§

impl IncludeCurve<BSplineCurve<Point3<f64>>> for RevolutedCurve<NurbsCurve<Vector4>>

source§

fn include(&self, curve: &BSplineCurve<Point3>) -> bool

Returns whether the curve curve is included in the surface self.
source§

impl IncludeCurve<BSplineCurve<Point3<f64>>> for Sphere

source§

fn include(&self, curve: &BSplineCurve<Point3>) -> bool

Returns whether the curve curve is included in the surface self.
source§

impl<P: Clone> Invertible for BSplineCurve<P>

source§

fn invert(&mut self)

Inverts self
source§

fn inverse(&self) -> Self

Returns the inverse.
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>,

source§

type Point = P

The curve is in the space of Self::Point.
source§

fn parameter_division(&self, range: (f64, f64), tol: f64) -> (Vec<f64>, Vec<P>)

Creates the curve division (parameters, corresponding points). Read more
source§

impl<P: ControlPoint<f64>> ParameterTransform for BSplineCurve<P>

source§

fn parameter_transform(&mut self, scalar: f64, move: f64) -> &mut Self

parameter range move by affine transformation Read more
source§

fn parameter_transformed(&self, scalar: f64, move: f64) -> Self

parameter range move by affine transformation Read more
source§

fn parameter_normalization(&mut self) -> &mut Self

Makes the parameter range (0.0, 1.0).
source§

impl<P: ControlPoint<f64>> ParametricCurve for BSplineCurve<P>

source§

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

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

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§

type Point = P

The curve is in the space of Self::Point.
source§

type Vector = <P as ControlPoint<f64>>::Diff

The derivation vector of the curve.
source§

fn parameter_range(&self) -> ParameterRange

Returns default parameter range
source§

fn try_range_tuple(&self) -> Option<(f64, f64)>

Return the ends of parameter_range by tuple. If the range is unbounded, return `None``.
source§

fn period(&self) -> Option<f64>

None in default implementation; Some(period) if periodic.
source§

impl<P: PartialEq> PartialEq for BSplineCurve<P>

source§

fn eq(&self, other: &BSplineCurve<P>) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
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,

source§

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§

type Point = P

point
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,

source§

type Point = P

point
source§

fn search_parameter<H: Into<SPHint1D>>( &self, point: P, hint: H, trial: usize, ) -> Option<f64>

Search parameter t such that self.subs(t) is near point.
Returns None if could not find such parameter.
source§

impl<P> Serialize for BSplineCurve<P>
where P: Serialize,

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl<M, P> Transformed<M> for BSplineCurve<P>
where P: EuclideanSpace, M: Transform<P>,

source§

fn transform_by(&mut self, trans: M)

transform by trans.
source§

fn transformed(&self, trans: T) -> Self

transformed geometry by trans.
source§

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> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> CloneToUninit for T
where T: Clone,

source§

unsafe fn clone_to_uninit(&self, dst: *mut T)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dst. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> ToOwned for T
where T: Clone,

source§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

source§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

source§

fn vzip(self) -> V

source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

source§

impl<C> ParametricCurve2D for C
where C: ParametricCurve<Point = Point2<f64>, Vector = Vector2<f64>>,

source§

impl<C> ParametricCurve3D for C
where C: ParametricCurve<Point = Point3<f64>, Vector = Vector3<f64>>,