b304c329ef
- aggiunta estensione di curve agli estremi di data lunghezza - a selezione oggetto aggiunto flag per farlo solo se già visibile - possibilità di ciclare gli oggetti selezionati a ritroso - a tutti gli oggetti Geo aggiunto il costruttore di copia.
2037 lines
62 KiB
C++
2037 lines
62 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 "CurveLine.h"
|
|
#include "CurveArc.h"
|
|
#include "CurveBezier.h"
|
|
#include "GeoConst.h"
|
|
#include "GeoObjFactory.h"
|
|
#include "NgeWriter.h"
|
|
#include "NgeReader.h"
|
|
#include "/EgtDev/Include/EGkStringUtils3d.h"
|
|
#include "/EgtDev/Include/EgtPointerOwner.h"
|
|
#include <algorithm>
|
|
|
|
using namespace std ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
GEOOBJ_REGISTER( CRV_COMPO, NGE_C_CMP, CurveComposite) ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
CurveComposite::CurveComposite( void)
|
|
: m_nStatus( TO_VERIFY), m_nCounter(), m_bClosed( false), m_VtExtr(), m_dThick()
|
|
{
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
CurveComposite::~CurveComposite( void)
|
|
{
|
|
Clear() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::Clear( void)
|
|
{
|
|
// ciclo di pulizia
|
|
PCRVSMPL_DEQUE::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 ;
|
|
m_VtExtr = V_NULL ;
|
|
m_dThick = 0 ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::AddCurve( const ICurve& cCrv, bool bEndOrStart, double dLinTol)
|
|
{
|
|
// 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, bEndOrStart, dLinTol))
|
|
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 = ( bEndOrStart ? pCrvCompo->GetFirstCurve() : pCrvCompo->GetLastCurve()) ;
|
|
while ( pCrvOri != nullptr) {
|
|
// creo una copia della curva
|
|
pSmplCrv = GetCurve( pCrvOri->Clone()) ;
|
|
if ( pSmplCrv == nullptr)
|
|
return false ;
|
|
// inserisco la curva
|
|
if ( ! AddSimpleCurve( pSmplCrv, bEndOrStart, dLinTol))
|
|
return false ;
|
|
// passo alla prossima curva componente
|
|
pCrvOri = ( bEndOrStart ? pCrvCompo->GetNextCurve() : pCrvCompo->GetPrevCurve()) ;
|
|
}
|
|
}
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::AddCurve( ICurve* pCrv, bool bEndOrStart, double dLinTol)
|
|
{
|
|
// verifica curva
|
|
if ( pCrv == nullptr)
|
|
return false ;
|
|
// se curva semplice
|
|
if ( pCrv->IsSimple()) {
|
|
// inserisco la curva
|
|
if ( ! AddSimpleCurve( pCrv, bEndOrStart, dLinTol))
|
|
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->RemoveFirstOrLastCurve( ! bEndOrStart)) != nullptr) {
|
|
// inserisco la curva
|
|
if ( ! AddSimpleCurve( pSmplCrv, bEndOrStart, dLinTol))
|
|
return false ;
|
|
}
|
|
// cancello la curva composita originaria
|
|
delete pCrvCompo ;
|
|
}
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::AddSimpleCurve( ICurve* pSmplCrv, bool bEndOrStart, double dLinTol)
|
|
{
|
|
// prendo la proprietà del puntatore
|
|
PtrOwner<ICurve> pCrv( pSmplCrv) ;
|
|
if ( IsNull( 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 ;
|
|
|
|
// annullo l'estrusione
|
|
pCrv->SetExtrusion( V_NULL) ;
|
|
|
|
// recupero i punti iniziali e finali della curva
|
|
Point3d ptStart, ptEnd ;
|
|
if ( ! pCrv->GetStartPoint( ptStart) || ! pCrv->GetEndPoint( ptEnd))
|
|
return false ;
|
|
|
|
// se non è la prima
|
|
if ( m_nCounter > 0) {
|
|
// se inserita alla fine
|
|
if ( bEndOrStart) {
|
|
// verifico sia in continuità con il finale attuale
|
|
if ( ! AreSamePointApprox( ptStart, m_PtEnd)) {
|
|
// se in tolleranza, modifico l'inizio dell'entità
|
|
if ( SqDist( ptStart, m_PtEnd) < ( dLinTol * dLinTol)) {
|
|
if ( ! pCrv->ModifyStart( m_PtEnd))
|
|
return false ;
|
|
}
|
|
else
|
|
return false ;
|
|
}
|
|
}
|
|
// altrimenti inserita all'inizio
|
|
else {
|
|
// verifico sia in continuità con l'iniziale attuale
|
|
if ( ! AreSamePointApprox( ptEnd, m_PtStart)) {
|
|
// se in tolleranza, modifico la fine dell'entità
|
|
if ( SqDist( ptEnd, m_PtStart) < ( dLinTol * dLinTol)) {
|
|
if ( ! pCrv->ModifyEnd( m_PtStart))
|
|
return false ;
|
|
}
|
|
else
|
|
return false ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// se prima curva, assegno il punto iniziale o finale
|
|
if ( m_nCounter == 0) {
|
|
if ( bEndOrStart)
|
|
m_PtStart = ptStart ;
|
|
else
|
|
m_PtEnd = ptEnd ;
|
|
}
|
|
|
|
// inserisco la curva nella lista
|
|
if ( bEndOrStart)
|
|
m_CrvSmplS.push_back( ::Release( pCrv)) ;
|
|
else
|
|
m_CrvSmplS.push_front( ::Release( pCrv)) ;
|
|
m_nCounter ++ ;
|
|
|
|
// assegno il nuovo punto estremo
|
|
if ( bEndOrStart)
|
|
m_PtEnd = ptEnd ;
|
|
else
|
|
m_PtStart = ptStart ;
|
|
|
|
// aggiorno il flag di curva chiusa
|
|
m_bClosed = ( AreSamePointApprox( 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 ( IsNull( 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::FromPolyLine( const PolyLine& PL)
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nCounter != 0 || m_nStatus != TO_VERIFY)
|
|
return false ;
|
|
// deve esserci almeno 1 linea (2 punti)
|
|
if ( PL.GetLineNbr() < 1)
|
|
return false ;
|
|
|
|
// ciclo di inserimento dei segmenti che uniscono i punti
|
|
Point3d ptIni, ptFin ;
|
|
PL.GetFirstPoint( ptIni) ;
|
|
while ( PL.GetNextPoint( ptFin)) {
|
|
// se i punti della coppia coincidono, passo alla coppia successiva
|
|
if ( AreSamePointApprox( ptIni, ptFin))
|
|
continue ;
|
|
// creo il segmento di retta
|
|
PtrOwner<ICurveLine> pCrvLine( CreateCurveLine()) ;
|
|
if ( IsNull( pCrvLine))
|
|
return false ;
|
|
// assegno i punti estremi
|
|
if ( ! pCrvLine->Set( ptIni, ptFin))
|
|
return false ;
|
|
// aggiungo la retta alla curva composita
|
|
if ( ! AddSimpleCurve( Release( pCrvLine)))
|
|
return false ;
|
|
// aggiorno dati prossimo punto iniziale
|
|
ptIni = ptFin ;
|
|
}
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::FromPolyArc( const PolyArc& PA)
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nCounter != 0 || m_nStatus != TO_VERIFY)
|
|
return false ;
|
|
// deve esserci almeno 1 arco (2 punti)
|
|
if ( PA.GetArcNbr() < 1)
|
|
return false ;
|
|
|
|
// Creo le diverse curve semplici e le inserisco in quella composita
|
|
double dBulge, dNextBulge ;
|
|
Point3d ptIni, ptFin ;
|
|
PA.GetFirstPoint( ptIni, dBulge) ;
|
|
while ( PA.GetNextPoint( ptFin, dNextBulge)) {
|
|
// se i punti della coppia coincidono, passo alla coppia successiva
|
|
if ( AreSamePointApprox( ptIni, ptFin))
|
|
continue ;
|
|
// se retta
|
|
if ( fabs( dBulge) < EPS_SMALL) {
|
|
// creo la retta
|
|
PtrOwner<CurveLine> pCrvLine( CreateBasicCurveLine()) ;
|
|
if ( IsNull( pCrvLine))
|
|
return false ;
|
|
// setto la linea
|
|
if ( ! pCrvLine->Set( ptIni, ptFin))
|
|
return false ;
|
|
// inserisco la linea nella curva composta
|
|
if ( ! AddSimpleCurve( ::Release( pCrvLine)))
|
|
return false ;
|
|
}
|
|
// altrimenti arco
|
|
else {
|
|
// creo l'arco
|
|
PtrOwner<CurveArc> pCrvArc( CreateBasicCurveArc()) ;
|
|
if ( IsNull( pCrvArc))
|
|
return false ;
|
|
// setto l'arco
|
|
if ( ! pCrvArc->Set2PNB( ptIni, ptFin, PA.GetExtrusion(), dBulge))
|
|
return false ;
|
|
// inserisco l'arco nella curva composta
|
|
if ( ! AddSimpleCurve( Release( pCrvArc)))
|
|
return false ;
|
|
}
|
|
// aggiorno dati prossimo punto iniziale
|
|
ptIni = ptFin ;
|
|
dBulge = dNextBulge ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::PolygonCenterCorner( int nSides, const Point3d& ptCen, const Point3d& ptCorner)
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nCounter != 0 || m_nStatus != TO_VERIFY)
|
|
return false ;
|
|
// almeno 3 lati
|
|
if ( nSides < 3)
|
|
return false ;
|
|
|
|
// angolo al centro corrispondente ad un lato
|
|
double dAngCenSideDeg = ANG_FULL / nSides ;
|
|
double dCosAng = cos( dAngCenSideDeg * DEGTORAD) ;
|
|
double dSinAng = sin( dAngCenSideDeg * DEGTORAD) ;
|
|
|
|
// ciclo di inserimento dei segmenti che uniscono i punti
|
|
Point3d ptStart = ptCorner ;
|
|
Point3d ptEnd ;
|
|
for ( int i = 1 ; i <= nSides ; ++ i) {
|
|
// calcolo il secondo punto del lato
|
|
ptEnd = ptStart ;
|
|
ptEnd.Rotate( ptCen, Z_AX, dCosAng, dSinAng) ;
|
|
// se primo lato, verifico che la lunghezza sia superiore al minimo
|
|
if ( i == 1) {
|
|
if ( AreSamePointApprox( ptStart, ptEnd))
|
|
return false ;
|
|
}
|
|
// creo il segmento di retta
|
|
PtrOwner<CurveLine> pCrvLine( CreateBasicCurveLine()) ;
|
|
if ( IsNull( pCrvLine))
|
|
return false ;
|
|
// assegno i punti estremi
|
|
if ( ! pCrvLine->Set( ptStart, ptEnd))
|
|
return false ;
|
|
// aggiungo la retta alla curva composita
|
|
if ( ! AddSimpleCurve( Release( pCrvLine)))
|
|
return false ;
|
|
// aggiorno punto iniziale prossimo lato
|
|
ptStart = ptEnd ;
|
|
}
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::PolygonCenterMidSide( int nSides, const Point3d& ptCen, const Point3d& ptMidSide)
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nCounter != 0 || m_nStatus != TO_VERIFY)
|
|
return false ;
|
|
// almeno 3 lati
|
|
if ( nSides < 3)
|
|
return false ;
|
|
|
|
// calcolo la posizione del corner
|
|
double dHalfCentSideAngDeg = ANG_FULL / ( 2 * nSides) ;
|
|
double dCoeff = tan( dHalfCentSideAngDeg * DEGTORAD) ;
|
|
Vector3d vtDir = ptCen - ptMidSide ;
|
|
vtDir.z = 0 ;
|
|
vtDir.Rotate( Z_AX, 0, 1) ;
|
|
Point3d ptCorner = ptMidSide + vtDir * dCoeff ;
|
|
|
|
// ora costruisco come poligono con centro e corner
|
|
return PolygonCenterCorner( nSides, ptCen, ptCorner) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::PolygonSide( int nSides, const Point3d& ptStart, const Point3d& ptEnd)
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nCounter != 0 || m_nStatus != TO_VERIFY)
|
|
return false ;
|
|
// almeno 3 lati
|
|
if ( nSides < 3)
|
|
return false ;
|
|
// verifico che la lunghezza sia superiore al minimo
|
|
if ( AreSamePointApprox( ptStart, ptEnd))
|
|
return false ;
|
|
|
|
// calcolo la posizione del centro
|
|
double dHalfCentSideAngDeg = ANG_FULL / ( 2 * nSides) ;
|
|
double dCoeff = 1 / ( 2 * tan( dHalfCentSideAngDeg * DEGTORAD)) ;
|
|
Vector3d vtDir = ptEnd - ptStart ;
|
|
vtDir.z = 0 ;
|
|
vtDir.Rotate( Z_AX, 0, 1) ;
|
|
Point3d ptCen = Media( ptStart, ptEnd, 0.5) + vtDir * dCoeff ;
|
|
|
|
// ora costruisco come poligono con centro e corner
|
|
return PolygonCenterCorner( nSides, ptCen, ptStart) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
CurveComposite*
|
|
CurveComposite::Clone( void) const
|
|
{
|
|
// alloco oggetto
|
|
CurveComposite* pCrv = new(nothrow) CurveComposite ;
|
|
if ( pCrv != nullptr) {
|
|
if ( ! pCrv->CopyFrom( *this)) {
|
|
delete pCrv ;
|
|
return nullptr ;
|
|
}
|
|
}
|
|
|
|
return pCrv ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::CopyFrom( const IGeoObj* pGObjSrc)
|
|
{
|
|
// se sorgente è una curva composita
|
|
const CurveComposite* pCC = GetBasicCurveComposite( pGObjSrc) ;
|
|
if ( pCC != nullptr)
|
|
return CopyFrom( *pCC) ;
|
|
// se sorgente è un'altro tipo di curva
|
|
const ICurve* pCrv = GetCurve( pGObjSrc) ;
|
|
if ( pCrv != nullptr) {
|
|
Clear() ;
|
|
return AddCurve( *pCrv) ;
|
|
}
|
|
// altrimenti errroe
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::CopyFrom( const CurveComposite& ccSrc)
|
|
{
|
|
if ( &ccSrc == this)
|
|
return true ;
|
|
Clear() ;
|
|
m_VtExtr = ccSrc.m_VtExtr ;
|
|
m_dThick = ccSrc.m_dThick ;
|
|
PCRVSMPL_DEQUE::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
|
|
{
|
|
// dati generali di una curva
|
|
if ( ! CurveDump( *this, sOut, szNewLine))
|
|
return false ;
|
|
// parametri : 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() ;
|
|
}
|
|
// da versione 1008 : linea con VtEstrusione e Spessore
|
|
if ( ! ngeOut.WriteVector( m_VtExtr, ";"))
|
|
return false ;
|
|
if ( ! ngeOut.WriteDouble( m_dThick, ";", true))
|
|
return false ;
|
|
|
|
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 ;
|
|
}
|
|
// da versione 1008 : linea con VtEstrusione e Spessore
|
|
if ( ngeIn.GetFileVersion() >= NGE_VER_1008) {
|
|
if ( ! ngeIn.ReadVector( m_VtExtr, ";"))
|
|
return false ;
|
|
if ( ! ngeIn.ReadDouble( m_dThick, ";", true))
|
|
return false ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::GetLocalBBox( BBox3d& b3Loc, int nFlag) 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, nFlag) ;
|
|
// aggiorno il box
|
|
b3Loc.Add( b3Crv) ;
|
|
// passo alla curva successiva
|
|
pCrvSmpl = GetNextCurve() ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::GetBBox( const Frame3d& frRef, BBox3d& b3Ref, int nFlag) 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, nFlag) ;
|
|
// aggiorno il box
|
|
b3Ref.Add( b3Crv) ;
|
|
// passo alla curva successiva
|
|
pCrvSmpl = GetNextCurve() ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::Validate( void)
|
|
{
|
|
if ( m_nStatus == TO_VERIFY) {
|
|
Point3d ptPrevEnd ;
|
|
Point3d ptStart ;
|
|
// ciclo su tutte le curve
|
|
int nCount = 0 ;
|
|
PCRVSMPL_DEQUE::const_iterator Iter ;
|
|
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 ( ! AreSamePointApprox( ptPrevEnd, ptStart)) {
|
|
m_nStatus = ERR ;
|
|
return false ;
|
|
}
|
|
}
|
|
// recupero il punto finale
|
|
(*Iter)->GetEndPoint( ptPrevEnd) ;
|
|
}
|
|
// aggiorno
|
|
m_nStatus = ( nCount > 0 ? OK : TO_VERIFY) ;
|
|
m_nCounter = nCount ;
|
|
if ( m_nStatus == OK) {
|
|
m_CrvSmplS.front()->GetStartPoint( m_PtStart) ;
|
|
m_CrvSmplS.back()->GetEndPoint( m_PtEnd) ;
|
|
m_bClosed = ( AreSamePointApprox( m_PtStart, m_PtEnd)) ;
|
|
}
|
|
else
|
|
m_bClosed = false ;
|
|
}
|
|
|
|
return ( m_nStatus == OK) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::IsFlat( Plane3d& plPlane, double dToler) const
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// polilinea dei punti rappresentativi
|
|
PolyLine shPL ;
|
|
// punto iniziale
|
|
Point3d ptP ;
|
|
if ( ! GetStartPoint( ptP) ||
|
|
! shPL.AddUPoint( 0, ptP))
|
|
return false ;
|
|
// ciclo sulle curve semplici (aggiungo solo eventuali punti intermedi e finali)
|
|
int nCount = 0 ;
|
|
for ( const ICurve* pCrv = GetFirstCurve() ;
|
|
pCrv != nullptr ;
|
|
pCrv = GetNextCurve(), ++ nCount) {
|
|
switch ( pCrv->GetType()) {
|
|
case CRV_LINE :
|
|
// punto finale
|
|
if ( ! pCrv->GetEndPoint( ptP) ||
|
|
! shPL.AddUPoint( nCount + 1, ptP))
|
|
return false ;
|
|
break ;
|
|
case CRV_ARC :
|
|
// punto a 1/3
|
|
if ( ! pCrv->GetPointD1D2( 0.3333, ICurve::FROM_MINUS, ptP) ||
|
|
! shPL.AddUPoint( nCount + 0.3333, ptP))
|
|
return false ;
|
|
// punto a 7/11
|
|
if ( ! pCrv->GetPointD1D2( 0.6363, ICurve::FROM_MINUS, ptP) ||
|
|
! shPL.AddUPoint( nCount + 0.6363, ptP))
|
|
return false ;
|
|
// punto finale
|
|
if ( ! pCrv->GetEndPoint( ptP) ||
|
|
! shPL.AddUPoint( nCount + 1, ptP))
|
|
return false ;
|
|
break ;
|
|
case CRV_BEZ :
|
|
{ const CurveBezier* pBez = GetBasicCurveBezier( pCrv) ;
|
|
// inserisco tutti i punti di controllo tranne il primo
|
|
int nLastPC = pBez->GetDegree() ;
|
|
for ( int i = 1 ; i <= nLastPC ; ++ i) {
|
|
double dU = nCount + i / double( nLastPC) ;
|
|
if ( ! shPL.AddUPoint( dU, pBez->GetControlPoint( i)))
|
|
return false ;
|
|
}
|
|
} break ;
|
|
}
|
|
}
|
|
// recupero dati sulla planarità della polilinea
|
|
int nRank ;
|
|
Point3d ptCen ;
|
|
Vector3d vtDir ;
|
|
bool bFlat = shPL.IsFlat( nRank, ptCen, vtDir, dToler) ;
|
|
// se punto
|
|
switch ( nRank) {
|
|
case 0 : // punto
|
|
if ( bFlat) {
|
|
plPlane.vtN = ( m_VtExtr.IsSmall() ? Z_AX : m_VtExtr) ;
|
|
plPlane.dDist = ( ptCen - ORIG) * plPlane.vtN ;
|
|
}
|
|
else {
|
|
plPlane.vtN = ( m_VtExtr.IsSmall() ? V_NULL : m_VtExtr) ;
|
|
plPlane.dDist = 0 ;
|
|
}
|
|
break ;
|
|
case 1 : // linea
|
|
if ( m_VtExtr.IsSmall()) {
|
|
plPlane.vtN = FromUprightOrtho( vtDir) ;
|
|
}
|
|
else {
|
|
plPlane.vtN = m_VtExtr ;
|
|
bFlat = bFlat && ( AreOrthoApprox( m_VtExtr, vtDir)) ;
|
|
}
|
|
plPlane.dDist = ( ptCen - ORIG) * plPlane.vtN ;
|
|
break ;
|
|
default : // piana o 3d
|
|
if ( m_VtExtr.IsSmall()) {
|
|
plPlane.vtN = vtDir ;
|
|
}
|
|
else {
|
|
plPlane.vtN = m_VtExtr ;
|
|
bFlat = bFlat && ( AreSameOrOppositeVectorApprox( m_VtExtr, vtDir)) ;
|
|
}
|
|
plPlane.dDist = ( ptCen - ORIG) * plPlane.vtN ;
|
|
break ;
|
|
}
|
|
|
|
return bFlat ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
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 del parametro a metà lunghezza
|
|
double dLen, dMid ;
|
|
if ( ! GetLength( dLen) || ! GetParamAtLength( 0.5 * dLen, dMid))
|
|
return false ;
|
|
// calcolo il punto
|
|
return GetPointD1D2( dMid, FROM_MINUS, ptMid) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::GetMidDir( Vector3d& vtDir) const
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
// determino il valore del parametro a metà lunghezza
|
|
double dLen, dMid ;
|
|
if ( ! GetLength( dLen) || ! GetParamAtLength( 0.5 * dLen, dMid))
|
|
return false ;
|
|
// calcolo la direzione
|
|
return ::GetTang( *this, 0.5 * m_nCounter, FROM_MINUS, vtDir) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
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::GetIndSCurveAndLocPar( double dU, Side nS, int& nSCrv, double& dLocU) const
|
|
{
|
|
// verifico che il parametro non sia troppo fuori dai limiti
|
|
if ( dU < - 100 * EPS_PARAM || dU > m_nCounter + 100 * EPS_PARAM)
|
|
return false ;
|
|
|
|
// il parametro U deve essere compreso tra 0 e m_nCounter (le curve chiuse sono cicliche)
|
|
if ( dU < ( 0 + EPS_PARAM)) {
|
|
// se chiusa e voglio valutare prima dell'inizio devo valutare prima della fine
|
|
if ( m_bClosed && nS == ICurve::FROM_MINUS)
|
|
dU = m_nCounter ;
|
|
// altrimenti posso valutare solo dopo l'inizio
|
|
else {
|
|
dU = 0 ;
|
|
nS = ICurve::FROM_PLUS ;
|
|
}
|
|
}
|
|
else if ( dU > ( m_nCounter - EPS_PARAM)) {
|
|
// se chiusa e voglio valutare dopo la fine devo valutare dopo l'inizio
|
|
if ( m_bClosed && nS == ICurve::FROM_PLUS)
|
|
dU = 0 ;
|
|
// altrimenti posso valutare solo prima della fine
|
|
else {
|
|
dU = m_nCounter ;
|
|
nS = ICurve::FROM_MINUS ;
|
|
}
|
|
}
|
|
|
|
// determino la curva di appartenenza e il valore locale (ovvero nella curva) del parametro
|
|
nSCrv = static_cast<int>( dU) ;
|
|
dLocU = dU - nSCrv ;
|
|
if ( fabs( dLocU) < EPS_PARAM && nSCrv > 0 && nS == ICurve::FROM_MINUS) {
|
|
-- nSCrv ;
|
|
dLocU += 1 ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::GetPointD1D2( double dU, Side nS, Point3d& ptPos, Vector3d* pvtDer1, Vector3d* pvtDer2) const
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// determino la curva di appartenenza e il valore locale del parametro
|
|
int nC ;
|
|
double dUc ;
|
|
if ( ! GetIndSCurveAndLocPar( dU, nS, nC, dUc))
|
|
return false ;
|
|
|
|
// eseguo il calcolo sulla curva semplice
|
|
return m_CrvSmplS[nC]->GetPointD1D2( dUc, ICurve::FROM_MINUS, ptPos, pvtDer1, pvtDer2) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::GetLength( double& dLen) const
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// ciclo di calcolo
|
|
dLen = 0 ;
|
|
PCRVSMPL_DEQUE::const_iterator Iter ;
|
|
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) {
|
|
double dLenCrvSmpl ;
|
|
if ( (*Iter)->GetLength( dLenCrvSmpl))
|
|
dLen += dLenCrvSmpl ;
|
|
else
|
|
return false ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::GetLengthAtParam( double dU, double& dLen) const
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// il parametro U deve essere compreso tra 0 e m_nCounter
|
|
if ( dU < - EPS_PARAM || dU > ( m_nCounter + EPS_PARAM))
|
|
return false ;
|
|
|
|
// ciclo di calcolo
|
|
dLen = 0 ;
|
|
double dUToGo = dU ;
|
|
PCRVSMPL_DEQUE::const_iterator Iter ;
|
|
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) {
|
|
// dominio parametrico della curva semplice
|
|
double dParStart, dParEnd ;
|
|
(*Iter)->GetDomain( dParStart, dParEnd) ;
|
|
// se resto nella curva
|
|
if ( dUToGo <= ( dParEnd - dParStart)) {
|
|
double dParamLen ;
|
|
if ( ! (*Iter)->GetLengthAtParam( dUToGo, dParamLen))
|
|
return false ;
|
|
dLen += dParamLen ;
|
|
break ;
|
|
}
|
|
// altrimenti
|
|
else {
|
|
// lunghezza parametrica rimanente
|
|
dUToGo -= ( dParEnd - dParStart) ;
|
|
// lunghezza progressiva
|
|
double dCrvLen ;
|
|
if ( ! (*Iter)->GetLength( dCrvLen))
|
|
return false ;
|
|
dLen += dCrvLen ;
|
|
}
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::GetParamAtLength( double dLen, double& dU) const
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// se prima di inizio, errore
|
|
if ( dLen < - EPS_SMALL)
|
|
return false ;
|
|
|
|
// inizio
|
|
if ( dLen < EPS_SMALL) {
|
|
dU = 0 ;
|
|
return true ;
|
|
}
|
|
|
|
// ciclo di calcolo
|
|
dU = 0 ;
|
|
double dLenToGo = dLen ;
|
|
PCRVSMPL_DEQUE::const_iterator Iter ;
|
|
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) {
|
|
// lunghezza della curva semplice
|
|
double dCrvLen ;
|
|
if ( ! (*Iter)->GetLength( dCrvLen))
|
|
return false ;
|
|
// se resto nella curva
|
|
if ( dLenToGo <= dCrvLen) {
|
|
double dULen ;
|
|
if ( ! (*Iter)->GetParamAtLength( dLenToGo, dULen))
|
|
return false ;
|
|
dU += dULen ;
|
|
break ;
|
|
}
|
|
// altrimenti
|
|
else {
|
|
// lunghezza rimanente
|
|
dLenToGo -= dCrvLen ;
|
|
// lunghezza parametrica progressiva
|
|
double dParStart, dParEnd ;
|
|
(*Iter)->GetDomain( dParStart, dParEnd) ;
|
|
dU += ( dParEnd - dParStart) ;
|
|
}
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::IsPointOn( const Point3d& ptP, double dTol) const
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
// verifico che il punto sia sulla curva ( distanza minore di tolleranza)
|
|
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() ;
|
|
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// eseguo approssimazione
|
|
double dStartPar = 0 ;
|
|
PolyLine PLSmpl ;
|
|
PCRVSMPL_DEQUE::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 ( ! PL.Join( PLSmpl, dStartPar))
|
|
return false ;
|
|
// incremento inizio parametro per prossima curva semplice
|
|
dStartPar += 1 ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::ApproxWithArcs( double dLinTol, double dAngTolDeg, PolyArc& PA) const
|
|
{
|
|
// pulisco il poliarco
|
|
PA.Clear() ;
|
|
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// eseguo approssimazione
|
|
double dStartPar = 0 ;
|
|
PolyArc PASmpl ;
|
|
PCRVSMPL_DEQUE::const_iterator Iter ;
|
|
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) {
|
|
// recupero approssimazione per curva semplice
|
|
if ( ! (*Iter)->ApproxWithArcs( dLinTol, dAngTolDeg, PASmpl))
|
|
return false ;
|
|
// la accodo opportunamente a quella della curva composita
|
|
if ( ! PA.Join( PASmpl, dStartPar))
|
|
return false ;
|
|
// incremento inizio parametro per prossima curva semplice
|
|
dStartPar += 1 ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
ICurve*
|
|
CurveComposite::CopyParamRange( double dUStart, double dUEnd) const
|
|
{
|
|
// i parametri start ed end devono essere compresi nel dominio parametrico della curva
|
|
if ( dUStart < - EPS_PARAM || dUStart > m_nCounter + EPS_PARAM ||
|
|
dUEnd < - EPS_PARAM || dUEnd > m_nCounter + EPS_PARAM)
|
|
return nullptr ;
|
|
// se il parametro start supera quello di end
|
|
if ( dUStart > dUEnd - EPS_PARAM) {
|
|
// se curva aperta, il trim la cancella completamente quindi non resta alcunchè
|
|
if ( ! m_bClosed)
|
|
return nullptr ;
|
|
// se curva chiusa, il trim si avvolge attorno al punto di giunzione
|
|
else
|
|
// incremento il parametro finale della dimensione del dominio parametrico originale della curva
|
|
dUEnd += m_nCounter ;
|
|
}
|
|
// determino gli indici della prima e dell'ultima curva da copiare
|
|
int nIdStart = static_cast<int>( floor( dUStart)) ;
|
|
int nIdEnd = static_cast<int>( ceil( dUEnd)) ;
|
|
// creo la curva composita copia
|
|
PtrOwner<CurveComposite> pCopy( new CurveComposite()) ;
|
|
if ( IsNull( pCopy))
|
|
return nullptr ;
|
|
// eseguo la copia delle sole curve semplici necessarie
|
|
for ( int i = nIdStart ; i < nIdEnd ; ++ i) {
|
|
// quando supero il numero di curve nella composita originale riparto dall'inizio
|
|
int j = i % m_nCounter ;
|
|
// accodo la curva alla copia
|
|
if ( ! pCopy->AddCurve( *(m_CrvSmplS[j])))
|
|
return nullptr ;
|
|
}
|
|
// aggiorno i parametri di trim, tenendo conto delle curve semplici saltate all'inizio
|
|
dUStart -= nIdStart ;
|
|
dUEnd -= nIdStart ;
|
|
// eseguo il trim della copia
|
|
if ( ! pCopy->TrimStartEndAtParam( dUStart, dUEnd))
|
|
return nullptr ;
|
|
return ( ::Release( pCopy)) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::Invert( void)
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// inverto le singole curve
|
|
PCRVSMPL_DEQUE::iterator Iter ;
|
|
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter)
|
|
(*Iter)->Invert() ;
|
|
|
|
// inverto l'ordine della lista
|
|
reverse( m_CrvSmplS.begin(), m_CrvSmplS.end()) ;
|
|
|
|
// scambio punti iniziale e finale
|
|
swap( m_PtStart, m_PtEnd) ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::ModifyStart( const Point3d& ptNewStart)
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// recupero la prima curva
|
|
if ( m_CrvSmplS.empty())
|
|
return false ;
|
|
ICurve* pCrv = m_CrvSmplS.front() ;
|
|
// modifico l'inizio di questa curva
|
|
if ( ! pCrv->ModifyStart( ptNewStart))
|
|
return false ;
|
|
// aggiorno il punto iniziale e il flag di curva chiusa
|
|
m_PtStart = ptNewStart ;
|
|
m_bClosed = ( AreSamePointApprox( m_PtStart, m_PtEnd)) ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::ModifyEnd( const Point3d& ptNewEnd)
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
// recupero l'ultima curva
|
|
if ( m_CrvSmplS.empty())
|
|
return false ;
|
|
ICurve* pCrv = m_CrvSmplS.back() ;
|
|
// modifico la fine di questa curva
|
|
if ( ! pCrv->ModifyEnd( ptNewEnd))
|
|
return false ;
|
|
// aggiorno il punto finale e il flag di curva chiusa
|
|
m_PtEnd = ptNewEnd ;
|
|
m_bClosed = ( AreSamePointApprox( m_PtStart, m_PtEnd)) ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::TrimStartAtParam( double dUTrim)
|
|
{
|
|
// ciclo sulle diverse curve dall'inizio
|
|
double dUToTrim = dUTrim ;
|
|
PCRVSMPL_DEQUE::iterator Iter ;
|
|
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ;) {
|
|
// dominio parametrico della curva semplice
|
|
double dParStart, dParEnd ;
|
|
(*Iter)->GetDomain( dParStart, dParEnd) ;
|
|
// lunghezza parametrica progressiva
|
|
dUToTrim -= ( dParEnd - dParStart) ;
|
|
// se lunghezza ancora da tagliare non nulla
|
|
if ( dUToTrim > EPS_PARAM) {
|
|
delete (*Iter) ;
|
|
Iter ++ ;
|
|
m_CrvSmplS.pop_front() ;
|
|
m_nCounter -- ;
|
|
}
|
|
// se lunghezza ancora da tagliare nulla (entro la tolleranza)
|
|
else if ( dUToTrim > - EPS_PARAM ||
|
|
! (*Iter)->TrimStartAtParam( 1 + dUToTrim)) {
|
|
delete (*Iter) ;
|
|
Iter ++ ;
|
|
m_CrvSmplS.pop_front() ;
|
|
m_nCounter -- ;
|
|
if ( m_nCounter == 0)
|
|
return false ;
|
|
(*Iter)->GetStartPoint( m_PtStart) ;
|
|
m_bClosed = ( AreSamePointApprox( m_PtStart, m_PtEnd)) ;
|
|
break ;
|
|
}
|
|
// altrimenti superata lunghezza ancora da tagliare (taglio già fatto al test sopra)
|
|
else {
|
|
(*Iter)->GetStartPoint( m_PtStart) ;
|
|
m_bClosed = ( AreSamePointApprox( m_PtStart, m_PtEnd)) ;
|
|
break ;
|
|
}
|
|
}
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::TrimEndAtParam( double dUTrim)
|
|
{
|
|
// ciclo sulle diverse curve dalla fine
|
|
bool bToErase = false ;
|
|
double dUToTrim = dUTrim ;
|
|
PCRVSMPL_DEQUE::iterator Iter ;
|
|
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ;) {
|
|
// dominio parametrico della curva semplice
|
|
double dParStart, dParEnd ;
|
|
(*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_PARAM) {
|
|
Iter ++ ;
|
|
}
|
|
// se lunghezza parametrica ancora da tagliare nulla (entro la tolleranza)
|
|
else if ( dUToTrim > - EPS_PARAM) {
|
|
// imposto punto finale e verifico curva chiusa
|
|
(*Iter)->GetEndPoint( m_PtEnd) ;
|
|
m_bClosed = ( AreSamePointApprox( 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)) {
|
|
// se trim fallito, rimaneva troppo poco e quindi la cancello
|
|
bToErase = true ;
|
|
continue ;
|
|
}
|
|
// imposto punto finale e verifica curva chiusa
|
|
(*Iter)->GetEndPoint( m_PtEnd) ;
|
|
m_bClosed = ( AreSamePointApprox( 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::TrimStartEndAtParam( double dUStartTrim, double dUEndTrim)
|
|
{
|
|
// i parametri start ed end devono essere compresi nel dominio parametrico della curva
|
|
if ( dUStartTrim < - EPS_PARAM || dUStartTrim > m_nCounter + EPS_PARAM ||
|
|
dUEndTrim < - EPS_PARAM || dUEndTrim > m_nCounter + EPS_PARAM)
|
|
return false ;
|
|
#if 0
|
|
// verifico che i trim non cancellino interamente la curva
|
|
if ( dUStartTrim > dUEndTrim - EPS_PARAM)
|
|
return false ;
|
|
#endif
|
|
// se il parametro start supera quello di end
|
|
if ( dUStartTrim > dUEndTrim - EPS_PARAM) {
|
|
// se curva aperta, il trim la cancella completamente quindi errore
|
|
if ( ! m_bClosed)
|
|
return false ;
|
|
// se curva chiusa, il trim interessa il punto di giunzione
|
|
else {
|
|
// calcolo il minimo numero di curve da accodare per coprire il range esteso
|
|
int nNumCrv = static_cast<int>( ceil( dUEndTrim)) ;
|
|
// incremento il parametro finale della dimensione del dominio parametrico originale della curva
|
|
dUEndTrim += m_nCounter ;
|
|
// eseguo accodamento delle curve
|
|
for ( int i = 0 ; i < nNumCrv ; ++ i) {
|
|
if ( ! AddCurve( *(m_CrvSmplS[i])))
|
|
return false ;
|
|
}
|
|
}
|
|
}
|
|
// per parametro start : determino la curva di appartenenza e il valore locale del parametro
|
|
int nCs ;
|
|
double dUcs ;
|
|
if ( ! GetIndSCurveAndLocPar( dUStartTrim, ICurve::FROM_PLUS, nCs, dUcs))
|
|
return false ;
|
|
// per parametro end : determino la curva di appartenenza e il valore locale del parametro
|
|
int nCe ;
|
|
double dUce ;
|
|
if ( ! GetIndSCurveAndLocPar( dUEndTrim, ICurve::FROM_MINUS, nCe, dUce))
|
|
return false ;
|
|
// trim finale
|
|
if ( ! TrimEndAtParam( dUEndTrim))
|
|
return false ;
|
|
// se i due trim sono fatti sulla stessa curva devo compensare la riparametrizzazione dopo il primo
|
|
if ( nCs == nCe) {
|
|
double dNewUStartTrim = nCs + dUcs / dUce ;
|
|
return TrimStartAtParam( dNewUStartTrim) ;
|
|
}
|
|
// altrimenti, va bene il valore ricevuto come parametro
|
|
else
|
|
return TrimStartAtParam( dUStartTrim) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::TrimStartAtLen( double dLenTrim)
|
|
{
|
|
// ciclo sulle diverse curve dall'inizio
|
|
double dLenToTrim = dLenTrim ;
|
|
PCRVSMPL_DEQUE::iterator Iter ;
|
|
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ;) {
|
|
// lunghezza della curva
|
|
double dCrvLen ;
|
|
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 = ( AreSamePointApprox( 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 = ( AreSamePointApprox( m_PtStart, m_PtEnd)) ;
|
|
break ;
|
|
}
|
|
}
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::TrimEndAtLen( double dLenTrim)
|
|
{
|
|
// ciclo sulle diverse curve dalla fine
|
|
bool bToErase = false ;
|
|
double dLenToTrim = dLenTrim ;
|
|
PCRVSMPL_DEQUE::iterator Iter ;
|
|
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ;) {
|
|
double dCrvLen ;
|
|
// 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 = ( AreSamePointApprox( 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 = ( AreSamePointApprox( 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::ExtendStartByLen( double dLenExt)
|
|
{
|
|
// la lunghezza di estensione deve essere positiva
|
|
if ( dLenExt < - EPS_ZERO)
|
|
return false ;
|
|
|
|
// recupero la prima curva ed estendo quella
|
|
if ( m_CrvSmplS.begin() == m_CrvSmplS.end())
|
|
return false ;
|
|
// estendo la prima curva
|
|
if ( ! (*m_CrvSmplS.begin())->ExtendStartByLen( dLenExt)) {
|
|
m_nStatus = ERR ;
|
|
return false ;
|
|
}
|
|
|
|
// imposto punto iniziale e verifica curva chiusa
|
|
(*m_CrvSmplS.begin())->GetStartPoint( m_PtStart) ;
|
|
m_bClosed = ( AreSamePointApprox( m_PtStart, m_PtEnd)) ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::ExtendEndByLen( double dLenExt)
|
|
{
|
|
// la lunghezza di estensione deve essere positiva
|
|
if ( dLenExt < - EPS_ZERO)
|
|
return false ;
|
|
|
|
// vado sulla fine
|
|
PCRVSMPL_DEQUE::iterator Iter = m_CrvSmplS.end() ;
|
|
if ( Iter == m_CrvSmplS.begin())
|
|
return false ;
|
|
-- Iter ;
|
|
// recupero la curva
|
|
if ( Iter == m_CrvSmplS.end())
|
|
return false ;
|
|
// estendo l'ultima curva
|
|
if ( ! (*Iter)->ExtendEndByLen( dLenExt)) {
|
|
m_nStatus = ERR ;
|
|
return false ;
|
|
}
|
|
|
|
// imposto punto finale e verifica curva chiusa
|
|
(*m_CrvSmplS.begin())->GetEndPoint( m_PtEnd) ;
|
|
m_bClosed = ( AreSamePointApprox( m_PtStart, m_PtEnd)) ;
|
|
|
|
// 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_DEQUE::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_DEQUE::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) ;
|
|
// ruoto il vettore estrusione
|
|
m_VtExtr.Rotate( 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_DEQUE::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) ;
|
|
// scalo vettore estrusione, lo normalizzo e aggiusto spessore
|
|
m_VtExtr.Scale( frRef, dCoeffX, dCoeffY, dCoeffZ) ;
|
|
double dLen = m_VtExtr.Len() ;
|
|
if ( dLen > EPS_ZERO) {
|
|
m_VtExtr /= dLen ;
|
|
m_dThick *= dLen ;
|
|
}
|
|
|
|
m_nStatus = TO_VERIFY ;
|
|
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_DEQUE::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) ;
|
|
// specchio il vettore estrusione
|
|
m_VtExtr.Mirror( 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_DEQUE::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) ;
|
|
// eseguo scorrimento del vettore estrusione, lo normalizzo e aggiusto spessore
|
|
m_VtExtr.Shear( vtNorm, vtDir, dCoeff) ;
|
|
double dLen = m_VtExtr.Len() ;
|
|
if ( dLen > EPS_ZERO) {
|
|
m_VtExtr /= dLen ;
|
|
m_dThick *= dLen ;
|
|
}
|
|
|
|
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_DEQUE::iterator Iter ;
|
|
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter)
|
|
(*Iter)->ToGlob( frRef) ;
|
|
|
|
// trasformo i punti estremi e il vettore estrusione
|
|
m_PtStart.ToGlob( frRef) ;
|
|
m_PtEnd.ToGlob( frRef) ;
|
|
m_VtExtr.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_DEQUE::iterator Iter ;
|
|
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter)
|
|
(*Iter)->ToLoc( frRef) ;
|
|
|
|
// trasformo i punti estremi e il vettore estrusione
|
|
m_PtStart.ToLoc( frRef) ;
|
|
m_PtEnd.ToLoc( frRef) ;
|
|
m_VtExtr.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_DEQUE::iterator Iter ;
|
|
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) {
|
|
(*Iter)->LocToLoc( frOri, frDest) ;
|
|
}
|
|
|
|
// trasformo i punti estremi e il vettore estrusione
|
|
m_PtStart.LocToLoc( frOri, frDest) ;
|
|
m_PtEnd.LocToLoc( frOri, frDest) ;
|
|
m_VtExtr.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
|
|
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
|
|
++ m_Iter ;
|
|
|
|
// recupero la curva
|
|
if ( m_Iter != m_CrvSmplS.end())
|
|
return (*m_Iter) ;
|
|
else
|
|
return nullptr ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
const ICurve*
|
|
CurveComposite::GetLastCurve( void) const
|
|
{
|
|
// la curva deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return nullptr ;
|
|
|
|
// vado alla fine
|
|
m_Iter = m_CrvSmplS.end() ;
|
|
if ( m_Iter == m_CrvSmplS.begin())
|
|
return nullptr ;
|
|
-- m_Iter ;
|
|
|
|
// recupero la curva
|
|
if ( m_Iter != m_CrvSmplS.end())
|
|
return (*m_Iter) ;
|
|
else
|
|
return nullptr ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
const ICurve*
|
|
CurveComposite::GetPrevCurve( void) const
|
|
{
|
|
// la curva deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return nullptr ;
|
|
|
|
// vado al precedente
|
|
if ( m_Iter == m_CrvSmplS.begin())
|
|
return nullptr ;
|
|
-- m_Iter ;
|
|
|
|
// recupero la curva
|
|
if ( m_Iter != m_CrvSmplS.end())
|
|
return (*m_Iter) ;
|
|
else
|
|
return nullptr ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
ICurve*
|
|
CurveComposite::RemoveFirstOrLastCurve( bool bLast)
|
|
{
|
|
// la curva composita deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return nullptr ;
|
|
|
|
// recupero la curva semplice iniziale o finale e la tolgo dalla lista
|
|
if ( ! m_CrvSmplS.empty()) {
|
|
ICurve* pCrv ;
|
|
if ( bLast) {
|
|
// recupero la curva
|
|
pCrv = *(m_CrvSmplS.rbegin()) ;
|
|
// la tolgo dalla lista
|
|
m_CrvSmplS.pop_back() ;
|
|
// aggiorno la curva composita
|
|
pCrv->GetStartPoint( m_PtEnd) ;
|
|
-- m_nCounter ;
|
|
}
|
|
else {
|
|
// recupero la curva
|
|
pCrv = *(m_CrvSmplS.begin()) ;
|
|
// la tolgo dalla lista
|
|
m_CrvSmplS.pop_front() ;
|
|
// aggiorno la curva composita
|
|
pCrv->GetEndPoint( m_PtStart) ;
|
|
-- m_nCounter ;
|
|
}
|
|
// eseguo mini verifica
|
|
m_nStatus = ( m_nCounter > 0 ? OK : TO_VERIFY) ;
|
|
if ( m_nStatus == OK)
|
|
m_bClosed = ( AreSamePointApprox( m_PtStart, m_PtEnd)) ;
|
|
else
|
|
m_bClosed = false ;
|
|
// assegno estrusione e spessore della curva composita
|
|
pCrv->SetExtrusion( m_VtExtr) ;
|
|
pCrv->SetThickness( m_dThick) ;
|
|
return pCrv ;
|
|
}
|
|
else
|
|
return nullptr ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::IsParamAtJoint( double dU) const
|
|
{
|
|
// se aperta e all'inizio o alla fine o lontano dagli interi non è giunzione
|
|
if ( ( ! m_bClosed && fabs( dU) < EPS_ZERO) ||
|
|
( ! m_bClosed && fabs( dU - m_nCounter) < EPS_ZERO) ||
|
|
fabs( dU - (int) ( dU + EPS_ZERO)) > EPS_ZERO)
|
|
return false ;
|
|
else
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::ChangeStartPoint( double dU)
|
|
{
|
|
// la curva deve essere chiusa (ne verifica anche lo stato)
|
|
if ( ! IsClosed())
|
|
return false ;
|
|
|
|
// il nuovo inizio è l'estremo di una curva semplice più vicino al parametro ricevuto
|
|
int nCurve = static_cast<int> ( dU + 0.5) ;
|
|
|
|
// verifico ci siano abbastanza curve
|
|
if ( nCurve > m_nCounter)
|
|
return false ;
|
|
|
|
// tolgo le curve dalla testa e le inserisco in coda
|
|
for ( int i = 0 ; i < nCurve ; ++ i) {
|
|
// estraggo la curva dall'inizio
|
|
ICurve* pCrv = RemoveFirstOrLastCurve( false) ;
|
|
if ( pCrv == nullptr)
|
|
return false ;
|
|
// la inserisco alla fine
|
|
if ( ! AddCurve( pCrv, true)) {
|
|
delete pCrv ;
|
|
return false ;
|
|
}
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::ArcsToBezierCurves( void)
|
|
{
|
|
// verifico le singole curve
|
|
PCRVSMPL_DEQUE::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) {
|
|
// eseguo trasformazione
|
|
PtrOwner<ICurve> pNewCrv( ArcToBezierCurve( (*Iter))) ;
|
|
if ( IsNull( pNewCrv))
|
|
return false ;
|
|
// se risultato è singola curva
|
|
if ( pNewCrv->IsSimple()) {
|
|
// elimino l'arco e lo sostituisco con la curva di Bezier
|
|
delete (*Iter) ;
|
|
(*Iter) = Release( pNewCrv) ;
|
|
}
|
|
// altrimenti è una curva composita
|
|
else {
|
|
CurveComposite* pCC = GetBasicCurveComposite( Get( pNewCrv)) ;
|
|
if ( pCC == nullptr)
|
|
return false ;
|
|
// inserisco le curve prima dell'arco
|
|
int nParts = 0 ;
|
|
PCRVSMPL_DEQUE::iterator Iter2 ;
|
|
for ( Iter2 = pCC->m_CrvSmplS.begin() ; Iter2 != pCC->m_CrvSmplS.end() ; ++ Iter2) {
|
|
Iter = m_CrvSmplS.insert( Iter, (*Iter2)) ;
|
|
++ Iter ;
|
|
++ nParts ;
|
|
}
|
|
pCC->m_CrvSmplS.clear() ;
|
|
pCC->m_nCounter = 0 ;
|
|
// elimino l'arco (e sposto l'iteratore alla curva precedente)
|
|
delete (*Iter) ;
|
|
Iter = m_CrvSmplS.erase( Iter) ;
|
|
-- Iter ;
|
|
// aggiorno il numero di curve
|
|
m_nCounter += nParts - 1 ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|