diff --git a/CurveAux.cpp b/CurveAux.cpp index 2036ac9..7083333 100644 --- a/CurveAux.cpp +++ b/CurveAux.cpp @@ -411,14 +411,51 @@ CopyThickness( const ICurve* pSouCrv, ICurve* pDestCrv) return true ; } +//---------------------------------------------------------------------------- +ICurve* +CurveToBezierCurve( const ICurve* pCrv, bool bDeg3OrDeg2, bool bForceRat) +{ + PtrOwner pBezierForm ; + switch ( pCrv->GetType()) { + case CRV_LINE :{ + const ICurveLine* pCrvLine = static_cast( pCrv) ; + pBezierForm.Set( LineToBezierCurve( pCrvLine, bDeg3OrDeg2, bForceRat)) ; + break ; + } + case CRV_ARC : { + const ICurveArc* pCrvArc = static_cast( pCrv) ; + pBezierForm.Set( ArcToBezierCurve( pCrvArc, bDeg3OrDeg2)) ; + break ; + } + case CRV_COMPO : { + const ICurveComposite* pCrvCompo = static_cast( pCrv) ; + pBezierForm.Set( CompositeToBezierCurve( pCrvCompo, bDeg3OrDeg2, bForceRat)) ; + break ; + } + case CRV_BEZIER : { + const ICurveBezier* pCrvBezier = static_cast( pCrv) ; + pBezierForm.Set( BezierToBasicBezierCurve( pCrvBezier, bDeg3OrDeg2, bForceRat)) ; + break ; + } + default : + return nullptr ; + break ; + } + + return Release( pBezierForm) ; +} + //---------------------------------------------------------------------------- ICurveBezier* -LineToBezierCurve( const ICurveLine* pCrvLine) +LineToBezierCurve( const ICurveLine* pCrvLine, bool bDeg3OrDeg2, bool bForceRat) { PtrOwner pCrvBezier( CreateCurveBezier()) ; // rendo tutte le curve di grado 2 e razionali così posso convertire anche archi e avere tutte curve dello stesso grado e razionali - pCrvBezier->Init( 2, true) ; + int nDeg = bDeg3OrDeg2 ? 3 : 2 ; + pCrvBezier->Init( nDeg, true) ; pCrvBezier->FromLine( *pCrvLine) ; + if ( bForceRat) + pCrvBezier->MakeRational() ; return Release( pCrvBezier) ; } @@ -426,31 +463,35 @@ LineToBezierCurve( const ICurveLine* pCrvLine) ICurve* ArcToBezierCurve( const ICurve* pCrv, bool bDeg3OrDeg2) { + // una spirale non può essere forzata al grado 2 + // verifico sia un arco const CurveArc* pArc = GetBasicCurveArc( pCrv) ; if ( pArc == nullptr) return nullptr ; // se angolo al centro sotto il limite, basta una curva - if ( ( abs( pArc->GetAngCenter()) < BEZARC_ANG_CEN_MAX + EPS_ANG_SMALL && abs( pArc->GetDeltaN()) < EPS_ZERO && ! bDeg3OrDeg2) || - ( abs( pArc->GetAngCenter()) < BEZARC_ANG_CEN_MAX + EPS_ANG_SMALL && bDeg3OrDeg2)) { + if ( abs( pArc->GetAngCenter()) < BEZARC_ANG_CEN_MAX + EPS_ANG_SMALL) { // creo la curva di Bezier equivalente all'arco - PtrOwner pCrvBez( CreateBasicCurveBezier()) ; + PtrOwner pCrvBez( CreateBasicCurveBezier()) ; if ( IsNull( pCrvBez) || ! pCrvBez->FromArc( *pArc)) return nullptr ; + // se l'arco era piano ed è richiesta una curva di grado 3 allora aumento una volta il grado + if ( bDeg3OrDeg2 && abs( pArc->GetDeltaN()) < EPS_ZERO) + pCrvBez.Set( BezierIncreaseDegree( pCrvBez)) ; // restituisco la curva return Release( pCrvBez) ; } // altrimenti curva composita di Bezier else { // creo la curva composita - PtrOwner pCrvCompo( CreateBasicCurveComposite()) ; + PtrOwner pCrvCompo( CreateBasicCurveComposite()) ; if ( IsNull( pCrvCompo)) return nullptr ; // inserisco nella CC le curve di Bezier equivalenti alle parti dell'arco int nParts = (int) ceil( abs( pArc->GetAngCenter()) / ( BEZARC_ANG_CEN_MAX + EPS_ANG_SMALL)) ; - if ( ! bDeg3OrDeg2 && abs( pArc->GetDeltaN()) > EPS_ZERO) - nParts *= 2 ; + //if ( ! bDeg3OrDeg2 && abs( pArc->GetDeltaN()) > EPS_ZERO) + // nParts *= 2 ; nParts = max( nParts, 2) ; for ( int i = 0 ; i < nParts ; ++ i) { // copio l'arco originale @@ -458,9 +499,12 @@ ArcToBezierCurve( const ICurve* pCrv, bool bDeg3OrDeg2) // lo limito alla parte di interesse cArc.TrimStartEndAtParam( i / double( nParts), ( i + 1) / double( nParts)) ; // creo la curva di Bezier equivalente - PtrOwner pCrvBez( CreateBasicCurveBezier()) ; + PtrOwner pCrvBez( CreateBasicCurveBezier()) ; if ( IsNull( pCrvBez) || ! pCrvBez->FromArc( cArc)) return nullptr ; + // se l'arco era piano ed è richiesta una curva di grado 3 allora aumento una volta il grado + if ( bDeg3OrDeg2 && abs( pArc->GetDeltaN()) < EPS_ZERO) + pCrvBez.Set( BezierIncreaseDegree( pCrvBez)) ; // aggiungo la curva di Bezier a quella composita if ( ! pCrvCompo->AddCurve( Release( pCrvBez))) return nullptr ; @@ -475,7 +519,7 @@ ArcToBezierCurve( const ICurve* pCrv, bool bDeg3OrDeg2) //---------------------------------------------------------------------------- ICurve* -CompositeToBezierCurve( const ICurveComposite* pCC) +CompositeToBezierCurve( const ICurveComposite* pCC, bool bDeg3OrDeg2, bool bForceRat) { // converto tutte le curve in bezier razionali di grado 2 PtrOwner pCCBezier( CreateCurveComposite()) ; @@ -491,14 +535,14 @@ CompositeToBezierCurve( const ICurveComposite* pCC) } else if ( pCC->GetCurve(i)->GetType() == CRV_LINE) { const CurveLine* crLine = GetBasicCurveLine( pCC->GetCurve(i)) ; - ICurve* pCrvBezier = LineToBezierCurve( crLine) ; + ICurve* pCrvBezier = LineToBezierCurve( crLine, bDeg3OrDeg2, bForceRat) ; if ( pCrvBezier == nullptr) return nullptr ; pCrvNew.Set( pCrvBezier) ; } else if ( pCC->GetCurve(i)->GetType() == CRV_BEZIER ) { const CurveBezier* crvBezier = GetBasicCurveBezier( pCC->GetCurve(i)) ; - ICurve* pCrvBezier = BezierToBasicBezierCurve( crvBezier) ; + ICurve* pCrvBezier = BezierToBasicBezierCurve( crvBezier, bDeg3OrDeg2, bForceRat) ; if ( pCrvBezier == nullptr) return nullptr ; pCrvNew.Set( pCrvBezier) ; @@ -511,7 +555,7 @@ CompositeToBezierCurve( const ICurveComposite* pCC) //---------------------------------------------------------------------------- ICurve* -BezierToBasicBezierCurve( const ICurveBezier* pCrvBezier) +BezierToBasicBezierCurve( const ICurveBezier* pCrvBezier, bool bDeg3OrDeg2, bool bForceRat) { // resta da calcolare un errore sull'approssimazione oppure usare la tecnica di spezzare la curva originale in sottocurve e approssimarle con bezier cubiche // per ridurre molto l'errore @@ -521,34 +565,26 @@ BezierToBasicBezierCurve( const ICurveBezier* pCrvBezier) int nDeg = pCrvBezier->GetDegree() ; bool bRat = pCrvBezier->IsRational() ; // se la curva è già nella forma giusta la restituisco - if ( nDeg == 2 && bRat) + int nDegWanted = bDeg3OrDeg2 ? 3 : 2 ; + if ( nDeg == nDegWanted && ( ( ! bRat && ! bForceRat) || bRat)) return Release( pCrvNew) ; - // sennò la riduco di grado fino al 2 - PtrOwner pBasicBezier ( CreateCurveBezier()) ; - pBasicBezier->Init( 2, true) ; - double dW = 1 ; - if ( nDeg == 1) { - Point3d ptStart = pCrvBezier->GetControlPoint( 0) ; - Point3d ptEnd = pCrvBezier->GetControlPoint( 1) ; - pBasicBezier->SetControlPoint( 0, ptStart, dW) ; - pBasicBezier->SetControlPoint( 1, 0.5 * (ptStart + ptEnd), dW) ; - pBasicBezier->SetControlPoint( 2, ptEnd, dW) ; - return Release( pBasicBezier) ; + // sennò mi porto al grado giusto + if ( nDeg < nDegWanted) { + while ( nDeg < nDegWanted) + pCrvNew.Set( BezierIncreaseDegree( pCrvNew)) ; } - while ( nDeg > 2 ) { - pCrvNew.Set( BezierDecreaseDegree( pCrvNew, 1)) ; - if ( IsNull( pCrvNew) || ! pCrvNew->IsValid()) - return nullptr ; - -- nDeg ; - } - for ( int i = 0 ; i < 3 ; ++i) { - Point3d ptCopy = pCrvNew->GetControlPoint( i) ; - if ( bRat) - dW = pCrvNew->GetControlWeight( i) ; - pBasicBezier->SetControlPoint( i, ptCopy, dW) ; + else if ( nDeg > nDegWanted) { + while ( nDeg > nDegWanted) { + pCrvNew.Set( BezierDecreaseDegree( pCrvNew, 1)) ; + if ( IsNull( pCrvNew) || ! pCrvNew->IsValid()) + return nullptr ; + -- nDeg ; + } } + if ( bForceRat) + pCrvNew->MakeRational() ; - return Release( pBasicBezier) ; + return Release( pCrvNew) ; } ICurveBezier* @@ -576,15 +612,19 @@ BezierIncreaseDegree(const ICurveBezier* pCrvBezier) double dWcurr ; for ( double i = 1 ; i < nDeg ; ++i) { ptCtrlCurr = pCrvBezier->GetControlPoint( int( i)) ; - Point3d ptNew = ( i / nDeg) * ptCtrlPrev + ( 1 - i / ( nDeg)) * ptCtrlCurr ; + double dAlpha = i / nDeg ; if ( bRat) { dWcurr = pCrvBezier->GetControlWeight( int( i)) ; - double dWnew = ( i / nDeg) * dWprev + ( 1 - i / ( nDeg)) * dWcurr ; + double dWnew = dAlpha * dWprev + ( 1 - dAlpha) * dWcurr ; + Point3d ptNew = dAlpha * ptCtrlPrev * dWprev + ( 1 - dAlpha) * ptCtrlCurr * dWcurr; + ptNew /= dWnew ; pNewBezier->SetControlPoint( int( i), ptNew, dWnew) ; - dWprev = dWnew ; + dWprev = dWcurr ; } - else + else { + Point3d ptNew = dAlpha * ptCtrlPrev + ( 1 - dAlpha) * ptCtrlCurr ; pNewBezier->SetControlPoint( int( i), ptNew) ; + } ptCtrlPrev = ptCtrlCurr ; } // salvo l'ultimo punto @@ -628,30 +668,37 @@ BezierDecreaseDegree(const ICurveBezier* pCrvBezier, double dTol) double dAlpha = i / ( nDeg + 1) ; // old è riferito alla curva originale Point3d ptOld = pCrvBezier->GetControlPoint( int( i)) ; - ptCtrlCurr = ( ptOld + (- dAlpha * ptCtrlPrev)) / ( 1 - dAlpha) ; if ( bRat) { double dWold = pCrvBezier->GetControlWeight( int( i)) ; dWcurr = ( dWold + (- dAlpha * dWprev)) / ( 1 - dAlpha) ; + ptCtrlCurr = ( ptOld * dWold + (- dAlpha * ptCtrlPrev * dWprev)) / ( 1 - dAlpha) ; + ptCtrlCurr /= dWcurr ; pNewBezier->SetControlPoint( int( i), ptCtrlCurr, dWcurr) ; dWprev = dWcurr ; } - else + else { + ptCtrlCurr = ( ptOld + (- dAlpha * ptCtrlPrev)) / ( 1 - dAlpha) ; pNewBezier->SetControlPoint( int( i), ptCtrlCurr) ; + } ptCtrlPrev = ptCtrlCurr ; } // risolvo il punto di mezzo per il caso nDeg pari if ( ( nDeg + 1) % 2 == 0) { // pari double dAlpha = r / ( nDeg + 1.) ; Point3d ptOld = pCrvBezier->GetControlPoint( r) ; - ptCtrlCurr = ( ptOld + (- dAlpha * ptCtrlPrev)) / ( 1 - dAlpha) ; + if ( bRat) { double dWold = pCrvBezier->GetControlWeight( r) ; dWcurr = ( dWold + (- dAlpha * dWprev)) / ( 1 - dAlpha) ; + ptCtrlCurr = ( ptOld * dWold + (- dAlpha * ptCtrlPrev * dWprev)) / ( 1 - dAlpha) ; + ptCtrlCurr /= dWcurr ; pNewBezier->SetControlPoint( r, ptCtrlCurr, dWcurr) ; dWprev = dWcurr ; } - else + else { + ptCtrlCurr = ( ptOld + (- dAlpha * ptCtrlPrev)) / ( 1 - dAlpha) ; pNewBezier->SetControlPoint( r, ptCtrlCurr) ; + } } // salvo l'ultimo punto ptCtrlCurr = pCrvBezier->GetControlPoint( nDeg + 1) ; @@ -668,15 +715,18 @@ BezierDecreaseDegree(const ICurveBezier* pCrvBezier, double dTol) for ( double i = nDeg - 1 ; i > r ; --i) { double dAlpha = ( i + 1) / ( nDeg + 1) ; Point3d ptOld = pCrvBezier->GetControlPoint( int( i) + 1) ; - ptCtrlCurr = ( ptOld + ( - ( 1 - dAlpha) * ptCtrlPrev)) / dAlpha ; if ( bRat) { double dWold = pCrvBezier->GetControlWeight( int( i) + 1) ; dWcurr = ( dWold - ( ( 1 - dAlpha) * dWprev)) / dAlpha ; + ptCtrlCurr = ( ptOld * dWold + ( - ( 1 - dAlpha) * ptCtrlPrev * dWprev)) / dAlpha ; + ptCtrlCurr /= dWcurr ; pNewBezier->SetControlPoint( int( i), ptCtrlCurr, dWcurr) ; dWprev = dWcurr ; } - else + else { + ptCtrlCurr = ( ptOld + ( - ( 1 - dAlpha) * ptCtrlPrev)) / dAlpha ; pNewBezier->SetControlPoint( int( i), ptCtrlCurr) ; + } ptCtrlPrev = ptCtrlCurr ; } // risolvo il punto di mezzo per il caso nDeg dispari @@ -687,29 +737,37 @@ BezierDecreaseDegree(const ICurveBezier* pCrvBezier, double dTol) double dAlpha = r / ( nDeg + 1.) ; ptCtrlPrev = pNewBezier->GetControlPoint( r - 1) ; Point3d ptOld = pCrvBezier->GetControlPoint( r) ; - Point3d ptL = ( ptOld + ( - dAlpha * ptCtrlPrev)) / ( 1 - dAlpha) ; + Point3d ptL ; double dWL = 1 ; if ( bRat) { dWprev = pNewBezier->GetControlWeight( r - 1) ; double dWold =pCrvBezier->GetControlWeight( r) ; dWL = ( dWold - ( dAlpha * dWprev)) / ( 1 - dAlpha) ; + ptL = ( ptOld * dWold + ( - dAlpha * ptCtrlPrev * dWprev)) / ( 1 - dAlpha) ; } + else + ptL = ( ptOld + ( - dAlpha * ptCtrlPrev)) / ( 1 - dAlpha) ; // punto di destra dAlpha = ( r + 1.) / ( nDeg + 1.) ; ptCtrlPrev = pNewBezier->GetControlPoint( r + 1) ; ptOld = pCrvBezier->GetControlPoint( r + 1) ; double dWR = 1 ; + Point3d ptR ; if ( bRat) { dWprev = pNewBezier->GetControlWeight( r + 1) ; double dWold =pCrvBezier->GetControlWeight( r + 1) ; dWR = ( dWold - ( ( 1 - dAlpha) * dWprev)) / dAlpha ; + ptR = ( ptOld * dWold + ( - ( 1 - dAlpha) * ptCtrlPrev * dWprev)) / dAlpha ; } - Point3d ptR = ( ptOld + ( - ( 1 - dAlpha) * ptCtrlPrev)) / dAlpha ; + else + ptR = ( ptOld + ( - ( 1 - dAlpha) * ptCtrlPrev)) / dAlpha ; // calcolo il punto di mezzo e lo aggiungo Point3d ptNew = ( ptL + ptR) / 2 ; - double dWnew = ( dWL + dWR) / 2 ; - if ( bRat) + if ( bRat) { + double dWnew = ( dWL + dWR) / 2 ; + ptNew /= dWnew ; pNewBezier->SetControlPoint( r, ptNew, dWnew) ; + } else pNewBezier->SetControlPoint( r, ptNew) ; dErr = Dist( ptL, ptR) ; @@ -815,15 +873,16 @@ NurbsCurveCanonicalize( CNurbsData& cnData) if ( ! bRepeated || (bRepeated && AreSamePointApprox( cnData.vCP[0],cnData.vCP[cnData.nDeg]))){ // salvo il vettore dei nodi in caso mi accorga di avere tra le mani una curva unclamped DBLVECTOR vU = cnData.vU ; - // se il primo e l'ultimo punto non coincidono allora aggiungo il primo punto in fondo al vettore dei punti di controllo - if ( ! AreSamePointApprox( cnData.vCP[0], cnData.vCP.back()) ) { - cnData.vCP.push_back( cnData.vCP[0]) ; - if ( cnData.bRat) - cnData.vW.push_back( cnData.vW[0]) ; - } - // se effettivamente ho dei nodi in più da togliere allora li tolgo - if ( int( cnData.vU.size()) != int(cnData.vCP.size()) + cnData.nDeg - 1) { - // devo poi anche togliere i nodi di troppo // presuppongo che la convenzione sia che i nodi di troppo sono alla fine del vettore dei nodi + // se effettivamente ho dei nodi in più da togliere allora li tolgo ed eventualmente aggiungo punti di controllo + if ( int(cnData.vU.size()) > int(cnData.vCP.size()) + cnData.nDeg - 1 ) { + // se il primo e l'ultimo punto non coincidono allora aggiungo il primo punto in fondo al vettore dei punti di controllo + if ( ! AreSamePointApprox( cnData.vCP[0], cnData.vCP.back())) { + bFirstAddedAtEnd = true ; + cnData.vCP.push_back( cnData.vCP[0]) ; + if ( cnData.bRat) + cnData.vW.push_back( cnData.vW[0]) ; + } + // devo poi anche togliere i nodi di troppo // presuppongo che la convenzione sia che i nodi di troppo siano alla fine del vettore dei nodi cnData.vU = DBLVECTOR( cnData.vU.begin(), cnData.vU.end() - cnData.nDeg) ; // controllo eventualmente anche i nodi extra // se ne ho due in più ne tolgo uno in cima e uno in fondo @@ -922,9 +981,20 @@ NurbsCurveCanonicalize( CNurbsData& cnData) // trovo il nodo di cui aumentare la molteplicità e ne calcolo la molteplicità int b = nU - nDeg - 1 + 1 ; int i = b ; + //int c = b ; while ( b > 0 && abs( cnData.vU[b] - cnData.vU[b - 1]) < EPS_ZERO) -- b ; int mult = min( i - b + 1, nDeg) ; // mi aspetto che sia 1, ma comunque sarà < nDeg + + //while ( i > 0 && abs( cnData.vU[i] - cnData.vU[i - 1]) < EPS_ZERO) + // -- i ; + //int mult = min( b - i + 1, nDeg) ; // mi aspetto che sia 1, ma comunque sarà < nDeg + + //// devo controllare anche i nodi successivi! + //while ( c < nU - 1 && abs( cnData.vU[c + 1] - cnData.vU[c]) < EPS_ZERO) + // ++ c ; + //int mult = min( c - i + 1, nDeg) ; // mi aspetto che sia 1, ma comunque sarà < nDeg + // recupero i punti da modificare if ( ! cnData.bRat) { for ( int i = 0 ; i <= nDeg - mult ; ++ i) @@ -986,9 +1056,20 @@ NurbsCurveCanonicalize( CNurbsData& cnData) // aumento la molteplicità del punto u_p-1 b = nDeg - 1 ; i = b ; + //c = b ; while ( b > 0 && abs( cnData.vU[b] - cnData.vU[b - 1]) < EPS_ZERO) -- b ; mult = min( i - b + 1, nDeg) ; // mi aspetto che sia 1, ma comunque sarà < cnData.nDeg + + //while ( i > 0 && abs( cnData.vU[i] - cnData.vU[i - 1]) < EPS_ZERO) + // -- i ; + //mult = min( b - i + 1, nDeg) ; // mi aspetto che sia 1, ma comunque sarà < cnData.nDeg + + //// devo controllare anche i nodi successivi! + //while ( c < nU -1 && abs(cnData.vU[c + 1] - cnData.vU[c]) < EPS_ZERO ) + // ++ c ; + //mult = min( c - i + 1, nDeg) ; // mi aspetto che sia 1, ma comunque sarà < cnData.nDeg + // recupero i punti da modificare if ( ! cnData.bRat) { for ( int i = 0 ; i <= nDeg - mult ; ++ i) @@ -1161,6 +1242,7 @@ NurbsToBezierCurve( const CNurbsData& cnData) int a = cnData.nDeg - 1 ; int b = cnData.nDeg ; bool bPrevRejected = false ; + //algoritmo A5.6 di Piegl e Tiller // ciclo while ( b < nU - 1) { int i = b ; diff --git a/CurveBezier.cpp b/CurveBezier.cpp index c7b64be..1f11b55 100644 --- a/CurveBezier.cpp +++ b/CurveBezier.cpp @@ -141,6 +141,32 @@ CurveBezier::SetControlPoint( int nInd, const Point3d& ptCtrl, double dW) return true ; } +//---------------------------------------------------------------------------- +bool +CurveBezier::SetControlWeight( int nInd, double dW) +{ + // verifico validità, razionalità e indice + if ( m_nStatus != OK || ! m_bRat || nInd < 0 || nInd > m_nDeg) + return false ; + + // verifico che il peso non sia nullo o negativo + if ( dW < EPS_SMALL) + return false ; + + // assegno il valore e il peso + m_vWeCtrl[nInd] = dW ; + + // annullo analisi presenza singolarità + m_dParSing = - 2 ; + + // imposto ricalcolo Voronoi + ResetVoronoiObject() ; + // imposto ricalcolo della grafica + m_OGrMgr.Reset() ; + + return true ; +} + //---------------------------------------------------------------------------- bool CurveBezier::FromArc( const ICurveArc& crArc) @@ -2208,3 +2234,17 @@ CurveBezier::ResetVoronoiObject() const delete m_pVoronoiObj ; m_pVoronoiObj = nullptr ; } + +//---------------------------------------------------------------------------- +bool +CurveBezier::MakeRational( void) +{ + if ( m_bRat) + return true ; + // creo il vettore dei pesi e li setto tutti a 1 + m_vWeCtrl.assign( m_nDeg + 1, 1) ; + // aggiorno il flag rational + m_bRat = true ; + + return true ; +} diff --git a/CurveBezier.h b/CurveBezier.h index b402f6c..dfc33fc 100644 --- a/CurveBezier.h +++ b/CurveBezier.h @@ -137,6 +137,7 @@ class CurveBezier : public ICurveBezier, public IGeoObjRW bool Init( int nDeg, bool bIsRational) override ; bool SetControlPoint( int nInd, const Point3d& ptCtrl) override ; bool SetControlPoint( int nInd, const Point3d& ptCtrl, double dW) override ; + bool SetControlWeight( int nInd, double dW) override ; bool FromArc( const ICurveArc& crArc) override ; bool FromLine( const ICurveLine& crLine) override ; int GetDegree( void) const override @@ -148,6 +149,7 @@ class CurveBezier : public ICurveBezier, public IGeoObjRW double GetControlWeight( int nInd, bool* pbOk = NULL) const override ; bool GetControlPolygonLength( double& dLen) const override ; int GetSingularParam( double& dPar) const override ; + bool MakeRational( void) override ; public : // IGeoObjRW int GetNgeId( void) const override ; diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc index 06e49bd..11258ea 100644 Binary files a/EgtGeomKernel.rc and b/EgtGeomKernel.rc differ diff --git a/EgtGeomKernel.vcxproj b/EgtGeomKernel.vcxproj index a1768f8..2a61ee7 100644 --- a/EgtGeomKernel.vcxproj +++ b/EgtGeomKernel.vcxproj @@ -320,9 +320,11 @@ copy $(TargetPath) \EgtProg\Dll64 + + diff --git a/EgtGeomKernel.vcxproj.filters b/EgtGeomKernel.vcxproj.filters index d88555b..7b4369b 100644 --- a/EgtGeomKernel.vcxproj.filters +++ b/EgtGeomKernel.vcxproj.filters @@ -540,6 +540,12 @@ File di origine\GeoCollisionAvoid + + File di origine\GeoProject + + + File di origine\GeoCreate + diff --git a/ProjectCurveSurfBez.cpp b/ProjectCurveSurfBez.cpp new file mode 100644 index 0000000..5d2263c --- /dev/null +++ b/ProjectCurveSurfBez.cpp @@ -0,0 +1,55 @@ +//---------------------------------------------------------------------------- +// EgalTech 2024-2024 +//---------------------------------------------------------------------------- +// File : ProjectCurveSurfBez.cpp Data : 07.05.24 Versione : 2.6e3 +// Contenuto : Implementazione funzioni proiezione curve su superficie Bezier. +// +// +// +// Modifiche : 07.05.24 DB Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "/EgtDev/Include/EGkProjectCurveSurfTm.h" +#include "/EgtDev/Include/EGkSurfBezier.h" + +using namespace std ; + +//---------------------------------------------------------------------------- +bool +ProjectCurveOnSurfBez( const ICurve& crCrv, const ISurfBezier& surfBez, const Vector3d& vtDir, double dLinTol, double dMaxSegmLen, + PNT5AXVECTOR& vPt5ax) +{ + const ISurfTriMesh* pAuxSurf = surfBez.GetAuxSurf() ; + return ProjectCurveOnSurfTm( crCrv, *pAuxSurf, vtDir, dLinTol, dMaxSegmLen, vPt5ax) ; +} + +//---------------------------------------------------------------------------- +bool +ProjectCurveOnSurfBez( const ICurve& crCrv, const ISurfBezier& surfBez, const IGeoPoint3d& gpRef, + double dLinTol, double dMaxSegmLen, PNT5AXVECTOR& vPt5ax) +{ + const ISurfTriMesh* pAuxSurf = surfBez.GetAuxSurf() ; + return ProjectCurveOnSurfTm( crCrv, *pAuxSurf, gpRef, dLinTol, dMaxSegmLen, vPt5ax) ; +} + +//---------------------------------------------------------------------------- +bool +ProjectCurveOnSurfBez( const ICurve& crCrv, const ISurfBezier& surfBez, const ICurve& crRef, + double dLinTol, double dMaxSegmLen, PNT5AXVECTOR& vPt5ax) +{ + const ISurfTriMesh* pAuxSurf = surfBez.GetAuxSurf() ; + return ProjectCurveOnSurfTm( crCrv, *pAuxSurf, crRef, dLinTol, dMaxSegmLen, vPt5ax) ; +} + +//---------------------------------------------------------------------------- +bool +ProjectCurveOnSurfBez( const ICurve& crCrv, const ISurfBezier& surfBez, const ISurfTriMesh& tmRef, + double dLinTol, double dMaxSegmLen, PNT5AXVECTOR& vPt5ax) +{ + const ISurfTriMesh* pAuxSurf = surfBez.GetAuxSurf() ; + return ProjectCurveOnSurfTm( crCrv, *pAuxSurf, tmRef, dLinTol, dMaxSegmLen, vPt5ax) ; +} diff --git a/SbzFromCurves.cpp b/SbzFromCurves.cpp new file mode 100644 index 0000000..2185f08 --- /dev/null +++ b/SbzFromCurves.cpp @@ -0,0 +1,1155 @@ +//---------------------------------------------------------------------------- +// EgalTech 20024 +//---------------------------------------------------------------------------- +// File : SbzFromCurves.cpp Data : 07.05.24 Versione : 2.6e2 +// Contenuto : Implementazione di funzioni per creazione di superfici Sbz +// a partire da curve, con diversi metodi. +// +// +// Modifiche : 07.05.24 DB Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "GeoConst.h" +#include "CurveLine.h" +#include "CurveArc.h" +#include "CurveComposite.h" +#include "SurfTriMesh.h" +#include "SurfBezier.h" +#include "Voronoi.h" +#include "/EgtDev/Include/EGkSfrCreate.h" +#include "/EgtDev/Include/EGkOffsetCurve.h" +#include "/EgtDev/Include/EGkStmFromCurves.h" +#include "/EgtDev/Include/EGkStmFromTriangleSoup.h" +#include "/EgtDev/Include/EGkRotationMinimizingFrame.h" +#include "/EgtDev/Include/EGkRotationXplaneFrame.h" +#include "/EgtDev/Include/EGkIntersCurves.h" +#include "/EgtDev/Include/EGkSurfBezier.h" +#include "/EgtDev/Include/EGkSbzFromCurves.h" +#include "/EgtDev/Include/EgtPointerOwner.h" +#include + +using namespace std ; + +//------------------------------------------------------------------------------- +ISurfBezier* +GetSurfBezierByFlatContour( const ICurve* pCurve, double dLinTol) +{ + // verifica parametri + if ( pCurve == nullptr) + return nullptr ; + // calcolo la polilinea che approssima la curva + PolyLine PL ; + if ( ! pCurve->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL)) + return nullptr ; + // creo e setto la superficie trimesh + PtrOwner pSbz( CreateBasicSurfBezier()) ; + if ( IsNull( pSbz) || ! pSbz->CreateByFlatContour( PL)) + return nullptr ; + //// salvo tolleranza lineare usata + //pSTM->SetLinearTolerance( dLinTol) ; + // restituisco la superficie + return Release( pSbz) ; +} + +//------------------------------------------------------------------------------- +ISurfBezier* +GetSurfBezierByRegion( const CICURVEPVECTOR& vpCurve, double dLinTol) +{ + // verifica parametri + if ( &vpCurve == nullptr || vpCurve.empty()) + return nullptr ; + // calcolo le polilinee che approssimano le curve della regione + POLYLINEVECTOR vPL ; + Vector3d vtN ; + if ( ! CalcRegionPolyLines( vpCurve, dLinTol, vPL, vtN)) + return nullptr ; + //for ( int i = 0 ; i < int(vpCurve.size()) ; ++i ) { + // PolyLine pl ; + // vpCurve[i]->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, pl) ; + // vPL.push_back( pl) ; + //} + // creo e setto la superficie di bezier + PtrOwner pSbz( CreateBasicSurfBezier()) ; + if ( IsNull( pSbz) || ! pSbz->CreateByRegion( vPL)) + return nullptr ; + //// salvo tolleranza lineare usata + //pSbz->SetLinearTolerance( dLinTol) ; + // restituisco la superficie + return Release( pSbz) ; +} + +//------------------------------------------------------------------------------- +ISurfBezier* +GetSurfBezierByExtrusion( const ICurve* pCurve, const Vector3d& vtExtr, + bool bCapEnds, double dLinTol) +{ + // verifica parametri + if ( pCurve == nullptr || &vtExtr == nullptr) + return nullptr ; + // calcolo la polilinea che approssima la curva + PolyLine PL ; + if ( ! pCurve->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL)) + return nullptr ; + // se richiesta chiusura agli estremi + bool bDoCapEnds = false ; + if ( bCapEnds) { + // verifico che la curva sia chiusa e piatta + Plane3d plPlane ; + double dArea ; + if ( PL.IsClosedAndFlat( plPlane, dArea, 50 * EPS_SMALL)) { + // componente dell'estrusione perpendicolare al piano della curva + double dOrthoExtr = plPlane.GetVersN() * vtExtr ; + if ( ( abs( dOrthoExtr) > EPS_SMALL)) { + bDoCapEnds = true ; + // se negativa, inverto il senso del contorno + if ( dOrthoExtr < 0) + PL.Invert() ; + } + } + } + + //PtrOwner pBezierForm( CurveToBezierCurve( pCurve)) ; + PtrOwner pBezierForm( pCurve->Clone()) ; + // creo e setto la superficie trimesh + PtrOwner pSbz( CreateBasicSurfBezier()) ; + if ( IsNull( pSbz) || ! pSbz->CreateByExtrusion( pBezierForm, vtExtr)) + return nullptr ; + + //// se da fare, metto i tappi sulle estremità + //if ( bDoCapEnds) { + // // creo la prima superficie di estremità + // SurfTriMesh STM1 ; + // if ( ! STM1.CreateByFlatContour( PL)) + // return nullptr ; + // // la copio + // SurfTriMesh STM2 = STM1 ; + // // inverto la prima superficie + // STM1.Invert() ; + // // traslo la seconda + // STM2.Translate( vtExtr) ; + + // ////// SurfCompo? + // //// le unisco alla superficie del fianco + // //if ( ! pSbz->DoSewing( STM1) || ! pSTM->DoSewing( STM2)) + // // return nullptr ; + //} + //// salvo tolleranza lineare usata + //pSbz->SetLinearTolerance( dLinTol) ; + // restituisco la superficie + return Release( pSbz) ; +} + +////------------------------------------------------------------------------------- +//ISurfCompo* +//GetSurfBezierByRegionExtrusion( const CICURVEPVECTOR& vpCurve, const Vector3d& vtExtr, double dLinTol) ///// RICHIEDE LE SURF COMPO///////////////// +//{ +// // verifica parametri +// if ( &vpCurve == nullptr || vpCurve.empty() || &vtExtr == nullptr) +// return nullptr ; +// // se una sola curva, uso la funzione precedente +// if ( vpCurve.size() == 1 ) +// return GetSurfBezierByExtrusion( vpCurve[0], vtExtr, true, dLinTol) ; +// // calcolo le polilinee che approssimano le curve della regione +// POLYLINEVECTOR vPL ; +// Vector3d vtN ; +// if ( ! CalcRegionPolyLines( vpCurve, dLinTol, vPL, vtN)) +// return nullptr ; +// // verifico la direzione di estrusione +// double dOrthoExtr = vtN * vtExtr ; +// if ( ( abs( dOrthoExtr) < EPS_SMALL)) +// return nullptr ; +// // se componente estrusione negativa, inverto tutti i percorsi +// if ( dOrthoExtr < 0) { +// for ( int i = 0 ; i < int( vPL.size()) ; ++ i) +// vPL[i].Invert() ; +// } +// // creo la prima superficie di estremità +// PtrOwner pSbz1( CreateBasicSurfBezier()) ; +// if ( IsNull( pSbz1) || ! pSbz1->CreateByRegion( vPL)) +// return nullptr ; +// // creo la seconda superficie come copia della prima e poi inverto la prima +// PtrOwner pSbz2( pSbz1->Clone()) ; +// pSbz1->Invert() ; +// +// // creo e unisco le diverse superfici di estrusione +// for ( int i = 0 ; i < int( vPL.size()) ; ++ i) { +// // estrusione +// SurfBezier SbzLat ; +// if ( ! SbzLat.CreateByExtrusion( vPL[i], vtExtr)) // qui mi serve la curva e non la polyline della curva. vuol dire che dalla CalcRegionPolyLines devo farmi restituire anche le curve ordinate +// return nullptr ; +// } +// //// salvo tolleranza lineare usata +// //pSTM->SetLinearTolerance( dLinTol) ; +// // restituisco la superficie +// return Release( pSrfCompo) ; // in realtà dovrei restituire tre superfici!!! due basi e una sup laterale( e quindi fare una SurfCompo) oppure dovrei spezzare le basi in tot pezzi e creare una superficie unica +//} + +//------------------------------------------------------------------------------- +ISurfBezier* +GetSurfBezierByRevolve( const ICurve* pCurve, const Point3d& ptAx, const Vector3d& vtAx, + bool bCapEnds, double dLinTol) // con l'aggiunta delle SURFCOMPO posso gestire anche i cap e curve che attraversano l'asse +{ + // verifica parametri + if ( pCurve == nullptr || &ptAx == nullptr || &vtAx == nullptr) + return nullptr ; + // limite minimo su tolleranza + dLinTol = max( dLinTol, EPS_SMALL) ; + //// calcolo la polilinea che approssima la curva + //PolyLine PL ; + //if ( ! pCurve->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL)) + // return nullptr ; + //// calcolo lo step di rotazione + //double dMaxRad = 0 ; + //if ( ! PL.GetMaxDistanceFromLine( ptAx, vtAx, 1, dMaxRad, false) || dMaxRad < EPS_SMALL) + // return nullptr ; + //double dStepRotDeg = sqrt( 8 * dLinTol / dMaxRad) * RADTODEG ; + + + //// se richiesta chiusura degli estremi + //if ( bCapEnds && ! PL.IsClosed()) { // serve la SURFCOMPO + // Vector3d vtAxN = vtAx ; + // vtAxN.Normalize() ; + // double dPosIni = 0, dPosFin = 0 ; + // Point3d ptP ; + // // proietto l'ultimo punto sull'asse di rotazione + // if ( PL.GetLastPoint( ptP)) { + // dPosFin = ( ptP - ptAx) * vtAxN ; + // Point3d ptPOnAx = ptAx + dPosFin * vtAxN ; + // // se non giace sull'asse, aggiungo il punto proiettato + // if ( ! AreSamePointApprox( ptP, ptPOnAx)) { + // double dU ; + // PL.GetLastU( dU) ; + // PL.AddUPoint( ( dU + 1), ptPOnAx) ; + // } + // } + // // inverto la polilinea + // PL.Invert() ; + // // proietto l'ultimo punto (era il primo) sull'asse di rotazione + // if ( PL.GetLastPoint( ptP)) { + // dPosIni = ( ptP - ptAx) * vtAxN ; + // Point3d ptPOnAx = ptAx + dPosIni * vtAxN ; + // // se non giace sull'asse, aggiungo il punto proiettato + // if ( ! AreSamePointApprox( ptP, ptPOnAx)) { + // double dU ; + // PL.GetLastU( dU) ; + // PL.AddUPoint( ( dU + 1), ptPOnAx) ; + // } + // } + // // decido se reinvertire la polilinea + // if ( dPosFin > dPosIni) + // PL.Invert() ; + //} + + // creo e setto la superficie trimesh + PtrOwner pSbz( CreateBasicSurfBezier()) ; + if ( IsNull( pSbz) || ! pSbz->CreateByScrewing( pCurve, ptAx, vtAx, ANG_FULL, 0)) + return nullptr ; + // se superficie risultante chiusa, verifico che la normale sia verso l'esterno + double dVol ; + if ( pSbz->GetVolume( dVol) && dVol < 0) + pSbz->Invert() ; + //// salvo tolleranza lineare usata + //pSbz->SetLinearTolerance( dLinTol) ; + // restituisco la superficie + return Release( pSbz) ; +} + +//------------------------------------------------------------------------------- +ISurfBezier* +GetSurfBezierByScrewing( const ICurve* pCurve, const Point3d& ptAx, const Vector3d& vtAx, + double dAngRotDeg, double dMove, bool bCapEnds, double dLinTol) +{ + // verifica parametri + if ( pCurve == nullptr || &ptAx == nullptr || &vtAx == nullptr) + return nullptr ; + // limite minimo su tolleranza + dLinTol = max( dLinTol, EPS_SMALL) ; + // calcolo la polilinea che approssima la curva + PolyLine PL ; + if ( ! pCurve->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL)) + return nullptr ; + + //// calcolo lo step di rotazione + //double dMaxRad = 0 ; + //if ( ! PL.GetMaxDistanceFromLine( ptAx, vtAx, 1, dMaxRad, false) || dMaxRad < EPS_SMALL) + // return nullptr ; + //double dStepRotDeg = sqrt( 8 * dLinTol / dMaxRad) * RADTODEG ; + //// se superficie rototraslata, necessari limiti sulla lunghezza dei segmenti + //if ( abs( dAngRotDeg) > EPS_ANG_SMALL && abs( dMove) > EPS_SMALL){ + // double dLenMax = 2.5 * abs( dMove * dStepRotDeg / dAngRotDeg) ; + // if ( ! PL.AdjustForMaxSegmentLen( dLenMax)) + // return nullptr ; + //} + // creo e setto la superficie bezier + PtrOwner pSbz( CreateBasicSurfBezier()) ; + if ( IsNull( pSbz) || ! pSbz->CreateByScrewing( pCurve, ptAx, vtAx, dAngRotDeg, dMove)) + return nullptr ; + //// se richiesti caps /// richiede la SurfCompo + //if ( bCapEnds) { + // // determino se la sezione è chiusa e piatta + // Plane3d plPlane ; double dArea ; + // bool bSectClosedFlat = PL.IsClosedAndFlat( plPlane, dArea, 10 * EPS_SMALL) ; + // // determino non sia una semplice rivoluzione + // bool bRevolved = ( abs( abs( dAngRotDeg) - ANG_FULL) < EPS_ANG_SMALL && abs( dMove) < EPS_SMALL) ; + // // se sezione chiusa e piatta e non rivoluzione, posso aggiungere i tappi + // if ( bSectClosedFlat && ! bRevolved) { + // // aggiungo il cap sull'inizio + // PtrOwner pSci( CreateBasicSurfTriMesh()) ; + // if ( IsNull( pSci) || ! pSci->CreateByFlatContour( PL)) + // return nullptr ; + // pSTM->DoSewing( *pSci) ; + // // aggiungo il cap sulla fine + // Vector3d vtMove = vtAx ; + // vtMove.Normalize() ; + // vtMove *= dMove ; + // PL.Translate( vtMove) ; + // PL.Rotate( ptAx, vtAx, dAngRotDeg) ; + // PtrOwner pSce( CreateBasicSurfTriMesh()) ; + // if ( IsNull( pSce) || ! pSce->CreateByFlatContour( PL)) + // return nullptr ; + // pSce->Invert() ; + // pSTM->DoSewing( *pSce) ; + // } + //} + // se superficie risultante chiusa, verifico che la normale sia verso l'esterno + double dVol ; + if ( pSbz->GetVolume( dVol) && dVol < 0) + pSbz->Invert() ; + //// salvo tolleranza lineare usata + //pSTM->SetLinearTolerance( dLinTol) ; + // restituisco la superficie + return Release( pSbz) ; +} +// +////------------------------------------------------------------------------------- +//static ISurfBezier* +//GetSurfBezierSharpRectSwept( double dDimH, double dDimV, const ICurve* pGuide, int nCapType, double dLinTol) // DA SISTEMARE - ancora copia della versione stm, cambia solo il nome della funzione////////////////////// +//{ +// // verifico che la linea guida sia piana +// Plane3d plGuide ; +// if ( ! pGuide->IsFlat( plGuide, false, 10 * EPS_SMALL)) +// return nullptr ; +// Vector3d vtNorm = plGuide.GetVersN() ; +// // determino se la guida è chiusa +// bool bGuideClosed = pGuide->IsClosed() ; +// // curve di offset +// OffsetCurve OffsCrvR ; +// if ( ! OffsCrvR.Make( pGuide, dDimH / 2, ICurve::OFF_FILLET) || OffsCrvR.GetCurveCount() == 0) +// return nullptr ; +// PtrOwner pCrvR( OffsCrvR.GetLongerCurve()) ; +// if ( IsNull( pCrvR)) +// return nullptr ; +// OffsetCurve OffsCrvL ; +// if ( ! OffsCrvL.Make( pGuide, -dDimH / 2, ICurve::OFF_FILLET) || OffsCrvL.GetCurveCount() == 0) +// return nullptr ; +// PtrOwner pCrvL( OffsCrvL.GetLongerCurve()) ; +// if ( IsNull( pCrvL)) +// return nullptr ; +// // costruisco le parti di superficie +// PtrOwner pSrfTop( GetSurfTriMeshRuled( pCrvR, pCrvL, ISurfTriMesh::RLT_MINDIST, dLinTol)) ; +// if ( IsNull( pSrfTop)) +// return nullptr ; +// PtrOwner pSrfBot( pSrfTop->Clone()) ; +// if ( IsNull( pSrfBot)) +// return nullptr ; +// pSrfBot->Translate( -dDimV * vtNorm) ; +// pSrfBot->Invert() ; +// PtrOwner pSrfRgt( GetSurfTriMeshByExtrusion( pCrvR, -dDimV * vtNorm, false, dLinTol)) ; +// if ( IsNull( pSrfRgt)) +// return nullptr ; +// pSrfRgt->Invert() ; +// PtrOwner pSrfLft( GetSurfTriMeshByExtrusion( pCrvL, -dDimV * vtNorm, false, dLinTol)) ; +// if ( IsNull( pSrfLft)) +// return nullptr ; +// // unisco le parti +// PtrOwner pSTM( Release( pSrfTop)) ; +// pSTM->DoSewing( *pSrfRgt) ; +// pSTM->DoSewing( *pSrfLft) ; +// pSTM->DoSewing( *pSrfBot) ; +// // salvo tolleranza lineare usata e imposto angolo per smooth +// pSTM->SetLinearTolerance( dLinTol) ; +// pSTM->SetSmoothAngle( 20) ; +// // se guida aperta e tappi piatti +// if ( ! bGuideClosed && nCapType == RSCAP_FLAT) { +// // verifico che le due estremità siano chiuse e piatte +// POLYLINEVECTOR vPL ; +// if ( ! pSTM->GetLoops( vPL) || vPL.size() != 2) +// return nullptr ; +// Plane3d plEnds ; double dArea ; +// if ( ! vPL[0].IsClosedAndFlat( plEnds, dArea, 100 * EPS_SMALL)) +// return nullptr ; +// if ( ! vPL[1].IsClosedAndFlat( plEnds, dArea, 100 * EPS_SMALL)) +// return nullptr ; +// // aggiungo il cap sull'inizio +// PtrOwner pSci( CreateBasicSurfTriMesh()) ; +// if ( IsNull( pSci) || ! pSci->CreateByFlatContour( vPL[0])) +// return nullptr ; +// pSci->Invert() ; +// pSTM->DoSewing( *pSci) ; +// // aggiungo il cap sulla fine +// PtrOwner pSce( CreateBasicSurfTriMesh()) ; +// if ( IsNull( pSce) || ! pSce->CreateByFlatContour( vPL[1])) +// return nullptr ; +// pSce->Invert() ; +// pSTM->DoSewing( *pSce) ; +// } +// // se altrimenti guida aperta e tappi arrotondati +// if ( ! bGuideClosed && ( nCapType == RSCAP_ROUND || nCapType == RSCAP_BEVEL)) { +// // step di rotazione per rispettare la tolleranza +// double dStepRotDeg = ( nCapType == RSCAP_BEVEL ? ANG_STRAIGHT / 4 : sqrt( 8 * dLinTol / dDimH) * RADTODEG) ; +// // aggiungo il cap sull'inizio +// Point3d ptStart ; +// pGuide->GetStartPoint( ptStart) ; +// Vector3d vtStart ; +// pGuide->GetStartDir( vtStart) ; +// vtStart.Rotate( vtNorm, 0, 1) ; +// PolyLine PLStart ; +// PLStart.AddUPoint( 0, ptStart) ; +// PLStart.AddUPoint( 1, ptStart + dDimH / 2 * vtStart) ; +// PLStart.AddUPoint( 2, ptStart + dDimH / 2 * vtStart - dDimV * vtNorm) ; +// PLStart.AddUPoint( 3, ptStart - dDimV * vtNorm) ; +// PtrOwner pSci( CreateBasicSurfTriMesh()) ; +// if ( IsNull( pSci) || ! pSci->CreateByScrewing( PLStart, ptStart, vtNorm, ANG_STRAIGHT, dStepRotDeg, 0)) +// return nullptr ; +// pSci->Invert() ; +// pSTM->DoSewing( *pSci) ; +// // aggiungo il cap sulla fine +// Point3d ptEnd ; +// pGuide->GetEndPoint( ptEnd) ; +// Vector3d vtEnd ; +// pGuide->GetEndDir( vtEnd) ; +// vtEnd.Rotate( vtNorm, 0, -1) ; +// PolyLine PLEnd ; +// PLEnd.AddUPoint( 0, ptEnd) ; +// PLEnd.AddUPoint( 1, ptEnd + dDimH / 2 * vtEnd) ; +// PLEnd.AddUPoint( 2, ptEnd + dDimH / 2 * vtEnd - dDimV * vtNorm) ; +// PLEnd.AddUPoint( 3, ptEnd - dDimV * vtNorm) ; +// PtrOwner pSce( CreateBasicSurfTriMesh()) ; +// if ( IsNull( pSce) || ! pSce->CreateByScrewing( PLEnd, ptEnd, vtNorm, ANG_STRAIGHT, dStepRotDeg, 0)) +// return nullptr ; +// pSce->Invert() ; +// pSTM->DoSewing( *pSce) ; +// } +// // restituisco la superficie +// return Release( pSTM) ; +//} +// +////------------------------------------------------------------------------------- +//static ISurfBezier* +//GetSurfBezierBeveledRectSwept( double dDimH, double dDimV, double dBevelH, double dBevelV, const ICurve* pGuide, int nCapType, double dLinTol) // DA SISTEMARE - ancora copia della versione stm, cambia solo il nome della funzione////////////////////// +//{ +// // metodo di calcolo impostato da USE_VORONOI +// +// // verifico che la linea guida sia piana +// Plane3d plGuide ; +// if ( ! pGuide->IsFlat( plGuide, false, 10 * EPS_SMALL)) +// return nullptr ; +// // assegno la normale del piano +// Vector3d vtNorm = plGuide.GetVersN() ; +// // determino il punto centrale della sezione +// Point3d ptCen ; +// pGuide->GetStartPoint( ptCen) ; +// ptCen -= dDimV / 2 * vtNorm ; +// // determino se la guida è chiusa +// bool bGuideClosed = pGuide->IsClosed() ; +// // curve di offset +// const int NUM_OFFS = 4 ; +// OffsetCurve vOffsCrv[NUM_OFFS] ; +// double vDist[NUM_OFFS] = { dDimH / 2 - dBevelH, -dDimH / 2 + dBevelH, dDimH / 2, -dDimH / 2} ; +// bool bOk = true ; +// if ( ! USE_VORONOI) { +// future vRes[NUM_OFFS] ; +// for ( int i = 0 ; i < NUM_OFFS ; ++ i) +// vRes[i] = async( launch::async, &OffsetCurve::Make, &vOffsCrv[i], pGuide, vDist[i], ICurve::OFF_FILLET) ; +// bool bOk = true ; +// int nFin = 0 ; +// while ( nFin < NUM_OFFS) { +// for ( int i = 0 ; i < NUM_OFFS ; ++ i) { +// if ( vRes[i].valid() && vRes[i].wait_for( chrono::nanoseconds{ 1}) == future_status::ready) { +// bOk = vRes[i].get() && bOk ; +// ++ nFin ; +// } +// } +// } +// } +// else { +// // se Voronoi non è possibile calcolare gli offset di una stessa curva in parallelo +// for ( int i = 0 ; i < NUM_OFFS && bOk ; ++ i) +// bOk = vOffsCrv[i].Make( pGuide, vDist[i], ICurve::OFF_FILLET) ; +// } +// +// if ( ! bOk || +// vOffsCrv[0].GetCurveCount() == 0 || vOffsCrv[1].GetCurveCount() == 0 || +// vOffsCrv[2].GetCurveCount() == 0 || vOffsCrv[3].GetCurveCount() == 0) +// return nullptr ; +// PtrOwner pCrvR( vOffsCrv[0].GetLongerCurve()) ; +// if ( IsNull( pCrvR)) +// return nullptr ; +// PtrOwner pCrvL( vOffsCrv[1].GetLongerCurve()) ; +// if ( IsNull( pCrvL)) +// return nullptr ; +// PtrOwner pCrvRb( vOffsCrv[2].GetLongerCurve()) ; +// if ( IsNull( pCrvRb)) +// return nullptr ; +// pCrvRb->Translate( - dBevelV * vtNorm) ; +// PtrOwner pCrvLb( vOffsCrv[3].GetLongerCurve()) ; +// if ( IsNull( pCrvLb)) +// return nullptr ; +// pCrvLb->Translate( - dBevelV * vtNorm) ; +// // costruisco le parti di superficie +// PtrOwner pSrfTop( GetSurfTriMeshRuled( pCrvR, pCrvL, ISurfTriMesh::RLT_MINDIST, dLinTol)) ; +// if ( IsNull( pSrfTop)) +// return nullptr ; +// PtrOwner pSrfBot( pSrfTop->Clone()) ; +// if ( IsNull( pSrfBot)) +// return nullptr ; +// pSrfBot->Translate( -dDimV * vtNorm) ; +// pSrfBot->Invert() ; +// PtrOwner pSrfTopR( GetSurfTriMeshRuled( pCrvRb, pCrvR, ISurfTriMesh::RLT_MINDIST, dLinTol)) ; +// if ( IsNull( pSrfTopR)) +// return nullptr ; +// PtrOwner pSrfBotR( pSrfTopR->Clone()) ; +// if ( IsNull( pSrfBotR)) +// return nullptr ; +// pSrfBotR->Mirror( ptCen, vtNorm) ; +// PtrOwner pSrfTopL( GetSurfTriMeshRuled( pCrvL, pCrvLb, ISurfTriMesh::RLT_MINDIST, dLinTol)) ; +// if ( IsNull( pSrfTopL)) +// return nullptr ; +// PtrOwner pSrfBotL( pSrfTopL->Clone()) ; +// if ( IsNull( pSrfBotL)) +// return nullptr ; +// pSrfBotL->Mirror( ptCen, vtNorm) ; +// PtrOwner pSrfRgt( GetSurfTriMeshByExtrusion( pCrvRb, ( -dDimV + 2 * dBevelV) * vtNorm, false, dLinTol)) ; +// if ( IsNull( pSrfRgt)) +// return nullptr ; +// pSrfRgt->Invert() ; +// PtrOwner pSrfLft( GetSurfTriMeshByExtrusion( pCrvLb, ( -dDimV + 2 * dBevelV) * vtNorm, false, dLinTol)) ; +// if ( IsNull( pSrfLft)) +// return nullptr ; +// // unisco le parti +// int nBuckets = max( 4 * ( pSrfRgt->GetVertexSize() + pSrfLft->GetVertexSize()), 1000) ; +// StmFromTriangleSoup stmSoup ; +// if ( ! stmSoup.Start( nBuckets)) +// return nullptr ; +// stmSoup.AddSurfTriMesh( *pSrfTop) ; +// stmSoup.AddSurfTriMesh( *pSrfTopR) ; +// stmSoup.AddSurfTriMesh( *pSrfTopL) ; +// stmSoup.AddSurfTriMesh( *pSrfRgt) ; +// stmSoup.AddSurfTriMesh( *pSrfLft) ; +// stmSoup.AddSurfTriMesh( *pSrfBotR) ; +// stmSoup.AddSurfTriMesh( *pSrfBotL) ; +// stmSoup.AddSurfTriMesh( *pSrfBot) ; +// PtrOwner pSTM ; +// // se guida aperta e tappi piatti +// if ( ! bGuideClosed && nCapType == RSCAP_FLAT) { +// // completo unione e recupero la superficie risultante +// if ( ! stmSoup.End()) +// return nullptr ; +// pSTM.Set( stmSoup.GetSurf()) ; +// // preparo seconda zuppa di triangoli per inserire i tappi +// StmFromTriangleSoup stmCapSoup ; +// if ( ! stmCapSoup.Start( nBuckets)) +// return nullptr ; +// // verifico che le due estremità siano chiuse e piatte +// POLYLINEVECTOR vPL ; +// if ( ! pSTM->GetLoops( vPL) || vPL.size() != 2) +// return nullptr ; +// Plane3d plEnds ; double dArea ; +// if ( ! vPL[0].IsClosedAndFlat( plEnds, dArea, 50 * EPS_SMALL)) +// return nullptr ; +// if ( ! vPL[1].IsClosedAndFlat( plEnds, dArea, 50 * EPS_SMALL)) +// return nullptr ; +// // calcolo il cap sull'inizio +// PtrOwner pSci( CreateBasicSurfTriMesh()) ; +// if ( IsNull( pSci) || ! pSci->CreateByFlatContour( vPL[0])) +// return nullptr ; +// pSci->Invert() ; +// // calcolo il cap sulla fine +// PtrOwner pSce( CreateBasicSurfTriMesh()) ; +// if ( IsNull( pSce) || ! pSce->CreateByFlatContour( vPL[1])) +// return nullptr ; +// pSce->Invert() ; +// // cucio i tappi all'estrusione +// if ( ! pSTM->DoSewing( *pSci) || ! pSTM->DoSewing( *pSce)) +// return nullptr ; +// } +// // se altrimenti guida aperta e tappi arrotondati +// else if ( ! bGuideClosed && ( nCapType == RSCAP_ROUND || nCapType == RSCAP_BEVEL)) { +// // step di rotazione per rispettare il tipo o la tolleranza +// double dStepRotDeg = ( nCapType == RSCAP_BEVEL ? ANG_STRAIGHT / 4 : sqrt( 8 * dLinTol / dDimH) * RADTODEG) ; +// // aggiungo il cap sull'inizio +// Point3d ptStart ; +// pGuide->GetStartPoint( ptStart) ; +// Vector3d vtStart ; +// pGuide->GetStartDir( vtStart) ; +// vtStart.Rotate( vtNorm, 0, 1) ; +// PolyLine PLStart ; +// PLStart.AddUPoint( 0, ptStart) ; +// PLStart.AddUPoint( 1, ptStart + ( dDimH / 2 - dBevelH) * vtStart) ; +// PLStart.AddUPoint( 2, ptStart + dDimH / 2 * vtStart - dBevelV * vtNorm) ; +// PLStart.AddUPoint( 3, ptStart + dDimH / 2 * vtStart - ( dDimV - dBevelV) * vtNorm) ; +// PLStart.AddUPoint( 4, ptStart + ( dDimH / 2 - dBevelH) * vtStart - dDimV * vtNorm) ; +// PLStart.AddUPoint( 5, ptStart - dDimV * vtNorm) ; +// PtrOwner pSci( CreateBasicSurfTriMesh()) ; +// if ( IsNull( pSci) || ! pSci->CreateByScrewing( PLStart, ptStart, vtNorm, ANG_STRAIGHT, dStepRotDeg, 0)) +// return nullptr ; +// pSci->Invert() ; +// stmSoup.AddSurfTriMesh( *pSci) ; +// // aggiungo il cap sulla fine +// Point3d ptEnd ; +// pGuide->GetEndPoint( ptEnd) ; +// Vector3d vtEnd ; +// pGuide->GetEndDir( vtEnd) ; +// vtEnd.Rotate( vtNorm, 0, -1) ; +// PolyLine PLEnd ; +// PLEnd.AddUPoint( 0, ptEnd) ; +// PLEnd.AddUPoint( 1, ptEnd + ( dDimH / 2 - dBevelH) * vtEnd) ; +// PLEnd.AddUPoint( 2, ptEnd + dDimH / 2 * vtEnd - dBevelV * vtNorm) ; +// PLEnd.AddUPoint( 3, ptEnd + dDimH / 2 * vtEnd - ( dDimV - dBevelV) * vtNorm) ; +// PLEnd.AddUPoint( 4, ptEnd + ( dDimH / 2 - dBevelH) * vtEnd - dDimV * vtNorm) ; +// PLEnd.AddUPoint( 5, ptEnd - dDimV * vtNorm) ; +// PtrOwner pSce( CreateBasicSurfTriMesh()) ; +// if ( IsNull( pSce) || ! pSce->CreateByScrewing( PLEnd, ptEnd, vtNorm, ANG_STRAIGHT, dStepRotDeg, 0)) +// return nullptr ; +// pSce->Invert() ; +// stmSoup.AddSurfTriMesh( *pSce) ; +// // completo unione e recupero la superficie risultante +// if ( ! stmSoup.End()) +// return nullptr ; +// pSTM.Set( stmSoup.GetSurf()) ; +// } +// else { +// // completo unione e recupero la superficie risultante +// if ( ! stmSoup.End()) +// return nullptr ; +// pSTM.Set( stmSoup.GetSurf()) ; +// } +// // salvo tolleranza lineare usata e imposto angolo per smooth +// pSTM->SetLinearTolerance( dLinTol) ; +// pSTM->SetSmoothAngle( 20) ; +// // restituisco la superficie +// return Release( pSTM) ; +//} +// +////------------------------------------------------------------------------------- +//ISurfBezier* +//GetSurfBezierRectSwept( double dDimH, double dDimV, double dBevelH, double dBevelV, const ICurve* pGuide, int nCapType, double dLinTol) // DA SISTEMARE - ancora copia della versione stm, cambia solo il nome della funzione////////////////////// +//{ +// // verifica parametri +// if ( pGuide == nullptr || dBevelH > 0.4 * dDimH || dBevelV > 0.4 * dDimV) +// return nullptr ; +// // determino se sezione squadrata o con smusso +// bool bSharp = ( dBevelH < 100 * EPS_SMALL || dBevelV < 100 * EPS_SMALL) ; +// // eseguo +// if ( bSharp) +// return GetSurfBezierSharpRectSwept( dDimH, dDimV, pGuide, nCapType, dLinTol) ; +// else +// return GetSurfBezierBeveledRectSwept( dDimH, dDimV, dBevelH, dBevelV, pGuide, nCapType, dLinTol) ; +//} +// +////------------------------------------------------------------------------------- +//static ISurfBezier* +//GetSurfBezierSweptInPlane( const ICurve* pSect, const ICurve* pGuide, const Vector3d& vtNorm, bool bCapEnds, double dLinTol) // DA SISTEMARE - ancora copia della versione stm, cambia solo il nome della funzione////////////////////// +//{ +// // determino se la sezione è chiusa +// bool bSectClosed = pSect->IsClosed() ; +// // determino se la guida è chiusa +// bool bGuideClosed = pGuide->IsClosed() ; +// +// // riferimento all'inizio della linea guida +// Frame3d frStart ; +// Point3d ptStart ; +// pGuide->GetStartPoint( ptStart) ; +// Vector3d vtStart ; +// pGuide->GetStartDir( vtStart) ; +// frStart.Set( ptStart, -vtStart, vtStart ^ vtNorm) ; +// +// // calcolo la polilinea che approssima la sezione +// PolyLine PL ; +// if ( ! pSect->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL)) +// return nullptr ; +// +// // porto la sezione in questo riferimento e ve la appiattisco +// if ( ! PL.ToLoc( frStart) || ! PL.Flatten()) +// return nullptr ; +// +// // preparo collettore delle superfici componenti +// StmFromTriangleSoup StmFts ; +// if ( ! StmFts.Start()) +// return nullptr ; +// +// // superficie swept +// PtrOwner pPrevCrv ; +// Point3d ptP ; +// bool bPoint = PL.GetFirstPoint( ptP) ; +// while ( bPoint) { +// // nuova curva ( definita dall'Offset ) +// OffsetCurve OffsCrv ; +// if ( ! OffsCrv.Make( pGuide, ptP.x, ICurve::OFF_FILLET) || OffsCrv.GetCurveCount() == 0) +// return nullptr ; +// PtrOwner pCurrCrv( OffsCrv.GetLongerCurve()) ; +// if ( IsNull( pCurrCrv)) +// return nullptr ; +// pCurrCrv->Translate( ptP.y * frStart.VersY()) ; +// // se esiste la curva precedente, costruisco la rigata ( di tipo minima distanza) +// if ( ! IsNull( pPrevCrv)) { +// PtrOwner pSr( GetSurfTriMeshRuled( pPrevCrv, pCurrCrv, ISurfTriMesh::RLT_MINDIST, dLinTol)) ; +// if ( IsNull( pSr)) +// return nullptr ; +// // inserisco nel collettore +// StmFts.AddSurfTriMesh( *pSr) ; +// } +// // salvo la curva come prossima precedente +// pPrevCrv.Set( pCurrCrv) ; +// // prossimo punto +// bPoint = PL.GetNextPoint( ptP) ; +// } +// +// // recupero la supeficie risultante +// if ( ! StmFts.End()) +// return nullptr ; +// PtrOwner pSTM( GetBasicSurfTriMesh( StmFts.GetSurf())) ; +// if ( IsNull( pSTM)) +// return nullptr ; +// // salvo tolleranza lineare usata +// pSTM->SetLinearTolerance( dLinTol) ; +// +// // se richiesti caps e sezione chiusa e guida aperta +// if ( bCapEnds && bSectClosed && ! bGuideClosed) { +// // verifico che le due estremità siano chiuse e piatte +// POLYLINEVECTOR vPL ; +// if ( ! pSTM->GetLoops( vPL) || vPL.size() != 2) +// return nullptr ; +// Plane3d plEnds ; double dArea ; +// if ( ! vPL[0].IsClosedAndFlat( plEnds, dArea, 100 * EPS_SMALL)) +// return nullptr ; +// if ( ! vPL[1].IsClosedAndFlat( plEnds, dArea, 100 * EPS_SMALL)) +// return nullptr ; +// // aggiungo il cap sull'inizio +// PtrOwner pSci( CreateBasicSurfTriMesh()) ; +// if ( IsNull( pSci) || ! pSci->CreateByFlatContour( PL)) +// return nullptr ; +// pSci->ToGlob( frStart) ; +// // unisco +// pSTM->DoSewing( *pSci) ; +// // riferimento alla fine della linea guida +// Frame3d frEnd ; +// Point3d ptEnd ; +// pGuide->GetEndPoint( ptEnd) ; +// Vector3d vtEnd ; +// pGuide->GetEndDir( vtEnd) ; +// frEnd.Set( ptEnd, -vtEnd, vtEnd ^ vtNorm) ; +// // aggiungo il cap sulla fine +// PtrOwner pSce( CreateBasicSurfTriMesh()) ; +// if ( IsNull( pSce) || ! pSce->CreateByFlatContour( PL)) +// return nullptr ; +// pSce->Invert() ; +// pSce->ToGlob( frEnd) ; +// // unisco +// pSTM->DoSewing( *pSce) ; +// } +// // se superficie risultante chiusa, verifico che la normale sia verso l'esterno +// double dVol ; +// if ( pSTM->GetVolume( dVol) && dVol < 0) +// pSTM->Invert() ; +// // restituisco la superficie +// return Release( pSTM) ; +//} +// +////------------------------------------------------------------------------------- +//static ISurfBezier* +//GetSurfBezierSwept3d( const ICurve* pSect, const ICurve* pGuide, const Vector3d& vtAx, bool bCapEnds, double dLinTol) // DA SISTEMARE - ancora copia della versione stm, cambia solo il nome della funzione////////////////////// +//{ +// // determino se la sezione è chiusa +// bool bSectClosed = pSect->IsClosed() ; +// // determino se la guida è chiusa +// bool bGuideClosed = pGuide->IsClosed() ; +// // determino algoritmo da usare per calcolare i riferimenti lungo la curva +// bool bRMF = vtAx.IsSmall() ; +// +// // riferimento all'inizio della linea guida +// Point3d ptStart ; +// pGuide->GetStartPoint( ptStart) ; +// Vector3d vtStart ; +// pGuide->GetStartDir( vtStart) ; +// Frame3d frStart ; +// if ( bRMF) { +// if ( ! frStart.Set( ptStart, vtStart)) +// return nullptr ; +// } +// else { +// Vector3d vtAxX = vtAx ^ vtStart ; +// if ( vtAxX.IsSmall()) { +// vtAxX = FromUprightOrtho( vtAx) ; +// vtAxX.Rotate( vtAx, 0, 1) ; +// } +// if ( ! frStart.Set( ptStart, vtStart, vtAxX)) +// return nullptr ; +// } +// +// // calcolo la polilinea che approssima la sezione +// PolyLine PL ; +// if ( ! pSect->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL)) +// return nullptr ; +// +// // recupero la sezione dalla PolyLine approssimata come Curva +// PtrOwner pSecLocApprox( CreateBasicCurveComposite()) ; +// if ( IsNull( pSecLocApprox) || +// ! pSecLocApprox->FromPolyLine( PL) || +// ! pSecLocApprox->IsValid()) +// return nullptr ; +// +// // porto la PolyLine e la curva della sezione nel riferimento nel punto iniziale della guida +// PL.ToLoc( frStart) ; +// pSecLocApprox->ToLoc( frStart) ; +// +// // calcolo il vettore di Frames campionati lungo la guida mediante la tolleranza definita +// FRAME3DVECTOR vFrames ; +// if ( bRMF) { +// RotationMinimizingFrame RMF ; +// if ( ! RMF.Set( pGuide, frStart) || +// ! RMF.GetFramesByTolerance( dLinTol, vFrames) || vFrames.empty()) +// return nullptr ; +// } +// else { +// RotationXplaneFrame RXF ; +// if ( ! RXF.Set( pGuide, vtAx, frStart.VersX()) || +// ! RXF.GetFramesByTolerance( dLinTol, vFrames) || vFrames.empty()) +// return nullptr ; +// } +// +// // preparo collettore delle superfici componenti +// StmFromTriangleSoup StmFts ; +// if ( ! StmFts.Start()) +// return nullptr ; +// +// // per ogni Frame calcolato, la sezione va roto-traslata lungo la guida +// for ( int i = 0 ; i < int( vFrames.size()) - 1 ; ++ i) { +// +// // definisco la sezione allo step corrente +// PtrOwner pSecCurr( pSecLocApprox->Clone()) ; +// if ( IsNull( pSecCurr) || ! pSecCurr->IsValid()) +// return nullptr ; +// +// // considero la sezione ( in locale ) come vista dal globale +// if ( ! pSecCurr->ToGlob( vFrames[i])) +// return nullptr ; +// +// // definisco la sezione allo step successivo +// PtrOwner pSecSucc( pSecLocApprox->Clone()) ; +// if ( IsNull( pSecSucc) || ! pSecSucc->IsValid()) +// return nullptr ; +// +// // considero la sezione ( in locale ) come vista dal globale +// if ( ! pSecSucc->ToGlob( vFrames[i+1])) +// return nullptr ; +// +// // creo la rigata tra queste due sezioni +// PtrOwner pSr( GetSurfTriMeshRuled( pSecCurr, pSecSucc, ISurfTriMesh::RLT_ISOPAR_SMOOTH, dLinTol)) ; +// if ( IsNull( pSr) || ! pSr->IsValid()) +// return nullptr ; +// // la inverto +// pSr->Invert() ; +// // inserisco la superficie nel collettore +// StmFts.AddSurfTriMesh( *pSr) ; +// } +// +// // se richiesti caps e sezione chiusa e guida aperta +// if ( bCapEnds && bSectClosed && ! bGuideClosed) { +// +// // aggiungo il cap sull'inizio ( portandolo nel frame del punto iniziale della guida ) +// PtrOwner pSci( CreateBasicSurfTriMesh()) ; +// if ( IsNull( pSci) || ! pSci->CreateByFlatContour( PL)) +// return nullptr ; +// pSci->ToGlob( vFrames.front()) ; +// // aggiungo +// StmFts.AddSurfTriMesh( *pSci) ; +// +// // aggiungo il cap sulla fine ( portandolo nel frame del punto finale della guida ) +// PtrOwner pSce( CreateBasicSurfTriMesh()) ; +// if ( IsNull( pSce) || ! pSce->CreateByFlatContour( PL)) +// return nullptr ; +// pSce->ToGlob( vFrames.back()) ; +// // inverto +// pSce->Invert() ; +// // aggiungo +// StmFts.AddSurfTriMesh( *pSce) ; +// } +// +// // recupero la supeficie risultante +// if ( ! StmFts.End()) +// return nullptr ; +// PtrOwner pSTM( GetBasicSurfTriMesh( StmFts.GetSurf())) ; +// if ( IsNull( pSTM)) +// return nullptr ; +// // salvo tolleranza lineare usata +// pSTM->SetLinearTolerance( dLinTol) ; +// +// // se superficie risultante chiusa, verifico che la normale sia verso l'esterno +// double dVol ; +// if ( pSTM->GetVolume( dVol) && dVol < 0) +// pSTM->Invert() ; +// +// // restituisco la superficie +// return Release( pSTM) ; +//} +// +////------------------------------------------------------------------------------- +//ISurfBezier* +//GetSurfTriMeshSwept( const ICurve* pSect, const ICurve* pGuide, const Vector3d& vtAx, +// bool bCapEnds, double dLinTol) // DA SISTEMARE - ancora copia della versione stm, cambia solo il nome della funzione////////////////////// +//{ +// // verifica parametri +// if ( pSect == nullptr || pGuide == nullptr) +// return nullptr ; +// +// bool bIsLine = false ; +// if ( pGuide->GetType() == CRV_LINE) +// bIsLine = true ; +// else { +// const CurveComposite* pCompo = GetBasicCurveComposite( pGuide) ; +// Point3d ptStart, ptEnd ; +// if ( pCompo != nullptr && pCompo->IsALine( 10 * EPS_SMALL, ptStart, ptEnd)) +// bIsLine = true ; +// } +// // se la guida è piana +// Plane3d plGuide ; +// if ( pGuide->IsFlat( plGuide, bIsLine, 10 * EPS_SMALL)) +// return GetSurfBezierSweptInPlane( pSect, pGuide, plGuide.GetVersN(), bCapEnds, dLinTol) ; +// +// // altrimenti swept 3d +// return GetSurfBezierSwept3d( pSect, pGuide, vtAx, bCapEnds, dLinTol) ; +//} +// +////------------------------------------------------------------------------------- +//ISurfBezier* +//GetSurfBezierSwept( const ISurfFlatRegion* pSfrSect, const ICurve* pGuide, const Vector3d& vtAx, +// bool bCapEnds, double dLinTol) // DA SISTEMARE - ancora copia della versione stm, cambia solo il nome della funzione////////////////////// +//{ +// // verifica dei parametri +// if ( pSfrSect == nullptr || pGuide == nullptr) +// return nullptr ; +// +// // predispongo collettore superfici componenti +// StmFromTriangleSoup StmSoup ; +// StmSoup.Start() ; +// +// // per ogni loop della superficie, creo una Swept +// for ( int nC = 0 ; nC < pSfrSect->GetChunkCount() ; ++ nC) { +// for ( int nL = 0 ; nL < pSfrSect->GetLoopCount( nC) ; ++ nL) { +// // recupero il loop +// PtrOwner pCrvLoop( pSfrSect->GetLoop( nC, nL)) ; +// if ( IsNull( pCrvLoop) || ! pCrvLoop->IsValid()) +// return nullptr ; +// // creo la Trimesh Swept +// PtrOwner pStmLoopSwept( GetSurfTriMeshSwept( pCrvLoop, pGuide, vtAx, false, dLinTol)) ; +// if ( IsNull( pStmLoopSwept) || ! pStmLoopSwept->IsValid()) +// return nullptr ; +// // aggiungo la Swept ricavata al risultato finale ( come triangoli ) +// StmSoup.AddSurfTriMesh( *pStmLoopSwept) ; +// } +// } +// +// // Recupero la superficie +// if ( ! StmSoup.End()) +// return nullptr ; +// PtrOwner pStmSwept( StmSoup.GetSurf()) ; +// if ( IsNull( pStmSwept)) +// return nullptr ; +// +// // se rischiesta chiusura... +// // Controllo solo che la guida non sia chiusa, la sezione derivando da una Flatregion è sempre chiusa +// if ( bCapEnds && ! pGuide->IsClosed()) { +// // recupero i loop all'inizio (dalla regione e apportunamente approssimati) +// POLYLINEVECTOR vPLi ; +// for ( int nC = 0 ; nC < pSfrSect->GetChunkCount() ; ++ nC) { +// for ( int nL = 0 ; nL < pSfrSect->GetLoopCount( nC) ; ++ nL) { +// vPLi.emplace_back() ; +// if ( ! pSfrSect->ApproxLoopWithLines( nC, nL, dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, vPLi.back())) +// return nullptr ; +// } +// } +// // creo il cap sull'inizio e lo attacco alla swept ( è già in posizione giusta) +// PtrOwner pSci( CreateSurfTriMesh()) ; +// if ( ! pSci->CreateByRegion( vPLi)) +// return nullptr ; +// pStmSwept->DoSewing( *pSci) ; +// // recupero i loops alla fine +// POLYLINEVECTOR vPLe ; +// if ( ! pStmSwept->GetLoops( vPLe)) +// return nullptr ; +// // creo la superficie alla fine e la attacco +// PtrOwner pSce( CreateSurfTriMesh()) ; +// if ( ! pSce->CreateByRegion( vPLe)) +// return nullptr ; +// // attacco la superficie finale alla swept +// pSce->Invert() ; +// pStmSwept->DoSewing( *pSce) ; +// } +// // se superficie risultante chiusa, verifico che la normale sia verso l'esterno +// double dVol ; +// if ( pStmSwept->GetVolume( dVol) && dVol < 0) +// pStmSwept->Invert() ; +// +// return Release( pStmSwept) ; +//} +// +////------------------------------------------------------------------------------- +//ISurfBezier* +//GetSurfBezierTransSwept( const ICurve* pSect, const ICurve* pGuide, bool bCapEnds, double dLinTol) // DA SISTEMARE - ancora copia della versione stm, cambia solo il nome della funzione////////////////////// +//{ +// // verifica parametri +// if ( pSect == nullptr || pGuide == nullptr) +// return nullptr ; +// // determino se la sezione è chiusa +// bool bSectClosed = pSect->IsClosed() ; +// // punto iniziale della sezione e vettore a inizio guida +// Point3d ptStart ; +// if ( ! pSect->GetStartPoint( ptStart)) +// return nullptr ; +// Point3d ptGuide ; +// if ( ! pGuide->GetStartPoint( ptGuide)) +// return nullptr ; +// Vector3d vtDelta = ptStart - ptGuide ; +// // calcolo la polilinea che approssima la guida +// PolyLine PLG ; +// if ( ! pGuide->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PLG)) +// return nullptr ; +// // determino se la guida è chiusa +// bool bGuideClosed = PLG.IsClosed() ; +// // calcolo la superficie +// PtrOwner pSTM( CreateBasicSurfTriMesh()) ; +// if ( IsNull( pSTM)) +// return nullptr ; +// // salvo tolleranza lineare usata +// pSTM->SetLinearTolerance( dLinTol) ; +// // superficie swept +// PtrOwner pPrevCrv ; +// Point3d ptP ; +// bool bPoint = PLG.GetFirstPoint( ptP) ; +// while ( bPoint) { +// // nuova curva +// PtrOwner pCurrCrv( pSect->Clone()) ; +// if ( IsNull( pCurrCrv)) +// return nullptr ; +// pCurrCrv->Translate( ptP - ptStart + vtDelta) ; +// // se esiste la curva precedente, costruisco la rigata (di tipo minima distanza) +// if ( ! IsNull( pPrevCrv)) { +// PtrOwner pSr( GetSurfTriMeshRuled( pPrevCrv, pCurrCrv, ISurfTriMesh::RLT_ISOPAR, dLinTol)) ; +// if ( IsNull( pSr)) +// return nullptr ; +// pSTM->DoSewing( *pSr) ; +// } +// // salvo la curva come prossima precedente +// pPrevCrv.Set( pCurrCrv) ; +// // prossimo punto +// bPoint = PLG.GetNextPoint( ptP) ; +// } +// // se richiesti caps e sezione chiusa e guida aperta +// if ( bCapEnds && bSectClosed && ! bGuideClosed) { +// // calcolo la polilinea che approssima la sezione +// PolyLine PLS ; +// if ( ! pSect->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PLS)) +// return nullptr ; +// // verifico che la sezione sia chiusa e piatta +// Plane3d plSect ; double dArea ; +// if ( PLS.IsClosedAndFlat( plSect, dArea, 100 * EPS_SMALL)) { +// // aggiungo il cap sull'inizio +// PtrOwner pSci( CreateBasicSurfTriMesh()) ; +// if ( IsNull( pSci) || ! pSci->CreateByFlatContour( PLS)) +// return nullptr ; +// pSci->Invert() ; +// Point3d ptGi ; PLG.GetFirstPoint( ptGi) ; +// pSci->Translate( ptGi - ptStart + vtDelta) ; +// pSTM->DoSewing( *pSci) ; +// // aggiungo il cap sulla fine +// PtrOwner pSce( CreateBasicSurfTriMesh()) ; +// if ( IsNull( pSce) || ! pSce->CreateByFlatContour( PLS)) +// return nullptr ; +// Point3d ptGe ; PLG.GetLastPoint( ptGe) ; +// pSce->Translate( ptGe - ptStart + vtDelta) ; +// pSTM->DoSewing( *pSce) ; +// } +// } +// // se superficie risultante chiusa, verifico che la normale sia verso l'esterno +// double dVol ; +// if ( pSTM->GetVolume( dVol) && dVol < 0) +// pSTM->Invert() ; +// // restituisco la superficie +// return Release( pSTM) ; +//} + +//------------------------------------------------------------------------------- +ISurfBezier* +GetSurfBezierRuled( const Point3d& ptP, const ICurve* pCurve, double dLinTol) +{ + // verifica parametri + if ( &ptP == nullptr || pCurve == nullptr) + return nullptr ; + //// calcolo la polilinea che approssima la curva + //PolyLine PL ; + //if ( ! pCurve->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL)) + // return nullptr ; + // creo e setto la superficie trimesh + PtrOwner pSbz( CreateBasicSurfBezier()) ; + if ( IsNull( pSbz) || ! pSbz->CreateByPointCurve( ptP, pCurve)) + return nullptr ; + //// salvo tolleranza lineare usata + //pSbz->SetLinearTolerance( dLinTol) ; + // restituisco la superficie + return Release( pSbz) ; +} + +//------------------------------------------------------------------------------- +ISurfBezier* +GetSurfBezierRuled( const ICurve* pCurve1, const ICurve* pCurve2, int nType, double dLinTol) +{ + // verifica parametri + if ( pCurve1 == nullptr || pCurve2 == nullptr) + return nullptr ; + + // qui anziché fare le polyline converto le curve in bezier! + // SE NON HO LO STESSO NUMERO DI CURVE COME LO GESTISCO?? + + //// calcolo la polilinea che approssima la prima curva + //PolyLine PL1 ; + //if ( ! pCurve1->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL1)) + // return nullptr ; + //// calcolo la polilinea che approssima la seconda curva + //PolyLine PL2 ; + //if ( ! pCurve2->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL2)) + // return nullptr ; + + + // dLinTol servirà quando ci sarà la funzione ApproxWithCurveBezier + // se la curva è già una bezier singola la tengo, sennò la converto // e la compo di bezier??? + PtrOwner pCC1( CreateCurveComposite()) ; + if ( pCurve1->GetType() != CRV_BEZIER) + pCC1->AddCurve( CurveToBezierCurve( pCurve1)) ; + else + pCC1->AddCurve( pCurve1->Clone()) ; + if ( IsNull( pCC1) || ! pCC1->IsValid()) + return nullptr ; + + // se la curva è già una bezier singola la tengo, sennò la converto + PtrOwner pCC2( CreateCurveComposite()) ; + if ( pCurve2->GetType() != CRV_BEZIER) + pCC2->AddCurve( CurveToBezierCurve( pCurve2)) ; + else + pCC2->AddCurve( pCurve2->Clone()) ; + if ( IsNull( pCC2) || ! pCC2->IsValid()) + return nullptr ; + + // creo e setto la superficie trimesh + PtrOwner pSbz( CreateBasicSurfBezier()) ; + if ( IsNull( pSbz) || ! pSbz->CreateByTwoCurves( pCC1, pCC2, nType)) + return nullptr ; + //// salvo tolleranza lineare usata + //pSbz->SetLinearTolerance( dLinTol) ; + // restituisco la superficie + return Release( pSbz) ; +} \ No newline at end of file diff --git a/SbzStandard.cpp b/SbzStandard.cpp index 5dd2cbe..ea4f4b1 100644 --- a/SbzStandard.cpp +++ b/SbzStandard.cpp @@ -17,12 +17,13 @@ #include "SurfTriMesh.h" #include "SurfBezier.h" #include "/EgtDev/Include/EGkSbzStandard.h" +#include "/EgtDev/Include/EGkSbzFromCurves.h" using namespace std ; //------------------------------------------------------------------------------- ISurfBezier* -CreateBezierSphere( const Point3d& ptCenter, double dR) +GetSurfBezierSphere( const Point3d& ptCenter, double dR) { // creo una superficie di Bezier di grado 2 con 45 punti di controllo PtrOwner pSrfBez( CreateSurfBezier()) ; @@ -78,3 +79,35 @@ CreateBezierSphere( const Point3d& ptCenter, double dR) return Release( pSrfBez) ; } + +////------------------------------------------------------------------------------- +//ISurfBezier* +//GetSurfBezierCone( const Point3d& ptCenter, double dRadius, const Vector3d& dHeight) +//{ +// // le dimensioni devono essere significative +// if ( dRadius < EPS_SMALL || abs( dHeight) < EPS_SMALL) +// return nullptr ; +// // creo la circonferenza di base +// CurveArc cArc ; +// cArc.Set( ORIG, Z_AX, dRadius) ; +// if ( dHeight < 0) +// cArc.Invert() ; +// // punto di vertice +// Point3d ptTip( 0, 0, dHeight) ; +// // creo la superficie laterale del cono +// PtrOwner pSbz( GetSurfBezierRuled( ptTip, &cArc)) ; +// if ( IsNull( pSbz)) +// return nullptr ; +// +// //// creo la superficie di base e la inverto +// //PtrOwner pSTM1( GetSurfTriMeshByFlatContour( &cArc, dLinTol)) ; +// //if ( IsNull( pSTM1)) +// // return nullptr ; +// //pSTM1->Invert() ; +// //// la unisco alla superficie del fianco +// //if ( ! pSTM->DoSewing( *pSTM1)) +// // return nullptr ; +// +// // restituisco la superficie +// return Release( pSbz) ; +//} diff --git a/SfrCreate.cpp b/SfrCreate.cpp index c75c006..3e34479 100644 --- a/SfrCreate.cpp +++ b/SfrCreate.cpp @@ -571,4 +571,139 @@ SurfFlatRegionByContours::GetUnusedCurveTempProps( INTVECTOR& vId) vId.push_back( pCrv->GetTempProp()) ; } return ( ! vId.empty()) ; -} \ No newline at end of file +} + +//------------------------------------------------------------------------------- +bool +CalcRegionPolyLines( const CICURVEPVECTOR& vpCurve, double dLinTol, + POLYLINEVECTOR& vPL, Vector3d& vtN) +{ + // se non ho curve, non faccio nulla + if ( int( vpCurve.size()) == 0) + return true ; + + // calcolo le polilinee che approssimano le curve + vPL.resize( vpCurve.size()) ; + for ( int i = 0 ; i < int( vpCurve.size()) ; ++ i) { + if ( ! vpCurve[i]->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, vPL[i])) + return false ; + } + + // ricavo versore normale + Plane3d plPlane ; double dArea ; + if ( ! vPL[0].IsClosedAndFlat( plPlane, dArea, 50 * EPS_SMALL)) + return false ; + vtN = plPlane.GetVersN() ; + + typedef std::pair INDAREA ; + std::vector m_vArea ; + // calcolo piano medio e area delle curve + m_vArea.reserve( vPL.size()) ; + for ( int i = 0 ; i < int( vPL.size()) ; ++ i) { + // calcolo piano medio e area + Plane3d plPlane ; + double dArea ; + if ( ! vPL[i].IsClosedAndFlat( plPlane, dArea)) + return false ; + // verifico che le normali siano molto vicine + if ( ! AreSameOrOppositeVectorApprox( plPlane.GetVersN(), vtN)) + return false ; + // assegno il segno all'area secondo il verso della normale + if ( ( plPlane.GetVersN() * vtN) > 0) + m_vArea.emplace_back( i, dArea) ; + else + m_vArea.emplace_back( i, - dArea) ; + } + // ordino in senso decrescente sull'area + sort( m_vArea.begin(), m_vArea.end(), + []( const INDAREA& a, const INDAREA& b) { return ( abs( a.second) > abs( b.second)) ; }) ; + + // dalle PolyLine passo alle curve nel piano XY ( prendo la prima come riferimento, trascuro le Z delle successive) + Frame3d frRef ; frRef.Set( ORIG, vtN) ; + if ( ! frRef.IsValid()) + return false ; + ICRVCOMPOPOVECTOR vCrvCompo( int( vPL.size())) ; + for ( int i = 0 ; i < int( vPL.size()) ; ++ i) { + vCrvCompo[i].Set( CreateCurveComposite()) ; + vCrvCompo[i]->FromPolyLine( vPL[i]) ; + vCrvCompo[i]->ToLoc( frRef) ; + } + + // creo una matrice di interi ; ogni riga corrisponde ad un chunk, dove in posizione 0 c'è il loop esterno e nelle + // successive i loop interni + INTMATRIX vnPLIndMat ; + + // vettore di indici per ordinare le PolyLine + INTVECTOR vPL_IndOrder ; vPL_IndOrder.resize( int( vPL.size())) ; + for ( int i = 0 ; i < int( m_vArea.size()) ; ++ i) + vPL_IndOrder[i] = m_vArea[i].first ; + + // aggiungo le diverse curve + bool bFirstCrv ; + Plane3d plExtLoop ; + double dAreaExtLoop = 0. ; + do { + bFirstCrv = true ; + for ( int i = 0 ; i < int( m_vArea.size()) ; ++ i) { + // recupero indice di percorso e verifico sia valido + int j = m_vArea[i].first ; + if ( j < 0) + continue ; + // lo inserisco come esterno... + if ( bFirstCrv) { + vnPLIndMat.push_back({ j}) ; + m_vArea[i].first = -1 ; + dAreaExtLoop = m_vArea[i].second ; + // inverto se necessario + if ( m_vArea[i].second < EPS_SMALL) { + vPL[j].Invert() ; + vCrvCompo[j]->Invert() ; + dAreaExtLoop *= -1 ; + } + bFirstCrv = false ; + } + // ... altrimenti verifico se il loop è interno o no + else { + // il loop è interno se è sia interno al loop esterno della riga di vnPLIndMat e allo stesso tempo + // esterno a tutti i loop già inseriti nella riga attuale. + // verifica rispetto loop esterno + IntersCurveCurve ccInt( *vCrvCompo[vnPLIndMat.back().front()], *vCrvCompo[j]) ; + CRVCVECTOR ccClass ; + if ( ccInt.GetCrossOrOverlapIntersCount() > 0 || + ! ccInt.GetCurveClassification( 1, EPS_SMALL, ccClass) || + ccClass.empty() || ccClass[0].nClass != CRVC_IN) + continue ; + // verifica rispetto ai loop interni + bool bOk = true ; + for ( int k = 1 ; k < int( vnPLIndMat.back().size()) ; ++ k) { + IntersCurveCurve ccInt2( *vCrvCompo[vnPLIndMat.back()[k]], *vCrvCompo[j]) ; + CRVCVECTOR ccClass2 ; + if ( ccInt2.GetCrossOrOverlapIntersCount() > 0 || + ! ccInt2.GetCurveClassification( 1, EPS_SMALL, ccClass2) || + ccClass2.empty() || ccClass2[0].nClass != CRVC_IN) { + bOk = false ; + break ; + } + } + if ( bOk) { + // inserisco nella matrice + vnPLIndMat.back().push_back( j) ; + m_vArea[i].first = -1 ; + // inverto se necessario + if ( m_vArea[i].second * dAreaExtLoop > 0.) { + vPL[j].Invert() ; + vCrvCompo[j]->Invert() ; + } + } + } + } + } while ( ! bFirstCrv) ; + + // ordino le PolyLine per area + POLYLINEVECTOR vPL_tmp ; + for ( int i = 0 ; i < int( vPL_IndOrder.size()) ; ++ i) + vPL_tmp.push_back( vPL[ vPL_IndOrder[i]]) ; + swap( vPL, vPL_tmp) ; + + return true ; +} diff --git a/StmFromCurves.cpp b/StmFromCurves.cpp index c548740..2681463 100644 --- a/StmFromCurves.cpp +++ b/StmFromCurves.cpp @@ -31,10 +31,6 @@ using namespace std ; -//------------------------------------------------------------------------------- -static bool CalcRegionPolyLines( const CICURVEPVECTOR& vpCurve, double dLinTol, - POLYLINEVECTOR& vPL, Vector3d& vtN) ; - //------------------------------------------------------------------------------- ISurfTriMesh* GetSurfTriMeshByFlatContour( const ICurve* pCurve, double dLinTol) @@ -1433,138 +1429,3 @@ GetSurfTriMeshRuled( const ICurve* pCurve1, const ICurve* pCurve2, int nType, do // restituisco la superficie return Release( pSTM) ; } - -//------------------------------------------------------------------------------- -bool -CalcRegionPolyLines( const CICURVEPVECTOR& vpCurve, double dLinTol, - POLYLINEVECTOR& vPL, Vector3d& vtN) -{ - // se non ho curve, non faccio nulla - if ( int( vpCurve.size()) == 0) - return true ; - - // calcolo le polilinee che approssimano le curve - vPL.resize( vpCurve.size()) ; - for ( int i = 0 ; i < int( vpCurve.size()) ; ++ i) { - if ( ! vpCurve[i]->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, vPL[i])) - return false ; - } - - // ricavo versore normale - Plane3d plPlane ; double dArea ; - if ( ! vPL[0].IsClosedAndFlat( plPlane, dArea, 50 * EPS_SMALL)) - return false ; - vtN = plPlane.GetVersN() ; - - typedef std::pair INDAREA ; - std::vector m_vArea ; - // calcolo piano medio e area delle curve - m_vArea.reserve( vPL.size()) ; - for ( int i = 0 ; i < int( vPL.size()) ; ++ i) { - // calcolo piano medio e area - Plane3d plPlane ; - double dArea ; - if ( ! vPL[i].IsClosedAndFlat( plPlane, dArea)) - return false ; - // verifico che le normali siano molto vicine - if ( ! AreSameOrOppositeVectorApprox( plPlane.GetVersN(), vtN)) - return false ; - // assegno il segno all'area secondo il verso della normale - if ( ( plPlane.GetVersN() * vtN) > 0) - m_vArea.emplace_back( i, dArea) ; - else - m_vArea.emplace_back( i, - dArea) ; - } - // ordino in senso decrescente sull'area - sort( m_vArea.begin(), m_vArea.end(), - []( const INDAREA& a, const INDAREA& b) { return ( abs( a.second) > abs( b.second)) ; }) ; - - // dalle PolyLine passo alle curve nel piano XY ( prendo la prima come riferimento, trascuro le Z delle successive) - Frame3d frRef ; frRef.Set( ORIG, vtN) ; - if ( ! frRef.IsValid()) - return false ; - ICRVCOMPOPOVECTOR vCrvCompo( int( vPL.size())) ; - for ( int i = 0 ; i < int( vPL.size()) ; ++ i) { - vCrvCompo[i].Set( CreateCurveComposite()) ; - vCrvCompo[i]->FromPolyLine( vPL[i]) ; - vCrvCompo[i]->ToLoc( frRef) ; - } - - // creo una matrice di interi ; ogni riga corrisponde ad un chunk, dove in posizione 0 c'è il loop esterno e nelle - // successive i loop interni - INTMATRIX vnPLIndMat ; - - // vettore di indici per ordinare le PolyLine - INTVECTOR vPL_IndOrder ; vPL_IndOrder.resize( int( vPL.size())) ; - for ( int i = 0 ; i < int( m_vArea.size()) ; ++ i) - vPL_IndOrder[i] = m_vArea[i].first ; - - // aggiungo le diverse curve - bool bFirstCrv ; - Plane3d plExtLoop ; - double dAreaExtLoop = 0. ; - do { - bFirstCrv = true ; - for ( int i = 0 ; i < int( m_vArea.size()) ; ++ i) { - // recupero indice di percorso e verifico sia valido - int j = m_vArea[i].first ; - if ( j < 0) - continue ; - // lo inserisco come esterno... - if ( bFirstCrv) { - vnPLIndMat.push_back({ j}) ; - m_vArea[i].first = -1 ; - dAreaExtLoop = m_vArea[i].second ; - // inverto se necessario - if ( m_vArea[i].second < EPS_SMALL) { - vPL[j].Invert() ; - vCrvCompo[j]->Invert() ; - dAreaExtLoop *= -1 ; - } - bFirstCrv = false ; - } - // ... altrimenti verifico se il loop è interno o no - else { - // il loop è interno se è sia interno al loop esterno della riga di vnPLIndMat e allo stesso tempo - // esterno a tutti i loop già inseriti nella riga attuale. - // verifica rispetto loop esterno - IntersCurveCurve ccInt( *vCrvCompo[vnPLIndMat.back().front()], *vCrvCompo[j]) ; - CRVCVECTOR ccClass ; - if ( ccInt.GetCrossOrOverlapIntersCount() > 0 || - ! ccInt.GetCurveClassification( 1, EPS_SMALL, ccClass) || - ccClass.empty() || ccClass[0].nClass != CRVC_IN) - continue ; - // verifica rispetto ai loop interni - bool bOk = true ; - for ( int k = 1 ; k < int( vnPLIndMat.back().size()) ; ++ k) { - IntersCurveCurve ccInt2( *vCrvCompo[vnPLIndMat.back()[k]], *vCrvCompo[j]) ; - CRVCVECTOR ccClass2 ; - if ( ccInt2.GetCrossOrOverlapIntersCount() > 0 || - ! ccInt2.GetCurveClassification( 1, EPS_SMALL, ccClass2) || - ccClass2.empty() || ccClass2[0].nClass != CRVC_IN) { - bOk = false ; - break ; - } - } - if ( bOk) { - // inserisco nella matrice - vnPLIndMat.back().push_back( j) ; - m_vArea[i].first = -1 ; - // inverto se necessario - if ( m_vArea[i].second * dAreaExtLoop > 0.) { - vPL[j].Invert() ; - vCrvCompo[j]->Invert() ; - } - } - } - } - } while ( ! bFirstCrv) ; - - // ordino le PolyLine per area - POLYLINEVECTOR vPL_tmp ; - for ( int i = 0 ; i < int( vPL_IndOrder.size()) ; ++ i) - vPL_tmp.push_back( vPL[ vPL_IndOrder[i]]) ; - swap( vPL, vPL_tmp) ; - - return true ; -} diff --git a/SurfBezier.cpp b/SurfBezier.cpp index 383c5f2..d855055 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -33,17 +33,21 @@ #include "/EgtDev/Include/EGkChainCurves.h" #include "/EgtDev/Include/EGkIntersLineSurfBez.h" #include "/EgtDev/Include/EGkDistPointSurfTm.h" +#include "/EgtDev/Include/EGkDistPointLine.h" +#include "/EgtDev/Include/EGkDistPointCurve.h" #include "/EgtDev/Include/EGkCurveComposite.h" +#include "/EgtDev/Include/EGkCurveArc.h" #include "/EgtDev/Include/EGkGeoPoint3d.h" #include "/EgtDev/Include/EGkIntervals.h" #include "/EgtDev/Extern/Eigen/Dense" -#include using namespace std ; //---------------------------------------------------------------------------- GEOOBJ_REGISTER( SRF_BEZIER, NGE_S_BEZ, SurfBezier) ; +static bool ChangeStartForClosed( PolyLine& plU0, PolyLine& plU1, ICurveComposite* pCrvU0, ICurveComposite* pCrvU1) ; + //---------------------------------------------------------------------------- SurfBezier::SurfBezier( void) : m_pSTM( nullptr), m_nStatus( TO_VERIFY), m_nDegU(), m_nDegV(), m_nSpanU(), m_nSpanV(), m_bRat( false), @@ -63,7 +67,7 @@ SurfBezier::~SurfBezier( void) bool SurfBezier::Init( int nDegU, int nDegV, int nSpanU, int nSpanV, bool bIsRational) { - // verifico validit� grado + // verifico validità grado if ( nDegU < 1 || nDegU > MAXDEG || nDegV < 1 || nDegV > MAXDEG || nSpanU < 1 || nSpanV < 1) return false ; @@ -95,7 +99,7 @@ SurfBezier::Init( int nDegU, int nDegV, int nSpanU, int nSpanV, bool bIsRational bool SurfBezier::SetControlPoint( int nInd, const Point3d& ptCtrl) { - // verifico validit� indice + // verifico validità indice if ( m_nStatus != OK || m_bRat || nInd < 0 || nInd >= GetDim()) return false ; @@ -117,7 +121,7 @@ SurfBezier::SetControlPoint( int nInd, const Point3d& ptCtrl) bool SurfBezier::SetControlPoint( int nInd, const Point3d& ptCtrl, double dW) { - // verifico validit�, razionalit� e indice + // verifico validità, razionalità e indice if ( m_nStatus != OK || ! m_bRat || nInd < 0 || nInd >= GetDim()) return false ; @@ -198,7 +202,7 @@ SurfBezier::GetTrimRegion( void) const bool SurfBezier::GetInfo( int& nDegU, int& nDegV, int& nSpanU, int& nSpanV, bool& bIsRat, bool& bTrimmed) const { - // verifico validit� superficie + // verifico validità superficie if ( m_nStatus != OK) return false ; // restituisco gradi e flag di razionale @@ -215,7 +219,7 @@ SurfBezier::GetInfo( int& nDegU, int& nDegV, int& nSpanU, int& nSpanV, bool& bIs const Point3d& SurfBezier::GetControlPoint( int nInd, bool* pbOk) const { - // verifico validit� e indice + // verifico validità e indice if ( m_nStatus != OK || nInd < 0 || nInd >= GetDim()) { if ( pbOk != NULL) *pbOk = false ; @@ -231,7 +235,7 @@ SurfBezier::GetControlPoint( int nInd, bool* pbOk) const double SurfBezier::GetControlWeight( int nInd, bool* pbOk) const { - // verifico validit�, razionalit� e indice + // verifico validità, razionalità e indice if ( m_nStatus != OK || ! m_bRat || nInd < 0 || nInd >= GetDim()) { if ( pbOk != NULL) *pbOk = false ; @@ -543,7 +547,7 @@ 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 delle due derivate è piccola, mi sposto lungo il relativo parametro e uso le tangenti 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 ; @@ -650,7 +654,7 @@ SurfBezier::GetTitle( void) const bool SurfBezier::Dump( string& sOut, bool bMM, const char* szNewLine) const { - // verifico validit� superficie + // verifico validità superficie if ( m_nStatus != OK) sOut += string( "Status=Invalid") + szNewLine ; // area @@ -883,7 +887,7 @@ SurfBezier::Rotate( const Point3d& ptAx, const Vector3d& vtAx, double dCosAng, d // la superficie deve essere validata if ( m_nStatus != OK) return false ; - // verifico validit� dell'asse di rotazione + // verifico validità dell'asse di rotazione if ( vtAx.IsSmall()) return false ; @@ -939,7 +943,7 @@ SurfBezier::Mirror( const Point3d& ptOn, const Vector3d& vtNorm) // la superficie deve essere validata if ( m_nStatus != OK) return false ; - // verifico validit� del piano di specchiatura + // verifico validità del piano di specchiatura if ( vtNorm.IsSmall()) return false ; @@ -962,7 +966,7 @@ SurfBezier::Shear( const Point3d& ptOn, const Vector3d& vtNorm, const Vector3d& // la superficie deve essere validata if ( m_nStatus != OK) return false ; - // verifico validit� dei parametri + // verifico validità dei parametri if ( vtNorm.IsSmall() || vtDir.IsSmall()) return false ; @@ -984,11 +988,11 @@ SurfBezier::ToGlob( const Frame3d& frRef) // la superficie deve essere validata if ( m_nStatus != OK) return false ; - // verifico validit� del frame + // verifico validità del frame if ( frRef.GetType() == Frame3d::ERR) return false ; - // se frame identit�, non devo fare alcunch� + // se frame identità, non devo fare alcunché if ( IsGlobFrame( frRef)) return true ; @@ -1010,11 +1014,11 @@ SurfBezier::ToLoc( const Frame3d& frRef) // la superficie deve essere validata if ( m_nStatus != OK) return false ; - // verifico validit� del frame + // verifico validità del frame if ( frRef.GetType() == Frame3d::ERR) return false ; - // se frame identit�, non devo fare alcunch� + // se frame identità, non devo fare alcunché if ( IsGlobFrame( frRef)) return true ; @@ -1036,11 +1040,11 @@ SurfBezier::LocToLoc( const Frame3d& frOri, const Frame3d& frDest) // la superficie deve essere validata if ( m_nStatus != OK) return false ; - // verifico validit� dei frame + // verifico validità dei frame if ( frOri.GetType() == Frame3d::ERR || frDest.GetType() == Frame3d::ERR) return false ; - // se i due riferimenti coincidono, non devo fare alcunch� + // se i due riferimenti coincidono, non devo fare alcunché if ( AreSameFrame( frOri, frDest)) return true ; @@ -1303,7 +1307,7 @@ SurfBezier::GetLoop( int nLoop) const // se loop chiuso lo restituisco, altrimenti errore return ( pLoop->IsClosed() ? Release( pLoop) : nullptr) ; } - // la superficie � trimmata, quindi devo cercare nei vari chunck il loop corrispondente + // la superficie è trimmata, quindi devo cercare nei vari chunck il loop corrispondente else { if ( nLoop > m_pTrimReg->GetChunkCount()) return nullptr ; @@ -1516,8 +1520,8 @@ SurfBezier::GetApproxSurf( double dTol, double dSideMin) const // costruttore della superficie POLYLINEMATRIX vvPL ; + POLYLINEMATRIX vvPL3d ; //POLYLINEVECTOR vPL ; // per usare i polygon basic - //Tree Tree( this, true) ; Tree Tree ; if ( ! Tree.SetSurf( this, true)) return nullptr ; @@ -1540,10 +1544,11 @@ SurfBezier::GetApproxSurf( double dTol, double dSideMin) const else { //Tree.BuildTree( 5 * LIN_TOL_FINE, 0.1) ; Tree.BuildTree( dTol, dSideMin) ; + //Tree.BuildTree( 1, 5) ; //debug } - if ( ! Tree.GetPolygons( vvPL)) + if ( ! Tree.GetPolygons( vvPL, vvPL3d)) continue ; - //Tree.GetPolygonsBasic( vPL) ; // per usare i polygon basic + //Tree.GetPolygonsBasic( vPL, true) ; // per usare i polygon basic // aggiorno la chiusura della superficie m_bClosedU = m_bClosedU || Tree.IsClosedU() ; @@ -1567,6 +1572,7 @@ SurfBezier::GetApproxSurf( double dTol, double dSideMin) const return nullptr ; // prendo i punti di ogni polyline dell'albero, li triangolo e li porto in 3d + int c = 0 ; for ( POLYLINEVECTOR vPL : vvPL) { PNTVECTOR vPnt ; INTVECTOR vTria ; @@ -1574,14 +1580,44 @@ SurfBezier::GetApproxSurf( double dTol, double dSideMin) const if ( ! Tri.Make( vPL, vPnt, vTria)) return nullptr ; + //vedo se la polyline 3d che passo io corrisponde a quella che usavo prima + POLYLINEVECTOR vPL3d = vvPL3d[c] ; + // porto i punti in 3d PNTVECTOR vPnt3d ; - for ( int i = 0 ; i < int( vPnt.size()) ; ++ i) { - Point3d pt3d ; - if ( ! GetPointD1D2( vPnt[i].x / SBZ_TREG_COEFF, vPnt[i].y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt3d)) - return nullptr ; - vPnt3d.push_back( pt3d) ; + + for( int i = 0 ; i < int( vPL3d.size()) ; ++i) { + PolyLine pl3d = vPL3d[i] ; + Point3d pt3d ; pl3d.GetFirstPoint( pt3d) ; + //vPnt3d.push_back( pt3d) ; + while ( pl3d.GetNextPoint( pt3d)) { + vPnt3d.push_back( pt3d) ; + } } + + // controllo per ogni polyline se è stato invertito il vettore dei punti + int nCurrPoint = 0 ; + for( int i = 0 ; i < int( vPL.size()) ; ++i) { + Point3d pt3d ; vPL[i].GetFirstPoint( pt3d) ; + vPL[i].GetNextPoint( pt3d) ; + int nPoints = vPL[i].GetPointNbr() - 2 ; + if ( ! AreSamePointApprox( vPnt[nCurrPoint], pt3d)) + reverse( vPnt3d.begin() + nCurrPoint, vPnt3d.begin() + nCurrPoint + nPoints) ; + nCurrPoint += nPoints ; + } + + //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 ; + if ( ! GetPointD1D2( vPnt[i].x / SBZ_TREG_COEFF, vPnt[i].y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt3d)) + return nullptr ; + vPnt3d.push_back( pt3d) ; + } + } + int nTria = int( vTria.size()) / 3 ; for ( int i = 0 ; i < nTria ; ++i) { if ( ! stmSoup.AddTriangle( vPnt3d[vTria[3*i]], vPnt3d[vTria[3*i+1]], vPnt3d[vTria[3*i+2]], @@ -1590,6 +1626,7 @@ SurfBezier::GetApproxSurf( double dTol, double dSideMin) const vPnt[vTria[3*i+2]].x, vPnt[vTria[3*i+2]].y)) return nullptr ; } + ++c ; } // termino @@ -1749,10 +1786,10 @@ SurfBezier::UnprojectCurveFromStm( const ICurveComposite* pCC, ICRVCOMPOPVECTOR& Point3d pt3DPrev = pt3D ; Point3d pt2DPrev = pt2D ; bool bPrevIsPole = false ; + bool bHorizontalPole = true ; if ( bThroughEdge) { // devo cambiare le coordinate di pt2DPrev per periodicità // capisco su quale lato è e lo porto sul lato opposto - Point3d pt = pt2DPrev ; if ( m_bClosedU) { if ( pt2DPrev.x < 1) pt2DPrev.x = m_nSpanU * SBZ_TREG_COEFF ; @@ -1765,27 +1802,35 @@ SurfBezier::UnprojectCurveFromStm( const ICurveComposite* pCC, ICRVCOMPOPVECTOR& else if ( (m_nSpanV * SBZ_TREG_COEFF - pt2DPrev.y) < 1) pt2DPrev.y = 0 ; } - bPrevIsPole = AreSamePointApprox( pt, pt2DPrev) ; + // verifico se il punto era in un polo + if ( ( m_vbPole[0] && m_nSpanV * SBZ_TREG_COEFF - pt2DPrev.y < 1 ) || + ( m_vbPole[2] && pt2DPrev.y < 1 ) ) { + bPrevIsPole = true ; + bHorizontalPole = true ; + } + if ( ( m_vbPole[1] && pt2DPrev.x < 1 ) || + ( m_vbPole[3] && m_nSpanU * SBZ_TREG_COEFF - pt2DPrev.x < 1 ) ) { + bPrevIsPole = true ; + bHorizontalPole = false ; + } } pCrv->GetEndPoint( pt3D) ; if ( ! UnprojectPoint( pt3D, pt2D, pt3DPrev, &bThroughEdge, pPlCut)) return false ; - if ( bPrevIsPole) { + + // se il precedente era passato attraverso l'edge ed era un edge di polo allora devo sistemare le coordinate + if( bPrevIsPole){ // se il punto precedente era di polo allora devo correggere le sue coordinate 2D - if ( ( m_vbPole[0] || m_vbPole[2] )) { - if ( pt2DPrev.y < 1 || m_nSpanV * SBZ_TREG_COEFF - pt2DPrev.y < 1) - pt2DPrev.x = pt2D.x ; - } - if ( ( m_vbPole[1] || m_vbPole[3] )) { - if ( pt2DPrev.x < 1 || m_nSpanU * SBZ_TREG_COEFF - pt2DPrev.x < 1) - pt2DPrev.y = pt2D.y ; - } + if ( bHorizontalPole) + pt2DPrev.x = pt2D.x ; + else if ( ! bHorizontalPole) + pt2DPrev.y = pt2D.y ; } Vector3d vtDir = pt2D - pt2DPrev ; vtDir.Normalize() ; // se mi accorgo che sto per tracciare un taglio lungo un bordo posso semplicmente evitarlo - if ( (1 - abs(vtDir.x) < EPS_SMALL && (pt2D.y < EPS_SMALL || m_nSpanV * SBZ_TREG_COEFF - pt2D.y < 1)) || // parallelo agli edge 0 e 2 e su uno di questi - (1 - abs(vtDir.y) < EPS_SMALL && (pt2D.x < EPS_SMALL || m_nSpanU * SBZ_TREG_COEFF - pt2D.x < 1))) { // parallello agli edge 1 e 3 e su uno di questi + if ( (1 - abs(vtDir.x) < SQ_EPS_SMALL && (pt2D.y < 1 || m_nSpanV * SBZ_TREG_COEFF - pt2D.y < 1)) || // parallelo agli edge 0 e 2 e su uno di questi + (1 - abs(vtDir.y) < SQ_EPS_SMALL && (pt2D.x < 1 || m_nSpanU * SBZ_TREG_COEFF - pt2D.x < 1))) { // parallello agli edge 1 e 3 e su uno di questi ++ nRejected ; continue ; } @@ -1794,6 +1839,7 @@ SurfBezier::UnprojectCurveFromStm( const ICurveComposite* pCC, ICRVCOMPOPVECTOR& dParamH = m_nSpanV * SBZ_TREG_COEFF ; dParamL = m_nSpanU * SBZ_TREG_COEFF ; // sia questo punto che il precedente sono su un edge, ma il segmento che li unisce non è parallelo ad un edge + // ( i punti per periodicità hanno coordinate diverse anche se dovrebbero averle uguali, quindi il segmento attraversa tutto lo spazio parametrico, anche se in realtà è lungo il bordo di chiusura) // potrei star tracciando un taglio sul bordo di chiusura // controllo se sto tracciando una linea che unisce due lati di chiusura, allora in realtà sdtarei tracciando un taglio sull'edge e quindi posso non tracciarlo if ( (abs( vtDir.x) > abs( vtDir.y) && Dist( pt2D, pt2DPrev) > dParamL * 0.5) || @@ -1882,76 +1928,13 @@ struct hash { }; //---------------------------------------------------------------------------- -bool -SurfBezier::Cut( const Plane3d& plPlane, bool bSaveOnEq) +ISurfFlatRegion* +SurfBezier::CreateTrimRegionFromCuts( ICRVCOMPOPOVECTOR& vpCCOpen, ICRVCOMPOPOVECTOR& vpCCClosed) const { - // faccio l'intersezione della trimesh ausiliaria con il piano posso ottenere: punti, curve 3d e triangoli( coplanari al piano di taglio) - // i punti li escludo - // le curve 3d le trasformo in curve 2d e le aggiungo alle curve di trim - // accorpo eventuali triangoli adiacenti ed estraggo i loop delle regioni ottenute; questi vengono poi portati in 2d e aggiunti alle curve di trim - - // se necessario calcolo i poli - if ( m_vbPole.empty()) - CalcPoles() ; - - PNTVECTOR vPnt ; - BIPNTVECTOR vBPnt ; - TRIA3DVECTOR vTria ; - IntersPlaneSurfTm( plPlane, *GetAuxSurf(), vPnt, vBPnt, vTria) ; - - // concateno le curve 3d - ChainCurves chainC ; - double dToler = EPS_SMALL ; - chainC.Init( false, dToler, int( vBPnt.size())) ; - for ( int i = 0 ; i < int( vBPnt.size()) ; ++ i) { - Vector3d vtDir = vBPnt[i].second - vBPnt[i].first ; - vtDir.Normalize() ; - if ( ! chainC.AddCurve( i + 1, vBPnt[i].first, vtDir, vBPnt[i].second, vtDir)) - return false ; - } - // GESTIONE DELLE CURVE OTTENUTE DALL'INTERSEZIONE - - // recupero i percorsi concatenati - Point3d ptNear = ( vBPnt.empty() ? ORIG : vBPnt[0].first) ; - INTVECTOR vId ; - - // separo tra loop chiusi, interni allo spazio parametrico e loop passanti che tagliano lo spazio intersecando i bordi - ICRVCOMPOPOVECTOR vpCCOpen ; - ICRVCOMPOPOVECTOR vpCCClosed ; - - while ( chainC.GetChainFromNear( ptNear, false, vId)) { - // creo una curva composita - PtrOwner pCrvCompo( CreateCurveComposite()) ; - if ( IsNull( pCrvCompo)) - return false ; - // recupero gli estremi dei segmenti, creo le linee e le inserisco nella composita - bool bAdded = true ; - for ( int i = 0 ; i < int( vId.size()) ; ++ i) { - // creo un segmento di retta - 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 ; - Point3d ptStart = ( bAdded ? vBPnt[nInd].first : ptNear) ; - Point3d ptEnd = vBPnt[nInd].second ; - // provo ad accodarlo alla composita - bAdded = ( Dist( ptStart, ptEnd) > dToler / 2 && - pLine->Set( ptStart, ptEnd)) ; - bAdded = bAdded && pCrvCompo->AddCurve( pLine, true, dToler) ; - ptNear = ( bAdded ? ptEnd : ptStart) ; - } - if ( ! AddCurveCompoToCuts( pCrvCompo, vpCCOpen, vpCCClosed, EPS_SMALL, &plPlane)) - return false ; - } - //comincio a creare la superficie aggiungendo i tagli aperti ai bordi attualmente esistenti SurfFlatRegionByContours sfrContour ; if ( int(vpCCOpen.size()) != 0 ) { - // qui devo aggiungere tutto del codice nuovo per ricostruire in altro modo il nuovo bordo della superficie // recupero la regione attuale - - PtrOwner pNewTrim( CreateBasicSurfFlatRegion()) ; if ( m_bTrimmed) pNewTrim.Set( GetTrimRegion()->Clone()) ; @@ -2114,11 +2097,11 @@ SurfBezier::Cut( const Plane3d& plPlane, bool bSaveOnEq) } } } - + // devo trovare fino a che punto seguire il loop che ho trovato come prosecuzione del taglio corrente // devo quindi trovare la prossima intersezione con un taglio int nInters = -1 ; - double dNextCut = numeric_limits::infinity() ; + double dNextCut = INFINITO ; double dEndCurrentCut ; for ( int i = 0 ; i < int( mInters[tiEnd].size()); ++i) { // se ho trovato l'intersezione con la fine del taglio corrente, salvo il parametro sul loop @@ -2139,7 +2122,7 @@ SurfBezier::Cut( const Plane3d& plPlane, bool bSaveOnEq) } } if ( nInters == -1) { - dNextCut = numeric_limits::infinity() ; + dNextCut = INFINITO ; for ( const auto& pair : mInters) { if ( get<0>(pair.first) == get<0>(tiEnd) && get<1>(pair.first) == get<1>(tiEnd)) { for ( int i = 0 ; i < int(pair.second.size()); ++i ) { @@ -2180,6 +2163,80 @@ SurfBezier::Cut( const Plane3d& plPlane, bool bSaveOnEq) } } + // aggiungo i loop chiusi + for ( int i = 0 ; i < int( vpCCClosed.size()); ++i ) + sfrContour.AddCurve( Release( vpCCClosed[i])) ; + + PtrOwner pSfrTrimReg( sfrContour.GetSurf()) ; + return Release( pSfrTrimReg) ; +} + +//---------------------------------------------------------------------------- +bool +SurfBezier::Cut( const Plane3d& plPlane, bool bSaveOnEq) +{ + // faccio l'intersezione della trimesh ausiliaria con il piano posso ottenere: punti, curve 3d e triangoli( coplanari al piano di taglio) + // i punti li escludo + // le curve 3d le trasformo in curve 2d e le aggiungo alle curve di trim + // accorpo eventuali triangoli adiacenti ed estraggo i loop delle regioni ottenute; questi vengono poi portati in 2d e aggiunti alle curve di trim + + // N.B. : questa funzione non prevede poli interni alla superficie, ma solo lati che sono collassati in poli!!!! + + // se necessario calcolo i poli + if ( m_vbPole.empty()) + CalcPoles() ; + + PNTVECTOR vPnt ; + BIPNTVECTOR vBPnt ; + TRIA3DVECTOR vTria ; + IntersPlaneSurfTm( plPlane, *GetAuxSurf(), vPnt, vBPnt, vTria) ; + + // concateno le curve 3d + ChainCurves chainC ; + double dToler = EPS_SMALL ; + chainC.Init( false, dToler, int( vBPnt.size())) ; + for ( int i = 0 ; i < int( vBPnt.size()) ; ++ i) { + Vector3d vtDir = vBPnt[i].second - vBPnt[i].first ; + vtDir.Normalize() ; + if ( ! chainC.AddCurve( i + 1, vBPnt[i].first, vtDir, vBPnt[i].second, vtDir)) + return false ; + } + // GESTIONE DELLE CURVE OTTENUTE DALL'INTERSEZIONE + + // recupero i percorsi concatenati + Point3d ptNear = ( vBPnt.empty() ? ORIG : vBPnt[0].first) ; + INTVECTOR vId ; + + // separo tra loop chiusi, interni allo spazio parametrico e loop passanti che tagliano lo spazio intersecando i bordi + ICRVCOMPOPOVECTOR vpCCOpen ; + ICRVCOMPOPOVECTOR vpCCClosed ; + + while ( chainC.GetChainFromNear( ptNear, false, vId)) { + // creo una curva composita + PtrOwner pCrvCompo( CreateCurveComposite()) ; + if ( IsNull( pCrvCompo)) + return false ; + // recupero gli estremi dei segmenti, creo le linee e le inserisco nella composita + bool bAdded = true ; + for ( int i = 0 ; i < int( vId.size()) ; ++ i) { + // creo un segmento di retta + 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 ; + Point3d ptStart = ( bAdded ? vBPnt[nInd].first : ptNear) ; + Point3d ptEnd = vBPnt[nInd].second ; + // provo ad accodarlo alla composita + bAdded = ( Dist( ptStart, ptEnd) > dToler / 2 && + pLine->Set( ptStart, ptEnd)) ; + bAdded = bAdded && pCrvCompo->AddCurve( pLine, true, dToler) ; + ptNear = ( bAdded ? ptEnd : ptStart) ; + } + if ( ! AddCurveCompoToCuts( pCrvCompo, vpCCOpen, vpCCClosed, EPS_SMALL, &plPlane)) + return false ; + } + //GESTIONE DEI TRIANGOLI RISULTANTI DALL'INTERSEZIONE StmFromTriangleSoup StmFts ; if ( ! StmFts.Start()) @@ -2197,16 +2254,15 @@ SurfBezier::Cut( const Plane3d& plPlane, bool bSaveOnEq) pNewStm->GetLoops( vPLTria) ; } - // aggiungo i loop chiusi - for ( int i = 0 ; i < int( vpCCClosed.size()); ++i ) - sfrContour.AddCurve( Release( vpCCClosed[i])) ; // aggiungo loop derivati dai triangoli for ( int i = 0 ; i < int( vPLTria.size()); ++i ) { - PtrOwner pCC( CreateCurveComposite()) ; - pCC->FromPolyLine( vPLTria[i]) ; - sfrContour.AddCurve( Release( pCC)) ; + vpCCClosed.emplace_back() ; + vpCCClosed.back()->FromPolyLine( vPLTria[i]) ; } - PtrOwner pSFR( sfrContour.GetSurf()) ; + + // ora posso chiamare la costruzione dello spazio parametrico trimmato + + PtrOwner pSFR( CreateTrimRegionFromCuts( vpCCOpen, vpCCClosed)) ; if ( IsNull( pSFR) || ! pSFR->IsValid()) return false ; @@ -2316,6 +2372,7 @@ SurfBezier::UnprojectPointFromStm( int nT, const Point3d& ptI, Point3d& ptSP, in // devo subito capire se sono in un polo o no // se sono in polo e mi hanno passato un punto precedente allora devo prendere il triangolo di quel punto bool bIsPole = false ; + bool bNearPole = false ; // devo capire se il triangolo di riferimento ha un vertice in un polo int nInters = 0 ; INTVECTOR vInters(4) ; fill( vInters.begin(), vInters.end(), 0) ; @@ -2369,6 +2426,39 @@ SurfBezier::UnprojectPointFromStm( int nT, const Point3d& ptI, Point3d& ptSP, in pSurfTm->GetVertex( nVert[0], vPT[0]) ; pSurfTm->GetVertex( nVert[1], vPT[1]) ; pSurfTm->GetVertex( nVert[2], vPT[2]) ; + // devo capire se il trinagolo ha un vertice su un polo + int nVertOnPole = -1 ; + int nEdge = -1 ; + // do per scontato che al più un vertice possa essere in un polo + if ( m_vbPole[0] || m_vbPole[2]) { + for( int p = 0 ; p < 3 ; ++p) { + if ( ( m_vbPole[0] && vPtPa[p].y > m_nSpanV * SBZ_TREG_COEFF - EPS_SMALL ) ) { + bNearPole = true ; + nVertOnPole = p ; + nEdge = 0 ; + } + else if ( m_vbPole[2] && vPtPa[p].y < 0 + EPS_SMALL) { + bNearPole = true ; + nVertOnPole = p ; + nEdge = 2 ; + } + } + } + else if ( m_vbPole[1] || m_vbPole[3]) { + for( int p = 0 ; p < 3 ; ++p) { + if ( ( m_vbPole[3] && vPtPa[p].x > m_nSpanU * SBZ_TREG_COEFF - EPS_SMALL)) { + bNearPole = true ; + nVertOnPole = p ; + nEdge = 3 ; + } + else if ( m_vbPole[1] && vPtPa[p].x < 0 + EPS_SMALL) { + bNearPole = true ; + nVertOnPole = p ; + nEdge = 1 ; + } + } + } + // se la superficie è chiusa controllo se devo tenere conto della periodicità nel prendere le coordinate parametriche dei vertici double dParamH, dParamL ; if ( m_bClosedU || m_bClosedV) { @@ -2392,11 +2482,11 @@ SurfBezier::UnprojectPointFromStm( int nT, const Point3d& ptI, Point3d& ptSP, in 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à + // do per scontato che se la superficie è chiusa lungo un parametro i lati di chiusura non siano dei poli if ( m_bClosedU && abs(vtDir.x) > abs( vtDir.y) && dDist > dParamL * 0.5 ) { // trovo se dei vertici del triangolo sono sul bordo dello spazio parametrico INTVECTOR vOn(3) ; fill( vOn.begin(), vOn.end(), -1) ; - int nVertOnPole = -1 ; INTVECTOR vEdgesClosed = { 1, 3} ; // scorro sui vertici for ( int p = 0 ; p < 3; ++p ) { @@ -2404,20 +2494,8 @@ SurfBezier::UnprojectPointFromStm( int nT, const Point3d& ptI, Point3d& ptSP, in for ( int ed : vEdgesClosed) { // scorro sui tratti che compongono l'edge for ( int i = 0 ; i < int( m_mCCEdge[ed].size()) ; ++i) { - if ( ! m_mCCEdge[ed][i]->IsValid()) { - Point3d pt ; - if ( ! m_mCCEdge[ed][i]->GetOnlyPoint(pt)) - return false ; - if ( AreSamePointApprox( pt, vPT[p])) { - vOn[p] = ed ; - // se un vertice sta su un polo me lo segno - nVertOnPole = p ; - } - } - else { - if (m_mCCEdge[ed][i]->IsPointOn(vPT[p]) && vOn[p] == -1 ) - vOn[p] = ed ; - } + if (m_mCCEdge[ed][i]->IsPointOn(vPT[p]) && vOn[p] == -1 ) + vOn[p] = ed ; } } } @@ -2425,9 +2503,9 @@ SurfBezier::UnprojectPointFromStm( int nT, const Point3d& ptI, Point3d& ptSP, in if ( vOn[0] > 0 || vOn[1] > 0 || vOn[2] > 0) { // se ho più un vertice sul lato oppure se ne ho solo uno ma non è sul polo allora procedo alla correzione delle coordinate if ( vOn[0] * vOn[1] * vOn[2] < 0 || - (vOn[0] > 0 && vOn[0] != nVertOnPole) || - (vOn[1] > 0 && vOn[1] != nVertOnPole) || - (vOn[2] > 0 && vOn[2] != nVertOnPole)) { + (vOn[0] > 0 && 0 != nVertOnPole) || + (vOn[1] > 0 && 1 != nVertOnPole) || + (vOn[2] > 0 && 2 != nVertOnPole)) { double dRightX ; // tengo per buone le coordinate dei vertici che NON sono sul bordo dello spazio parametrico for ( int p = 0 ; p < 3; ++p) { @@ -2458,20 +2536,8 @@ SurfBezier::UnprojectPointFromStm( int nT, const Point3d& ptI, Point3d& ptSP, in for (int ed : vEdgesClosed) { // scorro sui tratti che compongono l'edge for ( int i = 0 ; i < int( m_mCCEdge[ed].size()) ; ++i) { - if ( ! m_mCCEdge[ed][i]->IsValid()) { - Point3d pt ; - if ( ! m_mCCEdge[ed][i]->GetOnlyPoint( pt)) - return false ; - if ( AreSamePointApprox( pt, vPT[p])) { - vOn[p] = ed ; - // se un vertice sta su un polo me lo segno - nVertOnPole = p ; - } - } - else { - if( m_mCCEdge[ed][i]->IsPointOn( vPT[p]) && vOn[p] == -1) - vOn[p] = ed ; - } + if( m_mCCEdge[ed][i]->IsPointOn( vPT[p]) && vOn[p] == -1) + vOn[p] = ed ; } } } @@ -2479,9 +2545,9 @@ SurfBezier::UnprojectPointFromStm( int nT, const Point3d& ptI, Point3d& ptSP, in if ( vOn[0] > 0 || vOn[1] > 0 || vOn[2] > 0) { // se ho più un vertice sul lato oppure se ne ho solo uno ma non è sul polo allora procedo alla correzione delle coordinate if ( vOn[0] * vOn[1] * vOn[2] < 0 || - (vOn[0] > 0 && vOn[0] != nVertOnPole) || - (vOn[1] > 0 && vOn[1] != nVertOnPole) || - (vOn[2] > 0 && vOn[2] != nVertOnPole)) { + (vOn[0] > 0 && 0 != nVertOnPole) || + (vOn[1] > 0 && 1 != nVertOnPole) || + (vOn[2] > 0 && 2 != nVertOnPole)) { double dRightY ; // tengo per buone le coordinate dei vertici che NON sono sul bordo dello spazio parametrico for ( int p = 0 ; p < 3; ++p) { @@ -2503,52 +2569,27 @@ SurfBezier::UnprojectPointFromStm( int nT, const Point3d& ptI, Point3d& ptSP, in } } // devo anche tener conto della possibilità che i lati siano collassati in poli - if ( bIsPole) { - int nInters = -1 ; - for ( int c = 0 ; c < 4 ; ++c) { - if ( ( c == 0 && vInters[0] == vInters[3]) || - ( c != 0 && vInters[c] == vInters[c - 1])){ - nInters = c ; - break ; - } - } - // se non ho trovato il lato su cui ho il polo - if ( nInters == -1) + if ( bIsPole || bNearPole) { + // controllo di aver trovato il lato collassato in polo su cui sta il vertice del triangolo o il punto di intersezione + if ( nEdge == -1) return false ; - // trovo quale vertice è sull'edge di polo - BOOLVECTOR vbOn(3) ; - fill( vbOn.begin(), vbOn.end(), false) ; - for ( int p = 0 ; p < 3; ++p ) { - for ( int c = 0 ; c < 4; ++c) { - for( int i = 0 ; int( m_mCCEdge[c].size()) ; ++i) { - if ( ! m_mCCEdge[c][i]->IsValid()) { - Point3d pt ; - if ( ! m_mCCEdge[c][i]->GetOnlyPoint( pt)) - return false ; - vbOn[p] = vbOn[p] || AreSamePointApprox( pt, vPT[p]) ; - } - else - vbOn[p] = vbOn[p] || m_mCCEdge[c][i]->IsPointOn( vPT[p]) ; - } - } - } // trovo la coordinata giusta da tenere ( x o y a seconda dell'edge) double dRightX, dRightY ; for ( int p = 0 ; p < 3; ++p) { - if ( ! vbOn[p]) { - if ( nInters == 0 || nInters == 2) { + if ( p != nVertOnPole) { + if ( nEdge == 0 || nEdge == 2) { dRightX = vPtPa[p].x ; - dRightY = nInters == 0 ? dParamH : 0 ; + dRightY = nEdge == 0 ? dParamH : 0 ; } - else if ( nInters == 1 || nInters == 3) { - dRightX = nInters == 1 ? 0 : dParamL ; + else if ( nEdge == 1 || nEdge == 3) { + dRightX = nEdge == 1 ? 0 : dParamL ; dRightY = vPtPa[p].y ; } } } // correggo le coordinate del punto sull'edge di polo for ( int p = 0 ; p < 3 ; ++p) { - if ( vbOn[p]) { + if ( p == nVertOnPole) { vPtPa[p].x = dRightX ; vPtPa[p].y = dRightY ; } @@ -2723,6 +2764,8 @@ SurfBezier::UnprojectPoint( const Point3d& pt3D, Point3d& ptParam, const Point3d bool SurfBezier::CalcPoles( void) { + if ( m_vbPole.size() != 0) + return true ; // la funzione identifica se degli edge della superficie non trimmata sono in realtà dei poli for ( int i = 0 ; i < 4 ; ++i) m_vbPole.emplace_back( true) ; @@ -3247,3 +3290,1324 @@ SurfBezier::IsPlanar( void) const // nel dubbio restituisco false return false ; } + +//---------------------------------------------------------------------------- +bool +SurfBezier::CreateByFlatContour( const PolyLine& PL) +{ + Plane3d plPlane ; + double dArea = 0 ; + if ( ! PL.IsClosedAndFlat( plPlane, dArea, EPS_SMALL)) + return false ; + // creo una superficie piana grande come il box della curva nel suo piano e poi la trimmo + // recupero il box + BBox3d bboxContour ; + PL.GetLocalBBox( bboxContour) ; + // inizializzo la superficie come una bezier di primo grado formata da una sola patch + int nDegU = 1, nDegV = 1, nSpanU = 1, nSpanV = 1 ; + bool bRat = false ; + Init( nDegU, nDegV, nSpanU, nSpanV, bRat) ; + // i punti di controllo sono i quattro vertici della bbox ( che è piana) + Point3d ptBL = bboxContour.GetMin() ; + Point3d ptTR = bboxContour.GetMax() ; + SetControlPoint( 0, ptBL) ; + SetControlPoint( 1, Point3d( ptTR.x, ptBL.y)) ; + SetControlPoint( 2, Point3d( ptBL.x, ptTR.y)) ; + SetControlPoint( 3, ptTR) ; + + // calcolo il corrispondente parametrico del contorno + PtrOwner pCCContour( CreateCurveComposite()) ; + if ( IsNull( pCCContour)) + return false ; + pCCContour->FromPolyLine( PL) ; + + // calcolo gli eventuali poli, necessari per poter chiamare le funzioni di unproject + CalcPoles() ; + ICRVCOMPOPOVECTOR vCCOpen ; + ICRVCOMPOPOVECTOR vCCClosed ; + AddCurveCompoToCuts( pCCContour, vCCOpen, vCCClosed) ; + // creo la regione di trim dai loop di trim + PtrOwner pSfrTrim( CreateTrimRegionFromCuts( vCCOpen, vCCClosed)) ; + if ( IsNull( pSfrTrim) || ! pSfrTrim->IsValid()) + return false ; + SetTrimRegion( *pSfrTrim) ; + + if ( plPlane.GetVersN().z < EPS_SMALL) + Invert() ; + + // aggiorno lo stato + m_nStatus = OK ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfBezier::CreateByRegion( const POLYLINEVECTOR& vPL) +{ + // le polyline in input devono essere già ordinate per area + // la prima polyline quindi è il loop più esterno + Plane3d plPlane ; + double dArea = 0 ; + if ( ! vPL[0].IsClosedAndFlat(plPlane, dArea, EPS_SMALL) ) + return false ; + // creo una superficie piana grande come il box della curva nel suo piano e poi la trimmo + // recupero il box + BBox3d bboxContour ; + vPL[0].GetLocalBBox(bboxContour) ; + // inizializzo la superficie come una bezier di primo grado formata da una sola patch + int nDegU = 1, nDegV = 1, nSpanU = 1, nSpanV = 1 ; + bool bRat = false ; + Init( nDegU, nDegV, nSpanU, nSpanV, bRat) ; + // i punti di controllo sono i quattro vertici della bbox ( che è piana) + Point3d ptBL = bboxContour.GetMin() ; + Point3d ptTR = bboxContour.GetMax() ; + SetControlPoint( 0, ptBL) ; + SetControlPoint( 1, Point3d( ptTR.x, ptBL.y)) ; + SetControlPoint( 2, Point3d( ptBL.x, ptTR.y)) ; + SetControlPoint( 3, ptTR) ; + // creo i vettori dei tagli aperti e chiusi + CalcPoles() ; + ICRVCOMPOPOVECTOR vCCOpen ; + ICRVCOMPOPOVECTOR vCCClosed ; + for ( int i = 0 ; i < int( vPL.size()) ; ++i) { + ICurveComposite* pCC( CreateBasicCurveComposite()) ; + pCC->FromPolyLine( vPL[i]) ; + if ( ! AddCurveCompoToCuts( pCC, vCCOpen, vCCClosed)) + return false ; // o metto un continue? + } + // unisco i tagli e creo la regione di trim + PtrOwner pSfrTrim( CreateTrimRegionFromCuts( vCCOpen, vCCClosed)) ; + if ( IsNull( pSfrTrim) || ! pSfrTrim->IsValid()) + return false ; + SetTrimRegion( *pSfrTrim) ; + + if ( plPlane.GetVersN().z < EPS_SMALL) + Invert() ; + + // aggiorno lo stato + m_nStatus = OK ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfBezier::CreateByExtrusion( const ICurve* pCrv, const Vector3d& vtExtr, bool bDeg3orDeg2) +{ + if ( pCrv == nullptr) + return false ; + // verifico che la curva passata sia una bezier semplice o una composita di bezier + if ( pCrv->GetType() != CRV_COMPO && pCrv->GetType() != CRV_BEZIER) + return false ; + // se composita verifico che curve siano con lo stesso grado e uniformi come tipo + + PtrOwner pCC( CreateCurveComposite()) ; + pCC->AddCurve( pCrv->Clone()) ; + bool bRat = false ; + int nDegU = 1 ; + for ( int i = 0 ; i < pCC->GetCurveCount() ; ++i) { + if ( pCC->GetCurve( i)->GetType() != CRV_BEZIER) + return false ; + const ICurveBezier* pCrvBez = static_cast( pCC->GetCurve( i)) ; + if ( i == 0 ) { + bRat = pCrvBez->IsRational() ; + nDegU = pCrvBez->GetDegree() ; + } + else { + if ( pCrvBez->GetDegree() != nDegU || pCrvBez->IsRational() != bRat) + return false ; + } + } + + // riempio la matrice dei punti di controllo + // parto dalla curva che sto estrudendo e mi alzo progressivamente seguendo il vettore vtExtr + int nDegV = bDeg3orDeg2 ? 3 : 2 ; + int nSpanU = pCC->GetCurveCount() ; + int nSpanV = 1 ; + Init(nDegU, nDegV, nSpanU, nSpanV, bRat) ; + + for ( int k = 0 ; k < nSpanU ; ++k) { + const ICurveBezier* pCrvBezier = static_cast( pCC->GetCurve( k)) ; + for ( int i = 0 ; i < nDegU + 1 ; ++i) { + if ( k != 0 && i == 0) + continue ; + Point3d ptCtrl = pCrvBezier->GetControlPoint( i) ; + + int nInd = k * nDegU + i ; + if ( bRat) { + double dW = pCrvBezier->GetControlWeight( i) ; + SetControlPoint( nInd, ptCtrl, dW) ; + } + else + SetControlPoint( nInd, ptCtrl) ; + } + } + + Vector3d vtStep = vtExtr / nDegV ; + // calcolo il vettore di progressione del singolo step per passare dalla curva di partenza alla curva finale + for ( int j = 1 ; j < nDegV + 1 ; ++j) { + for ( int k = 0 ; k < nSpanU ; ++k) { + for ( int i = 0 ; i < nDegU + 1 ; ++i) { + int nIndPrev = ( j - 1) * ( nDegU * nSpanU + 1) + ( k * nDegU + i) ; + Point3d ptCtrl = GetControlPoint( nIndPrev, nullptr) ; + ptCtrl += vtStep ; + int nInd = j * ( nDegU * nSpanU + 1) + k * nDegU + i ; + if ( bRat) { + double dW = GetControlWeight( i, nullptr) ; + SetControlPoint( nInd, ptCtrl, dW) ; + } + else + SetControlPoint( nInd, ptCtrl) ; + } + } + } + + // aggiorno lo stato + m_nStatus = OK ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfBezier::CreateByScrewing( const ICurve* pCurve, const Point3d& ptAx, const Vector3d& vtAx, double dAngRotDeg, double dMove) +{ + // verifico che l'asse di rotazione sia non nullo + if ( vtAx.IsSmall()) + return false ; + // verifico se solo rivoluzione + bool bOnlyRev = ( abs( dMove) < EPS_SMALL) ; + // verifico che l'angolo di rotazione sia significativo e, se solo rivoluzione, non superi un giro + if ( abs( dAngRotDeg) < EPS_ANG_SMALL) + return false ; + if ( bOnlyRev && abs( dAngRotDeg) > ANG_FULL) + dAngRotDeg = _copysign( ANG_FULL, dAngRotDeg) ; + + // se sto facendo una rivoluzione e la curva è piana faccio un controllo + // se la curva attraversa l'asse allora mi fermo + if ( dMove < EPS_SMALL ) { + Plane3d plPlane ; + if ( pCurve->IsFlat(plPlane, false, EPS_SMALL) ) { + PtrOwner pAx( CreateCurveLine()) ; + pAx->Set( ptAx - vtAx * 5e5, ptAx + vtAx * 5e5) ; + IntersCurveCurve icc( *pCurve, *pAx) ; + Point3d ptStart ; pCurve->GetStartPoint( ptStart) ; + Point3d ptEnd ; pCurve->GetStartPoint( ptEnd) ; + for ( int i = 0 ; i < int(icc.GetIntersCount()) ; ++i) { + IntCrvCrvInfo iccInfo ; + icc.GetIntCrvCrvInfo( i, iccInfo) ; + // se è il punto di inizio o di fine va bene e procedo + if ( AreSamePointApprox( ptStart, iccInfo.IciA[0].ptI) || AreSamePointApprox( ptEnd, iccInfo.IciA[0].ptI)) + continue ; + // se la curva oltrepassa l'asse allora mi fermo, se tocca l'asse, ma resta dallo stesso lato, allora vado avanti + if ( iccInfo.IciA->nPrevTy != iccInfo.IciA->nNextTy) + return false ; + } + } + } + + // converto in bezier la curva iniziale + PtrOwner pCrvU ( CreateCurveComposite()) ; + // se la curva è già una bezier singola la tengo, sennò la converto + if ( pCurve->GetType() != CRV_BEZIER) + pCrvU->AddCurve( CurveToBezierCurve( pCurve)) ; + else + pCrvU->AddCurve( pCurve->Clone()) ; + if ( IsNull( pCrvU) || ! pCrvU->IsValid()) + return false ; + int nSpanU = int( pCrvU->GetCurveCount()) ; + int nDegU = ( GetCurveBezier( pCrvU->GetCurve(0)))->GetDegree() ; + + // creo la spirale su cui far la rail della curva ( in questo caso sarà la curva di bezier che delimita il bordo sinistro dello spazio parametrico tra il punto P00 e il punto P01) + PtrOwner pCrvV ( CreateCurveComposite()) ; + // devo trovare un punto che NON stia sull'asse per poter costruire una spirale e sapere quante span in V avrò + DBLVECTOR vdSpiralW ; + bool bFound = false ; + for ( int j = 0 ; j < nSpanU && ! bFound ; ++j) { + const ICurveBezier* pSubCrvBezU = GetCurveBezier( pCrvU->GetCurve( j)) ; + for ( int i = 0 ; i < nDegU + 1 && ! bFound ; ++i) { + Point3d ptCtrlU = pSubCrvBezU->GetControlPoint( i) ; + DistPointLine dpl( ptCtrlU, ptAx, vtAx, 0, false) ; + if ( ! dpl.IsSmall()) { + PtrOwner pSpiral( CreateCurveArc()) ; + pSpiral->SetCPAN( ptAx, ptCtrlU, dAngRotDeg, dMove, vtAx) ; + // converto in bezier la spirale + pCrvV->AddCurve( ArcToBezierCurve( pSpiral,true)) ; + const ICurveBezier* pFirstBez = GetCurveBezier( pCrvV->GetCurve( 0)) ; + int nDeg = pFirstBez->GetDegree() ; // questo è 3 o 2 + for ( int k = 0 ; k < nDeg + 1 ; ++k) + vdSpiralW.push_back( pFirstBez->GetControlWeight( k)) ; + bFound = true ; + } + } + } + if ( ! bFound) + return false ; + + if ( IsNull( pCrvV) || ! pCrvV->IsValid()) + return false ; + int nSpanV = int( pCrvV->GetCurveCount()) ; + int nDegV = ( GetCurveBezier( pCrvV->GetCurve(0)))->GetDegree() ; + // inizializzo la superficie + bool bRat = true ; // perché nella direzione del parametro V ho sicuramente delle razioniali + Init( nDegU, nDegV, nSpanU, nSpanV, bRat) ; + // ora posso settare i punti di controllo + // scorro le curve che compongono la spirale + Point3d ptPrev ; pCrvV->GetStartPoint( ptPrev) ; + Frame3d frRev ; frRev.Set( ptAx, vtAx) ; + PtrOwner pCrvUNew( pCrvU->Clone()) ; + Vector3d vtDirPrev = ptPrev - ptAx ; + vtDirPrev.ToLoc( frRev) ; + + // VERSIONE 1 // c'è qualcosa che non torna, probabilmente dovuto alla razionalità della spirale + //// faccio una rail della curva di base lungo la spirale + //for ( int j = 0 ; j < nSpanV ; ++j) { + // const ICurveBezier* pSubCrvBezV = GetCurveBezier( pCrvV->GetCurve( j)) ; + // for( int z = 0 ; z < nDegV + 1 ; ++z) { + // Point3d ptRef = pSubCrvBezV->GetControlPoint( z) ; + // double dWRef = pSubCrvBezV->GetControlWeight( z) ; + // ptRef *= dWRef ; + // Vector3d vtStepMove = ( ptRef - ptPrev) ; + // pCrvUNew->Translate( vtStepMove) ; + // // ruoto la curva base + // Vector3d vtDirNew = ptRef - ptAx ; + // vtDirNew.ToLoc( frRev) ; + // double dAng = 0 ; + // vtDirPrev.GetAngleXY( vtDirNew, dAng) ; + // pCrvUNew->Rotate( ptRef, vtAx, dAng) ; + // // scorro le curve che compongono la curva principale + // for ( int k = 0 ; k < nSpanU ; ++k ) { + // const ICurveBezier* pSubCrvBezU = GetCurveBezier( pCrvUNew->GetCurve( k)) ; + // // scorro i punti di controllo della sottocurva + // for ( int i = 0 ; i < nDegU + 1 ; ++i) { + // Point3d ptCtrl = pSubCrvBezU->GetControlPoint( i) ; + // ptCtrl /= dWRef ; + // double dW = pSubCrvBezU->GetControlWeight( i) ; + // SetControlPoint( nDegU * k + i, nDegV * j + z, ptCtrl, dW * dWRef) ; + // } + // } + // vtDirPrev = vtDirNew ; + // ptPrev = ptRef ; + // } + //} + + // VERSIONE 2 // funziona + // per ogni punto di controllo della curva di base creo la spirale che rappresenta la screw di quel punto + // scorro le sottocurve della curva di base + for ( int k = 0 ; k < nSpanU ; ++k ) { + const ICurveBezier* pSubCrvBezU = GetCurveBezier( pCrvUNew->GetCurve( k)) ; + //scorro i punti di controllo + for ( int i = 0 ; i < nDegU + 1 ; ++i) { + if ( k != 0 && i == 0) + continue ; + Point3d ptCtrlU = pSubCrvBezU->GetControlPoint( i) ; + double dWU = pSubCrvBezU->GetControlWeight( i) ; + + PtrOwner pCrvV( CreateCurveComposite()) ; + // verifico se il punto di controllo sta sull'asse + // in tal caso anziché una spirale creo semplicemente una linea lungo l'asse + DistPointLine dpl( ptCtrlU, ptAx, vtAx, 0, false) ; + if ( ! dpl.IsSmall()) { + // creo la spirale e la converto in bezier + PtrOwner pSpiral( CreateCurveArc()) ; + pSpiral->SetCPAN( ptAx, ptCtrlU, dAngRotDeg, dMove, vtAx) ; + ICurve* pSpiralBezier( ArcToBezierCurve( pSpiral)) ; // converto in curva bezier di grado 3 perché l'arco è una spirale + pCrvV->AddCurve( pSpiralBezier) ; + } + else if ( dMove > EPS_SMALL){ + // creo un segmento in forma bezier con il giusto numero di span + PtrOwner pCL( CreateBasicCurveLine()) ; + pCL->Set( ptCtrlU, ptCtrlU + vtAx * dMove) ; + double dStep = 1. / nSpanV ; + for ( int j = 0 ; j < nSpanV ; ++j) { + PtrOwner pCLSingleSpan( GetCurveLine( pCL->CopyParamRange( j * dStep, ( j + 1) * dStep))) ; + PtrOwner pCrvBezForm( LineToBezierCurve( pCLSingleSpan,true)) ; + // prima di aggiungere le curve alla composito setto i pesi + for ( int z = 0 ; z < pCrvBezForm->GetDegree() + 1 ; ++z) + pCrvBezForm->SetControlWeight( z, vdSpiralW[z]) ; + pCrvV->AddCurve( Release( pCrvBezForm)) ; + } + } + // se sto facendo una rivoluzione ( dMove == 0) e ho un punto di controllo sull'asse allora ho un polo + // devo aggiungere sempre lo stesso punto per tutta la riga della matrice dei punti di controllo, con i pesi giusti + else { + PtrOwner pCrvBezier( CreateCurveBezier()) ; + pCrvBezier->Init( nDegV, bRat) ; + for ( int z = 0 ; z < nDegV + 1 ; ++z) { + pCrvBezier->SetControlPoint( z, ptCtrlU, vdSpiralW[z]) ; + } + for ( int j = 0 ; j < nSpanV ; ++j) + pCrvV->AddCurve( pCrvBezier->Clone()) ; + } + + // aggiungo i punti di controllo + // scorro le sottocurve della spirale + for ( int j = 0 ; j < nSpanV ; ++j) { + const ICurveBezier* pSubCrvBezV = GetCurveBezier( pCrvV->GetCurve( j)) ; + // scorro i punti di controllo + for( int z = 0 ; z < nDegV + 1 ; ++z) { + double dWV = pSubCrvBezV->GetControlWeight( z) ; + Point3d ptCtrlV = pSubCrvBezV->GetControlPoint( z) ; + SetControlPoint( nDegU * k + i, nDegV * j + z, ptCtrlV, dWU * dWV) ; + } + } + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfBezier::CreateByPointCurve( const Point3d& pt, const ICurve* pCurve) +{ + // converto in bezier la curva iniziale + PtrOwner pCrvU ( CreateCurveComposite()) ; + // se la curva è già una bezier singola la tengo, sennò la converto + if ( pCurve->GetType() != CRV_BEZIER) + pCrvU->AddCurve( CurveToBezierCurve( pCurve)) ; + else + pCrvU->AddCurve( pCurve->Clone()) ; + if ( IsNull( pCrvU) || ! pCrvU->IsValid()) + return false ; + // recupero span e grado nel parametro U + int nSpanU = int( pCrvU->GetCurveCount()) ; + int nDegU = ( GetCurveBezier( pCrvU->GetCurve(0)))->GetDegree() ; + bool bRat = (GetCurveBezier( pCrvU->GetCurve(0)))->IsRational() ; + // in V decido che la funzione è una patch di grado 1 + int nSpanV = 1 ; + int nDegV = 1 ; + // inizializzo la curva e aggiungo i punti di controllo + Init( nDegU, nDegV, nSpanU, nSpanV, bRat) ; + // scorro le patch nel parametro U + for ( int k = 0 ; k < nSpanU ; ++k) { + const ICurveBezier* pSubCrvU = GetCurveBezier( pCrvU->GetCurve( k)) ; + // scorro i punti di controllo in U + for ( int i = 0 ; i < nDegU + 1 ; ++i ) { + + double dW = pSubCrvU->GetControlWeight( i) ; + Point3d ptCtrl = i == 0 ? pSubCrvU->GetControlPoint( i) : pt ; + // scorro sul parametro V // do per scontato di avere una patch di grado 1 ( quindi nel parametro V ho solo due punti) + for ( int j = 0 ; j < nDegV + 1 ; ++j) { + if ( ! bRat) + SetControlPoint( nDegU * k + i, j, ptCtrl) ; + else + SetControlPoint( nDegU * k + i, j , ptCtrl, dW) ; + } + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfBezier::CreateByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, int nRuledType) +{ + // converto in bezier la curva iniziale + PtrOwner pCrvU0 ( CreateCurveComposite()) ; + // se la curva è già una bezier singola la tengo, sennò la converto + if ( pCurve0->GetType() != CRV_BEZIER) { + // se è una compo controllo che siano già tutte bezier + bool bAlreadyBez = true ; + if ( pCurve0->GetType() == CRV_COMPO) { + const ICurveComposite* pCC0 = GetBasicCurveComposite( pCurve0) ; + for ( int i = 0 ; i < pCC0->GetCurveCount() ; ++i) { + if ( pCC0->GetCurve( i)->GetType() != CRV_BEZIER) { + bAlreadyBez = false ; + break ; + } + } + } + else + bAlreadyBez = false ; + if ( ! bAlreadyBez) + pCrvU0->AddCurve( CurveToBezierCurve( pCurve0)) ; + else + pCrvU0->AddCurve( pCurve0->Clone()) ; + } + else + pCrvU0->AddCurve( pCurve0->Clone()) ; + if ( IsNull( pCrvU0) || ! pCrvU0->IsValid()) + return false ; + // recupero span e grado nel parametro U + int nSpanU0 = int( pCrvU0->GetCurveCount()) ; + int nDegU0 = ( GetCurveBezier( pCrvU0->GetCurve(0)))->GetDegree() ; + bool bRat0 = (GetCurveBezier( pCrvU0->GetCurve(0)))->IsRational() ; + // se la curva è già una bezier singola la tengo, sennò la converto + PtrOwner pCrvU1 ( CreateCurveComposite()) ; + // se la curva è già una bezier singola la tengo, sennò la converto + if ( pCurve1->GetType() != CRV_BEZIER) { + // se è una compo controllo che siano già tutte bezier + bool bAlreadyBez = true ; + if ( pCurve1->GetType() == CRV_COMPO) { + const ICurveComposite* pCC1 = GetBasicCurveComposite( pCurve1) ; + for ( int i = 0 ; i < pCC1->GetCurveCount() ; ++i) { + if ( pCC1->GetCurve( i)->GetType() != CRV_BEZIER) { + bAlreadyBez = false ; + break ; + } + } + } + else + bAlreadyBez = false ; + if ( ! bAlreadyBez) + pCrvU1->AddCurve( CurveToBezierCurve( pCurve1)) ; + else + pCrvU1->AddCurve( pCurve1->Clone()) ; + } + else + pCrvU1->AddCurve( pCurve1->Clone()) ; + // recupero span e grado nel parametro U + int nSpanU1 = int( pCrvU1->GetCurveCount()) ; + int nDegU1 = ( GetCurveBezier( pCrvU1->GetCurve(0)))->GetDegree() ; + bool bRat1 = (GetCurveBezier( pCrvU1->GetCurve(0)))->IsRational() ; + //// se non ho lo stesso numero di span nelle due curve devo capire come gestire il caso. + //// per il momento non implementato + //if ( nSpanU0 != nSpanU1) + // return nullptr ; + // se le due curve hanno grado diverso allora aumento il grado di quella con grado inferiore + if ( nDegU0 != nDegU1) { + while ( nDegU0 < nDegU1) { + ICurveComposite* pCC( CreateCurveComposite()) ; + for( int k = 0 ; k < nSpanU0 ; ++k) + pCC->AddCurve( BezierIncreaseDegree( GetCurveBezier( pCrvU0->GetCurve( k)))) ; + ++nDegU0 ; + pCrvU0.Set( pCC) ; + } + while ( nDegU0 > nDegU1) { + ICurveComposite* pCC( CreateCurveComposite()) ; + for( int k = 0 ; k < nSpanU0 ; ++k) + pCC->AddCurve( BezierIncreaseDegree( GetCurveBezier( pCrvU1->GetCurve( k)))) ; + ++nDegU1 ; + pCrvU1.Set( pCC) ; + } + } + // omogenizzo la razionalità + if ( bRat0 != bRat1) { + if ( ! bRat0) { + ICurveComposite* pCC( CreateCurveComposite()) ; + for ( int k = 0 ; k < nSpanU0 ; ++k) { + ICurveBezier* pCrvBez = GetCurveBezier( pCrvU0->GetCurve( k)->Clone()) ; + pCrvBez->MakeRational() ; + pCC->AddCurve( pCrvBez) ; + } + pCrvU0.Set( pCC) ; + bRat0 = true ; + } + if ( ! bRat1) { + ICurveComposite* pCC( CreateCurveComposite()) ; + for ( int k = 0 ; k < nSpanU1 ; ++k) { + ICurveBezier* pCrvBez = GetCurveBezier( pCrvU1->GetCurve( k)->Clone()) ; + pCrvBez->MakeRational() ; + pCC->AddCurve( pCrvBez) ; + } + pCrvU1.Set( pCC) ; + bRat1 = true ; + } + } + + if ( nDegU0 != nDegU1) + return false ; + + int nDegU = nDegU0 ; + + // in V decido che la funzione è una patch di grado 1 + int nSpanV = 1 ; + int nDegV = 1 ; + + //// se le due curve hanno lo stesso numero di span semplicemente creo la superficie // NON BASTA!! DEVO COMUNQUE TENER CONTO DELLA MODALITA' RICHIESTA + //if ( nSpanU0 == nSpanU1) { + // // inizializzo la curva e aggiungo i punti di controllo + // Init( nDegU0, nDegV, nSpanU0, nSpanV, bRat0) ; + // // scorro sul parametro V // do per scontato di avere una patch di grado 1 ( quindi nel parametro V ho solo due punti) + // for ( int j = 0 ; j < nDegV + 1 ; ++j) { + // // scorro le patch nel parametro U + // for ( int k = 0 ; k < nSpanU0 ; ++k) { + // const ICurveBezier* pSubCrvU = GetCurveBezier( j == 0 ? pCrvU0->GetCurve( k) : pCrvU1->GetCurve( k)) ; + // // scorro i punti di controllo in U + // for ( int i = 0 ; i < nDegU0 + 1 ; ++i ) { + // double dW = pSubCrvU->GetControlWeight( i) ; + // Point3d ptCtrl = pSubCrvU->GetControlPoint( i) ; + // if ( ! bRat0) + // SetControlPoint( nDegU0 * k + i, j, ptCtrl) ; + // else + // SetControlPoint( nDegU0 * k + i, j , ptCtrl, dW) ; + // } + // } + // } + //} + + // ho bisogno della rappresentazione delle curve in forma di polyline, con inizio e fine delle sottocurve + PolyLine plU0, plU1 ; + int nCount0 = 0 ; + DBLVECTOR vdW0 ; + for ( int k = 0 ; k < nSpanU0 ; ++k ) { + const ICurveBezier* pSubCrv0 = GetCurveBezier( pCrvU0->GetCurve( k)) ; + for ( int i = 0 ; i < nDegU + 1 ; ++i ) { + if( i != nDegU && !( i == 0 && k == 0)) + continue ; + Point3d ptCtrl = pSubCrv0->GetControlPoint( i) ; + if ( bRat0) + vdW0.push_back( pSubCrv0->GetControlWeight( i)) ; + // aggiungo alla polyline solo gli estremi delle sottocurve ( senza ripetizioni) + if ( plU0.AddUPoint( nCount0, ptCtrl)) + ++ nCount0 ; + } + } + int nCount1 = 0 ; + DBLVECTOR vdW1 ; + for ( int k = 0 ; k < nSpanU1 ; ++k ) { + const ICurveBezier* pSubCrv1 = GetCurveBezier( pCrvU1->GetCurve( k)) ; + for ( int i = 0 ; i < nDegU1 + 1 ; ++i ) { + if( i != nDegU && !( i == 0 && k == 0)) + continue ; + Point3d ptCtrl = pSubCrv1->GetControlPoint( i) ; + if ( bRat1) + vdW1.push_back( pSubCrv1->GetControlWeight( i)) ; + if ( plU1.AddUPoint( nCount1, ptCtrl)) + ++ nCount1 ; + } + } + + // verifico ci siano almeno due punti diversi per curva + if ( ( plU0.IsClosed() && plU0.GetPointNbr() < 3) || plU0.GetPointNbr() < 2) + return false ; + if ( ( plU1.IsClosed() && plU1.GetPointNbr() < 3) || plU1.GetPointNbr() < 2) + return false ; + + // determino il numero di span che avrà la superficie basandomi sulla curva con più sottocurve + int nSpanU = max( nSpanU0, nSpanU1) ; + // punti per curva + int nLastPoint = nDegU + 1 ; + // definisco la razionalità + bool bRat = bRat0 && bRat1 ; + int nSecondRowInd = nDegU * nSpanU + 1 ; + + // se sono chiuse devo controllare che gli start siano il più allineati possibile, se non lo sono cambio gli start + ChangeStartForClosed( plU0, plU1, pCrvU0, pCrvU1) ; + + // se sto usando la ISOPARM o la MINDIST semplice allora collego più span di una curva allo stesso punto + if ( nRuledType == RLT_B_MINDIST) { + // creo le liste di punti per le isoparametriche in U + PNTIVECTOR vPnt0Match, vPnt1Match ; + bool bCommonPoint = false ; + + AssociatePolyLinesMinDistPoints( plU0, plU1, vPnt0Match, vPnt1Match, bCommonPoint) ; + // devo contare il numero di ripetizioni dei match nel mezzo delle curve, perché aumentano il numero di span della superficie!! + int nRep0 = 0 ; + int nIndMatch = 0 ; + int nIndMatchNext = 0 ; + int nRep1 = int( vPnt1Match.size() - 1) - vPnt0Match.back().second ; + for ( int i = 0 ; i < int( vPnt0Match.size() - 1) ; ++i) { + nIndMatch = vPnt0Match[i].second ; + nIndMatchNext = vPnt0Match[i+1].second ; + if ( nIndMatch != nIndMatchNext) + nRep1 += nIndMatchNext - nIndMatch - 1 ; + if ( nIndMatch == nIndMatchNext) + ++nRep0 ; + } + // reinizializzo la superficie con il nuovo numero di span in U + nSpanU = nSpanU0 + nRep1 ; + if ( nSpanU < max(nSpanU0, nSpanU1)) + nSpanU = max(nSpanU0, nSpanU1) ; + nSecondRowInd = nDegU * nSpanU + 1 ; + Init( nDegU, nDegV, nSpanU, nSpanV, bRat) ; + + // numero di span aggiunte su U0 e U1 + nCount0 = 0 ; + nCount1 = 0 ; + + // scorro gli estremi delle sottocurve della curva U0 + for ( int i = 0 ; i < int( vPnt0Match.size() - 1) ; ++i) { + nIndMatch = vPnt0Match[i].second ; + nIndMatchNext = vPnt0Match[i+1].second ; + const ICurveBezier* pSubCrv0 ; + if ( nIndMatch == nIndMatchNext) { + pSubCrv0 = GetCurveBezier( pCrvU0->GetCurve( i)) ; + for ( int j = nCount0 == 0 ? 0 : 1 ; j < nLastPoint ; ++j) { + if ( ! bRat0) + SetControlPoint( nCount0 * nDegU + j, pSubCrv0->GetControlPoint( j)) ; + else + SetControlPoint( nCount0 * nDegU + j, pSubCrv0->GetControlPoint( j), pSubCrv0->GetControlWeight( j)) ; + } + ++ nCount0 ; + // ripeto l'ultimo punto aggiunto alla riga U1 della superificie + int nInd = nIndMatch > 0 ? nIndMatch - 1 : 0 ; + const ICurveBezier* pSubCrv0 = GetCurveBezier( pCrvU1->GetCurve( nInd)) ; + for ( int j = nCount1 == 0 ? 0 : 1 ; j < nLastPoint ; ++j) { + int nPoint = nCount1 == 0 ? 0 : nDegU ; + if ( ! bRat0) + SetControlPoint( nSecondRowInd + nCount1 * nDegU + j, pSubCrv0->GetControlPoint( nPoint)) ; + else + SetControlPoint( nSecondRowInd + nCount1 * nDegU + j, pSubCrv0->GetControlPoint( nPoint), pSubCrv0->GetControlWeight( nPoint)) ; + } + ++nCount1 ; + } + else { + // qui devo capire se aggiungere la nuova sottocurva prima o dopo la ripetizione dei punti + // se il match del punto della U1 è uguale al punto a cui ero arrivato sulla U0 allora prima aggiungo la ripetizione di punti + // se invece il match è più avanti allora aggiuno prima la curva e poi la ripetzione di punti + bool bSubCurveAddedFirst = true ; + for ( int z = vPnt0Match[i].second ; z <= vPnt0Match[i+1].second ; ++z) + bSubCurveAddedFirst = bSubCurveAddedFirst && vPnt1Match[z].second != i ; + + if( bSubCurveAddedFirst) { + // aggiungo una sottocurva dalla curva U0 + pSubCrv0 = GetCurveBezier( pCrvU0->GetCurve( i)) ; + for ( int j = nCount0 == 0 ? 0 : 1 ; j < nLastPoint ; ++j) { + if ( ! bRat0) + SetControlPoint( nCount0 * nDegU + j, pSubCrv0->GetControlPoint( j)) ; + else + SetControlPoint( nCount0 * nDegU + j, pSubCrv0->GetControlPoint( j), pSubCrv0->GetControlWeight( j)) ; + } + ++ nCount0 ; + } + + // ripeto l'ultimo punto aggiunto per il numero di curve balzate - 1 della curva U1 + for( int k = 0 ; k < nIndMatchNext - nIndMatch - 1 ; ++k) { + pSubCrv0 = GetCurveBezier( pCrvU0->GetCurve( i != 0 ? i - 1 : i)) ; + for ( int j = nCount0 == 0 ? 0 : 1 ; j < nLastPoint ; ++j) { + int nPoint = i == 0 && ! bSubCurveAddedFirst ? 0 : nDegU ; + if ( ! bRat0) + SetControlPoint( nCount0 * nDegU + j, pSubCrv0->GetControlPoint( nPoint)) ; + else + SetControlPoint( nCount0 * nDegU + j, pSubCrv0->GetControlPoint( nPoint), pSubCrv0->GetControlWeight( nPoint)) ; + } + ++ nCount0 ; + } + // se non l'ho già aggiunta prima aggiungo una sottocurva della U0 + if( ! bSubCurveAddedFirst) { + pSubCrv0 = GetCurveBezier( pCrvU0->GetCurve( i)) ; + for ( int j = nCount0 == 0 ? 0 : 1 ; j < nLastPoint ; ++j) { + if ( ! bRat0) + SetControlPoint( nCount0 * nDegU + j, pSubCrv0->GetControlPoint( j)) ; + else + SetControlPoint( nCount0 * nDegU + j, pSubCrv0->GetControlPoint( j), pSubCrv0->GetControlWeight( j)) ; + } + ++ nCount0 ; + } + + + // aggiungo tutte le sottocurve che ho balzato della curva U1 + for( int k = 0 ; k < nIndMatchNext - nIndMatch ; ++k) { + pSubCrv0 = GetCurveBezier( pCrvU1->GetCurve( nIndMatch + k)) ; + for ( int j = nCount1 == 0 ? 0 : 1 ; j < nLastPoint ; ++j ) { + if ( ! bRat) + SetControlPoint( nSecondRowInd + nCount1 * nDegU + j, pSubCrv0->GetControlPoint( j)) ; + else + SetControlPoint( nSecondRowInd + nCount1 * nDegU + j, pSubCrv0->GetControlPoint( j), pSubCrv0->GetControlWeight( j)) ; + } + ++ nCount1 ; + } + } + } + + //controllo se ho aggiunto tutti i punti della curva U1 + if ( vPnt0Match.back().second != nSpanU1) { + // riaggiungo l'ultimo punto della U0 + const ICurveBezier* pSubCrv0 = GetCurveBezier( pCrvU0->GetCurve( nSpanU0 - 1)) ; + int nPoint = nDegU ; + while( nCount0 < nSpanU) { + for ( int j = 1 ; j < nLastPoint ; ++j) { + if ( ! bRat0) + SetControlPoint( nCount0 * nDegU + j, pSubCrv0->GetControlPoint( nPoint)) ; + else + SetControlPoint( nCount0 * nDegU + j, pSubCrv0->GetControlPoint( nPoint), pSubCrv0->GetControlWeight( nPoint)) ; + } + ++ nCount0 ; + } + + // aggiungo le restanti sottocurve della curva U1 + int nCrv1 = vPnt0Match.back().second ; + while( nCrv1 < nSpanU1) { + const ICurveBezier* pSubCrv1 = GetCurveBezier( pCrvU1->GetCurve( nCrv1)) ; + for ( int j = 1 ; j < nLastPoint ; ++j) { + if ( ! bRat1) + SetControlPoint( nSecondRowInd + nCount1 * nDegU + j, pSubCrv1->GetControlPoint( j)) ; + else + SetControlPoint( nSecondRowInd + nCount1 * nDegU + j, pSubCrv1->GetControlPoint( j), pSubCrv1->GetControlWeight( j)) ; + } + ++ nCount1 ; + ++ nCrv1 ; + } + } + } + else if ( nRuledType == RLT_B_ISOPAR) { + // inizializzo la superficie + Init( nDegU, nDegV, nSpanU, nSpanV, bRat) ; + Point3d ptP0Start ; pCrvU0->GetStartPoint( ptP0Start) ; + Point3d ptP1Start ; pCrvU1->GetStartPoint( ptP1Start) ; + // setto i primi due punti delle righe + nCount0 = 0 ; // sottocurva su pCrvU0 + if ( ! bRat) + SetControlPoint( 0, ptP0Start) ; + else + SetControlPoint( 0, ptP0Start, vdW0[0]) ; + nCount1 = 0 ; // sottocurva su pCrvU1 + if ( ! bRat) + SetControlPoint( nSecondRowInd, ptP1Start) ; + else + SetControlPoint( nSecondRowInd, ptP1Start, vdW1[0]) ; + + INTVECTOR vMatch ; + int nLong = 0 ; + // prendo la polyline con più punti e scelgo a quali punti dell'altra polyline vanno associati + FindMatchByParam( plU0, plU1, vMatch,nLong) ; + + for( int i = 0 ; i < int( vMatch.size() - 1) ; ++i) { + int nCount = i ; // span in U aggiunte + // scorro i punti della polyline più lunga + // se il punto corrente e il successivo sono associati allo stesso punto dell'altra polyline + // allora devo aggiungere la sottocurva della curva più lunga e ripetere l'ultimo punto aggiunto dell'altra polyline + // se il corrente e il successivo sono associati a punti successivi + // allora devo aggiungere una sottocurva per ognuna delle due curve + if ( vMatch[i] == vMatch[i+1]) { + // se la curva più lunga è la prima + if ( nLong == 0) { + // aggiungo la curva sulla prima riga + for ( int i = 1 ; i < nLastPoint ; ++i) { + const ICurveBezier* pSubCrv0 = GetCurveBezier( pCrvU0->GetCurve( nCount0)) ; + Point3d ptCtrl = pSubCrv0->GetControlPoint( i) ; + if ( ! bRat) + SetControlPoint( nCount * nDegU + i, ptCtrl) ; + else { + double dW = pSubCrv0->GetControlWeight( i) ; + SetControlPoint( nCount * nDegU + i, ptCtrl, dW) ; + } + } + ++ nCount0 ; + // riaggungo lo start point sulla seconda riga + // o end point se ho già aggiunto tutte le curve + int nInd = nCount1 < nSpanU1 ? 0 : nDegU ; + int nSubCrv = nCount1 < nSpanU1 ? nCount1 : nSpanU1 - 1 ; + const ICurveBezier* pSubCrv1 = GetCurveBezier( pCrvU1->GetCurve( nSubCrv)) ; + Point3d ptCtrl = pSubCrv1->GetControlPoint( nInd) ; + for ( int i = 1 ; i < nLastPoint ; ++i) { + if ( ! bRat) + SetControlPoint( nSecondRowInd + nCount * nDegU + i, ptCtrl) ; + else { + double dW = pSubCrv1->GetControlWeight( i) ; + SetControlPoint( nSecondRowInd + nCount * nDegU + i, ptCtrl, dW) ; + } + } + } + else { + // aggiungo la curva sulla seconda riga + for ( int i = 1 ; i < nLastPoint ; ++i) { + const ICurveBezier* pSubCrv1 = GetCurveBezier( pCrvU1->GetCurve( nCount1)) ; + Point3d ptCtrl = pSubCrv1->GetControlPoint( i) ; + if ( ! bRat) + SetControlPoint( nSecondRowInd + nCount * nDegU + i, ptCtrl) ; + else { + double dW = pSubCrv1->GetControlWeight( i) ; + SetControlPoint( nSecondRowInd + nCount * nDegU + i, ptCtrl, dW) ; + } + } + ++ nCount1 ; + // riaggungo lo start point sulla prima riga + // o end point se ho già aggiunto tutte le curve + int nInd = nCount0 < nSpanU0 ? 0 : nDegU ; + int nSubCrv = nCount0 < nSpanU0 ? nCount0 : nSpanU0 - 1 ; + const ICurveBezier* pSubCrv0 = GetCurveBezier( pCrvU0->GetCurve( nSubCrv)) ; + Point3d ptCtrl = pSubCrv0->GetControlPoint( nInd) ; + for ( int i = 1 ; i < nLastPoint ; ++i) { + if ( ! bRat) + SetControlPoint( nCount * nDegU + i, ptCtrl) ; + else { + double dW = pSubCrv0->GetControlWeight( i) ; + SetControlPoint( nCount * nDegU + i, ptCtrl, dW) ; + } + } + } + } + // altrimenti aggiungo una sottocurva da entrambe le curve + else { + // aggiungo la curva sulla prima riga + for ( int i = 1 ; i < nLastPoint ; ++i) { + const ICurveBezier* pSubCrv0 = GetCurveBezier( pCrvU0->GetCurve( nCount0)) ; + Point3d ptCtrl = pSubCrv0->GetControlPoint( i) ; + if ( ! bRat) + SetControlPoint( nCount * nDegU + i, ptCtrl) ; + else { + double dW = pSubCrv0->GetControlWeight( i) ; + SetControlPoint( nCount * nDegU + i, ptCtrl, dW) ; + } + } + ++ nCount0 ; + // aggiungo la curva sulla seconda riga + for ( int i = 1 ; i < nLastPoint ; ++i) { + const ICurveBezier* pSubCrv1 = GetCurveBezier( pCrvU1->GetCurve( nCount1)) ; + Point3d ptCtrl = pSubCrv1->GetControlPoint( i) ; + if ( ! bRat) + SetControlPoint( nSecondRowInd + nCount * nDegU + i, ptCtrl) ; + else { + double dW = pSubCrv1->GetControlWeight( i) ; + SetControlPoint( nSecondRowInd + nCount * nDegU + i, ptCtrl, dW) ; + } + } + ++ nCount1 ; + } + } + } + // spezzo le curve di bezier dove è necessario aggiungere dei punti + else if ( nRuledType == RLT_B_MINDIST_PLUS ) { + // scorro la prima curva e per ogni punto di fine sottocurva cerco il minDistPoint sull'altra curva + // in quel punto la curva verrà spezzata, a meno che non si trovi una joint già sufficientemente vicina + + // prima trovo le associazioni senza aggiunte di punti + Point3d ptP1 ; plU1.GetFirstPoint( ptP1) ; + vector> vMatch1 ; + while ( plU1.GetNextPoint( ptP1, true)) { + DistPointCurve dpc( ptP1, *pCrvU0, false) ; + int nFlag = 0 ; + double dParam ; dpc.GetParamAtMinDistPoint( 0, dParam, nFlag) ; + Point3d ptJoint ; dpc.GetMinDistPoint( 0, ptJoint, nFlag) ; + vMatch1.push_back( pair( ptJoint, dParam)) ; + } + + int nAtStart1 = 0 ; // match ripetuti dalla curva U0 allo start della curva U1 + int nAtEnd1 = 0 ; + Point3d ptP0 ; plU0.GetFirstPoint( ptP0) ; + int c = 0 ; + int nCrvCount = 0 ; + int nRep0 = 0 ; // match interni consecutivi uguali di punti della curva U0 con punti della curva U1 + int nRep1 = 0 ; + double dLastParamMatch = 0 ; + Point3d ptLastPointMatch = ptP0 ; + BOOLVECTOR vbRep0( nSpanU0) ; + INTVECTOR vnAddedOrNextIsRep0 ; // 0 non Rep, 1 Rep, 2 Next is Rep ; + DBLVECTOR vdSplit0 ; + DBLVECTOR vdMatch0 ; + fill( vbRep0.begin(), vbRep0.end(), false) ; + while ( plU0.GetNextPoint( ptP0, true)) { + // devo salvarmi se matcho più punti con lo start o l'end della curva totale + DistPointCurve dpc( ptP0, *pCrvU1, false) ; + int nFlag = 0 ; + double dParam ; dpc.GetParamAtMinDistPoint( 0, dParam, nFlag) ; + Point3d ptJoint ; dpc.GetMinDistPoint( 0, ptJoint, nFlag) ; + vdMatch0.push_back( dParam) ; + if ( dParam < EPS_SMALL ) { + ++nAtStart1 ; + vbRep0[c] = true ; + ++c ; + continue ; + } + else if ( dParam > nSpanU1 - EPS_SMALL ) { + vbRep0[c] = nAtEnd1 == 0 ? false : true ; + vbRep0.back() = true ; + ++ nAtEnd1 ; + ++c ; + continue ; + } + if ( dParam <= dLastParamMatch || AreSamePointApprox( ptJoint, ptLastPointMatch)) { + dParam = dLastParamMatch ; + vbRep0[c] = true ; + ++ nRep0 ; + ++c ; + continue ; + } + else { + dLastParamMatch = dParam ; + ptLastPointMatch = ptJoint ; + nCrvCount = pCrvU1->GetCurveCount() ; + // se sono già troppo vicino ad un split esistente allora non faccio nulla + if ( abs(dParam - round( dParam)) < 100 * EPS_PARAM) { + ++c ; + continue ; + } + vdSplit0.push_back( dParam) ; + // verifico se ho un match per questo punto + // in tal caso vuol dire che sto creando una ripetizione nRep1 + int nCase = 0 ; + for ( int j = 0 ; j < int( vMatch1.size()) ; ++j) { + if ( abs(vMatch1[j].second - (c + 1)) < EPS_SMALL) { + // devo però verificare che non ci sia un match successivo, perché in quel caso non ho una ripetizione + bool bFoundMatch = false ; + for ( int z = int( vMatch1[j].second) ; z < int( vdMatch0.size()) ; ++z) { + if ( abs( vdMatch0[z] - ( j + 1 )) < EPS_SMALL ) { + bFoundMatch = true ; + break ; + } + } + + if ( ! bFoundMatch) { + ++nRep1 ; + // capisco se il punto è rep o se lo è il suo successivo + if( j + 1 < dParam) + nCase = 1 ; + else + nCase = 2 ; + } + break ; + } + } + vnAddedOrNextIsRep0.push_back( nCase) ; + } + ++c ; + } + int nAtStart0 = 0 ; + int nAtEnd0 = 0 ; + plU1.GetFirstPoint( ptP1) ; + c = 0 ; + dLastParamMatch = 0 ; + ptLastPointMatch = ptP1 ; + INTVECTOR vnAddedOrNextIsRep1 ; // 0 non Rep, 1 Rep, 2 Next is Rep ; + DBLVECTOR vdSplit1 ; + BOOLVECTOR vbRep1( plU1.GetPointNbr() - 1) ; + fill( vbRep1.begin(), vbRep1.end(), false) ; + while ( plU1.GetNextPoint( ptP1, true)) { + DistPointCurve dpc( ptP1, *pCrvU0, false) ; + int nFlag = 0 ; + double dParam ; dpc.GetParamAtMinDistPoint( 0, dParam, nFlag) ; + Point3d ptJoint ; dpc.GetMinDistPoint( 0, ptJoint, nFlag) ; + if ( dParam < EPS_SMALL ) { + ++nAtStart0 ; + vbRep1[c] = true ; + ++c ; + continue ; + } + else if ( dParam > nSpanU0 - EPS_SMALL ) { + vbRep1[c] = nAtEnd0 == 0 ? false : true ; + vbRep1.back() = true ; + ++ nAtEnd0 ; + ++c ; + continue ; + } + if ( dParam <= dLastParamMatch || AreSamePointApprox( ptJoint, ptLastPointMatch)) { + dParam = dLastParamMatch ; + vbRep1[c] = true ; + ++ nRep1 ; + ++c ; + continue ; + } + else { + dLastParamMatch = dParam ; + ptLastPointMatch = ptJoint ; + nCrvCount = pCrvU0->GetCurveCount() ; + //se sono troppo vicino ad uno split esistente allora non faccio nulla + if( abs(dParam - round( dParam)) < 100 * EPS_PARAM) { + ++c ; + continue ; + } + vdSplit1.push_back( dParam) ; + // verifico se ho un match per questo punto + // in tal caso vuol dire che sto creando una ripetizione nRep0 + int nCase = 0 ; + for ( int j = 0 ; j < int( vdMatch0.size()) ; ++j) { + if ( abs(vdMatch0[j] - (c + 1)) < EPS_SMALL) { + // devo però verificare che non ci sia un match successivo, perché in quel caso non ho una ripetizione + bool bFoundMatch = false ; + for ( int z = int( vdMatch0[j]) ; z < int( vMatch1.size()) ; ++z) { + if ( abs( vMatch1[z].second - ( j + 1 )) < EPS_SMALL ) { + bFoundMatch = true ; + break ; + } + } + + if ( ! bFoundMatch) { + ++nRep0 ; + // capisco se il punto è rep o se lo è il suo successivo + if( j + 1 < dParam) + nCase = 1 ; + else + nCase = 2 ; + } + break ; + } + } + vnAddedOrNextIsRep1.push_back( nCase) ; + } + ++c ; + } + + // applico effettivamente gli split e aggiungo gli elementi ai vettori vbRep + int nUnit = 0 ; + if ( ! vdSplit0.empty()) + nUnit = int( vdSplit0.back()) ; + for ( int z = int( vdSplit0.size() - 1) ; z >= 0 ; --z) { + double dSplit = vdSplit0[z] ; + int nSplit = int( dSplit) ; + // se sto cercando di fare uno split sulla stessa curva che ho già splittato al passaggio precedente allora devo + // riscalare + if ( nSplit == nUnit && z < int( vdSplit0.size() - 1)) { + dSplit = nSplit + ( dSplit - nSplit) / (vdSplit0[z+1] - nSplit); + } + nUnit = nSplit ; + pCrvU1->AddJoint( dSplit) ; + switch( vnAddedOrNextIsRep0[z]) { + case 0 : if( vbRep1[nSplit]) + ++ nRep1 ; + // di default aggiungerei false, ma se il successivo è già un Rep allora anche questo deve esserlo + vbRep1.insert( vbRep1.begin() + nSplit, vbRep1[nSplit]) ; break ; + case 1 : vbRep1.insert( vbRep1.begin() + nSplit, true) ; break ; + case 2 : if ( vbRep1[nSplit]) + --nRep1 ; + else + vbRep1[nSplit] = true ; + vbRep1.insert( vbRep1.begin() + nSplit, false) ; break ; + } + } + if( ! vdSplit1.empty()) + nUnit = int( vdSplit1.back()) ; + for ( int z = int( vdSplit1.size() - 1) ; z >= 0 ; --z) { + double dSplit = vdSplit1[z] ; + int nSplit = int( dSplit) ; + // se sto cercando di fare uno split sulla stessa curva che ho già splittato al passaggio precedente allora devo + // riscalare + if ( nSplit == nUnit && z < int( vdSplit1.size() - 1)) { + dSplit = nSplit + ( dSplit - nSplit) / (vdSplit1[z+1] - nSplit); + } + nUnit = nSplit ; + pCrvU0->AddJoint( dSplit) ; + switch( vnAddedOrNextIsRep1[z]) { + case 0 : if( vbRep0[nSplit]) + ++ nRep0 ; + // di default aggiungerei false, ma se il successivo è già un Rep allora anche questo deve esserlo + vbRep0.insert( vbRep0.begin() + nSplit, vbRep0[nSplit]) ; break ; + case 1 : vbRep0.insert( vbRep0.begin() + nSplit, true) ; break ; + case 2 : if( vbRep0[nSplit]) + -- nRep0 ; + else + vbRep0[nSplit] = true ; + vbRep0.insert( vbRep0.begin() + nSplit, false) ; break ; + } + } + + nSpanU0 = pCrvU0->GetCurveCount() ; + nSpanU1 = pCrvU1->GetCurveCount() ; + //aggiusto i vettori delle ripetizioni in modo in modo che non arrivino mai ad essere contemporaneamente true + int nAddedSpan = 0 ; + int nCrv0 = 0 ; + int nCrv1 = 0 ; + while ( nAddedSpan < nSpanU0 + nAtStart0 + nAtEnd0 + nRep1) { + if ( nCrv0 >= nSpanU0) + nCrv0 = nSpanU0 - 1; + if ( nCrv1 >= nSpanU1) + nCrv1 = nSpanU1 - 1; + bool bRep0 = vbRep0[nCrv0] ; + bool bRep1 = vbRep1[nCrv1] ; + if ( bRep0 && bRep1 ) { + vbRep0[nCrv0] = false ; + bRep0 = false ; + vbRep1[nCrv1] = false ; + bRep1 = false ; + -- nRep0 ; + -- nRep1 ; + } + if ( ! bRep0 || nCrv1 == nSpanU1 - 1) + ++ nCrv1 ; + if ( ! bRep1 || nCrv0 == nSpanU0 - 1) + ++ nCrv0 ; + ++nAddedSpan ; + } + // se non sono arrivato all'ultima curva su U0 o U1 vuol dire che ho creato delle ripetizioni che non ho contato prima + if( nCrv1 < nSpanU1) { + nRep1 += nSpanU1 - nCrv1 ; + for ( int z = int( vbRep1.size() - 1) ; z >= nCrv1 ; --z) + vbRep1[z] = true ; + } + if( nCrv0 < nSpanU0) { + nRep0 += nSpanU0 - nCrv0 ; + for ( int z = int( vbRep0.size() - 1) ; z >= nCrv0 ; --z) + vbRep0[z] = true ; + } + + // trovo il numero di span che dovrà avere la superficie + // ( numero di sottocurve che compongono la U0 + tutte le ripetizioni dei match di punti della curva U1 con i punti di U0) + nSpanU = nSpanU0 + nAtStart0 + nAtEnd0 + nRep1 ; + + nSecondRowInd = nDegU * nSpanU + 1 ; + // inizializzo la superficie + Init( nDegU, nDegV, nSpanU, nSpanV, bRat) ; + + // aggiungo i punti di controllo scorrendo in contemporanea le due curve + nAddedSpan = 0 ; + nCrv0 = 0 ; + nCrv1 = 0 ; + bool bLast0 = false ; + bool bLast1 = false ; + while ( nAddedSpan < nSpanU) { + if ( nCrv0 >= nSpanU0){ + nCrv0 = nSpanU0 - 1; + bLast0 = true ; + } + if ( nCrv1 >= nSpanU1) { + nCrv1 = nSpanU1 - 1; + bLast1 = true ; + } + bool bRep0 = vbRep0[nCrv0] ; + bool bRep1 = vbRep1[nCrv1] ; + const ICurveBezier* pSubCrv0 = GetCurveBezier( pCrvU0->GetCurve( nCrv0)) ; + for( int i = nAddedSpan == 0 ? 0 : 1 ; i < nLastPoint ; ++ i) { + int nInd = i ; + // se ho una ripetizione allora riaggiungo l'ultimo punto. Se sono ancora alla curva 0 invece devo aggiungere lo start della curva U0 + if ( bRep1 || bLast0) + nInd = ! bLast0 ? 0 : nDegU ; + if ( ! bRat) + SetControlPoint( nAddedSpan * nDegU + i, pSubCrv0->GetControlPoint( nInd)) ; + else + SetControlPoint( nAddedSpan * nDegU + i, pSubCrv0->GetControlPoint( nInd), pSubCrv0->GetControlWeight( nInd)) ; + } + if ( ! bRep1) + ++ nCrv0 ; + const ICurveBezier* pSubCrv1 = GetCurveBezier( pCrvU1->GetCurve( nCrv1)) ; + for( int i = nAddedSpan == 0 ? 0 : 1 ; i < nLastPoint ; ++ i) { + int nInd = i ; + // se ho una ripetizione allora riaggiungo l'ultimo punto. Se sono ancora alla curva 0 invece devo aggiungere lo start della curva U0 + if ( bRep0 || bLast1) + nInd = ! bLast1 ? 0 : nDegU ; + if ( ! bRat) + SetControlPoint( nSecondRowInd + nAddedSpan * nDegU + i, pSubCrv1->GetControlPoint( nInd)) ; + else + SetControlPoint( nSecondRowInd + nAddedSpan * nDegU + i, pSubCrv1->GetControlPoint( nInd), pSubCrv1->GetControlWeight( nInd)) ; + } + if ( ! bRep0) + ++ nCrv1 ; + ++ nAddedSpan ; + } + } + else if ( RLT_B_LENPAR ) { + // da implementare + return false ; + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfBezier::FindMatchByParam( const PolyLine& pl0, const PolyLine& pl1, INTVECTOR& vMatch, int& nLong) const +{ + // per la modalità isoparametrica + int nPoints0 = pl0.GetPointNbr() ; + int nPoints1 = pl1.GetPointNbr() ; + DBLVECTOR vSplit ; + int nMin = min( nPoints0, nPoints1) ; + for ( int i = 0 ; i < nMin - 1 ; ++i) { + // valuto il limite dell'area di influenza dei punti della curva con meno punti + // per i punti intermedi il limite è la metà tra i punti + // per il primo e l'ultimo punto aumento il peso di quest'ultimi nel calcolo della media + double dW = 2./3. ; + //double dW = 1./2. ; + if ( i == 0) + vSplit.push_back( (i * (1- dW) + ( i + 1) * dW) / ( nMin - 1)) ; + else if ( i == nMin - 2) + vSplit.push_back( (i * dW + ( i + 1) * ( 1 - dW)) / ( nMin - 1)) ; + else + vSplit.push_back( ( 2. * i + 1) / (2 * ( nMin - 1))) ; + } + int nCount = 0 ; + int nMax = max(nPoints0, nPoints1) ; + nLong = nPoints0 < nPoints1 ? 1 : 0 ; + for ( double j = 0 ; j < nMax ; ++j) { + if ( nCount < int(vSplit.size()) && j / ( nMax - 1) > vSplit[nCount] ) + ++nCount ; + vMatch.push_back( nCount) ; + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfBezier::ParametrizeByLen( const ICurveComposite* pCurve0, const ICurveComposite* pCurve1, DBLVECTOR& vParam0, DBLVECTOR& vParam1) const +{ + int nSpanU0 = pCurve0->GetCurveCount() ; + int nSpanU1 = pCurve1->GetCurveCount() ; + DBLVECTOR vLen0 ; + DBLVECTOR vLen1 ; + double dLenTot0 = 0 ; + double dLenTot1 = 0 ; + for( int i = 0 ; i < nSpanU0 ; ++i) { + const ICurve* pSubCrv0 = pCurve0->GetCurve( i) ; + double dLen ; pSubCrv0->GetLength( dLen) ; + dLenTot0 += dLen ; + vLen0.push_back( dLen) ; + } + for( int i = 0 ; i < nSpanU1 ; ++i) { + const ICurve* pSubCrv1 = pCurve1->GetCurve( i) ; + double dLen ; pSubCrv1->GetLength( dLen) ; + dLenTot1 += dLen ; + vLen1.push_back( dLen) ; + } + // determino il parametro di ogni curva rispetto alla lunghezza totale + for ( int i = 0 ; i < nSpanU0 ; ++i) + vParam0.push_back( vLen0[i] / dLenTot0) ; + for ( int i = 0 ; i < nSpanU1 ; ++i) + vParam1.push_back( vLen1[i] / dLenTot1) ; + + return true ; +} + +////---------------------------------------------------------------------------- +//bool +//SurfBezier::FindMatchByParam( const DBLVECTOR& vParam0, const DBLVECTOR& vParam1, INTVECTOR& vMatch0, INTVECTOR& vMatch1) const +//{ +// // per la modalità parametrata sulla lunghezza +// int nPoints0 = vParam0.size() ; +// int nPoints1 = vParam1.size() ; +// DBLVECTOR vSplit ; +// for ( int i = 0 ; i < nPoints0 - 1 ; ++i) { +// // valuto il limite dell'area di influenza dei punti della curva con meno punti +// // per i punti intermedi il limite è la metà tra i punti +// // per il primo e l'ultimo punto aumento il peso di quest'ultimi nel calcolo della media +// if ( i == 0) +// vSplit.push_back( (i * (1./3.) + ( i + 1) * ( 2./3.)) / ( nPoints0 - 1)) ; +// else if ( i == nPoints0 - 2) +// vSplit.push_back( (i * (2./3.) + ( i + 1) * ( 1./3.)) / ( nPoints0 - 1)) ; +// else +// vSplit.push_back( ( 2. * i + 1) / (2 * ( nPoints0 - 1))) ; +// } +// int nCount = 0 ; +// for ( double j = 0 ; j < nPoints1 ; ++j) { +// if ( nCount < int(vSplit.size()) && j / ( nPoints1 - 1) > vSplit[nCount] ) +// ++nCount ; +// vMatch0.push_back( nCount) ; +// } +// 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 ; +} diff --git a/SurfBezier.h b/SurfBezier.h index c58f9d2..9693ef3 100644 --- a/SurfBezier.h +++ b/SurfBezier.h @@ -137,6 +137,12 @@ class SurfBezier : public ISurfBezier, public IGeoObjRW // se la superficie è trimmata restituisce i loop dello spazio parametrico in forma di linee spezzate bool GetLoops( ICRVCOMPOPOVECTOR& vCC, bool bLineOrBezier, int nEdge = -1) const override ; bool IsPlanar( void) const override ; + bool CreateByFlatContour( const PolyLine& PL) override ; + bool CreateByRegion( const POLYLINEVECTOR& vPL) override ; + bool CreateByExtrusion( const ICurve* pCurve, const Vector3d& vtExtr, bool bDeg3OrDeg2 = false) override ; + bool CreateByScrewing( const ICurve* pCurve, const Point3d& ptAx, const Vector3d& vtAx, double dAngRotDeg, double dMove) override ; + bool CreateByPointCurve( const Point3d& pt, const ICurve* pCurve) override ; + bool CreateByTwoCurves( const ICurve* pCurve1, const ICurve* pCurve2, int nType) override ; public : // IGeoObjRW int GetNgeId( void) const override ; @@ -189,11 +195,14 @@ class SurfBezier : public ISurfBezier, public IGeoObjRW double GetCurveOnVApproxLen( double dU) const ; // funzione che proietta nello spazio parametrico un trim derivante da un taglio con un piano, categorizzandolo come aperto o chiuso ( nel parametrico) bool AddCurveCompoToCuts( ICurveComposite* pCrvCompo, ICRVCOMPOPOVECTOR& vpCCOpen, ICRVCOMPOPOVECTOR& vpCCClosed, double dToler = EPS_SMALL, const Plane3d* pPlCut = nullptr) const ; + ISurfFlatRegion* CreateTrimRegionFromCuts( ICRVCOMPOPOVECTOR& vpCCOpen, ICRVCOMPOPOVECTOR& vpCCClosed) const ; // restituisce il singolo edge della superficie non trimmata ICurveComposite* GetSingleEdge3D( bool bLineOrBezier, int nEdge) const ; bool UpdateEdgesFromTree( Tree& tr) const ; // funzione che calcola se gli edge sono collassati in poli bool CalcPoles( void) ; + bool FindMatchByParam( const PolyLine& pl0, const PolyLine& pl1, INTVECTOR& vMatch, int& nLong) const ; + bool ParametrizeByLen( const ICurveComposite* pCurve0, const ICurveComposite* pCurve1, DBLVECTOR& vParam0, DBLVECTOR& vParam1) const ; private : ObjGraphicsMgr m_OGrMgr ; // gestore grafica dell'oggetto diff --git a/SurfTriMesh.cpp b/SurfTriMesh.cpp index 8847922..e9ab10f 100644 --- a/SurfTriMesh.cpp +++ b/SurfTriMesh.cpp @@ -2715,6 +2715,8 @@ VeryfyPolylineForRevolution( const PolyLine& PL, const Point3d& ptAx, const Vect ptPc.z = 0 ; ++ nSeg ; // verifico distanza + // se la curva è chiusa oppure è vicina all'asse ( entro EPS_SMALL), ma non ho che sono start o end ad essere sull'asse + // allora dovrò rimaneggiare la polyline if ( DistPointLine( ORIG, ptPp, ptPc).IsSmall()) { if ( bClosed || ( ! ( nSeg == 1 && AreSamePointApprox( ORIG, ptPp)) && @@ -2833,10 +2835,12 @@ SurfTriMesh::CreateByScrewing( const PolyLine& PL, const Point3d& ptAx, const Ve // verifico che la polilinea non attraversi l'asse di rivoluzione o lo tocchi in punti interni PolyLine MyPL = PL ; + // commented for debug if ( ! VeryfyPolylineForRevolution( MyPL, ptAx, vtAx) && ! AdjustPolylineForRevolution( MyPL, ptAx, vtAx)) { LOG_ERROR( GetEGkLogger(), "StmCreateByRevolution : polyline inside meets axis") return false ; } + // commented for debug // imposto ricalcolo m_nStatus = ERR ; diff --git a/Tree.cpp b/Tree.cpp index 20e7574..57ef219 100644 --- a/Tree.cpp +++ b/Tree.cpp @@ -21,6 +21,7 @@ #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" @@ -790,6 +791,42 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax) } } + // 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 ; + 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] ; + + // 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 > 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 ; + } + // 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 ; @@ -802,12 +839,12 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax) bVert = true ; } m_mTree[nCToSplit].SetSplitDirVert( bVert) ; - Point3d ptP00, ptP10, ptP11, ptP01 ; + //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 - 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) ; @@ -849,7 +886,7 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax) 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 ( (dSideMinVal / 2 >= dSideMin || dSideMinVal < EPS_SMALL) && dSideMaxVal < dSideMax && ( dCurvV > dLinTol || dCurvU > dLinTol)) { + 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) ; @@ -919,6 +956,13 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax) } } } + 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 ; + } if ( bSplit || dSideMaxVal > dSideMax) { m_mTree[nCToSplit].SetSplitDirVert( bVert) ; @@ -953,7 +997,7 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax) nCToSplit = m_mTree[nCToSplit].m_nChild1 ; } } - Balance() ; // 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à // probabilmente mi servirà salvare nella cella il livello di profondità } // bilineare else { @@ -972,7 +1016,7 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax) double dLen3 = Dist( ptP00, ptP01) ; bool bVert = false ; - // calcolo in quale direzione è meglio dividere in base allo stretch + // calcolo in quale direzione è meglio dividere in base allo stretch // in realtà visto che non parametro rispetto alla dimensione nel parametrico, così mi trovo a dividere con un quad-tree Point3d ptPSrfU, ptPSrfV ; double dU = 0, dV = 0 ; double dDistU = 0, dDistV = 0 ; @@ -1035,6 +1079,7 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax) } else { 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 } // se la cella è abbastanza grande da poter essere divisa ancora e devo approssimare meglio, la divido if ( dSideMinVal / 2 >= dSideMin && dSideMaxVal < dSideMax && dErr > dLinTol) { @@ -1522,17 +1567,43 @@ Tree::GetDepth( int nId, int nRef = -2) const //---------------------------------------------------------------------------- bool -Tree::GetPolygons( POLYLINEMATRIX& vPolygons) +Tree::GetPolygons( POLYLINEMATRIX& vvPolygons) +{ + POLYLINEMATRIX vvPolygonsBasic3d ; + return GetPolygons( vvPolygons, false, vvPolygonsBasic3d) ; +} + +//---------------------------------------------------------------------------- +bool +Tree::GetPolygons( POLYLINEMATRIX& vvPolygons, POLYLINEMATRIX& vPolygonsBasic3d) +{ + return GetPolygons( vvPolygons, true, vPolygonsBasic3d) ; +} + +//---------------------------------------------------------------------------- +bool +Tree::GetPolygons( POLYLINEMATRIX& vvPolygons, bool bForTriangulation, POLYLINEMATRIX& vvPolygons3d) { if ( (int) m_vPolygons.size() == 0) { if ( ! m_bTrimmed) { - vPolygons.clear() ; + vvPolygons.clear() ; POLYLINEVECTOR vPolygonsBasic ; - GetPolygonsBasic( vPolygonsBasic) ; + POLYLINEVECTOR vPolygonsBasic3d ; + if ( bForTriangulation) + GetPolygonsBasic( vPolygonsBasic, vPolygonsBasic3d) ; + else + GetPolygonsBasic( vPolygonsBasic) ; + int c = 0; for ( PolyLine pl : vPolygonsBasic) { POLYLINEVECTOR vSinglePolygon ; vSinglePolygon.push_back( pl) ; - vPolygons.push_back( vSinglePolygon) ; + vvPolygons.push_back( vSinglePolygon) ; + if ( bForTriangulation) { + POLYLINEVECTOR vSinglePolygon3d ; + vSinglePolygon3d.push_back( vPolygonsBasic3d[c]) ; + vvPolygons3d.push_back( vSinglePolygon3d) ; + } + ++c ; } return true ; } @@ -1540,6 +1611,10 @@ Tree::GetPolygons( POLYLINEMATRIX& vPolygons) else { POLYLINEVECTOR vPolygonsBasic ; GetPolygonsBasic( vPolygonsBasic) ; + POLYLINEVECTOR vPolygons ; + POLYLINEVECTOR vPolygonsBasic3d ; + if ( bForTriangulation) + GetPolygonsBasic( vPolygons, vPolygonsBasic3d) ; // aggiungo 4 elementi al vettore che contiene ciò che resta degli edge dopo il trim m_vCEdge2D.clear() ; for ( int i = 0 ; i < 4 ; ++i) { @@ -1558,7 +1633,17 @@ Tree::GetPolygons( POLYLINEMATRIX& vPolygons) // vettore dei poligoni ( loop) della cella nId POLYLINEVECTOR vCellPolygons ; vCellPolygons.push_back( vPolygonsBasic[i]) ; - vPolygons.push_back( vCellPolygons) ; + vvPolygons.push_back( vCellPolygons) ; + if ( bForTriangulation ) { + POLYLINEVECTOR vCellPolygons3d ; + PolyLine plPolygon3d ; + plPolygon3d.AddUPoint( 0, m_mVert[nId][0]) ; + plPolygon3d.AddUPoint( 1, m_mVert[nId][1]) ; + plPolygon3d.AddUPoint( 2, m_mVert[nId][2]) ; + plPolygon3d.AddUPoint( 3, m_mVert[nId][3]) ; + vCellPolygons3d.push_back( plPolygon3d) ; + vvPolygons3d.push_back( vCellPolygons3d) ; + } } else if ( m_mTree[nId].m_nFlag == 0) continue ; @@ -1575,37 +1660,58 @@ Tree::GetPolygons( POLYLINEMATRIX& vPolygons) // in questo for analizzo solo i loop che tagliano la cella while( (int)vToCheck.size() != 0) { int nPolyBefore = nPoly ; - CreateCellPolygons( i, vPolygons, vToCheck, nPoly, vnParentChunk, vPolygonsBasic[i]) ; + PolyLine pl3d ; + if( bForTriangulation) + pl3d = vPolygonsBasic3d[i] ; + CreateCellPolygons( i, vvPolygons, vvPolygons3d, vToCheck, nPoly, vnParentChunk, vPolygonsBasic[i], pl3d) ; if ( nPolyBefore == nPoly) break ; } // ora analizzo anche i loop che sono contenuti nella cella - CreateIslandAndHoles( i, vPolygons, nPoly, vnParentChunk) ; + CreateIslandAndHoles( i, vvPolygons, vvPolygons3d, nPoly, vnParentChunk, bForTriangulation) ; } } return true ; } } else { - vPolygons = m_vPolygons ; + vvPolygons = m_vPolygons ; return true ; } } +//---------------------------------------------------------------------------- +bool +Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygons, POLYLINEVECTOR& vPolygons3d) +{ + return GetPolygonsBasic( vPolygons, true, vPolygons3d) ; +} + //---------------------------------------------------------------------------- bool Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygons, INTVECTOR vCells) +{ + POLYLINEVECTOR vPolygons3d ; + return GetPolygonsBasic( vPolygons, false, vPolygons3d, vCells) ; +} + +//---------------------------------------------------------------------------- +bool +Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygons, bool bForTriangulation, POLYLINEVECTOR& vPolygons3d, 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 + ( 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 + bForTriangulation) { // oppure se sto chiedendo i poligoni per la triangolazione ( devo fare considerazioni particolari se ho dei poli sui lati del parametrico) m_vPolygons.clear() ; + m_vPolygons3d.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 ; PNTVECTOR vVertices ; + PNTVECTOR vVertices3d ; INTVECTOR vNeigh ; // setto le celle che sono sul LeftEdge e sul TopEdge if ( m_bClosedU) { @@ -1627,8 +1733,14 @@ Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygons, INTVECTOR vCells) // N.B. :i poligoni sono costruiti a partire dal ptBL !!! for ( int nId : vCells) { vVertices.clear() ; + vVertices3d.clear() ; vNeigh.clear() ; vVertices.push_back( m_mTree.at( nId).GetBottomLeft()) ; + vVertices3d.push_back( m_mVert.at( nId)[0]) ; + INTVECTOR vnVert ; + BOOLVECTOR vbBonusVert(4) ; + fill( vbBonusVert.begin(), vbBonusVert.end(), false) ; + vnVert.push_back( int(vVertices.size()) - 1) ; GetBottomNeigh( nId, vNeigh) ; // aggiungo i vertici che sono sul lato bottom, solo se ho più di un vicino bottom if ( (int) vNeigh.size() != 0 && (int) vNeigh.size() != 1){ @@ -1638,13 +1750,17 @@ Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygons, INTVECTOR vCells) for ( int j : vNeigh) { Point3d pt( m_mTree.at( j).GetTopRight().x, m_mTree.at( nId).GetBottomLeft().y) ; vVertices.push_back( pt) ; + vVertices3d.push_back( m_mVert[j][2]) ; } } else { - for ( int j : vNeigh) + for ( int j : vNeigh) { vVertices.push_back( m_mTree.at( j).GetTopRight()) ; + vVertices3d.push_back( m_mVert[j][2]) ; + } } bBottomRight = true ; + vbBonusVert[2] = true ; } else bBottomRight = false ; @@ -1654,42 +1770,55 @@ Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygons, INTVECTOR vCells) if ( (int) vNeigh.size() != 0 && (int) vNeigh.size() != 1){ // se la superficie è chiusa lungo il parametro U e le celle vicine right sono sul lato Left // devo aggiungere i vertici tenendo conto della periodicità dello spazio parametrico. + vnVert.push_back( int(vVertices.size())) ; if ( m_bClosedU && m_mTree.at( vNeigh[0]).m_bOnLeftEdge ) { for ( int j : vNeigh) { Point3d pt( m_mTree.at( nId).GetTopRight().x, m_mTree.at(j).GetBottomLeft().y) ; vVertices.push_back( pt) ; + vVertices3d.push_back( m_mVert[j][0]) ; } } else { - for ( int j : vNeigh) + for ( int j : vNeigh) { vVertices.push_back( m_mTree.at( j).GetBottomLeft()) ; + vVertices3d.push_back( m_mVert[j][0]) ; + } } - + vbBonusVert[3] = true ; } // se non l'ho già aggiunto tramite i vicini bottom aggiungo il punto bottom right - else if ( ! bBottomRight) { + else if ( ! bBottomRight) { Point3d ptBr( m_mTree.at( nId).GetTopRight().x, m_mTree.at( nId).GetBottomLeft().y) ; vVertices.push_back( ptBr) ; + vVertices3d.push_back( m_mVert[nId][1]) ; + vnVert.push_back( int(vVertices.size()) - 1) ; } vNeigh.clear() ; vVertices.push_back( m_mTree.at( nId).GetTopRight()) ; + vVertices3d.push_back( m_mVert[nId][2]) ; + vnVert.push_back( int(vVertices.size()) - 1) ; GetTopNeigh ( nId, vNeigh) ; std::reverse( vNeigh.begin(), vNeigh.end()) ; // aggiungo i vertici che sono sul lato top, solo se ho più di un vicino top if ( ! vNeigh.empty() && vNeigh.size() != 1) { // se la superficie è chiusa lungo il parametro V e la cella è sul lato top // devo aggiungere i vertici tenendo conto della periodicità dello spazio parametrico. + vnVert.push_back( int(vVertices.size())) ; if ( m_bClosedV && m_mTree.at( nId).m_bOnTopEdge) { for ( int j : vNeigh) { Point3d pt( m_mTree.at( j).GetBottomLeft().x, m_mTree.at( nId).GetTopRight().y) ; vVertices.push_back( pt) ; + vVertices3d.push_back( m_mVert[j][0]) ; } } else { - for ( int j : vNeigh) + for ( int j : vNeigh) { vVertices.push_back( m_mTree.at( j).GetBottomLeft()) ; + vVertices3d.push_back( m_mVert[j][0]) ; + } } bTopLeft = true ; + vbBonusVert[0] = true ; } else bTopLeft = false ; @@ -1700,24 +1829,123 @@ Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygons, INTVECTOR vCells) if ( (int) vNeigh.size() != 0 && (int) vNeigh.size() != 1) { // se la superficie è chiusa lungo il parametro U e la cella è sul lato left // devo aggiungere i vertici tenendo conto della periodicità dello spazio parametrico. + vnVert.push_back( int(vVertices.size())) ; if ( m_bClosedU && m_mTree.at( nId).m_bOnLeftEdge) { for ( int j : vNeigh) { Point3d pt( m_mTree.at( nId).GetBottomLeft().x, m_mTree.at(j).GetTopRight().y) ; vVertices.push_back( pt) ; + vVertices3d.push_back( m_mVert[j][2]) ; } } else { - for ( int j : vNeigh) + for ( int j : vNeigh) { vVertices.push_back( m_mTree.at( j).GetTopRight()) ; + vVertices3d.push_back( m_mVert[j][2]) ; + } } + vbBonusVert[1] = true ; } // se non l'ho già aggiunto tramite i vicini top aggiungo il punto top left else if ( ! bTopLeft) { Point3d ptTl( m_mTree.at( nId).GetBottomLeft().x, m_mTree.at( nId).GetTopRight().y) ; vVertices.push_back( ptTl) ; + vVertices3d.push_back( m_mVert[nId][3]) ; + vnVert.push_back( int(vVertices.size()) - 1) ; } vNeigh.clear() ; vVertices.push_back( m_mTree.at( nId).GetBottomLeft()) ; + vVertices3d.push_back( m_mVert[nId][0]) ; + vnVert.push_back( int(vVertices.size()) - 1) ; + + BOOLVECTOR vbKeepPoint( vVertices.size()) ; + fill( vbKeepPoint.begin(), vbKeepPoint.end(), true) ; + + if ( bForTriangulation){ + // ora devo controllare se uno dei lati della cella è collassato in un punto. + // se così, devo guardare se sui due lati adiacenti a quello di polo ho messo dei punti extra + // se ne ho messi solo su uno dei due allora devo togliere il vertice dell'altro lato + if ( AreSamePointApprox(m_mVert.at(nId).at(0), m_mVert.at(nId).at(1)) && ( vbBonusVert[1] || vbBonusVert[3] ) ) { + // se ho punti bonus su entrambi i lati non devo fare nulla + if ( !( vbBonusVert[1] && vbBonusVert[3] ) ) { + // sennò devo togliere l'estremo del lato su cui NON ho punti bonus + if ( vbBonusVert[1] ) {// lati contati a partire da quello sopra in senso CCW + //vVertices.erase(vVertices.begin() + vnVert[1]) ; // vertici della cella contati a partire da ptBL in senso CCW + //vVertices3d.erase(vVertices3d.begin() + vnVert[1]) ; + vbKeepPoint[vnVert[1]] = false ; + m_mTree[nId].m_nVertToErase = 1 ; // ptBr + } + else if ( vbBonusVert[3] ) { + //// dovrei eliminare ptBL, quindi devo eliminare il primo e l'ultimo punto della polyline e poi chiuderla con quello che era il penultimo punto + //vVertices.pop_back() ; + //vVertices[0] = vVertices.end()[-1] ; + //vVertices3d.pop_back() ; + //vVertices3d[0] = vVertices3d.end()[-1] ; + vbKeepPoint[0] = false ; + vbKeepPoint.back() = false ; + m_mTree[nId].m_nVertToErase = 0 ; // ptBL + } + } + } + if ( AreSamePointApprox(m_mVert.at(nId).at(1), m_mVert.at(nId).at(2)) && ( vbBonusVert[0] || vbBonusVert[2] ) ) { + // se ho punti bonus su entrambi i lati non devo fare nulla + if ( !( vbBonusVert[0] && vbBonusVert[2] ) ) { + // sennò devo togliere l'estremo del lato su cui NON ho punti bonus + if ( vbBonusVert[0] ){ // lati contati a partire da quello sopra in senso CCW + //vVertices.erase(vVertices.begin() + vnVert[1]) ; // vertici della cella contati a partire da ptBL in senso CCW + //vVertices3d.erase(vVertices3d.begin() + vnVert[1]) ; + vbKeepPoint[vnVert[1]] = false ; + m_mTree[nId].m_nVertToErase = 1 ; // ptBr + } + else if ( vbBonusVert[2] ){ + //vVertices.erase(vVertices.begin() + vnVert[2]) ; + //vVertices3d.erase(vVertices3d.begin() + vnVert[2]) ; + vbKeepPoint[vnVert[2]] = false ; + m_mTree[nId].m_nVertToErase = 2 ; // ptTR + } + } + } + if ( AreSamePointApprox(m_mVert.at(nId).at(2), m_mVert.at(nId).at(3)) && ( vbBonusVert[1] || vbBonusVert[3] ) ) { + // se ho punti bonus su entrambi i lati non devo fare nulla + if ( !( vbBonusVert[1] && vbBonusVert[3] ) ) { + // sennò devo togliere l'estremo del lato su cui NON ho punti bonus + if ( vbBonusVert[1] ){ // lati contati a partire da quello sopra in senso CCW + //vVertices.erase(vVertices.begin() + vnVert[2]) ; // vertici della cella contati a partire da ptBL in senso CCW + //vVertices3d.erase(vVertices3d.begin() + vnVert[2]) ; + vbKeepPoint[vnVert[2]] = false ; + m_mTree[nId].m_nVertToErase = 2 ; // ptTR + } + else if ( vbBonusVert[3] ) { + //vVertices.erase(vVertices.begin() + vnVert[3]) ; + //vVertices3d.erase(vVertices3d.begin() + vnVert[3]) ; + vbKeepPoint[vnVert[3]] = false ; + m_mTree[nId].m_nVertToErase = 3 ; // ptTl + } + } + } + if ( AreSamePointApprox(m_mVert.at(nId).at(3), m_mVert.at(nId).at(0)) && ( vbBonusVert[0] || vbBonusVert[2] ) ) { + // se ho punti bonus su entrambi i lati non devo fare nulla + if ( !( vbBonusVert[0] && vbBonusVert[2] ) ) { + // sennò devo togliere l'estremo del lato su cui NON ho punti bonus + if ( vbBonusVert[0] ) { // lati contati a partire da quello sopra in senso CCW + //// dovrei eliminare ptBL, quindi devo eliminare il primo e l'ultimo punto della polyline e poi chiuderla con quello che era il penultimo punto + //vVertices.pop_back() ; + //vVertices[0] = vVertices.end()[-1] ; + //vVertices3d.pop_back() ; + //vVertices3d[0] = vVertices3d.end()[-1] ; + vbKeepPoint[0] = false ; + vbKeepPoint.back() = false ; + m_mTree[nId].m_nVertToErase = 0 ; // ptBL + } + else if ( vbBonusVert[2] ) { + //vVertices.erase(vVertices.begin() + vnVert[3]) ; + //vVertices3d.erase(vVertices3d.begin() + vnVert[3]) ; + vbKeepPoint[vnVert[3]] = false ; + m_mTree[nId].m_nVertToErase = 3 ; // ptTl + } + } + } + } + if ( ! m_bTrimmed) { // se ho una cella con vicino dello stesso grado ( quindi il poligono ha solo 5 punti) controllo la curvatura nella cella e // se necessario cambio l'ordine dei vertici per scegliere la diagonale di split migliore @@ -1737,14 +1965,24 @@ Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygons, INTVECTOR vCells) if ( Dist( ptP00P11, ptPSrf) + EPS_SMALL > Dist( ptP10P01, ptPSrf)) { rotate( vVertices.begin(), vVertices.begin() + 1,vVertices.end()) ; vVertices.back() = vVertices.at( 0) ; + rotate( vVertices3d.begin(), vVertices3d.begin() + 1,vVertices3d.end()) ; + vVertices3d.back() = vVertices3d.at( 0) ; + rotate( vbKeepPoint.begin(), vbKeepPoint.begin() + 1,vbKeepPoint.end()) ; + vbKeepPoint.back() = vbKeepPoint.at( 0) ; } } } m_vPolygons.emplace_back() ; m_vPolygons.back().emplace_back() ; + m_vPolygons3d.emplace_back() ; + m_vPolygons3d.back().emplace_back() ; for ( int i = 0 ; i < (int) vVertices.size() ; ++i) { - m_vPolygons.back().back().AddUPoint( i, vVertices.at( i)) ; + int dPar = i ; + if( ! vbKeepPoint[i]) + dPar = -1 ; + m_vPolygons.back().back().AddUPoint( dPar, vVertices.at( i)) ; + m_vPolygons3d.back().back().AddUPoint( dPar, vVertices3d.at( i)) ; } } @@ -1754,6 +1992,7 @@ Tree::GetPolygonsBasic( POLYLINEVECTOR& vPolygons, INTVECTOR vCells) for ( int t = 0 ; t < (int)m_vPolygons.size() ; ++ t) { for ( int z = 0 ; z < (int)m_vPolygons[t].size() ; ++z) { vPolygons.push_back( m_vPolygons[t][z]) ; + vPolygons3d.push_back( m_vPolygons3d[t][z]) ; } } return true ; @@ -1887,23 +2126,23 @@ Tree::FindCell( const Point3d& ptToAssign, const CurveLine& cl, INTVECTOR vCells // potrei essere su un lato if ( nEdge == 0 || nEdge == 1 || nEdge == 2 || nEdge == 3) { // se è orientato con il lato mi sposto a destra - if ( ( nEdge == 0 || nEdge == 2 ) && abs(vtDir.x) > 1 - EPS_SMALL ) { + if ( ( nEdge == 0 || nEdge == 2 ) && abs(vtDir.x) > 1 - EPS_SMALL/100 ) { Vector3d vtDirDX = vtDir ; vtDirDX.Rotate( Z_AX, -90) ; ptIntersPlus = ptIntersPlus + vtDirDX * EPS_SMALL ; } - else if ( (nEdge == 0 || nEdge == 2) && abs(vtDir.y) > EPS_SMALL) + else if ( (nEdge == 0 || nEdge == 2) && abs(vtDir.y) > EPS_SMALL/100) ptIntersPlus.y += (vtDir.y > 0 ? 1 : -1) * EPS_SMALL ; - else if ( ( nEdge == 1 || nEdge == 3 ) && abs(vtDir.y) > 1 - EPS_SMALL ) { + else if ( ( nEdge == 1 || nEdge == 3 ) && abs(vtDir.y) > 1 - EPS_SMALL/100 ) { Vector3d vtDirDX = vtDir ; vtDirDX.Rotate( Z_AX, -90) ; ptIntersPlus = ptIntersPlus + vtDirDX * EPS_SMALL ; } - else if ( (nEdge == 1 || nEdge == 3) && abs(vtDir.x) > EPS_SMALL) + else if ( (nEdge == 1 || nEdge == 3) && abs(vtDir.x) > EPS_SMALL/100) ptIntersPlus.x += (vtDir.x > 0 ? 1 : -1) * EPS_SMALL ; } // o in un vertice else if ( nEdge == 4 || nEdge == 5 || nEdge == 6 || nEdge == 7) { // se non è orientato con gli assi procedo con la direzione del trim - if ( abs(vtDir.x) < 1 - EPS_SMALL && abs(vtDir.y) < 1 - EPS_SMALL ) + if ( abs(vtDir.x) < 1 - EPS_SMALL/100 && abs(vtDir.y) < 1 - EPS_SMALL/100 ) ptIntersPlus = ptIntersPlus + vtDir * EPS_SMALL ; // altrimenti ruoto a destra else { @@ -2059,7 +2298,7 @@ Tree::TraceLoopLabelCell( const POLYLINEVECTOR& vplPolygons) // qui devo mettere una tolleranza negativa per poter tener conto anche dei punti che sono SULLA curva while ( ! IsPointInsidePolyLine( ptCurr, vplPolygons[nIdPolygon], dLinTol)) { // sto uscendo dalla cella, quindi cerco l'intersezione - if ( bEraseNextPoint) { + if ( bEraseNextPoint && vptInters.size() != 0) { vptInters.pop_back() ; bEraseNextPoint = false ; } @@ -2067,16 +2306,17 @@ Tree::TraceLoopLabelCell( const POLYLINEVECTOR& vplPolygons) // trovo l'intersezione e passo alla cella successiva. nId viene aggiornato dalla funzione FindInters // se non trovo l'intersezione vuol dire che non sono nella cella giusta! // al precedente FindInters avrei dovuto passare di cella - if ( ! FindInters( nId, clTrim, vptInters, true)) { + if ( ! FindInters( nId, clTrim, vplPolygons[nIdPolygon], vptInters, true)) { // scarterò il punto molto vicino al lato e tengo solo l'intersezione del trim col lato - vptInters.pop_back() ; + if( vptInters.size() != 0) + vptInters.pop_back() ; plLoop.GetPrevPoint( ptTEnd) ; plLoop.GetPrevPoint( ptTStart) ; plLoop.GetNextPoint( ptCurr) ; clTrim.Set( ptTStart, ptTEnd) ; clTrim.ExtendEndByLen( EPS_SMALL * 2) ; clTrim.ExtendStartByLen( EPS_SMALL * 2) ; - if ( ! FindInters( nId, clTrim, vptInters, true)) + if ( ! FindInters( nId, clTrim, vplPolygons[nIdPolygon], vptInters, true)) return false ; bEraseNextPoint = true ; } @@ -2090,10 +2330,19 @@ Tree::TraceLoopLabelCell( const POLYLINEVECTOR& vplPolygons) // aggiorno la polyline splittata UpdateSplitLoop( plLoopSplit, nPtLoopSplit, vptInters.back()) ; } - // aggiungo la fine del segmento nel vettore delle intersezioni - vptInters.push_back( ptCurr) ; - // aggiorno la polyline splittata - UpdateSplitLoop( plLoopSplit, nPtLoopSplit, ptCurr) ; + // VERSIONE NUOVA + // controllo di aggiungere un punto abbastanza distante dal precedente + if( ! AreSamePointEpsilon( vptInters.back(), ptCurr, 2 * EPS_SMALL)) { + // aggiungo la fine del segmento nel vettore delle intersezioni + vptInters.push_back( ptCurr) ; + // aggiorno la polyline splittata + UpdateSplitLoop( plLoopSplit, nPtLoopSplit, ptCurr) ; + } + ////VECCHIA VERSIONE + //// aggiungo la fine del segmento nel vettore delle intersezioni + //vptInters.push_back( ptCurr) ; + //// aggiorno la polyline splittata + //UpdateSplitLoop( plLoopSplit, nPtLoopSplit, ptCurr) ; } if ( nId == nFirstCell) vptInters.pop_back() ; @@ -2293,97 +2542,122 @@ Tree::TraceLoopLabelCell( const POLYLINEVECTOR& vplPolygons) //---------------------------------------------------------------------------- bool -Tree::FindInters( int& nId, const CurveLine& clTrim, PNTVECTOR& vptInters, bool bFirstInters) +Tree::FindInters( int& nId, const CurveLine& clTrim, const PolyLine& plPolygon, PNTVECTOR& vptInters, bool bFirstInters) { - CurveLine clEdge , clEdge2 ; - Point3d ptStart , ptEnd ; - clTrim.GetStartPoint( ptStart) ; - clTrim.GetEndPoint( ptEnd) ; - // trovo da quale lato sto uscendo Point3d ptTR = m_mTree[nId].GetTopRight() ; Point3d ptBL = m_mTree[nId].GetBottomLeft() ; Point3d ptTl( ptBL.x , ptTR.y) ; Point3d ptBr( ptTR.x , ptBL.y) ; int nEdge ; // flag che indica il lato su cui ho l'intersezione a partire dal lato top in senso antiorario - // oltre il 3 sono le celle adiacenti in diagonale al vertice-> 4 corrisponde al ptTl e da lì in senso antiorario - // -1 se la curva è sempre dentro la cella Point3d ptInters ; - //int nEdge2 ; - if ( ptEnd.y >= ptTR.y && ptEnd.x <= ptTR.x) { - //nEdge = 0 ; - // lato sopra - clEdge.Set( ptTR, ptTl) ; - // lato sinistro - if ( ptEnd.x < ptBL.x) { - //nEdge2 = 1 ; - clEdge2.Set( ptTl, ptBL) ; - } - } - else if ( ptEnd.x <= ptBL.x && ptEnd.y <= ptTR.y) { - nEdge = 1 ; - // lato sinistro - clEdge.Set( ptTl, ptBL) ; - // lato sotto - if ( ptEnd.y < ptBL.y) { - //nEdge2 = 2 ; - clEdge2.Set( ptBL, ptBr) ; - } - } - else if ( ptEnd.y <= ptBL.y && ptEnd.x >= ptBL.x) { - nEdge = 2 ; - // lato sotto - clEdge.Set( ptBL, ptBr) ; - // lato destro - if ( ptEnd.x > ptTR.x) { - //nEdge2 = 3 ; - clEdge2.Set( ptBr, ptTR) ; - } - } - else if ( ptEnd.x >= ptTR.x && ptEnd.y >= ptBL.y) { - nEdge = 3 ; - // lato desto - clEdge.Set( ptBr, ptTR) ; - // lato sopra - if ( ptEnd.y > ptTR.y) { - //nEdge2 = 0 ; - clEdge2.Set( ptTR, ptTl) ; - } - } - else - return false ; - bool bIntersFound = false ; - // intersezione e controlli - IntersLineLine illExit( clTrim, clEdge, true) ; - IntCrvCrvInfo aInfo, aInfo2 ; - if ( ! illExit.GetIntCrvCrvInfo( aInfo)) { - bIntersFound = false ; - if ( ! clEdge2.IsValid()) - return false ; + //CurveLine clEdge , clEdge2 ; + //Point3d ptStart , ptEnd ; + //clTrim.GetStartPoint( ptStart) ; + //clTrim.GetEndPoint( ptEnd) ; + //// trovo da quale lato sto uscendo + ////int nEdge ; // flag che indica il lato su cui ho l'intersezione a partire dal lato top in senso antiorario + //// oltre il 3 sono le celle adiacenti in diagonale al vertice-> 4 corrisponde al ptTl e da lì in senso antiorario + //// -1 se la curva è sempre dentro la cella + ////int nEdge2 ; + //if ( ptEnd.y >= ptTR.y && ptEnd.x <= ptTR.x) { + // //nEdge = 0 ; + // // lato sopra + // clEdge.Set( ptTR, ptTl) ; + // // lato sinistro + // if ( ptEnd.x < ptBL.x) { + // //nEdge2 = 1 ; + // clEdge2.Set( ptTl, ptBL) ; + // } + //} + //else if ( ptEnd.x <= ptBL.x && ptEnd.y <= ptTR.y) { + // nEdge = 1 ; + // // lato sinistro + // clEdge.Set( ptTl, ptBL) ; + // // lato sotto + // if ( ptEnd.y < ptBL.y) { + // //nEdge2 = 2 ; + // clEdge2.Set( ptBL, ptBr) ; + // } + //} + //else if ( ptEnd.y <= ptBL.y && ptEnd.x >= ptBL.x) { + // nEdge = 2 ; + // // lato sotto + // clEdge.Set( ptBL, ptBr) ; + // // lato destro + // if ( ptEnd.x > ptTR.x) { + // //nEdge2 = 3 ; + // clEdge2.Set( ptBr, ptTR) ; + // } + //} + //else if ( ptEnd.x >= ptTR.x && ptEnd.y >= ptBL.y) { + // nEdge = 3 ; + // // lato desto + // clEdge.Set( ptBr, ptTR) ; + // // lato sopra + // if ( ptEnd.y > ptTR.y) { + // //nEdge2 = 0 ; + // clEdge2.Set( ptTR, ptTl) ; + // } + //} + //else + // return false ; + + //bool bIntersFound = false ; + //// intersezione e controlli + //IntersLineLine illExit( clTrim, clEdge, true) ; + //IntCrvCrvInfo aInfo, aInfo2 ; + //if ( ! illExit.GetIntCrvCrvInfo( aInfo)) { + // bIntersFound = false ; + // if ( ! clEdge2.IsValid()) + // return false ; + //} + //else { + // bIntersFound = true ; + // if ( aInfo.bOverlap) + // ptInters = aInfo.IciA[1].ptI ; + // else + // ptInters = aInfo.IciA[0].ptI ; + //} + //if ( clEdge2.IsValid() && ! bIntersFound){ + // IntersLineLine illExit2( clTrim, clEdge2, true) ; + // // verifico su quale dei due lati ho l'intersezione + // if ( ! illExit2.GetIntCrvCrvInfo( aInfo2)) + // bIntersFound = false ; + // else { + // bIntersFound = true ; + // //// solo intersezione sul lato 2 + // if ( aInfo2.bOverlap) + // ptInters = aInfo2.IciA[1].ptI ; + // else + // ptInters = aInfo2.IciA[0].ptI ; + // } + //} + //if ( ! bIntersFound) + // return false ; + + PtrOwner pCC( CreateCurveComposite()) ; + PolyLine plSimplePolygon ; + plSimplePolygon = plPolygon ; + plSimplePolygon.RemoveAlignedPoints() ; + pCC->FromPolyLine( plSimplePolygon) ; + IntersCurveCurve icc( clTrim, *pCC) ; + IntCrvCrvInfo iccInfo ; + if ( icc.GetOverlaps()) { + for ( int i = 0 ; i < icc.GetIntersCount() ; ++i) { + icc.GetIntCrvCrvInfo( i, iccInfo) ; + if( iccInfo.bOverlap){ + ptInters = iccInfo.IciA[1].ptI ; + break ; + } + } } else { - bIntersFound = true ; - if ( aInfo.bOverlap) - ptInters = aInfo.IciA[1].ptI ; - else - ptInters = aInfo.IciA[0].ptI ; + int nLastInters = icc.GetIntersCount() -1 ; + icc.GetIntCrvCrvInfo( nLastInters, iccInfo) ; + ptInters = iccInfo.IciA[0].ptI ; } - if ( clEdge2.IsValid() && ! bIntersFound){ - IntersLineLine illExit2( clTrim, clEdge2, true) ; - // verifico su quale dei due lati ho l'intersezione - if ( ! illExit2.GetIntCrvCrvInfo( aInfo2)) - bIntersFound = false ; - else { - bIntersFound = true ; - //// solo intersezione sul lato 2 - if ( aInfo2.bOverlap) - ptInters = aInfo2.IciA[1].ptI ; - else - ptInters = aInfo2.IciA[0].ptI ; - } - } - if ( ! bIntersFound) - return false ; + // determino il lato/vertice di uscita OnWhichEdge( nId, ptInters, nEdge) ; m_mTree[nId].m_vInters.back().nOut = nEdge ; @@ -2406,7 +2680,7 @@ Tree::FindInters( int& nId, const CurveLine& clTrim, PNTVECTOR& vptInters, bool else if ( nEdge == 7) ptInters = ptTR ; // aggiungo il nuovo punto al vettore delle intersezioni - if ( (int)vptInters.size() == 0 || ! AreSamePointApprox( ptInters , vptInters.back())) + if ( (int)vptInters.size() == 0 || ! AreSamePointEpsilon( ptInters , vptInters.back(), 2 * EPS_SMALL)) vptInters.push_back( ptInters) ; else { // se l'ultimo punto del vettore delle intersezioni è quasi uguale al punto che devo aggiungere allora lo sostituisco con quest'ultimo @@ -2721,24 +2995,46 @@ Tree::FindInters( int& nId, const CurveLine& clTrim, PNTVECTOR& vptInters, bool //---------------------------------------------------------------------------- bool -Tree::CreateCellPolygons( int nLeafId, POLYLINEMATRIX& vPolygons, INTVECTOR& vToCheck, int& nPoly, INTVECTOR& vnParentChunk, const PolyLine& plCell) +Tree::CreateCellPolygons( int nLeafId, POLYLINEMATRIX& vPolygons, POLYLINEMATRIX& vPolygons3d, INTVECTOR& vToCheck, int& nPoly, INTVECTOR& vnParentChunk, + const PolyLine& plCell, const PolyLine& plCell3d) { // conto quanti vertici in più ho per lato e creo un vettore dei vertici per lato int nId = m_vnLeaves[nLeafId] ; - PNTMATRIX vEdgeVertex ; - Point3d ptTl( m_mTree[nId].GetBottomLeft().x, m_mTree[nId].GetTopRight().y) ; - Point3d ptBr( m_mTree[nId].GetTopRight().x, m_mTree[nId].GetBottomLeft().y) ; - vEdgeVertex.emplace_back() ; - vEdgeVertex.back().push_back( m_mTree[nId].GetTopRight()) ; - vEdgeVertex.emplace_back() ; - vEdgeVertex.back().push_back( ptTl) ; - vEdgeVertex.emplace_back() ; - vEdgeVertex.back().push_back( m_mTree[nId].GetBottomLeft()) ; - vEdgeVertex.emplace_back() ; - vEdgeVertex.back().push_back( ptBr) ; + PNTMATRIX vEdgeVertex(4) ; + PNTMATRIX vEdgeVertex3d(4) ; + Point3d ptBL = m_mTree[nId].GetBottomLeft() ; + Point3d ptTR = m_mTree[nId].GetTopRight() ; + Point3d ptTl = m_mTree[nId].GetTopLeft() ; + Point3d ptBr = m_mTree[nId].GetBottomRight() ; + int nVertToErase = m_mTree.at(nId).m_nVertToErase ; + if( nVertToErase != 2) + vEdgeVertex[0].push_back( ptTR) ; + if( nVertToErase != 3) + vEdgeVertex[1].push_back( ptTl) ; + if( nVertToErase != 0) + vEdgeVertex[2].push_back( ptBL) ; + if( nVertToErase != 1) + vEdgeVertex[3].push_back( ptBr) ; + // capisco se sono in modalità ForTriangulation + bool bForTriangulation = plCell3d.GetPointNbr() != 0 ; + if ( bForTriangulation) { + if( nVertToErase != 2) + vEdgeVertex3d[0].push_back( m_mVert[nId][2]) ; + if( nVertToErase != 3) + vEdgeVertex3d[1].push_back( m_mVert[nId][3]) ; + if( nVertToErase != 0) + vEdgeVertex3d[2].push_back( m_mVert[nId][0]) ; + if( nVertToErase != 1) + vEdgeVertex3d[3].push_back( m_mVert[nId][1]) ; + } + + + // la PolyLine è riempita a partire dal lato bottom - Point3d ptStart ; + Point3d ptStart, pt3d ; plCell.GetFirstPoint( ptStart) ; + if ( bForTriangulation) + plCell3d.GetFirstPoint( pt3d) ; INTVECTOR vEdge = { 2, 3, 0, 1} ; for ( int p = 0 ; p < 4 ; ++ p) { int j = vEdge[p] ; @@ -2746,8 +3042,22 @@ Tree::CreateCellPolygons( int nLeafId, POLYLINEMATRIX& vPolygons, INTVECTOR& vTo if ( j == 3) next = 0 ; Point3d ptToAdd ; - while ( plCell.GetNextPoint( ptToAdd) && ! AreSamePointExact( ptToAdd, vEdgeVertex[next][0])) { - vEdgeVertex[j].push_back( ptToAdd) ; + Point3d ptNextVert ; + switch ( next ) { + case 0 : ptNextVert = ptTR ; break ; + case 1 : ptNextVert = ptTl; break ; + case 2 : ptNextVert = ptBL ; break ; + case 3 : ptNextVert = ptBr ; break ; + } + if ( ! bForTriangulation) { + while ( plCell.GetNextPoint( ptToAdd) && ! AreSamePointExact( ptToAdd, ptNextVert)) + vEdgeVertex[j].push_back( ptToAdd) ; + } + else { + while ( plCell.GetNextPoint( ptToAdd) && plCell3d.GetNextPoint( pt3d) && ! AreSamePointExact( ptToAdd, ptNextVert)) { + vEdgeVertex[j].push_back( ptToAdd) ; + vEdgeVertex3d[j].push_back( pt3d) ; + } } } @@ -2755,8 +3065,10 @@ Tree::CreateCellPolygons( int nLeafId, POLYLINEMATRIX& vPolygons, INTVECTOR& vTo INTVECTOR vToCheckNow = vToCheck ; // vettore dei poligoni ( loop) della cella nId POLYLINEVECTOR vCellPolygons ; + POLYLINEVECTOR vCellPolygons3d ; // costruisco i poligoni partendo dal vettore delle intersezioni, come spiegato a pag15 di Cripps PolyLine plTrimmedPoly ; + PolyLine plTrimmedPoly3d ; // numero di volte che la cella è stata attraversata da una curva di trim int nPassToCheck = (int) vToCheckNow.size() ; // numero di vertici aggiunti al nuovo poligono @@ -2781,7 +3093,7 @@ Tree::CreateCellPolygons( int nLeafId, POLYLINEMATRIX& vPolygons, INTVECTOR& vTo nFirstLoopInPoly = j ; } for ( Point3d ptInt : inA.vpt) { - AddVertex( nId, vEdgeVertex, plTrimmedPoly, c, ptInt) ; + AddVertex( nId, vEdgeVertex, vEdgeVertex3d, plTrimmedPoly, c, ptInt, plTrimmedPoly3d, bForTriangulation) ; } vAddedLoops.push_back( j) ; nEdge = inA.nOut ; @@ -2792,73 +3104,36 @@ Tree::CreateCellPolygons( int nLeafId, POLYLINEMATRIX& vPolygons, INTVECTOR& vTo Vector3d vLast = ptLast - ptSecondToLast ; vLast.Normalize() ; Vector3d vEdge ; - //if ( AreSameEdge( nEdge, 0)) { - // if ( AreSamePointExact( ptLast, ptTl)) { - // vEdge = m_mTree[nId].GetBottomLeft() - ptTl ; - // vEdge.Normalize() ; - // if ( AreOppositeVectorApprox( vLast, vEdge)) { - // plTrimmedPoly.EraseLastUPoint() ; - // nEdge = 1 ; - // } - // } - //} - //else if ( AreSameEdge( nEdge, 1) && AreSamePointExact( ptLast, m_mTree[nId].GetBottomLeft())) { - // vEdge = ptBr - m_mTree[nId].GetBottomLeft() ; - // vEdge.Normalize() ; - // if ( AreOppositeVectorApprox( vLast, vEdge)) { - // plTrimmedPoly.EraseLastUPoint() ; - // nEdge = 2 ; - // } - //} - //else if ( AreSameEdge( nEdge, 2)) { - // if ( AreSamePointExact( ptLast, ptBr)) { - // vEdge = m_mTree[nId].GetTopRight() - ptBr ; - // vEdge.Normalize() ; - // if ( AreOppositeVectorApprox( vLast, vEdge)) { - // plTrimmedPoly.EraseLastUPoint() ; - // nEdge = 3 ; - // } - // } - //} - //else if ( AreSameEdge( nEdge, 3) && AreSamePointExact( ptLast, m_mTree[nId].GetTopRight())) { - // vEdge = ptTl - m_mTree[nId].GetTopRight() ; - // vEdge.Normalize() ; - // if ( AreOppositeVectorApprox( vLast, vEdge)) { - // plTrimmedPoly.EraseLastUPoint() ; - // nEdge = 0 ; - // } - //} - // estendo: se l'ultimo tratto è sovrapposto e controverso allora elimino l'ultimo punto if ( nEdge == 0 || nEdge == 7 ) { - //vEdge = ptTl - m_mTree[nId].GetTopRight() ; vEdge.Set( 1,0,0) ; if ( AreOppositeVectorApprox( vLast, vEdge)) { plTrimmedPoly.EraseLastUPoint() ; + plTrimmedPoly3d.EraseLastUPoint() ; nEdge = 0 ; } } else if ( nEdge == 1 || nEdge == 4 ) { - //vEdge = ptBr - m_mTree[nId].GetBottomLeft() ; vEdge.Set( 0,-1,0) ; if ( AreOppositeVectorApprox( vLast, vEdge)) { plTrimmedPoly.EraseLastUPoint() ; + plTrimmedPoly3d.EraseLastUPoint() ; nEdge = 1 ; } } else if ( nEdge == 2 || nEdge == 5 ) { - //vEdge = ptTl - m_mTree[nId].GetTopRight() ; vEdge.Set( -1,0,0) ; if ( AreOppositeVectorApprox( vLast, vEdge)) { plTrimmedPoly.EraseLastUPoint() ; + plTrimmedPoly3d.EraseLastUPoint() ; nEdge = 2 ; } } else if ( nEdge == 3 || nEdge == 6 ) { - //vEdge = m_mTree[nId].GetTopRight() - ptBr ; vEdge.Set( 0,1,0) ; if ( AreOppositeVectorApprox( vLast, vEdge)) { plTrimmedPoly.EraseLastUPoint() ; + plTrimmedPoly3d.EraseLastUPoint() ; nEdge = 3 ; } } @@ -2867,6 +3142,7 @@ Tree::CreateCellPolygons( int nLeafId, POLYLINEMATRIX& vPolygons, INTVECTOR& vTo // quindi salto al prossimo loop if ( plTrimmedPoly.GetPointNbr() == 1) { plTrimmedPoly.Clear() ; + plTrimmedPoly3d.Clear() ; if ( j == nFirstLoopInPoly) nEdgeIn = -1 ; continue ; @@ -2904,12 +3180,12 @@ Tree::CreateCellPolygons( int nLeafId, POLYLINEMATRIX& vPolygons, INTVECTOR& vTo if ( nEdge == 0) ptVert = ptTl ; else if ( nEdge == 1) - ptVert = m_mTree[nId].GetBottomLeft() ; + ptVert = ptBL ; else if ( nEdge == 2) ptVert = ptBr ; else if ( nEdge == 3) - ptVert = m_mTree[nId].GetTopRight() ; - AddVertex( nId, vEdgeVertex, plTrimmedPoly, c, ptVert) ; + ptVert = ptTR ; + AddVertex( nId, vEdgeVertex, vEdgeVertex3d, plTrimmedPoly, c, ptVert, plTrimmedPoly3d, bForTriangulation) ; if ( nEdge > 3 && nEdge != 7) nEdge = nEdge - 4 ; else if ( nEdge < 3) @@ -2929,6 +3205,7 @@ Tree::CreateCellPolygons( int nLeafId, POLYLINEMATRIX& vPolygons, INTVECTOR& vTo for ( int p = 1 ; p < (int) vEdgeVertex[nEdge].size() ; ++ p) { if ( CheckIfBefore( nEdge, vEdgeVertex[nEdge][p], m_mTree[nId].m_vInters[vToCheckNow[nNext]].vpt[0])) { plTrimmedPoly.AddUPoint( c, vEdgeVertex[nEdge][p]) ; + plTrimmedPoly3d.AddUPoint( c, vEdgeVertex3d[nEdge][p]) ; ++ c ; } } @@ -2942,6 +3219,7 @@ Tree::CreateCellPolygons( int nLeafId, POLYLINEMATRIX& vPolygons, INTVECTOR& vTo for ( int p = 1 ; p < (int) vEdgeVertex[nEdge].size() ; ++ p) { if ( CheckIfBefore( nEdge, vEdgeVertex[nEdge][p], ptStart)) { plTrimmedPoly.AddUPoint( c, vEdgeVertex[nEdge][p]) ; + plTrimmedPoly3d.AddUPoint( c, vEdgeVertex3d[nEdge][p]) ; ++ c ; } } @@ -2958,12 +3236,12 @@ Tree::CreateCellPolygons( int nLeafId, POLYLINEMATRIX& vPolygons, INTVECTOR& vTo if ( nEdge == 0) ptVert = ptTl ; else if ( nEdge == 1) - ptVert = m_mTree[nId].GetBottomLeft() ; + ptVert = ptBL ; else if ( nEdge == 2) ptVert = ptBr ; else if ( nEdge == 3) - ptVert = m_mTree[nId].GetTopRight() ; - AddVertex( nId, vEdgeVertex, plTrimmedPoly, c, ptVert) ; + ptVert = ptTR ; + AddVertex( nId, vEdgeVertex, vEdgeVertex3d, plTrimmedPoly, c, ptVert, plTrimmedPoly3d, bForTriangulation) ; if ( nEdge > 3 && nEdge != 7) nEdge = nEdge - 4 ; else if ( nEdge < 3) @@ -2976,12 +3254,14 @@ Tree::CreateCellPolygons( int nLeafId, POLYLINEMATRIX& vPolygons, INTVECTOR& vTo for ( int p = 1 ; p < (int) vEdgeVertex[nEdge].size() ; ++ p) { if ( CheckIfBefore( nEdge, vEdgeVertex[nEdge][p], ptStart)) { plTrimmedPoly.AddUPoint( c, vEdgeVertex[nEdge][p]) ; + plTrimmedPoly3d.AddUPoint( c, vEdgeVertex3d[nEdge][p]) ; ++ c ; } } } plTrimmedPoly.Close() ; + plTrimmedPoly3d.Close() ; // controllo sull'area del poligono, se è 0 ( quindi un segmento), non lo aggiungo double dArea ; plTrimmedPoly.GetAreaXY( dArea) ; @@ -2989,13 +3269,19 @@ Tree::CreateCellPolygons( int nLeafId, POLYLINEMATRIX& vPolygons, INTVECTOR& vTo if ( dArea > 0) { vCellPolygons.push_back( plTrimmedPoly) ; vPolygons.push_back( vCellPolygons) ; + vCellPolygons.clear() ; + if( bForTriangulation) { + vCellPolygons3d.push_back( plTrimmedPoly3d) ; + vPolygons3d.push_back( vCellPolygons3d) ; + vCellPolygons3d.clear() ; + } ++ nPoly ; vnParentChunk.push_back( inA.nChunk) ; - vCellPolygons.clear() ; } c = 0 ; plTrimmedPoly.Clear() ; + plTrimmedPoly3d.Clear() ; nEdgeIn = -1 ; // devo verificare se tra i loop che sono finiti in vToCheck in realtà qualcuno l'ho usato per fare un poligono for ( int k = 0 ; k < (int)vToCheck.size() ; ++ k) { @@ -3014,18 +3300,20 @@ Tree::CreateCellPolygons( int nLeafId, POLYLINEMATRIX& vPolygons, INTVECTOR& vTo //---------------------------------------------------------------------------- bool -Tree::CreateIslandAndHoles( int nLeafId, POLYLINEMATRIX& vPolygons, int& nPoly, INTVECTOR& vnParentChunk) +Tree::CreateIslandAndHoles( int nLeafId, POLYLINEMATRIX& vPolygons, POLYLINEMATRIX& vPolygons3d, int& nPoly, INTVECTOR& vnParentChunk, bool bForTriangulation) { // vettore dei poligoni ( loop) della cella nId POLYLINEVECTOR vCellPolygons ; + POLYLINEVECTOR vCellPolygons3d ; // costruisco i poligoni partendo dal vettore delle intersezioni int nId = m_vnLeaves[nLeafId] ; - PolyLine plTrimmedPoly ; + //capisco se sono in modalità ForTriangulation // loop interni in una cella intersecata int nChunkBiggestCW = -1 ; if ( m_mTree[nId].m_nFlag == 3 || m_mTree[nId].m_nFlag == 2) { PolyLine plInLoop ; + PolyLine plInLoop3d ; Inters inA ; // se ho almeno un loop CW che non è contenuto in un altro poligono o in un loop interno CCW devo aggiungere il bordo bool bAllContained = true ; @@ -3062,18 +3350,26 @@ Tree::CreateIslandAndHoles( int nLeafId, POLYLINEMATRIX& vPolygons, int& nPoly, // i loop esterni sono CW, quindi prima dei loop di trim aggiungo il bordo cella Point3d ptVert = m_mTree[nId].GetTopRight() ; plInLoop.AddUPoint( 0, ptVert) ; - ptVert.x = m_mTree[nId].GetBottomLeft().x ; - ptVert.y = m_mTree[nId].GetTopRight().y ; + ptVert = m_mTree[nId].GetTopLeft() ; plInLoop.AddUPoint( 1, ptVert) ; ptVert = m_mTree[nId].GetBottomLeft() ; plInLoop.AddUPoint( 2, ptVert) ; - ptVert.x = m_mTree[nId].GetTopRight().x ; - ptVert.y = m_mTree[nId].GetBottomLeft().y ; + ptVert = m_mTree[nId].GetBottomRight() ; plInLoop.AddUPoint( 3, ptVert) ; plInLoop.Close() ; vCellPolygons.push_back( plInLoop) ; vPolygons.push_back( vCellPolygons) ; ++ nPoly ; + if ( bForTriangulation) { + plInLoop3d.AddUPoint( 0, m_mVert[nId][2]); + plInLoop3d.AddUPoint( 1, m_mVert[nId][3]); + plInLoop3d.AddUPoint( 2, m_mVert[nId][0]); + plInLoop3d.AddUPoint( 3, m_mVert[nId][1]); + vCellPolygons3d.push_back( plInLoop3d) ; + vPolygons3d.push_back( vCellPolygons3d) ; + vCellPolygons3d.clear() ; + plInLoop3d.Clear() ; + } // imposto il chunk del loop CW più grande ( il primo che ho incontrato) vnParentChunk.push_back( nChunkBiggestCW) ; vCellPolygons.clear() ; @@ -3086,9 +3382,15 @@ Tree::CreateIslandAndHoles( int nLeafId, POLYLINEMATRIX& vPolygons, int& nPoly, int k = 0 ; for ( Point3d ptInt : inA.vpt) { plInLoop.AddUPoint( k, ptInt) ; + if ( bForTriangulation) { + Point3d pt3d ; m_pSrfBz->GetPointD1D2( ptInt.x / SBZ_TREG_COEFF, ptInt.y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt3d) ; + plInLoop3d.AddUPoint( k, pt3d) ; + } ++ k ; } plInLoop.Close() ; + if ( bForTriangulation) + plInLoop3d.Close() ; bool bAdded = false ; // se il loop è CW devo controllare in quale altro dei poligoni che ho già aggiunto è contenuto if ( ! inA.bCCW) { @@ -3099,6 +3401,10 @@ Tree::CreateIslandAndHoles( int nLeafId, POLYLINEMATRIX& vPolygons, int& nPoly, if ( IsPointInsidePolyLine( ptStart, vPolygons[nOtherPoly - r - 1][0], -0.01) && vnParentChunk[nPoly - r - 1] == inA.nChunk) { vPolygons[nOtherPoly - r - 1].push_back( plInLoop) ; plInLoop.Clear() ; + if ( bForTriangulation) { + vPolygons3d[nOtherPoly - r - 1].push_back( plInLoop3d) ; + plInLoop3d.Clear() ; + } bAdded = true ; break ; } @@ -3107,12 +3413,20 @@ Tree::CreateIslandAndHoles( int nLeafId, POLYLINEMATRIX& vPolygons, int& nPoly, if ( ! bAdded) { vCellPolygons.push_back( plInLoop) ; vPolygons.push_back( vCellPolygons) ; - ++ nPoly ; - vnParentChunk.push_back( inA.nChunk) ; plInLoop.Clear() ; vCellPolygons.clear() ; + if ( bForTriangulation) { + vCellPolygons3d.push_back( plInLoop3d) ; + vPolygons3d.push_back( vCellPolygons3d) ; + plInLoop3d.Clear() ; + vCellPolygons3d.clear() ; + } + ++ nPoly ; + vnParentChunk.push_back( inA.nChunk) ; } plInLoop.Clear() ; + if ( bForTriangulation) + plInLoop3d.Clear() ; } else continue ; @@ -3271,18 +3585,24 @@ Tree::AreSameEdge( int nEdge1, int nEdge2) const //---------------------------------------------------------------------------- bool -Tree::AddVertex( int nId, const PNTMATRIX& vEdgeVertex, PolyLine& plTrimmedPoly, int& c, const Point3d& ptToAdd) const +Tree::AddVertex( int nId, const PNTMATRIX& vEdgeVertex, const PNTMATRIX& vEdgeVertex3d, PolyLine& plTrimmedPoly, int& c, + const Point3d& ptToAdd, PolyLine& plTrimmedPoly3d, bool bForTriangulation) const { // se è il primo punto della PolyLine lo aggiungo if ( plTrimmedPoly.GetPointNbr() == 0) { plTrimmedPoly.AddUPoint( c, ptToAdd) ; + if ( bForTriangulation) { + Point3d pt3d ; + m_pSrfBz->GetPointD1D2( ptToAdd.x / SBZ_TREG_COEFF, ptToAdd.y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt3d) ; + plTrimmedPoly3d.AddUPoint( c, pt3d) ; + } ++ c ; return true ; } - Point3d ptBr = vEdgeVertex[3][0] ; - Point3d ptTR = vEdgeVertex[0][0] ; - Point3d ptTl = vEdgeVertex[1][0] ; - Point3d ptBL = vEdgeVertex[2][0] ; + Point3d ptBr = m_mTree.at(nId).GetBottomRight() ; + Point3d ptTR = m_mTree.at(nId).GetTopRight() ; + Point3d ptTl = m_mTree.at(nId).GetTopLeft() ; + Point3d ptBL = m_mTree.at(nId).GetBottomLeft() ; Point3d ptLast ; plTrimmedPoly.GetLastPoint( ptLast) ; // verifico di essere allineato con un lato, sennò aggiungo e basta @@ -3290,20 +3610,39 @@ Tree::AddVertex( int nId, const PNTMATRIX& vEdgeVertex, PolyLine& plTrimmedPoly, if ( ! AreSamePointApprox( ptToAdd, ptLast)) vDir = ptToAdd - ptLast ; else - return true ; + return false ; // se non riesco a normalizzare perché sono troppo vicino ad un vertice allora aggiungo direttamente il vertice if ( ! vDir.Normalize()) { plTrimmedPoly.EraseLastUPoint() ; - if ( AreSamePointApprox( ptToAdd, ptBr)) - plTrimmedPoly.AddUPoint( c, ptBr) ; - else if ( AreSamePointApprox( ptToAdd, ptTR)) - plTrimmedPoly.AddUPoint( c, ptTR) ; - else if ( AreSamePointApprox( ptToAdd, ptTl)) - plTrimmedPoly.AddUPoint( c, ptTl) ; - else if ( AreSamePointApprox( ptToAdd, ptBL)) - plTrimmedPoly.AddUPoint( c, ptBL) ; + Point3d ptVert ; + int nVert = -1 ; + if ( AreSamePointApprox( ptToAdd, ptBr)){ + ptVert = ptBr ; + nVert = 1 ; + } + else if ( AreSamePointApprox( ptToAdd, ptTR)) { + ptVert = ptTR ; + nVert = 2 ; + } + else if ( AreSamePointApprox( ptToAdd, ptTl)) { + ptVert = ptTl ; + nVert = 3 ; + } + else if ( AreSamePointApprox( ptToAdd, ptBL)) { + ptVert = ptBL ; + nVert = 0 ; + } else - plTrimmedPoly.AddUPoint( c, ptToAdd) ; + ptVert = ptToAdd ; + plTrimmedPoly.AddUPoint( c, ptVert) ; + if( bForTriangulation){ + Point3d pt3d ; + if ( nVert != -1) + pt3d = m_mVert.at(nId)[nVert] ; + else + m_pSrfBz->GetPointD1D2( ptVert.x, ptVert.y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt3d) ; + plTrimmedPoly3d.AddUPoint( c, pt3d) ; + } ++ c ; return true ; } @@ -3311,62 +3650,110 @@ Tree::AddVertex( int nId, const PNTMATRIX& vEdgeVertex, PolyLine& plTrimmedPoly, // se su un edge devo fare dei controlli // edge 0 if ( ptToAdd.x >= ptBL.x && ptToAdd.x <= ptTR.x && ptToAdd.y == ptTR.y && abs( vDir.x) > 1 - EPS_SMALL) { - for ( int t = 0 ; t < (int)vEdgeVertex[0].size() ; ++ t) { + for ( int t = 1 ; t < (int)vEdgeVertex[0].size() ; ++ t) { Point3d ptIntermed = vEdgeVertex[0][t] ; if ( ptIntermed.x > ptToAdd.x && ptIntermed.x < ptLast.x) { plTrimmedPoly.AddUPoint( c, ptIntermed) ; + if( bForTriangulation) + plTrimmedPoly3d.AddUPoint( c, vEdgeVertex3d[0][t]) ; ++ c ; } } plTrimmedPoly.AddUPoint( c, ptToAdd) ; + if( bForTriangulation){ + Point3d pt3d ; + if( ! AreSamePointApprox(ptToAdd, ptTl)) + m_pSrfBz->GetPointD1D2( ptToAdd.x / SBZ_TREG_COEFF, ptToAdd.y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt3d) ; + else + pt3d = vEdgeVertex3d[1][0] ; + plTrimmedPoly3d.AddUPoint( c, pt3d) ; + } ++ c ; } // edge 1 else if ( ptToAdd.y >= ptBL.y && ptToAdd.y <= ptTR.y && ptToAdd.x == ptBL.x && abs( vDir.y) > 1 - EPS_SMALL) { - for ( int t = 0 ; t < (int)vEdgeVertex[1].size() ; ++ t) { + for ( int t = 1 ; t < (int)vEdgeVertex[1].size() ; ++ t) { Point3d ptIntermed = vEdgeVertex[1][t] ; if ( ptIntermed.y > ptToAdd.y && ptIntermed.y < ptLast.y) { plTrimmedPoly.AddUPoint( c, ptIntermed) ; + if( bForTriangulation) + plTrimmedPoly3d.AddUPoint( c, vEdgeVertex3d[1][t]) ; ++ c ; } } plTrimmedPoly.AddUPoint( c, ptToAdd) ; + if( bForTriangulation) { + Point3d pt3d ; + if( ! AreSamePointApprox(ptToAdd, ptBL)) + m_pSrfBz->GetPointD1D2( ptToAdd.x / SBZ_TREG_COEFF, ptToAdd.y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt3d) ; + else + pt3d = vEdgeVertex3d[2][0] ; + plTrimmedPoly3d.AddUPoint( c, pt3d) ; + } ++ c ; } // edge 2 else if ( ptToAdd.x >= ptBL.x && ptToAdd.x <= ptTR.x && ptToAdd.y == ptBL.y && abs( vDir.x) > 1 - EPS_SMALL) { - for ( int t = 0 ; t < (int)vEdgeVertex[2].size() ; ++ t) { + for ( int t = 1 ; t < (int)vEdgeVertex[2].size() ; ++ t) { Point3d ptIntermed = vEdgeVertex[2][t] ; if ( ptIntermed.x < ptToAdd.x && ptIntermed.x > ptLast.x) { plTrimmedPoly.AddUPoint( c, ptIntermed) ; + if( bForTriangulation) + plTrimmedPoly3d.AddUPoint( c, vEdgeVertex3d[2][t]) ; ++ c ; } } plTrimmedPoly.AddUPoint( c, ptToAdd) ; + if( bForTriangulation){ + Point3d pt3d ; + if( ! AreSamePointApprox(ptToAdd, ptBr)) + m_pSrfBz->GetPointD1D2( ptToAdd.x / SBZ_TREG_COEFF, ptToAdd.y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt3d) ; + else + pt3d = vEdgeVertex3d[3][0] ; + plTrimmedPoly3d.AddUPoint( c, pt3d) ; + } ++ c ; } // edge 3 else if ( ptToAdd.y >= ptBL.y && ptToAdd.y <= ptTR.y && ptToAdd.x == ptTR.x && abs( vDir.y) > 1 - EPS_SMALL) { - for ( int t = 0 ; t < (int)vEdgeVertex[3].size() ; ++ t) { + for ( int t = 1 ; t < (int)vEdgeVertex[3].size() ; ++ t) { Point3d ptIntermed = vEdgeVertex[3][t] ; if ( ptIntermed.y < ptToAdd.y && ptIntermed.y > ptLast.y) { plTrimmedPoly.AddUPoint( c, ptIntermed) ; + if( bForTriangulation) + plTrimmedPoly3d.AddUPoint( c, vEdgeVertex3d[3][t]) ; ++ c ; } } plTrimmedPoly.AddUPoint( c, ptToAdd) ; + if( bForTriangulation) { + Point3d pt3d ; + if( ! AreSamePointApprox(ptToAdd, ptTR)) + m_pSrfBz->GetPointD1D2( ptToAdd.x / SBZ_TREG_COEFF, ptToAdd.y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt3d) ; + else + pt3d = vEdgeVertex3d[0][0] ; + plTrimmedPoly3d.AddUPoint( c, pt3d) ; + } ++ c ; } // sono allineato con un lato, ma NON sono su un lato // aggiungo e basta else { plTrimmedPoly.AddUPoint( c, ptToAdd) ; + if( bForTriangulation) { + Point3d pt3d ; m_pSrfBz->GetPointD1D2( ptToAdd.x / SBZ_TREG_COEFF, ptToAdd.y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt3d) ; + plTrimmedPoly3d.AddUPoint( c, pt3d) ; + } ++ c ; } } // non su un edge, quindi aggiungo e basta else { plTrimmedPoly.AddUPoint( c, ptToAdd) ; + if( bForTriangulation) { + Point3d pt3d ; m_pSrfBz->GetPointD1D2( ptToAdd.x / SBZ_TREG_COEFF, ptToAdd.y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt3d) ; + plTrimmedPoly3d.AddUPoint( c, pt3d) ; + } ++ c ; } return true ; @@ -3984,6 +4371,7 @@ Tree::AddCutsToRoot( POLYLINEVECTOR& vCuts) bool Tree::AdjustCuts( void) { + // correzione del verso dei tagli aperti 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 @@ -4025,10 +4413,19 @@ Tree::CreateCellContour( POLYLINEMATRIX& vPolygons) pl.AddUPoint(2, m_mTree.at(nRoot).GetBottomLeft()) ; pl.AddUPoint(3, m_mTree.at(nRoot).GetBottomRight()) ; pl.Close() ; + PolyLine pl3d ; + pl3d.AddUPoint(0, m_mVert.at(nRoot)[2]) ; + pl3d.AddUPoint(1, m_mVert.at(nRoot)[3]) ; + pl3d.AddUPoint(2, m_mVert.at(nRoot)[0]) ; + pl3d.AddUPoint(3, m_mVert.at(nRoot)[1]) ; + pl3d.Close() ; // ora posso creare il poligono della cella con i tagli + POLYLINEMATRIX vPolygons3d ; while( (int)vToCheck.size() != 0) { int nPolyBefore = nPoly ; - CreateCellPolygons( 0, vPolygons, vToCheck, nPoly, vnParentChunk, pl) ; + CreateCellPolygons( 0, vPolygons, vPolygons3d, vToCheck, nPoly, vnParentChunk, pl, pl3d) ; // l'aggiunta di vPolygons3d forse è un problema in questo punto. + // sarà da valutare quando si aggiungerà la funzione per aggiungere tagli aperti + // e se si vuole usare la funzione su uno spazio 2D ideale non collegato ad una sup di Bezier if ( nPolyBefore == nPoly) break ; } diff --git a/Tree.h b/Tree.h index 39a6cd1..7d6a1e8 100644 --- a/Tree.h +++ b/Tree.h @@ -155,7 +155,7 @@ class Cell ~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_nFlag2( 0), m_nRightEdgeIn( -1), m_bOnLeftEdge( false), m_bOnTopEdge( false), + m_nChild1( -2), m_nChild2( -2), m_nFlag( -1), m_nFlag2( 0), 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) ; @@ -163,7 +163,7 @@ class Cell } 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_nFlag2( 0), m_nRightEdgeIn( -1), m_bOnLeftEdge( false), m_bOnTopEdge( false), + m_nChild1( -2), m_nChild2( -2), m_nFlag( -1), m_nFlag2( 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) ; } @@ -185,9 +185,9 @@ class Cell { return Point3d( m_ptPtr.x, m_ptPbl.y); } 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, sennò orizzontalmente { return m_bSplitVert ; } - bool IsLeaf( void) const // flag che indica se la cella ha figli o se � una foglia + bool IsLeaf( void) const // flag che indica se la cella ha figli o se è una foglia { return ( m_nChild1 == -2 && m_nChild2 == -2) ; } bool IsProcessed( void) const // flag che indica se tutti i figli della cella, se ce ne sono, sono stati processati { return m_bProcessed ; } @@ -217,6 +217,7 @@ class Cell bool m_bOnTopEdge ; // flag che indica se la cella è sul lato top ( per superfici chiuse sul parametro V) std::vector m_vInters ; // vettore delle intersezioni della cella con i loop di trim // ogni elemento del vettore è l'insieme dei punti che caratterizza un attraversamento della cella + int m_nVertToErase ; // vertice da eliminare dal poligono della cella, in caso di lato sovrapposto ad un lato di polo private : Point3d m_ptPbl ; // punto bottom left @@ -235,12 +236,17 @@ class Tree 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( 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) ; - bool GetPolygons( POLYLINEMATRIX& vPolygons) ; - 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 GetPolygons( POLYLINEMATRIX& vvPolygons) ; + bool GetPolygons( POLYLINEMATRIX& vvPolygons, POLYLINEMATRIX& vvPolygons3d) ; + bool GetPolygons( POLYLINEMATRIX& vPolygons, bool bForTriangulation, POLYLINEMATRIX& vvPolygons3d) ; + bool GetPolygonsBasic( POLYLINEVECTOR& vPolygons, bool bForTriangulation, POLYLINEVECTOR& vPolygons3d, 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 + // se richiesti per la triangolazione ad alcuni poligoni potrebbero venire tolti dei punti per evitare errori dovuti ad eventuali poli sui bordi del parametrico + bool GetPolygonsBasic( POLYLINEVECTOR& vPolygons, POLYLINEVECTOR& vPolygons3d) ; + bool GetPolygonsBasic( POLYLINEVECTOR& vPolygons, INTVECTOR vCells = {}) ; bool GetLeaves ( std::vector& vLeaves) const ; // restituisce gli indici delle foglie nell'albero bool GetEdges3D ( POLYLINEMATRIX& mPLEdges) ; // restituisce gli edge 3D come polyline bool GetSplitLoops( POLYLINEVECTOR& vPl) const // funzione che restituisce i loop splitatti ai confini delle celle @@ -256,8 +262,8 @@ class Tree private : bool LimitLoop( PolyLine& pl, POLYLINEVECTOR& vPl, BOOLVECTOR& vbOrientation) const ; // funzione che limita i loop di trim allo spazio parametrico 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 + 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 void GetTopNeigh( int nId, INTVECTOR& vTopNeighs) const ; // restituisce le celle foglie che sono adiacenti al lato top @@ -268,17 +274,18 @@ class Tree 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 - bool FindInters( int& nId, const CurveLine& clTrim, PNTVECTOR& vptInters, bool bFirstInters = true) ; // trova le intersezioni tra una cella e una linea di trim + bool TraceLoopLabelCell( const POLYLINEVECTOR& vplPolygons) ; // tracing dei loop e labelling delle celle + bool FindInters( int& nId, const CurveLine& clTrim, const PolyLine& plPolygon, PNTVECTOR& vptInters, bool bFirstInters = true) ; // trova le intersezioni tra una cella e una linea di trim // resituisce l'id della cella verso cui la curva di trim esce e il vettore delle intersezioni per la cella successiva con il primo punto - bool CreateCellPolygons( int nLeafId, POLYLINEMATRIX& vPolygons, INTVECTOR& vToCheck, int& nPoly, INTVECTOR& vnParentChunk, const PolyLine& plCell) ; // crea i poligoni della cella passata. richiede anche la funzione CreateIslandAndHoles per completare i poligoni. - bool CreateIslandAndHoles( int nLeafId, POLYLINEMATRIX& vPolygons, int& nPoly, INTVECTOR& vnParentChunk) ; // ai poligoni generati da CreatePolygonsCell aggiunge i loop che creano isole o buchi all'interno della singola cella + bool CreateCellPolygons( int nLeafId, POLYLINEMATRIX& vPolygons, POLYLINEMATRIX& vPolygons3d, INTVECTOR& vToCheck, int& nPoly, INTVECTOR& vnParentChunk, const PolyLine& plCell, const PolyLine& plCell3d) ; // crea i poligoni della cella passata. richiede anche la funzione CreateIslandAndHoles per completare i poligoni. + bool CreateIslandAndHoles( int nLeafId, POLYLINEMATRIX& vPolygons, POLYLINEMATRIX& vvPolygons3d, int& nPoly, INTVECTOR& vnParentChunk, bool bForTriangulation) ; // ai poligoni generati da CreatePolygonsCell aggiunge i loop che creano isole o buchi all'interno della singola cella bool CheckIfBefore( const PolyLine& pl, int nEdge) const ; // controllo se ptEnd è prima di ptStart sul lato nEdge rispetto al senso antiorario bool CheckIfBefore( const Inters& inA) const ; // controlla se l'ingresso è prima dell'uscita in senso antiorario a partire da ptTR. bool CheckIfBefore( int nEdge1, const Point3d& ptP1, int nEdge2, const Point3d& ptP2) const ; // verifico quale punto viene prima tra pt1 e pt2 a partire da ptTR girando in senso CCW (punto 1 su edge 1 e punto 2 su edge 2, rispetto al lato 3) bool CheckIfBefore( int nEdge, const Point3d& ptP1, const Point3d& ptP2, int nEdge2 = -1) const ; // sul lato nEdge controllo se ptP1 viene prima di ptP2. bool AreSameEdge( int nEdge1, int nEdge2) const ; // indica se i due edge sono lo stesso. Un vertice adiacente ad un edge viene considerato uguale a questo edge - bool AddVertex( int nId, const PNTMATRIX& vEdgeVertex, PolyLine& plTrimmedPoly, int& c, const Point3d& ptToAdd) const ; // aggiunge un punto ad un poligono in una cella, premurandosi di aggiungere eventualmente vertici o punti di celle vicine di cui tenere conto + bool AddVertex( int nId, const PNTMATRIX& vEdgeVertex, const PNTMATRIX& vEdgeVertex3d, PolyLine& plTrimmedPoly, int& c, + const Point3d& ptToAdd, PolyLine& plTrimmedPoly3d, bool ForTriangulation) const ; // aggiunge un punto ad un poligono in una cella, premurandosi di aggiungere eventualmente vertici o punti di celle vicine di cui tenere conto bool SetRightEdgeIn( int nId) ; // categorizza la cella in base all'edge destro per poter poi definire m_nFlag bool CategorizeCell( int nId) ; // categorizza la cella in base al flag m_nFlag (dentro, fuori, intersecata) bool CheckIfBetween( const Inters& inA, const Inters& inB) const ; // / controllo se inB è compreso tra l'end e lo start di inA (in senso CCW) @@ -310,8 +317,9 @@ class Tree int m_nSpanU ; // numero di span lungo il parametro U int m_nSpanV ; // numero di span lungo il parametro V POLYLINEMATRIX m_vPolygons ; // matrice dei poligoni del tree - std::map m_mTree ; // mappa che contiene tutti i nodi e le foglie dell'albero. -2 � puntatore Null e -1 � root - std::map m_mVert ; // mappa che contiene tutti i vertici 3d delle celle del tree. L'Id � lo stesso che la cella ha in m_mTree + POLYLINEMATRIX m_vPolygons3d ; // matrice dei poligoni3d del tree + std::map m_mTree ; // mappa che contiene tutti i nodi e le foglie dell'albero. -2 è puntatore Null e -1 è root + std::map m_mVert ; // mappa che contiene tutti i vertici 3d delle celle del tree. L'Id è lo stesso che la cella ha in m_mTree. I punti sono nell'ordine P00, P10, P11, P01 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