NURBSCurve< D > Class Template Reference

#include <NURBSMath.h>

Inheritance diagram for NURBSCurve< D >:

Public Member Functions

 NURBSCurve ()
 
 NURBSCurve (const NURBSCurve< D > &other)
 
template<typename Dummy = Result<void>>
std::enable_if_t< D !=DYNAMICDEGREE, Dummy > Init (Int points, NURBSCURVE_KNOTMODE mode=NURBSCURVE_KNOTMODE::CLAMPED_UNIFORM)
 
template<typename Dummy = Result<void>>
std::enable_if_t< D==DYNAMICDEGREE, Dummy > Init (Int points, Int degree, NURBSCURVE_KNOTMODE mode=NURBSCURVE_KNOTMODE::CLAMPED_UNIFORM)
 
void Reset ()
 
Result< VectorEvaluateAt (Float s) const
 
Result< VectorDeriveAt (Float s) const
 
Result< IntGetDegree () const
 
Result< IntGetMaxDegree () const
 
Int GetPointCount () const
 
Result< IntGetWeightCount () const
 
Result< VectorGetPoint (Int i) const
 
Result< Vector4dGetPointWithWeight (Int i) const
 
const Block< const Vector4dGetPointsWithWeights () const
 
Result< FloatGetWeight (Int i) const
 
const BaseArray< Float > & GetKnots () const
 
NURBSCURVE_KNOTMODE GetKnotMode () const
 
Result< void > SetPoint (Int i, const Vector &point)
 
Result< void > SetPointWithWeight (Int i, const Vector4d &point)
 
Result< void > ChangePoints (const Block< const Vector > &points)
 
Result< void > SetPoints (const Block< const Vector > &points)
 
Result< void > SetPointsWithWeights (const Block< const Vector4d > &points)
 
Result< void > SetWeight (Int i, Float weight)
 
Result< void > ChangeWeights (const Block< const Float32 > &weights)
 
Result< void > ChangeWeights (const Block< const Float > &weights)
 
Result< void > SetKnot (Int i, Float knot)
 
Result< void > SetKnots (NURBSCURVE_KNOTMODE mode)
 
Result< void > SetKnots (const Block< const Float > &knots)
 
Result< void > SetKnots (Block< const Float > &&knots)
 
Result< Pair< Block< Vector4d >, Int > > InsertKnot (Float s, Int nTimes)
 
Result< Pair< Block< Vector4d >, Int > > AddControlPoint (const Float t)
 

Protected Member Functions

 NURBSCurve (const Interface::MTable &derivedTable)
 
Result< VectorDeriveAt (Float u, Int span) const
 
Result< Pair< Block< Vector4d >, Int > > InsertKnot (Float u, Int span, Int nTimes)
 
Result< VectorEvaluateAt (Float u, Int span) const
 
Float MapStoU (Float s) const
 
Float MapUtoS (Float u) const
 
Float GetUmin () const
 
Float GetUmax () const
 
Result< IntFindSpan (Float u) const
 
Result< KnotInfoGetKnotInfo (Int k)
 
Result< void > CheckForKnotConsistency ()
 
Result< void > InitKnots (NURBSCURVE_KNOTMODE mode)
 
maxon::Result< void > ComputeBasisFunctions (Float u, Int span, Int maxDerivationDegree, detail::SmallStackMatrix< 2+1, D+1, Float > &basisFunctionsOutput) const
 
Result< IntGetKnotCount () const
 
Result< Vector4dCalculatePointFromBasisFunctions (Int span, Int deg, const detail::SmallStackMatrix< 2+1, D+1, Float > &basisFunctions) const
 
Result< void > InitInternal (Int numPoints, Int degree, NURBSCURVE_KNOTMODE mode)
 
Result< void > InitInternal (Int degree, const BaseArray< Vector4d > &points, const BaseArray< Float > &knots)
 
template<Int OtherN>
Result< void > InitInternal (const NURBSCurve< OtherN > &other)
 
Result< FloatGetKnot (Int i) const
 
template<typename T >
Result< void > ChangeWeightsInternal (const Block< const T > &weights)
 
- Protected Member Functions inherited from NURBSCurveInterface
MAXON_METHOD Result< VectorEvaluateAt (Float s) const
 
