b709776f5f
- piccole mdofiche poco più che estetiche.
498 lines
17 KiB
C++
498 lines
17 KiB
C++
//----------------------------------------------------------------------------
|
|
// EgalTech 2015-2015
|
|
//----------------------------------------------------------------------------
|
|
// File : SurfFlatRegionBooleans.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* pSfrOther = GetBasicSurfFlatRegion( &Other) ;
|
|
if ( pSfrOther == nullptr)
|
|
return false ;
|
|
const SurfFlatRegion& SfrOther = *pSfrOther ;
|
|
|
|
// verifico che le due regioni giacciano in piani paralleli
|
|
if ( ! AreSameVectorApprox( m_frF.VersZ(), SfrOther.m_frF.VersZ()))
|
|
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) ;
|
|
// calcolo vettore di movimento per portarle nel piano XY (Z=0)
|
|
Vector3d vtMove( 0, 0, - frTransf.Orig().z) ;
|
|
if ( ! vtMove.IsSmall()) {
|
|
for ( auto& pLoop : pCopyOth->m_vpLoop)
|
|
pLoop->Translate( vtMove) ;
|
|
}
|
|
// assegno il nuovo riferimento
|
|
pCopyOth->m_frF = m_frF ;
|
|
// aggiorno puntatore della copia in lavoro
|
|
pOther = 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( vpCurve) ;
|
|
MyTestAndDelete( vpLoop) ;
|
|
return false ;
|
|
}
|
|
|
|
// creo una nuova regione a partire da questi loop
|
|
PtrOwner<SurfFlatRegion> pSfr( MyNewSurfFromLoops( vpLoop)) ;
|
|
if ( IsNull( pSfr)) {
|
|
MyTestAndDelete( vpCurve) ;
|
|
MyTestAndDelete( vpLoop) ;
|
|
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() ;
|
|
// imposto ricalcolo Voronoi
|
|
ResetVoronoiObject() ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfFlatRegion::Subtract( const ISurfFlatRegion& Other)
|
|
{
|
|
// converto l'altra regione nell'oggetto base
|
|
const SurfFlatRegion* pSfrOther = GetBasicSurfFlatRegion( &Other) ;
|
|
if ( pSfrOther == nullptr)
|
|
return false ;
|
|
const SurfFlatRegion& SfrOther = *pSfrOther ;
|
|
|
|
// verifico che le due regioni giacciano in piani paralleli
|
|
if ( ! AreSameVectorApprox( m_frF.VersZ(), SfrOther.m_frF.VersZ()))
|
|
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) ;
|
|
// calcolo vettore di movimento per portarle nel piano XY (Z=0)
|
|
Vector3d vtMove( 0, 0, - frTransf.Orig().z) ;
|
|
if ( ! vtMove.IsSmall()) {
|
|
for ( auto& pLoop : pCopyOth->m_vpLoop)
|
|
pLoop->Translate( vtMove) ;
|
|
}
|
|
// assegno il nuovo riferimento
|
|
pCopyOth->m_frF = m_frF ;
|
|
// aggiorno puntatore della copia in lavoro
|
|
pOther = 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( vpCurve) ;
|
|
MyTestAndDelete( vpLoop) ;
|
|
return false ;
|
|
}
|
|
|
|
// creo una nuova regione a partire da questi loop
|
|
PtrOwner<SurfFlatRegion> pSfr ;
|
|
if ( vpLoop.empty())
|
|
pSfr.Set( new( nothrow) SurfFlatRegion) ;
|
|
else
|
|
pSfr.Set( MyNewSurfFromLoops( vpLoop)) ;
|
|
if ( IsNull( pSfr)) {
|
|
MyTestAndDelete( vpCurve) ;
|
|
MyTestAndDelete( vpLoop) ;
|
|
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() ;
|
|
// imposto ricalcolo Voronoi
|
|
ResetVoronoiObject() ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfFlatRegion::Intersect( const ISurfFlatRegion& Other)
|
|
{
|
|
// converto l'altra regione nell'oggetto base
|
|
const SurfFlatRegion* pSfrOther = GetBasicSurfFlatRegion( &Other) ;
|
|
if ( pSfrOther == nullptr)
|
|
return false ;
|
|
const SurfFlatRegion& SfrOther = *pSfrOther ;
|
|
|
|
// verifico che le due regioni giacciano in piani paralleli
|
|
if ( ! AreSameVectorApprox( m_frF.VersZ(), SfrOther.m_frF.VersZ()))
|
|
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) ;
|
|
// calcolo vettore di movimento per portarle nel piano XY (Z=0)
|
|
Vector3d vtMove( 0, 0, - frTransf.Orig().z) ;
|
|
if ( ! vtMove.IsSmall()) {
|
|
for ( auto& pLoop : pCopyOth->m_vpLoop)
|
|
pLoop->Translate( vtMove) ;
|
|
}
|
|
// assegno il nuovo riferimento
|
|
pCopyOth->m_frF = m_frF ;
|
|
// aggiorno puntatore della copia in lavoro
|
|
pOther = 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( vpCurve) ;
|
|
MyTestAndDelete( vpLoop) ;
|
|
return false ;
|
|
}
|
|
|
|
// creo una nuova regione a partire da questi loop
|
|
PtrOwner<SurfFlatRegion> pSfr ;
|
|
if ( vpLoop.empty())
|
|
pSfr.Set( new( nothrow) SurfFlatRegion) ;
|
|
else
|
|
pSfr.Set( MyNewSurfFromLoops( vpLoop)) ;
|
|
if ( IsNull( pSfr)) {
|
|
MyTestAndDelete( vpCurve) ;
|
|
MyTestAndDelete( vpLoop) ;
|
|
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() ;
|
|
// imposto ricalcolo Voronoi
|
|
ResetVoronoiObject() ;
|
|
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, EPS_SMALL, ccClass))
|
|
return false ;
|
|
// creo intervalli validi, tenendo classificazioni ricevute
|
|
Intervals inOk1( EPS_PARAM), inOk2( EPS_PARAM) ;
|
|
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
|
|
double dToler = 5 * EPS_SMALL ;
|
|
ChainCurves chainC ;
|
|
chainC.Init( false, dToler, 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
|
|
bool bOk = pCrvCompo->AddCurve( vpCurve[i-1], true, dToler) ;
|
|
vpCurve[i-1] = nullptr ;
|
|
if ( ! bOk)
|
|
return false ;
|
|
}
|
|
|
|
// pulisco
|
|
pCrvCompo->RemoveSmallParts( 2 * EPS_SMALL, EPS_ANG_SMALL) ;
|
|
// aggiorno il nuovo punto vicino
|
|
if ( pCrvCompo->GetCurveCount() > 0)
|
|
pCrvCompo->GetEndPoint( ptNearStart) ;
|
|
// se lunghezza curva inferiore a 2 volte la tolleranza, la salto
|
|
double dCrvLen ;
|
|
if ( ! pCrvCompo->GetLength( dCrvLen) || dCrvLen < 2. * dToler)
|
|
continue ;
|
|
// se curva chiusa entro 3 volte la tolleranza ma considerata aperta, la chiudo bene
|
|
Point3d ptStart, ptEnd ;
|
|
if ( pCrvCompo->GetStartPoint( ptStart) &&
|
|
pCrvCompo->GetEndPoint( ptEnd) &&
|
|
AreSamePointEpsilon( ptStart, ptEnd, 3 * dToler) &&
|
|
! AreSamePointApprox( ptStart, ptEnd)) {
|
|
// porto i punti iniziale e finale a coincidere esattamente
|
|
Point3d ptNew = Media( ptStart, ptEnd) ;
|
|
pCrvCompo->ModifyStart( ptNew) ;
|
|
pCrvCompo->ModifyEnd( ptNew) ;
|
|
}
|
|
// 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 pair<int,double> INDAREA ; // coppia indice, area
|
|
typedef vector<INDAREA> INDAREAVECTOR ; // vettore di coppie indice, area
|
|
INDAREAVECTOR vArea ;
|
|
vArea.reserve( vpLoop.size()) ;
|
|
for ( int i = 0 ; i < int( vpLoop.size()) ;) {
|
|
double dArea ;
|
|
if ( ! vpLoop[i]->GetAreaXY( dArea))
|
|
return nullptr ;
|
|
if ( abs( dArea) > SQ_EPS_SMALL) {
|
|
vArea.emplace_back( i, dArea) ;
|
|
++ i ;
|
|
}
|
|
else {
|
|
delete vpLoop[i] ;
|
|
vpLoop.erase( vpLoop.begin() + i) ;
|
|
}
|
|
}
|
|
// 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 ( abs( 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, EPS_SMALL, ccClass) ||
|
|
ccClass.empty() || ccClass[0].nClass != CRVC_IN)
|
|
continue ;
|
|
// lo inserisco
|
|
if ( pSfr->MyAddIntLoop( vpLoop[l], -1)) {
|
|
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 ;
|
|
}
|