f0a1df86cc
- corretta GetSurfFlatRegionFromFatCurve per creazione superficie quando curva non su piano XY.
429 lines
16 KiB
C++
429 lines
16 KiB
C++
//----------------------------------------------------------------------------
|
|
// EgalTech 2015-2016
|
|
//----------------------------------------------------------------------------
|
|
// File : StmFromCurves.cpp Data : 11.08.16 Versione : 1.6t2
|
|
// Contenuto : Implementazione di funzioni per creazione di superfici Stm
|
|
// a partire da curve, con diversi metodi.
|
|
//
|
|
//
|
|
// Modifiche : 01.02.15 DS Creazione modulo.
|
|
// 11.08.16 DS In GetSurfFlatRegionFromFatCurve sostituito Offset a SimpleOffset.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
//--------------------------- Include ----------------------------------------
|
|
#include "stdafx.h"
|
|
#include "CurveLine.h"
|
|
#include "CurveArc.h"
|
|
#include "CurveComposite.h"
|
|
#include "SurfFlatRegion.h"
|
|
#include "GeoConst.h"
|
|
#include "/EgtDev/Include/EgkBiArcs.h"
|
|
#include "/EgtDev/Include/EgkOffsetCurve.h"
|
|
#include "/EgtDev/Include/EGkSfrCreate.h"
|
|
#include "/EgtDev/Include/EgtPointerOwner.h"
|
|
#include <algorithm>
|
|
|
|
using namespace std ;
|
|
|
|
//-------------------------------------------------------------------------------
|
|
ISurfFlatRegion*
|
|
GetSurfFlatRegionRectangle( double dWidth, double dLen)
|
|
{
|
|
// le dimensioni devono essere significative
|
|
if ( dWidth < EPS_SMALL || dLen < EPS_SMALL)
|
|
return nullptr ;
|
|
// creo il contorno
|
|
PolyLine PL ;
|
|
PL.AddUPoint( 0, ORIG) ;
|
|
PL.AddUPoint( 1, Point3d( dWidth, 0, 0)) ;
|
|
PL.AddUPoint( 2, Point3d( dWidth, dLen, 0)) ;
|
|
PL.AddUPoint( 3, Point3d( 0, dLen, 0)) ;
|
|
PL.AddUPoint( 4, ORIG) ;
|
|
PtrOwner<CurveComposite> pCC( CreateBasicCurveComposite()) ;
|
|
if ( IsNull( pCC) || ! pCC->FromPolyLine( PL))
|
|
return nullptr ;
|
|
// creo il rettangolo
|
|
PtrOwner<SurfFlatRegion> pSfr( CreateBasicSurfFlatRegion()) ;
|
|
if ( IsNull( pSfr) || ! pSfr->AddExtLoop( Release( pCC)))
|
|
return nullptr ;
|
|
else
|
|
return Release( pSfr) ;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
ISurfFlatRegion*
|
|
GetSurfFlatRegionStadium( double dWidth, double dLen)
|
|
{
|
|
// le dimensioni devono essere significative
|
|
if ( dWidth < EPS_SMALL || dLen < EPS_SMALL)
|
|
return nullptr ;
|
|
// se dimensioni praticamente uguali, è un disco
|
|
if ( abs( dWidth - dLen) < 10 * EPS_SMALL)
|
|
return GetSurfFlatRegionDisk( ( dWidth + dLen) / 4) ;
|
|
// creo il contorno
|
|
PolyArc PA ;
|
|
if ( dWidth > dLen) {
|
|
double dRad = dLen / 2 ;
|
|
PA.AddUPoint( 0, Point3d( dRad, 0, 0), 0) ;
|
|
PA.AddUPoint( 1, Point3d( dWidth - dRad, 0, 0), 1) ;
|
|
PA.AddUPoint( 2, Point3d( dWidth - dRad, dLen, 0), 0) ;
|
|
PA.AddUPoint( 3, Point3d( dRad, dLen, 0), 1) ;
|
|
PA.AddUPoint( 4, Point3d( dRad, 0, 0), 0) ;
|
|
}
|
|
else {
|
|
double dRad = dWidth / 2 ;
|
|
PA.AddUPoint( 0, Point3d( dWidth, dRad, 0), 0) ;
|
|
PA.AddUPoint( 1, Point3d( dWidth, dLen - dRad, 0), 1) ;
|
|
PA.AddUPoint( 2, Point3d( 0, dLen - dRad, 0), 0) ;
|
|
PA.AddUPoint( 3, Point3d( 0, dRad, 0), 1) ;
|
|
PA.AddUPoint( 4, Point3d( dWidth, dRad, 0), 0) ;
|
|
}
|
|
PtrOwner<CurveComposite> pCC( CreateBasicCurveComposite()) ;
|
|
if ( IsNull( pCC) || ! pCC->FromPolyArc( PA))
|
|
return nullptr ;
|
|
// creo il rettangolo
|
|
PtrOwner<SurfFlatRegion> pSfr( CreateBasicSurfFlatRegion()) ;
|
|
if ( IsNull( pSfr) || ! pSfr->AddExtLoop( Release( pCC)))
|
|
return nullptr ;
|
|
else
|
|
return Release( pSfr) ;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
ISurfFlatRegion*
|
|
GetSurfFlatRegionDisk( double dRadius)
|
|
{
|
|
// le dimensioni devono essere significative
|
|
if ( dRadius < EPS_SMALL)
|
|
return nullptr ;
|
|
// creo la circonferenza di riferimento
|
|
PtrOwner<CurveArc> pArc( CreateBasicCurveArc()) ;
|
|
if ( IsNull( pArc))
|
|
return nullptr ;
|
|
pArc->Set( ORIG, Z_AX, dRadius, X_AX, ANG_FULL, 0) ;
|
|
// creo il disco
|
|
PtrOwner<SurfFlatRegion> pSfr( CreateBasicSurfFlatRegion()) ;
|
|
if ( IsNull( pSfr) || ! pSfr->AddExtLoop( Release( pArc)))
|
|
return nullptr ;
|
|
else
|
|
return Release( pSfr) ;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
ISurfFlatRegion*
|
|
GetSurfFlatRegionFromFatCurve( ICurve* pCrv, double dRadius, bool bSquareEnds, bool bSquareMids)
|
|
{
|
|
// mi impossesso della curva
|
|
PtrOwner<ICurve> pCurve( pCrv) ;
|
|
if ( IsNull( pCurve))
|
|
return nullptr ;
|
|
// la inserisco in una curva composita
|
|
Vector3d vtExtr ; pCrv->GetExtrusion( vtExtr) ;
|
|
if ( vtExtr.IsSmall())
|
|
vtExtr = Z_AX ;
|
|
PtrOwner<CurveComposite> pCompo1( CreateBasicCurveComposite()) ;
|
|
if ( IsNull( pCompo1) || ! pCompo1->AddCurve( Release( pCurve)))
|
|
return nullptr ;
|
|
pCompo1->SetExtrusion( vtExtr) ;
|
|
// se distanza tra gli estremi minore di due volte il raggio la chiudo, purchè curva abbastanza lunga
|
|
Point3d ptStart, ptEnd, ptMid ;
|
|
Vector3d vtStart, vtEnd ;
|
|
pCompo1->GetStartPoint( ptStart) ;
|
|
pCompo1->GetStartDir( vtStart) ;
|
|
pCompo1->GetEndPoint( ptEnd) ;
|
|
pCompo1->GetEndDir( vtEnd) ;
|
|
pCompo1->GetMidPoint( ptMid) ;
|
|
if ( Dist( ptStart, ptEnd) <= 2 * dRadius && Dist( ptStart, ptMid) > 2 * dRadius && Dist( ptEnd, ptMid) > 2 * dRadius) {
|
|
double dAngEnd ; vtEnd.ToSpherical( nullptr, nullptr, &dAngEnd) ;
|
|
double dAngStart ; vtStart.ToSpherical( nullptr, nullptr, &dAngStart) ;
|
|
PtrOwner<ICurve> pClose( GetBiArc( ptEnd, dAngEnd, ptStart, dAngStart, 0.5)) ;
|
|
if ( ! IsNull( pClose))
|
|
pCompo1->AddCurve( Release( pClose)) ;
|
|
else
|
|
pCompo1->Close() ;
|
|
}
|
|
// tipo di offset
|
|
int nOffsType = ( bSquareMids ? ICurve::OFF_EXTEND : ICurve::OFF_FILLET) ;
|
|
// se curva chiusa
|
|
if ( pCompo1->IsClosed()) {
|
|
// fondo le curve allineate
|
|
pCompo1->MergeCurves( LIN_TOL_FINE, ANG_TOL_STD_DEG) ;
|
|
// ne faccio una copia e la inverto
|
|
PtrOwner<CurveComposite> pCompo2( pCompo1->Clone()) ;
|
|
if ( IsNull( pCompo2) || ! pCompo2->Invert())
|
|
return nullptr ;
|
|
// per creare la regione
|
|
SurfFlatRegionByContours SfrCntr( false, false) ;
|
|
// offset della prima curva a destra del raggio
|
|
OffsetCurve OffsCrv1 ;
|
|
if ( ! OffsCrv1.Make( pCompo1, dRadius, nOffsType))
|
|
return nullptr ;
|
|
ICurve* pOffs1 = OffsCrv1.GetLongerCurve() ;
|
|
if ( pOffs1 != nullptr)
|
|
SfrCntr.AddCurve( pOffs1) ;
|
|
// offset della seconda curva a destra del raggio (è invertita rispetto alla precedente)
|
|
OffsetCurve OffsCrv2 ;
|
|
if ( ! OffsCrv2.Make( pCompo2, dRadius, nOffsType))
|
|
return nullptr ;
|
|
ICurve* pOffs2 = OffsCrv2.GetLongerCurve() ;
|
|
if ( pOffs2 != nullptr)
|
|
SfrCntr.AddCurve( pOffs2) ;
|
|
// creo la regione
|
|
return SfrCntr.GetSurf() ;
|
|
}
|
|
// altrimenti
|
|
else {
|
|
// se richiesti estremi squadrati, la allungo del raggio alle due estremità
|
|
if ( bSquareEnds) {
|
|
pCompo1->ExtendStartByLen( dRadius) ;
|
|
pCompo1->ExtendEndByLen( dRadius) ;
|
|
}
|
|
// fondo le curve allineate
|
|
pCompo1->MergeCurves( LIN_TOL_FINE, ANG_TOL_STD_DEG) ;
|
|
// ne faccio una copia e la inverto
|
|
PtrOwner<CurveComposite> pCompo2( pCompo1->Clone()) ;
|
|
if ( IsNull( pCompo2) || ! pCompo2->Invert())
|
|
return nullptr ;
|
|
// offset della prima curva a destra del raggio
|
|
OffsetCurve OffsCrv1 ;
|
|
if ( ! OffsCrv1.Make( pCompo1, dRadius, nOffsType))
|
|
return nullptr ;
|
|
ICurve* pOffs1 = OffsCrv1.GetLongerCurve() ;
|
|
if ( pOffs1 != nullptr) {
|
|
pCompo1->Clear() ;
|
|
pCompo1->AddCurve( pOffs1) ;
|
|
}
|
|
// offset della seconda curva a destra del raggio
|
|
OffsetCurve OffsCrv2 ;
|
|
if ( ! OffsCrv2.Make( pCompo2, dRadius, nOffsType))
|
|
return nullptr ;
|
|
ICurve* pOffs2 = OffsCrv2.GetLongerCurve() ;
|
|
if ( pOffs2 != nullptr) {
|
|
pCompo2->Clear() ;
|
|
pCompo2->AddCurve( pOffs2) ;
|
|
}
|
|
// se estremi squadrati
|
|
if ( bSquareEnds) {
|
|
// aggiungo alla prima curva una linea che la unisca alla seconda
|
|
PtrOwner<CurveLine> pLine( CreateBasicCurveLine()) ;
|
|
Point3d ptEnd1, ptStart2 ;
|
|
if ( IsNull( pLine) ||
|
|
! pCompo1->GetEndPoint( ptEnd1) ||
|
|
! pCompo2->GetStartPoint( ptStart2) ||
|
|
! pLine->Set( ptEnd1, ptStart2) ||
|
|
! pCompo1->AddCurve( Release( pLine)))
|
|
return nullptr ;
|
|
// unisco le due curve composite e le chiudo
|
|
if ( ! pCompo1->AddCurve( Release( pCompo2)) || ! pCompo1->Close())
|
|
return nullptr ;
|
|
}
|
|
// altrimenti estremi arrotondati
|
|
else {
|
|
// aggiungo alla prima curva un arco che la unisca alla seconda
|
|
PtrOwner<CurveArc> pArc1( CreateBasicCurveArc()) ;
|
|
Point3d ptEnd1, ptStart2 ;
|
|
Vector3d vtEnd1, vtStart2 ;
|
|
if ( IsNull( pArc1) ||
|
|
! pCompo1->GetEndPoint( ptEnd1) ||
|
|
! pCompo1->GetEndDir( vtEnd1) ||
|
|
! pCompo2->GetStartPoint( ptStart2) ||
|
|
! pCompo2->GetStartDir( vtStart2))
|
|
return nullptr ;
|
|
// verifico se arco tangente alla prima o alla seconda curva
|
|
if ( AreSameVectorApprox( vtEnd1, vtEnd)) {
|
|
if ( ! pArc1->Set2PVN( ptEnd1, ptStart2, vtEnd1, vtExtr) ||
|
|
! pCompo1->AddCurve( Release( pArc1)))
|
|
return nullptr ;
|
|
}
|
|
else {
|
|
if ( ! pArc1->Set2PVN( ptStart2, ptEnd1, -vtStart2, vtExtr) ||
|
|
! pArc1->Invert() ||
|
|
! pCompo1->AddCurve( Release( pArc1)))
|
|
return nullptr ;
|
|
}
|
|
// aggiungo alla seconda curva un arco che la unisca alla prima
|
|
PtrOwner<CurveArc> pArc2( CreateBasicCurveArc()) ;
|
|
Point3d ptEnd2, ptStart1 ;
|
|
Vector3d vtEnd2, vtStart1 ;
|
|
if ( IsNull( pArc2) ||
|
|
! pCompo2->GetEndPoint( ptEnd2) ||
|
|
! pCompo2->GetEndDir( vtEnd2) ||
|
|
! pCompo1->GetStartPoint( ptStart1) ||
|
|
! pCompo1->GetStartDir( vtStart1))
|
|
return nullptr ;
|
|
// verifico se arco tangente alla seconda o alla prima curva
|
|
if ( AreOppositeVectorApprox( vtEnd2, vtStart)) {
|
|
if ( ! pArc2->Set2PVN( ptEnd2, ptStart1, vtEnd2, vtExtr) ||
|
|
! pCompo2->AddCurve( Release( pArc2)))
|
|
return nullptr ;
|
|
}
|
|
else {
|
|
if ( ! pArc2->Set2PVN( ptStart1, ptEnd2, -vtStart1, vtExtr) ||
|
|
! pArc2->Invert() ||
|
|
! pCompo2->AddCurve( Release( pArc2)))
|
|
return nullptr ;
|
|
}
|
|
// unisco le due curve composite
|
|
if ( ! pCompo1->AddCurve( Release( pCompo2)))
|
|
return nullptr ;
|
|
}
|
|
// creo la regione
|
|
SurfFlatRegionByContours SfrCntr( false, false) ;
|
|
SfrCntr.AddCurve( Release( pCompo1)) ;
|
|
return SfrCntr.GetSurf() ;
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
// Classe SurfFlatRegionByContours
|
|
//-------------------------------------------------------------------------------
|
|
SurfFlatRegionByContours::~SurfFlatRegionByContours(void)
|
|
{
|
|
// cancello eventuali curve rimaste
|
|
for ( auto& pCrv : m_vpCrv) {
|
|
if ( pCrv != nullptr)
|
|
delete pCrv ;
|
|
pCrv = nullptr ;
|
|
}
|
|
m_vpCrv.clear() ;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
bool
|
|
SurfFlatRegionByContours::AddCurve( ICurve* pCrv)
|
|
{
|
|
// acquisisco la curva
|
|
PtrOwner<ICurve> pMyCrv( pCrv) ;
|
|
if ( IsNull( pMyCrv) || ! pMyCrv->IsValid())
|
|
return false ;
|
|
// verifico sia chiusa
|
|
if ( ! pMyCrv->IsClosed())
|
|
return false ;
|
|
// la inserisco nel vettore delle curve
|
|
m_vpCrv.push_back( Release( pMyCrv)) ;
|
|
return true ;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
bool
|
|
SurfFlatRegionByContours::Prepare( void)
|
|
{
|
|
// calcolo piano medio e area delle curve
|
|
m_vArea.reserve( m_vpCrv.size()) ;
|
|
Vector3d vtN0 ;
|
|
for ( int i = 0 ; i < int( m_vpCrv.size()) ; ++ i) {
|
|
// calcolo piano medio e area
|
|
Plane3d plPlane ;
|
|
double dArea ;
|
|
if ( ! m_vpCrv[i]->GetArea( plPlane, dArea))
|
|
return false ;
|
|
// imposto la normale del primo contorno come riferimento
|
|
if ( i == 0)
|
|
vtN0 = plPlane.GetVersN() ;
|
|
// verifico che le normali siano molto vicine
|
|
if ( ! AreSameOrOppositeVectorApprox( plPlane.GetVersN(), vtN0))
|
|
return false ;
|
|
// assegno il segno all'area secondo il verso della normale
|
|
if ( ( plPlane.GetVersN() * vtN0) > 0)
|
|
m_vArea.emplace_back( i, dArea) ;
|
|
else
|
|
m_vArea.emplace_back( i, - dArea) ;
|
|
}
|
|
// ordino in senso decrescente sull'area
|
|
sort( m_vArea.begin(), m_vArea.end(),
|
|
[]( const INDAREA& a, const INDAREA& b) { return ( abs( a.second) > abs( b.second)) ; }) ;
|
|
return true ;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
ISurfFlatRegion*
|
|
SurfFlatRegionByContours::GetSurf( void)
|
|
{
|
|
// se è la prima superficie, devo preparare
|
|
if ( m_bFirst) {
|
|
if ( ! Prepare())
|
|
return nullptr ;
|
|
m_bFirst = false ;
|
|
}
|
|
// altrimenti, se ammessa una sola superficie errore
|
|
else if ( ! m_bAllowedMore) {
|
|
return nullptr ;
|
|
}
|
|
// creo la superficie
|
|
PtrOwner<SurfFlatRegion> pSfr( CreateBasicSurfFlatRegion()) ;
|
|
if ( IsNull( pSfr))
|
|
return nullptr ;
|
|
// aggiungo le diverse curve
|
|
bool bFirstCrv ;
|
|
do {
|
|
bFirstCrv = true ;
|
|
for ( int i = 0 ; i < int( m_vArea.size()) ; ++ i) {
|
|
// recupero indice di percorso e verifico sia valido
|
|
int j = m_vArea[i].first ;
|
|
if ( j < 0)
|
|
continue ;
|
|
// la prima deve essere il loop esterno
|
|
if ( bFirstCrv) {
|
|
// ne faccio una copia
|
|
PtrOwner<ICurve> pCrv( m_vpCrv[j]->Clone()) ;
|
|
if ( IsNull( pCrv)) {
|
|
m_vArea[i].first = - 1 ;
|
|
continue ;
|
|
}
|
|
// provo a inserirla
|
|
if ( pSfr->AddExtLoop( Release( pCrv))) {
|
|
bFirstCrv = false ;
|
|
delete m_vpCrv[j] ;
|
|
m_vpCrv[j] = nullptr ;
|
|
m_vArea[i].first = - 1 ;
|
|
}
|
|
}
|
|
// gli altri sono loop interni
|
|
else {
|
|
// ne faccio una copia
|
|
PtrOwner<ICurve> pCrv( m_vpCrv[j]->Clone()) ;
|
|
if ( IsNull( pCrv)) {
|
|
m_vArea[i].first = - 1 ;
|
|
continue ;
|
|
}
|
|
// provo a inserirla
|
|
if ( pSfr->AddIntLoop( Release( pCrv))) {
|
|
delete m_vpCrv[j] ;
|
|
m_vpCrv[j] = nullptr ;
|
|
m_vArea[i].first = - 1 ;
|
|
}
|
|
}
|
|
}
|
|
} while ( m_bAllowedMultiChunk && ! bFirstCrv) ;
|
|
// se non valida, errore
|
|
if ( ! pSfr->IsValid())
|
|
return nullptr ;
|
|
// restituisco la superficie
|
|
return Release( pSfr) ;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
bool
|
|
SurfFlatRegionByContours::AllCurvesUsed( void)
|
|
{
|
|
// verifico se sono rimaste delle curve
|
|
for ( auto& pCrv : m_vpCrv) {
|
|
if ( pCrv != nullptr)
|
|
return false ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
bool
|
|
SurfFlatRegionByContours::GetUnusedCurveTempProps( INTVECTOR& vId)
|
|
{
|
|
vId.clear() ;
|
|
// verifico se sono rimaste delle curve
|
|
for ( auto& pCrv : m_vpCrv) {
|
|
if ( pCrv != nullptr)
|
|
vId.push_back( pCrv->GetTempProp()) ;
|
|
}
|
|
return ( ! vId.empty()) ;
|
|
} |