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 non-uniform B-Spline curve defined by 00018 * a set of knots, basis function, and CVs. 00019 * 00020 */ 00021 00022 #ifndef __GEO_PrimNURBCurve_h__ 00023 #define __GEO_PrimNURBCurve_h__ 00024 00025 #include "GEO_API.h" 00026 #include "GEO_Curve.h" 00027 #include "GEO_PrimType.h" 00028 00029 class UT_Vector4; 00030 class GB_NUBBasis; 00031 class UT_Vector3Array; 00032 00033 class GEO_API GEO_PrimNURBCurve : public GEO_Curve { 00034 public: 00035 // Constructor that attaches this curve to detail "d". 00036 GEO_PrimNURBCurve(GEO_Detail *d, unsigned int m=0) 00037 : GEO_Curve(d, (int)m) {} 00038 00039 // Trivial class destructor, virtual by inheritance. Please read the 00040 // comments on the parent class d-tor. 00041 ~GEO_PrimNURBCurve(); 00042 00043 // Given a domain value (u), store all the basis derivatives (from 0 to du 00044 // inclusive) into bmatx. Return the min index of the CVs needed 00045 // for the linear combination. The indices may exceed the number of 00046 // vertices if the curve is wrapped, so remember to use % getVertexCount(). 00047 virtual int evaluateBasisDerivs(float u,float bmatx[][GB_MAXORDER], 00048 int &cvoffset, unsigned du = 0, 00049 int uoffset = -1) const; 00050 00051 // Evaluate the basis at the given point in the domain and also return 00052 // the index of the first CV to linearly combine the basis with. The CV 00053 // index may exceed the number of vertices if the curve is wrapped, 00054 // so remember to use modulus (%). This method handles both rational and 00055 // non-rational curves. 00056 virtual int evaluateBasis(float u,float *ubvals, int &cvoffset, 00057 unsigned du=0, int uoffset=-1) const; 00058 00059 // Two flavours of a bulk curve evaluator that computes points or 00060 // derivatives inside a parametric segment determined by: 00061 // a) the u value specified in uArr. The length of the parameter arrays 00062 // is arrLen. b) uStart, uStop. 00063 // The functions return 0 if successful, and -1 otherwise. 00064 virtual int evaluateSegm(float *uArr, unsigned uArrLen, 00065 UT_Vector4 *pos, unsigned du=0) const; 00066 virtual bool evaluateSegm(fpreal uStart, fpreal uStop, 00067 unsigned nu, GEO_Vertex **results, 00068 GEO_AttributeHandleList &hlist, 00069 unsigned du) const; 00070 virtual int evaluateSegm(float uStart, float uStop, unsigned nu, 00071 UT_Vector4 *pos, unsigned du=0) const; 00072 virtual int evaluateSegmWAttrib(float uStart, float uStop, 00073 unsigned nu, UT_Vector4 *pos, 00074 GB_AttributeData *adata, 00075 const GB_FloatOffsets &foffsets, 00076 unsigned du=0) const; 00077 00078 // Another pair of curve evaluators. These take a start and a stop index 00079 // in the valid knot domain and an lod representing number of points to 00080 // be interpolated between every two breakpoints. The methods ALWAYS 00081 // interpolate the encountered breakpoints (aka "edit points"). They return 00082 // the number of points in the list or -1 if unsuccessful. Please save 00083 // yourself headaches and pass VALID start and end indices (see the 00084 // method validInterval() in GB_Basis). 00085 virtual int evaluateBreakSegm(int uStartIdx, int uStopIdx, 00086 int lod, GEO_Vertex **results, 00087 GEO_AttributeHandleList &hlist, 00088 unsigned du=0) const; 00089 virtual int evaluateBreakSegm(int uStartIdx, int uStopIdx, int lod, 00090 UT_Vector4 *pos, unsigned du=0) const; 00091 virtual int evaluateBreakSegmWAttrib(int uStartIdx, int uStopIdx, 00092 int lod, UT_Vector4 *pos, 00093 GB_AttributeData *adata, 00094 const GB_FloatOffsets &foffsets, 00095 unsigned du=0) const; 00096 00097 // Compute the location of the breakpoint. Return 0 if OK, else -1. 00098 virtual int evaluateBreakpoint(int uidx, UT_Vector4 &pos, 00099 int du=0) const; 00100 00101 // compute the un-normalized lengths corresponding to points on the curve 00102 // evaluated at the valid knots parameter values 00103 // (ones with which lie within curve paramer domain) and store them 00104 // in the 'lengths' array. Returns the curve "length" (same as last knot). 00105 // The meaning of "length" depends on ptype, and can mean chord length, 00106 // square chord length, approximate arc length. 00107 virtual float getKnotLengths(GB_ParmType ptype, 00108 UT_FloatArray &lengths) const; 00109 00110 // Evaluate the curve over the valid parametric interval, and place the 00111 // points in the pos array. Return 0 if successful, and -1 otherwise. 00112 virtual int fillCurve(int nu, UT_Vector4 *pos) const; 00113 00114 // Given a CV index figure out the min/max indicies of the knots between 00115 // which the curve needs to be re-evaluated if the CV changes. If not 00116 // given a valid CV index, the method returns -1. Otherwise it returns 0. 00117 // If the curve wraps the domain we return will be rather large. 00118 virtual int domainRangeOfCV(int cvidx, int &mink,int &maxk) const; 00119 00120 // Given a CV index figure out the min/max breakpoints which are 00121 // affected if the CV changes. If not given a valid CV index, the 00122 // method returns -1. Otherwise it returns 0. Also returns -1 if 00123 // no breakpoints are affected. 00124 // NOTE: use % breakCount since maxbkp may be >= breakCount 00125 virtual int breakpointRangeOfCV(int cvidx, int &minbkp, 00126 int &maxbkp) const; 00127 00128 // Reparameterize the curve by changing its basis. Everything up and 00129 // including the first valid knot remains unchanged. This type of 00130 // reparameterization is generally NOT shape preserving: 00131 virtual void reparameterize(GB_ParmType ptype); 00132 00133 // Change the multiplicity of the knot by inserting it "r" times after 00134 // checking its current multiplicity. The maximum valid r for a knot is 00135 // equal to the degree of the basis (ie order-1). Return -1 if k is outside 00136 // the valid interval or greater than the number of CVs. Otherwise, return 00137 // the index of the inserted knot and the initial multiplicity. 00138 virtual int refine(float k, GEO_AttributeHandleList &hl, int r=1); 00139 virtual int refine (float k,int r = 1); 00140 virtual int refineWAttrib(float k,const GB_FloatOffsets &foffsets, 00141 int r = 1); 00142 virtual int refineWAttrib(float k, 00143 const GB_FloatOffsets *ptoffsets, 00144 const GB_FloatOffsets *vtxoffsets, 00145 int r = 1); 00146 00147 // Given a parameter in the face domain, insert as many CVs as necessary to 00148 // create a discontinuity at the corresponding point on the curve.The shape 00149 // of the curve should NOT change. Return u's index upon success and -1 00150 // otherwise. 00151 virtual int subdivide (float u, GEO_AttributeHandleList &hl); 00152 virtual int subdivide (float u); 00153 virtual int subdivideWAttrib(float u, 00154 const GB_FloatOffsets &foffsets); 00155 00156 00157 // Increase the order. Return 0 if successful, -1 otherwise (eg. 00158 // order cannot be increased because it's >= MAXORDER). 00159 virtual int raiseOrder(int neworder, GEO_AttributeHandleList &hl); 00160 virtual int raiseOrder (int neworder); 00161 virtual int raiseOrderWAttrib(int neworder, 00162 const GB_FloatOffsets &foffsets); 00163 00164 // Warp the curve at u by the given delta. Change 1 or 2 Cvs and possibly 00165 // insert a knot once or more as well. If a knot is inserted or we happen 00166 // to land exactly on a knot, we change only one CV. The bias makes sense 00167 // only when changing 2 CVs, and will be ignored altogether if < 0. 00168 // We return the index of the affected knot in the sequence, or -1 if 00169 // there's an error. 00170 virtual int warp(float u, const UT_Vector3 &delta, 00171 GEO_AttributeHandleList &hlist, 00172 float sharpness = 0.0f, float bias = -1.0f); 00173 virtual int warp(float u, const UT_Vector3 &delta, 00174 GB_FloatOffsets *foffsets = 0, 00175 float sharpness = 0.0f, float bias = -1.0f); 00176 00177 // Translate the CVs such that the given breakpoint change positions by 00178 // the given delta. Return -1 if something goes wrong, 0 if translation 00179 // was successful. 00180 // NOTE: uindices cannot contain any duplicates. If the curve is closed, 00181 // the first and last breakpoint are considered the same. 00182 virtual int translateBreakpoints(const UT_IntArray &uindices, 00183 const UT_Vector3 &delta, 00184 int fixbkpts = 1, 00185 GB_PointGroup *ptgroup = NULL, 00186 GEO_Delta *geodelta = 0); 00187 virtual int transformBreakpoints(const UT_IntArray &uindices, 00188 const UT_Matrix4 &matx, 00189 int fixbkpts = 1, 00190 GB_PointGroup *ptgroup = NULL, 00191 GEO_Delta *geodelta = 0); 00192 00193 // Append another face to us in one of two ways: blend the two endpoints 00194 // or connect them straight or rounded. The bias ranges from 0 to 1 and is 00195 // relevant only to blending. The tolerance for blending: if 0, the two 00196 // endpoints will merge into one point with a discontinuity; if less than 00197 // 1, we insert knots into the curves to minimize the affected areas; if 1, 00198 // no refinement is done. For the non-blend case, the tolerance will 00199 // generate a span whose shape goes from round to straight; 0 tolerance 00200 // means straight connection. If unrefine is on, we'll try to reduce the 00201 // complexity of the face if we're connecting rounded. We return 0 if OK 00202 // and -1 if error. Both curves must be open, clamped, and have the same 00203 // order. 00204 virtual int attach(const GEO_Face &face, int blend = 1, 00205 float bias = 0.5f, float tolerance = 1.0f, 00206 int unrefine = 1,GB_PointGroup *ptgroup=0); 00207 00208 // Build a planar (domain) face of the same type as us and with the same 00209 // number of vertices. Copying the (x,y) values of our points to the planar 00210 // face is optional. 00211 virtual GD_Face *planar(GD_Detail &dgdp, int copyxy = 0) const; 00212 00213 // Notify whomever needs to know that we have changed the weight or the 00214 // coordinates of cv[r]. 00215 virtual int recordChange(unsigned r); 00216 00217 // Set the wrap or open flag, and make sure the basis knot vectors are 00218 // consistent with the change. These functions are virtual by inheritance. 00219 00220 // Convert a topologically open curve into a topologically closed one. 00221 // The rounded flag is mainly for surface end caps to indicate a half cap 00222 // or a full cap. 00223 // 00224 // If rounded = 1: 00225 // closed rounded curve. 00226 // non end interpolated. 00227 // may or may not preserve shape depending on the flag. 00228 // (however, always preserve shape if original curve is 00229 // non end interpolated) 00230 // If rounded = 0: 00231 // closed curve with a straight edge. 00232 // end interpolated. 00233 // always preserve the shape. (ignore preserveShape flag) 00234 virtual void close(int rounded = 1, int preserveShape = 0); 00235 00236 // Convert a topologically closed curve into a topologically open one. 00237 // 00238 // For an end interpolation closed curve, we get (topologically) open 00239 // curve: 00240 // 1. For preserve shape: 00241 // exactly the same shape without any open gap. 00242 // end interpolated open curve. 00243 // 2. For non preserve shape: 00244 // hull remained but the curve changed shape with an open gap. 00245 // end interpolated open curve. 00246 // 00247 // For a non end interpolation closed curve, we get (topologically) open 00248 // curve: 00249 // 1. For preserve shape: 00250 // a portion of the original curve, thus have open gap. 00251 // non end interpolated open curve. 00252 // 2. For non preserve shape: 00253 // hull remained but the curve changed shape with an open gap. 00254 // Note: end interpolated open curve. 00255 virtual void open(int preserveShape = 0, int = 0); 00256 00257 // Check if the basis interpolates the endpoints, or change the flag. 00258 short interpolatesEnds(void) const; 00259 void toggleEndCondition(void); 00260 00261 // Insert or delete vertices. The insertion methods return the index if 00262 // successful and -1 otherwise. The deletion methods return 0 if ok and 00263 // -1 otherwise. The insertion methods create the point if it does not 00264 // exist. 00265 virtual int insertVertex(GEO_Point *ppt=0, unsigned int where=0); 00266 virtual int appendVertex(GEO_Point *ppt=0); 00267 virtual int deleteVertex(GEO_Vertex &vtx); 00268 virtual int deleteVertex(unsigned int num); 00269 00270 // Delete the vertex that uses the point. 00271 virtual int ifDetachPoint(GB_Element *ppt) const; 00272 00273 // Assuming the curve is closed, "unroll" it so that the CVs that are 00274 // shared to form a wrapped curve are made unique. Also, the curve becomes 00275 // open. The base class method only flips the open flag. If the curve is 00276 // not closed, the method returns -1. Otherwise it returns 0. 00277 virtual int unroll(int append_pts = 1); 00278 00279 // Shift the array of vertices by an offset and wrap around. 00280 // Cycle a subrange if the curve is closed and cycle the basis 00281 // accordingly. The offset can be either negative or positive. 00282 // Optionally remap the new basis to the original length and origin 00283 virtual int cycle(int amount, int keepSpan = 1); 00284 00285 // Raise the number of CVs to match the newcount. The shape of the curve 00286 // (especially if parametric) should NOT change. Return 0 upon success 00287 // and -1 otherwise. start and stop define which indices to examine 00288 // if newcount is negative it is taken as a relative value. 00289 virtual int loft(int newcount, int start=-1, int stop=-1); 00290 00291 // If this curve is open and non-end-interpolating, insert knots such that 00292 // it becomes end-interpolating without changing its shape. Return 0 if 00293 // successful and -1 othewise. 00294 int clamp(GB_PointGroup *delpoints = 0); 00295 void unclamp(void); 00296 00297 // Query the primitive type. The function is virtual by inheritance. 00298 virtual unsigned getPrimitiveId(void) const; 00299 00300 // Remove the interior knot at knotIdx num times if possible, 00301 // where 1 <= num <= the multiplicity mult of the knot, and 00302 // U[knotIdx] != U[knotIdx+1]. 00303 // If multiplicity mult is not given, the procedure will compute it. 00304 // The tol specifies the tolerance of distance between the knot removable 00305 // position and its actual position. To force knot removal, set tol= -1.0F 00306 // The deleteGroup is used to gather unused cv geo points to be deleted. 00307 // (It is more efficient to delete points in a group.) 00308 // Note: During the process of knot removal, interior cvs geo points 00309 // may changed and/or deleted. 00310 // Output: the actual number of times that the knot got removed. 00311 00312 int unrefine(int knotIdx, GEO_AttributeHandleList &hlist, 00313 int num, int mult = 0, 00314 fpreal tol = 1e-4F, 00315 GB_PointGroup *deleteGroup = 0); 00316 00317 int unrefine(int knotIdx, int num, int mult = 0, 00318 float tol = 1e-4F, 00319 GB_PointGroup *deleteGroup = 0); 00320 00321 int unrefineWAttrib(int knotIdx, 00322 const GB_FloatOffsets &foffsets, int num, 00323 int mult = 0, 00324 float to = 1e-4F, 00325 GB_PointGroup *deleteGroup = 0); 00326 00327 00328 // Get error bound for removing of a knot once. 00329 float getKnotRemovalBound(int knotIdx, int mult=0) const; 00330 00331 // Merge a bunch of NURB curves together. The curves are assumed to 00332 // be all NURBS, all of the same order and characteristics such as 00333 // non/end-interp, open/closed. 00334 static int mergeGroup(GEO_Detail *gdp, GB_PrimitiveGroup *nurbs); 00335 static int mergeGroup(GEO_Detail *gdp, UT_PtrArray<GEO_Primitive*> *nurbcurves_array); 00336 00337 // Reverses the vertices of a given face. 00338 virtual void reverse(); 00339 00340 // If ustart and ustop are two values in the valid interval,ustart < ustop, 00341 // return the part of curve defined by ustart and ustop in a new primitive. 00342 // Return 0 if a problem is encountered. 00343 virtual GEO_Curve *extract(float ustart,float ustop) const; 00344 00345 00346 protected: 00347 // Get a new basis of a type that matches our type: 00348 virtual GB_Basis *newBasis(void) const; 00349 00350 // Parameter correction by Newton iteration. 00351 void correctParam(const UT_Vector4 &p, float &u, 00352 float distTol=1e-10F, float angTol=1e-2F, 00353 int maxIter=50) const; 00354 00355 // Protected methods which translate/transform selected breakpoints and 00356 // perform an interpolation. 00357 virtual int translateBkptsFixed(const UT_IntArray &uindices, 00358 const UT_Vector3 &delta, 00359 GB_PointGroup *ptgroup = NULL, 00360 GEO_Delta *geodelta = 0); 00361 virtual int transformBkptsFixed(const UT_IntArray &uindices, 00362 const UT_Matrix4 &matx, 00363 GB_PointGroup *ptgroup = NULL, 00364 GEO_Delta *geodelta = 0); 00365 00366 // Methods which translate/transform selected breakpoints and do not 00367 // perform an interpolation. 00368 int translateBkptsNonFixed(const UT_IntArray &uindices, 00369 const UT_Vector3 &delta, 00370 GB_PointGroup *ptgroup = NULL, 00371 GEO_Delta *geodelta = 0); 00372 int transformBkptsNonFixed(const UT_IntArray &uindices, 00373 const UT_Matrix4 &matx, 00374 GB_PointGroup *ptgroup = NULL, 00375 GEO_Delta *geodelta = 0); 00376 00377 private: 00378 int xformBreakpoints(const UT_IntArray &uindices, 00379 const UT_Vector3Array &trans, 00380 GB_PointGroup *ptgroup = NULL, 00381 GEO_Delta *geodelta = 0); 00382 00383 // Merge the given basis into ours and refine the curve accordingly. 00384 // It is assumed that both bases have the same order and that "basis" 00385 // contains all our knots plus possibly others. Also, it is assumed that 00386 // "basis" has been GB_Basis::map()-ed onto our knot interval. The 00387 // method returns 0 if OK and -1 if problems. 00388 // Finally, it is assumed that the basis has no knots of higher 00389 // multiplicity than degree. This is not checked for here, so one 00390 // must ensure the resulting basis is of proper length. 00391 int merge(const GB_NUBBasis &basis); 00392 00393 // Return the multiplicity of knot k, cycling the curve first and/or 00394 // unsharing the wrapped points if necessary. 00395 int alignKnot(float k, int &kidx, 00396 int &cycfix, int &interpfix); 00397 void unAlignKnot(int &kidx, int cycfix, int interpfix); 00398 }; 00399 00400 #endif
1.5.9