Files
EgtExchange/BtlGeomOutline.cpp
T
Dario Sassi 1acfbaba22 EgtExchange 1.6p1 :
- piccole migliorie.
2016-04-13 06:29:08 +00:00

523 lines
19 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().nFlag != 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( GetSurfFlatRegion( 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().nFlag != 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( GetSurfFlatRegion( 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 ;
// 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
if ( ! RemoveDanglingFace( 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 true ;
}
//----------------------------------------------------------------------------
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 ( PointInPlaneApprox( ptP1, plFace) && PointInPlaneApprox( ptP2, plFace)) ;
}
//----------------------------------------------------------------------------
bool
BtlGeom::RemoveDanglingFace( const ICURVEPVECTOR vCrvP[], ISurfTriMesh* pStm)
{
// vettore con flag di interessamento faccia
bool bInFace[SIDE_NBR] ;
for ( int i = BTL_SIDE_FRONT ; i <= BTL_SIDE_LEFT ; ++ i)
bInFace[i-1] = ( vCrvP[i-1].size() > 0) ;
// prima normale alla faccia
Vector3d vtN ;
if ( ! pStm->GetFacetNormal( 0, vtN))
return false ;
// verifico facce 5 e 6
if ( ( bInFace[1-1] && bInFace[2-1]) || ( bInFace[1-1] && bInFace[3-1]) ||
( bInFace[1-1] && bInFace[4-1]) || ( bInFace[2-1] && bInFace[3-1]) ||
( bInFace[2-1] && bInFace[4-1]) || ( bInFace[3-1] && bInFace[4-1])) {
if ( ! bInFace[5-1] && vtN.x > 0) {
// cancello la regione della faccia
int nRegId = GetFaceRegion( 5) ;
m_pGDB->Erase( nRegId) ;
}
else if ( ! bInFace[6-1] && vtN.x < 0) {
// cancello la regione della faccia
int nRegId = GetFaceRegion( 6) ;
m_pGDB->Erase( nRegId) ;
}
}
// verifico facce 1 e 3
if ( ( bInFace[2-1] && bInFace[4-1]) || ( bInFace[2-1] && bInFace[5-1]) ||
( bInFace[2-1] && bInFace[6-1]) || ( bInFace[4-1] && bInFace[5-1]) ||
( bInFace[4-1] && bInFace[6-1]) || ( bInFace[5-1] && bInFace[6-1])) {
if ( ! bInFace[1-1] && vtN.y < 0) {
// cancello la regione della faccia
int nRegId = GetFaceRegion( 1) ;
m_pGDB->Erase( nRegId) ;
}
else if ( ! bInFace[3-1] && vtN.y > 0) {
// cancello la regione della faccia
int nRegId = GetFaceRegion( 3) ;
m_pGDB->Erase( nRegId) ;
}
}
// verifico facce 2 e 4
if ( ( bInFace[1-1] && bInFace[3-1]) || ( bInFace[1-1] && bInFace[5-1]) ||
( bInFace[1-1] && bInFace[6-1]) || ( bInFace[3-1] && bInFace[5-1]) ||
( bInFace[3-1] && bInFace[6-1]) || ( bInFace[5-1] && bInFace[6-1])) {
if ( ! bInFace[2-1] && vtN.z < 0) {
// cancello la regione della faccia
int nRegId = GetFaceRegion( 2) ;
m_pGDB->Erase( nRegId) ;
}
else if ( ! bInFace[4-1] && vtN.z > 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) ;
// 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()) {
// intersezione della curva col contorno
IntersCurveCurve intCC( *pCrvCompo, *pFaceCnt) ;
int nIntCount = intCC.GetIntersCount() ;
if ( nIntCount < 2)
continue ;
IntCrvCrvInfo iccInfo ;
intCC.GetIntCrvCrvInfo( 0, iccInfo) ;
double dParEnd = iccInfo.IciB[0].dU ;
intCC.GetIntCrvCrvInfo( nIntCount - 1, iccInfo) ;
double dParStart = iccInfo.IciB[0].dU ;
// recupero parte del contorno tra intersezione fine e intersezione inizio
PtrOwner<ICurve> pTmpCrv( pFaceCnt->CopyParamRange( dParStart, dParEnd)) ;
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)) ;
// se la regione sottrazione totale è nulla, la assegno
if ( IsNull( pSubReg))
pSubReg.Set( SfrCntr.GetSurf()) ;
// altrimenti la interseco
else {
PtrOwner<ISurfFlatRegion> pSfrReg(SfrCntr.GetSurf()) ;
if ( IsNull( pSfrReg))
continue ;
pSubReg->Intersect( *pSfrReg) ;
}
}
// se esiste regione sottrazione, la tolgo dalla regione della faccia
if ( ! IsNull( pSubReg)) {
// sottraggo
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) ;
}