//---------------------------------------------------------------------------- // EgalTech 2013-2013 //---------------------------------------------------------------------------- // File : OffsetAux.cpp Data : 23.11.23 Versione : 2.5k5 // Contenuto : Implementazione di alcune funzioni di utilità per gli offset delle curve. // // // // Modifiche : 23.11.23 SP Creazione modulo spostando alcune funzioni da OffsetCurve.cpp. // // //---------------------------------------------------------------------------- #include "stdafx.h" #include "OffsetAux.h" #include "CurveArc.h" #include "CurveLine.h" #include "GeoConst.h" #include "/EgtDev/Include/EGkIntervals.h" #include "/EgtDev/Include/EGkIntersCurves.h" #include "/EgtDev/Include/EGkChainCurves.h" using namespace std ; //---------------------------------------------------------------------------- static bool IsFillet( const ICurve* pCrv, double dDist) ; static bool ModifyFillet( ICurve* pCrv, double dDist, int nType, ICurveComposite& ccAux) ; static bool AdjustIntersections( ICRVCOMPOPVECTOR& CrvList) ; //---------------------------------------------------------------------------- bool IdentifyFillets( ICurveComposite* pCrvCo, double dDist) { // identifico le sottocurve di tipo fillet e assegno loro temp param 1.0 per riconoscerle nella funzione AdjustCurveFillets for ( int i = 0 ; i < pCrvCo->GetCurveCount() ; i ++) { if ( IsFillet( pCrvCo->GetCurve( i), dDist)) pCrvCo->SetCurveTempParam( i, 1.0) ; else pCrvCo->SetCurveTempParam( i, 0.0) ; } return true ; } //---------------------------------------------------------------------------- bool IsFillet( const ICurve* pCrv, double dDist) { if ( pCrv == nullptr) return false ; // deve essere un arco if ( pCrv->GetType() != CRV_ARC) return false ; const CurveArc* pArc = GetBasicCurveArc( pCrv) ; // deve avere raggio uguale alla distanza di offset if ( abs( pArc->GetRadius() - abs( dDist)) > EPS_SMALL) return false ; // deve essere CCW se offset a destra e CW se offset a sinistra return ( pArc->GetAngCenter() * dDist > 0) ; } //---------------------------------------------------------------------------- bool AdjustCurveFillets( ICURVEPOVECTOR& vOffset, double dDist, int nType) { if ( vOffset.empty()) return true ; // suddivido le curve di offset individuando i fillet e isolandoli dagli altri tratti ICRVCOMPOPVECTOR vCrvs ; for ( int i = 0 ; i < int( vOffset.size()) ; i ++) { CurveComposite* pCompo = GetBasicCurveComposite( vOffset[i]) ; if ( pCompo == nullptr) return false ; bool bNewCrv = true ; PtrOwner pCrv( pCompo->RemoveFirstOrLastCurve(false)) ; while ( ! IsNull( pCrv)) { if ( pCrv->GetTempParam() > EPS_SMALL) { // se fillet calcolo il nuovo raccordo CurveComposite* ccTemp = CreateBasicCurveComposite() ; ModifyFillet( pCrv, dDist, nType, *ccTemp) ; // assegno temp param per identificarlo nei conti successivi ccTemp->SetTempParam( 1) ; vCrvs.push_back( ccTemp) ; bNewCrv = true ; } else { // aggiungo la curva if ( bNewCrv) { bNewCrv = false ; CurveComposite* pCompo = ConvertCurveToBasicComposite( Release( pCrv)) ; if ( pCompo == nullptr) return false ; vCrvs.push_back( pCompo) ; } else vCrvs.back()->AddCurve( Release( pCrv)) ; } // passo alla curva successiva pCrv.Set( pCompo->RemoveFirstOrLastCurve( false)) ; } } vOffset.clear() ; // gestione delle intersezioni if ( ! AdjustIntersections( vCrvs)) return false ; // concateno i tratti ottenuti ChainCurves ChainCrv ; ChainCrv.Init( false, 2 * EPS_SMALL, vCrvs.size()) ; for ( int i = 0 ; i < int( vCrvs.size()); ++ i) { Point3d ptS, ptE ; Vector3d vtS, vtE ; vCrvs[i]->GetStartPoint( ptS) ; vCrvs[i]->GetEndPoint( ptE) ; vCrvs[i]->GetStartDir( vtS) ; vCrvs[i]->GetEndDir( vtE) ; ChainCrv.AddCurve( i + 1, ptS, vtS, ptE, vtE) ; } // recupero i concatenamenti Point3d ptRef ; vCrvs[0]->GetStartPoint( ptRef) ; INTVECTOR vIds ; while ( ChainCrv.GetChainFromNear( ptRef, false, vIds)) { PtrOwner pCompo( CreateBasicCurveComposite()) ; if ( IsNull( pCompo)) return false ; for ( auto i : vIds) pCompo->AddCurve( vCrvs[i-1]) ; pCompo->MergeCurves( LIN_TOL_MIN, ANG_TOL_STD_DEG) ; pCompo->GetEndPoint( ptRef) ; vOffset.emplace_back( Release( pCompo)) ; } return true ; } //---------------------------------------------------------------------------- bool ModifyFillet( ICurve* pCrv, double dDist, int nType, ICurveComposite& ccAux) { // la curva deve essere un arco CurveArc* pArc = GetBasicCurveArc( pCrv) ; if ( pArc == nullptr) return false ; // angolo al centro dell'arco double dAngDeg = pArc->GetAngCenter() ; // elimino dal tipo le parti estranee all'angolo esterno nType &= ( ICurve::OFF_FILLET | ICurve::OFF_CHAMFER | ICurve::OFF_EXTEND) ; // se l'angolo esterno supera il retto, offset extend diventa offset chamfer if ( nType == ICurve::OFF_EXTEND && abs( dAngDeg) > ANG_RIGHT + EPS_ANG_SMALL) nType = ICurve::OFF_CHAMFER ; // se angolo esterno molto piccolo, semplifico tutto const double SMALL_EXT_ANG = 1.0 ; bool bAngSmall = ( abs( dAngDeg) < SMALL_EXT_ANG) ; if ( bAngSmall) nType = ICurve::OFF_EXTEND ; switch ( nType) { case ICurve::OFF_CHAMFER : { // lunghezza aggiuntiva in tangenza double dLen = abs( dDist) * tan( abs( dAngDeg) / 4 * DEGTORAD) ; // punti di costruzione smusso Point3d ptP1, ptP1a, ptP2a, ptP2 ; if ( ! pArc->GetStartPoint( ptP1) || ! pArc->GetEndPoint( ptP2)) return false ; Vector3d vtDir1, vtDir2 ; if ( ! pArc->GetStartDir( vtDir1) || ! pArc->GetEndDir( vtDir2)) return false ; ptP1a = ptP1 + vtDir1 * dLen ; ptP2a = ptP2 - vtDir2 * dLen ; // aggiungo una nuova linea PtrOwner pLine1( CreateBasicCurveLine()) ; if ( IsNull( pLine1) || ! pLine1->Set( ptP1, ptP1a)) return false ; if ( ! ccAux.AddCurve( Release( pLine1))) return false ; // tratto intermedio PtrOwner pLine2( CreateBasicCurveLine()) ; if ( IsNull( pLine2) || ! pLine2->Set( ptP1a, ptP2a)) return false ; if ( ! ccAux.AddCurve( Release( pLine2))) return false ; // aggiungo una nuova linea PtrOwner pLine3( CreateBasicCurveLine()) ; if ( IsNull( pLine3) || ! pLine3->Set( ptP2a, ptP2)) return false ; if ( ! ccAux.AddCurve( Release( pLine3))) return false ; return true ; } break ; case ICurve::OFF_EXTEND : { // lunghezza aggiuntiva in tangenza double dLen = abs( dDist) * tan( abs( dAngDeg) / 2 * DEGTORAD) ; // punti di costruzione estensione Point3d ptP1, ptPc, ptP2 ; if ( ! pArc->GetStartPoint( ptP1) || ! pArc->GetEndPoint( ptP2)) return false ; Vector3d vtDir1, vtDir2 ; if ( ! pArc->GetStartDir( vtDir1) || ! pArc->GetEndDir( vtDir2)) return false ; ptPc = ptP1 + vtDir1 * dLen ; // aggiungo una nuova linea PtrOwner pLine1( CreateBasicCurveLine()) ; if ( IsNull( pLine1) || ! pLine1->Set( ptP1, ptPc)) return false ; if ( ! ccAux.AddCurve( Release( pLine1))) return false ; // aggiungo una nuova linea PtrOwner pLine2( CreateBasicCurveLine()) ; if ( IsNull( pLine2) || ! pLine2->Set( ptPc, ptP2)) return false ; if ( ! ccAux.AddCurve( Release( pLine2))) return false ; return true ; } } return false ; } //---------------------------------------------------------------------------- bool AdjustIntersections( ICRVCOMPOPVECTOR& vCrvs) { // sistema le curve nel vettore vCrvs eliminando le parti coinvolte nelle intersezioni vector vIntervals( vCrvs.size()) ; INTVECTOR vFillets ; for ( int i = 0 ; i < int( vCrvs.size()) ; i ++) { // salvo i parametri della curva double dParS, dParE ; vCrvs[i]->GetDomain( dParS, dParE) ; vIntervals[i].Set( dParS, dParE) ; // verifico se raccordo if ( vCrvs[i]->GetTempParam() > EPS_SMALL) vFillets.emplace_back( i) ; } // verifico se i raccordi intersecano le altre curve bool bInters = false ; for ( int i = 0 ; i < int( vFillets.size()) ; i ++) { int nIdx = vFillets[i] ; for ( int j = 0 ; j < int( vCrvs.size()) ; j ++) { if ( j == nIdx) continue ; IntersCurveCurve intCC( *vCrvs[nIdx], *vCrvs[j]) ; int nCnt = intCC.GetIntersCount() ; if ( nCnt > 1) { // aggiorno gli intervalli della curva sottraendo la parte coinvolta dall'intersezione for ( int k = 0 ; k < nCnt - 1 ; k = k+2) { IntCrvCrvInfo iccInfo1, iccInfo2 ; intCC.GetIntCrvCrvInfo( k, iccInfo1) ; // verifico non sia intersezione nell'estremo iniziale o sovrapposizione if ( iccInfo1.IciA[0].dU < EPS_SMALL || iccInfo1.bOverlap) { k-- ; continue ; } intCC.GetIntCrvCrvInfo( k+1, iccInfo2) ; vIntervals[nIdx].Subtract( iccInfo1.IciA[0].dU, iccInfo2.IciA[0].dU) ; vIntervals[j].Subtract( iccInfo1.IciB[0].dU, iccInfo2.IciB[0].dU) ; bInters = true ; } } } } if ( ! bInters) return true ; // aggiorno le curve eliminando i tratti coinvolti nelle intersezioni for ( int i = 0 ; i < int( vIntervals.size()) ; i++) { if ( vIntervals[i].GetCount() > 1) { PtrOwner pCompo( CloneBasicCurveComposite( vCrvs[i])) ; if ( IsNull( pCompo)) return false ; double dParS, dParE ; vIntervals[i].GetFirst( dParS, dParE) ; vCrvs[i]->TrimStartEndAtParam( dParS, dParE) ; while ( vIntervals[i].GetNext( dParS, dParE)) { CurveComposite* pCrv = ConvertCurveToBasicComposite( pCompo->CopyParamRange( dParS, dParE)) ; if ( pCrv == nullptr) return false ; vCrvs.emplace_back( pCrv) ; } } else { double dParS, dParE ; vIntervals[i].GetFirst( dParS, dParE) ; vCrvs[i]->TrimStartEndAtParam( dParS, dParE) ; } } return true ; }