Panda3D
eggMakeTube.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 eggMakeTube.cxx
10  * @author drose
11  * @date 2003-10-01
12  */
13 
14 #include "eggMakeTube.h"
15 #include "eggGroup.h"
16 #include "eggVertexPool.h"
17 #include "eggVertex.h"
18 #include "eggPolygon.h"
19 #include "pointerTo.h"
20 #include "look_at.h"
21 
22 /**
23  *
24  */
25 EggMakeTube::
26 EggMakeTube() {
27 
28  set_program_brief("generate a tube or sphere from geometry in an .egg file");
29  set_program_description
30  ("egg-make-tube generates an egg file representing a \"tube\" model, "
31  "a cylinder capped on both ends by hemispheres. This is similar "
32  "in shape to the CollisionCapsule object within Panda.\n\n"
33  "This program can also generate spheres if you omit -b; in this "
34  "case, you are generating a degenerate tube of length 0.");
35 
36  add_option
37  ("a", "x,y,z", 0,
38  "Specify the first endpoint of the tube.",
39  &EggWriter::dispatch_double_triple, nullptr, _point_a);
40 
41  add_option
42  ("b", "x,y,z", 0,
43  "Specify the second endpoint of the tube.",
44  &EggWriter::dispatch_double_triple, &_got_point_b, _point_b);
45 
46  add_option
47  ("r", "radius", 0,
48  "Specify the radius of the tube. The tube will extend beyond "
49  "the endpoints in each direction by the amount of radius.",
50  &EggWriter::dispatch_double, nullptr, &_radius);
51 
52  add_option
53  ("slices", "count", 0,
54  "Specify the number of slices appearing radially around the tube.",
55  &EggWriter::dispatch_int, nullptr, &_num_slices);
56 
57  add_option
58  ("crings", "count", 0,
59  "Specify the number of rings appearing in each endcap of the tube.",
60  &EggWriter::dispatch_int, nullptr, &_num_crings);
61 
62  add_option
63  ("trings", "count", 0,
64  "Specify the number of rings appearing in the cylindrical body "
65  "of the tube.",
66  &EggWriter::dispatch_int, nullptr, &_num_trings);
67 
68  _point_a[0] = 0.0;
69  _point_a[1] = 0.0;
70  _point_a[2] = 0.0;
71 
72  _point_b[0] = 0.0;
73  _point_b[1] = 0.0;
74  _point_b[2] = 0.0;
75 
76  _radius = 1.0;
77 
78  _num_slices = 8;
79  _num_crings = 4;
80  _num_trings = 1;
81 }
82 
83 /**
84  *
85  */
86 void EggMakeTube::
87 run() {
88  if (!_got_point_b) {
89  _point_b[0] = _point_a[0];
90  _point_b[1] = _point_a[1];
91  _point_b[2] = _point_a[2];
92  }
93 
94  // We will generate the vertices in the canonical space (along the y axis),
95  // then transform it to the desired point.
96  LVector3d direction(_point_b[0] - _point_a[0],
97  _point_b[1] - _point_a[1],
98  _point_b[2] - _point_a[2]);
99  _length = direction.length();
100 
101  // First, create an enclosing group and a vertex pool.
102  _group = new EggGroup("tube");
103  _data->add_child(_group);
104 
105  _vpool = new EggVertexPool("tube");
106  _group->add_child(_vpool);
107 
108  // Generate the first endcap.
109  int ri, si;
110  EggVertex *vtx_1;
111  EggVertex *vtx_2;
112 
113  for (ri = 0; ri < _num_crings; ri++) {
114  vtx_1 = nullptr;
115  vtx_2 = nullptr;
116  for (si = 0; si <= _num_slices; si++) {
117  EggVertex *vtx_3 = calc_sphere1_vertex(ri, si);
118  EggVertex *vtx_4 = calc_sphere1_vertex(ri + 1, si);
119  add_polygon(vtx_1, vtx_2, vtx_4, vtx_3);
120  vtx_1 = vtx_3;
121  vtx_2 = vtx_4;
122  }
123  }
124 
125  // Now the cylinder sides.
126  if (_length != 0.0) {
127  for (ri = 0; ri < _num_trings; ri++) {
128  vtx_1 = nullptr;
129  vtx_2 = nullptr;
130  for (si = 0; si <= _num_slices; si++) {
131  EggVertex *vtx_3 = calc_tube_vertex(ri, si);
132  EggVertex *vtx_4 = calc_tube_vertex(ri + 1, si);
133  add_polygon(vtx_1, vtx_2, vtx_4, vtx_3);
134  vtx_1 = vtx_3;
135  vtx_2 = vtx_4;
136  }
137  }
138  }
139 
140  // And the second endcap.
141  for (ri = _num_crings - 1; ri >= 0; ri--) {
142  vtx_1 = nullptr;
143  vtx_2 = nullptr;
144  for (si = 0; si <= _num_slices; si++) {
145  EggVertex *vtx_3 = calc_sphere2_vertex(ri + 1, si);
146  EggVertex *vtx_4 = calc_sphere2_vertex(ri, si);
147  add_polygon(vtx_1, vtx_2, vtx_4, vtx_3);
148  vtx_1 = vtx_3;
149  vtx_2 = vtx_4;
150  }
151  }
152 
153  // Now transform the vertices out of the canonical position.
154  LMatrix4d mat;
155  look_at(mat, direction, LVector3d(0.0, 0.0, 1.0), CS_zup_right);
156  mat.set_row(3, LPoint3d(_point_a[0], _point_a[1], _point_a[2]));
157  _group->transform(mat);
158 
159  write_egg_file();
160 }
161 
162 /**
163  * Calculates a particular vertex on the surface of the first endcap
164  * hemisphere.
165  */
166 EggVertex *EggMakeTube::
167 calc_sphere1_vertex(int ri, int si) {
168  double r = (double)ri / (double)_num_crings;
169  double s = (double)si / (double)_num_slices;
170 
171  // Find the point on the rim, based on the slice.
172  double theta = s * 2.0 * MathNumbers::pi;
173  double x_rim = cos(theta);
174  double z_rim = sin(theta);
175 
176  // Now pull that point in towards the pole, based on the ring.
177  double phi = r * 0.5 * MathNumbers::pi;
178  double to_pole = sin(phi);
179 
180  double x = _radius * x_rim * to_pole;
181  double y = -_radius * cos(phi);
182  double z = _radius * z_rim * to_pole;
183 
184  EggVertex vert;
185  vert.set_pos(LPoint3d(x, y, z));
186 
187  return _vpool->create_unique_vertex(vert);
188 }
189 
190 /**
191  * Calculates a vertex on the side of the cylindrical body of the tube.
192  */
193 EggVertex *EggMakeTube::
194 calc_tube_vertex(int ri, int si) {
195  double r = (double)ri / (double)_num_trings;
196  double s = (double)si / (double)_num_slices;
197 
198  // Find the point on the rim, based on the slice.
199  double theta = s * 2.0 * MathNumbers::pi;
200  double x_rim = cos(theta);
201  double z_rim = sin(theta);
202 
203  double x = _radius * x_rim;
204  double y = _length * r;
205  double z = _radius * z_rim;
206 
207  EggVertex vert;
208  vert.set_pos(LPoint3d(x, y, z));
209 
210  return _vpool->create_unique_vertex(vert);
211 }
212 
213 /**
214  * Calculates a particular vertex on the surface of the second endcap
215  * hemisphere.
216  */
217 EggVertex *EggMakeTube::
218 calc_sphere2_vertex(int ri, int si) {
219  double r = (double)ri / (double)_num_crings;
220  double s = (double)si / (double)_num_slices;
221 
222  // Find the point on the rim, based on the slice.
223  double theta = s * 2.0 * MathNumbers::pi;
224  double x_rim = cos(theta);
225  double z_rim = sin(theta);
226 
227  // Now pull that point in towards the pole, based on the ring.
228  double phi = r * 0.5 * MathNumbers::pi;
229  double to_pole = sin(phi);
230 
231  double x = _radius * x_rim * to_pole;
232  double y = _length + _radius * cos(phi);
233  double z = _radius * z_rim * to_pole;
234 
235  EggVertex vert;
236  vert.set_pos(LPoint3d(x, y, z));
237 
238  return _vpool->create_unique_vertex(vert);
239 }
240 
241 /**
242  * Adds the polygon defined by the indicated four vertices to the group. If
243  * the first vertex is NULL, does nothing.
244  */
245 void EggMakeTube::
246 add_polygon(EggVertex *a, EggVertex *b, EggVertex *c, EggVertex *d) {
247  if (a == nullptr) {
248  return;
249  }
250 
251  PT(EggPolygon) poly = new EggPolygon;
252  poly->add_vertex(a);
253  if (a != b) {
254  poly->add_vertex(b);
255  }
256  poly->add_vertex(c);
257  if (c != d) {
258  poly->add_vertex(d);
259  }
260 
261  _group->add_child(poly.p());
262 }
263 
264 
265 int main(int argc, char *argv[]) {
266  EggMakeTube prog;
267  prog.parse_command_line(argc, argv);
268  prog.run();
269  return 0;
270 }
EggNode * add_child(EggNode *node)
Adds the indicated child to the group and returns it.
The main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
Definition: eggGroup.h:34
A program to generate an egg file representing a tube model, similar in shape to a CollisionCapsule.
Definition: eggMakeTube.h:29
void transform(const LMatrix4d &mat)
Applies the indicated transformation to the node and all of its descendants.
Definition: eggNode.I:253
A single polygon.
Definition: eggPolygon.h:24
EggVertex * add_vertex(EggVertex *vertex)
Adds the indicated vertex to the end of the primitive's list of vertices, and returns it.
A collection of vertices.
Definition: eggVertexPool.h:41
EggVertex * create_unique_vertex(const EggVertex &copy)
Creates a new vertex in the pool that is a copy of the indicated one and returns it.
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal.
Definition: eggVertex.h:39
void set_pos(double pos)
Sets the vertex position.
Definition: eggVertex.I:42
void write_egg_file()
Writes out the egg file as the normal result of the program.
Definition: eggWriter.cxx:177
virtual void parse_command_line(int argc, char **argv)
Dispatches on each of the options on the command line, and passes the remaining parameters to handle_...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.