//---------------------------------------------------------------------------- // 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 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 pCC( CreateBasicCurveComposite()) ; if ( IsNull( pCC) || ! pCC->FromPolyLine( PL)) return nullptr ; // creo il rettangolo PtrOwner 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 ( fabs( 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 pCC( CreateBasicCurveComposite()) ; if ( IsNull( pCC) || ! pCC->FromPolyArc( PA)) return nullptr ; // creo il rettangolo PtrOwner 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 pArc( CreateBasicCurveArc()) ; if ( IsNull( pArc)) return nullptr ; pArc->Set( ORIG, Z_AX, dRadius, X_AX, ANG_FULL, 0) ; // creo il disco PtrOwner 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 pCurve( pCrv) ; if ( IsNull( pCurve)) return nullptr ; // la inserisco in una curva composita PtrOwner pCompo1( CreateBasicCurveComposite()) ; if ( IsNull( pCompo1) || ! pCompo1->AddCurve( Release( pCurve))) return nullptr ; // 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 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 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 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 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 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, Z_AX) || ! pCompo1->AddCurve( Release( pArc1))) return nullptr ; } else { if ( ! pArc1->Set2PVN( ptStart2, ptEnd1, -vtStart2, Z_AX) || ! pArc1->Invert() || ! pCompo1->AddCurve( Release( pArc1))) return nullptr ; } // aggiungo alla seconda curva un arco che la unisca alla prima PtrOwner 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, Z_AX) || ! pCompo2->AddCurve( Release( pArc2))) return nullptr ; } else { if ( ! pArc2->Set2PVN( ptStart1, ptEnd2, -vtStart1, Z_AX) || ! 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 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 ( fabs( a.second) > fabs( 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 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 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 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()) ; }