Blender V2.61 - r43446
|
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 }