119bbe0bcb
- prime migliorie nella creazione di solidi swept con sezione rettangolare e bevel ( prima versione, da sistemare caps flat e none) - correzione in Voronoi.
2038 lines
81 KiB
C++
2038 lines
81 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 "IntersLineLine.h"
|
|
#include "/EgtDev/Include/EGkSfrCreate.h"
|
|
#include "/EgtDev/Include/EGkOffsetCurve.h"
|
|
#include "/EgtDev/Include/EGkStmFromCurves.h"
|
|
#include "/EgtDev/Include/EGkStmFromTriangleSoup.h"
|
|
#include "/EgtDev/Include/EGkRotationMinimizingFrame.h"
|
|
#include "/EgtDev/Include/EGkRotationXplaneFrame.h"
|
|
#include "/EgtDev/Include/EGkIntersCurves.h"
|
|
#include "/EgtDev/Include/EGkDistPointCurve.h"
|
|
#include "/EgtDev/Include/EgtPointerOwner.h"
|
|
#include <future>
|
|
|
|
using namespace std ;
|
|
|
|
|
|
//-------------------------------------------------------------------------------
|
|
// costanti per SurfTmRectSwept
|
|
static const int STM_RECTSWEPT_FLATCAP_START = -1 ;
|
|
static const int STM_RECTSWEPT_FLATCAP_END = -2 ;
|
|
static const int STM_RECTSWEPT_LINK = -3 ;
|
|
static const int STM_RECTSWEPT_FLATCAP_EXTRA = -4 ;
|
|
|
|
|
|
//-------------------------------------------------------------------------------
|
|
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 ;
|
|
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 nullptr ;
|
|
}
|
|
Vector3d vtN ;
|
|
INTMATRIX vnPLIndMat ;
|
|
BOOLVECTOR vbInvert ;
|
|
if ( ! CalcRegionPolyLines( vPL, vtN, vnPLIndMat, vbInvert))
|
|
return nullptr ;
|
|
for ( int i = 0 ; i < int( vnPLIndMat.size()) ; ++i) {
|
|
for ( int j = 0 ; j < int( vnPLIndMat[i].size()) ; ++j){
|
|
if ( vbInvert[vnPLIndMat[i][j]])
|
|
vPL[vnPLIndMat[i][j]].Invert() ;
|
|
}
|
|
}
|
|
// creo e setto la superficie trimesh
|
|
PtrOwner<SurfTriMesh> pSTM( CreateBasicSurfTriMesh()) ;
|
|
if ( IsNull( pSTM) || ! pSTM->CreateByRegion( vPL, vnPLIndMat))
|
|
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 ;
|
|
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 nullptr ;
|
|
}
|
|
Vector3d vtN ;
|
|
INTMATRIX vnPLIndMat ;
|
|
BOOLVECTOR vbInvert ;
|
|
if ( ! CalcRegionPolyLines( vPL, vtN, vnPLIndMat, vbInvert))
|
|
return nullptr ;
|
|
for ( int i = 0 ; i < int( vPL.size()) ; ++i) {
|
|
if ( vbInvert[i])
|
|
vPL[i].Invert() ;
|
|
}
|
|
// 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()) ;
|
|
// alla funzione CreateByRegion passo anche la matrice che contiene la struttura dei chunk. Le polyline hanno già il verso giusto
|
|
if ( IsNull( pSTM) || ! pSTM->CreateByRegion( vPL, vnPLIndMat))
|
|
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 bool
|
|
RemoveFatCurveJunctions( ICURVEPOVECTOR& vCrvs)
|
|
{
|
|
ICURVEPOVECTOR vResCurves ;
|
|
for ( int i = 0 ; i < ssize( vCrvs) ; i ++) {
|
|
int nStart = ssize( vResCurves) ;
|
|
CurveComposite* pFatCrv = GetBasicCurveComposite( vCrvs[i]) ;
|
|
if ( pFatCrv == nullptr)
|
|
return false ;
|
|
PtrOwner<CurveComposite> pCrv( CreateBasicCurveComposite()) ;
|
|
if ( IsNull( pCrv))
|
|
return false ;
|
|
PtrOwner<ICurve> pCurrCrv( pFatCrv->RemoveFirstOrLastCurve( false)) ;
|
|
while ( ! IsNull( pCurrCrv)) {
|
|
if ( abs( pCurrCrv->GetTempParam() - VRONI_JUNCTION_OPEN) < EPS_SMALL) {
|
|
if ( pCrv->IsValid()) {
|
|
// salvo la catena trovata fino ad ora e la resetto
|
|
vResCurves.emplace_back( Release( pCrv)) ;
|
|
pCrv.Set( CreateBasicCurveComposite()) ;
|
|
if ( IsNull( pCrv))
|
|
return false ;
|
|
}
|
|
}
|
|
else {
|
|
// aggiungo la curva alla catena corrente
|
|
pCrv->AddCurve( Release( pCurrCrv)) ;
|
|
}
|
|
pCurrCrv.Set( pFatCrv->RemoveFirstOrLastCurve( false)) ;
|
|
}
|
|
if ( pCrv->IsValid()) {
|
|
if ( ssize( vResCurves) != nStart) {
|
|
// verifico se da concatenare alla prima
|
|
Point3d ptEnd ; pCrv->GetEndPoint( ptEnd) ;
|
|
Point3d ptStart ; vResCurves[nStart]->GetStartPoint( ptStart) ;
|
|
if ( AreSamePointApprox( ptStart, ptEnd)) {
|
|
ICurveComposite* pCompo = GetBasicCurveComposite( vResCurves[nStart]) ;
|
|
if ( pCompo == nullptr)
|
|
return false ;
|
|
pCompo->AddCurve( Release( pCrv), false) ;
|
|
}
|
|
else
|
|
vResCurves.emplace_back( Release( pCrv)) ;
|
|
}
|
|
else
|
|
vResCurves.emplace_back( Release( pCrv)) ;
|
|
}
|
|
}
|
|
swap( vResCurves, vCrvs) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
static ISurfFlatRegion*
|
|
CalcSweptSurface( ICurveComposite* pGuide, const Vector3d& vtNorm, double dOffs)
|
|
{
|
|
PtrOwner<ISurfFlatRegion> pSrf( CreateSurfFlatRegion()) ;
|
|
if ( IsNull( pSrf))
|
|
return nullptr ;
|
|
|
|
// per ogni sottotratto della guida calcolo la regione spazzata dalla sezione su quel tratto
|
|
for ( int i = 0 ; i < pGuide->GetCurveCount() ; i ++) {
|
|
PtrOwner<ICurve> pCrv( pGuide->GetCurve( i)->Clone()) ;
|
|
pCrv->SetExtrusion( vtNorm) ;
|
|
if ( pCrv->SimpleOffset( - dOffs)) {
|
|
PtrOwner<ICurveComposite> pBorder( CreateCurveComposite()) ;
|
|
if ( IsNull( pBorder))
|
|
return nullptr ;
|
|
pBorder->AddCurve( pGuide->GetCurve( i)->Clone()) ;
|
|
pCrv->Invert() ;
|
|
Point3d ptS ; pCrv->GetStartPoint( ptS) ;
|
|
pBorder->AddLine( ptS) ;
|
|
pBorder->AddCurve( Release( pCrv)) ;
|
|
pBorder->Close() ;
|
|
|
|
if ( ! pSrf->IsValid()) {
|
|
pSrf->AddExtLoop( Release( pBorder)) ;
|
|
}
|
|
else {
|
|
PtrOwner<ISurfFlatRegion> pSrfTmp( CreateSurfFlatRegion()) ;
|
|
if ( IsNull( pSrfTmp))
|
|
return nullptr ;
|
|
pSrfTmp->AddExtLoop( Release( pBorder)) ;
|
|
pSrf->Add( *pSrfTmp) ;
|
|
}
|
|
}
|
|
else {
|
|
// se arco che collassa devo costruire separatamente i due spicchi
|
|
ICurveArc* pArc = GetCurveArc( pCrv) ;
|
|
if ( pArc == nullptr)
|
|
return nullptr ;
|
|
|
|
Point3d ptC = pArc->GetCenter() ;
|
|
Point3d ptS ; pArc->GetStartPoint( ptS) ;
|
|
Vector3d vtS = ptC - ptS ;
|
|
vtS.Normalize() ;
|
|
Point3d ptS2 = ptS + vtS * dOffs ;
|
|
|
|
Point3d ptE ; pArc->GetEndPoint( ptE) ;
|
|
Vector3d vtE = ptC - ptE ;
|
|
vtE.Normalize() ;
|
|
Point3d ptE2 = ptE + vtE * dOffs ;
|
|
|
|
PtrOwner<ICurveArc> pArc2( CreateCurveArc()) ;
|
|
if ( IsNull( pArc2) || ! pArc2->SetC2PN( ptC, ptS2, ptE2, vtNorm))
|
|
return nullptr ;
|
|
|
|
PtrOwner<ICurveComposite> pBorder1( CreateCurveComposite()) ;
|
|
if ( IsNull( pBorder1))
|
|
return nullptr ;
|
|
pBorder1->AddPoint( ptC) ;
|
|
pBorder1->AddLine( ptS) ;
|
|
pBorder1->AddCurve( Release( pCrv)) ;
|
|
pBorder1->Close() ;
|
|
|
|
PtrOwner<ICurveComposite> pBorder2( CreateCurveComposite()) ;
|
|
if ( IsNull( pBorder2))
|
|
return nullptr ;
|
|
pBorder2->AddPoint( ptC) ;
|
|
pBorder2->AddLine( ptS2) ;
|
|
pBorder2->AddCurve( Release( pArc2)) ;
|
|
pBorder2->Close() ;
|
|
|
|
PtrOwner<ISurfFlatRegion> pSrfTmp2( CreateSurfFlatRegion()) ;
|
|
if ( IsNull( pSrfTmp2))
|
|
return nullptr ;
|
|
pSrfTmp2->AddExtLoop( Release( pBorder2)) ;
|
|
|
|
if ( ! pSrf->IsValid()) {
|
|
pSrf->AddExtLoop( Release( pBorder1)) ;
|
|
pSrf->Add( *pSrfTmp2) ;
|
|
}
|
|
else {
|
|
PtrOwner<ISurfFlatRegion> pSrfTmp1( CreateSurfFlatRegion()) ;
|
|
if ( IsNull( pSrfTmp1))
|
|
return nullptr ;
|
|
pSrfTmp1->AddExtLoop( Release( pBorder1)) ;
|
|
pSrf->Add( *pSrfTmp1) ;
|
|
pSrf->Add( *pSrfTmp2) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
return Release( pSrf) ;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
static bool
|
|
AdjustSurfTriMeshRectSweptCaps( int nCapType, ICURVEPOVECTOR& vCrvs, const Vector3d& vtNorm, const ICurve* pOrigGuide, double dOffs)
|
|
{
|
|
// se RSCAP_FLAT trasformo tutte le giunzioni relative agli estremi in linee controllando se necessario chiudere le curve
|
|
// con opportuni tratti di offset.
|
|
// RSCAP_NONE viene gestito allo stesso modo perchè per la superficie top e bottom servono curve chiuse, le curve
|
|
// di giunzione saranno rimosse successivamente per il calcolo della superficie laterale
|
|
if ( nCapType == RSCAP_FLAT || nCapType == RSCAP_NONE) {
|
|
|
|
// spezzo le curve in corrispondenza delle junctions
|
|
RemoveFatCurveJunctions( vCrvs) ;
|
|
|
|
// creo le linee di junction sugli estremi della giuda ( j = 0 start, j = 1 end)
|
|
for ( int j = 0 ; j < 2 ; j ++) {
|
|
Point3d ptP ;
|
|
Vector3d vtDir ;
|
|
if ( j == 0) {
|
|
pOrigGuide->GetStartPoint( ptP) ;
|
|
pOrigGuide->GetStartDir( vtDir) ;
|
|
}
|
|
else {
|
|
pOrigGuide->GetEndPoint( ptP) ;
|
|
pOrigGuide->GetEndDir( vtDir) ;
|
|
}
|
|
vtDir.Rotate( vtNorm, ANG_RIGHT) ;
|
|
Point3d pt1 = ptP + dOffs * vtDir ;
|
|
Point3d pt2 = ptP - dOffs * vtDir ;
|
|
|
|
// cerco su quali curve poggia la linea di junction
|
|
int nCrv1 = -1 ; bool bStart1 = true ;
|
|
int nCrv2 = -1 ; bool bStart2 = true ;
|
|
for ( int i = 0 ; i < ssize( vCrvs) ; i ++) {
|
|
Point3d ptS ; vCrvs[i]->GetStartPoint( ptS) ;
|
|
Point3d ptE ; vCrvs[i]->GetEndPoint( ptE) ;
|
|
if ( AreSamePointEpsilon( ptS, pt1, 10 * EPS_SMALL)) {
|
|
nCrv1 = i ;
|
|
bStart1 = true ;
|
|
}
|
|
else if ( AreSamePointEpsilon( ptS, pt2, 10 * EPS_SMALL)) {
|
|
nCrv2 = i ;
|
|
bStart2 = true ;
|
|
}
|
|
if ( AreSamePointEpsilon( ptE, pt1, 10 * EPS_SMALL)) {
|
|
nCrv1 = i ;
|
|
bStart1 = false ;
|
|
}
|
|
else if ( AreSamePointEpsilon( ptE, pt2, 10 * EPS_SMALL)) {
|
|
nCrv2 = i ;
|
|
bStart2 = false ;
|
|
}
|
|
}
|
|
int nFlatCapProp = ( j == 0 ? STM_RECTSWEPT_FLATCAP_START : STM_RECTSWEPT_FLATCAP_END) ;
|
|
|
|
// se congiunge due curve le unisco
|
|
if ( nCrv1 != -1 && nCrv2 != -1) {
|
|
if ( nCrv1 == nCrv2) {
|
|
// se è la stessa curva la chiudo semplicemente con una linea
|
|
ICurveComposite* pCompo = GetCurveComposite( vCrvs[nCrv1]) ;
|
|
if ( pCompo == nullptr)
|
|
return false ;
|
|
pCompo->Close() ;
|
|
pCompo->SetCurveTempProp( pCompo->GetCurveCount() - 1, nFlatCapProp) ;
|
|
}
|
|
else {
|
|
int nFirst = ( bStart1 ? nCrv2 : nCrv1) ;
|
|
int nSecond = ( bStart1 ? nCrv1 : nCrv2) ;
|
|
ICurveComposite* pCompo = GetCurveComposite( vCrvs[nFirst]) ;
|
|
if ( pCompo == nullptr)
|
|
return false ;
|
|
Point3d ptRef ; vCrvs[nSecond]->GetStartPoint( ptRef) ;
|
|
pCompo->AddLine( ptRef) ;
|
|
pCompo->SetCurveTempProp( pCompo->GetCurveCount() - 1, nFlatCapProp) ;
|
|
pCompo->AddCurve( Release( vCrvs[nSecond])) ;
|
|
// elimino la curva mergiata dal vettore
|
|
swap( vCrvs[nSecond], vCrvs.back()) ;
|
|
vCrvs.pop_back() ;
|
|
}
|
|
}
|
|
|
|
// se non congiunge due curve aggiungo il tratto lineare libero sull'estremo
|
|
else {
|
|
if ( nCrv1 != -1) {
|
|
ICurveComposite* pCompo = GetCurveComposite( vCrvs[nCrv1]) ;
|
|
if ( pCompo == nullptr)
|
|
return false ;
|
|
pCompo->AddLine( pt2, ! bStart1) ;
|
|
int nSubCrv = ( bStart1 ? 0 : pCompo->GetCurveCount() - 1) ;
|
|
pCompo->SetCurveTempProp( nSubCrv, nFlatCapProp) ;
|
|
}
|
|
else if ( nCrv2 != -1) {
|
|
ICurveComposite* pCompo = GetCurveComposite( vCrvs[nCrv2]) ;
|
|
if ( pCompo == nullptr)
|
|
return false ;
|
|
pCompo->AddLine( pt1, ! bStart2) ;
|
|
int nSubCrv = ( bStart2 ? 0 : pCompo->GetCurveCount() - 1) ;
|
|
pCompo->SetCurveTempProp( nSubCrv, nFlatCapProp) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// controllo chiusura di tutte le curve
|
|
for ( int i = 0 ; i < ssize( vCrvs) ; i++) {
|
|
if ( ! vCrvs[i]->IsClosed()) {
|
|
|
|
ICurveComposite* pCompo = GetCurveComposite( vCrvs[i]) ;
|
|
if ( pCompo == nullptr)
|
|
return false ;
|
|
double dTempProp1 = pCompo->GetFirstCurve()->GetTempProp() ;
|
|
double dTempProp2 = pCompo->GetLastCurve()->GetTempProp() ;
|
|
|
|
// verifico se necessaria inversione della guida per renderla coerente con la fat curve
|
|
bool bInvert = false ;
|
|
if ( dTempProp1 < 0 || dTempProp2 < 0) {
|
|
bInvert = ( dTempProp1 == STM_RECTSWEPT_FLATCAP_END || dTempProp2 == STM_RECTSWEPT_FLATCAP_START) ;
|
|
}
|
|
else {
|
|
Point3d ptS ; pCompo->GetStartPoint( ptS) ;
|
|
DistPointCurve distPC( ptS, *pOrigGuide) ;
|
|
int nSide = 0 ;
|
|
distPC.GetSideAtMinDistPoint( 0, vtNorm, nSide) ;
|
|
bInvert = ( nSide == MDS_RIGHT) ;
|
|
}
|
|
|
|
// ricavo la superficie spazzata dalla guida
|
|
PtrOwner<ICurveComposite> pGuide( ConvertCurveToComposite( pOrigGuide->Clone())) ;
|
|
if ( bInvert)
|
|
pGuide->Invert() ;
|
|
PtrOwner<ISurfFlatRegion> pSurf( CalcSweptSurface( pGuide, vtNorm, dOffs)) ;
|
|
|
|
// verifico come trimmare
|
|
bool bTrimStart = false ;
|
|
bool bTrimEnd = false ;
|
|
if ( dTempProp1 < 0 && dTempProp2 >= 0)
|
|
bTrimStart = true ;
|
|
else if ( dTempProp1 >= 0 && dTempProp2 < 0)
|
|
bTrimEnd = true ;
|
|
else if ( dTempProp1 < 0 && dTempProp2 < 0) {
|
|
bTrimStart = true ;
|
|
bTrimEnd = true ;
|
|
}
|
|
|
|
// recupero il loop opportuno
|
|
PtrOwner<ICurveComposite> pBorder( ConvertCurveToComposite( pSurf->GetLoop( 0, 0))) ;
|
|
if ( pSurf->GetChunkCount() > 1) {
|
|
Point3d ptRef ; pCompo->GetStartPoint( ptRef) ;
|
|
if ( bTrimStart)
|
|
pCompo->GetEndPoint( ptRef) ;
|
|
for ( int j = 0 ; j < pSurf->GetChunkCount() ; j ++) {
|
|
pBorder.Set( ConvertCurveToComposite( pSurf->GetLoop( j, 0))) ;
|
|
if ( pBorder->IsPointOn( ptRef))
|
|
break ;
|
|
}
|
|
}
|
|
|
|
double dPar1, dPar2 ;
|
|
if ( ! bTrimStart && ! bTrimEnd) {
|
|
Point3d ptS ; pCompo->GetStartPoint( ptS) ;
|
|
Point3d ptE ; pCompo->GetEndPoint( ptE) ;
|
|
pBorder->GetParamAtPoint( ptE, dPar1) ;
|
|
pBorder->GetParamAtPoint( ptS, dPar2) ;
|
|
}
|
|
else if ( bTrimStart && bTrimEnd) {
|
|
|
|
const CurveLine* pLineS = GetBasicCurveLine( pCompo->GetFirstCurve()) ;
|
|
const CurveLine* pLineE = GetBasicCurveLine( pCompo->GetLastCurve()) ;
|
|
|
|
if ( pLineS == nullptr || pLineE == nullptr)
|
|
return false ;
|
|
|
|
IntersLineLine intLL( *pLineS, *pLineE) ;
|
|
if ( intLL.GetNumInters() > 0) {
|
|
IntCrvCrvInfo aInfo ;
|
|
intLL.GetIntCrvCrvInfo( aInfo) ;
|
|
pCompo->TrimStartEndAtParam( aInfo.IciA[0].dU, pCompo->GetCurveCount() - 1 + aInfo.IciB[0].dU) ;
|
|
continue ;
|
|
}
|
|
else {
|
|
// da fare in frame locale
|
|
IntersCurveCurve intCC( *pLineS, *pBorder) ;
|
|
IntCrvCrvInfo aInfo ;
|
|
intCC.GetIntCrvCrvInfo( intCC.GetIntersCount() - 1, aInfo) ;
|
|
dPar2 = aInfo.IciB[0].dU ;
|
|
pCompo->TrimStartAtParam( aInfo.IciA[0].dU) ;
|
|
|
|
IntersCurveCurve intCC2( *pLineE, *pBorder) ;
|
|
intCC2.GetIntCrvCrvInfo( 0, aInfo) ;
|
|
dPar1 = aInfo.IciB[0].dU ;
|
|
|
|
pCompo->TrimEndAtParam( pCompo->GetCurveCount() - 1 + aInfo.IciA[0].dU) ;
|
|
}
|
|
}
|
|
else if ( bTrimStart) {
|
|
Point3d ptE ; pCompo->GetEndPoint( ptE) ;
|
|
pBorder->GetParamAtPoint( ptE, dPar1) ;
|
|
|
|
// intersezione con lo start
|
|
const ICurve* pLine = pCompo->GetFirstCurve() ;
|
|
IntersCurveCurve intCC( *pLine, *pBorder) ;
|
|
IntCrvCrvInfo aInfo ;
|
|
intCC.GetIntCrvCrvInfo( intCC.GetIntersCount() - 1, aInfo) ;
|
|
dPar2 = aInfo.IciB[0].dU ;
|
|
|
|
pCompo->TrimStartAtParam( aInfo.IciA[0].dU) ;
|
|
}
|
|
else {
|
|
Point3d ptS ; pCompo->GetStartPoint( ptS) ;
|
|
pBorder->GetParamAtPoint( ptS, dPar2) ;
|
|
|
|
// intersezione con end
|
|
const ICurve* pLine = pCompo->GetLastCurve() ;
|
|
IntersCurveCurve intCC( *pLine, *pBorder) ;
|
|
IntCrvCrvInfo aInfo ;
|
|
intCC.GetIntCrvCrvInfo( 0, aInfo) ;
|
|
dPar1 = aInfo.IciB[0].dU ;
|
|
|
|
pCompo->TrimEndAtParam( pCompo->GetCurveCount() - 1 + aInfo.IciA[0].dU) ;
|
|
}
|
|
|
|
pBorder->TrimStartEndAtParam( dPar1, dPar2) ;
|
|
// setto temp param per identificarli
|
|
for ( int j = 0 ; j < pBorder->GetCurveCount() ; j++) {
|
|
pBorder->SetCurveTempProp( j, STM_RECTSWEPT_FLATCAP_EXTRA) ;
|
|
}
|
|
|
|
pCompo->AddCurve( Release( pBorder)) ;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// se RSCAP_BEVEL approssimo tutte le junction relative agli estremi
|
|
else if ( nCapType == RSCAP_BEVEL) {
|
|
double dStepRotDeg = ANG_STRAIGHT / 4 ; // tolleranza
|
|
for ( int i = 0 ; i < ssize( vCrvs) ; i ++) {
|
|
CurveComposite* pFatCrv = GetBasicCurveComposite( vCrvs[i]) ;
|
|
if ( pFatCrv == nullptr)
|
|
return false ;
|
|
PtrOwner<CurveComposite> pNewCrv( CreateBasicCurveComposite()) ;
|
|
if ( IsNull( pNewCrv))
|
|
return false ;
|
|
PtrOwner<ICurve> pCurrCrv( pFatCrv->RemoveFirstOrLastCurve( false)) ;
|
|
while ( ! IsNull( pCurrCrv)) {
|
|
if ( pCurrCrv->GetTempParam() > EPS_SMALL) {
|
|
// sostituisco con la sua approssimazione
|
|
CurveComposite* ccTemp = CreateBasicCurveComposite() ;
|
|
CurveArc* pArc = GetBasicCurveArc( pCurrCrv) ;
|
|
if ( pArc == nullptr || ccTemp == nullptr)
|
|
return false ;
|
|
int nStep = max( 1, static_cast<int>( ceil( pArc->GetAngCenter() / dStepRotDeg))) ;
|
|
for ( int j = 0 ; j <= nStep ; ++ j) {
|
|
Point3d ptArc ;
|
|
pArc->GetPointD1D2( (double)j / nStep, ICurve::FROM_MINUS, ptArc) ;
|
|
if ( j == 0)
|
|
ccTemp->AddPoint( ptArc) ;
|
|
else
|
|
ccTemp->AddLine( ptArc) ;
|
|
}
|
|
pNewCrv->AddCurve( ccTemp) ;
|
|
}
|
|
else {
|
|
// aggiungo la curva
|
|
pNewCrv->AddCurve( Release( pCurrCrv)) ;
|
|
}
|
|
// passo alla curva successiva
|
|
pCurrCrv.Set( pFatCrv->RemoveFirstOrLastCurve( false)) ;
|
|
}
|
|
vCrvs[i].Set( pNewCrv) ;
|
|
}
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
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, true, 10 * EPS_SMALL))
|
|
return nullptr ;
|
|
Vector3d vtNorm ; pGuide->GetExtrusion( vtNorm) ;
|
|
if ( vtNorm.IsSmall())
|
|
vtNorm = Z_AX ;
|
|
// determino se la guida è chiusa
|
|
bool bGuideClosed = pGuide->IsClosed() ;
|
|
|
|
// calcolo fat curve
|
|
ICURVEPOVECTOR vFatCrvs ;
|
|
if ( ! CalcCurveFatCurve( *pGuide, vFatCrvs, dDimH / 2, false, false))
|
|
return nullptr ;
|
|
|
|
// se necessario modifico i caps sugli estremi
|
|
if ( ! bGuideClosed) {
|
|
if ( ! AdjustSurfTriMeshRectSweptCaps( nCapType, vFatCrvs, vtNorm, pGuide, dDimH / 2))
|
|
return nullptr ;
|
|
}
|
|
|
|
PtrOwner<ISurfTriMesh> pSTM ;
|
|
if ( nCapType == RSCAP_NONE && ! bGuideClosed) {
|
|
// se nessun cap devo costruire separatamente le superfici top/bottom e quelle laterali
|
|
CICURVEPVECTOR vTopCurves ; vTopCurves.reserve( vFatCrvs.size()) ;
|
|
for ( int i = 0 ; i < ssize( vFatCrvs) ; i ++)
|
|
vTopCurves.emplace_back( vFatCrvs[i]) ;
|
|
PtrOwner<ISurfTriMesh> pSrfTop( GetSurfTriMeshByRegion( vTopCurves, dLinTol)) ;
|
|
if ( IsNull( pSrfTop))
|
|
return nullptr ;
|
|
PtrOwner<ISurfTriMesh> pSrfBot( pSrfTop->Clone()) ;
|
|
if ( IsNull( pSrfBot))
|
|
return nullptr ;
|
|
pSrfBot->Translate( -dDimV * vtNorm) ;
|
|
pSrfBot->Invert() ;
|
|
|
|
int nBuckets = max( 4 * ( pSrfTop->GetVertexSize()), 1000) ;
|
|
StmFromTriangleSoup stmSoup ;
|
|
if ( ! stmSoup.Start( nBuckets))
|
|
return nullptr ;
|
|
stmSoup.AddSurfTriMesh( *pSrfTop) ;
|
|
stmSoup.AddSurfTriMesh( *pSrfBot) ;
|
|
|
|
// rimuovo le giunzioni per costruire le superfici laterali
|
|
if ( ! RemoveFatCurveJunctions( vFatCrvs))
|
|
return nullptr ;
|
|
for ( int i = 0 ; i < ssize( vFatCrvs) ; i ++) {
|
|
PtrOwner<ISurfTriMesh> pSrfLat( GetSurfTriMeshByExtrusion( vFatCrvs[i], -dDimV * vtNorm, false, dLinTol)) ;
|
|
if ( IsNull( pSrfLat))
|
|
return nullptr ;
|
|
pSrfLat->Invert() ;
|
|
stmSoup.AddSurfTriMesh( *pSrfLat) ;
|
|
}
|
|
if ( ! stmSoup.End())
|
|
return nullptr ;
|
|
pSTM.Set( stmSoup.GetSurf()) ;
|
|
}
|
|
else {
|
|
// costruisco la superficie per estrusione dalle fat curve
|
|
CICURVEPVECTOR vCurves ; vCurves.reserve( vFatCrvs.size()) ;
|
|
for ( int i = 0 ; i < ssize( vFatCrvs) ; i ++)
|
|
vCurves.emplace_back( vFatCrvs[i]) ;
|
|
pSTM.Set( GetSurfTriMeshByRegionExtrusion( vCurves, - dDimV * vtNorm, dLinTol)) ;
|
|
}
|
|
|
|
if ( IsNull( pSTM))
|
|
return nullptr ;
|
|
// salvo tolleranza lineare usata e imposto angolo per smooth
|
|
pSTM->SetLinearTolerance( dLinTol) ;
|
|
pSTM->SetSmoothAngle( 20) ;
|
|
// restituisco la superficie
|
|
return Release( pSTM) ;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
static ICurveComposite*
|
|
Connect( const ICurve* pGuide, ICURVEPOVECTOR& vCrvs, const INTVECTOR& vIdx, double dRadius, double dBevelH, double dBevelV,
|
|
const Vector3d& vtNorm, int nCapType)
|
|
{
|
|
double dChainTol = 50 * EPS_SMALL ;
|
|
double dOffsMin = 0.5 * dRadius - dBevelH ;
|
|
double dOffsMax = 0.5 * dRadius ;
|
|
|
|
// calcolo il medial axis e conservo solo le porzioni interne alla regione tra i due offset
|
|
ICURVEPOVECTOR vMedialAxis ;
|
|
CalcCurveMedialAxis( *pGuide, vMedialAxis, 0) ;
|
|
ICRVCOMPOPOVECTOR vMedialCrvs ;
|
|
for ( int i = 0 ; i < ssize( vMedialAxis) ; i ++) {
|
|
double dPar1 = vMedialAxis[i]->GetTempParam( 0) ;
|
|
double dPar2 = vMedialAxis[i]->GetTempParam( 1) ;
|
|
|
|
// se non comprende l'offset non va considerato
|
|
if ( dPar1 > dOffsMax - EPS_SMALL || dPar2 < dOffsMin + EPS_SMALL)
|
|
continue ;
|
|
|
|
if ( dOffsMin - EPS_SMALL < dPar1 && dPar2 < dOffsMax + EPS_SMALL) {
|
|
// tratto va conservato completamente
|
|
vMedialCrvs.emplace_back( ConvertCurveToComposite( Release( vMedialAxis[i]))) ;
|
|
}
|
|
else {
|
|
// determino la parte compresa tra gli offset massimo e minimo
|
|
if ( vMedialAxis[i]->GetType() == CRV_LINE) {
|
|
double dTrimParS = ( dOffsMin - dPar1) / ( dPar2 - dPar1) ;
|
|
double dTrimParE = ( dOffsMax - dPar1) / ( dPar2 - dPar1) ;
|
|
dTrimParS = clamp( dTrimParS, 0.0, 1.0) ;
|
|
dTrimParE = clamp( dTrimParE, 0.0, 1.0) ;
|
|
vMedialAxis[i]->TrimStartEndAtParam( dTrimParS, dTrimParE) ;
|
|
if ( dTrimParS > EPS_SMALL)
|
|
vMedialAxis[i]->SetTempParam( dOffsMin, 0) ;
|
|
if ( dTrimParE < 1 - EPS_SMALL)
|
|
vMedialAxis[i]->SetTempParam( dOffsMax, 1) ;
|
|
vMedialCrvs.emplace_back( ConvertCurveToComposite( Release( vMedialAxis[i]))) ;
|
|
}
|
|
else {
|
|
ICurveComposite* pCompo = GetCurveComposite( vMedialAxis[i]) ;
|
|
if ( pCompo == nullptr)
|
|
return nullptr ;
|
|
double dS, dE ; pCompo->GetDomain( dS, dE) ;
|
|
double dTrimParS = dS ;
|
|
double dTrimParE = dE ;
|
|
for ( int j = 0 ; j < pCompo->GetCurveCount() ; j ++) {
|
|
double dPar1 = pCompo->GetCurve( j)->GetTempParam( 0) ;
|
|
double dPar2 = pCompo->GetCurve( j)->GetTempParam( 1) ;
|
|
if ( dPar1 - EPS_SMALL < dOffsMin && dOffsMin < dPar2 + EPS_SMALL)
|
|
dTrimParS = j + ( dOffsMin - dPar1) / ( dPar2 - dPar1) ;
|
|
if ( dPar1 - EPS_SMALL < dOffsMax && dOffsMax < dPar2 + EPS_SMALL) {
|
|
dTrimParE = j + ( dOffsMax - dPar1) / ( dPar2 - dPar1) ;
|
|
break ;
|
|
}
|
|
}
|
|
dTrimParS = clamp( dTrimParS, 0.0, dE) ;
|
|
dTrimParE = clamp( dTrimParE, 0.0, dE) ;
|
|
pCompo->TrimStartEndAtParam( dTrimParS, dTrimParE) ;
|
|
if ( dTrimParS > EPS_SMALL)
|
|
pCompo->SetCurveTempParam( 0, dOffsMin, 0) ;
|
|
if ( dTrimParE < dE - EPS_SMALL)
|
|
pCompo->SetCurveTempParam( pCompo->GetCurveCount() - 1, dOffsMax, 1) ;
|
|
vMedialCrvs.emplace_back( ConvertCurveToComposite( Release( vMedialAxis[i]))) ;
|
|
}
|
|
}
|
|
|
|
// aggiusto la quota
|
|
if ( vMedialCrvs.back()->GetCurveCount() == 1) {
|
|
double dPar1 = vMedialCrvs.back()->GetTempParam( 0) ;
|
|
double dPar2 = vMedialCrvs.back()->GetTempParam( 1) ;
|
|
Point3d ptS, ptE ;
|
|
vMedialCrvs.back()->GetStartPoint( ptS) ;
|
|
vMedialCrvs.back()->GetEndPoint( ptE) ;
|
|
double dDeltaS = - dBevelV / dBevelH * ( dPar1 - dOffsMin) ;
|
|
double dDeltaE = - dBevelV / dBevelH * ( dPar2 - dOffsMin) ;
|
|
vMedialCrvs.back()->ModifyStart( ptS + vtNorm * dDeltaS) ;
|
|
vMedialCrvs.back()->ModifyEnd( ptE + vtNorm * dDeltaE) ;
|
|
}
|
|
else {
|
|
for ( int j = 0 ; j < vMedialCrvs.back()->GetCurveCount() ; j ++) {
|
|
double dPar = vMedialCrvs.back()->GetCurve( j)->GetTempParam( 0) ;
|
|
Point3d ptJ ;
|
|
vMedialCrvs.back()->GetPointD1D2( j, ICurve::FROM_MINUS, ptJ) ;
|
|
double dDelta = - dBevelV / dBevelH * ( dPar - dOffsMin) ;
|
|
vMedialCrvs.back()->ModifyJoint( j, ptJ + vtNorm * dDelta) ;
|
|
}
|
|
Point3d ptE ; vMedialCrvs.back()->GetEndPoint( ptE) ;
|
|
double dPar = vMedialCrvs.back()->GetLastCurve()->GetTempParam( 1) ;
|
|
double dDelta = - dBevelV / dBevelH * ( dPar - dOffsMin) ;
|
|
vMedialCrvs.back()->ModifyEnd( ptE + vtNorm * dDelta) ;
|
|
}
|
|
}
|
|
|
|
// chain dei medialaxis
|
|
GetChainedCurves( vMedialCrvs, 5 * EPS_SMALL, true) ;
|
|
|
|
// se cap flat aggiungo tratti sugli estremi
|
|
if ( nCapType == RSCAP_FLAT) {
|
|
|
|
Frame3d frLoc ; frLoc.Set( ORIG, vtNorm) ;
|
|
|
|
for ( int i = 0 ; i < 2 ; i ++) {
|
|
// recupero il tratto start/end
|
|
int nRefProp = ( i == 0 ? STM_RECTSWEPT_FLATCAP_START : STM_RECTSWEPT_FLATCAP_END) ;
|
|
bool bFound = false ;
|
|
for ( int j = 0 ; j < ssize( vCrvs) && ! bFound ; j ++) {
|
|
ICurveComposite* pCompo = GetCurveComposite( vCrvs[j]) ;
|
|
if ( pCompo == nullptr)
|
|
return nullptr ;
|
|
for ( int k = 0 ; k < pCompo->GetCurveCount() ; k++) {
|
|
int nProp = pCompo->GetCurve( k)->GetTempProp() ;
|
|
if ( nProp == nRefProp) {
|
|
double dLen ; pCompo->GetCurve( k)->GetLength( dLen) ;
|
|
if ( abs( dLen - 2 * dOffsMax) > EPS_SMALL) {
|
|
Point3d ptP ; pCompo->GetCurve( k)->GetStartPoint( ptP) ;
|
|
Vector3d vtDir ; pCompo->GetCurve( k)->GetStartDir( vtDir) ;
|
|
if ( i == 0)
|
|
vtDir.Invert() ;
|
|
PtrOwner<ICurveLine> pLine( CreateCurveLine()) ;
|
|
if ( IsNull( pLine))
|
|
return nullptr ;
|
|
pLine->SetPVL( ptP, vtDir, 2 * dOffsMax - dLen) ;
|
|
pLine->ToLoc( frLoc) ;
|
|
|
|
// verifico se interseca una curva dei medialaxis
|
|
for ( int l = 0 ; l < ssize( vMedialCrvs) ; l++) {
|
|
vMedialCrvs[l]->ToLoc( frLoc) ;
|
|
IntersCurveCurve intCC( *pLine, *vMedialCrvs[l]) ;
|
|
vMedialCrvs[l]->ToGlob( frLoc) ;
|
|
if ( intCC.GetIntersCount() == 1) {
|
|
IntCrvCrvInfo aInfo ;
|
|
intCC.GetIntCrvCrvInfo( 0, aInfo) ;
|
|
double dTempParam1 = vMedialCrvs[l]->GetFirstCurve()->GetTempParam() ;
|
|
double dTempParam2 = vMedialCrvs[l]->GetLastCurve()->GetTempParam() ;
|
|
if ( dTempParam1 < dTempParam2) {
|
|
vMedialCrvs[l]->TrimStartAtParam( aInfo.IciB[0].dU) ;
|
|
vMedialCrvs[l]->AddLine( ptP, false) ;
|
|
vMedialCrvs[l]->SetCurveTempParam( 0, dOffsMax, 0) ;
|
|
}
|
|
else {
|
|
vMedialCrvs[l]->TrimEndAtParam( aInfo.IciB[0].dU) ;
|
|
vMedialCrvs[l]->AddLine( ptP) ;
|
|
vMedialCrvs[l]->SetCurveTempParam( vMedialCrvs[l]->GetCurveCount() - 1, dOffsMax, 1) ;
|
|
}
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
bFound = true ;
|
|
break ;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
// creo catena
|
|
ICurveComposite* pResult = nullptr ;
|
|
BOOLVECTOR vUsed1( vIdx.size(), false) ;
|
|
|
|
for ( int i = 0 ; i < ssize( vMedialCrvs) ; i++) {
|
|
// verifico se è una curva sensata per il collegamento ( ovvero se i parametri ai suoi estremi sono il valore di max offset)
|
|
bool bValid = false ;
|
|
if ( vMedialCrvs[i]->GetCurveCount() == 1) {
|
|
double dPar1 = vMedialCrvs[i]->GetFirstCurve()->GetTempParam() ;
|
|
double dPar2 = vMedialCrvs[i]->GetFirstCurve()->GetTempParam( 1) ;
|
|
bValid = ( abs( dPar1 - dOffsMax) < EPS_SMALL && abs( dPar2 - dOffsMax) < EPS_SMALL) ;
|
|
}
|
|
else {
|
|
// controllo sia parametro start ed end perchè il chain permette inversione
|
|
double dParS1 = vMedialCrvs[i]->GetFirstCurve()->GetTempParam() ;
|
|
double dParS2 = vMedialCrvs[i]->GetFirstCurve()->GetTempParam( 1) ;
|
|
double dParE1 = vMedialCrvs[i]->GetLastCurve()->GetTempParam( ) ;
|
|
double dParE2 = vMedialCrvs[i]->GetLastCurve()->GetTempParam( 1) ;
|
|
bValid = ( ( abs( dParS1 - dOffsMax) < EPS_SMALL || abs( dParS2 - dOffsMax) < EPS_SMALL) &&
|
|
( abs( dParE1 - dOffsMax) < EPS_SMALL || abs( dParE2 - dOffsMax) < EPS_SMALL)) ;
|
|
}
|
|
|
|
if ( ! bValid)
|
|
continue ;
|
|
|
|
// setto tutte le temp prop ad un valore fissato per identificarla in seguito
|
|
for ( int nC = 0 ; nC < vMedialCrvs[i]->GetCurveCount() ; nC ++)
|
|
vMedialCrvs[i]->SetCurveTempProp( nC, STM_RECTSWEPT_LINK) ;
|
|
|
|
// trovo le curve che collega
|
|
Point3d ptS ; vMedialCrvs[i]->GetStartPoint( ptS) ;
|
|
Point3d ptE ; vMedialCrvs[i]->GetEndPoint( ptE) ;
|
|
double dParS = -1, dParE = -1 ;
|
|
int nS = -1, nE = -1 ;
|
|
for ( int j = 0 ; j < ssize( vIdx) ; j ++) {
|
|
if ( vCrvs[vIdx[j]] == nullptr)
|
|
continue ;
|
|
if ( nS == -1 && vCrvs[vIdx[j]]->GetParamAtPoint( ptS, dParS, dChainTol))
|
|
nS = vIdx[j] ;
|
|
else if ( nE == -1 && vCrvs[vIdx[j]]->GetParamAtPoint( ptE, dParE, dChainTol))
|
|
nE = vIdx[j] ;
|
|
if ( nS != -1 && nE != -1)
|
|
break ;
|
|
}
|
|
|
|
if ( nS == -1 || nE == -1)
|
|
return nullptr ;
|
|
|
|
// i parametri devono essere su un joint per costruzione
|
|
dParS = round( dParS) ;
|
|
dParE = round( dParE) ;
|
|
|
|
pResult = GetCurveComposite( vCrvs[nS]) ;
|
|
|
|
ICurve* pResultEnd = nullptr ;
|
|
if ( dParS > EPS_SMALL) {
|
|
pResultEnd = pResult->CopyParamRange( dParS, pResult->GetCurveCount()) ;
|
|
pResult->TrimEndAtParam( dParS) ;
|
|
}
|
|
pResult->AddCurve( vMedialCrvs[i]->Clone(), true, dChainTol) ;
|
|
GetBasicCurveComposite( vCrvs[nE])->ChangeStartPoint( dParE) ;
|
|
pResult->AddCurve( Release( vCrvs[nE]), true, dChainTol) ;
|
|
vMedialCrvs[i]->Invert() ;
|
|
pResult->AddCurve( Release( vMedialCrvs[i]), true, dChainTol) ;
|
|
if ( pResultEnd != nullptr)
|
|
pResult->AddCurve( pResultEnd, true, dChainTol) ;
|
|
// forzo chiusura
|
|
pResult->Close() ;
|
|
}
|
|
return pResult ;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
static bool
|
|
GetTrimParams( const ICurveComposite* pCrv1, const ICurveComposite* pCrv2, int nOrigCrv, int nCurrCrv2, const Vector3d& vtNorm,
|
|
DBLVECTOR& vPar1, DBLVECTOR& vPar2)
|
|
{
|
|
int nFlag ;
|
|
|
|
Point3d ptP ; pCrv2->GetCurve( nCurrCrv2)->GetStartPoint( ptP) ;
|
|
int nStart = int( floor( vPar1.back() + 0.5)) ;
|
|
|
|
// se deriva da una curva ben definita della giuda cerco la corrispondente dal lato corretto sull'altra curva
|
|
if ( nOrigCrv != 0) {
|
|
for ( int j = nStart ; j < pCrv1->GetCurveCount() ; j ++) {
|
|
int nOrigCrv1 = pCrv1->GetCurve( j)->GetTempProp() ;
|
|
if ( nOrigCrv1 == nOrigCrv) {
|
|
// se estremo di flat cap spezzo il bisettore appena trovato nel punto a minima distanza
|
|
// e sulla curva 1 avrò corrispondenza con un punto
|
|
if ( nOrigCrv == STM_RECTSWEPT_FLATCAP_START || nOrigCrv == STM_RECTSWEPT_FLATCAP_END) {
|
|
Point3d ptRef ; pCrv1->GetCurve( j)->GetStartPoint( ptRef) ;
|
|
PtrOwner<ICurve> pCurrBisector( pCrv2->CopyParamRange( vPar2.back(), nCurrCrv2)) ;
|
|
DistPointCurve distPC( ptRef, *pCurrBisector) ;
|
|
double dParTrim ; distPC.GetParamAtMinDistPoint( 0, dParTrim, nFlag) ;
|
|
vPar1.emplace_back( j) ;
|
|
vPar2.emplace_back( vPar2.back() + dParTrim) ;
|
|
vPar1.emplace_back( j) ;
|
|
vPar2.emplace_back( nCurrCrv2) ;
|
|
}
|
|
else {
|
|
DistPointCurve distPC( ptP, *pCrv1->GetCurve( j)) ;
|
|
int nSide = 0 ;
|
|
double dParMinDist ;
|
|
distPC.GetSideAtMinDistPoint( 0, vtNorm, nSide) ;
|
|
if ( nSide == MDS_RIGHT) {
|
|
distPC.GetParamAtMinDistPoint( 0, dParMinDist, nFlag) ;
|
|
dParMinDist += j ;
|
|
vPar1.emplace_back( dParMinDist) ;
|
|
vPar2.emplace_back( nCurrCrv2) ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// se deriva da raccordo devo controllare il più vicino
|
|
else {
|
|
double dMinDist = INFINITO ;
|
|
double dParMinDist ;
|
|
for ( int j = nStart ; j < pCrv1->GetCurveCount() ; j ++) {
|
|
int nOrigCrv1 = pCrv1->GetCurve( j)->GetTempProp() ;
|
|
if ( nOrigCrv1 == nOrigCrv) {
|
|
DistPointCurve distPC( ptP, *pCrv1->GetCurve( j)) ;
|
|
int nSide = 0 ;
|
|
distPC.GetSideAtMinDistPoint( 0, vtNorm, nSide) ;
|
|
if ( nSide == MDS_RIGHT) {
|
|
double dCurrDist ; distPC.GetDist( dCurrDist) ;
|
|
if ( dCurrDist < dMinDist) {
|
|
distPC.GetParamAtMinDistPoint( 0, dParMinDist, nFlag) ;
|
|
dParMinDist += j ;
|
|
dMinDist = dCurrDist ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
vPar1.emplace_back( dParMinDist) ;
|
|
vPar2.emplace_back( nCurrCrv2) ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
static bool
|
|
Associate( const ICurveComposite* pCrv1, ICurveComposite* pCrv2, const Vector3d& vtNorm, DBLVECTOR& vPar1, DBLVECTOR& vPar2)
|
|
{
|
|
|
|
vPar1.emplace_back( 0) ;
|
|
vPar2.emplace_back( 0) ;
|
|
|
|
// assegno il punto di inizio della curva 2 il più vicino possibile a quello della curva 1 preferendo curve non problematiche
|
|
int nStartCrvId = pCrv1->GetFirstCurve()->GetTempProp() ;
|
|
if ( nStartCrvId == STM_RECTSWEPT_FLATCAP_START) {
|
|
for ( int i = 0 ; i < pCrv2->GetCurveCount() ; i ++) {
|
|
int nOrigCrv = pCrv2->GetCurve( i)->GetTempProp() ;
|
|
if ( nOrigCrv == nStartCrvId) {
|
|
pCrv2->ChangeStartPoint( i) ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
Point3d ptStart ; pCrv1->GetStartPoint( ptStart) ;
|
|
double dPar ; int nFlag ;
|
|
DistPointCurve( ptStart, *pCrv2).GetParamAtMinDistPoint(0, dPar, nFlag) ;
|
|
pCrv2->ChangeStartPoint( dPar) ;
|
|
}
|
|
|
|
// segnalo parametro di split per le curve quando trovo l'inizio o la fine di un tratto che deriva da un bisettore
|
|
// o da un tratto aggiunto per la chiusura dei flat caps
|
|
bool bBisector = false ;
|
|
for ( int i = 0 ; i < pCrv2->GetCurveCount() ; i++) {
|
|
int nTmpProp = pCrv2->GetCurve( i)->GetTempProp() ;
|
|
if ( nTmpProp == STM_RECTSWEPT_LINK || nTmpProp == STM_RECTSWEPT_FLATCAP_EXTRA) {
|
|
if ( ! bBisector) {
|
|
// inizio bisettore
|
|
bBisector = true ;
|
|
if ( i > 0) {
|
|
int nOrigCrv = pCrv2->GetCurve( i-1)->GetTempProp() ;
|
|
GetTrimParams( pCrv1, pCrv2, nOrigCrv, i, vtNorm, vPar1, vPar2) ;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if ( bBisector) {
|
|
// fine del bisettore
|
|
bBisector = false ;
|
|
int nOrigCrv = pCrv2->GetCurve(i)->GetTempProp() ;
|
|
GetTrimParams( pCrv1, pCrv2, nOrigCrv, i, vtNorm, vPar1, vPar2) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// aggiungo parametro finale
|
|
double dTmp, dE1, dE2 ;
|
|
pCrv1->GetDomain( dTmp, dE1) ;
|
|
pCrv2->GetDomain( dTmp, dE2) ;
|
|
|
|
vPar1.emplace_back( dE1) ;
|
|
vPar2.emplace_back( dE2) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
static POLYLINEVECTOR
|
|
TrimPolyLine( const PolyLine& PLOrig, const DBLVECTOR& vPar)
|
|
{
|
|
POLYLINEVECTOR vPL ; vPL.reserve( vPar.size()) ;
|
|
|
|
double dPar1, dPar2 ;
|
|
Point3d pt1, pt2 ;
|
|
|
|
bool bFound = PLOrig.GetFirstUPoint( &dPar1, &pt1) ;
|
|
PolyLine PLCurr ; PLCurr.AddUPoint( 0, pt1) ;
|
|
bFound = PLOrig.GetNextUPoint( &dPar2, &pt2) ;
|
|
for ( int i = 0 ; i < ssize( vPar) && bFound ; i ++) {
|
|
while( dPar2 < vPar[i] - EPS_SMALL && bFound) {
|
|
// se non si è ancora arrivati al parametro richiesto devo aggiungere il punto e passare al successivo
|
|
PLCurr.AddUPoint( dPar2, pt2) ;
|
|
dPar1 = dPar2 ;
|
|
pt1 = pt2 ;
|
|
bFound = PLOrig.GetNextUPoint( &dPar2, &pt2) ;
|
|
}
|
|
|
|
if ( bFound) {
|
|
// ricavo il punto di interruzione
|
|
double dCoeff = ( vPar[i] - dPar1) / ( dPar2 - dPar1) ;
|
|
Point3d ptSplit = Media( pt1, pt2, dCoeff) ;
|
|
PLCurr.AddUPoint( vPar[i], ptSplit) ;
|
|
// ho concluso una polyline e pareparo la prossima
|
|
vPL.emplace_back( PLCurr) ;
|
|
PLCurr.Clear() ;
|
|
PLCurr.AddUPoint( vPar[i], ptSplit) ;
|
|
}
|
|
}
|
|
|
|
// ultima curva
|
|
if ( PLCurr.GetPointNbr() > 1)
|
|
vPL.emplace_back( PLCurr) ;
|
|
|
|
return vPL ;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
static ISurfTriMesh*
|
|
GetSurfTriMeshBeveledRectSwept( double dDimH, double dDimV, double dBevelH, double dBevelV, const ICurve* pGuide, int nCapType, double dLinTol)
|
|
{
|
|
// verifico che la linea guida sia piana
|
|
Plane3d plGuide ;
|
|
if ( ! pGuide->IsFlat( plGuide, true, 10 * EPS_SMALL))
|
|
return nullptr ;
|
|
Vector3d vtNorm ; pGuide->GetExtrusion( vtNorm) ;
|
|
if ( vtNorm.IsSmall())
|
|
vtNorm = Z_AX ;
|
|
// determino il punto centrale della sezione
|
|
Point3d ptCen ; pGuide->GetStartPoint( ptCen) ;
|
|
ptCen -= dDimV / 2 * vtNorm ;
|
|
// determino se la guida è chiusa
|
|
bool bGuideClosed = pGuide->IsClosed() ;
|
|
|
|
// calcolo le fat curve
|
|
ICURVEPOVECTOR vFatCrvs1 ;
|
|
if ( ! CalcCurveFatCurve( *pGuide, vFatCrvs1, dDimH / 2 - dBevelH, false, false))
|
|
return nullptr ;
|
|
ICURVEPOVECTOR vFatCrvs2 ;
|
|
if ( ! CalcCurveFatCurve( *pGuide, vFatCrvs2, dDimH / 2, false, false))
|
|
return nullptr ;
|
|
|
|
// aggiusto per eventuali caps
|
|
if ( ! bGuideClosed) {
|
|
if ( ! AdjustSurfTriMeshRectSweptCaps( nCapType, vFatCrvs1, vtNorm, pGuide, dDimH / 2 - dBevelH) ||
|
|
! AdjustSurfTriMeshRectSweptCaps( nCapType, vFatCrvs2, vtNorm, pGuide, dDimH / 2))
|
|
return nullptr ;
|
|
}
|
|
|
|
// setto estrusione
|
|
for ( int i = 0 ; i < ssize( vFatCrvs1) ; i++)
|
|
vFatCrvs1[i]->SetExtrusion( vtNorm) ;
|
|
for ( int i = 0 ; i < ssize( vFatCrvs2) ; i++)
|
|
vFatCrvs2[i]->SetExtrusion( vtNorm) ;
|
|
|
|
// ordino i vettori per avere il loop esterno per primo
|
|
for ( int i = 0 ; i < ssize( vFatCrvs1) ; i ++) {
|
|
Plane3d plPlane ; double dTmp ;
|
|
vFatCrvs1[i]->GetArea( plPlane, dTmp) ;
|
|
if ( AreSameVectorApprox( plPlane.GetVersN(), vtNorm)) {
|
|
swap( vFatCrvs1[i], vFatCrvs1[0]) ;
|
|
break ;
|
|
}
|
|
}
|
|
for ( int i = 0 ; i < ssize( vFatCrvs2) ; i ++) {
|
|
Plane3d plPlane ; double dTmp ;
|
|
vFatCrvs2[i]->GetArea( plPlane, dTmp) ;
|
|
if ( AreSameVectorApprox( plPlane.GetVersN(), vtNorm)) {
|
|
swap( vFatCrvs2[i], vFatCrvs2[0]) ;
|
|
break ;
|
|
}
|
|
}
|
|
|
|
// sposto il punto di start del loop esterno della FatCrv1 in modo sensato
|
|
ICurveComposite* pCompo = GetCurveComposite( vFatCrvs1[0]) ;
|
|
if ( pCompo == nullptr)
|
|
return nullptr ;
|
|
for ( int j = 0 ; j < pCompo->GetCurveCount() ; j ++) {
|
|
int nOrigCrv = pCompo->GetCurve( j)->GetTempProp() ;
|
|
if ( nOrigCrv > 0) {
|
|
Point3d ptP ; pCompo->GetCurve( j)->GetStartPoint( ptP) ;
|
|
DistPointCurve distPC( ptP, *vFatCrvs2[0]) ;
|
|
double dDist = 0 ;
|
|
distPC.GetDist( dDist) ;
|
|
if ( abs( dDist - dBevelH) < 100 * EPS_SMALL) {
|
|
pCompo->ChangeStartPoint( j + 0.5) ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
|
|
for ( int i = 0 ; i < ssize( vFatCrvs2) ; i++)
|
|
vFatCrvs2[i]->Translate( - dBevelV * vtNorm) ;
|
|
|
|
// trasformo in polylines
|
|
POLYLINEVECTOR vPL1( vFatCrvs1.size()) ;
|
|
for ( int i = 0 ; i < ssize( vFatCrvs1) ; i++)
|
|
vFatCrvs1[i]->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, vPL1[i]) ;
|
|
|
|
// costruisco le parti di superficie
|
|
PtrOwner<ISurfTriMesh> pSrfTop( CreateSurfTriMesh()) ;
|
|
if ( IsNull( pSrfTop) || ! pSrfTop->CreateByPolygonWithHoles( vPL1))
|
|
return nullptr ;
|
|
PtrOwner<ISurfTriMesh> pSrfBot( pSrfTop->Clone()) ;
|
|
if ( IsNull( pSrfBot))
|
|
return nullptr ;
|
|
pSrfBot->Translate( -dDimV * vtNorm) ;
|
|
pSrfBot->Invert() ;
|
|
|
|
int nBuckets = max( 4 * ( pSrfTop->GetVertexSize()), 1000) ;
|
|
StmFromTriangleSoup stmSoup ;
|
|
if ( ! stmSoup.Start( nBuckets))
|
|
return nullptr ;
|
|
stmSoup.AddSurfTriMesh( *pSrfTop) ;
|
|
stmSoup.AddSurfTriMesh( *pSrfBot) ;
|
|
|
|
BOOLVECTOR bUsed( vFatCrvs2.size(), false) ;
|
|
bool bRepair = false ;
|
|
|
|
for ( int i = 0 ; i < ssize( vFatCrvs1) ; i ++) {
|
|
// cerco le FatCurve2 che contengono la FatCurve1 corrente
|
|
INTVECTOR vAssociatedIdx ;
|
|
for ( int j = 0 ; j < ssize( vFatCrvs2) ; j ++) {
|
|
if ( ! bUsed[j]) {
|
|
double dS, dE ; vFatCrvs2[j]->GetDomain( dS, dE) ;
|
|
double dU = 0.5 ;
|
|
int nSide = MDS_ON ;
|
|
while ( nSide == MDS_ON && dU < dE) {
|
|
Point3d ptTest ; vFatCrvs2[j]->GetPointD1D2( dU, ICurve::FROM_MINUS, ptTest) ;
|
|
DistPointCurve distPC( ptTest, *vFatCrvs1[i]) ;
|
|
distPC.GetSideAtMinDistPoint( 0, vtNorm, nSide) ;
|
|
if ( nSide == MDS_RIGHT) {
|
|
bUsed[j] = true ;
|
|
vAssociatedIdx.emplace_back( j) ;
|
|
}
|
|
dU += 1 ;
|
|
}
|
|
}
|
|
}
|
|
|
|
ISURFTMPOVECTOR vSurfLatTop ;
|
|
ISURFTMPOVECTOR vSurfLat ;
|
|
|
|
// a) se non ha associate allora collassa in un punto/curva ad una quota opportuna
|
|
if ( vAssociatedIdx.empty()) {
|
|
|
|
double dLimitOffs ;
|
|
if ( ! CalcCurveLimitOffset( *vFatCrvs1[i], dLimitOffs))
|
|
return nullptr ;
|
|
OffsetCurve OffsCrv ;
|
|
OffsCrv.Make( vFatCrvs1[i], dLimitOffs, ICurve::OFF_FILLET) ;
|
|
|
|
PtrOwner<SurfTriMesh> pSrfLatT( CreateBasicSurfTriMesh()) ;
|
|
if ( IsNull( pSrfLatT))
|
|
return nullptr ;
|
|
|
|
Point3d ptOffs ; Vector3d vtOut ;
|
|
if ( OffsCrv.GetPointOffset( ptOffs, vtOut)) {
|
|
// se collassa in un punto
|
|
ptOffs.Translate( - dBevelV / dBevelH * dLimitOffs * vtNorm) ;
|
|
pSrfLatT->CreateByPointCurve( ptOffs, vPL1[i]) ;
|
|
pSrfLatT->Invert() ;
|
|
}
|
|
else {
|
|
// se collassa in una curva
|
|
PtrOwner<ICurveComposite> pAssociatedCrv( ConvertCurveToComposite( OffsCrv.GetLongerCurve())) ;
|
|
if ( IsNull( pAssociatedCrv))
|
|
return nullptr ;
|
|
pAssociatedCrv->Translate( - dBevelV / dBevelH * dLimitOffs * vtNorm) ;
|
|
|
|
Point3d ptStart ; vFatCrvs1[i]->GetStartPoint( ptStart) ;
|
|
double dPar ; int nFlag ;
|
|
DistPointCurve( ptStart, *pAssociatedCrv).GetParamAtMinDistPoint(0, dPar, nFlag) ;
|
|
pAssociatedCrv->ChangeStartPoint( dPar) ;
|
|
|
|
PolyLine PL2 ;
|
|
pAssociatedCrv->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL2) ;
|
|
pSrfLatT->CreateByTwoCurves( PL2, vPL1[i], ISurfTriMesh::RLT_MINDIST) ;
|
|
}
|
|
vSurfLatTop.emplace_back( Release( pSrfLatT)) ;
|
|
}
|
|
|
|
|
|
// b) se ha una sola associata costruisco la rigata tra le due curve
|
|
else if ( vAssociatedIdx.size() == 1) {
|
|
|
|
ICurveComposite* pAssociatedCrv = GetCurveComposite( vFatCrvs2[vAssociatedIdx[0]]) ;
|
|
if ( pAssociatedCrv == nullptr)
|
|
return nullptr ;
|
|
|
|
// per avere rigata ottimale modifico il punto di inizio della seconda curva
|
|
Point3d ptStart ; vFatCrvs1[i]->GetStartPoint( ptStart) ;
|
|
double dPar ; int nFlag ;
|
|
DistPointCurve( ptStart, *pAssociatedCrv).GetParamAtMinDistPoint( 0, dPar, nFlag) ;
|
|
pAssociatedCrv->ChangeStartPoint( dPar) ;
|
|
|
|
PolyLine PL2 ;
|
|
pAssociatedCrv->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL2) ;
|
|
|
|
PtrOwner<SurfTriMesh> pSrfLatT( CreateBasicSurfTriMesh()) ;
|
|
if ( IsNull( pSrfLatT) || ! pSrfLatT->CreateByTwoCurves( PL2, vPL1[i], ISurfTriMesh::RLT_MINDIST))
|
|
return nullptr ;
|
|
vSurfLatTop.emplace_back( Release( pSrfLatT)) ;
|
|
|
|
PtrOwner<SurfTriMesh> pSrfLat( CreateBasicSurfTriMesh()) ;
|
|
if ( IsNull( pSrfLat) || ! pSrfLat->CreateByExtrusion( PL2, ( - dDimV + 2 * dBevelV) * vtNorm))
|
|
return nullptr ;
|
|
pSrfLat->Invert() ;
|
|
vSurfLat.emplace_back( Release( pSrfLat)) ;
|
|
}
|
|
else {
|
|
bRepair = true ;
|
|
|
|
// superfici verticali
|
|
for ( int j = 0 ; j < ssize( vAssociatedIdx) ; j ++) {
|
|
PolyLine PL2 ;
|
|
vFatCrvs2[vAssociatedIdx[j]]->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL2) ;
|
|
PtrOwner<SurfTriMesh> pSrfLat( CreateBasicSurfTriMesh()) ;
|
|
if ( IsNull( pSrfLat) || ! pSrfLat->CreateByExtrusion( PL2, ( - dDimV + 2 * dBevelV) * vtNorm))
|
|
return nullptr ;
|
|
pSrfLat->Invert() ;
|
|
vSurfLat.emplace_back( Release( pSrfLat)) ;
|
|
}
|
|
|
|
// collego le curve tramite bisettori
|
|
ICurveComposite* pFatCrv2 = Connect( pGuide, vFatCrvs2, vAssociatedIdx, dDimH, dBevelH, dBevelV, vtNorm, nCapType) ;
|
|
if ( pFatCrv2 == nullptr)
|
|
return nullptr ;
|
|
|
|
// individuo i punti ottimali dove spezzare le polylines per avere delle rigate ottimali
|
|
DBLVECTOR vPar1, vPar2 ;
|
|
Associate( GetCurveComposite( vFatCrvs1[i]), pFatCrv2, vtNorm, vPar1, vPar2) ;
|
|
PolyLine PL2 ;
|
|
pFatCrv2->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL2) ;
|
|
POLYLINEVECTOR vPolyLine1 = TrimPolyLine( vPL1[i], vPar1) ;
|
|
POLYLINEVECTOR vPolyLine2 = TrimPolyLine( PL2, vPar2) ;
|
|
|
|
for ( int j = 0 ; j < ssize( vPolyLine1) ; j ++) {
|
|
|
|
if ( vPolyLine1[j].GetPointNbr() == 1 ) {
|
|
// collassa
|
|
Point3d pt1 ; vPolyLine1[j].GetFirstPoint( pt1) ;
|
|
Point3d pt2 ; vPolyLine2[j].GetFirstPoint( pt2) ;
|
|
Point3d pt3 ; vPolyLine2[j].GetLastPoint( pt3) ;
|
|
|
|
vPolyLine2[j].Close() ;
|
|
PtrOwner<SurfTriMesh> pSrfLatT( CreateBasicSurfTriMesh()) ;
|
|
if ( IsNull( pSrfLatT ))
|
|
return nullptr ;
|
|
pSrfLatT->CreateByFlatContour( vPolyLine2[j]) ;
|
|
vSurfLatTop.emplace_back( Release( pSrfLatT)) ;
|
|
|
|
Triangle3d trExtra ;
|
|
trExtra.Set( pt1, pt2, pt3) ;
|
|
stmSoup.AddTriangle( trExtra) ;
|
|
trExtra.Mirror( ptCen, vtNorm) ;
|
|
stmSoup.AddTriangle( trExtra) ;
|
|
}
|
|
else {
|
|
PtrOwner<SurfTriMesh> pSrfLatT( CreateBasicSurfTriMesh()) ;
|
|
if ( IsNull( pSrfLatT))
|
|
return nullptr ;
|
|
pSrfLatT->CreateByTwoCurves( vPolyLine1[j], vPolyLine2[j], ISurfTriMesh::RLT_MINDIST) ;
|
|
pSrfLatT->Invert() ;
|
|
vSurfLatTop.emplace_back( Release( pSrfLatT)) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// inserisco le superfici laterali verticali
|
|
for ( int j = 0 ; j < ssize( vSurfLat) ; j ++)
|
|
stmSoup.AddSurfTriMesh( *vSurfLat[j]) ;
|
|
|
|
// inserisco le superfici laterali rigate e il loro mirror
|
|
for ( int j = 0 ; j < ssize( vSurfLatTop) ; j ++) {
|
|
stmSoup.AddSurfTriMesh( *vSurfLatTop[j]) ;
|
|
vSurfLatTop[j]->Mirror( ptCen, vtNorm) ;
|
|
stmSoup.AddSurfTriMesh( *vSurfLatTop[j]) ;
|
|
}
|
|
}
|
|
|
|
if ( ! stmSoup.End())
|
|
return nullptr ;
|
|
|
|
PtrOwner<ISurfTriMesh> pSTM ;
|
|
pSTM.Set( stmSoup.GetSurf()) ;
|
|
if ( IsNull( pSTM))
|
|
return nullptr ;
|
|
|
|
// se ho spezzato per la superficie laterale, rischio di aver creato Tjunctions
|
|
if ( bRepair)
|
|
pSTM->Repair() ;
|
|
|
|
// 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) ;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
static ISurfTriMesh*
|
|
GetSurfTriMeshSweptInPlane( const ICurve* pSect, const ICurve* pGuide, const Vector3d& vtNorm, bool bCapEnds, double dLinTol)
|
|
{
|
|
// determino se la sezione è chiusa
|
|
bool bSectClosed = pSect->IsClosed() ;
|
|
// determino se la guida è chiusa
|
|
bool bGuideClosed = pGuide->IsClosed() ;
|
|
|
|
// riferimento all'inizio della linea guida
|
|
Frame3d frStart ;
|
|
Point3d ptStart ;
|
|
pGuide->GetStartPoint( ptStart) ;
|
|
Vector3d vtStart ;
|
|
pGuide->GetStartDir( vtStart) ;
|
|
frStart.Set( ptStart, -vtStart, vtStart ^ vtNorm) ;
|
|
|
|
// calcolo la polilinea che approssima la sezione
|
|
PolyLine PL ;
|
|
if ( ! pSect->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL))
|
|
return nullptr ;
|
|
|
|
// porto la sezione in questo riferimento e ve la appiattisco
|
|
if ( ! PL.ToLoc( frStart) || ! PL.Flatten())
|
|
return nullptr ;
|
|
|
|
// preparo collettore delle superfici componenti
|
|
StmFromTriangleSoup StmFts ;
|
|
if ( ! StmFts.Start())
|
|
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 ;
|
|
// inserisco nel collettore
|
|
StmFts.AddSurfTriMesh( *pSr) ;
|
|
}
|
|
// salvo la curva come prossima precedente
|
|
pPrevCrv.Set( pCurrCrv) ;
|
|
// prossimo punto
|
|
bPoint = PL.GetNextPoint( ptP) ;
|
|
}
|
|
|
|
// recupero la supeficie risultante
|
|
if ( ! StmFts.End())
|
|
return nullptr ;
|
|
PtrOwner<SurfTriMesh> pSTM( GetBasicSurfTriMesh( StmFts.GetSurf())) ;
|
|
if ( IsNull( pSTM))
|
|
return nullptr ;
|
|
// salvo tolleranza lineare usata
|
|
pSTM->SetLinearTolerance( dLinTol) ;
|
|
|
|
// 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) ;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
static ISurfTriMesh*
|
|
GetSurfTriMeshSwept3d( const ICurve* pSect, const ICurve* pGuide, const Vector3d& vtAx, bool bCapEnds, double dLinTol)
|
|
{
|
|
// determino se la sezione è chiusa
|
|
bool bSectClosed = pSect->IsClosed() ;
|
|
// determino se la guida è chiusa
|
|
bool bGuideClosed = pGuide->IsClosed() ;
|
|
// determino algoritmo da usare per calcolare i riferimenti lungo la curva
|
|
bool bRMF = ( ! vtAx.IsValid() || vtAx.IsSmall()) ;
|
|
|
|
// riferimento all'inizio della linea guida
|
|
Point3d ptStart ;
|
|
pGuide->GetStartPoint( ptStart) ;
|
|
Vector3d vtStart ;
|
|
pGuide->GetStartDir( vtStart) ;
|
|
Frame3d frStart ;
|
|
if ( bRMF) {
|
|
if ( ! frStart.Set( ptStart, vtStart))
|
|
return nullptr ;
|
|
}
|
|
else {
|
|
Vector3d vtAxX = vtAx ^ vtStart ;
|
|
if ( vtAxX.IsSmall()) {
|
|
vtAxX = FromUprightOrtho( vtAx) ;
|
|
vtAxX.Rotate( vtAx, 0, 1) ;
|
|
}
|
|
if ( ! frStart.Set( ptStart, vtStart, vtAxX))
|
|
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 ;
|
|
|
|
// recupero la sezione dalla PolyLine approssimata come Curva
|
|
PtrOwner<CurveComposite> pSecLocApprox( CreateBasicCurveComposite()) ;
|
|
if ( IsNull( pSecLocApprox) ||
|
|
! pSecLocApprox->FromPolyLine( PL) ||
|
|
! pSecLocApprox->IsValid())
|
|
return nullptr ;
|
|
|
|
// porto la PolyLine e la curva della sezione nel riferimento nel punto iniziale della guida
|
|
PL.ToLoc( frStart) ;
|
|
pSecLocApprox->ToLoc( frStart) ;
|
|
|
|
// calcolo il vettore di Frames campionati lungo la guida mediante la tolleranza definita
|
|
FRAME3DVECTOR vFrames ;
|
|
if ( bRMF) {
|
|
RotationMinimizingFrame RMF ;
|
|
if ( ! RMF.Set( pGuide, frStart) ||
|
|
! RMF.GetFramesByTolerance( dLinTol, vFrames) || vFrames.empty())
|
|
return nullptr ;
|
|
}
|
|
else {
|
|
RotationXplaneFrame RXF ;
|
|
if ( ! RXF.Set( pGuide, vtAx, frStart.VersX()) ||
|
|
! RXF.GetFramesByTolerance( dLinTol, vFrames) || vFrames.empty())
|
|
return nullptr ;
|
|
}
|
|
|
|
// preparo collettore delle superfici componenti
|
|
StmFromTriangleSoup StmFts ;
|
|
if ( ! StmFts.Start())
|
|
return nullptr ;
|
|
|
|
// per ogni Frame calcolato, la sezione va roto-traslata lungo la guida
|
|
for ( int i = 0 ; i < int( vFrames.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( vFrames[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( vFrames[i+1]))
|
|
return nullptr ;
|
|
|
|
// creo la rigata tra queste due sezioni
|
|
PtrOwner<ISurfTriMesh> pSr( GetSurfTriMeshRuled( pSecCurr, pSecSucc, ISurfTriMesh::RLT_ISOPAR_SMOOTH, dLinTol)) ;
|
|
if ( IsNull( pSr) || ! pSr->IsValid())
|
|
return nullptr ;
|
|
// la inverto
|
|
pSr->Invert() ;
|
|
// inserisco la superficie nel collettore
|
|
StmFts.AddSurfTriMesh( *pSr) ;
|
|
}
|
|
|
|
// se richiesti caps e sezione chiusa e guida aperta
|
|
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( vFrames.front()) ;
|
|
// aggiungo
|
|
StmFts.AddSurfTriMesh( *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( vFrames.back()) ;
|
|
// inverto
|
|
pSce->Invert() ;
|
|
// aggiungo
|
|
StmFts.AddSurfTriMesh( *pSce) ;
|
|
}
|
|
|
|
// recupero la supeficie risultante
|
|
if ( ! StmFts.End())
|
|
return nullptr ;
|
|
PtrOwner<SurfTriMesh> pSTM( GetBasicSurfTriMesh( StmFts.GetSurf())) ;
|
|
if ( IsNull( pSTM))
|
|
return nullptr ;
|
|
// salvo tolleranza lineare usata
|
|
pSTM->SetLinearTolerance( dLinTol) ;
|
|
|
|
// 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 ICurve* pSect, const ICurve* pGuide, const Vector3d& vtAx,
|
|
bool bCapEnds, double dLinTol)
|
|
{
|
|
// verifica parametri
|
|
if ( pSect == nullptr || pGuide == nullptr)
|
|
return nullptr ;
|
|
|
|
bool bIsLine = false ;
|
|
if ( pGuide->GetType() == CRV_LINE)
|
|
bIsLine = true ;
|
|
else {
|
|
const CurveComposite* pCompo = GetBasicCurveComposite( pGuide) ;
|
|
Point3d ptStart, ptEnd ;
|
|
if ( pCompo != nullptr && pCompo->IsALine( 10 * EPS_SMALL, ptStart, ptEnd))
|
|
bIsLine = true ;
|
|
}
|
|
// se la guida è piana e il vettore di riferimento è non definito oppure non nullo
|
|
Plane3d plGuide ;
|
|
if ( pGuide->IsFlat( plGuide, bIsLine, 10 * EPS_SMALL) && ( ! vtAx.IsValid() || ! vtAx.IsSmall()))
|
|
return GetSurfTriMeshSweptInPlane( pSect, pGuide, plGuide.GetVersN(), bCapEnds, dLinTol) ;
|
|
|
|
// altrimenti swept 3d
|
|
return GetSurfTriMeshSwept3d( pSect, pGuide, vtAx, bCapEnds, dLinTol) ;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
ISurfTriMesh*
|
|
GetSurfTriMeshSwept( const ISurfFlatRegion* pSfrSect, const ICurve* pGuide, const Vector3d& vtAx,
|
|
bool bCapEnds, double dLinTol)
|
|
{
|
|
// verifica dei parametri
|
|
if ( pSfrSect == nullptr || pGuide == nullptr)
|
|
return nullptr ;
|
|
|
|
// predispongo collettore superfici componenti
|
|
StmFromTriangleSoup StmSoup ;
|
|
StmSoup.Start() ;
|
|
|
|
// per ogni loop della superficie, creo una Swept
|
|
for ( int nC = 0 ; nC < pSfrSect->GetChunkCount() ; ++ nC) {
|
|
for ( int nL = 0 ; nL < pSfrSect->GetLoopCount( nC) ; ++ nL) {
|
|
// recupero il loop
|
|
PtrOwner<ICurve> pCrvLoop( pSfrSect->GetLoop( nC, nL)) ;
|
|
if ( IsNull( pCrvLoop) || ! pCrvLoop->IsValid())
|
|
return nullptr ;
|
|
// creo la Trimesh Swept
|
|
PtrOwner<ISurfTriMesh> pStmLoopSwept( GetSurfTriMeshSwept( pCrvLoop, pGuide, vtAx, false, dLinTol)) ;
|
|
if ( IsNull( pStmLoopSwept) || ! pStmLoopSwept->IsValid())
|
|
return nullptr ;
|
|
// aggiungo la Swept ricavata al risultato finale ( come triangoli )
|
|
StmSoup.AddSurfTriMesh( *pStmLoopSwept) ;
|
|
}
|
|
}
|
|
|
|
// Recupero la superficie
|
|
if ( ! StmSoup.End())
|
|
return nullptr ;
|
|
PtrOwner<ISurfTriMesh> pStmSwept( StmSoup.GetSurf()) ;
|
|
if ( IsNull( pStmSwept))
|
|
return nullptr ;
|
|
|
|
// se rischiesta chiusura...
|
|
// Controllo solo che la guida non sia chiusa, la sezione derivando da una Flatregion è sempre chiusa
|
|
if ( bCapEnds && ! pGuide->IsClosed()) {
|
|
// recupero i loop all'inizio (dalla regione e apportunamente approssimati)
|
|
POLYLINEVECTOR vPLi ;
|
|
for ( int nC = 0 ; nC < pSfrSect->GetChunkCount() ; ++ nC) {
|
|
for ( int nL = 0 ; nL < pSfrSect->GetLoopCount( nC) ; ++ nL) {
|
|
vPLi.emplace_back() ;
|
|
if ( ! pSfrSect->ApproxLoopWithLines( nC, nL, dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, vPLi.back()))
|
|
return nullptr ;
|
|
}
|
|
}
|
|
// creo il cap sull'inizio e lo attacco alla swept ( è già in posizione giusta)
|
|
PtrOwner<SurfTriMesh> pSci( CreateBasicSurfTriMesh()) ;
|
|
INTMATRIX vnPLIndMat ;
|
|
if ( ! pSci->CreateByRegion( vPLi, vnPLIndMat))
|
|
return nullptr ;
|
|
pStmSwept->DoSewing( *pSci) ;
|
|
// recupero i loops alla fine
|
|
POLYLINEVECTOR vPLe ;
|
|
if ( ! pStmSwept->GetLoops( vPLe))
|
|
return nullptr ;
|
|
// creo la superficie alla fine e la attacco
|
|
PtrOwner<SurfTriMesh> pSce( CreateBasicSurfTriMesh()) ;
|
|
vnPLIndMat.clear() ;
|
|
if ( ! pSce->CreateByRegion( vPLe, vnPLIndMat))
|
|
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) ;
|
|
}
|