diff --git a/Pocketing.cpp b/Pocketing.cpp index 2790360..2f7f7b4 100644 --- a/Pocketing.cpp +++ b/Pocketing.cpp @@ -1140,9 +1140,9 @@ Pocketing::GetCurves( SelData Id, ICURVEPLIST& lstPC, ISurfTriMesh* pStmTmp) if ( ! pCurve->GetExtrusion( vtExtr) || vtExtr.IsSmall()) pCurve->SetExtrusion( Z_AX) ; // corenza con vtTool - if ( ! m_vtTool.IsValid()) - m_vtTool = vtExtr ; - else if ( AreSameVectorApprox( vtExtr, m_vtTool)) + if ( ! m_vtNormal.IsValid()) + m_vtNormal = vtExtr ; + else if ( ! AreSameVectorApprox( vtExtr, m_vtNormal)) return false ; // verifico sia piana e se necessario la appiattisco PtrOwner pFlatCrv( FlattenCurve( *pCurve, 50 * EPS_SMALL, 50 * EPS_ANG_SMALL, FLTCRV_USE_EXTR)) ; @@ -1177,9 +1177,9 @@ Pocketing::GetCurves( SelData Id, ICURVEPLIST& lstPC, ISurfTriMesh* pStmTmp) if ( ! pCrv->GetExtrusion( vtExtr) || vtExtr.IsSmall()) pCrv->SetExtrusion( Z_AX) ; // corenza con vtTool - if ( ! m_vtTool.IsValid()) - m_vtTool = vtExtr ; - else if ( AreSameVectorApprox( vtExtr, m_vtTool)) + if ( ! m_vtNormal.IsValid()) + m_vtNormal = vtExtr ; + else if ( ! AreSameVectorApprox( vtExtr, m_vtNormal)) return false ; // tutte le curve sono chiuse ResetCurveAllTempProp( pCrv) ; @@ -1202,14 +1202,16 @@ Pocketing::GetCurves( SelData Id, ICURVEPLIST& lstPC, ISurfTriMesh* pStmTmp) int nFacet = (( Id.nSub == SEL_SUB_ALL) ? 0 : Id.nSub) ; // recupero la normale esterna della faccia Vector3d vtN ; - if ( ! pSurf->GetFacetNormal( nFacet, vtN)) + if ( ! pStm->GetFacetNormal( nFacet, vtN)) return false ; - if ( ! m_vtTool.IsValid()) - m_vtTool = vtN ; - else if ( AreSameVectorApprox( vtN, m_vtTool)) + if ( ! m_vtNormal.IsValid()) + m_vtNormal = vtN ; + else if ( ! AreSameVectorApprox( vtN, m_vtNormal)) return false ; + // inverto per definire il volume di pocketing + pStm->Invert() ; // aggiungo la Trimesh - if ( ! pStmTmp->Add( *pSurf)) + if ( ! pStmTmp->Add( *pStm)) return false ; return true ; } @@ -1225,16 +1227,16 @@ Pocketing::GetCurves( SelData Id, ICURVEPLIST& lstPC, ISurfTriMesh* pStmTmp) // porto in globale pSfr->ToGlob( frGlob) ; // recupero la normale della regione - Vector3d vtN = pReg->GetNormVersor() ; + Vector3d vtN = pSfr->GetNormVersor() ; if ( vtN.IsSmall()) return false ; - if ( ! m_vtTool.IsValid()) - m_vtTool = vtN ; - else if ( AreSameVectorApprox( vtN, m_vtTool)) + if ( ! m_vtNormal.IsValid()) + m_vtNormal = vtN ; + else if ( ! AreSameVectorApprox( vtN, m_vtNormal)) return false ; // determino intervallo di chunk int nCstart = 0 ; - int nCend = pReg->GetChunkCount() ; + int nCend = pSfr->GetChunkCount() ; if ( Id.nSub != SEL_SUB_ALL) { nCstart = Id.nSub ; nCend = nCstart + 1 ; @@ -1244,8 +1246,8 @@ Pocketing::GetCurves( SelData Id, ICURVEPLIST& lstPC, ISurfTriMesh* pStmTmp) // creo vettore delle curve CICURVEPVECTOR vCrv ; // recupero i contorni del chunk - for ( int nL = 0 ; nL < pReg->GetLoopCount( nC) ; ++ nL) { - PtrOwner pCrvLoop( ConvertCurveToComposite( pReg->GetLoop( nC, nL))) ; + for ( int nL = 0 ; nL < pSfr->GetLoopCount( nC) ; ++ nL) { + PtrOwner pCrvLoop( ConvertCurveToComposite( pSfr->GetLoop( nC, nL))) ; if ( IsNull( pCrvLoop)) return false ; // unisco le eventuali parti allineate @@ -1258,7 +1260,7 @@ Pocketing::GetCurves( SelData Id, ICURVEPLIST& lstPC, ISurfTriMesh* pStmTmp) vCrv.emplace_back( Release( pCrvLoop)) ; } // creo la TriMesh associata ( tutti i lati sono chiusi) - PtrOwner pStm_extr( GetSurfTriMeshByRegionExtrusion( vCrv, vtN)) ; + PtrOwner pStm_extr( GetSurfTriMeshByRegionExtrusion( vCrv, 3000 * vtN)) ; if ( IsNull( pStm_extr) || ! pStm_extr->IsValid()) return false ; pStmTmp->Add( *pStm_extr) ; @@ -1450,13 +1452,361 @@ Pocketing::Chain( int nGrpDestId) vCrvCompo.emplace_back( Release( pCrvCompo)) ; } - // creazione della TriMesh di pocketing + // ricavo un punto interno per il finito corrente + Point3d ptInside ; + if ( pStm_tmp->GetTriangleCount() > 0) + pStm_tmp->GetCentroid( ptInside) ; + else if ( int( vCrvCompo.size() > 0)) + vCrvCompo[0]->GetCentroid( ptInside) ; + else + return false ; + + // creazione della TriMesh di pocketing + if ( ! CreateStmForIntersection( pStm_tmp, vCrvCompo)) + return false ; + + // intersezione della Trimesh con il finito -> rivavo il volume di svuotatura + if ( ! SetPocketingVolume( ptInside, pStm_tmp)) + return false ; + + // QUIIIIIIIIIIIIIII + return false ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +Pocketing::CreateStmForIntersection( ISurfTriMesh* pStm, ICRVCOMPOPOVECTOR& vCrvCompo) +{ + // se non ho entità esco + if ( int( vCrvCompo.size()) == 0) + return true ; + + // creo un frame centrato sulla prima curva con Z orientata come m_vtTool + Point3d ptOrig ; + if ( ! vCrvCompo[0]->GetCentroid( ptOrig)) + if ( ! vCrvCompo[0]->GetStartPoint( ptOrig)) + return false ; + Frame3d frHeight ; frHeight.Set( ptOrig, m_vtNormal) ; + if ( ! frHeight.IsValid()) + return false ; + + struct CurveQuotes { + int nCrvInd ; + double dQuote ; + } ; + + // scorro le curve e ricavo le quote + vector vdCrvQuotes ; + for ( int i = 0 ; i < int( vCrvCompo.size()) ; ++ i) { + vCrvCompo[i]->ToLoc( frHeight) ; // porto in locale + Point3d ptOnCurve ; + if ( ! vCrvCompo[0]->GetCentroid( ptOnCurve)) + if ( ! vCrvCompo[0]->GetStartPoint( ptOnCurve)) + return false ; + CurveQuotes CrvQt ; + CrvQt.nCrvInd = i ; + CrvQt.dQuote = ptOnCurve.z ; + vdCrvQuotes.push_back( CrvQt) ; + vCrvCompo[i]->ToGlob( frHeight) ; // porto in globale + } + + // ordino le quote + sort( vdCrvQuotes.begin(), vdCrvQuotes.end(), []( CurveQuotes &CrvQt0, CurveQuotes &CrvQt1) { + return CrvQt0.dQuote < CrvQt0.dQuote ; }) ; + + // creo una FlatRegion con le curve alla stessa quota + ISURFFRPOVECTOR vSfrByQuotes ; + int nInd = 0 ; + while( nInd < int( vdCrvQuotes.size())) { + // regione tempoeranea con la curva attuale + SurfFlatRegionByContours sfrBC ; + sfrBC.AddCurve( vCrvCompo[vdCrvQuotes[nInd].nCrvInd]) ; + ++ nInd ; + for ( int j = nInd ; j < int( vdCrvQuotes.size()) ; ++ j) { + nInd = j ; + if ( abs( vdCrvQuotes[j].dQuote - vdCrvQuotes[nInd].dQuote) > EPS_SMALL) + break ; + // se curva successiva alla stessa quota -> aggiungo alla regione + sfrBC.AddCurve( vCrvCompo[vdCrvQuotes[j].nCrvInd]) ; + } + // creo la regione + PtrOwner pSfrCurr( sfrBC.GetSurf()) ; + if ( IsNull( pSfrCurr) || ! pSfrCurr->IsValid()) + return false ; + // inverto se necessario + if ( AreOppositeVectorApprox( m_vtNormal, pSfrCurr->GetNormVersor())) + pSfrCurr->Invert() ; + // aggiungo al vettore + vSfrByQuotes.emplace_back( Release( pSfrCurr)) ; + } + + // devo allargare i lati aperti della curva esterna, così la superficie si adatterà al finito mediante l'intersezione + for ( int s = 0 ; s < int( vSfrByQuotes.size()) ; ++ s) { + // per ogni superficie ricavo il loop esterno e le sue isole + for ( int c = 0 ; c < vSfrByQuotes[s]->GetChunkCount() ; ++ c) { + // creo il vettore contenente il Loop esterno esteso e le isole + CICURVEPVECTOR vCrv ; + // loop esterno + PtrOwner pCrvLoopExt( ConvertCurveToComposite( vSfrByQuotes[s]->GetLoop( c, 0))) ; + if ( IsNull( pCrvLoopExt) || ! pCrvLoopExt->IsValid()) + return false ; + // allargo il loop esterno presso i chiusi + if ( ! GetExtendedLoopToFitStmVolume( pCrvLoopExt)) + return false ; + // inserisco la curva nel vettore + vCrv.emplace_back( Release( pCrvLoopExt)) ; + // inserisco le isole + for ( int l = 1 ; l < vSfrByQuotes[s]->GetLoopCount( c) ; ++ l) + vCrv.emplace_back( vSfrByQuotes[s]->GetLoop( c, l)) ; + // creo la TriMesh per l'intersezione con il finito + PtrOwner pStmTmp( GetSurfTriMeshByRegionExtrusion( vCrv, 3000 * m_vtNormal)) ; + if ( IsNull( pStmTmp) || ! pStmTmp->IsValid()) + return false ; + // aggiungo questa regione a quella passata come parametro alla funzione + pStm->Add( *pStmTmp) ; + } + } + + + m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pStm->Clone()) ; - // intersezione con il finito return true ; } +//---------------------------------------------------------------------------- +bool +Pocketing::GetExtendedLoopToFitStmVolume( ICurveComposite* pCrvLoop) +{ + // controllo del parametro + if ( pCrvLoop == nullptr || ! pCrvLoop->IsValid()) + return false ; + + // ricavo i parametri della curva + double dThick ; pCrvLoop->GetThickness( dThick) ; + int nTmpProp0 = pCrvLoop->GetTempProp() ; + int nTmpProp1 = pCrvLoop->GetTempProp( 1) ; + + // ricavo i tratti omogenei ( campio il punto iniziale della curva nel punto medio del chiuso più lungo se presente) + ICURVEPOVECTOR vCrvOpen, vCrvClose ; + if ( ! GetHomogeneousParts( pCrvLoop, vCrvOpen, vCrvClose, true)) + return false ; + + // se curva tutta chiusa -> non devo estendere + if ( int( vCrvOpen.size()) == 0) + return true ; + // se curva tutta aperta -> Offset ed esco + else if ( int( vCrvClose.size()) == 0) { + OffsetCurve OffsCrv ; + if ( ! OffsCrv.Make( pCrvLoop, 3000, ICurve::OFF_EXTEND)) { + m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ; + return false ; + } + pCrvLoop->CopyFrom( OffsCrv.GetLongerCurve()) ; + return pCrvLoop->IsClosed() && pCrvLoop->IsValid() ; + } + + // scorro i tratti chusi ( se presenti sono almeno due) + for ( int cl = 0 ; cl < int( vCrvClose.size()) - 1 ; ++ cl) { + // linea di estensione sulla parte finale + Point3d ptSL1 ; vCrvClose[cl]->GetEndPoint( ptSL1) ; + Vector3d vtSL1 ; vCrvClose[cl]->GetEndDir( vtSL1) ; + PtrOwner pLineS( CreateCurveLine()) ; + if ( IsNull( pLineS) || pLineS->SetPVL( ptSL1, vtSL1, 30000)) + return false ; + // linea di estensione sulla parte finale + Point3d ptSL2 ; vCrvClose[cl+1]->GetStartPoint( ptSL2) ; + Vector3d vtSL2 ; vCrvClose[cl+1]->GetStartDir( vtSL2) ; vtSL2.Invert() ; + PtrOwner pLineE( CreateCurveLine()) ; + if ( IsNull( pLineE) || pLineE->SetPVL( ptSL2, vtSL2, 30000)) + return false ; + // se le linee di intersecano + IntersCurveCurve IntCC( *pLineE, *pLineS) ; + if ( IntCC.GetIntersCount() == 1) { + // ricavo il punto di intersezione + IntCrvCrvInfo aInfo ; + if ( ! IntCC.GetIntCrvCrvInfo( 0, aInfo)) + return false ; + Point3d ptInters( aInfo.IciA[0].ptI) ; + // modifico la curva inzile, raccordandola linearmente al punto di intersezione + double dUS, dUE ; + pCrvLoop->GetParamAtPoint( ptSL1, dUS) ; + pCrvLoop->GetParamAtPoint( ptSL2, dUE) ; + // tratto precedente + PtrOwner pCrvPrec( CloneCurveComposite( pCrvLoop)) ; + if ( IsNull( pCrvPrec) || pCrvPrec->TrimEndAtParam( dUS)) + return false ; + // tratto successivo + PtrOwner pCrvSucc( CloneCurveComposite( pCrvLoop)) ; + if ( IsNull( pCrvSucc) || pCrvSucc->TrimStartAtParam( dUE)) + return false ; + pCrvLoop->Clear() ; + if ( ! pCrvLoop->AddCurve( Release( pCrvPrec)) || + ! pCrvLoop->AddLine( ptInters) || + ! pCrvLoop->AddLine( ptSL2) || + ! pCrvLoop->AddCurve( Release( pCrvSucc))) + return false ; + } + // se invece non ci sono intersezioni tra le linee + else if ( IntCC.GetIntersCount() == 0) { + // estendo il tratto aperto con un Offset + OffsetCurve OffsCrv ; + if ( ! OffsCrv.Make( vCrvOpen[cl], 300, ICurve::OFF_EXTEND)) { + m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ; + return false ; + } + PtrOwner pCrvOffs( OffsCrv.GetLongerCurve()) ; + if ( IsNull( pCrvOffs) || ! pCrvOffs->IsValid()) + return false ; + // estendo l'inizio e la fine + if ( ! pCrvOffs->ExtendStartByLen( 30000) || + ! pCrvOffs->ExtendEndByLen( 30000)) + return false ; + // intersecon questa curva con le rette + IntersCurveCurve IntCC_S( *pLineS, *pCrvOffs) ; + IntersCurveCurve IntCC_E( *pLineE, *pCrvOffs) ; + Point3d ptInters_S, ptInters_E ; + if ( IntCC_S.GetIntersCount() == 1) { + IntCrvCrvInfo aInfoS ; + if ( ! IntCC_S.GetIntCrvCrvInfo( 0, aInfoS)) + return false ; + ptInters_S = aInfoS.IciA[0].ptI ; + } + else + return false ; + if ( IntCC_E.GetCrossIntersCount() == 1) { + IntCrvCrvInfo aInfoE ; + if ( ! IntCC_E.GetIntCrvCrvInfo( 0, aInfoE)) + return false ; + ptInters_E = aInfoE.IciA[0].ptI ; + } + else + return false ; + // trimmo la curva Offsettata nei punti di intersezione + double dUS, dUE ; + pCrvOffs->GetParamAtPoint( ptInters_S, dUS) ; + pCrvOffs->GetParamAtPoint( ptInters_E, dUE) ; + if ( ! pCrvOffs->TrimStartEndAtParam( dUS, dUE)) + return false ; + // modifico la curva inzile, raccordandola linearmente al trim dell'Offset + pCrvLoop->GetParamAtPoint( ptSL1, dUS) ; + pCrvLoop->GetParamAtPoint( ptSL2, dUE) ; + // tratto precedente + PtrOwner pCrvPrec( CloneCurveComposite( pCrvLoop)) ; + if ( IsNull( pCrvPrec) || pCrvPrec->TrimEndAtParam( dUS)) + return false ; + // tratto successivo + PtrOwner pCrvSucc( CloneCurveComposite( pCrvLoop)) ; + if ( IsNull( pCrvSucc) || pCrvSucc->TrimStartAtParam( dUE)) + return false ; + pCrvLoop->Clear() ; + if ( ! pCrvLoop->AddCurve( Release( pCrvPrec)) || + ! pCrvLoop->AddLine( ptInters_S) || + ! pCrvLoop->AddCurve( Release( pCrvOffs)) || + ! pCrvLoop->AddLine( ptInters_E) || + ! pCrvLoop->AddCurve( Release( pCrvSucc))) + return false ; + } + else // non definito + return false ; + } + + return pCrvLoop->IsClosed() && pCrvLoop->IsValid() ; +} + +//---------------------------------------------------------------------------- +bool +Pocketing::SetPocketingVolume( const Point3d& ptInside, ISurfTriMesh* pStm) +{ + // controllo parametro + if ( pStm == nullptr || ! pStm->IsValid()) + return false ; + + // controllo MachManager e database geometrico + if ( m_pMchMgr == nullptr || m_pGeomDB == nullptr) + return false ; + + // TriMesh del finito + PtrOwner pStmCurrRawPart( CreateSurfTriMesh()) ; + if ( IsNull( pStmCurrRawPart)) + return false ; + + // flag per RawPart trovata + bool bFound = false ; + + // considero tutte le superfici dei pezzi nei grezzi attivi della fase + int nRawId = m_pMchMgr->GetFirstRawPart() ; + while ( nRawId != GDB_ID_NULL && !bFound) { + if ( m_pMchMgr->VerifyRawPartPhase( nRawId, m_nPhase)) { + // ciclo sui pezzi del grezzo + int nPartId = m_pMchMgr->GetFirstPartInRawPart( nRawId) ; + while ( nPartId != GDB_ID_NULL && !bFound) { + // ciclo sui layer dei pezzi + int nLayId = m_pGeomDB->GetFirstGroupInGroup( nPartId) ; + while ( nLayId != GDB_ID_NULL && !bFound) { + // ciclo sulle entità del layer + int nEntId = m_pGeomDB->GetFirstInGroup( nLayId) ; + while ( nEntId != GDB_ID_NULL && !bFound) { + // se entità superficie e visibile, la aggiungo + int nStat ; + if ( m_pGeomDB->GetGeoType( nEntId) == SRF_TRIMESH) { + // recupero l'ggetto dal databse con tale Id + const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( nEntId) ; + // recupero il frame in cui si trova + Frame3d frPart ; + m_pGeomDB->GetGlobFrame( nEntId, frPart) ; + if ( pGObj == nullptr) + return false ; + // controllo che effettivamente sia una TriMesh + if ( pGObj->GetType() == SRF_TRIMESH) { + // Trimesh della Part + PtrOwner pStmRawPart( CloneSurfTriMesh( pGObj)) ; + if ( IsNull( pStmRawPart)) + return false ; + // porto la Trimesh in globale + pStmRawPart->LocToLoc( frPart, GLOB_FRM) ; + // controllo se il punto è interno a tale Part + double dElev = 0. ; + DistPointSurfTm DistPtStm( ptInside, *pStmRawPart) ; + if ( DistPtStm.IsPointInside()) { + pStmCurrRawPart->CopyFrom( pStmRawPart) ; + IGeoPoint3d* ptIns( CreateGeoPoint3d()) ; ptIns->Set( ptInside) ; + m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, ptIns) ; + m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pStmCurrRawPart->Clone()) ; + if ( ! pStmCurrRawPart->IsValid()) + return false ; + bFound = true ; + break ; + } + } + } + // passo alla entità successiva + nEntId = m_pGeomDB->GetNext( nEntId) ; + } + nLayId =m_pGeomDB->GetNextGroup( nLayId) ; + } + nPartId = m_pMchMgr->GetNextPartInRawPart( nPartId) ; + } + } + nRawId = m_pMchMgr->GetNextRawPart( nRawId) ; + } + + // parte non trovata + if ( ! bFound) + return false ; + + // interseco la TriMesh complessiva di pocketing con il finito, ottenendo il volume di svuotatura + m_pStmVolPocket.Set( Release( pStmCurrRawPart)) ; + if ( IsNull( m_pStmVolPocket) || ! m_pStmVolPocket->IsValid()) + return false ; + if ( ! m_pStmVolPocket->Intersect( *pStm)) // intersezione + return false ; + m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, m_pStmVolPocket->Clone()) ; + + return m_pStmVolPocket->IsValid() && m_pStmVolPocket->GetTriangleCount() > 0 ; +} + //---------------------------------------------------------------------------- bool Pocketing::ProcessPath( int nAuxId, int nPvId, int nClId) diff --git a/Pocketing.h b/Pocketing.h index 77ba08d..165cd9f 100644 --- a/Pocketing.h +++ b/Pocketing.h @@ -81,7 +81,16 @@ class Pocketing : public Machining bool GeneratePocketingPv( int nPathId, const ISurfFlatRegion* pSrfPock) ; bool CheckSelectedId( void) ; bool DetectShape( int nId, Frame3d frPocket) ; - bool DetectOpenEdgeInsideRaw ( ISurfFlatRegion* pSfr, const ISurfTriMesh* pStmRaw ) ; + bool DetectOpenEdgeInsideRaw ( ISurfFlatRegion* pSfr, const ISurfTriMesh* pStmRaw) ; + + + bool CreateStmForIntersection( ISurfTriMesh* pStm, ICRVCOMPOPOVECTOR& vCrvCompo) ; + bool GetExtendedLoopToFitStmVolume( ICurveComposite* pCrvLoop) ; + bool SetPocketingVolume( const Point3d& ptInside, ISurfTriMesh* pStm) ; + bool GetCurrentPart( const Point3d ptInside, ISurfTriMesh* pStmRawPart) ; + + + // =========================== MIGLIORIE GENERALI ==================== bool ModifyCurveToSmoothed( ICurveComposite* pCrvOffset, double dRightPer, double dleftPer) ; @@ -371,7 +380,7 @@ class Pocketing : public Machining double m_dOpenMinSafe ; // minima distanza di sicurezza di attacco su lato aperto PtrOwner m_pStmVolPocket ; // volume delle svuotatura - Vector3d m_vtTool = V_INVALID ; // versore direzione tool + Vector3d m_vtNormal = V_INVALID ; // versore normale ai piani di pocketing