www.pudn.com > cad3d.zip > Face.cpp
// TopFace.cpp: implementation of the CFace class.
//
//////////////////////////////////////////////////////////////////////
#include "Topology/stdafx.h"
#include "Topology/Face.h"
#include "htf.h"
#include "3DMath/3DVector.h"
#include "Topology/IVertex.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CFace::CFace(ISurfTopology* pTopology)
: m_pTopology(pTopology)
{
}
CFace::~CFace()
{
}
void CFace::SetTopology(ISurfTopology* pSurfTop)
{
m_pTopology = pSurfTop;
}
top_int CFace::GetRelId(top_int nBase, top_int nOffset) const
{
return (nBase + nOffset) % GetVerticesCount();
}
top_int CFace::GetPrevId(top_int nBase) const
{
return nBase == 0 ? GetVerticesCount() - 1 : nBase - 1;
}
top_int CFace::GetVerticesCount() const
{
return m_vertices.size();
}
void CFace::SetVerticesCount(top_int nCount)
{
m_vertices.resize(nCount);
m_links.resize(nCount);
}
top_int CFace::GetLinkIdFast(top_int nId0, top_int nId1) const
{
top_int nLastId = GetVerticesCount() - 1;
top_int nLinkId = htf::max(nId0, nId1) == nLastId ? nLastId : htf::min(nId0, nId1);
return nLinkId;
}
top_int CFace::GetLinkId(top_int nId0, top_int nId1) const
{
top_int nVerts = GetVerticesCount();
//check if the ids are in the valid range
if ( nId0 < 0 || nId0 >= nVerts || nId1 < 0 || nId1 >= nVerts ||
GetRelId(nId1,1) != nId0 ) //check if the links are oriented in the same directions
{
return -1;
}
//check if the (valid) ids lie both on one and the same edge
top_int nLastId = nVerts - 1;
top_int nDiff = abs(nId0 - nId1);
if ( nDiff == 1 )
return htf::min(nId0, nId1);
else if ( nDiff == nLastId)
return nLastId;
return -1;
}
top_int CFace::GetLinkId(IVertex* pVer0, IVertex* pVer1) const
{
top_int nId0 = GetVertexId(pVer0);
top_int nId1 = GetVertexId(pVer1);
return GetLinkId(nId0, nId1);
}
top_int CFace::GetLinkId(IFace* pFace) const
{
top_int nCnt = GetVerticesCount();
for (top_int i = 0; i < nCnt; ++i)
{
if ( m_links[i] == pFace )
{
return i;
}
}
return -1;
}
bool CFace::IsLinkedTo(IFace* pFace) const
{
return GetLinkId(pFace) != -1;
}
//vertex handling
void CFace::SetVertex(top_int i, IVertex* pVer)
{
m_vertices[i] = pVer;
}
top_int CFace::GetVertexId(const IVertex* pVer) const
{
top_int nCnt = GetVerticesCount();
for (top_int i = 0; i < nCnt; i++)
{
if ( m_vertices[i] == pVer )
return i;
}
return -1;
}
bool CFace::HasVertex(IVertex* pVer) const
{
return GetVertexId(pVer) != -1;
}
void CFace::RemoveVertex(IVertex* pVer)
{
top_int nId = GetVertexId(pVer);
CHECK( nId != -1);
top_int nPrevId = GetPrevId(nId);
m_vertices.erase( m_vertices.begin() + nId );
if (m_links[nId] != NULL)
{//clear the link between nId .. nId + 1
m_links[nId].ClearLinks();
}
if (m_links[nPrevId] != NULL)
{//clear the link between nId - 1.. nId
m_links[nPrevId].ClearLinks();
}
m_links.erase(m_links.begin() + nId);//erases the link
int nCnt = GetVerticesCount();
for (int i = nId; i < nCnt; ++i)
{//repair damaged neighbours links
if (m_links[i] != NULL)
{
m_links[i].GetNbLinkRef().DecNbId();
}
}
}
bool CFace::IsValid() const
{
return GetVerticesCount() >= 3;
}
void CFace::ClearLinks()
{
top_int nCnt = GetVerticesCount();
for (top_int i = 0; i < nCnt; ++i)
{
if ( m_links[i] != NULL )
{
m_links[i].ClearLinks();
}
}
}
IVertex* CFace::GetVertexPtr(top_int i)
{
return m_vertices[i];
}
const IVertex* CFace::GetVertexPtr(top_int i) const
{
return m_vertices[i];
}
IVertex& CFace::GetVertexRef(top_int i)
{
return *m_vertices[i];
}
const IVertex& CFace::GetVertexRef(top_int i) const
{
return *m_vertices[i];
}
//links to other faces handling (edges)
void CFace::SetLink(top_int i, const IFaceLink& rLink)
{
m_links[i] = rLink;
}
IFaceLink& CFace::GetLinkRef(top_int i)
{
return m_links[i];
}
const IFaceLink& CFace::GetLinkRef(top_int i) const
{
return m_links[i];
}
//orientation handling
void CFace::Reverse()
{
ClearLinks();
top_int nVerts = GetVerticesCount();
top_int nHalfVerts = nVerts/2;
for (top_int i = 0; i < nHalfVerts; ++i)
{
std::swap(m_vertices[i], m_vertices[nVerts - i - 1]);
}
}
void CFace::AddToNormals()
{
CIVertexVector::iterator i = m_vertices.begin();
CIVertexVector::iterator iEnd = m_vertices.end();
for (; i != iEnd; ++i)
{
static_cast(**i).Normalize();
}
C3DVector first( static_cast(*m_vertices.front()) - static_cast(*m_vertices.back()) );
C3DVector prev ( first);
for (i = m_vertices.begin(); i != iEnd; ++i)
{
CIVertexVector::iterator ni = i;
C3DVector next(++ni != iEnd ? static_cast(**ni) - static_cast(**i) : first );
(**i).GetNormalRef() += (prev^next);
prev = next;
}
}
//sets the proper vertex class
//iterate through the faces around the vertex, until return back to this(inner face)
//or the chain appears broken - the vertex is on the border
const IVertex& CFace::ClassifyVertex(top_int i) const
{
const IFace* pNextFace = this;
top_int nNextVerId = i;
for (;;)
{
top_int nLinkId = pNextFace->GetPrevId(nNextVerId);
if (pNextFace->GetLinkRef(nLinkId) != NULL)
{ //move to the next corner face
nNextVerId = pNextFace->GetLinkRef(nLinkId).GetNbId();
pNextFace = pNextFace->GetLinkRef(nLinkId);
}
else
{ //no more corner faces in this direction - so the vertex is boundary or corner
if ( pNextFace == this && GetLinkRef(i) == NULL )
{//the chain is broken at the first face (this) and there are no other faces in the opposite direction
m_vertices[i]->SetState( IVertex::CORNER);
}
else
{//at least two faces share this corner - so (maybe) this is boundary
m_vertices[i]->SetState( IVertex::BOUNDARY);
}
return *m_vertices[i];
}
if (pNextFace == this)
{//back at the first face - so this vertex is inner
m_vertices[i]->SetState(IVertex::INNER);
return *m_vertices[i];
}
}
}
void CFace::ClassifyVertices() const
{
top_int nVertsCount = GetVerticesCount();
for (top_int i = 0; i < nVertsCount; ++i)
{
ClassifyVertex(i);
}
}