//---------------------------------------------------------------------------- // 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/EGkOffsetCurve.h" #include "/EgtDev/Include/EGkSfrCreate.h" #include "/EgtDev/Include/EGkStmStandard.h" #include "/EgtDev/Include/EGkStmFromCurves.h" #include "/EgtDev/Include/EGkStmFromTriangleSoup.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, int nContType, int nContData, double dContPar, const STRVECTOR& vsUAtt) { // 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 ; // costruisco il percorso di contorno PtrOwner pCrvCompo( CurveFromFces( dqFce)) ; if ( IsNull( pCrvCompo)) return false ; // aggiusto orientamento affinché sia antiorario (devo inoltre invertire il segno dell'angolo di fianco) double dArea ; pCrvCompo->GetAreaXY( dArea) ; if ( dArea < 0) { pCrvCompo->Invert() ; for ( int i = 0 ; i < pCrvCompo->GetCurveCount() ; ++ i) { int nAng ; if ( pCrvCompo->GetCurveTempProp( i, nAng) && abs( nAng) > 10) pCrvCompo->SetCurveTempProp( i, - nAng) ; } } // Porto il percorso sul piano corretto Frame3d frRef = GetSideFrame( nSide) ; pCrvCompo->ToGlob( frRef) ; // Sistemazioni della curva pCrvCompo->SetExtrusion( frRef.VersZ()) ; pCrvCompo->SetThickness( -GetSideHeight( nSide)) ; // Creo la superficie PtrOwner pStm ; pStm.Set( CreateOneCurveFreeContour( pCrvCompo)) ; 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 ; // recupero eventuali angoli di fianco DBLVECTOR vSideAng ; if ( VerifyFreeContourCurveSideAng( pCrvCompo)) GetFreeContourCurveSideAngles( pCrvCompo, vSideAng) ; // inserisco la curva nel DB geometrico int nTId = m_pGDB->AddGeoObj( GDB_ID_NULL, m_nOutsId, Release( pCrvCompo)) ; if ( nTId != GDB_ID_NULL && vSideAng.size() > 0) m_pGDB->SetInfo( nTId, IKEY_SIDEANGS, vSideAng) ; // colore Color cCol = m_ProcsCol ; m_pGDB->SetMaterial( nId, cCol) ; m_pGDB->SetMaterial( nTId, cCol) ; // nome m_pGDB->SetName( nId, GetOutlineOutName( nSide)) ; // info con tipo m_pGDB->SetInfo( nId, IKEY_GROUP, 4) ; m_pGDB->SetInfo( nId, IKEY_PROC, 251) ; m_pGDB->SetInfo( nId, IKEY_SIDE, nSide) ; // eventuali parametri del contorno if ( nContType > 0 || ( nContType >= 0 && nContData != 0)) m_pGDB->SetInfo( nId, IKEY_CNT_TYPE, nContType) ; if ( nContData != 0) m_pGDB->SetInfo( nId, IKEY_CNT_DATA, nContData) ; if ( abs( dContPar) > EPS_SMALL) m_pGDB->SetInfo( nId, IKEY_CNT_PAR, dContPar) ; // eventuali attributi utente if ( ! SetUserAttributes( nId, vsUAtt)) return false ; // identificativi di geometrie ausiliarie SetAuxId( nId, {nTId}) ; // se richiesto Outline nel piano XY verifico ed eventualmente ruoto il pezzo if ( m_nFlatVertPos == 4) { Frame3d frOutline ; if ( m_pGDB->GetGroupGlobFrame( m_nOutsId, frOutline)) { Vector3d vtNorm = GetSideVersN( nSide) ; vtNorm.ToGlob( frOutline) ; if ( ! AreSameOrOppositeVectorApprox( vtNorm, Z_AX)) { BBox3d b3Part ; if ( m_pGDB->GetGlobalBBox( m_nBoxId, b3Part)) { Vector3d vtDim = b3Part.GetMax() - b3Part.GetMin() ; Point3d ptAx = b3Part.GetMin() + 0.5 * Vector3d( 0, vtDim.y, vtDim.y) ; m_pGDB->RotateGlob( m_nPartId, ptAx, X_AX, 0, 1) ; } } } } return true ; } //---------------------------------------------------------------------------- bool BtlGeom::AddPartOutline( int nSide, int nCrvId, const DBLVECTOR& vdPar, const STRVECTOR& vsUAtt) { // reset dell'identificativo della geometria principale della feature m_nProcId = GDB_ID_NULL ; // verifico esistenza pezzo if ( m_nBoxId == GDB_ID_NULL) return false ; // verifico validità faccia if ( ! IsTrueSide( nSide)) return false ; // verifica dei parametri if ( vdPar.size() < 14) return false ; // sistemo i dati int nContType = lround( vdPar[11]) ; // P13 int nContData = lround( vdPar[12]) ; // P14 double dContPar = vdPar[13] ; // P15 // verifico esista il percorso di contorno if ( nCrvId == GDB_ID_NULL) { // inserisco superficie vuota come marcatore PtrOwner pStm( CreateSurfTriMesh()) ; if ( IsNull( pStm) || ! pStm->AdjustTopology()) return false ; // la inserisco nel DB geometrico int nId = m_pGDB->AddGeoObj( GDB_ID_NULL, m_nOutsId, Release( pStm)) ; if ( nId == GDB_ID_NULL) return false ; // nome m_pGDB->SetName( nId, GetOutlineOutName( nSide)) ; // info con tipo m_pGDB->SetInfo( nId, IKEY_GROUP, 4) ; m_pGDB->SetInfo( nId, IKEY_PROC, 251) ; m_pGDB->SetInfo( nId, IKEY_SIDE, nSide) ; // eventuali parametri del contorno if ( nContType > 0 || ( nContType >= 0 && nContData != 0)) m_pGDB->SetInfo( nId, IKEY_CNT_TYPE, nContType) ; if ( nContData != 0) m_pGDB->SetInfo( nId, IKEY_CNT_DATA, nContData) ; if ( abs( dContPar) > EPS_SMALL) m_pGDB->SetInfo( nId, IKEY_CNT_PAR, dContPar) ; // eventuali attributi utente if ( ! SetUserAttributes( nId, vsUAtt)) return false ; m_nProcId = nId ; // messaggio di warning in log string sOut = " Warning : Empty Outline (" + ToString( nSide) + ") on line " + ToString( m_nBtlLine) ; LOG_WARN( GetEExLogger(), sOut.c_str()) return true ; } // copio il percorso di contorno PtrOwner pCrvCompo ; if ( m_pGDB->GetGeoType( nCrvId) & GEO_CURVE) { pCrvCompo.Set( CreateCurveComposite()) ; if ( ! pCrvCompo->CopyFrom( m_pGDB->GetGeoObj( nCrvId))) pCrvCompo.Reset() ; } if ( IsNull( pCrvCompo)) return false ; // verifico che sia chiuso if ( ! pCrvCompo->IsClosed()) return false ; // assegno eventuali angoli di fianco { DBLVECTOR vSideAng ; if ( m_pGDB->GetInfo( nCrvId, IKEY_SIDEANGS, vSideAng)) { for ( int i = 0 ; i < int( vSideAng.size()) ; ++ i) pCrvCompo->SetCurveTempProp( i, int( vSideAng[i] * 1000)) ; } } // Lo porto nel riferimento del lato e ve lo appiattisco Frame3d frRef = GetSideFrame( nSide) ; pCrvCompo->ToLoc( frRef) ; pCrvCompo->Scale( Frame3d(), 1, 1, 0) ; // aggiusto orientamento affinché sia antiorario (devo inoltre invertire il segno dell'angolo di fianco) double dArea ; pCrvCompo->GetAreaXY( dArea) ; if ( dArea < 0) { pCrvCompo->Invert() ; for ( int i = 0 ; i < pCrvCompo->GetCurveCount() ; ++ i) { int nAng ; if ( pCrvCompo->GetCurveTempProp( i, nAng) && abs( nAng) > 10) pCrvCompo->SetCurveTempProp( i, -nAng) ; } } // Porto il percorso sul piano corretto pCrvCompo->ToGlob( frRef) ; // Sistemazioni della curva pCrvCompo->SetExtrusion( frRef.VersZ()) ; pCrvCompo->SetThickness( -GetSideHeight( nSide)) ; // Creo la superficie PtrOwner pStm ; pStm.Set( CreateOneCurveFreeContour( pCrvCompo)) ; 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 ; // recupero eventuali angoli di fianco DBLVECTOR vSideAng ; if ( VerifyFreeContourCurveSideAng( pCrvCompo)) GetFreeContourCurveSideAngles( pCrvCompo, vSideAng) ; // inserisco la curva nel DB geometrico int nTId = m_pGDB->AddGeoObj( GDB_ID_NULL, m_nOutsId, Release( pCrvCompo)) ; if ( nTId != GDB_ID_NULL && vSideAng.size() > 0) m_pGDB->SetInfo( nTId, IKEY_SIDEANGS, vSideAng) ; // colore Color cCol = m_ProcsCol ; m_pGDB->SetMaterial( nId, cCol) ; m_pGDB->SetMaterial( nTId, cCol) ; // nome m_pGDB->SetName( nId, GetOutlineOutName( nSide)) ; // info con tipo m_pGDB->SetInfo( nId, IKEY_GROUP, 4) ; m_pGDB->SetInfo( nId, IKEY_PROC, 251) ; m_pGDB->SetInfo( nId, IKEY_SIDE, nSide) ; // eventuali parametri del contorno if ( nContType > 0 || ( nContType >= 0 && nContData != 0)) m_pGDB->SetInfo( nId, IKEY_CNT_TYPE, nContType) ; if ( nContData != 0) m_pGDB->SetInfo( nId, IKEY_CNT_DATA, nContData) ; if ( abs( dContPar) > EPS_SMALL) m_pGDB->SetInfo( nId, IKEY_CNT_PAR, dContPar) ; // eventuali attributi utente if ( ! SetUserAttributes( nId, vsUAtt)) return false ; // identificativi di geometrie ausiliarie SetAuxId( nId, {nTId}) ; m_nProcId = nId ; return true ; } //---------------------------------------------------------------------------- bool BtlGeom::AddPartAperture( int nSide, const FCEDEQUE& dqFce, int nContType, int nContData, double dContPar, const STRVECTOR& vsUAtt) { // 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 ; // costruisco il percorso di contorno PtrOwner pCrvCompo( CurveFromFces( dqFce)) ; if ( IsNull( pCrvCompo)) return false ; // aggiusto orientamento affinché sia orario double dArea ; pCrvCompo->GetAreaXY( dArea) ; if ( dArea > 0) pCrvCompo->Invert() ; // Porto il percorso sul piano corretto Frame3d frRef = GetSideFrame( nSide) ; pCrvCompo->ToGlob( frRef) ; // Sistemazioni della curva pCrvCompo->SetExtrusion( frRef.VersZ()) ; pCrvCompo->SetThickness( -GetSideHeight( nSide)) ; // Creo la superficie PtrOwner pStm ; pStm.Set( CreateOneCurveFreeContour( pCrvCompo)) ; 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 ; // recupero eventuali angoli di fianco DBLVECTOR vSideAng ; if ( VerifyFreeContourCurveSideAng( pCrvCompo)) GetFreeContourCurveSideAngles( pCrvCompo, vSideAng) ; // inserisco la curva nel DB geometrico int nTId = m_pGDB->AddGeoObj( GDB_ID_NULL, m_nOutsId, Release( pCrvCompo)) ; if ( nTId != GDB_ID_NULL && vSideAng.size() > 0) m_pGDB->SetInfo( nTId, IKEY_SIDEANGS, vSideAng) ; // colore Color cCol = m_ProcsCol ; m_pGDB->SetMaterial( nId, cCol) ; m_pGDB->SetMaterial( nTId, cCol) ; // nome m_pGDB->SetName( nId, GetOutlineApertureName( nSide)) ; // info con tipo m_pGDB->SetInfo( nId, IKEY_GROUP, 4) ; m_pGDB->SetInfo( nId, IKEY_PROC, 252) ; m_pGDB->SetInfo( nId, IKEY_SIDE, nSide) ; // eventuali parametri del contorno if ( nContType > 0 || ( nContType >= 0 && nContData != 0)) m_pGDB->SetInfo( nId, IKEY_CNT_TYPE, nContType) ; if ( nContData != 0) m_pGDB->SetInfo( nId, IKEY_CNT_DATA, nContData) ; if ( abs( dContPar) > EPS_SMALL) m_pGDB->SetInfo( nId, IKEY_CNT_PAR, dContPar) ; // eventuali attributi utente if ( ! SetUserAttributes( nId, vsUAtt)) return false ; // identificativi di geometrie ausiliarie SetAuxId( nId, {nTId}) ; return true ; } //---------------------------------------------------------------------------- bool BtlGeom::AddPartAperture( int nSide, int nCrvId, const DBLVECTOR& vdPar, const STRVECTOR& vsUAtt) { // reset dell'identificativo della geometria principale della feature m_nProcId = GDB_ID_NULL ; // verifico esistenza pezzo if ( m_nBoxId == GDB_ID_NULL) return false ; // verifico validità faccia if ( ! IsTrueSide( nSide)) return false ; // verifica dei parametri if ( vdPar.size() < 14) return false ; // sistemo i dati int nContType = lround( vdPar[11]) ; // P13 int nContData = lround( vdPar[12]) ; // P14 double dContPar = vdPar[13] ; // P15 // verifico esista il percorso di contorno if ( nCrvId == GDB_ID_NULL) { // inserisco superficie vuota come marcatore PtrOwner pStm( CreateSurfTriMesh()) ; if ( IsNull( pStm) || ! pStm->AdjustTopology()) return false ; // la inserisco nel DB geometrico int nId = m_pGDB->AddGeoObj( GDB_ID_NULL, m_nOutsId, Release( pStm)) ; if ( nId == GDB_ID_NULL) return false ; // nome m_pGDB->SetName( nId, GetOutlineApertureName( nSide)) ; // info con tipo m_pGDB->SetInfo( nId, IKEY_GROUP, 4) ; m_pGDB->SetInfo( nId, IKEY_PROC, 252) ; m_pGDB->SetInfo( nId, IKEY_SIDE, nSide) ; // eventuali parametri del contorno if ( nContType > 0 || ( nContType >= 0 && nContData != 0)) m_pGDB->SetInfo( nId, IKEY_CNT_TYPE, nContType) ; if ( nContData != 0) m_pGDB->SetInfo( nId, IKEY_CNT_DATA, nContData) ; if ( abs( dContPar) > EPS_SMALL) m_pGDB->SetInfo( nId, IKEY_CNT_PAR, dContPar) ; // eventuali attributi utente if ( ! SetUserAttributes( nId, vsUAtt)) return false ; m_nProcId = nId ; // messaggio di warning in log string sOut = " Warning : Empty Aperture (" + ToString( nSide) + ") on line " + ToString( m_nBtlLine) ; LOG_WARN( GetEExLogger(), sOut.c_str()) return true ; } // copio il percorso di contorno PtrOwner pCrvCompo ; if ( m_pGDB->GetGeoType( nCrvId) & GEO_CURVE) { pCrvCompo.Set( CreateCurveComposite()) ; if ( ! pCrvCompo->CopyFrom( m_pGDB->GetGeoObj( nCrvId))) pCrvCompo.Reset() ; } if ( IsNull( pCrvCompo)) return false ; // verifico che sia chiuso if ( ! pCrvCompo->IsClosed()) return false ; // assegno eventuali angoli di fianco { DBLVECTOR vSideAng ; if ( m_pGDB->GetInfo( nCrvId, IKEY_SIDEANGS, vSideAng)) { for ( int i = 0 ; i < int( vSideAng.size()) ; ++ i) pCrvCompo->SetCurveTempProp( i, int( vSideAng[i] * 1000)) ; } } // Lo porto nel riferimento del lato e ve lo appiattisco Frame3d frRef = GetSideFrame( nSide) ; pCrvCompo->ToLoc( frRef) ; pCrvCompo->Scale( Frame3d(), 1, 1, 0) ; // aggiusto orientamento affinché sia orario double dArea ; pCrvCompo->GetAreaXY( dArea) ; if ( dArea > 0) pCrvCompo->Invert() ; // Porto il percorso sul piano corretto e ve lo appiattisco pCrvCompo->ToGlob( frRef) ; // Sistemazioni della curva pCrvCompo->SetExtrusion( frRef.VersZ()) ; pCrvCompo->SetThickness( -GetSideHeight( nSide)) ; // Creo la superficie PtrOwner pStm ; pStm.Set( CreateOneCurveFreeContour( pCrvCompo)) ; 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 ; // recupero eventuali angoli di fianco DBLVECTOR vSideAng ; if ( VerifyFreeContourCurveSideAng( pCrvCompo)) GetFreeContourCurveSideAngles( pCrvCompo, vSideAng) ; // inserisco la curva nel DB geometrico int nTId = m_pGDB->AddGeoObj( GDB_ID_NULL, m_nOutsId, Release( pCrvCompo)) ; if ( nTId != GDB_ID_NULL && vSideAng.size() > 0) m_pGDB->SetInfo( nTId, IKEY_SIDEANGS, vSideAng) ; // colore Color cCol = m_ProcsCol ; m_pGDB->SetMaterial( nId, cCol) ; m_pGDB->SetMaterial( nTId, cCol) ; // nome m_pGDB->SetName( nId, GetOutlineApertureName( nSide)) ; // info con tipo m_pGDB->SetInfo( nId, IKEY_GROUP, 4) ; m_pGDB->SetInfo( nId, IKEY_PROC, 252) ; m_pGDB->SetInfo( nId, IKEY_SIDE, nSide) ; // eventuali parametri del contorno if ( nContType > 0 || ( nContType >= 0 && nContData != 0)) m_pGDB->SetInfo( nId, IKEY_CNT_TYPE, nContType) ; if ( nContData != 0) m_pGDB->SetInfo( nId, IKEY_CNT_DATA, nContData) ; if ( abs( dContPar) > EPS_SMALL) m_pGDB->SetInfo( nId, IKEY_CNT_PAR, dContPar) ; // eventuali attributi utente if ( ! SetUserAttributes( nId, vsUAtt)) return false ; // identificativi di geometrie ausiliarie SetAuxId( nId, {nTId}) ; m_nProcId = nId ; return true ; } //---------------------------------------------------------------------------- bool BtlGeom::UpdateOutLine( void) { // verifiche if ( m_pGDB == nullptr || m_nPartId == GDB_ID_NULL) return false ; // pulisco il gruppo di Outline (elimino tutte le regioni) int nOutId = m_pGDB->GetFirstInGroup( m_nOutsId) ; while ( nOutId != GDB_ID_NULL) { int nNextId = m_pGDB->GetNext( nOutId) ; if ( m_pGDB->GetGeoType( nOutId) == SRF_FLATRGN) m_pGDB->Erase( nOutId) ; nOutId = nNextId ; } // se non riesco a creare l'outline speciale if ( ! AddPartCustomOutline()) // creo quello standard AddPartStdOutline() ; // taglio con tutte le aperture TrimOutlineWithApertures() ; // taglio con tutte le features TrimOutlineWithProcesses() ; // se presente Shape, nascondo Outline int nShapeId = m_pGDB->GetFirstNameInGroup( m_nOutsId, OL_SHAPE_NAME) ; if ( nShapeId != GDB_ID_NULL) { int nEntId = m_pGDB->GetFirstInGroup( m_nOutsId) ; while ( nEntId != GDB_ID_NULL) { if ( nEntId != nShapeId) m_pGDB->SetStatus( nEntId, GDB_ST_OFF) ; nEntId = m_pGDB->GetNext( nEntId) ; } } return true ; } //---------------------------------------------------------------------------- bool BtlGeom::AddPartStdOutline( void) { // verifico esistenza pezzo if ( m_nBoxId == GDB_ID_NULL) return false ; // aggiungo le regioni delle facce for ( int nSide = BTL_SIDE_FRONT ; nSide <= BTL_SIDE_RIGHT ; ++ 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) ; } return true ; } //---------------------------------------------------------------------------- bool BtlGeom::AddPartCustomOutline( void) { // se gruppo di Outline vuoto if ( m_pGDB->GetGroupObjs( m_nOutsId) == 0) return false ; // Cerco contorno per creare le facce sopra e sotto bool bDone = false ; int nOutId = m_pGDB->GetFirstInGroup( m_nOutsId) ; while ( nOutId != GDB_ID_NULL) { int nDO = 1 ; m_pGDB->GetInfo( nOutId, IKEY_DO, nDO) ; int nPrc = 0 ; m_pGDB->GetInfo( nOutId, IKEY_PROC, nPrc) ; if ( nDO != 0 && nPrc == 251 && m_pGDB->GetGeoType( nOutId) == SRF_TRIMESH) { // Riferimento int nSide = 0 ; m_pGDB->GetInfo( nOutId, IKEY_SIDE, nSide) ; Frame3d frRef = GetSideFrame( nSide) ; Vector3d vtExtr = - frRef.VersZ() * GetSideHeight( nSide) ; // Superficie del contorno const ISurfTriMesh* pStm = GetSurfTriMesh( m_pGDB->GetGeoObj( nOutId)) ; // Creo le regioni sopra e sotto PtrOwner pSfr1 ; PtrOwner pSfr2 ; // dai contorni della superficie POLYLINEVECTOR vPL ; bool bOk = pStm->GetLoops( vPL) && vPL.size() == 2 ; if ( bOk) { PtrOwner pLoop1( CreateCurveComposite()) ; PtrOwner pMySfr1( CreateSurfFlatRegion()) ; bOk = ( ! IsNull( pLoop1) && ! IsNull( pMySfr1) && pLoop1->FromPolyLine( vPL[0]) && pMySfr1->AddExtLoop( Release( pLoop1))) ; bOk = bOk && pMySfr1->Invert() ; PtrOwner pLoop2( CreateCurveComposite()) ; PtrOwner pMySfr2( CreateSurfFlatRegion()) ; bOk = ( bOk && ! IsNull( pLoop2) && ! IsNull( pMySfr2) && pLoop2->FromPolyLine( vPL[1]) && pMySfr2->AddExtLoop( Release( pLoop2))) ; bOk = bOk && pMySfr2->Invert() ; if ( AreSameVectorApprox( pMySfr1->GetNormVersor(), frRef.VersZ())) { pSfr1.Set( pMySfr1) ; pSfr2.Set( pMySfr2) ; } else { pSfr1.Set( pMySfr2) ; pSfr2.Set( pMySfr1) ; } } // se non riesce, li calcolo in modo approssimato if ( ! bOk) { int nAuxId = GDB_ID_NULL ; m_pGDB->GetInfo( nOutId, IKEY_AUXID, nAuxId) ; if ( nAuxId == GDB_ID_NULL) return false ; nAuxId += nOutId ; const ICurveComposite* pCrvCompo = GetCurveComposite( m_pGDB->GetGeoObj( nAuxId)) ; if ( pCrvCompo == nullptr) return false ; pSfr1.Set( CreateSurfFlatRegion()) ; if ( IsNull( pSfr1) || ! pSfr1->AddExtLoop( *pCrvCompo)) return false ; pSfr2.Set( 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)) ; // faccio una copia di queste regioni (non vanno ridotte con altre feature) int nCopyId1 = m_pGDB->Copy( nId1, GDB_ID_NULL, nId1, GDB_AFTER) ; m_pGDB->SetName( nCopyId1, GetOutlineTopName( nSide) + OL_SUFFIX_REGION_NAME) ; m_pGDB->SetInfo( nCopyId1, IKEY_OTL_REGION, 1) ; m_pGDB->SetStatus( nCopyId1, GDB_ST_OFF) ; int nCopyId2 = m_pGDB->Copy( nId2, GDB_ID_NULL, nId2, GDB_AFTER) ; m_pGDB->SetName( nCopyId2, GetOutlineBottomName( nSide) + OL_SUFFIX_REGION_NAME) ; m_pGDB->SetInfo( nCopyId2, IKEY_OTL_REGION, 1) ; m_pGDB->SetStatus( nCopyId2, GDB_ST_OFF) ; // dichiaro di aver creato le superfici bDone = true ; } nOutId = m_pGDB->GetNext( nOutId) ; } return bDone ; } //---------------------------------------------------------------------------- bool BtlGeom::TrimOutlineWithApertures( void) { // Cerco eventuali aperture per tagliare le facce sopra e sotto int nApeId = m_pGDB->GetFirstInGroup( m_nOutsId) ; while ( nApeId != GDB_ID_NULL) { int nDO = 1 ; m_pGDB->GetInfo( nApeId, IKEY_DO, nDO) ; int nPrc = 0 ; m_pGDB->GetInfo( nApeId, IKEY_PROC, nPrc) ; if ( nDO != 0 && nPrc == 252 && m_pGDB->GetGeoType( nApeId) == SRF_TRIMESH) { // Riferimento int nSide = 0 ; m_pGDB->GetInfo( nApeId, IKEY_SIDE, nSide) ; Frame3d frRef = GetSideFrame( nSide) ; Vector3d vtExtr = - frRef.VersZ() * GetSideHeight( nSide) ; // Recupero la curva ausiliaria int nAuxId = GDB_ID_NULL ; m_pGDB->GetInfo( nApeId, IKEY_AUXID, nAuxId) ; if ( nAuxId == GDB_ID_NULL) return false ; nAuxId += nApeId ; const ICurveComposite* pCrvAux = GetCurveComposite( m_pGDB->GetGeoObj( nAuxId)) ; PtrOwner pCrvCompo( ( pCrvAux != nullptr ? pCrvAux->Clone() : nullptr)) ; if ( pCrvCompo == nullptr) return false ; // Creo le regioni sopra e sotto pCrvCompo->Invert() ; 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( GetFaceRegion( nSide))) ; if ( pSfrTop == nullptr) return false ; pSfrTop->Subtract( *pSfr1) ; ISurfFlatRegion* pSfrBot = GetSurfFlatRegion( m_pGDB->GetGeoObj( GetFaceRegion( GetOppositeSide( nSide)))) ; if ( pSfrBot == nullptr) return false ; pSfrBot->Subtract( *pSfr2) ; } nApeId = m_pGDB->GetNext( nApeId) ; } return true ; } //---------------------------------------------------------------------------- bool BtlGeom::TrimOutlineWithProcesses( void) { // calcolo il numero dei processi di trimming presenti int nProcCount = 0 ; for ( int nProcId = m_pGDB->GetFirstInGroup( m_nProcsId) ; nProcId != GDB_ID_NULL ; nProcId = m_pGDB->GetNext( nProcId)) { // deve essere una superficie if ( m_pGDB->GetGeoType( nProcId) != SRF_TRIMESH) continue ; // deve essere attiva int nDO = 1 ; m_pGDB->GetInfo( nProcId, IKEY_DO, nDO) ; if ( nDO == 0) continue ; // deve essere abilitata al trimming int nTrim = 1 ; m_pGDB->GetInfo( nProcId, IKEY_TRIM, nTrim) ; if ( nTrim == 0 || ! UseProcessToTrimOutline( nProcId)) continue ; // incremento il conteggio ++ nProcCount ; } // se troppi, salto i fori bool bSkipDrills = ( nProcCount > 200) ; // eseguo il trim for ( int nProcId = m_pGDB->GetFirstInGroup( m_nProcsId) ; nProcId != GDB_ID_NULL ; nProcId = m_pGDB->GetNext( nProcId)) { // deve essere una superficie if ( m_pGDB->GetGeoType( nProcId) != SRF_TRIMESH) continue ; // deve essere attiva int nDO = 1 ; m_pGDB->GetInfo( nProcId, IKEY_DO, nDO) ; if ( nDO == 0) continue ; // deve essere abilitata al trimming int nTrim = 1 ; m_pGDB->GetInfo( nProcId, IKEY_TRIM, nTrim) ; if ( nTrim == 0 || ! UseProcessToTrimOutline( nProcId)) continue ; // se fori da saltare, non deve essere un foro if ( bSkipDrills) { int nProc = 0 ; m_pGDB->GetInfo( nProcId, IKEY_PROC, nProc) ; if ( nProc == 40) continue ; } // eseguo il trim TrimOutline( nProcId) ; } 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 tipo di trim int nTrim = 0 ; m_pGDB->GetInfo( nProcSurfId, IKEY_TRIM, nTrim) ; // Recupero eventuale superficie originale int nOrigId = 0 ; if ( m_pGDB->GetInfo( nProcSurfId, IKEY_ORIGID, nOrigId)) nProcSurfId += nOrigId ; // Se processo con più superfici da usare insieme per trim, devo unirle if ( nTrim == 2) { // Recupero le due superfici del processo di lavorazione int nAux ; if ( m_pGDB->GetInfo( nProcSurfId, IKEY_AUXID, nAux) && nAux != 0) { const ISurfTriMesh* pStm = GetSurfTriMesh( m_pGDB->GetGeoObj( nProcSurfId)) ; const ISurfTriMesh* pAux = GetSurfTriMesh( m_pGDB->GetGeoObj( nProcSurfId + nAux)) ; if ( pStm != nullptr && pAux != nullptr) { PtrOwner pTrim ; pTrim.Set( pAux->Clone()) ; pTrim->DoSewing( *pStm) ; return TrimOutline( pTrim) ; } } return false ; } // Trim con una sola superficie const ISurfTriMesh* pStm = GetSurfTriMesh( m_pGDB->GetGeoObj( nProcSurfId)) ; if ( pStm == nullptr) return false ; // eseguo trim return TrimOutline( pStm) ; } //---------------------------------------------------------------------------- bool BtlGeom::TrimOutline( const 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_RIGHT ; ++ 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_RIGHT ; ++ 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_RIGHT ; ++ 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 (5) e BTL_SIDE_RIGHT (6) if ( ( nCross & CROSS_CUT_X) != 0) { 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) ; } else 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) ; } } // 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( 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( 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 && ! m_pGDB->ExistsInfo( nId, IKEY_OTL_REGION)) return nId ; nId = m_pGDB->GetNext( nId) ; } return GDB_ID_NULL ; } //---------------------------------------------------------------------------- ICurve* BtlGeom::GetFaceContour( int nSide) { // verifico validità indice di faccia if ( nSide < BTL_SIDE_FRONT || nSide > BTL_SIDE_RIGHT) 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 entro il limite const double EPS_IN_NEAR = 0.2 ; const double EPS_OUT_NEAR = 5.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::IsPointOutFaceContour( const Point3d& ptP, int nSide) { // Il punto è nel riferimento faccia // Verifico se sta all'esterno del contorno return ( ptP.x < -EPS_SMALL || ptP.x > GetSideLength( nSide) - EPS_SMALL || ptP.y < -EPS_SMALL || ptP.y > GetSideWidth( nSide) - EPS_SMALL) ; } //---------------------------------------------------------------------------- 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) ; } //---------------------------------------------------------------------------- bool BtlGeom::TrimProcessWithOutline( int nProcId) { // se non richiesto, esco subito if ( ! m_bTrimWithOutline) return true ; // verifico esistenza superficie della feature da trimmare ISurfTriMesh* pStm = GetSurfTriMesh( m_pGDB->GetGeoObj( nProcId)) ; if ( pStm == nullptr) return false ; // se prevista anche una seconda superficie da trimmare ISurfTriMesh* pStm2 = nullptr ; int nTrim = 0 ; if ( m_pGDB->GetInfo( nProcId, IKEY_TRIM, nTrim) && nTrim == 2) { int nAux ; if ( m_pGDB->GetInfo( nProcId, IKEY_AUXID, nAux) && nAux != 0) pStm2 = GetSurfTriMesh( m_pGDB->GetGeoObj( nProcId + nAux)) ; if ( pStm2 == nullptr) return false ; } // verifico esistenza superficie di outline int nOutId = GDB_ID_NULL ; int nEntId = m_pGDB->GetFirstInGroup( m_nOutsId) ; while ( nEntId != GDB_ID_NULL) { int nDO = 1 ; m_pGDB->GetInfo( nEntId, IKEY_DO, nDO) ; int nProc = 0 ; m_pGDB->GetInfo( nEntId, IKEY_PROC, nProc) ; int nSide = 0 ; m_pGDB->GetInfo( nEntId, IKEY_SIDE, nSide) ; if ( nDO != 0 && nProc == 251 && nSide != 0) { nOutId = nEntId ; break ; } nEntId = m_pGDB->GetNext( nEntId) ; } if ( nOutId == GDB_ID_NULL) return true ; // recupero la curva associata alla superficie di trim int nAuxId = 0 ; m_pGDB->GetInfo( nOutId, IKEY_AUXID, nAuxId) ; if ( nAuxId == 0) return true ; int nCrv = nOutId + nAuxId ; const ICurve* pCrv = GetCurve( m_pGDB->GetGeoObj( nCrv)) ; if ( pCrv == nullptr) return true ; // creo una copia della superficie come originale int nCopyId = m_pGDB->AddGeoObj( GDB_ID_NULL, m_nProcsId, pStm->Clone()) ; if ( nCopyId == GDB_ID_NULL) return false ; string sOrigId = ( nCopyId - nProcId > 0 ? "+" : "") + ToString( nCopyId - nProcId) ; m_pGDB->SetInfo( nProcId, IKEY_ORIGID, sOrigId) ; string sMainId = ( nProcId - nCopyId > 0 ? "+" : "") + ToString( nProcId - nCopyId) ; m_pGDB->SetInfo( nCopyId, IKEY_MAINID, sMainId) ; m_pGDB->SetMode( nCopyId, GDB_MD_HIDDEN) ; // se esiste anche seconda superficie, copio anche questa if ( pStm2 != nullptr) { int nCopy2Id = m_pGDB->AddGeoObj( GDB_ID_NULL, m_nProcsId, pStm2->Clone()) ; if ( nCopy2Id == GDB_ID_NULL) return false ; string sAuxId = ( nCopy2Id - nCopyId > 0 ? "+" : "") + ToString( nCopy2Id - nCopyId) ; m_pGDB->SetInfo( nCopyId, IKEY_AUXID, sAuxId) ; m_pGDB->SetMode( nCopy2Id, GDB_MD_HIDDEN) ; } // eseguo piccolo offset della curva per evitare problemi di sovrapposizioni OffsetCurve OffsCrv ; if ( ! OffsCrv.Make( pCrv, -50 * EPS_SMALL, ICurve::OFF_EXTEND) || OffsCrv.GetCurveCount() == 0) { return false ; } PtrOwner pCopyCrv( OffsCrv.GetLongerCurve()) ; // eseguo il trim return ( pStm->GeneralizedCut( *pCopyCrv, false) && ( pStm2 == nullptr || pStm2->GeneralizedCut( *pCopyCrv, false))) ; } //---------------------------------------------------------------------------- bool BtlGeom::AddShapeBTLX( const INTMATRIX& vFacesVertices, const PNTVECTOR& vPoints) { StmFromTriangleSoup StmFts ; if ( ! StmFts.Start()) { LOG_ERROR( GetEExLogger(), " Error reading Part Shape: StmFts.Start error") return false ; } for ( auto it = vFacesVertices.begin() ; it != vFacesVertices.end() ; it++) { INTVECTOR vVertices = *it ; if ( vVertices.size() < 3) { LOG_ERROR( GetEExLogger(), " Error reading Part Shape: Face not valid") return false ; } // creo il contorno della faccia PtrOwner pCurveCompo( CreateCurveComposite()) ; pCurveCompo->AddPoint( vPoints[vVertices[0]]) ; for ( size_t i = 1 ; i != vVertices.size() ; i++) pCurveCompo->AddLine( vPoints[vVertices[i]]) ; pCurveCompo->AddLine( vPoints[vVertices[0]]) ; PtrOwner pSurf( GetSurfTriMeshByFlatContour( pCurveCompo)) ; if ( ! IsNull( pSurf)) { // recupero tutti i triangoli Triangle3d Tria ; int nT = pSurf->GetFirstTriangle( Tria) ; while ( nT != SVT_NULL) { // inserisco il triangolo nella nuova superficie StmFts.AddTriangle( Tria) ; // passo al triangolo successivo nT = pSurf->GetNextTriangle( nT, Tria) ; } } } if ( ! StmFts.End()) { LOG_ERROR( GetEExLogger(), " Error reading Part Shape: StmFts.End error") return false ; } PtrOwner pShape( StmFts.GetSurf()) ; int nId = m_pGDB->AddGeoObj( GDB_ID_NULL, m_nPartId + 3, Release( pShape)) ; // salvo in outline if ( nId == GDB_ID_NULL) return false ; m_pGDB->SetName( nId, OL_SHAPE_NAME) ; m_pGDB->SetMaterial( nId, m_OutsCol) ; m_pGDB->SetStatus( nId, GDB_ST_ON) ; return true ; }