Panda3D

Loading...
Searching...
No Matches
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 */
19NurbsSurfaceEvaluator::
20NurbsSurfaceEvaluator() {
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 */
32NurbsSurfaceEvaluator::
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 */
107PN_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 */
155PN_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 */
191PT(NurbsSurfaceResult) NurbsSurfaceEvaluator::
192evaluate(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::
215output(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::
229get_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::
255get_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::
276recompute_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::
306recompute_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::
336recompute_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::
362recompute_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:794
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
nurbsSurfaceEvaluator.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TransformState
STTransform::operator CPT TransformState() const
This is used internally to convert an STTransform into a TransformState pointer.
Definition stTransform.I:98