6942f5fc23
- nella proiezione di curve su superfici aggiunto paramtetro bFromVsTo.
1104 lines
42 KiB
C++
1104 lines
42 KiB
C++
//----------------------------------------------------------------------------
|
|
// EgalTech 2023-2026
|
|
//----------------------------------------------------------------------------
|
|
// File : ProjectCurveSurfTm.cpp Data : 03.01.26 Versione : 3.1a1
|
|
// Contenuto : Implementazione funzioni proiezione curve su superficie Trimesh.
|
|
//
|
|
//
|
|
//
|
|
// Modifiche : 31.08.23 DS Creazione modulo.
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
//--------------------------- Include ----------------------------------------
|
|
#include "stdafx.h"
|
|
#include "SurfTriMesh.h"
|
|
#include "SurfBezier.h"
|
|
#include "GeoConst.h"
|
|
#include "/EgtDev/Include/EGkDistPointLine.h"
|
|
#include "/EgtDev/Include/EGkDistPointCurve.h"
|
|
#include "/EgtDev/Include/EGkDistPointSurfTm.h"
|
|
#include "/EgtDev/Include/EGkDistPointSurfBz.h"
|
|
#include "/EgtDev/Include/EGkIntersPlanePlane.h"
|
|
#include "/EgtDev/Include/EGkIntersLinePlane.h"
|
|
#include "/EgtDev/Include/EGkIntersLineSurfTm.h"
|
|
#include "/EgtDev/Include/EGkProjectCurveSurf.h"
|
|
|
|
using namespace std ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Angolo limite tra normale al triangolo e direzione di proiezione 89°
|
|
const double COS_ANG_LIM = 0.0175 ;
|
|
// Angolo massimo tra normali per effettuare bisezione su spigolo
|
|
const double COS_ANG_MAX_CORNER = 0.8660 ;
|
|
// Tipologia di punto
|
|
const int P5AX_TO_DELETE = -1 ; // da cancellare
|
|
const int P5AX_OUT = 0 ; // aggiunto prima di inizio o dopo fine
|
|
const int P5AX_STD = 1 ; // standard
|
|
const int P5AX_CVEX = 2 ; // su angolo convesso
|
|
const int P5AX_CONC = 3 ; // in angolo concavo
|
|
const int P5AX_BEFORE_CONC = 4 ; // adiacente ad angolo concavo
|
|
const int P5AX_AFTER_CONC = 5 ; // adiacente ad angolo concavo
|
|
|
|
//----------------------------------------------------------------------------
|
|
static double
|
|
GetSurfBezierTol( double dLinTol)
|
|
{
|
|
return max( dLinTol / 10, EPS_SMALL) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
static bool
|
|
PointsInTolerance( const PNT5AXVECTOR& vPt5ax, int nPrec, int nCurr, int nNext, double dSqTol)
|
|
{
|
|
for ( int i = nPrec + 1 ; i < nCurr ; ++ i) {
|
|
double dSqDist ;
|
|
if ( ! DistPointLine( vPt5ax[i].ptP, vPt5ax[nPrec].ptP, vPt5ax[nNext].ptP).GetSqDist( dSqDist) || dSqDist > dSqTol)
|
|
return false ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
static bool
|
|
AddPointsOnCorners( PNT5AXVECTOR& vPt5ax)
|
|
{
|
|
for ( int i = 1 ; i < ssize( vPt5ax) ; ++ i) {
|
|
// precedente
|
|
int j = i - 1 ;
|
|
// se normali tra corrente e precedente oltre limite e punti abbastanza lontani
|
|
if ( vPt5ax[i].vtDir1 * vPt5ax[j].vtDir1 < COS_ANG_MAX_CORNER &&
|
|
SqDist( vPt5ax[i].ptP, vPt5ax[j].ptP) > 25 * SQ_EPS_SMALL) {
|
|
// intersezione tra le due facce
|
|
Plane3d plPlane1 ; plPlane1.Set( vPt5ax[j].ptP, vPt5ax[j].vtDir1) ;
|
|
Plane3d plPlane2 ; plPlane2.Set( vPt5ax[i].ptP, vPt5ax[i].vtDir1) ;
|
|
Point3d ptEdge ; Vector3d vtEdge ;
|
|
if ( IntersPlanePlane( plPlane1, plPlane2, ptEdge, vtEdge) == IPPT_YES) {
|
|
Plane3d plPlane3 ; plPlane3.Set(vPt5ax[i].ptP, (vPt5ax[i].ptP - vPt5ax[j].ptP) ^ ( vPt5ax[i].vtDir1 + vPt5ax[j].vtDir1)) ;
|
|
Point3d ptInt ;
|
|
if ( IntersLinePlane( ptEdge, vtEdge, 1, plPlane3, ptInt, false) == ILPT_YES) {
|
|
// verifico se spigolo convesso o concavo
|
|
bool bConvex ;
|
|
if ( ! AreSamePointApprox( ptInt, vPt5ax[j].ptP))
|
|
bConvex = ( ( vPt5ax[j].vtDir1 ^ ( ptInt - vPt5ax[j].ptP)) * vtEdge > 0) ;
|
|
else
|
|
bConvex = (( vPt5ax[i].vtDir1 ^ ( ptInt - vPt5ax[i].ptP)) * vtEdge < 0) ;
|
|
// se convesso, metto due punti con direzione appena prima e appena dopo
|
|
if ( bConvex) {
|
|
Vector3d vtLine1 = ptInt - vPt5ax[j].ptP ; double dLen1 = vtLine1.Len() ;
|
|
Vector3d vtLine2 = vPt5ax[i].ptP - ptInt ; double dLen2 = vtLine2.Len() ;
|
|
if ( dLen1 > 2 * EPS_SMALL) {
|
|
Point5ax Pt5ax ;
|
|
Pt5ax.ptP = ptInt - vtLine1 / dLen1 * 2 * EPS_SMALL ;
|
|
Pt5ax.vtDir1 = vPt5ax[j].vtDir1 ;
|
|
Pt5ax.vtDir2 = vPt5ax[j].vtDir2 ;
|
|
Pt5ax.vtDirU = vPt5ax[j].vtDirU ;
|
|
Pt5ax.vtDirV = vPt5ax[j].vtDirV ;
|
|
Pt5ax.dPar = ( vPt5ax[i].dPar + vPt5ax[j].dPar) / 2 ;
|
|
Pt5ax.nFlag = P5AX_CVEX ;
|
|
vPt5ax.insert( vPt5ax.begin() + i, Pt5ax) ;
|
|
++ i ;
|
|
}
|
|
else
|
|
vPt5ax[j].nFlag = P5AX_CVEX ;
|
|
if ( dLen2 > 2 * EPS_SMALL) {
|
|
Point5ax Pt5ax ;
|
|
Pt5ax.ptP = ptInt + vtLine2 / dLen2 * 2 * EPS_SMALL ;
|
|
Pt5ax.vtDir1 = vPt5ax[i].vtDir1 ;
|
|
Pt5ax.vtDir2 = vPt5ax[i].vtDir2 ;
|
|
Pt5ax.vtDirU = vPt5ax[i].vtDirU ;
|
|
Pt5ax.vtDirV = vPt5ax[i].vtDirV ;
|
|
Pt5ax.dPar = ( vPt5ax[i].dPar + vPt5ax[j].dPar) / 2 ;
|
|
Pt5ax.nFlag = P5AX_CVEX ;
|
|
vPt5ax.insert( vPt5ax.begin() + i, Pt5ax) ;
|
|
++ i ;
|
|
}
|
|
else
|
|
vPt5ax[i].nFlag = P5AX_CVEX ;
|
|
}
|
|
// altrimenti concavo, aggiungo un solo punto con la direzione media
|
|
else {
|
|
Point5ax Pt5ax ;
|
|
Pt5ax.ptP = ptInt ;
|
|
Pt5ax.vtDir1 = Media( vPt5ax[i].vtDir1, vPt5ax[j].vtDir1) ; Pt5ax.vtDir1.Normalize() ;
|
|
Pt5ax.vtDir2 = Media( vPt5ax[i].vtDir2, vPt5ax[j].vtDir2) ; Pt5ax.vtDir2.Normalize() ;
|
|
Pt5ax.vtDirU = Media( vPt5ax[i].vtDirU, vPt5ax[j].vtDirU) ; Pt5ax.vtDirU.Normalize() ;
|
|
Pt5ax.vtDirV = Media( vPt5ax[i].vtDirV, vPt5ax[j].vtDirV) ; Pt5ax.vtDirV.Normalize() ;
|
|
Pt5ax.dPar = ( vPt5ax[i].dPar + vPt5ax[j].dPar) / 2 ;
|
|
Pt5ax.nFlag = P5AX_CONC ;
|
|
vPt5ax.insert( vPt5ax.begin() + i, Pt5ax) ;
|
|
++ i ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
static bool
|
|
RemovePointsInExcess( PNT5AXVECTOR& vPt5ax, double dLinTol, double dMaxSegmLen, bool bTestDir)
|
|
{
|
|
// Parametri di riferimento
|
|
double dSqMaxLen = dMaxSegmLen * dMaxSegmLen ;
|
|
double dSqTol = dLinTol * dLinTol ;
|
|
const double LENREF = 200 ;
|
|
double dCosAngLim = 1 - dSqTol / ( 2 * LENREF * LENREF) ;
|
|
// Cerco gli angoli interni e marco opportunamente i punti nelle vicinanze fino ai limiti prima e dopo
|
|
int nInd = 0 ;
|
|
while ( nInd < ssize( vPt5ax)) {
|
|
if ( vPt5ax[nInd].nFlag == P5AX_CONC) {
|
|
// analizzo i punti appena precedenti
|
|
int nIpv = nInd - 1 ;
|
|
while ( nIpv >= 0) {
|
|
double dSqLen = SqDist( vPt5ax[nInd].ptP, vPt5ax[nIpv].ptP) ;
|
|
if ( dSqLen < dSqMaxLen)
|
|
vPt5ax[nIpv].nFlag = P5AX_TO_DELETE ;
|
|
else {
|
|
vPt5ax[nIpv].nFlag = P5AX_BEFORE_CONC ;
|
|
break ;
|
|
}
|
|
-- nIpv ;
|
|
}
|
|
// analizzo i punti appena successivi
|
|
int nInx = nInd + 1 ;
|
|
while ( nInx < ssize( vPt5ax)) {
|
|
double dSqLen = SqDist( vPt5ax[nInd].ptP, vPt5ax[nInx].ptP) ;
|
|
if ( dSqLen < dSqMaxLen)
|
|
vPt5ax[nInx].nFlag = P5AX_TO_DELETE ;
|
|
else {
|
|
vPt5ax[nInx].nFlag = P5AX_AFTER_CONC ;
|
|
break ;
|
|
}
|
|
++ nInx ;
|
|
}
|
|
}
|
|
++ nInd ;
|
|
}
|
|
// Rimuovo i punti allineati entro la tolleranza e non più lontani tra loro del massimo
|
|
int nCnt = 0 ;
|
|
int nPrec = 0 ;
|
|
int nCurr = 1 ;
|
|
int nNext = 2 ;
|
|
while ( nNext < ssize( vPt5ax)) {
|
|
bool bRemove = false ;
|
|
// lunghezza del segmento che unisce gli adiacenti
|
|
double dSqLen = SqDist( vPt5ax[nPrec].ptP, vPt5ax[nNext].ptP) ;
|
|
// se rimovibile (Flag standard) e lunghezza inferiore al massimo, passo agli altri controlli
|
|
if ( vPt5ax[nCurr].nFlag == P5AX_STD && dSqLen <= dSqMaxLen) {
|
|
// distanza del punto corrente dal segmento che unisce gli adiacenti
|
|
DistPointLine dPL( vPt5ax[nCurr].ptP, vPt5ax[nPrec].ptP, vPt5ax[nNext].ptP) ;
|
|
double dSqDist ;
|
|
// se distanza inferiore a tolleranza lineare
|
|
if ( dPL.GetSqDist( dSqDist) && dSqDist < dSqTol && PointsInTolerance( vPt5ax, nPrec, nCurr, nNext, dSqTol)) {
|
|
// verifico se errore angolare inferiore a limite
|
|
double dPar ; dPL.GetParamAtMinDistPoint( dPar) ;
|
|
if ( bTestDir) {
|
|
Vector3d vtNew = Media( vPt5ax[nPrec].vtDir1, vPt5ax[nNext].vtDir1, dPar) ;
|
|
if ( vtNew.Normalize() && vtNew * vPt5ax[nCurr].vtDir1 > dCosAngLim)
|
|
bRemove = true ;
|
|
}
|
|
else {
|
|
Vector3d vtNew = Media( vPt5ax[nPrec].vtDir2, vPt5ax[nNext].vtDir2, dPar) ;
|
|
if ( vtNew.Normalize() && vtNew * vPt5ax[nCurr].vtDir2 > dCosAngLim)
|
|
bRemove = true ;
|
|
}
|
|
}
|
|
}
|
|
// se da eliminare
|
|
if ( bRemove) {
|
|
// dichiaro da eliminare il punto
|
|
vPt5ax[nCurr].nFlag = P5AX_TO_DELETE ;
|
|
// avanzo con corrente e successivo
|
|
nCurr = nNext ;
|
|
++ nNext ;
|
|
}
|
|
// altrimenti da tenere
|
|
else {
|
|
// avanzo il terzetto di uno step
|
|
nPrec = nCurr ;
|
|
nCurr = nNext ;
|
|
++ nNext ;
|
|
// incremento contatore dei punti conservati
|
|
++ nCnt ;
|
|
}
|
|
}
|
|
|
|
// Copio i punti da conservare in un vettore temporaneo
|
|
PNT5AXVECTOR vMyPt5ax ;
|
|
vMyPt5ax.reserve( nCnt) ;
|
|
for ( const auto& Pt5ax : vPt5ax) {
|
|
if ( Pt5ax.nFlag != P5AX_TO_DELETE)
|
|
vMyPt5ax.emplace_back( Pt5ax) ;
|
|
}
|
|
// scambio i due vettori
|
|
vPt5ax.swap( vMyPt5ax) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
static const SurfTriMesh*
|
|
MyGetAuxSurf( const ISurf* pSrf)
|
|
{
|
|
if ( pSrf == nullptr)
|
|
return nullptr ;
|
|
switch ( pSrf->GetType()) {
|
|
case SRF_TRIMESH :
|
|
return GetBasicSurfTriMesh( pSrf) ;
|
|
case SRF_FLATRGN :
|
|
return GetBasicSurfFlatRegion( pSrf)->GetAuxSurf() ;
|
|
case SRF_BEZIER :
|
|
return GetBasicSurfBezier( pSrf)->GetAuxSurf() ;
|
|
default :
|
|
return nullptr ;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
static bool
|
|
ProjectPointOnSurf( const Point3d& ptP, const CISURFPVECTOR& vpSurf, double dPar, Point5ax& Pt5ax)
|
|
{
|
|
// punto sulle superfici a minima distanza
|
|
int nSurfMin = -1 ;
|
|
int nTriaMin = -1 ;
|
|
double dUMin = -1, dVMin = -1 ;
|
|
Point3d ptMin ;
|
|
double dMinDist = NAN ;
|
|
for ( int i = 0 ; i < ssize( vpSurf) ; ++ i) {
|
|
// punto sulla superficie a minima distanza
|
|
int nSrfType = ( vpSurf[i] != nullptr ? vpSurf[i]->GetType() : GEO_NONE) ;
|
|
if ( nSrfType == SRF_TRIMESH || nSrfType == SRF_FLATRGN) {
|
|
DistPointSurfTm dPS( ptP, *MyGetAuxSurf( vpSurf[i])) ;
|
|
double dDist ;
|
|
if ( dPS.GetDist( dDist) && ( nSurfMin == -1 || dDist < dMinDist)) {
|
|
nSurfMin = i ;
|
|
dPS.GetMinDistPoint( ptMin) ;
|
|
dPS.GetMinDistTriaIndex ( nTriaMin) ;
|
|
dMinDist = dDist ;
|
|
}
|
|
}
|
|
else if ( nSrfType == SRF_BEZIER) {
|
|
DistPointSurfBz dPS( ptP, *GetBasicSurfBezier( vpSurf[i])) ;
|
|
double dDist ;
|
|
if ( dPS.GetDist( dDist) && ( nSurfMin == -1 || dDist < dMinDist)) {
|
|
nSurfMin = i ;
|
|
dPS.GetMinDistPoint( ptMin) ;
|
|
dPS.GetParamsAtMinDistPoint( dUMin, dVMin) ;
|
|
dMinDist = dDist ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// se trovato
|
|
if ( nSurfMin >= 0) {
|
|
// assegno il punto
|
|
Point3d ptInt = ptMin ;
|
|
// calcolo gli altri dati
|
|
int nSrfType = ( vpSurf[nSurfMin] != nullptr ? vpSurf[nSurfMin]->GetType() : GEO_NONE) ;
|
|
if ( nSrfType == SRF_TRIMESH || nSrfType == SRF_FLATRGN) {
|
|
// recupero superficie trimesh
|
|
const SurfTriMesh* pSurfTm = MyGetAuxSurf( vpSurf[nSurfMin]) ;
|
|
// calcolo la normale (si calcola smooth, in caso di errore si prende quella del triangolo)
|
|
Triangle3dEx trTria ;
|
|
if ( ! pSurfTm->GetTriangle( nTriaMin, trTria))
|
|
return false ;
|
|
Vector3d vtN ;
|
|
if ( ! CalcNormal( ptMin, trTria, vtN))
|
|
vtN = trTria.GetN() ;
|
|
// assegno valori al punto 5assi
|
|
Pt5ax.ptP = ptInt ;
|
|
Pt5ax.vtDir1 = vtN ;
|
|
Pt5ax.vtDir2 = vtN ;
|
|
Pt5ax.vtDirU = V_NULL ;
|
|
Pt5ax.vtDirV = V_NULL ;
|
|
Pt5ax.dPar = dPar ;
|
|
Pt5ax.nFlag = P5AX_STD ;
|
|
}
|
|
else if ( nSrfType == SRF_BEZIER) {
|
|
Point3d ptSB ;
|
|
Vector3d vtN, vtDerU, vtDerV ;
|
|
if ( ! GetBasicSurfBezier( vpSurf[nSurfMin])->GetPointNrmD1D2( dUMin, dVMin, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS,
|
|
ptSB, vtN, &vtDerU, &vtDerV))
|
|
return false ;
|
|
vtDerU.Normalize() ;
|
|
vtDerV.Normalize() ;
|
|
// assegno valori al punto 5assi
|
|
Pt5ax.ptP = ptInt ;
|
|
Pt5ax.vtDir1 = vtN ;
|
|
Pt5ax.vtDir2 = vtN ;
|
|
Pt5ax.vtDirU = vtDerU ;
|
|
Pt5ax.vtDirV = vtDerV ;
|
|
Pt5ax.dPar = dPar ;
|
|
Pt5ax.nFlag = P5AX_STD ;
|
|
}
|
|
// ritorno con successo
|
|
return true ;
|
|
}
|
|
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf,
|
|
double dLinTol, double dMaxSegmLen, bool bSharpEdges, PNT5AXVECTOR& vPt5ax)
|
|
{
|
|
// controllo le tolleranze
|
|
dLinTol = max( dLinTol, LIN_TOL_MIN) ;
|
|
dMaxSegmLen = max( dMaxSegmLen, 10 * EPS_SMALL) ;
|
|
|
|
// approssimo la curva con una polilinea entro la tolleranza
|
|
PolyLine PL ;
|
|
if ( ! crCrv.ApproxWithLines( 10 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL) ||
|
|
! PL.RemoveAlignedPoints( dLinTol, false) )
|
|
return false ;
|
|
const double MAX_SEG_LEN = min( dMaxSegmLen, 0.977) ;
|
|
if ( ! PL.AdjustForMaxSegmentLen( MAX_SEG_LEN))
|
|
return false ;
|
|
|
|
// Pulisco e riservo spazio nel vettore dei punti risultanti
|
|
vPt5ax.clear() ;
|
|
vPt5ax.reserve( PL.GetPointNbr()) ;
|
|
|
|
// proietto i punti della polilinea sulla superficie secondo la direzione di minima distanza
|
|
double dPar ;
|
|
Point3d ptP ;
|
|
bool bFound = PL.GetFirstUPoint( &dPar, &ptP) ;
|
|
while ( bFound) {
|
|
// se trovo proiezione, la salvo
|
|
Point5ax Pt5ax ;
|
|
if ( ProjectPointOnSurf( ptP, vpSurf, dPar, Pt5ax))
|
|
vPt5ax.emplace_back( Pt5ax) ;
|
|
// passo al successivo
|
|
bFound = PL.GetNextUPoint( &dPar, &ptP) ;
|
|
}
|
|
|
|
// se richiesto, inserimento punti intermedi in presenza di spigoli
|
|
if ( bSharpEdges)
|
|
AddPointsOnCorners( vPt5ax) ;
|
|
|
|
// rimozione punti in eccesso rispetto alle tolleranze
|
|
RemovePointsInExcess( vPt5ax, dLinTol, dMaxSegmLen, bSharpEdges) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// --- vettore di oggetti intersezione massiva rette parallele SurfTM --------
|
|
typedef std::vector<IntersParLinesSurfTm*> INTPARLINESTMPVECTOR ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
static bool
|
|
ProjectPointOnSurf( const Point3d& ptP, const CISRFTMPVECTOR& vpStm, const Frame3d& frRefLine, const INTPARLINESTMPVECTOR& vpIntPLSTM,
|
|
double dPar, bool bFromVsTo, Point5ax& Pt5ax)
|
|
{
|
|
// intersezione retta di proiezione con superfici (conservo l'intersezione più alta)
|
|
Point3d ptL = GetToLoc( ptP, frRefLine) ;
|
|
int nInd = -1 ;
|
|
IntLinStmInfo IntRes ;
|
|
for ( int i = 0 ; i < ssize( vpIntPLSTM) ; ++ i) {
|
|
ILSIVECTOR vIntRes ;
|
|
if ( vpIntPLSTM[i]->GetInters( ptL, 1, vIntRes, false)) {
|
|
// se dalla direzione
|
|
if ( bFromVsTo) {
|
|
// cerco la prima intersezione valida a partire dall'ultima (è la più alta)
|
|
int nI = ssize( vIntRes) - 1 ;
|
|
while ( nI >= 0 && abs( vIntRes[nI].dCosDN) < COS_ANG_LIM)
|
|
--nI ;
|
|
// se trovata
|
|
if ( nI >= 0) {
|
|
if ( nInd < 0) {
|
|
IntRes = vIntRes[nI] ;
|
|
nInd = i ;
|
|
}
|
|
else {
|
|
double dUref = (( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE) ? IntRes.dU2 : IntRes.dU) ;
|
|
double dU = (( vIntRes[nI].nILTT == ILTT_SEGM || vIntRes[nI].nILTT == ILTT_SEGM_ON_EDGE) ? vIntRes[nI].dU2 : vIntRes[nI].dU) ;
|
|
if ( dU > dUref) {
|
|
IntRes = vIntRes[nI] ;
|
|
nInd = i ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// altrimenti verso la direzione
|
|
else {
|
|
// cerco la prima intersezione valida a partire dalla prima (è la più alta)
|
|
int nI = 0 ;
|
|
while ( nI < ssize( vIntRes) && abs( vIntRes[nI].dCosDN) < COS_ANG_LIM)
|
|
++nI ;
|
|
// se trovata
|
|
if ( nI < ssize( vIntRes)) {
|
|
if ( nInd < 0) {
|
|
IntRes = vIntRes[nI] ;
|
|
nInd = i ;
|
|
}
|
|
else {
|
|
double dUref = (( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE) ? IntRes.dU : IntRes.dU2) ;
|
|
double dU = (( vIntRes[nI].nILTT == ILTT_SEGM || vIntRes[nI].nILTT == ILTT_SEGM_ON_EDGE) ? vIntRes[nI].dU : vIntRes[nI].dU2) ;
|
|
if ( dU < dUref) {
|
|
IntRes = vIntRes[nI] ;
|
|
nInd = i ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// se trovata
|
|
if ( nInd >= 0) {
|
|
// calcolo il punto
|
|
Point3d ptInt ;
|
|
if ( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE)
|
|
ptInt = IntRes.ptI2 ;
|
|
else
|
|
ptInt = IntRes.ptI ;
|
|
// calcolo la normale (si calcola smooth, in caso di errore si prende quella del triangolo)
|
|
Triangle3dEx trTria ;
|
|
if ( ! vpStm[nInd]->GetTriangle( IntRes.nT, trTria))
|
|
return false ;
|
|
Vector3d vtN ;
|
|
if ( ! CalcNormal( ptInt, trTria, vtN))
|
|
vtN = trTria.GetN() ;
|
|
// assegno valori al punto 5assi
|
|
Pt5ax.ptP = ptInt ;
|
|
Pt5ax.vtDir1 = vtN ;
|
|
Pt5ax.vtDir2 = frRefLine.VersZ() ;
|
|
Pt5ax.vtDirU = V_NULL ;
|
|
Pt5ax.vtDirV = V_NULL ;
|
|
Pt5ax.dPar = dPar ;
|
|
Pt5ax.nFlag = P5AX_STD ;
|
|
// ritorno con successo
|
|
return true ;
|
|
}
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const Vector3d& vtDir,
|
|
double dLinTol, double dMaxSegmLen, bool bSharpEdges, bool bFromVsTo, PNT5AXVECTOR& vPt5ax)
|
|
{
|
|
// sistemazioni per tipo di superficie
|
|
CISRFTMPVECTOR vpSurfTm ;
|
|
for ( int i = 0 ; i < ssize( vpSurf) ; ++ i) {
|
|
const SurfTriMesh* pSurfTm = nullptr ;
|
|
switch ( vpSurf[i]->GetType()) {
|
|
case SRF_TRIMESH :
|
|
pSurfTm = GetBasicSurfTriMesh( vpSurf[i]) ;
|
|
break ;
|
|
case SRF_BEZIER :
|
|
{ double dOldLinTol = GetSurfBezierAuxSurfRefinedTol() ;
|
|
SetSurfBezierAuxSurfRefinedTol( GetSurfBezierTol( dLinTol)) ;
|
|
pSurfTm = GetBasicSurfBezier( vpSurf[i])->GetAuxSurfRefined() ;
|
|
SetSurfBezierAuxSurfRefinedTol( dOldLinTol) ;
|
|
} break ;
|
|
case SRF_FLATRGN :
|
|
pSurfTm = GetBasicSurfFlatRegion( vpSurf[i])->GetAuxSurf() ;
|
|
break ;
|
|
default :
|
|
break ;
|
|
}
|
|
if ( pSurfTm == nullptr)
|
|
return false ;
|
|
vpSurfTm.emplace_back( pSurfTm) ;
|
|
}
|
|
|
|
// controllo le tolleranze
|
|
dLinTol = max( dLinTol, LIN_TOL_MIN) ;
|
|
dMaxSegmLen = max( dMaxSegmLen, 10 * EPS_SMALL) ;
|
|
|
|
// approssimo la curva con una polilinea entro la tolleranza
|
|
PolyLine PL ;
|
|
if ( ! crCrv.ApproxWithLines( 10 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL) ||
|
|
! PL.RemoveAlignedPoints( dLinTol, false) )
|
|
return false ;
|
|
const double MAX_SEG_LEN = min( dMaxSegmLen, 0.977) ;
|
|
if ( ! PL.AdjustForMaxSegmentLen( MAX_SEG_LEN))
|
|
return false ;
|
|
|
|
// Oggetti per calcolo massivo intersezioni tra linee di proiezione e superfici
|
|
Frame3d frRefLine ;
|
|
if ( ! frRefLine.Set( ORIG, vtDir))
|
|
return false ;
|
|
INTPARLINESTMPVECTOR vpIntPLSTM ; vpIntPLSTM.reserve( vpSurfTm.size()) ;
|
|
for ( int i = 0 ; i < ssize( vpSurfTm) ; ++ i) {
|
|
IntersParLinesSurfTm* pIntPLSTM = new IntersParLinesSurfTm( frRefLine, *vpSurfTm[i]) ;
|
|
if ( pIntPLSTM == nullptr) {
|
|
for ( int j = 0 ; j < ssize( vpIntPLSTM) ; ++ j)
|
|
delete vpIntPLSTM[j] ;
|
|
return false ;
|
|
}
|
|
vpIntPLSTM.emplace_back( pIntPLSTM) ;
|
|
}
|
|
|
|
// Pulisco e riservo spazio nel vettore dei punti risultanti
|
|
vPt5ax.clear() ;
|
|
vPt5ax.reserve( PL.GetPointNbr()) ;
|
|
|
|
// proietto i punti della polilinea sulla superficie
|
|
double dPar ;
|
|
Point3d ptP ;
|
|
bool bFound = PL.GetFirstUPoint( &dPar, &ptP) ;
|
|
while ( bFound) {
|
|
// se trovo proiezione, la salvo
|
|
Point5ax Pt5ax ;
|
|
if ( ProjectPointOnSurf( ptP, vpSurfTm, frRefLine, vpIntPLSTM, dPar, bFromVsTo, Pt5ax))
|
|
vPt5ax.emplace_back( Pt5ax) ;
|
|
// passo al successivo
|
|
bFound = PL.GetNextUPoint( &dPar, &ptP) ;
|
|
}
|
|
|
|
// Libero oggetti per calcolo massivo
|
|
for ( int i = 0 ; i < ssize( vpIntPLSTM) ; ++ i)
|
|
delete vpIntPLSTM[i] ;
|
|
|
|
// se richiesto, inserimento punti intermedi in presenza di spigoli
|
|
if ( bSharpEdges)
|
|
AddPointsOnCorners( vPt5ax) ;
|
|
|
|
// rimozione punti in eccesso rispetto alle tolleranze
|
|
RemovePointsInExcess( vPt5ax, dLinTol, dMaxSegmLen, bSharpEdges) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
static bool
|
|
ProjectPointOnSurf( const Point3d& ptP, const CISRFTMPVECTOR& vpStm, const IGeoPoint3d& gpRef, double dPar, bool bFromVsTo,
|
|
Point5ax& Pt5ax)
|
|
{
|
|
// punto di riferimento
|
|
Point3d ptMin = gpRef.GetPoint() ;
|
|
// intersezione della retta di minima distanza con le superfici
|
|
Vector3d vtLine = ptP - ptMin ;
|
|
double dLineLen = vtLine.Len() ;
|
|
if ( dLineLen > EPS_SMALL) {
|
|
vtLine /= dLineLen ;
|
|
// conservo l'intersezione più alta
|
|
int nInd = -1 ;
|
|
IntLinStmInfo IntRes ;
|
|
for ( int i = 0 ; i < ssize( vpStm) ; ++ i) {
|
|
ILSIVECTOR vIntRes ;
|
|
if ( IntersLineSurfTm( ptP, vtLine, dLineLen, *vpStm[i], vIntRes, false)) {
|
|
// se dal punto
|
|
if ( bFromVsTo) {
|
|
// cerco la prima intersezione valida a partire dall'ultima (è la più alta)
|
|
int nI = ssize( vIntRes) - 1 ;
|
|
while ( nI >= 0 && abs( vIntRes[nI].dCosDN) < COS_ANG_LIM)
|
|
--nI ;
|
|
// se trovata
|
|
if ( nI >= 0) {
|
|
if ( nInd < 0) {
|
|
IntRes = vIntRes[nI] ;
|
|
nInd = i ;
|
|
}
|
|
else {
|
|
double dUref = (( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE) ? IntRes.dU2 : IntRes.dU) ;
|
|
double dU = (( vIntRes[nI].nILTT == ILTT_SEGM || vIntRes[nI].nILTT == ILTT_SEGM_ON_EDGE) ? vIntRes[nI].dU2 : vIntRes[nI].dU) ;
|
|
if ( dU > dUref) {
|
|
IntRes = vIntRes[nI] ;
|
|
nInd = i ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// altrimenti verso il punto
|
|
else {
|
|
// cerco la prima intersezione valida a partire dalla prima (è la più alta)
|
|
int nI = 0 ;
|
|
while ( nI < ssize( vIntRes) && abs( vIntRes[nI].dCosDN) < COS_ANG_LIM)
|
|
++nI ;
|
|
// se trovata
|
|
if ( nI < ssize( vIntRes)) {
|
|
if ( nInd < 0) {
|
|
IntRes = vIntRes[nI] ;
|
|
nInd = i ;
|
|
}
|
|
else {
|
|
double dUref = (( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE) ? IntRes.dU : IntRes.dU2) ;
|
|
double dU = (( vIntRes[nI].nILTT == ILTT_SEGM || vIntRes[nI].nILTT == ILTT_SEGM_ON_EDGE) ? vIntRes[nI].dU : vIntRes[nI].dU2) ;
|
|
if ( dU < dUref) {
|
|
IntRes = vIntRes[nI] ;
|
|
nInd = i ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// se trovata
|
|
if ( nInd >= 0) {
|
|
// calcolo il punto
|
|
Point3d ptInt ;
|
|
if ( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE)
|
|
ptInt = IntRes.ptI2 ;
|
|
else
|
|
ptInt = IntRes.ptI ;
|
|
// calcolo la normale (si calcola smooth, in caso di errore si prende quella del triangolo)
|
|
Triangle3dEx trTria ;
|
|
if ( ! vpStm[nInd]->GetTriangle( IntRes.nT, trTria))
|
|
return false ;
|
|
Vector3d vtN ;
|
|
if ( ! CalcNormal( ptInt, trTria, vtN))
|
|
vtN = trTria.GetN() ;
|
|
// assegno valori al punto 5assi
|
|
Pt5ax.ptP = ptInt ;
|
|
Pt5ax.vtDir1 = vtN ;
|
|
Pt5ax.vtDir2 = vtLine ;
|
|
Pt5ax.vtDirU = V_NULL ;
|
|
Pt5ax.vtDirV = V_NULL ;
|
|
Pt5ax.dPar = dPar ;
|
|
Pt5ax.nFlag = P5AX_STD ;
|
|
// ritorno con successo
|
|
return true ;
|
|
}
|
|
}
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const IGeoPoint3d& gpRef,
|
|
double dLinTol, double dMaxSegmLen, bool bSharpEdges, bool bFromVsTo, PNT5AXVECTOR& vPt5ax)
|
|
{
|
|
// sistemazioni per tipo di superficie
|
|
CISRFTMPVECTOR vpSurfTm ;
|
|
for ( int i = 0 ; i < ssize( vpSurf) ; ++ i) {
|
|
const SurfTriMesh* pSurfTm = nullptr ;
|
|
switch ( vpSurf[i]->GetType()) {
|
|
case SRF_TRIMESH :
|
|
pSurfTm = GetBasicSurfTriMesh( vpSurf[i]) ;
|
|
break ;
|
|
case SRF_BEZIER :
|
|
{ double dOldLinTol = GetSurfBezierAuxSurfRefinedTol() ;
|
|
SetSurfBezierAuxSurfRefinedTol( GetSurfBezierTol( dLinTol)) ;
|
|
pSurfTm = GetBasicSurfBezier( vpSurf[i])->GetAuxSurfRefined() ;
|
|
SetSurfBezierAuxSurfRefinedTol( dOldLinTol) ;
|
|
} break ;
|
|
case SRF_FLATRGN :
|
|
pSurfTm = GetBasicSurfFlatRegion( vpSurf[i])->GetAuxSurf() ;
|
|
break ;
|
|
default :
|
|
break ;
|
|
}
|
|
if ( pSurfTm == nullptr)
|
|
return false ;
|
|
vpSurfTm.emplace_back( pSurfTm) ;
|
|
}
|
|
|
|
// controllo le tolleranze
|
|
dLinTol = max( dLinTol, LIN_TOL_MIN) ;
|
|
dMaxSegmLen = max( dMaxSegmLen, 10 * EPS_SMALL) ;
|
|
|
|
// approssimo la curva con una polilinea entro la tolleranza
|
|
PolyLine PL ;
|
|
if ( ! crCrv.ApproxWithLines( 10 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL) ||
|
|
! PL.RemoveAlignedPoints( dLinTol, false) )
|
|
return false ;
|
|
const double MAX_SEG_LEN = min( dMaxSegmLen, 0.977) ;
|
|
if ( ! PL.AdjustForMaxSegmentLen( MAX_SEG_LEN))
|
|
return false ;
|
|
|
|
// Pulisco e riservo spazio nel vettore dei punti risultanti
|
|
vPt5ax.clear() ;
|
|
vPt5ax.reserve( PL.GetPointNbr()) ;
|
|
|
|
// proietto i punti della polilinea sulla superficie con direzione data dal punto di riferimento
|
|
double dPar ;
|
|
Point3d ptP ;
|
|
bool bFound = PL.GetFirstUPoint( &dPar, &ptP) ;
|
|
while ( bFound) {
|
|
// se trovo proiezione, la salvo
|
|
Point5ax Pt5ax ;
|
|
if ( ProjectPointOnSurf( ptP, vpSurfTm, gpRef, dPar, bFromVsTo, Pt5ax))
|
|
vPt5ax.emplace_back( Pt5ax) ;
|
|
// passo al successivo
|
|
bFound = PL.GetNextUPoint( &dPar, &ptP) ;
|
|
}
|
|
|
|
// se richiesto, inserimento punti intermedi in presenza di spigoli
|
|
if ( bSharpEdges)
|
|
AddPointsOnCorners( vPt5ax) ;
|
|
|
|
// rimozione punti in eccesso rispetto alle tolleranze
|
|
RemovePointsInExcess( vPt5ax, dLinTol, dMaxSegmLen, bSharpEdges) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
static bool
|
|
ProjectPointOnSurf( const Point3d& ptP, const CISRFTMPVECTOR& vpStm, const ICurve& crRef, double dPar, bool bFromVsTo,
|
|
Point5ax& Pt5ax)
|
|
{
|
|
// punto a minima distanza
|
|
DistPointCurve dPC( ptP, crRef) ;
|
|
Point3d ptMin ;
|
|
int nFlag ;
|
|
if ( dPC.GetMinDistPoint( 0, ptMin, nFlag)) {
|
|
// intersezione della retta di minima distanza con le superfici
|
|
Vector3d vtLine = ptP - ptMin ;
|
|
double dLineLen = vtLine.Len() ;
|
|
if ( dLineLen > EPS_SMALL) {
|
|
vtLine /= dLineLen ;
|
|
// conservo l'intersezione più alta
|
|
int nInd = -1 ;
|
|
IntLinStmInfo IntRes ;
|
|
for ( int i = 0 ; i < ssize( vpStm) ; ++ i) {
|
|
ILSIVECTOR vIntRes ;
|
|
if ( IntersLineSurfTm( ptP, vtLine, dLineLen, *vpStm[i], vIntRes, false)) {
|
|
// se dalla curva
|
|
if ( bFromVsTo) {
|
|
// cerco la prima intersezione valida a partire dall'ultima (è la più alta)
|
|
int nI = ssize( vIntRes) - 1 ;
|
|
while ( nI >= 0 && abs( vIntRes[nI].dCosDN) < COS_ANG_LIM)
|
|
--nI ;
|
|
// se trovata
|
|
if ( nI >= 0) {
|
|
if ( nInd < 0) {
|
|
IntRes = vIntRes[nI] ;
|
|
nInd = i ;
|
|
}
|
|
else {
|
|
double dUref = (( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE) ? IntRes.dU2 : IntRes.dU) ;
|
|
double dU = (( vIntRes[nI].nILTT == ILTT_SEGM || vIntRes[nI].nILTT == ILTT_SEGM_ON_EDGE) ? vIntRes[nI].dU2 : vIntRes[nI].dU) ;
|
|
if ( dU > dUref) {
|
|
IntRes = vIntRes[nI] ;
|
|
nInd = i ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// altrimenti verso la curva
|
|
else {
|
|
// cerco la prima intersezione valida a partire dalla prima (è la più alta)
|
|
int nI = 0 ;
|
|
while ( nI < ssize( vIntRes) && abs( vIntRes[nI].dCosDN) < COS_ANG_LIM)
|
|
++nI ;
|
|
// se trovata
|
|
if ( nI < ssize( vIntRes)) {
|
|
if ( nInd < 0) {
|
|
IntRes = vIntRes[nI] ;
|
|
nInd = i ;
|
|
}
|
|
else {
|
|
double dUref = (( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE) ? IntRes.dU : IntRes.dU2) ;
|
|
double dU = (( vIntRes[nI].nILTT == ILTT_SEGM || vIntRes[nI].nILTT == ILTT_SEGM_ON_EDGE) ? vIntRes[nI].dU : vIntRes[nI].dU2) ;
|
|
if ( dU < dUref) {
|
|
IntRes = vIntRes[nI] ;
|
|
nInd = i ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// se trovata
|
|
if ( nInd >= 0) {
|
|
// assegno il punto
|
|
Point3d ptInt ;
|
|
if ( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE)
|
|
ptInt = IntRes.ptI2 ;
|
|
else
|
|
ptInt = IntRes.ptI ;
|
|
// calcolo la normale (si calcola smooth, in caso di errore si prende quella del triangolo)
|
|
Triangle3dEx trTria ;
|
|
if ( ! vpStm[nInd]->GetTriangle( IntRes.nT, trTria))
|
|
return false ;
|
|
Vector3d vtN ;
|
|
if ( ! CalcNormal( ptInt, trTria, vtN))
|
|
vtN = trTria.GetN() ;
|
|
// assegno valori al punto 5assi
|
|
Pt5ax.ptP = ptInt ;
|
|
Pt5ax.vtDir1 = vtN ;
|
|
Pt5ax.vtDir2 = ( bFromVsTo ? vtLine : -vtLine) ;
|
|
Pt5ax.vtDirU = V_NULL ;
|
|
Pt5ax.vtDirV = V_NULL ;
|
|
Pt5ax.dPar = dPar ;
|
|
Pt5ax.nFlag = P5AX_STD ;
|
|
// ritorno con successo
|
|
return true ;
|
|
}
|
|
}
|
|
}
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const ICurve& crRef,
|
|
double dLinTol, double dMaxSegmLen, bool bSharpEdges, bool bFromVsTo, PNT5AXVECTOR& vPt5ax)
|
|
{
|
|
// Sistemazioni per tipo di superficie
|
|
CISRFTMPVECTOR vpSurfTm ;
|
|
for ( int i = 0 ; i < ssize( vpSurf) ; ++ i) {
|
|
const SurfTriMesh* pSurfTm = nullptr ;
|
|
switch ( vpSurf[i]->GetType()) {
|
|
case SRF_TRIMESH :
|
|
pSurfTm = GetBasicSurfTriMesh( vpSurf[i]) ;
|
|
break ;
|
|
case SRF_BEZIER :
|
|
{ double dOldLinTol = GetSurfBezierAuxSurfRefinedTol() ;
|
|
SetSurfBezierAuxSurfRefinedTol( GetSurfBezierTol( dLinTol)) ;
|
|
pSurfTm = GetBasicSurfBezier( vpSurf[i])->GetAuxSurfRefined() ;
|
|
SetSurfBezierAuxSurfRefinedTol( dOldLinTol) ;
|
|
} break ;
|
|
case SRF_FLATRGN :
|
|
pSurfTm = GetBasicSurfFlatRegion( vpSurf[i])->GetAuxSurf() ;
|
|
break ;
|
|
default :
|
|
break ;
|
|
}
|
|
if ( pSurfTm == nullptr)
|
|
return false ;
|
|
vpSurfTm.emplace_back( pSurfTm) ;
|
|
}
|
|
|
|
// Controllo le tolleranze
|
|
dLinTol = max( dLinTol, LIN_TOL_MIN) ;
|
|
dMaxSegmLen = max( dMaxSegmLen, 10 * EPS_SMALL) ;
|
|
|
|
// Approssimo la curva con una polilinea entro la tolleranza
|
|
PolyLine PL ;
|
|
if ( ! crCrv.ApproxWithLines( 10 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL) ||
|
|
! PL.RemoveAlignedPoints( dLinTol, false) )
|
|
return false ;
|
|
const double MAX_SEG_LEN = min( dMaxSegmLen, 0.977) ;
|
|
if ( ! PL.AdjustForMaxSegmentLen( MAX_SEG_LEN))
|
|
return false ;
|
|
|
|
// Pulisco e riservo spazio nel vettore dei punti risultanti
|
|
vPt5ax.clear() ;
|
|
vPt5ax.reserve( PL.GetPointNbr()) ;
|
|
|
|
// proietto i punti della polilinea sulla superficie con direzione normale alla curva di riferimento
|
|
double dPar ;
|
|
Point3d ptP ;
|
|
bool bFound = PL.GetFirstUPoint( &dPar, &ptP) ;
|
|
while ( bFound) {
|
|
// se trovo proiezione, la salvo
|
|
Point5ax Pt5ax ;
|
|
if ( ProjectPointOnSurf( ptP, vpSurfTm, crRef, dPar, bFromVsTo, Pt5ax))
|
|
vPt5ax.emplace_back( Pt5ax) ;
|
|
// passo al successivo
|
|
bFound = PL.GetNextUPoint( &dPar, &ptP) ;
|
|
}
|
|
|
|
// se richiesto, inserimento punti intermedi in presenza di spigoli
|
|
if ( bSharpEdges)
|
|
AddPointsOnCorners( vPt5ax) ;
|
|
|
|
// rimozione punti in eccesso rispetto alle tolleranze
|
|
RemovePointsInExcess( vPt5ax, dLinTol, dMaxSegmLen, bSharpEdges) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
static bool
|
|
ProjectPointOnSurf( const Point3d& ptP, const CISRFTMPVECTOR& vpStm, const SurfTriMesh& stmRef, double dPar, bool bFromVsTo,
|
|
Point5ax& Pt5ax)
|
|
{
|
|
// punto sulla superficie guida a minima distanza
|
|
DistPointSurfTm dPS( ptP, stmRef) ;
|
|
Point3d ptMin ;
|
|
int nTriaMin ;
|
|
if ( dPS.GetMinDistPoint( ptMin) && dPS.GetMinDistTriaIndex ( nTriaMin)) {
|
|
// recupero direzione della retta di minima distanza, altrimenti normale alla superficie
|
|
Vector3d vtLine = ptP - ptMin ;
|
|
double dLineLen = vtLine.Len() ;
|
|
if ( dLineLen > EPS_SMALL)
|
|
vtLine /= dLineLen ;
|
|
else {
|
|
// calcolo la normale della superficie guida
|
|
Triangle3dEx trGuide ;
|
|
if ( ! stmRef.GetTriangle( nTriaMin, trGuide))
|
|
return false ;
|
|
if ( ! CalcNormal( ptMin, trGuide, vtLine))
|
|
vtLine = trGuide.GetN() ;
|
|
dLineLen = 100 ;
|
|
}
|
|
// intersezione della retta con le superfici (conservo l'intersezione più alta)
|
|
int nInd = -1 ;
|
|
IntLinStmInfo IntRes ;
|
|
for ( int i = 0 ; i < ssize( vpStm) ; ++ i) {
|
|
ILSIVECTOR vIntRes ;
|
|
if ( IntersLineSurfTm( ptP, vtLine, dLineLen, *vpStm[i], vIntRes, false)) {
|
|
// se dalla superficie
|
|
if ( bFromVsTo) {
|
|
// cerco la prima intersezione valida a partire dall'ultima (è la più alta)
|
|
int nI = ssize( vIntRes) - 1 ;
|
|
while ( nI >= 0 && abs( vIntRes[nI].dCosDN) < COS_ANG_LIM)
|
|
--nI ;
|
|
// se trovata
|
|
if ( nI >= 0) {
|
|
if ( nInd < 0) {
|
|
IntRes = vIntRes[nI] ;
|
|
nInd = i ;
|
|
}
|
|
else {
|
|
double dUref = (( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE) ? IntRes.dU2 : IntRes.dU) ;
|
|
double dU = (( vIntRes[nI].nILTT == ILTT_SEGM || vIntRes[nI].nILTT == ILTT_SEGM_ON_EDGE) ? vIntRes[nI].dU2 : vIntRes[nI].dU) ;
|
|
if ( dU > dUref) {
|
|
IntRes = vIntRes[nI] ;
|
|
nInd = i ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// altrimenti verso la superficie
|
|
else {
|
|
// cerco la prima intersezione valida a partire dalla prima (è la più alta)
|
|
int nI = 0 ;
|
|
while ( nI < ssize( vIntRes) && abs( vIntRes[nI].dCosDN) < COS_ANG_LIM)
|
|
++nI ;
|
|
// se trovata
|
|
if ( nI < ssize( vIntRes)) {
|
|
if ( nInd < 0) {
|
|
IntRes = vIntRes[nI] ;
|
|
nInd = i ;
|
|
}
|
|
else {
|
|
double dUref = (( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE) ? IntRes.dU : IntRes.dU2) ;
|
|
double dU = (( vIntRes[nI].nILTT == ILTT_SEGM || vIntRes[nI].nILTT == ILTT_SEGM_ON_EDGE) ? vIntRes[nI].dU : vIntRes[nI].dU2) ;
|
|
if ( dU < dUref) {
|
|
IntRes = vIntRes[nI] ;
|
|
nInd = i ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// se trovata
|
|
if ( nInd >= 0) {
|
|
// calcolo il punto
|
|
Point3d ptInt ;
|
|
if ( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE)
|
|
ptInt = IntRes.ptI2 ;
|
|
else
|
|
ptInt = IntRes.ptI ;
|
|
// calcolo la normale (si calcola smooth, in caso di errore si prende quella del triangolo)
|
|
Triangle3dEx trTria ;
|
|
if ( ! vpStm[nInd]->GetTriangle( IntRes.nT, trTria))
|
|
return false ;
|
|
Vector3d vtN ;
|
|
if ( ! CalcNormal( ptMin, trTria, vtN))
|
|
vtN = trTria.GetN() ;
|
|
// calcolo la normale della superficie guida
|
|
Triangle3dEx trGuide ;
|
|
if ( ! stmRef.GetTriangle( nTriaMin, trGuide))
|
|
return false ;
|
|
Vector3d vtN2 ;
|
|
if ( ! CalcNormal( ptMin, trGuide, vtN2))
|
|
vtN2 = trGuide.GetN() ;
|
|
// assegno valori al punto 5assi
|
|
Pt5ax.ptP = ptInt ;
|
|
Pt5ax.vtDir1 = vtN ;
|
|
Pt5ax.vtDir2 = vtN2 ;
|
|
Pt5ax.vtDirU = V_NULL ;
|
|
Pt5ax.vtDirV = V_NULL ;
|
|
Pt5ax.dPar = dPar ;
|
|
Pt5ax.nFlag = P5AX_STD ;
|
|
// ritorno con successo
|
|
return true ;
|
|
}
|
|
}
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const ISurf& sfRef,
|
|
double dLinTol, double dMaxSegmLen, bool bSharpEdges, bool bFromVsTo, PNT5AXVECTOR& vPt5ax)
|
|
{
|
|
// sistemazioni per tipo di superficie
|
|
CISRFTMPVECTOR vpSurfTm ;
|
|
for ( int i = 0 ; i < ssize( vpSurf) ; ++ i) {
|
|
const SurfTriMesh* pSurfTm = nullptr ;
|
|
switch ( vpSurf[i]->GetType()) {
|
|
case SRF_TRIMESH :
|
|
pSurfTm = GetBasicSurfTriMesh( vpSurf[i]) ;
|
|
break ;
|
|
case SRF_BEZIER :
|
|
{ double dOldLinTol = GetSurfBezierAuxSurfRefinedTol() ;
|
|
SetSurfBezierAuxSurfRefinedTol( GetSurfBezierTol( dLinTol)) ;
|
|
pSurfTm = GetBasicSurfBezier( vpSurf[i])->GetAuxSurfRefined() ;
|
|
SetSurfBezierAuxSurfRefinedTol( dOldLinTol) ;
|
|
} break ;
|
|
case SRF_FLATRGN :
|
|
pSurfTm = GetBasicSurfFlatRegion( vpSurf[i])->GetAuxSurf() ;
|
|
break ;
|
|
default :
|
|
break ;
|
|
}
|
|
if ( pSurfTm == nullptr)
|
|
return false ;
|
|
vpSurfTm.emplace_back( pSurfTm) ;
|
|
}
|
|
|
|
// sistemazioni per tipo di superficie di riferimento
|
|
const SurfTriMesh* pRefTm = nullptr ;
|
|
switch ( sfRef.GetType()) {
|
|
case SRF_TRIMESH :
|
|
pRefTm = GetBasicSurfTriMesh( &sfRef) ;
|
|
break ;
|
|
case SRF_BEZIER :
|
|
{ double dOldLinTol = GetSurfBezierAuxSurfRefinedTol() ;
|
|
SetSurfBezierAuxSurfRefinedTol( GetSurfBezierTol( dLinTol)) ;
|
|
pRefTm = GetBasicSurfBezier( &sfRef)->GetAuxSurfRefined() ;
|
|
SetSurfBezierAuxSurfRefinedTol( dOldLinTol) ;
|
|
} break ;
|
|
case SRF_FLATRGN :
|
|
pRefTm = GetBasicSurfFlatRegion( &sfRef)->GetAuxSurf() ;
|
|
break ;
|
|
default :
|
|
break ;
|
|
}
|
|
if ( pRefTm == nullptr)
|
|
return false ;
|
|
|
|
// controllo le tolleranze
|
|
dLinTol = max( dLinTol, LIN_TOL_MIN) ;
|
|
dMaxSegmLen = max( dMaxSegmLen, 10 * EPS_SMALL) ;
|
|
|
|
// approssimo la curva con una polilinea entro la tolleranza
|
|
PolyLine PL ;
|
|
if ( ! crCrv.ApproxWithLines( 10 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL) ||
|
|
! PL.RemoveAlignedPoints( dLinTol, false) )
|
|
return false ;
|
|
const double MAX_SEG_LEN = min( dMaxSegmLen, 0.977) ;
|
|
if ( ! PL.AdjustForMaxSegmentLen( MAX_SEG_LEN))
|
|
return false ;
|
|
|
|
// Pulisco e riservo spazio nel vettore dei punti risultanti
|
|
vPt5ax.clear() ;
|
|
vPt5ax.reserve( PL.GetPointNbr()) ;
|
|
|
|
// proietto i punti della polilinea sulla superficie con direzione normale alla curva di riferimento
|
|
double dPar ;
|
|
Point3d ptP ;
|
|
bool bFound = PL.GetFirstUPoint( &dPar, &ptP) ;
|
|
while ( bFound) {
|
|
// se trovo proiezione, la salvo
|
|
Point5ax Pt5ax ;
|
|
if ( ProjectPointOnSurf( ptP, vpSurfTm, *pRefTm, dPar, bFromVsTo, Pt5ax))
|
|
vPt5ax.emplace_back( Pt5ax) ;
|
|
// passo al successivo
|
|
bFound = PL.GetNextUPoint( &dPar, &ptP) ;
|
|
}
|
|
|
|
// se richiesto, inserimento punti intermedi in presenza di spigoli
|
|
if ( bSharpEdges)
|
|
AddPointsOnCorners( vPt5ax) ;
|
|
|
|
// rimozione punti in eccesso rispetto alle tolleranze
|
|
RemovePointsInExcess( vPt5ax, dLinTol, dMaxSegmLen, bSharpEdges) ;
|
|
|
|
return true ;
|
|
}
|