Panda3D
 All Classes Functions Variables Enumerations
nurbsSurfaceEvaluator.cxx
00001 // Filename: nurbsSurfaceEvaluator.cxx
00002 // Created by:  drose (10Oct03)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "nurbsSurfaceEvaluator.h"
00016 
00017 ////////////////////////////////////////////////////////////////////
00018 //     Function: NurbsSurfaceEvaluator::Constructor
00019 //       Access: Published
00020 //  Description:
00021 ////////////////////////////////////////////////////////////////////
00022 NurbsSurfaceEvaluator::
00023 NurbsSurfaceEvaluator() {
00024   _u_order = 4;
00025   _v_order = 4;
00026   _u_knots_dirty = true;
00027   _v_knots_dirty = true;
00028   _u_basis_dirty = true;
00029   _v_basis_dirty = true;
00030 }
00031 
00032 ////////////////////////////////////////////////////////////////////
00033 //     Function: NurbsSurfaceEvaluator::Destructor
00034 //       Access: Published
00035 //  Description:
00036 ////////////////////////////////////////////////////////////////////
00037 NurbsSurfaceEvaluator::
00038 ~NurbsSurfaceEvaluator() {
00039 }
00040 
00041 ////////////////////////////////////////////////////////////////////
00042 //     Function: NurbsSurfaceEvaluator::reset
00043 //       Access: Published
00044 //  Description: Resets all the vertices and knots to their default
00045 //               values, and sets the surface up with the indicated
00046 //               number of vertices.  You must then call set_vertex()
00047 //               repeatedly to fill in all of the vertex values
00048 //               appropriately.
00049 ////////////////////////////////////////////////////////////////////
00050 void NurbsSurfaceEvaluator::
00051 reset(int num_u_vertices, int num_v_vertices) {
00052   int num_vertices = num_u_vertices * num_v_vertices;
00053   _vertices.clear();
00054   _vertices.reserve(num_vertices);
00055   _num_u_vertices = num_u_vertices;
00056   _num_v_vertices = num_v_vertices;
00057 
00058   for (int i = 0; i < num_vertices; i++) {
00059     _vertices.push_back(NurbsVertex());
00060   }
00061   _u_knots_dirty = true;
00062   _v_knots_dirty = true;
00063   _u_basis_dirty = true;
00064   _v_basis_dirty = true;
00065 }
00066 
00067 ////////////////////////////////////////////////////////////////////
00068 //     Function: NurbsSurfaceEvaluator::get_vertex_space
00069 //       Access: Published
00070 //  Description: Returns the coordinate space of the nth control
00071 //               vertex of the surface, expressed as a NodePath.
00072 ////////////////////////////////////////////////////////////////////
00073 NodePath NurbsSurfaceEvaluator::
00074 get_vertex_space(int ui, int vi, const NodePath &rel_to) const {
00075 #ifndef NDEBUG
00076   static NodePath empty_node_path;
00077   nassertr(ui >= 0 && ui < _num_u_vertices &&
00078            vi >= 0 && vi < _num_v_vertices, empty_node_path);
00079 #endif
00080   return vert(ui, vi).get_space(rel_to);
00081 }
00082 
00083 ////////////////////////////////////////////////////////////////////
00084 //     Function: NurbsSurfaceEvaluator::set_extended_vertices
00085 //       Access: Public
00086 //  Description: Simultaneously sets several extended values in the
00087 //               slots d through (d + num_values - 1) from the
00088 //               num_values elements of the indicated array.  This is
00089 //               equivalent to calling set_extended_vertex()
00090 //               num_values times.  See set_extended_vertex().
00091 ////////////////////////////////////////////////////////////////////
00092 void NurbsSurfaceEvaluator::
00093 set_extended_vertices(int ui, int vi, int d, 
00094                       const PN_stdfloat values[], int num_values) {
00095   nassertv(ui >= 0 && ui < _num_u_vertices &&
00096            vi >= 0 && vi < _num_v_vertices);
00097 
00098   NurbsVertex &vertex = vert(ui, vi);
00099   for (int n = 0; n < num_values; n++) {
00100     vertex.set_extended_vertex(d + n, values[n]);
00101   }
00102 }
00103 
00104 ////////////////////////////////////////////////////////////////////
00105 //     Function: NurbsSurfaceEvaluator::set_u_knot
00106 //       Access: Published
00107 //  Description: Sets the value of the nth knot.  Each knot value
00108 //               should be greater than or equal to the preceding
00109 //               value.  If no knot values are set, a default knot
00110 //               vector is supplied.
00111 ////////////////////////////////////////////////////////////////////
00112 void NurbsSurfaceEvaluator::
00113 set_u_knot(int i, PN_stdfloat knot) {
00114   if (_u_knots_dirty) {
00115     recompute_u_knots();
00116   }
00117   nassertv(i >= 0 && i < (int)_u_knots.size());
00118   _u_knots[i] = knot;
00119 }
00120 
00121 ////////////////////////////////////////////////////////////////////
00122 //     Function: NurbsSurfaceEvaluator::get_u_knot
00123 //       Access: Published
00124 //  Description: Returns the value of the nth knot.
00125 ////////////////////////////////////////////////////////////////////
00126 PN_stdfloat NurbsSurfaceEvaluator::
00127 get_u_knot(int i) const {
00128   if (_u_knots_dirty) {
00129     ((NurbsSurfaceEvaluator *)this)->recompute_u_knots();
00130   }
00131   nassertr(i >= 0 && i < (int)_u_knots.size(), 0.0f);
00132   return _u_knots[i];
00133 }
00134 
00135 ////////////////////////////////////////////////////////////////////
00136 //     Function: NurbsSurfaceEvaluator::normalize_u_knots
00137 //       Access: Published
00138 //  Description: Normalizes the knot sequence so that the parametric
00139 //               range of the surface in the U direction is 0 .. 1.
00140 ////////////////////////////////////////////////////////////////////
00141 void NurbsSurfaceEvaluator::
00142 normalize_u_knots() {
00143   if (_u_knots_dirty) {
00144     recompute_u_knots();
00145   }
00146 
00147   if (_num_u_vertices > _u_order - 1) {
00148     double min_value = _u_knots[_u_order - 1];
00149     double max_value = _u_knots[_num_u_vertices];
00150     double range = (max_value - min_value);
00151 
00152     for (Knots::iterator ki = _u_knots.begin(); ki != _u_knots.end(); ++ki) {
00153       (*ki) = ((*ki) - min_value) / range;
00154     }
00155     _u_basis_dirty = true;
00156   }
00157 }
00158 
00159 ////////////////////////////////////////////////////////////////////
00160 //     Function: NurbsSurfaceEvaluator::set_v_knot
00161 //       Access: Published
00162 //  Description: Sets the value of the nth knot.  Each knot value
00163 //               should be greater than or equal to the preceding
00164 //               value.  If no knot values are set, a default knot
00165 //               vector is supplied.
00166 ////////////////////////////////////////////////////////////////////
00167 void NurbsSurfaceEvaluator::
00168 set_v_knot(int i, PN_stdfloat knot) {
00169   if (_v_knots_dirty) {
00170     recompute_v_knots();
00171   }
00172   nassertv(i >= 0 && i < (int)_v_knots.size());
00173   _v_knots[i] = knot;
00174 }
00175 
00176 ////////////////////////////////////////////////////////////////////
00177 //     Function: NurbsSurfaceEvaluator::get_v_knot
00178 //       Access: Published
00179 //  Description: Returns the value of the nth knot.
00180 ////////////////////////////////////////////////////////////////////
00181 PN_stdfloat NurbsSurfaceEvaluator::
00182 get_v_knot(int i) const {
00183   if (_v_knots_dirty) {
00184     ((NurbsSurfaceEvaluator *)this)->recompute_v_knots();
00185   }
00186   nassertr(i >= 0 && i < (int)_v_knots.size(), 0.0f);
00187   return _v_knots[i];
00188 }
00189 
00190 ////////////////////////////////////////////////////////////////////
00191 //     Function: NurbsSurfaceEvaluator::normalize_v_knots
00192 //       Access: Published
00193 //  Description: Normalizes the knot sequence so that the parametric
00194 //               range of the surface in the U direction is 0 .. 1.
00195 ////////////////////////////////////////////////////////////////////
00196 void NurbsSurfaceEvaluator::
00197 normalize_v_knots() {
00198   if (_v_knots_dirty) {
00199     recompute_v_knots();
00200   }
00201 
00202   if (_num_v_vertices > _v_order - 1) {
00203     double min_value = _v_knots[_v_order - 1];
00204     double max_value = _v_knots[_num_v_vertices];
00205     double range = (max_value - min_value);
00206 
00207     for (Knots::iterator ki = _v_knots.begin(); ki != _v_knots.end(); ++ki) {
00208       (*ki) = ((*ki) - min_value) / range;
00209     }
00210     _v_basis_dirty = true;
00211   }
00212 }
00213 
00214 ////////////////////////////////////////////////////////////////////
00215 //     Function: NurbsSurfaceEvaluator::evaluate
00216 //       Access: Published
00217 //  Description: Returns a NurbsSurfaceResult object that represents the
00218 //               result of applying the knots to all of the current
00219 //               values of the vertices, transformed into the
00220 //               indicated coordinate space.
00221 ////////////////////////////////////////////////////////////////////
00222 PT(NurbsSurfaceResult) NurbsSurfaceEvaluator::
00223 evaluate(const NodePath &rel_to) const {
00224   if (_u_basis_dirty) {
00225     ((NurbsSurfaceEvaluator *)this)->recompute_u_basis();
00226   }
00227   if (_v_basis_dirty) {
00228     ((NurbsSurfaceEvaluator *)this)->recompute_v_basis();
00229   }
00230 
00231   // First, transform the vertices as appropriate.
00232   Vert4Array vecs;
00233   get_vertices(vecs, rel_to);
00234 
00235   // And apply those transformed vertices to the basis matrices to
00236   // derive the result.
00237   return new NurbsSurfaceResult(_u_basis, _v_basis,
00238                                 &vecs[0], &_vertices[0],
00239                                 _num_u_vertices, _num_v_vertices);
00240 }
00241 
00242 ////////////////////////////////////////////////////////////////////
00243 //     Function: NurbsSurfaceEvaluator::output
00244 //       Access: Published
00245 //  Description: 
00246 ////////////////////////////////////////////////////////////////////
00247 void NurbsSurfaceEvaluator::
00248 output(ostream &out) const {
00249   out << "NurbsSurface, (" << get_num_u_knots() << ", " << get_num_v_knots()
00250       << ") knots.";
00251 }
00252 
00253 ////////////////////////////////////////////////////////////////////
00254 //     Function: NurbsSurfaceEvaluator::get_vertices
00255 //       Access: Public
00256 //  Description: Fills the indicated vector with the set of vertices
00257 //               in the surface, transformed to the given space.  This
00258 //               flavor returns the vertices in 4-dimensional
00259 //               homogenous space.
00260 //
00261 //               Vertices are arranged in linear sequence, with the v
00262 //               coordinate changing more rapidly.
00263 ////////////////////////////////////////////////////////////////////
00264 void NurbsSurfaceEvaluator::
00265 get_vertices(NurbsSurfaceEvaluator::Vert4Array &verts, const NodePath &rel_to) const {
00266   int num_vertices = (int)_vertices.size();
00267   verts.reserve(verts.size() + num_vertices);
00268   int vi;
00269   for (vi = 0; vi < num_vertices; vi++) {
00270     NodePath space = _vertices[vi].get_space(rel_to);
00271     const LVecBase4 &vertex = _vertices[vi].get_vertex();
00272     if (space.is_empty()) {
00273       verts.push_back(vertex);
00274     } else {
00275       CPT(TransformState) transform = space.get_transform(rel_to);
00276       const LMatrix4 &mat = transform->get_mat();
00277       verts.push_back(vertex * mat);
00278     }
00279   }
00280 }
00281 
00282 ////////////////////////////////////////////////////////////////////
00283 //     Function: NurbsSurfaceEvaluator::get_vertices
00284 //       Access: Public
00285 //  Description: Fills the indicated vector with the set of vertices
00286 //               in the surface, transformed to the given space.  This
00287 //               flavor returns the vertices in 3-dimensional
00288 //               space.
00289 //
00290 //               Vertices are arranged in linear sequence, with the v
00291 //               coordinate changing more rapidly.
00292 ////////////////////////////////////////////////////////////////////
00293 void NurbsSurfaceEvaluator::
00294 get_vertices(NurbsSurfaceEvaluator::Vert3Array &verts, const NodePath &rel_to) const {
00295   int num_vertices = (int)_vertices.size();
00296   verts.reserve(verts.size() + num_vertices);
00297   int vi;
00298   for (vi = 0; vi < num_vertices; vi++) {
00299     const NodePath &space = _vertices[vi].get_space(rel_to);
00300     LVecBase4 vertex = _vertices[vi].get_vertex();
00301     if (!space.is_empty()) {
00302       CPT(TransformState) transform = space.get_transform(rel_to);
00303       const LMatrix4 &mat = transform->get_mat();
00304       vertex = vertex * mat;
00305     }
00306     LPoint3 v3(vertex[0] / vertex[3], vertex[1] / vertex[3], vertex[2] / vertex[3]);
00307     verts.push_back(v3);
00308   }
00309 }
00310 
00311 ////////////////////////////////////////////////////////////////////
00312 //     Function: NurbsSurfaceEvaluator::recompute_u_knots
00313 //       Access: Private
00314 //  Description: Creates a default knot vector.
00315 ////////////////////////////////////////////////////////////////////
00316 void NurbsSurfaceEvaluator::
00317 recompute_u_knots() {
00318   _u_knots.clear();
00319   int num_knots = get_num_u_knots();
00320   _u_knots.reserve(num_knots);
00321 
00322   PN_stdfloat value = 0.0f;
00323 
00324   int i = 0;
00325   while (i < _u_order) {
00326     _u_knots.push_back(value);
00327     i++;
00328   }
00329   while (i < num_knots - _u_order) {
00330     value += 1.0f;
00331     _u_knots.push_back(value);
00332     i++;
00333   }
00334   value += 1.0f;
00335   while (i < num_knots) {
00336     _u_knots.push_back(value);
00337     i++;
00338   }
00339 
00340   _u_knots_dirty = false;
00341 }
00342 
00343 ////////////////////////////////////////////////////////////////////
00344 //     Function: NurbsSurfaceEvaluator::recompute_v_knots
00345 //       Access: Private
00346 //  Description: Creates a default knot vector.
00347 ////////////////////////////////////////////////////////////////////
00348 void NurbsSurfaceEvaluator::
00349 recompute_v_knots() {
00350   _v_knots.clear();
00351   int num_knots = get_num_v_knots();
00352   _v_knots.reserve(num_knots);
00353 
00354   PN_stdfloat value = 0.0f;
00355 
00356   int i = 0;
00357   while (i < _v_order) {
00358     _v_knots.push_back(value);
00359     i++;
00360   }
00361   while (i < num_knots - _v_order) {
00362     value += 1.0f;
00363     _v_knots.push_back(value);
00364     i++;
00365   }
00366   value += 1.0f;
00367   while (i < num_knots) {
00368     _v_knots.push_back(value);
00369     i++;
00370   }
00371 
00372   _v_knots_dirty = false;
00373 }
00374 
00375 ////////////////////////////////////////////////////////////////////
00376 //     Function: NurbsSurfaceEvaluator::recompute_u_basis
00377 //       Access: Private
00378 //  Description: Recomputes the basis matrices according to the knot
00379 //               vector.
00380 ////////////////////////////////////////////////////////////////////
00381 void NurbsSurfaceEvaluator::
00382 recompute_u_basis() {
00383   if (_u_knots_dirty) {
00384     ((NurbsSurfaceEvaluator *)this)->recompute_u_knots();
00385   }
00386 
00387   _u_basis.clear(_u_order);
00388   if (_num_u_vertices > _u_order - 1) {
00389     int min_knot = _u_order;
00390     int max_knot = _num_u_vertices;
00391     
00392     for (int i = min_knot; i <= max_knot; i++) {
00393       nassertv(i - 1 >= 0 && i < (int)_u_knots.size());
00394       if (_u_knots[i - 1] < _u_knots[i]) {
00395         // Here's a non-empty segment.
00396         _u_basis.append_segment(i - _u_order, &_u_knots[i - _u_order]);
00397       }
00398     }
00399   }
00400 
00401   _u_basis_dirty = false;
00402 }
00403 
00404 ////////////////////////////////////////////////////////////////////
00405 //     Function: NurbsSurfaceEvaluator::recompute_v_basis
00406 //       Access: Private
00407 //  Description: Recomputes the basis matrices according to the knot
00408 //               vector.
00409 ////////////////////////////////////////////////////////////////////
00410 void NurbsSurfaceEvaluator::
00411 recompute_v_basis() {
00412   if (_v_knots_dirty) {
00413     ((NurbsSurfaceEvaluator *)this)->recompute_v_knots();
00414   }
00415 
00416   _v_basis.clear(_v_order);
00417   if (_num_v_vertices > _v_order - 1) {
00418     int min_knot = _v_order;
00419     int max_knot = _num_v_vertices;
00420     
00421     for (int i = min_knot; i <= max_knot; i++) {
00422       nassertv(i - 1 >= 0 && i < (int)_v_knots.size());
00423       if (_v_knots[i - 1] < _v_knots[i]) {
00424         // Here's a non-empty segment.
00425         _v_basis.append_segment(i - _v_order, &_v_knots[i - _v_order]);
00426       }
00427     }
00428   }
00429 
00430   _v_basis_dirty = false;
00431 }
 All Classes Functions Variables Enumerations