2 Stan Melax Convex Hull Computation
3 Copyright (c) 2003-2006 Stan Melax http://www.melax.com/
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:
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.
18 #include "btConvexHull.h"
19 #include "btAlignedObjectArray.h"
21 #include "btVector3.h"
27 //----------------------------------
34 int3(int _x,int _y, int _z){x=_x;y=_y;z=_z;}
35 const int& operator[](int i) const {return (&x)[i];}
36 int& operator[](int i) {return (&x)[i];}
40 //------- btPlane ----------
43 inline btPlane PlaneFlip(const btPlane &plane){return btPlane(-plane.normal,-plane.dist);}
44 inline int operator==( const btPlane &a, const btPlane &b ) { return (a.normal==b.normal && a.dist==b.dist); }
45 inline int coplanar( const btPlane &a, const btPlane &b ) { return (a==b || a==PlaneFlip(b)); }
48 //--------- Utility Functions ------
50 btVector3 PlaneLineIntersection(const btPlane &plane, const btVector3 &p0, const btVector3 &p1);
51 btVector3 PlaneProject(const btPlane &plane, const btVector3 &point);
53 btVector3 ThreePlaneIntersection(const btPlane &p0,const btPlane &p1, const btPlane &p2);
54 btVector3 ThreePlaneIntersection(const btPlane &p0,const btPlane &p1, const btPlane &p2)
56 btVector3 N1 = p0.normal;
57 btVector3 N2 = p1.normal;
58 btVector3 N3 = p2.normal;
60 btVector3 n2n3; n2n3 = N2.cross(N3);
61 btVector3 n3n1; n3n1 = N3.cross(N1);
62 btVector3 n1n2; n1n2 = N1.cross(N2);
64 btScalar quotient = (N1.dot(n2n3));
66 btAssert(btFabs(quotient) > btScalar(0.000001));
68 quotient = btScalar(-1.) / quotient;
72 btVector3 potentialVertex = n2n3;
73 potentialVertex += n3n1;
74 potentialVertex += n1n2;
75 potentialVertex *= quotient;
77 btVector3 result(potentialVertex.getX(),potentialVertex.getY(),potentialVertex.getZ());
82 btScalar DistanceBetweenLines(const btVector3 &ustart, const btVector3 &udir, const btVector3 &vstart, const btVector3 &vdir, btVector3 *upoint=NULL, btVector3 *vpoint=NULL);
83 btVector3 TriNormal(const btVector3 &v0, const btVector3 &v1, const btVector3 &v2);
84 btVector3 NormalOf(const btVector3 *vert, const int n);
87 btVector3 PlaneLineIntersection(const btPlane &plane, const btVector3 &p0, const btVector3 &p1)
89 // returns the point where the line p0-p1 intersects the plane n&d
92 btScalar dn= btDot(plane.normal,dif);
93 btScalar t = -(plane.dist+btDot(plane.normal,p0) )/dn;
97 btVector3 PlaneProject(const btPlane &plane, const btVector3 &point)
99 return point - plane.normal * (btDot(point,plane.normal)+plane.dist);
102 btVector3 TriNormal(const btVector3 &v0, const btVector3 &v1, const btVector3 &v2)
104 // return the normal of the triangle
105 // inscribed by v0, v1, and v2
106 btVector3 cp=btCross(v1-v0,v2-v1);
107 btScalar m=cp.length();
108 if(m==0) return btVector3(1,0,0);
109 return cp*(btScalar(1.0)/m);
113 btScalar DistanceBetweenLines(const btVector3 &ustart, const btVector3 &udir, const btVector3 &vstart, const btVector3 &vdir, btVector3 *upoint, btVector3 *vpoint)
116 cp = btCross(udir,vdir).normalized();
118 btScalar distu = -btDot(cp,ustart);
119 btScalar distv = -btDot(cp,vstart);
120 btScalar dist = (btScalar)fabs(distu-distv);
124 plane.normal = btCross(vdir,cp).normalized();
125 plane.dist = -btDot(plane.normal,vstart);
126 *upoint = PlaneLineIntersection(plane,ustart,ustart+udir);
131 plane.normal = btCross(udir,cp).normalized();
132 plane.dist = -btDot(plane.normal,ustart);
133 *vpoint = PlaneLineIntersection(plane,vstart,vstart+vdir);
147 #define SPLIT (OVER|UNDER)
148 #define PAPERWIDTH (btScalar(0.001))
150 btScalar planetestepsilon = PAPERWIDTH;
154 typedef ConvexH::HalfEdge HalfEdge;
156 ConvexH::ConvexH(int vertices_size,int edges_size,int facets_size)
158 vertices.resize(vertices_size);
159 edges.resize(edges_size);
160 facets.resize(facets_size);
164 int PlaneTest(const btPlane &p, const btVector3 &v);
165 int PlaneTest(const btPlane &p, const btVector3 &v) {
166 btScalar a = btDot(v,p.normal)+p.dist;
167 int flag = (a>planetestepsilon)?OVER:((a<-planetestepsilon)?UNDER:COPLANAR);
171 int SplitTest(ConvexH &convex,const btPlane &plane);
172 int SplitTest(ConvexH &convex,const btPlane &plane) {
174 for(int i=0;i<convex.vertices.size();i++) {
175 flag |= PlaneTest(plane,convex.vertices[i]);
183 unsigned char planetest;
185 unsigned char undermap;
186 unsigned char overmap;
191 unsigned char planetest;
199 unsigned char undermap;
200 unsigned char overmap;
217 int maxdirfiltered(const T *p,int count,const T &dir,btAlignedObjectArray<int> &allow)
221 for(int i=0;i<count;i++)
224 if(m==-1 || btDot(p[i],dir)>btDot(p[m],dir))
231 btVector3 orth(const btVector3 &v);
232 btVector3 orth(const btVector3 &v)
234 btVector3 a=btCross(v,btVector3(0,0,1));
235 btVector3 b=btCross(v,btVector3(0,1,0));
236 if (a.length() > b.length())
238 return a.normalized();
240 return b.normalized();
246 int maxdirsterid(const T *p,int count,const T &dir,btAlignedObjectArray<int> &allow)
251 m = maxdirfiltered(p,count,dir,allow);
252 if(allow[m]==3) return m;
254 T v = btCross(u,dir);
256 for(btScalar x = btScalar(0.0) ; x<= btScalar(360.0) ; x+= btScalar(45.0))
258 btScalar s = btSin(SIMD_RADS_PER_DEG*(x));
259 btScalar c = btCos(SIMD_RADS_PER_DEG*(x));
260 int mb = maxdirfiltered(p,count,dir+(u*s+v*c)*btScalar(0.025),allow);
266 if(ma!=-1 && ma!=mb) // Yuck - this is really ugly
269 for(btScalar xx = x-btScalar(40.0) ; xx <= x ; xx+= btScalar(5.0))
271 btScalar s = btSin(SIMD_RADS_PER_DEG*(xx));
272 btScalar c = btCos(SIMD_RADS_PER_DEG*(xx));
273 int md = maxdirfiltered(p,count,dir+(u*s+v*c)*btScalar(0.025),allow);
294 int operator ==(const int3 &a,const int3 &b);
295 int operator ==(const int3 &a,const int3 &b)
299 if(a[i]!=b[i]) return 0;
305 int above(btVector3* vertices,const int3& t, const btVector3 &p, btScalar epsilon);
306 int above(btVector3* vertices,const int3& t, const btVector3 &p, btScalar epsilon)
308 btVector3 n=TriNormal(vertices[t[0]],vertices[t[1]],vertices[t[2]]);
309 return (btDot(n,p-vertices[t[0]]) > epsilon); // EPSILON???
311 int hasedge(const int3 &t, int a,int b);
312 int hasedge(const int3 &t, int a,int b)
317 if(t[i]==a && t[i1]==b) return 1;
321 int hasvert(const int3 &t, int v);
322 int hasvert(const int3 &t, int v)
324 return (t[0]==v || t[1]==v || t[2]==v) ;
326 int shareedge(const int3 &a,const int3 &b);
327 int shareedge(const int3 &a,const int3 &b)
333 if(hasedge(a,b[i1],b[i])) return 1;
338 class btHullTriangle;
342 class btHullTriangle : public int3
349 btHullTriangle(int a,int b,int c):int3(a,b,c),n(-1,-1,-1)
352 rise = btScalar(0.0);
357 int &neib(int a,int b);
361 int &btHullTriangle::neib(int a,int b)
369 if((*this)[i]==a && (*this)[i1]==b) return n[i2];
370 if((*this)[i]==b && (*this)[i1]==a) return n[i2];
375 void HullLibrary::b2bfix(btHullTriangle* s,btHullTriangle*t)
384 btAssert(m_tris[s->neib(a,b)]->neib(b,a) == s->id);
385 btAssert(m_tris[t->neib(a,b)]->neib(b,a) == t->id);
386 m_tris[s->neib(a,b)]->neib(b,a) = t->neib(b,a);
387 m_tris[t->neib(b,a)]->neib(a,b) = s->neib(a,b);
391 void HullLibrary::removeb2b(btHullTriangle* s,btHullTriangle*t)
394 deAllocateTriangle(s);
396 deAllocateTriangle(t);
399 void HullLibrary::checkit(btHullTriangle *t)
404 btAssert(m_tris[t->id]==t);
412 // release compile fix
419 btAssert( m_tris[t->n[i]]->neib(b,a) == t->id);
423 btHullTriangle* HullLibrary::allocateTriangle(int a,int b,int c)
425 void* mem = btAlignedAlloc(sizeof(btHullTriangle),16);
426 btHullTriangle* tr = new (mem)btHullTriangle(a,b,c);
427 tr->id = m_tris.size();
428 m_tris.push_back(tr);
433 void HullLibrary::deAllocateTriangle(btHullTriangle* tri)
435 btAssert(m_tris[tri->id]==tri);
436 m_tris[tri->id]=NULL;
437 tri->~btHullTriangle();
442 void HullLibrary::extrude(btHullTriangle *t0,int v)
445 int n = m_tris.size();
446 btHullTriangle* ta = allocateTriangle(v,t[1],t[2]);
447 ta->n = int3(t0->n[0],n+1,n+2);
448 m_tris[t0->n[0]]->neib(t[1],t[2]) = n+0;
449 btHullTriangle* tb = allocateTriangle(v,t[2],t[0]);
450 tb->n = int3(t0->n[1],n+2,n+0);
451 m_tris[t0->n[1]]->neib(t[2],t[0]) = n+1;
452 btHullTriangle* tc = allocateTriangle(v,t[0],t[1]);
453 tc->n = int3(t0->n[2],n+0,n+1);
454 m_tris[t0->n[2]]->neib(t[0],t[1]) = n+2;
458 if(hasvert(*m_tris[ta->n[0]],v)) removeb2b(ta,m_tris[ta->n[0]]);
459 if(hasvert(*m_tris[tb->n[0]],v)) removeb2b(tb,m_tris[tb->n[0]]);
460 if(hasvert(*m_tris[tc->n[0]],v)) removeb2b(tc,m_tris[tc->n[0]]);
461 deAllocateTriangle(t0);
465 btHullTriangle* HullLibrary::extrudable(btScalar epsilon)
468 btHullTriangle *t=NULL;
469 for(i=0;i<m_tris.size();i++)
471 if(!t || (m_tris[i] && t->rise<m_tris[i]->rise))
476 return (t->rise >epsilon)?t:NULL ;
482 int4 HullLibrary::FindSimplex(btVector3 *verts,int verts_count,btAlignedObjectArray<int> &allow)
485 basis[0] = btVector3( btScalar(0.01), btScalar(0.02), btScalar(1.0) );
486 int p0 = maxdirsterid(verts,verts_count, basis[0],allow);
487 int p1 = maxdirsterid(verts,verts_count,-basis[0],allow);
488 basis[0] = verts[p0]-verts[p1];
489 if(p0==p1 || basis[0]==btVector3(0,0,0))
490 return int4(-1,-1,-1,-1);
491 basis[1] = btCross(btVector3( btScalar(1),btScalar(0.02), btScalar(0)),basis[0]);
492 basis[2] = btCross(btVector3(btScalar(-0.02), btScalar(1), btScalar(0)),basis[0]);
493 if (basis[1].length() > basis[2].length())
495 basis[1].normalize();
498 basis[1].normalize ();
500 int p2 = maxdirsterid(verts,verts_count,basis[1],allow);
501 if(p2 == p0 || p2 == p1)
503 p2 = maxdirsterid(verts,verts_count,-basis[1],allow);
505 if(p2 == p0 || p2 == p1)
506 return int4(-1,-1,-1,-1);
507 basis[1] = verts[p2] - verts[p0];
508 basis[2] = btCross(basis[1],basis[0]).normalized();
509 int p3 = maxdirsterid(verts,verts_count,basis[2],allow);
510 if(p3==p0||p3==p1||p3==p2) p3 = maxdirsterid(verts,verts_count,-basis[2],allow);
511 if(p3==p0||p3==p1||p3==p2)
512 return int4(-1,-1,-1,-1);
513 btAssert(!(p0==p1||p0==p2||p0==p3||p1==p2||p1==p3||p2==p3));
514 if(btDot(verts[p3]-verts[p0],btCross(verts[p1]-verts[p0],verts[p2]-verts[p0])) <0) {btSwap(p2,p3);}
515 return int4(p0,p1,p2,p3);
518 int HullLibrary::calchullgen(btVector3 *verts,int verts_count, int vlimit)
520 if(verts_count <4) return 0;
521 if(vlimit==0) vlimit=1000000000;
523 btVector3 bmin(*verts),bmax(*verts);
524 btAlignedObjectArray<int> isextreme;
525 isextreme.reserve(verts_count);
526 btAlignedObjectArray<int> allow;
527 allow.reserve(verts_count);
529 for(j=0;j<verts_count;j++)
532 isextreme.push_back(0);
533 bmin.setMin (verts[j]);
534 bmax.setMax (verts[j]);
536 btScalar epsilon = (bmax-bmin).length() * btScalar(0.001);
537 btAssert (epsilon != 0.0);
540 int4 p = FindSimplex(verts,verts_count,allow);
541 if(p.x==-1) return 0; // simplex failed
545 btVector3 center = (verts[p[0]]+verts[p[1]]+verts[p[2]]+verts[p[3]]) / btScalar(4.0); // a valid interior point
546 btHullTriangle *t0 = allocateTriangle(p[2],p[3],p[1]); t0->n=int3(2,3,1);
547 btHullTriangle *t1 = allocateTriangle(p[3],p[2],p[0]); t1->n=int3(3,2,0);
548 btHullTriangle *t2 = allocateTriangle(p[0],p[1],p[3]); t2->n=int3(0,1,3);
549 btHullTriangle *t3 = allocateTriangle(p[1],p[0],p[2]); t3->n=int3(1,0,2);
550 isextreme[p[0]]=isextreme[p[1]]=isextreme[p[2]]=isextreme[p[3]]=1;
551 checkit(t0);checkit(t1);checkit(t2);checkit(t3);
553 for(j=0;j<m_tris.size();j++)
555 btHullTriangle *t=m_tris[j];
558 btVector3 n=TriNormal(verts[(*t)[0]],verts[(*t)[1]],verts[(*t)[2]]);
559 t->vmax = maxdirsterid(verts,verts_count,n,allow);
560 t->rise = btDot(n,verts[t->vmax]-verts[(*t)[0]]);
564 while(vlimit >0 && ((te=extrudable(epsilon)) != 0))
569 btAssert(!isextreme[v]); // wtf we've already done this vertex
571 //if(v==p0 || v==p1 || v==p2 || v==p3) continue; // done these already
574 if(!m_tris[j]) continue;
576 if(above(verts,t,verts[v],btScalar(0.01)*epsilon))
578 extrude(m_tris[j],v);
581 // now check for those degenerate cases where we have a flipped triangle or a really skinny triangle
585 if(!m_tris[j]) continue;
586 if(!hasvert(*m_tris[j],v)) break;
588 if(above(verts,nt,center,btScalar(0.01)*epsilon) || btCross(verts[nt[1]]-verts[nt[0]],verts[nt[2]]-verts[nt[1]]).length()< epsilon*epsilon*btScalar(0.1) )
590 btHullTriangle *nb = m_tris[m_tris[j]->n[0]];
591 btAssert(nb);btAssert(!hasvert(*nb,v));btAssert(nb->id<j);
599 btHullTriangle *t=m_tris[j];
601 if(t->vmax>=0) break;
602 btVector3 n=TriNormal(verts[(*t)[0]],verts[(*t)[1]],verts[(*t)[2]]);
603 t->vmax = maxdirsterid(verts,verts_count,n,allow);
604 if(isextreme[t->vmax])
606 t->vmax=-1; // already done that vertex - algorithm needs to be able to terminate.
610 t->rise = btDot(n,verts[t->vmax]-verts[(*t)[0]]);
618 int HullLibrary::calchull(btVector3 *verts,int verts_count, TUIntArray& tris_out, int &tris_count,int vlimit)
620 int rc=calchullgen(verts,verts_count, vlimit) ;
622 btAlignedObjectArray<int> ts;
625 for(i=0;i<m_tris.size();i++)
630 ts.push_back((*m_tris[i])[j]);
631 deAllocateTriangle(m_tris[i]);
634 tris_count = ts.size()/3;
635 tris_out.resize(ts.size());
637 for (i=0;i<ts.size();i++)
639 tris_out[i] = static_cast<unsigned int>(ts[i]);
650 bool HullLibrary::ComputeHull(unsigned int vcount,const btVector3 *vertices,PHullResult &result,unsigned int vlimit)
654 int ret = calchull( (btVector3 *) vertices, (int) vcount, result.m_Indices, tris_count, static_cast<int>(vlimit) );
655 if(!ret) return false;
656 result.mIndexCount = (unsigned int) (tris_count*3);
657 result.mFaceCount = (unsigned int) tris_count;
658 result.mVertices = (btVector3*) vertices;
659 result.mVcount = (unsigned int) vcount;
665 void ReleaseHull(PHullResult &result);
666 void ReleaseHull(PHullResult &result)
668 if ( result.m_Indices.size() )
670 result.m_Indices.clear();
674 result.mIndexCount = 0;
675 result.mVertices = 0;
679 //*********************************************************************
680 //*********************************************************************
681 //******** HullLib header
682 //*********************************************************************
683 //*********************************************************************
685 //*********************************************************************
686 //*********************************************************************
687 //******** HullLib implementation
688 //*********************************************************************
689 //*********************************************************************
691 HullError HullLibrary::CreateConvexHull(const HullDesc &desc, // describes the input request
692 HullResult &result) // contains the resulst
694 HullError ret = QE_FAIL;
699 unsigned int vcount = desc.mVcount;
700 if ( vcount < 8 ) vcount = 8;
702 btAlignedObjectArray<btVector3> vertexSource;
703 vertexSource.resize(static_cast<int>(vcount));
707 unsigned int ovcount;
709 bool ok = CleanupVertices(desc.mVcount,desc.mVertices, desc.mVertexStride, ovcount, &vertexSource[0], desc.mNormalEpsilon, scale ); // normalize point cloud, remove duplicates!
715 // if ( 1 ) // scale vertices back to their original size.
717 for (unsigned int i=0; i<ovcount; i++)
719 btVector3& v = vertexSource[static_cast<int>(i)];
726 ok = ComputeHull(ovcount,&vertexSource[0],hr,desc.mMaxVertices);
731 // re-index triangle mesh so it refers to only used vertices, rebuild a new vertex table.
732 btAlignedObjectArray<btVector3> vertexScratch;
733 vertexScratch.resize(static_cast<int>(hr.mVcount));
735 BringOutYourDead(hr.mVertices,hr.mVcount, &vertexScratch[0], ovcount, &hr.m_Indices[0], hr.mIndexCount );
739 if ( desc.HasHullFlag(QF_TRIANGLES) ) // if he wants the results as triangle!
741 result.mPolygons = false;
742 result.mNumOutputVertices = ovcount;
743 result.m_OutputVertices.resize(static_cast<int>(ovcount));
744 result.mNumFaces = hr.mFaceCount;
745 result.mNumIndices = hr.mIndexCount;
747 result.m_Indices.resize(static_cast<int>(hr.mIndexCount));
749 memcpy(&result.m_OutputVertices[0], &vertexScratch[0], sizeof(btVector3)*ovcount );
751 if ( desc.HasHullFlag(QF_REVERSE_ORDER) )
754 const unsigned int *source = &hr.m_Indices[0];
755 unsigned int *dest = &result.m_Indices[0];
757 for (unsigned int i=0; i<hr.mFaceCount; i++)
769 memcpy(&result.m_Indices[0], &hr.m_Indices[0], sizeof(unsigned int)*hr.mIndexCount);
774 result.mPolygons = true;
775 result.mNumOutputVertices = ovcount;
776 result.m_OutputVertices.resize(static_cast<int>(ovcount));
777 result.mNumFaces = hr.mFaceCount;
778 result.mNumIndices = hr.mIndexCount+hr.mFaceCount;
779 result.m_Indices.resize(static_cast<int>(result.mNumIndices));
780 memcpy(&result.m_OutputVertices[0], &vertexScratch[0], sizeof(btVector3)*ovcount );
784 const unsigned int *source = &hr.m_Indices[0];
785 unsigned int *dest = &result.m_Indices[0];
786 for (unsigned int i=0; i<hr.mFaceCount; i++)
789 if ( desc.HasHullFlag(QF_REVERSE_ORDER) )
816 HullError HullLibrary::ReleaseResult(HullResult &result) // release memory allocated for this result, we are done with it.
818 if ( result.m_OutputVertices.size())
820 result.mNumOutputVertices=0;
821 result.m_OutputVertices.clear();
823 if ( result.m_Indices.size() )
825 result.mNumIndices=0;
826 result.m_Indices.clear();
832 static void addPoint(unsigned int &vcount,btVector3 *p,btScalar x,btScalar y,btScalar z)
834 // XXX, might be broken
835 btVector3& dest = p[vcount];
842 btScalar GetDist(btScalar px,btScalar py,btScalar pz,const btScalar *p2);
843 btScalar GetDist(btScalar px,btScalar py,btScalar pz,const btScalar *p2)
846 btScalar dx = px - p2[0];
847 btScalar dy = py - p2[1];
848 btScalar dz = pz - p2[2];
850 return dx*dx+dy*dy+dz*dz;
855 bool HullLibrary::CleanupVertices(unsigned int svcount,
856 const btVector3 *svertices,
858 unsigned int &vcount, // output number of vertices
859 btVector3 *vertices, // location to store the results.
860 btScalar normalepsilon,
863 if ( svcount == 0 ) return false;
865 m_vertexIndexMapping.resize(0);
868 #define EPSILON btScalar(0.000001) /* close enough to consider two btScalaring point numbers to be 'the same'. */
872 btScalar recip[3]={0.f,0.f,0.f};
881 btScalar bmin[3] = { FLT_MAX, FLT_MAX, FLT_MAX };
882 btScalar bmax[3] = { -FLT_MAX, -FLT_MAX, -FLT_MAX };
884 const char *vtx = (const char *) svertices;
888 for (unsigned int i=0; i<svcount; i++)
890 const btScalar *p = (const btScalar *) vtx;
894 for (int j=0; j<3; j++)
896 if ( p[j] < bmin[j] ) bmin[j] = p[j];
897 if ( p[j] > bmax[j] ) bmax[j] = p[j];
902 btScalar dx = bmax[0] - bmin[0];
903 btScalar dy = bmax[1] - bmin[1];
904 btScalar dz = bmax[2] - bmin[2];
908 center[0] = dx*btScalar(0.5) + bmin[0];
909 center[1] = dy*btScalar(0.5) + bmin[1];
910 center[2] = dz*btScalar(0.5) + bmin[2];
912 if ( dx < EPSILON || dy < EPSILON || dz < EPSILON || svcount < 3 )
915 btScalar len = FLT_MAX;
917 if ( dx > EPSILON && dx < len ) len = dx;
918 if ( dy > EPSILON && dy < len ) len = dy;
919 if ( dz > EPSILON && dz < len ) len = dz;
921 if ( len == FLT_MAX )
923 dx = dy = dz = btScalar(0.01); // one centimeter
927 if ( dx < EPSILON ) dx = len * btScalar(0.05); // 1/5th the shortest non-zero edge.
928 if ( dy < EPSILON ) dy = len * btScalar(0.05);
929 if ( dz < EPSILON ) dz = len * btScalar(0.05);
932 btScalar x1 = center[0] - dx;
933 btScalar x2 = center[0] + dx;
935 btScalar y1 = center[1] - dy;
936 btScalar y2 = center[1] + dy;
938 btScalar z1 = center[2] - dz;
939 btScalar z2 = center[2] + dz;
941 addPoint(vcount,vertices,x1,y1,z1);
942 addPoint(vcount,vertices,x2,y1,z1);
943 addPoint(vcount,vertices,x2,y2,z1);
944 addPoint(vcount,vertices,x1,y2,z1);
945 addPoint(vcount,vertices,x1,y1,z2);
946 addPoint(vcount,vertices,x2,y1,z2);
947 addPoint(vcount,vertices,x2,y2,z2);
948 addPoint(vcount,vertices,x1,y2,z2);
950 return true; // return cube
976 vtx = (const char *) svertices;
978 for (unsigned int i=0; i<svcount; i++)
980 const btVector3 *p = (const btVector3 *)vtx;
983 btScalar px = p->getX();
984 btScalar py = p->getY();
985 btScalar pz = p->getZ();
989 px = px*recip[0]; // normalize
990 py = py*recip[1]; // normalize
991 pz = pz*recip[2]; // normalize
998 for (j=0; j<vcount; j++)
1000 /// XXX might be broken
1001 btVector3& v = vertices[j];
1007 btScalar dx = btFabs(x - px );
1008 btScalar dy = btFabs(y - py );
1009 btScalar dz = btFabs(z - pz );
1011 if ( dx < normalepsilon && dy < normalepsilon && dz < normalepsilon )
1013 // ok, it is close enough to the old one
1014 // now let us see if it is further from the center of the point cloud than the one we already recorded.
1015 // in which case we keep this one instead.
1017 btScalar dist1 = GetDist(px,py,pz,center);
1018 btScalar dist2 = GetDist(v[0],v[1],v[2],center);
1020 if ( dist1 > dist2 )
1034 btVector3& dest = vertices[vcount];
1040 m_vertexIndexMapping.push_back(j);
1044 // ok..now make sure we didn't prune so many vertices it is now invalid.
1047 btScalar bmin[3] = { FLT_MAX, FLT_MAX, FLT_MAX };
1048 btScalar bmax[3] = { -FLT_MAX, -FLT_MAX, -FLT_MAX };
1050 for (unsigned int i=0; i<vcount; i++)
1052 const btVector3& p = vertices[i];
1053 for (int j=0; j<3; j++)
1055 if ( p[j] < bmin[j] ) bmin[j] = p[j];
1056 if ( p[j] > bmax[j] ) bmax[j] = p[j];
1060 btScalar dx = bmax[0] - bmin[0];
1061 btScalar dy = bmax[1] - bmin[1];
1062 btScalar dz = bmax[2] - bmin[2];
1064 if ( dx < EPSILON || dy < EPSILON || dz < EPSILON || vcount < 3)
1066 btScalar cx = dx*btScalar(0.5) + bmin[0];
1067 btScalar cy = dy*btScalar(0.5) + bmin[1];
1068 btScalar cz = dz*btScalar(0.5) + bmin[2];
1070 btScalar len = FLT_MAX;
1072 if ( dx >= EPSILON && dx < len ) len = dx;
1073 if ( dy >= EPSILON && dy < len ) len = dy;
1074 if ( dz >= EPSILON && dz < len ) len = dz;
1076 if ( len == FLT_MAX )
1078 dx = dy = dz = btScalar(0.01); // one centimeter
1082 if ( dx < EPSILON ) dx = len * btScalar(0.05); // 1/5th the shortest non-zero edge.
1083 if ( dy < EPSILON ) dy = len * btScalar(0.05);
1084 if ( dz < EPSILON ) dz = len * btScalar(0.05);
1087 btScalar x1 = cx - dx;
1088 btScalar x2 = cx + dx;
1090 btScalar y1 = cy - dy;
1091 btScalar y2 = cy + dy;
1093 btScalar z1 = cz - dz;
1094 btScalar z2 = cz + dz;
1096 vcount = 0; // add box
1098 addPoint(vcount,vertices,x1,y1,z1);
1099 addPoint(vcount,vertices,x2,y1,z1);
1100 addPoint(vcount,vertices,x2,y2,z1);
1101 addPoint(vcount,vertices,x1,y2,z1);
1102 addPoint(vcount,vertices,x1,y1,z2);
1103 addPoint(vcount,vertices,x2,y1,z2);
1104 addPoint(vcount,vertices,x2,y2,z2);
1105 addPoint(vcount,vertices,x1,y2,z2);
1114 void HullLibrary::BringOutYourDead(const btVector3* verts,unsigned int vcount, btVector3* overts,unsigned int &ocount,unsigned int *indices,unsigned indexcount)
1116 btAlignedObjectArray<int>tmpIndices;
1117 tmpIndices.resize(m_vertexIndexMapping.size());
1120 for (i=0;i<m_vertexIndexMapping.size();i++)
1122 tmpIndices[i] = m_vertexIndexMapping[i];
1125 TUIntArray usedIndices;
1126 usedIndices.resize(static_cast<int>(vcount));
1127 memset(&usedIndices[0],0,sizeof(unsigned int)*vcount);
1131 for (i=0; i<int (indexcount); i++)
1133 unsigned int v = indices[i]; // original array index
1135 btAssert( v >= 0 && v < vcount );
1137 if ( usedIndices[static_cast<int>(v)] ) // if already remapped
1139 indices[i] = usedIndices[static_cast<int>(v)]-1; // index to new array
1144 indices[i] = ocount; // new index mapping
1146 overts[ocount][0] = verts[v][0]; // copy old vert to new vert array
1147 overts[ocount][1] = verts[v][1];
1148 overts[ocount][2] = verts[v][2];
1150 for (int k=0;k<m_vertexIndexMapping.size();k++)
1152 if (tmpIndices[k]==int(v))
1153 m_vertexIndexMapping[k]=ocount;
1156 ocount++; // increment output vert count
1158 btAssert( ocount >=0 && ocount <= vcount );
1160 usedIndices[static_cast<int>(v)] = ocount; // assign new index remapping