Bullet Collision Detection & Physics Library
btPolyhedralConvexShape.cpp
Go to the documentation of this file.
1 /*
2 Bullet Continuous Collision Detection and Physics Library
3 Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org
4 
5 This software is provided 'as-is', without any express or implied warranty.
6 In no event will the authors be held liable for any damages arising from the use of this software.
7 Permission is granted to anyone to use this software for any purpose,
8 including commercial applications, and to alter it and redistribute it freely,
9 subject to the following restrictions:
10 
11 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.
12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 3. This notice may not be removed or altered from any source distribution.
14 */
15 #if defined (_WIN32) || defined (__i386__)
16 #define BT_USE_SSE_IN_API
17 #endif
18 
20 #include "btConvexPolyhedron.h"
22 #include <new>
25 
26 
28 m_polyhedron(0)
29 {
30 
31 }
32 
34 {
35  if (m_polyhedron)
36  {
39  }
40 }
41 
43 {
44  if (m_polyhedron)
45  {
46  *m_polyhedron = polyhedron;
47  } else
48  {
49  void* mem = btAlignedAlloc(sizeof(btConvexPolyhedron),16);
50  m_polyhedron = new (mem) btConvexPolyhedron(polyhedron);
51  }
52 }
53 
55 {
56 
57  if (m_polyhedron)
58  {
61  }
62 
63  void* mem = btAlignedAlloc(sizeof(btConvexPolyhedron),16);
64  m_polyhedron = new (mem) btConvexPolyhedron;
65 
67 
68  for (int i=0;i<getNumVertices();i++)
69  {
70  btVector3& newVertex = orgVertices.expand();
71  getVertex(i,newVertex);
72  }
73 
75 
76  if (shiftVerticesByMargin)
77  {
78  btAlignedObjectArray<btVector3> planeEquations;
79  btGeometryUtil::getPlaneEquationsFromVertices(orgVertices,planeEquations);
80 
81  btAlignedObjectArray<btVector3> shiftedPlaneEquations;
82  for (int p=0;p<planeEquations.size();p++)
83  {
84  btVector3 plane = planeEquations[p];
85  // btScalar margin = getMargin();
86  plane[3] -= getMargin();
87  shiftedPlaneEquations.push_back(plane);
88  }
89 
91 
92  btGeometryUtil::getVerticesFromPlaneEquations(shiftedPlaneEquations,tmpVertices);
93 
94  conv.compute(&tmpVertices[0].getX(), sizeof(btVector3),tmpVertices.size(),0.f,0.f);
95  } else
96  {
97 
98  conv.compute(&orgVertices[0].getX(), sizeof(btVector3),orgVertices.size(),0.f,0.f);
99  }
100 
101 #ifndef BT_RECONSTRUCT_FACES
102 
103  int numVertices = conv.vertices.size();
104  m_polyhedron->m_vertices.resize(numVertices);
105  for (int p=0;p<numVertices;p++)
106  {
107  m_polyhedron->m_vertices[p] = conv.vertices[p];
108  }
109 
110  int v0, v1;
111  for (int j = 0; j < conv.faces.size(); j++)
112  {
113  btVector3 edges[3];
114  int numEdges = 0;
115  btFace combinedFace;
116  const btConvexHullComputer::Edge* edge = &conv.edges[conv.faces[j]];
117  v0 = edge->getSourceVertex();
118  int prevVertex=v0;
119  combinedFace.m_indices.push_back(v0);
120  v1 = edge->getTargetVertex();
121  while (v1 != v0)
122  {
123 
124  btVector3 wa = conv.vertices[prevVertex];
125  btVector3 wb = conv.vertices[v1];
126  btVector3 newEdge = wb-wa;
127  newEdge.normalize();
128  if (numEdges<2)
129  edges[numEdges++] = newEdge;
130 
131 
132  //face->addIndex(v1);
133  combinedFace.m_indices.push_back(v1);
134  edge = edge->getNextEdgeOfFace();
135  prevVertex = v1;
136  int v01 = edge->getSourceVertex();
137  v1 = edge->getTargetVertex();
138 
139  }
140 
141  btAssert(combinedFace.m_indices.size() > 2);
142 
143  btVector3 faceNormal = edges[0].cross(edges[1]);
144  faceNormal.normalize();
145 
146  btScalar planeEq=1e30f;
147 
148  for (int v=0;v<combinedFace.m_indices.size();v++)
149  {
150  btScalar eq = m_polyhedron->m_vertices[combinedFace.m_indices[v]].dot(faceNormal);
151  if (planeEq>eq)
152  {
153  planeEq=eq;
154  }
155  }
156  combinedFace.m_plane[0] = faceNormal.getX();
157  combinedFace.m_plane[1] = faceNormal.getY();
158  combinedFace.m_plane[2] = faceNormal.getZ();
159  combinedFace.m_plane[3] = -planeEq;
160 
161  m_polyhedron->m_faces.push_back(combinedFace);
162  }
163 
164 
165 #else//BT_RECONSTRUCT_FACES
166 
168  int numFaces = conv.faces.size();
169  faceNormals.resize(numFaces);
170  btConvexHullComputer* convexUtil = &conv;
171 
172 
174  tmpFaces.resize(numFaces);
175 
176  int numVertices = convexUtil->vertices.size();
177  m_polyhedron->m_vertices.resize(numVertices);
178  for (int p=0;p<numVertices;p++)
179  {
180  m_polyhedron->m_vertices[p] = convexUtil->vertices[p];
181  }
182 
183 
184  for (int i=0;i<numFaces;i++)
185  {
186  int face = convexUtil->faces[i];
187  //printf("face=%d\n",face);
188  const btConvexHullComputer::Edge* firstEdge = &convexUtil->edges[face];
189  const btConvexHullComputer::Edge* edge = firstEdge;
190 
191  btVector3 edges[3];
192  int numEdges = 0;
193  //compute face normals
194 
195  do
196  {
197 
198  int src = edge->getSourceVertex();
199  tmpFaces[i].m_indices.push_back(src);
200  int targ = edge->getTargetVertex();
201  btVector3 wa = convexUtil->vertices[src];
202 
203  btVector3 wb = convexUtil->vertices[targ];
204  btVector3 newEdge = wb-wa;
205  newEdge.normalize();
206  if (numEdges<2)
207  edges[numEdges++] = newEdge;
208 
209  edge = edge->getNextEdgeOfFace();
210  } while (edge!=firstEdge);
211 
212  btScalar planeEq = 1e30f;
213 
214 
215  if (numEdges==2)
216  {
217  faceNormals[i] = edges[0].cross(edges[1]);
218  faceNormals[i].normalize();
219  tmpFaces[i].m_plane[0] = faceNormals[i].getX();
220  tmpFaces[i].m_plane[1] = faceNormals[i].getY();
221  tmpFaces[i].m_plane[2] = faceNormals[i].getZ();
222  tmpFaces[i].m_plane[3] = planeEq;
223 
224  }
225  else
226  {
227  btAssert(0);//degenerate?
228  faceNormals[i].setZero();
229  }
230 
231  for (int v=0;v<tmpFaces[i].m_indices.size();v++)
232  {
233  btScalar eq = m_polyhedron->m_vertices[tmpFaces[i].m_indices[v]].dot(faceNormals[i]);
234  if (planeEq>eq)
235  {
236  planeEq=eq;
237  }
238  }
239  tmpFaces[i].m_plane[3] = -planeEq;
240  }
241 
242  //merge coplanar faces and copy them to m_polyhedron
243 
244  btScalar faceWeldThreshold= 0.999f;
245  btAlignedObjectArray<int> todoFaces;
246  for (int i=0;i<tmpFaces.size();i++)
247  todoFaces.push_back(i);
248 
249  while (todoFaces.size())
250  {
251  btAlignedObjectArray<int> coplanarFaceGroup;
252  int refFace = todoFaces[todoFaces.size()-1];
253 
254  coplanarFaceGroup.push_back(refFace);
255  btFace& faceA = tmpFaces[refFace];
256  todoFaces.pop_back();
257 
258  btVector3 faceNormalA(faceA.m_plane[0],faceA.m_plane[1],faceA.m_plane[2]);
259  for (int j=todoFaces.size()-1;j>=0;j--)
260  {
261  int i = todoFaces[j];
262  btFace& faceB = tmpFaces[i];
263  btVector3 faceNormalB(faceB.m_plane[0],faceB.m_plane[1],faceB.m_plane[2]);
264  if (faceNormalA.dot(faceNormalB)>faceWeldThreshold)
265  {
266  coplanarFaceGroup.push_back(i);
267  todoFaces.remove(i);
268  }
269  }
270 
271 
272  bool did_merge = false;
273  if (coplanarFaceGroup.size()>1)
274  {
275  //do the merge: use Graham Scan 2d convex hull
276 
278  btVector3 averageFaceNormal(0,0,0);
279 
280  for (int i=0;i<coplanarFaceGroup.size();i++)
281  {
282 // m_polyhedron->m_faces.push_back(tmpFaces[coplanarFaceGroup[i]]);
283 
284  btFace& face = tmpFaces[coplanarFaceGroup[i]];
285  btVector3 faceNormal(face.m_plane[0],face.m_plane[1],face.m_plane[2]);
286  averageFaceNormal+=faceNormal;
287  for (int f=0;f<face.m_indices.size();f++)
288  {
289  int orgIndex = face.m_indices[f];
290  btVector3 pt = m_polyhedron->m_vertices[orgIndex];
291 
292  bool found = false;
293 
294  for (int i=0;i<orgpoints.size();i++)
295  {
296  //if ((orgpoints[i].m_orgIndex == orgIndex) || ((rotatedPt-orgpoints[i]).length2()<0.0001))
297  if (orgpoints[i].m_orgIndex == orgIndex)
298  {
299  found=true;
300  break;
301  }
302  }
303  if (!found)
304  orgpoints.push_back(GrahamVector3(pt,orgIndex));
305  }
306  }
307 
308 
309 
310  btFace combinedFace;
311  for (int i=0;i<4;i++)
312  combinedFace.m_plane[i] = tmpFaces[coplanarFaceGroup[0]].m_plane[i];
313 
315 
316  averageFaceNormal.normalize();
317  GrahamScanConvexHull2D(orgpoints,hull,averageFaceNormal);
318 
319  for (int i=0;i<hull.size();i++)
320  {
321  combinedFace.m_indices.push_back(hull[i].m_orgIndex);
322  for(int k = 0; k < orgpoints.size(); k++)
323  {
324  if(orgpoints[k].m_orgIndex == hull[i].m_orgIndex)
325  {
326  orgpoints[k].m_orgIndex = -1; // invalidate...
327  break;
328  }
329  }
330  }
331 
332  // are there rejected vertices?
333  bool reject_merge = false;
334 
335 
336 
337  for(int i = 0; i < orgpoints.size(); i++) {
338  if(orgpoints[i].m_orgIndex == -1)
339  continue; // this is in the hull...
340  // this vertex is rejected -- is anybody else using this vertex?
341  for(int j = 0; j < tmpFaces.size(); j++) {
342 
343  btFace& face = tmpFaces[j];
344  // is this a face of the current coplanar group?
345  bool is_in_current_group = false;
346  for(int k = 0; k < coplanarFaceGroup.size(); k++) {
347  if(coplanarFaceGroup[k] == j) {
348  is_in_current_group = true;
349  break;
350  }
351  }
352  if(is_in_current_group) // ignore this face...
353  continue;
354  // does this face use this rejected vertex?
355  for(int v = 0; v < face.m_indices.size(); v++) {
356  if(face.m_indices[v] == orgpoints[i].m_orgIndex) {
357  // this rejected vertex is used in another face -- reject merge
358  reject_merge = true;
359  break;
360  }
361  }
362  if(reject_merge)
363  break;
364  }
365  if(reject_merge)
366  break;
367  }
368 
369  if (!reject_merge)
370  {
371  // do this merge!
372  did_merge = true;
373  m_polyhedron->m_faces.push_back(combinedFace);
374  }
375  }
376  if(!did_merge)
377  {
378  for (int i=0;i<coplanarFaceGroup.size();i++)
379  {
380  btFace face = tmpFaces[coplanarFaceGroup[i]];
382  }
383 
384  }
385 
386 
387 
388  }
389 
390 #endif //BT_RECONSTRUCT_FACES
391 
393 
394  return true;
395 }
396 
397 #ifndef MIN
398  #define MIN(_a, _b) ((_a) < (_b) ? (_a) : (_b))
399 #endif
400 
402 {
403 
404 
405  btVector3 supVec(0,0,0);
406 #ifndef __SPU__
407  int i;
408  btScalar maxDot(btScalar(-BT_LARGE_FLOAT));
409 
410  btVector3 vec = vec0;
411  btScalar lenSqr = vec.length2();
412  if (lenSqr < btScalar(0.0001))
413  {
414  vec.setValue(1,0,0);
415  } else
416  {
417  btScalar rlen = btScalar(1.) / btSqrt(lenSqr );
418  vec *= rlen;
419  }
420 
421  btVector3 vtx;
422  btScalar newDot;
423 
424  for( int k = 0; k < getNumVertices(); k += 128 )
425  {
426  btVector3 temp[128];
427  int inner_count = MIN(getNumVertices() - k, 128);
428  for( i = 0; i < inner_count; i++ )
429  getVertex(i,temp[i]);
430  i = (int) vec.maxDot( temp, inner_count, newDot);
431  if (newDot > maxDot)
432  {
433  maxDot = newDot;
434  supVec = temp[i];
435  }
436  }
437 
438 #endif //__SPU__
439  return supVec;
440 }
441 
442 
443 
444 void btPolyhedralConvexShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const
445 {
446 #ifndef __SPU__
447  int i;
448 
449  btVector3 vtx;
450  btScalar newDot;
451 
452  for (i=0;i<numVectors;i++)
453  {
454  supportVerticesOut[i][3] = btScalar(-BT_LARGE_FLOAT);
455  }
456 
457  for (int j=0;j<numVectors;j++)
458  {
459  const btVector3& vec = vectors[j];
460 
461  for( int k = 0; k < getNumVertices(); k += 128 )
462  {
463  btVector3 temp[128];
464  int inner_count = MIN(getNumVertices() - k, 128);
465  for( i = 0; i < inner_count; i++ )
466  getVertex(i,temp[i]);
467  i = (int) vec.maxDot( temp, inner_count, newDot);
468  if (newDot > supportVerticesOut[j][3])
469  {
470  supportVerticesOut[j] = temp[i];
471  supportVerticesOut[j][3] = newDot;
472  }
473  }
474  }
475 
476 #endif //__SPU__
477 }
478 
479 
480 
482 {
483 #ifndef __SPU__
484  //not yet, return box inertia
485 
486  btScalar margin = getMargin();
487 
488  btTransform ident;
489  ident.setIdentity();
490  btVector3 aabbMin,aabbMax;
491  getAabb(ident,aabbMin,aabbMax);
492  btVector3 halfExtents = (aabbMax-aabbMin)*btScalar(0.5);
493 
494  btScalar lx=btScalar(2.)*(halfExtents.x()+margin);
495  btScalar ly=btScalar(2.)*(halfExtents.y()+margin);
496  btScalar lz=btScalar(2.)*(halfExtents.z()+margin);
497  const btScalar x2 = lx*lx;
498  const btScalar y2 = ly*ly;
499  const btScalar z2 = lz*lz;
500  const btScalar scaledmass = mass * btScalar(0.08333333);
501 
502  inertia = scaledmass * (btVector3(y2+z2,x2+z2,x2+y2));
503 #endif //__SPU__
504 }
505 
506 
507 
509 {
511  recalcLocalAabb();
512 }
513 
516 m_localAabbMin(1,1,1),
517 m_localAabbMax(-1,-1,-1),
518 m_isLocalAabbValid(false)
519 {
520 }
521 
523 {
524  getNonvirtualAabb(trans,aabbMin,aabbMax,getMargin());
525 }
526 
528 {
529  m_isLocalAabbValid = true;
530 
531  #if 1
532  static const btVector3 _directions[] =
533  {
534  btVector3( 1., 0., 0.),
535  btVector3( 0., 1., 0.),
536  btVector3( 0., 0., 1.),
537  btVector3( -1., 0., 0.),
538  btVector3( 0., -1., 0.),
539  btVector3( 0., 0., -1.)
540  };
541 
542  btVector3 _supporting[] =
543  {
544  btVector3( 0., 0., 0.),
545  btVector3( 0., 0., 0.),
546  btVector3( 0., 0., 0.),
547  btVector3( 0., 0., 0.),
548  btVector3( 0., 0., 0.),
549  btVector3( 0., 0., 0.)
550  };
551 
552  batchedUnitVectorGetSupportingVertexWithoutMargin(_directions, _supporting, 6);
553 
554  for ( int i = 0; i < 3; ++i )
555  {
556  m_localAabbMax[i] = _supporting[i][i] + m_collisionMargin;
557  m_localAabbMin[i] = _supporting[i + 3][i] - m_collisionMargin;
558  }
559 
560  #else
561 
562  for (int i=0;i<3;i++)
563  {
564  btVector3 vec(btScalar(0.),btScalar(0.),btScalar(0.));
565  vec[i] = btScalar(1.);
567  m_localAabbMax[i] = tmp[i];
568  vec[i] = btScalar(-1.);
569  tmp = localGetSupportingVertex(vec);
570  m_localAabbMin[i] = tmp[i];
571  }
572  #endif
573 }
574 
575 
576 
577 
btAlignedObjectArray< btVector3 > m_vertices
void push_back(const T &_Val)
#define BT_LARGE_FLOAT
Definition: btScalar.h:294
const Edge * getNextEdgeOfFace() const
void getAabb(const btTransform &t, btVector3 &aabbMin, btVector3 &aabbMax) const
getAabb&#39;s default implementation is brute force, expected derived classes to implement a fast dedicat...
void setValue(const btScalar &_x, const btScalar &_y, const btScalar &_z)
Definition: btVector3.h:652
void getNonvirtualAabb(const btTransform &trans, btVector3 &aabbMin, btVector3 &aabbMax, btScalar margin) const
btAlignedObjectArray< Edge > edges
The btConvexInternalShape is an internal base class, shared by most convex shape implementations.
virtual void setLocalScaling(const btVector3 &scaling)
btScalar btSqrt(btScalar y)
Definition: btScalar.h:444
void setIdentity()
Set this transformation to the identity.
Definition: btTransform.h:172
#define btAssert(x)
Definition: btScalar.h:131
virtual void getVertex(int i, btVector3 &vtx) const =0
long maxDot(const btVector3 *array, long array_count, btScalar &dotOut) const
returns index of maximum dot product between this and vectors in array[]
Definition: btVector3.h:1015
Convex hull implementation based on Preparata and Hong See http://code.google.com/p/bullet/issues/det...
#define MIN(_a, _b)
btScalar dot(const btVector3 &v) const
Return the dot product.
Definition: btVector3.h:235
virtual btScalar getMargin() const
btVector3 & normalize()
Normalize this vector x^2 + y^2 + z^2 = 1.
Definition: btVector3.h:309
const btScalar & x() const
Return the x value.
Definition: btVector3.h:587
btAlignedObjectArray< int > m_indices
int size() const
return the number of elements in the array
btAlignedObjectArray< btFace > m_faces
virtual void getAabb(const btTransform &t, btVector3 &aabbMin, btVector3 &aabbMax) const
getAabb&#39;s default implementation is brute force, expected derived classes to implement a fast dedicat...
virtual bool initializePolyhedralFeatures(int shiftVerticesByMargin=0)
optional method mainly used to generate multiple contact points by clipping polyhedral features (face...
btVector3 cross(const btVector3 &v) const
Return the cross product between this and another vector.
Definition: btVector3.h:389
#define btAlignedFree(ptr)
The btPolyhedralConvexShape is an internal interface class for polyhedral convex shapes.
virtual int getNumVertices() const =0
static void getPlaneEquationsFromVertices(btAlignedObjectArray< btVector3 > &vertices, btAlignedObjectArray< btVector3 > &planeEquationsOut)
const btScalar & y() const
Return the y value.
Definition: btVector3.h:589
virtual btVector3 localGetSupportingVertex(const btVector3 &vec) const
btVector3 can be used to represent 3D points and vectors.
Definition: btVector3.h:83
btScalar length2() const
Return the length of the vector squared.
Definition: btVector3.h:257
btAlignedObjectArray< btVector3 > vertices
The btTransform class supports rigid transforms with only translation and rotation and no scaling/she...
Definition: btTransform.h:34
btScalar m_plane[4]
void remove(const T &key)
void resize(int newsize, const T &fillData=T())
virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3 *vectors, btVector3 *supportVerticesOut, int numVectors) const
virtual void calculateLocalInertia(btScalar mass, btVector3 &inertia) const
T & expand(const T &fillValue=T())
btConvexPolyhedron * m_polyhedron
void GrahamScanConvexHull2D(btAlignedObjectArray< GrahamVector3 > &originalPoints, btAlignedObjectArray< GrahamVector3 > &hull, const btVector3 &normalAxis)
#define btAlignedAlloc(size, alignment)
virtual void setLocalScaling(const btVector3 &scaling)
btScalar compute(const void *coords, bool doubleCoords, int stride, int count, btScalar shrink, btScalar shrinkClamp)
static void getVerticesFromPlaneEquations(const btAlignedObjectArray< btVector3 > &planeEquations, btAlignedObjectArray< btVector3 > &verticesOut)
btAlignedObjectArray< int > faces
virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3 &vec) const
virtual void setPolyhedralFeatures(btConvexPolyhedron &polyhedron)
float btScalar
The btScalar type abstracts floating point numbers, to easily switch between double and single floati...
Definition: btScalar.h:292
const btScalar & z() const
Return the z value.
Definition: btVector3.h:591