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  */
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 }
void set_knot(int i, PN_stdfloat knot)
Sets the value of the nth knot.
get_num_knots
Returns the number of knot values in the curve.
void reset(int num_vertices)
Resets all the vertices and knots to their default values, and sets the curve up with the indicated n...
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.
This class is an abstraction for evaluating NURBS curves.
get_vertex
Returns the nth control vertex of the curve, relative to its indicated coordinate space.
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.
This represents a single control vertex in a NurbsEvaluator.
Definition: nurbsVertex.h:32
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void clear(int order)
Removes all the segments from the curve.
get_knot
Returns the value of the nth knot.
void normalize_knots()
Normalizes the knot sequence so that the parametric range of the curve is 0
get_num_vertices
Returns the number of control vertices in the curve.
The result of a NurbsCurveEvaluator.
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:161
PT(NurbsCurveResult) NurbsCurveEvaluator
Returns a NurbsCurveResult object that represents the result of applying the knots to all of the curr...
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_...