Panda3D
eggNurbsSurface.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 eggNurbsSurface.cxx
10  * @author drose
11  * @date 2000-02-15
12  */
13 
14 #include "eggNurbsSurface.h"
15 
16 #include "indent.h"
17 
18 TypeHandle EggNurbsSurface::_type_handle;
19 
20 /**
21  * Makes a copy of this object.
22  */
24 make_copy() const {
25  return new EggNurbsSurface(*this);
26 }
27 
28 /**
29  * Prepares a new surface definition with the indicated order and number of
30  * knots in each dimension. This also implies a particular number of vertices
31  * in each dimension as well (the number of knots minus the order), but it is
32  * up to the user to add the correct number of vertices to the surface by
33  * repeatedly calling push_back().
34  */
36 setup(int u_order, int v_order,
37  int num_u_knots, int num_v_knots) {
38  _u_order = u_order;
39  _v_order = v_order;
40  _u_knots.clear();
41  _v_knots.clear();
42 
43  int i;
44  _u_knots.reserve(num_u_knots);
45  for (i = 0; i < num_u_knots; i++) {
46  _u_knots.push_back((double)i);
47  }
48  _v_knots.reserve(num_v_knots);
49  for (i = 0; i < num_v_knots; i++) {
50  _v_knots.push_back((double)i);
51  }
52 }
53 
54 /**
55  * Directly changes the number of knots in the U direction. This will either
56  * add zero-valued knots onto the end, or truncate knot values from the end,
57  * depending on whether the list is being increased or decreased. If
58  * possible, it is preferable to use the setup() method instead of directly
59  * setting the number of knots, as this may result in an invalid surface.
60  */
62 set_num_u_knots(int num) {
63  if ((int)_u_knots.size() >= num) {
64  // Truncate knot values at the end.
65  _u_knots.erase(_u_knots.begin() + num, _u_knots.end());
66  } else {
67  // Append knot values to the end.
68  _u_knots.reserve(num);
69  for (int i = _u_knots.size(); i < num; i++) {
70  _u_knots.push_back(0.0);
71  }
72  }
73 }
74 
75 /**
76  * Directly changes the number of knots in the V direction. This will either
77  * add zero-valued knots onto the end, or truncate knot values from the end,
78  * depending on whether the list is being increased or decreased. If
79  * possible, it is preferable to use the setup() method instead of directly
80  * setting the number of knots, as this may result in an invalid surface.
81  */
83 set_num_v_knots(int num) {
84  if ((int)_v_knots.size() >= num) {
85  // Truncate knot values at the end.
86  _v_knots.erase(_v_knots.begin() + num, _v_knots.end());
87  } else {
88  // Append knot values to the end.
89  _v_knots.reserve(num);
90  for (int i = _v_knots.size(); i < num; i++) {
91  _v_knots.push_back(0.0);
92  }
93  }
94 }
95 
96 /**
97  * Returns true if the NURBS parameters are all internally consistent (e.g.
98  * it has the right number of vertices to match its number of knots and order
99  * in each dimension), or false otherwise.
100  */
102 is_valid() const {
103  if (_u_order < 1 || _u_order > 4 || _v_order < 1 || _v_order > 4) {
104  // Invalid order.
105  return false;
106  }
107 
108  if (get_num_cvs() != (int)size()) {
109  // Wrong number of CV's.
110  return false;
111  }
112 
113  // Do all the knot values monotonically increase?
114  int i;
115  for (i = 1; i < get_num_u_knots(); i++) {
116  if (get_u_knot(i) < get_u_knot(i - 1)) {
117  return false;
118  }
119  }
120  for (i = 1; i < get_num_v_knots(); i++) {
121  if (get_v_knot(i) < get_v_knot(i - 1)) {
122  return false;
123  }
124  }
125 
126  // Everything's looking good!
127  return true;
128 }
129 
130 /**
131  * Returns true if the surface appears to be closed in the U direction. Since
132  * the Egg syntax does not provide a means for explicit indication of closure,
133  * this has to be guessed at by examining the surface itself.
134  */
136 is_closed_u() const {
137  // Technically, the surface is closed if the CV's at the end are repeated
138  // from the beginning. We'll do a cheesy test for expediency's sake: the
139  // surface is closed if the first n knots are not repeated. I think this
140  // will catch all the normal surfaces we're likely to see.
141 
142  int i;
143  for (i = 1; i < get_u_order(); i++) {
144  if (get_u_knot(i) != get_u_knot(i-1)) {
145  return true;
146  }
147  }
148  return false;
149 }
150 
151 /**
152  * Returns true if the surface appears to be closed in the V direction. Since
153  * the Egg syntax does not provide a means for explicit indication of closure,
154  * this has to be guessed at by examining the surface itself.
155  */
157 is_closed_v() const {
158  int i;
159  for (i = 1; i < get_v_order(); i++) {
160  if (get_v_knot(i) != get_v_knot(i-1)) {
161  return true;
162  }
163  }
164  return false;
165 }
166 
167 /**
168  * Writes the nurbsSurface to the indicated output stream in Egg format.
169  */
171 write(std::ostream &out, int indent_level) const {
172  write_header(out, indent_level, "<NurbsSurface>");
173 
174  Trims::const_iterator ti;
175  for (ti = _trims.begin(); ti != _trims.end(); ++ti) {
176  indent(out, indent_level + 2) << "<Trim> {\n";
177  Loops::const_iterator li;
178  for (li = (*ti).begin(); li != (*ti).end(); ++li) {
179  indent(out, indent_level + 4) << "<Loop> {\n";
180  Curves::const_iterator ci;
181  for (ci = (*li).begin(); ci != (*li).end(); ++ci) {
182  (*ci)->write(out, indent_level + 6);
183  }
184  indent(out, indent_level + 4) << "}\n";
185  }
186  indent(out, indent_level + 2) << "}\n";
187  }
188 
189  if (get_u_subdiv() != 0) {
190  indent(out, indent_level + 2)
191  << "<Scalar> U-subdiv { " << get_u_subdiv() << " }\n";
192  }
193  if (get_v_subdiv() != 0) {
194  indent(out, indent_level + 2)
195  << "<Scalar> V-subdiv { " << get_v_subdiv() << " }\n";
196  }
197  indent(out, indent_level + 2)
198  << "<Order> { " << get_u_order() << " " << get_v_order() << " }\n";
199  indent(out, indent_level + 2)
200  << "<U-Knots> {\n";
201  write_long_list(out, indent_level+4, _u_knots.begin(), _u_knots.end(),
202  "", "", 72);
203  indent(out, indent_level + 2)
204  << "}\n";
205  indent(out, indent_level + 2)
206  << "<V-Knots> {\n";
207  write_long_list(out, indent_level+4, _v_knots.begin(), _v_knots.end(),
208  "", "", 72);
209  indent(out, indent_level + 2)
210  << "}\n";
211 
212  write_body(out, indent_level+2);
213 
214  Curves::const_iterator ci;
215  for (ci = _curves_on_surface.begin(); ci != _curves_on_surface.end(); ++ci) {
216  (*ci)->write(out, indent_level + 2);
217  }
218 
219  indent(out, indent_level) << "}\n";
220 }
221 
222 /**
223  * The recursive implementation of apply_texmats().
224  */
225 void EggNurbsSurface::
226 r_apply_texmats(EggTextureCollection &textures) {
227  // A NURBS cannot safely apply texture matrices, so we leave it alone.
228 }
get_num_v_knots
Returns the number of knots in the V direction.
void write_header(std::ostream &out, int indent_level, const char *egg_keyword) const
Writes the first line of the egg object, e.g.
get_num_u_knots
Returns the number of knots in the U direction.
void set_num_v_knots(int num)
Directly changes the number of knots in the V direction.
get_v_knot
Returns the nth knot value defined in the V direction.
int get_v_subdiv() const
Returns the requested number of subdivisions in the U direction, or 0 if no particular subdivisions h...
Definition: eggSurface.I:82
void setup(int u_order, int v_order, int num_u_knots, int num_v_knots)
Prepares a new surface definition with the indicated order and number of knots in each dimension.
This is a collection of textures by TRef name.
bool is_closed_v() const
Returns true if the surface appears to be closed in the V direction.
bool is_valid() const
Returns true if the NURBS parameters are all internally consistent (e.g.
int get_u_order() const
Returns the order of the surface in the U direction.
void set_num_u_knots(int num)
Directly changes the number of knots in the U direction.
int get_num_cvs() const
Returns the total number of control vertices that *should* be defined for the surface.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
void write_long_list(std::ostream &out, int indent_level, InputIterator ifirst, InputIterator ilast, std::string first_prefix="", std::string later_prefix="", int max_col=72)
Writes a list of things to the indicated output stream, with a space separating each item.
Definition: indent.I:22
int get_v_order() const
Returns the order of the surface in the V direction.
bool is_closed_u() const
Returns true if the surface appears to be closed in the U direction.
get_u_knot
Returns the nth knot value defined in the U direction.
virtual void write(std::ostream &out, int indent_level) const override
Writes the nurbsSurface to the indicated output stream in Egg format.
A parametric NURBS surface.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
virtual EggNurbsSurface * make_copy() const override
Makes a copy of this object.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int get_u_subdiv() const
Returns the requested number of subdivisions in the U direction, or 0 if no particular subdivisions h...
Definition: eggSurface.I:62