From ef12fe8bd12564e59d137d45b2e3ee82434f2450 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Tue, 30 Jun 2026 09:22:32 +0200 Subject: [PATCH] EgtGeomKernel : - miglioria dell'offset3d e del SurfExtend. --- OffsetCurve3d.cpp | 90 +++++++++++++++++++++++++++++--------------- ProjectCurveSurf.cpp | 87 +++++++++++++++++++++++++++++++++++------- 2 files changed, 134 insertions(+), 43 deletions(-) diff --git a/OffsetCurve3d.cpp b/OffsetCurve3d.cpp index ed7801e..d4ec9bb 100644 --- a/OffsetCurve3d.cpp +++ b/OffsetCurve3d.cpp @@ -25,10 +25,10 @@ using namespace std ; -#define SAVECRVORIG 0 -#define SAVEOFFDIR 0 -#define SAVECYL 0 -#define SAVEOFFSET 0 +#define SAVECRVORIG 1 +#define SAVEOFFDIR 1 +#define SAVECYL 1 +#define SAVEOFFSET 1 #if SAVECRVORIG || SAVEOFFDIR || SAVECYL || SAVEOFFSET #include "/EgtDev/Include/EGkColor.h" #include "/EgtDev/Include/EGkGeoVector3d.h" @@ -154,11 +154,22 @@ OffsetCurve3d::Make( const PNT5AXVECTOR& vPnt5Ax, double dOffDist, int nType) const ICurve* pCrvCurr ; OFFSETSEGVEC vOffsetCrvs ; Vector3d vtDirPrevOff = V_INVALID ; - for ( int i = 1 ; i <= pCrv->GetCurveCount() ; ++i) { - pCrvCurr = pCrv->GetNextCurve() ; + int nRejected = 0 ; + int nClosure = bClosed ? 1 : 0 ; + bool bCheckingClosure = false ; + bool bPlanarConcCvex = false ; + for ( int i = 1 ; i <= pCrv->GetCurveCount() + nClosure ; ++i) { + int nCurr = i ; + int nPrev = i - 1 ; + if ( i > pCrv->GetCurveCount()) { + nCurr = 0 ; + bCheckingClosure = true ; + } + if ( ! bCheckingClosure) + pCrvCurr = pCrv->GetNextCurve() ; if ( pCrvCurr == nullptr && bClosed) pCrvCurr = pCrv->GetFirstCurve() ; - Vector3d vtOffDir = vOffDir[i] ; + Vector3d vtOffDir = vOffDir[nCurr] ; Vector3d vtDirCurr ; if ( pCrvCurr != nullptr) pCrvCurr->GetStartDir( vtDirCurr) ; @@ -166,16 +177,18 @@ OffsetCurve3d::Make( const PNT5AXVECTOR& vPnt5Ax, double dOffDist, int nType) vtDirCurr = vtDirPrev ; pCrvPrev->GetStartDir( vtDirPrev) ; Vector3d vtTang ; - if ( vFlag[i] != OffsetCurve3d::AngType::ANG_CVEX) + // so che ci sono due punti in stretta prossimità dell'angolo, quindi discrimino tra la tangeten prima e dopo l'angolo + // negli altri casi faccio la media + if ( vFlag[nCurr] != OffsetCurve3d::AngType::ANG_CVEX) vtTang = Media( vtDirCurr, vtDirPrev) ; - else if ( vFlag[i] == OffsetCurve3d::AngType::ANG_CVEX && vFlag[i-1] != OffsetCurve3d::AngType::ANG_CVEX) + else if ( vFlag[nCurr] == OffsetCurve3d::AngType::ANG_CVEX && vFlag[nPrev] != OffsetCurve3d::AngType::ANG_CVEX) vtTang = vtDirPrev ; else vtTang = vtDirCurr ; vtTang.Normalize() ; Vector3d vtCorr = vtOffDir ; double dCorrK = 1 ; - if ( vFlag[i] == OffsetCurve3d::AngType::ANG_CONC) { + if ( vFlag[nCurr] == OffsetCurve3d::AngType::ANG_CONC) { double dHalfAlfa = acos( vtTang * vtTangPrev) ; dCorrK = 1 / sin( 90 - dHalfAlfa) ; } @@ -188,7 +201,7 @@ OffsetCurve3d::Make( const PNT5AXVECTOR& vPnt5Ax, double dOffDist, int nType) dRadCorr = dOffDist ; ptP = ptP + dRadCorr * dCorrK * vtCorr ; // se secondo punto di angolo esterno di fianco, inserisco movimenti intermedi - if ( vFlag[i] == OffsetCurve3d::AngType::ANG_CVEX && vFlag[i-1] == OffsetCurve3d::AngType::ANG_CVEX) { + if ( vFlag[nCurr] == OffsetCurve3d::AngType::ANG_CVEX && vFlag[nPrev] == OffsetCurve3d::AngType::ANG_CVEX && bPlanarConcCvex) { double dAlfa = acos( vtTang * vtTangPrev) ; double dDelta = dOffDist * tan( dAlfa / 4) ; Point3d ptAdd1 = ptPrev + dDelta * vtTangPrev ; @@ -201,9 +214,14 @@ OffsetCurve3d::Make( const PNT5AXVECTOR& vPnt5Ax, double dOffDist, int nType) vOffsetCrvs.emplace_back( pCL2, OffsetCurve3d::AngType::ANG_CVEX, -1) ; ptPrev = ptAdd2 ; } + Vector3d vtAng = vtDirPrev ^ vtDirCurr ; + const double COS_ANG_MAX_PLANAR = 0.7 ; + bPlanarConcCvex = false ; + if ( ! vtAng.IsSmall() && vtAng.Normalize()) + bPlanarConcCvex = abs( vtAng * vOffDir[nCurr]) < COS_ANG_MAX_PLANAR ; //// se punto di angolo interno di fianco, elimino eventuali movimenti precedenti invertiti - //if ( vFlag[i] == OffsetCurve3d::AngType::ANG_CVEX == 3) { + //if ( vFlag[nCurr] == OffsetCurve3d::AngType::ANG_CVEX == 3) { // local nLastId = EgtGetLastInGroup( nClPathId) // while nLastId do // local vtMlast = ptP - EgtEP( nLastId, GDB_ID.ROOT) ; vtMlast:normalize() @@ -226,23 +244,28 @@ OffsetCurve3d::Make( const PNT5AXVECTOR& vPnt5Ax, double dOffDist, int nType) // end //} - Vector3d vtDirCurrOff = ptP - ptPrev ; vtDirCurrOff.Normalize() ; - double dProj = 1 ; - if ( vtDirPrevOff.IsValid()) - dProj = vtDirCurrOff * vtDirPrevOff ; - // prima di inserirlo controllo che il tratto non torni indietro - if ( vFlag[i] != ANG_STR || dProj > - 0.5) { - // aggiungo tratto - ICurveLine* pCL = CreateBasicCurveLine() ; - pCL->Set( ptPrev, ptP) ; - vOffsetCrvs.emplace_back( pCL, vFlag[i], i - 1) ; - // aggiorno punto precedente - ptPrev = ptP ; - vtCorrPrev = vtCorr ; - vtTangPrev = vtTang ; - vtDirPrev = vtDirCurr ; - pCrvPrev = pCrvCurr ; - vtDirPrevOff = vtDirCurrOff ; + if ( ! bCheckingClosure) { + Vector3d vtDirCurrOff = ptP - ptPrev ; vtDirCurrOff.Normalize() ; + double dProj = 1 ; + if ( vtDirPrevOff.IsValid()) + dProj = vtDirCurrOff * vtDirPrevOff ; + // prima di inserirlo controllo che il tratto non torni indietro + if ( vFlag[nCurr] != ANG_STR || dProj > - 0.5) { + // aggiungo tratto + ICurveLine* pCL = CreateBasicCurveLine() ; + pCL->Set( ptPrev, ptP) ; + vOffsetCrvs.emplace_back( pCL, vFlag[nCurr], i - 1) ; + // aggiorno punto precedente + ptPrev = ptP ; + vtCorrPrev = vtCorr ; + vtTangPrev = vtTang ; + vtDirPrev = vtDirCurr ; + if ( i < pCrv->GetCurveCount()) + pCrvPrev = pCrvCurr ; + vtDirPrevOff = vtDirCurrOff ; + } + else + ++nRejected ; } } @@ -251,6 +274,7 @@ OffsetCurve3d::Make( const PNT5AXVECTOR& vPnt5Ax, double dOffDist, int nType) Point3d ptP ; vOffsetCrvs.front().pCrv->GetStartPoint( ptP) ; ICurveLine* pCL = CreateBasicCurveLine() ; pCL->Set( ptPrev, ptP) ; + // aggiungo solo se valida, quindi se non sono già coincidenti if ( pCL->IsValid()) vOffsetCrvs.emplace_back( pCL, OffsetCurve3d::AngType::ANG_STR, -1) ; } @@ -301,10 +325,16 @@ OffsetCurve3d::Make( const PNT5AXVECTOR& vPnt5Ax, double dOffDist, int nType) vCol.push_back( PURPLE) ; else if ( vOffsetCrvs[i].nFlag == OffsetCurve3d::AngType::ANG_CVEX) vCol.push_back( RED) ; + else if ( vOffsetCrvs[i].nFlag == OffsetCurve3d::AngType::ANG_BEFORE_CONC) + vCol.push_back( OLIVE) ; + else if ( vOffsetCrvs[i].nFlag == OffsetCurve3d::AngType::ANG_AFTER_CONC) + vCol.push_back( YELLOW) ; + else if ( vOffsetCrvs[i].nFlag == OffsetCurve3d::AngType::ANG_CONC) + vCol.push_back( Color(0,64,0)) ; //dark green } #endif SaveGeoObj( vGeo, vCol, "C:\\Temp\\curve offset 3d\\crvoffset.nge") ; -#endif +#endif // qua andrebbe gestito con una chain ( ptorebbero essere più di una curva) PtrOwner pCrvOffset( CreateBasicCurveComposite()) ; diff --git a/ProjectCurveSurf.cpp b/ProjectCurveSurf.cpp index 7383155..38d87ec 100644 --- a/ProjectCurveSurf.cpp +++ b/ProjectCurveSurf.cpp @@ -161,6 +161,45 @@ AddPointsOnCorners( PNT5AXVECTOR& vPt5ax) } } + int i = 0 ; + int j = ssize( vPt5ax) - 1 ; + bool bClosed = AreSamePointApprox( vPt5ax[i].ptP, vPt5ax[j].ptP) ; + // se la curva è chiusa controllo inizio e fine + if ( bClosed) { + // se normali tra corrente e precedente oltre limite + int k = i + 1 ; + int z = j - 1 ; + double dProjPrev = ( vPt5ax[j].ptP - vPt5ax[z].ptP) * vPt5ax[i].vtDir1 ; + double dProjCurr = ( vPt5ax[k].ptP - vPt5ax[i].ptP) * vPt5ax[j].vtDir1 ; + if ( vPt5ax[i].vtDir1 * vPt5ax[j].vtDir1 < COS_ANG_MAX_CORNER) { + bool bConvex = ( abs( dProjCurr) > abs( dProjPrev) ? dProjCurr < 0 : dProjPrev < 0) ; + if ( bConvex) { + vPt5ax[i].nFlag = P5AX_CVEX ; + vPt5ax[j].nFlag = P5AX_CVEX ; + } + else { + vPt5ax[i].nFlag = P5AX_CONC ; + vPt5ax[j].nFlag = P5AX_CONC ; + Vector3d vtDir1 = Media( vPt5ax[i].vtDir1, vPt5ax[j].vtDir1) ; vtDir1.Normalize() ; + Vector3d vtDir2 = Media( vPt5ax[i].vtDir2, vPt5ax[j].vtDir2) ; vtDir2.Normalize() ; + Vector3d vtDirU = Media( vPt5ax[i].vtDirU, vPt5ax[j].vtDirU) ; vtDirU.Normalize() ; + Vector3d vtDirV = Media( vPt5ax[i].vtDirV, vPt5ax[j].vtDirV) ; vtDirV.Normalize() ; + vPt5ax[i].vtDir1 = vtDir1 ; + vPt5ax[j].vtDir1 = vtDir1 ; + vPt5ax[i].vtDir2 = vtDir2 ; + vPt5ax[j].vtDir2 = vtDir2 ; + vPt5ax[i].vtDirU = vtDirU ; + vPt5ax[j].vtDirU = vtDirU ; + vPt5ax[i].vtDirV = vtDirV ; + vPt5ax[j].vtDirV = vtDirV ; + } + } + else if ( abs( dProjPrev) > abs( dProjCurr) ? dProjPrev > dSinSmallAngle : dProjCurr > dSinSmallAngle) { + vPt5ax[i].nFlag = P5AX_SMOOTH_CONC ; + vPt5ax[j].nFlag = P5AX_SMOOTH_CONC ; + } + } + // riscorro tutto il vettore per vedere se ho creato delle zone concave smooth frammentate (separate solo da un tratto non classificato concavo), che quindi uniformo for ( int i = 1 ; i < ssize( vPt5ax) - 1 ; ++ i) { if ( vPt5ax[i].nFlag != P5AX_SMOOTH_CONC && vPt5ax[i-1].nFlag == P5AX_SMOOTH_CONC && vPt5ax[i+1].nFlag == P5AX_SMOOTH_CONC) @@ -404,18 +443,25 @@ ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, PL.GetLastLine( pt1, pt2) ; vtDirPrev = pt2 - pt1 ; } + Vector3d vtLast ; PL.GetLastULine( &dPar, &ptP, &dParNext, &ptPNext) ; + vtLast = ptPNext - ptP ; vtLast.Normalize() ; bool bFound = PL.GetFirstULine( &dPar, &ptP, &dParNext, &ptPNext) ; Vector3d vtFirst = ptPNext - ptP ; vtFirst.Normalize() ; bool bClosed = PL.IsClosed() ; bool bLast = false ; Vector3d vtNormPrev = V_INVALID ; + Point3d ptPrev ; + bool bFirst = true ; while ( bFound) { // se trovo proiezione, la salvo Point5ax Pt5ax ; if ( ProjectPointOnSurf( ptP, vpSurf, dPar, Pt5ax)) vPt5ax.emplace_back( Pt5ax) ; // controllo che la normale trovata sia in linea con la precedente, se i due tratti erano abbastanza allineati - if ( ! bClosed && ssize( vPt5ax) > 2) { + bool bRecalc = false ; + if ( bFirst) + bRecalc = true ; + if ( ssize( vPt5ax) > 2) { Point5ax& pt5Curr = vPt5ax.back() ; Point5ax& pt5Prev = vPt5ax.end()[-2] ; Point5ax& pt5PrevPrev = vPt5ax.end()[-3] ; @@ -424,9 +470,25 @@ ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, double dProjDir = vtDirCurr * vtDirPrev ; if ( dProjDir > COS_ANG_MAX_CORNER) { double dProjNorm = vPt5ax.back().vtDir1 * vtNormPrev ; - if ( dProjNorm < COS_ANG_MAX_CORNER) { - vPt5ax.back().vtDir1 = vtNormPrev ; - vPt5ax.back().vtDir2 = vtNormPrev ; + if ( dProjNorm < COS_ANG_MAX_CORNER) + bRecalc = true ; + } + } + Vector3d vtDirNext = ptPNext - ptP ; vtDirNext.Normalize() ; + // se sono arrivato ad uno spigolo tengo la normale appena prima dello spigolo + if ( bRecalc) { + Point3d ptAlter ; + if ( ! bFirst) { + Vector3d vtDirPrev = ptP - ptPrev ; vtDirPrev.Normalize() ; + ptAlter = ptP - vtDirPrev * 5 * EPS_SMALL ; + } + else + ptAlter = ptP + vtDirNext * 5 * EPS_SMALL ; + Point5ax Pt5axRec ; + if ( ProjectPointOnSurf( ptAlter, vpSurf, dPar, Pt5axRec)) { + if ( Pt5axRec.vtDir1 * Pt5ax.vtDir1 < COS_ANG_MAX_CORNER) { + vPt5ax.back().vtDir1 = Pt5axRec.vtDir1 ; + vPt5ax.back().vtDir2 = Pt5axRec.vtDir2 ; } } } @@ -435,32 +497,31 @@ ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, Vector3d vtDir ; if ( ! bNormOrTang) { Vector3d vtNorm = vPt5ax.back().vtDir1 ; - if ( ! bLast) { - vtDir = ptPNext - ptP ; - vtDir.Normalize() ; - } - else if ( bClosed) - vtDir = vtFirst ; + if ( bFirst) + vtDir = vtDirNext ; else vtDir = vtDirPrev ; - Vector3d vtDirTemp = vtDir ; - if ( vtDirPrev.IsValid()) { + // in caso sia stato superato l'angolo limite dò priorità alla direzione precedente + if ( vtDirPrev.IsValid() && (! bFirst || ( bFirst && bClosed))) { double dProj = vtDir * vtDirPrev ; if ( dProj > COS_ANG_MAX_CORNER) vtDir = Media( vtDir, vtDirPrev) ; } - vtDirPrev = vtDirTemp ; + vtDirPrev = vtDirNext ; Vector3d vtTang = vtDir ^ vtNorm ; vtTang.Normalize() ; vPt5ax.back().vtDir1 = vtTang ; vPt5ax.back().vtDir2 = vtTang ; } // passo al successivo + ptPrev = ptP ; bFound = PL.GetNextULine( &dPar, &ptP, &dParNext, &ptPNext) ; // se sono arrivato alla fine aggiungo l'ultimo punto if ( ! bFound && ! bLast) { bLast = true ; bFound = true ; } + if ( bFirst) + bFirst = false ; } // se richiesto, inserimento punti intermedi in presenza di spigoli