3f1f365451
- migliorie e irrobustimenti a calcolo silhouette di trimesh con collisio avoid.
367 lines
13 KiB
C++
367 lines
13 KiB
C++
//----------------------------------------------------------------------------
|
|
// EgalTech 2024-2024
|
|
//----------------------------------------------------------------------------
|
|
// File : CAvSilhouetteSurfTm.cpp Data : 08.06.24 Versione : 2.6f2
|
|
// Contenuto : Implementazione della funzione CAvSilhouetteSurfTm.
|
|
//
|
|
//
|
|
//
|
|
// Modifiche : 08.06.24 DS Creazione modulo.
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "stdafx.h"
|
|
#include "CAvToolSurfTm.h"
|
|
#include "GeoConst.h"
|
|
#include "/EgtDev/Include/EGkCAvSilhouetteSurfTm.h"
|
|
#include "/EgtDev/Include/EGkChainCurves.h"
|
|
#include "/EgtDev/Include/EGkOffsetCurve.h"
|
|
|
|
using namespace std ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Funzioni locali per calcolo isolinee con metodo Marching Squares
|
|
//----------------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Quadrato (C=corner E=edge) :
|
|
//
|
|
// C3 - E2 - C2
|
|
// | |
|
|
// E3 E1
|
|
// | |
|
|
// C0 - E0 - C1
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------------
|
|
static Point3d
|
|
CalcPoint( const Point3d& ptS, const Point3d& ptE, double dLevel)
|
|
{
|
|
return Media( ptS, ptE, ( ptS.z - dLevel) / ( ptS.z - ptE.z)) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
static int
|
|
ProcessSquare( int nFlag, const Point3d ptP[4], double dLevel,
|
|
Point3d& ptL1s, Point3d& ptL1e, Point3d& ptL2s, Point3d& ptL2e)
|
|
{
|
|
static int LineTable[16][5] = { { 0, -1, -1, -1, -1},
|
|
{ 1, 0, 3, -1, -1},
|
|
{ 1, 1, 0, -1, -1},
|
|
{ 1, 1, 3, -1, -1},
|
|
{ 1, 2, 1, -1, -1},
|
|
{ 2, 0, 1, 2, 3},
|
|
{ 1, 2, 0, -1, -1},
|
|
{ 1, 2, 3, -1, -1},
|
|
{ 1, 3, 2, -1, -1},
|
|
{ 1, 0, 2, -1, -1},
|
|
{ 2, 1, 2, 3, 0},
|
|
{ 1, 1, 2, -1, -1},
|
|
{ 1, 3, 1, -1, -1},
|
|
{ 1, 0, 1, -1, -1},
|
|
{ 1, 3, 0, -1, -1},
|
|
{ 0, -1, -1, -1, -1}} ;
|
|
// flag fuori dai limiti
|
|
if ( nFlag < 0 || nFlag > 15)
|
|
return -1 ;
|
|
// nessuna linea
|
|
if ( LineTable[nFlag][0] == 0)
|
|
return 0 ;
|
|
// una linea
|
|
else if ( LineTable[nFlag][0] == 1) {
|
|
int nI1s = LineTable[nFlag][1] ;
|
|
int nI1e = LineTable[nFlag][2] ;
|
|
ptL1s = CalcPoint( ptP[nI1s], ptP[( nI1s + 1) % 4], dLevel) ;
|
|
ptL1e = CalcPoint( ptP[nI1e], ptP[( nI1e + 1) % 4], dLevel) ;
|
|
return ( AreSamePointApprox( ptL1s, ptL1e) ? 0 : 1) ;
|
|
}
|
|
// due linee
|
|
else if ( LineTable[nFlag][0] == 2) {
|
|
int nI1s = LineTable[nFlag][1] ;
|
|
int nI1e = LineTable[nFlag][2] ;
|
|
ptL1s = CalcPoint( ptP[nI1s], ptP[( nI1s + 1) % 4], dLevel) ;
|
|
ptL1e = CalcPoint( ptP[nI1e], ptP[( nI1e + 1) % 4], dLevel) ;
|
|
int nI2s = LineTable[nFlag][3] ;
|
|
int nI2e = LineTable[nFlag][4] ;
|
|
ptL2s = CalcPoint( ptP[nI2s], ptP[( nI2s + 1) % 4], dLevel) ;
|
|
ptL2e = CalcPoint( ptP[nI2e], ptP[( nI2e + 1) % 4], dLevel) ;
|
|
return 2 ;
|
|
}
|
|
return -1 ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
static bool
|
|
MarchingSquares( const DBLVECTOR& vdGrid, int nStepX, int nStepY, double dStep, double dLevel, POLYLINEVECTOR& vPL)
|
|
{
|
|
// Predispongo il concatenamento
|
|
BIPNTVECTOR vBiPnt ;
|
|
vBiPnt.reserve( 2 * ( nStepX + nStepY)) ;
|
|
ChainCurves chainC ;
|
|
chainC.Init( false, EPS_SMALL, 2 * ( nStepX + nStepY)) ;
|
|
// Ciclo sui quadrati della griglia
|
|
for ( int j = 0 ; j < nStepY ; ++ j) {
|
|
for ( int i = 0 ; i < nStepX ; ++ i) {
|
|
// indici dei vertici nella griglia
|
|
int nInd0 = i + j * ( nStepX + 1) ;
|
|
int nInd1 = ( i + 1) + j * ( nStepX + 1) ;
|
|
int nInd2 = ( i + 1) + ( j + 1) * ( nStepX + 1) ;
|
|
int nInd3 = i + ( j + 1) * ( nStepX + 1) ;
|
|
// flag del quadrato
|
|
int nFlag = ( vdGrid[nInd0] > dLevel - EPS_SMALL ? 1 : 0) +
|
|
( vdGrid[nInd1] > dLevel - EPS_SMALL ? 2 : 0) +
|
|
( vdGrid[nInd2] > dLevel - EPS_SMALL ? 4 : 0) +
|
|
( vdGrid[nInd3] > dLevel - EPS_SMALL ? 8 : 0) ;
|
|
// punti di vertice del quadrato
|
|
Point3d ptP[4] = { { i * dStep, j * dStep, vdGrid[nInd0]},
|
|
{ ( i + 1) * dStep, j * dStep, vdGrid[nInd1]},
|
|
{ ( i + 1) * dStep, ( j + 1) * dStep, vdGrid[nInd2]},
|
|
{ i * dStep, ( j + 1) * dStep, vdGrid[nInd3]}} ;
|
|
// calcolo segmenti da inserire
|
|
Point3d ptL1s, ptL1e, ptL2s, ptL2e ;
|
|
int nSegCnt = ProcessSquare( nFlag, ptP, dLevel, ptL1s, ptL1e, ptL2s, ptL2e) ;
|
|
if ( nSegCnt == -1)
|
|
return false ;
|
|
else if ( nSegCnt == 1) {
|
|
vBiPnt.emplace_back( ptL1s, ptL1e) ;
|
|
Vector3d vtDir1 = ptL1e - ptL1s ; vtDir1.Normalize() ;
|
|
chainC.AddCurve( int( vBiPnt.size()), ptL1s, vtDir1, ptL1e, vtDir1) ;
|
|
}
|
|
else if ( nSegCnt == 2) {
|
|
vBiPnt.emplace_back( ptL1s, ptL1e) ;
|
|
Vector3d vtDir1 = ptL1e - ptL1s ; vtDir1.Normalize() ;
|
|
chainC.AddCurve( int( vBiPnt.size()), ptL1s, vtDir1, ptL1e, vtDir1) ;
|
|
vBiPnt.emplace_back( ptL2s, ptL2e) ;
|
|
Vector3d vtDir2 = ptL2e - ptL2s ; vtDir2.Normalize() ;
|
|
chainC.AddCurve( int( vBiPnt.size()), ptL2s, vtDir2, ptL2e, vtDir2) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Recupero i contorni
|
|
const double MIN_LEN = 0.2 ;
|
|
INTVECTOR vnId ;
|
|
while ( chainC.GetChainFromNear( ORIG, false, vnId)) {
|
|
// creo una composita
|
|
CurveComposite crvCompo ;
|
|
Point3d ptPrev = vBiPnt[vnId[0]-1].first ;
|
|
crvCompo.AddPoint( ptPrev) ;
|
|
for ( int i = 0 ; i < int( vnId.size()) ; ++ i) {
|
|
Point3d ptCurr = vBiPnt[vnId[i]-1].second ;
|
|
// per evitare difetti a Z con entità corte
|
|
if ( SqDist( ptPrev, ptCurr) > MIN_LEN * MIN_LEN) {
|
|
crvCompo.AddLine( ptCurr) ;
|
|
ptPrev = ptCurr ;
|
|
}
|
|
}
|
|
// la chiudo
|
|
crvCompo.Close() ;
|
|
// elimino le parti allineate
|
|
crvCompo.MergeCurves( 10 * EPS_SMALL, ANG_TOL_STD_DEG) ;
|
|
// per test mettere a 1
|
|
#if 0
|
|
vPL.emplace_back( PolyLine()) ;
|
|
crvCompo.ApproxWithLines( 0, 0, ICurve::APL_SPECIAL, vPL.back()) ;
|
|
#else
|
|
// eseguo offset a sinistra pari allo step
|
|
OffsetCurve offsCompo ;
|
|
offsCompo.Make( &crvCompo, -0.5 * dStep, ICurve::OFF_CHAMFER) ;
|
|
PtrOwner<ICurve> pCrvOffset( offsCompo.GetLongerCurve()) ;
|
|
if ( ! IsNull( pCrvOffset)) {
|
|
vPL.emplace_back( PolyLine()) ;
|
|
pCrvOffset->ApproxWithLines( 0.5 * dStep, ANG_TOL_APPROX_DEG, ICurve::APL_STD, vPL.back()) ;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Silhouette rispetto ad una direzione e sopra una quota di una superficie TriMesh
|
|
// ( dTol è il passo della griglia di campionamento e il raggio del cilindro di prova)
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CAvSilhouetteSurfTm( const ISurfTriMesh& Stm, const Plane3d& plPlane, double dTol, POLYLINEVECTOR& vPL)
|
|
{
|
|
// verifico superficie
|
|
if ( &Stm == nullptr || ! Stm.IsValid())
|
|
return false ;
|
|
// verifico piano
|
|
if ( &plPlane == nullptr || plPlane.GetVersN().IsSmall())
|
|
return false ;
|
|
// verifico tolleranza
|
|
dTol = max( dTol, 100 * EPS_SMALL) ;
|
|
// verifico parametri di ritorno
|
|
if ( &vPL == nullptr)
|
|
return false ;
|
|
vPL.clear() ;
|
|
|
|
// sistema di riferimento nel piano
|
|
Frame3d frPlane ;
|
|
if ( ! frPlane.Set( plPlane.GetPoint(), plPlane.GetVersN()))
|
|
return false ;
|
|
|
|
// bounding box della superficie nel riferimento del piano
|
|
BBox3d b3Surf ;
|
|
if ( ! Stm.GetBBox( GetInvert( frPlane), b3Surf, BBF_STANDARD))
|
|
return false ;
|
|
// calcolo dati della griglia
|
|
const double EXTRA_XY = 1.5 * dTol ;
|
|
const double EXTRA_Z = 10 ;
|
|
b3Surf.Expand( EXTRA_XY, EXTRA_XY, EXTRA_Z) ;
|
|
Point3d ptOrig = GetToGlob( b3Surf.GetMin(), frPlane) ;
|
|
Vector3d vtAxX = frPlane.VersX() ;
|
|
Vector3d vtAxY = frPlane.VersY() ;
|
|
Vector3d vtAxZ = frPlane.VersZ() ;
|
|
int nStepX = int( ceil( b3Surf.GetDimX() / dTol)) ;
|
|
int nStepY = int( ceil( b3Surf.GetDimY() / dTol)) ;
|
|
double dDimZ = b3Surf.GetDimZ() ;
|
|
|
|
// calcolo dei punti della griglia (sul top del cilindro)
|
|
PNTUVECTOR vPntM( ( nStepX + 1) * ( nStepY + 1)) ;
|
|
for ( int j = 0 ; j <= nStepY ; ++ j) {
|
|
for ( int i = 0 ; i <= nStepX ; ++ i) {
|
|
int nInd = i + j * ( nStepX + 1) ;
|
|
Point3d ptP = ptOrig + i * dTol * vtAxX + j * dTol * vtAxY + dDimZ * vtAxZ ;
|
|
vPntM[nInd] = { ptP, 0.} ;
|
|
}
|
|
}
|
|
|
|
// esecuzione della verifica
|
|
CAvToolSurfTm cavTstm ;
|
|
cavTstm.SetStdTool( dDimZ, dTol, 0) ;
|
|
cavTstm.SetSurfTm( Stm) ;
|
|
if ( ! cavTstm.TestSeries( vPntM, vtAxZ, vtAxZ, -1))
|
|
return false ;
|
|
|
|
// riporto i punti sul tip del cilindro
|
|
for ( auto& PntU : vPntM)
|
|
PntU.first -= dDimZ * vtAxZ ;
|
|
|
|
// griglia degli spostamenti
|
|
DBLVECTOR vdGrid( ( nStepX + 1) * ( nStepY + 1)) ;
|
|
for ( int j = 0 ; j <= nStepY ; ++ j) {
|
|
for ( int i = 0 ; i <= nStepX ; ++ i) {
|
|
int nInd = i + j * ( nStepX + 1) ;
|
|
vdGrid[nInd] = -vPntM[nInd].second ;
|
|
}
|
|
}
|
|
|
|
// calcolo della silhouette con il metodo MarchingSquares
|
|
double dLevel = -b3Surf.GetMin().z ;
|
|
if ( ! MarchingSquares( vdGrid, nStepX, nStepY, dTol, dLevel, vPL))
|
|
return false ;
|
|
// riporto nella corretta posizione le curve trovate
|
|
for ( auto& PL : vPL) {
|
|
PL.Translate( b3Surf.GetMin() - ORIG) ;
|
|
PL.ToGlob( frPlane) ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Silhouette rispetto ad una direzione e sopra diverse quote di una superficie TriMesh
|
|
//----------------------------------------------------------------------------
|
|
CAvParSilhouettesSurfTm::CAvParSilhouettesSurfTm( const CISURFTMPVECTOR& vpStm, const Frame3d& frPlanes, double dTol)
|
|
{
|
|
m_vpStm = vpStm ;
|
|
m_frPlanes = frPlanes ;
|
|
m_dTol = max( dTol, 100 * EPS_SMALL) ;
|
|
m_nStepX = 0 ;
|
|
m_nStepY = 0 ;
|
|
m_bGridOk = false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CAvParSilhouettesSurfTm::Prepare( void)
|
|
{
|
|
// ingombro delle superfici nel riferimento dei piani
|
|
BBox3d b3All ;
|
|
Frame3d frInv = GetInvert( m_frPlanes) ;
|
|
for ( auto pStm : m_vpStm) {
|
|
BBox3d b3Surf ;
|
|
if ( ! pStm->GetBBox( frInv, b3Surf, BBF_STANDARD))
|
|
return false ;
|
|
b3All.Add( b3Surf) ;
|
|
}
|
|
|
|
// calcolo dati della griglia
|
|
const double EXTRA_XY = 1.5 * m_dTol ;
|
|
const double EXTRA_Z = 10 ;
|
|
b3All.Expand( EXTRA_XY, EXTRA_XY, EXTRA_Z) ;
|
|
Point3d ptOrig = GetToGlob( b3All.GetMin(), m_frPlanes) ;
|
|
Vector3d vtAxX = m_frPlanes.VersX() ;
|
|
Vector3d vtAxY = m_frPlanes.VersY() ;
|
|
Vector3d vtAxZ = m_frPlanes.VersZ() ;
|
|
m_nStepX = int( ceil( b3All.GetDimX() / m_dTol)) ;
|
|
m_nStepY = int( ceil( b3All.GetDimY() / m_dTol)) ;
|
|
m_vtMove = b3All.GetMin() - ORIG ;
|
|
double dDimZ = b3All.GetDimZ() ;
|
|
|
|
// calcolo dei punti della griglia (sul top del cilindro)
|
|
PNTUVECTOR vPntM( ( m_nStepX + 1) * ( m_nStepY + 1)) ;
|
|
for ( int j = 0 ; j <= m_nStepY ; ++ j) {
|
|
for ( int i = 0 ; i <= m_nStepX ; ++ i) {
|
|
int nInd = i + j * ( m_nStepX + 1) ;
|
|
Point3d ptP = ptOrig + i * m_dTol * vtAxX + j * m_dTol * vtAxY + dDimZ * vtAxZ ;
|
|
vPntM[nInd] = { ptP, 0.} ;
|
|
}
|
|
}
|
|
|
|
// esecuzione della verifica
|
|
CAvToolSurfTm cavTstm ;
|
|
if ( ! cavTstm.SetStdTool( dDimZ, m_dTol, 0))
|
|
return false ;
|
|
if ( m_vpStm.empty() || ! cavTstm.SetSurfTm( *( m_vpStm[0])))
|
|
return false ;
|
|
for ( int k = 1 ; k < int( m_vpStm.size()) ; ++ k)
|
|
cavTstm.AddSurfTm( *( m_vpStm[k])) ;
|
|
if ( ! cavTstm.TestSeries( vPntM, vtAxZ, vtAxZ, -1))
|
|
return false ;
|
|
|
|
// riporto i punti sul tip del cilindro
|
|
for ( auto& PntU : vPntM)
|
|
PntU.first -= dDimZ * vtAxZ ;
|
|
|
|
// griglia degli spostamenti
|
|
m_vdGrid.clear() ;
|
|
m_vdGrid.resize( ( m_nStepX + 1) * ( m_nStepY + 1)) ;
|
|
for ( int j = 0 ; j <= m_nStepY ; ++ j) {
|
|
for ( int i = 0 ; i <= m_nStepX ; ++ i) {
|
|
int nInd = i + j * ( m_nStepX + 1) ;
|
|
m_vdGrid[nInd] = -vPntM[nInd].second ;
|
|
}
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
CAvParSilhouettesSurfTm::GetSilhouette( double dLevel, POLYLINEVECTOR& vPL)
|
|
{
|
|
// reset risultato
|
|
vPL.clear() ;
|
|
|
|
// se necessario eseguo i calcoli preparatori
|
|
if ( ! m_bGridOk && ! Prepare())
|
|
return false ;
|
|
m_bGridOk = true ;
|
|
|
|
// calcolo della silhouette con il metodo MarchingSquares
|
|
dLevel -= m_vtMove.z ;
|
|
if ( ! MarchingSquares( m_vdGrid, m_nStepX, m_nStepY, m_dTol, dLevel, vPL))
|
|
return false ;
|
|
// riporto nella corretta posizione le curve trovate
|
|
for ( auto& PL : vPL) {
|
|
PL.Translate( m_vtMove) ;
|
|
PL.ToGlob( m_frPlanes) ;
|
|
}
|
|
return true ;
|
|
}
|