Struct bezier_nd::Bezier

source ·
pub struct Bezier<F, V, const D: usize>where
    F: Float,
    V: Vector<F, D>,{ /* private fields */ }
Expand description

A Bezier is an implementation of a linear, quadratic or cubic Bezier curve using a parameter which has the Float trait, and consists of points that have the Vector trait.

To split a quadratic bezier at t is simple: the split point is p(t), and the two control points (cl, cr) are:

cl(t) = u.p0 + t.c ; cr = u.c + t.p1

Hence the Quadratic Bezier between t0 and t1 can be calculated by splitting to get the right-hand Bezier of t0->1, and splitting this to get the left-hand Bezier at (t1-t0)/u0 = (t2,u2)

Note t2 = (t1-t0)/u0; u2=1-t2 = (u0+t0-t1)/u0 = (1-t1)/u0 = u1/u0

   cl(t0) = u0.p0 + t0.c
   cr(t0) = u0.c  + t1.p1
    p(t0) = u0.cl(t0)  + t0.cr(t0)

Bezier t0->1 : p(t0), cr(t0), p1

 c(t0,t1)  = u2.p(t0)  + t2.cr(t0)
           = u2.u0.cl(t0) + u2.t0.cr(t0) + t2.cr(t0)
           = u2.u0.cl(t0) + (u2.t0+t2).cr(t0)
 But u2.u0    = u1
 And u2.t0+t2 = u1/u0.t0+(t1-t0)/u0
              = (t0.u1+t1-t0)/u0
              = (t0 - t1.t0 + t1 - t0) / u0
              = (t1 - t1.t0) / u0
              = t1(1-t0) / (1-t0)
              = t1

Hence

 c(t0,t1)  = u1.cl(t0) + t1.cr(t0)
           = u0.u1.p0 + u1.t0.c + u0.t1.c + t0.t1.p1
           = u0.u1.p0 + (u1.t0+u0.t1).c + t0.t1.p1

And the points are:

     p(t0) = u0.u0.p0 + 2(u0.t0).c + t0.t0.p1
     p(t1) = u1.u1.p0 + 2(u1.t1).c + t1.t1.p1

Implementations§

source§

impl<F, V, const D: usize> Bezier<F, V, D>where F: Float, V: Vector<F, D>,

source

pub fn borrow_pt(&self, index: usize) -> &V

Borrow the start or end point of the Bezier - index 0 gives the start point, index 1 the end point

It can also be used to borrow the control points (which are index 2 and 3) if they are used for the Bezier; this is not generally required, as a Bezier is designed to be rendered into straight lines.

source

pub fn endpoints(self) -> (V, V)

Deconstruct and get the endpoints

source

pub fn get_distance(&self) -> F

Get the distance between the start and end points

This is not the same as the length of the Bezier, as it may be a curve.

source

pub fn line(p0: &V, p1: &V) -> Self

Create a new Bezier that is a line between two points

source

pub fn quadratic(p0: &V, c: &V, p1: &V) -> Self

Create a new Quadratic Bezier that is a line between two points with one absolute control points

source

pub fn cubic(p0: &V, c0: &V, c1: &V, p1: &V) -> Self

Create a new Cubic Bezier that is a line between two points with two absolute control points

source

pub fn degree(&self) -> usize

Returns number of points used for the Bezier (2 to 4)

Cubic beziers return 3 Quadratic beziers return 2 Linear beziers (lines…) return 1

source

pub fn scale(&mut self, s: F)

Scale the Bezier by applying the scale factor to all of the points

This is an example of the Bezier::map_pts method

source

pub fn map_pts<Map: Fn(V) -> V>(&mut self, map: Map)

Apply a function to all of the points in the Bezier

source

pub fn point_at(&self, t: F) -> V

Returns the point at parameter ‘t’ along the Bezier

source

pub fn tangent_at(&self, t: F) -> V

Returns the tangent vector at parameter ‘t’ along the Bezier

Note that this is not necessarily a unit vector

source

pub fn bisect(&self) -> (Self, Self)

Returns two Bezier’s that split the curve at parameter t=0.5

For quadratics the midpoint is 1/4(p0 + 2*c + p1)

source

pub fn bezier_between(&self, t0: F, t1: F) -> Self

Returns the Bezier that is a subset of this Bezier between two parameters 0 <= t0 < t1 <= 1

source

pub fn as_lines(&self, straightness: F) -> BezierLineIter<F, V, D>

Return a BezierLineIter iterator that provides line segments when the Bezier is broken down into ‘straight’ enough through bisection.

source

pub fn as_points(&self, straightness: F) -> BezierPointIter<F, V, D>

Return a BezierPointIter iterator that provides points along the curve when the Bezier is broken down into ‘straight’ enough through bisection.

source

pub fn is_straight(&self, straightness: F) -> bool

Returns true if the Bezier is straighter than a ‘straightness’ measure

A linear bezier is always straight.

