Răsfoiți Sursa

prepare for n-dimensional nurbs, and nurbs surfaces

David Rose 22 ani în urmă
părinte
comite
b29c053644

+ 51 - 2
panda/src/parametrics/nurbsCurveEvaluator.I

@@ -60,7 +60,11 @@ get_num_vertices() const {
 ////////////////////////////////////////////////////////////////////
 //     Function: NurbsCurveEvaluator::set_vertex
 //       Access: Published
-//  Description: Sets the nth control vertex of the curve.
+//  Description: Sets the nth control vertex of the curve, as a vertex
+//               in 4-d homogeneous space.  In this form, the first
+//               three components of the vertex should already have
+//               been scaled by the fourth component, which is the
+//               homogeneous weight.
 ////////////////////////////////////////////////////////////////////
 INLINE void NurbsCurveEvaluator::
 set_vertex(int i, const LVecBase4f &vertex) {
@@ -71,7 +75,10 @@ set_vertex(int i, const LVecBase4f &vertex) {
 ////////////////////////////////////////////////////////////////////
 //     Function: NurbsCurveEvaluator::set_vertex
 //       Access: Published
-//  Description: Sets the nth control vertex of the curve.
+//  Description: Sets the nth control vertex of the curve.  This
+//               flavor sets the vertex as a 3-d coordinate and a
+//               weight; the 3-d coordinate values are implicitly
+//               scaled up by the weight factor.
 ////////////////////////////////////////////////////////////////////
 INLINE void NurbsCurveEvaluator::
 set_vertex(int i, const LVecBase3f &vertex, float weight) {
@@ -128,6 +135,48 @@ set_vertex_space(int i, const string &space) {
   _vertices[i].set_space(space);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsCurveEvaluator::set_extended_vertex
+//       Access: Public
+//  Description: Sets an n-dimensional vertex value.  This allows
+//               definition of a NURBS surface or curve in a sparse
+//               n-dimensional space, typically used for associating
+//               additional properties (like color or joint
+//               membership) with each vertex of a surface.
+//
+//               The value d is an arbitrary integer value and
+//               specifies the dimension of question for this
+//               particular vertex.  Any number of dimensions may be
+//               specified, and they need not be consecutive.  If a
+//               value for a given dimension is not specified, is it
+//               implicitly 0.0.
+//
+//               The value is implicitly scaled by the homogenous
+//               weight value--that is, the fourth component of the
+//               value passed to set_vertex().  This means the
+//               ordinary vertex must be set first, before the
+//               extended vertices can be set.
+////////////////////////////////////////////////////////////////////
+void NurbsCurveEvaluator::
+set_extended_vertex(int i, int d, float value) {
+  nassertv(i >= 0 && i < (int)_vertices.size());
+  _vertices[i].set_extended_vertex(d, value);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsCurveEvaluator::float_extended_vertex
+//       Access: Public
+//  Description: Returns an n-dimensional vertex value.  See
+//               set_extended_vertex().  This returns the value set
+//               for the indicated dimension, or 0.0 if nothing has
+//               been set.
+////////////////////////////////////////////////////////////////////
+float NurbsCurveEvaluator::
+get_extended_vertex(int i, int d) const {
+  nassertr(i >= 0 && i < (int)_vertices.size(), 0.0f);
+  return _vertices[i].get_extended_vertex(d);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: NurbsCurveEvaluator::get_num_knots
 //       Access: Published

+ 6 - 5
panda/src/parametrics/nurbsCurveEvaluator.cxx

@@ -121,12 +121,13 @@ evaluate(const NodePath &rel_to) const {
   }
 
   // First, transform the vertices as appropriate.
-  pvector<LVecBase4f> verts;
-  get_vertices(verts, rel_to);
+  pvector<LVecBase4f> vecs;
+  get_vertices(vecs, rel_to);
 
   // And apply those transformed vertices to the basis matrices to
   // derive the result.
-  return new NurbsCurveResult(_basis, _order, &verts[0], (int)verts.size());
+  return new NurbsCurveResult(_basis, &vecs[0], &_vertices[0],
+                              (int)_vertices.size());
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -223,7 +224,7 @@ recompute_basis() {
     ((NurbsCurveEvaluator *)this)->recompute_knots();
   }
 
-  _basis.clear();
+  _basis.clear(_order);
   if ((int)_vertices.size() > _order - 1) {
     int min_knot = _order;
     int max_knot = (int)_vertices.size() + 1;
@@ -232,7 +233,7 @@ recompute_basis() {
       nassertv(i - 1 >= 0 && i < (int)_knots.size());
       if (_knots[i - 1] < _knots[i]) {
         // Here's a non-empty segment.
-        _basis.append_segment(_order, i - _order, &_knots[i - _order]);
+        _basis.append_segment(i - _order, &_knots[i - _order]);
       }
     }
   }

+ 3 - 0
panda/src/parametrics/nurbsCurveEvaluator.h

@@ -64,6 +64,9 @@ PUBLISHED:
   INLINE void set_vertex_space(int i, const string &space);
   NodePath get_vertex_space(int i, const NodePath &rel_to) const;
 
+  INLINE void set_extended_vertex(int i, int d, float value);
+  INLINE float get_extended_vertex(int i, int d) const;
+
   INLINE int get_num_knots() const;
   void set_knot(int i, float knot);
   float get_knot(int i) const;

+ 23 - 6
panda/src/parametrics/nurbsCurveResult.I

@@ -34,7 +34,7 @@ INLINE NurbsCurveResult::
 ////////////////////////////////////////////////////////////////////
 INLINE float NurbsCurveResult::
 get_start_t() const {
-  return _prod.get_start_t();
+  return _basis.get_start_t();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -44,7 +44,7 @@ get_start_t() const {
 ////////////////////////////////////////////////////////////////////
 INLINE float NurbsCurveResult::
 get_end_t() const {
-  return _prod.get_end_t();
+  return _basis.get_end_t();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -61,7 +61,7 @@ eval_point(float t, LVecBase3f &point) {
     return false;
   }
 
-  eval_segment_point(segment, _prod.scale_t(segment, t), point);
+  eval_segment_point(segment, _basis.scale_t(segment, t), point);
   return true;
 }
 
@@ -80,10 +80,27 @@ eval_tangent(float t, LVecBase3f &tangent) {
     return false;
   }
 
-  eval_segment_tangent(segment, _prod.scale_t(segment, t), tangent);
+  eval_segment_tangent(segment, _basis.scale_t(segment, t), tangent);
   return true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsCurveResult::eval_extended_point
+//       Access: Published
+//  Description: Evaluates the curve in n-dimensional space according
+//               to the extended vertices associated with the curve in
+//               the indicated dimension.
+////////////////////////////////////////////////////////////////////
+INLINE float NurbsCurveResult::
+eval_extended_point(float t, int d) {
+  int segment = find_segment(t);
+  if (segment == -1) {
+    return 0.0f;
+  }
+
+  return eval_segment_extended_point(segment, _basis.scale_t(segment, t), d);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: NurbsCurveResult::get_num_segments
 //       Access: Public
@@ -94,7 +111,7 @@ eval_tangent(float t, LVecBase3f &tangent) {
 ////////////////////////////////////////////////////////////////////
 INLINE int NurbsCurveResult::
 get_num_segments() const {
-  return _prod.get_num_segments();
+  return _basis.get_num_segments();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -107,5 +124,5 @@ get_num_segments() const {
 ////////////////////////////////////////////////////////////////////
 INLINE float NurbsCurveResult::
 get_segment_t(int segment, float t) const {
-  return t * (_prod.get_to(segment) - _prod.get_from(segment)) + _prod.get_from(segment);
+  return t * (_basis.get_to(segment) - _basis.get_from(segment)) + _basis.get_from(segment);
 }

+ 76 - 24
panda/src/parametrics/nurbsCurveResult.cxx

@@ -27,20 +27,26 @@
 //               and the indicated table of control vertex positions.
 ////////////////////////////////////////////////////////////////////
 NurbsCurveResult::
-NurbsCurveResult(const NurbsMatrixVector &basis, int order,
-                 const LVecBase4f verts[], int num_vertices) {
+NurbsCurveResult(const NurbsMatrixVector &basis,
+                 const LVecBase4f vecs[], const NurbsVertex *verts,
+                 int num_vertices) :
+  _basis(basis),
+  _verts(verts)
+{
   _last_segment = -1;
+  int order = _basis.get_order();
+  int num_segments = _basis.get_num_segments();
 
-  int num_segments = basis.get_num_segments();
+  _composed.reserve(num_segments);
   for (int i = 0; i < num_segments; i++) {
-    int vi = basis.get_vertex_index(i);
+    int vi = _basis.get_vertex_index(i);
     nassertv(vi >= 0 && vi < num_vertices);
 
-    // Create a matrix from our (up to) four involved vertices.
+    // Create a geometry matrix from our (up to) four involved vertices.
     LMatrix4f geom;
     int ci = 0;
     while (ci < order) {
-      geom.set_row(ci, verts[vi + ci]);
+      geom.set_row(ci, vecs[vi + ci]);
       ci++;
     }
     while (ci < 4) {
@@ -48,9 +54,11 @@ NurbsCurveResult(const NurbsMatrixVector &basis, int order,
       ci++;
     }
 
-    // And compose this matrix with the segment to produce a new
-    // matrix.
-    _prod.compose_segment(basis, i, geom);
+    // And compose this geometry matrix with the basis matrix to
+    // produce a new matrix, which will be used to evaluate the curve.
+    LMatrix4f result;
+    result.multiply(_basis.get_basis(i), geom);
+    _composed.push_back(result);
   }
 }
 
@@ -74,12 +82,13 @@ NurbsCurveResult(const NurbsMatrixVector &basis, int order,
 ////////////////////////////////////////////////////////////////////
 void NurbsCurveResult::
 eval_segment_point(int segment, float t, LVecBase3f &point) const {
-  const LMatrix4f &mat = _prod.get_matrix(segment);
-
   float t2 = t*t;
   LVecBase4f tvec(t*t2, t2, t, 1.0f);
-  LVecBase4f r = tvec * mat;
-  point.set(r[0] / r[3], r[1] / r[3], r[2] / r[3]);
+
+  float weight = tvec.dot(_composed[segment].get_col(3));
+  point.set(tvec.dot(_composed[segment].get_col(0)) / weight,
+            tvec.dot(_composed[segment].get_col(1)) / weight,
+            tvec.dot(_composed[segment].get_col(2)) / weight);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -92,12 +101,54 @@ eval_segment_point(int segment, float t, LVecBase3f &point) const {
 ////////////////////////////////////////////////////////////////////
 void NurbsCurveResult::
 eval_segment_tangent(int segment, float t, LVecBase3f &tangent) const {
-  const LMatrix4f &mat = _prod.get_matrix(segment);
-
   float t2 = t*t;
   LVecBase4f tvec(t2, t, 1.0f, 0.0f);
-  LVecBase4f r = tvec * mat;
-  tangent.set(r[0], r[1], r[2]);
+
+  tangent.set(tvec.dot(_composed[segment].get_col(0)),
+              tvec.dot(_composed[segment].get_col(1)),
+              tvec.dot(_composed[segment].get_col(2)));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsCurveResult::eval_segment_extended_point
+//       Access: Published
+//  Description: Evaluates the curve in n-dimensional space according
+//               to the extended vertices associated with the curve in
+//               the indicated dimension.
+////////////////////////////////////////////////////////////////////
+float NurbsCurveResult::
+eval_segment_extended_point(int segment, float t, int d) const {
+  nassertr(segment >= 0 && segment < _basis.get_num_segments(), 0.0f);
+
+  int order = _basis.get_order();
+  int vi = _basis.get_vertex_index(segment);
+
+  LVecBase4f geom;
+  int ci = 0;
+  while (ci < order) {
+    geom[ci] = _verts[vi + ci].get_extended_vertex(d);
+    ci++;
+  }
+  while (ci < 4) {
+    geom[ci] = 0.0f;
+    ci++;
+  }
+
+  const LMatrix4f &basis = _basis.get_basis(segment);
+
+  // Compute matrix * column vector.
+  LVecBase4f composed_geom(basis.get_row(0).dot(geom),
+                           basis.get_row(1).dot(geom),
+                           basis.get_row(2).dot(geom),
+                           basis.get_row(3).dot(geom));
+
+  float t2 = t*t;
+  LVecBase4f tvec(t*t2, t2, t, 1.0f);
+
+  float weight = tvec.dot(_composed[segment].get_col(3));
+
+  float result = tvec.dot(composed_geom) / weight;
+  return result;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -111,7 +162,7 @@ int NurbsCurveResult::
 find_segment(float t) {
   // Trivially check the endpoints of the curve.
   if (t >= get_end_t()) {
-    return _prod.get_num_segments() - 1;
+    return _basis.get_num_segments() - 1;
   } else if (t <= get_start_t()) {
     return 0;
   }
@@ -123,11 +174,11 @@ find_segment(float t) {
   }
 
   // Look for the segment the hard way.
-  int segment = r_find_segment(t, 0, _prod.get_num_segments() - 1);
+  int segment = r_find_segment(t, 0, _basis.get_num_segments() - 1);
   if (segment != -1) {
     _last_segment = segment;
-    _last_from = _prod.get_from(segment);
-    _last_to = _prod.get_to(segment);
+    _last_from = _basis.get_from(segment);
+    _last_to = _basis.get_to(segment);
   }
   return segment;
 }
@@ -147,10 +198,10 @@ r_find_segment(float t, int top, int bot) const {
     return -1;
   }
   int mid = (top + bot) / 2;
-  nassertr(mid >= 0 && mid < _prod.get_num_segments(), -1);
+  nassertr(mid >= 0 && mid < _basis.get_num_segments(), -1);
 
-  float from = _prod.get_from(mid);
-  float to = _prod.get_to(mid);
+  float from = _basis.get_from(mid);
+  float to = _basis.get_to(mid);
   if (from > t) {
     // Too high, try lower.
     return r_find_segment(t, top, mid - 1);
@@ -164,3 +215,4 @@ r_find_segment(float t, int top, int bot) const {
     return mid;
   }
 }
+

+ 16 - 3
panda/src/parametrics/nurbsCurveResult.h

@@ -23,6 +23,8 @@
 #include "referenceCount.h"
 #include "nurbsMatrixVector.h"
 
+class NurbsVertex;
+
 ////////////////////////////////////////////////////////////////////
 //       Class : NurbsCurveResult
 // Description : The result of a NurbsCurveEvaluator.  This object
@@ -39,8 +41,9 @@
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA NurbsCurveResult : public ReferenceCount {
 public:
-  NurbsCurveResult(const NurbsMatrixVector &basis, int order,
-                   const LVecBase4f verts[], int num_vertices);
+  NurbsCurveResult(const NurbsMatrixVector &basis, 
+                   const LVecBase4f vecs[], const NurbsVertex *verts,
+                   int num_vertices);
 
 PUBLISHED:
   INLINE ~NurbsCurveResult();
@@ -50,17 +53,27 @@ PUBLISHED:
 
   INLINE bool eval_point(float t, LVecBase3f &point);
   INLINE bool eval_tangent(float t, LVecBase3f &tangent);
+  INLINE float eval_extended_point(float t, int d);
   
   INLINE int get_num_segments() const;
   void eval_segment_point(int segment, float t, LVecBase3f &point) const;
   void eval_segment_tangent(int segment, float t, LVecBase3f &tangent) const;
+  float eval_segment_extended_point(int segment, float t, int d) const;
   INLINE float get_segment_t(int segment, float t) const;
   
 private:
   int find_segment(float t);
   int r_find_segment(float t, int top, int bot) const;
 
-  NurbsMatrixVector _prod;
+  NurbsMatrixVector _basis;
+  const NurbsVertex *_verts;
+
+  // We pre-compose the basis matrix and the geometry vectors, so we
+  // have these handy for evaluation.  There is one entry in the
+  // _composed_vector for each entry in basis._segments.
+  typedef pvector<LMatrix4f> ComposedGeom;
+  ComposedGeom _composed;
+
 
   int _last_segment;
   float _last_from;

+ 18 - 4
panda/src/parametrics/nurbsMatrixVector.I

@@ -24,6 +24,7 @@
 ////////////////////////////////////////////////////////////////////
 INLINE NurbsMatrixVector::
 NurbsMatrixVector() {
+  _order = 0;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -35,6 +36,16 @@ INLINE NurbsMatrixVector::
 ~NurbsMatrixVector() {
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsMatrixVector::get_order
+//       Access: Public
+//  Description: Returns the order of the segments in the curve.
+////////////////////////////////////////////////////////////////////
+INLINE int NurbsMatrixVector::
+get_order() const {
+  return _order;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: NurbsMatrixVector::get_num_segments
 //       Access: Public
@@ -105,14 +116,17 @@ get_to(int segment) const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: NurbsMatrixVector::get_matrix
+//     Function: NurbsMatrixVector::get_basis
 //       Access: Public
-//  Description: Returns the matrix associated with the nth segment.
+//  Description: Returns the basis matrix associated with the nth
+//               segment.  This is the pure matrix based on the knot
+//               vector over the segment; it does not depend on the
+//               control vertices.
 ////////////////////////////////////////////////////////////////////
 INLINE const LMatrix4f &NurbsMatrixVector::
-get_matrix(int segment) const {
+get_basis(int segment) const {
   nassertr(segment >= 0 && segment < (int)_segments.size(), LMatrix4f::ident_mat());
-  return _segments[segment]._matrix;
+  return _segments[segment]._basis;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 12 - 33
panda/src/parametrics/nurbsMatrixVector.cxx

@@ -24,7 +24,8 @@
 //  Description: Removes all the segments from the curve.
 ////////////////////////////////////////////////////////////////////
 void NurbsMatrixVector::
-clear() {
+clear(int order) {
+  _order = order;
   _segments.clear();
 }
 
@@ -35,16 +36,16 @@ clear() {
 //               and appends it to the set of basis matrices.
 ////////////////////////////////////////////////////////////////////
 void NurbsMatrixVector::
-append_segment(int order, int vertex_index, const float knots[]) {
+append_segment(int vertex_index, const float knots[]) {
   int i;
 
   // Scale the supplied knots to the range 0..1.
   float scaled_knots[8];
-  float min_k = knots[order - 1];
-  float max_k = knots[order];
+  float min_k = knots[_order - 1];
+  float max_k = knots[_order];
 
   nassertv(min_k != max_k);
-  for (i = 0; i < order + order; i++) {
+  for (i = 0; i < _order + _order; i++) {
     scaled_knots[i] = (knots[i] - min_k) / (max_k - min_k);
   }
 
@@ -53,40 +54,18 @@ append_segment(int order, int vertex_index, const float knots[]) {
   segment._from = min_k;
   segment._to = max_k;
 
-  for (i = 0; i < order; i++) {
-    LVecBase4f b = nurbs_blending_function(order, i, order, scaled_knots);
-    segment._matrix.set_col(i, b);
+  for (i = 0; i < _order; i++) {
+    LVecBase4f b = nurbs_blending_function(_order, i, _order, scaled_knots);
+    segment._basis.set_col(i, b);
   }
 
-  for (i = order; i < 4; i++) {
-    segment._matrix.set_col(i, LVecBase4f::zero());
+  for (i = _order; i < 4; i++) {
+    segment._basis.set_col(i, LVecBase4f::zero());
   }
 
   _segments.push_back(segment);
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: NurbsMatrixVector::compose_segment
-//       Access: Public
-//  Description: Appends a new segment to the vector by composing the
-//               indicated geometry matrix with the indicated basis
-//               matrix from the given vector.
-////////////////////////////////////////////////////////////////////
-void NurbsMatrixVector::
-compose_segment(const NurbsMatrixVector &basis, int segment, 
-                const LMatrix4f &geom) {
-  nassertv(segment >= 0 && segment < (int)basis._segments.size());
-  const Segment &source = basis._segments[segment];
-
-  Segment dest;
-  dest._vertex_index = source._vertex_index;
-  dest._from = source._from;
-  dest._to = source._to;
-  dest._matrix = source._matrix * geom;
-
-  _segments.push_back(dest);
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: NurbsMatrixVector::nurbs_blending_function
 //       Access: Private, Static
@@ -99,7 +78,7 @@ nurbs_blending_function(int order, int i, int j, const float knots[]) {
   LVecBase4f r;
 
   if (j == 1) {
-    if (i == order-1 && knots[i] < knots[i+1]) {
+    if (i == order - 1 && knots[i] < knots[i + 1]) {
       r.set(0.0f, 0.0f, 0.0f, 1.0f);
     } else {
       r.set(0.0f, 0.0f, 0.0f, 0.0f);

+ 11 - 7
panda/src/parametrics/nurbsMatrixVector.h

@@ -24,6 +24,8 @@
 #include "pvector.h"
 #include "pmap.h"
 
+class NurbsVertex;
+
 ////////////////////////////////////////////////////////////////////
 //       Class : NurbsMatrixVector
 // Description : This encapsulates a series of matrices that are used
@@ -37,11 +39,13 @@
 //               eventually replace the whole ParametricCurve class
 //               hierarchy.
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA NurbsMatrixVector {
+class NurbsMatrixVector {
 public:
   INLINE NurbsMatrixVector();
   INLINE ~NurbsMatrixVector();
 
+  INLINE int get_order() const;
+
   INLINE int get_num_segments() const;
   INLINE float get_start_t() const;
   INLINE float get_end_t() const;
@@ -49,25 +53,25 @@ public:
   INLINE int get_vertex_index(int segment) const;
   INLINE float get_from(int segment) const;
   INLINE float get_to(int segment) const;
-  INLINE const LMatrix4f &get_matrix(int segment) const;
+  INLINE const LMatrix4f &get_basis(int segment) const;
   INLINE float scale_t(int segment, float t) const;
 
-  void clear();
-  void append_segment(int order, int vertex_index, const float knots[]);
-  void compose_segment(const NurbsMatrixVector &basis, int segment, 
-                       const LMatrix4f &geom);
+  void clear(int order);
+  void append_segment(int vertex_index, const float knots[]);
 
 private:
   static LVecBase4f nurbs_blending_function(int order, int i, int j, 
                                             const float knots[]);
 
 private:
+  int _order;
+
   class Segment {
   public:
     int _vertex_index;
     float _from;
     float _to;
-    LMatrix4f _matrix;
+    LMatrix4f _basis;
   };
 
   typedef pvector<Segment> Segments;

+ 45 - 0
panda/src/parametrics/nurbsVertex.cxx

@@ -18,3 +18,48 @@
 
 #include "nurbsVertex.h"
 
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsVertex::set_extended_vertex
+//       Access: Public
+//  Description: Sets an n-dimensional vertex value.  This allows
+//               definition of a NURBS surface or curve in a sparse
+//               n-dimensional space, typically used for associating
+//               additional properties (like color or joint
+//               membership) with each vertex of a surface.
+//
+//               The value d is an arbitrary integer value and
+//               specifies the dimension of question for this
+//               particular vertex.  Any number of dimensions may be
+//               specified, and they need not be consecutive.  If a
+//               value for a given dimension is not specified, is it
+//               implicitly 0.0.
+//
+//               The value is implicitly scaled by the homogenous
+//               weight value--that is, the fourth component of the
+//               value passed to set_vertex().  This means the
+//               ordinary vertex must be set first, before the
+//               extended vertices can be set.
+////////////////////////////////////////////////////////////////////
+void NurbsVertex::
+set_extended_vertex(int d, float value) {
+  _extended[d] = value * _vertex[3];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsVertex::float_extended_vertex
+//       Access: Public
+//  Description: Returns an n-dimensional vertex value.  See
+//               set_extended_vertex().  This returns the value set
+//               for the indicated dimension, or 0.0 if nothing has
+//               been set.
+////////////////////////////////////////////////////////////////////
+float NurbsVertex::
+get_extended_vertex(int d) const {
+  Extended::const_iterator ei;
+  ei = _extended.find(d);
+  if (ei == _extended.end()) {
+    return 0.0f;
+  }
+  return (*ei).second;
+}

+ 6 - 0
panda/src/parametrics/nurbsVertex.h

@@ -22,6 +22,7 @@
 #include "pandabase.h"
 #include "luse.h"
 #include "nodePath.h"
+#include "pmap.h"
 
 ////////////////////////////////////////////////////////////////////
 //       Class : NurbsVertex
@@ -51,10 +52,15 @@ public:
   INLINE void set_space(const string &space);
   INLINE NodePath get_space(const NodePath &rel_to) const;
 
+  void set_extended_vertex(int d, float value);
+  float get_extended_vertex(int d) const;
+
 private:
   LVecBase4f _vertex;
   NodePath _space;
   string _space_path;
+  typedef pmap<int, float> Extended;
+  Extended _extended;
 };
 
 #include "nurbsVertex.I"