Panda3D
nurbsCurveEvaluator.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 nurbsCurveEvaluator.cxx
10  * @author drose
11  * @date 2002-12-03
12  */
13 
14 #include "nurbsCurveEvaluator.h"
15 
16 /**
17  *
18  */
19 NurbsCurveEvaluator::
20 NurbsCurveEvaluator() {
21  _order = 4;
22  _knots_dirty = true;
23  _basis_dirty = true;
24 }
25 
26 /**
27  *
28  */
29 NurbsCurveEvaluator::
30 ~NurbsCurveEvaluator() {
31 }
32 
33 /**
34  * Resets all the vertices and knots to their default values, and sets the
35  * curve up with the indicated number of vertices. You must then call
36  * set_vertex() repeatedly to fill in all of the vertex values appropriately.
37  */
39 reset(int num_vertices) {
40  _vertices.clear();
41  _vertices.reserve(num_vertices);
42 
43  for (int i = 0; i < num_vertices; i++) {
44  _vertices.push_back(NurbsVertex());
45  }
46  _knots_dirty = true;
47  _basis_dirty = true;
48 }
49 
50 /**
51  * Returns the coordinate space of the nth control vertex of the curve,
52  * expressed as a NodePath.
53  */
55 get_vertex_space(int i, const NodePath &rel_to) const {
56 #ifndef NDEBUG
57  static NodePath empty_node_path;
58  nassertr(i >= 0 && i < (int)_vertices.size(), empty_node_path);
59 #endif
60  return _vertices[i].get_space(rel_to);
61 }
62 
63 /**
64  * Simultaneously sets several extended values in the slots d through (d +
65  * num_values - 1) from the num_values elements of the indicated array. This
66  * is equivalent to calling set_extended_vertex() num_values times. See
67  * set_extended_vertex().
68  */
70 set_extended_vertices(int i, int d, const PN_stdfloat values[], int num_values) {
71  nassertv(i >= 0 && i < (int)_vertices.size());
72 
73  NurbsVertex &vertex = _vertices[i];
74  for (int n = 0; n < num_values; n++) {
75  vertex.set_extended_vertex(d + n, values[n]);
76  }
77 }
78 
79 /**
80  * Sets the value of the nth knot. Each knot value should be greater than or
81  * equal to the preceding value. If no knot values are set, a default knot
82  * vector is supplied.
83  */
85 set_knot(int i, PN_stdfloat knot) {
86  if (_knots_dirty) {
87  recompute_knots();
88  }
89  nassertv(i >= 0 && i < (int)_knots.size());
90  _knots[i] = knot;
91 }
92 
93 /**
94  * Returns the value of the nth knot.
95  */
96 PN_stdfloat NurbsCurveEvaluator::
97 get_knot(int i) const {
98  if (_knots_dirty) {
99  ((NurbsCurveEvaluator *)this)->recompute_knots();
100  }
101  nassertr(i >= 0 && i < (int)_knots.size(), 0.0f);
102  return _knots[i];
103 }
104 
105 /**
106  * Normalizes the knot sequence so that the parametric range of the curve is 0
107  * .. 1.
108  */
110 normalize_knots() {
111  if (_knots_dirty) {
112  recompute_knots();
113  }
114 
115  if (get_num_vertices() > _order - 1) {
116  double min_value = _knots[_order - 1];
117  double max_value = _knots[get_num_vertices()];
118  double range = (max_value - min_value);
119 
120  for (Knots::iterator ki = _knots.begin(); ki != _knots.end(); ++ki) {
121  (*ki) = ((*ki) - min_value) / range;
122  }
123  _basis_dirty = true;
124  }
125 }
126 
127 /**
128  * Returns a NurbsCurveResult object that represents the result of applying
129  * the knots to all of the current values of the vertices, transformed into
130  * the indicated coordinate space.
131  */
132 PT(NurbsCurveResult) NurbsCurveEvaluator::
133 evaluate(const NodePath &rel_to) const {
134  if (_basis_dirty) {
135  ((NurbsCurveEvaluator *)this)->recompute_basis();
136  }
137 
138  // First, transform the vertices as appropriate.
139  Vert4Array vecs;
140  get_vertices(vecs, rel_to);
141 
142  // And apply those transformed vertices to the basis matrices to derive the
143  // result.
144  return new NurbsCurveResult(_basis, &vecs[0], &_vertices[0],
145  (int)_vertices.size());
146 }
147 
148 /**
149  * Returns a NurbsCurveResult object that represents the result of applying
150  * the knots to all of the current values of the vertices, transformed into
151  * the indicated coordinate space, and then further transformed by the
152  * indicated matrix.
153  */
154 PT(NurbsCurveResult) NurbsCurveEvaluator::
155 evaluate(const NodePath &rel_to, const LMatrix4 &mat) const {
156  if (_basis_dirty) {
157  ((NurbsCurveEvaluator *)this)->recompute_basis();
158  }
159 
160  // First, transform the vertices as appropriate.
161  Vert4Array vecs;
162  get_vertices(vecs, rel_to);
163 
164  // And then apply the indicated matrix.
165  Vert4Array::iterator vi;
166  for (vi = vecs.begin(); vi != vecs.end(); ++vi) {
167  (*vi) = (*vi) * mat;
168  }
169 
170  // And apply those transformed vertices to the basis matrices to derive the
171  // result.
172  return new NurbsCurveResult(_basis, &vecs[0], &_vertices[0],
173  (int)_vertices.size());
174 }
175 
176 /**
177  *
178  */
179 void NurbsCurveEvaluator::
180 output(std::ostream &out) const {
181  out << "NurbsCurve, " << get_num_knots() << " knots.";
182 }
183 
184 
185 /**
186  * Fills the indicated vector with the set of vertices in the curve,
187  * transformed to the given space. This flavor returns the vertices in
188  * 4-dimensional homogenous space.
189  */
190 void NurbsCurveEvaluator::
191 get_vertices(NurbsCurveEvaluator::Vert4Array &verts, const NodePath &rel_to) const {
192  int num_vertices = (int)_vertices.size();
193  verts.reserve(verts.size() + num_vertices);
194  int vi;
195  for (vi = 0; vi < num_vertices; vi++) {
196  verts.push_back(get_vertex(vi, rel_to));
197  }
198 }
199 
200 /**
201  * Fills the indicated vector with the set of vertices in the curve,
202  * transformed to the given space. This flavor returns the vertices in
203  * 3-dimensional space.
204  */
205 void NurbsCurveEvaluator::
206 get_vertices(NurbsCurveEvaluator::Vert3Array &verts, const NodePath &rel_to) const {
207  int num_vertices = (int)_vertices.size();
208  verts.reserve(verts.size() + num_vertices);
209  int vi;
210  for (vi = 0; vi < num_vertices; vi++) {
211  LVecBase4 vertex = get_vertex(vi, rel_to);
212  // Avoid division by zero
213  if (vertex[3] == 0.0) {
214  verts.push_back(LPoint3(vertex[0], vertex[1], vertex[2]));
215  } else {
216  LPoint3 v3(vertex[0] / vertex[3], vertex[1] / vertex[3], vertex[2] / vertex[3]);
217  verts.push_back(v3);
218  }
219  }
220 }
221 
222 /**
223  * Creates a default knot vector.
224  */
225 void NurbsCurveEvaluator::
226 recompute_knots() {
227  _knots.clear();
228  int num_knots = get_num_knots();
229  _knots.reserve(num_knots);
230 
231  PN_stdfloat value = 0.0f;
232 
233  int i = 0;
234  while (i < _order) {
235  _knots.push_back(value);
236  i++;
237  }
238  while (i < num_knots - _order) {
239  value += 1.0f;
240  _knots.push_back(value);
241  i++;
242  }
243  value += 1.0f;
244  while (i < num_knots) {
245  _knots.push_back(value);
246  i++;
247  }
248 
249  _knots_dirty = false;
250 }
251 
252 /**
253  * Recomputes the basis matrices according to the knot vector.
254  */
255 void NurbsCurveEvaluator::
256 recompute_basis() {
257  if (_knots_dirty) {
258  ((NurbsCurveEvaluator *)this)->recompute_knots();
259  }
260 
261  _basis.clear(_order);
262  if ((int)_vertices.size() > _order - 1) {
263  int min_knot = _order;
264  int max_knot = (int)_vertices.size();
265 
266  for (int i = min_knot; i <= max_knot; i++) {
267  nassertv(i - 1 >= 0 && i < (int)_knots.size());
268  if (_knots[i - 1] < _knots[i]) {
269  // Here's a non-empty segment.
270  _basis.append_segment(i - _order, &_knots[i - _order]);
271  }
272  }
273  }
274 
275  _basis_dirty = false;
276 }
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:159
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 curves.
void reset(int num_vertices)
Resets all the vertices and knots to their default values, and sets the curve up with the indicated n...
get_num_vertices
Returns the number of control vertices in the curve.
void normalize_knots()
Normalizes the knot sequence so that the parametric range of the curve is 0
NodePath get_vertex_space(int i, const NodePath &rel_to) const
Returns the coordinate space of the nth control vertex of the curve, expressed as a NodePath.
get_vertex
Returns the nth control vertex of the curve, relative to its indicated coordinate space.
void set_extended_vertices(int i, 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_...
get_num_knots
Returns the number of knot values in the curve.
get_knot
Returns the value of the nth knot.
void set_knot(int i, PN_stdfloat knot)
Sets the value of the nth knot.
The result of a NurbsCurveEvaluator.
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.
Definition: nurbsVertex.cxx:33
PT(NurbsCurveResult) NurbsCurveEvaluator
Returns a NurbsCurveResult object that represents the result of applying the knots to all of the curr...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.