Raw File
NURBSCurve.h
// Geometric Tools, LLC
// Copyright (c) 1998-2012
// Distributed under the Boost Software License, Version 1.0.

#pragma once

#include "NURBSGlobal.h"
#include "SingleCurve.h"
#include "BSplineBasis.h"

namespace NURBS
{

template <typename Real>
class NURBSCurve : public SingleCurve<Real>
{
public:
    // Construction and destruction.  The caller is responsible for deleting
    // the input arrays if they were dynamically allocated.  Internal copies
    // of the arrays are made, so to dynamically change control points,
    // control weights, or knots, you must use the 'SetControlPoint',
    // 'GetControlPoint', 'SetControlWeight', 'GetControlWeight', and 'Knot'
    // member functions.

    // The homogeneous input points are (x,y,z,w) where the (x,y,z) values are
    // stored in the ctrlPoint array and the w values are stored in the
    // ctrlWeight array.  The output points from curve evaluations are of
    // the form (x',y',z') = (x/w,y/w,z/w).

    // Uniform spline.  The number of control points is n+1 >= 2.  The degree
    // of the spline is d and must satisfy 1 <= d <= n.  The knots are
    // implicitly calculated in [0,1].  If open is 'true', the spline is
    // open and the knots are
    //   t[i] = 0,               0 <= i <= d
    //          (i-d)/(n+1-d),   d+1 <= i <= n
    //          1,               n+1 <= i <= n+d+1
    // If open is 'false', the spline is periodic and the knots are
    //   t[i] = (i-d)/(n+1-d),   0 <= i <= n+d+1
    // If loop is 'true', extra control points are added to generate a closed
    // curve.  For an open spline, the control point array is reallocated and
    // one extra control point is added, set to the first control point
    // C[n+1] = C[0].  For a periodic spline, the control point array is
    // reallocated and the first d points are replicated.  In either case the
    // knot array is calculated accordingly.

    NURBSCurve (){}
	virtual ~NURBSCurve() {} 

    NURBSCurve (const Array1D_Vector3 & ctrlPoint, const Array1D_Real & ctrlWeight, int degree = 3, bool loop = false, bool open = true);

	static Array1D_Real uniformWeights(int n){ return Array1D_Real(n,1.0); }
	static NURBSCurve<Real> createCurveFromPoints( const Array1D_Vector3 & ctrlPoint ) 
	{ return NURBSCurve<Real>( ctrlPoint, uniformWeights( ctrlPoint.size() ) ); }

    static NURBSCurve<Real> createCurve(Vector3 from, Vector3 to, int steps = 5);

    // Open, nonuniform spline.  The knot array must have n-d elements.  The
    // elements must be nondecreasing.  Each element must be in [0,1].
    NURBSCurve (int numCtrlPoints, const Array1D_Vector3 & ctrlPoint, const Array1D_Real & ctrlWeight, int degree, bool loop, const Real* knot);

    int GetNumCtrlPoints () const;
    int GetDegree () const;
    bool IsOpen () const;
    bool IsUniform () const;
    bool IsLoop () const;

    // Control points and weights may be changed at any time.  The input index
    // should be valid (0 <= i <= n).  If it is invalid, the return value of
    // GetControlPoint is a vector whose components are all MAX_REAL, and the
    // return value of GetControlWeight is MAX_REAL.
    // undefined.
    void SetControlPoint (int i, const Vector3& ctrl);
    Vector3 GetControlPoint (int i) const;
    void SetControlWeight (int i, Real weight);
    Real GetControlWeight (int i) const;

    // The knot values can be changed only if the basis function is nonuniform
    // and the input index is valid (0 <= i <= n-d-1).  If these conditions
    // are not satisfied, GetKnot returns MAX_REAL.
    void SetKnot (int i, Real knot);
    Real GetKnot (int i) const;

	Array1D_Real GetKnotVector(bool isInnerOnly = false);

	// Refinement:
	void refine( Array1D_Real & insKnts, Array1D_Vector3 & Qw, Array1D_Real & Ubar );
    int findSpan(int n, int p, Real u, Array1D_Real U );
	int findSpan( Real u );
	
	Array1D_Vector3 midPointRefined();
	void computeMidPointRefine( Array1D_Vector3 & Qw, Array1D_Real & Ubar );

	Array1D_Real insertKnot(Real u, int k, int s, int r, Array1D_Vector3 & Qw, int * uq = NULL);

	Array1D_Vector3 simpleRefine(int k); 

	Array1D_Vector3 removeKnots( int iterations = 1 );
	Real KnotRemovalError( int r, int s );

    // The spline is defined for 0 <= t <= 1.  If a t-value is outside [0,1],
    // an open spline clamps t to [0,1].  That is, if t > 1, t is set to 1;
    // if t < 0, t is set to 0.  A periodic spline wraps to to [0,1].  That
    // is, if t is outside [0,1], then t is set to t-floor(t).
    virtual Vector3 GetPosition (Real t) ;
    virtual Vector3 GetFirstDerivative (Real t) ;
    virtual Vector3 GetSecondDerivative (Real t) ;
    virtual Vector3 GetThirdDerivative (Real t) ;

    // If you need position and derivatives at the same time, it is more
    // efficient to call these functions.  Pass the addresses of those
    // quantities whose values you want.  You may pass 0 in any argument
    // whose value you do not want.
    void Get (Real t, Vector3* pos, Vector3* der1,
        Vector3* der2, Vector3* der3);

    // Access the basis function to compute it without control points.  This
    // is useful for least squares fitting of curves.
    BSplineBasis<Real>& GetBasis ();

    std::vector<Vector3> getControlPoints();

    Real timeAt(const Vector3 &pos);
	Real fastTimeAt(const Vector3 &pos);

    std::vector<std::vector<Vector3> > toSegments(Scalar resolution);

    // Modify
    void translate(const Vector3 &delta);
    void scale(Scalar scaleFactor);
    void scaleInPlace(Scalar scaleFactor, int placeCtrlPoint);
    void translateTo(const Vector3 &newPos, int cpIDX);

public:
    // Replicate the necessary number of control points when the Create
    // function has loop equal to true, in which case the spline curve must
    // be a closed curve.
    void CreateControl (const Array1D_Vector3 & ctrlPoint, const Array1D_Real & ctrlWeight);

    int mNumCtrlPoints;
    Array1D_Vector3 mCtrlPoint;  // ctrl[n+1]
    Array1D_Real mCtrlWeight;    // weight[n+1]
    bool mLoop;
    BSplineBasis<Real> mBasis;
    int mReplicate;  // the number of replicated control points

	// Misc
	Array1D_Vector3 misc_points;
};

typedef NURBSCurve<float> NURBSCurvef;
typedef NURBSCurve<double> NURBSCurved;

}
back to top