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
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 */
42reset(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 */
63get_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 */
79set_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 */
96set_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::
108get_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 */
144set_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::
156get_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 */
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 */
214void 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 */
228void 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 */
254void 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 */
275void 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 */
305void 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 */
335void 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 */
361void 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 is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition nodePath.h:159
bool is_empty() const
Returns true if the NodePath contains no nodes.
Definition nodePath.I:188
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
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 clear(int order)
Removes all the segments from the curve.
This class is an abstraction for evaluating NURBS surfaces.
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_...
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...
set_u_knot
Sets the value of the nth knot.
get_v_knot
Returns the value of the nth knot.
set_v_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 normalize_u_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.
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.
void normalize_v_knots()
Normalizes the knot sequence so that the parametric range of the surface in the U direction is 0 .
get_u_knot
Returns the value of the nth knot.
The result of a NurbsSurfaceEvaluator.
This represents a single control vertex in a NurbsEvaluator.
Definition nurbsVertex.h:32
void set_extended_vertex(int d, PN_stdfloat value)
Sets an n-dimensional vertex value.
Indicates a coordinate-system transform on vertices.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.