Files
EgtGeomKernel/SurfFlatRegion.cpp
T
DarioS 2ba32eb93c EgtGeomKernel :
- altre piccole ottimizzazioni nel cambio sistema di riferimento.
2023-07-27 10:23:03 +02:00

1649 lines
53 KiB
C++

//----------------------------------------------------------------------------
// EgalTech 2015-2015
//----------------------------------------------------------------------------
// File : SurfFlatRegion.cpp Data : 05.08.15 Versione : 1.6h2
// Contenuto : Implementazione della classe Surface FlatRegion.
//
//
//
// Modifiche : 05.08.15 DS Creazione modulo.
//
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "SurfFlatRegion.h"
#include "GeoObjFactory.h"
#include "NgeWriter.h"
#include "NgeReader.h"
#include "CurveAux.h"
#include "CurveComposite.h"
#include "CurveLine.h"
#include "AdjustLoops.h"
#include "GeoConst.h"
#include "/EgtDev/Include/EGkStringUtils3d.h"
#include "/EgtDev/Include/EGkUiUnits.h"
#include "/EgtDev/Include/EGkIntervals.h"
#include "/EgtDev/Include/EgtPointerOwner.h"
using namespace std ;
//----------------------------------------------------------------------------
GEOOBJ_REGISTER( SRF_FLATRGN, NGE_S_FRG, SurfFlatRegion) ;
//----------------------------------------------------------------------------
SurfFlatRegion::SurfFlatRegion( void)
: m_pSTM( nullptr), m_nStatus( TO_VERIFY)
{
m_nTempProp[0] = 0 ;
m_nTempProp[1] = 0 ;
}
//----------------------------------------------------------------------------
SurfFlatRegion::~SurfFlatRegion( void)
{
Clear() ;
}
//----------------------------------------------------------------------------
bool
SurfFlatRegion::Clear( void)
{
m_nStatus = TO_VERIFY ;
m_frF.Reset() ;
// pulizia dei loop
for ( auto& pLoop : m_vpLoop)
delete pLoop ;
m_vpLoop.clear() ;
m_nTempProp[0] = 0 ;
m_nTempProp[1] = 0 ;
// imposto ricalcolo della grafica
m_OGrMgr.Reset() ;
ResetAuxSurf() ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFlatRegion::AddExtLoop( const ICurve& cCrv)
{
// verifico validità curva
if ( &cCrv == nullptr)
return false ;
// creo una copia della curva
ICurve* pCrv( cCrv.Clone()) ;
if ( pCrv == nullptr)
return false ;
// procedo
return AddExtLoop( pCrv) ;
}
//----------------------------------------------------------------------------
bool
SurfFlatRegion::AddExtLoop( ICurve* pCrv)
{
// acquisisco la curva
PtrOwner<ICurve> pMyCrv( pCrv) ;
if ( IsNull( pMyCrv))
return false ;
// verifico sia chiusa
if ( ! pMyCrv->IsClosed())
return false ;
// verifico sia piana e imposto estrusione come normale al piano
double dArea ;
Plane3d plPlane ;
if ( ! pMyCrv->GetArea( plPlane, dArea))
return false ;
pMyCrv->SetExtrusion( plPlane.GetVersN()) ;
pMyCrv->SetThickness( 0) ;
// rimuovo eventuali sovrapposizioni (calcolate nel suo piano)
ICURVEPLIST CrvLst ;
if ( ! AdjustLoops( Release( pMyCrv), CrvLst, true))
return false ;
// aggiungo le singole curve
bool bOk = true ;
for ( auto& pSingCrv : CrvLst) {
if ( ! AddSimpleExtLoop( pSingCrv))
bOk = false ;
}
return bOk ;
}
//----------------------------------------------------------------------------
bool
SurfFlatRegion::AddSimpleExtLoop( ICurve* pCrv)
{
// acquisisco la curva
PtrOwner<ICurve> pMyCrv( pCrv) ;
if ( IsNull( pMyCrv))
return false ;
// verifico sia chiusa
if ( ! pMyCrv->IsClosed())
return false ;
// verifico sia piana
double dArea ;
Plane3d plPlane ;
if ( ! pMyCrv->GetArea( plPlane, dArea))
return false ;
// se sto costruendo il primo chunk
if ( m_vExtInd.size() == 0) {
// assegno il riferimento intrinseco
if ( ! m_frF.Set( ORIG + plPlane.GetVersN() * plPlane.GetDist(), plPlane.GetVersN()))
return false ;
// sistemo il senso di rotazione (deve essere CCW -> area > 0)
if ( dArea < 0)
pMyCrv->Invert() ;
}
// altrimenti
else {
// verifico che il piano della curva coincida con quello XY intrinseco
plPlane.ToLoc( m_frF) ;
if ( ! plPlane.GetVersN().IsZ() || abs( plPlane.GetDist()) > EPS_SMALL)
return false ;
// sistemo il senso di rotazione (deve essere CCW -> area > 0)
if ( ( plPlane.GetVersN().z > 0 && dArea < 0) ||
( plPlane.GetVersN().z < 0 && dArea > 0))
pMyCrv->Invert() ;
}
// porto la curva nel riferimento intrinseco
if ( ! pMyCrv->ToLoc( m_frF))
return false ;
Vector3d vtExtr ;
if ( pMyCrv->GetExtrusion( vtExtr) && ! vtExtr.IsSmall())
pMyCrv->SetExtrusion( Z_AX) ;
// verifico non abbia auto-intersezioni che si attraversano o si sovrappongano
SelfIntersCurve sInt( *pMyCrv) ;
if ( sInt.GetCrossOrOverlapIntersCount() > 0)
return false ;
// verifico che sia esterna alle curve esterne degli altri chunk
bool bOk = true ;
CRVCVECTOR ccClass ;
for ( auto i : m_vExtInd) {
IntersCurveCurve ccInt( *pMyCrv, *m_vpLoop[i]) ;
if ( ccInt.GetCrossOrOverlapIntersCount() > 0 ||
! ccInt.GetCurveClassification( 0, EPS_SMALL, ccClass) ||
ccClass.empty() || ccClass[0].nClass != CRVC_OUT) {
bOk = false ;
break ;
}
}
// oppure esterna ad un loop interno degli altri chunk
for ( int i = 0 ; i < int( m_vpLoop.size()) ; ++ i) {
// se loop esterno, salto
if ( binary_search( m_vExtInd.begin(), m_vExtInd.end(), i))
continue ;
IntersCurveCurve ccInt( *pMyCrv, *m_vpLoop[i]) ;
if ( ccInt.GetCrossOrOverlapIntersCount() == 0 &&
ccInt.GetCurveClassification( 0, EPS_SMALL, ccClass) &&
! ccClass.empty() && ccClass[0].nClass == CRVC_OUT) {
bOk = true ;
break ;
}
}
if ( ! bOk)
return false ;
// assegno la curva come loop esterno
if ( MyAddExtLoop( pMyCrv))
Release( pMyCrv) ;
// imposto ricalcolo della grafica
ResetAuxSurf() ;
m_OGrMgr.Reset() ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFlatRegion::MyAddExtLoop( ICurve* pCrv)
{
try {
m_vpLoop.push_back( pCrv) ;
m_vExtInd.push_back( int( m_vpLoop.size()) - 1) ;
m_nStatus = OK ;
}
catch (...) {
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFlatRegion::AddIntLoop( const ICurve& cCrv)
{
// verifico validità curva
if ( &cCrv == nullptr)
return false ;
// creo una copia della curva
ICurve* pCrv( cCrv.Clone()) ;
if ( pCrv == nullptr)
return false ;
// procedo
return AddIntLoop( pCrv) ;
}
//----------------------------------------------------------------------------
bool
SurfFlatRegion::AddIntLoop( ICurve* pCrv)
{
// acquisisco la curva
PtrOwner<ICurve> pMyCrv( pCrv) ;
if ( IsNull( pMyCrv))
return false ;
// verifico sia chiusa
if ( ! pMyCrv->IsClosed())
return false ;
// verifico sia piana e imposto estrusione come normale al piano
double dArea ;
Plane3d plPlane ;
if ( ! pMyCrv->GetArea( plPlane, dArea))
return false ;
pMyCrv->SetExtrusion( plPlane.GetVersN()) ;
pMyCrv->SetThickness( 0) ;
// rimuovo eventuali sovrapposizioni (calcolate nel suo piano)
ICURVEPLIST CrvLst ;
if ( ! AdjustLoops( Release( pMyCrv), CrvLst, true))
return false ;
// aggiungo le singole curve
bool bOk = true ;
for ( auto& pSingCrv : CrvLst) {
if ( ! AddSimpleIntLoop( pSingCrv))
bOk = false ;
}
return bOk ;
}
//----------------------------------------------------------------------------
bool
SurfFlatRegion::AddSimpleIntLoop( ICurve* pCrv)
{
// acquisisco la curva
PtrOwner<ICurve> pMyCrv( pCrv) ;
if ( IsNull( pMyCrv) || ! pMyCrv->IsValid())
return false ;
// verifico lo stato
if ( m_nStatus != OK || m_vpLoop.empty())
return false ;
// verifico sia chiusa
if ( ! pMyCrv->IsClosed())
return false ;
// porto la curva nel riferimento intrinseco
if ( ! pMyCrv->ToLoc( m_frF))
return false ;
Vector3d vtExtr ;
if ( pMyCrv->GetExtrusion( vtExtr) && ! vtExtr.IsSmall())
pMyCrv->SetExtrusion( Z_AX) ;
// verifico sia piana e il piano coincida con quello XY intrinseco
double dArea ;
Plane3d plPlane ;
if ( ! pMyCrv->GetArea( plPlane, dArea))
return false ;
if ( ! plPlane.GetVersN().IsZ() || abs( plPlane.GetDist()) > EPS_SMALL)
return false ;
// sistemo il senso di rotazione (deve essere CW -> se N==Z+ area < 0, se N==Z- area > 0)
if ( ( plPlane.GetVersN().z > 0 && dArea > 0) || ( plPlane.GetVersN().z < 0 && dArea < 0))
pMyCrv->Invert() ;
// verifico non abbia auto-intersezioni
SelfIntersCurve sInt( *pMyCrv) ;
if ( sInt.GetCrossOrOverlapIntersCount() > 0)
return false ;
// ricerca del chunk in cui andrebbe inserito
int nChunk = -1 ;
for ( int i = 0 ; i < int( m_vExtInd.size()) ; ++ i) {
// verifica rispetto al loop esterno
IntersCurveCurve ccInt( *pMyCrv, *m_vpLoop[m_vExtInd[i]]) ;
CRVCVECTOR ccClass ;
if ( ccInt.GetCrossOrOverlapIntersCount() > 0 ||
! ccInt.GetCurveClassification( 0, EPS_SMALL, ccClass) ||
ccClass.empty() || ccClass[0].nClass != CRVC_IN)
continue ;
// verifica rispetto ai loop interni
bool bOk = true ;
int nLoopCnt = GetLoopCount( i) ;
for ( int j = 0 ; j < nLoopCnt ; ++ j) {
int k = m_vExtInd[i] + j ;
IntersCurveCurve ccInt2( *pMyCrv, *m_vpLoop[k]) ;
CRVCVECTOR ccClass2 ;
if ( ccInt2.GetCrossOrOverlapIntersCount() > 0 ||
! ccInt2.GetCurveClassification( 0, EPS_SMALL, ccClass2) ||
ccClass2.empty() || ccClass2[0].nClass != CRVC_IN) {
bOk = false ;
break ;
}
}
if ( bOk) {
nChunk = i ;
break ;
}
}
if ( nChunk == -1)
return false ;
// aggiungo la curva all'elenco dei loop
if ( MyAddIntLoop( pMyCrv, nChunk))
Release( pMyCrv) ;
// imposto ricalcolo della grafica
ResetAuxSurf() ;
m_OGrMgr.Reset() ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFlatRegion::MyAddIntLoop( ICurve* pCrv, int nChunk)
{
try {
// se da aggiungere all'ultimo chunk
if ( nChunk == -1)
m_vpLoop.push_back( pCrv) ;
// altrimenti aggiungo al chunck indicato
else {
int nLoopCnt = GetLoopCount( nChunk) ;
if ( nLoopCnt == 0)
return false ;
int nOffset = m_vExtInd[nChunk] + nLoopCnt ;
m_vpLoop.insert( m_vpLoop.begin() + nOffset, pCrv) ;
for ( int i = nChunk + 1 ; i < int( m_vExtInd.size()) ; ++ i)
++ m_vExtInd[i] ;
}
}
catch (...) {
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
SurfFlatRegion*
SurfFlatRegion::Clone( void) const
{
// alloco oggetto
SurfFlatRegion* pSfr = new( nothrow) SurfFlatRegion ;
if ( pSfr != nullptr) {
if ( ! pSfr->CopyFrom( *this)) {
delete pSfr ;
return nullptr ;
}
}
return pSfr ;
}
//----------------------------------------------------------------------------
bool
SurfFlatRegion::CopyFrom( const IGeoObj* pGObjSrc)
{
const SurfFlatRegion* pSfr = GetBasicSurfFlatRegion( pGObjSrc) ;
if ( pSfr == nullptr)
return false ;
return CopyFrom( *pSfr) ;
}
//----------------------------------------------------------------------------
bool
SurfFlatRegion::CopyFrom( const SurfFlatRegion& sfrSrc)
{
if ( &sfrSrc == this)
return true ;
Clear() ;
if ( sfrSrc.m_pSTM != nullptr)
m_pSTM = sfrSrc.m_pSTM->Clone() ;
m_frF = sfrSrc.m_frF ;
for ( auto& pLoop : sfrSrc.m_vpLoop) {
ICurve* pCrv = pLoop->Clone() ;
if ( pCrv == nullptr)
return false ;
m_vpLoop.push_back( pCrv) ;
}
m_vExtInd = sfrSrc.m_vExtInd ;
m_nTempProp[0] = sfrSrc.m_nTempProp[0] ;
m_nTempProp[1] = sfrSrc.m_nTempProp[1] ;
m_nStatus = sfrSrc.m_nStatus ;
return ( m_nStatus == OK && ! m_vpLoop.empty()) ;
}
//----------------------------------------------------------------------------
GeoObjType
SurfFlatRegion::GetType( void) const
{
return static_cast<GeoObjType>( GEOOBJ_GETTYPE( SurfFlatRegion)) ;
}
//----------------------------------------------------------------------------
const string&
SurfFlatRegion::GetTitle( void) const
{
static const string sTitle = "SurfFr" ;
return sTitle ;
}
//----------------------------------------------------------------------------
bool
SurfFlatRegion::Dump( string& sOut, bool bMM, const char* szNewLine) const
{
// verifico validità regione
if ( m_nStatus != OK)
sOut += string( "Status=Invalid") + szNewLine ;
// area
double dArea ;
if ( GetArea( dArea))
sOut += "Area=" + ToString( GetAreaInUiUnits( dArea, bMM),1) + szNewLine ;
// riferimento intrinseco : origine, VersoreX, VersoreY, VersoreZ
sOut += "O(" + ToString( GetInUiUnits( m_frF.Orig(), bMM)) + ")" + szNewLine ;
sOut += "VX(" + ToString( m_frF.VersX()) + ")" + szNewLine ;
sOut += "VY(" + ToString( m_frF.VersY()) + ")" + szNewLine ;
sOut += "VZ(" + ToString( m_frF.VersZ()) + ")" + szNewLine ;
// ciclo sui chunk (parti connesse)
int nChunkCount = GetChunkCount() ;
sOut += string( "Chunks =") + ToString( nChunkCount) + szNewLine ;
for ( int i = 0 ; i < nChunkCount ; ++ i) {
int nLoopCount = GetLoopCount( i) ;
// ciclo sui loop del chunk
for ( int j = 0 ; j < nLoopCount ; ++ j) {
int k = GetIndFromChunkLoop( i, j) ;
// loop esterno
if ( j == 0) {
sOut += "Chunk # " + ToString( i) + szNewLine ;
sOut += string( "External Loop : ") + szNewLine ;
m_vpLoop[k]->Dump( sOut, bMM, szNewLine) ;
sOut += "Internal Loops =" + ToString( GetLoopCount( i) - 1) + szNewLine ;
}
// loop interno
else {
sOut += "## " + ToString( j) + szNewLine ;
m_vpLoop[k]->Dump( sOut, bMM, szNewLine) ;
}
}
}
return true ;
}
//----------------------------------------------------------------------------
int
SurfFlatRegion::GetNgeId( void) const
{
return GEOOBJ_GETNGEID( SurfFlatRegion) ;
}
//----------------------------------------------------------------------------
bool
SurfFlatRegion::Save( NgeWriter& ngeOut) const
{
// frame
if ( ! ngeOut.WriteFrame( m_frF, ";", true))
return false ;
// numero di loops (esterno + interni)
if ( ! ngeOut.WriteInt( int( m_vpLoop.size()), nullptr, true))
return false ;
// ciclo sui loop
int i = 0 ;
for ( auto& pLoop : m_vpLoop) {
// recupero il gestore di lettura/scrittura della curva
const IGeoObjRW* pLoopRW = dynamic_cast<const IGeoObjRW*>( pLoop) ;
if ( pLoopRW == nullptr)
return false ;
// emetto il tipo della curva
if ( ! ngeOut.WriteKey( pLoopRW->GetNgeId()))
return false ;
// assegno ed emetto il nome della curva, seguito da chunk e loop
string sCrvName = "##" + ToString( i) ;
if ( ! ngeOut.WriteString( sCrvName, ";"))
return false ;
int nChunk, nLoop ;
if ( ! GetChunkLoopFromInd( i, nChunk, nLoop))
return false ;
if ( ! ngeOut.WriteInt( nChunk, ",") ||
! ngeOut.WriteInt( nLoop, ";", true))
return false ;
// salvo la curva
if ( ! pLoopRW->Save( ngeOut))
return false ;
// passo alla successiva
++ i ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFlatRegion::Load( NgeReader& ngeIn)
{
Clear() ;
// leggo i dati del riferimento
if ( ! ngeIn.ReadFrame( m_frF, ";", true))
return false ;
// leggo la prossima linea ( 1 parametro)
// recupero il numero di curve componenti
int nCounter ;
if ( ! ngeIn.ReadInt( nCounter, nullptr, true))
return false ;
// leggo le curve componenti
for ( int i = 0 ; i < nCounter ; ++ i) {
// recupero la prossima linea (con il tipo di oggetto)
int nNgeId ;
if ( ! ngeIn.ReadKey( nNgeId))
return false ;
// creo l'oggetto
int nType = GEOOBJ_NGEIDTOTYPE( nNgeId) ;
IGeoObj* pGeoO = GEOOBJ_CREATE( nType) ;
if ( pGeoO == nullptr)
return false ;
// recupero la linea con il nome, chunk e loop
string sName ;
int j ;
bool bOk = ngeIn.ReadString( sName, ";") &&
FromString( sName.substr(2), j) && i == j ;
int nChunk = 0, nLoop = 0 ;
bOk = ngeIn.ReadInt( nChunk, ",") &&
ngeIn.ReadInt( nLoop, ";", true) ;
// ne leggo i dati
IGeoObjRW* pGObjRW = dynamic_cast<IGeoObjRW*>( pGeoO) ;
bOk = bOk && ( pGObjRW != nullptr && pGObjRW->Load( ngeIn)) ;
// verifico sia una curva
ICurve* pCrv = ::GetCurve( pGeoO) ;
bOk = bOk && ( pCrv != nullptr) ;
// aggiungo questa curva
if ( bOk) {
m_vpLoop.push_back( pCrv) ;
if ( nLoop == 0) {
m_vExtInd.push_back( i) ;
bOk = ( nChunk + 1 == int( m_vExtInd.size())) ;
}
}
// se errore
if ( ! bOk)
return false ;
}
// aggiorno stato
m_nStatus = OK ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFlatRegion::GetLocalBBox( BBox3d& b3Loc, int nFlag) const
{
// verifico lo stato
if ( m_nStatus != OK || m_vpLoop.empty())
return false ;
// reset del bbox
b3Loc.Reset() ;
// è il bounding box dei loop esterni
for ( auto i : m_vExtInd) {
BBox3d b3Tmp ;
if ( m_vpLoop[i]->GetBBox( m_frF, b3Tmp, nFlag))
b3Loc.Add( b3Tmp) ;
}
return ( ! b3Loc.IsEmpty()) ;
}
//----------------------------------------------------------------------------
bool
SurfFlatRegion::GetBBox( const Frame3d& frRef, BBox3d& b3Ref, int nFlag) const
{
// verifico lo stato
if ( m_nStatus != OK || m_vpLoop.empty())
return false ;
// frame composito
Frame3d frCompo = m_frF * frRef ;
// reset del bbox
b3Ref.Reset() ;
// è il bounding box dei loop esterni
for ( auto i : m_vExtInd) {
BBox3d b3Tmp ;
if ( m_vpLoop[i]->GetBBox( frCompo, b3Ref, nFlag))
b3Ref.Add( b3Tmp) ;
}
return ( ! b3Ref.IsEmpty()) ;
}
//----------------------------------------------------------------------------
bool
SurfFlatRegion::Translate( const Vector3d& vtMove)
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// imposto ricalcolo della grafica
ResetAuxSurf() ;
m_OGrMgr.Reset() ;
// traslo il riferimento
m_frF.Translate( vtMove) ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFlatRegion::Rotate( const Point3d& ptAx, const Vector3d& vtAx, double dCosAng, double dSinAng)
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// verifico validità dell'asse di rotazione
if ( vtAx.IsSmall())
return false ;
// imposto ricalcolo della grafica
ResetAuxSurf() ;
m_OGrMgr.Reset() ;
// ruoto il riferimento
return m_frF.Rotate( ptAx, vtAx, dCosAng, dSinAng) ;
}
//----------------------------------------------------------------------------
bool
SurfFlatRegion::Scale( const Frame3d& frRef, double dCoeffX, double dCoeffY, double dCoeffZ)
{
// verifico lo stato
if ( m_nStatus != OK || m_vpLoop.empty())
return false ;
// verifico non sia nulla
if ( abs( dCoeffX) < EPS_ZERO && abs( dCoeffY) < EPS_ZERO && abs( dCoeffZ) < EPS_ZERO)
return false ;
// imposto ricalcolo della grafica
ResetAuxSurf() ;
m_OGrMgr.Reset() ;
// se scalatura non uniforme, sostituisco eventuali archi con curve di Bezier
if ( abs( dCoeffX - dCoeffY) > EPS_SMALL || abs( dCoeffX - dCoeffZ) > EPS_SMALL) {
if ( ! ConvertArcsToBezierCurves())
return false ;
}
// parziale scalatura del riferimento (non può essere completa)
Frame3d frTrasf = m_frF ;
m_frF.PseudoScale( frRef, dCoeffX, dCoeffY, dCoeffZ) ;
// porto i loop nel nuovo riferimento, senza modificarne la geometria in globale
frTrasf.ToLoc( m_frF) ;
for ( auto& pLoop : m_vpLoop)
pLoop->ToGlob( frTrasf) ;
// porto il riferimento di scalatura nel nuovo riferimento del gruppo
Frame3d frRefLoc = frRef ;
frRefLoc.ToLoc( m_frF) ;
// determino se contiene anche un mirror (numero dispari di coefficienti negativi)
bool bMirror = ( dCoeffX < 0) ;
bMirror = ( bMirror ? ( dCoeffY > 0) : ( dCoeffY < 0)) ;
bMirror = ( bMirror ? ( dCoeffZ > 0) : ( dCoeffZ < 0)) ;
// ciclo sui loop
bool bOk = true ;
for ( auto& pLoop : m_vpLoop) {
if ( ! pLoop->Scale( frRefLoc, dCoeffX, dCoeffY, dCoeffZ))
bOk = false ;
if ( bMirror) {
if ( ! pLoop->Invert())
bOk = false ;
}
}
return bOk ;
}
//----------------------------------------------------------------------------
bool
SurfFlatRegion::Mirror( const Point3d& ptOn, const Vector3d& vtNorm)
{
// verifico lo stato
if ( m_nStatus != OK || m_vpLoop.empty())
return false ;
// verifico validità del piano di specchiatura
if ( vtNorm.IsSmall())
return false ;
// imposto ricalcolo della grafica
ResetAuxSurf() ;
m_OGrMgr.Reset() ;
// parziale mirror del riferimento (non può essere completa)
Frame3d frTrasf = m_frF ;
m_frF.PseudoMirror( ptOn, vtNorm) ;
// porto i loop nel nuovo riferimento, senza modificarne la geometria in globale
frTrasf.ToLoc( m_frF) ;
for ( auto& pLoop : m_vpLoop)
pLoop->ToGlob( frTrasf) ;
// porto i dati del piano di mirror nel riferimento del gruppo
Point3d ptOnLoc = ptOn ;
ptOnLoc.ToLoc( m_frF) ;
Vector3d vtNormLoc = vtNorm ;
vtNormLoc.ToLoc( m_frF) ;
// ciclo sui loop (mirror + invert)
bool bOk = true ;
for ( auto& pLoop : m_vpLoop) {
if ( ! pLoop->Mirror( ptOnLoc, vtNormLoc) || ! pLoop->Invert())
bOk = false ;
}
return bOk ;
}
//----------------------------------------------------------------------------
bool
SurfFlatRegion::Invert( void)
{
// E' un mirror rispetto al piano XY del riferimento intrinseco
return Mirror( m_frF.Orig(), m_frF.VersZ()) ;
}
//----------------------------------------------------------------------------
bool
SurfFlatRegion::Shear( const Point3d& ptOn, const Vector3d& vtNorm, const Vector3d& vtDir, double dCoeff)
{
// verifico lo stato
if ( m_nStatus != OK || m_vpLoop.empty())
return false ;
// verifico validità dei parametri
if ( vtNorm.IsSmall() || vtDir.IsSmall())
return false ;
// imposto ricalcolo della grafica
ResetAuxSurf() ;
m_OGrMgr.Reset() ;
// se il piano di scorrimento non coincide con XY intrinseco, converto eventuali archi in curve di Bezier
if ( ! AreSameOrOppositeVectorExact( m_frF.VersZ(), vtNorm)) {
if ( ! ConvertArcsToBezierCurves())
return false ;
}
// parziale scorrimento del riferimento (non può essere completa)
Frame3d frTrasf = m_frF ;
m_frF.PseudoShear( ptOn, vtNorm, vtDir, dCoeff) ;
// porto i loop nel nuovo riferimento, senza modificarne la geometria in globale
frTrasf.ToLoc( m_frF) ;
for ( auto& pLoop : m_vpLoop)
pLoop->ToGlob( frTrasf) ;
// porto i dati di scorrimento nel riferimento del gruppo
Point3d ptOnLoc = ptOn ;
ptOnLoc.ToLoc( m_frF) ;
Vector3d vtNormLoc = vtNorm ;
vtNormLoc.ToLoc( m_frF) ;
Vector3d vtDirLoc = vtDir ;
vtDirLoc.ToLoc( m_frF) ;
// ciclo sugli oggetti
bool bOk = true ;
for ( auto& pLoop : m_vpLoop) {
if ( ! pLoop->Shear( ptOnLoc, vtNormLoc, vtDirLoc, dCoeff))
bOk = false ;
}
return bOk ;
}
//----------------------------------------------------------------------------
bool
SurfFlatRegion::ConvertArcsToBezierCurves( void)
{
// verifico lo stato
if ( m_nStatus != OK || m_vpLoop.empty())
return false ;
// ciclo sui loop
for ( auto& pLoop : m_vpLoop) {
if ( pLoop->GetType() == CRV_ARC) {
ICurve* pCrvNew = ArcToBezierCurve( pLoop) ;
if ( pCrvNew == nullptr)
return false ;
delete pLoop ;
pLoop = pCrvNew ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFlatRegion::ToGlob( const Frame3d& frRef)
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// verifico validità del frame
if ( frRef.GetType() == Frame3d::ERR)
return false ;
// se frame identità, non devo fare alcunché
if ( IsGlobFrame( frRef))
return true ;
// imposto ricalcolo della grafica
ResetAuxSurf() ;
m_OGrMgr.Reset() ;
// trasformo il riferimento
return m_frF.ToGlob( frRef) ; ;
}
//----------------------------------------------------------------------------
bool
SurfFlatRegion::ToLoc( const Frame3d& frRef)
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// verifico validità del frame
if ( frRef.GetType() == Frame3d::ERR)
return false ;
// se frame identità, non devo fare alcunché
if ( IsGlobFrame( frRef))
return true ;
// imposto ricalcolo della grafica
ResetAuxSurf() ;
m_OGrMgr.Reset() ;
// trasformo il riferimento
return m_frF.ToLoc( frRef) ; ;
}
//----------------------------------------------------------------------------
bool
SurfFlatRegion::LocToLoc( const Frame3d& frOri, const Frame3d& frDest)
{
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// verifico validità dei frame
if ( frOri.GetType() == Frame3d::ERR || frDest.GetType() == Frame3d::ERR)
return false ;
// se i due riferimenti coincidono, non devo fare alcunché
if ( AreSameFrame( frOri, frDest))
return true ;
// imposto ricalcolo della grafica
ResetAuxSurf() ;
m_OGrMgr.Reset() ;
// trasformo il riferimento
return m_frF.LocToLoc( frOri, frDest) ; ;
}
//----------------------------------------------------------------------------
bool
SurfFlatRegion::GetArea( double& dArea) const
{
// controllo parametro di ritorno
if ( &dArea == nullptr)
return false ;
// inizio con area nulla
dArea = 0 ;
// la regione deve essere validata
if ( m_nStatus != OK || m_vpLoop.empty())
return false ;
// sommo l'area di tutti i loop (gli interni hanno area negativa)
bool bOk = true ;
for ( const auto& pLoop : m_vpLoop) {
double dTemp ;
if ( pLoop->GetAreaXY( dTemp))
dArea += dTemp ;
else
bOk = false ;
}
return bOk ;
}
//----------------------------------------------------------------------------
bool
SurfFlatRegion::GetGrossArea( double& dArea) const
{
// controllo parametro di ritorno
if ( &dArea == nullptr)
return false ;
// inizio con area nulla
dArea = 0 ;
// la regione deve essere validata
if ( m_nStatus != OK || m_vpLoop.empty())
return false ;
// sommo l'area di tutti e soli i loop esterni (con area positiva)
bool bOk = true ;
for ( int i = 0 ; i < GetChunkCount() ; ++ i) {
double dTemp ;
const ICurve* pCrv = GetMyLoop( i, 0) ;
if ( pCrv != nullptr && pCrv->GetAreaXY( dTemp))
dArea += abs( dTemp) ;
else
bOk = false ;
}
return bOk ;
}
//----------------------------------------------------------------------------
bool
SurfFlatRegion::GetCentroid( Point3d& ptCen) const
{
// controllo parametro di ritorno
if ( &ptCen == nullptr)
return false ;
// la regione deve essere validata
if ( m_nStatus != OK || m_vpLoop.empty())
return false ;
// determino il centroide dei soli loop esterni
double dArea = 0 ;
ptCen = ORIG ;
for ( int i = 0 ; i < GetChunkCount() ; ++ i) {
Point3d ptC ;
double dA ;
const ICurve* pCrv = GetMyLoop( i, 0) ;
if ( pCrv == nullptr || ! pCrv->GetCentroid( ptC) || ! pCrv->GetAreaXY( dA))
return false ;
ptCen += ptC * abs( dA) ;
dArea += abs( dA) ;
}
// verifico di aver trovato qualcosa
if ( dArea < SQ_EPS_SMALL)
return false ;
// medio il centro
ptCen /= dArea ;
// lo porto dal riferimento intrinseco a quello in cui è immersa l'entità
ptCen.ToGlob( m_frF) ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFlatRegion::GetChunkCentroid( int nChunk, Point3d& ptCen) const
{
// controllo parametro di ritorno
if ( &ptCen == nullptr)
return false ;
// la regione deve essere validata
if ( m_nStatus != OK || m_vpLoop.empty())
return false ;
// determino il centroide del solo loop esterno del chunk
const ICurve* pCrv = GetMyLoop( nChunk, 0) ;
if ( pCrv == nullptr || ! pCrv->GetCentroid( ptCen))
return false ;
// lo porto dal riferimento intrinseco a quello in cui è immersa l'entità
ptCen.ToGlob( m_frF) ;
return true ;
}
//----------------------------------------------------------------------------
int
SurfFlatRegion::GetChunkCount( void) const
{
// la regione deve essere validata
if ( m_nStatus != OK)
return 0 ;
return int( m_vExtInd.size()) ;
}
//----------------------------------------------------------------------------
int
SurfFlatRegion::GetLoopCount( int nChunk) const
{
// la regione deve essere validata
if ( m_nStatus != OK || m_vpLoop.empty())
return 0 ;
// non deve superare l'indice massimo ( Count - 1)
int nChunkMax = int( m_vExtInd.size()) - 1 ;
if ( nChunk < 0 || nChunk > nChunkMax)
return 0 ;
// se non è l'ultimo Chunk
if ( nChunk < nChunkMax)
return ( m_vExtInd[nChunk+1] - m_vExtInd[nChunk]) ;
// altrimenti
else
return ( int( m_vpLoop.size()) - m_vExtInd[nChunk]) ;
}
//----------------------------------------------------------------------------
int
SurfFlatRegion::GetIndFromChunkLoop( int nChunk, int nLoop) const
{
// recupero il numero di loop nel chunk
int nLoopCount = GetLoopCount( nChunk) ;
if ( nLoopCount <= 0)
return - 1 ;
// verifico che il loop esista
if ( nLoop < 0 || nLoop >= nLoopCount)
return - 1 ;
// ritorno il suo indice
return ( m_vExtInd[nChunk] + nLoop) ;
}
//----------------------------------------------------------------------------
bool
SurfFlatRegion::GetChunkLoopFromInd( int nInd, int& nChunk, int& nLoop) const
{
// valori non validi
nChunk = - 1 ;
nLoop = - 1 ;
// verifico validità di nInd
if ( nInd < 0 || nInd >= int( m_vpLoop.size()))
return false ;
// verifica esistenza array di chunks
if ( m_vExtInd.empty())
return false ;
// ricerca del chunk e del loop
nChunk = 0 ;
while ( ( nChunk + 1) < int( m_vExtInd.size())) {
if ( nInd < m_vExtInd[nChunk+1])
break ;
++ nChunk ;
}
nLoop = nInd - m_vExtInd[nChunk] ;
return true ;
}
//----------------------------------------------------------------------------
ICurve*
SurfFlatRegion::GetMyLoop( int nInd) const
{
// la regione deve essere validata
if ( m_nStatus != OK)
return nullptr ;
// verifico che l'indice sia nei limiti
if ( nInd < 0 || nInd >= int( m_vpLoop.size()))
return nullptr ;
else
return m_vpLoop[nInd] ;
}
//----------------------------------------------------------------------------
ICurve*
SurfFlatRegion::GetMyLoop( int nChunk, int nLoop) const
{
return GetMyLoop( GetIndFromChunkLoop( nChunk, nLoop)) ;
}
//----------------------------------------------------------------------------
ICurve*
SurfFlatRegion::GetLoop( int nChunk, int nLoop) const
{
// recupero il loop nel riferimento intrinseco
const ICurve* pMyCrv = GetMyLoop( nChunk, nLoop) ;
if ( pMyCrv == nullptr)
return nullptr ;
// ne faccio una copia
ICurve* pCrv = pMyCrv->Clone() ;
if ( pCrv == nullptr)
return nullptr ;
// assegno la normale alla regione come estrusione
pCrv->SetExtrusion( Z_AX) ;
// la porto nel riferimento in cui è inserito l'oggetto
pCrv->ToGlob( m_frF) ;
return pCrv ;
}
//----------------------------------------------------------------------------
bool
SurfFlatRegion::ApproxLoopWithLines( int nChunk, int nLoop, double dLinTol, double dAngTolDeg, int nType, PolyLine& PL) const
{
// recupero il loop nel riferimento intrinseco
const ICurve* pMyCrv = GetMyLoop( nChunk, nLoop) ;
if ( pMyCrv == nullptr)
return false ;
// ne creo una approssimazione
if ( ! pMyCrv->ApproxWithLines( dLinTol, dAngTolDeg, nType, PL))
return false ;
// la porto nel riferimento in cui è inserito l'oggetto
PL.ToGlob( m_frF) ;
return true ;
}
//----------------------------------------------------------------------------
SurfTriMesh*
SurfFlatRegion::CalcAuxSurf( double dLinTol, double dAngTolDeg) const
{
// la superficie deve essere validata
if ( m_nStatus != OK || m_vpLoop.empty())
return nullptr ;
// la creo
PtrOwner<SurfTriMesh> pSTM( CreateBasicSurfTriMesh()) ;
if ( IsNull( pSTM))
return nullptr ;
// per ogni chunk (componente connesso)
for ( int i = 0 ; i < GetChunkCount() ; ++ i) {
// calcolo le polilinee che approssimano i loop
POLYLINEVECTOR vPL ;
vPL.resize( GetLoopCount( i)) ;
int j = 0 ;
ICurve* pLoop = GetMyLoop( i, j) ;
while ( pLoop != nullptr) {
// approssimo con linee a destra per non avere problemi in punti di contatto tra esterni e interni
if ( ! pLoop->ApproxWithLines( dLinTol, dAngTolDeg, ICurve::APL_RIGHT, vPL[j]))
return nullptr ;
pLoop = GetMyLoop( i, ++j) ;
}
// se chunk abbastanza grande, creo la superficie trimesh relativa
double dArea ;
if ( vPL[0].GetAreaXY( dArea) && dArea > 100 * SQ_EPS_SMALL) {
// creo, setto la superficie trimesh ed elimino punti ripetuti
PtrOwner<SurfTriMesh> pChSTM( CreateBasicSurfTriMesh()) ;
if ( IsNull( pChSTM) || ! pChSTM->CreateByRegion( vPL) || ! pChSTM->DoCompacting())
return nullptr ;
// porto la trimesh in globale al riferimento intrinseco
pChSTM->ToGlob( m_frF) ;
// inserisco questa trimesh in quella complessiva
pSTM->DoSewing( *pChSTM) ;
}
}
// la restituisco
return Release( pSTM) ;
}
//----------------------------------------------------------------------------
const SurfTriMesh*
SurfFlatRegion::GetAuxSurf( void) const
{
// la superficie deve essere validata
if ( m_nStatus != OK || m_vpLoop.empty())
return nullptr ;
// se già calcolata, la restituisco
if ( m_pSTM != nullptr)
return m_pSTM ;
// la creo e la salvo
m_pSTM = CalcAuxSurf( LIN_TOL_FINE, ANG_TOL_STD_DEG) ;
return m_pSTM ;
}
//----------------------------------------------------------------------------
void
SurfFlatRegion::ResetAuxSurf( void) const
{
if ( m_pSTM != nullptr)
delete( m_pSTM) ;
m_pSTM = nullptr ;
}
//----------------------------------------------------------------------------
SurfFlatRegion*
SurfFlatRegion::CloneChunk( int nChunk) const
{
// verifico esistenza del chunk (implicitamente anche lo stato)
int nLoop = GetLoopCount( nChunk) ;
if ( nLoop == 0)
return nullptr ;
// alloco la nuova regione
PtrOwner<SurfFlatRegion> pSfr( CreateBasicSurfFlatRegion()) ;
if ( IsNull( pSfr))
return nullptr ;
// copio il riferimento intrinseco
pSfr->m_frF = m_frF ;
// copio i loop del chunk indicato
for ( int i = 0 ; i < nLoop ; ++i) {
ICurve* pCrv = GetMyLoop( nChunk, i)->Clone() ;
if ( pCrv == nullptr)
return nullptr ;
pSfr->m_vpLoop.push_back( pCrv) ;
}
// sistemo indice dell'unico loop esterno
pSfr->m_vExtInd.push_back( 0) ;
pSfr->m_nStatus = OK ;
return Release( pSfr) ;
}
//----------------------------------------------------------------------------
bool
SurfFlatRegion::MyGetCurveClassification( const ICurve& Crv, double dLenMin, CRVCVECTOR& ccClass) const
{
// la curva deve già essere nel riferimento intrinseco della regione
// verifico lo stato
if ( m_nStatus != OK || m_vpLoop.empty())
return false ;
// verifico la curva
if ( &Crv == nullptr || ! Crv.IsValid())
return false ;
// dominio della curva
double dStart, dEnd ;
if ( ! Crv.GetDomain( dStart, dEnd))
return false ;
// intervalli totali delle diverse classi
Intervals inTIn( EPS_PARAM), inTOut( EPS_PARAM), inTOnP( EPS_PARAM), inTOnM( EPS_PARAM) ;
inTOut.Set( dStart, dEnd) ; // inizializzo come tutta la linea per poi poter rimuovere parti
// ciclo sui chunk
for ( int nChunk = 0 ; nChunk < GetChunkCount() ; ++ nChunk) {
// intervalli di Chunk delle diverse classi
Intervals inCIn( EPS_PARAM), inCOut( EPS_PARAM), inCOnP( EPS_PARAM), inCOnM( EPS_PARAM) ;
inCIn.Set( dStart, dEnd) ; // inizializzo come tutta la linea per poi poter rimuovere parti
// classifico la curva con tutti i loop presenti nel chunk
for ( int nLoop = 0 ; nLoop < GetLoopCount( nChunk) ; ++ nLoop) {
const ICurve* pLoop = GetMyLoop( nChunk, nLoop) ;
// intersezione
IntersCurveCurve ccInt( Crv, *pLoop) ;
// classificazione
CRVCVECTOR ccPart ;
if ( ! ccInt.GetCurveClassification( 0, dLenMin, ccPart))
return false ;
for ( auto& ccOne : ccPart) {
switch ( ccOne.nClass) {
case CRVC_IN :
// IN è Remove degli altri
break ;
case CRVC_OUT :
// intervallo standard
if ( ccOne.dParS < ccOne.dParE - EPS_PARAM) {
inCOut.Add( ccOne.dParS, ccOne.dParE) ;
inCIn.Subtract( ccOne.dParS, ccOne.dParE) ;
}
// intervallo che attraversa punto di chiusura della curva
else {
inCOut.Add( ccOne.dParS, dEnd) ;
inCOut.Add( dStart, ccOne.dParE) ;
inCIn.Subtract( ccOne.dParS, dEnd) ;
inCIn.Subtract( dStart, ccOne.dParE) ;
}
break ;
case CRVC_ON_P :
// intervallo standard
if ( ccOne.dParS < ccOne.dParE - EPS_PARAM) {
inCOnP.Add( ccOne.dParS, ccOne.dParE) ;
inCIn.Subtract( ccOne.dParS, ccOne.dParE) ;
}
// intervallo che attraversa punto di chiusura della curva
else {
inCOnP.Add( ccOne.dParS, dEnd) ;
inCOnP.Add( dStart, ccOne.dParE) ;
inCIn.Subtract( ccOne.dParS, dEnd) ;
inCIn.Subtract( dStart, ccOne.dParE) ;
}
break ;
case CRVC_ON_M :
// intervallo standard
if ( ccOne.dParS < ccOne.dParE - EPS_PARAM) {
inCOnM.Add( ccOne.dParS, ccOne.dParE) ;
inCIn.Subtract( ccOne.dParS, ccOne.dParE) ;
}
// intervallo che attraversa punto di chiusura della curva
else {
inCOnM.Add( ccOne.dParS, dEnd) ;
inCOnM.Add( dStart, ccOne.dParE) ;
inCIn.Subtract( ccOne.dParS, dEnd) ;
inCIn.Subtract( dStart, ccOne.dParE) ;
}
break ;
default : return false ;
}
}
}
// aggiorno gli intervalli di classificazione totali
// In, OnP e OnM vengono aggiornati per somma
inTIn.Add( inCIn) ;
inTOnP.Add( inCOnP) ;
inTOnM.Add( inCOnM) ;
// Out viene ricavato per differenza degli altri
inTOut.Subtract( inCIn) ;
inTOut.Subtract( inCOnP) ;
inTOut.Subtract( inCOnM) ;
}
// ricostruisco la classificazione completa e la ordino
double dMin, dMax ;
bool bFound = inTIn.GetFirst( dMin, dMax) ;
while ( bFound) {
ccClass.emplace_back( dMin, dMax, CRVC_IN) ;
bFound = inTIn.GetNext( dMin, dMax) ;
}
bFound = inTOut.GetFirst( dMin, dMax) ;
while ( bFound) {
ccClass.emplace_back( dMin, dMax, CRVC_OUT) ;
bFound = inTOut.GetNext( dMin, dMax) ;
}
bFound = inTOnP.GetFirst( dMin, dMax) ;
while ( bFound) {
ccClass.emplace_back( dMin, dMax, CRVC_ON_P) ;
bFound = inTOnP.GetNext( dMin, dMax) ;
}
bFound = inTOnM.GetFirst( dMin, dMax) ;
while ( bFound) {
ccClass.emplace_back( dMin, dMax, CRVC_ON_M) ;
bFound = inTOnM.GetNext( dMin, dMax) ;
}
sort( ccClass.begin(), ccClass.end(),
[]( const CrvClass& a, const CrvClass& b) { return ( a.dParS < b.dParS) ; }) ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfFlatRegion::GetCurveClassification( const ICurve& Crv, double dLenMin, CRVCVECTOR& ccClass) const
{
// verifico lo stato
if ( m_nStatus != OK || m_vpLoop.empty())
return false ;
// verifico la curva
if ( &Crv == nullptr || ! Crv.IsValid())
return false ;
// curva in locale nel riferimento intrinseco
const ICurve* pCrvLoc = nullptr ;
PtrOwner<ICurve> pCopyCrv ;
if ( AreSameFrame( m_frF, GLOB_FRM))
pCrvLoc = &Crv ;
else {
pCopyCrv.Set( Crv.Clone()) ;
if ( IsNull( pCopyCrv))
return false ;
pCopyCrv->ToLoc( m_frF) ;
pCrvLoc = pCopyCrv ;
}
// esecuzione classificazione nel riferimento intrinseco
return MyGetCurveClassification( *pCrvLoc, dLenMin, ccClass) ;
}
//----------------------------------------------------------------------------
int
SurfFlatRegion::GetChunkSimpleClassification( int nChunk, const ISurfFlatRegion& Other, int nOthChunk) const
{
// verifico lo stato e il numero di chunk
if ( m_nStatus != OK || m_vpLoop.empty() || nChunk >= GetChunkCount())
return REGC_NULL ;
// recupero rappresentazione base dell'altra regione
const SurfFlatRegion& Reg2 = *GetBasicSurfFlatRegion( &Other) ;
// verifico lo stato e il numero di chunk dell'altra regione
if ( &Reg2 == nullptr || Reg2.m_nStatus != OK || Reg2.m_vpLoop.empty() || nOthChunk >= Reg2.GetChunkCount())
return REGC_NULL ;
// verifico che le due regioni giacciano in piani paralleli
if ( ! AreSameVectorApprox( m_frF.VersZ(), Reg2.m_frF.VersZ()))
return REGC_NULL ;
// curva esterna del chunk della prima regione (ovviamente già in locale al riferimento intrinseco)
const ICurve* pCrv1Loc = GetMyLoop( nChunk, 0) ;
// curva esterna del chunk della seconda regione in locale nel riferimento intrinseco della prima
const ICurve* pCrv2Loc = nullptr ;
PtrOwner<ICurve> pCopyCrv ;
if ( AreSameFrame( m_frF, Reg2.m_frF))
pCrv2Loc = Reg2.GetMyLoop( nOthChunk, 0) ;
else {
pCopyCrv.Set( Reg2.GetMyLoop( nOthChunk, 0)->Clone()) ;
if ( IsNull( pCopyCrv))
return REGC_NULL ;
pCopyCrv->LocToLoc( Reg2.m_frF, m_frF) ;
pCrv2Loc = pCopyCrv ;
}
// se i box delle due curve sono esterni, i chunk sono esterni
BBox3d b3Crv1, b3Crv2 ;
pCrv1Loc->GetLocalBBox( b3Crv1) ;
pCrv2Loc->GetLocalBBox( b3Crv2) ;
if ( ! b3Crv1.OverlapsXY( b3Crv2))
return REGC_OUT ;
// classifico il loop esterno del chunk della prima regione rispetto a quello del chunk della seconda
IntersCurveCurve ccInt( *pCrv1Loc, *pCrv2Loc) ;
int nClass = ccInt.GetRegionCurveClassification() ;
switch ( nClass){
default : // CCREGC_NULL
return REGC_NULL ;
case CCREGC_IN1 :
return REGC_IN1 ;
case CCREGC_IN2 :
return REGC_IN2 ;
case CCREGC_SAME :
return REGC_SAME ;
case CCREGC_OUT :
return REGC_OUT ;
case CCREGC_INTERS :
return REGC_INTERS ;
}
}
//----------------------------------------
bool
SurfFlatRegion::GetZigZagInfill( double dStep, bool bStepCorrection, bool bInvert, ICRVCOMPOPOVECTOR& vpCrvs) const
{
// ingombro della regione
BBox3d b3Pocket ;
GetLocalBBox( b3Pocket) ;
Point3d ptMin ; double dDimX, dDimY, dDimZ ;
b3Pocket.GetMinDim( ptMin, dDimX, dDimY, dDimZ) ;
// lunghezza dei contorni
DBLVECTOR vLen( m_vpLoop.size()) ;
for ( size_t i = 0 ; i < vLen.size() ; i++)
m_vpLoop[i]->GetLength( vLen[i]) ;
// passi in Y
double dYStep = dStep ;
int nYStep = static_cast<int>( floor( dDimY / dStep)) ;
int nRef = 0 ;
if ( bStepCorrection) {
// se permesso, lo modifico per coprire uniformemente la regione
nYStep = static_cast<int>( ceil( ( dDimY - 30 * EPS_SMALL) / dStep)) ;
dYStep = ( nYStep > 0 ? ( dDimY - 30 * EPS_SMALL) / nYStep : 0) ;
nRef = ( ( nYStep + ( bInvert ? 0 : 1)) % 2) ;
}
// tratto valido
struct Section {
bool bActive ;
Point3d ptS ;
Point3d ptE ;
double dOs ;
double dOe ;
size_t nIdxS ; // indice del loop a cui appartiene ptS
size_t nIdxE ; // indice del loop a cui appartiene ptE
} ;
// raccolta di tratti
typedef vector<vector<Section>> VECVECSECT ;
VECVECSECT vvSec ;
vvSec.resize( nYStep + 1) ;
// calcolo le linee di svuotatura
int nCount = 0 ;
for ( int i = 0 ; i <= nYStep ; ++ i) {
// determino senso
bool bPlus = (( i % 2) == nRef) ;
// definisco correzione per essere sicura di poter fare primo e ultimo step
double dCorr = 0 ;
if ( i == 0)
dCorr = 10 * EPS_SMALL ;
else if ( i == nYStep)
dCorr = - 10 * EPS_SMALL ;
// definisco la linea
PtrOwner<CurveLine> pLine( CreateBasicCurveLine()) ;
const double EXP_LEN = 1.0 ;
Point3d ptStart( ptMin.x - EXP_LEN, ptMin.y + dCorr + i * dYStep, ptMin.z + dDimZ) ;
if ( IsNull( pLine) || ! pLine->SetPVL( ptStart, X_AX , dDimX + 2 * EXP_LEN)) {
return false ;
}
// calcolo la classificazione della curva rispetto alla regione
CRVCVECTOR ccClass ;
if ( ! GetCurveClassification( *pLine, EPS_SMALL, ccClass))
return false ;
// determino gli intervalli di curva da conservare
Intervals inOk ;
for ( auto& ccOne : ccClass) {
if ( ccOne.nClass == CRVC_IN || ccOne.nClass == CRVC_ON_P || ccOne.nClass == CRVC_ON_M)
inOk.Add( ccOne.dParS, ccOne.dParE) ;
}
// inserisco i tratti validi (secondo X+ i pari, secondo X- i dispari)
double dParS, dParE ;
bool bFound = ( bPlus ? inOk.GetFirst( dParS, dParE) : inOk.GetLast( dParE, dParS)) ;
while ( bFound) {
// determino i dati della sezione
Section Sect ;
Sect.bActive = true ;
pLine->GetPointD1D2( dParS, ICurve::FROM_PLUS, Sect.ptS) ;
pLine->GetPointD1D2( dParE, ICurve::FROM_MINUS, Sect.ptE) ;
// porto i punti nel riferimento della curva
if ( ! AreSameFrame( m_frF, GLOB_FRM)) {
Sect.ptS.ToLoc( m_frF) ;
Sect.ptE.ToLoc( m_frF) ;
}
// cerco la curva della regione che passa per ptS
bool bCrvFound = false ;
for ( size_t k = 0 ; ! bCrvFound && k < m_vpLoop.size() ; k++) {
bCrvFound = m_vpLoop[k]->GetParamAtPoint( Sect.ptS, Sect.dOs, 10 * EPS_SMALL) ;
if ( bCrvFound)
Sect.nIdxS = k ;
}
if ( ! bCrvFound)
return false ;
// cerco la curva della regione che passa per ptE
bCrvFound = false ;
for ( size_t k = 0 ; ! bCrvFound && k < m_vpLoop.size() ; k++) {
bCrvFound = m_vpLoop[k]->GetParamAtPoint( Sect.ptE, Sect.dOe, 10 * EPS_SMALL) ;
if ( bCrvFound)
Sect.nIdxE = k ;
}
if ( ! bCrvFound)
return false ;
// inserisco nel contenitore
vvSec[i].emplace_back( Sect) ;
++ nCount ;
// recupero intervallo successivo
bFound = ( bPlus ? inOk.GetNext( dParS, dParE) : inOk.GetPrev( dParE, dParS)) ;
}
}
// dominio del contorno
DBLVECTOR vUmax( m_vpLoop.size()) ;
DBLVECTOR vUmin( m_vpLoop.size()) ;
DBLVECTOR vUspan( m_vpLoop.size()) ;
for ( size_t i = 0 ; i < m_vpLoop.size() ; i++) {
m_vpLoop[i]->GetDomain( vUmin[i], vUmax[i]) ;
vUspan[i] = vUmax[i] - vUmin[i] ;
}
// creo i percorsi di svuotatura
vpCrvs.reserve( nCount) ;
int nI = -1, nJ = -1 ;
while ( true) {
// se sezione non valida
if ( nI < 0 || nJ < 0) {
// ricerco la prima valida
for ( int k = 0 ; k < int( vvSec.size()) && nI < 0 ; ++ k) {
for ( int l = 0 ; l < int( vvSec[k].size()) && nJ < 0 ; ++ l) {
if ( vvSec[k][l].bActive) {
nI = k ;
nJ = l ;
}
}
}
// se trovata, creo nuova curva composita
if ( nI >= 0 && nJ >= 0) {
// creo la curva
vpCrvs.emplace_back( CreateCurveComposite()) ;
// aggiungo punto iniziale
vpCrvs.back()->AddPoint( vvSec[nI][nJ].ptS) ;
}
// altrimenti, esco
else
break ;
}
// determino senso
bool bPlus = (( nI % 2) == nRef) ;
// aggiungo la sezione alla curva
Section& Sec = vvSec[nI][nJ] ;
Sec.bActive = false ;
vpCrvs.back()->AddLine( vvSec[nI][nJ].ptE) ;
// cerco nella stessa fila o in quella successiva sezione successiva raccordabile tramite il contorno
double dUstart = Sec.dOe ;
double dUref = ( bPlus ? INFINITO : - INFINITO) ;
int nNextI = -1 ;
int nNextJ = -1 ;
int li = nJ + 1 ;
for ( int k = nI ; k <= nI + 1 && k < int( vvSec.size()) ; ++ k) {
for ( int l = li ; l < int( vvSec[k].size()) ; ++ l) {
if ( ! vvSec[k][l].bActive)
continue ;
// la nuova sezione deve partire dalla stessa curva su cui ci si è fermati
if ( vvSec[k][l].nIdxS != Sec.nIdxE)
continue ;
double dU = vvSec[k][l].dOs ;
if ( bPlus) {
if ( dU < dUstart)
dU += vUspan[Sec.nIdxE] ;
if ( dU < dUref) {
dUref = dU ;
nNextI = k ;
nNextJ = l ;
}
}
else {
if ( dU > dUstart)
dU -= vUspan[Sec.nIdxE] ;
if ( dU > dUref) {
dUref = dU ;
nNextI = k ;
nNextJ = l ;
}
}
}
li = 0 ;
}
// se trovato, aggiungo il tratto di contorno e continuo
if ( nNextI != -1) {
PtrOwner<ICurve> pCopy ;
size_t idx = vvSec[nNextI][nNextJ].nIdxS ;
if ( bPlus) {
if ( dUref > vUmax[idx])
dUref -= vUspan[idx] ;
pCopy.Set( m_vpLoop[idx]->CopyParamRange( dUstart, dUref)) ;
if ( ! IsNull( pCopy)) {
double dCLen ; pCopy->GetLength( dCLen) ;
if ( dCLen > 0.5 * vLen[idx]) {
pCopy.Set( m_vpLoop[idx]->CopyParamRange( dUref, dUstart)) ;
if ( ! IsNull( pCopy))
pCopy->Invert() ;
}
}
}
else {
if ( dUref < vUmin[idx])
dUref += vUspan[idx] ;
pCopy.Set( m_vpLoop[idx]->CopyParamRange( dUref, dUstart)) ;
if ( ! IsNull( pCopy)) {
pCopy->Invert() ;
double dCLen ; pCopy->GetLength( dCLen) ;
if ( dCLen > 0.5 * vLen[idx])
pCopy.Set( m_vpLoop[idx]->CopyParamRange( dUstart, dUref)) ;
}
}
BBox3d b3Copy ;
if ( ! IsNull( pCopy))
pCopy->GetBBox( m_frF, b3Copy) ;
if ( ! b3Copy.IsEmpty() && ( b3Copy.GetMax().y - b3Copy.GetMin().y) < dYStep + 10 * EPS_SMALL) {
vpCrvs.back()->AddCurve( Release( pCopy)) ;
nI = nNextI ;
nJ = nNextJ ;
}
else {
nI = -1 ;
nJ = -1 ;
}
}
else {
nI = -1 ;
nJ = -1 ;
}
}
// porto le curve calcolate nel riferimento globale
if ( ! AreSameFrame( m_frF, GLOB_FRM)) {
for ( int i = 0 ; i < ( int) vpCrvs.size() ; i++)
vpCrvs[i]->ToGlob( m_frF) ;
}
return true ;
}