diff --git a/CalcPocketing.cpp b/CalcPocketing.cpp index 655785d..070a43f 100644 --- a/CalcPocketing.cpp +++ b/CalcPocketing.cpp @@ -3236,10 +3236,12 @@ CalcTrapezoidSpiralXCoord( const ICurveComposite* pCrvPocket, int nBase, int nSe for ( int i = 0 ; i < intCC2.GetIntersCount() ; ++ i) { IntCrvCrvInfo ccClass2 ; if ( intCC2.GetIntCrvCrvInfo( i, ccClass2)) { + double dDiffY = ccClass2.IciA[0].ptI.y - dYCoord ; + double dOffs = sqrt( dRad * dRad - dDiffY * dDiffY) ; if ( bStart) - dXCoord = max( dXCoord, Box3d.GetMax().x + sqrt( dRad * dRad - pow(( ccClass2.IciA[0].ptI.y - dYCoord), 2))) ; + dXCoord = max( dXCoord, Box3d.GetMax().x + dOffs) ; else - dXCoord = min( dXCoord, Box3d.GetMin().x - sqrt( dRad * dRad - pow(( ccClass2.IciA[0].ptI.y - dYCoord), 2))) ; + dXCoord = min( dXCoord, Box3d.GetMin().x - dOffs) ; } } } diff --git a/CurveAux.cpp b/CurveAux.cpp index 78f5258..d16938c 100644 --- a/CurveAux.cpp +++ b/CurveAux.cpp @@ -1068,9 +1068,9 @@ ApproxArcCurveBezierWithSingleCubic( const ICurveBezier* pCrvBez, const Point3d& double ay = ptStart.y - ptCen.y ; double bx = ptEnd.x - ptCen.x ; double by = ptEnd.y - ptCen.y ; - double q1 = pow( ax, 2) + pow( ay, 2) ; + double q1 = ax * ax + ay * ay ; double q2 = q1 + ax * bx + ay * by ; - double k2 = 4./3 * ( sqrt( 2 * q1 * q2) - q2) / ( ax * by - ay * bx) ; + double k2 = 4. / 3 * ( sqrt( 2 * q1 * q2) - q2) / ( ax * by - ay * bx) ; Point3d ptCtrl1, ptCtrl2 ; ptCtrl1.x = ptStart.x - k2 * ay ; ptCtrl1.y = ptStart.y + k2 * ax ; diff --git a/CurveBezier.cpp b/CurveBezier.cpp index b0b1824..4a5aa42 100644 --- a/CurveBezier.cpp +++ b/CurveBezier.cpp @@ -2274,17 +2274,17 @@ CurveBezier::MakeRationalStandardForm( void) { if ( ! m_bRat) return false ; - double dW0 = m_vWeCtrl[0] ; + double dW0 = m_vWeCtrl.front() ; double dWn = m_vWeCtrl.back() ; - if( dW0 > 1- EPS_ZERO && dWn > 1 - EPS_ZERO) + if ( dW0 > 1 - EPS_ZERO && dWn > 1 - EPS_ZERO) return true ; - if( dW0 < EPS_ZERO || dWn < EPS_ZERO) + if ( dW0 < EPS_ZERO || dWn < EPS_ZERO) return false ; - // formula del Farin + // formula del Farin double dCoeff = pow( dW0 / dWn, 1. / m_nDeg) ; for ( int i = 0 ; i < m_nDeg + 1 ; ++i) - m_vWeCtrl[i] *= pow( dCoeff, i) / dW0 ; + m_vWeCtrl[i] *= Pow( dCoeff, i) / dW0 ; return true ; } @@ -2293,13 +2293,13 @@ CurveBezier::MakeRationalStandardForm( void) bool CurveBezier::MakeNonRational( double dTol) { - if( ! m_bRat) + if ( ! m_bRat) return true ; // controllo se i pesi sono tutti == 1 allora è una finta razionale e mi basta fare una copia dei punti di controllo bool bIsActualRat = false ; for ( int i = 0 ; i < m_nDeg ; ++i) { - if ( abs(m_vWeCtrl[i] - 1) > EPS_SMALL) { + if ( abs( m_vWeCtrl[i] - 1) > EPS_SMALL) { bIsActualRat = true ; break ; } @@ -2323,8 +2323,8 @@ CurveBezier::MakeNonRational( double dTol) pNewBez->Init( nDeg, false) ; PNTVECTOR vPntCtrl ; PNTVECTOR vPntSampling ; - for ( int p = 0 ; p < nDeg + 1; ++p) { - Point3d pt ; GetPointD1D2( double(p) / nDeg, pt) ; + for ( int p = 0 ; p < nDeg + 1 ; ++p) { + Point3d pt ; GetPointD1D2( double( p) / nDeg, pt) ; pNewBez->SetControlPoint( p, pt) ; vPntCtrl.push_back( pt) ; } @@ -2334,8 +2334,8 @@ CurveBezier::MakeNonRational( double dTol) while ( dErr > dTol && c < 100) { double dErrMax = 0 ; // calcolo le differenze tra i punti di sampling sulla nuova curva e quelli sulla curva originale - for ( int p = 0 ; p < nDeg + 1; ++p) { - Point3d pt ; pNewBez->GetPointD1D2( double(p) / nDeg, pt) ; + for ( int p = 0 ; p < nDeg + 1 ; ++p) { + Point3d pt ; pNewBez->GetPointD1D2( double( p) / nDeg, pt) ; Vector3d vDiff = vPntSampling[p] - pt ; double dErrLoc = vDiff.Len() ; if( dErrLoc > dErrMax) @@ -2353,15 +2353,15 @@ CurveBezier::MakeNonRational( double dTol) // calcolo l'errore di approssimazione sulla curva CalcBezierApproxError( this, pNewBez, dErr) ; bOk = dErr < dTol ; - if( bOk) { + if ( bOk) { // aggiorno la curva di bezier originale con quella approssimata Init( nDeg, false) ; - for( int i = 0 ; i < nDeg + 1 ; ++i) { + for ( int i = 0 ; i < nDeg + 1 ; ++i) { SetControlPoint( i, pNewBez->GetControlPoint( i)) ; SetControlWeight( i, pNewBez->GetControlWeight( i)) ; } } - else if( nDeg < m_nDeg + 4) + else if ( nDeg < m_nDeg + 4) goto retry ; } diff --git a/SurfBezier.cpp b/SurfBezier.cpp index ee3a3aa..942021e 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -42,22 +42,34 @@ #include "/EgtDev/Include/EGkIntervals.h" #include "/EgtDev/Extern/Eigen/Dense" - using namespace std ; //---------------------------------------------------------------------------- GEOOBJ_REGISTER( SRF_BEZIER, NGE_S_BEZ, SurfBezier) ; -static bool ChangeStartForClosed( PolyLine& plU0, PolyLine& plU1, ICurveComposite* pCrvU0, ICurveComposite* pCrvU1) ; -static bool ParametrizeByLen( const ICurveComposite* pCurve, DBLVECTOR& vParam) ; -static bool BuildCommonParam( const DBLMATRIX& mParam, DBLVECTOR& vCommonParam) ; +//---------------------------------------------------------------------------- +static unordered_map s_mBernCache ; // mappa dei polinomi di bernstein +static double s_dAuxSurfTol = 200 * EPS_SMALL ; +static double s_dAuxSurfRefinedTol = 50 * EPS_SMALL ; -static unordered_map m_mBernCache ; // mappa dei polinomi di bernstein +//---------------------------------------------------------------------------- +void +SetSurfBezierAuxSurfTol( double dTol) +{ + s_dAuxSurfTol = max( dTol, EPS_SMALL) ; +} + +//---------------------------------------------------------------------------- +void +SetSurfBezierAuxSurfRefinedTol( double dTol) +{ + s_dAuxSurfRefinedTol = max( dTol, EPS_SMALL) ; +} //---------------------------------------------------------------------------- SurfBezier::SurfBezier( void) : m_pSTM( nullptr), m_pSTMRefined( nullptr), m_nStatus( TO_VERIFY), m_nDegU(), m_nDegV(), m_nSpanU(), m_nSpanV(), m_bRat( false), - m_bTrimmed( false), m_bClosedU( false), m_bClosedV( false), m_pTrimReg(nullptr), m_nTempProp{0,0}, m_dTempParam{0.0,0.0} + m_bTrimmed( false), m_bClosedU( false), m_bClosedV( false), m_pTrimReg( nullptr), m_nTempProp{0,0}, m_dTempParam{0.0,0.0}, m_nIsPlanar( -1) { } @@ -365,24 +377,26 @@ SurfBezier::GetCentroid( Point3d& ptCen) const return false ; // inizio con centro nell'origine ptCen = ORIG ; - // calcolo il baricentro - if ( m_pSTM == nullptr) - if ( ! GetAuxSurf()) - return false ; - return m_pSTM->GetCentroid( ptCen) ; + // calcolo il baricentro della superficie ausiliaria + GetAuxSurf() ; + if ( m_pSTM != nullptr) + return m_pSTM->GetCentroid( ptCen) ; + else + return false ; } //---------------------------------------------------------------------------- bool SurfBezier::GetBernstein( double dU, int nDegU, DBLVECTOR& vBernU) const { - INTINT key( nDegU, int( dU * pow(2,24))) ; - if ( m_mBernCache.find( key) == m_mBernCache.end()) { + const int TWO_TO_24 = 16777216 ; + INTINT key( nDegU, int( dU * TWO_TO_24)) ; + if ( s_mBernCache.find( key) == s_mBernCache.end()) { DBLVECTOR vBern( nDegU + 1) ; GetAllBernstein( dU, nDegU, vBern) ; - m_mBernCache[key] = vBern ; + s_mBernCache[key] = vBern ; } - vBernU = m_mBernCache[key] ; + vBernU = s_mBernCache[key] ; return true ; } @@ -741,42 +755,49 @@ SurfBezier::GetPointNrmD1D2( double dU, double dV, Side nUs, Side nVs, if ( vtN.Normalize()) return true ; - // se solo una delle due derivate è piccola, mi sposto lungo il relativo parametro e uso le tangenti + // se solo una sola delle due derivate è piccola, mi sposto lungo l'altro parametro if ( pvtDerU->Len() < EPS_SMALL && pvtDerV->Len() > 10 * EPS_SMALL) { - double dCoeff = ( dU - 1000 * EPS_PARAM < 0. ? 1 : -1) ; - double dUm = dU + 1000 * EPS_PARAM * dCoeff ; + double dVm = dV ; + if ( nVs == ISurfBezier::FROM_MINUS) + dVm = ( dV - 100 * EPS_PARAM < 0 ? dV + 100 * EPS_PARAM : dV - 100 * EPS_PARAM) ; + else + dVm = ( dV + 100 * EPS_PARAM > m_nSpanV ? dV - 100 * EPS_PARAM : dV + 100 * EPS_PARAM) ; Point3d ptTmp ; Vector3d vtTmpU, vtTmpV ; - GetPointD1D2( dUm, dV, nUs, nVs, ptTmp, &vtTmpU, &vtTmpV) ; - vtN = ( *pvtDerV ^ vtTmpV) * dCoeff ; + GetPointD1D2( dU, dVm, nUs, nVs, ptTmp, &vtTmpU, &vtTmpV) ; + vtN = vtTmpU ^ vtTmpV ; if ( vtN.Normalize()) return true ; } if ( pvtDerU->Len() > 10 * EPS_SMALL && pvtDerV->Len() < EPS_SMALL) { - double dCoeff = ( dV - 1000 * EPS_PARAM < 0. ? 1 : -1) ; - double dVm = dV + 1000 * EPS_PARAM * dCoeff ; + double dUm = dU ; + if ( nUs == ISurfBezier::FROM_MINUS) + dUm = ( dU - 100 * EPS_PARAM < 0 ? dU + 100 * EPS_PARAM : dU - 100 * EPS_PARAM) ; + else + dUm = ( dU + 100 * EPS_PARAM > m_nSpanU ? dU - 100 * EPS_PARAM : dU + 100 * EPS_PARAM) ; Point3d ptTmp ; Vector3d vtTmpU, vtTmpV ; - GetPointD1D2( dU, dVm, nUs, nVs, ptTmp, &vtTmpU, &vtTmpV) ; - vtN = ( vtTmpU ^ *pvtDerU) * dCoeff ; + GetPointD1D2( dUm, dV, nUs, nVs, ptTmp, &vtTmpU, &vtTmpV) ; + vtN = vtTmpU ^ vtTmpV ; if ( vtN.Normalize()) return true ; } // ricalcolo con una piccola variazione di entrambi i parametri - double dUm ; - if ( dU - 100 * EPS_PARAM < 0.) - dUm = dU + 100 * EPS_PARAM ; + double dUm = dU ; + if ( nUs == ISurfBezier::FROM_MINUS) + dUm = ( dU - 100 * EPS_PARAM < 0 ? dU + 100 * EPS_PARAM : dU - 100 * EPS_PARAM) ; else - dUm = dU - 100 * EPS_PARAM ; - double dVm ; - if ( dV - 100 * EPS_PARAM < 0.) - dVm = dV + 100 * EPS_PARAM ; + dUm = ( dU + 100 * EPS_PARAM > m_nSpanU ? dU - 100 * EPS_PARAM : dU + 100 * EPS_PARAM) ; + double dVm = dV ; + if ( nVs == ISurfBezier::FROM_MINUS) + dVm = ( dV - 100 * EPS_PARAM < 0 ? dV + 100 * EPS_PARAM : dV - 100 * EPS_PARAM) ; else - dVm = dV - 100 * EPS_PARAM ; + dVm = ( dV + 100 * EPS_PARAM > m_nSpanV ? dV - 100 * EPS_PARAM : dV + 100 * EPS_PARAM) ; Point3d ptTmp ; - GetPointD1D2( dUm, dVm, nUs, nVs, ptTmp, pvtDerU, pvtDerV) ; - vtN = *pvtDerU ^ *pvtDerV ; + Vector3d vtTmpU, vtTmpV ; + GetPointD1D2( dUm, dVm, nUs, nVs, ptTmp, &vtTmpU, &vtTmpV) ; + vtN = vtTmpU ^ vtTmpV ; return vtN.Normalize() ; } @@ -829,7 +850,7 @@ SurfBezier::CopyFrom( const SurfBezier& sbSrc) m_mCCEdge.back().emplace_back( sbSrc.m_mCCEdge[i][j]->Clone()) ; } } - if( sbSrc.m_bTrimmed) { + if ( sbSrc.m_bTrimmed) { for ( int i = 0 ; i < int( sbSrc.m_vCCLoop.size()) ; ++i) m_vCCLoop.emplace_back( sbSrc.m_vCCLoop[i]->Clone()); } @@ -1679,11 +1700,21 @@ SurfBezier::GetAuxSurf( void) const ResetAuxSurf() ; return nullptr ; } - // se già calcolata, la restituisco - if ( m_pSTM != nullptr) - return m_pSTM ; + // se già calcolata + if ( m_pSTM != nullptr) { + // se con la stessa tolleranza, la restituisco + if ( abs( s_dAuxSurfTol - m_pSTM->GetTempParam()) < EPS_SMALL) + return m_pSTM ; + // altrimenti la cancello prima di ricalcolarla + else { + delete( m_pSTM) ; + m_pSTM = nullptr ; + } + } // eseguo calcolo - m_pSTM = GetApproxSurf( 1000 * EPS_SMALL, 100 * EPS_SMALL) ; + m_pSTM = GetApproxSurf( s_dAuxSurfTol, 100 * EPS_SMALL) ; + if ( m_pSTM != nullptr) + m_pSTM->SetTempParam( s_dAuxSurfTol) ; return m_pSTM ; } @@ -1697,10 +1728,20 @@ SurfBezier::GetAuxSurfRefined( void) const return nullptr ; } // se già calcolata, la restituisco - if ( m_pSTMRefined != nullptr) - return m_pSTMRefined ; + if ( m_pSTMRefined != nullptr) { + // se con la stessa tolleranza, la restituisco + if ( abs( s_dAuxSurfRefinedTol - m_pSTMRefined->GetTempParam()) < EPS_SMALL) + return m_pSTMRefined ; + // altrimenti la cancello prima di ricalcolarla + else { + delete( m_pSTMRefined) ; + m_pSTMRefined = nullptr ; + } + } // eseguo calcolo - m_pSTMRefined = GetApproxSurf( 50 * EPS_SMALL, 100 * EPS_SMALL) ; + m_pSTMRefined = GetApproxSurf( s_dAuxSurfRefinedTol, 100 * EPS_SMALL) ; + if ( m_pSTMRefined != nullptr) + m_pSTMRefined->SetTempParam( s_dAuxSurfRefinedTol) ; return m_pSTMRefined ; } @@ -1714,11 +1755,11 @@ SurfBezier::GetApproxSurf( double dTol, double dSideMin) const // se c'è ausiliaria di visualizzazione con gli stessi parametri, ne restituisco una copia if ( m_pSTM != nullptr && - abs( dTol - 1000 * EPS_SMALL) < EPS_SMALL && abs( dSideMin - 100 * EPS_SMALL) < EPS_SMALL) + abs( dTol - s_dAuxSurfTol) < EPS_SMALL && abs( dSideMin - 100 * EPS_SMALL) < EPS_SMALL) return m_pSTM->Clone() ; // se c'è ausiliaria e richiesta con gli stessi parametri, ne restituisco una copia if ( m_pSTMRefined != nullptr && - abs( dTol - 50 * EPS_SMALL) < EPS_SMALL && abs( dSideMin - 100 * EPS_SMALL) < EPS_SMALL) + abs( dTol - s_dAuxSurfRefinedTol) < EPS_SMALL && abs( dSideMin - 100 * EPS_SMALL) < EPS_SMALL) return m_pSTMRefined->Clone() ; // costruttore della superficie @@ -1726,28 +1767,18 @@ SurfBezier::GetApproxSurf( double dTol, double dSideMin) const POLYLINEMATRIX vvPL3d ; //POLYLINEVECTOR vPL ; // per usare i polygon basic Tree Tree ; - if ( ! Tree.SetSurf( this, true)) + if ( ! Tree.SetSurf( this)) return nullptr ; BIPNTVECTOR vTrees ; Tree.GetIndependentTrees( vTrees) ; - bool bTest = false ; // per debug // resetto il vettore degli edge m_mCCEdge.clear() ; m_vCCLoop.clear() ; for ( int i = 0 ; i < (int) vTrees.size() ; ++ i) { Point3d ptMin = get<0>( vTrees[i]) ; Point3d ptMax = get<1>( vTrees[i]) ; - Tree.SetSurf( this, true, ptMin, ptMax) ; - if ( bTest) { - Tree.BuildTree_test() ; // per debug - //Tree.BuildTree( 5 * LIN_TOL_FINE, 1) ; // per debug - Tree.SetTestMode() ; - } - else { - //Tree.BuildTree( 5 * LIN_TOL_FINE, 0.1) ; - Tree.BuildTree( dTol, dSideMin) ; - //Tree.BuildTree( 1, 5) ; //debug - } + Tree.SetSurf( this, ptMin, ptMax) ; + Tree.BuildTree( dTol, dSideMin) ; if ( ! Tree.GetPolygons( vvPL, vvPL3d, m_mCCEdge, m_vCCLoop)) continue ; //Tree.GetPolygonsBasic( vPL, true) ; // per usare i polygon basic @@ -1787,18 +1818,18 @@ SurfBezier::GetApproxSurf( double dTol, double dSideMin) const POLYLINEVECTOR vPL3d = vvPL3d[c] ; PNTVECTOR vPnt3d ; - for( int i = 0 ; i < int( vPL3d.size()) ; ++i) { + for ( int i = 0 ; i < int( vPL3d.size()) ; ++i) { PolyLine& pl3d = vPL3d[i] ; Point3d pt3d ; pl3d.GetFirstPoint( pt3d) ; - if( vPL3d.size() > 1) + if ( vPL3d.size() > 1) vPnt3d.push_back( pt3d) ; while ( pl3d.GetNextPoint( pt3d)) { vPnt3d.push_back( pt3d) ; } } - // se ho ottenuto meno triangoli di quelli che avrei dovuto avere allora potrei aver avuto un problema in prossimità di un polo - // se comunque ho corrispondenza tra vPnt e vPnt3d allora eseguo la trinagolazione in 3d + // se ho ottenuto meno triangoli di quelli che avrei dovuto avere allora potrei aver avuto un problema in prossimità di un polo + // se comunque ho corrispondenza tra vPnt e vPnt3d allora eseguo la trinagolazione in 3d int nTriaNumber = ( vPnt.size() - 2) + (2 * (vPL.size() - 1)) - (vPL.size() > 2 ? vPL.size() - 2 : 0) - (vPL.size() != 1 ? vPL.size() : 0) ; bool bTriangulationFailedIn2D = nTriaNumber != ( vTria.size()) / 3 ; //bool bMismatch2D3D = vPnt.size() != vPnt3d.size() ; @@ -1810,13 +1841,13 @@ SurfBezier::GetApproxSurf( double dTol, double dSideMin) const if ( ! Tri.Make( vPL3d, vPnt, vTria)) bTriangulationSucceded = false ; bTriangulationSucceded = bTriangulationSucceded && ( vPnt.size() - 2) + (2 * (vPL.size() - 1)) - (vPL.size() > 2 ? vPL.size() - 2 : 0) - (vPL.size() != 1 ? vPL.size() : 0) == ( vTria.size() ) / 3 ; - if( bTriangulationFailedIn2D) { + if ( bTriangulationFailedIn2D) { if ( bTriangulationSucceded) LOG_INFO( GetEGkLogger(), "Info : Last problem in MakeByEC23(1) RESOLVED") else LOG_INFO( GetEGkLogger(), "Info : This problem in MakeByEC23(1) is the same as the previous one") } - if( bTriangulationSucceded) { + if ( bTriangulationSucceded) { bTriangulatedIn3D = true ; // calcolo la normale della polyline per flippare eventualmente i triangoli se hanno la normale sbagliata PolyLine& pl3d = vPL3d[0] ; @@ -1825,7 +1856,7 @@ SurfBezier::GetApproxSurf( double dTol, double dSideMin) const Vector3d vtN = plPlane.GetVersN() ; Triangle3d tria ; tria.Set( vPnt[vTria[0]], vPnt[vTria[1]], vPnt[vTria[2]]) ; - if( tria.GetN() * vtN < 0) + if ( tria.GetN() * vtN < 0) reverse( vTria.begin(), vTria.end()) ; } else { @@ -1835,11 +1866,11 @@ SurfBezier::GetApproxSurf( double dTol, double dSideMin) const } // riordino il vettore dei punti su cui non ho fatto la triangolazione - if( int(vPL.size()) == 2) { + if ( vPL.size() == 2) { //if( vPnt.size() != vPnt3d.size()) // return nullptr ; PNTVECTOR vPntOrd ; - if( bTriangulatedIn3D) { + if ( bTriangulatedIn3D) { ReorderPntVector( vPL3d, true, vPnt, vPL, vPntOrd) ; vPnt3d = vPnt ; vPnt = vPntOrd ; @@ -1850,7 +1881,7 @@ SurfBezier::GetApproxSurf( double dTol, double dSideMin) const } } else if ( bTriangulatedIn3D) { - if( vPL.size() == 1) { + if ( vPL.size() == 1) { vPnt3d = vPnt ; PNTVECTOR vPnt2d ; for( int i = 0 ; i < int( vPL.size()) ; ++i) { @@ -1871,9 +1902,9 @@ SurfBezier::GetApproxSurf( double dTol, double dSideMin) const } } - //controllo che i due vettori vPnt e vPnt3d abbiano la stessa lunghezza, sennò vuol dire che nel vettore vPnt3d ho avuto dei Rejected e devo ricalcolarli - // i punti in eccesso verranno poi scartati dalla trimesh - if( vPnt.size() != vPnt3d.size()) { + // controllo che i due vettori vPnt e vPnt3d abbiano la stessa lunghezza, sennò vuol dire che nel vettore vPnt3d ho avuto dei Rejected e devo ricalcolarli + // i punti in eccesso verranno poi scartati dalla trimesh + if ( vPnt.size() != vPnt3d.size()) { vPnt3d.clear() ; for ( int i = 0 ; i < int( vPnt.size()) ; ++ i) { Point3d pt3d ; @@ -2029,23 +2060,15 @@ bool SurfBezier::GetLeaves( vector>& vLeaves) const { Tree Tree ; - if ( ! Tree.SetSurf( this, true)) + if ( ! Tree.SetSurf( this)) return false ; BIPNTVECTOR vTrees ; Tree.GetIndependentTrees( vTrees) ; for ( int i = 0 ; i < int( vTrees.size()) ; ++ i) { Point3d ptMin = get<0>( vTrees[i]) ; Point3d ptMax = get<1>( vTrees[i]) ; - Tree.SetSurf( this, true, ptMin, ptMax) ; - bool bTest = false ; // per debug - if ( bTest) { - Tree.BuildTree_test() ; // per debug - //Tree.BuildTree( 5 * LIN_TOL_FINE, 1) ; // per debug - } - else { - //Tree.BuildTree( 100 * LIN_TOL_FINE, 0.1) ; - Tree.BuildTree( 5 * LIN_TOL_FINE, 0.1) ; - } + Tree.SetSurf( this, ptMin, ptMax) ; + Tree.BuildTree( s_dAuxSurfTol, 100 * EPS_SMALL) ; vector vCells ; Tree.GetLeaves( vCells) ; for ( int k = 0 ; k < int( vCells.size()) ; ++ k) { @@ -2825,7 +2848,7 @@ SurfBezier::UnprojectPointFromStm( int nT, const Point3d& ptI, Point3d& ptSP, in for ( int i = 0 ; i < int( m_mCCEdge[c].size()) ; ++i) { if ( ! m_mCCEdge[c][i]->IsValid()) { Point3d pt ; - if ( ! m_mCCEdge[c][i]->GetOnlyPoint(pt)) + if ( ! m_mCCEdge[c][i]->GetOnlyPoint( pt)) return false ; vInters[c] = AreSamePointApprox( pt, ptI) ? 1 : 0 ; if ( vInters[c] == 1) @@ -3177,8 +3200,8 @@ SurfBezier::UnprojectPoint( const Point3d& pt3D, Point3d& ptParam, const Point3d } // calcolo le nuove coordinate Vector3d vtDir ; - double dASum = abs(dfdU) + abs(dfdV) ; - double dSSum = sqrt( pow(dfdU,2) + pow( dfdV,2)) ; + double dASum = abs( dfdU) + abs( dfdV) ; + double dSSum = sqrt( dfdU * dfdU + dfdV * dfdV) ; vtDir.Set( - dfdU, - dfdV, 0) ; if ( ! vtDir.Normalize() ) vtDir.Set( - dfdU / dSSum, - dfdV / dSSum, 0) ; @@ -4191,8 +4214,8 @@ SurfBezier::CreateByPointCurve( const Point3d& pt, const ICurve* pCurve) return false ; // recupero span e grado nel parametro U int nSpanU = int( CrvU.GetCurveCount()) ; - int nDegU = ( GetCurveBezier( CrvU.GetCurve(0)))->GetDegree() ; - bool bRat = (GetCurveBezier( CrvU.GetCurve(0)))->IsRational() ; + int nDegU = GetCurveBezier( CrvU.GetCurve(0))->GetDegree() ; + bool bRat = GetCurveBezier( CrvU.GetCurve(0))->IsRational() ; // in V decido che la funzione è una patch di grado 1 int nSpanV = 1 ; int nDegV = 1 ; @@ -4219,6 +4242,52 @@ SurfBezier::CreateByPointCurve( const Point3d& pt, const ICurve* pCurve) return true ; } +//---------------------------------------------------------------------------- +static bool +ChangeStartForClosed( PolyLine& plU0, PolyLine& plU1, ICurveComposite* pCrvU0, ICurveComposite* pCrvU1) { + // se sono chiuse devo controllare che gli start siano il più allineati possibile, se non lo sono cambio gli start + if ( plU0.IsClosed() && plU1.IsClosed()) { + vector> vDistVert ; + tuple tMatch ; + Point3d pt0 ; + bool bOk0 = plU0.GetFirstPoint( pt0) ; + int c0 = 0 ; + double dMinDist = INFINITO ; + while ( bOk0) { + Point3d pt1 ; + bool bOk1 = plU1.GetFirstPoint( pt1) ; + int c1 = 0 ; + while ( bOk1) { + double dDist = Dist( pt0, pt1) ; + if ( dDist < dMinDist) { + tMatch = make_tuple( dDist, c0, pt0, c1, pt1) ; + dMinDist = dDist ; + } + ++c1 ; + bOk1 = plU1.GetNextPoint( pt1) ; + } + vDistVert.push_back( tMatch) ; + dMinDist = INFINITO ; + c1 = 0 ; + ++c0 ; + bOk0 = plU0.GetNextPoint( pt0) ; + } + int nMin = 0 ; + dMinDist = INFINITO ; + for ( int i = 0 ; i < int( vDistVert.size()) ; ++i) { + if( get<0>(vDistVert[i]) < dMinDist) { + dMinDist = get<0>(vDistVert[i]) ; + nMin = i ; + } + } + ChangePolyLineStart(plU0, get<2>(vDistVert[nMin]), EPS_SMALL) ; + ChangePolyLineStart(plU1, get<4>(vDistVert[nMin]), EPS_SMALL) ; + pCrvU0->ChangeStartPoint( double( get<1>(vDistVert[nMin]))) ; + pCrvU1->ChangeStartPoint( double( get<3>(vDistVert[nMin]))) ; + } + return true ; +} + //---------------------------------------------------------------------------- bool SurfBezier::CreateByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, int nRuledType) @@ -5098,52 +5167,6 @@ SplitByCommonParam( ICURVEPOVECTOR& vCrvBezUnif, DBLVECTOR& vCommonParam, DBLMAT return true ; } -static bool -ChangeStartForClosed( PolyLine& plU0, PolyLine& plU1, ICurveComposite* pCrvU0, ICurveComposite* pCrvU1) { - // se sono chiuse devo controllare che gli start siano il più allineati possibile, se non lo sono cambio gli start - if ( plU0.IsClosed() && plU1.IsClosed()) { - vector> vDistVert ; - tuple tMatch ; - Point3d pt0 ; - bool bOk0 = plU0.GetFirstPoint( pt0) ; - int c0 = 0 ; - double dMinDist = INFINITO ; - while ( bOk0) { - Point3d pt1 ; - bool bOk1 = plU1.GetFirstPoint( pt1) ; - int c1 = 0 ; - while ( bOk1) { - double dDist = Dist( pt0, pt1) ; - if ( dDist < dMinDist) { - tMatch = make_tuple( dDist, c0, pt0, c1, pt1) ; - dMinDist = dDist ; - } - ++c1 ; - bOk1 = plU1.GetNextPoint( pt1) ; - } - vDistVert.push_back( tMatch) ; - dMinDist = INFINITO ; - c1 = 0 ; - ++c0 ; - bOk0 = plU0.GetNextPoint( pt0) ; - } - int nMin = 0 ; - dMinDist = INFINITO ; - for ( int i = 0 ; i < int( vDistVert.size()) ; ++i) { - if( get<0>(vDistVert[i]) < dMinDist) { - dMinDist = get<0>(vDistVert[i]) ; - nMin = i ; - } - } - ChangePolyLineStart(plU0, get<2>(vDistVert[nMin]), EPS_SMALL) ; - ChangePolyLineStart(plU1, get<4>(vDistVert[nMin]), EPS_SMALL) ; - pCrvU0->ChangeStartPoint( double( get<1>(vDistVert[nMin]))) ; - pCrvU1->ChangeStartPoint( double( get<3>(vDistVert[nMin]))) ; - } - return true ; -} - - //---------------------------------------------------------------------------- bool SurfBezier::CreateBySetOfCurves( const ICURVEPOVECTOR& vCrvBez, bool bReduceToDeg3) @@ -5311,7 +5334,7 @@ SurfBezier::CreateBySetOfCurves( const ICURVEPOVECTOR& vCrvBez, bool bReduceToDe Point3d pt2 = ptP2 ; pt2.ToLoc( frParab) ; Eigen::Matrix3d mA ; - mA.col(0) << pow(pt0.x,2), pow(pt1.x,2) , pow(pt2.x,2) ; + mA.col(0) << pt0.x * pt0.x, pt1.x * pt1.x, pt2.x * pt2.x ; mA.col(1) << pt0.x, pt1.x , pt2.x ; mA.col(2) << 1, 1, 1 ; if( abs( mA.determinant()) < EPS_SMALL) diff --git a/SurfBezier.h b/SurfBezier.h index d02a7cd..e3432da 100644 --- a/SurfBezier.h +++ b/SurfBezier.h @@ -82,10 +82,10 @@ class SurfBezier : public ISurfBezier, public IGeoObjRW bool GetVolume( double& dVolume) const override { if ( &dVolume == nullptr) return false ; - if( m_pSTM == nullptr) + if ( m_pSTM == nullptr) GetAuxSurf() ; dVolume = 0 ; - if( m_pSTM != nullptr) + if ( m_pSTM != nullptr) m_pSTM->GetVolume( dVolume) ; return true ; } bool GetCentroid( Point3d& ptCen) const override ; diff --git a/Tree.cpp b/Tree.cpp index 5064b47..0b7c94c 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -21,12 +21,13 @@ #include "SurfFlatRegion.h" #include "IntersLineLine.h" #include "AdjustLoops.h" -#include "/EgtDev/Include/EGkDistLineLine.h" #include "/EgtDev/Include/EGkPolyLine.h" -#include "/EgtDev/Include/EGkDistPointCurve.h" #include "/EgtDev/Include/EGkCurve.h" -#include "DistPointCrvComposite.h" #include "/EgtDev/Include/EGkSfrCreate.h" +#include "/EgtDev/Include/EGkDistPointCurve.h" +#include "/EgtDev/Include/EGkDistLineLine.h" +#include "/EgtDev/Include/EGkDistPointTria.h" +#include "/EgtDev/Include/EGkStringUtils3d.h" #include #include @@ -34,8 +35,8 @@ using namespace std ; //---------------------------------------------------------------------------- Tree::Tree( void) - : m_pSrfBz( nullptr), m_bTrimmed( false), m_bBilinear( false), m_bMulti( false), m_bClosedU( false), m_bClosedV( false), m_vbPole( { false, false, false, false}), - m_bSplitPatches( true), m_bTestMode( false) + : m_pSrfBz( nullptr), m_bTrimmed( false), m_bBilinear( false), m_bMulti( false), m_bClosedU( false), m_bClosedV( false), + m_vbPole{ false, false, false, false} { Point3d ptBl( 0, 0), ptTr ( 1 * SBZ_TREG_COEFF, 1 * SBZ_TREG_COEFF) ; Cell cRoot( ptBl, ptTr) ; @@ -49,8 +50,8 @@ Tree::~Tree( void) //---------------------------------------------------------------------------- Tree::Tree( const Point3d ptBl, const Point3d ptTr) - : m_pSrfBz( nullptr), m_bTrimmed( false), m_bBilinear( false), m_bMulti( false), m_bClosedU( false), m_bClosedV( false), m_vbPole( { false, false, false, false}), - m_bSplitPatches( true), m_bTestMode( false) + : m_pSrfBz( nullptr), m_bTrimmed( false), m_bBilinear( false), m_bMulti( false), m_bClosedU( false), m_bClosedV( false), + m_vbPole{ false, false, false, false} { Cell cRoot( ptBl, ptTr) ; m_mTree.insert( pair< int, Cell>( -1, cRoot)) ; @@ -101,32 +102,40 @@ Tree::AdjustLoop( PolyLine& pl, POLYLINEVECTOR& vPl, BOOLVECTOR& vbOrientation) } //---------------------------------------------------------------------------- -bool -Tree::GetPoint( double dU, double dV, Point3d& pt) const +static double +GetHalfKey( double dPar) { - pair key (static_cast(dU * pow(2,15)), static_cast(dV * pow(2,15))) ; + const int TWO_TO_15 = 32768 ; + return ( dPar * TWO_TO_15) ; +} + +//---------------------------------------------------------------------------- +bool +Tree::GetPoint( double dU, double dV, Point3d& ptP) const +{ + pair key( int64_t( GetHalfKey( dU)), int64_t( GetHalfKey( dV))) ; bool bOk = true ; if ( m_mPt3d.find( key) == m_mPt3d.end()) { - bOk = bOk && m_pSrfBz->GetPoint( dU / SBZ_TREG_COEFF, dV / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt) ; - m_mPt3d[key] = pt ; + bOk = bOk && m_pSrfBz->GetPoint( dU / SBZ_TREG_COEFF, dV / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP) ; + m_mPt3d[key] = ptP ; } - pt = m_mPt3d[key] ; + ptP = m_mPt3d[key] ; return bOk ; } //---------------------------------------------------------------------------- bool -Tree::SavePoint( double dU, double dV, Point3d& pt) +Tree::SavePoint( double dU, double dV, Point3d& ptP) { - pair key (static_cast(dU * pow(2,15)), static_cast(dV * pow(2,15))) ; + pair key( int64_t( GetHalfKey( dU)), int64_t( GetHalfKey( dV))) ; if ( m_mPt3d.find( key) == m_mPt3d.end()) - m_mPt3d[key] = pt ; + m_mPt3d[key] = ptP ; return true ; } //---------------------------------------------------------------------------- bool -Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMin, const Point3d& ptMax) +Tree::SetSurf( const SurfBezier* pSrfBz, const Point3d& ptMin, const Point3d& ptMax) { if ( pSrfBz == nullptr || ! pSrfBz->IsValid()) return false ; @@ -140,7 +149,6 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi m_vCCLoop2D.clear() ; m_pSrfBz = pSrfBz ; - m_bSplitPatches = bSplitPatches ; // le coordinate delle celle sono nello spazio parametrico int nDegU, nDegV, nSpanU, nSpanV ; bool bIsRat, bTrimmed ; @@ -230,43 +238,52 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi // se richiesto divido preliminarmente le patches m_vnParents.clear() ; bool bIsPlanar = m_pSrfBz->IsPlanar() ; - if( ! bIsPlanar || m_bMulti) { - // se la superficie è chiusa lungo il parametro U, sistemo le adiacenze al bordo - if ( AreSamePointApprox(ptP00, ptP10) && AreSamePointApprox(ptP01, ptP11) ) { - m_mTree[-1].m_nLeft = -1 ; - m_mTree[-1].m_nRight = -1 ; - m_bClosedU = true ; + if ( ! bIsPlanar || m_bMulti) { + // se la superficie è chiusa lungo il parametro U, sistemo le adiacenze al bordo + if ( AreSamePointApprox( ptP00, ptP10) && AreSamePointApprox( ptP01, ptP11) ) { + Point3d ptP0001 ; + GetPoint( ptMin.x, ( ptMin.y + ptTop.y) / 2, ptP0001) ; + Point3d ptP1011 ; + GetPoint( ptTop.x, ( ptMin.y + ptTop.y) / 2, ptP1011) ; + if ( AreSamePointApprox( ptP0001, ptP1011)) { + m_mTree[-1].m_nLeft = -1 ; + m_mTree[-1].m_nRight = -1 ; + m_bClosedU = true ; + } } - // se la superficie è chiusa lungo il parametro V, sistemo le adiacenze al bordo - if ( ( AreSamePointApprox(ptP00, ptP01) && AreSamePointApprox(ptP10, ptP11) ) ) { - m_mTree[-1].m_nTop = -1 ; - m_mTree[-1].m_nBottom = -1 ; - m_bClosedV = true ; + // se la superficie è chiusa lungo il parametro V, sistemo le adiacenze al bordo + if ( ( AreSamePointApprox( ptP00, ptP01) && AreSamePointApprox( ptP10, ptP11) ) ) { + Point3d ptP0010 ; + GetPoint( ( ptMin.x + ptTop.x) / 2, ptMin.y, ptP0010) ; + Point3d ptP0111 ; + GetPoint( (ptMin.x + ptTop.x) / 2, ptTop.y, ptP0111) ; + if ( AreSamePointApprox( ptP0010, ptP0111)) { + m_mTree[-1].m_nTop = -1 ; + m_mTree[-1].m_nBottom = -1 ; + m_bClosedV = true ; + } } - if ( (m_bSplitPatches && ( nSpanU > 1 || nSpanV > 1)) || m_bClosedU || m_bClosedV) { + if ( nSpanU > 1 || nSpanV > 1 || m_bClosedU || m_bClosedV) { int nId = -1 ; int nSplit = nSpanU ; bool bSplitInHalf = false ; - // se la superficie è chiusa lungo un parametro la splitto lungo quel parametro almeno una volta - if( m_bClosedU && nSpanU == 1) { + // se la superficie è chiusa lungo un parametro la splitto lungo quel parametro almeno una volta + if ( m_bClosedU && nSpanU == 1) { nSplit = 2 ; bSplitInHalf = true ; } for ( int i = 1 ; i < nSplit ; ++i) { m_mTree[nId].SetSplitDirVert( true) ; - double dSplit = bSplitInHalf ? i * SBZ_TREG_COEFF / 2 : i * SBZ_TREG_COEFF ; - if ( Split( nId, dSplit)) { - //++ nId ; - //++ nId ; + double dSplit = ( bSplitInHalf ? i * SBZ_TREG_COEFF / 2 : i * SBZ_TREG_COEFF) ; + if ( Split( nId, dSplit)) nId = m_mTree[nId].m_nChild2 ; - } } INTVECTOR vLeaves ; GetHeightLeaves( -1, vLeaves) ; nSplit = nSpanV - 1 ; bSplitInHalf = false ; - // se la superficie è chiusa lungo un parametro la splitto lungo quel parametro almeno una volta - if( m_bClosedV && nSpanV == 1) { + // se la superficie è chiusa lungo un parametro la splitto lungo quel parametro almeno una volta + if ( m_bClosedV && nSpanV == 1) { nSplit = 1 ; bSplitInHalf = true ; } @@ -284,20 +301,8 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi // se è chiusa e non ho già fatto split preliminare, splitto sul parametro su cui è chiusa // e sistemo le adiacenze if ( ( AreSamePointApprox( ptP00, ptP01) || AreSamePointApprox( ptP10, ptP11)) || - ( AreSamePointApprox( ptP00, ptP10) || AreSamePointApprox( ptP01, ptP11))) { + ( AreSamePointApprox( ptP00, ptP10) || AreSamePointApprox( ptP01, ptP11))) { if ( ( AreSamePointApprox( ptP00, ptP01) || AreSamePointApprox( ptP10, ptP11))) { - - ////questo in teoria non serve più perché lo faccio appena sopra - if( int( m_mTree.size()) == 1) { - if ( AreSamePointApprox( ptP00, ptP01) && AreSamePointApprox( ptP10, ptP11)) { - m_mTree[-1].m_nTop = -1 ; - m_mTree[-1].m_nBottom = -1 ; - m_bClosedV = true ; - } - m_mTree[-1].SetSplitDirVert( false) ; - Split( -1) ; - } - //////// // qui devo fare il controllo capped ( chiusura a semisfera) // devo controllare se i punti ai parametri U=0 e U=1 sono tutti coincidenti @@ -314,7 +319,7 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi } m_vbPole[1] = bPole0 ; m_vbPole[3] = bPole1 ; - if ( bPole0 && bPole1 && int( m_mTree.size() == 3)) { + if ( bPole0 && bPole1 && m_mTree.size() == 3) { m_mTree[0].SetSplitDirVert( true) ; Split( 0) ; m_mTree[1].SetSplitDirVert( true) ; @@ -323,29 +328,16 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi } // nella condizione di questo if non controllo eventuali divisioni preliminari, perché ne tengo conto dopo if ( AreSamePointApprox( ptP00, ptP10) || AreSamePointApprox( ptP01, ptP11)) { - - //// questo in teoria non serve più perché lo faccio sopra - if ( m_mTree.size() == 1) { - if ( AreSamePointApprox( ptP00, ptP10) && AreSamePointApprox( ptP01, ptP11)) { - m_mTree[-1].m_nLeft = -1 ; - m_mTree[-1].m_nRight = -1 ; - m_bClosedU = true ; - } - m_mTree[-1].SetSplitDirVert( true) ; - Split( -1) ; - } - //////// - // devo controllare se i punti ai parametri V=0 e V=1 sono tutti coincidenti - // in caso devo fare uno split nell'altra direzione + // devo controllare se i punti ai parametri V=0 e V=1 sono tutti coincidenti + // in caso devo fare uno split nell'altra direzione bool bOk = false ; bool bPole0 = true, bPole1 = true ; - Point3d ptV0, ptV1 ; - // controllo se tutti i punti sull'isoparametrica sono uguali + // controllo se tutti i punti sull'isoparametrica sono uguali for ( int i = 1 ; i < nDegU * nSpanU + 1 ; ++ i) { - ptV0 = m_pSrfBz->GetControlPoint( i, &bOk) ; + Point3d ptV0 = m_pSrfBz->GetControlPoint( i, &bOk) ; bPole0 = bPole0 && AreSamePointApprox( ptP00, ptV0) ; - ptV1 = m_pSrfBz->GetControlPoint( i + ( nDegU * nSpanU + 1) * ( nDegV * nSpanV), &bOk) ; + Point3d ptV1 = m_pSrfBz->GetControlPoint( i + ( nDegU * nSpanU + 1) * ( nDegV * nSpanV), &bOk) ; bPole1 = bPole1 && AreSamePointApprox( ptP01, ptV1) ; } m_vbPole[0] = bPole1 ; @@ -357,7 +349,7 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi Split( 1) ; } // se ho fatto solo 1 split orizzontale e ho due celle foglie nId = 0 e nId = 1 - if ( int( m_mTree.size() == 3) && ! m_mTree.at(-1).IsSplitVert()) { + if ( m_mTree.size() == 3 && ! m_mTree.at(-1).IsSplitVert()) { m_mTree[0].m_nLeft = -1 ; m_mTree[0].m_nRight = -1 ; m_mTree[1].m_nLeft = -1 ; @@ -370,41 +362,11 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi } } } - // calcolo i parent che ho creato con le eventuali divisioni preliminari + // calcolo i parent che ho creato con le eventuali divisioni preliminari INTVECTOR vLeaves ; GetHeightLeaves( -1, vLeaves) ; m_vnParents = vLeaves ; - - // calcolo e salvo la lunghezza reale delle curve di bezier di bordo - PtrOwner pCrvV0( m_pSrfBz->GetCurveOnU( 0)) ; - PtrOwner pCrvV1( m_pSrfBz->GetCurveOnU( double(nSpanV))) ; - PtrOwner pCrvU0( m_pSrfBz->GetCurveOnV( 0)) ; - PtrOwner pCrvU1( m_pSrfBz->GetCurveOnV( double(nSpanU))) ; - double dLen0 ; pCrvV0->GetApproxLength( dLen0) ; - double dLen1 ; pCrvU1->GetApproxLength( dLen1) ; - double dLen2 ; pCrvV1->GetApproxLength( dLen2) ; - double dLen3 ; pCrvU0->GetApproxLength( dLen3) ; - if ( dLen0 < EPS_ZERO && dLen2 < EPS_ZERO ) { - PtrOwner pCrvV( m_pSrfBz->GetCurveOnU( double(nSpanV) / 2)) ; - pCrvV->GetApproxLength( dLen0) ; - if ( dLen0 < EPS_ZERO ) { - pCrvV.Set( m_pSrfBz->GetCurveOnU( double(nSpanV) / 4)) ; - pCrvV->GetApproxLength( dLen0) ; - } - } - if ( dLen1 < EPS_ZERO && dLen3 < EPS_ZERO ) { - PtrOwner pCrvU( m_pSrfBz->GetCurveOnV( double(nSpanU) / 2)) ; - pCrvU->GetApproxLength( dLen1) ; - if ( dLen1 < EPS_ZERO ) { - pCrvU.Set( m_pSrfBz->GetCurveOnV( double(nSpanU) / 4)) ; - pCrvU->GetApproxLength( dLen1) ; - } - } - m_vDim.clear() ; - m_vDim.push_back( ( dLen0 > EPS_ZERO ? dLen0 : 1)) ; - m_vDim.push_back( ( dLen1 > EPS_ZERO ? dLen1 : 1)) ; - m_vDim.push_back( ( dLen2 > EPS_ZERO ? dLen2 : 1)) ; - m_vDim.push_back( ( dLen3 > EPS_ZERO ? dLen3 : 1)) ; + return true ; } @@ -419,7 +381,7 @@ AddOrMergeBBox( const BBox3d& bBox3dA, vector& vBBox, bool bAdd = true, return true ; } bool bAdded = false ; - for ( int b = 0 ; b < (int)vBBox.size() ; ++b) { + for ( int b = 0 ; b < int( vBBox.size()) ; ++b) { BBox3d bBox3dB = vBBox[b] ; BBox3d b3Int ; // se sono celle diverse e ho un'intersezione faccio il merge @@ -565,7 +527,7 @@ bool Tree::Split( int nId) { double dValue ; - Cell& cCell = m_mTree.at(nId) ; + Cell& cCell = m_mTree.at( nId) ; if ( cCell.IsSplitVert()) dValue = ( cCell.GetBottomLeft().x + cCell.GetTopRight().x) / 2 ; else @@ -573,223 +535,44 @@ Tree::Split( int nId) return Split( nId, dValue) ; } -//---------------------------------------------------------------------------- -bool -Tree::BuildTree_test( double dLinTol, double dSideMin, double dSideMax) -{ - // per poter usare questa funzione, anziché quella normale, bisogna: - // - commentare la parte di funzione di SetSurf dove si fanno gli split preliminare - // - se si usa anche la funzione GetLeaves, bisogna anche lì usare BuildTree_test al posto di BuildTree - - //celle 0,1 - m_mTree[-1].SetSplitDirVert( true) ; - Split( -1) ; - //celle 2,3 - m_mTree[0].SetSplitDirVert( false) ; - Split( 0) ; - //celle 4,5 - m_mTree[2].SetSplitDirVert( false) ; - Split( 2) ; - //celle 6,7 - m_mTree[3].SetSplitDirVert( true) ; - Split( 3) ; - //celle 8,9 - m_mTree[1].SetSplitDirVert( false) ; - Split( 1) ; - //celle 10,11 - m_mTree[8].SetSplitDirVert( true) ; - Split( 8) ; - //celle 12,13 - m_mTree[9].SetSplitDirVert( false) ; - Split( 9) ; - m_vnLeaves.push_back( 4) ; - //m_vnLeaves.push_back( 5) ; - m_vnLeaves.push_back( 6) ; - //m_vnLeaves.push_back( 7) ; - //m_vnLeaves.push_back( 10) ; - m_vnLeaves.push_back( 11) ; - //m_vnLeaves.push_back( 12) ; - m_vnLeaves.push_back( 13) ; - - // aggiunta di split - //celle 14,15 - m_mTree[5].SetSplitDirVert( true) ; - Split( 5) ; - m_vnLeaves.push_back( 14) ; - m_vnLeaves.push_back( 15) ; - //celle 16,17 - m_mTree[7].SetSplitDirVert( false) ; - Split( 7) ; - m_vnLeaves.push_back( 16) ; - m_vnLeaves.push_back( 17) ; - //celle 18,19 - m_mTree[12].SetSplitDirVert( true) ; - Split( 12) ; - m_vnLeaves.push_back( 18) ; - m_vnLeaves.push_back( 19) ; - //celle 20,21 - m_mTree[10].SetSplitDirVert( false) ; - Split( 10) ; - m_vnLeaves.push_back( 20) ; - m_vnLeaves.push_back( 21) ; - // riempio anche la lista dei parent delle celle - m_vnParents = m_vnLeaves ; - - return true ; -} - //---------------------------------------------------------------------------- bool Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax) { - // suddivido lo spazio parametrico con divisioni a metà su uno dei due parametri + // suddivido lo spazio parametrico con divisioni a metà su uno dei due parametri int nCToSplit = -1 ; Cell* pcToSplit = &m_mTree[nCToSplit] ; bool bIsPlanar = m_pSrfBz->IsPlanar() ; if ( ! m_bBilinear) { - while ( nCToSplit != -2 && pcToSplit->IsProcessed() == false) { - // controllo che la cella non sia già stata preliminarmente splittata + while ( nCToSplit != -2 && ! pcToSplit->IsProcessed()) { + + // se la pezza non è già stata preliminarmente splittata if ( pcToSplit->IsLeaf()) { - // calcolo in quale direzione ho più curvatura - // ptP00P10 è un punto tra P00 e P10 - double dCurvU = 0, dCurvV = 0 ; + + // dimensioni parametriche della pezza double dLenParU = ( pcToSplit->GetTopRight().x - pcToSplit->GetBottomLeft().x) / SBZ_TREG_COEFF ; double dLenParV = ( pcToSplit->GetTopRight().y - pcToSplit->GetBottomLeft().y) / SBZ_TREG_COEFF ; - Point3d ptP00, ptP10, ptP11, ptP01 ; - // i vertici della cella - GetPoint(pcToSplit->GetBottomLeft().x, pcToSplit->GetBottomLeft().y, ptP00) ; - GetPoint(pcToSplit->GetTopRight().x, pcToSplit->GetBottomLeft().y, ptP10) ; - GetPoint(pcToSplit->GetTopRight().x, pcToSplit->GetTopRight().y, ptP11) ; - GetPoint(pcToSplit->GetBottomLeft().x, pcToSplit->GetTopRight().y, ptP01) ; - if ( dLenParU <= 1. / m_nDegV || dLenParV <= 1. / m_nDegU || Dist(ptP00, ptP11) < dSideMin * 2 - || Dist(ptP10, ptP01) < dSideMin * 2) { - double dU = ( pcToSplit->GetTopRight().x + pcToSplit->GetBottomLeft().x) / 2 ; - double dV = ( pcToSplit->GetTopRight().y + pcToSplit->GetBottomLeft().y) / 2 ; - double dULoc = 0.5, dVLoc = 0.5 ; - Point3d ptPSrf, ptP00P10, ptP10P11, ptP11P01, ptP01P00 ; - GetPoint( dU, dV, ptPSrf) ; - GetPoint( dU, pcToSplit->GetBottomLeft().y, ptP00P10) ; - GetPoint( pcToSplit->GetTopRight().x, dV, ptP10P11) ; - GetPoint( dU, pcToSplit->GetTopRight().y, ptP11P01) ; - GetPoint( pcToSplit->GetBottomLeft().x, dV, ptP01P00) ; - Point3d ptV = ( 1 - dULoc) * ptP00P10 + dULoc * ptP11P01 ; - Point3d ptU = ( 1 - dVLoc) * ptP10P11 + dVLoc * ptP01P00 ; - dCurvV = Dist( ptV, ptPSrf) ; - dCurvU = Dist( ptU, ptPSrf) ; - } - // faccio un'analisi più fine della curvatura se almeno il grado di una curva di uno dei due parametri è alto e - // se sto ancora guardando una cella abbastanza grande - else{ - Point3d ptPSrf, ptP00P10, ptP10P11, ptP11P01, ptP01P00, ptPSrfMid ; - double dStep = 1. / ( m_nDegU * 2) ; - for ( double k = dStep ; k < 1 + EPS_SMALL ; k = k + dStep) { - double dU = ( k * pcToSplit->GetTopRight().x + ( 1 - k) * pcToSplit->GetBottomLeft().x) ; - double dV = ( pcToSplit->GetTopRight().y + pcToSplit->GetBottomLeft().y) / 2 ; - GetPoint( dU, dV, ptPSrf) ; - if ( k == 0.5) - ptPSrfMid = ptPSrf ; - GetPoint( dU, pcToSplit->GetBottomLeft().y, ptP00P10) ; - GetPoint( dU, pcToSplit->GetTopRight().y, ptP11P01) ; - CurveLine clV ; - clV.Set( ptP00P10, ptP11P01) ; - DistPointCurve dpc( ptPSrf, clV) ; - double dDist ; - dpc.GetDist( dDist) ; - dCurvV = max( dCurvV, dDist) ; - } - dStep = 1. / ( m_nDegV * 2) ; - for ( double k = dStep ; k < 1 + EPS_SMALL ; k = k + dStep) { - double dU = ( pcToSplit->GetTopRight().x + pcToSplit->GetBottomLeft().x) / 2 ; - double dV = ( k * pcToSplit->GetTopRight().y + ( 1 - k) * pcToSplit->GetBottomLeft().y) ; - if ( k == 0.5 && ! AreSamePointApprox( ORIG, ptPSrfMid)) - ptPSrf = ptPSrfMid ; - else - GetPoint( dU, dV, ptPSrf) ; - GetPoint( pcToSplit->GetTopRight().x, dV, ptP10P11) ; - GetPoint( pcToSplit->GetBottomLeft().x, dV, ptP01P00) ; - CurveLine clU ; - clU.Set( ptP01P00, ptP10P11) ; - DistPointCurve dpc( ptPSrf, clU) ; - double dDist ; - dpc.GetDist( dDist) ; - dCurvU = max( dCurvU, dDist) ; - } - } - // devo calcolare anche il twist, in caso di bordi rettilinei ( superficie di grado maggiore di 1, ma che in realtà è una bilineare) - // NON posso guardare la distanza tra il punto medio delle diagonali e il punto centrale della cella ( uLoc = 0.5, vLoc = 0.5) - // posso guardare la distanza tra le due diagonali - bool bTwist = false ; - // serve una valutazione più fine, sennò approssimo la superficie in modo troppo grossolano - DistLineLine dll( ptP00, ptP11, ptP10, ptP01, true, true) ; - double dDist = 0 ; dll.GetDist( dDist) ; - if ( dDist > max(dCurvU, dCurvV) || dDist < 5 * EPS_SMALL) { - bool bFlat = false ; - // controllo se la cella è twistata di 180 gradi e quindi piatta - Triangle3d tria1, tria2 ; - tria1.Set( ptP00, ptP10, ptP11) ; tria1.Validate( true) ; - tria2.Set( ptP00, ptP11, ptP01) ; tria2.Validate( true) ; - if( AreOppositeVectorEpsilon(tria1.GetN(), tria2.GetN(), 5 * EPS_SMALL)) { - bTwist = true ; - bFlat = true ; - } - // controllo che la cella non sia piatta - if( ! bTwist) { - PolyLine plCell ; - plCell.AddUPoint(0,ptP00) ; - plCell.AddUPoint(1,ptP10) ; - plCell.AddUPoint(2,ptP11) ; - double dU = (pcToSplit->GetTopRight().x + pcToSplit->GetBottomLeft().x) / 2 ; - double dV = (pcToSplit->GetTopRight().y + pcToSplit->GetBottomLeft().y) / 2 ; - Point3d ptCen ; GetPoint( dU, dV, ptCen) ; - plCell.AddUPoint(3,ptCen) ; - plCell.AddUPoint(4,ptP01) ; - plCell.Close() ; - Plane3d plPlane ; double dArea = 0 ; - bFlat = plCell.IsClosedAndFlat( plPlane, dArea, 10 * EPS_SMALL) ; - } - if( ! bFlat && dDist > 5 * EPS_SMALL) { - bTwist = true ; - // devo decidere in quale direzione splittare - // dovrei capire in quale delle due direzioni è più torta la superficie - Vector3d vtU0 = ptP10 - ptP00 ; - Vector3d vtU1 = ptP11 - ptP01 ; - double dAngU ; - bool bDetU = false ; - vtU0.GetRotation( vtU1, vtU0 ^ vtU1, dAngU, bDetU) ; - Vector3d vtV0 = ptP01 - ptP00 ; - Vector3d vtV1 = ptP11 - ptP10 ; - double dAngV ; - bool bDetV = false ; - // faccio la get rotation tra le coppie vettori, usando come asse il loro prodotto vettoriale per ottenere la rotazione tra i due lati - // splitto nella direzione perpendicolare alla coppia di vettori più torti tra loro. - vtV0.GetRotation( vtV1, vtV0 ^ vtV1, dAngV, bDetV) ; - if ( dAngU > dAngV) - dCurvV = dDist ; - else - dCurvU = dDist ; - } - } + // vertici e centro della pezza + Point3d ptP00, ptP10, ptP11, ptP01, ptCen ; + GetPoint( pcToSplit->GetBottomLeft().x, pcToSplit->GetBottomLeft().y, ptP00) ; + GetPoint( pcToSplit->GetTopRight().x, pcToSplit->GetBottomLeft().y, ptP10) ; + GetPoint( pcToSplit->GetTopRight().x, pcToSplit->GetTopRight().y, ptP11) ; + GetPoint( pcToSplit->GetBottomLeft().x, pcToSplit->GetTopRight().y, ptP01) ; + GetPoint( pcToSplit->GetCenter().x, pcToSplit->GetCenter().y, ptCen) ; + //{ string sLog = "P00=" + ToString( ptP00, 3) + " P10=" + ToString( ptP10, 3) + + // " P11=" + ToString( ptP11, 3) + " P01=" + ToString( ptP01, 3) + + // " Cen=" + ToString( ptCen, 3); + // LOG_DBG_INFO( GetEGkLogger(), sLog.c_str())} - // per lo split scelgo la direzione che è più vicina alla superficie originale nel punto di maggior distanza - // misura approssimativa della curvatura in una direzione - bool bVert ; - if ( dCurvV > dCurvU) { - // lungo la direzione V ho una curvatura maggiore - bVert = false ; - } - else { - // lungo la direzione U ho una curvatura maggiore - bVert = true ; - } - pcToSplit->SetSplitDirVert( bVert) ; - // distanza reale tra i vertici della cella + // distanze sul contorno tra i quattro vertici double dLen0 = Dist( ptP00, ptP10) ; double dLen1 = Dist( ptP10, ptP11) ; double dLen2 = Dist( ptP01, ptP11) ; double dLen3 = Dist( ptP00, ptP01) ; + // distanza reale tra i vertici della pezza if ( dLen0 < EPS_ZERO && dLen2 < EPS_ZERO ) { - double dV = ( pcToSplit->GetBottomLeft().y + pcToSplit->GetTopRight().y) / 2 / SBZ_TREG_COEFF ; + double dV = pcToSplit->GetCenter().y / SBZ_TREG_COEFF ; PtrOwner pCrvV( m_pSrfBz->GetCurveOnU( dV)) ; double dLenU0, dLenU1 ; pCrvV->GetLengthAtParam( pcToSplit->GetBottomLeft().x / SBZ_TREG_COEFF, dLenU0) ; @@ -797,126 +580,177 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax) dLen0 = abs( dLenU1 - dLenU0) ; } if ( dLen1 < EPS_ZERO && dLen3 < EPS_ZERO ) { - double dU = ( pcToSplit->GetBottomLeft().x + pcToSplit->GetTopRight().x) / 2 / SBZ_TREG_COEFF ; + double dU = pcToSplit->GetCenter().x / SBZ_TREG_COEFF ; PtrOwner pCrvU( m_pSrfBz->GetCurveOnV( dU)) ; double dLenV0, dLenV1 ; pCrvU->GetLengthAtParam( pcToSplit->GetBottomLeft().y / SBZ_TREG_COEFF, dLenV0) ; pCrvU->GetLengthAtParam( pcToSplit->GetTopRight().y / SBZ_TREG_COEFF, dLenV1) ; dLen1 = abs( dLenV1 - dLenV0) ; } + + // calcolo massimo della freccia (sagitta) + double dSagU = 0, dSagV = 0 ; + + // da distanza tra centro e triangoli di approssimazione + if ( dSagU < dLinTol && dSagV < dLinTol) { + // distanza del centro dai due triangoli con la prima diagonale + Triangle3d Tria1A, Tria1B ; + Tria1A.Set( ptP00, ptP10, ptP11) ; Tria1A.Validate( true) ; + Tria1B.Set( ptP00, ptP11, ptP01) ; Tria1B.Validate( true) ; + double dDist1A = NAN ; + DistPointTriangle( ptCen, Tria1A).GetDist( dDist1A) ; + double dDist1B = NAN ; + DistPointTriangle( ptCen, Tria1B).GetDist( dDist1B) ; + double dDist1 = min( dDist1A, dDist1B) ; + // distanza del centro dai due triangoli con la seconda diagonale + Triangle3d Tria2A, Tria2B ; + Tria2A.Set( ptP10, ptP11, ptP01) ; Tria2A.Validate( true) ; + Tria2B.Set( ptP10, ptP01, ptP00) ; Tria2B.Validate( true) ; + double dDist2A = NAN ; + DistPointTriangle( ptCen, Tria2A).GetDist( dDist2A) ; + double dDist2B = NAN ; + DistPointTriangle( ptCen, Tria2B).GetDist( dDist2B) ; + double dDist2 = min( dDist2A, dDist2B) ; + // prendo la minore delle due distanze + double dDist = min( dDist1, dDist2) ; + // se maggiore della tolleranza, imposto come freccia + if ( isfinite( dDist) && dDist > dLinTol) { + // divido in base alle distanze tra i vertici dei lati + if ( max( dLen0, dLen2) >= max( dLen1, dLen3)) + dSagU = dDist ; + else + dSagV = dDist ; + //{ string sLog = " Da triangoli : FrecciaU=" + ToString( dSagU, 3) + " FrecciaV=" + ToString( dSagV, 3) ; + // LOG_DBG_INFO( GetEGkLogger(), sLog.c_str())} + } + } + + // su isoparametriche in U e V + if ( dSagU < dLinTol && dSagV < dLinTol) { + // step di verifica in U e in V + int nStepU = ( dLenParU > 1. / m_nDegU ? m_nDegU + 1 : 2) ; + int nStepV = ( dLenParV > 1. / m_nDegV ? m_nDegV + 1 : 2) ; + // verifico lungo curve in U + for ( int i = 0 ; i <= nStepU ; ++ i) { + // parametro U in analisi + double dCoeffU = double( i) / nStepU ; + double dU = ( 1 - dCoeffU) * pcToSplit->GetBottomLeft().x + dCoeffU * pcToSplit->GetTopRight().x ; + // linea tra gli estremi a questa U (ptP00P10 è un punto tra P00 e P10 e così via) + Point3d ptP00P10 ; + GetPoint( dU, pcToSplit->GetBottomLeft().y, ptP00P10) ; + Point3d ptP11P01 ; + GetPoint( dU, pcToSplit->GetTopRight().y, ptP11P01) ; + CurveLine clV ; + clV.Set( ptP00P10, ptP11P01) ; + // verifico alcuni punti intermedi in V + for ( int j = 1 ; j < nStepV ; ++ j) { + // parametro in V + double dCoeffV = double( j) / nStepV ; + double dV = ( 1 - dCoeffV) * pcToSplit->GetBottomLeft().y + dCoeffV * pcToSplit->GetTopRight().y ; + // punto a U, V + Point3d ptPSrf ; + GetPoint( dU, dV, ptPSrf) ; + // distanza del punto dalla precedente linea + DistPointCurve dpc( ptPSrf, clV) ; + double dDist ; + dpc.GetDist( dDist) ; + dSagV = max( dSagV, dDist) ; + } + } + // verifico lungo curve in V + for ( int i = 0 ; i <= nStepV ; ++ i) { + // parametro in V in analisi + double dCoeffV = double( i) / nStepV ; + double dV = ( 1 - dCoeffV) * pcToSplit->GetBottomLeft().y + dCoeffV * pcToSplit->GetTopRight().y ; + // linea tra gli estremi a questa V + Point3d ptP10P11 ; + GetPoint( pcToSplit->GetTopRight().x, dV, ptP10P11) ; + Point3d ptP01P00 ; + GetPoint( pcToSplit->GetBottomLeft().x, dV, ptP01P00) ; + CurveLine clU ; + clU.Set( ptP01P00, ptP10P11) ; + // verifico alcuni punti intermedi in U + for ( int j = 1 ; j < nStepU ; ++ j) { + // parametro U + double dCoeffU = double( j) / nStepU ; + double dU = ( 1 - dCoeffU) * pcToSplit->GetBottomLeft().x + dCoeffU * pcToSplit->GetTopRight().x ; + // punto a U, V + Point3d ptPSrf ; + GetPoint( dU, dV, ptPSrf) ; + // distanza del punto dalla precedente linea + DistPointCurve dpc( ptPSrf, clU) ; + double dDist ; + dpc.GetDist( dDist) ; + dSagU = max( dSagU, dDist) ; + } + } + //{ string sLog = " Da Isoparam : FrecciaU=" + ToString( dSagU, 3) + " FrecciaV=" + ToString( dSagV, 3) ; + // LOG_DBG_INFO( GetEGkLogger(), sLog.c_str())} + } + + // per lo split scelgo la direzione che è più vicina alla superficie originale nel punto di maggior distanza + // misura approssimativa della curvatura in una direzione + bool bVert ; + if ( max( dLen0, dLen2) > 5 * max( dLen1, dLen3)) + bVert = true ; + else if ( max( dLen1, dLen3) > 5 * max( dLen0, dLen2)) + bVert = false ; + else + bVert = ( dSagV <= dSagU) ; + pcToSplit->SetSplitDirVert( bVert) ; // verifico che la cella sia da splittare e che eventualmente sia abbastanza grande da poterlo fare - double dSideMinVal = 0, dSideMaxVal = 0 ; + double dSideMinVal = 0 ; + double dLengMinVal = 0 ; if ( bVert) { if ( dLen0 > EPS_ZERO && dLen2 > EPS_ZERO) dSideMinVal = min( dLen0, dLen2) ; else dSideMinVal = max( dLen0, dLen2) ; + if ( dLen1 > EPS_ZERO && dLen3 > EPS_ZERO) + dLengMinVal = min( dLen1, dLen3) ; + else + dLengMinVal = max( dLen1, dLen3) ; } else { if ( dLen1 > EPS_ZERO && dLen3 > EPS_ZERO) dSideMinVal = min( dLen1, dLen3) ; else dSideMinVal = max( dLen1, dLen3) ; + if ( dLen0 > EPS_ZERO && dLen2 > EPS_ZERO) + dLengMinVal = min( dLen0, dLen2) ; + else + dLengMinVal = max( dLen0, dLen2) ; } - // calcolo le diagonali per controllare la dimensione massima dei triangoli in cui dividerei la cella - dSideMaxVal = max( Dist( ptP00, ptP11), Dist( ptP10, ptP01)) ; + // calcolo le diagonali per controllare la dimensione massima dei triangoli in cui dividerei la cella + double dSideMaxVal = max( Dist( ptP00, ptP11), Dist( ptP10, ptP01)) ; - // se la cella è abbastanza grande da poter essere divisa ancora, calcolo l'errore di approssimazione + // se la cella è abbastanza grande da poter essere divisa ancora, calcolo l'errore di approssimazione + // ( dSideMinVal è zero se entrambi i lati da splittare sono collassati in un punto, controllo dLengMinVal) bool bSplit = false ; - // dSideMinVal potrebbe essere zero se entrambi i lati che dovrei splittare sono collassati in un punto, ma questo non vuol - // dire che non dovrei eseguire lo split - if ( ! bTwist && (dSideMinVal / 2 >= dSideMin || dSideMinVal < EPS_SMALL) && dSideMaxVal < dSideMax && ( dCurvV > dLinTol || dCurvU > dLinTol)) { - CurveLine cl0010, cl0001, cl1011, cl0111 ; - // V=0 - cl0010.Set( ptP00, ptP10) ; - // V=1 - cl0111.Set( ptP01, ptP11) ; - Point3d pt0010, pt0111, ptBz0, ptBz1, ptBzV ; - int nFlag ; - CurveLine clV ; - // determino quanti Step fare per ogni direzione parametrica - double dDimU = ( dLen0 >= dLen2 ? dLen0 / m_vDim[0] : dLen2 / m_vDim[2]) ; - dDimU = ( dDimU > 1 ? 1 : dDimU) ; - double dDimV = ( dLen1 >= dLen3 ? dLen1 / m_vDim[1] : dLen3 / m_vDim[3]) ; - dDimV = ( dDimV > 1 ? 1 : dDimV) ; - // numero di Step per campionare la superficie nelle due direzioni parametriche - int nStepsU = int( 51 * dDimU + 5 * ( 1 - dDimU)) ; - int nStepsV = int( 51 * dDimV + 5 * ( 1 - dDimV)) ; - for ( int u = 0 ; u < nStepsU && ! bSplit ; ++ u) { - double dU = double ( u) / double ( nStepsU - 1) ; - double dULoc = ( ( 1 - dU) * pcToSplit->GetBottomLeft().x + dU * pcToSplit->GetTopRight().x) ; - if ( ! GetPoint( dULoc, pcToSplit->GetBottomLeft().y, ptBz0) || - ! GetPoint( dULoc, pcToSplit->GetTopRight().y, ptBz1)) - return false ; - // verifico che la cella non sia uno spicchio in verticale, cioè con ptP00 == ptP01 && ptP10 == ptP11 - // ( vedi disegno sotto per uno spicchio verticale) - // sennò i punti che cerco sono semplicemente i vertici - if ( cl0010.IsValid()) { - DistPointCurve dpc0010( ptBz0, cl0010) ; - dpc0010.GetMinDistPoint( 0, pt0010, nFlag) ; - } - else - pt0010 = ptP00 ; - if ( cl0111.IsValid()) { - DistPointCurve dpc0111( ptBz1, cl0111) ; - dpc0111.GetMinDistPoint( 0, pt0111, nFlag) ; - } - else - pt0111 = ptP01 ; - // curva a parametro U fisso, con V che scorre - clV.Set( pt0010, pt0111) ; - for ( int v = 0 ; v < nStepsV ; ++ v) { - double dV = double ( v) / double ( nStepsV - 1) ; - double dVLoc = ( ( 1 - dV) * pcToSplit->GetBottomLeft().y + dV * pcToSplit->GetTopRight().y) ; - if ( ! GetPoint( dULoc, dVLoc, ptBzV)) - return false ; - DistPointCurve dpc( ptBzV, clV) ; - // distanza di approssimazione locale - double dDist ; - dpc.GetDist( dDist) ; - // se la cella è uno spicchio, quindi con due lati collassati, devo calcolare in modo diverso dist - // ptP00 == ptP01 - // / \ - // / \ - // / \ - // ( ) - // \ / - // \ / - // \ / - // ptP10 == ptP11 - if ( ! clV.IsValid() && AreSamePointApprox( ptP00, ptP01) && AreSamePointApprox( ptP10, ptP11)) { - DistPointCurve dpcSlice( ptBzV, cl0010) ; - dpcSlice.GetDist( dDist) ; - } - if ( dDist > dLinTol) { - bSplit = true ; - break ; - } - } - } + bool bDimOk = ( dSideMinVal / 2 >= dSideMin || ( dSideMinVal < EPS_SMALL && dLengMinVal / 2 >= dSideMin)) ; + if ( dSideMaxVal > dSideMax) { + bSplit = true ; + //LOG_DBG_INFO( GetEGkLogger(), " Split by SideMax") } - else if ( bTwist ) { - // se la cella è twistata allora l'errore lo calcolo come nelle bilineari - //double dErr = 1. / 4. * ( ( ptP00 - ptP01) + ( ptP11 - ptP10)).Len() ; - double dErr = ( ( ptP00 - ptP01) + ( ptP11 - ptP10)).Len() / 20 ; - if ( dErr > dLinTol) - bSplit = true ; + else if ( dSagV > dLinTol || dSagU > dLinTol) { + bSplit = bDimOk ; + //if ( bSplit) + // LOG_DBG_INFO( GetEGkLogger(), " Split by SagittaUV") } - if ( bSplit || dSideMaxVal > dSideMax) { + if ( bSplit) { pcToSplit->SetSplitDirVert( bVert) ; - // effettuo lo split + // effettuo lo split Split( nCToSplit) ; - - // procedo con lo split del Child1 + // procedo con lo split del Child1 nCToSplit = pcToSplit->m_nChild1 ; pcToSplit = &m_mTree[nCToSplit] ; } else { - // sono arrivato ad una cella Leaf, quindi salvo la cella + // sono arrivato ad una cella Leaf, quindi salvo la cella m_vnLeaves.push_back( nCToSplit) ; pcToSplit->SetProcessed() ; - // risalgo i parent finché non trovo il primo Child2 da processare + // risalgo i parent finché non trovo il primo Child2 da processare nCToSplit = pcToSplit->m_nParent ; pcToSplit = &m_mTree[nCToSplit] ; if ( nCToSplit == -2) @@ -942,26 +776,26 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax) pcToSplit = &m_mTree[nCToSplit] ; } } - Balance() ; // da implementare quando dividerò ad un parametro a scelta e non a metà // probabilmente mi servirà salvare nella cella il livello di profondità } - // bilineare + + // bilineare else { while ( nCToSplit != -2 && pcToSplit->IsProcessed() == false) { if ( pcToSplit->IsLeaf()) { - // vertici della cella + // vertici della cella Point3d ptP00, ptP10, ptP11, ptP01 ; GetPoint(pcToSplit->GetBottomLeft().x, pcToSplit->GetBottomLeft().y, ptP00) ; GetPoint(pcToSplit->GetTopRight().x, pcToSplit->GetBottomLeft().y, ptP10) ; GetPoint(pcToSplit->GetTopRight().x, pcToSplit->GetTopRight().y, ptP11) ; GetPoint(pcToSplit->GetBottomLeft().x, pcToSplit->GetTopRight().y, ptP01) ; - // distanza reale tra i vertici della cella + // distanza reale tra i vertici della cella double dLen0 = Dist( ptP00, ptP10) ; double dLen1 = Dist( ptP10, ptP11) ; double dLen2 = Dist( ptP01, ptP11) ; double dLen3 = Dist( ptP00, ptP01) ; bool bVert = false ; - ///per capire in quale direzione splittare devo guardare quale coppia di lati opposti è più sghemba + // per capire in quale direzione splittare devo guardare quale coppia di lati opposti è più sghemba Vector3d vtU0 = ptP01 - ptP00 ; Vector3d vtU1 = ptP11 - ptP10 ; double dLU0, dFU0, dTU0, dLU1, dFU1, dTU1 ; @@ -974,7 +808,7 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax) vtV0.ToSpherical( &dLV0, &dFV0, &dTV0) ; vtV1.ToSpherical( &dLV1, &dFV1, &dTV1) ; double dSkewnessU = abs( dFV1 - dFV0) + abs( dTV1 - dTV0) ; - if( dSkewnessU > dSkewnessV) + if ( dSkewnessU > dSkewnessV) bVert = false ; else bVert = true ; @@ -1005,25 +839,24 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax) } } } - else if ( ! bIsPlanar){ - dErr = 1. / 4. * ( ( ptP00 - ptP01) + ( ptP11 - ptP10)).Len() ; - //int dErr2 = 1. / 4. * ( ( ptP10 - ptP01) + ( ptP11 - ptP00)).Len() ; //correzione che mi verrebbe intuitiva, ma che fa dividere la superficie molto di più ( probabilmente troppo)!! quindi probabilmente sbagliata + else if ( ! bIsPlanar) { + dErr = ( ( ptP00 - ptP01) + ( ptP11 - ptP10)).Len() / 4 ; } - // se la cella è abbastanza grande da poter essere divisa ancora e devo approssimare meglio, la divido + // se la cella è abbastanza grande da poter essere divisa ancora e devo approssimare meglio, la divido if ( dSideMinVal / 2 >= dSideMin && dSideMaxVal < dSideMax && dErr > dLinTol) { pcToSplit->SetSplitDirVert( bVert) ; - // effettuo lo split + // effettuo lo split Split( nCToSplit) ; - // procedo con lo split del Child1 + // procedo con lo split del Child1 nCToSplit = pcToSplit->m_nChild1 ; pcToSplit = &m_mTree[nCToSplit] ; } else { - // sono arrivato ad una cella Leaf, quindi salvo la cella + // sono arrivato ad una cella Leaf, quindi salvo la cella m_vnLeaves.push_back( nCToSplit) ; pcToSplit->SetProcessed() ; - // risalgo i parent finché non trovo il primo Child2 da processare + // risalgo i parent finché non trovo il primo Child2 da processare nCToSplit = pcToSplit->m_nParent ; pcToSplit = &m_mTree[nCToSplit] ; if ( nCToSplit == -2) @@ -1050,22 +883,10 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax) } } } + return true ; } -//---------------------------------------------------------------------------- -void -Tree::Balance() -{ - //for ( int i : vCheck) { - // // non ancora implementato - // // rendo il tree balanced : ogni foglia deve avere una profondità di +- 1 rispetto alle foglie adiacenti. - //} - - // al momento il problema viene bypassato in fase di generazione dei poligoni, considerando per ogni cella, oltre ai propri vertici - // i vertici dei vicini che giacciono sui suoi lati -} - //---------------------------------------------------------------------------- void Tree::GetTopNeigh( int nId, INTVECTOR& vTopNeighs) const @@ -1546,8 +1367,8 @@ Tree::GetPolygons( POLYLINEMATRIX& vvPolygons, POLYLINEMATRIX& vvPolygons3d, vec else { // vettore in cui salvo il chunk di appartenenza di ogni loop che attraversa la cella INTVECTOR vnParentChunk ; - // vettore in cui salvo i loop che non appartengono al poligono che sto cotruendo nel ciclo attuale e da cui ripasserò dopo - INTVECTOR vToCheck( (int) m_mTree[nId].m_vInters.size()) ; + // vettore in cui salvo i loop che non appartengono al poligono che sto costruendo nel ciclo attuale e da cui ripasserò dopo + INTVECTOR vToCheck( m_mTree[nId].m_vInters.size()) ; iota( vToCheck.begin(), vToCheck.end(), 0) ; // numero di poligoni aggiunti int nPoly = 0 ; @@ -1942,23 +1763,20 @@ Tree::FindCell( const Point3d& ptToAssign, const CurveLine& clTrim, bool bRecurs // se fallisce ritorna un vettore vuoto // verifico che il punto sia all'interno dello spazio parametrico // allargo i bordi in modo da tenere anche i punti sul bordo dello spazio parametrico - if ( ptToAssign.x < m_mTree.at( -1).GetBottomLeft().x - EPS_SMALL || ptToAssign.x > m_mTree.at( -1).GetTopRight().x + EPS_SMALL|| - ptToAssign.y < m_mTree.at( -1).GetBottomLeft().y - EPS_SMALL || ptToAssign.y > m_mTree.at( -1).GetTopRight().y + EPS_SMALL) { - //nCells.push_back( - 2) ; + if ( ptToAssign.x < m_mTree.at( -1).GetBottomLeft().x - EPS_SMALL || + ptToAssign.x > m_mTree.at( -1).GetTopRight().x + EPS_SMALL || + ptToAssign.y < m_mTree.at( -1).GetBottomLeft().y - EPS_SMALL || + ptToAssign.y > m_mTree.at( -1).GetTopRight().y + EPS_SMALL) { return nCells ; } // se ho diviso preliminarmente le patches e in uno dei due parametri ho un numero dispari di patches devo individuare a mano la cella parent // in cui individuare la foglia giusta - if ( (m_bSplitPatches && ( m_nSpanU > 1 || m_nSpanV > 1)) || m_bTestMode) { + if ( m_nSpanU > 1 || m_nSpanV > 1) { INTVECTOR nParents = FindCell( ptToAssign, clTrim, m_vnParents) ; if ( nParents.empty()) return nCells ; nId = nParents.back() ; - if ( m_bTestMode ) { - nCells.push_back(nId) ; - return nCells ; - } } // individuo la foglia in cui ho lo start del loop while ( ! m_mTree.at( nId).IsLeaf()) { @@ -1988,8 +1806,7 @@ Tree::FindCell( const Point3d& ptToAssign, const CurveLine& clTrim, bool bRecurs Point3d ptBr( m_mTree.at( nId).GetTopRight().x , m_mTree.at( nId).GetBottomLeft().y) ; Point3d ptTl( m_mTree.at( nId).GetBottomLeft().x , m_mTree.at( nId).GetTopRight().y) ; if ( abs( ptToAssign.x - ptTl.x) < EPS_SMALL || abs( ptToAssign.x - ptBr.x) < EPS_SMALL || - abs( ptToAssign.y - ptTl.y) < EPS_SMALL || abs( ptToAssign.y - ptBr.y) < EPS_SMALL) - { + abs( ptToAssign.y - ptTl.y) < EPS_SMALL || abs( ptToAssign.y - ptBr.y) < EPS_SMALL) { Vector3d vtDir ; clTrim.GetStartDir( vtDir) ; // proseguo lungo la curva di trim di EPS_SMALL @@ -1999,8 +1816,10 @@ Tree::FindCell( const Point3d& ptToAssign, const CurveLine& clTrim, bool bRecurs Vector3d vtDirDX = vtDir ; vtDirDX.Rotate( Z_AX, 90) ; ptToAssignPlus = ptToAssignPlus + vtDir * EPS_SMALL ; // controllo di non essere uscito dallo spazio parametrico ed eventualmente giro a sinistra - if ( ptToAssignPlus.x < m_mTree.at( -1).GetBottomLeft().x - EPS_SMALL || ptToAssignPlus.x > m_mTree.at( -1).GetTopRight().x + EPS_SMALL|| - ptToAssignPlus.y < m_mTree.at( -1).GetBottomLeft().y - EPS_SMALL || ptToAssignPlus.y > m_mTree.at( -1).GetTopRight().y + EPS_SMALL) { + if ( ptToAssignPlus.x < m_mTree.at( -1).GetBottomLeft().x - EPS_SMALL || + ptToAssignPlus.x > m_mTree.at( -1).GetTopRight().x + EPS_SMALL || + ptToAssignPlus.y < m_mTree.at( -1).GetBottomLeft().y - EPS_SMALL || + ptToAssignPlus.y > m_mTree.at( -1).GetTopRight().y + EPS_SMALL) { // rispetto al punto di partenza avanzo lungo la curva di trim ptToAssignPlus = ptToAssign + vtDir * EPS_SMALL ; Vector3d vtDirSX = vtDir ; vtDirSX.Rotate( Z_AX, -90) ; @@ -4340,7 +4159,7 @@ Tree::CreateCellContour( POLYLINEMATRIX& vPolygons) int nRoot = -1 ; // preparo tutto per poter chiamare la createCellPolygon m_vnLeaves.push_back( nRoot) ; - INTVECTOR vToCheck( (int) m_mTree.at(nRoot).m_vInters.size()) ; + INTVECTOR vToCheck( m_mTree.at(nRoot).m_vInters.size()) ; iota( vToCheck.begin(), vToCheck.end(), 0) ; int nPoly = 0 ; INTVECTOR vnParentChunk ; diff --git a/Tree.h b/Tree.h index 16ce8f8..1b53ea1 100644 --- a/Tree.h +++ b/Tree.h @@ -28,7 +28,7 @@ struct PairHashInt64 { size_t h2 = std::hash{}(key.second) ; return h1 ^ (h2 << 1); // Combine hashes } -}; +} ; //---------------------------------------------------------------------------- struct Inters { @@ -42,13 +42,13 @@ struct Inters { // se ho più intersezioni che entrano in un lato le riordino considerando che percorro i lati in senso antiorario a partire da ptTR bool operator < ( Inters& b) { - // trovo in che ordine stanno i due start, tenendo conto anche della possibilità che siano vertici + // trovo in che ordine stanno i due start, tenendo conto anche della possibilità che siano vertici INTVECTOR vEdges = { 7, 0, 4, 1, 5, 2, 6, 3} ; const auto iter1 = find( vEdges.begin(), vEdges.end(), nIn) ; int nPos1 = std::distance( vEdges.begin(), iter1) ; const auto iter2 = find( vEdges.begin(), vEdges.end(), b.nIn) ; int nPos2 = std::distance( vEdges.begin(), iter2) ; - // se sono loop interni li ordino in modo decrescente rispetto all'area + // se sono loop interni li ordino in modo decrescente rispetto all'area bool bEqIn = ( nIn == b.nIn) ; double dAreaA = 0 , dAreaB = 0 ; if ( bEqIn && nIn == -1) { @@ -63,7 +63,7 @@ struct Inters { pl.Close() ; pl.GetAreaXY( dAreaB) ; } - // se nIn è un vertice sistemo il valore + // se nIn è un vertice sistemo il valore int nEdgeIn = nIn ; if ( nIn > 3) nEdgeIn = nIn - 4 ; @@ -75,13 +75,13 @@ struct Inters { ( bEqIn && nEdgeIn == 3 && vpt[0].y < b.vpt[0].y)) ; } - static bool FirstEncounter ( Inters& a, Inters& b) + static bool FirstEncounter( Inters& a, Inters& b) { - // riordino in base al lato toccato, o dall'uscita o dall'ingresso, che viene prima. - // ottengo l'ordine che avrei percorrendo il bordo da ptTR e considerando i loop che incontro, indipendentemente se li incontro nel punto di uscita o ingresso - // nell'intersezione salvo se il taglio è stato ordinato guardando l'ingresso o l'uscita + // riordino in base al lato toccato, o dall'uscita o dall'ingresso, che viene prima. + // ottengo l'ordine che avrei percorrendo il bordo da ptTR e considerando i loop che incontro, indipendentemente se li incontro nel punto di uscita o ingresso + // nell'intersezione salvo se il taglio è stato ordinato guardando l'ingresso o l'uscita INTVECTOR vEdges = { 7, 0, 4, 1, 5, 2, 6, 3} ; - // trovo i lati di ingresso e uscita + // trovo i lati di ingresso e uscita const auto iter1 = find( vEdges.begin(), vEdges.end(), a.nIn) ; int nPos1 = std::distance( vEdges.begin(), iter1) ; const auto iter2 = find( vEdges.begin(), vEdges.end(), a.nOut) ; @@ -92,13 +92,13 @@ struct Inters { int nPos4 = std::distance( vEdges.begin(), iter4) ; int nFirstA = 0 ; int nFirstB = 0 ; - // salvo l'indice del primo punto dell'intersezione che ho incontrato scorrendo il bordo da ptTR - // salvo il lato che viene prima confrontando ingresso e uscita + // salvo l'indice del primo punto dell'intersezione che ho incontrato scorrendo il bordo da ptTR + // salvo il lato che viene prima confrontando ingresso e uscita if ( nPos2 < nPos1) { nPos1 = nPos2 ; nFirstA = int( a.vpt.size()) - 1 ; } - // se ingresso e uscita sono sullo stesso lato allora confronto le coordinate per capire se viene prima l'ingresso o l'uscita + // se ingresso e uscita sono sullo stesso lato allora confronto le coordinate per capire se viene prima l'ingresso o l'uscita else if ( nPos2 == nPos1 ) { if ( nPos1 == 0 ) nFirstA = a.vpt[0].x > a.vpt.back().x ? 0 : ( int( a.vpt.size()) - 1) ; @@ -125,11 +125,11 @@ struct Inters { } a.bSortedbyStart = nFirstA == 0 ; b.bSortedbyStart = nFirstB == 0 ; - // se sono diversi ritorno il confronto + // se sono diversi ritorno il confronto if ( nPos1 != nPos3) return nPos1 < nPos3 ; - // se sono uguali devo valutare il punto di intersezione - return ( nPos1 == 0 && a.vpt[nFirstA].x > b.vpt[nFirstB].x) || + // se sono uguali devo valutare il punto di intersezione + return ( nPos1 == 0 && a.vpt[nFirstA].x > b.vpt[nFirstB].x) || ( nPos1 == 1 && a.vpt[nFirstA].y > b.vpt[nFirstB].y) || ( nPos1 == 2 && a.vpt[nFirstA].x < b.vpt[nFirstB].x) || ( nPos1 == 3 && a.vpt[nFirstA].y < b.vpt[nFirstB].y) ; @@ -163,17 +163,15 @@ class Cell public : ~Cell( void) {} Cell( void) - : m_nId( -1),m_nTop ( -2), m_nBottom( -2), m_nLeft( -2), m_nRight ( -2), m_nParent( -2), m_nDepth( 0), - m_nChild1( -2), m_nChild2( -2), m_nFlag( -1), m_bLabelled( false), m_nRightEdgeIn( -1), m_bOnLeftEdge( false), m_bOnTopEdge( false), m_nVertToErase( -1), - m_ptPbl( ORIG), m_ptPtr( SBZ_TREG_COEFF, SBZ_TREG_COEFF, 0), m_bProcessed( false), m_bSplitVert( true) - { - Point3d ptTr ( 1 * SBZ_TREG_COEFF, 1 * SBZ_TREG_COEFF) ; - m_ptPtr = ptTr ; - } + : m_nId( -1), m_nTop( -2), m_nBottom( -2), m_nLeft( -2), m_nRight( -2), m_nParent( -2), m_nDepth( 0), + m_dSplit( 0), m_nChild1( -2), m_nChild2( -2), m_nFlag( -1), m_bLabelled( false), m_nRightEdgeIn( -1), + m_bOnLeftEdge( false), m_bOnTopEdge( false), m_nVertToErase( -1), m_ptPbl( ORIG), + m_ptPtr( SBZ_TREG_COEFF, SBZ_TREG_COEFF, 0), m_bProcessed( false), m_bSplitVert( true) {} Cell( const Point3d& ptBL, const Point3d& ptTR) - : m_nId( -1),m_nTop ( -2), m_nBottom( -2), m_nLeft( -2), m_nRight ( -2), m_nParent( -2), m_nDepth( 0), - m_nChild1( -2), m_nChild2( -2), m_nFlag( -1), m_bLabelled( 0), m_nRightEdgeIn( -1), m_bOnLeftEdge( false), m_bOnTopEdge( false), m_nVertToErase( -1), - m_ptPbl( ptBL), m_ptPtr( ptTR), m_bProcessed( false), m_bSplitVert( true) {} + : m_nId( -1), m_nTop( -2), m_nBottom( -2), m_nLeft( -2), m_nRight( -2), m_nParent( -2), m_nDepth( 0), + m_dSplit( 0), m_nChild1( -2), m_nChild2( -2), m_nFlag( -1), m_bLabelled( 0), m_nRightEdgeIn( -1), + m_bOnLeftEdge( false), m_bOnTopEdge( false), m_nVertToErase( -1), m_ptPbl( ptBL), + m_ptPtr( ptTR), m_bProcessed( false), m_bSplitVert( true) {} bool IsSame( const Cell& cOtherCell) const { return ( m_nId == cOtherCell.m_nId) ; } void SetBottomLeft( const Point3d& ptBL) @@ -192,9 +190,11 @@ class Cell { return Point3d( m_ptPbl.x, m_ptPtr.y) ; } Point3d GetBottomRight( void) const { return Point3d( m_ptPtr.x, m_ptPbl.y); } + Point3d GetCenter( void) const + { return ( m_ptPbl + m_ptPtr) / 2 ; } double GetSplitValue( void) const { return m_dSplit ; } - bool IsSplitVert( void) const // se true la cella verrebbe splittata verticalmente, sennò orizzontalmente + bool IsSplitVert( void) const // se true la cella verrebbe splittata verticalmente, altrimenti orizzontalmente { return m_bSplitVert ; } bool IsLeaf( void) const // flag che indica se la cella ha figli o se è una foglia { return ( m_nChild1 == -2 && m_nChild2 == -2) ; } @@ -245,41 +245,43 @@ class Tree public : ~Tree( void) ; Tree( void) ; - //Tree ( const SurfBezier* pSrfBz, bool bSplitPatches = true, const Point3d& ptMin = ORIG, const Point3d& ptMax = ORIG) ; - Tree( const Point3d ptBl, const Point3d ptTr) ; // creatore da usare solo nel caso in cui si voglia aggiungere tagli ad un'unica cella e del risultato ottenere il contorno - bool SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches = true, const Point3d& ptMin = ORIG, const Point3d& ptMax = ORIG) ; - bool GetIndependentTrees( BIPNTVECTOR& vTrees) ; // calcolo la suddivisione della superficie solo sulle singole bbox dei loop di trim ( unendo quelli vicini) - bool BuildTree( double dLinTol = LIN_TOL_STD, double dSideMin = 1, double dSideMax = INFINITO) ; // dSideMax è il massimo per la dimensione maggiore di un triangolo della trimesh - // dSideMin è lunghezza minima del lato di una cella nello spazio reale - bool BuildTree_test( double dLinTol = LIN_TOL_STD, double dSideMin = 1, double dSideMax = INFINITO) ; + Tree( const Point3d ptBl, const Point3d ptTr) ; // da usare solo nel caso in cui si voglia aggiungere tagli ad un'unica cella e del risultato ottenere il contorno + bool SetSurf( const SurfBezier* pSrfBz, const Point3d& ptMin = ORIG, const Point3d& ptMax = ORIG) ; + bool GetIndependentTrees( BIPNTVECTOR& vTrees) ; // calcolo la suddivisione della superficie solo sulle singole bbox dei loop di trim ( unendo quelli vicini) + bool BuildTree( double dLinTol = LIN_TOL_STD, + double dSideMin = 1, // è la minima lunghezza del lato di una cella + double dSideMax = INFINITO) ; // è la massima dimensione di un triangolo della trimesh bool GetPolygons( POLYLINEMATRIX& vvPolygons, POLYLINEMATRIX& vvPolygons3d, vector& vCCEdges3D, ICRVCOMPOPOVECTOR& vCCLoops) ; bool GetPolygonsBasic( POLYLINEVECTOR& vPolygons, POLYLINEVECTOR& vPolygonsCorrected, POLYLINEVECTOR& vPolygons3d) ; // restituisce il poligono corrispondente ad ogni cella foglia dell'albero // ad ogni poligono sono stati aggiunti tutti i vertici dei vicini posizionati sui suoi lati // ad alcuni poligoni potrebbero venire tolti dei punti per evitare errori dovuti ad eventuali poli sui bordi del parametrico - bool GetLeaves ( std::vector& vLeaves) const ; // restituisce gli indici delle foglie nell'albero + bool GetLeaves( std::vector& vLeaves) const ; // restituisce gli indici delle foglie nell'albero bool GetEdges3D ( vector& mCCEdge, POLYLINEVECTOR& vPolygons) ; // restituisce gli edge 3D come polyline - bool GetSplitLoops( ICRVCOMPOPOVECTOR& vCCLoopSplit) const // funzione che restituisce i loop splitatti ai confini delle celle - { for ( int i = 0 ; i < int( m_vCCLoop2D.size()); ++i) vCCLoopSplit.emplace_back( m_vCCLoop2D[i]->Clone()) ; return true ; }; - void SetTestMode( void) { m_bTestMode = true ;} ; // attivando la test mode, per la costruzione dell'albero viene usata la funzione BuiltTree_test e viene corretta di conseguenza la FindCell + bool GetSplitLoops( ICRVCOMPOPOVECTOR& vCCLoopSplit) const // restituisce i loop splitatti ai confini delle celle + { for ( int i = 0 ; i < int( m_vCCLoop2D.size()); ++i) + vCCLoopSplit.emplace_back( m_vCCLoop2D[i]->Clone()) ; + return true ; } // funzioni da usare per ricostruire tagli che vanno aggiunti allo spazio parametrico bool AddCutsToRoot( POLYLINEVECTOR& vCuts) ; // aggiunge i tagli al tree bool CreateCellContour( POLYLINEMATRIX& vPolygons) ; // crea il nuovo contorno esterno, tenendo conto dei tagli - bool IsClosedU( void) const { return m_bClosedU ;} ; // funzione che riferisce se la superficie è chiusa lungo il parametro U - bool IsClosedV( void) const { return m_bClosedV ;} ; // funzione che riferisce se la superficie è chiusa lungo il parametro V - std::vector GetPoles( void) { return m_vbPole ;} ; // funzione che restituisce i flag che indicano se i lati sono collassati in dei poli + bool IsClosedU( void) const // restituisce flag di chiusara in U + { return m_bClosedU ; } + bool IsClosedV( void) const // restituisce flag di chiusara in V + { return m_bClosedV ; } + BOOLVECTOR GetPoles( void) // restituisce i flag che indicano se i lati sono collassati in dei poli + { return m_vbPole ; } private : bool Split( int nId, double dSplitValue) ; // funzione di split di una cella al parametro indicato nella direzione data da bVert bool Split( int nId) ; // funzione di split di una cella dell'albero a metà nella direzione data da bVert - void Balance( void) ; // creo rami in modo che tutte tutte le foglie abbiano come adiacenti foglie ad una profondità di +- 1 - int GetHeightLeaves( int nId, INTVECTOR& vnLeaves, int d = 0) const ; // altezza del subtree a partire dal nodo nId - int GetDepth( int nId, int nRef) const ; // livello del nodo nId + int GetHeightLeaves( int nId, INTVECTOR& vnLeaves, int d = 0) const ; // altezza del subtree a partire dal nodo nId + int GetDepth( int nId, int nRef) const ; // livello del nodo nId void GetTopNeigh( int nId, INTVECTOR& vTopNeighs) const ; // restituisce le celle foglie che sono adiacenti al lato top void GetBottomNeigh( int nId, INTVECTOR& vBottomNeighs) const ; // restituisce le celle foglie che sono adiacenti al lato bottom void GetLeftNeigh( int nId, INTVECTOR& vLeftNeighs) const ; // restituisce le celle foglie che sono adiacenti al lato left void GetRightNeigh( int nId, INTVECTOR& vRightNeighs) const ; // restituisce le celle foglie che sono adiacenti al lato right void GetRootNeigh( int nEdge, INTVECTOR& vNeigh) ; // restituisce le foglie dell'albero che sono adiacenti al lato nEdge, numerato a partire dal top ( 0) in senso antiorario - void ResetTree( void) ; // resetto m_bProcessed a false per tutti i nodi dell'albero + void ResetTree( void) ; // resetto m_bProcessed a false per tutti i nodi dell'albero INTVECTOR FindCell( const Point3d& ptToAssign, const CurveLine& cl, bool bRecurs = false) const ; // dato un punto, trova la cella foglia a cui appartiene INTVECTOR FindCell( const Point3d& ptToAssign, const CurveLine& cl, INTVECTOR vCells, bool bRecurs = false) const ; // dato un punto, trova la cella foglia a cui appartiene bool TraceLoopLabelCell( const POLYLINEVECTOR& vplPolygons) ; // tracing dei loop e labelling delle celle @@ -307,10 +309,8 @@ class Tree bool GetPoint(double dU, double dV, Point3d& pt) const ; bool SavePoint( double dU, double dV, Point3d& pt) ; - private : const SurfBezier* m_pSrfBz ; // superficie di bezier - DBLVECTOR m_vDim ; // distanze tra i vertici della superficie di bezier in 3d in ordine antiorario a partire da ptP00 bool m_bTrimmed ; // superficie trimmata unordered_map m_mChunk ; // mappa in cui vengono salvati chunk di appartenza per ogni loop di trim vector> m_vPlApprox ; // vettore contenente le approssimazioni dei loop // il bool indica se la curva è CCW @@ -319,16 +319,14 @@ class Tree bool m_bClosedU ; // superficie chiusa lungo il parametro U bool m_bClosedV ; // superficie chiusa lungo il parametro V BOOLVECTOR m_vbPole ; // vettore che indica se i vari lati sono collassati in poli ( indici riferiti all'ordine degli edge) - bool m_bSplitPatches ; // flag che indica se le patches sono state divise prima della creazione dell'albero int m_nDegU ; // grado della superficie nel parametro U int m_nDegV ; // grado della superficie nel parametro V int m_nSpanU ; // numero di span lungo il parametro U int m_nSpanV ; // numero di span lungo il parametro V unordered_map m_mTree ; // mappa che contiene tutti i nodi e le foglie dell'albero. -2 è puntatore Null e -1 è root - mutable unordered_map,Point3d, PairHashInt64> m_mPt3d ; // mappa che contiene tutti i punti 3d della superficie calcolati (la chiave sono le coordinate, moltiplicate per 2^24 e trasformate in int) + mutable unordered_map,Point3d,PairHashInt64> m_mPt3d ; // mappa che contiene tutti i punti 3d della superficie calcolati (la chiave sono le coordinate, moltiplicate per 2^24 e trasformate in int) INTVECTOR m_vnLeaves ; // vettore delle foglie INTVECTOR m_vnParents ; // vettore delle celle ottenute dalla divisione preliminare in singole patch - bool m_bTestMode ; // bool che indica se la test mode è attiva ICRVCOMPOPOVECTOR m_vCCLoop2D ; // vettore che contiene le CurveCompo che rappresentano i loop di trim tenendo conto della divisione in celle vector> m_vCEdge2D ; // vettore che le chain che rappresentano ciò che resta degli edge originali, tenendo conto dei trim. } ; \ No newline at end of file