diff --git a/SbzFromCurves.cpp b/SbzFromCurves.cpp index af0d46e..09ddf2e 100644 --- a/SbzFromCurves.cpp +++ b/SbzFromCurves.cpp @@ -726,7 +726,7 @@ GetSurfBezierRuled( const ICurve* pCurve1, const ICurve* pCurve2, int nType, dou // creo e setto la superficie trimesh PtrOwner pSbz( CreateBasicSurfBezier()) ; - if ( IsNull( pSbz) || ! pSbz->CreateByTwoCurves( pCC1, pCC2, nType)) + if ( IsNull( pSbz) || ! pSbz->CreateSmoothByTwoCurves( pCC1, pCC2, 10)) return nullptr ; // restituisco la superficie diff --git a/SurfBezier.cpp b/SurfBezier.cpp index 70ebca4..079eba6 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -52,7 +52,9 @@ #define SAVEMATCHCURVES 0 #define SAVEFAILEDTREE 0 #define SAVELIMITSURF 0 -#if SAVEFAILEDTRIANGULATION || SAVEREBUILTISO || SAVERULEDISO || SAVERULEDGUIDEDISO || SAVEMATCHCURVES || SAVEFAILEDTREE || SAVELIMITSURF +#define SAVEPACEDISO 1 +#if SAVEFAILEDTRIANGULATION || SAVEREBUILTISO || SAVERULEDISO || SAVERULEDGUIDEDISO || SAVEMATCHCURVES \ + || SAVEFAILEDTREE || SAVELIMITSURF || SAVEPACEDISO #include "/EgtDev/Include/EGkGeoObjSave.h" std::vector vGeo ; #endif @@ -5213,19 +5215,6 @@ SurfBezier::CreateByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, int i = c ; } } - //// faccio un merge di regioni adiacenti di mismatch - //int nCurr = 0, nNext = 1 ; - //while ( nNext < ssize( vMismatch0)) { - // if ( vMismatch0[nNext].first - vMismatch0[nCurr].second < 2 + EPS_SMALL) { - // vMismatch0[nCurr].second = vMismatch0[nNext].second ; - // } - // else { - // ++nCurr ; - // vMismatch0[nCurr] = vMismatch0[nNext] ; - // } - // ++nNext ; - //} - //vMismatch0.resize( nCurr + 1) ; DBLVECTOR vdDistMismatch1 ; int nPnt1 = CrvU1.GetCurveCount() ; @@ -5248,19 +5237,6 @@ SurfBezier::CreateByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, int i = c ; } } - //// faccio un merge di regioni adiacenti di mismatch - //nCurr = 0, nNext = 1 ; - //while ( nNext < ssize( vMismatch1)) { - // if ( vMismatch1[nNext].first - vMismatch1[nCurr].second < 2 + EPS_SMALL) { - // vMismatch1[nCurr].second = vMismatch1[nNext].second ; - // } - // else { - // ++nCurr ; - // vMismatch1[nCurr] = vMismatch1[nNext] ; - // } - // ++nNext ; - //} - //vMismatch1.resize( nCurr + 1) ; // verifico la presenza di eventuali "edge" lungo le polyline ( punti di passaggio di un edge e quindi cambi bruschi di direzione della polyline) BOOLVECTOR vEdgeSplit0, vEdgeSplit1 ; @@ -5920,6 +5896,263 @@ SurfBezier::CreateByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, int return true ; } +struct Edge { + Vector3d vtPrev ; + Vector3d vtCurr ; + Point3d ptCurr ; + Edge(const Vector3d& _vtPrev, const Vector3d& _vtCurr, const Point3d& _ptCurr) : + vtPrev( _vtPrev), vtCurr( _vtCurr), ptCurr( _ptCurr) {;} +}; +typedef vector EDGEVECTOR ; + +//---------------------------------------------------------------------------- +bool +SurfBezier::CreateSmoothByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, double dSampleLen) +{ + // converto in bezier la curva iniziale + CurveComposite CrvU0 ; + // 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) + CrvU0.AddCurve( CurveToBezierCurve( pCurve0)) ; + else + CrvU0.AddCurve( pCurve0->Clone()) ; + } + else + CrvU0.AddCurve( pCurve0->Clone()) ; + if ( ! CrvU0.IsValid()) + return false ; + // recupero span e grado nel parametro U + int nSpanU0 = int( CrvU0.GetCurveCount()) ; + int nDegU0 = ( GetCurveBezier( CrvU0.GetCurve(0)))->GetDegree() ; + bool bRat0 = (GetCurveBezier( CrvU0.GetCurve(0)))->IsRational() ; + // se la curva è già una bezier singola la tengo, sennò la converto + CurveComposite CrvU1 ; + // 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) + CrvU1.AddCurve( CurveToBezierCurve( pCurve1)) ; + else + CrvU1.AddCurve( pCurve1->Clone()) ; + } + else + CrvU1.AddCurve( pCurve1->Clone()) ; + // recupero span e grado nel parametro U + int nSpanU1 = int( CrvU1.GetCurveCount()) ; + int nDegU1 = ( GetCurveBezier( CrvU1.GetCurve(0)))->GetDegree() ; + bool bRat1 = (GetCurveBezier( CrvU1.GetCurve(0)))->IsRational() ; + // se le due curve hanno grado diverso allora aumento il grado di quella con grado inferiore + if ( nDegU0 != nDegU1) { + while ( nDegU0 < nDegU1) { + CurveComposite CC ; + for ( int k = 0 ; k < nSpanU0 ; ++k) + CC.AddCurve( BezierIncreaseDegree( GetCurveBezier( CrvU0.GetCurve( k)))) ; + ++nDegU0 ; + CrvU0 = CC ; + } + while ( nDegU0 > nDegU1) { + CurveComposite CC ; + for ( int k = 0 ; k < nSpanU0 ; ++k) + CC.AddCurve( BezierIncreaseDegree( GetCurveBezier( CrvU1.GetCurve( k)))) ; + ++nDegU1 ; + CrvU1 = CC ; + } + } + // omogenizzo la razionalità + if ( bRat0 != bRat1) { + if ( bRat0) { + CurveComposite CC ; + for ( int k = 0 ; k < nSpanU0 ; ++k) { + const ICurveBezier* pCrvBez = GetCurveBezier( CrvU0.GetCurve( k)) ; + CC.AddCurve( EditBezierCurve( pCrvBez, nDegU0, false)) ; + } + CrvU0 = CC ; + bRat0 = false ; + } + if ( bRat1) { + CurveComposite CC ; + for ( int k = 0 ; k < nSpanU1 ; ++k) { + const ICurveBezier* pCrvBez = GetCurveBezier( CrvU1.GetCurve( k)) ; + CC.AddCurve( EditBezierCurve( pCrvBez, nDegU0, false)) ; + } + CrvU1 = CC ; + bRat1 = false ; + } + } + + 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 ; + + bool bIsClosed0 = CrvU0.IsClosed() ; + bool bIsClosed1 = CrvU1.IsClosed() ; + + BIPNTVECTOR vPairs ; + + // Recupero parametri iniziali + double dLen0 ; CrvU0.GetLength( dLen0) ; + double dLen1 ; CrvU1.GetLength( dLen1) ; + double dUS0, dUE0 ; CrvU0.GetDomain( dUS0, dUE0) ; + double dUS1, dUE1 ; CrvU1.GetDomain( dUS1, dUE1) ; + double dLenPrev0 = 0., dLenCurr0 = 0. ; + double dLenPrev1 = 0., dLenCurr1 = 0. ; + double dUPrev0 = 0., dUCurr0 = 0. ; + double dUPrev1 = 0., dUCurr1 = 0. ; + Point3d ptPrev0, ptCurr0 ; CrvU0.GetStartPoint( ptPrev0) ; + Point3d ptPrev1, ptCurr1 ; CrvU1.GetStartPoint( ptPrev1) ; + Vector3d vtCurr0 = V_NULL, vtCurr1 = V_NULL ; + +#if SAVEPACEDISO + vGeo.clear() ; +#endif + + while ( dLenPrev0 + dSampleLen < dLen0 - EPS_ZERO) { + // Recupero dU, Point3d e dLen corrente sul primo bordo, per un incremento del passo di campionamento + dLenCurr0 = Clamp( dLenPrev0 + dSampleLen, 0., dLen0) ; + CrvU0.GetParamAtLength( dLenCurr0, dUCurr0) ; + CrvU0.GetPointD1D2( dUCurr0, ICurve::FROM_MINUS, ptCurr0, &vtCurr0) ; + vtCurr0.Normalize() ; + + // --- Piano di taglio per punto a minima distanza + IntersCurvePlane ICP( CrvU1, ptCurr0, vtCurr0) ; + bool bOkPlane = ( ICP.GetIntersPointNearTo( ptPrev1, ptCurr1, dUCurr1) && dUCurr1 > dUPrev1) ; + if ( ! bOkPlane) { + // --- Cerco il punto a minima distanza + DistPointCurve DPC( ptCurr0, CrvU1) ; + int nFlag ; + bool bOkMinDist = ( DPC.GetParamAtMinDistPoint( dUPrev1, dUCurr1, nFlag) && dUCurr1 > dUPrev1) ; + if ( ! bOkMinDist) { + // --- Aumento la distanza corrente del passo di campionamento + double dLen = Clamp( dLenPrev1 + dSampleLen, 0., dLen1) ; + CrvU1.GetParamAtLength( dLen, dUCurr1) ; + } + } + + // Recupero il punto corrente e la direzione tangente sul secondo bordo + CrvU1.GetLengthAtParam( dUCurr1, dLenCurr1) ; + CrvU1.GetPointD1D2( dUCurr1, ICurve::FROM_MINUS, ptCurr1, &vtCurr1) ; + vtCurr1.Normalize() ; + + // Verifico se le direzioni tangenti sono tra di loro circa parallele + const double COS_ANG_TOL = cos( 10. * DEGTORAD) ; + if ( vtCurr0 * vtCurr1 < COS_ANG_TOL) { + // Se fuori dalla tolleranza, recupero il miglior versore tangente sul secondo bordo nell'intervallo successivo di lunghezza ( 1. * dMyDist) + CrvU1.GetLengthAtPoint( ptCurr1, dLenCurr1) ; + double dLimInfLen1 = Clamp( dLenCurr1 - dSampleLen, dLenPrev1, dLen1) ; + double dLimSupLen1 = Clamp( dLenCurr1 + dSampleLen, dLenPrev1, dLen1) ; + // [Controllo migliorabile, magari mendiante metodo di bisezione (?)] + const int NUM_STEP = 20 ; + double dMinCos = - 1. - EPS_ZERO ; + for ( int i = 0 ; i <= NUM_STEP ; ++ i) { + double dLen = dLimInfLen1 + i * ( dLimSupLen1 - dLimInfLen1) / NUM_STEP ; + double dUStep1 ; CrvU1.GetParamAtLength( dLen, dUStep1) ; + Point3d ptStep1 ; Vector3d vtStep1 = V_NULL ; + CrvU1.GetPointD1D2( dUStep1, ICurve::FROM_MINUS, ptStep1, &vtStep1) ; vtStep1.Normalize() ; + double dStepCos1 = vtCurr0 * vtStep1 ; + if ( dStepCos1 > dMinCos) { + ptCurr1 = ptStep1 ; + vtCurr1 = vtStep1 ; + dUCurr1 = dUStep1 ; + dMinCos = dStepCos1 ; + } + } + } + + // analizzo l'eventuale presenza di edge + int nSubCrv = int( ceil( dUPrev0)) ; + EDGEVECTOR vEdge0, vEdge1 ; + double dCosEdge = cos( 35. * DEGTORAD) ; + while ( nSubCrv < dUCurr0) { + if ( nSubCrv == 0 && ! bIsClosed0) + continue ; + int nPrevCrv = ( nSubCrv > 0 ? nSubCrv - 1 : int( dUE0 - 1)) ; + Vector3d vtPrev ; CrvU0.GetCurve( nPrevCrv)->GetEndDir( vtPrev) ; + Point3d ptCurr ; CrvU0.GetCurve( nPrevCrv)->GetEndPoint( ptCurr) ; + CrvU0.GetCurve( nSubCrv)->GetStartDir( vtCurr0) ; + vtCurr0.Normalize() ; + vtPrev.Normalize() ; + if ( vtPrev * vtCurr0 < dCosEdge) + vEdge0.emplace_back( vtPrev, vtCurr0, ptCurr) ; + ++ nSubCrv ; + } + nSubCrv = int( ceil( dUPrev1)) ; + while ( nSubCrv < dUCurr1) { + if ( nSubCrv == 0 && ! bIsClosed0) + continue ; + int nPrevCrv = ( nSubCrv > 0 ? nSubCrv - 1 : int( dUE1 - 1)) ; + Vector3d vtPrev ; CrvU1.GetCurve( nPrevCrv)->GetEndDir( vtPrev) ; + Point3d ptCurr ; CrvU1.GetCurve( nPrevCrv)->GetEndPoint( ptCurr) ; + CrvU1.GetCurve( nSubCrv)->GetStartDir( vtCurr1) ; + vtCurr1.Normalize() ; + vtPrev.Normalize() ; + if ( vtPrev * vtCurr1 < dCosEdge) + vEdge1.emplace_back( vtPrev, vtCurr1, ptCurr) ; + ++ nSubCrv ; + } + if ( ssize( vEdge0) > 0 && ssize( vEdge1) > 0) { + int c = 0 ; + for ( int i = 0 ; i < ssize( vEdge0) ; ++i) { + for ( int j = c ; j < ssize( vEdge1) ; ++j) { + if ( vEdge0[i].vtPrev * vEdge1[j].vtPrev > COS_ANG_TOL || vEdge0[i].vtCurr * vEdge1[j].vtCurr > COS_ANG_TOL) { + vPairs.emplace_back( vEdge0[i].ptCurr, vEdge1[j].ptCurr) ; + c = j + 1 ; + break ; + } + } + } + } + +#if SAVEPACEDISO + ICurveLine* CL = CreateCurveLine() ; CL->Set( ptCurr0, ptCurr1) ; + vGeo.push_back( CL) ; +#endif + + // Inserisco le curve di sincronizzazione nel Layer di destinazine + vPairs.emplace_back( ptCurr0, ptCurr1) ; + + // Aggiorno i parametri + ptPrev0 = ptCurr0 ; dUPrev0 = dUCurr0 ; dLenPrev0 = dLenCurr0 ; + ptPrev1 = ptCurr1 ; dUPrev1 = dUCurr1 ; dLenPrev1 = dLenCurr1 ; + } + +#if SAVEPACEDISO + SaveGeoObj( vGeo, "D:\\Temp\\bezier\\ruled\\smoothness\\iso.nge") ; +#endif + + return CreateByIsoParamSet( &CrvU0, &CrvU1, vPairs) ; +} + //---------------------------------------------------------------------------- bool SurfBezier::FindMatchByParam( const PolyLine& pl0, const PolyLine& pl1, INTVECTOR& vMatch, int& nLong) const @@ -6535,14 +6768,17 @@ SurfBezier::CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, c // se non ho corrispondenza allora aggiungo uno split sulla curva a cui manca il punto corrispondente else if ( vdParamPos0[c0] < vdParamPos1[c1]) { double dPar ; CrvU1.GetParamAtLength( dLenPrev1 + dLen1 * vdParamPos0[c0], dPar) ; - if ( abs( dPar - round( dPar)) > EPS_SMALL) { - vdSplit1.push_back( dPar) ; - nSplit1 = vdSplit1.size() ; - } - else if ( dPar = round( dPar) ; dPar > nLastParam1){ - ++ c1 ; - ++ nLastParam1 ; + if ( dPar > dLastParam1 + EPS_PARAM) { + if ( abs( dPar - round( dPar)) > EPS_SMALL) { + vdSplit1.push_back( dPar) ; + nSplit1 = vdSplit1.size() ; + } + else if ( dPar = round( dPar) ; dPar > nLastParam1){ + ++ c1 ; + ++ nLastParam1 ; + } } + dLastParam1 = dPar ; ++nLastParam0 ; vPairs.emplace_back( nLastParam0 + nSplit0, nLastParam1 + nSplit1) ; ++c0 ; @@ -6550,14 +6786,17 @@ SurfBezier::CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, c else if ( vdParamPos0[c0] > vdParamPos1[c1]) { double dPar ; CrvU0.GetParamAtLength( dLenPrev0 + dLen0 * vdParamPos1[c1], dPar) ; // se lo split non è in prossimità di una joint già esistente allora lo aggiungo - if ( abs( dPar - round( dPar)) > EPS_SMALL) { - vdSplit0.push_back( dPar) ; - nSplit0 = vdSplit0.size() ; - } - else if ( dPar = round( dPar) ; dPar > nLastParam0){ - ++ c0 ; - ++ nLastParam0 ; + if ( dPar > dLastParam0 + EPS_PARAM) { + if ( abs( dPar - round( dPar)) > EPS_SMALL) { + vdSplit0.push_back( dPar) ; + nSplit0 = vdSplit0.size() ; + } + else if ( dPar = round( dPar) ; dPar > nLastParam0){ + ++ c0 ; + ++ nLastParam0 ; + } } + dLastParam0 = dPar ; ++nLastParam1 ; vPairs.emplace_back( nLastParam0 + nSplit0, nLastParam1 + nSplit1) ; ++c1 ; diff --git a/SurfBezier.h b/SurfBezier.h index 1338978..e484396 100644 --- a/SurfBezier.h +++ b/SurfBezier.h @@ -154,6 +154,7 @@ class SurfBezier : public ISurfBezier, public IGeoObjRW bool RemoveCollapsedSpans( void) override ; bool SwapParameters( void) ; bool LimitSurfToTrimmedRegion( void) override ; + bool CreateSmoothByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, double dSampleLen) override ; public : // IGeoObjRW int GetNgeId( void) const override ;