//---------------------------------------------------------------------------- // 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 "DistPointLine.h" #include "PolygonPlane.h" #include "PointsPCA.h" #include "\EgtDev\Include\EGkPolyLine.h" #include "\EgtDev\Include\EGkPlane3d.h" //---------------------------------------------------------------------------- PolyLine::PolyLine( void) { m_nCount = 0 ; m_iter = m_lUPoints.end() ; } //---------------------------------------------------------------------------- PolyLine::~PolyLine( void) { } //---------------------------------------------------------------------------- bool PolyLine::Clear( void) { m_nCount = 0 ; m_lUPoints.clear() ; m_iter = m_lUPoints.end() ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::AddUPoint( double dPar, const Point3d& ptP) { try { m_lUPoints.push_back( UPOINT( dPar, ptP)) ; } catch (...) { return false ; } m_nCount ++ ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::EraseFirstUPoint( void) { if ( m_lUPoints.empty()) return false ; m_lUPoints.pop_front() ; m_nCount -- ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::EraseLastUPoint( void) { if ( m_lUPoints.empty()) return false ; m_lUPoints.pop_back() ; m_nCount -- ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::AddOffsetToU( double dOffset) { UPNTLIST::iterator iter ; for ( iter = m_lUPoints.begin() ; iter != m_lUPoints.end() ; ++ iter) iter->first += dOffset ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::Translate( const Vector3d& vtMove) { UPNTLIST::iterator iter ; for ( iter = m_lUPoints.begin() ; iter != m_lUPoints.end() ; ++ iter) iter->second.Translate( vtMove) ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::Rotate( const Point3d& ptAx, const Vector3d& vtAx, double dCosAng, double dSinAng) { UPNTLIST::iterator iter ; for ( iter = m_lUPoints.begin() ; iter != m_lUPoints.end() ; ++ iter) iter->second.Rotate( ptAx, vtAx, dCosAng, dSinAng) ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::Scale( const Frame3d& frRef, double dCoeffX, double dCoeffY, double dCoeffZ) { UPNTLIST::iterator iter ; for ( iter = m_lUPoints.begin() ; iter != m_lUPoints.end() ; ++ iter) iter->second.Scale( frRef, dCoeffX, dCoeffY, dCoeffZ) ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::Mirror( const Point3d& ptOn, const Vector3d& vtNorm) { UPNTLIST::iterator iter ; for ( iter = m_lUPoints.begin() ; iter != m_lUPoints.end() ; ++ iter) iter->second.Mirror( ptOn, vtNorm) ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::Shear( const Point3d& ptOn, const Vector3d& vtNorm, const Vector3d& vtDir, double dCoeff) { UPNTLIST::iterator iter ; for ( iter = m_lUPoints.begin() ; iter != m_lUPoints.end() ; ++ iter) iter->second.Shear( ptOn, vtNorm, vtDir, dCoeff) ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::ToGlob( const Frame3d& frRef) { UPNTLIST::iterator iter ; for ( iter = m_lUPoints.begin() ; iter != m_lUPoints.end() ; ++ iter) iter->second.ToGlob( frRef) ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::ToLoc( const Frame3d& frRef) { UPNTLIST::iterator iter ; for ( iter = m_lUPoints.begin() ; iter != m_lUPoints.end() ; ++ iter) iter->second.ToLoc( frRef) ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::LocToLoc( const Frame3d& frOri, const Frame3d& frDest) { UPNTLIST::iterator iter ; for ( iter = m_lUPoints.begin() ; iter != m_lUPoints.end() ; ++ iter) iter->second.LocToLoc( frOri, frDest) ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::Splice( PolyLine& PL) { m_lUPoints.splice( m_lUPoints.end(), PL.m_lUPoints) ; m_nCount += PL.GetPointNbr() ; PL.m_nCount = 0 ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::IsClosed( void) const { if ( m_lUPoints.size() < 3) return false ; return ( AreSamePointApprox( m_lUPoints.front().second, m_lUPoints.back().second)) ; } //---------------------------------------------------------------------------- bool PolyLine::GetFirstUPoint( double* pdPar, Point3d* pptP) const { m_iter = m_lUPoints.begin() ; if ( m_iter == m_lUPoints.end()) return false ; if ( pdPar != nullptr) *pdPar = m_iter->first ; if ( pptP != nullptr) *pptP = m_iter->second ; 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())) return false ; if ( pdPar != nullptr) *pdPar = m_iter->first ; if ( pptP != nullptr) *pptP = m_iter->second ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::GetLastUPoint( double* pdPar, Point3d* pptP) 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 ( pdPar != nullptr) *pdPar = m_iter->first ; if ( pptP != nullptr) *pptP = m_iter->second ; return true ; } //---------------------------------------------------------------------------- bool PolyLine::GetPrevUPoint( double* pdPar, Point3d* pptP, bool bNotFirst) const { if ( m_iter == m_lUPoints.begin()) return false ; -- m_iter ; if ( bNotFirst && m_iter == m_lUPoints.begin()) return false ; if ( pdPar != nullptr) *pdPar = m_iter->first ; if ( pptP != nullptr) *pptP = m_iter->second ; 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->first ; if ( pptIni != nullptr) *pptIni = m_iter->second ; // parametro e punto finali ++ m_iter ; if ( m_iter == m_lUPoints.end()) return false ; if ( pdFin != nullptr) *pdFin = m_iter->first ; if ( pptFin != nullptr) *pptFin = m_iter->second ; 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->first ; if ( pptIni != nullptr) *pptIni = m_iter->second ; // parametro e punto finali ++ m_iter ; if ( m_iter == m_lUPoints.end()) return false ; if ( pdFin != nullptr) *pdFin = m_iter->first ; if ( pptFin != nullptr) *pptFin = m_iter->second ; 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->first ; if ( pptFin != nullptr) *pptFin = m_iter->second ; // parametro e punto iniziali if ( m_iter == m_lUPoints.begin()) return false ; -- m_iter ; if ( pdIni != nullptr) *pdIni = m_iter->first ; if ( pptIni != nullptr) *pptIni = m_iter->second ; 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->first ; if ( pptFin != nullptr) *pptFin = m_iter->second ; // parametro e punto iniziali if ( m_iter == m_lUPoints.begin()) return false ; -- m_iter ; if ( pdIni != nullptr) *pdIni = m_iter->first ; if ( pptIni != nullptr) *pptIni = m_iter->second ; 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( double& dMaxDist, const Point3d& ptAx, const Vector3d& vtAx, double dLen, 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, ptAx, vtAx, dLen, bIsSegment) ; double dDist ; if ( dstPL.GetDist( dDist) && dDist > dMaxDist) dMaxDist = dDist ; } return true ; }