00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
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
00073
00074
00075
00076
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
00087
00088 ref<Cache> cache = Application::getInstance()->universe()->cache();
00089 ref<VDirectory> d = cache->getCache(file->pathName());
00090 if (d->contains(file->name())) {
00091
00092
00093 BinarySerializer in(Serializer::Input, d->file(file->name()));
00094 in(*this);
00095
00096 }
00097 else {
00098
00099
00100
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
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
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
00130 Polyhedron::Polyhedron(const gfx::TriangleContainer& tris)
00131 : boundsCached(false), massPropertiesCached(false), node(0)
00132 {
00133
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
00202
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
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();
00304
00305 if (!(visualAttributes & Visual::ShowAxes))
00306 node = model;
00307 else {
00308
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
00338 const osg::BoundingSphere& bs = createOSGVisual(gfx::Visual::VerticesOnly)->getBound();
00339 Real radius = bs.radius();
00340 boundingSphere = BoundingSphere(bs.center(), radius);
00341
00342 boundingBox.setCenter(bs.center());
00343 boundingBox.setDimension(base::Dimension3(radius,radius,radius)*2.0);
00344
00345 boundsCached=true;
00346 }
00347
00348
00349
00350
00351
00352 ref<Polyhedron::Vertex> Polyhedron::vertex(const Point3& p)
00353 {
00354
00355
00356
00357
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
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
00376
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
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
00433
00434
00435
00436
00437 bool emptyModel = (model == 0);
00438 s(emptyModel);
00439
00440 if (!emptyModel) {
00441
00442 ref<VDirectory> tempDir = Application::getInstance()->filesystem()->temp();
00443
00444
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()) {
00460
00461 tempFile->close();
00462 osgDB::writeNodeFile( *model, tempFile->pathName().str().c_str() );
00463
00464
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
00474 Int osgModelSize = mbuf.size()-1;
00475 s(osgModelSize);
00476
00477 for(Int i=0; i<osgModelSize; i++)
00478 s(mbuf[i]);
00479 }
00480 else {
00481
00482 Int osgModelSize;
00483 s(osgModelSize);
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
00494 model = osgDB::readNodeFile( tempFile->pathName().str().c_str() );
00495
00496 tempDir->deleteFile( name );
00497 }
00498
00499 }
00500 else {
00501 if (s.isInput()) model = 0;
00502 }
00503
00504
00505 bool follow = s.followReferences(false);
00506
00507 s(verts)(edges)(polys);
00508 s.followReferences(follow);
00509
00510
00511
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
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
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