diff --git a/SurfBezier.cpp b/SurfBezier.cpp index e8326a5..ee91115 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -45,7 +45,7 @@ GEOOBJ_REGISTER( SRF_BEZIER, NGE_S_BEZ, SurfBezier) ; //---------------------------------------------------------------------------- SurfBezier::SurfBezier( void) : m_pSTM( nullptr), m_nStatus( TO_VERIFY), m_nDegU(), m_nDegV(), m_nSpanU(), m_nSpanV(), m_bRat( false), - m_bTrimmed( 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} { } @@ -138,6 +138,8 @@ SurfBezier::SetControlPoint( int nInd, const Point3d& ptCtrl, double dW) bool SurfBezier::SetTrimRegion( ISurfFlatRegion& sfrTrimReg, bool bIntersectOrSubtract) { + // controllo se aveo trim precedenti ed eventualmente faccio un'intersezione con lo spazio esistente + // verifico la regione passata if ( &sfrTrimReg == nullptr || ! sfrTrimReg.IsValid()) return false ; @@ -157,11 +159,14 @@ SurfBezier::SetTrimRegion( ISurfFlatRegion& sfrTrimReg, bool bIntersectOrSubtrac return false ; } ResetAuxSurf() ; - delete m_pSTM ; // assegno la regione di trim m_bTrimmed = true ; - delete m_pTrimReg ; - m_pTrimReg = GetBasicSurfFlatRegion( Release( pSfrTrim)) ; + if ( m_pTrimReg != nullptr ) { + if ( ! m_pTrimReg->Intersect( *pSfrTrim)) + return false ; + } + else + m_pTrimReg = GetBasicSurfFlatRegion( Release( pSfrTrim)) ; return true ; } @@ -1441,7 +1446,7 @@ SurfBezier::GetAuxSurf( void) const ResetAuxSurf() ; return nullptr ; } - // se gi� calcolata, la restituisco + // se già calcolata, la restituisco if ( m_pSTM != nullptr) return m_pSTM ; @@ -1475,8 +1480,22 @@ SurfBezier::GetAuxSurf( void) const //} //// per usare i polygon basic/////////////////// + + /////////////////// così facendo sto recuperando gli Edge e la chiususra solo dell'ULTIMO TREE analizzato!!!!! (in caso di trim che creano più chunk analizzo più tree separatamente)/////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // aggiorno la chiusura della superficie + m_bClosedU = Tree.IsClosedU() ; + m_bClosedV = Tree.IsClosedV() ; + m_vbPole = Tree.GetPoles() ; + // salvo i bordi in 3d, che servono in caso si voglia trimmare la superficie DOPO aver costruito la trimesh ausiliaria - Tree.GetEdge3D( m_vPLEdges) ; + POLYLINEVECTOR vPLEdges ; + Tree.GetEdge3D( vPLEdges) ; + for ( int i= 0 ; i < int( vPLEdges.size()); ++i) { + m_vCCEdge.emplace_back( CreateBasicCurveComposite()) ; + m_vCCEdge.back()->FromPolyLine( vPLEdges[i]) ; + } + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // qui non sarebbe male stampare un messaggio di errore nel log se avevo un'area da disegnare ma non sono usciti dei poligoni if ( int(vvPL.size()) == 0) @@ -1582,7 +1601,7 @@ SurfBezier::UnprojectCurveFromStm( const ICurveComposite* pCC) const return nullptr ; pl.AddUPoint( 0, pt2D) ; // aggiungo tutti i successivi - for ( int i = 1 ; i < int( pCC->GetCurveCount()) ; ++i) { + for ( int i = 0 ; i < int( pCC->GetCurveCount()) ; ++i) { const ICurve* pCrv = pCC->GetCurve( i) ; pCrv->GetEndPoint( pt3D) ; DistPointSurfTm distPtStm( pt3D, *GetAuxSurf()) ; @@ -1596,6 +1615,37 @@ SurfBezier::UnprojectCurveFromStm( const ICurveComposite* pCC) const return Release( pCC2D) ; } +//---------------------------------------------------------------------------- +bool +SurfBezier::AddCurveCompoToCuts( ICurveComposite* pCrvCompo, ICRVCOMPOPOVECTOR& vpCCOpen, ICRVCOMPOPOVECTOR& vpCCClosed, double dToler) +{ + // se lunghezza curva inferiore a 5 volte la tolleranza, la ignoro e sposto il punto finale nel punto di fine della curva che sto ignorando + double dCrvLen ; + if ( ! pCrvCompo->GetLength( dCrvLen) || dCrvLen < 5. * dToler) + return true ; + // se curva chiusa entro 5 volte la tolleranza ma considerata aperta, la chiudo bene + Point3d ptStart, ptEnd ; + if ( pCrvCompo->GetStartPoint( ptStart) && + pCrvCompo->GetEndPoint( ptEnd) && + AreSamePointEpsilon( ptStart, ptEnd, 5. * dToler) && + ! AreSamePointApprox( ptStart, ptEnd)) { + // porto il punto finale a coincidere esattamente con l'inizio + pCrvCompo->ModifyEnd( ptStart) ; + } + // unisco segmenti allineati + pCrvCompo->MergeCurves( 0.5 * dToler, ANG_TOL_STD_DEG) ; + + // porto la curva nello spazio parametrico + PtrOwner pCC( UnprojectCurveFromStm( pCrvCompo)) ; + + // le curve aperte le tengo da parte per giuntarle alla fine col bordo + if ( ! pCC->IsClosed()) + vpCCOpen.emplace_back( Release( pCC)) ; + // le curve chiuse le metto tutte insieme subito + else + vpCCClosed.emplace_back( Release( pCC)) ; + return true ; +} //---------------------------------------------------------------------------- bool @@ -1609,13 +1659,17 @@ SurfBezier::Cut( const Plane3d& plPlane, bool bSaveOnEq) PNTVECTOR vPnt ; BIPNTVECTOR vBPnt ; TRIA3DVECTOR vTria ; + // con queste righe funzionano anche i tagli multipli//////////////////////////////////////////////// + bool bMod = false ; + // ATTENZIONE!!!!! ad ogni "return false" in questa funzione dovrei reimpostare "m_bTrimmed = true" se bMod == true/////////////////////////////////////////////////// + if ( m_bTrimmed) { + m_bTrimmed = false ; + ResetAuxSurf() ; + bMod = true ; + } + ////i tagli multipli//////////////////////////////////////////////// IntersPlaneSurfTm( plPlane, *GetAuxSurf(), vPnt, vBPnt, vTria) ; - // recupero la superficie di trim a cui devo aggiungere tutt i nuovi loop di trim - PtrOwner sfrTrimReg ( GetTrimRegion()) ; - if ( IsNull( sfrTrimReg)) - sfrTrimReg.Set( CreateBasicSurfFlatRegion()) ; - // concateno le curve 3d ChainCurves chainC ; double dToler = EPS_SMALL ; @@ -1631,13 +1685,14 @@ SurfBezier::Cut( const Plane3d& plPlane, bool bSaveOnEq) // recupero i percorsi concatenati Point3d ptNear = ( vBPnt.empty() ? ORIG : vBPnt[0].first) ; INTVECTOR vId ; - // Devo controllare se i trim intersecano il bordo dello spazio parametrico ed eventualmente spezzare le curve di trim in 2D tenendo conto della periodicità - // costruisco le curveCompo che rappresetano gli edge - ICRVCOMPOPVECTOR vCCEdge ; - for ( int i= 0 ; i < int( m_vPLEdges.size()); ++i) { - vCCEdge.emplace_back() ; - vCCEdge.back()->FromPolyLine( m_vPLEdges[i]) ; - } + + // debug///////////////////////////////////////////////////////// + //vector vGeoObj ; + //vGeoObj.push_back( static_cast(vCCEdge[1])) ; + //vGeoObj.push_back( static_cast(vCCEdge[3])) ; + //SaveGeoObj( vGeoObj, "D:\\Temp\\inters\\sphere_3d_edges.nge") ; + // debug///////////////////////////////////////////////////////// + // separo tra loop chiusi, interni allo spazio parametrico e loop passanti che tagliano lo spazio intersecando i bordi ICRVCOMPOPOVECTOR vpCCOpen ; ICRVCOMPOPOVECTOR vpCCClosed ; @@ -1648,10 +1703,11 @@ SurfBezier::Cut( const Plane3d& plPlane, bool bSaveOnEq) return false ; // recupero gli estremi dei segmenti, creo le linee e le inserisco nella composita bool bAdded = true ; + bool bPrevLineThroughEdge = false ; for ( int i = 0 ; i < int( vId.size()) ; ++ i) { // creo un segmento di retta - PtrOwner pLine( CreateCurveLine()) ; - if ( IsNull( pLine)) + ICurveLine* pLine( CreateCurveLine()) ; + if ( pLine == nullptr) return false ; // recupero gli estremi (non vanno mai invertiti per opzione di concatenamento) int nInd = abs( vId[i]) - 1 ; @@ -1659,37 +1715,79 @@ SurfBezier::Cut( const Plane3d& plPlane, bool bSaveOnEq) Point3d ptEnd = vBPnt[nInd].second ; // provo ad accodarlo alla composita bAdded = ( Dist( ptStart, ptEnd) > dToler / 2 && - pLine->Set( ptStart, ptEnd) && - pCrvCompo->AddCurve( Release( pLine), true, dToler)) ; - ptNear = ( bAdded ? ptEnd : ptStart) ; - } - // se lunghezza curva inferiore a 5 volte la tolleranza, la ignoro e sposto il punto finale nel punto di fine della curva che sto ignorando - double dCrvLen ; - if ( ! pCrvCompo->GetLength( dCrvLen) || dCrvLen < 5. * dToler) - continue ; - // se curva chiusa entro 5 volte la tolleranza ma considerata aperta, la chiudo bene - Point3d ptStart, ptEnd ; - if ( pCrvCompo->GetStartPoint( ptStart) && - pCrvCompo->GetEndPoint( ptEnd) && - AreSamePointEpsilon( ptStart, ptEnd, 5. * dToler) && - ! AreSamePointApprox( ptStart, ptEnd)) { - // porto il punto finale a coincidere esattamente con l'inizio - pCrvCompo->ModifyEnd( ptStart) ; - } - // assegno estrusione come direzione normale al piano - pCrvCompo->SetExtrusion( plPlane.GetVersN()) ; - // unisco segmenti allineati - pCrvCompo->MergeCurves( 0.5 * dToler, ANG_TOL_STD_DEG) ; + pLine->Set( ptStart, ptEnd)) ; + // se la superficie è chiusa devo controllare se sto attraversando un edge con un trim + if ( (m_bClosedU || m_bClosedV) && ! bPrevLineThroughEdge) { + IntersCurveCurve icc0( *pLine, *m_vCCEdge[0]) ; + IntersCurveCurve icc1( *pLine, *m_vCCEdge[1]) ; + IntersCurveCurve icc2( *pLine, *m_vCCEdge[2]) ; + IntersCurveCurve icc3( *pLine, *m_vCCEdge[3]) ; + // se non ho intersezioni proseguo aggiungendo il punto + if ( icc0.GetIntersCount() == 0 && + icc1.GetIntersCount() == 0 && + icc2.GetIntersCount() == 0 && + icc3.GetIntersCount() == 0) { + // se non ho intersezioni con gli edge posso aggiungere semplicemente alla compo + bAdded = bAdded && pCrvCompo->AddCurve( pLine, true, dToler) ; + ptNear = ( bAdded ? ptEnd : ptStart) ; + } + else { + // recupero la prima intersezione che trovo + // se ho intersezioni multiple è perché sono edge sovrapposti + IntCrvCrvInfo iccInfo ; + if ( icc0.GetIntersCount() != 0) + icc0.GetIntCrvCrvInfo( 0, iccInfo) ; + else if ( icc1.GetIntersCount() != 0) + icc1.GetIntCrvCrvInfo( 0, iccInfo) ; + else if ( icc2.GetIntersCount() != 0) + icc2.GetIntCrvCrvInfo( 0, iccInfo) ; + else if ( icc3.GetIntersCount() != 0) + icc3.GetIntCrvCrvInfo( 0, iccInfo) ; - // porto la curva nello spazio parametrico - PtrOwner pCC( UnprojectCurveFromStm( pCrvCompo)) ; - - // le curve aperte le tengo da parte per giuntarle alla fine col bordo - if ( ! pCC->IsClosed()) - vpCCOpen.emplace_back( Release( pCC)) ; - // le curve chiuse le metto tutte insieme subito - else - vpCCClosed.emplace_back( Release( pCC)) ; // da controllare che funzioni anche se passo i loop con orientamenti sbagliati////////// + ICurveLine* pCLPart1 ( CreateCurveLine()) ; + // spezzo la linea che avrei dovuto inserire, facendola finire dove ho l'intersezione con un edge della cella root + Vector3d vtDir ; pLine->GetStartDir( vtDir) ; + Point3d ptBeforeTheEdge = iccInfo.IciA[0].ptI - vtDir * EPS_SMALL * EPS_SMALL ; + pCLPart1->Set( ptStart, ptBeforeTheEdge) ; + pCrvCompo->AddCurve( pCLPart1, true, dToler) ; + bAdded = false ; + AddCurveCompoToCuts( pCrvCompo, vpCCOpen, vpCCClosed) ; + pCrvCompo->Clear() ; + // comincio a costruire una nuova curva partendo oltre l'edge che ho appena attraversato + // probabilmente mi conviene spostare di poco il punto in modo da aiutare la funzione di Unproject + //ICurveLine* pCLPart2 ( CreateCurveLine()) ; + Point3d ptBeyondTheEdge = iccInfo.IciA[0].ptI + vtDir * EPS_SMALL * EPS_SMALL; + //pCLPart2->Set( ptBeyondTheEdge, ptEnd) ; + //bAdded = bAdded && pCrvCompo->AddCurve( pCLPart2, true, dToler) ; + ptNear = ptBeyondTheEdge ; + bPrevLineThroughEdge = true ; + } + } + // sennò procedo normalmente aggiungendo il punto + else { + bAdded = bAdded && pCrvCompo->AddCurve( pLine, true, dToler) ; + ptNear = ( bAdded ? ptEnd : ptStart) ; + bPrevLineThroughEdge = false ; + } + } + AddCurveCompoToCuts( pCrvCompo, vpCCOpen, vpCCClosed) ; + } + ////debug + //vector vGeoObj ; + //for ( int i = 0 ; i < int(vpCCOpen.size()); ++i ) + // vGeoObj.emplace_back(static_cast( vpCCOpen[i]->Clone())) ; + //SaveGeoObj( vGeoObj, "D:\\Temp\\inters\\sphere_openCuts_beforeJoint.nge") ; + ////debug + if ( int( vpCCOpen.size()) != 0) { + // devo verificare se devo giuntare la prima curva aperta con l'ultima + Point3d ptStartOpen, ptEndOpen ; + vpCCOpen.front()->GetStartPoint( ptStartOpen) ; + vpCCOpen.back()->GetEndPoint( ptEndOpen) ; + if ( AreSamePointApprox(ptStartOpen, ptEndOpen) ) { + vpCCOpen.back()->AddCurve( vpCCOpen.front()) ; + Release( vpCCOpen[0]) ; + vpCCOpen.erase( vpCCOpen.begin()) ; + } } // creo il nuovo bordo usando i loop aperti @@ -1703,6 +1801,15 @@ SurfBezier::Cut( const Plane3d& plPlane, bool bSaveOnEq) vPL.emplace_back( pl) ; } Tree.AddCutsToRoot( vPL) ; + ////debug + //vector vGeoObj ; + //for ( int k = 0 ; k < int( vPL.size()) ; ++ k) { + // PtrOwner pCrv( CreateCurveComposite()) ; + // pCrv->FromPolyLine( vPL[k]) ; + // vGeoObj.emplace_back( static_cast(Release( pCrv))) ; + //} + //SaveGeoObj( vGeoObj, "D:\\Temp\\inters\\sphere_openCuts.nge") ; + ////debug Tree.CreateCellContour( vPolygons) ; } @@ -1729,6 +1836,10 @@ SurfBezier::Cut( const Plane3d& plPlane, bool bSaveOnEq) for ( int j = 0 ; j < int( vPolygons[i].size()); ++j) { PtrOwner pCC( CreateCurveComposite()) ; pCC->FromPolyLine( vPolygons[i][j]) ; + ////debug + //PtrOwner pCrvCopy( pCC->Clone()) ; + //SaveGeoObj( Release(pCrvCopy), "D:\\Temp\\inters\\sphere_trim_curve2D.nge") ; + ////debug sfrContour.AddCurve( Release( pCC)) ; } } @@ -1771,19 +1882,29 @@ SurfBezier::Cut( const Plane3d& plPlane, bool bSaveOnEq) // aggiorno la superficie di trim Point3d ptStart ; - Vector3d vtDir ; + Vector3d vtDir, vtDirS, vtDirE ; PtrOwner pCrv( pSFR->GetLoop( nChunkMin, nLoopMin)) ; pCrv->GetStartPoint( ptStart) ; - pCrv->GetStartDir( vtDir) ; - vtDir.Rotate( Z_AX, bPos? 90 : -90) ; + pCrv->GetStartDir( vtDirS) ; + pCrv->GetEndDir( vtDirE) ; + //vtDirS.Rotate( Z_AX, bPos? 90 : -90) ; + vtDir = vtDirS + vtDirE ; PtrOwner pCL( CreateCurveLine()) ; - pCL->SetPVL( ptStart, vtDir, 1e6) ; - IntersCurveCurve icc( *Release( pCL), *Release(pCrv)) ; - // verifico di guardare verso l'interno ( il numero di intersezioni deve essere pari visto che partivo da un punto sulla curva) - if ( icc.GetIntersCount()%2 != 0) - return false ; // o sennò un altro tentativo prima di rinunciare + pCL->SetPVL( ptStart, vtDirS, 1e6) ; + IntersCurveCurve icc( *pCL, *pCrv) ; IntCrvCrvInfo iccInfo ; - icc.GetIntCrvCrvInfo( 1, iccInfo) ; + // verifico di guardare verso l'interno ( il numero di intersezioni deve essere pari visto che partivo da un punto sulla curva) + if ( icc.GetIntersCount()%2 != 0) { + vtDir = vtDirS - vtDirE ; + PtrOwner pCL2( CreateCurveLine()) ; pCL2->SetPVL( ptStart, vtDir, 1e6) ; + IntersCurveCurve icc2( *pCL2, *pCrv) ; + if ( icc2.GetIntersCount()%2 != 0) + return false ; + icc2.GetIntCrvCrvInfo( 1, iccInfo) ; + } + else + icc.GetIntCrvCrvInfo( 1, iccInfo) ; + Point3d ptI = iccInfo.IciA[0].ptI ; Point3d ptToCheck = ( ptStart + ptI) / 2 ; Point3d pt3D ; GetPointD1D2( ptToCheck.x / SBZ_TREG_COEFF, ptToCheck.y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt3D) ; @@ -1793,12 +1914,20 @@ SurfBezier::Cut( const Plane3d& plPlane, bool bSaveOnEq) // 1. se il punto è sopra il piano ed era dentro una curva CCW // 2. se il punto è sotto il piano ed era interno ad una curva CW + //debug PtrOwner pSrfFR_Copy( pSFR->Clone()) ; SaveGeoObj( Release(pSrfFR_Copy), "D:\\Temp\\inters\\failed_trim.nge", GDB_SV_BIN) ; - if ( ( dDist > 0 && bPos) || ( dDist < 0 && ! bPos)) - SetTrimRegion( *Release( pSFR), false) ; - else - SetTrimRegion( *Release( pSFR)) ; + //debug + + // la SetTrimRegion controlla se avevo trim precedenti ed eventualmente fa l'intersezione con lo spazio esistente + if ( ( dDist > 0 && bPos) || ( dDist < 0 && ! bPos)) { + if ( ! SetTrimRegion( *pSFR, false) || ! m_pTrimReg->IsValid()) + return false ; + } + else { + if ( ! SetTrimRegion( *pSFR) || ! m_pTrimReg->IsValid()) + return false ; + } return true ; } @@ -1812,40 +1941,168 @@ SurfBezier::UnprojectPointFromStm( int nT, const Point3d& ptI, Point3d& ptSP, in // recupero i dati dei vertici del triangolo che fa intersezione int nVert[3] ; pSurfTm->GetTriangle( nT, nVert) ; - double dU0, dV0, dU1, dV1,dU2, dV2 ; - pSurfTm->GetVertexParam( nVert[0], dU0, dV0) ; - pSurfTm->GetVertexParam( nVert[1], dU1, dV1) ; - pSurfTm->GetVertexParam( nVert[2], dU2, dV2) ; - Point3d pt0, pt1, pt2 ; - pSurfTm->GetVertex( nVert[0], pt0) ; - pSurfTm->GetVertex( nVert[1], pt1) ; - pSurfTm->GetVertex( nVert[2], pt2) ; + PNTVECTOR vPtPa(3) ; + pSurfTm->GetVertexParam( nVert[0], vPtPa[0].x,vPtPa[0].y) ; + pSurfTm->GetVertexParam( nVert[1], vPtPa[1].x,vPtPa[1].y) ; + pSurfTm->GetVertexParam( nVert[2], vPtPa[2].x,vPtPa[2].y) ; + PNTVECTOR vPT(3) ; + pSurfTm->GetVertex( nVert[0], vPT[0]) ; + pSurfTm->GetVertex( nVert[1], vPT[1]) ; + pSurfTm->GetVertex( nVert[2], vPT[2]) ; + // se la superficie è chiusa controllo se devo tenere conto della periodicità nel prendere le coordinate parametriche dei vertici + if ( m_bClosedU || m_bClosedV) { + double dParamH = m_nSpanV * SBZ_TREG_COEFF ; + double dParamL = m_nSpanU * SBZ_TREG_COEFF ; + // devo trovare il lato più lungo e confrontarlo con le dimensioni dello spazio parametrico + Vector3d vtDir ; + double dDist ; + if ( DistXY( vPtPa[0], vPtPa[1]) > DistXY( vPtPa[1], vPtPa[2]) && DistXY( vPtPa[0], vPtPa[1]) > Dist( vPtPa[0], vPtPa[2])){ + vtDir = vPtPa[1] - vPtPa[0] ; + dDist = DistXY( vPtPa[0], vPtPa[1]) ; + } + else if ( DistXY( vPtPa[1], vPtPa[2]) > DistXY( vPtPa[0], vPtPa[1]) && DistXY( vPtPa[1], vPtPa[2]) > Dist( vPtPa[0], vPtPa[2])){ + vtDir = vPtPa[2] - vPtPa[1] ; + dDist = DistXY( vPtPa[1], vPtPa[2]) ; + } + else if ( DistXY( vPtPa[0], vPtPa[2]) > DistXY( vPtPa[0], vPtPa[1]) && DistXY( vPtPa[0], vPtPa[2]) > Dist( vPtPa[1], vPtPa[2])){ + vtDir = vPtPa[2] - vPtPa[0] ; + dDist = DistXY( vPtPa[0], vPtPa[2]) ; + } + vtDir.Normalize() ; + // se la dimensione maggiore è grande come la dimensione dello spazio parametrico allora potrebbe essere che le coordinate parametriche di un vertice + // siano da correggere per periodicità + if ( m_bClosedU && abs(vtDir.x) > abs( vtDir.y) && dDist > dParamL * 0.95 ) { + // trovo se dei punti del triangolo sono sul bordo dello spazio parametrico + BOOLVECTOR vbOn(3) ; + for ( int p = 0 ; p < 3; ++p ) { + if ( m_vCCEdge[1]->IsAPoint()) { + Point3d pt ; + m_vCCEdge[1]->GetStartPoint( pt) ; + vbOn[p] = AreSamePointApprox( pt, vPT[p]) ; + } + else + vbOn[p] =m_vCCEdge[1]->IsPointOn( vPT[p]) ; + if ( m_vCCEdge[3]->IsAPoint()) { + Point3d pt ; + m_vCCEdge[3]->GetStartPoint( pt) ; + vbOn[p] = AreSamePointApprox( pt, vPT[p]) ; + } + else + vbOn[p] =m_vCCEdge[3]->IsPointOn( vPT[p]) ; + } + // controllo che almeno un punto sia su un edge + if ( vbOn[0] || vbOn[1] || vbOn[2]) { + double dRightX ; + // tengo per buone le coordinate dei punti che NON sono sul bordo dello spazio parametrico + for ( int p = 0 ; p < 3; ++p) { + if ( !vbOn[p] ) { + dRightX = vPtPa[p].x ; + break ; + } + } + for ( int p = 0 ; p < 3; ++p) { + if ( abs(vPtPa[p].x - dRightX) > EPS_SMALL ) { + if ( vPtPa[p].x < EPS_SMALL) + vPtPa[p].x = dParamL ; + else + vPtPa[p].x = 0 ; + } + } + } + } + else if ( m_bClosedV && abs(vtDir.y) > abs(vtDir.x) && dDist > dParamH * 0.95) { + BOOLVECTOR vbOn(3) ; + for ( int p = 0 ; p < 3; ++p ) { + if ( m_vCCEdge[0]->IsAPoint()) { + Point3d pt ; + m_vCCEdge[0]->GetStartPoint( pt) ; + vbOn[p] = AreSamePointApprox( pt, vPT[p]) ; + } + else + vbOn[p] =m_vCCEdge[0]->IsPointOn( vPT[p]) ; + if ( m_vCCEdge[2]->IsAPoint()) { + Point3d pt ; + m_vCCEdge[2]->GetStartPoint( pt) ; + vbOn[p] = AreSamePointApprox( pt, vPT[p]) ; + } + else + vbOn[p] =m_vCCEdge[2]->IsPointOn( vPT[p]) ; + } + // controllo che almeno un punto sia su un edge + if ( vbOn[0] || vbOn[1] || vbOn[2]) { + double dRightY ; + // tengo per buone le coordinate dei punti che NON sono sul bordo dello spazio parametrico + for ( int p = 0 ; p < 3; ++p) { + if ( ! vbOn[p]) { + dRightY = vPtPa[p].y ; + break ; + } + } + for ( int p = 0 ; p < 3; ++p) { + if ( abs(vPtPa[p].y - dRightY) > EPS_SMALL) { + if ( vPtPa[p].y < EPS_SMALL) + vPtPa[p].y = dParamH ; + else + vPtPa[p].y = 0 ; + } + } + } + } + } + // devo anche tener conto della possibilità che i lati siano collassati in poli + //if ( m_vbPole[0]) + // ; // se l'intersezione era su un vertice restituisco le coordinate parametriche del vertice if ( nIL == 3 ) { - if ( AreSamePointApprox(ptI, pt0)) - ptSP.Set( dU0, dV0, 0) ; - else if ( AreSamePointApprox(ptI, pt1)) - ptSP.Set( dU1, dV1, 0) ; - else if ( AreSamePointApprox(ptI, pt2)) - ptSP.Set( dU2, dV2, 0) ; + if ( AreSamePointApprox(ptI, vPT[0])) + ptSP = vPtPa[0] ; + else if ( AreSamePointApprox(ptI, vPT[1])) + ptSP = vPtPa[1] ; + else if ( AreSamePointApprox(ptI, vPT[2])) + ptSP = vPtPa[2] ; return true ; } // calcolo approssimativamente le coordinate nello spazio parametrico del punto di intersezione // quindi prima calcolo la composizione lineare tra i vertici del triangolo per ottenere il punto di intersezione Eigen::Matrix3d mA ; - mA.col(0) << pt0.x, pt0.y , pt0.z ; - mA.col(1) << pt1.x, pt1.y , pt1.z ; - mA.col(2) << pt2.x, pt2.y , pt2.z ; + mA.col(0) << vPT[0].x, vPT[0].y , vPT[0].z ; + mA.col(1) << vPT[1].x, vPT[1].y , vPT[1].z ; + mA.col(2) << vPT[2].x, vPT[2].y , vPT[2].z ; Eigen::Vector3d b ( ptI.x, ptI.y, ptI.z) ; Eigen::Vector3d x = mA.fullPivLu().solve(b) ; // applico questa composizione alle loro coordinate parametriche Eigen::Matrix3d mB ; - mB.col(0) << dU0, dV0, 0 ; - mB.col(1) << dU1, dV1, 0 ; - mB.col(2) << dU2, dV2, 0 ; + mB.col(0) << vPtPa[0].x, vPtPa[0].y, 0 ; + mB.col(1) << vPtPa[1].x, vPtPa[1].y, 0 ; + mB.col(2) << vPtPa[2].x, vPtPa[2].y, 0 ; Eigen::Vector3d ptParam = mB * x ; ptSP.x = ptParam.x() ; ptSP.y = ptParam.y() ; + // controllo se le coordinate sono nello spazio parametrico ed eventualmente se posso sistemarle tenendo conto della periodicità ( se la superficie è chiusa) + if ( ptSP.x < 0) { + if ( m_bClosedU) + ptSP.x += m_nSpanU * SBZ_TREG_COEFF ; + else + ptSP.x = 0 ; + } + if ( ptSP.x > m_nSpanU * SBZ_TREG_COEFF ) { + if ( m_bClosedU) + ptSP.x -= m_nSpanU * SBZ_TREG_COEFF ; + else + ptSP.x = m_nSpanU * SBZ_TREG_COEFF ; + } + if ( ptSP.y < 0 ) { + if ( m_bClosedV) + ptSP.y += m_nSpanV * SBZ_TREG_COEFF ; + else + ptSP.y = 0 ; + } + if ( ptSP.y > m_nSpanV * SBZ_TREG_COEFF ) { + if ( m_bClosedU) + ptSP.y -= m_nSpanV * SBZ_TREG_COEFF ; + else + ptSP.y = m_nSpanV * SBZ_TREG_COEFF ; + } return true ; } diff --git a/SurfBezier.h b/SurfBezier.h index 7e150f4..6e2ae77 100644 --- a/SurfBezier.h +++ b/SurfBezier.h @@ -163,6 +163,7 @@ class SurfBezier : public ISurfBezier, public IGeoObjRW bool GetCurveOnV( double dU, int nStep, PolyLine& plCrvV) const ; double GetCurveOnUApproxLen( double dV) const ; double GetCurveOnVApproxLen( double dU) const ; + bool AddCurveCompoToCuts( ICurveComposite* pCrvCompo, ICRVCOMPOPOVECTOR& vpCCOpen, ICRVCOMPOPOVECTOR& vpCCClosed, double dToler = EPS_SMALL) ; private : ObjGraphicsMgr m_OGrMgr ; // gestore grafica dell'oggetto @@ -174,12 +175,15 @@ class SurfBezier : public ISurfBezier, public IGeoObjRW int m_nSpanV ; // numero di pezze in V bool m_bRat ; // flag di razionale/polinomiale bool m_bTrimmed ; // flag per presenza regione di trim + mutable bool m_bClosedU ; // flag che indica se la superficie è chiusa lungo il parametro U + mutable bool m_bClosedV ; // flag che indica se la superficie è chiusa lungo il parametro V + mutable BOOLVECTOR m_vbPole ; // vettore di flag che indicano se i lati sono collassati in dei poli PNTVECTOR m_vPtCtrl ; // vettore dei punti di controllo DBLVECTOR m_vWeCtrl ; // vettore dei pesi di controllo SurfFlatRegion* m_pTrimReg ; // eventuale regione di trim int m_nTempProp[2] ; // vettore proprietà temporanee double m_dTempParam[2] ; // vettore parametri temporanei - mutable POLYLINEVECTOR m_vPLEdges ; // vettore delle polyline degli edge nello spazio 3D + mutable ICRVCOMPOPVECTOR m_vCCEdge ;// vettore delle curve compo degli edge nello spazio 3D } ; //----------------------------------------------------------------------------- diff --git a/Tree.cpp b/Tree.cpp index 2c63934..5c895b7 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -30,7 +30,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_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}), + m_bSplitPatches( true), m_bTestMode( false) { Point3d ptBl( 0, 0), ptTr ( 1 * SBZ_TREG_COEFF, 1 * SBZ_TREG_COEFF) ; Cell cRoot( ptBl, ptTr) ; @@ -39,7 +40,8 @@ Tree::Tree( void) //---------------------------------------------------------------------------- Tree::Tree( const SurfBezier* pSrfBz, const bool bSplitPatches, const Point3d& ptMin, const Point3d& ptMax) - : m_pSrfBz( nullptr), m_bTrimmed( false), m_bBilinear( false), m_bMulti( false), m_bClosedU( false), m_bClosedV( 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}), + m_bSplitPatches( true), m_bTestMode( false) { SetSurf( pSrfBz, bSplitPatches, ptMin, ptMax) ; } @@ -51,7 +53,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_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}), + m_bSplitPatches( true), m_bTestMode( false) { Cell cRoot( ptBl, ptTr) ; m_mTree.insert( pair< int, Cell>( -1, cRoot)) ; @@ -227,16 +230,18 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi // 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 + bool bPole0 = true, bPole1 = true ; + Point3d ptU0, ptU1 ; + // controllo se tutti i punti di controllo 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) ; + ptU0 = m_pSrfBz->GetControlPoint( i * ( nDegU * nSpanU + 1), &bOk) ; + bPole0 = bPole0 && AreSamePointApprox( ptP00, ptU0) ; + ptU1 = m_pSrfBz->GetControlPoint( ( i + 1) * ( nDegU * nSpanU + 1) - 1, &bOk) ; + bPole1 = bPole1 && AreSamePointApprox( ptP10, ptU1) ; } - if ( bCapped0 && bCapped1) { + m_vbPole[1] = bPole0 ; + m_vbPole[3] = bPole1 ; + if ( bPole0 && bPole1) { m_mTree[0].SetSplitDirVert( true) ; Split( 0) ; m_mTree[1].SetSplitDirVert( true) ; @@ -256,16 +261,18 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi // 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 ; + bool bPole0 = true, bPole1 = true ; + Point3d ptV0, ptV1 ; // 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) ; + ptV0 = m_pSrfBz->GetControlPoint( i, &bOk) ; + bPole0 = bPole0 && AreSamePointApprox( ptP00, ptV0) ; + ptV1 = m_pSrfBz->GetControlPoint( i + ( nDegU * nSpanU + 1) * ( nDegV * nSpanV), &bOk) ; + bPole1 = bPole1 && AreSamePointApprox( ptP01, ptV1) ; } - if ( bCapped0 && bCapped1) { + m_vbPole[0] = bPole0 ; + m_vbPole[3] = bPole1 ; + if ( bPole0 && bPole1) { m_mTree[0].SetSplitDirVert( false) ; Split( 0) ; m_mTree[1].SetSplitDirVert( false) ; @@ -1434,12 +1441,13 @@ Tree::GetPolygons( POLYLINEMATRIX& vPolygons) //---------------------------------------------------------------------------- bool -Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygons, INTVECTOR& vCells) +Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygons, INTVECTOR vCells) { // condizioni per il calcolo dei poligoni di base if ( m_vPolygons.empty() || // se non li ho mai calcolati ( ! m_vPolygons.empty() && ! vCells.empty()) || // se ho già calcolato dei poligoni ma ne sto chiedendo di un altro gruppo di celle ( vCells.empty() && m_vPolygons.size() != m_vnLeaves.size())) { // se sto chiedendo i poligoni di tutte le celle, ma i poligoni già calcolati sono meno delle celle + m_vPolygons.clear() ; // se non ho dato un elenco di celle in input do per scontato che la chiamata sia per calcolare i poligoni di tutte le foglie if ( vCells.empty()) vCells = m_vnLeaves ; @@ -1463,6 +1471,7 @@ Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygons, INTVECTOR& vCells) bool bBottomRight , bTopLeft ; // scorro lungo tutte le celle leaves e oltre agli angoli della cella aggiungo alla polyline della cella anche i vertici, delle celle adiacenti, // che sono sui lati della cella corrente + // N.B. :i poligoni sono costruiti a partire dal ptBL !!! for ( int nId : vCells) { vVertices.clear() ; vNeigh.clear() ; @@ -3582,34 +3591,64 @@ Tree::GetEdge3D( POLYLINEVECTOR& vPLEdges) // scorro sui poligoni delle celle di un lato for ( int c = 0 ; c < int( mPL[i].size()) ; ++c) { Point3d pt ; mPL[i][c].GetFirstPoint( pt) ; + Point3d pt3d ; // a seconda del lato controllo di stare scorrendo il poligono prendendo solo i punti su quel lato - if ( i == 0 && AreSamePointApprox(pt, m_mTree.at(vEdges[0][c]).GetTopRight()) ) { + if ( i == 0) { + while ( ! AreSamePointApprox(pt, m_mTree.at(vEdges[0][c]).GetTopRight()) && mPL[i][c].GetNextPoint( pt)) { + continue ; + } + vPLEdges.back().AddUPoint( nPtCount, m_mVert.at(vEdges[0][c])[2]) ; + ++ nPtCount ; // scorro fino alla fine di quel lato - while ( ! AreSamePointApprox(pt, m_mTree.at(vEdges[0][c]).GetTopLeft()) && mPL[i][c].GetNextPoint( pt)) { - vPLEdges.back().AddUPoint( nPtCount, pt) ; + while ( mPL[i][c].GetNextPoint( pt) && ! AreSamePointApprox(pt, m_mTree.at(vEdges[0][c]).GetTopLeft())) { + m_pSrfBz->GetPointD1D2( pt.x / SBZ_TREG_COEFF, pt.y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt3d) ; + vPLEdges.back().AddUPoint( nPtCount, pt3d) ; ++ nPtCount ; } + vPLEdges.back().AddUPoint( nPtCount, m_mVert.at(vEdges[0][c])[3]) ; + ++ nPtCount ; } - else if ( i == 1 && AreSamePointApprox(pt, m_mTree.at(vEdges[1][c]).GetTopLeft()) ) { + else if ( i == 1 ) { + while ( ! AreSamePointApprox(pt, m_mTree.at(vEdges[1][c]).GetTopLeft()) && mPL[i][c].GetNextPoint( pt)) { + continue ; + } + vPLEdges.back().AddUPoint( nPtCount, m_mVert.at(vEdges[1][c])[3]) ; + ++ nPtCount ; // scorro fino alla fine di quel lato - while ( ! AreSamePointApprox(pt, m_mTree.at(vEdges[1][c]).GetBottomLeft()) && mPL[i][c].GetNextPoint( pt)) { + while ( mPL[i][c].GetNextPoint( pt) && ! AreSamePointApprox(pt, m_mTree.at(vEdges[1][c]).GetBottomLeft())) { vPLEdges.back().AddUPoint( nPtCount, pt) ; ++ nPtCount ; } + vPLEdges.back().AddUPoint( nPtCount, m_mVert.at(vEdges[1][c])[0]) ; + ++ nPtCount ; } - else if ( i == 2 && AreSamePointApprox(pt, m_mTree.at(vEdges[2][c]).GetBottomLeft()) ) { + else if ( i == 2) { + while ( ! AreSamePointApprox(pt, m_mTree.at(vEdges[2][c]).GetBottomLeft()) && mPL[i][c].GetNextPoint( pt)) { + continue ; + } + vPLEdges.back().AddUPoint( nPtCount, m_mVert.at(vEdges[2][c])[0]) ; + ++ nPtCount ; // scorro fino alla fine di quel lato - while ( ! AreSamePointApprox(pt, m_mTree.at(vEdges[2][c]).GetBottomRight()) && mPL[i][c].GetNextPoint( pt)) { + while ( mPL[i][c].GetNextPoint( pt) && ! AreSamePointApprox(pt, m_mTree.at(vEdges[2][c]).GetBottomRight())) { vPLEdges.back().AddUPoint( nPtCount, pt) ; ++ nPtCount ; } + vPLEdges.back().AddUPoint( nPtCount, m_mVert.at(vEdges[2][c])[1]) ; + ++ nPtCount ; } - else if ( i == 3 && AreSamePointApprox(pt, m_mTree.at(vEdges[3][c]).GetBottomRight()) ) { + else if ( i == 3) { + while ( ! AreSamePointApprox(pt, m_mTree.at(vEdges[3][c]).GetBottomRight()) && mPL[i][c].GetNextPoint( pt)) { + continue ; + } + vPLEdges.back().AddUPoint( nPtCount, m_mVert.at(vEdges[3][c])[1]) ; + ++ nPtCount ; // scorro fino alla fine di quel lato - while ( ! AreSamePointApprox(pt, m_mTree.at(vEdges[3][c]).GetTopRight()) && mPL[i][c].GetNextPoint( pt)) { + while ( mPL[i][c].GetNextPoint( pt) && ! AreSamePointApprox(pt, m_mTree.at(vEdges[3][c]).GetTopRight())) { vPLEdges.back().AddUPoint( nPtCount, pt) ; ++ nPtCount ; } + vPLEdges.back().AddUPoint( nPtCount, m_mVert.at(vEdges[3][c])[2]) ; + ++ nPtCount ; } } } @@ -3631,14 +3670,69 @@ Tree::AddCutsToRoot( POLYLINEVECTOR& vCuts) PolyLine pl = vCuts.at( i) ; m_mTree.at( nRoot).m_vInters.emplace_back() ; Point3d pt ; pl.GetFirstPoint( pt) ; - int nEdgeIn ; OnWhichEdge( nRoot, pt, nEdgeIn) ; + int nEdgeIn ; + // se non trovo il primo punto esattamente su un lato, estendo il primo tratto della polyline all'inditro finchè trovo un'intersezione con un lato + // questa intersezione diventa il nuovo primo punto del vettore intersezione + if ( ! OnWhichEdge(nRoot, pt, nEdgeIn) ) { + Point3d ptSecond ; pl.GetNextPoint( ptSecond) ; + PtrOwner pCL( CreateCurveLine()) ; pCL->SetPVL( ptSecond, pt - ptSecond, 1e6) ; + PtrOwner pCL0( CreateCurveLine()) ; pCL0->Set( m_mTree.at(-1).GetTopRight(), m_mTree.at(-1).GetTopLeft()) ; + PtrOwner pCL1( CreateCurveLine()) ; pCL1->Set( m_mTree.at(-1).GetTopLeft(), m_mTree.at(-1).GetBottomLeft()) ; + PtrOwner pCL2( CreateCurveLine()) ; pCL2->Set( m_mTree.at(-1).GetBottomLeft(), m_mTree.at(-1).GetBottomRight()) ; + PtrOwner pCL3( CreateCurveLine()) ; pCL3->Set( m_mTree.at(-1).GetBottomRight(), m_mTree.at(-1).GetTopRight()) ; + IntersCurveCurve icc0( *pCL, *pCL0) ; + IntersCurveCurve icc1( *pCL, *pCL1) ; + IntersCurveCurve icc2( *pCL, *pCL2) ; + IntersCurveCurve icc3( *pCL, *pCL3) ; + IntCrvCrvInfo iccInfo ; + if (icc0.GetCrossIntersCount() != 0) + icc0.GetIntCrvCrvInfo( 0, iccInfo) ; + else if (icc1.GetCrossIntersCount() != 0) + icc1.GetIntCrvCrvInfo( 0, iccInfo) ; + else if (icc2.GetCrossIntersCount() != 0) + icc2.GetIntCrvCrvInfo( 0, iccInfo) ; + else if (icc3.GetCrossIntersCount() != 0) + icc3.GetIntCrvCrvInfo( 0, iccInfo) ; + pt = iccInfo.IciA[0].ptI ; + if ( ! OnWhichEdge(nRoot, pt, nEdgeIn)) + return false ; + } m_mTree.at( nRoot).m_vInters.back().nIn = nEdgeIn ; PNTVECTOR vInters ; vInters.emplace_back( pt) ; while ( pl.GetNextPoint( pt)) vInters.emplace_back( pt) ; pl.GetLastPoint( pt) ; - int nEdgeOut ; OnWhichEdge( nRoot, pt, nEdgeOut) ; + int nEdgeOut ; + // se non trovo l'ultimo punto esattamente su un lato, estendo l'ultimo tratto della polyline in avnti finchè trovo un'intersezione con un lato + // questa intersezione diventa il nuovo ultimo punto del vettore intersezione + if ( ! OnWhichEdge(nRoot, pt, nEdgeOut) ) { + Point3d ptSecondToLast ; pl.GetNextPoint( ptSecondToLast) ; + PtrOwner pCL( CreateCurveLine()) ; pCL->SetPVL( ptSecondToLast, pt - ptSecondToLast, 1e6) ; + PtrOwner pCL0( CreateCurveLine()) ; pCL0->Set( m_mTree.at(-1).GetTopRight(), m_mTree.at(-1).GetTopLeft()) ; + PtrOwner pCL1( CreateCurveLine()) ; pCL1->Set( m_mTree.at(-1).GetTopLeft(), m_mTree.at(-1).GetBottomLeft()) ; + PtrOwner pCL2( CreateCurveLine()) ; pCL2->Set( m_mTree.at(-1).GetBottomLeft(), m_mTree.at(-1).GetBottomRight()) ; + PtrOwner pCL3( CreateCurveLine()) ; pCL3->Set( m_mTree.at(-1).GetBottomRight(), m_mTree.at(-1).GetTopRight()) ; + IntersCurveCurve icc0( *pCL, *pCL0) ; + IntersCurveCurve icc1( *pCL, *pCL1) ; + IntersCurveCurve icc2( *pCL, *pCL2) ; + IntersCurveCurve icc3( *pCL, *pCL3) ; + IntCrvCrvInfo iccInfo ; + if (icc0.GetCrossIntersCount() != 0) + icc0.GetIntCrvCrvInfo( 0, iccInfo) ; + else if (icc1.GetCrossIntersCount() != 0) + icc1.GetIntCrvCrvInfo( 0, iccInfo) ; + else if (icc2.GetCrossIntersCount() != 0) + icc2.GetIntCrvCrvInfo( 0, iccInfo) ; + else if (icc3.GetCrossIntersCount() != 0) + icc3.GetIntCrvCrvInfo( 0, iccInfo) ; + pt = iccInfo.IciA[0].ptI ; + vInters.pop_back() ; + vInters.emplace_back( pt) ; + if ( ! OnWhichEdge(nRoot, pt, nEdgeOut)) + return false ; + } + m_mTree.at( nRoot).m_vInters.back().vpt = vInters ; m_mTree.at( nRoot).m_vInters.back().nOut = nEdgeOut ; } // chiamo una funzione per renderli coerenti @@ -3650,6 +3744,8 @@ Tree::AddCutsToRoot( POLYLINEVECTOR& vCuts) bool Tree::AdjustCuts( void) { + if ( int( m_mTree.at( -1).m_vInters.size()) == 1) + return true ; // li riordino per ordine di quali taglio incontrerei percorrendo il bordo della cella a partire da ptTR sort( m_mTree.at( -1).m_vInters.begin(), m_mTree.at( -1).m_vInters.end(), [](Inters& a, Inters& b){ return Inters::FirstEncounter(a,b) ;}) ; // ora controllo che le intersezioni che trovo siano ingressi alternati ad uscite, sennò inverto l'intersezione @@ -3657,6 +3753,9 @@ Tree::AdjustCuts( void) for ( int i = 0 ; i < int( m_mTree.at( -1).m_vInters.size()); ++i) { if ( m_mTree.at( -1).m_vInters.at(i).bSortedbyStart == bPreviousWasStart) { reverse( m_mTree.at( -1).m_vInters.at(i).vpt.begin(), m_mTree.at( -1).m_vInters.at(i).vpt.end()) ; + int nEdgeOutNew = m_mTree.at( -1).m_vInters.at(i).nIn ; + m_mTree.at( -1).m_vInters.at(i).nIn = m_mTree.at( -1).m_vInters.at(i).nOut ; + m_mTree.at( -1).m_vInters.at(i).nOut = nEdgeOutNew ; bPreviousWasStart = m_mTree.at( -1).m_vInters.at(i).bSortedbyStart ; } else diff --git a/Tree.h b/Tree.h index 0ae3288..d3ee8be 100644 --- a/Tree.h +++ b/Tree.h @@ -86,32 +86,32 @@ struct Inters { // salvo il lato che viene prima confrontando ingresso e uscita if ( nPos2 < nPos1) { nPos1 = nPos2 ; - nFirstA = int( a.vpt.size()) ; + 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 else if ( nPos2 == nPos1 ) { if ( nPos1 == 0 ) - nFirstA = a.vpt[0].x > a.vpt.back().x ? 0 : int( a.vpt.size()) ; + nFirstA = a.vpt[0].x > a.vpt.back().x ? 0 : ( int( a.vpt.size()) - 1) ; else if ( nPos1 == 1 ) - nFirstA = a.vpt[0].y > a.vpt.back().y ? 0 : int( a.vpt.size()) ; + nFirstA = a.vpt[0].y > a.vpt.back().y ? 0 : ( int( a.vpt.size()) - 1) ; else if ( nPos1 == 2 ) - nFirstA = a.vpt[0].x < a.vpt.back().x ? 0 : int( a.vpt.size()) ; + nFirstA = a.vpt[0].x < a.vpt.back().x ? 0 : ( int( a.vpt.size()) - 1) ; else if ( nPos1 == 3 ) - nFirstA = a.vpt[0].y < a.vpt.back().y ? 0 : int( a.vpt.size()) ; + nFirstA = a.vpt[0].y < a.vpt.back().y ? 0 : ( int( a.vpt.size()) - 1) ; } if ( nPos4 < nPos3) { nPos3 = nPos4 ; - nFirstB = int( b.vpt.size()) ; + nFirstB = int( b.vpt.size()) - 1 ; } else if ( nPos4 == nPos3 ) { if ( nPos3 == 0 ) - nFirstB = b.vpt[0].x > b.vpt.back().x ? 0 : int( b.vpt.size()) ; + nFirstB = b.vpt[0].x > b.vpt.back().x ? 0 : ( int( b.vpt.size()) - 1) ; else if ( nPos3 == 1 ) - nFirstB = b.vpt[0].y > b.vpt.back().y ? 0 : int( b.vpt.size()) ; + nFirstB = b.vpt[0].y > b.vpt.back().y ? 0 : ( int( b.vpt.size()) - 1) ; else if ( nPos3 == 2 ) - nFirstB = b.vpt[0].x < b.vpt.back().x ? 0 : int( b.vpt.size()) ; + nFirstB = b.vpt[0].x < b.vpt.back().x ? 0 : ( int( b.vpt.size()) - 1) ; else if ( nPos3 == 3 ) - nFirstB = b.vpt[0].y < b.vpt.back().y ? 0 : int( b.vpt.size()) ; + nFirstB = b.vpt[0].y < b.vpt.back().y ? 0 : ( int( b.vpt.size()) - 1) ; } a.bSortedbyStart = nFirstA == 0 ; b.bSortedbyStart = nFirstB == 0 ; @@ -238,14 +238,17 @@ class Tree // 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) ; bool GetPolygons( POLYLINEMATRIX& vPolygons) ; - bool GetPolygonsBasic( POLYLINEVECTOR& vPolygons, INTVECTOR& vCells = {}) ; // restituisce il poligono corrispondente ad ogni cella foglia dell'albero + bool GetPolygonsBasic( POLYLINEVECTOR& vPolygons, INTVECTOR vCells = {}) ; // 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 bool GetLeaves ( std::vector& vLeaves) const ; // restituisce gli indici delle foglie nell'albero bool GetEdge3D ( POLYLINEVECTOR& vPLEdges) ; // restituisce gli edge 3D come curve composite 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 // 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 CreateCellContour( POLYLINEMATRIX& vPolygons) ; // crea il nuovo contorno esterno, tenendo conto dei tagli + bool IsClosedU( void) { return m_bClosedU ;} ; // funzione che riferisce se la superficie è chiusa lungo il parametro U + bool IsClosedV( void) { 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 private : bool Split( int nId, double dSplitValue) ; // funzione di split di una cella al parametro indicato nella direzione data da bVert @@ -291,6 +294,7 @@ class Tree bool m_bMulti ; // superficie multi-patch 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