Files
EgtGeomKernel/CurveComposite.cpp
T
2013-12-24 22:09:55 +00:00

848 lines
24 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 <algorithm>
#include "\EgtDev\Include\EGnStringUtils.h"
#include "CurveComposite.h"
#include "GeoObjFactory.h"
using namespace std ;
//----------------------------------------------------------------------------
GEOOBJ_REGISTER( CRV_COMPO, "C_CMP", CurveComposite) ;
//----------------------------------------------------------------------------
const double CurveComposite::PAR_START = 0 ;
//----------------------------------------------------------------------------
CurveComposite::CurveComposite( void)
{
m_nStatus = TO_VERIFY ;
m_nCounter = 0 ;
m_bClosed = false ;
}
//----------------------------------------------------------------------------
CurveComposite::~CurveComposite( void)
{
Clear() ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::Clear( void)
{
PCRVSMPL_LIST::iterator Iter ;
// ciclo di pulizia
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter)
delete (*Iter) ;
m_CrvSmplS.clear() ;
m_nCounter = 0 ;
m_bClosed = false ;
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)) {
delete 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)) {
delete pSmplCrv ;
return false ;
}
// passo alla prossima curva componente
pCrvOri = pCrvCompo->GetNextCurve() ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::AddSimpleCurve( ICurve* pSmplCrv)
{
Point3d ptStart ;
Point3d ptEnd ;
// 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 ( ! pSmplCrv->IsSimple())
return false ;
// recupero i punti iniziali e finali della curva
if ( ! pSmplCrv->GetStartPoint( ptStart) || ! pSmplCrv->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( pSmplCrv) ;
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 ;
}
//----------------------------------------------------------------------------
CurveComposite*
CurveComposite::Clone( void) const
{
CurveComposite* pCrv ;
// alloco oggetto
pCrv = new(nothrow) CurveComposite ;
if ( pCrv != nullptr)
*pCrv = *(const_cast<CurveComposite*>(this)) ;
return pCrv ;
}
//----------------------------------------------------------------------------
const string&
CurveComposite::GetKey( void) const
{
return GEOOBJ_GETKEY( CurveComposite) ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::Save( ostream& osOut) const
{
int i ;
string sCrvName ;
const ICurve* pCrvSmpl ;
// numero di curve
osOut << ToString( m_nCounter) << endl ;
// ciclo sulle curve componenti
i = 0 ;
pCrvSmpl = GetFirstCurve() ;
while ( pCrvSmpl != nullptr) {
// emetto tipo della curva semplice
osOut << pCrvSmpl->GetKey() << endl ;
// assegno ed emetto nome della curva semplice
sCrvName = "#" + ToString( ++i) ;
osOut << sCrvName << endl ;
// salvataggio della curva semplice
if ( ! pCrvSmpl->Save( osOut))
return false ;
// passo alla successiva
pCrvSmpl = GetNextCurve() ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::Load( Scanner& TheScanner)
{
int nType ;
string sLine ;
STRVECTOR vsParams ;
bool bOk ;
int i ;
int nCounter ;
IGeoObj* pGeoO ;
ICurve* pCrv ;
// leggo la prossima linea
if ( ! TheScanner.GetLine( sLine))
return false ;
// la divido in parametri
Tokenize( sLine, ",", vsParams) ;
// 1 parametro : numero di curve componenti
if ( vsParams.size() != 1)
return false ;
// recupero il numero di curve componenti
if ( ! FromString( vsParams[0], nCounter))
return false ;
// leggo le curve componenti
for ( i = 0 ; i < nCounter ; ++ i) {
// recupero la prossima linea (con il tipo di oggetto)
if ( ! TheScanner.GetLine( sLine))
return false ;
// creo l'oggetto
nType = GEOOBJ_KEYTOTYPE( sLine) ;
pGeoO = GEOOBJ_CREATE( nType) ;
if ( pGeoO == nullptr)
return false ;
// recupero la linea con il nome
bOk = TheScanner.GetLine( sLine) ;
// ne leggo i dati
bOk = bOk && pGeoO->Load( TheScanner) ;
// verifico sia una curva
pCrv = ::GetCurve( pGeoO) ;
bOk = bOk && ( pCrv != nullptr && pCrv->IsSimple()) ;
// aggiungo questa curva (sicuramente semplice)
bOk = bOk && AddSimpleCurve( pCrv) ;
// se errore
if ( ! bOk) {
delete pGeoO ;
return false ;
}
}
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::GetDomain( double& dStart, double& dEnd) const
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// assegno gli estremi del dominio
dStart = PAR_START ;
dEnd = m_nCounter ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::GetPointD1D2( double dU, Point3d& ptPos, Vector3d& vtDer1, Vector3d& vtDer2) const
{
double dParStart ;
double dParEnd ;
PCRVSMPL_LIST::const_iterator Iter ;
// il parametro U deve essere compreso tra 0 e m_nCounter
if ( dU < PAR_START)
dU = PAR_START ;
else if ( dU > m_nCounter)
dU = m_nCounter ;
// determino la curva di appartenenza e faccio eseguire il calcolo
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) {
(*Iter)->GetDomain( dParStart, dParEnd) ;
if ( dU <= ( dParEnd - dParStart))
return (*Iter)->GetPointD1D2( dParStart + dU, ptPos, vtDer1, vtDer2) ;
else
dU -= ( dParEnd - dParStart) ;
}
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::ApproxWithLines( double dLinTol, double dAngTolDeg, PolyLine& PL) const
{
bool bFirst ;
double dStartPar ;
Point3d ptP ;
PolyLine PLSmpl ;
PCRVSMPL_LIST::const_iterator Iter ;
bFirst = true ;
dStartPar = 0 ;
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::Reverse( void)
{
PCRVSMPL_LIST::iterator Iter ;
// inverto le singole curve
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter)
(*Iter)->Reverse() ;
// inverto l'ordine della lista
m_CrvSmplS.reverse() ;
// scambio punti iniziale e finale
swap( m_PtStart, m_PtEnd) ;
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 ;
}
}
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 ;
}
}
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 ;
}
}
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 ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::Translate( const Vector3d& vtMove)
{
PCRVSMPL_LIST::iterator Iter ;
// traslo le singole curve
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)
{
PCRVSMPL_LIST::iterator Iter ;
// verifico validità dell'asse di rotazione
if ( vtAx.IsSmall())
return false ;
// ruoto le singole curve
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 Point3d& ptCen, double dCoeffX, double dCoeffY, double dCoeffZ)
{
PCRVSMPL_LIST::iterator Iter ;
// ammessa solo scalatura uniforme (per la presenza di archi)
if ( fabs( dCoeffX - dCoeffY) > EPS_SMALL || fabs( dCoeffX - dCoeffZ) > EPS_SMALL)
return false ;
// verifico non sia nulla
if ( fabs( dCoeffX) < EPS_ZERO)
return false ;
// scalo le singole curve
for ( Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter)
(*Iter)->Scale( ptCen, dCoeffX, dCoeffX, dCoeffX) ;
// scalo i punti estremi
m_PtStart.Scale( ptCen, dCoeffX, dCoeffX, dCoeffX) ;
m_PtEnd.Scale( ptCen, dCoeffX, dCoeffX, dCoeffX) ;
return Validate() ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::Mirror( const Point3d& ptOn, const Vector3d& vtNorm)
{
PCRVSMPL_LIST::iterator Iter ;
// verifico validità del piano di specchiatura
if ( vtNorm.IsSmall())
return false ;
// specchio le singole curve
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::ToGlob( const Frame3d& frRef)
{
PCRVSMPL_LIST::iterator Iter ;
// verifico validità del frame
if ( frRef.GetType() == Frame3d::ERR)
return false ;
// trasformo le singole curve
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)
{
PCRVSMPL_LIST::iterator Iter ;
// verifico validità del frame
if ( frRef.GetType() == Frame3d::ERR)
return false ;
// trasformo le singole curve
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 ;
}
//----------------------------------------------------------------------------
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 ;
}
//----------------------------------------------------------------------------
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 ;
}