9b564445cd
- creazione di superfici trimesh da piani contornati e per estrusione - migliorie a PolyLine - migliorie a FromString - modifiche a Vector3d e Point3d.
210 lines
6.4 KiB
C++
210 lines
6.4 KiB
C++
//----------------------------------------------------------------------------
|
||
// 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 ;
|
||
}
|
||
|