2 Stan Melax Convex Hull Computation
3 Copyright (c) 2003-2006 Stan Melax http://www.melax.com/
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:
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.
18 #include "btConvexHull.h"
19 #include "btAlignedObjectArray.h"
21 #include "btVector3.h"
23 //----------------------------------
30 int3(int _x, int _y, int _z)
36 const int &operator[](int i) const { return (&x)[i]; }
37 int &operator[](int i) { return (&x)[i]; }
40 //------- btPlane ----------
42 inline btPlane PlaneFlip(const btPlane &plane) { return btPlane(-plane.normal, -plane.dist); }
43 inline int operator==(const btPlane &a, const btPlane &b) { return (a.normal == b.normal && a.dist == b.dist); }
44 inline int coplanar(const btPlane &a, const btPlane &b) { return (a == b || a == PlaneFlip(b)); }
46 //--------- Utility Functions ------
48 btVector3 PlaneLineIntersection(const btPlane &plane, const btVector3 &p0, const btVector3 &p1);
49 btVector3 PlaneProject(const btPlane &plane, const btVector3 &point);
51 btVector3 ThreePlaneIntersection(const btPlane &p0, const btPlane &p1, const btPlane &p2);
52 btVector3 ThreePlaneIntersection(const btPlane &p0, const btPlane &p1, const btPlane &p2)
54 btVector3 N1 = p0.normal;
55 btVector3 N2 = p1.normal;
56 btVector3 N3 = p2.normal;
65 btScalar quotient = (N1.dot(n2n3));
67 btAssert(btFabs(quotient) > btScalar(0.000001));
69 quotient = btScalar(-1.) / quotient;
73 btVector3 potentialVertex = n2n3;
74 potentialVertex += n3n1;
75 potentialVertex += n1n2;
76 potentialVertex *= quotient;
78 btVector3 result(potentialVertex.getX(), potentialVertex.getY(), potentialVertex.getZ());
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);
86 btVector3 PlaneLineIntersection(const btPlane &plane, const btVector3 &p0, const btVector3 &p1)
88 // returns the point where the line p0-p1 intersects the plane n&d
91 btScalar dn = btDot(plane.normal, dif);
92 btScalar t = -(plane.dist + btDot(plane.normal, p0)) / dn;
93 return p0 + (dif * t);
96 btVector3 PlaneProject(const btPlane &plane, const btVector3 &point)
98 return point - plane.normal * (btDot(point, plane.normal) + plane.dist);
101 btVector3 TriNormal(const btVector3 &v0, const btVector3 &v1, const btVector3 &v2)
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);
111 btScalar DistanceBetweenLines(const btVector3 &ustart, const btVector3 &udir, const btVector3 &vstart, const btVector3 &vdir, btVector3 *upoint, btVector3 *vpoint)
114 cp = btCross(udir, vdir).normalized();
116 btScalar distu = -btDot(cp, ustart);
117 btScalar distv = -btDot(cp, vstart);
118 btScalar dist = (btScalar)fabs(distu - distv);
122 plane.normal = btCross(vdir, cp).normalized();
123 plane.dist = -btDot(plane.normal, vstart);
124 *upoint = PlaneLineIntersection(plane, ustart, ustart + udir);
129 plane.normal = btCross(udir, cp).normalized();
130 plane.dist = -btDot(plane.normal, ustart);
131 *vpoint = PlaneLineIntersection(plane, vstart, vstart + vdir);
139 #define SPLIT (OVER | UNDER)
140 #define PAPERWIDTH (btScalar(0.001))
142 btScalar planetestepsilon = PAPERWIDTH;
144 typedef ConvexH::HalfEdge HalfEdge;
146 ConvexH::ConvexH(int vertices_size, int edges_size, int facets_size)
148 vertices.resize(vertices_size);
149 edges.resize(edges_size);
150 facets.resize(facets_size);
153 int PlaneTest(const btPlane &p, const btVector3 &v);
154 int PlaneTest(const btPlane &p, const btVector3 &v)
156 btScalar a = btDot(v, p.normal) + p.dist;
157 int flag = (a > planetestepsilon) ? OVER : ((a < -planetestepsilon) ? UNDER : COPLANAR);
161 int SplitTest(ConvexH &convex, const btPlane &plane);
162 int SplitTest(ConvexH &convex, const btPlane &plane)
165 for (int i = 0; i < convex.vertices.size(); i++)
167 flag |= PlaneTest(plane, convex.vertices[i]);
175 unsigned char planetest;
177 unsigned char undermap;
178 unsigned char overmap;
183 unsigned char planetest;
191 unsigned char undermap;
192 unsigned char overmap;
203 int maxdirfiltered(const T *p, int count, const T &dir, btAlignedObjectArray<int> &allow)
207 for (int i = 0; i < count; i++)
210 if (m == -1 || btDot(p[i], dir) > btDot(p[m], dir))
217 btVector3 orth(const btVector3 &v);
218 btVector3 orth(const btVector3 &v)
220 btVector3 a = btCross(v, btVector3(0, 0, 1));
221 btVector3 b = btCross(v, btVector3(0, 1, 0));
222 if (a.length() > b.length())
224 return a.normalized();
228 return b.normalized();
233 int maxdirsterid(const T *p, int count, const T &dir, btAlignedObjectArray<int> &allow)
238 m = maxdirfiltered(p, count, dir, allow);
239 if (allow[m] == 3) return m;
241 T v = btCross(u, dir);
243 for (btScalar x = btScalar(0.0); x <= btScalar(360.0); x += btScalar(45.0))
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)
253 if (ma != -1 && ma != mb) // Yuck - this is really ugly
256 for (btScalar xx = x - btScalar(40.0); xx <= x; xx += btScalar(5.0))
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)
278 int operator==(const int3 &a, const int3 &b);
279 int operator==(const int3 &a, const int3 &b)
281 for (int i = 0; i < 3; i++)
283 if (a[i] != b[i]) return 0;
288 int above(btVector3 *vertices, const int3 &t, const btVector3 &p, btScalar epsilon);
289 int above(btVector3 *vertices, const int3 &t, const btVector3 &p, btScalar epsilon)
291 btVector3 n = TriNormal(vertices[t[0]], vertices[t[1]], vertices[t[2]]);
292 return (btDot(n, p - vertices[t[0]]) > epsilon); // EPSILON???
294 int hasedge(const int3 &t, int a, int b);
295 int hasedge(const int3 &t, int a, int b)
297 for (int i = 0; i < 3; i++)
299 int i1 = (i + 1) % 3;
300 if (t[i] == a && t[i1] == b) return 1;
304 int hasvert(const int3 &t, int v);
305 int hasvert(const int3 &t, int v)
307 return (t[0] == v || t[1] == v || t[2] == v);
309 int shareedge(const int3 &a, const int3 &b);
310 int shareedge(const int3 &a, const int3 &b)
313 for (i = 0; i < 3; i++)
315 int i1 = (i + 1) % 3;
316 if (hasedge(a, b[i1], b[i])) return 1;
321 class btHullTriangle;
323 class btHullTriangle : public int3
330 btHullTriangle(int a, int b, int c) : int3(a, b, c), n(-1, -1, -1)
333 rise = btScalar(0.0);
338 int &neib(int a, int b);
341 int &btHullTriangle::neib(int a, int b)
345 for (i = 0; i < 3; i++)
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];
355 void HullLibrary::b2bfix(btHullTriangle *s, btHullTriangle *t)
358 for (i = 0; i < 3; i++)
360 int i1 = (i + 1) % 3;
361 int i2 = (i + 2) % 3;
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);
371 void HullLibrary::removeb2b(btHullTriangle *s, btHullTriangle *t)
374 deAllocateTriangle(s);
376 deAllocateTriangle(t);
379 void HullLibrary::checkit(btHullTriangle *t)
384 btAssert(m_tris[t->id] == t);
385 for (i = 0; i < 3; i++)
387 int i1 = (i + 1) % 3;
388 int i2 = (i + 2) % 3;
392 // release compile fix
399 btAssert(m_tris[t->n[i]]->neib(b, a) == t->id);
403 btHullTriangle *HullLibrary::allocateTriangle(int a, int b, int c)
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);
413 void HullLibrary::deAllocateTriangle(btHullTriangle *tri)
415 btAssert(m_tris[tri->id] == tri);
416 m_tris[tri->id] = NULL;
417 tri->~btHullTriangle();
421 void HullLibrary::extrude(btHullTriangle *t0, int v)
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;
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);
443 btHullTriangle *HullLibrary::extrudable(btScalar epsilon)
446 btHullTriangle *t = NULL;
447 for (i = 0; i < m_tris.size(); i++)
449 if (!t || (m_tris[i] && t->rise < m_tris[i]->rise))
454 return (t->rise > epsilon) ? t : NULL;
457 int4 HullLibrary::FindSimplex(btVector3 *verts, int verts_count, btAlignedObjectArray<int> &allow)
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())
470 basis[1].normalize();
475 basis[1].normalize();
477 int p2 = maxdirsterid(verts, verts_count, basis[1], allow);
478 if (p2 == p0 || p2 == p1)
480 p2 = maxdirsterid(verts, verts_count, -basis[1], allow);
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)
495 return int4(p0, p1, p2, p3);
498 int HullLibrary::calchullgen(btVector3 *verts, int verts_count, int vlimit)
500 if (verts_count < 4) return 0;
501 if (vlimit == 0) vlimit = 1000000000;
503 btVector3 bmin(*verts), bmax(*verts);
504 btAlignedObjectArray<int> isextreme;
505 isextreme.reserve(verts_count);
506 btAlignedObjectArray<int> allow;
507 allow.reserve(verts_count);
509 for (j = 0; j < verts_count; j++)
512 isextreme.push_back(0);
513 bmin.setMin(verts[j]);
514 bmax.setMax(verts[j]);
516 btScalar epsilon = (bmax - bmin).length() * btScalar(0.001);
517 btAssert(epsilon != 0.0);
519 int4 p = FindSimplex(verts, verts_count, allow);
520 if (p.x == -1) return 0; // simplex failed
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;
537 for (j = 0; j < m_tris.size(); j++)
539 btHullTriangle *t = m_tris[j];
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]]);
548 while (vlimit > 0 && ((te = extrudable(epsilon)) != 0))
553 btAssert(!isextreme[v]); // wtf we've already done this vertex
555 //if(v==p0 || v==p1 || v==p2 || v==p3) continue; // done these already
559 if (!m_tris[j]) continue;
561 if (above(verts, t, verts[v], btScalar(0.01) * epsilon))
563 extrude(m_tris[j], v);
566 // now check for those degenerate cases where we have a flipped triangle or a really skinny triangle
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))
575 btHullTriangle *nb = m_tris[m_tris[j]->n[0]];
577 btAssert(!hasvert(*nb, v));
578 btAssert(nb->id < j);
586 btHullTriangle *t = m_tris[j];
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])
593 t->vmax = -1; // already done that vertex - algorithm needs to be able to terminate.
597 t->rise = btDot(n, verts[t->vmax] - verts[(*t)[0]]);
605 int HullLibrary::calchull(btVector3 *verts, int verts_count, TUIntArray &tris_out, int &tris_count, int vlimit)
607 int rc = calchullgen(verts, verts_count, vlimit);
609 btAlignedObjectArray<int> ts;
612 for (i = 0; i < m_tris.size(); i++)
616 for (int j = 0; j < 3; j++)
617 ts.push_back((*m_tris[i])[j]);
618 deAllocateTriangle(m_tris[i]);
621 tris_count = ts.size() / 3;
622 tris_out.resize(ts.size());
624 for (i = 0; i < ts.size(); i++)
626 tris_out[i] = static_cast<unsigned int>(ts[i]);
633 bool HullLibrary::ComputeHull(unsigned int vcount, const btVector3 *vertices, PHullResult &result, unsigned int vlimit)
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;
645 void ReleaseHull(PHullResult &result);
646 void ReleaseHull(PHullResult &result)
648 if (result.m_Indices.size())
650 result.m_Indices.clear();
654 result.mIndexCount = 0;
655 result.mVertices = 0;
658 //*********************************************************************
659 //*********************************************************************
660 //******** HullLib header
661 //*********************************************************************
662 //*********************************************************************
664 //*********************************************************************
665 //*********************************************************************
666 //******** HullLib implementation
667 //*********************************************************************
668 //*********************************************************************
670 HullError HullLibrary::CreateConvexHull(const HullDesc &desc, // describes the input request
671 HullResult &result) // contains the resulst
673 HullError ret = QE_FAIL;
677 unsigned int vcount = desc.mVcount;
678 if (vcount < 8) vcount = 8;
680 btAlignedObjectArray<btVector3> vertexSource;
683 vertexSource.resize(static_cast<int>(vcount), zero);
687 unsigned int ovcount;
689 bool ok = CleanupVertices(desc.mVcount, desc.mVertices, desc.mVertexStride, ovcount, &vertexSource[0], desc.mNormalEpsilon, scale); // normalize point cloud, remove duplicates!
693 // if ( 1 ) // scale vertices back to their original size.
695 for (unsigned int i = 0; i < ovcount; i++)
697 btVector3 &v = vertexSource[static_cast<int>(i)];
704 ok = ComputeHull(ovcount, &vertexSource[0], hr, desc.mMaxVertices);
708 // re-index triangle mesh so it refers to only used vertices, rebuild a new vertex table.
709 btAlignedObjectArray<btVector3> vertexScratch;
710 vertexScratch.resize(static_cast<int>(hr.mVcount));
712 BringOutYourDead(hr.mVertices, hr.mVcount, &vertexScratch[0], ovcount, &hr.m_Indices[0], hr.mIndexCount);
716 if (desc.HasHullFlag(QF_TRIANGLES)) // if he wants the results as triangle!
718 result.mPolygons = false;
719 result.mNumOutputVertices = ovcount;
720 result.m_OutputVertices.resize(static_cast<int>(ovcount));
721 result.mNumFaces = hr.mFaceCount;
722 result.mNumIndices = hr.mIndexCount;
724 result.m_Indices.resize(static_cast<int>(hr.mIndexCount));
726 memcpy(&result.m_OutputVertices[0], &vertexScratch[0], sizeof(btVector3) * ovcount);
728 if (desc.HasHullFlag(QF_REVERSE_ORDER))
730 const unsigned int *source = &hr.m_Indices[0];
731 unsigned int *dest = &result.m_Indices[0];
733 for (unsigned int i = 0; i < hr.mFaceCount; i++)
744 memcpy(&result.m_Indices[0], &hr.m_Indices[0], sizeof(unsigned int) * hr.mIndexCount);
749 result.mPolygons = true;
750 result.mNumOutputVertices = ovcount;
751 result.m_OutputVertices.resize(static_cast<int>(ovcount));
752 result.mNumFaces = hr.mFaceCount;
753 result.mNumIndices = hr.mIndexCount + hr.mFaceCount;
754 result.m_Indices.resize(static_cast<int>(result.mNumIndices));
755 memcpy(&result.m_OutputVertices[0], &vertexScratch[0], sizeof(btVector3) * ovcount);
759 const unsigned int *source = &hr.m_Indices[0];
760 unsigned int *dest = &result.m_Indices[0];
761 for (unsigned int i = 0; i < hr.mFaceCount; i++)
764 if (desc.HasHullFlag(QF_REVERSE_ORDER))
789 HullError HullLibrary::ReleaseResult(HullResult &result) // release memory allocated for this result, we are done with it.
791 if (result.m_OutputVertices.size())
793 result.mNumOutputVertices = 0;
794 result.m_OutputVertices.clear();
796 if (result.m_Indices.size())
798 result.mNumIndices = 0;
799 result.m_Indices.clear();
804 static void addPoint(unsigned int &vcount, btVector3 *p, btScalar x, btScalar y, btScalar z)
806 // XXX, might be broken
807 btVector3 &dest = p[vcount];
814 btScalar GetDist(btScalar px, btScalar py, btScalar pz, const btScalar *p2);
815 btScalar GetDist(btScalar px, btScalar py, btScalar pz, const btScalar *p2)
817 btScalar dx = px - p2[0];
818 btScalar dy = py - p2[1];
819 btScalar dz = pz - p2[2];
821 return dx * dx + dy * dy + dz * dz;
824 bool HullLibrary::CleanupVertices(unsigned int svcount,
825 const btVector3 *svertices,
827 unsigned int &vcount, // output number of vertices
828 btVector3 *vertices, // location to store the results.
829 btScalar normalepsilon,
832 if (svcount == 0) return false;
834 m_vertexIndexMapping.resize(0);
836 #define EPSILON btScalar(0.000001) /* close enough to consider two btScalaring point numbers to be 'the same'. */
840 btScalar recip[3] = {0.f, 0.f, 0.f};
849 btScalar bmin[3] = {FLT_MAX, FLT_MAX, FLT_MAX};
850 btScalar bmax[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
852 const char *vtx = (const char *)svertices;
856 for (unsigned int i = 0; i < svcount; i++)
858 const btScalar *p = (const btScalar *)vtx;
862 for (int j = 0; j < 3; j++)
864 if (p[j] < bmin[j]) bmin[j] = p[j];
865 if (p[j] > bmax[j]) bmax[j] = p[j];
870 btScalar dx = bmax[0] - bmin[0];
871 btScalar dy = bmax[1] - bmin[1];
872 btScalar dz = bmax[2] - bmin[2];
876 center[0] = dx * btScalar(0.5) + bmin[0];
877 center[1] = dy * btScalar(0.5) + bmin[1];
878 center[2] = dz * btScalar(0.5) + bmin[2];
880 if (dx < EPSILON || dy < EPSILON || dz < EPSILON || svcount < 3)
882 btScalar len = FLT_MAX;
884 if (dx > EPSILON && dx < len) len = dx;
885 if (dy > EPSILON && dy < len) len = dy;
886 if (dz > EPSILON && dz < len) len = dz;
890 dx = dy = dz = btScalar(0.01); // one centimeter
894 if (dx < EPSILON) dx = len * btScalar(0.05); // 1/5th the shortest non-zero edge.
895 if (dy < EPSILON) dy = len * btScalar(0.05);
896 if (dz < EPSILON) dz = len * btScalar(0.05);
899 btScalar x1 = center[0] - dx;
900 btScalar x2 = center[0] + dx;
902 btScalar y1 = center[1] - dy;
903 btScalar y2 = center[1] + dy;
905 btScalar z1 = center[2] - dz;
906 btScalar z2 = center[2] + dz;
908 addPoint(vcount, vertices, x1, y1, z1);
909 addPoint(vcount, vertices, x2, y1, z1);
910 addPoint(vcount, vertices, x2, y2, z1);
911 addPoint(vcount, vertices, x1, y2, z1);
912 addPoint(vcount, vertices, x1, y1, z2);
913 addPoint(vcount, vertices, x2, y1, z2);
914 addPoint(vcount, vertices, x2, y2, z2);
915 addPoint(vcount, vertices, x1, y2, z2);
917 return true; // return cube
931 center[0] *= recip[0];
932 center[1] *= recip[1];
933 center[2] *= recip[2];
937 vtx = (const char *)svertices;
939 for (unsigned int i = 0; i < svcount; i++)
941 const btVector3 *p = (const btVector3 *)vtx;
944 btScalar px = p->getX();
945 btScalar py = p->getY();
946 btScalar pz = p->getZ();
950 px = px * recip[0]; // normalize
951 py = py * recip[1]; // normalize
952 pz = pz * recip[2]; // normalize
959 for (j = 0; j < vcount; j++)
961 /// XXX might be broken
962 btVector3 &v = vertices[j];
968 btScalar dx = btFabs(x - px);
969 btScalar dy = btFabs(y - py);
970 btScalar dz = btFabs(z - pz);
972 if (dx < normalepsilon && dy < normalepsilon && dz < normalepsilon)
974 // ok, it is close enough to the old one
975 // now let us see if it is further from the center of the point cloud than the one we already recorded.
976 // in which case we keep this one instead.
978 btScalar dist1 = GetDist(px, py, pz, center);
979 btScalar dist2 = GetDist(v[0], v[1], v[2], center);
994 btVector3 &dest = vertices[vcount];
1000 m_vertexIndexMapping.push_back(j);
1004 // ok..now make sure we didn't prune so many vertices it is now invalid.
1007 btScalar bmin[3] = {FLT_MAX, FLT_MAX, FLT_MAX};
1008 btScalar bmax[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
1010 for (unsigned int i = 0; i < vcount; i++)
1012 const btVector3 &p = vertices[i];
1013 for (int j = 0; j < 3; j++)
1015 if (p[j] < bmin[j]) bmin[j] = p[j];
1016 if (p[j] > bmax[j]) bmax[j] = p[j];
1020 btScalar dx = bmax[0] - bmin[0];
1021 btScalar dy = bmax[1] - bmin[1];
1022 btScalar dz = bmax[2] - bmin[2];
1024 if (dx < EPSILON || dy < EPSILON || dz < EPSILON || vcount < 3)
1026 btScalar cx = dx * btScalar(0.5) + bmin[0];
1027 btScalar cy = dy * btScalar(0.5) + bmin[1];
1028 btScalar cz = dz * btScalar(0.5) + bmin[2];
1030 btScalar len = FLT_MAX;
1032 if (dx >= EPSILON && dx < len) len = dx;
1033 if (dy >= EPSILON && dy < len) len = dy;
1034 if (dz >= EPSILON && dz < len) len = dz;
1038 dx = dy = dz = btScalar(0.01); // one centimeter
1042 if (dx < EPSILON) dx = len * btScalar(0.05); // 1/5th the shortest non-zero edge.
1043 if (dy < EPSILON) dy = len * btScalar(0.05);
1044 if (dz < EPSILON) dz = len * btScalar(0.05);
1047 btScalar x1 = cx - dx;
1048 btScalar x2 = cx + dx;
1050 btScalar y1 = cy - dy;
1051 btScalar y2 = cy + dy;
1053 btScalar z1 = cz - dz;
1054 btScalar z2 = cz + dz;
1056 vcount = 0; // add box
1058 addPoint(vcount, vertices, x1, y1, z1);
1059 addPoint(vcount, vertices, x2, y1, z1);
1060 addPoint(vcount, vertices, x2, y2, z1);
1061 addPoint(vcount, vertices, x1, y2, z1);
1062 addPoint(vcount, vertices, x1, y1, z2);
1063 addPoint(vcount, vertices, x2, y1, z2);
1064 addPoint(vcount, vertices, x2, y2, z2);
1065 addPoint(vcount, vertices, x1, y2, z2);
1074 void HullLibrary::BringOutYourDead(const btVector3 *verts, unsigned int vcount, btVector3 *overts, unsigned int &ocount, unsigned int *indices, unsigned indexcount)
1076 btAlignedObjectArray<int> tmpIndices;
1077 tmpIndices.resize(m_vertexIndexMapping.size());
1080 for (i = 0; i < m_vertexIndexMapping.size(); i++)
1082 tmpIndices[i] = m_vertexIndexMapping[i];
1085 TUIntArray usedIndices;
1086 usedIndices.resize(static_cast<int>(vcount));
1087 memset(&usedIndices[0], 0, sizeof(unsigned int) * vcount);
1091 for (i = 0; i < int(indexcount); i++)
1093 unsigned int v = indices[i]; // original array index
1095 btAssert(v >= 0 && v < vcount);
1097 if (usedIndices[static_cast<int>(v)]) // if already remapped
1099 indices[i] = usedIndices[static_cast<int>(v)] - 1; // index to new array
1103 indices[i] = ocount; // new index mapping
1105 overts[ocount][0] = verts[v][0]; // copy old vert to new vert array
1106 overts[ocount][1] = verts[v][1];
1107 overts[ocount][2] = verts[v][2];
1109 for (int k = 0; k < m_vertexIndexMapping.size(); k++)
1111 if (tmpIndices[k] == int(v))
1112 m_vertexIndexMapping[k] = ocount;
1115 ocount++; // increment output vert count
1117 btAssert(ocount >= 0 && ocount <= vcount);
1119 usedIndices[static_cast<int>(v)] = ocount; // assign new index remapping