Files
EgtGeomKernel/Triangulate.cpp
T
Dario Sassi 9b564445cd EgtGeomKernel 1.5d2 :
- creazione di superfici trimesh da piani contornati e per estrusione
- migliorie a PolyLine
- migliorie a FromString
- modifiche a Vector3d e Point3d.
2014-04-09 13:00:17 +00:00

210 lines
6.4 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//----------------------------------------------------------------------------
// EgalTech 2014-2014
//----------------------------------------------------------------------------
// File : Triangulate.cpp Data : 08.04.14 Versione : 1.5d2
// Contenuto : Implementazione della classe Triangulate.
//
//
//
// Modifiche : 08.04.14 DS Creazione modulo.
//
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "Triangulate.h"
#include "\EgtDev\Include\EGkPolyLine.h"
#include "\EgtDev\Include\EGkPlane3d.h"
//----------------------------------------------------------------------------
// In : PolyLine
// Out : PNTVECTOR (Point3d Vector) : points of the polyline
// INTVECTOR (int Vector) : 3*T indices of above points for T triangles
//----------------------------------------------------------------------------
bool
Triangulate::Make( const PolyLine& PL, PNTVECTOR& vPt, INTVECTOR& vTr)
{
// verifico che la polilinea sia chiusa -> poligono
if ( ! PL.IsClosed())
return false ;
// calcolo il piano medio del poligono
Plane3d plPlane ;
if ( ! PL.IsPlanar( plPlane, 50 * EPS_SMALL))
return false ;
int nPlane ;
bool bCCW ;
if ( fabs( plPlane.vtN.z) >= fabs( plPlane.vtN.x) &&
fabs( plPlane.vtN.z) >= fabs( plPlane.vtN.y)) {
nPlane = PL_XY ;
bCCW = ( plPlane.vtN.z > 0) ;
}
else if ( fabs( plPlane.vtN.x) >= fabs( plPlane.vtN.y)) {
nPlane = PL_YZ ;
bCCW = ( plPlane.vtN.x > 0) ;
}
else {
nPlane = PL_ZX ;
bCCW = ( plPlane.vtN.y > 0) ;
}
// riempio il vettore con i vertici del poligono da triangolare
vPt.clear() ;
vPt.reserve( PL.GetPointNbr() - 1) ;
// se orientato correttamente (componente di N > 0)
if ( bCCW) {
// salto il primo punto (coincide con l'ultimo)
Point3d ptP ;
if ( ! PL.GetFirstPoint( ptP))
return false ;
// inserisco i punti
while ( PL.GetNextPoint( ptP))
vPt.push_back( ptP) ;
}
// altrimenti lo prendo al contrario
else {
// salto l'ultimo punto (coincide con il primo)
Point3d ptP ;
if ( ! PL.GetLastPoint( ptP))
return false ;
// inserisco i punti
while ( PL.GetPrevPoint( ptP))
vPt.push_back( ptP) ;
}
// eseguo la triangolazione
return MakeByEC( vPt, nPlane, vTr) ;
}
//----------------------------------------------------------------------------
// Triangulate the CCW n-gon specified by the vertices vPt (Pt[n] != Pt[0])
// Ear Clipping algorithm
//----------------------------------------------------------------------------
bool
Triangulate::MakeByEC( const PNTVECTOR& vPt, int nPlane, INTVECTOR& vTr)
{
// At least 3 points
int n = int( vPt.size()) ;
if ( n < 3)
return false ;
// Save the plane
if ( nPlane != PL_XY && nPlane != PL_YZ && nPlane != PL_ZX)
return false ;
m_nPlane = nPlane ;
// Clear and preallocate triangle vector ( #triangles = n - 2)
vTr.clear() ;
vTr.reserve( 3 * ( n - 2)) ;
// Set up previous and next links to effectively form a double-linked vertex list
INTVECTOR prev( n) ;
INTVECTOR next( n) ;
for ( int i = 0 ; i < n ; ++ i) {
prev[i] = i - 1 ;
next[i] = i + 1 ;
}
prev[0] = n - 1 ;
next[n - 1] = 0 ;
// Start at vertex 0
int i = 0 ;
int nCount = n ;
// Keep removing vertices until just a triangle left
while ( n >= 3) {
// To avoid infinite loop
if ( nCount <= 0)
return false ;
-- nCount ;
// Test if current vertex, v[i], is an ear
bool bIsEar = true ;
// An ear must be convex (here counterclockwise)
if ( TriangleIsCCW( vPt[prev[i]], vPt[i], vPt[next[i]])) {
// Loop over all vertices not part of the tentative ear
int k = next[next[i]] ;
do {
// If vertex k is inside the ear triangle, then this is not an ear
if ( TestPointInTriangle( vPt[k], vPt[prev[i]], vPt[i], vPt[next[i]])) {
bIsEar = false ;
break;
}
k = next[k] ;
} while (k != prev[i]) ;
}
else {
// The ear triangle is clockwise so v[i] is not an ear
bIsEar = false ;
}
// If current vertex v[i] is an ear, delete it and visit the previous vertex
if ( bIsEar) {
// Triangle (v[prev[i]], v[i], v[next[i]]) is an ear
vTr.push_back( prev[i]) ;
vTr.push_back( i) ;
vTr.push_back( next[i]) ;
// Delete vertex v[i] by redirecting next and previous links
// of neighboring verts past it. Decrement vertex count
next[prev[i]] = next[i] ;
prev[next[i]] = prev[i] ;
n--;
// Visit the previous vertex next
i = prev[i] ;
// Reset Count
nCount = n ;
}
else {
// Current vertex is not an ear; visit the next vertex
i = next[i] ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
Triangulate::TriangleIsCCW( const Point3d& ptA, const Point3d& ptB, const Point3d& ptC)
{
double dV11 ;
double dV12 ;
double dV21 ;
double dV22 ;
switch ( m_nPlane) {
default : // PL_XY
dV11 = ptB.x - ptA.x ;
dV12 = ptB.y - ptA.y ;
dV21 = ptC.x - ptB.x ;
dV22 = ptC.y - ptB.y ;
break ;
case PL_YZ :
dV11 = ptB.y - ptA.y ;
dV12 = ptB.z - ptA.z ;
dV21 = ptC.y - ptB.y ;
dV22 = ptC.z - ptB.z ;
break ;
case PL_ZX :
dV11 = ptB.z - ptA.z ;
dV12 = ptB.x - ptA.x ;
dV21 = ptC.z - ptB.z ;
dV22 = ptC.x - ptB.x ;
break ;
}
return ( ( dV11 * dV22 - dV12 * dV21) > 0) ;
}
//----------------------------------------------------------------------------
// Test if point p is contained in triangle (a, b, c)
bool
Triangulate::TestPointInTriangle( const Point3d& ptP, const Point3d& ptA, const Point3d& ptB, const Point3d& ptC)
{
if ( ! TriangleIsCCW( ptA, ptB, ptP))
return false ;
if ( ! TriangleIsCCW( ptB, ptC, ptP))
return false ;
if ( ! TriangleIsCCW( ptC, ptA, ptP))
return false ;
return true ;
}