EgtGeomKernel 2.7l2 :
- Modificate le funzioni di Offset per superfici TriMesh aperte - Aggiunta la funzione per la creazione di Shell per TriMesh.
This commit is contained in:
Binary file not shown.
+641
-93
@@ -9,6 +9,7 @@
|
||||
// Modifiche : 10.06.25 RE Creazione modulo.
|
||||
// 10.06.25 RE Offset di superfici chiuse.
|
||||
// 04.07.25 RE Thickening Offset di superfici generiche.
|
||||
// 10.12.25 RE Creazione superfici Shell.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
@@ -16,11 +17,17 @@
|
||||
#include "stdafx.h"
|
||||
#include "VolZmap.h"
|
||||
#include "SurfTriMesh.h"
|
||||
#include "EgtDev/Include/EGkDistPointSurfTm.h"
|
||||
#include "\EgtDev\Include\EGkSurfTriMeshAux.h"
|
||||
#include "/EgtDev/Include/EGkDistPointSurfTm.h"
|
||||
#include "/EgtDev/Include/EGkDistPointCurve.h"
|
||||
#include "/EgtDev/Include/EGkDistPointTria.h"
|
||||
#include "/EgtDev/Include/EGkSurfTriMeshAux.h"
|
||||
#include "/EgtDev/Include/EGkStmFromCurves.h"
|
||||
#include "/EgtDev/Include/EGkStmFromTriangleSoup.h"
|
||||
#include <future>
|
||||
|
||||
#define DEBUG 0
|
||||
#if DEBUG
|
||||
#include "/EgtDev/Include/EGnStringUtils.h"
|
||||
#include "/EgtDev/Include/EGkGeoObjSave.h"
|
||||
#include "/EgtDev/Include/EGkGeoPoint3d.h"
|
||||
#include "/EgtDev/Include/EGkGeoVector3d.h"
|
||||
@@ -58,6 +65,255 @@ SumStm( const CISURFTMPVECTOR& vStm)
|
||||
return ( Release( pStmAdd)) ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Funzioni per la distanza tra punto e superficie TriMesh in parallelo
|
||||
//----------------------------------------------------------------------------
|
||||
static bool
|
||||
BoundingBoxDifference( const BBox3d& boxA, const BBox3d& boxB, BOXVECTOR& vBoxDiff)
|
||||
{
|
||||
// svuoto il risultato
|
||||
vBoxDiff.clear() ;
|
||||
// se box A vuoto, risultato vuoto
|
||||
if ( boxA.IsEmpty())
|
||||
return false ;
|
||||
// se box B vuoto o i box non si intersecano, risultato è ancora A
|
||||
BBox3d boxInt ;
|
||||
if ( boxB.IsSmall() || ! boxA.FindIntersection( boxB, boxInt)) {
|
||||
vBoxDiff.emplace_back( boxA) ;
|
||||
return true ;
|
||||
}
|
||||
// recupero i punti estremi dei box A e Intersezione
|
||||
Point3d ptMinA, ptMaxA ; boxA.GetMinMax( ptMinA, ptMaxA) ;
|
||||
Point3d ptMinInt, ptMaxInt ; boxInt.GetMinMax( ptMinInt, ptMaxInt) ;
|
||||
// sotto
|
||||
if ( ptMinInt.z - ptMinA.z > EPS_SMALL) {
|
||||
BBox3d boxD( ptMinA, Point3d( ptMaxA.x, ptMaxA.y, ptMinInt.z)) ;
|
||||
vBoxDiff.emplace_back( boxD) ;
|
||||
}
|
||||
// sopra
|
||||
if ( ptMaxA.z - ptMaxInt.z > EPS_SMALL) {
|
||||
BBox3d boxD( Point3d( ptMinA.x, ptMinA.y, ptMaxInt.z), ptMaxA) ;
|
||||
vBoxDiff.emplace_back( boxD) ;
|
||||
}
|
||||
// davanti
|
||||
if ( ptMinInt.y - ptMinA.y > EPS_SMALL) {
|
||||
BBox3d boxD( Point3d( ptMinA.x, ptMinA.y, ptMinInt.z), Point3d( ptMaxA.x, ptMinInt.y, ptMaxInt.z)) ;
|
||||
vBoxDiff.emplace_back( boxD) ;
|
||||
}
|
||||
// dietro
|
||||
if ( ptMaxA.y - ptMaxInt.y > EPS_SMALL) {
|
||||
BBox3d boxD( Point3d( ptMinA.x, ptMaxInt.y, ptMinInt.z), Point3d( ptMaxA.x, ptMaxA.y, ptMaxInt.z)) ;
|
||||
vBoxDiff.emplace_back( boxD) ;
|
||||
}
|
||||
// sinistra
|
||||
if ( ptMinInt.x - ptMinA.x > EPS_SMALL) {
|
||||
BBox3d boxD( Point3d( ptMinA.x, ptMinInt.y, ptMinInt.z), Point3d( ptMinInt.x, ptMaxInt.y, ptMaxInt.z)) ;
|
||||
vBoxDiff.emplace_back( boxD) ;
|
||||
}
|
||||
// destra
|
||||
if ( ptMaxA.y - ptMaxInt.y > EPS_SMALL) {
|
||||
BBox3d boxD( Point3d( ptMaxInt.x, ptMinInt.y, ptMinInt.z), Point3d( ptMaxA.x, ptMaxInt.y, ptMaxInt.z)) ;
|
||||
vBoxDiff.emplace_back( boxD) ;
|
||||
}
|
||||
// risultato
|
||||
return ( ! vBoxDiff.empty()) ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
static bool
|
||||
DistPointSurfTmMultiThread( const Point3d& ptP, const SurfTriMesh& SurfTm, double& dDist,
|
||||
bool& bIsInside, INTVECTOR& vIndClosestTria)
|
||||
{
|
||||
// verifico che la supercicie sia valida
|
||||
if ( ! SurfTm.IsValid())
|
||||
return false ;
|
||||
|
||||
// inizializzo distanza non calcolata
|
||||
dDist = - 1. ;
|
||||
// vettore di indici dei triangoli più vicini inizialmente vuoto
|
||||
vIndClosestTria.clear() ;
|
||||
// vettore dei flag temporanei inizialmente tutto a 0
|
||||
INTVECTOR vIntFlags( SurfTm.GetTriangleCount(), 0) ;
|
||||
|
||||
// recupero e verifico il box locale della superficie
|
||||
BBox3d b3Stm = SurfTm.GetAllTriaBox() ;
|
||||
if ( b3Stm.IsEmpty())
|
||||
return false ;
|
||||
|
||||
// cerco triangoli in box centrati sul punto dato di ampiezza crescente ed escludendo le parti già verificate.
|
||||
// termino quando non trovo più triangoli che possano soddisfare la richiesta.
|
||||
Point3d ptMin, ptMax ; b3Stm.GetMinMax( ptMin, ptMax) ;
|
||||
double dDeltaLen = max( min( min( b3Stm.GetDimX(), b3Stm.GetDimY()), b3Stm.GetDimZ()) / 40., 20.) ;
|
||||
double dBoxHalfLenX = max( max( ptMin.x - ptP.x, ptP.x - ptMax.x), 0.) + dDeltaLen ;
|
||||
double dBoxHalfLenY = max( max( ptMin.y - ptP.y, ptP.y - ptMax.y), 0.) + dDeltaLen ;
|
||||
double dBoxHalfLenZ = max( max( ptMin.z - ptP.z, ptP.z - ptMax.z), 0.) + dDeltaLen ;
|
||||
// considero anche il box precedente per poter analizzare solo il volume differenza tra i due
|
||||
BBox3d boxPPrev( ptP) ;
|
||||
BBox3d boxP( ptP, dBoxHalfLenX, dBoxHalfLenY, dBoxHalfLenZ) ;
|
||||
// variabili distanza minima, indice del triangolo di distanza minima, punto di distanza minima
|
||||
double dMinDist = DBL_MAX ;
|
||||
int nMinDistTriaIndex = SVT_NULL ;
|
||||
Point3d ptMinDistPoint ;
|
||||
// finché non si verifica la condizione di terminazione ingrandisco il box.
|
||||
bool bContinue = true ;
|
||||
|
||||
// creazione del vettore dei triangoli più vicini a ptP
|
||||
vector<pair<int, Triangle3d>> vTria ; // <indice triangolo, Triangolo>
|
||||
while ( bContinue) {
|
||||
// calcolo il box differenza con il precedente per non esplorare parti già considerate
|
||||
BOXVECTOR vBox ;
|
||||
BoundingBoxDifference( boxP, boxPPrev, vBox) ;
|
||||
// Ciclo sui box differenza
|
||||
bool bCollide = false ;
|
||||
for ( const auto& b3Box : vBox) {
|
||||
// interseco il box con quello della superficie e ne verifico la distanza minima dal punto
|
||||
BBox3d b3Int ;
|
||||
if ( ! b3Box.FindIntersection( b3Stm, b3Int) || b3Int.DistFromPoint( ptP) > dMinDist)
|
||||
continue ;
|
||||
// ricerca sui triangoli nel box
|
||||
bCollide = true ;
|
||||
INTVECTOR vnIds ;
|
||||
if ( SurfTm.GetAllTriaOverlapBox( b3Int, vnIds)) {
|
||||
// ciclo sui triangoli del sotto-box corrente
|
||||
for ( auto nT : vnIds) {
|
||||
Triangle3d trCurTria ;
|
||||
if ( vIntFlags[nT] == 0 && SurfTm.GetTriangle( nT, trCurTria)) {
|
||||
vIntFlags[nT] = 1 ;
|
||||
DistPointTriangle distPT( ptP, trCurTria) ;
|
||||
double dCurrDist ;
|
||||
// se la distanza del triangolo è valida e minore di quella attuale aggiorno
|
||||
if ( distPT.GetDist( dCurrDist)) {
|
||||
// se distanze uguali...
|
||||
if ( abs( dCurrDist - dMinDist) < EPS_SMALL)
|
||||
// aggiungo il triangolo
|
||||
vTria.emplace_back( make_pair( nT, trCurTria)) ;
|
||||
// se minore...
|
||||
else if ( dCurrDist < dMinDist) {
|
||||
// pulisco il vettore
|
||||
vTria.clear() ;
|
||||
dMinDist = dCurrDist ;
|
||||
nMinDistTriaIndex = nT ;
|
||||
distPT.GetMinDistPoint( ptMinDistPoint) ;
|
||||
// aggiungo il triangolo
|
||||
vTria.emplace_back( make_pair( nT, trCurTria)) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// se si verifica la condizione di terminazione arresto il ciclo altrimenti aggiorno i box
|
||||
if ( ! bCollide || dMinDist < EPS_SMALL)
|
||||
bContinue = false ;
|
||||
else {
|
||||
boxPPrev = boxP ;
|
||||
boxP.Expand( dDeltaLen) ;
|
||||
}
|
||||
}
|
||||
// se non ho trovato nessun triangolo, errore
|
||||
if ( nMinDistTriaIndex == SVT_NULL)
|
||||
return false ;
|
||||
|
||||
// riempio il vettore dei triangoli a minima distanza
|
||||
for ( auto& Tria : vTria)
|
||||
vIndClosestTria.emplace_back( Tria.first) ;
|
||||
// salvo la distanza
|
||||
dDist = dMinDist ;
|
||||
|
||||
// determino il Side
|
||||
if ( dDist < EPS_SMALL) {
|
||||
bIsInside = false ;
|
||||
return true ;
|
||||
}
|
||||
// se ho solo un triangolo
|
||||
else if ( int( vTria.size()) == 1) {
|
||||
bIsInside = ( ( ptP - ptMinDistPoint) * vTria.back().second.GetN() < - EPS_SMALL) ;
|
||||
return true ;
|
||||
}
|
||||
|
||||
// controllo se tutti i triangoli a minima distanza forniscono la stessa informazione
|
||||
// ( il punto potrebbe essere esterno a tutti, interno a tutti o indefinito )
|
||||
bool bInside = false ;
|
||||
bool bOutside = false ;
|
||||
for ( int i = 0 ; i < int( vTria.size()) ; ++ i) {
|
||||
if ( ( ptP - vTria[i].second.GetP( 0)) * vTria[i].second.GetN() < - EPS_SMALL)
|
||||
bInside = true ;
|
||||
else
|
||||
bOutside = true ;
|
||||
}
|
||||
|
||||
bIsInside = false ;
|
||||
if ( bOutside == bInside) {
|
||||
Point3d ptBar_tot ;
|
||||
for ( const auto& Tria : vTria)
|
||||
ptBar_tot += Tria.second.GetCentroid() ;
|
||||
for ( const auto& Tria : vTria) {
|
||||
Point3d ptInters1, ptInters2 ;
|
||||
int nType = IntersLineTria( ptP, ptBar_tot, Tria.second, ptInters1, ptInters2) ;
|
||||
if ( nType == ILTT_IN) {
|
||||
DistPointTriangle( ptP, Tria.second).GetMinDistPoint( ptMinDistPoint) ;
|
||||
bIsInside = ( ( ptP - ptMinDistPoint) * Tria.second.GetN() < - EPS_SMALL) ;
|
||||
nMinDistTriaIndex = Tria.first ;
|
||||
break ;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
bIsInside = bInside ;
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
static bool
|
||||
ClassifyTrianglesMultiThread( const TRIA3DEXVECTOR& vTria, int nIndS, int nIndE,
|
||||
const SurfTriMesh& SurfTm, double dOffs, double dPrec,
|
||||
bool bSaveInside, BOOLVECTOR& vbSafe)
|
||||
{
|
||||
// verifico che la superficie sia valida
|
||||
if ( ! SurfTm.IsValid())
|
||||
return false ;
|
||||
// verifico la validità degli indici
|
||||
if ( nIndS < 0 || nIndE >= int( vTria.size()))
|
||||
return false ;
|
||||
// verifico la dimensione dei vettori
|
||||
if ( vTria.size() != vbSafe.size())
|
||||
return false ;
|
||||
|
||||
// scorro gli indici dei triangoli da classificare
|
||||
for ( int k = nIndS ; k <= nIndE ; ++ k) {
|
||||
// recupero il triangolo corrente
|
||||
const Triangle3dEx& Tria = vTria[k] ;
|
||||
// preparo gli elementi di classificazione
|
||||
DBLVECTOR vDists ; vDists.resize( 3) ;
|
||||
INTMATRIX matIndClosestTria ; matIndClosestTria.resize( 3) ;
|
||||
// verifico che i suoi punti siano distanti almeno |dOffs| - dTol dalla superficie
|
||||
vbSafe[k] = true ;
|
||||
for ( int i = 0 ; vbSafe[k] && i < 3 ; ++ i) {
|
||||
bool bIsInside = false ;
|
||||
DistPointSurfTmMultiThread( Tria.GetP( i), SurfTm, vDists[i], bIsInside, matIndClosestTria[i]) ;
|
||||
vbSafe[k] = ( ( vDists[i] > abs( dOffs) - 0.25 * dPrec) &&
|
||||
( vDists[i] < abs( dOffs) + 0.25 * dPrec) &&
|
||||
( bIsInside == bSaveInside)) ;
|
||||
}
|
||||
// se tutti sufficientemente distanti
|
||||
if ( vbSafe[k]) {
|
||||
// i triangoli a minima distanza devono avere normale simile
|
||||
bool bPerp = true ;
|
||||
for ( int i = 0 ; bPerp && i < 3 ; ++ i) {
|
||||
for ( int j = 0 ; bPerp && j < int( matIndClosestTria[i].size()) ; ++ j) {
|
||||
Triangle3d TriaCloser ;
|
||||
SurfTm.GetTriangle( matIndClosestTria[i][j], TriaCloser) ;
|
||||
bPerp = ( abs( Tria.GetN() * TriaCloser.GetN()) < cos( 30. * DEGTORAD)) ;
|
||||
}
|
||||
}
|
||||
vbSafe[k] = ( ! bPerp) ;
|
||||
}
|
||||
}
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Funzione che crea l'Offset di una superficie TriMesh
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -94,123 +350,138 @@ CreateSurfTriMeshesOffset( const CISURFTMPVECTOR& vStm, double dOffs, double dPr
|
||||
return SumStm( vStm) ;
|
||||
|
||||
// creo lo Zmap associato alle superfici TriMesh
|
||||
VolZmap OneVolZmap ;
|
||||
if ( ! OneVolZmap.CreateFromTriMeshOffset( vStm, dOffs, dMyPrec, nType))
|
||||
VolZmap myVolZmap ;
|
||||
if ( ! myVolZmap.CreateFromTriMeshOffset( vStm, dOffs, dMyPrec, nType))
|
||||
return nullptr ;
|
||||
if ( ! OneVolZmap.IsValid())
|
||||
if ( ! myVolZmap.IsValid())
|
||||
return nullptr ;
|
||||
|
||||
// recupero le superfici aperte
|
||||
CISURFTMPVECTOR vStmOpen ;
|
||||
for ( const ISurfTriMesh* pStm : vStm) {
|
||||
if ( pStm != nullptr && pStm->IsValid() && ! pStm->IsClosed())
|
||||
if ( pStm != nullptr && pStm->IsValid() && ! pStm->IsClosed())
|
||||
vStmOpen.emplace_back( pStm) ;
|
||||
}
|
||||
|
||||
// --- se non ho superfici aperte
|
||||
if ( vStmOpen.empty()) {
|
||||
// restituisco la superficie TriMesh di Offset
|
||||
return ( OneVolZmap.GetSurfTriMesh()) ;
|
||||
return ( myVolZmap.GetSurfTriMesh()) ;
|
||||
}
|
||||
|
||||
// --- se ho delle superfici aperte
|
||||
// lo Zmap creato è orientato e definisce una superficie chiusa; devo rimuovere i triangoli in eccesso
|
||||
|
||||
// anzitutto controllo che lo Zmap sia valido
|
||||
if ( ! OneVolZmap.IsValid())
|
||||
return nullptr ;
|
||||
|
||||
// inzializzo la superficie TriMesh da restituire
|
||||
PtrOwner<SurfTriMesh> pStm( CreateBasicSurfTriMesh()) ;
|
||||
if ( IsNull( pStm) || ! pStm->Init( 3, 1))
|
||||
return nullptr ;
|
||||
PointGrid3d VertGrid ; VertGrid.Init( 50000) ;
|
||||
|
||||
// tolleranza di vicinanza alla superficie
|
||||
double dTolDist = 30. * EPS_SMALL ;
|
||||
|
||||
#if DEBUG
|
||||
VT.emplace_back( OneVolZmap.Clone()) ;
|
||||
VC.emplace_back( BLACK) ;
|
||||
#endif
|
||||
|
||||
// ciclo lungo i blocchi dello ZMap
|
||||
for ( int nB = 0 ; nB < OneVolZmap.GetBlockCount() ; ++ nB) {
|
||||
|
||||
// recupero i triangoli
|
||||
// --- se ho delle superfici chiuse
|
||||
TRIA3DEXVECTOR vAllTria, vTriaOffs ;
|
||||
for ( int nB = 0 ; nB < myVolZmap.GetBlockCount() ; ++ nB) {
|
||||
TRIA3DEXVECTOR vTria, vTriaSafe ;
|
||||
OneVolZmap.GetBlockTriangles( nB, vTria) ;
|
||||
|
||||
// un triangolo viene ritenuto valido se è non è troppo vicino ( dOffs) alle superfici aperte
|
||||
myVolZmap.GetBlockTriangles( nB, vTria) ;
|
||||
#if DEBUG
|
||||
TRIA3DVECTOR vTriaUnsafe ;
|
||||
#endif
|
||||
for ( int nT = 0 ; nT < int( vTria.size()) ; ++ nT) {
|
||||
|
||||
// recupero il triangolo
|
||||
Triangle3dEx& Tria = vTria[nT] ;
|
||||
|
||||
// scorro le superficie aperte
|
||||
bool bInsert = true ;
|
||||
for ( int nS = 0 ; bInsert && nS < int( vStm.size()) ; ++ nS) {
|
||||
|
||||
// controllo se posso inserirlo
|
||||
vector<DistPointSurfTm> vDistPtStm ;
|
||||
for ( int i = 0 ; i < 3 && bInsert ; ++ i) {
|
||||
double dDist = 0. ;
|
||||
vDistPtStm.emplace_back( DistPointSurfTm( Tria.GetP( i), *vStm[nS])) ;
|
||||
bInsert = ( vDistPtStm.back().GetDist( dDist) && dDist > abs( dOffs) - dTolDist) ;
|
||||
}
|
||||
// se il triangolo è al più a distanza di |dOffs| - dTolDist
|
||||
if ( bInsert) {
|
||||
// recupero i triangoli a distanza minima dai vertici del triangolo corrente
|
||||
bool bPerp = true ;
|
||||
for ( int i = 0 ; i < 3 && bPerp ; ++ i) {
|
||||
INTVECTOR vTria ;
|
||||
vDistPtStm[i].GetMinDistTriaIndices( vTria) ;
|
||||
for ( int j = 0 ; j < int( vTria.size()) && bPerp ; ++ j) {
|
||||
Triangle3d TriaCloser ;
|
||||
vStm[nS]->GetTriangle( vTria[j], TriaCloser) ;
|
||||
bPerp = ( abs( Tria.GetN() * TriaCloser.GetN()) < dTolDist) ;
|
||||
}
|
||||
}
|
||||
// se tutti i triangoli a distanza minima sono perpendicolari, allora non lo inserisco
|
||||
bInsert = ( ! bPerp) ;
|
||||
BBox3d BBoxTria ;
|
||||
Tria.GetLocalBBox( BBoxTria) ;
|
||||
// azzero flag di colore
|
||||
vAllTria.push_back( Tria) ;
|
||||
}
|
||||
}
|
||||
// classifico i triangoli
|
||||
PtrOwner<const SurfTriMesh> pStmBasic( nullptr) ;
|
||||
if ( int( vStmOpen.size() == 1))
|
||||
pStmBasic.Set( GetBasicSurfTriMesh( CloneSurfTriMesh( vStmOpen[0]))) ;
|
||||
else {
|
||||
StmFromTriangleSoup AllOpenStmSoup ; AllOpenStmSoup.Start() ;
|
||||
for ( const ISurfTriMesh* pStmOpen : vStmOpen) {
|
||||
if ( pStmOpen != nullptr && pStmOpen->IsValid()) {
|
||||
for ( int nT = 0 ; nT < pStmOpen->GetTriangleCount() ; ++ nT) {
|
||||
Triangle3d Tria ;
|
||||
if ( pStmOpen->GetTriangle( nT, Tria))
|
||||
AllOpenStmSoup.AddTriangle( Tria) ;
|
||||
}
|
||||
}
|
||||
|
||||
// se triangolo da inserire
|
||||
if ( bInsert)
|
||||
vTriaSafe.emplace_back( Tria) ;
|
||||
|
||||
#if DEBUG
|
||||
ICurveComposite* pCompo = CreateCurveComposite() ;
|
||||
pCompo->AddPoint( Tria.GetP( 0)) ;
|
||||
pCompo->AddLine( Tria.GetP( 1)) ;
|
||||
pCompo->AddLine( Tria.GetP( 2)) ;
|
||||
pCompo->Close() ;
|
||||
Color myCol = ( bInsert ? Color( 0., 1., 0., .5) : Color( 1., 0., 0., .5)) ;
|
||||
VT.emplace_back( CloneCurveComposite( pCompo)) ;
|
||||
VC.emplace_back( myCol) ;
|
||||
ISurfFlatRegion* pSfrTria = CreateSurfFlatRegion() ;
|
||||
pSfrTria->AddExtLoop( pCompo) ;
|
||||
VT.emplace_back( pSfrTria) ;
|
||||
VC.emplace_back( myCol) ;
|
||||
#endif
|
||||
}
|
||||
|
||||
// inserisco tutti i triangoli validi
|
||||
if ( ! pStm->AddTriaFromZMap( vTriaSafe, VertGrid))
|
||||
return nullptr ;
|
||||
AllOpenStmSoup.End() ;
|
||||
pStmBasic.Set( GetBasicSurfTriMesh( AllOpenStmSoup.GetSurf())) ;
|
||||
}
|
||||
if ( pStmBasic == nullptr)
|
||||
return nullptr ;
|
||||
BBox3d b3Stm = pStmBasic->GetAllTriaBox() ;
|
||||
if ( b3Stm.IsEmpty())
|
||||
return nullptr ;
|
||||
// numero di triangoli da analizzare
|
||||
int nTriaCnt = int( vAllTria.size()) ;
|
||||
// definisco un vettore di Flag per i triangoli già visitati
|
||||
INTVECTOR vIntFlags( pStmBasic->GetTriangleCount()) ;
|
||||
// numero massimo di thread concorrenti
|
||||
int nThreadMax = thread::hardware_concurrency() ;
|
||||
bool bOk = true ;
|
||||
BOOLVECTOR vbSafeTria( vAllTria.size(), true) ;
|
||||
if ( nThreadMax <= 1 || nTriaCnt < 50)
|
||||
ClassifyTrianglesMultiThread( vAllTria, 0, nTriaCnt - 1, *pStmBasic, abs( dOffs), dPrec, ( dOffs < 0.), vbSafeTria) ;
|
||||
else {
|
||||
const int MAX_PARTS = 32 ;
|
||||
INTINTVECTOR vFstLst( MAX_PARTS) ;
|
||||
// calcolo le parti del vettore
|
||||
int nPartCnt = min( nThreadMax, MAX_PARTS) ;
|
||||
int nPartDim = nTriaCnt / nPartCnt + 1 ;
|
||||
for ( int i = 0 ; i < nPartCnt ; ++ i) {
|
||||
vFstLst[i].first = i * nPartDim ;
|
||||
vFstLst[i].second = min( ( i + 1) * nPartDim, nTriaCnt) - 1 ;
|
||||
}
|
||||
// processo le parti
|
||||
future<bool> vRes[MAX_PARTS] ;
|
||||
for ( int i = 0 ; i < nPartCnt ; ++ i) {
|
||||
vRes[i] = async( launch::async, &ClassifyTrianglesMultiThread, cref( vAllTria), vFstLst[i].first,
|
||||
vFstLst[i].second, cref( *pStmBasic), abs( dOffs), dPrec, ( dOffs < 0.), ref( vbSafeTria)) ;
|
||||
}
|
||||
// attendo i risultati
|
||||
int nFin = 0 ;
|
||||
while ( nFin < nPartCnt) {
|
||||
for ( int i = 0 ; i < nPartCnt ; ++ i) {
|
||||
if ( vRes[i].valid() && vRes[i].wait_for( chrono::nanoseconds{ 1}) == future_status::ready) {
|
||||
bOk = vRes[i].get() && bOk ;
|
||||
++ nFin ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( ! bOk)
|
||||
return nullptr ;
|
||||
TRIA3DEXVECTOR vTriaSafe ; vTriaSafe.reserve( vAllTria.size()) ;
|
||||
#if DEBUG
|
||||
TRIA3DEXVECTOR vTriaUnSafe ; vTriaUnSafe.reserve( vAllTria.size()) ;
|
||||
#endif
|
||||
for ( int i = 0 ; i < int( vAllTria.size()) ; ++ i) {
|
||||
if ( vbSafeTria[i])
|
||||
vTriaSafe.emplace_back( vAllTria[i]) ;
|
||||
#if DEBUG
|
||||
if ( ! vbSafeTria[i])
|
||||
vTriaUnSafe.emplace_back( vAllTria[i]) ;
|
||||
#endif
|
||||
}
|
||||
|
||||
// definisco la superficie con i soli triangoli validi
|
||||
StmFromTriangleSoup TriaSoup ; TriaSoup.Start() ;
|
||||
for ( const Triangle3d& SafeTria : vTriaSafe)
|
||||
TriaSoup.AddTriangle( SafeTria) ;
|
||||
TriaSoup.End() ;
|
||||
PtrOwner<ISurfTriMesh> pStmOffs( TriaSoup.GetSurf()) ;
|
||||
if ( IsNull( pStmOffs) || ! pStmOffs->IsValid() || pStmOffs->GetTriangleCount() == 0)
|
||||
return nullptr ;
|
||||
|
||||
#if DEBUG
|
||||
StmFromTriangleSoup _invalidSoup ; _invalidSoup.Start() ;
|
||||
for ( const Triangle3d& _unsafeTria : vTriaUnSafe)
|
||||
_invalidSoup.AddTriangle( _unsafeTria) ;
|
||||
_invalidSoup.End() ;
|
||||
VT.emplace_back( pStmOffs->Clone()) ;
|
||||
VC.emplace_back( LIME) ;
|
||||
VT.emplace_back( _invalidSoup.GetSurf()) ;
|
||||
VC.emplace_back( RED) ;
|
||||
SaveGeoObj( VT, VC, "C:\\Temp\\TriangleSelection.nge") ;
|
||||
#endif
|
||||
|
||||
|
||||
// sistemo la topologia
|
||||
if ( ! pStm->AdjustTopologyFromZMap())
|
||||
return nullptr ;
|
||||
|
||||
return ( Release( pStm)) ;
|
||||
return ( Release( pStmOffs)) ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -240,3 +511,280 @@ CreateSurfTriMeshesThickeningOffset( const CISURFTMPVECTOR& vStm, double dOffs,
|
||||
// restituisco la superficie TriMesh
|
||||
return ( OneVolZmap.GetSurfTriMesh()) ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Funzione per creare la Superficie TriMesh Shell da una Trimesh aperta
|
||||
//----------------------------------------------------------------------------
|
||||
ISurfTriMesh*
|
||||
CreateSurfTriMeshShell( const ISurfTriMesh* pStm, double dThick, double dPrec)
|
||||
{
|
||||
// verifico che la superficie sia valida ed aperta
|
||||
if ( pStm == nullptr || ! pStm->IsValid() || pStm->IsClosed())
|
||||
return nullptr ;
|
||||
// lo spessore deve essere sempre positivo, il verso è sempre dato dalla normale dei triangoli
|
||||
dThick = - max( 10. * EPS_SMALL, abs( dThick)) ;
|
||||
|
||||
// creo il suo Offset ( salvandomi lo Zmap per l'orientamento)
|
||||
#if DEBUG
|
||||
PerformanceCounter PC ; PC.Start() ;
|
||||
#endif
|
||||
VolZmap myVolZMap ;
|
||||
if ( ! myVolZMap.CreateFromTriMeshOffset( { pStm}, dThick, dPrec))
|
||||
return nullptr ;
|
||||
if ( ! myVolZMap.IsValid())
|
||||
return nullptr ;
|
||||
#if DEBUG
|
||||
LOG_INFO( GetEGkLogger(), ( string{ "Tria Time : "} + ToString( PC.Stop())).c_str()) ;
|
||||
VT.clear() ; VC.clear() ;
|
||||
VT.emplace_back( myVolZMap.Clone()) ;
|
||||
VC.emplace_back( BLACK) ;
|
||||
VT.emplace_back( pStm->Clone()) ;
|
||||
VC.emplace_back( YELLOW) ;
|
||||
SaveGeoObj( VT, VC, "C:\\Temp\\VolZMapOffs.nge") ;
|
||||
#endif
|
||||
|
||||
#if DEBUG
|
||||
VT.clear() ; VC.clear() ;
|
||||
PC.Start() ;
|
||||
#endif
|
||||
|
||||
// recupero i triangoli dallo ZMap creato
|
||||
TRIA3DEXVECTOR vAllTria, vTriaOffs ;
|
||||
for ( int nB = 0 ; nB < myVolZMap.GetBlockCount() ; ++ nB) {
|
||||
TRIA3DEXVECTOR vTria, vTriaSafe ;
|
||||
myVolZMap.GetBlockTriangles( nB, vTria) ;
|
||||
#if DEBUG
|
||||
TRIA3DVECTOR vTriaUnsafe ;
|
||||
#endif
|
||||
for ( int nT = 0 ; nT < int( vTria.size()) ; ++ nT) {
|
||||
Triangle3dEx& Tria = vTria[nT] ;
|
||||
BBox3d BBoxTria ;
|
||||
Tria.GetLocalBBox( BBoxTria) ;
|
||||
// azzero flag di colore
|
||||
vAllTria.push_back( Tria) ;
|
||||
}
|
||||
}
|
||||
// classifico i triangoli
|
||||
const SurfTriMesh* pStmBasic = GetBasicSurfTriMesh( pStm) ;
|
||||
if ( pStmBasic == nullptr)
|
||||
return nullptr ;
|
||||
BBox3d b3Stm = pStmBasic->GetAllTriaBox() ;
|
||||
if ( b3Stm.IsEmpty())
|
||||
return nullptr ;
|
||||
// numero di triangoli da analizzare
|
||||
int nTriaCnt = int( vAllTria.size()) ;
|
||||
// definisco un vettore di Flag per i triangoli già visitati
|
||||
INTVECTOR vIntFlags( pStmBasic->GetTriangleCount()) ;
|
||||
// numero massimo di thread concorrenti
|
||||
int nThreadMax = thread::hardware_concurrency() ;
|
||||
bool bOk = true ;
|
||||
BOOLVECTOR vbSafeTria( vAllTria.size(), true) ;
|
||||
if ( nThreadMax <= 1 || nTriaCnt < 50)
|
||||
ClassifyTrianglesMultiThread( vAllTria, 0, nTriaCnt - 1, *pStmBasic, dThick, dPrec, true, vbSafeTria) ;
|
||||
else {
|
||||
const int MAX_PARTS = 32 ;
|
||||
INTINTVECTOR vFstLst( MAX_PARTS) ;
|
||||
// calcolo le parti del vettore
|
||||
int nPartCnt = min( nThreadMax, MAX_PARTS) ;
|
||||
int nPartDim = nTriaCnt / nPartCnt + 1 ;
|
||||
for ( int i = 0 ; i < nPartCnt ; ++ i) {
|
||||
vFstLst[i].first = i * nPartDim ;
|
||||
vFstLst[i].second = min( ( i + 1) * nPartDim, nTriaCnt) - 1 ;
|
||||
}
|
||||
// processo le parti
|
||||
future<bool> vRes[MAX_PARTS] ;
|
||||
for ( int i = 0 ; i < nPartCnt ; ++ i) {
|
||||
vRes[i] = async( launch::async, &ClassifyTrianglesMultiThread, cref( vAllTria), vFstLst[i].first,
|
||||
vFstLst[i].second, cref( *pStmBasic), dThick, dPrec, true, ref( vbSafeTria)) ;
|
||||
}
|
||||
// attendo i risultati
|
||||
int nFin = 0 ;
|
||||
while ( nFin < nPartCnt) {
|
||||
for ( int i = 0 ; i < nPartCnt ; ++ i) {
|
||||
if ( vRes[i].valid() && vRes[i].wait_for( chrono::nanoseconds{ 1}) == future_status::ready) {
|
||||
bOk = vRes[i].get() && bOk ;
|
||||
++ nFin ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( ! bOk)
|
||||
return nullptr ;
|
||||
TRIA3DEXVECTOR vTriaSafe ; vTriaSafe.reserve( vAllTria.size()) ;
|
||||
#if DEBUG
|
||||
TRIA3DEXVECTOR vTriaUnSafe ; vTriaUnSafe.reserve( vAllTria.size()) ;
|
||||
#endif
|
||||
for ( int i = 0 ; i < int( vAllTria.size()) ; ++ i) {
|
||||
if ( vbSafeTria[i])
|
||||
vTriaSafe.emplace_back( vAllTria[i]) ;
|
||||
#if DEBUG
|
||||
if ( ! vbSafeTria[i])
|
||||
vTriaUnSafe.emplace_back( vAllTria[i]) ;
|
||||
#endif
|
||||
}
|
||||
|
||||
// definisco la superficie con i soli triangoli validi
|
||||
StmFromTriangleSoup TriaSoup ; TriaSoup.Start() ;
|
||||
for ( const Triangle3d& SafeTria : vTriaSafe)
|
||||
TriaSoup.AddTriangle( SafeTria) ;
|
||||
TriaSoup.End() ;
|
||||
PtrOwner<ISurfTriMesh> pStmOffs( TriaSoup.GetSurf()) ;
|
||||
if ( IsNull( pStmOffs) || ! pStmOffs->IsValid() || pStmOffs->GetTriangleCount() == 0)
|
||||
return nullptr ;
|
||||
|
||||
#if DEBUG
|
||||
LOG_INFO( GetEGkLogger(), ( string{ "Tria Time ( exceed Approx) : "} + ToString( PC.Stop())).c_str()) ;
|
||||
StmFromTriangleSoup _invalidSoup ; _invalidSoup.Start() ;
|
||||
for ( const Triangle3d& _unsafeTria : vTriaUnSafe)
|
||||
_invalidSoup.AddTriangle( _unsafeTria) ;
|
||||
_invalidSoup.End() ;
|
||||
VT.emplace_back( pStmOffs->Clone()) ;
|
||||
VC.emplace_back( LIME) ;
|
||||
VT.emplace_back( _invalidSoup.GetSurf()) ;
|
||||
VC.emplace_back( RED) ;
|
||||
SaveGeoObj( VT, VC, "C:\\Temp\\TriangleSelection.nge") ;
|
||||
VT.clear() ; VC.clear() ;
|
||||
PC.Start() ;
|
||||
#endif
|
||||
|
||||
// recupero i loops della superficie originaria e del suo Offset orientato ( non devono essere diminuiti)
|
||||
POLYLINEVECTOR vPL, vPLOffs ;
|
||||
if ( ! pStm->GetLoops( vPL) || ! pStmOffs->GetLoops( vPLOffs))
|
||||
return nullptr ;
|
||||
|
||||
// trasformo ogni loop in curve composite ( devono essere chiuse)
|
||||
ICRVCOMPOPOVECTOR vCompoLoops ; vCompoLoops.reserve( vPL.size()) ;
|
||||
for ( const PolyLine& PL : vPL) {
|
||||
if ( PL.IsClosed()) {
|
||||
if ( ! vCompoLoops.emplace_back( CreateCurveComposite()) ||
|
||||
! vCompoLoops.back()->FromPolyLine( PL) ||
|
||||
! vCompoLoops.back()->IsValid())
|
||||
return nullptr ;
|
||||
}
|
||||
}
|
||||
ICRVCOMPOPOVECTOR vCompoOffsLoops ; vCompoOffsLoops.reserve( vPLOffs.size()) ;
|
||||
for ( const PolyLine& PLOffs : vPLOffs) {
|
||||
if ( PLOffs.IsClosed()) {
|
||||
if ( ! vCompoOffsLoops.emplace_back( CreateCurveComposite()) ||
|
||||
! vCompoOffsLoops.back()->FromPolyLine( PLOffs) ||
|
||||
! vCompoOffsLoops.back()->IsValid())
|
||||
return nullptr ;
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
VT.emplace_back( pStmOffs->Clone()) ;
|
||||
VC.emplace_back( YELLOW) ;
|
||||
for ( ICurveComposite* pCompo : vCompoLoops) {
|
||||
VT.emplace_back( pCompo->Clone()) ;
|
||||
VC.emplace_back( AQUA) ;
|
||||
}
|
||||
for ( ICurveComposite* pCompoOffs : vCompoOffsLoops) {
|
||||
VT.emplace_back( pCompoOffs->Clone()) ;
|
||||
VC.emplace_back( ORANGE) ;
|
||||
}
|
||||
SaveGeoObj( VT, VC, "C:\\Temp\\myCurve.nge") ;
|
||||
VT.clear() ; VC.clear() ;
|
||||
#endif
|
||||
|
||||
// per ogni curva della superficie originale cerco la sua associata
|
||||
// NB. per la creazione della superficie ruled la prima curva è quellla che determina il verso
|
||||
// dei triangoli associati. Per un corretto ed automatico orientamento della superficie
|
||||
// la prima curva deve essere sempre definita dalla superficie originale ed invertita ( le
|
||||
// curve nella rigata devono seguire lo stesso orientamento
|
||||
ISURFTMPOVECTOR vStmRuled ; vStmRuled.reserve( vCompoLoops.size()) ;
|
||||
BOOLVECTOR vIndMatched( vCompoOffsLoops.size(), false) ;
|
||||
for ( ICurveComposite* pCompoLoop : vCompoLoops) {
|
||||
// sposto il punto iniziale della curva nel tratto più lungo
|
||||
double dMaxLen = - INFINITO ;
|
||||
int nIndCrv = 0 ;
|
||||
for ( int nCrv = 0 ; nCrv < pCompoLoop->GetCurveCount() ; ++ nCrv) {
|
||||
const ICurve* pCurve = pCompoLoop->GetCurve( nCrv) ;
|
||||
if ( pCurve != nullptr && pCurve->IsValid()) {
|
||||
double dCurrLen = 0. ;
|
||||
pCurve->GetLength( dCurrLen) ;
|
||||
if ( dCurrLen > dMaxLen) {
|
||||
dMaxLen = dCurrLen ;
|
||||
nIndCrv = nCrv ;
|
||||
}
|
||||
}
|
||||
}
|
||||
pCompoLoop->ChangeStartPoint( nIndCrv + 0.5) ;
|
||||
Point3d ptStart ; pCompoLoop->GetStartPoint( ptStart) ;
|
||||
// dalle altre curve derivanti dalla superficie di Offset cerco quella più vicina al punto inziale
|
||||
double dMinSqDist = INFINITO ;
|
||||
int nIndOffsCrv = -1 ;
|
||||
Point3d ptMinDist ;
|
||||
for ( int nOffsCrv = 0 ; nOffsCrv < int( vCompoOffsLoops.size()) ; ++ nOffsCrv) {
|
||||
if ( vIndMatched[nOffsCrv])
|
||||
continue ;
|
||||
// recupero la curva e calcolo la distanza
|
||||
const ICurveComposite* pCompoOffsLoop = vCompoOffsLoops[nOffsCrv] ;
|
||||
int nFlag = 0 ;
|
||||
Point3d ptCurrMinDist ;
|
||||
if ( DistPointCurve( ptStart, *pCompoOffsLoop).GetMinDistPoint( 0., ptCurrMinDist, nFlag)) {
|
||||
double dCurrSqDist = SqDist( ptStart, ptCurrMinDist) ;
|
||||
if ( dCurrSqDist < dMinSqDist) {
|
||||
dMinSqDist = dCurrSqDist ;
|
||||
nIndOffsCrv = nOffsCrv ;
|
||||
ptMinDist = ptCurrMinDist ;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( nIndOffsCrv == -1)
|
||||
return nullptr ;
|
||||
// associo le due curve
|
||||
ICurveComposite* pCompoOffsLoop = vCompoOffsLoops[nIndOffsCrv] ;
|
||||
double dParMinDist = 0. ;
|
||||
pCompoOffsLoop->GetParamAtPoint( ptMinDist, dParMinDist, 10. * EPS_SMALL) ;
|
||||
pCompoOffsLoop->ChangeStartPoint( dParMinDist) ;
|
||||
|
||||
#if DEBUG
|
||||
Color _cCol = Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, 1.) ;
|
||||
VT.emplace_back( pCompoLoop->Clone()) ;
|
||||
VC.emplace_back( _cCol) ;
|
||||
VT.emplace_back( pCompoOffsLoop->Clone()) ;
|
||||
VC.emplace_back( _cCol) ;
|
||||
#endif
|
||||
|
||||
// creo la superficie tra queste due curve e la oriento in modo da definire un volume
|
||||
pCompoLoop->Invert() ;
|
||||
PtrOwner<ISurfTriMesh> pStmRuled( GetSurfTriMeshRuled( pCompoLoop, pCompoOffsLoop, ISurfTriMesh::RuledType::RLT_MINDIST)) ;
|
||||
if ( IsNull( pStmRuled) || ! pStmRuled->IsValid() ||
|
||||
! vStmRuled.emplace_back( Release( pStmRuled)))
|
||||
return nullptr ;
|
||||
|
||||
#if DEBUG
|
||||
LOG_INFO( GetEGkLogger(), ( string{ "Strip generation : "} + ToString( PC.Stop())).c_str()) ;
|
||||
VT.emplace_back( vStmRuled.back()->Clone()) ;
|
||||
VC.emplace_back( _cCol) ;
|
||||
_cCol.SetAlpha( .5) ;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
SaveGeoObj( VT, VC, "C:\\Temp\\Strips.nge") ;
|
||||
PC.Start() ;
|
||||
#endif
|
||||
|
||||
// compongo la superficie finale
|
||||
PtrOwner<ISurfTriMesh> pStmOrig( CloneSurfTriMesh( pStm)) ;
|
||||
if ( IsNull( pStmOrig) || ! pStmOrig->IsValid())
|
||||
return nullptr ;
|
||||
PtrOwner<ISurfTriMesh> pStmRef( Release( pStmOrig)) ;
|
||||
if ( IsNull( pStmRef) || ! pStmRef->IsValid())
|
||||
return nullptr ;
|
||||
for ( int nStrip = 0 ; nStrip < int( vStmRuled.size()) ; ++ nStrip) {
|
||||
if ( ! pStmRef->DoSewing( *vStmRuled[nStrip]))
|
||||
return nullptr ;
|
||||
}
|
||||
if ( ! pStmRef->DoSewing( *pStmOffs))
|
||||
return nullptr ;
|
||||
pStmRef->Repair() ;
|
||||
|
||||
#if DEBUG
|
||||
LOG_INFO( GetEGkLogger(), ( string{ "Sewing : "} + ToString( PC.Stop())).c_str()) ;
|
||||
#endif
|
||||
|
||||
return ( ( ! IsNull( pStmRef) && pStmRef->IsValid()) ? Release( pStmRef) : nullptr) ;
|
||||
}
|
||||
@@ -472,15 +472,18 @@ class VolZmap : public IVolZmap, public IGeoObjRW
|
||||
bool UpdateVolZMapBySurfThickeningSharpedOffset( const ISurfTriMesh* Surf, int nType, double dOffs, double dTol) ;
|
||||
bool CreateOffsetSphereOnVertex( const Point3d& ptV, double dOffs, int nGrid, int nVertexType = 0) ;
|
||||
bool CreateOffsetCylinderOnEdge( const Point3d& ptP1, const Point3d& ptP2, double dOffs, int nGrid, int nVertexType = 0) ;
|
||||
bool CreateFatOffsetExtrusionFace( const ISurfTriMesh* Surf, double dOffs, bool bThickle) ;
|
||||
bool CreateFatOffsetExtrusionFace( const ISurfTriMesh* Surf, double dOffs, bool bThickle, int nTool = 0) ;
|
||||
bool CreateOrientedOffsetExtrusionFace( const ISurfTriMesh* Surf, double dOffs) ;
|
||||
bool SubtractIntervalsForOffset( int nGrid, int nI, int nJ,
|
||||
double dMin, double dMax, const Vector3d& vtNMin, const Vector3d& vtNMax,
|
||||
int nToolNum, bool bSkipSwap = false) ;
|
||||
bool AddIntervalsForOffset( int nGrid, int nI, int nJ,
|
||||
double dMin, double dMax, const Vector3d& vtNMin, const Vector3d& vtNMax,
|
||||
int nToolNum, bool bSkipSwap = false) ;
|
||||
int nToolMin, int nToolMax, bool bSkipSwap = false) ;
|
||||
bool CutByPlaneForOffset( const Plane3d& plCut) ;
|
||||
bool AddSurfTmForOffset( const ISurfTriMesh* pStm, int nTool) ;
|
||||
bool AddMapPartForOffset( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, const Vector3d& vtLen, const Point3d& ptMapOrig,
|
||||
const ISurfTriMesh& Surf, int nTool, IntersParLinesSurfTm& intPLSTM) ;
|
||||
// Funzioni per Offset di Zmap
|
||||
bool OffsetFillet( double dOffs) ;
|
||||
bool OffsetSharped( double dOffs, int nType) ;
|
||||
|
||||
+747
-196
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user