Panda3D
qtessSurface.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 qtessSurface.cxx
10  * @author drose
11  * @date 2003-10-13
12  */
13 
14 #include "qtessSurface.h"
15 #include "qtessGlobals.h"
16 #include "qtessInputEntry.h"
17 #include "config_egg_qtess.h"
18 #include "eggPolygon.h"
19 #include "eggVertexPool.h"
20 #include "eggVertex.h"
21 #include "eggComment.h"
22 #include "egg_parametrics.h"
23 #include "pset.h"
24 #include "pmap.h"
25 
26 using std::max;
27 using std::string;
28 
29 /**
30  *
31  */
32 QtessSurface::
33 QtessSurface(EggNurbsSurface *egg_surface) :
34  _egg_surface(egg_surface)
35 {
36  _nurbs = make_nurbs_surface(_egg_surface, LMatrix4d::ident_mat());
37  _has_vertex_color = _egg_surface->has_vertex_color();
38 
39  // The first four slots are reserved for vertex color.
40  _next_d = 4;
41 
42  _importance = 1.0;
43  _importance2 = 1.0;
44  _match_u = _match_v = nullptr;
45  _tess_u = _tess_v = 0;
46  _got_scores = false;
47 
48  // If the surface is closed in either dimension, the mininum tesselation in
49  // that dimension is by default 3, so we don't ribbonize the surface.
50  // Otherwise the minimum is 1.
51  _min_u = _min_v = 1;
52  if (egg_surface->is_closed_u()) {
53  _min_u = 3;
54  }
55  if (egg_surface->is_closed_v()) {
56  _min_v = 3;
57  }
58 
59  if (_nurbs == nullptr) {
60  _num_u = _num_v = 0;
61 
62  } else {
63  record_vertex_extras();
64 
65  _nurbs->normalize_u_knots();
66  _nurbs->normalize_v_knots();
67  _nurbs_result = _nurbs->evaluate();
68 
69  _num_u = _nurbs->get_num_u_segments();
70  _num_v = _nurbs->get_num_v_segments();
71 
72  if (QtessGlobals::_respect_egg) {
73  if (egg_surface->get_u_subdiv() != 0) {
74  _num_u = egg_surface->get_u_subdiv();
75  }
76  if (egg_surface->get_v_subdiv() != 0) {
77  _num_v = egg_surface->get_v_subdiv();
78  }
79  }
80  }
81 }
82 
83 /**
84  * Computes the curvature/stretch score for the surface, if it has not been
85  * already computed, and returns the net surface score. This is used both for
86  * automatically distributing isoparams among the surfaces by curvature, as
87  * well as for automatically placing the isoparams within each surface by
88  * curvature.
89  */
90 double QtessSurface::
91 get_score(double ratio) {
92  if (_nurbs == nullptr) {
93  return 0.0;
94  }
95 
96  if (!_got_scores) {
97  _u_placer.get_scores(_nurbs->get_num_u_segments() * 100,
98  _nurbs->get_num_v_segments() * 2,
99  ratio, _nurbs_result, true);
100  _v_placer.get_scores(_nurbs->get_num_v_segments() * 100,
101  _nurbs->get_num_u_segments() * 2,
102  ratio, _nurbs_result, false);
103  _got_scores = true;
104  }
105 
106  return _u_placer.get_total_score() * _v_placer.get_total_score() * _importance2;
107 }
108 
109 /**
110  * Applies the appropriate tesselation to the surface, and replaces its node
111  * in the tree with an EggGroup containing both the new vertex pool and all of
112  * the polygons.
113  */
114 int QtessSurface::
116  apply_match();
117  int tris = 0;
118 
119  PT(EggGroup) group = do_uniform_tesselate(tris);
120  PT(EggNode) new_node = group.p();
121  if (new_node == nullptr) {
122  new_node = new EggComment(_egg_surface->get_name(),
123  "Omitted NURBS surface.");
124  tris = 0;
125  }
126  EggGroupNode *parent = _egg_surface->get_parent();
127  nassertr(parent != nullptr, 0);
128  parent->remove_child(_egg_surface);
129  parent->add_child(new_node);
130 
131  return tris;
132 }
133 
134 /**
135  * Writes a line to the given output file telling qtess how this surface
136  * should be tesselated uniformly. Returns the number of tris.
137  */
138 int QtessSurface::
139 write_qtess_parameter(std::ostream &out) {
140  apply_match();
141 
142  if (_tess_u == 0 || _tess_v == 0) {
143  out << get_name() << " : omit\n";
144 
145  } else if (_iso_u.empty() || _iso_v.empty()) {
146  out << get_name() << " : " << _tess_u << " " << _tess_v << "\n";
147 
148  } else {
149  out << get_name() << " : " << _iso_u.back() << " " << _iso_v.back();
150  QtessInputEntry::output_extra(out, _iso_u, 'u');
151  QtessInputEntry::output_extra(out, _iso_v, 'v');
152  out << "\n";
153  }
154 
155  return count_tris();
156 }
157 
158 
159 /**
160  * Sets up the surface to omit itself from the output.
161  */
162 void QtessSurface::
163 omit() {
164  _tess_u = 0;
165  _tess_v = 0;
166 }
167 
168 /**
169  * Sets the surface up to tesselate itself uniformly at u x v, or if autoplace
170  * is true, automatically with u x v quads.
171  */
172 void QtessSurface::
173 tesselate_uv(int u, int v, bool autoplace, double ratio) {
174  _tess_u = u;
175  _tess_v = v;
176  _iso_u.clear();
177  _iso_v.clear();
178  if (autoplace) {
179  tesselate_auto(_tess_u, _tess_v, ratio);
180  }
181 }
182 
183 /**
184  * Sets the surface up to tesselate itself at specific isoparams only.
185  */
186 void QtessSurface::
188  const pvector<double> &v_list) {
189  _iso_u = u_list;
190  _iso_v = v_list;
191  _tess_u = (int)_iso_u.size() - 1;
192  _tess_v = (int)_iso_v.size() - 1;
193 }
194 
195 /**
196  * Sets the surface up to tesselate itself to a uniform amount per isoparam.
197  */
198 void QtessSurface::
199 tesselate_per_isoparam(double pi, bool autoplace, double ratio) {
200  if (_num_u == 0 || _num_v == 0) {
201  omit();
202 
203  } else {
204  _tess_u = max(_min_u, (int)floor(_num_u * _importance * pi + 0.5));
205  _tess_v = max(_min_v, (int)floor(_num_v * _importance * pi + 0.5));
206  _iso_u.clear();
207  _iso_v.clear();
208  if (autoplace) {
209  tesselate_auto(_tess_u, _tess_v, ratio);
210  }
211  }
212 }
213 
214 
215 /**
216  * Sets the surface up to tesselate itself according to its computed curvature
217  * score in both dimensions.
218  */
219 void QtessSurface::
220 tesselate_per_score(double pi, bool autoplace, double ratio) {
221  if (get_score(ratio) <= 0.0) {
222  omit();
223 
224  } else {
225  _tess_u = max(_min_u, (int)floor(_u_placer.get_total_score() * _importance * pi + 0.5));
226  _tess_v = max(_min_v, (int)floor(_v_placer.get_total_score() * _importance * pi + 0.5));
227  _iso_u.clear();
228  _iso_v.clear();
229  if (autoplace) {
230  tesselate_auto(_tess_u, _tess_v, ratio);
231  }
232  }
233 }
234 
235 /**
236  * Sets the surface up to tesselate itself by automatically determining the
237  * best place to put the indicated u x v isoparams.
238  */
239 void QtessSurface::
240 tesselate_auto(int u, int v, double ratio) {
241  if (get_score(ratio) <= 0.0) {
242  omit();
243 
244  } else {
245  _u_placer.place(u, _iso_u);
246  _v_placer.place(v, _iso_v);
247  _tess_u = (int)_iso_u.size() - 1;
248  _tess_v = (int)_iso_v.size() - 1;
249  }
250 }
251 
252 /**
253  * Records the joint membership and morph offsets of each control vertex in
254  * the extra-dimensional space of the NURBS, so that we can extract this data
255  * out again later to apply to the polygon vertices.
256  */
257 void QtessSurface::
258 record_vertex_extras() {
259  int num_u_vertices = _egg_surface->get_num_u_cvs();
260  int num_v_vertices = _egg_surface->get_num_v_cvs();
261 
262  for (int ui = 0; ui < num_u_vertices; ui++) {
263  for (int vi = 0; vi < num_v_vertices; vi++) {
264  int i = _egg_surface->get_vertex_index(ui, vi);
265  EggVertex *egg_vertex = _egg_surface->get_vertex(i);
266 
267  // The joint membership.
268  EggVertex::GroupRef::const_iterator gi;
269  for (gi = egg_vertex->gref_begin(); gi != egg_vertex->gref_end(); ++gi) {
270  EggGroup *joint = (*gi);
271  int d = get_joint_membership_index(joint);
272  double membership = joint->get_vertex_membership(egg_vertex);
273  _nurbs->set_extended_vertex(ui, vi, d, membership);
274  }
275 
276  // The xyz morphs.
277  EggMorphVertexList::const_iterator dxi;
278  for (dxi = egg_vertex->_dxyzs.begin();
279  dxi != egg_vertex->_dxyzs.end();
280  ++dxi) {
281  const string &morph_name = (*dxi).get_name();
282  LVector3 delta = LCAST(PN_stdfloat, (*dxi).get_offset());
283  int d = get_dxyz_index(morph_name);
284  _nurbs->set_extended_vertices(ui, vi, d, delta.get_data(), 3);
285  }
286 
287  // The rgba morphs.
288  EggMorphColorList::const_iterator dri;
289  for (dri = egg_vertex->_drgbas.begin();
290  dri != egg_vertex->_drgbas.end();
291  ++dri) {
292  const string &morph_name = (*dri).get_name();
293  const LVector4 &delta = (*dri).get_offset();
294  int d = get_drgba_index(morph_name);
295  _nurbs->set_extended_vertices(ui, vi, d, delta.get_data(), 4);
296  }
297  }
298  }
299 }
300 
301 /**
302  * If the surface was set up to copy its tesselation in either axis from
303  * another surface, makes this copy now.
304  */
305 void QtessSurface::
306 apply_match() {
307  if (_match_u != nullptr) {
308  QtessSurface *m = *_match_u;
309  if (m == nullptr) {
310  qtess_cat.warning()
311  << "No surface to match " << get_name() << " to in U.\n";
312  } else {
313  if (qtess_cat.is_debug()) {
314  qtess_cat.debug()
315  << "Matching " << get_name() << " in U to " << m->get_name()
316  << " in " << (_match_u_to_u?'U':'V') << ".\n";
317  }
318  if (_match_u_to_u) {
319  _tess_u = m->_tess_u;
320  _iso_u = m->_iso_u;
321  } else {
322  _tess_u = m->_tess_v;
323  _iso_u = m->_iso_v;
324  }
325  }
326  }
327 
328  if (_match_v != nullptr) {
329  QtessSurface *m = *_match_v;
330  if (m == nullptr) {
331  qtess_cat.warning()
332  << "No surface to match " << get_name() << " in V.\n";
333  } else {
334  if (qtess_cat.is_debug()) {
335  qtess_cat.debug()
336  << "Matching " << get_name() << " in V to " << m->get_name()
337  << " in " << (_match_v_to_v?'V':'U') << ".\n";
338  }
339  if (_match_v_to_v) {
340  _tess_v = m->_tess_v;
341  _iso_v = m->_iso_v;
342  } else {
343  _tess_v = m->_tess_u;
344  _iso_v = m->_iso_u;
345  }
346  }
347  }
348 }
349 
350 /**
351  * Subdivide the surface uniformly according to the parameters specified by an
352  * earlier call to omit(), teseselate_uv(), or tesselate_per_isoparam().
353  */
354 PT(EggGroup) QtessSurface::
355 do_uniform_tesselate(int &tris) const {
356  tris = 0;
357 
358  if (_tess_u == 0 || _tess_v == 0) {
359  // No tesselation!
360  if (qtess_cat.is_debug()) {
361  qtess_cat.debug()
362  << get_name() << " : omit\n";
363  }
364  return nullptr;
365  }
366 
367  PT(EggGroup) group = new EggGroup(_egg_surface->get_name());
368 
369  // _tess_u and _tess_v are the number of patches to create. Convert that to
370  // the number of vertices.
371 
372  int num_u = _tess_u + 1;
373  int num_v = _tess_v + 1;
374 
375  if (qtess_cat.is_debug()) {
376  qtess_cat.debug() << get_name() << " : " << tris << "\n";
377  }
378 
379  assert(_iso_u.empty() || (int)_iso_u.size() == num_u);
380  assert(_iso_v.empty() || (int)_iso_v.size() == num_v);
381 
382  // Now how many vertices is that total, and how many vertices per strip?
383  int num_verts = num_u * num_v;
384 
385  // Create a vertex pool.
386  PT(EggVertexPool) vpool = new EggVertexPool(_egg_surface->get_name());
387  group->add_child(vpool);
388 
389  // Create all the vertices.
390  int ui, vi;
391  double u, v;
392 
393  typedef pvector<EggVertex *> VertexList;
394  VertexList new_verts;
395  new_verts.reserve(num_verts);
396 
397  // Also collect the vertices into this set to group them by spatial position
398  // only. This is relevant for calculating normals.
399  typedef pset<EggVertex *> NVertexGroup;
400  typedef pmap<LVertexd, NVertexGroup> NVertexCollection;
401  NVertexCollection n_collection;
402 
403  for (vi = 0; vi < num_v; vi++) {
404  if (_iso_v.empty()) {
405  v = (double)vi / (double)(num_v-1);
406  } else {
407  v = _iso_v[vi] / _iso_v.back();
408  }
409  for (ui = 0; ui < num_u; ui++) {
410  if (_iso_u.empty()) {
411  u = (double)ui / (double)(num_u-1);
412  } else {
413  u = _iso_u[ui] / _iso_u.back();
414  }
415 
416  PT(EggVertex) egg_vertex = evaluate_vertex(u, v);
417  vpool->add_vertex(egg_vertex);
418  new_verts.push_back(egg_vertex);
419  n_collection[egg_vertex->get_pos3()].insert(egg_vertex);
420  }
421  }
422  nassertr((int)new_verts.size() == num_verts, nullptr);
423 
424  // Now create a bunch of quads.
425  for (vi = 1; vi < num_v; vi++) {
426  for (ui = 1; ui < num_u; ui++) {
427  PT(EggPolygon) poly = new EggPolygon;
428  poly->add_vertex(new_verts[vi*num_u + (ui-1)]);
429  poly->add_vertex(new_verts[(vi-1)*num_u + (ui-1)]);
430  poly->add_vertex(new_verts[(vi-1)*num_u + ui]);
431  poly->add_vertex(new_verts[vi*num_u + ui]);
432 
433  poly->copy_attributes(*_egg_surface);
434 
435  // We compute a polygon normal just so we can verify the calculated
436  // vertex normals. It's also helpful for identifying degenerate
437  // polygons.
438  if (poly->recompute_polygon_normal()) {
439  tris += 2;
440  group->add_child(poly);
441  }
442  }
443  }
444 
445  // Now check all the vertex normals by comparing them to the polygon
446  // normals. Some might have not been computed at all; others might be
447  // facing in the wrong direction.
448 
449  // Now go back through and normalize the computed normals.
450  NVertexCollection::const_iterator nci;
451  for (nci = n_collection.begin(); nci != n_collection.end(); ++nci) {
452  const NVertexGroup &group = (*nci).second;
453 
454  // Calculate the normal these vertices should have based on the polygons
455  // that share it.
456  LNormald normal = LNormald::zero();
457  int num_polys = 0;
458  NVertexGroup::const_iterator ngi;
459  for (ngi = group.begin(); ngi != group.end(); ++ngi) {
460  EggVertex *egg_vertex = (*ngi);
461  EggVertex::PrimitiveRef::const_iterator pri;
462  for (pri = egg_vertex->pref_begin();
463  pri != egg_vertex->pref_end();
464  ++pri) {
465  EggPrimitive *egg_primitive = (*pri);
466  nassertr(egg_primitive->has_normal(), nullptr);
467  normal += egg_primitive->get_normal();
468  num_polys++;
469  }
470  }
471 
472  if (num_polys > 0) {
473  normal /= (double)num_polys;
474 
475  // Now compare this normal with what the NURBS representation
476  // calculated. It should be facing in at least vaguely the same
477  // direction.
478  for (ngi = group.begin(); ngi != group.end(); ++ngi) {
479  EggVertex *egg_vertex = (*ngi);
480  if (egg_vertex->has_normal()) {
481  if (normal.dot(egg_vertex->get_normal()) < 0.0) {
482  // This one is backwards.
483  egg_vertex->set_normal(-egg_vertex->get_normal());
484  }
485  } else {
486  // This vertex doesn't have a normal; it gets the computed normal.
487  egg_vertex->set_normal(normal);
488  }
489  }
490  }
491  }
492 
493  return group;
494 }
495 
496 /**
497  * Evaluates the surface at the given u, v position and sets the vertex to the
498  * appropriate values. Also sets the joint membership of the vertex.
499  */
500 PT(EggVertex) QtessSurface::
501 evaluate_vertex(double u, double v) const {
502  PT(EggVertex) egg_vertex = new EggVertex;
503 
504  LVertex point;
505  LNormal normal;
506  _nurbs_result->eval_point(u, v, point);
507  _nurbs_result->eval_normal(u, v, normal);
508 
509  // If the normal is too short, don't consider it--it's probably inaccurate
510  // due to numerical limitations. We'll recompute it later based on the
511  // polygon normals.
512  PN_stdfloat length = normal.length();
513  if (length > 0.0001f) {
514  normal /= length;
515  egg_vertex->set_normal(LCAST(double, normal));
516  }
517 
518  egg_vertex->set_pos(LCAST(double, point));
519  egg_vertex->set_uv(LVecBase2d(u, v));
520 
521  // The color is stored, by convention, in slots 0-4 of the surface.
522  if (_has_vertex_color) {
523  LColor rgba;
524  _nurbs_result->eval_extended_points(u, v, 0, &rgba[0], 4);
525  egg_vertex->set_color(rgba);
526  }
527 
528  // Also fill in the joint membership.
529  JointTable::const_iterator jti;
530  for (jti = _joint_table.begin(); jti != _joint_table.end(); ++jti) {
531  EggGroup *joint = (*jti).first;
532  int d = (*jti).second;
533 
534  double membership = _nurbs_result->eval_extended_point(u, v, d);
535  if (membership > 0.0) {
536  joint->ref_vertex(egg_vertex, membership);
537  }
538  }
539 
540  // And the morphs.
541  MorphTable::const_iterator mti;
542  for (mti = _dxyz_table.begin(); mti != _dxyz_table.end(); ++mti) {
543  const string &morph_name = (*mti).first;
544  int d = (*mti).second;
545 
546  LVector3 delta;
547  _nurbs_result->eval_extended_points(u, v, d, &delta[0], 3);
548  if (!delta.almost_equal(LVector3::zero())) {
549  egg_vertex->_dxyzs.insert(EggMorphVertex(morph_name, LCAST(double, delta)));
550  }
551  }
552 
553  for (mti = _drgba_table.begin(); mti != _drgba_table.end(); ++mti) {
554  const string &morph_name = (*mti).first;
555  int d = (*mti).second;
556 
557  LVector4 delta;
558  _nurbs_result->eval_extended_points(u, v, d, &delta[0], 4);
559  if (!delta.almost_equal(LVector4::zero())) {
560  egg_vertex->_drgbas.insert(EggMorphColor(morph_name, delta));
561  }
562  }
563 
564  return egg_vertex;
565 }
EggVertex::pref_begin
PrimitiveRef::const_iterator pref_begin() const
Returns an iterator that can, in conjunction with pref_end(), be used to traverse the entire set of p...
Definition: eggVertex.cxx:793
EggComment
A comment that appears in an egg file within a <Comment> entry.
Definition: eggComment.h:24
eggVertexPool.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pvector< double >
EggVertex::pref_end
PrimitiveRef::const_iterator pref_end() const
Returns an iterator that can, in conjunction with pref_begin(), be used to traverse the entire set of...
Definition: eggVertex.cxx:805
QtessSurface::omit
void omit()
Sets up the surface to omit itself from the output.
Definition: qtessSurface.cxx:163
QtessSurface::tesselate_uv
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,...
Definition: qtessSurface.cxx:173
pmap
This is our own Panda specialization on the default STL map.
Definition: pmap.h:49
QtessSurface
A reference to an EggNurbsSurface in the egg file, and its parameters as set by the user input file a...
Definition: qtessSurface.h:32
QtessSurface::tesselate_per_isoparam
void tesselate_per_isoparam(double pi, bool autoplace, double ratio)
Sets the surface up to tesselate itself to a uniform amount per isoparam.
Definition: qtessSurface.cxx:199
QtessSurface::tesselate_specific
void tesselate_specific(const pvector< double > &u_list, const pvector< double > &v_list)
Sets the surface up to tesselate itself at specific isoparams only.
Definition: qtessSurface.cxx:187
EggMorphList::insert
std::pair< iterator, bool > insert(const MorphType &value)
This is similar to the insert() interface for sets, except it does not guarantee that the resulting l...
Definition: eggMorphList.I:159
EggGroupNode
A base class for nodes in the hierarchy that are not leaf nodes.
Definition: eggGroupNode.h:46
EggPrimitive
A base class for any of a number of kinds of geometry primitives: polygons, point lights,...
Definition: eggPrimitive.h:47
EggVertex::gref_end
GroupRef::const_iterator gref_end() const
Returns an iterator that can, in conjunction with gref_begin(), be used to traverse the entire set of...
Definition: eggVertex.cxx:714
QtessSurface::tesselate_auto
void tesselate_auto(int u, int v, double ratio)
Sets the surface up to tesselate itself by automatically determining the best place to put the indica...
Definition: qtessSurface.cxx:240
qtessSurface.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
QtessSurface::tesselate
int tesselate()
Applies the appropriate tesselation to the surface, and replaces its node in the tree with an EggGrou...
Definition: qtessSurface.cxx:115
QtessSurface::get_score
double get_score(double ratio)
Computes the curvature/stretch score for the surface, if it has not been already computed,...
Definition: qtessSurface.cxx:91
pmap.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
EggNurbsSurface::is_closed_v
bool is_closed_v() const
Returns true if the surface appears to be closed in the V direction.
Definition: eggNurbsSurface.cxx:157
EggVertex::set_uv
void set_uv(const LTexCoordd &texCoord)
Replaces the unnamed UV coordinate pair on the vertex with the indicated value.
Definition: eggVertex.I:193
QtessInputEntry::output_extra
static void output_extra(std::ostream &out, const pvector< double > &iso, char axis)
This function is used to identify the extra isoparams in the list added by user control.
Definition: qtessInputEntry.cxx:359
EggVertex
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal.
Definition: eggVertex.h:39
EggPolygon
A single polygon.
Definition: eggPolygon.h:24
eggVertex.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
EggGroup::get_vertex_membership
double get_vertex_membership(const EggVertex *vert) const
Returns the amount of membership of the indicated vertex in this group.
Definition: eggGroup.cxx:677
EggPrimitive::add_vertex
EggVertex * add_vertex(EggVertex *vertex)
Adds the indicated vertex to the end of the primitive's list of vertices, and returns it.
Definition: eggPrimitive.cxx:654
eggComment.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
QtessSurface::count_tris
int count_tris() const
Returns the number of triangles that will be generated by the current tesselation parameters.
Definition: qtessSurface.I:104
config_egg_qtess.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
QtessSurface::write_qtess_parameter
int write_qtess_parameter(std::ostream &out)
Writes a line to the given output file telling qtess how this surface should be tesselated uniformly.
Definition: qtessSurface.cxx:139
EggSurface::get_u_subdiv
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
EggGroup::ref_vertex
void ref_vertex(EggVertex *vert, double membership=1.0)
Adds the vertex to the set of those referenced by the group, at the indicated membership level.
Definition: eggGroup.cxx:608
EggNurbsSurface::is_closed_u
bool is_closed_u() const
Returns true if the surface appears to be closed in the U direction.
Definition: eggNurbsSurface.cxx:136
EggMorph
A single <Dxyz> or <Duv> or some such entry.
Definition: eggMorph.h:30
pset.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
EggSurface::get_v_subdiv
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
EggVertex::get_pos3
LVertexd get_pos3() const
Valid if get_num_dimensions() returns 3 or 4.
Definition: eggVertex.I:131
EggVertexPool
A collection of vertices.
Definition: eggVertexPool.h:41
egg_parametrics.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
qtessInputEntry.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
EggVertex::gref_begin
GroupRef::const_iterator gref_begin() const
Returns an iterator that can, in conjunction with gref_end(), be used to traverse the entire set of g...
Definition: eggVertex.cxx:702
EggNode
A base class for things that may be directly added into the egg hierarchy.
Definition: eggNode.h:35
EggGroup
The main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
Definition: eggGroup.h:34
EggGroupNode::add_child
EggNode * add_child(EggNode *node)
Adds the indicated child to the group and returns it.
Definition: eggGroupNode.cxx:243
EggVertex::set_pos
void set_pos(double pos)
Sets the vertex position.
Definition: eggVertex.I:42
qtessGlobals.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
EggNurbsSurface
A parametric NURBS surface.
Definition: eggNurbsSurface.h:27
QtessSurface::tesselate_per_score
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.
Definition: qtessSurface.cxx:220
eggPolygon.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pset
This is our own Panda specialization on the default STL set.
Definition: pset.h:49