A straightness measure for a quadratic bezier (one control point) can be thought of as the ratio between the area of the triangle formed by the two endpoints and the control point (three points must form a triangle on a plane) in relation to the distance between the endpoints (the curve will be entirely within the triangle.

A straightness measure for a cubic bezier (two control points) can be though of similarly, except that the curve now must fit within a volume given by the two control points and the endpoints; hence the straightness is measured in some way by the volume in relation to the distance between the endpoints, but also should be no straighter than the area of any one control point in relation to the disnance between the endpoints (the Bezier may be a planar curve that is quite unstraight but with a volume of zero).

Hence the straightness here is defined as the sum of (the ratio between (the distance of each control point from the straight line between the two endpoints) and (the distance between the two endpoints))

straightness is thus independent of the length of the Bezier

source

pub fn length(&self, straightness: F) -> F

Calculates the length of the Bezier when it is rendered down to the given a straightness

straightness is independent of the length of the Bezier

source

pub fn t_of_distance(&self, straightness: F, distance: F) -> (F, bool)

Calculates the parameter ‘t’ at a certain distance along the Bezier given a straightness

straightness is independent of the length of the Bezier

Returns t,true if the distance is along the Bezier

Returns 0.,false if the distance is before the start of the Bezier

Returns 1.,false if the distance is beyond the end of the Bezier

source

pub fn arc(angle: F, radius: F, center: &V, unit: &V, normal: &V, rotate: F) -> Self

Create a Cubic Bezier that approximates closely a circular arc

The arc has a center C, a radius R, and is of an angle (should be <= PI/2).

The arc sweeps through points a distance R from C, in a circle using a pair of the planar unit vectors in the vector space for the points.

The arc will be between an angle A1 and A2, where A2-A1 == angle, and A1==rotate

source

pub fn of_round_corner(corner: &V, v0: &V, v1: &V, radius: F) -> Self

Create a Cubic Bezier that is a circular arc focused on the corner point, with v0 and v1 are vectors IN to the point (P)

As it is a circular arc we have a kite P, P+k.v0, C, P+k.v1, where

|P+k.v0 - C| = |P+k.v1 - C| = r; |P-C| = d (i.e. side lengths are r, r, k, k)

with two corners being right-angles. (and d is the length of the kite diagonal opposite these right-angles).

The kite is formed from two d, r, k right-angled triangles; it has two other angles, alpha and 2theta, (alpha = angle between v0 and v1). Hence alpha = 180 - 2theta, theta = 90-(alpha/2)

Hence d^2 = r^2 + k^2; r/d = cos(theta), k/d=sin(theta)

We know cos(alpha) = v0.v1 (assuming unit vectors).

cos(alpha) = cos(180-2*theta)
           = -cos(2*theta)
           = -(2cos^2(theta) - 1)
           = 1 - 2cos^2(theta)

cos^2(theta) = (1 - cos(alpha)) / 2 = r^2/d^2

sin^2(theta) = (1 + cos(alpha)) / 2

=> d^2 = 2*r^2  / (1 - cos(alpha))

Hence also k^2, and hence d and k.

Then we require an arc given the angle of the arc is 2*theta

source

pub fn center_radius_of_bezier_arc(&self) -> (V, F)

Find the center and radius of a Bezier if it is assumed to be a circular arc

what is the center of the circle given point p0 and unit tangent t0 and point p1 and unit tangent t1

|p0-c|^2 = |p1-c|^2 = r^2
(p0-c) . t0 = 0
(p1-c) . t1 = 0

Consider c = k0.t0 + k1.t1

(given t0.t0 == 1 and t1.t1==1)

(p0-c) . t0 = (p0 - k0.t0 - k1.t1).t0 = 0
      p0.t0 = k0 + k1(t1.t0)

similarly

      p1.t1 = k1 + k0(t1.t0)

hence

 (t1.t0) * (p1.t1)         = k0.(t1.t0)^2 + k1(t1.t0)
 p0.t0 - (t1.t0) * (p1.t1) = k0 ( 1 - (t1.t0)^2)
 k0 = (p0.t0 - p1.t1 * t1.t0) / ( 1 - (t1.t0)^2)
 k1 = (p1.t1 - p0.t0 * t1.t0) / ( 1 - (t1.t0)^2)

Trait Implementations§

source§

impl<F, V, const D: usize> Clone for Bezier<F, V, D>where F: Float + Clone, V: Vector<F, D> + Clone,

source§

fn clone(&self) -> Bezier<F, V, D>

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<F, V, const D: usize> Debug for Bezier<F, V, D>where F: Float + Debug, V: Vector<F, D> + Debug,

source§

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

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

impl<F, V, const D: usize> Display for Bezier<F, V, D>where F: Float, V: Vector<F, D>,

source§

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

Display the `Bezier’ as sets of points

source§

impl<F, V, const D: usize> PartialEq<Bezier<F, V, D>> for Bezier<F, V, D>where F: Float + PartialEq, V: Vector<F, D> + PartialEq,

source§

fn eq(&self, other: &Bezier<F, V, D>) -> bool

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

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

This method tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
source§

impl<F, V, const D: usize> Copy for Bezier<F, V, D>where F: Float + Copy, V: Vector<F, D> + Copy,

source§

impl<F, V, const D: usize> StructuralPartialEq for Bezier<F, V, D>where F: Float, V: Vector<F, D>,

Auto Trait Implementations§

§

impl<F, V, const D: usize> RefUnwindSafe for Bezier<F, V, D>where F: RefUnwindSafe, V: RefUnwindSafe,

§

impl<F, V, const D: usize> Send for Bezier<F, V, D>where F: Send, V: Send,

§

impl<F, V, const D: usize> Sync for Bezier<F, V, D>where F: Sync, V: Sync,

§

impl<F, V, const D: usize> Unpin for Bezier<F, V, D>where F: Unpin, V: Unpin,

§

impl<F, V, const D: usize> UnwindSafe for Bezier<F, V, D>where F: UnwindSafe, V: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

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

const: unstable · source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

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

const: unstable · source§

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

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

const: unstable · source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

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

const: unstable · 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 Twhere T: Clone,

§

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> ToString for Twhere T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

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

§

type Error = Infallible

The type returned in the event of a conversion error.
const: unstable · source§

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

Performs the conversion.
source§

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

§

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

The type returned in the event of a conversion error.
const: unstable · source§

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

Performs the conversion.