static void Statistics (dgSphere &sphere, dgVector &eigenValues, dgVector &scaleVector, const hacd::HaF32 vertex[], hacd::HaI32 vertexCount, hacd::HaI32 stride) { dgBigVector var (hacd::HaF32 (0.0f), hacd::HaF32 (0.0f), hacd::HaF32 (0.0f), hacd::HaF32 (0.0f)); dgBigVector cov (hacd::HaF32 (0.0f), hacd::HaF32 (0.0f), hacd::HaF32 (0.0f), hacd::HaF32 (0.0f)); dgBigVector massCenter (hacd::HaF32 (0.0f), hacd::HaF32 (0.0f), hacd::HaF32 (0.0f), hacd::HaF32 (0.0f)); const hacd::HaF32* ptr = vertex; for (hacd::HaI32 i = 0; i < vertexCount; i ++) { hacd::HaF32 x = ptr[0] * scaleVector.m_x; hacd::HaF32 y = ptr[1] * scaleVector.m_y; hacd::HaF32 z = ptr[2] * scaleVector.m_z; ptr += stride; massCenter += dgBigVector (x, y, z, hacd::HaF32 (0.0f)); var += dgBigVector (x * x, y * y, z * z, hacd::HaF32 (0.0f)); cov += dgBigVector (x * y, x * z, y * z, hacd::HaF32 (0.0f)); } hacd::HaF64 k = hacd::HaF64 (1.0) / vertexCount; var = var.Scale (k); cov = cov.Scale (k); massCenter = massCenter.Scale (k); hacd::HaF64 Ixx = var.m_x - massCenter.m_x * massCenter.m_x; hacd::HaF64 Iyy = var.m_y - massCenter.m_y * massCenter.m_y; hacd::HaF64 Izz = var.m_z - massCenter.m_z * massCenter.m_z; hacd::HaF64 Ixy = cov.m_x - massCenter.m_x * massCenter.m_y; hacd::HaF64 Ixz = cov.m_y - massCenter.m_x * massCenter.m_z; hacd::HaF64 Iyz = cov.m_z - massCenter.m_y * massCenter.m_z; sphere.m_front = dgVector (hacd::HaF32(Ixx), hacd::HaF32(Ixy), hacd::HaF32(Ixz), hacd::HaF32 (0.0f)); sphere.m_up = dgVector (hacd::HaF32(Ixy), hacd::HaF32(Iyy), hacd::HaF32(Iyz), hacd::HaF32 (0.0f)); sphere.m_right = dgVector (hacd::HaF32(Ixz), hacd::HaF32(Iyz), hacd::HaF32(Izz), hacd::HaF32 (0.0f)); sphere.EigenVectors (eigenValues); }
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 () :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) { }
static void Statistics ( dgSphere &sphere, dgVector &eigenValues, dgVector &scaleVector, const dgFloat32 vertex[], dgInt32 vertexCount, dgInt32 stride) { dgInt32 i; const dgFloat32 *ptr; dgFloat32 x; dgFloat32 z; dgFloat32 y; dgFloat64 k; dgFloat64 Ixx; dgFloat64 Iyy; dgFloat64 Izz; dgFloat64 Ixy; dgFloat64 Ixz; dgFloat64 Iyz; dgBigVector var (0.0f, 0.0f, 0.0f, 0.0f); dgBigVector cov (0.0f, 0.0f, 0.0f, 0.0f); dgBigVector massCenter (0.0f, 0.0f, 0.0f, 0.0f); ptr = vertex; for (i = 0; i < vertexCount; i ++) { x = ptr[0] * scaleVector.m_x; y = ptr[1] * scaleVector.m_y; z = ptr[2] * scaleVector.m_z; ptr += stride; massCenter += dgBigVector (x, y, z, 0.0f); var += dgBigVector (x * x, y * y, z * z, 0.0f); cov += dgBigVector (x * y, x * z, y * z, 0.0f); } k = 1.0 / vertexCount; var = var.Scale (k); cov = cov.Scale (k); massCenter = massCenter.Scale (k); Ixx = var.m_x - massCenter.m_x * massCenter.m_x; Iyy = var.m_y - massCenter.m_y * massCenter.m_y; Izz = var.m_z - massCenter.m_z * massCenter.m_z; Ixy = cov.m_x - massCenter.m_x * massCenter.m_y; Ixz = cov.m_y - massCenter.m_x * massCenter.m_z; Iyz = cov.m_z - massCenter.m_y * massCenter.m_z; sphere.m_front = dgVector (dgFloat32(Ixx), dgFloat32(Ixy), dgFloat32(Ixz), dgFloat32 (0.0f)); sphere.m_up = dgVector (dgFloat32(Ixy), dgFloat32(Iyy), dgFloat32(Iyz), dgFloat32 (0.0f)); sphere.m_right = dgVector (dgFloat32(Ixz), dgFloat32(Iyz), dgFloat32(Izz), dgFloat32 (0.0f)); sphere.EigenVectors (eigenValues); }
dgBigVector LineTriangleIntersection (const dgBigVector& p0, const dgBigVector& p1, const dgBigVector& A, const dgBigVector& B, const dgBigVector& C) { dgHugeVector ph0 (p0); dgHugeVector ph1 (p1); dgHugeVector Ah (A); dgHugeVector Bh (B); dgHugeVector Ch (C); dgHugeVector p1p0 (ph1 - ph0); dgHugeVector Ap0 (Ah - ph0); dgHugeVector Bp0 (Bh - ph0); dgHugeVector Cp0 (Ch - ph0); dgGoogol t0 ((Bp0 * Cp0) % p1p0); //hacd::HaF64 val0 = t0.GetAproximateValue(); //if (val0 < hacd::HaF64 (0.0f)) { if (hacd::HaF64(t0) < hacd::HaF64(0.0f)) { return dgBigVector (hacd::HaF32 (0.0f), hacd::HaF32 (0.0f), hacd::HaF32 (0.0f), hacd::HaF32 (-1.0f)); } dgGoogol t1 ((Cp0 * Ap0) % p1p0); // hacd::HaF64 val1 = t1.GetAproximateValue(); // if (val1 < hacd::HaF64 (0.0f)) { if (hacd::HaF64 (t1) < hacd::HaF64 (0.0f)) { return dgBigVector (hacd::HaF32 (0.0f), hacd::HaF32 (0.0f), hacd::HaF32 (0.0f), hacd::HaF32 (-1.0f)); } dgGoogol t2 ((Ap0 * Bp0) % p1p0); //hacd::HaF64 val2 = t2.GetAproximateValue(); //if (val2 < hacd::HaF64 (0.0f)) { if (hacd::HaF64 (t2) < hacd::HaF64 (0.0f)) { return dgBigVector (hacd::HaF32 (0.0f), hacd::HaF32 (0.0f), hacd::HaF32 (0.0f), hacd::HaF32 (-1.0f)); } dgGoogol sum = t0 + t1 + t2; //hacd::HaF64 den = sum.GetAproximateValue(); #ifdef _DEBUG //dgBigVector testpoint (A.Scale (val0 / den) + B.Scale (val1 / den) + C.Scale(val2 / den)); dgBigVector testpoint (A.Scale (t0 / sum) + B.Scale (t1 / sum) + C.Scale(t2 / sum)); hacd::HaF64 volume = ((B - A) * (C - A)) % (testpoint - A); HACD_ASSERT (fabs (volume) < hacd::HaF64 (1.0e-12f)); #endif // return dgBigVector (val0 / den, val1 / den, val2 / den, hacd::HaF32 (0.0f)); return dgBigVector (t0 / sum, t1 / sum, t2 / sum, hacd::HaF32 (0.0f)); }
dgBigVector LineTriangleIntersection (const dgBigVector& p0, const dgBigVector& p1, const dgBigVector& A, const dgBigVector& B, const dgBigVector& C) { dgHugeVector ph0 (p0); dgHugeVector ph1 (p1); dgHugeVector Ah (A); dgHugeVector Bh (B); dgHugeVector Ch (C); dgHugeVector p1p0 (ph1 - ph0); dgHugeVector Ap0 (Ah - ph0); dgHugeVector Bp0 (Bh - ph0); dgHugeVector Cp0 (Ch - ph0); dgGoogol t0 ((Bp0 * Cp0) % p1p0); dgFloat64 val0 = t0.GetAproximateValue(); if (val0 < dgFloat64 (0.0f)) { return dgBigVector (dgFloat32 (0.0f), dgFloat32 (0.0f), dgFloat32 (0.0f), dgFloat32 (-1.0f)); } dgGoogol t1 ((Cp0 * Ap0) % p1p0); dgFloat64 val1 = t1.GetAproximateValue(); if (val1 < dgFloat64 (0.0f)) { return dgBigVector (dgFloat32 (0.0f), dgFloat32 (0.0f), dgFloat32 (0.0f), dgFloat32 (-1.0f)); } dgGoogol t2 ((Ap0 * Bp0) % p1p0); dgFloat64 val2 = t2.GetAproximateValue(); if (val2 < dgFloat64 (0.0f)) { return dgBigVector (dgFloat32 (0.0f), dgFloat32 (0.0f), dgFloat32 (0.0f), dgFloat32 (-1.0f)); } dgGoogol sum = t0 + t1 + t2; dgFloat64 den = sum.GetAproximateValue(); #ifdef _DEBUG dgBigVector testpoint (A.Scale (val0 / den) + B.Scale (val1 / den) + C.Scale(val2 / den)); dgFloat64 volume = ((B - A) * (C - A)) % (testpoint - A); _ASSERTE (fabs (volume) < dgFloat64 (1.0e-12f)); #endif return dgBigVector (val0 / den, val1 / den, val2 / den, dgFloat32 (0.0f)); }
dgBigVector LineTriangleIntersection (const dgBigVector& p0, const dgBigVector& p1, const dgBigVector& A, const dgBigVector& B, const dgBigVector& C) { dgHugeVector ph0 (p0); dgHugeVector ph1 (p1); dgHugeVector Ah (A); dgHugeVector Bh (B); dgHugeVector Ch (C); dgHugeVector p1p0 (ph1 - ph0); dgHugeVector Ap0 (Ah - ph0); dgHugeVector Bp0 (Bh - ph0); dgHugeVector Cp0 (Ch - ph0); dgGoogol t0 ((Bp0 * Cp0) % p1p0); double val0 = t0.GetAproximateValue(); if (val0 < double (0.0f)) { return dgBigVector (float (0.0f), float (0.0f), float (0.0f), float (-1.0f)); } dgGoogol t1 ((Cp0 * Ap0) % p1p0); double val1 = t1.GetAproximateValue(); if (val1 < double (0.0f)) { return dgBigVector (float (0.0f), float (0.0f), float (0.0f), float (-1.0f)); } dgGoogol t2 ((Ap0 * Bp0) % p1p0); double val2 = t2.GetAproximateValue(); if (val2 < double (0.0f)) { return dgBigVector (float (0.0f), float (0.0f), float (0.0f), float (-1.0f)); } dgGoogol sum = t0 + t1 + t2; double den = sum.GetAproximateValue(); return dgBigVector (val0 / den, val1 / den, val2 / den, float (0.0f)); }
dgAABBPointTree4d* dgConvexHull4d::BuildTree (dgAABBPointTree4d* const parent, dgHullVector* const points, dgInt32 count, dgInt32 baseIndex, dgInt8** memoryPool, dgInt32& maxMemSize) const { dgAABBPointTree4d* tree = NULL; dgAssert (count); dgBigVector minP ( dgFloat32 (1.0e15f), dgFloat32 (1.0e15f), dgFloat32 (1.0e15f), dgFloat32 (1.0e15f)); dgBigVector maxP (-dgFloat32 (1.0e15f), -dgFloat32 (1.0e15f), -dgFloat32 (1.0e15f), -dgFloat32 (1.0e15f)); if (count <= DG_VERTEX_CLUMP_SIZE_4D) { dgAABBPointTree4dClump* const clump = new (*memoryPool) dgAABBPointTree4dClump; *memoryPool += sizeof (dgAABBPointTree4dClump); maxMemSize -= sizeof (dgAABBPointTree4dClump); dgAssert (maxMemSize >= 0); dgAssert (clump); clump->m_count = count; for (dgInt32 i = 0; i < count; i ++) { clump->m_indices[i] = i + baseIndex; const dgBigVector& p = points[i]; minP.m_x = dgMin (p.m_x, minP.m_x); minP.m_y = dgMin (p.m_y, minP.m_y); minP.m_z = dgMin (p.m_z, minP.m_z); minP.m_w = dgMin (p.m_w, minP.m_w); maxP.m_x = dgMax (p.m_x, maxP.m_x); maxP.m_y = dgMax (p.m_y, maxP.m_y); maxP.m_z = dgMax (p.m_z, maxP.m_z); maxP.m_w = dgMax (p.m_w, maxP.m_w); } clump->m_left = NULL; clump->m_right = NULL; tree = clump; } else { dgBigVector median (dgFloat32 (0.0f), dgFloat32 (0.0f), dgFloat32 (0.0f), dgFloat32 (0.0f)); dgBigVector varian (dgFloat32 (0.0f), dgFloat32 (0.0f), dgFloat32 (0.0f), dgFloat32 (0.0f)); for (dgInt32 i = 0; i < count; i ++) { const dgBigVector& p = points[i]; minP.m_x = dgMin (p.m_x, minP.m_x); minP.m_y = dgMin (p.m_y, minP.m_y); minP.m_z = dgMin (p.m_z, minP.m_z); minP.m_w = dgMin (p.m_w, minP.m_w); maxP.m_x = dgMax (p.m_x, maxP.m_x); maxP.m_y = dgMax (p.m_y, maxP.m_y); maxP.m_z = dgMax (p.m_z, maxP.m_z); maxP.m_w = dgMax (p.m_w, maxP.m_w); median = median + p; varian = varian + p.CompProduct4(p); } varian = varian.Scale4 (dgFloat32 (count)) - median.CompProduct4(median); dgInt32 index = 0; dgFloat64 maxVarian = dgFloat64 (-1.0e10f); for (dgInt32 i = 0; i < 4; i ++) { if (varian[i] > maxVarian) { index = i; maxVarian = varian[i]; } } dgBigVector center = median.Scale4 (dgFloat64 (1.0f) / dgFloat64 (count)); dgFloat64 test = center[index]; dgInt32 i0 = 0; dgInt32 i1 = count - 1; do { for (; i0 <= i1; i0 ++) { dgFloat64 val = points[i0][index]; if (val > test) { break; } } for (; i1 >= i0; i1 --) { dgFloat64 val = points[i1][index]; if (val < test) { break; } } if (i0 < i1) { dgSwap(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) dgAABBPointTree4d; *memoryPool += sizeof (dgAABBPointTree4d); maxMemSize -= sizeof (dgAABBPointTree4d); dgAssert (maxMemSize >= 0); dgAssert (i0); dgAssert (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); } dgAssert (tree); tree->m_parent = parent; tree->m_box[0] = minP - dgBigVector (dgFloat64 (1.0e-3f), dgFloat64 (1.0e-3f), dgFloat64 (1.0e-3f), dgFloat64 (1.0e-3f)); tree->m_box[1] = maxP + dgBigVector (dgFloat64 (1.0e-3f), dgFloat64 (1.0e-3f), dgFloat64 (1.0e-3f), dgFloat64 (1.0e-3f)); return tree; }
dgDelaunayTetrahedralization::dgDelaunayTetrahedralization( dgMemoryAllocator* const allocator, const dgFloat64* const vertexCloud, dgInt32 count, dgInt32 strideInByte, dgFloat64 distTol) : dgConvexHull4d(allocator) { #ifdef _WIN32 dgUnsigned32 controlWorld = dgControlFP (0xffffffff, 0); dgControlFP(_PC_53, _MCW_PC); #endif dgStack<dgBigVector> pool(count); dgBigVector* const points = &pool[0]; dgInt32 stride = dgInt32(strideInByte / sizeof(dgFloat64)); for (dgInt32 i = 0; i < count; i++) { volatile float x = float(vertexCloud[i * stride + 0]); volatile float y = float(vertexCloud[i * stride + 1]); volatile float z = float(vertexCloud[i * stride + 2]); points[i] = dgBigVector(x, y, z, x * x + y * y + z * z); } dgInt32 oldCount = count; BuildHull(allocator, &pool[0], count, distTol); #if 1 // if ((oldCount > m_count) && (m_count >= 4)) { if (oldCount > m_count) { // this is probably a regular convex solid, which will have a zero volume hull // add the rest of the points by incremental insertion with small perturbation dgInt32 hullCount = m_count; for (dgInt32 i = 0; i < count; i++) { bool inHull = false; const dgHullVector* const hullPoints = &m_points[0]; for (dgInt32 j = 0; j < hullCount; j++) { if (hullPoints[j].m_index == i) { inHull = true; break; } } if (!inHull) { dgBigVector q(points[i]); dgInt32 index = AddVertex(q); if (index == -1) { q.m_x += dgFloat64(1.0e-3f); q.m_y += dgFloat64(1.0e-3f); q.m_z += dgFloat64(1.0e-3f); index = AddVertex(q); _ASSERTE(index != -1); }_ASSERTE(index != -1); // m_points[index] = points[i]; m_points[index].m_index = i; } } } #else if (oldCount > m_count) { // this is probably a regular convex solid, which will have a zero volume hull // perturbate a point and try again dgBigVector p (points[0]); points[0].m_x += dgFloat64 (1.0e-0f); points[0].m_y += dgFloat64 (1.0e-0f); points[0].m_z += dgFloat64 (1.0e-0f); points[0].m_w = points[0].m_x * points[0].m_x + points[0].m_y * points[0].m_y + points[0].m_z * points[0].m_z; BuildHull (allocator, &pool[0], oldCount, distTol); _ASSERTE (oldCount == m_count); // restore the old point //points[0].m_w = points[0].m_x * points[0].m_x + points[0].m_y * points[0].m_y + points[0].m_z * points[0].m_z; } #endif #ifdef _DEBUG SortVertexArray(); #endif #ifdef _WIN32 dgControlFP(controlWorld, _MCW_PC); #endif }
dgMeshEffect * dgMeshEffect::CreateVoronoiConvexDecomposition (dgMemoryAllocator * const allocator, dgInt32 pointCount, dgInt32 pointStrideInBytes, const dgFloat32 * const pointCloud, dgInt32 materialId, const dgMatrix & textureProjectionMatrix) { dgFloat32 normalAngleInRadians = 30.0f * 3.1416f / 180.0f; dgStack<dgBigVector> buffer (pointCount + 16); dgBigVector * const pool = &buffer[0]; dgInt32 count = 0; dgFloat64 quantizeFactor = dgFloat64 (16.0f); dgFloat64 invQuantizeFactor = dgFloat64 (1.0f) / quantizeFactor; dgInt32 stride = pointStrideInBytes / sizeof (dgFloat32); dgBigVector pMin (dgFloat32 (1.0e10f), dgFloat32 (1.0e10f), dgFloat32 (1.0e10f), dgFloat32 (0.0f)); dgBigVector pMax (dgFloat32 (-1.0e10f), dgFloat32 (-1.0e10f), dgFloat32 (-1.0e10f), dgFloat32 (0.0f)); for (dgInt32 i = 0; i < pointCount; i ++) { dgFloat64 x = pointCloud[i * stride + 0]; dgFloat64 y = pointCloud[i * stride + 1]; dgFloat64 z = pointCloud[i * stride + 2]; x = floor (x * quantizeFactor) * invQuantizeFactor; y = floor (y * quantizeFactor) * invQuantizeFactor; z = floor (z * quantizeFactor) * invQuantizeFactor; dgBigVector p (x, y, z, dgFloat64 (0.0f)); pMin = dgBigVector (dgMin (x, pMin.m_x), dgMin (y, pMin.m_y), dgMin (z, pMin.m_z), dgFloat64 (0.0f)); pMax = dgBigVector (dgMax (x, pMax.m_x), dgMax (y, pMax.m_y), dgMax (z, pMax.m_z), dgFloat64 (0.0f)); pool[count] = p; count ++; } // add the bbox as a barrier pool[count + 0] = dgBigVector ( pMin.m_x, pMin.m_y, pMin.m_z, dgFloat64 (0.0f)); pool[count + 1] = dgBigVector ( pMax.m_x, pMin.m_y, pMin.m_z, dgFloat64 (0.0f)); pool[count + 2] = dgBigVector ( pMin.m_x, pMax.m_y, pMin.m_z, dgFloat64 (0.0f)); pool[count + 3] = dgBigVector ( pMax.m_x, pMax.m_y, pMin.m_z, dgFloat64 (0.0f)); pool[count + 4] = dgBigVector ( pMin.m_x, pMin.m_y, pMax.m_z, dgFloat64 (0.0f)); pool[count + 5] = dgBigVector ( pMax.m_x, pMin.m_y, pMax.m_z, dgFloat64 (0.0f)); pool[count + 6] = dgBigVector ( pMin.m_x, pMax.m_y, pMax.m_z, dgFloat64 (0.0f)); pool[count + 7] = dgBigVector ( pMax.m_x, pMax.m_y, pMax.m_z, dgFloat64 (0.0f)); count += 8; dgStack<dgInt32> indexList (count); count = dgVertexListToIndexList (&pool[0].m_x, sizeof (dgBigVector), 3, count, &indexList[0], dgFloat64 (5.0e-2f)); dgAssert (count >= 8); dgFloat64 maxSize = dgMax (pMax.m_x - pMin.m_x, pMax.m_y - pMin.m_y, pMax.m_z - pMin.m_z); pMin -= dgBigVector (maxSize, maxSize, maxSize, dgFloat64 (0.0f)); pMax += dgBigVector (maxSize, maxSize, maxSize, dgFloat64 (0.0f)); // add the a guard zone, so that we do no have to clip dgInt32 guadVertexKey = count; pool[count + 0] = dgBigVector ( pMin.m_x, pMin.m_y, pMin.m_z, dgFloat64 (0.0f)); pool[count + 1] = dgBigVector ( pMax.m_x, pMin.m_y, pMin.m_z, dgFloat64 (0.0f)); pool[count + 2] = dgBigVector ( pMin.m_x, pMax.m_y, pMin.m_z, dgFloat64 (0.0f)); pool[count + 3] = dgBigVector ( pMax.m_x, pMax.m_y, pMin.m_z, dgFloat64 (0.0f)); pool[count + 4] = dgBigVector ( pMin.m_x, pMin.m_y, pMax.m_z, dgFloat64 (0.0f)); pool[count + 5] = dgBigVector ( pMax.m_x, pMin.m_y, pMax.m_z, dgFloat64 (0.0f)); pool[count + 6] = dgBigVector ( pMin.m_x, pMax.m_y, pMax.m_z, dgFloat64 (0.0f)); pool[count + 7] = dgBigVector ( pMax.m_x, pMax.m_y, pMax.m_z, dgFloat64 (0.0f)); count += 8; dgDelaunayTetrahedralization delaunayTetrahedras (allocator, &pool[0].m_x, count, sizeof (dgBigVector), dgFloat32 (0.0f)); delaunayTetrahedras.RemoveUpperHull (); // delaunayTetrahedras.Save("xxx0.txt"); dgInt32 tetraCount = delaunayTetrahedras.GetCount(); dgStack<dgBigVector> voronoiPoints (tetraCount + 32); dgStack<dgDelaunayTetrahedralization::dgListNode *> tetradrumNode (tetraCount); dgTree<dgList<dgInt32>, dgInt32> delanayNodes (allocator); dgInt32 index = 0; const dgHullVector * const delanayPoints = delaunayTetrahedras.GetHullVertexArray(); for (dgDelaunayTetrahedralization::dgListNode * node = delaunayTetrahedras.GetFirst(); node; node = node->GetNext()) { dgConvexHull4dTetraherum & tetra = node->GetInfo(); voronoiPoints[index] = tetra.CircumSphereCenter (delanayPoints); tetradrumNode[index] = node; for (dgInt32 i = 0; i < 4; i ++) { dgTree<dgList<dgInt32>, dgInt32>::dgTreeNode * header = delanayNodes.Find (tetra.m_faces[0].m_index[i]); if (!header) { dgList<dgInt32> list (allocator); header = delanayNodes.Insert (list, tetra.m_faces[0].m_index[i]); } header->GetInfo().Append (index); } index ++; } dgMeshEffect * const voronoiPartition = new (allocator) dgMeshEffect (allocator); voronoiPartition->BeginPolygon(); dgFloat64 layer = dgFloat64 (0.0f); dgTree<dgList<dgInt32>, dgInt32>::Iterator iter (delanayNodes); for (iter.Begin(); iter; iter ++) { dgTree<dgList<dgInt32>, dgInt32>::dgTreeNode * const nodeNode = iter.GetNode(); const dgList<dgInt32> & list = nodeNode->GetInfo(); dgInt32 key = nodeNode->GetKey(); if (key < guadVertexKey) { dgBigVector pointArray[512]; dgInt32 indexArray[512]; dgInt32 count = 0; for (dgList<dgInt32>::dgListNode * ptr = list.GetFirst(); ptr; ptr = ptr->GetNext()) { dgInt32 i = ptr->GetInfo(); pointArray[count] = voronoiPoints[i]; count ++; dgAssert (count < dgInt32 (sizeof (pointArray) / sizeof (pointArray[0]))); } count = dgVertexListToIndexList (&pointArray[0].m_x, sizeof (dgBigVector), 3, count, &indexArray[0], dgFloat64 (1.0e-3f)); if (count >= 4) { dgMeshEffect convexMesh (allocator, &pointArray[0].m_x, count, sizeof (dgBigVector), dgFloat64 (0.0f)); if (convexMesh.GetCount()) { convexMesh.CalculateNormals (normalAngleInRadians); convexMesh.UniformBoxMapping (materialId, textureProjectionMatrix); for (dgInt32 i = 0; i < convexMesh.m_pointCount; i ++) convexMesh.m_points[i].m_w = layer; for (dgInt32 i = 0; i < convexMesh.m_atribCount; i ++) convexMesh.m_attrib[i].m_vertex.m_w = layer; voronoiPartition->MergeFaces (&convexMesh); layer += dgFloat64 (1.0f); } } } } voronoiPartition->EndPolygon (dgFloat64 (1.0e-8f), false); // voronoiPartition->SaveOFF("xxx0.off"); //voronoiPartition->ConvertToPolygons(); return voronoiPartition; }