Files
EgtExchange/BtlGeomOutline.cpp
T
Dario Sassi df864c93a8 EgtExchange 2.7k1 :
- adattamenti e ricompilazione per passaggio a C++ 20
2025-11-01 17:34:12 +01:00

1429 lines
54 KiB
C++

//----------------------------------------------------------------------------
// 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<ICurveComposite> 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<ISurfTriMesh> 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<ISurfTriMesh> 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<ICurveComposite> 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<ISurfTriMesh> 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<ICurveComposite> 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<ISurfTriMesh> 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<ISurfTriMesh> 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<ICurveComposite> 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<ISurfTriMesh> 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 e abilitato, nascondo Outline
int nDO ;
int nShapeId = m_pGDB->GetFirstNameInGroup( m_nOutsId, OL_SHAPE_NAME) ;
if ( nShapeId != GDB_ID_NULL && m_pGDB->GetInfo( nShapeId, IKEY_DO, nDO) && nDO != 0) {
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<ISurfFlatRegion> 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<ISurfFlatRegion> pSfr1 ;
PtrOwner<ISurfFlatRegion> pSfr2 ;
// dai contorni della superficie
POLYLINEVECTOR vPL ;
bool bOk = pStm->GetLoops( vPL) && vPL.size() == 2 ;
if ( bOk) {
PtrOwner<ICurveComposite> pLoop1( CreateCurveComposite()) ;
PtrOwner<ISurfFlatRegion> pMySfr1( CreateSurfFlatRegion()) ;
bOk = ( ! IsNull( pLoop1) && ! IsNull( pMySfr1) && pLoop1->FromPolyLine( vPL[0]) && pMySfr1->AddExtLoop( Release( pLoop1))) ;
bOk = bOk && pMySfr1->Invert() ;
PtrOwner<ICurveComposite> pLoop2( CreateCurveComposite()) ;
PtrOwner<ISurfFlatRegion> 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<ICurveComposite> pCrvCompo( ( pCrvAux != nullptr ? pCrvAux->Clone() : nullptr)) ;
if ( pCrvCompo == nullptr)
return false ;
// Creo le regioni sopra e sotto
pCrvCompo->Invert() ;
PtrOwner<ISurfFlatRegion> pSfr1( CreateSurfFlatRegion()) ;
if ( IsNull( pSfr1) || ! pSfr1->AddExtLoop( Release( pCrvCompo)))
return false ;
PtrOwner<ISurfFlatRegion> 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<ISurfTriMesh> 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<ICurveLine> 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<ISurfFlatRegion> pSubReg ;
// recupero il riferimento della faccia
Frame3d frFace = GetSideFrame( nSide) ;
// recupero il contorno della faccia nel suo proprio riferimento
PtrOwner<ICurve> 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, ssize( vCrvP)) ;
for ( int i = 0 ; i < ssize( vCrvP) ; ++ 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<ICurveComposite> pCrvCompo( CreateCurveComposite()) ;
if ( IsNull( pCrvCompo))
return false ;
// recupero le curve semplici e le inserisco nella curva composita
for ( int i = 0 ; i < ssize( vId2s) ; ++ 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<ICurve> 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<ISurfFlatRegion> 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<ISurfFlatRegion> 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<ISurfFlatRegion> 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<ICurveComposite> 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<ICurveLine> pRay( CreateCurveLine()) ;
if ( IsNull( pRay) || ! pRay->SetPVL( ptP, vtDir, dL + dW))
return false ;
// Recupero il contorno della faccia
PtrOwner<ICurve> 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<ICurve> 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<ICurveComposite> pCurveCompo( CreateCurveComposite()) ;
pCurveCompo->AddPoint( vPoints[vVertices[0]]) ;
for ( int i = 1 ; i < ssize( vVertices) ; i++)
pCurveCompo->AddLine( vPoints[vVertices[i]]) ;
pCurveCompo->AddLine( vPoints[vVertices[0]]) ;
// creo la faccia e recupero i suoi triangoli
PtrOwner<ISurfTriMesh> pSurf( GetSurfTriMeshByFlatContour( pCurveCompo)) ;
if ( ! IsNull( pSurf))
StmFts.AddSurfTriMesh( *pSurf) ;
}
if ( ! StmFts.End()) {
LOG_ERROR( GetEExLogger(), " Error reading Part Shape: StmFts.End error")
return false ;
}
PtrOwner<ISurfTriMesh> pShape( StmFts.GetSurf()) ;
int nId = m_pGDB->AddGeoObj( GDB_ID_NULL, m_nOutsId, Release( pShape)) ;
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_OFF) ;
m_pGDB->SetInfo( nId, IKEY_DO, 0) ;
return true ;
}