//
// File: triangle.cc
//
// (C) 2000-2008 Helmut Cantzler
//
// Licensed under the terms of the Lesser General Public License.
//
#include "triangle.h"
Triangle::Triangle(Vertex *v1, Vertex *v2, Vertex *v3, TriangleType type)
{
int v;
plane=0;
fromPolygon = type == POLYGON_TRIANGLE ? true : false;
vertices[0]=v1;
vertices[1]=v2;
vertices[2]=v3;
edges[0]=edges[1]=edges[2]=NULL;
calcProperties();
for (v=0; v < 3; v++)
{
vertices[v]->addTriangle(this);
vertices[v]->addNormal(&surfaceNormal);
}
}
Triangle::Triangle(Edge *e1, Edge *e2, Edge *e3)
{
int i;
plane=0;
fromPolygon = false;
edges[0]=e1;
edges[1]=e2;
edges[2]=e3;
for (i=0; i < 3; i++)
edges[i]->addTriangle(this);
if ( (edges[0]->vertices[0] != edges[1]->vertices[0]) &&
(edges[0]->vertices[0] != edges[1]->vertices[1]) )
{
vertices[0]=edges[0]->vertices[0];
vertices[1]=edges[0]->vertices[1];
}
else
{
vertices[0]=edges[0]->vertices[1];
vertices[1]=edges[0]->vertices[0];
}
if ( (edges[1]->vertices[0] != edges[0]->vertices[0]) &&
(edges[1]->vertices[0] != edges[0]->vertices[1]) )
{
vertices[2]=edges[1]->vertices[0];
}
else
{
vertices[2]=edges[1]->vertices[1];
}
calcProperties();
for (i=0; i < 3; i++)
{
vertices[i]->addTriangle(this);
vertices[i]->addNormal(&surfaceNormal);
}
}
void Triangle::setVertices(const MathVector *v1, const MathVector *v2,
const MathVector *v3)
{
vertices[0]->set(v1);
vertices[1]->set(v2);
vertices[2]->set(v3);
calcProperties();
}
void Triangle::calcProperties(void)
{
// calculate surface centroid and register triangle at the vertices
surfaceCentroid.setZero();
for (int v=0; v < 3; v++)
surfaceCentroid.add(vertices[v]->mathData());
surfaceCentroid.scale(1.0/3.0);
// calculate the vectors between the vertices
MathVector c[3];
MathVector::sub(vertices[0]->mathData(), vertices[1]->mathData(), &c[0]);
MathVector::sub(vertices[0]->mathData(), vertices[2]->mathData(), &c[1]);
MathVector::sub(vertices[2]->mathData(), vertices[1]->mathData(), &c[2]);
// calculate surface normal
MathVector::crossProduct(&c[0], &c[1], &surfaceNormal);
surfaceNormal.normalize();
// calculate distance to the origin from the centroid in direction
// of the surface normal
surfaceDistanceToOrigin = MathVector::dotProduct(&surfaceCentroid,
&surfaceNormal);
// calculate surface perimeter
surfacePerimeter = c[0].length() + c[1].length() + c[2].length();
// calculate surface size
float s=surfacePerimeter/2.0;
surfaceSize=sqrt(s * (s-c[0].length()) * (s-c[1].length()) * (s-c[2].length()));
}
Triangle::~Triangle()
{
for (int i=0; i < 3; i++)
{
vertices[i]->deleteTriangle(this);
if (edges[i] != NULL)
edges[i]->deleteTriangle(this);
}
}
void Triangle::moveCentroid(const MathVector *v)
{
surfaceCentroid.add(v);
}
void Triangle::negateNormal(void)
{
Vertex *dummy;
dummy=vertices[1];
vertices[1]=vertices[2];
vertices[2]=dummy;
surfaceNormal.negation();
surfaceDistanceToOrigin = -surfaceDistanceToOrigin;
}
const float* Triangle::centroid(void) const
{
return surfaceCentroid.v;
}
const MathVector* Triangle::mathCentroid(void) const
{
return &surfaceCentroid;
}
const float* Triangle::floatNormal(void) const
{
return surfaceNormal.v;
}
const MathVector* Triangle::mathNormal(void) const
{
return &surfaceNormal;
}
float Triangle::size(void) const
{
return surfaceSize;
}
float Triangle::perimeter(void) const
{
return surfacePerimeter;
}
float Triangle::distanceToOrigin(void) const
{
return surfaceDistanceToOrigin;
}
float Triangle::angle(const Vertex *v) const
{
MathVector c[3];
int i, k;
// find the two vectors between the vertices
for (i=k=0; i < 3; i++)
if (v != vertices[i])
MathVector::sub(v->mathData(), vertices[i]->mathData(), &c[k++]);
// calculate the angle between the edges
return k == 2 ? MathVector::angle90(&c[0], &c[1]) : 0;
}
vector<Triangle*> Triangle::neighbors(void) const
{
list<Triangle*> *edgeTriangles;
list<Triangle*>::iterator it;
vector<Triangle*> nei;
for (int i=0; i < 3; i++)
{
edgeTriangles=&edges[i]->triangles;
for (it=edgeTriangles->begin(); it != edgeTriangles->end(); it++)
if (!equal(*it))
nei.push_back(*it);
}
return nei;
}
vector<Triangle*> Triangle::neighborsOnPlane(void) const
{
vector<Triangle*> nei = neighbors();
vector<Triangle*>::iterator it;
for (it=nei.begin(); it != nei.end(); )
if ((*it)->plane == plane)
it++;
else
it=nei.erase(it);
return nei;
}
int Triangle::getSurroundingPlane(void) const
{
vector<Triangle*> nei = neighbors();
int i, k, size = (int) nei.size();
if (size == 1)
return nei[0]->plane;
// look for two which are the same
for (i=0; i < size-1; i++)
for (k=i+1; k < size; k++)
if (nei[i]->plane == nei[k]->plane)
return nei[i]->plane;
return 0;
}
int Triangle::changeVertex(const Vertex *oldV, Vertex *newV)
{
int i=0;
while (i < 3 && vertices[i] != oldV)
i++;
if (i != 3)
{
vertices[i]=newV;
return 1;
}
return 0;
}
void Triangle::setTextCoordinates(int i, float s, float t)
{
vertices[i]->setTextCoordinates(s, t);
}
void Triangle::setTextCoordinates(int i, const pair<float, float>* texCoord)
{
vertices[i]->setTextCoordinates(texCoord);
}
float Triangle::getTextT(int i) const
{
return vertices[i]->getTextT();
}
float Triangle::getTextS(int i) const
{
return vertices[i]->getTextS();
}
bool Triangle::equal(const Triangle *tri) const
{
return vertices[0] == tri->vertices[0] &&
vertices[1] == tri->vertices[1] && vertices[2] == tri->vertices[2];
}
bool Triangle::onSamePlane(const Triangle *tri, float distanceTolerance,
float orientationTolerance) const
{
MathVector normal2 = tri->surfaceNormal;
float distance2 = MathVector::dotProduct(&tri->surfaceCentroid,
&surfaceNormal);
// triangle facing in different directions?
if (MathVector::angle90(&surfaceNormal, &normal2) >
GRAD2RAD(orientationTolerance))
return 0;
// optimisation ?!?!
//
// if (MathVector::angle90(&surfaceNormal, &normal2) > GRAD2RAD(20.0))
//
// because the normals are already normalised
// if (acos(MathVector::dotProduct(&surfaceNormal, &normal2)) > GRAD2RAD(20.0))
//
// one function call less
// if (acos(MathVector::dotProduct(&surfaceNormal, &normal2)) > GRAD2RAD(20.0))
//
// move cos on other side
// if (MathVector::dotProduct(&surfaceNormal, &normal2) < cos(GRAD2RAD(20.0)))
float d = surfaceDistanceToOrigin - distance2;
// the centroids are on the same plane?
return fabs(d)*100 < distanceTolerance;
}
bool Triangle::isFromPolygon(void) const
{
return fromPolygon;
}