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 */
41 void NurbsSurfaceEvaluator::
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 */
62 NodePath NurbsSurfaceEvaluator::
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 */
78 void NurbsSurfaceEvaluator::
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 */
95 void NurbsSurfaceEvaluator::
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 */
120 void NurbsSurfaceEvaluator::
121 normalize_u_knots() {
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 */
143 void NurbsSurfaceEvaluator::
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 */
168 void NurbsSurfaceEvaluator::
169 normalize_v_knots() {
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 }
NodePath
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:159
NodePath::is_empty
bool is_empty() const
Returns true if the NodePath contains no nodes.
Definition: nodePath.I:188
NodePath::get_transform
const TransformState * get_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete transform object set on this node.
Definition: nodePath.cxx:791
NurbsBasisVector::append_segment
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.
Definition: nurbsBasisVector.cxx:30
NurbsBasisVector::clear
void clear(int order)
Removes all the segments from the curve.
Definition: nurbsBasisVector.cxx:20
NurbsSurfaceEvaluator
This class is an abstraction for evaluating NURBS surfaces.
Definition: nurbsSurfaceEvaluator.h:34
NurbsSurfaceEvaluator::set_extended_vertices
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_...
Definition: nurbsSurfaceEvaluator.cxx:79
NurbsSurfaceEvaluator::reset
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...
Definition: nurbsSurfaceEvaluator.cxx:42
NurbsSurfaceEvaluator::set_u_knot
set_u_knot
Sets the value of the nth knot.
Definition: nurbsSurfaceEvaluator.h:84
NurbsSurfaceEvaluator::get_v_knot
get_v_knot
Returns the value of the nth knot.
Definition: nurbsSurfaceEvaluator.h:72
NurbsSurfaceEvaluator::set_v_knot
set_v_knot
Sets the value of the nth knot.
Definition: nurbsSurfaceEvaluator.h:85
NurbsSurfaceEvaluator::get_num_v_knots
get_num_v_knots
Returns the number of knot values in the surface in the V direction.
Definition: nurbsSurfaceEvaluator.h:72
NurbsSurfaceEvaluator::normalize_u_knots
void normalize_u_knots()
Normalizes the knot sequence so that the parametric range of the surface in the U direction is 0 .
Definition: nurbsSurfaceEvaluator.cxx:121
NurbsSurfaceEvaluator::get_num_u_knots
get_num_u_knots
Returns the number of knot values in the surface in the U direction.
Definition: nurbsSurfaceEvaluator.h:66
NurbsSurfaceEvaluator::get_vertex_space
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.
Definition: nurbsSurfaceEvaluator.cxx:63
NurbsSurfaceEvaluator::normalize_v_knots
void normalize_v_knots()
Normalizes the knot sequence so that the parametric range of the surface in the U direction is 0 .
Definition: nurbsSurfaceEvaluator.cxx:169
NurbsSurfaceEvaluator::get_u_knot
get_u_knot
Returns the value of the nth knot.
Definition: nurbsSurfaceEvaluator.h:66
NurbsSurfaceResult
The result of a NurbsSurfaceEvaluator.
Definition: nurbsSurfaceResult.h:29
NurbsVertex
This represents a single control vertex in a NurbsEvaluator.
Definition: nurbsVertex.h:32
NurbsVertex::set_extended_vertex
void set_extended_vertex(int d, PN_stdfloat value)
Sets an n-dimensional vertex value.
Definition: nurbsVertex.cxx:33
TransformState
Indicates a coordinate-system transform on vertices.
Definition: transformState.h:54
pvector< LPoint3 >
PT
PT(NurbsSurfaceResult) NurbsSurfaceEvaluator
Returns a NurbsSurfaceResult object that represents the result of applying the knots to all of the cu...
Definition: nurbsSurfaceEvaluator.cxx:191
nurbsSurfaceEvaluator.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.