| |
|
|
| |
| |
| |
| |
| |
| |
| |
|
|
| #include "Wm4FoundationPCH.h" |
| #include "Wm4ConvexHull3.h" |
| #include "Wm4Mapper3.h" |
| #include "Wm4Query3Filtered.h" |
| #include "Wm4Query3Int64.h" |
| #include "Wm4Query3TInteger.h" |
| #include "Wm4Query3TRational.h" |
|
|
| namespace Wm4 |
| { |
|
|
| |
| template <class Real> |
| ConvexHull3<Real>::ConvexHull3 (int iVertexQuantity, Vector3<Real>* akVertex, |
| Real fEpsilon, bool bOwner, Query::Type eQueryType) |
| : |
| ConvexHull<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_akPlaneDirection[0] = Vector3<Real>::ZERO; |
| m_akPlaneDirection[1] = Vector3<Real>::ZERO; |
| m_akSVertex = nullptr; |
| m_pkQuery = nullptr; |
|
|
| Mapper3<Real> kMapper(m_iVertexQuantity,m_akVertex,m_fEpsilon); |
| if (kMapper.GetDimension() == 0) |
| { |
| |
| |
| return; |
| } |
|
|
| 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; |
|
|
| int i0 = kMapper.GetExtremeIndex(0); |
| int i1 = kMapper.GetExtremeIndex(1); |
| int i2 = kMapper.GetExtremeIndex(2); |
| int i3 = kMapper.GetExtremeIndex(3); |
|
|
| m_akSVertex = WM4_NEW Vector3<Real>[m_iVertexQuantity]; |
| int i; |
|
|
| if (eQueryType != Query::QT_RATIONAL && eQueryType != Query::QT_FILTERED) |
| { |
| |
| Vector3<Real> kMin = kMapper.GetMin(); |
| Real fScale = ((Real)1.0)/kMapper.GetMaxRange(); |
| for (i = 0; i < m_iVertexQuantity; i++) |
| { |
| m_akSVertex[i] = (m_akVertex[i] - kMin)*fScale; |
| } |
|
|
| Real fExpand; |
| if (eQueryType == Query::QT_INT64) |
| { |
| |
| |
| fExpand = (Real)(1 << 20); |
| m_pkQuery = WM4_NEW Query3Int64<Real>(m_iVertexQuantity, |
| m_akSVertex); |
| } |
| else if (eQueryType == Query::QT_INTEGER) |
| { |
| |
| |
| fExpand = (Real)(1 << 24); |
| 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); |
| } |
|
|
| for (i = 0; i < m_iVertexQuantity; i++) |
| { |
| m_akSVertex[i] *= fExpand; |
| } |
| } |
| else |
| { |
| |
| |
| size_t uiSize = m_iVertexQuantity*sizeof(Vector3<Real>); |
| System::Memcpy(m_akSVertex,uiSize,m_akVertex,uiSize); |
|
|
| 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,m_fEpsilon); |
| } |
| } |
|
|
| Triangle* pkT0; |
| Triangle* pkT1; |
| Triangle* pkT2; |
| Triangle* pkT3; |
|
|
| if (kMapper.GetExtremeCCW()) |
| { |
| pkT0 = WM4_NEW Triangle(i0,i1,i3); |
| pkT1 = WM4_NEW Triangle(i0,i2,i1); |
| pkT2 = WM4_NEW Triangle(i0,i3,i2); |
| pkT3 = WM4_NEW Triangle(i1,i2,i3); |
| pkT0->AttachTo(pkT1,pkT3,pkT2); |
| pkT1->AttachTo(pkT2,pkT3,pkT0); |
| pkT2->AttachTo(pkT0,pkT3,pkT1); |
| pkT3->AttachTo(pkT1,pkT2,pkT0); |
| } |
| else |
| { |
| pkT0 = WM4_NEW Triangle(i0,i3,i1); |
| pkT1 = WM4_NEW Triangle(i0,i1,i2); |
| pkT2 = WM4_NEW Triangle(i0,i2,i3); |
| pkT3 = WM4_NEW Triangle(i1,i3,i2); |
| pkT0->AttachTo(pkT2,pkT3,pkT1); |
| pkT1->AttachTo(pkT0,pkT3,pkT2); |
| pkT2->AttachTo(pkT1,pkT3,pkT0); |
| pkT3->AttachTo(pkT0,pkT2,pkT1); |
| } |
|
|
| m_kHull.clear(); |
| m_kHull.insert(pkT0); |
| m_kHull.insert(pkT1); |
| m_kHull.insert(pkT2); |
| m_kHull.insert(pkT3); |
|
|
| for (i = 0; i < m_iVertexQuantity; i++) |
| { |
| if (!Update(i)) |
| { |
| DeleteHull(); |
| return; |
| } |
| } |
|
|
| ExtractIndices(); |
| } |
| |
| template <class Real> |
| ConvexHull3<Real>::~ConvexHull3 () |
| { |
| if (m_bOwner) |
| { |
| WM4_DELETE[] m_akVertex; |
| } |
| WM4_DELETE[] m_akSVertex; |
| WM4_DELETE m_pkQuery; |
| } |
| |
| template <class Real> |
| const Vector3<Real>& ConvexHull3<Real>::GetLineOrigin () const |
| { |
| return m_kLineOrigin; |
| } |
| |
| template <class Real> |
| const Vector3<Real>& ConvexHull3<Real>::GetLineDirection () const |
| { |
| return m_kLineDirection; |
| } |
| |
| template <class Real> |
| const Vector3<Real>& ConvexHull3<Real>::GetPlaneOrigin () const |
| { |
| return m_kPlaneOrigin; |
| } |
| |
| template <class Real> |
| const Vector3<Real>& ConvexHull3<Real>::GetPlaneDirection (int i) const |
| { |
| assert(0 <= i && i < 2); |
| return m_akPlaneDirection[i]; |
| } |
| |
| template <class Real> |
| ConvexHull1<Real>* ConvexHull3<Real>::GetConvexHull1 () 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 ConvexHull1<Real>(m_iVertexQuantity,afProjection, |
| m_fEpsilon,true,m_eQueryType); |
| } |
| |
| template <class Real> |
| ConvexHull2<Real>* ConvexHull3<Real>::GetConvexHull2 () 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 ConvexHull2<Real>(m_iVertexQuantity,akProjection, |
| m_fEpsilon,true,m_eQueryType); |
| } |
| |
| template <class Real> |
| bool ConvexHull3<Real>::Update (int i) |
| { |
| |
| Triangle* pkVisible = nullptr; |
| Triangle* pkTri; |
| typename std::set<Triangle*>::iterator pkIter; |
| for (pkIter = m_kHull.begin(); pkIter != m_kHull.end(); pkIter++) |
| { |
| pkTri = *pkIter; |
| if (pkTri->GetSign(i,m_pkQuery) > 0) |
| { |
| pkVisible = pkTri; |
| break; |
| } |
| } |
|
|
| if (!pkVisible) |
| { |
| |
| return true; |
| } |
|
|
| |
| std::stack<Triangle*> kVisible; |
| std::map<int,TerminatorData> kTerminator; |
| kVisible.push(pkVisible); |
| pkVisible->OnStack = true; |
| int j, iV0, iV1; |
| while (!kVisible.empty()) |
| { |
| pkTri = kVisible.top(); |
| kVisible.pop(); |
| pkTri->OnStack = false; |
| for (j = 0; j < 3; j++) |
| { |
| Triangle* pkAdj = pkTri->A[j]; |
| if (pkAdj) |
| { |
| |
| int iNullIndex = pkTri->DetachFrom(j,pkAdj); |
|
|
| if (pkAdj->GetSign(i,m_pkQuery) > 0) |
| { |
| if (!pkAdj->OnStack) |
| { |
| |
| kVisible.push(pkAdj); |
| pkAdj->OnStack = true; |
| } |
| } |
| else |
| { |
| |
| iV0 = pkTri->V[j]; |
| iV1 = pkTri->V[(j+1)%3]; |
| kTerminator[iV0] = TerminatorData(iV0,iV1,iNullIndex, |
| pkAdj); |
| } |
| } |
| } |
| m_kHull.erase(pkTri); |
| WM4_DELETE pkTri; |
| } |
|
|
| |
| |
| int iSize = (int)kTerminator.size(); |
| assert(iSize >= 3); |
| typename std::map<int,TerminatorData>::iterator pkEdge = |
| kTerminator.begin(); |
| iV0 = pkEdge->second.V[0]; |
| iV1 = pkEdge->second.V[1]; |
| pkTri = WM4_NEW Triangle(i,iV0,iV1); |
| m_kHull.insert(pkTri); |
|
|
| |
| int iSaveV0 = pkEdge->second.V[0]; |
| Triangle* pkSaveTri = pkTri; |
|
|
| |
| pkTri->A[1] = pkEdge->second.Tri; |
| pkEdge->second.Tri->A[pkEdge->second.NullIndex] = pkTri; |
| for (j = 1; j < iSize; j++) |
| { |
| pkEdge = kTerminator.find(iV1); |
| assert(pkEdge != kTerminator.end()); |
| iV0 = iV1; |
| iV1 = pkEdge->second.V[1]; |
| Triangle* pkNext = WM4_NEW Triangle(i,iV0,iV1); |
| m_kHull.insert(pkNext); |
|
|
| |
| pkNext->A[1] = pkEdge->second.Tri; |
| pkEdge->second.Tri->A[pkEdge->second.NullIndex] = pkNext; |
|
|
| |
| pkNext->A[0] = pkTri; |
| pkTri->A[2] = pkNext; |
|
|
| pkTri = pkNext; |
| } |
| assert(iV1 == iSaveV0); |
| (void)iSaveV0; |
|
|
| |
| pkSaveTri->A[0] = pkTri; |
| pkTri->A[2] = pkSaveTri; |
|
|
| return true; |
| } |
| |
| template <class Real> |
| void ConvexHull3<Real>::ExtractIndices () |
| { |
| int iTQuantity = (int)m_kHull.size(); |
| m_iSimplexQuantity = iTQuantity; |
| m_aiIndex = WM4_NEW int[3*m_iSimplexQuantity]; |
|
|
| typename std::set<Triangle*>::iterator pkIter; |
| int i = 0; |
| for (pkIter = m_kHull.begin(); pkIter != m_kHull.end(); pkIter++) |
| { |
| Triangle* pkTri = *pkIter; |
| for (int j = 0; j < 3; j++) |
| { |
| m_aiIndex[i++] = pkTri->V[j]; |
| } |
| WM4_DELETE pkTri; |
| } |
| m_kHull.clear(); |
| } |
| |
| template <class Real> |
| void ConvexHull3<Real>::DeleteHull () |
| { |
| typename std::set<Triangle*>::iterator pkIter; |
| for (pkIter = m_kHull.begin(); pkIter != m_kHull.end(); pkIter++) |
| { |
| Triangle* pkTri = *pkIter; |
| WM4_DELETE pkTri; |
| } |
| m_kHull.clear(); |
| } |
| |
| template <class Real> |
| ConvexHull3<Real>::ConvexHull3 (const char* acFilename) |
| : |
| ConvexHull<Real>(0,(Real)0.0,false,Query::QT_REAL) |
| { |
| m_akVertex = nullptr; |
| m_akSVertex = nullptr; |
| m_pkQuery = nullptr; |
| bool bLoaded = Load(acFilename); |
| assert(bLoaded); |
| (void)bLoaded; |
| } |
| |
| template <class Real> |
| bool ConvexHull3<Real>::Load (const char* acFilename) |
| { |
| FILE* pkIFile = System::Fopen(acFilename,"rb"); |
| if (!pkIFile) |
| { |
| return false; |
| } |
|
|
| ConvexHull<Real>::Load(pkIFile); |
|
|
| WM4_DELETE m_pkQuery; |
| WM4_DELETE[] m_akSVertex; |
| 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]; |
|
|
| size_t uiSize = sizeof(Real); |
| int iVQ = 3*m_iVertexQuantity; |
| if (uiSize == 4) |
| { |
| System::Read4le(pkIFile,iVQ,m_akVertex); |
| System::Read4le(pkIFile,iVQ,m_akSVertex); |
| 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,iVQ,m_akSVertex); |
| 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 ConvexHull3<Real>::Save (const char* acFilename) const |
| { |
| FILE* pkOFile = System::Fopen(acFilename,"wb"); |
| if (!pkOFile) |
| { |
| return false; |
| } |
|
|
| ConvexHull<Real>::Save(pkOFile); |
|
|
| size_t uiSize = sizeof(Real); |
| int iVQ = 3*m_iVertexQuantity; |
| if (uiSize == 4) |
| { |
| System::Write4le(pkOFile,iVQ,m_akVertex); |
| System::Write4le(pkOFile,iVQ,m_akSVertex); |
| 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,iVQ,m_akSVertex); |
| 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 <class Real> |
| ConvexHull3<Real>::Triangle::Triangle (int iV0, int iV1, int iV2) |
| { |
| V[0] = iV0; |
| V[1] = iV1; |
| V[2] = iV2; |
| A[0] = nullptr; |
| A[1] = nullptr; |
| A[2] = nullptr; |
| Sign = 0; |
| Time = -1; |
| OnStack = false; |
| } |
| |
| template <class Real> |
| int ConvexHull3<Real>::Triangle::GetSign (int i, const Query3<Real>* pkQuery) |
| { |
| if (i != Time) |
| { |
| Time = i; |
| Sign = pkQuery->ToPlane(i,V[0],V[1],V[2]); |
| } |
|
|
| return Sign; |
| } |
| |
| template <class Real> |
| void ConvexHull3<Real>::Triangle::AttachTo (Triangle* pkAdj0, |
| Triangle* pkAdj1, Triangle* pkAdj2) |
| { |
| |
| A[0] = pkAdj0; |
| A[1] = pkAdj1; |
| A[2] = pkAdj2; |
| } |
| |
| template <class Real> |
| int ConvexHull3<Real>::Triangle::DetachFrom (int iAdj, Triangle* pkAdj) |
| { |
| assert(0 <= iAdj && iAdj < 3 && A[iAdj] == pkAdj); |
| A[iAdj] = nullptr; |
| for (int i = 0; i < 3; i++) |
| { |
| if (pkAdj->A[i] == this) |
| { |
| pkAdj->A[i] = nullptr; |
| return i; |
| } |
| } |
| return -1; |
| } |
| |
|
|
| |
| |
| |
| template WM4_FOUNDATION_ITEM |
| class ConvexHull3<float>; |
|
|
| template WM4_FOUNDATION_ITEM |
| class ConvexHull3<double>; |
| |
| } |
|
|