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 }
void transform(const LMatrix4d &mat)
Applies the indicated transformation to the node and all of its descendants.
Definition: eggNode.I:253
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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_...
void set_pos(double pos)
Sets the vertex position.
Definition: eggVertex.I:42
The main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
Definition: eggGroup.h:34
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal.
Definition: eggVertex.h:39
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void write_egg_file()
Writes out the egg file as the normal result of the program.
Definition: eggWriter.cxx:177
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A single polygon.
Definition: eggPolygon.h:24
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A program to generate an egg file representing a tube model, similar in shape to a CollisionCapsule.
Definition: eggMakeTube.h:29
EggNode * add_child(EggNode *node)
Adds the indicated child to the group and returns it.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
A collection of vertices.
Definition: eggVertexPool.h:41
EggVertex * add_vertex(EggVertex *vertex)
Adds the indicated vertex to the end of the primitive's list of vertices, and returns it.