EgtGeomKernel 1.6h4 :
- aggiunto metodo GetCrossOrOverlapIntersCount a SelfIntersCurve - aggiunti metodi GetCrossIntersCount e GetCrossOrOverlapIntersCount a IntersCurveCurve - allentati controlli sui loop delle regioni, ora possono toccarsi ma non attraversarsi in punti isolati - aggiunte funzioni per operazioni booleante tra regioni Add, Subtract e Intersect.
This commit is contained in:
@@ -0,0 +1,426 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// EgalTech 2015-2015
|
||||
//----------------------------------------------------------------------------
|
||||
// File : SurfFlatRegion.cpp Data : 18.08.15 Versione : 1.6h4
|
||||
// Contenuto : Implementazione delle funzioni booleane per SurfFlatRegion.
|
||||
//
|
||||
//
|
||||
//
|
||||
// Modifiche : 18.08.15 DS Creazione modulo.
|
||||
//
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
//--------------------------- Include ----------------------------------------
|
||||
#include "stdafx.h"
|
||||
#include "SurfFlatRegion.h"
|
||||
#include "CurveComposite.h"
|
||||
#include "GeoConst.h"
|
||||
#include "/EgtDev/Include/EGkChainCurves.h"
|
||||
#include "/EgtDev/Include/EGkIntervals.h"
|
||||
#include "/EgtDev/Include/EgtPointerOwner.h"
|
||||
|
||||
using namespace std ;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
SurfFlatRegion::Add( const ISurfFlatRegion& Other)
|
||||
{
|
||||
// converto l'altra regione nell'oggetto base
|
||||
const SurfFlatRegion& SfrOther = dynamic_cast<const SurfFlatRegion&>( Other) ;
|
||||
if ( &SfrOther == nullptr)
|
||||
return false ;
|
||||
|
||||
// verifico che le due regioni giacciano nello stesso piano
|
||||
if ( ! AreSameVectorApprox( m_frF.VersZ(), SfrOther.m_frF.VersZ()) ||
|
||||
fabs( ( m_frF.Orig() - SfrOther.m_frF.Orig()) * m_frF.VersZ()) > EPS_SMALL)
|
||||
return false ;
|
||||
|
||||
// gestione eventuale copia dell'altra per trasformare il riferimento
|
||||
const SurfFlatRegion* pOther = &SfrOther ;
|
||||
PtrOwner<SurfFlatRegion> pCopyOth ;
|
||||
// se riferimenti intrinseci diversi, la trasformo
|
||||
if ( ! AreSameFrame( m_frF, SfrOther.m_frF)) {
|
||||
// creo la copia
|
||||
pCopyOth.Set( SfrOther.Clone()) ;
|
||||
if ( IsNull( pCopyOth))
|
||||
return false ;
|
||||
// calcolo riferimento di traformazione
|
||||
Frame3d frTransf = pCopyOth->m_frF ;
|
||||
frTransf.ToLoc( m_frF) ;
|
||||
// trasformo le curve
|
||||
for ( auto& pLoop : pCopyOth->m_vpLoop)
|
||||
pLoop->ToGlob( frTransf) ;
|
||||
// assegno il nuovo riferimento
|
||||
pCopyOth->m_frF = m_frF ;
|
||||
// aggiorno puntatore della copia in lavoro
|
||||
pOther = Get( pCopyOth) ;
|
||||
}
|
||||
|
||||
// vettore con curve utili da entrambe le regioni
|
||||
PCRV_DEQUE vpCurve ;
|
||||
if ( ! MySelectCurves( m_vpLoop, *pOther, CRVC_OUT, false, CRVC_ON_P, false, vpCurve) ||
|
||||
! MySelectCurves( pOther->m_vpLoop, *this, CRVC_OUT, false, CRVC_NULL, false, vpCurve)) {
|
||||
MyTestAndDelete( vpCurve) ;
|
||||
return false ;
|
||||
}
|
||||
|
||||
// vettore con curve concatenate che sono i contorni del risultato
|
||||
PCRV_DEQUE vpLoop ;
|
||||
// concateno e verifico di aver usato tutte le curve
|
||||
if ( ! MyChainCurves( vpCurve, vpLoop) || ! MyTestAndDelete( vpCurve)) {
|
||||
MyTestAndDelete( vpLoop) ;
|
||||
return false ;
|
||||
}
|
||||
|
||||
// creo una nuova regione a partire da questi loop
|
||||
PtrOwner<SurfFlatRegion> pSfr( MyNewSurfFromLoops( vpLoop)) ;
|
||||
if ( IsNull( pSfr))
|
||||
return false ;
|
||||
|
||||
// pulisco la superficie corrente
|
||||
for ( auto& pLoop : m_vpLoop)
|
||||
delete pLoop ;
|
||||
m_vpLoop.clear() ;
|
||||
|
||||
// sposto i dati della nuova superficie in quella corrente
|
||||
m_vExtInd = pSfr->m_vExtInd ;
|
||||
m_vpLoop = pSfr->m_vpLoop ;
|
||||
for ( auto& pLoop : pSfr->m_vpLoop)
|
||||
pLoop = nullptr ;
|
||||
m_nStatus = pSfr->m_nStatus ;
|
||||
|
||||
// imposto ricalcolo della grafica
|
||||
ResetAuxSurf() ;
|
||||
m_OGrMgr.Reset() ;
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
SurfFlatRegion::Subtract( const ISurfFlatRegion& Other)
|
||||
{
|
||||
// converto l'altra regione nell'oggetto base
|
||||
const SurfFlatRegion& SfrOther = dynamic_cast<const SurfFlatRegion&>( Other) ;
|
||||
if ( &SfrOther == nullptr)
|
||||
return false ;
|
||||
|
||||
// verifico che le due regioni giacciano nello stesso piano
|
||||
if ( ! AreSameVectorApprox( m_frF.VersZ(), SfrOther.m_frF.VersZ()) ||
|
||||
fabs( ( m_frF.Orig() - SfrOther.m_frF.Orig()) * m_frF.VersZ()) > EPS_SMALL)
|
||||
return false ;
|
||||
|
||||
// gestione eventuale copia dell'altra per trasformare il riferimento
|
||||
const SurfFlatRegion* pOther = &SfrOther ;
|
||||
PtrOwner<SurfFlatRegion> pCopyOth ;
|
||||
// se riferimenti intrinseci diversi, la trasformo
|
||||
if ( ! AreSameFrame( m_frF, SfrOther.m_frF)) {
|
||||
// creo la copia
|
||||
pCopyOth.Set( SfrOther.Clone()) ;
|
||||
if ( IsNull( pCopyOth))
|
||||
return false ;
|
||||
// calcolo riferimento di traformazione
|
||||
Frame3d frTransf = pCopyOth->m_frF ;
|
||||
frTransf.ToLoc( m_frF) ;
|
||||
// trasformo le curve
|
||||
for ( auto& pLoop : pCopyOth->m_vpLoop)
|
||||
pLoop->ToGlob( frTransf) ;
|
||||
// assegno il nuovo riferimento
|
||||
pCopyOth->m_frF = m_frF ;
|
||||
// aggiorno puntatore della copia in lavoro
|
||||
pOther = Get( pCopyOth) ;
|
||||
}
|
||||
|
||||
// vettore con curve utili da entrambe le regioni
|
||||
PCRV_DEQUE vpCurve ;
|
||||
if ( ! MySelectCurves( m_vpLoop, *pOther, CRVC_OUT, false, CRVC_ON_M, false, vpCurve) ||
|
||||
! MySelectCurves( pOther->m_vpLoop, *this, CRVC_IN, true, CRVC_NULL, false, vpCurve)) {
|
||||
MyTestAndDelete( vpCurve) ;
|
||||
return false ;
|
||||
}
|
||||
|
||||
// vettore con curve concatenate che sono i contorni del risultato
|
||||
PCRV_DEQUE vpLoop ;
|
||||
// concateno e verifico di aver usato tutte le curve
|
||||
if ( ! MyChainCurves( vpCurve, vpLoop) || ! MyTestAndDelete( vpCurve)) {
|
||||
MyTestAndDelete( vpLoop) ;
|
||||
return false ;
|
||||
}
|
||||
|
||||
// creo una nuova regione a partire da questi loop
|
||||
PtrOwner<SurfFlatRegion> pSfr( MyNewSurfFromLoops( vpLoop)) ;
|
||||
if ( IsNull( pSfr))
|
||||
return false ;
|
||||
|
||||
// pulisco la superficie corrente
|
||||
for ( auto& pLoop : m_vpLoop)
|
||||
delete pLoop ;
|
||||
m_vpLoop.clear() ;
|
||||
|
||||
// sposto i dati della nuova superficie in quella corrente
|
||||
m_vExtInd = pSfr->m_vExtInd ;
|
||||
m_vpLoop = pSfr->m_vpLoop ;
|
||||
for ( auto& pLoop : pSfr->m_vpLoop)
|
||||
pLoop = nullptr ;
|
||||
m_nStatus = pSfr->m_nStatus ;
|
||||
|
||||
// imposto ricalcolo della grafica
|
||||
ResetAuxSurf() ;
|
||||
m_OGrMgr.Reset() ;
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
SurfFlatRegion::Intersect( const ISurfFlatRegion& Other)
|
||||
{
|
||||
// converto l'altra regione nell'oggetto base
|
||||
const SurfFlatRegion& SfrOther = dynamic_cast<const SurfFlatRegion&>( Other) ;
|
||||
if ( &SfrOther == nullptr)
|
||||
return false ;
|
||||
|
||||
// verifico che le due regioni giacciano nello stesso piano
|
||||
if ( ! AreSameVectorApprox( m_frF.VersZ(), SfrOther.m_frF.VersZ()) ||
|
||||
fabs( ( m_frF.Orig() - SfrOther.m_frF.Orig()) * m_frF.VersZ()) > EPS_SMALL)
|
||||
return false ;
|
||||
|
||||
// gestione eventuale copia dell'altra per trasformare il riferimento
|
||||
const SurfFlatRegion* pOther = &SfrOther ;
|
||||
PtrOwner<SurfFlatRegion> pCopyOth ;
|
||||
// se riferimenti intrinseci diversi, la trasformo
|
||||
if ( ! AreSameFrame( m_frF, SfrOther.m_frF)) {
|
||||
// creo la copia
|
||||
pCopyOth.Set( SfrOther.Clone()) ;
|
||||
if ( IsNull( pCopyOth))
|
||||
return false ;
|
||||
// calcolo riferimento di traformazione
|
||||
Frame3d frTransf = pCopyOth->m_frF ;
|
||||
frTransf.ToLoc( m_frF) ;
|
||||
// trasformo le curve
|
||||
for ( auto& pLoop : pCopyOth->m_vpLoop)
|
||||
pLoop->ToGlob( frTransf) ;
|
||||
// assegno il nuovo riferimento
|
||||
pCopyOth->m_frF = m_frF ;
|
||||
// aggiorno puntatore della copia in lavoro
|
||||
pOther = Get( pCopyOth) ;
|
||||
}
|
||||
|
||||
// vettore con curve utili da entrambe le regioni
|
||||
PCRV_DEQUE vpCurve ;
|
||||
if ( ! MySelectCurves( m_vpLoop, *pOther, CRVC_IN, false, CRVC_ON_P, false, vpCurve) ||
|
||||
! MySelectCurves( pOther->m_vpLoop, *this, CRVC_IN, false, CRVC_NULL, false, vpCurve)) {
|
||||
MyTestAndDelete( vpCurve) ;
|
||||
return false ;
|
||||
}
|
||||
|
||||
// vettore con curve concatenate che sono i contorni del risultato
|
||||
PCRV_DEQUE vpLoop ;
|
||||
// concateno e verifico di aver usato tutte le curve
|
||||
if ( ! MyChainCurves( vpCurve, vpLoop) || ! MyTestAndDelete( vpCurve)) {
|
||||
MyTestAndDelete( vpLoop) ;
|
||||
return false ;
|
||||
}
|
||||
|
||||
// creo una nuova regione a partire da questi loop
|
||||
PtrOwner<SurfFlatRegion> pSfr( MyNewSurfFromLoops( vpLoop)) ;
|
||||
if ( IsNull( pSfr))
|
||||
return false ;
|
||||
|
||||
// pulisco la superficie corrente
|
||||
for ( auto& pLoop : m_vpLoop)
|
||||
delete pLoop ;
|
||||
m_vpLoop.clear() ;
|
||||
|
||||
// sposto i dati della nuova superficie in quella corrente
|
||||
m_vExtInd = pSfr->m_vExtInd ;
|
||||
m_vpLoop = pSfr->m_vpLoop ;
|
||||
for ( auto& pLoop : pSfr->m_vpLoop)
|
||||
pLoop = nullptr ;
|
||||
m_nStatus = pSfr->m_nStatus ;
|
||||
|
||||
// imposto ricalcolo della grafica
|
||||
ResetAuxSurf() ;
|
||||
m_OGrMgr.Reset() ;
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
SurfFlatRegion::MySelectCurves( const PCRV_DEQUE& vpLoop, const SurfFlatRegion& Other,
|
||||
int nType1, bool bInvert1, int nType2, bool bInvert2,
|
||||
PCRV_DEQUE& vpCurve)
|
||||
{
|
||||
// classifico le curve rispetto alla regione altra e copio le parti utili
|
||||
for ( auto& pLoop : vpLoop) {
|
||||
// eseguo classificazione
|
||||
CRVCVECTOR ccClass ;
|
||||
if ( ! Other.MyGetCurveClassification( *pLoop, ccClass))
|
||||
return false ;
|
||||
// creo intervalli validi, tenendo classificazioni ricevute
|
||||
Intervals inOk1, inOk2 ;
|
||||
for ( auto& ccOne : ccClass) {
|
||||
if ( nType1 != CRVC_NULL && ccOne.nClass == nType1)
|
||||
inOk1.Add( ccOne.dParE, ccOne.dParS) ;
|
||||
else if ( nType2 != CRVC_NULL && ccOne.nClass == nType2)
|
||||
inOk2.Add( ccOne.dParE, ccOne.dParS) ;
|
||||
}
|
||||
// copio queste parti
|
||||
double dParS, dParE ;
|
||||
bool bFound = inOk1.GetFirst( dParS, dParE) ;
|
||||
while ( bFound) {
|
||||
ICurve* pCrv = pLoop->CopyParamRange( dParS, dParE) ;
|
||||
if ( pCrv != nullptr) {
|
||||
if ( bInvert1)
|
||||
pCrv->Invert() ;
|
||||
vpCurve.push_back( pCrv) ;
|
||||
}
|
||||
bFound = inOk1.GetNext( dParS, dParE) ;
|
||||
}
|
||||
bFound = inOk2.GetFirst( dParS, dParE) ;
|
||||
while ( bFound) {
|
||||
ICurve* pCrv = pLoop->CopyParamRange( dParS, dParE) ;
|
||||
if ( pCrv != nullptr) {
|
||||
if ( bInvert2)
|
||||
pCrv->Invert() ;
|
||||
vpCurve.push_back( pCrv) ;
|
||||
}
|
||||
bFound = inOk2.GetNext( dParS, dParE) ;
|
||||
}
|
||||
}
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
SurfFlatRegion::MyChainCurves( PCRV_DEQUE& vpCurve, PCRV_DEQUE& vpLoop)
|
||||
{
|
||||
// concateno le curve
|
||||
ChainCurves chainC ;
|
||||
chainC.Init( false, 5 * EPS_SMALL, int( vpCurve.size())) ;
|
||||
for ( int i = 0 ; i < int( vpCurve.size()) ; ++i) {
|
||||
// recupero i dati della curva necessari al concatenamento e li assegno
|
||||
Point3d ptStart, ptEnd ;
|
||||
Vector3d vtStart, vtEnd ;
|
||||
if ( ! vpCurve[i]->GetStartPoint( ptStart) || ! vpCurve[i]->GetStartDir( vtStart) ||
|
||||
! vpCurve[i]->GetEndPoint( ptEnd) || ! vpCurve[i]->GetEndDir( vtEnd))
|
||||
return false ;
|
||||
if ( ! chainC.AddCurve( i + 1, ptStart, vtStart, ptEnd, vtEnd))
|
||||
return false ;
|
||||
}
|
||||
// recupero i percorsi concatenati
|
||||
INTVECTOR vIds ;
|
||||
Point3d ptNearStart ;
|
||||
while ( chainC.GetChainFromNear( ptNearStart, false, vIds)) {
|
||||
// creo una curva composita
|
||||
PtrOwner<CurveComposite> pCrvCompo( CreateBasicCurveComposite()) ;
|
||||
if ( IsNull( pCrvCompo))
|
||||
return false ;
|
||||
// recupero le curve e le inserisco nella nuova curva composita
|
||||
for ( auto i : vIds) {
|
||||
// la aggiungo alla curva composta
|
||||
if ( ! pCrvCompo->AddCurve( vpCurve[i-1], true, 5 * EPS_SMALL))
|
||||
return false ;
|
||||
vpCurve[i-1] = nullptr ;
|
||||
}
|
||||
// aggiorno il nuovo punto vicino
|
||||
if ( pCrvCompo->GetCurveCount() > 0)
|
||||
pCrvCompo->GetEndPoint( ptNearStart) ;
|
||||
// compatto la nuova curva
|
||||
pCrvCompo->MergeCurves( LIN_TOL_MIN, ANG_TOL_STD_DEG) ;
|
||||
// inserisco la curva composita nel gruppo destinazione
|
||||
if ( pCrvCompo->GetCurveCount() > 0) {
|
||||
vpLoop.push_back( ::Release( pCrvCompo)) ;
|
||||
}
|
||||
}
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
SurfFlatRegion*
|
||||
SurfFlatRegion::MyNewSurfFromLoops( PCRV_DEQUE& vpLoop)
|
||||
{
|
||||
// verifico che le curve siano chiuse e ne determino l'area
|
||||
typedef std::pair<int,double> INDAREA ; // coppia indice, area
|
||||
typedef std::vector<INDAREA> INDAREAVECTOR ; // vettore di coppie indice, area
|
||||
INDAREAVECTOR vArea ;
|
||||
vArea.reserve( vpLoop.size()) ;
|
||||
for ( int i = 0 ; i < int( vpLoop.size()) ; ++ i) {
|
||||
double dArea ;
|
||||
if ( ! vpLoop[i]->GetAreaXY( dArea))
|
||||
return nullptr ;
|
||||
vArea.emplace_back( i, dArea) ;
|
||||
}
|
||||
// ordino in senso decrescente sull'area
|
||||
sort( vArea.begin(), vArea.end(),
|
||||
[]( const INDAREA& a, const INDAREA&b) { return a.second > b.second ; }) ;
|
||||
|
||||
// determino quanti sono i nuovi cicli esterni (area positiva)
|
||||
int nLoopCount = int( vArea.size()) ;
|
||||
int nExtCount = 0 ;
|
||||
for ( int i = 0 ; i < nLoopCount ; ++ i) {
|
||||
if ( vArea[i].second > 0)
|
||||
++ nExtCount ;
|
||||
}
|
||||
|
||||
// creo una nuova regione
|
||||
PtrOwner<SurfFlatRegion> pSfr( CreateBasicSurfFlatRegion()) ;
|
||||
// ciclo sui loop esterni, all'indietro dal più piccolo al più grande
|
||||
for ( int i = nExtCount - 1 ; i >= 0 ; -- i) {
|
||||
// inserisco il nuovo esterno
|
||||
int j = vArea[i].first ;
|
||||
ICurve* pExtLoop = vpLoop[j] ;
|
||||
double dExtArea = vArea[i].second ;
|
||||
if ( pSfr->MyAddExtLoop( vpLoop[j])) {
|
||||
vpLoop[j] = nullptr ;
|
||||
vArea[i].first = - 1 ;
|
||||
}
|
||||
else
|
||||
continue ;
|
||||
// provo ad inserire i loop interni
|
||||
for ( int k = nExtCount ; k < nLoopCount ; ++ k) {
|
||||
// verifico non sia già stato inserito
|
||||
if ( vArea[k].first < 0)
|
||||
continue ;
|
||||
// salto gli interni con area maggiore dell'esterno corrente
|
||||
if ( fabs( vArea[k].second) > dExtArea)
|
||||
continue ;
|
||||
int l = vArea[k].first ;
|
||||
// verifico che sia interno all'esterno corrente
|
||||
CRVCVECTOR ccClass ;
|
||||
IntersCurveCurve ccInt( *vpLoop[l], *pExtLoop) ;
|
||||
if ( ccInt.GetCrossOrOverlapIntersCount() > 0 ||
|
||||
! ccInt.GetCurveClassification( 0, ccClass) ||
|
||||
ccClass.empty() || ccClass[0].nClass != CRVC_IN)
|
||||
continue ;
|
||||
// lo inserisco
|
||||
if ( pSfr->MyAddIntLoop( vpLoop[l])) {
|
||||
vpLoop[l] = nullptr ;
|
||||
vArea[k].first = - 1 ;
|
||||
}
|
||||
}
|
||||
}
|
||||
// se non valida, errore
|
||||
if ( ! pSfr->IsValid())
|
||||
return nullptr ;
|
||||
// verifico non siano rimasti loop inutilizzati
|
||||
if ( ! MyTestAndDelete( vpLoop))
|
||||
return nullptr ;
|
||||
// tutto bene, ritorno la superficie appena creata
|
||||
return Release( pSfr) ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
SurfFlatRegion::MyTestAndDelete( PCRV_DEQUE& vpCrv)
|
||||
{
|
||||
bool bOk = true ;
|
||||
for ( auto& pCrv : vpCrv) {
|
||||
if ( pCrv != nullptr) {
|
||||
delete pCrv ;
|
||||
pCrv = nullptr ;
|
||||
bOk = false ;
|
||||
}
|
||||
}
|
||||
return bOk ;
|
||||
}
|
||||
Reference in New Issue
Block a user