//---------------------------------------------------------------------------- // EgalTech 2013-2013 //---------------------------------------------------------------------------- // File : CurveAux.cpp Data : 22.11.13 Versione : 1.3a1 // Contenuto : Implementazione di alcune funzioni di utilità per le curve. // // // // Modifiche : 22.11.13 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "CurveAux.h" #include "GeoConst.h" #include "/EgtDev/Include/EgkCurveComposite.h" #include "/EgtDev/Include/EgkCurveBezier.h" #include "/EgtDev/Include/EgkCurveArc.h" #include "/EgtDev/Include/EgtPointerOwner.h" //---------------------------------------------------------------------------- bool IsClosed( const ICurve& crvC) { Point3d ptStart ; Point3d ptEnd ; return ( crvC.GetStartPoint( ptStart) && crvC.GetEndPoint( ptEnd) && AreSamePointNear( ptStart, ptEnd)) ; } //---------------------------------------------------------------------------- bool GetTang( const ICurve& crvC, double dU, ICurve::Side nS, Vector3d& vtTang) { Point3d ptPos ; return GetPointTang( crvC, dU, nS, ptPos, vtTang) ; } //---------------------------------------------------------------------------- bool GetPointTang( const ICurve& crvC, double dU, ICurve::Side nS, Point3d& ptPos, Vector3d& vtTang) { if ( ! crvC.GetPointD1D2( dU, nS, ptPos, &vtTang)) return false ; if ( vtTang.Normalize()) return true ; // nel caso la derivata prima sia nulla, utilizziamo la seconda Vector3d vtDummy ; if ( ! crvC.GetPointD1D2( dU, nS, ptPos, &vtDummy, &vtTang)) return false ; return vtTang.Normalize() ; } //---------------------------------------------------------------------------- bool GetPointDiffGeom( const ICurve& crvC, double dU, ICurve::Side nS, CrvPointDiffGeom& oDiffG) { double dSqLenD1 ; Point3d ptPos ; Vector3d vtDer1 ; Vector3d vtDer2 ; if ( ! crvC.GetPointD1D2( dU, nS, ptPos, &vtDer1, &vtDer2)) return false ; // assegno parametro e posizione oDiffG.dU = dU ; oDiffG.ptP = ptPos ; // se esiste la derivata prima non nulla dSqLenD1 = vtDer1.SqLen() ; if ( vtDer1.Normalize()) { oDiffG.vtT = vtDer1 ; // del vettore deriv2^ tengo la sola componente perpendicolare al vettore tangente oDiffG.vtN = vtDer2 - ( vtDer2 * vtDer1) * vtDer1 ; if ( oDiffG.vtN.Normalize()) { oDiffG.dCurv = ( vtDer1 ^ vtDer2).Len() / dSqLenD1 ; oDiffG.nStatus = CrvPointDiffGeom::NCRV ; } else { oDiffG.dCurv = 0 ; oDiffG.nStatus = CrvPointDiffGeom::TANG ; } } // se esiste almeno derivata seconda non nulla, definisce la tangente else if ( vtDer2.Normalize()) { oDiffG.vtT = vtDer2 ; oDiffG.vtN.Set( 0, 0, 0) ; oDiffG.dCurv = 0 ; oDiffG.nStatus = CrvPointDiffGeom::TANG ; } // altrimenti non sono definite la tangente e la normale else { oDiffG.vtT.Set( 0, 0, 0) ; oDiffG.vtN.Set( 0, 0, 0) ; oDiffG.dCurv = 0 ; oDiffG.nStatus = CrvPointDiffGeom::POS ; } return true ; } //---------------------------------------------------------------------------- bool ArcToBezierCurve( const ICurve* pCrv, ICurve*& pCrvNew) { // verifico sia un arco const ICurveArc* pArc = GetCurveArc( pCrv) ; if ( pArc == nullptr) return false ; // se angolo al centro sotto il limite, basta una curva if ( fabs( pArc->GetAngCenter()) <= BEZARC_ANG_CEN_MAX) { // creo la curva di Bezier PtrOwner pCrvBez( CreateCurveBezier()) ; if ( ! IsValid( pCrvBez)) return false ; if ( ! pCrvBez->FromArc( *pArc)) return false ; // restituisco la curva pCrvNew = Release( pCrvBez) ; } // altrimenti curva composita di Bezier else { // creo la curva composita PtrOwner pCrvCompo( CreateCurveComposite()) ; if ( ! IsValid( pCrvCompo)) return false ; if ( ! pCrvCompo->AddCurve( *pArc) || ! pCrvCompo->ArcsToBezierCurves()) return false ; // restituisco la curva pCrvNew = Release( pCrvCompo) ; } return true ; } //---------------------------------------------------------------------------- bool NurbsCurveCanonicalize( CNurbsData& cnData) { // se periodica if ( cnData.bPeriodic) { // va trasformata in non-periodica (clamped) // vedere The NurbsBook di Les Piegl e Tiller // mancano esempi per testare return false ; } // se con nodi extra if ( cnData.bExtraKnotes) { int nKnotesNbr = int( cnData.vU.size()) ; if ( nKnotesNbr < 4) return false ; cnData.bExtraKnotes = false ; for ( int i = 0 ; i < nKnotesNbr - 2 ; ++ i) cnData.vU[i] = cnData.vU[i+1] ; cnData.vU.resize( nKnotesNbr - 2) ; return true ; } return true ; } //---------------------------------------------------------------------------- bool NurbsToBezierCurve( const CNurbsData& cnData, ICurve*& pCrvNew) { // la curva Nurbs deve essere in forma canonica if ( cnData.bPeriodic || cnData.bExtraKnotes) return false ; // numero dei nodi int nU = int( cnData.vCP.size()) + cnData.nDeg - 1 ; // controllo relazione nodi - punti di controllo if ( nU != int( cnData.vU.size())) return false ; // numero degli intervalli int nInt = nU - 2 * cnData.nDeg + 1 ; // se 1 solo intervallo, la Nurbs è già una curva di Bezier if ( nInt == 1) { // creo la curva di Bezier PtrOwner pCrvBez( CreateCurveBezier()) ; if ( ! IsValid( pCrvBez)) return false ; // la inizializzo if ( ! pCrvBez->Init( cnData.nDeg, cnData.bRat)) return false ; for ( int i = 0 ; i <= cnData.nDeg ; ++ i) { if ( ! cnData.bRat) { if ( ! pCrvBez->SetControlPoint( i, cnData.vCP[i])) return false ; } else { if ( ! pCrvBez->SetControlPoint( i, cnData.vCP[i], cnData.vW[i])) return false ; } } // restituisco la curva pCrvNew = Release( pCrvBez) ; return true ; } // altrimenti è equivalente ad una curva composita, la creo PtrOwner pCrvCompo( CreateCurveComposite()) ; if ( ! IsValid( pCrvCompo)) return false ; // vettore dei punti di controllo della curva di Bezier PNTVECTOR vBC ; vBC.resize( cnData.nDeg + 1) ; DBLVECTOR vBW ; vBW.resize( cnData.nDeg + 1) ; if ( ! cnData.bRat) { for ( int i = 0 ; i <= cnData.nDeg ; ++ i) vBC[i] = cnData.vCP[i] ; } else { for ( int i = 0 ; i <= cnData.nDeg ; ++ i) { vBC[i] = cnData.vCP[i] * cnData.vW[i] ; vBW[i] = cnData.vW[i] ; } } // primi coefficienti della successiva PNTVECTOR vNextBC ; vNextBC.resize( cnData.nDeg - 1) ; DBLVECTOR vNextBW ; vNextBW.resize( cnData.nDeg - 1) ; // ... DBLVECTOR vAlfa ; vAlfa.resize( cnData.nDeg - 1) ; int a = cnData.nDeg - 1 ; int b = cnData.nDeg ; // ciclo while ( b < nU - 1) { int i = b ; while ( b < nU - 1 && fabs( cnData.vU[b+1] - cnData.vU[b]) < EPS_ZERO) ++ b ; int mult = std::min( b - i + 1, cnData.nDeg) ; if ( mult < cnData.nDeg) { // numeratore di alfa double numer = cnData.vU[b] - cnData.vU[a] ; // calcola e salva gli alfa for ( int j = cnData.nDeg ; j > mult ; -- j) vAlfa[j-mult-1] = numer / ( cnData.vU[a+j] - cnData.vU[a]) ; // inserisco il nodo r volte int r = cnData.nDeg - mult ; for ( int j = 1 ; j <= r ; ++ j) { int save = r - j ; int s = mult + j ; for ( int k = cnData.nDeg ; k >= s ; -- k) vBC[k] = vAlfa[k-s] * vBC[k] + ( 1 - vAlfa[k-s]) * vBC[k-1] ; if ( cnData.bRat) { for ( int k = cnData.nDeg ; k >= s ; -- k) vBW[k] = vAlfa[k-s] * vBW[k] + ( 1 - vAlfa[k-s]) * vBW[k-1] ; } if ( b < nU - 1) { vNextBC[save] = vBC[cnData.nDeg] ; if ( cnData.bRat) vNextBW[save] = vBW[cnData.nDeg] ; } } } // costruisco la curva di Bezier e la inserisco nella curva composita PtrOwner pCrvBez( CreateCurveBezier()) ; if ( ! IsValid( pCrvBez)) return false ; // la inizializzo if ( ! pCrvBez->Init( cnData.nDeg, cnData.bRat)) return false ; if ( ! cnData.bRat) { for ( int i = 0 ; i <= cnData.nDeg ; ++ i) { if ( ! pCrvBez->SetControlPoint( i, vBC[i])) return false ; } } else { for ( int i = 0 ; i <= cnData.nDeg ; ++ i) { if ( ! pCrvBez->SetControlPoint( i, vBC[i] / vBW[i], vBW[i])) return false ; } } // la aggiungo alla curva composita if ( ! pCrvCompo->AddCurve( Release( pCrvBez))) return false ; // inizializzazioni per la prossima curva di Bezier if ( b < nU - 1) { if ( ! cnData.bRat) { for ( int i = 0 ; i < cnData.nDeg - 1 ; ++ i) vBC[i] = vNextBC[i] ; for ( int i = cnData.nDeg - mult ; i <= cnData.nDeg ; ++ i) vBC[i] = cnData.vCP[b-cnData.nDeg+i+1] ; } else { for ( int i = 0 ; i < cnData.nDeg - 1 ; ++ i) { vBC[i] = vNextBC[i] ; vBW[i] = vNextBW[i] ; } for ( int i = cnData.nDeg - mult ; i <= cnData.nDeg ; ++ i) { vBC[i] = cnData.vCP[b-cnData.nDeg+i+1] * cnData.vW[b-cnData.nDeg+i+1] ; vBW[i] = cnData.vW[b-cnData.nDeg+i+1] ; } } a = b ; ++ b ; } } // restituisco la curva composita pCrvNew = Release( pCrvCompo) ; return true ; }