Panda3D
 All Classes Functions Variables Enumerations
qtessInputEntry.cxx
1 // Filename: qtessInputEntry.cxx
2 // Created by: drose (13Oct03)
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 "qtessInputEntry.h"
16 #include "qtessSurface.h"
17 #include "qtessGlobals.h"
18 #include "config_egg_qtess.h"
19 #include "indent.h"
20 #include "string_utils.h"
21 
22 #include <ctype.h>
23 #include <algorithm>
24 
25 ////////////////////////////////////////////////////////////////////
26 // Function: QtessInputEntry::Constructor
27 // Access: Public
28 // Description:
29 ////////////////////////////////////////////////////////////////////
30 QtessInputEntry::
31 QtessInputEntry(const string &name) {
32  _type = T_undefined;
33  _num_patches = 0.0;
34  _auto_place = QtessGlobals::_auto_place;
35  _auto_distribute = QtessGlobals::_auto_distribute;
36  _curvature_ratio = QtessGlobals::_curvature_ratio;
37  if (!name.empty()) {
38  add_node_name(name);
39  }
40 }
41 
42 ////////////////////////////////////////////////////////////////////
43 // Function: QtessInputEntry::Copy Assignment Operator
44 // Access: Public
45 // Description:
46 ////////////////////////////////////////////////////////////////////
47 void QtessInputEntry::
48 operator = (const QtessInputEntry &copy) {
49  _node_names = copy._node_names;
50  _type = copy._type;
51  _num_tris = copy._num_tris;
52  _num_u = copy._num_u;
53  _num_v = copy._num_v;
54  _per_isoparam = copy._per_isoparam;
55  _iso_u = copy._iso_u;
56  _iso_v = copy._iso_v;
57  _surfaces = copy._surfaces;
58  _num_patches = copy._num_patches;
59  _auto_place = copy._auto_place;
60  _auto_distribute = copy._auto_distribute;
61  _curvature_ratio = copy._curvature_ratio;
62  _importance = copy._importance;
63  _constrain_u = copy._constrain_u;
64  _constrain_v = copy._constrain_v;
65 }
66 
67 ////////////////////////////////////////////////////////////////////
68 // Class : DoublesAlmostEqual
69 // Description : An STL function object to determine if two doubles
70 // are very nearly equal. Used in set_uv(), below.
71 ////////////////////////////////////////////////////////////////////
73 public:
74  int operator ()(double a, double b) const {
75  return fabs(a - b) < 0.00001;
76  }
77 };
78 
79 ////////////////////////////////////////////////////////////////////
80 // Class : DoubleAlmostMatches
81 // Description : An STL function object to determine if a double
82 // is vert nearly equal the supplied value . Used in
83 // set_uv(), below.
84 ////////////////////////////////////////////////////////////////////
86 public:
87  DoubleAlmostMatches(double v) : _v(v) {}
88  int operator ()(double a) const {
89  return fabs(a - _v) < 0.00001;
90  }
91  double _v;
92 };
93 
94 
95 ////////////////////////////////////////////////////////////////////
96 // Function: QtessInputEntry::set_uv
97 // Access: Public
98 // Description: Sets specific tesselation. The tesselation will be u
99 // by v quads, with the addition of any isoparams
100 // described in the list of params.
101 ////////////////////////////////////////////////////////////////////
102 void QtessInputEntry::
103 set_uv(int u, int v, const string params[], int num_params) {
104  _num_u = u;
105  _num_v = v;
106 
107  // First, fill up the arrays with the defaults.
108  int i;
109  for (i = 0; i <= _num_u; i++) {
110  _iso_u.push_back(i);
111  }
112  for (i = 0; i <= _num_v; i++) {
113  _iso_v.push_back(i);
114  }
115 
116  // Then get out all the additional entries.
117  for (i = 0; i < num_params; i++) {
118  const string &param = params[i];
119 
120  if (param[0] == '!' && param.size() > 2) {
121  double value;
122  if (!string_to_double(param.substr(2), value)) {
123  qtess_cat.warning()
124  << "Ignoring invalid parameter: " << param << "\n";
125  } else {
126  switch (tolower(param[1])) {
127  case 'u':
128  _auto_place = false;
129  _iso_u.erase(remove_if(_iso_u.begin(), _iso_u.end(),
130  DoubleAlmostMatches(value)),
131  _iso_u.end());
132  break;
133 
134  case 'v':
135  _auto_place = false;
136  _iso_v.erase(remove_if(_iso_v.begin(), _iso_v.end(),
137  DoubleAlmostMatches(value)),
138  _iso_v.end());
139  break;
140 
141  default:
142  qtess_cat.warning()
143  << "Ignoring invalid parameter: " << params[i] << "\n";
144  }
145  }
146  } else {
147  double value;
148  if (!string_to_double(param.substr(1), value)) {
149  qtess_cat.warning()
150  << "Ignoring invalid parameter: " << param << "\n";
151  } else {
152  switch (tolower(param[0])) {
153  case 'u':
154  _auto_place = false;
155  _iso_u.push_back(value);
156  break;
157 
158  case 'v':
159  _auto_place = false;
160  _iso_v.push_back(value);
161  break;
162 
163  default:
164  qtess_cat.warning()
165  << "Ignoring invalid parameter: " << params[i] << "\n";
166  }
167  }
168  }
169  }
170 
171  // Now sort them into ascending order and remove duplicates.
172  sort(_iso_u.begin(), _iso_u.end());
173  sort(_iso_v.begin(), _iso_v.end());
174  _iso_u.erase(unique(_iso_u.begin(), _iso_u.end(), DoublesAlmostEqual()), _iso_u.end());
175  _iso_v.erase(unique(_iso_v.begin(), _iso_v.end(), DoublesAlmostEqual()), _iso_v.end());
176 
177  _type = T_uv;
178 }
179 
180 
181 ////////////////////////////////////////////////////////////////////
182 // Function: QtessInputEntry::add_extra_u_isoparam
183 // Access: Public
184 // Description: May be called a number of times before set_uv() to add
185 // specific additional isoparams to the tesselation.
186 ////////////////////////////////////////////////////////////////////
189  _iso_u.push_back(u);
190 }
191 
192 ////////////////////////////////////////////////////////////////////
193 // Function: QtessInputEntry::add_extra_v_isoparam
194 // Access: Public
195 // Description: May be called a number of times before set_uv() to add
196 // specific additional isoparams to the tesselation.
197 ////////////////////////////////////////////////////////////////////
200  _iso_v.push_back(v);
201 }
202 
203 ////////////////////////////////////////////////////////////////////
204 // Function: QtessInputEntry::match
205 // Access: Public
206 // Description: Tests the surface to see if it matches any of the
207 // regular expressions that define this node entry. If
208 // so, adds it to the set of matched surfaces and
209 // returns the type of the matching entry. If no match
210 // is found, returns T_undefined.
211 ////////////////////////////////////////////////////////////////////
212 QtessInputEntry::Type QtessInputEntry::
213 match(QtessSurface *surface) {
214  const string &name = surface->get_name();
215 
216  NodeNames::const_iterator nni;
217  for (nni = _node_names.begin();
218  nni != _node_names.end();
219  ++nni) {
220  const GlobPattern &pattern = (*nni);
221  if (pattern.matches(name)) {
222  // We have a winner!
223  switch (_type) {
224  case T_importance:
225  // A type of "Importance" is a special case. This entry
226  // doesn't specify any kind of tesselation on the surface, and
227  // in fact doesn't preclude the surface from matching anything
228  // later. It just specifies the relative importance of the
229  // surface to all the other surfaces.
230  if (qtess_cat.is_debug()) {
231  qtess_cat.debug()
232  << "Assigning importance of " << _importance*100.0
233  << "% to " << name << "\n";
234  }
235  surface->set_importance(_importance);
236  return T_undefined;
237 
238  case T_match_uu:
239  case T_match_uv:
240  // Similarly for type "matchUU". This indicates that all the
241  // surfaces that match this one must all share the
242  // U-tesselation with whichever surface first matched against
243  // the first node name.
244  if (nni == _node_names.begin() && _constrain_u==NULL) {
245  // This is the lucky surface that dominates!
246  _constrain_u = surface;
247  } else {
248  if (_type == T_match_uu) {
249  surface->set_match_u(&_constrain_u, true);
250  } else {
251  surface->set_match_v(&_constrain_u, false);
252  }
253  }
254  return T_undefined;
255 
256  case T_match_vv:
257  case T_match_vu:
258  // Ditto for "matchVV".
259  if (nni == _node_names.begin() && _constrain_v==NULL) {
260  // This is the lucky surface that dominates!
261  _constrain_v = surface;
262  } else {
263  if (_type == T_match_vv) {
264  surface->set_match_v(&_constrain_v, true);
265  } else {
266  surface->set_match_u(&_constrain_v, false);
267  }
268  }
269  return T_undefined;
270 
271  case T_min_u:
272  // And for min U and V.
273  if (qtess_cat.is_debug()) {
274  qtess_cat.debug()
275  << "Assigning minimum of " << _num_u << " in U to "
276  << name << "\n";
277  }
278  surface->set_min_u(_num_u);
279  return T_undefined;
280 
281  case T_min_v:
282  if (qtess_cat.is_debug()) {
283  qtess_cat.debug()
284  << "Assigning minimum of " << _num_v << " in V to "
285  << name << "\n";
286  }
287  surface->set_min_v(_num_v);
288  return T_undefined;
289 
290  default:
291  _surfaces.push_back(surface);
292  if (_auto_distribute) {
293  _num_patches += surface->get_score(_curvature_ratio);
294  } else {
295  _num_patches += surface->count_patches();
296  }
297  return _type;
298  }
299  }
300  }
301 
302  return T_undefined;
303 }
304 
305 ////////////////////////////////////////////////////////////////////
306 // Function: QtessInputEntry::count_tris
307 // Access: Public
308 // Description: Determines the tesselation u,v amounts of each
309 // attached surface, and stores this information in the
310 // surface pointer. Returns the total number of tris
311 // that will be produced.
312 ////////////////////////////////////////////////////////////////////
314 count_tris(double tri_factor, int attempts) {
315  int total_tris = 0;
316  bool aim_for_tris = false;
317 
318  if (_type == T_num_tris && _num_patches > 0.0) {
319  // If we wanted to aim for a particular number of triangles for
320  // the group, choose a per-isoparam setting that will approximately
321  // achieve this.
322  if (_auto_distribute) {
323  set_per_score(sqrt(0.5 * (double)_num_tris / _num_patches / tri_factor));
324  } else {
325  set_per_isoparam(sqrt(0.5 * (double)_num_tris / _num_patches / tri_factor));
326  }
327  aim_for_tris = true;
328  }
329 
330  Surfaces::iterator si;
331  for (si = _surfaces.begin(); si != _surfaces.end(); ++si) {
332  QtessSurface *surface = (*si);
333 
334  switch (_type) {
335  case T_undefined:
336  case T_omit:
337  surface->omit();
338  break;
339 
340  case T_uv:
341  if (!_iso_u.empty() && !_iso_v.empty() && !_auto_place) {
342  surface->tesselate_specific(_iso_u, _iso_v);
343  } else {
344  surface->tesselate_uv(_num_u, _num_v, _auto_place, _curvature_ratio);
345  }
346  break;
347 
348  case T_per_isoparam:
349  surface->tesselate_per_isoparam(_per_isoparam, _auto_place, _curvature_ratio);
350  break;
351 
352  case T_per_score:
353  surface->tesselate_per_score(_per_isoparam, _auto_place, _curvature_ratio);
354  break;
355 
356  default:
357  break;
358  }
359 
360  total_tris += surface->count_tris();
361  }
362 
363  if (aim_for_tris && attempts < 10 &&
364  (double)total_tris / (double)_num_tris > 1.1) {
365  // We'd like to get within 10% of the requested number of
366  // triangles, if possible. Keep trying until we do, or until we
367  // just need to give up.
368  set_num_tris(_num_tris);
369  return count_tris(tri_factor * total_tris / _num_tris, attempts + 1);
370  }
371 
372  return total_tris;
373 }
374 
375 
376 ////////////////////////////////////////////////////////////////////
377 // Function: QtessInputEntry::output_extra
378 // Access: Public, Static
379 // Description: This function is used to identify the extra isoparams
380 // in the list added by user control.
381 ////////////////////////////////////////////////////////////////////
383 output_extra(ostream &out, const pvector<double> &iso, char axis) {
385  int expect = 0;
386  for (di = iso.begin(); di != iso.end(); ++di) {
387  while ((*di) > (double)expect) {
388  // Didn't find one we were expecting. Omit it.
389  out << " !" << axis << expect;
390  }
391  if ((*di)==(double)expect) {
392  // Here's one we were expecting; ignore it.
393  expect++;
394  } else {
395  // Here's a new one. Write it.
396  out << " " << axis << *di;
397  }
398  }
399 }
400 
401 ////////////////////////////////////////////////////////////////////
402 // Function: QtessInputEntry::output
403 // Access: Public
404 // Description:
405 ////////////////////////////////////////////////////////////////////
406 void QtessInputEntry::
407 output(ostream &out) const {
408  NodeNames::const_iterator nni;
409  for (nni = _node_names.begin();
410  nni != _node_names.end();
411  ++nni) {
412  out << (*nni) << " ";
413  }
414  out << ": ";
415 
416  bool show_auto = false;
417 
418  switch (_type) {
419  case T_undefined:
420  break;
421 
422  case T_omit:
423  out << "omit";
424  break;
425 
426  case T_num_tris:
427  out << _num_tris;
428  show_auto = true;
429  break;
430 
431  case T_uv:
432  out << _num_u << " " << _num_v;
433  output_extra(out, _iso_u, 'u');
434  output_extra(out, _iso_v, 'v');
435  show_auto = true;
436  break;
437 
438  case T_per_isoparam:
439  case T_per_score:
440  out << "i" << _per_isoparam;
441  show_auto = true;
442  break;
443 
444  case T_importance:
445  out << _importance * 100.0 << "%";
446  break;
447 
448  case T_match_uu:
449  out << "matchuu";
450  break;
451 
452  case T_match_vv:
453  out << "matchvv";
454  break;
455 
456  case T_match_uv:
457  out << "matchuv";
458  break;
459 
460  case T_match_vu:
461  out << "matchvu";
462  break;
463 
464  case T_min_u:
465  out << "minu " << _num_u;
466  break;
467 
468  case T_min_v:
469  out << "minv " << _num_v;
470  break;
471 
472  default:
473  out << "Invalid!";
474  }
475 
476  if (show_auto) {
477  out << " " << (_auto_place?"":"!") << "ap"
478  << " " << (_auto_distribute?"":"!") << "ad";
479  if (_auto_place || _auto_distribute) {
480  out << " ar" << _curvature_ratio;
481  }
482  }
483 }
484 
485 ////////////////////////////////////////////////////////////////////
486 // Function: QtessInputEntry::output
487 // Access: Public
488 // Description:
489 ////////////////////////////////////////////////////////////////////
490 void QtessInputEntry::
491 write(ostream &out, int indent_level) const {
492  indent(out, indent_level) << (*this) << "\n";
493 }
double count_patches() const
Returns the number of patches the NURBS contains.
Definition: qtessSurface.I:121
A reference to an EggNurbsSurface in the egg file, and its parameters as set by the user input file a...
Definition: qtessSurface.h:34
void set_importance(double importance2)
Sets the importance of the surface, as a ratio in proportion to the square of its size...
Definition: qtessSurface.I:44
int count_tris(double tri_factor=1.0, int attempts=0)
Determines the tesselation u,v amounts of each attached surface, and stores this information in the s...
void set_match_v(QtessSurface **match_v, bool match_v_to_v)
Indicates the surface to which this surface must match in its V direction.
Definition: qtessSurface.I:84
bool matches(const string &candidate) const
Returns true if the candidate string matches the pattern, false otherwise.
Definition: globPattern.I:157
void set_match_u(QtessSurface **match_u, bool match_u_to_u)
Indicates the surface to which this surface must match in its U direction.
Definition: qtessSurface.I:64
void set_min_v(int min_v)
Specifies the absolute minimum number of segments allowed in the V direction.
Definition: qtessSurface.I:107
Stores one entry in the qtess input file.
void add_extra_u_isoparam(double u)
May be called a number of times before set_uv() to add specific additional isoparams to the tesselati...
double get_score(double ratio)
Computes the curvature/stretch score for the surface, if it has not been already computed, and returns the net surface score.
void set_min_u(int min_u)
Specifies the absolute minimum number of segments allowed in the U direction.
Definition: qtessSurface.I:96
void omit()
Sets up the surface to omit itself from the output.
An STL function object to determine if two doubles are very nearly equal.
void tesselate_specific(const pvector< double > &u_list, const pvector< double > &v_list)
Sets the surface up to tesselate itself at specific isoparams only.
void tesselate_per_isoparam(double pi, bool autoplace, double ratio)
Sets the surface up to tesselate itself to a uniform amount per isoparam.
void tesselate_per_score(double pi, bool autoplace, double ratio)
Sets the surface up to tesselate itself according to its computed curvature score in both dimensions...
An STL function object to determine if a double is vert nearly equal the supplied value ...
Type match(QtessSurface *surface)
Tests the surface to see if it matches any of the regular expressions that define this node entry...
void tesselate_uv(int u, int v, bool autoplace, double ratio)
Sets the surface up to tesselate itself uniformly at u x v, or if autoplace is true, automatically with u x v quads.
static void output_extra(ostream &out, const pvector< double > &iso, char axis)
This function is used to identify the extra isoparams in the list added by user control.
This class can be used to test for string matches against standard Unix-shell filename globbing conve...
Definition: globPattern.h:37
void add_extra_v_isoparam(double u)
May be called a number of times before set_uv() to add specific additional isoparams to the tesselati...
int count_tris() const
Returns the number of triangles that will be generated by the current tesselation parameters...
Definition: qtessSurface.I:132