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

physics/Polyhedron.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: Polyhedron.cpp 1031 2004-02-11 20:46:36Z jungd $
00019  
00020 ****************************************************************************/
00021 
00022 #include <physics/Polyhedron>
00023 
00024 #include <base/Application>
00025 #include <base/File>
00026 #include <base/VDirectory>
00027 #include <base/BinarySerializer>
00028 #include <base/Cache>
00029 #include <base/Dimension3>
00030 #include <base/io_error>
00031 #include <base/Externalizer>
00032 #include <gfx/VisualTriangles>
00033 #include <gfx/TriangleIterator>
00034 #include <gfx/Triangle3>
00035 #include <physics/Material>
00036 //#include <physics/OBBCollisionModel>
00037 #include <physics/GJKCollisionModel>
00038 
00039 
00040 #include <osgDB/ReadFile>
00041 #include <osgDB/WriteFile>
00042 #include <osg/Group>
00043 #include <osg/Geode>
00044 #include <osg/ShapeDrawable>
00045 
00046 using physics::Polyhedron;
00047 
00048 using base::Application;
00049 using base::File;
00050 using base::VFile;
00051 using base::VDirectory;
00052 using base::Serializer;
00053 using base::BinarySerializer;
00054 using base::Cache;
00055 using base::reflist;
00056 using gfx::VisualTriangles;
00057 using gfx::Segment3;
00058 using physics::BoundingBox;
00059 using physics::BoundingSphere;
00060 using physics::MassProperties;
00061 using physics::Material;
00062 using physics::CollisionModel;
00063 
00064 using osg::Group;
00065 using osg::Vec3;
00066 
00067 
00068 
00069 const Real coordEps = 1e-10;
00070 
00071 
00072 /// \todo consider building the geometry on demand, rather than
00073 /// always building and copying it around. Perhaps seperate it out
00074 /// into a different class for representation.  So we can just construct
00075 /// winged-edge if needed (e.g. after convex hull conversion of splitting
00076 /// into convex parts, for example)
00077 Polyhedron::Polyhedron() 
00078   : boundsCached(false), massPropertiesCached(false),
00079     model(0), node(0), collisionModel(0) 
00080 {
00081 }
00082 
00083 Polyhedron::Polyhedron(ref<base::VFile> file) throw(std::invalid_argument, base::io_error)
00084   : boundsCached(false), massPropertiesCached(false)
00085 {
00086   // First see if the osg model & polyhedron geometry data has
00087   //  been cached for this file
00088   ref<Cache> cache = Application::getInstance()->universe()->cache();
00089   ref<VDirectory> d = cache->getCache(file->pathName());
00090   if (d->contains(file->name())) { // cached
00091 
00092     // Deserialize from cache file
00093     BinarySerializer in(Serializer::Input, d->file(file->name()));
00094     in(*this);
00095 
00096   }
00097   else { // not cached, build geometry & cache it
00098 
00099     // Load OSG model
00100     //  OSG doesn't support reading from a stream, only a real file
00101     if (instanceof(*file,File)) {
00102       try {
00103         model = osgDB::readNodeFile( file->pathName().str().c_str() );
00104       } catch (std::exception&) {
00105         model = 0;
00106       }
00107       if (model==0)
00108         throw std::runtime_error(Exception("Error loading model file "+file->pathName().str()));
00109 
00110       shapeHasAppearance = true;
00111       
00112       // build geometry from OSG model's Visual
00113       Logln("Building Polyhedron data-structure from " << file->name().str());
00114       buildGeometry(VisualTriangles(*this));
00115     }
00116     else
00117       throw std::invalid_argument(Exception("Can only load from standard Unix files.  Sorry"));
00118 
00119     // Serialize to cache file
00120     ref<VFile> cacheFile = d->createFile(file->name());
00121     BinarySerializer out(Serializer::Output, cacheFile);
00122     out(*this);
00123     out.flush();
00124     cacheFile->close();
00125   }
00126 
00127 }
00128 
00129 /// \todo test (normals?, mesh->setIncides() - yes indices needed, implement)
00130 Polyhedron::Polyhedron(const gfx::TriangleContainer& tris)
00131   : boundsCached(false), massPropertiesCached(false), node(0)
00132 {
00133   // Put triangles into a model (OSGVisual only for now)
00134    osg::TriangleMesh* mesh = new osg::TriangleMesh();
00135 
00136    array<Vec3>& coords = *new array<Vec3>(0,128);
00137    array<Vec3>& normals = *new array<Vec3>(0,128);
00138    gfx::TriangleContainer::const_iterator i = tris.begin();
00139    gfx::TriangleContainer::const_iterator end = tris.end();
00140    while (i != end) {
00141      const gfx::Triangle3& t(*i);
00142      coords.push_back(t(1).toVec3());
00143      coords.push_back(t(2).toVec3());
00144      coords.push_back(t(3).toVec3());
00145      base::Vector3 n(t.normal());
00146      n.normalize();
00147      normals.push_back(n.toVec3());
00148      ++i;
00149    }
00150    coords.trim();
00151    normals.trim();
00152 
00153    
00154    osg::Vec3Array* v = new osg::Vec3Array(coords.size());
00155    for(Int i=0; i<coords.size(); i++)
00156      (*v)[i] = coords[i];
00157    mesh->setVertices(v);
00158    
00159    osg::Geode* geode = new osg::Geode();
00160    geode->setName("Polyhedron(TriangleContainer)");
00161    geode->addDrawable(new osg::ShapeDrawable(mesh));
00162    model = geode;
00163 
00164    buildGeometry(tris);
00165 }
00166 
00167 Polyhedron::Polyhedron(osg::Node& n)
00168   : boundsCached(false), massPropertiesCached(false)
00169 {
00170   model = &n;
00171   buildGeometry(VisualTriangles(*this));
00172 }
00173 
00174 
00175 Polyhedron::Polyhedron(const Polyhedron& p)
00176   : ComplexShape(p), 
00177     boundsCached(false), massPropertiesCached(false), 
00178     verts(p.verts), edges(p.edges), polys(p.polys),
00179     model(model)
00180 {
00181 }
00182 
00183 
00184 Polyhedron::Polyhedron(const Shape& s)
00185   : Shape(s), 
00186     boundsCached(true), 
00187     boundingBox(s.getBoundingBox()), boundingSphere(s.getBoundingSphere()),
00188     massPropertiesCached(false)
00189 {
00190   if (s.visualTypeSupported(OSGVisual)) {
00191     model = s.createOSGVisual();
00192     buildGeometry(VisualTriangles(*this));
00193   }
00194   else
00195     throw std::invalid_argument(Exception("Shape must support OSGVisual"));
00196 }
00197 
00198 
00199 Polyhedron::~Polyhedron()
00200 {
00201   // The geometry structures contain circular references, so we must
00202   //  break the links so that they will be reclaimed properly
00203   VertexList::iterator v = verts.begin();
00204   VertexList::iterator vend = verts.end();
00205   while (v != vend) {
00206     (*v)->edges.clear();
00207     ++v;
00208   }  
00209 
00210   EdgeList::iterator ei = edges.begin();
00211   EdgeList::iterator eend = edges.end();
00212   while (ei != eend) {
00213     (*ei)->v1 = ref<Vertex>(0);
00214     (*ei)->v2 = ref<Vertex>(0);
00215     (*ei)->poly1 = ref<Polygon>(0);
00216     (*ei)->poly2 = ref<Polygon>(0);
00217     ++ei;
00218   }
00219 
00220   PolygonList::iterator p = polys.begin();
00221   PolygonList::iterator pend = polys.begin();
00222   while (p != pend) {
00223     (*p)->edges.clear();
00224     ++p;
00225   }
00226 }
00227 
00228 
00229 
00230 
00231 const MassProperties& Polyhedron::getMassProperties(ref<const Material> material) const
00232 { 
00233   if (massPropertiesCached && (density == material->density()))
00234     return massProperties;
00235 
00236   density = material->density();
00237   massProperties = MassProperties(VisualTriangles(*this),material);
00238 
00239   massPropertiesCached = true;
00240   return massProperties;
00241 }
00242 
00243 
00244 
00245 Segment3 Polyhedron::shortestSegmentBetween(const base::Transform& t, const Point3& p) const
00246 {
00247   Unimplemented;
00248 }
00249 
00250 
00251 Segment3 Polyhedron::shortestSegmentBetween(const base::Transform& t, const gfx::Segment3& s) const
00252 {
00253   Unimplemented;
00254 }
00255 
00256 
00257 Segment3 Polyhedron::shortestSegmentBetween(const base::Transform& t, const gfx::Triangle3& tri) const
00258 {
00259   Unimplemented;
00260 }
00261 
00262 
00263 Segment3 Polyhedron::shortestSegmentBetween(const base::Transform& t, const gfx::Quad3& q) const
00264 {
00265   Unimplemented;
00266 }
00267 
00268 
00269 Segment3 Polyhedron::shortestSegmentBetween(const base::Transform& t1, ref<const Shape> s, const base::Transform& t2) const
00270 {
00271   Unimplemented;
00272 }
00273 
00274 
00275 
00276 
00277 // CollisionModelProvider
00278 base::ref<CollisionModel> Polyhedron::getCollisionModel(CollisionModel::CollisionModelType modelType) const
00279 {
00280   if ((collisionModel!=0) && 
00281       ((this->modelType==modelType) || (modelType==CollisionModel::AnyModel)))
00282     return collisionModel;
00283   
00284   collisionModel = Shape::getCollisionModel(modelType);
00285   this->modelType=modelType;
00286 
00287   return collisionModel;
00288 }
00289 
00290 
00291 
00292 
00293 
00294 
00295 
00296 
00297 
00298 osg::Node* Polyhedron::createOSGVisual(Attributes visualAttributes) const
00299 {
00300   if ((node!=0) && (visualAttributes==attributes))
00301     return &(*node);
00302 
00303   if (model==0) return new osg::Group(); // empty
00304 
00305   if (!(visualAttributes & Visual::ShowAxes)) 
00306     node = model;
00307   else {
00308     // create axes 
00309     Group* group = new Group();
00310     group->addChild( &(*model) );
00311     group->addChild( createOSGAxes(getBoundingBox().getDimension()/2.0) );
00312     node = group;
00313   }
00314 
00315   attributes = visualAttributes;
00316   return &(*node);
00317 }
00318 
00319 
00320 BoundingBox Polyhedron::getBoundingBox() const
00321 {
00322   if (!boundsCached)
00323     computeBounds();
00324   return boundingBox;
00325 }
00326 
00327 BoundingSphere Polyhedron::getBoundingSphere() const
00328 {
00329   if (!boundsCached)
00330     computeBounds();
00331   return boundingSphere;
00332 }
00333 
00334 
00335 void Polyhedron::computeBounds() const
00336 {
00337   // Let OSG calculate the BoundingSphere of the visual
00338   const osg::BoundingSphere& bs = createOSGVisual(gfx::Visual::VerticesOnly)->getBound();
00339   Real radius = bs.radius();
00340   boundingSphere = BoundingSphere(bs.center(), radius);
00341   // Now calculate bounding box to enclose the sphere
00342   boundingBox.setCenter(bs.center());
00343   boundingBox.setDimension(base::Dimension3(radius,radius,radius)*2.0);
00344 
00345   boundsCached=true;
00346 }
00347 
00348 
00349 
00350 // methods for building the geometric model
00351 
00352 ref<Polyhedron::Vertex> Polyhedron::vertex(const Point3& p)
00353 {
00354   // search backward through existing vertices
00355   // (for most models existing vertices
00356   //  that are referenced tend to be ones that have been
00357   //  encountered reciently)
00358   VertexList::reverse_iterator v = verts.rbegin();
00359   VertexList::reverse_iterator end = verts.rend();
00360   while (v != end) {
00361     if ((*v)->coord.equals(p, coordEps))
00362       return (*v);
00363     ++v;
00364   }
00365 
00366   // not found, so create a new vertex
00367   ref<Vertex> vert(NewObj Vertex(p));
00368   verts.push_back(vert);
00369   return vert;
00370 }
00371 
00372 
00373 ref<Polyhedron::Edge> Polyhedron::edge(ref<Vertex> v1, ref<Vertex> v2)
00374 {
00375   // if edge v1-v2 is preexisting, then it should be in v1's list of
00376   //  edges (or v2)
00377   EdgeList::const_iterator ei = v1->edges_begin();
00378   EdgeList::const_iterator end = v1->edges_end();
00379   while (ei != end) {
00380     ref<Edge> e(*ei); 
00381     if (   ((e->v1 == v1) && (e->v2 == v2))
00382         || ((e->v1 == v2) && (e->v2 == v1)) )
00383       return e;
00384     ++ei;
00385   }
00386 
00387   // wasn't there, so create a new edge
00388   ref<Edge> edge(NewObj Edge(v1,v2));
00389   v1->edges.push_back(edge);
00390   v2->edges.push_back(edge);
00391   edges.push_back(edge);
00392   return edge;
00393 }
00394 
00395 
00396 
00397 void Polyhedron::buildGeometry(const gfx::TriangleContainer& tris)
00398 {
00399   gfx::TriangleContainer::const_iterator i = tris.begin();
00400   gfx::TriangleContainer::const_iterator end = tris.end();
00401 
00402   while (i != end) {
00403     const gfx::Triangle3& t(*i);
00404 
00405     ref<Vertex> v1 = vertex(t[0]);
00406     ref<Vertex> v2 = vertex(t[1]);
00407     ref<Vertex> v3 = vertex(t[2]);
00408     
00409     ref<Edge> e1 = edge(v1, v2);
00410     ref<Edge> e2 = edge(v2, v3);
00411     ref<Edge> e3 = edge(v3, v1);
00412     
00413     ref<Polygon> poly(NewObj Polygon());
00414     poly->addEdge(e1);
00415     poly->addEdge(e2);
00416     poly->addEdge(e3);
00417 
00418     e1->addPoly(poly);
00419     e2->addPoly(poly);
00420     e3->addPoly(poly);
00421     
00422     polys.push_back(poly);
00423     
00424     ++i;
00425   }
00426 
00427 }
00428 
00429 
00430 void Polyhedron::serialize(base::Serializer& s)
00431 {
00432   // first serialize the OSG model
00433   //  (currently the only way to do that with OSG is to write it to
00434   //    a file, then copy the file to the serialization stream.
00435   //    The reverse for input)
00436 
00437   bool emptyModel = (model == 0);
00438   s(emptyModel);
00439 
00440   if (!emptyModel) {
00441 
00442     ref<VDirectory> tempDir = Application::getInstance()->filesystem()->temp();
00443     // create a file "polyhedronN.osg" where N is the first Int such that the
00444     //  name is available
00445     Int pn = 0;
00446     ref<VFile> tempFile;
00447     String name;
00448     do {
00449       name = String("polyhedron")+base::intToString(pn)+".osg";
00450       try {
00451         tempFile = tempDir->createFile( name );
00452       } catch (base::io_error&) {
00453         tempFile = ref<VFile>(0);
00454         pn++;
00455       }
00456     } while (tempFile == 0);
00457 
00458     
00459     if (s.isOutput()) { // Output
00460       // write model to tmpFile
00461       tempFile->close();
00462       osgDB::writeNodeFile( *model, tempFile->pathName().str().c_str() );
00463 
00464       // copy all the bytes from tmpFile to a memory buffer (we need the size in advance)
00465       array<char> mbuf(0,32768);
00466       std::istream& in = tempFile->istream();
00467       while (in.good()) {
00468         mbuf.at(mbuf.size()) = in.get();
00469       }
00470       tempFile->close();
00471       tempDir->deleteFile( name );
00472 
00473       // output size to s
00474       Int osgModelSize = mbuf.size()-1; // size (bytes)
00475       s(osgModelSize);
00476       // an the buffer
00477       for(Int i=0; i<osgModelSize; i++)
00478         s(mbuf[i]);
00479     }
00480     else { // Input
00481       // read osg data from s and write it to tmpFile
00482       Int osgModelSize;
00483       s(osgModelSize); // read size (bytes)
00484 
00485       std::ostream& out = tempFile->ostream();
00486       char c;
00487       for(Int i=0; i<osgModelSize; i++) {
00488         s(c);
00489         out << c;
00490       } 
00491       tempFile->close();
00492       
00493       // now ask OSG to read tmpFile into a model
00494       model = osgDB::readNodeFile( tempFile->pathName().str().c_str() );
00495 
00496       tempDir->deleteFile( name );
00497     }
00498 
00499   }
00500   else { // emptyModel
00501     if (s.isInput()) model = 0;
00502   }
00503 
00504   // finally, now serialize the polyhedron geometry data
00505   bool follow = s.followReferences(false);
00506 
00507   s(verts)(edges)(polys);
00508   s.followReferences(follow);
00509   
00510 
00511   // zero out cached data
00512   if (s.isInput()) {
00513     boundsCached = massPropertiesCached = 0;
00514     node = 0;
00515     collisionModel = ref<CollisionModel>(0);
00516   }
00517 
00518 }
00519 
00520 
00521 
00522 
00523 void Polyhedron::getAdjacentVertices(const Point3& v, array<Point3>& adjacent) const
00524 {
00525   /*
00526   adjacent.clear();
00527   Int vi;
00528   for(vi=0; vi<verts.size(); vi++) {
00529     if (verts[vi].coord.equals(v,coordEps)) 
00530       break;
00531   }
00532   if (vi==verts.size()) return;
00533 
00534   // for each edge
00535   array<Int>::const_iterator ei = verts[vi].edges.begin();
00536   array<Int>::const_iterator end = verts[vi].edges.end();
00537   while (ei != end) {
00538     const Edge& e(edges[*ei]);
00539     if (e.vi1 != vi)
00540       adjacent.push_back(verts[e.vi1].coord);
00541     else
00542       adjacent.push_back(verts[e.vi2].coord);
00543     ++ei;
00544   }
00545   */
00546   Unimplemented;
00547 }
00548 
00549 
00550 
00551 
00552 bool Polyhedron::formatSupported(String format, Real version, ExternalizationType type) const
00553 { 
00554   return ( (format=="xml") && (version==1.0) ); 
00555 }
00556 
00557 
00558 void Polyhedron::externalize(base::Externalizer& e, String format, Real version)
00559 {
00560   if (format == "") format = "xml";
00561                                                                                                                                                                                                     
00562   if (!formatSupported(format,version,e.ioType()))
00563     throw std::invalid_argument(Exception(String("format ")+format+" v"+base::realToString(version)+" unsupported"));
00564                                                                                                                                                                                                     
00565   if (e.isOutput()) {
00566     Unimplemented;                                                                                                                                                                                                 
00567   }
00568   else {
00569     Unimplemented;                                                                                                                                                                                                 
00570   }
00571 }
00572 
00573 

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