EgtMachKernel :

- in Finiture ZLevel migliorato l'ordinamento delle curve.
This commit is contained in:
Riccardo Elitropi
2025-08-07 17:00:27 +02:00
parent dc0bb1876f
commit bc6c7d8745
+414 -230
View File
@@ -110,12 +110,13 @@ enum {
#define DEBUG 0
#define DEBUG_SFR 0
#define ENABLE_ZCONST_DEBUG 0
#define ENABLE_ZCONST_PATH_DEBUG 0
#define ENABLE_OPTIMAL_DEBUG 0
#define ENABLE_OPTIMAL_SOFT_DEBUG 0
#define ENABLE_OPTIMAL_FINAL_CURVES_DEBUG 0
#define ENABLE_PENCIL_DEBUG 0
#define ENABLE_LINK_DEBUG 0
#if DEBUG || DEBUG_SFR || ENABLE_ZCONST_DEBUG || ENABLE_OPTIMAL_DEBUG || ENABLE_OPTIMAL_SOFT_DEBUG || ENABLE_PENCIL_DEBUG || ENABLE_OPTIMAL_FINAL_CURVES_DEBUG || ENABLE_LINK_DEBUG
#if DEBUG || DEBUG_SFR || ENABLE_ZCONST_DEBUG || ENABLE_ZCONST_PATH_DEBUG || ENABLE_OPTIMAL_DEBUG || ENABLE_OPTIMAL_SOFT_DEBUG || ENABLE_PENCIL_DEBUG || ENABLE_OPTIMAL_FINAL_CURVES_DEBUG || ENABLE_LINK_DEBUG
#include "/EgtDev/Include/EGkGeoPoint3d.h"
#include "/EgtDev/Include/EGkGeoVector3d.h"
#include "/EgtDev/Include/EgtPerfCounter.h"
@@ -2532,278 +2533,461 @@ SurfFinishing::CreateZConstPaths( ICAvToolSurfTm* pCAvTlStm, const Frame3d& frSu
{
// funzione per collegare le curve trovate creando quindi i percorsi di lavoro
// NB. Nel primo TempParam deve essere memorizzata la distanza del piano della curva con il piano della Sfr
// NB. Vengono memorizzate le seguenti informazioni :
// - la prima tempProp della curva è il numero del piano in cui giace il punto iniziale
// - la seconda tempProp della curva è il numero del piano in cui giace il punto finale
// controllo dei parametri
if ( pSfr == nullptr || ! pSfr->IsValid())
return false ;
PtrOwner<ISurfFlatRegion> pSfrClass( CloneSurfFlatRegion( pSfr)) ;
if ( IsNull( pSfrClass) || ! pSfrClass->IsValid())
return false ;
// porto il tool nel frame della superficie
Vector3d vtToolLoc = GetToLoc( vtTool, frSurf) ;
// porto tutte le curve nel piano XY locale alla pSfr
// porto tutte le curve nel piano XY locale alla pSfr e, per ognuna di esse, definisco la regione
// piana di proiezione del materiale rimosso orientato a sinistra della curva
Frame3d frXY ;
Point3d ptCenter ; pSfr->GetCentroid( ptCenter) ;
if ( ! frXY.Set( ptCenter, vtToolLoc))
return false ;
vector<ISURFFRPOVECTOR> vSfrRemMatCol ; vSfrRemMatCol.resize( vCrvCompo.size()) ; // RemovedMaterialColumn
double dRadSignOffs = m_Params.m_bInvert ? m_TParams.m_dDiam / 2. : - m_TParams.m_dDiam / 2. ;
#if ENABLE_ZCONST_PATH_DEBUG
int nGrp = m_pGeomDB->AddGroup( GDB_ID_NULL, GDB_ID_ROOT, GLOB_FRM) ;
m_pGeomDB->SetName( nGrp, "Crv & Sfr") ;
m_pGeomDB->SetStatus( nGrp, GDB_ST_OFF) ;
#endif
for ( int i = 0 ; i < int( vCrvCompo.size()) ; ++ i) {
vSfrRemMatCol[i].resize( vCrvCompo[i].size()) ;
for ( int j = 0 ; j < int( vCrvCompo[i].size()) ; ++ j) {
// --- Frame locale XY
vCrvCompo[i][j]->ToLoc( frXY) ;
#if ENABLE_ZCONST_DEBUG
int _a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, vCrvCompo[i][j]->Clone()) ;
m_pGeomDB->SetMaterial( _a, OLIVE) ;
vCrvCompo[i][j]->SetExtrusion( m_Params.m_bInvert ? - Z_AX : Z_AX) ;
SurfFlatRegionByContours SfrBC ;
// --- Se curva chiusa
if ( vCrvCompo[i][j]->IsClosed()) {
SfrBC.AddCurve( CloneCurveComposite( vCrvCompo[i][j])) ;
OffsetCurve OffsCrv ;
OffsCrv.Make( vCrvCompo[i][j], dRadSignOffs, ICurve::OFF_FILLET) ;
PtrOwner<ICurve> pCrvIsl( OffsCrv.GetLongerCurve()) ;
while ( ! IsNull( pCrvIsl)) {
SfrBC.AddCurve( Release( pCrvIsl)) ;
pCrvIsl.Set( OffsCrv.GetLongerCurve()) ;
}
}
// --- Se curva aperta
else {
OffsetCurve OffsCrv ;
OffsCrv.Make( vCrvCompo[i][j], dRadSignOffs, ICurve::OFF_FILLET) ;
// [euristico, migliorabile/da_correggere]
PtrOwner<ICurve> pCrvInt( OffsCrv.GetLongerCurve()) ;
if ( ! IsNull( pCrvInt)) {
pCrvInt->Invert() ;
Point3d ptS ; pCrvInt->GetStartPoint( ptS) ;
Point3d ptE ; vCrvCompo[i][j]->GetStartPoint( ptE) ;
PtrOwner<ICurveComposite> pSfrLoop( CreateCurveComposite()) ;
if ( IsNull( pSfrLoop))
return false ;
pSfrLoop->AddCurve( CloneCurveComposite( vCrvCompo[i][j])) ;
pSfrLoop->AddLine( ptS) ;
pSfrLoop->AddCurve( Release( pCrvInt)) ;
pSfrLoop->AddLine( ptE) ;
SfrBC.AddCurve( Release( pSfrLoop)) ;
}
}
vSfrRemMatCol[i][j].Set( SfrBC.GetSurf()) ;
if ( IsNull( vSfrRemMatCol[i][j]) || ! vSfrRemMatCol[i][j]->IsValid())
vSfrRemMatCol[i][j].Set( GetSurfFlatRegionFromFatCurve( vCrvCompo[i][j]->Clone(), m_TParams.m_dDiam / 2., false, false)) ;
// tutte rivolte come Z_AX ( vtTool locale)
if ( AreOppositeVectorApprox( vSfrRemMatCol[i][j]->GetNormVersor(), Z_AX))
vSfrRemMatCol[i][j]->Invert() ;
#if ENABLE_ZCONST_PATH_DEBUG
Color myCol = Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, 1.) ;
int nLay = m_pGeomDB->AddGroup( GDB_ID_NULL, nGrp, GLOB_FRM) ;
m_pGeomDB->SetName( nLay, ToString( vCrvCompo[i][j]->GetTempParam( 0))) ;
int nId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, vCrvCompo[i][j]->Clone()) ;
m_pGeomDB->SetMaterial( nId, myCol) ;
nId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, vSfrRemMatCol[i][j]->Clone()) ;
myCol.SetAlpha( .25) ;
m_pGeomDB->SetMaterial( nId, myCol) ;
#endif
}
}
// tengo una copia dei bordi della regione
pSfrClass->ToLoc( frXY) ;
#if ENABLE_ZCONST_DEBUG
int _a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrClass->Clone()) ;
m_pGeomDB->SetMaterial( _a, Color( 0., 1., 0., .15)) ;
// definisco le relazioni delle curve mediante le superfici create
int nRowSize = int( vCrvCompo.size()) ;
int nColSize = 0 ;
for ( int i = 0 ; i < nRowSize ; ++ i)
nColSize = max( nColSize, int( vCrvCompo[i].size())) ;
unordered_map<int, INTINTVECTOR> MapLock ;
unordered_map<int, INTINTVECTOR> MapUnlock ;
for ( int nR = int( vCrvCompo.size()) - 1 ; nR >= 1 ; -- nR) {
for ( int nC = 0 ; nC < int( vCrvCompo[nR].size()) ; ++ nC) {
for ( int nCol = 0 ; nCol < int( vCrvCompo[nR - 1].size()) ; ++ nCol) {
PtrOwner<ISurfFlatRegion> pSfrCheck( CloneSurfFlatRegion( vSfrRemMatCol[nR][nC])) ;
if ( ! IsNull( pSfrCheck)) {
pSfrCheck->Intersect( *vSfrRemMatCol[nR - 1][nCol]) ;
if ( pSfrCheck->IsValid() && pSfrCheck->GetChunkCount() > 0) {
int nKeyLock = nR * nColSize + nC ;
int nKeyUnLock = ( nR - 1) * nColSize + nCol ;
MapLock[nKeyLock].emplace_back( make_pair( nR - 1, nCol)) ;
MapUnlock[nKeyUnLock].emplace_back( make_pair( nR, nC)) ;
}
}
}
}
}
// definisco i gruppi di curve indpendenti; Un insieme di curve risulta indipendente da un altro
// insieme se l'ordine di esecuzione di essi è indifferente ;
// [non esiste alcuna curva nel gruppo A che interferisce con una curva del gruppo B)
vector<ICRVCOMPOPOVECTOR> vIndependentCurveGroup ;
bool bGroup = true ;
int nCont = 0 ;
while ( bGroup && nCont < nRowSize * nColSize) {
++ nCont ;
bGroup = false ;
// cerco la prima curva non ancora inserita in un gruppo
for ( int nR = int( vCrvCompo.size()) - 1 ; nR >= 0 && ! bGroup ; -- nR) {
// scorro sulle colonne ( dalla prima all'ultima) [ordine casuale]
for ( int nC = 0 ; nC < int( vCrvCompo[nR].size()) && ! bGroup ; ++ nC) {
// se la curva attuale già in un gruppo ( quindi nullptr), passo alla successiva
if ( vCrvCompo[nR][nC] == nullptr)
continue ;
// se trovo una curva, allora ho un nuovo gruppo da analizzare
bGroup = true ;
// creazione spazio per un nuovo gruppo
vIndependentCurveGroup.resize( vIndependentCurveGroup.size() + 1) ;
INTINTVECTOR vMapIndCheck = { make_pair( nR, nC)} ;
// finchè ho indici di riga-colonna da verificare
while ( ! vMapIndCheck.empty()) {
// memorizzo gli indici correnti
int nCurrRow = vMapIndCheck.back().first ;
int nCurrCol = vMapIndCheck.back().second ;
// tolgo l'elemento ( non devo ricontrollarlo all'iterazione successiva)
vMapIndCheck.pop_back() ;
// aggiungo la curva al percorso corrente
vIndependentCurveGroup.back().emplace_back( Release( vCrvCompo[nCurrRow][nCurrCol])) ;
// --- se la curva non è bloccata da nessun'altra
auto itLock = MapLock.find( nCurrRow * nColSize + nCurrCol) ;
if ( itLock == MapLock.end()) {
; // non faccio nulla ( ultimo piano locale)
}
// --- altrimenti
else {
// --- scorro le curve che bloccano quella corrente
for ( int i = 0 ; i < int( itLock->second.size()) ; ++ i) {
int nBR = itLock->second[i].first ;
int nBC = itLock->second[i].second ;
INTINT Key = make_pair( nBR, nBC) ;
auto itUnLock = MapUnlock.find( nBR * nColSize + nBC) ;
// verifico che non ci siano altre curve bloccate
bool bLock = false ;
for ( int j = 0 ; j < int( itUnLock->second.size()) && ! bLock ; ++ j)
bLock = ( vCrvCompo[itUnLock->second[j].first][itUnLock->second[j].second] != nullptr) ;
if ( ! bLock)
vMapIndCheck.emplace_back( Key) ;
}
}
}
}
}
}
#if ENABLE_ZCONST_PATH_DEBUG
nGrp = m_pGeomDB->AddGroup( GDB_ID_NULL, GDB_ID_ROOT, GLOB_FRM) ;
m_pGeomDB->SetName( nGrp, "Independent Groups") ;
m_pGeomDB->SetStatus( nGrp, GDB_ST_OFF) ;
vector<Color> vCol ;
vector<int> vLay ;
for ( int nPath = 0 ; nPath < int( vIndependentCurveGroup.size()) ; ++ nPath) {
int nLay = m_pGeomDB->AddGroup( GDB_ID_NULL, nGrp, GLOB_FRM) ;
vLay.emplace_back( nLay) ;
Color myCol = Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, 1.) ;
vCol.emplace_back( myCol) ;
for ( auto& pCrv : vIndependentCurveGroup[nPath]) {
int nId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, CloneCurveComposite( pCrv)) ;
m_pGeomDB->SetMaterial( nId, myCol) ;
}
}
#endif
// definisco il piano locale della regione piana ( frXY è centrato su di essa)
Plane3d plProjection ;
if ( ! plProjection.Set( ORIG, Z_AX))
return false ;
// ordino i gruppi di curve indipendenti
typedef pair<int, pair<double, double>> INTDBLDBL ; // <Ind, <ZMax, ZMin>>
vector<INTDBLDBL> vMapGrpZLoc ;
vMapGrpZLoc.reserve( vIndependentCurveGroup.size()) ;
for ( int i = 0 ; i < int( vIndependentCurveGroup.size()) ; ++ i) {
// scorro le curve del gruppo cercando quella più in alto ( rispetto alla Zlocale di frXY)
double dZMax = - INFINITO ;
double dZMin = INFINITO ;
for ( auto& pCrv : vIndependentCurveGroup[i]) {
double dCurrZ = pCrv->GetTempParam( 0) ;
dZMax = max( dZMax, dCurrZ) ;
dZMin = min( dZMin, dCurrZ) ;
}
vMapGrpZLoc.emplace_back( make_pair( i, make_pair( dZMax, dZMin))) ;
}
// ordino
sort( vMapGrpZLoc.begin(), vMapGrpZLoc.end(), []( const INTDBLDBL& GrpA, const INTDBLDBL& GrpB) {
// Se ZMax coincidenti, viene prima quello con ZMin superiore
if ( abs( GrpA.second.first - GrpB.second.first) < 10 * EPS_SMALL)
return ( GrpA.second.second > GrpB.second.second) ;
// Se diffeenti, viene prima quello con ZMax superiore
return ( GrpA.second > GrpB.second) ;
}) ;
#if ENABLE_ZCONST_PATH_DEBUG
nGrp = m_pGeomDB->AddGroup( GDB_ID_NULL, GDB_ID_ROOT, GLOB_FRM) ;
m_pGeomDB->SetName( nGrp, "Ordered Independent Groups") ;
m_pGeomDB->SetStatus( nGrp, GDB_ST_OFF) ;;
vLay.clear() ;
for ( int nPath = 0 ; nPath < int( vMapGrpZLoc.size()) ; ++ nPath) {
int nLay = m_pGeomDB->AddGroup( GDB_ID_NULL, nGrp, GLOB_FRM) ;
vLay.emplace_back( nLay) ;
for ( auto& pCrv : vIndependentCurveGroup[vMapGrpZLoc[nPath].first]) {
int nId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, CloneCurveComposite( pCrv)) ;
m_pGeomDB->SetMaterial( nId, vCol[vMapGrpZLoc[nPath].first]) ;
}
}
#endif
// tengo una copia dei bordi della regione ( servono per limitare i collegamenti tra le curve dei Path)
PtrOwner<ISurfFlatRegion> pSfrClass( CloneSurfFlatRegion( pSfr)) ;
if ( IsNull( pSfrClass) || ! pSfrClass->IsValid() || ! pSfrClass->ToLoc( frXY))
return false ;
ICRVCOMPOPOVECTOR vCrvSfrLoops ;
for ( int nC = 0 ; nC < pSfrClass->GetChunkCount() ; ++ nC) {
for ( int nL = 0 ; nL < pSfrClass->GetLoopCount( nC) ; ++ nL) {
PtrOwner<ICurveComposite> pCrvLoop( ConvertCurveToComposite( pSfrClass->GetLoop( nC, nL))) ;
if ( IsNull( pCrvLoop) || ! pCrvLoop->IsValid())
return false ;
// tutti i loop sono orientati come il loop esterno ( aiuta per la classificazione della curve)
// tutti i loop sono orientati come il loop esterno
// NB. Per classificare i collegamenti si usa la regione, non queste curve !
// [ Vengono utilizzate per non inizializzare ogni volta una curva corrispondente al bordo
// della superficie di classificazione]
if ( nL > 0)
pCrvLoop->Invert() ;
vCrvSfrLoops.emplace_back( Release( pCrvLoop)) ;
#if ENABLE_ZCONST_DEBUG
int _a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, vCrvSfrLoops.back()->Clone()) ;
m_pGeomDB->SetMaterial( _a, PURPLE) ;
#endif
}
}
// definisco il piano locale della regione piana
Plane3d plProjection ;
if ( ! plProjection.Set( ORIG, Z_AX))
return false ;
int nCurrRow = 0 ;
// scorro le righe
for ( ; nCurrRow < int( vCrvCompo.size()) - 1 ; ++ nCurrRow) {
// scorro sulle colonne
for ( int nCurrCol = 0 ; nCurrCol < int( vCrvCompo[nCurrRow].size()) ; ++ nCurrCol) {
// se la curva attuale è nulla, passo alla successiva
if ( vCrvCompo[nCurrRow][nCurrCol] == nullptr)
continue ;
// recupero il punto finale della curva corrente
Point3d ptCurrEnd ; vCrvCompo[nCurrRow][nCurrCol]->GetEndPoint( ptCurrEnd) ;
// recupero la distanza con la Sfr
double dSfrDistCurr = vCrvCompo[nCurrRow][nCurrCol]->GetTempParam( 0) ;
// inizializzo spazio per un nuovo percorso ( inserisco la curva corrente)
vCrvPath.resize( vCrvPath.size() + 1) ;
vCrvPath.back().Set( vCrvCompo[nCurrRow][nCurrCol]) ;
// salvo come prima temp prop il numero del piano a cui sono
vCrvPath.back()->SetTempProp( nCurrRow + 1, 0) ;
// scorro sulle righe successive
for ( int nNextRow = nCurrRow + 1 ; nNextRow < int( vCrvCompo.size()) ; ++ nNextRow) {
// cerco le curve valide tra le colonne
double dMinSqDist = INFINITO ; // euristico
int nNextCol_path = -1 ;
for ( int nNextCol = 0 ; nNextCol < int( vCrvCompo[nNextRow].size()) ; ++ nNextCol) {
// se curva già in un Path, cerco la successiva
if ( vCrvCompo[nNextRow][nNextCol] == nullptr)
continue ;
// se la curva successiva è aperta
if ( ! vCrvCompo[nNextRow][nNextCol]->IsClosed()) {
// controllo la distanza con il punto iniziale della curva
Point3d ptS ; vCrvCompo[nNextRow][nNextCol]->GetStartPoint( ptS) ;
double dNextSqDist = SqDist( ptS, ptCurrEnd) ;
if ( dNextSqDist < dMinSqDist) {
dMinSqDist = dNextSqDist ;
nNextCol_path = nNextCol ;
}
// controllo la distanza con il punto finale della curva
Point3d ptE ; vCrvCompo[nNextRow][nNextCol]->GetEndPoint( ptE) ;
dNextSqDist = SqDist( ptE, ptCurrEnd) ;
if ( dNextSqDist < dMinSqDist) {
dMinSqDist = dNextSqDist ;
nNextCol_path = nNextCol ;
vCrvCompo[nNextRow][nNextCol]->Invert() ; // inverto
}
}
// se la curva successiva è chiusa
else {
// cerco il punto a minima distanza
DistPointCurve DistPtCrv( ptCurrEnd, *vCrvCompo[nNextRow][nNextCol]) ;
double dNextSqDist = 0. ;
if ( DistPtCrv.GetSqDist( dNextSqDist)) {
if ( dNextSqDist < dMinSqDist) {
dMinSqDist = dNextSqDist ;
nNextCol_path = nNextCol ;
double dMinPar = 0. ;
int nFlag = 0 ;
if ( DistPtCrv.GetParamAtMinDistPoint( 0., dMinPar, nFlag))
vCrvCompo[nNextRow][nNextCol]->ChangeStartPoint( dMinPar) ;
}
}
}
// definisco i collegamenti tra i percorsi
#if ENABLE_ZCONST_PATH_DEBUG
nGrp = m_pGeomDB->AddGroup( GDB_ID_NULL, GDB_ID_ROOT, GLOB_FRM) ;
m_pGeomDB->SetName( nGrp, "Paths") ;
m_pGeomDB->SetStatus( nGrp, GDB_ST_OFF) ;
#endif
const double LINK_TOL = 25. * EPS_SMALL ;
Point3d ptRef = P_INVALID ;
for ( int i = 0 ; i < int( vMapGrpZLoc.size()) ; ++ i) {
// recupero l'indice ordinato del percorso
int nPath = vMapGrpZLoc[i].first ;
// inverto il vettore delle curve di bordo del percorso corrente
reverse( vIndependentCurveGroup[nPath].begin(), vIndependentCurveGroup[nPath].end()) ;
// definisco il vettore dei collegamenti creati tra le curve
// NB. Un collegamento potrebbe non essere valido e non realizzabile
// NB. Il collegamento i-esimo collega la curva di bordo (i-1)-esima con la curva di bordo i-esima
ICRVCOMPOPOVECTOR vCompoLink ;
vCompoLink.resize( vIndependentCurveGroup[nPath].size()) ; // nullptr per ogni Link
// --- se non ho curve, passo al gruppo successivo
if ( vIndependentCurveGroup[nPath].empty())
continue ;
// --- se ho una sola curva, allora controllo se posso cambiare il suo punto d'inizio
// nel caso non sia la prima in assoluto [ -> controllo ptRef]
if ( int( vIndependentCurveGroup[nPath].size()) == 1) {
if ( ptRef.IsValid()) {
// --- se la curva di bordo singola è aperta
if ( ! vIndependentCurveGroup[nPath][0]->IsClosed()) {
// ... se necessario la inverto per recuperare l'estremo più vicino a ptRef
// [ per ora le curve aperte possono essere invertite nelle finiture a ZLevel]
Point3d ptS ; vIndependentCurveGroup[nPath][0]->GetStartPoint( ptS) ;
Point3d ptE ; vIndependentCurveGroup[nPath][0]->GetEndPoint( ptE) ;
if ( SqDist( ptE, ptRef) < SqDist( ptS, ptRef))
vIndependentCurveGroup[nPath][0]->Invert() ;
}
// se non ho trovato nessuna colonna valida
if ( nNextCol_path == -1) {
nCurrRow = 0 ; // azzero il contatore delle righe
break ; // interrompo ciclo sulle righe successive di ricerca
}
// altrimenti creo raccordo e aggiungo la curva al percorso
// --- se la curva di bordo singola è chiusa
else {
// definisco un tratto lineare che collega gli estremi
Point3d ptStartLink = ptCurrEnd ;
Point3d ptEndLink ; vCrvCompo[nNextRow][nNextCol_path]->GetStartPoint( ptEndLink) ;
PtrOwner<ICurveLine> pLineLink( CreateCurveLine()) ;
if ( IsNull( pLineLink) || ! pLineLink->Set( ptStartLink, ptEndLink) ||
! pLineLink->IsValid()) {
// se tratto lineare non valido, non creo il collegamento
nCurrRow = 0 ; // azzero il contatore delle righe
break ; // interrompo ciclo sulle righe successive di ricerca
}
// se la linea è parallela a vtTool( Z_AX), allora ho una parete verticale (localmente)
Vector3d vtLineLink ; pLineLink->GetStartDir( vtLineLink) ;
if ( AreSameOrOppositeVectorEpsilon( vtLineLink, Z_AX, 100 * EPS_SMALL)) {
// in questo caso la proiezione del link è automaticamente sul bordo della pSrfClass
vCrvPath.back()->AddCurve( Release( pLineLink), true, 1500 * EPS_SMALL) ;
vCrvPath.back()->AddCurve( Release( vCrvCompo[nNextRow][nNextCol_path]), true, 1500 * EPS_SMALL) ;
// cerco il punto a minima distanza da ptRef ( non inverto, tengo il senso di lavorazione)
double dMinPar = 0. ;
int nFlag = 0 ;
DistPointCurve( ptRef, *vIndependentCurveGroup[nPath][0]).GetParamAtMinDistPoint( 0., dMinPar, nFlag) ;
vIndependentCurveGroup[nPath][0]->ChangeStartPoint( dMinPar) ;
}
}
// inserisco la curva nel percorso
vCrvPath.emplace_back( Release( vIndependentCurveGroup[nPath][0])) ;
// aggiorno il punto di riferimento
vCrvPath.back()->GetEndPoint( ptRef) ;
#if ENABLE_ZCONST_PATH_DEBUG
int nLay = m_pGeomDB->AddGroup( GDB_ID_NULL, nGrp, GLOB_FRM) ;
m_pGeomDB->SetName( nLay, "Single") ;
Color myCol = Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, 1.) ;
int nId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, CloneCurveComposite( vCrvPath.back())) ;
m_pGeomDB->SetMaterial( nId, myCol) ;
#endif
continue ;
}
// --- se ho più curve di bordo, scorro le curve a due a due per creare i collegamenti
for ( int nCompo = 0 ; nCompo < int( vIndependentCurveGroup[nPath].size()) - 1 ; ++ nCompo) {
// se prima curva di bordo e ho un punto di riferimento valido
if ( nCompo == 0 && ptRef.IsValid()) {
// --- se la prima curva di bordo è aperta
if ( ! vIndependentCurveGroup[nPath][0]->IsClosed()) {
// ... se necessario la inverto per recuperare l'estremo più vicino a ptRef
// [ per ora le curve aperte possono essere invertite nelle finiture a ZLevel]
Point3d ptS ; vIndependentCurveGroup[nPath][0]->GetStartPoint( ptS) ;
Point3d ptE ; vIndependentCurveGroup[nPath][0]->GetEndPoint( ptE) ;
if ( SqDist( ptE, ptRef) < SqDist( ptS, ptRef))
vIndependentCurveGroup[nPath][0]->Invert() ;
}
// --- se la prima curva di bordo è chiusa
else {
// cerco il punto a minima distanza da ptRef ( non inverto, tengo il senso di lavorazione)
double dMinPar = 0. ;
int nFlag = 0 ;
DistPointCurve( ptRef, *vIndependentCurveGroup[nPath][0]).GetParamAtMinDistPoint( 0., dMinPar, nFlag) ;
vIndependentCurveGroup[nPath][0]->ChangeStartPoint( dMinPar) ;
}
}
// come riferimento imposto inizialmente il punto finale della curva corrente
vIndependentCurveGroup[nPath][nCompo]->GetEndPoint( ptRef) ;
// --- se la curva di bordo successiva è aperta...
if ( ! vIndependentCurveGroup[nPath][nCompo + 1]->IsClosed()) {
// ... se necessario la inverto per recuperare l'estremo più vicino a quello corrente
// [ per ora le curve aperte possono essere invertite nelle finiture a ZLevel]
Point3d ptS ; vIndependentCurveGroup[nPath][nCompo + 1]->GetStartPoint( ptS) ;
Point3d ptE ; vIndependentCurveGroup[nPath][nCompo + 1]->GetEndPoint( ptE) ;
if ( SqDist( ptE, ptRef) < SqDist( ptS, ptRef))
vIndependentCurveGroup[nPath][nCompo + 1]->Invert() ;
}
// --- se la curva successiva è chiusa
else {
// cerco il punto a minima distanza ( non inverto, tengo il senso di lavorazione)
double dMinPar = 0. ;
int nFlag = 0 ;
DistPointCurve( ptRef, *vIndependentCurveGroup[nPath][nCompo + 1]).GetParamAtMinDistPoint( 0., dMinPar, nFlag) ;
vIndependentCurveGroup[nPath][nCompo + 1]->ChangeStartPoint( dMinPar) ;
}
// definisco il collegamento diretto come tratto lineare
Point3d ptStartLink ; vIndependentCurveGroup[nPath][nCompo]->GetEndPoint( ptStartLink) ;
Point3d ptEndLink ; vIndependentCurveGroup[nPath][nCompo + 1]->GetStartPoint( ptEndLink) ;
PtrOwner<ICurveLine> pLineLink( CreateCurveLine()) ;
if ( IsNull( pLineLink) || ! pLineLink->Set( ptStartLink, ptEndLink) || ! pLineLink->IsValid())
continue ; // il Link rimane nullptr
// --- se il Link è parallelo a vtTool ( Z_AX in locale), allora ho una parete verticale ( localemente)
Vector3d vtDirLink ; pLineLink->GetStartDir( vtDirLink) ;
if ( AreSameOrOppositeVectorEpsilon( vtDirLink, Z_AX, 100 * EPS_SMALL)) {
// la proiezione del Link è automaticamente all'interno della superficie di classificazione
vCompoLink[nCompo + 1].Set( ConvertCurveToComposite( Release( pLineLink))) ;
}
// --- se il tratto lineare è troppo lungo, non considero il collegamento come valido
else {
if ( SqDist( ptStartLink, ptEndLink) > 4. * m_TParams.m_dDiam * m_TParams.m_dDiam)
continue ; // il Link rimane nullptr
// proietto la curva nel piano locale della superficie di classificazione ( Z=0 ; Z_AX)
PtrOwner<ICurve> pLineLinkProj( ProjectCurveOnPlane( *pLineLink, plProjection)) ;
if ( IsNull( pLineLinkProj) || ! pLineLinkProj->IsValid())
return false ;
// effettuo la classificazione
CRVCVECTOR ccClass ;
if ( ! pSfrClass->GetCurveClassification( *pLineLinkProj, EPS_SMALL, ccClass))
continue ; // il Link rimane nullptr
// inizializzo il link come curva vuota e scorro le classificazioni ottenute
vCompoLink[nCompo + 1].Set( CreateCurveComposite()) ;
for ( int i = 0 ; i < int( ccClass.size()) ; ++ i) {
// recupero il tratto di curve corrente
PtrOwner<ICurve> pSubCrv( pLineLinkProj->CopyParamRange( ccClass[i].dParS, ccClass[i].dParE)) ;
if ( IsNull( pSubCrv) || ! pSubCrv->IsValid()) // troppo piccolo...
continue ; // passo al tratto di classificazione successivo
// --- se la curva non è esterna alla regione, la conservo
if ( ccClass[i].nClass != CRVC_OUT) {
if ( ! vCompoLink[nCompo + 1]->AddCurve( Release( pSubCrv), true, LINK_TOL))
return false ;
}
// --- se la curva è esterna, devo seguire il bordo della regione di classificazione
else {
// altrimenti, se i punti sono distanti, allora non considero valido il collegamento
if ( SqDist( ptStartLink, ptEndLink) > 2. * m_TParams.m_dDiam) {
nCurrRow = 0 ; // azzero il contatore delle righe
break ; // interrompo ciclo sulle righe successive di ricerca
}
#if ENABLE_ZCONST_DEBUG
int _b = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pLineLink->Clone()) ;
m_pGeomDB->SetMaterial( _b, ORANGE) ;
#endif
// proietto la curva nel piano locale della pSfrClass ( Z=0 ; Z_AX)
PtrOwner<ICurve> pLineLinkProjected( ProjectCurveOnPlane( *pLineLink, plProjection)) ;
if ( IsNull( pLineLinkProjected) || ! pLineLinkProjected->IsValid())
return false ;
#if ENABLE_ZCONST_DEBUG
int _c = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pLineLinkProjected->Clone()) ;
m_pGeomDB->SetMaterial( _c, YELLOW) ;
#endif
// classifico la curva proiettata in base alla superficie
CRVCVECTOR ccClass ;
if ( ! pSfrClass->GetCurveClassification( *pLineLinkProjected, EPS_SMALL, ccClass))
return false ;
// inizializzo la nuova curva di Link
PtrOwner<ICurveComposite> pCompoLink( CreateCurveComposite()) ;
if ( IsNull( pCompoLink))
return false ;
// scorro sulle classificazioni ottenute
for ( int i = 0 ; i < int( ccClass.size()) ; ++ i) {
// recupero il tratto di curva corrente
PtrOwner<ICurve> pCrv( pLineLinkProjected->CopyParamRange( ccClass[i].dParS, ccClass[i].dParE)) ;
if ( IsNull( pCrv) || ! pCrv->IsValid()) // troppo piccolo...
continue ; // passo al tratto di classificazione successivo
// se la curva non è esterna alla regione, allora la conservo (non rivina le Stm)
if ( ccClass[i].nClass != CRVC_OUT) {
if ( ! pCompoLink->AddCurve( Release( pCrv), true, 25 * EPS_SMALL))
// recupero gli estremi del segmento di classificazione esterno alla pSfrClass
Point3d ptS_sfr ; pLineLinkProj->GetPointD1D2( ccClass[i].dParS, ICurve::FROM_MINUS, ptS_sfr) ;
Point3d ptE_sfr ; pLineLinkProj->GetPointD1D2( ccClass[i].dParE, ICurve::FROM_MINUS, ptE_sfr) ;
// scorro tutti i loop della regione di classificazione
for ( int j = 0 ; j < int( vCrvSfrLoops.size()) ; ++ j) {
// se i punti trovati sono sul loop corrente
if ( vCrvSfrLoops[j]->IsPointOn( ptS_sfr, LINK_TOL) &&
vCrvSfrLoops[j]->IsPointOn( ptE_sfr, LINK_TOL)) {
// devo orientare la SubCrv secondo il giusto verso di percorrenza
double dUS ; vCrvSfrLoops[j]->GetParamAtPoint( ptS_sfr, dUS, LINK_TOL) ;
double dUE ; vCrvSfrLoops[j]->GetParamAtPoint( ptE_sfr, dUE, LINK_TOL) ;
PtrOwner<ICurve> pCrvA( ( vCrvSfrLoops[j]->CopyParamRange( dUS, dUE))) ;
PtrOwner<ICurve> pCrvB( ( vCrvSfrLoops[j]->CopyParamRange( dUE, dUS))) ;
double dLenA = INFINITO ; double dLenB = INFINITO ;
if ( ! IsNull( pCrvA) && pCrvA->IsValid())
pCrvA->GetLength( dLenA) ;
if ( ! IsNull( pCrvB) && pCrvB->IsValid()) {
// sempre percorsa in senso opposto
pCrvB->Invert() ;
pCrvB->GetLength( dLenB) ;
}
// aggiungo la curva
if ( ! vCompoLink[nCompo + 1]->AddCurve( dLenA < dLenB ? Release( pCrvA) : Release( pCrvB), true, LINK_TOL))
return false ;
}
// se la curva è esterna, allora devo seguire il bordo della regione di classificazione
else {
// recupero gli estremi del segmento di classificazione esterno alla pSfrClass
Point3d ptS_sfr ; pLineLinkProjected->GetPointD1D2( ccClass[i].dParS, ICurve::FROM_MINUS, ptS_sfr) ;
Point3d ptE_sfr ; pLineLinkProjected->GetPointD1D2( ccClass[i].dParE, ICurve::FROM_MINUS, ptE_sfr) ;
// scorro tutti i loop della regione di classificazione
for ( int j = 0 ; j < int( vCrvSfrLoops.size()) ; ++ j) {
// se i punti trovati sono sul loop corrente
if ( vCrvSfrLoops[j]->IsPointOn( ptS_sfr, 25 * EPS_SMALL) &&
vCrvSfrLoops[j]->IsPointOn( ptE_sfr, 25 * EPS_SMALL)) {
// devo capire quale delle due curve (pCrvA, pCrvB) devo seguire sul bordo
double dUS ; vCrvSfrLoops[j]->GetParamAtPoint( ptS_sfr, dUS, 25 * EPS_SMALL) ;
double dUE ; vCrvSfrLoops[j]->GetParamAtPoint( ptE_sfr, dUE, 25 * EPS_SMALL) ;
PtrOwner<ICurveComposite> pCrvA( ConvertCurveToComposite( vCrvSfrLoops[j]->CopyParamRange( dUS, dUE))) ;
PtrOwner<ICurveComposite> pCrvB( ConvertCurveToComposite( vCrvSfrLoops[j]->CopyParamRange( dUE, dUS))) ;
// tra le due curve (pCrvA, pCrvB) scelgo quella con lunghezza minore
double dLenA = INFINITO ; double dLenB = INFINITO ;
if ( ! IsNull( pCrvA) && pCrvA->IsValid())
pCrvA->GetLength( dLenA) ;
if ( ! IsNull( pCrvB) && pCrvB->IsValid()) {
// la pCrvB è sempre percorsa in senso opposto
pCrvB->Invert() ;
pCrvB->GetLength( dLenB) ;
}
// aggiungo la curva
if ( ! pCompoLink->AddCurve( dLenA < dLenB ? Release( pCrvA) : Release( pCrvB), true, 25 * EPS_SMALL))
return false ;
}
}
}
}
// se il link trovato non è valido, ricomincio la ricerca
if ( ! pCompoLink->IsValid()) {
nCurrRow = 0 ; // azzero il contatore delle righe
break ; // interrompo ciclo sulle righe successive di ricerca
}
// porto il link sulla curva attuale di silhouette e lo proietto sulla pStm (sono in locale)
double dSfrDistNext = vCrvCompo[nNextRow][nNextCol_path]->GetTempParam( 0) ;
pCompoLink->Translate( Z_AX * min( dSfrDistCurr, dSfrDistNext)) ;
#if ENABLE_ZCONST_DEBUG
int _d = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCompoLink->Clone()) ;
m_pGeomDB->SetMaterial( _d, LIME) ;
#endif
if ( ! CalcZConstProjectedLink( pCAvTlStm, frXY, frSurf, vtTool, dDepth, ptStartLink, ptEndLink, pCompoLink))
return false ;
#if ENABLE_ZCONST_DEBUG
int _e = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCompoLink->Clone()) ;
m_pGeomDB->SetMaterial( _e, RED) ;
#endif
// aggiungo le curve ritrovate al percorso attuale
if ( ! vCrvPath.back()->AddCurve( Release( pCompoLink), true, 1500 * EPS_SMALL) ||
! vCrvPath.back()->AddCurve( Release( vCrvCompo[nNextRow][nNextCol_path]), true, 1500 * EPS_SMALL))
return false ;
}
vCrvPath.back()->GetEndPoint( ptCurrEnd) ; // aggiorno il punto finale del percorso
vCrvPath.back()->SetTempProp( nNextRow + 1, 1) ; // salvo come seconda temp prop il piano a cui sono
}
}
}
}
// se non ho percorsi, non faccio nulla
if ( vCrvPath.empty())
return true ;
// se ho percorsi non validi, errore
for ( int i = 0 ; i < int( vCrvPath.size()) ; ++ i) {
if ( vCrvPath[i] == nullptr || ! vCrvPath[i]->IsValid())
return false ;
}
// se il link trovato non è valido, passo al successivo
if ( ! vCompoLink[nCompo + 1]->IsValid())
continue ; // il link rimane inizializzato e non valido ( 0 curve)
// preso come riferimento il primo percorso, ordino i successivi in base alla vicinanza
Point3d ptRef ; vCrvPath.front()->GetEndPoint( ptRef) ;
double dSqMaxDist = INFINITO ;
for ( int i = 1 ; i < int( vCrvPath.size()) ; ++ i) {
int nNextInd = i + 1 ;
for ( int j = nNextInd ; j < int( vCrvPath.size()) ; ++ j) {
Point3d ptS ; vCrvPath[j]->GetStartPoint( ptS) ;
double dCurrSqDist = SqDist( ptS, ptRef) ;
if ( dCurrSqDist < dSqMaxDist) {
dSqMaxDist = dCurrSqDist ;
nNextInd = j ;
// porto il link sul piano della curva più in alto tra le due
Point3d ptCheck ;
vIndependentCurveGroup[nPath][nCompo + 1]->GetStartPoint( ptCheck) ;
double dSfrDistNext = DistPointPlane( ptCheck, plProjection) ;
vIndependentCurveGroup[nPath][nCompo]->GetStartPoint( ptCheck) ;
double dSfrDistCurr = DistPointPlane( ptCheck, plProjection) ;
vCompoLink[nCompo + 1]->Translate( Z_AX * min( dSfrDistCurr, dSfrDistNext)) ;
// proietto tale Link sulla superficie
if ( ! CalcZConstProjectedLink( pCAvTlStm, frXY, frSurf, vtTool, dDepth, ptStartLink, ptEndLink, vCompoLink[nCompo + 1]))
return false ;
}
}
if ( nNextInd != i + 1)
swap( vCrvPath[i], vCrvPath[nNextInd]) ;
dSqMaxDist = INFINITO ;
// calcolo il percorso unendo le curve di bordo con i Link ricavati
const double PATH_TOL = 1500. * EPS_SMALL ;
#if ENABLE_ZCONST_PATH_DEBUG
int nLay = GDB_ID_NULL ;
Color myCol = INVISIBLE ;
#endif
for ( int nCompo = 0 ; nCompo < int( vIndependentCurveGroup[nPath].size()) - 1 ; ++ nCompo) {
if ( IsNull( vCompoLink[nCompo]) || ! vCompoLink[nCompo]->IsValid()) {
#if ENABLE_ZCONST_PATH_DEBUG
nLay = m_pGeomDB->AddGroup( GDB_ID_NULL, nGrp, GLOB_FRM) ;
myCol = Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, 1.) ;
#endif
if ( ! vCrvPath.emplace_back( CreateCurveComposite()))
return false ;
}
else {
#if ENABLE_ZCONST_PATH_DEBUG
int nId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, CloneCurveComposite( vCompoLink[nCompo])) ;
m_pGeomDB->SetMaterial( nId, myCol) ;
#endif
vCrvPath.back()->AddCurve( Release( vCompoLink[nCompo]), true, PATH_TOL) ;
}
#if ENABLE_ZCONST_PATH_DEBUG
int nId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, CloneCurveComposite( vIndependentCurveGroup[nPath][nCompo])) ;
m_pGeomDB->SetMaterial( nId, myCol) ;
#endif
vCrvPath.back()->AddCurve( Release( vIndependentCurveGroup[nPath][nCompo]), true, PATH_TOL) ;
}
}
// riporto i percorsi nel frame originale