diff --git a/SurfBezier.cpp b/SurfBezier.cpp index 054b366..c1c5b3d 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -1382,7 +1382,7 @@ SurfBezier::GetCurveOnVApproxLen( double dU) const return 0 ; return dLen ; } - +// ////---------------------------------------------------------------------------- //const SurfTriMesh* //SurfBezier::GetAuxSurf( void) const @@ -1471,75 +1471,9 @@ SurfBezier::GetAuxSurf( void) const // se già calcolata, la restituisco if ( m_pSTM != nullptr) return m_pSTM ; - //// definisco il numero degli step in U e in V - // double dMaxLenU = 0 ; - // for ( int j = 0 ; j <= m_nDegV * m_nSpanV ; ++ j) - // dMaxLenU = max( dMaxLenU, GetCurveOnUApproxLen( double( j) / m_nDegV)) ; - // int nStepU = GetSteps( m_nDegU, m_nSpanU, dMaxLenU, 2) ; - // double dMaxLenV = 0 ; - // for ( int i = 0 ; i <= m_nDegU * m_nSpanU ; ++ i) - // dMaxLenV = max( dMaxLenV, GetCurveOnVApproxLen( double( i) / m_nDegU)) ; - // int nStepV = GetSteps( m_nDegV, m_nSpanV, dMaxLenV, 2) ; - // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // if ( m_nDegU == 1 && m_nDegV == 1) { - // // costruttore della superficie - // StmFromTriangleSoup stmSoup ; - // if ( ! stmSoup.Start()) - // return nullptr ; - // // prima curva isoparametrica (potrebbe essere un solo punto) - // PolyLine PL1 ; - // GetCurveOnU( 0, nStepU, PL1) ; - // bool bSingle1 = ( PL1.GetPointNbr() == 1) ; - // // ciclo sulle isoparametriche - // for ( int i = 1 ; i <= nStepV ; ++ i) { - // // seconda curva isoparametrica (con tanti punti quanti la prima, oppure uno solo) - // double dV = double( i) * m_nSpanV / nStepV ; - // PolyLine PL2 ; - // GetCurveOnU( dV, nStepU, PL2) ; - // bool bSingle2 = ( PL2.GetPointNbr() == 1) ; - // // inserisco i triangoli della striscia nel costruttore della TriMesh - // Point3d ptP1c, ptP2c ; - // Point3d ptP1n, ptP2n ; - // bool bNext = PL1.GetFirstPoint( ptP1c) && PL2.GetFirstPoint( ptP2c) ; - // if ( bNext) { - // if ( bSingle1 && bSingle2) - // bNext = false ; - // if ( bSingle1) - // ptP1n = ptP1c ; - // else - // bNext = bNext && PL1.GetNextPoint( ptP1n) ; - // if ( bSingle2) - // ptP2n = ptP2c ; - // else - // bNext = bNext && PL2.GetNextPoint( ptP2n) ; - // } - // while ( bNext) { - // // eventuale primo triangolo (con base sui correnti e vertice su P2 successivo) - // if ( ! AreSamePointApprox( ptP1c, ptP2c)) - // stmSoup.AddTriangle( ptP2c, ptP1c, ptP2n) ; - // // eventuale secondo triangolo (con vertice su P1 corrente e base sui successivi) - // if ( ! AreSamePointApprox( ptP1n, ptP2n)) - // stmSoup.AddTriangle( ptP1c, ptP1n, ptP2n) ; - // // passo alla successiva coppia - // ptP1c = ptP1n ; - // ptP2c = ptP2n ; - // bNext = ( bSingle1 || PL1.GetNextPoint( ptP1n)) && ( bSingle2 || PL2.GetNextPoint( ptP2n)) ; - // } - // // salvo isoparametrica PL2 in PL1 - // PL1.GetUPointList().swap( PL2.GetUPointList()) ; - // bSingle1 = bSingle2 ; - // } - // // la completo - // if ( ! stmSoup.End()) - // return nullptr ; - // // la salvo - // m_pSTM = GetBasicSurfTriMesh( stmSoup.GetSurf()) ; - // } - // else { - - + // costruttore della superficie - Tree Tree( this) ; + Tree Tree( this, true) ; Tree.BuildTree() ; POLYLINEVECTOR vPL ; Tree.GetPolygons( vPL) ; @@ -1548,7 +1482,7 @@ SurfBezier::GetAuxSurf( void) const if ( ! stmSoup.Start()) return nullptr ; - // prendo i punti di ogni polyline dell'albero, li triangolo e li porto in 3d + // prendo i punti di ogni polyline dell'albero, li triangolo e li porto in 3d for ( PolyLine i : vPL) { PNTVECTOR vPnt ; INTVECTOR vTria ; @@ -1556,7 +1490,7 @@ SurfBezier::GetAuxSurf( void) const if ( ! Tri.Make( i, vPnt, vTria)) return nullptr ; - // porto i punti in 3d + // porto i punti in 3d PNTVECTOR vPnt3d ; for ( int i = 0 ; i < int( vPnt.size()) ; ++ i) { Point3d pt3d ; @@ -1571,11 +1505,11 @@ SurfBezier::GetAuxSurf( void) const } } - // la salvo + // la salvo if ( ! stmSoup.End()) return nullptr ; m_pSTM = GetBasicSurfTriMesh( stmSoup.GetSurf()) ; - //} //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + return m_pSTM ; } diff --git a/Tree.cpp b/Tree.cpp index 9d672ab..bce006f 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -99,21 +99,7 @@ void Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches) m_bBilinear = true ; if ( nSpanU * nSpanV != 1) m_bMulti = true ; - if ( bSplitPatches) { - int nId = -1 ; - for ( int i = 1 ; i < nSpanU ; ++i ) { - m_mTree[nId].SetSplitDirVert( true) ; - Split( nId, i) ; - } - for ( int j = 1 ; j < nSpanV ; ++j ) { - - } - - // split preliminari per dividere le patch in modo da triangolarle indipendentemente//////////////////////////////////////////////////////// - // devo sistemare le adiacenze // queste si sistemano da sole con lo split - - // così creo dei child1 da cui devo ripassare per processarle, ma nel mio algoritmo non è previto!!!!!!!!!!!!!!!!! - } + // salvo i vertici 3d della cella root Point3d ptTop( nSpanU, nSpanV) ; Cell cRoot( ORIG, ptTop) ; @@ -130,24 +116,96 @@ void Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches) ptP01 = m_pSrfBz->GetControlPoint( ( nDegU * nSpanU + 1 ) * ( nDegV * nSpanV), &bOk) ; vVert.push_back( ptP01) ; m_mVert.insert( pair( -1, vVert)) ; - // verifico se la superficie è chiusa ed eventualmente sistemo le adiacenze - if ( ( AreSamePointApprox(ptP00, ptP01) && AreSamePointApprox(ptP10, ptP11) ) || - ( AreSamePointApprox(ptP00, ptP10) && AreSamePointApprox(ptP01, ptP11) ) ) { - m_bClosed = true ; - // devo gestire se passo da entrambi questi if/////////////////////////////////////////////////////////////////////////////////////////////////////////// - if ( AreSamePointApprox(ptP00, ptP01)) { - m_mTree[-1].m_nTop = -1 ; - m_mTree[-1].m_nBottom = -1 ; - m_mTree[-1].SetSplitDirVert( false) ; - Split(-1) ; + // se richiesto divido preliminarmente le patches + if ( bSplitPatches && ( nSpanU > 1 || nSpanV > 1)) { + int nId = -1 ; + for ( int i = 1 ; i < nSpanU ; ++i) { + m_mTree[nId].SetSplitDirVert( true) ; + Split( nId, i) ; + ++ nId ; + ++ nId ; } - if (AreSamePointApprox(ptP00, ptP10)) { - m_mTree[-1].m_nLeft = -1 ; - m_mTree[-1].m_nRight = -1 ; - m_mTree[-1].SetSplitDirVert( true) ; - Split( -1) ; + INTVECTOR vLeaves ; + GetHeightLeaves( -1, vLeaves) ; + for ( int nId : vLeaves) { + for ( int j = nSpanV - 1 ; j > 0 ; --j ) { + m_mTree[nId].SetSplitDirVert( false) ; + Split( nId, j) ; + nId = m_mTree[nId].m_nChild2 ; + } + } + // split preliminari per dividere le patch in modo da triangolarle indipendentemente//////////////////////////////////////////////////////// + } + // se non ho già splittato le patches, controllo se la superficie è chiusa. In tal caso la splitto sul parametro su cui è chiusa + else { + // verifico se la superficie è chiusa ed eventualmente sistemo le adiacenze + if ( ( AreSamePointApprox( ptP00, ptP01) && AreSamePointApprox( ptP10, ptP11)) || + ( AreSamePointApprox( ptP00, ptP10) && AreSamePointApprox( ptP01, ptP11))) { + m_bClosed = true ; + if ( AreSamePointApprox(ptP00, ptP01)) { + m_mTree[-1].m_nTop = -1 ; + m_mTree[-1].m_nBottom = -1 ; + m_mTree[-1].SetSplitDirVert( false) ; + Split(-1) ; + // qui devo fare il controllo capped + // devo controllare se i punti ai parametri U=0 e U=1 sono tutti coincidenti + // in caso devo fare uno split nell'altra direzione + bool bOk = false ; + bool bCapped0 = true, bCapped1 = true ; + Point3d ptV0, ptV1 ; + // controllo se tutti i punti sull'isoparametrica sono uguali + for ( int i = 1 ; i < nDegV * nSpanV + 1 ; ++ i) { + ptV0 = m_pSrfBz->GetControlPoint( i * ( nDegU * nSpanU + 1), &bOk) ; + bCapped0 = bCapped0 && AreSamePointApprox( ptP00, ptV0) ; + ptV1 = m_pSrfBz->GetControlPoint( ( i + 1) * ( nDegU * nSpanU + 1) - 1, &bOk) ; + bCapped1 = bCapped1 && AreSamePointApprox( ptP10, ptV1) ; + } + if ( bCapped0 && bCapped1) { + m_mTree[0].SetSplitDirVert( true) ; + Split( 0) ; + m_mTree[1].SetSplitDirVert( true) ; + Split( 1) ; + } + } + if ( AreSamePointApprox(ptP00, ptP10)) { + if( (int) m_mTree.size() == 1) { + m_mTree[-1].m_nLeft = -1 ; + m_mTree[-1].m_nRight = -1 ; + 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 + bool bOk = false ; + bool bCapped0 = true, bCapped1 = true ; + Point3d ptU0, ptU1 ; + // controllo se tutti i punti sull'isoparametrica sono uguali + for ( int i = 1 ; i < nDegU * nSpanU + 1 ; ++ i) { + ptU0 = m_pSrfBz->GetControlPoint( i, &bOk) ; + bCapped0 = bCapped0 && AreSamePointApprox( ptP00, ptU0) ; + ptU1 = m_pSrfBz->GetControlPoint( i + ( nDegU * nSpanU + 1 ) * ( nDegV * nSpanV), &bOk) ; + bCapped1 = bCapped1 && AreSamePointApprox( ptP01, ptU1) ; + } + if ( bCapped0 && bCapped1) { + m_mTree[0].SetSplitDirVert( false) ; + Split( 0) ; + m_mTree[1].SetSplitDirVert( false) ; + Split( 1) ; + } + } + else if ( (int) m_mTree.size() > 1 && (int) m_mTree.size() < 4) { + m_mTree[0].m_nLeft = -1 ; + m_mTree[0].m_nRight = -1 ; + m_mTree[1].m_nLeft = -1 ; + m_mTree[1].m_nRight = -1 ; + m_mTree[0].SetSplitDirVert( true) ; + Split( 0) ; + m_mTree[1].SetSplitDirVert( true) ; + Split( 1) ; + } + } } } + // calcolo e salvo la distanza reale tra i vertici della cella root double dLen0 = Dist( ptP00, ptP10) ; double dLen1 = Dist( ptP10, ptP11) ; @@ -163,84 +221,87 @@ void Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches) void Tree::Split( int nId, double dSplitValue) { - // per lo split a parametro libero devo impedire che si facciano split troppo vicini al bordo!!!!!!!!!!!!!!!!!!! - Cell cChild1, cChild2 ; - cChild1.m_nDepth = m_mTree[nId].m_nDepth + 1 ; - cChild2.m_nDepth = m_mTree[nId].m_nDepth + 1 ; - int nNodes = (int) m_mTree.size() ; - cChild1.m_nId = nNodes - 1 ; - m_mTree[nId].m_nChild1 = nNodes - 1 ; - cChild2.m_nId = nNodes ; - m_mTree[nId].m_nChild2 = nNodes ; - m_mTree.insert( pair( nNodes - 1, cChild1)) ; - m_mTree.insert( pair( nNodes, cChild2)) ; - Point3d ptVert1, ptVert2 ; - PNTVECTOR vVert ; - m_mVert.insert( pair( nNodes - 1, vVert)) ; - m_mVert.insert( pair( nNodes, vVert)) ; - if ( ! m_mTree[nId].IsSplitVert()) - { - // la cella figlio 1 è quella sopra - Point3d ptBL( m_mTree[nId].GetBottomLeft().x, ( m_mTree[nId].GetBottomLeft().y + m_mTree[nId].GetTopRight().y) / 2) ; - m_mTree[m_mTree[nId].m_nChild1].SetBottomLeft( ptBL) ; - m_mTree[m_mTree[nId].m_nChild1].SetTopRight( m_mTree[nId].GetTopRight()) ; - m_mTree[m_mTree[nId].m_nChild1].m_nTop = m_mTree[nId].m_nTop ; - m_mTree[m_mTree[nId].m_nChild1].m_nBottom = m_mTree[nId].m_nChild2 ; - m_mTree[m_mTree[nId].m_nChild1].m_nLeft = m_mTree[nId].m_nLeft ; - m_mTree[m_mTree[nId].m_nChild1].m_nRight = m_mTree[nId].m_nRight ; - Point3d ptTR( m_mTree[nId].GetTopRight().x, ( m_mTree[nId].GetTopRight().y + m_mTree[nId].GetBottomLeft().y) / 2) ; - m_mTree[m_mTree[nId].m_nChild2].SetBottomLeft( m_mTree[nId].GetBottomLeft()) ; - m_mTree[m_mTree[nId].m_nChild2].SetTopRight( ptTR) ; - m_mTree[m_mTree[nId].m_nChild2].m_nTop = m_mTree[nId].m_nChild1 ; - m_mTree[m_mTree[nId].m_nChild2].m_nBottom = m_mTree[nId].m_nBottom ; - m_mTree[m_mTree[nId].m_nChild2].m_nLeft = m_mTree[nId].m_nLeft ; - m_mTree[m_mTree[nId].m_nChild2].m_nRight = m_mTree[nId].m_nRight ; - // metto i corrispondenti 3d dei punti dello split nella mappa m_mVert - // per ogni cella i punti devono essere nell'ordine ptP00, ptP10, ptP11, ptP01 - //double dV = ( 1 - dSplitValue) * m_mTree[nId].GetBottomLeft().y + dSplitValue * m_mTree[nId].GetTopRight().y ; - m_pSrfBz->GetPointD1D2( m_mTree[nId].GetBottomLeft().x, dSplitValue, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptVert1) ; - m_pSrfBz->GetPointD1D2( m_mTree[nId].GetTopRight().x, dSplitValue, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptVert2) ; - m_mVert[nNodes - 1].push_back( ptVert1) ; - m_mVert[nNodes - 1].push_back( ptVert2) ; - m_mVert[nNodes - 1].push_back( m_mVert[nId][2]) ; - m_mVert[nNodes - 1].push_back( m_mVert[nId][3]) ; - m_mVert[nNodes].push_back( m_mVert[nId][0]) ; - m_mVert[nNodes].push_back( m_mVert[nId][1]) ; - m_mVert[nNodes].push_back( ptVert2) ; - m_mVert[nNodes].push_back( ptVert1) ; + // controllo che lo split non venga fatto sul lato della cella + if ( ( m_mTree[nId].IsSplitVert() && dSplitValue > m_mTree[nId].GetBottomLeft().x + EPS_SMALL && dSplitValue < m_mTree[nId].GetTopRight().x - EPS_SMALL) || + ( ! m_mTree[nId].IsSplitVert() && dSplitValue > m_mTree[nId].GetBottomLeft().y + EPS_SMALL && dSplitValue < m_mTree[nId].GetTopRight().y - EPS_SMALL)) { + // per lo split a parametro libero devo impedire che si facciano split troppo vicini al bordo!!!!!!!!!!!!!!!!!!! + m_mTree[nId].m_dSplit = dSplitValue ; + Cell cChild1, cChild2 ; + cChild1.m_nDepth = m_mTree[nId].m_nDepth + 1 ; + cChild2.m_nDepth = m_mTree[nId].m_nDepth + 1 ; + int nNodes = (int) m_mTree.size() ; + cChild1.m_nId = nNodes - 1 ; + m_mTree[nId].m_nChild1 = nNodes - 1 ; + cChild2.m_nId = nNodes ; + m_mTree[nId].m_nChild2 = nNodes ; + m_mTree.insert( pair( nNodes - 1, cChild1)) ; + m_mTree.insert( pair( nNodes, cChild2)) ; + Point3d ptVert1, ptVert2 ; + PNTVECTOR vVert ; + m_mVert.insert( pair( nNodes - 1, vVert)) ; + m_mVert.insert( pair( nNodes, vVert)) ; + if ( ! m_mTree[nId].IsSplitVert()) + { + // la cella figlio 1 è quella sopra + Point3d ptBL( m_mTree[nId].GetBottomLeft().x, dSplitValue) ; + m_mTree[m_mTree[nId].m_nChild1].SetBottomLeft( ptBL) ; + m_mTree[m_mTree[nId].m_nChild1].SetTopRight( m_mTree[nId].GetTopRight()) ; + m_mTree[m_mTree[nId].m_nChild1].m_nTop = m_mTree[nId].m_nTop ; + m_mTree[m_mTree[nId].m_nChild1].m_nBottom = m_mTree[nId].m_nChild2 ; + m_mTree[m_mTree[nId].m_nChild1].m_nLeft = m_mTree[nId].m_nLeft ; + m_mTree[m_mTree[nId].m_nChild1].m_nRight = m_mTree[nId].m_nRight ; + Point3d ptTR( m_mTree[nId].GetTopRight().x, dSplitValue) ; + m_mTree[m_mTree[nId].m_nChild2].SetBottomLeft( m_mTree[nId].GetBottomLeft()) ; + m_mTree[m_mTree[nId].m_nChild2].SetTopRight( ptTR) ; + m_mTree[m_mTree[nId].m_nChild2].m_nTop = m_mTree[nId].m_nChild1 ; + m_mTree[m_mTree[nId].m_nChild2].m_nBottom = m_mTree[nId].m_nBottom ; + m_mTree[m_mTree[nId].m_nChild2].m_nLeft = m_mTree[nId].m_nLeft ; + m_mTree[m_mTree[nId].m_nChild2].m_nRight = m_mTree[nId].m_nRight ; + // metto i corrispondenti 3d dei punti dello split nella mappa m_mVert + // per ogni cella i punti devono essere nell'ordine ptP00, ptP10, ptP11, ptP01 + m_pSrfBz->GetPointD1D2( m_mTree[nId].GetBottomLeft().x, dSplitValue, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptVert1) ; + m_pSrfBz->GetPointD1D2( m_mTree[nId].GetTopRight().x, dSplitValue, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptVert2) ; + m_mVert[nNodes - 1].push_back( ptVert1) ; + m_mVert[nNodes - 1].push_back( ptVert2) ; + m_mVert[nNodes - 1].push_back( m_mVert[nId][2]) ; + m_mVert[nNodes - 1].push_back( m_mVert[nId][3]) ; + m_mVert[nNodes].push_back( m_mVert[nId][0]) ; + m_mVert[nNodes].push_back( m_mVert[nId][1]) ; + m_mVert[nNodes].push_back( ptVert2) ; + m_mVert[nNodes].push_back( ptVert1) ; + } + else { + // la cella figlio 1 è quella di sinistra + Point3d ptTR( dSplitValue, m_mTree[nId].GetTopRight().y) ; + m_mTree[m_mTree[nId].m_nChild1].SetBottomLeft( m_mTree[nId].GetBottomLeft()) ; + m_mTree[m_mTree[nId].m_nChild1].SetTopRight( ptTR) ; + m_mTree[m_mTree[nId].m_nChild1].m_nTop = m_mTree[nId].m_nTop ; + m_mTree[m_mTree[nId].m_nChild1].m_nBottom = m_mTree[nId].m_nBottom ; + m_mTree[m_mTree[nId].m_nChild1].m_nLeft = m_mTree[nId].m_nLeft ; + m_mTree[m_mTree[nId].m_nChild1].m_nRight = m_mTree[nId].m_nChild2 ; + Point3d ptBL( dSplitValue, m_mTree[nId].GetBottomLeft().y) ; + m_mTree[m_mTree[nId].m_nChild2].SetBottomLeft( ptBL) ; + m_mTree[m_mTree[nId].m_nChild2].SetTopRight( m_mTree[nId].GetTopRight()) ; + m_mTree[m_mTree[nId].m_nChild2].m_nTop = m_mTree[nId].m_nTop ; + m_mTree[m_mTree[nId].m_nChild2].m_nBottom = m_mTree[nId].m_nBottom ; + m_mTree[m_mTree[nId].m_nChild2].m_nLeft = m_mTree[nId].m_nChild1 ; + m_mTree[m_mTree[nId].m_nChild2].m_nRight = m_mTree[nId].m_nRight ; + // metto i corrispondenti 3d dei punti dello split nella mappa m_mVert + // per ogni cella i punti devono essere nell'ordine ptP00, ptP10, ptP11, ptP01 + m_pSrfBz->GetPointD1D2( dSplitValue, m_mTree[nId].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptVert2) ; + m_pSrfBz->GetPointD1D2( dSplitValue, m_mTree[nId].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptVert1) ; + m_mVert[nNodes - 1].push_back( m_mVert[nId][0]) ; + m_mVert[nNodes - 1].push_back( ptVert2) ; + m_mVert[nNodes - 1].push_back( ptVert1) ; + m_mVert[nNodes - 1].push_back( m_mVert[nId][3]) ; + m_mVert[nNodes].push_back( ptVert2) ; + m_mVert[nNodes].push_back( m_mVert[nId][1]) ; + m_mVert[nNodes].push_back( m_mVert[nId][2]) ; + m_mVert[nNodes].push_back( ptVert1) ; + } + m_mTree[m_mTree[nId].m_nChild1].SetParent( nId) ; + m_mTree[m_mTree[nId].m_nChild2].SetParent( nId) ; } - else { - // la cella figlio 1 è quella di sinistra - Point3d ptTR( ( m_mTree[nId].GetBottomLeft().x + m_mTree[nId].GetTopRight().x) / 2, m_mTree[nId].GetTopRight().y) ; - m_mTree[m_mTree[nId].m_nChild1].SetBottomLeft( m_mTree[nId].GetBottomLeft()) ; - m_mTree[m_mTree[nId].m_nChild1].SetTopRight( ptTR) ; - m_mTree[m_mTree[nId].m_nChild1].m_nTop = m_mTree[nId].m_nTop ; - m_mTree[m_mTree[nId].m_nChild1].m_nBottom = m_mTree[nId].m_nBottom ; - m_mTree[m_mTree[nId].m_nChild1].m_nLeft = m_mTree[nId].m_nLeft ; - m_mTree[m_mTree[nId].m_nChild1].m_nRight = m_mTree[nId].m_nChild2 ; - Point3d ptBL(( m_mTree[nId].GetBottomLeft().x + m_mTree[nId].GetTopRight().x) / 2, m_mTree[nId].GetBottomLeft().y) ; - m_mTree[m_mTree[nId].m_nChild2].SetBottomLeft( ptBL) ; - m_mTree[m_mTree[nId].m_nChild2].SetTopRight( m_mTree[nId].GetTopRight()) ; - m_mTree[m_mTree[nId].m_nChild2].m_nTop = m_mTree[nId].m_nTop ; - m_mTree[m_mTree[nId].m_nChild2].m_nBottom = m_mTree[nId].m_nBottom ; - m_mTree[m_mTree[nId].m_nChild2].m_nLeft = m_mTree[nId].m_nChild1 ; - m_mTree[m_mTree[nId].m_nChild2].m_nRight = m_mTree[nId].m_nRight ; - // metto i corrispondenti 3d dei punti dello split nella mappa m_mVert - // per ogni cella i punti devono essere nell'ordine ptP00, ptP10, ptP11, ptP01 - //double dU = ( m_mTree[nId].GetBottomLeft().x + m_mTree[nId].GetTopRight().x) / 2 ; - m_pSrfBz->GetPointD1D2( dSplitValue, m_mTree[nId].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptVert2) ; - m_pSrfBz->GetPointD1D2( dSplitValue, m_mTree[nId].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptVert1) ; - m_mVert[nNodes - 1].push_back( m_mVert[nId][0]) ; - m_mVert[nNodes - 1].push_back( ptVert2) ; - m_mVert[nNodes - 1].push_back( ptVert1) ; - m_mVert[nNodes - 1].push_back( m_mVert[nId][3]) ; - m_mVert[nNodes].push_back( ptVert2) ; - m_mVert[nNodes].push_back( m_mVert[nId][1]) ; - m_mVert[nNodes].push_back( m_mVert[nId][2]) ; - m_mVert[nNodes].push_back( ptVert1) ; - } - m_mTree[m_mTree[nId].m_nChild1].SetParent( nId) ; - m_mTree[m_mTree[nId].m_nChild2].SetParent( nId) ; } //---------------------------------------------------------------------------- @@ -259,307 +320,288 @@ Tree::Split( int nId) bool Tree::BuildTree( double dLinTol_, double dSideMin, double dSideMax) { // suddivido lo spazio parametrico con divisioni a metà su uno dei due parametri - INTVECTOR vBalanceCheck ; int nCToSplit = -1 ; - // se ho già fatto degli split preliminari parto dal primo child anziché dal root - if ( (int) m_mTree.size() > 1) - nCToSplit = 0 ; double dLinTol = 0.2 ; //double dSideMin = 1 ; if ( ! m_bTrimmed) { if ( ! m_bBilinear) { while ( nCToSplit != -2 && m_mTree[nCToSplit].IsProcessed() == false) { - // calcolo in quale direzione ho più curvatura - // ptP00P10 è un punto tra P00 e P10 - double dU = ( m_mTree[nCToSplit].GetTopRight().x + m_mTree[nCToSplit].GetBottomLeft().x) / 2 ; - double dV = ( m_mTree[nCToSplit].GetTopRight().y + m_mTree[nCToSplit].GetBottomLeft().y) / 2 ; - double dULoc = 0.5, dVLoc = 0.5 ; - Point3d ptPSrf, ptP00P10, ptP10P11, ptP11P01, ptP01P00 ; - m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; - m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00P10) ; - m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10P11) ; - m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11P01) ; - m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01P00) ; - Point3d ptV = ( 1 - dULoc) * ptP00P10 + dULoc * ptP11P01 ; - Point3d ptU = ( 1 - dVLoc) * ptP10P11 + dVLoc * ptP01P00 ; - // per lo split scelgo la direzione che è più vicina alla superficie originale nel punto di maggior distanza - // misura approssimativa della curvatura in una direzione - double dCurvV = Dist(ptV, ptPSrf) ; - double dCurvU = Dist(ptU, ptPSrf) ; - 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 ; - } - Point3d ptP00, ptP10, ptP11, ptP01 ; - // distanza reale tra i vertici della cella - ptP00 = m_mVert[nCToSplit][0] ; - ptP10 = m_mVert[nCToSplit][1] ; - ptP11 = m_mVert[nCToSplit][2] ; - ptP01 = m_mVert[nCToSplit][3] ; - double dLen0 = Dist( ptP00, ptP10) ; - double dLen1 = Dist( ptP10, ptP11) ; - double dLen2 = Dist( ptP01, ptP11) ; - double dLen3 = Dist( ptP00, ptP01) ; - // verifico che la cella sia da splittare e che eventualmente sia abbastanza grande da poterlo fare - double dSideMinVal = 0, dSideMaxVal = 0 ; - if ( bVert) { - if ( dLen0 != 0 && dLen2 != 0) - dSideMinVal = min( dLen0, dLen2) ; - else - dSideMinVal = max( dLen0, dLen2) ; - } - else { - if ( dLen1 != 0 && dLen3 != 0) - dSideMinVal = min( dLen1, dLen3) ; - else - dSideMinVal = max( dLen1, dLen3) ; - } - // calcolo le diagonali per controllare la dimensione massima dei triangoli in cui dividerei la cella - dSideMaxVal = max( Dist( ptP00, ptP11), Dist( ptP10, ptP01)) ; + // controllo che la cella non sia già stata preliminarmente splittata + if ( m_mTree[nCToSplit].IsLeaf()) { + // calcolo in quale direzione ho più curvatura + // ptP00P10 è un punto tra P00 e P10 + double dU = ( m_mTree[nCToSplit].GetTopRight().x + m_mTree[nCToSplit].GetBottomLeft().x) / 2 ; + double dV = ( m_mTree[nCToSplit].GetTopRight().y + m_mTree[nCToSplit].GetBottomLeft().y) / 2 ; + double dULoc = 0.5, dVLoc = 0.5 ; + Point3d ptPSrf, ptP00P10, ptP10P11, ptP11P01, ptP01P00 ; + m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; + m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP00P10) ; + m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetTopRight().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP10P11) ; + m_pSrfBz->GetPointD1D2( dU, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP11P01) ; + m_pSrfBz->GetPointD1D2( m_mTree[nCToSplit].GetBottomLeft().x, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptP01P00) ; + Point3d ptV = ( 1 - dULoc) * ptP00P10 + dULoc * ptP11P01 ; + Point3d ptU = ( 1 - dVLoc) * ptP10P11 + dVLoc * ptP01P00 ; + // per lo split scelgo la direzione che è più vicina alla superficie originale nel punto di maggior distanza + // misura approssimativa della curvatura in una direzione + double dCurvV = Dist( ptV, ptPSrf) ; + double dCurvU = Dist( ptU, ptPSrf) ; + 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 ; + } + m_mTree[nCToSplit].SetSplitDirVert( bVert) ; + Point3d ptP00, ptP10, ptP11, ptP01 ; + // distanza reale tra i vertici della cella + ptP00 = m_mVert[nCToSplit][0] ; + ptP10 = m_mVert[nCToSplit][1] ; + ptP11 = m_mVert[nCToSplit][2] ; + ptP01 = m_mVert[nCToSplit][3] ; + double dLen0 = Dist( ptP00, ptP10) ; + double dLen1 = Dist( ptP10, ptP11) ; + double dLen2 = Dist( ptP01, ptP11) ; + double dLen3 = Dist( ptP00, ptP01) ; + // verifico che la cella sia da splittare e che eventualmente sia abbastanza grande da poterlo fare + double dSideMinVal = 0, dSideMaxVal = 0 ; + if ( bVert) { + if ( dLen0 != 0 && dLen2 != 0) + dSideMinVal = min( dLen0, dLen2) ; + else + dSideMinVal = max( dLen0, dLen2) ; + } + else { + if ( dLen1 != 0 && dLen3 != 0) + dSideMinVal = min( dLen1, dLen3) ; + else + dSideMinVal = max( dLen1, dLen3) ; + } + // calcolo le diagonali per controllare la dimensione massima dei triangoli in cui dividerei la cella + dSideMaxVal = max( Dist( ptP00, ptP11), Dist( ptP10, ptP01)) ; - // se la cella è abbastanza grande da poter essere divisa ancora, calcolo l'errore di approssimazione - double dErr = 0 ; - if ( dSideMinVal / 2 >= dSideMin && dSideMaxVal < dSideMax && ( dCurvV > dLinTol || dCurvU > dLinTol)) { - CurveLine cl0010, cl0001, cl1011, cl0111 ; - // U=0 - cl0010.Set( ptP00, ptP10) ; - // U=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]) ; - double dDimV = ( dLen1 >= dLen3 ? dLen1 / m_vDim[1] : dLen3 / m_vDim[3]) ; - // 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 ; ++ u) { - dU = double ( u) / double ( nStepsU - 1) ; - dULoc = ( 1 - dU) * m_mTree[nCToSplit].GetBottomLeft().x + dU * m_mTree[nCToSplit].GetTopRight().x ; - if ( ! m_pSrfBz->GetPointD1D2( dULoc, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz0) || - ! m_pSrfBz->GetPointD1D2( dULoc, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz1)) - return false ; - DistPointCurve dpc0010( ptBz0, cl0010) ; - DistPointCurve dpc0111( ptBz1, cl0111) ; - dpc0010.GetMinDistPoint( 0, pt0010, nFlag) ; - dpc0111.GetMinDistPoint( 0, pt0111, nFlag) ; - clV.Set( pt0010, pt0111) ; - for ( int v = 0 ; v < nStepsV ; ++ v) { - dV = double ( v) / double ( nStepsV - 1) ; - dVLoc = ( 1 - dV) * m_mTree[nCToSplit].GetBottomLeft().y + dV * m_mTree[nCToSplit].GetTopRight().y ; - if ( ! m_pSrfBz->GetPointD1D2( dULoc, dVLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBzV)) + // se la cella è abbastanza grande da poter essere divisa ancora, calcolo l'errore di approssimazione + double dErr = 0 ; + bool bSplit = false ; + if ( dSideMinVal / 2 >= dSideMin && dSideMaxVal < dSideMax && ( dCurvV > dLinTol || dCurvU > dLinTol)) { + CurveLine cl0010, cl0001, cl1011, cl0111 ; + // U=0 + cl0010.Set( ptP00, ptP10) ; + // U=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) { + dU = double ( u) / double ( nStepsU - 1) ; + dULoc = ( 1 - dU) * m_mTree[nCToSplit].GetBottomLeft().x + dU * m_mTree[nCToSplit].GetTopRight().x ; + if ( ! m_pSrfBz->GetPointD1D2( dULoc, m_mTree[nCToSplit].GetBottomLeft().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz0) || + ! m_pSrfBz->GetPointD1D2( dULoc, m_mTree[nCToSplit].GetTopRight().y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBz1)) return false ; - DistPointCurve dpc( ptBzV, clV) ; - // distanza di approssimazione locale - double dDist ; - dpc.GetDist( dDist) ; - if ( dDist > dErr) - dErr = dDist ; + DistPointCurve dpc0010( ptBz0, cl0010) ; + DistPointCurve dpc0111( ptBz1, cl0111) ; + dpc0010.GetMinDistPoint( 0, pt0010, nFlag) ; + dpc0111.GetMinDistPoint( 0, pt0111, nFlag) ; + clV.Set( pt0010, pt0111) ; + for ( int v = 0 ; v < nStepsV ; ++ v) { + dV = double ( v) / double ( nStepsV - 1) ; + dVLoc = ( 1 - dV) * m_mTree[nCToSplit].GetBottomLeft().y + dV * m_mTree[nCToSplit].GetTopRight().y ; + if ( ! m_pSrfBz->GetPointD1D2( dULoc, dVLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBzV)) + return false ; + DistPointCurve dpc( ptBzV, clV) ; + // distanza di approssimazione locale + double dDist ; + dpc.GetDist( dDist) ; + //if ( dDist > dErr) + // dErr = dDist ; + if ( dDist > dLinTol) { + bSplit = true ; + break ; + } + } } } - } - if ( dErr > dLinTol || dSideMaxVal > dSideMax) { - m_mTree[nCToSplit].SetSplitDirVert( bVert) ; - // effettuo lo split - Split( nCToSplit) ; + //if ( dErr > dLinTol || dSideMaxVal > dSideMax) { + if ( bSplit || dSideMaxVal > dSideMax) { + m_mTree[nCToSplit].SetSplitDirVert( bVert) ; + // effettuo lo split + Split( nCToSplit) ; - // procedo con lo split del Child1 - nCToSplit = m_mTree[nCToSplit].m_nChild1 ; - } - else { - // sono arrivato ad una cella Leaf, quindi salvo la cella - m_vnLeaves.push_back( nCToSplit) ; - m_mTree[nCToSplit].Processed() ; - // risalgo i parent finché non trovo il primo Child2 da processare - nCToSplit = m_mTree[nCToSplit].m_nParent ; - if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) + // procedo con lo split del Child1 + nCToSplit = m_mTree[nCToSplit].m_nChild1 ; + } + else { + // sono arrivato ad una cella Leaf, quindi salvo la cella + m_vnLeaves.push_back( nCToSplit) ; m_mTree[nCToSplit].Processed() ; - while ( m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) { - if ( m_mTree[nCToSplit].m_nParent != -2) - nCToSplit = m_mTree[nCToSplit].m_nParent ; + // risalgo i parent finché non trovo il primo Child2 da processare + nCToSplit = m_mTree[nCToSplit].m_nParent ; if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) m_mTree[nCToSplit].Processed() ; - if ( nCToSplit == -1 && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) - break ; + while ( m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) { + if ( m_mTree[nCToSplit].m_nParent != -2) + nCToSplit = m_mTree[nCToSplit].m_nParent ; + if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) + m_mTree[nCToSplit].Processed() ; + if ( nCToSplit == -1 && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) + break ; + } + nCToSplit = m_mTree[nCToSplit].m_nChild2 ; } - nCToSplit = m_mTree[nCToSplit].m_nChild2 ; + } + else { + nCToSplit = m_mTree[nCToSplit].m_nChild1 ; } } - Balance( vBalanceCheck) ; // da implementare quando dividerò ad un parametro a scelta e non a metà + Balance() ; // da implementare quando dividerò ad un parametro a scelta e non a metà } // bilineare else { while ( nCToSplit != -2 && m_mTree[nCToSplit].IsProcessed() == false) { - // vertici della cella - Point3d ptP00, ptP10, ptP11, ptP01 ; - ptP00 = m_mVert[nCToSplit][0] ; - ptP10 = m_mVert[nCToSplit][1] ; - ptP11 = m_mVert[nCToSplit][2] ; - ptP01 = m_mVert[nCToSplit][3] ; - - // 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) ; - - // calcolo se è migliore la divisione in orizzontale o in verticale - Point3d ptP00P10, ptP00P01 , ptP01P11, ptP10P11 ; - ptP00P10 = ( ptP00 + ptP10) / 2 ; - ptP10P11 = ( ptP10 + ptP11) / 2 ; - ptP01P11 = ( ptP01 + ptP11) / 2 ; - ptP00P01 = ( ptP00 + ptP01) / 2 ; - bool bVert = false ; - - - //// questo calcolo è inutile perché confronto due cose che sono sempre uguali/////////////////////////////////////////////////////// - // calcolo se è meglio spezzare in orizzontale o in verticale - //double dErrVert1 = ( ( ptP00 - ptP01) + ( ptP01P11 - ptP00P10)).Len() ; - //double dErrVert2 = ( ( ptP00P10 - ptP01P11) + ( ptP11 - ptP10)).Len() ; - //double dErrOriz1 = ( ( ptP00P01 - ptP01) + ( ptP11 - ptP10P11)).Len() ; - //double dErrOriz2 = ( ( ptP00 - ptP00P01) + ( ptP10P11 - ptP10)).Len() ; - ////if (0 ) { - //if ( abs( dErrVert1 + dErrVert2 - dErrOriz1 - dErrOriz2) < EPS_SMALL && nCToSplit != -1) { - // bVert = ! m_mTree[m_mTree[nCToSplit].m_nParent].IsSplitVert() ; - //} - //else { - // if ( dErrVert1 + dErrVert2 > dErrOriz1 + dErrOriz2) { - // bVert = false ; - // } - // else { - // bVert = true ; - // } - //} - - // con questo esce la C sulla bilineare - // calcolo in quale direzione è meglio dividere in base allo stretch - Point3d ptPSrfU, ptPSrfV ; - double dU = 0, dV = 0 ; - double dDistU = 0, dDistV = 0 ; - double dULoc, dVLoc ; - PNTVECTOR vPtU, vPtV ; - if ( ! m_bMulti) { - if ( max(dLen0, dLen2) > max(dLen1, dLen3)) { - bVert = true ; - } - else { - bVert = false ; - } - } - else { - for ( double i = 0.25 ; i < 1 ; i = i + 0.25 ) { - /*Point3d ptU = ( 1 - i) * ptP00P01 + i * ptP10P11 ; - Point3d ptV = ( 1 - i) * ptP00P10 + i * ptP01P11 ;*/ - dU = ( 1 - i) * m_mTree[nCToSplit].GetBottomLeft().x + i * m_mTree[nCToSplit].GetTopRight().x ; - dV = ( 1 - i) * m_mTree[nCToSplit].GetBottomLeft().y + i * m_mTree[nCToSplit].GetTopRight().y ; - dVLoc = ( m_mTree[nCToSplit].GetBottomLeft().y + m_mTree[nCToSplit].GetTopRight().y) / 2 ; - dULoc = ( m_mTree[nCToSplit].GetBottomLeft().x + m_mTree[nCToSplit].GetTopRight().x) / 2 ; - m_pSrfBz->GetPointD1D2( dU, dVLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrfU) ; - m_pSrfBz->GetPointD1D2( dULoc, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrfV) ; - //dDistU = max( Dist( ptU , ptPSrfU), dDistU) ; - //dDistV = max( Dist( ptV , ptPSrfV), dDistV) ; - vPtU.push_back(ptPSrfU) ; - vPtV.push_back(ptPSrfV) ; - } - // devo guardare se i tre punti in vPtU e vPtV sono allineati - CurveLine clU, clV; - clU.Set(vPtU[0], vPtU[1]) ; - clV.Set(vPtV[0], vPtV[1]) ; - DistPointCurve dpcU( vPtU[2], clU, false) ; - DistPointCurve dpcV( vPtV[2], clV, false) ; - dpcU.GetDist( dDistU) ; - dpcV.GetDist( dDistV) ; - if ( dDistU > dDistV ) { - bVert = true ; - } - else { - bVert = false ; - } - } - - // diagonali - //Point3d ptP00P11, ptP10P01, ptPSrf ; - //ptP00P11 = ( ptP00 + ptP11) / 2 ; - //ptP10P01 = ( ptP10 + ptP01) / 2 ; - //double dU = ( m_mTree[nCToSplit].GetBottomLeft().x + m_mTree[nCToSplit].GetTopRight().x) / 2 ; - //double dV = ( m_mTree[nCToSplit].GetBottomLeft().y + m_mTree[nCToSplit].GetTopRight().y) / 2 ; - //m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; - //if ( Dist( ptP00P11, ptPSrf) > Dist( ptP10P01, ptPSrf)) - // bVert = false ; - //else - // bVert = true ; - - - - - // verifico che la cella sia abbastanza grande da poter essere splittata - double dSideMinVal = 0, dSideMaxVal = 0 ; - if ( bVert) { - if ( dLen0 != 0 && dLen2 != 0) - dSideMinVal = min( dLen0, dLen2) ; - else - dSideMinVal = max( dLen0, dLen2) ; - } - else { - if ( dLen1 != 0 && dLen3 != 0) - dSideMinVal = min( dLen1, dLen3) ; - else - dSideMinVal = max( dLen1, dLen3) ; - } - // calcolo le diagonali per controllare la dimensione massima dei triangoli in cui dividerei la cella - dSideMaxVal = max( Dist( ptP00, ptP11), Dist( ptP10, ptP01)) ; - - - double dErr = 0 ; - if ( m_bMulti ) { - Point3d ptPSrf ; - Plane3d plAppr ; - plAppr.Set( ptP00, ( ptP00 - ptP01) ^ ( ptP00 - ptP10)) ; - for ( double i = 0.25 ; i < 1 ; i = i + 0.25) { - for ( double j = 0.25 ; j < 1 ; j = j + 0.25) { - double dU = ( 1 - i) * m_mTree[nCToSplit].GetTopRight().x + i * m_mTree[nCToSplit].GetBottomLeft().x ; - double dV = ( 1 - j) * m_mTree[nCToSplit].GetTopRight().y + j * m_mTree[nCToSplit].GetBottomLeft().y ; - m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; - dErr = max( abs( DistPointPlane( ptPSrf, plAppr)), dErr) ; + if ( m_mTree[nCToSplit].IsLeaf()) { + // vertici della cella + Point3d ptP00, ptP10, ptP11, ptP01 ; + ptP00 = m_mVert[nCToSplit][0] ; + ptP10 = m_mVert[nCToSplit][1] ; + ptP11 = m_mVert[nCToSplit][2] ; + ptP01 = m_mVert[nCToSplit][3] ; + // 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) ; + // calcolo se è migliore la divisione in orizzontale o in verticale + Point3d ptP00P10, ptP00P01 , ptP01P11, ptP10P11 ; + ptP00P10 = ( ptP00 + ptP10) / 2 ; + ptP10P11 = ( ptP10 + ptP11) / 2 ; + ptP01P11 = ( ptP01 + ptP11) / 2 ; + ptP00P01 = ( ptP00 + ptP01) / 2 ; + + bool bVert = false ; + // calcolo in quale direzione è meglio dividere in base allo stretch + Point3d ptPSrfU, ptPSrfV ; + double dU = 0, dV = 0 ; + double dDistU = 0, dDistV = 0 ; + double dULoc, dVLoc ; + PNTVECTOR vPtU, vPtV ; + if ( ! m_bMulti) { + if ( max(dLen0, dLen2) > max(dLen1, dLen3)) { + bVert = true ; + } + else { + bVert = false ; } } - } - else { - dErr = 1. / 4. * ( (ptP00 - ptP01) + (ptP11 - ptP10)).Len() ; - } - // se la cella è abbastanza grande da poter essere divisa ancora e devo approssimare meglio, la divido - if ( dSideMinVal / 2 >= dSideMin && dSideMaxVal < dSideMax && dErr > dLinTol) { - m_mTree[nCToSplit].SetSplitDirVert( bVert) ; - // effettuo lo split - Split( nCToSplit) ; + else { + for ( double i = 0.25 ; i < 1 ; i = i + 0.25 ) { + dU = ( 1 - i) * m_mTree[nCToSplit].GetBottomLeft().x + i * m_mTree[nCToSplit].GetTopRight().x ; + dV = ( 1 - i) * m_mTree[nCToSplit].GetBottomLeft().y + i * m_mTree[nCToSplit].GetTopRight().y ; + dVLoc = ( m_mTree[nCToSplit].GetBottomLeft().y + m_mTree[nCToSplit].GetTopRight().y) / 2 ; + dULoc = ( m_mTree[nCToSplit].GetBottomLeft().x + m_mTree[nCToSplit].GetTopRight().x) / 2 ; + m_pSrfBz->GetPointD1D2( dU, dVLoc, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrfU) ; + m_pSrfBz->GetPointD1D2( dULoc, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrfV) ; + vPtU.push_back( ptPSrfU) ; + vPtV.push_back( ptPSrfV) ; + } + // devo guardare se i tre punti in vPtU e vPtV sono allineati + CurveLine clU, clV; + clU.Set(vPtU[0], vPtU[1]) ; + clV.Set(vPtV[0], vPtV[1]) ; + DistPointCurve dpcU( vPtU[2], clU, false) ; + DistPointCurve dpcV( vPtV[2], clV, false) ; + dpcU.GetDist( dDistU) ; + dpcV.GetDist( dDistV) ; + if ( dDistU > dDistV) { + bVert = true ; + } + else { + bVert = false ; + } + } + + // verifico che la cella sia abbastanza grande da poter essere splittata + double dSideMinVal = 0, dSideMaxVal = 0 ; + if ( bVert) { + if ( dLen0 != 0 && dLen2 != 0) + dSideMinVal = min( dLen0, dLen2) ; + else + dSideMinVal = max( dLen0, dLen2) ; + } + else { + if ( dLen1 != 0 && dLen3 != 0) + dSideMinVal = min( dLen1, dLen3) ; + else + dSideMinVal = max( dLen1, dLen3) ; + } + // calcolo le diagonali per controllare la dimensione massima dei triangoli in cui dividerei la cella + dSideMaxVal = max( Dist( ptP00, ptP11), Dist( ptP10, ptP01)) ; - // procedo con lo split del Child1 - nCToSplit = m_mTree[nCToSplit].m_nChild1 ; - } - else { - // sono arrivato ad una cella Leaf, quindi salvo la cella - m_vnLeaves.push_back( nCToSplit) ; - m_mTree[nCToSplit].Processed() ; - // risalgo i parent finché non trovo il primo Child2 da processare - nCToSplit = m_mTree[nCToSplit].m_nParent ; - if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) + + double dErr = 0 ; + if ( m_bMulti) { + Point3d ptPSrf ; + Plane3d plAppr ; + if ( ! AreSamePointApprox( ptP00, ptP10) && ! AreSamePointApprox( ptP00, ptP01)) + plAppr.Set( ptP00, ( ptP00 - ptP01) ^ ( ptP00 - ptP10)) ; + else if ( AreSamePointApprox( ptP00, ptP10)) { + plAppr.Set( ptP01, ( ptP00 - ptP01) ^ ( ptP01 - ptP11)) ; + } + else if ( AreSamePointApprox( ptP00, ptP01)) { + plAppr.Set( ptP10, ( ptP10 - ptP11) ^ ( ptP00 - ptP10)) ; + } + for ( double i = 0.25 ; i < 1 ; i = i + 0.25) { + for ( double j = 0.25 ; j < 1 ; j = j + 0.25) { + double dU = ( 1 - i) * m_mTree[nCToSplit].GetTopRight().x + i * m_mTree[nCToSplit].GetBottomLeft().x ; + double dV = ( 1 - j) * m_mTree[nCToSplit].GetTopRight().y + j * m_mTree[nCToSplit].GetBottomLeft().y ; + m_pSrfBz->GetPointD1D2( dU, dV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptPSrf) ; + dErr = max( abs( DistPointPlane( ptPSrf, plAppr)), dErr) ; + } + } + } + else { + dErr = 1. / 4. * ( (ptP00 - ptP01) + (ptP11 - ptP10)).Len() ; + } + // se la cella è abbastanza grande da poter essere divisa ancora e devo approssimare meglio, la divido + if ( dSideMinVal / 2 >= dSideMin && dSideMaxVal < dSideMax && dErr > dLinTol) { + m_mTree[nCToSplit].SetSplitDirVert( bVert) ; + // effettuo lo split + Split( nCToSplit) ; + + // procedo con lo split del Child1 + nCToSplit = m_mTree[nCToSplit].m_nChild1 ; + } + else { + // sono arrivato ad una cella Leaf, quindi salvo la cella + m_vnLeaves.push_back( nCToSplit) ; m_mTree[nCToSplit].Processed() ; - while ( m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) { - if ( m_mTree[nCToSplit].m_nParent != -2) - nCToSplit = m_mTree[nCToSplit].m_nParent ; + // risalgo i parent finché non trovo il primo Child2 da processare + nCToSplit = m_mTree[nCToSplit].m_nParent ; if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) m_mTree[nCToSplit].Processed() ; - if ( nCToSplit == -1 && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) - break ; + while ( m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) { + if ( m_mTree[nCToSplit].m_nParent != -2) + nCToSplit = m_mTree[nCToSplit].m_nParent ; + if ( m_mTree[m_mTree[nCToSplit].m_nChild1].IsProcessed() && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) + m_mTree[nCToSplit].Processed() ; + if ( nCToSplit == -1 && m_mTree[m_mTree[nCToSplit].m_nChild2].IsProcessed()) + break ; + } + nCToSplit = m_mTree[nCToSplit].m_nChild2 ; } - nCToSplit = m_mTree[nCToSplit].m_nChild2 ; + } + else { + nCToSplit = m_mTree[nCToSplit].m_nChild1 ; } } } @@ -572,7 +614,7 @@ bool Tree::BuildTree( double dLinTol_, double dSideMin, double dSideMax) } //---------------------------------------------------------------------------- -void Tree::Balance( INTVECTOR vCheck) +void Tree::Balance() { //for ( int i : vCheck ) { // // non ancora implementato @@ -652,12 +694,13 @@ void Tree::GetTopNeigh( int nId, INTVECTOR& vTopNeighs) vector vCells ; for ( int k : vTopNeighs) vCells.push_back( m_mTree[k]) ; - sort( vCells.begin(), vCells.end(), Cell::minorX ) ; + std::sort( vCells.begin(), vCells.end(), Cell::minorX) ; vTopNeighs.clear() ; for ( Cell c : vCells) vTopNeighs.push_back( c.m_nId) ; } + //---------------------------------------------------------------------------- void Tree::GetBottomNeigh( int nId, INTVECTOR& vBottomNeighs) { @@ -730,7 +773,7 @@ void Tree::GetBottomNeigh( int nId, INTVECTOR& vBottomNeighs) vector vCells ; for ( int k : vBottomNeighs) vCells.push_back( m_mTree[k]) ; - sort( vCells.begin(), vCells.end(), Cell::minorX) ; + std::sort( vCells.begin(), vCells.end(), Cell::minorX) ; vBottomNeighs.clear() ; for ( Cell c : vCells) vBottomNeighs.push_back( c.m_nId) ; @@ -809,7 +852,7 @@ void Tree::GetLeftNeigh( int nId, INTVECTOR& vLeftNeighs) vector vCells ; for ( int k : vLeftNeighs) vCells.push_back( m_mTree[k]) ; - sort( vCells.begin(), vCells.end(), Cell::minorY) ; + std::sort( vCells.begin(), vCells.end(), Cell::minorY) ; vLeftNeighs.clear() ; for ( Cell c : vCells) vLeftNeighs.push_back( c.m_nId) ; @@ -887,7 +930,7 @@ void Tree::GetRightNeigh( int nId, INTVECTOR& vRightNeighs) vector vCells ; for ( int k : vRightNeighs) vCells.push_back( m_mTree[k]) ; - sort( vCells.begin(), vCells.end(), Cell::minorY) ; + std::sort( vCells.begin(), vCells.end(), Cell::minorY) ; vRightNeighs.clear() ; for ( Cell c : vCells) vRightNeighs.push_back( c.m_nId) ; @@ -896,35 +939,41 @@ void Tree::GetRightNeigh( int nId, INTVECTOR& vRightNeighs) //---------------------------------------------------------------------------- int Tree::GetHeightLeaves( int nId, INTVECTOR& vnLeaves, int d) { - if ( (int) vnLeaves.size() == 0) { - if ( m_mTree[nId].IsLeaf()) - return d ; - else { - vnLeaves.push_back( m_mTree[nId].m_nChild1) ; - vnLeaves.push_back( m_mTree[nId].m_nChild2) ; - if ( ! m_mTree[m_mTree[nId].m_nChild1].IsLeaf() || ! m_mTree[m_mTree[nId].m_nChild2].IsLeaf()) - // almeno un child non è leaf quindi devo richiamare ricorsivamente questa funzione sui child in questione - d = GetHeightLeaves( nId, vnLeaves, m_mTree[m_mTree[nId].m_nChild1].m_nDepth) ; - } + if ( nId == -1 && m_mTree[-1].IsLeaf()) { + vnLeaves.push_back( -1) ; + return 0 ; } else { - for ( int j = 0 ; j != (int) vnLeaves.size() ; ++ j) { - int i = vnLeaves[j] ; - if ( m_mTree[i].IsLeaf() ) { - continue ; - } + if ( (int) vnLeaves.size() == 0) { + if ( m_mTree[nId].IsLeaf()) + return d ; else { - // se la cella non è leaf la tolgo dal vettore delle foglie e aggiungo invece i suoi child - vnLeaves.erase( remove( vnLeaves.begin(),vnLeaves.end(),i)) ; - -- j ; - vnLeaves.push_back( m_mTree[i].m_nChild1) ; - vnLeaves.push_back( m_mTree[i].m_nChild2) ; - d = max ( d, m_mTree[m_mTree[i].m_nChild1].m_nDepth) ; + vnLeaves.push_back( m_mTree[nId].m_nChild1) ; + vnLeaves.push_back( m_mTree[nId].m_nChild2) ; + if ( ! m_mTree[m_mTree[nId].m_nChild1].IsLeaf() || ! m_mTree[m_mTree[nId].m_nChild2].IsLeaf()) + // almeno un child non è leaf quindi devo richiamare ricorsivamente questa funzione sui child in questione + d = GetHeightLeaves( nId, vnLeaves, m_mTree[m_mTree[nId].m_nChild1].m_nDepth) ; } } - return d ; + else { + for ( int j = 0 ; j != (int) vnLeaves.size() ; ++ j) { + int i = vnLeaves[j] ; + if ( m_mTree[i].IsLeaf() ) { + continue ; + } + else { + // se la cella non è leaf la tolgo dal vettore delle foglie e aggiungo invece i suoi child + vnLeaves.erase( remove( vnLeaves.begin(),vnLeaves.end(),i)) ; + -- j ; + vnLeaves.push_back( m_mTree[i].m_nChild1) ; + vnLeaves.push_back( m_mTree[i].m_nChild2) ; + d = max ( d, m_mTree[m_mTree[i].m_nChild1].m_nDepth) ; + } + } + return d ; + } + return d - m_mTree[nId].m_nDepth ; } - return d - m_mTree[nId].m_nDepth ; } //---------------------------------------------------------------------------- @@ -974,7 +1023,7 @@ bool Tree::GetPolygons( POLYLINEVECTOR& vPolygons) vNeigh.clear() ; vVertices.push_back( m_mTree[nId].GetTopRight()) ; GetTopNeigh ( nId, vNeigh) ; - reverse( vNeigh.begin(), vNeigh.end()) ; + std::reverse( vNeigh.begin(), vNeigh.end()) ; // aggiungo i vertici che sono sul lato top, solo se ho più di un vicino top if ( (int) vNeigh.size() != 0 && (int) vNeigh.size() != 1) { for ( int j : vNeigh) @@ -985,7 +1034,7 @@ bool Tree::GetPolygons( POLYLINEVECTOR& vPolygons) bTopLeft = false ; vNeigh.clear() ; GetLeftNeigh ( nId, vNeigh) ; - reverse( vNeigh.begin(), vNeigh.end()) ; + std::reverse( vNeigh.begin(), vNeigh.end()) ; // aggiungo i vertici che sono sul lato left, solo se ho più di un vicino left if ( (int) vNeigh.size() != 0 && (int) vNeigh.size() != 1) { for ( int j : vNeigh) diff --git a/Tree.h b/Tree.h index 00f73bf..7ccbc33 100644 --- a/Tree.h +++ b/Tree.h @@ -48,6 +48,7 @@ class Cell int m_nRight ; // cella adiacente al lato right int m_nParent ; // cella genitore int m_nDepth ; // profondità della cella rispetto a root + double m_dSplit ; // parametro a cui è stata splittata la cella int m_nChild1 ; // prima cella figlio int m_nChild2 ; // seconda cella figlio @@ -56,7 +57,6 @@ class Cell Point3d m_ptPtr ; // punto top right bool m_bProcessed ; // flag che indica se la cella è stata processata bool m_bSplitVert ; // flag che indica in quale direzione è stata divisa la cella - double m_dSplit ; // parametro a cui è stata splittata la cella } ; //---------------------------------------------------------------------------- @@ -66,7 +66,7 @@ public : ~Tree( void) ; Tree( void) ; Tree ( const SurfBezier* pSrfBz, bool bSplitPatches = false) ; - void SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches = false) ; + void SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches = true) ; bool BuildTree( double dLinTol = LIN_TOL_STD, double dSideMin = 5, 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 GetPolygons( POLYLINEVECTOR& vPolygons) ; @@ -74,7 +74,7 @@ public : private : void Split( int nId, double dSplitValue) ; // funzione di split di una cella al parametro indicato nella direzione data da bVert void Split( int nId) ; // funzione di split di una cella dell'albero a metà nella direzione data da bVert - void Balance ( INTVECTOR vCheck) ; // creo rami in modo che tutte tutte le foglie abbiano come adiacenti foglie ad una profonditù di +- 1 + void Balance () ; // 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) ; // altezza del subtree a partire dal nodo nId int GetDepth ( int nId, int nRef) ; // livello del nodo nId void GetTopNeigh( int nId, INTVECTOR& vTopNeighs) ; // restituisce le celle foglie che sono adiacenti al lato top