Blender V2.61 - r43446

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 }