Panda3D

eggMakeTube.cxx

00001 // Filename: eggMakeTube.cxx
00002 // Created by:  drose (01Oct03)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "eggMakeTube.h"
00016 #include "eggGroup.h"
00017 #include "eggVertexPool.h"
00018 #include "eggVertex.h"
00019 #include "eggPolygon.h"
00020 #include "pointerTo.h"
00021 #include "look_at.h"
00022 #include "pystub.h"
00023 
00024 ////////////////////////////////////////////////////////////////////
00025 //     Function: EggMakeTube::Constructor
00026 //       Access: Public
00027 //  Description: 
00028 ////////////////////////////////////////////////////////////////////
00029 EggMakeTube::
00030 EggMakeTube() {
00031 
00032   set_program_description
00033     ("egg-make-tube generates an egg file representing a \"tube\" model, "
00034      "a cylinder capped on both ends by hemispheres.  This is similar "
00035      "in shape to the CollisionTube object within Panda.\n\n"
00036      "This program can also generate spheres if you omit -b; in this "
00037      "case, you are generating a degenerate tube of length 0.");
00038 
00039   add_option
00040     ("a", "x,y,z", 0, 
00041      "Specify the first endpoint of the tube.",
00042      &EggWriter::dispatch_double_triple, NULL, _point_a);
00043 
00044   add_option
00045     ("b", "x,y,z", 0, 
00046      "Specify the second endpoint of the tube.",
00047      &EggWriter::dispatch_double_triple, &_got_point_b, _point_b);
00048 
00049   add_option
00050     ("r", "radius", 0, 
00051      "Specify the radius of the tube.  The tube will extend beyond "
00052      "the endpoints in each direction by the amount of radius.",
00053      &EggWriter::dispatch_double, NULL, &_radius);
00054 
00055   add_option
00056     ("slices", "count", 0, 
00057      "Specify the number of slices appearing radially around the tube.",
00058      &EggWriter::dispatch_int, NULL, &_num_slices);
00059 
00060   add_option
00061     ("crings", "count", 0, 
00062      "Specify the number of rings appearing in each endcap of the tube.",
00063      &EggWriter::dispatch_int, NULL, &_num_crings);
00064 
00065   add_option
00066     ("trings", "count", 0, 
00067      "Specify the number of rings appearing in the cylindrical body "
00068      "of the tube.",
00069      &EggWriter::dispatch_int, NULL, &_num_trings);
00070 
00071   _point_a[0] = 0.0;
00072   _point_a[1] = 0.0;
00073   _point_a[2] = 0.0;
00074 
00075   _point_b[0] = 0.0;
00076   _point_b[1] = 0.0;
00077   _point_b[2] = 0.0;
00078 
00079   _radius = 1.0;
00080 
00081   _num_slices = 8;
00082   _num_crings = 4;
00083   _num_trings = 1;
00084 }
00085 
00086 ////////////////////////////////////////////////////////////////////
00087 //     Function: EggMakeTube::run
00088 //       Access: Public
00089 //  Description:
00090 ////////////////////////////////////////////////////////////////////
00091 void EggMakeTube::
00092 run() {
00093   if (!_got_point_b) {
00094     _point_b[0] = _point_a[0];
00095     _point_b[1] = _point_a[1];
00096     _point_b[2] = _point_a[2];
00097   }
00098 
00099   // We will generate the vertices in the canonical space (along the y
00100   // axis), then transform it to the desired point.
00101   LVector3d direction(_point_b[0] - _point_a[0],
00102                       _point_b[1] - _point_a[1],
00103                       _point_b[2] - _point_a[2]);
00104   _length = direction.length();
00105 
00106   // First, create an enclosing group and a vertex pool.
00107   _group = new EggGroup("tube");
00108   _data->add_child(_group);
00109 
00110   _vpool = new EggVertexPool("tube");
00111   _group->add_child(_vpool);
00112 
00113   // Generate the first endcap.
00114   int ri, si;
00115   EggVertex *vtx_1;
00116   EggVertex *vtx_2;
00117 
00118   for (ri = 0; ri < _num_crings; ri++) {
00119     vtx_1 = NULL;
00120     vtx_2 = NULL;
00121     for (si = 0; si <= _num_slices; si++) {
00122       EggVertex *vtx_3 = calc_sphere1_vertex(ri, si);
00123       EggVertex *vtx_4 = calc_sphere1_vertex(ri + 1, si);
00124       add_polygon(vtx_1, vtx_2, vtx_4, vtx_3);
00125       vtx_1 = vtx_3;
00126       vtx_2 = vtx_4;
00127     }
00128   }
00129 
00130   // Now the cylinder sides.
00131   if (_length != 0.0) {
00132     for (ri = 0; ri < _num_trings; ri++) {
00133       vtx_1 = NULL;
00134       vtx_2 = NULL;
00135       for (si = 0; si <= _num_slices; si++) {
00136         EggVertex *vtx_3 = calc_tube_vertex(ri, si);
00137         EggVertex *vtx_4 = calc_tube_vertex(ri + 1, si);
00138         add_polygon(vtx_1, vtx_2, vtx_4, vtx_3);
00139         vtx_1 = vtx_3;
00140         vtx_2 = vtx_4;
00141       }
00142     }
00143   }
00144 
00145   // And the second endcap.
00146   for (ri = _num_crings - 1; ri >= 0; ri--) {
00147     vtx_1 = NULL;
00148     vtx_2 = NULL;
00149     for (si = 0; si <= _num_slices; si++) {
00150       EggVertex *vtx_3 = calc_sphere2_vertex(ri + 1, si);
00151       EggVertex *vtx_4 = calc_sphere2_vertex(ri, si);
00152       add_polygon(vtx_1, vtx_2, vtx_4, vtx_3);
00153       vtx_1 = vtx_3;
00154       vtx_2 = vtx_4;
00155     }
00156   }
00157 
00158   // Now transform the vertices out of the canonical position.
00159   LMatrix4d mat;
00160   look_at(mat, direction, LVector3d(0.0, 0.0, 1.0), CS_zup_right);
00161   mat.set_row(3, LPoint3d(_point_a[0], _point_a[1], _point_a[2]));
00162   _group->transform(mat);
00163 
00164   write_egg_file();
00165 }
00166 
00167 ////////////////////////////////////////////////////////////////////
00168 //     Function: EggMakeTube::calc_sphere1_vertex
00169 //       Access: Private
00170 //  Description: Calculates a particular vertex on the surface of the
00171 //               first endcap hemisphere.
00172 ////////////////////////////////////////////////////////////////////
00173 EggVertex *EggMakeTube::
00174 calc_sphere1_vertex(int ri, int si) {
00175   double r = (double)ri / (double)_num_crings;
00176   double s = (double)si / (double)_num_slices;
00177 
00178   // Find the point on the rim, based on the slice.
00179   double theta = s * 2.0 * MathNumbers::pi;
00180   double x_rim = cos(theta);
00181   double z_rim = sin(theta);
00182 
00183   // Now pull that point in towards the pole, based on the ring.
00184   double phi = r * 0.5 * MathNumbers::pi;
00185   double to_pole = sin(phi);
00186 
00187   double x = _radius * x_rim * to_pole;
00188   double y = -_radius * cos(phi);
00189   double z = _radius * z_rim * to_pole;
00190 
00191   EggVertex vert;
00192   vert.set_pos(LPoint3d(x, y, z));
00193 
00194   return _vpool->create_unique_vertex(vert);
00195 }
00196 
00197 ////////////////////////////////////////////////////////////////////
00198 //     Function: EggMakeTube::calc_tube_vertex
00199 //       Access: Private
00200 //  Description: Calculates a vertex on the side of the cylindrical
00201 //               body of the tube.
00202 ////////////////////////////////////////////////////////////////////
00203 EggVertex *EggMakeTube::
00204 calc_tube_vertex(int ri, int si) {
00205   double r = (double)ri / (double)_num_trings;
00206   double s = (double)si / (double)_num_slices;
00207 
00208   // Find the point on the rim, based on the slice.
00209   double theta = s * 2.0 * MathNumbers::pi;
00210   double x_rim = cos(theta);
00211   double z_rim = sin(theta);
00212 
00213   double x = _radius * x_rim;
00214   double y = _length * r;
00215   double z = _radius * z_rim;
00216 
00217   EggVertex vert;
00218   vert.set_pos(LPoint3d(x, y, z));
00219 
00220   return _vpool->create_unique_vertex(vert);
00221 }
00222 
00223 ////////////////////////////////////////////////////////////////////
00224 //     Function: EggMakeTube::calc_sphere2_vertex
00225 //       Access: Private
00226 //  Description: Calculates a particular vertex on the surface of the
00227 //               second endcap hemisphere.
00228 ////////////////////////////////////////////////////////////////////
00229 EggVertex *EggMakeTube::
00230 calc_sphere2_vertex(int ri, int si) {
00231   double r = (double)ri / (double)_num_crings;
00232   double s = (double)si / (double)_num_slices;
00233 
00234   // Find the point on the rim, based on the slice.
00235   double theta = s * 2.0 * MathNumbers::pi;
00236   double x_rim = cos(theta);
00237   double z_rim = sin(theta);
00238 
00239   // Now pull that point in towards the pole, based on the ring.
00240   double phi = r * 0.5 * MathNumbers::pi;
00241   double to_pole = sin(phi);
00242 
00243   double x = _radius * x_rim * to_pole;
00244   double y = _length + _radius * cos(phi);
00245   double z = _radius * z_rim * to_pole;
00246 
00247   EggVertex vert;
00248   vert.set_pos(LPoint3d(x, y, z));
00249 
00250   return _vpool->create_unique_vertex(vert);
00251 }
00252 
00253 ////////////////////////////////////////////////////////////////////
00254 //     Function: EggMakeTube::add_polygon
00255 //       Access: Private
00256 //  Description: Adds the polygon defined by the indicated four
00257 //               vertices to the group.  If the first vertex is
00258 //               NULL, does nothing.
00259 ////////////////////////////////////////////////////////////////////
00260 void EggMakeTube::
00261 add_polygon(EggVertex *a, EggVertex *b, EggVertex *c, EggVertex *d) {
00262   if (a == (EggVertex *)NULL) {
00263     return;
00264   }
00265 
00266   PT(EggPolygon) poly = new EggPolygon;
00267   poly->add_vertex(a);
00268   if (a != b) {
00269     poly->add_vertex(b);
00270   }
00271   poly->add_vertex(c);
00272   if (c != d) {
00273     poly->add_vertex(d);
00274   }
00275 
00276   _group->add_child(poly.p());
00277 }
00278 
00279 
00280 int main(int argc, char *argv[]) {
00281   // A call to pystub() to force libpystub.so to be linked in.
00282   pystub();
00283 
00284   EggMakeTube prog;
00285   prog.parse_command_line(argc, argv);
00286   prog.run();
00287   return 0;
00288 }
 All Classes Functions Variables Enumerations