//---------------------------------------------------------------------------- // 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 "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() { } //---------------------------------------------------------------------------- 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 ; // 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 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.vtN * plPlane.dDist, plPlane.vtN)) 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.vtN.IsZplus() || plPlane.vtN.IsZminus()) || fabs( plPlane.dDist) > EPS_SMALL) return false ; // sistemo il senso di rotazione (deve essere CCW -> area > 0) if ( ( plPlane.vtN.IsZplus() && dArea < 0) || ( plPlane.vtN.IsZminus() && dArea > 0)) pMyCrv->Invert() ; } // porto la curva nel riferimento intrinseco if ( ! pMyCrv->ToLoc( m_frF)) return false ; // verifico non abbia auto-intersezioni che si attraversano 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, 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, ccClass) && ! ccClass.empty() && ccClass[0].nClass == CRVC_OUT) { bOk = true ; break ; } } if ( ! bOk) return false ; // assegno la curva come loop esterno if ( MyAddExtLoop( Get( 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 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 ; // verifico sia piana e il piano coincida con quello XY intrinseco double dArea ; Plane3d plPlane ; if ( ! pMyCrv->GetArea( plPlane, dArea)) return false ; if ( ! ( plPlane.vtN.IsZplus() || plPlane.vtN.IsZminus()) || fabs( plPlane.dDist) > EPS_SMALL) return false ; // sistemo il senso di rotazione (deve essere CW -> se N==Z+ area < 0, se N==Z- area>0) if ( ( plPlane.vtN.IsZplus() && dArea > 0) || ( plPlane.vtN.IsZminus() && dArea < 0)) pMyCrv->Invert() ; // verifico non abbia auto-intersezioni SelfIntersCurve sInt( *pMyCrv) ; if ( sInt.GetCrossOrOverlapIntersCount() > 0) return false ; // verifico non abbia intersezioni e non sia esterna ai loop già definiti del medesimo chunk CRVCVECTOR ccClass ; for ( int i = m_vExtInd.back() ; i < int( m_vpLoop.size()) ; ++ i) { IntersCurveCurve ccInt( *pMyCrv, *m_vpLoop[i]) ; if ( ccInt.GetCrossOrOverlapIntersCount() > 0 || ! ccInt.GetCurveClassification( 0, ccClass) || ccClass.empty() || ccClass[0].nClass != CRVC_IN) return false ; } // aggiungo la curva all'elenco dei loop if ( MyAddIntLoop( Get( pMyCrv))) Release( pMyCrv) ; // imposto ricalcolo della grafica ResetAuxSurf() ; m_OGrMgr.Reset() ; return true ; } //---------------------------------------------------------------------------- bool SurfFlatRegion::MyAddIntLoop( ICurve* pCrv) { try { m_vpLoop.push_back( pCrv) ; } 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 = dynamic_cast( 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 = sfrSrc.m_nTempProp ; m_nStatus = sfrSrc.m_nStatus ; return ( m_nStatus == OK && ! m_vpLoop.empty()) ; } //---------------------------------------------------------------------------- GeoObjType SurfFlatRegion::GetType( void) const { return static_cast( GEOOBJ_GETTYPE( SurfFlatRegion)) ; } //---------------------------------------------------------------------------- const string& SurfFlatRegion::GetTitle( void) const { static const string sTitle = "FlatRegion" ; 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( 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, nLoop ; bOk = ngeIn.ReadInt( nChunk, ",") && ngeIn.ReadInt( nLoop, ";", true) ; // ne leggo i dati IGeoObjRW* pGObjRW = dynamic_cast( 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 ; // è il bounding box del loop esterno return m_vpLoop[0]->GetBBox( m_frF, b3Loc, nFlag) ; } //---------------------------------------------------------------------------- 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 ; // è il bounding box del loop esterno return m_vpLoop[0]->GetBBox( frCompo, b3Ref, nFlag) ; } //---------------------------------------------------------------------------- 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 ; // 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 ; // imposto ricalcolo della grafica ResetAuxSurf() ; m_OGrMgr.Reset() ; // se scalatura non uniforme, sostituisco eventuali archi con curve di Bezier if ( fabs( dCoeffX - dCoeffY) > EPS_SMALL || fabs( 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) ; // ciclo sui loop bool bOk = true ; for ( auto& pLoop : m_vpLoop) { if ( ! pLoop->Scale( frRefLoc, dCoeffX, dCoeffY, dCoeffZ)) 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 ; // 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 ; // 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 ; // trasformo il riferimento return m_frF.ToGlob( frRef) ; ; } //---------------------------------------------------------------------------- bool SurfFlatRegion::ToLoc( const Frame3d& frRef) { // verifico lo stato if ( m_nStatus != OK) return false ; // 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 ; // 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 ( auto& pLoop : m_vpLoop) { double dTemp ; if ( pLoop->GetAreaXY( dTemp)) dArea += 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 del solo loop esterno if ( ! m_vpLoop[0]->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 ; // la porto nel riferimento in cui è inserito l'oggetto pCrv->ToGlob( m_frF) ; return pCrv ; } //---------------------------------------------------------------------------- const ISurfTriMesh* 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 PtrOwner 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( LIN_TOL_SFR, ANG_TOL_STD_DEG, ICurve::APL_RIGHT, vPL[j])) return nullptr ; pLoop = GetMyLoop( i, ++j) ; } // porto le polilinee in globale al riferimento intrinseco for ( auto& PL : vPL) PL.ToGlob( m_frF) ; // creo, setto la superficie trimesh ed elimino punti ripetuti PtrOwner pChSTM( CreateBasicSurfTriMesh()) ; if ( IsNull( pChSTM) || ! pChSTM->CreateByRegion( vPL) || ! pChSTM->DoCompacting()) return nullptr ; // inserisco questa trimesh in quella complessiva pSTM->DoSewing( *Get( pChSTM)) ; } // la salvo m_pSTM = Release( pSTM) ; 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 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, CRVCVECTOR& ccClass) const { // la curva devono 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, inTOut, inTOnP, inTOnM ; 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, inCOut, inCOnP, inCOnM ; 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, 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, 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 pCopyCrv ; if ( AreSameFrame( m_frF, GLOB_FRM)) pCrvLoc = &Crv ; else { pCopyCrv.Set( Crv.Clone()) ; if ( IsNull( pCopyCrv)) return false ; pCopyCrv->ToLoc( m_frF) ; pCrvLoc = Get( pCopyCrv) ; } // esecuzione classificazione nel riferimento intrinseco return MyGetCurveClassification( *pCrvLoc, ccClass) ; }