diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index c10778f..fad7a02 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -79,6 +79,53 @@ static double TOL_TRAPEZOID = 50 * EPS_SMALL ; // tolleranza per casi a trapezio typedef vector 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 VT ; + vector 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( 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 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( 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( 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 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()) diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc index 7518f17..77d8328 100644 Binary files a/EgtGeomKernel.rc and b/EgtGeomKernel.rc differ diff --git a/Triangulate.cpp b/Triangulate.cpp index 0f60c4e..8545f2c 100644 --- a/Triangulate.cpp +++ b/Triangulate.cpp @@ -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 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 ; +} diff --git a/stdafx.h b/stdafx.h index 74264f5..b85a1e6 100644 --- a/stdafx.h +++ b/stdafx.h @@ -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")