//---------------------------------------------------------------------------- // EgalTech 2013-2013 //---------------------------------------------------------------------------- // File : PolyLine.cpp Data : 22.12.13 Versione : 1.4l3 // Contenuto : Implementazione della classe PolyLine. // // // // Modifiche : 22.12.13 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "CurveLine.h" #include "DistPointLine.h" #include "IntersLineLine.h" #include "PolygonPlane.h" #include "PointsPCA.h" #include "/EgtDev/Include/EGkPolyLine.h" #include "/EgtDev/Include/EGkPlane3d.h" #include "/EgtDev/Include/EGnStringUtils.h" using namespace std ; //---------------------------------------------------------------------------- PolyLine::PolyLine( void) { m_nRejected = 0 ; m_iter = m_lUPoints.end() ; } //---------------------------------------------------------------------------- PolyLine::~PolyLine( void) { } //---------------------------------------------------------------------------- bool PolyLine::Clear( void) { m_nRejected = 0 ; m_lUPoints.clear() ; m_iter = m_lUPoints.end() ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::AddUPoint( double dPar, const Point3d& ptP) { // se il punto è uguale al precedente (ignoro parametro), non lo inserisco ma ok if ( m_lUPoints.size() > 0 && AreSamePointApprox( ptP, m_lUPoints.back().first)) { ++ m_nRejected ; return true ; } // eseguo inserimento try { m_lUPoints.emplace_back( ptP, dPar) ; } catch (...) { return false ; } return true ; } //---------------------------------------------------------------------------- bool PolyLine::Close( void) { // ci devono essere almeno 2 punti if ( m_lUPoints.size() < 2) return false ; // verifico non sia già chiuso if ( AreSamePointApprox( m_lUPoints.front().first, m_lUPoints.back().first)) return false ; // aggiungo un punto uguale al primo in coda return AddUPoint( m_lUPoints.front().second, m_lUPoints.front().first) ; } //---------------------------------------------------------------------------- bool PolyLine::EraseFirstUPoint( void) { if ( m_lUPoints.empty()) return false ; m_lUPoints.pop_front() ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::EraseLastUPoint( void) { if ( m_lUPoints.empty()) return false ; m_lUPoints.pop_back() ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::AddOffsetToU( double dOffset) { PNTULIST::iterator iter ; for ( iter = m_lUPoints.begin() ; iter != m_lUPoints.end() ; ++ iter) iter->second += dOffset ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::Translate( const Vector3d& vtMove) { PNTULIST::iterator iter ; for ( iter = m_lUPoints.begin() ; iter != m_lUPoints.end() ; ++ iter) iter->first.Translate( vtMove) ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::Rotate( const Point3d& ptAx, const Vector3d& vtAx, double dCosAng, double dSinAng) { PNTULIST::iterator iter ; for ( iter = m_lUPoints.begin() ; iter != m_lUPoints.end() ; ++ iter) iter->first.Rotate( ptAx, vtAx, dCosAng, dSinAng) ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::Scale( const Frame3d& frRef, double dCoeffX, double dCoeffY, double dCoeffZ) { PNTULIST::iterator iter ; for ( iter = m_lUPoints.begin() ; iter != m_lUPoints.end() ; ++ iter) iter->first.Scale( frRef, dCoeffX, dCoeffY, dCoeffZ) ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::Mirror( const Point3d& ptOn, const Vector3d& vtNorm) { PNTULIST::iterator iter ; for ( iter = m_lUPoints.begin() ; iter != m_lUPoints.end() ; ++ iter) iter->first.Mirror( ptOn, vtNorm) ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::Shear( const Point3d& ptOn, const Vector3d& vtNorm, const Vector3d& vtDir, double dCoeff) { PNTULIST::iterator iter ; for ( iter = m_lUPoints.begin() ; iter != m_lUPoints.end() ; ++ iter) iter->first.Shear( ptOn, vtNorm, vtDir, dCoeff) ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::ToGlob( const Frame3d& frRef) { PNTULIST::iterator iter ; for ( iter = m_lUPoints.begin() ; iter != m_lUPoints.end() ; ++ iter) iter->first.ToGlob( frRef) ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::ToLoc( const Frame3d& frRef) { PNTULIST::iterator iter ; for ( iter = m_lUPoints.begin() ; iter != m_lUPoints.end() ; ++ iter) iter->first.ToLoc( frRef) ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::LocToLoc( const Frame3d& frOri, const Frame3d& frDest) { // se i due riferimenti coincidono, non devo fare alcunché if ( AreSameFrame( frOri, frDest)) return true ; // ciclo sui punti PNTULIST::iterator iter ; for ( iter = m_lUPoints.begin() ; iter != m_lUPoints.end() ; ++ iter) iter->first.LocToLoc( frOri, frDest) ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::Join( PolyLine& PL, double dOffsetPar) { // se l'altra polilinea non contiene alcunchè, esco con ok if ( PL.m_lUPoints.size() == 0) return true ; // verifico che l'ultimo punto di questa polilinea coincida con il primo dell'altra if ( m_lUPoints.size() > 0 && ! AreSamePointApprox( m_lUPoints.back().first, PL.m_lUPoints.front().first)) return false ; // cancello l'ultimo di questa EraseLastUPoint() ; // aggiungo eventuale offset all'altra if ( fabs( dOffsetPar) > EPS_PARAM) PL.AddOffsetToU( dOffsetPar) ; // sposto i punti dall'altra polilinea a questa m_lUPoints.splice( m_lUPoints.end(), PL.m_lUPoints) ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::Split( double dU, PolyLine& PL) { // pulisco la polilinea destinazione PL.Clear() ; // ricerca del punto in cui dividere PNTULIST::const_iterator iter ; iter = m_lUPoints.begin() ; while ( iter != m_lUPoints.end() && iter->second < ( dU + EPS_PARAM)) ++ iter ; if ( iter == m_lUPoints.end()) return false ; // sposto i punti nell'altra polilinea PL.m_lUPoints.splice( PL.m_lUPoints.end(), m_lUPoints, iter, m_lUPoints.end()) ; // prepongo l'ultimo punto rimasto PL.m_lUPoints.push_front( m_lUPoints.back()) ; // annullo l'iteratore corrente m_iter = m_lUPoints.end() ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::GetLocalBBox( BBox3d& b3Loc) const { // assegno il box in locale, scorrendo tutti i punti b3Loc.Reset() ; for ( PNTULIST::const_iterator iter = m_lUPoints.begin() ; iter != m_lUPoints.end() ; ++ iter) b3Loc.Add( iter->first) ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::IsClosed( void) const { if ( m_lUPoints.size() < 3) return false ; return ( AreSamePointApprox( m_lUPoints.front().first, m_lUPoints.back().first)) ; } //---------------------------------------------------------------------------- bool PolyLine::GetFirstUPoint( double* pdPar, Point3d* pptP, bool bNotLast) const { m_iter = m_lUPoints.begin() ; if ( m_iter == m_lUPoints.end()) return false ; if ( bNotLast && m_iter == -- ( m_lUPoints.end())) { m_iter = m_lUPoints.end() ; return false ; } if ( pdPar != nullptr) *pdPar = m_iter->second ; if ( pptP != nullptr) *pptP = m_iter->first ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::GetNextUPoint( double* pdPar, Point3d* pptP, bool bNotLast) const { if ( m_iter == m_lUPoints.end()) return false ; ++ m_iter ; if ( m_iter == m_lUPoints.end()) return false ; if ( bNotLast && m_iter == -- ( m_lUPoints.end())) { m_iter = m_lUPoints.end() ; return false ; } if ( pdPar != nullptr) *pdPar = m_iter->second ; if ( pptP != nullptr) *pptP = m_iter->first ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::GetLastUPoint( double* pdPar, Point3d* pptP, bool bNotFirst) const { m_iter = m_lUPoints.end() ; if ( m_iter == m_lUPoints.begin()) return false ; -- m_iter ; if ( m_iter == m_lUPoints.end()) return false ; if ( bNotFirst && m_iter == m_lUPoints.begin()) { m_iter = m_lUPoints.end() ; return false ; } if ( pdPar != nullptr) *pdPar = m_iter->second ; if ( pptP != nullptr) *pptP = m_iter->first ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::GetPrevUPoint( double* pdPar, Point3d* pptP, bool bNotFirst) const { if ( m_iter == m_lUPoints.begin()) return false ; -- m_iter ; if ( m_iter == m_lUPoints.end()) return false ; if ( bNotFirst && m_iter == m_lUPoints.begin()) { m_iter = m_lUPoints.end() ; return false ; } if ( pdPar != nullptr) *pdPar = m_iter->second ; if ( pptP != nullptr) *pptP = m_iter->first ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::GetCurrUPoint( double* pdPar, Point3d* pptP) const { // verifico validità punto corrente if ( m_iter == m_lUPoints.end()) return false ; if ( pdPar != nullptr) *pdPar = m_iter->second ; if ( pptP != nullptr) *pptP = m_iter->first ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::GetFirstULine( double* pdIni, Point3d* pptIni, double* pdFin, Point3d* pptFin) const { // parametro e punto iniziali m_iter = m_lUPoints.begin() ; if ( m_iter == m_lUPoints.end()) return false ; if ( pdIni != nullptr) *pdIni = m_iter->second ; if ( pptIni != nullptr) *pptIni = m_iter->first ; // parametro e punto finali ++ m_iter ; if ( m_iter == m_lUPoints.end()) return false ; if ( pdFin != nullptr) *pdFin = m_iter->second ; if ( pptFin != nullptr) *pptFin = m_iter->first ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::GetNextULine( double* pdIni, Point3d* pptIni, double* pdFin, Point3d* pptFin) const { // parametro e punto iniziali (è il precedente finale) if ( m_iter == m_lUPoints.end()) return false ; if ( pdIni != nullptr) *pdIni = m_iter->second ; if ( pptIni != nullptr) *pptIni = m_iter->first ; // parametro e punto finali ++ m_iter ; if ( m_iter == m_lUPoints.end()) return false ; if ( pdFin != nullptr) *pdFin = m_iter->second ; if ( pptFin != nullptr) *pptFin = m_iter->first ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::GetLastULine( double* pdIni, Point3d* pptIni, double* pdFin, Point3d* pptFin) const { // parametro e punto finali m_iter = m_lUPoints.end() ; if ( m_iter == m_lUPoints.begin()) return false ; -- m_iter ; if ( m_iter == m_lUPoints.end()) return false ; if ( pdFin != nullptr) *pdFin = m_iter->second ; if ( pptFin != nullptr) *pptFin = m_iter->first ; // parametro e punto iniziali if ( m_iter == m_lUPoints.begin()) return false ; -- m_iter ; if ( pdIni != nullptr) *pdIni = m_iter->second ; if ( pptIni != nullptr) *pptIni = m_iter->first ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::GetPrevULine( double* pdIni, Point3d* pptIni, double* pdFin, Point3d* pptFin) const { // parametro e punto finali if ( m_iter == m_lUPoints.end()) return false ; if ( pdFin != nullptr) *pdFin = m_iter->second ; if ( pptFin != nullptr) *pptFin = m_iter->first ; // parametro e punto iniziali if ( m_iter == m_lUPoints.begin()) return false ; -- m_iter ; if ( pdIni != nullptr) *pdIni = m_iter->second ; if ( pptIni != nullptr) *pptIni = m_iter->first ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::IsFlat( int& nRank, Point3d& ptCen, Vector3d& vtDir, double dToler) const { // cerco le componenti principali (tramite PCA) Point3d ptP ; PointsPCA ptsPCA ; for ( bool bFound = GetFirstPoint( ptP) ; bFound ; bFound = GetNextPoint( ptP)) ptsPCA.AddPoint( ptP) ; // recupero il rango, ovvero la dimensionalità dell'insieme di punti nRank = ptsPCA.GetRank() ; // se dimensione nulla, o non ci sono punti o sono tutti praticamente coincidenti if ( nRank == 0) return ptsPCA.GetCenter( ptCen) ; // se dimensione 1, allora i punti sono distribuiti su una linea if ( nRank == 1) { // assegno il centro e la direzione della linea (il verso è indifferente) ptsPCA.GetCenter( ptCen) ; ptsPCA.GetPrincipalComponent( 0, vtDir) ; return true ; } // altrimenti dimensione 2 o 3, allora è determinato un piano principale, verifico se tutti i punti vi giacciono // Center and normal vector ptsPCA.GetCenter( ptCen) ; Vector3d vtX, vtY ; ptsPCA.GetPrincipalComponent( 0, vtX) ; ptsPCA.GetPrincipalComponent( 1, vtY) ; vtDir = vtX ^ vtY ; if ( ! vtDir.Normalize()) { // riduco la dimensionalità a lineare nRank = 1 ; // assegno il centro e la direzione della linea (il verso è indifferente) ptsPCA.GetCenter( ptCen) ; vtDir = vtX ; return true ; } if ( vtDir.z < 0) vtDir.Invert() ; // Plane calculation Plane3d plPlane ; plPlane.vtN = vtDir ; plPlane.dDist = ( ptCen - ORIG) * plPlane.vtN ; // Test each vertex to see if it is farther from plane than allowed max distance for ( bool bFound = GetFirstPoint( ptP) ; bFound ; bFound = GetNextPoint( ptP)) { double dDist = ( ( ptP - ORIG) * plPlane.vtN) - plPlane.dDist ; if ( fabs( dDist) > dToler) return false ; } return true ; } //---------------------------------------------------------------------------- bool PolyLine::IsClosedAndFlat( Plane3d& plPlane, double& dArea, double dToler) const { // Test if closed if ( ! IsClosed()) return false ; // Compute a representative plane for the polygon Point3d ptP ; PolygonPlane PolyPlane ; for ( bool bFound = GetFirstPoint( ptP) ; bFound ; bFound = GetNextPoint( ptP)) PolyPlane.AddPoint( ptP) ; if ( ! PolyPlane.GetPlane( plPlane) || ! PolyPlane.GetArea( dArea)) return false ; // Test each vertex to see if it is farther from plane than allowed max distance for ( bool bFound = GetFirstPoint( ptP) ; bFound ; bFound = GetNextPoint( ptP)) { double dDist = ( ( ptP - ORIG) * plPlane.vtN) - plPlane.dDist ; if ( fabs( dDist) > dToler) return false ; } // All points passed distance test, so polygon is considered planar return true ; } //---------------------------------------------------------------------------- bool PolyLine::GetApproxLength( double& dLen) const { // calcolo la lunghezza approssimata come somma di ogni singolo tratto lineare dLen = 0 ; Point3d ptIni, ptFin ; for ( bool bFound = GetFirstLine( ptIni, ptFin) ; bFound ; bFound = GetNextLine( ptIni, ptFin)) { dLen += ApproxDist( ptIni, ptFin) ; } return ( dLen > EPS_ZERO) ; } //---------------------------------------------------------------------------- bool PolyLine::GetLength( double& dLen) const { // calcolo la lunghezza come somma di ogni singolo tratto lineare dLen = 0 ; Point3d ptIni, ptFin ; for ( bool bFound = GetFirstLine( ptIni, ptFin) ; bFound ; bFound = GetNextLine( ptIni, ptFin)) { dLen += Dist( ptIni, ptFin) ; } return ( dLen > EPS_ZERO) ; } //---------------------------------------------------------------------------- bool PolyLine::GetAreaXY( double& dArea) const { // verifico sia chiusa if ( ! IsClosed()) return false ; // calcolo l'area considerando solo XY (è la Z di Newell) dArea = 0 ; Point3d ptIni, ptFin ; for ( bool bFound = GetFirstLine( ptIni, ptFin) ; bFound ; bFound = GetNextLine( ptIni, ptFin)) { dArea += ( ptIni.x - ptFin.x) * ( ptIni.y + ptFin.y) ; // projection on xy } dArea = 0.5 * dArea ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::GetMaxDistanceFromLine( const Point3d& ptLine, const Vector3d& vtLine, double dLen, double& dMaxDist, bool bIsSegment) const { // Verifico che la polilinea esista if ( GetPointNbr() < 1) return false ; // Calcolo la distanza di ogni punto dalla linea dMaxDist = 0 ; Point3d ptP ; for ( bool bFound = GetFirstPoint( ptP) ; bFound ; bFound = GetNextPoint( ptP)) { DistPointLine dstPL( ptP, ptLine, vtLine, dLen, bIsSegment) ; double dDist ; if ( dstPL.GetDist( dDist) && dDist > dMaxDist) dMaxDist = dDist ; } return true ; } //---------------------------------------------------------------------------- bool PolyLine::AdjustForMaxSegmentLen( double dMaxLen) { PNTULIST::iterator iter = m_lUPoints.begin() ; // se non ci sono punti, esco subito if ( iter == m_lUPoints.end()) return false ; // imposto il primo punto come precedente double dUprec = iter->second ; Point3d ptPprec = iter->first ; // passo al secondo ++ iter ; // ciclo sui punti try { while ( iter != m_lUPoints.end()) { // recupero dati correnti double dUcurr = iter->second ; Point3d ptPcurr = iter->first ; // verifico lunghezza segmento dal precedente double dSqLen = SqDist( ptPprec, ptPcurr) ; if ( dSqLen > dMaxLen * dMaxLen) { double dLen = sqrt( dSqLen) ; // determino il numero di divisioni int nStep = int( dLen / dMaxLen + 0.999) ; // inserisco i punti necessari for ( int i = 1 ; i < nStep ; ++ i) { double dCoeff = double( i) / nStep ; m_lUPoints.insert( iter, POINTU( Media( ptPprec, ptPcurr, dCoeff), (( 1 - dCoeff) * dUprec + dCoeff * dUcurr))) ; } } // passo al successivo dUprec = dUcurr ; ptPprec = ptPcurr ; ++ iter ; } } catch (...) { return false ; } return true ; } //---------------------------------------------------------------------------- bool PolyLine::RemoveAlignedPoints( double dToler) { // se non ci sono almeno 3 punti, esco subito if ( m_lUPoints.size() < 3) return true ; // coefficiente deduzione tolleranza const double COEFF_TOL = 0.7 ; // si analizza la distanza di un punto dal segmento che unisce precente e successivo // punto precedente auto precP = m_lUPoints.begin() ; // punto corrente auto currP = next( precP) ; // punto successivo auto nextP = next( currP) ; // assegno la tolleranza corrente double dCurrToler = dToler ; // mentre esiste un successivo while ( nextP != m_lUPoints.end()) { // distanza del punto corrente dal segmento che unisce gli adiacenti DistPointLine dPL( currP->first, precP->first, nextP->first) ; double dSqDist ; // se da eliminare if ( dPL.GetSqDist( dSqDist) && dSqDist < dCurrToler * dCurrToler) { // diminuisco la tolleranza corrente dell'errore attuale dCurrToler -= COEFF_TOL * sqrt( dSqDist) ; // elimino il punto m_lUPoints.erase( currP) ; // avanzo con corrente e successivo currP = nextP ; ++ nextP ; } // altrimenti da tenere else { // ripristino la tolleranza corrente dCurrToler = dToler ; // avanzo il terzetto di uno step precP = currP ; currP = nextP ; ++ nextP ; } } // se curva chiusa con almeno 4 punti, devo analizzare il terzetto attorno alla chiusura if ( IsClosed() && m_lUPoints.size() >= 4) { // precP e currP sono già corretti // il primo punto ripete l'ultimo (geometricamente coincide con currP) auto firstP = m_lUPoints.begin() ; // questo è il vero successivo nextP = next( firstP) ; // distanza del punto corrente dal segmento che unisce gli adiacenti DistPointLine dPL( currP->first, precP->first, nextP->first) ; double dSqDist ; // se da eliminare if ( dPL.GetSqDist( dSqDist) && dSqDist < dCurrToler * dCurrToler) { // faccio coincidere il primo punto con il precedente firstP->first = precP->first ; // elimino il punto corrente m_lUPoints.erase( currP) ; } } return true ; } //---------------------------------------------------------------------------- bool PolyLine::ApproxOnSide( const Vector3d& vtN, bool bLeftSide, double dToler) { // se non ci sono almeno 3 punti, esco subito if ( m_lUPoints.size() < 3) return true ; // coefficienti deduzione tolleranza const double COEFF_TOL = 0.90 ; // punto precedente auto precP = m_lUPoints.begin() ; // punto corrente auto currP = next( precP) ; // punto successivo auto nextP = next( currP) ; // assegno la tolleranza corrente double dCurrToler = dToler ; // mentre esiste un successivo while ( nextP != m_lUPoints.end()) { // --- si verifica se possibile eliminare il punto corrente rimanendo dal lato voluto e in tolleranza --- // distanza del punto corrente dal segmento che unisce gli adiacenti DistPointLine dPL( currP->first, precP->first, nextP->first) ; double dSqDist = INFINITO * INFINITO ; dPL.GetSqDist( dSqDist) ; // se punti allineati if ( dSqDist < EPS_SMALL * EPS_SMALL) { // ripristino la tolleranza corrente dCurrToler = dToler ; // elimino il corrente m_lUPoints.erase( currP) ; // avanzo con corrente e successivo currP = nextP ; ++ nextP ; continue ; } // se lato sinistro e gira a sinistra o lato destro e gira a destra double dCrossXY = ( ( currP->first - precP->first) ^ ( nextP->first - currP->first)) * vtN ; if ( ( bLeftSide && dCrossXY > 0) || ( ! bLeftSide && dCrossXY < 0)) { // se eliminabile if ( dSqDist < dCurrToler * dCurrToler) { // diminuisco la tolleranza corrente dell'errore attuale dCurrToler -= COEFF_TOL * sqrt( dSqDist) ; // elimino il punto corrente m_lUPoints.erase( currP) ; // avanzo con corrente e successivo currP = nextP ; ++ nextP ; continue ; } } // --- si verifica se possibile elimare segmento da corrente a successivo rimanendo in tolleranza e dal lato voluto --- // punto successivo del successivo auto nex2P = next( nextP) ; if ( nex2P != m_lUPoints.end()) { double dCros2XY = ( ( nextP->first - currP->first) ^ ( nex2P->first - nextP->first)) * vtN ; // se lato sinistro e 2 giri a destra o lato destro e 2 giri a sinistra if ( ( bLeftSide && dCrossXY < 0 && dCros2XY < 0) || ( ! bLeftSide && dCrossXY > 0 && dCros2XY > 0)) { // calcolo del punto di intersezione tra i segmenti precP-currP e nextP-next2P, allungati al centro CurveLine Line1, Line2 ; if ( Line1.Set( precP->first, currP->first) && Line1.ExtendEndByLen( 1000) && Line2.Set( nextP->first, nex2P->first) && Line2.ExtendStartByLen( 1000)) { // se la normale non coincide con l'asse Z, devo portare le linee nel riferimento OCS di questa Frame3d frNorm ; if ( ! vtN.IsZplus() && ! vtN.IsZminus()) frNorm.Set( ORIG, vtN) ; Line1.ToLoc( frNorm) ; Line2.ToLoc( frNorm) ; IntersLineLine IntLL( Line1, Line2) ; IntCrvCrvInfo IntInfo ; if ( IntLL.GetIntCrvCrvInfo( IntInfo) && ! IntInfo.bOverlap) { Point3d ptInt = 0.5 * ( IntInfo.IciA[0].ptI + IntInfo.IciB[0].ptI) ; ptInt.ToGlob( frNorm) ; // verifico che distanza dell'intersezione dal segmento currP-nextP sia inferiore a tolleranza corrente DistPointLine dIL( ptInt, currP->first, nextP->first) ; double dSqDist2 = INFINITO * INFINITO ; dIL.GetSqDist( dSqDist2) ; // se eliminabile if ( dSqDist2 < dCurrToler * dCurrToler) { // diminuisco la tolleranza corrente dell'errore attuale dCurrToler -= COEFF_TOL * sqrt( dSqDist2) ; // sposto il successivo sull'intersezione e ne aggiorno il parametro nextP->first = ptInt ; nextP->second = 0.5 * ( currP->second + nextP->second) ; // elimino il punto corrente m_lUPoints.erase( currP) ; // avanzo con corrente e successivo currP = nextP ; nextP = nex2P ; continue ; } } } } } // non è stato eliminato alcunché // ripristino la tolleranza corrente dCurrToler = dToler ; // avanzo il terzetto di uno step precP = currP ; currP = nextP ; ++ nextP ; } return true ; } //---------------------------------------------------------------------------- bool PolyLine::MakeConvex( const Vector3d& vtN, bool bLeftSide) { // ciclo i controlli finchè non ci sono rimozioni bool bRemoved = true ; while ( bRemoved) { bRemoved = false ; // se non ci sono almeno 3 punti, esco subito if ( m_lUPoints.size() < 3) return true ; // punto precedente auto precP = m_lUPoints.begin() ; // punto corrente auto currP = next( precP) ; // punto successivo auto nextP = next( currP) ; // mentre esiste un successivo while ( nextP != m_lUPoints.end()) { // --- si verifica se possibile eliminare il punto corrente rimanendo dal lato voluto --- // se lato sinistro e gira a sinistra o lato destro e gira a destra double dCrossXY = ( ( currP->first - precP->first) ^ ( nextP->first - currP->first)) * vtN ; if ( ( bLeftSide && dCrossXY > - EPS_ZERO) || ( ! bLeftSide && dCrossXY < EPS_ZERO)) { // elimino il punto corrente m_lUPoints.erase( currP) ; // avanzo con corrente e successivo currP = nextP ; ++ nextP ; // dichiaro rimozione bRemoved = true ; continue ; } // non è stato eliminato alcunché : avanzo il terzetto di uno step precP = currP ; currP = nextP ; ++ nextP ; } // se rimasti due punti coincidenti, elimino il secondo if ( m_lUPoints.size() == 2 && AreSamePointApprox( m_lUPoints.front().first, m_lUPoints.back().first)) { m_lUPoints.pop_back() ; return false ; } } return true ; } //---------------------------------------------------------------------------- bool PolyLine::Invert( bool bInvertU) { // verifico non sia vuota if ( m_lUPoints.empty()) return true ; // inverto la lista m_lUPoints.reverse() ; // se richiesto, inverto anche il parametro U if ( bInvertU) { // recupero il primo valore di U che è il vecchio finale ed è il riferimento di inversione double dUfin = m_lUPoints.front().second ; // ciclo su tutti gli elementi for ( auto& UPoint : m_lUPoints) { UPoint.second = dUfin - UPoint.second ; } } return true ; } //---------------------------------------------------------------------------- bool PolyLine::Flatten( double dZ) { // verifico non sia vuota if ( m_lUPoints.empty()) return true ; // ciclo su tutti gli elementi per portarli alla Z indicata for ( auto& UPoint : m_lUPoints) { UPoint.first.z = dZ ; } // elimino i punti consecutivi diventati coincidenti (almeno 2) if ( m_lUPoints.size() < 2) return true ; // punto precedente auto precP = m_lUPoints.begin() ; // punto corrente auto currP = next( precP) ; // mentre esiste un corrente while ( currP != m_lUPoints.end()) { // se coincidono if ( AreSamePointApprox( precP->first, currP->first)) { // elimino il punto corrente currP = m_lUPoints.erase( currP) ; // il precedente rimane inalterato } // altrimenti da tenere else { // avanzo la coppia di uno step precP = currP ; ++ currP ; } } return true ; }