aboutsummaryrefslogtreecommitdiff
path: root/APEX_1.4/shared/general/HACD/src/dgPolyhedra.cpp
diff options
context:
space:
mode:
authorgit perforce import user <a@b>2016-10-25 12:29:14 -0600
committerSheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees>2016-10-25 18:56:37 -0500
commit3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch)
treefa6485c169e50d7415a651bf838f5bcd0fd3bfbd /APEX_1.4/shared/general/HACD/src/dgPolyhedra.cpp
downloadphysx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz
physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip
Initial commit:
PhysX 3.4.0 Update @ 21294896 APEX 1.4.0 Update @ 21275617 [CL 21300167]
Diffstat (limited to 'APEX_1.4/shared/general/HACD/src/dgPolyhedra.cpp')
-rw-r--r--APEX_1.4/shared/general/HACD/src/dgPolyhedra.cpp2433
1 files changed, 2433 insertions, 0 deletions
diff --git a/APEX_1.4/shared/general/HACD/src/dgPolyhedra.cpp b/APEX_1.4/shared/general/HACD/src/dgPolyhedra.cpp
new file mode 100644
index 00000000..5e43af37
--- /dev/null
+++ b/APEX_1.4/shared/general/HACD/src/dgPolyhedra.cpp
@@ -0,0 +1,2433 @@
+/* Copyright (c) <2003-2011> <Julio Jerez, Newton Game Dynamics>
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+*
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+*
+* 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.
+*
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+*
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "dgTypes.h"
+#include "dgHeap.h"
+#include "dgStack.h"
+#include "dgSphere.h"
+#include "dgPolyhedra.h"
+#include "dgConvexHull3d.h"
+#include "dgSmallDeterminant.h"
+#include <string.h>
+
+
+//#define DG_MIN_EDGE_ASPECT_RATIO double (0.02f)
+
+class dgDiagonalEdge
+{
+ public:
+ dgDiagonalEdge (dgEdge* const edge)
+ :m_i0(edge->m_incidentVertex), m_i1(edge->m_twin->m_incidentVertex)
+ {
+ }
+ int32_t m_i0;
+ int32_t m_i1;
+};
+
+
+struct dgEdgeCollapseEdgeHandle
+{
+ dgEdgeCollapseEdgeHandle (dgEdge* const newEdge)
+ :m_inList(false), m_edge(newEdge)
+ {
+ }
+
+ dgEdgeCollapseEdgeHandle (const dgEdgeCollapseEdgeHandle &dataHandle)
+ :m_inList(true), m_edge(dataHandle.m_edge)
+ {
+ dgEdgeCollapseEdgeHandle* const handle = (dgEdgeCollapseEdgeHandle *)IntToPointer (m_edge->m_userData);
+ if (handle) {
+ HACD_ASSERT (handle != this);
+ handle->m_edge = NULL;
+ }
+ m_edge->m_userData = uint64_t (PointerToInt(this));
+ }
+
+ ~dgEdgeCollapseEdgeHandle ()
+ {
+ if (m_inList) {
+ if (m_edge) {
+ dgEdgeCollapseEdgeHandle* const handle = (dgEdgeCollapseEdgeHandle *)IntToPointer (m_edge->m_userData);
+ if (handle == this) {
+ m_edge->m_userData = PointerToInt (NULL);
+ }
+ }
+ }
+ m_edge = NULL;
+ }
+
+ uint32_t m_inList;
+ dgEdge* m_edge;
+};
+
+
+class dgVertexCollapseVertexMetric
+{
+ public:
+ double elem[10];
+
+ dgVertexCollapseVertexMetric (const dgBigPlane &plane)
+ {
+ elem[0] = plane.m_x * plane.m_x;
+ elem[1] = plane.m_y * plane.m_y;
+ elem[2] = plane.m_z * plane.m_z;
+ elem[3] = plane.m_w * plane.m_w;
+ elem[4] = double (2.0) * plane.m_x * plane.m_y;
+ elem[5] = double (2.0) * plane.m_x * plane.m_z;
+ elem[6] = double (2.0) * plane.m_x * plane.m_w;
+ elem[7] = double (2.0) * plane.m_y * plane.m_z;
+ elem[8] = double (2.0) * plane.m_y * plane.m_w;
+ elem[9] = double (2.0) * plane.m_z * plane.m_w;
+ }
+
+ void Clear ()
+ {
+ memset (elem, 0, 10 * sizeof (double));
+ }
+
+ void Accumulate (const dgVertexCollapseVertexMetric& p)
+ {
+ elem[0] += p.elem[0];
+ elem[1] += p.elem[1];
+ elem[2] += p.elem[2];
+ elem[3] += p.elem[3];
+ elem[4] += p.elem[4];
+ elem[5] += p.elem[5];
+ elem[6] += p.elem[6];
+ elem[7] += p.elem[7];
+ elem[8] += p.elem[8];
+ elem[9] += p.elem[9];
+ }
+
+ void Accumulate (const dgBigPlane& plane)
+ {
+ elem[0] += plane.m_x * plane.m_x;
+ elem[1] += plane.m_y * plane.m_y;
+ elem[2] += plane.m_z * plane.m_z;
+ elem[3] += plane.m_w * plane.m_w;
+
+ elem[4] += double (2.0f) * plane.m_x * plane.m_y;
+ elem[5] += double (2.0f) * plane.m_x * plane.m_z;
+ elem[7] += double (2.0f) * plane.m_y * plane.m_z;
+
+ elem[6] += double (2.0f) * plane.m_x * plane.m_w;
+ elem[8] += double (2.0f) * plane.m_y * plane.m_w;
+ elem[9] += double (2.0f) * plane.m_z * plane.m_w;
+ }
+
+
+ double Evalue (const dgVector &p) const
+ {
+ double acc = elem[0] * p.m_x * p.m_x + elem[1] * p.m_y * p.m_y + elem[2] * p.m_z * p.m_z +
+ elem[4] * p.m_x * p.m_y + elem[5] * p.m_x * p.m_z + elem[7] * p.m_y * p.m_z +
+ elem[6] * p.m_x + elem[8] * p.m_y + elem[9] * p.m_z + elem[3];
+ return fabs (acc);
+ }
+};
+
+
+
+dgPolyhedra::dgPolyhedra (void)
+ :dgTree <dgEdge, int64_t>()
+ ,m_baseMark(0)
+ ,m_edgeMark(0)
+ ,m_faceSecuence(0)
+{
+}
+
+dgPolyhedra::dgPolyhedra (const dgPolyhedra &polyhedra)
+ :dgTree <dgEdge, int64_t>()
+ ,m_baseMark(0)
+ ,m_edgeMark(0)
+ ,m_faceSecuence(0)
+{
+ dgStack<int32_t> indexPool (1024 * 16);
+ dgStack<uint64_t> userPool (1024 * 16);
+ int32_t* const index = &indexPool[0];
+ uint64_t* const user = &userPool[0];
+
+ BeginFace ();
+ Iterator iter(polyhedra);
+ for (iter.Begin(); iter; iter ++) {
+ dgEdge* const edge = &(*iter);
+ if (edge->m_incidentFace < 0) {
+ continue;
+ }
+
+ if (!FindEdge(edge->m_incidentVertex, edge->m_twin->m_incidentVertex)) {
+ int32_t indexCount = 0;
+ dgEdge* ptr = edge;
+ do {
+ user[indexCount] = ptr->m_userData;
+ index[indexCount] = ptr->m_incidentVertex;
+ indexCount ++;
+ ptr = ptr->m_next;
+ } while (ptr != edge);
+
+ dgEdge* const face = AddFace (indexCount, index, (int64_t*) user);
+ ptr = face;
+ do {
+ ptr->m_incidentFace = edge->m_incidentFace;
+ ptr = ptr->m_next;
+ } while (ptr != face);
+ }
+ }
+ EndFace();
+
+ m_faceSecuence = polyhedra.m_faceSecuence;
+
+#ifdef __ENABLE_SANITY_CHECK
+ HACD_ASSERT (SanityCheck());
+#endif
+}
+
+dgPolyhedra::~dgPolyhedra ()
+{
+}
+
+
+int32_t dgPolyhedra::GetFaceCount() const
+{
+ Iterator iter (*this);
+ int32_t count = 0;
+ int32_t mark = IncLRU();
+ for (iter.Begin(); iter; iter ++) {
+ dgEdge* const edge = &(*iter);
+ if (edge->m_mark == mark) {
+ continue;
+ }
+
+ if (edge->m_incidentFace < 0) {
+ continue;
+ }
+
+ count ++;
+ dgEdge* ptr = edge;
+ do {
+ ptr->m_mark = mark;
+ ptr = ptr->m_next;
+ } while (ptr != edge);
+ }
+ return count;
+}
+
+
+
+dgEdge* dgPolyhedra::AddFace ( int32_t count, const int32_t* const index, const int64_t* const userdata)
+{
+ class IntersectionFilter
+ {
+ public:
+ IntersectionFilter ()
+ {
+ m_count = 0;
+ }
+
+ bool Insert (int32_t /*dummy*/, int64_t value)
+ {
+ int32_t i;
+ for (i = 0 ; i < m_count; i ++) {
+ if (m_array[i] == value) {
+ return false;
+ }
+ }
+ m_array[i] = value;
+ m_count ++;
+ return true;
+ }
+
+ int32_t m_count;
+ int64_t m_array[2048];
+ };
+
+ IntersectionFilter selfIntersectingFaceFilter;
+
+ int32_t dummyValues = 0;
+ int32_t i0 = index[count-1];
+ for (int32_t i = 0; i < count; i ++) {
+ int32_t i1 = index[i];
+ dgPairKey code0 (i0, i1);
+
+ if (!selfIntersectingFaceFilter.Insert (dummyValues, code0.GetVal())) {
+ return NULL;
+ }
+
+ dgPairKey code1 (i1, i0);
+ if (!selfIntersectingFaceFilter.Insert (dummyValues, code1.GetVal())) {
+ return NULL;
+ }
+
+
+ if (i0 == i1) {
+ return NULL;
+ }
+ if (FindEdge (i0, i1)) {
+ return NULL;
+ }
+ i0 = i1;
+ }
+
+ m_faceSecuence ++;
+
+ i0 = index[count-1];
+ int32_t i1 = index[0];
+ uint64_t udata0 = 0;
+ uint64_t udata1 = 0;
+ if (userdata) {
+ udata0 = uint64_t (userdata[count-1]);
+ udata1 = uint64_t (userdata[0]);
+ }
+
+ bool state;
+ dgPairKey code (i0, i1);
+ dgEdge tmpEdge (i0, m_faceSecuence, udata0);
+ dgTreeNode* node = Insert (tmpEdge, code.GetVal(), state);
+ HACD_ASSERT (!state);
+ dgEdge* edge0 = &node->GetInfo();
+ dgEdge* const first = edge0;
+
+ for (int32_t i = 1; i < count; i ++) {
+ i0 = i1;
+ i1 = index[i];
+ udata0 = udata1;
+ udata1 = uint64_t (userdata ? userdata[i] : 0);
+
+ dgPairKey code (i0, i1);
+ dgEdge tmpEdge (i0, m_faceSecuence, udata0);
+ node = Insert (tmpEdge, code.GetVal(), state);
+ HACD_ASSERT (!state);
+
+ dgEdge* const edge1 = &node->GetInfo();
+ edge0->m_next = edge1;
+ edge1->m_prev = edge0;
+ edge0 = edge1;
+ }
+
+ first->m_prev = edge0;
+ edge0->m_next = first;
+
+ return first->m_next;
+}
+
+
+void dgPolyhedra::EndFace ()
+{
+ dgPolyhedra::Iterator iter (*this);
+
+ // Connect all twin edge
+ for (iter.Begin(); iter; iter ++) {
+ dgEdge* const edge = &(*iter);
+ if (!edge->m_twin) {
+ edge->m_twin = FindEdge (edge->m_next->m_incidentVertex, edge->m_incidentVertex);
+ if (edge->m_twin) {
+ edge->m_twin->m_twin = edge;
+ }
+ }
+ }
+
+#ifdef __ENABLE_SANITY_CHECK
+ HACD_ASSERT (SanityCheck());
+#endif
+ dgStack<dgEdge*> edgeArrayPool(GetCount() * 2 + 256);
+
+ int32_t edgeCount = 0;
+ dgEdge** const edgeArray = &edgeArrayPool[0];
+ for (iter.Begin(); iter; iter ++) {
+ dgEdge* const edge = &(*iter);
+ if (!edge->m_twin) {
+ bool state;
+ dgPolyhedra::dgPairKey code (edge->m_next->m_incidentVertex, edge->m_incidentVertex);
+ dgEdge tmpEdge (edge->m_next->m_incidentVertex, -1);
+ tmpEdge.m_incidentFace = -1;
+ dgPolyhedra::dgTreeNode* const node = Insert (tmpEdge, code.GetVal(), state);
+ HACD_ASSERT (!state);
+ edge->m_twin = &node->GetInfo();
+ edge->m_twin->m_twin = edge;
+ edgeArray[edgeCount] = edge->m_twin;
+ edgeCount ++;
+ }
+ }
+
+ for (int32_t i = 0; i < edgeCount; i ++) {
+ dgEdge* const edge = edgeArray[i];
+ HACD_ASSERT (!edge->m_prev);
+ dgEdge *ptr = edge->m_twin;
+ for (; ptr->m_next; ptr = ptr->m_next->m_twin){}
+ ptr->m_next = edge;
+ edge->m_prev = ptr;
+ }
+
+#ifdef __ENABLE_SANITY_CHECK
+ HACD_ASSERT (SanityCheck ());
+#endif
+}
+
+
+void dgPolyhedra::DeleteFace(dgEdge* const face)
+{
+ dgEdge* edgeList[1024 * 16];
+
+ if (face->m_incidentFace > 0) {
+ int32_t count = 0;
+ dgEdge* ptr = face;
+ do {
+ ptr->m_incidentFace = -1;
+ int32_t i = 0;
+ for (; i < count; i ++) {
+ if ((edgeList[i] == ptr) || (edgeList[i]->m_twin == ptr)) {
+ break;
+ }
+ }
+ if (i == count) {
+ edgeList[count] = ptr;
+ count ++;
+ }
+ ptr = ptr->m_next;
+ } while (ptr != face);
+
+
+ for (int32_t i = 0; i < count; i ++) {
+ dgEdge* const ptr = edgeList[i];
+ if (ptr->m_twin->m_incidentFace < 0) {
+ DeleteEdge (ptr);
+ }
+ }
+ }
+}
+
+
+
+dgBigVector dgPolyhedra::FaceNormal (dgEdge* const face, const double* const pool, int32_t strideInBytes) const
+{
+ int32_t stride = strideInBytes / (int32_t)sizeof (double);
+ dgEdge* edge = face;
+ dgBigVector p0 (&pool[edge->m_incidentVertex * stride]);
+ edge = edge->m_next;
+ dgBigVector p1 (&pool[edge->m_incidentVertex * stride]);
+ dgBigVector e1 (p1 - p0);
+
+ dgBigVector normal (float (0.0f), float (0.0f), float (0.0f), float (0.0f));
+ for (edge = edge->m_next; edge != face; edge = edge->m_next) {
+ dgBigVector p2 (&pool[edge->m_incidentVertex * stride]);
+ dgBigVector e2 (p2 - p0);
+ normal += e1 * e2;
+ e1 = e2;
+ }
+ return normal;
+}
+
+
+dgEdge* dgPolyhedra::AddHalfEdge (int32_t v0, int32_t v1)
+{
+ if (v0 != v1) {
+ dgPairKey pairKey (v0, v1);
+ dgEdge tmpEdge (v0, -1);
+
+ dgTreeNode* node = Insert (tmpEdge, pairKey.GetVal());
+ return node ? &node->GetInfo() : NULL;
+ } else {
+ return NULL;
+ }
+}
+
+
+void dgPolyhedra::DeleteEdge (dgEdge* const edge)
+{
+ dgEdge *const twin = edge->m_twin;
+
+ edge->m_prev->m_next = twin->m_next;
+ twin->m_next->m_prev = edge->m_prev;
+ edge->m_next->m_prev = twin->m_prev;
+ twin->m_prev->m_next = edge->m_next;
+
+ dgTreeNode *const nodeA = GetNodeFromInfo (*edge);
+ dgTreeNode *const nodeB = GetNodeFromInfo (*twin);
+
+ HACD_ASSERT (&nodeA->GetInfo() == edge);
+ HACD_ASSERT (&nodeB->GetInfo() == twin);
+
+ Remove (nodeA);
+ Remove (nodeB);
+}
+
+
+dgEdge* dgPolyhedra::SpliteEdge (int32_t newIndex, dgEdge* const edge)
+{
+ dgEdge* const edge00 = edge->m_prev;
+ dgEdge* const edge01 = edge->m_next;
+ dgEdge* const twin00 = edge->m_twin->m_next;
+ dgEdge* const twin01 = edge->m_twin->m_prev;
+
+ int32_t i0 = edge->m_incidentVertex;
+ int32_t i1 = edge->m_twin->m_incidentVertex;
+
+ int32_t f0 = edge->m_incidentFace;
+ int32_t f1 = edge->m_twin->m_incidentFace;
+
+ DeleteEdge (edge);
+
+ dgEdge* const edge0 = AddHalfEdge (i0, newIndex);
+ dgEdge* const edge1 = AddHalfEdge (newIndex, i1);
+
+ dgEdge* const twin0 = AddHalfEdge (newIndex, i0);
+ dgEdge* const twin1 = AddHalfEdge (i1, newIndex);
+ HACD_ASSERT (edge0);
+ HACD_ASSERT (edge1);
+ HACD_ASSERT (twin0);
+ HACD_ASSERT (twin1);
+
+ edge0->m_twin = twin0;
+ twin0->m_twin = edge0;
+
+ edge1->m_twin = twin1;
+ twin1->m_twin = edge1;
+
+ edge0->m_next = edge1;
+ edge1->m_prev = edge0;
+
+ twin1->m_next = twin0;
+ twin0->m_prev = twin1;
+
+ edge0->m_prev = edge00;
+ edge00 ->m_next = edge0;
+
+ edge1->m_next = edge01;
+ edge01->m_prev = edge1;
+
+ twin0->m_next = twin00;
+ twin00->m_prev = twin0;
+
+ twin1->m_prev = twin01;
+ twin01->m_next = twin1;
+
+ edge0->m_incidentFace = f0;
+ edge1->m_incidentFace = f0;
+
+ twin0->m_incidentFace = f1;
+ twin1->m_incidentFace = f1;
+
+#ifdef __ENABLE_SANITY_CHECK
+ // HACD_ASSERT (SanityCheck ());
+#endif
+
+ return edge0;
+}
+
+
+
+bool dgPolyhedra::FlipEdge (dgEdge* const edge)
+{
+ // dgTreeNode *node;
+ if (edge->m_next->m_next->m_next != edge) {
+ return false;
+ }
+
+ if (edge->m_twin->m_next->m_next->m_next != edge->m_twin) {
+ return false;
+ }
+
+ if (FindEdge(edge->m_prev->m_incidentVertex, edge->m_twin->m_prev->m_incidentVertex)) {
+ return false;
+ }
+
+ dgEdge *const prevEdge = edge->m_prev;
+ dgEdge *const prevTwin = edge->m_twin->m_prev;
+
+ dgPairKey edgeKey (prevTwin->m_incidentVertex, prevEdge->m_incidentVertex);
+ dgPairKey twinKey (prevEdge->m_incidentVertex, prevTwin->m_incidentVertex);
+
+ ReplaceKey (GetNodeFromInfo (*edge), edgeKey.GetVal());
+ // HACD_ASSERT (node);
+
+ ReplaceKey (GetNodeFromInfo (*edge->m_twin), twinKey.GetVal());
+ // HACD_ASSERT (node);
+
+ edge->m_incidentVertex = prevTwin->m_incidentVertex;
+ edge->m_twin->m_incidentVertex = prevEdge->m_incidentVertex;
+
+ edge->m_userData = prevTwin->m_userData;
+ edge->m_twin->m_userData = prevEdge->m_userData;
+
+ prevEdge->m_next = edge->m_twin->m_next;
+ prevTwin->m_prev->m_prev = edge->m_prev;
+
+ prevTwin->m_next = edge->m_next;
+ prevEdge->m_prev->m_prev = edge->m_twin->m_prev;
+
+ edge->m_prev = prevTwin->m_prev;
+ edge->m_next = prevEdge;
+
+ edge->m_twin->m_prev = prevEdge->m_prev;
+ edge->m_twin->m_next = prevTwin;
+
+ prevTwin->m_prev->m_next = edge;
+ prevTwin->m_prev = edge->m_twin;
+
+ prevEdge->m_prev->m_next = edge->m_twin;
+ prevEdge->m_prev = edge;
+
+ edge->m_next->m_incidentFace = edge->m_incidentFace;
+ edge->m_prev->m_incidentFace = edge->m_incidentFace;
+
+ edge->m_twin->m_next->m_incidentFace = edge->m_twin->m_incidentFace;
+ edge->m_twin->m_prev->m_incidentFace = edge->m_twin->m_incidentFace;
+
+
+#ifdef __ENABLE_SANITY_CHECK
+ HACD_ASSERT (SanityCheck ());
+#endif
+
+ return true;
+}
+
+
+
+bool dgPolyhedra::GetConectedSurface (dgPolyhedra &polyhedra) const
+{
+ if (!GetCount()) {
+ return false;
+ }
+
+ dgEdge* edge = NULL;
+ Iterator iter(*this);
+ for (iter.Begin (); iter; iter ++) {
+ edge = &(*iter);
+ if ((edge->m_mark < m_baseMark) && (edge->m_incidentFace > 0)) {
+ break;
+ }
+ }
+
+ if (!iter) {
+ return false;
+ }
+
+ int32_t faceIndex[4096];
+ int64_t faceDataIndex[4096];
+ dgStack<dgEdge*> stackPool (GetCount());
+ dgEdge** const stack = &stackPool[0];
+
+ int32_t mark = IncLRU();
+
+ polyhedra.BeginFace ();
+ stack[0] = edge;
+ int32_t index = 1;
+ while (index) {
+ index --;
+ dgEdge* const edge = stack[index];
+
+ if (edge->m_mark == mark) {
+ continue;
+ }
+
+ int32_t count = 0;
+ dgEdge* ptr = edge;
+ do {
+ ptr->m_mark = mark;
+ faceIndex[count] = ptr->m_incidentVertex;
+ faceDataIndex[count] = int64_t (ptr->m_userData);
+ count ++;
+ HACD_ASSERT (count < int32_t ((sizeof (faceIndex)/sizeof(faceIndex[0]))));
+
+ if ((ptr->m_twin->m_incidentFace > 0) && (ptr->m_twin->m_mark != mark)) {
+ stack[index] = ptr->m_twin;
+ index ++;
+ HACD_ASSERT (index < GetCount());
+ }
+
+ ptr = ptr->m_next;
+ } while (ptr != edge);
+
+ polyhedra.AddFace (count, &faceIndex[0], &faceDataIndex[0]);
+ }
+
+ polyhedra.EndFace ();
+
+ return true;
+}
+
+
+void dgPolyhedra::ChangeEdgeIncidentVertex (dgEdge* const edge, int32_t newIndex)
+{
+ dgEdge* ptr = edge;
+ do {
+ dgTreeNode* node = GetNodeFromInfo(*ptr);
+ dgPairKey Key0 (newIndex, ptr->m_twin->m_incidentVertex);
+ ReplaceKey (node, Key0.GetVal());
+
+ node = GetNodeFromInfo(*ptr->m_twin);
+ dgPairKey Key1 (ptr->m_twin->m_incidentVertex, newIndex);
+ ReplaceKey (node, Key1.GetVal());
+
+ ptr->m_incidentVertex = newIndex;
+
+ ptr = ptr->m_twin->m_next;
+ } while (ptr != edge);
+}
+
+
+void dgPolyhedra::DeleteDegenerateFaces (const double* const pool, int32_t strideInBytes, double area)
+{
+ if (!GetCount()) {
+ return;
+ }
+
+#ifdef __ENABLE_SANITY_CHECK
+ HACD_ASSERT (SanityCheck ());
+#endif
+ dgStack <dgPolyhedra::dgTreeNode*> faceArrayPool(GetCount() / 2 + 100);
+
+ int32_t count = 0;
+ dgPolyhedra::dgTreeNode** const faceArray = &faceArrayPool[0];
+ int32_t mark = IncLRU();
+ Iterator iter (*this);
+ for (iter.Begin(); iter; iter ++) {
+ dgEdge* const edge = &(*iter);
+
+ if ((edge->m_mark != mark) && (edge->m_incidentFace > 0)) {
+ faceArray[count] = iter.GetNode();
+ count ++;
+ dgEdge* ptr = edge;
+ do {
+ ptr->m_mark = mark;
+ ptr = ptr->m_next;
+ } while (ptr != edge);
+ }
+ }
+
+ double area2 = area * area;
+ area2 *= double (4.0f);
+
+ for (int32_t i = 0; i < count; i ++) {
+ dgPolyhedra::dgTreeNode* const faceNode = faceArray[i];
+ dgEdge* const edge = &faceNode->GetInfo();
+
+ dgBigVector normal (FaceNormal (edge, pool, strideInBytes));
+
+ double faceArea = normal % normal;
+ if (faceArea < area2) {
+ DeleteFace (edge);
+ }
+ }
+
+#ifdef __ENABLE_SANITY_CHECK
+ mark = IncLRU();
+ for (iter.Begin(); iter; iter ++) {
+ dgEdge* const edge = &(*iter);
+ if ((edge->m_mark != mark) && (edge->m_incidentFace > 0)) {
+ //HACD_ASSERT (edge->m_next->m_next->m_next == edge);
+ dgEdge* ptr = edge;
+ do {
+ ptr->m_mark = mark;
+ ptr = ptr->m_next;
+ } while (ptr != edge);
+
+ dgBigVector normal (FaceNormal (edge, pool, strideInBytes));
+
+ double faceArea = normal % normal;
+ HACD_ASSERT (faceArea >= area2);
+ }
+ }
+ HACD_ASSERT (SanityCheck ());
+#endif
+}
+
+
+static void NormalizeVertex (int32_t count, dgBigVector* const dst, const double* const src, int32_t stride)
+{
+// dgBigVector min;
+// dgBigVector max;
+// GetMinMax (min, max, src, count, int32_t (stride * sizeof (double)));
+// dgBigVector centre (float (0.0f), float (0.0f), float (0.0f), float (0.0f));
+ for (int32_t i = 0; i < count; i ++) {
+// dst[i].m_x = centre.m_x + src[i * stride + 0];
+// dst[i].m_y = centre.m_y + src[i * stride + 1];
+// dst[i].m_z = centre.m_z + src[i * stride + 2];
+ dst[i].m_x = src[i * stride + 0];
+ dst[i].m_y = src[i * stride + 1];
+ dst[i].m_z = src[i * stride + 2];
+ dst[i].m_w= double (0.0f);
+ }
+}
+
+static dgBigPlane EdgePlane (int32_t i0, int32_t i1, int32_t i2, const dgBigVector* const pool)
+{
+ const dgBigVector& p0 = pool[i0];
+ const dgBigVector& p1 = pool[i1];
+ const dgBigVector& p2 = pool[i2];
+
+ dgBigPlane plane (p0, p1, p2);
+ double mag = sqrt (plane % plane);
+ if (mag < double (1.0e-12f)) {
+ mag = double (1.0e-12f);
+ }
+ mag = double (1.0f) / mag;
+
+ plane.m_x *= mag;
+ plane.m_y *= mag;
+ plane.m_z *= mag;
+ plane.m_w *= mag;
+
+ return plane;
+}
+
+
+static dgBigPlane UnboundedLoopPlane (int32_t i0, int32_t i1, int32_t i2, const dgBigVector* const pool)
+{
+ const dgBigVector p0 = pool[i0];
+ const dgBigVector p1 = pool[i1];
+ const dgBigVector p2 = pool[i2];
+ dgBigVector E0 (p1 - p0);
+ dgBigVector E1 (p2 - p0);
+
+ dgBigVector N ((E0 * E1) * E0);
+ double dist = - (N % p0);
+ dgBigPlane plane (N, dist);
+
+ double mag = sqrt (plane % plane);
+ if (mag < double (1.0e-12f)) {
+ mag = double (1.0e-12f);
+ }
+ mag = double (10.0f) / mag;
+
+ plane.m_x *= mag;
+ plane.m_y *= mag;
+ plane.m_z *= mag;
+ plane.m_w *= mag;
+
+ return plane;
+}
+
+
+static void CalculateAllMetrics (const dgPolyhedra* const polyhedra, dgVertexCollapseVertexMetric* const table, const dgBigVector* const pool)
+{
+ int32_t edgeMark = polyhedra->IncLRU();
+ dgPolyhedra::Iterator iter (*polyhedra);
+ for (iter.Begin(); iter; iter ++) {
+ dgEdge* const edge = &(*iter);
+
+ HACD_ASSERT (edge);
+ if (edge->m_mark != edgeMark) {
+
+ if (edge->m_incidentFace > 0) {
+ int32_t i0 = edge->m_incidentVertex;
+ int32_t i1 = edge->m_next->m_incidentVertex;
+ int32_t i2 = edge->m_prev->m_incidentVertex;
+
+ dgBigPlane constrainPlane (EdgePlane (i0, i1, i2, pool));
+ dgVertexCollapseVertexMetric tmp (constrainPlane);
+
+ dgEdge* ptr = edge;
+ do {
+ ptr->m_mark = edgeMark;
+ i0 = ptr->m_incidentVertex;
+ table[i0].Accumulate(tmp);
+
+ ptr = ptr->m_next;
+ } while (ptr != edge);
+
+ } else {
+ HACD_ASSERT (edge->m_twin->m_incidentFace > 0);
+ int32_t i0 = edge->m_twin->m_incidentVertex;
+ int32_t i1 = edge->m_twin->m_next->m_incidentVertex;
+ int32_t i2 = edge->m_twin->m_prev->m_incidentVertex;
+
+ edge->m_mark = edgeMark;
+ dgBigPlane constrainPlane (UnboundedLoopPlane (i0, i1, i2, pool));
+ dgVertexCollapseVertexMetric tmp (constrainPlane);
+
+ i0 = edge->m_incidentVertex;
+ table[i0].Accumulate(tmp);
+
+ i0 = edge->m_twin->m_incidentVertex;
+ table[i0].Accumulate(tmp);
+ }
+ }
+ }
+}
+
+
+double dgPolyhedra::EdgePenalty (const dgBigVector* const pool, dgEdge* const edge) const
+{
+ int32_t i0 = edge->m_incidentVertex;
+ int32_t i1 = edge->m_next->m_incidentVertex;
+
+ const dgBigVector& p0 = pool[i0];
+ const dgBigVector& p1 = pool[i1];
+ dgBigVector dp (p1 - p0);
+
+ double dot = dp % dp;
+ if (dot < double(1.0e-6f)) {
+ return double (-1.0f);
+ }
+
+ if ((edge->m_incidentFace > 0) && (edge->m_twin->m_incidentFace > 0)) {
+ dgBigVector edgeNormal (FaceNormal (edge, &pool[0].m_x, sizeof (dgBigVector)));
+ dgBigVector twinNormal (FaceNormal (edge->m_twin, &pool[0].m_x, sizeof (dgBigVector)));
+
+ double mag0 = edgeNormal % edgeNormal;
+ double mag1 = twinNormal % twinNormal;
+ if ((mag0 < double (1.0e-24f)) || (mag1 < double (1.0e-24f))) {
+ return double (-1.0f);
+ }
+
+ edgeNormal = edgeNormal.Scale (double (1.0f) / sqrt(mag0));
+ twinNormal = twinNormal.Scale (double (1.0f) / sqrt(mag1));
+
+ dot = edgeNormal % twinNormal;
+ if (dot < double (-0.9f)) {
+ return float (-1.0f);
+ }
+
+ dgEdge* ptr = edge;
+ do {
+ if ((ptr->m_incidentFace <= 0) || (ptr->m_twin->m_incidentFace <= 0)){
+ dgEdge* const adj = edge->m_twin;
+ ptr = edge;
+ do {
+ if ((ptr->m_incidentFace <= 0) || (ptr->m_twin->m_incidentFace <= 0)){
+ return float (-1.0);
+ }
+ ptr = ptr->m_twin->m_next;
+ } while (ptr != adj);
+ }
+ ptr = ptr->m_twin->m_next;
+ } while (ptr != edge);
+ }
+
+ int32_t faceA = edge->m_incidentFace;
+ int32_t faceB = edge->m_twin->m_incidentFace;
+
+ i0 = edge->m_twin->m_incidentVertex;
+ dgBigVector p (pool[i0].m_x, pool[i0].m_y, pool[i0].m_z, float (0.0f));
+
+ bool penalty = false;
+ dgEdge* ptr = edge;
+ do {
+ dgEdge* const adj = ptr->m_twin;
+
+ int32_t face = adj->m_incidentFace;
+ if ((face != faceB) && (face != faceA) && (face >= 0) && (adj->m_next->m_incidentFace == face) && (adj->m_prev->m_incidentFace == face)){
+
+ int32_t i0 = adj->m_next->m_incidentVertex;
+ const dgBigVector& p0 = pool[i0];
+
+ int32_t i1 = adj->m_incidentVertex;
+ const dgBigVector& p1 = pool[i1];
+
+ int32_t i2 = adj->m_prev->m_incidentVertex;
+ const dgBigVector& p2 = pool[i2];
+
+ dgBigVector n0 ((p1 - p0) * (p2 - p0));
+ dgBigVector n1 ((p1 - p) * (p2 - p));
+
+// double mag0 = n0 % n0;
+// HACD_ASSERT (mag0 > double(1.0e-16f));
+// mag0 = sqrt (mag0);
+
+// double mag1 = n1 % n1;
+// mag1 = sqrt (mag1);
+
+ double dot = n0 % n1;
+ if (dot < double (0.0f)) {
+// if (dot <= (mag0 * mag1 * float (0.707f)) || (mag0 > (double(16.0f) * mag1))) {
+ penalty = true;
+ break;
+ }
+ }
+
+ ptr = ptr->m_twin->m_next;
+ } while (ptr != edge);
+
+ double aspect = float (-1.0f);
+ if (!penalty) {
+ int32_t i0 = edge->m_twin->m_incidentVertex;
+ dgBigVector p0 (pool[i0]);
+
+ aspect = float (1.0f);
+ for (dgEdge* ptr = edge->m_twin->m_next->m_twin->m_next; ptr != edge; ptr = ptr->m_twin->m_next) {
+ if (ptr->m_incidentFace > 0) {
+ int32_t i0 = ptr->m_next->m_incidentVertex;
+ const dgBigVector& p1 = pool[i0];
+
+ int32_t i1 = ptr->m_prev->m_incidentVertex;
+ const dgBigVector& p2 = pool[i1];
+
+ dgBigVector e0 (p1 - p0);
+ dgBigVector e1 (p2 - p1);
+ dgBigVector e2 (p0 - p2);
+
+ double mag0 = e0 % e0;
+ double mag1 = e1 % e1;
+ double mag2 = e2 % e2;
+ double maxMag = GetMax (mag0, mag1, mag2);
+ double minMag = GetMin (mag0, mag1, mag2);
+ double ratio = minMag / maxMag;
+
+ if (ratio < aspect) {
+ aspect = ratio;
+ }
+ }
+ }
+ aspect = sqrt (aspect);
+ //aspect = 1.0f;
+ }
+
+ return aspect;
+}
+
+static void CalculateVertexMetrics (dgVertexCollapseVertexMetric table[], const dgBigVector* const pool, dgEdge* const edge)
+{
+ int32_t i0 = edge->m_incidentVertex;
+
+// const dgBigVector& p0 = pool[i0];
+ table[i0].Clear ();
+ dgEdge* ptr = edge;
+ do {
+
+ if (ptr->m_incidentFace > 0) {
+ int32_t i1 = ptr->m_next->m_incidentVertex;
+ int32_t i2 = ptr->m_prev->m_incidentVertex;
+ dgBigPlane constrainPlane (EdgePlane (i0, i1, i2, pool));
+ table[i0].Accumulate (constrainPlane);
+
+ } else {
+ int32_t i1 = ptr->m_twin->m_incidentVertex;
+ int32_t i2 = ptr->m_twin->m_prev->m_incidentVertex;
+ dgBigPlane constrainPlane (UnboundedLoopPlane (i0, i1, i2, pool));
+ table[i0].Accumulate (constrainPlane);
+
+ i1 = ptr->m_prev->m_incidentVertex;
+ i2 = ptr->m_prev->m_twin->m_prev->m_incidentVertex;
+ constrainPlane = UnboundedLoopPlane (i0, i1, i2, pool);
+ table[i0].Accumulate (constrainPlane);
+ }
+
+ ptr = ptr->m_twin->m_next;
+ } while (ptr != edge);
+}
+
+static void RemoveHalfEdge (dgPolyhedra* const polyhedra, dgEdge* const edge)
+{
+ dgEdgeCollapseEdgeHandle* const handle = (dgEdgeCollapseEdgeHandle *) IntToPointer (edge->m_userData);
+ if (handle) {
+ handle->m_edge = NULL;
+ }
+
+ dgPolyhedra::dgTreeNode* const node = polyhedra->GetNodeFromInfo(*edge);
+ HACD_ASSERT (node);
+ polyhedra->Remove (node);
+}
+
+
+static dgEdge* CollapseEdge(dgPolyhedra* const polyhedra, dgEdge* const edge)
+{
+ int32_t v0 = edge->m_incidentVertex;
+ int32_t v1 = edge->m_twin->m_incidentVertex;
+
+#ifdef __ENABLE_SANITY_CHECK
+ dgPolyhedra::dgPairKey TwinKey (v1, v0);
+ dgPolyhedra::dgTreeNode* const node = polyhedra->Find (TwinKey.GetVal());
+ dgEdge* const twin1 = node ? &node->GetInfo() : NULL;
+ HACD_ASSERT (twin1);
+ HACD_ASSERT (edge->m_twin == twin1);
+ HACD_ASSERT (twin1->m_twin == edge);
+ HACD_ASSERT (edge->m_incidentFace != 0);
+ HACD_ASSERT (twin1->m_incidentFace != 0);
+#endif
+
+
+ dgEdge* retEdge = edge->m_twin->m_prev->m_twin;
+ if (retEdge == edge->m_twin->m_next) {
+ return NULL;
+ }
+ if (retEdge == edge->m_twin) {
+ return NULL;
+ }
+ if (retEdge == edge->m_next) {
+ retEdge = edge->m_prev->m_twin;
+ if (retEdge == edge->m_twin->m_next) {
+ return NULL;
+ }
+ if (retEdge == edge->m_twin) {
+ return NULL;
+ }
+ }
+
+ dgEdge* lastEdge = NULL;
+ dgEdge* firstEdge = NULL;
+ if ((edge->m_incidentFace >= 0) && (edge->m_twin->m_incidentFace >= 0)) {
+ lastEdge = edge->m_prev->m_twin;
+ firstEdge = edge->m_twin->m_next->m_twin->m_next;
+ } else if (edge->m_twin->m_incidentFace >= 0) {
+ firstEdge = edge->m_twin->m_next->m_twin->m_next;
+ lastEdge = edge;
+ } else {
+ lastEdge = edge->m_prev->m_twin;
+ firstEdge = edge->m_twin->m_next;
+ }
+
+ for (dgEdge* ptr = firstEdge; ptr != lastEdge; ptr = ptr->m_twin->m_next) {
+ dgEdge* badEdge = polyhedra->FindEdge (edge->m_twin->m_incidentVertex, ptr->m_twin->m_incidentVertex);
+ if (badEdge) {
+ return NULL;
+ }
+ }
+
+ dgEdge* const twin = edge->m_twin;
+ if (twin->m_next == twin->m_prev->m_prev) {
+ twin->m_prev->m_twin->m_twin = twin->m_next->m_twin;
+ twin->m_next->m_twin->m_twin = twin->m_prev->m_twin;
+
+ RemoveHalfEdge (polyhedra, twin->m_prev);
+ RemoveHalfEdge (polyhedra, twin->m_next);
+ } else {
+ twin->m_next->m_prev = twin->m_prev;
+ twin->m_prev->m_next = twin->m_next;
+ }
+
+ if (edge->m_next == edge->m_prev->m_prev) {
+ edge->m_next->m_twin->m_twin = edge->m_prev->m_twin;
+ edge->m_prev->m_twin->m_twin = edge->m_next->m_twin;
+ RemoveHalfEdge (polyhedra, edge->m_next);
+ RemoveHalfEdge (polyhedra, edge->m_prev);
+ } else {
+ edge->m_next->m_prev = edge->m_prev;
+ edge->m_prev->m_next = edge->m_next;
+ }
+
+ HACD_ASSERT (twin->m_twin->m_incidentVertex == v0);
+ HACD_ASSERT (edge->m_twin->m_incidentVertex == v1);
+ RemoveHalfEdge (polyhedra, twin);
+ RemoveHalfEdge (polyhedra, edge);
+
+ dgEdge* ptr = retEdge;
+ do {
+ dgPolyhedra::dgPairKey pairKey (v0, ptr->m_twin->m_incidentVertex);
+
+ dgPolyhedra::dgTreeNode* node = polyhedra->Find (pairKey.GetVal());
+ if (node) {
+ if (&node->GetInfo() == ptr) {
+ dgPolyhedra::dgPairKey key (v1, ptr->m_twin->m_incidentVertex);
+ ptr->m_incidentVertex = v1;
+ node = polyhedra->ReplaceKey (node, key.GetVal());
+ HACD_ASSERT (node);
+ }
+ }
+
+ dgPolyhedra::dgPairKey TwinKey (ptr->m_twin->m_incidentVertex, v0);
+ node = polyhedra->Find (TwinKey.GetVal());
+ if (node) {
+ if (&node->GetInfo() == ptr->m_twin) {
+ dgPolyhedra::dgPairKey key (ptr->m_twin->m_incidentVertex, v1);
+ node = polyhedra->ReplaceKey (node, key.GetVal());
+ HACD_ASSERT (node);
+ }
+ }
+
+ ptr = ptr->m_twin->m_next;
+ } while (ptr != retEdge);
+
+ return retEdge;
+}
+
+
+
+void dgPolyhedra::Optimize (const double* const array, int32_t strideInBytes, double tol)
+{
+ dgList <dgEdgeCollapseEdgeHandle>::dgListNode *handleNodePtr;
+
+ int32_t stride = int32_t (strideInBytes / sizeof (double));
+
+#ifdef __ENABLE_SANITY_CHECK
+ HACD_ASSERT (SanityCheck ());
+#endif
+
+ int32_t edgeCount = GetEdgeCount() * 4 + 1024 * 16;
+ int32_t maxVertexIndex = GetLastVertexIndex();
+
+ dgStack<dgBigVector> vertexPool (maxVertexIndex);
+ dgStack<dgVertexCollapseVertexMetric> vertexMetrics (maxVertexIndex + 512);
+
+ dgList <dgEdgeCollapseEdgeHandle> edgeHandleList;
+ dgStack<char> heapPool (2 * edgeCount * int32_t (sizeof (double) + sizeof (dgEdgeCollapseEdgeHandle*) + sizeof (int32_t)));
+ dgDownHeap<dgList <dgEdgeCollapseEdgeHandle>::dgListNode* , double> bigHeapArray(&heapPool[0], heapPool.GetSizeInBytes());
+
+ NormalizeVertex (maxVertexIndex, &vertexPool[0], array, stride);
+ memset (&vertexMetrics[0], 0, maxVertexIndex * sizeof (dgVertexCollapseVertexMetric));
+ CalculateAllMetrics (this, &vertexMetrics[0], &vertexPool[0]);
+
+
+ double tol2 = tol * tol;
+ Iterator iter (*this);
+ for (iter.Begin(); iter; iter ++) {
+ dgEdge* const edge = &(*iter);
+
+ edge->m_userData = 0;
+ int32_t index0 = edge->m_incidentVertex;
+ int32_t index1 = edge->m_twin->m_incidentVertex;
+
+ dgVertexCollapseVertexMetric &metric = vertexMetrics[index0];
+ dgVector p (&vertexPool[index1].m_x);
+ double cost = metric.Evalue (p);
+ if (cost < tol2) {
+ cost = EdgePenalty (&vertexPool[0], edge);
+
+ if (cost > double (0.0f)) {
+ dgEdgeCollapseEdgeHandle handle (edge);
+ handleNodePtr = edgeHandleList.Addtop (handle);
+ bigHeapArray.Push (handleNodePtr, cost);
+ }
+ }
+ }
+
+
+ while (bigHeapArray.GetCount()) {
+ handleNodePtr = bigHeapArray[0];
+
+ dgEdge* edge = handleNodePtr->GetInfo().m_edge;
+ bigHeapArray.Pop();
+ edgeHandleList.Remove (handleNodePtr);
+
+ if (edge) {
+ CalculateVertexMetrics (&vertexMetrics[0], &vertexPool[0], edge);
+
+ int32_t index0 = edge->m_incidentVertex;
+ int32_t index1 = edge->m_twin->m_incidentVertex;
+ dgVertexCollapseVertexMetric &metric = vertexMetrics[index0];
+ dgBigVector p (vertexPool[index1]);
+
+ if ((metric.Evalue (p) < tol2) && (EdgePenalty (&vertexPool[0], edge) > double (0.0f))) {
+
+#ifdef __ENABLE_SANITY_CHECK
+ HACD_ASSERT (SanityCheck ());
+#endif
+
+ edge = CollapseEdge(this, edge);
+
+#ifdef __ENABLE_SANITY_CHECK
+ HACD_ASSERT (SanityCheck ());
+#endif
+ if (edge) {
+ // Update vertex metrics
+ CalculateVertexMetrics (&vertexMetrics[0], &vertexPool[0], edge);
+
+ // Update metrics for all surrounding vertex
+ dgEdge* ptr = edge;
+ do {
+ CalculateVertexMetrics (&vertexMetrics[0], &vertexPool[0], ptr->m_twin);
+ ptr = ptr->m_twin->m_next;
+ } while (ptr != edge);
+
+ // calculate edge cost of all incident edges
+ int32_t mark = IncLRU();
+ ptr = edge;
+ do {
+ HACD_ASSERT (ptr->m_mark != mark);
+ ptr->m_mark = mark;
+
+ index0 = ptr->m_incidentVertex;
+ index1 = ptr->m_twin->m_incidentVertex;
+
+ dgVertexCollapseVertexMetric &metric = vertexMetrics[index0];
+ dgBigVector p (vertexPool[index1]);
+
+ double cost = float (-1.0f);
+ if (metric.Evalue (p) < tol2) {
+ cost = EdgePenalty (&vertexPool[0], ptr);
+ }
+
+ if (cost > double (0.0f)) {
+ dgEdgeCollapseEdgeHandle handle (ptr);
+ handleNodePtr = edgeHandleList.Addtop (handle);
+ bigHeapArray.Push (handleNodePtr, cost);
+ } else {
+ dgEdgeCollapseEdgeHandle* const handle = (dgEdgeCollapseEdgeHandle*)IntToPointer (ptr->m_userData);
+ if (handle) {
+ handle->m_edge = NULL;
+ }
+ ptr->m_userData = uint32_t (NULL);
+
+ }
+
+ ptr = ptr->m_twin->m_next;
+ } while (ptr != edge);
+
+
+ // calculate edge cost of all incident edges to a surrounding vertex
+ ptr = edge;
+ do {
+ dgEdge* const incidentEdge = ptr->m_twin;
+
+ dgEdge* ptr1 = incidentEdge;
+ do {
+ index0 = ptr1->m_incidentVertex;
+ index1 = ptr1->m_twin->m_incidentVertex;
+
+ if (ptr1->m_mark != mark) {
+ ptr1->m_mark = mark;
+ dgVertexCollapseVertexMetric &metric = vertexMetrics[index0];
+ dgBigVector p (vertexPool[index1]);
+
+ double cost = float (-1.0f);
+ if (metric.Evalue (p) < tol2) {
+ cost = EdgePenalty (&vertexPool[0], ptr1);
+ }
+
+ if (cost > double (0.0f)) {
+ HACD_ASSERT (cost > double(0.0f));
+ dgEdgeCollapseEdgeHandle handle (ptr1);
+ handleNodePtr = edgeHandleList.Addtop (handle);
+ bigHeapArray.Push (handleNodePtr, cost);
+ } else {
+ dgEdgeCollapseEdgeHandle *handle;
+ handle = (dgEdgeCollapseEdgeHandle*)IntToPointer (ptr1->m_userData);
+ if (handle) {
+ handle->m_edge = NULL;
+ }
+ ptr1->m_userData = uint32_t (NULL);
+
+ }
+ }
+
+ if (ptr1->m_twin->m_mark != mark) {
+ ptr1->m_twin->m_mark = mark;
+ dgVertexCollapseVertexMetric &metric = vertexMetrics[index1];
+ dgBigVector p (vertexPool[index0]);
+
+ double cost = float (-1.0f);
+ if (metric.Evalue (p) < tol2) {
+ cost = EdgePenalty (&vertexPool[0], ptr1->m_twin);
+ }
+
+ if (cost > double (0.0f)) {
+ HACD_ASSERT (cost > double(0.0f));
+ dgEdgeCollapseEdgeHandle handle (ptr1->m_twin);
+ handleNodePtr = edgeHandleList.Addtop (handle);
+ bigHeapArray.Push (handleNodePtr, cost);
+ } else {
+ dgEdgeCollapseEdgeHandle *handle;
+ handle = (dgEdgeCollapseEdgeHandle*) IntToPointer (ptr1->m_twin->m_userData);
+ if (handle) {
+ handle->m_edge = NULL;
+ }
+ ptr1->m_twin->m_userData = uint32_t (NULL);
+
+ }
+ }
+
+ ptr1 = ptr1->m_twin->m_next;
+ } while (ptr1 != incidentEdge);
+
+ ptr = ptr->m_twin->m_next;
+ } while (ptr != edge);
+ }
+ }
+ }
+ }
+}
+
+
+dgEdge* dgPolyhedra::FindEarTip (dgEdge* const face, const double* const pool, int32_t stride, dgDownHeap<dgEdge*, double>& heap, const dgBigVector &normal) const
+{
+ dgEdge* ptr = face;
+ dgBigVector p0 (&pool[ptr->m_prev->m_incidentVertex * stride]);
+ dgBigVector p1 (&pool[ptr->m_incidentVertex * stride]);
+ dgBigVector d0 (p1 - p0);
+ double f = sqrt (d0 % d0);
+ if (f < double (1.0e-10f)) {
+ f = double (1.0e-10f);
+ }
+ d0 = d0.Scale (double (1.0f) / f);
+
+ double minAngle = float (10.0f);
+ do {
+ dgBigVector p2 (&pool [ptr->m_next->m_incidentVertex * stride]);
+ dgBigVector d1 (p2 - p1);
+ float f = dgSqrt (d1 % d1);
+ if (f < float (1.0e-10f)) {
+ f = float (1.0e-10f);
+ }
+ d1 = d1.Scale (float (1.0f) / f);
+ dgBigVector n (d0 * d1);
+
+ double angle = normal % n;
+ if (angle >= double (0.0f)) {
+ heap.Push (ptr, angle);
+ }
+
+ if (angle < minAngle) {
+ minAngle = angle;
+ }
+
+ d0 = d1;
+ p1 = p2;
+ ptr = ptr->m_next;
+ } while (ptr != face);
+
+ if (minAngle > float (0.1f)) {
+ return heap[0];
+ }
+
+ dgEdge* ear = NULL;
+ while (heap.GetCount()) {
+ ear = heap[0];
+ heap.Pop();
+
+ if (FindEdge (ear->m_prev->m_incidentVertex, ear->m_next->m_incidentVertex)) {
+ continue;
+ }
+
+ dgBigVector p0 (&pool [ear->m_prev->m_incidentVertex * stride]);
+ dgBigVector p1 (&pool [ear->m_incidentVertex * stride]);
+ dgBigVector p2 (&pool [ear->m_next->m_incidentVertex * stride]);
+
+ dgBigVector p10 (p1 - p0);
+ dgBigVector p21 (p2 - p1);
+ dgBigVector p02 (p0 - p2);
+
+ for (ptr = ear->m_next->m_next; ptr != ear->m_prev; ptr = ptr->m_next) {
+ dgBigVector p (&pool [ptr->m_incidentVertex * stride]);
+
+ double side = ((p - p0) * p10) % normal;
+ if (side < double (0.05f)) {
+ side = ((p - p1) * p21) % normal;
+ if (side < double (0.05f)) {
+ side = ((p - p2) * p02) % normal;
+ if (side < float (0.05f)) {
+ break;
+ }
+ }
+ }
+ }
+
+ if (ptr == ear->m_prev) {
+ break;
+ }
+ }
+
+ return ear;
+}
+
+
+
+
+
+//dgEdge* TriangulateFace (dgPolyhedra& polyhedra, dgEdge* face, const float* const pool, int32_t stride, dgDownHeap<dgEdge*, float>& heap, dgVector* const faceNormalOut)
+dgEdge* dgPolyhedra::TriangulateFace (dgEdge* face, const double* const pool, int32_t stride, dgDownHeap<dgEdge*, double>& heap, dgBigVector* const faceNormalOut)
+{
+#ifdef _DEBUG
+ dgEdge* perimeter [1024 * 16];
+ dgEdge* ptr = face;
+ int32_t perimeterCount = 0;
+ do {
+ perimeter[perimeterCount] = ptr;
+ perimeterCount ++;
+ HACD_ASSERT (perimeterCount < int32_t (sizeof (perimeter) / sizeof (perimeter[0])));
+ ptr = ptr->m_next;
+ } while (ptr != face);
+ perimeter[perimeterCount] = face;
+ HACD_ASSERT ((perimeterCount + 1) < int32_t (sizeof (perimeter) / sizeof (perimeter[0])));
+#endif
+ dgBigVector normal (FaceNormal (face, pool, int32_t (stride * sizeof (double))));
+
+ double dot = normal % normal;
+ if (dot < double (1.0e-12f)) {
+ if (faceNormalOut) {
+ *faceNormalOut = dgBigVector (float (0.0f), float (0.0f), float (0.0f), float (0.0f));
+ }
+ return face;
+ }
+ normal = normal.Scale (double (1.0f) / sqrt (dot));
+ if (faceNormalOut) {
+ *faceNormalOut = normal;
+ }
+
+
+ while (face->m_next->m_next->m_next != face) {
+ dgEdge* const ear = FindEarTip (face, pool, stride, heap, normal);
+ if (!ear) {
+ return face;
+ }
+ if ((face == ear) || (face == ear->m_prev)) {
+ face = ear->m_prev->m_prev;
+ }
+ dgEdge* const edge = AddHalfEdge (ear->m_next->m_incidentVertex, ear->m_prev->m_incidentVertex);
+ if (!edge) {
+ return face;
+ }
+ dgEdge* const twin = AddHalfEdge (ear->m_prev->m_incidentVertex, ear->m_next->m_incidentVertex);
+ if (!twin) {
+ return face;
+ }
+ HACD_ASSERT (twin);
+
+
+ edge->m_mark = ear->m_mark;
+ edge->m_userData = ear->m_next->m_userData;
+ edge->m_incidentFace = ear->m_incidentFace;
+
+ twin->m_mark = ear->m_mark;
+ twin->m_userData = ear->m_prev->m_userData;
+ twin->m_incidentFace = ear->m_incidentFace;
+
+ edge->m_twin = twin;
+ twin->m_twin = edge;
+
+ twin->m_prev = ear->m_prev->m_prev;
+ twin->m_next = ear->m_next;
+ ear->m_prev->m_prev->m_next = twin;
+ ear->m_next->m_prev = twin;
+
+ edge->m_next = ear->m_prev;
+ edge->m_prev = ear;
+ ear->m_prev->m_prev = edge;
+ ear->m_next = edge;
+
+ heap.Flush ();
+ }
+ return NULL;
+}
+
+
+void dgPolyhedra::MarkAdjacentCoplanarFaces (dgPolyhedra& polyhedraOut, dgEdge* const face, const double* const pool, int32_t strideInBytes)
+{
+ const double normalDeviation = double (0.9999f);
+ const double distanceFromPlane = double (1.0f / 128.0f);
+
+ int32_t faceIndex[1024 * 4];
+ dgEdge* stack[1024 * 4];
+ dgEdge* deleteEdge[1024 * 4];
+
+ int32_t deleteCount = 1;
+ deleteEdge[0] = face;
+ int32_t stride = int32_t (strideInBytes / sizeof (double));
+
+ HACD_ASSERT (face->m_incidentFace > 0);
+
+ dgBigVector normalAverage (FaceNormal (face, pool, strideInBytes));
+ double dot = normalAverage % normalAverage;
+ if (dot > double (1.0e-12f)) {
+ int32_t testPointsCount = 1;
+ dot = double (1.0f) / sqrt (dot);
+ dgBigVector normal (normalAverage.Scale (dot));
+
+ dgBigVector averageTestPoint (&pool[face->m_incidentVertex * stride]);
+ dgBigPlane testPlane(normal, - (averageTestPoint % normal));
+
+ polyhedraOut.BeginFace();
+
+ IncLRU();
+ int32_t faceMark = IncLRU();
+
+ int32_t faceIndexCount = 0;
+ dgEdge* ptr = face;
+ do {
+ ptr->m_mark = faceMark;
+ faceIndex[faceIndexCount] = ptr->m_incidentVertex;
+ faceIndexCount ++;
+ HACD_ASSERT (faceIndexCount < int32_t (sizeof (faceIndex) / sizeof (faceIndex[0])));
+ ptr = ptr ->m_next;
+ } while (ptr != face);
+ polyhedraOut.AddFace(faceIndexCount, faceIndex);
+
+ int32_t index = 1;
+ deleteCount = 0;
+ stack[0] = face;
+ while (index)
+ {
+ index --;
+ dgEdge* const face = stack[index];
+ deleteEdge[deleteCount] = face;
+ deleteCount ++;
+ HACD_ASSERT (deleteCount < int32_t (sizeof (deleteEdge) / sizeof (deleteEdge[0])));
+// TODO:JWR Temporarily commented out... HACD_ASSERT (face->m_next->m_next->m_next == face);
+
+ dgEdge* edge = face;
+ do
+ {
+ dgEdge* const ptr = edge->m_twin;
+ if (ptr->m_incidentFace > 0)
+ {
+ if (ptr->m_mark != faceMark)
+ {
+ dgEdge* ptr1 = ptr;
+ faceIndexCount = 0;
+ do
+ {
+ ptr1->m_mark = faceMark;
+ faceIndex[faceIndexCount] = ptr1->m_incidentVertex;
+ HACD_ASSERT (faceIndexCount < int32_t (sizeof (faceIndex) / sizeof (faceIndex[0])));
+ faceIndexCount ++;
+ ptr1 = ptr1 ->m_next;
+ } while (ptr1 != ptr);
+
+ dgBigVector normal1 (FaceNormal (ptr, pool, strideInBytes));
+ dot = normal1 % normal1;
+ if (dot < double (1.0e-12f)) {
+ deleteEdge[deleteCount] = ptr;
+ deleteCount ++;
+ HACD_ASSERT (deleteCount < int32_t (sizeof (deleteEdge) / sizeof (deleteEdge[0])));
+ } else {
+ //normal1 = normal1.Scale (double (1.0f) / sqrt (dot));
+ dgBigVector testNormal (normal1.Scale (double (1.0f) / sqrt (dot)));
+ dot = normal % testNormal;
+ if (dot >= normalDeviation) {
+ dgBigVector testPoint (&pool[ptr->m_prev->m_incidentVertex * stride]);
+ double dist = fabs (testPlane.Evalue (testPoint));
+ if (dist < distanceFromPlane) {
+ testPointsCount ++;
+
+ averageTestPoint += testPoint;
+ testPoint = averageTestPoint.Scale (double (1.0f) / double(testPointsCount));
+
+ normalAverage += normal1;
+ testNormal = normalAverage.Scale (double (1.0f) / sqrt (normalAverage % normalAverage));
+ testPlane = dgBigPlane (testNormal, - (testPoint % testNormal));
+
+ polyhedraOut.AddFace(faceIndexCount, faceIndex);;
+ stack[index] = ptr;
+ index ++;
+ HACD_ASSERT (index < int32_t (sizeof (stack) / sizeof (stack[0])));
+ }
+ }
+ }
+ }
+ }
+
+ edge = edge->m_next;
+ } while (edge != face);
+ }
+ polyhedraOut.EndFace();
+ }
+
+ for (int32_t index = 0; index < deleteCount; index ++) {
+ DeleteFace (deleteEdge[index]);
+ }
+}
+
+
+void dgPolyhedra::RefineTriangulation (const double* const vertex, int32_t stride, dgBigVector* const normal, int32_t perimeterCount, dgEdge** const perimeter)
+{
+ dgList<dgDiagonalEdge> dignonals;
+
+ for (int32_t i = 1; i <= perimeterCount; i ++) {
+ dgEdge* const last = perimeter[i - 1];
+ for (dgEdge* ptr = perimeter[i]->m_prev; ptr != last; ptr = ptr->m_twin->m_prev) {
+ dgList<dgDiagonalEdge>::dgListNode* node = dignonals.GetFirst();
+ for (; node; node = node->GetNext()) {
+ const dgDiagonalEdge& key = node->GetInfo();
+ if (((key.m_i0 == ptr->m_incidentVertex) && (key.m_i1 == ptr->m_twin->m_incidentVertex)) ||
+ ((key.m_i1 == ptr->m_incidentVertex) && (key.m_i0 == ptr->m_twin->m_incidentVertex))) {
+ break;
+ }
+ }
+ if (!node) {
+ dgDiagonalEdge key (ptr);
+ dignonals.Append(key);
+ }
+ }
+ }
+
+ dgEdge* const face = perimeter[0];
+ int32_t i0 = face->m_incidentVertex * stride;
+ int32_t i1 = face->m_next->m_incidentVertex * stride;
+ dgBigVector p0 (vertex[i0], vertex[i0 + 1], vertex[i0 + 2], float (0.0f));
+ dgBigVector p1 (vertex[i1], vertex[i1 + 1], vertex[i1 + 2], float (0.0f));
+
+ dgBigVector p1p0 (p1 - p0);
+ double mag2 = p1p0 % p1p0;
+ for (dgEdge* ptr = face->m_next->m_next; mag2 < float (1.0e-12f); ptr = ptr->m_next) {
+ int32_t i1 = ptr->m_incidentVertex * stride;
+ dgBigVector p1 (vertex[i1], vertex[i1 + 1], vertex[i1 + 2], float (0.0f));
+ p1p0 = p1 - p0;
+ mag2 = p1p0 % p1p0;
+ }
+
+ dgMatrix matrix (dgGetIdentityMatrix());
+ matrix.m_posit = p0;
+ matrix.m_front = dgVector (p1p0.Scale (double (1.0f) / sqrt (mag2)));
+ matrix.m_right = dgVector (normal->Scale (double (1.0f) / sqrt (*normal % *normal)));
+ matrix.m_up = matrix.m_right * matrix.m_front;
+ matrix = matrix.Inverse();
+ matrix.m_posit.m_w = float (1.0f);
+
+ int32_t maxCount = dignonals.GetCount() * dignonals.GetCount();
+ while (dignonals.GetCount() && maxCount) {
+ maxCount --;
+ dgList<dgDiagonalEdge>::dgListNode* const node = dignonals.GetFirst();
+ dgDiagonalEdge key (node->GetInfo());
+ dignonals.Remove(node);
+ dgEdge* const edge = FindEdge(key.m_i0, key.m_i1);
+ if (edge) {
+ int32_t i0 = edge->m_incidentVertex * stride;
+ int32_t i1 = edge->m_next->m_incidentVertex * stride;
+ int32_t i2 = edge->m_next->m_next->m_incidentVertex * stride;
+ int32_t i3 = edge->m_twin->m_prev->m_incidentVertex * stride;
+
+ dgBigVector p0 (vertex[i0], vertex[i0 + 1], vertex[i0 + 2], double (0.0f));
+ dgBigVector p1 (vertex[i1], vertex[i1 + 1], vertex[i1 + 2], double (0.0f));
+ dgBigVector p2 (vertex[i2], vertex[i2 + 1], vertex[i2 + 2], double (0.0f));
+ dgBigVector p3 (vertex[i3], vertex[i3 + 1], vertex[i3 + 2], double (0.0f));
+
+ p0 = matrix.TransformVector(p0);
+ p1 = matrix.TransformVector(p1);
+ p2 = matrix.TransformVector(p2);
+ p3 = matrix.TransformVector(p3);
+
+ double circleTest[3][3];
+ circleTest[0][0] = p0[0] - p3[0];
+ circleTest[0][1] = p0[1] - p3[1];
+ circleTest[0][2] = circleTest[0][0] * circleTest[0][0] + circleTest[0][1] * circleTest[0][1];
+
+ circleTest[1][0] = p1[0] - p3[0];
+ circleTest[1][1] = p1[1] - p3[1];
+ circleTest[1][2] = circleTest[1][0] * circleTest[1][0] + circleTest[1][1] * circleTest[1][1];
+
+ circleTest[2][0] = p2[0] - p3[0];
+ circleTest[2][1] = p2[1] - p3[1];
+ circleTest[2][2] = circleTest[2][0] * circleTest[2][0] + circleTest[2][1] * circleTest[2][1];
+
+ double error;
+ double det = Determinant3x3 (circleTest, &error);
+ if (det < float (0.0f)) {
+ dgEdge* frontFace0 = edge->m_prev;
+ dgEdge* backFace0 = edge->m_twin->m_prev;
+
+ FlipEdge(edge);
+
+ if (perimeterCount > 4) {
+ dgEdge* backFace1 = backFace0->m_next;
+ dgEdge* frontFace1 = frontFace0->m_next;
+ for (int32_t i = 0; i < perimeterCount; i ++) {
+ if (frontFace0 == perimeter[i]) {
+ frontFace0 = NULL;
+ }
+ if (frontFace1 == perimeter[i]) {
+ frontFace1 = NULL;
+ }
+
+ if (backFace0 == perimeter[i]) {
+ backFace0 = NULL;
+ }
+ if (backFace1 == perimeter[i]) {
+ backFace1 = NULL;
+ }
+ }
+
+ if (backFace0 && (backFace0->m_incidentFace > 0) && (backFace0->m_twin->m_incidentFace > 0)) {
+ dgDiagonalEdge key (backFace0);
+ dignonals.Append(key);
+ }
+ if (backFace1 && (backFace1->m_incidentFace > 0) && (backFace1->m_twin->m_incidentFace > 0)) {
+ dgDiagonalEdge key (backFace1);
+ dignonals.Append(key);
+ }
+
+ if (frontFace0 && (frontFace0->m_incidentFace > 0) && (frontFace0->m_twin->m_incidentFace > 0)) {
+ dgDiagonalEdge key (frontFace0);
+ dignonals.Append(key);
+ }
+
+ if (frontFace1 && (frontFace1->m_incidentFace > 0) && (frontFace1->m_twin->m_incidentFace > 0)) {
+ dgDiagonalEdge key (frontFace1);
+ dignonals.Append(key);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+void dgPolyhedra::RefineTriangulation (const double* const vertex, int32_t stride)
+{
+ dgEdge* edgePerimeters[1024 * 16];
+ int32_t perimeterCount = 0;
+
+ dgPolyhedra::Iterator iter (*this);
+ for (iter.Begin(); iter; iter ++) {
+ dgEdge* const edge = &(*iter);
+ if (edge->m_incidentFace < 0) {
+ dgEdge* ptr = edge;
+ do {
+ edgePerimeters[perimeterCount] = ptr->m_twin;
+ perimeterCount ++;
+ HACD_ASSERT (perimeterCount < int32_t (sizeof (edgePerimeters) / sizeof (edgePerimeters[0])));
+ ptr = ptr->m_prev;
+ } while (ptr != edge);
+ break;
+ }
+ }
+ HACD_ASSERT (perimeterCount);
+ HACD_ASSERT (perimeterCount < int32_t (sizeof (edgePerimeters) / sizeof (edgePerimeters[0])));
+ edgePerimeters[perimeterCount] = edgePerimeters[0];
+
+ dgBigVector normal (FaceNormal(edgePerimeters[0], vertex, int32_t (stride * sizeof (double))));
+ if ((normal % normal) > float (1.0e-12f)) {
+ RefineTriangulation (vertex, stride, &normal, perimeterCount, edgePerimeters);
+ }
+}
+
+
+void dgPolyhedra::OptimizeTriangulation (const double* const vertex, int32_t strideInBytes)
+{
+ int32_t polygon[1024 * 8];
+ int32_t stride = int32_t (strideInBytes / sizeof (double));
+
+ dgPolyhedra leftOver;
+ dgPolyhedra buildConvex;
+
+ buildConvex.BeginFace();
+ dgPolyhedra::Iterator iter (*this);
+
+ for (iter.Begin(); iter; ) {
+ dgEdge* const edge = &(*iter);
+ iter++;
+
+ if (edge->m_incidentFace > 0) {
+ dgPolyhedra flatFace;
+ MarkAdjacentCoplanarFaces (flatFace, edge, vertex, strideInBytes);
+ //HACD_ASSERT (flatFace.GetCount());
+
+ if (flatFace.GetCount()) {
+ //flatFace.Triangulate (vertex, strideInBytes, &leftOver);
+ //HACD_ASSERT (!leftOver.GetCount());
+ flatFace.RefineTriangulation (vertex, stride);
+
+ int32_t mark = flatFace.IncLRU();
+ dgPolyhedra::Iterator iter (flatFace);
+ for (iter.Begin(); iter; iter ++) {
+ dgEdge* const edge = &(*iter);
+ if (edge->m_mark != mark) {
+ if (edge->m_incidentFace > 0) {
+ dgEdge* ptr = edge;
+ int32_t vertexCount = 0;
+ do {
+ polygon[vertexCount] = ptr->m_incidentVertex;
+ vertexCount ++;
+ HACD_ASSERT (vertexCount < int32_t (sizeof (polygon) / sizeof (polygon[0])));
+ ptr->m_mark = mark;
+ ptr = ptr->m_next;
+ } while (ptr != edge);
+ if (vertexCount >= 3) {
+ buildConvex.AddFace (vertexCount, polygon);
+ }
+ }
+ }
+ }
+ }
+ iter.Begin();
+ }
+ }
+ buildConvex.EndFace();
+ HACD_ASSERT (GetCount() == 0);
+ SwapInfo(buildConvex);
+}
+
+
+void dgPolyhedra::Triangulate (const double* const /*vertex*/, int32_t /*strideInBytes*/, dgPolyhedra* const /*leftOver*/)
+{
+ int32_t count = GetCount() / 2;
+ dgStack<char> memPool (int32_t ((count + 512) * (2 * sizeof (double))));
+ dgDownHeap<dgEdge*, double> heap(&memPool[0], memPool.GetSizeInBytes());
+#if 0
+ int32_t stride = int32_t (strideInBytes / sizeof (double));
+ int32_t mark = IncLRU();
+ Iterator iter (*this);
+ for (iter.Begin(); iter; )
+ {
+ dgEdge* const thisEdge = &(*iter);
+ iter ++;
+
+ if (thisEdge->m_mark == mark)
+ {
+ continue;
+ }
+ if (thisEdge->m_incidentFace < 0)
+ {
+ continue;
+ }
+
+ count = 0;
+ dgEdge* ptr = thisEdge;
+ do
+ {
+ count ++;
+ ptr->m_mark = mark;
+ ptr = ptr->m_next;
+ } while (ptr != thisEdge);
+
+ if (count > 3)
+ {
+ dgEdge* const edge = TriangulateFace (thisEdge, vertex, stride, heap, NULL);
+ heap.Flush ();
+
+ if (edge)
+ {
+ HACD_ASSERT (edge->m_incidentFace > 0);
+
+ if (leftOver)
+ {
+ int32_t* const index = (int32_t *) &heap[0];
+ int64_t* const data = (int64_t *)&index[count];
+ int32_t i = 0;
+ dgEdge* ptr = edge;
+ do {
+ index[i] = ptr->m_incidentVertex;
+ data[i] = int64_t (ptr->m_userData);
+ i ++;
+ ptr = ptr->m_next;
+ } while (ptr != edge);
+ leftOver->AddFace(i, index, data);
+ }
+ DeleteFace (edge);
+ iter.Begin();
+ }
+ }
+ }
+ OptimizeTriangulation (vertex, strideInBytes);
+ mark = IncLRU();
+ m_faceSecuence = 1;
+ for (iter.Begin(); iter; iter ++)
+ {
+ dgEdge* edge = &(*iter);
+ if (edge->m_mark == mark)
+ {
+ continue;
+ }
+ if (edge->m_incidentFace < 0)
+ {
+ continue;
+ }
+ HACD_ASSERT (edge == edge->m_next->m_next->m_next);
+
+ for (int32_t i = 0; i < 3; i ++)
+ {
+ edge->m_incidentFace = m_faceSecuence;
+ edge->m_mark = mark;
+ edge = edge->m_next;
+ }
+ m_faceSecuence ++;
+ }
+#endif
+}
+
+
+static void RemoveColinearVertices (dgPolyhedra& flatFace, const double* const vertex, int32_t stride)
+{
+ dgEdge* edgePerimeters[1024];
+
+ int32_t perimeterCount = 0;
+ int32_t mark = flatFace.IncLRU();
+ dgPolyhedra::Iterator iter (flatFace);
+ for (iter.Begin(); iter; iter ++) {
+ dgEdge* const edge = &(*iter);
+ if ((edge->m_incidentFace < 0) && (edge->m_mark != mark)) {
+ dgEdge* ptr = edge;
+ do {
+ ptr->m_mark = mark;
+ ptr = ptr->m_next;
+ } while (ptr != edge);
+ edgePerimeters[perimeterCount] = edge;
+ perimeterCount ++;
+ HACD_ASSERT (perimeterCount < int32_t (sizeof (edgePerimeters) / sizeof (edgePerimeters[0])));
+ }
+ }
+
+ for (int32_t i = 0; i < perimeterCount; i ++) {
+ dgEdge* edge = edgePerimeters[i];
+ dgEdge* ptr = edge;
+ dgVector p0 (&vertex[ptr->m_incidentVertex * stride]);
+ dgVector p1 (&vertex[ptr->m_next->m_incidentVertex * stride]);
+ dgVector e0 (p1 - p0) ;
+ e0 = e0.Scale (float (1.0f) / (dgSqrt (e0 % e0) + float (1.0e-12f)));
+ int32_t ignoreTest = 1;
+ do {
+ ignoreTest = 0;
+ dgVector p2 (&vertex[ptr->m_next->m_next->m_incidentVertex * stride]);
+ dgVector e1 (p2 - p1);
+ e1 = e1.Scale (float (1.0f) / (dgSqrt (e1 % e1) + float (1.0e-12f)));
+ float dot = e1 % e0;
+ if (dot > float (float (0.9999f))) {
+
+ for (dgEdge* interiorEdge = ptr->m_next->m_twin->m_next; interiorEdge != ptr->m_twin; interiorEdge = ptr->m_next->m_twin->m_next) {
+ flatFace.DeleteEdge (interiorEdge);
+ }
+
+ if (ptr->m_twin->m_next->m_next->m_next == ptr->m_twin) {
+ HACD_ASSERT (ptr->m_twin->m_next->m_incidentFace > 0);
+ flatFace.DeleteEdge (ptr->m_twin->m_next);
+ }
+
+ HACD_ASSERT (ptr->m_next->m_twin->m_next->m_twin == ptr);
+ edge = ptr->m_next;
+
+ if (!flatFace.FindEdge (ptr->m_incidentVertex, edge->m_twin->m_incidentVertex) &&
+ !flatFace.FindEdge (edge->m_twin->m_incidentVertex, ptr->m_incidentVertex)) {
+ ptr->m_twin->m_prev = edge->m_twin->m_prev;
+ edge->m_twin->m_prev->m_next = ptr->m_twin;
+
+ edge->m_next->m_prev = ptr;
+ ptr->m_next = edge->m_next;
+
+ edge->m_next = edge->m_twin;
+ edge->m_prev = edge->m_twin;
+ edge->m_twin->m_next = edge;
+ edge->m_twin->m_prev = edge;
+ flatFace.DeleteEdge (edge);
+ flatFace.ChangeEdgeIncidentVertex (ptr->m_twin, ptr->m_next->m_incidentVertex);
+
+ e1 = e0;
+ p1 = p2;
+ edge = ptr;
+ ignoreTest = 1;
+ continue;
+ }
+ }
+
+ e0 = e1;
+ p1 = p2;
+ ptr = ptr->m_next;
+ } while ((ptr != edge) || ignoreTest);
+ }
+}
+
+
+static int32_t GetInteriorDiagonals (dgPolyhedra& polyhedra, dgEdge** const diagonals, int32_t maxCount)
+{
+ int32_t count = 0;
+ int32_t mark = polyhedra.IncLRU();
+ dgPolyhedra::Iterator iter (polyhedra);
+ for (iter.Begin(); iter; iter++) {
+ dgEdge* const edge = &(*iter);
+ if (edge->m_mark != mark) {
+ if (edge->m_incidentFace > 0) {
+ if (edge->m_twin->m_incidentFace > 0) {
+ edge->m_twin->m_mark = mark;
+ if (count < maxCount){
+ diagonals[count] = edge;
+ count ++;
+ }
+ HACD_ASSERT (count <= maxCount);
+ }
+ }
+ }
+ edge->m_mark = mark;
+ }
+
+ return count;
+}
+
+static bool IsEssensialPointDiagonal (dgEdge* const diagonal, const dgBigVector& normal, const double* const pool, int32_t stride)
+{
+ double dot;
+ dgBigVector p0 (&pool[diagonal->m_incidentVertex * stride]);
+ dgBigVector p1 (&pool[diagonal->m_twin->m_next->m_twin->m_incidentVertex * stride]);
+ dgBigVector p2 (&pool[diagonal->m_prev->m_incidentVertex * stride]);
+
+ dgBigVector e1 (p1 - p0);
+ dot = e1 % e1;
+ if (dot < double (1.0e-12f)) {
+ return false;
+ }
+ e1 = e1.Scale (double (1.0f) / sqrt(dot));
+
+ dgBigVector e2 (p2 - p0);
+ dot = e2 % e2;
+ if (dot < double (1.0e-12f)) {
+ return false;
+ }
+ e2 = e2.Scale (double (1.0f) / sqrt(dot));
+
+ dgBigVector n1 (e1 * e2);
+
+ dot = normal % n1;
+ //if (dot > double (float (0.1f)f)) {
+ //if (dot >= double (-1.0e-6f)) {
+ if (dot >= double (0.0f)) {
+ return false;
+ }
+ return true;
+}
+
+
+static bool IsEssensialDiagonal (dgEdge* const diagonal, const dgBigVector& normal, const double* const pool, int32_t stride)
+{
+ return IsEssensialPointDiagonal (diagonal, normal, pool, stride) || IsEssensialPointDiagonal (diagonal->m_twin, normal, pool, stride);
+}
+
+
+void dgPolyhedra::ConvexPartition (const double* const vertex, int32_t strideInBytes, dgPolyhedra* const leftOversOut)
+{
+ if (GetCount()) {
+ Triangulate (vertex, strideInBytes, leftOversOut);
+ DeleteDegenerateFaces (vertex, strideInBytes, float (1.0e-5f));
+ Optimize (vertex, strideInBytes, float (1.0e-4f));
+ DeleteDegenerateFaces (vertex, strideInBytes, float (1.0e-5f));
+
+ if (GetCount()) {
+ int32_t removeCount = 0;
+ int32_t stride = int32_t (strideInBytes / sizeof (double));
+
+ int32_t polygon[1024 * 8];
+ dgEdge* diagonalsPool[1024 * 8];
+ dgPolyhedra buildConvex;
+
+ buildConvex.BeginFace();
+ dgPolyhedra::Iterator iter (*this);
+ for (iter.Begin(); iter; ) {
+ dgEdge* edge = &(*iter);
+ iter++;
+ if (edge->m_incidentFace > 0) {
+
+ dgPolyhedra flatFace;
+ MarkAdjacentCoplanarFaces (flatFace, edge, vertex, strideInBytes);
+
+ if (flatFace.GetCount()) {
+ flatFace.RefineTriangulation (vertex, stride);
+ RemoveColinearVertices (flatFace, vertex, stride);
+
+ int32_t diagonalCount = GetInteriorDiagonals (flatFace, diagonalsPool, sizeof (diagonalsPool) / sizeof (diagonalsPool[0]));
+ if (diagonalCount) {
+ edge = &flatFace.GetRoot()->GetInfo();
+ if (edge->m_incidentFace < 0) {
+ edge = edge->m_twin;
+ }
+ HACD_ASSERT (edge->m_incidentFace > 0);
+
+ dgBigVector normal (FaceNormal (edge, vertex, strideInBytes));
+ normal = normal.Scale (double (1.0f) / sqrt (normal % normal));
+
+ edge = NULL;
+ dgPolyhedra::Iterator iter (flatFace);
+ for (iter.Begin(); iter; iter ++) {
+ edge = &(*iter);
+ if (edge->m_incidentFace < 0) {
+ break;
+ }
+ }
+ HACD_ASSERT (edge);
+
+ int32_t isConvex = 1;
+ dgEdge* ptr = edge;
+ int32_t mark = flatFace.IncLRU();
+
+ dgBigVector normal2 (normal);
+ dgBigVector p0 (&vertex[ptr->m_prev->m_incidentVertex * stride]);
+ dgBigVector p1 (&vertex[ptr->m_incidentVertex * stride]);
+ dgBigVector e0 (p1 - p0);
+ e0 = e0.Scale (float (1.0f) / (dgSqrt (e0 % e0) + float (1.0e-14f)));
+ do {
+ dgBigVector p2 (&vertex[ptr->m_next->m_incidentVertex * stride]);
+ dgBigVector e1 (p2 - p1);
+ e1 = e1.Scale (float (1.0f) / (sqrt (e1 % e1) + float (1.0e-14f)));
+ double dot = (e0 * e1) % normal2;
+ //if (dot > float (0.0f)) {
+ if (dot > float (5.0e-3f)) {
+ isConvex = 0;
+ break;
+ }
+ ptr->m_mark = mark;
+ e0 = e1;
+ p1 = p2;
+ ptr = ptr->m_next;
+ } while (ptr != edge);
+
+ if (isConvex) {
+ dgPolyhedra::Iterator iter (flatFace);
+ for (iter.Begin(); iter; iter ++) {
+ ptr = &(*iter);
+ if (ptr->m_incidentFace < 0) {
+ if (ptr->m_mark < mark) {
+ isConvex = 0;
+ break;
+ }
+ }
+ }
+ }
+
+ if (isConvex) {
+ if (diagonalCount > 2) {
+ int32_t count = 0;
+ ptr = edge;
+ do {
+ polygon[count] = ptr->m_incidentVertex;
+ count ++;
+ HACD_ASSERT (count < int32_t (sizeof (polygon) / sizeof (polygon[0])));
+ ptr = ptr->m_next;
+ } while (ptr != edge);
+
+ for (int32_t i = 0; i < count - 1; i ++) {
+ for (int32_t j = i + 1; j < count; j ++) {
+ if (polygon[i] == polygon[j]) {
+ i = count;
+ isConvex = 0;
+ break ;
+ }
+ }
+ }
+ }
+ }
+
+ if (isConvex) {
+ for (int32_t j = 0; j < diagonalCount; j ++) {
+ dgEdge* const diagonal = diagonalsPool[j];
+ removeCount ++;
+ flatFace.DeleteEdge (diagonal);
+ }
+ } else {
+ for (int32_t j = 0; j < diagonalCount; j ++) {
+ dgEdge* const diagonal = diagonalsPool[j];
+ if (!IsEssensialDiagonal(diagonal, normal, vertex, stride)) {
+ removeCount ++;
+ flatFace.DeleteEdge (diagonal);
+ }
+ }
+ }
+ }
+
+ int32_t mark = flatFace.IncLRU();
+ dgPolyhedra::Iterator iter (flatFace);
+ for (iter.Begin(); iter; iter ++) {
+ dgEdge* const edge = &(*iter);
+ if (edge->m_mark != mark) {
+ if (edge->m_incidentFace > 0) {
+ dgEdge* ptr = edge;
+ int32_t diagonalCount = 0;
+ do {
+ polygon[diagonalCount] = ptr->m_incidentVertex;
+ diagonalCount ++;
+ HACD_ASSERT (diagonalCount < int32_t (sizeof (polygon) / sizeof (polygon[0])));
+ ptr->m_mark = mark;
+ ptr = ptr->m_next;
+ } while (ptr != edge);
+ if (diagonalCount >= 3) {
+ buildConvex.AddFace (diagonalCount, polygon);
+ }
+ }
+ }
+ }
+ }
+ iter.Begin();
+ }
+ }
+
+ buildConvex.EndFace();
+ HACD_ASSERT (GetCount() == 0);
+ SwapInfo(buildConvex);
+ }
+ }
+}
+
+
+dgSphere dgPolyhedra::CalculateSphere (const double* const vertex, int32_t strideInBytes, const dgMatrix* const /*basis*/) const
+{
+/*
+ // this si a degenerate mesh of a flat plane calculate OOBB by discrete rotations
+ dgStack<int32_t> pool (GetCount() * 3 + 6);
+ int32_t* const indexList = &pool[0];
+
+ dgMatrix axis (dgGetIdentityMatrix());
+ dgBigVector p0 (float ( 1.0e10f), float ( 1.0e10f), float ( 1.0e10f), float (0.0f));
+ dgBigVector p1 (float (-1.0e10f), float (-1.0e10f), float (-1.0e10f), float (0.0f));
+
+ int32_t stride = int32_t (strideInBytes / sizeof (double));
+ int32_t indexCount = 0;
+ int32_t mark = IncLRU();
+ dgPolyhedra::Iterator iter(*this);
+ for (iter.Begin(); iter; iter ++) {
+ dgEdge* const edge = &(*iter);
+ if (edge->m_mark != mark) {
+ dgEdge *ptr = edge;
+ do {
+ ptr->m_mark = mark;
+ ptr = ptr->m_twin->m_next;
+ } while (ptr != edge);
+ int32_t index = edge->m_incidentVertex;
+ indexList[indexCount + 6] = edge->m_incidentVertex;
+ dgBigVector point (vertex[index * stride + 0], vertex[index * stride + 1], vertex[index * stride + 2], float (0.0f));
+ for (int32_t i = 0; i < 3; i ++) {
+ if (point[i] < p0[i]) {
+ p0[i] = point[i];
+ indexList[i * 2 + 0] = index;
+ }
+ if (point[i] > p1[i]) {
+ p1[i] = point[i];
+ indexList[i * 2 + 1] = index;
+ }
+ }
+ indexCount ++;
+ }
+ }
+ indexCount += 6;
+
+
+ dgBigVector size (p1 - p0);
+ double volume = size.m_x * size.m_y * size.m_z;
+
+
+ for (float pitch = float (0.0f); pitch < float (90.0f); pitch += float (10.0f)) {
+ dgMatrix pitchMatrix (dgPitchMatrix(pitch * float (3.1416f) / float (180.0f)));
+ for (float yaw = float (0.0f); yaw < float (90.0f); yaw += float (10.0f)) {
+ dgMatrix yawMatrix (dgYawMatrix(yaw * float (3.1416f) / float (180.0f)));
+ for (float roll = float (0.0f); roll < float (90.0f); roll += float (10.0f)) {
+ int32_t tmpIndex[6];
+ dgMatrix rollMatrix (dgRollMatrix(roll * float (3.1416f) / float (180.0f)));
+ dgMatrix tmp (pitchMatrix * yawMatrix * rollMatrix);
+ dgBigVector q0 (float ( 1.0e10f), float ( 1.0e10f), float ( 1.0e10f), float (0.0f));
+ dgBigVector q1 (float (-1.0e10f), float (-1.0e10f), float (-1.0e10f), float (0.0f));
+
+ float volume1 = float (1.0e10f);
+ for (int32_t i = 0; i < indexCount; i ++) {
+ int32_t index = indexList[i];
+ dgBigVector point (vertex[index * stride + 0], vertex[index * stride + 1], vertex[index * stride + 2], float (0.0f));
+ point = tmp.UnrotateVector(point);
+
+ for (int32_t j = 0; j < 3; j ++) {
+ if (point[j] < q0[j]) {
+ q0[j] = point[j];
+ tmpIndex[j * 2 + 0] = index;
+ }
+ if (point[j] > q1[j]) {
+ q1[j] = point[j];
+ tmpIndex[j * 2 + 1] = index;
+ }
+ }
+
+
+ dgVector size1 (q1 - q0);
+ volume1 = size1.m_x * size1.m_y * size1.m_z;
+ if (volume1 >= volume) {
+ break;
+ }
+ }
+
+ if (volume1 < volume) {
+ p0 = q0;
+ p1 = q1;
+ axis = tmp;
+ volume = volume1;
+ memcpy (indexList, tmpIndex, sizeof (tmpIndex));
+ }
+ }
+ }
+ }
+
+ HACD_ASSERT (0);
+ dgSphere sphere (axis);
+ dgVector q0 (p0);
+ dgVector q1 (p1);
+ sphere.m_posit = axis.RotateVector((q1 + q0).Scale (float (0.5f)));
+ sphere.m_size = (q1 - q0).Scale (float (0.5f));
+ return sphere;
+*/
+
+ int32_t stride = int32_t (strideInBytes / sizeof (double));
+
+ int32_t vertexCount = 0;
+ int32_t mark = IncLRU();
+ dgPolyhedra::Iterator iter(*this);
+ for (iter.Begin(); iter; iter ++) {
+ dgEdge* const edge = &(*iter);
+ if (edge->m_mark != mark) {
+ dgEdge* ptr = edge;
+ do {
+ ptr->m_mark = mark;
+ ptr = ptr->m_twin->m_next;
+ } while (ptr != edge);
+ vertexCount ++;
+ }
+ }
+ HACD_ASSERT (vertexCount);
+
+ mark = IncLRU();
+ int32_t vertexCountIndex = 0;
+ dgStack<dgBigVector> pool (vertexCount);
+ for (iter.Begin(); iter; iter ++) {
+ dgEdge* const edge = &(*iter);
+ if (edge->m_mark != mark) {
+ dgEdge* ptr = edge;
+ do {
+ ptr->m_mark = mark;
+ ptr = ptr->m_twin->m_next;
+ } while (ptr != edge);
+ int32_t incidentVertex = edge->m_incidentVertex * stride;
+ pool[vertexCountIndex] = dgBigVector (vertex[incidentVertex + 0], vertex[incidentVertex + 1], vertex[incidentVertex + 2], float (0.0f));
+ vertexCountIndex ++;
+ }
+ }
+ HACD_ASSERT (vertexCountIndex <= vertexCount);
+
+ dgMatrix axis (dgGetIdentityMatrix());
+ dgSphere sphere (axis);
+ dgConvexHull3d convexHull (&pool[0].m_x, sizeof (dgBigVector), vertexCountIndex, 0.0f);
+ if (convexHull.GetCount()) {
+ dgStack<int32_t> triangleList (convexHull.GetCount() * 3);
+ int32_t trianglesCount = 0;
+ for (dgConvexHull3d::dgListNode* node = convexHull.GetFirst(); node; node = node->GetNext()) {
+ dgConvexHull3DFace* const face = &node->GetInfo();
+ triangleList[trianglesCount * 3 + 0] = face->m_index[0];
+ triangleList[trianglesCount * 3 + 1] = face->m_index[1];
+ triangleList[trianglesCount * 3 + 2] = face->m_index[2];
+ trianglesCount ++;
+ HACD_ASSERT ((trianglesCount * 3) <= triangleList.GetElementsCount());
+ }
+
+ dgVector* const dst = (dgVector*) &pool[0].m_x;
+ for (int32_t i = 0; i < convexHull.GetVertexCount(); i ++) {
+ dst[i] = convexHull.GetVertex(i);
+ }
+ sphere.SetDimensions (&dst[0].m_x, sizeof (dgVector), &triangleList[0], trianglesCount * 3, NULL);
+
+ } else if (vertexCountIndex >= 3) {
+ dgStack<int32_t> triangleList (GetCount() * 3 * 2);
+ int32_t mark = IncLRU();
+ int32_t trianglesCount = 0;
+ for (iter.Begin(); iter; iter ++) {
+ dgEdge* const edge = &(*iter);
+ if (edge->m_mark != mark) {
+ dgEdge* ptr = edge;
+ do {
+ ptr->m_mark = mark;
+ ptr = ptr->m_twin->m_next;
+ } while (ptr != edge);
+
+ ptr = edge->m_next->m_next;
+ do {
+ triangleList[trianglesCount * 3 + 0] = edge->m_incidentVertex;
+ triangleList[trianglesCount * 3 + 1] = ptr->m_prev->m_incidentVertex;
+ triangleList[trianglesCount * 3 + 2] = ptr->m_incidentVertex;
+ trianglesCount ++;
+ HACD_ASSERT ((trianglesCount * 3) <= triangleList.GetElementsCount());
+ ptr = ptr->m_twin->m_next;
+ } while (ptr != edge);
+
+ dgVector* const dst = (dgVector*) &pool[0].m_x;
+ for (int32_t i = 0; i < vertexCountIndex; i ++) {
+ dst[i] = pool[i];
+ }
+ sphere.SetDimensions (&dst[0].m_x, sizeof (dgVector), &triangleList[0], trianglesCount * 3, NULL);
+ }
+ }
+ }
+ return sphere;
+
+}