//********************************************
// Face3d.cpp
//********************************************
// class CFace3d
//********************************************
// alliez@usc.edu
// Created : 10/12/97
// Modified : 09/02/98
//********************************************
#include "stdafx.h"
#include "Base3d.h"
#include "Face3d.h"
//////////////////////////////////////////////
// CONSTRUCTORS
//////////////////////////////////////////////
//********************************************
// Constructor
//********************************************
CFace3d::CFace3d()
{
for(int i=0;i<3;i++)
m_pFace[i] = NULL;
for(i=0;i<6;i++)
m_pVertex[i] = NULL;
m_Flag = 0;
}
//********************************************
// Constructor
//********************************************
CFace3d::CFace3d(CVertex3d *pVertex1,
CVertex3d *pVertex2,
CVertex3d *pVertex3)
{
// Face
for(int i=0;i<3;i++)
m_pFace[i] = NULL;
// Vertices
Set(pVertex1,pVertex2,pVertex3);
for(i=3;i<6;i++)
m_pVertex[i] = NULL;
// Normal
m_Normal.Set(0.0f,0.0f,0.0f);
m_Flag = 0;
}
//********************************************
// Constructor
//********************************************
CFace3d::CFace3d(CFace3d *pFace)
{
Set(pFace);
m_Flag = 0;
}
//////////////////////////////////////////////
// DATAS
//////////////////////////////////////////////
//********************************************
// Set
//********************************************
inline void CFace3d::Clear()
{
for(int i=0;i<3;i++)
m_pFace[i] = NULL;
for(i=0;i<6;i++)
m_pVertex[i] = NULL;
m_Flag = 0;
}
//********************************************
// Equal
//********************************************
int CFace3d::Equal(CFace3d *pFace)
{
return (HasVertex(pFace->v1()) &&
HasVertex(pFace->v2()) &&
HasVertex(pFace->v3()));
}
//********************************************
// IsValid
//********************************************
int CFace3d::IsValid()
{
int success = 1;
success &= (m_pFace[0] != this);
success &= (m_pFace[1] != this);
success &= (m_pFace[2] != this);
// Different neighbors, if there are
success &= ((m_pFace[0] != m_pFace[1]) || (m_pFace[0] == NULL));
success &= ((m_pFace[0] != m_pFace[2]) || (m_pFace[0] == NULL));
success &= ((m_pFace[1] != m_pFace[2]) || (m_pFace[1] == NULL));
#ifdef _DEBUG
if(!success)
{
TRACE("Face [%x] has the same neighbors\n",this);
}
#endif
// Different vertices
success &= (m_pVertex[0] != m_pVertex[1]);
success &= (m_pVertex[1] != m_pVertex[2]);
success &= (m_pVertex[0] != m_pVertex[2]);
/*
#ifdef _DEBUG
if(NbFaceNeighbor() != 3)
{
TRACE("Face [%x] has %d neighbors\n",NbFaceNeighbor());
}
#endif
*/
#ifdef _DEBUG
if(!success)
{
TRACE("Face [%x] has the same vertices \n",this);
}
#endif
// Reciproc. neighboring
for(int i=0;i<3;i++)
{
CFace3d *pFace = f(i);
if(pFace != NULL)
{
if(!pFace->HasNeighbor(this))
{
TRACE("Face [%x] has invalid reciproc. neighboring \n",this);
success = 0;
}
}
}
return success;
}
//********************************************
// Set
//********************************************
inline void CFace3d::Set(CVertex3d *pVertex1,
CVertex3d *pVertex2,
CVertex3d *pVertex3)
{
m_pVertex[0] = pVertex1;
m_pVertex[1] = pVertex2;
m_pVertex[2] = pVertex3;
}
//********************************************
// Set
//********************************************
inline void CFace3d::Set(CFace3d *pFace1,
CFace3d *pFace2,
CFace3d *pFace3)
{
m_pFace[0] = pFace1;
m_pFace[1] = pFace2;
m_pFace[2] = pFace3;
}
//********************************************
// Set
//********************************************
inline void CFace3d::Set(CVertex3d *pVertex1,
CVertex3d *pVertex2,
CVertex3d *pVertex3,
CFace3d *pFace1,
CFace3d *pFace2,
CFace3d *pFace3)
{
m_pVertex[0] = pVertex1;
m_pVertex[1] = pVertex2;
m_pVertex[2] = pVertex3;
m_pFace[0] = pFace1;
m_pFace[1] = pFace2;
m_pFace[2] = pFace3;
}
//********************************************
// Set
//********************************************
inline void CFace3d::Set(CFace3d *pFace)
{
Set(pFace->v1(),pFace->v2(),pFace->v3());
Set(pFace->f1(),pFace->f2(),pFace->f3());
}
//********************************************
// SetFlagOnVerticesIfDiff
//********************************************
void CFace3d::SetFlagOnVerticesIfDiff(int FlagDiff,
int flag)
{
for(int i=0;i<3;i++)
{
CVertex3d *pVertex = v(i);
if(pVertex->GetFlag() != FlagDiff)
pVertex->SetFlag((char)flag);
}
}
//********************************************
// IndexFrom
//********************************************
int CFace3d::IndexFrom(CVertex3d *pVertex)
{
ASSERT(HasVertex(pVertex));
for(int i=0;i<3;i++)
if(m_pVertex[i]==pVertex)
return i;
return 0;
}
//********************************************
// GetCenter
// Allocate on the heap
//********************************************
CVertex3d* CFace3d::GetCenter(void)
{
CVertex3d* pVertex = new CVertex3d;
pVertex->x((m_pVertex[0]->x()+m_pVertex[1]->x()+m_pVertex[2]->x())/3.0f);
pVertex->y((m_pVertex[0]->y()+m_pVertex[1]->y()+m_pVertex[2]->y())/3.0f);
pVertex->z((m_pVertex[0]->z()+m_pVertex[1]->z()+m_pVertex[2]->z())/3.0f);
return pVertex;
}
//********************************************
// FindNearestVertex
//********************************************
CVertex3d *CFace3d::FindNearestVertex(CVertex3d *pVertex)
{
CVertex3d *pV = v(0);
double MinDistance = DistanceSquare(pVertex,v(0));
for(int i=1;i<3;i++)
{
double tmp = DistanceSquare(pVertex,v(i));
if(tmp < MinDistance)
{
MinDistance = tmp;
pV = v(i);
}
}
return pV;
}
//********************************************
// ColorSharpEdge
//********************************************
void CFace3d::ColorSharpEdge(double threshold,
CColor &color)
{
for(int i=0;i<3;i++)
if(SinAngle(this,f(i)) >= threshold)
{
v(i)->SetColor(color);
v((i+1)%3)->SetColor(color);
}
}
//********************************************
// ColorSharpEdge
//********************************************
int CFace3d::GetSharpEdge(double threshold,
int *SharpEdge)
{
int success = 0;
for(int i=0;i<3;i++)
if(f(i) != NULL)
if(SinAngle(this,f(i)) >= threshold)
{
SharpEdge[i]=1;
success = 1;
}
return success;
}
//********************************************
// HasSharpEdge
//********************************************
int CFace3d::HasSharpEdge(double threshold)
{
for(int i=0;i<3;i++)
{
double sinus = SinAngle(this,f(i));
//TRACE("SinAngle : %g\n",sinus);
if(sinus >= threshold)
return 1;
}
return 0;
}
//////////////////////////////////////////////
// DATA ACCESS
//////////////////////////////////////////////
//********************************************
// GetType
//********************************************
int CFace3d::GetType()
{
return TYPE_FACE3D;
}
//********************************************
// NbVertex
//********************************************
int CFace3d::NbVertex()
{
int NbVertex = 0;
for(int i=0;i<6;i++)
NbVertex += (m_pVertex[i] != NULL);
return NbVertex;
}
//********************************************
// NbFaceNeighbor
//********************************************
int CFace3d::NbFaceNeighbor()
{
int NbFace = 0;
NbFace += (m_pFace[0] != NULL);
NbFace += (m_pFace[1] != NULL);
NbFace += (m_pFace[2] != NULL);
return NbFace;
}
//////////////////////////////////////////////
// PROCESSING
//////////////////////////////////////////////
//********************************************
// CalculateNormal
//********************************************
void CFace3d::CalculateNormal()
{
CVector3d u(m_pVertex[0],m_pVertex[1]);
CVector3d v(m_pVertex[0],m_pVertex[2]);
u.Inner(v);
m_Normal.Set(u);
m_Normal.NormalizeL2();
}
//////////////////////////////////////////////
// MISC
//////////////////////////////////////////////
//********************************************
// HasVertex
//********************************************
int CFace3d::HasVertex(CVertex3d *pVertex)
{
return (m_pVertex[0] == pVertex ||
m_pVertex[1] == pVertex ||
m_pVertex[2] == pVertex);
}
//********************************************
// HasVertexWithFlag
//********************************************
int CFace3d::HasVertexWithFlag(int flag)
{
return (m_pVertex[0]->GetFlag() == flag ||
m_pVertex[1]->GetFlag() == flag ||
m_pVertex[2]->GetFlag() == flag);
}
//********************************************
// HasVertex
//********************************************
int CFace3d::HasVertex(CVertex3d *pVertex,
int *index)
{
for(int i=0;i<3;i++)
if(m_pVertex[i] == pVertex)
{
*index = i;
return 1;
}
return 0;
}
//********************************************
// HasVertex
//********************************************
int CFace3d::HasNeighbor(CFace3d *pFace)
{
return (m_pFace[0] == pFace ||
m_pFace[1] == pFace ||
m_pFace[2] == pFace);
}
//********************************************
// HasVertex
//********************************************
int CFace3d::HasNeighbor(CFace3d *pFace,
int *index)
{
for(int i=0;i<3;i++)
if(m_pFace[i] == pFace)
{
*index = i;
return 1;
}
return 0;
}
//********************************************
// GetNeighborExclusive
// Get neighboring face wich has pVertexHas
// and has not pVertexHasNot
//********************************************
CFace3d *CFace3d::GetNeighborExclusive(CVertex3d *pVertexHas,
CVertex3d *pVertexHasNot)
{
for(int i=0;i<3;i++)
{
CFace3d *pFace = f(i);
if(pFace != NULL)
if(pFace->HasVertex(pVertexHas) &&
!pFace->HasVertex(pVertexHasNot))
return pFace;
}
return NULL;
}
//********************************************
// GetVertexExclusive
//********************************************
CVertex3d *CFace3d::GetVertexExclusive(CVertex3d *pV0,
CVertex3d *pV1)
{
for(int i=0;i<3;i++)
if(v(i) != pV0 && v(i) != pV1)
return v(i);
return NULL;
}
//********************************************
// GetVertexExclusive
// Return vertex common to this and pFace,
// but pV
//********************************************
CVertex3d *CFace3d::GetVertexExclusive(CVertex3d *pV,
CFace3d *pFace)
{
for(int i=0;i<3;i++)
if(v(i) != pV && pFace->HasVertex(v(i)))
return v(i);
return NULL;
}
//********************************************
// GetFaceNeighborExclusive
//********************************************
CFace3d *CFace3d::GetFaceNeighborExclusive(CFace3d *pF0,
CFace3d *pF1)
{
for(int i=0;i<3;i++)
if(f(i) != pF0 && f(i) != pF1)
return f(i);
return NULL;
}
//********************************************
// GetVertexFaceNeighborExclusive
// Get vertex on neighboring face, which is not
// on "this".
// index : neighboring face
//********************************************
CVertex3d *CFace3d::GetVertexFaceNeighborExclusive(unsigned int index)
{
CFace3d *pFace = m_pFace[index%3];
for(int i=0;i<3;i++)
if(!this->HasVertex(pFace->v(i)))
return pFace->v(i);
return NULL;
}
//********************************************
// JointNeighbor
//********************************************
int CFace3d::JointNeighbor(CFace3d **pFace0,
CFace3d **pFace1)
{
ASSERT(NbFaceNeighbor()==2);
if(NbFaceNeighbor()!=2)
return 0;
// Find 2 neighbors
CFace3d *pFaceNeighbor[2];
int k=0;
for(int i=0;i<3;i++)
{
if(m_pFace[i] != NULL)
pFaceNeighbor[k++] = m_pFace[i];
}
ASSERT(k==2);
if(k!=2)
return 0;
ASSERT(pFaceNeighbor[0]->HasNeighbor(this));
ASSERT(pFaceNeighbor[1]->HasNeighbor(this));
ASSERT(pFaceNeighbor[0] != this);
ASSERT(pFaceNeighbor[1] != this);
*pFace0 = pFaceNeighbor[0];
*pFace1 = pFaceNeighbor[1];
pFaceNeighbor[0]->UpdateNeighbor(this,pFaceNeighbor[1]);
pFaceNeighbor[1]->UpdateNeighbor(this,pFaceNeighbor[0]);
return 1;
}
//********************************************
// UpdateVertex
//********************************************
int CFace3d::UpdateVertex(CVertex3d *pOld,
CVertex3d *pNew)
{
int index;
if(HasVertex(pOld,&index))
{
v(index,pNew);
CalculateNormal(); // Update normal
return 1;
}
return 0;
}
//********************************************
// UpdateNeighbor
//********************************************
int CFace3d::UpdateNeighbor(CFace3d *pOld,
CFace3d *pNew)
{
int index;
if(HasNeighbor(pOld,&index))
{
f(index,pNew);
return 1;
}
return 0;
}
//********************************************
// Share2Vertex (exactly)
//********************************************
int CFace3d::Share2Vertex(CFace3d *pFace)
{
if(pFace == NULL)
return 0;
int NbSharedVertex = 0;
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
NbSharedVertex += (pFace->v(i) == m_pVertex[j]);
return (NbSharedVertex == 2);
}
//********************************************
// Share2Vertex (exactly)
// Get sharing edge index info
//********************************************
int CFace3d::Share2Vertex(CFace3d *pFace,
int *IndexEdgeThis,
int *IndexEdgeOther)
{
if(!Share2Vertex(pFace))
return 0;
int IndexThis[3] = {0,0,0};
int IndexOther[3] = {0,0,0};
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
if(pFace->v(i) == m_pVertex[j])
{
IndexThis[j] = 1;
IndexOther[i] = 1;
}
// Set IndexEdges
*IndexEdgeThis = (IndexThis[0] && IndexThis[1]) ? 0 : (IndexThis[1] && IndexThis[2]) ? 1 : 2;
*IndexEdgeOther = (IndexOther[0] && IndexOther[1]) ? 0 : (IndexOther[1] && IndexOther[2]) ? 1 : 2;
// ** DEBUG **
if(*IndexEdgeThis == 2)
{
ASSERT(IndexThis[0] && IndexThis[2]);
}
if(*IndexEdgeOther == 2)
{
ASSERT(IndexOther[0] && IndexOther[2]);
}
return 1;
}
//********************************************
// Share2Vertex (exactly)
// Get sharing edge index info
//********************************************
int CFace3d::Share2Vertex(CFace3d *pFace,
CVertex3d **pSharedV1,
CVertex3d **pSharedV2)
{
int EdgeThis;
int EdgeOther;
if(!Share2Vertex(pFace))
{
*pSharedV1 = NULL;
*pSharedV2 = NULL;
return 0;
}
Share2Vertex(pFace,&EdgeThis,&EdgeOther);
*pSharedV1 = v(EdgeThis);
*pSharedV2 = v((EdgeThis+1)%3);
return 1;
}
//********************************************
// Share1Vertex (exactly)
//********************************************
int CFace3d::Share1Vertex(CFace3d *pFace)
{
int NbSharedVertex = 0;
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
NbSharedVertex += (pFace->v(i) == m_pVertex[j]);
return (NbSharedVertex == 1);
}
//********************************************
// UpdateVertexRecursive
//********************************************
int CFace3d::UpdateVertexRecursive(CVertex3d *pVertexOld,
CVertex3d *pVertexNew)
{
if(pVertexOld == pVertexNew)
return 0;
//TRACE("Update vertex %x in face %x\n",pVertexOld,this);
this->UpdateVertex(pVertexOld,pVertexNew);
for(int i=0;i<3;i++)
{
CFace3d *pFace = f(i);
if(pFace != NULL)
if(pFace->HasVertex(pVertexOld))
pFace->UpdateVertexRecursive(pVertexOld,pVertexNew);
}
return 1;
}
//////////////////////////////////////////////
// DEBUG
//////////////////////////////////////////////
//********************************************
// Trace
//********************************************
void CFace3d::Trace()
{
TRACE("\n");
TRACE("Face %x\n",this);
TRACE("Vertex : %d\n",NbVertex());
TRACE("Face (n) : %d\n",NbFaceNeighbor());
TRACE("Normal : %s\n",(m_Normal.GetNormL2Square()==0) ? "no" : "yes");
TRACE("Vertices : (%g,%g,%g) (%g,%g,%g) (%g,%g,%g) \n",
m_pVertex[0]->x(),m_pVertex[0]->y(),m_pVertex[0]->z(),
m_pVertex[1]->x(),m_pVertex[1]->y(),m_pVertex[1]->z(),
m_pVertex[2]->x(),m_pVertex[2]->y(),m_pVertex[2]->z());
TRACE("Normal : (%g,%g,%g)\n",m_Normal.x(),m_Normal.y(),m_Normal.z());
// ** DEBUG **
/*
for(int i=0;i<3;i++)
m_pVertex[i]->Trace();
*/
}
//////////////////////////////////////////////
// OPENGL
//////////////////////////////////////////////
//********************************************
// glDraw
// Highlights face and its neighbors
//********************************************
void CFace3d::glDraw(unsigned char *ColorFace,
CMesh3d *pMesh /* = NULL */,
unsigned char *ColorNeightbor /* = NULL */)
{
// Transform
if(pMesh != NULL)
{
CTransform *pTransform = pMesh->GetTransform();
::glPushMatrix();
// Position / translation / scaling
glTranslatef(pTransform->GetTranslation()->x(),
pTransform->GetTranslation()->y(),
pTransform->GetTranslation()->z());
glScalef(pTransform->GetScale()->x(),
pTransform->GetScale()->y(),
pTransform->GetScale()->z());
glRotatef(pTransform->GetValueRotation(),
pTransform->GetRotation()->x(),
pTransform->GetRotation()->y(),
pTransform->GetRotation()->z());
}
// Neighbor
if(ColorNeightbor != NULL)
{
glColor3ub(ColorNeightbor[0],ColorNeightbor[1],ColorNeightbor[2]);
for(int k=0;k<3;k++)
{
CFace3d *pFace = f(k);
if(pFace != NULL)
{
::glBegin(GL_POLYGON);
::glVertex3f(pFace->v1()->x(),pFace->v1()->y(),pFace->v1()->z());
::glVertex3f(pFace->v2()->x(),pFace->v2()->y(),pFace->v2()->z());
::glVertex3f(pFace->v3()->x(),pFace->v3()->y(),pFace->v3()->z());
::glEnd();
}
}
}
// Main face
glColor3ub(ColorFace[0],ColorFace[1],ColorFace[2]);
::glBegin(GL_POLYGON);
for(int i=0;i<3;i++)
::glVertex3f(m_pVertex[i]->x(),m_pVertex[i]->y(),m_pVertex[i]->z());
::glEnd();
if(pMesh != NULL)
{
::glPopMatrix();
}
}
//********************************************
// Area
//********************************************
double CFace3d::Area()
{
return ::Area(m_pVertex[0],m_pVertex[1],m_pVertex[2]);
}
//********************************************
// Perimeter
//********************************************
double CFace3d::Perimeter()
{
return (::Distance(m_pVertex[0],m_pVertex[1]) +
::Distance(m_pVertex[1],m_pVertex[2]) +
::Distance(m_pVertex[2],m_pVertex[0]));
}
//********************************************
// Compacity
//********************************************
double CFace3d::Compacity()
{
double perimeter = Perimeter();
if(perimeter == 0.0f)
{
TRACE("CFace3d::Compacity : null triangle\n");
return 0.0;
}
return (4.0*PI*Area()/(perimeter*perimeter));
}
// ** EOF **