//********************************************
// Vertex3d.cpp
//********************************************
// class CVertex3d
//********************************************
// pierre.alliez@cnet.francetelecom.fr
// Created : 10/12/97
// Modified : 14/01/98
//********************************************
#include "stdafx.h"
#include "math.h"
#include "Base3d.h"
#include "Vertex3d.h"
#include "Face3d.h"
//////////////////////////////////////////////
// DATAS
//////////////////////////////////////////////
//********************************************
// GetType
//********************************************
int CVertex3d::GetType()
{
return TYPE_VERTEX3D;
}
//////////////////////////////////////////////
// OPERATORS
//////////////////////////////////////////////
//********************************************
// Operator =
//********************************************
CVertex3d CVertex3d::operator=(CVertex3d& vertex)
{
CVertex3d v;
v.Set(vertex);
return v;
}
//////////////////////////////////////////////
// VERTEX NEIGHBORING
//////////////////////////////////////////////
//********************************************
// AddNeighbor
//********************************************
void CVertex3d::AddNeighbor(CVertex3d *pVertex)
{
// Duplicate vertices are removed
if(pVertex == this)
return;
if(!HasNeighbor(pVertex))
m_ArrayVertexNeighbor.Add(pVertex);
}
//********************************************
// AddNeighborNoCheck
//********************************************
void CVertex3d::AddNeighborNoCheck(CVertex3d *pVertex)
{
// Add a neighboring vertex
m_ArrayVertexNeighbor.Add(pVertex);
}
//********************************************
// NbNeighbor
//********************************************
int CVertex3d::NbVertexNeighbor(void)
{
return m_ArrayVertexNeighbor.GetSize();
}
//********************************************
// RemoveAllNeighbor
//********************************************
void CVertex3d::RemoveAllVertexNeighbor(void)
{
m_ArrayVertexNeighbor.RemoveAll();
}
//********************************************
// RemoveVertexNeighbor
//********************************************
int CVertex3d::RemoveNeighbor(CVertex3d *pVertex)
{
int size = m_ArrayVertexNeighbor.GetSize();
for(int i=0;i<size;i++)
if(m_ArrayVertexNeighbor[i]==pVertex)
{
m_ArrayVertexNeighbor.RemoveAt(i);
return 1;
}
return 0;
}
//********************************************
// UpdateNeighbor
//********************************************
int CVertex3d::UpdateNeighbor(CVertex3d *pVertexOld,
CVertex3d *pVertexNew)
{
int success = 0;
for(int j=0;j<m_ArrayVertexNeighbor.GetSize();j++)
if(m_ArrayVertexNeighbor[j] == pVertexOld)
{
m_ArrayVertexNeighbor.RemoveAt(j);
this->AddNeighbor(pVertexNew);
pVertexNew->AddNeighbor(this);
success = 1;
}
return success;
}
//********************************************
// UpdateNeighbor
//********************************************
void CVertex3d::UpdateNeighborRecursive(CVertex3d *pVertexOld,
CVertex3d *pVertexNew)
{
for(int i=0;i<m_ArrayVertexNeighbor.GetSize();i++)
if(m_ArrayVertexNeighbor[i]!=NULL)
m_ArrayVertexNeighbor[i]->UpdateNeighbor(pVertexOld,pVertexNew);
}
//********************************************
// FindFaceAroundContainVertex
//********************************************
int CVertex3d::FindFaceAroundContainVertex(CVertex3d *pVertex,
CArray3d<CFace3d> &ArrayFace)
{
int success = 0;
for(int i=0;i<m_ArrayFaceNeighbor.GetSize();i++)
if(m_ArrayFaceNeighbor[i] != NULL)
if(m_ArrayFaceNeighbor[i]->HasVertex(pVertex))
{
ArrayFace.Add(m_ArrayFaceNeighbor[i]);
success = 1;
}
return success;
}
//********************************************
// GetMeanAreaAround
//********************************************
double CVertex3d::GetMeanAreaAround()
{
return ::GetMeanArea(&m_ArrayFaceNeighbor);
}
//********************************************
// GetMinAreaAround
//********************************************
double CVertex3d::GetMinAreaAround()
{
return ::GetMinArea(&m_ArrayFaceNeighbor);
}
//////////////////////////////////////////////
// FACE NEIGHBORING
//////////////////////////////////////////////
//********************************************
// AddFaceNeighbor
//********************************************
void CVertex3d::AddNeighbor(CFace3d *pFace)
{
// Add a neighboring face only when it
// is not included in the array
if(!HasNeighbor(pFace))
m_ArrayFaceNeighbor.Add(pFace);
}
//********************************************
// NbFaceNeighbor
//********************************************
int CVertex3d::NbFaceNeighbor(void)
{
return m_ArrayFaceNeighbor.GetSize();
}
//********************************************
// RemoveAllFaceNeighbor
//********************************************
void CVertex3d::RemoveAllFaceNeighbor(void)
{
m_ArrayFaceNeighbor.RemoveAll();
}
//********************************************
// RemoveFaceNeighbor
//********************************************
int CVertex3d::RemoveNeighbor(CFace3d *pFace)
{
int size = m_ArrayFaceNeighbor.GetSize();
for(int i=0;i<size;i++)
if(m_ArrayFaceNeighbor[i]==pFace)
{
m_ArrayFaceNeighbor.RemoveAt(i);
return 1;
}
return 0;
}
//********************************************
// Find each faces sharing between pVertex
// and "this"
// We assume adjacency is built
//********************************************
int CVertex3d::FindSharingFaces(CVertex3d *pVertex,
CArray3d<CFace3d> &array)
{
int added = 0;
int NbFaceNeighbor = pVertex->NbFaceNeighbor();
for(int i=0;i<NbFaceNeighbor;i++)
{
if(m_ArrayFaceNeighbor.Has(pVertex->GetFaceNeighbor(i)))
{
array.Add(pVertex->GetFaceNeighbor(i));
added++;
}
}
return added;
}
//////////////////////////////////////////////
// BOUNDARIES
//////////////////////////////////////////////
//********************************************
// IsOnBoundary
//********************************************
int CVertex3d::IsOnBoundary()
{
// ** DEBUG **
int size = m_ArrayFaceNeighbor.GetSize();
for(int i=0;i<size;i++)
for(int j=0;j<3;j++)
if(m_ArrayFaceNeighbor[i]->f(j) == NULL &&
(m_ArrayFaceNeighbor[i]->v(j) == this ||
m_ArrayFaceNeighbor[i]->v((j+1)%3) == this))
return 1;
return 0;
}
//////////////////////////////////////////////
// FLAGS
//////////////////////////////////////////////
int CVertex3d::HasNeighborWithFlag(int flag)
{
int size = NbVertexNeighbor();
for(int i=0;i<size;i++)
{
CVertex3d *pVertex = m_ArrayVertexNeighbor[i];
if(pVertex->GetFlag() == flag)
return 1;
}
return 0;
}
int CVertex3d::HasNeighborWithFlagButDiff(int flag,
CVertex3d *pVertexDiff)
{
int size = NbVertexNeighbor();
for(int i=0;i<size;i++)
{
CVertex3d *pVertex = m_ArrayVertexNeighbor[i];
if(pVertex != pVertexDiff)
if(pVertex->GetFlag() == flag)
return 1;
}
return 0;
}
CVertex3d *CVertex3d::GetFirstVertexNeighborWithFlag(int flag)
{
int size = NbVertexNeighbor();
for(int i=0;i<size;i++)
{
CVertex3d *pVertex = m_ArrayVertexNeighbor[i];
if(pVertex->GetFlag() == flag)
return pVertex;
}
return NULL;
}
CVertex3d *CVertex3d::GetNearestVertexNeighborWithFlag(int flag)
{
double distance = 1e38;
CVertex3d *pVertexNearest = NULL;
int size = NbVertexNeighbor();
for(int i=0;i<size;i++)
{
CVertex3d *pVertex = m_ArrayVertexNeighbor[i];
if(pVertex->GetFlag() == flag)
{
double tmp = ::DistanceSquare(this,pVertex);
if(tmp < distance)
{
pVertexNearest = pVertex;
distance = tmp;
}
}
}
return pVertexNearest;
}
int CVertex3d::DiffFlagsOnNeighboringFaces()
{
int size = NbFaceNeighbor();
if(size <= 1)
return 0;
int flag = m_ArrayFaceNeighbor[0]->GetFlag(); // first flag
for(int i=1;i<size;i++)
{
CFace3d *pFace = m_ArrayFaceNeighbor[i];
int tmp = pFace->GetFlag();
if(tmp != flag)
return 1;
}
return 0;
}
int CVertex3d::IsFlagSmallestOnNeighboringFaces(int flag)
{
int size = NbFaceNeighbor();
for(int i=0;i<size;i++)
{
CFace3d *pFace = m_ArrayFaceNeighbor[i];
int tmp = pFace->GetFlag();
if(tmp < flag)
return 0;
}
return 1;
}
CVertex3d *CVertex3d::GetFirstVertexNeighborWithFlagButDiff(int flag,
CVertex3d *pVertexDiff)
{
int size = NbVertexNeighbor();
for(int i=0;i<size;i++)
{
CVertex3d *pVertex = m_ArrayVertexNeighbor[i];
if(pVertex != pVertexDiff)
if(pVertex->GetFlag() == flag)
return pVertex;
}
return NULL;
}
int CVertex3d::NbVertexNeighborWithFlag(int flag)
{
int nb = 0;
int size = NbVertexNeighbor();
for(int i=0;i<size;i++)
if(m_ArrayVertexNeighbor[i]->GetFlag() == flag)
nb++;
return nb;
}
int CVertex3d::FindVertexNeighborsWhichFlagIsGreater(int flag,
CArray3d<CVertex3d> &array)
{
int added = 0;
int size = NbVertexNeighbor();
for(int i=0;i<size;i++)
{
CVertex3d *pVertex = m_ArrayVertexNeighbor[i];
if(pVertex->GetFlag() > flag)
{
array.Add(pVertex);
added++;
}
}
return added;
}
int CVertex3d::FindVertexNeighborsWhichFlagIsSmaller(int flag,
CArray3d<CVertex3d> &array)
{
int added = 0;
int size = NbVertexNeighbor();
for(int i=0;i<size;i++)
{
CVertex3d *pVertex = m_ArrayVertexNeighbor[i];
if(pVertex->GetFlag() < flag)
{
array.Add(pVertex);
added++;
}
}
return added;
}
//********************************************
// GetFirstNeighborWithFlagAndSharingFaceWithFlag
//********************************************
CVertex3d *CVertex3d::GetFirstNeighborWithFlagAndSharingFaceWithFlag(int FlagVertex,
int FlagFace)
{
int size = NbVertexNeighbor();
for(int i=0;i<size;i++)
{
CVertex3d *pVertex = m_ArrayVertexNeighbor[i];
if(pVertex->GetFlag() == FlagVertex)
{
CArray3d<CFace3d> array;
if(FindSharingFaces(pVertex,array))
{
int NbFace = array.GetSize();
for(int j=0;j<NbFace;j++)
{
CFace3d *pFace = array[j];
if(pFace->GetFlag() == FlagFace)
return pVertex;
}
}
}
}
return NULL;
}
//////////////////////////////////////////////
// SHARP EDGES
//////////////////////////////////////////////
//********************************************
// NbSharpEdge
//********************************************
int CVertex3d::NbSharpEdge(const double threshold)
{
// 3 sharp edges on boundaries
if(IsOnBoundary())
return 3;
int NbSharp = ::NbSharpEdge(m_ArrayFaceNeighbor,threshold);
//TRACE("NbSharp : %d\n",NbSharp);
return NbSharp;
}
//********************************************
// NormalSum
//********************************************
int CVertex3d::NormalSum(double *pSum)
{
return ::NormalSum(m_ArrayFaceNeighbor,pSum);
}
//********************************************
// NormalMax
//********************************************
int CVertex3d::NormalMax(double *pMax)
{
return ::NormalMax(m_ArrayFaceNeighbor,pMax);
}
//////////////////////////////////////////////
//////////////////////////////////////////////
// CURVENESS
//////////////////////////////////////////////
//////////////////////////////////////////////
//********************************************
// GetMeanCurveAround
//********************************************
double CVertex3d::GetMeanCurveAround()
{
int size = m_ArrayFaceNeighbor.GetSize();
if(size == 0)
return 0.0f;
double sum;
::NormalSum(m_ArrayFaceNeighbor,&sum);
return sum/size;
}
//********************************************
// GetSumCurveAround
//********************************************
double CVertex3d::GetSumCurveAround()
{
double sum;
if(::NormalSum(m_ArrayFaceNeighbor,&sum))
return sum;
else
return 0.0;
}
//********************************************
// GetMaxCurveAround
//********************************************
double CVertex3d::GetMaxCurveAround()
{
double max;
if(::NormalMax(m_ArrayFaceNeighbor,&max))
return max;
else
{
TRACE("** CVertex3d::GetMaxCurveAround\n");
return 0.0;
}
}
double CVertex3d::GetMaxAngleAround()
{
double max;
if(::MaxAngleBetweenFaces(m_ArrayFaceNeighbor,&max))
return max;
else
return 0.0;
}
//********************************************
// GetMaxCurveAroundAndNeighbors
//********************************************
double CVertex3d::GetMaxCurveAroundAndNeighbors()
{
double max = 0.0;
::NormalMax(m_ArrayFaceNeighbor,&max);
int size = m_ArrayVertexNeighbor.GetSize();
for(int i=0;i<size;i++)
max = max(max,m_ArrayVertexNeighbor[i]->GetMaxCurveAround());
return max;
}
//////////////////////////////////////////////
// MISC
//////////////////////////////////////////////
//********************************************
// Diff
//********************************************
int CVertex3d::Diff(CVertex3d *pVertex)
{
return ( (m_Coord[0] != pVertex->x()) ||
(m_Coord[1] != pVertex->y()) ||
(m_Coord[2] != pVertex->z()));
}
//********************************************
// Equal
//********************************************
int CVertex3d::Equal(CVertex3d *pVertex)
{
return ( (m_Coord[0] == pVertex->x()) &&
(m_Coord[1] == pVertex->y()) &&
(m_Coord[2] == pVertex->z()));
}
//////////////////////////////////////////////
// PRECISION
//////////////////////////////////////////////
//********************************************
// ReplaceOnGrid
//********************************************
void CVertex3d::ReplaceOnGrid(float threshold)
{
for(int i=0;i<3;i++)
m_Coord[i] = (m_Coord[i] < threshold) ? 0.0f : m_Coord[i];
}
//********************************************
// GetMeanLengthEdgeAround
//********************************************
double CVertex3d::GetMeanLengthEdgeAround()
{
double sum = 0.0f;
int size = m_ArrayVertexNeighbor.GetSize();
if(size == 0)
return 0.0f;
for(int i=0;i<size;i++)
sum += ::Distance(m_ArrayVertexNeighbor[i],this);
return (sum/size);
}
//////////////////////////////////////////////
// DEBUG
//////////////////////////////////////////////
//********************************************
// Trace
//********************************************
void CVertex3d::Trace()
{
TRACE("\n");
TRACE("** Vertex **\n");
TRACE("Adress : %x\n",this);
TRACE("Coordinates : (%g %g %g)\n",m_Coord[0],m_Coord[1],m_Coord[2]);
TRACE("Normal : (%g %g %g)\n",m_Normal.x(),m_Normal.y(),m_Normal.z());
TRACE("Neighbors : %d\n",m_ArrayVertexNeighbor.GetSize());
int size = m_ArrayFaceNeighbor.GetSize();
for(int i=0;i<size;i++)
{
m_ArrayFaceNeighbor[i]->Trace();
ASSERT(m_ArrayFaceNeighbor[i]->IsValid());
}
}
//////////////////////////////////////////////
// OPENGL
//////////////////////////////////////////////
//********************************************
// glDrawHighlight
// Highlights vertex and its neighbors
//********************************************
void CVertex3d::glDrawHighlight(const float radius,
const float RadiusNeighbor,
unsigned char *ColorVertex,
CMesh3d *pMesh /* = NULL */,
unsigned char *ColorNeightbor /* = NULL */)
{
GLUquadricObj* pQuadric = gluNewQuadric();
// 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());
}
// Main vertex
glColor3ub(ColorVertex[0],ColorVertex[1],ColorVertex[2]);
glPushMatrix();
glTranslated(m_Coord[0],m_Coord[1],m_Coord[2]);
gluSphere(pQuadric,radius,8,8);
glPopMatrix();
// Neighbors
if(ColorNeightbor != NULL)
{
int size = NbVertexNeighbor();
if(size != 0)
{
glColor3ub(ColorNeightbor[0],ColorNeightbor[1],ColorNeightbor[2]);
for(int i=0;i<size;i++)
{
CVertex3d *pVertex = (CVertex3d *)m_ArrayVertexNeighbor[i];
glPushMatrix();
glTranslated(pVertex->x(),pVertex->y(),pVertex->z());
gluSphere(pQuadric,RadiusNeighbor,8,8);
glPopMatrix();
}
}
}
// Face neighbors
int size = NbFaceNeighbor();
if(size != 0)
{
glColor3ub(0,0,255);
for(int i=0;i<size;i++)
{
CFace3d *pFace = m_ArrayFaceNeighbor[i];
::glBegin(GL_TRIANGLES);
::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();
}
}
// Restore
if(pMesh != NULL)
::glPopMatrix();
}
//********************************************
// glDraw
//********************************************
int CVertex3d::glDraw()
{
GLUquadricObj* pQuadric = gluNewQuadric();
// Main vertex
glColor3ub(m_Color.r(),m_Color.g(),m_Color.b());
glPushMatrix();
glTranslated(m_Coord[0],m_Coord[1],m_Coord[2]);
gluSphere(pQuadric,0.01,8,8);
glPopMatrix();
return 1;
}
//********************************************
// glDraw
//********************************************
void CVertex3d::glDraw(const float radius,
unsigned char *ColorVertex,
CMesh3d *pMesh /* = NULL */)
{
GLUquadricObj* pQuadric = gluNewQuadric();
// 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());
}
// Main vertex
glColor3ub(ColorVertex[0],ColorVertex[1],ColorVertex[2]);
glPushMatrix();
glTranslated(m_Coord[0],m_Coord[1],m_Coord[2]);
gluSphere(pQuadric,radius,8,8);
gluDeleteQuadric(pQuadric);
glPopMatrix();
// Restore
if(pMesh != NULL)
::glPopMatrix();
}
// ** EOF **