Merge branch 'master' of https://gitlab.steamware.net/egalware-cadcam/libreriebase/EgtGeomKernel
This commit is contained in:
+51
-2
@@ -79,6 +79,53 @@ static double TOL_TRAPEZOID = 50 * EPS_SMALL ; // tolleranza per casi a trapezio
|
||||
typedef vector<ICRVCOMPOPOVECTOR> VICRVCOMPOPOVECTOR ;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// definizione varibaile di debug
|
||||
#define ENABLE_DEBUG 0
|
||||
#if ENABLE_DEBUG
|
||||
#include "EgtDev/Include/EGkGeoObjSave.h"
|
||||
#include "EgtDev/Include/EGkGeoPoint3d.h"
|
||||
#include "EgtDev/Include/EGkGeoVector3d.h"
|
||||
//----------------------------------------------------------------------------
|
||||
// Debug Functions
|
||||
//----------------------------------------------------------------------------
|
||||
void
|
||||
DrawObjs( const ISURFFRPOVECTOR& vSfr, bool bSfrUniform, bool bAlphaCoverage,
|
||||
const ICRVCOMPOPOVECTOR& vCompo, bool bCompoUniform, string sName)
|
||||
{
|
||||
// definisco i vettori per geometrie e colori
|
||||
vector<IGeoObj*> VT ;
|
||||
vector<Color> VC ;
|
||||
|
||||
// disegno le superfici
|
||||
for ( int nS = 0 ; nS < int( vSfr.size()) ; ++ nS) {
|
||||
if ( vSfr[nS] == nullptr || ! vSfr[nS]->IsValid())
|
||||
return ;
|
||||
VT.emplace_back( static_cast<IGeoObj*>( vSfr[nS]->Clone())) ;
|
||||
VC.emplace_back( bAlphaCoverage ? Color( 0., 64., 0., .5) : Color( 0., 255., 0., .5)) ;
|
||||
for ( int nC = 0 ; nC < vSfr[nS]->GetChunkCount() ; ++ nC) {
|
||||
for ( int nL = 0 ; nL < vSfr[nS]->GetLoopCount( nC) ; ++ nL) {
|
||||
PtrOwner<ICurveComposite> pCrvCompo( ConvertCurveToComposite( vSfr[nS]->GetLoop( nC, nL))) ;
|
||||
for ( int nU = 0 ; nU < pCrvCompo->GetCurveCount() ; ++ nU) {
|
||||
int nProp0 ; pCrvCompo->GetCurveTempProp( nU, nProp0, 0) ;
|
||||
VT.emplace_back( static_cast<IGeoObj*>( pCrvCompo->GetCurve( nU)->Clone())) ;
|
||||
VC.emplace_back( bSfrUniform ? WHITE : ( nProp0 == 0 ? ( bAlphaCoverage ? AQUA : BLUE) : ( bAlphaCoverage ? ORANGE : RED))) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// disegno le curve
|
||||
for ( int nC = 0 ; nC < int( vCompo.size()) ; ++ nC) {
|
||||
if ( vCompo[nC] == nullptr || ! vCompo[nC]->IsValid())
|
||||
continue ;
|
||||
VT.emplace_back( static_cast<IGeoObj*>( vCompo[nC]->Clone())) ;
|
||||
VC.emplace_back( Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, 1.)) ;
|
||||
}
|
||||
|
||||
SaveGeoObj( VT, VC, sName) ;
|
||||
return ;
|
||||
}
|
||||
#endif
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
static double
|
||||
@@ -7374,7 +7421,7 @@ AdjustCloseEsgesForConformalGuide( ICurveComposite* pCrvCompo, const PocketParam
|
||||
if ( IsNull( pMyCompo))
|
||||
return false ;
|
||||
CRVCVECTOR ccClass ;
|
||||
if ( pSfrLimit->GetCurveClassification( *vpCrvs[i], EPS_SMALL, ccClass)) {
|
||||
if ( pSfrLimit->GetCurveClassification( *vpCrvs[i], 125 * EPS_SMALL, ccClass)) {
|
||||
for ( int j = 0 ; j < int( ccClass.size()) ; ++ j) {
|
||||
// recupero il tratto di curva
|
||||
PtrOwner<ICurveComposite> pMyCurve( ConvertCurveToComposite( vpCrvs[i]->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE))) ;
|
||||
@@ -8395,6 +8442,7 @@ GetConformalOffsets( const ISurfFlatRegion* pSfrChunk, const ISurfFlatRegion* pS
|
||||
for ( int j = 0 ; j < int( vCrvOffs[i].size()) ; ++ j)
|
||||
ModifyCurveToSmoothed( vCrvOffs[i][j], PockParam, dSmoothPar, dSmoothPar, false) ;
|
||||
}
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
@@ -8572,7 +8620,7 @@ AddConformal( ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig,
|
||||
bool
|
||||
CalcPocketing( const ISurfFlatRegion* pSfr, double dRad, double dRadOffs, double dStep, double dAngle,
|
||||
int nType, bool bSmooth, bool bInvert, bool bAvoidOpt, bool bAllowZigZagOneWayBorders,
|
||||
const Point3d& ptEndPrec, const ISurfFlatRegion* pSfrLimit, bool bAllOffs, ICRVCOMPOPOVECTOR& vCrvCompoRes)
|
||||
bool bCalcFeed, const Point3d& ptEndPrec, const ISurfFlatRegion* pSfrLimit, bool bAllOffs, ICRVCOMPOPOVECTOR& vCrvCompoRes)
|
||||
{
|
||||
// controllo dei parametri
|
||||
if ( pSfr == nullptr || ! pSfr->IsValid() ||
|
||||
@@ -8594,6 +8642,7 @@ CalcPocketing( const ISurfFlatRegion* pSfr, double dRad, double dRadOffs, double
|
||||
myParams.dSideStep = dStep ;
|
||||
myParams.bInvert = bInvert ;
|
||||
myParams.bAvoidOpt = bAvoidOpt ;
|
||||
myParams.bCalcFeed = bCalcFeed ;
|
||||
myParams.bAllowZigZagOneWayBorders = bAllowZigZagOneWayBorders ;
|
||||
myParams.bOptOffsets = ( ! bAllOffs) ;
|
||||
if ( ptEndPrec.IsValid())
|
||||
|
||||
Binary file not shown.
+404
-16
@@ -22,20 +22,27 @@
|
||||
#include "/EgtDev/Include/EGkPlane3d.h"
|
||||
#include "/EgtDev/Include/EGkStringUtils3d.h"
|
||||
#include "/EgtDev/Include/EgtNumUtils.h"
|
||||
#include "CurveComposite.h"
|
||||
#include "IntersCrvCompoCrvCompo.h"
|
||||
#include "/EgtDev/Extern/fist/Include/api_fist.h"
|
||||
#include <algorithm>
|
||||
|
||||
using namespace std ;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
enum EarStatus{ EAS_NULL = -1, EAS_NO = 0, EAS_OK = 1} ;
|
||||
enum TrgType { TRG_STD = 0, TRG_CAP = 1, TRG_NEEDLE = 2} ;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
static bool ChangeStartPntVector( int nNewStart, PNTVECTOR& vPi) ;
|
||||
static bool MakeByFist( const POLYLINEVECTOR& vPL, PNTVECTOR& vPt, INTVECTOR& vTr) ;
|
||||
static bool RemoveFistInvalidTrg( PNTVECTOR& vPt, INTVECTOR& vTr) ;
|
||||
static int CalcTriangleType( const PNTVECTOR& vPt, const INTVECTOR& vTr, int nTrg) ;
|
||||
static bool FindAdjacentOnLongerEdge( PNTVECTOR& vPt, INTVECTOR& vTr, int nTrgA, int&nEdgeA, int& nTrgB, int& nEdgeB) ;
|
||||
static bool FlipTrg( INTVECTOR& vTr, int nTrgA, int nTrgB, int nEdgeA, int nEdgeB) ;
|
||||
static bool TestAdjacentOnEdge( INTVECTOR& vTr, int nTrgA, int nEdgeA, int nTrgTest1, int nTrgTest2, int& nTrgB, int& nEdgeB) ;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
static bool FORCE_EARCUT_HPP = false ;
|
||||
static bool FORCE_FIST = false ;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// In : PolyLine
|
||||
@@ -49,8 +56,13 @@ Triangulate::Make( const PolyLine& PL, PNTVECTOR& vPt, INTVECTOR& vTr)
|
||||
vPt.clear() ;
|
||||
vTr.clear() ;
|
||||
// verifico che la polilinea contenga almeno 4 punti (primo e ultimo coincidenti)
|
||||
if ( PL.GetPointNbr() < 4)
|
||||
if ( PL.GetPointNbr() < 4 || ! PL.IsClosed())
|
||||
return false ;
|
||||
|
||||
// se fist ( e geometria più complessa di un quadrilatero)
|
||||
if ( FORCE_FIST && PL.GetPointNbr() > 5)
|
||||
return MakeByFist( {PL}, vPt, vTr) ;
|
||||
|
||||
// verifico che la polilinea sia chiusa e piana e calcolo il piano medio del poligono
|
||||
double dArea ;
|
||||
Plane3d plPlane ;
|
||||
@@ -117,6 +129,11 @@ Triangulate::Make( const POLYLINEVECTOR& vPL, PNTVECTOR& vPt, INTVECTOR& vTr)
|
||||
// se una sola polilinea mi riconduco al caso precedente
|
||||
if ( vPL.size() == 1)
|
||||
return Make( vPL[0], vPt, vTr) ;
|
||||
|
||||
// se fist
|
||||
if ( FORCE_FIST)
|
||||
return MakeByFist( vPL, vPt, vTr) ;
|
||||
|
||||
// verifico che la polilinea esterna sia chiusa e piana e calcolo il piano medio del poligono
|
||||
double dArea ;
|
||||
Plane3d plExtPlane ;
|
||||
@@ -134,7 +151,7 @@ Triangulate::Make( const POLYLINEVECTOR& vPL, PNTVECTOR& vPt, INTVECTOR& vTr)
|
||||
if ( ! vPL[i].IsClosedAndFlat( plPlane, dArea2, 50 * EPS_SMALL) ||
|
||||
! AreOppositeVectorApprox( plExtPlane.GetVersN(), plPlane.GetVersN()))
|
||||
return false ;
|
||||
}
|
||||
}
|
||||
|
||||
// forzo esecuzione triangolazione con earcut.hpp
|
||||
if ( FORCE_EARCUT_HPP) {
|
||||
@@ -238,7 +255,7 @@ Triangulate::MakeAdvanced( const POLYLINEVECTOR& vPLORIG, PNTVECTOR& vPt, INTVEC
|
||||
// se non ho PolyLine, allora non faccio nulla
|
||||
if ( vPLORIG.empty())
|
||||
return true ;
|
||||
|
||||
|
||||
POLYLINEVECTOR vPL ;
|
||||
Vector3d vtN ;
|
||||
// se non sono stati passate le info per ordinare le polyline allora le ordino
|
||||
@@ -259,7 +276,7 @@ Triangulate::MakeAdvanced( const POLYLINEVECTOR& vPLORIG, PNTVECTOR& vPt, INTVEC
|
||||
vPL = vPLORIG ;
|
||||
vnPLIndMat = vnPLIndMatPre ;
|
||||
}
|
||||
|
||||
|
||||
// chiamo la Triangolazione per ogni riga della matrice ( quindi su ogni "Chunk")
|
||||
for ( int i = 0 ; i < int( vnPLIndMat.size()) ; ++ i) {
|
||||
PNTVECTOR vPt_tmp ; INTVECTOR vTr_tmp ;
|
||||
@@ -274,7 +291,7 @@ Triangulate::MakeAdvanced( const POLYLINEVECTOR& vPLORIG, PNTVECTOR& vPt, INTVEC
|
||||
for ( int t = 0 ; t < int( vTr_tmp.size()) ; ++ t)
|
||||
vTr.push_back( nSize + vTr_tmp[t]) ;
|
||||
}
|
||||
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
@@ -576,7 +593,7 @@ Triangulate::MakeByEC2( const PNTVECTOR& vPt, INTVECTOR& vTr, double& dMinMinAng
|
||||
// Reset earity of diagonal endpoints
|
||||
vEar[vPrev[i]] = EAS_NULL ;
|
||||
vEar[vNext[i]] = EAS_NULL ;
|
||||
// �Delete� vertex v[i] by redirecting next and previous links
|
||||
// Delete vertex v[i] by redirecting next and previous links
|
||||
// of neighboring verts past it. Decrement vertex count
|
||||
vNext[vPrev[i]] = vNext[i] ;
|
||||
vPrev[vNext[i]] = vPrev[i] ;
|
||||
@@ -714,7 +731,7 @@ Triangulate::MakeByEC3( const PNTVECTOR& vPt, INTVECTOR& vTr, double& dMinMinAng
|
||||
// Reset earity of diagonal endpoints
|
||||
vEar[vPrev[i]] = EAS_NULL ;
|
||||
vEar[vNext[i]] = EAS_NULL ;
|
||||
// �Delete� vertex v[i] by redirecting next and previous links
|
||||
// Delete vertex v[i] by redirecting next and previous links
|
||||
// of neighboring verts past it. Decrement vertex count
|
||||
vNext[vPrev[i]] = vNext[i] ;
|
||||
vPrev[vNext[i]] = vPrev[i] ;
|
||||
@@ -808,7 +825,7 @@ Triangulate::TestTriangle( const PNTVECTOR& vPt, const INTVECTOR& vPol,
|
||||
}
|
||||
}
|
||||
else {
|
||||
// The �ear� triangle is clockwise so v[i] is not an ear
|
||||
// The ear triangle is clockwise so v[i] is not an ear
|
||||
bIsEar = false ;
|
||||
}
|
||||
|
||||
@@ -1153,14 +1170,14 @@ Triangulate::GetOuterPntToJoin( const PNTVECTOR& vPt, const Point3d& ptP, int& n
|
||||
break ;
|
||||
}
|
||||
}
|
||||
// non ho trovato alcunch�, errore
|
||||
// non ho trovato alcunchè, errore
|
||||
if ( nI == - 1)
|
||||
return false ;
|
||||
// se ho trovato un punto esatto del contorno, non devo fare altri controlli
|
||||
if ( AreSamePointApprox( ptInt, vPt[nI]))
|
||||
return true ;
|
||||
// devo ora verificare che il segmento che unisce i punti non intersechi altri lati del contorno esterno
|
||||
// altrimenti tengo il punto con raggio pi� vicino a X_AX o Y_AX o Z_AX secondo m_nPlane
|
||||
// altrimenti tengo il punto con raggio più vicino a X_AX o Y_AX o Z_AX secondo m_nPlane
|
||||
int nJ = nI ;
|
||||
Point3d ptPa = ptP ;
|
||||
Point3d ptPb = vPt[nI] ;
|
||||
@@ -1176,7 +1193,7 @@ Triangulate::GetOuterPntToJoin( const PNTVECTOR& vPt, const Point3d& ptP, int& n
|
||||
double dMinTan = INFINITO ;
|
||||
double dMinSqDist = SQ_INFINITO ;
|
||||
for ( int i = 0 ; i < nNumPt ; ++ i) {
|
||||
// salto il punto gi� trovato
|
||||
// salto il punto già trovato
|
||||
if ( i == nJ)
|
||||
continue ;
|
||||
// verifico se sta nel triangolo
|
||||
@@ -1212,7 +1229,7 @@ Triangulate::GetOuterPntToJoin( const PNTVECTOR& vPt, const Point3d& ptP, int& n
|
||||
bool
|
||||
Triangulate::PointInSector( const Point3d& ptTest, const Point3d& ptPrev, const Point3d& ptCorn, const Point3d& ptNext)
|
||||
{
|
||||
// la parte valida del settore � a sinistra dei segmenti ptPrev --> ptCorn --> ptNext
|
||||
// la parte valida del settore è a sinistra dei segmenti ptPrev --> ptCorn --> ptNext
|
||||
// se corner convesso
|
||||
if ( TriangleIsCCW( ptPrev, ptCorn, ptNext, 0))
|
||||
return ( TriangleIsCCW( ptPrev, ptCorn, ptTest) &&
|
||||
@@ -1227,13 +1244,384 @@ Triangulate::PointInSector( const Point3d& ptTest, const Point3d& ptPrev, const
|
||||
bool
|
||||
ChangeStartPntVector( int nNewStart, PNTVECTOR& vPi)
|
||||
{
|
||||
// se il nuovo inizio coincide col vecchio, non devo fare alcunch�
|
||||
// se il nuovo inizio coincide col vecchio, non devo fare alcunchè
|
||||
if ( nNewStart == 0)
|
||||
return true ;
|
||||
// se il nuovo indice � oltre la dimensione del vettore, errore
|
||||
// se il nuovo indice è oltre la dimensione del vettore, errore
|
||||
if ( nNewStart >= int( vPi.size()))
|
||||
return false ;
|
||||
// ciclo di aggiustamento
|
||||
rotate( vPi.begin(), vPi.begin() + nNewStart, vPi.end()) ;
|
||||
return true ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Funzioni per triangolare usando la libreria FIST
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
int
|
||||
CalcTriangleType( const PNTVECTOR& vPt, const INTVECTOR& vTr, int nTrg)
|
||||
{
|
||||
Vector3d vtV1 = vPt[vTr[3*nTrg + 1]] - vPt[vTr[3*nTrg]] ;
|
||||
Vector3d vtV2 = vPt[vTr[3*nTrg + 2]] - vPt[vTr[3*nTrg + 1]] ;
|
||||
Vector3d vtN = vtV1 ^ vtV2 ;
|
||||
double dSqN = vtN.SqLen() ;
|
||||
|
||||
double dSqLen1 = vtV1.SqLen() ;
|
||||
double dSqLen2 = vtV2.SqLen() ;
|
||||
double dSqLen3 = ( vtV1 + vtV2).SqLen() ;
|
||||
// un triangolo è invalido ( needle o cap) se viene scartato dai controlli di AddTriangle
|
||||
if ( dSqN < SQ_EPS_ZERO || dSqN < SQ_EPS_TRIA_H * max( {dSqLen1, dSqLen2, dSqLen3})) {
|
||||
if ( dSqLen1 < SQ_EPS_ZERO || dSqLen2 < SQ_EPS_ZERO || dSqLen3 < SQ_EPS_ZERO)
|
||||
return TRG_NEEDLE ;
|
||||
else
|
||||
return TRG_CAP ;
|
||||
}
|
||||
else
|
||||
return TRG_STD ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
FlipTrg( INTVECTOR& vTr, int nTA, int nTB, int nEA, int nEB)
|
||||
{
|
||||
vTr[3*nTA + nEA] = vTr[3*nTB + ( nEB + 2) % 3] ;
|
||||
vTr[3*nTB + nEB] = vTr[3*nTA + ( nEA + 2) % 3] ;
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
TestAdjacentOnEdge( INTVECTOR& vTr, int nTA, int nEA, int nTTest1, int nTTest2, int& nTB, int& nEB)
|
||||
{
|
||||
// individuo quale triangolo tra nTTest1 e nTTest2 è quello adiacente a nTA lungo il lato nEA
|
||||
nTB = -1 ;
|
||||
nEB = -1 ;
|
||||
// recupero i vertici di nEA
|
||||
int nV1 = vTr[3*nTA + nEA] ;
|
||||
int nV2 = vTr[3*nTA + ( nEA + 1) % 3] ;
|
||||
|
||||
// verifico se è TTest1 quello adiacente
|
||||
if ( vTr[3*nTTest1] == nV2 && vTr[3*nTTest1+1] == nV1) {
|
||||
nEB = 0 ;
|
||||
nTB = nTTest1 ;
|
||||
}
|
||||
else if ( vTr[3*nTTest1+1] == nV2 && vTr[3*nTTest1+2] == nV1) {
|
||||
nEB = 1 ;
|
||||
nTB = nTTest1 ;
|
||||
}
|
||||
else if ( vTr[3*nTTest1] == nV1 && vTr[3*nTTest1+2] == nV2) {
|
||||
nEB = 2 ;
|
||||
nTB = nTTest1 ;
|
||||
}
|
||||
// verifico se è TTest2 quello adiacente
|
||||
else if ( vTr[3*nTTest2] == nV2 && vTr[3*nTTest2+1] == nV1) {
|
||||
nEB = 0 ;
|
||||
nTB = nTTest2 ;
|
||||
}
|
||||
else if ( vTr[3*nTTest2+1] == nV2 && vTr[3*nTTest2+2] == nV1) {
|
||||
nEB = 1 ;
|
||||
nTB = nTTest2 ;
|
||||
}
|
||||
else if ( vTr[3*nTTest2] == nV1 && vTr[3*nTTest2+2] == nV2) {
|
||||
nEB = 2 ;
|
||||
nTB = nTTest2 ;
|
||||
}
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
FindAdjacentOnLongerEdge( PNTVECTOR& vPt, INTVECTOR& vTr, int nTA, int& nEA, int& nTB, int& nEB)
|
||||
{
|
||||
// recupero il lato più lungo del triangolo nTA
|
||||
nEA = -1 ;
|
||||
double dMaxLen = -1 ;
|
||||
for ( int j = 0 ; j < 3 ; j++) {
|
||||
double dCurrLen = SqDist( vPt[vTr[3*nTA + j]], vPt[vTr[3*nTA + ( j+1)%3]]) ;
|
||||
if ( dCurrLen > dMaxLen) {
|
||||
dMaxLen = dCurrLen ;
|
||||
nEA = j ;
|
||||
}
|
||||
}
|
||||
|
||||
// cerco il triangolo nTB adiacente a nTA lungo nEA
|
||||
nTB = -1 ;
|
||||
nEB = -1 ;
|
||||
int nV1 = vTr[3*nTA + nEA] ;
|
||||
int nV2 = vTr[3*nTA + ( nEA + 1) % 3] ;
|
||||
int nTria = vTr.size() / 3 ;
|
||||
for ( int j = 0 ; j < nTria ; j++) {
|
||||
if ( j == nTA)
|
||||
continue ;
|
||||
if ( vTr[3*j] == nV2 && vTr[3*j+1] == nV1) {
|
||||
nEB = 0 ;
|
||||
nTB = j ;
|
||||
break ;
|
||||
}
|
||||
else if ( vTr[3*j+1] == nV2 && vTr[3*j+2] == nV1) {
|
||||
nEB = 1 ;
|
||||
nTB = j ;
|
||||
break ;
|
||||
}
|
||||
else if ( vTr[3*j] == nV1 && vTr[3*j+2] == nV2) {
|
||||
nEB = 2 ;
|
||||
nTB = j ;
|
||||
break ;
|
||||
}
|
||||
}
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
RemoveFistInvalidTrg( PNTVECTOR& vPt, INTVECTOR& vTr)
|
||||
{
|
||||
// scorro tutti i triangoli alla ricerca di triangoli validi per FIST ma invalidi per le nostre tolleranze.
|
||||
// I triangoli invalidi possono essere di due tipologie: cap o needle.
|
||||
// I triangoli cap se eliminati danno origine a T-junctions, quindi devono essere gestiti opportunamente con dei flip.
|
||||
// I triangoli needle se eliminati non sono problematici, ma i loro vertici coincidenti vanno gestiti opportunamente nel
|
||||
// calcolo delle adiacenze dei triangoli cap.
|
||||
|
||||
int nTria = int( vTr.size()) / 3 ;
|
||||
INTVECTOR vCapTria ;
|
||||
INTVECTOR vNeedleTria ;
|
||||
BOOLVECTOR vbIsValidTria( nTria, true) ;
|
||||
bool bRemovedTrg = false ;
|
||||
|
||||
for ( int i = 0 ; i < nTria ; i ++) {
|
||||
int nTrgType = CalcTriangleType( vPt, vTr, i) ;
|
||||
if ( nTrgType == TRG_CAP) {
|
||||
vbIsValidTria[i] = false ;
|
||||
vCapTria.emplace_back( i) ;
|
||||
}
|
||||
else if ( nTrgType == TRG_NEEDLE) {
|
||||
vNeedleTria.emplace_back( i) ;
|
||||
}
|
||||
}
|
||||
|
||||
// se non ci sono triangoli cap non c'è bisogno di modifiche
|
||||
if ( vCapTria.empty())
|
||||
return true ;
|
||||
|
||||
// 1) elimino i triangoli di tipo needle gestendo i vertici coincidenti
|
||||
if ( ! vNeedleTria.empty()) {
|
||||
bRemovedTrg = true ;
|
||||
for ( int i = 0 ; i < int( vNeedleTria.size()) ; i++) {
|
||||
int nT = vNeedleTria[i] ;
|
||||
if ( vTr[3*nT] != vTr[3*nT+1] && vTr[3*nT] != vTr[3*nT+2] && vTr[3*nT+1] != vTr[3*nT+2]) {
|
||||
// individuo i vertici coincidenti
|
||||
int nOldId = -1 ;
|
||||
int nNewId = -1 ;
|
||||
Vector3d vtV1 = vPt[vTr[3*nT+1]] - vPt[vTr[3*nT]] ;
|
||||
if ( vtV1.SqLen() < SQ_EPS_ZERO) {
|
||||
// vertici coincidenti 0 e 1
|
||||
nOldId = vTr[3*nT] ;
|
||||
nNewId = vTr[3*nT+1] ;
|
||||
}
|
||||
else {
|
||||
Vector3d vtV2 = vPt[vTr[3*nT+2]] - vPt[vTr[3*nT+1]] ;
|
||||
if ( vtV2.SqLen() < SQ_EPS_ZERO) {
|
||||
// vertici coincidenti 1 e 2
|
||||
nOldId = vTr[3*nT+1] ;
|
||||
nNewId = vTr[3*nT+2] ;
|
||||
}
|
||||
else {
|
||||
// vertici coincidenti 0 e 2
|
||||
nOldId = vTr[3*nT] ;
|
||||
nNewId = vTr[3*nT+2] ;
|
||||
}
|
||||
}
|
||||
// aggiorno il vettore dei triangoli unificando i vertici coincidenti
|
||||
for ( int k = 0 ; k < int( vTr.size()) ; k ++) {
|
||||
if ( vTr[k] == nOldId)
|
||||
vTr[k] = nNewId ;
|
||||
}
|
||||
}
|
||||
// annullo il triangolo
|
||||
vTr[3*nT] = -1 ;
|
||||
vTr[3*nT+1] = -1 ;
|
||||
vTr[3*nT+2] = -1 ;
|
||||
}
|
||||
}
|
||||
|
||||
// 2) sistemo i triangoli di tipo cap
|
||||
for ( int i = 0 ; i < int( vCapTria.size()) ; i++) {
|
||||
|
||||
int nTA = vCapTria[i] ;
|
||||
// verifico se il triangolo è già stato resto valido ( da una catena)
|
||||
if ( vbIsValidTria[nTA])
|
||||
continue ;
|
||||
|
||||
// trovo l'adiacenza sul suo lato più lungo
|
||||
int nEA = -1 ;
|
||||
int nEB = -1 ;
|
||||
int nTB = -1 ;
|
||||
FindAdjacentOnLongerEdge( vPt, vTr, nTA, nEA, nTB, nEB) ;
|
||||
|
||||
if ( nTB == -1) {
|
||||
// se non ha un triangolo adiacente posso annullarlo
|
||||
vTr[3*nTA] = -1 ;
|
||||
vTr[3*nTA+1] = -1 ;
|
||||
vTr[3*nTA+2] = -1 ;
|
||||
vbIsValidTria[nTA] = true ;
|
||||
bRemovedTrg = true ;
|
||||
continue ;
|
||||
}
|
||||
else if ( vbIsValidTria[nTB]) {
|
||||
// se è adiacente è valido, eseguo il flip
|
||||
FlipTrg( vTr, nTA, nTB, nEA, nEB) ;
|
||||
vbIsValidTria[nTA] = true ;
|
||||
}
|
||||
else {
|
||||
// se adiacente è invalido, individuo una catena di triangoli invalidi da risolvere non appena si indentifica
|
||||
// adiacenza con triangolo valido
|
||||
INTVECTOR vChain, vChainEdges ;
|
||||
vChain.emplace_back( nTA) ;
|
||||
vChainEdges.emplace_back( nEA) ;
|
||||
|
||||
while ( nTB != -1 && ! vbIsValidTria[nTB]) {
|
||||
// aggiungo alla catena
|
||||
vChain.emplace_back( nTB) ;
|
||||
|
||||
// calcolo il successivo
|
||||
nTA = nTB ;
|
||||
FindAdjacentOnLongerEdge( vPt, vTr, nTA, nEA, nTB, nEB) ;
|
||||
vChainEdges.emplace_back( nEA) ;
|
||||
|
||||
// verifico di non aver trovato un'adiacenza ambigua ( ovvero due triangoli invalidi adiacenti sui loro lati più lunghi)
|
||||
// e quindi di non essere entrato in un loop
|
||||
if ( nTB == vChain[vChain.size()-2]) {
|
||||
// flip dei due triangoli per modificare il lato più lungo e togliere adiacenza ambigua
|
||||
FlipTrg( vTr, nTA, nTB, nEA, nEB) ;
|
||||
// aggiorno per iterazione successiva
|
||||
if ( vChain.size() == 2) {
|
||||
vChain.pop_back() ;
|
||||
vChainEdges.pop_back() ;
|
||||
FindAdjacentOnLongerEdge( vPt, vTr, vChain.back(), nEA, nTB, nEB) ;
|
||||
vChainEdges[0] = nEA ;
|
||||
}
|
||||
else {
|
||||
// elimino gli ultimi due triangoli che sono appena stati flippati e ricalcolo adiacenza del triangolo
|
||||
// precedente
|
||||
vChain.pop_back() ;
|
||||
vChain.pop_back() ;
|
||||
vChainEdges.pop_back() ;
|
||||
vChainEdges.pop_back() ;
|
||||
int nTTest1 = nTA ;
|
||||
int nTTest2 = nTB ;
|
||||
TestAdjacentOnEdge( vTr, vChain.back(), vChainEdges.back(), nTTest1, nTTest2, nTB, nEB) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// se la catena termina su triangolo nullo, annullo tutti i triangoli della catena
|
||||
if ( nTB == -1) {
|
||||
bRemovedTrg = true ;
|
||||
for ( int k = 0 ; k < int( vChain.size()) ; k++) {
|
||||
vTr[3*vChain[k]] = -1 ;
|
||||
vTr[3*vChain[k] + 1] = -1 ;
|
||||
vTr[3*vChain[k] + 2] = -1 ;
|
||||
vbIsValidTria[vChain[k]] = true ;
|
||||
}
|
||||
}
|
||||
// se catena termina su un triangolo valido, applico il flip a cascata a partire dall'ultimo triangolo invalido
|
||||
else {
|
||||
FlipTrg( vTr, vChain.back(), nTB, vChainEdges.back(), nEB) ;
|
||||
vbIsValidTria[vChain.back()] = true ;
|
||||
int nTrgTest1 = vChain.back() ;
|
||||
int nTrgTest2 = nTB ;
|
||||
for ( int i = int( vChain.size()-2) ; i >= 0 ; i--) {
|
||||
// triangolo corrente
|
||||
int nTA = vChain[i] ;
|
||||
int nEA = vChainEdges[i] ;
|
||||
// devo trovare il nuovo adiacente dopo il flip dei successivi nella catena
|
||||
TestAdjacentOnEdge( vTr, nTA, nEA, nTrgTest1, nTrgTest2, nTB, nEB) ;
|
||||
// flip per rendere valido il triangolo corrente
|
||||
FlipTrg( vTr, nTA, nTB, nEA, nEB) ;
|
||||
vbIsValidTria[nTA] = true ;
|
||||
// aggiorno i trg di test per lo step successivo
|
||||
nTrgTest1 = nTA ;
|
||||
nTrgTest2 = nTB ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// se sono stati annullati dei triangoli, li rimuovo dal vettore
|
||||
if ( bRemovedTrg) {
|
||||
INTVECTOR vTrTmp ;
|
||||
vTrTmp.reserve( vTr.size()) ;
|
||||
for ( int i = 0 ; i < int( vTr.size()) ; i++)
|
||||
if ( vTr[i] != -1)
|
||||
vTrTmp.emplace_back( vTr[i]) ;
|
||||
swap( vTr, vTrTmp) ;
|
||||
}
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
MakeByFist( const POLYLINEVECTOR& vPL, PNTVECTOR& vPt, INTVECTOR& vTr)
|
||||
{
|
||||
// opzioni di triangolazione
|
||||
rt_options rt_opt ;
|
||||
InitDefaults( &rt_opt) ;
|
||||
rt_opt.ears_top = false ;
|
||||
rt_opt.ears_random = false ;
|
||||
rt_opt.ears_sorted = true ;
|
||||
rt_opt.ears_fancy = true ;
|
||||
|
||||
// creo oggetto di fist per triangolazione
|
||||
global_struct fist ;
|
||||
InitGlobalStruct( &fist, &rt_opt, true) ;
|
||||
|
||||
// allocazione ottimizzata degli array di fist
|
||||
int nLoops = int( vPL.size()) ;
|
||||
int nVertices = 0 ;
|
||||
for ( int i = 0 ; i < nLoops ; i ++)
|
||||
nVertices += ( vPL[i].GetPointNbr() - 1) ;
|
||||
OptimizeMemoryAllocation( &fist, nLoops, nVertices) ;
|
||||
|
||||
// assegno i dati a fist
|
||||
for ( int i = 0 ; i < nLoops ; i ++) {
|
||||
// salvo i vertici saltando il primo punto ( coincide con l'ultimo)
|
||||
Point3d pt ;
|
||||
if ( ! vPL[i].GetFirstPoint( pt))
|
||||
return false ;
|
||||
while ( vPL[i].GetNextPoint( pt))
|
||||
StoreVertex( &fist.c_vertex, pt.x, pt.y, pt.z) ;
|
||||
// salvo il loop
|
||||
int nPoints = vPL[i].GetPointNbr() ;
|
||||
AddLoopInFace( &fist, nLoops - 1, i == 0, nPoints - 1) ;
|
||||
}
|
||||
StoreGroupNumber( &fist.c_list, &fist.c_vertex) ;
|
||||
|
||||
// eseguo triangolazione
|
||||
Triangulate( &fist) ;
|
||||
|
||||
// recupero i vertici da fist
|
||||
vPt.reserve( fist.c_vertex.num_vertices) ;
|
||||
for ( int i = 0 ; i < fist.c_vertex.num_vertices ; i ++)
|
||||
vPt.emplace_back( fist.c_vertex.vertices[i].x, fist.c_vertex.vertices[i].y, fist.c_vertex.vertices[i].z) ;
|
||||
|
||||
// recupero i triangoli da fist
|
||||
vTr.reserve( 3 * fist.c_vertex.num_triangles) ;
|
||||
for ( int i = 0 ; i < fist.c_vertex.num_triangles ; i ++) {
|
||||
vTr.emplace_back( fist.c_vertex.triangles[i].v1) ;
|
||||
vTr.emplace_back( fist.c_vertex.triangles[i].v2) ;
|
||||
vTr.emplace_back( fist.c_vertex.triangles[i].v3) ;
|
||||
}
|
||||
|
||||
// rimuovo eventuali triangoli validi per fist ma invalidi per le nostre tolleranze
|
||||
RemoveFistInvalidTrg( vPt, vTr) ;
|
||||
|
||||
// chiudo fist e dealloco la sua memoria
|
||||
FIST_TerminateProgram( &fist) ;
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
#pragma comment(lib, EGTEXTDIR "zlib/Lib/zlib" EGTLIBVER ".lib")
|
||||
#pragma comment(lib, EGTEXTDIR "vroni/Lib/vroni" EGTLIBVER ".lib")
|
||||
#pragma comment(lib, EGTEXTDIR "fist/Lib/fist" EGTLIBVER ".lib")
|
||||
#pragma comment(lib, EGTLIBDIR "EgtGeneral" EGTLIBVER ".lib")
|
||||
#pragma comment(lib, EGTLIBDIR "EgtNumKernel" EGTLIBVER ".lib")
|
||||
#pragma comment(lib, EGTLIBDIR "SEgtLock" EGTLIBVER ".lib")
|
||||
|
||||
Reference in New Issue
Block a user