Files
EgtGeomKernel/StmFromCurves.cpp
T
Dario Sassi 5bcd4bb67d EgtGeomKernel 1.8j4 :
- aggiunta classe Polygon3d (da EgtExchange)
- razionalizzata classe Plane3d
- corretta funzione IntersLineTria.
2017-10-16 07:56:04 +00:00

388 lines
15 KiB
C++

//----------------------------------------------------------------------------
// EgalTech 2015-2015
//----------------------------------------------------------------------------
// File : StmFromCurves.cpp Data : 01.02.15 Versione : 1.6b1
// Contenuto : Implementazione di funzioni per creazione di superfici Stm
// a partire da curve, con diversi metodi.
//
//
// Modifiche : 01.02.15 DS Creazione modulo.
//
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "GeoConst.h"
#include "/EgtDev/Include/EGkStmFromCurves.h"
#include "/EgtDev/Include/EgtPointerOwner.h"
#include <algorithm>
using namespace std ;
//-------------------------------------------------------------------------------
static bool CalcRegionPolyLines( const CICURVEPVECTOR& vpCurve, double dLinTol,
POLYLINEVECTOR& vPL, Vector3d& vtN) ;
//-------------------------------------------------------------------------------
ISurfTriMesh*
GetSurfTriMeshByFlatContour( const ICurve* pCurve, double dLinTol)
{
// verifica parametri
if ( pCurve == nullptr)
return nullptr ;
// calcolo la polilinea che approssima la curva
PolyLine PL ;
if ( ! pCurve->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL))
return nullptr ;
// creo e setto la superficie trimesh
PtrOwner<ISurfTriMesh> pSTM( CreateSurfTriMesh()) ;
if ( IsNull( pSTM) || ! pSTM->CreateByFlatContour( PL))
return nullptr ;
// salvo tolleranza lineare usata
pSTM->SetLinearTolerance( dLinTol) ;
// restituisco la superficie
return Release( pSTM) ;
}
//-------------------------------------------------------------------------------
ISurfTriMesh*
GetSurfTriMeshByRegion( const CICURVEPVECTOR& vpCurve, double dLinTol)
{
// verifica parametri
if ( &vpCurve == nullptr || vpCurve.empty())
return nullptr ;
// calcolo le polilinee che approssimano le curve della regione
POLYLINEVECTOR vPL ;
Vector3d vtN ;
if ( ! CalcRegionPolyLines( vpCurve, dLinTol, vPL, vtN))
return nullptr ;
// creo e setto la superficie trimesh
PtrOwner<ISurfTriMesh> pSTM( CreateSurfTriMesh()) ;
if ( IsNull( pSTM) || ! pSTM->CreateByRegion( vPL))
return nullptr ;
// salvo tolleranza lineare usata
pSTM->SetLinearTolerance( dLinTol) ;
// restituisco la superficie
return Release( pSTM) ;
}
//-------------------------------------------------------------------------------
ISurfTriMesh*
GetSurfTriMeshByExtrusion( const ICurve* pCurve, const Vector3d& vtExtr,
bool bCapEnds, double dLinTol)
{
// verifica parametri
if ( pCurve == nullptr || &vtExtr == nullptr)
return nullptr ;
// calcolo la polilinea che approssima la curva
PolyLine PL ;
if ( ! pCurve->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL))
return nullptr ;
// se richiesta chiusura agli estremi
bool bDoCapEnds = false ;
if ( bCapEnds) {
// verifico che la curva sia chiusa e piatta
Plane3d plPlane ;
double dArea ;
if ( PL.IsClosedAndFlat( plPlane, dArea, 50 * EPS_SMALL)) {
// componente dell'estrusione perpendicolare al piano della curva
double dOrthoExtr = plPlane.GetVersN() * vtExtr ;
if ( ( fabs( dOrthoExtr) > EPS_SMALL)) {
bDoCapEnds = true ;
// se negativa, inverto il senso del contorno
if ( dOrthoExtr < 0)
PL.Invert() ;
}
}
}
// creo e setto la superficie trimesh
PtrOwner<ISurfTriMesh> pSTM( CreateSurfTriMesh()) ;
if ( IsNull( pSTM) || ! pSTM->CreateByExtrusion( PL, vtExtr))
return nullptr ;
// se da fare, metto i tappi sulle estremità
if ( bDoCapEnds) {
// creo la prima superficie di estremità
PtrOwner<ISurfTriMesh> pSTM1( CreateSurfTriMesh()) ;
if ( IsNull( pSTM1) || ! pSTM1->CreateByFlatContour( PL))
return nullptr ;
// la copio
PtrOwner<ISurfTriMesh> pSTM2( pSTM1->Clone()) ;
if ( IsNull( pSTM2))
return nullptr ;
// inverto la prima superficie
pSTM1->Invert() ;
// traslo la seconda
pSTM2->Translate( vtExtr) ;
// le unisco alla superficie del fianco
if ( ! pSTM->DoSewing( *pSTM1) || ! pSTM->DoSewing( *pSTM2))
return nullptr ;
}
// salvo tolleranza lineare usata
pSTM->SetLinearTolerance( dLinTol) ;
// restituisco la superficie
return Release( pSTM) ;
}
//-------------------------------------------------------------------------------
ISurfTriMesh*
GetSurfTriMeshByRegionExtrusion( const CICURVEPVECTOR& vpCurve, const Vector3d& vtExtr, double dLinTol)
{
// verifica parametri
if ( &vpCurve == nullptr || vpCurve.empty() || &vtExtr == nullptr)
return nullptr ;
// se una sola curva, uso la funzione precedente
if ( vpCurve.size() == 1 )
return GetSurfTriMeshByExtrusion( vpCurve[0], vtExtr, true, dLinTol) ;
// calcolo le polilinee che approssimano le curve della regione
POLYLINEVECTOR vPL ;
Vector3d vtN ;
if ( ! CalcRegionPolyLines( vpCurve, dLinTol, vPL, vtN))
return nullptr ;
// verifico la direzione di estrusione
double dOrthoExtr = vtN * vtExtr ;
if ( ( fabs( dOrthoExtr) < EPS_SMALL))
return nullptr ;
// se componente estrusione negativa, inverto tutti i percorsi
if ( dOrthoExtr < 0) {
for ( int i = 0 ; i < int( vPL.size()) ; ++ i)
vPL[i].Invert() ;
}
// creo la prima superficie di estremità
PtrOwner<ISurfTriMesh> pSTM( CreateSurfTriMesh()) ;
if ( IsNull( pSTM) || ! pSTM->CreateByRegion( vPL))
return nullptr ;
// creo la seconda superficie e la unisco alla prima
{ // copio la prima superficie
PtrOwner<ISurfTriMesh> pSTM2( pSTM->Clone()) ;
if ( IsNull( pSTM2))
return nullptr ;
// inverto la prima superficie
pSTM->Invert() ;
// traslo la seconda
pSTM2->Translate( vtExtr) ;
// la unisco alla prima
if ( ! pSTM->DoSewing( *pSTM2))
return nullptr ;
}
// creo e unisco le diverse superfici di estrusione
for ( int i = 0 ; i < int( vPL.size()) ; ++ i) {
// estrusione
PtrOwner<ISurfTriMesh> pSTM2( CreateSurfTriMesh()) ;
if ( IsNull( pSTM2) || ! pSTM2->CreateByExtrusion( vPL[i], vtExtr))
return nullptr ;
// la unisco alla superficie principale
if ( ! pSTM->DoSewing( *pSTM2))
return nullptr ;
}
// compatto la superficie
if ( ! pSTM->DoCompacting())
return nullptr ;
// salvo tolleranza lineare usata
pSTM->SetLinearTolerance( dLinTol) ;
// restituisco la superficie
return Release( pSTM) ;
}
//-------------------------------------------------------------------------------
ISurfTriMesh*
GetSurfTriMeshByRevolve( const ICurve* pCurve, const Point3d& ptAx, const Vector3d& vtAx,
bool bCapEnds, double dLinTol)
{
// verifica parametri
if ( pCurve == nullptr || &ptAx == nullptr || &vtAx == nullptr)
return nullptr ;
// limite minimo su tolleranza
dLinTol = max( dLinTol, EPS_SMALL) ;
// calcolo la polilinea che approssima la curva
PolyLine PL ;
if ( ! pCurve->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL))
return nullptr ;
// calcolo lo step di rotazione
double dMaxRad = 0 ;
if ( ! PL.GetMaxDistanceFromLine( ptAx, vtAx, 1, dMaxRad, false) || dMaxRad < EPS_SMALL)
return nullptr ;
double dStepRotDeg = sqrt( 8 * dLinTol / dMaxRad) * RADTODEG ;
// se richiesta chiusura degli estremi
if ( bCapEnds && ! PL.IsClosed()) {
Vector3d vtAxN = vtAx ;
vtAxN.Normalize() ;
double dPosIni, dPosFin ;
Point3d ptP ;
// proietto l'ultimo punto sull'asse di rotazione
if ( PL.GetLastPoint( ptP)) {
dPosFin = ( ptP - ptAx) * vtAxN ;
Point3d ptPOnAx = ptAx + dPosFin * vtAxN ;
// se non giace sull'asse, aggiungo il punto proiettato
if ( ! AreSamePointApprox( ptP, ptPOnAx)) {
double dU ;
PL.GetLastU( dU) ;
PL.AddUPoint( ( dU + 1), ptPOnAx) ;
}
}
// inverto la polilinea
PL.Invert() ;
// proietto l'ultimo punto (era il primo) sull'asse di rotazione
if ( PL.GetLastPoint( ptP)) {
dPosIni = ( ptP - ptAx) * vtAxN ;
Point3d ptPOnAx = ptAx + dPosIni * vtAxN ;
// se non giace sull'asse, aggiungo il punto proiettato
if ( ! AreSamePointApprox( ptP, ptPOnAx)) {
double dU ;
PL.GetLastU( dU) ;
PL.AddUPoint( ( dU + 1), ptPOnAx) ;
}
}
// decido se reinvertire la polilinea
if ( dPosFin > dPosIni)
PL.Invert() ;
}
// creo e setto la superficie trimesh
PtrOwner<ISurfTriMesh> pSTM( CreateSurfTriMesh()) ;
if ( IsNull( pSTM) || ! pSTM->CreateByScrewing( PL, ptAx, vtAx, ANG_FULL, dStepRotDeg, 0))
return nullptr ;
// salvo tolleranza lineare usata
pSTM->SetLinearTolerance( dLinTol) ;
// restituisco la superficie
return Release( pSTM) ;
}
//-------------------------------------------------------------------------------
ISurfTriMesh*
GetSurfTriMeshByScrewing( const ICurve* pCurve, const Point3d& ptAx, const Vector3d& vtAx,
double dAngRotDeg, double dMove, double dLinTol)
{
// verifica parametri
if ( pCurve == nullptr || &ptAx == nullptr || &vtAx == nullptr)
return nullptr ;
// limite minimo su tolleranza
dLinTol = max( dLinTol, EPS_SMALL) ;
// calcolo la polilinea che approssima la curva
PolyLine PL ;
if ( ! pCurve->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL))
return nullptr ;
// calcolo lo step di rotazione
double dMaxRad = 0 ;
if ( ! PL.GetMaxDistanceFromLine( ptAx, vtAx, 1, dMaxRad, false) || dMaxRad < EPS_SMALL)
return nullptr ;
double dStepRotDeg = sqrt( 8 * dLinTol / dMaxRad) * RADTODEG ;
// se superficie rototraslata, necessari limiti sulla lunghezza dei segmenti
if ( fabs( dAngRotDeg) > EPS_ANG_SMALL && fabs( dMove) > EPS_SMALL){
double dLenMax = 2.5 * fabs( dMove * dStepRotDeg / dAngRotDeg) ;
if ( ! PL.AdjustForMaxSegmentLen( dLenMax))
return nullptr ;
}
// creo e setto la superficie trimesh
PtrOwner<ISurfTriMesh> pSTM( CreateSurfTriMesh()) ;
if ( IsNull( pSTM) || ! pSTM->CreateByScrewing( PL, ptAx, vtAx, dAngRotDeg, dStepRotDeg, dMove))
return nullptr ;
// salvo tolleranza lineare usata
pSTM->SetLinearTolerance( dLinTol) ;
// restituisco la superficie
return Release( pSTM) ;
}
//-------------------------------------------------------------------------------
ISurfTriMesh*
GetSurfTriMeshRuled( const Point3d& ptP, const ICurve* pCurve, double dLinTol)
{
// verifica parametri
if ( &ptP == nullptr || pCurve == nullptr)
return nullptr ;
// calcolo la polilinea che approssima la curva
PolyLine PL ;
if ( ! pCurve->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL))
return nullptr ;
// creo e setto la superficie trimesh
PtrOwner<ISurfTriMesh> pSTM( CreateSurfTriMesh()) ;
if ( IsNull( pSTM) || ! pSTM->CreateByPointCurve( ptP, PL))
return nullptr ;
// salvo tolleranza lineare usata
pSTM->SetLinearTolerance( dLinTol) ;
// restituisco la superficie
return Release( pSTM) ;
}
//-------------------------------------------------------------------------------
ISurfTriMesh*
GetSurfTriMeshRuled( const ICurve* pCurve1, const ICurve* pCurve2, double dLinTol)
{
// verifica parametri
if ( pCurve1 == nullptr || pCurve2 == nullptr)
return nullptr ;
// calcolo la polilinea che approssima la prima curva
PolyLine PL1 ;
if ( ! pCurve1->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL1))
return nullptr ;
// calcolo la polilinea che approssima la seconda curva
PolyLine PL2 ;
if ( ! pCurve2->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL2))
return nullptr ;
// creo e setto la superficie trimesh
PtrOwner<ISurfTriMesh> pSTM( CreateSurfTriMesh()) ;
if ( IsNull( pSTM) || ! pSTM->CreateByTwoCurves( PL1, PL2))
return nullptr ;
// salvo tolleranza lineare usata
pSTM->SetLinearTolerance( dLinTol) ;
// restituisco la superficie
return Release( pSTM) ;
}
//-------------------------------------------------------------------------------
bool
CalcRegionPolyLines( const CICURVEPVECTOR& vpCurve, double dLinTol,
POLYLINEVECTOR& vPL, Vector3d& vtN)
{
// calcolo le polilinee che approssimano le curve
POLYLINEVECTOR vPLtmp ;
vPLtmp.resize( vpCurve.size()) ;
for ( int i = 0 ; i < int( vpCurve.size()) ; ++ i) {
if ( ! vpCurve[i]->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, vPLtmp[i]))
return nullptr ;
}
// ne calcolo l'area e genero un ordine in senso decrescente
typedef pair<int,double> INDAREA ; // coppia indice, area
typedef vector<INDAREA> INDAREAVECTOR ; // vettore di coppie indice, area
INDAREAVECTOR vArea ;
vArea.reserve( vPLtmp.size()) ;
Vector3d vtN0 ;
for ( int i = 0 ; i < int( vPLtmp.size()) ; ++ i) {
// verifico chiusura, calcolo piano medio e area
Plane3d plPlane ;
double dArea ;
if ( ! vPLtmp[i].IsClosedAndFlat( plPlane, dArea, 50 * EPS_SMALL))
return false ;
// imposto la normale del primo contorno come riferimento
if ( i == 0)
vtN0 = plPlane.GetVersN() ;
// verifico che le normali siano molto vicine
if ( ! AreSameOrOppositeVectorApprox( plPlane.GetVersN(), vtN0))
return false ;
// assegno il segno all'area secondo il verso della normale
if ( ( plPlane.GetVersN() * vtN0) > 0)
vArea.emplace_back( i, dArea) ;
else
vArea.emplace_back( i, - dArea) ;
}
sort( vArea.begin(), vArea.end(),
[]( const INDAREA& a, const INDAREA& b) { return ( fabs( a.second) > fabs( b.second)) ; }) ;
// sposto le polilinee nel vettore da restituire secondo l'ordine
vPL.clear() ;
vPL.resize( vPLtmp.size()) ;
bool bCCW = true ;
for ( int i = 0 ; i < int( vPLtmp.size()) ; ++ i) {
// scambio
swap( vPL[i], vPLtmp[vArea[i].first]) ;
// verifico senso di rotazione del contorno esterno
if ( i == 0)
bCCW = ( vArea[i].second > 0) ;
// aggiusto gli altri contorni
else {
if ( ( bCCW && vArea[i].second > 0) || ( ! bCCW && vArea[i].second < 0))
vPL[i].Invert() ;
}
}
// restituisco la normale positiva alla regione
vtN = ( bCCW ? vtN0 : - vtN0) ;
return true ;
}