| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | #include "Wm4FoundationPCH.h"
|
| | #include "Wm4Delaunay3.h"
|
| | #include "Wm4DelPolyhedronFace.h"
|
| | #include "Wm4Mapper3.h"
|
| | #include "Wm4ETManifoldMesh.h"
|
| | #include "Wm4Delaunay2.h"
|
| | #include "Wm4Query3Filtered.h"
|
| | #include "Wm4Query3Int64.h"
|
| | #include "Wm4Query3TInteger.h"
|
| | #include "Wm4Query3TRational.h"
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | static const int gs_aaiIndex[4][3] = { {1,2,3}, {0,3,2}, {0,1,3}, {0,2,1} };
|
| |
|
| | namespace Wm4
|
| | {
|
| |
|
| | template <class Real>
|
| | Delaunay3<Real>::Delaunay3 (int iVertexQuantity, Vector3<Real>* akVertex,
|
| | Real fEpsilon, bool bOwner, Query::Type eQueryType)
|
| | :
|
| | Delaunay<Real>(iVertexQuantity,fEpsilon,bOwner,eQueryType),
|
| | m_kLineOrigin(Vector3<Real>::ZERO),
|
| | m_kLineDirection(Vector3<Real>::ZERO),
|
| | m_kPlaneOrigin(Vector3<Real>::ZERO)
|
| | {
|
| | assert(akVertex);
|
| | m_akVertex = akVertex;
|
| | m_iUniqueVertexQuantity = 0;
|
| | m_akPlaneDirection[0] = Vector3<Real>::ZERO;
|
| | m_akPlaneDirection[1] = Vector3<Real>::ZERO;
|
| | m_akSVertex = nullptr;
|
| | m_pkQuery = nullptr;
|
| | m_iPathLast = -1;
|
| | m_aiPath = nullptr;
|
| | m_iLastFaceV0 = -1;
|
| | m_iLastFaceV1 = -1;
|
| | m_iLastFaceV2 = -1;
|
| | m_iLastFaceOpposite = -1;
|
| | m_iLastFaceOppositeIndex = -1;
|
| |
|
| | Mapper3<Real> kMapper(m_iVertexQuantity,m_akVertex,m_fEpsilon);
|
| | if (kMapper.GetDimension() == 0)
|
| | {
|
| |
|
| |
|
| | return;
|
| | }
|
| |
|
| | int i;
|
| | if (kMapper.GetDimension() == 1)
|
| | {
|
| |
|
| |
|
| | m_iDimension = 1;
|
| | m_kLineOrigin = kMapper.GetOrigin();
|
| | m_kLineDirection = kMapper.GetDirection(0);
|
| | return;
|
| | }
|
| |
|
| | if (kMapper.GetDimension() == 2)
|
| | {
|
| |
|
| |
|
| | m_iDimension = 2;
|
| | m_kPlaneOrigin = kMapper.GetOrigin();
|
| | m_akPlaneDirection[0] = kMapper.GetDirection(0);
|
| | m_akPlaneDirection[1] = kMapper.GetDirection(1);
|
| | return;
|
| | }
|
| |
|
| | m_iDimension = 3;
|
| |
|
| |
|
| |
|
| | m_akSVertex = WM4_NEW Vector3<Real>[m_iVertexQuantity+4];
|
| |
|
| | if (eQueryType != Query::QT_RATIONAL && eQueryType != Query::QT_FILTERED)
|
| | {
|
| |
|
| | m_kMin = kMapper.GetMin();
|
| | m_fScale = ((Real)1.0)/kMapper.GetMaxRange();
|
| | for (i = 0; i < m_iVertexQuantity; i++)
|
| | {
|
| | m_akSVertex[i] = (m_akVertex[i] - m_kMin)*m_fScale;
|
| | }
|
| |
|
| |
|
| | m_aiSV[0] = m_iVertexQuantity++;
|
| | m_aiSV[1] = m_iVertexQuantity++;
|
| | m_aiSV[2] = m_iVertexQuantity++;
|
| | m_aiSV[3] = m_iVertexQuantity++;
|
| | m_akSVertex[m_aiSV[0]] = Vector3<Real>((Real)-1.0,(Real)-1.0,
|
| | (Real)-1.0);
|
| | m_akSVertex[m_aiSV[1]] = Vector3<Real>((Real)+6.0,(Real)-1.0,
|
| | (Real)-1.0);
|
| | m_akSVertex[m_aiSV[2]] = Vector3<Real>((Real)-1.0,(Real)+6.0,
|
| | (Real)-1.0);
|
| | m_akSVertex[m_aiSV[3]] = Vector3<Real>((Real)-1.0,(Real)-1.0,
|
| | (Real)+6.0);
|
| |
|
| | Real fExpand;
|
| | if (eQueryType == Query::QT_INT64)
|
| | {
|
| |
|
| |
|
| | fExpand = (Real)(1 << 10);
|
| | m_pkQuery = WM4_NEW Query3Int64<Real>(m_iVertexQuantity,
|
| | m_akSVertex);
|
| | }
|
| | else if (eQueryType == Query::QT_INTEGER)
|
| | {
|
| |
|
| |
|
| |
|
| | fExpand = (Real)(1 << 20);
|
| | m_pkQuery = WM4_NEW Query3TInteger<Real>(m_iVertexQuantity,
|
| | m_akSVertex);
|
| | }
|
| | else
|
| | {
|
| |
|
| | fExpand = (Real)1.0;
|
| | m_pkQuery = WM4_NEW Query3<Real>(m_iVertexQuantity,m_akSVertex);
|
| | }
|
| |
|
| | m_fScale *= fExpand;
|
| | for (i = 0; i < m_iVertexQuantity; i++)
|
| | {
|
| | m_akSVertex[i] *= fExpand;
|
| | }
|
| | }
|
| | else
|
| | {
|
| |
|
| | m_kMin = Vector3<Real>::ZERO;
|
| | m_fScale = (Real)1.0;
|
| | size_t uiSize = m_iVertexQuantity*sizeof(Vector3<Real>);
|
| | System::Memcpy(m_akSVertex,uiSize,m_akVertex,uiSize);
|
| |
|
| |
|
| | Vector3<Real> kMin = kMapper.GetMin();
|
| | Vector3<Real> kMax = kMapper.GetMax();
|
| | Vector3<Real> kDelta = kMax - kMin;
|
| | Vector3<Real> kSMin = kMin - kDelta;
|
| | Vector3<Real> kSMax = kMax + ((Real)5.0)*kDelta;
|
| | m_aiSV[0] = m_iVertexQuantity++;
|
| | m_aiSV[1] = m_iVertexQuantity++;
|
| | m_aiSV[2] = m_iVertexQuantity++;
|
| | m_aiSV[3] = m_iVertexQuantity++;
|
| | m_akSVertex[m_aiSV[0]] = kSMin;
|
| | m_akSVertex[m_aiSV[1]] = Vector3<Real>(kSMax[0],kSMin[1],kSMin[2]);
|
| | m_akSVertex[m_aiSV[2]] = Vector3<Real>(kSMin[0],kSMax[1],kSMin[2]);
|
| | m_akSVertex[m_aiSV[3]] = Vector3<Real>(kSMin[0],kSMin[1],kSMax[2]);
|
| |
|
| | if (eQueryType == Query::QT_RATIONAL)
|
| | {
|
| | m_pkQuery = WM4_NEW Query3TRational<Real>(m_iVertexQuantity,
|
| | m_akSVertex);
|
| | }
|
| | else
|
| | {
|
| | m_pkQuery = WM4_NEW Query3Filtered<Real>(m_iVertexQuantity,
|
| | m_akSVertex,fEpsilon);
|
| | }
|
| | }
|
| |
|
| | DelTetrahedron<Real>* pkTetra = WM4_NEW DelTetrahedron<Real>(m_aiSV[0],
|
| | m_aiSV[1],m_aiSV[2],m_aiSV[3]);
|
| | m_kTetrahedron.insert(pkTetra);
|
| |
|
| |
|
| |
|
| |
|
| | std::set<Vector3<Real> > kProcessed;
|
| | for (i = 0; i < m_iVertexQuantity-4; i++)
|
| | {
|
| | if (kProcessed.find(m_akSVertex[i]) == kProcessed.end())
|
| | {
|
| | Update(i);
|
| | kProcessed.insert(m_akSVertex[i]);
|
| | }
|
| | }
|
| | m_iUniqueVertexQuantity = (int)kProcessed.size();
|
| |
|
| |
|
| | RemoveTetrahedra();
|
| |
|
| |
|
| | std::map<DelTetrahedron<Real>*,int> kPermute;
|
| | typename std::set<DelTetrahedron<Real>*>::iterator pkTIter =
|
| | m_kTetrahedron.begin();
|
| | for (i = 0; pkTIter != m_kTetrahedron.end(); pkTIter++)
|
| | {
|
| | pkTetra = *pkTIter;
|
| | kPermute[pkTetra] = i++;
|
| | }
|
| | kPermute[nullptr] = -1;
|
| |
|
| |
|
| | m_iSimplexQuantity = (int)m_kTetrahedron.size();
|
| | if (m_iSimplexQuantity > 0)
|
| | {
|
| | m_aiIndex = WM4_NEW int[4*m_iSimplexQuantity];
|
| | m_aiAdjacent = WM4_NEW int[4*m_iSimplexQuantity];
|
| | i = 0;
|
| | pkTIter = m_kTetrahedron.begin();
|
| | for (; pkTIter != m_kTetrahedron.end(); pkTIter++)
|
| | {
|
| | pkTetra = *pkTIter;
|
| | m_aiIndex[i] = pkTetra->V[0];
|
| | m_aiAdjacent[i++] = kPermute[pkTetra->A[0]];
|
| | m_aiIndex[i] = pkTetra->V[1];
|
| | m_aiAdjacent[i++] = kPermute[pkTetra->A[1]];
|
| | m_aiIndex[i] = pkTetra->V[2];
|
| | m_aiAdjacent[i++] = kPermute[pkTetra->A[2]];
|
| | m_aiIndex[i] = pkTetra->V[3];
|
| | m_aiAdjacent[i++] = kPermute[pkTetra->A[3]];
|
| | }
|
| | assert(i == 4*m_iSimplexQuantity);
|
| |
|
| | m_iPathLast = -1;
|
| | m_aiPath = WM4_NEW int[m_iSimplexQuantity+1];
|
| | }
|
| |
|
| |
|
| |
|
| | m_iVertexQuantity -= 4;
|
| |
|
| | pkTIter = m_kTetrahedron.begin();
|
| | for (; pkTIter != m_kTetrahedron.end(); ++pkTIter)
|
| | {
|
| | WM4_DELETE *pkTIter;
|
| | }
|
| | }
|
| |
|
| | template <class Real>
|
| | Delaunay3<Real>::~Delaunay3 ()
|
| | {
|
| | WM4_DELETE m_pkQuery;
|
| | WM4_DELETE[] m_akSVertex;
|
| | WM4_DELETE[] m_aiPath;
|
| | if (m_bOwner)
|
| | {
|
| | WM4_DELETE[] m_akVertex;
|
| | }
|
| | }
|
| |
|
| | template <class Real>
|
| | const Vector3<Real>* Delaunay3<Real>::GetVertices () const
|
| | {
|
| | return m_akVertex;
|
| | }
|
| |
|
| | template <class Real>
|
| | int Delaunay3<Real>::GetUniqueVertexQuantity () const
|
| | {
|
| | return m_iUniqueVertexQuantity;
|
| | }
|
| |
|
| | template <class Real>
|
| | const Vector3<Real>& Delaunay3<Real>::GetLineOrigin () const
|
| | {
|
| | return m_kLineOrigin;
|
| | }
|
| |
|
| | template <class Real>
|
| | const Vector3<Real>& Delaunay3<Real>::GetLineDirection () const
|
| | {
|
| | return m_kLineDirection;
|
| | }
|
| |
|
| | template <class Real>
|
| | Delaunay1<Real>* Delaunay3<Real>::GetDelaunay1 () const
|
| | {
|
| | assert(m_iDimension == 1);
|
| | if (m_iDimension != 1)
|
| | {
|
| | return nullptr;
|
| | }
|
| |
|
| | Real* afProjection = WM4_NEW Real[m_iVertexQuantity];
|
| | for (int i = 0; i < m_iVertexQuantity; i++)
|
| | {
|
| | Vector3<Real> kDiff = m_akVertex[i] - m_kLineOrigin;
|
| | afProjection[i] = m_kLineDirection.Dot(kDiff);
|
| | }
|
| |
|
| | return WM4_NEW Delaunay1<Real>(m_iVertexQuantity,afProjection,m_fEpsilon,
|
| | true,m_eQueryType);
|
| | }
|
| |
|
| | template <class Real>
|
| | const Vector3<Real>& Delaunay3<Real>::GetPlaneOrigin () const
|
| | {
|
| | return m_kPlaneOrigin;
|
| | }
|
| |
|
| | template <class Real>
|
| | const Vector3<Real>& Delaunay3<Real>::GetPlaneDirection (int i) const
|
| | {
|
| | assert(0 <= i && i < 2);
|
| | return m_akPlaneDirection[i];
|
| | }
|
| |
|
| | template <class Real>
|
| | Delaunay2<Real>* Delaunay3<Real>::GetDelaunay2 () const
|
| | {
|
| | assert(m_iDimension == 2);
|
| | if (m_iDimension != 2)
|
| | {
|
| | return nullptr;
|
| | }
|
| |
|
| | Vector2<Real>* akProjection = WM4_NEW Vector2<Real>[m_iVertexQuantity];
|
| | for (int i = 0; i < m_iVertexQuantity; i++)
|
| | {
|
| | Vector3<Real> kDiff = m_akVertex[i] - m_kPlaneOrigin;
|
| | akProjection[i][0] = m_akPlaneDirection[0].Dot(kDiff);
|
| | akProjection[i][1] = m_akPlaneDirection[1].Dot(kDiff);
|
| | }
|
| |
|
| | return WM4_NEW Delaunay2<Real>(m_iVertexQuantity,akProjection,m_fEpsilon,
|
| | true,m_eQueryType);
|
| | }
|
| |
|
| | template <class Real>
|
| | bool Delaunay3<Real>::GetHull (int& riTQuantity, int*& raiIndex) const
|
| | {
|
| | assert(m_iDimension == 3);
|
| | if (m_iDimension != 3)
|
| | {
|
| | return false;
|
| | }
|
| |
|
| | riTQuantity = 0;
|
| | raiIndex = nullptr;
|
| |
|
| |
|
| | int i, iAdjQuantity = 4*m_iSimplexQuantity;
|
| | for (i = 0; i < iAdjQuantity; i++)
|
| | {
|
| | if (m_aiAdjacent[i] == -1)
|
| | {
|
| | riTQuantity++;
|
| | }
|
| | }
|
| | assert(riTQuantity > 0);
|
| | if (riTQuantity == 0)
|
| | {
|
| | return false;
|
| | }
|
| |
|
| |
|
| | raiIndex = WM4_NEW int[3*riTQuantity];
|
| | int* piIndex = raiIndex;
|
| | for (i = 0; i < iAdjQuantity; i++)
|
| | {
|
| | if (m_aiAdjacent[i] == -1)
|
| | {
|
| | int iTetra = i/4, iFace = i%4;
|
| | for (int j = 0; j < 4; j++)
|
| | {
|
| | if (j != iFace)
|
| | {
|
| | *piIndex++ = m_aiIndex[4*iTetra+j];
|
| | }
|
| | }
|
| | if ((iFace % 2) == 0)
|
| | {
|
| | int iSave = *(piIndex-1);
|
| | *(piIndex-1) = *(piIndex-2);
|
| | *(piIndex-2) = iSave;
|
| | }
|
| | }
|
| | }
|
| |
|
| | return true;
|
| | }
|
| |
|
| | template <class Real>
|
| | int Delaunay3<Real>::GetContainingTetrahedron (const Vector3<Real>& rkP)
|
| | const
|
| | {
|
| | assert(m_iDimension == 3);
|
| | if (m_iDimension != 3)
|
| | {
|
| | return -1;
|
| | }
|
| |
|
| |
|
| | Vector3<Real> kXFrmP = (rkP - m_kMin)*m_fScale;
|
| |
|
| |
|
| | int iIndex = (m_iPathLast >= 0 ? m_aiPath[m_iPathLast] : 0);
|
| | m_iPathLast = -1;
|
| | m_iLastFaceV0 = -1;
|
| | m_iLastFaceV1 = -1;
|
| | m_iLastFaceV2 = -1;
|
| | m_iLastFaceOpposite = -1;
|
| | m_iLastFaceOppositeIndex = -1;
|
| |
|
| |
|
| | for (int i = 0; i < m_iSimplexQuantity; i++)
|
| | {
|
| | m_aiPath[++m_iPathLast] = iIndex;
|
| |
|
| | int* aiV = &m_aiIndex[4*iIndex];
|
| |
|
| |
|
| | if (m_pkQuery->ToPlane(kXFrmP,aiV[1],aiV[2],aiV[3]) > 0)
|
| | {
|
| | iIndex = m_aiAdjacent[4*iIndex];
|
| | if (iIndex == -1)
|
| | {
|
| | m_iLastFaceV0 = aiV[1];
|
| | m_iLastFaceV1 = aiV[2];
|
| | m_iLastFaceV2 = aiV[3];
|
| | m_iLastFaceOpposite = aiV[0];
|
| | m_iLastFaceOppositeIndex = 0;
|
| | return -1;
|
| | }
|
| | continue;
|
| | }
|
| |
|
| |
|
| | if (m_pkQuery->ToPlane(kXFrmP,aiV[0],aiV[2],aiV[3]) < 0)
|
| | {
|
| | iIndex = m_aiAdjacent[4*iIndex+1];
|
| | if (iIndex == -1)
|
| | {
|
| | m_iLastFaceV0 = aiV[0];
|
| | m_iLastFaceV1 = aiV[2];
|
| | m_iLastFaceV2 = aiV[3];
|
| | m_iLastFaceOpposite = aiV[1];
|
| | m_iLastFaceOppositeIndex = 1;
|
| | return -1;
|
| | }
|
| | continue;
|
| | }
|
| |
|
| |
|
| | if (m_pkQuery->ToPlane(kXFrmP,aiV[0],aiV[1],aiV[3]) > 0)
|
| | {
|
| | iIndex = m_aiAdjacent[4*iIndex+2];
|
| | if (iIndex == -1)
|
| | {
|
| | m_iLastFaceV0 = aiV[0];
|
| | m_iLastFaceV1 = aiV[1];
|
| | m_iLastFaceV2 = aiV[3];
|
| | m_iLastFaceOpposite = aiV[2];
|
| | m_iLastFaceOppositeIndex = 2;
|
| | return -1;
|
| | }
|
| | continue;
|
| | }
|
| |
|
| |
|
| | if (m_pkQuery->ToPlane(kXFrmP,aiV[0],aiV[1],aiV[2]) < 0)
|
| | {
|
| | iIndex = m_aiAdjacent[4*iIndex+3];
|
| | if (iIndex == -1)
|
| | {
|
| | m_iLastFaceV0 = aiV[0];
|
| | m_iLastFaceV1 = aiV[1];
|
| | m_iLastFaceV2 = aiV[2];
|
| | m_iLastFaceOpposite = aiV[3];
|
| | m_iLastFaceOppositeIndex = 3;
|
| | return -1;
|
| | }
|
| | continue;
|
| | }
|
| |
|
| | m_iLastFaceV0 = -1;
|
| | m_iLastFaceV1 = -1;
|
| | m_iLastFaceV2 = -1;
|
| | m_iLastFaceOppositeIndex = -1;
|
| | return iIndex;
|
| | }
|
| |
|
| | return -1;
|
| | }
|
| |
|
| | template <class Real>
|
| | int Delaunay3<Real>::GetPathLast () const
|
| | {
|
| | return m_iPathLast;
|
| | }
|
| |
|
| | template <class Real>
|
| | const int* Delaunay3<Real>::GetPath () const
|
| | {
|
| | return m_aiPath;
|
| | }
|
| |
|
| | template <class Real>
|
| | int Delaunay3<Real>::GetLastFace (int& riV0, int& riV1, int& riV2,
|
| | int& riV3) const
|
| | {
|
| | riV0 = m_iLastFaceV0;
|
| | riV1 = m_iLastFaceV1;
|
| | riV2 = m_iLastFaceV2;
|
| | riV3 = m_iLastFaceOpposite;
|
| | return m_iLastFaceOppositeIndex;
|
| | }
|
| |
|
| | template <class Real>
|
| | bool Delaunay3<Real>::GetVertexSet (int i, Vector3<Real> akV[4]) const
|
| | {
|
| | assert(m_iDimension == 3);
|
| | if (m_iDimension != 3)
|
| | {
|
| | return false;
|
| | }
|
| |
|
| | if (0 <= i && i < m_iSimplexQuantity)
|
| | {
|
| | akV[0] = m_akVertex[m_aiIndex[4*i ]];
|
| | akV[1] = m_akVertex[m_aiIndex[4*i+1]];
|
| | akV[2] = m_akVertex[m_aiIndex[4*i+2]];
|
| | akV[3] = m_akVertex[m_aiIndex[4*i+3]];
|
| | return true;
|
| | }
|
| |
|
| | return false;
|
| | }
|
| |
|
| | template <class Real>
|
| | bool Delaunay3<Real>::GetIndexSet (int i, int aiIndex[4]) const
|
| | {
|
| | assert(m_iDimension == 3);
|
| | if (m_iDimension != 3)
|
| | {
|
| | return false;
|
| | }
|
| |
|
| | if (0 <= i && i < m_iSimplexQuantity)
|
| | {
|
| | aiIndex[0] = m_aiIndex[4*i ];
|
| | aiIndex[1] = m_aiIndex[4*i+1];
|
| | aiIndex[2] = m_aiIndex[4*i+2];
|
| | aiIndex[3] = m_aiIndex[4*i+3];
|
| | return true;
|
| | }
|
| |
|
| | return false;
|
| | }
|
| |
|
| | template <class Real>
|
| | bool Delaunay3<Real>::GetAdjacentSet (int i, int aiAdjacent[4]) const
|
| | {
|
| | assert(m_iDimension == 3);
|
| | if (m_iDimension != 3)
|
| | {
|
| | return false;
|
| | }
|
| |
|
| | if (0 <= i && i < m_iSimplexQuantity)
|
| | {
|
| | aiAdjacent[0] = m_aiAdjacent[4*i ];
|
| | aiAdjacent[1] = m_aiAdjacent[4*i+1];
|
| | aiAdjacent[2] = m_aiAdjacent[4*i+2];
|
| | aiAdjacent[3] = m_aiAdjacent[4*i+3];
|
| | return true;
|
| | }
|
| |
|
| | return false;
|
| | }
|
| |
|
| | template <class Real>
|
| | bool Delaunay3<Real>::GetBarycentricSet (int i, const Vector3<Real>& rkP,
|
| | Real afBary[4]) const
|
| | {
|
| | assert(m_iDimension == 3);
|
| | if (m_iDimension != 3)
|
| | {
|
| | return false;
|
| | }
|
| |
|
| | if (0 <= i && i < m_iSimplexQuantity)
|
| | {
|
| | Vector3<Real> kV0 = m_akVertex[m_aiIndex[4*i ]];
|
| | Vector3<Real> kV1 = m_akVertex[m_aiIndex[4*i+1]];
|
| | Vector3<Real> kV2 = m_akVertex[m_aiIndex[4*i+2]];
|
| | Vector3<Real> kV3 = m_akVertex[m_aiIndex[4*i+3]];
|
| | rkP.GetBarycentrics(kV0,kV1,kV2,kV3,afBary);
|
| | return true;
|
| | }
|
| |
|
| | return false;
|
| | }
|
| |
|
| | template <class Real>
|
| | void Delaunay3<Real>::Update (int i)
|
| | {
|
| |
|
| | DelTetrahedron<Real>* pkTetra = GetContainingTetrahedron(i);
|
| |
|
| |
|
| | std::stack<DelTetrahedron<Real>*> kStack;
|
| | ETManifoldMesh kPolyhedron(nullptr,DelPolyhedronFace<Real>::TCreator);
|
| | kStack.push(pkTetra);
|
| | pkTetra->OnStack = true;
|
| | int j, iV0, iV1, iV2;
|
| | DelPolyhedronFace<Real>* pkFace;
|
| | while (!kStack.empty())
|
| | {
|
| | pkTetra = kStack.top();
|
| | kStack.pop();
|
| | pkTetra->OnStack = false;
|
| | for (j = 0; j < 4; j++)
|
| | {
|
| | DelTetrahedron<Real>* pkAdj = pkTetra->A[j];
|
| | if (pkAdj)
|
| | {
|
| |
|
| |
|
| | int iNullIndex = pkTetra->DetachFrom(j,pkAdj);
|
| |
|
| | if (pkAdj->IsInsertionComponent(i,pkTetra,m_pkQuery,m_aiSV))
|
| | {
|
| | if (!pkAdj->OnStack)
|
| | {
|
| |
|
| | kStack.push(pkAdj);
|
| | pkAdj->OnStack = true;
|
| | }
|
| | }
|
| | else
|
| | {
|
| |
|
| | iV0 = pkTetra->V[gs_aaiIndex[j][0]];
|
| | iV1 = pkTetra->V[gs_aaiIndex[j][1]];
|
| | iV2 = pkTetra->V[gs_aaiIndex[j][2]];
|
| | pkFace = (DelPolyhedronFace<Real>*)
|
| | kPolyhedron.InsertTriangle(iV0,iV1,iV2);
|
| | pkFace->NullIndex = iNullIndex;
|
| | pkFace->Tetra = pkAdj;
|
| | }
|
| | }
|
| | else
|
| | {
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | iV0 = pkTetra->V[gs_aaiIndex[j][0]];
|
| | if (IsSupervertex(iV0))
|
| | {
|
| | iV1 = pkTetra->V[gs_aaiIndex[j][1]];
|
| | if (IsSupervertex(iV1))
|
| | {
|
| | iV2 = pkTetra->V[gs_aaiIndex[j][2]];
|
| | if (IsSupervertex(iV2))
|
| | {
|
| | pkFace = (DelPolyhedronFace<Real>*)
|
| | kPolyhedron.InsertTriangle(iV0,iV1,iV2);
|
| | pkFace->NullIndex = -1;
|
| | pkFace->Tetra = nullptr;
|
| | }
|
| | }
|
| | }
|
| | }
|
| | }
|
| | m_kTetrahedron.erase(pkTetra);
|
| | WM4_DELETE pkTetra;
|
| | }
|
| |
|
| |
|
| |
|
| | const ETManifoldMesh::TMap& rkTMap = kPolyhedron.GetTriangles();
|
| | assert(rkTMap.size() >= 4 && kPolyhedron.IsClosed());
|
| | typename ETManifoldMesh::TMapCIterator pkTIter;
|
| | for (pkTIter = rkTMap.begin(); pkTIter != rkTMap.end(); pkTIter++)
|
| | {
|
| | pkFace = (DelPolyhedronFace<Real>*)pkTIter->second;
|
| |
|
| |
|
| | pkTetra = WM4_NEW DelTetrahedron<Real>(i,pkFace->V[0],pkFace->V[1],
|
| | pkFace->V[2]);
|
| | m_kTetrahedron.insert(pkTetra);
|
| |
|
| |
|
| | pkTetra->A[0] = pkFace->Tetra;
|
| | if (pkFace->Tetra)
|
| | {
|
| | pkFace->Tetra->A[pkFace->NullIndex] = pkTetra;
|
| | }
|
| |
|
| |
|
| |
|
| |
|
| | pkFace->Tetra = pkTetra;
|
| | }
|
| |
|
| |
|
| | DelPolyhedronFace<Real>* pkAdjFace;
|
| | for (pkTIter = rkTMap.begin(); pkTIter != rkTMap.end(); pkTIter++)
|
| | {
|
| | pkFace = (DelPolyhedronFace<Real>*)pkTIter->second;
|
| |
|
| | pkAdjFace = (DelPolyhedronFace<Real>*)pkFace->T[0];
|
| | pkFace->Tetra->A[3] = pkAdjFace->Tetra;
|
| | assert(SharesFace(3,pkFace->Tetra,pkAdjFace->Tetra));
|
| |
|
| | pkAdjFace = (DelPolyhedronFace<Real>*)pkFace->T[1];
|
| | pkFace->Tetra->A[1] = pkAdjFace->Tetra;
|
| | assert(SharesFace(1,pkFace->Tetra,pkAdjFace->Tetra));
|
| |
|
| | pkAdjFace = (DelPolyhedronFace<Real>*)pkFace->T[2];
|
| | pkFace->Tetra->A[2] = pkAdjFace->Tetra;
|
| | assert(SharesFace(2,pkFace->Tetra,pkAdjFace->Tetra));
|
| | }
|
| | }
|
| |
|
| | template <class Real>
|
| | DelTetrahedron<Real>* Delaunay3<Real>::GetContainingTetrahedron (int i) const
|
| | {
|
| |
|
| |
|
| |
|
| |
|
| | DelTetrahedron<Real>* pkTetra = *m_kTetrahedron.begin();
|
| | int iTQuantity = (int)m_kTetrahedron.size();
|
| | for (int iT = 0; iT < iTQuantity; iT++)
|
| | {
|
| | int* aiV = pkTetra->V;
|
| |
|
| |
|
| | if (m_pkQuery->ToPlane(i,aiV[1],aiV[2],aiV[3]) > 0)
|
| | {
|
| | pkTetra = pkTetra->A[0];
|
| | if (!pkTetra)
|
| | {
|
| | break;
|
| | }
|
| | continue;
|
| | }
|
| |
|
| |
|
| | if (m_pkQuery->ToPlane(i,aiV[0],aiV[2],aiV[3]) < 0)
|
| | {
|
| | pkTetra = pkTetra->A[1];
|
| | if (!pkTetra)
|
| | {
|
| | break;
|
| | }
|
| | continue;
|
| | }
|
| |
|
| |
|
| | if (m_pkQuery->ToPlane(i,aiV[0],aiV[1],aiV[3]) > 0)
|
| | {
|
| | pkTetra = pkTetra->A[2];
|
| | if (!pkTetra)
|
| | {
|
| | break;
|
| | }
|
| | continue;
|
| | }
|
| |
|
| |
|
| | if (m_pkQuery->ToPlane(i,aiV[0],aiV[1],aiV[2]) < 0)
|
| | {
|
| | pkTetra = pkTetra->A[3];
|
| | if (!pkTetra)
|
| | {
|
| | break;
|
| | }
|
| | continue;
|
| | }
|
| |
|
| | return pkTetra;
|
| | }
|
| |
|
| | assert(false);
|
| | return nullptr;
|
| | }
|
| |
|
| | template <class Real>
|
| | void Delaunay3<Real>::RemoveTetrahedra ()
|
| | {
|
| |
|
| | std::set<DelTetrahedron<Real>*> kRemoveTetra;
|
| | DelTetrahedron<Real>* pkTetra;
|
| | typename std::set<DelTetrahedron<Real>*>::iterator pkTIter =
|
| | m_kTetrahedron.begin();
|
| | for (; pkTIter != m_kTetrahedron.end(); pkTIter++)
|
| | {
|
| | pkTetra = *pkTIter;
|
| | for (int j = 0; j < 4; j++)
|
| | {
|
| | if (IsSupervertex(pkTetra->V[j]))
|
| | {
|
| | kRemoveTetra.insert(pkTetra);
|
| | break;
|
| | }
|
| | }
|
| | }
|
| |
|
| |
|
| | pkTIter = kRemoveTetra.begin();
|
| | for (; pkTIter != kRemoveTetra.end(); pkTIter++)
|
| | {
|
| | pkTetra = *pkTIter;
|
| | for (int j = 0; j < 4; j++)
|
| | {
|
| |
|
| | DelTetrahedron<Real>* pkAdj = pkTetra->A[j];
|
| | if (pkAdj)
|
| | {
|
| | for (int k = 0; k < 4; k++)
|
| | {
|
| | if (pkAdj->A[k] == pkTetra)
|
| | {
|
| | pkAdj->A[k] = nullptr;
|
| | break;
|
| | }
|
| | }
|
| | }
|
| | }
|
| | m_kTetrahedron.erase(pkTetra);
|
| | WM4_DELETE pkTetra;
|
| | }
|
| | }
|
| |
|
| | template <class Real>
|
| | bool Delaunay3<Real>::IsSupervertex (int i) const
|
| | {
|
| | for (int j = 0; j < 4; j++)
|
| | {
|
| | if (i == m_aiSV[j])
|
| | {
|
| | return true;
|
| | }
|
| | }
|
| | return false;
|
| | }
|
| |
|
| | template <class Real>
|
| | bool Delaunay3<Real>::SharesFace (int i, DelTetrahedron<Real>* pkFace,
|
| | DelTetrahedron<Real>* pkAdj)
|
| | {
|
| | int aiF[3], iCount = 0, j;
|
| | for (j = 0; j < 4; j++)
|
| | {
|
| | if (j != i)
|
| | {
|
| | aiF[iCount++] = pkFace->V[j];
|
| | }
|
| | }
|
| |
|
| | for (i = 0; i < 4; i++)
|
| | {
|
| | if (pkAdj->V[i] != aiF[0] &&
|
| | pkAdj->V[i] != aiF[1] &&
|
| | pkAdj->V[i] != aiF[2])
|
| | {
|
| | break;
|
| | }
|
| | }
|
| | if (i == 4)
|
| | {
|
| | return false;
|
| | }
|
| |
|
| | int aiA[3];
|
| | for (j = 0, iCount = 0; j < 4; j++)
|
| | {
|
| | if (j != i)
|
| | {
|
| | aiA[iCount++] = pkAdj->V[j];
|
| | }
|
| | }
|
| |
|
| | if (aiF[0] > aiF[1])
|
| | {
|
| | j = aiF[0];
|
| | aiF[0] = aiF[1];
|
| | aiF[1] = j;
|
| | }
|
| | if (aiF[1] > aiF[2])
|
| | {
|
| | j = aiF[1];
|
| | aiF[1] = aiF[2];
|
| | aiF[2] = j;
|
| | }
|
| | if (aiF[0] > aiF[1])
|
| | {
|
| | j = aiF[0];
|
| | aiF[0] = aiF[1];
|
| | aiF[1] = j;
|
| | }
|
| |
|
| | if (aiA[0] > aiA[1])
|
| | {
|
| | j = aiA[0];
|
| | aiA[0] = aiA[1];
|
| | aiA[1] = j;
|
| | }
|
| | if (aiA[1] > aiA[2])
|
| | {
|
| | j = aiA[1];
|
| | aiA[1] = aiA[2];
|
| | aiA[2] = j;
|
| | }
|
| | if (aiA[0] > aiA[1])
|
| | {
|
| | j = aiA[0];
|
| | aiA[0] = aiA[1];
|
| | aiA[1] = j;
|
| | }
|
| |
|
| | if (aiA[0] != aiF[0] || aiA[1] != aiF[1] || aiA[2] != aiF[2])
|
| | {
|
| | return false;
|
| | }
|
| |
|
| | return true;
|
| | }
|
| |
|
| | template <class Real>
|
| | Delaunay3<Real>::Delaunay3 (const char* acFilename)
|
| | :
|
| | Delaunay<Real>(0,(Real)0.0,false,Query::QT_REAL)
|
| | {
|
| | m_akVertex = nullptr;
|
| | m_akSVertex = nullptr;
|
| | m_pkQuery = nullptr;
|
| | m_aiPath = nullptr;
|
| | bool bLoaded = Load(acFilename);
|
| | assert(bLoaded);
|
| | (void)bLoaded;
|
| | }
|
| |
|
| | template <class Real>
|
| | bool Delaunay3<Real>::Load (const char* acFilename)
|
| | {
|
| | FILE* pkIFile = System::Fopen(acFilename,"rb");
|
| | if (!pkIFile)
|
| | {
|
| | return false;
|
| | }
|
| |
|
| | Delaunay<Real>::Load(pkIFile);
|
| |
|
| | WM4_DELETE m_pkQuery;
|
| | WM4_DELETE[] m_akSVertex;
|
| | WM4_DELETE[] m_aiPath;
|
| | if (m_bOwner)
|
| | {
|
| | WM4_DELETE[] m_akVertex;
|
| | }
|
| |
|
| | m_bOwner = true;
|
| | m_akVertex = WM4_NEW Vector3<Real>[m_iVertexQuantity];
|
| | m_akSVertex = WM4_NEW Vector3<Real>[m_iVertexQuantity+4];
|
| | m_aiPath = WM4_NEW int[m_iSimplexQuantity+1];
|
| |
|
| | System::Read4le(pkIFile,1,&m_iUniqueVertexQuantity);
|
| | System::Read4le(pkIFile,4,m_aiSV);
|
| | System::Read4le(pkIFile,1,&m_iPathLast);
|
| | System::Read4le(pkIFile,1,&m_iLastFaceV0);
|
| | System::Read4le(pkIFile,1,&m_iLastFaceV1);
|
| | System::Read4le(pkIFile,1,&m_iLastFaceV2);
|
| | System::Read4le(pkIFile,1,&m_iLastFaceOpposite);
|
| | System::Read4le(pkIFile,1,&m_iLastFaceOppositeIndex);
|
| | System::Read4le(pkIFile,m_iSimplexQuantity+1,m_aiPath);
|
| |
|
| | size_t uiSize = sizeof(Real);
|
| | int iVQ = 3*m_iVertexQuantity, iSVQ = 3*(m_iVertexQuantity + 4);
|
| | if (uiSize == 4)
|
| | {
|
| | System::Read4le(pkIFile,iVQ,m_akVertex);
|
| | System::Read4le(pkIFile,iSVQ,m_akSVertex);
|
| | System::Read4le(pkIFile,3,(Real*)m_kMin);
|
| | System::Read4le(pkIFile,1,&m_fScale);
|
| | System::Read4le(pkIFile,3,(Real*)m_kLineOrigin);
|
| | System::Read4le(pkIFile,3,(Real*)m_kLineDirection);
|
| | System::Read4le(pkIFile,3,(Real*)m_kPlaneOrigin);
|
| | System::Read4le(pkIFile,3,(Real*)m_akPlaneDirection[0]);
|
| | System::Read4le(pkIFile,3,(Real*)m_akPlaneDirection[1]);
|
| | }
|
| | else
|
| | {
|
| | System::Read8le(pkIFile,iVQ,m_akVertex);
|
| | System::Read8le(pkIFile,iSVQ,m_akSVertex);
|
| | System::Read8le(pkIFile,3,(Real*)m_kMin);
|
| | System::Read8le(pkIFile,1,&m_fScale);
|
| | System::Read8le(pkIFile,3,(Real*)m_kLineOrigin);
|
| | System::Read8le(pkIFile,3,(Real*)m_kLineDirection);
|
| | System::Read8le(pkIFile,3,(Real*)m_kPlaneOrigin);
|
| | System::Read8le(pkIFile,3,(Real*)m_akPlaneDirection[0]);
|
| | System::Read8le(pkIFile,3,(Real*)m_akPlaneDirection[1]);
|
| | }
|
| |
|
| | System::Fclose(pkIFile);
|
| |
|
| | switch (m_eQueryType)
|
| | {
|
| | case Query::QT_INT64:
|
| | m_pkQuery = WM4_NEW Query3Int64<Real>(m_iVertexQuantity,m_akSVertex);
|
| | break;
|
| | case Query::QT_INTEGER:
|
| | m_pkQuery = WM4_NEW Query3TInteger<Real>(m_iVertexQuantity,
|
| | m_akSVertex);
|
| | break;
|
| | case Query::QT_RATIONAL:
|
| | m_pkQuery = WM4_NEW Query3TRational<Real>(m_iVertexQuantity,
|
| | m_akSVertex);
|
| | break;
|
| | case Query::QT_REAL:
|
| | m_pkQuery = WM4_NEW Query3<Real>(m_iVertexQuantity,m_akSVertex);
|
| | break;
|
| | case Query::QT_FILTERED:
|
| | m_pkQuery = WM4_NEW Query3Filtered<Real>(m_iVertexQuantity,
|
| | m_akSVertex,m_fEpsilon);
|
| | break;
|
| | }
|
| |
|
| | return true;
|
| | }
|
| |
|
| | template <class Real>
|
| | bool Delaunay3<Real>::Save (const char* acFilename) const
|
| | {
|
| | FILE* pkOFile = System::Fopen(acFilename,"wb");
|
| | if (!pkOFile)
|
| | {
|
| | return false;
|
| | }
|
| |
|
| | Delaunay<Real>::Save(pkOFile);
|
| |
|
| | System::Write4le(pkOFile,1,&m_iUniqueVertexQuantity);
|
| | System::Write4le(pkOFile,4,m_aiSV);
|
| | System::Write4le(pkOFile,1,&m_iPathLast);
|
| | System::Write4le(pkOFile,1,&m_iLastFaceV0);
|
| | System::Write4le(pkOFile,1,&m_iLastFaceV1);
|
| | System::Write4le(pkOFile,1,&m_iLastFaceV2);
|
| | System::Write4le(pkOFile,1,&m_iLastFaceOpposite);
|
| | System::Write4le(pkOFile,1,&m_iLastFaceOppositeIndex);
|
| | System::Write4le(pkOFile,m_iSimplexQuantity+1,m_aiPath);
|
| |
|
| | size_t uiSize = sizeof(Real);
|
| | int iVQ = 3*m_iVertexQuantity, iSVQ = 3*(m_iVertexQuantity + 4);
|
| | if (uiSize == 4)
|
| | {
|
| | System::Write4le(pkOFile,iVQ,m_akVertex);
|
| | System::Write4le(pkOFile,iSVQ,m_akSVertex);
|
| | System::Write4le(pkOFile,3,(const Real*)m_kMin);
|
| | System::Write4le(pkOFile,1,&m_fScale);
|
| | System::Write4le(pkOFile,3,(const Real*)m_kLineOrigin);
|
| | System::Write4le(pkOFile,3,(const Real*)m_kLineDirection);
|
| | System::Write4le(pkOFile,3,(const Real*)m_kPlaneOrigin);
|
| | System::Write4le(pkOFile,3,(const Real*)m_akPlaneDirection[0]);
|
| | System::Write4le(pkOFile,3,(const Real*)m_akPlaneDirection[1]);
|
| | }
|
| | else
|
| | {
|
| | System::Write8le(pkOFile,iVQ,m_akVertex);
|
| | System::Write8le(pkOFile,iSVQ,m_akSVertex);
|
| | System::Write8le(pkOFile,3,(const Real*)m_kMin);
|
| | System::Write8le(pkOFile,1,&m_fScale);
|
| | System::Write8le(pkOFile,3,(const Real*)m_kLineOrigin);
|
| | System::Write8le(pkOFile,3,(const Real*)m_kLineDirection);
|
| | System::Write8le(pkOFile,3,(const Real*)m_kPlaneOrigin);
|
| | System::Write8le(pkOFile,3,(const Real*)m_akPlaneDirection[0]);
|
| | System::Write8le(pkOFile,3,(const Real*)m_akPlaneDirection[1]);
|
| | }
|
| |
|
| | System::Fclose(pkOFile);
|
| | return true;
|
| | }
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | template WM4_FOUNDATION_ITEM
|
| | class Delaunay3<float>;
|
| |
|
| | template WM4_FOUNDATION_ITEM
|
| | class Delaunay3<double>;
|
| |
|
| | }
|
| |
|