From 0b37e12df9a9ce13fc7dafca182b82a73867df77 Mon Sep 17 00:00:00 2001 From: LorenzoM Date: Wed, 21 Apr 2021 17:52:35 +0200 Subject: [PATCH] Fix Operazioni booleane e taglio trimesh con un piano --- IntersSurfTmSurfTm.cpp | 10 +- IntersTriaTria.cpp | 388 ++++++- SfrCreate.cpp | 63 ++ SurfTriMesh.cpp | 86 +- SurfTriMesh.h | 90 ++ SurfTriMeshBooleans.cpp | 2237 ++++++++++++++++++++++++++++++++++++++- 6 files changed, 2777 insertions(+), 97 deletions(-) diff --git a/IntersSurfTmSurfTm.cpp b/IntersSurfTmSurfTm.cpp index 5427444..c12ccc3 100644 --- a/IntersSurfTmSurfTm.cpp +++ b/IntersSurfTmSurfTm.cpp @@ -75,10 +75,10 @@ IntersSurfTmSurfTm( const ISurfTriMesh& Stm1, const ISurfTriMesh& Stm2, // intersezione tra i triangoli Point3d ptInt, ptInt2 ; TRIA3DVECTOR vIttTria ; - int nResEx = IntersTriaTria( TriaA, TriaB, ptInt, ptInt2, vIttTria) ; - int nRes = FromSpecialToNormal( nResEx) ; + int nRes = IntersTriaTria( TriaA, TriaB, ptInt, ptInt2, vIttTria) ; // se punto - if ( nRes == ITTT_VERT || nRes == ITTT_PNT) { + if ( nRes == ITTT_VERT_VERT || nRes == ITTT_VERT_EDGE || nRes == ITTT_VERT_INT || + nRes == ITTT_EDGE_VERT || nRes == ITTT_EDGE_EDGE_PNT || nRes == ITTT_INT_VERT) { // verifico se punto già inserito int nId ; if ( ! PtGrid.Find( ptInt, 10 * EPS_SMALL, nId)) { @@ -87,7 +87,8 @@ IntersSurfTmSurfTm( const ISurfTriMesh& Stm1, const ISurfTriMesh& Stm2, } } // se altrimenti segmento - else if ( nRes == ITTT_EDGE || nRes == ITTT_YES) { + else if ( nRes == ITTT_EDGE_EDGE_SEG || nRes == ITTT_EDGE_INT || + nRes == ITTT_INT_EDGE || nRes == ITTT_INT_INT_SEG ) { // se abbastanza lungo if ( ! AreSamePointApprox( ptInt, ptInt2)) { // verifico se già inserito @@ -217,3 +218,4 @@ IntersSurfTmSurfTm( const ISurfTriMesh& Stm1, const ISurfTriMesh& Stm2, return true ; } + diff --git a/IntersTriaTria.cpp b/IntersTriaTria.cpp index 793429c..8aa5378 100644 --- a/IntersTriaTria.cpp +++ b/IntersTriaTria.cpp @@ -25,20 +25,16 @@ using namespace std ; -//---------------------------------------------------------------------------- -int nTriaTriaIntersCases[6][6] = { { ITTTS_NO, ITTTS_NO, ITTTS_NO, ITTTS_NO, ITTTS_NO, ITTTS_NO }, - { ITTTS_NO, ITTTS_INT_INT_SEG, ITTTS_INT_EDGE, ITTTS_NO, ITTTS_NO, ITTTS_NO }, - { ITTTS_NO, ITTTS_EDGE_INT, ITTTS_EDGE_EDGE_SEG, ITTTS_NO, ITTTS_NO, ITTTS_NO }, - { ITTTS_NO, ITTTS_NO, ITTTS_NO, ITTTS_VERT_VERT, ITTTS_VERT_EDGE, ITTTS_VERT_INT }, - { ITTTS_NO, ITTTS_NO, ITTTS_NO, ITTTS_EDGE_VERT, ITTTS_EDGE_EDGE_PNT, ITTTS_NO }, - { ITTTS_NO, ITTTS_NO, ITTTS_NO, ITTTS_INT_VERT, ITTTS_NO, ITTTS_NO } } ; - //---------------------------------------------------------------------------- static int IntersCoplanarTriaTria( const Triangle3d& trTria1, const Triangle3d& trTria2, TRIA3DVECTOR& vTria) ; +//---------------------------------------------------------------------------- +static int FindTriaTriaIntersType( const Triangle3d& trTria1, const Triangle3d& trTria2, const Point3d& ptLineSt, const Vector3d& vtLineDir, + double dStU1, double dEnU1, double dStU2, double dEnU2, int nRes1, int nRes2, double& dIntStU, double& dIntEnU) ; + //---------------------------------------------------------------------------- int -IntersTriaTria( const Triangle3d& trTria1, const Triangle3d& trTria2, Point3d& ptInt, Point3d& ptInt2, TRIA3DVECTOR& vTria) +IntersTriaTria( const Triangle3d& trTria1, const Triangle3d& trTria2, Point3d& ptInt, Point3d& ptInt2, TRIA3DVECTOR& vTria, bool bSpecial) { // piano del secondo triangolo Plane3d plTria2 ; @@ -79,8 +75,8 @@ IntersTriaTria( const Triangle3d& trTria1, const Triangle3d& trTria2, Point3d& p return ITTT_NO ; // intersezione tra i piani dei due triangoli - Point3d ptL1 ; Vector3d vtL1 ; - int nResPP = IntersPlanePlane( plTria1, plTria2, ptL1, vtL1) ; + Point3d ptL ; Vector3d vtL ; + int nResPP = IntersPlanePlane( plTria1, plTria2, ptL, vtL) ; if ( nResPP == IPPT_NO) return ITTT_NO ; @@ -91,47 +87,22 @@ IntersTriaTria( const Triangle3d& trTria1, const Triangle3d& trTria2, Point3d& p return IntersCoplanarTriaTria( trTria1, trTria2, vTria) ; // limito la linea di intersezione con il primo triangolo - int nRes1 = IntersCoplanarLineTria( ptL1, vtL1, 100.0, trTria1, ptInt, ptInt2, false) ; - if ( nRes1 == ILTT_NO) - return ITTT_NO ; - - // il segmento calcolato va limitato col secondo triangolo - Point3d ptL2 = ptInt ; - Vector3d vtL2 = vtL1 ; - double dLen = 0 ; - if ( nRes1 != ILTT_VERT) { - vtL2 = ptInt2 - ptInt ; - dLen = vtL2.Len() ; - vtL2 /= dLen ; - } - Point3d ptI1 = ptInt ; - Point3d ptI12 = ptInt2 ; - int nRes2 = IntersCoplanarLineTria( ptL2, vtL2, dLen, trTria2, ptInt, ptInt2, true) ; - - // gestione casi speciali apparentemente incongruenti - if ( ( nRes1 == ILTT_SEGM && nRes2 == ILTT_EDGE) || ( nRes1 == ILTT_EDGE && nRes2 == ILTT_SEGM)) { - if ( nRes1 == ILTT_SEGM) { - if ( PointInTria( ptI1, trTria2) != PTT_OUT && PointInTria( ptI12, trTria2) != PTT_OUT) { - ptInt = ( ptI1 + ptI12) / 2 ; - ptInt2 = ( ptI1 + ptI12) / 2 ; - return ITTTS_EDGE_EDGE_PNT ; - } - else - return ITTTS_NO ; - } - else { - Point3d ptI3, ptI32 ; - IntersCoplanarLineTria( ptL1, vtL1, 100.0, trTria2, ptI3, ptI32, false) ; - if ( PointInTria( ptI3, trTria1) != PTT_OUT && PointInTria( ptI32, trTria1) != PTT_OUT) { - ptInt = ( ptI3 + ptI32) / 2 ; - ptInt2 = ( ptI3 + ptI32) / 2 ; - return ITTTS_EDGE_EDGE_PNT ; - } - else - return ITTTS_NO ; - } + Point3d ptSt1, ptEn1 ; + int nRes1 = IntersCoplanarLineTria( ptL, vtL, 100.0, trTria1, ptSt1, ptEn1, false) ; + // limito la liena di intersezione con il secondo triangolo + Point3d ptSt2, ptEn2 ; + int nRes2 = IntersCoplanarLineTria( ptL, vtL, 100.0, trTria2, ptSt2, ptEn2, false) ; + double dIntStU, dIntEnU; + int nIntType = FindTriaTriaIntersType( trTria1, trTria2, ptL, vtL, + ( ptSt1 - ptL) * vtL, ( ptEn1 - ptL) * vtL, + ( ptSt2 - ptL) * vtL, ( ptEn2 - ptL) * vtL, + nRes1, nRes2, dIntStU, dIntEnU) ; + if ( nIntType != ITTT_NO) { + ptInt = ptL + dIntStU * vtL ; + ptInt2 = ptL + dIntEnU * vtL ; + return nIntType ; } - return nTriaTriaIntersCases[nRes1][nRes2] ; + return ITTT_NO; } //---------------------------------------------------------------------------- @@ -225,3 +196,318 @@ IntersCoplanarTriaTria( const Triangle3d& trTria1, const Triangle3d& trTria2, TR return ITTT_OVERLAPS ; } + +//---------------------------------------------------------------------------- +int +FindTriaTriaIntersType( const Triangle3d& trTria1, const Triangle3d& trTria2, const Point3d& ptLineSt, const Vector3d& vtLineDir, + double dStU1, double dEnU1, double dStU2, double dEnU2, int nRes1, int nRes2, double& dIntStU, double& dIntEnU) +{ + // Controllo su validità input + if ( ! ( trTria1.IsValid() && trTria2.IsValid() && vtLineDir.IsNormalized())) + return ITTT_NO ; + // Casi + if ( nRes1 == ILTT_SEGM) { + if ( nRes2 == ILTT_SEGM) { + if ( dEnU2 < dStU1 - EPS_SMALL) + return ITTT_NO ; + else if ( dEnU2 < dStU1 + EPS_SMALL) { + dIntStU = 0.5 * ( dStU1 + dEnU2) ; + dIntEnU = 0.5 * ( dStU1 + dEnU2) ; + Point3d ptInt = ptLineSt + dIntStU * vtLineDir ; + bool bOnVert1 = false ; + bool bOnVert2 = false ; + for ( int n = 0 ; n < 3 ; ++ n) { + if ( AreSamePointApprox( trTria1.GetP( n), ptInt)) + bOnVert1 = true ; + if ( AreSamePointApprox( trTria2.GetP( n), ptInt)) + bOnVert2 = true ; + } + if ( bOnVert1) { + if ( bOnVert2) + return ITTT_VERT_VERT ; + else + return ITTT_VERT_EDGE ; + } + else if ( bOnVert2) + return ITTT_EDGE_VERT ; + else + return ITTT_EDGE_EDGE_PNT ; + } + else if ( dStU2 < dEnU1 - EPS_SMALL) { + dIntStU = max( dStU1, dStU2) ; + dIntEnU = min( dEnU1, dEnU2) ; + return ITTT_INT_INT_SEG ; + } + else if ( dStU2 < dEnU1 + EPS_SMALL) { + dIntStU = 0.5 * ( dStU2 + dEnU1) ; + dIntEnU = 0.5 * ( dStU2 + dEnU1) ; + Point3d ptInt = ptLineSt + dIntStU * vtLineDir ; + bool bOnVert1 = false; + bool bOnVert2 = false; + for ( int n = 0 ; n < 3 ; ++ n) { + if ( AreSamePointApprox( trTria1.GetP( n), ptInt)) + bOnVert1 = true ; + if ( AreSamePointApprox( trTria2.GetP( n), ptInt)) + bOnVert2 = true ; + } + if ( bOnVert1) { + if ( bOnVert2) + return ITTT_VERT_VERT ; + else + return ITTT_VERT_EDGE ; + } + else if ( bOnVert2) + return ITTT_EDGE_VERT ; + else + return ITTT_EDGE_EDGE_PNT ; + } + else + return ITTT_NO ; + } + else if ( nRes2 == ILTT_SEGM_ON_EDGE) { + if ( dEnU2 < dStU1 - EPS_SMALL) + return ITTT_NO ; + else if ( dEnU2 < dStU1 + EPS_SMALL) { + dIntStU = 0.5 * ( dStU1 + dEnU2) ; + dIntEnU = 0.5 * ( dStU1 + dEnU2) ; + Point3d ptInt = ptLineSt + dIntStU * vtLineDir ; + bool bOnVert1 = false ; + for ( int n = 0 ; n < 3 ; ++ n) { + if ( AreSamePointApprox( trTria1.GetP( n), ptInt)) + bOnVert1 = true ; + } + if ( bOnVert1) + return ITTT_VERT_VERT ; + else + return ITTT_EDGE_VERT ; + } + else if ( dStU2 < dEnU1 - EPS_SMALL) { + dIntStU = max( dStU1, dStU2) ; + dIntEnU = min( dEnU1, dEnU2) ; + return ITTT_INT_EDGE ; + } + else if ( dStU2 < dEnU1 + EPS_SMALL) { + dIntStU = 0.5 * ( dStU2 + dEnU1) ; + dIntEnU = 0.5 * ( dStU2 + dEnU1) ; + Point3d ptInt = ptLineSt + dIntStU * vtLineDir ; + bool bOnVert1 = false ; + for ( int n = 0 ; n < 3 ; ++ n) { + if ( AreSamePointApprox( trTria1.GetP( n), ptInt)) + bOnVert1 = true ; + } + if ( bOnVert1) + return ITTT_VERT_VERT ; + else + return ITTT_EDGE_VERT ; + } + else + return ITTT_NO ; + } + else if ( nRes2 == ILTT_VERT) { + dEnU2 = dStU2 ; + if ( dStU2 < dStU1 - EPS_SMALL) + return ITTT_NO ; + else if ( dStU2 < dStU1 + EPS_SMALL) { + dIntStU = 0.5 * ( dStU1 + dStU2) ; + dIntEnU = 0.5 * ( dStU1 + dStU2) ; + Point3d ptInt = ptLineSt + dIntStU * vtLineDir ; + bool bOnVert1 = false ; + for ( int n = 0 ; n < 3 ; ++ n) { + if ( AreSamePointApprox( trTria1.GetP( n), ptInt)) + bOnVert1 = true ; + } + if ( bOnVert1) + return ITTT_VERT_VERT ; + else + return ITTT_EDGE_VERT ; + } + else if ( dStU2 < dEnU1 - EPS_SMALL) { + dIntStU = max( dStU1, dStU2) ; + dIntEnU = min( dEnU1, dEnU2) ; + return ITTT_INT_VERT ; + } + else if ( dStU2 < dEnU1 + EPS_SMALL) { + dIntStU = 0.5 * ( dStU2 + dEnU1) ; + dIntEnU = 0.5 * ( dStU2 + dEnU1) ; + Point3d ptInt = ptLineSt + dIntStU * vtLineDir ; + bool bOnVert1 = false ; + for ( int n = 0 ; n < 3 ; ++ n) { + if ( AreSamePointApprox( trTria1.GetP( n), ptInt)) + bOnVert1 = true ; + } + if ( bOnVert1) + return ITTT_VERT_VERT ; + else + return ITTT_EDGE_VERT ; + } + else + return ITTT_NO ; + } + else + return ITTT_NO ; + } + else if ( nRes1 == ILTT_SEGM_ON_EDGE) { + if ( nRes2 == ILTT_SEGM) { + if ( dEnU2 < dStU1 - EPS_SMALL) + return ITTT_NO ; + else if ( dEnU2 < dStU1 + EPS_SMALL) { + dIntStU = 0.5 * ( dStU1 + dEnU2) ; + dIntEnU = 0.5 * ( dStU1 + dEnU2) ; + Point3d ptInt = ptLineSt + dIntStU * vtLineDir ; + bool bOnVert2 = false ; + for ( int n = 0 ; n < 3 ; ++ n) { + if ( AreSamePointApprox( trTria2.GetP( n), ptInt)) + bOnVert2 = true ; + } + if ( bOnVert2) + return ITTT_VERT_VERT ; + else + return ITTT_VERT_EDGE ; + } + else if ( dStU2 < dEnU1 - EPS_SMALL) { + dIntStU = max( dStU1, dStU2) ; + dIntEnU = min( dEnU1, dEnU2) ; + return ITTT_EDGE_INT ; + } + else if ( dStU2 < dEnU1 + EPS_SMALL) { + dIntStU = 0.5 * ( dStU2 + dEnU1) ; + dIntEnU = 0.5 * ( dStU2 + dEnU1) ; + Point3d ptInt = ptLineSt + dIntStU * vtLineDir ; + bool bOnVert2 = false ; + for ( int n = 0 ; n < 3 ; ++ n) { + if ( AreSamePointApprox( trTria2.GetP( n), ptInt)) + bOnVert2 = true ; + } + if ( bOnVert2) + return ITTT_VERT_VERT ; + else + return ITTT_VERT_EDGE ; + } + else + return ITTT_NO ; + } + else if ( nRes2 == ILTT_SEGM_ON_EDGE) { + if ( dEnU2 < dStU1 - EPS_SMALL) + return ITTT_NO ; + else if ( dEnU2 < dStU1 + EPS_SMALL) { + dIntStU = 0.5 * ( dStU1 + dEnU2) ; + dIntEnU = 0.5 * ( dStU1 + dEnU2) ; + return ITTT_VERT_VERT ; + } + else if ( dStU2 < dEnU1 - EPS_SMALL) { + dIntStU = max( dStU1, dStU2) ; + dIntEnU = min( dEnU1, dEnU2) ; + return ITTT_EDGE_EDGE_SEG ; + } + else if ( dStU2 < dEnU1 + EPS_SMALL) { + dIntStU = 0.5 * ( dStU2 + dEnU1) ; + dIntEnU = 0.5 * ( dStU2 + dEnU1) ; + return ITTT_VERT_VERT ; + } + else + return ITTT_NO ; + } + else if ( nRes2 == ILTT_VERT) { + dEnU2 = dStU2 ; + if ( dEnU2 < dStU1 - EPS_SMALL) + return ITTT_NO ; + else if ( dEnU2 < dStU1 + EPS_SMALL) { + dIntStU = 0.5 * ( dStU1 + dEnU2) ; + dIntEnU = 0.5 * ( dStU1 + dEnU2) ; + return ITTT_VERT_VERT ; + } + else if ( dStU2 < dEnU1 - EPS_SMALL) { + dIntStU = max( dStU1, dStU2) ; + dIntEnU = min( dEnU1, dEnU2) ; + return ITTT_EDGE_VERT ; + } + else if ( dStU2 < dEnU1 + EPS_SMALL) { + dIntStU = 0.5 * ( dStU2 + dEnU1) ; + dIntEnU = 0.5 * ( dStU2 + dEnU1) ; + return ITTT_VERT_VERT ; + } + else + return ITTT_NO ; + } + else + return ITTT_NO ; + } + else if ( nRes1 == ILTT_VERT) { + dEnU1 = dStU1 ; + if ( nRes2 == ILTT_SEGM) { + if ( dEnU2 < dStU1 - EPS_SMALL) + return ITTT_NO ; + else if ( dEnU2 < dStU1 + EPS_SMALL) { + dIntStU = 0.5 * ( dStU1 + dEnU2) ; + dIntEnU = 0.5 * ( dStU1 + dEnU2) ; + Point3d ptInt = ptLineSt + dIntStU * vtLineDir ; + bool bOnVert2 = false ; + for ( int n = 0 ; n < 3 ; ++ n) { + if ( AreSamePointApprox( trTria2.GetP( n), ptInt)) + bOnVert2 = true ; + } + if ( bOnVert2) + return ITTT_VERT_VERT ; + else + return ITTT_VERT_EDGE ; + } + else if ( dStU2 < dEnU1 - EPS_SMALL) { + dIntStU = max( dStU1, dStU2) ; + dIntEnU = min( dEnU1, dEnU2) ; + return ITTT_VERT_INT ; + } + else if ( dStU2 < dEnU1 + EPS_SMALL) { + dIntStU = 0.5 * ( dStU2 + dEnU1) ; + dIntEnU = 0.5 * ( dStU2 + dEnU1) ; + Point3d ptInt = ptLineSt + dIntStU * vtLineDir ; + bool bOnVert2 = false ; + for ( int n = 0 ; n < 3 ; ++ n) { + if ( AreSamePointApprox( trTria2.GetP( n), ptInt)) + bOnVert2 = true ; + } + if ( bOnVert2) + return ITTT_VERT_VERT ; + else + return ITTT_VERT_EDGE ; + } + else + return ITTT_NO ; + } + else if ( nRes2 == ILTT_SEGM_ON_EDGE) { + if ( dEnU2 < dStU1 - EPS_SMALL) + return ITTT_NO ; + else if ( dEnU2 < dStU1 + EPS_SMALL) { + dIntStU = 0.5 * ( dStU1 + dEnU2) ; + dIntEnU = 0.5 * ( dStU1 + dEnU2) ; + return ITTT_VERT_VERT ; + } + else if ( dStU2 < dEnU1 - EPS_SMALL) { + dIntStU = max( dStU1, dStU2) ; + dIntEnU = min( dEnU1, dEnU2) ; + return ITTT_VERT_EDGE ; + } + else if ( dStU2 < dEnU1 + EPS_SMALL) { + dIntStU = 0.5 * ( dStU1 + dStU2) ; + dIntEnU = 0.5 * ( dStU1 + dStU2) ; + return ITTT_VERT_VERT ; + } + else + return ITTT_NO ; + } + else if ( nRes2 == ILTT_VERT) { + if ( dStU2 < dStU1 - EPS_SMALL) + return ITTT_NO ; + else if ( dStU2 < dStU1 + EPS_SMALL) { + dIntStU = 0.5 * ( dStU1 + dStU2) ; + dIntEnU = 0.5 * ( dStU1 + dStU2) ; + return ITTT_VERT_VERT ; + } + else + return ITTT_NO ; + } + else + return ITTT_NO ; + } + else + return ITTT_NO ; +} diff --git a/SfrCreate.cpp b/SfrCreate.cpp index afe0871..c720968 100644 --- a/SfrCreate.cpp +++ b/SfrCreate.cpp @@ -18,6 +18,7 @@ #include "CurveComposite.h" #include "SurfFlatRegion.h" #include "GeoConst.h" +#include "/EgtDev/Include/EgkPolyLine.h" #include "/EgtDev/Include/EgkBiArcs.h" #include "/EgtDev/Include/EgkOffsetCurve.h" #include "/EgtDev/Include/EGkSfrCreate.h" @@ -275,6 +276,68 @@ GetSurfFlatRegionFromFatCurve( ICurve* pCrv, double dRadius, bool bSquareEnds, b } } +//---------------------------------------------------------------------------- +ISurfFlatRegion* +GetSurfFlatRegionFromPolyLine( const PolyLine& ContourPolyLine) +{ + // Creo la regione. + PtrOwner pSfr( CreateBasicSurfFlatRegion()) ; + if ( IsNull( pSfr)) + return nullptr ; + // Creo curva composita. + PtrOwner pLoop( CreateBasicCurveComposite()) ; + if ( IsNull( pLoop)) + return nullptr ; + Point3d ptSt, ptEn ; + bool bContinue = ContourPolyLine.GetFirstPoint( ptSt) && + ContourPolyLine.GetNextPoint( ptEn) ; + while ( bContinue) { + CurveLine cvLine ; + cvLine.Set( ptSt, ptEn) ; + pLoop->AddCurve( cvLine) ; + ptSt = ptEn ; + bContinue = ContourPolyLine.GetNextPoint( ptEn) ; + } + pSfr->AddExtLoop( Release( pLoop)) ; + return Release( pSfr) ; +} + +//---------------------------------------------------------------------------- +ISurfFlatRegion* +GetSurfFlatRegionFromPolyLineVector( const POLYLINEVECTOR& vContoursPolyLineVec) +{ + // Creo la regione. + PtrOwner pSfr( CreateBasicSurfFlatRegion()) ; + if ( IsNull( pSfr)) + return nullptr ; + // Ciclo sulle PolyLine. + for ( int nL = 0 ; nL < int( vContoursPolyLineVec.size()) ; ++ nL) { + // Creo curva composita. + PtrOwner pLoop( CreateBasicCurveComposite()) ; + if ( IsNull( pLoop)) + return nullptr ; + Point3d ptSt, ptEn ; + bool bContinue = vContoursPolyLineVec[nL].GetFirstPoint( ptSt) && + vContoursPolyLineVec[nL].GetNextPoint( ptEn) ; + while ( bContinue) { + CurveLine cvLine ; + cvLine.Set( ptSt, ptEn) ; + pLoop->AddCurve( cvLine) ; + ptSt = ptEn ; + bContinue = vContoursPolyLineVec[nL].GetNextPoint( ptEn) ; + } + // Loop esterno + if ( nL == 0) { + pSfr->AddExtLoop( Release( pLoop)) ; + } + // Loop interno + else { + pSfr->AddIntLoop( Release( pLoop)) ; + } + } + return Release( pSfr) ; +} + //------------------------------------------------------------------------------- // Classe SurfFlatRegionByContours //------------------------------------------------------------------------------- diff --git a/SurfTriMesh.cpp b/SurfTriMesh.cpp index 10f98b9..e1d4955 100644 --- a/SurfTriMesh.cpp +++ b/SurfTriMesh.cpp @@ -21,10 +21,13 @@ #include "DistPointLine.h" #include "Triangulate.h" #include "GeoConst.h" +#include "SurfFlatRegion.h" +#include "/EgtDev/Include/EGkIntersLinePlane.h" #include "/EgtDev/Include/EGkPointGrid3d.h" #include "/EgtDev/Include/EGkPolyLine.h" #include "/EgtDev/Include/EGkStringUtils3d.h" #include "/EgtDev/Include/EGkUiUnits.h" +#include "/EgtDev/Include/EgkSfrCreate.h" #include "/EgtDev/Include/EgtPointerOwner.h" #include #include @@ -3298,7 +3301,9 @@ SurfTriMesh::Invert( void) bool SurfTriMesh::Cut( const Plane3d& plPlane, bool bSaveOnEq) { - // la superficie deve essere validata +#define UseTria 0 +#if UseTria + // la superficie deve essere validata if ( m_nStatus != OK) return false ; @@ -3502,14 +3507,89 @@ SurfTriMesh::Cut( const Plane3d& plPlane, bool bSaveOnEq) } } - // se effettuate modifiche + // se effettuate modifiche if ( bModif) { - // aggiorno tutto + // aggiorno tutto if ( ! AdjustVertices() || ! DoCompacting()) return false ; } return true ; +#endif + +#if ! UseTria + + bool bModif = false ; + + // Setto il triangolo come né fuori né dentro. + int nTriaNum = GetTriangleSize(); + for ( int nT = 0 ; nT < nTriaNum ; ++ nT) { + m_vTria[nT].nTempPart = 0 ; + } + + INTERSCHAINMAP IntersLineMap ; + INTERSEDGEMAP EdgeInterLineMap ; + INTERSEDGEMAP EdgeEdgeLineMap ; + + // Ciclo su tutte le facce. + int nFacetNum = GetFacetCount() ; + for ( int nF = 0 ; nF < nFacetNum ; ++ nF) { + // Dati della faccia + POLYLINEVECTOR vLoopVec ; + GetFacetLoops( nF, vLoopVec) ; + if ( vLoopVec.empty()) + continue ; + PtrOwner pReg( GetBasicSurfFlatRegion( GetSurfFlatRegionFromPolyLineVector( vLoopVec))) ; + if ( pReg == nullptr) + return false ; + SurfFlatRegion Region = *pReg ; + LineFacetClassVector IntersLinePart ; + int nIntType = IntersFacetPlane( Region, vLoopVec[0], plPlane, IntersLinePart) ; + if ( nIntType == FacetPlaneIntersType::FPI_CUT) { + for ( int nPart = 0 ; nPart < int( IntersLinePart.size()) ; ++ nPart) { + // Salvo intersezione per la faccia. + auto it = IntersLineMap.find( nF) ; + if ( it != IntersLineMap.end()) { + it->second.emplace_back( IntersInnSeg( IntersLinePart[nPart].ptSt, IntersLinePart[nPart].ptEn)) ; + } + else { + IntersLineMap.emplace( nF, IntersInnChain( 1, IntersInnSeg( IntersLinePart[nPart].ptSt, IntersLinePart[nPart].ptEn))) ; + } + } + } + else if ( nIntType == FacetPlaneIntersType::FPI_ON) { + INTVECTOR vT ; + GetAllTriaInFacet( nF, vT) ; + for ( auto& nT : vT) + m_vTria[nT].nTempPart = Region.GetNormVersor() * plPlane.GetVersN() > 0. ? 2 : - 2 ; + } + else if ( nIntType == FacetPlaneIntersType::FPI_INN) { + INTVECTOR vT ; + GetAllTriaInFacet( nF, vT) ; + for ( auto& nT : vT) + m_vTria[nT].nTempPart = 1 ; + } + else if ( nIntType == FacetPlaneIntersType::FPI_OUT) { + INTVECTOR vT ; + GetAllTriaInFacet( nF, vT) ; + for ( auto& nT : vT) + m_vTria[nT].nTempPart = - 1 ; + } + else + ; + } + // Divido le facce. + PieceMap NewFacet ; + SplitFacet( IntersLineMap, NewFacet) ; + RetriangulateFacetPieces( NewFacet, EdgeInterLineMap, EdgeEdgeLineMap) ; + + int nNumTria = GetTriangleSize() ; + for ( int nT = 0 ; nT < nNumTria ; ++ nT) + if ( m_vTria[nT].nTempPart == - 1 || m_vTria[nT].nTempPart == - 2 || ( ! bSaveOnEq && m_vTria[nT].nTempPart == 2)) + RemoveTriangle( nT) ; + + return AdjustVertices() && DoCompacting() ; +#endif } //---------------------------------------------------------------------------- diff --git a/SurfTriMesh.h b/SurfTriMesh.h index 6c37cb8..bc72487 100644 --- a/SurfTriMesh.h +++ b/SurfTriMesh.h @@ -21,6 +21,8 @@ #include #include +class SurfFlatRegion ; + //---------------------------------------------------------------------------- // Classe Vertice class StmVert @@ -110,6 +112,70 @@ typedef std::vector TJuncLoopVec ; // Set di TEdgeId typedef std::set TJEdgeSet ; +// Definizione strutture intersezione linea-faccia +//---------------------------------------------------------------------------- +struct LineFacetClass { + Point3d ptSt, ptEn ; + int nTypeA, nTypeB ; + LineFacetClass() { + nTypeA = 0 ; + nTypeB = 0 ; + } + LineFacetClass( const Point3d& ptS, const Point3d ptE, int nTpA, int nTpB) { + ptSt = ptS ; + ptEn = ptE ; + nTypeA = nTpA ; + nTypeB = nTpB ; + } +} ; +typedef std::vector LineFacetClassVector ; + +//---------------------------------------------------------------------------- +enum FacetPlaneIntersType { FPI_ERROR = 0, FPI_CUT = 1, FPI_INN = 2, FPI_OUT = 3, FPI_ON = 4 } ; + +//---------------------------------------------------------------------------- +// Definizione strutture e contenitori +// Contatti interno-interno +struct IntersInnSeg { + Point3d ptSt ; + Point3d ptEn ; + Vector3d vtOuter ; + IntersInnSeg(void) { + ; + } + IntersInnSeg(const Point3d& ptS, const Point3d& ptE) { + ptSt = ptS; + ptEn = ptE; + } + IntersInnSeg(const Point3d& ptS, const Point3d& ptE, const Vector3d& vtO) { + ptSt = ptS; + ptEn = ptE; + vtOuter = vtO; + } +}; +typedef std::vector IntersInnChain ; +typedef std::vector INNCHAINVECTOR ; +typedef std::unordered_map INTERSCHAINMAP ; +// Contatti con spigolo +struct IntersEdge { + Point3d ptSt ; + Point3d ptEn ; + INTVECTOR vOthFacetIndex ; + IntersEdge( const Point3d& ptS, const Point3d& ptE, const INTVECTOR& vOFI) { + ptSt = ptS; + ptEn = ptE; + vOthFacetIndex = vOFI; + } +} ; +typedef std::vector IntersEdgeVec ; +typedef std::unordered_map INTERSEDGEMAP ; +// Parte di faccia +struct FacetPiece { + POLYLINEVECTOR vPieceLoop ; + int nPiecePart ; +} ; +typedef std::unordered_map> PieceMap ; + //---------------------------------------------------------------------------- class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW { @@ -318,6 +384,22 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW bool RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECTORMAP& Ambiguos, SurfTriMesh& Surf, bool& bModif) ; bool AmbiguosTriangleManager( TRIA3DVECTORMAP& Ambiguos, SurfTriMesh& Surf) ; bool IntersectTriMeshTriangle( SurfTriMesh& Other) ; + int IntersFacetPlane( const SurfFlatRegion& Region, const PolyLine& ExtLoop, const Plane3d& plCutPlane, + LineFacetClassVector& IntersLinePart) ; + bool IntersFacetFacet( const SurfFlatRegion& RegionA, const PolyLine& ExtLoopA, + const SurfFlatRegion& RegionB, const PolyLine& ExtLoopB, + LineFacetClassVector& IntersLinePart) ; + bool ItersectTriMeshFacets( SurfTriMesh& Other) ; + bool RetriangulateFacetPieces( const PieceMap& NewFacet, + const INTERSEDGEMAP& EdgeInterLineMap, + const INTERSEDGEMAP& EdgeEdgeLineMap) ; + bool EdgeInteriorContactManager( const SurfTriMesh& OthSurf, + const INTERSCHAINMAP& InterInterLineMap, + const INTERSEDGEMAP& EdgeInterLineMap) ; + bool EdgeEdgeContactManager( const SurfTriMesh& OthSurf, + const INTERSCHAINMAP& InterInterLineMap, + const INTERSEDGEMAP& EdgeEdgeLineMap) ; + bool SplitFacet( const INTERSCHAINMAP& IntersLineMap, PieceMap& NewFacet); bool IdentifyParts( void) const ; bool RemoveTJunctions( void) ; bool RemoveCaps( void) ; @@ -347,6 +429,14 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW mutable BBox3d m_b3HGrd3d ; // Box3d collegato a Hash Grid 3d } ; +//---------------------------------------------------------------------------- +static bool ChangePolyLineStart( const Point3d& ptNewStart, PolyLine& Loop) ; +// nSegNum 0-based +static bool PointPositionOnPolyLine( const Point3d& ptPoint, /*const*/ PolyLine& Loop, int& nSegNum, double& dParOnSeg) ; +static bool IsPointInsidePolyLine( const Point3d& ptP, /*const*/ PolyLine& plPoly) ; +static bool SplitPolyLineAtPoint( const Point3d& ptPoint, /*const*/ PolyLine& Loop, PolyLine& Loop1, PolyLine& Loop2) ; +static bool AddPolyLineToPolyLine(PolyLine& Poly, PolyLine& PolyToAdd) ; + //----------------------------------------------------------------------------- inline SurfTriMesh* CreateBasicSurfTriMesh( void) { return ( static_cast( CreateGeoObj( SRF_TRIMESH))) ; } diff --git a/SurfTriMeshBooleans.cpp b/SurfTriMeshBooleans.cpp index 325019d..f4069fd 100644 --- a/SurfTriMeshBooleans.cpp +++ b/SurfTriMeshBooleans.cpp @@ -19,11 +19,15 @@ #include "DistPointLine.h" #include "Triangulate.h" #include "GeoConst.h" +#include "/EgtDev/Include/EgtNumUtils.h" #include "/EgtDev/Include/EgkCurve.h" #include "/EgtDev/Include/EgkDistPointCurve.h" #include "/EgtDev/Include/EgkDistPointTria.h" #include "/EgtDev/Include/EgkIntersLineTria.h" +#include "/EgtDev/Include/EgkIntersLineBox.h" +#include "/EgtDev/Include/EgkIntersPlanePlane.h" #include "/EgtDev/Include/EgkIntersTriaTria.h" +#include "/EgtDev/Include/EgkSfrCreate.h" #include "/EgtDev/Include/EGkChainCurves.h" #include "/EgtDev/Include/EGkGeoCollection.h" #include "/EgtDev/Include/EGkPolygon3d.h" @@ -54,10 +58,10 @@ IntersRectangleTriangle( const Point3d& ptP, const Vector3d& vtL1, const Vector3 int nIntA = 0 ; Point3d ptIntA1, ptIntA2 ; TRIA3DVECTOR vTriaA ; - int nIntTypeA = IntersTriaTria( trTria, trTriaA, ptIntA1, ptIntA2, vTriaA) ; - if ( FromSpecialToNormal( nIntTypeA) == ITTT_PNT || FromSpecialToNormal( nIntTypeA) == ITTT_VERT) - nIntA = 1 ; - else if ( FromSpecialToNormal( nIntTypeA) == ITTT_YES || FromSpecialToNormal( nIntTypeA) == ITTT_EDGE) { + int nIntTypeA = IntersTriaTria( trTria, trTriaA, ptIntA1, ptIntA2, vTriaA) ; + if ( nIntTypeA == ITTT_VERT_VERT || nIntTypeA == ITTT_VERT_EDGE || nIntTypeA == ITTT_VERT_INT || nIntTypeA == ITTT_EDGE_VERT || nIntTypeA == ITTT_EDGE_EDGE_PNT || nIntTypeA == ITTT_INT_VERT) + nIntA = 1 ; + else if ( nIntTypeA == ITTT_EDGE_EDGE_SEG || nIntTypeA == ITTT_EDGE_INT || nIntTypeA == ITTT_INT_EDGE || nIntTypeA == ITTT_INT_INT_SEG) { nIntA = 2 ; } // Interseco il triangolo con il secondo dei due triangoli del rettangolo @@ -65,9 +69,9 @@ IntersRectangleTriangle( const Point3d& ptP, const Vector3d& vtL1, const Vector3 Point3d ptIntB1, ptIntB2 ; TRIA3DVECTOR vTriaB ; int nIntTypeB = IntersTriaTria( trTria, trTriaB, ptIntB1, ptIntB2, vTriaB) ; - if ( FromSpecialToNormal( nIntTypeB) == ITTT_PNT || FromSpecialToNormal( nIntTypeB) == ITTT_VERT) + if ( nIntTypeB == ITTT_VERT_VERT || nIntTypeB == ITTT_VERT_EDGE || nIntTypeB == ITTT_VERT_INT || nIntTypeB == ITTT_EDGE_VERT || nIntTypeB == ITTT_EDGE_EDGE_PNT || nIntTypeB == ITTT_INT_VERT) nIntB = 1 ; - else if ( FromSpecialToNormal( nIntTypeB) == ITTT_YES || FromSpecialToNormal( nIntTypeB) == ITTT_EDGE) { + else if ( nIntTypeB == ITTT_EDGE_EDGE_SEG || nIntTypeB == ITTT_EDGE_INT || nIntTypeB == ITTT_INT_EDGE || nIntTypeB == ITTT_INT_INT_SEG) { nIntB = 2 ; } // Unisco le due intersezioni @@ -1781,13 +1785,15 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other) // Interseco i triangoli Point3d ptSegSt, ptSegEn ; TRIA3DVECTOR vTria ; - int nIntType = IntersTriaTria( trTriaA, trTriaB, ptSegSt, ptSegEn, vTria) ; - if ( FromSpecialToNormal( nIntType) != ITTT_NO && - FromSpecialToNormal( nIntType) != ITTT_OVERLAPS && - FromSpecialToNormal( nIntType) != ITTTS_VERT_VERT) { + int nIntType = IntersTriaTria( trTriaA, trTriaB, ptSegSt, ptSegEn, vTria, true) ; + if ( nIntType == ITTT_EDGE_EDGE_SEG || + nIntType == ITTT_EDGE_INT || + nIntType == ITTT_INT_EDGE || + nIntType == ITTT_INT_INT_SEG) { // Assegno i dati di intersezione IntSegment CurInters ; - if ( FromSpecialToNormal( nIntType) == ITTT_EDGE || FromSpecialToNormal( nIntType) == ITTT_YES) { + if ( nIntType == ITTT_EDGE_EDGE_SEG || nIntType == ITTT_EDGE_INT || + nIntType == ITTT_INT_EDGE || nIntType == ITTT_INT_INT_SEG) { CurInters.ptSt = ptSegSt ; CurInters.ptEn = ptSegEn ; CurInters.bDegenerate = false ; @@ -1802,7 +1808,7 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other) CurInters.vtOuter.Normalize() ; // Salvo intersezione per superficie A bool bIntOnEndgeA = false ; - if ( nIntType != ITTTS_EDGE_EDGE_SEG && nIntType != ITTTS_EDGE_INT) { + if ( nIntType != ITTT_EDGE_EDGE_SEG && nIntType != ITTT_EDGE_INT) { auto itA = LineMapA.find( nTA) ; if ( itA != LineMapA.end()) { itA->second.emplace_back( CurInters) ; @@ -1823,7 +1829,7 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other) // Salvo intersezione per superficie B bool bIntOnEndgeB = false ; - if ( nIntType != ITTTS_EDGE_EDGE_SEG && nIntType != ITTTS_INT_EDGE) { + if ( nIntType != ITTT_EDGE_EDGE_SEG && nIntType != ITTT_INT_EDGE) { auto itB = LineMapB.find( vNearTria[nTB]) ; if ( itB != LineMapB.end()) { itB->second.emplace_back( CurInters) ; @@ -1909,9 +1915,6 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other) } } } - else { - ; - } } } @@ -2033,7 +2036,7 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other) TRIA3DVECTOR vTriaAB ; Point3d ptTempA, ptTempB ; int nIntTypeAB = IntersTriaTria( trTriaA, trTriaB, ptTempA, ptTempB, vTriaAB) ; - if ( nIntTypeAB == ITTTS_OVERLAPS) { + if ( nIntTypeAB == ITTT_OVERLAPS) { bool bInvertB = trTriaA.GetN() * trTriaB.GetN() < 0. ; m_vTria[nTA].nTempPart = ( bInvertB ? -2 : 2) ; SurfB.m_vTria[vNearTria[nTB]].nTempPart = ( bInvertB ? - 2 : 2) ; @@ -2424,11 +2427,12 @@ SurfTriMesh::Intersect( const ISurfTriMesh& Other) m_OGrMgr.Clear() ; SurfTriMesh SurfB ; SurfB.CopyFrom( &Other) ; - Frame3d frScalingRef ; - frScalingRef.Set( m_vVert[0].ptP, X_AX, Y_AX, Z_AX) ; - Scale( frScalingRef, BOOLEAN_SCALE, BOOLEAN_SCALE, BOOLEAN_SCALE) ; - SurfB.Scale( frScalingRef, BOOLEAN_SCALE, BOOLEAN_SCALE, BOOLEAN_SCALE) ; - IntersectTriMeshTriangle( SurfB) ; + //Frame3d frScalingRef ; + //frScalingRef.Set( m_vVert[0].ptP, X_AX, Y_AX, Z_AX) ; + //Scale( frScalingRef, BOOLEAN_SCALE, BOOLEAN_SCALE, BOOLEAN_SCALE) ; + //SurfB.Scale( frScalingRef, BOOLEAN_SCALE, BOOLEAN_SCALE, BOOLEAN_SCALE) ; + //IntersectTriMeshTriangle( SurfB) ; + ItersectTriMeshFacets( SurfB) ; IdentifyParts() ; SurfB.IdentifyParts() ; int nTriaNumA = GetTriangleSize() ; @@ -2449,13 +2453,13 @@ SurfTriMesh::Intersect( const ISurfTriMesh& Other) AddTriangle( nNewVert, m_nMaxTFlag) ; } } - bool bOk = ( AdjustVertices() && DoCompacting()) ; - bOk && RemoveTripleTriangles() ; - bOk = bOk && ( AdjustVertices() && DoCompacting()) ; - bOk && RemoveTJunctions() ; - bOk = bOk && ( AdjustVertices() && DoCompacting()) ; - Scale( frScalingRef, 1. / BOOLEAN_SCALE, 1. / BOOLEAN_SCALE, 1. / BOOLEAN_SCALE) ; - return bOk ; + //bool bOk = ( AdjustVertices() && DoCompacting()) ; + //bOk && RemoveTripleTriangles() ; + //bOk = bOk && ( AdjustVertices() && DoCompacting()) ; + //bOk && RemoveTJunctions() ; + /*bOk = bOk*/return RemoveTJunctions() && ( AdjustVertices() && DoCompacting()) ; + //Scale( frScalingRef, 1. / BOOLEAN_SCALE, 1. / BOOLEAN_SCALE, 1. / BOOLEAN_SCALE) ; + /* return bOk ;*/ } //---------------------------------------------------------------------------- @@ -2508,19 +2512,16 @@ SurfTriMesh::GetSurfClassification( const ISurfTriMesh& ClassifierSurf, // Le superfici devono essere valide if ( ! IsValid() || ! ClassifierSurf.IsValid()) return false ; - if ( ClassifierSurf.GetVertexCount() == 0 || ClassifierSurf.GetTriangleCount() == 0) - return false ; - if ( m_vVert.empty() || m_vTria.empty()) - return true ; SurfTriMesh SurfC ; SurfC.CopyFrom( &ClassifierSurf) ; - Frame3d frScalingRef ; - frScalingRef.Set( m_vVert[0].ptP, X_AX, Y_AX, Z_AX) ; - Scale( frScalingRef, BOOLEAN_SCALE, BOOLEAN_SCALE, BOOLEAN_SCALE) ; - SurfC.Scale( frScalingRef, BOOLEAN_SCALE, BOOLEAN_SCALE, BOOLEAN_SCALE) ; - IntersectTriMeshTriangle( SurfC) ; + //Frame3d frScalingRef ; + //frScalingRef.Set( m_vVert[0].ptP, X_AX, Y_AX, Z_AX) ; + //Scale( frScalingRef, BOOLEAN_SCALE, BOOLEAN_SCALE, BOOLEAN_SCALE) ; + //SurfC.Scale( frScalingRef, BOOLEAN_SCALE, BOOLEAN_SCALE, BOOLEAN_SCALE) ; + ItersectTriMeshFacets( SurfC) ; + //IntersectTriMeshTriangle( SurfC) ; IdentifyParts() ; - Scale( frScalingRef, 1. / BOOLEAN_SCALE, 1. / BOOLEAN_SCALE, 1. / BOOLEAN_SCALE) ; + //Scale( frScalingRef, 1. / BOOLEAN_SCALE, 1. / BOOLEAN_SCALE, 1. / BOOLEAN_SCALE) ; int nTriaNum = GetTriangleSize() ; for ( int nT = 0 ; nT < nTriaNum ; ++ nT) { @@ -2574,3 +2575,2161 @@ SurfTriMesh::CutWithOtherSurf( const ISurfTriMesh& CutterSurf, bool bInVsOut, bo Scale( frScalingRef, 1. / BOOLEAN_SCALE, 1. / BOOLEAN_SCALE, 1. / BOOLEAN_SCALE) ; return bOk ; } + +//---------------------------------------------------------------------------- +int +SurfTriMesh::IntersFacetPlane( const SurfFlatRegion& Region, const PolyLine& ExtLoop, const Plane3d& plCutPlane, + LineFacetClassVector& IntersLinePart) +{ + // Se la regione o il piano non sono validi, non è possibile proseguire. + if ( ! ( Region.IsValid() && plCutPlane.IsValid())) + return FPI_ERROR ; + // Determino il piano della regione. + Plane3d plFacetPlane ; + plFacetPlane.Set( Region.GetPlanePoint(), Region.GetNormVersor()) ; + // Se il piano della regione non è valido, non è possibile proseguire. + if ( ! plCutPlane.IsValid()) + return FPI_ERROR ; + // Pulisco il vettore delle intersezioni risultanti. + IntersLinePart.resize( 0) ; + // Calcolo le distanze dei vertici della faccia dal piano. + int nExtLoopPointNum = int( ExtLoop.GetPointNbr()) ; + vector vDist ; + vDist.reserve( nExtLoopPointNum) ; + Point3d ptP ; + bool bContinue = ExtLoop.GetFirstPoint( ptP) ; + while ( bContinue) { + vDist.emplace_back( DistPointPlane( ptP, plCutPlane)) ; + bContinue = ExtLoop.GetNextPoint( ptP) ; + } + // Verifico posizione della faccia rispetto al piano. + int nVertPos = 0 ; int nVertNeg = 0 ; + for ( const auto& dDist : vDist) { + if ( dDist > 0.5 * EPS_SMALL) + ++ nVertPos ; + else if ( dDist < - 0.5 * EPS_SMALL) + ++ nVertNeg ; + } + +#define FirstMode 1 +#if FirstMode + // Tutto sul piano. + if ( nVertPos == 0 && nVertNeg == 0) + return FPI_ON ; + // Tutto dentro + else if ( nVertPos == 0) + return FPI_INN ; + // Tutto fuori + else if ( nVertNeg == 0) + return FPI_OUT ; + + // Intersezione tra i piani delle due facce + Point3d ptL ; Vector3d vtL ; + int nResPP = IntersPlanePlane( plFacetPlane, plCutPlane, ptL, vtL) ; + // Non essendo complanari, se non trovo la retta d'intersezione c'è un errore. + if ( nResPP == IPPT_NO || nResPP == IPPT_OVERLAPS) + return FPI_ERROR ; + + // Box contenente entrambe le regioni + BBox3d b3Box ; + Region.GetLocalBBox( b3Box) ; + b3Box.Expand( 10) ; + + // Limito la retta nel box contenente le regioni + INTDBLVECTOR vInters ; + if ( ! IntersLineBox( ptL, vtL, 100., b3Box, vInters, false) || int( vInters.size()) < 2) + return FPI_ERROR ; + double dLen = vInters.back().second - vInters[0].second ; + Point3d ptIntLineSt = ptL + vInters[0].second * vtL ; + Point3d ptIntLineEn = ptL + vInters.back().second * vtL ; + CurveLine cvPlaneIntersLine ; + cvPlaneIntersLine.Set( ptIntLineSt, ptIntLineEn) ; + + // Limito la linea di intersezione con la faccia. + CRVCVECTOR IntersectionResults ; + bool bClassificationOk = Region.GetCurveClassification( cvPlaneIntersLine, IntersectionResults) ; + // Se non trovo le intersezioni, c'è un errore. + if ( ! bClassificationOk) + return FPI_ERROR ; + + // Prendo la parte interna o sul bordo. + int nPartNum = int( IntersectionResults.size()) ; + for ( int n = 0 ; n < nPartNum ; ++ n) { + int nType = IntersectionResults[n].nClass ; + if ( nType == CRVC_IN || nType == CRVC_ON_P || nType == CRVC_ON_M) { + double dParS = dLen * IntersectionResults[n].dParS ; + double dParE = dLen * IntersectionResults[n].dParE ; + IntersLinePart.emplace_back( LineFacetClass( ptIntLineSt + dParS * vtL, ptIntLineSt + dParE * vtL, nType, nType)) ; + } + } + + return int( IntersLinePart.size()) > 0 ; +#endif + +#if ! FirstMode + return true; +#endif +} + +//---------------------------------------------------------------------------- +bool +SurfTriMesh::IntersFacetFacet( const SurfFlatRegion& RegionA, const PolyLine& ExtLoopA, + const SurfFlatRegion& RegionB, const PolyLine& ExtLoopB, + LineFacetClassVector& IntersLinePart) +{ + IntersLinePart.resize( 0) ; + + // Determino i piani delle regioni + Plane3d plPlaneA, plPlaneB ; + plPlaneA.Set( RegionA.GetPlanePoint(), RegionA.GetNormVersor()) ; + plPlaneB.Set( RegionB.GetPlanePoint(), RegionB.GetNormVersor()) ; + + // Calcolo le distanze dei vertici della faccia A dal piano della faccia B. + int nExtLoopPointNumA = int( ExtLoopA.GetPointNbr()) ; + vector vDistA ; + vDistA.reserve( nExtLoopPointNumA) ; + Point3d ptP ; + bool bContinue = ExtLoopA.GetFirstPoint( ptP) ; + while ( bContinue) { + vDistA.emplace_back( DistPointPlane( ptP, plPlaneB)) ; + bContinue = ExtLoopA.GetNextPoint( ptP) ; + } + // Verifico posizione della faccia A rispetto al piano della faccia B. + int nVertPosA = 0 ; int nVertNegA = 0 ; + for ( const auto& dDist : vDistA) { + if ( dDist > EPS_SMALL) + ++ nVertPosA ; + else if ( dDist < - EPS_SMALL) + ++ nVertNegA ; + } + // Se la faccia A giace tutta da una parte del piano, nessuna intersezione + if ( nVertPosA == nExtLoopPointNumA || nVertNegA == nExtLoopPointNumA) + return false ; + + // Calcolo le distanze dei vertici della faccia B dal piano della faccia A. + int nExtLoopPointNumB = int( ExtLoopB.GetPointNbr()) ; + vector vDistB ; + vDistB.reserve( nExtLoopPointNumB) ; + bContinue = ExtLoopB.GetFirstPoint( ptP) ; + while ( bContinue) { + vDistB.emplace_back( DistPointPlane( ptP, plPlaneA)) ; + bContinue = ExtLoopB.GetNextPoint( ptP) ; + } + // Verifico posizione della faccia B rispetto al piano della faccia A. + int nVertPosB = 0 ; int nVertNegB = 0 ; + for ( const auto& dDist : vDistB) { + if ( dDist > EPS_SMALL) + ++ nVertPosB ; + else if ( dDist < - EPS_SMALL) + ++ nVertNegB ; + } + // Se la faccia B giace tutta da una parte del piano, nessuna intersezione + if ( nVertPosB == nExtLoopPointNumB || nVertNegB == nExtLoopPointNumB) + return false ; + + // Intersezione tra i piani delle due facce + Point3d ptL ; Vector3d vtL ; + int nResPP = IntersPlanePlane( plPlaneA, plPlaneB, ptL, vtL) ; + if ( nResPP == IPPT_NO) + return false ; + + // Se le facce sono complanari + if ( nResPP == IPPT_OVERLAPS) + return false ; + + // Box contenente entrambe le regioni + BBox3d b3Box, b3BoxB; + RegionA.GetLocalBBox( b3Box) ; + RegionB.GetLocalBBox( b3BoxB) ; + b3Box.Add(b3BoxB); + b3Box.Expand( 10); + + // Limito la retta nel box contenente le regioni + INTDBLVECTOR vInters; + if ( ! IntersLineBox(ptL, vtL, 100., b3Box, vInters, false) || int( vInters.size()) dParSA + EPS_SMALL) { + double dMinPar = max( dParSA, dParSB) ; + double dMaxPar = min( dParEA, dParEB) ; + IntersLinePart.emplace_back( LineFacetClass( ptIntLineSt + dMinPar * vtL, ptIntLineSt + dMaxPar * vtL, nTypeA, nTypeB)) ; + } + } + } + } + } + + return int( IntersLinePart.size()) > 0 ; +} + +//---------------------------------------------------------------------------- +//bool +//CreateFlatRegionFromPolyLineVector( const POLYLINEVECTOR& PolyVec, SurfFlatRegion& Region) +//{ +// bool bOk = true ; +// for ( int nL = 0 ; nL < int( PolyVec.size()) && bOk ; ++ nL) { +// CurveComposite Loop ; +// Point3d ptSt, ptEn ; +// bool bContinue = PolyVec[nL].GetFirstPoint( ptSt) && PolyVec[nL].GetNextPoint( ptEn) ; +// while ( bContinue) { +// CurveLine cvLine ; +// cvLine.Set( ptSt, ptEn) ; +// Loop.AddCurve( cvLine) ; +// ptSt = ptEn ; +// bContinue = PolyVec[nL].GetNextPoint( ptEn) ; +// } +// if ( nL == 0) +// bOk = bOk && Region.AddExtLoop( Loop) ; +// else +// bOk = bOk && Region.AddIntLoop( Loop) ; +// } +// return bOk ; +//} + +//---------------------------------------------------------------------------- +static bool +ChangePolyLineStart( const Point3d& ptNewStart, PolyLine& Loop) +{ + // Rinomino la lista di punti della PolyLine. + PNTULIST& LoopList = Loop.GetUPointList() ; + // Ciclo sui segmenti del loop per cercare il tratto del loop chiuso più vicino al punto. + double dMinSqDist = DBL_MAX ; + auto itMinDist = LoopList.end() ; + auto itSt = LoopList.begin() ; + auto itEn = itSt ; + ++ itEn ; + for ( ; itSt != LoopList.end() && itEn != LoopList.end() ; ++ itSt, ++ itEn) { + // Estremi del segmento corrente del loop + Point3d ptSegSt = itSt->first ; + Point3d ptSegEn = itEn->first ; + // Distanza del punto dal segmento del loop + DistPointLine dDistCalc( ptNewStart, ptSegSt, ptSegEn) ; + double dSqDist ; + dDistCalc.GetSqDist( dSqDist) ; + if ( dSqDist < dMinSqDist) { + dMinSqDist = dSqDist ; + itMinDist = itSt ; + } + } + // Se il punto non sta sul loop, errore + if ( dMinSqDist > 100 * SQ_EPS_SMALL) + return false ; + // Se il punto non sta su un vertice del segmento, lo aggiungo. Altrimenti non devo fare nulla. + auto itNewPointSt = LoopList.begin() ; + auto itNext = itMinDist ; + ++ itNext ; + bool bOnStart = AreSamePointApprox( ptNewStart, itMinDist->first) ; + bool bOnEnd = AreSamePointApprox( ptNewStart, itNext->first) ; + itNewPointSt = LoopList.emplace( itNext, ptNewStart, 0) ; + // Sposto i punti precedenti in coda. + bool bStartRemoved = false ; + auto it = LoopList.begin() ; + while ( it != itNewPointSt) { + if ( bStartRemoved) { + LoopList.emplace_back( it->first, it->second) ; + } + bStartRemoved = true ; + it = LoopList.erase( it) ; + } + // Se il punto inserito non coincide con l'inizio del segmento chiudo il loop. + if ( ! bOnStart) { + LoopList.emplace_back( ptNewStart, 0) ; + // Se coincide con la fine tolgo il punto di fine che diviene inutile. + if ( bOnEnd) { + //LoopList.erase( itNext) ; + auto itNewStart = LoopList.begin() ; + ++ itNewStart ; + LoopList.erase( itNewStart) ; + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +// nSegNum 0-based +static bool +PointPositionOnPolyLine( const Point3d& ptPoint, /*const*/ PolyLine& Loop, int& nSegNum, double& dParOnSeg) +{ + // Rinomino la lista di punti della PolyLine. + /*const*/ PNTULIST& LoopList = Loop.GetUPointList() ; + // Ciclo sui segmenti del loop per cercare il tratto del loop chiuso più vicino al punto. + nSegNum = - 1 ; + double dMinSqDist = DBL_MAX ; + int nS = 0 ; + auto itMinDistSt = LoopList.end() ; + auto itMinDistEn = itMinDistSt ; + auto itSt = LoopList.begin() ; + auto itEn = itSt ; + ++ itEn ; + for ( ; itSt != LoopList.end() && itEn != LoopList.end() ; ++ itSt, ++ itEn, ++ nS) { + // Estremi del segmento corrente del loop + Point3d ptSegSt = itSt->first ; + Point3d ptSegEn = itEn->first ; + // Distanza del punto dal segmento del loop + DistPointLine dDistCalc( ptPoint, ptSegSt, ptSegEn) ; + double dSqDist ; + dDistCalc.GetSqDist( dSqDist) ; + if ( dSqDist < dMinSqDist) { + nSegNum = nS ; + dMinSqDist = dSqDist ; + itMinDistSt = itSt ; + itMinDistEn = itEn ; + } + } + // Se il punto non sta sul loop, lo segnalo. + if ( dMinSqDist > 100 * SQ_EPS_SMALL) + return false ; + // Calcolo il parametro lungo il segmento. + Vector3d vtSeg = itMinDistEn->first - itMinDistSt->first ; + double dSegLen = vtSeg.Len() ; + if ( dSegLen < EPS_SMALL) + return false ; + vtSeg /= dSegLen ; + dParOnSeg = Clamp( ( ptPoint - itMinDistSt->first) * vtSeg, 0., dSegLen) ; + return true ; +} + +//---------------------------------------------------------------------------- +static bool +IsPointInsidePolyLine( const Point3d& ptP, /*const*/ PolyLine& plPoly) +{ + // Se la PolyLine non è chiusa, il punto non può essere interno. + if ( ! plPoly.IsClosed()) + return false ; + // Lista dei punti + /*const*/ PNTULIST& List = plPoly.GetUPointList() ; + // Ciclo sui segmenti della PolyLine per cercarne il tratto più vicino al punto. + double dMinSqDist = DBL_MAX ; + Point3d ptMinDist ; + auto itMinDistSt = List.end() ; + auto itSt = List.begin() ; + auto itEn = itSt ; + ++ itEn ; + for ( ; itSt != List.end() && itEn != List.end() ; ++ itSt, ++ itEn) { + // Estremi del segmento corrente del loop + Point3d ptSegSt = itSt->first ; + Point3d ptSegEn = itEn->first ; + // Distanza del punto dal segmento del loop + DistPointLine dDistCalc( ptP, ptSegSt, ptSegEn) ; + double dSqDist ; + dDistCalc.GetSqDist( dSqDist) ; + if ( dSqDist < dMinSqDist) { + dMinSqDist = dSqDist ; + dDistCalc.GetMinDistPoint( ptMinDist) ; + itMinDistSt = itSt ; + } + } + // Termine del segmento di minima distanza. + auto itMinDistEn = itMinDistSt ; + ++ itMinDistEn ; + // Punto di minima distanza nell'estremo iniziale del segento + if ( AreSamePointApprox( ptMinDist, itMinDistSt->first)) { + auto itPrevSt = List.begin() ; + if ( itMinDistSt == List.begin()) { + auto itAuxNext = itPrevSt ; + ++ ( ++ itAuxNext) ; + for ( ; itAuxNext != List.end() ; ++ itPrevSt, ++ itAuxNext) + ; + } + else { + auto itAuxNext = itPrevSt ; + ++ itAuxNext ; + for (; itAuxNext != itMinDistSt; ++itPrevSt, ++itAuxNext) + ; + } + Vector3d vtPrevTan = itMinDistSt->first - itPrevSt->first ; + vtPrevTan.Normalize() ; + Vector3d vtTan = itMinDistEn->first - itMinDistSt->first ; + vtTan.Normalize() ; + Polygon3d AuxPolygon ; + AuxPolygon.FromPolyLine( plPoly) ; + Vector3d vtPolyNorm = AuxPolygon.GetVersN() ; + Vector3d vtPrevOut = vtPrevTan ^ vtPolyNorm ; + Vector3d vtOut = vtTan ^ vtPolyNorm ; + // Caso concavo + if ( vtTan * vtPrevOut > 0) { + Vector3d vtTest = ptP - ptMinDist ; + if ( vtTest * vtPrevOut < 0 || vtTest * vtOut < 0) + return true ; + } + // Caso convesso + else { + Vector3d vtTest = ptP - ptMinDist ; + if ( vtTest * vtPrevOut < 0 && vtTest * vtOut < 0) + return true ; + } + } + // Punto di minima distanza nell'estremo finale del segento + else if ( AreSamePointApprox( ptMinDist, itMinDistEn->first)) { + auto itNextEn = itMinDistEn ; + ++ itNextEn ; + if ( itNextEn == List.end()) { + itNextEn = List.begin() ; + ++ itNextEn ; + } + Vector3d vtTan = itMinDistEn->first - itMinDistSt->first ; + vtTan.Normalize() ; + Vector3d vtNextTan = itNextEn->first - itMinDistEn->first ; + vtNextTan.Normalize() ; + Polygon3d AuxPolygon ; + AuxPolygon.FromPolyLine( plPoly) ; + Vector3d vtPolyNorm = AuxPolygon.GetVersN() ; + Vector3d vtOut = vtTan ^ vtPolyNorm ; + Vector3d vtNextOut = vtNextTan ^ vtPolyNorm ; + // Caso concavo + if ( vtNextTan * vtOut > 0) { + Vector3d vtTest = ptP - ptMinDist ; + if ( vtTest * vtOut < 0 || vtTest * vtNextOut < 0) + return true ; + } + // Caso convesso + else { + Vector3d vtTest = ptP - ptMinDist ; + if ( vtTest * vtOut < 0 && vtTest * vtNextOut < 0) + return true ; + } + } + // Punto di minima distanza interno al segmeno + else { + Vector3d vtP = ptP - itMinDistSt->first ; + Vector3d vtTan = itMinDistEn->first - itMinDistSt->first ; + vtTan.Normalize() ; + Polygon3d AuxPolygon ; + AuxPolygon.FromPolyLine( plPoly) ; + Vector3d vtPolyNorm = AuxPolygon.GetVersN() ; + Vector3d vtOut = vtTan ^ vtPolyNorm ; + vtP -= ( vtP * vtTan) * vtTan ; + if ( vtP * vtOut < - EPS_SMALL) + return true ; + } + return false ; +} + +//---------------------------------------------------------------------------- +bool +DistPointPolyLine( const Point3d& ptP, const PolyLine& plPoly, double& dPointPolyLineDist) +{ + if ( plPoly.GetPointNbr() == 0) + return false ; + dPointPolyLineDist = DBL_MAX ; + Point3d ptSt, ptEn ; + bool bContinue = plPoly.GetFirstPoint( ptSt) && plPoly.GetNextPoint( ptEn) ; + while ( bContinue) { + double dPoinLineDist ; + DistPointLine PointLineDistCalc( ptP, ptSt, ptEn) ; + PointLineDistCalc.GetDist( dPoinLineDist) ; + if ( dPoinLineDist < dPointPolyLineDist) + dPointPolyLineDist = dPoinLineDist ; + ptSt = ptEn ; + bContinue = plPoly.GetNextPoint( ptEn) ; + } + return true ; +} + +//---------------------------------------------------------------------------- +// Una faccia di una trimesh ha una sola componente connessa. +// Si assume che i loop siano corretti e rispettino tale proprietà. +bool +DistPointFacet( const Point3d& ptP, /*const*/ POLYLINEVECTOR& vPolyVec, double& dPointFacetDist) +{ + // Vedo se la proiezione del punto sul piano della faccia è interno ad essa. + Point3d ptPlaneP ; + Vector3d vtPlaneN ; + double dPointPlaneSignedDist ; + Point3d ptProjP ; + bool bPointIsInside = true ; + for ( int nLoop = 0 ; nLoop < int( vPolyVec.size()) && bPointIsInside ; ++ nLoop) { + Plane3d plPlane ; + double dArea ; + if ( ! vPolyVec[nLoop].IsClosedAndFlat( plPlane, dArea)) + return false ; + if ( nLoop == 0) { + ptPlaneP = plPlane.GetPoint() ; + vtPlaneN = plPlane.GetVersN() ; + dPointPlaneSignedDist = ( ptP - ptPlaneP) * vtPlaneN ; + ptProjP = ptP + dPointPlaneSignedDist * vtPlaneN ; + } + if ( ! IsPointInsidePolyLine( ptProjP, vPolyVec[nLoop])) + bPointIsInside = false ; + } + // Se la proiezione del punto sul piano della faccia è interno, ho finito. + // La distanza del punto dalla faccia è pari alla distanza dello stesso dal piano + // in cui giace quest'ultima. + if ( bPointIsInside) { + dPointFacetDist = abs( dPointPlaneSignedDist) ; + return bPointIsInside ; + } + // Calcolo la minima distanza del punto dalle polilinee del contorno. + dPointFacetDist = DBL_MAX ; + for ( int nLoop = 0 ; nLoop < int( vPolyVec.size()) ; ++ nLoop) { + double dDist ; + if ( DistPointPolyLine( ptP, vPolyVec[nLoop], dDist) && dDist < dPointFacetDist) + dPointFacetDist = dDist ; + } + return true ; +} + +//---------------------------------------------------------------------------- +static bool +SplitPolyLineAtPoint( const Point3d& ptPoint, /*const*/ PolyLine& Loop, PolyLine& Loop1, PolyLine& Loop2) +{ + // Rinomino la lista di punti della PolyLine. + /*const*/ PNTULIST& LoopList = Loop.GetUPointList() ; + // Ciclo sui segmenti del loop per cercare il tratto del loop chiuso più vicino al punto. + double dMinSqDist = DBL_MAX ; + auto itMinDistSt = LoopList.end() ; + auto itSt = LoopList.begin() ; + auto itEn = itSt ; + ++ itEn ; + for ( ; itSt != LoopList.end() && itEn != LoopList.end() ; ++ itSt, ++ itEn) { + // Estremi del segmento corrente del loop + Point3d ptSegSt = itSt->first ; + Point3d ptSegEn = itEn->first ; + // Distanza del punto dal segmento del loop + DistPointLine dDistCalc( ptPoint, ptSegSt, ptSegEn) ; + double dSqDist ; + dDistCalc.GetSqDist( dSqDist) ; + if ( dSqDist < dMinSqDist) { + dMinSqDist = dSqDist ; + itMinDistSt = itSt ; + } + } + // Se il punto non sta sul loop, lo segnalo. + if ( dMinSqDist > 100 * SQ_EPS_SMALL) + return false ; + // Se il punto di stop sta su un vertice non devo aggiungerlo e il + // punto di stop sarà uno degli estremi del segmento su cui giace. + auto itStop = itMinDistSt ; + auto itNext = itMinDistSt ; + ++ itNext ; + if ( AreSamePointApprox( ptPoint, itStop->first)) + ; + else if ( AreSamePointApprox( ptPoint, itNext->first)) + itStop = itNext ; + else { + itStop = LoopList.emplace( itNext, ptPoint, 0.) ; + } + // Creo i due loop + PNTULIST& LoopList1 = Loop1.GetUPointList() ; + PNTULIST& LoopList2 = Loop2.GetUPointList() ; + for ( auto it = LoopList.begin() ; it != itStop ; ++ it) { + LoopList1.emplace_back( it->first, it->second) ; + } + LoopList1.emplace_back( itStop->first, itStop->second) ; + for ( auto it = itStop ; it != LoopList.end() ; ++ it) { + LoopList2.emplace_back( it->first, it->second) ; + } + return true ; +} + +//---------------------------------------------------------------------------- +static bool +AddPolyLineToPolyLine( PolyLine& Poly, PolyLine& PolyToAdd) +{ + // Se la PolyLine a cui devo aggiungere l'altra è chiusa, non posso aggiungere nulla. + if ( Poly.IsClosed()) + return false ; + // Se la PolyLina che devo aggiungere è vuota, ho finito. + PNTULIST& PolyToAddList = PolyToAdd.GetUPointList() ; + if ( int( PolyToAddList.size()) == 0) + return true ; + // Se Poly non è vuota e la sua fine non coincide con l'inizio di PolyToAdd, non è possibile aggiungere nulla. + Point3d ptLast ; + Poly.GetLastPoint( ptLast) ; + auto it = PolyToAddList.begin() ; + if ( Poly.GetPointNbr() != 0 && ! AreSamePointEpsilon( it->first, ptLast, 10 * EPS_SMALL)) + return false ; + /*if ( Poly.GetPointNbr() == 0) + Poly.AddUPoint( 0., it->first) ; + ++ it ;*/ + // Aggiungo i punti. + for ( ; it != PolyToAddList.end() ; ++ it) { + Poly.AddUPoint( 0., it->first) ; + } + return true ; +} + +//---------------------------------------------------------------------------- +struct PositionOnPolyLine { + int nIndexInVec ; + int nSegNum ; + double dParOnSeg ; + PositionOnPolyLine( int nIndex, int nSeg, double dPar) { + nIndexInVec = nIndex ; + nSegNum = nSeg ; + dParOnSeg = dPar ; + } +} ; + +//---------------------------------------------------------------------------- +bool +SurfTriMesh::SplitFacet( const INTERSCHAINMAP& IntersLineMap, PieceMap& NewFacet) +{ + for ( auto it = IntersLineMap.begin() ; it != IntersLineMap.end() ; ++ it) { + // Normale alla faccia + Vector3d vtFacetNorm ; + GetFacetNormal( it->first, vtFacetNorm) ; + // Creo i loop + ChainCurves LoopCreator ; + LoopCreator.Init( false, 10 * EPS_SMALL, int( it->second.size()), 10) ; + // Carico le curve per concatenarle + for ( int nCv = 0 ; nCv < int( it->second.size()); ++ nCv) { + Point3d ptSt = it->second[nCv].ptSt ; + Point3d ptEn = it->second[nCv].ptEn ; + Vector3d vtDir = ptEn - ptSt ; + vtDir.Normalize() ; + LoopCreator.AddCurve( nCv + 1, ptSt, vtDir, ptEn, vtDir) ; + } + // Recupero i concatenamenti e li divido fra chiusi e aperti. + INTVECTOR vIds ; + Point3d ptNearStart = ( it->second.size() > 0 ? it->second[0].ptSt : ORIG) ; + INNCHAINVECTOR cvClosedChain ; + INNCHAINVECTOR cvOpenChain ; + while ( LoopCreator.GetChainFromNear( ptNearStart, false, vIds)) { + IntersInnChain chTemp ; + for ( auto i : vIds) { + // Aggiungo la linea alla curva composta. + chTemp.emplace_back( it->second[i - 1]) ; + } + int nCurLoopLast = max( int( chTemp.size()) - 1, 0) ; + if ( AreSamePointEpsilon( chTemp[0].ptSt, chTemp[nCurLoopLast].ptEn, 10 * EPS_SMALL) && nCurLoopLast > 0) + cvClosedChain.emplace_back( chTemp) ; + else + cvOpenChain.emplace_back( chTemp) ; + } + // Elimino la seconda copia di catene aperte doppie + for ( int nI = 0 ; nI < int( cvOpenChain.size()) - 1 ; ++ nI) { + for ( int nJ = nI + 1 ; nJ < int( cvOpenChain.size()) ; ++ nJ) { + if ( cvOpenChain[nI].size() == cvOpenChain[nJ].size()) { + bool bSame = true ; + for ( int nK = 0 ; nK < int( cvOpenChain[nI].size()) ; ++ nK) { + if ( ! AreSamePointEpsilon( cvOpenChain[nI][nK].ptSt, cvOpenChain[nJ][nK].ptSt, 10 * EPS_SMALL) || + ! AreSamePointEpsilon( cvOpenChain[nI][nK].ptEn, cvOpenChain[nJ][nK].ptEn, 10 * EPS_SMALL)) { + bSame = false ; + break ; + } + } + if ( bSame) { + cvOpenChain.erase( cvOpenChain.begin() + nJ) ; + -- nJ ; + } + } + } + } + // Elimino la seconda copia di catene chiuse doppie + for ( int nI = 0 ; nI < int( cvClosedChain.size()) - 1 ; ++ nI) { + for ( int nJ = nI + 1 ; nJ < int( cvClosedChain.size()) ; ++ nJ) { + if ( cvClosedChain[nI].size() == cvClosedChain[nJ].size()) { + bool bSame = true ; + for ( int nK = 0 ; nK < int( cvClosedChain[nI].size()) ; ++ nK) { + if ( ! AreSamePointEpsilon( cvClosedChain[nI][nK].ptSt, cvClosedChain[nJ][nK].ptSt, 10 * EPS_SMALL) || + ! AreSamePointEpsilon( cvClosedChain[nI][nK].ptEn, cvClosedChain[nJ][nK].ptEn, 10 * EPS_SMALL)) { + bSame = false ; + break ; + } + } + if ( bSame) { + cvClosedChain.erase( cvClosedChain.begin() + nJ) ; + -- nJ ; + } + } + } + } + // Recupero i loop della faccia da dividere + vector& vNewPieces = ( NewFacet.emplace( it->first, vector()).first)->second ; + vNewPieces.emplace_back(); + vNewPieces.back().nPiecePart = 1 ; + GetFacetLoops( it->first, vNewPieces.back().vPieceLoop) ; + // Divido la faccia in parti. + // Ciclo sulle catene finché non esauriscono. + int nIterNumber = 0 ; + int nPrevLastChainNum = int( cvOpenChain.size()) ; + while ( int( cvOpenChain.size()) > 0) { + // Controllo di non essere in un loop infinito. + int nLastChainNum = int( cvOpenChain.size()) - 1 ; + if ( nPrevLastChainNum == nLastChainNum) { + cvOpenChain.insert( cvOpenChain.begin(), cvOpenChain.back()) ; + cvOpenChain.pop_back() ; + ++ nIterNumber ; + } + else { + nIterNumber = 0 ; + nPrevLastChainNum = nLastChainNum; + } + if ( nIterNumber == int( cvOpenChain.size())) { + cvOpenChain.resize( int( cvOpenChain.size()) - 1) ; + -- nLastChainNum ; + } + if ( int( cvOpenChain.size()) == 0) + break ; + // Ciclo su tutte le parti della faccia. + int nPartLoopNum = int( vNewPieces.size()) ; + for ( int nPart = 0 ; nPart < nPartLoopNum ; ++ nPart) { + // Cerco i loop su cui la catena corrente inizia e finisce. + INTVECTOR vLoopIndexes ; + // Ciclo sui loop della faccia. + for ( int nLoop = 0 ; nLoop < int( vNewPieces[nPart].vPieceLoop.size()) && int( vLoopIndexes.size()) < 2 ; ++ nLoop) { + int nSegNum ; + double dParOnSeg ; + if ( PointPositionOnPolyLine( cvOpenChain[nLastChainNum][0].ptSt, vNewPieces[nPart].vPieceLoop[nLoop], nSegNum, dParOnSeg)) { + vLoopIndexes.emplace_back( nLoop) ; + if ( vLoopIndexes.size() > 1) { + swap( vLoopIndexes[0], vLoopIndexes[1]) ; + } + } + if ( PointPositionOnPolyLine( cvOpenChain[nLastChainNum][cvOpenChain[nLastChainNum].size() - 1].ptEn, + vNewPieces[nPart].vPieceLoop[nLoop], nSegNum, dParOnSeg)) { + vLoopIndexes.emplace_back( nLoop) ; + } + } + // Se non ho trovato almeno un taglio completo, vado al prossimo. + if ( int( vLoopIndexes.size()) < 2) + continue ; + // La catena finisce sul loop ove inizia. Divido la nuova parte. + if ( vLoopIndexes[0] == vLoopIndexes[1]) { + // Cambio inizio al loop iniziale. + ChangePolyLineStart( cvOpenChain[nLastChainNum].back().ptEn, vNewPieces[nPart].vPieceLoop[vLoopIndexes[0]]) ; + // Divido il loop della parte + // Loop1 + PolyLine NewLoop1 ; + // Inserisco i punti della catena nella PolyLine del nuovo loop. + for ( int m = 0 ; m < int( cvOpenChain[nLastChainNum].size()) ; ++ m) { + NewLoop1.AddUPoint( 0., cvOpenChain[nLastChainNum][m].ptSt) ; + if ( m == int( cvOpenChain[nLastChainNum].size()) - 1) + NewLoop1.AddUPoint( 0., cvOpenChain[nLastChainNum][m].ptEn) ; + } + // Spezzo il loop successivo alla catena nel punto in cui comincia la catena successiva. + PolyLine SplitLoop1, SplitLoop2 ; + SplitPolyLineAtPoint( cvOpenChain[nLastChainNum][0].ptSt, + vNewPieces[nPart].vPieceLoop[vLoopIndexes[0]], + SplitLoop1, SplitLoop2) ; + // Aggiungo i punti precedenti il punto di frattura nella in NewLoop1. + AddPolyLineToPolyLine( NewLoop1, SplitLoop1) ; + // Loop2 + PolyLine NewLoop2 ; + AddPolyLineToPolyLine( NewLoop2, SplitLoop2) ; + // Inserisco i punti della catena nella PolyLine del nuovo loop. + for ( int m = int( cvOpenChain[nLastChainNum].size()) - 1 ; m >= 0 ; -- m) { + NewLoop2.AddUPoint( 0., cvOpenChain[nLastChainNum][m].ptEn) ; + if ( m == 0) + NewLoop2.AddUPoint( 0., cvOpenChain[nLastChainNum][m].ptSt) ; + } + // Loop esterno coinvolto + if ( vLoopIndexes[0] == 0) { + // Creo i pezzi nuovi, i cui loop esterni sono quelli appena definiti. + FacetPiece PieceInn, PieceOut ; + PieceInn.vPieceLoop.emplace_back( NewLoop1) ; + PieceInn.nPiecePart = 1 ; + PieceOut.vPieceLoop.emplace_back( NewLoop2) ; + PieceOut.nPiecePart = - 1 ; + // Assegno i loop interni del vecchio pezzo non tagliati da catene ai nuovi. + for ( int nIL = 1 ; nIL < int( vNewPieces[nPart].vPieceLoop.size()) ; ++ nIL) { + if ( nIL == vLoopIndexes[0]) + continue ; + Point3d ptPointInnerLoop ; + vNewPieces[nPart].vPieceLoop[nIL].GetFirstPoint( ptPointInnerLoop) ; + if ( PieceInn.vPieceLoop[0].GetPointNbr() < PieceOut.vPieceLoop[0].GetPointNbr()) { + if ( IsPointInsidePolyLine( ptPointInnerLoop, PieceInn.vPieceLoop[0])) { + PieceInn.vPieceLoop.emplace_back( vNewPieces[nPart].vPieceLoop[nIL]) ; + } + else { + PieceOut.vPieceLoop.emplace_back( vNewPieces[nPart].vPieceLoop[nIL]) ; + } + } + else { + if ( IsPointInsidePolyLine( ptPointInnerLoop, PieceOut.vPieceLoop[0])) { + PieceOut.vPieceLoop.emplace_back( vNewPieces[nPart].vPieceLoop[nIL]) ; + } + else { + PieceInn.vPieceLoop.emplace_back( vNewPieces[nPart].vPieceLoop[nIL]) ; + } + } + } + vNewPieces.erase( vNewPieces.begin() + nPart) ; + vNewPieces.emplace_back( PieceInn) ; + vNewPieces.emplace_back( PieceOut) ; + } + // Loop esterno non coinvolto + else { + Plane3d plLoopPlane1, plLoopPlane2, plContLoopPlane; + double dArea1, dArea2, dAreaCont; + NewLoop1.IsClosedAndFlat(plLoopPlane1, dArea1); + NewLoop2.IsClosedAndFlat(plLoopPlane2, dArea2); + vNewPieces[nPart].vPieceLoop[0].IsClosedAndFlat(plContLoopPlane, dAreaCont); + Vector3d vtLoopPlaneNorm1 = plLoopPlane1.GetVersN(); + Vector3d vtLoopPlaneNorm2 = plLoopPlane2.GetVersN(); + Vector3d vtContLoopPlaneNorm = plContLoopPlane.GetVersN(); + PolyLine NewLoopCCW, NewLoopCW; + bool bFirstLoopIsCounter = vtLoopPlaneNorm1 * vtContLoopPlaneNorm > EPS_SMALL; + if (bFirstLoopIsCounter) { + NewLoopCCW = NewLoop1; + NewLoopCW = NewLoop2; + } + else { + NewLoopCCW = NewLoop2; + NewLoopCW = NewLoop1; + } + // Creo il pezzo nuovo, il cui loop esterno è stato appena definito. + FacetPiece DetachedPiece; + DetachedPiece.vPieceLoop.emplace_back(NewLoopCCW); + DetachedPiece.nPiecePart = bFirstLoopIsCounter ? 1 : -1; + // Al pezzo pezzo staccato assegno i loop interni del vecchio pezzo non tagliati da catene. + for ( int nIL = 1 ; nIL < int( vNewPieces[nPart].vPieceLoop.size()) ; ++ nIL) { + if ( nIL == vLoopIndexes[0]) + continue ; + Point3d ptPointInnerLoop ; + vNewPieces[nPart].vPieceLoop[nIL].GetFirstPoint( ptPointInnerLoop) ; + if ( IsPointInsidePolyLine( ptPointInnerLoop, DetachedPiece.vPieceLoop[0])) { + DetachedPiece.vPieceLoop.emplace_back( vNewPieces[nPart].vPieceLoop[nIL]) ; + vNewPieces[nPart].vPieceLoop.erase( vNewPieces[nPart].vPieceLoop.begin() + nIL) ; + // Cambio il numero dei loop talgiati + for ( int nIntersLoop = 0 ; nIntersLoop < int( vLoopIndexes.size()) ; ++ nIntersLoop) { + if ( vLoopIndexes[nIntersLoop] > nIL) + -- vLoopIndexes[nIntersLoop] ; + } + -- nIL ; + } + } + // Aggiungo al pezzo, da cui si stacca quello appena creato, il loop complementare a quello che appartiene al pezzo che si stacca. + /*if ( ! bFirstLoopIsCounter)*/ + vNewPieces[nPart].vPieceLoop.erase(vNewPieces[nPart].vPieceLoop.begin() + vLoopIndexes[0]); + vNewPieces[nPart].vPieceLoop.emplace_back( NewLoopCW) ; + vNewPieces[nPart].nPiecePart = bFirstLoopIsCounter ? - 1 : 1 ; + vNewPieces.emplace_back( DetachedPiece) ; + } + // Elimino la catena usata. + cvOpenChain.erase( cvOpenChain.begin() + nLastChainNum) ; + // Interrompo il ciclo sulle parti. + break ; + } + // Cerco le catene per dividere la nuova parte. + else { + INTVECTOR vChainIndex ; + vChainIndex.emplace_back( nLastChainNum) ; + while ( vLoopIndexes.back() != vLoopIndexes[0]) { + // Cambio inizio del loop corrente in modo che il punto di inizio sia il punto finale dell'ultima catena trovata. + ChangePolyLineStart( cvOpenChain[vChainIndex.back()].back().ptEn, vNewPieces[nPart].vPieceLoop[vLoopIndexes.back()]) ; + // Cerco catene che iniziano sul loop coorente + vector vChainStartingOnLoop ; + for ( int nCh = 0 ; nCh < nLastChainNum ; ++ nCh) { + int nSegNum ; + double dParOnSeg ; + if ( PointPositionOnPolyLine( cvOpenChain[nCh][0].ptSt, vNewPieces[nPart].vPieceLoop[vLoopIndexes.back()], nSegNum, dParOnSeg)) { + vChainStartingOnLoop.emplace_back( PositionOnPolyLine(nCh, nSegNum, dParOnSeg)) ; + } + } + // Ordino le catene secondo la vicinanza lungo il loop del loro punto d'inizio al punto d'inizio del loop stesso. + sort( vChainStartingOnLoop.begin(), vChainStartingOnLoop.end(), [] ( PositionOnPolyLine Ch1, PositionOnPolyLine Ch2) { + if ( Ch1.nSegNum/*nIndexInVec*/ < Ch2.nSegNum/*nIndexInVec*/) + return true ; + else if ( Ch1.nSegNum/*nIndexInVec*/ == Ch2.nSegNum/*nIndexInVec*/) + return Ch1.dParOnSeg < Ch2.dParOnSeg ; + else + return false ; } ) ; + // Cerco la prima catena che non termina sul loop corrente. + for ( int n = 0 ; n < int( vChainStartingOnLoop.size()) ; ++ n) { + // Indice della catena e indice del segmento finale + int nCh = vChainStartingOnLoop[n].nIndexInVec ; + int nLastLineIndex = int( cvOpenChain[nCh].size()) - 1 ; + // Ciclo sui loop + int nLoopNum = int( vNewPieces[nPart].vPieceLoop.size()) ; + int nLoop ; + for ( nLoop = 0 ; nLoop < nLoopNum ; ++ nLoop) { + // Salto il loop corrente + if ( nLoop == vLoopIndexes.back()) + continue ; + int nSegNum ; + double dParOnSeg ; + // La catena termina su questo loop diverso da quello corrente. + if ( nLoop != vLoopIndexes.back() && + PointPositionOnPolyLine( cvOpenChain[nCh][nLastLineIndex].ptEn, vNewPieces[nPart].vPieceLoop[nLoop], nSegNum, dParOnSeg)) { + // Salvo l'indice della catena e quello del loop. + vChainIndex.emplace_back( nCh) ; + vLoopIndexes.emplace_back( nLoop) ; + break ; + } + } + if ( nLoop == nLoopNum) + break ; + } + } + // Cambio inizio al loop iniziale. + ChangePolyLineStart( cvOpenChain[vChainIndex.back()].back().ptEn, vNewPieces[nPart].vPieceLoop[vLoopIndexes[0]]) ; + // Divido i loop della parte. + POLYLINEVECTOR vPolySecondPartVec ; + PolyLine NewLoop1 ; + for ( int n = 0 ; n < int( vChainIndex.size()) ; ++ n) { + // Inserisco i punti della catena nella PolyLine del nuovo loop. + for ( int m = 0 ; m < int( cvOpenChain[vChainIndex[n]].size()) ; ++ m) { + NewLoop1.AddUPoint( 0., cvOpenChain[vChainIndex[n]][m].ptSt) ; + if ( m == int( cvOpenChain[vChainIndex[n]].size()) - 1) + NewLoop1.AddUPoint( 0., cvOpenChain[vChainIndex[n]][m].ptEn) ; + } + // Spezzo il loop successivo alla catena nel punto in cui comincia la catena successiva. + PolyLine SplitLoop1, SplitLoop2 ; + SplitPolyLineAtPoint( cvOpenChain[vChainIndex[( n + 1) % int( vChainIndex.size())]][0].ptSt, + vNewPieces[nPart].vPieceLoop[vLoopIndexes[n + 1]], + SplitLoop1, SplitLoop2) ; + // Aggiungo i punti precedenti il punto di frattura in NewLoop1. + AddPolyLineToPolyLine( NewLoop1, SplitLoop1) ; + // Salvo la parte dopo il punto di frattura in un apposito vettore. + vPolySecondPartVec.emplace_back( SplitLoop2) ; + } + PolyLine NewLoop2 ; + for ( int n = int( vChainIndex.size()) - 1 ; n >= 0 ; -- n) { + // Aggiungo i punti successivi il punto di frattura in NewLoop2. + AddPolyLineToPolyLine( NewLoop2, vPolySecondPartVec[n]) ; + // Inserisco i punti della catena nella PolyLine del nuovo loop. + for ( int m = int( cvOpenChain[vChainIndex[n]].size()) - 1 ; m >= 0 ; -- m) { + NewLoop2.AddUPoint( 0., cvOpenChain[vChainIndex[n]][m].ptEn) ; + if ( m == 0) + NewLoop2.AddUPoint( 0., cvOpenChain[vChainIndex[n]][m].ptSt) ; + } + } + // Controllo che il loop esterno sia interessato. + bool bExtCutted = false ; + for ( int n = 0 ; n < int( vLoopIndexes.size()) && ! bExtCutted ; ++ n) { + if ( vLoopIndexes[n] == 0) + bExtCutted = true ; + } + // Loop esterno interessato + if ( bExtCutted) { + // Creo i pezzi nuovi, i cui loop esterni sono quelli appena definiti. + FacetPiece PieceInn, PieceOut ; + PieceInn.vPieceLoop.emplace_back( NewLoop1) ; + PieceInn.nPiecePart = 1 ; + PieceOut.vPieceLoop.emplace_back( NewLoop2) ; + PieceOut.nPiecePart = - 1 ; + // Assegno i loop interni del vecchio pezzo non tagliati da catene ai nuovi. + for ( int nIL = 1 ; nIL < int( vNewPieces[nPart].vPieceLoop.size()) ; ++ nIL) { + bool bUsed = false ; + for ( int nU = 0 ; nU < int( vLoopIndexes.size()) - 1 ; ++ nU) { + if ( nIL == vLoopIndexes[nU]) { + bUsed = true ; + break ; + } + } + if ( bUsed) + continue ; + Point3d ptPointInnerLoop ; + vNewPieces[nPart].vPieceLoop[nIL].GetFirstPoint( ptPointInnerLoop) ; + if ( PieceInn.vPieceLoop[0].GetPointNbr() < PieceOut.vPieceLoop[0].GetPointNbr()) { + if ( IsPointInsidePolyLine( ptPointInnerLoop, PieceInn.vPieceLoop[0])) { + PieceInn.vPieceLoop.emplace_back( vNewPieces[nPart].vPieceLoop[nIL]) ; + } + else { + PieceOut.vPieceLoop.emplace_back( vNewPieces[nPart].vPieceLoop[nIL]) ; + } + } + else { + if ( IsPointInsidePolyLine( ptPointInnerLoop, PieceOut.vPieceLoop[0])) { + PieceOut.vPieceLoop.emplace_back( vNewPieces[nPart].vPieceLoop[nIL]) ; + } + else { + PieceInn.vPieceLoop.emplace_back( vNewPieces[nPart].vPieceLoop[nIL]) ; + } + } + } + // Aggiungo i due nuovi pezzi ed elimino quello da cui sono nati. + vNewPieces.erase( vNewPieces.begin() + nPart) ; + vNewPieces.emplace_back( PieceInn) ; + vNewPieces.emplace_back( PieceOut) ; + } + // Loop esterno non interessato + else { + Plane3d plLoopPlane1, plLoopPlane2, plContLoopPlane ; + double dArea1, dArea2, dAreaCont ; + NewLoop1.IsClosedAndFlat( plLoopPlane1, dArea1) ; + NewLoop2.IsClosedAndFlat( plLoopPlane2, dArea2) ; + vNewPieces[nPart].vPieceLoop[0].IsClosedAndFlat( plContLoopPlane, dAreaCont) ; + Vector3d vtLoopPlaneNorm1 = plLoopPlane1.GetVersN(); + Vector3d vtLoopPlaneNorm2 = plLoopPlane2.GetVersN(); + Vector3d vtContLoopPlaneNorm = plContLoopPlane.GetVersN(); + PolyLine NewLoopCCW, NewLoopCW; + bool bFirstLoopIsCounter = vtLoopPlaneNorm1 * vtContLoopPlaneNorm > EPS_SMALL; + if ( bFirstLoopIsCounter) { + NewLoopCCW = NewLoop1 ; + NewLoopCW = NewLoop2 ; + } + else { + NewLoopCCW = NewLoop2 ; + NewLoopCW = NewLoop1 ; + } + // // Creo il pezzo nuovo, il cui loop esterno è stato appena definito. + // FacetPiece PieceInn ; + // PieceInn.vPieceLoop.emplace_back( NewLoop1) ; + // PieceInn.nPiecePart = 1 ; + // // Assegno i loop interni del vecchio pezzo non tagliati da catene ai nuovi. + // for ( int nIL = 1 ; nIL < int( vNewPieces[nPart].vPieceLoop.size()) ; ++ nIL) { + // bool bUsed = false ; + // for ( int nU = 1 ; nU < int( vLoopIndexes.size()) - 1 ; ++ nU) { + // if ( nIL == vLoopIndexes[nU]) { + // bUsed = true ; + // break ; + // } + // } + // if ( bUsed) + // continue ; + // Point3d ptPointInnerLoop ; + // vNewPieces[nPart].vPieceLoop[nIL].GetFirstPoint( ptPointInnerLoop) ; + // if ( IsPointInsidePolyLine( ptPointInnerLoop, PieceInn.vPieceLoop[0])) { + // PieceInn.vPieceLoop.emplace_back( vNewPieces[nPart].vPieceLoop[nIL]) ; + // vNewPieces[nPart].vPieceLoop.erase( vNewPieces[nPart].vPieceLoop.begin() + nIL) ; + // -- nIL ; + // } + // } + // // Aggiungo al pezzo, da cui si stacca quello appena creato, il loop complementare a quello che appartiene al nuovo pezzo. + // vNewPieces[nPart].vPieceLoop.emplace_back( NewLoop2) ; + // vNewPieces[nPart].nPiecePart = - 1 ; + // vNewPieces.emplace_back( PieceInn) ; + // Creo il pezzo nuovo, il cui loop esterno è stato appena definito. + FacetPiece DetachedPiece ; + DetachedPiece.vPieceLoop.emplace_back( NewLoopCCW) ; + DetachedPiece.nPiecePart = bFirstLoopIsCounter ? 1 : - 1 ; + // Al pezzo che si stacca assegno i loop interni del vecchio pezzo non tagliati da catene. + for ( int nIL = 1 ; nIL < int( vNewPieces[nPart].vPieceLoop.size()) ; ++ nIL) { + bool bUsed = false ; + for ( int nU = 1 ; nU < int( vLoopIndexes.size()) - 1 ; ++ nU) { + if ( nIL == vLoopIndexes[nU]) { + bUsed = true ; + break ; + } + } + if ( bUsed) + continue ; + Point3d ptPointInnerLoop ; + vNewPieces[nPart].vPieceLoop[nIL].GetFirstPoint( ptPointInnerLoop) ; + if ( IsPointInsidePolyLine( ptPointInnerLoop, DetachedPiece.vPieceLoop[0])) { + DetachedPiece.vPieceLoop.emplace_back( vNewPieces[nPart].vPieceLoop[nIL]) ; + vNewPieces[nPart].vPieceLoop.erase( vNewPieces[nPart].vPieceLoop.begin() + nIL) ; + // Cambio il numero dei loop talgiati + for ( int nIntersLoop = 0 ; nIntersLoop < int( vLoopIndexes.size()) ; ++ nIntersLoop) { + if ( vLoopIndexes[nIntersLoop] > nIL) + -- vLoopIndexes[nIntersLoop] ; + } + -- nIL ; + } + } + // Aggiungo al pezzo, da cui si stacca quello appena creato, il loop complementare a quello che appartiene al pezzo che si stacca. + vLoopIndexes.resize(int(vLoopIndexes.size()) - 1); + sort( vLoopIndexes.begin(), vLoopIndexes.end(), [] ( int nIndex1, int nIndex2) { return nIndex1 > nIndex2 ; }) ; + for (int nLoopInd = 0; nLoopInd < int(vLoopIndexes.size()); ++nLoopInd) { + vNewPieces[nPart].vPieceLoop.erase(vNewPieces[nPart].vPieceLoop.begin() + vLoopIndexes[nLoopInd]); + } + vNewPieces[nPart].vPieceLoop.emplace_back( NewLoopCW) ; + vNewPieces[nPart].nPiecePart = bFirstLoopIsCounter ? - 1 : 1 ; + vNewPieces.emplace_back( DetachedPiece) ; + } + // Elimino catene usate. + sort( vChainIndex.begin(), vChainIndex.end(), [] ( int nIndex1, int nIndex2) { return nIndex1 > nIndex2 ; }) ; + for ( int nChInd = 0 ; nChInd < int( vChainIndex.size()) ; ++ nChInd) { + cvOpenChain.erase( cvOpenChain.begin() + vChainIndex[nChInd]) ; + } + // Interrompo il ciclo sulle parti. + break ; + } + } + } + // Assegno i loop chiusi interni alle rispettive parti di faccia. + // Ciclo sui pezzi di facet. + int nPieceNum = int( vNewPieces.size()) ; + for ( int nPieceN = 0 ; nPieceN < nPieceNum ; ++ nPieceN) { + // Ciclo sui loop interni + for ( int nInnL = 0 ; nInnL < int( cvClosedChain.size()) ; ++ nInnL) { + // Trasformo il loop interno in PolyLine. + PolyLine CurInnerLoop ; + CurInnerLoop.AddUPoint( 0., cvClosedChain[nInnL][0].ptSt) ; + for ( int nSeg = 0 ; nSeg < int( cvClosedChain[nInnL].size()) ; ++ nSeg) { + CurInnerLoop.AddUPoint( 0., cvClosedChain[nInnL][nSeg].ptEn) ; + } + Plane3d plPlane ; + double dArea ; + if ( ! CurInnerLoop.IsClosedAndFlat( plPlane, dArea) || dArea < EPS_SMALL) + continue ; + // Ciclo sui punti del loop interno. + PNTULIST& LoopList = CurInnerLoop.GetUPointList() ; + for ( auto itInn = LoopList.begin() ; itInn != LoopList.end() ; ++ itInn) { + Point3d ptInnP = itInn->first ; + Point3d ptInnNextP ; + auto itInnNext = itInn ; + ++ itInnNext ; + if ( itInnNext != LoopList.end()) + ptInnNextP = itInnNext->first ; + if ( IsPointInsidePolyLine( ptInnP, vNewPieces[nPieceN].vPieceLoop[0]) || ( itInnNext != LoopList.end() && + IsPointInsidePolyLine( 0.5 * ( ptInnP + ptInnNextP), vNewPieces[nPieceN].vPieceLoop[0]))) { + Polygon3d AuxPolygon ; + AuxPolygon.FromPolyLine( CurInnerLoop) ; + Vector3d vtInnLoopNorm = AuxPolygon.GetVersN() ; + if ( vtFacetNorm * vtInnLoopNorm < 0.) { + // Aggiungo loop al pezzo. + vNewPieces[nPieceN].nPiecePart = 1 ; + vNewPieces[nPieceN].vPieceLoop.emplace_back( CurInnerLoop) ; + // Aggiungo nuovo pezzo. + vNewPieces.emplace_back() ; + vNewPieces.back().vPieceLoop.emplace_back( CurInnerLoop) ; + vNewPieces.back().vPieceLoop.back().Invert() ; + vNewPieces.back().nPiecePart = - 1 ; + // Cerco loop interni a quello appena aggiunto + INTVECTOR vSecondLevel ; + for ( int nSI = 1 ; nSI < int( vNewPieces[nPieceN].vPieceLoop.size()) ; ++ nSI) { + PNTULIST& SecLevLoopList = vNewPieces[nPieceN].vPieceLoop[nSI].GetUPointList() ; + for ( auto itSL = SecLevLoopList.begin() ; itSL != SecLevLoopList.end() ; ++ itSL) { + Point3d ptPntSL = itSL->first ; + if ( IsPointInsidePolyLine( ptPntSL, vNewPieces.back().vPieceLoop.back())) { + vSecondLevel.emplace_back( nSI) ; + break ; + } + } + } + // Aggiungo i loop al nuovo pezzo e li tolgo dal precedente. + for ( int nSI = 0 ; nSI < int( vSecondLevel.size()) ; ++ nSI) + vNewPieces.back().vPieceLoop.emplace_back( vNewPieces[nPieceN].vPieceLoop[vSecondLevel[nSI]]) ; + for ( int nSI = 0 ; nSI < int( vSecondLevel.size()) ; ++ nSI) + vNewPieces[nPieceN].vPieceLoop.erase( vNewPieces[nPieceN].vPieceLoop.begin() + vSecondLevel[nSI]) ; + break ; + } + else { + // Aggiungo loop al pezzo. + vNewPieces[nPieceN].nPiecePart = - 1 ; + vNewPieces[nPieceN].vPieceLoop.emplace_back( CurInnerLoop) ; + vNewPieces[nPieceN].vPieceLoop.back().Invert() ; + // Aggiungo nuovo pezzo. + vNewPieces.emplace_back() ; + vNewPieces.back().vPieceLoop.emplace_back( CurInnerLoop) ; + vNewPieces.back().nPiecePart = 1 ; + // Cerco loop interni a quello appena aggiunto + INTVECTOR vSecondLevel ; + for ( int nSI = 1 ; nSI < int( vNewPieces[nPieceN].vPieceLoop.size()) ; ++ nSI) { + PNTULIST& SecLevLoopList = vNewPieces[nPieceN].vPieceLoop[nSI].GetUPointList() ; + for ( auto itSL = SecLevLoopList.begin() ; itSL != SecLevLoopList.end() ; ++ itSL) { + Point3d ptPntSL = itSL->first ; + if ( IsPointInsidePolyLine( ptPntSL, vNewPieces.back().vPieceLoop.back())) { + vSecondLevel.emplace_back( nSI) ; + break ; + } + } + } + // Aggiungo i loop al nuovo pezzo e li tolgo dal precedente. + for ( int nSI = 0 ; nSI < int( vSecondLevel.size()) ; ++ nSI) + vNewPieces.back().vPieceLoop.emplace_back( vNewPieces[nPieceN].vPieceLoop[vSecondLevel[nSI]]) ; + for ( int nSI = 0 ; nSI < int( vSecondLevel.size()) ; ++ nSI) + vNewPieces[nPieceN].vPieceLoop.erase( vNewPieces[nPieceN].vPieceLoop.begin() + vSecondLevel[nSI]) ; + break ; + } + } + } + } + } + // Aggiungo al loop esterno i punti dei loop interni che lo toccano. + // Ciclo sui pezzi della faccia. + for ( int nPieceN = 0 ; nPieceN < nPieceNum ; ++ nPieceN) { + // Ciclo sui segmenti del loop esterno. + PNTULIST& ExtLoopList = vNewPieces[nPieceN].vPieceLoop[0].GetUPointList() ; + auto itSt = ExtLoopList.begin() ; auto itEn = itSt ; ++ itEn ; + for ( ; itEn != ExtLoopList.end(); ++itSt, ++itEn) { + Point3d ptSt = itSt->first ; + Point3d ptEn = itEn->first ; + Vector3d vtSeg = ptEn - ptSt ; + double dSegLen = vtSeg.Len() ; + vtSeg /= dSegLen ; + // Vettore dei punti dei loop interni che stanno sul segmento del loop esterno + PNTUVECTOR vPointWithOrder ; + // Ciclo sui loop interni del pezzo + int nInnerLoopNum = int( vNewPieces[nPieceN].vPieceLoop.size()) ; + for ( int nInnLoop = 1 ; nInnLoop < nInnerLoopNum ; ++ nInnLoop) { + // Ciclo sui punti del loop interno. + Point3d ptInnPoint ; + bool bIsFirst = true ; + bool bContinue = vNewPieces[nPieceN].vPieceLoop[nInnLoop].GetFirstPoint( ptInnPoint) ; + while ( bContinue) { + DistPointLine DistCalculator( ptInnPoint, ptSt, ptEn) ; + double dDist ; + DistCalculator.GetDist( dDist) ; + double dLongPos = ( ptInnPoint - ptSt) * vtSeg ; + if ( dDist < 10 * EPS_SMALL && dLongPos > 0. && dLongPos < dSegLen) { + POINTU NewPointU ; + NewPointU.first = ptInnPoint ; + NewPointU.second = dLongPos ; + if ( ! bIsFirst) + vPointWithOrder.emplace_back( NewPointU) ; + } + bIsFirst = false ; + bContinue = vNewPieces[nPieceN].vPieceLoop[nInnLoop].GetNextPoint( ptInnPoint) ; + } + } + // Riordino i punti interni sul segmento esterno in funzione della distanza dall'origine di esso + for ( int nPi = 0 ; nPi < int( vPointWithOrder.size()) - 1 ; ++ nPi) { + for ( int nPj = nPi + 1 ; nPj < int( vPointWithOrder.size()) ; ++ nPj) { + if ( vPointWithOrder[nPi].second > vPointWithOrder[nPj].second) { + swap( vPointWithOrder[nPi], vPointWithOrder[nPj]) ; + } + } + } + // Aggiungo i punti al loop esterno + for ( int nPi = 0 ; nPi < int( vPointWithOrder.size()) ; ++ nPi) { + itSt = ExtLoopList.emplace( itEn, vPointWithOrder[nPi]) ; + } + } + } + // Se non ho diviso la faccia, la elimino + if ( int( vNewPieces.size()) == 1) + NewFacet.erase( it->first) ; + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfTriMesh::EdgeInteriorContactManager( const SurfTriMesh& OthSurf, + const INTERSCHAINMAP& InterInterLineMap, + const INTERSEDGEMAP& EdgeInterLineMap) +{ + // Ciclo su tutte le facce. + for ( auto it = EdgeInterLineMap.begin() ; it != EdgeInterLineMap.end() ; ++ it) { + int nFacet = it->first ; + const vector& vEdgeContact = it->second ; + // Triangoli della faccia + INTVECTOR vFacetTria ; + GetAllTriaInFacet( nFacet, vFacetTria) ; + // Versore normale alla faccia. + Vector3d vtN = m_vTria[m_vFacet[nFacet]].vtN ; + // Se la faccia è stata tagliata, salto alla prossima faccia. + if ( InterInterLineMap.find( nFacet) != InterInterLineMap.end()) + continue ; + int nInOutPart = 0 ; + // Ciclo sui contatti edge-interno della faccia. + for ( const IntersEdge& Edge : vEdgeContact) { + // Estremi del segmento di contatto + Point3d ptSegSt = Edge.ptSt ; + Point3d ptSegEn = Edge.ptEn ; + Vector3d vtSegDir = ptSegEn - ptSegSt ; + double dLen = vtSegDir.Len() ; + if ( dLen < EPS_SMALL) + continue ; + vtSegDir /= dLen ; + // Cerco il tratto della frontiera della faccia su cui giace il segmento di contatto. + Vector3d vtLoopSeg ; + POLYLINEVECTOR vFacetLoop ; + GetFacetLoops( nFacet, vFacetLoop) ; + for ( int nL = 0 ; nL < int( vFacetLoop.size()) && nInOutPart == 0 ; ++ nL) { + Point3d ptLs, ptLe ; + bool bContinue = vFacetLoop[nL].GetFirstPoint( ptLs) && vFacetLoop[nL].GetNextPoint( ptLe) ; + while ( bContinue) { + DistPointLine StartPointLineDistCalc( ptLs, ptSegSt, ptSegEn, false) ; + double dDistStart ; + StartPointLineDistCalc.GetDist( dDistStart) ; + DistPointLine EndPointLineDistCalc( ptLe, ptSegSt, ptSegEn, false) ; + double dDistEnd ; + EndPointLineDistCalc.GetDist( dDistEnd) ; + double dUS = ( ptLs - ptSegSt) * vtSegDir ; + double dUE = ( ptLe - ptSegSt) * vtSegDir ; + // Segmento sovrapposto + if ( dDistStart < EPS_SMALL && dDistEnd < EPS_SMALL && dUS < dLen + EPS_SMALL && dUE > - EPS_SMALL) { + vtLoopSeg = ptLe - ptLs ; + vtLoopSeg.Normalize() ; + bContinue = false ; + } + else { + ptLs = ptLe ; + bContinue = vFacetLoop[nL].GetNextPoint( ptLe) ; + } + } + } + // Determino il valore dell'indice interno/esterno. + Vector3d vtIn = vtN ^ vtLoopSeg ; + // Ciclo sulle facce di contatto dell'altra superficie. + for ( int nOthFacet = 0 ; nOthFacet < int( Edge.vOthFacetIndex.size()) && nInOutPart == 0 ; ++ nOthFacet) { + int nOthFacetIndex = Edge.vOthFacetIndex[nOthFacet] ; + // Versore normale all'altra faccia. + Vector3d vtOthN = OthSurf.m_vTria[OthSurf.m_vFacet[nOthFacetIndex]].vtN ; + // Valore dell'indice interno/esterno. + nInOutPart = ( vtIn * vtOthN < - EPS_SMALL ? 1 : ( vtIn * vtOthN > EPS_SMALL ? - 1 : 0)) ; + } + // Ciclo sui triangoli della faccia + for ( int& nT : vFacetTria) { + // Assegno indice interno/esterno al triangolo + m_vTria[nT].nTempPart = nInOutPart ; + Triangle3d trTria ; + GetTriangle( nT, trTria) ; + trTria.Validate() ; + // Se un segmento del triangolo si sovrappone a quello di contatto, lo marco come invalicabile. + for ( int n = 0 ; n < 3 ; ++ n) { + Point3d ptTS = trTria.GetP( n) ; + Point3d ptTE = trTria.GetP( ( n + 1) % 3) ; + DistPointLine StartPointLineDistCalc( ptTS, ptSegSt, ptSegEn, false) ; + double dDistStart ; + StartPointLineDistCalc.GetDist( dDistStart) ; + DistPointLine EndPointLineDistCalc( ptTE, ptSegSt, ptSegEn, false) ; + double dDistEnd ; + EndPointLineDistCalc.GetDist( dDistEnd) ; + double dUS = ( ptTS - ptSegSt) * vtSegDir ; + double dUE = ( ptTE - ptSegSt) * vtSegDir ; + // Segmento sovrapposto + if ( dDistStart < EPS_SMALL && dDistEnd < EPS_SMALL && dUS < dLen + EPS_SMALL && dUE > - EPS_SMALL) { + m_vTria[nT].nETempFlag[n] = 1 ; + } + } + } + } + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfTriMesh::EdgeEdgeContactManager( const SurfTriMesh& OthSurf, + const INTERSCHAINMAP& InterInterLineMap, + const INTERSEDGEMAP& EdgeEdgeLineMap) +{ + // Ciclo su tutte le facce. + for ( auto it = EdgeEdgeLineMap.begin() ; it != EdgeEdgeLineMap.end() ; ++ it) { + int nFacet = it->first ; + const vector& vEdgeContact = it->second ; + // Triangoli della faccia + INTVECTOR vFacetTria ; + GetAllTriaInFacet( nFacet, vFacetTria) ; + // Versore normale alla faccia. + Vector3d vtN = m_vTria[m_vFacet[nFacet]].vtN ; + // Se la faccia è stata tagliata, salto alla prossima faccia. + if ( InterInterLineMap.find( nFacet) != InterInterLineMap.end()) + continue ; + int nInOutPart = 0 ; + // Ciclo sui contatti edge-interno della faccia. + for ( const IntersEdge& Edge : vEdgeContact) { + // Estremi del segmento di contatto + Point3d ptSegSt = Edge.ptSt ; + Point3d ptSegEn = Edge.ptEn ; + Vector3d vtSegDir = ptSegEn - ptSegSt ; + double dLen = vtSegDir.Len() ; + if ( dLen < EPS_SMALL) + continue ; + vtSegDir /= dLen ; + // Cerco il tratto della frontiera della faccia su cui giace il segmento di contatto. + Vector3d vtLoopSeg ; + POLYLINEVECTOR vFacetLoop ; + GetFacetLoops( nFacet, vFacetLoop) ; + for ( int nL = 0 ; nL < int( vFacetLoop.size()) && nInOutPart == 0 ; ++ nL) { + Point3d ptLs, ptLe ; + bool bContinue = vFacetLoop[nL].GetFirstPoint( ptLs) && vFacetLoop[nL].GetNextPoint( ptLe) ; + while ( bContinue) { + DistPointLine StartPointLineDistCalc( ptLs, ptSegSt, ptSegEn, false) ; + double dDistStart ; + StartPointLineDistCalc.GetDist( dDistStart) ; + DistPointLine EndPointLineDistCalc( ptLe, ptSegSt, ptSegEn, false) ; + double dDistEnd ; + EndPointLineDistCalc.GetDist( dDistEnd) ; + double dUS = ( ptLs - ptSegSt) * vtSegDir ; + double dUE = ( ptLe - ptSegSt) * vtSegDir ; + // Segmento sovrapposto + if ( dDistStart < EPS_SMALL && dDistEnd < EPS_SMALL && dUS < dLen + EPS_SMALL && dUE > - EPS_SMALL) { + vtLoopSeg = ptLe - ptLs ; + vtLoopSeg.Normalize() ; + bContinue = false ; + } + else { + ptLs = ptLe ; + bContinue = vFacetLoop[nL].GetNextPoint( ptLe) ; + } + } + } + // Determino il valore dell'indice interno/esterno. + // Vettore diretto verso l'interno della faccia. + Vector3d vtIn = vtN ^ vtLoopSeg ; + // Ciclo sulle facce di contatto dell'altra superficie. + int nOthFacet1 ; + int nOthFacet2 = - 1 ; + for ( nOthFacet1 = 0 ; nOthFacet1 < int( Edge.vOthFacetIndex.size()) - 1 && nInOutPart == 0 ; ++ nOthFacet1) { + int nOthFacetIndex1 = Edge.vOthFacetIndex[nOthFacet1] ; + Vector3d vtOthN1 = OthSurf.m_vTria[OthSurf.m_vFacet[nOthFacetIndex1]].vtN ; + for ( nOthFacet2 = nOthFacet1 + 1 ; nOthFacet2 < int( Edge.vOthFacetIndex.size()) && nInOutPart == 0 ; ++ nOthFacet2) { + int nOthFacetIndex2 = Edge.vOthFacetIndex[nOthFacet2] ; + Vector3d vtOthN2 = OthSurf.m_vTria[OthSurf.m_vFacet[nOthFacetIndex2]].vtN ; + if ( ! AreSameVectorApprox( vtOthN1, vtOthN2)) { + break ; + } + } + if ( nOthFacet2 != int( Edge.vOthFacetIndex.size())) + break ; + } + // Se l'indice interno/esterno non è stato assegnato + if ( nInOutPart == 0) { + // Se non ho trovato una coppia di facce, uso la prima. + if ( ( nOthFacet1 == int( Edge.vOthFacetIndex.size()) - 1 && nOthFacet2 == int( Edge.vOthFacetIndex.size())) || nOthFacet2 == - 1) { + ; + //int nOthFacetIndex1 = Edge.vOthFacetIndex[0] ; + //Vector3d vtOthN1 = OthSurf.m_vTria[OthSurf.m_vFacet[nOthFacetIndex1]].vtN ; + //// Valore dell'indice interno/esterno. + //nInOutPart = ( vtIn * vtOthN1 < - EPS_SMALL ? 1 : ( vtIn * vtOthN1 > EPS_SMALL ? - 1 : 0)) ; + } + // Due facce + else { + int nOthFacetIndex1 = Edge.vOthFacetIndex[nOthFacet1] ; + Vector3d vtOthN1 = OthSurf.m_vTria[OthSurf.m_vFacet[nOthFacetIndex1]].vtN ; + int nOthFacetIndex2 = Edge.vOthFacetIndex[nOthFacet2] ; + Vector3d vtOthN2 = OthSurf.m_vTria[OthSurf.m_vFacet[nOthFacetIndex2]].vtN ; + POLYLINEVECTOR vOthFacetLoop2 ; + OthSurf.GetFacetLoops( nOthFacetIndex2, vOthFacetLoop2) ; + Vector3d vtContactEdgeLoop2 ; + Point3d ptLs, ptLe ; + bool bContinue = true ; + for ( int nL = 0 ; nL < int( vOthFacetLoop2.size()) && bContinue ; ++ nL) { + bContinue = vOthFacetLoop2[nL].GetFirstPoint( ptLs) && vOthFacetLoop2[nL].GetNextPoint( ptLe) ; + while ( bContinue) { + DistPointLine StartPointLineDistCalc( ptLs, ptSegSt, ptSegEn, false) ; + double dDistStart ; + StartPointLineDistCalc.GetDist( dDistStart) ; + DistPointLine EndPointLineDistCalc( ptLe, ptSegSt, ptSegEn, false) ; + double dDistEnd ; + EndPointLineDistCalc.GetDist( dDistEnd) ; + double dUS = ( ptLs - ptSegSt) * vtSegDir ; + double dUE = ( ptLe - ptSegSt) * vtSegDir ; + // Segmento sovrapposto + if ( dDistStart < EPS_SMALL && dDistEnd < EPS_SMALL && dUS < dLen + EPS_SMALL && dUE > - EPS_SMALL) { + vtContactEdgeLoop2 = ptLe - ptLs ; + vtContactEdgeLoop2.Normalize() ; + bContinue = false ; + } + else { + ptLs = ptLe ; + bContinue = vOthFacetLoop2[nL].GetNextPoint( ptLe) ; + } + } + } + Vector3d vtInFacet2 = vtN ^ vtContactEdgeLoop2 ; + // Convesso + if ( vtInFacet2 * vtOthN1 < 0.) { + nInOutPart = vtIn * vtOthN1 < 0 && vtIn * vtOthN2 < 0 ? 1 : - 1 ; + } + // Concavo + else { + nInOutPart = vtIn * vtOthN1 > 0 && vtIn * vtOthN2 > 0 ? - 1 : 1 ; + } + } + } + // Ciclo sui triangoli della faccia + for ( int& nT : vFacetTria) { + // Assegno indice interno/esterno al triangolo + m_vTria[nT].nTempPart = nInOutPart ; + Triangle3d trTria ; + GetTriangle( nT, trTria) ; + trTria.Validate() ; + // Se un segmento del triangolo si sovrappone a quello di contatto, lo marco come invalicabile. + for ( int n = 0 ; n < 3 ; ++ n) { + Point3d ptTS = trTria.GetP( n) ; + Point3d ptTE = trTria.GetP( ( n + 1) % 3) ; + DistPointLine StartPointLineDistCalc( ptTS, ptSegSt, ptSegEn, false) ; + double dDistStart ; + StartPointLineDistCalc.GetDist( dDistStart) ; + DistPointLine EndPointLineDistCalc( ptTE, ptSegSt, ptSegEn, false) ; + double dDistEnd ; + EndPointLineDistCalc.GetDist( dDistEnd) ; + double dUS = ( ptTS - ptSegSt) * vtSegDir ; + double dUE = ( ptTE - ptSegSt) * vtSegDir ; + // Segmento sovrapposto + if ( dDistStart < EPS_SMALL && dDistEnd < EPS_SMALL && dUS < dLen + EPS_SMALL && dUE > - EPS_SMALL) { + m_vTria[nT].nETempFlag[n] = 1 ; + } + } + } + } + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfTriMesh::RetriangulateFacetPieces( const PieceMap& NewFacet, + const INTERSEDGEMAP& EdgeInterLineMap, + const INTERSEDGEMAP& EdgeEdgeLineMap) +{ + // Vettore degli indici delle facce + INTVECTOR vFacetIndexes ; + // Ciclo sulle facce. + for ( auto it = NewFacet.begin() ; it != NewFacet.end() ; ++ it) { + // Accedo al colore di un triangolo della faccia e cancello i triangoli della faccia. + INTVECTOR vFacetTria ; + GetAllTriaInFacet( it->first, vFacetTria) ; + for ( int& nT : vFacetTria) + RemoveTriangle( nT) ; + } + int nIndexPosInVec = 0 ; + for ( auto it = NewFacet.begin() ; it != NewFacet.end() ; ++ it) { + const vector& PiecesVector = it->second ; + // Ciclo sui nuovi pezzi di faccia. + int nPartNum = int( PiecesVector.size()) ; + for ( int nPart = 0 ; nPart < nPartNum ; ++ nPart) { + PNTVECTOR vPt ; + INTVECTOR vTr ; + if ( Triangulate().Make( PiecesVector[nPart].vPieceLoop, vPt, vTr)) { + // Inserisco i nuovi triangoli + for ( int n = 0 ; n < int( vTr.size()) - 2 ; n += 3) { + int nNewTriaVertId[3] = { vTr[n], vTr[n + 1], vTr[n + 2]} ; + int nNewId[3] = { AddVertex( vPt[nNewTriaVertId[0]]), + AddVertex( vPt[nNewTriaVertId[1]]), + AddVertex( vPt[nNewTriaVertId[2]])} ; + // Il colore passato nel secondo parametro è definito perché il vettore delle facce ha ancora salvato l'indice di un suo triangolo e + // il triangolo è cancellato semplicente assegnadno la costante apposita VT_DEL (-2) a nIdVert[0]; ma il suo colore resta definito. + int nNewTriaNum = AddTriangle( nNewId, m_vTria[m_vFacet[it->first]].nTFlag) ; + if ( IsValidSvt( nNewTriaNum)) { + // Assegno l'indice della parte interno/esterno. + m_vTria[nNewTriaNum].nTempPart = PiecesVector[nPart].nPiecePart ; + // Indici parte interno/esterno invalicabili + m_vTria[nNewTriaNum].nETempFlag[0] = 0 ; + m_vTria[nNewTriaNum].nETempFlag[1] = 0 ; + m_vTria[nNewTriaNum].nETempFlag[2] = 0 ; + // Se la faccia ha avuto un contatto edge-interior, cerco edge invalicabili. + auto itEdgeInterEdge = EdgeInterLineMap.find( it->first) ; + auto itEdgeEdgeEdge = EdgeEdgeLineMap.find( it->first) ; + if ( itEdgeInterEdge != EdgeInterLineMap.end()) { + const vector& vEdgeContact = itEdgeInterEdge->second ; + Triangle3d trTria ; + GetTriangle( nNewTriaNum, trTria) ; + // Ciclo sui segmenti del triangolo. + for ( int n = 0 ; n < 3 ; ++ n) { + Point3d ptTS = trTria.GetP( n) ; + Point3d ptTE = trTria.GetP( ( n + 1) % 3) ; + for (int m = 0; m < int(vEdgeContact.size()) ; ++ m) { + Point3d ptEdgeSt = vEdgeContact[m].ptSt ; + Point3d ptEdgeEn = vEdgeContact[m].ptEn ; + Vector3d vtEdgeDir = ptEdgeEn - ptEdgeSt ; + double dLen = vtEdgeDir.Len() ; + if ( dLen < EPS_SMALL) + continue ; + DistPointLine StartPointLineDistCalc( ptTS, ptEdgeSt, ptEdgeEn, false) ; + double dDistStart ; + StartPointLineDistCalc.GetDist( dDistStart) ; + DistPointLine EndPointLineDistCalc( ptTE, ptEdgeSt, ptEdgeEn, false) ; + double dDistEnd ; + EndPointLineDistCalc.GetDist( dDistEnd) ; + double dUS = ( ptTS - ptEdgeSt) * vtEdgeDir ; + double dUE = ( ptTE - ptEdgeSt) * vtEdgeDir ; + // Segmento sovrapposto + if ( dDistStart < EPS_SMALL && dDistEnd < EPS_SMALL && dUS < dLen && dUE > 0) { + m_vTria[nNewTriaNum].nETempFlag[n] = 1 ; + break ; + } + } + } + } + else if ( itEdgeEdgeEdge != EdgeEdgeLineMap.end()) { + const vector& vEdgeContact = itEdgeEdgeEdge->second ; + Triangle3d trTria ; + GetTriangle( nNewTriaNum, trTria) ; + // Ciclo sui segmenti del triangolo. + for ( int n = 0 ; n < 3 ; ++ n) { + Point3d ptTS = trTria.GetP( n) ; + Point3d ptTE = trTria.GetP( ( n + 1) % 3) ; + for (int m = 0; m < int(vEdgeContact.size()) ; ++ m) { + Point3d ptEdgeSt = vEdgeContact[m].ptSt ; + Point3d ptEdgeEn = vEdgeContact[m].ptEn ; + Vector3d vtEdgeDir = ptEdgeEn - ptEdgeSt ; + double dLen = vtEdgeDir.Len() ; + if ( dLen < EPS_SMALL) + continue ; + DistPointLine StartPointLineDistCalc( ptTS, ptEdgeSt, ptEdgeEn, false) ; + double dDistStart ; + StartPointLineDistCalc.GetDist( dDistStart) ; + DistPointLine EndPointLineDistCalc( ptTE, ptEdgeSt, ptEdgeEn, false) ; + double dDistEnd ; + EndPointLineDistCalc.GetDist( dDistEnd) ; + double dUS = ( ptTS - ptEdgeSt) * vtEdgeDir ; + double dUE = ( ptTE - ptEdgeSt) * vtEdgeDir ; + // Segmento sovrapposto + if ( dDistStart < EPS_SMALL && dDistEnd < EPS_SMALL && dUS < dLen && dUE > 0) { + m_vTria[nNewTriaNum].nETempFlag[n] = 1 ; + break ; + } + } + } + } + } + } + } + } + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfTriMesh::ItersectTriMeshFacets( SurfTriMesh& Other) +{ //////////////////////////////////////////////////////////////////////////////////////////////////////// + static int nTime = 0; + nTime++; + if (nTime == 32) + int mimi = 0; + //////////////////////////////////////////////////////////////////////////////////////////////////////// + SurfTriMesh& SurfB = Other ; + // Le superfici devono essere valide + if ( m_nStatus != OK || ! SurfB.IsValid()) + return false ; + // Unordered map dei segmenti di intersezione (contatti interno-interno) e dei contatti con edge + INTERSCHAINMAP IntersLineMapA, IntersLineMapB ; + INTERSEDGEMAP EdgeInnLineMapA, EdgeInnLineMapB ; + INTERSEDGEMAP EdgeEdgeLineMapA, EdgeEdgeLineMapB ; + // Setto il triangolo come né fuori né dentro + int nTriaNumA = GetTriangleSize(); + int nTriaNumB = SurfB.GetTriangleSize(); + for ( int nTA = 0 ; nTA < nTriaNumA ; ++ nTA) { + m_vTria[nTA].nTempPart = 0 ; + m_vTria[nTA].nETempFlag[0] = 0 ; + m_vTria[nTA].nETempFlag[1] = 0 ; + m_vTria[nTA].nETempFlag[2] = 0 ; + } + for ( int nTB = 0 ; nTB < nTriaNumB ; ++ nTB) { + SurfB.m_vTria[nTB].nTempPart = 0 ; + SurfB.m_vTria[nTB].nETempFlag[0] = 0 ; + SurfB.m_vTria[nTB].nETempFlag[1] = 0 ; + SurfB.m_vTria[nTB].nETempFlag[2] = 0 ; + } + // Ciclo sulle facce delle mesh + int nFacetNumA = GetFacetCount() ; + int nFacetNumB = SurfB.GetFacetCount() ; + for ( int nFA = 0 ; nFA < nFacetNumA ; ++ nFA) { + // Dati della faccia + POLYLINEVECTOR LoopVecA ; + GetFacetLoops( nFA, LoopVecA) ; + PtrOwner pRegA( GetBasicSurfFlatRegion( GetSurfFlatRegionFromPolyLineVector( LoopVecA))) ; + if ( pRegA == nullptr) + return false ; + SurfFlatRegion RegionA = *pRegA ; + // Recupero tutti i triangoli della superficie B che cadono nel box della faccia di A. + BBox3d b3BoxA ; + RegionA.GetLocalBBox( b3BoxA) ; + INTVECTOR vNearTria ; + SurfB.GetAllTriaOverlapBox( b3BoxA, vNearTria) ; + // Determino le facce a cui appartengono i tirangoli che cadono nel box + INTVECTOR vFacetIndexesB ; + for ( int& nT : vNearTria) { + int nF = SurfB.GetFacetFromTria(nT) ; + int n ; + for ( n = 0 ; n < int( vFacetIndexesB.size()) ; ++ n) { + if ( nF == vFacetIndexesB[n]) + break ; + } + if ( n == int(vFacetIndexesB.size())) + vFacetIndexesB.emplace_back( nF) ; + } + for ( int& nFB : vFacetIndexesB) { + // Dati della faccia + POLYLINEVECTOR LoopVecB ; + SurfB.GetFacetLoops( nFB, LoopVecB) ; + PtrOwner pRegB( GetBasicSurfFlatRegion( GetSurfFlatRegionFromPolyLineVector( LoopVecB))) ; + if ( pRegB == nullptr) + return false ; + SurfFlatRegion RegionB = *pRegB ; + // Interseco le due facce + LineFacetClassVector CommonIntersection ; + // Intersezione fra le facce + if ( IntersFacetFacet( RegionA, LoopVecA[0], RegionB, LoopVecB[0], CommonIntersection)) { + // Ciclo sulle parti dell'intersezione + for ( int nPart = 0 ; nPart < int( CommonIntersection.size()) ; ++ nPart) { + // Intersezione nell'interno di entrambe le facce + if ( CommonIntersection[nPart].nTypeA == CRVC_IN && + CommonIntersection[nPart].nTypeB == CRVC_IN) { + // Salvo intersezione per la faccia A + auto itA = IntersLineMapA.find( nFA) ; + if ( itA != IntersLineMapA.end()) { + itA->second.emplace_back( IntersInnSeg( CommonIntersection[nPart].ptSt, CommonIntersection[nPart].ptEn)) ; + } + else { + IntersLineMapA.emplace( nFA, IntersInnChain( 1, IntersInnSeg( CommonIntersection[nPart].ptSt, CommonIntersection[nPart].ptEn))) ; + } + // Salvo intersezione per la faccia B + auto itB = IntersLineMapB.find( nFB) ; + if ( itB != IntersLineMapB.end()) { + itB->second.emplace_back( IntersInnSeg( CommonIntersection[nPart].ptEn, CommonIntersection[nPart].ptSt)) ; + } + else { + IntersLineMapB.emplace( nFB, IntersInnChain( 1, IntersInnSeg( CommonIntersection[nPart].ptEn, CommonIntersection[nPart].ptSt))) ; + } + } + // Intersezione all'interno della faccia A + else if ( CommonIntersection[nPart].nTypeA == CRVC_IN) { + // Salvo intersezione per la faccia A + auto itA = IntersLineMapA.find( nFA) ; + if ( itA != IntersLineMapA.end()) { + itA->second.emplace_back( IntersInnSeg( CommonIntersection[nPart].ptSt, CommonIntersection[nPart].ptEn)) ; + } + else { + IntersLineMapA.emplace( nFA, IntersInnChain( 1, IntersInnSeg( CommonIntersection[nPart].ptSt, CommonIntersection[nPart].ptEn))) ; + } + // Salvo intersezione per la faccia B + auto itB = EdgeInnLineMapB.find( nFB) ; + if ( itB != EdgeInnLineMapB.end()) { + int nE ; + for ( nE = 0 ; nE < int( itB->second.size()) ; ++ nE) { + if ( AreSamePointExact( itB->second[nE].ptSt, CommonIntersection[nPart].ptEn) && + AreSamePointExact( itB->second[nE].ptEn, CommonIntersection[nPart].ptSt)) { + itB->second[nE].vOthFacetIndex.emplace_back( nFA) ; + break ; + } + } + if ( nE == int( itB->second.size())) { + itB->second.emplace_back( IntersEdge( CommonIntersection[nPart].ptEn, CommonIntersection[nPart].ptSt, INTVECTOR( 1, nFA))) ; + } + } + else { + EdgeInnLineMapB.emplace( nFB, IntersEdgeVec( 1, IntersEdge( CommonIntersection[nPart].ptEn, CommonIntersection[nPart].ptSt, + INTVECTOR( 1, nFA)))) ; + } + } + // Intersezione all'interno della faccia B + else if ( CommonIntersection[nPart].nTypeB == CRVC_IN) { + // Salvo intersezione per la faccia A + auto itA = EdgeInnLineMapA.find( nFA) ; + if ( itA != EdgeInnLineMapA.end()) { + int nE ; + for ( nE = 0 ; nE < int( itA->second.size()) ; ++ nE) { + if ( AreSamePointExact( itA->second[nE].ptSt, CommonIntersection[nPart].ptSt) && + AreSamePointExact( itA->second[nE].ptEn, CommonIntersection[nPart].ptEn)) { + itA->second[nE].vOthFacetIndex.emplace_back( nFB) ; + break ; + } + } + if ( nE == int( itA->second.size())) { + itA->second.emplace_back( IntersEdge( CommonIntersection[nPart].ptSt, CommonIntersection[nPart].ptEn, INTVECTOR( 1, nFB))) ; + } + } + else { + EdgeInnLineMapA.emplace( nFA, IntersEdgeVec( 1, IntersEdge( CommonIntersection[nPart].ptSt, CommonIntersection[nPart].ptEn, + INTVECTOR( 1, nFB)))) ; + } + // Salvo intersezione per la faccia B + auto itB = IntersLineMapB.find( nFB) ; + if ( itB != IntersLineMapB.end()) { + itB->second.emplace_back( IntersInnSeg( CommonIntersection[nPart].ptEn, CommonIntersection[nPart].ptSt)) ; + } + else { + IntersLineMapB.emplace( nFB, IntersInnChain( 1, IntersInnSeg( CommonIntersection[nPart].ptEn, CommonIntersection[nPart].ptSt))) ; + } + } + // Intersezione sulla frontiera di entrambe le facce + else { + // Salvo intersezione per la faccia A + auto itA = EdgeEdgeLineMapA.find( nFA) ; + if ( itA != EdgeEdgeLineMapA.end()) { + int nE ; + for ( nE = 0 ; nE < int( itA->second.size()) ; ++ nE) { + if ( ( AreSamePointExact( itA->second[nE].ptSt, CommonIntersection[nPart].ptSt) && + AreSamePointExact( itA->second[nE].ptEn, CommonIntersection[nPart].ptEn)) || + ( AreSamePointExact( itA->second[nE].ptSt, CommonIntersection[nPart].ptEn) && + AreSamePointExact( itA->second[nE].ptEn, CommonIntersection[nPart].ptSt))) { + itA->second[nE].vOthFacetIndex.emplace_back( nFB) ; + break ; + } + } + if ( nE == int( itA->second.size())) { + itA->second.emplace_back( IntersEdge( CommonIntersection[nPart].ptSt, CommonIntersection[nPart].ptEn, INTVECTOR( 1, nFB))); + } + } + else { + EdgeEdgeLineMapA.emplace( nFA, IntersEdgeVec( 1, IntersEdge( CommonIntersection[nPart].ptSt, CommonIntersection[nPart].ptEn, + INTVECTOR( 1, nFB)))) ; + } + // Salvo intersezione per la faccia B + auto itB = EdgeEdgeLineMapB.find( nFB) ; + if ( itB != EdgeEdgeLineMapB.end()) { + int nE ; + for ( nE = 0 ; nE < int( itB->second.size()) ; ++ nE) { + if ( ( AreSamePointExact( itB->second[nE].ptSt, CommonIntersection[nPart].ptEn) && + AreSamePointExact( itB->second[nE].ptEn, CommonIntersection[nPart].ptSt)) || + ( AreSamePointExact( itB->second[nE].ptSt, CommonIntersection[nPart].ptSt) && + AreSamePointExact( itB->second[nE].ptEn, CommonIntersection[nPart].ptEn))) { + itB->second[nE].vOthFacetIndex.emplace_back( nFA) ; + break ; + } + } + if ( nE == int( itB->second.size())) { + itB->second.emplace_back( IntersEdge( CommonIntersection[nPart].ptEn, CommonIntersection[nPart].ptSt, INTVECTOR( 1, nFA))) ; + } + } + else { + EdgeEdgeLineMapB.emplace( nFB, IntersEdgeVec( 1, IntersEdge( CommonIntersection[nPart].ptEn, CommonIntersection[nPart].ptSt, + INTVECTOR( 1, nFA)))) ; + } + } + } + } + } + } + + // Divido le facce + PieceMap NewFacetA, NewFacetB ; + SplitFacet( IntersLineMapA, NewFacetA) ; + SurfB.SplitFacet( IntersLineMapB, NewFacetB) ; + + // Facce EdgeInn + EdgeInteriorContactManager( SurfB, IntersLineMapA, EdgeInnLineMapA) ; + SurfB.EdgeInteriorContactManager( *this, IntersLineMapB, EdgeInnLineMapB) ; + + // Facce Edge Edge + EdgeEdgeContactManager( SurfB, IntersLineMapA, EdgeEdgeLineMapA) ; + SurfB.EdgeEdgeContactManager( *this, IntersLineMapB, EdgeEdgeLineMapB) ; + + // Se non ci sono stati tagli, valuto se una è tutta interna all'altra. + if ( int( NewFacetA.size() + NewFacetB.size()) == 0) { + int nVertNum = 0 ; + Point3d ptVert ; + int nCurVert = GetFirstVertex( ptVert) ; + int nInOutNumA = 0 ; + while ( nInOutNumA == 0 && nCurVert != SVT_NULL) { + int nFacetNum = - 1 ; + double dMinDist = DBL_MAX ; + for ( int nFB = 0 ; nFB < SurfB.GetFacetCount() ; ++ nFB) { + // Loop della faccia della superficie B + POLYLINEVECTOR vFacetLoopVec ; + SurfB.GetFacetLoops( nFB, vFacetLoopVec) ; + double dDist ; + if ( DistPointFacet( ptVert, vFacetLoopVec, dDist) && dDist < dMinDist) { + dMinDist = dDist ; + nFacetNum = nFB ; + } + } + if ( nFacetNum >= 0) { + Triangle3d trTriaB ; + SurfB.GetTriangle( SurfB.m_vFacet[nFacetNum], trTriaB) ; + trTriaB.Validate() ; + if ( ( ptVert - trTriaB.GetP( 0)) * trTriaB.GetN() < - EPS_SMALL) + nInOutNumA = 1 ; + else if ( ( ptVert - trTriaB.GetP( 0)) * trTriaB.GetN() > EPS_SMALL) + nInOutNumA = - 1 ; + } + if ( nInOutNumA == 0) { + nCurVert = GetNextVertex( nVertNum, ptVert) ; + ++ nVertNum ; + } + } + // Se la superficie A non è interna valuto la posizione della superficie B. + int nInOutNumB = nInOutNumA == 1 ? - 1 : 0 ; + if ( nInOutNumB == 0) { + nVertNum = 0 ; + nCurVert = SurfB.GetFirstVertex( ptVert) ; + while ( nInOutNumB == 0 && nCurVert != SVT_NULL) { + int nFacetNum = - 1 ; + double dMinDist = DBL_MAX ; + for ( int nFA = 0 ; nFA < GetFacetCount() ; ++ nFA) { + // Loop della faccia della superficie A + POLYLINEVECTOR vFacetLoopVec ; + GetFacetLoops( nFA, vFacetLoopVec) ; + double dDist ; + if ( DistPointFacet( ptVert, vFacetLoopVec, dDist) && dDist < dMinDist) { + dMinDist = dDist ; + nFacetNum = nFA ; + } + } + if ( nFacetNum >= 0) { + Triangle3d trTriaA ; + GetTriangle( m_vFacet[nFacetNum], trTriaA) ; + trTriaA.Validate() ; + if ( ( ptVert - trTriaA.GetP( 0)) * trTriaA.GetN() < - EPS_SMALL) + nInOutNumB = 1 ; + else if ( ( ptVert - trTriaA.GetP( 0)) * trTriaA.GetN() > EPS_SMALL) + nInOutNumB = - 1 ; + + } + if ( nInOutNumB == 0) { + nCurVert = SurfB.GetNextVertex( nVertNum, ptVert) ; + ++ nVertNum ; + } + } + } + // Se la posizione della superficie A rispetto alla B non è definita e + // B è esterna ad A, allora assumiamo che siano reciprocamente esterne. + if ( nInOutNumA == 0 && nInOutNumA == - 1) + nInOutNumA = - 1 ; + // Assegno gli indici interni/esterni. + for ( int nTA = 0 ; nTA < nTriaNumA ; ++ nTA) { + m_vTria[nTA].nTempPart = nInOutNumA ; + } + for ( int nTB = 0 ; nTB < nTriaNumB ; ++ nTB) { + SurfB.m_vTria[nTB].nTempPart = nInOutNumB ; + } + } + +#define UseTria 0 +#if ! UseTria + // Gestisco facce sovrapposte. + // Ciclo sulle facce di A. + for ( int nFA = 0 ; nFA < nFacetNumA ; ++ nFA) { + auto itFacetA = NewFacetA.find( nFA) ; + // Faccia A divisa in pezzi. + if ( itFacetA != NewFacetA.end()) { + // Ciclo sui pezzi della faccia A. + for ( int nPieceNumA = 0 ; nPieceNumA < int( itFacetA->second.size()) ; ++ nPieceNumA) { + // Dati del pezzo di faccia di A + POLYLINEVECTOR& vPieceLoopsVecA = itFacetA->second[nPieceNumA].vPieceLoop ; + PtrOwner pRegA( GetBasicSurfFlatRegion( GetSurfFlatRegionFromPolyLineVector( vPieceLoopsVecA))) ; + if ( pRegA == nullptr) + return false ; + SurfFlatRegion RegionA = *pRegA ; + Plane3d plPlaneA ; + plPlaneA.Set( RegionA.GetPlanePoint(), RegionA.GetNormVersor()) ; + // Recupero tutti i triangoli della superficie B che cadono nel box del pezzo di faccia di A. + BBox3d b3BoxA ; + RegionA.GetLocalBBox( b3BoxA) ; + INTVECTOR vNearTria ; + SurfB.GetAllTriaOverlapBox( b3BoxA, vNearTria) ; + // Determino le facce a cui appartengono i tirangoli che cadono nel box + INTVECTOR vFacetIndexesB ; + for ( int& nT : vNearTria) { + int nF = SurfB.GetFacetFromTria( nT) ; + int n ; + for ( n = 0 ; n < int( vFacetIndexesB.size()) ; ++ n) { + if ( nF == vFacetIndexesB[n]) + break ; + } + if ( n == int( vFacetIndexesB.size())) + vFacetIndexesB.emplace_back( nF) ; + } + // Ciclo sulle facce di B + for ( int& nFB : vFacetIndexesB) { + auto itFacetB = NewFacetB.find( nFB) ; + // Faccia B divisa in pezzi + if ( itFacetB != NewFacetB.end()) { + // Ciclo sui pezzi della faccia B. + for ( int nPieceNumB = 0 ; nPieceNumB < int( itFacetB->second.size()) ; ++ nPieceNumB) { + // Dati del pezzo di faccia di B + POLYLINEVECTOR& vPieceLoopsVecB = itFacetB->second[nPieceNumB].vPieceLoop ; + PtrOwner pRegB( GetBasicSurfFlatRegion( GetSurfFlatRegionFromPolyLineVector( vPieceLoopsVecB))) ; + if ( pRegB == nullptr) + return false ; + SurfFlatRegion RegionB = *pRegB ; + Plane3d plPlaneB ; + plPlaneB.Set( RegionB.GetPlanePoint(), RegionB.GetNormVersor()) ; + // Intersezione tra i piani delle due facce: se non esiste esse sono complanari. + Point3d ptL ; Vector3d vtL ; + int nResPP = IntersPlanePlane( plPlaneA, plPlaneB, ptL, vtL) ; + if ( /*nResPP == IPPT_NO ||*/ nResPP == IPPT_OVERLAPS) { + SurfFlatRegion frIntersRegion = RegionA ; + frIntersRegion.Intersect( RegionB) ; + double dIntersRegArea ; + frIntersRegion.GetArea( dIntersRegArea) ; + // Assegno indice di parte ai pezzi. + if ( dIntersRegArea > EPS_SMALL) { + bool bCodirectedNorm = RegionA.GetNormVersor() * RegionB.GetNormVersor() > 0; + int nPartIndex = bCodirectedNorm ? 2 : - 2 ; + itFacetA->second[nPieceNumA].nPiecePart = nPartIndex; + itFacetB->second[nPieceNumB].nPiecePart = nPartIndex; + } + } + } + } + // Faccia B non divisa in pezzi + else { + // Dati della faccia + POLYLINEVECTOR vFacetLoopVecB ; + SurfB.GetFacetLoops( nFB, vFacetLoopVecB) ; + PtrOwner pRegB( GetBasicSurfFlatRegion( GetSurfFlatRegionFromPolyLineVector( vFacetLoopVecB))) ; + if ( pRegB == nullptr) + return false ; + SurfFlatRegion RegionB = *pRegB ; + Plane3d plPlaneB ; + plPlaneB.Set( RegionB.GetPlanePoint(), RegionB.GetNormVersor()) ; + // Intersezione tra i piani delle due facce: se non esiste esse sono complanari. + Point3d ptL ; Vector3d vtL ; + int nResPP = IntersPlanePlane( plPlaneA, plPlaneB, ptL, vtL) ; + if ( /*nResPP == IPPT_NO ||*/ nResPP == IPPT_OVERLAPS) { + SurfFlatRegion frIntersRegion = RegionA ; + frIntersRegion.Intersect( RegionB) ; + double dIntersRegArea ; + frIntersRegion.GetArea( dIntersRegArea) ; + // Assegno indice di parte al pezzo di faccia A e ai triangoli della faccia B. + if ( dIntersRegArea > EPS_SMALL) { + bool bCodirectedNorm = RegionA.GetNormVersor() * RegionB.GetNormVersor() > 0 ; + int nPartIndex = bCodirectedNorm ? 2 : - 2 ; + itFacetA->second[nPieceNumA].nPiecePart = nPartIndex ; + INTVECTOR vTB ; + SurfB.GetAllTriaInFacet( nFB, vTB) ; + for ( int& nTB : vTB) + SurfB.m_vTria[nTB].nTempPart = nPartIndex ; + } + } + } + } + } + } + // Faccia A non divisa in pezzi + else { + // Dati della faccia + POLYLINEVECTOR vFacetLoopsVecA ; + GetFacetLoops( nFA, vFacetLoopsVecA) ; + PtrOwner pRegA( GetBasicSurfFlatRegion( GetSurfFlatRegionFromPolyLineVector( vFacetLoopsVecA))) ; + if ( pRegA == nullptr) + return false ; + SurfFlatRegion RegionA = *pRegA ; + Plane3d plPlaneA ; + plPlaneA.Set( RegionA.GetPlanePoint(), RegionA.GetNormVersor()) ; + // Recupero tutti i triangoli della superficie B che cadono nel box del pezzo di faccia di A. + BBox3d b3BoxA ; + RegionA.GetLocalBBox( b3BoxA) ; + INTVECTOR vNearTria ; + SurfB.GetAllTriaOverlapBox( b3BoxA, vNearTria) ; + // Determino le facce a cui appartengono i tirangoli che cadono nel box + INTVECTOR vFacetIndexesB ; + for ( int& nT : vNearTria) { + int nF = SurfB.GetFacetFromTria( nT) ; + int n ; + for ( n = 0 ; n < int( vFacetIndexesB.size()) ; ++ n) { + if ( nF == vFacetIndexesB[n]) + break ; + } + if ( n == int( vFacetIndexesB.size())) + vFacetIndexesB.emplace_back( nF) ; + } + // Ciclo sulle facce di B + for ( int& nFB : vFacetIndexesB) { + auto itFacetB = NewFacetB.find( nFB) ; + // Faccia B divisa in pezzi + if ( itFacetB != NewFacetB.end()) { + for ( int nPieceNumB = 0 ; nPieceNumB < int( itFacetB->second.size()) ; ++ nPieceNumB) { + POLYLINEVECTOR& vPieceLoopsVecB = itFacetB->second[nPieceNumB].vPieceLoop ; + PtrOwner pRegB( GetBasicSurfFlatRegion( GetSurfFlatRegionFromPolyLineVector( vPieceLoopsVecB))) ; + if ( pRegB == nullptr) + return false ; + SurfFlatRegion RegionB = *pRegB ; + Plane3d plPlaneB ; + plPlaneB.Set( RegionB.GetPlanePoint(), RegionB.GetNormVersor()) ; + // Intersezione tra i piani delle due facce: se non esiste esse sono complanari. + Point3d ptL ; Vector3d vtL ; + int nResPP = IntersPlanePlane( plPlaneA, plPlaneB, ptL, vtL) ; + if ( /*nResPP == IPPT_NO ||*/ nResPP == IPPT_OVERLAPS) { + SurfFlatRegion frIntersRegion = RegionA ; + frIntersRegion.Intersect( RegionB) ; + double dIntersRegArea ; + frIntersRegion.GetArea( dIntersRegArea) ; + // Assegno indice di parte ai triangoli di A e ai pezzi di B. + if ( dIntersRegArea > EPS_SMALL) { + bool bCodirectedNorm = RegionA.GetNormVersor() * RegionB.GetNormVersor() > 0 ; + int nPartIndex = bCodirectedNorm ? 2 : - 2 ; + INTVECTOR vTA ; + GetAllTriaInFacet( nFA, vTA) ; + for ( int& nTA : vTA) + m_vTria[nTA].nTempPart = nPartIndex ; + itFacetB->second[nPieceNumB].nPiecePart = nPartIndex ; + } + } + } + } + // Faccia B non divisa in pezzi + else { + // Dati della faccia + POLYLINEVECTOR vFacetLoopVecB ; + SurfB.GetFacetLoops( nFB, vFacetLoopVecB) ; + PtrOwner pRegB( GetBasicSurfFlatRegion( GetSurfFlatRegionFromPolyLineVector( vFacetLoopVecB))) ; + if ( pRegB == nullptr) + return false ; + SurfFlatRegion RegionB = *pRegB ; + Plane3d plPlaneB ; + plPlaneB.Set( RegionB.GetPlanePoint(), RegionB.GetNormVersor()) ; + // Intersezione tra i piani delle due facce: se non esiste esse sono complanari. + Point3d ptL ; Vector3d vtL ; + int nResPP = IntersPlanePlane( plPlaneA, plPlaneB, ptL, vtL) ; + if ( /*nResPP == IPPT_NO ||*/ nResPP == IPPT_OVERLAPS) { + SurfFlatRegion frIntersRegion = RegionA ; + frIntersRegion.Intersect( RegionB) ; + double dIntersRegArea ; + frIntersRegion.GetArea( dIntersRegArea) ; + // Assegno indice di parte al pezzo di faccia A e ai triangoli della faccia B. + if ( dIntersRegArea > EPS_SMALL) { + bool bCodirectedNorm = RegionA.GetNormVersor() * RegionB.GetNormVersor() > 0 ; + int nPartIndex = bCodirectedNorm ? 2 : - 2 ; + INTVECTOR vTA ; + GetAllTriaInFacet( nFA, vTA) ; + for ( int& nTA : vTA) + m_vTria[nTA].nTempPart = nPartIndex ; + INTVECTOR vTB ; + SurfB.GetAllTriaInFacet( nFB, vTB) ; + for ( int& nTB : vTB) + SurfB.m_vTria[nTB].nTempPart = nPartIndex ; + } + } + } + } + } + } +#endif + + // Elimino i triangoli delle facce e li sostituisco con i nuovi con i loro indici + RetriangulateFacetPieces( NewFacetA, EdgeInnLineMapA, EdgeEdgeLineMapB) ; + SurfB.RetriangulateFacetPieces( NewFacetB, EdgeInnLineMapB, EdgeEdgeLineMapB) ; + + bool bOk = ( AdjustVertices() && DoCompacting() && SurfB.AdjustVertices() && SurfB.DoCompacting()) ; + +#if UseTria + // Gestione triangoli sovrapposti + if ( bOk) { + int nTriaNum2A = GetTriangleSize() ; + // Resetto e ricalcolo la HashGrid della superficie B + SurfB.ResetHashGrids3d() ; + for ( int nTA = 0 ; nTA < nTriaNum2A ; ++ nTA) { + // Se il triangolo A non è valido, continuo + Triangle3d trTriaA ; + if ( ! GetTriangle( nTA, trTriaA) || ! trTriaA.Validate( true)) + continue ; + // Box del triangolo A + BBox3d b3dTriaA ; + trTriaA.GetLocalBBox( b3dTriaA) ; + // Recupero i triangoli di B che interferiscono col box del triangolo di A + INTVECTOR vNearTria ; + SurfB.GetAllTriaOverlapBox( b3dTriaA, vNearTria) ; + for ( int nTB = 0 ; nTB < int( vNearTria.size()) ; ++ nTB) { + // Se il triangolo B non è valido, continuo + Triangle3d trTriaB ; + if ( ! SurfB.GetTriangle( vNearTria[nTB], trTriaB) || ! trTriaB.Validate( true)) + continue ; + // Se i triangoli sono sovrapposti + TRIA3DVECTOR vTriaAB ; + Point3d ptTempA, ptTempB ; + int nIntTypeAB = IntersTriaTria( trTriaA, trTriaB, ptTempA, ptTempB, vTriaAB) ; + // Verifica della correttezza del'intersezione + bool bSuccesfullInters = true ; + if ( int( vTriaAB.size()) == 1) { + Point3d ptIntTriaCentroid = vTriaAB[0].GetCentroid() ; + bSuccesfullInters = IsPointInsideTriangle( ptIntTriaCentroid, trTriaA, TriangleType::EXACT) && + IsPointInsideTriangle( ptIntTriaCentroid, trTriaB, TriangleType::EXACT) ; + } + // Se l'intersezeione è corretta e i triangoli sono sovrapposti aggiorno gli indici. + if ( nIntTypeAB == ITTT_OVERLAPS && bSuccesfullInters) { + bool bInvertB = trTriaA.GetN() * trTriaB.GetN() < 0. ; + m_vTria[nTA].nTempPart = ( bInvertB ? -2 : 2) ; + SurfB.m_vTria[vNearTria[nTB]].nTempPart = ( bInvertB ? - 2 : 2) ; + } + } + } + return ( AdjustVertices() && DoCompacting() && SurfB.AdjustVertices() && SurfB.DoCompacting()) ; + } +#endif + return bOk ; +} \ No newline at end of file