234878388d
- approssimazione con archi di curve composite viene fatta nel piano perpendicolare all'estrusione o se questa non definita nel piano medio della curva - trim start/end a parametro di curve composite ora irrobustito.
3536 lines
115 KiB
C++
3536 lines
115 KiB
C++
//----------------------------------------------------------------------------
|
|
// EgalTech 2013-2022
|
|
//----------------------------------------------------------------------------
|
|
// File : CurveComposite.cpp Data : 23.01.22 Versione : 2.4a4
|
|
// Contenuto : Implementazione della classe CCurveComposite.
|
|
//
|
|
//
|
|
//
|
|
// Modifiche : 26.04.13 DS Creazione modulo.
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
//--------------------------- Include ----------------------------------------
|
|
#include "stdafx.h"
|
|
#include "CurveComposite.h"
|
|
#include "DistPointLine.h"
|
|
#include "DistPointCrvComposite.h"
|
|
#include "CurveLine.h"
|
|
#include "CurveArc.h"
|
|
#include "CurveBezier.h"
|
|
#include "PolygonPlane.h"
|
|
#include "SurfFlatRegion.h"
|
|
#include "RemoveCurveDefects.h"
|
|
#include "GeoConst.h"
|
|
#include "GeoObjFactory.h"
|
|
#include "NgeWriter.h"
|
|
#include "NgeReader.h"
|
|
#include "/EgtDev/Include/EGkCurveByApprox.h"
|
|
#include "/EgtDev/Include/EGkArcSpecial.h"
|
|
#include "/EgtDev/Include/EGkSfrCreate.h"
|
|
#include "/EgtDev/Include/EGkIntervals.h"
|
|
#include "/EgtDev/Include/EGkStringUtils3d.h"
|
|
#include "/EgtDev/Include/EgtNumUtils.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_VtExtr(), m_dThick(), m_ptStart(), m_Iter( m_CrvSmplS.end())
|
|
{
|
|
m_nTempProp[0] = 0 ;
|
|
m_nTempProp[1] = 0 ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
CurveComposite::~CurveComposite( void)
|
|
{
|
|
Clear() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::Clear( void)
|
|
{
|
|
// ciclo di pulizia
|
|
for ( auto Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter)
|
|
delete (*Iter) ;
|
|
m_CrvSmplS.clear() ;
|
|
|
|
m_nStatus = TO_VERIFY ;
|
|
m_VtExtr = V_NULL ;
|
|
m_dThick = 0 ;
|
|
m_ptStart = ORIG ;
|
|
m_nTempProp[0] = 0 ;
|
|
m_nTempProp[1] = 0 ;
|
|
m_Iter = m_CrvSmplS.end() ;
|
|
|
|
// 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 = 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 = 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 composita, devo aggiungere le singole curve semplici
|
|
else {
|
|
// riloco le curve dalla composita sorgente alla corrente
|
|
PtrOwner<CurveComposite> pCrvCompo( GetBasicCurveComposite( pCrv)) ;
|
|
if ( IsNull( pCrvCompo) || ! AddCurveByRelocate( *pCrvCompo, bEndOrStart, dLinTol))
|
|
return false ;
|
|
}
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::AddCurveByRelocate( CurveComposite& ccSrc, bool bEndOrStart, double dLinTol)
|
|
{
|
|
// verifica curva
|
|
if ( &ccSrc == nullptr)
|
|
return false ;
|
|
|
|
// recupero le curve componenti e le inserisco nella lista
|
|
ICurve* pSmplCrv ;
|
|
while ( ( pSmplCrv = ccSrc.RemoveFirstOrLastCurve( ! bEndOrStart)) != nullptr) {
|
|
// inserisco la curva
|
|
if ( ! AddSimpleCurve( pSmplCrv, bEndOrStart, dLinTol))
|
|
return false ;
|
|
}
|
|
|
|
// 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_CrvSmplS.empty() && m_nStatus == TO_VERIFY))
|
|
return false ;
|
|
|
|
// controllo la tolleranza
|
|
dLinTol = max( dLinTol, EPS_SMALL) ;
|
|
|
|
// verifico che il parametro sia una curva semplice
|
|
if ( ! pCrv->IsSimple())
|
|
return false ;
|
|
|
|
// annullo l'estrusione e lo spessore
|
|
pCrv->SetExtrusion( V_NULL) ;
|
|
pCrv->SetThickness( 0) ;
|
|
|
|
// recupero i punti iniziali e finali della curva
|
|
Point3d ptCrvStart, ptCrvEnd ;
|
|
if ( ! pCrv->GetStartPoint( ptCrvStart) || ! pCrv->GetEndPoint( ptCrvEnd))
|
|
return false ;
|
|
|
|
// se non è la prima
|
|
if ( ! m_CrvSmplS.empty()) {
|
|
// se inserita alla fine
|
|
if ( bEndOrStart) {
|
|
// verifico sia in continuità con il finale attuale
|
|
Point3d ptEnd ;
|
|
GetEndPoint( ptEnd) ;
|
|
if ( ! AreSamePointEpsilon( ptCrvStart, ptEnd, 0.01 * EPS_SMALL)) {
|
|
// se in tolleranza, modifico l'inizio dell'entità
|
|
if ( SqDist( ptCrvStart, ptEnd) < ( dLinTol * dLinTol)) {
|
|
// lunghezza della curva originale
|
|
double dOldLen ; pCrv->GetLength( dOldLen) ;
|
|
// eseguo modifica
|
|
if ( ! pCrv->ModifyStart( ptEnd))
|
|
return false ;
|
|
// verifico che la lunghezza non sia variata troppo
|
|
double dNewLen ; pCrv->GetLength( dNewLen) ;
|
|
if ( abs( dNewLen - dOldLen) > 10 * dLinTol)
|
|
return false ;
|
|
}
|
|
else
|
|
return false ;
|
|
}
|
|
}
|
|
// altrimenti inserita all'inizio
|
|
else {
|
|
// verifico sia in continuità con l'iniziale attuale
|
|
Point3d ptStart ;
|
|
GetStartPoint( ptStart) ;
|
|
if ( ! AreSamePointEpsilon( ptCrvEnd, ptStart, 0.01 * EPS_SMALL)) {
|
|
// se in tolleranza, modifico la fine dell'entità
|
|
if ( SqDist( ptCrvEnd, ptStart) < ( dLinTol * dLinTol)) {
|
|
if ( ! pCrv->ModifyEnd( ptStart))
|
|
return false ;
|
|
}
|
|
else
|
|
return false ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// inserisco la curva nella lista
|
|
if ( bEndOrStart)
|
|
m_CrvSmplS.push_back( ::Release( pCrv)) ;
|
|
else
|
|
m_CrvSmplS.push_front( ::Release( pCrv)) ;
|
|
|
|
// aggiorno lo stato
|
|
m_nStatus = OK ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::Close( void)
|
|
{
|
|
// verifico curva valida
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
// determino la distanza tra gli estremi
|
|
Point3d ptStart, ptEnd ;
|
|
if ( ! GetStartPoint( ptStart) ||
|
|
! GetEndPoint( ptEnd))
|
|
return false ;
|
|
// se distanza inferiore al limite ridotto, non faccio alcunché
|
|
if ( AreSamePointEpsilon( ptStart, ptEnd, EPS_SMALL / 10))
|
|
return true ;
|
|
// se molto vicini li modifico
|
|
if ( AreSamePointEpsilon( ptStart, ptEnd, 10 * EPS_SMALL)) {
|
|
Point3d ptMid = Media( ptStart, ptEnd) ;
|
|
if ( ! ModifyStart( ptMid) ||
|
|
! ModifyEnd( ptMid))
|
|
return false ;
|
|
}
|
|
// altrimenti aggiungo la linea di chiusura
|
|
else {
|
|
PtrOwner<CurveLine> pLine( CreateBasicCurveLine()) ;
|
|
if ( ! pLine->Set( ptEnd, ptStart) ||
|
|
! AddSimpleCurve( Release( pLine)))
|
|
return false ;
|
|
}
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::FromSplit( const ICurve& cCrv, int nParts)
|
|
{
|
|
// verifico lo stato
|
|
if ( ! m_CrvSmplS.empty() || 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( 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_CrvSmplS.empty() || 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_CrvSmplS.empty() || 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 ( abs( 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, const Vector3d& vtN)
|
|
{
|
|
// verifico lo stato
|
|
if ( ! m_CrvSmplS.empty() || m_nStatus != TO_VERIFY)
|
|
return false ;
|
|
// almeno 3 lati e normale ben definita
|
|
if ( nSides < 3 || vtN.IsSmall())
|
|
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, vtN, 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, const Vector3d& vtN)
|
|
{
|
|
// verifico lo stato
|
|
if ( ! m_CrvSmplS.empty() || m_nStatus != TO_VERIFY)
|
|
return false ;
|
|
// almeno 3 lati e normale ben definita
|
|
if ( nSides < 3 || vtN.IsSmall())
|
|
return false ;
|
|
|
|
// calcolo la posizione del corner
|
|
double dHalfCentSideAngDeg = ANG_FULL / ( 2 * nSides) ;
|
|
double dCoeff = tan( dHalfCentSideAngDeg * DEGTORAD) ;
|
|
Vector3d vtDir = ptCen - ptMidSide ;
|
|
vtDir -= ( vtDir * vtN) * vtN / vtN.SqLen() ;
|
|
vtDir.Rotate( vtN, 0, 1) ;
|
|
Point3d ptCorner = ptMidSide + vtDir * dCoeff ;
|
|
|
|
// ora costruisco come poligono con centro e corner
|
|
return PolygonCenterCorner( nSides, ptCen, ptCorner, vtN) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::PolygonSide( int nSides, const Point3d& ptStart, const Point3d& ptEnd, const Vector3d& vtN)
|
|
{
|
|
// verifico lo stato
|
|
if ( ! m_CrvSmplS.empty() || m_nStatus != TO_VERIFY)
|
|
return false ;
|
|
// almeno 3 lati e normale ben definita
|
|
if ( nSides < 3 || vtN.IsSmall())
|
|
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 -= ( vtDir * vtN) * vtN / vtN.SqLen() ;
|
|
vtDir.Rotate( vtN, 0, 1) ;
|
|
Point3d ptCen = Media( ptStart, ptEnd, 0.5) + vtDir * dCoeff ;
|
|
|
|
// ora costruisco come poligono con centro e corner
|
|
return PolygonCenterCorner( nSides, ptCen, ptStart, vtN) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
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() ;
|
|
pCrv->GetExtrusion( m_VtExtr) ;
|
|
pCrv->GetThickness( m_dThick) ;
|
|
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 ;
|
|
m_nTempProp[0] = ccSrc.m_nTempProp[0] ;
|
|
m_nTempProp[1] = ccSrc.m_nTempProp[1] ;
|
|
for ( auto& pCrv : ccSrc.m_CrvSmplS) {
|
|
if ( ! AddCurve( *pCrv))
|
|
return false ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::RelocateFrom( CurveComposite& ccSrc)
|
|
{
|
|
if ( &ccSrc == this)
|
|
return true ;
|
|
Clear() ;
|
|
m_VtExtr = ccSrc.m_VtExtr ;
|
|
m_dThick = ccSrc.m_dThick ;
|
|
m_nTempProp[0] = ccSrc.m_nTempProp[0] ;
|
|
m_nTempProp[1] = ccSrc.m_nTempProp[1] ;
|
|
for ( ICurve* pCrv = ccSrc.RemoveFirstOrLastCurve( false) ;
|
|
pCrv != nullptr ;
|
|
pCrv = ccSrc.RemoveFirstOrLastCurve( false)) {
|
|
if ( ! AddSimpleCurve( pCrv))
|
|
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 = "CurveCompo" ;
|
|
return sTitle ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::Dump( string& sOut, bool bMM, const char* szNewLine) const
|
|
{
|
|
// dati generali di una curva
|
|
if ( ! CurveDump( *this, sOut, bMM, szNewLine))
|
|
return false ;
|
|
// prealloco la stringa
|
|
const int MAX_CRV = 1000 ;
|
|
sOut.reserve( 100 + min( int (m_CrvSmplS.size()), MAX_CRV) * 60) ;
|
|
// parametri : numero di curve
|
|
sOut += "CrvNbr=" + ToString( int( m_CrvSmplS.size())) + szNewLine ;
|
|
// ciclo sulle curve componenti
|
|
int i = 0 ;
|
|
const ICurve* pCrvSmpl = GetFirstCurve() ;
|
|
while ( pCrvSmpl != nullptr && i < MAX_CRV) {
|
|
// assegno ed emetto nome e tipo della curva semplice
|
|
sOut += "#" + ToString( i) + " " + pCrvSmpl->GetTitle() + szNewLine ;
|
|
// salvataggio della curva semplice
|
|
if ( ! pCrvSmpl->Dump( sOut, bMM, szNewLine))
|
|
return false ;
|
|
// passo alla successiva
|
|
++ i ;
|
|
pCrvSmpl = GetNextCurve() ;
|
|
}
|
|
if ( pCrvSmpl != nullptr)
|
|
sOut += string( ". . .") + szNewLine ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int
|
|
CurveComposite::GetNgeId( void) const
|
|
{
|
|
return GEOOBJ_GETNGEID( CurveComposite) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::Save( NgeWriter& ngeOut) const
|
|
{
|
|
// numero di curve
|
|
if ( ! ngeOut.WriteInt( int( m_CrvSmplS.size()), nullptr, true))
|
|
return false ;
|
|
// ciclo sulle curve componenti
|
|
int i = 0 ;
|
|
const ICurve* pCrvSmpl = GetFirstCurve() ;
|
|
while ( pCrvSmpl != nullptr) {
|
|
// recupero il gestore di lettura/scrittura della curva
|
|
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() ;
|
|
}
|
|
// se c'è estrusione, devo tenerne conto (curve componenti sempre con vtExtr e dThick nulli)
|
|
if ( ! m_VtExtr.IsSmall() && abs( m_dThick) > EPS_SMALL) {
|
|
Point3d ptMinExtr = b3Loc.GetMin() + m_VtExtr * m_dThick ;
|
|
Point3d ptMaxExtr = b3Loc.GetMax() + m_VtExtr * m_dThick ;
|
|
b3Loc.Add( ptMinExtr) ;
|
|
b3Loc.Add( ptMaxExtr) ;
|
|
}
|
|
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 (sempre senza estrusione)
|
|
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() ;
|
|
}
|
|
// se c'è estrusione, devo tenerne conto (curve componenti sempre con vtExtr e dThick nulli)
|
|
if ( ! m_VtExtr.IsSmall() && abs( m_dThick) > EPS_SMALL) {
|
|
Vector3d vtFrExtr = m_VtExtr ;
|
|
vtFrExtr.ToGlob( frRef) ;
|
|
Point3d ptMinExtr = b3Ref.GetMin() + vtFrExtr * m_dThick ;
|
|
Point3d ptMaxExtr = b3Ref.GetMax() + vtFrExtr * m_dThick ;
|
|
b3Ref.Add( ptMinExtr) ;
|
|
b3Ref.Add( ptMaxExtr) ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::Validate( void)
|
|
{
|
|
if ( m_nStatus == TO_VERIFY) {
|
|
Point3d ptPrevEnd ;
|
|
Point3d ptStart ;
|
|
// ciclo su tutte le curve
|
|
int nCount = 0 ;
|
|
PCSD_CONST_ITER 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) ;
|
|
}
|
|
|
|
return ( m_nStatus == OK) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::IsFlat( Plane3d& plPlane, bool bUseExtrusion, 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 = GetCurve( nCount) ;
|
|
pCrv != nullptr ;
|
|
pCrv = GetCurve( ++ 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_BEZIER :
|
|
{ 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.Set( ptCen, ( m_VtExtr.IsSmall() ? Z_AX : m_VtExtr)) ;
|
|
else
|
|
plPlane.Set( 0, ( m_VtExtr.IsSmall() ? V_NULL : m_VtExtr)) ;
|
|
break ;
|
|
case 1 : // linea
|
|
if ( m_VtExtr.IsSmall())
|
|
plPlane.Set( ptCen, FromUprightOrtho( vtDir)) ;
|
|
else {
|
|
Vector3d vtN = OrthoCompo( m_VtExtr, vtDir) ;
|
|
if ( ! vtN.Normalize())
|
|
vtN = FromUprightOrtho( vtDir) ;
|
|
plPlane.Set( ptCen, vtN) ;
|
|
bFlat = bFlat && ( ! bUseExtrusion || AreSameOrOppositeVectorApprox( m_VtExtr, vtN)) ;
|
|
}
|
|
break ;
|
|
default : // piana o 3d
|
|
if ( m_VtExtr.IsSmall())
|
|
plPlane.Set( ptCen, vtDir) ;
|
|
else {
|
|
plPlane.Set( ptCen, (( m_VtExtr * vtDir) > 0 ? vtDir : - vtDir)) ;
|
|
bFlat = bFlat && ( ! bUseExtrusion || AreSameOrOppositeVectorApprox( m_VtExtr, vtDir)) ;
|
|
}
|
|
break ;
|
|
}
|
|
|
|
return bFlat ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::IsClosed( void) const
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK || m_CrvSmplS.empty())
|
|
return false ;
|
|
|
|
// ricavo punti iniziale e finale e li confronto
|
|
Point3d ptStart, ptEnd ;
|
|
return ( m_CrvSmplS.front()->GetStartPoint( ptStart) &&
|
|
m_CrvSmplS.back()->GetEndPoint( ptEnd) &&
|
|
AreSamePointApprox( ptStart, ptEnd)) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::GetStartPoint( Point3d& ptStart) const
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK || m_CrvSmplS.empty())
|
|
return false ;
|
|
|
|
// assegno il punto
|
|
return m_CrvSmplS.front()->GetStartPoint( ptStart) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::GetEndPoint( Point3d& ptEnd) const
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK || m_CrvSmplS.empty())
|
|
return false ;
|
|
|
|
// assegno il punto
|
|
return m_CrvSmplS.back()->GetEndPoint( ptEnd) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
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::GetCentroid( Point3d& ptCen) const
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
// approssimo la curva con una polilinea
|
|
PolyLine PL ;
|
|
if ( ! ApproxWithLines( LIN_TOL_STD, ANG_TOL_STD_DEG, APL_SPECIAL_INT, PL))
|
|
return false ;
|
|
// calcolo il centro mediante PolygonPlane
|
|
Point3d ptP ;
|
|
PolygonPlane PolyPlane ;
|
|
for ( bool bFound = PL.GetFirstPoint( ptP) ; bFound ; bFound = PL.GetNextPoint( ptP))
|
|
PolyPlane.AddPoint( ptP) ;
|
|
if ( PolyPlane.GetCentroid( ptCen))
|
|
return true ;
|
|
// se non riuscito, uso il punto medio
|
|
return GetMidPoint( ptCen) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::GetStartDir( Vector3d& vtDir) const
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK || m_CrvSmplS.empty())
|
|
return false ;
|
|
|
|
// assegno il punto
|
|
return m_CrvSmplS.front()->GetStartDir( vtDir) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::GetEndDir( Vector3d& vtDir) const
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK || m_CrvSmplS.empty())
|
|
return false ;
|
|
|
|
// assegno il punto
|
|
return m_CrvSmplS.back()->GetEndDir( vtDir) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
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, dMid, 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.0 ;
|
|
dEnd = double( m_CrvSmplS.size()) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::GetIndSCurveAndLocPar( double dU, Side nS, int& nSCrv, double& dLocU) const
|
|
{
|
|
// deve esserci almeno una curva semplice
|
|
if ( m_CrvSmplS.empty())
|
|
return false ;
|
|
|
|
// valore massimo del parametro
|
|
double dMaxU = double( m_CrvSmplS.size()) ;
|
|
|
|
// verifico che il parametro non sia troppo fuori dai limiti
|
|
if ( dU < - 100 * EPS_PARAM || dU > dMaxU + 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 ( IsClosed() && nS == ICurve::FROM_MINUS)
|
|
dU = dMaxU ;
|
|
// altrimenti posso valutare solo dopo l'inizio
|
|
else {
|
|
dU = 0 ;
|
|
nS = ICurve::FROM_PLUS ;
|
|
}
|
|
}
|
|
else if ( dU > ( dMaxU - EPS_PARAM)) {
|
|
// se chiusa e voglio valutare dopo la fine devo valutare dopo l'inizio
|
|
if ( IsClosed() && nS == ICurve::FROM_PLUS)
|
|
dU = 0 ;
|
|
// altrimenti posso valutare solo prima della fine
|
|
else {
|
|
dU = dMaxU ;
|
|
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 ( abs( dLocU) < 5 * EPS_PARAM && nSCrv > 0 && nS == ICurve::FROM_MINUS) {
|
|
-- nSCrv ;
|
|
dLocU = 1 ;
|
|
}
|
|
else if ( abs( dLocU) > 1 - 5 * EPS_PARAM && nSCrv < dMaxU - 1 && nS == ICurve::FROM_PLUS) {
|
|
++ nSCrv ;
|
|
dLocU = 0 ;
|
|
}
|
|
|
|
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::GetApproxLength( double& dLen) const
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// ciclo di calcolo
|
|
dLen = 0 ;
|
|
for ( auto Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) {
|
|
double dLenCrvSmpl ;
|
|
if ( (*Iter)->GetType() == CRV_BEZIER) {
|
|
if ( GetBasicCurveBezier(*Iter)->GetApproxLength( dLenCrvSmpl))
|
|
dLen += dLenCrvSmpl ;
|
|
else
|
|
return false ;
|
|
}
|
|
else {
|
|
if ( (*Iter)->GetLength( dLenCrvSmpl))
|
|
dLen += dLenCrvSmpl ;
|
|
else
|
|
return false ;
|
|
}
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::GetLength( double& dLen) const
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// ciclo di calcolo
|
|
dLen = 0 ;
|
|
PCSD_CONST_ITER 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 > ( double( m_CrvSmplS.size()) + EPS_PARAM))
|
|
return false ;
|
|
|
|
// ciclo di calcolo
|
|
dLen = 0 ;
|
|
double dUToGo = dU ;
|
|
PCSD_CONST_ITER 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 ;
|
|
PCSD_CONST_ITER 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 ;
|
|
return true ;
|
|
}
|
|
// altrimenti
|
|
else {
|
|
// lunghezza rimanente
|
|
dLenToGo -= dCrvLen ;
|
|
// lunghezza parametrica progressiva
|
|
double dParStart, dParEnd ;
|
|
(*Iter)->GetDomain( dParStart, dParEnd) ;
|
|
dU += ( dParEnd - dParStart) ;
|
|
}
|
|
}
|
|
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
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)
|
|
return ( DistPointCrvComposite( ptP, *this).IsEpsilon( dTol)) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::GetParamAtPoint( const Point3d& ptP, double& dPar, double dTol) const
|
|
{
|
|
DistPointCrvComposite DPC( ptP, *this) ;
|
|
if ( ! DPC.IsEpsilon( dTol))
|
|
return false ;
|
|
int nFlag ;
|
|
return DPC.GetParamAtMinDistPoint( 0, dPar, nFlag) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::GetLengthAtPoint( const Point3d& ptP, double& dLen, double dTol) const
|
|
{
|
|
double dU ;
|
|
if ( ! GetParamAtPoint( ptP, dU, dTol))
|
|
return false ;
|
|
return GetLengthAtParam( dU, dLen) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::ApproxWithLines( double dLinTol, double dAngTolDeg, int nType, PolyLine& PL) const
|
|
{
|
|
// pulisco la polilinea
|
|
PL.Clear() ;
|
|
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// limiti minimi su tolleranza e deviazione angolare
|
|
dLinTol = max( dLinTol, LIN_TOL_MIN) ;
|
|
dAngTolDeg = max( dAngTolDeg, ANG_TOL_MIN_DEG) ;
|
|
|
|
// se speciale, approssimo ogni singola entità e conservo le estremità interne (joint)
|
|
if ( nType == APL_SPECIAL || nType == APL_SPECIAL_INT) {
|
|
// eseguo approssimazione
|
|
double dStartPar = 0 ;
|
|
for ( auto& pCrv : m_CrvSmplS) {
|
|
// assegno estrusione e spessore della curva composita
|
|
pCrv->SetExtrusion( m_VtExtr) ;
|
|
pCrv->SetThickness( m_dThick) ;
|
|
// recupero approssimazione per curva semplice
|
|
PolyLine PLSmpl ;
|
|
if ( ! pCrv->ApproxWithLines( dLinTol, dAngTolDeg, nType, PLSmpl))
|
|
return false ;
|
|
// se richiesto almeno un punto interno con curve non rettilinee e ci sono solo gli estremi
|
|
if ( nType == APL_SPECIAL_INT && pCrv->GetType() != CRV_LINE && PLSmpl.GetPointNbr() == 2) {
|
|
// aggiungo il punto interno
|
|
Point3d ptMid ;
|
|
if ( ! pCrv->GetMidPoint( ptMid))
|
|
return false ;
|
|
double dU ;
|
|
PLSmpl.GetLastU( dU) ;
|
|
dU /= 2 ;
|
|
PNTULIST& List = PLSmpl.GetUPointList() ;
|
|
List.insert( ++ List.begin(), { ptMid, dU}) ;
|
|
}
|
|
// ripristino estrusione e spessore della curva semplice (annullandoli)
|
|
pCrv->SetExtrusion( V_NULL) ;
|
|
pCrv->SetThickness( 0) ;
|
|
// 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 ;
|
|
}
|
|
|
|
// se lineare con lato obbligato...
|
|
if ( nType == APL_LEFT || nType == APL_LEFT_CONVEX ||
|
|
nType == APL_RIGHT || nType == APL_RIGHT_CONVEX) {
|
|
// prima approssimazione lineare alla tolleranza minima del programma
|
|
if ( ! ApproxWithLines( EPS_SMALL, dAngTolDeg, APL_SPECIAL, PL))
|
|
return false ;
|
|
// eliminazione dei punti in tolleranza andando solo dalla parte ammessa
|
|
Vector3d vtExtr = ( m_VtExtr.IsSmall() ? Z_AX : m_VtExtr) ;
|
|
if ( ! PL.ApproxOnSide( vtExtr, ( nType == APL_LEFT || nType == APL_LEFT_CONVEX), dLinTol))
|
|
return false ;
|
|
// se necessario, sistemo per convessità dalla parte ammessa
|
|
if ( nType == APL_RIGHT_CONVEX || nType == APL_LEFT_CONVEX) {
|
|
if ( ! PL.MakeConvex( vtExtr, ( nType == APL_LEFT_CONVEX)))
|
|
return false ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
// altrimenti standard
|
|
// prima approssimazione lineare a 10 * Epsilon di ogni singola entità
|
|
if ( ! ApproxWithLines( 10 * EPS_SMALL, dAngTolDeg, APL_SPECIAL, PL))
|
|
return false ;
|
|
// eliminazione dei punti in tolleranza
|
|
return PL.RemoveAlignedPoints( dLinTol) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::ApproxWithArcs( double dLinTol, double dAngTolDeg, PolyArc& PA) const
|
|
{
|
|
// pulisco il poliarco
|
|
PA.Clear() ;
|
|
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// determino riferimento naturale della curva in base all'estrusione o al piano medio se questa è nulla
|
|
Frame3d frNat ;
|
|
if ( ! m_VtExtr.IsSmall()) {
|
|
frNat.Set( ORIG, m_VtExtr) ;
|
|
}
|
|
else {
|
|
Plane3d plPlane ;
|
|
IsFlat( plPlane, false) ;
|
|
if ( plPlane.IsValid()) {
|
|
if ( plPlane.GetVersN().z < -EPS_ZERO)
|
|
plPlane.Invert() ;
|
|
frNat.Set( ORIG, plPlane.GetVersN()) ;
|
|
}
|
|
}
|
|
|
|
// eseguo approssimazione
|
|
double dStartPar = 0 ;
|
|
for ( const auto& pCrv : m_CrvSmplS) {
|
|
// ne faccio una copia
|
|
PtrOwner<ICurve> pCrvL( pCrv->Clone()) ;
|
|
if ( IsNull( pCrvL))
|
|
return false ;
|
|
// assegno estrusione e spessore della curva composita
|
|
pCrvL->SetExtrusion( m_VtExtr) ;
|
|
pCrvL->SetThickness( m_dThick) ;
|
|
// la porto nel riferimento naturale
|
|
pCrvL->ToLoc( frNat) ;
|
|
// recupero approssimazione per curva semplice
|
|
PolyArc PASmpl ;
|
|
if ( ! pCrvL->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 ;
|
|
}
|
|
|
|
// riporto l'approssimazione nel riferimento della composita
|
|
PA.ToGlob( frNat) ;
|
|
|
|
// assegno estrusione della curva composita
|
|
PA.SetExtrusion( m_VtExtr) ;
|
|
|
|
// eliminazione dei punti in tolleranza (opportunamente diminuita)
|
|
return PA.RemoveAlignedPoints( 0.5 * dLinTol) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::ApproxWithArcsEx( double dLinTol, double dAngTolDeg, double dLinFea, PolyArc& PA) const
|
|
{
|
|
// pulisco il poliarco
|
|
PA.Clear() ;
|
|
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// preparazione per approssimazione di multilinee
|
|
bool bMultiLine = false ;
|
|
double dMlStartPar = 0 ;
|
|
CurveByApprox crvByApprox ;
|
|
|
|
// determino riferimento naturale della curva in base all'estrusione o al piano medio se questa è nulla
|
|
Frame3d frNat ;
|
|
if ( ! m_VtExtr.IsSmall()) {
|
|
frNat.Set( ORIG, m_VtExtr) ;
|
|
}
|
|
else {
|
|
Plane3d plPlane ;
|
|
IsFlat( plPlane, false) ;
|
|
if ( plPlane.IsValid()) {
|
|
if ( plPlane.GetVersN().z < -EPS_ZERO)
|
|
plPlane.Invert() ;
|
|
frNat.Set( ORIG, plPlane.GetVersN()) ;
|
|
}
|
|
}
|
|
|
|
// eseguo approssimazione
|
|
double dStartPar = 0 ;
|
|
for ( const auto& pCrv : m_CrvSmplS) {
|
|
// ne faccio una copia
|
|
PtrOwner<ICurve> pCrvL( pCrv->Clone()) ;
|
|
if ( IsNull( pCrvL))
|
|
return false ;
|
|
// assegno estrusione e spessore della curva composita
|
|
pCrvL->SetExtrusion( m_VtExtr) ;
|
|
pCrvL->SetThickness( m_dThick) ;
|
|
// la porto nel riferimento naturale
|
|
pCrvL->ToLoc( frNat) ;
|
|
// se segmento di linea non feature
|
|
double dLen ;
|
|
if ( pCrvL->GetType() == CRV_LINE && pCrvL->GetLength( dLen) && dLen < dLinFea) {
|
|
CurveLine* pLine = GetBasicCurveLine( pCrvL) ;
|
|
// se inizio di approx multilinea
|
|
if ( ! bMultiLine) {
|
|
bMultiLine = true ;
|
|
dMlStartPar = dStartPar ;
|
|
crvByApprox.Reset() ;
|
|
crvByApprox.AddPoint( pLine->GetStart()) ;
|
|
}
|
|
// aggiungo punti a distanza opportuna
|
|
const double STEP = 5 ;
|
|
int nStep = int( dLen / STEP) ;
|
|
for ( int i = 1 ; i < nStep ; ++ i) {
|
|
double dCoeff = i / double( nStep) ;
|
|
crvByApprox.AddPoint( Media( pLine->GetStart(), pLine->GetEnd(), dCoeff)) ;
|
|
}
|
|
// aggiungo il punto finale
|
|
crvByApprox.AddPoint( pLine->GetEnd()) ;
|
|
}
|
|
// altrimenti
|
|
else {
|
|
// se in corso approx multilinee
|
|
if ( bMultiLine) {
|
|
bMultiLine = false ;
|
|
PolyArc PASmpl ;
|
|
if ( ! crvByApprox.GetArcs( dLinTol, dAngTolDeg, dLinFea, PASmpl))
|
|
return false ;
|
|
// la accodo opportunamente a quella della curva composita
|
|
if ( ! PA.Join( PASmpl, dMlStartPar))
|
|
return false ;
|
|
}
|
|
// recupero approssimazione per curva semplice
|
|
PolyArc PASmpl ;
|
|
if ( ! pCrvL->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 ;
|
|
}
|
|
// se approssimazione multiline ancora aperta
|
|
if ( bMultiLine) {
|
|
bMultiLine = false ;
|
|
PolyArc PASmpl ;
|
|
if ( ! crvByApprox.GetArcs( dLinTol, dAngTolDeg, dLinFea, PASmpl))
|
|
return false ;
|
|
// la accodo opportunamente a quella della curva composita
|
|
if ( ! PA.Join( PASmpl, dMlStartPar))
|
|
return false ;
|
|
}
|
|
|
|
// riporto l'approssimazione nel riferimento della composita
|
|
PA.ToGlob( frNat) ;
|
|
|
|
// assegno estrusione della curva composita
|
|
PA.SetExtrusion( m_VtExtr) ;
|
|
|
|
// eliminazione dei punti in tolleranza (opportunamente diminuita)
|
|
return PA.RemoveAlignedPoints( 0.5 * dLinTol) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
ICurve*
|
|
CurveComposite::CopyParamRange( double dUStart, double dUEnd) const
|
|
{
|
|
// valore massimo del parametro
|
|
double dMaxU = double( m_CrvSmplS.size()) ;
|
|
// i parametri start ed end devono essere compresi nel dominio parametrico della curva
|
|
if ( dUStart < - EPS_PARAM || dUStart > dMaxU + EPS_PARAM ||
|
|
dUEnd < - EPS_PARAM || dUEnd > dMaxU + EPS_PARAM)
|
|
return nullptr ;
|
|
// se i parametri coincidono, non resta alcunchè
|
|
if ( abs( dUEnd - dUStart) < 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 ( ! IsClosed())
|
|
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 += dMaxU ;
|
|
}
|
|
// 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( nothrow) 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_CrvSmplS.size() ;
|
|
// 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
|
|
for ( auto Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter)
|
|
(*Iter)->Invert() ;
|
|
|
|
// inverto l'ordine della lista
|
|
reverse( m_CrvSmplS.begin(), m_CrvSmplS.end()) ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::SimpleOffset( double dDist, int nType)
|
|
{
|
|
// se distanza di offset nulla, non devo fare alcunché
|
|
if ( abs( dDist) < EPS_SMALL)
|
|
return true ;
|
|
|
|
// --- l'offset va effettuato in un piano perpendicolare al vettore estrusione ---
|
|
|
|
// verifico il vettore estrusione
|
|
bool bNeedRef = ( ! m_VtExtr.IsSmall() && ! m_VtExtr.IsZplus()) ;
|
|
|
|
// se necessario cambio il riferimento
|
|
Frame3d frExtr ;
|
|
if ( bNeedRef) {
|
|
// calcolo il riferimento OCS con VtExtr come asse Z
|
|
if ( ! frExtr.Set( ORIG, m_VtExtr))
|
|
return false ;
|
|
// esprimo la curva in questo riferimento
|
|
ToLoc( frExtr) ;
|
|
}
|
|
|
|
// eseguo l'offset nel piano XY
|
|
bool bOk = SimpleOffsetXY( dDist, nType) ;
|
|
|
|
// riporto la curva nel riferimento originale
|
|
if ( bNeedRef)
|
|
ToGlob( frExtr) ;
|
|
|
|
return bOk ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
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 ;
|
|
|
|
// 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 ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::AddPoint( const Point3d& ptStart)
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != TO_VERIFY)
|
|
return false ;
|
|
// assegno il punto
|
|
m_ptStart = ptStart ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::AddLineTg( double dLen, bool bEndOrStart)
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
// costruisco la linea
|
|
PtrOwner<CurveLine> pLine( CreateBasicCurveLine()) ;
|
|
if ( IsNull( pLine))
|
|
return false ;
|
|
// se da aggiungere alla fine
|
|
if ( bEndOrStart) {
|
|
Point3d ptEnd ;
|
|
Vector3d vtEnd ;
|
|
if ( ! GetEndPoint( ptEnd) || ! GetEndDir( vtEnd))
|
|
return false ;
|
|
Point3d ptNew = ptEnd + vtEnd * dLen ;
|
|
if ( ! pLine->Set( ptEnd, ptNew))
|
|
return false ;
|
|
}
|
|
// altrimenti da aggiungere all'inizio
|
|
else {
|
|
Point3d ptStart ;
|
|
Vector3d vtStart ;
|
|
if ( ! GetStartPoint( ptStart) || ! GetStartDir( vtStart))
|
|
return false ;
|
|
Point3d ptNew = ptStart - vtStart * dLen ;
|
|
if ( ! pLine->Set( ptNew, ptStart))
|
|
return false ;
|
|
}
|
|
return AddCurve( Release( pLine), bEndOrStart) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::AddLine( const Point3d& ptNew, bool bEndOrStart)
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK && m_nStatus != TO_VERIFY)
|
|
return false ;
|
|
// costruisco la linea
|
|
PtrOwner<CurveLine> pLine( CreateBasicCurveLine()) ;
|
|
if ( IsNull( pLine))
|
|
return false ;
|
|
// se da aggiungere alla fine
|
|
if ( bEndOrStart) {
|
|
Point3d ptEnd = m_ptStart ;
|
|
if ( m_nStatus == OK)
|
|
GetEndPoint( ptEnd) ;
|
|
if ( ! pLine->Set( ptEnd, ptNew))
|
|
return false ;
|
|
}
|
|
// altrimenti da aggiungere all'inizio
|
|
else {
|
|
Point3d ptStart = m_ptStart ;
|
|
if ( m_nStatus == OK)
|
|
GetStartPoint( ptStart) ;
|
|
if ( ! pLine->Set( ptNew, ptStart))
|
|
return false ;
|
|
}
|
|
return AddCurve( Release( pLine), bEndOrStart) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::AddArcTg( const Point3d& ptNew, bool bEndOrStart)
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
// recupero il versore normale al piano ( estrusione oppure se nulla asse Z locale)
|
|
Vector3d vtN = ( m_VtExtr.IsSmall() ? Z_AX : m_VtExtr) ;
|
|
// costruisco l'arco (in casi articolari può essere una linea)
|
|
PtrOwner<ICurve> pCrv ;
|
|
// se da aggiungere alla fine
|
|
if ( bEndOrStart) {
|
|
Point3d ptEnd ;
|
|
GetEndPoint( ptEnd) ;
|
|
Vector3d vtDir ;
|
|
GetEndDir( vtDir) ;
|
|
pCrv.Set( GetArc2PVN( ptEnd, ptNew, vtDir, vtN)) ;
|
|
if ( IsNull( pCrv))
|
|
return false ;
|
|
}
|
|
// altrimenti da aggiungere all'inizio
|
|
else {
|
|
Point3d ptStart ;
|
|
GetStartPoint( ptStart) ;
|
|
Vector3d vtDir ;
|
|
GetStartDir( vtDir) ;
|
|
pCrv.Set( GetArc2PVN( ptStart, ptNew, -vtDir, vtN)) ;
|
|
if ( IsNull( pCrv))
|
|
return false ;
|
|
pCrv->Invert() ;
|
|
}
|
|
return AddCurve( Release( pCrv), bEndOrStart) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::AddArc2P( const Point3d& ptOther, const Point3d& ptNew, bool bEndOrStart)
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK && m_nStatus != TO_VERIFY)
|
|
return false ;
|
|
// costruisco l'arco (in casi articolari può essere una linea)
|
|
PtrOwner<ICurve> pCrv ;
|
|
// se da aggiungere alla fine
|
|
if ( bEndOrStart) {
|
|
Point3d ptEnd = m_ptStart ;
|
|
if ( m_nStatus == OK)
|
|
GetEndPoint( ptEnd) ;
|
|
pCrv.Set( GetArc3P( ptEnd, ptOther, ptNew, false)) ;
|
|
if ( IsNull( pCrv))
|
|
return false ;
|
|
}
|
|
// altrimenti da aggiungere all'inizio
|
|
else {
|
|
Point3d ptStart = m_ptStart ;
|
|
if ( m_nStatus == OK)
|
|
GetStartPoint( ptStart) ;
|
|
pCrv.Set( GetArc3P( ptNew, ptOther, ptStart, false)) ;
|
|
if ( IsNull( pCrv))
|
|
return false ;
|
|
}
|
|
return AddCurve( Release( pCrv), bEndOrStart) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::AddJoint( double dU)
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
// recupero la curva in cui cade il parametro
|
|
int nSCrv ;
|
|
double dLocU ;
|
|
if ( ! GetIndSCurveAndLocPar( dU, FROM_MINUS, nSCrv, dLocU))
|
|
return false ;
|
|
ICurve* pCurve = m_CrvSmplS[ nSCrv] ;
|
|
// creo due copie della curva
|
|
PtrOwner<ICurve> pCrv1( pCurve->Clone()) ;
|
|
PtrOwner<ICurve> pCrv2( pCurve->Clone()) ;
|
|
if ( IsNull( pCrv1) || IsNull( pCrv2))
|
|
return false ;
|
|
// della prima curva tengo la parte dall'inizio al parametro, della seconda la rimanente
|
|
// ( se non riesco a trimmare, la nuova giunzione coincide con una già esistente, esco con successo)
|
|
if ( ! pCrv1->TrimEndAtParam( dLocU) || ! pCrv2->TrimStartAtParam( dLocU))
|
|
return true ;
|
|
// elimino la curva originale
|
|
delete pCurve ;
|
|
// devo ora inserire le due curve al posto di quella originale
|
|
m_CrvSmplS.insert( m_CrvSmplS.begin() + nSCrv, Release(pCrv1)) ;
|
|
m_CrvSmplS[ nSCrv+1] = Release( pCrv2) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::ModifyJoint( int nU, const Point3d& ptNewJoint)
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
// numero di curve
|
|
int nCrvCount = GetCurveCount() ;
|
|
// verifico l'indice della giunzione
|
|
if ( nU < 0 || nU > nCrvCount)
|
|
return false ;
|
|
// recupero l'indice e il puntatore alla curva precedente (se esiste)
|
|
int nPrevCrv = -1 ;
|
|
if ( nU > 0)
|
|
nPrevCrv = nU - 1 ;
|
|
else if ( IsClosed())
|
|
nPrevCrv = nCrvCount - 1 ;
|
|
ICurve* pPrevCrv = ( nPrevCrv != -1 ? m_CrvSmplS[ nPrevCrv] : nullptr) ;
|
|
// recupero il puntatore alla curva successiva (se esiste)
|
|
int nNextCrv = -1 ;
|
|
if ( nU < nCrvCount)
|
|
nNextCrv = nU ;
|
|
else if ( IsClosed())
|
|
nNextCrv = 0 ;
|
|
ICurve* pNextCrv = ( nNextCrv != -1 ? m_CrvSmplS[ nNextCrv] : nullptr) ;
|
|
// recupero punto iniziale dell'entità precedente (se esiste)
|
|
Point3d ptStart ;
|
|
if ( pPrevCrv != nullptr && ! pPrevCrv->GetStartPoint( ptStart))
|
|
return false ;
|
|
// recupero punto finale dell'entità successiva (se esiste)
|
|
Point3d ptEnd ;
|
|
if ( pNextCrv != nullptr && ! pNextCrv->GetEndPoint( ptEnd))
|
|
return false ;
|
|
// modifico il punto finale dell'eventuale entità precedente
|
|
if ( pPrevCrv != nullptr && ! pPrevCrv->ModifyEnd( ptNewJoint)) {
|
|
// se entità precedente si annulla, la elimino
|
|
if ( AreSamePointApprox( ptStart, ptNewJoint)) {
|
|
delete pPrevCrv ;
|
|
m_CrvSmplS.erase( m_CrvSmplS.begin() + nPrevCrv) ;
|
|
}
|
|
// altrimenti diventa un segmento di retta
|
|
else {
|
|
// creo la linea
|
|
PtrOwner<CurveLine> pLine( CreateBasicCurveLine()) ;
|
|
if ( IsNull( pLine) || ! pLine->Set( ptStart, ptNewJoint))
|
|
return false ;
|
|
// sostituisco la linea alla curva precedente
|
|
m_CrvSmplS[nPrevCrv] = Release( pLine) ;
|
|
// elimino la curva originale
|
|
delete( pPrevCrv) ;
|
|
}
|
|
}
|
|
// modifico il punto iniziale dell'eventuale entità successiva
|
|
if ( pNextCrv != nullptr && ! pNextCrv->ModifyStart( ptNewJoint)) {
|
|
// se entità successiva si annulla, la elimino
|
|
if ( AreSamePointApprox( ptNewJoint, ptEnd)) {
|
|
delete pNextCrv ;
|
|
m_CrvSmplS.erase( m_CrvSmplS.begin() + nNextCrv) ;
|
|
}
|
|
// altrimenti diventa un segmento di retta
|
|
else {
|
|
// creo la linea
|
|
PtrOwner<CurveLine> pLine( CreateBasicCurveLine()) ;
|
|
if ( IsNull( pLine) || ! pLine->Set( ptNewJoint, ptEnd))
|
|
return false ;
|
|
// sostituisco la linea alla curva precedente
|
|
m_CrvSmplS[nNextCrv] = Release( pLine) ;
|
|
// elimino la curva originale
|
|
delete( pNextCrv) ;
|
|
}
|
|
}
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::RemoveJoint( int nU)
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
// numero di curve
|
|
int nCrvCount = GetCurveCount() ;
|
|
// verifico l'indice della giunzione
|
|
if ( nU < 0 || nU > nCrvCount)
|
|
return false ;
|
|
// devono esserci almeno 2 curve se composita aperta e almeno 3 se chiusa
|
|
if ( nCrvCount < 2 || ( nCrvCount < 3 && IsClosed()))
|
|
return false ;
|
|
// recupero l'indice della curva precedente (se esiste)
|
|
int nPrevCrv = - 1 ;
|
|
if ( nU > 0)
|
|
nPrevCrv = nU - 1 ;
|
|
else if ( IsClosed())
|
|
nPrevCrv = nCrvCount - 1 ;
|
|
// recupero l'indice della curva successiva (se esiste)
|
|
int nNextCrv = - 1 ;
|
|
if ( nU < nCrvCount)
|
|
nNextCrv = nU ;
|
|
else if ( IsClosed())
|
|
nNextCrv = 0 ;
|
|
// se non esiste curva precedente, va eliminata la prima curva
|
|
if ( nPrevCrv == -1) {
|
|
// recupero la curva la cancello e la rimuovo
|
|
ICurve* pCrv = *(m_CrvSmplS.begin()) ;
|
|
delete pCrv ;
|
|
m_CrvSmplS.pop_front() ;
|
|
}
|
|
// se non esiste curva successiva, va eliminata l'ultima curva
|
|
else if ( nNextCrv == -1) {
|
|
// recupero la curva la cancello e la rimuovo
|
|
ICurve* pCrv = *(m_CrvSmplS.rbegin()) ;
|
|
delete pCrv ;
|
|
m_CrvSmplS.pop_back() ;
|
|
}
|
|
// altrimenti devo modificare la precedente ed eliminare la successiva
|
|
else {
|
|
// recupero punto finale della curva successiva
|
|
Point3d ptEnd ;
|
|
m_CrvSmplS[nNextCrv]->GetEndPoint( ptEnd) ;
|
|
// modifico punto finale della curva precedente
|
|
if ( ! m_CrvSmplS[nPrevCrv]->ModifyEnd( ptEnd))
|
|
return false ;
|
|
// recupero la curva successiva, la cancello e la rimuovo
|
|
ICurve* pCrv = *(m_CrvSmplS.begin() + nNextCrv) ;
|
|
delete pCrv ;
|
|
m_CrvSmplS.erase( m_CrvSmplS.begin() + nNextCrv) ;
|
|
}
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::MoveCurve( int nCrv, const Vector3d& vtMove)
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
// numero di curve
|
|
int nCrvCount = GetCurveCount() ;
|
|
// la curva deve esistere
|
|
if ( nCrv < 0 || nCrv > nCrvCount - 1)
|
|
return false ;
|
|
// recupero la curva corrente
|
|
ICurve* pCrv = *(m_CrvSmplS.begin() + nCrv) ;
|
|
// recupero l'indice e il puntatore alla curva precedente (se esiste)
|
|
int nPrevCrv = -1 ;
|
|
if ( nCrv > 0)
|
|
nPrevCrv = nCrv - 1 ;
|
|
else if ( IsClosed())
|
|
nPrevCrv = nCrvCount - 1 ;
|
|
ICurve* pPrevCrv = ( nPrevCrv != -1 ? m_CrvSmplS[ nPrevCrv] : nullptr) ;
|
|
// recupero il puntatore alla curva successiva (se esiste)
|
|
int nNextCrv = -1 ;
|
|
if ( nCrv + 1 < nCrvCount)
|
|
nNextCrv = nCrv + 1 ;
|
|
else if ( IsClosed())
|
|
nNextCrv = 0 ;
|
|
ICurve* pNextCrv = ( nNextCrv != -1 ? m_CrvSmplS[ nNextCrv] : nullptr) ;
|
|
// recupero punti iniziale e finale dell'entità precedente (se esiste)
|
|
Point3d ptPrevStart, ptPrevEnd ;
|
|
if ( pPrevCrv != nullptr && ( ! pPrevCrv->GetStartPoint( ptPrevStart) || ! pPrevCrv->GetEndPoint( ptPrevEnd)))
|
|
return false ;
|
|
// recupero punti iniziale e finale dell'entità successiva (se esiste)
|
|
Point3d ptNextStart, ptNextEnd ;
|
|
if ( pNextCrv != nullptr && ( ! pNextCrv->GetStartPoint( ptNextStart) || ! pNextCrv->GetEndPoint( ptNextEnd)))
|
|
return false ;
|
|
// modifico il punto finale dell'eventuale entità precedente
|
|
if ( pPrevCrv != nullptr && ! pPrevCrv->ModifyEnd( ptPrevEnd + vtMove)) {
|
|
// se entità precedente si annulla, la elimino
|
|
if ( AreSamePointApprox( ptPrevStart, ptPrevEnd + vtMove)) {
|
|
delete pPrevCrv ;
|
|
m_CrvSmplS.erase( m_CrvSmplS.begin() + nPrevCrv) ;
|
|
if ( nPrevCrv < nNextCrv)
|
|
-- nNextCrv ;
|
|
}
|
|
// altrimenti diventa un segmento di retta
|
|
else {
|
|
// creo la linea
|
|
PtrOwner<CurveLine> pLine( CreateBasicCurveLine()) ;
|
|
if ( IsNull( pLine) || ! pLine->Set( ptPrevStart, ptPrevEnd + vtMove))
|
|
return false ;
|
|
// sostituisco la linea alla curva precedente
|
|
m_CrvSmplS[nPrevCrv] = Release( pLine) ;
|
|
// elimino la curva originale
|
|
delete( pPrevCrv) ;
|
|
}
|
|
}
|
|
// modifico il punto iniziale dell'eventuale entità successiva
|
|
if ( pNextCrv != nullptr && ! pNextCrv->ModifyStart( ptNextStart + vtMove)) {
|
|
// se entità successiva si annulla, la elimino
|
|
if ( AreSamePointApprox( ptNextStart + vtMove, ptNextEnd)) {
|
|
delete pNextCrv ;
|
|
m_CrvSmplS.erase( m_CrvSmplS.begin() + nNextCrv) ;
|
|
}
|
|
// altrimenti diventa un segmento di retta
|
|
else {
|
|
// creo la linea
|
|
PtrOwner<CurveLine> pLine( CreateBasicCurveLine()) ;
|
|
if ( IsNull( pLine) || ! pLine->Set( ptNextStart + vtMove, ptNextEnd))
|
|
return false ;
|
|
// sostituisco la linea alla curva precedente
|
|
m_CrvSmplS[nNextCrv] = Release( pLine) ;
|
|
// elimino la curva originale
|
|
delete( pNextCrv) ;
|
|
}
|
|
}
|
|
// traslo la curva corrente
|
|
pCrv->Translate( vtMove) ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::ModifyCurveToArc( int nCrv, const Point3d& ptMid)
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
// numero di curve
|
|
int nCrvCount = GetCurveCount() ;
|
|
// la curva deve esistere
|
|
if ( nCrv < 0 || nCrv > nCrvCount - 1)
|
|
return false ;
|
|
// recupero la curva corrente
|
|
ICurve* pCrv = m_CrvSmplS[nCrv] ;
|
|
// recupero gli estremi
|
|
Point3d ptStart, ptEnd ;
|
|
if ( ! pCrv->GetStartPoint( ptStart) || ! pCrv->GetEndPoint( ptEnd))
|
|
return false ;
|
|
// creo l'arco
|
|
PtrOwner<CurveArc> pArc( CreateBasicCurveArc()) ;
|
|
if ( IsNull( pArc) || ! pArc->Set3P( ptStart, ptMid, ptEnd))
|
|
return false ;
|
|
// sostituisco l'arco alla curva precedente
|
|
m_CrvSmplS[nCrv] = Release( pArc) ;
|
|
// elimino la curva originale
|
|
delete( pCrv) ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::ModifyCurveToLine( int nCrv)
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
// numero di curve
|
|
int nCrvCount = GetCurveCount() ;
|
|
// la curva deve esistere
|
|
if ( nCrv < 0 || nCrv > nCrvCount - 1)
|
|
return false ;
|
|
// recupero la curva corrente
|
|
ICurve* pCrv = m_CrvSmplS[nCrv] ;
|
|
// se già linea non devo fare alcunchè
|
|
if ( pCrv->GetType() == CRV_LINE)
|
|
return true ;
|
|
// recupero gli estremi
|
|
Point3d ptStart, ptEnd ;
|
|
if ( ! pCrv->GetStartPoint( ptStart) || ! pCrv->GetEndPoint( ptEnd))
|
|
return false ;
|
|
// creo la linea
|
|
PtrOwner<CurveLine> pLine( CreateBasicCurveLine()) ;
|
|
if ( IsNull( pLine) || ! pLine->Set( ptStart, ptEnd))
|
|
return false ;
|
|
// sostituisco la linea alla curva precedente
|
|
m_CrvSmplS[nCrv] = Release( pLine) ;
|
|
// elimino la curva originale
|
|
delete( pCrv) ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::TrimStartAtParam( double dUTrim)
|
|
{
|
|
// verifico validità parametro
|
|
double dMaxU = double( m_CrvSmplS.size()) ;
|
|
if ( dUTrim < -EPS_PARAM || dUTrim > dMaxU - EPS_PARAM)
|
|
return false ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
// ciclo sulle diverse curve dall'inizio
|
|
double dUToTrim = dUTrim ;
|
|
for ( auto 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.erase( Iter) ;
|
|
}
|
|
// se lunghezza ancora da tagliare nulla (entro la tolleranza)
|
|
else if ( dUToTrim > - EPS_PARAM ||
|
|
! (*Iter)->TrimStartAtParam( 1 + dUToTrim)) {
|
|
delete (*Iter) ;
|
|
Iter = m_CrvSmplS.erase( Iter) ;
|
|
break ;
|
|
}
|
|
// altrimenti superata lunghezza ancora da tagliare (taglio già fatto al test sopra)
|
|
else {
|
|
break ;
|
|
}
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::TrimEndAtParam( double dUTrim)
|
|
{
|
|
// verifico validità parametro
|
|
double dMaxU = double( m_CrvSmplS.size()) ;
|
|
if ( dUTrim < EPS_PARAM || dUTrim > dMaxU + EPS_PARAM)
|
|
return false ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
// ciclo sulle diverse curve dalla fine
|
|
bool bToErase = false ;
|
|
double dUToTrim = dUTrim ;
|
|
for ( auto 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) ;
|
|
}
|
|
// 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) {
|
|
// 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 ;
|
|
}
|
|
// passo alla entità successiva
|
|
++ Iter ;
|
|
// dichiaro ingresso in zona da cancellare
|
|
bToErase = true ;
|
|
}
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::TrimStartEndAtParam( double dUStartTrim, double dUEndTrim)
|
|
{
|
|
// valore massimo del parametro
|
|
double dMaxU = double( m_CrvSmplS.size()) ;
|
|
// i parametri start ed end devono essere compresi nel dominio parametrico della curva
|
|
if ( dUStartTrim < - EPS_PARAM || dUStartTrim > dMaxU + EPS_PARAM ||
|
|
dUEndTrim < - EPS_PARAM || dUEndTrim > dMaxU + EPS_PARAM)
|
|
return false ;
|
|
// se il parametro start supera quello di end
|
|
if ( dUStartTrim > dUEndTrim - EPS_PARAM) {
|
|
// se curva aperta, il trim la cancella completamente quindi errore
|
|
if ( ! IsClosed())
|
|
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 += dMaxU ;
|
|
// 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)
|
|
{
|
|
// verifico validità lunghezza risultante
|
|
if ( dLenTrim < EPS_ZERO)
|
|
return true ;
|
|
double dLen ;
|
|
if ( ! GetLength( dLen) || ( dLen - dLenTrim) < EPS_SMALL)
|
|
return false ;
|
|
// ciclo sulle diverse curve dall'inizio
|
|
double dLenToTrim = dLenTrim ;
|
|
for ( auto 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() ;
|
|
if ( m_CrvSmplS.empty())
|
|
return false ;
|
|
}
|
|
// se lunghezza ancora da tagliare nulla (entro la tolleranza)
|
|
else if ( dLenToTrim > - EPS_SMALL) {
|
|
delete (*Iter) ;
|
|
Iter ++ ;
|
|
m_CrvSmplS.pop_front() ;
|
|
if ( m_CrvSmplS.empty())
|
|
return false ;
|
|
break ;
|
|
}
|
|
// altrimenti superata lunghezza ancora da tagliare
|
|
else {
|
|
if ( ! (*Iter)->TrimStartAtLen( dCrvLen + dLenToTrim)) {
|
|
m_nStatus = ERR ;
|
|
return false ;
|
|
}
|
|
break ;
|
|
}
|
|
}
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::TrimEndAtLen( double dLenTrim)
|
|
{
|
|
// verifico validità lunghezza risultante
|
|
if ( dLenTrim < EPS_SMALL)
|
|
return false ;
|
|
double dLen ;
|
|
if ( ! GetLength( dLen))
|
|
return false ;
|
|
if ( ( dLen - dLenTrim) < EPS_ZERO)
|
|
return true ;
|
|
// ciclo sulle diverse curve dalla fine
|
|
bool bToErase = false ;
|
|
double dLenToTrim = dLenTrim ;
|
|
for ( auto Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ;) {
|
|
double dCrvLen = 0 ;
|
|
// 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) ;
|
|
}
|
|
// 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) {
|
|
// 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 ;
|
|
}
|
|
// 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 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
|
|
auto 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 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
|
|
for ( auto& pCrv : m_CrvSmplS)
|
|
pCrv->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
|
|
for ( auto& pCrv : m_CrvSmplS)
|
|
pCrv->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 ( abs( dCoeffX) < EPS_ZERO && abs( dCoeffY) < EPS_ZERO && abs( dCoeffZ) < EPS_ZERO)
|
|
return false ;
|
|
|
|
// verifico se chiusa
|
|
bool bClosed = IsClosed() ;
|
|
|
|
// calcolo bbox allineato con riferimento di scalatura e senza tener conto dello spessore
|
|
// lo scalo per verificare se tutto si riduce a un punto
|
|
BBox3d b3Ref ;
|
|
double dOriThick = 0 ;
|
|
swap( dOriThick, m_dThick) ;
|
|
if ( ! GetBBox( frRef, b3Ref))
|
|
return false ;
|
|
swap( dOriThick, m_dThick) ;
|
|
Vector3d vtDelta = b3Ref.GetMax() - b3Ref.GetMin() ;
|
|
if ( abs( vtDelta.x * dCoeffX) < EPS_SMALL &&
|
|
abs( vtDelta.y * dCoeffY) < EPS_SMALL &&
|
|
abs( vtDelta.z * dCoeffZ) < EPS_SMALL)
|
|
return false ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
// se scalatura non omogenea, devo trasformare tutti gli archi in curve di Bezier
|
|
if ( abs( dCoeffX - dCoeffY) > EPS_SMALL || abs( dCoeffX - dCoeffZ) > EPS_SMALL) {
|
|
if ( ! ArcsToBezierCurves())
|
|
return false ;
|
|
}
|
|
|
|
// scalo le singole curve
|
|
for ( auto Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ) {
|
|
// eseguo la scalatura
|
|
bool bOk = (*Iter)->Scale( frRef, dCoeffX, dCoeffY, dCoeffZ) ;
|
|
// se tutto bene, passo alla prossima
|
|
if ( bOk)
|
|
++Iter ;
|
|
// altrimenti, l'entità si è annullata => devo toglierla dalla lista e cancellarla
|
|
else {
|
|
// si è annullata l'entità, la elimino e la tolgo dalla lista
|
|
delete (*Iter) ;
|
|
Iter = m_CrvSmplS.erase( Iter) ;
|
|
}
|
|
}
|
|
|
|
// se ingrandimento, aggiusto coincidenza estremi delle singole curve
|
|
if ( abs( dCoeffX) > 1 || abs( dCoeffY) > 1 || abs( dCoeffZ) > 1) {
|
|
int nCount = int( m_CrvSmplS.size()) ;
|
|
for ( int i = 0 ; i < nCount ; ++ i) {
|
|
int j = i - 1 ;
|
|
if ( j < 0) {
|
|
if ( bClosed)
|
|
j = nCount - 1 ;
|
|
else
|
|
continue ;
|
|
}
|
|
ICurve* pCrvPrev = m_CrvSmplS[j] ;
|
|
ICurve* pCrvCurr = m_CrvSmplS[i] ;
|
|
Point3d ptEndPrev ; pCrvPrev->GetEndPoint( ptEndPrev) ;
|
|
Point3d ptStaCurr ; pCrvCurr->GetStartPoint( ptStaCurr) ;
|
|
if ( ! AreSamePointApprox( ptEndPrev, ptStaCurr)) {
|
|
Point3d ptNew = Media( ptEndPrev, ptStaCurr) ;
|
|
pCrvPrev->ModifyEnd( ptNew) ;
|
|
pCrvCurr->ModifyStart( ptNew) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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
|
|
for ( auto& pCrv : m_CrvSmplS)
|
|
pCrv->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
|
|
for ( auto& pCrv : m_CrvSmplS)
|
|
pCrv->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
|
|
for ( auto& pCrv : m_CrvSmplS)
|
|
pCrv->ToGlob( frRef) ;
|
|
|
|
// trasformo il vettore estrusione
|
|
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
|
|
for ( auto& pCrv : m_CrvSmplS)
|
|
pCrv->ToLoc( frRef) ;
|
|
|
|
// trasformo il vettore estrusione
|
|
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
|
|
for ( auto& pCrv : m_CrvSmplS)
|
|
pCrv->LocToLoc( frOri, frDest) ;
|
|
|
|
// trasformo il vettore estrusione
|
|
m_VtExtr.LocToLoc( frOri, frDest) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
const ICurve*
|
|
CurveComposite::GetCurve( int nCrv) const
|
|
{
|
|
// la curva deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return nullptr ;
|
|
// verifico che l'indice sia nei limiti
|
|
if ( nCrv < 0 || nCrv >= int( m_CrvSmplS.size()))
|
|
return nullptr ;
|
|
// restituisco la curva
|
|
return m_CrvSmplS[nCrv] ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
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
|
|
if ( m_Iter == m_CrvSmplS.end())
|
|
return nullptr ;
|
|
++ 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() || m_Iter == m_CrvSmplS.end())
|
|
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() ;
|
|
}
|
|
else {
|
|
// recupero la curva
|
|
pCrv = *(m_CrvSmplS.begin()) ;
|
|
// la tolgo dalla lista
|
|
m_CrvSmplS.pop_front() ;
|
|
}
|
|
// eseguo mini verifica
|
|
m_nStatus = ( m_CrvSmplS.size() > 0 ? OK : TO_VERIFY) ;
|
|
// 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
|
|
bool bClosed = IsClosed() ;
|
|
if ( ( ! bClosed && abs( dU) < EPS_PARAM) ||
|
|
( ! bClosed && abs( dU - double( m_CrvSmplS.size())) < EPS_PARAM) ||
|
|
abs( dU - (int) ( dU + EPS_PARAM)) > EPS_PARAM)
|
|
return false ;
|
|
else
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::ChangeStartPoint( double dU)
|
|
{
|
|
// la curva deve essere chiusa (ne verifica anche lo stato)
|
|
if ( ! IsClosed())
|
|
return false ;
|
|
|
|
// questa funzione gestisce già anche il cambio di inizio su curve chiuse
|
|
return TrimStartEndAtParam( dU, dU) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::ArcsToBezierCurves( void)
|
|
{
|
|
// verifico le singole curve
|
|
for ( auto 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( pNewCrv) ;
|
|
if ( pCC == nullptr)
|
|
return false ;
|
|
// inserisco le curve prima dell'arco
|
|
for ( auto Iter2 = pCC->m_CrvSmplS.begin() ; Iter2 != pCC->m_CrvSmplS.end() ; ++ Iter2) {
|
|
Iter = m_CrvSmplS.insert( Iter, (*Iter2)) ;
|
|
++ Iter ;
|
|
}
|
|
pCC->m_CrvSmplS.clear() ;
|
|
// elimino l'arco (e sposto l'iteratore alla curva precedente)
|
|
delete (*Iter) ;
|
|
Iter = m_CrvSmplS.erase( Iter) ;
|
|
-- Iter ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::ArcsBezierCurvesToArcsPerpExtr( double dLinTol, double dAngTolDeg)
|
|
{
|
|
// verifico le singole curve
|
|
for ( auto Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++ Iter) {
|
|
// se arco in piano non perpendicolare ad estrusione o curva di Bezier trasformo
|
|
if ( ( (*Iter)->GetType() == CRV_ARC && ! AreSameVectorApprox( m_VtExtr, GetBasicCurveArc( *Iter)->GetNormVersor())) ||
|
|
(*Iter)->GetType() == CRV_BEZIER) {
|
|
// eseguo trasformazione
|
|
(*Iter)->SetExtrusion( m_VtExtr) ;
|
|
PtrOwner<ICurve> pNewCrv( CurveToArcsPerpExtrCurve( (*Iter), dLinTol, dAngTolDeg)) ;
|
|
(*Iter)->SetExtrusion( V_NULL) ;
|
|
if ( IsNull( pNewCrv))
|
|
return false ;
|
|
// se risultato è singola curva
|
|
if ( pNewCrv->IsSimple()) {
|
|
// elimino la curva originale e la sostituisco con l'arco
|
|
delete (*Iter) ;
|
|
(*Iter) = Release( pNewCrv) ;
|
|
}
|
|
// altrimenti è una curva composita
|
|
else {
|
|
CurveComposite* pCC = GetBasicCurveComposite( pNewCrv) ;
|
|
if ( pCC == nullptr)
|
|
return false ;
|
|
// inserisco le curve prima dell'originale
|
|
for ( auto Iter2 = pCC->m_CrvSmplS.begin() ; Iter2 != pCC->m_CrvSmplS.end() ; ++ Iter2) {
|
|
Iter = m_CrvSmplS.insert( Iter, (*Iter2)) ;
|
|
++ Iter ;
|
|
}
|
|
pCC->m_CrvSmplS.clear() ;
|
|
// elimino la curva originale (e sposto l'iteratore alla curva precedente)
|
|
delete (*Iter) ;
|
|
Iter = m_CrvSmplS.erase( Iter) ;
|
|
-- Iter ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::StraightArcsToLines( double dLinTol, double dAngTolDeg)
|
|
{
|
|
// controllo le tolleranze
|
|
dLinTol = max( dLinTol, EPS_SMALL) ;
|
|
dAngTolDeg = Clamp( dAngTolDeg, EPS_ANG_SMALL, ANG_RIGHT) ;
|
|
// verifico le singole curve
|
|
for ( auto Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++ Iter) {
|
|
CurveArc* pArc = GetBasicCurveArc( *Iter) ;
|
|
if ( pArc != nullptr &&
|
|
abs( pArc->GetAngCenter()) < dAngTolDeg &&
|
|
pArc->GetRadius() * ( 1 - cos( pArc->GetAngCenter() / 2 * DEGTORAD)) < dLinTol) {
|
|
// recupero gli estremi
|
|
Point3d ptStart, ptEnd ;
|
|
if ( ! pArc->GetStartPoint( ptStart) || ! pArc->GetEndPoint( ptEnd))
|
|
return false ;
|
|
// creo la linea
|
|
PtrOwner<CurveLine> pLine( CreateBasicCurveLine()) ;
|
|
if ( IsNull( pLine) || ! pLine->Set( ptStart, ptEnd))
|
|
return false ;
|
|
// elimino la curva originale e la sostituisco con la nuova
|
|
delete (*Iter) ;
|
|
(*Iter) = Release( pLine) ;
|
|
}
|
|
}
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
static int
|
|
MergeTwoCurves( ICurve* pCrvP, ICurve* pCrvC, double& dCurrLinTol, double dCosAngTol, bool bNeedSameProp)
|
|
{
|
|
// se precedente molto corta
|
|
double dLenP ;
|
|
if ( pCrvP->GetLength( dLenP) && dLenP < dCurrLinTol) {
|
|
// se abbastanza allineata alla successiva
|
|
Vector3d vtDirP, vtDirC ;
|
|
if ( pCrvP->GetEndDir( vtDirP) && pCrvC->GetStartDir( vtDirC) && ( vtDirP * vtDirC) >= dCosAngTol) {
|
|
Point3d ptStart ;
|
|
return ( pCrvP->GetStartPoint( ptStart) && pCrvC->ModifyStart( ptStart) ? -1 : 0) ;
|
|
}
|
|
}
|
|
// se corrente molto corta
|
|
double dLenC ;
|
|
if ( pCrvC->GetLength( dLenC) && dLenC < dCurrLinTol) {
|
|
// se abbastanza allineata alla precedente
|
|
Vector3d vtDirP, vtDirC ;
|
|
if ( pCrvP->GetEndDir( vtDirP) && pCrvC->GetStartDir( vtDirC) && ( vtDirP * vtDirC) >= dCosAngTol) {
|
|
Point3d ptEnd ;
|
|
return ( pCrvC->GetEndPoint( ptEnd) && pCrvP->ModifyEnd( ptEnd) ? 1 : 0) ;
|
|
}
|
|
}
|
|
// verifico compatibilità delle proprietà
|
|
int nTpr0P = pCrvP->GetTempProp( 0) ;
|
|
int nTpr0C = pCrvC->GetTempProp( 0) ;
|
|
int nTpr1P = pCrvP->GetTempProp( 1) ;
|
|
int nTpr1C = pCrvC->GetTempProp( 1) ;
|
|
if ( bNeedSameProp && ( nTpr0P != nTpr0C || nTpr1P != nTpr1C))
|
|
return 0 ;
|
|
// coefficiente deduzione tolleranza
|
|
const double COEFF_TOL = 0.7 ;
|
|
// se entrambe rette
|
|
if ( pCrvP->GetType() == CRV_LINE && pCrvC->GetType() == CRV_LINE) {
|
|
CurveLine* pLineP = GetBasicCurveLine( pCrvP) ;
|
|
CurveLine* pLineC = GetBasicCurveLine( pCrvC) ;
|
|
// verifico se allineate
|
|
Vector3d vtDirP, vtDirC ;
|
|
if ( pLineP != nullptr && pLineP->GetStartDir( vtDirP) &&
|
|
pLineC != nullptr && pLineC->GetStartDir( vtDirC) &&
|
|
( vtDirP * vtDirC) >= dCosAngTol) {
|
|
// verifico se il punto di giunzione sia eliminabile
|
|
DistPointLine dPL( pLineP->GetEnd(), pLineP->GetStart(), pLineC->GetEnd()) ;
|
|
double dSqDist ;
|
|
if ( dPL.GetSqDist( dSqDist) && dSqDist < dCurrLinTol * dCurrLinTol) {
|
|
// se modifica linea corrente ok, procedo con l'unione
|
|
if ( pLineC->ModifyStart( pLineP->GetStart())) {
|
|
// diminuisco la tolleranza corrente dell'errore attuale
|
|
dCurrLinTol -= COEFF_TOL * sqrt( dSqDist) ;
|
|
// se curve originali con proprietà diversa, la cancello
|
|
if ( nTpr0P != nTpr0C)
|
|
pLineC->SetTempProp( 0, 0) ;
|
|
if ( nTpr1P != nTpr1C)
|
|
pLineC->SetTempProp( 0, 1) ;
|
|
// torno flag modifica
|
|
return -1 ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// se entrambi archi
|
|
else if ( pCrvP->GetType() == CRV_ARC && pCrvC->GetType() == CRV_ARC) {
|
|
CurveArc* pArcP = GetBasicCurveArc( pCrvP) ;
|
|
CurveArc* pArcC = GetBasicCurveArc( pCrvC) ;
|
|
// centro del primo arco riportato alla quota del punto finale sulla normale dello stesso
|
|
Point3d ptC1Fin = pArcP->GetCenter() + pArcP->GetNormVersor() * pArcP->GetDeltaN() ;
|
|
// centro del secondo arco alla quota del punto iniziale sulla normale dello stesso
|
|
Point3d ptC2Ini = pArcC->GetCenter() ;
|
|
// verifico la coincidenza dei centri
|
|
if ( ! AreSamePointEpsilon( ptC1Fin, ptC2Ini, dCurrLinTol))
|
|
return 0 ;
|
|
// verifico la coincidenza dei raggi
|
|
if ( abs( pArcP->GetRadius() - pArcC->GetRadius()) > dCurrLinTol)
|
|
return 0 ;
|
|
// verifico la collinearità delle normali (tenendo conto del raggio)
|
|
if ( ! (( pArcP->GetNormVersor() - pArcC->GetNormVersor()) * pArcP->GetRadius()).IsSmall() &&
|
|
! (( pArcP->GetNormVersor() + pArcC->GetNormVersor()) * pArcP->GetRadius()).IsSmall())
|
|
return 0 ;
|
|
// verifico la coincidenza del senso di rotazione (verso delle normali e segno angoli al centro)
|
|
if ( pArcP->GetNormVersor() * pArcC->GetNormVersor() * pArcP->GetAngCenter() * pArcC->GetAngCenter() < 0)
|
|
return 0 ;
|
|
// verifico di non superare l'angolo giro al centro
|
|
if ( abs( pArcP->GetAngCenter() + pArcC->GetAngCenter()) > ANG_FULL + EPS_ANG_SMALL)
|
|
return 0 ;
|
|
// se archi piatti
|
|
if ( pArcP->IsPlane() && pArcC->IsPlane()) {
|
|
// se calcolo nuovo arco ok, procedo con l'unione
|
|
Point3d ptP1 ;
|
|
pArcP->GetStartPoint( ptP1) ;
|
|
Point3d ptP2 ;
|
|
pArcP->GetEndPoint( ptP2) ;
|
|
Point3d ptP3 ;
|
|
pArcC->GetEndPoint( ptP3) ;
|
|
// verifico se circonferenza completa
|
|
bool bCirc = ( AreSamePointApprox( ptP1, ptP3)) ;
|
|
if ( bCirc)
|
|
pArcC->GetMidPoint( ptP3) ;
|
|
CurveArc NewArc ;
|
|
if ( NewArc.Set3P( ptP1, ptP2, ptP3, bCirc)) {
|
|
// verifico normale al piano dell'arco
|
|
if ( NewArc.GetNormVersor() * pArcC->GetNormVersor() < 0)
|
|
NewArc.InvertN() ;
|
|
// se curve originali con la stessa proprietà, la riporto
|
|
if ( nTpr0P == nTpr0C)
|
|
NewArc.SetTempProp( nTpr0C, 0) ;
|
|
if ( nTpr1P == nTpr1C)
|
|
NewArc.SetTempProp( nTpr1C, 1) ;
|
|
// aggiorno l'arco corrente e torno flag modifica
|
|
*pArcC = NewArc ;
|
|
return -1 ;
|
|
}
|
|
else
|
|
return 0 ;
|
|
}
|
|
// verifico coincidenza pendenza sulla normale
|
|
double dN = pArcP->GetNormVersor() * pArcC->GetNormVersor() ;
|
|
if ( abs(( pArcC->GetDeltaN() * pArcP->GetAngCenter() - dN * pArcP->GetDeltaN() * pArcC->GetAngCenter()) /
|
|
( pArcP->GetAngCenter() + pArcC->GetAngCenter())) < dCurrLinTol) {
|
|
// se calcolo nuovo arco ok, procedo con l'unione
|
|
Point3d ptP1 ;
|
|
pArcP->GetStartPoint( ptP1) ;
|
|
Vector3d vtDir1 ;
|
|
pArcP->GetStartDir( vtDir1) ;
|
|
Point3d ptP3 ;
|
|
pArcC->GetEndPoint( ptP3) ;
|
|
CurveArc NewArc ;
|
|
if ( NewArc.Set2PVN( ptP1, ptP3, vtDir1, pArcC->GetNormVersor())) {
|
|
// se curve originali con la stessa proprietà, la riporto
|
|
if ( nTpr0P == nTpr0C)
|
|
NewArc.SetTempProp( nTpr0C, 0) ;
|
|
if ( nTpr1P == nTpr1C)
|
|
NewArc.SetTempProp( nTpr1C, 1) ;
|
|
// aggiorno l'arco corrente e torno flag modifica
|
|
*pArcC = NewArc ;
|
|
return -1 ;
|
|
}
|
|
else
|
|
return 0 ;
|
|
}
|
|
}
|
|
|
|
// nessuna fusione
|
|
return 0 ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::MergeCurves( double dLinTol, double dAngTolDeg, bool bStartEnd, bool bNeedSameProp)
|
|
{
|
|
// se non ci sono almeno 2 curve, esco subito
|
|
if ( m_CrvSmplS.size() < 2)
|
|
return true ;
|
|
// controllo sui limiti di tolleranza
|
|
dLinTol = max( dLinTol, EPS_SMALL) ;
|
|
dAngTolDeg = max( dAngTolDeg, EPS_ANG_SMALL) ;
|
|
double dCosAngTol = cos( dAngTolDeg * DEGTORAD) ;
|
|
// tolleranza lineare corrente
|
|
double dCurrLinTol = dLinTol ;
|
|
// devo verificare coppie di curve
|
|
auto iterP = m_CrvSmplS.begin() ;
|
|
auto iterC = next( iterP) ;
|
|
// mentre esiste la coppia
|
|
while ( iterC != m_CrvSmplS.end()) {
|
|
// se curve unite
|
|
switch ( MergeTwoCurves( *iterP, *iterC, dCurrLinTol, dCosAngTol, bNeedSameProp)) {
|
|
case -1 : // cancello l'entità precedente e la tolgo dalla lista
|
|
delete (*iterP) ;
|
|
iterC = m_CrvSmplS.erase( iterP) ;
|
|
break ;
|
|
case 1 : // cancello l'entità corrente e la tolgo dalla lista
|
|
delete (*iterC) ;
|
|
iterC = m_CrvSmplS.erase( iterC) ;
|
|
iterC = prev( iterC) ;
|
|
break ;
|
|
default : // ripristino la tolleranza
|
|
dCurrLinTol = dLinTol ;
|
|
break ;
|
|
}
|
|
// avanzo
|
|
iterP = iterC ;
|
|
iterC = next( iterC) ;
|
|
}
|
|
// se richiesto e curva chiusa devo confrontare anche ultima e prima curva
|
|
if ( bStartEnd && m_CrvSmplS.size() >= 2 && IsClosed()) {
|
|
iterC = m_CrvSmplS.begin() ;
|
|
switch ( MergeTwoCurves( *iterP, *iterC, dCurrLinTol, dCosAngTol, bNeedSameProp)) {
|
|
case -1 : // cancello l'entità precedente e la tolgo dalla lista
|
|
delete (*iterP) ;
|
|
m_CrvSmplS.erase( iterP) ;
|
|
break ;
|
|
case 1 : // cancello l'entità corrente e la tolgo dalla lista
|
|
delete (*iterC) ;
|
|
m_CrvSmplS.erase( iterC) ;
|
|
break ;
|
|
}
|
|
}
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::RemoveSmallDefects( double dLinTol, double dAngTolDeg, bool bAlsoSpikes)
|
|
{
|
|
return (( ! bAlsoSpikes || RemoveCurveSpikes( this, dLinTol)) && RemoveCurveSmallZs(this, dLinTol)) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
static bool
|
|
SplitTopBottomArcs( CurveComposite& cCompo)
|
|
{
|
|
int i = 0 ;
|
|
const ICurve* pCrv = cCompo.GetCurve( i) ;
|
|
while ( pCrv != nullptr) {
|
|
if ( pCrv->GetType() == CRV_ARC) {
|
|
const CurveArc* pArc = GetBasicCurveArc( pCrv) ;
|
|
// determino la rotazione angolare dall'inizio alle direzioni destra e sinistra
|
|
double dAng1, dAng2 ;
|
|
bool bDet ;
|
|
pArc->GetStartVersor().GetRotation( X_AX, Z_AX, dAng1, bDet) ;
|
|
pArc->GetStartVersor().GetRotation( - X_AX, Z_AX, dAng2, bDet) ;
|
|
// oriento queste rotazioni come l'angolo al centro dell'arco
|
|
if ( pArc->GetAngCenter() > 0) {
|
|
if ( dAng1 < 0)
|
|
dAng1 += ANG_FULL ;
|
|
if ( dAng2 < 0)
|
|
dAng2 += ANG_FULL ;
|
|
}
|
|
else {
|
|
if ( dAng1 > 0)
|
|
dAng1 -= ANG_FULL ;
|
|
if ( dAng2 > 0)
|
|
dAng2 -= ANG_FULL ;
|
|
}
|
|
// le ordino in senso crescente di ampiezza assoluta
|
|
if ( abs( dAng1) > abs( dAng2))
|
|
swap( dAng1, dAng2) ;
|
|
// verifico se la prima di queste rotazioni è compresa nell'arco
|
|
if ( abs( dAng1) > EPS_ANG_SMALL && abs( dAng1) < abs( pArc->GetAngCenter()) - EPS_ANG_SMALL) {
|
|
cCompo.AddJoint( i + dAng1 / pArc->GetAngCenter()) ;
|
|
}
|
|
// verifico la seconda
|
|
else if ( abs( dAng2) > EPS_ANG_SMALL && abs( dAng2) < abs( pArc->GetAngCenter()) - EPS_ANG_SMALL) {
|
|
cCompo.AddJoint( i + dAng2 / pArc->GetAngCenter()) ;
|
|
}
|
|
}
|
|
// passo alla successiva
|
|
pCrv = cCompo.GetCurve( ++i) ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::RemoveUndercutOnY( double dLinTol, double dAngTolDeg)
|
|
{
|
|
// verifico sia una curva che giace nel piano XY e con vettore estrusione nullo o Z
|
|
BBox3d b3Box ;
|
|
if ( ! GetLocalBBox( b3Box) || ( b3Box.GetMax().z - b3Box.GetMin().z) > dLinTol)
|
|
return false ;
|
|
if ( ! m_VtExtr.IsSmall() && ! AreSameVectorApprox( m_VtExtr, Z_AX))
|
|
return false ;
|
|
// ne faccio una copia
|
|
CurveComposite ccCopy ;
|
|
if ( ! ccCopy.CopyFrom( this))
|
|
return false ;
|
|
// eventuali modifiche deve essere formata solo da archi e rette
|
|
if ( ! ccCopy.ArcsBezierCurvesToArcsPerpExtr( dLinTol, dAngTolDeg))
|
|
return false ;
|
|
// divido gli archi in sopra e sotto
|
|
if ( ! SplitTopBottomArcs( ccCopy))
|
|
return false ;
|
|
// creo la regione unione delle regioni sottese ad ogni curva rispetto ad un Y inferiore al minimo del box
|
|
SurfFlatRegion SfrTot ;
|
|
const double DELTA_Y = 10 ;
|
|
double dYmin = b3Box.GetMin().y - DELTA_Y ;
|
|
PtrOwner<ICurve> pCrv ;
|
|
while ( pCrv.Set( ccCopy.RemoveFirstOrLastCurve( false))) {
|
|
// creo la regione sottesa dalla curva
|
|
PtrOwner<CurveComposite> pCompo( CreateBasicCurveComposite()) ;
|
|
if ( IsNull( pCompo))
|
|
return false ;
|
|
pCompo->AddCurve( Release( pCrv)) ;
|
|
// estremi
|
|
Point3d ptStart, ptEnd ;
|
|
pCompo->GetStartPoint( ptStart) ;
|
|
pCompo->GetEndPoint( ptEnd) ;
|
|
// se curva pressochè verticale non sottende alcunché, quindi la salto
|
|
if ( abs( ptStart.x - ptEnd.x) < EPS_SMALL)
|
|
continue ;
|
|
// ordino gli estremi
|
|
if ( ptStart.x < ptEnd.x) {
|
|
swap( ptStart, ptEnd) ;
|
|
pCompo->Invert() ;
|
|
}
|
|
// chiudo la curva
|
|
pCompo->AddLine( Point3d( ptEnd.x, dYmin, ptEnd.z)) ;
|
|
pCompo->AddLine( Point3d( ptStart.x, dYmin, ptStart.z)) ;
|
|
pCompo->Close() ;
|
|
// creo regione sottesa
|
|
SurfFlatRegion Sfr ;
|
|
Sfr.AddExtLoop( Release( pCompo)) ;
|
|
if ( ! Sfr.IsValid())
|
|
return false ;
|
|
// la unisco alla regione complessiva
|
|
if ( ! SfrTot.IsValid())
|
|
SfrTot = Sfr ;
|
|
else {
|
|
if ( ! SfrTot.Add( Sfr))
|
|
return false ;
|
|
}
|
|
}
|
|
// recupero il contorno esterno della regione
|
|
PtrOwner<ICurve> pOutLoop( SfrTot.GetLoop( 0, 0)) ;
|
|
if ( IsNull( pOutLoop))
|
|
return false ;
|
|
// elimino le parti sotto il minimo del box
|
|
// box della parte da eliminare
|
|
double dWidth = b3Box.GetMax().x - b3Box.GetMin().x + 20 * EPS_SMALL ;
|
|
double dLen = DELTA_Y + 10 * EPS_SMALL ;
|
|
PtrOwner<ISurfFlatRegion> pSfrCut( GetSurfFlatRegionRectangle( dWidth, dLen)) ;
|
|
if ( IsNull( pSfrCut))
|
|
return false ;
|
|
pSfrCut->Translate( b3Box.GetMin() - Point3d( 10 * EPS_SMALL, dLen, 0)) ;
|
|
// calcolo la classificazione della curva rispetto alla regione
|
|
CRVCVECTOR ccClass ;
|
|
if ( ! pSfrCut->GetCurveClassification( *pOutLoop, EPS_SMALL, ccClass))
|
|
return false ;
|
|
// determino gli intervalli di curva da conservare
|
|
Intervals inOk ;
|
|
for ( auto& ccOne : ccClass) {
|
|
if ( ccOne.nClass == CRVC_OUT)
|
|
inOk.Add( ccOne.dParS, ccOne.dParE) ;
|
|
}
|
|
// Sempre un solo intervallo effettivo su curva chiusa
|
|
double dTrimS, dTrimE, dDummy ;
|
|
if ( inOk.GetCount() == 1)
|
|
inOk.GetFirst( dTrimS, dTrimE) ;
|
|
else if ( inOk.GetCount() == 2) {
|
|
inOk.GetFirst( dDummy, dTrimE) ;
|
|
inOk.GetNext( dTrimS, dDummy) ;
|
|
}
|
|
else
|
|
return false ;
|
|
if ( ! pOutLoop->TrimStartEndAtParam( dTrimS, dTrimE))
|
|
return false ;
|
|
// assegno la nuova curva
|
|
Clear() ;
|
|
return AddCurve( Release( pOutLoop)) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::IsAPoint( void) const
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// ciclo di verifica
|
|
for ( auto Iter = m_CrvSmplS.begin() ; Iter != m_CrvSmplS.end() ; ++Iter) {
|
|
if ( (*Iter)->GetType() != CRV_BEZIER ||
|
|
! GetBasicCurveBezier(*Iter)->IsAPoint())
|
|
return false ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::IsALine( double dLinTol, Point3d& ptStart, Point3d& ptEnd) const
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK || m_CrvSmplS.empty())
|
|
return false ;
|
|
|
|
// recupero gli estremi
|
|
if ( ! m_CrvSmplS.front()->GetStartPoint( ptStart) ||
|
|
! m_CrvSmplS.back()->GetEndPoint( ptEnd))
|
|
return false ;
|
|
|
|
// verifico non siano coincidenti
|
|
if ( AreSamePointEpsilon( ptStart, ptEnd, min( dLinTol, EPS_SMALL)))
|
|
return false ;
|
|
|
|
// provo ad approssimarla con segmenti e verifico se si riduce ad un segmento di retta
|
|
PolyLine PL ;
|
|
if ( ! ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, APL_SPECIAL, PL))
|
|
return false ;
|
|
// elimino i punti allineati entro la tolleranza
|
|
if ( ! PL.RemoveAlignedPoints( dLinTol))
|
|
return false ;
|
|
// se sono rimasti due punti è una retta
|
|
return ( PL.GetPointNbr() == 2) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::IsOneCircle( Point3d& ptCen, Vector3d& vtN, double& dRad, bool& bCCW) const
|
|
{
|
|
// deve essere una sola entità
|
|
if ( GetCurveCount() != 1)
|
|
return false ;
|
|
// deve essere un arco di circonferenza completo
|
|
const CurveArc* pArc = GetBasicCurveArc( GetFirstCurve()) ;
|
|
if ( pArc == nullptr || ! pArc->IsACircle())
|
|
return false ;
|
|
// assegno i parametri
|
|
ptCen = pArc->GetCenter() ;
|
|
vtN = pArc->GetNormVersor() ;
|
|
dRad = pArc->GetRadius() ;
|
|
bCCW = ( pArc->GetAngCenter() > 0) ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::IsACircle( double dLinTol, Point3d& ptCen, Vector3d& vtN, double& dRad, bool& bCCW) const
|
|
{
|
|
// deve essere chiusa
|
|
if ( ! IsClosed())
|
|
return false ;
|
|
|
|
// se è formata da una sola entità arco che è una circonferenza
|
|
if ( IsOneCircle( ptCen, vtN, dRad, bCCW))
|
|
return true ;
|
|
|
|
// provo ad approssimarla con archi e verifico se si riduce ad una circonferenza
|
|
PolyArc PA ;
|
|
if ( ! ApproxWithArcs( dLinTol, ANG_TOL_STD_DEG, PA))
|
|
return false ;
|
|
CurveComposite CrvTemp ;
|
|
if ( ! CrvTemp.FromPolyArc( PA) || ! CrvTemp.MergeCurves( dLinTol, ANG_TOL_STD_DEG))
|
|
return false ;
|
|
return CrvTemp.IsOneCircle( ptCen, vtN, dRad, bCCW) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::IsARectangle( double dLinTol, Point3d& ptP, Vector3d& vtL1, Vector3d& vtL2) const
|
|
{
|
|
// deve essere chiusa
|
|
if ( ! IsClosed())
|
|
return false ;
|
|
// approssimo con segmenti di retta
|
|
PolyLine PL ;
|
|
if ( ! ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, APL_STD, PL))
|
|
return false ;
|
|
// deve giacere in un piano entro la tolleranza
|
|
Plane3d plPlane ;
|
|
if ( ! PL.IsFlat( plPlane, dLinTol))
|
|
return false ;
|
|
// deve essere formata da 4 segmenti
|
|
if ( PL.GetLineNbr() != 4)
|
|
return false ;
|
|
// recupero i 4 vertici
|
|
Point3d ptV1 ; PL.GetFirstPoint( ptV1) ;
|
|
Point3d ptV2 ; PL.GetNextPoint( ptV2) ;
|
|
Point3d ptV3 ; PL.GetNextPoint( ptV3) ;
|
|
Point3d ptV4 ; PL.GetNextPoint( ptV4) ;
|
|
// verifico che le diagonali si incontrino nel loro punto medio (-> è un parallelogramma)
|
|
if ( ! AreSamePointEpsilon( Media( ptV1, ptV3), Media( ptV2, ptV4), dLinTol / 2))
|
|
return false ;
|
|
// verifico che le diagonali abbiano la stessa lunghezza (-> è un rettangolo)
|
|
if ( abs( Dist( ptV1, ptV3) - Dist( ptV2, ptV4)) > dLinTol)
|
|
return false ;
|
|
// assegno i parametri del rettangolo
|
|
ptP = ptV1 ;
|
|
vtL1 = ptV2 - ptV1 ;
|
|
vtL2 = ptV4 - ptV1 ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::IsATrapezoid( double dLinTol, Point3d& ptP, Vector3d& vtB1, Vector3d& vtL1, Vector3d& vtB2) const
|
|
{
|
|
// deve essere chiusa
|
|
if ( ! IsClosed())
|
|
return false ;
|
|
// approssimo con segmenti di retta
|
|
PolyLine PL ;
|
|
if ( ! ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, APL_STD, PL))
|
|
return false ;
|
|
// deve giacere in un piano entro la tolleranza
|
|
Plane3d plPlane ;
|
|
if ( ! PL.IsFlat( plPlane, dLinTol))
|
|
return false ;
|
|
// deve essere formata da 4 segmenti
|
|
if ( PL.GetLineNbr() != 4)
|
|
return false ;
|
|
// recupero i 4 vertici
|
|
Point3d ptV1 ; PL.GetFirstPoint( ptV1) ;
|
|
Point3d ptV2 ; PL.GetNextPoint( ptV2) ;
|
|
Point3d ptV3 ; PL.GetNextPoint( ptV3) ;
|
|
Point3d ptV4 ; PL.GetNextPoint( ptV4) ;
|
|
// verifico se V4->V3 è parallelo a V1->V2
|
|
double dV3B12, dV4B12 ;
|
|
if ( ! DistPointLine( ptV3, ptV1, ptV2, false).GetDist( dV3B12) ||
|
|
! DistPointLine( ptV4, ptV1, ptV2, false).GetDist( dV4B12))
|
|
return false ;
|
|
if ( abs( dV3B12 - dV4B12) < EPS_SMALL) {
|
|
ptP = ptV1 ;
|
|
vtB1 = ptV2 - ptV1 ;
|
|
vtL1 = ptV4 - ptV1 ;
|
|
vtB2 = ptV3 - ptV4 ;
|
|
return true ;
|
|
}
|
|
// verifico se V1->V4 è parallelo a V2->V3
|
|
double dV1B23, dV4B23 ;
|
|
if ( ! DistPointLine( ptV1, ptV2, ptV3, false).GetDist( dV1B23) ||
|
|
! DistPointLine( ptV4, ptV2, ptV3, false).GetDist( dV4B23))
|
|
return false ;
|
|
if ( abs( dV1B23 - dV4B23) < EPS_SMALL) {
|
|
ptP = ptV2 ;
|
|
vtB1 = ptV3 - ptV2 ;
|
|
vtL1 = ptV1 - ptV2 ;
|
|
vtB2 = ptV4 - ptV1 ;
|
|
return true ;
|
|
}
|
|
// non è un trapezio
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::SetCurveTempProp( int nCrv, int nProp, int nPropNum)
|
|
{
|
|
// la curva deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
// verifico che l'indice sia nei limiti
|
|
if ( nCrv < 0 || nCrv >= int( m_CrvSmplS.size()))
|
|
return false ;
|
|
// eseguo assegnazione
|
|
m_CrvSmplS[nCrv]->SetTempProp( nProp, nPropNum) ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CurveComposite::GetCurveTempProp( int nCrv, int& nProp, int nPropNum) const
|
|
{
|
|
// la curva deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
// verifico che l'indice sia nei limiti
|
|
if ( nCrv < 0 || nCrv >= int( m_CrvSmplS.size()))
|
|
return false ;
|
|
// eseguo recupero
|
|
nProp = m_CrvSmplS[nCrv]->GetTempProp( nPropNum) ;
|
|
return true ;
|
|
}
|