25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

1189 lines
28 KiB

  1. /*
  2. Stan Melax Convex Hull Computation
  3. Copyright (c) 2003-2006 Stan Melax http://www.melax.com/
  4. This software is provided 'as-is', without any express or implied warranty.
  5. In no event will the authors be held liable for any damages arising from the use of this software.
  6. Permission is granted to anyone to use this software for any purpose,
  7. including commercial applications, and to alter it and redistribute it freely,
  8. subject to the following restrictions:
  9. 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.
  10. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
  11. 3. This notice may not be removed or altered from any source distribution.
  12. */
  13. #include <string.h>
  14. #include "btConvexHull.h"
  15. #include "btAlignedObjectArray.h"
  16. #include "btMinMax.h"
  17. #include "btVector3.h"
  18. template <class T>
  19. void Swap(T &a,T &b)
  20. {
  21. T tmp = a;
  22. a=b;
  23. b=tmp;
  24. }
  25. //----------------------------------
  26. class int3
  27. {
  28. public:
  29. int x,y,z;
  30. int3(){};
  31. int3(int _x,int _y, int _z){x=_x;y=_y;z=_z;}
  32. const int& operator[](int i) const {return (&x)[i];}
  33. int& operator[](int i) {return (&x)[i];}
  34. };
  35. //------- btPlane ----------
  36. inline btPlane PlaneFlip(const btPlane &plane){return btPlane(-plane.normal,-plane.dist);}
  37. inline int operator==( const btPlane &a, const btPlane &b ) { return (a.normal==b.normal && a.dist==b.dist); }
  38. inline int coplanar( const btPlane &a, const btPlane &b ) { return (a==b || a==PlaneFlip(b)); }
  39. //--------- Utility Functions ------
  40. btVector3 PlaneLineIntersection(const btPlane &plane, const btVector3 &p0, const btVector3 &p1);
  41. btVector3 PlaneProject(const btPlane &plane, const btVector3 &point);
  42. btVector3 ThreePlaneIntersection(const btPlane &p0,const btPlane &p1, const btPlane &p2);
  43. btVector3 ThreePlaneIntersection(const btPlane &p0,const btPlane &p1, const btPlane &p2)
  44. {
  45. btVector3 N1 = p0.normal;
  46. btVector3 N2 = p1.normal;
  47. btVector3 N3 = p2.normal;
  48. btVector3 n2n3; n2n3 = N2.cross(N3);
  49. btVector3 n3n1; n3n1 = N3.cross(N1);
  50. btVector3 n1n2; n1n2 = N1.cross(N2);
  51. btScalar quotient = (N1.dot(n2n3));
  52. btAssert(btFabs(quotient) > btScalar(0.000001));
  53. quotient = btScalar(-1.) / quotient;
  54. n2n3 *= p0.dist;
  55. n3n1 *= p1.dist;
  56. n1n2 *= p2.dist;
  57. btVector3 potentialVertex = n2n3;
  58. potentialVertex += n3n1;
  59. potentialVertex += n1n2;
  60. potentialVertex *= quotient;
  61. btVector3 result(potentialVertex.getX(),potentialVertex.getY(),potentialVertex.getZ());
  62. return result;
  63. }
  64. btScalar DistanceBetweenLines(const btVector3 &ustart, const btVector3 &udir, const btVector3 &vstart, const btVector3 &vdir, btVector3 *upoint=NULL, btVector3 *vpoint=NULL);
  65. btVector3 TriNormal(const btVector3 &v0, const btVector3 &v1, const btVector3 &v2);
  66. btVector3 NormalOf(const btVector3 *vert, const int n);
  67. btVector3 PlaneLineIntersection(const btPlane &plane, const btVector3 &p0, const btVector3 &p1)
  68. {
  69. // returns the point where the line p0-p1 intersects the plane n&d
  70. static btVector3 dif;
  71. dif = p1-p0;
  72. btScalar dn= btDot(plane.normal,dif);
  73. btScalar t = -(plane.dist+btDot(plane.normal,p0) )/dn;
  74. return p0 + (dif*t);
  75. }
  76. btVector3 PlaneProject(const btPlane &plane, const btVector3 &point)
  77. {
  78. return point - plane.normal * (btDot(point,plane.normal)+plane.dist);
  79. }
  80. btVector3 TriNormal(const btVector3 &v0, const btVector3 &v1, const btVector3 &v2)
  81. {
  82. // return the normal of the triangle
  83. // inscribed by v0, v1, and v2
  84. btVector3 cp=btCross(v1-v0,v2-v1);
  85. btScalar m=cp.length();
  86. if(m==0) return btVector3(1,0,0);
  87. return cp*(btScalar(1.0)/m);
  88. }
  89. btScalar DistanceBetweenLines(const btVector3 &ustart, const btVector3 &udir, const btVector3 &vstart, const btVector3 &vdir, btVector3 *upoint, btVector3 *vpoint)
  90. {
  91. static btVector3 cp;
  92. cp = btCross(udir,vdir).normalized();
  93. btScalar distu = -btDot(cp,ustart);
  94. btScalar distv = -btDot(cp,vstart);
  95. btScalar dist = (btScalar)fabs(distu-distv);
  96. if(upoint)
  97. {
  98. btPlane plane;
  99. plane.normal = btCross(vdir,cp).normalized();
  100. plane.dist = -btDot(plane.normal,vstart);
  101. *upoint = PlaneLineIntersection(plane,ustart,ustart+udir);
  102. }
  103. if(vpoint)
  104. {
  105. btPlane plane;
  106. plane.normal = btCross(udir,cp).normalized();
  107. plane.dist = -btDot(plane.normal,ustart);
  108. *vpoint = PlaneLineIntersection(plane,vstart,vstart+vdir);
  109. }
  110. return dist;
  111. }
  112. #define COPLANAR (0)
  113. #define UNDER (1)
  114. #define OVER (2)
  115. #define SPLIT (OVER|UNDER)
  116. #define PAPERWIDTH (btScalar(0.001))
  117. btScalar planetestepsilon = PAPERWIDTH;
  118. typedef ConvexH::HalfEdge HalfEdge;
  119. ConvexH::ConvexH(int vertices_size,int edges_size,int facets_size)
  120. {
  121. vertices.resize(vertices_size);
  122. edges.resize(edges_size);
  123. facets.resize(facets_size);
  124. }
  125. int PlaneTest(const btPlane &p, const btVector3 &v);
  126. int PlaneTest(const btPlane &p, const btVector3 &v) {
  127. btScalar a = btDot(v,p.normal)+p.dist;
  128. int flag = (a>planetestepsilon)?OVER:((a<-planetestepsilon)?UNDER:COPLANAR);
  129. return flag;
  130. }
  131. int SplitTest(ConvexH &convex,const btPlane &plane);
  132. int SplitTest(ConvexH &convex,const btPlane &plane) {
  133. int flag=0;
  134. for(int i=0;i<convex.vertices.size();i++) {
  135. flag |= PlaneTest(plane,convex.vertices[i]);
  136. }
  137. return flag;
  138. }
  139. class VertFlag
  140. {
  141. public:
  142. unsigned char planetest;
  143. unsigned char junk;
  144. unsigned char undermap;
  145. unsigned char overmap;
  146. };
  147. class EdgeFlag
  148. {
  149. public:
  150. unsigned char planetest;
  151. unsigned char fixes;
  152. short undermap;
  153. short overmap;
  154. };
  155. class PlaneFlag
  156. {
  157. public:
  158. unsigned char undermap;
  159. unsigned char overmap;
  160. };
  161. class Coplanar{
  162. public:
  163. unsigned short ea;
  164. unsigned char v0;
  165. unsigned char v1;
  166. };
  167. template<class T>
  168. int maxdirfiltered(const T *p,int count,const T &dir,btAlignedObjectArray<int> &allow)
  169. {
  170. btAssert(count);
  171. int m=-1;
  172. for(int i=0;i<count;i++)
  173. if(allow[i])
  174. {
  175. if(m==-1 || btDot(p[i],dir)>btDot(p[m],dir))
  176. m=i;
  177. }
  178. btAssert(m!=-1);
  179. return m;
  180. }
  181. btVector3 orth(const btVector3 &v);
  182. btVector3 orth(const btVector3 &v)
  183. {
  184. btVector3 a=btCross(v,btVector3(0,0,1));
  185. btVector3 b=btCross(v,btVector3(0,1,0));
  186. if (a.length() > b.length())
  187. {
  188. return a.normalized();
  189. } else {
  190. return b.normalized();
  191. }
  192. }
  193. template<class T>
  194. int maxdirsterid(const T *p,int count,const T &dir,btAlignedObjectArray<int> &allow)
  195. {
  196. int m=-1;
  197. while(m==-1)
  198. {
  199. m = maxdirfiltered(p,count,dir,allow);
  200. if(allow[m]==3) return m;
  201. T u = orth(dir);
  202. T v = btCross(u,dir);
  203. int ma=-1;
  204. for(btScalar x = btScalar(0.0) ; x<= btScalar(360.0) ; x+= btScalar(45.0))
  205. {
  206. btScalar s = btSin(SIMD_RADS_PER_DEG*(x));
  207. btScalar c = btCos(SIMD_RADS_PER_DEG*(x));
  208. int mb = maxdirfiltered(p,count,dir+(u*s+v*c)*btScalar(0.025),allow);
  209. if(ma==m && mb==m)
  210. {
  211. allow[m]=3;
  212. return m;
  213. }
  214. if(ma!=-1 && ma!=mb) // Yuck - this is really ugly
  215. {
  216. int mc = ma;
  217. for(btScalar xx = x-btScalar(40.0) ; xx <= x ; xx+= btScalar(5.0))
  218. {
  219. // LOL BEGIN
  220. btScalar ss = btSin(SIMD_RADS_PER_DEG*(xx));
  221. btScalar cc = btCos(SIMD_RADS_PER_DEG*(xx));
  222. int md = maxdirfiltered(p,count,dir+(u*ss+v*cc)*btScalar(0.025),allow);
  223. // LOL END
  224. if(mc==m && md==m)
  225. {
  226. allow[m]=3;
  227. return m;
  228. }
  229. mc=md;
  230. }
  231. }
  232. ma=mb;
  233. }
  234. allow[m]=0;
  235. m=-1;
  236. }
  237. btAssert(0);
  238. return m;
  239. }
  240. int operator ==(const int3 &a,const int3 &b);
  241. int operator ==(const int3 &a,const int3 &b)
  242. {
  243. for(int i=0;i<3;i++)
  244. {
  245. if(a[i]!=b[i]) return 0;
  246. }
  247. return 1;
  248. }
  249. // LOL BEGIN
  250. int above(btVector3 const* vertices,const int3& t, const btVector3 &p, btScalar epsilon);
  251. int above(btVector3 const* vertices,const int3& t, const btVector3 &p, btScalar epsilon)
  252. // LOL END
  253. {
  254. btVector3 n=TriNormal(vertices[t[0]],vertices[t[1]],vertices[t[2]]);
  255. return (btDot(n,p-vertices[t[0]]) > epsilon); // EPSILON???
  256. }
  257. int hasedge(const int3 &t, int a,int b);
  258. int hasedge(const int3 &t, int a,int b)
  259. {
  260. for(int i=0;i<3;i++)
  261. {
  262. int i1= (i+1)%3;
  263. if(t[i]==a && t[i1]==b) return 1;
  264. }
  265. return 0;
  266. }
  267. int hasvert(const int3 &t, int v);
  268. int hasvert(const int3 &t, int v)
  269. {
  270. return (t[0]==v || t[1]==v || t[2]==v) ;
  271. }
  272. int shareedge(const int3 &a,const int3 &b);
  273. int shareedge(const int3 &a,const int3 &b)
  274. {
  275. int i;
  276. for(i=0;i<3;i++)
  277. {
  278. int i1= (i+1)%3;
  279. if(hasedge(a,b[i1],b[i])) return 1;
  280. }
  281. return 0;
  282. }
  283. class btHullTriangle;
  284. class btHullTriangle : public int3
  285. {
  286. public:
  287. int3 n;
  288. int id;
  289. int vmax;
  290. btScalar rise;
  291. btHullTriangle(int a,int b,int c):int3(a,b,c),n(-1,-1,-1)
  292. {
  293. vmax=-1;
  294. rise = btScalar(0.0);
  295. }
  296. ~btHullTriangle()
  297. {
  298. }
  299. int &neib(int a,int b);
  300. };
  301. int &btHullTriangle::neib(int a,int b)
  302. {
  303. static int er=-1;
  304. int i;
  305. for(i=0;i<3;i++)
  306. {
  307. int i1=(i+1)%3;
  308. int i2=(i+2)%3;
  309. if((*this)[i]==a && (*this)[i1]==b) return n[i2];
  310. if((*this)[i]==b && (*this)[i1]==a) return n[i2];
  311. }
  312. btAssert(0);
  313. return er;
  314. }
  315. void HullLibrary::b2bfix(btHullTriangle* s,btHullTriangle*t)
  316. {
  317. int i;
  318. for(i=0;i<3;i++)
  319. {
  320. int i1=(i+1)%3;
  321. int i2=(i+2)%3;
  322. int a = (*s)[i1];
  323. int b = (*s)[i2];
  324. btAssert(m_tris[s->neib(a,b)]->neib(b,a) == s->id);
  325. btAssert(m_tris[t->neib(a,b)]->neib(b,a) == t->id);
  326. m_tris[s->neib(a,b)]->neib(b,a) = t->neib(b,a);
  327. m_tris[t->neib(b,a)]->neib(a,b) = s->neib(a,b);
  328. }
  329. }
  330. void HullLibrary::removeb2b(btHullTriangle* s,btHullTriangle*t)
  331. {
  332. b2bfix(s,t);
  333. deAllocateTriangle(s);
  334. deAllocateTriangle(t);
  335. }
  336. void HullLibrary::checkit(btHullTriangle *t)
  337. {
  338. (void)t;
  339. int i;
  340. btAssert(m_tris[t->id]==t);
  341. for(i=0;i<3;i++)
  342. {
  343. int i1=(i+1)%3;
  344. int i2=(i+2)%3;
  345. int a = (*t)[i1];
  346. int b = (*t)[i2];
  347. // release compile fix
  348. (void)i1;
  349. (void)i2;
  350. (void)a;
  351. (void)b;
  352. btAssert(a!=b);
  353. btAssert( m_tris[t->n[i]]->neib(b,a) == t->id);
  354. }
  355. }
  356. btHullTriangle* HullLibrary::allocateTriangle(int a,int b,int c)
  357. {
  358. void* mem = btAlignedAlloc(sizeof(btHullTriangle),16);
  359. btHullTriangle* tr = new (mem)btHullTriangle(a,b,c);
  360. tr->id = m_tris.size();
  361. m_tris.push_back(tr);
  362. return tr;
  363. }
  364. void HullLibrary::deAllocateTriangle(btHullTriangle* tri)
  365. {
  366. btAssert(m_tris[tri->id]==tri);
  367. m_tris[tri->id]=NULL;
  368. tri->~btHullTriangle();
  369. btAlignedFree(tri);
  370. }
  371. void HullLibrary::extrude(btHullTriangle *t0,int v)
  372. {
  373. int3 t= *t0;
  374. int n = m_tris.size();
  375. btHullTriangle* ta = allocateTriangle(v,t[1],t[2]);
  376. ta->n = int3(t0->n[0],n+1,n+2);
  377. m_tris[t0->n[0]]->neib(t[1],t[2]) = n+0;
  378. btHullTriangle* tb = allocateTriangle(v,t[2],t[0]);
  379. tb->n = int3(t0->n[1],n+2,n+0);
  380. m_tris[t0->n[1]]->neib(t[2],t[0]) = n+1;
  381. btHullTriangle* tc = allocateTriangle(v,t[0],t[1]);
  382. tc->n = int3(t0->n[2],n+0,n+1);
  383. m_tris[t0->n[2]]->neib(t[0],t[1]) = n+2;
  384. checkit(ta);
  385. checkit(tb);
  386. checkit(tc);
  387. if(hasvert(*m_tris[ta->n[0]],v)) removeb2b(ta,m_tris[ta->n[0]]);
  388. if(hasvert(*m_tris[tb->n[0]],v)) removeb2b(tb,m_tris[tb->n[0]]);
  389. if(hasvert(*m_tris[tc->n[0]],v)) removeb2b(tc,m_tris[tc->n[0]]);
  390. deAllocateTriangle(t0);
  391. }
  392. btHullTriangle* HullLibrary::extrudable(btScalar epsilon)
  393. {
  394. int i;
  395. btHullTriangle *t=NULL;
  396. for(i=0;i<m_tris.size();i++)
  397. {
  398. if(!t || (m_tris[i] && t->rise<m_tris[i]->rise))
  399. {
  400. t = m_tris[i];
  401. }
  402. }
  403. return (t->rise >epsilon)?t:NULL ;
  404. }
  405. // LOL BEGIN
  406. int4 HullLibrary::FindSimplex(btVector3 const *verts,int verts_count,btAlignedObjectArray<int> &allow)
  407. // LOL END
  408. {
  409. btVector3 basis[3];
  410. basis[0] = btVector3( btScalar(0.01), btScalar(0.02), btScalar(1.0) );
  411. int p0 = maxdirsterid(verts,verts_count, basis[0],allow);
  412. int p1 = maxdirsterid(verts,verts_count,-basis[0],allow);
  413. basis[0] = verts[p0]-verts[p1];
  414. if(p0==p1 || basis[0]==btVector3(0,0,0))
  415. return int4(-1,-1,-1,-1);
  416. basis[1] = btCross(btVector3( btScalar(1),btScalar(0.02), btScalar(0)),basis[0]);
  417. basis[2] = btCross(btVector3(btScalar(-0.02), btScalar(1), btScalar(0)),basis[0]);
  418. if (basis[1].length() > basis[2].length())
  419. {
  420. basis[1].normalize();
  421. } else {
  422. basis[1] = basis[2];
  423. basis[1].normalize ();
  424. }
  425. int p2 = maxdirsterid(verts,verts_count,basis[1],allow);
  426. if(p2 == p0 || p2 == p1)
  427. {
  428. p2 = maxdirsterid(verts,verts_count,-basis[1],allow);
  429. }
  430. if(p2 == p0 || p2 == p1)
  431. return int4(-1,-1,-1,-1);
  432. basis[1] = verts[p2] - verts[p0];
  433. basis[2] = btCross(basis[1],basis[0]).normalized();
  434. int p3 = maxdirsterid(verts,verts_count,basis[2],allow);
  435. if(p3==p0||p3==p1||p3==p2) p3 = maxdirsterid(verts,verts_count,-basis[2],allow);
  436. if(p3==p0||p3==p1||p3==p2)
  437. return int4(-1,-1,-1,-1);
  438. btAssert(!(p0==p1||p0==p2||p0==p3||p1==p2||p1==p3||p2==p3));
  439. if(btDot(verts[p3]-verts[p0],btCross(verts[p1]-verts[p0],verts[p2]-verts[p0])) <0) {Swap(p2,p3);}
  440. return int4(p0,p1,p2,p3);
  441. }
  442. // LOL BEGIN
  443. int HullLibrary::calchullgen(btVector3 const *verts,int verts_count, int vlimit)
  444. // LOL END
  445. {
  446. if(verts_count <4) return 0;
  447. if(vlimit==0) vlimit=1000000000;
  448. int j;
  449. btVector3 bmin(*verts),bmax(*verts);
  450. btAlignedObjectArray<int> isextreme;
  451. isextreme.reserve(verts_count);
  452. btAlignedObjectArray<int> allow;
  453. allow.reserve(verts_count);
  454. for(j=0;j<verts_count;j++)
  455. {
  456. allow.push_back(1);
  457. isextreme.push_back(0);
  458. bmin.setMin (verts[j]);
  459. bmax.setMax (verts[j]);
  460. }
  461. btScalar epsilon = (bmax-bmin).length() * btScalar(0.001);
  462. btAssert (epsilon != 0.0);
  463. int4 p = FindSimplex(verts,verts_count,allow);
  464. if(p.x==-1) return 0; // simplex failed
  465. btVector3 center = (verts[p[0]]+verts[p[1]]+verts[p[2]]+verts[p[3]]) / btScalar(4.0); // a valid interior point
  466. btHullTriangle *t0 = allocateTriangle(p[2],p[3],p[1]); t0->n=int3(2,3,1);
  467. btHullTriangle *t1 = allocateTriangle(p[3],p[2],p[0]); t1->n=int3(3,2,0);
  468. btHullTriangle *t2 = allocateTriangle(p[0],p[1],p[3]); t2->n=int3(0,1,3);
  469. btHullTriangle *t3 = allocateTriangle(p[1],p[0],p[2]); t3->n=int3(1,0,2);
  470. isextreme[p[0]]=isextreme[p[1]]=isextreme[p[2]]=isextreme[p[3]]=1;
  471. checkit(t0);checkit(t1);checkit(t2);checkit(t3);
  472. for(j=0;j<m_tris.size();j++)
  473. {
  474. btHullTriangle *t=m_tris[j];
  475. btAssert(t);
  476. btAssert(t->vmax<0);
  477. btVector3 n=TriNormal(verts[(*t)[0]],verts[(*t)[1]],verts[(*t)[2]]);
  478. t->vmax = maxdirsterid(verts,verts_count,n,allow);
  479. t->rise = btDot(n,verts[t->vmax]-verts[(*t)[0]]);
  480. }
  481. btHullTriangle *te;
  482. vlimit-=4;
  483. while(vlimit >0 && ((te=extrudable(epsilon)) != 0))
  484. {
  485. // LOL BEGIN
  486. //int3 ti=*te;
  487. // LOL END
  488. int v=te->vmax;
  489. btAssert(v != -1);
  490. btAssert(!isextreme[v]); // wtf we've already done this vertex
  491. isextreme[v]=1;
  492. //if(v==p0 || v==p1 || v==p2 || v==p3) continue; // done these already
  493. j=m_tris.size();
  494. while(j--) {
  495. if(!m_tris[j]) continue;
  496. int3 t=*m_tris[j];
  497. if(above(verts,t,verts[v],btScalar(0.01)*epsilon))
  498. {
  499. extrude(m_tris[j],v);
  500. }
  501. }
  502. // now check for those degenerate cases where we have a flipped triangle or a really skinny triangle
  503. j=m_tris.size();
  504. while(j--)
  505. {
  506. if(!m_tris[j]) continue;
  507. if(!hasvert(*m_tris[j],v)) break;
  508. int3 nt=*m_tris[j];
  509. 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) )
  510. {
  511. btHullTriangle *nb = m_tris[m_tris[j]->n[0]];
  512. btAssert(nb);btAssert(!hasvert(*nb,v));btAssert(nb->id<j);
  513. extrude(nb,v);
  514. j=m_tris.size();
  515. }
  516. }
  517. j=m_tris.size();
  518. while(j--)
  519. {
  520. btHullTriangle *t=m_tris[j];
  521. if(!t) continue;
  522. if(t->vmax>=0) break;
  523. btVector3 n=TriNormal(verts[(*t)[0]],verts[(*t)[1]],verts[(*t)[2]]);
  524. t->vmax = maxdirsterid(verts,verts_count,n,allow);
  525. if(isextreme[t->vmax])
  526. {
  527. t->vmax=-1; // already done that vertex - algorithm needs to be able to terminate.
  528. }
  529. else
  530. {
  531. t->rise = btDot(n,verts[t->vmax]-verts[(*t)[0]]);
  532. }
  533. }
  534. vlimit --;
  535. }
  536. return 1;
  537. }
  538. // LOL BEGIN
  539. int HullLibrary::calchull(btVector3 const *verts,int verts_count, TUIntArray& tris_out, int &tris_count,int vlimit)
  540. // LOL END
  541. {
  542. int rc=calchullgen(verts,verts_count, vlimit) ;
  543. if(!rc) return 0;
  544. btAlignedObjectArray<int> ts;
  545. int i;
  546. for(i=0;i<m_tris.size();i++)
  547. {
  548. if(m_tris[i])
  549. {
  550. for(int j=0;j<3;j++)
  551. ts.push_back((*m_tris[i])[j]);
  552. deAllocateTriangle(m_tris[i]);
  553. }
  554. }
  555. tris_count = ts.size()/3;
  556. tris_out.resize(ts.size());
  557. for (i=0;i<ts.size();i++)
  558. {
  559. tris_out[i] = static_cast<unsigned int>(ts[i]);
  560. }
  561. m_tris.resize(0);
  562. return 1;
  563. }
  564. bool HullLibrary::ComputeHull(unsigned int vcount,const btVector3 *vertices,PHullResult &result,unsigned int vlimit)
  565. {
  566. int tris_count;
  567. // LOL BEGIN
  568. int ret = calchull( vertices, (int) vcount, result.m_Indices, tris_count, static_cast<int>(vlimit) );
  569. // LOL END
  570. if(!ret) return false;
  571. result.mIndexCount = (unsigned int) (tris_count*3);
  572. result.mFaceCount = (unsigned int) tris_count;
  573. result.mVertices = (btVector3*) vertices;
  574. result.mVcount = (unsigned int) vcount;
  575. return true;
  576. }
  577. void ReleaseHull(PHullResult &result);
  578. void ReleaseHull(PHullResult &result)
  579. {
  580. if ( result.m_Indices.size() )
  581. {
  582. result.m_Indices.clear();
  583. }
  584. result.mVcount = 0;
  585. result.mIndexCount = 0;
  586. result.mVertices = 0;
  587. }
  588. //*********************************************************************
  589. //*********************************************************************
  590. //******** HullLib header
  591. //*********************************************************************
  592. //*********************************************************************
  593. //*********************************************************************
  594. //*********************************************************************
  595. //******** HullLib implementation
  596. //*********************************************************************
  597. //*********************************************************************
  598. HullError HullLibrary::CreateConvexHull(const HullDesc &desc, // describes the input request
  599. HullResult &result) // contains the resulst
  600. {
  601. HullError ret = QE_FAIL;
  602. PHullResult hr;
  603. unsigned int vcount = desc.mVcount;
  604. if ( vcount < 8 ) vcount = 8;
  605. btAlignedObjectArray<btVector3> vertexSource;
  606. vertexSource.resize(static_cast<int>(vcount));
  607. btVector3 scale;
  608. unsigned int ovcount;
  609. bool ok = CleanupVertices(desc.mVcount,desc.mVertices, desc.mVertexStride, ovcount, &vertexSource[0], desc.mNormalEpsilon, scale ); // normalize point cloud, remove duplicates!
  610. if ( ok )
  611. {
  612. // if ( 1 ) // scale vertices back to their original size.
  613. {
  614. for (unsigned int i=0; i<ovcount; i++)
  615. {
  616. btVector3& v = vertexSource[static_cast<int>(i)];
  617. v[0]*=scale[0];
  618. v[1]*=scale[1];
  619. v[2]*=scale[2];
  620. }
  621. }
  622. ok = ComputeHull(ovcount,&vertexSource[0],hr,desc.mMaxVertices);
  623. if ( ok )
  624. {
  625. // re-index triangle mesh so it refers to only used vertices, rebuild a new vertex table.
  626. btAlignedObjectArray<btVector3> vertexScratch;
  627. vertexScratch.resize(static_cast<int>(hr.mVcount));
  628. BringOutYourDead(hr.mVertices,hr.mVcount, &vertexScratch[0], ovcount, &hr.m_Indices[0], hr.mIndexCount );
  629. ret = QE_OK;
  630. if ( desc.HasHullFlag(QF_TRIANGLES) ) // if he wants the results as triangle!
  631. {
  632. result.mPolygons = false;
  633. result.mNumOutputVertices = ovcount;
  634. result.m_OutputVertices.resize(static_cast<int>(ovcount));
  635. result.mNumFaces = hr.mFaceCount;
  636. result.mNumIndices = hr.mIndexCount;
  637. result.m_Indices.resize(static_cast<int>(hr.mIndexCount));
  638. memcpy(&result.m_OutputVertices[0], &vertexScratch[0], sizeof(btVector3)*ovcount );
  639. if ( desc.HasHullFlag(QF_REVERSE_ORDER) )
  640. {
  641. const unsigned int *source = &hr.m_Indices[0];
  642. unsigned int *dest = &result.m_Indices[0];
  643. for (unsigned int i=0; i<hr.mFaceCount; i++)
  644. {
  645. dest[0] = source[2];
  646. dest[1] = source[1];
  647. dest[2] = source[0];
  648. dest+=3;
  649. source+=3;
  650. }
  651. }
  652. else
  653. {
  654. memcpy(&result.m_Indices[0], &hr.m_Indices[0], sizeof(unsigned int)*hr.mIndexCount);
  655. }
  656. }
  657. else
  658. {
  659. result.mPolygons = true;
  660. result.mNumOutputVertices = ovcount;
  661. result.m_OutputVertices.resize(static_cast<int>(ovcount));
  662. result.mNumFaces = hr.mFaceCount;
  663. result.mNumIndices = hr.mIndexCount+hr.mFaceCount;
  664. result.m_Indices.resize(static_cast<int>(result.mNumIndices));
  665. memcpy(&result.m_OutputVertices[0], &vertexScratch[0], sizeof(btVector3)*ovcount );
  666. // if ( 1 )
  667. {
  668. const unsigned int *source = &hr.m_Indices[0];
  669. unsigned int *dest = &result.m_Indices[0];
  670. for (unsigned int i=0; i<hr.mFaceCount; i++)
  671. {
  672. dest[0] = 3;
  673. if ( desc.HasHullFlag(QF_REVERSE_ORDER) )
  674. {
  675. dest[1] = source[2];
  676. dest[2] = source[1];
  677. dest[3] = source[0];
  678. }
  679. else
  680. {
  681. dest[1] = source[0];
  682. dest[2] = source[1];
  683. dest[3] = source[2];
  684. }
  685. dest+=4;
  686. source+=3;
  687. }
  688. }
  689. }
  690. ReleaseHull(hr);
  691. }
  692. }
  693. return ret;
  694. }
  695. HullError HullLibrary::ReleaseResult(HullResult &result) // release memory allocated for this result, we are done with it.
  696. {
  697. if ( result.m_OutputVertices.size())
  698. {
  699. result.mNumOutputVertices=0;
  700. result.m_OutputVertices.clear();
  701. }
  702. if ( result.m_Indices.size() )
  703. {
  704. result.mNumIndices=0;
  705. result.m_Indices.clear();
  706. }
  707. return QE_OK;
  708. }
  709. static void addPoint(unsigned int &vcount,btVector3 *p,btScalar x,btScalar y,btScalar z)
  710. {
  711. // XXX, might be broken
  712. btVector3& dest = p[vcount];
  713. dest[0] = x;
  714. dest[1] = y;
  715. dest[2] = z;
  716. vcount++;
  717. }
  718. btScalar GetDist(btScalar px,btScalar py,btScalar pz,const btScalar *p2);
  719. btScalar GetDist(btScalar px,btScalar py,btScalar pz,const btScalar *p2)
  720. {
  721. btScalar dx = px - p2[0];
  722. btScalar dy = py - p2[1];
  723. btScalar dz = pz - p2[2];
  724. return dx*dx+dy*dy+dz*dz;
  725. }
  726. bool HullLibrary::CleanupVertices(unsigned int svcount,
  727. const btVector3 *svertices,
  728. unsigned int stride,
  729. unsigned int &vcount, // output number of vertices
  730. btVector3 *vertices, // location to store the results.
  731. btScalar normalepsilon,
  732. btVector3& scale)
  733. {
  734. if ( svcount == 0 ) return false;
  735. m_vertexIndexMapping.resize(0);
  736. #define EPSILON btScalar(0.000001) /* close enough to consider two btScalaring point numbers to be 'the same'. */
  737. vcount = 0;
  738. btScalar recip[3]={0.f,0.f,0.f};
  739. if ( scale )
  740. {
  741. scale[0] = 1;
  742. scale[1] = 1;
  743. scale[2] = 1;
  744. }
  745. btScalar bmin[3] = { FLT_MAX, FLT_MAX, FLT_MAX };
  746. btScalar bmax[3] = { -FLT_MAX, -FLT_MAX, -FLT_MAX };
  747. const char *vtx = (const char *) svertices;
  748. // if ( 1 )
  749. {
  750. for (unsigned int i=0; i<svcount; i++)
  751. {
  752. const btScalar *p = (const btScalar *) vtx;
  753. vtx+=stride;
  754. for (int j=0; j<3; j++)
  755. {
  756. if ( p[j] < bmin[j] ) bmin[j] = p[j];
  757. if ( p[j] > bmax[j] ) bmax[j] = p[j];
  758. }
  759. }
  760. }
  761. btScalar dx = bmax[0] - bmin[0];
  762. btScalar dy = bmax[1] - bmin[1];
  763. btScalar dz = bmax[2] - bmin[2];
  764. btVector3 center;
  765. center[0] = dx*btScalar(0.5) + bmin[0];
  766. center[1] = dy*btScalar(0.5) + bmin[1];
  767. center[2] = dz*btScalar(0.5) + bmin[2];
  768. if ( dx < EPSILON || dy < EPSILON || dz < EPSILON || svcount < 3 )
  769. {
  770. btScalar len = FLT_MAX;
  771. if ( dx > EPSILON && dx < len ) len = dx;
  772. if ( dy > EPSILON && dy < len ) len = dy;
  773. if ( dz > EPSILON && dz < len ) len = dz;
  774. if ( len == FLT_MAX )
  775. {
  776. dx = dy = dz = btScalar(0.01); // one centimeter
  777. }
  778. else
  779. {
  780. if ( dx < EPSILON ) dx = len * btScalar(0.05); // 1/5th the shortest non-zero edge.
  781. if ( dy < EPSILON ) dy = len * btScalar(0.05);
  782. if ( dz < EPSILON ) dz = len * btScalar(0.05);
  783. }
  784. btScalar x1 = center[0] - dx;
  785. btScalar x2 = center[0] + dx;
  786. btScalar y1 = center[1] - dy;
  787. btScalar y2 = center[1] + dy;
  788. btScalar z1 = center[2] - dz;
  789. btScalar z2 = center[2] + dz;
  790. addPoint(vcount,vertices,x1,y1,z1);
  791. addPoint(vcount,vertices,x2,y1,z1);
  792. addPoint(vcount,vertices,x2,y2,z1);
  793. addPoint(vcount,vertices,x1,y2,z1);
  794. addPoint(vcount,vertices,x1,y1,z2);
  795. addPoint(vcount,vertices,x2,y1,z2);
  796. addPoint(vcount,vertices,x2,y2,z2);
  797. addPoint(vcount,vertices,x1,y2,z2);
  798. return true; // return cube
  799. }
  800. else
  801. {
  802. if ( scale )
  803. {
  804. scale[0] = dx;
  805. scale[1] = dy;
  806. scale[2] = dz;
  807. recip[0] = 1 / dx;
  808. recip[1] = 1 / dy;
  809. recip[2] = 1 / dz;
  810. center[0]*=recip[0];
  811. center[1]*=recip[1];
  812. center[2]*=recip[2];
  813. }
  814. }
  815. vtx = (const char *) svertices;
  816. for (unsigned int i=0; i<svcount; i++)
  817. {
  818. const btVector3 *p = (const btVector3 *)vtx;
  819. vtx+=stride;
  820. btScalar px = p->getX();
  821. btScalar py = p->getY();
  822. btScalar pz = p->getZ();
  823. if ( scale )
  824. {
  825. px = px*recip[0]; // normalize
  826. py = py*recip[1]; // normalize
  827. pz = pz*recip[2]; // normalize
  828. }
  829. // if ( 1 )
  830. {
  831. unsigned int j;
  832. for (j=0; j<vcount; j++)
  833. {
  834. /// XXX might be broken
  835. btVector3& v = vertices[j];
  836. btScalar x = v[0];
  837. btScalar y = v[1];
  838. btScalar z = v[2];
  839. btScalar dx = btFabs(x - px );
  840. btScalar dy = btFabs(y - py );
  841. btScalar dz = btFabs(z - pz );
  842. if ( dx < normalepsilon && dy < normalepsilon && dz < normalepsilon )
  843. {
  844. // ok, it is close enough to the old one
  845. // now let us see if it is further from the center of the point cloud than the one we already recorded.
  846. // in which case we keep this one instead.
  847. btScalar dist1 = GetDist(px,py,pz,center);
  848. btScalar dist2 = GetDist(v[0],v[1],v[2],center);
  849. if ( dist1 > dist2 )
  850. {
  851. v[0] = px;
  852. v[1] = py;
  853. v[2] = pz;
  854. }
  855. break;
  856. }
  857. }
  858. if ( j == vcount )
  859. {
  860. btVector3& dest = vertices[vcount];
  861. dest[0] = px;
  862. dest[1] = py;
  863. dest[2] = pz;
  864. vcount++;
  865. }
  866. m_vertexIndexMapping.push_back(j);
  867. }
  868. }
  869. // ok..now make sure we didn't prune so many vertices it is now invalid.
  870. // if ( 1 )
  871. {
  872. btScalar bmin[3] = { FLT_MAX, FLT_MAX, FLT_MAX };
  873. btScalar bmax[3] = { -FLT_MAX, -FLT_MAX, -FLT_MAX };
  874. for (unsigned int i=0; i<vcount; i++)
  875. {
  876. const btVector3& p = vertices[i];
  877. for (int j=0; j<3; j++)
  878. {
  879. if ( p[j] < bmin[j] ) bmin[j] = p[j];
  880. if ( p[j] > bmax[j] ) bmax[j] = p[j];
  881. }
  882. }
  883. btScalar dx = bmax[0] - bmin[0];
  884. btScalar dy = bmax[1] - bmin[1];
  885. btScalar dz = bmax[2] - bmin[2];
  886. if ( dx < EPSILON || dy < EPSILON || dz < EPSILON || vcount < 3)
  887. {
  888. btScalar cx = dx*btScalar(0.5) + bmin[0];
  889. btScalar cy = dy*btScalar(0.5) + bmin[1];
  890. btScalar cz = dz*btScalar(0.5) + bmin[2];
  891. btScalar len = FLT_MAX;
  892. if ( dx >= EPSILON && dx < len ) len = dx;
  893. if ( dy >= EPSILON && dy < len ) len = dy;
  894. if ( dz >= EPSILON && dz < len ) len = dz;
  895. if ( len == FLT_MAX )
  896. {
  897. dx = dy = dz = btScalar(0.01); // one centimeter
  898. }
  899. else
  900. {
  901. if ( dx < EPSILON ) dx = len * btScalar(0.05); // 1/5th the shortest non-zero edge.
  902. if ( dy < EPSILON ) dy = len * btScalar(0.05);
  903. if ( dz < EPSILON ) dz = len * btScalar(0.05);
  904. }
  905. btScalar x1 = cx - dx;
  906. btScalar x2 = cx + dx;
  907. btScalar y1 = cy - dy;
  908. btScalar y2 = cy + dy;
  909. btScalar z1 = cz - dz;
  910. btScalar z2 = cz + dz;
  911. vcount = 0; // add box
  912. addPoint(vcount,vertices,x1,y1,z1);
  913. addPoint(vcount,vertices,x2,y1,z1);
  914. addPoint(vcount,vertices,x2,y2,z1);
  915. addPoint(vcount,vertices,x1,y2,z1);
  916. addPoint(vcount,vertices,x1,y1,z2);
  917. addPoint(vcount,vertices,x2,y1,z2);
  918. addPoint(vcount,vertices,x2,y2,z2);
  919. addPoint(vcount,vertices,x1,y2,z2);
  920. return true;
  921. }
  922. }
  923. return true;
  924. }
  925. void HullLibrary::BringOutYourDead(const btVector3* verts,unsigned int vcount, btVector3* overts,unsigned int &ocount,unsigned int *indices,unsigned indexcount)
  926. {
  927. btAlignedObjectArray<int>tmpIndices;
  928. tmpIndices.resize(m_vertexIndexMapping.size());
  929. int i;
  930. for (i=0;i<m_vertexIndexMapping.size();i++)
  931. {
  932. tmpIndices[i] = m_vertexIndexMapping[i];
  933. }
  934. TUIntArray usedIndices;
  935. usedIndices.resize(static_cast<int>(vcount));
  936. memset(&usedIndices[0],0,sizeof(unsigned int)*vcount);
  937. ocount = 0;
  938. for (i=0; i<int (indexcount); i++)
  939. {
  940. unsigned int v = indices[i]; // original array index
  941. btAssert( v >= 0 && v < vcount );
  942. if ( usedIndices[static_cast<int>(v)] ) // if already remapped
  943. {
  944. indices[i] = usedIndices[static_cast<int>(v)]-1; // index to new array
  945. }
  946. else
  947. {
  948. indices[i] = ocount; // new index mapping
  949. overts[ocount][0] = verts[v][0]; // copy old vert to new vert array
  950. overts[ocount][1] = verts[v][1];
  951. overts[ocount][2] = verts[v][2];
  952. for (int k=0;k<m_vertexIndexMapping.size();k++)
  953. {
  954. if (tmpIndices[k]==int(v))
  955. m_vertexIndexMapping[k]=ocount;
  956. }
  957. ocount++; // increment output vert count
  958. btAssert( ocount >=0 && ocount <= vcount );
  959. usedIndices[static_cast<int>(v)] = ocount; // assign new index remapping
  960. }
  961. }
  962. }