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