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