Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

physics/Box.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002   Copyright (C)1996 David Jung <opensim@pobox.com>
00003 
00004   This program/file is free software; you can redistribute it and/or modify
00005   it under the terms of the GNU General Public License as published by
00006   the Free Software Foundation; either version 2 of the License, or
00007   (at your option) any later version.
00008   
00009   This program is distributed in the hope that it will be useful,
00010   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012   GNU General Public License for more details. (http://www.gnu.org)
00013   
00014   You should have received a copy of the GNU General Public License
00015   along with this program; if not, write to the Free Software
00016   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017   
00018   $Id: Box.cpp 1031 2004-02-11 20:46:36Z jungd $
00019  
00020 ****************************************************************************/
00021 
00022 #include <physics/Box>
00023 
00024 #include <base/Externalizer>
00025 #include <gfx/VisualTriangles>
00026 #include <physics/Material>
00027 #include <physics/Sphere>
00028 
00029 #include <osg/Group>
00030 #include <osg/Geode>
00031 #include <osg/ShapeDrawable>
00032 
00033 
00034 using physics::Box;
00035 
00036 using base::Transform;
00037 using base::Point3;
00038 using base::dom::DOMNode;
00039 using base::dom::DOMElement;
00040 using gfx::Color3;
00041 using gfx::VisualTriangles;
00042 using gfx::Segment3;
00043 using gfx::Triangle3;
00044 using gfx::Quad3;
00045 using physics::MassProperties;
00046 using physics::CollisionModel;
00047 
00048 using osg::Node;
00049 using osg::Group;
00050 using osg::Geode;
00051 
00052 
00053 Box::Box(Real width, Real height, Real depth)
00054   : dim(width,height,depth), massPropertiesCached(false)
00055 {}
00056 
00057 Box::Box(const Box& b) 
00058   : dim(b.dim), massPropertiesCached(false)
00059 {}
00060 
00061 Box::~Box() 
00062 {
00063 }
00064 
00065 
00066 const MassProperties& Box::getMassProperties(ref<const Material> material) const
00067 {
00068   if (massPropertiesCached && (density == material->density()))
00069     return massProperties;
00070 
00071   density = material->density();
00072   
00073   Real dx = dim.x;
00074   Real dy = dim.y;
00075   Real dz = dim.z; 
00076   
00077   Real volume = dx*dy*dz;
00078   massProperties.mass = volume*density;
00079   
00080   Real k = massProperties.mass/12.0;
00081   Matrix3 Ibody;
00082   Ibody.e(1,1) = (dy*dy + dz*dz)*k;
00083   Ibody.e(2,2) = (dx*dx + dz*dz)*k;
00084   Ibody.e(3,3) = (dx*dx + dy*dy)*k;
00085   massProperties.setIbody(Ibody);
00086 
00087   massProperties.centerOfMass = Point3(0.0,0.0,0.0);
00088   
00089   massPropertiesCached = true;
00090 
00091   return massProperties;
00092 }
00093 
00094 
00095 
00096 osg::Node* Box::createOSGVisual(Visual::Attributes visualAttributes) const
00097 {
00098   if ((node!=0) && (attributes==visualAttributes))
00099     return &(*node);
00100 
00101   // NB: Perhaps we should construct a single Cube for the Box class and
00102   //  just share it for all boxes, with a scale transform above it?
00103   //  (slower, but less memory) !!!
00104   //  (same goes for other Shapes - Cylinder, etc.)
00105 /* 
00106   osg::GeoSet* cube = new osg::GeoSet();
00107 
00108   // set up the primitives
00109   cube->setPrimType( osg::GeoSet::QUADS );
00110   cube->setNumPrims( 6 );      // the six square faces
00111   
00112   // set up the primitive indices
00113   int* cubeLengthList = new int[6];
00114   cubeLengthList[0] = 4; // each side of the cube has 4 vertices
00115   cubeLengthList[1] = 4;
00116   cubeLengthList[2] = 4;
00117   cubeLengthList[3] = 4;
00118   cubeLengthList[4] = 4;
00119   cubeLengthList[5] = 4;
00120   
00121   cube->setPrimLengths( cubeLengthList );
00122   
00123   // set up the coordinates.
00124   array<Quad3> quads(asQuads());
00125   osg::Vec3 *cubeCoords = new osg::Vec3[4*quads.size()];
00126   for(Int i=0; i<quads.size(); i++) {
00127     const Quad3& q(quads[i]);
00128     cubeCoords[4*i  ].set( q.c1.x, q.c1.y, q.c1.z );
00129     cubeCoords[4*i+1].set( q.c2.x, q.c2.y, q.c2.z );
00130     cubeCoords[4*i+2].set( q.c3.x, q.c3.y, q.c3.z );
00131     cubeCoords[4*i+3].set( q.c4.x, q.c4.y, q.c4.z );
00132     
00133   }
00134   */
00135   /*
00136   cubeCoords[0].set( -1.0000f,   1.0000f,  -1.000f );
00137   cubeCoords[1].set( 1.0000f,   1.0000f,  -1.0000f );
00138   cubeCoords[2].set( 1.0000f,  -1.0000f,  -1.0000f );
00139   cubeCoords[3].set( -1.0000f,  -1.0000f,  -1.000 );
00140   
00141   cubeCoords[4].set( 1.0000f,   1.0000f,  -1.0000f );
00142   cubeCoords[5].set( 1.0000f,   1.0000f,   1.0000f );
00143   cubeCoords[6].set( 1.0000f,  -1.0000f,   1.0000f );
00144   cubeCoords[7].set( 1.0000f,  -1.0000f,  -1.0000f );
00145   
00146   cubeCoords[8].set( 1.0000f,   1.0000f,   1.0000f );
00147   cubeCoords[9].set( -1.0000f,   1.0000f,   1.000f );
00148   cubeCoords[10].set( -1.0000f,  -1.0000f,   1.000f );
00149   cubeCoords[11].set( 1.0000f,  -1.0000f,   1.0000f );
00150   
00151   cubeCoords[12].set( -1.0000f,   1.0000f,   1.000 );
00152   cubeCoords[13].set( -1.0000f,   1.0000f,  -1.000 );
00153   cubeCoords[14].set( -1.0000f,  -1.0000f,  -1.000 );
00154   cubeCoords[15].set( -1.0000f,  -1.0000f,   1.000 );
00155   
00156   cubeCoords[16].set( -1.0000f,   1.0000f,   1.000 );
00157   cubeCoords[17].set( 1.0000f,   1.0000f,   1.0000f );
00158   cubeCoords[18].set( 1.0000f,   1.0000f,  -1.0000f );
00159   cubeCoords[19].set( -1.0000f,   1.0000f,  -1.000f );
00160   
00161   cubeCoords[20].set( -1.0000f,  -1.0000f,   1.000f );
00162   cubeCoords[21].set( -1.0000f,  -1.0000f,  -1.000f );
00163   cubeCoords[22].set( 1.0000f,  -1.0000f,  -1.0000f );
00164   cubeCoords[23].set( 1.0000f,  -1.0000f,   1.0000f );
00165   
00166 
00167   // !!! need to subdivide here for better lighting
00168   // maybe make some LOD nodes.
00169 
00170   // Scale to dimensions
00171   for(Int c=0; c<24; c++) {
00172     cubeCoords[c].x() *= dim.x/2.0;
00173     cubeCoords[c].y() *= dim.y/2.0;
00174     cubeCoords[c].z() *= dim.z/2.0;
00175   }
00176 */
00177 /*
00178   cube->setCoords( cubeCoords );
00179     
00180   // set up the normals.
00181   osg::Vec3 *cubeNormals = new osg::Vec3[6];
00182   cubeNormals[0].set(0.0f,0.0f,-1.0f);
00183   cubeNormals[1].set(1.0f,0.0f,0.0f);
00184   cubeNormals[2].set(0.0f,0.0f,1.0f);
00185   cubeNormals[3].set(-1.0f,0.0f,0.0f);
00186   cubeNormals[4].set(0.0f,1.0f,0.0f);
00187   cubeNormals[5].set(0.0f,-1.0f,0.0f);
00188   cube->setNormals( cubeNormals );
00189   cube->setNormalBinding( osg::GeoSet::BIND_PERPRIM );
00190 */
00191   // Create a osg::Geode and add the GeoSet 
00192   //  Drawables to it.
00193   osg::Geode* geode = new Geode();
00194   geode->setName("Box");
00195   //  geode->addDrawable( cube );
00196   geode->addDrawable(new osg::ShapeDrawable(
00197                           new osg::Box(osg::Vec3(0.0f,0.0f,0.0f),dim.x,dim.y,dim.z)));
00198 
00199   if (!(visualAttributes & Visual::ShowAxes)) 
00200     node = geode;
00201   else {
00202     if (dim.x > 0.16)  //!!!
00203       node=geode; //!!! 
00204     else {//!!!
00205     // create axes 
00206     Group* group = new Group();
00207     group->addChild( geode );
00208     group->addChild( createOSGAxes(dimensions()) );
00209     node = group;
00210     }//!!!
00211   }
00212   attributes = visualAttributes;
00213   return &(*node);
00214 }
00215 
00216 
00217 
00218 array<Quad3> Box::asQuads() const
00219 {
00220   array<Quad3> quads;
00221   quads.push_back(Quad3(Point3(-1, 1,-1),
00222                         Point3( 1, 1,-1),
00223                         Point3( 1,-1,-1),
00224                         Point3(-1,-1,-1)));
00225                         
00226   quads.push_back(Quad3(Point3( 1, 1,-1),
00227                         Point3( 1, 1, 1),
00228                         Point3( 1,-1, 1),
00229                         Point3( 1,-1,-1)));
00230                         
00231   quads.push_back(Quad3(Point3( 1, 1, 1),
00232                         Point3(-1, 1, 1),
00233                         Point3(-1,-1, 1),
00234                         Point3( 1,-1, 1)));
00235                         
00236   quads.push_back(Quad3(Point3(-1, 1, 1),
00237                         Point3(-1, 1,-1),
00238                         Point3(-1,-1,-1),
00239                         Point3(-1,-1, 1)));
00240                         
00241   quads.push_back(Quad3(Point3(-1, 1, 1),
00242                         Point3( 1, 1, 1),
00243                         Point3( 1, 1,-1),
00244                         Point3(-1, 1,-1)));
00245                         
00246   quads.push_back(Quad3(Point3(-1,-1, 1),
00247                         Point3(-1,-1,-1),
00248                         Point3( 1,-1,-1),
00249                         Point3( 1,-1, 1)));
00250 
00251   // scale to dimensions
00252   for(Int i=0; i<6; i++) {
00253     Quad3& q(quads[i]);
00254     for(Int c=0; c<4; c++) {
00255       Point3& cc(q[c]);
00256       cc.x *= dim.x/2.0;
00257       cc.y *= dim.y/2.0;
00258       cc.z *= dim.z/2.0;
00259     }
00260   }                     
00261                         
00262   return quads;                         
00263 }
00264 
00265 
00266 Segment3 Box::shortestSegmentBetween(const Transform& t, const Point3& p) const
00267 {
00268   array<Quad3> quads(asQuads());
00269   Real dist2 = consts::maxReal;
00270   Point3 closest;
00271   for(Int i=0; i<quads.size(); i++) {
00272     quads[i].transform(t);
00273     Point3 cp(quads[i].pointClosestTo(p));
00274     Real d2 = (p-cp).norm();
00275     if (d2 < dist2) {
00276       dist2 = d2;
00277       closest = cp;
00278     }
00279   }
00280   return Segment3(closest,p);
00281 }
00282 
00283 
00284 Segment3 Box::shortestSegmentBetween(const Transform& t, const Segment3& s) const
00285 {
00286   array<Quad3> quads(asQuads());
00287   Real dist2 = consts::maxReal;
00288   Segment3 shortest;
00289   for(Int i=0; i<quads.size(); i++) {
00290     quads[i].transform(t);
00291     Segment3 ss(quads[i].shortestSegmentBetween(s));
00292     Real d2 = ss.norm();
00293     if (d2 < dist2) {
00294       dist2 = d2;
00295       shortest = ss;
00296     }
00297   }
00298   return shortest;
00299 }
00300 
00301   
00302 Segment3 Box::shortestSegmentBetween(const Transform& t, const Triangle3& tri) const
00303 {
00304   array<Quad3> quads(asQuads());
00305   Real dist2 = consts::maxReal;
00306   Segment3 shortest;
00307   for(Int i=0; i<quads.size(); i++) {
00308     quads[i].transform(t);
00309     Segment3 ss(quads[i].shortestSegmentBetween(tri));
00310     Real d2 = ss.norm();
00311     if (d2 < dist2) {
00312       dist2 = d2;
00313       shortest = ss;
00314     }
00315   }
00316   return shortest;
00317 }
00318 
00319   
00320 Segment3 Box::shortestSegmentBetween(const Transform& t, const Quad3& q) const
00321 {
00322   array<Quad3> quads(asQuads());
00323   Real dist2 = consts::maxReal;
00324   Segment3 shortest;
00325   for(Int i=0; i<quads.size(); i++) {
00326     quads[i].transform(t);
00327     Segment3 ss(quads[i].shortestSegmentBetween(q));
00328     Real d2 = ss.norm();
00329     if (d2 < dist2) {
00330       dist2 = d2;
00331       shortest = ss;
00332     }
00333   }
00334   return shortest;
00335 }
00336 
00337   
00338 Segment3 Box::shortestSegmentBetween(const Transform& t1, ref<const Shape> s, const Transform& t2) const
00339 {
00340   Segment3 shortest;
00341   
00342   if (instanceof(*s, const Box)) {
00343     ref<const Box> b(narrow_ref<const Box>(s));
00344     
00345     array<Quad3> quads1(asQuads());
00346     array<Quad3> quads2(b->asQuads());
00347     for(Int i=0; i<quads1.size(); i++) quads1[i].transform(t1);
00348     for(Int i=0; i<quads2.size(); i++) quads2[i].transform(t2);
00349     
00350     Real dist2 = consts::maxReal;
00351     for(Int i1=0; i1<quads1.size(); i1++) {
00352       for(Int i2=0; i2<quads2.size(); i2++) {
00353         Segment3 ss(quads1[i1].shortestSegmentBetween(quads2[i2]));
00354         Real d2 = ss.norm();
00355         if (d2 < dist2) {
00356           dist2 = d2;
00357           shortest = ss;
00358         }
00359       }
00360     }
00361     
00362   } 
00363   else if (instanceof(*s, const Sphere)) {
00364     
00365     ref<const Sphere> sphere(narrow_ref<const Sphere>(s));
00366     // just find the shortest segment between the box and the center, then
00367     //  shorten it to the sphere surface
00368     // (doesn't handle case where they intersect properly)
00369     Point3 sphereCenter( t2.getTranslation() );
00370     shortest = Segment3( shortestSegmentBetween( t1, sphereCenter ) );
00371 
00372     Real r(sphere->radius());
00373     // shorten it by r on the e end
00374     Vector3 dir(shortest.e-shortest.s);
00375     shortest.e = shortest.s + dir*(1-(r/dir.length()));
00376     
00377   }
00378   else { // other shapes not yet implemented;
00379     Unimplemented; 
00380   }
00381   
00382   return shortest;
00383 }
00384  
00385 
00386 
00387 gfx::Point3 Box::support(const gfx::Vector3& v) const
00388 {
00389   return gfx::Point3( (v.x<0)?-(dim.x/2.0):(dim.x/2.0),
00390                       (v.y<0)?-(dim.y/2.0):(dim.y/2.0),
00391                       (v.z<0)?-(dim.z/2.0):(dim.z/2.0) );
00392 }
00393 
00394 
00395 base::ref<CollisionModel> Box::getCollisionModel(CollisionModel::CollisionModelType modelType) const
00396 {
00397   if ((collisionModel!=0) && 
00398       ((this->modelType==modelType) || (modelType==CollisionModel::AnyModel)))
00399     return collisionModel;
00400 
00401   collisionModel = Shape::getCollisionModel(modelType);
00402   this->modelType=modelType;
00403 
00404   return collisionModel;
00405 }
00406 
00407  
00408 void Box::serialize(base::Serializer& s)
00409 {
00410   s(dim.x,"x")(dim.y,"y")(dim.z,"z");
00411 
00412   if (s.isInput()) {
00413     massPropertiesCached = false;
00414     node = 0;
00415     collisionModel = ref<CollisionModel>(0);
00416   }
00417 }
00418 
00419 
00420 
00421 bool Box::formatSupported(String format, Real version, ExternalizationType type) const
00422 { 
00423   return ( (format=="xml") && (version==1.0) ); 
00424 }
00425 
00426 
00427 void Box::externalize(base::Externalizer& e, String format, Real version)
00428 {
00429   if (format == "") format = "xml";
00430                                                                                                                                                                                                     
00431   if (!formatSupported(format,version,e.ioType()))
00432     throw std::invalid_argument(Exception(String("format ")+format+" v"+base::realToString(version)+" unsupported"));
00433                                                                                                                                                                                                     
00434   if (e.isOutput()) {
00435 
00436     DOMElement*  boxElem = e.createElement("box");
00437     e.setElementAttribute(boxElem,"width",base::realToString(dim.x));
00438     e.setElementAttribute(boxElem,"height",base::realToString(dim.y));
00439     e.setElementAttribute(boxElem,"depth",base::realToString(dim.z));
00440     
00441     e.appendElement(boxElem);
00442   }
00443   else {
00444 
00445     massPropertiesCached = false;
00446     node = 0;
00447     collisionModel = ref<CollisionModel>(0);
00448 
00449     DOMNode* context = e.context();
00450     
00451     DOMElement* boxElem = e.getFirstElement(context, "box");
00452         
00453     dim.x = e.toReal( e.getDefaultedElementAttribute(boxElem, "width", "1") );
00454     dim.y = e.toReal( e.getDefaultedElementAttribute(boxElem, "height", "1") );
00455     dim.z = e.toReal( e.getDefaultedElementAttribute(boxElem, "depth", "1") );
00456     
00457     e.removeElement(boxElem);
00458     
00459   }
00460 }
00461 
00462 
00463 

Generated on Thu Jul 29 15:56:21 2004 for OpenSim by doxygen 1.3.6