ea87db1ae1
- negli offset gestite autointersezioni per raccordi chamfer ed extend.
302 lines
11 KiB
C++
302 lines
11 KiB
C++
//----------------------------------------------------------------------------
|
|
// 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<ICurve> 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<CurveComposite> 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<CurveLine> pLine1( CreateBasicCurveLine()) ;
|
|
if ( IsNull( pLine1) || ! pLine1->Set( ptP1, ptP1a))
|
|
return false ;
|
|
if ( ! ccAux.AddCurve( Release( pLine1)))
|
|
return false ;
|
|
// tratto intermedio
|
|
PtrOwner<CurveLine> pLine2( CreateBasicCurveLine()) ;
|
|
if ( IsNull( pLine2) || ! pLine2->Set( ptP1a, ptP2a))
|
|
return false ;
|
|
if ( ! ccAux.AddCurve( Release( pLine2)))
|
|
return false ;
|
|
// aggiungo una nuova linea
|
|
PtrOwner<CurveLine> 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<CurveLine> pLine1( CreateBasicCurveLine()) ;
|
|
if ( IsNull( pLine1) || ! pLine1->Set( ptP1, ptPc))
|
|
return false ;
|
|
if ( ! ccAux.AddCurve( Release( pLine1)))
|
|
return false ;
|
|
// aggiungo una nuova linea
|
|
PtrOwner<CurveLine> 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<Intervals> 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<CurveComposite> 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 ;
|
|
}
|