Panda3D
|
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 }