//---------------------------------------------------------------------------- // EgalTech 2015-2018 //---------------------------------------------------------------------------- // File : EXE_NstCreateFlatParts.cpp Data : 06.09.18 Versione : 1.9i1 // Contenuto : Funzioni di creazione pezzi piani per EXE. // // // // Modifiche : 28.12.15 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "EXE.h" #include "EXE_Const.h" #include "EXE_Macro.h" #include "EXE_Nst.h" #include "/EgtDev/Include/EXeExecutor.h" #include "/EgtDev/Include/EXeConst.h" #include "/EgtDev/Include/EXeCmdLogOff.h" #include "/EgtDev/Include/EGkCurveLine.h" #include "/EgtDev/Include/EGkCurveArc.h" #include "/EgtDev/Include/EGkCurveComposite.h" #include "/EgtDev/Include/EGkIntersCurves.h" #include "/EgtDev/Include/EGkSfrCreate.h" #include "/EgtDev/Include/EGkExtText.h" #include "/EgtDev/Include/EGkGdbIterator.h" #include "/EgtDev/Include/EGkIntervals.h" #include "/EgtDev/Include/EGkPointGrid3d.h" #include "/EgtDev/Include/EMkMachiningGeoConst.h" #include "/EgtDev/Include/EgtPointerOwner.h" using namespace std ; //---------------------------------------------------------------------------- // Raccolte di coppie Point3d,Color typedef std::pair POINTCOLOR ; // coppia punto, colore typedef std::vector PNTCOLVECTOR ; // vettore di coppie punto, colore //---------------------------------------------------------------------------- // Costanti const double EPS_PNTCOL = 1.0 ; const double MIN_LEN_COLOR = 1.0 ; const double MIN_LEN_SPLIT = 10.0 ; const double MIN_AREA = 1.0 ; //---------------------------------------------------------------------------- static bool VerifyCalcLevel( IGdbIterator* pEnt, int nReqLev) { int nLev ; return ( pEnt->GetCalcLevel( nLev) && nLev == nReqLev) ; } //---------------------------------------------------------------------------- static bool ApproxCurveIfNeeded( IGdbIterator* pEnt, double dToler) { // deve essere una curva int nGeoType = pEnt->GetGeoType() ; if ( (nGeoType & GEO_CURVE) == 0) return false ; // verifico se da approssimare if ( nGeoType == CRV_LINE || nGeoType == CRV_ARC) return true ; else if ( nGeoType == CRV_COMPO) { ICurveComposite* pCrvCo = GetCurveComposite( pEnt->GetGeoObj()) ; double dLen ; pCrvCo->GetLength( dLen) ; int nCrvs = pCrvCo->GetCurveCount() ; if ( nCrvs <= 5 && dLen > nCrvs * LIN_FEA_STD) { // controllo non ci siano curve di Bezier bool bSomeBezier = false ; const ICurve* pCrv = pCrvCo->GetFirstCurve() ; while ( pCrv != nullptr) { if ( pCrv->GetType() == CRV_BEZIER) bSomeBezier = true ; pCrv = pCrvCo->GetNextCurve() ; } if ( ! bSomeBezier) return true ; } } // esecuzione dell'approssimazione ICurve* pCrv = GetCurve( pEnt->GetGeoObj()) ; PtrOwner pCC( CreateCurveComposite()) ; PolyArc PA ; double dTol = max( dToler, LIN_TOL_FINE) ; bool bOk = pCrv->ApproxWithArcsEx( dTol, ANG_TOL_STD_DEG, LIN_FEA_STD, PA) && pCC->FromPolyArc( PA) ; // eliminazione di small Z bOk = bOk && pCC->RemoveSmallDefects( 0.5 * dTol, ANG_TOL_STD_DEG) ; // merge di archi identici di biarchi bOk = bOk && pCC->MergeCurves( 0.5 * dTol, ANG_TOL_STD_DEG) ; bOk = bOk && pEnt->GetGDB()->ReplaceGeoObj( pEnt->GetId(), Release( pCC)) ; return bOk ; } //---------------------------------------------------------------------------- static bool AdjustNearlyClosedCurve( IGdbIterator* pEnt) { // deve essere una curva int nGeoType = pEnt->GetGeoType() ; if ( (nGeoType & GEO_CURVE) == 0) return false ; // se linea non devo fare alcunché if ( nGeoType == CRV_LINE) return true ; // se arco, verifico se quasi circonferenza if ( nGeoType == CRV_ARC) { ICurveArc* pArc = GetCurveArc( pEnt->GetGeoObj()) ; Point3d ptStart ; pArc->GetStartPoint( ptStart) ; Point3d ptEnd ; pArc->GetEndPoint( ptEnd) ; double dAngCenDeg = pArc->GetAngCenter() ; if ( abs( dAngCenDeg) > ANG_STRAIGHT && AreSamePointEpsilon( ptStart, ptEnd, LIN_TOL_STD)) return pArc->ChangeAngCenter( dAngCenDeg > 0 ? ANG_FULL : - ANG_FULL) ; return true ; } // altrimenti, verifico se approssimativamente chiusa ICurve* pCrv = GetCurve( pEnt->GetGeoObj()) ; Point3d ptStart ; pCrv->GetStartPoint( ptStart) ; Point3d ptEnd ; pCrv->GetEndPoint( ptEnd) ; if ( AreSamePointEpsilon( ptStart, ptEnd, LIN_TOL_STD)) return pCrv->ModifyEnd( ptStart) ; return true ; } //---------------------------------------------------------------------------- static bool FilterAndApprox( double dToler) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // preparo gli iteratori PtrOwner pPar( CreateGdbIterator( pGeomDB)) ; PtrOwner pLay( CreateGdbIterator( pGeomDB)) ; PtrOwner pEnt( CreateGdbIterator( pGeomDB)) ; if ( IsNull( pPar) || IsNull( pLay) || IsNull( pEnt)) return false ; // ciclo su tutti gli oggetti del DB geometrico bool bPok = pPar->GoToFirstInGroup( GDB_ID_ROOT) ; while ( bPok) { // sotto la radice sono ammessi solo gruppi di livello User -> Pezzi if ( pPar->GetGdbType() != GDB_TY_GROUP || ! VerifyCalcLevel( pPar, GDB_LV_USER)) { bPok = pPar->EraseAndGoToNext() ; continue ; } // ciclo su tutti gli oggetti del pezzo bool bLok = pLay->GoToFirstInGroup( *pPar) ; while ( bLok) { // sotto ogni pezzo sono ammessi solo gruppi di livello User -> Layer if ( pLay->GetGdbType() != GDB_TY_GROUP || ! VerifyCalcLevel( pLay, GDB_LV_USER)) { bLok = pLay->EraseAndGoToNext() ; continue ; } // ciclo su tutti gli oggetti del layer bool bEok = pEnt->GoToFirstInGroup( *pLay) ; while ( bEok) { // sotto ogni layer sono ammesse solo curve o testi di livello User bool bCurve = (( pEnt->GetGeoType() & GEO_CURVE) != 0) ; bool bText = ( pEnt->GetGeoType() == EXT_TEXT) ; if ( ( ! bCurve && ! bText) || ! VerifyCalcLevel( pEnt, GDB_LV_USER)) { bEok = pEnt->EraseAndGoToNext() ; continue ; } // aggiustamenti per curve if ( bCurve) { // eventuale approx della curva se Bezier o Composita con molti piccoli segmenti ApproxCurveIfNeeded( pEnt, dToler) ; // se curva approssimativamente chiusa, la chiudo esattamente AdjustNearlyClosedCurve( pEnt) ; } // passo alla successiva entità bEok = pEnt->GoToNext() ; } // passo al successivo layer bLok = pLay->GoToNext() ; } // passo al successivo pezzo bPok = pPar->GoToNext() ; } return true ; } //---------------------------------------------------------------------------- static bool SaveColorWithMidPnt( PNTCOLVECTOR& vPntCol) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // preparo gli iteratori PtrOwner pPar( CreateGdbIterator( pGeomDB)) ; PtrOwner pLay( CreateGdbIterator( pGeomDB)) ; PtrOwner pEnt( CreateGdbIterator( pGeomDB)) ; if ( IsNull( pPar) || IsNull( pLay) || IsNull( pEnt)) return false ; // ciclo su tutti gli oggetti del DB geometrico bool bPok = pPar->GoToFirstInGroup( GDB_ID_ROOT) ; while ( bPok) { // ciclo su tutti gli oggetti del pezzo bool bLok = pLay->GoToFirstInGroup( *pPar) ; while ( bLok) { // ciclo su tutti gli oggetti del layer bool bEok = pEnt->GoToFirstInGroup( *pLay) ; while ( bEok) { // se curva composita if ( pEnt->GetGeoType() == CRV_COMPO) { // se c'è il colore e abbastanza lunga Color cCol ; double dLen ; if ( pEnt->GetCalcMaterial( cCol) && ExeCurveLength( pEnt->GetId(), &dLen) && dLen > MIN_LEN_COLOR) { // ciclo sulle curve elementari const ICurveComposite* pCompo = GetCurveComposite( pEnt->GetGeoObj()) ; const ICurve* pCrv = pCompo->GetFirstCurve() ; while ( pCrv != NULL) { // recupero il punto medio Point3d ptMid ; if ( pCrv->GetMidPoint( ptMid)) { // inserisco nella lista dei punti-colori, se punto non già presente if ( find_if( vPntCol.begin(), vPntCol.end(), [&](const POINTCOLOR& PntCol) { return AreSamePointEpsilon( PntCol.first, ptMid, EPS_PNTCOL) ;}) == vPntCol.end()) vPntCol.emplace_back( ptMid, cCol) ; } pCrv = pCompo->GetNextCurve() ; } } } // altrimenti linea o arco else if ( ( pEnt->GetGeoType() & GEO_CURVE) != 0) { // recupero il colore proprio e il punto medio Color cCol ; Point3d ptMid ; double dLen ; if ( pEnt->GetCalcMaterial( cCol) && ExeMidPoint( pEnt->GetId(), GDB_ID_ROOT, ptMid) && ExeCurveLength( pEnt->GetId(), &dLen) && dLen > MIN_LEN_COLOR) { // inserisco nella lista dei punti-colori, se punto non già presente if ( find_if( vPntCol.begin(), vPntCol.end(), [&](const POINTCOLOR& PntCol) { return AreSamePointEpsilon( PntCol.first, ptMid, EPS_PNTCOL) ;}) == vPntCol.end()) vPntCol.emplace_back( ptMid, cCol) ; } } // passo alla successiva entità bEok = pEnt->GoToNext() ; } // passo al successivo layer bLok = pLay->GoToNext() ; } // passo al successivo pezzo bPok = pPar->GoToNext() ; } return true ; } //---------------------------------------------------------------------------- static bool ApplyColorWithMidPnt( const PNTCOLVECTOR& vPntCol) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // Points number int n = int( vPntCol.size()) ; // Overall box BBox3d b3All ; for ( const auto& PntCol : vPntCol) b3All.Add( PntCol.first) ; // Grid cell dimension double dCellDim ; b3All.GetRadius( dCellDim) ; dCellDim *= 2 / sqrt( n) ; // Grid PointGrid3d PntGrid ; if ( ! PntGrid.Init( 2 * n, dCellDim)) return false ; for ( int i = 0 ; i < int( vPntCol.size()) ; ++ i) PntGrid.InsertPoint( vPntCol[i].first, i) ; // Ciclo sui pezzi int nPartId = ExeGetFirstPart( false) ; while ( nPartId != GDB_ID_NULL) { // Ciclo sui layer del pezzo int nLayerId = ExeGetFirstLayer( nPartId, false) ; while ( nLayerId != GDB_ID_NULL) { string sLayName ; pGeomDB->GetName( nLayerId, sLayName) ; // Se layer OutLoop, InLoop o OnPath if ( sLayName == NST_OUT_LAYER || sLayName == NST_IN_LAYER || sLayName == NST_ON_LAYER) { // Ciclo su tutti gli oggetti del layer int nEntId = pGeomDB->GetFirstInGroup( nLayerId) ; while ( nEntId != GDB_ID_NULL) { // se curva ICurve* pCrv = GetCurve( pGeomDB->GetGeoObj( nEntId)) ; if ( pCrv != nullptr) { // recupero il riferimento Frame3d frCrv ; pGeomDB->GetGlobFrame( nEntId, frCrv) ; // recupero il box e lo espando della tolleranza BBox3d b3Ent ; pGeomDB->GetGlobalBBox( nEntId, b3Ent) ; b3Ent.Expand( EPS_PNTCOL) ; // cerco i punti-colore che possono appartenere all'entità INTVECTOR vnIs ; PntGrid.Find( b3Ent, vnIs) ; for ( int i = 0 ; i < int( vnIs.size()) ;) { Point3d ptCol = vPntCol[vnIs[i]].first ; ptCol.ToLoc( frCrv) ; if ( pCrv->IsPointOn( ptCol, EPS_PNTCOL)) ++ i ; else vnIs.erase( vnIs.begin() + i) ; } // se due punti di colore diverso divido la curva in parti corrispondenti ai punti if ( vnIs.size() == 2 && ! ( vPntCol[vnIs[0]].second == vPntCol[vnIs[1]].second)) { // recupero la posizione dei punti lungo la curva Point3d ptCol1 = vPntCol[vnIs[0]].first ; ptCol1.ToLoc( frCrv) ; double dLen1 = - 1 ; pCrv->GetLengthAtPoint( ptCol1, dLen1, EPS_PNTCOL) ; Point3d ptCol2 = vPntCol[vnIs[1]].first ; ptCol2.ToLoc( frCrv) ; double dLen2 = - 1 ; pCrv->GetLengthAtPoint( ptCol2, dLen2, EPS_PNTCOL) ; // recupero i colori Color cCol1 = vPntCol[vnIs[0]].second ; Color cCol2 = vPntCol[vnIs[1]].second ; if ( dLen2 < dLen1) swap( cCol1, cCol2) ; // determino la posizione di divisione double dLenSplit = max( 2 * min( dLen1, dLen2), 0.) ; double dLenTot ; pCrv->GetLength( dLenTot) ; if ( dLenSplit > MIN_LEN_SPLIT && dLenTot - dLenSplit > MIN_LEN_SPLIT) { // divido la curva opportunamente double dParSplit ; pCrv->GetParamAtLength( dLenSplit, dParSplit) ; int nNewId = ExeSplitCurveAtParam( nEntId, dParSplit) ; // sistemo opportunamente le info pGeomDB->SetInfo( nEntId, MCH_KEY_NEXTANG, 0) ; pGeomDB->SetInfo( nNewId, MCH_KEY_PREVANG, 0) ; // assegno i colori pGeomDB->SetMaterial( nEntId, cCol1) ; pGeomDB->SetMaterial( nNewId, cCol2) ; // aggiorno entità corrente nEntId = nNewId ; } else if ( dLenSplit > MIN_LEN_SPLIT) { // assegno il colore pGeomDB->SetMaterial( nEntId, cCol1) ; } else if ( dLenTot - dLenSplit > MIN_LEN_SPLIT) { // assegno il colore pGeomDB->SetMaterial( nEntId, cCol2) ; } } // se altrimenti almeno un punto, assegno direttamente il colore del primo else if ( vnIs.size() > 0) pGeomDB->SetMaterial( nEntId, vPntCol[vnIs[0]].second) ; // altrimenti non assegno colore } // passo alla successiva entità nEntId = pGeomDB->GetNext( nEntId) ; } } nLayerId = ExeGetNextLayer( nLayerId, false) ; } nPartId = ExeGetNextPart( nPartId, false) ; } return true ; } //---------------------------------------------------------------------------- static bool ChainCurves( int& nLay) { // seleziono tutte e sole le curve ExeSetObjFilterForSelect( false, true, false, false, false) ; bool bOk = ExeSelectAll( false) ; // creo un nuovo pezzo con layer in cui mettere tutti i concatenati int nPart = ExeCreateGroup( GDB_ID_ROOT, Frame3d(), RTY_GLOB) ; nLay = ExeCreateGroup( nPart, Frame3d(), RTY_GLOB) ; bOk = ( bOk && nLay != GDB_ID_NULL) ; // concateno tutte le curve INTVECTOR vIds ; vIds.push_back( GDB_ID_SEL) ; int nCount ; int nFirstId = ( bOk ? ExeCreateCurveCompoByChain( nLay, vIds, ORIG, true, RTY_GLOB, &nCount) : GDB_ID_NULL) ; bOk = ( bOk && nFirstId != GDB_ID_NULL) ; // sposto gli eventuali testi ExeSetObjFilterForSelect( false, false, false, false, true) ; bOk = ExeSelectAll( false) ; int nId = ExeGetFirstSelectedObj() ; while ( nId != GDB_ID_NULL) { bOk = bOk && ExeRelocateGlob( nId, nLay, GDB_LAST_SON) ; nId = ExeGetNextSelectedObj() ; } ExeDeselectAll() ; // cancello i gruppi rimasti vuoti ExeEraseEmptyParts() ; // ripristino filtro di selezione ExeSetObjFilterForSelect( true, true, true, true, true) ; return bOk ; } //---------------------------------------------------------------------------- static bool CreateFlatPartsByRegions( int nLay) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // recupero il padre del layer int nParentId = pGeomDB->GetParentId( nLay) ; // preparo gli iteratori PtrOwner pEnt( CreateGdbIterator( pGeomDB)) ; if ( IsNull( pEnt)) return false ; // separo le curve aperte da quelle chiuse e salvo vettore aree di queste ultime INTDBLVECTOR vArea ; // vettore di coppie indice curva chiusa + area INTVECTOR vOpenIds ; // vettore indici curve aperte INTVECTOR vTextIds ; // vettore indici testi bool bEok = pEnt->GoToFirstInGroup( nLay) ; while ( bEok) { ICurve* pCrv = GetCurve( pEnt->GetGeoObj()) ; if ( pCrv == nullptr) { IExtText* pTxt = GetExtText( pEnt->GetGeoObj()) ; if ( pTxt == nullptr) bEok = pEnt->EraseAndGoToNext() ; else { vTextIds.push_back( pEnt->GetId()) ; bEok = pEnt->GoToNext() ; } } else if ( ! pCrv->IsClosed()) { vOpenIds.push_back( pEnt->GetId()) ; bEok = pEnt->GoToNext() ; } else { double dArea ; pCrv->GetAreaXY( dArea) ; if ( abs( dArea) > MIN_AREA) { if ( dArea < 0) { pCrv->Invert() ; dArea = - dArea ; } vArea.emplace_back( pEnt->GetId(), dArea) ; } else vOpenIds.push_back( pEnt->GetId()) ; bEok = pEnt->GoToNext() ; } } // ordino le aree in senso decrescente sort( vArea.begin(), vArea.end(), []( const INTDBL& a, const INTDBL&b) { return abs( a.second) > abs( b.second) ; }) ; // creo i pezzi a partire dalle curve chiuse più grandi e dalle curve che vi sono contenute for ( int i = 0 ; i < int( vArea.size()) ; ++ i) { if ( vArea[i].first == GDB_ID_NULL) continue ; // creo pezzo con questa geometria int nPartId = pGeomDB->InsertGroup( GDB_ID_NULL, nParentId, GDB_BEFORE, Frame3d()) ; // creo layer nel pezzo int nLayId = pGeomDB->AddGroup( GDB_ID_NULL, nPartId, Frame3d()) ; // sposto il contorno nel pezzo pGeomDB->RelocateGlob( vArea[i].first, nLayId) ; ICurve* pCrv = GetCurve( pGeomDB->GetGeoObj( vArea[i].first)) ; // ne determino il box e il centro BBox3d b3Part ; pGeomDB->GetGlobalBBox( vArea[i].first, b3Part) ; Point3d ptPartCen ; b3Part.GetCenter( ptPartCen) ; // cerco altri contorni chiusi che siano contenuti completamente o parzialmente for ( int j = i + 1 ; j < int( vArea.size()) ; ++ j) { if ( vArea[j].first == GDB_ID_NULL) continue ; ICurve* pCrv2 = GetCurve( pGeomDB->GetGeoObj( vArea[j].first)) ; // intersezione e classificazione CRVCVECTOR ccClass ; IntersCurveCurve intCC( *pCrv2, *pCrv) ; if ( ! intCC.GetCurveClassification( 0, EPS_SMALL, ccClass)) continue ; // se completamente interna if ( ccClass.size() == 1 && ccClass[0].nClass == CRVC_IN) { pGeomDB->RelocateGlob( vArea[j].first, nLayId) ; vArea[j].first = GDB_ID_NULL ; } // se più di un tratto else if ( ccClass.size() > 1) { // verifico se parzialmente interna bool bIn = false ; bool bOther = false ; for ( int k = 0 ; k < int( ccClass.size()) ; ++ k) { if ( ccClass[k].nClass == CRVC_IN) bIn = true ; else bOther = true ; } // se parzialmente interna, la sposto negli aperti if ( bIn && bOther) { vOpenIds.push_back( vArea[j].first) ; vArea[j].first = GDB_ID_NULL ; } } } // verifico i contorni aperti che siano contenuti completamente o parzialmente for ( int j = 0 ; j < int( vOpenIds.size()) ; ++ j) { if ( vOpenIds[j] == GDB_ID_NULL) continue ; ICurve* pCrv2 = GetCurve( pGeomDB->GetGeoObj( vOpenIds[j])) ; Intervals inCrv ; double dParS, dParE ; pCrv2->GetDomain( dParS, dParE) ; inCrv.Set( dParS, dParE) ; // intersezione e classificazione CRVCVECTOR ccClass ; IntersCurveCurve intCC( *pCrv2, *pCrv) ; if ( ! intCC.GetCurveClassification( 0, EPS_SMALL, ccClass)) continue ; // conservo solo le parti interne for ( int k = 0 ; k < int( ccClass.size()) ; ++ k) { if ( ccClass[k].nClass != CRVC_IN) inCrv.Subtract( ccClass[k].dParS, ccClass[k].dParE) ; } // tratti di curva rimasti int nNum = inCrv.GetCount() ; // se rimangono uno o più tratti if ( nNum >= 1) { double dParS, dParE ; bool bInt = inCrv.GetFirst( dParS, dParE) ; while ( bInt) { // copio la curva e la modifico int nCopyId = pGeomDB->Copy( vOpenIds[j], GDB_ID_NULL, nLayId) ; // modifico l'originale ICurve* pOriCrv = GetCurve( pGeomDB->GetGeoObj( nCopyId)) ; pOriCrv->TrimStartEndAtParam( dParS, dParE) ; // passo al successivo intervallo bInt = inCrv.GetNext( dParS, dParE) ; } } } // cerco il testo contenuto almeno parzialmente e più vicino al centro del pezzo double dMinSqDist = SQ_INFINITO ; int nMinJ = -1 ; for ( int j = 0 ; j < int( vTextIds.size()) ; ++ j) { if ( vTextIds[j] == GDB_ID_NULL) continue ; // verifico se il box del testo interferisce con il box del contorno BBox3d b3Text ; if ( pGeomDB->GetGlobalBBox( vTextIds[j], b3Text) && b3Part.OverlapsXY( b3Text)) { // verifico se a minima distanza Point3d ptCen ; b3Text.GetCenter( ptCen) ; double dSqDist = SqDistXY( ptPartCen, ptCen) ; if ( dSqDist < dMinSqDist) { dMinSqDist = dSqDist ; nMinJ = j ; } } } // se trovato un testo, lo inserisco nel pezzo if ( nMinJ != -1) { pGeomDB->RelocateGlob( vTextIds[nMinJ], nLayId) ; vTextIds[nMinJ] = GDB_ID_NULL ; } } // elimino la geometria originale rimasta pGeomDB->Erase( nParentId) ; return true ; } //---------------------------------------------------------------------------- static bool CreateFlatPartsByLayers( void) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // preparo gli iteratori PtrOwner pPar( CreateGdbIterator( pGeomDB)) ; PtrOwner pLay( CreateGdbIterator( pGeomDB)) ; if ( IsNull( pPar) || IsNull( pLay)) return false ; // ciclo su tutti i gruppi della radice (pezzi) bool bPok = pPar->GoToFirstGroupInGroup( GDB_ID_ROOT) ; int nFirstId = pPar->GetId() ; while ( bPok) { // ciclo su tutti i sottogruppi (layer) bool bLok = pLay->GoToFirstGroupInGroup( *pPar) ; while ( bLok) { // creo pezzo con questa geometria int nPartId = pGeomDB->InsertGroup( GDB_ID_NULL, nFirstId, GDB_BEFORE, Frame3d()) ; // passo al pezzo l'eventuale nome del layer string sName ; if ( pLay->GetName( sName)) { pGeomDB->SetName( nPartId, sName) ; pLay->RemoveName() ; } // sposto il layer sotto questo pezzo if ( ! pGeomDB->RelocateGlob( pLay->GetId(), nPartId)) return false ; // altro layer del gruppo originale bLok = pLay->GoToFirstGroupInGroup( *pPar) ; } // passo al successivo bPok = pPar->GoToNextGroup() ; } // cancello i gruppi svuotati bPok = pPar->GoTo( nFirstId) ; while ( bPok) bPok = pPar->EraseAndGoToNext() ; return true ; } //---------------------------------------------------------------------------- static bool CreateFlatPartsByClosedCurves( void) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // preparo gli iteratori PtrOwner pPar( CreateGdbIterator( pGeomDB)) ; PtrOwner pLay( CreateGdbIterator( pGeomDB)) ; PtrOwner pEnt( CreateGdbIterator( pGeomDB)) ; if ( IsNull( pPar) || IsNull( pLay) || IsNull( pEnt)) return false ; // ciclo su tutti i gruppi della radice (pezzi) INTVECTOR vTextIds ; // vettore indici testi bool bPok = pPar->GoToFirstGroupInGroup( GDB_ID_ROOT) ; int nFirstId = pPar->GetId() ; while ( bPok) { // ciclo su tutti i sottogruppi (layer) bool bLok = pLay->GoToFirstGroupInGroup( *pPar) ; while ( bLok) { // ciclo su tutte le entità bool bEok = pEnt->GoToFirstInGroup( *pLay) ; while ( bEok) { // se curva chiusa if ( ( pEnt->GetGeoType() & GEO_CURVE) != 0 && GetCurve( pEnt->GetGeoObj())->IsClosed()) { // creo pezzo e layer per questa geometria int nPartId = pGeomDB->InsertGroup( GDB_ID_NULL, nFirstId, GDB_BEFORE, Frame3d()) ; int nLayerId = pGeomDB->InsertGroup( GDB_ID_NULL, nPartId, GDB_LAST_SON, Frame3d()) ; int nEntId = pEnt->GetId() ; // recupero successiva entità bEok = pEnt->GoToNext() ; // sposto l'entità sotto questo layer if ( ! pGeomDB->RelocateGlob( nEntId, nLayerId)) return false ; } // se altrimento testi, ne salvo l'identificativo else if ( pEnt->GetGeoType() == EXT_TEXT) { vTextIds.emplace_back( pEnt->GetId()) ; bEok = pEnt->GoToNext() ; } // altrimenti cancello else bEok = pEnt->EraseAndGoToNext() ; } // altro layer del gruppo originale bLok = pLay->GoToNextGroup() ; } // passo al successivo bPok = pPar->GoToNextGroup() ; } // ciclo sui pezzi creati, per eventuale inserimento testi for ( bool bPok = pPar->GoToFirstGroupInGroup( GDB_ID_ROOT) ; bPok && pPar->GetId() != nFirstId ; bPok = pPar->GoToNextGroup()) { // ingombro e centro del pezzo BBox3d b3Part ; if ( ! pGeomDB->GetGlobalBBox( pPar->GetId(), b3Part)) continue ; Point3d ptPartCen ; b3Part.GetCenter( ptPartCen) ; // cerco il testo contenuto almeno parzialmente e più vicino al centro del pezzo double dMinSqDist = SQ_INFINITO ; int nMinJ = -1 ; for ( int j = 0 ; j < int( vTextIds.size()) ; ++ j) { if ( vTextIds[j] == GDB_ID_NULL) continue ; // verifico se il box del testo interferisce con il box del contorno BBox3d b3Text ; if ( pGeomDB->GetGlobalBBox( vTextIds[j], b3Text) && b3Part.OverlapsXY( b3Text)) { // verifico se a minima distanza Point3d ptCen ; b3Text.GetCenter( ptCen) ; double dSqDist = SqDistXY( ptPartCen, ptCen) ; if ( dSqDist < dMinSqDist) { dMinSqDist = dSqDist ; nMinJ = j ; } } } // se trovato un testo, lo inserisco nel pezzo if ( nMinJ != -1) { pGeomDB->RelocateGlob( vTextIds[nMinJ], pGeomDB->GetFirstGroupInGroup( pPar->GetId())) ; vTextIds[nMinJ] = GDB_ID_NULL ; } } // elimino i testi rimasti non assegnati for ( int j = 0 ; j < int( vTextIds.size()) ; ++ j) { if ( vTextIds[j] != GDB_ID_NULL) pGeomDB->Erase( vTextIds[j]) ; } // cancello i gruppi svuotati bPok = pPar->GoTo( nFirstId) ; while ( bPok) bPok = pPar->EraseAndGoToNext() ; return true ; } //---------------------------------------------------------------------------- static bool VerifyPrepareFlatParts( void) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // preparo gli iteratori PtrOwner pPar( CreateGdbIterator( pGeomDB)) ; PtrOwner pEnt( CreateGdbIterator( pGeomDB)) ; if ( IsNull( pPar) || IsNull( pEnt)) return false ; // ciclo sui pezzi bool bPok = pPar->GoToFirstGroupInGroup( GDB_ID_ROOT) ; while ( bPok) { // seleziono tutte le curve del pezzo ExeSetObjFilterForSelect( false, true, false, false, false) ; bool bOk = ExeSelectPartObjs( pPar->GetId()) ; // creo un nuovo layer in cui mettere tutti i concatenati int nRegId = ExeCreateGroup( pPar->GetId(), Frame3d(), RTY_GLOB) ; bOk = ( bOk && nRegId != GDB_ID_NULL) ; bOk = bOk && pGeomDB->SetName( nRegId, NST_PARTREG_LAYER) ; // concateno tutte le curve INTVECTOR vIds ; vIds.push_back( GDB_ID_SEL) ; int nCount ; int nFirstId = ( bOk ? ExeCreateCurveCompoByChain( nRegId, vIds, ORIG, false, RTY_GLOB, &nCount) : GDB_ID_NULL) ; bOk = ( bOk && nFirstId != GDB_ID_NULL) ; // deseleziono tutto pGeomDB->ClearSelection() ; // elimino le curve aperte del nuovo layer e uso le chiuse per creare la regione INTVECTOR vOpenIds ; STRVECTOR vClosedIds ; SurfFlatRegionByContours SfrCntr( false, false) ; bool bEok = pEnt->GoToFirstInGroup( nRegId) ; while ( bEok) { ICurve* pCrv = GetCurve( pEnt->GetGeoObj()) ; if ( pCrv == nullptr) { bEok = pEnt->EraseAndGoToNext() ; } else if ( ! pCrv->IsClosed()) { // salvo Id di origine nell'elenco curve aperte da controllare INTVECTOR vTmpIds ; if ( pGeomDB->GetInfo( pEnt->GetId(), CRV_ORIG, vTmpIds)) vOpenIds.insert( vOpenIds.end(), vTmpIds.begin(), vTmpIds.end()) ; bEok = pEnt->EraseAndGoToNext() ; } else { // verifico sia orientata in senso CCW double dArea ; pCrv->GetAreaXY( dArea) ; if ( abs( dArea) < MIN_AREA) { bEok = pEnt->EraseAndGoToNext() ; continue ; } else if ( dArea < 0) pCrv->Invert() ; // salvo Id entità corrente e preparo passaggio a prossima int nEntId = pEnt->GetId() ; bEok = pEnt->GoToNext() ; // salvo stringa con elenco Id di origine string sInfo ; if ( pGeomDB->GetInfo( nEntId, CRV_ORIG, sInfo)) { vClosedIds.emplace_back( sInfo) ; pCrv->SetTempProp( int( vClosedIds.size())) ; } // estraggo curva da entità che viene cancellata SfrCntr.AddCurve( pCrv) ; pGeomDB->RemoveGeoObjAndErase( nEntId) ; } } // creo la regione ISurfFlatRegion* pSfr = SfrCntr.GetSurf() ; bOk = bOk && ( pSfr != nullptr) ; // inserisco eventuali curve chiuse non usate nell'elenco delle aperte if ( ! SfrCntr.AllCurvesUsed()) { // recupero indice da proprietà temporanea di curve non usate INTVECTOR vUnId ; SfrCntr.GetUnusedCurveTempProps( vUnId) ; // recupero Id originali associati for ( auto nUnId : vUnId) { if ( nUnId > 0 && nUnId <= int( vClosedIds.size())) { INTVECTOR vTmpIds ; if ( FromString( vClosedIds[nUnId - 1], vTmpIds)) vOpenIds.insert( vOpenIds.end(), vTmpIds.begin(), vTmpIds.end()) ; } } } // inserisco la superficie nel DB int nNewId = ( bOk ? pGeomDB->AddGeoObj( GDB_ID_NULL, nRegId, pSfr) : GDB_ID_NULL) ; bOk = ( bOk && nNewId != GDB_ID_NULL) ; // assegno il colore Color cCol = AQUA ; cCol.SetAlpha( 0.25) ; bOk = bOk && pGeomDB->SetMaterial( nNewId, cCol) ; // scrittura di eventuale testo e delle dimensioni nel layer della regione if ( bOk) { string sText ; // recupero eventuale testo associato al pezzo int nTextId = pGeomDB->GetFirstInGroup( pGeomDB->GetFirstGroupInGroup( pPar->GetId())) ; while ( nTextId != GDB_ID_NULL && pGeomDB->GetGeoType( nTextId) != EXT_TEXT) nTextId = pGeomDB->GetNext( nTextId) ; ExeTextGetContent( nTextId, sText) ; // se non vuoto lo assegno come nome if ( ! IsEmptyOrSpaces( sText)) pGeomDB->SetName( pPar->GetId(), sText) ; // se non vuoto aggiungo separatore di linea if ( ! sText.empty()) sText += ETXT_LINEBREAK ; // recupero dimensioni pezzo BBox3d b3Reg ; pGeomDB->GetGlobalBBox( nNewId, b3Reg) ; Point3d ptMin, ptMax ; b3Reg.GetMinMax( ptMin, ptMax) ; double dDimX = ptMax.x - ptMin.x ; double dDimY = ptMax.y - ptMin.y ; sText += ToString( ExeToUiUnits( dDimX), 2) + "x" + ToString( ExeToUiUnits( dDimY), 2) ; Point3d ptCen = Media( ptMin, ptMax, 0.5) ; Vector3d vtDir = ( dDimX >= dDimY ? X_AX : Y_AX) ; double dDimT = min( 0.05 * max( dDimX, dDimY), 0.5 * min( dDimX, dDimY)) ; PtrOwner pText( CreateExtText()) ; if ( ! IsNull( pText) && pText->Set( ptCen, Z_AX, vtDir, sText, "", 100, false, dDimT, 1, 0, ETXT_IPMC)) { int nTextId = pGeomDB->AddGeoObj( GDB_ID_NULL, nRegId, Release( pText)) ; pGeomDB->SetMaterial( nTextId, BLACK) ; } } // creo un nuovo layer in cui copiare il contorno esterno PtrOwner pOutCrv( bOk ? pSfr->GetLoop( 0, 0) : nullptr) ; if ( ! IsNull( pOutCrv)) { int nOutLoopId = ExeCreateGroup( pPar->GetId(), Frame3d(), RTY_GLOB) ; bOk = bOk && nOutLoopId != GDB_ID_NULL ; bOk = bOk && pGeomDB->SetName( nOutLoopId, NST_OUT_LAYER) ; pGeomDB->AddGeoObj( GDB_ID_NULL, nOutLoopId, Release( pOutCrv)) ; } // creo nuovi layer in cui copiare gli eventuali contorni interni if ( bOk && pSfr->GetLoopCount( 0) > 1) { int i = 1 ; PtrOwner pInCrv( bOk ? pSfr->GetLoop( 0, i) : nullptr) ; while ( ! IsNull( pInCrv)) { int nInLoopId = ExeCreateGroup( pPar->GetId(), Frame3d(), RTY_GLOB) ; bOk = bOk && nInLoopId != GDB_ID_NULL ; bOk = bOk && pGeomDB->SetName( nInLoopId, NST_IN_LAYER) ; pGeomDB->AddGeoObj( GDB_ID_NULL, nInLoopId, Release( pInCrv)) ; ++ i ; pInCrv.Set( bOk ? pSfr->GetLoop( 0, i) : nullptr) ; } } // creo nuovi layer in cui mettere le curve aperte if ( bOk && vOpenIds.size() > 0) { for ( int i = 0 ; bOk && i < int( vOpenIds.size()) ; ++i) { int nOnPathId = ExeCreateGroup( pPar->GetId(), Frame3d(), RTY_GLOB) ; bOk = bOk && nOnPathId != GDB_ID_NULL ; bOk = bOk && pGeomDB->SetName( nOnPathId, NST_ON_LAYER) ; pGeomDB->RelocateGlob( vOpenIds[i], nOnPathId) ; } } // taglio le curve aperte con la regione for ( int i = 0 ; bOk && i < int( vOpenIds.size()) ; ++i) { ICurve* pCrv = GetCurve( pGeomDB->GetGeoObj( vOpenIds[i])) ; // calcolo la classificazione della curva rispetto alla regione CRVCVECTOR ccClass ; if ( ! pSfr->GetCurveClassification( *pCrv, EPS_SMALL, ccClass)) continue ; // conservo solo gli intervalli di curva interni Intervals inOk ; for ( auto& ccOne : ccClass) { if ( ccOne.nClass == CRVC_IN) inOk.Add( ccOne.dParE, ccOne.dParS) ; } // recupero un intervallo di id contigui per tutte le parti int nFirstId = pGeomDB->GetNewId() ; if ( nFirstId == vOpenIds[i] + 1) nFirstId = vOpenIds[i] ; pGeomDB->ChangeId( vOpenIds[i], nFirstId) ; int nCurrId = nFirstId ; // eseguo la divisione nCount = 0 ; double dParS, dParE ; bool bFound = inOk.GetFirst( dParS, dParE) ; while ( bFound) { // copio la curva int nCopyId = pGeomDB->Copy( nCurrId, GDB_ID_NULL, nCurrId, GDB_AFTER) ; ICurve* pCopyCrv = GetCurve( pGeomDB->GetGeoObj( nCopyId)) ; if ( pCopyCrv == nullptr) break ; ++ nCount ; // modifico l'originale bOk = bOk && pCrv->TrimStartEndAtParam( dParS, dParE) ; // la copia diventa il nuovo corrente nCurrId = nCopyId ; pCrv = pCopyCrv ; // passo alla successiva divisione bFound = inOk.GetNext( dParS, dParE) ; } // cancello l'ultima copia (se non c'erano intervalli validi è l'originale) if ( nCurrId != GDB_ID_NULL) pGeomDB->Erase( nCurrId) ; } // se errore sul pezzo, lo elimino if ( ! bOk) bPok = pPar->EraseAndGoToNextGroup() ; // passo al pezzo successivo else bPok = pPar->GoToNextGroup() ; } // ripristino filtro selezione ExeSetObjFilterForSelect( true, true, true, true, true) ; return true ; } //---------------------------------------------------------------------------- bool ExeCreateAdjustFlatParts( int nType, double dToler) { // Disabilito registrazione comandi CmdLogOff cmdLogOff ; // filtro e approssimo le curve FilterAndApprox( dToler) ; // salvo punto medio curve con colore proprio PNTCOLVECTOR vPntCol ; SaveColorWithMidPnt( vPntCol) ; // creo i pezzi if ( ! ExeCreateFlatParts( nType, dToler)) return false ; // sistemo i pezzi if ( ! ExeAdjustFlatParts()) return false ; // ripristino dei colori originali delle curve ApplyColorWithMidPnt( vPntCol) ; return true ; } //---------------------------------------------------------------------------- bool ExeCreateFlatParts( int nType, double dToler) { // disabilito registrazione comandi CmdLogOff cmdLogOff ; // filtro e approssimo le curve bool bOk = FilterAndApprox( dToler) ; // creazione basata sulle regioni if ( nType == FPC_REGION) { int nLay ; // concateno bOk = bOk && ChainCurves( nLay) ; // costruisco i pezzi bOk = bOk && CreateFlatPartsByRegions( nLay) ; } // creazione basata sui layer else if ( nType == FPC_LAYER) { // costruisco i pezzi bOk = bOk && CreateFlatPartsByLayers() ; } // creazione basata su curve chiuse else if ( nType == FPC_CLOSEDCURVE) { // costruisco i pezzi bOk = bOk && CreateFlatPartsByClosedCurves() ; } // creazione basata sui pezzi NGE // sono già a posto // verifica e aggiustamento dei pezzi bOk = bOk && VerifyPrepareFlatParts() ; return bOk ; } //---------------------------------------------------------------------------- bool ExeAdjustFlatParts( void) { // Disabilito registrazione comandi CmdLogOff cmdLogOff ; // Ciclo sui pezzi bool bOk = true ; int nPartId = ExeGetFirstPart( false) ; while ( nPartId != GDB_ID_NULL) { // Sistemo il pezzo bOk = ExeAdjustFlatPart( nPartId) && bOk ; // Passo al pezzo successivo nPartId = ExeGetNextPart(nPartId, false) ; } return bOk ; } //---------------------------------------------------------------------------- bool ExeAdjustFlatPart( int nPartId) { // Disabilito registrazione comandi CmdLogOff cmdLogOff ; // Ciclo sui layer int nLayerId = ExeGetFirstLayer( nPartId, false) ; while ( nLayerId != GDB_ID_NULL) { // Recupero il layer successivo int nNextLayerId = ExeGetNextLayer( nLayerId, false) ; // Recupero il nome del layer string sLayName ; if ( ExeGetName( nLayerId, sLayName)) { // Se layer OutLoop o InLoop if ( sLayName == NST_OUT_LAYER || sLayName == NST_IN_LAYER) { // Sistemo i layer per applicare facilmente le lavorazioni ExeAdjustFlatPartLayer( nLayerId) ; } } // Se senza nome, lo elimino else ExeErase( {nLayerId}) ; // Passo al layer successivo nLayerId = nNextLayerId ; } return true ; } //---------------------------------------------------------------------------- static bool MyCreateCurveCompoByReorder( IGeomDB* pGeomDB, int nLayerId, const INTVECTOR& vCrvIds) { int nCount = 0 ; int nFirstId = ExeCreateCurveCompoByReorder( nLayerId, vCrvIds, ORIG, false, RTY_GLOB, &nCount) ; for ( int i = 0 ; i < nCount ; ++ i) { int nCurrId = nFirstId + i ; INTVECTOR vOrigId ; pGeomDB->GetInfo( nCurrId, CRV_ORIG, vOrigId) ; for ( int j = 0 ; j < int( vOrigId.size()) ; ++ j) { if ( j == 0) pGeomDB->CopyAttributes( vOrigId[j], nCurrId) ; pGeomDB->Erase( vOrigId[j]) ; } } return ( nCount > 0) ; } //---------------------------------------------------------------------------- static double MyIntersectRayLayerCurves( IGeomDB* pGeomDB, Point3d ptP, Vector3d vtDir, bool bMatOnLeft, int nLayerId, int nNoId) { // semiretta tangente const double HL_LEN = 10000 ; const double HL_OFFS = 0.01 ; PtrOwner pLine( CreateCurveLine()) ; if ( IsNull( pLine) || ! pLine->SetPVL( ptP + vtDir * HL_OFFS, vtDir, HL_LEN)) return 0 ; // cerco intersezione con le curve del layer (tranne quella esclusa) double dFirstDist = INFINITO ; int nIntId = pGeomDB->GetFirstInGroup( nLayerId) ; while ( nIntId != GDB_ID_NULL) { if ( nIntId != nNoId) { const ICurve* pIntCrv = GetCurve( pGeomDB->GetGeoObj( nIntId)) ; if ( pIntCrv != nullptr) { // cerco intersezioni della semiretta che entrano nel pezzo IntersCurveCurve intCC( *pLine, *pIntCrv) ; if ( intCC.GetIntersCount() > 0) { IntCrvCrvInfo aInfo ; intCC.GetIntCrvCrvInfo( 0, aInfo) ; if ( ! aInfo.bOverlap) { // se intersezione va dentro if ( aInfo.IciA[0].nNextTy == ICCT_IN) { double dDist = aInfo.IciA[0].dU * HL_LEN ; if ( dDist < dFirstDist) dFirstDist = dDist ; } // se intersezione indefinita, la classifico else if ( aInfo.IciA[0].nNextTy == ICCT_NULL) { Point3d ptMid ; pIntCrv->GetMidPoint( ptMid) ; double dDist = CrossXY( vtDir, ( ptMid - ptP)) ; if ( ( bMatOnLeft && dDist < -EPS_SMALL) || ( ! bMatOnLeft && dDist > EPS_SMALL)) { double dDist = aInfo.IciA[0].dU * HL_LEN ; if ( dDist < dFirstDist) dFirstDist = dDist ; } } // intersezioni sovrapposte si possono ignorare } } } } nIntId = pGeomDB->GetNext( nIntId) ; } // restituisco la distanza del primo punto di intersezione (infinito se non trovata) return dFirstDist ; } //---------------------------------------------------------------------------- static double MyIntersectArcLayerCurves( IGeomDB* pGeomDB, Point3d ptP, Vector3d vtDir, double dRad, bool bMatOnLeft, int nLayerId, int nNoId) { // semicirconferenza tangente const double HA_ANG = 270 ; const double HA_OFFS = 0.01 ; Vector3d vtOrtho = vtDir ; vtOrtho.Rotate( Z_AX, 0, ( dRad > 0 ? -1 : 1)) ; Point3d ptIni = ptP + vtDir * HA_OFFS ; Point3d ptCen = ptIni - vtOrtho * abs( dRad) ; PtrOwner pArc( CreateCurveArc()) ; if ( IsNull( pArc) || ! pArc->SetCPA( ptCen, ptIni, ( dRad > 0 ? HA_ANG : -HA_ANG), 0)) return 0 ; // cerco intersezione con le curve del layer (tranne quella esclusa) double dFirstDist = INFINITO ; int nIntId = pGeomDB->GetFirstInGroup( nLayerId) ; while ( nIntId != GDB_ID_NULL) { if ( nIntId != nNoId) { const ICurve* pIntCrv = GetCurve( pGeomDB->GetGeoObj( nIntId)) ; if ( pIntCrv != nullptr) { // cerco intersezioni della semicirconferenza che entrano nel pezzo IntersCurveCurve intCC( *pArc, *pIntCrv) ; if ( intCC.GetIntersCount() > 0) { IntCrvCrvInfo aInfo ; intCC.GetIntCrvCrvInfo( 0, aInfo) ; if ( ! aInfo.bOverlap) { // se intersezione va dentro if ( aInfo.IciA[0].nNextTy == ICCT_IN) { double dDist = aInfo.IciA[0].dU * HA_ANG * DEGTORAD * abs( dRad) ; if ( dDist < dFirstDist) dFirstDist = dDist ; } // se intersezione indefinita, la classifico else if ( aInfo.IciA[0].nNextTy == ICCT_NULL) { Point3d ptMid ; pIntCrv->GetMidPoint( ptMid) ; double dDist = CrossXY( vtDir, ( ptMid - ptP)) ; if ( ( bMatOnLeft && dDist < -EPS_SMALL) || ( ! bMatOnLeft && dDist > EPS_SMALL)) { double dDist = aInfo.IciA[0].dU * HA_ANG * DEGTORAD * abs( dRad) ; if ( dDist < dFirstDist) dFirstDist = dDist ; } } // intersezioni sovrapposte si possono ignorare } } } } nIntId = pGeomDB->GetNext( nIntId) ; } // restituisco la distanza del primo punto di intersezione (infinito se non trovata) return dFirstDist ; } //---------------------------------------------------------------------------- bool ExeAdjustFlatPartLayer( int nLayerId) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // Disabilito registrazione comandi CmdLogOff cmdLogOff ; bool bOk = true ; // Elimino dal gruppo gli oggetti che non sono curve int nId = pGeomDB->GetFirstInGroup( nLayerId) ; while ( nId != GDB_ID_NULL && bOk) { // Recupero successiva int nNextId = pGeomDB->GetNext( nId) ; // Se non è una curva, la cancello if ( ( pGeomDB->GetGeoType( nId) & GEO_CURVE) == 0) pGeomDB->Erase( nId) ; // Passo all'entità successiva nId = nNextId ; } // Compatto e poi esplodo le curve composite nId = pGeomDB->GetFirstInGroup( nLayerId) ; while ( nId != GDB_ID_NULL && bOk) { // Recupero successiva int nNextId = pGeomDB->GetNext( nId) ; // Se curva composita if ( pGeomDB->GetGeoType( nId) == CRV_COMPO) { // Compatto bOk = ExeMergeCurvesInCurveCompo( nId, 10 * EPS_SMALL, true) && bOk ; // Esplodo in curve semplici bOk = ExeExplodeCurveCompo( nId, nullptr) && bOk ; } // Passo all'entità successiva nId = nNextId ; } // Unisco gli archi consecutivi convessi (quindi con angolo al centro positivo) INTVECTOR vAccwIds ; nId = pGeomDB->GetFirstInGroup( nLayerId) ; while ( nId != GDB_ID_NULL && bOk) { const ICurveArc* pArc = GetCurveArc( pGeomDB->GetGeoObj( nId)) ; if ( pArc != nullptr) { double dAngCen = pArc->GetAngCenter() ; if ( dAngCen > EPS_ANG_SMALL && dAngCen < ANG_FULL - EPS_ANG_SMALL) vAccwIds.emplace_back( nId) ; } nId = pGeomDB->GetNext( nId) ; } if ( vAccwIds.size() > 1) bOk = MyCreateCurveCompoByReorder( pGeomDB, nLayerId, vAccwIds) && bOk ; // Spezzo le curve composite con discontinuità sulla tangente nId = pGeomDB->GetFirstInGroup( nLayerId) ; while ( nId != GDB_ID_NULL && bOk) { // Recupero successiva int nNextId = pGeomDB->GetNext( nId) ; // Se curva composita if ( pGeomDB->GetGeoType( nId) == CRV_COMPO) { bOk = ( ExeSplitCurveAtCorners( nId, 5.0, nullptr) != GDB_ID_NULL) && bOk ; } // Passo all'entità successiva nId = nNextId ; } // Riconduco a curva semplice le composite formate da una sola curva semplice nId = pGeomDB->GetFirstInGroup( nLayerId) ; while ( nId != GDB_ID_NULL && bOk) { // Recupero successiva int nNextId = pGeomDB->GetNext( nId) ; // Se curva composita formata da una sola curva semplice if ( pGeomDB->GetGeoType( nId) == CRV_COMPO) { const ICurveComposite* pCrvCompo = GetCurveComposite( pGeomDB->GetGeoObj( nId)) ; if ( pCrvCompo->GetCurveCount() == 1) bOk = ExeExplodeCurveCompo( nId, nullptr) && bOk ; } // Passo all'entità successiva nId = nNextId ; } // Aggiorno l'ordinamento bOk = bOk && ExeReorderCurvesInGroup( nLayerId, ORIG, RTY_GLOB) ; // Inserisco in ogni curva info su angoli con precedente e successiva int nFirstId = pGeomDB->GetFirstInGroup( nLayerId) ; nId = nFirstId ; while ( bOk && nId != GDB_ID_NULL) { // Recupero successiva int nNextId = pGeomDB->GetNext( nId) ; // Successiva geometrica (si considera il layer formato da curve contigue che si chiudono) int nCalcId = (( nNextId != GDB_ID_NULL) ? nNextId : nFirstId) ; if ( nCalcId != GDB_ID_NULL) { // Recupero le due curve const ICurve* pCrv1 = GetCurve( pGeomDB->GetGeoObj( nId)) ; const ICurve* pCrv2 = GetCurve( pGeomDB->GetGeoObj( nCalcId)) ; if ( pCrv1 == nullptr || pCrv2 == nullptr) { bOk = false ; continue ; } // Punto di giunzione Point3d ptP ; pCrv1->GetEndPoint( ptP) ; // Direzione finale curva corrente e iniziale curva successiva Vector3d vtDir1, vtDir2 ; if ( ! pCrv1->GetEndDir( vtDir1) || ! pCrv2->GetStartDir( vtDir2)) { bOk = false ; continue ; } // Determino l'angolo tra le due direzioni double dAngDeg1 = 0 ; vtDir1.GetAngleXY( vtDir2, dAngDeg1) ; double dAngDeg2 = dAngDeg1 ; // Se angolo piccolo (circa tangenti), verifico se hanno lo stesso raggio di curvatura const double EPS_ANG_TG = 5.0 ; if ( abs( dAngDeg1) < EPS_ANG_TG) { // prima curva double dUStart1, dUEnd1 ; pCrv1->GetDomain( dUStart1, dUEnd1) ; Point3d ptP1 ; pCrv1->GetPointD1D2( dUEnd1 - 0.25, ICurve::FROM_PLUS, ptP1) ; Vector3d vtDiff1 = ptP - ptP1 ; double dAngDiff1Deg ; vtDiff1.GetAngleXY( vtDir1, dAngDiff1Deg) ; // seconda curva double dUStart2, dUEnd2 ; pCrv2->GetDomain( dUStart2, dUEnd2) ; Point3d ptP2 ; pCrv2->GetPointD1D2( dUStart2 + 0.25, ICurve::FROM_MINUS, ptP2) ; Vector3d vtDiff2 = ptP2 - ptP ; double dAngDiff2Deg ; vtDir2.GetAngleXY( vtDiff2, dAngDiff2Deg) ; // se entrambe concave if ( dAngDiff1Deg < - EPS_ANG_SMALL && dAngDiff2Deg < - EPS_ANG_SMALL) { // se non sono archi con raggio quasi uguale, li considero entrambi concavi const ICurveArc* pArc1 = GetCurveArc( pCrv1) ; const ICurveArc* pArc2 = GetCurveArc( pCrv2) ; if ( pArc1 == nullptr || pArc2 == nullptr || abs( pArc1->GetRadius() - pArc2->GetRadius()) > 10.) { dAngDeg1 = - 1 ; dAngDeg2 = - 1 ; } } // se altrimenti prima concava else if ( dAngDiff1Deg < -EPS_ANG_SMALL) dAngDeg2 = - 1 ; // se altrimenti seconda concava else if ( dAngDiff2Deg < -EPS_ANG_SMALL) dAngDeg1 = - 1 ; } // Scrivo l'angolo nelle info delle curve pGeomDB->SetInfo( nId, MCH_KEY_NEXTANG, dAngDeg1) ; pGeomDB->SetInfo( nCalcId, MCH_KEY_PREVANG, dAngDeg2) ; // Se precedente non forma angolo interno con successivo if ( dAngDeg1 > -EPS_ANG_SMALL) { // Cerco lunghezza libera di prosecuzione tangente double dFreeDist = MyIntersectRayLayerCurves( pGeomDB, ptP, vtDir1, true, nLayerId, nId) ; // Se curva con angolo esterno oltre 30deg cerco eventuale ulteriore limite per prosecuzione curva if ( pCrv1->GetType() != CRV_LINE && dAngDeg1 > FL_ARC_ANG_MIN) { double dUmin, dUmax ; pCrv1->GetDomain( dUmin, dUmax) ; CrvPointDiffGeom oDiffG ; if ( pCrv1->GetPointDiffGeom( dUmax, ICurve::FROM_MINUS, oDiffG) && oDiffG.nStatus == CrvPointDiffGeom::NCRV) { if ( oDiffG.dCurv > EPS_TRIA_H) { double dRad = 1 / oDiffG.dCurv * ( CrossXY( oDiffG.vtT, oDiffG.vtN) > 0 ? 1 : -1) ; double dArcFreeDist = MyIntersectArcLayerCurves( pGeomDB, ptP, vtDir1, dRad, true, nLayerId, nId) ; dFreeDist = min( dFreeDist, dArcFreeDist) ; } } } // Se c'è un limite, lo salvo if ( dFreeDist < INFINITO) pGeomDB->SetInfo( nId, MCH_KEY_END_FREELEN, dFreeDist) ; } // Se successivo non forma angolo interno con precedente if ( dAngDeg2 > -EPS_ANG_SMALL) { // Cerco lunghezza libera di prosecuzione tangente all'indietro double dFreeDist = MyIntersectRayLayerCurves( pGeomDB, ptP, -vtDir2, false, nLayerId, nCalcId) ; // Se curva con angolo esterno oltre 30deg cerco eventuale ulteriore limite per prosecuzione curva if ( pCrv2->GetType() != CRV_LINE && dAngDeg2 > FL_ARC_ANG_MIN) { double dUmin, dUmax ; pCrv2->GetDomain( dUmin, dUmax) ; CrvPointDiffGeom oDiffG ; if ( pCrv2->GetPointDiffGeom( dUmin, ICurve::FROM_PLUS, oDiffG) && oDiffG.nStatus == CrvPointDiffGeom::NCRV) { if ( oDiffG.dCurv > EPS_TRIA_H) { double dRad = 1 / oDiffG.dCurv * ( CrossXY( oDiffG.vtT, oDiffG.vtN) > 0 ? -1 : 1) ; double dArcFreeDist = MyIntersectArcLayerCurves( pGeomDB, ptP, -vtDir2, dRad, false, nLayerId, nId) ; dFreeDist = min( dFreeDist, dArcFreeDist) ; } } } // Se c'è un limite, lo salvo if ( dFreeDist < INFINITO) pGeomDB->SetInfo( nCalcId, MCH_KEY_START_FREELEN, dFreeDist) ; } } // Passo all'entità successiva nId = nNextId ; } return bOk ; } //---------------------------------------------------------------------------- static bool AdjustCurves( ICurve* pCrv1, ICurve* pCrv2) { // se fine della prima coincide con inizio della seconda non devo fare alcunchè Point3d ptEnd1 ; pCrv1->GetEndPoint( ptEnd1) ; Point3d ptStart2 ; pCrv2->GetStartPoint( ptStart2) ; if ( AreSamePointApprox( ptEnd1, ptStart2)) return true ; // allungo le due curve if ( ! pCrv1->ExtendEndByLen( 200) || ! pCrv2->ExtendStartByLen( 200)) return false ; // cerco intersezioni IntersCurveCurve intCC( *pCrv1, *pCrv2) ; if ( intCC.GetIntersCount() == 0) return false ; // prendo l'intersezione più vicina al punto medio tra gli estremi originali delle curve Point3d ptMid = 0.5 * ( ptEnd1 + ptStart2) ; Point3d ptNew1, ptNew2 ; if ( ! intCC.GetIntersPointNearTo( 0, ptMid, ptNew1) || ! intCC.GetIntersPointNearTo( 1, ptMid, ptNew2)) return false ; // modifico le due curve sul punto medio Point3d ptNew = 0.5 * ( ptNew1 + ptNew2) ; return ( pCrv1->ModifyEnd( ptNew) && pCrv2->ModifyStart( ptNew)) ; } //---------------------------------------------------------------------------- static bool ExeUpdateFlatPartRegion( int nPartId, bool bCalc) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // ripristino lo stato originale int nRegOrigId = pGeomDB->GetFirstNameInGroup( nPartId, NST_PARTREG_ORIG_LAYER) ; if ( nRegOrigId != GDB_ID_NULL) { pGeomDB->Erase( pGeomDB->GetFirstNameInGroup( nPartId, NST_PARTREG_LAYER)) ; pGeomDB->SetName( nRegOrigId, NST_PARTREG_LAYER) ; pGeomDB->SetStatus( nRegOrigId, GDB_ST_ON) ; } // se non richiesto calcolo, non devo fare altro if ( ! bCalc) return true ; // recupero il layer esterno int nOlId = pGeomDB->GetFirstNameInGroup( nPartId, NST_OUT_LAYER) ; if ( nOlId == GDB_ID_NULL) return false ; // se il pezzo non ha lati esterni a singola inclinazione con offset negativo non devo fare alcunchè bool bAllFixSides = true ; int nCrvId = pGeomDB->GetFirstInGroup( nOlId) ; while ( nCrvId != GDB_ID_NULL) { double dOffset ; if ( pGeomDB->GetInfo( nCrvId, NST_KEY_OFFSET, dOffset) && dOffset < - EPS_SMALL && ! pGeomDB->ExistsInfo( nCrvId, NST_KEY_SIDEANG2)) { bAllFixSides = false ; break ; } nCrvId = pGeomDB->GetNext( nCrvId) ; } if ( bAllFixSides) return true ; // creo il layer per la nuova regione (con il medesimo riferimento del layer esterno) Frame3d frOl ; pGeomDB->GetGroupFrame( nOlId, frOl) ; int nNewRegId = pGeomDB->AddGroup( GDB_ID_NULL, nPartId, frOl) ; if ( nNewRegId == GDB_ID_NULL) return false ; // copio le entità del contorno esterno e le offsetto opportunamente nCrvId = pGeomDB->GetFirstInGroup( nOlId) ; while ( nCrvId != GDB_ID_NULL) { // copio la curva nel gruppo temporaneo int nNewId = pGeomDB->CopyGlob( nCrvId, GDB_ID_NULL, nNewRegId) ; if ( nNewId == GDB_ID_NULL) return false ; // determino ed eseguo offset double dOffset = 0 ; if ( pGeomDB->GetInfo( nCrvId, NST_KEY_OFFSET, dOffset) && dOffset < - EPS_SMALL && ! pGeomDB->ExistsInfo( nCrvId, NST_KEY_SIDEANG2)) { ICurve* pCrv = GetCurve( pGeomDB->GetGeoObj( nNewId)) ; if ( pCrv == nullptr) return false ; pCrv->SimpleOffset( dOffset) ; } // passo alla successiva nCrvId = pGeomDB->GetNext( nCrvId) ; } // aggiusto tra loro le entità offsettate int nFirstCrvId = pGeomDB->GetFirstInGroup( nNewRegId) ; ICurve* pCrv1 = GetCurve( pGeomDB->GetGeoObj( nFirstCrvId)) ; int nNextCrvId = pGeomDB->GetNext( nFirstCrvId) ; ICurve* pCrv2 = GetCurve( pGeomDB->GetGeoObj( nNextCrvId)) ; while ( nNextCrvId != GDB_ID_NULL) { // sistemo le curve pCrv2 = GetCurve( pGeomDB->GetGeoObj( nNextCrvId)) ; if ( pCrv1 == nullptr || pCrv2 == nullptr || ! AdjustCurves( pCrv1, pCrv2)) return false ; // passo alla successiva pCrv1 = pCrv2 ; nNextCrvId = pGeomDB->GetNext( nNextCrvId) ; } // anche prima e ultima pCrv2 = GetCurve( pGeomDB->GetGeoObj( nFirstCrvId)) ; if ( pCrv1 == nullptr || pCrv2 == nullptr || ! AdjustCurves( pCrv1, pCrv2)) return false ; // creo la regione PtrOwner pCompo( CreateCurveComposite()) ; if ( IsNull( pCompo)) return false ; for ( int nCrvId = pGeomDB->GetFirstInGroup( nNewRegId) ; nCrvId != GDB_ID_NULL ; nCrvId = pGeomDB->GetFirstInGroup( nNewRegId)) { ICurve* pCrv = GetCurve( pGeomDB->RemoveGeoObjAndErase( nCrvId)) ; if ( pCrv != nullptr) pCompo->AddCurve( pCrv) ; else pGeomDB->Erase( nCrvId) ; } SurfFlatRegionByContours SfrCntr( false) ; SfrCntr.AddCurve( Release( pCompo)) ; PtrOwner pSfr2( SfrCntr.GetSurf()) ; // copio le entità del gruppo regione originale nel nuovo gruppo int nRegId = pGeomDB->GetFirstNameInGroup( nPartId, NST_PARTREG_LAYER) ; int nSrfOrig = GDB_ID_NULL ; int nId = pGeomDB->GetFirstInGroup( nRegId) ; while ( nId != GDB_ID_NULL) { int nNewId = pGeomDB->CopyGlob( nId, GDB_ID_NULL, nNewRegId) ; if ( nSrfOrig == GDB_ID_NULL && pGeomDB->GetGeoType( nNewId) == SRF_FLATRGN) nSrfOrig = nNewId ; nId = pGeomDB->GetNext( nId) ; } if ( nSrfOrig == GDB_ID_NULL) { pGeomDB->Erase( nNewRegId) ; return false ; } // interseco la vecchia regione con la nuova ISurfFlatRegion* pSfr1 = GetSurfFlatRegion( pGeomDB->GetGeoObj( nSrfOrig)) ; if ( ! pSfr1->Intersect( *pSfr2) || ! pSfr1->IsValid()) { pGeomDB->Erase( nNewRegId) ; return false ; } // sistemo i nomi e lo stato dei gruppi pGeomDB->SetName( nRegId, NST_PARTREG_ORIG_LAYER) ; pGeomDB->SetStatus( nRegId, GDB_ST_OFF) ; pGeomDB->SetName( nNewRegId, NST_PARTREG_LAYER) ; return true ; } //---------------------------------------------------------------------------- static bool AdjustLayerCurves( IGeomDB* pGeomDB, int nLayId) { // aggiusto tra loro le entità curve del layer int nFirstCrvId = pGeomDB->GetFirstInGroup( nLayId) ; ICurve* pCrv1 = GetCurve( pGeomDB->GetGeoObj( nFirstCrvId)) ; int nNextCrvId = pGeomDB->GetNext( nFirstCrvId) ; ICurve* pCrv2 = GetCurve( pGeomDB->GetGeoObj( nNextCrvId)) ; while ( nNextCrvId != GDB_ID_NULL) { // sistemo le curve pCrv2 = GetCurve( pGeomDB->GetGeoObj( nNextCrvId)) ; if ( pCrv1 == nullptr || pCrv2 == nullptr || ! AdjustCurves( pCrv1, pCrv2)) return false ; // passo alla successiva pCrv1 = pCrv2 ; nNextCrvId = pGeomDB->GetNext( nNextCrvId) ; } // anche prima e ultima pCrv2 = GetCurve( pGeomDB->GetGeoObj( nFirstCrvId)) ; if ( pCrv1 == nullptr || pCrv2 == nullptr || ! AdjustCurves( pCrv1, pCrv2)) return false ; return true ; } //---------------------------------------------------------------------------- bool ExeCalcFlatPartUpRegion( int nPartId, bool bCalc) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // aggiorno la regione standard if ( ! ExeUpdateFlatPartRegion( nPartId, bCalc)) return false ; // ripristino lo stato originale pGeomDB->Erase( pGeomDB->GetFirstNameInGroup( nPartId, NST_PARTUPREG_LAYER)) ; // se non richiesto calcolo, non devo fare altro if ( ! bCalc) return true ; // recupero il layer esterno int nOlId = pGeomDB->GetFirstNameInGroup( nPartId, NST_OUT_LAYER) ; if ( nOlId == GDB_ID_NULL) return false ; // se il pezzo non ha lati esterni con offset negativo non devo fare alcunchè bool bAllFixSides = true ; int nCrvId = pGeomDB->GetFirstInGroup( nOlId) ; while ( nCrvId != GDB_ID_NULL) { double dOffset, dOffset2 ; if ( ( pGeomDB->GetInfo( nCrvId, NST_KEY_OFFSET, dOffset) && dOffset < - EPS_SMALL) || ( pGeomDB->GetInfo( nCrvId, NST_KEY_OFFSET2, dOffset2) && dOffset2 < - EPS_SMALL)) { bAllFixSides = false ; break ; } nCrvId = pGeomDB->GetNext( nCrvId) ; } if ( bAllFixSides) return true ; // creo il layer per la regione sopra (con il medesimo riferimento del layer esterno) Frame3d frOl ; pGeomDB->GetGroupFrame( nOlId, frOl) ; int nUpRegId = pGeomDB->AddGroup( GDB_ID_NULL, nPartId, frOl) ; if ( nUpRegId == GDB_ID_NULL) return false ; pGeomDB->SetName( nUpRegId, NST_PARTUPREG_LAYER) ; // copio le entità del contorno esterno e le offsetto opportunamente nCrvId = pGeomDB->GetFirstInGroup( nOlId) ; while ( nCrvId != GDB_ID_NULL) { // copio la curva nel gruppo temporaneo int nNewId = pGeomDB->CopyGlob( nCrvId, GDB_ID_NULL, nUpRegId) ; if ( nNewId == GDB_ID_NULL) return false ; // determino ed eseguo offset double dOffset = 0, dOffset2 = 0 ; if ( ( pGeomDB->GetInfo( nCrvId, NST_KEY_OFFSET, dOffset) && dOffset < - EPS_SMALL) || ( pGeomDB->GetInfo( nCrvId, NST_KEY_OFFSET2, dOffset2) && dOffset2 < - EPS_SMALL)) { double dCalcOffset = min( dOffset, dOffset2) ; ICurve* pCrv = GetCurve( pGeomDB->GetGeoObj( nNewId)) ; if ( pCrv == nullptr) return false ; pCrv->SimpleOffset( dCalcOffset) ; } // passo alla successiva nCrvId = pGeomDB->GetNext( nCrvId) ; } // aggiusto tra loro le curve offsettate (allungandole e/o accorciandole) if ( ! AdjustLayerCurves( pGeomDB, nUpRegId)) return false ; // creo la regione PtrOwner pCompo( CreateCurveComposite()) ; if ( IsNull( pCompo)) return false ; for ( int nCrvId = pGeomDB->GetFirstInGroup( nUpRegId) ; nCrvId != GDB_ID_NULL ; nCrvId = pGeomDB->GetFirstInGroup( nUpRegId)) { ICurve* pCrv = GetCurve( pGeomDB->RemoveGeoObjAndErase( nCrvId)) ; if ( pCrv != nullptr) pCompo->AddCurve( pCrv) ; else pGeomDB->Erase( nCrvId) ; } SurfFlatRegionByContours SfrCntr( false) ; SfrCntr.AddCurve( Release( pCompo)) ; int nSfrId = pGeomDB->InsertGeoObj( GDB_ID_NULL, nUpRegId, GDB_FIRST_SON, SfrCntr.GetSurf()) ; if ( nSfrId == GDB_ID_NULL) return false ; // assegno il colore Color cCol = AQUA ; int nRegLay = pGeomDB->GetFirstNameInGroup( nPartId, NST_PARTREG_LAYER) ; if ( nRegLay != GDB_ID_NULL) pGeomDB->GetMaterial( nRegLay, cCol) ; cCol.SetAlpha( 0.25) ; pGeomDB->SetMaterial( nSfrId, cCol) ; return true ; } //---------------------------------------------------------------------------- static bool IgnoreOutlineFillet( IGeomDB* pGeomDB, int nCrvId, int nLayId) { // verifico se la curva nCrvId è un raccordo che deve essere ignorato, ovvero se si tratta di un arco non inclinato, in tangenza // e consecutivo ad almeno un lato inclinato // verifico se arco if ( pGeomDB->GetGeoType( nCrvId) == CRV_ARC) { // verifico se non inclinato double dSideAng = 0, dSideAng2 = 0 ; pGeomDB->GetInfo( nCrvId, NST_KEY_SIDEANG, dSideAng) ; pGeomDB->GetInfo( nCrvId, NST_KEY_SIDEANG2, dSideAng2) ; if ( abs( dSideAng) < EPS_ANG_SMALL && abs( dSideAng2) < EPS_ANG_SMALL) { // verifico se in tangenza con curve consecutive double dPrevAng = ANG_RIGHT, dNextAng = ANG_RIGHT ; pGeomDB->GetInfo( nCrvId, MCH_KEY_PREVANG, dPrevAng) ; pGeomDB->GetInfo( nCrvId, MCH_KEY_NEXTANG, dNextAng) ; if ( abs( dPrevAng) < EPS_ANG_SMALL && abs( dNextAng) < EPS_ANG_SMALL) { // verifico se è inclinata almeno una tra la curva precedente e quella successiva int nPrevId = pGeomDB->GetPrev( nCrvId) ; if ( nPrevId == GDB_ID_NULL) nPrevId = pGeomDB->GetLastInGroup( nLayId) ; if ( nPrevId == GDB_ID_NULL) return false ; double dSideAng, dSideAng2 ; if ( ( pGeomDB->GetInfo( nPrevId, NST_KEY_SIDEANG, dSideAng) && abs( dSideAng) > EPS_ANG_SMALL) || ( pGeomDB->GetInfo( nPrevId, NST_KEY_SIDEANG2, dSideAng2) && abs( dSideAng2) > EPS_ANG_SMALL)) return true ; int nNextId = pGeomDB->GetNext( nCrvId) ; if ( nNextId == GDB_ID_NULL) nNextId = pGeomDB->GetFirstInGroup( nLayId) ; if ( nNextId == GDB_ID_NULL) return false ; if ( ( pGeomDB->GetInfo( nNextId, NST_KEY_SIDEANG, dSideAng) && abs( dSideAng) > EPS_ANG_SMALL) || ( pGeomDB->GetInfo( nNextId, NST_KEY_SIDEANG2, dSideAng2) && abs( dSideAng2) > EPS_ANG_SMALL)) return true ; } } } return false ; } //---------------------------------------------------------------------------- static bool AdjustLayerForSideAngle( IGeomDB* pGeomDB, int nLayOrigId, const string& sLayOrig, int nLayReg, double dH) { // creo una copia del layer int nLayId = pGeomDB->Copy( nLayOrigId, GDB_ID_NULL, nLayOrigId, GDB_AFTER) ; if ( nLayId == GDB_ID_NULL) return false ; pGeomDB->SetName( nLayOrigId, sLayOrig) ; pGeomDB->SetInfo( nLayOrigId, NST_KEY_COPY, nLayId) ; pGeomDB->SetStatus( nLayOrigId, GDB_ST_OFF) ; // verifico se le curve del layer sono tutte chiuse, quindi sono cerchi non inclinabili int nCurves = 0 ; int nCircles = 0 ; for ( int nCrvId = pGeomDB->GetFirstInGroup( nLayId) ; nCrvId != GDB_ID_NULL ; nCrvId = pGeomDB->GetNext( nCrvId)) { const ICurve* pCrv = GetCurve( pGeomDB->GetGeoObj( nCrvId)) ; if ( pCrv == nullptr) return false ; ++ nCurves ; if ( pCrv->IsClosed()) ++ nCircles ; } if ( nCircles != 0 && nCircles != nCurves) return false ; bool bCircles = ( nCircles == nCurves) ; // se sono cerchi if ( bCircles) { // li copio nel layer della regione for ( int nCrvId = pGeomDB->GetFirstInGroup( nLayId) ; nCrvId != GDB_ID_NULL ; nCrvId = pGeomDB->GetNext( nCrvId)) { if ( pGeomDB->Copy( nCrvId, GDB_ID_NULL, nLayReg) == GDB_ID_NULL) return false ; } return true ; } // recupero il riferimento del layer Frame3d frLay ; pGeomDB->GetGroupFrame( nLayId, frLay) ; // creo un primo layer temporaneo (sotto) const string sTmpLayName = "TmpLay" ; int nTmpLayId = pGeomDB->AddGroup( GDB_ID_NULL, pGeomDB->GetParentId( nLayId), frLay) ; if ( nTmpLayId == GDB_ID_NULL) return false ; pGeomDB->SetName( nTmpLayId, sTmpLayName) ; pGeomDB->SetLevel( nTmpLayId, GDB_LV_TEMP) ; // copio le entità del contorno e le offsetto opportunamente for ( int nCrvId = pGeomDB->GetFirstInGroup( nLayId) ; nCrvId != GDB_ID_NULL ; nCrvId = pGeomDB->GetNext( nCrvId)) { // copio la curva nel gruppo temporaneo int nNewId = pGeomDB->CopyGlob( nCrvId, GDB_ID_NULL, nTmpLayId) ; if ( nNewId == GDB_ID_NULL) return false ; // determino ed eseguo offset double dSideAng, dSideAng2 ; if ( pGeomDB->GetInfo( nCrvId, NST_KEY_SIDEANG, dSideAng) && abs( dSideAng) > EPS_ANG_SMALL) { double dOffset = 0 ; pGeomDB->GetInfo( nCrvId, NST_KEY_OFFSET, dOffset) ; double dCalcOffset = dH * tan( dSideAng * DEGTORAD) + dOffset ; ICurve* pCrv = GetCurve( pGeomDB->GetGeoObj( nNewId)) ; if ( pCrv == nullptr) return false ; if ( ! pCrv->SimpleOffset( dCalcOffset)) pGeomDB->Erase( nNewId) ; } else if ( pGeomDB->GetInfo( nCrvId, NST_KEY_SIDEANG2, dSideAng2) && abs( dSideAng2) > EPS_ANG_SMALL) { double dOffset2 = 0 ; pGeomDB->GetInfo( nCrvId, NST_KEY_OFFSET2, dOffset2) ; double dDepth2 = 0 ; pGeomDB->GetInfo( nCrvId, NST_KEY_DEPTH2, dDepth2) ; double dAgg2 = 0 ; pGeomDB->GetInfo( nCrvId, NST_KEY_AGG2, dAgg2) ; double dCalcOffset = ( dDepth2 - dAgg2) * tan( dSideAng2 * DEGTORAD) + dOffset2 ; ICurve* pCrv = GetCurve( pGeomDB->GetGeoObj( nNewId)) ; if ( pCrv == nullptr) return false ; if ( ! pCrv->SimpleOffset( dCalcOffset)) pGeomDB->Erase( nNewId) ; } // verifico se raccordo da ignorare per poter calcolare la regione else if ( IgnoreOutlineFillet( pGeomDB, nCrvId, nLayId)) pGeomDB->Erase( nNewId) ; } // aggiusto tra loro le curve offsettate (allungandole e/o accorciandole) if ( ! AdjustLayerCurves( pGeomDB, nTmpLayId)) return false ; // creo un secondo layer temporaneo (sopra) const string sTmpLay2Name = "TmpLay2" ; int nTmpLay2Id = pGeomDB->AddGroup( GDB_ID_NULL, pGeomDB->GetParentId( nLayId), frLay) ; if ( nTmpLay2Id == GDB_ID_NULL) return false ; pGeomDB->SetName( nTmpLay2Id, sTmpLay2Name) ; pGeomDB->SetLevel( nTmpLay2Id, GDB_LV_TEMP) ; // copio le entità del contorno e le offsetto opportunamente for ( int nCrvId = pGeomDB->GetFirstInGroup( nLayId) ; nCrvId != GDB_ID_NULL ; nCrvId = pGeomDB->GetNext( nCrvId)) { // copio la curva nel gruppo temporaneo int nNewId = pGeomDB->CopyGlob( nCrvId, GDB_ID_NULL, nTmpLay2Id) ; if ( nNewId == GDB_ID_NULL) return false ; // determino ed eseguo offset double dSideAng, dSideAng2 ; if ( pGeomDB->GetInfo( nCrvId, NST_KEY_SIDEANG, dSideAng) && abs( dSideAng) > EPS_ANG_SMALL) { double dOffset = 0 ; pGeomDB->GetInfo( nCrvId, NST_KEY_OFFSET, dOffset) ; double dCalcOffset = dOffset ; ICurve* pCrv = GetCurve( pGeomDB->GetGeoObj( nNewId)) ; if ( pCrv == nullptr) return false ; if ( ! pCrv->SimpleOffset( dCalcOffset)) pGeomDB->Erase( nNewId) ; } else if ( pGeomDB->GetInfo( nCrvId, NST_KEY_SIDEANG2, dSideAng2) && abs( dSideAng2) > EPS_ANG_SMALL) { double dOffset2 = 0 ; pGeomDB->GetInfo( nCrvId, NST_KEY_OFFSET2, dOffset2) ; double dCalcOffset = dOffset2 ; ICurve* pCrv = GetCurve( pGeomDB->GetGeoObj( nNewId)) ; if ( pCrv == nullptr) return false ; if ( ! pCrv->SimpleOffset( dCalcOffset)) pGeomDB->Erase( nNewId) ; } // verifico se raccordo da ignorare per poter calcolare la regione else if ( IgnoreOutlineFillet( pGeomDB, nCrvId, nLayId)) pGeomDB->Erase( nNewId) ; } // aggiusto tra loro le curve offsettate (allungandole e/o accorciandole) if ( ! AdjustLayerCurves( pGeomDB, nTmpLay2Id)) return false ; // eventuali allungamenti/accorciamenti per le curve del loop for ( int nCrvId = pGeomDB->GetFirstInGroup( nLayId) ; nCrvId != GDB_ID_NULL ; nCrvId = pGeomDB->GetNext( nCrvId)) { // recupero il nome string sName ; if ( ! pGeomDB->GetName( nCrvId, sName)) continue ; // recupero curve con lo stesso nome nei gruppi delli regioni sotto e sopra int nCrvDrId = pGeomDB->GetFirstNameInGroup( nTmpLayId, sName) ; int nCrvUrId = pGeomDB->GetFirstNameInGroup( nTmpLay2Id, sName) ; // verifico siano curve ICurve* pCrv = GetCurve( pGeomDB->GetGeoObj( nCrvId)) ; ICurve* pCrvDr = GetCurve( pGeomDB->GetGeoObj( nCrvDrId)) ; ICurve* pCrvUr = GetCurve( pGeomDB->GetGeoObj( nCrvUrId)) ; if ( pCrv == nullptr || pCrvDr == nullptr || pCrvUr == nullptr) continue ; // verifico se devo allungare o accorciare la curva all'inizio double dPrevAng = 0 ; pGeomDB->GetInfo( nCrvId, MCH_KEY_PREVANG, dPrevAng) ; Point3d ptStart ; pCrv->GetStartPoint( ptStart) ; Vector3d vtStartDir ; pCrv->GetStartDir( vtStartDir) ; Point3d ptStartDr ; pCrvDr->GetStartPoint( ptStartDr) ; Point3d ptStartUr ; pCrvUr->GetStartPoint( ptStartUr) ; double dStartProD = - ( ( ptStartDr - ptStart) * vtStartDir) ; double dStartProU = - ( ( ptStartUr - ptStart) * vtStartDir) ; if ( dPrevAng > - EPS_ANG_SMALL) { //if ( dStartProD > EPS_SMALL) // pCrv->ExtendStartByLen( dStartProD) ; double dStartProMin = min( dStartProD, dStartProU) ; if ( dStartProMin < - EPS_SMALL) { pCrv->TrimStartAtLen( - dStartProMin) ; if ( abs( dStartProD - dStartProU) > EPS_SMALL) pGeomDB->SetInfo( nCrvId, MCH_KEY_START_WHISKEXT, abs( dStartProD - dStartProU)) ; } else pGeomDB->SetInfo( nCrvId, MCH_KEY_START_WHISKEXT, max( dStartProD, dStartProU)) ; } else { if ( dStartProD < - EPS_SMALL) pCrv->TrimStartAtLen( - dStartProD) ; } // verifico se devo allungare la curva alla fine double dNextAng = 0 ; pGeomDB->GetInfo( nCrvId, MCH_KEY_NEXTANG, dNextAng) ; Point3d ptEnd ; pCrv->GetEndPoint( ptEnd) ; Vector3d vtEndDir ; pCrv->GetEndDir( vtEndDir) ; Point3d ptEndDr ; pCrvDr->GetEndPoint( ptEndDr) ; Point3d ptEndUr ; pCrvUr->GetEndPoint( ptEndUr) ; double dEndProD = ( ptEndDr - ptEnd) * vtEndDir ; double dEndProU = ( ptEndUr - ptEnd) * vtEndDir ; if ( dNextAng > - EPS_ANG_SMALL) { //if ( dEndProD > EPS_SMALL) // pCrv->ExtendEndByLen( dEndProD) ; double dEndProMin = min( dEndProD, dEndProU) ; if ( dEndProMin < - EPS_SMALL) { double dLen ; pCrv->GetLength( dLen) ; pCrv->TrimEndAtLen( dLen + dEndProMin) ; if ( abs( dEndProD - dEndProU) > EPS_SMALL) pGeomDB->SetInfo( nCrvId, MCH_KEY_END_WHISKEXT, abs( dEndProD - dEndProU)) ; } else pGeomDB->SetInfo( nCrvId, MCH_KEY_END_WHISKEXT, max( dEndProD, dEndProU)) ; } else { if ( dEndProD < - EPS_SMALL) { double dLen ; pCrv->GetLength( dLen) ; pCrv->TrimEndAtLen( dLen + dEndProD) ; } } } // concateno le curve del primo layer temporaneo PtrOwner pCompo( CreateCurveComposite()) ; if ( IsNull( pCompo)) return false ; for ( int nCrvId = pGeomDB->GetFirstInGroup( nTmpLayId) ; nCrvId != GDB_ID_NULL ; nCrvId = pGeomDB->GetFirstInGroup( nTmpLayId)) { ICurve* pCrv = GetCurve( pGeomDB->RemoveGeoObjAndErase( nCrvId)) ; if ( pCrv != nullptr) pCompo->AddCurve( pCrv) ; else pGeomDB->Erase( nCrvId) ; } // cancello i layer temporanei pGeomDB->Erase( nTmpLayId) ; pGeomDB->Erase( nTmpLay2Id) ; // inserisco la curva concatenata nel layer della regione if ( pGeomDB->AddGeoObj( GDB_ID_NULL, nLayReg, Release( pCompo)) == GDB_ID_NULL) return false ; return true ; } //---------------------------------------------------------------------------- bool ExeCalcFlatPartDownRegion( int nPartId, double dH) { IGeomDB* pGeomDB = GetCurrGeomDB() ; VERIFY_GEOMDB( pGeomDB, false) // ripristino lo stato originale pGeomDB->Erase( pGeomDB->GetFirstNameInGroup( nPartId, NST_PARTDOWNREG_LAYER)) ; int nOlOrigId = pGeomDB->GetFirstNameInGroup( nPartId, NST_OUT_ORIG_LAYER) ; if ( nOlOrigId != GDB_ID_NULL) { pGeomDB->Erase( pGeomDB->GetFirstNameInGroup( nPartId, NST_OUT_LAYER)) ; pGeomDB->SetName( nOlOrigId, NST_OUT_LAYER) ; pGeomDB->SetStatus( nOlOrigId, GDB_ST_ON) ; } for ( int nIlOrigId = pGeomDB->GetFirstNameInGroup( nPartId, NST_IN_ORIG_LAYER) ; nIlOrigId != GDB_ID_NULL ; nIlOrigId = pGeomDB->GetFirstNameInGroup( nPartId, NST_IN_ORIG_LAYER)) { int nCopyId = GDB_ID_NULL ; pGeomDB->GetInfo( nIlOrigId, NST_KEY_COPY, nCopyId) ; if ( nCopyId != GDB_ID_NULL) pGeomDB->Erase( nCopyId) ; pGeomDB->SetName( nIlOrigId, NST_IN_LAYER) ; pGeomDB->SetStatus( nIlOrigId, GDB_ST_ON) ; } // se spessore nullo, non devo fare altro if ( dH < EPS_SMALL) return true ; // recupero i layer esterno ed interni (primo sempre esterno) INTVECTOR vLayId ; int nOlId = pGeomDB->GetFirstNameInGroup( nPartId, NST_OUT_LAYER) ; if ( nOlId == GDB_ID_NULL) return false ; vLayId.push_back( nOlId) ; for ( int nIlId = pGeomDB->GetFirstNameInGroup( nPartId, NST_IN_LAYER) ; nIlId != GDB_ID_NULL ; nIlId = pGeomDB->GetNextName( nIlId, NST_IN_LAYER)) vLayId.push_back( nIlId) ; // se il pezzo non ha lati esterni o interni inclinati all'infuori non devo fare alcunchè bool bAllVertSides = true ; for ( size_t i = 0 ; i < vLayId.size() ; ++ i) { int nCrvId = pGeomDB->GetFirstInGroup( vLayId[i]) ; while ( nCrvId != GDB_ID_NULL) { double dSideAng, dSideAng2 ; if ( ( pGeomDB->GetInfo( nCrvId, NST_KEY_SIDEANG, dSideAng) && abs( dSideAng) > EPS_ANG_SMALL) || ( pGeomDB->GetInfo( nCrvId, NST_KEY_SIDEANG2, dSideAng2) && abs( dSideAng2) > EPS_ANG_SMALL)) { bAllVertSides = false ; break ; } nCrvId = pGeomDB->GetNext( nCrvId) ; } } if ( bAllVertSides) return true ; // assegno un nome alle curve dei layer che ne sono prive for ( size_t i = 0 ; i < vLayId.size() ; ++ i) { int nCnt = 0 ; for ( int nCrvId = pGeomDB->GetFirstInGroup( vLayId[i]) ; nCrvId != GDB_ID_NULL ; nCrvId = pGeomDB->GetNext( nCrvId)) { if ( ! pGeomDB->ExistsName( nCrvId) && ( pGeomDB->GetGeoType( nCrvId) & GEO_CURVE) != 0) { ++ nCnt ; pGeomDB->SetName( nCrvId, "B" + ToString( nCnt)) ; } } } // creo il layer per la regione sotto (con il medesimo riferimento del layer esterno) Frame3d frOl ; pGeomDB->GetGroupFrame( nOlId, frOl) ; int nDwnRegId = pGeomDB->AddGroup( GDB_ID_NULL, nPartId, frOl) ; if ( nDwnRegId == GDB_ID_NULL) return false ; pGeomDB->SetName( nDwnRegId, NST_PARTDOWNREG_LAYER) ; // modifico i layer e creo i contorni per la nuova regione for ( size_t i = 0 ; i < vLayId.size() ; ++ i) { string sLayOrig = ( i == 0 ? NST_OUT_ORIG_LAYER : NST_IN_ORIG_LAYER) ; if ( ! AdjustLayerForSideAngle( pGeomDB, vLayId[i], sLayOrig, nDwnRegId, dH)) return false ; } // creo la regione SurfFlatRegionByContours SfrCntr( false) ; for ( int nCrvId = pGeomDB->GetFirstInGroup( nDwnRegId) ; nCrvId != GDB_ID_NULL ; nCrvId = pGeomDB->GetFirstInGroup( nDwnRegId)) { ICurve* pCrv = GetCurve( pGeomDB->RemoveGeoObjAndErase( nCrvId)) ; if ( pCrv != nullptr) SfrCntr.AddCurve( pCrv) ; else pGeomDB->Erase( nCrvId) ; } int nSfrId = pGeomDB->AddGeoObj( GDB_ID_NULL, nDwnRegId, SfrCntr.GetSurf()) ; if ( nSfrId == GDB_ID_NULL) return false ; // assegno il colore Color cCol = AQUA ; int nRegLay = pGeomDB->GetFirstNameInGroup( nPartId, NST_PARTREG_LAYER) ; if ( nRegLay != GDB_ID_NULL) pGeomDB->GetMaterial( nRegLay, cCol) ; cCol.SetAlpha( 0.25) ; pGeomDB->SetMaterial( nSfrId, cCol) ; return true ; } //---------------------------------------------------------------------------- int GetFlatPartRegion( IGeomDB* pGeomDB, int nId) { if ( pGeomDB == nullptr) return GDB_ID_NULL ; // recupero regione totale del pezzo (è la prima del sottogruppo di nome Region) int nRegGrp = pGeomDB->GetFirstNameInGroup( nId, NST_PARTREG_LAYER) ; int nRegId = pGeomDB->GetFirstInGroup( nRegGrp) ; while ( nRegId != GDB_ID_NULL) { if ( pGeomDB->GetGeoType( nRegId) == SRF_FLATRGN) break ; nRegId = pGeomDB->GetNext( nRegId) ; } return nRegId ; } //---------------------------------------------------------------------------- int GetFlatPartUpRegion( IGeomDB* pGeomDB, int nId) { if ( pGeomDB == nullptr) return GDB_ID_NULL ; // recupero regione sopra del pezzo (è la prima del sottogruppo di nome UpReg) int nRegGrp = pGeomDB->GetFirstNameInGroup( nId, NST_PARTUPREG_LAYER) ; int nRegId = pGeomDB->GetFirstInGroup( nRegGrp) ; while ( nRegId != GDB_ID_NULL) { if ( pGeomDB->GetGeoType( nRegId) == SRF_FLATRGN) break ; nRegId = pGeomDB->GetNext( nRegId) ; } return nRegId ; } //---------------------------------------------------------------------------- int GetFlatPartDownRegion( IGeomDB* pGeomDB, int nId) { if ( pGeomDB == nullptr) return GDB_ID_NULL ; // recupero regione sotto del pezzo (è la prima del sottogruppo di nome DwnReg) int nRegGrp = pGeomDB->GetFirstNameInGroup( nId, NST_PARTDOWNREG_LAYER) ; int nRegId = pGeomDB->GetFirstInGroup( nRegGrp) ; while ( nRegId != GDB_ID_NULL) { if ( pGeomDB->GetGeoType( nRegId) == SRF_FLATRGN) break ; nRegId = pGeomDB->GetNext( nRegId) ; } return nRegId ; } //---------------------------------------------------------------------------- bool GetFlatPartCutRegions( IGeomDB* pGeomDB, int nId, bool bReduced, INTVECTOR& vCrId) { if ( pGeomDB == nullptr) return false ; // recupero gruppo preview lavorazioni del pezzo int nPVGrp = pGeomDB->GetFirstNameInGroup( nId, MCH_PV) ; if ( nPVGrp == GDB_ID_NULL) return true ; // ciclo sulle lavorazioni int nMchId = pGeomDB->GetFirstGroupInGroup( nPVGrp) ; while ( nMchId != GDB_ID_NULL) { int nClId = pGeomDB->GetFirstGroupInGroup( nMchId) ; while ( nClId != GDB_ID_NULL) { int nCrId = pGeomDB->GetFirstNameInGroup( nClId, ( bReduced ? MCH_PV_RRCUT : MCH_PV_RCUT)) ; while ( nCrId != GDB_ID_NULL) { vCrId.emplace_back( nCrId) ; nCrId = pGeomDB->GetNextName( nCrId, ( bReduced ? MCH_PV_RRCUT : MCH_PV_RCUT)) ; } nClId = pGeomDB->GetNextGroup( nClId) ; } nMchId = pGeomDB->GetNextGroup( nMchId) ; } return true ; } //---------------------------------------------------------------------------- bool GetFlatPartDownCutRegions( IGeomDB* pGeomDB, int nId, bool bReduced, INTVECTOR& vDwnCrId) { if ( pGeomDB == nullptr) return false ; // recupero gruppo preview lavorazioni del pezzo int nPVGrp = pGeomDB->GetFirstNameInGroup( nId, MCH_PV) ; if ( nPVGrp == GDB_ID_NULL) return true ; // ciclo sulle lavorazioni int nMchId = pGeomDB->GetFirstGroupInGroup( nPVGrp) ; while ( nMchId != GDB_ID_NULL) { int nClId = pGeomDB->GetFirstGroupInGroup( nMchId) ; while ( nClId != GDB_ID_NULL) { // ciclo sui sopra e salvo gli eventuali sotto (per tenerli sincronizzati) int nCrId = pGeomDB->GetFirstNameInGroup( nClId, ( bReduced ? MCH_PV_RRCUT : MCH_PV_RCUT)) ; int nDwnCrId = pGeomDB->GetFirstNameInGroup( nClId, ( bReduced ? MCH_PV_DOWN_RRCUT : MCH_PV_DOWN_RCUT)) ; while ( nCrId != GDB_ID_NULL) { vDwnCrId.emplace_back( nDwnCrId) ; nCrId = pGeomDB->GetNextName( nCrId, ( bReduced ? MCH_PV_RRCUT : MCH_PV_RCUT)) ; nDwnCrId = pGeomDB->GetNextName( nDwnCrId, ( bReduced ? MCH_PV_DOWN_RRCUT : MCH_PV_DOWN_RCUT)) ; } nClId = pGeomDB->GetNextGroup( nClId) ; } nMchId = pGeomDB->GetNextGroup( nMchId) ; } return true ; } //---------------------------------------------------------------------------- bool GetFlatPartInterpartGap(IGeomDB* pGeomDB, int nId, double& dGap) { if ( pGeomDB == nullptr) return false ; // valore di default dGap = 0 ; // recupero gruppo preview lavorazioni del pezzo int nPVGrp = pGeomDB->GetFirstNameInGroup( nId, MCH_PV) ; if ( nPVGrp == GDB_ID_NULL) return true ; // ciclo sulle lavorazioni int nMchId = pGeomDB->GetFirstGroupInGroup( nPVGrp) ; while ( nMchId != GDB_ID_NULL) { int nClId = pGeomDB->GetFirstGroupInGroup( nMchId) ; while ( nClId != GDB_ID_NULL) { double dCurrGap ; if ( pGeomDB->GetInfo(nClId, MCH_PV_KEY_WT, dCurrGap) && dCurrGap > dGap) dGap = dCurrGap ; nClId = pGeomDB->GetNextGroup( nClId) ; } nMchId = pGeomDB->GetNextGroup( nMchId) ; } return true ; } //---------------------------------------------------------------------------- int GetFlatPartFromRegion( IGeomDB* pGeomDB, int nId) { if ( pGeomDB == nullptr) return GDB_ID_NULL ; // verifico che il layer di appartenenza sia una regione int nLayerId = pGeomDB->GetParentId( nId) ; string sName ; if ( ! pGeomDB->GetName( nLayerId, sName) && ! EqualNoCase( sName, NST_PARTREG_LAYER) && ! EqualNoCase( sName, NST_PARTUPREG_LAYER) && ! EqualNoCase( sName, NST_PARTDOWNREG_LAYER)) return GDB_ID_NULL ; // restituisco il padre del layer return ( pGeomDB->GetParentId( nLayerId)) ; } //---------------------------------------------------------------------------- int GetFlatPartFromCut( IGeomDB* pGeomDB, int nId) { if ( pGeomDB == nullptr) return GDB_ID_NULL ; // verifico appartenga al gruppo PreView (padre di padre di padre) int nPvId = pGeomDB->GetParentId( pGeomDB->GetParentId( pGeomDB->GetParentId( nId))) ; string sName ; if ( ! pGeomDB->GetName( nPvId, sName) && ! EqualNoCase( sName, MCH_PV)) return GDB_ID_NULL ; // restituisco il padre del layer return ( pGeomDB->GetParentId( nPvId)) ; } //---------------------------------------------------------------------------- INTVECTOR GetGeometryFromCut( IGeomDB* pGeomDB, IMachMgr* pMachMgr, int nId) { INTVECTOR vnIds ; if ( pGeomDB == nullptr || pMachMgr == nullptr) return vnIds ; // verifico appartenga ad una lavorazione int nMchId ; if ( ! pGeomDB->GetInfo( pGeomDB->GetParentId( pGeomDB->GetParentId( nId)), "MId", nMchId)) return vnIds ; // recupero la geometria di applicazione della lavorazione (deve essere una sola) if ( ! pMachMgr->SetCurrMachining( nMchId)) return vnIds ; SELVECTOR vSelIds ; pMachMgr->GetMachiningGeometry( vSelIds) ; vnIds.reserve( vSelIds.size()) ; for ( const SelData& mySelData : vSelIds) vnIds.emplace_back( mySelData.nId) ; return vnIds ; } //---------------------------------------------------------------------------- bool GetFlatPartApproxContour( IGeomDB* pGeomDB, int nId, PolyLine& PL) { if ( pGeomDB == nullptr) return false ; // Recupero la superficie regione piana int nRegId = GetFlatPartRegion( pGeomDB, nId) ; const ISurfFlatRegion* pSfr = GetSurfFlatRegion( pGeomDB->GetGeoObj( nRegId)) ; if ( pSfr == nullptr) return false ; // ne recupero il riferimento globale Frame3d frSurf ; pGeomDB->GetGlobFrame( nRegId, frSurf) ; // ne approssimo il contorno con una polilinea che porto in globale if ( ! pSfr->ApproxLoopWithLines( 0, 0, LIN_TOL_STD, ANG_TOL_STD_DEG, ICurve::APL_STD, PL)) return false ; PL.ToGlob( frSurf) ; return true ; }