Panda3D
|
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 }