//---------------------------------------------------------------------------- // 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 "Voronoi.h" #include "/EgtDev/Include/EGkStringUtils3d.h" #include "/EgtDev/Include/EGkUiUnits.h" #include "/EgtDev/Include/EGkIntervals.h" #include "/EgtDev/Include/EgtPointerOwner.h" #define SAVECLASSCRV 0 #define SAVEADJUSTCRV 0 #if SAVECLASSCRV || SAVEADJUSTCRV std::vector vGeo ; #include "/EgtDev/Include/EGkGeoObjSave.h" #endif 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_dTempParam{0.0,0.0}, m_pVoronoiObj( nullptr) { } //---------------------------------------------------------------------------- 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_vExtInd.clear() ; m_nTempProp[0] = 0 ; m_nTempProp[1] = 0 ; m_dTempParam[0] = 0.0 ; m_dTempParam[1] = 0.0 ; // imposto ricalcolo della grafica m_OGrMgr.Reset() ; ResetAuxSurf() ; // imposto ricalcolo Voronoi ResetVoronoiObject() ; 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 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 SAVEADJUSTCRV SaveGeoObj( pMyCrv->Clone(), "D:\\Temp\\inters\\CrvCrvInters\\before_adjust.nge") ; #endif if ( ! AdjustLoops( Release( pMyCrv), CrvLst, true)) return false ; #if SAVEADJUSTCRV for ( auto& pSingCrv : CrvLst) vGeo.push_back( pSingCrv->Clone()) ; SaveGeoObj( vGeo, "D:\\Temp\\inters\\CrvCrvInters\\after_adjust.nge") ; #endif // aggiungo le singole curve int nExtAdded = 0 ; bool bOk = true ; for ( auto& pSingCrv : CrvLst) { bool bAdded = false ; if ( AddSimpleExtLoop( pSingCrv, bAdded)) ++ nExtAdded ; else bOk = false ; } return ( bOk && nExtAdded > 0) ; } //---------------------------------------------------------------------------- bool SurfFlatRegion::AddSimpleExtLoop( ICurve* pCrv, bool& bAdded) { // default bAdded = false ; // 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 ; if ( dArea < SQ_EPS_SMALL) return true ; // se sto costruendo il primo chunk if ( m_vExtInd.empty()) { // 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().IsZEpsilon( 2 * EPS_ZERO) || 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 che sia esterna alle curve esterne degli altri chunk bool bOk = true ; CRVCVECTOR ccClass ; for ( auto i : m_vExtInd) { #if SAVEADJUSTCRV vGeo.clear() ; vGeo.push_back( pMyCrv->Clone()) ; vGeo.push_back( m_vpLoop[i]->Clone()) ; SaveGeoObj( vGeo, "D:\\Temp\\inters\\CrvCrvInters\\during_add_simpleExt.nge") ; #endif 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() ; // imposto ricalcolo Voronoi ResetVoronoiObject() ; bAdded = true ; return true ; } //---------------------------------------------------------------------------- bool SurfFlatRegion::MyAddExtLoop( ICurve* pCrv) { m_vpLoop.push_back( pCrv) ; m_vExtInd.push_back( int( m_vpLoop.size()) - 1) ; m_nStatus = OK ; 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)) 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 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().IsZEpsilon( 2 * EPS_ZERO) || 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() ; // 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() ; // imposto ricalcolo Voronoi ResetVoronoiObject() ; return true ; } //---------------------------------------------------------------------------- bool SurfFlatRegion::MyAddIntLoop( ICurve* pCrv, int nChunk) { //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] ; } 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_dTempParam[0] = sfrSrc.m_dTempParam[0] ; m_dTempParam[1] = sfrSrc.m_dTempParam[1] ; 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 = "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( 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( 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, b3Tmp, 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 Voronoi if ( m_pVoronoiObj != nullptr) m_pVoronoiObj->Translate( vtMove) ; // 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 Voronoi if ( m_pVoronoiObj != nullptr) m_pVoronoiObj->Rotate( ptAx, vtAx, dCosAng, dSinAng) ; // 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() ; // imposto ricalcolo Voronoi ResetVoronoiObject() ; // 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() ; // imposto ricalcolo Voronoi ResetVoronoiObject() ; // 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() ; // imposto ricalcolo Voronoi ResetVoronoiObject() ; // 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( GetCurveArc(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 Voronoi if ( m_pVoronoiObj != nullptr) m_pVoronoiObj->ToGlob( frRef) ; // 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 Voronoi if ( m_pVoronoiObj != nullptr) m_pVoronoiObj->ToLoc( frRef) ; // 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 Voronoi if ( m_pVoronoiObj != nullptr) m_pVoronoiObj->LocToLoc( frOri, frDest) ; // trasformo il riferimento return m_frF.LocToLoc( frOri, frDest) ; ; } //---------------------------------------------------------------------------- bool SurfFlatRegion::GetArea( double& dArea) const { // 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 { // 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 { // 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 ; } //---------------------------------------------------------------------------- int SurfFlatRegion::GetChunkCount( void) const { // la regione deve essere validata if ( m_nStatus != OK) return 0 ; return int( m_vExtInd.size()) ; } //---------------------------------------------------------------------------- bool SurfFlatRegion::GetChunkCentroid( int nChunk, Point3d& ptCen) const { // 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 ; } //---------------------------------------------------------------------------- bool SurfFlatRegion::GetChunkArea( int nChunk, double& dArea) const { // default, area nulla dArea = 0 ; // la regione deve essere validata if ( m_nStatus != OK || m_vpLoop.empty()) return false ; // il chunk deve esistere if ( nChunk < 0 || nChunk >= GetChunkCount()) return false ; // calcolo l'area bool bOk = true ; for ( int nL = 0 ; nL < GetLoopCount( nChunk) ; ++ nL) { const ICurve* pLoop = GetMyLoop( nChunk, nL) ; double dLoopArea ; if ( pLoop != nullptr && pLoop->GetAreaXY( dLoopArea)) dArea += dLoopArea ; else bOk = false ; } return bOk ; } //---------------------------------------------------------------------------- bool SurfFlatRegion::GetChunkPerimeter( int nChunk, double& dLen) const { // default, perimetro nullo dLen = 0 ; // la regione deve essere validata if ( m_nStatus != OK || m_vpLoop.empty()) return false ; // il chunk deve esistere if ( nChunk < 0 || nChunk >= GetChunkCount()) return false ; // calcolo il perimetro bool bOk = true ; for ( int nL = 0 ; nL < GetLoopCount( nChunk) ; ++ nL) { const ICurve* pLoop = GetMyLoop( nChunk, nL) ; double dLoopLen ; if ( pLoop != nullptr && pLoop->GetLength( dLoopLen)) dLen += dLoopLen ; else bOk = false ; } return bOk ; } //---------------------------------------------------------------------------- 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 ; } //---------------------------------------------------------------------------- int SurfFlatRegion::GetLoopCurveCount( int nChunk, int nLoop) const { // recupero il loop nel riferimento intrinseco const ICurve* pMyCrv = GetMyLoop( nChunk, nLoop) ; if ( pMyCrv == nullptr) return 0 ; // restituisco il numero di curve di cui è composto const ICurveComposite* pMyCompo = GetCurveComposite( pMyCrv) ; return ( pMyCompo == nullptr ? 1 : pMyCompo->GetCurveCount()) ; } //---------------------------------------------------------------------------- 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 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.reserve( 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 vPL.emplace_back( PolyLine()) ; if ( ! pLoop->ApproxWithLines( dLinTol, dAngTolDeg, ICurve::APL_RIGHT, vPL.back())) return nullptr ; double dLoopArea ; if ( ! vPL.back().GetAreaXY( dLoopArea) || abs( dLoopArea) <= 25 * SQ_EPS_SMALL) vPL.pop_back() ; pLoop = GetMyLoop( i, ++j) ; } // se chunk abbastanza grande, creo la superficie trimesh relativa double dArea ; if ( ! vPL.empty() && vPL[0].GetAreaXY( dArea) && dArea > 25 * SQ_EPS_SMALL) { // creo, setto la superficie trimesh ed elimino punti ripetuti PtrOwner pChSTM( CreateBasicSurfTriMesh()) ; INTMATRIX vnPLIndMat ; if ( IsNull( pChSTM) || ! pChSTM->CreateByRegion( vPL, vnPLIndMat) || ! 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) ; } } // se vuota if ( pSTM->IsEmpty()) pSTM->AdjustTopology() ; // 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 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::EraseChunk(int nChunk) { // la regione deve essere validata if ( m_nStatus != OK || m_vpLoop.empty()) return false ; // il chunk deve esistere if ( nChunk < 0 || nChunk >= GetChunkCount()) return false ; // se un solo chunk, resetto la regione if ( GetChunkCount() == 1) { Clear() ; return true ; } // se ultimo chunk if ( nChunk == m_vExtInd.size() - 1) { // elimino i loop for ( int i = m_vExtInd[nChunk] ; i < int( m_vpLoop.size()) ; ++ i) { delete m_vpLoop[i] ; m_vpLoop[i] = nullptr ; } m_vpLoop.erase( m_vpLoop.begin() + m_vExtInd[nChunk], m_vpLoop.end()) ; // elimino indice di loop esterno m_vExtInd.pop_back() ; } // altrimenti else { // numero di loop da eliminare int nLoopCnt = m_vExtInd[nChunk+1] - m_vExtInd[nChunk] ; // elimino i loop for ( int i = m_vExtInd[nChunk] ; i < m_vExtInd[nChunk+1] ; ++ i) { delete m_vpLoop[i] ; m_vpLoop[i] = nullptr ; } m_vpLoop.erase( m_vpLoop.begin() + m_vExtInd[nChunk], m_vpLoop.begin() + m_vExtInd[nChunk+1]) ; // elimino indice di loop esterno m_vExtInd.erase( m_vExtInd.begin() + nChunk) ; // aggiorno indice inizio chunk successivi for ( int i = nChunk ; i < int( m_vExtInd.size()) ; ++i) m_vExtInd[i] -= nLoopCnt ; } // imposto ricalcolo della grafica m_OGrMgr.Reset() ; ResetAuxSurf() ; // imposto ricalcolo Voronoi ResetVoronoiObject() ; return true ; } //---------------------------------------------------------------------------- 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 #if SAVECLASSCRV //debug vector vGeo ; vGeo.push_back( Crv.Clone()) ; vGeo.push_back( pLoop->Clone()) ; SaveGeoObj( vGeo, "D:\\Temp\\inters\\CrvCrvInters\\crv_and_loop.nge") ; #endif 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 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 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::CheckChunkInterference( int nChunk, const ISurfFlatRegion& Other, int nOthChunk, bool& bInterference) const { bInterference = false ; // verifico lo stato e il numero di chunk if ( m_nStatus != OK || m_vpLoop.empty() || nChunk >= GetChunkCount()) return false ; // recupero rappresentazione base dell'altra regione const SurfFlatRegion& Reg2 = *GetBasicSurfFlatRegion( &Other) ; // verifico lo stato e il numero di chunk dell'altra regione if ( Reg2.m_nStatus != OK || Reg2.m_vpLoop.empty() || nOthChunk >= Reg2.GetChunkCount()) return false ; // verifico che le due regioni giacciano in piani paralleli if ( ! AreSameVectorApprox( m_frF.VersZ(), Reg2.m_frF.VersZ())) return false ; // classifico il loop esterno del chunk della prima regione rispetto a quello del chunk della seconda int nClass = GetChunkSimpleClassification( nChunk, Other, nOthChunk) ; if ( nClass == REGC_NULL) return false ; // se le regioni non hanno isole, allora ho già identificato se i Chunks fanno interferenza int nLoopCnt = GetLoopCount( nChunk) ; int nOtherLoopCnt = Other.GetLoopCount( nOthChunk) ; if ( nLoopCnt == 1 && nOtherLoopCnt == 1) { bInterference = ( nClass != REGC_OUT) ; return true ; } // --- a prescindere dalle isole presenti nei 2 Chunks in esame : // se i due loop esterni si intersecano tra loro o sono gli stessi, allora fanno per forza interferenza if ( nClass == REGC_INTERS || nClass == CCREGC_SAME) { bInterference = true ; return true ; } // se invece sono esterni tra loro, allora non c'è interferenza else if ( nClass == REGC_OUT) return true ; // --- Analisi del loop interni : // se la curva esterna corrente è interna alla curva esterna dell'altro chunk else if ( nClass == REGC_IN1) { // se l'altro chunk non ha isole, c'è interferenza (a prescinere da numero di loop interni del primo chunk) if ( nOtherLoopCnt == 1) { bInterference = true ; return true ; } // curva esterna del chunk della prima regione (ovviamente già in locale al riferimento intrinseco) const ICurve* pCrv1Loc = GetMyLoop( nChunk, 0) ; // per ogni loop interno (isole) for ( int i = 1 ; i < nOtherLoopCnt ; ++ i) { const ICurve* pCrv2Loc = nullptr ; PtrOwner pCopyCrv ; if ( AreSameFrame( m_frF, Reg2.m_frF)) pCrv2Loc = Reg2.GetMyLoop( nOthChunk, i) ; else { pCopyCrv.Set( Reg2.GetMyLoop( nOthChunk, i)->Clone()) ; if ( IsNull( pCopyCrv)) return false ; pCopyCrv->LocToLoc( Reg2.m_frF, m_frF) ; pCrv2Loc = pCopyCrv ; } // classifico il loop esterno del chunk della prima regione rispetto all'interno corrente del chunk della seconda IntersCurveCurve ccInt( *pCrv1Loc, *pCrv2Loc) ; int nInternalClass = ccInt.GetRegionCurveClassification() ; // se le curve non sono classificabili, errore if ( nInternalClass == REGC_NULL) return false ; // se la curva di bordo corrente è interna (le isole girano al contrario) all'isola corrente else if ( nInternalClass == REGC_IN1) ; // non faccio nulla, potrebbe non essere l'isola adatta per la classificazione // se la curva di bordo corrente è esterna (le isole girano al contrario) all'isola corrente, allora non ho interferenza else if ( nInternalClass == REGC_OUT) return true ; // se la curva di bordo corrente interseca l'isola o coincide con essa allora c'è interferenza else if ( nInternalClass == REGC_INTERS || nInternalClass == REGC_SAME) { bInterference = true ; return true ; } // negli altri casi ho un orientamento errato dei loop o delle regioni else return false ; } } // se la curva esterna dell'altro chunk è interna alla curva esterna corrente else if ( nClass == REGC_IN2) { // se l'altro chunk non ha isole, c'è interferenza if ( nLoopCnt == 1) { bInterference = true ; return true ; } // curva esterna del chunk della prima regione (ovviamente già in locale al riferimento intrinseco) const ICurve* pCrv2Loc = Reg2.GetMyLoop( nChunk, 0) ; // per ogni loop interno (isole) for ( int i = 1 ; i < nLoopCnt ; ++ i) { const ICurve* pCrv1Loc = nullptr ; PtrOwner pCopyCrv ; if ( AreSameFrame( Reg2.m_frF, m_frF)) pCrv1Loc = GetMyLoop( nOthChunk, i) ; else { pCopyCrv.Set( GetMyLoop( nOthChunk, i)->Clone()) ; if ( IsNull( pCopyCrv)) return false ; pCopyCrv->LocToLoc( m_frF, Reg2.m_frF) ; pCrv1Loc = pCopyCrv ; } // classifico il loop esterno del chunk della prima regione rispetto a quello del chunk della seconda IntersCurveCurve ccInt( *pCrv2Loc, *pCrv1Loc) ; int nInternalClass = ccInt.GetRegionCurveClassification() ; // se le curve non sono classificabili, errore if ( nInternalClass == REGC_NULL) return false ; // se la curva di bordo corrente è interna (le isole girano al contrario) all'isola corrente else if ( nInternalClass == REGC_IN1) ; // non faccio nulla, potrebbe non essere l'isola adatta per la classificazione // se la curva di bordo corrente è esterna (le isole girano al contrario) all'isola corrente, allora non ho interferenza else if ( nInternalClass == REGC_OUT) return true ; // se la curva di bordo corrente interseca l'isola o coincide con essa allora c'è interferenza else if ( nInternalClass == REGC_INTERS || nInternalClass == REGC_SAME) { bInterference = true ; return true ; } // negli altri casi ho un orientamento errato dei loop o delle regioni else return false ; } } // in questo la curva di bordo è interna ad ogni isola ma interna anche al loop esterno, quindi esiste interferenza bInterference = true ; return true ; } //---------------------------------------------------------------------------- bool SurfFlatRegion::CalcVoronoiObject() const { if ( m_nStatus != OK) return false ; // creo oggetto vroni con la superficie m_pVoronoiObj = new( std::nothrow) Voronoi( this, false) ; if ( m_pVoronoiObj == nullptr) return false ; return true ; } //---------------------------------------------------------------------------- void SurfFlatRegion::ResetVoronoiObject() const { if ( m_pVoronoiObj != nullptr) delete m_pVoronoiObj ; m_pVoronoiObj = nullptr ; } //--------------------------------------------------------------------------- bool SurfFlatRegion::CalcVoronoiDiagram( ICURVEPOVECTOR& vCrvs, int nBound) const { // verifico se è stato calcolato if ( m_pVoronoiObj == nullptr) if ( ! CalcVoronoiObject()) return false ; return m_pVoronoiObj->CalcVoronoiDiagram( vCrvs, nBound) ; } //---------------------------------------------------------------------------- bool SurfFlatRegion::CalcMedialAxis( ICURVEPOVECTOR& vCrvs, int nSide) const { // verifico se è stato calcolato if ( m_pVoronoiObj == nullptr) if ( ! CalcVoronoiObject()) return false ; return m_pVoronoiObj->CalcMedialAxis( vCrvs, nSide) ; } //---------------------------------------------------------------------------- bool SurfFlatRegion::GetChunkMaxOffset( int nChunk, double& dOffs) const { // verifico se è stato calcolato Voronoi if ( m_pVoronoiObj == nullptr) if ( ! CalcVoronoiObject()) return false ; // il massimo offset per il chunk è il massimo offset del suo loop esterno // ( il diagramma di Voronoi tiene già conto della limitazione con i loop interni) int nInd = GetIndFromChunkLoop( nChunk, 0) ; return m_pVoronoiObj->CalcLimitOffset( nInd, true, dOffs) ; } //---------------------------------------------------------------------------- bool SurfFlatRegion::GetMaxOffset( double& dOffs) const { int nChunks = GetChunkCount() ; if ( nChunks == 0) return false ; // calcolo il massimo fra gli offset limite di tutti i suoi chunks if ( ! GetChunkMaxOffset( 0, dOffs)) return false ; for ( int i = 1 ; i < nChunks ; i++) { double dCurrOffs ; if ( ! GetChunkMaxOffset( i, dCurrOffs)) return false ; if ( dCurrOffs > dOffs) dOffs = dCurrOffs ; } return true ; } //---------------------------------------------------------------------------- bool SurfFlatRegion::SetCurveTempProp( int nChunk, int nLoop, int nCrv, int nProp, int nPropInd) { ICurve* pLoop = GetMyLoop( nChunk, nLoop) ; if ( pLoop == nullptr) return false ; if ( pLoop->GetType() != CRV_COMPO) { if ( nCrv != 0) return false ; pLoop->SetTempProp( nProp, nPropInd) ; return true ; } return GetBasicCurveComposite( pLoop)->SetCurveTempProp( nCrv, nProp, nPropInd) ; } //---------------------------------------------------------------------------- bool SurfFlatRegion::GetCurveTempProp( int nChunk, int nLoop, int nCrv, int& nProp, int nPropInd) const { ICurve* pLoop = GetMyLoop( nChunk, nLoop) ; if ( pLoop == nullptr) return false ; if ( pLoop->GetType() != CRV_COMPO) { if ( nCrv != 0) return false ; nProp = pLoop->GetTempProp( nPropInd) ; return true ; } return GetBasicCurveComposite( pLoop)->GetCurveTempProp( nCrv, nProp, nPropInd) ; } //---------------------------------------------------------------------------- bool SurfFlatRegion::ResetAllCurveTempProps( void) { for ( int nC = 0 ; nC < GetChunkCount() ; ++ nC) { for ( int nL = 0 ; nL < GetLoopCount( nC) ; ++ nL) { ICurve* pLoop = GetMyLoop( nC, nL) ; if ( pLoop != nullptr) { if ( pLoop->GetType() != CRV_COMPO) { pLoop->SetTempProp( 0, 0) ; pLoop->SetTempProp( 0, 1) ; } else { CurveComposite* pCompoLoop = GetBasicCurveComposite( pLoop) ; for ( int nI = 0 ; nI < pCompoLoop->GetCurveCount() ; ++ nI) { pCompoLoop->SetCurveTempProp( nI, 0, 0) ; pCompoLoop->SetCurveTempProp( nI, 0, 1) ; } } } } } return true ; } //---------------------------------------------------------------------------- bool SurfFlatRegion::SetCurveTempParam( int nChunk, int nLoop, int nCrv, double dParam, int nParamInd) { ICurve* pLoop = GetMyLoop( nChunk, nLoop) ; if ( pLoop == nullptr) return false ; if ( pLoop->GetType() != CRV_COMPO) { if ( nCrv != 0) return false ; pLoop->SetTempParam( dParam, nParamInd) ; return true ; } return GetBasicCurveComposite( pLoop)->SetCurveTempParam( nCrv, dParam, nParamInd) ; } //---------------------------------------------------------------------------- bool SurfFlatRegion::GetCurveTempParam( int nChunk, int nLoop, int nCrv, double& dParam, int nParamInd) const { ICurve* pLoop = GetMyLoop( nChunk, nLoop) ; if ( pLoop == nullptr) return false ; if ( pLoop->GetType() != CRV_COMPO) { if ( nCrv != 0) return false ; dParam = pLoop->GetTempParam( nParamInd) ; return true ; } return GetBasicCurveComposite( pLoop)->GetCurveTempParam( nCrv, dParam, nParamInd) ; } //---------------------------------------------------------------------------- bool SurfFlatRegion::ResetAllCurveTempParams( void) { for ( int nC = 0 ; nC < GetChunkCount() ; ++ nC) { for ( int nL = 0 ; nL < GetLoopCount( nC) ; ++ nL) { ICurve* pLoop = GetMyLoop( nC, nL) ; if ( pLoop != nullptr) { if ( pLoop->GetType() != CRV_COMPO) { pLoop->SetTempParam( 0, 0) ; pLoop->SetTempParam( 0, 1) ; } else { CurveComposite* pCompoLoop = GetBasicCurveComposite( pLoop) ; for ( int nI = 0 ; nI < pCompoLoop->GetCurveCount() ; ++ nI) { pCompoLoop->SetCurveTempParam( nI, 0, 0) ; pCompoLoop->SetCurveTempParam( nI, 0, 1) ; } } } } } return true ; }