00001 /* 00002 * PROPRIETARY INFORMATION. This software is proprietary to 00003 * Side Effects Software Inc., and is not to be reproduced, 00004 * transmitted, or disclosed in any way without written permission. 00005 * 00006 * Produced by: 00007 * Cristin Barghiel 00008 * Side Effects Software Inc. 00009 * 20 Maud St. 00010 * Toronto, Ontario, M5V 2M5 00011 * Canada 00012 * 416-366-4607 00013 * 00014 * NAME: Geometry Library (C++) 00015 * 00016 * COMMENTS: 00017 * This class implements a piecewise NUB spline basis. 00018 * 00019 * 00020 */ 00021 00022 #ifndef __GB_NUBBasis_h__ 00023 #define __GB_NUBBasis_h__ 00024 00025 #include "GB_API.h" 00026 #include <UT/UT_Vector4Array.h> 00027 #include <UT/UT_Vector.h> 00028 #include "GB_Basis.h" 00029 00030 #define GB_UNCLAMP_SCALE 3.0F // knot scale factor for unclamp 00031 // end interpolating curve/surface 00032 00033 enum GB_KnotSpaceType 00034 { 00035 GB_KNOT_UNIFORM = 0, 00036 GB_KNOT_AVERAGING = 1 00037 }; 00038 00039 class GB_API GB_NUBBasis : public GB_Basis { 00040 public: 00041 // Class constructors. The basis is cubic by default and always built to 00042 // be valid in terms of its order. Therefore, the length will be increased 00043 // if necessary. 00044 00045 GB_NUBBasis(unsigned len=8, unsigned ord=4); 00046 00047 // This c-tor takes a given knot vector and its length, and it expects 00048 // you're making sure it is a valid sequence and in accordance with the 00049 // type of basis: if end interpolating, the number of equal knots at the 00050 // ends must == the order; if non-interpolating, the number of equal knots 00051 // at each end must be 2. 00052 GB_NUBBasis(float *kVec, unsigned len, unsigned ord, int e = 1); 00053 00054 // This basis will end up with nk+2 knots if not end-interpolating, and 00055 // with nk + 2*order knots otherwise. A certain number of end knots will 00056 // be identical. 00057 GB_NUBBasis(fpreal kFirst, fpreal step, unsigned nk, unsigned ord, 00058 int interpolateEnds = 1); 00059 00060 // This c-tor allows you to build the equivalent of a Bezier basis. 00061 // To end up with a Bezier-like basis, set the multiplicity=ord-1. 00062 // The end points will always have 'ord' multiplicity, so this is 00063 // an end-interpolating basis. The multiplicity must be >= 1 and < ord. 00064 GB_NUBBasis(unsigned bkpoints, unsigned multiplicity, unsigned ord); 00065 00066 // Class destructor. Virtual by inheritance. 00067 virtual ~GB_NUBBasis(); 00068 00069 // Copy my data from the given source. If compatible is 1, we copy the 00070 // data only if b has the same order and length as we do, and if 00071 // it doesn't we return -1. If all goes well, return 0. 00072 virtual int copyFrom(const GB_Basis &b, int compatible = 0); 00073 00074 // Evaluate on a specific domain interval, on which at least one 00075 // basis function is non-zero given domain point u. 00076 virtual void evalInterval(fpreal u, int offset, int derv, 00077 float *vals) const; 00078 00079 // Evaluate the all the derivs of the basis from 0 to derv (inclusive). 00080 void evaluateDerivMatrix(fpreal u, int offset, int derv, 00081 float bmatx[][GB_MAXORDER])const; 00082 00083 // Compute one basis function (ie. the one with the given index) 00084 // value at u. 00085 virtual fpreal computeBValue(int index, fpreal u) const; 00086 00087 // Find out if two knot sequences are similar (ie if the knot spacings 00088 // are the same all over) and their knot count is the same. We assume 00089 // "b" is a NUBBasis! 00090 virtual int isSimilar(const GB_Basis &b) const; 00091 00092 // Check if our basis has a similar knot spacing OUTSIDE the valid 00093 // interval as the given basis. This is helpful in determining whether 00094 // merging two non end-interpolating bases requires an a priori conversion 00095 // to end-interpolating. 00096 int similarOrderEnds(const GB_NUBBasis &b) const; 00097 00098 // Return the number of breakpoints (ie. unique knots) in the knot 00099 // vector, in the valid interval. 00100 virtual int breakCount(void) const; 00101 00102 // Find the index of the last knot in the sequence that defines 00103 // breakpoint of index bptIdx, or the breakpoint of domain value 00104 // 'param'. Return -1 if not found. The search is done within the 00105 // limits of the valid interval. 00106 int breakpnt(int bptIdx) const; 00107 int breakpnt(fpreal param) const; 00108 00109 // Given the index of a knot (kidx) and two bounds in the knot sequence 00110 // (a and b) find out the index of the breakpoint that the knot represents, 00111 // and possibly adjust kidx so that knot[kidx+1] > knot[kidx]. Return -1 00112 // if not found. 00113 virtual int knotToBreakpoint(int &kidx, int a, int b) const; 00114 00115 // Compute an array of breakpoints (i.e. unique knots) in the valid 00116 // interval and return their number: 00117 virtual int breakpoints(UT_FloatArray &arr, fpreal tol) const; 00118 virtual int breakpoints(UT_FloatArray &arr) const; 00119 00120 // Query the multiplicity of a knot. The second method assumes the knot 00121 // index is valid ie [1,len-2]. Return 0 if knot not found, and -1 if 00122 // k is outside the valid interval or greater than the number of CVs 00123 // implied by the knot length and the "wrapped" parameter. The 1st method 00124 // also returns the index of knot t such that k >= t. 00125 virtual int multiplicity(fpreal k, int &tidx) const; 00126 int multiplicity(int wrapped, int &kidx) const; 00127 00128 // Return the expected multiplicity of the end knots. It depends on the 00129 // basis order and the end conditions. 00130 virtual int endMultiplicity(void) const; 00131 00132 // Change the multiplicity of the knot by inserting it "r" times WITHOUT 00133 // checking its current multiplicity. kidx is the index of a knot t 00134 // such that k >= t. 00135 void refine(fpreal k, int kidx, int r, int wrapped); 00136 00137 // Return the first and last real knot values and indices: 00138 int firstRealIndex() const { return 1; } 00139 int lastRealIndex() const { return getLength()-2; } 00140 fpreal firstRealKnot () const 00141 { 00142 return getVector()((unsigned)firstRealIndex()); 00143 } 00144 fpreal lastRealKnot () const 00145 { 00146 return getVector()((unsigned)lastRealIndex()); 00147 } 00148 00149 // Return the boundaries of the valid evaluation interval: 00150 virtual void validInterval(int &a, int &b) const; 00151 00152 // Return the index of the knot where the valid evaluation begins. 00153 // Typically, for a cubic spline, this index is 3 in the end-point 00154 // interpolating case and 1 otherwise. If float is completely outside 00155 // the valid knot sequence, this method returns -1. 00156 int findValidStart(fpreal u, int uOffset = -1) const; 00157 00158 // findOffset is similar to findValidStart except it is virtual, 00159 // and with an input of startIdx to begin searching, 00160 // but no uOffset input. 00161 virtual int findOffset(fpreal k, int startIdx = 0) const; 00162 00163 // Given a domain range in the valid interval, compute the range of CVs 00164 // that will be involved in the evaluation of the curve in that range. 00165 // Since the basis doesn't know about wrapping, the endcv index might 00166 // be higher than the spline's number of CVs. 00167 virtual void cvRangeOfDomain(int ustartidx, int ustopidx, 00168 int &startcv, int &endcv) const; 00169 virtual void cvRangeOfDomain(fpreal ustart, fpreal ustop, 00170 int &startcv, int &endcv) const; 00171 00172 // Given valid breakpoint index, compute the range of CVs that have a 00173 // non-zero influence at the knot of the breakpoint. Since the basis 00174 // doesn't know about wrapping, the endcv index might be higher than the 00175 // spline's number of CVs. 00176 virtual void cvRangeOfBreakpoint(int bkp, int &startcv, 00177 int &cv) const; 00178 00179 // Compute the idx'th greville abscissa of the knot vector. The function 00180 // does not do boundary checking. Clamping to the valid interval is 00181 // optional. 00182 virtual fpreal greville(unsigned idx, int clamp = 1, 00183 int wrapped = 1) const; 00184 00185 // Grow the length of the basis by one, and set the value of the new 00186 // knot to something valid. If the basis is interpolating the second 00187 // endpoint, the last 'order' knots are made equal. A zero length basis 00188 // will have its length increased to 2 * order. 00189 // This method returns the index of the last element. 00190 virtual int grow(int wrapped); 00191 00192 // Shrink the basis by one. Return the new length. 00193 virtual int shrink(int wrapped); 00194 00195 // Insert a new knot as a result of a CV insertion at index cvIdx. The 00196 // knot index is cvIdx + 1, which is returned by growAt() if all goes OK. 00197 // -1 is returned upon failure. 00198 int growAt(unsigned cvIdx, int wrapped); 00199 00200 // Delete a knot as a result of a CV removal at index cvIdx. The knot 00201 // index is cvIdx + 1. The method returns the new length if successful, 00202 // and -1 otherwise. 00203 int shrinkAt(unsigned cvIdx, int wrapped); 00204 00205 // Attach another basis to us and grow our basis as a result. The bases 00206 // must have the same type and order. Return 0 if successful and -1 00207 // otherwise. If "overlap" is true, we overlap the beginning of b with 00208 // our end. Spreading makes sense when you can have multiple knots in the 00209 // basis, and causes identical knots to be spread within range of the 00210 // neighbouring knots. 00211 virtual int attach(const GB_Basis &b, int overlap = 1, 00212 int spread = 0); 00213 00214 // Change the size of the basis (and maybe some of its values too) to 00215 // make it a valid basis for wrapped splines. The second method applies 00216 // the reversed processs: 00217 virtual void wrap(void); 00218 virtual void unwrap(void); 00219 00220 // Reverse the breakpoints in the basis. 00221 virtual void reverse(int wrapped); 00222 00223 // Rebuild the basis as a uniform sequence with a given step. 00224 virtual void rebuild(fpreal ustart = 0.0f, fpreal ustep = 1.0f); 00225 00226 // Make the knots uniform of just find out if they are uniform: 00227 virtual void uniform(fpreal step = 1.0f); 00228 virtual int isUniform(void) const; 00229 00230 // Check if the basis interpolates the endpoints, or change the flag. 00231 // Normally, publis users of these methods should use toggleEndCondition() 00232 // because it take care about spreading of collapsing the knots for you. 00233 // Only if you REALLY know what you are doing and just want to toggle the 00234 // flag, use interpolateEnds(1 or 0). 00235 short interpolatesEnds(void) const { return endCondition; } 00236 void interpolatesEnds(int yesno) { endCondition = (short)yesno; } 00237 void toggleEndCondition(void); 00238 00239 // Make the basis periodic (needed by wrapped splines): 00240 void periodic(void); 00241 00242 // Reparameterize the basis using the chord-length method, and clamp it 00243 // to the valid interval. The origin and length of the valid domain remains 00244 // unchanged. 00245 virtual void chord(UT_Vector4Array &cvs); 00246 00247 // Slide the knots found in the given range left or right by an amount at 00248 // most as large as the distance to the nearest knot outside the range. 00249 // The bias is a percentage value of the left-right distance, its default 00250 // value is 0.5 (i.e. don't change anything), and is clamped to [0,1]. 00251 // The method returns 0 if OK and -1 if out of range. 00252 virtual int slideRange(fpreal umin, fpreal umax, fpreal ubias=0.5F); 00253 00254 // Functions redefined from the base class. 00255 virtual const char *getName(void) const; 00256 virtual unsigned int getType(void) const; 00257 virtual int getDimension(void) const; 00258 00259 // I/O functions. 00260 virtual int save(ostream &os, int wrapped = 0, 00261 int binary = 0) const; 00262 virtual bool load(UT_IStream &is, int cvs, 00263 int wrapped = 0); 00264 00265 // Validate the basis given CV information: return 1 if OK, 0 if NOK. 00266 // If adapt is 1, we adapt the basis flags to the knots. If adapt is 2 00267 // we adapt the knots to the basis flags, if any. If adapt is 0 we 00268 // return failure. 00269 virtual bool validate(int adapt_to_knots = 0); 00270 virtual bool validate(int cvLen, int doesWrap) const; 00271 virtual bool validate(int cvLen, int basisLen, int doesWrap) const; 00272 00273 // Maximum order accepted. This value is used to set the sizes of 00274 // work areas. 00275 static const int maxOrder; 00276 00277 // Find index in the knot vector such that knotVec[idx] <= k and 00278 // k < knotVec[idx+1]. The function returns a negative value if 00279 // k is outside the validInterval(). If k > last valid knot we return the 00280 // the index of the last valid knot (ie. the dimension) + 1. 00281 int findStart(fpreal k, int startIdx = 0) const; 00282 00283 // Set up the knot vector with the given parameterization for 00284 // interpolation. 00285 void knotsEqualSpace(UT_Vector ¶m, int wrapped=0); 00286 void knotsAveraging(UT_Vector ¶m, int wrapped=0); 00287 00288 // Set up the knot vector with the given parameterization for 00289 // approximation. 00290 void knotsSpreading(UT_Vector ¶m); 00291 00292 // Set up the knot vector with the given parameterization for building 00293 // a curve out of breakpoints. 00294 void knotsBreakpoints(UT_Vector ¶m); 00295 00296 // Cycle the knots, optionally keeping the original span length and origin 00297 int cycle(int amount, int keepSpan); 00298 00299 // Create a new basis containing the partial merging of bases a and b 00300 // If their order is different return -1. Otherwise return 0. 00301 // The resultant basis contains knots a0..a1 of basis a merged with 00302 // knots b0..b1 from basis b (after being mapped onto a0..a1) 00303 // If the aknot or bknot array is given, they are set with the 00304 // (appropriately mapped) knots values corresponding to the new insertions 00305 00306 virtual int mergePartial(const GB_Basis &a, const GB_Basis &b, 00307 int a0, int a1, int b0, int b1, 00308 UT_FloatArray *aknot = 0, 00309 UT_FloatArray *bknot = 0); 00310 00311 // will set the endCondition flag to 1 if and only if there are sufficient 00312 // knots at BOTH ends to make the curve touch the end CVs. Otherwise it will 00313 // set the endCondition flag to 0 00314 void updateEndCondition(void); 00315 00316 // Return the discontinuity information for the basis at the given 00317 // parameter value u. If discont_derv is returned as -1, the curve 00318 // is infinitely differentiable here (of course, derivatives >= order 00319 // will be zero). Otherwise, discont_derv contains the lowest derivative 00320 // number that is discontinuous at this point. It also returns the u 00321 // value at the other side of the discontinuity, if such a discontinuity 00322 // exists. 00323 virtual void getDiscontinuityInfo(fpreal u, int &discont_derv, 00324 float &prev_span_u, 00325 int wrapped=0) const; 00326 00327 protected: 00328 // Compute the values or the derivatives at a domain point in the 00329 // correct interval. 00330 void computeBValues(fpreal u, const float* knots, 00331 int order, float* vals) const; 00332 void computeBDerivs(fpreal u, const float* knots, int order, 00333 int derv, float* vals) const; 00334 00335 // Initialize a knot sequence given an initial knot value and a step: 00336 void initialize(fpreal kFirst, fpreal step); 00337 00338 // Spread the knots within a given range. We assume the rance is valid. 00339 void spreadKnots(int aidx, int bidx); 00340 00341 private: 00342 short endCondition; // 1 if it interpolates the ends. 00343 00344 }; 00345 00346 #endif
1.5.9