btConvexHull.cpp

Go to the documentation of this file.
00001 /*
00002 Stan Melax Convex Hull Computation
00003 Copyright (c) 2003-2006 Stan Melax http://www.melax.com/
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 <string.h>
00017 
00018 #include "btConvexHull.h"
00019 #include "btAlignedObjectArray.h"
00020 #include "btMinMax.h"
00021 #include "btVector3.h"
00022 
00023 
00024 
00025 template <class T>
00026 void Swap(T &a,T &b)
00027 {
00028         T tmp = a;
00029         a=b;
00030         b=tmp;
00031 }
00032 
00033 
00034 //----------------------------------
00035 
00036 class int3  
00037 {
00038 public:
00039         int x,y,z;
00040         int3(){};
00041         int3(int _x,int _y, int _z){x=_x;y=_y;z=_z;}
00042         const int& operator[](int i) const {return (&x)[i];}
00043         int& operator[](int i) {return (&x)[i];}
00044 };
00045 
00046 
00047 //------- btPlane ----------
00048 
00049 
00050 inline btPlane PlaneFlip(const btPlane &plane){return btPlane(-plane.normal,-plane.dist);}
00051 inline int operator==( const btPlane &a, const btPlane &b ) { return (a.normal==b.normal && a.dist==b.dist); }
00052 inline int coplanar( const btPlane &a, const btPlane &b ) { return (a==b || a==PlaneFlip(b)); }
00053 
00054 
00055 //--------- Utility Functions ------
00056 
00057 btVector3  PlaneLineIntersection(const btPlane &plane, const btVector3 &p0, const btVector3 &p1);
00058 btVector3  PlaneProject(const btPlane &plane, const btVector3 &point);
00059 
00060 btVector3  ThreePlaneIntersection(const btPlane &p0,const btPlane &p1, const btPlane &p2);
00061 btVector3  ThreePlaneIntersection(const btPlane &p0,const btPlane &p1, const btPlane &p2)
00062 {
00063         btVector3 N1 = p0.normal;
00064         btVector3 N2 = p1.normal;
00065         btVector3 N3 = p2.normal;
00066 
00067         btVector3 n2n3; n2n3 = N2.cross(N3);
00068         btVector3 n3n1; n3n1 = N3.cross(N1);
00069         btVector3 n1n2; n1n2 = N1.cross(N2);
00070 
00071         btScalar quotient = (N1.dot(n2n3));
00072 
00073         btAssert(btFabs(quotient) > btScalar(0.000001));
00074         
00075         quotient = btScalar(-1.) / quotient;
00076         n2n3 *= p0.dist;
00077         n3n1 *= p1.dist;
00078         n1n2 *= p2.dist;
00079         btVector3 potentialVertex = n2n3;
00080         potentialVertex += n3n1;
00081         potentialVertex += n1n2;
00082         potentialVertex *= quotient;
00083 
00084         btVector3 result(potentialVertex.getX(),potentialVertex.getY(),potentialVertex.getZ());
00085         return result;
00086 
00087 }
00088 
00089 btScalar   DistanceBetweenLines(const btVector3 &ustart, const btVector3 &udir, const btVector3 &vstart, const btVector3 &vdir, btVector3 *upoint=NULL, btVector3 *vpoint=NULL);
00090 btVector3  TriNormal(const btVector3 &v0, const btVector3 &v1, const btVector3 &v2);
00091 btVector3  NormalOf(const btVector3 *vert, const int n);
00092 
00093 
00094 btVector3 PlaneLineIntersection(const btPlane &plane, const btVector3 &p0, const btVector3 &p1)
00095 {
00096         // returns the point where the line p0-p1 intersects the plane n&d
00097                                 static btVector3 dif;
00098                 dif = p1-p0;
00099                                 btScalar dn= btDot(plane.normal,dif);
00100                                 btScalar t = -(plane.dist+btDot(plane.normal,p0) )/dn;
00101                                 return p0 + (dif*t);
00102 }
00103 
00104 btVector3 PlaneProject(const btPlane &plane, const btVector3 &point)
00105 {
00106         return point - plane.normal * (btDot(point,plane.normal)+plane.dist);
00107 }
00108 
00109 btVector3 TriNormal(const btVector3 &v0, const btVector3 &v1, const btVector3 &v2)
00110 {
00111         // return the normal of the triangle
00112         // inscribed by v0, v1, and v2
00113         btVector3 cp=btCross(v1-v0,v2-v1);
00114         btScalar m=cp.length();
00115         if(m==0) return btVector3(1,0,0);
00116         return cp*(btScalar(1.0)/m);
00117 }
00118 
00119 
00120 btScalar DistanceBetweenLines(const btVector3 &ustart, const btVector3 &udir, const btVector3 &vstart, const btVector3 &vdir, btVector3 *upoint, btVector3 *vpoint)
00121 {
00122         static btVector3 cp;
00123         cp = btCross(udir,vdir).normalized();
00124 
00125         btScalar distu = -btDot(cp,ustart);
00126         btScalar distv = -btDot(cp,vstart);
00127         btScalar dist = (btScalar)fabs(distu-distv);
00128         if(upoint) 
00129                 {
00130                 btPlane plane;
00131                 plane.normal = btCross(vdir,cp).normalized();
00132                 plane.dist = -btDot(plane.normal,vstart);
00133                 *upoint = PlaneLineIntersection(plane,ustart,ustart+udir);
00134         }
00135         if(vpoint) 
00136                 {
00137                 btPlane plane;
00138                 plane.normal = btCross(udir,cp).normalized();
00139                 plane.dist = -btDot(plane.normal,ustart);
00140                 *vpoint = PlaneLineIntersection(plane,vstart,vstart+vdir);
00141         }
00142         return dist;
00143 }
00144 
00145 
00146 
00147 
00148 
00149 
00150 
00151 #define COPLANAR   (0)
00152 #define UNDER      (1)
00153 #define OVER       (2)
00154 #define SPLIT      (OVER|UNDER)
00155 #define PAPERWIDTH (btScalar(0.001))
00156 
00157 btScalar planetestepsilon = PAPERWIDTH;
00158 
00159 
00160 
00161 typedef ConvexH::HalfEdge HalfEdge;
00162 
00163 ConvexH::ConvexH(int vertices_size,int edges_size,int facets_size)
00164 {
00165         vertices.resize(vertices_size);
00166         edges.resize(edges_size);
00167         facets.resize(facets_size);
00168 }
00169 
00170 
00171 int PlaneTest(const btPlane &p, const btVector3 &v);
00172 int PlaneTest(const btPlane &p, const btVector3 &v) {
00173         btScalar a  = btDot(v,p.normal)+p.dist;
00174         int   flag = (a>planetestepsilon)?OVER:((a<-planetestepsilon)?UNDER:COPLANAR);
00175         return flag;
00176 }
00177 
00178 int SplitTest(ConvexH &convex,const btPlane &plane);
00179 int SplitTest(ConvexH &convex,const btPlane &plane) {
00180         int flag=0;
00181         for(int i=0;i<convex.vertices.size();i++) {
00182                 flag |= PlaneTest(plane,convex.vertices[i]);
00183         }
00184         return flag;
00185 }
00186 
00187 class VertFlag
00188 {
00189 public:
00190         unsigned char planetest;
00191         unsigned char junk;
00192         unsigned char undermap;
00193         unsigned char overmap;
00194 };
00195 class EdgeFlag 
00196 {
00197 public:
00198         unsigned char planetest;
00199         unsigned char fixes;
00200         short undermap;
00201         short overmap;
00202 };
00203 class PlaneFlag
00204 {
00205 public:
00206         unsigned char undermap;
00207         unsigned char overmap;
00208 };
00209 class Coplanar{
00210 public:
00211         unsigned short ea;
00212         unsigned char v0;
00213         unsigned char v1;
00214 };
00215 
00216 
00217 
00218 
00219 
00220 
00221 
00222 
00223 template<class T>
00224 int maxdirfiltered(const T *p,int count,const T &dir,btAlignedObjectArray<int> &allow)
00225 {
00226         btAssert(count);
00227         int m=-1;
00228         for(int i=0;i<count;i++) 
00229                 if(allow[i])
00230                 {
00231                         if(m==-1 || btDot(p[i],dir)>btDot(p[m],dir))
00232                                 m=i;
00233                 }
00234         btAssert(m!=-1);
00235         return m;
00236 } 
00237 
00238 btVector3 orth(const btVector3 &v);
00239 btVector3 orth(const btVector3 &v)
00240 {
00241         btVector3 a=btCross(v,btVector3(0,0,1));
00242         btVector3 b=btCross(v,btVector3(0,1,0));
00243         if (a.length() > b.length())
00244         {
00245                 return a.normalized();
00246         } else {
00247                 return b.normalized();
00248         }
00249 }
00250 
00251 
00252 template<class T>
00253 int maxdirsterid(const T *p,int count,const T &dir,btAlignedObjectArray<int> &allow)
00254 {
00255         int m=-1;
00256         while(m==-1)
00257         {
00258                 m = maxdirfiltered(p,count,dir,allow);
00259                 if(allow[m]==3) return m;
00260                 T u = orth(dir);
00261                 T v = btCross(u,dir);
00262                 int ma=-1;
00263                 for(btScalar x = btScalar(0.0) ; x<= btScalar(360.0) ; x+= btScalar(45.0))
00264                 {
00265                         btScalar s = btSin(SIMD_RADS_PER_DEG*(x));
00266                         btScalar c = btCos(SIMD_RADS_PER_DEG*(x));
00267                         int mb = maxdirfiltered(p,count,dir+(u*s+v*c)*btScalar(0.025),allow);
00268                         if(ma==m && mb==m)
00269                         {
00270                                 allow[m]=3;
00271                                 return m;
00272                         }
00273                         if(ma!=-1 && ma!=mb)  // Yuck - this is really ugly
00274                         {
00275                                 int mc = ma;
00276                                 for(btScalar xx = x-btScalar(40.0) ; xx <= x ; xx+= btScalar(5.0))
00277                                 {
00278                                         btScalar s = btSin(SIMD_RADS_PER_DEG*(xx));
00279                                         btScalar c = btCos(SIMD_RADS_PER_DEG*(xx));
00280                                         int md = maxdirfiltered(p,count,dir+(u*s+v*c)*btScalar(0.025),allow);
00281                                         if(mc==m && md==m)
00282                                         {
00283                                                 allow[m]=3;
00284                                                 return m;
00285                                         }
00286                                         mc=md;
00287                                 }
00288                         }
00289                         ma=mb;
00290                 }
00291                 allow[m]=0;
00292                 m=-1;
00293         }
00294         btAssert(0);
00295         return m;
00296 } 
00297 
00298 
00299 
00300 
00301 int operator ==(const int3 &a,const int3 &b);
00302 int operator ==(const int3 &a,const int3 &b) 
00303 {
00304         for(int i=0;i<3;i++) 
00305         {
00306                 if(a[i]!=b[i]) return 0;
00307         }
00308         return 1;
00309 }
00310 
00311 
00312 int above(btVector3* vertices,const int3& t, const btVector3 &p, btScalar epsilon);
00313 int above(btVector3* vertices,const int3& t, const btVector3 &p, btScalar epsilon) 
00314 {
00315         btVector3 n=TriNormal(vertices[t[0]],vertices[t[1]],vertices[t[2]]);
00316         return (btDot(n,p-vertices[t[0]]) > epsilon); // EPSILON???
00317 }
00318 int hasedge(const int3 &t, int a,int b);
00319 int hasedge(const int3 &t, int a,int b)
00320 {
00321         for(int i=0;i<3;i++)
00322         {
00323                 int i1= (i+1)%3;
00324                 if(t[i]==a && t[i1]==b) return 1;
00325         }
00326         return 0;
00327 }
00328 int hasvert(const int3 &t, int v);
00329 int hasvert(const int3 &t, int v)
00330 {
00331         return (t[0]==v || t[1]==v || t[2]==v) ;
00332 }
00333 int shareedge(const int3 &a,const int3 &b);
00334 int shareedge(const int3 &a,const int3 &b)
00335 {
00336         int i;
00337         for(i=0;i<3;i++)
00338         {
00339                 int i1= (i+1)%3;
00340                 if(hasedge(a,b[i1],b[i])) return 1;
00341         }
00342         return 0;
00343 }
00344 
00345 class btHullTriangle;
00346 
00347 
00348 
00349 class btHullTriangle : public int3
00350 {
00351 public:
00352         int3 n;
00353         int id;
00354         int vmax;
00355         btScalar rise;
00356         btHullTriangle(int a,int b,int c):int3(a,b,c),n(-1,-1,-1)
00357         {
00358                 vmax=-1;
00359                 rise = btScalar(0.0);
00360         }
00361         ~btHullTriangle()
00362         {
00363         }
00364         int &neib(int a,int b);
00365 };
00366 
00367 
00368 int &btHullTriangle::neib(int a,int b)
00369 {
00370         static int er=-1;
00371         int i;
00372         for(i=0;i<3;i++) 
00373         {
00374                 int i1=(i+1)%3;
00375                 int i2=(i+2)%3;
00376                 if((*this)[i]==a && (*this)[i1]==b) return n[i2];
00377                 if((*this)[i]==b && (*this)[i1]==a) return n[i2];
00378         }
00379         btAssert(0);
00380         return er;
00381 }
00382 void HullLibrary::b2bfix(btHullTriangle* s,btHullTriangle*t)
00383 {
00384         int i;
00385         for(i=0;i<3;i++) 
00386         {
00387                 int i1=(i+1)%3;
00388                 int i2=(i+2)%3;
00389                 int a = (*s)[i1];
00390                 int b = (*s)[i2];
00391                 btAssert(m_tris[s->neib(a,b)]->neib(b,a) == s->id);
00392                 btAssert(m_tris[t->neib(a,b)]->neib(b,a) == t->id);
00393                 m_tris[s->neib(a,b)]->neib(b,a) = t->neib(b,a);
00394                 m_tris[t->neib(b,a)]->neib(a,b) = s->neib(a,b);
00395         }
00396 }
00397 
00398 void HullLibrary::removeb2b(btHullTriangle* s,btHullTriangle*t)
00399 {
00400         b2bfix(s,t);
00401         deAllocateTriangle(s);
00402 
00403         deAllocateTriangle(t);
00404 }
00405 
00406 void HullLibrary::checkit(btHullTriangle *t)
00407 {
00408         (void)t;
00409 
00410         int i;
00411         btAssert(m_tris[t->id]==t);
00412         for(i=0;i<3;i++)
00413         {
00414                 int i1=(i+1)%3;
00415                 int i2=(i+2)%3;
00416                 int a = (*t)[i1];
00417                 int b = (*t)[i2];
00418 
00419                 // release compile fix
00420                 (void)i1;
00421                 (void)i2;
00422                 (void)a;
00423                 (void)b;
00424 
00425                 btAssert(a!=b);
00426                 btAssert( m_tris[t->n[i]]->neib(b,a) == t->id);
00427         }
00428 }
00429 
00430 btHullTriangle* HullLibrary::allocateTriangle(int a,int b,int c)
00431 {
00432         void* mem = btAlignedAlloc(sizeof(btHullTriangle),16);
00433         btHullTriangle* tr = new (mem)btHullTriangle(a,b,c);
00434         tr->id = m_tris.size();
00435         m_tris.push_back(tr);
00436 
00437         return tr;
00438 }
00439 
00440 void    HullLibrary::deAllocateTriangle(btHullTriangle* tri)
00441 {
00442         btAssert(m_tris[tri->id]==tri);
00443         m_tris[tri->id]=NULL;
00444         tri->~btHullTriangle();
00445         btAlignedFree(tri);
00446 }
00447 
00448 
00449 void HullLibrary::extrude(btHullTriangle *t0,int v)
00450 {
00451         int3 t= *t0;
00452         int n = m_tris.size();
00453         btHullTriangle* ta = allocateTriangle(v,t[1],t[2]);
00454         ta->n = int3(t0->n[0],n+1,n+2);
00455         m_tris[t0->n[0]]->neib(t[1],t[2]) = n+0;
00456         btHullTriangle* tb = allocateTriangle(v,t[2],t[0]);
00457         tb->n = int3(t0->n[1],n+2,n+0);
00458         m_tris[t0->n[1]]->neib(t[2],t[0]) = n+1;
00459         btHullTriangle* tc = allocateTriangle(v,t[0],t[1]);
00460         tc->n = int3(t0->n[2],n+0,n+1);
00461         m_tris[t0->n[2]]->neib(t[0],t[1]) = n+2;
00462         checkit(ta);
00463         checkit(tb);
00464         checkit(tc);
00465         if(hasvert(*m_tris[ta->n[0]],v)) removeb2b(ta,m_tris[ta->n[0]]);
00466         if(hasvert(*m_tris[tb->n[0]],v)) removeb2b(tb,m_tris[tb->n[0]]);
00467         if(hasvert(*m_tris[tc->n[0]],v)) removeb2b(tc,m_tris[tc->n[0]]);
00468         deAllocateTriangle(t0);
00469 
00470 }
00471 
00472 btHullTriangle* HullLibrary::extrudable(btScalar epsilon)
00473 {
00474         int i;
00475         btHullTriangle *t=NULL;
00476         for(i=0;i<m_tris.size();i++)
00477         {
00478                 if(!t || (m_tris[i] && t->rise<m_tris[i]->rise))
00479                 {
00480                         t = m_tris[i];
00481                 }
00482         }
00483         return (t->rise >epsilon)?t:NULL ;
00484 }
00485 
00486 
00487 
00488 
00489 int4 HullLibrary::FindSimplex(btVector3 *verts,int verts_count,btAlignedObjectArray<int> &allow)
00490 {
00491         btVector3 basis[3];
00492         basis[0] = btVector3( btScalar(0.01), btScalar(0.02), btScalar(1.0) );      
00493         int p0 = maxdirsterid(verts,verts_count, basis[0],allow);   
00494         int     p1 = maxdirsterid(verts,verts_count,-basis[0],allow);
00495         basis[0] = verts[p0]-verts[p1];
00496         if(p0==p1 || basis[0]==btVector3(0,0,0)) 
00497                 return int4(-1,-1,-1,-1);
00498         basis[1] = btCross(btVector3(     btScalar(1),btScalar(0.02), btScalar(0)),basis[0]);
00499         basis[2] = btCross(btVector3(btScalar(-0.02),     btScalar(1), btScalar(0)),basis[0]);
00500         if (basis[1].length() > basis[2].length())
00501         {
00502                 basis[1].normalize();
00503         } else {
00504                 basis[1] = basis[2];
00505                 basis[1].normalize ();
00506         }
00507         int p2 = maxdirsterid(verts,verts_count,basis[1],allow);
00508         if(p2 == p0 || p2 == p1)
00509         {
00510                 p2 = maxdirsterid(verts,verts_count,-basis[1],allow);
00511         }
00512         if(p2 == p0 || p2 == p1) 
00513                 return int4(-1,-1,-1,-1);
00514         basis[1] = verts[p2] - verts[p0];
00515         basis[2] = btCross(basis[1],basis[0]).normalized();
00516         int p3 = maxdirsterid(verts,verts_count,basis[2],allow);
00517         if(p3==p0||p3==p1||p3==p2) p3 = maxdirsterid(verts,verts_count,-basis[2],allow);
00518         if(p3==p0||p3==p1||p3==p2) 
00519                 return int4(-1,-1,-1,-1);
00520         btAssert(!(p0==p1||p0==p2||p0==p3||p1==p2||p1==p3||p2==p3));
00521         if(btDot(verts[p3]-verts[p0],btCross(verts[p1]-verts[p0],verts[p2]-verts[p0])) <0) {Swap(p2,p3);}
00522         return int4(p0,p1,p2,p3);
00523 }
00524 
00525 int HullLibrary::calchullgen(btVector3 *verts,int verts_count, int vlimit)
00526 {
00527         if(verts_count <4) return 0;
00528         if(vlimit==0) vlimit=1000000000;
00529         int j;
00530         btVector3 bmin(*verts),bmax(*verts);
00531         btAlignedObjectArray<int> isextreme;
00532         isextreme.reserve(verts_count);
00533         btAlignedObjectArray<int> allow;
00534         allow.reserve(verts_count);
00535 
00536         for(j=0;j<verts_count;j++) 
00537         {
00538                 allow.push_back(1);
00539                 isextreme.push_back(0);
00540                 bmin.setMin (verts[j]);
00541                 bmax.setMax (verts[j]);
00542         }
00543         btScalar epsilon = (bmax-bmin).length() * btScalar(0.001);
00544         btAssert (epsilon != 0.0);
00545 
00546 
00547         int4 p = FindSimplex(verts,verts_count,allow);
00548         if(p.x==-1) return 0; // simplex failed
00549 
00550 
00551 
00552         btVector3 center = (verts[p[0]]+verts[p[1]]+verts[p[2]]+verts[p[3]]) / btScalar(4.0);  // a valid interior point
00553         btHullTriangle *t0 = allocateTriangle(p[2],p[3],p[1]); t0->n=int3(2,3,1);
00554         btHullTriangle *t1 = allocateTriangle(p[3],p[2],p[0]); t1->n=int3(3,2,0);
00555         btHullTriangle *t2 = allocateTriangle(p[0],p[1],p[3]); t2->n=int3(0,1,3);
00556         btHullTriangle *t3 = allocateTriangle(p[1],p[0],p[2]); t3->n=int3(1,0,2);
00557         isextreme[p[0]]=isextreme[p[1]]=isextreme[p[2]]=isextreme[p[3]]=1;
00558         checkit(t0);checkit(t1);checkit(t2);checkit(t3);
00559 
00560         for(j=0;j<m_tris.size();j++)
00561         {
00562                 btHullTriangle *t=m_tris[j];
00563                 btAssert(t);
00564                 btAssert(t->vmax<0);
00565                 btVector3 n=TriNormal(verts[(*t)[0]],verts[(*t)[1]],verts[(*t)[2]]);
00566                 t->vmax = maxdirsterid(verts,verts_count,n,allow);
00567                 t->rise = btDot(n,verts[t->vmax]-verts[(*t)[0]]);
00568         }
00569         btHullTriangle *te;
00570         vlimit-=4;
00571         while(vlimit >0 && ((te=extrudable(epsilon)) != 0))
00572         {
00573                 int3 ti=*te;
00574                 int v=te->vmax;
00575                 btAssert(v != -1);
00576                 btAssert(!isextreme[v]);  // wtf we've already done this vertex
00577                 isextreme[v]=1;
00578                 //if(v==p0 || v==p1 || v==p2 || v==p3) continue; // done these already
00579                 j=m_tris.size();
00580                 while(j--) {
00581                         if(!m_tris[j]) continue;
00582                         int3 t=*m_tris[j];
00583                         if(above(verts,t,verts[v],btScalar(0.01)*epsilon)) 
00584                         {
00585                                 extrude(m_tris[j],v);
00586                         }
00587                 }
00588                 // now check for those degenerate cases where we have a flipped triangle or a really skinny triangle
00589                 j=m_tris.size();
00590                 while(j--)
00591                 {
00592                         if(!m_tris[j]) continue;
00593                         if(!hasvert(*m_tris[j],v)) break;
00594                         int3 nt=*m_tris[j];
00595                         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) )
00596                         {
00597                                 btHullTriangle *nb = m_tris[m_tris[j]->n[0]];
00598                                 btAssert(nb);btAssert(!hasvert(*nb,v));btAssert(nb->id<j);
00599                                 extrude(nb,v);
00600                                 j=m_tris.size(); 
00601                         }
00602                 } 
00603                 j=m_tris.size();
00604                 while(j--)
00605                 {
00606                         btHullTriangle *t=m_tris[j];
00607                         if(!t) continue;
00608                         if(t->vmax>=0) break;
00609                         btVector3 n=TriNormal(verts[(*t)[0]],verts[(*t)[1]],verts[(*t)[2]]);
00610                         t->vmax = maxdirsterid(verts,verts_count,n,allow);
00611                         if(isextreme[t->vmax]) 
00612                         {
00613                                 t->vmax=-1; // already done that vertex - algorithm needs to be able to terminate.
00614                         }
00615                         else
00616                         {
00617                                 t->rise = btDot(n,verts[t->vmax]-verts[(*t)[0]]);
00618                         }
00619                 }
00620                 vlimit --;
00621         }
00622         return 1;
00623 }
00624 
00625 int HullLibrary::calchull(btVector3 *verts,int verts_count, TUIntArray& tris_out, int &tris_count,int vlimit) 
00626 {
00627         int rc=calchullgen(verts,verts_count,  vlimit) ;
00628         if(!rc) return 0;
00629         btAlignedObjectArray<int> ts;
00630         int i;
00631 
00632         for(i=0;i<m_tris.size();i++)
00633         {
00634                 if(m_tris[i])
00635                 {
00636                         for(int j=0;j<3;j++)
00637                                 ts.push_back((*m_tris[i])[j]);
00638                         deAllocateTriangle(m_tris[i]);
00639                 }
00640         }
00641         tris_count = ts.size()/3;
00642         tris_out.resize(ts.size());
00643         
00644         for (i=0;i<ts.size();i++)
00645         {
00646                 tris_out[i] = static_cast<unsigned int>(ts[i]);
00647         }
00648         m_tris.resize(0);
00649 
00650         return 1;
00651 }
00652 
00653 
00654 
00655 
00656 
00657 bool HullLibrary::ComputeHull(unsigned int vcount,const btVector3 *vertices,PHullResult &result,unsigned int vlimit)
00658 {
00659         
00660         int    tris_count;
00661         int ret = calchull( (btVector3 *) vertices, (int) vcount, result.m_Indices, tris_count, static_cast<int>(vlimit) );
00662         if(!ret) return false;
00663         result.mIndexCount = (unsigned int) (tris_count*3);
00664         result.mFaceCount  = (unsigned int) tris_count;
00665         result.mVertices   = (btVector3*) vertices;
00666         result.mVcount     = (unsigned int) vcount;
00667         return true;
00668 
00669 }
00670 
00671 
00672 void ReleaseHull(PHullResult &result);
00673 void ReleaseHull(PHullResult &result)
00674 {
00675         if ( result.m_Indices.size() )
00676         {
00677                 result.m_Indices.clear();
00678         }
00679 
00680         result.mVcount = 0;
00681         result.mIndexCount = 0;
00682         result.mVertices = 0;
00683 }
00684 
00685 
00686 //*********************************************************************
00687 //*********************************************************************
00688 //********  HullLib header
00689 //*********************************************************************
00690 //*********************************************************************
00691 
00692 //*********************************************************************
00693 //*********************************************************************
00694 //********  HullLib implementation
00695 //*********************************************************************
00696 //*********************************************************************
00697 
00698 HullError HullLibrary::CreateConvexHull(const HullDesc       &desc,           // describes the input request
00699                                                                                                                                                                         HullResult           &result)         // contains the resulst
00700 {
00701         HullError ret = QE_FAIL;
00702 
00703 
00704         PHullResult hr;
00705 
00706         unsigned int vcount = desc.mVcount;
00707         if ( vcount < 8 ) vcount = 8;
00708 
00709         btAlignedObjectArray<btVector3> vertexSource;
00710         vertexSource.resize(static_cast<int>(vcount));
00711 
00712         btVector3 scale;
00713 
00714         unsigned int ovcount;
00715 
00716         bool ok = CleanupVertices(desc.mVcount,desc.mVertices, desc.mVertexStride, ovcount, &vertexSource[0], desc.mNormalEpsilon, scale ); // normalize point cloud, remove duplicates!
00717 
00718         if ( ok )
00719         {
00720 
00721 
00722 //              if ( 1 ) // scale vertices back to their original size.
00723                 {
00724                         for (unsigned int i=0; i<ovcount; i++)
00725                         {
00726                                 btVector3& v = vertexSource[static_cast<int>(i)];
00727                                 v[0]*=scale[0];
00728                                 v[1]*=scale[1];
00729                                 v[2]*=scale[2];
00730                         }
00731                 }
00732 
00733                 ok = ComputeHull(ovcount,&vertexSource[0],hr,desc.mMaxVertices);
00734 
00735                 if ( ok )
00736                 {
00737 
00738                         // re-index triangle mesh so it refers to only used vertices, rebuild a new vertex table.
00739                         btAlignedObjectArray<btVector3> vertexScratch;
00740                         vertexScratch.resize(static_cast<int>(hr.mVcount));
00741 
00742                         BringOutYourDead(hr.mVertices,hr.mVcount, &vertexScratch[0], ovcount, &hr.m_Indices[0], hr.mIndexCount );
00743 
00744                         ret = QE_OK;
00745 
00746                         if ( desc.HasHullFlag(QF_TRIANGLES) ) // if he wants the results as triangle!
00747                         {
00748                                 result.mPolygons          = false;
00749                                 result.mNumOutputVertices = ovcount;
00750                                 result.m_OutputVertices.resize(static_cast<int>(ovcount));
00751                                 result.mNumFaces          = hr.mFaceCount;
00752                                 result.mNumIndices        = hr.mIndexCount;
00753 
00754                                 result.m_Indices.resize(static_cast<int>(hr.mIndexCount));
00755 
00756                                 memcpy(&result.m_OutputVertices[0], &vertexScratch[0], sizeof(btVector3)*ovcount );
00757 
00758                         if ( desc.HasHullFlag(QF_REVERSE_ORDER) )
00759                                 {
00760 
00761                                         const unsigned int *source = &hr.m_Indices[0];
00762                                         unsigned int *dest   = &result.m_Indices[0];
00763 
00764                                         for (unsigned int i=0; i<hr.mFaceCount; i++)
00765                                         {
00766                                                 dest[0] = source[2];
00767                                                 dest[1] = source[1];
00768                                                 dest[2] = source[0];
00769                                                 dest+=3;
00770                                                 source+=3;
00771                                         }
00772 
00773                                 }
00774                                 else
00775                                 {
00776                                         memcpy(&result.m_Indices[0], &hr.m_Indices[0], sizeof(unsigned int)*hr.mIndexCount);
00777                                 }
00778                         }
00779                         else
00780                         {
00781                                 result.mPolygons          = true;
00782                                 result.mNumOutputVertices = ovcount;
00783                                 result.m_OutputVertices.resize(static_cast<int>(ovcount));
00784                                 result.mNumFaces          = hr.mFaceCount;
00785                                 result.mNumIndices        = hr.mIndexCount+hr.mFaceCount;
00786                                 result.m_Indices.resize(static_cast<int>(result.mNumIndices));
00787                                 memcpy(&result.m_OutputVertices[0], &vertexScratch[0], sizeof(btVector3)*ovcount );
00788 
00789 //                              if ( 1 )
00790                                 {
00791                                         const unsigned int *source = &hr.m_Indices[0];
00792                                         unsigned int *dest   = &result.m_Indices[0];
00793                                         for (unsigned int i=0; i<hr.mFaceCount; i++)
00794                                         {
00795                                                 dest[0] = 3;
00796                                                 if ( desc.HasHullFlag(QF_REVERSE_ORDER) )
00797                                                 {
00798                                                         dest[1] = source[2];
00799                                                         dest[2] = source[1];
00800                                                         dest[3] = source[0];
00801                                                 }
00802                                                 else
00803                                                 {
00804                                                         dest[1] = source[0];
00805                                                         dest[2] = source[1];
00806                                                         dest[3] = source[2];
00807                                                 }
00808 
00809                                                 dest+=4;
00810                                                 source+=3;
00811                                         }
00812                                 }
00813                         }
00814                         ReleaseHull(hr);
00815                 }
00816         }
00817 
00818         return ret;
00819 }
00820 
00821 
00822 
00823 HullError HullLibrary::ReleaseResult(HullResult &result) // release memory allocated for this result, we are done with it.
00824 {
00825         if ( result.m_OutputVertices.size())
00826         {
00827                 result.mNumOutputVertices=0;
00828                 result.m_OutputVertices.clear();
00829         }
00830         if ( result.m_Indices.size() )
00831         {
00832                 result.mNumIndices=0;
00833                 result.m_Indices.clear();
00834         }
00835         return QE_OK;
00836 }
00837 
00838 
00839 static void addPoint(unsigned int &vcount,btVector3 *p,btScalar x,btScalar y,btScalar z)
00840 {
00841         // XXX, might be broken
00842         btVector3& dest = p[vcount];
00843         dest[0] = x;
00844         dest[1] = y;
00845         dest[2] = z;
00846         vcount++;
00847 }
00848 
00849 btScalar GetDist(btScalar px,btScalar py,btScalar pz,const btScalar *p2);
00850 btScalar GetDist(btScalar px,btScalar py,btScalar pz,const btScalar *p2)
00851 {
00852 
00853         btScalar dx = px - p2[0];
00854         btScalar dy = py - p2[1];
00855         btScalar dz = pz - p2[2];
00856 
00857         return dx*dx+dy*dy+dz*dz;
00858 }
00859 
00860 
00861 
00862 bool  HullLibrary::CleanupVertices(unsigned int svcount,
00863                                    const btVector3 *svertices,
00864                                    unsigned int stride,
00865                                    unsigned int &vcount,       // output number of vertices
00866                                    btVector3 *vertices,                 // location to store the results.
00867                                    btScalar  normalepsilon,
00868                                    btVector3& scale)
00869 {
00870         if ( svcount == 0 ) return false;
00871 
00872         m_vertexIndexMapping.resize(0);
00873 
00874 
00875 #define EPSILON btScalar(0.000001) /* close enough to consider two btScalaring point numbers to be 'the same'. */
00876 
00877         vcount = 0;
00878 
00879         btScalar recip[3]={0.f,0.f,0.f};
00880 
00881         if ( scale )
00882         {
00883                 scale[0] = 1;
00884                 scale[1] = 1;
00885                 scale[2] = 1;
00886         }
00887 
00888         btScalar bmin[3] = {  FLT_MAX,  FLT_MAX,  FLT_MAX };
00889         btScalar bmax[3] = { -FLT_MAX, -FLT_MAX, -FLT_MAX };
00890 
00891         const char *vtx = (const char *) svertices;
00892 
00893 //      if ( 1 )
00894         {
00895                 for (unsigned int i=0; i<svcount; i++)
00896                 {
00897                         const btScalar *p = (const btScalar *) vtx;
00898 
00899                         vtx+=stride;
00900 
00901                         for (int j=0; j<3; j++)
00902                         {
00903                                 if ( p[j] < bmin[j] ) bmin[j] = p[j];
00904                                 if ( p[j] > bmax[j] ) bmax[j] = p[j];
00905                         }
00906                 }
00907         }
00908 
00909         btScalar dx = bmax[0] - bmin[0];
00910         btScalar dy = bmax[1] - bmin[1];
00911         btScalar dz = bmax[2] - bmin[2];
00912 
00913         btVector3 center;
00914 
00915         center[0] = dx*btScalar(0.5) + bmin[0];
00916         center[1] = dy*btScalar(0.5) + bmin[1];
00917         center[2] = dz*btScalar(0.5) + bmin[2];
00918 
00919         if ( dx < EPSILON || dy < EPSILON || dz < EPSILON || svcount < 3 )
00920         {
00921 
00922                 btScalar len = FLT_MAX;
00923 
00924                 if ( dx > EPSILON && dx < len ) len = dx;
00925                 if ( dy > EPSILON && dy < len ) len = dy;
00926                 if ( dz > EPSILON && dz < len ) len = dz;
00927 
00928                 if ( len == FLT_MAX )
00929                 {
00930                         dx = dy = dz = btScalar(0.01); // one centimeter
00931                 }
00932                 else
00933                 {
00934                         if ( dx < EPSILON ) dx = len * btScalar(0.05); // 1/5th the shortest non-zero edge.
00935                         if ( dy < EPSILON ) dy = len * btScalar(0.05);
00936                         if ( dz < EPSILON ) dz = len * btScalar(0.05);
00937                 }
00938 
00939                 btScalar x1 = center[0] - dx;
00940                 btScalar x2 = center[0] + dx;
00941 
00942                 btScalar y1 = center[1] - dy;
00943                 btScalar y2 = center[1] + dy;
00944 
00945                 btScalar z1 = center[2] - dz;
00946                 btScalar z2 = center[2] + dz;
00947 
00948                 addPoint(vcount,vertices,x1,y1,z1);
00949                 addPoint(vcount,vertices,x2,y1,z1);
00950                 addPoint(vcount,vertices,x2,y2,z1);
00951                 addPoint(vcount,vertices,x1,y2,z1);
00952                 addPoint(vcount,vertices,x1,y1,z2);
00953                 addPoint(vcount,vertices,x2,y1,z2);
00954                 addPoint(vcount,vertices,x2,y2,z2);
00955                 addPoint(vcount,vertices,x1,y2,z2);
00956 
00957                 return true; // return cube
00958 
00959 
00960         }
00961         else
00962         {
00963                 if ( scale )
00964                 {
00965                         scale[0] = dx;
00966                         scale[1] = dy;
00967                         scale[2] = dz;
00968 
00969                         recip[0] = 1 / dx;
00970                         recip[1] = 1 / dy;
00971                         recip[2] = 1 / dz;
00972 
00973                         center[0]*=recip[0];
00974                         center[1]*=recip[1];
00975                         center[2]*=recip[2];
00976 
00977                 }
00978 
00979         }
00980 
00981 
00982 
00983         vtx = (const char *) svertices;
00984 
00985         for (unsigned int i=0; i<svcount; i++)
00986         {
00987                 const btVector3 *p = (const btVector3 *)vtx;
00988                 vtx+=stride;
00989 
00990                 btScalar px = p->getX();
00991                 btScalar py = p->getY();
00992                 btScalar pz = p->getZ();
00993 
00994                 if ( scale )
00995                 {
00996                         px = px*recip[0]; // normalize
00997                         py = py*recip[1]; // normalize
00998                         pz = pz*recip[2]; // normalize
00999                 }
01000 
01001 //              if ( 1 )
01002                 {
01003                         unsigned int j;
01004 
01005                         for (j=0; j<vcount; j++)
01006                         {
01008                                 btVector3& v = vertices[j];
01009 
01010                                 btScalar x = v[0];
01011                                 btScalar y = v[1];
01012                                 btScalar z = v[2];
01013 
01014                                 btScalar dx = btFabs(x - px );
01015                                 btScalar dy = btFabs(y - py );
01016                                 btScalar dz = btFabs(z - pz );
01017 
01018                                 if ( dx < normalepsilon && dy < normalepsilon && dz < normalepsilon )
01019                                 {
01020                                         // ok, it is close enough to the old one
01021                                         // now let us see if it is further from the center of the point cloud than the one we already recorded.
01022                                         // in which case we keep this one instead.
01023 
01024                                         btScalar dist1 = GetDist(px,py,pz,center);
01025                                         btScalar dist2 = GetDist(v[0],v[1],v[2],center);
01026 
01027                                         if ( dist1 > dist2 )
01028                                         {
01029                                                 v[0] = px;
01030                                                 v[1] = py;
01031                                                 v[2] = pz;
01032                                                 
01033                                         }
01034 
01035                                         break;
01036                                 }
01037                         }
01038 
01039                         if ( j == vcount )
01040                         {
01041                                 btVector3& dest = vertices[vcount];
01042                                 dest[0] = px;
01043                                 dest[1] = py;
01044                                 dest[2] = pz;
01045                                 vcount++;
01046                         }
01047                         m_vertexIndexMapping.push_back(j);
01048                 }
01049         }
01050 
01051         // ok..now make sure we didn't prune so many vertices it is now invalid.
01052 //      if ( 1 )
01053         {
01054                 btScalar bmin[3] = {  FLT_MAX,  FLT_MAX,  FLT_MAX };
01055                 btScalar bmax[3] = { -FLT_MAX, -FLT_MAX, -FLT_MAX };
01056 
01057                 for (unsigned int i=0; i<vcount; i++)
01058                 {
01059                         const btVector3& p = vertices[i];
01060                         for (int j=0; j<3; j++)
01061                         {
01062                                 if ( p[j] < bmin[j] ) bmin[j] = p[j];
01063                                 if ( p[j] > bmax[j] ) bmax[j] = p[j];
01064                         }
01065                 }
01066 
01067                 btScalar dx = bmax[0] - bmin[0];
01068                 btScalar dy = bmax[1] - bmin[1];
01069                 btScalar dz = bmax[2] - bmin[2];
01070 
01071                 if ( dx < EPSILON || dy < EPSILON || dz < EPSILON || vcount < 3)
01072                 {
01073                         btScalar cx = dx*btScalar(0.5) + bmin[0];
01074                         btScalar cy = dy*btScalar(0.5) + bmin[1];
01075                         btScalar cz = dz*btScalar(0.5) + bmin[2];
01076 
01077                         btScalar len = FLT_MAX;
01078 
01079                         if ( dx >= EPSILON && dx < len ) len = dx;
01080                         if ( dy >= EPSILON && dy < len ) len = dy;
01081                         if ( dz >= EPSILON && dz < len ) len = dz;
01082 
01083                         if ( len == FLT_MAX )
01084                         {
01085                                 dx = dy = dz = btScalar(0.01); // one centimeter
01086                         }
01087                         else
01088                         {
01089                                 if ( dx < EPSILON ) dx = len * btScalar(0.05); // 1/5th the shortest non-zero edge.
01090                                 if ( dy < EPSILON ) dy = len * btScalar(0.05);
01091                                 if ( dz < EPSILON ) dz = len * btScalar(0.05);
01092                         }
01093 
01094                         btScalar x1 = cx - dx;
01095                         btScalar x2 = cx + dx;
01096 
01097                         btScalar y1 = cy - dy;
01098                         btScalar y2 = cy + dy;
01099 
01100                         btScalar z1 = cz - dz;
01101                         btScalar z2 = cz + dz;
01102 
01103                         vcount = 0; // add box
01104 
01105                         addPoint(vcount,vertices,x1,y1,z1);
01106                         addPoint(vcount,vertices,x2,y1,z1);
01107                         addPoint(vcount,vertices,x2,y2,z1);
01108                         addPoint(vcount,vertices,x1,y2,z1);
01109                         addPoint(vcount,vertices,x1,y1,z2);
01110                         addPoint(vcount,vertices,x2,y1,z2);
01111                         addPoint(vcount,vertices,x2,y2,z2);
01112                         addPoint(vcount,vertices,x1,y2,z2);
01113 
01114                         return true;
01115                 }
01116         }
01117 
01118         return true;
01119 }
01120 
01121 void HullLibrary::BringOutYourDead(const btVector3* verts,unsigned int vcount, btVector3* overts,unsigned int &ocount,unsigned int *indices,unsigned indexcount)
01122 {
01123         btAlignedObjectArray<int>tmpIndices;
01124         tmpIndices.resize(m_vertexIndexMapping.size());
01125         int i;
01126 
01127         for (i=0;i<m_vertexIndexMapping.size();i++)
01128         {
01129                 tmpIndices[i] = m_vertexIndexMapping[i];
01130         }
01131 
01132         TUIntArray usedIndices;
01133         usedIndices.resize(static_cast<int>(vcount));
01134         memset(&usedIndices[0],0,sizeof(unsigned int)*vcount);
01135 
01136         ocount = 0;
01137 
01138         for (i=0; i<int (indexcount); i++)
01139         {
01140                 unsigned int v = indices[i]; // original array index
01141 
01142                 btAssert( v >= 0 && v < vcount );
01143 
01144                 if ( usedIndices[static_cast<int>(v)] ) // if already remapped
01145                 {
01146                         indices[i] = usedIndices[static_cast<int>(v)]-1; // index to new array
01147                 }
01148                 else
01149                 {
01150 
01151                         indices[i] = ocount;      // new index mapping
01152 
01153                         overts[ocount][0] = verts[v][0]; // copy old vert to new vert array
01154                         overts[ocount][1] = verts[v][1];
01155                         overts[ocount][2] = verts[v][2];
01156 
01157                         for (int k=0;k<m_vertexIndexMapping.size();k++)
01158                         {
01159                                 if (tmpIndices[k]==int(v))
01160                                         m_vertexIndexMapping[k]=ocount;
01161                         }
01162 
01163                         ocount++; // increment output vert count
01164 
01165                         btAssert( ocount >=0 && ocount <= vcount );
01166 
01167                         usedIndices[static_cast<int>(v)] = ocount; // assign new index remapping
01168 
01169                 
01170                 }
01171         }
01172 
01173         
01174 }

Generated on Mon Feb 15 22:17:03 2010 for Bullet Collision Detection & Physics Library by  doxygen 1.6.1