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