Bullet Collision Detection & Physics Library
btConvexHull.cpp
Go to the documentation of this file.
1/*
2Stan Melax Convex Hull Computation
3Copyright (c) 2003-2006 Stan Melax http://www.melax.com/
4
5This software is provided 'as-is', without any express or implied warranty.
6In no event will the authors be held liable for any damages arising from the use of this software.
7Permission is granted to anyone to use this software for any purpose,
8including commercial applications, and to alter it and redistribute it freely,
9subject to the following restrictions:
10
111. 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.
122. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
133. This notice may not be removed or altered from any source distribution.
14*/
15
16#include <string.h>
17
18#include "btConvexHull.h"
20#include "btMinMax.h"
21#include "btVector3.h"
22
23//----------------------------------
24
25class int3
26{
27public:
28 int x, y, z;
29 int3(){};
30 int3(int _x, int _y, int _z)
31 {
32 x = _x;
33 y = _y;
34 z = _z;
35 }
36 const int &operator[](int i) const { return (&x)[i]; }
37 int &operator[](int i) { return (&x)[i]; }
38};
39
40//------- btPlane ----------
41
42inline btPlane PlaneFlip(const btPlane &plane) { return btPlane(-plane.normal, -plane.dist); }
43inline int operator==(const btPlane &a, const btPlane &b) { return (a.normal == b.normal && a.dist == b.dist); }
44inline int coplanar(const btPlane &a, const btPlane &b) { return (a == b || a == PlaneFlip(b)); }
45
46//--------- Utility Functions ------
47
48btVector3 PlaneLineIntersection(const btPlane &plane, const btVector3 &p0, const btVector3 &p1);
49btVector3 PlaneProject(const btPlane &plane, const btVector3 &point);
50
51btVector3 ThreePlaneIntersection(const btPlane &p0, const btPlane &p1, const btPlane &p2);
52btVector3 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
82btScalar DistanceBetweenLines(const btVector3 &ustart, const btVector3 &udir, const btVector3 &vstart, const btVector3 &vdir, btVector3 *upoint = NULL, btVector3 *vpoint = NULL);
83btVector3 TriNormal(const btVector3 &v0, const btVector3 &v1, const btVector3 &v2);
84btVector3 NormalOf(const btVector3 *vert, const int n);
85
86btVector3 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
96btVector3 PlaneProject(const btPlane &plane, const btVector3 &point)
97{
98 return point - plane.normal * (btDot(point, plane.normal) + plane.dist);
99}
100
101btVector3 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
111btScalar 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
143
145
146ConvexH::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
153int PlaneTest(const btPlane &p, const btVector3 &v);
154int 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
161int SplitTest(ConvexH &convex, const btPlane &plane);
162int 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
173{
174public:
175 unsigned char planetest;
176 unsigned char junk;
177 unsigned char undermap;
178 unsigned char overmap;
179};
181{
182public:
183 unsigned char planetest;
184 unsigned char fixes;
185 short undermap;
186 short overmap;
187};
189{
190public:
191 unsigned char undermap;
192 unsigned char overmap;
193};
195{
196public:
197 unsigned short ea;
198 unsigned char v0;
199 unsigned char v1;
200};
201
202template <class T>
203int 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
217btVector3 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
232template <class T>
233int 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 {
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
278int operator==(const int3 &a, const int3 &b);
279int 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
288int above(btVector3 *vertices, const int3 &t, const btVector3 &p, btScalar epsilon);
289int 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}
294int hasedge(const int3 &t, int a, int b);
295int 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}
304int hasvert(const int3 &t, int v);
305int hasvert(const int3 &t, int v)
306{
307 return (t[0] == v || t[1] == v || t[2] == v);
308}
309int shareedge(const int3 &a, const int3 &b);
310int 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
321class btHullTriangle;
322
323class btHullTriangle : public int3
324{
325public:
327 int id;
328 int vmax;
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 }
336 {
337 }
338 int &neib(int a, int b);
339};
340
341int &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}
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
372{
373 b2bfix(s, t);
375
377}
378
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
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
414{
415 btAssert(m_tris[tri->id] == tri);
416 m_tris[tri->id] = NULL;
417 tri->~btHullTriangle();
418 btAlignedFree(tri);
419}
420
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]]);
441}
442
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
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
498int 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);
505 isextreme.reserve(verts_count);
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
605int 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;
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]);
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
633bool 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
645void 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
670HullError 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
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.
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
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;
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
787HullError 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
802static 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
812btScalar 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
822bool 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
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 {
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 }
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
1072void 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}
#define btAlignedFree(ptr)
#define btAlignedAlloc(size, alignment)
#define EPSILON
ConvexH::HalfEdge HalfEdge
btVector3 ThreePlaneIntersection(const btPlane &p0, const btPlane &p1, const btPlane &p2)
btScalar DistanceBetweenLines(const btVector3 &ustart, const btVector3 &udir, const btVector3 &vstart, const btVector3 &vdir, btVector3 *upoint=NULL, btVector3 *vpoint=NULL)
int maxdirsterid(const T *p, int count, const T &dir, btAlignedObjectArray< int > &allow)
btVector3 PlaneLineIntersection(const btPlane &plane, const btVector3 &p0, const btVector3 &p1)
#define OVER
static void addPoint(unsigned int &vcount, btVector3 *p, btScalar x, btScalar y, btScalar z)
int operator==(const btPlane &a, const btPlane &b)
void ReleaseHull(PHullResult &result)
#define COPLANAR
int hasvert(const int3 &t, int v)
btPlane PlaneFlip(const btPlane &plane)
btVector3 NormalOf(const btVector3 *vert, const int n)
int coplanar(const btPlane &a, const btPlane &b)
btVector3 PlaneProject(const btPlane &plane, const btVector3 &point)
int maxdirfiltered(const T *p, int count, const T &dir, btAlignedObjectArray< int > &allow)
btVector3 TriNormal(const btVector3 &v0, const btVector3 &v1, const btVector3 &v2)
#define UNDER
int SplitTest(ConvexH &convex, const btPlane &plane)
int hasedge(const int3 &t, int a, int b)
int above(btVector3 *vertices, const int3 &t, const btVector3 &p, btScalar epsilon)
btScalar planetestepsilon
int PlaneTest(const btPlane &p, const btVector3 &v)
#define PAPERWIDTH
btScalar GetDist(btScalar px, btScalar py, btScalar pz, const btScalar *p2)
int shareedge(const int3 &a, const int3 &b)
btVector3 orth(const btVector3 &v)
HullError
Definition: btConvexHull.h:108
@ QE_OK
Definition: btConvexHull.h:109
@ QE_FAIL
Definition: btConvexHull.h:110
@ QF_TRIANGLES
Definition: btConvexHull.h:50
@ QF_REVERSE_ORDER
Definition: btConvexHull.h:51
btScalar length(const btQuaternion &q)
Return the length of a quaternion.
Definition: btQuaternion.h:895
#define SIMD_RADS_PER_DEG
Definition: btScalar.h:529
float btScalar
The btScalar type abstracts floating point numbers, to easily switch between double and single floati...
Definition: btScalar.h:314
btScalar btSin(btScalar x)
Definition: btScalar.h:499
btScalar btFabs(btScalar x)
Definition: btScalar.h:497
btScalar btCos(btScalar x)
Definition: btScalar.h:498
void btSwap(T &a, T &b)
Definition: btScalar.h:643
#define btAssert(x)
Definition: btScalar.h:153
btScalar btDot(const btVector3 &v1, const btVector3 &v2)
Return the dot product between two vectors.
Definition: btVector3.h:890
btVector3 btCross(const btVector3 &v1, const btVector3 &v2)
Return the cross product of two vectors.
Definition: btVector3.h:918
btAlignedObjectArray< HalfEdge > edges
Definition: btConvexHull.h:141
btAlignedObjectArray< btPlane > facets
Definition: btConvexHull.h:142
btAlignedObjectArray< btVector3 > vertices
Definition: btConvexHull.h:140
unsigned short ea
unsigned char v0
unsigned char v1
short overmap
short undermap
unsigned char planetest
unsigned char fixes
bool HasHullFlag(HullFlag flag) const
Definition: btConvexHull.h:82
unsigned int mVcount
Definition: btConvexHull.h:99
btScalar mNormalEpsilon
Definition: btConvexHull.h:102
unsigned int mMaxVertices
Definition: btConvexHull.h:103
const btVector3 * mVertices
Definition: btConvexHull.h:100
unsigned int mVertexStride
Definition: btConvexHull.h:101
btHullTriangle * extrudable(btScalar epsilon)
class btHullTriangle * allocateTriangle(int a, int b, int c)
bool ComputeHull(unsigned int vcount, const btVector3 *vertices, PHullResult &result, unsigned int vlimit)
HullError ReleaseResult(HullResult &result)
void BringOutYourDead(const btVector3 *verts, unsigned int vcount, btVector3 *overts, unsigned int &ocount, unsigned int *indices, unsigned indexcount)
HullError CreateConvexHull(const HullDesc &desc, HullResult &result)
void deAllocateTriangle(btHullTriangle *)
int calchull(btVector3 *verts, int verts_count, TUIntArray &tris_out, int &tris_count, int vlimit)
btAlignedObjectArray< int > m_vertexIndexMapping
Definition: btConvexHull.h:187
void b2bfix(btHullTriangle *s, btHullTriangle *t)
void removeb2b(btHullTriangle *s, btHullTriangle *t)
btAlignedObjectArray< class btHullTriangle * > m_tris
Definition: btConvexHull.h:184
void checkit(btHullTriangle *t)
void extrude(class btHullTriangle *t0, int v)
int calchullgen(btVector3 *verts, int verts_count, int vlimit)
int4 FindSimplex(btVector3 *verts, int verts_count, btAlignedObjectArray< int > &allow)
bool CleanupVertices(unsigned int svcount, const btVector3 *svertices, unsigned int stride, unsigned int &vcount, btVector3 *vertices, btScalar normalepsilon, btVector3 &scale)
btAlignedObjectArray< btVector3 > m_OutputVertices
Definition: btConvexHull.h:39
btAlignedObjectArray< unsigned int > m_Indices
Definition: btConvexHull.h:42
unsigned int mNumOutputVertices
Definition: btConvexHull.h:38
unsigned int mNumFaces
Definition: btConvexHull.h:40
bool mPolygons
Definition: btConvexHull.h:37
unsigned int mNumIndices
Definition: btConvexHull.h:41
unsigned int mFaceCount
Definition: btConvexHull.h:175
unsigned int mVcount
Definition: btConvexHull.h:173
unsigned int mIndexCount
Definition: btConvexHull.h:174
btVector3 * mVertices
Definition: btConvexHull.h:176
TUIntArray m_Indices
Definition: btConvexHull.h:177
unsigned char overmap
unsigned char undermap
unsigned char junk
unsigned char undermap
unsigned char overmap
unsigned char planetest
int size() const
return the number of elements in the array
void resize(int newsize, const T &fillData=T())
void clear()
clear the array, deallocated memory. Generally it is better to use array.resize(0),...
void push_back(const T &_Val)
int & neib(int a, int b)
btHullTriangle(int a, int b, int c)
btVector3 normal
Definition: btConvexHull.h:116
btScalar dist
Definition: btConvexHull.h:117
btVector3 can be used to represent 3D points and vectors.
Definition: btVector3.h:82
const btScalar & getZ() const
Return the z value.
Definition: btVector3.h:565
void setMax(const btVector3 &other)
Set each element to the max of the current values and the values of another btVector3.
Definition: btVector3.h:609
btScalar length() const
Return the length of the vector.
Definition: btVector3.h:257
btVector3 cross(const btVector3 &v) const
Return the cross product between this and another vector.
Definition: btVector3.h:380
btScalar dot(const btVector3 &v) const
Return the dot product.
Definition: btVector3.h:229
btVector3 normalized() const
Return a normalized version of this vector.
Definition: btVector3.h:949
const btScalar & getY() const
Return the y value.
Definition: btVector3.h:563
btVector3 & normalize()
Normalize this vector x^2 + y^2 + z^2 = 1.
Definition: btVector3.h:303
const btScalar & getX() const
Return the x value.
Definition: btVector3.h:561
int & operator[](int i)
int3(int _x, int _y, int _z)
const int & operator[](int i) const
int x
Definition: btConvexHull.h:149