Panda3D
 All Classes Functions Variables Enumerations
nurbsCurveEvaluator.cxx
00001 // Filename: nurbsCurveEvaluator.cxx
00002 // Created by:  drose (03Dec02)
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 "nurbsCurveEvaluator.h"
00016 
00017 ////////////////////////////////////////////////////////////////////
00018 //     Function: NurbsCurveEvaluator::Constructor
00019 //       Access: Published
00020 //  Description:
00021 ////////////////////////////////////////////////////////////////////
00022 NurbsCurveEvaluator::
00023 NurbsCurveEvaluator() {
00024   _order = 4;
00025   _knots_dirty = true;
00026   _basis_dirty = true;
00027 }
00028 
00029 ////////////////////////////////////////////////////////////////////
00030 //     Function: NurbsCurveEvaluator::Destructor
00031 //       Access: Published
00032 //  Description:
00033 ////////////////////////////////////////////////////////////////////
00034 NurbsCurveEvaluator::
00035 ~NurbsCurveEvaluator() {
00036 }
00037 
00038 ////////////////////////////////////////////////////////////////////
00039 //     Function: NurbsCurveEvaluator::reset
00040 //       Access: Published
00041 //  Description: Resets all the vertices and knots to their default
00042 //               values, and sets the curve up with the indicated
00043 //               number of vertices.  You must then call set_vertex()
00044 //               repeatedly to fill in all of the vertex values
00045 //               appropriately.
00046 ////////////////////////////////////////////////////////////////////
00047 void NurbsCurveEvaluator::
00048 reset(int num_vertices) {
00049   _vertices.clear();
00050   _vertices.reserve(num_vertices);
00051 
00052   for (int i = 0; i < num_vertices; i++) {
00053     _vertices.push_back(NurbsVertex());
00054   }
00055   _knots_dirty = true;
00056   _basis_dirty = true;
00057 }
00058 
00059 ////////////////////////////////////////////////////////////////////
00060 //     Function: NurbsCurveEvaluator::get_vertex_space
00061 //       Access: Published
00062 //  Description: Returns the coordinate space of the nth control
00063 //               vertex of the curve, expressed as a NodePath.
00064 ////////////////////////////////////////////////////////////////////
00065 NodePath NurbsCurveEvaluator::
00066 get_vertex_space(int i, const NodePath &rel_to) const {
00067 #ifndef NDEBUG
00068   static NodePath empty_node_path;
00069   nassertr(i >= 0 && i < (int)_vertices.size(), empty_node_path);
00070 #endif
00071   return _vertices[i].get_space(rel_to);
00072 }
00073 
00074 ////////////////////////////////////////////////////////////////////
00075 //     Function: NurbsCurveEvaluator::set_extended_vertices
00076 //       Access: Public
00077 //  Description: Simultaneously sets several extended values in the
00078 //               slots d through (d + num_values - 1) from the
00079 //               num_values elements of the indicated array.  This is
00080 //               equivalent to calling set_extended_vertex()
00081 //               num_values times.  See set_extended_vertex().
00082 ////////////////////////////////////////////////////////////////////
00083 void NurbsCurveEvaluator::
00084 set_extended_vertices(int i, int d, const PN_stdfloat values[], int num_values) {
00085   nassertv(i >= 0 && i < (int)_vertices.size());
00086 
00087   NurbsVertex &vertex = _vertices[i];
00088   for (int n = 0; n < num_values; n++) {
00089     vertex.set_extended_vertex(d + n, values[n]);
00090   }
00091 }
00092 
00093 ////////////////////////////////////////////////////////////////////
00094 //     Function: NurbsCurveEvaluator::set_knot
00095 //       Access: Published
00096 //  Description: Sets the value of the nth knot.  Each knot value
00097 //               should be greater than or equal to the preceding
00098 //               value.  If no knot values are set, a default knot
00099 //               vector is supplied.
00100 ////////////////////////////////////////////////////////////////////
00101 void NurbsCurveEvaluator::
00102 set_knot(int i, PN_stdfloat knot) {
00103   if (_knots_dirty) {
00104     recompute_knots();
00105   }
00106   nassertv(i >= 0 && i < (int)_knots.size());
00107   _knots[i] = knot;
00108 }
00109 
00110 ////////////////////////////////////////////////////////////////////
00111 //     Function: NurbsCurveEvaluator::get_knot
00112 //       Access: Published
00113 //  Description: Returns the value of the nth knot.
00114 ////////////////////////////////////////////////////////////////////
00115 PN_stdfloat NurbsCurveEvaluator::
00116 get_knot(int i) const {
00117   if (_knots_dirty) {
00118     ((NurbsCurveEvaluator *)this)->recompute_knots();
00119   }
00120   nassertr(i >= 0 && i < (int)_knots.size(), 0.0f);
00121   return _knots[i];
00122 }
00123 
00124 ////////////////////////////////////////////////////////////////////
00125 //     Function: NurbsCurveEvaluator::normalize_knots
00126 //       Access: Published
00127 //  Description: Normalizes the knot sequence so that the parametric
00128 //               range of the curve is 0 .. 1.
00129 ////////////////////////////////////////////////////////////////////
00130 void NurbsCurveEvaluator::
00131 normalize_knots() {
00132   if (_knots_dirty) {
00133     recompute_knots();
00134   }
00135 
00136   if (get_num_vertices() > _order - 1) {
00137     double min_value = _knots[_order - 1];
00138     double max_value = _knots[get_num_vertices()];
00139     double range = (max_value - min_value);
00140 
00141     for (Knots::iterator ki = _knots.begin(); ki != _knots.end(); ++ki) {
00142       (*ki) = ((*ki) - min_value) / range;
00143     }
00144     _basis_dirty = true;
00145   }
00146 }
00147 
00148 ////////////////////////////////////////////////////////////////////
00149 //     Function: NurbsCurveEvaluator::evaluate
00150 //       Access: Published
00151 //  Description: Returns a NurbsCurveResult object that represents the
00152 //               result of applying the knots to all of the current
00153 //               values of the vertices, transformed into the
00154 //               indicated coordinate space.
00155 ////////////////////////////////////////////////////////////////////
00156 PT(NurbsCurveResult) NurbsCurveEvaluator::
00157 evaluate(const NodePath &rel_to) const {
00158   if (_basis_dirty) {
00159     ((NurbsCurveEvaluator *)this)->recompute_basis();
00160   }
00161 
00162   // First, transform the vertices as appropriate.
00163   Vert4Array vecs;
00164   get_vertices(vecs, rel_to);
00165 
00166   // And apply those transformed vertices to the basis matrices to
00167   // derive the result.
00168   return new NurbsCurveResult(_basis, &vecs[0], &_vertices[0],
00169                               (int)_vertices.size());
00170 }
00171 
00172 ////////////////////////////////////////////////////////////////////
00173 //     Function: NurbsCurveEvaluator::evaluate
00174 //       Access: Published
00175 //  Description: Returns a NurbsCurveResult object that represents the
00176 //               result of applying the knots to all of the current
00177 //               values of the vertices, transformed into the
00178 //               indicated coordinate space, and then further
00179 //               transformed by the indicated matrix.
00180 ////////////////////////////////////////////////////////////////////
00181 PT(NurbsCurveResult) NurbsCurveEvaluator::
00182 evaluate(const NodePath &rel_to, const LMatrix4 &mat) const {
00183   if (_basis_dirty) {
00184     ((NurbsCurveEvaluator *)this)->recompute_basis();
00185   }
00186 
00187   // First, transform the vertices as appropriate.
00188   Vert4Array vecs;
00189   get_vertices(vecs, rel_to);
00190 
00191   // And then apply the indicated matrix.
00192   Vert4Array::iterator vi;
00193   for (vi = vecs.begin(); vi != vecs.end(); ++vi) {
00194     (*vi) = (*vi) * mat;
00195   }
00196 
00197   // And apply those transformed vertices to the basis matrices to
00198   // derive the result.
00199   return new NurbsCurveResult(_basis, &vecs[0], &_vertices[0],
00200                               (int)_vertices.size());
00201 }
00202 
00203 ////////////////////////////////////////////////////////////////////
00204 //     Function: NurbsCurveEvaluator::output
00205 //       Access: Published
00206 //  Description: 
00207 ////////////////////////////////////////////////////////////////////
00208 void NurbsCurveEvaluator::
00209 output(ostream &out) const {
00210   out << "NurbsCurve, " << get_num_knots() << " knots.";
00211 }
00212 
00213 
00214 ////////////////////////////////////////////////////////////////////
00215 //     Function: NurbsCurveEvaluator::get_vertices
00216 //       Access: Public
00217 //  Description: Fills the indicated vector with the set of vertices
00218 //               in the curve, transformed to the given space.  This
00219 //               flavor returns the vertices in 4-dimensional
00220 //               homogenous space.
00221 ////////////////////////////////////////////////////////////////////
00222 void NurbsCurveEvaluator::
00223 get_vertices(NurbsCurveEvaluator::Vert4Array &verts, const NodePath &rel_to) const {
00224   int num_vertices = (int)_vertices.size();
00225   verts.reserve(verts.size() + num_vertices);
00226   int vi;
00227   for (vi = 0; vi < num_vertices; vi++) {
00228     verts.push_back(get_vertex(vi, rel_to));
00229   }
00230 }
00231 
00232 ////////////////////////////////////////////////////////////////////
00233 //     Function: NurbsCurveEvaluator::get_vertices
00234 //       Access: Public
00235 //  Description: Fills the indicated vector with the set of vertices
00236 //               in the curve, transformed to the given space.  This
00237 //               flavor returns the vertices in 3-dimensional
00238 //               space.
00239 ////////////////////////////////////////////////////////////////////
00240 void NurbsCurveEvaluator::
00241 get_vertices(NurbsCurveEvaluator::Vert3Array &verts, const NodePath &rel_to) const {
00242   int num_vertices = (int)_vertices.size();
00243   verts.reserve(verts.size() + num_vertices);
00244   int vi;
00245   for (vi = 0; vi < num_vertices; vi++) {
00246     LVecBase4 vertex = get_vertex(vi, rel_to);
00247     LPoint3 v3(vertex[0] / vertex[3], vertex[1] / vertex[3], vertex[2] / vertex[3]);
00248     verts.push_back(v3);
00249   }
00250 }
00251 
00252 ////////////////////////////////////////////////////////////////////
00253 //     Function: NurbsCurveEvaluator::recompute_knots
00254 //       Access: Private
00255 //  Description: Creates a default knot vector.
00256 ////////////////////////////////////////////////////////////////////
00257 void NurbsCurveEvaluator::
00258 recompute_knots() {
00259   _knots.clear();
00260   int num_knots = get_num_knots();
00261   _knots.reserve(num_knots);
00262 
00263   PN_stdfloat value = 0.0f;
00264 
00265   int i = 0;
00266   while (i < _order) {
00267     _knots.push_back(value);
00268     i++;
00269   }
00270   while (i < num_knots - _order) {
00271     value += 1.0f;
00272     _knots.push_back(value);
00273     i++;
00274   }
00275   value += 1.0f;
00276   while (i < num_knots) {
00277     _knots.push_back(value);
00278     i++;
00279   }
00280 
00281   _knots_dirty = false;
00282 }
00283 
00284 ////////////////////////////////////////////////////////////////////
00285 //     Function: NurbsCurveEvaluator::recompute_basis
00286 //       Access: Private
00287 //  Description: Recomputes the basis matrices according to the knot
00288 //               vector.
00289 ////////////////////////////////////////////////////////////////////
00290 void NurbsCurveEvaluator::
00291 recompute_basis() {
00292   if (_knots_dirty) {
00293     ((NurbsCurveEvaluator *)this)->recompute_knots();
00294   }
00295 
00296   _basis.clear(_order);
00297   if ((int)_vertices.size() > _order - 1) {
00298     int min_knot = _order;
00299     int max_knot = (int)_vertices.size();
00300     
00301     for (int i = min_knot; i <= max_knot; i++) {
00302       nassertv(i - 1 >= 0 && i < (int)_knots.size());
00303       if (_knots[i - 1] < _knots[i]) {
00304         // Here's a non-empty segment.
00305         _basis.append_segment(i - _order, &_knots[i - _order]);
00306       }
00307     }
00308   }
00309 
00310   _basis_dirty = false;
00311 }
 All Classes Functions Variables Enumerations