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 abstract class handles splines bases. 00018 * 00019 * 00020 */ 00021 00022 #ifndef __GB_Basis_h__ 00023 #define __GB_Basis_h__ 00024 00025 #include "GB_API.h" 00026 #include <stdio.h> 00027 #include <iostream.h> 00028 #include <UT/UT_Vector4.h> 00029 #include <UT/UT_FloatArray.h> 00030 #include <UT/UT_IntArray.h> 00031 #include <UT/UT_Vector4Array.h> 00032 #include <UT/UT_Math.h> 00033 #include "GB_Defines.h" 00034 00035 class UT_IStream; 00036 00037 #define GB_BASIS_BEZSPLINE 0x00001 00038 #define GB_BASIS_NUBSPLINE 0x00002 00039 00040 #define GB_BASIS_N "Basis" 00041 #define GB_BASIS_BEZSPLINE_N "Bezier" 00042 #define GB_BASIS_NUBSPLINE_N "NURB" 00043 00044 // GB_SPAN_DISTANCE is the distance that we back up from a given knot value 00045 // to ensure that the evaluation is done in the previous span. 00046 const fpreal GB_SPAN_DISTANCE = 2.0f * UT_FTOLERANCE; 00047 00048 00049 class GB_API GB_Basis { 00050 public: 00051 // Class constructors. The basis is cubic by default. Last two ctors 00052 // allocate space for the knot vector and do NOT verify the validity of 00053 // the data. It's up to the derived classes to make sure a given vector 00054 // length is appropriate for the specified order. 00055 GB_Basis(unsigned len=4, unsigned ord=4) : order(ord), dataVec(len,len) {} 00056 GB_Basis(float *vec, unsigned len, unsigned ord = 4); 00057 GB_Basis(fpreal vFirst, fpreal step, unsigned nv, unsigned ord = 4); 00058 00059 // Class destructor. 00060 virtual ~GB_Basis(); 00061 00062 // Evaluate on a specific domain interval, on which at least one 00063 // basis function is non-zero given domain point u. 00064 virtual void evalInterval(fpreal u, int offset, int derv, 00065 float *vals) const = 0; 00066 00067 // Compute one basis function (ie. the one with the given index) 00068 // value at u. 00069 virtual fpreal computeBValue(int index, fpreal u) const = 0; 00070 00071 // Find out if two knot sequences are similar (ie if the knot spacings 00072 // are the same all over) and their knot count is the same. 00073 virtual int isSimilar(const GB_Basis &b) const = 0; 00074 00075 // Return the length of the domain vector or its contents. Careful, the 00076 // contents don't belong to you. 00077 int getLength(void) const 00078 { 00079 return (int)dataVec.entries(); 00080 } 00081 const float *getData(void) const { return dataVec.getRawArray(); } 00082 float *getData(void) { return dataVec.array(); } 00083 00084 // Query the order and the dimension of the basis: 00085 int getOrder(void) const { return (int)order; } 00086 virtual int getDimension(void) const = 0; 00087 00088 // Return the boundaries of the valid evaluation interval, both as 00089 // indices and as data values: 00090 virtual void validInterval(int &a, int &b) const = 0; 00091 00092 // Return the size of the basis within the valid interval: 00093 fpreal validIntervalSize(void) const; 00094 00095 // Return the number of breakpoints (ie. unique knots) in the knot 00096 // vector, in the valid interval. 00097 virtual int breakCount(void) const = 0; 00098 00099 // Given the index of a knot (kidx) and two bounds in the knot sequence 00100 // (a and b) find out the index of the breakpoint that the knot represents, 00101 // and possibly adjust kidx so that knot[kidx+1] > knot[kidx]. Return -1 00102 // if not found. 00103 virtual int knotToBreakpoint(int &kidx, int a, int b) const = 0; 00104 00105 // Compute an array of breakpoints (i.e. unique knots) in the valid 00106 // interval and return their number: 00107 virtual int breakpoints(UT_FloatArray &arr) const = 0; 00108 virtual int breakpoints(UT_FloatArray &arr, 00109 fpreal tol) const = 0; 00110 00111 // Compute an array of multiplicities for each knot in the knot sequence. 00112 // Return the number of breakpoints (i.e. unique knots). 00113 int multiplicities(UT_IntArray &arr) const; 00114 00115 // Return the multiplicity of a domain point or -1 if outside the domain. 00116 // "uidx" is the index of the largest breakpoint <= u. 00117 virtual int multiplicity(fpreal u, int &uidx) const = 0; 00118 00119 // Return the expected multiplicity of the end knots (1 by default): 00120 virtual int endMultiplicity(void) const; 00121 00122 // Given a domain range in the valid interval, compute the range of CVs 00123 // that will be involved in the evaluation of the curve in that range. 00124 // Since the basis doesn't know about wrapping, the endcv index might 00125 // be higher than the spline's number of CVs. 00126 virtual void cvRangeOfDomain(int ustartidx, int ustopidx, 00127 int &startcv, int &endcv) const = 0; 00128 virtual void cvRangeOfDomain(fpreal ustart, fpreal ustop, 00129 int &startcv, int &endcv) const = 0; 00130 00131 // Given valid breakpoint index, compute the range of CVs that have a 00132 // non-zero influence at the knot of the breakpoint. Since the basis 00133 // doesn't know about wrapping, the endcv index might be higher than the 00134 // spline's number of CVs. 00135 virtual void cvRangeOfBreakpoint(int bkp, int &startcv, 00136 int &stopcv) const = 0; 00137 00138 // Each derived class has its own name and id: 00139 virtual const char *getName(void) const = 0; 00140 virtual unsigned int getType(void) const = 0; 00141 00142 // Generate a new basis of the species specified in the name or type 00143 // respectively. 00144 static GB_Basis *newSpecies(const char *name); 00145 static GB_Basis *newSpecies(unsigned int type); 00146 00147 // I/O functions. 00148 virtual int save(ostream &os, int wrapped = 0, 00149 int binary = 0) const; 00150 virtual bool load(UT_IStream &is, int cvs, 00151 int wrapped = 0); 00152 00153 // Copy my data from the given source. If compatible is 1, we copy the 00154 // data only if b has the same order and length as we do, and if 00155 // it doesn't we return -1. If all goes well, return 0. 00156 virtual int copyFrom(const GB_Basis &b, int compatible = 0); 00157 00158 // Validate the basis given CV information: return 1 if OK, 0 if NOK. 00159 // If adapt is 1, we adapt the basis flags to the knots. If adapt is 2 00160 // we adapt the knots to the basis flags, if any. If adapt is 0 we 00161 // return failure. 00162 virtual bool validate(int adapt = 0) = 0; 00163 virtual bool validate(int cvLen, int doesWrap) const = 0; 00164 virtual bool validate(int cvLen, int bLen, int doesWrap) const = 0; 00165 00166 // Compute the idx'th greville abscissa of the domain vector. Clamping 00167 // to the valid interval is optional and might not make any difference 00168 // for some spline types. 00169 virtual fpreal greville(unsigned idx, int clamp = 1, 00170 int wrapped = 0) const = 0; 00171 00172 // Resize the basis vector. This call updates the number of entries, too. 00173 void resize(unsigned sz, int copydata = 0) 00174 { 00175 dataVec.resize(sz, (unsigned short)copydata); 00176 dataVec.entries(sz); 00177 } 00178 00179 // Grow the length of the basis by one, and set the value of the new entry 00180 // to last knot + 1. The method returns the index of the appended element. 00181 virtual int grow(int wrapped=0) = 0; 00182 00183 // Shrink the basis by one. The basis should not shrink beyond a valid 00184 // length. Return the new length. 00185 virtual int shrink(int wrapped=0) = 0; 00186 00187 // Attach another basis to us and grow our basis as a result. The bases 00188 // must have the same type and order. Return 0 if successful and -1 00189 // otherwise. If "overlap" is true, we overlap the beginning of b with 00190 // our end. Spreading makes sense when you can have multiple knots in the 00191 // basis, and causes identical knots to be spread within range of the 00192 // neighbouring knots. 00193 virtual int attach(const GB_Basis &b, int overlap = 1, 00194 int spread = 0) = 0; 00195 00196 // Change the size of the basis (and maybe some of its values too) to 00197 // make it a valid basis for wrapped splines. The second method applies 00198 // the reversed processs: 00199 virtual void wrap(void) = 0; 00200 virtual void unwrap(void) = 0; 00201 00202 // Reverse the breakpoints in the basis. 00203 virtual void reverse(int ) = 0; 00204 00205 // Find index in the knot vector for the break point corresponding to k. 00206 virtual int findOffset(fpreal k, int startIdx=0) const = 0; 00207 00208 // Convert a value from unit to real knot and vice-versa. Usually you'll 00209 // want to map only within the valid interval. 00210 fpreal unitToReal(fpreal u_unit, int valid_interval=1) const; 00211 fpreal realToUnit(fpreal u_real, int valid_interval=1) const; 00212 00213 // Append or insert or remove an element: 00214 int append(void) { return (int)dataVec.append(); } 00215 int insert(unsigned i) { return (int)dataVec.insert(i); } 00216 int remove(unsigned i) { return (int)dataVec.removeIndex(i); } 00217 00218 // Merge the given basis into ours provided they both have the same order. 00219 // If their order is different return -1. Otherwise return 0. 00220 // A copy of "b"'s knots is mapped to our knot interval first, then merged 00221 // with us. The second method stres the mapping into "b" itself. 00222 int merge(const GB_Basis &b); 00223 int merge(GB_Basis &b); 00224 00225 00226 // Create a new basis containing the partial merging of bases a and b 00227 // If their order is different return -1. Otherwise return 0. 00228 // The resultant basis contains knots a0..a1 of basis a merged with 00229 // knots b0..b1 from basis b (after being mapped onto a0..a1) 00230 // If the aknot or bknot array is given, they are set with the 00231 // (appropriately mapped) knots values corresponding to the new insertions 00232 virtual int mergePartial(const GB_Basis &a, const GB_Basis &b, 00233 int a0, int a1, int b0, int b1, 00234 UT_FloatArray *aknot = 0, 00235 UT_FloatArray *bknot = 0); 00236 00237 // Find the index of a breakpoint such that the distance between it and the 00238 // next breakpoint is the largest in the whole sequence. The search is 00239 // done between two specified indices. 00240 int findMaxSpan(int start, int stop) const; 00241 00242 // Normalize the vector and optionally shift it to a new origin. Use the 00243 // given scale if greater than 0, else normalize to unit length. If "knots" 00244 // is given, the resulting values are deposited in it. 00245 void normalize(UT_FloatArray &knots, 00246 fpreal scale=0.0F, float *neworig=0) const; 00247 void normalize(fpreal scale=0.0F, float *neworig=0) 00248 { 00249 normalize(dataVec, scale, neworig); 00250 } 00251 00252 // Rebuild the basis as a uniform sequence with a given step. 00253 virtual void rebuild(fpreal ustart = 0.0f, fpreal ustep = 1.0f); 00254 00255 // Make the basis uniform of just find out if it is uniform: 00256 virtual void uniform(fpreal ustep = 1.0f); 00257 virtual int isUniform(void) const; 00258 00259 // Normalize the vector to the new length and optionally shift it to 00260 // a new origin. If "knots" is given, the resulting values are put in it. 00261 // The first method maps us to the interval of basis "b". In other words, 00262 // our extremities will be changed to match those of basis "b". 00263 void map(const GB_Basis &b); 00264 void map(UT_FloatArray &knots, 00265 fpreal newlen = 1.0F, float *neworig = 0) const; 00266 void map(fpreal newlen = 1.0F, float *neworig = 0) 00267 { 00268 map(dataVec, newlen, neworig); 00269 } 00270 00271 // Map domain value "u", which should be between our min and max knots, 00272 // to a domain value in basis "b". If you know the index of the knot 00273 // in our sequence such that k[uoffset] <= u, enter in as the last 00274 // parameter. The method returns -1 if it has failed (the two bases don't 00275 // have the same length or u is out of range). Otherwise it returns the 00276 // uoffset. 00277 int map(const GB_Basis &b, fpreal &u, int uoffset=0) const; 00278 00279 // Reparameterize the basis using the chord-length method, and clamp it 00280 // to the valid interval. The origin and length of the valid domain remains 00281 // unchanged. 00282 virtual void chord(UT_Vector4Array &cvs) = 0; 00283 00284 // Slide the knots found in the given range left or right by an amount at 00285 // most as large as the distance to the nearest knot outside the range. 00286 // The bias is a percentage value of the left-right distance, its default 00287 // value is 0.5 (i.e. don't change anything), and is clamped to [0,1]. 00288 // The method returns 0 if OK and -1 if out of range. 00289 virtual int slideRange(fpreal umin, fpreal umax, 00290 fpreal ubias=0.5F)=0; 00291 00292 // Set the order of the basis. Careful when you use it because it must 00293 // be <= GB_MAXORDER and must be appropriate for the number of knots. 00294 void setOrder(unsigned ord) { order = ord; } 00295 00296 // Get the greatest value knot that is smaller than the search value. 00297 // Return 0 if search value is out of range. The default search range 00298 // is from order-1 to dimension. 00299 int findClosest(fpreal val, int &idx, 00300 int startidx, int endidx) const; 00301 00302 // Return the index of the first knot that is approximately equal to 00303 // val. The entire sequence is searched from startidx. 00304 // Return -1 if not found. 00305 int findApproximate(fpreal val, int startidx, 00306 fpreal tol=0.00001F) const; 00307 00308 // Compute alphas needed for degree elevation. "increment" is the amount 00309 // by which we want the degree to grow. 00310 void computeRaiseOrderAlphas(unsigned int increment, 00311 float bezalfs[][GB_MAXORDER]) const; 00312 00313 // Return the discontinuity information for the basis at the given 00314 // parameter value u. If discont_derv is returned as -1, the curve 00315 // is infinitely differentiable here (of course, derivatives >= order 00316 // will be zero). Otherwise, discont_derv contains the lowest derivative 00317 // number that is discontinuous at this point. It also returns the u 00318 // value at the other side of the discontinuity, if such a discontinuity 00319 // exists. 00320 virtual void getDiscontinuityInfo(fpreal u, int &discont_derv, 00321 float &prev_span_u, 00322 int wrapped=0) const = 0; 00323 00324 // Retrieve the knot/breakpoint vector that contains the raw data and 00325 // the vector length: 00326 const UT_FloatArray &getVector(void) const { return dataVec; } 00327 UT_FloatArray &getVector(void) { return dataVec; } 00328 00329 protected: 00330 00331 private: 00332 // The order of the basis == degree + 1. Max is GB_MAXORDER. 00333 unsigned int order; 00334 00335 // Vector of knots or breakpoints. 00336 UT_FloatArray dataVec; 00337 00338 }; 00339 00340 #endif
1.5.9