Files
EgtGeomKernel/PolyLine.cpp
T
Dario Sassi ee0c3830ef EgtGeomKernel 1.5i5 :
- piccole migliorie.
2014-10-07 07:01:39 +00:00

609 lines
18 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_nRejected = 0 ;
m_nCount = 0 ;
m_iter = m_lUPoints.end() ;
}
//----------------------------------------------------------------------------
PolyLine::~PolyLine( void)
{
}
//----------------------------------------------------------------------------
bool
PolyLine::Clear( void)
{
m_nRejected = 0 ;
m_nCount = 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_nCount > 0 && AreSamePointApprox( ptP, m_lUPoints.back().first)) {
++ m_nRejected ;
return true ;
}
// eseguo inserimento
try {
m_lUPoints.push_back( POINTU( ptP, dPar)) ;
}
catch (...) {
return false ;
}
m_nCount ++ ;
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() ;
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)
{
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)
{
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_nCount == 0)
return true ;
// verifico che l'ultimo punto di questa polilinea coincida con il primo dell'altra
if ( m_nCount > 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 e aggiorno i contatori
m_lUPoints.splice( m_lUPoints.end(), PL.m_lUPoints) ;
m_nCount += PL.GetPointNbr() ;
PL.m_nCount = 0 ;
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()) ;
PL.m_nCount = int( PL.m_lUPoints.size()) ;
m_nCount -= PL.m_nCount ;
// prepongo l'ultimo punto rimasto
PL.m_lUPoints.push_front( m_lUPoints.back()) ;
++ PL.m_nCount ;
// annullo l'iteratore corrente
m_iter = m_lUPoints.end() ;
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( 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 ;
}