From 4c693ccd6065a7697af752da73387ec6ec983583 Mon Sep 17 00:00:00 2001 From: Daniele Bariletti Date: Thu, 4 Sep 2025 12:43:50 +0200 Subject: [PATCH] EgtGeomkernel : - aggiunta intersezione linea - superficie bezier bilineare. --- IntersLineSurfBez.cpp | 259 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 258 insertions(+), 1 deletion(-) diff --git a/IntersLineSurfBez.cpp b/IntersLineSurfBez.cpp index 1cfabe9..b9780e1 100644 --- a/IntersLineSurfBez.cpp +++ b/IntersLineSurfBez.cpp @@ -14,11 +14,17 @@ //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "CurveLine.h" +#include "CurveBezier.h" +#include "CurveComposite.h" +#include "SurfFlatRegion.h" #include "/EgtDev/Include/EGkDistPointLine.h" +#include "/EgtDev/Include/EGkDistLineLine.h" +#include "/EgtDev/Include/EGkDistPointSurfFr.h" #include "/EgtDev/Include/EGkIntersLineTria.h" #include "/EgtDev/Include/EGkIntersLineSurfTm.h" #include "/EgtDev/Include/EGkIntersLineSurfBez.h" #include "/EgtDev/Include/EGkSurfBezier.h" +#include "/EgtDev/Include/ENkPolynomialRoots.h" using namespace std ; @@ -67,7 +73,7 @@ static void UpdateInfoIntersLineSurfBz( const Point3d& ptL, const Vector3d& vtDir, int nILT, int nT, const Point3d& ptSP, const Point3d& ptIBz, double dCos, const Point3d& ptSP2, const Point3d& ptIBz2, double dCos2, ILSBIVECTOR& vInfo) { - if ( nILT == ILTT_IN || nILT == ILTT_EDGE || nILT == ILTT_VERT) { + if ( nILT == ILTT_IN || nILT == ILTT_EDGE || nILT == ILTT_VERT || nILT == ILTT_NO_TRIA) { double dU = ( ptIBz - ptL) * vtDir ; vInfo.emplace_back( nILT, dU, nT, dCos, ptIBz, ptSP) ; } @@ -232,3 +238,254 @@ FilterLineSurfBzInters( const ILSBIVECTOR& vInfo, INTDBLVECTOR& vInters) } return true ; } + +//---------------------------------------------------------------------------- +// Intersezione di una linea con una superficie di Bezier +//---------------------------------------------------------------------------- +bool +IntersLineSurfBzBilinear( const Point3d& ptL, const Vector3d& vtL, double dLen, const ISurfBezier* pSurfBz, + ILSBIVECTOR& vInfo, bool bFinite) +{ + int nDegU, nDegV, nSpanU, nSpanV ; + bool bRat, bTrimmed ; + pSurfBz->GetInfo( nDegU, nDegV, nSpanU, nSpanV, bRat, bTrimmed) ; + + // funzione pensata per funzionare solo con una monopatch bilineare + if( nDegU > 1 || nDegV > 1 || nSpanU > 1 || nSpanV > 1 || bRat) + return false ; + + int nInters = int( vInfo.size()) ; + + PNTVECTOR vPntCtrl ; + for( int p = 0 ; p < 4 ; ++p) { + bool bOk = false ; + vPntCtrl.push_back( pSurfBz->GetControlPoint( p, &bOk)) ; + } + + Vector3d a = vPntCtrl[3] - vPntCtrl[1] + ( vPntCtrl[0] - vPntCtrl[2]) ; + Vector3d b = vPntCtrl[1] - vPntCtrl[0] ; + Vector3d c = vPntCtrl[2] - vPntCtrl[0] ; + Vector3d d = vPntCtrl[0] - ORIG ; + + double A1 = a.x * vtL.z - a.z * vtL.x ; + double B1 = b.x * vtL.z - b.z * vtL.x ; + double C1 = c.x * vtL.z - c.z * vtL.x ; + double A2 = a.y * vtL.z - a.z * vtL.y ; + double B2 = b.y * vtL.z - b.z * vtL.y ; + double C2 = c.y * vtL.z - c.z * vtL.y ; + + double D1 = ( d.x - ptL.x) * vtL.z - ( d.z - ptL.z) * vtL.x ; + double D2 = ( d.y - ptL.y) * vtL.z - ( d.z - ptL.z) * vtL.y ; + + DBLVECTOR vdCoeff, vdRoots ; + vdCoeff = { (B2 * D1 - B1 * D2), ( A2 * D1 - A1 * D2 + B2 * C1 - B1 * C2), ( A2 * C1 - A1 * C2)} ; + int nRoots = PolynomialRoots( 2, vdCoeff, vdRoots) ; + bool bFound = false ; + for( int w = 0 ; w < nRoots ; ++w) { + if ( vdRoots[w] > 0 - EPS_ZERO && vdRoots[w] < 1 + EPS_ZERO ) { + double dU = 0, dV = vdRoots[w] ; + // verifico che non sia una soluzione con molteplicità > 1 + bool bAlreadyFound = false ; + for ( int k = w - 1 ; k >= 0 && ! bAlreadyFound ; --k) + bAlreadyFound = abs( dV - vdRoots[k]) < EPS_PARAM ; + if( ! bAlreadyFound) { + dU = (dV * (C1 - C2) + ( D1 - D2)) / ( dV * ( A2 - A1) + ( B2 - B1)) ; + if ( dU > - EPS_ZERO && dU < 1 + EPS_ZERO) { + Point3d ptIBez, ptIBez2 ; + Vector3d vtN ; + pSurfBz->GetPointNrmD1D2(dU, dV, ISurfBezier::Side::FROM_MINUS, ISurfBezier::Side::FROM_MINUS, ptIBez, vtN) ; + Point3d ptSP( dU, dV, 0), ptSP2 ; + double dCos = vtN * vtL, dCos2 = 0 ; + UpdateInfoIntersLineSurfBz( ptL, vtL, ILTT_NO_TRIA, -1, ptSP, ptIBez, dCos, ptSP2, ptIBez2, dCos2, vInfo) ; + bFound = true ; + } + } + } + + // se tutti i coefficienti sono zero allora potrei avere una linea che giace sulla superficie + // per trovare i punti di inizio e fine sovrapposizione trovo i punti a minima distanza tra la linea e gli edge della superficie + if( ! bFound && abs( vdCoeff[0]) < EPS_ZERO && abs( vdCoeff[1]) < EPS_ZERO && abs( vdCoeff[2]) < EPS_ZERO) { + ICRVCOMPOPOVECTOR vCrvEdge( 4) ; + vCrvEdge[0].Set(pSurfBz->GetCurveOnU( 0)) ; + vCrvEdge[1].Set(pSurfBz->GetCurveOnV( 1)) ; + vCrvEdge[2].Set(pSurfBz->GetCurveOnU( 1)) ; + vCrvEdge[3].Set(pSurfBz->GetCurveOnV( 0)) ; + double dAngTolDeg = 5 ; + for( int i = 0 ; i < 4 ; ++i) { + PolyLine plApprox ; vCrvEdge[0]->ApproxWithLines( EPS_SMALL, dAngTolDeg, ICurve::ApprLineType::APL_STD, plApprox) ; + //CurveComposite cCC ; + //cCC.FromPolyLine( plApprox) ; + int nClosestLine = -1 ; + double dMinDist = INFINITO ; + Point3d pt ; plApprox.GetFirstPoint( pt) ; + Point3d ptClosest ; + int c = 0 ; + int nTot = plApprox.GetPointNbr() ; + for( int j = 0 ; j < nTot ; ++j) { + DistPointLine dpl( pt, ptL, vtL, dLen, bFinite) ; + double dDist = INFINITO ; + dpl.GetDist( dDist) ; + if ( dDist < dMinDist) { + nClosestLine = c ; + dMinDist = dDist ; + } + plApprox.GetNextPoint( pt) ; + ++ c ; + } + + Point3d ptInt1, ptInt2 ; + if ( c < nTot - 1 && c > 0) { + // tra i due tratti dell'approssimazione che arrivano al punto selezionato come più vicino, devo trovare quale si avvicina di più + Point3d ptStart ; plApprox.GetFirstPoint( ptStart) ; + Point3d ptEnd ; + for( int z = 1 ; z < c - 1 ; ++z) + plApprox.GetNextPoint( ptStart) ; + plApprox.GetNextPoint( ptEnd) ; + // linea precedente al punto + Vector3d vtLinePre = ptEnd - ptStart ; + double dLenPre = vtLinePre.Len() ; + DistLineLine dllPre( ptStart, vtLinePre, dLenPre, ptL, vtL,dLen) ; + double dDistPre = INFINITO ; + dllPre.GetDist( dDistPre) ; + // linea che inzia con quel punto + ptStart = ptEnd ; + plApprox.GetNextPoint( ptEnd) ; + Vector3d vtLineCurr = ptEnd - ptStart ; + double dLenCurr = vtLineCurr.Len() ; + DistLineLine dllCurr( ptStart, vtLineCurr, dLenCurr, ptL, vtL,dLen) ; + double dDistCurr = INFINITO ; + dllCurr.GetDist( dDistCurr) ; + + if( dDistPre < dDistCurr) + dllPre.GetMinDistPoints( ptInt1, ptInt2) ; + else + dllCurr.GetMinDistPoints( ptInt1, ptInt2) ; + } + else if ( c == 0){ + // il punto più vicino è sulla prima linea + Point3d ptStart ; plApprox.GetFirstPoint( ptStart) ; + Point3d ptEnd ; plApprox.GetNextPoint( ptEnd) ; + Vector3d vtLineCurr = ptEnd - ptStart ; + double dLenCurr = vtLineCurr.Len() ; + DistLineLine dllCurr( ptStart, vtLineCurr, dLenCurr, ptL, vtL,dLen) ; + dllCurr.GetMinDistPoints( ptInt1, ptInt2) ; + } + else if ( c == nTot- 1) { + // il punto più vicino è sull'ultima linea + Point3d ptStart ; plApprox.GetFirstPoint( ptStart) ; + Point3d ptEnd ; + for( int z = 1 ; z < c - 1 ; ++z) + plApprox.GetNextPoint( ptStart) ; + plApprox.GetNextPoint( ptEnd) ; + Vector3d vtLinePre = ptEnd - ptStart ; + double dLenPre = vtLinePre.Len() ; + DistLineLine dllCurr( ptStart, vtLinePre, dLenPre, ptL, vtL,dLen) ; + dllCurr.GetMinDistPoints( ptInt1, ptInt2) ; + } + + double dU1 = 0, dV1 = 0, dU2 = 0, dV2 = 0 ; + // se ho trovato due punti vuol dire che la linea coincide con un edge e ho trovato tutto quello che serve + if( ! AreSamePointExact( ptInt2, ORIG)) { + if( i == 0) { + //dV1 = 0 ; dV2 = 0 ; + vCrvEdge[0]->GetParamAtPoint( ptInt1, dU1) ; + vCrvEdge[0]->GetParamAtPoint( ptInt2, dU2) ; + } + else if( i == 1) { + //dU1 = 1 ; dU2 = 1 ; + vCrvEdge[1]->GetParamAtPoint( ptInt1, dV1) ; + vCrvEdge[1]->GetParamAtPoint( ptInt2, dV2) ; + } + else if( i == 2){ + //dV1 = 1 ; dV2 = 1 ; + vCrvEdge[2]->GetParamAtPoint( ptInt1, dU1) ; + vCrvEdge[2]->GetParamAtPoint( ptInt2, dU2) ; + } + else if( i == 3){ + //dU1 = 0 ; dU2 = 0 ; + vCrvEdge[3]->GetParamAtPoint( ptInt1, dV1) ; + vCrvEdge[3]->GetParamAtPoint( ptInt2, dV2) ; + } + Point3d ptIBez1, ptIBez2 ; + Vector3d vtN1, vtN2 ; + pSurfBz->GetPointNrmD1D2(dU1, dV1, ISurfBezier::Side::FROM_MINUS, ISurfBezier::Side::FROM_MINUS, ptIBez1, vtN1) ; + pSurfBz->GetPointNrmD1D2(dU2, dV2, ISurfBezier::Side::FROM_MINUS, ISurfBezier::Side::FROM_MINUS, ptIBez2, vtN2) ; + Point3d ptSP1( dU1, dV1, 0) ; + double dCos1 = vtN1 * vtL ; + Point3d ptSP2( dU2, dV2, 0) ; + double dCos2 = vtN2 * vtL ; + // se avevo già trovato un punto singolo che coincide col primo punto di questa intersezione sovrapposta, allora cancello l'intersezione singola che + // avevo salvato e aggiungo quella sovrapposto che ho trovato ora + if( bFound) { + int nNewTot = int(vInfo.size()) ; + int nNewInters = nNewTot - nInters ; + bool bAlreadyFound = false ; + for( int i = 0 ; i < nNewInters ; ++i) { + bAlreadyFound = AreSamePointApprox(vInfo[nNewTot - i].ptUV, ptSP1) || AreSamePointApprox(vInfo[nNewTot - i].ptUV, ptSP2) ; + if ( bAlreadyFound) { + vInfo.erase( vInfo.begin() + nNewTot - i) ; + break ; + } + } + } + UpdateInfoIntersLineSurfBz( ptL, vtL, ILTT_NO_TRIA, -1, ptSP1, ptIBez1, dCos1, ptSP2, ptIBez2, dCos2, vInfo) ; + bFound = true ; + break ; + } + // se ho trovato un punto a distanza zero dalla linea allora ho trovato l'intersezione + else if( dMinDist < EPS_SMALL) { + if( i == 0) { + //dV1 = 0 ; + vCrvEdge[0]->GetParamAtPoint( ptInt1, dU1) ; + } + else if( i == 1) { + //dU1 = 1 ; + vCrvEdge[1]->GetParamAtPoint( ptInt1, dV1) ; + } + else if( i == 2){ + //dV1 = 1 ; + vCrvEdge[2]->GetParamAtPoint( ptInt1, dU1) ; + } + else if( i == 3){ + //dU1 = 0 ; + vCrvEdge[3]->GetParamAtPoint( ptInt1, dV1) ; + } + Point3d ptSP1( dU1, dV1, 0), ptSP2 ; + // se avevo trovato già altri punti controllo di non essere esattamente su una diagonale ( e quindi avere un'intersezione con ogni edge, ma due sono doppie) + if( bFound) { + int nNewTot = int(vInfo.size()) ; + int nNewInters = nNewTot - nInters ; + bool bAlreadyFound = false ; + for( int i = 0 ; i < nNewInters ; ++i) + bAlreadyFound = AreSamePointApprox(vInfo[nNewTot - i].ptUV, ptSP1) ; + if( bAlreadyFound) + continue ; + } + + Point3d ptIBez1, ptIBez2 ; + Vector3d vtN1, vtN2 ; + pSurfBz->GetPointNrmD1D2(dU1, dV1, ISurfBezier::Side::FROM_MINUS, ISurfBezier::Side::FROM_MINUS, ptIBez1, vtN1) ; + double dCos1 = vtN1 * vtL, dCos2 = 0 ; + UpdateInfoIntersLineSurfBz( ptL, vtL, ILTT_NO_TRIA, -1, ptSP1, ptIBez1, dCos1, ptSP2, ptIBez2, dCos2, vInfo) ; + bFound = true ; + } + } + } + + // se la superficie è trimmed verifico che i punti trovati siano all'interno del parametrico trimmato + if( bTrimmed && bFound) { + int nNewTot = int(vInfo.size()) ; + int nNewInters = nNewTot - nInters ; + const ISurfFlatRegion* pFRTrim = pSurfBz->GetTrimRegion() ; + for( int i = 0 ; i < nNewInters ; ++i) { + Point3d ptTest = vInfo[nNewTot - i].ptUV * SBZ_TREG_COEFF ; + bool bInside = false ; + double dDist = INFINITO ; + IsPointInsideSurfFr( ptTest, pFRTrim, dDist, bInside) ; + if( ! bInside) + vInfo.erase( vInfo.begin() + nNewTot - i) ; + } + } + + return true ; +}