diff --git a/CurveAux.cpp b/CurveAux.cpp index dec95b4..6d0043c 100644 --- a/CurveAux.cpp +++ b/CurveAux.cpp @@ -25,9 +25,13 @@ #include "/EgtDev/Include/EGkStringUtils3d.h" #include "/EgtDev/Include/EGkUiUnits.h" #include "/EgtDev/Include/EgtPointerOwner.h" +#include "/EgtDev/Extern/Eigen/Dense" using namespace std ; +static bool FindSpan( double dU, int nDeg, const DBLVECTOR& vKnots, int& nSpan) ; +static bool CalcBasisFunc( double dU, int nDeg, const DBLVECTOR& vKnots, DBLVECTOR& vBasis) ; + //---------------------------------------------------------------------------- bool IsClosed( const ICurve& crvC) @@ -420,12 +424,14 @@ CurveToBezierCurve( const ICurve* pCrv, int nDeg, bool bMakeRatOrNot) switch ( pCrv->GetType()) { case CRV_LINE :{ const ICurveLine* pCrvLine = static_cast( pCrv) ; - pBezierForm.Set( LineToBezierCurve( pCrvLine, nDeg, bMakeRatOrNot)) ; + int nDegWanted = nDeg == -1 ? 3 : nDeg ; + pBezierForm.Set( LineToBezierCurve( pCrvLine, nDegWanted, bMakeRatOrNot)) ; break ; } case CRV_ARC : { const ICurveArc* pCrvArc = static_cast( pCrv) ; - pBezierForm.Set( ArcToBezierCurve( pCrvArc, nDeg, bMakeRatOrNot)) ; + int nDegWanted = nDeg == -1 ? 3 : nDeg ; + pBezierForm.Set( ArcToBezierCurve( pCrvArc, nDegWanted, bMakeRatOrNot)) ; break ; } case CRV_COMPO : { @@ -557,12 +563,17 @@ CompositeToBezierCurve( const ICurveComposite* pCC, int nDeg, bool bMakeRatOrNot ICurve* EditBezierCurve( const ICurveBezier* pCrvBezier, int nDeg, bool bMakeRatOrNot, double dTol) { - if( nDeg < 3) + // se nDeg == -1 allora viene mantenuto il grado della curva originale + + if( nDeg == 2 || nDeg == 1) return nullptr ; - // dovrei restituire una bezier di grado 2, razionale per poter essere uniforme con le altre curve trasmorate in bezier + PtrOwner pCrvNew( pCrvBezier->Clone()) ; + int nDegCurr = pCrvNew->GetDegree() ; + bool bRat = pCrvNew->IsRational() ; + int nDegWanted = nDeg == -1 ? nDegCurr : nDeg ; if( ! bMakeRatOrNot) { - if( ! pCrvNew->MakeNonRational( 10 * EPS_SMALL)) { + if( ! pCrvNew->MakeNonRational( dTol)) { // se ho fallito la conversione diretta in curva non razionale allora la spezzo in bezier cubiche PtrOwner pBezCubics( CreateCurveComposite()) ; pBezCubics->AddCurve( ApproxBezierWithCubics(pCrvBezier, dTol)) ; @@ -570,17 +581,15 @@ EditBezierCurve( const ICurveBezier* pCrvBezier, int nDeg, bool bMakeRatOrNot, d return nullptr ; // adatto ogni sottocurva cubica PtrOwner pCCEdited( CreateCurveComposite()) ; + for ( int i = 0 ; i < pBezCubics->GetCurveCount() ; ++i) { - if( ! pCCEdited->AddCurve( EditBezierCurve( GetCurveBezier( pBezCubics->GetCurve( i)), nDeg, bMakeRatOrNot, dTol)) ) + if( ! pCCEdited->AddCurve( EditBezierCurve( GetCurveBezier( pBezCubics->GetCurve( i)), nDegWanted, bMakeRatOrNot, dTol)) ) return nullptr ; } return Release( pCCEdited) ; } } - int nDegCurr = pCrvNew->GetDegree() ; - bool bRat = pCrvNew->IsRational() ; // se la curva è già nella forma giusta la restituisco - int nDegWanted = nDeg ; if ( nDegCurr == nDegWanted && ( ( ! bRat && ! bMakeRatOrNot) || (bRat && bMakeRatOrNot))) return Release( pCrvNew) ; // sennò mi porto al grado giusto @@ -1022,6 +1031,141 @@ ApproxCurveWithBezier( const ICurve*, double dTol) return Release( pCC) ; } +//---------------------------------------------------------------------------- +ICurve* +InterpolatePointSetWithBezier( const PNTVECTOR& vPnt, double dTol) +{ + PtrOwner pCrvInt ; + // pag 364 del Piegl + // scelgo il parametro associato ad ogni punto in modo che rispecchi la distanza tra i punti + + int nPoints = vPnt.size() ; + if( nPoints < 4) + return nullptr ; + int nDeg = 3 ; + DBLVECTOR vLen ; + double dLenTot = 0 ; + for ( int i = 0 ; i < int( nPoints -1) ; ++i) { + double dLen = Dist(vPnt[i], vPnt[i+1]) ; + vLen.push_back( dLen) ; + dLenTot += dLen ; + } + DBLVECTOR vPntParam ; + vPntParam.resize( nPoints) ; + vPntParam[0] = 0 ; + vPntParam.back() = 1 ; + for ( int i = 1 ; i < int( nPoints - 1) ; ++i) + vPntParam[i] = vPntParam[i-1] + vLen[i-1] / dLenTot ; + + DBLVECTOR vKnots ; + vKnots.resize( nPoints + nDeg - 1) ; + for ( int i = 0 ; i < nDeg ; ++i) { + vKnots[i] = 0 ; + vKnots.end()[-i-1] = 1 ; + } + + for ( int i = nDeg ; i < nPoints - 1 ; ++i) { + double dKnot = 0 ; + for ( int j = i ; j < i + nDeg ; ++j) + dKnot += vPntParam[j - nDeg] ; + dKnot /= nDeg ; + vKnots[i] = dKnot ; + } + + Eigen::MatrixXd mA( nPoints, nPoints) ; + mA.fill( 0) ; + for ( int i = 0 ; i < nPoints ; ++i) { + int nSpan = 0 ; FindSpan(vPntParam[i], nDeg, vKnots, nSpan) ; + if ( i == 0) + mA.row(0).col(0) << 1 ; + else if ( i == nPoints - 1) + mA.row(i).col(nPoints - 1) << 1 ; + else { + DBLVECTOR vBasis ; vBasis.resize( nDeg + 1) ; + CalcBasisFunc( vPntParam[i], nDeg, vKnots, vBasis) ; + for( int j = nSpan - nDeg ; j < nSpan ; ++j) + mA.row(i).col(j) << vBasis[j - nSpan + nDeg] ; + } + } + + int nDim = 3 ; + Eigen::MatrixXd mb ; mb.resize( nPoints, nDim) ; + Eigen::MatrixXd mX = mA.fullPivLu().solve(mb) ; + + PNTVECTOR vPntCtrl ; + for ( int i = 0 ; i < nPoints ; ++i) + vPntCtrl.emplace_back( mX(i,0), mX(i,1), mX(i,2)) ; + CNurbsData cNurbs ; + cNurbs.nDeg = nDeg ; + cNurbs.vCP = vPntCtrl ; + cNurbs.vU = vKnots ; + cNurbs.bRat = false ; + + pCrvInt.Set( NurbsToBezierCurve( cNurbs)) ; + + return Release( pCrvInt) ; +} + +//---------------------------------------------------------------------------- +static bool +FindSpan( double dU, int nDeg, const DBLVECTOR& vKnots, int& nSpan) +{ + if( dU < 0) + return false ; + else if( dU < EPS_ZERO) { + nSpan = nDeg ; + return true ; + } + // trovo a quale span appartiene il parametro dU + int nKnots = int( vKnots.size()) ; + if( abs( dU - vKnots[nKnots-1]) < EPS_SMALL) { + nSpan = nKnots - 1 ; + return true ; + } + int nLow = nDeg ; + int nHigh = nKnots ; + int nMid = ( nLow + nHigh) / 2 ; + while ( dU < vKnots[nMid] || dU > vKnots[nMid + 1] ) { + if ( dU < vKnots[nMid]) + nHigh = nMid ; + else + nLow = nMid ; + nMid = ( nLow + nHigh) / 2 ; + if( nMid == nDeg) + break ; + } + nSpan = nMid ; + return true ; +} + +//---------------------------------------------------------------------------- +static bool +CalcBasisFunc( double dU, int nDeg, const DBLVECTOR& vKnots, DBLVECTOR& vBasis) +{ + // mi aspetto che il vettore vBasis sia di lunghezza nDeg + 1 + if( vBasis.size() != nDeg + 1) + return false ; + + int nSpan = 0 ; + FindSpan( dU, nDeg, vKnots, nSpan) ; + + vBasis[0] = 1 ; + DBLVECTOR vLeft ; vLeft.resize( nDeg + 1) ; + DBLVECTOR vRight ; vRight.resize( nDeg + 1) ; + for ( int j = 1 ; j <= nDeg ; ++j) { + vLeft[j] = dU - vKnots[nSpan + 1 -j] ; + vRight[j] = vKnots[nSpan + j] - dU ; + double dSaved = 0 ; + for ( int r = 0 ; r < j ; ++r) { + double dTemp = vBasis[r] / ( vRight[r+1] + vLeft[j-r]) ; + vBasis[r] = dSaved + vRight[r+1] * dTemp ; + dSaved = vLeft[j-r] * dTemp ; + } + vBasis[j] = dSaved ; + } + return true ; +} + //---------------------------------------------------------------------------- bool CalcBezierApproxError( const ICurveBezier* pCrvOri, const ICurveBezier* pCrvNew, double& dErr, int nPoints) diff --git a/CurveBezier.cpp b/CurveBezier.cpp index c54c194..b0b1824 100644 --- a/CurveBezier.cpp +++ b/CurveBezier.cpp @@ -2367,3 +2367,19 @@ CurveBezier::MakeNonRational( double dTol) return bOk ; } + +//---------------------------------------------------------------------------- +bool +CurveBezier::IsALine( void) const +{ + Point3d ptStart ; GetStartPoint( ptStart) ; + Point3d ptEnd ; GetEndPoint( ptEnd) ; + for ( int i = 1 ; i < m_nDeg ; ++i) { + Point3d ptCtrl = GetControlPoint( i) ; + DistPointLine dpl( ptCtrl, ptStart, ptEnd) ; + double dDist = 0 ; dpl.GetDist( dDist) ; + if( dDist > EPS_SMALL) + return false ; + } + return true ; +} diff --git a/CurveBezier.h b/CurveBezier.h index 2bee20c..9f045bd 100644 --- a/CurveBezier.h +++ b/CurveBezier.h @@ -152,6 +152,7 @@ class CurveBezier : public ICurveBezier, public IGeoObjRW bool MakeRational( void) override ; bool MakeRationalStandardForm( void) override ; bool MakeNonRational( double dTol) override ; + bool IsALine( void) const override ; public : // IGeoObjRW int GetNgeId( void) const override ; diff --git a/SbzFromCurves.cpp b/SbzFromCurves.cpp index 09bcf8d..4925389 100644 --- a/SbzFromCurves.cpp +++ b/SbzFromCurves.cpp @@ -20,6 +20,7 @@ #include "SurfTriMesh.h" #include "SurfBezier.h" #include "Voronoi.h" +#include "/EgtDev/Include/EGkDistPointLine.h" #include "/EgtDev/Include/EGkSfrCreate.h" #include "/EgtDev/Include/EGkOffsetCurve.h" #include "/EgtDev/Include/EGkStmFromCurves.h" @@ -49,8 +50,7 @@ GetSurfBezierByFlatContour( const ICurve* pCurve, double dLinTol) PtrOwner pSbz( CreateBasicSurfBezier()) ; if ( IsNull( pSbz) || ! pSbz->CreateByFlatContour( PL)) return nullptr ; - //// salvo tolleranza lineare usata - //pSTM->SetLinearTolerance( dLinTol) ; + // restituisco la superficie return Release( pSbz) ; } @@ -205,12 +205,6 @@ GetSurfBezierByRevolve( const ICurve* pCurve, const Point3d& ptAx, const Vector3 //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 @@ -255,8 +249,7 @@ GetSurfBezierByRevolve( const ICurve* pCurve, const Point3d& ptAx, const Vector3 double dVol ; if ( pSbz->GetVolume( dVol) && dVol < 0) pSbz->Invert() ; - //// salvo tolleranza lineare usata - //pSbz->SetLinearTolerance( dLinTol) ; + // restituisco la superficie return Release( pSbz) ; } @@ -276,17 +269,6 @@ GetSurfBezierByScrewing( const ICurve* pCurve, const Point3d& ptAx, const Vector 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)) @@ -322,8 +304,7 @@ GetSurfBezierByScrewing( const ICurve* pCurve, const Point3d& ptAx, const Vector double dVol ; if ( pSbz->GetVolume( dVol) && dVol < 0) pSbz->Invert() ; - //// salvo tolleranza lineare usata - //pSTM->SetLinearTolerance( dLinTol) ; + // restituisco la superficie return Release( pSbz) ; } @@ -653,254 +634,376 @@ GetSurfBezierByScrewing( const ICurve* pCurve, const Point3d& ptAx, const Vector // 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* +GetSurfBezierSweptInPlane( const ICurve* pSect, const ICurve* pGuide, const Vector3d& vtNorm, bool bCapEnds, double dLinTol) +{ + // 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) ; + + // capisco se la guida è una linea spezzata o una curva + bool bGuideIsPolyLine = false ; + switch( pGuide->GetType()) { + case CRV_COMPO : { + bGuideIsPolyLine = true ; + const ICurveComposite* pCC = GetCurveComposite( pGuide) ; + for ( int i = 0 ; i < pCC->GetCurveCount() && bGuideIsPolyLine ; ++i) { + const ICurve* pCrv = pCC->GetCurve( i) ; + if( pCrv->GetType() != CRV_LINE) { + if ( pCrv->GetType() == CRV_BEZIER) { + const ICurveBezier* pCrvBez = GetCurveBezier( pCrv) ; + bGuideIsPolyLine = pCrvBez->IsALine() ; + } + else + bGuideIsPolyLine = false ; + } + } + break ; + } + case CRV_LINE : + bGuideIsPolyLine = true ; + break ; + case CRV_BEZIER : { + // controllo se i punti di controllo sono allineati + const ICurveBezier* pCrvBez = GetCurveBezier( pGuide) ; + bGuideIsPolyLine = pCrvBez->IsALine() ; + break ; + } + default : + break ; + } + + bool bRat = false ; + int nSpanV = 0 ; + PtrOwner pCrvV( CreateCurveComposite()) ; + if ( bGuideIsPolyLine ) { + if( pGuide->GetType() == CRV_LINE) + nSpanV = 1 ; + else if ( pGuide->GetType() == CRV_COMPO) + nSpanV = GetCurveComposite( pGuide)->GetCurveCount() ; + } + else { + //converto in bezier la guida ( grado 3, non razionale) + if ( pGuide->GetType() != CRV_BEZIER) + pCrvV->AddCurve( CurveToBezierCurve( pGuide, 3, false)) ; + else { + const ICurveBezier* pGuideBez = GetCurveBezier( pGuide) ; + if( ! pGuideBez->IsRational()) + pCrvV->AddCurve( pGuide->Clone()) ; + else + pCrvV->AddCurve( EditBezierCurve( pGuideBez, 3, false)) ; + } + if ( IsNull( pCrvV) || ! pCrvV->IsValid()) + return nullptr ; + nSpanV = pCrvV->GetCurveCount() ; + } + + // converto in bezier la sezione ( grado 3, non razionale) + PtrOwner pCrvU( CreateCurveComposite()) ; + if ( pSect->GetType() != CRV_BEZIER) + pCrvU->AddCurve( CurveToBezierCurve( pSect, 3, false)) ; + else { + const ICurveBezier* pSectBez = GetCurveBezier( pSect) ; + if( ! pSectBez->IsRational()) + pCrvU->AddCurve( pSect->Clone()) ; + else + pCrvU->AddCurve( EditBezierCurve( pSectBez, 3, false)) ; + } + if ( IsNull( pCrvU) || ! pCrvU->IsValid()) + return nullptr ; + int nSpanU = int( pCrvU->GetCurveCount()) ; + + int nDegV = 3 ; + if ( bGuideIsPolyLine) + nDegV = 1 ; + + int nDegU = 9 ; + // superficie swept + PtrOwner pSurfBez( CreateSurfBezier()) ; + pSurfBez->Init( nDegU,nDegV, nSpanU, nSpanV, bRat) ; + + if ( bGuideIsPolyLine) { + frStart.Set( ptStart, -vtStart, vtStart ^ vtNorm) ; + // porto la sezione nel sistema di riferimento del piano in cui giace + pCrvU->ToLoc( frStart) ; + // la guida è una linea spezzata, quindi posso lavorare con gli offset + for( int i = 0 ; i < nSpanU ; ++i) { + const ICurveBezier* pSubCrv = GetCurveBezier( pCrvU->GetCurve( i)) ; + for ( int j = i==0 ? 0 : 1 ; j < nDegU + 1 ; ++j ) { + Point3d ptCtrl = pSubCrv->GetControlPoint( j) ; + // faccio l'offset della guida nel punto di controllo della sezione + OffsetCurve OffsCrv ; + if ( ! OffsCrv.Make( pGuide, ptCtrl.x, ICurve::OFF_EXTEND) || OffsCrv.GetCurveCount() == 0) + return nullptr ; + PtrOwner pCrvV( CreateCurveComposite()) ; + pCrvV->AddCurve( OffsCrv.GetLongerCurve()) ; + if ( IsNull( pCrvV)) + return nullptr ; + pCrvV->Translate( ptCtrl.y * frStart.VersY()) ; + if( pCrvV->GetCurveCount() != nSpanV) + return nullptr ; + // aggiungo i punti di controllo alla superficie + for ( int z = 0 ; z < nSpanV ; ++z) { + const ICurveLine* pCL = GetCurveLine( pCrvV->GetCurve( z)) ; + if( pCL == nullptr) + return nullptr ; + if( z == 0) { + Point3d ptSubStart ; pCL->GetStartPoint( ptSubStart) ; + pSurfBez->SetControlPoint( i * nDegU + j, 0, ptSubStart) ; + } + Point3d ptSubEnd ; pCL->GetEndPoint( ptSubEnd) ; + pSurfBez->SetControlPoint( i * nDegU + j, z + 1, ptSubEnd) ; + } + } + } + } + else { + + // VERSIONE con le copie della sezione ( superficie skinned) + + // creo delle copie della curva e faccio la skinned + // per ogni sottocurva della guida ( che sarà composta da curve di bezier di grado 3) + // posiziono una copia della curva di sezione per ogni punto di controllo + frStart.Set( ptStart, vtStart) ; + pCrvU->ToLoc( frStart) ; + ICURVEPOVECTOR vCrvSet ; + CICURVEPVECTOR vpCrv ; + RotationMinimizingFrame rmfGuide ; rmfGuide.Set( pCrvV, frStart) ; + double dStep = 0.25 ; + FRAME3DVECTOR vFrame ; + int nSpanV = pCrvV->GetCurveCount() ; + int nSplit = 8 * nSpanV ; + rmfGuide.GetFramesBySplit( nSplit, vFrame) ; + + for ( int i = 0 ; i < nSpanV ; ++i) { + for ( int j = i==0 ? 0 : 1 ; j < nSplit ; ++j) { + ICurve* pNewSect = pCrvU->Clone() ; + pNewSect->ToGlob( vFrame[j]) ; // da sistemare se ho più curve e in base allo step di divisione + vpCrv.push_back( pNewSect) ; + vCrvSet.emplace_back( pNewSect) ; + } + } + + return GetSurfBezierSkinned( vpCrv, dLinTol) ; + + + + //////VERSIONE con l'offset dei punti di controllo // richiede l'interpolazione dei punti + // + //// faccio l'offset della guida e poi riconverto i risultati in curve di bezier tramite interpolazione + // + //frStart.Set( ptStart, -vtStart, vtStart ^ vtNorm) ; + //// porto la sezione nel sistema di riferimento del piano in cui giace + //pCrvU->ToLoc( frStart) ; + //for( int i = 0 ; i < nSpanU ; ++i) { + // const ICurveBezier* pSubCrv = GetCurveBezier( pCrvU->GetCurve( i)) ; + // for ( int j = i==0 ? 0 : 1 ; j < nDegU + 1 ; ++j ) { + // Point3d ptCtrl = pSubCrv->GetControlPoint( j) ; + // // faccio l'offset della guida nel punto di controllo della sezione + // OffsetCurve OffsCrv ; + // if ( ! OffsCrv.Make( pGuide, ptCtrl.x, ICurve::OFF_EXTEND) || OffsCrv.GetCurveCount() == 0) + // return nullptr ; + // PtrOwner pCrvV( CreateCurveComposite()) ; + // pCrvV->AddCurve( OffsCrv.GetLongerCurve()) ; + // if ( IsNull( pCrvV)) + // return nullptr ; + // pCrvV->Translate( ptCtrl.y * frStart.VersY()) ; + // PNTVECTOR vPnt ; + // int nOffCrvs = pCrvV->GetCurveCount() ; + // for ( int z = 0 ; z < nOffCrvs ; ++z) { + // Point3d ptCtrl ; + // if ( z == 0) { + // pCrvV->GetCurve(z)->GetStartPoint( ptCtrl) ; + // vPnt.push_back( ptCtrl) ; + // } + // pCrvV->GetCurve(z)->GetEndPoint( ptCtrl) ; + // vPnt.push_back( ptCtrl) ; + // } + // pCrvV.Set( CreateCurveComposite()) ; + // pCrvV->AddCurve( InterpolatePointSetWithBezier( vPnt, dLinTol)) ; + // + // + // nSpanV = pCrvV->GetCurveCount() ; + // pSurfBez->Init( nDegU,nDegV, nSpanU, nSpanV, bRat) ; /// NON POSSO REINIZIALIZZARE LA SURF QUI! + // /// QUANDO INIZIO A INSERIRE I PUNTI DI CONTROLLO DEVO AVER DEFINITO nSpanV + // + // + // // aggiungo i punti di controllo alla superficie + // for ( int z = 0 ; z < nSpanV ; ++z) { + // const ICurveBezier* pCrvBez = GetCurveBezier( pCrvV->GetCurve( z)) ; + // if( pCrvBez == nullptr) + // return nullptr ; + // for ( int k = z == 0 ? 0 : 1 ; k < nDegV ; ++k) { + // Point3d ptCtrl = pCrvBez->GetControlPoint( k) ; + // pSurfBez->SetControlPoint( i * nDegU + j, z * nDegV + k, ptCtrl) ; + // } + // } + // } + //} + } + + + + + //// se richiesti caps e sezione chiusa e guida aperta + if ( bCapEnds && bSectClosed && ! bGuideClosed) { + // verifico che le due estremità siano chiuse e piatte + + } + + // restituisco la superficie + return Release( pSurfBez) ; +} + +//------------------------------------------------------------------------------- +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 nullptr ; +} + ////------------------------------------------------------------------------------- //ISurfBezier* //GetSurfTriMeshSwept( const ICurve* pSect, const ICurve* pGuide, const Vector3d& vtAx,