//---------------------------------------------------------------------------- // EgalTech 2015-2015 //---------------------------------------------------------------------------- // File : BtlGeomOutline.cpp Data : 06.11.15 Versione : 1.6k2 // Contenuto : Implementazione delle funzioni su outline per BtlGeom. // // // // Modifiche : 06.11.15 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "BtlGeom.h" #include "DllMain.h" #include "/EgtDev/Include/EGkCurveLine.h" #include "/EgtDev/Include/EGkCurveArc.h" #include "/EgtDev/Include/EGkCurveComposite.h" #include "/EgtDev/Include/EgkChainCurves.h" #include "/EgtDev/Include/EGkSfrCreate.h" #include "/EgtDev/Include/EGkStmStandard.h" #include "/EgtDev/Include/EGkStmFromCurves.h" #include "/EgtDev/Include/EGkExtText.h" #include "/EgtDev/Include/EGnStringUtils.h" #include "/EgtDev/Include/EgtPointerOwner.h" using namespace std ; //---------------------------------------------------------------------------- bool BtlGeom::AddPartOutline( int nSide, const FCEDEQUE& dqFce) { // verifico esistenza pezzo if ( m_nBoxId == GDB_ID_NULL) return false ; // verifico validità faccia if ( ! IsTrueSide( nSide)) return false ; // verifico siano definiti almeno 3 punti (2 archi) if ( dqFce.size() < 3) return false ; // verifico che primo e ultimo punto coincidano if ( ! AreSamePointApprox( dqFce.front().ptP, dqFce.back().ptP)) return false ; // verifico che sia un percorso semplice if ( dqFce.front().nType != FreeContourEnt::START) return false ; // verifico non ci sia angolo di sbandamento for ( auto& Fce : dqFce) { if ( abs( Fce.dAng) > EPS_ANG_SMALL) return false ; } // costruisco il percorso di contorno PtrOwner pCrvCompo( CurveFromFces( dqFce)) ; if ( IsNull( pCrvCompo)) return false ; // aggiusto orientamento affinché sia antiorario double dArea ; pCrvCompo->GetAreaXY( dArea) ; if ( dArea < 0) pCrvCompo->Invert() ; // Porto il percorso sul piano corretto Frame3d frRef = GetSideFrame( nSide) ; pCrvCompo->ToGlob( frRef) ; // Estrudo il contorno Vector3d vtExtr = - frRef.VersZ() * GetSideHeight( nSide) ; PtrOwner pStm( GetSurfTriMeshByExtrusion( pCrvCompo, vtExtr, false, EPS_SMALL)) ; if ( IsNull( pStm)) return false ; pStm->Invert() ; // Inserisco la superficie nel layer Outline int nId = m_pGDB->AddGeoObj( GDB_ID_NULL, m_nOutsId, Release( pStm)) ; if ( nId == GDB_ID_NULL) return false ; m_pGDB->SetName( nId, GetOutlineOutName( nSide)) ; // Creo le regioni sopra e sotto PtrOwner pSfr1( CreateSurfFlatRegion()) ; if ( IsNull( pSfr1) || ! pSfr1->AddExtLoop( Release( pCrvCompo))) return false ; PtrOwner pSfr2( pSfr1->Clone()) ; if ( IsNull( pSfr2)) return false ; pSfr2->Invert() ; pSfr2->Translate( vtExtr) ; // Inserisco le regioni nel layer Outline int nId1 = m_pGDB->AddGeoObj( GDB_ID_NULL, m_nOutsId, Release( pSfr1)) ; if ( nId1 == GDB_ID_NULL) return false ; m_pGDB->SetName( nId1, GetOutlineTopName( nSide)) ; m_pGDB->SetInfo( nId1, IKEY_OTL_SIDE, nSide) ; int nId2 = m_pGDB->AddGeoObj( GDB_ID_NULL, m_nOutsId, Release( pSfr2)) ; if ( nId2 == GDB_ID_NULL) return false ; m_pGDB->SetName( nId2, GetOutlineBottomName( nSide)) ; m_pGDB->SetInfo( nId2, IKEY_OTL_SIDE, GetOppositeSide( nSide)) ; // nascondo il box //m_pGDB->SetStatus( m_nBoxId, GDB_ST_OFF) ; return true ; } //---------------------------------------------------------------------------- bool BtlGeom::AddPartAperture( int nSide, const FCEDEQUE& dqFce) { // verifico esistenza pezzo if ( m_nBoxId == GDB_ID_NULL) return false ; // verifico validità faccia if ( ! IsTrueSide( nSide)) return false ; // verifico siano definiti almeno 4 punti (triangolo) if ( dqFce.size() < 4) return false ; // verifico che primo e ultimo punto coincidano if ( ! AreSamePointApprox( dqFce.front().ptP, dqFce.back().ptP)) return false ; // verifico che sia un percorso semplice if ( dqFce.front().nType != FreeContourEnt::START) return false ; // verifico non ci sia angolo di sbandamento for ( auto& Fce : dqFce) { if ( abs( Fce.dAng) > EPS_ANG_SMALL) return false ; } // costruisco il percorso di contorno PtrOwner pCrvCompo( CurveFromFces( dqFce)) ; if ( IsNull( pCrvCompo)) return false ; // aggiusto orientamento affinché sia antiorario double dArea ; pCrvCompo->GetAreaXY( dArea) ; if ( dArea < 0) pCrvCompo->Invert() ; // Porto il percorso sul piano corretto Frame3d frRef = GetSideFrame( nSide) ; pCrvCompo->ToGlob( frRef) ; // Estrudo il contorno Vector3d vtExtr = - frRef.VersZ() * GetSideHeight( nSide) ; PtrOwner pStm( GetSurfTriMeshByExtrusion( pCrvCompo, vtExtr, false, EPS_SMALL)) ; if ( IsNull( pStm)) return false ; // Inserisco la superficie nel layer Outline int nId = m_pGDB->AddGeoObj( GDB_ID_NULL, m_nOutsId, Release( pStm)) ; if ( nId == GDB_ID_NULL) return false ; m_pGDB->SetName( nId, GetOutlineApertureName( nSide)) ; // Creo le regioni sopra e sotto PtrOwner pSfr1( CreateSurfFlatRegion()) ; if ( IsNull( pSfr1) || ! pSfr1->AddExtLoop( Release( pCrvCompo))) return false ; PtrOwner pSfr2( pSfr1->Clone()) ; if ( IsNull( pSfr2)) return false ; pSfr2->Invert() ; pSfr2->Translate( vtExtr) ; // Sottraggo le regioni da quelle già presenti nell'outline ISurfFlatRegion* pSfrTop = GetSurfFlatRegion( m_pGDB->GetGeoObj( m_pGDB->GetFirstNameInGroup( m_nOutsId, GetOutlineTopName( nSide)))) ; if ( pSfrTop == nullptr) return false ; pSfrTop->Subtract( *pSfr1) ; ISurfFlatRegion* pSfrBot = GetSurfFlatRegion( m_pGDB->GetGeoObj( m_pGDB->GetFirstNameInGroup( m_nOutsId, GetOutlineBottomName( nSide)))) ; if ( pSfrBot == nullptr) return false ; pSfrBot->Subtract( *pSfr2) ; return true ; } //---------------------------------------------------------------------------- bool BtlGeom::AddPartStdOutline( void) { // verifico esistenza pezzo if ( m_nBoxId == GDB_ID_NULL) return false ; // aggiungo le regioni delle faccie for ( int nSide = BTL_SIDE_FRONT ; nSide <= BTL_SIDE_LEFT ; ++ nSide) { PtrOwner pSfr( GetSurfFlatRegionRectangle( GetSideLength( nSide),GetSideWidth( nSide))) ; if ( IsNull( pSfr)) return false ; pSfr->ToGlob( GetSideFrame( nSide)) ; // Inserisco la regione nel layer Outline int nId = m_pGDB->AddGeoObj( GDB_ID_NULL, m_nOutsId, Release( pSfr)) ; if ( nId == GDB_ID_NULL) return false ; m_pGDB->SetName( nId, GetOutlineTopName( nSide)) ; m_pGDB->SetInfo( nId, IKEY_OTL_SIDE, nSide) ; } // nascondo il box //m_pGDB->SetStatus( m_nBoxId, GDB_ST_OFF) ; return true ; } //---------------------------------------------------------------------------- bool BtlGeom::UseProcessToTrimOutline( int nProcId) { // se non trim speciale per pareti... if ( ! m_bSpecialTrim) return true ; // recupero il box della superficie BBox3d b3Proc ; Point3d ptMin, ptMax ; if ( ! m_pGDB->GetLocalBBox( nProcId, b3Proc) || ! b3Proc.GetMinMax( ptMin, ptMax)) return true ; // verifico rispetto allo spessore perpendicolare alla faccia maggiore if ( m_vtDim.y > m_vtDim.z) return ( ( ptMax.z - ptMin.z) > m_vtDim.z - 100 * EPS_SMALL) ; else return ( ( ptMax.y - ptMin.y) > m_vtDim.y - 100 * EPS_SMALL) ; } //---------------------------------------------------------------------------- bool BtlGeom::TrimOutline( int nProcSurfId) { // Recupero la superficie del processo di lavorazione ISurfTriMesh* pStm = GetSurfTriMesh( m_pGDB->GetGeoObj( nProcSurfId)) ; if ( pStm == nullptr) return false ; // eseguo trim return TrimOutline( pStm) ; } //---------------------------------------------------------------------------- bool BtlGeom::TrimOutline( ISurfTriMesh* pStm) { // Ne recupero le curve di contorno POLYLINEVECTOR vPL ; if ( ! pStm->GetLoops( vPL)) return false ; // elimino i loop troppo piccoli for ( int i = 0 ; i < int( vPL.size()) ; ++ i) { BBox3d b3PL ; double dDiam ; if ( ! vPL[i].GetLocalBBox( b3PL) || ! b3PL.GetDiameter( dDiam) || dDiam < 500 * EPS_SMALL) { vPL.erase( vPL.begin() + i) ; -- i ; } } // unisco tratti allineati for ( int i = 0 ; i < int( vPL.size()) ; ++ i) vPL[i].RemoveAlignedPoints( EPS_SMALL) ; // Divido le curve sulle varie facce del box del pezzo bool bOk = true ; bool bSomeInFace = false ; ICURVEPOVECTOR vCrvP[SIDE_NBR] ; for ( auto& PL : vPL) { // ciclo sulle linee della polilinea Point3d ptP1, ptP2 ; for ( bool bFound = PL.GetFirstLine( ptP1, ptP2) ; bFound ; bFound = PL.GetNextLine( ptP1, ptP2)) { // verifico la faccia di appartenenza int nFace ; if ( GetLineInFace( ptP1, ptP2, nFace)) { // creo la linea PtrOwner pLine( CreateCurveLine()) ; if ( ! IsNull( pLine) && pLine->Set( ptP1, ptP2)) { vCrvP[ nFace - 1].emplace_back( Release( pLine)) ; bSomeInFace = true ; } else bOk = false ; } } } // Se trovate curve che stanno completamente in una faccia if ( bSomeInFace) { // elimino curve troppo corte const double TOLER = 10 * EPS_SMALL ; for ( int i = 0 ; i < SIDE_NBR ; ++ i) { double dFaceLen = 0 ; for ( const auto& pLine : vCrvP[i]) { double dLen ; if ( pLine->GetLength( dLen)) dFaceLen += dLen ; } if ( dFaceLen < TOLER) vCrvP[i].clear() ; } // elimino eventuale faccia che rimarrebbe penzolante int nCross ; if ( IsCrossCut( vPL, nCross)) { if ( ! RemoveDanglingFace( nCross, vCrvP, pStm)) bOk = false ; } // per ogni faccia for ( int i = BTL_SIDE_FRONT ; i <= BTL_SIDE_LEFT ; ++ i) { if ( ! AdjustOneOutlineFace( i, vCrvP[i-1])) bOk = false ; } } // Altrimenti, verifico se la superficie di lavorazione coincide con una faccia else { Point3d ptCen ; Vector3d vtN ; // se la superficie è formata da una sola faccetta if ( pStm->GetFacetCount() == 1 && pStm->GetFacetCenter( 0, ptCen, vtN)) { // per ogni faccia for ( int i = BTL_SIDE_FRONT ; i <= BTL_SIDE_LEFT ; ++ i) { // piano della faccia Plane3d plFace = GetSidePlane( i) ; // verifico se la faccetta coincide con la faccia if ( PointInPlaneApprox( ptCen, plFace) && AreSameVectorApprox( vtN, plFace.GetVersN())) { // cancello la regione della faccia int nRegId = GetFaceRegion( i) ; m_pGDB->Erase( nRegId) ; break ; } } } } return bOk ; } //---------------------------------------------------------------------------- bool BtlGeom::GetLineInFace( const Point3d& ptP1, const Point3d& ptP2, int& nFace) const { // ciclo di verifica con le diverse facce nFace = BTL_SIDE_NONE ; for ( int i = BTL_SIDE_FRONT ; i <= BTL_SIDE_LEFT ; ++ i) { // se sta sulla faccia if ( IsLineOnFace( ptP1, ptP2, i)) { // se appartiene anche ad altra faccia, è sul bordo comune e quindi non interna if ( nFace != BTL_SIDE_NONE) return false ; // assegno la faccia else nFace = i ; } } return ( nFace != BTL_SIDE_NONE) ; } //---------------------------------------------------------------------------- bool BtlGeom::IsLineOnFace( const Point3d& ptP1, const Point3d& ptP2, int nFace) const { // piano della faccia Plane3d plFace = GetSidePlane( nFace) ; // sulla faccia se i due punti appartengono alla faccia return ( PointInPlaneEpsilon( ptP1, plFace, EPS_SMALL) && PointInPlaneEpsilon( ptP2, plFace, EPS_SMALL)) ; } //---------------------------------------------------------------------------- bool BtlGeom::IsCrossCut( const POLYLINEVECTOR& vPL, int& nCross) const { const double TOLER = 10 * EPS_SMALL ; // inizializzo flag int nCrossX = 0 ; int nCrossY = 0 ; int nCrossZ = 0 ; // ciclo sulle polilinee for ( auto& PL : vPL) { // ciclo sui punti della polilinea Point3d ptP ; for ( bool bFound = PL.GetFirstPoint( ptP) ; bFound ; bFound = PL.GetNextPoint( ptP)) { // verifica di appartenenza ad edge lungo X if ( abs( ptP.y) < TOLER && abs( ptP.z) < TOLER) nCrossX |= 1 ; if ( abs( ptP.y - m_vtDim.y) < TOLER && abs( ptP.z) < TOLER) nCrossX |= 2 ; if ( abs( ptP.y - m_vtDim.y) < TOLER && abs( ptP.z - m_vtDim.z) < TOLER) nCrossX |= 4 ; if ( abs( ptP.y) < TOLER && abs( ptP.z - m_vtDim.z) < TOLER) nCrossX |= 8 ; // verifica di appartenenza ad edge lungo Y if ( abs( ptP.z) < TOLER && abs( ptP.x) < TOLER) nCrossY |= 1 ; if ( abs( ptP.z - m_vtDim.z) < TOLER && abs( ptP.x) < TOLER) nCrossY |= 2 ; if ( abs( ptP.z - m_vtDim.z) < TOLER && abs( ptP.x - m_vtDim.x) < TOLER) nCrossY |= 4 ; if ( abs( ptP.z) < TOLER && abs( ptP.x - m_vtDim.x) < TOLER) nCrossY |= 8 ; // verifica di appartenenza ad edge lungo Z if ( abs( ptP.x) < TOLER && abs( ptP.y) < TOLER) nCrossZ |= 1 ; if ( abs( ptP.x - m_vtDim.x) < TOLER && abs( ptP.y) < TOLER) nCrossZ |= 2 ; if ( abs( ptP.x - m_vtDim.x) < TOLER && abs( ptP.y - m_vtDim.y) < TOLER) nCrossZ |= 4 ; if ( abs( ptP.x) < TOLER && abs( ptP.y - m_vtDim.y) < TOLER) nCrossZ |= 8 ; } } // non taglia niente nCross = CROSS_CUT_NONE ; // determino se taglia tutti gli edge di una direzione if ( nCrossX == ( 1 | 2 | 4 | 8)) nCross = CROSS_CUT_X ; else if ( nCrossY == ( 1 | 2 | 4 | 8)) nCross = CROSS_CUT_Y ; else if ( nCrossZ == ( 1 | 2 | 4 | 8)) nCross = CROSS_CUT_Z ; // determino se taglia gli edge combinati di due direzioni if ( ( ( nCrossZ & ( 1|8)) == ( 1|8) || ( nCrossZ & ( 2|4)) == ( 2|4)) && ( ( nCrossX & ( 1|2)) == ( 1|2) || ( nCrossX & ( 4|8)) == ( 4|8))) nCross = CROSS_CUT_Z | CROSS_CUT_X ; else if ( ( ( nCrossX & ( 1|8)) == ( 1|8) || ( nCrossX & ( 2|4)) == ( 2|4)) && ( ( nCrossY & ( 1|2)) == ( 1|2) || ( nCrossY & ( 4|8)) == ( 4|8))) nCross = CROSS_CUT_X | CROSS_CUT_Y ; else if ( ( ( nCrossY & ( 1|8)) == ( 1|8) || ( nCrossY & ( 2|4)) == ( 2|4)) && ( ( nCrossZ & ( 1|2)) == ( 1|2) || ( nCrossZ & ( 4|8)) == ( 4|8))) nCross = CROSS_CUT_Y | CROSS_CUT_Z ; return ( nCross != CROSS_CUT_NONE) ; } //---------------------------------------------------------------------------- bool BtlGeom::RemoveDanglingFace( int nCross, const ICURVEPOVECTOR vCrvP[], const ISurfTriMesh* pStm) { // normale media alla superficie Vector3d vtN ; for ( int i = 0 ; i < pStm->GetFacetCount() ; ++ i) { Vector3d vtFacN ; double dFacArea ; if ( pStm->GetFacetNormal( i, vtFacN) && pStm->GetFacetArea( i, dFacArea)) vtN += vtFacN * dFacArea ; } if ( ! vtN.Normalize()) return false ; // verifico facce BTL_SIDE_LEFT (6) e BTL_SIDE_RIGHT (5) if ( ( nCross & CROSS_CUT_X) != 0) { if ( vtN.x < - SIN_EPS_ANG_SMALL && vCrvP[6-1].size() == 0) { // cancello la regione della faccia int nRegId = GetFaceRegion( 6) ; m_pGDB->Erase( nRegId) ; } else if ( vtN.x > SIN_EPS_ANG_SMALL && vCrvP[5-1].size() == 0) { // cancello la regione della faccia int nRegId = GetFaceRegion( 5) ; m_pGDB->Erase( nRegId) ; } } // verifico facce BTL_SIDE_FRONT (1) e BTL_SIDE_BACK (3) if ( ( nCross & CROSS_CUT_Y) != 0) { if ( vtN.y < - SIN_EPS_ANG_SMALL && vCrvP[1-1].size() == 0) { // cancello la regione della faccia int nRegId = GetFaceRegion( 1) ; m_pGDB->Erase( nRegId) ; } else if ( vtN.y > SIN_EPS_ANG_SMALL && vCrvP[3-1].size() == 0) { // cancello la regione della faccia int nRegId = GetFaceRegion( 3) ; m_pGDB->Erase( nRegId) ; } } // verifico facce BTL_SIDE_BOTTOM (2) e BTL_SIDE_TOP (4) if ( ( nCross & CROSS_CUT_Z) != 0) { if ( vtN.z < - SIN_EPS_ANG_SMALL && vCrvP[2-1].size() == 0) { // cancello la regione della faccia int nRegId = GetFaceRegion( 2) ; m_pGDB->Erase( nRegId) ; } else if ( vtN.z > SIN_EPS_ANG_SMALL && vCrvP[4-1].size() == 0) { // cancello la regione della faccia int nRegId = GetFaceRegion( 4) ; m_pGDB->Erase( nRegId) ; } } return true ; } //---------------------------------------------------------------------------- bool BtlGeom::AdjustOneOutlineFace( int nSide, ICURVEPOVECTOR& vCrvP) { // verifico ci siano delle curve di taglio if ( vCrvP.size() == 0) return true ; // recupero la regione associata alla faccia int nRegId = GetFaceRegion( nSide) ; ISurfFlatRegion* pFaceReg = GetSurfFlatRegion( m_pGDB->GetGeoObj( nRegId)) ; if ( pFaceReg == nullptr) return true ; // preparo la regione da sottrarre PtrOwner pSubReg ; // recupero il riferimento della faccia Frame3d frFace = GetSideFrame( nSide) ; // recupero il contorno della faccia nel suo proprio riferimento PtrOwner pFaceCnt( GetFaceContour( nSide)) ; if ( IsNull( pFaceCnt)) return false ; // porto le linee nel riferimento della faccia for ( auto& pCrv : vCrvP) { pCrv->ToLoc( frFace) ; pCrv->Scale( GLOB_FRM, 1, 1, 0) ; } // concateno le linee senza invertirle const double TOLER = 10 * EPS_SMALL ; ChainCurves chainC ; chainC.Init( false, TOLER, int( vCrvP.size())) ; for ( size_t i = 0 ; i < vCrvP.size() ; ++ i) { Point3d ptStart, ptEnd ; Vector3d vtStart, vtEnd ; if ( ! vCrvP[i]->GetStartPoint( ptStart) || ! vCrvP[i]->GetStartDir( vtStart) || ! vCrvP[i]->GetEndPoint( ptEnd) || ! vCrvP[i]->GetEndDir( vtEnd)) return false ; if ( ! chainC.AddCurve( int( i+1), ptStart, vtStart, ptEnd, vtEnd)) return false ; } Point3d ptNearL = ORIG ; INTVECTOR vId2s ; while ( chainC.GetChainFromNear( ptNearL, false, vId2s)) { // creo una curva composita PtrOwner pCrvCompo( CreateCurveComposite()) ; if ( IsNull( pCrvCompo)) return false ; // recupero le curve semplici e le inserisco nella curva composita for ( size_t i = 0 ; i < vId2s.size() ; ++ i) { // indice della curva int j = vId2s[i] - 1 ; // la aggiungo alla curva composta bool bOk = pCrvCompo->AddCurve( Release( vCrvP[j]), true, TOLER) ; if ( ! bOk) return false ; } // se curva aperta, la completo con il contorno della faccia if ( ! pCrvCompo->IsClosed()) { const double EXTRA_LEN = 5 * EPS_SMALL ; // per sicurezza allungo gli estremi pCrvCompo->ExtendStartByLen( EXTRA_LEN) ; pCrvCompo->ExtendEndByLen( EXTRA_LEN) ; // intersezione della curva col contorno IntersCurveCurve intCC( *pCrvCompo, *pFaceCnt) ; int nIntCount = intCC.GetIntersCount() ; if ( nIntCount < 2) continue ; IntCrvCrvInfo iccInfo ; intCC.GetIntCrvCrvInfo( 0, iccInfo) ; double dParStart = iccInfo.IciA[0].dU ; double dParCntEnd = iccInfo.IciB[0].dU ; intCC.GetIntCrvCrvInfo( nIntCount - 1, iccInfo) ; double dParEnd = iccInfo.IciA[0].dU ; double dParCntStart = iccInfo.IciB[0].dU ; // aggiusto la curva pCrvCompo->TrimStartEndAtParam( dParStart, dParEnd) ; // recupero parte del contorno tra intersezione fine e intersezione inizio PtrOwner pTmpCrv( pFaceCnt->CopyParamRange( dParCntStart, dParCntEnd)) ; if ( IsNull( pTmpCrv) || ! pCrvCompo->AddCurve( Release( pTmpCrv))) continue ; // se ora non è chiusa, salto alla prossima concatenazione if ( ! pCrvCompo->IsClosed()) continue ; } // porto la curva nel riferimento del pezzo pCrvCompo->ToGlob( frFace) ; // creo una regione a partire dalla curva SurfFlatRegionByContours SfrCntr ; SfrCntr.AddCurve( Release( pCrvCompo)) ; PtrOwner pSfrReg( SfrCntr.GetSurf()) ; if ( IsNull( pSfrReg)) continue ; // se opposta alla faccia, devo prenderne il complementare rispetto a questa if ( AreOppositeVectorApprox( pFaceReg->GetNormVersor(), pSfrReg->GetNormVersor())) { PtrOwner pSfrTmp( Release( pSfrReg)) ; pSfrReg.Set( pFaceReg->Clone()) ; if ( IsNull( pSfrReg)) continue ; pSfrTmp->Invert() ; pSfrReg->Subtract( *pSfrTmp) ; } // se la regione sottrazione totale non esiste, la assegno if ( IsNull( pSubReg)) pSubReg.Set( Release( pSfrReg)) ; // altrimenti la combino con la nuova else { // salvo una copia della regione sottrazione totale PtrOwner pSubCopy( pSubReg->Clone()) ; if ( IsNull( pSubCopy)) return false ; // provo a intersecarle pSubReg->Intersect( *pSfrReg) ; // se non rimane alcunché, provo a unirle if ( ! pSubReg->IsValid()) { pSubReg.Set( Release( pSubCopy)) ; pSubReg->Add( *pSfrReg) ; } } } // se esiste regione sottrazione, la tolgo dalla regione della faccia if ( ! IsNull( pSubReg)) { // eseguo sottrazione pFaceReg->Subtract( *pSubReg) ; // se vuota, la elimino if ( ! pFaceReg->IsValid()) m_pGDB->Erase( nRegId) ; } return true ; } //---------------------------------------------------------------------------- int BtlGeom::GetFaceRegion( int nSide) { int nId = m_pGDB->GetFirstInGroup( m_nOutsId) ; while ( nId != GDB_ID_NULL) { int nS ; if ( m_pGDB->GetGeoType( nId) == SRF_FLATRGN && m_pGDB->GetInfo( nId, IKEY_OTL_SIDE, nS) && nS == nSide) return nId ; nId = m_pGDB->GetNext( nId) ; } return GDB_ID_NULL ; } //---------------------------------------------------------------------------- ICurveComposite* BtlGeom::GetFaceContour( int nSide) { // verifico validità indice di faccia if ( nSide < BTL_SIDE_FRONT || nSide > BTL_SIDE_LEFT) return nullptr ; // creo il contorno antiorario PolyLine PL ; PL.AddUPoint( 0, ORIG) ; PL.AddUPoint( 1, Point3d( GetSideLength( nSide), 0, 0)) ; PL.AddUPoint( 2, Point3d( GetSideLength( nSide), GetSideWidth( nSide), 0)) ; PL.AddUPoint( 3, Point3d( 0, GetSideWidth( nSide), 0)) ; PL.AddUPoint( 4, ORIG) ; // creo la curva composita PtrOwner pCrvCompo( CreateCurveComposite()) ; if ( IsNull( pCrvCompo) || ! pCrvCompo->FromPolyLine( PL)) return nullptr ; else return Release( pCrvCompo) ; } //---------------------------------------------------------------------------- bool BtlGeom::IsPointOnFaceContour( const Point3d& ptP, int nSide) { // Il punto è nel riferimento faccia // Verifico se sta sul contorno return ( abs( ptP.x) < EPS_SMALL || abs( ptP.x - GetSideLength( nSide)) < EPS_SMALL || abs( ptP.y) < EPS_SMALL || abs( ptP.y - GetSideWidth( nSide)) < EPS_SMALL) ; } //---------------------------------------------------------------------------- bool BtlGeom::IsPointNearFaceContour( const Point3d& ptP, int nSide) { // Il punto è nel riferimento faccia // Verifico se sta vicino al contorno o fuori const double EPS_IN_NEAR = 0.2 ; const double EPS_OUT_NEAR = 1.0 ; double dL = GetSideLength( nSide) ; double dW = GetSideWidth( nSide) ; return ( ( ptP.x > - EPS_OUT_NEAR && ptP.x < EPS_IN_NEAR) || ( ptP.x > dL - EPS_IN_NEAR && ptP.x < dL + EPS_OUT_NEAR) || ( ptP.y > - EPS_OUT_NEAR && ptP.y < EPS_IN_NEAR) || ( ptP.y > dW - EPS_IN_NEAR && ptP.y < dW + EPS_OUT_NEAR)) ; } //---------------------------------------------------------------------------- bool BtlGeom::SetPointOnFaceContour( Point3d& ptP, int nSide) { // Il punto è nel riferimento faccia // Dimensioni della faccia double dL = GetSideLength( nSide) ; double dW = GetSideWidth( nSide) ; // Sistemazioni per punto esterno if ( ptP.x < 0) ptP.x = 0 ; else if ( ptP.x > dL) ptP.x = dL ; if ( ptP.y < 0) ptP.y = 0 ; else if ( ptP.y > dW) ptP.y = dW ; // Sistemazioni per punto interno double vDist[4] = { abs( ptP.x), abs( ptP.x - dL), abs( ptP.y), abs( ptP.y - dW)} ; int nMinDistSide = 0 ; for ( int i = 1 ; i < 4 ; ++i) { if ( vDist[i] < vDist[nMinDistSide]) nMinDistSide = i ; } switch ( nMinDistSide) { case 0 : ptP.x = 0 ; break ; case 1 : ptP.x = dL ; break ; case 2 : ptP.y = 0 ; break ; case 3 : ptP.y = dW ; break ; } return true ; } //---------------------------------------------------------------------------- bool BtlGeom::TrimRayWithFaceContour( const Point3d& ptP, const Vector3d& vtDir, int nSide, Point3d& ptInt) { // Punto e direzione sono nel riferimento faccia // Dimensioni della faccia double dL = GetSideLength( nSide) ; double dW = GetSideWidth( nSide) ; // Verifico che il punto sia nella faccia if ( ptP.x < EPS_SMALL || ptP.x > dL - EPS_SMALL || ptP.y < EPS_SMALL || ptP.y > dW - EPS_SMALL) return false ; // Creo la linea rappresentativa del raggio PtrOwner pRay( CreateCurveLine()) ; if ( IsNull( pRay) || ! pRay->SetPVL( ptP, vtDir, dL + dW)) return false ; // Recupero il contorno della faccia PtrOwner pCont( GetFaceContour( nSide)) ; if ( IsNull( pCont)) return false ; // Calcolo l'intersezione del raggio con il contorno della faccia return IntersCurveCurve( *pRay, *pCont).GetIntersPointNearTo( 0, ptP, ptInt) ; }