Bullet Collision Detection & Physics Library

btPolyhedralConvexShape.cpp

Go to the documentation of this file.
00001 /*
00002 Bullet Continuous Collision Detection and Physics Library
00003 Copyright (c) 2003-2009 Erwin Coumans  http://bulletphysics.org
00004 
00005 This software is provided 'as-is', without any express or implied warranty.
00006 In no event will the authors be held liable for any damages arising from the use of this software.
00007 Permission is granted to anyone to use this software for any purpose, 
00008 including commercial applications, and to alter it and redistribute it freely, 
00009 subject to the following restrictions:
00010 
00011 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
00012 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
00013 3. This notice may not be removed or altered from any source distribution.
00014 */
00015 
00016 #include "BulletCollision/CollisionShapes/btPolyhedralConvexShape.h"
00017 #include "btConvexPolyhedron.h"
00018 #include "LinearMath/btConvexHullComputer.h"
00019 #include <new>
00020 #include "LinearMath/btGeometryUtil.h"
00021 #include "LinearMath/btGrahamScan2dConvexHull.h"
00022 
00023 
00024 btPolyhedralConvexShape::btPolyhedralConvexShape() :btConvexInternalShape(),
00025 m_polyhedron(0)
00026 {
00027 
00028 }
00029 
00030 btPolyhedralConvexShape::~btPolyhedralConvexShape()
00031 {
00032         if (m_polyhedron)
00033         {
00034                 btAlignedFree(m_polyhedron);
00035         }
00036 }
00037 
00038 
00039 bool    btPolyhedralConvexShape::initializePolyhedralFeatures()
00040 {
00041 
00042         if (m_polyhedron)
00043                 btAlignedFree(m_polyhedron);
00044         
00045         void* mem = btAlignedAlloc(sizeof(btConvexPolyhedron),16);
00046         m_polyhedron = new (mem) btConvexPolyhedron;
00047 
00048                 btAlignedObjectArray<btVector3> orgVertices;
00049 
00050         for (int i=0;i<getNumVertices();i++)
00051         {
00052                 btVector3& newVertex = orgVertices.expand();
00053                 getVertex(i,newVertex);
00054         }
00055 
00056 #if 0
00057         btAlignedObjectArray<btVector3> planeEquations;
00058         btGeometryUtil::getPlaneEquationsFromVertices(orgVertices,planeEquations);
00059 
00060         btAlignedObjectArray<btVector3> shiftedPlaneEquations;
00061         for (int p=0;p<planeEquations.size();p++)
00062         {
00063                    btVector3 plane = planeEquations[p];
00064                    plane[3] -= getMargin();
00065                    shiftedPlaneEquations.push_back(plane);
00066         }
00067 
00068         btAlignedObjectArray<btVector3> tmpVertices;
00069 
00070         btGeometryUtil::getVerticesFromPlaneEquations(shiftedPlaneEquations,tmpVertices);
00071         btConvexHullComputer conv;
00072         conv.compute(&tmpVertices[0].getX(), sizeof(btVector3),tmpVertices.size(),0.f,0.f);
00073 
00074 #else
00075         btConvexHullComputer conv;
00076         conv.compute(&orgVertices[0].getX(), sizeof(btVector3),orgVertices.size(),0.f,0.f);
00077 
00078 #endif
00079 
00080 
00081 
00082         btAlignedObjectArray<btVector3> faceNormals;
00083         int numFaces = conv.faces.size();
00084         faceNormals.resize(numFaces);
00085         btConvexHullComputer* convexUtil = &conv;
00086 
00087         
00088         btAlignedObjectArray<btFace>    tmpFaces;
00089         tmpFaces.resize(numFaces);
00090 
00091         int numVertices = convexUtil->vertices.size();
00092         m_polyhedron->m_vertices.resize(numVertices);
00093         for (int p=0;p<numVertices;p++)
00094         {
00095                 m_polyhedron->m_vertices[p] = convexUtil->vertices[p];
00096         }
00097 
00098 
00099         for (int i=0;i<numFaces;i++)
00100         {
00101                 int face = convexUtil->faces[i];
00102                 //printf("face=%d\n",face);
00103                 const btConvexHullComputer::Edge*  firstEdge = &convexUtil->edges[face];
00104                 const btConvexHullComputer::Edge*  edge = firstEdge;
00105 
00106                 btVector3 edges[3];
00107                 int numEdges = 0;
00108                 //compute face normals
00109 
00110                 btScalar maxCross2 = 0.f;
00111                 int chosenEdge = -1;
00112 
00113                 do
00114                 {
00115                         
00116                         int src = edge->getSourceVertex();
00117                         tmpFaces[i].m_indices.push_back(src);
00118                         int targ = edge->getTargetVertex();
00119                         btVector3 wa = convexUtil->vertices[src];
00120 
00121                         btVector3 wb = convexUtil->vertices[targ];
00122                         btVector3 newEdge = wb-wa;
00123                         newEdge.normalize();
00124                         if (numEdges<2)
00125                                 edges[numEdges++] = newEdge;
00126 
00127                         edge = edge->getNextEdgeOfFace();
00128                 } while (edge!=firstEdge);
00129 
00130                 btScalar planeEq = 1e30f;
00131 
00132                 
00133                 if (numEdges==2)
00134                 {
00135                         faceNormals[i] = edges[0].cross(edges[1]);
00136                         faceNormals[i].normalize();
00137                         tmpFaces[i].m_plane[0] = faceNormals[i].getX();
00138                         tmpFaces[i].m_plane[1] = faceNormals[i].getY();
00139                         tmpFaces[i].m_plane[2] = faceNormals[i].getZ();
00140                         tmpFaces[i].m_plane[3] = planeEq;
00141 
00142                 }
00143                 else
00144                 {
00145                         btAssert(0);//degenerate?
00146                         faceNormals[i].setZero();
00147                 }
00148 
00149                 for (int v=0;v<tmpFaces[i].m_indices.size();v++)
00150                 {
00151                         btScalar eq = m_polyhedron->m_vertices[tmpFaces[i].m_indices[v]].dot(faceNormals[i]);
00152                         if (planeEq>eq)
00153                         {
00154                                 planeEq=eq;
00155                         }
00156                 }
00157                 tmpFaces[i].m_plane[3] = -planeEq;
00158         }
00159 
00160         //merge coplanar faces and copy them to m_polyhedron
00161 
00162         btScalar faceWeldThreshold= 0.999f;
00163         btAlignedObjectArray<int> todoFaces;
00164         for (int i=0;i<tmpFaces.size();i++)
00165                 todoFaces.push_back(i);
00166 
00167         while (todoFaces.size())
00168         {
00169                 btAlignedObjectArray<int> coplanarFaceGroup;
00170                 int refFace = todoFaces[todoFaces.size()-1];
00171 
00172                 coplanarFaceGroup.push_back(refFace);
00173                 btFace& faceA = tmpFaces[refFace];
00174                 todoFaces.pop_back();
00175 
00176                 btVector3 faceNormalA(faceA.m_plane[0],faceA.m_plane[1],faceA.m_plane[2]);
00177                 for (int j=todoFaces.size()-1;j>=0;j--)
00178                 {
00179                         int i = todoFaces[j];
00180                         btFace& faceB = tmpFaces[i];
00181                         btVector3 faceNormalB(faceB.m_plane[0],faceB.m_plane[1],faceB.m_plane[2]);
00182                         if (faceNormalA.dot(faceNormalB)>faceWeldThreshold)
00183                         {
00184                                 coplanarFaceGroup.push_back(i);
00185                                 todoFaces.remove(i);
00186                         }
00187                 }
00188 
00189 
00190                 bool did_merge = false;
00191                 if (coplanarFaceGroup.size()>1)
00192                 {
00193                         //do the merge: use Graham Scan 2d convex hull
00194 
00195                         btAlignedObjectArray<GrahamVector2> orgpoints;
00196 
00197                         for (int i=0;i<coplanarFaceGroup.size();i++)
00198                         {
00199 //                              m_polyhedron->m_faces.push_back(tmpFaces[coplanarFaceGroup[i]]);
00200 
00201                                 btFace& face = tmpFaces[coplanarFaceGroup[i]];
00202                                 btVector3 faceNormal(face.m_plane[0],face.m_plane[1],face.m_plane[2]);
00203                                 btVector3 xyPlaneNormal(0,0,1);
00204 
00205                                 btQuaternion rotationArc = shortestArcQuat(faceNormal,xyPlaneNormal);
00206                                 
00207                                 for (int f=0;f<face.m_indices.size();f++)
00208                                 {
00209                                         int orgIndex = face.m_indices[f];
00210                                         btVector3 pt = m_polyhedron->m_vertices[orgIndex];
00211                                         btVector3 rotatedPt =  quatRotate(rotationArc,pt);
00212                                         rotatedPt.setZ(0);
00213                                         bool found = false;
00214 
00215                                         for (int i=0;i<orgpoints.size();i++)
00216                                         {
00217                                                 //if ((orgpoints[i].m_orgIndex == orgIndex) || ((rotatedPt-orgpoints[i]).length2()<0.0001))
00218                                                 if (orgpoints[i].m_orgIndex == orgIndex)
00219                                                 {
00220                                                         found=true;
00221                                                         break;
00222                                                 }
00223                                         }
00224                                         if (!found)
00225                                                 orgpoints.push_back(GrahamVector2(rotatedPt,orgIndex));
00226                                 }
00227                         }
00228 
00229                         btFace combinedFace;
00230                         for (int i=0;i<4;i++)
00231                                 combinedFace.m_plane[i] = tmpFaces[coplanarFaceGroup[0]].m_plane[i];
00232 
00233                         btAlignedObjectArray<GrahamVector2> hull;
00234                         GrahamScanConvexHull2D(orgpoints,hull);
00235 
00236                         for (int i=0;i<hull.size();i++)
00237                         {
00238                                 combinedFace.m_indices.push_back(hull[i].m_orgIndex);
00239                                 for(int k = 0; k < orgpoints.size(); k++) {
00240                                         if(orgpoints[k].m_orgIndex == hull[i].m_orgIndex) {
00241                                                 orgpoints[k].m_orgIndex = -1; // invalidate...
00242                                                 break;
00243                         }
00244                                 }
00245                         }
00246                         // are there rejected vertices?
00247                         bool reject_merge = false;
00248                         for(int i = 0; i < orgpoints.size(); i++) {
00249                                 if(orgpoints[i].m_orgIndex == -1)
00250                                         continue; // this is in the hull...
00251                                 // this vertex is rejected -- is anybody else using this vertex?
00252                                 for(int j = 0; j < tmpFaces.size(); j++) {
00253                                         btFace& face = tmpFaces[j];
00254                                         // is this a face of the current coplanar group?
00255                                         bool is_in_current_group = false;
00256                                         for(int k = 0; k < coplanarFaceGroup.size(); k++) {
00257                                                 if(coplanarFaceGroup[k] == j) {
00258                                                         is_in_current_group = true;
00259                                                         break;
00260                                                 }
00261                                         }
00262                                         if(is_in_current_group) // ignore this face...
00263                                                 continue;
00264                                         // does this face use this rejected vertex?
00265                                         for(int v = 0; v < face.m_indices.size(); v++) {
00266                                                 if(face.m_indices[v] == orgpoints[i].m_orgIndex) {
00267                                                         // this rejected vertex is used in another face -- reject merge
00268                                                         reject_merge = true;
00269                                                         break;
00270                                                 }
00271                                         }
00272                                         if(reject_merge)
00273                                                 break;
00274                                 }
00275                                 if(reject_merge)
00276                                         break;
00277                         }
00278                         if(!reject_merge) {
00279                                 // do this merge!
00280                                 did_merge = true;
00281                         m_polyhedron->m_faces.push_back(combinedFace);
00282                         }
00283                 }
00284                 if(!did_merge)
00285                 {
00286                         for (int i=0;i<coplanarFaceGroup.size();i++)
00287                         {
00288                                 m_polyhedron->m_faces.push_back(tmpFaces[coplanarFaceGroup[i]]);
00289                         }
00290 
00291                 }
00292 
00293 
00294 
00295         }
00296         
00297         m_polyhedron->initialize();
00298 
00299         return true;
00300 }
00301 
00302 
00303 btVector3       btPolyhedralConvexShape::localGetSupportingVertexWithoutMargin(const btVector3& vec0)const
00304 {
00305 
00306 
00307         btVector3 supVec(0,0,0);
00308 #ifndef __SPU__
00309         int i;
00310         btScalar maxDot(btScalar(-BT_LARGE_FLOAT));
00311 
00312         btVector3 vec = vec0;
00313         btScalar lenSqr = vec.length2();
00314         if (lenSqr < btScalar(0.0001))
00315         {
00316                 vec.setValue(1,0,0);
00317         } else
00318         {
00319                 btScalar rlen = btScalar(1.) / btSqrt(lenSqr );
00320                 vec *= rlen;
00321         }
00322 
00323         btVector3 vtx;
00324         btScalar newDot;
00325 
00326         for (i=0;i<getNumVertices();i++)
00327         {
00328                 getVertex(i,vtx);
00329                 newDot = vec.dot(vtx);
00330                 if (newDot > maxDot)
00331                 {
00332                         maxDot = newDot;
00333                         supVec = vtx;
00334                 }
00335         }
00336 
00337         
00338 #endif //__SPU__
00339         return supVec;
00340 }
00341 
00342 
00343 
00344 void    btPolyhedralConvexShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const
00345 {
00346 #ifndef __SPU__
00347         int i;
00348 
00349         btVector3 vtx;
00350         btScalar newDot;
00351 
00352         for (i=0;i<numVectors;i++)
00353         {
00354                 supportVerticesOut[i][3] = btScalar(-BT_LARGE_FLOAT);
00355         }
00356 
00357         for (int j=0;j<numVectors;j++)
00358         {
00359         
00360                 const btVector3& vec = vectors[j];
00361 
00362                 for (i=0;i<getNumVertices();i++)
00363                 {
00364                         getVertex(i,vtx);
00365                         newDot = vec.dot(vtx);
00366                         if (newDot > supportVerticesOut[j][3])
00367                         {
00368                                 //WARNING: don't swap next lines, the w component would get overwritten!
00369                                 supportVerticesOut[j] = vtx;
00370                                 supportVerticesOut[j][3] = newDot;
00371                         }
00372                 }
00373         }
00374 #endif //__SPU__
00375 }
00376 
00377 
00378 
00379 void    btPolyhedralConvexShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const
00380 {
00381 #ifndef __SPU__
00382         //not yet, return box inertia
00383 
00384         btScalar margin = getMargin();
00385 
00386         btTransform ident;
00387         ident.setIdentity();
00388         btVector3 aabbMin,aabbMax;
00389         getAabb(ident,aabbMin,aabbMax);
00390         btVector3 halfExtents = (aabbMax-aabbMin)*btScalar(0.5);
00391 
00392         btScalar lx=btScalar(2.)*(halfExtents.x()+margin);
00393         btScalar ly=btScalar(2.)*(halfExtents.y()+margin);
00394         btScalar lz=btScalar(2.)*(halfExtents.z()+margin);
00395         const btScalar x2 = lx*lx;
00396         const btScalar y2 = ly*ly;
00397         const btScalar z2 = lz*lz;
00398         const btScalar scaledmass = mass * btScalar(0.08333333);
00399 
00400         inertia = scaledmass * (btVector3(y2+z2,x2+z2,x2+y2));
00401 #endif //__SPU__
00402 }
00403 
00404 
00405 
00406 void    btPolyhedralConvexAabbCachingShape::setLocalScaling(const btVector3& scaling)
00407 {
00408         btConvexInternalShape::setLocalScaling(scaling);
00409         recalcLocalAabb();
00410 }
00411 
00412 btPolyhedralConvexAabbCachingShape::btPolyhedralConvexAabbCachingShape()
00413 :btPolyhedralConvexShape(),
00414 m_localAabbMin(1,1,1),
00415 m_localAabbMax(-1,-1,-1),
00416 m_isLocalAabbValid(false)
00417 {
00418 }
00419 
00420 void btPolyhedralConvexAabbCachingShape::getAabb(const btTransform& trans,btVector3& aabbMin,btVector3& aabbMax) const
00421 {
00422         getNonvirtualAabb(trans,aabbMin,aabbMax,getMargin());
00423 }
00424 
00425 void    btPolyhedralConvexAabbCachingShape::recalcLocalAabb()
00426 {
00427         m_isLocalAabbValid = true;
00428         
00429         #if 1
00430         static const btVector3 _directions[] =
00431         {
00432                 btVector3( 1.,  0.,  0.),
00433                 btVector3( 0.,  1.,  0.),
00434                 btVector3( 0.,  0.,  1.),
00435                 btVector3( -1., 0.,  0.),
00436                 btVector3( 0., -1.,  0.),
00437                 btVector3( 0.,  0., -1.)
00438         };
00439         
00440         btVector3 _supporting[] =
00441         {
00442                 btVector3( 0., 0., 0.),
00443                 btVector3( 0., 0., 0.),
00444                 btVector3( 0., 0., 0.),
00445                 btVector3( 0., 0., 0.),
00446                 btVector3( 0., 0., 0.),
00447                 btVector3( 0., 0., 0.)
00448         };
00449         
00450         batchedUnitVectorGetSupportingVertexWithoutMargin(_directions, _supporting, 6);
00451         
00452         for ( int i = 0; i < 3; ++i )
00453         {
00454                 m_localAabbMax[i] = _supporting[i][i] + m_collisionMargin;
00455                 m_localAabbMin[i] = _supporting[i + 3][i] - m_collisionMargin;
00456         }
00457         
00458         #else
00459 
00460         for (int i=0;i<3;i++)
00461         {
00462                 btVector3 vec(btScalar(0.),btScalar(0.),btScalar(0.));
00463                 vec[i] = btScalar(1.);
00464                 btVector3 tmp = localGetSupportingVertex(vec);
00465                 m_localAabbMax[i] = tmp[i];
00466                 vec[i] = btScalar(-1.);
00467                 tmp = localGetSupportingVertex(vec);
00468                 m_localAabbMin[i] = tmp[i];
00469         }
00470         #endif
00471 }
00472 
00473 
00474 
00475