diff options
| author | git perforce import user <a@b> | 2016-10-25 12:29:14 -0600 |
|---|---|---|
| committer | Sheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees> | 2016-10-25 18:56:37 -0500 |
| commit | 3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch) | |
| tree | fa6485c169e50d7415a651bf838f5bcd0fd3bfbd /APEX_1.4/shared/general/HACD/src/dgConvexHull3d.cpp | |
| download | physx-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/dgConvexHull3d.cpp')
| -rw-r--r-- | APEX_1.4/shared/general/HACD/src/dgConvexHull3d.cpp | 994 |
1 files changed, 994 insertions, 0 deletions
diff --git a/APEX_1.4/shared/general/HACD/src/dgConvexHull3d.cpp b/APEX_1.4/shared/general/HACD/src/dgConvexHull3d.cpp new file mode 100644 index 00000000..e08cdb3f --- /dev/null +++ b/APEX_1.4/shared/general/HACD/src/dgConvexHull3d.cpp @@ -0,0 +1,994 @@ +/* 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 "dgStack.h" +#include "dgTree.h" +#include "dgGoogol.h" +#include "dgConvexHull3d.h" +#include "dgSmallDeterminant.h" + +#define DG_VERTEX_CLUMP_SIZE_3D 8 + +class dgAABBPointTree3d +{ + public: +#ifdef _DEBUG + dgAABBPointTree3d() + { + static int32_t id = 0; + m_id = id; + id ++; + } + int32_t m_id; +#endif + + dgBigVector m_box[2]; + dgAABBPointTree3d* m_left; + dgAABBPointTree3d* m_right; + dgAABBPointTree3d* m_parent; +}; + +class dgHullVertex: public dgBigVector +{ + public: + int32_t m_index; +}; + +class dgAABBPointTree3dClump: public dgAABBPointTree3d +{ + public: + int32_t m_count; + int32_t m_indices[DG_VERTEX_CLUMP_SIZE_3D]; +}; + + +dgConvexHull3DFace::dgConvexHull3DFace() +{ + m_mark = 0; + m_twin[0] = NULL; + m_twin[1] = NULL; + m_twin[2] = NULL; +} + +double dgConvexHull3DFace::Evalue (const dgBigVector* const pointArray, const dgBigVector& point) const +{ + const dgBigVector& p0 = pointArray[m_index[0]]; + const dgBigVector& p1 = pointArray[m_index[1]]; + const dgBigVector& p2 = pointArray[m_index[2]]; + + double matrix[3][3]; + for (int32_t i = 0; i < 3; i ++) { + matrix[0][i] = p2[i] - p0[i]; + matrix[1][i] = p1[i] - p0[i]; + matrix[2][i] = point[i] - p0[i]; + } + + double error; + double det = Determinant3x3 (matrix, &error); + double precision = double (1.0f) / double (1<<24); + double errbound = error * precision; + if (fabs(det) > errbound) { + return det; + } + + dgGoogol exactMatrix[3][3]; + for (int32_t i = 0; i < 3; i ++) { + exactMatrix[0][i] = dgGoogol(p2[i]) - dgGoogol(p0[i]); + exactMatrix[1][i] = dgGoogol(p1[i]) - dgGoogol(p0[i]); + exactMatrix[2][i] = dgGoogol(point[i]) - dgGoogol(p0[i]); + } + + dgGoogol exactDet (Determinant3x3(exactMatrix)); + det = exactDet.GetAproximateValue(); + return det; +} + +dgBigPlane dgConvexHull3DFace::GetPlaneEquation (const dgBigVector* const pointArray) const +{ + const dgBigVector& p0 = pointArray[m_index[0]]; + const dgBigVector& p1 = pointArray[m_index[1]]; + const dgBigVector& p2 = pointArray[m_index[2]]; + dgBigPlane plane (p0, p1, p2); + plane = plane.Scale (1.0f / sqrt (plane % plane)); + return plane; +} + + +dgConvexHull3d::dgConvexHull3d () + :dgList<dgConvexHull3DFace>() + ,m_count (0) + ,m_diag() + ,m_aabbP0(dgBigVector (double (0.0), double (0.0), double (0.0), double (0.0))) + ,m_aabbP1(dgBigVector (double (0.0), double (0.0), double (0.0), double (0.0))) + ,m_points(1024) +{ +} + +dgConvexHull3d::dgConvexHull3d(const dgConvexHull3d& source) + :dgList<dgConvexHull3DFace>() + ,m_count (source.m_count) + ,m_diag(source.m_diag) + ,m_aabbP0 (source.m_aabbP0) + ,m_aabbP1 (source.m_aabbP1) + ,m_points(source.m_count) +{ + m_points[m_count-1].m_w = double (0.0f); + for (int i = 0; i < m_count; i ++) { + m_points[i] = source.m_points[i]; + } + dgTree<dgListNode*, dgListNode*> map; + for(dgListNode* sourceNode = source.GetFirst(); sourceNode; sourceNode = sourceNode->GetNext() ) { + dgListNode* const node = Append(); + map.Insert(node, sourceNode); + } + + for(dgListNode* sourceNode = source.GetFirst(); sourceNode; sourceNode = sourceNode->GetNext() ) { + dgListNode* const node = map.Find(sourceNode)->GetInfo(); + + dgConvexHull3DFace& face = node->GetInfo(); + dgConvexHull3DFace& srcFace = sourceNode->GetInfo(); + + face.m_mark = 0; + for (int32_t i = 0; i < 3; i ++) { + face.m_index[i] = srcFace.m_index[i]; + face.m_twin[i] = map.Find (srcFace.m_twin[i])->GetInfo(); + } + } +} + +dgConvexHull3d::dgConvexHull3d(const double* const vertexCloud, int32_t strideInBytes, int32_t count, double distTol, int32_t maxVertexCount) + :m_count (0) + ,m_diag() + ,m_aabbP0 (dgBigVector (double (0.0), double (0.0), double (0.0), double (0.0))) + ,m_aabbP1 (dgBigVector (double (0.0), double (0.0), double (0.0), double (0.0))) + ,m_points(count) +{ + BuildHull (vertexCloud, strideInBytes, count, distTol, maxVertexCount); +} + +dgConvexHull3d::~dgConvexHull3d(void) +{ +} + +void dgConvexHull3d::BuildHull (const double* const vertexCloud, int32_t strideInBytes, int32_t count, double distTol, int32_t maxVertexCount) +{ + int32_t treeCount = count / (DG_VERTEX_CLUMP_SIZE_3D>>1); + if (treeCount < 4) { + treeCount = 4; + } + treeCount *= 2; + + dgStack<dgHullVertex> points (count); + dgStack<dgAABBPointTree3dClump> treePool (treeCount + 256); + count = InitVertexArray(&points[0], vertexCloud, strideInBytes, count, &treePool[0], treePool.GetSizeInBytes()); + + if (m_count >= 4) { + CalculateConvexHull (&treePool[0], &points[0], count, distTol, maxVertexCount); + } +} + +int32_t dgConvexHull3d::ConvexCompareVertex(const dgHullVertex* const A, const dgHullVertex* const B, void* const context) +{ + HACD_FORCE_PARAMETER_REFERENCE(context); + for (int32_t i = 0; i < 3; i ++) { + if ((*A)[i] < (*B)[i]) { + return -1; + } else if ((*A)[i] > (*B)[i]) { + return 1; + } + } + return 0; +} + + + +dgAABBPointTree3d* dgConvexHull3d::BuildTree (dgAABBPointTree3d* const parent, dgHullVertex* const points, int32_t count, int32_t baseIndex, int8_t** memoryPool, int32_t& maxMemSize) const +{ + dgAABBPointTree3d* tree = NULL; + + HACD_ASSERT (count); + dgBigVector minP ( float (1.0e15f), float (1.0e15f), float (1.0e15f), float (0.0f)); + dgBigVector maxP (-float (1.0e15f), -float (1.0e15f), -float (1.0e15f), float (0.0f)); + if (count <= DG_VERTEX_CLUMP_SIZE_3D) { + + dgAABBPointTree3dClump* const clump = new (*memoryPool) dgAABBPointTree3dClump; + *memoryPool += sizeof (dgAABBPointTree3dClump); + maxMemSize -= sizeof (dgAABBPointTree3dClump); + HACD_ASSERT (maxMemSize >= 0); + + + clump->m_count = count; + for (int32_t i = 0; i < count; i ++) { + clump->m_indices[i] = i + baseIndex; + + const dgBigVector& p = points[i]; + minP.m_x = GetMin (p.m_x, minP.m_x); + minP.m_y = GetMin (p.m_y, minP.m_y); + minP.m_z = GetMin (p.m_z, minP.m_z); + + maxP.m_x = GetMax (p.m_x, maxP.m_x); + maxP.m_y = GetMax (p.m_y, maxP.m_y); + maxP.m_z = GetMax (p.m_z, maxP.m_z); + } + + clump->m_left = NULL; + clump->m_right = NULL; + tree = clump; + + } else { + dgBigVector median (float (0.0f), float (0.0f), float (0.0f), float (0.0f)); + dgBigVector varian (float (0.0f), float (0.0f), float (0.0f), float (0.0f)); + for (int32_t i = 0; i < count; i ++) { + + const dgBigVector& p = points[i]; + minP.m_x = GetMin (p.m_x, minP.m_x); + minP.m_y = GetMin (p.m_y, minP.m_y); + minP.m_z = GetMin (p.m_z, minP.m_z); + + maxP.m_x = GetMax (p.m_x, maxP.m_x); + maxP.m_y = GetMax (p.m_y, maxP.m_y); + maxP.m_z = GetMax (p.m_z, maxP.m_z); + + median += p; + varian += p.CompProduct (p); + } + + varian = varian.Scale (float (count)) - median.CompProduct(median); + int32_t index = 0; + double maxVarian = double (-1.0e10f); + for (int32_t i = 0; i < 3; i ++) { + if (varian[i] > maxVarian) { + index = i; + maxVarian = varian[i]; + } + } + dgBigVector center = median.Scale (double (1.0f) / double (count)); + + double test = center[index]; + + int32_t i0 = 0; + int32_t i1 = count - 1; + do { + for (; i0 <= i1; i0 ++) { + double val = points[i0][index]; + if (val > test) { + break; + } + } + + for (; i1 >= i0; i1 --) { + double val = points[i1][index]; + if (val < test) { + break; + } + } + + if (i0 < i1) { + Swap(points[i0], points[i1]); + i0++; + i1--; + } + } while (i0 <= i1); + + if (i0 == 0){ + i0 = count / 2; + } + if (i0 == (count - 1)){ + i0 = count / 2; + } + + tree = new (*memoryPool) dgAABBPointTree3d; + *memoryPool += sizeof (dgAABBPointTree3d); + maxMemSize -= sizeof (dgAABBPointTree3d); + HACD_ASSERT (maxMemSize >= 0); + + HACD_ASSERT (i0); + HACD_ASSERT (count - i0); + + tree->m_left = BuildTree (tree, points, i0, baseIndex, memoryPool, maxMemSize); + tree->m_right = BuildTree (tree, &points[i0], count - i0, i0 + baseIndex, memoryPool, maxMemSize); + } + + HACD_ASSERT (tree); + tree->m_parent = parent; + tree->m_box[0] = minP - dgBigVector (double (1.0e-3f), double (1.0e-3f), double (1.0e-3f), double (1.0f)); + tree->m_box[1] = maxP + dgBigVector (double (1.0e-3f), double (1.0e-3f), double (1.0e-3f), double (1.0f)); + return tree; +} + + + + + +int32_t dgConvexHull3d::InitVertexArray(dgHullVertex* const points, const double* const vertexCloud, int32_t strideInBytes, int32_t count, void* const memoryPool, int32_t maxMemSize) +{ + int32_t stride = int32_t (strideInBytes / sizeof (double)); + if (stride >= 4) { + for (int32_t i = 0; i < count; i ++) { + int32_t index = i * stride; + dgBigVector& vertex = points[i]; + vertex = dgBigVector (vertexCloud[index], vertexCloud[index + 1], vertexCloud[index + 2], vertexCloud[index + 3]); + HACD_ASSERT (dgCheckVector(vertex)); + points[i].m_index = 0; + } + } else { + for (int32_t i = 0; i < count; i ++) { + int32_t index = i * stride; + dgBigVector& vertex = points[i]; + vertex = dgBigVector (vertexCloud[index], vertexCloud[index + 1], vertexCloud[index + 2], double (0.0f)); + HACD_ASSERT (dgCheckVector(vertex)); + points[i].m_index = 0; + } + } + + dgSort(points, count, ConvexCompareVertex); + + int32_t indexCount = 0; + for (int i = 1; i < count; i ++) { + for (; i < count; i ++) { + if (ConvexCompareVertex (&points[indexCount], &points[i], NULL)) { + indexCount ++; + points[indexCount] = points[i]; + break; + } + } + } + count = indexCount + 1; + if (count < 4) { + m_count = 0; + return count; + } + + dgAABBPointTree3d* tree = BuildTree (NULL, points, count, 0, (int8_t**) &memoryPool, maxMemSize); + + m_aabbP0 = tree->m_box[0]; + m_aabbP1 = tree->m_box[1]; + + dgBigVector boxSize (tree->m_box[1] - tree->m_box[0]); + m_diag = float (sqrt (boxSize % boxSize)); + + dgStack<dgBigVector> normalArrayPool (256); + dgBigVector* const normalArray = &normalArrayPool[0]; + int32_t normalCount = BuildNormalList (&normalArray[0]); + + int32_t index = SupportVertex (&tree, points, normalArray[0]); + m_points[0] = points[index]; + points[index].m_index = 1; + + bool validTetrahedrum = false; + dgBigVector e1 (double (0.0f), double (0.0f), double (0.0f), double (0.0f)) ; + for (int32_t i = 1; i < normalCount; i ++) { + int32_t index = SupportVertex (&tree, points, normalArray[i]); + HACD_ASSERT (index >= 0); + + e1 = points[index] - m_points[0]; + double error2 = e1 % e1; + if (error2 > (float (1.0e-4f) * m_diag * m_diag)) { + m_points[1] = points[index]; + points[index].m_index = 1; + validTetrahedrum = true; + break; + } + } + if (!validTetrahedrum) { + m_count = 0; + HACD_ASSERT (0); + return count; + } + + validTetrahedrum = false; + dgBigVector e2(float (0.0f), float (0.0f), float (0.0f), float (0.0f));; + dgBigVector normal (float (0.0f), float (0.0f), float (0.0f), float (0.0f)); + for (int32_t i = 2; i < normalCount; i ++) { + int32_t index = SupportVertex (&tree, points, normalArray[i]); + HACD_ASSERT (index >= 0); + e2 = points[index] - m_points[0]; + normal = e1 * e2; + double error2 = sqrt (normal % normal); + if (error2 > (float (1.0e-4f) * m_diag * m_diag)) { + m_points[2] = points[index]; + points[index].m_index = 1; + validTetrahedrum = true; + break; + } + } + + if (!validTetrahedrum) { + m_count = 0; + HACD_ASSERT (0); + return count; + } + + // find the largest possible tetrahedron + validTetrahedrum = false; + dgBigVector e3(float (0.0f), float (0.0f), float (0.0f), float (0.0f)); + + index = SupportVertex (&tree, points, normal); + e3 = points[index] - m_points[0]; + double error2 = normal % e3; + if (fabs (error2) > (double (1.0e-6f) * m_diag * m_diag)) { + // we found a valid tetrahedra, about and start build the hull by adding the rest of the points + m_points[3] = points[index]; + points[index].m_index = 1; + validTetrahedrum = true; + } + if (!validTetrahedrum) { + dgVector n (normal.Scale(double (-1.0f))); + int32_t index = SupportVertex (&tree, points, n); + e3 = points[index] - m_points[0]; + double error2 = normal % e3; + if (fabs (error2) > (double (1.0e-6f) * m_diag * m_diag)) { + // we found a valid tetrahedra, about and start build the hull by adding the rest of the points + m_points[3] = points[index]; + points[index].m_index = 1; + validTetrahedrum = true; + } + } + if (!validTetrahedrum) { + for (int32_t i = 3; i < normalCount; i ++) { + int32_t index = SupportVertex (&tree, points, normalArray[i]); + HACD_ASSERT (index >= 0); + + //make sure the volume of the fist tetrahedral is no negative + e3 = points[index] - m_points[0]; + double error2 = normal % e3; + if (fabs (error2) > (double (1.0e-6f) * m_diag * m_diag)) { + // we found a valid tetrahedra, about and start build the hull by adding the rest of the points + m_points[3] = points[index]; + points[index].m_index = 1; + validTetrahedrum = true; + break; + } + } + } + if (!validTetrahedrum) { + // the points do not form a convex hull + m_count = 0; + //HACD_ASSERT (0); + return count; + } + + m_count = 4; + double volume = TetrahedrumVolume (m_points[0], m_points[1], m_points[2], m_points[3]); + if (volume > double (0.0f)) { + Swap(m_points[2], m_points[3]); + } + HACD_ASSERT (TetrahedrumVolume(m_points[0], m_points[1], m_points[2], m_points[3]) < double(0.0f)); + + return count; +} + +double dgConvexHull3d::TetrahedrumVolume (const dgBigVector& p0, const dgBigVector& p1, const dgBigVector& p2, const dgBigVector& p3) const +{ + dgBigVector p1p0 (p1 - p0); + dgBigVector p2p0 (p2 - p0); + dgBigVector p3p0 (p3 - p0); + return (p1p0 * p2p0) % p3p0; +} + + +void dgConvexHull3d::TessellateTriangle (int32_t level, const dgVector& p0, const dgVector& p1, const dgVector& p2, int32_t& count, dgBigVector* const ouput, int32_t& start) const +{ + if (level) { + HACD_ASSERT (dgAbsf (p0 % p0 - float (1.0f)) < float (1.0e-4f)); + HACD_ASSERT (dgAbsf (p1 % p1 - float (1.0f)) < float (1.0e-4f)); + HACD_ASSERT (dgAbsf (p2 % p2 - float (1.0f)) < float (1.0e-4f)); + dgVector p01 (p0 + p1); + dgVector p12 (p1 + p2); + dgVector p20 (p2 + p0); + + p01 = p01.Scale (float (1.0f) / dgSqrt(p01 % p01)); + p12 = p12.Scale (float (1.0f) / dgSqrt(p12 % p12)); + p20 = p20.Scale (float (1.0f) / dgSqrt(p20 % p20)); + + HACD_ASSERT (dgAbsf (p01 % p01 - float (1.0f)) < float (1.0e-4f)); + HACD_ASSERT (dgAbsf (p12 % p12 - float (1.0f)) < float (1.0e-4f)); + HACD_ASSERT (dgAbsf (p20 % p20 - float (1.0f)) < float (1.0e-4f)); + + TessellateTriangle (level - 1, p0, p01, p20, count, ouput, start); + TessellateTriangle (level - 1, p1, p12, p01, count, ouput, start); + TessellateTriangle (level - 1, p2, p20, p12, count, ouput, start); + TessellateTriangle (level - 1, p01, p12, p20, count, ouput, start); + + } else { + dgBigPlane n (p0, p1, p2); + n = n.Scale (double(1.0f) / sqrt (n % n)); + n.m_w = double(0.0f); + ouput[start] = n; + start += 8; + count ++; + } +} + + +int32_t dgConvexHull3d::SupportVertex (dgAABBPointTree3d** const treePointer, const dgHullVertex* const points, const dgBigVector& dir) const +{ +/* + double dist = float (-1.0e10f); + int32_t index = -1; + for (int32_t i = 0; i < count; i ++) { + //double dist1 = dir.DotProduct4 (points[i]); + double dist1 = dir % points[i]; + if (dist1 > dist) { + dist = dist1; + index = i; + } + } + HACD_ASSERT (index != -1); + return index; +*/ + + #define DG_STACK_DEPTH_3D 64 + double aabbProjection[DG_STACK_DEPTH_3D]; + const dgAABBPointTree3d *stackPool[DG_STACK_DEPTH_3D]; + + int32_t index = -1; + int32_t stack = 1; + stackPool[0] = *treePointer; + aabbProjection[0] = float (1.0e20f); + double maxProj = double (-1.0e20f); + int32_t ix = (dir[0] > double (0.0f)) ? 1 : 0; + int32_t iy = (dir[1] > double (0.0f)) ? 1 : 0; + int32_t iz = (dir[2] > double (0.0f)) ? 1 : 0; + while (stack) { + stack--; + double boxSupportValue = aabbProjection[stack]; + if (boxSupportValue > maxProj) { + const dgAABBPointTree3d* const me = stackPool[stack]; + + if (me->m_left && me->m_right) { + dgBigVector leftSupportPoint (me->m_left->m_box[ix].m_x, me->m_left->m_box[iy].m_y, me->m_left->m_box[iz].m_z, float (0.0)); + double leftSupportDist = leftSupportPoint % dir; + + dgBigVector rightSupportPoint (me->m_right->m_box[ix].m_x, me->m_right->m_box[iy].m_y, me->m_right->m_box[iz].m_z, float (0.0)); + double rightSupportDist = rightSupportPoint % dir; + + + if (rightSupportDist >= leftSupportDist) { + aabbProjection[stack] = leftSupportDist; + stackPool[stack] = me->m_left; + stack++; + HACD_ASSERT (stack < DG_STACK_DEPTH_3D); + aabbProjection[stack] = rightSupportDist; + stackPool[stack] = me->m_right; + stack++; + HACD_ASSERT (stack < DG_STACK_DEPTH_3D); + } else { + aabbProjection[stack] = rightSupportDist; + stackPool[stack] = me->m_right; + stack++; + HACD_ASSERT (stack < DG_STACK_DEPTH_3D); + aabbProjection[stack] = leftSupportDist; + stackPool[stack] = me->m_left; + stack++; + HACD_ASSERT (stack < DG_STACK_DEPTH_3D); + } + + } else { + dgAABBPointTree3dClump* const clump = (dgAABBPointTree3dClump*) me; + for (int32_t i = 0; i < clump->m_count; i ++) { + const dgHullVertex& p = points[clump->m_indices[i]]; + HACD_ASSERT (p.m_x >= clump->m_box[0].m_x); + HACD_ASSERT (p.m_x <= clump->m_box[1].m_x); + HACD_ASSERT (p.m_y >= clump->m_box[0].m_y); + HACD_ASSERT (p.m_y <= clump->m_box[1].m_y); + HACD_ASSERT (p.m_z >= clump->m_box[0].m_z); + HACD_ASSERT (p.m_z <= clump->m_box[1].m_z); + if (!p.m_index) { + double dist = p % dir; + if (dist > maxProj) { + maxProj = dist; + index = clump->m_indices[i]; + } + } else { + clump->m_indices[i] = clump->m_indices[clump->m_count - 1]; + clump->m_count = clump->m_count - 1; + i --; + } + } + + if (clump->m_count == 0) { + dgAABBPointTree3d* const parent = clump->m_parent; + if (parent) { + dgAABBPointTree3d* const sibling = (parent->m_left != clump) ? parent->m_left : parent->m_right; + HACD_ASSERT (sibling != clump); + dgAABBPointTree3d* const grandParent = parent->m_parent; + if (grandParent) { + sibling->m_parent = grandParent; + if (grandParent->m_right == parent) { + grandParent->m_right = sibling; + } else { + grandParent->m_left = sibling; + } + } else { + sibling->m_parent = NULL; + *treePointer = sibling; + } + } + } + } + } + } + + HACD_ASSERT (index != -1); + return index; +} + + +int32_t dgConvexHull3d::BuildNormalList (dgBigVector* const normalArray) const +{ + dgVector p0 ( float (1.0f), float (0.0f), float (0.0f), float (0.0f)); + dgVector p1 (-float (1.0f), float (0.0f), float (0.0f), float (0.0f)); + dgVector p2 ( float (0.0f), float (1.0f), float (0.0f), float (0.0f)); + dgVector p3 ( float (0.0f),-float (1.0f), float (0.0f), float (0.0f)); + dgVector p4 ( float (0.0f), float (0.0f), float (1.0f), float (0.0f)); + dgVector p5 ( float (0.0f), float (0.0f),-float (1.0f), float (0.0f)); + + int32_t count = 0; + int32_t subdivitions = 1; + + int32_t start = 0; + TessellateTriangle (subdivitions, p4, p0, p2, count, normalArray, start); + start = 1; + TessellateTriangle (subdivitions, p5, p3, p1, count, normalArray, start); + start = 2; + TessellateTriangle (subdivitions, p5, p1, p2, count, normalArray, start); + start = 3; + TessellateTriangle (subdivitions, p4, p3, p0, count, normalArray, start); + start = 4; + TessellateTriangle (subdivitions, p4, p2, p1, count, normalArray, start); + start = 5; + TessellateTriangle (subdivitions, p5, p0, p3, count, normalArray, start); + start = 6; + TessellateTriangle (subdivitions, p5, p2, p0, count, normalArray, start); + start = 7; + TessellateTriangle (subdivitions, p4, p1, p3, count, normalArray, start); + return count; +} + +dgConvexHull3d::dgListNode* dgConvexHull3d::AddFace (int32_t i0, int32_t i1, int32_t i2) +{ + dgListNode* const node = Append(); + dgConvexHull3DFace& face = node->GetInfo(); + + face.m_index[0] = i0; + face.m_index[1] = i1; + face.m_index[2] = i2; + return node; +} + +void dgConvexHull3d::DeleteFace (dgListNode* const node) +{ + Remove (node); +} + +bool dgConvexHull3d::Sanity() const +{ +/* + for (dgListNode* node = GetFirst(); node; node = node->GetNext()) { + dgConvexHull3DFace* const face = &node->GetInfo(); + for (int32_t i = 0; i < 3; i ++) { + dgListNode* const twinNode = face->m_twin[i]; + if (!twinNode) { + return false; + } + + int32_t count = 0; + dgListNode* me = NULL; + dgConvexHull3DFace* const twinFace = &twinNode->GetInfo(); + for (int32_t j = 0; j < 3; j ++) { + if (twinFace->m_twin[j] == node) { + count ++; + me = twinFace->m_twin[j]; + } + } + if (count != 1) { + return false; + } + if (me != node) { + return false; + } + } + } +*/ + return true; +} + +void dgConvexHull3d::CalculateConvexHull (dgAABBPointTree3d* vertexTree, dgHullVertex* const points, int32_t count, double distTol, int32_t maxVertexCount) +{ + distTol = fabs (distTol) * m_diag; + dgListNode* const f0Node = AddFace (0, 1, 2); + dgListNode* const f1Node = AddFace (0, 2, 3); + dgListNode* const f2Node = AddFace (2, 1, 3); + dgListNode* const f3Node = AddFace (1, 0, 3); + + dgConvexHull3DFace* const f0 = &f0Node->GetInfo(); + dgConvexHull3DFace* const f1 = &f1Node->GetInfo(); + dgConvexHull3DFace* const f2 = &f2Node->GetInfo(); + dgConvexHull3DFace* const f3 = &f3Node->GetInfo(); + + f0->m_twin[0] = (dgList<dgConvexHull3DFace>::dgListNode*)f3Node; + f0->m_twin[1] = (dgList<dgConvexHull3DFace>::dgListNode*)f2Node; + f0->m_twin[2] = (dgList<dgConvexHull3DFace>::dgListNode*)f1Node; + + f1->m_twin[0] = (dgList<dgConvexHull3DFace>::dgListNode*)f0Node; + f1->m_twin[1] = (dgList<dgConvexHull3DFace>::dgListNode*)f2Node; + f1->m_twin[2] = (dgList<dgConvexHull3DFace>::dgListNode*)f3Node; + + f2->m_twin[0] = (dgList<dgConvexHull3DFace>::dgListNode*)f0Node; + f2->m_twin[1] = (dgList<dgConvexHull3DFace>::dgListNode*)f3Node; + f2->m_twin[2] = (dgList<dgConvexHull3DFace>::dgListNode*)f1Node; + + f3->m_twin[0] = (dgList<dgConvexHull3DFace>::dgListNode*)f0Node; + f3->m_twin[1] = (dgList<dgConvexHull3DFace>::dgListNode*)f1Node; + f3->m_twin[2] = (dgList<dgConvexHull3DFace>::dgListNode*)f2Node; + + dgList<dgListNode*> boundaryFaces; + + boundaryFaces.Append(f0Node); + boundaryFaces.Append(f1Node); + boundaryFaces.Append(f2Node); + boundaryFaces.Append(f3Node); + + dgStack<dgListNode*> stackPool(1024 + m_count); + dgStack<dgListNode*> coneListPool(1024 + m_count); + dgStack<dgListNode*> deleteListPool(1024 + m_count); + + dgListNode** const stack = &stackPool[0]; + dgListNode** const coneList = &stackPool[0]; + dgListNode** const deleteList = &deleteListPool[0]; + + count -= 4; + maxVertexCount -= 4; + int32_t currentIndex = 4; + + while (boundaryFaces.GetCount() && count && (maxVertexCount > 0)) { + // my definition of the optimal convex hull of a given vertex count, + // is the convex hull formed by a subset of vertex from the input array + // that minimized the volume difference between the perfect hull form those vertex, and the hull of the sub set of vertex. + // Only using a priority heap we can be sure that it will generate the best hull selecting the best points from the vertex array. + // Since all our tools do not have a limit on the point count of a hull I can use either a list of a queue. + // a stack maximize construction speed, a Queue tend to maximize the volume of the generated Hull. for now we use a queue. + // For perfect hulls it does not make a difference if we use a stack, queue, or a priority heap, + // this only apply for when build hull of a limited vertex count. + // + // Also when building Hulls of a limited vertex count, this function runs in constant time. + // yes that is correct, it does not makes a difference if you build a N point hull from 100 vertex + // or from 100000 vertex input array. + + #if 0 + // using stack (faster) + dgListNode* const faceNode = boundaryFaces.GetFirst()->GetInfo(); + #else + // using a queue (some what slower by better hull for reduce vertex count) + dgListNode* const faceNode = boundaryFaces.GetLast()->GetInfo(); + #endif + + dgConvexHull3DFace* const face = &faceNode->GetInfo(); + dgBigPlane planeEquation (face->GetPlaneEquation (&m_points[0])); + + int32_t index = SupportVertex (&vertexTree, points, planeEquation); + const dgBigVector& p = points[index]; + double dist = planeEquation.Evalue(p); + + if ((dist >= distTol) && (face->Evalue(&m_points[0], p) > double(0.0f))) { + HACD_ASSERT (Sanity()); + + HACD_ASSERT (faceNode); + stack[0] = faceNode; + + int32_t stackIndex = 1; + int32_t deletedCount = 0; + + while (stackIndex) { + stackIndex --; + dgListNode* const node = stack[stackIndex]; + dgConvexHull3DFace* const face = &node->GetInfo(); + + if (!face->m_mark && (face->Evalue(&m_points[0], p) > double(0.0f))) { + #ifdef _DEBUG + for (int32_t i = 0; i < deletedCount; i ++) { + HACD_ASSERT (deleteList[i] != node); + } + #endif + + deleteList[deletedCount] = node; + deletedCount ++; + HACD_ASSERT (deletedCount < int32_t (deleteListPool.GetElementsCount())); + face->m_mark = 1; + for (int32_t i = 0; i < 3; i ++) { + dgListNode* const twinNode = (dgListNode*)face->m_twin[i]; + HACD_ASSERT (twinNode); + dgConvexHull3DFace* const twinFace = &twinNode->GetInfo(); + if (!twinFace->m_mark) { + stack[stackIndex] = twinNode; + stackIndex ++; + HACD_ASSERT (stackIndex < int32_t (stackPool.GetElementsCount())); + } + } + } + } + +// Swap (hullVertexArray[index], hullVertexArray[currentIndex]); + m_points[currentIndex] = points[index]; + points[index].m_index = 1; + + int32_t newCount = 0; + for (int32_t i = 0; i < deletedCount; i ++) { + dgListNode* const node = deleteList[i]; + dgConvexHull3DFace* const face = &node->GetInfo(); + HACD_ASSERT (face->m_mark == 1); + for (int32_t j0 = 0; j0 < 3; j0 ++) { + dgListNode* const twinNode = face->m_twin[j0]; + dgConvexHull3DFace* const twinFace = &twinNode->GetInfo(); + if (!twinFace->m_mark) { + int32_t j1 = (j0 == 2) ? 0 : j0 + 1; + dgListNode* const newNode = AddFace (currentIndex, face->m_index[j0], face->m_index[j1]); + boundaryFaces.Addtop(newNode); + + dgConvexHull3DFace* const newFace = &newNode->GetInfo(); + newFace->m_twin[1] = twinNode; + for (int32_t k = 0; k < 3; k ++) { + if (twinFace->m_twin[k] == node) { + twinFace->m_twin[k] = newNode; + } + } + coneList[newCount] = newNode; + newCount ++; + HACD_ASSERT (newCount < int32_t (coneListPool.GetElementsCount())); + } + } + } + + for (int32_t i = 0; i < newCount - 1; i ++) { + dgListNode* const nodeA = coneList[i]; + dgConvexHull3DFace* const faceA = &nodeA->GetInfo(); + HACD_ASSERT (faceA->m_mark == 0); + for (int32_t j = i + 1; j < newCount; j ++) { + dgListNode* const nodeB = coneList[j]; + dgConvexHull3DFace* const faceB = &nodeB->GetInfo(); + HACD_ASSERT (faceB->m_mark == 0); + if (faceA->m_index[2] == faceB->m_index[1]) { + faceA->m_twin[2] = nodeB; + faceB->m_twin[0] = nodeA; + break; + } + } + + for (int32_t j = i + 1; j < newCount; j ++) { + dgListNode* const nodeB = coneList[j]; + dgConvexHull3DFace* const faceB = &nodeB->GetInfo(); + HACD_ASSERT (faceB->m_mark == 0); + if (faceA->m_index[1] == faceB->m_index[2]) { + faceA->m_twin[0] = nodeB; + faceB->m_twin[2] = nodeA; + break; + } + } + } + + for (int32_t i = 0; i < deletedCount; i ++) { + dgListNode* const node = deleteList[i]; + boundaryFaces.Remove (node); + DeleteFace (node); + } + + maxVertexCount --; + currentIndex ++; + count --; + } else { + boundaryFaces.Remove (faceNode); + } + } + m_count = currentIndex; +} + + +void dgConvexHull3d::CalculateVolumeAndSurfaceArea (double& volume, double& surfaceArea) const +{ + double areaAcc = float (0.0f); + double volumeAcc = float (0.0f); + for (dgListNode* node = GetFirst(); node; node = node->GetNext()) { + const dgConvexHull3DFace* const face = &node->GetInfo(); + int32_t i0 = face->m_index[0]; + int32_t i1 = face->m_index[1]; + int32_t i2 = face->m_index[2]; + const dgBigVector& p0 = m_points[i0]; + const dgBigVector& p1 = m_points[i1]; + const dgBigVector& p2 = m_points[i2]; + dgBigVector normal ((p1 - p0) * (p2 - p0)); + double area = sqrt (normal % normal); + areaAcc += area; + volumeAcc += (p0 * p1) % p2; + } + HACD_ASSERT (volumeAcc >= double (0.0f)); + volume = volumeAcc * double (1.0f/6.0f); + surfaceArea = areaAcc * double (0.5f); +} + +// this code has linear time complexity on the number of faces +double dgConvexHull3d::RayCast (const dgBigVector& localP0, const dgBigVector& localP1) const +{ + double interset = float (1.2f); + double tE = double (0.0f); // for the maximum entering segment parameter; + double tL = double (1.0f); // for the minimum leaving segment parameter; + dgBigVector dS (localP1 - localP0); // is the segment direction vector; + int32_t hasHit = 0; + + for (dgListNode* node = GetFirst(); node; node = node->GetNext()) + { + const dgConvexHull3DFace* const face = &node->GetInfo(); + + int32_t i0 = face->m_index[0]; + int32_t i1 = face->m_index[1]; + int32_t i2 = face->m_index[2]; + + const dgBigVector& p0 = m_points[i0]; + dgBigVector normal ((m_points[i1] - p0) * (m_points[i2] - p0)); + + double N = -((localP0 - p0) % normal); + double D = dS % normal; + + if (fabs(D) < double (1.0e-12f)) + { // + if (N < double (0.0f)) + { + return double (1.2f); + } + else + { + continue; + } + } + + double t = N / D; + if (D < double (0.0f)) + { + if (t > tE) + { + tE = t; + hasHit = 1; + } + if (tE > tL) + { + return double (1.2f); + } + } + else + { + HACD_ASSERT (D >= double (0.0f)); + tL = GetMin (tL, t); + if (tL < tE) + { + return double (1.2f); + } + } + } + + if (hasHit) + { + interset = tE; + } + + return interset; +} + + |