104726c5ee
- migliorie varie.
1342 lines
53 KiB
C++
1342 lines
53 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 "CurveLine.h"
|
|
#include "CurveArc.h"
|
|
#include "CurveComposite.h"
|
|
#include "SurfTriMesh.h"
|
|
#include "Voronoi.h"
|
|
#include "RotationMinimizeFrame.h"
|
|
#include "/EgtDev/Include/EGkOffsetCurve.h"
|
|
#include "/EgtDev/Include/EGkStmFromCurves.h"
|
|
#include "/EgtDev/Include/EGkStmFromTriangleSoup.h"
|
|
#include "/EgtDev/Include/EgtPointerOwner.h"
|
|
#include "/EgtDev/Include/EGkSfrCreate.h"
|
|
#include <algorithm>
|
|
#include <thread>
|
|
#include <future>
|
|
#include <EgtDev/Include/EGkIntersCurves.h>
|
|
|
|
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<SurfTriMesh> pSTM( CreateBasicSurfTriMesh()) ;
|
|
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<SurfTriMesh> pSTM( CreateBasicSurfTriMesh()) ;
|
|
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 ( ( abs( dOrthoExtr) > EPS_SMALL)) {
|
|
bDoCapEnds = true ;
|
|
// se negativa, inverto il senso del contorno
|
|
if ( dOrthoExtr < 0)
|
|
PL.Invert() ;
|
|
}
|
|
}
|
|
}
|
|
// creo e setto la superficie trimesh
|
|
PtrOwner<SurfTriMesh> pSTM( CreateBasicSurfTriMesh()) ;
|
|
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à
|
|
SurfTriMesh STM1 ;
|
|
if ( ! STM1.CreateByFlatContour( PL))
|
|
return nullptr ;
|
|
// la copio
|
|
SurfTriMesh STM2 = STM1 ;
|
|
// inverto la prima superficie
|
|
STM1.Invert() ;
|
|
// traslo la seconda
|
|
STM2.Translate( vtExtr) ;
|
|
// le unisco alla superficie del fianco
|
|
if ( ! pSTM->DoSewing( STM1) || ! pSTM->DoSewing( STM2))
|
|
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 ( ( abs( 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<SurfTriMesh> pSTM( CreateBasicSurfTriMesh()) ;
|
|
if ( IsNull( pSTM) || ! pSTM->CreateByRegion( vPL))
|
|
return nullptr ;
|
|
// creo la seconda superficie e la unisco alla prima
|
|
{ // copio la prima superficie
|
|
SurfTriMesh STM2 = *pSTM ;
|
|
// inverto la prima superficie
|
|
pSTM->Invert() ;
|
|
// traslo la seconda
|
|
STM2.Translate( vtExtr) ;
|
|
// la unisco alla prima
|
|
if ( ! pSTM->DoSewing( STM2))
|
|
return nullptr ;
|
|
}
|
|
// creo e unisco le diverse superfici di estrusione
|
|
for ( int i = 0 ; i < int( vPL.size()) ; ++ i) {
|
|
// estrusione
|
|
SurfTriMesh STM2 ;
|
|
if ( ! STM2.CreateByExtrusion( vPL[i], vtExtr))
|
|
return nullptr ;
|
|
// la unisco alla superficie principale
|
|
if ( ! pSTM->DoSewing( STM2))
|
|
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 = 0, dPosFin = 0 ;
|
|
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<SurfTriMesh> pSTM( CreateBasicSurfTriMesh()) ;
|
|
if ( IsNull( pSTM) || ! pSTM->CreateByScrewing( PL, ptAx, vtAx, ANG_FULL, dStepRotDeg, 0))
|
|
return nullptr ;
|
|
// se superficie risultante chiusa, verifico che la normale sia verso l'esterno
|
|
double dVol ;
|
|
if ( pSTM->GetVolume( dVol) && dVol < 0)
|
|
pSTM->Invert() ;
|
|
// 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, 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 superficie rototraslata, necessari limiti sulla lunghezza dei segmenti
|
|
if ( abs( dAngRotDeg) > EPS_ANG_SMALL && abs( dMove) > EPS_SMALL){
|
|
double dLenMax = 2.5 * abs( dMove * dStepRotDeg / dAngRotDeg) ;
|
|
if ( ! PL.AdjustForMaxSegmentLen( dLenMax))
|
|
return nullptr ;
|
|
}
|
|
// creo e setto la superficie trimesh
|
|
PtrOwner<SurfTriMesh> pSTM( CreateBasicSurfTriMesh()) ;
|
|
if ( IsNull( pSTM) || ! pSTM->CreateByScrewing( PL, ptAx, vtAx, dAngRotDeg, dStepRotDeg, dMove))
|
|
return nullptr ;
|
|
// se richiesti caps
|
|
if ( bCapEnds) {
|
|
// determino se la sezione è chiusa e piatta
|
|
Plane3d plPlane ; double dArea ;
|
|
bool bSectClosedFlat = PL.IsClosedAndFlat( plPlane, dArea, 10 * EPS_SMALL) ;
|
|
// determino non sia una semplice rivoluzione
|
|
bool bRevolved = ( abs( abs( dAngRotDeg) - ANG_FULL) < EPS_ANG_SMALL && abs( dMove) < EPS_SMALL) ;
|
|
// se sezione chiusa e piatta e non rivoluzione, posso aggiungere i tappi
|
|
if ( bSectClosedFlat && ! bRevolved) {
|
|
// aggiungo il cap sull'inizio
|
|
PtrOwner<SurfTriMesh> pSci( CreateBasicSurfTriMesh()) ;
|
|
if ( IsNull( pSci) || ! pSci->CreateByFlatContour( PL))
|
|
return nullptr ;
|
|
pSTM->DoSewing( *pSci) ;
|
|
// aggiungo il cap sulla fine
|
|
Vector3d vtMove = vtAx ;
|
|
vtMove.Normalize() ;
|
|
vtMove *= dMove ;
|
|
PL.Translate( vtMove) ;
|
|
PL.Rotate( ptAx, vtAx, dAngRotDeg) ;
|
|
PtrOwner<SurfTriMesh> pSce( CreateBasicSurfTriMesh()) ;
|
|
if ( IsNull( pSce) || ! pSce->CreateByFlatContour( PL))
|
|
return nullptr ;
|
|
pSce->Invert() ;
|
|
pSTM->DoSewing( *pSce) ;
|
|
}
|
|
}
|
|
// se superficie risultante chiusa, verifico che la normale sia verso l'esterno
|
|
double dVol ;
|
|
if ( pSTM->GetVolume( dVol) && dVol < 0)
|
|
pSTM->Invert() ;
|
|
// salvo tolleranza lineare usata
|
|
pSTM->SetLinearTolerance( dLinTol) ;
|
|
// restituisco la superficie
|
|
return Release( pSTM) ;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
static ISurfTriMesh*
|
|
GetSurfTriMeshSharpRectSwept( double dDimH, double dDimV, const ICurve* pGuide, int nCapType, double dLinTol)
|
|
{
|
|
// verifico che la linea guida sia piana
|
|
Plane3d plGuide ;
|
|
if ( ! pGuide->IsFlat( plGuide, false, 10 * EPS_SMALL))
|
|
return nullptr ;
|
|
Vector3d vtNorm = plGuide.GetVersN() ;
|
|
// determino se la guida è chiusa
|
|
bool bGuideClosed = pGuide->IsClosed() ;
|
|
// curve di offset
|
|
OffsetCurve OffsCrvR ;
|
|
if ( ! OffsCrvR.Make( pGuide, dDimH / 2, ICurve::OFF_FILLET) || OffsCrvR.GetCurveCount() == 0)
|
|
return nullptr ;
|
|
PtrOwner<ICurve> pCrvR( OffsCrvR.GetLongerCurve()) ;
|
|
if ( IsNull( pCrvR))
|
|
return nullptr ;
|
|
OffsetCurve OffsCrvL ;
|
|
if ( ! OffsCrvL.Make( pGuide, -dDimH / 2, ICurve::OFF_FILLET) || OffsCrvL.GetCurveCount() == 0)
|
|
return nullptr ;
|
|
PtrOwner<ICurve> pCrvL( OffsCrvL.GetLongerCurve()) ;
|
|
if ( IsNull( pCrvL))
|
|
return nullptr ;
|
|
// costruisco le parti di superficie
|
|
PtrOwner<ISurfTriMesh> pSrfTop( GetSurfTriMeshRuled( pCrvR, pCrvL, ISurfTriMesh::RLT_MINDIST, dLinTol)) ;
|
|
if ( IsNull( pSrfTop))
|
|
return nullptr ;
|
|
PtrOwner<ISurfTriMesh> pSrfBot( pSrfTop->Clone()) ;
|
|
if ( IsNull( pSrfBot))
|
|
return nullptr ;
|
|
pSrfBot->Translate( -dDimV * vtNorm) ;
|
|
pSrfBot->Invert() ;
|
|
PtrOwner<ISurfTriMesh> pSrfRgt( GetSurfTriMeshByExtrusion( pCrvR, -dDimV * vtNorm, false, dLinTol)) ;
|
|
if ( IsNull( pSrfRgt))
|
|
return nullptr ;
|
|
pSrfRgt->Invert() ;
|
|
PtrOwner<ISurfTriMesh> pSrfLft( GetSurfTriMeshByExtrusion( pCrvL, -dDimV * vtNorm, false, dLinTol)) ;
|
|
if ( IsNull( pSrfLft))
|
|
return nullptr ;
|
|
// unisco le parti
|
|
PtrOwner<ISurfTriMesh> pSTM( Release( pSrfTop)) ;
|
|
pSTM->DoSewing( *pSrfRgt) ;
|
|
pSTM->DoSewing( *pSrfLft) ;
|
|
pSTM->DoSewing( *pSrfBot) ;
|
|
// salvo tolleranza lineare usata e imposto angolo per smooth
|
|
pSTM->SetLinearTolerance( dLinTol) ;
|
|
pSTM->SetSmoothAngle( 20) ;
|
|
// se guida aperta e tappi piatti
|
|
if ( ! bGuideClosed && nCapType == RSCAP_FLAT) {
|
|
// verifico che le due estremità siano chiuse e piatte
|
|
POLYLINEVECTOR vPL ;
|
|
if ( ! pSTM->GetLoops( vPL) || vPL.size() != 2)
|
|
return nullptr ;
|
|
Plane3d plEnds ; double dArea ;
|
|
if ( ! vPL[0].IsClosedAndFlat( plEnds, dArea, 100 * EPS_SMALL))
|
|
return nullptr ;
|
|
if ( ! vPL[1].IsClosedAndFlat( plEnds, dArea, 100 * EPS_SMALL))
|
|
return nullptr ;
|
|
// aggiungo il cap sull'inizio
|
|
PtrOwner<SurfTriMesh> pSci( CreateBasicSurfTriMesh()) ;
|
|
if ( IsNull( pSci) || ! pSci->CreateByFlatContour( vPL[0]))
|
|
return nullptr ;
|
|
pSci->Invert() ;
|
|
pSTM->DoSewing( *pSci) ;
|
|
// aggiungo il cap sulla fine
|
|
PtrOwner<SurfTriMesh> pSce( CreateBasicSurfTriMesh()) ;
|
|
if ( IsNull( pSce) || ! pSce->CreateByFlatContour( vPL[1]))
|
|
return nullptr ;
|
|
pSce->Invert() ;
|
|
pSTM->DoSewing( *pSce) ;
|
|
}
|
|
// se altrimenti guida aperta e tappi arrotondati
|
|
if ( ! bGuideClosed && ( nCapType == RSCAP_ROUND || nCapType == RSCAP_BEVEL)) {
|
|
// step di rotazione per rispettare la tolleranza
|
|
double dStepRotDeg = ( nCapType == RSCAP_BEVEL ? ANG_STRAIGHT / 4 : sqrt( 8 * dLinTol / dDimH) * RADTODEG) ;
|
|
// aggiungo il cap sull'inizio
|
|
Point3d ptStart ;
|
|
pGuide->GetStartPoint( ptStart) ;
|
|
Vector3d vtStart ;
|
|
pGuide->GetStartDir( vtStart) ;
|
|
vtStart.Rotate( vtNorm, 0, 1) ;
|
|
PolyLine PLStart ;
|
|
PLStart.AddUPoint( 0, ptStart) ;
|
|
PLStart.AddUPoint( 1, ptStart + dDimH / 2 * vtStart) ;
|
|
PLStart.AddUPoint( 2, ptStart + dDimH / 2 * vtStart - dDimV * vtNorm) ;
|
|
PLStart.AddUPoint( 3, ptStart - dDimV * vtNorm) ;
|
|
PtrOwner<SurfTriMesh> pSci( CreateBasicSurfTriMesh()) ;
|
|
if ( IsNull( pSci) || ! pSci->CreateByScrewing( PLStart, ptStart, vtNorm, ANG_STRAIGHT, dStepRotDeg, 0))
|
|
return nullptr ;
|
|
pSci->Invert() ;
|
|
pSTM->DoSewing( *pSci) ;
|
|
// aggiungo il cap sulla fine
|
|
Point3d ptEnd ;
|
|
pGuide->GetEndPoint( ptEnd) ;
|
|
Vector3d vtEnd ;
|
|
pGuide->GetEndDir( vtEnd) ;
|
|
vtEnd.Rotate( vtNorm, 0, -1) ;
|
|
PolyLine PLEnd ;
|
|
PLEnd.AddUPoint( 0, ptEnd) ;
|
|
PLEnd.AddUPoint( 1, ptEnd + dDimH / 2 * vtEnd) ;
|
|
PLEnd.AddUPoint( 2, ptEnd + dDimH / 2 * vtEnd - dDimV * vtNorm) ;
|
|
PLEnd.AddUPoint( 3, ptEnd - dDimV * vtNorm) ;
|
|
PtrOwner<SurfTriMesh> pSce( CreateBasicSurfTriMesh()) ;
|
|
if ( IsNull( pSce) || ! pSce->CreateByScrewing( PLEnd, ptEnd, vtNorm, ANG_STRAIGHT, dStepRotDeg, 0))
|
|
return nullptr ;
|
|
pSce->Invert() ;
|
|
pSTM->DoSewing( *pSce) ;
|
|
}
|
|
// restituisco la superficie
|
|
return Release( pSTM) ;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
static ISurfTriMesh*
|
|
GetSurfTriMeshBeveledRectSwept( double dDimH, double dDimV, double dBevelH, double dBevelV, const ICurve* pGuide, int nCapType, double dLinTol)
|
|
{
|
|
// metodo di calcolo impostato da USE_VORONOI
|
|
|
|
// verifico che la linea guida sia piana
|
|
Plane3d plGuide ;
|
|
if ( ! pGuide->IsFlat( plGuide, false, 10 * EPS_SMALL))
|
|
return nullptr ;
|
|
// assegno la normale del piano
|
|
Vector3d vtNorm = plGuide.GetVersN() ;
|
|
// determino il punto centrale della sezione
|
|
Point3d ptCen ;
|
|
pGuide->GetStartPoint( ptCen) ;
|
|
ptCen -= dDimV / 2 * vtNorm ;
|
|
// determino se la guida è chiusa
|
|
bool bGuideClosed = pGuide->IsClosed() ;
|
|
// curve di offset
|
|
const int NUM_OFFS = 4 ;
|
|
OffsetCurve vOffsCrv[NUM_OFFS] ;
|
|
double vDist[NUM_OFFS] = { dDimH / 2 - dBevelH, -dDimH / 2 + dBevelH, dDimH / 2, -dDimH / 2} ;
|
|
bool bOk = true ;
|
|
if ( ! USE_VORONOI) {
|
|
future<bool> vRes[NUM_OFFS] ;
|
|
for ( int i = 0 ; i < NUM_OFFS ; ++ i)
|
|
vRes[i] = async( launch::async, &OffsetCurve::Make, &vOffsCrv[i], pGuide, vDist[i], ICurve::OFF_FILLET) ;
|
|
bool bOk = true ;
|
|
int nFin = 0 ;
|
|
while ( nFin < NUM_OFFS) {
|
|
for ( int i = 0 ; i < NUM_OFFS ; ++ i) {
|
|
if ( vRes[i].valid() && vRes[i].wait_for( chrono::nanoseconds{ 1}) == future_status::ready) {
|
|
bOk = vRes[i].get() && bOk ;
|
|
++ nFin ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// se Voronoi non è possibile calcolare gli offset di una stessa curva in parallelo
|
|
for ( int i = 0 ; i < NUM_OFFS && bOk ; ++ i)
|
|
bOk = vOffsCrv[i].Make( pGuide, vDist[i], ICurve::OFF_FILLET) ;
|
|
}
|
|
|
|
if ( ! bOk ||
|
|
vOffsCrv[0].GetCurveCount() == 0 || vOffsCrv[1].GetCurveCount() == 0 ||
|
|
vOffsCrv[2].GetCurveCount() == 0 || vOffsCrv[3].GetCurveCount() == 0)
|
|
return nullptr ;
|
|
PtrOwner<ICurve> pCrvR( vOffsCrv[0].GetLongerCurve()) ;
|
|
if ( IsNull( pCrvR))
|
|
return nullptr ;
|
|
PtrOwner<ICurve> pCrvL( vOffsCrv[1].GetLongerCurve()) ;
|
|
if ( IsNull( pCrvL))
|
|
return nullptr ;
|
|
PtrOwner<ICurve> pCrvRb( vOffsCrv[2].GetLongerCurve()) ;
|
|
if ( IsNull( pCrvRb))
|
|
return nullptr ;
|
|
pCrvRb->Translate( - dBevelV * vtNorm) ;
|
|
PtrOwner<ICurve> pCrvLb( vOffsCrv[3].GetLongerCurve()) ;
|
|
if ( IsNull( pCrvLb))
|
|
return nullptr ;
|
|
pCrvLb->Translate( - dBevelV * vtNorm) ;
|
|
// costruisco le parti di superficie
|
|
PtrOwner<ISurfTriMesh> pSrfTop( GetSurfTriMeshRuled( pCrvR, pCrvL, ISurfTriMesh::RLT_MINDIST, dLinTol)) ;
|
|
if ( IsNull( pSrfTop))
|
|
return nullptr ;
|
|
PtrOwner<ISurfTriMesh> pSrfBot( pSrfTop->Clone()) ;
|
|
if ( IsNull( pSrfBot))
|
|
return nullptr ;
|
|
pSrfBot->Translate( -dDimV * vtNorm) ;
|
|
pSrfBot->Invert() ;
|
|
PtrOwner<ISurfTriMesh> pSrfTopR( GetSurfTriMeshRuled( pCrvRb, pCrvR, ISurfTriMesh::RLT_MINDIST, dLinTol)) ;
|
|
if ( IsNull( pSrfTopR))
|
|
return nullptr ;
|
|
PtrOwner<ISurfTriMesh> pSrfBotR( pSrfTopR->Clone()) ;
|
|
if ( IsNull( pSrfBotR))
|
|
return nullptr ;
|
|
pSrfBotR->Mirror( ptCen, vtNorm) ;
|
|
PtrOwner<ISurfTriMesh> pSrfTopL( GetSurfTriMeshRuled( pCrvL, pCrvLb, ISurfTriMesh::RLT_MINDIST, dLinTol)) ;
|
|
if ( IsNull( pSrfTopL))
|
|
return nullptr ;
|
|
PtrOwner<ISurfTriMesh> pSrfBotL( pSrfTopL->Clone()) ;
|
|
if ( IsNull( pSrfBotL))
|
|
return nullptr ;
|
|
pSrfBotL->Mirror( ptCen, vtNorm) ;
|
|
PtrOwner<ISurfTriMesh> pSrfRgt( GetSurfTriMeshByExtrusion( pCrvRb, ( -dDimV + 2 * dBevelV) * vtNorm, false, dLinTol)) ;
|
|
if ( IsNull( pSrfRgt))
|
|
return nullptr ;
|
|
pSrfRgt->Invert() ;
|
|
PtrOwner<ISurfTriMesh> pSrfLft( GetSurfTriMeshByExtrusion( pCrvLb, ( -dDimV + 2 * dBevelV) * vtNorm, false, dLinTol)) ;
|
|
if ( IsNull( pSrfLft))
|
|
return nullptr ;
|
|
// unisco le parti
|
|
int nBuckets = max( 4 * ( pSrfRgt->GetVertexSize() + pSrfLft->GetVertexSize()), 1000) ;
|
|
StmFromTriangleSoup stmSoup ;
|
|
if ( ! stmSoup.Start( nBuckets))
|
|
return nullptr ;
|
|
stmSoup.AddSurfTriMesh( *pSrfTop) ;
|
|
stmSoup.AddSurfTriMesh( *pSrfTopR) ;
|
|
stmSoup.AddSurfTriMesh( *pSrfTopL) ;
|
|
stmSoup.AddSurfTriMesh( *pSrfRgt) ;
|
|
stmSoup.AddSurfTriMesh( *pSrfLft) ;
|
|
stmSoup.AddSurfTriMesh( *pSrfBotR) ;
|
|
stmSoup.AddSurfTriMesh( *pSrfBotL) ;
|
|
stmSoup.AddSurfTriMesh( *pSrfBot) ;
|
|
PtrOwner<ISurfTriMesh> pSTM ;
|
|
// se guida aperta e tappi piatti
|
|
if ( ! bGuideClosed && nCapType == RSCAP_FLAT) {
|
|
// completo unione e recupero la superficie risultante
|
|
if ( ! stmSoup.End())
|
|
return nullptr ;
|
|
pSTM.Set( stmSoup.GetSurf()) ;
|
|
// preparo seconda zuppa di triangoli per inserire i tappi
|
|
StmFromTriangleSoup stmCapSoup ;
|
|
if ( ! stmCapSoup.Start( nBuckets))
|
|
return nullptr ;
|
|
// verifico che le due estremità siano chiuse e piatte
|
|
POLYLINEVECTOR vPL ;
|
|
if ( ! pSTM->GetLoops( vPL) || vPL.size() != 2)
|
|
return nullptr ;
|
|
Plane3d plEnds ; double dArea ;
|
|
if ( ! vPL[0].IsClosedAndFlat( plEnds, dArea, 50 * EPS_SMALL))
|
|
return nullptr ;
|
|
if ( ! vPL[1].IsClosedAndFlat( plEnds, dArea, 50 * EPS_SMALL))
|
|
return nullptr ;
|
|
// calcolo il cap sull'inizio
|
|
PtrOwner<SurfTriMesh> pSci( CreateBasicSurfTriMesh()) ;
|
|
if ( IsNull( pSci) || ! pSci->CreateByFlatContour( vPL[0]))
|
|
return nullptr ;
|
|
pSci->Invert() ;
|
|
// calcolo il cap sulla fine
|
|
PtrOwner<SurfTriMesh> pSce( CreateBasicSurfTriMesh()) ;
|
|
if ( IsNull( pSce) || ! pSce->CreateByFlatContour( vPL[1]))
|
|
return nullptr ;
|
|
pSce->Invert() ;
|
|
// cucio i tappi all'estrusione
|
|
if ( ! pSTM->DoSewing( *pSci) || ! pSTM->DoSewing( *pSce))
|
|
return nullptr ;
|
|
}
|
|
// se altrimenti guida aperta e tappi arrotondati
|
|
else if ( ! bGuideClosed && ( nCapType == RSCAP_ROUND || nCapType == RSCAP_BEVEL)) {
|
|
// step di rotazione per rispettare il tipo o la tolleranza
|
|
double dStepRotDeg = ( nCapType == RSCAP_BEVEL ? ANG_STRAIGHT / 4 : sqrt( 8 * dLinTol / dDimH) * RADTODEG) ;
|
|
// aggiungo il cap sull'inizio
|
|
Point3d ptStart ;
|
|
pGuide->GetStartPoint( ptStart) ;
|
|
Vector3d vtStart ;
|
|
pGuide->GetStartDir( vtStart) ;
|
|
vtStart.Rotate( vtNorm, 0, 1) ;
|
|
PolyLine PLStart ;
|
|
PLStart.AddUPoint( 0, ptStart) ;
|
|
PLStart.AddUPoint( 1, ptStart + ( dDimH / 2 - dBevelH) * vtStart) ;
|
|
PLStart.AddUPoint( 2, ptStart + dDimH / 2 * vtStart - dBevelV * vtNorm) ;
|
|
PLStart.AddUPoint( 3, ptStart + dDimH / 2 * vtStart - ( dDimV - dBevelV) * vtNorm) ;
|
|
PLStart.AddUPoint( 4, ptStart + ( dDimH / 2 - dBevelH) * vtStart - dDimV * vtNorm) ;
|
|
PLStart.AddUPoint( 5, ptStart - dDimV * vtNorm) ;
|
|
PtrOwner<SurfTriMesh> pSci( CreateBasicSurfTriMesh()) ;
|
|
if ( IsNull( pSci) || ! pSci->CreateByScrewing( PLStart, ptStart, vtNorm, ANG_STRAIGHT, dStepRotDeg, 0))
|
|
return nullptr ;
|
|
pSci->Invert() ;
|
|
stmSoup.AddSurfTriMesh( *pSci) ;
|
|
// aggiungo il cap sulla fine
|
|
Point3d ptEnd ;
|
|
pGuide->GetEndPoint( ptEnd) ;
|
|
Vector3d vtEnd ;
|
|
pGuide->GetEndDir( vtEnd) ;
|
|
vtEnd.Rotate( vtNorm, 0, -1) ;
|
|
PolyLine PLEnd ;
|
|
PLEnd.AddUPoint( 0, ptEnd) ;
|
|
PLEnd.AddUPoint( 1, ptEnd + ( dDimH / 2 - dBevelH) * vtEnd) ;
|
|
PLEnd.AddUPoint( 2, ptEnd + dDimH / 2 * vtEnd - dBevelV * vtNorm) ;
|
|
PLEnd.AddUPoint( 3, ptEnd + dDimH / 2 * vtEnd - ( dDimV - dBevelV) * vtNorm) ;
|
|
PLEnd.AddUPoint( 4, ptEnd + ( dDimH / 2 - dBevelH) * vtEnd - dDimV * vtNorm) ;
|
|
PLEnd.AddUPoint( 5, ptEnd - dDimV * vtNorm) ;
|
|
PtrOwner<SurfTriMesh> pSce( CreateBasicSurfTriMesh()) ;
|
|
if ( IsNull( pSce) || ! pSce->CreateByScrewing( PLEnd, ptEnd, vtNorm, ANG_STRAIGHT, dStepRotDeg, 0))
|
|
return nullptr ;
|
|
pSce->Invert() ;
|
|
stmSoup.AddSurfTriMesh( *pSce) ;
|
|
// completo unione e recupero la superficie risultante
|
|
if ( ! stmSoup.End())
|
|
return nullptr ;
|
|
pSTM.Set( stmSoup.GetSurf()) ;
|
|
}
|
|
else {
|
|
// completo unione e recupero la superficie risultante
|
|
if ( ! stmSoup.End())
|
|
return nullptr ;
|
|
pSTM.Set( stmSoup.GetSurf()) ;
|
|
}
|
|
// salvo tolleranza lineare usata e imposto angolo per smooth
|
|
pSTM->SetLinearTolerance( dLinTol) ;
|
|
pSTM->SetSmoothAngle( 20) ;
|
|
// restituisco la superficie
|
|
return Release( pSTM) ;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
ISurfTriMesh*
|
|
GetSurfTriMeshRectSwept( double dDimH, double dDimV, double dBevelH, double dBevelV, const ICurve* pGuide, int nCapType, double dLinTol)
|
|
{
|
|
// verifica parametri
|
|
if ( pGuide == nullptr || dBevelH > 0.4 * dDimH || dBevelV > 0.4 * dDimV)
|
|
return nullptr ;
|
|
// determino se sezione squadrata o con smusso
|
|
bool bSharp = ( dBevelH < 100 * EPS_SMALL || dBevelV < 100 * EPS_SMALL) ;
|
|
// eseguo
|
|
if ( bSharp)
|
|
return GetSurfTriMeshSharpRectSwept( dDimH, dDimV, pGuide, nCapType, dLinTol) ;
|
|
else
|
|
return GetSurfTriMeshBeveledRectSwept( dDimH, dDimV, dBevelH, dBevelV, pGuide, nCapType, dLinTol) ;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
ISurfTriMesh*
|
|
GetSurfTriMeshSwept( const ICurve* pSect, const ICurve* pGuide, bool bCapEnds, double dLinTol, Vector3d* vtStatic)
|
|
{
|
|
// verifica parametri
|
|
if ( pSect == nullptr || pGuide == nullptr)
|
|
return nullptr ;
|
|
|
|
// calcolo la polilinea che approssima la sezione
|
|
PolyLine PL ;
|
|
if ( ! pSect->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL))
|
|
return nullptr ;
|
|
|
|
// determino se la sezione è chiusa
|
|
bool bSectClosed = PL.IsClosed() ;
|
|
// determino se la guida è chiusa
|
|
bool bGuideClosed = pGuide->IsClosed() ;
|
|
|
|
// definisco la superficie da restituire ( definendo la sua tolleranza )
|
|
PtrOwner<SurfTriMesh> pSTM( CreateBasicSurfTriMesh()) ;
|
|
if ( IsNull( pSTM))
|
|
return nullptr ;
|
|
pSTM->SetLinearTolerance( dLinTol) ;
|
|
|
|
// calcolo punto e versore tangente iniziale
|
|
Point3d ptStart ; pGuide->GetStartPoint( ptStart) ;
|
|
Vector3d vtStart ; pGuide->GetStartDir( vtStart) ;
|
|
// inizializzazione del frame iniziale ( viene definito a seconda dei casi )
|
|
Frame3d frStart ;
|
|
|
|
/* GUIDA PIANA */
|
|
|
|
// verifico che la linea guida sia piana
|
|
Plane3d plGuide ;
|
|
if ( ! pGuide->IsFlat( plGuide, false, 10 * EPS_SMALL)) {
|
|
|
|
/*
|
|
La guida non è piana, l'estrusione può essere definita mediante :
|
|
( 1) un versore statico
|
|
( 2) mediante l'algoritmo del Rotation Minimize Frame
|
|
*/
|
|
|
|
// recupero la sezione dalla PolyLine approssimata come Curva
|
|
PtrOwner<CurveComposite> pSecLocApprox( CreateBasicCurveComposite()) ;
|
|
if ( IsNull( pSecLocApprox) ||
|
|
! pSecLocApprox->FromPolyLine( PL) ||
|
|
! pSecLocApprox->IsValid())
|
|
return nullptr ;
|
|
|
|
// recupero il frame iniziale sulla guida ( Origine sul punto iniziale e asse Z tangente )
|
|
frStart.Set( ptStart, vtStart) ;
|
|
if ( ! frStart.IsValid())
|
|
return nullptr ;
|
|
|
|
// tengo in memoria il frame nel punto iniziale e finale della guida in caso di caps
|
|
Frame3d frCaps_start ;
|
|
Frame3d frCaps_end ;
|
|
|
|
if ( vtStatic != nullptr) { // (1) versore statico
|
|
|
|
// creo il piano di proiezione con normale definita dal vettore
|
|
Plane3d plProj ;
|
|
plProj.Set( ORIG, *vtStatic) ;
|
|
if ( ! plProj.IsValid())
|
|
return nullptr ;
|
|
|
|
// porto la sezione nel frame definito dalla guida, tenendo il versore X del frame nel piano
|
|
// definito da vtStatic
|
|
Vector3d vtX = vtStart ; // versore tangente alla curva
|
|
vtX.Rotate( *vtStatic, 90) ; // ruoto di 90 gradi rispetto a vtStatic
|
|
OrthoCompo( vtX, *vtStatic) ; // tengo la componente nel piano
|
|
vtX.Normalize() ; // normalizzo
|
|
Frame3d frInitial ; frInitial.Set( ptStart, vtStart, vtX) ; // creo il frame
|
|
if ( ! frInitial.IsValid())
|
|
return nullptr ;
|
|
|
|
// porto la sezione nel riferimento
|
|
pSecLocApprox->ToLoc( frInitial) ;
|
|
PL.ToLoc( frInitial) ; //... porto anche la PolyLine del bordo della sezione
|
|
|
|
// approssimo la guida mediante la tolleranza richiesta
|
|
PolyLine PL_G ;
|
|
if ( ! pGuide->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL_G))
|
|
return nullptr ;
|
|
|
|
// punto attuale e punto successivo sulla guida su cui definire il frame
|
|
Point3d ptCurr, ptSucc ;
|
|
if ( ! PL_G.GetFirstPoint( ptCurr))
|
|
return nullptr ;
|
|
bool bNextPoint = PL_G.GetNextPoint( ptSucc) ;
|
|
if ( ! bNextPoint)
|
|
return nullptr ;
|
|
|
|
// parametro attuale e successivo riferito ai punti sulla guida
|
|
double dParCurr = 0 ;
|
|
double dParSucc ;
|
|
|
|
// versore attuale e successivo riferito ai punti sulla guida
|
|
Vector3d vtTanCurr, vtTanSucc ;
|
|
if ( ! pGuide->GetStartDir( vtTanCurr))
|
|
return nullptr ;
|
|
|
|
// frame iniziale e successivo riferito alla curva
|
|
Frame3d frCurr, frSucc ;
|
|
|
|
bool bFirstIter = true ; // per salvare il frame iniziale nel caso di caps
|
|
while ( bNextPoint) { // finchè recupero un punto sucessivo...
|
|
|
|
// recupero il parametro successivo riferito alla guida
|
|
if ( ! pGuide->GetParamAtPoint( ptSucc, dParSucc))
|
|
return nullptr ;
|
|
|
|
// recupero il versore tangente riferito al punto successivo sulla guida
|
|
if ( ! pGuide->GetPointD1D2( dParSucc, ICurve::FROM_MINUS, ptSucc, &vtTanSucc) ||
|
|
! vtTanSucc.Normalize())
|
|
return nullptr ;
|
|
|
|
// creazione del frame nel punto corrente
|
|
Vector3d vtX_curr = vtTanCurr ;
|
|
vtX_curr.Rotate( *vtStatic, 90) ;
|
|
OrthoCompo( vtX_curr, *vtStatic) ;
|
|
vtX_curr.Normalize() ;
|
|
frCurr.Set( ptCurr, vtTanCurr, vtX_curr) ;
|
|
if ( ! frCurr.IsValid())
|
|
return nullptr ;
|
|
|
|
// memorizzo il primo frame di caso di caps
|
|
if ( bFirstIter) {
|
|
frCaps_start = frCurr ;
|
|
bFirstIter = false ;
|
|
}
|
|
|
|
// creazione del frame nel punto successivo
|
|
Vector3d vtX_succ = vtTanSucc ;
|
|
vtX_succ.Rotate( *vtStatic, 90) ;
|
|
OrthoCompo( vtX_curr, *vtStatic) ;
|
|
vtX_succ.Normalize() ;
|
|
frSucc.Set( ptSucc, vtTanSucc, vtX_succ) ;
|
|
if ( ! frSucc.IsValid())
|
|
return nullptr ;
|
|
|
|
|
|
frCaps_end = frSucc ; // aggiorno il frame finale ad ogni step
|
|
|
|
// definisco la sezione allo step corrente
|
|
PtrOwner<ICurve> pSecCurr( pSecLocApprox->Clone()) ;
|
|
if ( IsNull( pSecCurr) || ! pSecCurr->IsValid())
|
|
return nullptr ;
|
|
|
|
// considero la sezione ( in locale ) come vista dal globale
|
|
if ( ! pSecCurr->ToGlob( frCurr))
|
|
return nullptr ;
|
|
|
|
// definisco la sezione allo step successivo
|
|
PtrOwner<ICurve> pSecSucc( pSecLocApprox->Clone()) ;
|
|
if ( IsNull( pSecSucc) || ! pSecSucc->IsValid())
|
|
return nullptr ;
|
|
|
|
// considero la sezione ( in locale ) come vista dal globale
|
|
if ( ! pSecSucc->ToGlob( frSucc))
|
|
return nullptr ;
|
|
|
|
// creo la rigata tra queste due sezioni
|
|
PtrOwner<ISurfTriMesh> pSr( GetSurfTriMeshRuled( pSecCurr, pSecSucc, ISurfTriMesh::RLT_MINDIST, dLinTol)) ;
|
|
if ( IsNull( pSr) || ! pSr->IsValid())
|
|
return nullptr ;
|
|
|
|
// attacco la rigata alla superficie da restituire
|
|
pSTM->DoSewing( *pSr) ;
|
|
|
|
// aggiornamento dei parametri
|
|
ptCurr = ptSucc ; // il punto corrente diventa il successivo
|
|
bNextPoint = PL_G.GetNextPoint( ptSucc) ; // il successivo lo recupero dalla PolyLine
|
|
vtTanCurr = vtTanSucc ; // il versore tangete corrente diventa il successivo
|
|
}
|
|
// la superficie definita dal RMF è invertita, il versore Z è diretto come la tangente della curva
|
|
pSTM->Invert() ;
|
|
|
|
}
|
|
else { // (2) Rotation Minimize Frame
|
|
|
|
// porto la PolyLine e la curva della sezione nel riferimento nel punto iniziale della guida
|
|
pSecLocApprox->ToLoc( frStart) ;
|
|
PL.ToLoc( frStart) ;
|
|
|
|
// calcolo il vettore di Frames campionati lungo la guida mediante la tolleranza definita
|
|
RotationMinimizeFrame RMF( pGuide, frStart) ;
|
|
FRAME3DVECTOR vRMF ;
|
|
if ( ! RMF.GetFramesByTollerance( vRMF, dLinTol) || vRMF.empty())
|
|
return nullptr ;
|
|
|
|
// per ogni RMF calcolato, la sezione va roto-traslata lungo la guida
|
|
for ( int i = 0 ; i < int( vRMF.size()) - 1 ; ++ i) {
|
|
|
|
// definisco la sezione allo step corrente
|
|
PtrOwner<ICurve> pSecCurr( pSecLocApprox->Clone()) ;
|
|
if ( IsNull( pSecCurr) || ! pSecCurr->IsValid())
|
|
return nullptr ;
|
|
|
|
// considero la sezione ( in locale ) come vista dal globale
|
|
if ( ! pSecCurr->ToGlob( vRMF[i]))
|
|
return nullptr ;
|
|
|
|
// definisco la sezione allo step successivo
|
|
PtrOwner<ICurve> pSecSucc( pSecLocApprox->Clone()) ;
|
|
if ( IsNull( pSecSucc) || ! pSecSucc->IsValid())
|
|
return nullptr ;
|
|
|
|
// considero la sezione ( in locale ) come vista dal globale
|
|
if ( ! pSecSucc->ToGlob( vRMF[i+1]))
|
|
return nullptr ;
|
|
|
|
// creo la rigata tra queste due sezioni
|
|
PtrOwner<ISurfTriMesh> pSr( GetSurfTriMeshRuled( pSecCurr, pSecSucc, ISurfTriMesh::RLT_MINDIST, dLinTol)) ;
|
|
if ( IsNull( pSr) || ! pSr->IsValid())
|
|
return nullptr ;
|
|
|
|
// attacco la rigata alla superficie da restituire
|
|
pSTM->DoSewing( *pSr) ;
|
|
}
|
|
// la superficie definita dal RMF è invertita, il versore Z è diretto come la tangente della curva
|
|
pSTM->Invert() ;
|
|
|
|
// assegno frame iniziale e finale per caps
|
|
frCaps_start = vRMF[0] ;
|
|
frCaps_end = vRMF.back() ;
|
|
}
|
|
|
|
// se richiesti caps e sezione chiusa e guida aperta
|
|
// (1) vtStatic, (2) Rotation Minimize Frame
|
|
if ( bCapEnds && bSectClosed && ! bGuideClosed) {
|
|
|
|
// aggiungo il cap sull'inizio ( portandolo nel frame del punto iniziale della guida )
|
|
PtrOwner<SurfTriMesh> pSci( CreateBasicSurfTriMesh()) ;
|
|
if ( IsNull( pSci) || ! pSci->CreateByFlatContour( PL))
|
|
return nullptr ;
|
|
pSci->ToGlob( frCaps_start) ;
|
|
// unisco
|
|
pSTM->DoSewing( *pSci) ;
|
|
|
|
// aggiungo il cap sulla fine ( portandolo nel frame del punto finale della guida )
|
|
PtrOwner<SurfTriMesh> pSce( CreateBasicSurfTriMesh()) ;
|
|
if ( IsNull( pSce) || ! pSce->CreateByFlatContour( PL))
|
|
return nullptr ;
|
|
pSce->ToGlob( frCaps_end) ;
|
|
|
|
pSce->Invert() ; // il versore z è definito dalle tangenti alla curva
|
|
|
|
// unisco
|
|
pSTM->DoSewing( *pSce) ;
|
|
}
|
|
|
|
// se superficie risultante chiusa, verifico che la normale sia verso l'esterno
|
|
double dVol ;
|
|
if ( pSTM->GetVolume( dVol) && dVol < 0)
|
|
pSTM->Invert() ;
|
|
|
|
// restituisco la superficie
|
|
return Release( pSTM) ;
|
|
|
|
}
|
|
|
|
/*
|
|
GUIDA PIANA
|
|
La guida è piana, l'estrusione viene definita mediante Offset della guida sulla sezione
|
|
*/
|
|
|
|
// il frame iniziale è definito dal versore tangente e dalla normale al piano
|
|
// che contiene la guida
|
|
Vector3d vtNorm = plGuide.GetVersN() ;
|
|
frStart.Set( ptStart, -vtStart, vtStart ^ vtNorm) ;
|
|
|
|
// porto la sezione in questo riferimento e ve la appiattisco
|
|
if ( ! PL.ToLoc( frStart) || ! PL.Flatten())
|
|
return nullptr ;
|
|
|
|
// superficie swept
|
|
PtrOwner<ICurve> pPrevCrv ;
|
|
Point3d ptP ;
|
|
bool bPoint = PL.GetFirstPoint( ptP) ;
|
|
while ( bPoint) {
|
|
// nuova curva ( definita dall'Offset )
|
|
OffsetCurve OffsCrv ;
|
|
if ( ! OffsCrv.Make( pGuide, ptP.x, ICurve::OFF_FILLET) || OffsCrv.GetCurveCount() == 0)
|
|
return nullptr ;
|
|
PtrOwner<ICurve> pCurrCrv( OffsCrv.GetLongerCurve()) ;
|
|
if ( IsNull( pCurrCrv))
|
|
return nullptr ;
|
|
pCurrCrv->Translate( ptP.y * frStart.VersY()) ;
|
|
|
|
// se esiste la curva precedente, costruisco la rigata ( di tipo minima distanza)
|
|
if ( ! IsNull( pPrevCrv)) {
|
|
PtrOwner<ISurfTriMesh> pSr( GetSurfTriMeshRuled( pPrevCrv, pCurrCrv, ISurfTriMesh::RLT_MINDIST, dLinTol)) ;
|
|
if ( IsNull( pSr))
|
|
return nullptr ;
|
|
|
|
// unisco
|
|
pSTM->DoSewing( *pSr) ;
|
|
}
|
|
|
|
// salvo la curva come prossima precedente
|
|
pPrevCrv.Set( pCurrCrv) ;
|
|
|
|
// prossimo punto
|
|
bPoint = PL.GetNextPoint( ptP) ;
|
|
}
|
|
|
|
// se richiesti caps e sezione chiusa e guida aperta
|
|
if ( bCapEnds && bSectClosed && ! bGuideClosed) {
|
|
|
|
// verifico che le due estremità siano chiuse e piatte
|
|
POLYLINEVECTOR vPL ;
|
|
if ( ! pSTM->GetLoops( vPL) || vPL.size() != 2)
|
|
return nullptr ;
|
|
Plane3d plEnds ; double dArea ;
|
|
if ( ! vPL[0].IsClosedAndFlat( plEnds, dArea, 100 * EPS_SMALL))
|
|
return nullptr ;
|
|
if ( ! vPL[1].IsClosedAndFlat( plEnds, dArea, 100 * EPS_SMALL))
|
|
return nullptr ;
|
|
|
|
// aggiungo il cap sull'inizio
|
|
PtrOwner<SurfTriMesh> pSci( CreateBasicSurfTriMesh()) ;
|
|
if ( IsNull( pSci) || ! pSci->CreateByFlatContour( PL))
|
|
return nullptr ;
|
|
pSci->ToGlob( frStart) ;
|
|
|
|
// unisco
|
|
pSTM->DoSewing( *pSci) ;
|
|
|
|
// riferimento alla fine della linea guida
|
|
Frame3d frEnd ;
|
|
Point3d ptEnd ;
|
|
pGuide->GetEndPoint( ptEnd) ;
|
|
Vector3d vtEnd ;
|
|
pGuide->GetEndDir( vtEnd) ;
|
|
frEnd.Set( ptEnd, -vtEnd, vtEnd ^ vtNorm) ;
|
|
|
|
// aggiungo il cap sulla fine
|
|
PtrOwner<SurfTriMesh> pSce( CreateBasicSurfTriMesh()) ;
|
|
if ( IsNull( pSce) || ! pSce->CreateByFlatContour( PL))
|
|
return nullptr ;
|
|
pSce->Invert() ;
|
|
pSce->ToGlob( frEnd) ;
|
|
|
|
// unisco
|
|
pSTM->DoSewing( *pSce) ;
|
|
}
|
|
|
|
// se superficie risultante chiusa, verifico che la normale sia verso l'esterno
|
|
double dVol ;
|
|
if ( pSTM->GetVolume( dVol) && dVol < 0)
|
|
pSTM->Invert() ;
|
|
|
|
// restituisco la superficie
|
|
return Release( pSTM) ;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
ISurfTriMesh*
|
|
GetSurfTriMeshSwept( const ISurfFlatRegion* pSfrSect, const ICurve* pGuide, bool bCapEnds,
|
|
double dLinTol, Vector3d* vtStatic)
|
|
{
|
|
// verifica dei parametri
|
|
if ( pSfrSect == nullptr || pGuide == nullptr)
|
|
return nullptr ;
|
|
|
|
// creo la Trimesh da restituire
|
|
PtrOwner<ISurfTriMesh> pStmSwept( CreateBasicSurfTriMesh()) ;
|
|
if ( IsNull( pStmSwept) || ! pStmSwept->AdjustTopology())
|
|
return nullptr ;
|
|
|
|
StmFromTriangleSoup StmSoup ;
|
|
StmSoup.Start() ;
|
|
// per ogni loop della superficie, creo una Swept
|
|
for ( int c = 0 ; c < pSfrSect->GetChunkCount() ; ++ c) {
|
|
for ( int l = 0 ; l < pSfrSect->GetLoopCount( c) ; ++ l) {
|
|
// recupero il loop
|
|
PtrOwner<ICurve> pCrvLoop( pSfrSect->GetLoop( c, l)) ;
|
|
if ( IsNull( pCrvLoop) || ! pCrvLoop->IsValid())
|
|
return nullptr ;
|
|
// creo la Trimesh Swept
|
|
PtrOwner<ISurfTriMesh> pStmLoopSwept( GetSurfTriMeshSwept( pCrvLoop, pGuide, false, dLinTol, vtStatic)) ;
|
|
if ( IsNull( pStmLoopSwept) || ! pStmLoopSwept->IsValid())
|
|
return nullptr ;
|
|
// aggiungo la Swept ricavata al risultato finale ( come triangoli )
|
|
StmSoup.AddSurfTriMesh( *pStmLoopSwept) ;
|
|
}
|
|
}
|
|
StmSoup.End() ;
|
|
if ( ! pStmSwept.Set( StmSoup.GetSurf()) || IsNull( pStmSwept) ||
|
|
! pStmSwept->IsValid() || ! pStmSwept->AdjustTopology())
|
|
return nullptr ;
|
|
|
|
|
|
// se rischista chiusura...
|
|
// NB. Controllo solo che al guida non sia chiusa, la sezione derivando da una Flatregion è chiusa per
|
|
// definizione
|
|
if ( bCapEnds && ! pGuide->IsClosed()) {
|
|
// creo il cap sull'inizio e lo attacco alla swept ( è già in posizione giusta )
|
|
PtrOwner<ISurfTriMesh> pSci( pSfrSect->GetAuxSurf()->Clone()) ;
|
|
if ( IsNull( pSci) || ! pSci->IsValid())
|
|
return nullptr ;
|
|
pStmSwept->DoSewing( *pSci) ;
|
|
// recupero i loops alla fine
|
|
POLYLINEVECTOR vPL ;
|
|
if ( ! pStmSwept->GetLoops( vPL))
|
|
return nullptr ;
|
|
// creo la superficie alla fine e la attacco
|
|
PtrOwner<ISurfTriMesh> pSce( CreateSurfTriMesh()) ;
|
|
if ( ! pSce->CreateByRegion( vPL))
|
|
return nullptr ;
|
|
// attacco la superficie finale alla swept
|
|
pSce->Invert() ;
|
|
pStmSwept->DoSewing( *pSce) ;
|
|
}
|
|
// se superficie risultante chiusa, verifico che la normale sia verso l'esterno
|
|
double dVol ;
|
|
if ( pStmSwept->GetVolume( dVol) && dVol < 0)
|
|
pStmSwept->Invert() ;
|
|
|
|
return Release( pStmSwept) ;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
ISurfTriMesh*
|
|
GetSurfTriMeshTransSwept( const ICurve* pSect, const ICurve* pGuide, bool bCapEnds, double dLinTol)
|
|
{
|
|
// verifica parametri
|
|
if ( pSect == nullptr || pGuide == nullptr)
|
|
return nullptr ;
|
|
// determino se la sezione è chiusa
|
|
bool bSectClosed = pSect->IsClosed() ;
|
|
// punto iniziale della sezione e vettore a inizio guida
|
|
Point3d ptStart ;
|
|
if ( ! pSect->GetStartPoint( ptStart))
|
|
return nullptr ;
|
|
Point3d ptGuide ;
|
|
if ( ! pGuide->GetStartPoint( ptGuide))
|
|
return nullptr ;
|
|
Vector3d vtDelta = ptStart - ptGuide ;
|
|
// calcolo la polilinea che approssima la guida
|
|
PolyLine PLG ;
|
|
if ( ! pGuide->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PLG))
|
|
return nullptr ;
|
|
// determino se la guida è chiusa
|
|
bool bGuideClosed = PLG.IsClosed() ;
|
|
// calcolo la superficie
|
|
PtrOwner<SurfTriMesh> pSTM( CreateBasicSurfTriMesh()) ;
|
|
if ( IsNull( pSTM))
|
|
return nullptr ;
|
|
// salvo tolleranza lineare usata
|
|
pSTM->SetLinearTolerance( dLinTol) ;
|
|
// superficie swept
|
|
PtrOwner<ICurve> pPrevCrv ;
|
|
Point3d ptP ;
|
|
bool bPoint = PLG.GetFirstPoint( ptP) ;
|
|
while ( bPoint) {
|
|
// nuova curva
|
|
PtrOwner<ICurve> pCurrCrv( pSect->Clone()) ;
|
|
if ( IsNull( pCurrCrv))
|
|
return nullptr ;
|
|
pCurrCrv->Translate( ptP - ptStart + vtDelta) ;
|
|
// se esiste la curva precedente, costruisco la rigata (di tipo minima distanza)
|
|
if ( ! IsNull( pPrevCrv)) {
|
|
PtrOwner<ISurfTriMesh> pSr( GetSurfTriMeshRuled( pPrevCrv, pCurrCrv, ISurfTriMesh::RLT_ISOPAR, dLinTol)) ;
|
|
if ( IsNull( pSr))
|
|
return nullptr ;
|
|
pSTM->DoSewing( *pSr) ;
|
|
}
|
|
// salvo la curva come prossima precedente
|
|
pPrevCrv.Set( pCurrCrv) ;
|
|
// prossimo punto
|
|
bPoint = PLG.GetNextPoint( ptP) ;
|
|
}
|
|
// se richiesti caps e sezione chiusa e guida aperta
|
|
if ( bCapEnds && bSectClosed && ! bGuideClosed) {
|
|
// calcolo la polilinea che approssima la sezione
|
|
PolyLine PLS ;
|
|
if ( ! pSect->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PLS))
|
|
return nullptr ;
|
|
// verifico che la sezione sia chiusa e piatta
|
|
Plane3d plSect ; double dArea ;
|
|
if ( PLS.IsClosedAndFlat( plSect, dArea, 100 * EPS_SMALL)) {
|
|
// aggiungo il cap sull'inizio
|
|
PtrOwner<SurfTriMesh> pSci( CreateBasicSurfTriMesh()) ;
|
|
if ( IsNull( pSci) || ! pSci->CreateByFlatContour( PLS))
|
|
return nullptr ;
|
|
pSci->Invert() ;
|
|
Point3d ptGi ; PLG.GetFirstPoint( ptGi) ;
|
|
pSci->Translate( ptGi - ptStart + vtDelta) ;
|
|
pSTM->DoSewing( *pSci) ;
|
|
// aggiungo il cap sulla fine
|
|
PtrOwner<SurfTriMesh> pSce( CreateBasicSurfTriMesh()) ;
|
|
if ( IsNull( pSce) || ! pSce->CreateByFlatContour( PLS))
|
|
return nullptr ;
|
|
Point3d ptGe ; PLG.GetLastPoint( ptGe) ;
|
|
pSce->Translate( ptGe - ptStart + vtDelta) ;
|
|
pSTM->DoSewing( *pSce) ;
|
|
}
|
|
}
|
|
// se superficie risultante chiusa, verifico che la normale sia verso l'esterno
|
|
double dVol ;
|
|
if ( pSTM->GetVolume( dVol) && dVol < 0)
|
|
pSTM->Invert() ;
|
|
// 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<SurfTriMesh> pSTM( CreateBasicSurfTriMesh()) ;
|
|
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, int nType, 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<SurfTriMesh> pSTM( CreateBasicSurfTriMesh()) ;
|
|
if ( IsNull( pSTM) || ! pSTM->CreateByTwoCurves( PL1, PL2, nType))
|
|
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)
|
|
{
|
|
// se non ho curve, non faccio nulla
|
|
if ( int( vpCurve.size()) == 0)
|
|
return true ;
|
|
|
|
// calcolo le polilinee che approssimano le curve
|
|
vPL.resize( vpCurve.size()) ;
|
|
for ( int i = 0 ; i < int( vpCurve.size()) ; ++ i) {
|
|
if ( ! vpCurve[i]->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, vPL[i]))
|
|
return false ;
|
|
}
|
|
|
|
// ricavo versore normale
|
|
Plane3d plPlane ; double dArea ;
|
|
if ( ! vPL[0].IsClosedAndFlat( plPlane, dArea, 50 * EPS_SMALL))
|
|
return false ;
|
|
vtN = plPlane.GetVersN() ;
|
|
|
|
typedef std::pair<int,double> INDAREA ;
|
|
std::vector<INDAREA> m_vArea ;
|
|
// calcolo piano medio e area delle curve
|
|
m_vArea.reserve( vPL.size()) ;
|
|
for ( int i = 0 ; i < int( vPL.size()) ; ++ i) {
|
|
// calcolo piano medio e area
|
|
Plane3d plPlane ;
|
|
double dArea ;
|
|
if ( ! vPL[i].IsClosedAndFlat( plPlane, dArea))
|
|
return false ;
|
|
// verifico che le normali siano molto vicine
|
|
if ( ! AreSameOrOppositeVectorApprox( plPlane.GetVersN(), vtN))
|
|
return false ;
|
|
// assegno il segno all'area secondo il verso della normale
|
|
if ( ( plPlane.GetVersN() * vtN) > 0)
|
|
m_vArea.emplace_back( i, dArea) ;
|
|
else
|
|
m_vArea.emplace_back( i, - dArea) ;
|
|
}
|
|
// ordino in senso decrescente sull'area
|
|
sort( m_vArea.begin(), m_vArea.end(),
|
|
[]( const INDAREA& a, const INDAREA& b) { return ( abs( a.second) > abs( b.second)) ; }) ;
|
|
|
|
// dalle PolyLine passo alle curve nel piano XY ( prendo la prima come riferimento, trascuro le Z delle successive)
|
|
Frame3d frRef ; frRef.Set( ORIG, vtN) ;
|
|
if ( ! frRef.IsValid())
|
|
return false ;
|
|
ICRVCOMPOPOVECTOR vCrvCompo( int( vPL.size())) ;
|
|
for ( int i = 0 ; i < int( vPL.size()) ; ++ i) {
|
|
vCrvCompo[i].Set( CreateCurveComposite()) ;
|
|
vCrvCompo[i]->FromPolyLine( vPL[i]) ;
|
|
vCrvCompo[i]->ToLoc( frRef) ;
|
|
}
|
|
|
|
// creo una matrice di interi ; ogni riga corrisponde ad un chunk, dove in posizione 0 c'è il loop esterno e nelle
|
|
// successive i loop interni
|
|
INTMATRIX vnPLIndMat ;
|
|
|
|
// vettore di indici per ordinare le PolyLine
|
|
INTVECTOR vPL_IndOrder ; vPL_IndOrder.resize( int( vPL.size())) ;
|
|
for ( int i = 0 ; i < int( m_vArea.size()) ; ++ i)
|
|
vPL_IndOrder[i] = m_vArea[i].first ;
|
|
|
|
// aggiungo le diverse curve
|
|
bool bFirstCrv ;
|
|
Plane3d plExtLoop ;
|
|
double dAreaExtLoop = 0. ;
|
|
do {
|
|
bFirstCrv = true ;
|
|
for ( int i = 0 ; i < int( m_vArea.size()) ; ++ i) {
|
|
// recupero indice di percorso e verifico sia valido
|
|
int j = m_vArea[i].first ;
|
|
if ( j < 0)
|
|
continue ;
|
|
// lo inserisco come esterno...
|
|
if ( bFirstCrv) {
|
|
vnPLIndMat.push_back({ j}) ;
|
|
m_vArea[i].first = -1 ;
|
|
dAreaExtLoop = m_vArea[i].second ;
|
|
// inverto se necessario
|
|
if ( m_vArea[i].second < EPS_SMALL) {
|
|
vPL[j].Invert() ;
|
|
vCrvCompo[j]->Invert() ;
|
|
dAreaExtLoop *= -1 ;
|
|
}
|
|
bFirstCrv = false ;
|
|
}
|
|
// ... altrimenti verifico se il loop è interno o no
|
|
else {
|
|
// il loop è interno se è sia interno al loop esterno della riga di vnPLIndMat e allo stesso tempo
|
|
// esterno a tutti i loop già inseriti nella riga attuale.
|
|
// verifica rispetto loop esterno
|
|
IntersCurveCurve ccInt( *vCrvCompo[vnPLIndMat.back().front()], *vCrvCompo[j]) ;
|
|
CRVCVECTOR ccClass ;
|
|
if ( ccInt.GetCrossOrOverlapIntersCount() > 0 ||
|
|
! ccInt.GetCurveClassification( 1, EPS_SMALL, ccClass) ||
|
|
ccClass.empty() || ccClass[0].nClass != CRVC_IN)
|
|
continue ;
|
|
// verifica rispetto ai loop interni
|
|
bool bOk = true ;
|
|
for ( int k = 1 ; k < int( vnPLIndMat.back().size()) ; ++ k) {
|
|
IntersCurveCurve ccInt2( *vCrvCompo[vnPLIndMat.back()[k]], *vCrvCompo[j]) ;
|
|
CRVCVECTOR ccClass2 ;
|
|
if ( ccInt2.GetCrossOrOverlapIntersCount() > 0 ||
|
|
! ccInt2.GetCurveClassification( 1, EPS_SMALL, ccClass2) ||
|
|
ccClass2.empty() || ccClass2[0].nClass != CRVC_IN) {
|
|
bOk = false ;
|
|
break ;
|
|
}
|
|
}
|
|
if ( bOk) {
|
|
// inserisco nella matrice
|
|
vnPLIndMat.back().push_back( j) ;
|
|
m_vArea[i].first = -1 ;
|
|
// inverto se necessario
|
|
if ( m_vArea[i].second * dAreaExtLoop > 0.) {
|
|
vPL[j].Invert() ;
|
|
vCrvCompo[j]->Invert() ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} while ( ! bFirstCrv) ;
|
|
|
|
// ordino le PolyLine per area
|
|
POLYLINEVECTOR vPL_tmp ;
|
|
for ( int i = 0 ; i < int( vPL_IndOrder.size()) ; ++ i)
|
|
vPL_tmp.push_back( vPL[ vPL_IndOrder[i]]) ;
|
|
swap( vPL, vPL_tmp) ;
|
|
|
|
return true ;
|
|
}
|