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