07c3fedfe5
- correzione in lettura STL ASCII con più spazi - correzioni e migliorie varie in lettura BTL.
701 lines
26 KiB
C++
701 lines
26 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/EGkSfrCreate.h"
|
|
#include "/EgtDev/Include/EGkStmStandard.h"
|
|
#include "/EgtDev/Include/EGkStmFromCurves.h"
|
|
#include "/EgtDev/Include/EGkExtText.h"
|
|
#include "/EgtDev/Include/EGnStringUtils.h"
|
|
#include "/EgtDev/Include/EgtPointerOwner.h"
|
|
|
|
using namespace std ;
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
BtlGeom::AddPartOutline( int nSide, const FCEDEQUE& dqFce)
|
|
{
|
|
// verifico esistenza pezzo
|
|
if ( m_nBoxId == GDB_ID_NULL)
|
|
return false ;
|
|
// verifico validità faccia
|
|
if ( ! IsTrueSide( nSide))
|
|
return false ;
|
|
// verifico siano definiti almeno 4 punti (triangolo)
|
|
if ( dqFce.size() < 4)
|
|
return false ;
|
|
// verifico che primo e ultimo punto coincidano
|
|
if ( ! AreSamePointApprox( dqFce.front().ptP, dqFce.back().ptP))
|
|
return false ;
|
|
// verifico che sia un percorso semplice
|
|
if ( dqFce.front().nType != FreeContourEnt::START)
|
|
return false ;
|
|
// verifico non ci sia angolo di sbandamento
|
|
for ( auto& Fce : dqFce) {
|
|
if ( fabs( Fce.dAng) > EPS_ANG_SMALL)
|
|
return false ;
|
|
}
|
|
// costruisco il percorso di contorno
|
|
PtrOwner<ICurveComposite> pCrvCompo( CurveFromFces( dqFce)) ;
|
|
if ( IsNull( pCrvCompo))
|
|
return false ;
|
|
// aggiusto orientamento affinché sia antiorario
|
|
double dArea ;
|
|
pCrvCompo->GetAreaXY( dArea) ;
|
|
if ( dArea < 0)
|
|
pCrvCompo->Invert() ;
|
|
// Porto il percorso sul piano corretto
|
|
Frame3d frRef = GetSideFrame( nSide) ;
|
|
pCrvCompo->ToGlob( frRef) ;
|
|
// Estrudo il contorno
|
|
Vector3d vtExtr = - frRef.VersZ() * GetSideHeight( nSide) ;
|
|
PtrOwner<ISurfTriMesh> pStm( GetSurfTriMeshByExtrusion( pCrvCompo, vtExtr, false, EPS_SMALL)) ;
|
|
if ( IsNull( pStm))
|
|
return false ;
|
|
pStm->Invert() ;
|
|
// Inserisco la superficie nel layer Outline
|
|
int nId = m_pGDB->AddGeoObj( GDB_ID_NULL, m_nOutsId, Release( pStm)) ;
|
|
if ( nId == GDB_ID_NULL)
|
|
return false ;
|
|
m_pGDB->SetName( nId, GetOutlineOutName( nSide)) ;
|
|
// Creo le regioni sopra e sotto
|
|
PtrOwner<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) ;
|
|
// Inserisco le regioni nel layer Outline
|
|
int nId1 = m_pGDB->AddGeoObj( GDB_ID_NULL, m_nOutsId, Release( pSfr1)) ;
|
|
if ( nId1 == GDB_ID_NULL)
|
|
return false ;
|
|
m_pGDB->SetName( nId1, GetOutlineTopName( nSide)) ;
|
|
m_pGDB->SetInfo( nId1, IKEY_OTL_SIDE, nSide) ;
|
|
int nId2 = m_pGDB->AddGeoObj( GDB_ID_NULL, m_nOutsId, Release( pSfr2)) ;
|
|
if ( nId2 == GDB_ID_NULL)
|
|
return false ;
|
|
m_pGDB->SetName( nId2, GetOutlineBottomName( nSide)) ;
|
|
m_pGDB->SetInfo( nId2, IKEY_OTL_SIDE, GetOppositeSide( nSide)) ;
|
|
// nascondo il box
|
|
m_pGDB->SetStatus( m_nBoxId, GDB_ST_OFF) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
BtlGeom::AddPartAperture( int nSide, const FCEDEQUE& dqFce)
|
|
{
|
|
// verifico esistenza pezzo
|
|
if ( m_nBoxId == GDB_ID_NULL)
|
|
return false ;
|
|
// verifico validità faccia
|
|
if ( ! IsTrueSide( nSide))
|
|
return false ;
|
|
// verifico siano definiti almeno 4 punti (triangolo)
|
|
if ( dqFce.size() < 4)
|
|
return false ;
|
|
// verifico che primo e ultimo punto coincidano
|
|
if ( ! AreSamePointApprox( dqFce.front().ptP, dqFce.back().ptP))
|
|
return false ;
|
|
// verifico che sia un percorso semplice
|
|
if ( dqFce.front().nType != FreeContourEnt::START)
|
|
return false ;
|
|
// verifico non ci sia angolo di sbandamento
|
|
for ( auto& Fce : dqFce) {
|
|
if ( fabs( Fce.dAng) > EPS_ANG_SMALL)
|
|
return false ;
|
|
}
|
|
// costruisco il percorso di contorno
|
|
PtrOwner<ICurveComposite> pCrvCompo( CurveFromFces( dqFce)) ;
|
|
if ( IsNull( pCrvCompo))
|
|
return false ;
|
|
// aggiusto orientamento affinché sia antiorario
|
|
double dArea ;
|
|
pCrvCompo->GetAreaXY( dArea) ;
|
|
if ( dArea < 0)
|
|
pCrvCompo->Invert() ;
|
|
// Porto il percorso sul piano corretto
|
|
Frame3d frRef = GetSideFrame( nSide) ;
|
|
pCrvCompo->ToGlob( frRef) ;
|
|
// Estrudo il contorno
|
|
Vector3d vtExtr = - frRef.VersZ() * GetSideHeight( nSide) ;
|
|
PtrOwner<ISurfTriMesh> pStm( GetSurfTriMeshByExtrusion( pCrvCompo, vtExtr, false, EPS_SMALL)) ;
|
|
if ( IsNull( pStm))
|
|
return false ;
|
|
// Inserisco la superficie nel layer Outline
|
|
int nId = m_pGDB->AddGeoObj( GDB_ID_NULL, m_nOutsId, Release( pStm)) ;
|
|
if ( nId == GDB_ID_NULL)
|
|
return false ;
|
|
m_pGDB->SetName( nId, GetOutlineApertureName( nSide)) ;
|
|
// Creo le regioni sopra e sotto
|
|
PtrOwner<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( m_pGDB->GetFirstNameInGroup( m_nOutsId, GetOutlineTopName( nSide)))) ;
|
|
if ( pSfrTop == nullptr)
|
|
return false ;
|
|
pSfrTop->Subtract( *pSfr1) ;
|
|
ISurfFlatRegion* pSfrBot = GetSurfFlatRegion( m_pGDB->GetGeoObj( m_pGDB->GetFirstNameInGroup( m_nOutsId, GetOutlineBottomName( nSide)))) ;
|
|
if ( pSfrBot == nullptr)
|
|
return false ;
|
|
pSfrBot->Subtract( *pSfr2) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
BtlGeom::AddPartStdOutline( void)
|
|
{
|
|
// verifico esistenza pezzo
|
|
if ( m_nBoxId == GDB_ID_NULL)
|
|
return false ;
|
|
// aggiungo le regioni delle faccie
|
|
for ( int nSide = BTL_SIDE_FRONT ; nSide <= BTL_SIDE_LEFT ; ++ nSide) {
|
|
PtrOwner<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) ;
|
|
}
|
|
// nascondo il box
|
|
m_pGDB->SetStatus( m_nBoxId, GDB_ST_OFF) ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
BtlGeom::UseProcessToTrimOutline( int nProcId)
|
|
{
|
|
// se non trim speciale per pareti...
|
|
if ( ! m_bSpecialTrim)
|
|
return true ;
|
|
// recupero il box della superficie
|
|
BBox3d b3Proc ;
|
|
Point3d ptMin, ptMax ;
|
|
if ( ! m_pGDB->GetLocalBBox( nProcId, b3Proc) || ! b3Proc.GetMinMax( ptMin, ptMax))
|
|
return true ;
|
|
// verifico rispetto allo spessore perpendicolare alla faccia maggiore
|
|
if ( m_vtDim.y > m_vtDim.z)
|
|
return ( ( ptMax.z - ptMin.z) > m_vtDim.z - 100 * EPS_SMALL) ;
|
|
else
|
|
return ( ( ptMax.y - ptMin.y) > m_vtDim.y - 100 * EPS_SMALL) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
BtlGeom::TrimOutline( int nProcSurfId)
|
|
{
|
|
// Recupero la superficie del processo di lavorazione
|
|
ISurfTriMesh* pStm = GetSurfTriMesh( m_pGDB->GetGeoObj( nProcSurfId)) ;
|
|
if ( pStm == nullptr)
|
|
return false ;
|
|
// 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 ;
|
|
ICURVEPVECTOR 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 eventuale faccia che rimarrebbe penzolante
|
|
int nCross ;
|
|
if ( IsCrossCut( vPL, nCross)) {
|
|
if ( ! RemoveDanglingFace( nCross, vCrvP, pStm))
|
|
bOk = false ;
|
|
}
|
|
// per ogni faccia
|
|
for ( int i = BTL_SIDE_FRONT ; i <= BTL_SIDE_LEFT ; ++ i) {
|
|
if ( ! AdjustOneOutlineFace( i, vCrvP[i-1]))
|
|
bOk = false ;
|
|
}
|
|
}
|
|
// Altrimenti, verifico se la superficie di lavorazione coincide con una faccia
|
|
else {
|
|
Point3d ptCen ;
|
|
Vector3d vtN ;
|
|
// se la superficie è formata da una sola faccetta
|
|
if ( pStm->GetFacetCount() == 1 && pStm->GetFacetCenter( 0, ptCen, vtN)) {
|
|
// per ogni faccia
|
|
for ( int i = BTL_SIDE_FRONT ; i <= BTL_SIDE_LEFT ; ++ i) {
|
|
// piano della faccia
|
|
Plane3d plFace = GetSidePlane( i) ;
|
|
// verifico se la faccetta coincide con la faccia
|
|
if ( PointInPlaneApprox( ptCen, plFace) && AreSameVectorApprox( vtN, plFace.vtN)) {
|
|
// cancello la regione della faccia
|
|
int nRegId = GetFaceRegion( i) ;
|
|
m_pGDB->Erase( nRegId) ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Pulisco il vettore delle curve
|
|
for ( int i = BTL_SIDE_FRONT ; i <= BTL_SIDE_LEFT ; ++ i) {
|
|
for ( auto& pCrv : vCrvP[i-1]) {
|
|
if ( pCrv != nullptr)
|
|
delete pCrv ;
|
|
pCrv = nullptr ;
|
|
}
|
|
}
|
|
|
|
return bOk ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
BtlGeom::GetLineInFace( const Point3d& ptP1, const Point3d& ptP2, int& nFace) const
|
|
{
|
|
// ciclo di verifica con le diverse facce
|
|
nFace = BTL_SIDE_NONE ;
|
|
for ( int i = BTL_SIDE_FRONT ; i <= BTL_SIDE_LEFT ; ++ i) {
|
|
// se sta sulla faccia
|
|
if ( IsLineOnFace( ptP1, ptP2, i)) {
|
|
// se appartiene anche ad altra faccia, è sul bordo comune e quindi non interna
|
|
if ( nFace != BTL_SIDE_NONE)
|
|
return false ;
|
|
// assegno la faccia
|
|
else
|
|
nFace = i ;
|
|
}
|
|
}
|
|
|
|
return ( nFace != BTL_SIDE_NONE) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
BtlGeom::IsLineOnFace( const Point3d& ptP1, const Point3d& ptP2, int nFace) const
|
|
{
|
|
// piano della faccia
|
|
Plane3d plFace = GetSidePlane( nFace) ;
|
|
// sulla faccia se i due punti appartengono alla faccia
|
|
return ( PointInPlaneEpsilon( ptP1, plFace, EPS_SMALL) && PointInPlaneEpsilon( ptP2, plFace, EPS_SMALL)) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
BtlGeom::IsCrossCut( const POLYLINEVECTOR& vPL, int& nCross) const
|
|
{
|
|
// 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) < EPS_SMALL && abs( ptP.z) < EPS_SMALL)
|
|
nCrossX |= 1 ;
|
|
if ( abs( ptP.y - m_vtDim.y) < EPS_SMALL && abs( ptP.z) < EPS_SMALL)
|
|
nCrossX |= 2 ;
|
|
if ( abs( ptP.y - m_vtDim.y) < EPS_SMALL && abs( ptP.z - m_vtDim.z) < EPS_SMALL)
|
|
nCrossX |= 4 ;
|
|
if ( abs( ptP.y) < EPS_SMALL && abs( ptP.z - m_vtDim.z) < EPS_SMALL)
|
|
nCrossX |= 8 ;
|
|
// verifica di appartenenza ad edge lungo Y
|
|
if ( abs( ptP.z) < EPS_SMALL && abs( ptP.x) < EPS_SMALL)
|
|
nCrossY |= 1 ;
|
|
if ( abs( ptP.z - m_vtDim.z) < EPS_SMALL && abs( ptP.x) < EPS_SMALL)
|
|
nCrossY |= 2 ;
|
|
if ( abs( ptP.z - m_vtDim.z) < EPS_SMALL && abs( ptP.x - m_vtDim.x) < EPS_SMALL)
|
|
nCrossY |= 4 ;
|
|
if ( abs( ptP.z) < EPS_SMALL && abs( ptP.x - m_vtDim.x) < EPS_SMALL)
|
|
nCrossY |= 8 ;
|
|
// verifica di appartenenza ad edge lungo Z
|
|
if ( abs( ptP.x) < EPS_SMALL && abs( ptP.y) < EPS_SMALL)
|
|
nCrossZ |= 1 ;
|
|
if ( abs( ptP.x - m_vtDim.x) < EPS_SMALL && abs( ptP.y) < EPS_SMALL)
|
|
nCrossZ |= 2 ;
|
|
if ( abs( ptP.x - m_vtDim.x) < EPS_SMALL && abs( ptP.y - m_vtDim.y) < EPS_SMALL)
|
|
nCrossZ |= 4 ;
|
|
if ( abs( ptP.x) < EPS_SMALL && abs( ptP.y - m_vtDim.y) < EPS_SMALL)
|
|
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 ICURVEPVECTOR 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 6 e 5
|
|
if ( ( nCross & CROSS_CUT_X) != 0) {
|
|
if ( vtN.x < - SIN_EPS_ANG_SMALL && vCrvP[6-1].size() == 0) {
|
|
// cancello la regione della faccia
|
|
int nRegId = GetFaceRegion( 6) ;
|
|
m_pGDB->Erase( nRegId) ;
|
|
}
|
|
else if ( vtN.x > SIN_EPS_ANG_SMALL && vCrvP[5-1].size() == 0) {
|
|
// cancello la regione della faccia
|
|
int nRegId = GetFaceRegion( 5) ;
|
|
m_pGDB->Erase( nRegId) ;
|
|
}
|
|
}
|
|
// verifico facce 1 e 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 2 e 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, ICURVEPVECTOR& 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<ICurveComposite> 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
|
|
double dToler = 10 * EPS_SMALL ;
|
|
ChainCurves chainC ;
|
|
chainC.Init( false, dToler, 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<ICurveComposite> 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( vCrvP[j], true, dToler) ;
|
|
vCrvP[j] = nullptr ;
|
|
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( Release( 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( Release( pSubCopy)) ;
|
|
pSubReg->Add( *pSfrReg) ;
|
|
}
|
|
}
|
|
}
|
|
// se esiste regione sottrazione, la tolgo dalla regione della faccia
|
|
if ( ! IsNull( pSubReg)) {
|
|
// eseguo sottrazione
|
|
pFaceReg->Subtract( *pSubReg) ;
|
|
// se vuota, la elimino
|
|
if ( ! pFaceReg->IsValid())
|
|
m_pGDB->Erase( nRegId) ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int
|
|
BtlGeom::GetFaceRegion( int nSide)
|
|
{
|
|
int nId = m_pGDB->GetFirstInGroup( m_nOutsId) ;
|
|
while ( nId != GDB_ID_NULL) {
|
|
int nS ;
|
|
if ( m_pGDB->GetGeoType( nId) == SRF_FLATRGN &&
|
|
m_pGDB->GetInfo( nId, IKEY_OTL_SIDE, nS) && nS == nSide)
|
|
return nId ;
|
|
nId = m_pGDB->GetNext( nId) ;
|
|
}
|
|
return GDB_ID_NULL ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
ICurveComposite*
|
|
BtlGeom::GetFaceContour( int nSide)
|
|
{
|
|
// verifico validità indice di faccia
|
|
if ( nSide < BTL_SIDE_FRONT || nSide > BTL_SIDE_LEFT)
|
|
return nullptr ;
|
|
// creo il contorno antiorario
|
|
PolyLine PL ;
|
|
PL.AddUPoint( 0, ORIG) ;
|
|
PL.AddUPoint( 1, Point3d( GetSideLength( nSide), 0, 0)) ;
|
|
PL.AddUPoint( 2, Point3d( GetSideLength( nSide), GetSideWidth( nSide), 0)) ;
|
|
PL.AddUPoint( 3, Point3d( 0, GetSideWidth( nSide), 0)) ;
|
|
PL.AddUPoint( 4, ORIG) ;
|
|
// creo la curva composita
|
|
PtrOwner<ICurveComposite> pCrvCompo( CreateCurveComposite()) ;
|
|
if ( IsNull( pCrvCompo) || ! pCrvCompo->FromPolyLine( PL))
|
|
return nullptr ;
|
|
else
|
|
return Release( pCrvCompo) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
BtlGeom::IsPointOnFaceContour( const Point3d& ptP, bool bPtLocal, int nSide)
|
|
{
|
|
// Punto in riferimento faccia
|
|
Point3d ptPl = ptP ;
|
|
if ( ! bPtLocal)
|
|
ptPl.ToLoc( GetSideFrame( nSide)) ;
|
|
// Verifico se sta sul contorno
|
|
return ( abs( ptPl.x) < EPS_SMALL || abs( ptPl.x - GetSideLength( nSide)) < EPS_SMALL ||
|
|
abs( ptPl.y) < EPS_SMALL || abs( ptPl.y - GetSideWidth( nSide)) < EPS_SMALL) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
BtlGeom::IsPointNearFaceContour( const Point3d& ptP, bool bPtLocal, int nSide)
|
|
{
|
|
// Punto in riferimento faccia
|
|
Point3d ptPl = ptP ;
|
|
if ( ! bPtLocal)
|
|
ptPl.ToLoc( GetSideFrame( nSide)) ;
|
|
// Verifico se sta vicino al contorno o fuori
|
|
const double EPS_IN_NEAR = 0.2 ;
|
|
const double EPS_OUT_NEAR = 1.0 ;
|
|
double dL = GetSideLength( nSide) ;
|
|
double dW = GetSideWidth( nSide) ;
|
|
return ( ( ptPl.x > - EPS_OUT_NEAR && ptPl.x < EPS_IN_NEAR) ||
|
|
( ptPl.x > dL - EPS_IN_NEAR && ptPl.x < dL + EPS_OUT_NEAR) ||
|
|
( ptPl.y > - EPS_OUT_NEAR && ptPl.y < EPS_IN_NEAR) ||
|
|
( ptPl.y > dW - EPS_IN_NEAR && ptPl.y < dW + EPS_OUT_NEAR)) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
BtlGeom::SetPointOnFaceContour( Point3d& ptP, bool bPtLocal, int nSide)
|
|
{
|
|
// Punto in riferimento faccia
|
|
Point3d ptPl = ptP ;
|
|
if ( ! bPtLocal)
|
|
ptPl.ToLoc( GetSideFrame( nSide)) ;
|
|
// Dimensioni della faccia
|
|
double dL = GetSideLength( nSide) ;
|
|
double dW = GetSideWidth( nSide) ;
|
|
// Sistemazioni per punto esterno
|
|
if ( ptPl.x < 0)
|
|
ptPl.x = 0 ;
|
|
else if ( ptPl.x > dL)
|
|
ptPl.x = dL ;
|
|
if ( ptPl.y < 0)
|
|
ptPl.y = 0 ;
|
|
else if ( ptPl.y > dW)
|
|
ptPl.y = dW ;
|
|
// Sistemazioni per punto interno
|
|
double vDist[4] = { abs( ptPl.x), abs( ptPl.x - dL), abs( ptPl.y), abs( ptPl.y - dW)} ;
|
|
int nMinDistSide = 0 ;
|
|
for ( int i = 1 ; i < 4 ; ++i) {
|
|
if ( vDist[i] < vDist[nMinDistSide])
|
|
nMinDistSide = i ;
|
|
}
|
|
switch ( nMinDistSide) {
|
|
case 0 : ptPl.x = 0 ; break ;
|
|
case 1 : ptPl.x = dL ; break ;
|
|
case 2 : ptPl.y = 0 ; break ;
|
|
case 3 : ptPl.y = dW ; break ;
|
|
}
|
|
// Riporto punto nel suo riferimento
|
|
if ( ! bPtLocal)
|
|
ptPl.ToGlob( GetSideFrame( nSide)) ;
|
|
ptP = ptPl ;
|
|
return true ;
|
|
} |