// Open, nonuniform spline, that takes external knot vector. // // if bIsInteriorKnot, the knot array must have n-d-1 elements, the standard start/end // sequences of #degree 0/1 knots will be automatically added by internal BSplineBasis. // // if !bIsInteriorKnot, the knot array must have n+d+1 elements and is used directly. // // eg for 7 control points degree-3 curve the full knot vector would be [0 0 0 0 a b c 1 1 1 1], // and the interior knot vector would be [a b c]. // // The knot elements must be nondecreasing. Each element must be in [0,1]. Note that // knot vectors can be arbitrary normalized by dividing by the largest knot, if // you have a knot vector with values > 1 // // loop=true duplicates the first control point to force loop closure, however this // was broken in the WildMagic code because it didn't add a knot. I am not // quite sure what to do here - a new non-1 knot value needs to be inserted for // the previous last control point, somehow. Or perhaps the knot vector needs // to be extended, ie the final degree-duplicate knots need value > 1? // // Currently to create a closed NURBS curve, the caller must handle this duplication // themselves. public NURBSCurve2(int numCtrlPoints, Vector2d[] ctrlPoint, double[] ctrlWeight, int degree, bool loop, double[] knot, bool bIsInteriorKnot = true) : base(0, 1) { if (numCtrlPoints < 2) { throw new Exception("NURBSCurve2(): only received " + numCtrlPoints + " control points!"); } if (degree < 1 || degree > numCtrlPoints - 1) { throw new Exception("NURBSCurve2(): invalid degree " + degree); } // [RMS] loop mode doesn't work yet if (loop == true) { throw new Exception("NURBSCUrve2(): loop mode is broken?"); } mLoop = loop; mNumCtrlPoints = numCtrlPoints; mReplicate = (loop ? 1 : 0); CreateControl(ctrlPoint, ctrlWeight); mBasis = new BSplineBasis(mNumCtrlPoints + mReplicate, degree, knot, bIsInteriorKnot); }
public BSplineBasis Clone() { var b2 = new BSplineBasis(); b2.mNumCtrlPoints = this.mNumCtrlPoints; b2.mDegree = this.mDegree; b2.mKnot = (double[])this.mKnot.Clone(); b2.mOpen = this.mOpen; b2.mUniform = this.mUniform; return(b2); }
// Construction and destruction. Internal copies of the // input 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,w) where the (x,y) 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') = (x/w,y/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. // // [RMS] "open" and "loop" are super-confusing here. Perhaps NURBSCurve2 should // be refactored into several subclasses w/ different constructors, so that // the naming makes sense? public NURBSCurve2(int numCtrlPoints, Vector2d[] ctrlPoint, double[] ctrlWeight, int degree, bool loop, bool open) : base(0, 1) { if (numCtrlPoints < 2) { throw new Exception("NURBSCurve2(): only received " + numCtrlPoints + " control points!"); } if (degree < 1 || degree > numCtrlPoints - 1) { throw new Exception("NURBSCurve2(): invalid degree " + degree); } mLoop = loop; mNumCtrlPoints = numCtrlPoints; mReplicate = (loop ? (open ? 1 : degree) : 0); CreateControl(ctrlPoint, ctrlWeight); mBasis = new BSplineBasis(mNumCtrlPoints + mReplicate, degree, open); }