MAXON_METHOD Result< VectorDeriveAt (Float s) const
 
MAXON_METHOD Result< IntGetDegree () const
 
MAXON_METHOD Result< IntGetMaxDegree () const
 
MAXON_METHOD Int GetPointCount () const
 
MAXON_METHOD Result< IntGetWeightCount () const
 
MAXON_METHOD Result< VectorGetPoint (Int i) const
 
MAXON_METHOD Result< Vector4dGetPointWithWeight (Int i) const
 
MAXON_METHOD const Block< const Vector4dGetPointsWithWeights () const
 
MAXON_METHOD Result< FloatGetWeight (Int i) const
 
MAXON_METHOD Result< void > SetPoint (Int i, const Vector &point)
 
MAXON_METHOD Result< void > SetPointWithWeight (Int i, const Vector4d &point)
 
MAXON_METHOD Result< void > ChangePoints (const Block< Vector > &points)
 
MAXON_METHOD Result< void > SetPointsWithWeights (const Block< const Vector4d > &points)
 
MAXON_METHOD Result< void > SetWeight (Int i, Float weight)
 
MAXON_METHOD Result< void > ChangeWeights (const Block< const Float > &weights)
 
MAXON_METHOD Result< void > ChangeWeights (const Block< const Float32 > &weights)
 
MAXON_METHOD Result< Pair< Block< Vector4d >, Int > > AddControlPoint (const Float t)
 

Protected Attributes

Int _curveDegree
 

Private Member Functions

 MAXON_IMPLEMENTATION_SIMPLE (NURBSCurve)
 

Private Attributes

NURBSCURVE_KNOTMODE _knotMode
 
BaseArray< Vector4d_points
 
BaseArray< Float_knots
 
Bool _memInit
 

Constructor & Destructor Documentation

◆ NURBSCurve() [1/3]

NURBSCurve ( const Interface::MTable &  derivedTable)
explicitprotected

◆ NURBSCurve() [2/3]

◆ NURBSCurve() [3/3]

NURBSCurve ( const NURBSCurve< D > &  other)

Member Function Documentation

◆ MAXON_IMPLEMENTATION_SIMPLE()

MAXON_IMPLEMENTATION_SIMPLE ( NURBSCurve< D >  )
private

◆ Init() [1/2]

std::enable_if_t<D != DYNAMICDEGREE, Dummy> Init ( Int  points,
NURBSCURVE_KNOTMODE  mode = NURBSCURVE_KNOTMODE::CLAMPED_UNIFORM 
)

◆ Init() [2/2]

std::enable_if_t<D == DYNAMICDEGREE, Dummy> Init ( Int  points,
Int  degree,
NURBSCURVE_KNOTMODE  mode = NURBSCURVE_KNOTMODE::CLAMPED_UNIFORM 
)

◆ Reset()

void Reset ( void  )

◆ EvaluateAt() [1/2]

Result<Vector> EvaluateAt ( Float  s) const

◆ DeriveAt() [1/2]

Result<Vector> DeriveAt ( Float  s) const

◆ GetDegree()

Result<Int> GetDegree ( ) const

◆ GetMaxDegree()

Result<Int> GetMaxDegree ( ) const

◆ GetPointCount()

Int GetPointCount ( void  ) const

◆ GetWeightCount()

Result<Int> GetWeightCount ( ) const

◆ GetPoint()

Result<Vector> GetPoint ( Int  i) const

◆ GetPointWithWeight()

Result<Vector4d> GetPointWithWeight ( Int  i) const

◆ GetPointsWithWeights()

const Block<const Vector4d> GetPointsWithWeights ( ) const

◆ GetWeight()

Result<Float> GetWeight ( Int  i) const

◆ GetKnots()

const BaseArray<Float>& GetKnots ( ) const

◆ GetKnotMode()

NURBSCURVE_KNOTMODE GetKnotMode ( ) const

◆ SetPoint()

Result<void> SetPoint ( Int  i,
const Vector point 
)

◆ SetPointWithWeight()

Result<void> SetPointWithWeight ( Int  i,
const Vector4d point 
)

◆ ChangePoints()

Result<void> ChangePoints ( const Block< const Vector > &  points)

◆ SetPoints()

Result<void> SetPoints ( const Block< const Vector > &  points)

