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);				
	}
}