From 02cb8a0d3c0bfbcbcaca5717b039865bb63f57d8 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Thu, 16 Apr 2026 09:41:22 +0200 Subject: [PATCH] EgtGeomKernel : - aggiornamento versione di RuledSmooth. - aggiunta controlli. - prima versione della regolarizzazione di curve bezier composte. --- CurveAux.cpp | 10 +- SurfBezier.cpp | 535 ++++++++++++++++++++++++++++++++++++------------- Trimming.cpp | 95 ++++----- 3 files changed, 448 insertions(+), 192 deletions(-) diff --git a/CurveAux.cpp b/CurveAux.cpp index 1aaceff..09000b6 100644 --- a/CurveAux.cpp +++ b/CurveAux.cpp @@ -1595,8 +1595,10 @@ FitWithBezier( const ICurve* pCrvOrig, const PNTVECTOR& vPnt, DBLVECTOR& vParam, //---------------------------------------------------------------------------- ICurve* -ApproxCurveWithBezier( const ICurve* pCrv , double dTol) +ApproxCurveWithBezier( const ICurve* pCrv , double dTol, const Vector3d& vtStart, const Vector3d& vtEnd) { + if ( pCrv == nullptr || ! pCrv->IsValid()) + return nullptr ; #if SAVECURVEPASSED SaveGeoObj( pCrv->Clone(), "D:\\Temp\\bezier\\approxWithBezier\\CurveDaApprossimare\\"+ToString(nCrvPassed) + ".nge") ; @@ -1668,6 +1670,12 @@ ApproxCurveWithBezier( const ICurve* pCrv , double dTol) VCT3DVECTOR vPrevDer ; VCT3DVECTOR vNextDer ; ComputeAkimaTangents( false, vParam, vPnt, vPrevDer, vNextDer) ; + vPrevDer[0] = vtStart ; + vNextDer.back() = vtEnd ; + if ( ! AreSameVectorExact(vtStart, V_NULL)) { + vPrevDer[1] = vtStart ; + vNextDer.end()[-2] = vtEnd ; + } int nOverSampling = ssize( vPntOverSampling) ; vParam.resize( nOverSampling) ; diff --git a/SurfBezier.cpp b/SurfBezier.cpp index 55a92f0..3ba9456 100644 --- a/SurfBezier.cpp +++ b/SurfBezier.cpp @@ -57,6 +57,7 @@ || SAVEFAILEDTREE || SAVELIMITSURF || SAVEPACEDISO #include "/EgtDev/Include/EGkGeoObjSave.h" std::vector vGeo ; + std::vector vCol ; #endif using namespace std ; @@ -5896,15 +5897,31 @@ SurfBezier::CreateByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, int return true ; } +// Struttura per Spigolo struct SharpEdge { double dParU ; Point3d ptEdge ; - Vector3d vtTanPrev, vtTanAft ; + Vector3d vtTanPrev, vtTanNext ; SharpEdge( double dU, const Point3d ptE, const Vector3d& vtTP, const Vector3d& vtTA) - : dParU( dU), ptEdge( ptE), vtTanPrev( vtTP), vtTanAft( vtTA) {} + : dParU( dU), ptEdge( ptE), vtTanPrev( vtTP), vtTanNext( vtTA) {} } ; typedef vector SHARPEDGEVECTOR ; +// Struttura per Punto a Curvatura Massima +struct CurvaturePoint { + double dParU ; + Point3d ptCurvature ; + Vector3d vtTanPrev, vtTanNext ; + CurvaturePoint( double dU, const Point3d ptE, const Vector3d& vtTP, const Vector3d& vtTA) + : dParU( dU), ptCurvature( ptE), vtTanPrev( vtTP), vtTanNext( vtTA) {} +} ; +typedef vector SHARPEDGEVECTOR ; + +// --------------------------------------------------------------------------- +// Calcolo delle Curve di Sync tra gli spigoli di una curva e l'altra curva nella sua integrità +// [Dato un vettore di SharpEdge di una Curva di Bordo si calcola la Linea di Sincronizzazione tra ognuno di essi +// e l'altra Curva di Bordo] +// -> Restituisce un vettore di Linee di Sincronizzazione static bool CalcSyncPointFromEdge( const SHARPEDGEVECTOR& vSharpEdge, const ICurveComposite* pCompoSubEdge, const SHARPEDGEVECTOR& vSharpSubEdge, BIPNTVECTOR& vSyncLines) @@ -5919,13 +5936,20 @@ CalcSyncPointFromEdge( const SHARPEDGEVECTOR& vSharpEdge, const ICurveComposite* if ( vSharpEdge.empty()) return true ; + // Se il numero di Spigoli coincide, allora li unisco sequenzialmente tra loro ( considerazione buona ???) + if ( ssize( vSharpEdge) == ssize( vSharpSubEdge)) { + for ( int i = 0 ; i < ssize( vSharpEdge) ; ++ i) + vSyncLines.emplace_back( vSharpEdge[i].ptEdge, vSharpSubEdge[i].ptEdge) ; + return false ; + } + // Scorro gli SharpEdges double dUPrevSubEdge = 0., dUCurrSubEdge = 0. ; for ( const SharpEdge& mySharpEdge : vSharpEdge) { // Recupero il parametro sulla curva di sincronizzazione // --- Piano di taglio per punto a distanza minima - IntersCurvePlane ICP( *pCompoSubEdge, mySharpEdge.ptEdge, Media( mySharpEdge.vtTanPrev, mySharpEdge.vtTanAft)) ; + IntersCurvePlane ICP( *pCompoSubEdge, mySharpEdge.ptEdge, Media( mySharpEdge.vtTanPrev, mySharpEdge.vtTanNext)) ; int nIndParCloser = -1, nIndPointCloser = -1 ; double dSqMinDist = INFINITO ; for ( int nInfo = 0 ; nInfo < ICP.GetIntersCount() ; ++ nInfo) { @@ -5940,7 +5964,7 @@ CalcSyncPointFromEdge( const SHARPEDGEVECTOR& vSharpEdge, const ICurveComposite* } } } - bool bOkPlane = ( nIndParCloser != -1 && nIndPointCloser != -1) ; + bool bOkPlane = ( nIndParCloser != -1 && nIndPointCloser != -1) ; if ( bOkPlane) { // Se gli indici sono tra loro coerenti allora ho individuato il punto if ( nIndParCloser == nIndPointCloser) { @@ -5948,30 +5972,31 @@ CalcSyncPointFromEdge( const SHARPEDGEVECTOR& vSharpEdge, const ICurveComposite* ICP.GetIntCrvPlnInfo( nIndParCloser, aInfo) ; dUCurrSubEdge = aInfo.Ici[0].dU ; } + // Se gli indici sono discordi, devo scegliere quale dei due punti tenere + else { + // scelgo il punto più vicino al corrente + IntCrvPlnInfo aInfoPt, aInfoPar ; + ICP.GetIntCrvPlnInfo( nIndPointCloser, aInfoPt) ; + ICP.GetIntCrvPlnInfo( nIndParCloser, aInfoPar) ; + dUCurrSubEdge = ( SqDist( mySharpEdge.ptEdge, aInfoPt.Ici[0].ptI) < SqDist( mySharpEdge.ptEdge, aInfoPar.Ici[0].ptI) ? + aInfoPt.Ici[0].dU : aInfoPar.Ici[0].dU) ; + } } - // Se gli indici sono discordi, devo scegliere quale dei due punti tenere - else { - // scelgo il punto più vicino al corrente - IntCrvPlnInfo aInfoPt, aInfoPar ; - ICP.GetIntCrvPlnInfo( nIndPointCloser, aInfoPt) ; - ICP.GetIntCrvPlnInfo( nIndParCloser, aInfoPar) ; - dUCurrSubEdge = ( SqDist( mySharpEdge.ptEdge, aInfoPt.Ici[0].ptI) < SqDist( mySharpEdge.ptEdge, aInfoPar.Ici[0].ptI) ? - aInfoPt.Ici[0].dU : aInfoPar.Ici[0].dU) ; - if ( ! bOkPlane) { - // --- Altrimenti, cerco il punto a minima distanza - DistPointCurve DPC( mySharpEdge.ptEdge, *pCompoSubEdge) ; - int nFlag ; - bool bOkMinDist = ( DPC.GetParamAtMinDistPoint( dUPrevSubEdge, dUCurrSubEdge, nFlag) && dUCurrSubEdge > dUPrevSubEdge) ; - if ( ! bOkMinDist) { - // --- Eh.... bho ( se arrivo qui non so che fare...) - double dUStart, dUEnd ; - pCompoSubEdge->GetDomain( dUStart, dUEnd) ; - dUCurrSubEdge = ( dUEnd - dUCurrSubEdge) / 2. ; - } + if ( ! bOkPlane) { + // --- Altrimenti, cerco il punto a minima distanza + DistPointCurve DPC( mySharpEdge.ptEdge, *pCompoSubEdge) ; + int nFlag ; + bool bOkMinDist = ( DPC.GetParamAtMinDistPoint( dUPrevSubEdge, dUCurrSubEdge, nFlag) && dUCurrSubEdge > dUPrevSubEdge) ; + if ( ! bOkMinDist) { + // --- Alla peggio mi posiziono a metà tra la posizione corrente e quella finale + double dPrevLen ; pCompoSubEdge->GetLengthAtParam( dUPrevSubEdge, dPrevLen) ; + double dLen ; pCompoSubEdge->GetLength( dLen) ; + pCompoSubEdge->GetParamAtLength( ( dPrevLen + dLen) / 2., dUCurrSubEdge) ; } } // Verifico se tale parametro può essere avvicinato ad uno Spigolo presente sulla curva + // NB. Come descitto sopra gli spigoli in generale è meglio sincronizzarli tra loro if ( ! vSharpSubEdge.empty()) { const double EDGE_LEN_TOL = 5. ; for ( const SharpEdge& mySharpSubEdge : vSharpSubEdge) { @@ -6001,7 +6026,104 @@ CalcSyncPointFromEdge( const SHARPEDGEVECTOR& vSharpEdge, const ICurveComposite* } // --------------------------------------------------------------------------- -// Debug [Gestione Edge in Quadrangolazioni] +// Calcolo della curva di Sync tra un punto di una curva di Bordo (calcolato come il punto a curvatura massima) e il suo +// associato sull'altra Curva di Bordo +// -> Restituisce la singola Linea di Sincronizzazione +static bool +CalcSyncPointFromCurvature( const CurvaturePoint& PointK, const ICurveComposite* pCompoSubEdge, BIPOINT& SyncLine) +{ + // Verifico la validità del SubEdge su cui trovare il punto di Sincronizzazione + if ( pCompoSubEdge == nullptr || ! pCompoSubEdge->IsValid()) + return false ; + + // --- Piano di taglio per punto a distanza minima + double dUCurrSubEdge = 0. ; + IntersCurvePlane ICP( *pCompoSubEdge, PointK.ptCurvature, Media( PointK.vtTanPrev, PointK.vtTanNext)) ; + int nIndParCloser = -1, nIndPointCloser = -1 ; + double dSqMinDist = INFINITO ; + for ( int nInfo = 0 ; nInfo < ICP.GetIntersCount() ; ++ nInfo) { + IntCrvPlnInfo aInfo ; + if ( ICP.GetIntCrvPlnInfo( nInfo, aInfo)) { + if ( nIndParCloser == -1) + nIndParCloser = nInfo ; + double dSqDist = SqDist( PointK.ptCurvature, aInfo.Ici[0].ptI) ; + if ( dSqDist < dSqMinDist) { + dSqMinDist = dSqDist ; + nIndPointCloser = nInfo ; + } + } + } + bool bOkPlane = ( nIndParCloser != -1 && nIndPointCloser != -1) ; + if ( bOkPlane) { + // Se gli indici sono tra loro coerenti allora ho individuato il punto + if ( nIndParCloser == nIndPointCloser) { + IntCrvPlnInfo aInfo ; + ICP.GetIntCrvPlnInfo( nIndParCloser, aInfo) ; + dUCurrSubEdge = aInfo.Ici[0].dU ; + } + // Se gli indici sono discordi, devo scegliere quale dei due punti tenere + else { + // scelgo il punto più vicino al corrente + IntCrvPlnInfo aInfoPt, aInfoPar ; + ICP.GetIntCrvPlnInfo( nIndPointCloser, aInfoPt) ; + ICP.GetIntCrvPlnInfo( nIndParCloser, aInfoPar) ; + dUCurrSubEdge = ( SqDist( PointK.ptCurvature, aInfoPt.Ici[0].ptI) < SqDist( PointK.ptCurvature, aInfoPar.Ici[0].ptI) ? + aInfoPt.Ici[0].dU : aInfoPar.Ici[0].dU) ; + } + } + if ( ! bOkPlane) { + // --- Altrimenti, cerco il punto a minima distanza + DistPointCurve DPC( PointK.ptCurvature, *pCompoSubEdge) ; + int nFlag ; + bool bOkMinDist = ( DPC.GetParamAtMinDistPoint( 0., dUCurrSubEdge, nFlag)) ; + if ( ! bOkMinDist) { + // --- Alla peggio mi posiziono a metà tra la posizione corrente e quella finale + double dPrevLen ; pCompoSubEdge->GetLengthAtParam( 0., dPrevLen) ; + double dLen ; pCompoSubEdge->GetLength( dLen) ; + pCompoSubEdge->GetParamAtLength( ( dPrevLen + dLen) / 2., dUCurrSubEdge) ; + } + } + + // Definisco il primo estremo della linea di Sincronizzazione corrente + SyncLine.first = PointK.ptCurvature ; + + // Verifico se posso muovermi attorno al punto trovato per allinearmi meglio con le normali alla curva + // NB. Si cerca di privilgiare i punti più vicini ( in parametro) al punto calcolato sopra, in modo da cercare di + // non discostare troppo la Linea di sincronizzazione dal punto trovato. + const double MAX_DIST = 2.5 ; + const int NUM_SAMPLE_PNT = 20 ; + double dLen ; pCompoSubEdge->GetLength( dLen) ; + double dSyncLen ; pCompoSubEdge->GetLengthAtParam( dUCurrSubEdge, dSyncLen) ; + Vector3d vtSyncTanPrev, vtSyncTanNext ; + pCompoSubEdge->GetPointD1D2( dUCurrSubEdge, ICurve::FROM_MINUS, SyncLine.second, &vtSyncTanPrev) ; vtSyncTanPrev.Normalize() ; + pCompoSubEdge->GetPointD1D2( dUCurrSubEdge, ICurve::FROM_PLUS, SyncLine.second, &vtSyncTanNext) ; vtSyncTanNext.Normalize() ; + double dLimInfLen = Clamp( dSyncLen - MAX_DIST, 0., dLen) ; + double dLimSupLen = Clamp( dSyncLen + MAX_DIST, 0., dLen) ; + int nSamplePnt = int( ceil( NUM_SAMPLE_PNT / 4.)) ; + double dMaxCos = ( Media( PointK.vtTanPrev, PointK.vtTanNext) * Media( vtSyncTanPrev, vtSyncTanNext)) ; + double dShiftR = ( dLimSupLen - dSyncLen) / nSamplePnt ; + double dShiftL = ( dSyncLen - dLimInfLen) / nSamplePnt ; + array vdLens = { dSyncLen, dSyncLen} ; + for ( int i = 1 ; i <= nSamplePnt ; ++ i) { + vdLens[0] += dShiftR ; + vdLens[1] -= dShiftL ; + for ( int j = 0 ; j < 2 ; ++ j) { + double dU ; pCompoSubEdge->GetParamAtLength( vdLens[j], dU) ; + Point3d ptCurr ; Vector3d vtTan ; + pCompoSubEdge->GetPointD1D2( dU, ICurve::FROM_MINUS, ptCurr, &vtTan) ; vtTan.Normalize() ; + double dCos = ( vtTan * Media( PointK.vtTanPrev, PointK.vtTanNext)) ; + if ( dCos > dMaxCos) { + dMaxCos = dCos ; + SyncLine.second = ptCurr ; + } + } + } + + return true ; +} + +// --------------------------------------------------------------------------- +// Gestione degli spigoli all'interno della Quadrangolazione corrente static bool ManageEdgesInQuadrangulation( const ICurveComposite* pSubEdge1, const ICurveComposite* pSubEdge2, BIPNTVECTOR& vSyncLines) { @@ -6020,7 +6142,7 @@ ManageEdgesInQuadrangulation( const ICurveComposite* pSubEdge1, const ICurveComp SHARPEDGEVECTOR vSharpEdges2 ; vSharpEdges2.reserve( max( 0, nCrv2 - 1)) ; // --- Cerco gli Spigoli sul SottoTratto del primo bordo - // Se la CurvaA ha solo una sottocurva, non faccio nulla + // Se la CurvaA ha più di una sottocurva, verifico l'esistenza di Spigoli (Sharp Edges) if ( nCrv1 > 1) { Point3d ptCurr1 ; // Scorro le sottocurve @@ -6029,17 +6151,17 @@ ManageEdgesInQuadrangulation( const ICurveComposite* pSubEdge1, const ICurveComp double dU = double( nCrv + 1) ; // Recupero le tangenti prima e dopo tale parametro Vector3d vtTanPrev ; pSubEdge1->GetPointD1D2( dU, ICurve::FROM_MINUS, ptCurr1, &vtTanPrev) ; - Vector3d vtTanAft ; pSubEdge1->GetPointD1D2( dU, ICurve::FROM_PLUS, ptCurr1, &vtTanAft) ; + Vector3d vtTanNext ; pSubEdge1->GetPointD1D2( dU, ICurve::FROM_PLUS, ptCurr1, &vtTanNext) ; // Verifico se ho uno spigolo vtTanPrev.Normalize() ; - vtTanAft.Normalize() ; - if ( vtTanPrev * vtTanAft < COS_EDGE_LIMIT) - vSharpEdges1.emplace_back( dU, ptCurr1, vtTanPrev, vtTanAft) ; + vtTanNext.Normalize() ; + if ( vtTanPrev * vtTanNext < COS_EDGE_LIMIT) + vSharpEdges1.emplace_back( dU, ptCurr1, vtTanPrev, vtTanNext) ; } } // --- Cerco gli spigoli sul Sottotratto del secondo bordo - // Se la Curva B ha solo una sottocurva, non faccio nulla + // Se la Curva B ha più di una sottocurva, verifico l'esistena di Spigoli (Sharp Edges) if ( nCrv2 > 1) { Point3d ptCurr2 ; // Scorro le sottocurve @@ -6048,24 +6170,24 @@ ManageEdgesInQuadrangulation( const ICurveComposite* pSubEdge1, const ICurveComp double dU = double( nCrv + 1) ; // Recupero le tangenti prima e dopo tale parametro Vector3d vtTanPrev ; pSubEdge2->GetPointD1D2( dU, ICurve::FROM_MINUS, ptCurr2, &vtTanPrev) ; - Vector3d vtTanAft ; pSubEdge2->GetPointD1D2( dU, ICurve::FROM_PLUS, ptCurr2, &vtTanAft) ; + Vector3d vtTanNext ; pSubEdge2->GetPointD1D2( dU, ICurve::FROM_PLUS, ptCurr2, &vtTanNext) ; // Verifico se ho uno spigolo vtTanPrev.Normalize() ; - vtTanAft.Normalize() ; - if ( vtTanPrev * vtTanAft < COS_EDGE_LIMIT) - vSharpEdges2.emplace_back( dU, ptCurr2, vtTanPrev, vtTanAft) ; + vtTanNext.Normalize() ; + if ( vtTanPrev * vtTanNext < COS_EDGE_LIMIT) + vSharpEdges2.emplace_back( dU, ptCurr2, vtTanPrev, vtTanNext) ; } } - // Se non ho alcuno spigolo, allora non faccio nulla + // Se non ho alcuno spigolo per entrambe le curve di Bordo, non faccio nulla if ( vSharpEdges1.empty() && vSharpEdges2.empty()) return true ; - // Recupero le Curve di Sincronizzazione dell'Edge 1 sull'Edge 2 + // Recupero le Curve di Sincronizzazione associate agli spigoli dal primo Bordo al secondo Bordo BIPNTVECTOR vSyncLines1 ; CalcSyncPointFromEdge( vSharpEdges1, pSubEdge2, vSharpEdges2, vSyncLines1) ; - // Recupero le Curve di Sincronizzazione dell'Edge 2 sull'Egde 1 + // Recupero le Curve di Sincronizzazione associate agli spigoli dal secondo Bordo al primo Bordo BIPNTVECTOR vSyncLines2 ; CalcSyncPointFromEdge( vSharpEdges2, pSubEdge1, vSharpEdges1, vSyncLines2) ; @@ -6078,7 +6200,7 @@ ManageEdgesInQuadrangulation( const ICurveComposite* pSubEdge1, const ICurveComp }) ; }) ; - // Ordino tutte le curve in base al parametro dU della curva principale + // Ordino tutte le curve in base al parametro dU della prima curva di Bordo vector> vSyncLinesPar ; vSyncLinesPar.reserve( vSyncLines1.size() + vSyncLines2.size()) ; for ( BIPOINT& SyncLine1 : vSyncLines1) { vSyncLinesPar.emplace_back( make_pair( make_pair( SyncLine1.first, SyncLine1.second), @@ -6094,9 +6216,16 @@ ManageEdgesInQuadrangulation( const ICurveComposite* pSubEdge1, const ICurveComp return SyncLineParA.second < SyncLineParB.second ; }) ; - // Restituisco il risultato - for ( auto Iter = vSyncLinesPar.begin() ; Iter != vSyncLinesPar.end() ; ++ Iter) - vSyncLines.emplace_back( Iter->first) ; + // Controllo che le linee di sincronizzazione non si intreccino e restituisco il risultato + // NB. Inserisco solo che curve che progressivamente non si intrecciano sulla seconda curva di Bordo + double dUSecondPrev = EPS_PARAM ; + for ( auto Iter = vSyncLinesPar.begin() ; Iter != vSyncLinesPar.end() ; ++ Iter) { + double dUSecondCurr ; pSubEdge2->GetParamAtPoint( ( *Iter).first.second, dUSecondCurr, TOL) ; + if ( dUSecondCurr > dUSecondPrev + EPS_SMALL) { + vSyncLines.emplace_back( Iter->first) ; + dUSecondPrev = dUSecondCurr ; + } + } return true ; } @@ -6110,75 +6239,188 @@ ManageTwistInQuadrangulation( const ICurveComposite* pSubEdge1, const ICurveComp if ( pSubEdge1 == nullptr || ! pSubEdge1->IsValid() || pSubEdge2 == nullptr || ! pSubEdge2->IsValid()) return false ; - // --- Verifico il cambiamento di Deviazione angolare tra Inizio-Fine del tratto ( ne basta uno dei due fuori dalla tolleranza) const double COS_LIMIT = cos( 50. * DEGTORAD) ; - Vector3d vtStart1 ; pSubEdge1->GetStartDir( vtStart1) ; - Vector3d vtEnd1 ; pSubEdge1->GetEndDir( vtEnd1) ; - bool bSplit = ( vtStart1 * vtEnd1 < COS_LIMIT) ; - if ( ! bSplit) { - Vector3d vtStart2 ; pSubEdge2->GetStartDir( vtStart2) ; - Vector3d vtEnd2 ; pSubEdge2->GetEndDir( vtEnd2) ; - bSplit = ( vtStart2 * vtEnd2 < COS_LIMIT) ; + const int NUM_SAMPLE_PNT = 20 ; + #if DEBUG_CURVATURE + vector> _vPtK1 ; + vector> _vPtK2 ; + IGeomDB* pGeomDB = GetCurrGeomDB() ; + VERIFY_GEOMDB( pGeomDB, false) + #endif + + // --- Verifico il cambiamento di Deviazione angolare tra Inizio-Fine della prima curva di Bordo + Vector3d vtS1 ; pSubEdge1->GetStartDir( vtS1) ; + Vector3d vtE1 ; pSubEdge1->GetEndDir( vtE1) ; + double dLen1 = - EPS_SMALL ; + bool bSplit1 = ( vtS1 * vtE1 < COS_LIMIT) ; + if ( bSplit1) { + // Individuo il punto a Curvatura Massima + pSubEdge1->GetLength( dLen1) ; + double dKMax1 = - INFINITO + 1, dUK1Max = - EPS_SMALL ; + Point3d ptKMax1 ; Vector3d vtTanKMax1Prev, vtTanKMax1Next ; + for ( int i = 0 ; i <= NUM_SAMPLE_PNT ; ++ i) { + // Ricavo la Lunghezza corrente e il parametro dU associato + double dCurrLen1 = Clamp( i * ( dLen1 / NUM_SAMPLE_PNT), 0., dLen1) ; + double dUCurr1 ; pSubEdge1->GetParamAtLength( dCurrLen1, dUCurr1) ; + // Calcolo la Curvatura + Point3d ptCurrSub1 ; + Vector3d vtCurrSub1Der1Prev, vtCurrSub1Der2Prev, vtCurrSub1Der1Next, vtCurrSub1Der2Next ; + pSubEdge1->GetPointD1D2( dUCurr1, ICurve::FROM_MINUS, ptCurrSub1, &vtCurrSub1Der1Prev, &vtCurrSub1Der2Prev) ; + pSubEdge1->GetPointD1D2( dUCurr1, ICurve::FROM_PLUS, ptCurrSub1, &vtCurrSub1Der1Next, &vtCurrSub1Der2Next) ; + Vector3d vtCurrSub1Der1 = Media( vtCurrSub1Der1Prev, vtCurrSub1Der1Next) ; + Vector3d vtCurrSub1Der2 = Media( vtCurrSub1Der2Prev, vtCurrSub1Der2Next) ; + double dCurrK1 = ( vtCurrSub1Der1 ^ vtCurrSub1Der2).Len() / max( EPS_SMALL, Pow( vtCurrSub1Der1.Len(), 3)) ; + // Se maggiore della massima trovata, aggiorno la massima + if ( dCurrK1 > dKMax1) { + dKMax1 = dCurrK1 ; + ptKMax1 = ptCurrSub1 ; + dUK1Max = dUCurr1 ; + vtTanKMax1Prev = vtCurrSub1Der1Prev ; + vtTanKMax1Next = vtCurrSub1Der1Next ; + } + #if DEBUG_CURVATURE + _vPtK1.emplace_back( make_pair( ptCurrSub1, dCurrK1)) ; + #endif + } + vtTanKMax1Prev.Normalize() ; + vtTanKMax1Next.Normalize() ; + // Calcolo la nuova linea di sincronizzazione + CurvaturePoint myCurvaturePoint( dUK1Max, ptKMax1, vtTanKMax1Prev, vtTanKMax1Next) ; + BIPOINT SyncLine ; + CalcSyncPointFromCurvature( myCurvaturePoint, pSubEdge2, SyncLine) ; + vSyncLines.emplace_back( SyncLine) ; } - // Sew non devo Splittare, non faccio nulla - if ( ! bSplit) + + // --- Verifico il cambiamento di Deviazione angolare tra Inizio-Fine del tratto per la prima curva di Bordo + Vector3d vtS2 ; pSubEdge2->GetStartDir( vtS2) ; + Vector3d vtE2 ; pSubEdge2->GetEndDir( vtE2) ; + double dLen2 = - EPS_SMALL ; + bool bSplit2 = ( vtS2 * vtE2 < COS_LIMIT) ; + if ( bSplit2) { + // Individuo il punto a Curvatura Massima + pSubEdge2->GetLength( dLen2) ; + double dKMax2 = - INFINITO + 1, dUK2Max = - EPS_SMALL ; + Point3d ptKMax2 ; Vector3d vtTanKMax2Prev, vtTanKMax2Next ; + for ( int i = 0 ; i <= NUM_SAMPLE_PNT ; ++ i) { + // Ricavo la Lunghezza corrente e il parametro dU associato + double dCurrLen2 = Clamp( i * ( dLen2 / NUM_SAMPLE_PNT), 0., dLen2) ; + double dUCurr2 ; pSubEdge2->GetParamAtLength( dCurrLen2, dUCurr2) ; + // Calcolo la Curvatura + Point3d ptCurrSub2 ; + Vector3d vtCurrSub2Der1Prev, vtCurrSub2Der2Prev, vtCurrSub2Der1Next, vtCurrSub2Der2Next ; + pSubEdge2->GetPointD1D2( dUCurr2, ICurve::FROM_MINUS, ptCurrSub2, &vtCurrSub2Der1Prev, &vtCurrSub2Der2Prev) ; + pSubEdge2->GetPointD1D2( dUCurr2, ICurve::FROM_PLUS, ptCurrSub2, &vtCurrSub2Der1Next, &vtCurrSub2Der2Next) ; + Vector3d vtCurrSub2Der1 = Media( vtCurrSub2Der1Prev, vtCurrSub2Der1Next) ; + Vector3d vtCurrSub2Der2 = Media( vtCurrSub2Der2Prev, vtCurrSub2Der2Next) ; + double dCurrK2 = ( vtCurrSub2Der1 ^ vtCurrSub2Der2).Len() / max( EPS_SMALL, Pow( vtCurrSub2Der1.Len(), 3)) ; + // Se maggiore della massima trovata, aggiorno la massima + if ( dCurrK2 > dKMax2) { + dKMax2 = dCurrK2 ; + ptKMax2 = ptCurrSub2 ; + dUK2Max = dUCurr2 ; + vtTanKMax2Prev = vtCurrSub2Der1Prev ; + vtTanKMax2Next = vtCurrSub2Der1Next ; + } + #if DEBUG_CURVATURE + _vPtK1.emplace_back( make_pair( ptCurrSub2, dCurrK2)) ; + #endif + } + vtTanKMax2Prev.Normalize() ; + vtTanKMax2Next.Normalize() ; + // Calcolo la nuova linea di sincronizzazione + CurvaturePoint myCurvaturePoint( dUK2Max, ptKMax2, vtTanKMax2Prev, vtTanKMax2Next) ; + BIPOINT SyncLine ; + CalcSyncPointFromCurvature( myCurvaturePoint, pSubEdge1, SyncLine) ; + // !<-- Inverto la curva di Sincronizzaione per coerenza con la prima -->! + swap( SyncLine.first, SyncLine.second) ; + vSyncLines.emplace_back( SyncLine) ; + } + + #if DEBUG_CURVATURE // Curvatura minima -> AQUA | Curvatura massima -> ORANGE + auto [itMin1, itMax1] = std::minmax_element( _vPtK1.begin(), _vPtK1.end(), [](auto const& A, auto const& B) { + return A.second < B.second ; + }) ; + double _dK1Max = itMax1->second ; + double _dK1Min = itMin1->second ; + for ( int i = 0 ; i < ssize( _vPtK1) ; ++ i) { + double _t = 0. ; + if ( _dK1Max > _dK1Min) + _t = ( _vPtK1[i].second - _dK1Min) / ( _dK1Max - _dK1Min) ; + double _dh = 30 - 180. ; // AQUA -> HSV( 180, 1, 1) | ORANGE -> HSV( 30, 1, 1) + if ( _dh > 180.) _dh -= 360.0 ; + if ( _dh < -180.0) _dh += 360.0 ; + double _h = 180. + _t * _dh ; + if ( _h < 0.0) _h += 360.0 ; + if ( _h >= 360.0) _h -= 360.0 ; + PtrOwner _ptC( CreateGeoPoint3d()) ; _ptC->Set( _vPtK1[i].first) ; + int _nId = pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, Release( _ptC)) ; + pGeomDB->SetMaterial( _nId, Color( GetColorFromHSV( HSV( _h, 1., 1.)))) ; + } + auto [itMin2, itMax2] = std::minmax_element( _vPtK2.begin(), _vPtK2.end(), [](auto const& A, auto const& B) { + return A.second < B.second ; + }) ; + double _dK2Max = itMax2->second ; + double _dK2Min = itMin2->second ; + for ( int i = 0 ; i < ssize( _vPtK2) ; ++ i) { + double _t = 0. ; + if ( _dK2Max > _dK2Min) + _t = ( _vPtK2[i].second - _dK2Min) / ( _dK2Max - _dK2Min) ; + double _dh = 30 - 180. ; // CYAN -> HSV( 180, 1, 1) | ORANGE -> HSV( 30, 1, 1) + if ( _dh > 180.) _dh -= 360.0 ; + if ( _dh < -180.0) _dh += 360.0 ; + double _h = 180. + _t * _dh ; + if ( _h < 0.0) _h += 360.0 ; + if ( _h >= 360.0) _h -= 360.0 ; + PtrOwner _ptC( CreateGeoPoint3d()) ; _ptC->Set( _vPtK2[i].first) ; + int _nId = pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, Release( _ptC)) ; + pGeomDB->SetMaterial( _nId, Color( GetColorFromHSV( HSV( _h, 1., 1.)))) ; + } + #endif + + // Se non ho alcuna linea di sincronizzazione, non faccio nulla + if ( vSyncLines.empty()) return true ; - double dLen1 ; pSubEdge1->GetLength( dLen1) ; - double dLen2 ; pSubEdge2->GetLength( dLen2) ; - // Individuo sulle due curve i punti a curvatura massima e definisco una Curva di Sync tra essi - Point3d ptKMax1, ptKMax2 ; - double dUKMax1, dUKMin1 ; - double dKMax1 = - INFINITO + 1, dKMax2 = - INFINITO + 1 ; - const int NUM_SAMPLE_PNT = 20 ; - for ( int i = 0 ; i <= NUM_SAMPLE_PNT ; ++ i) { - // Ricavo i parametri - double dU1 ; pSubEdge1->GetParamAtLength( Clamp( i * ( dLen1 / NUM_SAMPLE_PNT), 0., dLen1), dU1) ; - double dU2 ; pSubEdge2->GetParamAtLength( Clamp( i * ( dLen2 / NUM_SAMPLE_PNT), 0., dLen2), dU2) ; - // Calcolo la Curvatura - Point3d ptSub1 ; Vector3d vtSub1Der1, vtSub1Der2 ; - pSubEdge1->GetPointD1D2( dU1, ICurve::FROM_MINUS, ptSub1, &vtSub1Der1, &vtSub1Der2) ; - double dK1 = ( vtSub1Der1 ^ vtSub1Der2).Len() / max( EPS_SMALL, Pow( vtSub1Der1.Len(), 3)) ; - if ( dK1 > dKMax1) { - dKMax1 = dK1 ; - ptKMax1 = ptSub1 ; + const double TOL = 250. * EPS_SMALL ; + + // Elimino tutte le curve di Sincronizzazione a ridosso degli estremi della Quadrangolazione + // NB. Risultano ridondanti, creano SottoQuadrangolazioni molto strette o possono Inclinare eccssivamente l'Utensile + // NB. Così facendo evito anche di creare curve di Sync lungo le diagonali della Quadrangolazione + const double LEN_TOL = 2. ; + for ( int i = 0 ; i < ssize( vSyncLines) ; ++ i) { + double dSyncLen1 ; pSubEdge1->GetLengthAtPoint( vSyncLines[i].first, dSyncLen1, TOL) ; + bool bErase = ( dSyncLen1 < max( LEN_TOL, 0.2 * dLen1) || dSyncLen1 > min( dLen1 - LEN_TOL, 0.8 * dLen1)) ; + if ( ! bErase) { + double dSyncLen2 ; pSubEdge2->GetLengthAtPoint( vSyncLines[i].second, dSyncLen2, TOL) ; + bErase = ( dSyncLen2 < max( LEN_TOL, 0.2 * dLen2) || dSyncLen2 > min( dLen2 - LEN_TOL, 0.8 * dLen2)) ; } - Point3d ptSub2 ; Vector3d vtSub2Der1, vtSub2Der2 ; - pSubEdge2->GetPointD1D2( dU2, ICurve::FROM_MINUS, ptSub2, &vtSub2Der1, &vtSub2Der2) ; - double dK2 = ( vtSub2Der1 ^ vtSub2Der2).Len() / max( EPS_SMALL, Pow( vtSub2Der1.Len(), 3)) ; - if ( dK2 > dKMax2) { - dKMax2 = dK2 ; - ptKMax2 = ptSub2 ; + if ( bErase) { + vSyncLines.erase( vSyncLines.begin() + i) ; + -- i ; } } + if ( vSyncLines.empty()) + return true ; - // Avendo fissato il punto a curvatura massima su entrambe le curve, cerco di sportarmi lungo la seconda curva - // ( nell'intorno del suo punto a massima curvatura) per cercare una direzione coerente - Point3d ptCurr1 ; Vector3d vtCurr1 ; - - const double MAX_DIST = 2.5 ; - double dLenAtK2 ; pSubEdge2->GetLengthAtPoint( ptKMax2, dLenAtK2) ; - //double dLimInfLen = Clamp( dLenAtK2 - MAX_DIST, 0., dLen2) ; - //double dLimSupLen = Clamp( dLenAtK2 + MAX_DIST, 0., dLen2) ; - //int nSamplePnt = int( ceil( NUM_SAMPLE_PNT / 2.)) ; - //double dMinCos = -1 - EPS_SMALL ; - //for ( int i = 0 ; i <= nSamplePnt ; ++ i) { - // double dCurrLen = dLimInfLen + i * ( dLimSupLen - dLimInfLen) / nSamplePnt ; - // double dU ; pSubEdge2->GetParamAtLength( dCurrLen, dU) ; - // Point3d ptCurr ; Vector3d vtTan ; - // pSubEdge2->GetPointD1D2( dU, ICurve::FROM_MINUS, ptCurr, &vtTan) ; vtTan.Normalize() ; - // double dCos = ( vtTan * - //} - - // Verifico che entrambi gli estremi della Linea di Sync siano distanti dai bordi della Quadrangolazione corrente - double dLenAtK1 ; pSubEdge1->GetLengthAtPoint( ptKMax1, dLenAtK1) ; - const double DIST_TOL = 2. ; - if ( ( dLenAtK1 > DIST_TOL - EPS_SMALL && dLenAtK1 < dLen1 - DIST_TOL + EPS_SMALL) && - ( dLenAtK2 > DIST_TOL - EPS_SMALL && dLenAtK2 < dLen2 - DIST_TOL + EPS_SMALL)) { - // Verifico che la Linea di Sicnronizzazione non tagli in diagonale la Quadrangolazione corrente - if ( ( dLenAtK1 < dLen1 - dLenAtK1 && dLenAtK2 < dLen2 - dLenAtK2) || - ( dLenAtK1 > dLen1 - dLenAtK1 && dLenAtK2 > dLen2 - dLenAtK2)) - vSyncLines.emplace_back( make_pair( ptKMax1, ptKMax2)) ; + // Se due curve di Sincronizzazione rimaste + if ( ssize( vSyncLines) == 2) { + // Se si sovrappongono, ne elimino una + if ( AreSamePointEpsilon( vSyncLines[0].first, vSyncLines[1].first, LEN_TOL) && + AreSamePointEpsilon( vSyncLines[0].second, vSyncLines[1].second, LEN_TOL)) + vSyncLines.pop_back() ; + } + // Se due curve di Sincronizzazione rimaste + if ( ssize( vSyncLines) == 2) { + // Ordino tutte le linee di sincronizzazione in base al parametro dU della curva principale + double dU0 ; pSubEdge1->GetParamAtPoint( vSyncLines[0].first, dU0, TOL) ; + double dU1 ; pSubEdge1->GetParamAtPoint( vSyncLines[1].first, dU1, TOL) ; + if ( dU0 > dU1 - EPS_SMALL) + swap( vSyncLines[0], vSyncLines[1]) ; + // Verifico che le curve non si intreccino + pSubEdge2->GetParamAtPoint( vSyncLines[0].second, dU0, TOL) ; + pSubEdge2->GetParamAtPoint( vSyncLines[1].second, dU1, TOL) ; + if ( dU0 > dU1 - EPS_SMALL) + vSyncLines.pop_back() ; // lascio solo la prima... ( bisognerebbe scegliere quale lasciare con un criterio migliore ?) } return true ; @@ -6189,12 +6431,20 @@ bool SurfBezier::CreateSmoothRuledByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, double dSampleLen) { // converto in bezier le curve iniziali - PtrOwner pCrvEdge1( GetCurveBezier( CurveToBezierCurve( pCurve0, 3, false))) ; - PtrOwner pCrvEdge2( GetCurveBezier( CurveToBezierCurve( pCurve1, 3, false))) ; + PtrOwner pCrvEdge1( CurveToBezierCurve( pCurve0, 3, false)) ; + PtrOwner pCrvEdge2( CurveToBezierCurve( pCurve1, 3, false)) ; if ( IsNull( pCrvEdge1) || IsNull( pCrvEdge2)) return false ; + #if SAVEPACEDISO + vGeo.clear() ; + vCol.clear() ; + #endif + + // Verifico che la distanza di campionamento sia ammissibile + double dSampleDist = Clamp( dSampleLen, 2., 30.) ; // 20.0 sembra un passo di campionamento ideale + // Recupero parametri iniziali double dLen1 ; pCrvEdge1->GetLength( dLen1) ; double dLen2 ; pCrvEdge2->GetLength( dLen2) ; @@ -6207,10 +6457,10 @@ SurfBezier::CreateSmoothRuledByTwoCurves( const ICurve* pCurve0, const ICurve* p Point3d ptPrev1, ptCurr1 ; pCrvEdge1->GetStartPoint( ptPrev1) ; Point3d ptPrev2, ptCurr2 ; pCrvEdge2->GetStartPoint( ptPrev2) ; Vector3d vtCurr1 = V_NULL, vtCurr2 = V_NULL ; - BIPNTVECTOR vEdgeSyncLines ; - while ( dLenPrev1 + dSampleLen < dLen1 - EPS_ZERO) { + BIPNTVECTOR vSyncLines ; + while ( dLenPrev1 + dSampleDist < dLen1 - EPS_ZERO) { // Recupero dU, Point3d e dLen corrente sul primo bordo, per un incremento del passo di campionamento - dLenCurr1 = Clamp( dLenPrev1 + dSampleLen, 0., dLen1) ; + dLenCurr1 = Clamp( dLenPrev1 + dSampleDist, 0., dLen1) ; pCrvEdge1->GetParamAtLength( dLenCurr1, dUCurr1) ; pCrvEdge1->GetPointD1D2( dUCurr1, ICurve::FROM_MINUS, ptCurr1, &vtCurr1) ; vtCurr1.Normalize() ; @@ -6269,7 +6519,7 @@ SurfBezier::CreateSmoothRuledByTwoCurves( const ICurve* pCurve0, const ICurve* p } // Verifico di non essermi allontanato troppo double dLen ; pCrvEdge2->GetLengthAtParam( dUCurr2, dLen) ; - bOkPlane = ( dLen < dLenPrev2 + 2. * dSampleLen) ; + bOkPlane = ( dLen < dLenPrev2 + 2. * dSampleDist) ; } if ( ! bOkPlane) { // --- Altrimenti, cerco il punto a minima distanza @@ -6279,11 +6529,11 @@ SurfBezier::CreateSmoothRuledByTwoCurves( const ICurve* pCurve0, const ICurve* p // Verifico di non essermi allontanato troppo if ( bOkMinDist) { double dLen ; pCrvEdge2->GetLengthAtParam( dUCurr2, dLen) ; - bOkMinDist = ( dLen < dLenPrev2 + 2. * dSampleLen) ; + bOkMinDist = ( dLen < dLenPrev2 + 2. * dSampleDist) ; } if ( ! bOkMinDist) { // --- Aumento la distanza corrente del passo di campionamento - double dLen = Clamp( dLenPrev2 + dSampleLen, 0., dLen2) ; + double dLen = Clamp( dLenPrev2 + dSampleDist, 0., dLen2) ; pCrvEdge2->GetParamAtLength( dLen, dUCurr2) ; } } @@ -6296,10 +6546,10 @@ SurfBezier::CreateSmoothRuledByTwoCurves( const ICurve* pCurve0, const ICurve* p // Verifico se le direzioni tangenti sono tra di loro circa parallele const double COS_ANG_TOL = cos( 15. * DEGTORAD) ; if ( vtCurr1 * vtCurr2 < COS_ANG_TOL) { - // Se fuori dalla tolleranza, recupero il miglior versore tangente sul secondo bordo nell'intervallo successivo di lunghezza ( 2. * dSampleLen) + // Se fuori dalla tolleranza, recupero il miglior versore tangente sul secondo bordo nell'intervallo successivo di lunghezza ( 2. * dMyDist) pCrvEdge2->GetLengthAtPoint( ptCurr2, dLenCurr2) ; - double dLimInfLen2 = Clamp( dLenCurr2 - dSampleLen, dLenPrev2, dLen2) ; - double dLimSupLen2 = Clamp( dLenCurr2 + dSampleLen, dLenPrev2, dLen2) ; + double dLimInfLen2 = Clamp( dLenCurr2 - dSampleDist, dLenPrev2, dLen2) ; + double dLimSupLen2 = Clamp( dLenCurr2 + dSampleDist, dLenPrev2, dLen2) ; // [Controllo migliorabile, magari mendiante metodo di bisezione (?)] const int NUM_STEP = 20 ; double dMinCos = - 1. - EPS_ZERO ; @@ -6329,30 +6579,32 @@ SurfBezier::CreateSmoothRuledByTwoCurves( const ICurve* pCurve0, const ICurve* p pGeomDB->AddGeoObj( GDB_ID_NULL, nLay2, Release( vtGeo2)) ; #endif - // debug - //// Inserisco le curve di sincronizzazione nel Layer di destinazine - // PtrOwner pLine( CreateCurveLine()) ; pLine->Set( ptCurr1, ptCurr2) ; - // pGeomDB->AddGeoObj( GDB_ID_NULL, nDestGrp, Release( pLine)) ; +#if SAVEPACEDISO + // Inserisco le curve di sincronizzazione nel Layer di destinazine + PtrOwner pLine( CreateCurveLine()) ; pLine->Set( ptCurr1, ptCurr2) ; + vGeo.push_back( Release( pLine)) ; + vCol.push_back( LIME) ; +#endif - // --- Analisi degli spigoli all'interno della Quadrangolazione --- - // Perchè si fa questa cosa ? Perchè parametrizzando per la lunghezza i SottoTratti ricavati, non è sempre detto - // che uno spigolo di una curva sia sincronizzato con lo spigolo di un'altra ( se questi esistono)... Pertanto - // la Bezier Ruled ricavata non è detto che sia in grado di approssimare lo spigolo correttamente, potrebbe sdondarlo + // --- Analisi degli spigoli all'interno della Quadrangolazione corrente --- + // NB. Non è sempre detto che uno spigolo di una curva sia sincronizzato con lo spigolo di un'altra ( se questi esistono)... + // Pertanto la Bezier Ruled ricavata non è detto che sia in grado di approssimare lo spigolo correttamente, potrebbe sdondarlo PtrOwner pCrvQuad1( ConvertCurveToComposite( pCrvEdge1->CopyParamRange( dUPrev1, dUCurr1))) ; PtrOwner pCrvQuad2( ConvertCurveToComposite( pCrvEdge2->CopyParamRange( dUPrev2, dUCurr2))) ; + BIPNTVECTOR vEdgeSyncLines ; ManageEdgesInQuadrangulation( pCrvQuad1, pCrvQuad2, vEdgeSyncLines) ; +#if SAVEPACEDISO + for ( int i = 0 ; i < ssize( vEdgeSyncLines) ; ++ i) { + PtrOwner pLine( CreateCurveLine()) ; pLine->Set( vEdgeSyncLines[i].first, vEdgeSyncLines[i].second) ; + vGeo.push_back( Release( pLine)) ; + vCol.push_back( GREEN) ; + } +#endif - //debug - //for ( int i = 0 ; i < ssize( vEdgeSyncLines) ; ++ i) { - // PtrOwner pLine( CreateCurveLine()) ; pLine->Set( vEdgeSyncLines[i].first, vEdgeSyncLines[i].second) ; - // int nNewId = pGeomDB->AddGeoObj( GDB_ID_NULL, nDestGrp, Release( pLine)) ; - // pGeomDB->SetMaterial( nNewId, GREEN) ; - //} - - // --- Aggiunta di Linee di Sync all'interno della quandrangolazione corrente --- - // Perchè si fa questa cosa ? Perchè parametrizzando per la lunghezza i SottoTratti ricavati, nel caso di elevate variazioni - // angolari tra l'inizio e la fine ( tra due curva di Sync) si potrebbero generare delle torsioni non volute - // NB. Queste linee vengono create considerando le SubQuadrangolazioni con gli Spigoli. + // --- Aggiunta di Linee di Sync all'interno della Quandrangolazione corrente --- + // Perchè parametrizzando per la lunghezza i SottoTratti ricavati, nel caso di elevate variazioni angolari tra l'inizio e la fine + // ( tra due curva di Sync) si potrebbero generare delle torsioni non volute + // -->! NB. Queste linee vengono create considerando le SubQuadrangolazioni con gli Spigoli. !<-- BIPNTVECTOR vTwistSyncLines ; if ( vEdgeSyncLines.empty()) ManageTwistInQuadrangulation( pCrvQuad1, pCrvQuad2, vTwistSyncLines) ; @@ -6382,19 +6634,24 @@ SurfBezier::CreateSmoothRuledByTwoCurves( const ICurve* pCurve0, const ICurve* p SyncLinePrev = SyncLineNext ; } } - //for ( int i = 0 ; i < ssize( vTwistSyncLines) ; ++ i) { - // PtrOwner pLine( CreateCurveLine()) ; pLine->Set( vTwistSyncLines[i].first, vTwistSyncLines[i].second) ; - // int nNewId = pGeomDB->AddGeoObj( GDB_ID_NULL, nDestGrp, Release( pLine)) ; - // pGeomDB->SetMaterial( nNewId, OLIVE) ; - //} - +#if SAVEPACEDISO + for ( int i = 0 ; i < ssize( vTwistSyncLines) ; ++ i) { + PtrOwner pLine( CreateCurveLine()) ; pLine->Set( vTwistSyncLines[i].first, vTwistSyncLines[i].second) ; + vGeo.push_back( Release( pLine)) ; + vCol.push_back( OLIVE) ; + } +#endif // Aggiorno i parametri ptPrev1 = ptCurr1 ; dUPrev1 = dUCurr1 ; dLenPrev1 = dLenCurr1 ; ptPrev2 = ptCurr2 ; dUPrev2 = dUCurr2 ; dLenPrev2 = dLenCurr2 ; } - return CreateByIsoParamSet( pCrvEdge1, pCrvEdge2, vEdgeSyncLines) ; + #if SAVEPACEDISO + SaveGeoObj( vGeo, vCol, "D:\\Temp\\bezier\\ruled\\trimming\\smooth.nge") ; + #endif + + return CreateByIsoParamSet( pCrvEdge1, pCrvEdge2, vSyncLines) ; } //---------------------------------------------------------------------------- diff --git a/Trimming.cpp b/Trimming.cpp index c8eeb8c..588f1f8 100644 --- a/Trimming.cpp +++ b/Trimming.cpp @@ -83,6 +83,8 @@ using namespace std ; +bool RegolarizeBorders( const ICurve* pCrv1, const ICurve* pCrv2, ISurfBezier* pSurfBz, double dTol) ; + // Vettori e Matrici di Curve Composite typedef vector COMPOVECTOR ; typedef vector COMPOMATRIX ; @@ -3959,7 +3961,7 @@ GetTrimmingSurfBzSyncPoints( const ICurve* pCrvEdge1, const ICurve* pCrvEdge2, #endif // Definisco la superficie di Bezier rigata - PtrOwner pSBzRuled( GetBasicSurfBezier( GetSurfBezierRuled( pCompoEdge1, pCompoEdge2, ISurfBezier::RLT_B_MINDIST_PLUS, dMyLinTol))) ; + PtrOwner pSBzRuled( GetBasicSurfBezier( GetSurfBezierRuledSmooth( pCompoEdge1, pCompoEdge2, 10))) ; if ( IsNull( pSBzRuled) || ! pSBzRuled->IsValid()) return false ; @@ -4967,12 +4969,12 @@ typedef vector PNTINFOVECTOR ; //------------------------------------------------------------------------------ // Funzione per la regolarizzazione delle curve di bordo di una lavorazione di trim // Le curve vengono modificate entro una data tolleranza, in modo che -bool +static bool RegolarizeBorders( const ICurve* pCrv1, const ICurve* pCrv2, ISurfBezier* pSurfBz, double dTol) { #if DEBUG_SMOOTH_CURVATURE - VT.push_back( pSurfBz->Clone()) ; + VT.push_back( pCrv1->Clone()) ; #endif // le due curve sono compo di bezier, e tutte le sottocurve sono dello stesso grado (3) PNTINFOVECTOR vPntInfo ; @@ -5008,65 +5010,54 @@ RegolarizeBorders( const ICurve* pCrv1, const ICurve* pCrv2, ISurfBezier* pSurfB for ( int i = 0 ; i < ssize( vPntInfo) ; ++i) { if ( nCurrSide == 0) nCurrSide = vPntInfo[i].nSide ; - int j = i == ssize( vPntInfo) ? 0 : i + 1 ; - if ( i > 2 && vPntInfo[i].nSide != nCurrSide && vPntInfo[i].nSide != 0) { - if ( c == 2 && vPntInfo[i].nSide != nCurrSide) { - // ho trovato due punti a cavallo di una giunzione che formano localmente un cambio di concavità da evitare - Vector3d vtMove ; - if ( vPntInfo[i].dDist > EPS_SMALL) - vtMove = vPntInfo[i].vtN * vPntInfo[i].dDist * 2 ; - else - vtMove = vPntInfo[i].vtN * vPntInfo[i-1].dDist * 2 ; - vPntInfo[i].pt = vPntInfo[i].pt + vtMove ; - } - //devo modificare sicuramente due curve - int k = i / 3 ; - if ( i % 3 == 0) - --k ; - // aggiungo la prima curva - CurveBezier cbPrev ; - cbPrev.Init( 3,false) ; - cbPrev.SetControlPoint( 0, vPntInfo[k*3].pt) ; - cbPrev.SetControlPoint( 0, vPntInfo[k*3+1].pt) ; - cbPrev.SetControlPoint( 0, vPntInfo[k*3+2].pt) ; - cbPrev.SetControlPoint( 0, vPntInfo[k*3+3].pt) ; - CC.AddCurve( cbPrev) ; - //aggiungo la seconda curva - CurveBezier cbNext ; - cbNext.Init( 3,false) ; - cbNext.SetControlPoint( 0, vPntInfo[k*3+3].pt) ; - cbNext.SetControlPoint( 0, vPntInfo[k*3+4].pt) ; - cbNext.SetControlPoint( 0, vPntInfo[k*3+5].pt) ; - cbNext.SetControlPoint( 0, vPntInfo[k*3+6].pt) ; - CC.AddCurve( cbNext) ; + int nFirst = i ; + int nSecond = nFirst == ssize( vPntInfo) ? 0 : nFirst + 1 ; + int nThird = nSecond == ssize( vPntInfo) ? 0 : nSecond + 1 ; + int nFourth = nThird == ssize( vPntInfo) ? 0 : nThird + 1 ; + if ( i > 2 && vPntInfo[nFirst].nSide != nCurrSide && vPntInfo[nFirst].nSide != 0) { + // devo verificare anche che sia uguale ai due successivi + if ( ( vPntInfo[nFirst].nSide == vPntInfo[nSecond].nSide || vPntInfo[nSecond].nSide == 0) && + ( vPntInfo[nFirst].nSide == vPntInfo[nThird].nSide || vPntInfo[nThird].nSide == 0)) { + // se il successivo al terzetto è diverso ho un terzetto anomalo da aggiustare + // altrimenti ho un cambio naturale di concavità + if ( vPntInfo[nFirst].nSide != vPntInfo[nFourth].nSide) { + // modifico due curve + CurveComposite CCToApprox ; + int nCurrSub = nFirst / 3 ; + if ( nFirst % 3 == 0) + --nCurrSub ; + CCToApprox.AddCurve( pCC1->CopyParamRange( nCurrSub, nCurrSub + 2)) ; + Vector3d vtStart ; pCC1->GetStartDir( vtStart) ; + Vector3d vtEnd ; pCC1->GetEndDir( vtEnd) ; + PtrOwner pCrvApprox( ApproxCurveWithBezier( &CCToApprox, dTol, vtStart, vtEnd)) ; + if ( ! IsNull( pCrvApprox)) + CC.AddCurve( Release( pCrvApprox)) ; + else + return false ; - c = 0 ; - i = k + 6 ; - nCurrSide = vPntInfo[i].nSide ; + // scavalco i punti delle curve che ho appena modificato + i += 6 ; + } + c = 0 ; + nCurrSide = vPntInfo[i].nSide ; + } + else + ++c ; } else { ++c ; - if ( i % 3 == 0) - CC.AddCurve( pCC1->GetCurve( i / 3)->Clone()) ; + if ( i != 0 && i % 3 == 0) + CC.AddCurve( pCC1->GetCurve( i / 3 - 1)->Clone()) ; } } - PtrOwner pSB( CreateSurfBezier()) ; - pSB->CreateSmoothRuledByTwoCurves( pCrv1, pCrv2, 10) ; + //PtrOwner pSB( CreateSurfBezier()) ; + //pSB->CreateSmoothRuledByTwoCurves( pCrv1, pCrv2, 10) ; #if DEBUG_SMOOTH_CURVATURE - VT.push_back( pSB->Clone()) ; + VT.push_back( CC.Clone()) ; + VT.push_back( pSurfBz->Clone()) ; SaveGeoObj( VT, "D:\\Temp\\bezier\\ruled\\smoothness\\regolarized.nge") ; #endif return true ; } - -//------------------------------------------------------------------------------ -// Funzione per la regolarizzazione LOCALMENTE una curva di bordo -// Le curve vengono modificate entro una data tolleranza, in modo che -bool -RegolarizeBordersLocally( ICurve* pCrv, ISurfBezier* pSurfBz, double dTol) -{ - - return true ; -}