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