diff --git a/BBox3d.cpp b/BBox3d.cpp index 5593e0f..74271e0 100644 --- a/BBox3d.cpp +++ b/BBox3d.cpp @@ -13,8 +13,8 @@ //--------------------------- Include ---------------------------------------- #include "stdafx.h" -#include "\EgtDev\Include\EGkBBox3d.h" -#include "\EgtDev\Include\EGkFrame3d.h" +#include "/EgtDev/Include/EGkBBox3d.h" +#include "/EgtDev/Include/EGkFrame3d.h" #include using namespace std ; diff --git a/EgtGeomKernel.vcxproj b/EgtGeomKernel.vcxproj index 07eb34e..e6b8fd1 100644 --- a/EgtGeomKernel.vcxproj +++ b/EgtGeomKernel.vcxproj @@ -392,6 +392,7 @@ copy $(TargetPath) \EgtProg\Dll64 + diff --git a/EgtGeomKernel.vcxproj.filters b/EgtGeomKernel.vcxproj.filters index c1175ce..a8f9fbe 100644 --- a/EgtGeomKernel.vcxproj.filters +++ b/EgtGeomKernel.vcxproj.filters @@ -453,6 +453,9 @@ File di origine\GeoCollision + + File di origine\Geo + diff --git a/PolyLine.cpp b/PolyLine.cpp index 88c31ca..2384081 100644 --- a/PolyLine.cpp +++ b/PolyLine.cpp @@ -21,6 +21,7 @@ #include "GeoConst.h" #include "/EgtDev/Include/EGkPolyLine.h" #include "/EgtDev/Include/EGkPlane3d.h" +#include "/EgtDev/Include/EGkPolygon3d.h" #include "/EgtDev/Include/EGnStringUtils.h" using namespace std ; @@ -1296,3 +1297,479 @@ PolyLine::Trim( const Plane3d& plPlane, bool bInVsOut) return true ; } + +//---------------------------------------------------------------------------- +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 ; +} + +//---------------------------------------------------------------------------- +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 +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) + 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 ; + Point3d ptMinDist ; + auto itMinDistSt = List.end() ; + auto itSt = List.begin() ; + auto itEn = itSt ; + ++ itEn ; + for ( ; itSt != List.end() && itEn != List.end() ; ++ itSt, ++ itEn) { + // Estremi del segmento corrente del loop + Point3d ptSegSt = itSt->first ; + Point3d ptSegEn = itEn->first ; + // Distanza del punto dal segmento del loop + DistPointLine dDistCalc( ptP, ptSegSt, ptSegEn) ; + double dSqDist ; + dDistCalc.GetSqDist( dSqDist) ; + if ( dSqDist < dMinSqDist) { + dMinSqDist = dSqDist ; + dDistCalc.GetMinDistPoint( ptMinDist) ; + itMinDistSt = itSt ; + } + } + // Termine del segmento di minima distanza. + auto itMinDistEn = itMinDistSt ; + ++ itMinDistEn ; + // Punto di minima distanza nell'estremo iniziale del segento + if ( AreSamePointApprox( ptMinDist, itMinDistSt->first)) { + auto itPrevSt = List.begin() ; + if ( itMinDistSt == List.begin()) { + auto itAuxNext = itPrevSt ; + ++ ( ++ itAuxNext) ; + for ( ; itAuxNext != List.end() ; ++ itPrevSt, ++ itAuxNext) + ; + } + else { + auto itAuxNext = itPrevSt ; + ++ itAuxNext ; + for (; itAuxNext != itMinDistSt; ++itPrevSt, ++itAuxNext) + ; + } + Vector3d vtPrevTan = itMinDistSt->first - itPrevSt->first ; + vtPrevTan.Normalize() ; + Vector3d vtTan = itMinDistEn->first - itMinDistSt->first ; + vtTan.Normalize() ; + Polygon3d AuxPolygon ; + AuxPolygon.FromPolyLine( plPoly) ; + Vector3d vtPolyNorm = AuxPolygon.GetVersN() ; + Vector3d vtPrevOut = vtPrevTan ^ vtPolyNorm ; + Vector3d vtOut = vtTan ^ vtPolyNorm ; + // Caso concavo + if ( vtTan * vtPrevOut > 0) { + Vector3d vtTest = ptP - ptMinDist ; + if ( vtTest * vtPrevOut < 0 || vtTest * vtOut < 0) + return true ; + } + // Caso convesso + else { + Vector3d vtTest = ptP - ptMinDist ; + if ( vtTest * vtPrevOut < 0 && vtTest * vtOut < 0) + return true ; + } + } + // Punto di minima distanza nell'estremo finale del segento + else if ( AreSamePointApprox( ptMinDist, itMinDistEn->first)) { + auto itNextEn = itMinDistEn ; + ++ itNextEn ; + if ( itNextEn == List.end()) { + itNextEn = List.begin() ; + ++ itNextEn ; + } + Vector3d vtTan = itMinDistEn->first - itMinDistSt->first ; + vtTan.Normalize() ; + Vector3d vtNextTan = itNextEn->first - itMinDistEn->first ; + vtNextTan.Normalize() ; + Polygon3d AuxPolygon ; + AuxPolygon.FromPolyLine( plPoly) ; + Vector3d vtPolyNorm = AuxPolygon.GetVersN() ; + Vector3d vtOut = vtTan ^ vtPolyNorm ; + Vector3d vtNextOut = vtNextTan ^ vtPolyNorm ; + // Caso concavo + if ( vtNextTan * vtOut > 0) { + Vector3d vtTest = ptP - ptMinDist ; + if ( vtTest * vtOut < 0 || vtTest * vtNextOut < 0) + return true ; + } + // Caso convesso + else { + Vector3d vtTest = ptP - ptMinDist ; + if ( vtTest * vtOut < 0 && vtTest * vtNextOut < 0) + return true ; + } + } + // Punto di minima distanza interno al segmeno + else { + Vector3d vtP = ptP - itMinDistSt->first ; + Vector3d vtTan = itMinDistEn->first - itMinDistSt->first ; + vtTan.Normalize() ; + Polygon3d AuxPolygon ; + AuxPolygon.FromPolyLine( plPoly) ; + Vector3d vtPolyNorm = AuxPolygon.GetVersN() ; + Vector3d vtOut = vtTan ^ vtPolyNorm ; + vtP -= ( vtP * vtTan) * vtTan ; + if ( vtP * vtOut < - EPS_SMALL) + return true ; + } + return false ; +} + +//---------------------------------------------------------------------------- +bool +DistPointPolyLine( const Point3d& ptP, const PolyLine& plPoly, double& dPointPolyLineDist) +{ + if ( plPoly.GetPointNbr() == 0) + return false ; + dPointPolyLineDist = DBL_MAX ; + Point3d ptSt, ptEn ; + bool bContinue = plPoly.GetFirstPoint( ptSt) && plPoly.GetNextPoint( ptEn) ; + while ( bContinue) { + double dPoinLineDist ; + DistPointLine PointLineDistCalc( ptP, ptSt, ptEn) ; + PointLineDistCalc.GetDist( dPoinLineDist) ; + if ( dPoinLineDist < dPointPolyLineDist) + dPointPolyLineDist = dPoinLineDist ; + ptSt = ptEn ; + bContinue = plPoly.GetNextPoint( ptEn) ; + } + return true ; +} + +//---------------------------------------------------------------------------- +// Una faccia di una trimesh ha una sola componente connessa. +// Si assume che i loop siano corretti e rispettino tale proprietà. +bool +DistPointFacet( const Point3d& ptP, /*const*/ POLYLINEVECTOR& vPolyVec, double& dPointFacetDist) +{ + // Vedo se la proiezione del punto sul piano della faccia è interno ad essa. + Point3d ptPlaneP ; + Vector3d vtPlaneN ; + double dPointPlaneSignedDist ; + Point3d ptProjP ; + bool bPointIsInside = true ; + for ( int nLoop = 0 ; nLoop < int( vPolyVec.size()) && bPointIsInside ; ++ nLoop) { + Plane3d plPlane ; + double dArea ; + if ( ! vPolyVec[nLoop].IsClosedAndFlat( plPlane, dArea)) + return false ; + if ( nLoop == 0) { + ptPlaneP = plPlane.GetPoint() ; + vtPlaneN = plPlane.GetVersN() ; + dPointPlaneSignedDist = ( ptP - ptPlaneP) * vtPlaneN ; + ptProjP = ptP + dPointPlaneSignedDist * vtPlaneN ; + } + if ( ! IsPointInsidePolyLine( ptProjP, vPolyVec[nLoop])) + bPointIsInside = false ; + } + // Se la proiezione del punto sul piano della faccia è interno, ho finito. + // La distanza del punto dalla faccia è pari alla distanza dello stesso dal piano + // in cui giace quest'ultima. + if ( bPointIsInside) { + dPointFacetDist = abs( dPointPlaneSignedDist) ; + return bPointIsInside ; + } + // Calcolo la minima distanza del punto dalle polilinee del contorno. + dPointFacetDist = DBL_MAX ; + for ( int nLoop = 0 ; nLoop < int( vPolyVec.size()) ; ++ nLoop) { + double dDist ; + if ( DistPointPolyLine( ptP, vPolyVec[nLoop], dDist) && dDist < dPointFacetDist) + dPointFacetDist = dDist ; + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +SplitPolyLineAtPoint( const Point3d& ptPoint, /*const*/ PolyLine& Loop, PolyLine& Loop1, PolyLine& Loop2) +{ + // Rinomino la lista di punti della PolyLine. + /*const*/ PNTULIST& LoopList = Loop.GetUPointList() ; + // Ciclo sui segmenti del loop per cercare il tratto del loop chiuso più vicino al punto. + double dMinSqDist = DBL_MAX ; + auto itMinDistSt = LoopList.end() ; + auto itSt = LoopList.begin() ; + auto itEn = itSt ; + ++ itEn ; + for ( ; itSt != LoopList.end() && itEn != LoopList.end() ; ++ itSt, ++ itEn) { + // Estremi del segmento corrente del loop + Point3d ptSegSt = itSt->first ; + Point3d ptSegEn = itEn->first ; + // Distanza del punto dal segmento del loop + DistPointLine dDistCalc( ptPoint, ptSegSt, ptSegEn) ; + double dSqDist ; + dDistCalc.GetSqDist( dSqDist) ; + if ( dSqDist < dMinSqDist) { + dMinSqDist = dSqDist ; + itMinDistSt = itSt ; + } + } + // Se il punto non sta sul loop, lo segnalo. + if ( dMinSqDist > 4 * SQ_EPS_SMALL) + return false ; + // Se il punto di stop sta su un vertice non devo aggiungerlo e il + // punto di stop sarà uno degli estremi del segmento su cui giace. + auto itStop = itMinDistSt ; + auto itNext = itMinDistSt ; + ++ itNext ; + if ( AreSamePointApprox( ptPoint, itStop->first)) + ; + else if ( AreSamePointApprox( ptPoint, itNext->first)) + itStop = itNext ; + else { + itStop = LoopList.emplace( itNext, ptPoint, 0.) ; + } + // Creo i due loop + PNTULIST& LoopList1 = Loop1.GetUPointList() ; + PNTULIST& LoopList2 = Loop2.GetUPointList() ; + for ( auto it = LoopList.begin() ; it != itStop ; ++ it) { + LoopList1.emplace_back( it->first, it->second) ; + } + LoopList1.emplace_back( itStop->first, itStop->second) ; + for ( auto it = itStop ; it != LoopList.end() ; ++ it) { + LoopList2.emplace_back( it->first, it->second) ; + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +AddPolyLineToPolyLine( PolyLine& Poly, PolyLine& PolyToAdd) +{ + // Se la PolyLine a cui devo aggiungere l'altra è chiusa, non posso aggiungere nulla. + if ( Poly.IsClosed()) + return false ; + // Se la PolyLina che devo aggiungere è vuota, ho finito. + PNTULIST& PolyToAddList = PolyToAdd.GetUPointList() ; + if ( int( PolyToAddList.size()) == 0) + return true ; + // Se Poly non è vuota e la sua fine non coincide con l'inizio di PolyToAdd, non è possibile aggiungere nulla. + Point3d ptLast ; + Poly.GetLastPoint( ptLast) ; + auto it = PolyToAddList.begin() ; + if ( Poly.GetPointNbr() != 0 && ! AreSamePointEpsilon( it->first, ptLast, 10 * EPS_SMALL)) + return false ; + /*if ( Poly.GetPointNbr() == 0) + Poly.AddUPoint( 0., it->first) ; + ++ it ;*/ + // Aggiungo i punti. + for ( ; it != PolyToAddList.end() ; ++ it) { + Poly.AddUPoint( 0., it->first) ; + } + return true ; +} diff --git a/SurfTriMesh.cpp b/SurfTriMesh.cpp index 88b6ca6..5edfc9b 100644 --- a/SurfTriMesh.cpp +++ b/SurfTriMesh.cpp @@ -3716,6 +3716,8 @@ SurfTriMesh::Cut( const Plane3d& plPlane, bool bSaveOnEq) return false ; } + SimplifyFacets( 500) ; + return true ; } diff --git a/SurfTriMesh.h b/SurfTriMesh.h index 1b15035..6e61c43 100644 --- a/SurfTriMesh.h +++ b/SurfTriMesh.h @@ -397,6 +397,7 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW bool RetriangulateFacetPieces( const PieceMap& NewFacet, const INTERSEDGEMAP& EdgeInterLineMap, const INTERSEDGEMAP& EdgeEdgeLineMap) ; + bool SimplifyFacets( double dMaxEdgeLen) ; bool EdgeInteriorContactManager( const SurfTriMesh& OthSurf, const INTERSCHAINMAP& InterInterLineMap, const INTERSEDGEMAP& EdgeInterLineMap) ; diff --git a/SurfTriMeshBooleans.cpp b/SurfTriMeshBooleans.cpp index 808a372..4ad3e40 100644 --- a/SurfTriMeshBooleans.cpp +++ b/SurfTriMeshBooleans.cpp @@ -124,118 +124,6 @@ IntersRectangleTriangle( const Point3d& ptP, const Vector3d& vtL1, const Vector3 return 0 ; } -//---------------------------------------------------------------------------- -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 ; -} - //---------------------------------------------------------------------------- static bool AddChainToChain( const Chain& ChainToAdd, PNTVECTOR& OrigChain) @@ -2826,370 +2714,6 @@ SurfTriMesh::IntersFacetFacet( const SurfFlatRegion& RegionA, const PolyLine& Ex // return bOk ; //} -//---------------------------------------------------------------------------- -static bool -ChangePolyLineStart( const Point3d& ptNewStart, PolyLine& Loop) -{ - // Rinomino la lista di punti della PolyLine. - PNTULIST& LoopList = Loop.GetUPointList() ; - // Ciclo sui segmenti del loop per cercare il tratto del loop chiuso più vicino al punto. - double dMinSqDist = DBL_MAX ; - auto itMinDist = LoopList.end() ; - auto itSt = LoopList.begin() ; - auto itEn = itSt ; - ++ itEn ; - for ( ; itSt != LoopList.end() && itEn != LoopList.end() ; ++ itSt, ++ itEn) { - // Estremi del segmento corrente del loop - Point3d ptSegSt = itSt->first ; - Point3d ptSegEn = itEn->first ; - // Distanza del punto dal segmento del loop - DistPointLine dDistCalc( ptNewStart, ptSegSt, ptSegEn) ; - double dSqDist ; - dDistCalc.GetSqDist( dSqDist) ; - if ( dSqDist < dMinSqDist) { - dMinSqDist = dSqDist ; - itMinDist = itSt ; - } - } - // Se il punto non sta sul loop, errore - if ( dMinSqDist > 4 * SQ_EPS_SMALL) - return false ; - // Se il punto non sta su un vertice del segmento, lo aggiungo. Altrimenti non devo fare nulla. - auto itNewPointSt = LoopList.begin() ; - auto itNext = itMinDist ; - ++ itNext ; - bool bOnStart = AreSamePointApprox( ptNewStart, itMinDist->first) ; - bool bOnEnd = AreSamePointApprox( ptNewStart, itNext->first) ; - itNewPointSt = LoopList.emplace( itNext, ptNewStart, 0) ; - // Sposto i punti precedenti in coda. - bool bStartRemoved = false ; - auto it = LoopList.begin() ; - while ( it != itNewPointSt) { - if ( bStartRemoved) { - LoopList.emplace_back( it->first, it->second) ; - } - bStartRemoved = true ; - it = LoopList.erase( it) ; - } - // Se il punto inserito non coincide con l'inizio del segmento chiudo il loop. - if ( ! bOnStart) { - LoopList.emplace_back( ptNewStart, 0) ; - // Se coincide con la fine tolgo il punto di fine che diviene inutile. - if ( bOnEnd) { - //LoopList.erase( itNext) ; - auto itNewStart = LoopList.begin() ; - ++ itNewStart ; - LoopList.erase( itNewStart) ; - } - } - - return true ; -} - -//---------------------------------------------------------------------------- -// nSegNum 0-based -static bool -PointPositionOnPolyLine( const Point3d& ptPoint, /*const*/ PolyLine& Loop, int& nSegNum, double& dParOnSeg) -{ - // Rinomino la lista di punti della PolyLine. - /*const*/ PNTULIST& LoopList = Loop.GetUPointList() ; - // Ciclo sui segmenti del loop per cercare il tratto del loop chiuso più vicino al punto. - nSegNum = - 1 ; - double dMinSqDist = DBL_MAX ; - int nS = 0 ; - auto itMinDistSt = LoopList.end() ; - auto itMinDistEn = itMinDistSt ; - auto itSt = LoopList.begin() ; - auto itEn = itSt ; - ++ itEn ; - for ( ; itSt != LoopList.end() && itEn != LoopList.end() ; ++ itSt, ++ itEn, ++ nS) { - // Estremi del segmento corrente del loop - Point3d ptSegSt = itSt->first ; - Point3d ptSegEn = itEn->first ; - // Distanza del punto dal segmento del loop - DistPointLine dDistCalc( ptPoint, ptSegSt, ptSegEn) ; - double dSqDist ; - dDistCalc.GetSqDist( dSqDist) ; - if ( dSqDist < dMinSqDist) { - nSegNum = nS ; - dMinSqDist = dSqDist ; - itMinDistSt = itSt ; - itMinDistEn = itEn ; - } - } - // Se il punto non sta sul loop, lo segnalo. - if ( dMinSqDist > 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 ; -} - -//---------------------------------------------------------------------------- -static bool -IsPointInsidePolyLine( const Point3d& ptP, /*const*/ PolyLine& plPoly) -{ - // Se la PolyLine non è chiusa, il punto non può essere interno. - if ( ! plPoly.IsClosed()) - return false ; - // Lista dei punti - /*const*/ PNTULIST& List = plPoly.GetUPointList() ; - // Ciclo sui segmenti della PolyLine per cercarne il tratto più vicino al punto. - double dMinSqDist = DBL_MAX ; - Point3d ptMinDist ; - auto itMinDistSt = List.end() ; - auto itSt = List.begin() ; - auto itEn = itSt ; - ++ itEn ; - for ( ; itSt != List.end() && itEn != List.end() ; ++ itSt, ++ itEn) { - // Estremi del segmento corrente del loop - Point3d ptSegSt = itSt->first ; - Point3d ptSegEn = itEn->first ; - // Distanza del punto dal segmento del loop - DistPointLine dDistCalc( ptP, ptSegSt, ptSegEn) ; - double dSqDist ; - dDistCalc.GetSqDist( dSqDist) ; - if ( dSqDist < dMinSqDist) { - dMinSqDist = dSqDist ; - dDistCalc.GetMinDistPoint( ptMinDist) ; - itMinDistSt = itSt ; - } - } - // Termine del segmento di minima distanza. - auto itMinDistEn = itMinDistSt ; - ++ itMinDistEn ; - // Punto di minima distanza nell'estremo iniziale del segento - if ( AreSamePointApprox( ptMinDist, itMinDistSt->first)) { - auto itPrevSt = List.begin() ; - if ( itMinDistSt == List.begin()) { - auto itAuxNext = itPrevSt ; - ++ ( ++ itAuxNext) ; - for ( ; itAuxNext != List.end() ; ++ itPrevSt, ++ itAuxNext) - ; - } - else { - auto itAuxNext = itPrevSt ; - ++ itAuxNext ; - for (; itAuxNext != itMinDistSt; ++itPrevSt, ++itAuxNext) - ; - } - Vector3d vtPrevTan = itMinDistSt->first - itPrevSt->first ; - vtPrevTan.Normalize() ; - Vector3d vtTan = itMinDistEn->first - itMinDistSt->first ; - vtTan.Normalize() ; - Polygon3d AuxPolygon ; - AuxPolygon.FromPolyLine( plPoly) ; - Vector3d vtPolyNorm = AuxPolygon.GetVersN() ; - Vector3d vtPrevOut = vtPrevTan ^ vtPolyNorm ; - Vector3d vtOut = vtTan ^ vtPolyNorm ; - // Caso concavo - if ( vtTan * vtPrevOut > 0) { - Vector3d vtTest = ptP - ptMinDist ; - if ( vtTest * vtPrevOut < 0 || vtTest * vtOut < 0) - return true ; - } - // Caso convesso - else { - Vector3d vtTest = ptP - ptMinDist ; - if ( vtTest * vtPrevOut < 0 && vtTest * vtOut < 0) - return true ; - } - } - // Punto di minima distanza nell'estremo finale del segento - else if ( AreSamePointApprox( ptMinDist, itMinDistEn->first)) { - auto itNextEn = itMinDistEn ; - ++ itNextEn ; - if ( itNextEn == List.end()) { - itNextEn = List.begin() ; - ++ itNextEn ; - } - Vector3d vtTan = itMinDistEn->first - itMinDistSt->first ; - vtTan.Normalize() ; - Vector3d vtNextTan = itNextEn->first - itMinDistEn->first ; - vtNextTan.Normalize() ; - Polygon3d AuxPolygon ; - AuxPolygon.FromPolyLine( plPoly) ; - Vector3d vtPolyNorm = AuxPolygon.GetVersN() ; - Vector3d vtOut = vtTan ^ vtPolyNorm ; - Vector3d vtNextOut = vtNextTan ^ vtPolyNorm ; - // Caso concavo - if ( vtNextTan * vtOut > 0) { - Vector3d vtTest = ptP - ptMinDist ; - if ( vtTest * vtOut < 0 || vtTest * vtNextOut < 0) - return true ; - } - // Caso convesso - else { - Vector3d vtTest = ptP - ptMinDist ; - if ( vtTest * vtOut < 0 && vtTest * vtNextOut < 0) - return true ; - } - } - // Punto di minima distanza interno al segmeno - else { - Vector3d vtP = ptP - itMinDistSt->first ; - Vector3d vtTan = itMinDistEn->first - itMinDistSt->first ; - vtTan.Normalize() ; - Polygon3d AuxPolygon ; - AuxPolygon.FromPolyLine( plPoly) ; - Vector3d vtPolyNorm = AuxPolygon.GetVersN() ; - Vector3d vtOut = vtTan ^ vtPolyNorm ; - vtP -= ( vtP * vtTan) * vtTan ; - if ( vtP * vtOut < - EPS_SMALL) - return true ; - } - return false ; -} - -//---------------------------------------------------------------------------- -bool -DistPointPolyLine( const Point3d& ptP, const PolyLine& plPoly, double& dPointPolyLineDist) -{ - if ( plPoly.GetPointNbr() == 0) - return false ; - dPointPolyLineDist = DBL_MAX ; - Point3d ptSt, ptEn ; - bool bContinue = plPoly.GetFirstPoint( ptSt) && plPoly.GetNextPoint( ptEn) ; - while ( bContinue) { - double dPoinLineDist ; - DistPointLine PointLineDistCalc( ptP, ptSt, ptEn) ; - PointLineDistCalc.GetDist( dPoinLineDist) ; - if ( dPoinLineDist < dPointPolyLineDist) - dPointPolyLineDist = dPoinLineDist ; - ptSt = ptEn ; - bContinue = plPoly.GetNextPoint( ptEn) ; - } - return true ; -} - -//---------------------------------------------------------------------------- -// Una faccia di una trimesh ha una sola componente connessa. -// Si assume che i loop siano corretti e rispettino tale proprietà. -bool -DistPointFacet( const Point3d& ptP, /*const*/ POLYLINEVECTOR& vPolyVec, double& dPointFacetDist) -{ - // Vedo se la proiezione del punto sul piano della faccia è interno ad essa. - Point3d ptPlaneP ; - Vector3d vtPlaneN ; - double dPointPlaneSignedDist ; - Point3d ptProjP ; - bool bPointIsInside = true ; - for ( int nLoop = 0 ; nLoop < int( vPolyVec.size()) && bPointIsInside ; ++ nLoop) { - Plane3d plPlane ; - double dArea ; - if ( ! vPolyVec[nLoop].IsClosedAndFlat( plPlane, dArea)) - return false ; - if ( nLoop == 0) { - ptPlaneP = plPlane.GetPoint() ; - vtPlaneN = plPlane.GetVersN() ; - dPointPlaneSignedDist = ( ptP - ptPlaneP) * vtPlaneN ; - ptProjP = ptP + dPointPlaneSignedDist * vtPlaneN ; - } - if ( ! IsPointInsidePolyLine( ptProjP, vPolyVec[nLoop])) - bPointIsInside = false ; - } - // Se la proiezione del punto sul piano della faccia è interno, ho finito. - // La distanza del punto dalla faccia è pari alla distanza dello stesso dal piano - // in cui giace quest'ultima. - if ( bPointIsInside) { - dPointFacetDist = abs( dPointPlaneSignedDist) ; - return bPointIsInside ; - } - // Calcolo la minima distanza del punto dalle polilinee del contorno. - dPointFacetDist = DBL_MAX ; - for ( int nLoop = 0 ; nLoop < int( vPolyVec.size()) ; ++ nLoop) { - double dDist ; - if ( DistPointPolyLine( ptP, vPolyVec[nLoop], dDist) && dDist < dPointFacetDist) - dPointFacetDist = dDist ; - } - return true ; -} - -//---------------------------------------------------------------------------- -static bool -SplitPolyLineAtPoint( const Point3d& ptPoint, /*const*/ PolyLine& Loop, PolyLine& Loop1, PolyLine& Loop2) -{ - // Rinomino la lista di punti della PolyLine. - /*const*/ PNTULIST& LoopList = Loop.GetUPointList() ; - // Ciclo sui segmenti del loop per cercare il tratto del loop chiuso più vicino al punto. - double dMinSqDist = DBL_MAX ; - auto itMinDistSt = LoopList.end() ; - auto itSt = LoopList.begin() ; - auto itEn = itSt ; - ++ itEn ; - for ( ; itSt != LoopList.end() && itEn != LoopList.end() ; ++ itSt, ++ itEn) { - // Estremi del segmento corrente del loop - Point3d ptSegSt = itSt->first ; - Point3d ptSegEn = itEn->first ; - // Distanza del punto dal segmento del loop - DistPointLine dDistCalc( ptPoint, ptSegSt, ptSegEn) ; - double dSqDist ; - dDistCalc.GetSqDist( dSqDist) ; - if ( dSqDist < dMinSqDist) { - dMinSqDist = dSqDist ; - itMinDistSt = itSt ; - } - } - // Se il punto non sta sul loop, lo segnalo. - if ( dMinSqDist > 4 * SQ_EPS_SMALL) - return false ; - // Se il punto di stop sta su un vertice non devo aggiungerlo e il - // punto di stop sarà uno degli estremi del segmento su cui giace. - auto itStop = itMinDistSt ; - auto itNext = itMinDistSt ; - ++ itNext ; - if ( AreSamePointApprox( ptPoint, itStop->first)) - ; - else if ( AreSamePointApprox( ptPoint, itNext->first)) - itStop = itNext ; - else { - itStop = LoopList.emplace( itNext, ptPoint, 0.) ; - } - // Creo i due loop - PNTULIST& LoopList1 = Loop1.GetUPointList() ; - PNTULIST& LoopList2 = Loop2.GetUPointList() ; - for ( auto it = LoopList.begin() ; it != itStop ; ++ it) { - LoopList1.emplace_back( it->first, it->second) ; - } - LoopList1.emplace_back( itStop->first, itStop->second) ; - for ( auto it = itStop ; it != LoopList.end() ; ++ it) { - LoopList2.emplace_back( it->first, it->second) ; - } - return true ; -} - -//---------------------------------------------------------------------------- -static bool -AddPolyLineToPolyLine( PolyLine& Poly, PolyLine& PolyToAdd) -{ - // Se la PolyLine a cui devo aggiungere l'altra è chiusa, non posso aggiungere nulla. - if ( Poly.IsClosed()) - return false ; - // Se la PolyLina che devo aggiungere è vuota, ho finito. - PNTULIST& PolyToAddList = PolyToAdd.GetUPointList() ; - if ( int( PolyToAddList.size()) == 0) - return true ; - // Se Poly non è vuota e la sua fine non coincide con l'inizio di PolyToAdd, non è possibile aggiungere nulla. - Point3d ptLast ; - Poly.GetLastPoint( ptLast) ; - auto it = PolyToAddList.begin() ; - if ( Poly.GetPointNbr() != 0 && ! AreSamePointEpsilon( it->first, ptLast, 10 * EPS_SMALL)) - return false ; - /*if ( Poly.GetPointNbr() == 0) - Poly.AddUPoint( 0., it->first) ; - ++ it ;*/ - // Aggiungo i punti. - for ( ; it != PolyToAddList.end() ; ++ it) { - Poly.AddUPoint( 0., it->first) ; - } - return true ; -} - //---------------------------------------------------------------------------- struct PositionOnPolyLine { int nIndexInVec ; diff --git a/SurfTriMeshUtilities.cpp b/SurfTriMeshUtilities.cpp new file mode 100644 index 0000000..3febb65 --- /dev/null +++ b/SurfTriMeshUtilities.cpp @@ -0,0 +1,229 @@ +//---------------------------------------------------------------------------- +// EgalTech 2015-2015 +//---------------------------------------------------------------------------- +// File : SurfTriMeshUtilities.cpp Data : 25.10.21 Versione : +// Contenuto : Implementazione della classe Superfici TriMesh. +// +// +// +// Modifiche : 25.10.21 LM Creazione modulo. +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "Triangulate.h" +#include "SurfTriMesh.h" +#include "DistPointLine.h" +#include + +using namespace std ; + +//---------------------------------------------------------------------------- +bool +SurfTriMesh::SimplifyFacets( double dMaxEdgeLen) +{ + // Se la lunghezza massima del lato del triangolo sul bordo della faccia è nulla, ho finito. + if ( dMaxEdgeLen < EPS_SMALL) + return true ; + + // Le superfici devono essere valide. + if ( ! IsValid()) + return false ; + + // Verifico la definizione delle facce. + VerifyFaceting() ; + + // 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. + POLYLINEVECTOR LoopVec ; + GetFacetLoops( nF, LoopVec) ; + // Recupero le adiacenze della faccia. + INTMATRIX vAdj ; + GetFacetAdjacencies( nF, vAdj) ; + // Ciclo sui loop della faccia. + for ( int nL = 0 ; nL < int( LoopVec.size()) ; ++ nL) { + // 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) { + //ChangePolyLineStart( it->first, LoopVec[nL]) ; + { + // 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()) { + //ChangePolyLineStart( it->first, LoopVec[nL]) ; + { + // 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 ; + } + } + } + } + } + if ( bFacetToRetriangulate) { + FacetMap.emplace( nF, LoopVec) ; + } + } + + // Ciclo sulle facce da ritriangolare per eliminare i triangoli. + for ( auto itF = FacetMap.begin() ; itF != FacetMap.end() ; ++ itF) { + // Cancello i triangoli della faccia. + INTVECTOR vFacetTria ; + GetAllTriaInFacet( itF->first, vFacetTria) ; + 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) ; + } + } + } + + return AdjustVertices() && DoCompacting() ; +} \ No newline at end of file