From 76d009ddbe704937ccd74ee98d71b98109f286ed Mon Sep 17 00:00:00 2001 From: DarioS Date: Tue, 2 Nov 2021 08:19:11 +0100 Subject: [PATCH] EgtGeomKernel 2.3k1 : - corretto offset di segmenti di retta singoli con estrusione - modifiche per calcolo taglio superfici TriMesh - modifiche a funzione SimplifyFacets di superfici TriMesh. --- DistPointCrvAux.cpp | 21 +- EgtGeomKernel.rc | Bin 11718 -> 11718 bytes OffsetCurve.cpp | 13 +- PolyLine.cpp | 615 ++++++++-------------------- SurfTriMesh.cpp | 15 +- SurfTriMeshBooleans.cpp | 862 ++++++++++++--------------------------- SurfTriMeshUtilities.cpp | 390 +++++++++--------- 7 files changed, 680 insertions(+), 1236 deletions(-) diff --git a/DistPointCrvAux.cpp b/DistPointCrvAux.cpp index a6ca717..2839d26 100644 --- a/DistPointCrvAux.cpp +++ b/DistPointCrvAux.cpp @@ -23,33 +23,30 @@ bool CalcMinDistPointPolyLine( const Point3d& ptP, PolyLine& PL, double dLinTol, MDCVECTOR& vApproxMin) { - double dSqDist ; - double dPar ; - double dUIni ; - double dUFin ; - Point3d ptIni ; - Point3d ptFin ; - double dMinDist ; - double dSqMinDist ; - MinDistCalc approxMin ; + vApproxMin.reserve( 4) ; + vApproxMin.clear() ; bool bFound = false ; bool bOnEnd = false ; - vApproxMin.reserve( 4) ; - vApproxMin.clear() ; + double dUIni, dUFin ; + Point3d ptIni, ptFin ; + double dMinDist, dSqMinDist ; for ( bool bLine = PL.GetFirstULine( &dUIni, &ptIni, &dUFin, &ptFin) ; bLine ; bLine = PL.GetNextULine( &dUIni, &ptIni, &dUFin, &ptFin)) { // calcolo la distanza del punto dal segmento DistPointLine dstPtLn( ptP, ptIni, ptFin) ; + double dSqDist ; if ( ! dstPtLn.GetSqDist( dSqDist)) continue ; // altro punto con la stessa minima distanza già trovata if ( bFound && abs( dSqDist - dSqMinDist) < 2 * dMinDist * dLinTol) { // salvo i dati nella struttura + MinDistCalc approxMin ; approxMin.dDist = dMinDist ; dstPtLn.GetMinDistPoint( approxMin.ptQ) ; + double dPar ; dstPtLn.GetParamAtMinDistPoint( dPar) ; approxMin.dPar = ( 1 - dPar) * dUIni + dPar * dUFin ; approxMin.dParMin = dUIni ; @@ -66,8 +63,10 @@ CalcMinDistPointPolyLine( const Point3d& ptP, PolyLine& PL, double dLinTol, MDCV dSqMinDist = dSqDist ; dMinDist = sqrt( dSqMinDist) ; // salvo i dati nella struttura + MinDistCalc approxMin ; approxMin.dDist = dMinDist ; dstPtLn.GetMinDistPoint( approxMin.ptQ) ; + double dPar ; dstPtLn.GetParamAtMinDistPoint( dPar) ; approxMin.dPar = ( 1 - dPar) * dUIni + dPar * dUFin ; approxMin.dParMin = dUIni ; diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc index 7b4fecc786c77bbcd9657ce4d39e921c69fa6d84..b11cf1870180645e26e611e6019d82a370e99fb5 100644 GIT binary patch delta 118 zcmX>WeJpyz4>m@_&A0h3Gfl1&(wY2&Q-wL3!Emyouc8f3Bn%C USS9+Tp%Pe4^I+Uuq#VKp0P|)fEC2ui delta 118 zcmX>WeJpyz4>m@F&A0h3Gfl1&(wY2&Q-wK;!Emyouc8f3Bn%C USS9+Tp%Pe4^I+Uuq#VKp0P$cXBme*a diff --git a/OffsetCurve.cpp b/OffsetCurve.cpp index ca43e19..50bc767 100644 --- a/OffsetCurve.cpp +++ b/OffsetCurve.cpp @@ -68,9 +68,20 @@ OffsetCurve::Make( const ICurve* pCrv, double dDist, int nType) { // pulisco tutto Reset() ; + // verifico se la curva è un segmento di retta + bool bIsLine = false ; + const CurveLine* pLine = GetBasicCurveLine( pCrv) ; + if ( pLine != nullptr) + bIsLine = true ; + else { + const CurveComposite* pCompo = GetBasicCurveComposite( pCrv) ; + Point3d ptStart, ptEnd ; + if ( pCompo != nullptr && pCompo->IsALine( 10 * EPS_SMALL, ptStart, ptEnd)) + bIsLine = true ; + } // verifico che la curva esista e sia piana Plane3d plPlane ; - if ( pCrv == nullptr || ! pCrv->IsFlat( plPlane, false, 10 * EPS_SMALL)) + if ( pCrv == nullptr || ! pCrv->IsFlat( plPlane, bIsLine, 10 * EPS_SMALL)) return false ; // recupero o assegno estrusione Vector3d vtExtr ; diff --git a/PolyLine.cpp b/PolyLine.cpp index 2384081..1e00cea 100644 --- a/PolyLine.cpp +++ b/PolyLine.cpp @@ -21,8 +21,8 @@ #include "GeoConst.h" #include "/EgtDev/Include/EGkPolyLine.h" #include "/EgtDev/Include/EGkPlane3d.h" -#include "/EgtDev/Include/EGkPolygon3d.h" #include "/EgtDev/Include/EGnStringUtils.h" +#include "/EgtDev/Include/EgtNumUtils.h" using namespace std ; @@ -830,12 +830,11 @@ PolyLine::MyChangeStart( int nPos) // solo per polilinee chiuse if ( ! IsClosed()) return false ; - // cancello ultimo punto ( coincide con primo) + // cancello l'ultimo punto ( coincide con il primo) m_lUPoints.pop_back() ; - // sposto la metà iniziale dei punti alla fine - for ( int i = 0 ; i < nPos ; ++ i) - m_lUPoints.splice( m_lUPoints.end(), m_lUPoints, m_lUPoints.begin()) ; - // aggiungo punto finale come copia dell'iniziale + // sposto la parte iniziale dei punti alla fine + m_lUPoints.splice( m_lUPoints.end(), m_lUPoints, m_lUPoints.begin(), next( m_lUPoints.begin(), nPos)) ; + // aggiungo il punto finale come copia dell'iniziale m_lUPoints.push_back( m_lUPoints.front()) ; return true ; @@ -1298,478 +1297,220 @@ PolyLine::Trim( const Plane3d& plPlane, bool bInVsOut) return true ; } +//---------------------------------------------------------------------------- //---------------------------------------------------------------------------- bool -ChangeStart( const Point3d& ptNewStart, PNTVECTOR& Loop) +DistPointPolyLine( const Point3d& ptP, const PolyLine& plPoly, double& dDist) { - // Cerco il tratto del loop chiuso più vicino al punto - int nMinSeg = - 1 ; - double dMinSqDinst = DBL_MAX ; - for ( int nPt = 0 ; nPt < int( Loop.size()) ; ++ nPt) { - // Estremi del segmento corrente del loop - Point3d ptSegSt = Loop[nPt] ; - Point3d ptSegEn = Loop[( nPt + 1) % int( Loop.size())] ; - // Distanza del punto dal segmento del loop - DistPointLine dDistCalc( ptNewStart, ptSegSt, ptSegEn) ; - double dSqDist ; - dDistCalc.GetSqDist( dSqDist) ; - if ( dSqDist < dMinSqDinst) { - dMinSqDinst = dSqDist ; - nMinSeg = nPt ; - } - } - // Se il punto non sta sul loop, errore - if ( dMinSqDinst > SQ_EPS_SMALL) + // La polilinea deve contenere almeno due punti + if ( plPoly.GetPointNbr() < 2) return false ; - // Verifico che il punto stia su un vertice, in tal caso non devo fare nulla - bool bOnStart = AreSamePointApprox( Loop[nMinSeg], ptNewStart) ; - bool bOnEnd = AreSamePointApprox( Loop[( nMinSeg + 1) % int( Loop.size())], ptNewStart) ; - if ( bOnStart || bOnEnd) { - if ( bOnEnd) { - ++ nMinSeg ; - if ( nMinSeg % int( Loop.size()) == 0) - return true ; - } - PNTVECTOR vTempVec ; - for ( int nPt = 0 ; nPt < nMinSeg ; ++ nPt) - vTempVec.emplace_back( Loop[nPt]) ; - int nSize = int( Loop.size()) ; - for ( int nPt = 0 ; nPt < nSize - nMinSeg ; ++ nPt) { - Loop[nPt] = Loop[nPt + nMinSeg] ; - } - for ( int nPt = 0 ; nPt < int( vTempVec.size()) ; ++ nPt) { - Loop[nPt + nSize - nMinSeg] = vTempVec[nPt] ; - } - return true ; - } - // Ridimensiono il loop - Loop.resize( Loop.size() + 1) ; - // Copio i primi punti - PNTVECTOR LoopTemp ; - for ( int nPt = 0 ; nPt <= nMinSeg ; ++ nPt) - LoopTemp.emplace_back( Loop[nPt]) ; - // Aggiungo il nuovo punto all'inizio - Loop[0] = ptNewStart ; - // Sposto gli ultimi in testa - int nLastPointNum = int( Loop.size()) - 1 - nMinSeg ; - for ( int nPt = 1 ; nPt <= nLastPointNum ; ++ nPt) { - Loop[nPt] = Loop[nPt + nMinSeg] ; - } - // Porto i primi in fondo - for ( int nPt = 0 ; nPt < int( LoopTemp.size()) ; ++ nPt) { - Loop[nPt + nLastPointNum] = LoopTemp[nPt] ; + // Ciclo sui punti della polilinea + dDist = INFINITO ; + Point3d ptStart, ptEnd ; + plPoly.GetFirstPoint( ptStart) ; + while ( plPoly.GetNextPoint( ptEnd)) { + // distanza del punto dal segmento della polilinea + DistPointLine PointLineDistCalc( ptP, ptStart, ptEnd) ; + double dPlDist ; + PointLineDistCalc.GetDist( dPlDist) ; + if ( dPlDist < dDist) + dDist = dPlDist ; + // assegno nuovo inizio + ptStart = ptEnd ; } return true ; } //---------------------------------------------------------------------------- bool -SplitAtPoint( const Point3d& ptStop, const PNTVECTOR& Loop, PNTVECTOR& Loop1, PNTVECTOR& Loop2) +IsPointInsidePolyLine( const Point3d& ptP, const PolyLine& plPoly, double dToler) { - // Cerco il tratto del loop chiuso più vicino al punto - int nMinSeg = -1 ; - double dMinSqDinst = DBL_MAX ; - for ( int nPt = 0 ; nPt < int( Loop.size()) ; ++ nPt) { - // Estremi del segmento corrente del loop - Point3d ptSegSt = Loop[nPt] ; - Point3d ptSegEn = Loop[( nPt + 1) % int(Loop.size())] ; - // Distanza del punto dal segmento del loop - DistPointLine dDistCalc( ptStop, ptSegSt, ptSegEn) ; - double dSqDist ; - dDistCalc.GetSqDist( dSqDist) ; - if ( dSqDist < dMinSqDinst) { - dMinSqDinst = dSqDist ; - nMinSeg = nPt ; - } - } - // Se il punto non sta sul loop, errore - if ( dMinSqDinst > SQ_EPS_SMALL) + // La polilinea deve essere chiusa e piatta, altrimenti non ha senso parlare di interno + Plane3d plPlane ; + double dArea ; + if ( ! plPoly.IsClosedAndFlat( plPlane, dArea, 10 * EPS_SMALL)) return false ; - // Verifico che il punto stia su un vertice, in tal caso non devo aggiungerlo - bool bFirst = AreSamePointApprox( Loop[nMinSeg], ptStop) ; - bool bLast = AreSamePointApprox( Loop[( nMinSeg + 1) % int( Loop.size())], ptStop) ; - // Se il punto è sul vertice finale del segmento, aggiungo il vertice alla lista da inglobare al primo loop - if ( bLast) - ++ nMinSeg ; - // Inglobo fino a nSeg nel primo loop - for ( int nPt = 0 ; nPt <= nMinSeg ; ++ nPt) - Loop1.emplace_back( Loop[nPt]) ; - // Se il punto è interno al segmento, lo inglobo in entrambi i loop - if ( ! ( bFirst || bLast)) { - Loop1.emplace_back( ptStop) ; - Loop2.emplace_back( ptStop) ; - } - else { - Loop2.emplace_back( Loop[nMinSeg]) ; - } - // Inglobo gli ultimi vertici in Loop2 - for ( int nPt = nMinSeg + 1 ; nPt < int( Loop.size()) ; ++ nPt) - Loop2.emplace_back( Loop[nPt]) ; - Loop2.emplace_back( Loop[0]) ; - - return true ; -} - -//---------------------------------------------------------------------------- -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 > 4 * SQ_EPS_SMALL) + // Impongo l'orientamento CCW + if ( dArea < 0) + plPlane.Invert() ; + // Il punto deve giacere nel piano della polilinea + if ( ! PointInPlaneEpsilon( ptP, plPlane, 10 * 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 -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 > 4 * 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 ; -} - -//---------------------------------------------------------------------------- -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 ; + // Riferimento alla lista dei punti + PNTULIST& List = const_cast( plPoly).GetUPointList() ; + // Ciclo sui segmenti della polilinea per cercare il segmento più vicino al punto + double dMinSqDist = SQ_INFINITO ; 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) ; + auto itMinDistEnd = List.end() ; + auto itStart = List.begin() ; + auto itEnd = next( itStart) ; + for ( ; itEnd != List.end() ; ++ itStart, ++ itEnd) { + // Distanza del punto dal segmento corrente + DistPointLine dDistCalc( ptP, itStart->first, itEnd->first) ; double dSqDist ; - dDistCalc.GetSqDist( dSqDist) ; - if ( dSqDist < dMinSqDist) { + if ( dDistCalc.GetSqDist( dSqDist) && dSqDist < dMinSqDist) { dMinSqDist = dSqDist ; dDistCalc.GetMinDistPoint( ptMinDist) ; - itMinDistSt = itSt ; + itMinDistEnd = itEnd ; } } - // 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 ; - } + // Determino tangente di riferimento + Vector3d vtTang ; + // se minima distanza nell'estremo iniziale del segmento + if ( AreSamePointApprox( ptMinDist, prev( itMinDistEnd)->first)) { + // direzione del segmento + Vector3d vtCurrTg = itMinDistEnd->first - prev( itMinDistEnd)->first ; + vtCurrTg.Normalize() ; + // direzione del segmento precedente + Vector3d vtPrevTg ; + if ( prev( itMinDistEnd) != List.begin()) + vtPrevTg = prev( itMinDistEnd)->first - prev( itMinDistEnd, 2)->first ; + else + vtPrevTg = prev( itMinDistEnd)->first - prev( List.rbegin())->first ; + vtPrevTg.Normalize() ; + // tangente media + vtTang = vtPrevTg + vtCurrTg ; + vtTang.Normalize() ; } - // 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 ; - } + // se altrimenti minima distanza nell'estremo finale del segmento + else if ( AreSamePointApprox( ptMinDist, itMinDistEnd->first)) { + // direzione del segmento + Vector3d vtCurrTg = itMinDistEnd->first - prev( itMinDistEnd)->first ; + vtCurrTg.Normalize() ; + // direzione del segmento successivo + Vector3d vtNextTg ; + if ( next( itMinDistEnd) != List.end()) + vtNextTg = next( itMinDistEnd)->first - itMinDistEnd->first ; + else + vtNextTg = next( List.begin())->first - itMinDistEnd->first ; + vtNextTg.Normalize() ; + // tangente media + vtTang = vtCurrTg + vtNextTg ; + vtTang.Normalize() ; } - // Punto di minima distanza interno al segmeno + // altrimenti minima distanza con l'interno 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 ; + vtTang = itMinDistEnd->first - prev( itMinDistEnd)->first ; } - return false ; + // Determino la posizione del punto + Vector3d vtDiff = ptP - ptMinDist ; + Vector3d vtOut = vtTang ^ plPlane.GetVersN() ; + vtOut.Normalize() ; + return ( vtDiff * vtOut < -dToler) ; } //---------------------------------------------------------------------------- bool -DistPointPolyLine( const Point3d& ptP, const PolyLine& plPoly, double& dPointPolyLineDist) +GetPointParamOnPolyLine( const Point3d& ptP, const PolyLine& plPoly, double dToler, double& dPar) { - if ( plPoly.GetPointNbr() == 0) + // La polilinea deve contenere almeno due punti + if ( plPoly.GetPointNbr() < 2) 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 ; -} - -//---------------------------------------------------------------------------- -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) ; + // Ciclo sui punti della polilinea + int nSeg = -1 ; + double dMinSqDist = SQ_INFINITO ; + double dMinPar = -1 ; + Point3d ptStart, ptEnd ; + plPoly.GetFirstPoint( ptStart) ; + while ( plPoly.GetNextPoint( ptEnd)) { + // aggiorno l'indice + ++ nSeg ; + // distanza del punto dal segmento della polilinea + DistPointLine dDistCalc( ptP, ptStart, ptEnd) ; double dSqDist ; - dDistCalc.GetSqDist( dSqDist) ; - if ( dSqDist < dMinSqDist) { + if ( dDistCalc.GetSqDist( dSqDist) && dSqDist < dMinSqDist) { dMinSqDist = dSqDist ; - itMinDistSt = itSt ; + double dSegPar ; + dDistCalc.GetParamAtMinDistPoint( dSegPar) ; + dMinPar = nSeg + dSegPar ; + } + // assegno nuovo inizio + ptStart = ptEnd ; + } + // Il punto è sulla linea se la sua distanza rispetta la tolleranza + return ( dMinSqDist < dToler * dToler) ; +} + +//---------------------------------------------------------------------------- +bool +ChangePolyLineStart( PolyLine& plPoly, const Point3d& ptNewStart, double dToler) +{ + // La polilinea deve essere chiusa + if ( ! plPoly.IsClosed()) + return false ; + // Riferimento alla lista dei punti + PNTULIST& LoopList = const_cast( plPoly).GetUPointList() ; + // Ciclo sui segmenti della polilinea per cercare il segmento più vicino al punto + double dMinSqDist = SQ_INFINITO ; + auto itMinDistEnd = LoopList.end() ; + auto itStart = LoopList.begin() ; + auto itEnd = next( itStart) ; + for ( ; itEnd != LoopList.end() ; ++ itStart, ++ itEnd) { + // Distanza del punto dal segmento corrente + DistPointLine dDistCalc( ptNewStart, itStart->first, itEnd->first) ; + double dSqDist ; + if ( dDistCalc.GetSqDist( dSqDist) && dSqDist < dMinSqDist) { + dMinSqDist = dSqDist ; + itMinDistEnd = itEnd ; } } - // Se il punto non sta sul loop, lo segnalo. - if ( dMinSqDist > 4 * SQ_EPS_SMALL) + // Se il punto non sta sulla polilinea, non ha senso cambiare l'inizio + if ( dMinSqDist > dToler * dToler) 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) ; - } + // Se il punto non coincide con un vertice, lo aggiungo + auto itNewStart = LoopList.end() ; + if ( AreSamePointApprox( ptNewStart, prev( itMinDistEnd)->first)) + itNewStart = prev( itMinDistEnd) ; + else if ( AreSamePointApprox( ptNewStart, itMinDistEnd->first)) + itNewStart = itMinDistEnd ; + else + itNewStart = LoopList.emplace( itMinDistEnd, ptNewStart, 0) ; + // Cancello l'ultimo punto ( coincide con il primo) + LoopList.pop_back() ; + // Sposto la parte iniziale dei punti alla fine + LoopList.splice( LoopList.end(), LoopList, LoopList.begin(), itNewStart) ; + // Aggiungo il punto finale come copia dell'iniziale + LoopList.push_back( LoopList.front()) ; + return true ; } //---------------------------------------------------------------------------- bool -AddPolyLineToPolyLine( PolyLine& Poly, PolyLine& PolyToAdd) +SplitPolyLineAtPoint( const PolyLine& plPoly, const Point3d& ptP, double dToler, PolyLine& plPoly1, PolyLine& plPoly2) { - // Se la PolyLine a cui devo aggiungere l'altra è chiusa, non posso aggiungere nulla. - if ( Poly.IsClosed()) + // La polilinea deve contenere almeno due punti + if ( plPoly.GetPointNbr() < 2) 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) ; + // Riferimento alla lista dei punti + const PNTULIST& LoopList = const_cast( plPoly).GetUPointList() ; + // Ciclo sui segmenti della polilinea per cercare il segmento più vicino al punto + double dMinSqDist = SQ_INFINITO ; + auto itMinDistEnd = LoopList.end() ; + auto itStart = LoopList.begin() ; + auto itEnd = next( itStart) ; + for ( ; itEnd != LoopList.end() ; ++ itStart, ++ itEnd) { + // Distanza del punto dal segmento corrente + DistPointLine dDistCalc( ptP, itStart->first, itEnd->first) ; + double dSqDist ; + if ( dDistCalc.GetSqDist( dSqDist) && dSqDist < dMinSqDist) { + dMinSqDist = dSqDist ; + itMinDistEnd = itEnd ; + } } + // Se il punto non sta sulla polilinea, non ha senso spezzare + if ( dMinSqDist > dToler * dToler) + return false ; + // Copio i punti opportuni nella prima parte + PNTULIST& LoopList1 = plPoly1.GetUPointList() ; + for ( auto it = LoopList.begin() ; it != itMinDistEnd ; ++ it) + LoopList1.emplace_back( it->first, it->second) ; + plPoly1.AddUPoint( 0, ptP) ; + // Copio i punti opportuni nella seconda parte + PNTULIST& LoopList2 = plPoly2.GetUPointList() ; + for ( auto it = itMinDistEnd ; it != LoopList.end() ; ++ it) + LoopList2.emplace_back( it->first, it->second) ; + plPoly2.AddUPoint( 0, ptP, false) ; return true ; } diff --git a/SurfTriMesh.cpp b/SurfTriMesh.cpp index bdff31f..54a6022 100644 --- a/SurfTriMesh.cpp +++ b/SurfTriMesh.cpp @@ -3701,7 +3701,11 @@ SurfTriMesh::Cut( const Plane3d& plPlane, bool bSaveOnEq) if ( m_nStatus != OK) return false ; - // eseguo il taglio con il metodo delle faccette + // recupero il numero originale di triangoli e di facce + int nTriaOriCnt = GetTriangleCount() ; + int nFacetOriCnt = GetFacetCount() ; + + // eseguo il taglio con il metodo delle faccette o dei triangoli (per ora solo coi triangoli) bool bModif = false ; if ( true || ! CutByFacets( plPlane, bSaveOnEq, bModif)) { bModif = false ; @@ -3711,13 +3715,16 @@ SurfTriMesh::Cut( const Plane3d& plPlane, bool bSaveOnEq) // se effettuate modifiche if ( bModif) { - // aggiorno tutto + // aggiorno tutto if ( ! AdjustVertices() || ! DoCompacting()) return false ; + // se superficie originale a facce, cerco di semplificarle + if ( nFacetOriCnt < 200 || double( nTriaOriCnt) / nFacetOriCnt > 4) { + if ( ! SimplifyFacets( 500.0)) + LOG_ERROR( GetEGkLogger(), "Error in SimplifyFacets of Stm::Cut") + } } - SimplifyFacets( 20) ; - return true ; } diff --git a/SurfTriMeshBooleans.cpp b/SurfTriMeshBooleans.cpp index cef2380..46e6c7d 100644 --- a/SurfTriMeshBooleans.cpp +++ b/SurfTriMeshBooleans.cpp @@ -159,513 +159,181 @@ AddChainToChain( const Chain& ChainToAdd, PNTVECTOR& OrigChain) } //---------------------------------------------------------------------------- -//bool -//SurfTriMesh::GeneralizedCut( const ICurve& cvCurve, bool bSaveOnEq) -//{ -// // La superficie deve essere valida -// if ( m_nStatus != OK) -// return false ; -// // La curva deve essere valida e chiusa, il vettore estrusione deve essere non nullo -// Vector3d vtExtr ; -// if ( ! cvCurve.GetExtrusion( vtExtr) || vtExtr.IsSmall() || ! cvCurve.IsClosed()) -// return false ; -// // Approssimo la curva con segmenti -// CurveComposite cvCompo ; -// PolyLine PL ; -// if ( ! cvCurve.ApproxWithLines( LIN_TOL_MIN, ANG_TOL_STD_DEG, ICurve::APL_STD, PL) || ! cvCompo.FromPolyLine( PL)) -// return false ; -// // Appiattisco la polilinea nel piano perpendicolare all'estrusione -// Frame3d frCurve ; -// Point3d ptStart ; cvCompo.GetStartPoint( ptStart) ; -// frCurve.Set( ptStart, vtExtr) ; -// cvCompo.ToLoc( frCurve) ; -// if ( ! cvCompo.Scale( GLOB_FRM, 1, 1, 0)) -// return false ; -// double dArea ; -// cvCompo.GetAreaXY( dArea) ; -// BBox3d b3Crv ; -// cvCompo.GetLocalBBox( b3Crv) ; -// cvCompo.ToGlob( frCurve) ; -// // Assegno il senso di rotazione della curva (visto dalla punta del vettore estrusione) -// bool bCCW = ( dArea > 0) ; -// // Recupero Bounding-box della trimesh -// BBox3d b3SurfBox ; -// GetLocalBBox( b3SurfBox) ; -// // Trovo minima e massima distanza dei vertici del bounding-box della TriMesh dal piano della curva -// b3SurfBox.ToLoc( frCurve) ; -// Point3d ptMin, ptMax ; -// b3SurfBox.GetMinMax( ptMin, ptMax) ; -// Vector3d vtMax = ( ptMax.z + 10) * vtExtr ; -// Vector3d vtMin = ( ptMin.z - 10) * vtExtr ; -// -// // Ciclo sui triangoli -// bool bModif = false ; -// int nNumTria = GetTriangleSize() ; -// for ( int nT = 0 ; nT < nNumTria ; ++ nT) { -// // Recupero il triangolo -// Triangle3d trTria ; -// if ( ! GetTriangle( nT, trTria)) -// continue ; -// // Box del triangolo nel riferimento locale della curva -// BBox3d b3Tria ; -// trTria.GetLocalBBox( b3Tria) ; -// b3Tria.ToLoc( frCurve) ; -// // Se il box del triangolo non interseca quello locale della curva -// if ( ! b3Crv.OverlapsXY( b3Tria)) { -// // Se la parte da conservare è quella all'interno della curva, elimino il triangolo -// if ( bCCW) { -// RemoveTriangle( nT) ; -// bModif = true ; -// } -// continue ; -// } -// // Determino il numero di vertici del triangolo che cadono all'interno della curva -// int nVertInside = 0 ; -// for ( int nV = 0 ; nV < 3 ; ++ nV) { -// // Determino se il vertice cade dentro la curva -// DistPointCurve dstPC( trTria.GetP( nV), cvCompo) ; -// int nSide ; -// dstPC.GetSideAtMinDistPoint( 0, vtExtr, nSide) ; -// if ( nSide == MDS_LEFT || nSide == MDS_ON) -// ++ nVertInside ; -// } -// // Vettore di catene di punti -// CHAINVECTOR vChain ; -// // Ciclo sui segmenti -// int nChainCnt = 0 ; -// bool bChain = false ; -// Point3d ptChSt, ptChEn ; -// const ICurve* pCrv = cvCompo.GetFirstCurve() ; -// while ( pCrv != nullptr) { -// // estremi del segmento -// Point3d ptSt ; pCrv->GetStartPoint( ptSt) ; -// Point3d ptEn ; pCrv->GetEndPoint( ptEn) ; -// // Intersezione fra il rettangolo (ottenuto dall'estrusione del segmento corrente) e il triangolo -// Point3d ptSegSt, ptSegEn ; -// int nInt = IntersRectangleTriangle( ptSt + vtMin, ptEn - ptSt, vtMax - vtMin, trTria, ptSegSt, ptSegEn) ; -// if ( nInt != 0) { -// // Creo nuova catena se non c'è già o se discontinuità -// if ( ! bChain || ( ! AreSamePointApprox( ptSegSt, ptChEn) && ! AreSamePointApprox( ptSegEn, ptChSt))) { -// ++ nChainCnt ; -// vChain.resize( nChainCnt) ; -// bChain = false ; -// } -// // Assegno i dati di intersezione -// IntSegment CurInters ; -// if ( nInt == 2) { -// CurInters.ptSt = ptSegSt ; -// CurInters.ptEn = ptSegEn ; -// CurInters.bDegenerate = false ; -// } -// else { -// CurInters.ptSt = ptSegSt ; -// CurInters.ptEn = ptSegSt ; -// CurInters.bDegenerate = true ; -// } -// CurInters.vtOuter = ( ptEn - ptSt) ^ vtExtr ; -// CurInters.vtOuter.Normalize() ; -// // Inserisco nella catena -// if ( ! bChain) { -// vChain[nChainCnt - 1].emplace_back( CurInters) ; -// ptChSt = CurInters.ptSt ; -// ptChEn = CurInters.ptEn ; -// } -// else if ( AreSamePointApprox( ptSegSt, ptChEn)) { -// vChain[nChainCnt - 1].emplace_back( CurInters) ; -// ptChEn = CurInters.ptEn ; -// } -// else { -// vChain[nChainCnt - 1].insert( vChain[nChainCnt - 1].begin(), CurInters) ; -// ptChSt = CurInters.ptSt ; -// } -// bChain = true ; -// } -// else { -// bChain = false ; -// } -// pCrv = cvCompo.GetNextCurve() ; -// } -// if ( nChainCnt == 1 /* && vChain[0].size() == 1 && vChain[0][0].bDegenerate*/) { -// bool bAllDegenerate = true ; -// for ( int n = 0 ; n < int( vChain[0].size()) && bAllDegenerate ; ++ n) { -// bAllDegenerate = vChain[0][n].bDegenerate ; -// } -// if ( bAllDegenerate) { -// if ( nVertInside >= 2) -// nVertInside = 3 ; -// else -// nVertInside = 0 ; -// vChain.clear() ; -// nChainCnt = 0 ; -// } -// } -// // unisco eventuali catene estreme che sono parte di una stessa catena -// if ( nChainCnt > 1) { -// if ( AreSamePointApprox( vChain[0].front().ptSt, vChain[nChainCnt-1].back().ptEn)) { -// vChain[0].insert( vChain[0].begin(), vChain[nChainCnt-1].begin(), vChain[nChainCnt-1].end()) ; -// vChain.pop_back() ; -// -- nChainCnt ; -// } -// else if ( AreSamePointApprox( vChain[0].back().ptEn, vChain[nChainCnt-1].front().ptSt)) { -// vChain[0].insert( vChain[0].end(), vChain[nChainCnt-1].begin(), vChain[nChainCnt-1].end()) ; -// vChain.pop_back() ; -// -- nChainCnt ; -// } -// } -// // semplifico catene formate da punti degeneri -// for ( int nCh = 0 ; nCh < nChainCnt ; ++ nCh) { -// if ( vChain[nCh].size() == 2 && ( vChain[nCh][0].bDegenerate || vChain[nCh][1].bDegenerate)) { -// vChain[nCh][0].ptEn = vChain[nCh][1].ptEn ; -// vChain[nCh][0].vtOuter = ( vChain[nCh][0].bDegenerate ? vChain[nCh][1].vtOuter : vChain[nCh][0].vtOuter) ; -// vChain[nCh][0].bDegenerate = AreSamePointApprox( vChain[nCh][0].ptSt, vChain[nCh][0].ptEn) ; -// vChain[nCh].resize( 1) ; -// } -// } -// // Elimino la seconda copia di catene doppie -// for ( int nI = 0 ; nI < nChainCnt ; ++ nI) { -// for ( int nJ = nI + 1 ; nJ < nChainCnt ; ++ nJ) { -// if ( vChain[nI].size() == vChain[nJ].size()) { -// bool bSame = true ; -// for ( int nK = 0 ; nK < int( vChain[nI].size()) ; ++ nK) { -// if ( ! AreSamePointApprox( vChain[nI][nK].ptSt, vChain[nJ][nK].ptSt) || -// ! AreSamePointApprox( vChain[nI][nK].ptEn, vChain[nJ][nK].ptEn)) { -// bSame = false ; -// break ; -// } -// } -// if ( bSame) { -// vChain.erase( vChain.begin() + nJ) ; -// -- nChainCnt ; -// -- nJ ; -// } -// } -// } -// } -// -// // Fra le catene trovate separo le aperte dalle chiuse -// int nDegenerateChainNum = 0 ; -// INTVECTOR vnDegVec ; -// CHAINVECTOR cvClosedChain ; -// CHAINVECTOR cvOpenChain ; -// for ( int nL = 0 ; nL < int( vChain.size()) ; ++ nL) { -// bool bChainDegenerate = false ; -// if ( vChain[nL].size() == 1 && AreSamePointApprox( vChain[nL][0].ptSt, vChain[nL][0].ptEn)) { -// bChainDegenerate = true ; -// } -// -// if ( bChainDegenerate) -// ++ nDegenerateChainNum ; -// int nCurLoopLast = max( int( vChain[nL].size()) - 1, 0) ; -// if ( ( ! bChainDegenerate) && AreSamePointApprox( vChain[nL][0].ptSt, vChain[nL][nCurLoopLast].ptEn)) -// cvClosedChain.emplace_back( vChain[nL]) ; -// else { -// cvOpenChain.emplace_back( vChain[nL]) ; -// if ( bChainDegenerate) -// vnDegVec.emplace_back( 0) ; -// else -// vnDegVec.emplace_back( 1) ; -// } -// } -// for ( auto it = cvClosedChain.begin() ; it != cvClosedChain.end() ; ) { -// if ( int( it->size()) < 3) -// it = cvClosedChain.erase( it) ; -// else -// ++ it ; -// } -// // Se più di una catena chiusa oppure catene chiuse e aperte, errore -// if ( cvClosedChain.size() > 1 || -// ( cvClosedChain.size() > 0 && int( cvOpenChain.size()) > nDegenerateChainNum)) -// return false ; -// -// // Se c'è una catena chiusa -// if ( cvClosedChain.size() == 1) { -// // Ne ricavo una PolyLine -// PolyLine plInLoop ; -// for ( int nLine = 0 ; nLine < int( cvClosedChain[0].size()) ; ++ nLine) { -// plInLoop.AddUPoint( 0., cvClosedChain[0][nLine].ptSt) ; -// plInLoop.AddUPoint( 0., cvClosedChain[0][nLine].ptEn) ; -// } -// // I tre vertici sono dalla parte interna della curva (triangolo con buco) -// if ( ! bCCW) { -// // Rimuovo il triangolo corrente -// RemoveTriangle( nT) ; -// // Definisco il loop esterno (è il triangolo) -// PolyLine plExtLoop ; -// plExtLoop.AddUPoint( 0., trTria.GetP( 0)) ; -// plExtLoop.AddUPoint( 0., trTria.GetP( 1)) ; -// plExtLoop.AddUPoint( 0., trTria.GetP( 2)) ; -// plExtLoop.AddUPoint( 0., trTria.GetP( 0)) ; -// // Eseguo triangolazione -// POLYLINEVECTOR vPL ; -// vPL.emplace_back( plExtLoop) ; -// vPL.emplace_back( plInLoop) ; -// PNTVECTOR vPt ; -// INTVECTOR vTr ; -// if ( Triangulate().Make( vPL, 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]]) } ; -// AddTriangle( nNewId) ; -// bModif = true ; -// } -// } -// } -// // Se nessun vertice dalla parte interna della curva (rimane solo l'area della curva) -// else { -// // Rimuovo il triangolo corrente -// RemoveTriangle( nT) ; -// // Eseguo triangolazione -// PNTVECTOR vPt ; -// INTVECTOR vTr ; -// if ( Triangulate().Make( plInLoop, 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]]) } ; -// AddTriangle( nNewId) ; -// bModif = true ; -// } -// } -// } -// } -// -// // Loop aperti, devo chiuderli -// else if ( cvOpenChain.size() > 0) { -// -// // Creo il loop chiuso padre di tutti, il perimetro del triangolo. -// // Questo viene diviso in sotto-loop chiusi mediante quelli aperti. -// // I loop chiusi trovati precedentemente sono interni a uno dei sotto-loop -// // chiusi di cui è formato il perimetro. -// PNTVECTOR cvFirstLoop ; -// cvFirstLoop.emplace_back( trTria.GetP( 0)) ; -// cvFirstLoop.emplace_back( trTria.GetP( 1)) ; -// cvFirstLoop.emplace_back( trTria.GetP( 2)) ; -// -// PNTMATRIX cvBoundClosedLoopVec ; -// cvBoundClosedLoopVec.emplace_back(cvFirstLoop); -// BOOLVECTOR vbInOut ; -// vbInOut.push_back( true) ; -// // Divido il loop di partenza in sotto-loop -// while ( cvOpenChain.size() > 0) { -// int nLastOpenLoopN = int( cvOpenChain.size()) - 1 ; -// if ( vnDegVec[nLastOpenLoopN] == 1) { -// for ( int nLoop = 0 ; nLoop < int( cvBoundClosedLoopVec.size()) ; ++ nLoop) { -// // Estremi del loop aperto -// int nLastOpenLoopPoint = max( int( cvOpenChain[nLastOpenLoopN].size()) - 1, 0) ; -// Point3d ptOpenLoopStP = cvOpenChain[nLastOpenLoopN][0].ptSt ; -// Point3d ptOpenLoopEnP = cvOpenChain[nLastOpenLoopN][nLastOpenLoopPoint].ptEn ; -// PNTVECTOR Loop1, Loop2 ; -// bool bChangedStart = ChangeStart( ptOpenLoopStP, cvBoundClosedLoopVec[nLoop]) ; -// bool bSplitted = SplitAtPoint( ptOpenLoopEnP, cvBoundClosedLoopVec[nLoop], Loop1, Loop2) ; -// if ( ! ( bChangedStart && bSplitted)) -// continue ; -// Chain cvCounterChain ; -// for ( int nPt = int( cvOpenChain[nLastOpenLoopN].size()) - 1 ; nPt >= 0 ; -- nPt) { -// IntSegment CurSeg ; -// CurSeg.ptSt = cvOpenChain[nLastOpenLoopN][nPt].ptEn ; -// CurSeg.ptEn = cvOpenChain[nLastOpenLoopN][nPt].ptSt ; -// CurSeg.vtOuter = - cvOpenChain[nLastOpenLoopN][nPt].vtOuter ; -// CurSeg.bDegenerate = cvOpenChain[nLastOpenLoopN][nPt].bDegenerate ; -// cvCounterChain.emplace_back( CurSeg) ; -// } -// bool bAdded1 = AddChainToChain( cvCounterChain, Loop1) ; -// bool bAdded2 = AddChainToChain( cvOpenChain[nLastOpenLoopN], Loop2) ; -// if ( ! ( bAdded1 && bAdded2)) -// continue ; -// // Aggiungo i nuovi loop nel vettore -// int nCurSize = int( cvBoundClosedLoopVec.size()) ; -// cvBoundClosedLoopVec.resize( nCurSize + 1) ; -// vbInOut.resize( nCurSize + 1) ; -// for ( int nCL = nCurSize - 1 ; nCL > nLoop ; -- nCL) { -// cvBoundClosedLoopVec[nCL + 1] = cvBoundClosedLoopVec[nCL] ; -// vbInOut[nCL + 1] = vbInOut[nCL] ; -// } -// Vector3d vtTest = Loop1[1] - Loop1[0] ; -// vtTest.Normalize() ; -// bool bSecondInside = vtTest * cvOpenChain[nLastOpenLoopN][0].vtOuter < 0. ; -// cvBoundClosedLoopVec[nLoop] = Loop1 ; -// cvBoundClosedLoopVec[nLoop + 1] = Loop2 ; -// vbInOut[nLoop] = !true;//bSecondInside ; -// vbInOut[nLoop + 1] = !false;// !bSecondInside; -// ++ nLoop ; -// } -// } -// // Degenere -// else { -// Point3d ptProva = 0.5 * ( cvOpenChain[nLastOpenLoopN][0].ptSt + cvOpenChain[nLastOpenLoopN][0].ptEn) ; -// Vector3d vtVecProva = cvOpenChain[nLastOpenLoopN][0].vtOuter ; -// vtVecProva.Normalize( EPS_ZERO) ; -// for ( int nLoop = 0 ; nLoop < int( cvBoundClosedLoopVec.size()) ; ++ nLoop) { -// // Cerco se esistono dei tratti del loop chiuso corrente che sono -// // toccati dagli estremi del loop aperto corrente -// int nCvFirst = -1 ; -// int nCvSecond = -1 ; -// for ( int nLine = 0 ; nLine < int( cvBoundClosedLoopVec[nLoop].size()) && nCvSecond == -1 ; ++ nLine) { -// // Estremi del segmento corrente del loop chiuso corrente -// Point3d ptSegSt = cvBoundClosedLoopVec[nLoop][nLine] ; -// Point3d ptSegEn = cvBoundClosedLoopVec[nLoop][( nLine + 1) % int( cvBoundClosedLoopVec[nLoop].size())] ; -// // Vettore congiungente i su definiti punti -// Vector3d vtClosedLoopSeg = ptSegEn - ptSegSt ; -// vtClosedLoopSeg.Normalize() ; -// // Vedo se gli estremi del loop aperto stanno su un segmento del chiuso -// DistPointLine DistCalc( ptProva, ptSegSt, ptSegEn) ; -// double dSqDist ; -// DistCalc.GetSqDist( dSqDist) ; -// if ( dSqDist < 2 * SQ_EPS_SMALL) { -// if ( nCvFirst == -1) -// nCvFirst = nLine ; -// else -// nCvSecond = nLine ; -// } -// } -// -// if ( nCvFirst != nCvSecond && nCvSecond != -1) { -// // li ordino in senso crescente -// if ( nCvFirst > nCvSecond) -// swap( nCvFirst, nCvSecond) ; -// // punto medio tra primo e secondo -// int nCount = 0 ; -// Point3d ptM12 ; -// for ( int i = nCvFirst + 1 ; i <= nCvSecond ; ++ i) { -// ptM12 += cvBoundClosedLoopVec[nLoop][i] ; -// ++ nCount ; -// } -// ptM12 /= nCount ; -// // Distanza quadrata media dei punti tra primo e secondo dal baricentro -// double dVar12 = 0. ; -// for ( int i = nCvFirst + 1 ; i <= nCvSecond ; ++ i) { -// dVar12 += ( cvBoundClosedLoopVec[nLoop][i] - ptM12) * ( cvBoundClosedLoopVec[nLoop][i] - ptM12) ; -// } -// dVar12 /= nCount ; -// // punto medio fra secondo e primo -// nCount = 0 ; -// Point3d ptM21 ; -// for ( int i = nCvSecond + 1 ; i % int( cvBoundClosedLoopVec[nLoop].size()) ; ++ i) { -// ptM21 += cvBoundClosedLoopVec[nLoop][i] ; -// ++ nCount ; -// } -// for ( int i = 0 ; i <= nCvFirst ; ++ i) { -// ptM21 += cvBoundClosedLoopVec[nLoop][i] ; -// ++ nCount ; -// } -// ptM21 /= nCount ; -// // Distanza quadrata media dei punti tra secondo e primo dal baricentro -// double dVar21 = 0. ; -// for ( int i = nCvSecond ; i < i % int( cvBoundClosedLoopVec[nLoop].size()) ; ++ i) { -// dVar21 += ( cvBoundClosedLoopVec[nLoop][i] - ptM21) * ( cvBoundClosedLoopVec[nLoop][i] - ptM21) ; -// ++ nCount ; -// } -// for ( int i = 0 ; i <= nCvFirst ; ++ i) { -// dVar21 += ( cvBoundClosedLoopVec[nLoop][i] - ptM21) * ( cvBoundClosedLoopVec[nLoop][i] - ptM21) ; -// ++ nCount ; -// } -// dVar21 /= nCount ; -// // elimino i punti dalla parte non valida -// if ( dVar12 > dVar21) { -// // assegno i nuovi valori -// cvBoundClosedLoopVec[nLoop][nCvFirst] = ptProva ; -// cvBoundClosedLoopVec[nLoop][( nCvSecond + 1) % int(cvBoundClosedLoopVec[nLoop].size())] = ptProva ; -// // numero totale di punti -// int nPntTot = int( cvBoundClosedLoopVec[nLoop].size()); -// // elimino i punti superflui dopo -// for ( int i = nPntTot - 1 ; i > nCvSecond + 1 ; -- i) -// cvBoundClosedLoopVec[nLoop].pop_back() ; -// // elimino i punti superflui prima -// for ( int i = 0 ; i < nCvFirst ; ++ i) -// cvBoundClosedLoopVec[nLoop].erase( cvBoundClosedLoopVec[nLoop].begin()) ; -// // verifico se questo punto è dalla parte valida o no -// bool bC12 = ( ( ptM12 - ptProva) * vtVecProva < 0) ; -// vbInOut[nLoop] = bC12 ; -// } -// else { -// // assegno i nuovi valori -// cvBoundClosedLoopVec[nLoop][nCvFirst + 1] = ptProva ; -// cvBoundClosedLoopVec[nLoop][nCvSecond] = ptProva ; -// // elimino i punti superflui intermedi -// for ( int i = nCvFirst + 2 ; i < nCvSecond ; ++ i) -// cvBoundClosedLoopVec[nLoop].erase( cvBoundClosedLoopVec[nLoop].begin() + nCvFirst + 2) ; -// // verifico se questo punto è dalla parte valida o no -// bool bC21 = ( ( ptM21 - ptProva) * vtVecProva < 0) ; -// vbInOut[nLoop] = bC21 ; -// } -// } -// } -// } -// vnDegVec.resize( nLastOpenLoopN) ; -// cvOpenChain.resize( nLastOpenLoopN) ; -// } -// // Rimuovo il triangolo corrente -// RemoveTriangle( nT) ; -// // Trasformo i loop compositi in loop polyline -// POLYLINEVECTOR vplPolyVec ; -// vplPolyVec.resize( cvBoundClosedLoopVec.size()) ; -// for ( int nLoop = 0 ; nLoop < int( vplPolyVec.size()) ; ++ nLoop) { -// for ( int nLine = 0 ; nLine < int( cvBoundClosedLoopVec[nLoop].size()) ; ++ nLine) { -// vplPolyVec[nLoop].AddUPoint( 0., cvBoundClosedLoopVec[nLoop][nLine]) ; -// } -// vplPolyVec[nLoop].AddUPoint( 0., cvBoundClosedLoopVec[nLoop][0]) ; -// if ( vbInOut[nLoop]) { -// // Eseguo triangolazione -// Triangulate CreateTriangulation ; -// PNTVECTOR vPt ; -// INTVECTOR vTr ; -// if ( Triangulate().Make( vplPolyVec[nLoop], 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]]) } ; -// AddTriangle( nNewId) ; -// bModif = true ; -// } -// } -// } -// } -// } -// else if ( nVertInside == 0) -// RemoveTriangle( nT) ; -// } -// -// //// Se avvenuta modifica, aggiorno tutto -// // if ( bModif) -// // return ( AdjustVertices() && DoCompacting()) ; -// // Se avvenuta modifica, aggiorno tutto -// if ( bModif) { -// bool bOk = AdjustVertices() && DoCompacting() ; -// if ( bOk) -// SimplifyFacets( 100) ; -// return AdjustVertices() && DoCompacting() ; -// } -// -// return true ; -//} +// Una faccia di una trimesh ha una sola componente connessa, con un loop esterno e possibili loop interni +static bool +DistPointFacet( const Point3d& ptP, const POLYLINEVECTOR& vPolyVec, double& dPointFacetDist) +{ + // Verifico la presenza del loop esterno + if ( vPolyVec.size() < 1) + return false ; + // Proietto il punto sul piano della faccia, utilizzando il loop esterno + Plane3d plPlane ; + double dArea ; + if ( ! vPolyVec[0].IsClosedAndFlat( plPlane, dArea)) + return false ; + double dDistPtPl = DistPointPlane( ptP, plPlane) ; + Point3d ptProjP = ptP + dDistPtPl * plPlane.GetVersN() ; + // Verifico se il punto proiettato è esterno al loop esterno + int nPtOut = -1 ; + if ( ! IsPointInsidePolyLine( ptProjP, vPolyVec[0], EPS_SMALL)) + nPtOut = 0 ; + // Verifico se il punto proiettato è interno ai loop interni (quindi esterno alla faccia) + for ( int nLoop = 1 ; nLoop < int( vPolyVec.size()) && nPtOut < 0 ; ++ nLoop) { + Plane3d plPlane ; + double dArea ; + if ( ! vPolyVec[nLoop].IsClosedAndFlat( plPlane, dArea)) + return false ; + if ( IsPointInsidePolyLine( ptProjP, vPolyVec[nLoop], EPS_SMALL)) + nPtOut = nLoop ; + } + // Se il punto si proietta sulla faccia, la distanza dalla faccia coincide con quella dal piano + if ( nPtOut < 0) { + dPointFacetDist = abs( dDistPtPl) ; + return true ; + } + // Altrimenti calcolo la minima distanza del punto dalla polilinea del contorno a cui è esterno + double dDist ; + if ( DistPointPolyLine( ptP, vPolyVec[nPtOut], dDist)) { + dPointFacetDist = dDist ; + return true ; + } + return false ; +} +//---------------------------------------------------------------------------- +static bool +ChangeStart( const Point3d& ptNewStart, PNTVECTOR& Loop) +{ + // Cerco il tratto del loop chiuso più vicino al punto + int nMinSeg = - 1 ; + double dMinSqDinst = DBL_MAX ; + for ( int nPt = 0 ; nPt < int( Loop.size()) ; ++ nPt) { + // Estremi del segmento corrente del loop + Point3d ptSegSt = Loop[nPt] ; + Point3d ptSegEn = Loop[( nPt + 1) % int( Loop.size())] ; + // Distanza del punto dal segmento del loop + DistPointLine dDistCalc( ptNewStart, ptSegSt, ptSegEn) ; + double dSqDist ; + dDistCalc.GetSqDist( dSqDist) ; + if ( dSqDist < dMinSqDinst) { + dMinSqDinst = dSqDist ; + nMinSeg = nPt ; + } + } + // Se il punto non sta sul loop, errore + if ( dMinSqDinst > SQ_EPS_SMALL) + return false ; + // Verifico che il punto stia su un vertice, in tal caso non devo fare nulla + bool bOnStart = AreSamePointApprox( Loop[nMinSeg], ptNewStart) ; + bool bOnEnd = AreSamePointApprox( Loop[( nMinSeg + 1) % int( Loop.size())], ptNewStart) ; + if ( bOnStart || bOnEnd) { + if ( bOnEnd) { + ++ nMinSeg ; + if ( nMinSeg % int( Loop.size()) == 0) + return true ; + } + PNTVECTOR vTempVec ; + for ( int nPt = 0 ; nPt < nMinSeg ; ++ nPt) + vTempVec.emplace_back( Loop[nPt]) ; + int nSize = int( Loop.size()) ; + for ( int nPt = 0 ; nPt < nSize - nMinSeg ; ++ nPt) { + Loop[nPt] = Loop[nPt + nMinSeg] ; + } + for ( int nPt = 0 ; nPt < int( vTempVec.size()) ; ++ nPt) { + Loop[nPt + nSize - nMinSeg] = vTempVec[nPt] ; + } + return true ; + } + // Ridimensiono il loop + Loop.resize( Loop.size() + 1) ; + // Copio i primi punti + PNTVECTOR LoopTemp ; + for ( int nPt = 0 ; nPt <= nMinSeg ; ++ nPt) + LoopTemp.emplace_back( Loop[nPt]) ; + // Aggiungo il nuovo punto all'inizio + Loop[0] = ptNewStart ; + // Sposto gli ultimi in testa + int nLastPointNum = int( Loop.size()) - 1 - nMinSeg ; + for ( int nPt = 1 ; nPt <= nLastPointNum ; ++ nPt) { + Loop[nPt] = Loop[nPt + nMinSeg] ; + } + // Porto i primi in fondo + for ( int nPt = 0 ; nPt < int( LoopTemp.size()) ; ++ nPt) { + Loop[nPt + nLastPointNum] = LoopTemp[nPt] ; + } + return true ; +} + +//---------------------------------------------------------------------------- +static bool +SplitAtPoint( const Point3d& ptStop, const PNTVECTOR& Loop, PNTVECTOR& Loop1, PNTVECTOR& Loop2) +{ + // Cerco il tratto del loop chiuso più vicino al punto + int nMinSeg = -1 ; + double dMinSqDinst = DBL_MAX ; + for ( int nPt = 0 ; nPt < int( Loop.size()) ; ++ nPt) { + // Estremi del segmento corrente del loop + Point3d ptSegSt = Loop[nPt] ; + Point3d ptSegEn = Loop[( nPt + 1) % int(Loop.size())] ; + // Distanza del punto dal segmento del loop + DistPointLine dDistCalc( ptStop, ptSegSt, ptSegEn) ; + double dSqDist ; + dDistCalc.GetSqDist( dSqDist) ; + if ( dSqDist < dMinSqDinst) { + dMinSqDinst = dSqDist ; + nMinSeg = nPt ; + } + } + // Se il punto non sta sul loop, errore + if ( dMinSqDinst > SQ_EPS_SMALL) + return false ; + // Verifico che il punto stia su un vertice, in tal caso non devo aggiungerlo + bool bFirst = AreSamePointApprox( Loop[nMinSeg], ptStop) ; + bool bLast = AreSamePointApprox( Loop[( nMinSeg + 1) % int( Loop.size())], ptStop) ; + // Se il punto è sul vertice finale del segmento, aggiungo il vertice alla lista da inglobare al primo loop + if ( bLast) + ++ nMinSeg ; + // Inglobo fino a nSeg nel primo loop + for ( int nPt = 0 ; nPt <= nMinSeg ; ++ nPt) + Loop1.emplace_back( Loop[nPt]) ; + // Se il punto è interno al segmento, lo inglobo in entrambi i loop + if ( ! ( bFirst || bLast)) { + Loop1.emplace_back( ptStop) ; + Loop2.emplace_back( ptStop) ; + } + else { + Loop2.emplace_back( Loop[nMinSeg]) ; + } + // Inglobo gli ultimi vertici in Loop2 + for ( int nPt = nMinSeg + 1 ; nPt < int( Loop.size()) ; ++ nPt) + Loop2.emplace_back( Loop[nPt]) ; + Loop2.emplace_back( Loop[0]) ; + + return true ; +} + +//---------------------------------------------------------------------------- bool SurfTriMesh::GeneralizedCut( const ICurve& cvCurve, bool bSaveOnEq) { - // La superficie deve essere valida + // La superficie deve essere valida if ( m_nStatus != OK) return false ; - // Ritiangolo le facce. - SimplifyFacets( 100) ; - if ( ! AdjustVertices() || ! DoCompacting()) - return false ; - // La curva deve essere valida e chiusa, il vettore estrusione deve essere non nullo + // La curva deve essere valida e chiusa, il vettore estrusione deve essere non nullo Vector3d vtExtr ; if ( ! cvCurve.GetExtrusion( vtExtr) || vtExtr.IsSmall() || ! cvCurve.IsClosed()) return false ; - // Approssimo la curva con segmenti + + // Recupero il numero originale di triangoli e di facce + int nTriaOriCnt = GetTriangleCount() ; + int nFacetOriCnt = GetFacetCount() ; + + // Approssimo la curva con segmenti CurveComposite cvCompo ; PolyLine PL ; - if ( ! cvCurve.ApproxWithLines( LIN_TOL_MIN, ANG_TOL_STD_DEG, ICurve::APL_STD, PL) || ! cvCompo.FromPolyLine( PL)) + if ( ! cvCurve.ApproxWithLines( LIN_TOL_FINE, ANG_TOL_STD_DEG, ICurve::APL_STD, PL) || ! cvCompo.FromPolyLine( PL)) return false ; - // Appiattisco la polilinea nel piano perpendicolare all'estrusione + // Appiattisco la polilinea nel piano perpendicolare all'estrusione Frame3d frCurve ; Point3d ptStart ; cvCompo.GetStartPoint( ptStart) ; frCurve.Set( ptStart, vtExtr) ; @@ -677,80 +345,80 @@ SurfTriMesh::GeneralizedCut( const ICurve& cvCurve, bool bSaveOnEq) BBox3d b3Crv ; cvCompo.GetLocalBBox( b3Crv) ; cvCompo.ToGlob( frCurve) ; - // Assegno il senso di rotazione della curva (visto dalla punta del vettore estrusione) + // Assegno il senso di rotazione della curva (visto dalla punta del vettore estrusione) bool bCCW = ( dArea > 0) ; - // Recupero Bounding-box della trimesh + + // Recupero Bounding-box della trimesh BBox3d b3SurfBox ; GetLocalBBox( b3SurfBox) ; - // Trovo minima e massima distanza dei vertici del bounding-box della TriMesh dal piano della curva + // Trovo minima e massima distanza dei vertici del bounding-box della TriMesh dal piano della curva b3SurfBox.ToLoc( frCurve) ; Point3d ptMin, ptMax ; b3SurfBox.GetMinMax( ptMin, ptMax) ; Vector3d vtMax = ( ptMax.z + 10) * vtExtr ; Vector3d vtMin = ( ptMin.z - 10) * vtExtr ; - // Ciclo sui triangoli + // Ciclo sui triangoli bool bModif = false ; int nNumTria = GetTriangleSize() ; for ( int nT = 0 ; nT < nNumTria ; ++ nT) { - // Recupero il triangolo + // Recupero il triangolo Triangle3d trTria ; if ( ! GetTriangle( nT, trTria)) continue ; - // Box del triangolo nel riferimento locale della curva + // Box del triangolo nel riferimento locale della curva BBox3d b3Tria ; trTria.GetLocalBBox( b3Tria) ; b3Tria.ToLoc( frCurve) ; - // Se il box del triangolo non interseca quello locale della curva - if ( ! b3Crv.OverlapsXY(b3Tria)) { - // Se la parte da conservare è quella all'interno della curva, elimino il triangolo - if (bCCW) { + // Se il box del triangolo non interseca quello locale della curva + if ( ! b3Crv.OverlapsXY( b3Tria)) { + // Se la parte da conservare è quella all'interno della curva, elimino il triangolo + if ( bCCW) { RemoveTriangle( nT) ; bModif = true ; } continue ; } - // Determino il numero di vertici del triangolo che cadono all'interno della curva + // Determino il numero di vertici del triangolo che cadono all'interno della curva int nVertInside = 0 ; int nVertOutside = 0 ; for ( int nV = 0 ; nV < 3 ; ++ nV) { - // Determino se il vertice cade dentro la curva + // Determino se il vertice cade dentro la curva DistPointCurve dstPC( trTria.GetP( nV), cvCompo) ; int nSide ; dstPC.GetSideAtMinDistPoint( 0, vtExtr, nSide) ; - if ( nSide == MDS_LEFT || nSide == MDS_ON) { + if ( nSide == MDS_LEFT || nSide == MDS_ON) ++ nVertInside ; - } else ++ nVertOutside ; } - // Vettore di catene di punti + // Vettore di catene di punti CHAINVECTOR vChain ; - // Ciclo sui segmenti + // Ciclo sui segmenti int nChainCnt = 0 ; bool bChain = false ; Point3d ptChSt, ptChEn ; const ICurve* pCrv = cvCompo.GetFirstCurve() ; while ( pCrv != nullptr) { - // estremi del segmento + // estremi del segmento Point3d ptSt ; pCrv->GetStartPoint( ptSt) ; Point3d ptEn ; pCrv->GetEndPoint( ptEn) ; - // Intersezione fra il rettangolo (ottenuto dall'estrusione del segmento corrente) e il triangolo + // Intersezione fra il rettangolo (ottenuto dall'estrusione del segmento corrente) e il triangolo Point3d ptSegSt, ptSegEn ; int nInt = IntersRectangleTriangle( ptSt + vtMin, ptEn - ptSt, vtMax - vtMin, trTria, ptSegSt, ptSegEn) ; if ( nInt == 2) { - // Creo nuova catena se non c'è già o se discontinuità + // Creo nuova catena se non c'è già o se discontinuità if ( ! bChain || ( ! AreSamePointApprox( ptSegSt, ptChEn) && ! AreSamePointApprox( ptSegEn, ptChSt))) { ++ nChainCnt ; vChain.resize( nChainCnt) ; bChain = false ; } - // Assegno i dati di intersezione + // Assegno i dati di intersezione IntSegment CurInters ; CurInters.ptSt = ptSegSt ; CurInters.ptEn = ptSegEn ; - // Inserisco nella catena + // Inserisco nella catena if ( ! bChain) { vChain[nChainCnt - 1].emplace_back( CurInters) ; ptChSt = CurInters.ptSt ; @@ -776,7 +444,7 @@ SurfTriMesh::GeneralizedCut( const ICurve& cvCurve, bool bSaveOnEq) vChain.clear() ; nChainCnt = 0 ; } - // unisco eventuali catene estreme che sono parte di una stessa catena + // unisco eventuali catene estreme che sono parte di una stessa catena if ( nChainCnt > 1) { if ( AreSamePointApprox( vChain[0].front().ptSt, vChain[nChainCnt - 1].back().ptEn)) { vChain[0].insert( vChain[0].begin(), vChain[nChainCnt - 1].begin(), vChain[nChainCnt - 1].end()) ; @@ -790,10 +458,10 @@ SurfTriMesh::GeneralizedCut( const ICurve& cvCurve, bool bSaveOnEq) } } - // Elimino la seconda copia di catene doppie + // Elimino la seconda copia di catene doppie for ( int nI = 0 ; nI < nChainCnt ; ++ nI) { for ( int nJ = nI + 1 ; nJ < nChainCnt ; ++ nJ) { - if (vChain[nI].size() == vChain[nJ].size()) { + if ( vChain[nI].size() == vChain[nJ].size()) { bool bSame = true ; for ( int nK = 0 ; nK < int( vChain[nI].size()) ; ++ nK) { if ( ! AreSamePointApprox( vChain[nI][nK].ptSt, vChain[nJ][nK].ptSt) || @@ -811,7 +479,7 @@ SurfTriMesh::GeneralizedCut( const ICurve& cvCurve, bool bSaveOnEq) } } - // Fra le catene trovate separo le aperte dalle chiuse + // Fra le catene trovate separo le aperte dalle chiuse CHAINVECTOR cvClosedChain ; CHAINVECTOR cvOpenChain ; for ( int nL = 0 ; nL < int( vChain.size()) ; ++ nL) { @@ -828,36 +496,36 @@ SurfTriMesh::GeneralizedCut( const ICurve& cvCurve, bool bSaveOnEq) else ++ it ; } - // Se più di una catena chiusa oppure catene chiuse e aperte, errore + // Se più di una catena chiusa oppure catene chiuse e aperte, errore if ( cvClosedChain.size() > 1 || ( cvClosedChain.size() > 0 && int( cvOpenChain.size()) > 0)) return false ; - // Se c'è una catena chiusa + // Se c'è una catena chiusa if ( cvClosedChain.size() == 1) { - // Ne ricavo una PolyLine + // Ne ricavo una PolyLine PolyLine plInLoop ; for ( int nLine = 0 ; nLine < int( cvClosedChain[0].size()) ; ++ nLine) { plInLoop.AddUPoint( 0., cvClosedChain[0][nLine].ptSt) ; plInLoop.AddUPoint( 0., cvClosedChain[0][nLine].ptEn) ; } - // I tre vertici sono dalla parte interna della curva (triangolo con buco) + // I tre vertici sono dalla parte interna della curva (triangolo con buco) if ( ! bCCW) { - // Rimuovo il triangolo corrente + // Rimuovo il triangolo corrente RemoveTriangle( nT) ; - // Definisco il loop esterno (è il triangolo) + // Definisco il loop esterno (è il triangolo) PolyLine plExtLoop ; plExtLoop.AddUPoint( 0., trTria.GetP( 0)) ; plExtLoop.AddUPoint( 0., trTria.GetP( 1)) ; plExtLoop.AddUPoint( 0., trTria.GetP( 2)) ; plExtLoop.AddUPoint( 0., trTria.GetP( 0)) ; - // Eseguo triangolazione + // Eseguo triangolazione POLYLINEVECTOR vPL ; vPL.emplace_back( plExtLoop) ; vPL.emplace_back( plInLoop) ; PNTVECTOR vPt ; INTVECTOR vTr ; if ( Triangulate().Make( vPL, vPt, vTr)) { - // Inserisco i nuovi triangoli + // 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]]), @@ -868,15 +536,15 @@ SurfTriMesh::GeneralizedCut( const ICurve& cvCurve, bool bSaveOnEq) } } } - // Se nessun vertice dalla parte interna della curva (rimane solo l'area della curva) + // Se nessun vertice dalla parte interna della curva (rimane solo l'area della curva) else { - // Rimuovo il triangolo corrente + // Rimuovo il triangolo corrente RemoveTriangle( nT) ; - // Eseguo triangolazione + // Eseguo triangolazione PNTVECTOR vPt ; INTVECTOR vTr ; if ( Triangulate().Make( plInLoop, vPt, vTr)) { - // Inserisco i nuovi triangoli + // 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]]), @@ -888,13 +556,13 @@ SurfTriMesh::GeneralizedCut( const ICurve& cvCurve, bool bSaveOnEq) } } } - // Loop aperti, devo chiuderli - else if ( cvOpenChain.size() > 0) { - // Creo il loop chiuso padre di tutti, il perimetro del triangolo. - // Questo viene diviso in sotto-loop chiusi mediante quelli aperti. - // I loop chiusi trovati precedentemente sono interni a uno dei sotto-loop - // chiusi di cui è formato il perimetro. + // Loop aperti, devo chiuderli + else if ( cvOpenChain.size() > 0) { + // Creo il loop chiuso padre di tutti, il perimetro del triangolo. + // Questo viene diviso in sotto-loop chiusi mediante quelli aperti. + // I loop chiusi trovati precedentemente sono interni a uno dei sotto-loop + // chiusi di cui è formato il perimetro. PNTVECTOR cvFirstLoop ; cvFirstLoop.emplace_back( trTria.GetP( 0)) ; cvFirstLoop.emplace_back( trTria.GetP( 1)) ; @@ -904,11 +572,11 @@ SurfTriMesh::GeneralizedCut( const ICurve& cvCurve, bool bSaveOnEq) cvBoundClosedLoopVec.emplace_back( cvFirstLoop) ; BOOLVECTOR vbInOut ; vbInOut.push_back( true) ; - // Divido il loop di partenza in sotto-loop + // Divido il loop di partenza in sotto-loop while ( cvOpenChain.size() > 0) { int nLastOpenLoopN = int( cvOpenChain.size()) - 1 ; for ( int nLoop = 0 ; nLoop < int( cvBoundClosedLoopVec.size()) ; ++ nLoop) { - // Estremi del loop aperto + // Estremi del loop aperto int nLastOpenLoopPoint = max( int( cvOpenChain[nLastOpenLoopN].size()) - 1, 0) ; Point3d ptOpenLoopStP = cvOpenChain[nLastOpenLoopN][0].ptSt ; Point3d ptOpenLoopEnP = cvOpenChain[nLastOpenLoopN][nLastOpenLoopPoint].ptEn ; @@ -928,7 +596,7 @@ SurfTriMesh::GeneralizedCut( const ICurve& cvCurve, bool bSaveOnEq) bool bAdded2 = AddChainToChain( cvOpenChain[nLastOpenLoopN], Loop2) ; if ( ! ( bAdded1 && bAdded2)) continue ; - // Aggiungo i nuovi loop nel vettore + // Aggiungo i nuovi loop nel vettore int nCurSize = int( cvBoundClosedLoopVec.size()) ; cvBoundClosedLoopVec.resize( nCurSize + 1) ; vbInOut.resize( nCurSize + 1) ; @@ -944,9 +612,9 @@ SurfTriMesh::GeneralizedCut( const ICurve& cvCurve, bool bSaveOnEq) } cvOpenChain.resize( nLastOpenLoopN) ; } - // Rimuovo il triangolo corrente + // Rimuovo il triangolo corrente RemoveTriangle( nT) ; - // Trasformo i loop compositi in loop polyline + // Trasformo i loop compositi in loop polyline POLYLINEVECTOR vplPolyVec ; vplPolyVec.resize(cvBoundClosedLoopVec.size()) ; for ( int nLoop = 0 ; nLoop < int( vplPolyVec.size()) ; ++ nLoop) { @@ -955,12 +623,12 @@ SurfTriMesh::GeneralizedCut( const ICurve& cvCurve, bool bSaveOnEq) } vplPolyVec[nLoop].AddUPoint( 0., cvBoundClosedLoopVec[nLoop][0]) ; if ( vbInOut[nLoop]) { - // Eseguo triangolazione + // Eseguo triangolazione Triangulate CreateTriangulation ; PNTVECTOR vPt ; INTVECTOR vTr ; if ( Triangulate().Make( vplPolyVec[nLoop], vPt, vTr)) { - // Inserisco i nuovi triangoli + // 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]]), @@ -973,19 +641,22 @@ SurfTriMesh::GeneralizedCut( const ICurve& cvCurve, bool bSaveOnEq) } } } + + // da eliminare else if ( nVertInside == 0) RemoveTriangle( nT) ; } - //// Se avvenuta modifica, aggiorno tutto - // if ( bModif) - // return ( AdjustVertices() && DoCompacting()) ; - // Se avvenuta modifica, aggiorno tutto + // Se avvenuta modifica, aggiorno tutto if ( bModif) { - bool bOk = AdjustVertices() && DoCompacting() ; - if ( bOk) - SimplifyFacets( 100) ; - return AdjustVertices() && DoCompacting() ; + // aggiorno tutto + if ( ! AdjustVertices() || ! DoCompacting()) + return false ; + // se superficie originale a facce, cerco di semplificarle + if ( nFacetOriCnt < 200 || double( nTriaOriCnt) / nFacetOriCnt > 4) { + if ( ! SimplifyFacets( 500.0)) + LOG_ERROR( GetEGkLogger(), "Error in SimplifyFacets of Stm::GeneralizedCut") + } } return true ; @@ -3088,12 +2759,10 @@ SurfTriMesh::IntersFacetFacet( const SurfFlatRegion& RegionA, const PolyLine& Ex //---------------------------------------------------------------------------- struct PositionOnPolyLine { int nIndexInVec ; - int nSegNum ; - double dParOnSeg ; - PositionOnPolyLine( int nIndex, int nSeg, double dPar) { + double dPar ; + PositionOnPolyLine( int nIndex, double dParam) { nIndexInVec = nIndex ; - nSegNum = nSeg ; - dParOnSeg = dPar ; + dPar = dParam ; } } ; @@ -3205,16 +2874,15 @@ SurfTriMesh::SplitFacet( const INTERSCHAINMAP& IntersLineMap, PieceMap& NewFacet 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)) { + double dPar ; + if ( GetPointParamOnPolyLine( cvOpenChain[nLastChainNum][0].ptSt, vNewPieces[nPart].vPieceLoop[nLoop], 2 * EPS_SMALL, dPar)) { 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)) { + if ( GetPointParamOnPolyLine( cvOpenChain[nLastChainNum][cvOpenChain[nLastChainNum].size() - 1].ptEn, + vNewPieces[nPart].vPieceLoop[nLoop], 2 * EPS_SMALL, dPar)) { vLoopIndexes.emplace_back( nLoop) ; } } @@ -3224,7 +2892,7 @@ SurfTriMesh::SplitFacet( const INTERSCHAINMAP& IntersLineMap, PieceMap& NewFacet // 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]]) ; + ChangePolyLineStart( vNewPieces[nPart].vPieceLoop[vLoopIndexes[0]], cvOpenChain[nLastChainNum].back().ptEn, 2 * EPS_SMALL) ; // Divido il loop della parte // Loop1 PolyLine NewLoop1 ; @@ -3236,14 +2904,14 @@ SurfTriMesh::SplitFacet( const INTERSCHAINMAP& IntersLineMap, PieceMap& NewFacet } // 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]], + SplitPolyLineAtPoint( vNewPieces[nPart].vPieceLoop[vLoopIndexes[0]], + cvOpenChain[nLastChainNum][0].ptSt, 2 * EPS_SMALL, SplitLoop1, SplitLoop2) ; - // Aggiungo i punti precedenti il punto di frattura nella in NewLoop1. - AddPolyLineToPolyLine( NewLoop1, SplitLoop1) ; + // Aggiungo i punti precedenti il punto di frattura nella NewLoop1. + NewLoop1.Join( SplitLoop1) ; // Loop2 PolyLine NewLoop2 ; - AddPolyLineToPolyLine( NewLoop2, SplitLoop2) ; + NewLoop2.Join( 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) ; @@ -3265,7 +2933,7 @@ SurfTriMesh::SplitFacet( const INTERSCHAINMAP& IntersLineMap, PieceMap& NewFacet Point3d ptPointInnerLoop ; vNewPieces[nPart].vPieceLoop[nIL].GetFirstPoint( ptPointInnerLoop) ; if ( PieceInn.vPieceLoop[0].GetPointNbr() < PieceOut.vPieceLoop[0].GetPointNbr()) { - if ( IsPointInsidePolyLine( ptPointInnerLoop, PieceInn.vPieceLoop[0])) { + if ( IsPointInsidePolyLine( ptPointInnerLoop, PieceInn.vPieceLoop[0], EPS_SMALL)) { PieceInn.vPieceLoop.emplace_back( vNewPieces[nPart].vPieceLoop[nIL]) ; } else { @@ -3273,7 +2941,7 @@ SurfTriMesh::SplitFacet( const INTERSCHAINMAP& IntersLineMap, PieceMap& NewFacet } } else { - if ( IsPointInsidePolyLine( ptPointInnerLoop, PieceOut.vPieceLoop[0])) { + if ( IsPointInsidePolyLine( ptPointInnerLoop, PieceOut.vPieceLoop[0], EPS_SMALL)) { PieceOut.vPieceLoop.emplace_back( vNewPieces[nPart].vPieceLoop[nIL]) ; } else { @@ -3308,13 +2976,13 @@ SurfTriMesh::SplitFacet( const INTERSCHAINMAP& IntersLineMap, PieceMap& NewFacet 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. + // Al 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])) { + if ( IsPointInsidePolyLine( ptPointInnerLoop, DetachedPiece.vPieceLoop[0], EPS_SMALL)) { DetachedPiece.vPieceLoop.emplace_back( vNewPieces[nPart].vPieceLoop[nIL]) ; vNewPieces[nPart].vPieceLoop.erase( vNewPieces[nPart].vPieceLoop.begin() + nIL) ; // Cambio il numero dei loop tagliati @@ -3343,24 +3011,18 @@ SurfTriMesh::SplitFacet( const INTERSCHAINMAP& IntersLineMap, PieceMap& NewFacet 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()]) ; + ChangePolyLineStart( vNewPieces[nPart].vPieceLoop[vLoopIndexes.back()], cvOpenChain[vChainIndex.back()].back().ptEn, 2 * EPS_SMALL) ; // 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)) ; + double dPar ; + if ( GetPointParamOnPolyLine( cvOpenChain[nCh][0].ptSt, vNewPieces[nPart].vPieceLoop[vLoopIndexes.back()], 2 * EPS_SMALL, dPar)) { + vChainStartingOnLoop.emplace_back( PositionOnPolyLine(nCh, dPar)) ; } } // 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 ; } ) ; + return Ch1.dPar < Ch2.dPar ; } ) ; // 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 @@ -3373,10 +3035,9 @@ SurfTriMesh::SplitFacet( const INTERSCHAINMAP& IntersLineMap, PieceMap& NewFacet // Salto il loop corrente if ( nLoop == vLoopIndexes.back()) continue ; - int nSegNum ; - double dParOnSeg ; + double dPar ; // La catena termina su questo loop diverso da quello corrente. - if ( PointPositionOnPolyLine( cvOpenChain[nCh][nLastLineIndex].ptEn, vNewPieces[nPart].vPieceLoop[nLoop], nSegNum, dParOnSeg)) { + if ( GetPointParamOnPolyLine( cvOpenChain[nCh][nLastLineIndex].ptEn, vNewPieces[nPart].vPieceLoop[nLoop], 2 * EPS_SMALL, dPar)) { // Salvo l'indice della catena e quello del loop. vChainIndex.emplace_back( nCh) ; vLoopIndexes.emplace_back( nLoop) ; @@ -3389,7 +3050,7 @@ SurfTriMesh::SplitFacet( const INTERSCHAINMAP& IntersLineMap, PieceMap& NewFacet } } // Cambio inizio al loop iniziale. - ChangePolyLineStart( cvOpenChain[vChainIndex.back()].back().ptEn, vNewPieces[nPart].vPieceLoop[vLoopIndexes[0]]) ; + ChangePolyLineStart( vNewPieces[nPart].vPieceLoop[vLoopIndexes[0]], cvOpenChain[vChainIndex.back()].back().ptEn, 2 * EPS_SMALL) ; // Divido i loop della parte. POLYLINEVECTOR vPolySecondPartVec ; PolyLine NewLoop1 ; @@ -3402,18 +3063,18 @@ SurfTriMesh::SplitFacet( const INTERSCHAINMAP& IntersLineMap, PieceMap& NewFacet } // 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]], + SplitPolyLineAtPoint( vNewPieces[nPart].vPieceLoop[vLoopIndexes[n + 1]], + cvOpenChain[vChainIndex[( n + 1) % int( vChainIndex.size())]][0].ptSt, 2 * EPS_SMALL, SplitLoop1, SplitLoop2) ; // Aggiungo i punti precedenti il punto di frattura in NewLoop1. - AddPolyLineToPolyLine( NewLoop1, SplitLoop1) ; + NewLoop1.Join( 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]) ; + NewLoop2.Join( 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) ; @@ -3449,7 +3110,7 @@ SurfTriMesh::SplitFacet( const INTERSCHAINMAP& IntersLineMap, PieceMap& NewFacet Point3d ptPointInnerLoop ; vNewPieces[nPart].vPieceLoop[nIL].GetFirstPoint( ptPointInnerLoop) ; if ( PieceInn.vPieceLoop[0].GetPointNbr() < PieceOut.vPieceLoop[0].GetPointNbr()) { - if ( IsPointInsidePolyLine( ptPointInnerLoop, PieceInn.vPieceLoop[0])) { + if ( IsPointInsidePolyLine( ptPointInnerLoop, PieceInn.vPieceLoop[0], EPS_SMALL)) { PieceInn.vPieceLoop.emplace_back( vNewPieces[nPart].vPieceLoop[nIL]) ; } else { @@ -3457,7 +3118,7 @@ SurfTriMesh::SplitFacet( const INTERSCHAINMAP& IntersLineMap, PieceMap& NewFacet } } else { - if ( IsPointInsidePolyLine( ptPointInnerLoop, PieceOut.vPieceLoop[0])) { + if ( IsPointInsidePolyLine( ptPointInnerLoop, PieceOut.vPieceLoop[0], EPS_SMALL)) { PieceOut.vPieceLoop.emplace_back( vNewPieces[nPart].vPieceLoop[nIL]) ; } else { @@ -3533,7 +3194,7 @@ SurfTriMesh::SplitFacet( const INTERSCHAINMAP& IntersLineMap, PieceMap& NewFacet continue ; Point3d ptPointInnerLoop ; vNewPieces[nPart].vPieceLoop[nIL].GetFirstPoint( ptPointInnerLoop) ; - if ( IsPointInsidePolyLine( ptPointInnerLoop, DetachedPiece.vPieceLoop[0])) { + if ( IsPointInsidePolyLine( ptPointInnerLoop, DetachedPiece.vPieceLoop[0], EPS_SMALL)) { DetachedPiece.vPieceLoop.emplace_back( vNewPieces[nPart].vPieceLoop[nIL]) ; vNewPieces[nPart].vPieceLoop.erase( vNewPieces[nPart].vPieceLoop.begin() + nIL) ; // Cambio il numero dei loop talgiati @@ -3589,8 +3250,9 @@ SurfTriMesh::SplitFacet( const INTERSCHAINMAP& IntersLineMap, PieceMap& NewFacet ++ 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]))) { + if ( IsPointInsidePolyLine( ptInnP, vNewPieces[nPieceN].vPieceLoop[0], EPS_SMALL) || + ( itInnNext != LoopList.end() && + IsPointInsidePolyLine( 0.5 * ( ptInnP + ptInnNextP), vNewPieces[nPieceN].vPieceLoop[0], EPS_SMALL))) { Polygon3d AuxPolygon ; AuxPolygon.FromPolyLine( CurInnerLoop) ; Vector3d vtInnLoopNorm = AuxPolygon.GetVersN() ; @@ -3609,7 +3271,7 @@ SurfTriMesh::SplitFacet( const INTERSCHAINMAP& IntersLineMap, PieceMap& NewFacet 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())) { + if ( IsPointInsidePolyLine( ptPntSL, vNewPieces.back().vPieceLoop.back(), EPS_SMALL)) { vSecondLevel.emplace_back( nSI) ; break ; } @@ -3637,7 +3299,7 @@ SurfTriMesh::SplitFacet( const INTERSCHAINMAP& IntersLineMap, PieceMap& NewFacet 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())) { + if ( IsPointInsidePolyLine( ptPntSL, vNewPieces.back().vPieceLoop.back(), EPS_SMALL)) { vSecondLevel.emplace_back( nSI) ; break ; } @@ -4632,4 +4294,4 @@ SurfTriMesh::IntersectTriMeshFacets( SurfTriMesh& Other) } #endif return bOk ; -} \ No newline at end of file +} diff --git a/SurfTriMeshUtilities.cpp b/SurfTriMeshUtilities.cpp index b7e2e66..14c8d7d 100644 --- a/SurfTriMeshUtilities.cpp +++ b/SurfTriMeshUtilities.cpp @@ -1,8 +1,8 @@ //---------------------------------------------------------------------------- -// EgalTech 2015-2015 +// EgalTech 2021-2021 //---------------------------------------------------------------------------- -// File : SurfTriMeshUtilities.cpp Data : 25.10.21 Versione : -// Contenuto : Implementazione della classe Superfici TriMesh. +// File : SurfTriMeshUtilities.cpp Data : 01.11.21 Versione : 2.3k1 +// Contenuto : Implementazione funzioni di utilità di Superfici TriMesh. // // // @@ -19,208 +19,232 @@ using namespace std ; +//---------------------------------------------------------------------------- +static bool +IsVertex( PNTULIST& PointList, PNTULIST::const_iterator itCurr) +{ + // recupero il punto precedente + PNTULIST::const_iterator itPrev ; + if ( itCurr == PointList.begin()) + itPrev = prev( PointList.end(), 2) ; + else + itPrev = prev( itCurr) ; + // recupero il punto successivo + auto itNext = next( itCurr) ; + if ( itNext == PointList.end()) + itNext = next( PointList.begin()) ; + // se cambia faccia adiacente tra prima e dopo, va bene + if ( itPrev->second != itCurr->second) + return true ; + // se lati aperti e cambia direzione tra prima e dopo, va bene + if ( itPrev->second == -1) { + DistPointLine PointLineDistCalc( itCurr->first, itPrev->first, itNext->first) ; + double dDist ; + if ( PointLineDistCalc.GetDist( dDist) && dDist > EPS_SMALL) + return true ; + } + // altrimenti non va bene + return false ; +} + +//---------------------------------------------------------------------------- +static bool +ChooseGoodStartPoint( PNTULIST& PointList) +{ + // se il punto iniziale è un vertice, non devo fare alcunché + if ( IsVertex( PointList, PointList.begin())) + return true ; + // altrimenti cerco il vertice più vicino + for ( auto it = next( PointList.begin()) ; it != PointList.end() ; ++it) { + if ( IsVertex( PointList, it)) { + // cancello ultimo punto ( coincide con primo) + PointList.pop_back() ; + // sposto la parte iniziale dei punti alla fine + PointList.splice( PointList.end(), PointList, PointList.begin(), it) ; + // aggiungo punto finale come copia dell'iniziale + PointList.push_back( PointList.front()) ; + // ho finito + return true ; + } + } + return false ; +} + +//---------------------------------------------------------------------------- +static bool +AdjustLoop( PNTULIST& PointList, double dMaxEdgeLen, bool& bModif) +{ + // Ciclo sui punti del loop + auto itLast = PointList.begin() ; + for ( auto it = next( itLast) ; it != PointList.end() ; ++ it) { + + // Se dal punto corrente inizia un segmento adiacente a un'altra faccia + if ( itLast->second != it->second) { + // Elimino i punti interni + auto itNextToLast = next( itLast) ; + for ( auto itInn = itNextToLast ; itInn != it ; ) { + itInn = PointList.erase( itInn) ; + bModif = true ; + } + // Se la lunghezza del segmento supera il limite imposto + double dSegLen = Dist( it->first, itLast->first) ; + if ( dSegLen > dMaxEdgeLen) { + // determino il numero di step + double dRatio = dSegLen / dMaxEdgeLen ; + int nStepCount = int( dRatio) + 1 ; + // inserisco i punti + auto itAdd = it ; + for ( int nP = 1 ; nP < nStepCount ; ++ nP) { + double dCoeff = nP / nStepCount ; + itAdd = PointList.insert( itAdd, POINTU( Media( itLast->first, it->first, dCoeff), itLast->second)) ; + bModif = true ; + } + } + // Nuovo punto di riferimento + itLast = it ; + } + + // Se sono due segmenti liberi non allineati + else if ( itLast->second == - 1) { + // Calcolo se i punti compresi fra gli estremi sono allineati + bool bAreAligned = true ; + auto itNextToLast = next( itLast) ; + for ( auto itInn = itNextToLast ; itInn != it && bAreAligned ; ++ itInn) { + DistPointLine PointLineDistCalc( itInn->first, itLast->first, it->first) ; + double dDist ; + if ( PointLineDistCalc.GetDist( dDist)) + bAreAligned = ( dDist < EPS_SMALL) ; + } + // Se i punti sono allineati + if ( bAreAligned) { + // Verifico se il successivo punto non è più allineato + auto itNextToCurr = next( it) ; + if ( itNextToCurr != PointList.end()) { + for ( auto itInn = itNextToLast ; itInn != itNextToCurr && bAreAligned ; ++ itInn) { + DistPointLine PointLineDistCalc( itInn->first, itLast->first, itNextToCurr->first) ; + double dDist ; + if ( PointLineDistCalc.GetDist( dDist)) + bAreAligned = ( dDist < EPS_SMALL) ; + } + } + // Se ho trovato un insieme massimale di punti allineati li processo + if ( ! bAreAligned || itNextToCurr == PointList.end()) { + // Elimino i punti interni + for ( auto itInn = itNextToLast ; itInn != it ; ) { + itInn = PointList.erase( itInn) ; + bModif = true ; + } + // Se la lunghezza del segmento supera il limite imposto + double dSegLen = Dist( it->first, itLast->first) ; + if ( dSegLen > dMaxEdgeLen) { + // determino il numero di step + double dRatio = dSegLen / dMaxEdgeLen ; + int nStepCount = int( dRatio) + 1 ; + // inserisco i punti + auto itAdd = it ; + for ( int nP = 1 ; nP < nStepCount ; ++ nP) { + double dCoeff = nP / nStepCount ; + itAdd = PointList.insert( itAdd, POINTU( Media( itLast->first, it->first, dCoeff), itLast->second)) ; + bModif = true ; + } + } + // Nuovo punto di riferimento + itLast = it ; + } + } + } + } + + return true ; +} + //---------------------------------------------------------------------------- bool SurfTriMesh::SimplifyFacets( double dMaxEdgeLen) { - // Se la lunghezza massima del lato del triangolo sul bordo della faccia è nulla, ho finito. + // La trimesh deve essere valida + if ( ! IsValid()) + return false ; + // Se la lunghezza massima del lato del triangolo sul bordo della faccia è nulla, non devo fare alcunché if ( dMaxEdgeLen < EPS_SMALL) return true ; - // Le superfici devono essere valide. - if ( ! IsValid()) - return false ; + // Recupero il numero delle facce (esegue anche una verifica delle stesse) + int nFacetCnt = GetFacetCount() ; - // Verifico la definizione delle facce. - VerifyFaceting() ; + // Ciclo sulle facce della mesh per trovare quelle da ritriangolare + unordered_map< int, pair< PNTVECTOR, INTVECTOR>> FacetMap ; + for ( int nF = 0 ; nF < nFacetCnt ; ++ nF) { - // Ciclo sulle facce delle mesh. - unordered_map FacetMap ; - int nFacetNum = GetFacetCount() ; - for ( int nF = 0 ; nF < nFacetNum ; ++ nF) { - bool bFacetToRetriangulate = false ; - // Recupero i loop della faccia. + // Recupero i loop della faccia (il parametro indica la faccia adiacente) POLYLINEVECTOR LoopVec ; GetFacetLoops( nF, LoopVec) ; - // Recupero le adiacenze della faccia. - INTMATRIX vAdj ; - GetFacetAdjacencies( nF, vAdj) ; - // Ciclo sui loop della faccia. + + // Ciclo sui loop della faccia + bool bToRetriangulate = false ; for ( int nL = 0 ; nL < int( LoopVec.size()) ; ++ nL) { - // Lista dei punti del loop. + + // Lista dei punti del loop PNTULIST& PointList = LoopVec[nL].GetUPointList() ; - // Mi assicuro che il punto finale non sia all'interno di un segmento. - auto itFirst = PointList.begin() ; - int nNewStartPos = 0 ; - for ( auto it = itFirst ; it != PointList.end() ; ++ it, ++ nNewStartPos) { - if ( itFirst->second != it->second) { - { - // cancello ultimo punto ( coincide con primo) - PointList.pop_back() ; - // sposto la metà iniziale dei punti alla fine - for ( int i = 0 ; i < nNewStartPos ; ++ i) - PointList.splice( PointList.end(), PointList, PointList.begin()) ; - // aggiungo punto finale come copia dell'iniziale - PointList.push_back( PointList.front()) ; - } - break ; - } - else if ( itFirst->second == - 1 && it != itFirst) { - // Valuto se i punti compresi fra gli estremi sono allinati. - bool bAreAlligned = true ; - auto itNextToLast = itFirst ; - ++ itNextToLast ; - for ( auto itInn = itNextToLast ; itInn != it && bAreAlligned ; ++ itInn) { - DistPointLine PointLineDistCalc( itInn->first, itFirst->first, it->first, false) ; - double dDist ; - PointLineDistCalc.GetDist( dDist) ; - bAreAlligned = bAreAlligned && dDist < EPS_SMALL ; - } - // I punti sono allineati. - if ( bAreAlligned) { - // Valuto se includendo anche il punto successivo non ci sarebbe più allineamento, - // ovvero avrei trovato un insieme massimale di punti allineati. - auto itNextToCurr = it ; - ++ itNextToCurr ; - // Se il punto corrente è l'ultimo, ho trovato un insieme massimale di punti allineati. - if ( itNextToCurr != PointList.end()) { - for ( auto itInn = itNextToLast ; itInn != itNextToCurr && bAreAlligned ; ++ itInn) { - DistPointLine PointLineDistCalc( itInn->first, itFirst->first, itNextToCurr->first, false) ; - double dDist ; - PointLineDistCalc.GetDist( dDist) ; - bAreAlligned = bAreAlligned && dDist < EPS_SMALL ; - } - } - // Se ho trovato un insieme massimale di punti allineati li ridistribuisco, - // altrimenti procedo per includere il punto successivo nell'insieme. - if ( ! bAreAlligned || itNextToCurr == PointList.end()) { - { - // cancello ultimo punto ( coincide con primo) - PointList.pop_back() ; - // sposto la metà iniziale dei punti alla fine - for ( int i = 0 ; i < nNewStartPos ; ++ i) - PointList.splice( PointList.end(), PointList, PointList.begin()) ; - // aggiungo punto finale come copia dell'iniziale - PointList.push_back( PointList.front()) ; - } - break ; - } - } - } - } - // Ciclo sui punti del loop. - auto itLast = PointList.begin() ; - for ( auto it = itLast ; it != PointList.end() ; ++ it) { - // Dal punto corrente spicca un segmento adiacente a una nuova faccia. - if ( itLast->second != it->second) { - // Elimino punti interni. - auto itNextToLast = itLast ; - ++ itNextToLast ; - for ( auto itInn = itNextToLast ; itInn != it ; ) { - itInn = PointList.erase( itInn) ; - bFacetToRetriangulate = true ; - } - // Versore direzione del segmento e sua lunghezza. - Vector3d vtSeg = it->first - itLast->first ; - double dSegLen = vtSeg.Len() ; - vtSeg /= dSegLen ; - // Calcolo numero dei punti da inserire. - double dRatio = dSegLen / dMaxEdgeLen ; - int nStepNum = ( dRatio < 1 + EPS_SMALL ? int( dRatio) : int( dRatio) + 1) ; - // Aggiungo i nuovi punti. - double dMyLen = dSegLen / nStepNum ; - auto itAdd = it ; - for ( int nP = 1 ; nP < nStepNum ; ++ nP) { - itAdd = PointList.insert( itAdd, POINTU( it->first - nP * dMyLen * vtSeg, itLast->second)) ; - bFacetToRetriangulate = true ; - } - itLast = it ; - } - // Possono essere due segmenti liberi non allineati. - else if ( itLast->second == - 1 && it != itLast) { - // Valuto se i punti compresi fra gli estremi sono allinati. - bool bAreAlligned = true ; - auto itNextToLast = itLast ; - ++ itNextToLast ; - for ( auto itInn = itNextToLast ; itInn != it && bAreAlligned ; ++ itInn) { - DistPointLine PointLineDistCalc( itInn->first, itLast->first, it->first, false) ; - double dDist ; - PointLineDistCalc.GetDist( dDist) ; - bAreAlligned = bAreAlligned && dDist < EPS_SMALL ; - } - // I punti sono allineati. - if ( bAreAlligned) { - // Valuto se includendo anche il punto successivo non ci sarebbe più allineamento, - // ovvero avrei trovato un insieme massimale di punti allineati. - auto itNextToCurr = it ; - ++ itNextToCurr ; - // Se il punto corrente è l'ultimo, ho trovato un insieme massimale di punti allineati. - if ( itNextToCurr != PointList.end()) { - for ( auto itInn = itNextToLast ; itInn != itNextToCurr && bAreAlligned ; ++ itInn) { - DistPointLine PointLineDistCalc( itInn->first, itLast->first, itNextToCurr->first, false) ; - double dDist ; - PointLineDistCalc.GetDist( dDist) ; - bAreAlligned = bAreAlligned && dDist < EPS_SMALL ; - } - } - // Se ho trovato un insieme massimale di punti allineati li ridistribuisco, - // altrimenti procedo per includere il punto successivo nell'insieme. - if ( ! bAreAlligned || itNextToCurr == PointList.end()) { - for ( auto itInn = itNextToLast ; itInn != it ; ) { - itInn = PointList.erase( itInn) ; - bFacetToRetriangulate = true ; - } - // Versore direzione del segmento e sua lunghezza. - Vector3d vtSeg = it->first - itLast->first ; - double dSegLen = vtSeg.Len() ; - vtSeg /= dSegLen ; - // Calcolo numero dei punti da inserire. - double dRatio = dSegLen / dMaxEdgeLen ; - int nStepNum = ( dRatio < 1 + EPS_SMALL ? int( dRatio) : int( dRatio) + 1) ; - // Aggiungo i nuovi punti. - double dMyLen = dSegLen / nStepNum ; - auto itAdd = it ; - for ( int nP = 1 ; nP < nStepNum ; ++ nP) { - itAdd = PointList.insert( itAdd, POINTU( it->first - nP * dMyLen * vtSeg, itLast->second)) ; - bFacetToRetriangulate = true ; - } - itLast = it ; - } - } - } - } + + // Mi assicuro che il punto iniziale/finale non sia all'interno di un possibile segmento + if ( ! ChooseGoodStartPoint( PointList)) + return false ; + + // Sistemo il loop + bool bModif = false ; + if ( ! AdjustLoop( PointList, dMaxEdgeLen, bModif)) + return false ; + if ( bModif) + bToRetriangulate = true ; } - if ( bFacetToRetriangulate) { - FacetMap.emplace( nF, LoopVec) ; + + // Se da ritriangolare, + if ( bToRetriangulate) { + // Eseguo la ritriangolazione della faccia + PNTVECTOR vPt ; + INTVECTOR vTr ; + if ( Triangulate().Make( LoopVec, vPt, vTr)) { + FacetMap.emplace( nF, make_pair( vPt, vTr)) ; + } + // Se non riesco a triangolare anche solo questa faccia, interrompo tutto + else + return false ; } } - // Ciclo sulle facce da ritriangolare per eliminare i triangoli. + // Ciclo sulle facce da ritriangolare per eliminare i triangoli (nel contempo salvo flag colore) + unordered_map< int, int> ColorMap ; for ( auto itF = FacetMap.begin() ; itF != FacetMap.end() ; ++ itF) { - // Cancello i triangoli della faccia. + // Recupero i triangoli della faccia INTVECTOR vFacetTria ; GetAllTriaInFacet( itF->first, vFacetTria) ; - for ( int& nT : vFacetTria) + // Salvo il colore della faccia da flag di un suo triangolo + ColorMap.emplace( itF->first, m_vTria[m_vFacet[itF->first]].nTFlag) ; + // Cancello i triangoli della faccia. + for ( int nT : vFacetTria) RemoveTriangle( nT) ; } - // Ritriangolo le facce. - for ( auto itF = FacetMap.begin() ; itF != FacetMap.end() ; ++ itF) { - // Ritriangolo la faccia. - PNTVECTOR vPt ; - INTVECTOR vTr ; - if ( Triangulate().Make( itF->second, 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[itF->first]].nTFlag) ; - } + + // Applico le nuove triangolazioni delle facce + for ( auto itFac = FacetMap.begin() ; itFac != FacetMap.end() ; ++ itFac) { + const PNTVECTOR& vPt = itFac->second.first ; + const INTVECTOR& vTr = itFac->second.second ; + // Inserisco i nuovi triangoli + for ( int n = 0 ; n < int( vTr.size()) - 2 ; n += 3) { + int nNewId[3] = { AddVertex( vPt[vTr[n]]), + AddVertex( vPt[vTr[n + 1]]), + AddVertex( vPt[vTr[n + 2]])} ; + auto itCol = ColorMap.find( itFac->first) ; + int nTFlag = ( itCol != ColorMap.end() ? itCol->second : 0) ; + int nNewTriaId = AddTriangle( nNewId, nTFlag) ; } } - return AdjustVertices() && DoCompacting() ; -} \ No newline at end of file + // dichiaro necessità ricalcolo della grafica e di hashgrids3d + m_OGrMgr.Reset() ; + ResetHashGrids3d() ; + + // Eseguo aggiustamenti + return ( AdjustVertices() && DoCompacting()) ; +}