Panda3D
 All Classes Functions Variables Enumerations
nurbsSurfaceEvaluator.cxx
1 // Filename: nurbsSurfaceEvaluator.cxx
2 // Created by: drose (10Oct03)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "nurbsSurfaceEvaluator.h"
16 
17 ////////////////////////////////////////////////////////////////////
18 // Function: NurbsSurfaceEvaluator::Constructor
19 // Access: Published
20 // Description:
21 ////////////////////////////////////////////////////////////////////
22 NurbsSurfaceEvaluator::
23 NurbsSurfaceEvaluator() {
24  _u_order = 4;
25  _v_order = 4;
26  _u_knots_dirty = true;
27  _v_knots_dirty = true;
28  _u_basis_dirty = true;
29  _v_basis_dirty = true;
30 }
31 
32 ////////////////////////////////////////////////////////////////////
33 // Function: NurbsSurfaceEvaluator::Destructor
34 // Access: Published
35 // Description:
36 ////////////////////////////////////////////////////////////////////
37 NurbsSurfaceEvaluator::
38 ~NurbsSurfaceEvaluator() {
39 }
40 
41 ////////////////////////////////////////////////////////////////////
42 // Function: NurbsSurfaceEvaluator::reset
43 // Access: Published
44 // Description: Resets all the vertices and knots to their default
45 // values, and sets the surface up with the indicated
46 // number of vertices. You must then call set_vertex()
47 // repeatedly to fill in all of the vertex values
48 // appropriately.
49 ////////////////////////////////////////////////////////////////////
51 reset(int num_u_vertices, int num_v_vertices) {
52  int num_vertices = num_u_vertices * num_v_vertices;
53  _vertices.clear();
54  _vertices.reserve(num_vertices);
55  _num_u_vertices = num_u_vertices;
56  _num_v_vertices = num_v_vertices;
57 
58  for (int i = 0; i < num_vertices; i++) {
59  _vertices.push_back(NurbsVertex());
60  }
61  _u_knots_dirty = true;
62  _v_knots_dirty = true;
63  _u_basis_dirty = true;
64  _v_basis_dirty = true;
65 }
66 
67 ////////////////////////////////////////////////////////////////////
68 // Function: NurbsSurfaceEvaluator::get_vertex_space
69 // Access: Published
70 // Description: Returns the coordinate space of the nth control
71 // vertex of the surface, expressed as a NodePath.
72 ////////////////////////////////////////////////////////////////////
74 get_vertex_space(int ui, int vi, const NodePath &rel_to) const {
75 #ifndef NDEBUG
76  static NodePath empty_node_path;
77  nassertr(ui >= 0 && ui < _num_u_vertices &&
78  vi >= 0 && vi < _num_v_vertices, empty_node_path);
79 #endif
80  return vert(ui, vi).get_space(rel_to);
81 }
82 
83 ////////////////////////////////////////////////////////////////////
84 // Function: NurbsSurfaceEvaluator::set_extended_vertices
85 // Access: Public
86 // Description: Simultaneously sets several extended values in the
87 // slots d through (d + num_values - 1) from the
88 // num_values elements of the indicated array. This is
89 // equivalent to calling set_extended_vertex()
90 // num_values times. See set_extended_vertex().
91 ////////////////////////////////////////////////////////////////////
93 set_extended_vertices(int ui, int vi, int d,
94  const PN_stdfloat values[], int num_values) {
95  nassertv(ui >= 0 && ui < _num_u_vertices &&
96  vi >= 0 && vi < _num_v_vertices);
97 
98  NurbsVertex &vertex = vert(ui, vi);
99  for (int n = 0; n < num_values; n++) {
100  vertex.set_extended_vertex(d + n, values[n]);
101  }
102 }
103 
104 ////////////////////////////////////////////////////////////////////
105 // Function: NurbsSurfaceEvaluator::set_u_knot
106 // Access: Published
107 // Description: Sets the value of the nth knot. Each knot value
108 // should be greater than or equal to the preceding
109 // value. If no knot values are set, a default knot
110 // vector is supplied.
111 ////////////////////////////////////////////////////////////////////
113 set_u_knot(int i, PN_stdfloat knot) {
114  if (_u_knots_dirty) {
115  recompute_u_knots();
116  }
117  nassertv(i >= 0 && i < (int)_u_knots.size());
118  _u_knots[i] = knot;
119 }
120 
121 ////////////////////////////////////////////////////////////////////
122 // Function: NurbsSurfaceEvaluator::get_u_knot
123 // Access: Published
124 // Description: Returns the value of the nth knot.
125 ////////////////////////////////////////////////////////////////////
126 PN_stdfloat NurbsSurfaceEvaluator::
127 get_u_knot(int i) const {
128  if (_u_knots_dirty) {
129  ((NurbsSurfaceEvaluator *)this)->recompute_u_knots();
130  }
131  nassertr(i >= 0 && i < (int)_u_knots.size(), 0.0f);
132  return _u_knots[i];
133 }
134 
135 ////////////////////////////////////////////////////////////////////
136 // Function: NurbsSurfaceEvaluator::normalize_u_knots
137 // Access: Published
138 // Description: Normalizes the knot sequence so that the parametric
139 // range of the surface in the U direction is 0 .. 1.
140 ////////////////////////////////////////////////////////////////////
143  if (_u_knots_dirty) {
144  recompute_u_knots();
145  }
146 
147  if (_num_u_vertices > _u_order - 1) {
148  double min_value = _u_knots[_u_order - 1];
149  double max_value = _u_knots[_num_u_vertices];
150  double range = (max_value - min_value);
151 
152  for (Knots::iterator ki = _u_knots.begin(); ki != _u_knots.end(); ++ki) {
153  (*ki) = ((*ki) - min_value) / range;
154  }
155  _u_basis_dirty = true;
156  }
157 }
158 
159 ////////////////////////////////////////////////////////////////////
160 // Function: NurbsSurfaceEvaluator::set_v_knot
161 // Access: Published
162 // Description: Sets the value of the nth knot. Each knot value
163 // should be greater than or equal to the preceding
164 // value. If no knot values are set, a default knot
165 // vector is supplied.
166 ////////////////////////////////////////////////////////////////////
168 set_v_knot(int i, PN_stdfloat knot) {
169  if (_v_knots_dirty) {
170  recompute_v_knots();
171  }
172  nassertv(i >= 0 && i < (int)_v_knots.size());
173  _v_knots[i] = knot;
174 }
175 
176 ////////////////////////////////////////////////////////////////////
177 // Function: NurbsSurfaceEvaluator::get_v_knot
178 // Access: Published
179 // Description: Returns the value of the nth knot.
180 ////////////////////////////////////////////////////////////////////
181 PN_stdfloat NurbsSurfaceEvaluator::
182 get_v_knot(int i) const {
183  if (_v_knots_dirty) {
184  ((NurbsSurfaceEvaluator *)this)->recompute_v_knots();
185  }
186  nassertr(i >= 0 && i < (int)_v_knots.size(), 0.0f);
187  return _v_knots[i];
188 }
189 
190 ////////////////////////////////////////////////////////////////////
191 // Function: NurbsSurfaceEvaluator::normalize_v_knots
192 // Access: Published
193 // Description: Normalizes the knot sequence so that the parametric
194 // range of the surface in the U direction is 0 .. 1.
195 ////////////////////////////////////////////////////////////////////
198  if (_v_knots_dirty) {
199  recompute_v_knots();
200  }
201 
202  if (_num_v_vertices > _v_order - 1) {
203  double min_value = _v_knots[_v_order - 1];
204  double max_value = _v_knots[_num_v_vertices];
205  double range = (max_value - min_value);
206 
207  for (Knots::iterator ki = _v_knots.begin(); ki != _v_knots.end(); ++ki) {
208  (*ki) = ((*ki) - min_value) / range;
209  }
210  _v_basis_dirty = true;
211  }
212 }
213 
214 ////////////////////////////////////////////////////////////////////
215 // Function: NurbsSurfaceEvaluator::evaluate
216 // Access: Published
217 // Description: Returns a NurbsSurfaceResult object that represents the
218 // result of applying the knots to all of the current
219 // values of the vertices, transformed into the
220 // indicated coordinate space.
221 ////////////////////////////////////////////////////////////////////
223 evaluate(const NodePath &rel_to) const {
224  if (_u_basis_dirty) {
225  ((NurbsSurfaceEvaluator *)this)->recompute_u_basis();
226  }
227  if (_v_basis_dirty) {
228  ((NurbsSurfaceEvaluator *)this)->recompute_v_basis();
229  }
230 
231  // First, transform the vertices as appropriate.
232  Vert4Array vecs;
233  get_vertices(vecs, rel_to);
234 
235  // And apply those transformed vertices to the basis matrices to
236  // derive the result.
237  return new NurbsSurfaceResult(_u_basis, _v_basis,
238  &vecs[0], &_vertices[0],
239  _num_u_vertices, _num_v_vertices);
240 }
241 
242 ////////////////////////////////////////////////////////////////////
243 // Function: NurbsSurfaceEvaluator::output
244 // Access: Published
245 // Description:
246 ////////////////////////////////////////////////////////////////////
247 void NurbsSurfaceEvaluator::
248 output(ostream &out) const {
249  out << "NurbsSurface, (" << get_num_u_knots() << ", " << get_num_v_knots()
250  << ") knots.";
251 }
252 
253 ////////////////////////////////////////////////////////////////////
254 // Function: NurbsSurfaceEvaluator::get_vertices
255 // Access: Public
256 // Description: Fills the indicated vector with the set of vertices
257 // in the surface, transformed to the given space. This
258 // flavor returns the vertices in 4-dimensional
259 // homogenous space.
260 //
261 // Vertices are arranged in linear sequence, with the v
262 // coordinate changing more rapidly.
263 ////////////////////////////////////////////////////////////////////
265 get_vertices(NurbsSurfaceEvaluator::Vert4Array &verts, const NodePath &rel_to) const {
266  int num_vertices = (int)_vertices.size();
267  verts.reserve(verts.size() + num_vertices);
268  int vi;
269  for (vi = 0; vi < num_vertices; vi++) {
270  NodePath space = _vertices[vi].get_space(rel_to);
271  const LVecBase4 &vertex = _vertices[vi].get_vertex();
272  if (space.is_empty()) {
273  verts.push_back(vertex);
274  } else {
275  CPT(TransformState) transform = space.get_transform(rel_to);
276  const LMatrix4 &mat = transform->get_mat();
277  verts.push_back(vertex * mat);
278  }
279  }
280 }
281 
282 ////////////////////////////////////////////////////////////////////
283 // Function: NurbsSurfaceEvaluator::get_vertices
284 // Access: Public
285 // Description: Fills the indicated vector with the set of vertices
286 // in the surface, transformed to the given space. This
287 // flavor returns the vertices in 3-dimensional
288 // space.
289 //
290 // Vertices are arranged in linear sequence, with the v
291 // coordinate changing more rapidly.
292 ////////////////////////////////////////////////////////////////////
295  int num_vertices = (int)_vertices.size();
296  verts.reserve(verts.size() + num_vertices);
297  int vi;
298  for (vi = 0; vi < num_vertices; vi++) {
299  const NodePath &space = _vertices[vi].get_space(rel_to);
300  LVecBase4 vertex = _vertices[vi].get_vertex();
301  if (!space.is_empty()) {
302  CPT(TransformState) transform = space.get_transform(rel_to);
303  const LMatrix4 &mat = transform->get_mat();
304  vertex = vertex * mat;
305  }
306  LPoint3 v3(vertex[0] / vertex[3], vertex[1] / vertex[3], vertex[2] / vertex[3]);
307  verts.push_back(v3);
308  }
309 }
310 
311 ////////////////////////////////////////////////////////////////////
312 // Function: NurbsSurfaceEvaluator::recompute_u_knots
313 // Access: Private
314 // Description: Creates a default knot vector.
315 ////////////////////////////////////////////////////////////////////
316 void NurbsSurfaceEvaluator::
317 recompute_u_knots() {
318  _u_knots.clear();
319  int num_knots = get_num_u_knots();
320  _u_knots.reserve(num_knots);
321 
322  PN_stdfloat value = 0.0f;
323 
324  int i = 0;
325  while (i < _u_order) {
326  _u_knots.push_back(value);
327  i++;
328  }
329  while (i < num_knots - _u_order) {
330  value += 1.0f;
331  _u_knots.push_back(value);
332  i++;
333  }
334  value += 1.0f;
335  while (i < num_knots) {
336  _u_knots.push_back(value);
337  i++;
338  }
339 
340  _u_knots_dirty = false;
341 }
342 
343 ////////////////////////////////////////////////////////////////////
344 // Function: NurbsSurfaceEvaluator::recompute_v_knots
345 // Access: Private
346 // Description: Creates a default knot vector.
347 ////////////////////////////////////////////////////////////////////
348 void NurbsSurfaceEvaluator::
349 recompute_v_knots() {
350  _v_knots.clear();
351  int num_knots = get_num_v_knots();
352  _v_knots.reserve(num_knots);
353 
354  PN_stdfloat value = 0.0f;
355 
356  int i = 0;
357  while (i < _v_order) {
358  _v_knots.push_back(value);
359  i++;
360  }
361  while (i < num_knots - _v_order) {
362  value += 1.0f;
363  _v_knots.push_back(value);
364  i++;
365  }
366  value += 1.0f;
367  while (i < num_knots) {
368  _v_knots.push_back(value);
369  i++;
370  }
371 
372  _v_knots_dirty = false;
373 }
374 
375 ////////////////////////////////////////////////////////////////////
376 // Function: NurbsSurfaceEvaluator::recompute_u_basis
377 // Access: Private
378 // Description: Recomputes the basis matrices according to the knot
379 // vector.
380 ////////////////////////////////////////////////////////////////////
381 void NurbsSurfaceEvaluator::
382 recompute_u_basis() {
383  if (_u_knots_dirty) {
384  ((NurbsSurfaceEvaluator *)this)->recompute_u_knots();
385  }
386 
387  _u_basis.clear(_u_order);
388  if (_num_u_vertices > _u_order - 1) {
389  int min_knot = _u_order;
390  int max_knot = _num_u_vertices;
391 
392  for (int i = min_knot; i <= max_knot; i++) {
393  nassertv(i - 1 >= 0 && i < (int)_u_knots.size());
394  if (_u_knots[i - 1] < _u_knots[i]) {
395  // Here's a non-empty segment.
396  _u_basis.append_segment(i - _u_order, &_u_knots[i - _u_order]);
397  }
398  }
399  }
400 
401  _u_basis_dirty = false;
402 }
403 
404 ////////////////////////////////////////////////////////////////////
405 // Function: NurbsSurfaceEvaluator::recompute_v_basis
406 // Access: Private
407 // Description: Recomputes the basis matrices according to the knot
408 // vector.
409 ////////////////////////////////////////////////////////////////////
410 void NurbsSurfaceEvaluator::
411 recompute_v_basis() {
412  if (_v_knots_dirty) {
413  ((NurbsSurfaceEvaluator *)this)->recompute_v_knots();
414  }
415 
416  _v_basis.clear(_v_order);
417  if (_num_v_vertices > _v_order - 1) {
418  int min_knot = _v_order;
419  int max_knot = _num_v_vertices;
420 
421  for (int i = min_knot; i <= max_knot; i++) {
422  nassertv(i - 1 >= 0 && i < (int)_v_knots.size());
423  if (_v_knots[i - 1] < _v_knots[i]) {
424  // Here's a non-empty segment.
425  _v_basis.append_segment(i - _v_order, &_v_knots[i - _v_order]);
426  }
427  }
428  }
429 
430  _v_basis_dirty = false;
431 }
void get_vertices(Vert4Array &verts, const NodePath &rel_to) const
Fills the indicated vector with the set of vertices in the surface, transformed to the given space...
void set_u_knot(int i, PN_stdfloat knot)
Sets the value of the nth knot.
void set_v_knot(int i, PN_stdfloat knot)
Sets the value of the nth knot.
void normalize_v_knots()
Normalizes the knot sequence so that the parametric range of the surface in the U direction is 0 ...
int get_num_v_knots() const
Returns the number of knot values in the surface in the V direction.
PN_stdfloat get_u_knot(int i) const
Returns the value of the nth knot.
void append_segment(int vertex_index, const PN_stdfloat knots[])
Computes a NURBS basis for one segment of the curve and appends it to the set of basis matrices...
void normalize_u_knots()
Normalizes the knot sequence so that the parametric range of the surface in the U direction is 0 ...
const TransformState * get_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete transform object set on this node.
Definition: nodePath.cxx:925
This is a three-component point in space (as opposed to a three-component vector, which represents a ...
Definition: lpoint3.h:99
void set_extended_vertices(int ui, int vi, int d, const PN_stdfloat values[], int num_values)
Simultaneously sets several extended values in the slots d through (d + num_values - 1) from the num_...
This class is an abstraction for evaluating NURBS surfaces.
This represents a single control vertex in a NurbsEvaluator.
Definition: nurbsVertex.h:36
NodePath get_vertex_space(int ui, int vi, const NodePath &rel_to) const
Returns the coordinate space of the nth control vertex of the surface, expressed as a NodePath...
This is a 4-by-4 transform matrix.
Definition: lmatrix.h:451
void clear(int order)
Removes all the segments from the curve.
The result of a NurbsSurfaceEvaluator.
void reset(int num_u_vertices, int num_v_vertices)
Resets all the vertices and knots to their default values, and sets the surface up with the indicated...
This is the base class for all three-component vectors and points.
Definition: lvecBase4.h:111
bool is_empty() const
Returns true if the NodePath contains no nodes.
Definition: nodePath.I:236
int get_num_u_knots() const
Returns the number of knot values in the surface in the U direction.
void set_extended_vertex(int d, PN_stdfloat value)
Sets an n-dimensional vertex value.
Definition: nurbsVertex.cxx:41
PN_stdfloat get_v_knot(int i) const
Returns the value of the nth knot.
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:165