◆ SetPointsWithWeights()

Result<void> SetPointsWithWeights ( const Block< const Vector4d > &  points)

◆ SetWeight()

Result<void> SetWeight ( Int  i,
Float  weight 
)

◆ ChangeWeights() [1/2]

Result<void> ChangeWeights ( const Block< const Float32 > &  weights)

◆ ChangeWeights() [2/2]

Result<void> ChangeWeights ( const Block< const Float > &  weights)

◆ SetKnot()

Result<void> SetKnot ( Int  i,
Float  knot 
)

◆ SetKnots() [1/3]

Result<void> SetKnots ( NURBSCURVE_KNOTMODE  mode)

◆ SetKnots() [2/3]

Result<void> SetKnots ( const Block< const Float > &  knots)

◆ SetKnots() [3/3]

Result<void> SetKnots ( Block< const Float > &&  knots)

◆ InsertKnot() [1/2]

Result<Pair<Block<Vector4d>, Int> > InsertKnot ( Float  s,
Int  nTimes 
)

◆ AddControlPoint()

Result<Pair<Block<Vector4d>, Int> > AddControlPoint ( const Float  t)

◆ DeriveAt() [2/2]

Result<Vector> DeriveAt ( Float  u,
Int  span 
) const
protected

◆ InsertKnot() [2/2]

Result<Pair<Block<Vector4d>, Int> > InsertKnot ( Float  u,
Int  span,
Int  nTimes 
)
protected

This algorithm inserts nTimes new points into the knot vector. The naive way would be to simply insert new points into the vector and be done with it. This would change the curve shape though and the goal of this function is to add additional points into both the knot vector and the control point vector so that the shape of the curve remains unchanged.

This algorithm is also described in "The NURBS Book" on page 151. Inserting a new control point and knot works similarly to the deCasteljau algorithm. When inserting new knots, we need to calculate the appropriate control knots that will keep the curve shape the same. This is done by linearly interpolating the original control points with an interpolation factor alpha. This alpha value is calculated for the relevant control points that affect the insertion location. It is determined by the normalized position of the new knot inside the knot-space width of the original basis functions.

◆ EvaluateAt() [2/2]

Result<Vector> EvaluateAt ( Float  u,
Int  span 
) const
protected

◆ MapStoU()

Float MapStoU ( Float  s) const
protected

◆ MapUtoS()

Float MapUtoS ( Float  u) const
protected

◆ GetUmin()

Float GetUmin ( ) const
protected

◆ GetUmax()

Float GetUmax ( ) const
protected

◆ FindSpan()

Result<Int> FindSpan ( Float  u) const
protected

◆ GetKnotInfo()

Result<KnotInfo> GetKnotInfo ( Int  k)
protected

◆ CheckForKnotConsistency()

Result<void> CheckForKnotConsistency ( )
protected

◆ InitKnots()

Result<void> InitKnots ( NURBSCURVE_KNOTMODE  mode)
protected

◆ ComputeBasisFunctions()

maxon::Result<void> ComputeBasisFunctions ( Float  u,
Int  span,
Int  maxDerivationDegree,
detail::SmallStackMatrix< 2+1, D+1, Float > &  basisFunctionsOutput 
) const
protected

This functions calculates all basis functions of degree 1 to n that overlap the knot span "span". Since for a span that contains the parameter u only one basis function of degree 0 is not 0 this creates a triangular hierarchy of basis functions where each hierarchy level contains degree + 1 basis functions.

This algorithm maps this triangle to an index range from 0 to "curve degree" instead of working with the knot vector indices of the involved basis functions. This reduces memory requirements.

This Algorithm stores this hierarchy in the upper left triangle of a matrix (if 0,0 is the upper left corner) At 0,0 there is the degree 0 basis function value for u, which is always 1.

Calculating the interpolation factors for the parent basis functions requires us to normalize the parameter u in the knot-space width of each of the parent basis functions. Instead of always looking up the knot values for each basis function and then recalculating the normalization the algorithm instead stores the distance of the parameter u to all relevant knots to the left of u into an array. It does the same for all relevant knots to the right of it. This reduces the amount of computation in the inner loops. Bot vectors store their values in increasing distance order. They also exclude the very left most knot for the the basis function N0,n (the left-most basis function of degree n) because this distance is only ever needed to calculate the factor for the basis function N0,j-1. This "parent" basis function does not have any dependence on the single basis function of degree 0 that is not 0. So this basis function can also never be > 0. The same thing is true for the right-most relevant knot. That is why we don't need to store the distance to those knots and also why we don't even need to calculate the factor or look up the value of the lower degree base function for them.

