diff --git a/PocketingNT.cpp b/PocketingNT.cpp index 91a2acc..0006691 100644 --- a/PocketingNT.cpp +++ b/PocketingNT.cpp @@ -3113,8 +3113,7 @@ PocketingNT::ManageOpenEdges( ISurfFlatRegion* pSfr, const ISurfTriMesh* pStm) * come chiusi */ // controllo dei parametri - if ( pSfr == nullptr || ! pSfr->IsValid() || - pStm == nullptr) + if ( pSfr == nullptr || ! pSfr->IsValid() || pStm == nullptr) return false ; if ( ! pStm->IsValid()) return true ; @@ -3125,7 +3124,7 @@ PocketingNT::ManageOpenEdges( ISurfFlatRegion* pSfr, const ISurfTriMesh* pStm) // recupero i Chunk della superficie ISURFFRPOVECTOR vChunks( pSfr->GetChunkCount()) ; - for ( int nC = 0 ; nC < int( vChunks.size()) ; ++ nC) + for ( int nC = 0 ; nC < ssize( vChunks) ; ++ nC) vChunks[nC].Set( pSfr->CloneChunk( nC)) ; // definisco un frame locale nel piano XY @@ -3140,10 +3139,9 @@ PocketingNT::ManageOpenEdges( ISurfFlatRegion* pSfr, const ISurfTriMesh* pStm) if ( GetValInNotes( m_Params.m_sUserNotes, UN_OPEN, dOpenExtension) && dOpenExtension > EPS_SMALL) m_dOpenInRawExtension = dOpenExtension ; - // se la superficie ha flag di OpenOutRaw e non è stata impostata alcuna estensione massima, - // non modifico la geometria, lascio l'aperto esattamente dove si trova - // se invece ho flat di OpenOutRaw, dato che il lato aperto viene lasciato tale, devo ridurre la - // sua estensione del raggio utensile + // se la superficie ha flag di OpenOutRaw e non è stata impostata alcuna estensione massima, non modifico la geometria, + // lascio l'aperto esattamente dove si trova, se invece ho il flag di OpenOutRaw, dato che il lato aperto viene lasciato tale, + // devo ridurre la sua estensione del raggio utensile if ( m_bOpenOutRaw) { if ( dOpenExtension < 10. * EPS_SMALL) return true ; @@ -3171,223 +3169,237 @@ PocketingNT::ManageOpenEdges( ISurfFlatRegion* pSfr, const ISurfTriMesh* pStm) m_pGeomDB->SetMaterial( _a, Color( .35, .65, .45, .35)) ; #endif - // recupero solo la curva di bordo esterno, le isole aperte per ora sono trascurate // scorro i Chunk della regione piana da lavorare bool bModifSfr = false ; - for ( int nC = 0 ; nC < int( vChunks.size()) ; ++ nC) { - // recupero la curva di bordo - PtrOwner pCrvBorder( ConvertCurveToComposite( vChunks[nC]->GetLoop( 0, 0))) ; - if ( IsNull( pCrvBorder) || ! pCrvBorder->IsValid()) - return false ; - // recupero i tratti omogenei - ICRVCOMPOPOVECTOR vpCrvs ; - GetHomogeneousParts( pCrvBorder, vpCrvs) ; - // se tutta chiusa, non faccio nulla - if ( int( vpCrvs.size()) == 1 && vpCrvs[0]->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE) - continue ; - // scorro i tratti alla ricerca di lati aperti ( esistono necessariamente) - bool bOpenCrvInPart = false ; - for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { - if ( vpCrvs[i]->GetTempProp( 0) == TEMP_PROP_OPEN_EDGE) { - // analizzo le sottocurve del tratto - for ( int j = 0 ; j < vpCrvs[i]->GetCurveCount() ; ++ j) { - // per ogni sottocurva considero punto iniziale, finale e medio per campionarla - // ( si potrebbe in futuro campionare in maniera più fitta ) - PNTVECTOR vPt( 3, P_INVALID) ; - vpCrvs[i]->GetCurve( j)->GetStartPoint( vPt[0]) ; - vpCrvs[i]->GetCurve( j)->GetMidPoint( vPt[1]) ; - vpCrvs[i]->GetCurve( j)->GetEndPoint( vPt[2]) ; - // classifico tali punti rispetto alla superficie - bool bOpenEdgeInStm = false ; - double dDist = 0. ; - for ( int nPt = 0 ; nPt < int( vPt.size()) && ! bOpenEdgeInStm ; ++ nPt) { - DistPointSurfTm DistPtStm( vPt[nPt], *pStm) ; - bOpenEdgeInStm = ( DistPtStm.IsPointInside() && - DistPtStm.GetDist( dDist) && - dDist > TOL_PT_INSIDE_STM) ; - } - // se curva aperta nel pezzo, la classifico - if ( bOpenEdgeInStm) { - vpCrvs[i]->SetCurveTempProp( j, TEMP_PROP_OPEN_EDGE_IN_RAW, 0) ; - bOpenCrvInPart = true ; + for ( int nC = 0 ; nC < ssize( vChunks) ; ++ nC) { + // definisco le nuove curve di bordo + bool bModifChunk = false ; + int nLoops = vChunks[nC]->GetLoopCount( 0) ; + ICRVCOMPOPOVECTOR vCrvNewBorder ; vCrvNewBorder.resize( nLoops) ; + for ( int nL = 0 ; nL < nLoops ; ++ nL) { + // recupero la curva di bordo + PtrOwner pCrvBorder( ConvertCurveToComposite( vChunks[nC]->GetLoop( 0, nL))) ; + if ( IsNull( pCrvBorder) || ! pCrvBorder->IsValid()) + return false ; + // recupero i tratti omogenei + ICRVCOMPOPOVECTOR vpCrvs ; + GetHomogeneousParts( pCrvBorder, vpCrvs) ; + // se tutta chiusa, non faccio nulla + if ( ssize( vpCrvs) == 1 && vpCrvs[0]->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE) + continue ; + // scorro i tratti alla ricerca di lati aperti ( esistono necessariamente) + bool bOpenCrvInPart = false ; + for ( int i = 0 ; i < ssize( vpCrvs) ; ++ i) { + if ( vpCrvs[i]->GetTempProp( 0) == TEMP_PROP_OPEN_EDGE) { + // analizzo le sottocurve del tratto + for ( int j = 0 ; j < vpCrvs[i]->GetCurveCount() ; ++ j) { + // per ogni sottocurva considero punto iniziale, finale e medio per campionarla + PNTVECTOR vPt( 3, P_INVALID) ; + vpCrvs[i]->GetCurve( j)->GetStartPoint( vPt[0]) ; + vpCrvs[i]->GetCurve( j)->GetMidPoint( vPt[1]) ; + vpCrvs[i]->GetCurve( j)->GetEndPoint( vPt[2]) ; + // classifico tali punti rispetto alla superficie + bool bOpenEdgeInStm = false ; + double dDist = 0. ; + for ( int nPt = 0 ; nPt < int( vPt.size()) && ! bOpenEdgeInStm ; ++ nPt) { + DistPointSurfTm DistPtStm( vPt[nPt], *pStm) ; + bOpenEdgeInStm = ( DistPtStm.IsPointInside() && + DistPtStm.GetDist( dDist) && + dDist > TOL_PT_INSIDE_STM) ; + } + // se curva aperta nel pezzo, la classifico + if ( bOpenEdgeInStm) { + vpCrvs[i]->SetCurveTempProp( j, TEMP_PROP_OPEN_EDGE_IN_RAW, 0) ; + bOpenCrvInPart = true ; + } } } } - } - // se non sono state trovate curve interne al pezzo, allora passo al bordo successivo - if ( ! bOpenCrvInPart) - continue ; - // ricostruisco il bordo mediante proprietà assegnate ( esistono lati aperti interni al pezzo) - PtrOwner pCrvNewBorder( CreateCurveComposite()) ; - if ( IsNull( pCrvNewBorder)) - return false ; - for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { - if ( ! pCrvNewBorder->AddCurve( Release( vpCrvs[i]))) + // se non sono state trovate curve interne al pezzo, allora passo al bordo successivo + if ( ! bOpenCrvInPart) + continue ; + // ricostruisco il bordo mediante proprietà assegnate ( esistono lati aperti interni al pezzo) + PtrOwner pCrvNewBorder( CreateCurveComposite()) ; + if ( IsNull( pCrvNewBorder)) return false ; - } - // recupero i nuovi tratti omogenei - GetHomogeneousParts( pCrvNewBorder, vpCrvs) ; - #if DEBUG_OPEN_EDGE_IN_RAW - DebugDrawOpenEdgesInRaw( vpCrvs, nLayBase) ; - #endif - // caso limite : tutta la curva è aperta ed interna alla regione - if ( int( vpCrvs.size()) == 1 && vpCrvs[0]->GetTempProp( 0) == TEMP_PROP_OPEN_EDGE_IN_RAW) { - // Offset del bordo del Chunk - OffsetCurve OffsCrv ; - OffsCrv.Make( pCrvNewBorder, m_dOpenInRawExtension, ICurve::OFF_FILLET) ; - pCrvNewBorder.Set( ConvertCurveToComposite( OffsCrv.GetLongerCurve())) ; - if ( IsNull( pCrvNewBorder) || ! pCrvNewBorder->IsValid()) - return false ; - // considero il bordo come tutto chiuso ( evito entrate da fuori dal pezzo) - for ( int i = 0 ; i < pCrvNewBorder->GetCurveCount() ; ++ i) - pCrvNewBorder->SetCurveTempProp( i, m_bOpenOutRaw ? TEMP_PROP_OPEN_EDGE : TEMP_PROP_CLOSE_EDGE, 0) ; - } - // se invece presenta solo alcuni tratti Open interni al pezzo - else { - // porto tutti i tratti ricavati nel piano XY per le intersezioni - for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) - vpCrvs[i]->ToLoc( frXY) ; - // scorro i tratti con proprietà uniformi - bool bOk = true ; - for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { - if ( ! bOk) { - // considero il tratto precedente come chiuso - for ( int j = 0 ; j < vpCrvs[i-1]->GetCurveCount() ; ++ j) - vpCrvs[i-1]->SetCurveTempProp( j, TEMP_PROP_CLOSE_EDGE, 0) ; - bOk = true ; - } - // se tratto Open interno al grezzo - if ( vpCrvs[i]->GetTempProp( 0) == TEMP_PROP_OPEN_EDGE_IN_RAW) { - // effettuo Offset del tratto in esame - OffsetCurve OffsCrv ; - OffsCrv.Make( vpCrvs[i], m_dOpenInRawExtension, ICurve::OFF_FILLET) ; - PtrOwner pCrvOffsOpenInPart( ConvertCurveToComposite( OffsCrv.GetLongerCurve())) ; - if ( IsNull( pCrvOffsOpenInPart) || ! pCrvOffsOpenInPart->IsValid()) { - bOk = false ; - continue ; + for ( int i = 0 ; i < ssize( vpCrvs) ; ++ i) { + if ( ! pCrvNewBorder->AddCurve( Release( vpCrvs[i]))) + return false ; + } + // recupero i nuovi tratti omogenei + GetHomogeneousParts( pCrvNewBorder, vpCrvs) ; + #if DEBUG_OPEN_EDGE_IN_RAW + DebugDrawOpenEdgesInRaw( vpCrvs, nLayBase) ; + #endif + // caso limite : tutta la curva è aperta ed interna alla regione + if ( ssize( vpCrvs) == 1 && vpCrvs[0]->GetTempProp( 0) == TEMP_PROP_OPEN_EDGE_IN_RAW) { + // Offset del bordo del Chunk + OffsetCurve OffsCrv ; + OffsCrv.Make( pCrvNewBorder, m_dOpenInRawExtension, ICurve::OFF_FILLET) ; + pCrvNewBorder.Set( ConvertCurveToComposite( OffsCrv.GetLongerCurve())) ; + if ( IsNull( pCrvNewBorder) || ! pCrvNewBorder->IsValid()) + return false ; + // considero il bordo come tutto chiuso ( evito entrate da fuori dal pezzo) + for ( int i = 0 ; i < pCrvNewBorder->GetCurveCount() ; ++ i) + pCrvNewBorder->SetCurveTempProp( i, m_bOpenOutRaw ? TEMP_PROP_OPEN_EDGE : TEMP_PROP_CLOSE_EDGE, 0) ; + } + // se invece presenta solo alcuni tratti Open interni al pezzo + else { + // porto tutti i tratti ricavati nel piano XY per le intersezioni + for ( int i = 0 ; i < ssize( vpCrvs) ; ++ i) + vpCrvs[i]->ToLoc( frXY) ; + // scorro i tratti con proprietà uniformi + bool bOk = true ; + for ( int i = 0 ; i < ssize( vpCrvs) ; ++ i) { + if ( ! bOk) { + // considero il tratto precedente come chiuso + for ( int j = 0 ; j < vpCrvs[i-1]->GetCurveCount() ; ++ j) + vpCrvs[i-1]->SetCurveTempProp( j, TEMP_PROP_CLOSE_EDGE, 0) ; + bOk = true ; } - // recupero tratto precedente e successivo - int nIndPrev = ( i > 0 ? i - 1 : int( vpCrvs.size()) - 1) ; - int nIndAfter = ( i < int( vpCrvs.size()) - 1 ? i + 1 : 0) ; - // estendo per sicurezza il tratto di Offset ( per angoli acuti con i tratti adiacenti) - pCrvOffsOpenInPart->ExtendStartByLen( LEN_EXTENSION) ; - pCrvOffsOpenInPart->ExtendEndByLen( LEN_EXTENSION) ; - #if DEBUG_OPEN_EDGE_IN_RAW - int _a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLayConstr, pCrvOffsOpenInPart->Clone()) ; - m_pGeomDB->SetMaterial( _a, ORANGE) ; - #endif - // definisco due segmenti lineari - PtrOwner pLinePrev( CreateCurveLine()) ; - PtrOwner pLineAfter( CreateCurveLine()) ; - if ( IsNull( pLinePrev) || IsNull( pLineAfter)) - return false ; - Point3d ptLineStart ; - Vector3d vtLineStart ; - vpCrvs[nIndPrev]->GetEndPoint( ptLineStart) ; - vpCrvs[nIndPrev]->GetEndDir( vtLineStart) ; - if ( ! pLinePrev->Set( ptLineStart, ptLineStart + LEN_EXTENSION * vtLineStart)) - return false ; - #if DEBUG_OPEN_EDGE_IN_RAW - _a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLayConstr, pLinePrev->Clone()) ; - m_pGeomDB->SetMaterial( _a, BLACK) ; - #endif - Point3d ptLineEnd ; - Vector3d vtLineEnd ; - vpCrvs[nIndAfter]->GetStartPoint( ptLineEnd) ; - vpCrvs[nIndAfter]->GetStartDir( vtLineEnd) ; - if ( ! pLineAfter->Set( ptLineEnd - LEN_EXTENSION * vtLineEnd, ptLineEnd)) - return false ; - #if DEBUG_OPEN_EDGE_IN_RAW - _a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLayConstr, pLineAfter->Clone()) ; - m_pGeomDB->SetMaterial( _a, BLACK) ; - #endif - // intersezione con primo segmento ( raccordo verso lato Open In Raw Offs) - Point3d ptIntS ; - double dUS_Trim_Line ; - double dUS_Trim_Offs ; - IntersCurveCurve ICC_Prev( *pLinePrev, *pCrvOffsOpenInPart) ; - if ( ICC_Prev.GetIntersCount() > 0 && ICC_Prev.GetIntersPointNearTo( 0, ptLineStart, ptIntS)) { - pLinePrev->GetParamAtPoint( ptIntS, dUS_Trim_Line) ; - pCrvOffsOpenInPart->GetParamAtPoint( ptIntS, dUS_Trim_Offs) ; - } - else { - bOk = false ; - continue ; - } - // intersezione con secondo segmento ( raccordo da Lato Open In Raw Offs) - Point3d ptIntE ; - double dUE_Trim_Line ; - double dUE_Trim_Offs ; - IntersCurveCurve ICC_After( *pLineAfter, *pCrvOffsOpenInPart) ; - if ( ICC_After.GetIntersCount() > 0 && ICC_After.GetIntersPointNearTo( 0, ptLineEnd, ptIntE)) { - pLineAfter->GetParamAtPoint( ptIntE, dUE_Trim_Line) ; - pCrvOffsOpenInPart->GetParamAtPoint( ptIntE, dUE_Trim_Offs) ; - } - else { - bOk = false ; - continue ; - } - // se le rette si intersecano tra loro prima di raccordarsi sull'Offset - if ( dUS_Trim_Offs > dUE_Trim_Offs) { - // recupero punto di intersezione tra le rette - IntersCurveCurve ILL( *pLinePrev, *pLineAfter) ; - Point3d ptIntersLL ; - if ( ILL.GetIntersCount() != 1 || - ! ILL.GetIntersPointNearTo( 0, ptLineStart, ptIntersLL) || - ! pLinePrev->GetParamAtPoint( ptIntersLL, dUS_Trim_Line) || - ! pLineAfter->GetParamAtPoint( ptIntersLL, dUE_Trim_Line)) { + // se tratto Open interno al grezzo + if ( vpCrvs[i]->GetTempProp( 0) == TEMP_PROP_OPEN_EDGE_IN_RAW) { + // effettuo Offset del tratto in esame + OffsetCurve OffsCrv ; + OffsCrv.Make( vpCrvs[i], m_dOpenInRawExtension, ICurve::OFF_FILLET) ; + PtrOwner pCrvOffsOpenInPart( ConvertCurveToComposite( OffsCrv.GetLongerCurve())) ; + if ( IsNull( pCrvOffsOpenInPart) || ! pCrvOffsOpenInPart->IsValid()) { bOk = false ; continue ; } - // pulisco la curva di Offset - pCrvOffsOpenInPart->Clear() ; + // recupero tratto precedente e successivo + int nIndPrev = ( i > 0 ? i - 1 : ssize( vpCrvs) - 1) ; + int nIndAfter = ( i < ssize( vpCrvs) - 1 ? i + 1 : 0) ; + // estendo per sicurezza il tratto di Offset ( per angoli acuti con i tratti adiacenti) + pCrvOffsOpenInPart->ExtendStartByLen( LEN_EXTENSION) ; + pCrvOffsOpenInPart->ExtendEndByLen( LEN_EXTENSION) ; + #if DEBUG_OPEN_EDGE_IN_RAW + int _a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLayConstr, pCrvOffsOpenInPart->Clone()) ; + m_pGeomDB->SetMaterial( _a, ORANGE) ; + #endif + // definisco due segmenti lineari + PtrOwner pLinePrev( CreateCurveLine()) ; + PtrOwner pLineAfter( CreateCurveLine()) ; + if ( IsNull( pLinePrev) || IsNull( pLineAfter)) + return false ; + Point3d ptLineStart ; + Vector3d vtLineStart ; + vpCrvs[nIndPrev]->GetEndPoint( ptLineStart) ; + vpCrvs[nIndPrev]->GetEndDir( vtLineStart) ; + if ( ! pLinePrev->Set( ptLineStart, ptLineStart + LEN_EXTENSION * vtLineStart)) + return false ; + #if DEBUG_OPEN_EDGE_IN_RAW + _a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLayConstr, pLinePrev->Clone()) ; + m_pGeomDB->SetMaterial( _a, BLACK) ; + #endif + Point3d ptLineEnd ; + Vector3d vtLineEnd ; + vpCrvs[nIndAfter]->GetStartPoint( ptLineEnd) ; + vpCrvs[nIndAfter]->GetStartDir( vtLineEnd) ; + if ( ! pLineAfter->Set( ptLineEnd - LEN_EXTENSION * vtLineEnd, ptLineEnd)) + return false ; + #if DEBUG_OPEN_EDGE_IN_RAW + _a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLayConstr, pLineAfter->Clone()) ; + m_pGeomDB->SetMaterial( _a, BLACK) ; + #endif + // intersezione con primo segmento ( raccordo verso lato Open In Raw Offs) + Point3d ptIntS ; + double dUS_Trim_Line ; + double dUS_Trim_Offs ; + IntersCurveCurve ICC_Prev( *pLinePrev, *pCrvOffsOpenInPart) ; + if ( ICC_Prev.GetIntersCount() > 0 && ICC_Prev.GetIntersPointNearTo( 0, ptLineStart, ptIntS)) { + pLinePrev->GetParamAtPoint( ptIntS, dUS_Trim_Line) ; + pCrvOffsOpenInPart->GetParamAtPoint( ptIntS, dUS_Trim_Offs) ; + } + else { + bOk = false ; + continue ; + } + // intersezione con secondo segmento ( raccordo da Lato Open In Raw Offs) + Point3d ptIntE ; + double dUE_Trim_Line ; + double dUE_Trim_Offs ; + IntersCurveCurve ICC_After( *pLineAfter, *pCrvOffsOpenInPart) ; + if ( ICC_After.GetIntersCount() > 0 && ICC_After.GetIntersPointNearTo( 0, ptLineEnd, ptIntE)) { + pLineAfter->GetParamAtPoint( ptIntE, dUE_Trim_Line) ; + pCrvOffsOpenInPart->GetParamAtPoint( ptIntE, dUE_Trim_Offs) ; + } + else { + bOk = false ; + continue ; + } + // se le rette si intersecano tra loro prima di raccordarsi sull'Offset + if ( dUS_Trim_Offs > dUE_Trim_Offs) { + // recupero punto di intersezione tra le rette + IntersCurveCurve ILL( *pLinePrev, *pLineAfter) ; + Point3d ptIntersLL ; + if ( ILL.GetIntersCount() != 1 || + ! ILL.GetIntersPointNearTo( 0, ptLineStart, ptIntersLL) || + ! pLinePrev->GetParamAtPoint( ptIntersLL, dUS_Trim_Line) || + ! pLineAfter->GetParamAtPoint( ptIntersLL, dUE_Trim_Line)) { + bOk = false ; + continue ; + } + // pulisco la curva di Offset + pCrvOffsOpenInPart->Clear() ; + } + // se le rette non si intersecano tra loro + else { + double dU_Offs_Trim_Start = 0. ; + pCrvOffsOpenInPart->GetParamAtPoint( ptIntS, dU_Offs_Trim_Start) ; + pCrvOffsOpenInPart->TrimStartAtParam( dU_Offs_Trim_Start) ; + double dU_Offs_Trim_End = 0. ; + pCrvOffsOpenInPart->GetParamAtPoint( ptIntE, dU_Offs_Trim_End) ; + pCrvOffsOpenInPart->TrimEndAtParam( dU_Offs_Trim_End) ; + } + // aggiorno tutte le curve e le loro proprietà + pLinePrev->TrimEndAtParam( dUS_Trim_Line) ; + pLinePrev->SetTempProp( vpCrvs[nIndPrev]->GetTempProp( 0), 0) ; + vpCrvs[nIndPrev]->AddCurve( Release( pLinePrev), true) ; + pLineAfter->TrimStartAtParam( dUE_Trim_Line) ; + pLineAfter->SetTempProp( vpCrvs[nIndAfter]->GetTempProp( 0), 0) ; + vpCrvs[nIndAfter]->AddCurve( Release( pLineAfter), false) ; + vpCrvs[i].Set( Release( pCrvOffsOpenInPart)) ; + // assegno proprietà di lato aperto/chiuso + for ( int j = 0 ; j < vpCrvs[i]->GetCurveCount() ; ++ j) + vpCrvs[i]->SetCurveTempProp( j, m_bOpenOutRaw ? TEMP_PROP_OPEN_EDGE : TEMP_PROP_CLOSE_EDGE, 0) ; } - // se le rette non si intersecano tra loro - else { - double dU_Offs_Trim_Start = 0. ; - pCrvOffsOpenInPart->GetParamAtPoint( ptIntS, dU_Offs_Trim_Start) ; - pCrvOffsOpenInPart->TrimStartAtParam( dU_Offs_Trim_Start) ; - double dU_Offs_Trim_End = 0. ; - pCrvOffsOpenInPart->GetParamAtPoint( ptIntE, dU_Offs_Trim_End) ; - pCrvOffsOpenInPart->TrimEndAtParam( dU_Offs_Trim_End) ; - } - // aggiorno tutte le curve e le loro proprietà - pLinePrev->TrimEndAtParam( dUS_Trim_Line) ; - pLinePrev->SetTempProp( vpCrvs[nIndPrev]->GetTempProp( 0), 0) ; - vpCrvs[nIndPrev]->AddCurve( Release( pLinePrev), true) ; - pLineAfter->TrimStartAtParam( dUE_Trim_Line) ; - pLineAfter->SetTempProp( vpCrvs[nIndAfter]->GetTempProp( 0), 0) ; - vpCrvs[nIndAfter]->AddCurve( Release( pLineAfter), false) ; - vpCrvs[i].Set( Release( pCrvOffsOpenInPart)) ; - // assegno proprietà di lato aperto/chiuso - for ( int j = 0 ; j < vpCrvs[i]->GetCurveCount() ; ++ j) - vpCrvs[i]->SetCurveTempProp( j, m_bOpenOutRaw ? TEMP_PROP_OPEN_EDGE : TEMP_PROP_CLOSE_EDGE, 0) ; } + // ricostrusico il nuovo bordo + pCrvNewBorder->Clear() ; + #if DEBUG_OPEN_EDGE_IN_RAW + DebugDrawOpenEdgesInRaw( vpCrvs, nLayResult) ; + #endif + for ( int i = 0 ; i < ssize( vpCrvs) ; ++ i) { + if ( ! IsNull( vpCrvs[i]) && vpCrvs[i]->IsValid() && vpCrvs[i]->GetCurveCount() > 0) { + if ( ! pCrvNewBorder->AddCurve( Release( vpCrvs[i]))) + return false ; + } + } + // lo riporto nel frame globale + pCrvNewBorder->ToGlob( frXY) ; } - // ricostrusico il nuovo bordo - pCrvNewBorder->Clear() ; - #if DEBUG_OPEN_EDGE_IN_RAW - DebugDrawOpenEdgesInRaw( vpCrvs, nLayResult) ; - #endif - for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { - if ( ! IsNull( vpCrvs[i]) && vpCrvs[i]->IsValid() && vpCrvs[i]->GetCurveCount() > 0) { - if ( ! pCrvNewBorder->AddCurve( Release( vpCrvs[i]))) + // aggiorno il vettore dei bordi e il Flag di modifica del Chunk corrente + if ( ! vCrvNewBorder[nL].Set( Release( pCrvNewBorder))) + return false ; + bModifSfr = true ; + bModifChunk = true ; + } + // se il chunk ha subito modifiche ricostruisco i suoi Loops + if ( bModifChunk) { + for ( int nL = 0 ; nL < nLoops ; ++ nL) { + if ( IsNull( vCrvNewBorder[nL]) || ! vCrvNewBorder[nL]->IsValid()) { + if ( ! vCrvNewBorder[nL].Set( ConvertCurveToComposite( vChunks[nC]->GetLoop( 0, nL)))) return false ; } } - // lo riporto nel frame globale - pCrvNewBorder->ToGlob( frXY) ; + vChunks[nC]->Clear() ; + for ( int nL = 0 ; nL < nLoops ; ++ nL) { + if ( ( nL == 0 && ! vChunks[nC]->AddExtLoop( Release( vCrvNewBorder[nL]))) || + ( nL > 0 && ! vChunks[nC]->AddIntLoop( Release( vCrvNewBorder[nL])))) + return false ; + } } - // ricostruisco il Chunk con il nuovo bordo - PtrOwner pNewChunk( CreateSurfFlatRegion()) ; - if ( IsNull( pNewChunk) || ! pNewChunk->AddExtLoop( Release( pCrvNewBorder))) - return false ; - for ( int nI = 1 ; nI < vChunks[nC]->GetLoopCount( 0) ; ++ nI) { - if ( ! pNewChunk->AddIntLoop( vChunks[nC]->GetLoop( 0, nI))) - return false ; - } - vChunks[nC].Set( Release( pNewChunk)) ; - bModifSfr = true ; } // recupero la regione finale @@ -3395,7 +3407,7 @@ PocketingNT::ManageOpenEdges( ISurfFlatRegion* pSfr, const ISurfTriMesh* pStm) PtrOwner pSfrTmp( CreateSurfFlatRegion()) ; if ( IsNull( pSfrTmp)) return false ; - for ( auto& pSfrC : vChunks) { + for ( PtrOwner& pSfrC : vChunks) { if ( pSfrTmp->IsValid()) pSfrTmp->Add( *pSfrC) ; else diff --git a/SurfFinishing.cpp b/SurfFinishing.cpp index 0df54e1..fe93467 100644 --- a/SurfFinishing.cpp +++ b/SurfFinishing.cpp @@ -1997,9 +1997,11 @@ SurfFinishing::ProcessSfr( int nPathId, int nPvId, int nClId) return true ; // tengo una copia della regione attuale, nel caso di finitura Optimal - PtrOwner pSfrCntOrig( CloneSurfFlatRegion( pSfrCnt)) ; - if ( IsNull( pSfrCntOrig) || ! pSfrCntOrig->IsValid()) - return false ; + PtrOwner pSfrCntOrig( nullptr) ; + if ( m_Params.m_nSubType == SURFFIN_SUB_OPTIMAL) { + if ( ! pSfrCntOrig.Set( CloneSurfFlatRegion( pSfrCnt)) || ! pSfrCntOrig->IsValid()) + return false ; + } // se richiesto, elimino le parti al massimo affondamento bool bSkipMaxDown = true ; @@ -2275,7 +2277,7 @@ SurfFinishing::AddZigZag( ICAvToolSurfTm* pCAvTlStm, const Frame3d& frSurf, cons // calcolo lo ZigZag ICRVCOMPOPOVECTOR vpCrvs ; if ( ! CalcPocketing( pSfrCnt, m_TParams.m_dDiam / 2., 0., m_Params.m_dSideStep, m_Params.m_dSideAngle, 5., - POCKET_ZIGZAG, false, false, false, true, true, false, false, P_INVALID, nullptr, true, m_Params.m_dSideStep, + POCKET_ZIGZAG, false, false, m_Params.m_bInvert, true, true, false, false, P_INVALID, nullptr, true, m_Params.m_dSideStep, GetLeadInType(), m_Params.m_dLiTang, 0., GetLeadOutType(), m_Params.m_dLoTang, false, 0., 0., false, vpCrvs)) { m_pMchMgr->SetLastError( 3125, "Error in SurfFinishing : CalcPocketing failed") ; return false ; @@ -2303,7 +2305,7 @@ SurfFinishing::AddOneWay( ICAvToolSurfTm* pCAvTlStm, const Frame3d& frSurf, cons // calcolo OneWay ICRVCOMPOPOVECTOR vpCrvs ; if ( ! CalcPocketing( pSfrCnt, m_TParams.m_dDiam / 2., 0., m_Params.m_dSideStep, m_Params.m_dSideAngle, 5., - POCKET_ONEWAY, false, false, false, true, true, false, false, P_INVALID, nullptr, true, m_Params.m_dSideStep, + POCKET_ONEWAY, false, false, m_Params.m_bInvert, true, true, false, false, P_INVALID, nullptr, true, m_Params.m_dSideStep, GetLeadInType(), m_Params.m_dLiTang, 0., GetLeadOutType(), m_Params.m_dLoTang, false, 0., 0., false, vpCrvs)) { m_pMchMgr->SetLastError( 3125, "Error in SurfFinishing : CalcPocketing failed") ; return false ; @@ -2331,7 +2333,7 @@ SurfFinishing::AddSpiral( ICAvToolSurfTm* pCAvTlStm, const Frame3d& frSurf, cons int nType = ( bInVsOut ? POCKET_SPIRALIN : POCKET_SPIRALOUT) ; ICRVCOMPOPOVECTOR vpCrvs ; if ( ! CalcPocketing( pSfrCnt, m_TParams.m_dDiam / 2., 0., m_Params.m_dSideStep, m_Params.m_dSideAngle, 5., - nType, false, false, false, true, true, false, false, P_INVALID, nullptr, true, m_Params.m_dSideStep, + nType, false, false, m_Params.m_bInvert, true, true, false, false, P_INVALID, nullptr, true, m_Params.m_dSideStep, GetLeadInType(), m_Params.m_dLiTang, 0., GetLeadOutType(), m_Params.m_dLoTang, false, 0., 0., false, vpCrvs)) { m_pMchMgr->SetLastError( 3125, "Error in SurfFinishing : CalcPocketing failed") ; return false ; @@ -2933,7 +2935,7 @@ SurfFinishing::CreateZConstPaths( ICAvToolSurfTm* pCAvTlStm, const Frame3d& frSu // --- se ho una sola curva, allora controllo se posso cambiare il suo punto d'inizio // nel caso non sia la prima in assoluto [ -> controllo ptRef] - if ( int( vIndependentCurveGroup[nPath].size()) == 1) { + if ( ssize( vIndependentCurveGroup[nPath]) == 1) { if ( ptRef.IsValid()) { // --- se la curva di bordo singola è aperta if ( ! vIndependentCurveGroup[nPath][0]->IsClosed()) { @@ -3031,6 +3033,7 @@ SurfFinishing::CreateZConstPaths( ICAvToolSurfTm* pCAvTlStm, const Frame3d& frSu PtrOwner pLineLinkProj( ProjectCurveOnPlane( *pLineLink, plProjection)) ; if ( IsNull( pLineLinkProj) || ! pLineLinkProj->IsValid()) return false ; + // effettuo la classificazione CRVCVECTOR ccClass ; if ( ! pSfrClass->GetCurveClassification( *pLineLinkProj, EPS_SMALL, ccClass)) @@ -3082,7 +3085,7 @@ SurfFinishing::CreateZConstPaths( ICAvToolSurfTm* pCAvTlStm, const Frame3d& frSu if ( ! vCompoLink[nCompo + 1]->IsValid()) continue ; // il link rimane inizializzato e non valido ( 0 curve) - // porto il link sul piano della curva più in alto tra le due + // porto il link sul piano della curva più in basso tra le due Point3d ptCheck ; vIndependentCurveGroup[nPath][nCompo + 1]->GetStartPoint( ptCheck) ; double dSfrDistNext = DistPointPlane( ptCheck, plProjection) ; @@ -3101,7 +3104,7 @@ SurfFinishing::CreateZConstPaths( ICAvToolSurfTm* pCAvTlStm, const Frame3d& frSu int nLay = GDB_ID_NULL ; Color myCol = INVISIBLE ; #endif - for ( int nCompo = 0 ; nCompo < ssize( vIndependentCurveGroup[nPath]) - 1 ; ++ nCompo) { + for ( int nCompo = 0 ; nCompo < ssize( vIndependentCurveGroup[nPath]) ; ++ nCompo) { if ( IsNull( vCompoLink[nCompo]) || ! vCompoLink[nCompo]->IsValid()) { #if ENABLE_ZCONST_PATH_DEBUG nLay = m_pGeomDB->AddGroup( GDB_ID_NULL, nGrp, GLOB_FRM) ; @@ -3134,10 +3137,8 @@ SurfFinishing::CreateZConstPaths( ICAvToolSurfTm* pCAvTlStm, const Frame3d& frSu //---------------------------------------------------------------------------- bool -SurfFinishing::CalcZConstProjectedLink( ICAvToolSurfTm* pCAvTlStm, const Frame3d& frPocket, - const Frame3d& frSurf, const Vector3d& vtTool, double dDepth, - const Point3d ptStart_forced, const Point3d ptEnd_forced, - ICurveComposite* pCrv) const +SurfFinishing::CalcZConstProjectedLink( ICAvToolSurfTm* pCAvTlStm, const Frame3d& frPocket, const Frame3d& frSurf, const Vector3d& vtTool, + double dDepth, const Point3d ptStart_forced, const Point3d ptEnd_forced, ICurveComposite* pCrv) const { // funzione per proiettare una curva su una supericie trimesh passando per la silhouette // controllo dei parametri @@ -5416,25 +5417,9 @@ SurfFinishing::AddPencil( ICAvToolSurfTm* pCAvTlStm, const SURFLOCALVECTOR& vSrf //---------------------------------------------------------------------------- bool -SurfFinishing::CalcOptimalZigZagCurves( const ISurfFlatRegion* pSfrLoc, const Frame3d& frSurf, const Vector3d& vtTool, +SurfFinishing::CalcOptimalZigZagCurves( ISURFFRPOVECTOR& vSfrZigZagProj, const Frame3d& frSurf, const Vector3d& vtTool, double dDepth, ICAvToolSurfTm* pCAvTlStm, VECTORPATHS& vPaths) const { - // se la superficie non è valida, non restituisco nulla - if ( pSfrLoc == nullptr || ! pSfrLoc->IsValid()) - return true ; - - // mi assicuro di non uscire dalla superficie originale - PtrOwner pMySfrZigZag( CloneSurfFlatRegion( pSfrLoc)) ; - if ( IsNull( pMySfrZigZag) || ! pMySfrZigZag->IsValid()) - return false ; - // imposto i lati chiusi - for ( int nC = 0 ; nC < pMySfrZigZag->GetChunkCount() ; ++ nC) { - for ( int nL = 0 ; nL < pMySfrZigZag->GetLoopCount( nC) ; ++ nL) { - for ( int nU = 0 ; nU < pMySfrZigZag->GetLoopCurveCount( nC, nL) ; ++ nU) - pMySfrZigZag->SetCurveTempProp( nC, nL, nU, 0, TEMP_PROP_CLOSE_EDGE) ; - } - } - #if ENABLE_OPTIMAL_DEBUG int nGrp = m_pGeomDB->AddGroup( GDB_ID_NULL, GDB_ID_ROOT, GLOB_FRM) ; m_pGeomDB->SetName( nGrp, "ZigZag") ; @@ -5444,94 +5429,103 @@ SurfFinishing::CalcOptimalZigZagCurves( const ISurfFlatRegion* pSfrLoc, const Fr int nLaySfrProj = m_pGeomDB->AddGroup( GDB_ID_NULL, nGrp, GLOB_FRM) ; m_pGeomDB->SetName( nLaySfrProj, "SfrProj") ; m_pGeomDB->SetStatus( nLaySfrProj, GDB_ST_OFF) ; - int nSfrProjId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLaySfrProj, pMySfrZigZag->Clone()) ; - m_pGeomDB->SetMaterial( nSfrProjId, Color( 1., 0., 0., .5)) ; #endif - // controllo se richiesto altro tipo di lavorazione - int nSubType = POCKET_ZIGZAG ; - if ( GetValInNotes( m_Params.m_sUserNotes, UN_OPTIMALTYPE, nSubType)) { - // ammessi ZIG_ZAG, SPIRAL_IN, SPIRAL_OUT - if ( nSubType != POCKET_ZIGZAG && nSubType != POCKET_SPIRALIN && nSubType != POCKET_SPIRALOUT) - nSubType = POCKET_ZIGZAG ; - } - - // per ogni Chunk della superficie a ZigZag, calcolo le curve di lavoro - ICRVCOMPOPOVECTOR vCrvCompoZigZag ; - for ( int nC = 0 ; nC < pMySfrZigZag->GetChunkCount() ; ++ nC) { - // recupero il Chunk corrente - PtrOwner pSfrChunk( pMySfrZigZag->CloneChunk( nC)) ; - if ( IsNull( pSfrChunk) || ! pMySfrZigZag->IsValid()) - return false ; - // recupero la miglior direzione di orientamento per le curve a ZigZag - // --- approssimo il Loop esterno con una PolyLine - PolyLine PL ; - pSfrChunk->ApproxLoopWithLines( 0, 0, EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_STD, PL) ; - // --- porto la PolyLine sul piano locale XY - Point3d ptC ; pSfrChunk->GetCentroid( ptC) ; - Frame3d frXY ; - if ( ! frXY.Set( ptC, pSfrChunk->GetNormVersor())) - return false ; - PL.ToLoc( frXY) ; - pSfrChunk->ToGlob( frSurf) ; - // eseguo il calcolo della lavorazione ZigZag - ICRVCOMPOPOVECTOR vpCrvs ; - if ( ! CalcPocketing( pSfrChunk, m_TParams.m_dDiam / 2., 0., m_Params.m_dSideStep, m_Params.m_dSideAngle, 5., - nSubType, false, false, false, true, true, false, false, P_INVALID, nullptr, true, m_Params.m_dSideStep, - GetLeadInType(), m_Params.m_dLiTang, 0., GetLeadOutType(), m_Params.m_dLoTang, false, 0., 0., false, vpCrvs)) { - m_pMchMgr->SetLastError( 3125, "Error in SurfFinishing : CalcPocketing failed") ; - return false ; - } - // memorizzo le curve ricavate - for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) - vCrvCompoZigZag.emplace_back( Release( vpCrvs[i])) ; - } - - // porto i dati geometrici in locale alle superfici ( proeittando) - Vector3d vtAxL = vtTool ; - vtAxL.ToLoc( frSurf) ; - Vector3d vtMoveL = vtAxL ; - const double MIN_DIST = 1. ; - const double MAX_DIST = 50. ; - double dDist = Clamp( m_Params.m_dApprox, MIN_DIST, MAX_DIST) ; - - // ciclo sui percorsi ricavati - double dProgCoeff = 1. / max( int( vCrvCompoZigZag.size()), 1) ; - for ( int i = 0 ; i < int( vCrvCompoZigZag.size()) ; ++ i) { - // se non valida, passo alla successiva - if ( IsNull( vCrvCompoZigZag[i]) || ! vCrvCompoZigZag[i]->IsValid()) + // Scorro le superfici presenti + for ( ISurfFlatRegion* pSfrZigZag : vSfrZigZagProj) { + if ( pSfrZigZag == nullptr || ! pSfrZigZag->IsValid()) continue ; - // correggo il percorso per non interferire con le superfici - if ( pCAvTlStm != nullptr) { - // approssimo la curva con una polilinea - PolyLine PL ; - if ( ! vCrvCompoZigZag[i]->ApproxWithLines( LIN_TOL_STD, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL) || - ! PL.AdjustForMaxSegmentLen( dDist)) - return false ; - PL.ToLoc( frSurf) ; - // traslo della lunghezza utensile diminuita dell'affondamento - PL.Translate( vtAxL * ( m_TParams.m_dLen - dDepth)) ; - // eseguo CAv - if ( ! pCAvTlStm->TestPath( PL.GetUPointList(), vtAxL, vtMoveL, m_Params.m_dApprox, ( i + 1) * dProgCoeff)) - return false ; - // contro-traslo della lunghezza utensile - PL.Translate( - vtAxL * m_TParams.m_dLen) ; - // elimino i punti allineati - PL.RemoveAlignedPoints( 0.8 * m_Params.m_dApprox) ; - // creo una curva composita a partire dalla polilinea - PtrOwner pCrvCompo( CreateCurveComposite()) ; - if ( IsNull( pCrvCompo) || ! pCrvCompo->FromPolyLine( PL)) - return false ; - #if ENABLE_OPTIMAL_DEBUG - int nCrvId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLayCrv, CloneCurveComposite( pCrvCompo)) ; - m_pGeomDB->SetMaterial( nCrvId, RED) ; - #endif + // tutti i lati della superficie vengono considerati come chiusi, quindi per portare l'utensile lungo + // i bordi estendo la superficie del raggio utensile + if ( ! pSfrZigZag->Offset( m_TParams.m_dDiam / 2. - 5. * EPS_SMALL, ICurve::OFF_FILLET)) + return false ; + for ( int nC = 0 ; nC < pSfrZigZag->GetChunkCount() ; ++ nC) { + for ( int nL = 0 ; nL < pSfrZigZag->GetLoopCount( nC) ; ++ nL) { + for ( int nU = 0 ; nU < pSfrZigZag->GetLoopCurveCount( nC, nL) ; ++ nU) + pSfrZigZag->SetCurveTempProp( nC, nL, nU, 0, TEMP_PROP_CLOSE_EDGE) ; + } + } - // definisco un nuovo percorso - vPaths.resize( vPaths.size() + 1) ; - vPaths.back().nType = SURFFIN_SUB_ZIGZAG ; - vPaths.back().pCrvPath.Set( pCrvCompo) ; + #if ENABLE_OPTIMAL_DEBUG + int nSfrProjId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLaySfrProj, pSfrZigZag->Clone()) ; + m_pGeomDB->SetMaterial( nSfrProjId, Color( 1., 0., 0., .5)) ; + #endif + + // controllo se richiesto altro tipo di lavorazione + int nSubType = POCKET_ZIGZAG ; + if ( GetValInNotes( m_Params.m_sUserNotes, UN_OPTIMALTYPE, nSubType)) { + // ammessi ZIG_ZAG, SPIRAL_IN, SPIRAL_OUT + if ( nSubType != POCKET_ZIGZAG && nSubType != POCKET_SPIRALIN && nSubType != POCKET_SPIRALOUT) + nSubType = POCKET_ZIGZAG ; + } + + // per ogni Chunk della superficie a ZigZag, calcolo le curve di lavoro + ICRVCOMPOPOVECTOR vCrvCompoZigZag ; + for ( int nC = 0 ; nC < pSfrZigZag->GetChunkCount() ; ++ nC) { + // recupero il Chunk corrente + PtrOwner pSfrChunk( pSfrZigZag->CloneChunk( nC)) ; + if ( IsNull( pSfrChunk) || ! pSfrZigZag->IsValid()) + return false ; + // porto il Chunk in Globale + pSfrChunk->ToGlob( frSurf) ; + // eseguo il calcolo della lavorazione ZigZag + ICRVCOMPOPOVECTOR vpCrvs ; + if ( ! CalcPocketing( pSfrChunk, m_TParams.m_dDiam / 2., 0., m_Params.m_dSideStep, m_Params.m_dSideAngle, 5., + nSubType, false, false, false, true, true, false, false, P_INVALID, nullptr, true, m_Params.m_dSideStep, + GetLeadInType(), m_Params.m_dLiTang, 0., GetLeadOutType(), m_Params.m_dLoTang, false, 0., 0., false, vpCrvs)) { + m_pMchMgr->SetLastError( 3125, "Error in SurfFinishing : CalcPocketing failed") ; + return false ; + } + // memorizzo le curve ricavate + for ( int i = 0 ; i < ssize( vpCrvs) ; ++ i) + vCrvCompoZigZag.emplace_back( Release( vpCrvs[i])) ; + } + + // porto i dati geometrici in locale alle superfici ( proeittando) + Vector3d vtAxL = vtTool ; + vtAxL.ToLoc( frSurf) ; + Vector3d vtMoveL = vtAxL ; + const double MIN_DIST = 1. ; + const double MAX_DIST = 50. ; + double dDist = Clamp( m_Params.m_dApprox, MIN_DIST, MAX_DIST) ; + + // ciclo sui percorsi ricavati + double dProgCoeff = 1. / max( static_cast( ssize( vCrvCompoZigZag)), 1) ; + for ( int i = 0 ; i < ssize( vCrvCompoZigZag) ; ++ i) { + // se non valida, passo alla successiva + if ( IsNull( vCrvCompoZigZag[i]) || ! vCrvCompoZigZag[i]->IsValid()) + continue ; + // correggo il percorso per non interferire con le superfici + if ( pCAvTlStm != nullptr) { + // approssimo la curva con una polilinea + PolyLine PL ; + if ( ! vCrvCompoZigZag[i]->ApproxWithLines( LIN_TOL_STD, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL) || + ! PL.AdjustForMaxSegmentLen( dDist)) + return false ; + PL.ToLoc( frSurf) ; + // traslo della lunghezza utensile diminuita dell'affondamento + PL.Translate( vtAxL * ( m_TParams.m_dLen - dDepth)) ; + // eseguo CAv + if ( ! pCAvTlStm->TestPath( PL.GetUPointList(), vtAxL, vtMoveL, m_Params.m_dApprox, ( i + 1) * dProgCoeff)) + return false ; + // contro-traslo della lunghezza utensile + PL.Translate( - vtAxL * m_TParams.m_dLen) ; + // elimino i punti allineati + PL.RemoveAlignedPoints( 0.8 * m_Params.m_dApprox) ; + // creo una curva composita a partire dalla polilinea + PtrOwner pCrvCompo( CreateCurveComposite()) ; + if ( IsNull( pCrvCompo) || ! pCrvCompo->FromPolyLine( PL)) + return false ; + #if ENABLE_OPTIMAL_DEBUG + int nCrvId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLayCrv, CloneCurveComposite( pCrvCompo)) ; + m_pGeomDB->SetMaterial( nCrvId, RED) ; + #endif + // definisco un nuovo percorso + vPaths.resize( vPaths.size() + 1) ; + vPaths.back().nType = SURFFIN_SUB_ZIGZAG ; + vPaths.back().pCrvPath.Set( pCrvCompo) ; + } } } @@ -5540,15 +5534,13 @@ SurfFinishing::CalcOptimalZigZagCurves( const ISurfFlatRegion* pSfrLoc, const Fr //---------------------------------------------------------------------------- bool -SurfFinishing::CalcOptimalZConstCurves( const ISurfFlatRegion* pSfrLoc, const SURFLOCALVECTOR& vSrfLoc, - const Frame3d& frSurf, const Vector3d& vtTool, double dAngDegSplit, - double dAngDegTol, double dDepth, ICAvToolSurfTm* pCAvTlStm, - VECTORPATHS& vPaths, ISurfFlatRegion* pSfrProj) const +SurfFinishing::CalcOptimalZConstCurves( const ISurfFlatRegion* pSfrLoc, const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf, + const Vector3d& vtTool, double dAngDegSplit, double dAngDegTol, double dDepth, + ICAvToolSurfTm* pCAvTlStm, VECTORPATHS& vPaths) const { // se la superficie non è valida, non restituisco nulla if ( pSfrLoc == nullptr || ! pSfrLoc->IsValid()) return true ; - pSfrProj->Clear() ; // mi assicuro di non uscire dalla superficie originale PtrOwner pMySfrZConst( CloneSurfFlatRegion( pSfrLoc)) ; @@ -5564,7 +5556,7 @@ SurfFinishing::CalcOptimalZConstCurves( const ISurfFlatRegion* pSfrLoc, const SU // inizializzo la classe di calcolo delle silhouette CISURFTMPVECTOR vpStm ; vpStm.reserve( vSrfLoc.size()) ; // scorro le superfici - for ( int i = 0 ; i < int( vSrfLoc.size()) ; ++ i) { + for ( int i = 0 ; i < ssize( vSrfLoc) ; ++ i) { // recupero la superficie const ISurf* pSurf = GetSurf( vSrfLoc[i].Get()) ; if ( pSurf == nullptr || ! pSurf->IsValid()) @@ -5599,8 +5591,8 @@ SurfFinishing::CalcOptimalZConstCurves( const ISurfFlatRegion* pSfrLoc, const SU // inizializzo classe di calcolo per le curve a ZConst con utensile corrente PtrOwner pCavParSilh( CreateCAvParSilhouettesSurfTm()) ; if ( IsNull( pCavParSilh) || - ! pCavParSilh->SetData( vpStm, frSfr, SILH_SAMPLING, m_TParams.m_dSideAng, m_TParams.m_dDiam, - m_TParams.m_dCornRad, m_TParams.m_dMaxMat, GetOffsR(), dDepth)) + ! pCavParSilh->SetData( vpStm, frSfr, SILH_SAMPLING, m_TParams.m_dSideAng, m_TParams.m_dDiam, m_TParams.m_dCornRad, + m_TParams.m_dMaxMat, GetOffsR(), dDepth)) return false ; // recupero le curve singole definite dal bordo della Silhouette @@ -5617,7 +5609,6 @@ SurfFinishing::CalcOptimalZConstCurves( const ISurfFlatRegion* pSfrLoc, const SU // --- versore direzione utensile e versore direzione movimento Vector3d vtAxL = vtTool ; vtAxL.ToLoc( frSurf) ; - Vector3d vtMoveL = vtAxL ; // --- tolleranza di campionamento per punti della PolyLine const double MIN_DIST = 1. ; const double MAX_DIST = 50. ; @@ -5657,7 +5648,7 @@ SurfFinishing::CalcOptimalZConstCurves( const ISurfFlatRegion* pSfrLoc, const SU #endif // scorro i piani di ZConst ricavati... - for ( int i = 0 ; i < int( vvCrvCompo.size()) ; ++ i) { + for ( int i = 0 ; i < ssize( vvCrvCompo) ; ++ i) { // Dalle curve si ricavano le PolyLine corrispondeti e vengono suddivise in 3 categorie : // - PolyLine valide : definite da punti di campionamento consecutivi dove esiste una normale di // di collisione con angolo rispetto a vtTool > dSplitAngDeg @@ -5671,8 +5662,8 @@ SurfFinishing::CalcOptimalZConstCurves( const ISurfFlatRegion* pSfrLoc, const SU // la distanza dalla Sfr è memorizzata nel primo TempParam [*] double dSfrDist = 0. ; - // per il piano corrente scorro le curve di Silhouette ricavate... - for ( int j = 0 ; j < int( vvCrvCompo[i].size()) ; ++ j) { + // per il piano corrente scorro le curve di Silhouette ricavate + for ( int j = 0 ; j < ssize( vvCrvCompo[i]) ; ++ j) { // se curva non valida, passo alla successiva if ( IsNull( vvCrvCompo[i][j]) || ! vvCrvCompo[i][j]->IsValid()) continue ; @@ -5690,44 +5681,39 @@ SurfFinishing::CalcOptimalZConstCurves( const ISurfFlatRegion* pSfrLoc, const SU return false ; // scorro i punti della PolyLine e li calssifico - for ( POINTU& ptU : PL.GetUPointList()) { + for ( const POINTU& ptU : PL.GetUPointList()) { // La curva di Silhouette, una volta approssimata, può presentare alcuni punti quel poco // che basta più lontani dalla superficie per non ricavare alcuna collisione. - // NB. le curve ricavate sono approssimate, mergiate e leggermente smussate. - // --> In questo caso sposto leggermente il punto verso la superficie - // NB. Le curve di Silhoette per definizione sono orientate lasciando le vStm alla loro destra + // NB. Le curve ricavate sono approssimate, mergiate e leggermente smussate. + // --> In questo caso sposto leggermente il punto verso la superficie ( algoritmo iterativo fino a collisione individuata) + // NB. Le curve di Silhouette per definizione sono orientate lasciando le vStm alla loro destra int nPointType = DISCARD ; - double dPar ; - Point3d ptShift ; - Vector3d vtIn ; - VCT3DVECTOR vVtN ; - if ( vvCrvCompo[i][j]->GetParamAtPoint( ptU.first, dPar, 10 * EPS_SMALL) && - vvCrvCompo[i][j]->GetPointD1D2( dPar, ICurve::FROM_MINUS, ptShift, &vtIn)) { - ptShift.Translate( - vtAxL * m_TParams.m_dLen) ; // per ricavare la colisione - vtIn.Normalize() ; - vtIn.Rotate( vtAxL, ! m_Params.m_bInvert ? ANG_RIGHT : - ANG_RIGHT) ; - const double MAXSHIFT = SILH_SAMPLING ; - const int SAMPLETOL = 10 ; - double dShift = MAXSHIFT / ( 1. * SAMPLETOL) ; - for ( int i = 1 ; i < SAMPLETOL && vVtN.empty() ; ++ i) { - ptShift.Translate( vtIn * ( i * dShift)) ; // leggero spostamento del punto - double dToTDist = 0. ; - // calcolo la collisione - if ( ! pCAvTlStm->TestPositionAdv( ptShift, vtAxL, vtMoveL, dToTDist, vVtN)) - return false ; - // classificazione del punto - if ( ! vVtN.empty()) { - for ( Vector3d& vtN : vVtN) { - if ( abs( vtN * vtAxL) < dCosLimit) { - nPointType = VALID ; - break ; - } - else if ( abs( vtN * vtAxL) < dCosUpperBound) - nPointType = AMBIGUOUS ; - } + VCT3DLIST vvtN ; + double dMinDist = INFINITO - 1 ; + for ( int nSurf = 0 ; nSurf < ssize( vpStm) ; ++ nSurf) { + DistPointSurfTm distPtSurfTm( ptU.first, *vpStm[nSurf]) ; + double dMyDist = INFINITO - 2 ; + if ( distPtSurfTm.GetDist( dMyDist) && dMyDist < dMinDist) { + dMinDist = dMyDist ; + INTVECTOR vTriaMinDist ; distPtSurfTm.GetMinDistTriaIndices( vTriaMinDist) ; + Triangle3d Tria ; + for ( const int& nTria : vTriaMinDist) { + vpStm[nSurf]->GetTriangle( nTria, Tria) ; + vvtN.push_back( Tria.GetN()) ; } } } + // classificazione del punto + if ( ! vvtN.empty()) { + for ( const Vector3d& vtN : vvtN) { + if ( abs( vtN * vtAxL) < dCosLimit) { + nPointType = VALID ; + break ; + } + else if ( abs( vtN * vtAxL) < dCosUpperBound) + nPointType = AMBIGUOUS ; + } + } #if ENABLE_OPTIMAL_DEBUG PtrOwner pt( CreateGeoPoint3d()) ; @@ -5735,7 +5721,7 @@ SurfFinishing::CalcOptimalZConstCurves( const ISurfFlatRegion* pSfrLoc, const SU int a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLayPt, Release( pt)) ; m_pGeomDB->SetMaterial( a, nPointType == VALID ? GREEN : nPointType == AMBIGUOUS ? LIME : BLACK) ; - for ( Vector3d& vtN : vVtN) { + for ( Vector3d& vtN : vvtN) { PtrOwner vt( CreateGeoVector3d()) ; vt->Set( vtN) ; vt->Translate( ptU.first - ORIG) ; @@ -5762,7 +5748,7 @@ SurfFinishing::CalcOptimalZConstCurves( const ISurfFlatRegion* pSfrLoc, const SU // costruisco le PolyLine definitive bool bFirst = true ; - int nPL = int( vTypePL.size()) ; + int nPL = ssize( vTypePL) ; for ( int nInd = 0 ; nInd < nPL ; ++ nInd) { // se tratto valido if ( vTypePL[nInd].first == VALID) { @@ -5775,29 +5761,28 @@ SurfFinishing::CalcOptimalZConstCurves( const ISurfFlatRegion* pSfrLoc, const SU bFirst = false ; } // se tratto precedente ambiguo, lo aggiungo al tratto corrente e lo rendo invalido - if ( nPL > 1 && - ( vTypePL[nPrevInd].first == AMBIGUOUS || vTypePL[nPrevInd].first == VALID)) { - // controllo che i punti siano sufficientemente vicini ( sqrt(2) * dDist)) + if ( nPL > 1 && ( vTypePL[nPrevInd].first == AMBIGUOUS || vTypePL[nPrevInd].first == VALID)) { + // controllo che i punti siano sufficientemente vicini ( sqrt( 2) * dDist)) Point3d ptBack, ptCurr ; vTypePL[nPrevInd].second.GetLastPoint( ptBack) ; vTypePL[nInd].second.GetFirstPoint( ptCurr) ; - if ( AreSamePointEpsilon( ptBack, ptCurr, 2 * dDist * dDist)) { - for ( auto& ptU : vTypePL[nPrevInd].second.GetUPointList()) + if ( AreSamePointEpsilon( ptBack, ptCurr, SQRT2 * dDist)) { + for ( const POINTU& ptU : vTypePL[nPrevInd].second.GetUPointList()) vPL.back().AddUPoint( 0., ptU.first) ; vTypePL[nPrevInd].first = DISCARD ; } } // aggiungo il tratto corrente e lo rendo invalido - for ( auto& ptU : vTypePL[nInd].second.GetUPointList()) + for ( const POINTU& ptU : vTypePL[nInd].second.GetUPointList()) vPL.back().AddUPoint( 0., ptU.first) ; vTypePL[nInd].first = DISCARD ; // se tratto successivo ambiguo, lo aggiungo al tratto corrente e lo rendo invalido if ( vTypePL[nAfterInd].first == AMBIGUOUS) { - // controllo che i punti siano sufficientemente vicini ( sqrt(2) * dDist)) + // controllo che i punti siano sufficientemente vicini ( sqrt( 2) * dDist)) Point3d ptForward, ptCurr ; vTypePL[nAfterInd].second.GetFirstPoint( ptForward) ; vTypePL[nInd].second.GetLastPoint( ptCurr) ; - if ( AreSamePointEpsilon( ptForward, ptCurr, 2 * dDist * dDist)) { + if ( AreSamePointEpsilon( ptForward, ptCurr, SQRT2 * dDist)) { for ( auto& ptU : vTypePL[nAfterInd].second.GetUPointList()) vPL.back().AddUPoint( 0., ptU.first) ; vTypePL[nAfterInd].first = DISCARD ; @@ -5810,14 +5795,46 @@ SurfFinishing::CalcOptimalZConstCurves( const ISurfFlatRegion* pSfrLoc, const SU bFirst = true ; } + // verifico se inizio e fine delle PolyLine sono sufficientemente vicine, in caso positivo unisco in una PolyLine unica + if ( ssize( vPL) == 1 && vPL[0].GetPointNbr() > 1 && ! vPL[0].IsClosed()) { + Point3d ptStart ; vPL[0].GetFirstPoint( ptStart) ; + Point3d ptEnd ; vPL[0].GetLastPoint( ptEnd) ; + if ( AreSamePointEpsilon( ptStart, ptEnd, SQRT2 * dDist)) + vPL[0].Close() ; + } + else if ( ssize( vPL) > 1) { + BOOLVECTOR vbSkipIndex ; vbSkipIndex.resize( vPL.size()) ; + for ( int i = 0 ; i < ssize( vPL) ; ++ i) + vbSkipIndex[i] = ( vPL[i].IsClosed()) ; + for ( int i = 0 ; i < ssize( vPL) ; ++ i) { + if ( ! vbSkipIndex[i]) { + Point3d ptEnd ; vPL[i].GetLastPoint( ptEnd) ; + for ( int j = 0 ; j < ssize( vPL) ; ++ j) { + if ( j != i && ! vbSkipIndex[j]) { + Point3d ptStart ; vPL[j].GetFirstPoint( ptStart) ; + if ( AreSamePointEpsilon( ptStart, ptEnd, SQRT2 * dDist)) { + for ( POINTU& ptU : vPL[j].GetUPointList()) + vPL[i].AddUPoint( 0., ptU.first) ; + vbSkipIndex[j] = true ; + vPL[j].Clear() ; + -- i ; + break ; + } + } + } + } + } + } } // dalle PolyLine recupero le curve vvCrvCompo[i].clear() ; - for ( PolyLine& PL : vPL) { + for ( const PolyLine& PL : vPL) { + // se vuota, non faccio nulla + if ( PL.GetPointNbr() < 2) + continue ; // se PolyLine troppo corta, non la memorizzo ( < 1/4 circonferenza utensile) - double dLen = 0. ; - PL.GetLength( dLen) ; + double dLen = 0. ; PL.GetLength( dLen) ; if ( dLen < ( PIGRECO / 2.) * ( m_TParams.m_dDiam / 2.)) continue ; // definisco la curva e la abbellisco @@ -5830,46 +5847,11 @@ SurfFinishing::CalcOptimalZConstCurves( const ISurfFlatRegion* pSfrLoc, const SU vvCrvCompo[i].back()->SetTempParam( dSfrDist, 0) ; #if ENABLE_OPTIMAL_DEBUG int a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLayCrv, vvCrvCompo[i].back()->Clone()) ; - m_pGeomDB->SetMaterial( a, GREEN) ; + m_pGeomDB->SetMaterial( a, FUCHSIA) ; #endif } } - // NB. per determinare la regione da lavavorare a ZigZag, devo prima determinare la regione - // definita dalle curve ZConst. - // --- determino il piano di proiezione dalla regione originale - Plane3d plProj ; - if ( ! plProj.Set( ptC, vtAxL)) - return false ; - // --- per ogni curva valida, definisco una regione piana Fat sul piano calcolato - for ( auto& vCrvCompo : vvCrvCompo) { - for ( auto& pCrvCompo : vCrvCompo) { - // se curva non valida, passo alla successiva - if ( IsNull( pCrvCompo) || ! pCrvCompo->IsValid()) - continue ; - // proeitto la curva sul piano - PtrOwner pCrvProj( ProjectCurveOnPlane( *pCrvCompo, plProj)) ; - if ( IsNull( pCrvProj) || ! pCrvProj->IsValid()) - continue ; - // determino la sua FatRegion - pCrvProj->SetExtrusion( vtAxL) ; // per coprire eventuali regioni fini - PtrOwner pSfrFat( GetSurfFlatRegionFromFatCurve( pCrvProj->Clone(), m_Params.m_dSideStep / dCosLimit, false, false)) ; - if ( IsNull( pSfrFat) || ! pSfrFat->IsValid()) - continue ; - if ( AreOppositeVectorApprox( pSfrFat->GetNormVersor(), vtAxL)) - pSfrFat->Invert() ; - // aggiungo questa regione a quella complessiva - if ( pSfrProj->IsValid() && pSfrProj->GetChunkCount() > 0) - pSfrProj->Add( *pSfrFat) ; - else - pSfrProj->CopyFrom( pSfrFat) ; - } - } - #if ENABLE_OPTIMAL_DEBUG - int nSfrId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLaySfrProj, pSfrProj->Clone()) ; - m_pGeomDB->SetMaterial( nSfrId, Color( 0., 1., 0., .5)) ; - #endif - // collego tra loro le curve trovate definendo quindi un percorso ICRVCOMPOPOVECTOR vCrv ; if ( ! CreateZConstPaths( pCAvTlStm, frSurf, vvCrvCompo, vtTool, pMySfrZConst, dDepth, vCrv)) { @@ -5878,7 +5860,7 @@ SurfFinishing::CalcOptimalZConstCurves( const ISurfFlatRegion* pSfrLoc, const SU } // restituisco i percorsi trovati - for ( int i = 0 ; i < int( vCrv.size()) ; ++ i) { + for ( int i = 0 ; i < ssize( vCrv) ; ++ i) { vPaths.resize( vPaths.size() + 1) ; vPaths.back().pCrvPath.Set( Release( vCrv[i])) ; vPaths.back().nType = SURFFIN_SUB_Z_CONST ; @@ -5887,74 +5869,267 @@ SurfFinishing::CalcOptimalZConstCurves( const ISurfFlatRegion* pSfrLoc, const SU return true ; } +//---------------------------------------------------------------------------- +bool +SurfFinishing::AreSameSfrChunkEpsilon( const ISurfFlatRegion* pSfrChunkA, const ISurfFlatRegion* pSfrChunkB, double dMaxDist) const +{ + // se esiste una superficie non valida, sicuro le superfici non sono sovrapposte + if ( pSfrChunkA == nullptr || pSfrChunkB == nullptr || ! pSfrChunkA->IsValid() || ! pSfrChunkB->IsValid()) + return false ; + + // Verifico che le sueprfici siano orientate correntamente + if ( ! AreSameVectorApprox( pSfrChunkA->GetNormVersor(), pSfrChunkB->GetNormVersor())) + return false ; + + double dMyMaxDist = max( 10. * EPS_SMALL, dMaxDist) ; + + // verifico mediate FatCurves dei bordi se in tolleranza + PtrOwner pCrvExtBorderA( pSfrChunkA->GetLoop( 0, 0)) ; + PtrOwner pCrvExtBorderB( pSfrChunkB->GetLoop( 0, 0)) ; + if ( IsNull( pCrvExtBorderA) || IsNull( pCrvExtBorderB) || ! pCrvExtBorderA->IsValid() || ! pCrvExtBorderB->IsValid()) + return false ; + PtrOwner pSfrFatExtA( GetSurfFlatRegionFromFatCurve( pCrvExtBorderA->Clone(), dMyMaxDist, false, false)) ; + if ( IsNull( pSfrFatExtA) || ! pSfrFatExtA->IsValid()) + return false ; + CRVCVECTOR ccClass ; + if ( ! pSfrFatExtA->GetCurveClassification( *pCrvExtBorderB, EPS_SMALL, ccClass) || + ! ( ssize( ccClass) == 1 && ccClass[0].nClass == CRVC_IN)) + return false ; + + // Recupero la superficie con più isole + int nIslA = pSfrFatExtA->GetLoopCount( 0) - 1 ; + int nIslB = pSfrChunkB->GetLoopCount( 0) - 1 ; + if ( nIslA == 0 && nIslB == 0) + return true ; + + const ISurfFlatRegion* pSfrA = ( nIslA >= nIslB ? pSfrChunkA : pSfrChunkB) ; + const ISurfFlatRegion* pSfrB = ( nIslA < nIslB ? pSfrChunkA : pSfrChunkB) ; + if ( pSfrA == nullptr || pSfrB == nullptr) + return false ; + + // Regioni di Controllo + ISURFFRPOVECTOR vFatSurfA ; vFatSurfA.reserve( nIslA) ; + for ( int nIsl = 0 ; nIsl < nIslA ; ++ nIsl) { + PtrOwner pCrvIsl( pSfrA->GetLoop( 0, nIsl + 1)) ; + if ( ! IsNull( pCrvIsl) && pCrvIsl->IsValid()) { + PtrOwner pSfrFat( GetSurfFlatRegionFromFatCurve( pCrvIsl->Clone(), dMaxDist, false, false)) ; + if ( ! IsNull( pSfrFat) && pSfrFat->IsValid()) { + if ( ! vFatSurfA.emplace_back( Release( pSfrFat))) + return false ; + } + } + } + + // Loop dell'altra regione + for ( int nIsl = 0 ; nIsl < nIslB ; ++ nIsl) { + PtrOwner pCrvIsl( pSfrB->GetLoop( 0, nIsl + 1)) ; + if ( ! IsNull( pCrvIsl) && pCrvIsl->IsValid()) { + // Se curva troppo stretta, non la considero + OffsetCurve OffsCrv ; + if ( OffsCrv.Make( pCrvIsl, dMaxDist, ICurve::OFF_FILLET)) { + PtrOwner pCrv( OffsCrv.GetLongerCurve()) ; + if ( IsNull( pCrv) || ! pCrv->IsValid()) + continue ; + } + // verifico che esista una regione Fat che la contenga + bool bOk = true ; + for ( const ISurfFlatRegion* pSfrFat : vFatSurfA) { + CRVCVECTOR ccClass ; + if ( pSfrFat->GetCurveClassification( *pCrvExtBorderB, EPS_SMALL, ccClass) && + ssize( ccClass) == 1 && ccClass[0].nClass == CRVC_IN) { + bOk = true ; + break ; + } + } + if ( ! bOk) + return false ; + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::CalcOptimalZigZagRegion( const ISurfFlatRegion* pSfrCntLoc, const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf, + const Vector3d& vtToolLoc, double dDepth, double dSplitAngDeg, ISURFFRPOVECTOR& vpSfrZigZagProj) const +{ + // verifico validità dei parametri + if ( pSfrCntLoc == nullptr || ! pSfrCntLoc->IsValid()) + return false ; + vpSfrZigZagProj.clear() ; + + const double COS_SPLIT_ANG = cos( dSplitAngDeg * DEGTORAD) ; + + // scorro tutte le facce delle superfici presenti + CISURFTMPVECTOR vpStm ; vpStm.reserve( vSrfLoc.size()) ; + for ( const SurfLocal& SurfL : vSrfLoc) { + // recupero la superficie + const ISurf* pSurf = GetSurf( SurfL.Get()) ; + if ( pSurf == nullptr || ! pSurf->IsValid()) + continue ; + int nType = pSurf->GetType() ; + // se TriMesh + if ( nType == SRF_TRIMESH) { + const ISurfTriMesh* pStm = GetSurfTriMesh( pSurf) ; + if ( pStm != nullptr && pStm->IsValid() && pStm->GetTriangleCount() > 0) + vpStm.emplace_back( pStm) ; + } + // se Bezier + else if ( nType == SRF_BEZIER) { + const ISurfBezier* pSBz = GetSurfBezier( pSurf) ; + if ( pSBz != nullptr && pSBz->IsValid()) { + double dOldTol = GetSurfBezierAuxSurfRefinedTol() ; + SetSurfBezierAuxSurfRefinedTol( 5. * EPS_SMALL) ; + const ISurfTriMesh* pStm = pSBz->GetAuxSurfRefined() ; + SetSurfBezierAuxSurfRefinedTol( dOldTol) ; + if ( pStm != nullptr && pStm->IsValid() && pStm->GetTriangleCount() > 0) + vpStm.emplace_back( pStm) ; + } + } + } + + // Definisco una Zuppa di Triangoli per le facce entro la tolleranza + StmFromTriangleSoup StmSoup ; + StmSoup.Start() ; + for ( const ISurfTriMesh* pStm : vpStm) { + if ( pStm == nullptr || ! pStm->IsValid()) + continue ; + // scorro le faccie della superficie e controllo l'angolo presente + for ( int nF = 0 ; nF < pStm->GetFacetCount() ; ++ nF) { + Vector3d vtFaceN ; pStm->GetFacetNormal( nF, vtFaceN) ; + if ( vtFaceN * vtToolLoc > COS_SPLIT_ANG) { + INTVECTOR vnTria ; pStm->GetAllTriaInFacet( nF, vnTria) ; + for ( const int& nT : vnTria) { + Triangle3d Tria ; pStm->GetTriangle( nT, Tria) ; + StmSoup.AddTriangle( Tria) ; + } + } + } + } + StmSoup.End() ; + + // recupero i parametri per il calcolo delle regioni piane a ZigZag + Point3d ptTop ; pSfrCntLoc->GetCentroid( ptTop) ; + Frame3d frPlanes ; + if ( ! frPlanes.Set( ptTop, vtToolLoc)) + return false ; + const double TOL_SIL = 1.0 ; + INTDBLVECTOR vSfrDistInd ; + + // Recupero le Superfici TriMesh + PtrOwner pStmZigZag( StmSoup.GetSurf()) ; + while ( ! IsNull( pStmZigZag)) { + if ( pStmZigZag->IsValid() && pStmZigZag->GetTriangleCount() > 0) { + // ogni Part della TriMesh a ZigZag diventa una FlatRegion + for ( int nP = 0 ; nP < pStmZigZag->GetPartCount() ; ++ nP) { + PtrOwner pStmZigZagPart( pStmZigZag->ClonePart( nP)) ; + if ( ! IsNull( pStmZigZagPart) && pStmZigZagPart->IsValid()) { + // recupero il Box della Parte corrente e determino la quota media ( controllo basilare, migliorabile) + BBox3d BBoxPart ; + pStmZigZagPart->GetLocalBBox( BBoxPart) ; + Point3d ptMid ; BBoxPart.GetCenter( ptMid) ; + // recupero le PolyLine di proiezione per la definizione del bordo + PtrOwner pCavParSilh( CreateCAvParSilhouettesSurfTm()) ; + if ( IsNull( pCavParSilh) || ! pCavParSilh->SetData( {pStmZigZagPart}, frPlanes, TOL_SIL)) + return false ; + POLYLINEVECTOR vPL ; + if ( ! pCavParSilh->GetSilhouette( - dDepth, vPL)) + return false ; + // inizializzo classe di calcolo per regione piana corrente mediante le PolyLine ricavate + SurfFlatRegionByContours SfrByC ; + for ( const PolyLine& PL : vPL) { + PtrOwner pCompoPL( CreateCurveComposite()) ; + if ( IsNull( pCompoPL) || ! pCompoPL->FromPolyLine( PL) || ! SfrByC.AddCurve( pCompoPL->Clone())) + return false ; + } + // Recupero le superfici piane e le memorizzo + PtrOwner pSfrProj( SfrByC.GetSurf()) ; + while ( ! IsNull( pSfrProj)) { + if ( pSfrProj->IsValid()) { + // porto la superficie in Globale + if ( AreOppositeVectorEpsilon( pSfrProj->GetNormVersor(), vtToolLoc, 20. * EPS_SMALL)) + pSfrProj->Invert() ; + // limito questa regione all'intersezione con la superficie di Contorno + if ( ! pSfrProj->Intersect( *pSfrCntLoc)) + return false ; + if ( pSfrProj->IsValid()) { + // verifico che non ci siano delle superfici duplicate + bool bDuplicate = false ; + for ( int i = 0 ; ! bDuplicate && i < ssize( vpSfrZigZagProj) ; ++ i) + bDuplicate = AreSameSfrChunkEpsilon( pSfrProj, vpSfrZigZagProj[i], m_TParams.m_dDiam / 4.) ; + if ( ! bDuplicate) { + vpSfrZigZagProj.emplace_back( Release( pSfrProj)) ; + vSfrDistInd.emplace_back( make_pair( ssize( vpSfrZigZagProj) - 1, abs( ( ptMid - ptTop) * vtToolLoc))) ; + } + } + } + pSfrProj.Set( SfrByC.GetSurf()) ; + } + } + } + } + pStmZigZag.Set( StmSoup.GetSurf()) ; + } + if ( ssize( vpSfrZigZagProj) < 2) + return true ; + + // ordino le superfici ottenute in base alla distanza con la Superficie di contorno ( riferita alla Part di TriMesh) + ranges::sort( vSfrDistInd, {}, &pair::second) ; + for ( int i = 0 ; i < ssize( vSfrDistInd) ; ++ i) { + int nCurrI = i ; + while ( vSfrDistInd[nCurrI].first != nCurrI) { + int nNextI = vSfrDistInd[nCurrI].first ; + swap( vpSfrZigZagProj[nCurrI], vpSfrZigZagProj[nNextI]) ; + swap( vSfrDistInd[nCurrI], vSfrDistInd[nNextI]) ; + } + } + + return true ; +} + //---------------------------------------------------------------------------- bool SurfFinishing::AddOptimal( ICAvToolSurfTm* pCAvTlStm, const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf, - const ISurfFlatRegion* pSfrCntZigZag, const ISurfFlatRegion* pSfrCntZConst, + const ISurfFlatRegion* pSfrCnt, const ISurfFlatRegion* pSfrCntExt, const Vector3d& vtTool, double dDepth, double dElev, bool bSplitArcs) { // vettore dei percorsi da calcolare VECTORPATHS vPaths ; // se entrambe le regioni non sono valide, non faccio nulla - if ( ( pSfrCntZigZag == nullptr || ! pSfrCntZigZag->IsValid()) && - ( pSfrCntZConst == nullptr || ! pSfrCntZConst->IsValid())) + if ( ( pSfrCnt == nullptr || ! pSfrCnt->IsValid()) && ( pSfrCntExt == nullptr || ! pSfrCntExt->IsValid())) return false ; // recupero l'angolo di Split e la rispettiva tolleranza - double dAngDegSplit = 45 ; - GetValInNotes( m_Params.m_sUserNotes, UN_SPLITANGLE, dAngDegSplit) ; - double dAngDegTol = 5 ; - GetValInNotes( m_Params.m_sUserNotes, UN_ANGLETOL, dAngDegTol) ; + double dAngDegSplit = 45. ; GetValInNotes( m_Params.m_sUserNotes, UN_SPLITANGLE, dAngDegSplit) ; + double dAngDegTol = 5. ; GetValInNotes( m_Params.m_sUserNotes, UN_ANGLETOL, dAngDegTol) ; - // inizializzo l'area di lavoro determinata dalle curve ZigZag - PtrOwner pSfrZigZagProjLoc ; - if ( pSfrCntZigZag != nullptr && pSfrCntZigZag->IsValid()) { - if ( ! pSfrZigZagProjLoc.Set( CloneSurfFlatRegion( pSfrCntZigZag)) || - ! pSfrCntZigZag->IsValid()) - return false ; - pSfrZigZagProjLoc->ToLoc( frSurf) ; - } - else { - if ( ! pSfrZigZagProjLoc.Set( CreateSurfFlatRegion())) - return false ; + // tengo una copia della regione di contorno in locale alle superfici + PtrOwner pSfrCntLoc( CloneSurfFlatRegion( pSfrCnt)) ; + if ( IsNull( pSfrCntLoc) || ! pSfrCntLoc->IsValid() || ! pSfrCntLoc->ToLoc( frSurf)) + return false ; + + // --- [1°] calcolo delle curve ZLevel e [2°] definizione della regione di proiezione per Zlevel --- + PtrOwner pSfrCntZLevel( pSfrCntLoc->CreateOffsetSurf( - m_TParams.m_dDiam / 2. + EPS_SMALL, ICurve::OFF_FILLET)) ; + if ( IsNull( pSfrCntZLevel)) + return false ; + // calcolo tutte le curve a ZLevel e determino la regione rimossa da queste curve + if ( ! CalcOptimalZConstCurves( pSfrCntZLevel, vSrfLoc, frSurf, vtTool, dAngDegSplit, dAngDegTol, dDepth, pCAvTlStm, vPaths)) { + m_pMchMgr->SetLastError( 3124, "Error in SurfFinishing : region not computable") ; + return false ; } - // se ho una superficie di contorno per ZConst valida - if ( pSfrCntZConst != nullptr && pSfrCntZConst->IsValid()) { - - // definizione regione piana di lavoro per curve ZConst - PtrOwner pSfrZConstLoc( CloneSurfFlatRegion( pSfrCntZConst)) ; - if ( IsNull( pSfrZConstLoc) || ! pSfrZConstLoc->IsValid() || ! pSfrZConstLoc->ToLoc( frSurf)) - return false ; - - // recupero le curve dalla regione ZConst - PtrOwner pSfrZConstProj( CreateSurfFlatRegion()) ; - if ( IsNull( pSfrZConstProj) || - ! CalcOptimalZConstCurves( pSfrZConstLoc, vSrfLoc, frSurf, vtTool, dAngDegSplit, dAngDegTol, dDepth, pCAvTlStm, vPaths, pSfrZConstProj)) { - m_pMchMgr->SetLastError( 3124, "Error in SurfFinishing : region not computable") ; - return false ; - } - - // recupero le curve dalla regione Spiral - if ( pSfrZConstProj->IsValid() && pSfrZConstProj->GetChunkCount() > 0 && - pSfrZigZagProjLoc->IsValid()) { - PtrOwner pSfrZigZagProjLocClone( CloneSurfFlatRegion( pSfrZigZagProjLoc)) ; - if ( IsNull( pSfrZigZagProjLocClone) || ! pSfrZigZagProjLocClone->IsValid()) - return false ; - // alla superficie ZigZag tolgo la regione ZConst - pSfrZigZagProjLoc->Subtract( *pSfrZConstProj) ; - // nei pressi dei tratti in comune lo ZigZag deve lavorare a SideStep - // NB. pSfrZConstProj è ingrandita di SideStep - pSfrZigZagProjLoc->Offset( m_Params.m_dSideStep + m_TParams.m_dDiam / 2., ICurve::OFF_FILLET) ; - // la supercicie ZigZag deve comunque essere sempre contenuta in quella definita in originale - pSfrZigZagProjLoc->Intersect( *pSfrZigZagProjLocClone) ; - } + // [3°] calcolo della regione di proiezione ZigZag --- + ISURFFRPOVECTOR vSfrZigZagProj ; + if ( ! CalcOptimalZigZagRegion( pSfrCntZLevel, vSrfLoc, frSurf, GetToLoc( vtTool, frSurf), dDepth, dAngDegSplit, vSfrZigZagProj)) { + m_pMchMgr->SetLastError( 3124, "Error in SurfFinishing : region not computable") ; + return false ; } - // se ho una superficie di contorno per ZigZag valida - if ( ! IsNull( pSfrZigZagProjLoc) && pSfrZigZagProjLoc->IsValid()) { - if ( ! CalcOptimalZigZagCurves( pSfrZigZagProjLoc, frSurf, vtTool, dDepth, pCAvTlStm, vPaths)) { + // [4°] calcolo delle curve ZigZag --- + if ( ! vSfrZigZagProj.empty()) { + if ( ! CalcOptimalZigZagCurves( vSfrZigZagProj, frSurf, vtTool, dDepth, pCAvTlStm, vPaths)) { m_pMchMgr->SetLastError( 3124, "Error in SurfFinishing : region not computable") ; return false ; } @@ -5965,14 +6140,14 @@ SurfFinishing::AddOptimal( ICAvToolSurfTm* pCAvTlStm, const SURFLOCALVECTOR& vSr return true ; // porto tutte le curve in globale - for ( auto& path : vPaths) { + for ( PATH& path : vPaths) { if ( IsNull( path.pCrvPath) || ! path.pCrvPath->IsValid()) continue ; path.pCrvPath->ToGlob( frSurf) ; } // ordino i percorsi ricavati - if ( ! OrderOptimalPathsByZLoc( pSfrCntZConst, pSfrCntZigZag, vPaths)) + if ( ! OrderOptimalPathsByZLoc( pSfrCntExt, pSfrCnt, vPaths)) return false ; #if ENABLE_OPTIMAL_FINAL_CURVES_DEBUG @@ -5998,9 +6173,9 @@ SurfFinishing::AddOptimal( ICAvToolSurfTm* pCAvTlStm, const SURFLOCALVECTOR& vSr // aggiungo i percorsi di finitura calcolati ICRVCOMPOPOVECTOR vCrvCompo ; vCrvCompo.resize( vPaths.size()) ; - for ( int i = 0 ; i < int( vPaths.size()) ; ++ i) + for ( int i = 0 ; i < ssize( vPaths) ; ++ i) vCrvCompo[i].Set( Release( vPaths[i].pCrvPath)) ; - if ( ! AddFinishing( ( pSfrCntZConst == nullptr || ! pSfrCntZConst->IsValid()) ? pSfrCntZigZag : pSfrCntZConst, + if ( ! AddFinishing( ( pSfrCntExt == nullptr || ! pSfrCntExt->IsValid()) ? pSfrCnt : pSfrCntExt, pCAvTlStm, frSurf, vCrvCompo, vtTool, dElev, dDepth, bSplitArcs)) return false ; diff --git a/SurfFinishing.h b/SurfFinishing.h index cf21044..9ff555a 100644 --- a/SurfFinishing.h +++ b/SurfFinishing.h @@ -21,6 +21,7 @@ #include "GeoConst.h" #include "/EgtDev/Include/EGkCurveComposite.h" #include "/EgtDev/Include/EGkSurfTriMesh.h" +#include "/EgtDev/Include/EGkSurfFlatRegion.h" #include "/EgtDev/Include/EgtNumUtils.h" #include "/EgtDev/Include/EGkSurfLocal.h" @@ -177,8 +178,8 @@ class SurfFinishing : public Machining double dFrontTriaTolerAng, double& dMaxFrontTriaRad) const ; bool CalcOptimalZConstCurves( const ISurfFlatRegion* pSfrLoc, const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf, const Vector3d& vtTool, double dAngDegSplit, - double dAngDegTol, double dDepth, ICAvToolSurfTm* pCAvTlStm, VECTORPATHS& vPaths, ISurfFlatRegion* pSfrProj) const ; - bool CalcOptimalZigZagCurves( const ISurfFlatRegion* pSfrLoc, const Frame3d& frSurf, + double dAngDegTol, double dDepth, ICAvToolSurfTm* pCAvTlStm, VECTORPATHS& vPaths) const ; + bool CalcOptimalZigZagCurves( ISURFFRPOVECTOR& vSfrZigZagProj, const Frame3d& frSurf, const Vector3d& vtTool, double dDepth, ICAvToolSurfTm* pCAvTlStm, VECTORPATHS& vPaths) const ; bool GetOptimalSfr( ICAvToolSurfTm* pCAvTlStm, const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf, const ISurfFlatRegion* pSfrLoc, const Vector3d& vtTool, double dDepth, double dElev, ISurfFlatRegion* pSfrSpiral, ISurfFlatRegion* pSfrZConst) const ; @@ -213,6 +214,9 @@ class SurfFinishing : public Machining bool MarchingSquares( const VECTORCOLLISIONSFR& vPntM, int nType, double dOffsTol, int nStepX, int nStepY, double dClippingAngle, double dLimInfClippingAng, double dLimSupClippingAng, const Vector3d& vtAxL, const Vector3d& vtMoveL, ICAvToolSurfTm* pCAvTlStm, ICRVCOMPOPOVECTOR& vCrvCompo) const ; + bool AreSameSfrChunkEpsilon( const ISurfFlatRegion* pSfrChunkA, const ISurfFlatRegion* pSfrChunkB, double dMaxDist) const ; + bool CalcOptimalZigZagRegion( const ISurfFlatRegion* pSfrCntLoc, const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf, + const Vector3d& vtTool, double dDepth, double dSplitAngDeg, ISURFFRPOVECTOR& vpSfrZigZagProj) const ; double GetRightFeed( const Vector3d& vtMove, const Vector3d& vtTool) const ; double GetRadiusForStartEndElevation( void) const ; @@ -235,7 +239,7 @@ class SurfFinishing : public Machining int GetLeadOutType( void) const ; private : - SELVECTOR m_vId ; // identificativi entità geometriche da lavorare + SELVECTOR m_vId ; // identificativi entità geometriche da lavorare SurfFinishingData m_Params ; // parametri lavorazione ToolData m_TParams ; // parametri utensile double m_dTHoldBase ; // posizione base del porta-utensile