EgtGeomkernel :

- aggiunta intersezione linea - superficie bezier bilineare.
This commit is contained in:
Daniele Bariletti
2025-09-04 12:43:50 +02:00
parent c550fb1848
commit 4c693ccd60
+258 -1
View File
@@ -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 ;
}