| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #include "Wm4FoundationPCH.h" |
| | #include "Wm4ConvexHull2.h" |
| | #include "Wm4Mapper2.h" |
| | #include "Wm4Query2Filtered.h" |
| | #include "Wm4Query2Int64.h" |
| | #include "Wm4Query2TInteger.h" |
| | #include "Wm4Query2TRational.h" |
| |
|
| | namespace Wm4 |
| | { |
| |
|
| | |
| | template <class Real> |
| | ConvexHull2<Real>::ConvexHull2 (int iVertexQuantity, Vector2<Real>* akVertex, |
| | Real fEpsilon, bool bOwner, Query::Type eQueryType) |
| | : |
| | ConvexHull<Real>(iVertexQuantity,fEpsilon,bOwner,eQueryType), |
| | m_kLineOrigin(Vector2<Real>::ZERO), |
| | m_kLineDirection(Vector2<Real>::ZERO) |
| | { |
| | assert(akVertex); |
| | m_akVertex = akVertex; |
| | m_akSVertex = nullptr; |
| | m_pkQuery = nullptr; |
| |
|
| | Mapper2<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; |
| | } |
| |
|
| | m_iDimension = 2; |
| |
|
| | int i0 = kMapper.GetExtremeIndex(0); |
| | int i1 = kMapper.GetExtremeIndex(1); |
| | int i2 = kMapper.GetExtremeIndex(2); |
| |
|
| | m_akSVertex = WM4_NEW Vector2<Real>[m_iVertexQuantity]; |
| | int i; |
| |
|
| | if (eQueryType != Query::QT_RATIONAL && eQueryType != Query::QT_FILTERED) |
| | { |
| | |
| | Vector2<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 Query2Int64<Real>(m_iVertexQuantity, |
| | m_akSVertex); |
| | } |
| | else if (eQueryType == Query::QT_INTEGER) |
| | { |
| | |
| | |
| | fExpand = (Real)(1 << 24); |
| | m_pkQuery = WM4_NEW Query2TInteger<Real>(m_iVertexQuantity, |
| | m_akSVertex); |
| | } |
| | else |
| | { |
| | |
| | fExpand = (Real)1.0; |
| | m_pkQuery = WM4_NEW Query2<Real>(m_iVertexQuantity,m_akSVertex); |
| | } |
| |
|
| | for (i = 0; i < m_iVertexQuantity; i++) |
| | { |
| | m_akSVertex[i] *= fExpand; |
| | } |
| | } |
| | else |
| | { |
| | |
| | |
| | size_t uiSize = m_iVertexQuantity*sizeof(Vector2<Real>); |
| | System::Memcpy(m_akSVertex,uiSize,m_akVertex,uiSize); |
| |
|
| | if (eQueryType == Query::QT_RATIONAL) |
| | { |
| | m_pkQuery = WM4_NEW Query2TRational<Real>(m_iVertexQuantity, |
| | m_akSVertex); |
| | } |
| | else |
| | { |
| | m_pkQuery = WM4_NEW Query2Filtered<Real>(m_iVertexQuantity, |
| | m_akSVertex,m_fEpsilon); |
| | } |
| | } |
| |
|
| | Edge* pkE0; |
| | Edge* pkE1; |
| | Edge* pkE2; |
| |
|
| | if (kMapper.GetExtremeCCW()) |
| | { |
| | pkE0 = WM4_NEW Edge(i0,i1); |
| | pkE1 = WM4_NEW Edge(i1,i2); |
| | pkE2 = WM4_NEW Edge(i2,i0); |
| | } |
| | else |
| | { |
| | pkE0 = WM4_NEW Edge(i0,i2); |
| | pkE1 = WM4_NEW Edge(i2,i1); |
| | pkE2 = WM4_NEW Edge(i1,i0); |
| | } |
| |
|
| | pkE0->Insert(pkE2,pkE1); |
| | pkE1->Insert(pkE0,pkE2); |
| | pkE2->Insert(pkE1,pkE0); |
| |
|
| | Edge* pkHull = pkE0; |
| | for (i = 0; i < m_iVertexQuantity; i++) |
| | { |
| | if (!Update(pkHull,i)) |
| | { |
| | pkHull->DeleteAll(); |
| | return; |
| | } |
| | } |
| |
|
| | pkHull->GetIndices(m_iSimplexQuantity,m_aiIndex); |
| | pkHull->DeleteAll(); |
| | } |
| | |
| | template <class Real> |
| | ConvexHull2<Real>::~ConvexHull2 () |
| | { |
| | if (m_bOwner) |
| | { |
| | WM4_DELETE[] m_akVertex; |
| | } |
| | WM4_DELETE[] m_akSVertex; |
| | WM4_DELETE m_pkQuery; |
| | } |
| | |
| | template <class Real> |
| | const Vector2<Real>& ConvexHull2<Real>::GetLineOrigin () const |
| | { |
| | return m_kLineOrigin; |
| | } |
| | |
| | template <class Real> |
| | const Vector2<Real>& ConvexHull2<Real>::GetLineDirection () const |
| | { |
| | return m_kLineDirection; |
| | } |
| | |
| | template <class Real> |
| | ConvexHull1<Real>* ConvexHull2<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++) |
| | { |
| | Vector2<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> |
| | bool ConvexHull2<Real>::Update (Edge*& rpkHull, int i) |
| | { |
| | |
| | Edge* pkVisible = nullptr; |
| | Edge* pkCurrent = rpkHull; |
| | do |
| | { |
| | if (pkCurrent->GetSign(i,m_pkQuery) > 0) |
| | { |
| | pkVisible = pkCurrent; |
| | break; |
| | } |
| |
|
| | pkCurrent = pkCurrent->A[1]; |
| | } |
| | while (pkCurrent != rpkHull); |
| |
|
| | if (!pkVisible) |
| | { |
| | |
| | return true; |
| | } |
| |
|
| | |
| | Edge* pkAdj0 = pkVisible->A[0]; |
| | assert(pkAdj0); |
| | if (!pkAdj0) |
| | { |
| | return false; |
| | } |
| |
|
| | Edge* pkAdj1 = pkVisible->A[1]; |
| | assert(pkAdj1); |
| | if (!pkAdj1) |
| | { |
| | return false; |
| | } |
| |
|
| | pkVisible->DeleteSelf(); |
| |
|
| | while (pkAdj0->GetSign(i,m_pkQuery) > 0) |
| | { |
| | rpkHull = pkAdj0; |
| | pkAdj0 = pkAdj0->A[0]; |
| | assert(pkAdj0); |
| | if (!pkAdj0) |
| | { |
| | return false; |
| | } |
| |
|
| | pkAdj0->A[1]->DeleteSelf(); |
| | } |
| |
|
| | while (pkAdj1->GetSign(i,m_pkQuery) > 0) |
| | { |
| | rpkHull = pkAdj1; |
| | pkAdj1 = pkAdj1->A[1]; |
| | assert(pkAdj1); |
| | if (!pkAdj1) |
| | { |
| | return false; |
| | } |
| |
|
| | pkAdj1->A[0]->DeleteSelf(); |
| | } |
| |
|
| | |
| | |
| | Edge* pkEdge0 = WM4_NEW Edge(pkAdj0->V[1],i); |
| | Edge* pkEdge1 = WM4_NEW Edge(i,pkAdj1->V[0]); |
| | pkEdge0->Insert(pkAdj0,pkEdge1); |
| | pkEdge1->Insert(pkEdge0,pkAdj1); |
| | rpkHull = pkEdge0; |
| |
|
| | return true; |
| | } |
| | |
| | template <class Real> |
| | ConvexHull2<Real>::ConvexHull2 (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 ConvexHull2<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 Vector2<Real>[m_iVertexQuantity]; |
| | m_akSVertex = WM4_NEW Vector2<Real>[m_iVertexQuantity]; |
| |
|
| | size_t uiSize = sizeof(Real); |
| | int iVQ = 2*m_iVertexQuantity; |
| | if (uiSize == 4) |
| | { |
| | System::Read4le(pkIFile,iVQ,m_akVertex); |
| | System::Read4le(pkIFile,iVQ,m_akSVertex); |
| | System::Read4le(pkIFile,2,(Real*)m_kLineOrigin); |
| | System::Read4le(pkIFile,2,(Real*)m_kLineDirection); |
| | } |
| | else |
| | { |
| | System::Read8le(pkIFile,iVQ,m_akVertex); |
| | System::Read8le(pkIFile,iVQ,m_akSVertex); |
| | System::Read8le(pkIFile,2,(Real*)m_kLineOrigin); |
| | System::Read8le(pkIFile,2,(Real*)m_kLineDirection); |
| | } |
| |
|
| | System::Fclose(pkIFile); |
| |
|
| | switch (m_eQueryType) |
| | { |
| | case Query::QT_INT64: |
| | m_pkQuery = WM4_NEW Query2Int64<Real>(m_iVertexQuantity,m_akSVertex); |
| | break; |
| | case Query::QT_INTEGER: |
| | m_pkQuery = WM4_NEW Query2TInteger<Real>(m_iVertexQuantity, |
| | m_akSVertex); |
| | break; |
| | case Query::QT_RATIONAL: |
| | m_pkQuery = WM4_NEW Query2TRational<Real>(m_iVertexQuantity, |
| | m_akSVertex); |
| | break; |
| | case Query::QT_REAL: |
| | m_pkQuery = WM4_NEW Query2<Real>(m_iVertexQuantity,m_akSVertex); |
| | break; |
| | case Query::QT_FILTERED: |
| | m_pkQuery = WM4_NEW Query2Filtered<Real>(m_iVertexQuantity, |
| | m_akSVertex,m_fEpsilon); |
| | break; |
| | } |
| |
|
| | return true; |
| | } |
| | |
| | template <class Real> |
| | bool ConvexHull2<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 = 2*m_iVertexQuantity; |
| | if (uiSize == 4) |
| | { |
| | System::Write4le(pkOFile,iVQ,m_akVertex); |
| | System::Write4le(pkOFile,iVQ,m_akSVertex); |
| | System::Write4le(pkOFile,2,(const Real*)m_kLineOrigin); |
| | System::Write4le(pkOFile,2,(const Real*)m_kLineDirection); |
| | } |
| | else |
| | { |
| | System::Write8le(pkOFile,iVQ,m_akVertex); |
| | System::Write8le(pkOFile,iVQ,m_akSVertex); |
| | System::Write8le(pkOFile,2,(const Real*)m_kLineOrigin); |
| | System::Write8le(pkOFile,2,(const Real*)m_kLineDirection); |
| | } |
| |
|
| | System::Fclose(pkOFile); |
| | return true; |
| | } |
| | |
| |
|
| | |
| | |
| | |
| | template <class Real> |
| | ConvexHull2<Real>::Edge::Edge (int iV0, int iV1) |
| | { |
| | V[0] = iV0; |
| | V[1] = iV1; |
| | A[0] = nullptr; |
| | A[1] = nullptr; |
| | Sign = 0; |
| | Time = -1; |
| | } |
| | |
| | template <class Real> |
| | int ConvexHull2<Real>::Edge::GetSign (int i, const Query2<Real>* pkQuery) |
| | { |
| | if (i != Time) |
| | { |
| | Time = i; |
| | Sign = pkQuery->ToLine(i,V[0],V[1]); |
| | } |
| |
|
| | return Sign; |
| | } |
| | |
| | template <class Real> |
| | void ConvexHull2<Real>::Edge::Insert (Edge* pkAdj0, Edge* pkAdj1) |
| | { |
| | pkAdj0->A[1] = this; |
| | pkAdj1->A[0] = this; |
| | A[0] = pkAdj0; |
| | A[1] = pkAdj1; |
| | } |
| | |
| | template <class Real> |
| | void ConvexHull2<Real>::Edge::DeleteSelf () |
| | { |
| | if (A[0]) |
| | { |
| | A[0]->A[1] = nullptr; |
| | } |
| |
|
| | if (A[1]) |
| | { |
| | A[1]->A[0] = nullptr; |
| | } |
| |
|
| | WM4_DELETE this; |
| | } |
| | |
| | template <class Real> |
| | void ConvexHull2<Real>::Edge::DeleteAll () |
| | { |
| | Edge* pkAdj = A[1]; |
| | while (pkAdj && pkAdj != this) |
| | { |
| | Edge* pkSave = pkAdj->A[1]; |
| | WM4_DELETE pkAdj; |
| | pkAdj = pkSave; |
| | } |
| |
|
| | assert(pkAdj == this); |
| | WM4_DELETE this; |
| | } |
| | |
| | template <class Real> |
| | void ConvexHull2<Real>::Edge::GetIndices (int& riHQuantity, int*& raiHIndex) |
| | { |
| | |
| | riHQuantity = 0; |
| | Edge* pkCurrent = this; |
| | do |
| | { |
| | riHQuantity++; |
| | pkCurrent = pkCurrent->A[1]; |
| | } |
| | while (pkCurrent != this); |
| | raiHIndex = WM4_NEW int[riHQuantity]; |
| |
|
| | |
| | riHQuantity = 0; |
| | pkCurrent = this; |
| | do |
| | { |
| | raiHIndex[riHQuantity++] = pkCurrent->V[0]; |
| | pkCurrent = pkCurrent->A[1]; |
| | } |
| | while (pkCurrent != this); |
| | } |
| | |
| |
|
| | |
| | |
| | |
| | template WM4_FOUNDATION_ITEM |
| | class ConvexHull2<float>; |
| |
|
| | template WM4_FOUNDATION_ITEM |
| | class ConvexHull2<double>; |
| | |
| | } |
| |
|