diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc index 5ff8fcb..c8b0b3f 100644 Binary files a/EgtGeomKernel.rc and b/EgtGeomKernel.rc differ diff --git a/Trimming.cpp b/Trimming.cpp index f8c0f99..77a7e0d 100644 --- a/Trimming.cpp +++ b/Trimming.cpp @@ -16,11 +16,12 @@ #include "stdafx.h" #include "BiArcs.h" #include "GeoConst.h" +#include "CurveLine.h" #include "CurveArc.h" +#include "CurveBezier.h" #include "CurveComposite.h" #include "SurfTriMesh.h" #include "SurfBezier.h" -#include "CurveBezier.h" #include "/EgtDev/Include/EGkTrimming.h" #include "/EgtDev/Include/EGkCurveAux.h" #include "/EgtDev/Include/EGkChainCurves.h" @@ -56,12 +57,15 @@ #define DEBUG_CURVATURE 0 #define DEBUG_SIMPLE_PATCHES 0 #define DEBUG_SURF_PATCHES 0 +#define DEBUG_RAW_EDGES 0 #define DEBUG_EDGES 0 #define DEBUG_SHAPE_STM 0 +#define DEBUG_HOLES 0 #if DEBUG_BASIC_BORDERS || DEBUG_CHAIN_CURVES || DEBUG_ANG_APPROX || DEBUG_BEZIER_INTERP || \ - DEBUG_FACE_SEARCH || DEBUG_FACE_SEARCH_TRIA_MODIF || DEBUG_BRK_POINTS || DEBUG_BRK_THICK || DEBUG_BRK || \ - DEBUG_BORDERS_BY_NORMALS || DEBUG_SYNC_POINTS || DEBUG_BEZIER_RULED || DEBUG_CURVATURE || \ - DEBUG_SIMPLE_PATCHES || DEBUG_SURF_PATCHES || DEBUG_EDGES || DEBUG_SHAPE_STM || DEBUG + DEBUG_FACE_SEARCH || DEBUG_FACE_SEARCH_TRIA_MODIF || DEBUG_BRK_POINTS || DEBUG_BRK_THICK || \ + DEBUG_BRK || DEBUG_BORDERS_BY_NORMALS || DEBUG_SYNC_POINTS || DEBUG_BEZIER_RULED || DEBUG_CURVATURE || \ + DEBUG_SIMPLE_PATCHES || DEBUG_SURF_PATCHES || DEBUG_RAW_EDGES || DEBUG_EDGES || DEBUG_SHAPE_STM || \ + DEBUG_HOLES || DEBUG #include "CurveLine.h" #include "/EgtDev/Include/EGkGeoObjSave.h" #include "/EgtDev/Include/EgtPerfCounter.h" @@ -77,10 +81,11 @@ using namespace std ; -// Vettori e Matrici di curva composite +// Vettori e Matrici di Curve Composite typedef vector COMPOVECTOR ; -typedef vector COMPOMATRIX ; -// Strutta per Patch semplici, Bordi e insieme di Bordi +typedef vector COMPOMATRIX ; + +// Strutta per Patch Semplici, Bordi e Insieme di Bordi struct SimplePatch { Point3d ptStart ; Point3d ptEnd ; @@ -91,37 +96,26 @@ struct SimplePatch { SimplePatch( const Point3d& ptS, const Point3d& ptE, int nB, bool bDelete) : ptStart( ptS), ptEnd( ptE), bErase( bDelete), nBorder( nB) {} ; } ; -typedef vector SimpleBorder ; -typedef vector SimpleBorderVector ; -typedef vector SimpleBorderMatrix ; +typedef vector SimpleBorder ; +typedef vector SimpleBorderVector ; +typedef vector SimpleBorderMatrix ; + // Struttura per superficie con relative Patch +typedef vector BOXMATRIX ; struct SurfPatches { - int nIndSurf ; const ISurf* pSurf ; - vector vPatches ; // non definiscono per forza un bordo, sono solo patch non ordinate - COMPOVECTOR CompoPathces ; + BBox3d BoxSurf ; + SimpleBorderVector vBorderPatches ; + COMPOVECTOR vCompoBorders ; + COMPOMATRIX matCompoPatches ; + BOXMATRIX matBox3dPatches ; + vector> vSetPatchPar ; } ; typedef vector SURFPATCHESVECTOR ; -// Struttura per Calcolo delle Normali su una superficie lungo il suo bordo ( per parallelismo ) -struct BorderInfo { - const ISurf* pSurf ; - const ICurveComposite* pCompo ; - int nInd ; - double dParam ; - Point3d ptCrv ; - Vector3d vtTan ; - Vector3d vtNorm ; - Point3d ptFinal ; - BorderInfo( const ISurf* pS, const ICurveComposite* pC, int nI, double dP) - : pSurf( pS), pCompo( pC), nInd( nI), dParam( dP) {} -} ; -typedef vector VBORDERINFO ; +// Classificazione tipologia di triangoli enum TriaClass { OK = 0, SMALL = 1, CAP = 2, HAT = 3, FLIPPED = 4} ; -//----------------------------------------------------------------------------- -static const string sCircle{ "circle"} ; - //----------------------------------------------------------------------------- //--------------------------- Approssimazione --------------------------------- //----------------------------------------------------------------------------- @@ -292,7 +286,7 @@ GetPointSetByAngTol( const PolyLine& PL, double dAngTol, POLYLINEVECTOR& vPL) // Funzione che approssima la curva di bordo per la costruzione della Bezier Ruled mediante // Patches di curve di Bezier static bool -ApproxBorder( ICurveComposite& CrvCompo, double dLinTol, double dAngTol) +ApproxBorder( CurveComposite& CrvCompo, double dLinTol, double dAngTol) { // Controllo dei parametri if ( ! CrvCompo.IsValid()) @@ -324,6 +318,11 @@ ApproxBorder( ICurveComposite& CrvCompo, double dLinTol, double dAngTol) SaveGeoObj( VT, VC, "C:\\Temp\\RawEdge.nge") ; #endif + // NB. L'approssimazione avviene prima mediante Archi e Rette e successivamente mediante + // Curve di Bezier. Entrambe vengono eseguite con un tolleranza lineare dimezzata in modo + // da rispettare la tolleranza lineare per la curva complessiva. + double dHalfLinTol = max( EPS_SMALL, dLinTol / 2.) ; + // Approssimo le Patch mediante Archi CurveComposite CCApprox ; for ( const PolyLine& PL : vPL) { @@ -331,18 +330,18 @@ ApproxBorder( ICurveComposite& CrvCompo, double dLinTol, double dAngTol) CurveComposite CCPatch ; CCPatch.FromPolyLine( PL) ; // Creo la Patch Approssimata con Archi PolyArc PA ; - CCPatch.ApproxWithArcs( dLinTol, dAngTol, PA) ; + CCPatch.ApproxWithArcs( dHalfLinTol, dAngTol, PA) ; CurveComposite CCPatchApprox ; CCPatchApprox.FromPolyArc( PA) ; - // Rimozione delle Imperfezioni - CCPatchApprox.RemoveSmallDefects( dLinTol, dAngTol) ; - // Merge complessivo - CCPatchApprox.MergeCurves( dLinTol, dAngTol) ; + // Rimozione delle Imperfezioni ( metà della tolleranza lineare) + CCPatchApprox.RemoveSmallDefects( dHalfLinTol / 2., dAngTol) ; + // Merge complessivo ( metà della tolleranza lineare) + CCPatchApprox.MergeCurves( dHalfLinTol / 2., dAngTol) ; #if DEBUG_BEZIER_INTERP VT.emplace_back( CCPatchApprox.Clone()) ; VC.emplace_back( vColor[ ++ nIndCol]) ; #endif // Approssimo tale curva con una Bezier - PtrOwner pCrvPatchBZ( ApproxCurveWithBezier( &CCPatchApprox, dLinTol, 123456)) ; + PtrOwner pCrvPatchBZ( ApproxCurveWithBezier( &CCPatchApprox, dHalfLinTol, 123456)) ; if ( IsNull( pCrvPatchBZ) || ! pCrvPatchBZ->IsValid()) { LOG_ERROR( GetEGkLogger(), "Error : Interpolating points to bezier curve failed") ; return false ; @@ -360,6 +359,7 @@ ApproxBorder( ICurveComposite& CrvCompo, double dLinTol, double dAngTol) VC.emplace_back( RED) ; SaveGeoObj( VT, VC, "C:\\Temp\\RawEdge.nge") ; #endif + if ( CCApprox.IsValid()) CrvCompo.CopyFrom( CCApprox.Clone()) ; @@ -509,98 +509,6 @@ GetNormalAtPoint( const ISurf* pSurf, const Point3d& pt, Vector3d& vtN) return true ; } -// ---------------------------------------------------------------------------- -// Funzione per Splittare una Patch con un'altra -static bool -SplitPatchWithPatch( SurfPatches& SurfPatchA, SurfPatches& SurfPatchB, double dLinTol) -{ - // Definisco la tolleranza di parametro - const double TOL_LINE_PARAM = 10. * EPS_SMALL ; // <-- euristica, modificabile - - // Scorro le Patch della superficie A - for ( int nPatchA = 0 ; nPatchA < int( SurfPatchA.CompoPathces.size()) ; ++ nPatchA) { - // Recupero la PatchA - CurveComposite& PatchA = SurfPatchA.CompoPathces[nPatchA] ; - Point3d& ptStartA = SurfPatchA.vPatches[nPatchA].ptStart ; - Point3d& ptEndA = SurfPatchA.vPatches[nPatchA].ptEnd ; - // Scorro le Patch della supericie B - for ( int nPatchB = 0 ; nPatchB < int( SurfPatchB.CompoPathces.size()) ; ++ nPatchB) { - // Recupero la PatchB - CurveComposite& PatchB = SurfPatchB.CompoPathces[nPatchB] ; - Point3d& ptStartB = SurfPatchB.vPatches[nPatchB].ptStart ; - Point3d& ptEndB = SurfPatchB.vPatches[nPatchB].ptEnd ; - - // Verifico se gli estremi giaciono sulle linee - double dDist = 0. ; - double dPar = 0., dParS = 0., dParE = 0. ; - int nFlag = 0 ; - bool bSplit = false ; - Point3d ptInters ; - - // Estremi B su PatchA ( sono tutti tratti lineari, quindi nel 3d va bene) - DistPointCurve DLL0( ptStartB, PatchA) ; - bSplit = ( DLL0.GetDist( dDist) && dDist < dLinTol && - DLL0.GetParamAtMinDistPoint( 0., dPar, nFlag) && - PatchA.GetDomain( dParS, dParE) && - dParS + TOL_LINE_PARAM < dPar && dPar < dParE - TOL_LINE_PARAM) ; - if ( ! bSplit) { - DistPointCurve DLL1( ptEndB, PatchA) ; - bSplit = ( DLL1.GetDist( dDist) && dDist < dLinTol && - DLL1.GetParamAtMinDistPoint( 0., dPar, nFlag) && - PatchA.GetDomain( dParS, dParE) && - dParS + TOL_LINE_PARAM < dPar && dPar < dParE - TOL_LINE_PARAM) ; - } - // Se Split della PatchA richiesto - if ( bSplit) { - // Split della Patch - PatchA.GetPointD1D2( dPar, ICurve::FROM_MINUS, ptInters) ; - SimplePatch NextPatch( ptInters, ptEndA, 0, false) ; - SurfPatchA.vPatches.insert( SurfPatchA.vPatches.begin() + nPatchA + 1, NextPatch) ; - ptEndA = ptInters ; - // Split della curva composita associata - CurveComposite* pCompoAfter( PatchA.Clone()) ; - PatchA.TrimEndAtParam( dPar) ; - pCompoAfter->TrimStartAtParam( dPar) ; - SurfPatchA.CompoPathces.insert( SurfPatchA.CompoPathces.begin() + nPatchA + 1, *pCompoAfter) ; - // Aggiorno i contatori - -- nPatchA ; - break ; - } - - // Estremi Curr su LineNext ( sono tutti tratti lineari, quindi nel 3d va bene) - DistPointCurve DLL2( ptStartA, PatchB) ; - bSplit = ( DLL2.GetDist( dDist) && dDist < dLinTol && - DLL2.GetParamAtMinDistPoint( 0., dPar, nFlag) && - PatchB.GetDomain( dParS, dParE) && - dParS + TOL_LINE_PARAM < dPar && dPar < dParE - TOL_LINE_PARAM) ; - if ( ! bSplit) { - DistPointCurve DLL3( ptEndA, PatchB) ; - bSplit = ( DLL3.GetDist( dDist) && dDist < dLinTol && - DLL3.GetParamAtMinDistPoint( 0., dPar, nFlag) && - PatchB.GetDomain( dParS, dParE) && - dParS + TOL_LINE_PARAM < dPar && dPar < dParE - TOL_LINE_PARAM) ; - } - // Se Split della PatchB richiesto - if ( bSplit) { - // Split della Patch - PatchB.GetPointD1D2( dPar, ICurve::FROM_MINUS, ptInters) ; - SimplePatch NextPatch( ptInters, ptEndB, 0, false) ; - SurfPatchB.vPatches.insert( SurfPatchB.vPatches.begin() + nPatchB + 1, NextPatch) ; - ptEndB = ptInters ; - // Split della curva composita associata - CurveComposite* pCompoAfter( PatchB.Clone()) ; - PatchB.TrimEndAtParam( dPar) ; - pCompoAfter->TrimStartAtParam( dPar) ; - SurfPatchB.CompoPathces.insert( SurfPatchB.CompoPathces.begin() + nPatchB + 1, *pCompoAfter) ; - // Aggiorno i contatori - -- nPatchB ; - } - } - } - - return true ; -} - // ---------------------------------------------------------------------------- // Funzione per ottenere le Patch dei bordi di una superficie static bool @@ -648,32 +556,59 @@ ManagePatches( const POLYLINEVECTOR& vPLBorders, double dLinTol, double dAngTol, matCompoPatches.back().back().FromPolyLine( PLPatch) ; } } + // Dalle PolyLine ricevute tengo il vettore di Curve Composite. Il punto iniziale coicide con + // Quello della prima Patch trovata + COMPOVECTOR vCompoBorders ; vCompoBorders.reserve( vPLBorders.size()) ; + for ( int i = 0 ; i < ssize( vPLBorders) ; ++ i) { + vCompoBorders.emplace_back( CurveComposite()) ; + vCompoBorders.back().FromPolyLine( vPLBorders[i]) ; + if ( ! vCompoBorders.back().IsValid()) + return false ; + const PolyLine& PLFirstPatch = matPLPatches[i].front() ; + Point3d ptStart ; + if ( ! PLFirstPatch.GetFirstPoint( ptStart)) + return false ; + double dUS = 0. ; + vCompoBorders.back().GetParamAtPoint( ptStart, dUS) ; + vCompoBorders.back().ChangeStartPoint( dUS) ; + } // Ogni curva Patch diventa un insieme di tratti attivi definiti dagli estremi calcolati // NB. In questo modo si salvano solo gli estremi della curva Patch, mentre la sua geometria // è rimasta memorizzata in precedenza [*] // Ogni bordo viene quindi visto come un insieme di Patch semplici ( per adesso tutte attive) - SimpleBorderVector vvSimpleBorder ; vvSimpleBorder.reserve( matPLPatches.size()) ; + // Le Patch più corte della tolleranza vengono considerate invalide + SimpleBorderVector vSimpleBorder ; vSimpleBorder.reserve( matPLPatches.size()) ; + vector> matPatchPar ; matPatchPar.reserve( matPLPatches.size()) ; for ( int i = 0 ; i < int( matPLPatches.size()) ; ++ i) { - vvSimpleBorder.emplace_back( SimpleBorder()) ; - for ( int j = 0 ; j < int( matPLPatches[i].size()) ; ++ j) { + vSimpleBorder.emplace_back( SimpleBorder()) ; + matPatchPar.emplace_back( set()) ; + for ( int j = 0 ; j < ssize( matPLPatches[i]) ; ++ j) { Point3d ptS ; matPLPatches[i][j].GetFirstPoint( ptS) ; Point3d ptE ; matPLPatches[i][j].GetLastPoint( ptE) ; - vvSimpleBorder.back().emplace_back( ptS, ptE, i, false) ; + vSimpleBorder.back().emplace_back( ptS, ptE, i, false) ; + double dPar = -1. ; + if ( j != ssize( matPLPatches[i]) - 1) + vCompoBorders[i].GetParamAtPoint( ptE, dPar, dLinTol) ; + else { + double dParS = 0. ; + vCompoBorders[i].GetDomain( dParS, dPar) ; + } + matPatchPar.back().insert( int( round( dPar))) ; } } #if DEBUG_CHAIN_CURVES VC.clear() ; VT.clear() ; - for ( int i = 0 ; i < int( vvSimpleBorder.size()) ; ++ i) { - for ( int j = 0 ; j < int( vvSimpleBorder[i].size()) ; ++ j) { + for ( int i = 0 ; i < int( vSimpleBorder.size()) ; ++ i) { + for ( int j = 0 ; j < int( vSimpleBorder[i].size()) ; ++ j) { VT.emplace_back( matCompoPatches[i][j].Clone()) ; VC.emplace_back( RED) ; IGeoPoint3d* ptS = CreateGeoPoint3d() ; - ptS->Set( vvSimpleBorder[i][j].ptStart) ; + ptS->Set( vSimpleBorder[i][j].ptStart) ; VT.emplace_back( ptS) ; VC.emplace_back( AQUA) ; IGeoPoint3d* ptE = CreateGeoPoint3d() ; - ptE->Set( vvSimpleBorder[i][j].ptEnd) ; + ptE->Set( vSimpleBorder[i][j].ptEnd) ; VT.emplace_back( ptE) ; VC.emplace_back( AQUA) ; } @@ -686,138 +621,108 @@ ManagePatches( const POLYLINEVECTOR& vPLBorders, double dLinTol, double dAngTol, // una Patch cada ad esempio a metà di un'altra Patch e non nei suoi estremi ) // Soluzione : si spezzano le Patch ulteriormente in modo che ogni estremo di patch sia o nell'intorno // di un altro estremo di patch o isolato ( ad esempio nei bordi più esterni ) - const double TOL_LINE_PARAM = 10. * EPS_SMALL ; // <-- eursitica, modificabile - for ( int nCurrCrv = 0 ; nCurrCrv < int( vvSimpleBorder.size()) - 1 ; ++ nCurrCrv) { - // Recupero la curva corrente - SimpleBorder& CurrCurve = vvSimpleBorder[nCurrCrv] ; - // Scorro i suoi Edges - for ( int nCurrEdge = 0 ; nCurrEdge < int( CurrCurve.size()) ; ++ nCurrEdge) { - // Recupero il tratto di curva corrente - CurveComposite& CurrCompo = matCompoPatches[nCurrCrv][nCurrEdge] ; - // Scorro le curve successive - for ( int nNextCrv = nCurrCrv + 1 ; nNextCrv < int( vvSimpleBorder.size()) ; ++ nNextCrv) { - // Recupero la curva successiva - SimpleBorder& NextCurve = vvSimpleBorder[nNextCrv] ; - // Scorro i suoi Edges - for ( int nNextEdge = 0 ; nNextEdge < int( NextCurve.size()) ; ++ nNextEdge) { - // Se appartiene allo stesso bordo, passo alla seguente - if ( NextCurve[nNextEdge].nBorder == CurrCurve[nCurrEdge].nBorder) - continue ; - // Recupero il tratto di curva corrente - CurveComposite& NextCompo = matCompoPatches[nNextCrv][nNextEdge] ; - // Verifico se gli estremi giaciono sulle linee - double dDist = 0. ; - double dPar = 0., dParS = 0., dParE = 0. ; + BOOLVECTOR vBorderModif( vSimpleBorder.size(), false) ; + for ( int nCurrBorder = 0 ; nCurrBorder < ssize( vSimpleBorder) ; ++ nCurrBorder) { + // Recupero la Composita associata al Bordo Corrente + CurveComposite& CurrCompoBorder = vCompoBorders[nCurrBorder] ; + // Recupero le Patch associate + SimpleBorder& vPatchCurrBorder = vSimpleBorder[nCurrBorder] ; + // Recupero il vettore dei Parametri di Split + set& setSplitPar = matPatchPar[nCurrBorder] ; + #if DEBUG_CHAIN_CURVES + VC.clear() ; VT.clear() ; + VT.emplace_back( CurrCompoBorder.Clone()) ; + VC.emplace_back( RED) ; + for ( auto Iter = setSplitPar.begin() ; Iter != setSplitPar.end() ; ++ Iter) { + Point3d ptCurr ; + CurrCompoBorder.GetPointD1D2( *Iter, ICurve::FROM_MINUS, ptCurr) ; + PtrOwner ptGeoCurr( CreateGeoPoint3d()) ; ptGeoCurr->Set( ptCurr) ; + VT.emplace_back( ptGeoCurr->Clone()) ; + VC.emplace_back( ORANGE) ; + } + #endif + + // Scorro gli altri Bordi + for ( int nOtherBorder = 0 ; nOtherBorder < ssize( vSimpleBorder) ; ++ nOtherBorder) { + if ( nOtherBorder == nCurrBorder) + continue ; + #if DEBUG_CHAIN_CURVES + CurveComposite& OtherCompoBorder = vCompoBorders[nOtherBorder] ; + VT.emplace_back( OtherCompoBorder.Clone()) ; + VC.emplace_back( BLACK) ; + #endif + // Recupero l'altro bordo + SimpleBorder& OtherBorder = vSimpleBorder[nOtherBorder] ; + // Scorro le sue Patch + for ( int nOtherPatch = 0 ; nOtherPatch < ssize( OtherBorder) ; ++ nOtherPatch) { + // Recupero gli estremi della Path attuale + DistPointCurve DPTCRV( OtherBorder[nOtherPatch].ptStart, CurrCompoBorder) ; + double dDist = INFINITO ; + if ( DPTCRV.GetDist( dDist) && dDist < dLinTol) { + Point3d ptMinDist ; int nFlag = 0 ; - bool bSplit = false ; - Point3d ptInters ; - - // Estremi Next su LineCurr ( sono tutti tratti lineari, quindi nel 3d va bene) - DistPointCurve DLL0( NextCurve[nNextEdge].ptStart, CurrCompo) ; - bSplit = ( DLL0.GetDist( dDist) && dDist < dLinTol && - DLL0.GetParamAtMinDistPoint( 0., dPar, nFlag) && - CurrCompo.GetDomain( dParS, dParE) && - dParS + TOL_LINE_PARAM < dPar && dPar < dParE - TOL_LINE_PARAM) ; - if ( ! bSplit) { - DistPointCurve DLL1( NextCurve[nNextEdge].ptEnd, CurrCompo) ; - bSplit = ( DLL1.GetDist( dDist) && dDist < dLinTol && - DLL1.GetParamAtMinDistPoint( 0., dPar, nFlag) && - CurrCompo.GetDomain( dParS, dParE) && - dParS + TOL_LINE_PARAM < dPar && dPar < dParE - TOL_LINE_PARAM) ; - } - // Split dell'Edge se richiesto - if ( bSplit) { - #if DEBUG_CHAIN_CURVES - VT.clear() ; VC.clear() ; - VT.emplace_back( NextCompo.Clone()) ; - VC.emplace_back( ORANGE) ; - VT.emplace_back( CurrCompo.Clone()) ; - VC.emplace_back( LIME) ; - SaveGeoObj( VT, VC, "C:\\Temp\\LineIntersection.nge") ; - #endif - // Aggiorno gli Edges - CurrCompo.GetPointD1D2( dPar, ICurve::FROM_MINUS, ptInters) ; - SimplePatch NextEdge( ptInters, CurrCurve[nCurrEdge].ptEnd, - CurrCurve[nCurrEdge].nBorder, false) ; - CurrCurve.insert( CurrCurve.begin() + nCurrEdge + 1, NextEdge) ; - CurrCurve[nCurrEdge].ptEnd = ptInters ; - // Aggiorno le Curve - CurveComposite* pCompoAfter( CurrCompo.Clone()) ; - CurrCompo.TrimEndAtParam( dPar) ; - pCompoAfter->TrimStartAtParam( dPar) ; - matCompoPatches[nCurrCrv].insert( matCompoPatches[nCurrCrv].begin() + nCurrEdge + 1, *pCompoAfter) ; - // Aggiorno i contatori - -- nCurrEdge ; - nNextCrv = int( vvSimpleBorder.size()) ; - break ; - } - - // Estremi Curr su LineNext ( sono tutti tratti lineari, quindi nel 3d va bene) - DistPointCurve DLL2( CurrCurve[nCurrEdge].ptStart, NextCompo) ; - bSplit = ( DLL2.GetDist( dDist) && dDist < dLinTol && - DLL2.GetParamAtMinDistPoint( 0., dPar, nFlag) && - NextCompo.GetDomain( dParS, dParE) && - dParS + TOL_LINE_PARAM < dPar && dPar < dParE - TOL_LINE_PARAM) ; - if ( ! bSplit) { - DistPointCurve DLL3( CurrCurve[nCurrEdge].ptEnd, NextCompo) ; - bSplit = ( DLL3.GetDist( dDist) && dDist < dLinTol && - DLL3.GetParamAtMinDistPoint( 0., dPar, nFlag) && - NextCompo.GetDomain( dParS, dParE) && - dParS + TOL_LINE_PARAM < dPar && dPar < dParE - TOL_LINE_PARAM) ; - } - // Split dell'Edge se richiesto - if ( bSplit) { - #if DEBUG_CHAIN_CURVES - VT.clear() ; VC.clear() ; - VT.emplace_back( NextCompo.Clone()) ; - VC.emplace_back( ORANGE) ; - VT.emplace_back( CurrCompo.Clone()) ; - VC.emplace_back( LIME) ; - SaveGeoObj( VT, VC, "C:\\Temp\\LineIntersection.nge") ; - #endif - // Aggiorno gli Edges - NextCompo.GetPointD1D2( dPar, ICurve::FROM_MINUS, ptInters) ; - SimplePatch NextEdge( ptInters, NextCurve[nNextEdge].ptEnd, - NextCurve[nNextEdge].nBorder, false) ; - NextCurve.insert( NextCurve.begin() + nNextEdge + 1, NextEdge) ; - NextCurve[nNextEdge].ptEnd = ptInters ; - // Aggiorno le curve - CurveComposite* pCompoAfter( NextCompo.Clone()) ; - NextCompo.TrimEndAtParam( dPar) ; - pCompoAfter->TrimStartAtParam( dPar) ; - matCompoPatches[nNextCrv].insert( matCompoPatches[nNextCrv].begin() + nNextEdge + 1, *pCompoAfter) ; - // Aggiorno i contatori - -- nNextEdge ; + if ( DPTCRV.GetMinDistPoint( 0., ptMinDist, nFlag)) { + bool bInsert = true ; + for ( int nCurrPatch = 0 ; bInsert && nCurrPatch < ssize( vPatchCurrBorder) ; ++ nCurrPatch) { + const SimplePatch& Patch = vPatchCurrBorder[nCurrPatch] ; + bInsert = ( ! AreSamePointEpsilon( Patch.ptStart, ptMinDist, dLinTol) && + ! AreSamePointEpsilon( Patch.ptEnd, ptMinDist, dLinTol)) ; + } + if ( bInsert) { + double dPar = -1. ; + if ( DPTCRV.GetParamAtMinDistPoint( 0., dPar, nFlag)) { + setSplitPar.insert( dPar) ; + vBorderModif[nCurrBorder] = true ; + #if DEBUG_CHAIN_CURVES + PtrOwner ptGeoCurr( CreateGeoPoint3d()) ; + ptGeoCurr->Set( ptMinDist) ; + VT.emplace_back( ptGeoCurr->Clone()) ; + VC.emplace_back( AQUA) ; + #endif + } + } } } } } + #if DEBUG_CHAIN_CURVES + SaveGeoObj( VT, VC, "C:\\Temp\\SplitPathces.nge") ; + #endif } - #if DEBUG_CHAIN_CURVES - VC.clear() ; VT.clear() ; - for ( int i = 0 ; i < int( vvSimpleBorder.size()) ; ++ i) { - for ( int j = 0 ; j < int( vvSimpleBorder[i].size()) ; ++ j) { - VT.emplace_back( matCompoPatches[i][j].Clone()) ; - VC.emplace_back( RED) ; - IGeoPoint3d* pt = CreateGeoPoint3d() ; - pt->Set( vvSimpleBorder[i][j].ptStart) ; - VT.emplace_back( pt) ; - VC.emplace_back( AQUA) ; - pt = CreateGeoPoint3d() ; - pt->Set( vvSimpleBorder[i][j].ptEnd) ; - VT.emplace_back( pt) ; - VC.emplace_back( AQUA) ; + for ( int nCurrBorder = 0 ; nCurrBorder < ssize( vSimpleBorder) ; ++ nCurrBorder) { + // Se il bordo corrente non ha subito Split, passo al successivo + if ( ! vBorderModif[nCurrBorder]) + continue ; + // Pulisco le Composite associate associate a tale Bordo + COMPOVECTOR& vCompoPatches = matCompoPatches[nCurrBorder] ; + vCompoPatches.clear() ; + // Recupero la Curva Composita corrente + CurveComposite& CurrCompo = vCompoBorders[nCurrBorder] ; + // Inizializzo il nuovo Bordo semplice formato dalle Patch + SimpleBorder newSimpleBorder ; + // Recupero il vettore dei Parametri di Split + set& setSplitPar = matPatchPar[nCurrBorder] ; + double dLastPar = 0 ; + for ( auto Iter = setSplitPar.begin() ; Iter != setSplitPar.end() ; ++ Iter) { + PtrOwner pCrvPatch( CurrCompo.CopyParamRange( dLastPar, *Iter)) ; + if ( ! IsNull( pCrvPatch) && pCrvPatch->IsValid()) { // ad esempio per punti coincidenti + vCompoPatches.emplace_back( *ConvertCurveToBasicComposite( Release( pCrvPatch))) ; + Point3d ptStart ; vCompoPatches.back().GetStartPoint( ptStart) ; + Point3d ptEnd ; vCompoPatches.back().GetEndPoint( ptEnd) ; + newSimpleBorder.emplace_back( ptStart, ptEnd, nCurrBorder, false) ; + dLastPar = *Iter ; } } - SaveGeoObj( VT, VC, "C:\\Temp\\BordersWithOverlaps.nge") ; - #endif + vSimpleBorder[nCurrBorder] = newSimpleBorder ; + } + // Si eliminano ora tutte le Patch che si sovrappongono, in modo da ottenere solo un // le Patch che rappresentano il bordo esterno const double MAXPOINT = 10 ; - for ( int nCurrCrv = 0 ; nCurrCrv < int( vvSimpleBorder.size()) - 1 ; ++ nCurrCrv) { + for ( int nCurrCrv = 0 ; nCurrCrv < int( vSimpleBorder.size()) - 1 ; ++ nCurrCrv) { // Recupero la curva corrente - SimpleBorder& CurrCurve = vvSimpleBorder[nCurrCrv] ; + SimpleBorder& CurrCurve = vSimpleBorder[nCurrCrv] ; // Scorro i suoi Edges for ( int nCurrEdge = 0 ; nCurrEdge < int( CurrCurve.size()) ; ++ nCurrEdge) { // Se Edge cancellato, passo al successivo @@ -827,9 +732,9 @@ ManagePatches( const POLYLINEVECTOR& vPLBorders, double dLinTol, double dAngTol, Point3d& ptCurrStart = CurrCurve[nCurrEdge].ptStart ; Point3d& ptCurrEnd = CurrCurve[nCurrEdge].ptEnd ; // Scorro le curve successive - for ( int nNextCrv = nCurrCrv + 1 ; nNextCrv < int( vvSimpleBorder.size()) ; ++ nNextCrv) { + for ( int nNextCrv = nCurrCrv + 1 ; nNextCrv < int( vSimpleBorder.size()) ; ++ nNextCrv) { // Recupero la curva successiva - SimpleBorder& NextCurve = vvSimpleBorder[nNextCrv] ; + SimpleBorder& NextCurve = vSimpleBorder[nNextCrv] ; // Scorro i suoi Edges for ( int nNextEdge = 0 ; nNextEdge < int( NextCurve.size()) ; ++ nNextEdge) { // Se Edge cancellato, passo al successivo @@ -876,7 +781,7 @@ ManagePatches( const POLYLINEVECTOR& vPLBorders, double dLinTol, double dAngTol, } // Dalle PolyLine recupero delle curve composite ( quindi anch'esse come insieme di tratti linari) - ICRVCOMPOPOVECTOR vCompoPatches ; vCompoPatches.reserve( vvSimpleBorder.size()) ; + ICRVCOMPOPOVECTOR vCompoPatches ; vCompoPatches.reserve( vSimpleBorder.size()) ; for ( const PolyLine& PL : vPLBorders) { if ( ! vCompoPatches.emplace_back( CreateCurveComposite()) || ! vCompoPatches.back()->FromPolyLine( PL)) @@ -885,9 +790,9 @@ ManagePatches( const POLYLINEVECTOR& vPLBorders, double dLinTol, double dAngTol, } // Recupero solo i sottotratti di curva validi ( quindi che non fanno overlap tra loro) - for ( int nCrv = 0 ; nCrv < int( vvSimpleBorder.size()) ; ++ nCrv) { + for ( int nCrv = 0 ; nCrv < int( vSimpleBorder.size()) ; ++ nCrv) { // Recupero la curva - SimpleBorder& CrvEdge = vvSimpleBorder[nCrv] ; + SimpleBorder& CrvEdge = vSimpleBorder[nCrv] ; // Scorro i suoi edges for ( int nEdge = 0 ; nEdge < int( CrvEdge.size()) ; ++ nEdge) { // Se edge non attivo, passo al successivo @@ -1007,6 +912,14 @@ ChainCompoPatches( ICRVCOMPOPOVECTOR& vCompoPatches, double dChainTol, // Trasferisco le TempProps alle sottocurve for ( int nU = 0 ; nU < pCrv->GetCurveCount() ; ++ nU) pCrv->SetCurveTempProp( nU, pCrv->GetTempProp( 0), 0) ; + // Se estremi più distanti della tolleranza, li cambio nel punto medio tra essi + Point3d ptEndCurr ; vCompoChained.back()->GetEndPoint( ptEndCurr) ; + Point3d ptStartNext ; pCrv->GetStartPoint( ptStartNext) ; + if ( SqDist( ptEndCurr, ptStartNext) > dChainTol * dChainTol) { + Point3d ptMid = Media( ptEndCurr, ptStartNext) ; + vCompoChained.back()->ModifyEnd( ptMid) ; + pCrv->ModifyStart( ptMid) ; + } // Concateno if ( ! vCompoChained.back()->AddCurve( pCrv->Clone(), true, dChainTol)) return false ; @@ -1072,7 +985,7 @@ GetRawEdges( const POLYLINEVECTOR& vPLBorders, double dLinTol, double dAngTol, Point3d ptS ; vCompoChained[i]->GetStartPoint( ptS) ; Point3d ptE ; vCompoChained[i]->GetEndPoint( ptE) ; if ( AreSamePointEpsilon( ptS, ptE, dLinTol)) { - vCompoChained[i]->Close() ; + vCompoChained[i]->Close() ; // utilizza il punto medio // Riporto la Temp Prop int nTmpProp0 = vCompoChained[i]->GetFirstCurve()->GetTempProp( 0) ; vCompoChained[i]->SetCurveTempProp( vCompoChained[i]->GetCurveCount() - 1, nTmpProp0, 0) ; @@ -1670,6 +1583,97 @@ GetBorderByExtrusion( const SurfTriMesh* pStm, double dThick, double dLinTol, do // ---------------------------------- Analisi Adiacenze ----------------------- // ---------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- +// Funzione per calcolare le Patch di una Superficie TriMesh +static bool +CalcSurfPatch( const ISurf* pSurf, double dLinTol, double dAngTol, SurfPatches& SrfPatches) +{ + // Verifico che la Superficie sia valida + if ( pSurf == nullptr || ! pSurf->IsValid()) + return false ; + + // Recupero il Box della superficie ( ingrandito della tolleranza lineare) + if ( ! pSurf->GetLocalBBox( SrfPatches.BoxSurf)) + return false ; + SrfPatches.BoxSurf.Expand( 2. * dLinTol + 10. * EPS_SMALL) ; + + // Recupero i suoi Loops come PolyLines + POLYLINEVECTOR vPLBorders ; + if ( ! InsertLoopsOfSurf( pSurf, vPLBorders)) + return false ; + + // Dai Bordi, recupero le Patches + POLYLINEMATRIX matPLPatchBorders ; + if ( ! CalcPatches( vPLBorders, dAngTol, matPLPatchBorders)) + return false ; + + #if DEBUG_SURF_PATCHES + VT.clear() ; VC.clear() ; + VT.emplace_back( pSurf->Clone()) ; + VC.emplace_back( BLACK) ; + for ( int i = 0 ; i < ssize( matPLPatchBorders) ; ++ i) { + for ( int j = 0 ; j < ssize( matPLPatchBorders[i]) ; ++ j) { + CurveComposite CompoPatch ; CompoPatch.FromPolyLine( matPLPatchBorders[i][j]) ; + VT.emplace_back( CompoPatch.Clone()) ; + VC.emplace_back( Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, 1.)) ; + } + } + //SaveGeoObj( VT, VC, "C:\\Temp\\Patches.nge") ; + #endif + + // Definisco le Patches + // Recupero la Curva Composita associata per la Patch + // Memerizzo il Box3d della Patch + // Memorizzo i Parametri delle Patch sulle Curve Composite + SrfPatches.vCompoBorders.reserve( vPLBorders.size()) ; + SrfPatches.matCompoPatches.reserve( vPLBorders.size()) ; + SrfPatches.vBorderPatches.reserve( matPLPatchBorders.size()) ; + SrfPatches.matBox3dPatches.reserve( matPLPatchBorders.size()) ; + SrfPatches.vSetPatchPar.reserve( matPLPatchBorders.size()) ; + for ( int i = 0 ; i < ssize( matPLPatchBorders) ; ++ i) { + // Recupero il Bordo Corrente + const POLYLINEVECTOR& PLBorder = matPLPatchBorders[i] ; + // Recupero la Curva Composita di Bordo + SrfPatches.vCompoBorders.emplace_back( CurveComposite()) ; + SrfPatches.vCompoBorders.back().FromPolyLine( vPLBorders[i]) ; + // Inizializzo i Parametri + SrfPatches.vBorderPatches.emplace_back( SimpleBorder()) ; + SrfPatches.matBox3dPatches.emplace_back( BOXVECTOR{}) ; + SrfPatches.vSetPatchPar.emplace_back( set()) ; + SrfPatches.matCompoPatches.emplace_back( COMPOVECTOR{}) ; + for ( int j = 0 ; j < ssize( PLBorder) ; ++ j) { + // Recupero la PolyLine associata alla Patch corrente + const PolyLine& PLPatch = PLBorder[j] ; + // Definizione della Patch Semplice + Point3d ptStart ; PLPatch.GetFirstPoint( ptStart) ; + if ( j == 0) { + double dUStart = 0. ; + SrfPatches.vCompoBorders.back().GetParamAtPoint( ptStart, dUStart) ; + SrfPatches.vCompoBorders.back().ChangeStartPoint( dUStart) ; + } + Point3d ptEnd ; PLPatch.GetLastPoint( ptEnd) ; + SrfPatches.vBorderPatches.back().emplace_back( ptStart, ptEnd, i, false) ; + SrfPatches.matCompoPatches.back().emplace_back( CurveComposite()) ; + SrfPatches.matCompoPatches.back().back().FromPolyLine( PLPatch) ; + // Box Della Patch + SrfPatches.matBox3dPatches.back().emplace_back( BBox3d()) ; + PLPatch.GetLocalBBox( SrfPatches.matBox3dPatches.back().back()) ; + SrfPatches.matBox3dPatches.back().back().Expand( 2. * dLinTol + 10. * EPS_SMALL) ; + // Parametri dU associati + double dPar = -1. ; + if ( j != ssize( matPLPatchBorders[i]) - 1) + SrfPatches.vCompoBorders.back().GetParamAtPoint( ptEnd, dPar, dLinTol) ; + else { + double dParS = 0. ; + SrfPatches.vCompoBorders.back().GetDomain( dParS, dPar) ; + } + SrfPatches.vSetPatchPar.back().insert( int( round( dPar))) ; + } + } + + return true ; +} + // ---------------------------------------------------------------------------- // Funzione per individuare se un triangolo piccolo è trascurabile static bool @@ -1681,7 +1685,7 @@ CheckUnrelevantTriangle( const SurfTriMesh& Stm, int nCurrTria, int nTriaAdj, in if ( ! Stm.IsValid()) return false ; - // Verifico che il triangoli appartengano alla TriMesh + // Verifico che il triangolo appartenga alla TriMesh Triangle3d Tria, TriaAdj ; if ( ! Stm.GetTriangle( nCurrTria, Tria) || ! Stm.GetTriangle( nTriaAdj, TriaAdj)) return false ; @@ -1742,7 +1746,7 @@ AnalyzeTriangle( const Triangle3d& Tria, const Triangle3d& TriaAdj, double dAngT // Verifico caso Small double dArea = TriaAdj.GetArea() ; - if ( dArea < ( 70 * EPS_SMALL) * ( 70. * EPS_SMALL)) { // ~ 0.005 + if ( dArea < ( 70. * EPS_SMALL) * ( 70. * EPS_SMALL)) { // ~ 0.005 nTriaClass = TriaClass::SMALL ; return true ; } @@ -2530,8 +2534,10 @@ CheckCurvesInBox( const SurfTriMesh& Stm, const COMPOVECTOR& vCompoChain, const ! CompoBTmp.GetParamAtLength( dLenMinB, dUBS) || ! CompoBTmp.GetParamAtLength( dLenMaxB, dUBE)) return false ; - CompoA.CopyFrom( ConvertCurveToBasicComposite( CompoATmp.CopyParamRange( dUAS, dUAE))) ; - CompoB.CopyFrom( ConvertCurveToBasicComposite( CompoBTmp.CopyParamRange( dUBS, dUBE))) ; + PtrOwner pCrvATmp( CompoATmp.CopyParamRange( dUAS, dUAE)) ; + PtrOwner pCrvBTmp( CompoBTmp.CopyParamRange( dUBS, dUBE)) ; + CompoA.CopyFrom( pCrvATmp) ; + CompoB.CopyFrom( pCrvBTmp) ; #if DEBUG_FACE_SEARCH VT.emplace_back( CompoA.Clone()) ; @@ -2619,11 +2625,14 @@ UpdateBorderByTriaAdj( CurveComposite& Compo, double dLinTol, const COMPOVECTOR& return false ; CurveComposite CompoPrev ; if ( Compo.IsPointOn( ptS) && ! Compo.IsPointOn( ptE)) { - CompoPrev.CopyFrom( ConvertCurveToBasicComposite( CompoChain.CopyParamRange( dUBreak, dUE))) ; + PtrOwner pCrv( CompoChain.CopyParamRange( dUBreak, dUE)) ; + CompoPrev.CopyFrom( pCrv) ; CompoPrev.Invert() ; } - else if ( Compo.IsPointOn( ptE) && ! Compo.IsPointOn( ptS)) - CompoPrev.CopyFrom( ConvertCurveToBasicComposite( CompoChain.CopyParamRange( dUS, dUBreak))) ; + else if ( Compo.IsPointOn( ptE) && ! Compo.IsPointOn( ptS)) { + PtrOwner pCrv( CompoChain.CopyParamRange( dUS, dUBreak)) ; + CompoPrev.CopyFrom( pCrv) ; + } #if DEBUG_FACE_SEARCH VT.emplace_back( CompoPrev.Clone()) ; VC.emplace_back( LIME) ; @@ -2636,10 +2645,13 @@ UpdateBorderByTriaAdj( CurveComposite& Compo, double dLinTol, const COMPOVECTOR& if ( ! CompoChain.GetParamAtPoint( ptEnd, dUBreak, dLinTol)) return false ; CurveComposite CompoAft ; - if ( Compo.IsPointOn( ptS) && ! Compo.IsPointOn( ptE)) - CompoAft.CopyFrom( ConvertCurveToBasicComposite( CompoChain.CopyParamRange( dUBreak, dUE))) ; + if ( Compo.IsPointOn( ptS) && ! Compo.IsPointOn( ptE)) { + PtrOwner pCrv( CompoChain.CopyParamRange( dUBreak, dUE)) ; + CompoAft.CopyFrom( pCrv) ; + } else if ( Compo.IsPointOn( ptE) && ! Compo.IsPointOn( ptS)) { - CompoAft.CopyFrom( ConvertCurveToBasicComposite( CompoChain.CopyParamRange( dUS, dUBreak))) ; + PtrOwner pCrv( CompoChain.CopyParamRange( dUS, dUBreak)) ; + CompoAft.CopyFrom( pCrv) ; CompoAft.Invert() ; } #if DEBUG_FACE_SEARCH @@ -2658,13 +2670,17 @@ UpdateBorderByTriaAdj( CurveComposite& Compo, double dLinTol, const COMPOVECTOR& CurveComposite CompoPrev ; CurveComposite CompoAft ; if ( dUBreak < dUBreak1) { - CompoPrev.CopyFrom( ConvertCurveToBasicComposite( CompoChain.CopyParamRange( dUS, dUBreak))) ; - CompoAft.CopyFrom( ConvertCurveToBasicComposite( CompoChain.CopyParamRange( dUBreak1, dUE))) ; + PtrOwner pCrvPrev( CompoChain.CopyParamRange( dUS, dUBreak)) ; + PtrOwner pCrvAft( CompoChain.CopyParamRange( dUBreak1, dUE)) ; + CompoPrev.CopyFrom( pCrvPrev) ; + CompoAft.CopyFrom( pCrvAft) ; } else { - CompoPrev.CopyFrom( ConvertCurveToBasicComposite( CompoChain.CopyParamRange( dUBreak, dUE))) ; + PtrOwner pCrvPrev( CompoChain.CopyParamRange( dUBreak, dUE)) ; + CompoPrev.CopyFrom( pCrvPrev) ; CompoPrev.Invert() ; - CompoAft.CopyFrom( ConvertCurveToBasicComposite( CompoChain.CopyParamRange( dUS, dUBreak1))) ; + PtrOwner pCrvAft( CompoChain.CopyParamRange( dUS, dUBreak1)) ; + CompoAft.CopyFrom( pCrvAft) ; CompoAft.Invert() ; } #if DEBUG_FACE_SEARCH @@ -2679,7 +2695,8 @@ UpdateBorderByTriaAdj( CurveComposite& Compo, double dLinTol, const COMPOVECTOR& else if ( Compo.IsPointOn( ptS) && Compo.IsPointOn( ptE)) { CurveComposite CompoSingle ; if ( dUBreak < dUBreak1) { - CompoSingle.CopyFrom( ConvertCurveToBasicComposite( CompoChain.CopyParamRange( dUBreak, dUBreak1))) ; + PtrOwner pCrv( CompoChain.CopyParamRange( dUBreak, dUBreak1)) ; + CompoSingle.CopyFrom( pCrv) ; CompoSingle.Invert() ; #if DEBUG_FACE_SEARCH VT.emplace_back( CompoSingle.Clone()) ; @@ -2691,7 +2708,8 @@ UpdateBorderByTriaAdj( CurveComposite& Compo, double dLinTol, const COMPOVECTOR& } } else { - CompoSingle.CopyFrom( ConvertCurveToBasicComposite( CompoChain.CopyParamRange( dUBreak1, dUBreak))) ; + PtrOwner pCrv( CompoChain.CopyParamRange( dUBreak1, dUBreak)) ; + CompoSingle.CopyFrom( pCrv) ; #if DEBUG_FACE_SEARCH VT.emplace_back( CompoSingle.Clone()) ; VC.emplace_back( LIME) ; @@ -2707,7 +2725,7 @@ UpdateBorderByTriaAdj( CurveComposite& Compo, double dLinTol, const COMPOVECTOR& } #if DEBUG_FACE_SEARCH - //SaveGeoObj( VT, VC, "C:\\Temp\\6.nge") ; + //SaveGeoObj( VT, VC, "C:\\Temp\\6.nge") ; #endif bUpdate = ( bUpdateStart || bUpdateEnd) ; return true ; @@ -2768,8 +2786,9 @@ CheckBordersInBox( CurveComposite& CompoA, CurveComposite& CompoB, ! CompoX.GetParamAtLength( dSize + dSizeTol + 2. * EPS_SMALL, dUEndB)) return false ; // Per sicurezza [ migliorabile se stabile] - if ( ! myCompoA.CopyFrom( CompoX.CopyParamRange( dUStartA, dUE)) || - ! myCompoB.CopyFrom( CompoX.CopyParamRange( dUS, dUEndB))) + PtrOwner pCrvA( CompoX.CopyParamRange( dUStartA, dUE)) ; + PtrOwner pCrvB( CompoX.CopyParamRange( dUS, dUEndB)) ; + if ( ! myCompoA.CopyFrom( pCrvA) || ! myCompoB.CopyFrom( pCrvB)) return false ; dLenStartA = 0. ; dLenStartB = 0. ; @@ -3221,13 +3240,20 @@ MarchAlongPath( const BBox3d& BBoxCurr, const SurfTriMesh& Stm, } // ---------------------------------------------------------------------------- -// Funzione per definire se il bordo di una TriMesh è una circonferenza +// Funzione per definire se un bordo è una circonferenza +// ( Restituisce true nel caso lo sia e la circonferenza perfetta come ultimo parametro) static bool -IsBorderACircle( const PolyLine& PL, double dShapeLinTol, Point3d& ptC, Vector3d& vtN, double& dRad) +IsBorderACircle( const PolyLine& PL, double dLinTol, double dAngTol, Frame3d& frCircle, double& dRad, + CurveArc& CrvCircle) { // Se PolyLine aperta o non piana, non è un cerchio Plane3d PlanePL ; - if ( ! PL.IsClosed() || ! PL.IsFlat( PlanePL, dShapeLinTol)) + if ( ! PL.IsClosed() || ! PL.IsFlat( PlanePL, dLinTol)) + return false ; + + // Verifico che tutti i punti rispettino la tolleranza angolare + POLYLINEVECTOR vPL ; + if ( ! GetPointSetByAngTol( PL, dAngTol, vPL) || ssize( vPL) != 1) return false ; // Creo un sistema di riferimento centrato nella PolyLine @@ -3242,6 +3268,7 @@ IsBorderACircle( const PolyLine& PL, double dShapeLinTol, Point3d& ptC, Vector3d PolyLine PLLoc = PL ; PLLoc.ToLoc( frCurr) ; // Per ogni tratto salvo i suoi estremi e il punto medio in successione ( senza ripetizioni) + // ( I punti vengono proeittati nel piano per una maggiore precisione) PNTVECTOR vPts ; Point3d ptNext ; PLLoc.GetFirstPoint( ptNext) ; @@ -3250,6 +3277,27 @@ IsBorderACircle( const PolyLine& PL, double dShapeLinTol, Point3d& ptC, Vector3d vPts.push_back( Media( vPts.back(), ptNext)) ; vPts.push_back( ptNext) ; } + for ( POINTU& ptU : PLLoc.GetUPointList()) + ptU.first.z = 0. ; + + #if DEBUG_HOLES + vector VTCircle ; + vector VCCirle ; + CurveComposite CompoPL ; CompoPL.FromPolyLine( PLLoc) ; + VTCircle.emplace_back( CompoPL.Clone()) ; + VCCirle.emplace_back( RED) ; + IGeoPoint3d* ptCenter = CreateGeoPoint3d() ; ptCenter->Set( ptCentroid) ; + ptCenter->ToLoc( frCurr) ; + VTCircle.emplace_back( ptCenter) ; + VCCirle.emplace_back( BLUE) ; + for ( int i = 0 ; i < ssize( vPts) ; ++ i) { + IGeoPoint3d* ptOnCirle = CreateGeoPoint3d() ; ptOnCirle->Set( vPts[i]) ; + VTCircle.emplace_back( ptOnCirle) ; + VCCirle.emplace_back( GREEN) ; + } + SaveGeoObj( VTCircle, VCCirle, "C:\\Temp\\CircleDebug.nge") ; + Point3d ptIMin, ptEMin, ptMaxDist ; + #endif // Per ogni coppia di punti calcolo la Distanza Massima e Minima dal centro del cerchio locale ( ORIG) double dSqMaxDist = 0. ; @@ -3257,221 +3305,180 @@ IsBorderACircle( const PolyLine& PL, double dShapeLinTol, Point3d& ptC, Vector3d for ( int i = 0 ; i < int( floor( 0.5 * int( vPts.size()))) ; i = i + 2) { double dSqLineDist = INFINITO ; DistPointLine( ORIG, vPts[i], vPts[i + 1]).GetSqDist( dSqLineDist) ; - if ( dSqLineDist < dSqMinDist) + if ( dSqLineDist < dSqMinDist) { dSqMinDist = dSqLineDist ; + #if DEBUG_HOLES + ptIMin = vPts[i] ; ptEMin = vPts[i + 1] ; + #endif + } double dSqPtDist = SqDist( ORIG, vPts[i]) ; - if ( dSqPtDist > dSqMaxDist) + if ( dSqPtDist > dSqMaxDist) { dSqMaxDist = dSqPtDist ; + #if DEBUG_HOLES + ptMaxDist = vPts[i] ; + #endif + } } + #if DEBUG_HOLES + CurveLine LineMinDist ; LineMinDist.Set( ptIMin, ptEMin) ; + VTCircle.emplace_back( LineMinDist.Clone()) ; + VCCirle.emplace_back( YELLOW) ; + IGeoPoint3d* myPtMaxDist = CreateGeoPoint3d() ; myPtMaxDist->Set( ptMaxDist) ; + VTCircle.emplace_back( myPtMaxDist) ; + VCCirle.emplace_back( YELLOW) ; + SaveGeoObj( VTCircle, VCCirle, "C:\\Temp\\CircleDebug.nge") ; + #endif // Se distanza minima e massima entro tolleranza, allora è una circonferenza - if ( abs( dSqMaxDist - dSqMinDist) < dShapeLinTol * dShapeLinTol) { - ptC = ptCentroid ; - vtN = PlanePL.GetVersN() ; - dRad = 0.5 * ( sqrt( dSqMaxDist) + sqrt( dSqMinDist)) ; - return true ; + double dMinDist = sqrt( dSqMinDist) ; + double dMaxDist = sqrt( dSqMaxDist) ; + if ( abs( dMaxDist - dMinDist) < dLinTol) { + frCircle.Set( ptCentroid, PlanePL.GetVersN()) ; + dRad = ( dMinDist + dMaxDist) / 2. ; + return ( CrvCircle.Set( frCircle.Orig(), frCircle.VersZ(), dRad)) ; } return false ; } // ---------------------------------------------------------------------------- -// Funzione per estrarre Geometrie note da una sola TriMesh +// Funzione per definire se il bordo di una TriMesh è un'asola static bool -GetShapesFromSurf( const ISurf* pSurf, double dShapeLinTol, double dShapeAngTol, double dLinTol, - double dEdgeLinTol, double dAngTol, double dFaceAngTol, const STRVECTOR& vsShapes, - ISURFPOVECTOR& vSurfSel, ICRVCOMPOPOMATRIX& matCompoBorders) +IsBorderAButtonHole( const PolyLine& PL, double dLinTol, double dAngTol, Frame3d& frBtHole, + double& dRectLen, double& dRad, CurveComposite& CompoBthole) { - vSurfSel.clear() ; - matCompoBorders.clear() ; - // Verifico la validità della superficie - if ( pSurf == nullptr || ! pSurf->IsValid()) + // Se PolyLine aperta o non piana, non è un'asola + Plane3d PlanePL ; + if ( ! PL.IsClosed() || ! PL.IsFlat( PlanePL, dLinTol)) return false ; - // Recupero il Tipo - int nType = pSurf->GetType() ; + // Verifico che tutti i punti rispettino la tolleranza angolare + POLYLINEVECTOR vPL ; + if ( ! GetPointSetByAngTol( PL, dAngTol, vPL) || ssize( vPL) != 1) + return false ; - ISURFTMPOVECTOR vSurfTmSelTmp ; - // Se superficie di Besier, non faccio nulla (?) - if ( nType == SRF_BEZIER) - return true ; - // Se superficie TriMesh - else if ( nType == SRF_TRIMESH) { - // Recupero la TriMesh - const SurfTriMesh* pStmBasic = GetBasicSurfTriMesh( pSurf) ; - if ( pStmBasic == nullptr || ! pStmBasic->IsValid()) - return false ; - // Ciclo di Analisi Triangoli - const int MAXTRY = 1000 ; - int nCount = 0 ; - int nTriaCheck = 0 ; - BOOLVECTOR vbTria( pStmBasic->GetTriangleCount(), false) ; - while ( nCount < MAXTRY && nTriaCheck < pStmBasic->GetTriangleCount()) { - // Recupero il primo triangolo valido disponibile non ancora analizzato - int nFirstTria = 0 ; - for ( int nT = 0 ; nT < ssize( vbTria) ; ++ nT) { - if ( ! vbTria[nT]) { - nFirstTria = nT ; - break ; - } - } - unordered_set setNewTria ; setNewTria.reserve( pStmBasic->GetTriangleCount()) ; - unordered_set setAvoidTria ; setAvoidTria.reserve( pStmBasic->GetTriangleCount()) ; - // Collezioni di triangoli da analizzare - INTVECTOR vTria ; vTria.reserve( pStmBasic->GetTriangleCount()) ; - vTria.push_back( nFirstTria) ; - // Finchè ho triangoli da visitare - while ( ! vTria.empty()) { - // Recupero il triangolo corrente - int nCurrTria = vTria.back() ; - // Elimino il triangolo corente - vTria.pop_back() ; + #if DEBUG_HOLES + vector VTCircle ; + vector VCCirle ; + CurveComposite CompoPL ; CompoPL.FromPolyLine( PL) ; + VTCircle.emplace_back( CompoPL.Clone()) ; + VCCirle.emplace_back( RED) ; + SaveGeoObj( VTCircle, VCCirle, "C:\\Temp\\ButtonHoleDebug.nge") ; + #endif - // Se triangolo da evitare, passo al successivo - if ( setAvoidTria.find( nCurrTria) != setAvoidTria.end()) - continue ; - // Se triangolo mai visitato lo aggiungo tra quelli visitati, altrimenti passo al successivo - if ( vbTria[nCurrTria]) - continue ; - vbTria[nCurrTria] = true ; - ++ nTriaCheck ; + // Creo un sistema di riferimento centrato nella PolyLine e porto una sua copia in esso + Frame3d frXY ; + if ( ! frXY.Set( PlanePL.GetPoint(), PlanePL.GetVersN())) + return false ; + PolyLine PLXY = PL ; PLXY.ToLoc( frXY) ; + for ( POINTU& ptU : PLXY.GetUPointList()) + ptU.first.z = 0. ; - // Inserisco il triangolo corrente - setNewTria.insert( nCurrTria) ; + #if DEBUG_HOLES + CurveComposite CompoXY ; CompoXY.FromPolyLine( PLXY) ; + VTCircle.emplace_back( CompoXY.Clone()) ; + VCCirle.emplace_back( BLUE) ; + SaveGeoObj( VTCircle, VCCirle, "C:\\Temp\\ButtonHoleDebug.nge") ; + #endif - // Recupero il triangolo corrente e le sue adiacenze - int nTriaVertices[3] ; - if ( ! pStmBasic->GetTriangle( nCurrTria, nTriaVertices)) - return false ; - Triangle3d Tria ; - if ( ! pStmBasic->GetTriangle( nCurrTria, Tria)) - return false ; - int nIdAdjTriaId[3] ; - if ( ! pStmBasic->GetTriangleAdjacencies( nCurrTria, nIdAdjTriaId)) - return false ; + // Recupero il rettangolo ad area minima + Point3d ptCen ; + Vector3d vtRectAx ; + double dLen, dHeight ; + if ( ! PLXY.GetMinAreaRectangleXY( ptCen, vtRectAx, dLen, dHeight)) + return false ; - // Scorro le adiacenze - for ( int nAdj = 0 ; nAdj < 3 ; ++ nAdj) { - // Recupero l'indice del triangolo corrente - int nTriaAdj = nIdAdjTriaId[nAdj] ; - // Se non ho adiacenza, non faccio nulla - if ( nTriaAdj == SVT_NULL) - continue ; - // Recupero il triangolo adiacente - Triangle3d TriaAdj ; - if ( ! pStmBasic->GetTriangle( nTriaAdj, TriaAdj)) - return false ; - // Se la normale è fuori dalla tolleranza, memorizzo il triangolo tra quelli da scartare - if ( Tria.GetN() * TriaAdj.GetN() < cos( ( dFaceAngTol + EPS_ANG_SMALL) * DEGTORAD)) { - setAvoidTria.insert( nTriaAdj) ; - continue ; - } - // Inserisco il triangolo per la ricerca futura - vTria.push_back( nTriaAdj) ; - } - } - ++ nCount ; - // Se ho nuovi triangoli, definisco una superficie da essi - if ( ! setNewTria.empty()) { + // Verifico che non sia un rettangolo ben definito, non un quadrato + if ( dLen - dHeight < 1001. * EPS_SMALL) + return false ; // potrebbe essere una circonferenza - #if DEBUG_SHAPE_STM - VT.clear() ; VC.clear() ; - VT.emplace_back( pStmBasic->Clone()) ; - VC.emplace_back( BLACK) ; - StmFromTriangleSoup _TriaSoup ; _TriaSoup.Start() ; - for ( auto _Iter = setNewTria.begin() ; _Iter != setNewTria.end() ; ++ _Iter) { - Triangle3d _Tria ; - if ( ! pStmBasic->GetTriangle( *_Iter, _Tria)) - return false ; - _TriaSoup.AddTriangle( _Tria) ; - } - _TriaSoup.End() ; - VT.emplace_back( _TriaSoup.GetSurf()) ; - VC.emplace_back( LIME) ; - //SaveGeoObj( VT, VC, "C:\\Temp\\MyShape.nge") ; - VT.clear() ; VC.clear() ; - #endif + // Cambio il sistema di riferimento in quello definito dal rettangolo + Frame3d frRect ; + if ( ! frRect.Set( ptCen, Z_AX, vtRectAx)) + return false ; + PLXY.ToLoc( frRect) ; - StmFromTriangleSoup TriaSoup ; TriaSoup.Start() ; - for ( auto Iter = setNewTria.begin() ; Iter != setNewTria.end() ; ++ Iter) { - Triangle3d Tria ; - if ( ! pStmBasic->GetTriangle( *Iter, Tria)) - return false ; - TriaSoup.AddTriangle( Tria) ; - } - TriaSoup.End() ; - PtrOwner pStmTmp( TriaSoup.GetSurf()) ; - if ( ! IsNull( pStmTmp) && pStmTmp->IsValid() && pStmTmp->GetTriangleCount() > 0) { - if ( ! vSurfTmSelTmp.emplace_back( Release( pStmTmp))) - return false ; - } - } + #if DEBUG_HOLES + CompoXY.Clear() ; CompoXY.FromPolyLine( PLXY) ; + VTCircle.emplace_back( CompoXY.Clone()) ; + VCCirle.emplace_back( AQUA) ; + SaveGeoObj( VTCircle, VCCirle, "C:\\Temp\\ButtonHoleDebug.nge") ; + #endif + + // Individuo il punto in basso a sinistra del rettangolo + Point3d ptLeftBotton = ORIG - ( dLen / 2.) * X_AX - ( dHeight / 2.) * Y_AX ; + + // Semicirconferenza a sinistra + Point3d ptArcLeftCenter = ptLeftBotton + X_AX * dHeight / 2. + Y_AX * dHeight / 2. ; + CurveArc ArcLeft ; + ArcLeft.Set( ptArcLeftCenter, Z_AX, dHeight / 2., Y_AX, ANG_STRAIGHT, 0.) ; + + // Semicirconferenza a destra + Point3d ptArcRightCenter = ptLeftBotton + ( dLen - dHeight / 2.) * X_AX + Y_AX * dHeight / 2. ; + CurveArc ArcRight ; + ArcRight.Set( ptArcRightCenter, Z_AX, dHeight / 2., - Y_AX, ANG_STRAIGHT, 0.) ; + + // Tratto Lineare Top + CurveLine LineTop ; + LineTop.Set( ptArcRightCenter + Y_AX * dHeight / 2., ptArcLeftCenter + Y_AX * dHeight / 2.) ; + + // Tratto Lineare Botton + CurveLine LineBottom ; + LineBottom.Set( ptArcLeftCenter - Y_AX * dHeight / 2., ptArcRightCenter - Y_AX * dHeight / 2.) ; + + // Curva Composita complessiva dell'asola + CurveComposite CompoButtonHolePerfect ; + CompoButtonHolePerfect.AddCurve( LineTop) ; + CompoButtonHolePerfect.AddCurve( ArcLeft) ; + CompoButtonHolePerfect.AddCurve( LineBottom) ; + CompoButtonHolePerfect.AddCurve( ArcRight) ; + + #if DEBUG_HOLES + VTCircle.emplace_back( CompoButtonHolePerfect.Clone()) ; + VCCirle.emplace_back( WHITE) ; + SaveGeoObj( VTCircle, VCCirle, "C:\\Temp\\ButtonHoleDebug.nge") ; + #endif + + // Verifico che tutti i punti dell PolyLine siano abbastanza vicini a tale curva + // Campiono usando i punti medi, altrimenti qualsiasi poligono iscritto nell'asola ideale + // sarebbe valido + PNTVECTOR vPts ; + Point3d ptNext ; + PLXY.GetFirstPoint( ptNext) ; + vPts.push_back( ptNext) ; + while ( PLXY.GetNextPoint( ptNext)) { + vPts.push_back( Media( vPts.back(), ptNext)) ; + vPts.push_back( ptNext) ; + } + #if DEBUG_HOLES + for ( int i = 0 ; i < ssize( vPts) ; ++ i) { + IGeoPoint3d* ptOnCirle = CreateGeoPoint3d() ; ptOnCirle->Set( vPts[i]) ; + VTCircle.emplace_back( ptOnCirle) ; + VCCirle.emplace_back( GREEN) ; } + SaveGeoObj( VTCircle, VCCirle, "C:\\Temp\\ButtonHoleDebug.nge") ; + #endif + bool bButtonHole = true ; + for ( int i = 0 ; bButtonHole && i < ssize( vPts) ; ++ i) { + double dSqDist = INFINITO ; + bButtonHole = ( DistPointCurve( vPts[i], CompoButtonHolePerfect).GetSqDist( dSqDist) && + dSqDist < dLinTol * dLinTol) ; } - // Se non ho ricavato superfici, esco - if ( vSurfTmSelTmp.empty()) + // Se Asola, restituisco i parametri + if ( bButtonHole) { + frBtHole.Set( GetToGlob( GetToGlob( ORIG, frRect), frXY), + PlanePL.GetVersN(), + GetToGlob( GetToGlob( X_AX, frRect), frXY)) ; + dRectLen = dLen - 2. * dHeight ; + dRad = dHeight / 2. ; + CompoBthole.CopyFrom( &CompoButtonHolePerfect) ; + CompoBthole.ToGlob( frRect) ; + CompoBthole.ToGlob( frXY) ; return true ; - - // Per ognuna di esse ricerco le geometrie compatibili - for ( int i = 0 ; i < ssize( vSurfTmSelTmp) ; ++ i) { - // Recupero i Loops - POLYLINEVECTOR vPL ; - vSurfTmSelTmp[i]->GetLoops( vPL) ; - // Elimino i Loop che non sono chiusi - vPL.erase( - remove_if( vPL.begin(), vPL.end(), []( const PolyLine& PL) { - return ( ! PL.IsClosed()) ; - }), - vPL.end() - ) ; - // Se non ho esattamente due Loops, passo alla superficie successiva - if ( ssize( vPL) != 2) - continue ; - // Se devo ricercare Circonferenze - if ( find_if( vsShapes.begin(), vsShapes.end(), [&]( const string& sStr) { - return ( sStr.compare( sCircle) == 0) ; - }) != vsShapes.end()) { - // Verifico che le due PolyLine siano circonferenze - Point3d ptCA, ptCB ; Vector3d vtNA, vtNB ; double dRadA, dRadB ; - if ( IsBorderACircle( vPL[0], dShapeLinTol, ptCA, vtNA, dRadA) && - IsBorderACircle( vPL[1], dShapeAngTol, ptCB, vtNB, dRadB)) { - // Definisco le due circonferenze - PtrOwner pCirA( CreateCurveArc()) ; - PtrOwner pCirB( CreateCurveArc()) ; - if ( ! IsNull( pCirA) && ! IsNull( pCirB) && - pCirA->Set( ptCA, vtNA, dRadA) && - pCirB->Set( ptCB, vtNB, dRadB)) { - vSurfSel.emplace_back( GetSurf( Release( vSurfTmSelTmp[i]))) ; - matCompoBorders.emplace_back( ICRVCOMPOPOVECTOR{}) ; - matCompoBorders.back().resize( 2) ; - matCompoBorders.back()[0].Set( ConvertCurveToComposite( Release( pCirA))) ; - matCompoBorders.back()[1].Set( ConvertCurveToComposite( Release( pCirB))) ; - // l'Approssimazione delle curve prevede che io usi sempre tratti lineari, quindi approssimo - PolyLine PLA ; matCompoBorders.back()[0]->ApproxWithLines( dLinTol, dAngTol, ICurve::APL_SPECIAL, PLA) ; - PolyLine PLB ; matCompoBorders.back()[0]->ApproxWithLines( dLinTol, dAngTol, ICurve::APL_SPECIAL, PLB) ; - matCompoBorders.back()[0]->Clear() ; matCompoBorders.back()[0]->FromPolyLine( PLA) ; - matCompoBorders.back()[1]->Clear() ; matCompoBorders.back()[1]->FromPolyLine( PLB) ; - } - } - - #if DEBUG_SHAPE_STM - CurveComposite _CompoA ; _CompoA.FromPolyLine( vPL[0]) ; - CurveComposite _CompoB ; _CompoB.FromPolyLine( vPL[1]) ; - VT.emplace_back( _CompoA.Clone()) ; - VT.emplace_back( _CompoB.Clone()) ; - Color _cCol = Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, 1.) ; - VC.emplace_back( _cCol) ; - VC.emplace_back( _cCol) ; - #endif - } } - // #if DEBUG_SHAPE_STM - // SaveGeoObj( VT, VC, "C:\\Temp\\myAutoBorders.nge") ; - // #endif - - return true ; + return false ; } //----------------------------------------------------------------------------- @@ -3515,6 +3522,19 @@ GetTrimmingRawEdges( const CISURFPVECTOR& vSurf, const SELVECTOR& vSurfFace, return false ; } + #if DEBUG_RAW_EDGES + VT.clear() ; VC.clear() ; + for ( int i = 0 ; i < ssize( vSurf) ; ++ i) { + VT.emplace_back( vSurf[i]->Clone()) ; + VC.emplace_back( BLACK) ; + } + for ( int i = 0 ; i < ssize( vCompoRawEdges) ; ++ i) { + VT.emplace_back( vCompoRawEdges[i]) ; + VC.emplace_back( RED) ; + } + SaveGeoObj( VT, VC, "C:\\Temp\\RawEdges.nge") ; + #endif + return true ; } @@ -3650,10 +3670,10 @@ GetTrimmingFinalBorders( CISURFPVECTOR& vpSurf, const SELVECTOR& vSurfFaces, dou if ( IsNull( pCompoLoopExtr) || ! pCompoLoopExtr->FromPolyLine( PLLoopExtr)) continue ; vCompoBezierEdges.emplace_back( Release( pCompoLoop)) ; - if ( ! ApproxBorder( *vCompoBezierEdges.back(), dMyLinTol, dMyAngTol)) + if ( ! ApproxBorder( *GetBasicCurveComposite( vCompoBezierEdges.back()), dMyLinTol, dMyAngTol)) return false ; vCompoBezierEdges.emplace_back( Release( pCompoLoopExtr)) ; - if ( ! ApproxBorder( *vCompoBezierEdges.back(), dMyLinTol, dMyAngTol)) + if ( ! ApproxBorder( *GetBasicCurveComposite( vCompoBezierEdges.back()), dMyLinTol, dMyAngTol)) return false ; } @@ -3698,7 +3718,7 @@ GetTrimmingBezierEdges( ICRVCOMPOPOVECTOR& vCompoRawEdges, double dLinTol, doubl for ( int i = 0 ; i < int( vCompoRawEdges.size()) ; ++ i) { PtrOwner pCompoTmp( CloneCurveComposite( vCompoRawEdges[i])) ; if ( IsNull( pCompoTmp) || - ! ApproxBorder( *pCompoTmp, dMyLinTol, dMyAngTol) || + ! ApproxBorder( *GetBasicCurveComposite( pCompoTmp), dMyLinTol, dMyAngTol) || ! vBezierEdges.emplace_back( Release( pCompoTmp))) { LOG_ERROR( GetEGkLogger(), "Error in Trimming : Approxing edge failed") ; return false ; @@ -3905,15 +3925,15 @@ GetTrimmingRuledBezier( const CISURFPVECTOR& vSurf, const ICurve* pCrvEdge1, // quella faccia viene memorizzata e considerata come nuovo punto di partenza per la ricerca // di ulteriori adiacenze. bool -GetTrimmingStmAdjTria( const ISurfTriMesh* pStm, const INTVECTOR& vTria, const PNTVECTOR& vPts, +GetTrimmingStmAdjTria( const ISurfTriMesh* pStm, int nStartTria, const Point3d& ptStartTria, double dAngTol, double dSize, double dSizeTol, ISurfTriMesh* pStmAdjTria) { // La superfcicie deve essere inizializzata if ( pStmAdjTria == nullptr) return false ; - // Verifico la validità della superficie TriMesh e l'esistenza di triangoli di riferimento - if ( ! pStm->IsValid() || vTria.empty()) + // Verifico la validità della superficie TriMesh + if ( ! pStm->IsValid()) return false ; // Recupero la superficie di base @@ -3924,10 +3944,10 @@ GetTrimmingStmAdjTria( const ISurfTriMesh* pStm, const INTVECTOR& vTria, const P // Definisco un Box3d nel punto di Selezione di dimensioni pari al doppio della dimensione della // striscia di ricerca considerando la tolleranza Triangle3d firstTria ; - if ( ! pStmBasic->GetTriangle( vTria[0], firstTria)) + if ( ! pStmBasic->GetTriangle( nStartTria, firstTria)) return false ; BBox3d BBoxCurr ; - BBoxCurr.Add( vPts[0]) ; + BBoxCurr.Add( ptStartTria) ; const double EXPAND_EXTRA_TOL = 10. * EPS_SMALL ; BBoxCurr.Expand( ( dSize + dSizeTol + EXPAND_EXTRA_TOL)) ; @@ -3942,7 +3962,7 @@ GetTrimmingStmAdjTria( const ISurfTriMesh* pStm, const INTVECTOR& vTria, const P Point3d ptMid, ptMid1 ; int nTria = 0, nTria1 = 0 ; CurveComposite CompoA, CompoB ; - if ( ! GetBordersInBox( *pStmBasic, BBoxCurr, vTria[0], vPts[0], dSize, dSizeTol, true, true, + if ( ! GetBordersInBox( *pStmBasic, BBoxCurr, nStartTria, ptStartTria, dSize, dSizeTol, true, true, dAngTol, 2. * EPS_SMALL, setAvoidTria, setNewTria, mapTriaClass, CompoA, CompoB, ptMid, ptMid1, nTria, nTria1, bBreak, bStop)) return false ; @@ -3993,10 +4013,7 @@ GetTrimmingStmAdjTria( const ISurfTriMesh* pStm, const INTVECTOR& vTria, const P if ( IsNull( pStmTria) || ! pStmTria->IsValid() || pStmTria->GetTriangleCount() == 0) return false ; - else - return ( pStmAdjTria->CopyFrom( pStmTria)) ; - - return true ; + return ( pStmAdjTria->CopyFrom( pStmTria)) ; } //------------------------------------------------------------------------------ @@ -4015,87 +4032,197 @@ GetTrimmingAdjSurfs( const CISURFPVECTOR& vSurf, const CISURFPVECTOR& vOtherSurf return false ; } - // creo l'insieme delle curve di bordo in continuità + // Recupero le Patch delle superfici SURFPATCHESVECTOR vSurfPatches ; vSurfPatches.reserve( vSurf.size() + vOtherSurf.size()) ; - BOXVECTOR vBBox3d ; vBBox3d.reserve( vSurf.size() + vOtherSurf.size()) ; + // --- Superfici Selezionate for ( int nS = 0 ; nS < int( vSurf.size()) ; ++ nS) { vSurfPatches.emplace_back( SurfPatches()) ; vSurfPatches.back().pSurf = vSurf[nS] ; - vSurfPatches.back().nIndSurf = nS ; - vBBox3d.emplace_back( BBox3d()) ; - POLYLINEVECTOR vPLBorders ; - if ( ! InsertLoopsOfSurf( vSurf[nS], vPLBorders)) + if ( ! CalcSurfPatch( vSurf[nS], dLinTol, dAngTol, vSurfPatches.back())) return false ; - for ( int nPL = 0 ; nPL < int( vPLBorders.size()) ; ++ nPL) - vPLBorders[nPL].GetLocalBBox( vBBox3d.back()) ; - vBBox3d.back().Expand( 2. * dLinTol) ; - POLYLINEMATRIX matPLPatchBorders ; - if ( ! CalcPatches( vPLBorders, dAngTol, matPLPatchBorders)) - return false ; - for ( int i = 0 ; i < int( matPLPatchBorders.size()) ; ++ i) { - for ( int j = 0 ; j < int( matPLPatchBorders[i].size()) ; ++ j) { - Point3d ptS ; matPLPatchBorders[i][j].GetFirstPoint( ptS) ; - Point3d ptE ; matPLPatchBorders[i][j].GetLastPoint( ptE) ; - vSurfPatches.back().vPatches.emplace_back( ptS, ptE, i, false) ; - vSurfPatches.back().CompoPathces.emplace_back( CurveComposite()) ; - vSurfPatches.back().CompoPathces.back().FromPolyLine( matPLPatchBorders[i][j]) ; - } - } } + // --- Altre Superfici for ( int nS = 0 ; nS < int( vOtherSurf.size()) ; ++ nS) { vSurfPatches.emplace_back( SurfPatches()) ; vSurfPatches.back().pSurf = vOtherSurf[nS] ; - vSurfPatches.back().nIndSurf = int( vSurf.size()) + nS ; - vBBox3d.emplace_back( BBox3d()) ; - POLYLINEVECTOR vPLBorders ; - if ( ! InsertLoopsOfSurf( vOtherSurf[nS], vPLBorders)) - continue ; - for ( int nPL = 0 ; nPL < int( vPLBorders.size()) ; ++ nPL) - vPLBorders[nPL].GetLocalBBox( vBBox3d.back()) ; - vBBox3d.back().Expand( 2. * dLinTol) ; - POLYLINEMATRIX matPLPatchBorders ; - if ( ! CalcPatches( vPLBorders, dAngTol, matPLPatchBorders)) + if ( ! CalcSurfPatch( vOtherSurf[nS], dLinTol, dAngTol, vSurfPatches.back())) return false ; - for ( int i = 0 ; i < int( matPLPatchBorders.size()) ; ++ i) { - for ( int j = 0 ; j < int( matPLPatchBorders[i].size()) ; ++ j) { - Point3d ptS ; matPLPatchBorders[i][j].GetFirstPoint( ptS) ; - Point3d ptE ; matPLPatchBorders[i][j].GetLastPoint( ptE) ; - vSurfPatches.back().vPatches.emplace_back( ptS, ptE, i, false) ; - vSurfPatches.back().CompoPathces.emplace_back( CurveComposite()) ; - vSurfPatches.back().CompoPathces.back().FromPolyLine( matPLPatchBorders[i][j]) ; - } - } } - // Se necessario, Splitto le Patch per far combiaciare gli estremi - for ( int i = 0 ; i < int( vSurfPatches.size()) - 1 ; ++ i) { - for ( int j = i + 1 ; j < int( vSurfPatches.size()) ; ++ j) { - if ( vBBox3d[i].Overlaps( vBBox3d[j])) { - if ( ! SplitPatchWithPatch( vSurfPatches[i], vSurfPatches[j], dLinTol)) - return false ; - } - } - } - - #if DEBUG_SIMPLE_PATCHES + #if DEBUG_SURF_PATCHES VT.clear() ; VC.clear() ; - for ( int i = 0 ; i < int( vSurfPatches.size()) ; ++ i) { + for ( int i = 0 ; i < ssize( vSurfPatches) ; ++ i) { Color myCol = Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, 1.) ; - for ( int j = 0 ; j < int( vSurfPatches[i].CompoPathces.size()) ; ++ j) { - VT.emplace_back( vSurfPatches[i].CompoPathces[j].Clone()) ; + for ( int j = 0 ; j < ssize( vSurfPatches[i].vCompoBorders) ; ++ j) { + VT.emplace_back( vSurfPatches[i].vCompoBorders[j].Clone()) ; VC.emplace_back( myCol) ; - IGeoPoint3d* _pt = CreateGeoPoint3d() ; _pt->Set( vSurfPatches[i].vPatches[j].ptStart) ; - VT.emplace_back( _pt) ; - VC.emplace_back( AQUA) ; - IGeoPoint3d* _pt1 = CreateGeoPoint3d() ; _pt1->Set( vSurfPatches[i].vPatches[j].ptEnd) ; - VT.emplace_back( _pt1) ; - VC.emplace_back( AQUA) ; + set& setPar = vSurfPatches[i].vSetPatchPar[j] ; + for ( auto Iter = setPar.begin() ; Iter != setPar.end() ; ++ Iter) { + Point3d ptCurr ; + vSurfPatches[i].vCompoBorders[j].GetPointD1D2( *Iter, ICurve::FROM_MINUS, ptCurr) ; + PtrOwner ptGeoCurr( CreateGeoPoint3d()) ; ptGeoCurr->Set( ptCurr) ; + VT.emplace_back( ptGeoCurr->Clone()) ; + VC.emplace_back( ORANGE) ; + } } } - SaveGeoObj( VT, VC, "C:\\Temp\\SimplePatch.nge") ; + SaveGeoObj( VT, VC, "C:\\Temp\\SurfPatches.nge") ; #endif - // Verifico ora se le tangenze nei punti di giunzione sono al di sotto della tolleranza angolare + // Se necessario, Splitto le Patch per far combiaciare gli estremi + vector matBorderModif( vSurfPatches.size()) ; + for ( int i = 0 ; i < ssize( vSurfPatches) ; ++ i) { + // Recupero la SurfPatch corrente + SurfPatches& CurrSurfPatch = vSurfPatches[i] ; + // Recupero i Suoi Bordi e i Parametri associati + const SimpleBorderVector& vSimpleBorder = CurrSurfPatch.vBorderPatches ; + matBorderModif[i].resize( vSimpleBorder.size(), false) ; + const COMPOVECTOR& vCompoBorders = CurrSurfPatch.vCompoBorders ; + vector>& vSetSplitPar = CurrSurfPatch.vSetPatchPar ; + // Scorro i Bordi della Superficie + for ( int nCurrBorder = 0 ; nCurrBorder < ssize( vSimpleBorder) ; ++ nCurrBorder) { + // Recupero la Composita associata al Bordo Corrente e il suo Box + const CurveComposite& CurrCompoBorder = vCompoBorders[nCurrBorder] ; + BBox3d BBoxCurrCompoBorder ; CurrCompoBorder.GetLocalBBox( BBoxCurrCompoBorder) ; + // Recupero le Patch associate + const SimpleBorder& vPatchCurrBorder = vSimpleBorder[nCurrBorder] ; + // Recupero il vettore dei Parametri di Split + set& setSplitPar = vSetSplitPar[nCurrBorder] ; + #if DEBUG_SURF_PATCHES + VC.clear() ; VT.clear() ; + VT.emplace_back( CurrCompoBorder.Clone()) ; + VC.emplace_back( RED) ; + for ( auto Iter = setSplitPar.begin() ; Iter != setSplitPar.end() ; ++ Iter) { + Point3d ptCurr ; + CurrCompoBorder.GetPointD1D2( *Iter, ICurve::FROM_MINUS, ptCurr) ; + PtrOwner ptGeoCurr( CreateGeoPoint3d()) ; ptGeoCurr->Set( ptCurr) ; + VT.emplace_back( ptGeoCurr->Clone()) ; + VC.emplace_back( ORANGE) ; + } + #endif + // Scorro le altre SurfPatches + for ( int j = 0 ; j < ssize( vSurfPatches) ; ++ j) { + // Se stessa SurfPath, passo alla successiva + if ( i == j) + continue ; + // Recupero l'altra SurfPatch + SurfPatches& OtherSurfPatch = vSurfPatches[j] ; + // Recupero i Suoi Bordi e i Parametri associati + const SimpleBorderVector& vSimpleOtherBorder = OtherSurfPatch.vBorderPatches ; + const COMPOVECTOR& vCompoBorders = OtherSurfPatch.vCompoBorders ; + // Scorro i suoi bordi + for ( int nOtherBorder = 0 ; nOtherBorder < ssize( vSimpleOtherBorder) ; ++ nOtherBorder) { + // Recupero le Patch associate + const SimpleBorder& vPatchOtherBorder = vSimpleOtherBorder[nOtherBorder] ; + // Recupero la Composita associata al Bordo + const CurveComposite& OtherCompoBorder = vCompoBorders[nOtherBorder] ; + #if DEBUG_SURF_PATCHES + VT.emplace_back( OtherCompoBorder.Clone()) ; + VC.emplace_back( BLACK) ; + #endif + // Scorro le sue Patches + for ( int nOtherPatch = 0 ; nOtherPatch < ssize( vPatchOtherBorder) ; ++ nOtherPatch) { + // Recupero il Box della patch + BBox3d BBoxOtherPath = OtherSurfPatch.matBox3dPatches[nOtherBorder][nOtherPatch] ; + // Se Tali Box ( espansi già della tolleranza lineare) non interferiscono, allora passo + // alla Patch successiva + if ( ! BBoxCurrCompoBorder.Overlaps( BBoxOtherPath)) + continue ; + // Recupero gli estremi della Path attuale + DistPointCurve DPTCRV( vPatchOtherBorder[nOtherPatch].ptStart, CurrCompoBorder) ; + double dDist = INFINITO ; + if ( DPTCRV.GetDist( dDist) && dDist < dLinTol) { + Point3d ptMinDist ; + int nFlag = 0 ; + if ( DPTCRV.GetMinDistPoint( 0., ptMinDist, nFlag)) { + bool bInsert = true ; + for ( int nCurrPatch = 0 ; bInsert && nCurrPatch < ssize( vPatchCurrBorder) ; ++ nCurrPatch) { + const SimplePatch& Patch = vPatchCurrBorder[nCurrPatch] ; + bInsert = ( ! AreSamePointEpsilon( Patch.ptStart, ptMinDist, dLinTol) && + ! AreSamePointEpsilon( Patch.ptEnd, ptMinDist, dLinTol)) ; + } + if ( bInsert) { + double dPar = -1. ; + if ( DPTCRV.GetParamAtMinDistPoint( 0., dPar, nFlag)) { + setSplitPar.insert( dPar) ; + matBorderModif[i][nCurrBorder] = true ; + #if DEBUG_SURF_PATCHES + PtrOwner ptGeoCurr( CreateGeoPoint3d()) ; + ptGeoCurr->Set( ptMinDist) ; + VT.emplace_back( ptGeoCurr->Clone()) ; + VC.emplace_back( AQUA) ; + #endif + } + } + } + } + } + } + } + } + #if DEBUG_SURF_PATCHES + SaveGeoObj( VT, VC, "C:\\Temp\\SplitPathces.nge") ; + #endif + } + // Scorro tutte le Surf Patches + for ( int i = 0 ; i < ssize( vSurfPatches) ; ++ i) { + // Recupero la SurfPatch corrente + SurfPatches& CurrSurfPatch = vSurfPatches[i] ; + // Recupero i Suoi Bordi e i Parametri associati + SimpleBorderVector& vSimpleBorder = CurrSurfPatch.vBorderPatches ; + COMPOMATRIX& matCompoPatches = CurrSurfPatch.matCompoPatches ; + COMPOVECTOR& vCompoBorders = CurrSurfPatch.vCompoBorders ; + const vector>& vSetSplitPar = CurrSurfPatch.vSetPatchPar ; + // Scorro i Bordi + for ( int nCurrBorder = 0 ; nCurrBorder < ssize( vSimpleBorder) ; ++ nCurrBorder) { + // Se il bordo corrente non ha subito Split, passo al successivo + if ( ! matBorderModif[i][nCurrBorder]) + continue ; + // Pulisco la Composita associata a tale Bordo + COMPOVECTOR& vCompoPatches = matCompoPatches[nCurrBorder] ; + vCompoPatches.clear() ; + // Recupero la Curva Composita corrente + CurveComposite& CurrCompo = vCompoBorders[nCurrBorder] ; + // Inizializzo il nuovo Bordo semplice formato dalle Patch + SimpleBorder newSimpleBorder ; + // Recupero il vettore dei Parametri di Split + const set& setSplitPar = vSetSplitPar[nCurrBorder] ; + double dLastPar = 0 ; + for ( auto Iter = setSplitPar.begin() ; Iter != setSplitPar.end() ; ++ Iter) { + PtrOwner pCrvPatch( CurrCompo.CopyParamRange( dLastPar, *Iter)) ; + if ( ! IsNull( pCrvPatch) && pCrvPatch->IsValid()) { + vCompoPatches.emplace_back( *ConvertCurveToBasicComposite( Release( pCrvPatch))) ; + Point3d ptStart ; vCompoPatches.back().GetStartPoint( ptStart) ; + Point3d ptEnd ; vCompoPatches.back().GetEndPoint( ptEnd) ; + newSimpleBorder.emplace_back( ptStart, ptEnd, nCurrBorder, false) ; + dLastPar = *Iter ; + } + } + vSimpleBorder[nCurrBorder] = newSimpleBorder ; + } + } + #if DEBUG_SURF_PATCHES + VT.clear() ; VC.clear() ; + for ( int i = 0 ; i < ssize( vSurfPatches) ; ++ i) { + Color myCol = Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, 1.) ; + for ( int j = 0 ; j < ssize( vSurfPatches[i].matCompoPatches) ; ++ j) { + for ( int k = 0 ; k < ssize( vSurfPatches[i].matCompoPatches[j]) ; ++ k) { + VT.emplace_back( vSurfPatches[i].matCompoPatches[j][k].Clone()) ; + VC.emplace_back( myCol) ; + IGeoPoint3d* _pt = CreateGeoPoint3d() ; _pt->Set( vSurfPatches[i].vBorderPatches[j][k].ptStart) ; + VT.emplace_back( _pt) ; + VC.emplace_back( AQUA) ; + IGeoPoint3d* _pt1 = CreateGeoPoint3d() ; _pt1->Set( vSurfPatches[i].vBorderPatches[j][k].ptEnd) ; + VT.emplace_back( _pt1) ; + VC.emplace_back( AQUA) ; + } + } + } + SaveGeoObj( VT, VC, "C:\\Temp\\SplitPatch.nge") ; + #endif + + // Verifico ora se le Normali nei Tratti di giunzione tra Patches sono al di sotto + // della tolleranza angolare INTVECTOR vSurfToCheck ; INTSET setSurf ; for ( int i = 0 ; i < int( vSurf.size()) ; ++ i) @@ -4115,93 +4242,116 @@ GetTrimmingAdjSurfs( const CISURFPVECTOR& vSurf, const CISURFPVECTOR& vOtherSurf else continue ; - // Recupero la superficie corrente - const ISurf* pCurrSurf = vSurfPatches[nSurf].pSurf ; + // Recupero la Surf Patch Corrente + SurfPatches& currSurfPatch = vSurfPatches[nSurf] ; + // Recupero la Superficie corrente + const ISurf* pCurrSurf = currSurfPatch.pSurf ; + // Recupero il Box Corrente della Superficie + const BBox3d& BBoxCurrSurf = currSurfPatch.BoxSurf ; - // Scorro le sua Patches - for ( int nCurrPatch = 0 ; nCurrPatch < int( vSurfPatches[nSurf].vPatches.size()) ; ++ nCurrPatch) { - // Recupero la Patch attuale - SimplePatch& currPatch = vSurfPatches[nSurf].vPatches[nCurrPatch] ; - // Se Patch già analizzata, passo alla successiva - if ( currPatch.bErase) - continue ; - currPatch.bErase = true ; - // Scorro le altre Patches - for ( int nOtherSurf = 0 ; nOtherSurf < int( vSurfPatches.size()) ; ++ nOtherSurf) { - // Se stessa superficie, passo alla successiva - if ( nOtherSurf == nSurf) + // Scorro i suoi Bordi semplici + for ( int nCurrBorder = 0 ; nCurrBorder < ssize( currSurfPatch.vBorderPatches) ; ++ nCurrBorder) { + // Recupero il Bordo Corrente + SimpleBorder& CurrSimpleBorder = currSurfPatch.vBorderPatches[nCurrBorder] ; + // Scorro le sua Patches + for ( int nCurrPatch = 0 ; nCurrPatch < ssize( CurrSimpleBorder) ; ++ nCurrPatch) { + // Recupero la Patch attuale + SimplePatch& currPatch = CurrSimpleBorder[nCurrPatch] ; + // Se Patch già analizzata, passo alla successiva + if ( currPatch.bErase) continue ; - // Se superficie già analizzata, passo alla successiva - if ( setSurf.find( nOtherSurf) != setSurf.end()) - continue ; - // Recupero la superficie di confronto - const ISurf* pOtherSurf = vSurfPatches[nOtherSurf].pSurf ; - // Scorro le sua Patches - for ( int nOtherPatch = 0 ; nOtherPatch < int( vSurfPatches[nOtherSurf].vPatches.size()) ; ++ nOtherPatch) { - // Recupero la Patch di confronto - SimplePatch& nextPatch = vSurfPatches[nOtherSurf].vPatches[nOtherPatch] ; - // Se Patch già analizzata, passo alla successiva - if ( nextPatch.bErase) + currPatch.bErase = true ; + + // Scorro le altre Superfici + for ( int nOtherSurf = 0 ; nOtherSurf < ssize( vSurfPatches) ; ++ nOtherSurf) { + // Se stessa superficie, passo alla successiva + if ( nOtherSurf == nSurf) continue ; - // Se gli estremi coincidono - if ( ( AreSamePointEpsilon( currPatch.ptStart, nextPatch.ptStart, dLinTol) && - AreSamePointEpsilon( currPatch.ptEnd, nextPatch.ptEnd, dLinTol)) || - ( AreSamePointEpsilon( currPatch.ptStart, nextPatch.ptEnd, dLinTol) && - AreSamePointEpsilon( currPatch.ptEnd, nextPatch.ptStart, dLinTol))) { - // Controllo se le tangenze rimangono nella tolleranza - bool bTangent = true ; - // Campiono la Patch corrente - const int MAX_POINTS = 5 ; - BIPNTVECTOR vPtAPtB ; vPtAPtB.reserve( MAX_POINTS + 1) ; - CurveComposite& currCompoPatch = vSurfPatches[nSurf].CompoPathces[nCurrPatch] ; - CurveComposite& otherCompoPatch = vSurfPatches[nOtherSurf].CompoPathces[nOtherPatch] ; - bTangent = ( currCompoPatch.IsValid() && otherCompoPatch.IsValid()) ; - if ( bTangent) { - double dLen = 0.; - currCompoPatch.GetLength( dLen) ; - for ( int i = 0 ; bTangent && i <= MAX_POINTS ; ++ i) { - double dU = 0. ; - currCompoPatch.GetParamAtLength( ( dLen / MAX_POINTS) * i, dU) ; - Point3d ptCurr ; - currCompoPatch.GetPointD1D2( dU, ICurve::FROM_MINUS, ptCurr) ; - Point3d ptOther ; - int nFlag = 0 ; - if ( ! DistPointCurve( ptCurr, otherCompoPatch).GetMinDistPoint( 0., ptOther, nFlag)) - bTangent = false ; - // Recupero le due normali sulle curva patch campionate - Vector3d vtNCurr = V_INVALID, vtNOther = V_INVALID ; - if ( ! GetNormalAtPoint( pCurrSurf, ptCurr, vtNCurr) || - ! GetNormalAtPoint( pOtherSurf, ptOther, vtNOther)) - return false ; - bTangent = ( vtNCurr * vtNOther > cos( ( dFaceAngTol - EPS_ANG_SMALL) * DEGTORAD)) ; + // Se superficie già analizzata, passo alla successiva + if ( setSurf.find( nOtherSurf) != setSurf.end()) + continue ; + + // Recupero la Surf Patch + SurfPatches OtherSurfPatch = vSurfPatches[nOtherSurf] ; + // Recupero la Superficie + const ISurf* pOtherSurf = OtherSurfPatch.pSurf ; + // Recupero il Box della Superficie + const BBox3d& BBoxOtherSurf = OtherSurfPatch.BoxSurf ; + // Se non c'è Intersezione dei Box ( opportunamente estesi), passo alla SurfPatch successiva + if ( ! BBoxCurrSurf.Overlaps( BBoxOtherSurf)) + continue ; + + // Scorro i suoi Bordi semplici + for ( int nOtherBorder = 0 ; nOtherBorder < ssize( OtherSurfPatch.vBorderPatches) ; ++ nOtherBorder) { + // Recupero il Bordo + SimpleBorder& OtherSimpleBorder = OtherSurfPatch.vBorderPatches[nOtherBorder] ; + // Scorro le sue Patches + for ( int nOtherPatch = 0 ; nOtherPatch < ssize( OtherSimpleBorder) ; ++ nOtherPatch) { + // Recupero la Patch di confronto + SimplePatch& OtherPatch = OtherSimpleBorder[nOtherPatch] ; + // Se Patch già analizzata, passo alla successiva + if ( OtherPatch.bErase) + continue ; + // Se gli estremi coincidono + if ( ( AreSamePointEpsilon( currPatch.ptStart, OtherPatch.ptStart, dLinTol) && + AreSamePointEpsilon( currPatch.ptEnd, OtherPatch.ptEnd, dLinTol)) || + ( AreSamePointEpsilon( currPatch.ptStart, OtherPatch.ptEnd, dLinTol) && + AreSamePointEpsilon( currPatch.ptEnd, OtherPatch.ptStart, dLinTol))) { + // Controllo se le tangenze rimangono nella tolleranza + bool bTangent = true ; + // Campiono la Patch corrente ( passando per la Composita associata) + const int MAX_POINTS = 5 ; + BIPNTVECTOR vPtAPtB ; vPtAPtB.reserve( MAX_POINTS + 1) ; + CurveComposite& currCompoPatch = currSurfPatch.matCompoPatches[nCurrBorder][nCurrPatch] ; + CurveComposite& otherCompoPatch = OtherSurfPatch.matCompoPatches[nOtherBorder][nOtherPatch] ; + bTangent = ( currCompoPatch.IsValid() && otherCompoPatch.IsValid()) ; + if ( bTangent) { + double dLen = 0.; + currCompoPatch.GetLength( dLen) ; + for ( int i = 0 ; bTangent && i <= MAX_POINTS ; ++ i) { + double dU = 0. ; + currCompoPatch.GetParamAtLength( ( dLen / MAX_POINTS) * i, dU) ; + Point3d ptCurr ; + currCompoPatch.GetPointD1D2( dU, ICurve::FROM_MINUS, ptCurr) ; + Point3d ptOther ; + int nFlag = 0 ; + if ( ! DistPointCurve( ptCurr, otherCompoPatch).GetMinDistPoint( 0., ptOther, nFlag)) + bTangent = false ; + // Recupero le due normali sulle curva patch campionate + Vector3d vtNCurr = V_INVALID, vtNOther = V_INVALID ; + if ( ! GetNormalAtPoint( pCurrSurf, ptCurr, vtNCurr) || + ! GetNormalAtPoint( pOtherSurf, ptOther, vtNOther)) + return false ; + bTangent = ( vtNCurr * vtNOther > cos( ( dFaceAngTol - EPS_ANG_SMALL) * DEGTORAD)) ; + } + } + // Se superficie in tangenza, aggiorno i parametri + if ( bTangent) { + #if DEBUG_SURF_PATCHES + VC.clear() ; VT.clear() ; + VT.emplace_back( pCurrSurf->Clone()) ; + VC.emplace_back( LIME) ; + VT.emplace_back( pOtherSurf->Clone()) ; + VC.emplace_back( GREEN) ; + VT.emplace_back( currCompoPatch.Clone()) ; + VC.emplace_back( RED) ; + VT.emplace_back( otherCompoPatch.Clone()) ; + VC.emplace_back( BLUE) ; + SaveGeoObj( VT, VC, "C:\\Temp\\Test.nge") ; + #endif + vSurfToCheck.emplace_back( nOtherSurf) ; + OtherPatch.bErase = true ; + if ( nOtherSurf >= int( vSurf.size()) && + find( vIndOtherSurf.begin(), vIndOtherSurf.end(), nOtherSurf - ssize( vSurf)) == vIndOtherSurf.end()) + vIndOtherSurf.push_back( nOtherSurf - ssize( vSurf)) ; + } } } - // Se superficie in tangenza, aggiorno i parametri - if ( bTangent) { - #if DEBUG_SIMPLE_PATCHES - VC.clear() ; VT.clear() ; - VT.emplace_back( pCurrSurf->Clone()) ; - VC.emplace_back( LIME) ; - VT.emplace_back( pOtherSurf->Clone()) ; - VC.emplace_back( GREEN) ; - VT.emplace_back( currCompoPatch.Clone()) ; - VC.emplace_back( RED) ; - VT.emplace_back( otherCompoPatch.Clone()) ; - VC.emplace_back( BLUE) ; - SaveGeoObj( VT, VC, "C:\\Temp\\Test.nge") ; - #endif - vSurfToCheck.emplace_back( nOtherSurf) ; - nextPatch.bErase = true ; - if ( nOtherSurf >= int( vSurf.size()) && - find( vIndOtherSurf.begin(), vIndOtherSurf.end(), nOtherSurf - int( vSurf.size())) == vIndOtherSurf.end()) - vIndOtherSurf.push_back( nOtherSurf - int( vSurf.size())) ; - } } } } } } - #if DEBUG_SURF_PATCHES VT.clear() ; VC.clear() ; for ( const int& nInd : vIndOtherSurf) { @@ -4219,64 +4369,204 @@ GetTrimmingAdjSurfs( const CISURFPVECTOR& vSurf, const CISURFPVECTOR& vOtherSurf } //------------------------------------------------------------------------------ -// Funzione per la ricerca automatica delle Geometrie di Trimming +// Funzione per l'estrazione dei Bordi di Fori e Asole dato un vettore di Superfici bool -GetTrimmingAutoEntities( const CISURFPVECTOR& vSurf, double dShapeLinTol, double dShapeAngTol, - double dLinTol, double dEdgeLinTol, double dAngTol, double dAngFaceTol, - const STRVECTOR& vsShapes, ISURFPOMATRIX& matSelSurf, - ICRVCOMPOPOMATRIX& matCompoBorders, ISURFBEZPOVECTOR& vSurfBz) +GetTrimmingHoleBorders( const CISURFPVECTOR& vpSurf, const Point3d& ptRef, double dSurfLinTol, double dSurfAngTol, + double dEdgeLinTol, double dEdgeAngTol, double dEdgeThick, + ICRVCOMPOPOVECTOR& vHoleBorders) { - // Pulizia dei parametri di ingresso - matSelSurf.clear() ; - matCompoBorders.clear() ; - vSurfBz.clear() ; - - // Se non ho superfici non devo fare nulla - if ( vSurf.empty()) + vHoleBorders.clear() ; + // Se non ho superfici, non faccio nulla + if ( vpSurf.empty()) return true ; - // Verifico che le superfici presenti siano ben definite - for ( const ISurf* pSurf : vSurf) { + // Verifico che tutte le superfici siano valide + for ( const ISurf* pSurf : vpSurf) { if ( pSurf == nullptr || ! pSurf->IsValid()) return false ; } - // Controllo sulla tolleranza lineare - double dMyShapeLinTol = Clamp( dShapeLinTol, EPS_SMALL, 1e5 * EPS_SMALL) ; - double dMyLinTol = Clamp( dLinTol, EPS_SMALL, 1e5 * EPS_SMALL) ; - double dMyEdgeLinTol = Clamp( dEdgeLinTol, EPS_SMALL, 1e5 * EPS_SMALL) ; - // Controllo sulla tolleranza angolare - double dMyShapeAngTol = Clamp( dShapeAngTol, 1., 60.) ; - double dMyAngTol = Clamp( dAngTol, 1., 45.) ; - double dMyFaceAngTol = Clamp( dAngFaceTol, 1., 60.) ; - - ICRVCOMPOPOMATRIX matCompoBordersTmp ; - // Se una sola superficie, effettuo la ricerca per triangoli - if ( ssize( vSurf) == 1) { - ISURFPOVECTOR vSurfTmp ; - if ( ! GetShapesFromSurf( vSurf[0], dMyShapeLinTol, dMyShapeAngTol, dMyLinTol, dMyEdgeLinTol, - dMyAngTol, dMyFaceAngTol, vsShapes, vSurfTmp, matCompoBordersTmp)) - return false ; - for ( int i = 0 ; i < ssize( vSurfTmp) ; ++ i) { - matSelSurf.emplace_back( ISURFPOVECTOR{}) ; - matSelSurf.back().emplace_back( Release( vSurfTmp[i])) ; + #if DEBUG_HOLES + VT.clear() ; VC.clear() ; + for ( int i = 0 ; i < ssize( vpSurf) ; ++ i) { + VT.emplace_back( vpSurf[i]->Clone()) ; + VC.emplace_back( Color( 0., 0., 0., 0.25)) ; } - } - // Se più superfici eseguo la ricerca per Patches - else { - - } + SaveGeoObj( VT, VC, "C:\\Temp\\HoleBorders.nge") ; + #endif - // Se non ho alcuna Geometria voluta, esco - if ( matSelSurf.empty()) + // Aggiusto le tolleranze + double dMySurfLinTol = Clamp( dSurfLinTol, EPS_SMALL, 1e5) ; + double dMySurfAngTol = Clamp( dSurfAngTol, EPS_ANG_SMALL, 60.) ; + double dMyEdgeLinTol = Clamp( dEdgeLinTol, EPS_SMALL, 1e5) ; + double dMyEdgeAngTol = Clamp( dEdgeAngTol, EPS_ANG_SMALL, 60.) ; + double dMyEdgeThick = max( 10. * EPS_SMALL, dEdgeThick) ; // coerente con Offset + + // Dalle superfici ricavo i bordi Grezzi + SELVECTOR vSelIds ; vSelIds.resize( vpSurf.size()) ; + for ( int i = 0 ; i < ssize( vpSurf) ; ++ i) + vSelIds.emplace_back( SelData( i, SEL_SUB_ALL)) ; + ICRVCOMPOPOVECTOR vRawEdges ; + if ( ! GetTrimmingRawEdges( vpSurf, vSelIds, dMySurfLinTol, dMySurfAngTol, vRawEdges)) + return false ; + if ( vRawEdges.empty()) return true ; - // Per ogni Geometria, approssimo le Curve mediante delle Bezier e calolo la Rigata - for ( int i = 0 ; i < ssize( matSelSurf) ; ++ i) { - matCompoBorders.emplace_back( ICRVCOMPOPOVECTOR{}) ; matCompoBorders.back().reserve( 2) ; - if ( ! GetTrimmingBezierEdges( matCompoBordersTmp[i], dLinTol, dAngTol, matCompoBorders.back())) + #if DEBUG_HOLES + for ( int i = 0 ; i < ssize( vRawEdges) ; ++ i) { + VT.emplace_back( CloneCurveComposite( vRawEdges[i])) ; + VC.emplace_back( RED) ; + } + SaveGeoObj( VT, VC, "C:\\Temp\\HoleBorders.nge") ; + #endif + + // Tra le curve ricavate, tengo in considerazione solo Fori e Asole + enum HoleType { CIRCLE = 0, BUTTONHOLE = 1 } ; + struct Hole { + PtrOwner pCompoHole ; + int nType ; + Frame3d frCompo ; + double dRad ; + double dLen ; + Hole( ICurveComposite* pHole, int nT, const Frame3d& frC, double dR, double dL) + : nType( nT), frCompo( frC), dRad( dR), dLen( dL) { + pCompoHole.Set( pHole) ; + } + } ; + vector vHoles ; vHoles.reserve( vRawEdges.size()) ; + for ( int i = 0 ; i < ssize( vRawEdges) ; ++ i) { + // Verifico che la curva sia valida + if ( IsNull( vRawEdges[i]) || ! vRawEdges[i]->IsValid()) + continue ; + // Recupero la PolyLine associata + PolyLine PL ; + if ( ! vRawEdges[i]->ApproxWithLines( EPS_SMALL, EPS_ANG_SMALL, ICurve::APL_SPECIAL, PL)) return false ; - vSurfBz.emplace_back( GetTrimmingRuledBezier( vSurf, matCompoBorders.back()[0], matCompoBorders.back()[1], - dMyLinTol, BIPNTVECTOR{})) ; + // Verifico che -- CIRCONFERENZA -- + Frame3d frCompo ; + double dRad = 0. ; + CurveArc CrvCircle ; + if ( IsBorderACircle( PL, dMyEdgeLinTol, dMyEdgeAngTol, frCompo, dRad, CrvCircle)) { + PtrOwner pCompoCircle( CreateCurveComposite()) ; + if ( IsNull( pCompoCircle) || ! pCompoCircle->AddCurve( CrvCircle)) + return false ; + vHoles.emplace_back( Release( pCompoCircle), 0, frCompo, dRad, -1.) ; + continue ; + } + // Verifico se -- ASOLA -- + double dLen = 0. ; + CurveComposite CompoBtHole ; + if ( IsBorderAButtonHole( PL, dMyEdgeLinTol, dMyEdgeAngTol, frCompo, dLen, dRad, CompoBtHole)) { + PtrOwner pCompoBtHole( CreateCurveComposite()) ; + if ( IsNull( pCompoBtHole) || ! pCompoBtHole->AddCurve( CompoBtHole)) + return false ; + vHoles.emplace_back( Release( pCompoBtHole), HoleType::BUTTONHOLE, frCompo, dRad, dLen) ; + continue ; + } + } + + // Vedo se ci sono curve da accoppiare tra di loro + vHoleBorders.reserve( vHoles.size()) ; + if ( ssize( vHoles) > 1) { + for ( int i = 0 ; i < ssize( vHoles) - 1 ; ++ i) { + // Recupero la curva corrente, se non presente allora passo alla successiva + if ( IsNull( vHoles[i].pCompoHole)) + continue ; + int nIndJ = -1 ; + // Scorro le curve successive + for ( int j = i + 1 ; nIndJ == -1 && j < ssize( vHoles) ; ++ j) { + // Recupero la curva corrente, se non presente allora passo alla successiva + if ( IsNull( vHoles[i].pCompoHole)) + continue ; + // Se il tipo è differente non possono essere in coppia + if ( vHoles[i].nType != vHoles[j].nType) + continue ; + // Essendo della stessa topologia, verifico i parametri + bool bCouple = false ; + Vector3d vtCenCen ; + if ( vHoles[i].nType == HoleType::CIRCLE) { + bCouple = ( abs( vHoles[i].dRad - vHoles[j].dRad) < dMyEdgeLinTol && + AreSameOrOppositeVectorEpsilon( vHoles[i].frCompo.VersZ(), vHoles[j].frCompo.VersZ(), dMyEdgeLinTol)) ; + if ( bCouple) { + vtCenCen = ( vHoles[i].frCompo.Orig() - vHoles[j].frCompo.Orig()) ; + bCouple = ( vtCenCen.SqLen() > dMyEdgeLinTol * dMyEdgeLinTol) ; + if ( bCouple) { + bCouple = ( vtCenCen.Normalize() && + AreSameOrOppositeVectorEpsilon( vtCenCen, vHoles[i].frCompo.VersZ(), dMyEdgeLinTol)) ; + } + } + } + else if ( vHoles[i].nType == HoleType::BUTTONHOLE) { + bCouple = ( abs( vHoles[i].dRad - vHoles[j].dRad) < dMyEdgeLinTol && + abs( vHoles[i].dLen - vHoles[j].dLen) < dMyEdgeLinTol && + AreSameOrOppositeVectorEpsilon( vHoles[i].frCompo.VersZ(), vHoles[j].frCompo.VersZ(), dMyEdgeLinTol)) ; + if ( bCouple) { + vtCenCen = ( vHoles[i].frCompo.Orig() - vHoles[j].frCompo.Orig()) ; + bCouple = ( vtCenCen.SqLen() > dMyEdgeLinTol * dMyEdgeLinTol) ; + if ( bCouple) { + bCouple = ( vtCenCen.Normalize() && + AreSameOrOppositeVectorEpsilon( vtCenCen, vHoles[i].frCompo.VersZ(), dMyEdgeLinTol)) ; + } + } + } + if ( bCouple) + nIndJ = j ; + } + + // Determino l'indice della curva da conservare + int nInd = i ; + // Se curva non in coppia, allora ho finito, altrimenti devo sceglierne una + if ( nIndJ != -1) { + int nIndToErase = nIndJ ; + // Recupero i due Box + BBox3d BBoxI ; vHoles[i].pCompoHole->GetLocalBBox( BBoxI) ; + BBox3d BBoxJ ; vHoles[nIndJ].pCompoHole->GetLocalBBox( BBoxJ) ; + // Recupero le Coordinate massime di ZGlob + double dZI = BBoxI.GetMax().z ; + double dZJ = BBoxJ.GetMax().z ; + // Se le 2 curve hanno ZGlob massime differente tra loro + if ( abs( dZI - dZJ) > 5. * EPS_SMALL) { + // Tengo la Curva con ZGlob massima + if ( dZJ > dZI) + swap( nInd, nIndToErase) ; + } + // Se invece le ZGlob sono circa uguali + else { + // Tengo la Curva più distante dal punto di Riferimento ( se Valido) + if ( ptRef.IsValid()) { + double dSqDistI = INFINITO, dSqDistJ = INFINITO ; + DistPointCurve( ptRef, *vHoles[i].pCompoHole).GetSqDist( dSqDistI) ; + DistPointCurve( ptRef, *vHoles[nIndJ].pCompoHole).GetSqDist( dSqDistJ) ; + if ( dSqDistJ > dSqDistI) + swap( nInd, nIndToErase) ; + } + } + // Elimino la curva non significativa delle 2 + vHoles[nIndToErase].pCompoHole.Reset() ; + } + + // Imposto Estrusione alla curva nInd-esima + Vector3d vtExtr = vHoles[nInd].frCompo.VersZ() ; + // Se Estrusione perpendicolare a Z_AX + if ( OrthoCompo( Z_AX, vtExtr).Len() > 1 - 5. * EPS_SMALL) { + // Se punto di Riferimento valido + if ( ptRef.IsValid()) { + Vector3d vtCenCen = vHoles[nInd].frCompo.Orig() - ptRef ; + vtCenCen.Normalize() ; + vHoles[nInd].pCompoHole->SetExtrusion( ( vtExtr * vtCenCen > 0.) ? vtExtr : - vtExtr) ; + } + else + vHoles[nInd].pCompoHole->SetExtrusion( vtExtr) ; + } + // Se estrusione non perpendicolare a Z_AX + else + vHoles[nInd].pCompoHole->SetExtrusion( ( vtExtr * Z_AX > 0.) ? vtExtr : - vtExtr) ; + + // Imposso Spessore alla curva nInd-esima + vHoles[nInd].pCompoHole->SetThickness( - dMyEdgeThick) ; + + // Memorizzo la curva nInd-esima + vHoleBorders.emplace_back( Release( vHoles[nInd].pCompoHole)) ; + } } return true ;