77e74ccf4e
- aggiunta IsFlat a tutte le Curve - aggiunta ApproxWithArcs a tutte le Curve - aggiunto oggetto PolyArc (raccolta ordinata di linee e archi con bulge) - aggiunto oggetto PointsPCA per stima componenti principali di un insieme di punti - FromSpheriical e FromPolar di Vector3d sono diventati funzioni e aggiunto FromUprightOrtho - aggiunte Invert e a Vector3d.
520 lines
15 KiB
C++
520 lines
15 KiB
C++
//----------------------------------------------------------------------------
|
|
// 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 ;
|
|
}
|