Files
EgtGeomKernel/CurveComposite.cpp
T
Dario Sassi 4097bcd178 EgtGeomKernel 1.5f5 :
- gestione salvataggio in modalità testo compresso
- aggiunto controlli in scritture per salvataggio.
2014-06-18 07:27:03 +00:00

1307 lines
38 KiB
C++

//----------------------------------------------------------------------------
// EgalTech 2013-2013
//----------------------------------------------------------------------------
// File : CurveComposite.cpp Data : 23.11.13 Versione : 1.3a1
// Contenuto : Implementazione della classe CCurveComposite.
//
//
//
// Modifiche : 26.04.13 DS Creazione modulo.
//
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "CurveComposite.h"
#include "DistPointCrvComposite.h"
#include "GeoConst.h"
#include "GeoObjFactory.h"
#include "NgeWriter.h"
#include "NgeReader.h"
#include "/EgtDev/Include/EGnStringUtils.h"
#include "/EgtDev/Include/EgtPointerOwner.h"
#include "/EgtDev/Include/EGkCurveLine.h"
#include "/EgtDev/Include/EGkCurveArc.h"
#include "/EgtDev/Include/EGkCurveBezier.h"
#include <algorithm>
using namespace std ;
//----------------------------------------------------------------------------
GEOOBJ_REGISTER( CRV_COMPO, NGE_C_CMP, CurveComposite) ;
//----------------------------------------------------------------------------
CurveComposite::CurveComposite( void)
: m_nStatus( TO_VERIFY), m_nCounter( 0), m_bClosed( false)
{
}
//----------------------------------------------------------------------------
CurveComposite::~CurveComposite( void)
{
Clear() ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::Clear( void)
{
// ciclo di pulizia
PCRVSMPL_LIST::iterator Iter ;
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter)
delete (*Iter) ;
m_CrvSmplS.clear() ;
m_nStatus = TO_VERIFY ;
m_nCounter = 0 ;
m_bClosed = false ;
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::AddCurve( const ICurve& cCrv)
{
// se curva semplice
if ( cCrv.IsSimple()) {
// creo una copia della curva
ICurve* pSmplCrv = GetCurve( cCrv.Clone()) ;
if ( pSmplCrv == nullptr)
return false ;
// inserisco la curva
if ( ! AddSimpleCurve( pSmplCrv))
return false ;
}
// altrimenti curva composta, devo aggiungere le singole curve semplici
else {
const ICurveComposite* pCrvCompo ;
const ICurve* pCrvOri ;
ICurve* pSmplCrv ;
// recupero le curve componenti e le inserisco nella lista
pCrvCompo = GetCurveComposite( &cCrv) ;
if ( pCrvCompo == nullptr)
return false ;
pCrvOri = pCrvCompo->GetFirstCurve() ;
while ( pCrvOri != nullptr) {
// creo una copia della curva
pSmplCrv = GetCurve( pCrvOri->Clone()) ;
if ( pSmplCrv == nullptr)
return false ;
// inserisco la curva
if ( ! AddSimpleCurve( pSmplCrv))
return false ;
// passo alla prossima curva componente
pCrvOri = pCrvCompo->GetNextCurve() ;
}
}
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::AddCurve( ICurve* pCrv)
{
// se curva semplice
if ( pCrv->IsSimple()) {
// inserisco la curva
if ( ! AddSimpleCurve( pCrv))
return false ;
}
// altrimenti curva composta, devo aggiungere le singole curve semplici
else {
// puntatore alla curva composita originaria
CurveComposite* pCrvCompo = dynamic_cast<CurveComposite*>( pCrv) ;
if ( pCrvCompo == nullptr)
return false ;
// recupero le curve componenti e le inserisco nella lista
ICurve* pSmplCrv ;
while ( ( pSmplCrv = pCrvCompo->RemoveFirstCurve()) != nullptr) {
// inserisco la curva
if ( ! AddSimpleCurve( pSmplCrv))
return false ;
}
// cancello la curva composita originaria
delete pCrvCompo ;
}
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::AddSimpleCurve( ICurve* pSmplCrv)
{
Point3d ptStart ;
Point3d ptEnd ;
// prendo la proprietà del puntatore
PtrOwner<ICurve> pCrv( pSmplCrv) ;
if ( ! ::IsValid( pCrv))
return false ;
// verifico lo stato
if ( m_nStatus != OK && ! ( m_nCounter == 0 && m_nStatus == TO_VERIFY))
return false ;
// verifico che il parametro sia una curva semplice
if ( ! pCrv->IsSimple())
return false ;
// recupero i punti iniziali e finali della curva
if ( ! pCrv->GetStartPoint( ptStart) || ! pCrv->GetEndPoint( ptEnd))
return false ;
// se non è la prima, verifico sia in continuità con il finale corrente
if ( m_nCounter > 0 && ! AreSamePointNear( ptStart, m_PtEnd))
return false ;
// se prima curva, assegno il punto iniziale
if ( m_nCounter == 0)
m_PtStart = ptStart ;
// inserisco la curva nella lista
m_CrvSmplS.push_back( ::Release( pCrv)) ;
m_nCounter ++ ;
// assegno il punto finale
m_PtEnd = ptEnd ;
// aggiorno il flag di curva chiusa
m_bClosed = ( AreSamePointNear( m_PtStart, m_PtEnd)) ;
// aggiorno lo stato
m_nStatus = OK ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::FromSplit( const ICurve& cCrv, int nParts)
{
// verifico lo stato
if ( m_nCounter != 0 || m_nStatus != TO_VERIFY)
return false ;
// deve essere valida e semplice
if ( ! cCrv.IsValid() || ! cCrv.IsSimple())
return false ;
// se 1 parte o meno, non fa alcunchè
if ( nParts <= 1)
return true ;
// calcolo la lunghezza della curva
double dTotLen ;
if ( ! cCrv.GetLength( dTotLen))
return false ;
// ciclo di inserimento delle parti
double dStartLen = 0 ;
double dEndLen = 0 ;
for ( int i = 1 ; i <= nParts ; ++ i) {
dStartLen = dEndLen ;
dEndLen = dTotLen * i / (double) nParts ;
PtrOwner<ICurve> pSmplCrv( GetCurve( cCrv.Clone())) ;
if ( ! ::IsValid( pSmplCrv))
return false ;
if ( ! pSmplCrv->TrimEndAtLen( dEndLen) ||
! pSmplCrv->TrimStartAtLen( dStartLen))
return false ;
if ( ! AddSimpleCurve( Release( pSmplCrv)))
return false ;
}
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::FromPointVector( const PNTVECTOR& vPnt)
{
// verifico lo stato
if ( m_nCounter != 0 || m_nStatus != TO_VERIFY)
return false ;
// devono essere almeno 2 punti
if ( vPnt.size() < 2)
return false ;
// ciclo di inserimento dei segmenti che uniscono i punti
int iPrev = 0 ;
for ( int i = 1 ; i < int( vPnt.size()) ; ++ i) {
// se i punti della coppia coincidono, passo alla coppia successiva
if ( AreSamePointNear( vPnt[iPrev], vPnt[i]))
continue ;
// creo il segmento di retta
PtrOwner<ICurveLine> pCrvLine( CreateCurveLine()) ;
if ( ! ::IsValid( pCrvLine))
return false ;
// assegno i punti estremi
if ( ! pCrvLine->Set( vPnt[iPrev], vPnt[i]))
return false ;
// aggiungo la retta alla curva composita
if ( ! AddSimpleCurve( Release( pCrvLine)))
return false ;
// aggiorno indice punto ultimo inserito
iPrev = i ;
}
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::FromPointBulgeVector( const UPNTVECTOR& vUPnt, const Vector3d& vtN)
{
// verifico lo stato
if ( m_nCounter != 0 || m_nStatus != TO_VERIFY)
return false ;
// devono essere almeno 2 punti
if ( vUPnt.size() < 2)
return false ;
// Creo le diverse curve semplici e le inserisco in quella composita
int iPrev = 0 ;
for ( int i = 1 ; i < int( vUPnt.size()) ; ++i) {
// se i punti della coppia coincidono, passo alla coppia successiva
if ( AreSamePointNear( vUPnt[iPrev].second, vUPnt[i].second))
continue ;
// se retta
if ( fabs( vUPnt[i-1].first) < EPS_SMALL) {
// creo la retta
PtrOwner<ICurveLine> pCrvLine( CreateCurveLine()) ;
if ( ! ::IsValid( pCrvLine))
return false ;
// setto la linea
if ( ! pCrvLine->Set( vUPnt[iPrev].second, vUPnt[i].second))
return false ;
// inserisco la linea nella curva composta
if ( ! AddSimpleCurve( ::Release( pCrvLine)))
return false ;
}
// altrimenti arco
else {
// creo l'arco
PtrOwner<ICurveArc> pCrvArc( CreateCurveArc()) ;
if ( ! ::IsValid( pCrvArc))
return false ;
// setto l'arco
if ( ! pCrvArc->Set2PNB( vUPnt[iPrev].second, vUPnt[i].second, vtN, vUPnt[i-1].first))
return false ;
// inserisco l'arco nella curva composta
if ( ! AddSimpleCurve( Release( pCrvArc)))
return false ;
}
// aggiorno indice punto ultimo inserito
iPrev = i ;
}
return true ;
}
//----------------------------------------------------------------------------
CurveComposite*
CurveComposite::Clone( void) const
{
// alloco oggetto
CurveComposite* pCrv = new(nothrow) CurveComposite ;
if ( pCrv != nullptr) {
if ( ! pCrv->Copy( *this)) {
delete pCrv ;
return nullptr ;
}
}
return pCrv ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::Copy( const IGeoObj* pGObjSrc)
{
const CurveComposite* pCC = dynamic_cast<const CurveComposite*>( pGObjSrc) ;
if ( pCC == nullptr)
return false ;
return Copy( *pCC) ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::Copy( const CurveComposite& ccSrc)
{
if ( &ccSrc == this)
return true ;
Clear() ;
PCRVSMPL_LIST::const_iterator Iter ;
for ( Iter = ccSrc.m_CrvSmplS.begin() ; Iter != ccSrc.m_CrvSmplS.end() ; ++Iter) {
if ( ! AddCurve( **Iter))
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
GeoObjType
CurveComposite::GetType( void) const
{
return static_cast<GeoObjType>( GEOOBJ_GETTYPE( CurveComposite)) ;
}
//----------------------------------------------------------------------------
const string&
CurveComposite::GetTitle( void) const
{
static const string sTitle = "CComposite" ;
return sTitle ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::Dump( string& sOut, const char* szNewLine) const
{
// se curva aperta o chiusa
sOut += ( IsClosed() ? "Closed" : "Open") ;
// numero di curve
sOut += " CrvNbr=" + ToString( m_nCounter) + szNewLine ;
// ciclo sulle curve componenti
int i = 0 ;
const ICurve* pCrvSmpl = GetFirstCurve() ;
while ( pCrvSmpl != nullptr) {
// assegno ed emetto nome e tipo della curva semplice
sOut += "#" + ToString( ++i) + " " + pCrvSmpl->GetTitle() + szNewLine ;
// salvataggio della curva semplice
if ( ! pCrvSmpl->Dump( sOut, szNewLine))
return false ;
// passo alla successiva
pCrvSmpl = GetNextCurve() ;
}
return true ;
}
//----------------------------------------------------------------------------
int
CurveComposite::GetNgeId( void) const
{
return GEOOBJ_GETNGEID( CurveComposite) ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::Save( NgeWriter& ngeOut) const
{
// numero di curve
if ( ! ngeOut.WriteInt( m_nCounter, nullptr, true))
return false ;
// ciclo sulle curve componenti
int i = 0 ;
const ICurve* pCrvSmpl = GetFirstCurve() ;
while ( pCrvSmpl != nullptr) {
// recupero il gestore di lettura/scrittura delle curve
const IGeoObjRW* pCSmplRW = dynamic_cast<const IGeoObjRW*>( pCrvSmpl) ;
if ( pCSmplRW == nullptr)
return false ;
// emetto tipo della curva semplice
if ( ! ngeOut.WriteKey( pCSmplRW->GetNgeId()))
return false ;
// assegno ed emetto nome della curva semplice
string sCrvName = "#" + ToString( ++i) ;
if ( ! ngeOut.WriteString( sCrvName, nullptr, true))
return false ;
// salvataggio della curva semplice
if ( ! pCSmplRW->Save( ngeOut))
return false ;
// passo alla successiva
pCrvSmpl = GetNextCurve() ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::Load( NgeReader& ngeIn)
{
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
// leggo la prossima linea ( 1 parametro)
// recupero il numero di curve componenti
int nCounter ;
if ( ! ngeIn.ReadInt( nCounter, nullptr, true))
return false ;
// leggo le curve componenti
for ( int i = 0 ; i < nCounter ; ++ i) {
// recupero la prossima linea (con il tipo di oggetto)
int nNgeId ;
if ( ! ngeIn.ReadKey( nNgeId))
return false ;
// creo l'oggetto
int nType = GEOOBJ_NGEIDTOTYPE( nNgeId) ;
IGeoObj* pGeoO = GEOOBJ_CREATE( nType) ;
if ( pGeoO == nullptr)
return false ;
// recupero la linea con il nome
string sName ;
bool bOk = ngeIn.ReadString( sName, nullptr, true) ;
// ne leggo i dati
IGeoObjRW* pGObjRW = dynamic_cast<IGeoObjRW*>( pGeoO) ;
bOk = bOk && ( pGObjRW != nullptr && pGObjRW->Load( ngeIn)) ;
// verifico sia una curva
ICurve* pCrv = ::GetCurve( pGeoO) ;
bOk = bOk && ( pCrv != nullptr && pCrv->IsSimple()) ;
// aggiungo questa curva (sicuramente semplice)
bOk = bOk && AddSimpleCurve( pCrv) ;
// se errore
if ( ! bOk)
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::GetLocalBBox( BBox3d& b3Loc) const
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// inizializzo il box
b3Loc.Reset() ;
// ciclo sulle curve componenti
const ICurve* pCrvSmpl ;
pCrvSmpl = GetFirstCurve() ;
while ( pCrvSmpl != nullptr) {
BBox3d b3Crv ;
// recupero il box della curva
pCrvSmpl->GetLocalBBox( b3Crv) ;
// aggiorno il box
b3Loc.Add( b3Crv) ;
// passo alla curva successiva
pCrvSmpl = GetNextCurve() ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::GetBBox( const Frame3d& frRef, BBox3d& b3Ref) const
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// verifico validità del frame
if ( frRef.GetType() == Frame3d::ERR)
return false ;
// inizializzo il box
b3Ref.Reset() ;
// ciclo sulle curve componenti
const ICurve* pCrvSmpl ;
pCrvSmpl = GetFirstCurve() ;
while ( pCrvSmpl != nullptr) {
BBox3d b3Crv ;
// recupero il box della curva
pCrvSmpl->GetBBox( frRef, b3Crv) ;
// aggiorno il box
b3Ref.Add( b3Crv) ;
// passo alla curva successiva
pCrvSmpl = GetNextCurve() ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::Validate( void)
{
if ( m_nStatus == TO_VERIFY) {
int nCount ;
Point3d ptPrevEnd ;
Point3d ptStart ;
PCRVSMPL_LIST::const_iterator Iter ;
// ciclo su tutte le curve
nCount = 0 ;
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) {
// verifico validità della curva e sua semplicità
if ( ! (*Iter)->IsValid() || (*Iter)->GetType() == CRV_COMPO) {
m_nStatus = ERR ;
return false ;
}
// incremento contatore
++ nCount ;
// verifico continuità con la precedente (se non è la prima)
if ( nCount > 1) {
(*Iter)->GetStartPoint( ptStart) ;
if ( ! AreSamePointNear( ptPrevEnd, ptStart)) {
m_nStatus = ERR ;
return false ;
}
}
// recupero il punto finale
(*Iter)->GetEndPoint( ptPrevEnd) ;
}
// aggiorno
m_nStatus = OK ;
m_nCounter = nCount ;
m_CrvSmplS.front()->GetStartPoint( m_PtStart) ;
m_CrvSmplS.back()->GetEndPoint( m_PtEnd) ;
m_bClosed = ( AreSamePointNear( m_PtStart, m_PtEnd)) ;
}
return ( m_nStatus == OK) ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::GetStartPoint( Point3d& ptStart) const
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// assegno il punto
ptStart = m_PtStart ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::GetEndPoint( Point3d& ptEnd) const
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// assegno il punto
ptEnd = m_PtEnd ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::GetMidPoint( Point3d& ptMid) const
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// determino il valore medio del parametro della curva
double dStart, dEnd, dMid ;
GetDomain( dStart, dEnd) ;
dMid = 0.5 * ( dStart + dEnd) ;
// calcolo il punto
return GetPointD1D2( dMid, FROM_MINUS, ptMid) ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::GetDomain( double& dStart, double& dEnd) const
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// assegno gli estremi del dominio
dStart = 0 ;
dEnd = m_nCounter ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::GetPointD1D2( double dU, Side nS, Point3d& ptPos, Vector3d* pvtDer1, Vector3d* pvtDer2) const
{
PCRVSMPL_LIST::const_iterator Iter ;
// il parametro U deve essere compreso tra 0 e m_nCounter
if ( dU < ( 0 + EPS_ZERO)) {
dU = 0 ;
nS = ICurve::FROM_PLUS ;
}
else if ( dU > ( m_nCounter - EPS_ZERO)) {
dU = m_nCounter ;
nS = ICurve::FROM_MINUS ;
}
// determino la curva di appartenenza e faccio eseguire il calcolo
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) {
// ogni curva semplice ha parametro compreso tra 0 e 1
// se nella parametrizzazione della curva semplice, oppure all'estremo superiore e dal basso
if ( dU < ( 1 - EPS_ZERO) ||
( fabs( dU - 1) < EPS_ZERO && nS == ICurve::FROM_MINUS))
return (*Iter)->GetPointD1D2( dU, ICurve::FROM_MINUS, ptPos, pvtDer1, pvtDer2) ;
else
dU -= 1 ;
}
return false ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::GetLength( double& dLen) const
{
double dLenCrvSmpl ;
PCRVSMPL_LIST::const_iterator Iter ;
// ciclo di calcolo
dLen = 0 ;
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) {
if ( (*Iter)->GetLength( dLenCrvSmpl))
dLen += dLenCrvSmpl ;
else
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::IsPointOn( const Point3d& ptP, double dTol) const
{
double dSqDist ;
dTol = max( dTol, EPS_ZERO) ;
return ( DistPointCrvComposite( ptP, *this).GetSqDist( dSqDist) && dSqDist < dTol * dTol) ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::ApproxWithLines( double dLinTol, double dAngTolDeg, PolyLine& PL) const
{
// pulisco la polilinea
PL.Clear() ;
// la curva deve essere validata
if ( m_nStatus != OK)
return false ;
// eseguo approssimazione
bool bFirst = true ;
double dStartPar = 0 ;
PolyLine PLSmpl ;
PCRVSMPL_LIST::const_iterator Iter ;
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) {
// recupero approssimazione per curva semplice
if ( ! (*Iter)->ApproxWithLines( dLinTol, dAngTolDeg, PLSmpl))
return false ;
// la accodo opportunamente a quella della curva composita
if ( bFirst) {
PL.Splice( PLSmpl) ;
bFirst = false ;
}
else {
PLSmpl.EraseFirstUPoint() ;
PLSmpl.AddOffsetToU( dStartPar) ;
PL.Splice( PLSmpl) ;
}
// incremento inizio parametro per prossima curva semplice
dStartPar += 1 ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::Invert( void)
{
// inverto le singole curve
PCRVSMPL_LIST::iterator Iter ;
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter)
(*Iter)->Invert() ;
// inverto l'ordine della lista
m_CrvSmplS.reverse() ;
// scambio punti iniziale e finale
swap( m_PtStart, m_PtEnd) ;
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::TrimStartAtParam( double dUTrim)
{
double dParStart ;
double dParEnd ;
double dUToTrim ;
PCRVSMPL_LIST::iterator Iter ;
// ciclo sulle diverse curve dall'inizio
dUToTrim = dUTrim ;
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ;) {
// dominio parametrico della curva semplice
(*Iter)->GetDomain( dParStart, dParEnd) ;
// lunghezza parametrica progressiva
dUToTrim -= ( dParEnd - dParStart) ;
// se lunghezza ancora da tagliare non nulla
if ( dUToTrim > EPS_ZERO) {
delete (*Iter) ;
Iter ++ ;
m_CrvSmplS.pop_front() ;
m_nCounter -- ;
}
// se lunghezza ancora da tagliare nulla (entro la tolleranza)
else if ( dUToTrim > - EPS_ZERO) {
delete (*Iter) ;
Iter ++ ;
m_CrvSmplS.pop_front() ;
m_nCounter -- ;
if ( m_nCounter == 0)
return false ;
(*Iter)->GetStartPoint( m_PtStart) ;
m_bClosed = ( AreSamePointNear( m_PtStart, m_PtEnd)) ;
break ;
}
// altrimenti superata lunghezza ancora da tagliare
else {
if ( ! (*Iter)->TrimStartAtParam( 1 + dUToTrim)) {
m_nStatus = ERR ;
return false ;
}
(*Iter)->GetStartPoint( m_PtStart) ;
m_bClosed = ( AreSamePointNear( m_PtStart, m_PtEnd)) ;
break ;
}
}
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::TrimEndAtParam( double dUTrim)
{
bool bToErase ;
double dParStart ;
double dParEnd ;
double dUToTrim ;
PCRVSMPL_LIST::iterator Iter ;
// ciclo sulle diverse curve dalla fine
bToErase = false ;
dUToTrim = dUTrim ;
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ;) {
// dominio parametrico della curva semplice
(*Iter)->GetDomain( dParStart, dParEnd) ;
// lunghezza parametrica progressiva
dUToTrim -= ( dParEnd - dParStart) ;
// se da cancellare
if ( bToErase) {
// cancello l'entità, la tolgo dalla lista e passo alla successiva
delete (*Iter) ;
Iter = m_CrvSmplS.erase( Iter) ;
// decremento il numero di entità
m_nCounter -- ;
}
// se lunghezza parametrica ancora da tagliare non nulla
else if ( dUToTrim > EPS_ZERO) {
Iter ++ ;
}
// se lunghezza parametrica ancora da tagliare nulla (entro la tolleranza)
else if ( dUToTrim > - EPS_ZERO) {
// imposto punto finale e verifico curva chiusa
(*Iter)->GetEndPoint( m_PtEnd) ;
m_bClosed = ( AreSamePointNear( m_PtStart, m_PtEnd)) ;
// passo alla entità successiva
++ Iter ;
// dichiaro ingresso in zona da cancellare
bToErase = true ;
}
// altrimenti superata lunghezza parametrica ancora da tagliare
else {
// trimmo la curva semplice
if ( ! (*Iter)->TrimEndAtParam( 1 + dUToTrim)) {
m_nStatus = ERR ;
return false ;
}
// imposto punto finale e verifica curva chiusa
(*Iter)->GetEndPoint( m_PtEnd) ;
m_bClosed = ( AreSamePointNear( m_PtStart, m_PtEnd)) ;
// passo alla entità successiva
++ Iter ;
// dichiaro ingresso in zona da cancellare
bToErase = true ;
}
}
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::TrimStartAtLen( double dLenTrim)
{
double dLenToTrim ;
double dCrvLen ;
PCRVSMPL_LIST::iterator Iter ;
// ciclo sulle diverse curve dall'inizio
dLenToTrim = dLenTrim ;
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ;) {
// lunghezza della curva
if ( ! (*Iter)->GetLength( dCrvLen))
return false ;
// lunghezza progressiva
dLenToTrim -= dCrvLen ;
// se lunghezza ancora da tagliare non nulla
if ( dLenToTrim > EPS_SMALL) {
delete (*Iter) ;
Iter ++ ;
m_CrvSmplS.pop_front() ;
m_nCounter -- ;
}
// se lunghezza ancora da tagliare nulla (entro la tolleranza)
else if ( dLenToTrim > - EPS_SMALL) {
delete (*Iter) ;
Iter ++ ;
m_CrvSmplS.pop_front() ;
m_nCounter -- ;
if ( m_nCounter == 0)
return false ;
(*Iter)->GetStartPoint( m_PtStart) ;
m_bClosed = ( AreSamePointNear( m_PtStart, m_PtEnd)) ;
break ;
}
// altrimenti superata lunghezza ancora da tagliare
else {
if ( ! (*Iter)->TrimStartAtLen( dCrvLen + dLenToTrim)) {
m_nStatus = ERR ;
return false ;
}
(*Iter)->GetStartPoint( m_PtStart) ;
m_bClosed = ( AreSamePointNear( m_PtStart, m_PtEnd)) ;
break ;
}
}
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::TrimEndAtLen( double dLenTrim)
{
bool bToErase ;
double dLenToTrim ;
double dCrvLen ;
PCRVSMPL_LIST::iterator Iter ;
// ciclo sulle diverse curve dalla fine
bToErase = false ;
dLenToTrim = dLenTrim ;
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ;) {
// se non sono già nella zona da cancellare, aggiorno lunghezze
if ( ! bToErase) {
// lunghezza della curva
if ( ! (*Iter)->GetLength( dCrvLen))
return false ;
// lunghezza progressiva
dLenToTrim -= dCrvLen ;
}
// se da cancellare
if ( bToErase) {
// cancello l'entità, la tolgo dalla lista e passo alla successiva
delete (*Iter) ;
Iter = m_CrvSmplS.erase( Iter) ;
// decremento il numero di entità
m_nCounter -- ;
}
// se lunghezza ancora da tagliare non nulla
else if ( dLenToTrim > EPS_SMALL) {
// passo alla entità successiva
++ Iter ;
}
// se lunghezza ancora da tagliare nulla (entro la tolleranza)
else if ( dLenToTrim > - EPS_SMALL) {
// imposto punto finale e verifica curva chiusa
(*Iter)->GetEndPoint( m_PtEnd) ;
m_bClosed = ( AreSamePointNear( m_PtStart, m_PtEnd)) ;
// passo alla entità successiva
++ Iter ;
// dichiaro ingresso in zona da cancellare
bToErase = true ;
}
// altrimenti superata lunghezza ancora da tagliare
else {
// trimmo la curva semplice
if ( ! (*Iter)->TrimEndAtLen( dCrvLen + dLenToTrim)) {
m_nStatus = ERR ;
return false ;
}
// imposto punto finale e verifica curva chiusa
(*Iter)->GetEndPoint( m_PtEnd) ;
m_bClosed = ( AreSamePointNear( m_PtStart, m_PtEnd)) ;
// passo alla entità successiva
++ Iter ;
// dichiaro ingresso in zona da cancellare
bToErase = true ;
}
}
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::Translate( const Vector3d& vtMove)
{
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
// traslo le singole curve
PCRVSMPL_LIST::iterator Iter ;
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter)
(*Iter)->Translate( vtMove) ;
// traslo i punti estremi
m_PtStart.Translate( vtMove) ;
m_PtEnd.Translate( vtMove) ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::Rotate( const Point3d& ptAx, const Vector3d& vtAx, double dCosAng, double dSinAng)
{
// verifico validità dell'asse di rotazione
if ( vtAx.IsSmall())
return false ;
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
// ruoto le singole curve
PCRVSMPL_LIST::iterator Iter ;
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter)
(*Iter)->Rotate( ptAx, vtAx, dCosAng, dSinAng) ;
// ruoto i punti estremi
m_PtStart.Rotate( ptAx, vtAx, dCosAng, dSinAng) ;
m_PtEnd.Rotate( ptAx, vtAx, dCosAng, dSinAng) ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::Scale( const Frame3d& frRef, double dCoeffX, double dCoeffY, double dCoeffZ)
{
// verifico non sia nulla
if ( fabs( dCoeffX) < EPS_ZERO && fabs( dCoeffY) < EPS_ZERO && fabs( dCoeffZ) < EPS_ZERO)
return false ;
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
// se scalatura non omogenea, devo trasformare tutti gli archi in curve di Bezier
if ( fabs( dCoeffX - dCoeffY) > EPS_SMALL || fabs( dCoeffX - dCoeffZ) > EPS_SMALL) {
if ( ! ArcsToBezierCurves())
return false ;
}
// scalo le singole curve
PCRVSMPL_LIST::iterator Iter ;
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) {
// eseguo la scalatura
if ( ! (*Iter)->Scale( frRef, dCoeffX, dCoeffY, dCoeffZ))
return false ;
}
// scalo i punti estremi
m_PtStart.Scale( frRef, dCoeffX, dCoeffY, dCoeffZ) ;
m_PtEnd.Scale( frRef, dCoeffX, dCoeffY, dCoeffZ) ;
return Validate() ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::Mirror( const Point3d& ptOn, const Vector3d& vtNorm)
{
// verifico validità del piano di specchiatura
if ( vtNorm.IsSmall())
return false ;
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
// specchio le singole curve
PCRVSMPL_LIST::iterator Iter ;
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter)
(*Iter)->Mirror( ptOn, vtNorm) ;
// specchio i punti estremi
m_PtStart.Mirror( ptOn, vtNorm) ;
m_PtEnd.Mirror( ptOn, vtNorm) ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::Shear( const Point3d& ptOn, const Vector3d& vtNorm, const Vector3d& vtDir, double dCoeff)
{
// verifico validità dei parametri
if ( vtNorm.IsSmall() || vtDir.IsSmall())
return false ;
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
// trasformo tutti gli archi in curve di Bezier (potrei controllare gli archi uno ad uno...)
if ( ! ArcsToBezierCurves())
return false ;
// eseguo scorrimento delle singole curve
PCRVSMPL_LIST::iterator Iter ;
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter)
(*Iter)->Shear( ptOn, vtNorm, vtDir, dCoeff) ;
// eseguo scorrimento dei punti estremi
m_PtStart.Shear( ptOn, vtNorm, vtDir, dCoeff) ;
m_PtEnd.Shear( ptOn, vtNorm, vtDir, dCoeff) ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::ToGlob( const Frame3d& frRef)
{
// verifico validità del frame
if ( frRef.GetType() == Frame3d::ERR)
return false ;
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
// trasformo le singole curve
PCRVSMPL_LIST::iterator Iter ;
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter)
(*Iter)->ToGlob( frRef) ;
// trasformo i punti estremi
m_PtStart.ToGlob( frRef) ;
m_PtEnd.ToGlob( frRef) ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::ToLoc( const Frame3d& frRef)
{
// verifico validità del frame
if ( frRef.GetType() == Frame3d::ERR)
return false ;
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
// trasformo le singole curve
PCRVSMPL_LIST::iterator Iter ;
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter)
(*Iter)->ToLoc( frRef) ;
// trasformo i punti estremi
m_PtStart.ToLoc( frRef) ;
m_PtEnd.ToLoc( frRef) ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::LocToLoc( const Frame3d& frOri, const Frame3d& frDest)
{
// verifico validità dei frame
if ( frOri.GetType() == Frame3d::ERR || frDest.GetType() == Frame3d::ERR)
return false ;
// se i due riferimenti coincidono, non devo fare alcunché
if ( AreSameFrame( frOri, frDest))
return true ;
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
// trasformo le singole curve
PCRVSMPL_LIST::iterator Iter ;
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) {
(*Iter)->LocToLoc( frOri, frDest) ;
}
// trasformo i punti estremi
m_PtStart.LocToLoc( frOri, frDest) ;
m_PtEnd.LocToLoc( frOri, frDest) ;
return true ;
}
//----------------------------------------------------------------------------
const ICurve*
CurveComposite::GetFirstCurve( void) const
{
// la curva deve essere validata
if ( m_nStatus != OK)
return nullptr ;
// vado all'inizio
*(const_cast<PCRVSMPL_LIST::const_iterator*> (&m_Iter)) = m_CrvSmplS.begin() ;
// recupero la curva
if ( m_Iter != m_CrvSmplS.end())
return (*m_Iter) ;
else
return nullptr ;
}
//----------------------------------------------------------------------------
const ICurve*
CurveComposite::GetNextCurve( void) const
{
// la curva deve essere validata
if ( m_nStatus != OK)
return nullptr ;
// vado al successivo
(*(const_cast<PCRVSMPL_LIST::const_iterator*> (&m_Iter))) ++ ;
// recupero la curva
if ( m_Iter != m_CrvSmplS.end())
return (*m_Iter) ;
else
return nullptr ;
}
//----------------------------------------------------------------------------
ICurve*
CurveComposite::RemoveFirstCurve( void)
{
// la curva composita deve essere validata
if ( m_nStatus != OK)
return nullptr ;
// recupero la curva semplice iniziale e la tolgo dalla lista
if ( ! m_CrvSmplS.empty()) {
ICurve* pCrv = *(m_CrvSmplS.begin()) ;
m_CrvSmplS.pop_front() ;
return pCrv ;
}
else
return nullptr ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::IsParamAtJoint( double dU) const
{
// se all'inizio, alla fine o lontano dagli interi
if ( fabs( dU) < EPS_ZERO ||
fabs( dU - m_nCounter) < EPS_ZERO ||
fabs( dU - (int) ( dU + EPS_ZERO)) > EPS_ZERO)
return false ;
else
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::ArcsToBezierCurves( void)
{
// verifico le singole curve
PCRVSMPL_LIST::iterator Iter ;
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) {
// se arco, devo trasformare in una o più curve di Bezier
if ( (*Iter)->GetType() == CRV_ARC) {
const ICurveArc* pArc = GetCurveArc( (*Iter)) ;
// se angolo al centro sotto il limite, basta una curva
if ( fabs( pArc->GetAngCenter()) <= BEZARC_ANG_CEN_MAX + EPS_ANG_SMALL) {
// creo la curva di Bezier
PtrOwner<ICurveBezier> pCrvBez( CreateCurveBezier()) ;
if ( ! ::IsValid( pCrvBez))
return false ;
if ( ! pCrvBez->FromArc( *pArc))
return false ;
// elimino l'arco e lo sostituisco con la curva di Bezier
delete (*Iter) ;
(*Iter) = Release( pCrvBez) ;
}
// altrimenti ne servono diverse
else {
// divido in parti
CurveComposite cCompo ;
int nParts = (int) ceil( fabs( pArc->GetAngCenter()) / BEZARC_ANG_CEN_MAX) ;
if ( ! cCompo.FromSplit( *pArc, nParts))
return false ;
// trasformo le parti in curve di Bezier
if ( ! cCompo.ArcsToBezierCurves() || cCompo.GetCurveNumber() != nParts)
return false ;
// inserisco le curve prima dell'arco
m_CrvSmplS.splice( Iter, cCompo.m_CrvSmplS) ;
// elimino l'arco (e sposto l'iteratore alla curva precedente)
delete (*Iter) ;
PCRVSMPL_LIST::iterator ToErase = Iter ;
-- Iter ;
m_CrvSmplS.erase( ToErase) ;
// aggiorno il numero di curve
m_nCounter += nParts - 1 ;
}
}
}
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
return true ;
}