From 3d2f8c1495e4aa6cf9ac319946d7ca5dc7591367 Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Tue, 6 Feb 2024 10:23:22 +0100 Subject: [PATCH] EgtGeomKernel : - approsimazione PolyLine con Douglas-Peucker. --- PolyLine.cpp | 123 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 72 insertions(+), 51 deletions(-) diff --git a/PolyLine.cpp b/PolyLine.cpp index 8a18072..97fe40a 100644 --- a/PolyLine.cpp +++ b/PolyLine.cpp @@ -733,6 +733,45 @@ PointsInTolerance( const PNTVECTOR& vRPT, const Point3d& ptP1, const Point3d& pt return true ; } +//----------------------------------------------------------------------------- +static bool +douglasPeuckerSimplification( const PNTUVECTOR& vPtU, const double dSqTol, const int nIndStart, + const int nIndEnd, PNTUVECTOR& vPtU_simple) +{ + // se indici uguali, ritorno + if ( nIndStart == nIndEnd) + return true ; + + // distanza massima e indice del punto associato + double dMaxSqDist = 0. ; + int nMaxInd = 0 ; + + // scorro i punti intermedi tra nIndStart e nIndEnd + for ( int i = nIndStart + 1 ; i < nIndEnd ; ++ i) { + double dCurrSqDist = 0. ; + // distanza tra il punto attuale e la retta tra i punti di indici nIndStart ed nIndEnd + DistPointLine DPL( vPtU[i].first, vPtU[nIndStart].first, vPtU[nIndEnd].first) ; + if ( DPL.GetSqDist( dCurrSqDist) && dCurrSqDist > dMaxSqDist) { + // aggiorno i parametri + dMaxSqDist = dCurrSqDist ; + nMaxInd = i ; + } + } + + // se la distanza massima trovata è sopra la tolleranza, allora controllo la parte di PolyLine tra + // (nIndStart, nMaxInd) e quella tra (nMaxInd, nIndEnd) + if ( dMaxSqDist > dSqTol) { + // inserisco il punto + vPtU_simple.push_back( vPtU[nMaxInd]) ; + // split + if ( ! douglasPeuckerSimplification( vPtU, dSqTol, nIndStart, nMaxInd, vPtU_simple) || + ! douglasPeuckerSimplification( vPtU, dSqTol, nMaxInd, nIndEnd, vPtU_simple)) + return false ; + } + + return true ; +} + //---------------------------------------------------------------------------- bool PolyLine::RemoveAlignedPoints( double dToler) @@ -743,59 +782,41 @@ PolyLine::RemoveAlignedPoints( double dToler) // controllo minimo valore di tolleranza dToler = max( dToler, LIN_TOL_MIN) ; double dSqTol = dToler * dToler ; - // si analizza la distanza di un punto dal segmento che unisce precedente e successivo - // punto precedente - auto precP = m_lUPoints.begin() ; - // punto corrente - auto currP = next( precP) ; - // punto successivo - auto nextP = next( currP) ; - // lista dei punti appena rimossi - PNTVECTOR vRPT ; vRPT.reserve( 20) ; - // 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 < dSqTol && PointsInTolerance( vRPT, precP->first, nextP->first, dSqTol)) { - // aggiungo il punto nella lista dei rimossi - vRPT.emplace_back( currP->first) ; - // elimino il punto - m_lUPoints.erase( currP) ; - // avanzo con corrente e successivo - currP = nextP ; - ++ nextP ; - } - // altrimenti da tenere - else { - // cancello la lista dei rimossi - vRPT.clear() ; - // avanzo il terzetto di uno step - precP = currP ; - currP = nextP ; - ++ nextP ; - } + // vettore contenente i punti della polyline + PNTUVECTOR vPtU ; vPtU.reserve( int( m_lUPoints.size())) ; + // interatore primo punto + auto ptAct = m_lUPoints.begin() ; + for ( int i = 0 ; i < int( m_lUPoints.size()) ; ++ i) { + vPtU[i] = *ptAct ; + ptAct = next( ptAct) ; // incremento iteratore } - // 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 < dSqTol && PointsInTolerance( vRPT, precP->first, nextP->first, dSqTol)) { - // faccio coincidere il primo punto con il precedente - firstP->first = precP->first ; - // elimino il punto corrente - m_lUPoints.erase( currP) ; - } + + // vettore indice dei punti semplificati + PNTUVECTOR vPtU_simple ; + + // POLYLINE APERTA + if ( ! IsClosed()) { + // considero tutti i punti della PolyLine + if ( ! douglasPeuckerSimplification( vPtU, dSqTol, 0, int( vPtU.size()) - 1, vPtU_simple)) + return false ; } - + // POLYLINE CHIUSA + else { + // considero tutti i punti della PolyLine ad eccezione degli ultimi due + if ( ! douglasPeuckerSimplification( vPtU, dSqTol, 0, int( vPtU.size()) - 2, vPtU_simple)) + return false ; + // controllo se includere l'ultimo punto, calcolando la distanza tra esso e la retta + // definita dagli estremi dei punti semplificati ( primo ed ultimo) + double dLastSqDist = 0. ; + DistPointLine DPL( vPtU.back().first, vPtU_simple.front().first, vPtU_simple.back().first) ; + if ( DPL.GetSqDist( dLastSqDist) && dLastSqDist > dSqTol) + vPtU_simple.push_back( vPtU.back()) ; + } + + // pulisco e aggiungo i parametri ricavati + m_lUPoints.clear() ; + copy( vPtU_simple.begin(), vPtU_simple.end(), m_lUPoints.begin()) ; + return true ; }