EgtGeomKernel :

- in CalcPocketing aggiunta lavorazione CONFORMAL_ZIGZAG
- migliorie varie.
This commit is contained in:
Riccardo Elitropi
2024-07-30 14:01:17 +02:00
parent 1261de4dbb
commit df10b45c6b
+600 -67
View File
@@ -71,6 +71,7 @@ struct PocketParams {
bool bAllClosed = true ; // flag per indicare se tutti i bordi sono chiusi
double dOffsExtra = 2. ; // Offset aggiuntivo per percosi a ZigZag/OneWay se richieste le curve di bordo
Frame3d frLocXY ; // frame per conti nel piano XY
int nOffsType = ICurve::OFF_FILLET ; // tipologia di Offset per estensione degli aperti
} ;
static double TOL_TRAPEZOID = 50 * EPS_SMALL ; // tolleranza per casi a trapezio SpiralPocket
@@ -724,6 +725,62 @@ AssignFeedSpiralOpt( const int nOptType, const PocketParams& PockParams, ICurveC
return true ;
}
//----------------------------------------------------------------------------
static bool
AssignFeedConformalZigZag( ICurveComposite* pCompoPath, const ICurveComposite* pCrvLoop,
const PocketParams& PockParams)
{
// controllo dei parametri
if ( pCompoPath == nullptr || ! pCompoPath->IsValid())
return false ;
// controllo se il Flag per assegnare la Feed è attivo
if ( ! PockParams.bCalcFeed)
return AssignMaxFeed( pCompoPath, PockParams) ;
// imposto di Default la Feed minima per ogni sottocurva
AssignMinFeed( pCompoPath, PockParams) ;
// creo la superficie rimossa ( creata con il raggio utensile)
// creo la superficie di classificazione ( creata mediante raggio utensile e SideStep)
// creo la curva da restituire con le Feed Assegnate
PtrOwner<ISurfFlatRegion> pSfrRemoved( CreateSurfFlatRegion()) ;
PtrOwner<ISurfFlatRegion> pSfrClass( CreateSurfFlatRegion()) ;
PtrOwner<ICurveComposite> pCompoPathWithFeed( CreateCurveComposite()) ;
if ( IsNull( pSfrRemoved) || IsNull( pSfrClass) || IsNull( pCompoPathWithFeed))
return false ;
ICRVCOMPOPOVECTOR vCrvEmpty ;
// scorro tutte le curve del percorso
for ( int i = 0 ; i < pCompoPath->GetCurveCount() ; ++ i) {
// recupero la singola curva come composita
PtrOwner<ICurveComposite> pSingleCompo( ConvertCurveToComposite( pCompoPath->GetCurve( i)->Clone())) ;
if ( IsNull( pSingleCompo) || ! pSingleCompo->IsValid())
return false ;
// calcolo la Feed per tale curva
AssignFeedSpiral( pSingleCompo, pSfrClass, false, vCrvEmpty, pCrvLoop, PockParams, 2 * PockParams.dRad / 3) ;
// aggiorno la regione svuotata dal Tool
PtrOwner<ISurfFlatRegion> pSfrSingleCompo( GetSurfFlatRegionFromFatCurve( pSingleCompo->Clone(), PockParams.dRad + 5 * EPS_SMALL, false, false)) ;
if ( ! IsNull( pSfrSingleCompo) || ! pSfrSingleCompo->IsValid()) {
if ( ! pSfrClass->IsValid())
pSfrClass->CopyFrom( pSfrSingleCompo) ;
else
pSfrClass->Add( *pSfrSingleCompo) ;
}
if ( ! pCompoPathWithFeed->AddCurve( Release( pSingleCompo)))
return false ;
}
// restituisco la curva se valida
if ( pCompoPathWithFeed->IsValid())
pCompoPath->CopyFrom( pCompoPathWithFeed) ;
return true ;
}
//----------------------------------------------------------------------------
static bool
ResetCurveTempProps( ICurveComposite* pCrvCompo)
@@ -1026,7 +1083,7 @@ ExtendPath( ICurveComposite* pCompo, const ISurfFlatRegion* pSfr, const PocketPa
pCompo->AddLine( ptFall, bEndOrStart) ;
pCompo->SetCurveTempProp( ( bEndOrStart ? pCompo->GetCurveCount() - 1 : 0), TEMP_PROP_OUT_START, 0) ;
pCompo->SetCurveTempParam( ( bEndOrStart ? pCompo->GetCurveCount() - 1 : 0),
( bEndOrStart ? GetMaxFeed( PockParams) : GetMinFeed( PockParams), 0)) ;
( bEndOrStart ? GetMaxFeed( PockParams) : GetMinFeed( PockParams)), 0) ;
bOkExtended = true ;
return true ;
}
@@ -1231,8 +1288,9 @@ GetHomogeneousParts( ICurveComposite* pCrvCompo, const PocketParams& PockParams,
//---------------------------------------------------------------------------
static bool
CreateSurfFrIncidence( const ICurveComposite* pCrv, const Vector3d& vtTanS_, const Vector3d& vtTanE_,
const double dRad, ISurfFlatRegion* pSfrInc)
CreateSurfFrIncidence( const ICurveComposite* pCrv, const PocketParams& PockParams,
const Vector3d& vtTanS_, const Vector3d& vtTanE_, const double dRad,
ISurfFlatRegion* pSfrInc)
{
// controllo dei parametri
if ( pCrv == nullptr || ! pCrv->IsValid())
@@ -1252,7 +1310,7 @@ CreateSurfFrIncidence( const ICurveComposite* pCrv, const Vector3d& vtTanS_, con
OffsetCurve OffsCrv ;
PtrOwner<ICurve> pOffsExt( CreateCurveComposite()) ;
if ( IsNull( pOffsExt) ||
! OffsCrv.Make( pCrv, dRad, ICurve::OFF_FILLET) ||
! OffsCrv.Make( pCrv, dRad, PockParams.nOffsType) ||
! pOffsExt.Set( OffsCrv.GetLongerCurve()) ||
IsNull( pOffsExt))
return false ;
@@ -1261,7 +1319,7 @@ CreateSurfFrIncidence( const ICurveComposite* pCrv, const Vector3d& vtTanS_, con
PtrOwner<ICurve> pOffsInt( CreateCurveComposite()) ;
if ( IsNull( pOffsInt))
return false ;
if ( OffsCrv.Make( pCrv, - dRad, ICurve::OFF_FILLET)) {
if ( OffsCrv.Make( pCrv, - dRad, PockParams.nOffsType)) {
PtrOwner<ICurve> pMyCrv( OffsCrv.GetLongerCurve()) ;
if ( ! IsNull( pMyCrv) && pMyCrv->IsValid())
pOffsInt.Set( pMyCrv) ;
@@ -1336,7 +1394,7 @@ AdjustOpenEdge( const ICurveComposite* pCrvCompo, const ICRVCOMPOPOVECTOR& vCrvI
// definisco la regione di incidenza
PtrOwner<ISurfFlatRegion> pSfrInc( CreateSurfFlatRegion()) ;
if ( IsNull( pSfrInc) ||
! CreateSurfFrIncidence( pCrvBorder, vtTanS, vtTanE, dRad + 75 * EPS_SMALL, pSfrInc))
! CreateSurfFrIncidence( pCrvBorder, PockParams, vtTanS, vtTanE, dRad + 75 * EPS_SMALL, pSfrInc))
return false ;
// creo un vettore con tutte le curve che potrebbero cadere, in parte, nella regione di incidenza
@@ -1376,13 +1434,15 @@ AdjustOpenEdge( const ICurveComposite* pCrvCompo, const ICRVCOMPOPOVECTOR& vCrvI
continue ;
// 4) effettuo l'Offset della curva di metà dDiamJ
OffsetCurve OffsCrv ;
if ( ! OffsCrv.Make( vpCrvs[cl], - dDiamJ * 0.5 - 20 * EPS_SMALL, ICurve::OFF_FILLET))
if ( ! OffsCrv.Make( vpCrvs[cl], - dDiamJ * 0.5 - 20 * EPS_SMALL, PockParams.nOffsType))
return false ;
// 5) scorro tutte le curve di Offset che si sono formate, prendendo sempre la più lunga tra le rimanenti
PtrOwner<ICurve> pOffLongestCrv( OffsCrv.GetLongerCurve()) ;
while ( ! IsNull( pOffLongestCrv)) {
// 6) creo la regione di incidenza di tale curva ( "Curva a fagiolo")
PtrOwner<ISurfFlatRegion> pSfrBean( GetSurfFlatRegionFromFatCurve( Release( pOffLongestCrv), dDiamJ * 0.5, false, false)) ;
bool bSquareEnds = ( PockParams.nOffsType == ICurve::OFF_CHAMFER) ;
bool bSquareMids = ( PockParams.nOffsType == ICurve::OFF_CHAMFER) ;
PtrOwner<ISurfFlatRegion> pSfrBean( GetSurfFlatRegionFromFatCurve( Release( pOffLongestCrv), dDiamJ * 0.5, bSquareEnds, bSquareMids)) ;
if ( IsNull( pSfrBean) || ! pSfrBean->IsValid())
return false ;
// inverto se necessario
@@ -1585,6 +1645,10 @@ AdjustContourWithOpenEdges( ICurveComposite* pCrvCompo, ICRVCOMPOPOVECTOR& vCrvI
if ( PockParams.bAllowZigZagOneWayBorders &&
( PockParams.nType == POCKET_ZIGZAG || PockParams.nType == POCKET_ONEWAY))
dRad += PockParams.dOffsExtra ;
// se lavorazione a ZigZag con smusso, esco di Step/2 per pulire gli aperti
if ( PockParams.nType == POCKET_ZIGZAG && PockParams.bSmooth)
dRad += max( PockParams.dSideStep / 2, PockParams.dRad / 8) ;
// ricavo i tratti omogenei
ICRVCOMPOPOVECTOR vpCrvs ;
@@ -2026,6 +2090,9 @@ ModifySurfByOpenEdges( ISurfFlatRegion* pSfr, PocketParams& PockParams, ICRVCOMP
++ nChunkOneCurve ;
continue ;
}
// controllo se la lavorazione ammatte estensione da aperti
if ( PockParams.nType == POCKET_CONFORMAL_ZIGZAG)
continue ;
// vettore delle isole che userò ( le isole aperte piccole sono trascurate)
ICRVCOMPOPOVECTOR vCrvToTIsland ;
@@ -5950,7 +6017,7 @@ CreateSpiralPocketingPath( ICRVCOMPOPOVECTOR& vOffs, ICURVEPOVECTOR& vLinks, con
//----------------------------------------------------------------------------
static bool
CheckIfOffsetIsNecessary( const ICurveComposite* pCrvOffs, const double dOffs, const int nOffsCount,
CheckIfOffsetIsNecessary( const ICurveComposite* pCrvOffs, const double dOffs,
const int nIter, const PocketParams& PockParams, bool& bInsert)
{
@@ -5964,73 +6031,534 @@ CheckIfOffsetIsNecessary( const ICurveComposite* pCrvOffs, const double dOffs, c
return true ;
if ( nIter != 0) { // controllo se sono almeno al secondo offset...
// per ogni curva controllo se il controOffset + 5 * EPS_SMALL genera una regione ...
OffsetCurve OffsCrv ; // considero anche i casi in cui ho bSmallRad
if ( OffsCrv.Make( pCrvOffs, - PockParams.dRad + dOffs - 5 * EPS_SMALL , ICurve::OFF_FILLET)) {
// se questa curva sparisce -> non serve inserirla come offset, non svuota parti aggiuntive
if ( OffsCrv.GetCurveCount() == 0) {
bInsert = false ;
return true ;
}
}
else
return true ;
// controllo se richista ottimizzazione per Offsets mediante centroidi e medial Axis
if ( ! PockParams.bOptOffsetsAdv || OffsCrv.GetCurveCount() > 1)
return true ;
PtrOwner<ICurve> pCrvOffLonger( OffsCrv.GetLongerCurve()) ;
if ( IsNull( pCrvOffLonger) || ! pCrvOffLonger->IsValid())
return true ;
// Immagine del tool con centro nel centroide della zona da svuotare
Point3d ptC ; pCrvOffLonger->GetCentroid( ptC) ;
PtrOwner<ICurveArc> pCrvTool( CreateCurveArc()) ;
if( IsNull( pCrvTool))
// per ogni curva controllo se il suo Offset massimo non genera alcuna regione
double dMaxOffs ;
if ( ! CalcCurveLimitOffset( *pCrvOffs, dMaxOffs))
return false ;
pCrvTool->SetXY( ptC, PockParams.dRad - 5 * EPS_SMALL) ;
CRVCVECTOR ccClass ;
IntersCurveCurve intCC( *pCrvOffLonger, *pCrvTool) ;
intCC.GetCurveClassification( 1, EPS_SMALL, ccClass) ;
if ( int(ccClass.size()) == 1 && ccClass[0].nClass == CRVC_OUT) {
// centroide
// se questa curva sparisce -> non serve inserirla come offset, non svuota parti aggiuntive
if ( dMaxOffs < PockParams.dRad - dOffs + 5 * EPS_SMALL) {
bInsert = false ;
return true ;
}
}
else
return true ;
// recupero la PolyLine per altezza e lunghezza del Box2D ( rettangolo)
PolyLine pl ;
if ( ! pCrvOffLonger->ApproxWithLines( 100 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_STD, pl))
return true ;
Vector3d vtX ;
double dLen = 0 ; double dHeight = 0 ;
if ( ! pl.GetMinAreaRectangleXY( ptC, vtX, dLen, dHeight))
return true ;
// se non richiesto percorso avanzato
if ( ! PockParams.bOptOffsetsAdv)
return true ;
// frame locale, recupero DimX e DimY
Frame3d frLoc ; frLoc.Set( ptC, Z_AX, vtX) ;
if ( ! frLoc.IsValid())
return true ;
BBox3d bBox ;
frLoc.Invert() ;
pCrvOffLonger->GetBBox( frLoc, bBox) ;
double dDimX = bBox.GetDimX() ;
double dDimY = bBox.GetDimY() ;
OffsetCurve OffsCrv ; // considero anche i casi in cui ho bSmallRad
if ( ! OffsCrv.Make( pCrvOffs, - PockParams.dRad + dOffs - 5 * EPS_SMALL , ICurve::OFF_FILLET))
return false ;
// se dimensioni accettabili, inserisco
if ( dDimX < 2 * PockParams.dRad - 100 * EPS_SMALL ||
dDimY < 2 * 2 * PockParams.dRad - 100 * EPS_SMALL) {
bInsert = false ;
return true ;
}
// controllo se richista ottimizzazione per Offsets mediante centroidi e medial Axis
if ( OffsCrv.GetCurveCount() > 1)
return true ;
PtrOwner<ICurve> pCrvOffLonger( OffsCrv.GetLongerCurve()) ;
if ( IsNull( pCrvOffLonger) || ! pCrvOffLonger->IsValid())
return true ;
// Immagine del tool con centro nel centroide della zona da svuotare
Point3d ptC ; pCrvOffLonger->GetCentroid( ptC) ;
PtrOwner<ICurveArc> pCrvTool( CreateCurveArc()) ;
if( IsNull( pCrvTool))
return false ;
pCrvTool->SetXY( ptC, PockParams.dRad - 5 * EPS_SMALL) ;
CRVCVECTOR ccClass ;
IntersCurveCurve intCC( *pCrvOffLonger, *pCrvTool) ;
intCC.GetCurveClassification( 1, EPS_SMALL, ccClass) ;
if ( int(ccClass.size()) == 1 && ccClass[0].nClass == CRVC_OUT) {
// centroide
bInsert = false ;
return true ;
}
// recupero la PolyLine per altezza e lunghezza del Box2D ( rettangolo)
PolyLine pl ;
if ( ! pCrvOffLonger->ApproxWithLines( 100 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_STD, pl))
return true ;
Vector3d vtX ;
double dLen = 0 ; double dHeight = 0 ;
if ( ! pl.GetMinAreaRectangleXY( ptC, vtX, dLen, dHeight))
return true ;
// frame locale, recupero DimX e DimY
Frame3d frLoc ; frLoc.Set( ptC, Z_AX, vtX) ;
if ( ! frLoc.IsValid())
return true ;
BBox3d bBox ;
frLoc.Invert() ;
pCrvOffLonger->GetBBox( frLoc, bBox) ;
double dDimX = bBox.GetDimX() ;
double dDimY = bBox.GetDimY() ;
// se dimensioni accettabili, inserisco
if ( dDimX < 2 * PockParams.dRad - 100 * EPS_SMALL ||
dDimY < 2 * 2 * PockParams.dRad - 100 * EPS_SMALL) {
bInsert = false ;
return true ;
}
return true ;
}
//----------------------------------------------------------------------------
static bool
ExtendGuideByIteration( ICurveComposite* pCompoTempGuide, const ICurveComposite* pCompoPerimeter,
bool bInverted)
{
// controllo dei parametri
if ( pCompoTempGuide == nullptr || ! pCompoTempGuide->IsValid() ||
pCompoPerimeter == nullptr || ! pCompoPerimeter->IsValid())
return false ;
const double EXTENSION_VAL = 1000. ;
// ricavo il punto finale della guida
Point3d ptEndGuide ; pCompoTempGuide->GetEndPoint( ptEndGuide) ;
// direzione finale della guida
Vector3d vtEndGuide ; pCompoTempGuide->GetEndDir( vtEndGuide) ;
// creo un segmento diretto come il chiuso
PtrOwner<ICurveLine> pSeg( CreateCurveLine()) ;
if ( IsNull( pSeg) ||
! pSeg->Set( ptEndGuide, ptEndGuide + EXTENSION_VAL * vtEndGuide))
return false ;
// calcolo l'intersezione tra questo segmento e la curva di perimetro aperta
IntersCurveCurve ICC( *pSeg, *pCompoPerimeter) ;
// se l'unica intersezione è il punto iniziale del segmento, allora non estendo la guida
// ( vale anche nel caso di intersezione con Overlap)
if ( ICC.GetIntersCount() == 1) {
IntCrvCrvInfo aInfo ;
if ( ICC.GetIntCrvCrvInfo( 0, aInfo)) {
if ( AreSamePointApprox( aInfo.IciB[0].ptI, ptEndGuide))
return true ;
}
}
// passo alla PolyLine del perimetro
PolyLine PL ;
pCompoPerimeter->ApproxWithLines( EPS_SMALL, EPS_ANG_SMALL, ICurve::APL_STD, PL) ;
// cerco il punto più esterno rispetto alla direzione del chiuso
Point3d ptPoly ;
PL.GetFirstPoint( ptPoly) ;
while ( PL.GetNextPoint( ptPoly)) {
if ( ! pSeg->Set( ptEndGuide, ptEndGuide + ( ptPoly - ptEndGuide) * EXTENSION_VAL))
return false ;
// calcolo l'intersezione tra questo segmento e la curva di perimetro aperta
IntersCurveCurve ICC( *pSeg, *pCompoPerimeter) ;
// se una intersezione, allora di Overlap con punto iniziale e finale definito
if ( ICC.GetIntersCount() == 1) {
IntCrvCrvInfo aInfo ;
if ( ICC.GetIntCrvCrvInfo( 0, aInfo)) {
if ( aInfo.bOverlap) {
if ( AreSamePointApprox( aInfo.IciB[0].ptI, ptEndGuide) &&
AreSamePointApprox( aInfo.IciB[1].ptI, ptPoly))
return ( pCompoTempGuide->AddLine( ptPoly)) ;
}
else {
if ( AreSamePointApprox( aInfo.IciB[0].ptI, ptEndGuide))
return ( pCompoTempGuide->AddLine( ptPoly)) ;
}
}
}
// se più di una intersezione, allora il perimetro deve essere tutto Interno al segmento
// ( Out nel caso in cui ho le curve invertite)
IntCrvCrvInfo aInfo ;
bool bOk = true ;
for ( int i = 0 ; i < ICC.GetIntersCount() && bOk ; ++ i) {
bOk = ( ICC.GetIntCrvCrvInfo( i, aInfo)) ;
bOk = ( aInfo.bOverlap ||
( aInfo.IciB[0].nPrevTy != ( ! bInverted ? CRVC_OUT : CRVC_IN) &&
aInfo.IciB[0].nNextTy != ( ! bInverted ? CRVC_OUT : CRVC_IN))) ;
}
if ( bOk)
return ( pCompoTempGuide->AddLine( ptPoly)) ;
}
return true ;
}
//----------------------------------------------------------------------------
static bool
IsCompoMadeBy2DifferentHomogeneousParts( const ICurveComposite* pCompo, const PocketParams& PockParams,
bool& bOk, ICRVCOMPOPOVECTOR& vpCrvs)
{
// controllo dei parametri
if ( pCompo == nullptr || ! pCompo->IsValid())
return false ;
bOk = false ;
vpCrvs.clear() ;
// clono la curva composita ( cambierà il suo punto iniziale)
PtrOwner<ICurveComposite> pCompoCL( CloneCurveComposite( pCompo)) ;
if ( IsNull( pCompoCL) || ! pCompoCL->IsValid())
return false ;
// recupero i tratti con proprietà uniformi
GetHomogeneousParts( pCompoCL, PockParams, vpCrvs) ;
if ( vpCrvs.size() > 1) {
// unisco il primo e l'ultimo se estremi compatibili
Point3d ptE ; vpCrvs.back()->GetEndPoint( ptE) ;
Point3d ptS ; vpCrvs[0]->GetStartPoint( ptS) ;
if ( AreSamePointApprox( ptS, ptE)) {
vpCrvs[0]->AddCurve( Release( vpCrvs.back()), false) ;
vpCrvs.erase( vpCrvs.end() - 1) ;
}
}
// controlloo che la curva abbia esattamente due tratti omogenei
bOk = ( int( vpCrvs.size()) == 2) ;
if ( ! bOk)
vpCrvs.clear() ;
return true ;
}
//----------------------------------------------------------------------------
static bool
CalcCrvGuideConformalZigZag( const ISurfFlatRegion* pSfrChunk, PocketParams& PockParams, ICurveComposite* pCompoGuide,
ICurveComposite* pCompoClass)
{
// controllo dei parametri
if ( pCompoGuide == nullptr || pCompoClass == nullptr ||
pSfrChunk == nullptr || ! pSfrChunk->IsValid())
return false ;
pCompoGuide->Clear() ;
pCompoClass->Clear() ;
// la superficie deve avere un Chunk e non avere isole
if ( pSfrChunk->GetChunkCount() > 1 || pSfrChunk->GetLoopCount( 0) > 1)
return true ;
// ricavo la curva di bordo ( la curva che definisce il perimetro)
PtrOwner<ICurveComposite> pCompoPerimeter( ConvertCurveToComposite( pSfrChunk->GetLoop( 0, 0))) ;
if ( IsNull( pCompoPerimeter) || ! pCompoPerimeter->IsValid())
return false ;
// controllo che sia formata da esattamente due tratti omogenei
bool b2HP = false ;
ICRVCOMPOPOVECTOR vpCrvs ;
if ( ! IsCompoMadeBy2DifferentHomogeneousParts( pCompoPerimeter, PockParams, b2HP, vpCrvs))
return false ;
if ( ! b2HP)
return true ;
// allargo curva di Bordo secondo le specifiche di una lavorazione a SpiralIn
double dRad = PockParams.dRad ;
int nOffsType = PockParams.nOffsType ;
PockParams.dRad = max( dRad / 8, PockParams.dSideStep / 2) ;
PockParams.nOffsType = ICurve::OFF_CHAMFER ;
ICRVCOMPOPOVECTOR vCrvEmpty ;
if ( ! AdjustContourWithOpenEdges( pCompoPerimeter, vCrvEmpty, PockParams))
return false ;
PockParams.dRad = dRad ;
PockParams.nOffsType = nOffsType ;
// reucupero ora i due tratti uniformi ( della curva allargata)
if ( ! IsCompoMadeBy2DifferentHomogeneousParts( pCompoPerimeter, PockParams, b2HP, vpCrvs) ||
! b2HP)
return false ;
// la guida inizialmente è data dal tratto chiuso
// il perimetro coincide con il tratto aperto
PtrOwner<ICurveComposite> pCompoTempGuide( Release( vpCrvs[0])) ;
if ( IsNull( pCompoTempGuide) || ! pCompoTempGuide->IsValid())
return false ;
// estendo la curva nel suo tratto finale ed iniziale
for ( int i = 0 ; i < 2 ; ++ i) {
if ( ! ExtendGuideByIteration( pCompoTempGuide, vpCrvs[1], ( i == 1)))
return false ;
// se la guida diventa diventa chiusa, allora esco
if ( ! pCompoTempGuide->IsValid() || pCompoTempGuide->IsClosed())
return true ;
pCompoTempGuide->Invert() ;
vpCrvs[1]->Invert() ;
}
// tratto iniziale
Vector3d vtStart ; pCompoTempGuide->GetStartDir( vtStart) ;
Point3d ptStart ; pCompoTempGuide->GetStartPoint( ptStart) ;
PtrOwner<ICurveLine> pLineStart( CreateCurveLine()) ;
if ( IsNull( pLineStart) || ! pLineStart->Set( ptStart - 1000. * vtStart, ptStart))
return false ;
// tratto finale ( potrebbe intersecare il tratto iniziale)
Vector3d vtEnd ; pCompoTempGuide->GetEndDir( vtEnd) ;
Point3d ptEnd ; pCompoTempGuide->GetEndPoint( ptEnd) ;
PtrOwner<ICurveLine> pLineEnd( CreateCurveLine()) ;
if ( IsNull( pLineEnd) || ! pLineEnd->Set( ptEnd, ptEnd + 1000. * vtEnd))
return false ;
IntersCurveCurve ICC( *pLineStart, *pLineEnd) ;
if ( ICC.GetIntersCount() > 0) {
IntCrvCrvInfo aInfo ;
if ( ICC.GetIntCrvCrvInfo( 0, aInfo)) {
pLineStart->TrimStartAtParam( aInfo.IciA[0].dU) ;
pLineEnd->TrimEndAtParam( aInfo.IciB[0].dU) ;
}
}
// le due estensioni vanno tagliate presso i bordi dei lati aperti estesi
IntersCurveCurve ICCLS( *pLineStart, *vpCrvs[1]) ;
if ( ICCLS.GetIntersCount() > 0) {
IntCrvCrvInfo aInfo ;
for ( int i = 0 ; i < ICCLS.GetCrossIntersCount() ; ++ i) {
if ( ICCLS.GetIntCrvCrvInfo( i, aInfo)) {
if ( ! AreSamePointApprox( aInfo.IciA[ aInfo.bOverlap ? 1 : 0].ptI, ptStart))
pLineStart->ModifyStart( aInfo.IciA[aInfo.bOverlap ? 1 : 0].ptI) ;
}
}
}
IntersCurveCurve ICCLE( *pLineEnd, *vpCrvs[1]) ;
if ( ICCLE.GetIntersCount() > 0) {
IntCrvCrvInfo aInfo ;
for ( int i = 0 ; i < ICCLE.GetCrossIntersCount() ; ++ i) {
if ( ICCLE.GetIntCrvCrvInfo( 0, aInfo)) {
if ( ! AreSamePointApprox( aInfo.IciA[0].ptI, ptEnd))
pLineEnd->ModifyEnd( aInfo.IciA[0].ptI) ;
}
}
}
pCompoTempGuide->AddCurve( Release( pLineStart), false) ;
pCompoTempGuide->AddCurve( Release( pLineEnd), true) ;
// recupero la curva guida
pCompoGuide->CopyFrom( pCompoTempGuide) ;
// recupero la curva di classificazione ( abballendola)
PolyLine PL ;
pCompoPerimeter->ApproxWithLines( 10 * LIN_TOL_MIN, ANG_TOL_STD_DEG, ICurve::APL_STD, PL) ;
PL.RemoveAlignedPoints( 500 * EPS_SMALL) ;
pCompoPerimeter->Clear() ;
pCompoPerimeter->FromPolyLine( PL) ;
pCompoPerimeter->RemoveSmallDefects( 10 * LIN_TOL_MIN, ANG_TOL_STD_DEG, true) ;
pCompoPerimeter->MergeCurves( LIN_TOL_MIN, ANG_TOL_STD_DEG) ;
pCompoClass->CopyFrom( pCompoPerimeter) ;
ResetCurveTempProps( pCompoClass) ;
return true ;
}
//----------------------------------------------------------------------------
static bool
AddAddConformalZigZag( const ISurfFlatRegion* pSfr, PocketParams& PockParams,
ICRVCOMPOPOVECTOR& vCrvCompoRes)
{
/*
Calcolo ottimizzato di svuotatura mediante Offset progressivi di una guida, raccordati
rispetto al bordo della superficie di Pocketing mediante logica ZigZag
*/
// controllo dei parametri
if ( pSfr == nullptr || ! pSfr->IsValid())
return false ;
vCrvCompoRes.clear() ;
// ciclo sui chunk della regione
for ( int nC = 0 ; nC < pSfr->GetChunkCount() ; ++ nC) {
// recupero il Chunk nC-esimo
PtrOwner<ISurfFlatRegion> pSfrChunk( pSfr->CloneChunk( nC)) ;
if ( IsNull( pSfrChunk) || ! pSfrChunk->IsValid())
return false ;
// recupero il massimo Offset del Chunk nC-esimo
double dMaxOffs ;
pSfrChunk->GetMaxOffset( dMaxOffs) ;
// se inferiore del Tool ( ho già svuotato tale Chunk in precedenza)
if ( dMaxOffs < PockParams.dRad + 200 * EPS_SMALL)
continue ;
// ricavo la guida ideale e la curva su cui tagliare gli Offset a partire dal Chunk nC-esimo
PtrOwner<ICurveComposite> pCrvGuideExt( CreateCurveComposite()) ;
PtrOwner<ICurveComposite> pCrvClass( CreateCurveComposite()) ;
if ( IsNull( pCrvGuideExt) || IsNull( pCrvClass) ||
! CalcCrvGuideConformalZigZag( pSfr, PockParams, pCrvGuideExt, pCrvClass))
return false ;
// se non è stata trovata una guida ideale, allora passo al Chunk successivo
if ( ! pCrvGuideExt->IsValid() || pCrvGuideExt->GetCurveCount() == 0 ||
! pCrvClass->IsValid() || pCrvClass->GetCurveCount() == 0) {
return true ;
}
// memorizzo le curve di Offset tagliate a seconda dalla geometria del perimetro
ICRVCOMPOPOVECTOR vCompoInternalOffs ;
const int MAX_ITER = 100 ;
double dOffs = PockParams.dRad + PockParams.dRadialOffset ;
for ( int i = 0 ; i < MAX_ITER ; ++ i) {
OffsetCurve OffsCrv ;
if ( ! OffsCrv.Make( pCrvGuideExt, - dOffs, ICurve::OFF_FILLET))
return false ;
// se invece ne ottengo più di una, controllo se è necessaria
if ( OffsCrv.GetCurveCount() > 1) {
// recupero le curve extra ( tutte tranne la più lunga)
for ( int j = 0 ; j < OffsCrv.GetCurveCount() - 1 ; ++ j) {
// recupero la curva più corta
PtrOwner<ICurveComposite> pCrvShorter( ConvertCurveToComposite( OffsCrv.GetShorterCurve())) ;
if ( ! IsNull( pCrvShorter) && pCrvShorter->IsValid()) {
// controllo se è davvero necessaria per non lasciare materiale
bool bSkip = false ;
if ( pCrvShorter->IsClosed()) {
CheckIfOffsetIsNecessary( pCrvShorter, ( i == 0 ? dOffs : PockParams.dSideStep),
i, PockParams, bSkip) ;
if ( bSkip)
return true ;
}
}
}
}
// se non ottengo nessuna curva, allora ho finito
PtrOwner<ICurve> pCrvOffs( OffsCrv.GetLongerCurve()) ;
if ( IsNull( pCrvOffs) || ! pCrvOffs->IsValid())
break ;
// se ottengo una curva chiusa, lavorazione non ammessa
if ( pCrvOffs->IsClosed())
return true ;
// la inverto se numero di Offset progressivo dispari
if ( ( ! IsEven( i) && ! PockParams.bInvert) ||
( IsEven( i) && PockParams.bInvert))
pCrvOffs->Invert() ;
// classifico la curva rispetto al perimetro, devo tenere solo le parti interne
CRVCVECTOR ccClass ;
IntersCurveCurve ICC( *pCrvOffs, *pCrvClass) ;
if ( ! ICC.GetCurveClassification( 0, EPS_SMALL, ccClass))
return true ;
// scorro tutte le classificazioni ottenute
for ( int j = 0 ; j < int( ccClass.size()) ; ++ j) {
// tengo quelle strettamente interne
if ( ccClass[j].nClass == CRVC_IN) {
// recupero la porzione di Offset
PtrOwner<ICurve> pCrvOffs_Int( pCrvOffs->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE)) ;
if ( ! IsNull( pCrvOffs_Int) && pCrvOffs_Int->IsValid()) {
// salvo la curva
vCompoInternalOffs.emplace_back( ConvertCurveToComposite( Release( pCrvOffs_Int))) ;
// salvo come prima propeità temporanea, il numero di Offset progressivo
vCompoInternalOffs.back()->SetTempProp( i, 0) ;
}
}
}
dOffs += PockParams.dSideStep ;
}
// se non ho ottenuto Offset, passo al Chunk successivo
if ( vCompoInternalOffs.empty())
return true ;
/*
Creo la curva di Svuotatura come unione di due curve :
- La curva che non deve essere smussata ( curve di primo Offset e raccordi)
- La Curva che necessita di smusso ( le altre)
NB. Nel caso non sia richiesto lo smusso, allora la seconda curva non viene smussata, ma la
logica rimane la stessa.
*/
PtrOwner<ICurveComposite> pCompoNoSmooth( CreateCurveComposite()) ;
PtrOwner<ICurveComposite> pCompoSmooth( CreateCurveComposite()) ;
if ( IsNull( pCompoNoSmooth) || IsNull( pCompoSmooth))
return false ;
// scorro i tratti di Offset interni e aggiungo i raccordi sul bordo esterno
// raccordo il tratto di Offset interno corrente al successivo
const double TOL_JOINT = 25. * EPS_SMALL ;
double dHalfLenPerimeter ;
pCrvClass->GetLength( dHalfLenPerimeter) ;
dHalfLenPerimeter /= 2. ;
for ( int i = 0 ; i < int( vCompoInternalOffs.size()) - 1 ; ++ i) {
// recupero il parametro iniziale del raccordo sulla curva di perimetro
Point3d ptS ; vCompoInternalOffs[i]->GetEndPoint( ptS) ;
double dUS ; pCrvClass->GetParamAtPoint( ptS, dUS) ;
// recupero il parametro finale del raccordo sulla curva di perimetro
Point3d ptE ; vCompoInternalOffs[i+1]->GetStartPoint( ptE) ;
double dUE ; pCrvClass->GetParamAtPoint( ptE, dUE) ;
// aggiungo il tratto di Offset interno corrente alla curva di svuotatura
if ( vCompoInternalOffs[i]->GetTempProp() == 0) {
// se deriva dal primo Offset
if ( ! pCompoNoSmooth->AddCurve( Release( vCompoInternalOffs[i]), true, TOL_JOINT))
return false ;
}
else {
// se deriva da Offset successivi
if ( ! pCompoSmooth->AddCurve( Release( vCompoInternalOffs[i]), true, TOL_JOINT))
return false ;
}
// recupero il tratto di curva di interesse
PtrOwner<ICurve> pCrvJoint( pCrvClass->CopyParamRange( dUS, dUE)) ;
if ( ! IsNull( pCrvJoint) && pCrvJoint->IsValid()) {
double dLen ;
pCrvJoint->GetLength( dLen) ;
if ( dLen > dHalfLenPerimeter) {
pCrvJoint.Set( pCrvClass->CopyParamRange( dUE, dUS)) ;
pCrvJoint->Invert() ;
}
// aggiungo il tratto di percorso
if ( vCompoInternalOffs[i+1]->GetTempProp() == 0) {
// se l'offset successivo deriva ancora dal primo
if ( ! pCompoNoSmooth->AddCurve( Release( pCrvJoint), true, TOL_JOINT))
return false ;
}
else {
// se l'Offset successivo non deriva dal primo Offset
if ( ! pCompoSmooth->AddCurve( Release( pCrvJoint), true, TOL_JOINT))
return false ;
}
}
}
// aggiungo l'ultimo tratto di Offset
if ( vCompoInternalOffs.back()->GetTempProp() == 0) {
if ( ! pCompoNoSmooth->AddCurve( Release( vCompoInternalOffs.back()), true, TOL_JOINT))
return false ;
}
else {
if ( ! pCompoSmooth->AddCurve( vCompoInternalOffs.back()->Clone(), true, TOL_JOINT))
return false ;
}
// porto l'ultima curva del percorso NoSmooth nel percorso Smooth per avere un raccordo anche
// sul tratto di giunzione tra esse
if ( pCompoSmooth->IsValid() && pCompoNoSmooth->IsValid()) {
PtrOwner<ICurve> pCrv( pCompoNoSmooth->GetLastCurve()->Clone()) ;
if ( IsNull( pCrv) || ! pCrv->IsValid() ||
! pCompoSmooth->AddCurve( Release( pCrv), false, TOL_JOINT))
return false ;
delete( pCompoNoSmooth->RemoveFirstOrLastCurve( true)) ;
}
// smusso dove necessario
ModifyCurveToSmoothed( pCompoSmooth, PockParams, PockParams.dRad / 8, PockParams.dRad / 8, false) ;
// creo il percorso di svuotatura
PtrOwner<ICurveComposite> pCompoTempPath( CreateCurveComposite()) ;
if ( IsNull( pCompoTempPath))
return false ;
if ( pCompoNoSmooth->IsValid() && pCompoNoSmooth->GetCurveCount() > 0) {
if ( ! pCompoTempPath.Set( pCompoNoSmooth))
return false ;
}
if ( pCompoSmooth->IsValid()) {
if ( ! pCompoTempPath->AddCurve( Release( pCompoSmooth), true, TOL_JOINT))
return false ;
}
// se la curva finale di Pocketing è valida, allora la resituisco
if ( pCompoTempPath->IsValid()) {
// inverto l'ordine delle curve di Offset ( in modo da partire sempre ad eseguire il percorso
// più lontano dal dai lati chiusi)
pCompoTempPath->Invert() ;
// calcolo la Feed del percorso trovato
if ( ! AssignFeedConformalZigZag( pCompoTempPath, pCrvClass, PockParams))
return false ;
// aggiugno il tratto iniziale e finale per entrate da fuori
Vector3d vtStart ; pCompoTempPath->GetStartDir( vtStart) ;
vtStart.Invert() ;
bool bExt = false ;
if ( ! ExtendPath( pCompoTempPath, pSfr, PockParams, vtStart, false, bExt))
return false ;
Vector3d vtEnd ; pCompoTempPath->GetEndDir( vtEnd) ;
if ( ! ExtendPath( pCompoTempPath, pSfr, PockParams, vtEnd, true, bExt))
return false ;
// sostituisco la curva
if ( pCompoTempPath->IsValid())
vCrvCompoRes.emplace_back( Release( pCompoTempPath)) ;
}
}
return true ;
}
//----------------------------------------------------------------------------
static bool
@@ -6166,7 +6694,7 @@ CalcSpiral( const ISurfFlatRegion* pSrfPock, const PocketParams& PockParams, int
pCrvCompoBorder->Invert() ;
// controllo quali regioni di Offset possono essere sostituite
bool bInsert = true ;
if ( ! CheckIfOffsetIsNecessary( pCrvCompoBorder, dOffs - dOffsPrec, int( vOffs.size()), nIter, PockParams, bInsert))
if ( ! CheckIfOffsetIsNecessary( pCrvCompoBorder, dOffs - dOffsPrec, nIter, PockParams, bInsert))
return false ;
if ( bInsert)
vOffs.emplace_back( Release( pCrvCompoBorder)) ;
@@ -7317,7 +7845,8 @@ CalcPocketing( const ISurfFlatRegion* pSfr, double dRad, double dRadOffs, double
// controllo dei parametri
if ( pSfr == nullptr || ! pSfr->IsValid() ||
dStep < 10 * EPS_SMALL ||
( nType != POCKET_ZIGZAG && nType != POCKET_ONEWAY && nType != POCKET_SPIRALIN && nType != POCKET_SPIRALOUT))
( nType != POCKET_ZIGZAG && nType != POCKET_ONEWAY && nType != POCKET_SPIRALIN &&
nType != POCKET_SPIRALOUT && nType != POCKET_CONFORMAL_ZIGZAG))
return false ;
// pulizia vettore delle curve elementari
@@ -7381,7 +7910,11 @@ CalcPocketing( const ISurfFlatRegion* pSfr, double dRad, double dRadOffs, double
return false ;
break ;
case POCKET_SPIRALOUT :
if ( ! AddSpiralOut( pSfrAdj, pSfr, myParams, vCrvCompoRes))
if ( ! AddSpiralOut( pSfrAdj, pSfr_Loc, myParams, vCrvCompoRes))
return false ;
break ;
case POCKET_CONFORMAL_ZIGZAG :
if ( ! AddAddConformalZigZag( pSfr_Loc, myParams, vCrvCompoRes))
return false ;
break ;
}