Preventing the lookup and calculation is done by always excluding the calculation for all left-side basis functions of degree n-1. We can do this, because both the knot-space width and the "parent" basis function right-side "parent" of a basis function Ni is the same as the knot-space width and parent basis function of the left-side parent for the basis function Ni+1. So by simply taking the right parent, calculating the inverse knot-space width with the "distance from parameter u to right-most knot" of that parent basis function, you get the right part of the basis function Ni and then you use that same inverse width and the same value from the right parent basis function and multiply it with the "distance from parameter u to right-most knot of the parent basis function" to get the complete left term of the calculation for the basis function Ni+1. This is done as an optimization to reduce calculation overhead and also allows us to ignore the left parent for any N0,i, because we can pre-initialize the "saved" parent basis function as 0. Finally the last basis function of a hierarchy level is mirrored to the first: It only has a value for the left parent basis function. So now we don't need to calculate any value, we can just store the "saved" value, which represents the left part of the basis function equation to our triangle.

The other half of our matrix (minus the diagonal center line, which is used by the basis function values) that forms the other triangle is used to store the basis functions' widths in knot space.

The reason we don't run this algorithm in an array and just overwrite the basis functions for any Ni,j where j < n where our curve degree is n, is that we want to reuse these values in subsequent derivatives calculations. The same applies to the width values.

The second part of this algorithm is the calculation of the derivatives of the basis functions for each degree of derivation from 1 to k, where k is the highest level of derivation that we are interested in.

The formula for this is: N_(i,p)_(k) = (p! / (p - k)! ) * Sum_(j=0,k)( A_(k,j) * N_(i+j,p-k) Where i is the i-th basis function we are trying to calculate the derivative for. p is the degree of our basis functions, k is the k-th degree of derivation N_(i,p)_(k) is the k-th derivative of the i-th basis function of degree p. N_(i+j,p-k) is the i + j -th basis function at the degree p - k, which we already precomputed in the previous part of the algorithm. A is a recursively defined part of the equation that is defined as follows:

A_(0,0) = 1 A_(k,0) = A_(k-1,0) / ( U_(i+p-k+1) - U_i ) A_(k,j) = ( A_(k-1,j) - A_(k-1,k-1) ) / ( U_(i+p+j-k+1) - U_(i+k) ) for j = 1,...,k-1 A_(k,k) = -A_(k-1,k-1) / ( U_(i+p+1) - U_(i+k) )

Where the U_(xxx) are the basis function knot-space widths that were calculated in the previous part of the algorithm.

◆ GetKnotCount()

Result<Int> GetKnotCount ( ) const
protected

◆ CalculatePointFromBasisFunctions()

Result<Vector4d> CalculatePointFromBasisFunctions ( Int  span,
Int  deg,
const detail::SmallStackMatrix< 2+1, D+1, Float > &  basisFunctions 
) const
protected

◆ InitInternal() [1/3]

Result<void> InitInternal ( Int  numPoints,
Int  degree,
NURBSCURVE_KNOTMODE  mode 
)
protected

◆ InitInternal() [2/3]

Result<void> InitInternal ( Int  degree,
const BaseArray< Vector4d > &  points,
const BaseArray< Float > &  knots 
)
protected

◆ InitInternal() [3/3]

Result<void> InitInternal ( const NURBSCurve< OtherN > &  other)
protected

◆ GetKnot()

Result<Float> GetKnot ( Int  i) const
protected

◆ ChangeWeightsInternal()

Result<void> ChangeWeightsInternal ( const Block< const T > &  weights)
protected

Member Data Documentation

◆ _curveDegree

Int _curveDegree
protected

◆ _knotMode

NURBSCURVE_KNOTMODE _knotMode
private

◆ _points

BaseArray<Vector4d> _points
private

◆ _knots

BaseArray<Float> _knots
private

◆ _memInit

Bool _memInit
private