ec6eb3e645
- modifica a Trimming - sistemazioni estetiche varie.
6445 lines
264 KiB
C++
6445 lines
264 KiB
C++
//----------------------------------------------------------------------------
|
|
// EgalTech 2020-2020
|
|
//----------------------------------------------------------------------------
|
|
// File : SurfBezier.cpp Data : 11.08.20 Versione : 2.2h2
|
|
// Contenuto : Implementazione della classe Superfici Bezier.
|
|
//
|
|
//
|
|
//
|
|
// Modifiche : 22.03.20 DS Creazione modulo.
|
|
// 11.08.20 DS Trasformata in MultiPatch.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
//--------------------------- Include ----------------------------------------
|
|
#include "stdafx.h"
|
|
#include "SurfBezier.h"
|
|
#include "GeoObjFactory.h"
|
|
#include "NgeWriter.h"
|
|
#include "NgeReader.h"
|
|
#include "Bernstein.h"
|
|
#include "CurveArc.h"
|
|
#include "CurveBezier.h"
|
|
#include "CurveComposite.h"
|
|
#include "Tree.h"
|
|
#include "Triangulate.h"
|
|
#include "SurfTriMesh.h"
|
|
#include "/EgtDev/Include/EGkSfrCreate.h"
|
|
#include "/EgtDev/Include/EGkStmFromTriangleSoup.h"
|
|
#include "/EgtDev/Include/EGkStringUtils3d.h"
|
|
#include "/EgtDev/Include/EGkUiUnits.h"
|
|
#include "/EgtDev/Include/EgtNumUtils.h"
|
|
#include "/EgtDev/Include/EgtPointerOwner.h"
|
|
#include "/EgtDev/Include/EGkIntersPlaneSurfTm.h"
|
|
#include "/EgtDev/Include/EGkChainCurves.h"
|
|
#include "/EgtDev/Include/EGkIntersLineSurfBez.h"
|
|
#include "/EgtDev/Include/EGkIntersCurvePlane.h"
|
|
#include "/EgtDev/Include/EGkDistPointSurfTm.h"
|
|
#include "/EgtDev/Include/EGkDistPointLine.h"
|
|
#include "/EgtDev/Include/EGkDistPointCurve.h"
|
|
#include "/EgtDev/Include/EGkCurveComposite.h"
|
|
#include "/EgtDev/Include/EGkCurveArc.h"
|
|
#include "/EgtDev/Include/EGkGeoPoint3d.h"
|
|
#include "/EgtDev/Include/EGkIntervals.h"
|
|
#define EIGEN_NO_IO
|
|
#include "/EgtDev/Extern/Eigen/Dense"
|
|
|
|
#define SAVEFAILEDTRIANGULATION 0
|
|
#define SAVEISO 0
|
|
#define SAVERULEDISO 0
|
|
#define SAVERULEDGUIDEDISO 0
|
|
#if SAVEFAILEDTRIANGULATION || SAVEISO || SAVERULEDISO || SAVERULEDGUIDEDISO
|
|
#include "/EgtDev/Include/EGkGeoObjSave.h"
|
|
#endif
|
|
|
|
using namespace std ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
GEOOBJ_REGISTER( SRF_BEZIER, NGE_S_BEZ, SurfBezier) ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
struct PairHashIntInt {
|
|
size_t operator()(const pair<int, int>& key) const {
|
|
size_t h1 = hash<int>{}( key.first) ;
|
|
size_t h2 = hash<int>{}( key.second) ;
|
|
return h1 ^ ( h2 << 1) ; // Combine hashes
|
|
}
|
|
};
|
|
static unordered_map<INTINT, DBLVECTOR, PairHashIntInt> s_mBernCache ; // mappa dei polinomi di bernstein
|
|
|
|
//----------------------------------------------------------------------------
|
|
static double s_dAuxSurfTol = 200 * EPS_SMALL ;
|
|
static double s_dAuxSurfRefinedTol = 10 * EPS_SMALL ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
SetSurfBezierAuxSurfTol( double dTol)
|
|
{
|
|
s_dAuxSurfTol = max( dTol, EPS_SMALL) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
double
|
|
GetSurfBezierAuxSurfTol( void)
|
|
{
|
|
return s_dAuxSurfTol ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
SetSurfBezierAuxSurfRefinedTol( double dTol)
|
|
{
|
|
s_dAuxSurfRefinedTol = max( dTol, EPS_SMALL) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
double
|
|
GetSurfBezierAuxSurfRefinedTol( void)
|
|
{
|
|
return s_dAuxSurfRefinedTol ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
SurfBezier::SurfBezier( void)
|
|
: m_pSTM( nullptr), m_pSTMRefined( nullptr), m_nStatus( TO_VERIFY), m_nDegU(), m_nDegV(), m_nSpanU(), m_nSpanV(), m_bRat( false),
|
|
m_bTrimmed( false), m_bClosedU( false), m_bClosedV( false), m_pTrimReg( nullptr), m_nTempProp{0,0}, m_dTempParam{0.0,0.0}, m_nIsPlanar( -1)
|
|
{
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
SurfBezier::~SurfBezier( void)
|
|
{
|
|
ResetTrimRegion() ;
|
|
m_OGrMgr.Reset() ;
|
|
ResetAuxSurf() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::Init( int nDegU, int nDegV, int nSpanU, int nSpanV, bool bIsRational)
|
|
{
|
|
// verifico validità grado
|
|
if ( nDegU < 1 || nDegU > MAXDEG || nDegV < 1 || nDegV > MAXDEG || nSpanU < 1 || nSpanV < 1)
|
|
return false ;
|
|
|
|
// imposto gradi e flag di razionale
|
|
m_nDegU = nDegU ;
|
|
m_nDegV = nDegV ;
|
|
m_nSpanU = nSpanU ;
|
|
m_nSpanV = nSpanV ;
|
|
m_bRat = bIsRational ;
|
|
m_bTrimmed = false ;
|
|
ResetTrimRegion() ;
|
|
|
|
// dimensiono i vettori dei punti e dei pesi
|
|
m_vPtCtrl.assign( GetDim(), ORIG) ;
|
|
if ( bIsRational)
|
|
m_vWeCtrl.assign( GetDim(), 1) ;
|
|
else
|
|
m_vWeCtrl.clear() ;
|
|
m_nStatus = TO_VERIFY ;
|
|
m_nIsPlanar = NOT_CALCULATED ;
|
|
|
|
// setto la dimensione dei vettori
|
|
m_vBernU.resize( m_nDegU + 1) ;
|
|
m_vBernV.resize( m_nDegV + 1) ;
|
|
if (! m_bRat)
|
|
m_ptTemp.resize(m_nDegV + 1, ORIG) ;
|
|
else {
|
|
m_ptTempW.resize(m_nDegV + 1, ORIG) ;
|
|
m_dTempW.resize( m_nDegV + 1, 0) ;
|
|
m_vPtWCtrlLoc.resize( GetLocDim()) ;
|
|
m_vWeCtrlLoc.resize( GetLocDim()) ;
|
|
}
|
|
|
|
|
|
|
|
// imposto ricalcolo della grafica
|
|
ResetAuxSurf() ;
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return Validate() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::SetControlPoint( int nInd, const Point3d& ptCtrl)
|
|
{
|
|
// verifico validità indice
|
|
if ( m_nStatus != OK || m_bRat || nInd < 0 || nInd >= GetDim())
|
|
return false ;
|
|
|
|
// assegno il valore
|
|
m_vPtCtrl[nInd] = ptCtrl ;
|
|
|
|
// se razionale, metto il peso a 1
|
|
if ( m_bRat)
|
|
m_vWeCtrl[nInd] = 1 ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
ResetAuxSurf() ;
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::SetControlPoint( int nInd, const Point3d& ptCtrl, double dW)
|
|
{
|
|
// verifico validità, razionalità e indice
|
|
if ( m_nStatus != OK || ! m_bRat || nInd < 0 || nInd >= GetDim())
|
|
return false ;
|
|
|
|
// verifico che il peso non sia nullo o negativo
|
|
if ( dW < EPS_SMALL)
|
|
return false ;
|
|
|
|
// assegno il valore e il peso
|
|
m_vPtCtrl[nInd] = ptCtrl ;
|
|
m_vWeCtrl[nInd] = dW ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
ResetAuxSurf() ;
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::SetTrimRegion( ISurfFlatRegion& sfrTrimReg, bool bIntersectOrSubtract)
|
|
{
|
|
// controllo se aveo trim precedenti ed eventualmente faccio un'intersezione con lo spazio esistente
|
|
|
|
// verifico la regione passata
|
|
if ( &sfrTrimReg == nullptr || ! sfrTrimReg.IsValid())
|
|
return false ;
|
|
// se la normale ha z negativa ribalto la superficie, sennò le operazioni di intersect e subtract non funzionano
|
|
if ( sfrTrimReg.GetNormVersor().z < 0)
|
|
sfrTrimReg.Invert() ;
|
|
// limito la regione allo spazio parametrico della superficie
|
|
PtrOwner< ISurfFlatRegion> pSfrTrim( GetSurfFlatRegionRectangle( SBZ_TREG_COEFF * m_nSpanU, SBZ_TREG_COEFF * m_nSpanV)) ;
|
|
// bIntersectOrSubtract == true per ottenere lo spazio parametrico trimmato devo fare l'INTERSEZIONE tra il rettangolo totale e l'area passata
|
|
if ( bIntersectOrSubtract) {
|
|
if ( IsNull( pSfrTrim) || ! pSfrTrim->Intersect( sfrTrimReg) || ! pSfrTrim->IsValid()) {
|
|
// provo a offsettare il rettangolo parametrico ( ingrandendolo) per vedere se risolvo problemi di intersezione
|
|
pSfrTrim->Offset( 10* EPS_SMALL, ICurve::OFF_EXTEND) ;
|
|
if ( ! pSfrTrim->Intersect( sfrTrimReg) || ! pSfrTrim->IsValid())
|
|
return false ;
|
|
pSfrTrim->Offset( -10* EPS_SMALL, ICurve::OFF_EXTEND) ;
|
|
}
|
|
}
|
|
// bIntersectOrSubtract == false per ottenere lo spazio parametrico trimmato devo fare la SOTTRAZIONE tra il rettangolo totale e l'area passata
|
|
else {
|
|
if ( IsNull( pSfrTrim) || ! pSfrTrim->Subtract( sfrTrimReg) || ! pSfrTrim->IsValid()) {
|
|
// provo a offsettare il rettangolo parametrico ( ingrandendolo) per vedere se risolvo problemi di sottrazione
|
|
pSfrTrim->Offset( 10* EPS_SMALL, ICurve::OFF_EXTEND) ;
|
|
if ( ! pSfrTrim->Subtract( sfrTrimReg) || ! pSfrTrim->IsValid())
|
|
return false ;
|
|
pSfrTrim->Offset( -10* EPS_SMALL, ICurve::OFF_EXTEND) ;
|
|
}
|
|
}
|
|
ResetAuxSurf() ;
|
|
// assegno la regione di trim
|
|
if ( m_pTrimReg != nullptr ) {
|
|
if ( ! m_pTrimReg->Intersect( *pSfrTrim))
|
|
return false ;
|
|
}
|
|
else
|
|
m_pTrimReg = GetBasicSurfFlatRegion( Release( pSfrTrim)) ;
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
// setto la superficie trimmata
|
|
m_bTrimmed = true ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
SurfFlatRegion*
|
|
SurfBezier::GetTrimRegion( void) const
|
|
{
|
|
if ( ! m_bTrimmed || m_pTrimReg == nullptr )
|
|
return nullptr ;
|
|
return m_pTrimReg ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::GetInfo( int& nDegU, int& nDegV, int& nSpanU, int& nSpanV, bool& bIsRat, bool& bTrimmed) const
|
|
{
|
|
// verifico validità superficie
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
// restituisco gradi e flag di razionale
|
|
nDegU = m_nDegU ;
|
|
nDegV = m_nDegV ;
|
|
nSpanU = m_nSpanU ;
|
|
nSpanV = m_nSpanV ;
|
|
bIsRat = m_bRat ;
|
|
bTrimmed = m_bTrimmed ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
const Point3d&
|
|
SurfBezier::GetControlPoint( int nInd, bool* pbOk) const
|
|
{
|
|
// verifico validità e indice
|
|
if ( m_nStatus != OK || nInd < 0 || nInd >= GetDim()) {
|
|
if ( pbOk != NULL)
|
|
*pbOk = false ;
|
|
return ORIG ;
|
|
}
|
|
// ritorno i dati
|
|
if ( pbOk != NULL)
|
|
*pbOk = true ;
|
|
return m_vPtCtrl[nInd] ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
double
|
|
SurfBezier::GetControlWeight( int nInd, bool* pbOk) const
|
|
{
|
|
// verifico validità, razionalità e indice
|
|
if ( m_nStatus != OK || ! m_bRat || nInd < 0 || nInd >= GetDim()) {
|
|
if ( pbOk != NULL)
|
|
*pbOk = false ;
|
|
return 0 ;
|
|
}
|
|
// ritorno i dati
|
|
if ( pbOk != NULL)
|
|
*pbOk = true ;
|
|
return m_vWeCtrl[nInd] ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::IsAPoint( void) const
|
|
{
|
|
// verifico lo stato
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
// ciclo sui punti
|
|
for ( int i = 1 ; i < GetDim() ; ++ i) {
|
|
if ( ! AreSamePointApprox( m_vPtCtrl[0], m_vPtCtrl[i]))
|
|
return false ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::GetArea( double& dArea) const
|
|
{
|
|
// controllo parametro di ritorno
|
|
if ( &dArea == nullptr)
|
|
return false ;
|
|
// inizio con area nulla
|
|
dArea = 0 ;
|
|
// calcolo l'area
|
|
if ( m_pSTM == nullptr)
|
|
if ( ! GetAuxSurf())
|
|
return false ;
|
|
return m_pSTM->GetArea( dArea) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::IsClosed( void) const
|
|
{
|
|
// altrimenti verifico a mano
|
|
if ( m_nSpanU == 1 || m_nSpanV == 1)
|
|
return false ;
|
|
|
|
// controllo la prima riga con l'ultima
|
|
m_bClosedV = true ;
|
|
for ( int i = 0 ; i < m_nDegU * m_nSpanU + 1 && m_bClosedV ; ++i)
|
|
m_bClosedV = AreSamePointApprox( m_vPtCtrl[GetInd( i, 0)], m_vPtCtrl[ GetInd(i, m_nDegV * m_nSpanV)]) ;
|
|
|
|
// controllo la prima colonna con l'ultima
|
|
m_bClosedU = true ;
|
|
for ( int j = 0 ; j < m_nDegV * m_nSpanV + 1 && m_bClosedU ; ++j)
|
|
m_bClosedU = AreSamePointApprox( m_vPtCtrl[GetInd(0,j)], m_vPtCtrl[GetInd(m_nDegU * m_nSpanU,j)]) ;
|
|
|
|
// se ho la chiusura su entrambi i parametri ho la chiusura "in stile toro"
|
|
if ( m_bClosedU && m_bClosedV)
|
|
return true ;
|
|
|
|
//verifico se ci sono dei poli che chiudono la superficie, per vedere se ho la chiusura "in stile sfera, da polo a polo" ( classica superficie di rivoluzione)
|
|
CalcPoles() ;
|
|
// chiusa in U e con poli sugli altri 2 lati
|
|
if ( m_bClosedU && ! m_bClosedV && m_vbPole[0] && m_vbPole[2])
|
|
return true ;
|
|
// chiusa in V e con poli sugli altri due lati
|
|
if ( m_bClosedV && ! m_bClosedU && m_vbPole[1] && m_vbPole[3])
|
|
return true ;
|
|
|
|
// se ho due lati opposti che sono dei poli e sono anche coincidenti allora la superficie potrebbe essere chiusa "in stile sfera a saccoccia"
|
|
if ( m_vbPole[0] && m_vbPole[2] && AreSamePointApprox( m_vPtCtrl[GetInd(0,0)], m_vPtCtrl[GetInd(m_nDegU * m_nSpanU, m_nDegV * m_nSpanV)]) ) {
|
|
bool bV0BackAndForth = true ;
|
|
bool bV1BackAndForth = true ;
|
|
for ( int i = 0 ; i < (m_nDegV * m_nSpanV + 1) / 2 && bV0BackAndForth && bV1BackAndForth; ++i) {
|
|
bV0BackAndForth = AreSamePointApprox( m_vPtCtrl[GetInd(0,i)], m_vPtCtrl[GetInd(0,m_nDegV * m_nSpanV - i)]) ;
|
|
bV1BackAndForth = AreSamePointApprox( m_vPtCtrl[GetInd(m_nDegU * m_nSpanU,i)], m_vPtCtrl[GetInd(m_nDegU * m_nSpanU,m_nDegV * m_nSpanV - i)]) ;
|
|
}
|
|
if ( bV0BackAndForth && bV1BackAndForth)
|
|
return true ;
|
|
}
|
|
if ( m_vbPole[1] && m_vbPole[3] && AreSamePointApprox( m_vPtCtrl[GetInd(0,0)], m_vPtCtrl[GetInd(m_nDegU * m_nSpanU, m_nDegV * m_nSpanV)]) ) {
|
|
bool bU0BackAndForth = true ;
|
|
bool bU1BackAndForth = true ;
|
|
for ( int i = 0 ; i < (m_nDegU * m_nSpanU + 1) / 2 && bU0BackAndForth && bU1BackAndForth; ++i) {
|
|
bU0BackAndForth = AreSamePointApprox( m_vPtCtrl[GetInd( i,0)], m_vPtCtrl[GetInd( m_nDegU * m_nSpanU - i, 0)]) ;
|
|
bU1BackAndForth = AreSamePointApprox( m_vPtCtrl[GetInd( i, m_nDegV * m_nSpanV)], m_vPtCtrl[GetInd( m_nDegU * m_nSpanU - i, m_nDegV * m_nSpanV)]) ;
|
|
}
|
|
if ( bU0BackAndForth && bU1BackAndForth)
|
|
return true ;
|
|
}
|
|
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::GetCentroid( Point3d& ptCen) const
|
|
{
|
|
// controllo parametro di ritorno
|
|
if ( &ptCen == nullptr)
|
|
return false ;
|
|
// inizio con centro nell'origine
|
|
ptCen = ORIG ;
|
|
// calcolo il baricentro della superficie ausiliaria
|
|
GetAuxSurf() ;
|
|
if ( m_pSTM != nullptr)
|
|
return m_pSTM->GetCentroid( ptCen) ;
|
|
else
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::GetBernstein( double dU, int nDegU, DBLVECTOR& vBernU) const
|
|
{
|
|
const int TWO_TO_24 = 16777216 ;
|
|
INTINT key( nDegU, int( dU * TWO_TO_24)) ;
|
|
if ( s_mBernCache.find( key) == s_mBernCache.end()) {
|
|
DBLVECTOR vBern( nDegU + 1) ;
|
|
GetAllBernstein( dU, nDegU, vBern) ;
|
|
s_mBernCache[key] = vBern ;
|
|
}
|
|
vBernU = s_mBernCache[key] ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::GetPoint( double dU, double dV, Side nUs, Side nVs,Point3d& ptPos) const
|
|
{
|
|
// la curva deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// i parametri U e V devono essere compresi tra 0 e il corrispondente numero di Span
|
|
dU = Clamp( dU, 0., double( m_nSpanU)) ;
|
|
dV = Clamp( dV, 0., double( m_nSpanV)) ;
|
|
|
|
// determino gli intervalli di span e riduco i parametri in essi
|
|
int nBsU = min( int( dU), m_nSpanU - 1) ;
|
|
double dLocU = dU - nBsU ;
|
|
if ( abs( dLocU) < 5 * EPS_PARAM && nBsU > 0 && nUs == ISurfBezier::FROM_MINUS) {
|
|
-- nBsU ;
|
|
dLocU = 1 ;
|
|
}
|
|
else if ( abs( dLocU) > 1 - 5 * EPS_PARAM && nBsU < m_nSpanU - 1 && nUs == ISurfBezier::FROM_PLUS) {
|
|
++ nBsU ;
|
|
dLocU = 0 ;
|
|
}
|
|
int nOffsU = nBsU * m_nDegU ;
|
|
int nBsV = min( int( dV), m_nSpanV - 1) ;
|
|
double dLocV = dV - nBsV ;
|
|
if ( abs( dLocV) < 5 * EPS_PARAM && nBsV > 0 && nVs == ISurfBezier::FROM_MINUS) {
|
|
-- nBsV ;
|
|
dLocV = 1 ;
|
|
}
|
|
else if ( abs( dLocV) > 1 - 5 * EPS_PARAM && nBsV < m_nSpanV - 1 && nVs == ISurfBezier::FROM_PLUS) {
|
|
++ nBsV ;
|
|
dLocV = 0 ;
|
|
}
|
|
int nOffsV = nBsV * m_nDegV ;
|
|
|
|
// se forma polinomiale (o integrale)
|
|
if ( ! m_bRat) {
|
|
|
|
// calcolo dei polinomi di Bernstein per U di grado opportuno
|
|
GetBernstein( dLocU, m_nDegU, m_vBernU) ;
|
|
|
|
// calcolo dei punti intermedi
|
|
m_ptTemp.assign(GetLocDim(), ORIG) ;
|
|
for ( int j = 0 ; j <= m_nDegV ; ++ j) {
|
|
for ( int i = 0 ; i <= m_nDegU ; ++ i)
|
|
m_ptTemp[j] += m_vBernU[i] * m_vPtCtrl[GetInd( nOffsU + i, nOffsV + j)] ;
|
|
}
|
|
|
|
// calcolo dei polinomi di Bernstein per V di grado opportuno
|
|
GetBernstein( dLocV, m_nDegV, m_vBernV) ;
|
|
|
|
// calcolo del punto
|
|
ptPos = ORIG ;
|
|
for ( int j = 0 ; j <= m_nDegV ; ++ j)
|
|
ptPos += m_vBernV[j] * m_ptTemp[j] ;
|
|
}
|
|
|
|
// altrimenti forma razionale
|
|
else {
|
|
// recupero punti di controllo e pesi della patch in questione
|
|
// porto i punti in forma omogenea moltiplicandoli per i pesi
|
|
m_vPtWCtrlLoc.assign(GetLocDim(), ORIG) ;
|
|
m_vWeCtrlLoc.assign(GetLocDim(), 0) ;
|
|
for ( int j = 0 ; j <= m_nDegV ; ++ j) {
|
|
for ( int i = 0 ; i <= m_nDegU ; ++ i) {
|
|
m_vPtWCtrlLoc[GetLocInd( i, j)] = m_vWeCtrl[GetInd( nOffsU + i, nOffsV + j)] * m_vPtCtrl[GetInd( nOffsU + i, nOffsV + j)] ;
|
|
m_vWeCtrlLoc[GetLocInd( i, j)] = m_vWeCtrl[GetInd( nOffsU + i, nOffsV + j)] ;
|
|
}
|
|
}
|
|
|
|
// calcolo dei polinomi di Bernstein di grado opportuno
|
|
GetBernstein( dLocU, m_nDegU, m_vBernU) ;
|
|
|
|
// calcolo dei punti e pesi intermedi
|
|
m_ptTempW.assign(GetLocDim(), ORIG) ;
|
|
m_dTempW.assign(GetLocDim(), 0) ;
|
|
for ( int j = 0 ; j <= m_nDegV ; ++ j) {
|
|
for ( int i = 0 ; i <= m_nDegU ; ++ i) {
|
|
m_ptTempW[j] += m_vBernU[i] * m_vPtWCtrlLoc[GetLocInd( i, j)] ;
|
|
m_dTempW[j] += m_vBernU[i] * m_vWeCtrlLoc[GetLocInd( i, j)] ;
|
|
}
|
|
}
|
|
|
|
// calcolo dei polinomi di Bernstein per V di grado opportuno
|
|
GetBernstein( dLocV, m_nDegV, m_vBernV) ;
|
|
|
|
// calcolo del punto
|
|
double dW = 0 ;
|
|
ptPos = ORIG ;
|
|
for ( int j = 0 ; j <= m_nDegV ; ++ j) {
|
|
ptPos += m_vBernV[j] * m_ptTempW[j] ;
|
|
dW += m_vBernV[j] * m_dTempW[j] ;
|
|
}
|
|
|
|
// ritrasformo da forma omogenea a forma standard
|
|
double dInvW = 1 / ( ( dW > EPS_ZERO) ? dW : EPS_ZERO) ;
|
|
ptPos *= dInvW ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::GetPointD1D2( double dU, double dV, Side nUs, Side nVs,
|
|
Point3d& ptPos,
|
|
Vector3d* pvtDerU, Vector3d* pvtDerV, Vector3d* pvtDerUU, Vector3d* pvtDerVV, Vector3d* pvtDerUV) const
|
|
{
|
|
// la curva deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// i parametri U e V devono essere compresi tra 0 e il corrispondente numero di Span
|
|
dU = Clamp( dU, 0., double( m_nSpanU)) ;
|
|
dV = Clamp( dV, 0., double( m_nSpanV)) ;
|
|
|
|
// determino gli intervalli di span e riduco i parametri in essi
|
|
int nBsU = min( int( dU), m_nSpanU - 1) ;
|
|
double dLocU = dU - nBsU ;
|
|
if ( abs( dLocU) < 5 * EPS_PARAM && nBsU > 0 && nUs == ISurfBezier::FROM_MINUS) {
|
|
-- nBsU ;
|
|
dLocU = 1 ;
|
|
}
|
|
else if ( abs( dLocU) > 1 - 5 * EPS_PARAM && nBsU < m_nSpanU - 1 && nUs == ISurfBezier::FROM_PLUS) {
|
|
++ nBsU ;
|
|
dLocU = 0 ;
|
|
}
|
|
int nOffsU = nBsU * m_nDegU ;
|
|
int nBsV = min( int( dV), m_nSpanV - 1) ;
|
|
double dLocV = dV - nBsV ;
|
|
if ( abs( dLocV) < 5 * EPS_PARAM && nBsV > 0 && nVs == ISurfBezier::FROM_MINUS) {
|
|
-- nBsV ;
|
|
dLocV = 1 ;
|
|
}
|
|
else if ( abs( dLocV) > 1 - 5 * EPS_PARAM && nBsV < m_nSpanV - 1 && nVs == ISurfBezier::FROM_PLUS) {
|
|
++ nBsV ;
|
|
dLocV = 0 ;
|
|
}
|
|
int nOffsV = nBsV * m_nDegV ;
|
|
|
|
// se forma polinomiale (o integrale)
|
|
if ( ! m_bRat) {
|
|
|
|
// calcolo dei polinomi di Bernstein per U di grado opportuno
|
|
DBLVECTOR vBernU( m_nDegU + 1) ;
|
|
GetAllBernstein( dLocU, m_nDegU - 2, vBernU) ;
|
|
|
|
//// se richiesto, calcolo della derivata seconda
|
|
// if ( pvtDer2 != nullptr && pvtDer1 != nullptr) {
|
|
// *pvtDer2 = V_NULL ;
|
|
// for ( int i = 0 ; i <= m_nDeg - 2 ; ++ i) {
|
|
// *pvtDer2 += vBern[i] * ( m_vPtCtrl[i+2] + m_vPtCtrl[i] - 2 * m_vPtCtrl[i+1]) ;
|
|
// }
|
|
// *pvtDer2 *= m_nDeg * ( m_nDeg - 1) ;
|
|
// }
|
|
|
|
// aumento il grado
|
|
IncreaseAllBernsteinOneDegree( dLocU, m_nDegU - 1, vBernU) ;
|
|
|
|
// se richiesto, calcolo dei vettori intermedi per la derivata prima rispetto ad U
|
|
VCT3DVECTOR vtTemp1( m_nDegV + 1, V_NULL) ;
|
|
if ( pvtDerU != nullptr) {
|
|
for ( int j = 0 ; j <= m_nDegV ; ++ j) {
|
|
for ( int i = 0 ; i <= m_nDegU - 1 ; ++ i)
|
|
vtTemp1[j] += vBernU[i] * ( m_vPtCtrl[GetInd( nOffsU + i + 1, nOffsV + j)] - m_vPtCtrl[GetInd( nOffsU + i, nOffsV + j)]) ;
|
|
vtTemp1[j] *= m_nDegU ;
|
|
}
|
|
}
|
|
|
|
// aumento il grado
|
|
IncreaseAllBernsteinOneDegree( dLocU, m_nDegU, vBernU) ;
|
|
|
|
// calcolo dei punti intermedi
|
|
PNTVECTOR ptTemp( m_nDegV + 1, ORIG) ;
|
|
for ( int j = 0 ; j <= m_nDegV ; ++ j) {
|
|
for ( int i = 0 ; i <= m_nDegU ; ++ i)
|
|
ptTemp[j] += vBernU[i] * m_vPtCtrl[GetInd( nOffsU + i, nOffsV + j)] ;
|
|
}
|
|
|
|
// calcolo dei polinomi di Bernstein per V di grado opportuno
|
|
DBLVECTOR vBernV( m_nDegV + 1) ;
|
|
GetAllBernstein( dLocV, m_nDegV - 1, vBernV) ;
|
|
|
|
// se richiesto, calcolo della derivata prima rispetto a V
|
|
if ( pvtDerV != nullptr) {
|
|
*pvtDerV = V_NULL ;
|
|
for ( int j = 0 ; j <= m_nDegV - 1 ; ++ j)
|
|
*pvtDerV += vBernV[j] * ( ptTemp[j+1] - ptTemp[j]) ;
|
|
*pvtDerV *= m_nDegV ;
|
|
}
|
|
|
|
// aumento il grado
|
|
IncreaseAllBernsteinOneDegree( dLocV, m_nDegV, vBernV) ;
|
|
|
|
// calcolo del punto
|
|
ptPos = ORIG ;
|
|
for ( int j = 0 ; j <= m_nDegV ; ++ j)
|
|
ptPos += vBernV[j] * ptTemp[j] ;
|
|
|
|
// se richiesto, calcolo della derivata prima rispetto a U
|
|
if ( pvtDerU != nullptr) {
|
|
*pvtDerU = V_NULL ;
|
|
for ( int j = 0 ; j <= m_nDegV ; ++ j)
|
|
*pvtDerU += vBernV[j] * vtTemp1[j] ;
|
|
}
|
|
}
|
|
|
|
// altrimenti forma razionale
|
|
else {
|
|
|
|
// porto i punti in forma omogenea moltiplicandoli per i pesi
|
|
PNTVECTOR vPtWCtrl( GetLocDim()) ;
|
|
DBLVECTOR vWeCtrl( GetLocDim()) ;
|
|
for ( int j = 0 ; j <= m_nDegV ; ++ j) {
|
|
for ( int i = 0 ; i <= m_nDegU ; ++ i) {
|
|
vPtWCtrl[GetLocInd( i, j)] = m_vWeCtrl[GetInd( nOffsU + i, nOffsV + j)] * m_vPtCtrl[GetInd( nOffsU + i, nOffsV + j)] ;
|
|
vWeCtrl[GetLocInd( i, j)] = m_vWeCtrl[GetInd( nOffsU + i, nOffsV + j)] ;
|
|
}
|
|
}
|
|
|
|
// calcolo dei polinomi di Bernstein di grado opportuno
|
|
DBLVECTOR vBernU( m_nDegU + 1) ;
|
|
GetAllBernstein( dLocU, m_nDegU - 2, vBernU) ;
|
|
|
|
//// se richiesto, calcolo della derivata seconda
|
|
// double dW2 = 0 ;
|
|
// if ( pvtDer2 != nullptr && pvtDer1 != nullptr) {
|
|
// *pvtDer2 = V_NULL ;
|
|
// for ( int i = 0 ; i <= m_nDeg - 2 ; ++ i) {
|
|
// *pvtDer2 += vBern[i] * ( vPtWCtrl[i+2] + vPtWCtrl[i] - 2 * vPtWCtrl[i+1]) ;
|
|
// dW2 += vBern[i] * ( m_vWeCtrl[i+2] + m_vWeCtrl[i] - 2 * m_vWeCtrl[i+1]) ;
|
|
// }
|
|
// *pvtDer2 *= m_nDeg * ( m_nDeg - 1) ;
|
|
// dW2 *= m_nDeg * ( m_nDeg - 1) ;
|
|
// }
|
|
|
|
// aumento il grado
|
|
IncreaseAllBernsteinOneDegree( dLocU, m_nDegU - 1, vBernU) ;
|
|
|
|
// se richiesto, calcolo dei vettori intermedi per la derivata prima rispetto ad U
|
|
VCT3DVECTOR vtTemp1( m_nDegV + 1, V_NULL) ;
|
|
DBLVECTOR dTemp1( m_nDegV + 1, 0) ;
|
|
if ( pvtDerU != nullptr) {
|
|
for ( int j = 0 ; j <= m_nDegV ; ++ j) {
|
|
for ( int i = 0 ; i <= m_nDegU - 1 ; ++ i) {
|
|
vtTemp1[j] += vBernU[i] * ( vPtWCtrl[GetLocInd( i + 1, j)] - vPtWCtrl[GetLocInd( i, j)]) ;
|
|
dTemp1[j] += vBernU[i] * ( vWeCtrl[GetLocInd( i + 1, j)] - vWeCtrl[GetLocInd( i, j)]) ;
|
|
}
|
|
vtTemp1[j] *= m_nDegU ;
|
|
dTemp1[j] *= m_nDegU ;
|
|
}
|
|
}
|
|
|
|
// aumento il grado
|
|
IncreaseAllBernsteinOneDegree( dLocU, m_nDegU, vBernU) ;
|
|
|
|
// calcolo dei punti e pesi intermedi
|
|
PNTVECTOR ptTempW( m_nDegV + 1, ORIG) ;
|
|
DBLVECTOR dTempW( m_nDegV + 1, 0) ;
|
|
for ( int j = 0 ; j <= m_nDegV ; ++ j) {
|
|
for ( int i = 0 ; i <= m_nDegU ; ++ i) {
|
|
ptTempW[j] += vBernU[i] * vPtWCtrl[GetLocInd( i, j)] ;
|
|
dTempW[j] += vBernU[i] * vWeCtrl[GetLocInd( i, j)] ;
|
|
}
|
|
}
|
|
|
|
// calcolo dei polinomi di Bernstein per V di grado opportuno
|
|
DBLVECTOR vBernV( m_nDegV + 1) ;
|
|
GetAllBernstein( dLocV, m_nDegV - 1, vBernV) ;
|
|
|
|
// se richiesto, calcolo della derivata prima rispetto a V
|
|
double dW1v = 0 ;
|
|
if ( pvtDerV != nullptr) {
|
|
*pvtDerV = V_NULL ;
|
|
for ( int j = 0 ; j <= m_nDegV - 1 ; ++ j) {
|
|
*pvtDerV += vBernV[j] * ( ptTempW[j+1] - ptTempW[j]) ;
|
|
dW1v += vBernV[j] * ( dTempW[j+1] - dTempW[j]) ;
|
|
}
|
|
*pvtDerV *= m_nDegV ;
|
|
dW1v *= m_nDegV ;
|
|
}
|
|
|
|
// aumento il grado
|
|
IncreaseAllBernsteinOneDegree( dLocV, m_nDegV, vBernV) ;
|
|
|
|
// calcolo del punto
|
|
double dW = 0 ;
|
|
ptPos = ORIG ;
|
|
for ( int j = 0 ; j <= m_nDegV ; ++ j) {
|
|
ptPos += vBernV[j] * ptTempW[j] ;
|
|
dW += vBernV[j] * dTempW[j] ;
|
|
}
|
|
|
|
// ritrasformo da forma omogenea a forma standard
|
|
double dInvW = 1 / ( ( dW > EPS_ZERO) ? dW : EPS_ZERO) ;
|
|
ptPos *= dInvW ;
|
|
|
|
// se richiesto, calcolo della derivata prima rispetto a U
|
|
if ( pvtDerU != nullptr) {
|
|
*pvtDerU = V_NULL ;
|
|
double dW1u = 0 ;
|
|
for ( int j = 0 ; j <= m_nDegV ; ++ j) {
|
|
*pvtDerU += vBernV[j] * vtTemp1[j] ;
|
|
dW1u += vBernV[j] * dTemp1[j] ;
|
|
}
|
|
Vector3d vtPos( ptPos.x, ptPos.y, ptPos.z) ;
|
|
*pvtDerU = ( *pvtDerU - dW1u * vtPos) * dInvW ;
|
|
}
|
|
|
|
// se richiesto, completo il calcolo della derivata prima rispetto a V
|
|
if ( pvtDerV != nullptr) {
|
|
Vector3d vtPos( ptPos.x, ptPos.y, ptPos.z) ;
|
|
*pvtDerV = ( *pvtDerV - dW1v * vtPos) * dInvW ;
|
|
}
|
|
|
|
//if ( pvtDer1 != nullptr) {
|
|
// Vector3d vtPos( ptPos.x, ptPos.y, ptPos.z) ;
|
|
// *pvtDer1 = ( *pvtDer1 - dW1 * vtPos) * dInvW ;
|
|
// if ( pvtDer2 != nullptr)
|
|
// *pvtDer2 = ( *pvtDer2 - 2 * dW1 * *pvtDer1 - dW2 * vtPos) * dInvW ;
|
|
//}
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::GetPointNrmD1D2( double dU, double dV, Side nUs, Side nVs,
|
|
Point3d& ptPos, Vector3d& vtN,
|
|
Vector3d* pvtDerU, Vector3d* pvtDerV, Vector3d* pvtDerUU, Vector3d* pvtDerVV, Vector3d* pvtDerUV) const
|
|
{
|
|
// la superficie deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// i parametri U e V devono essere compresi tra 0 e il corrispondente numero di Span
|
|
dU = Clamp( dU, 0., double( m_nSpanU)) ;
|
|
dV = Clamp( dV, 0., double( m_nSpanV)) ;
|
|
|
|
// eseguo calcolo del punto con le derivate prime
|
|
Vector3d vtDerU ;
|
|
if ( pvtDerU == nullptr)
|
|
pvtDerU = &vtDerU ;
|
|
Vector3d vtDerV ;
|
|
if ( pvtDerV == nullptr)
|
|
pvtDerV = &vtDerV ;
|
|
GetPointD1D2( dU, dV, nUs, nVs, ptPos, pvtDerU, pvtDerV) ;
|
|
|
|
// calcolo la normale e la verifico
|
|
vtN = *pvtDerU ^ *pvtDerV ;
|
|
if ( vtN.Normalize())
|
|
return true ;
|
|
|
|
// se solo una sola delle due derivate è piccola, mi sposto lungo l'altro parametro
|
|
if ( pvtDerU->Len() < EPS_SMALL && pvtDerV->Len() > 10 * EPS_SMALL) {
|
|
double dVm = dV ;
|
|
if ( nVs == ISurfBezier::FROM_MINUS)
|
|
dVm = ( dV - 100 * EPS_PARAM < 0 ? dV + 100 * EPS_PARAM : dV - 100 * EPS_PARAM) ;
|
|
else
|
|
dVm = ( dV + 100 * EPS_PARAM > m_nSpanV ? dV - 100 * EPS_PARAM : dV + 100 * EPS_PARAM) ;
|
|
Point3d ptTmp ;
|
|
Vector3d vtTmpU, vtTmpV ;
|
|
GetPointD1D2( dU, dVm, nUs, nVs, ptTmp, &vtTmpU, &vtTmpV) ;
|
|
vtN = vtTmpU ^ vtTmpV ;
|
|
if ( vtN.Normalize())
|
|
return true ;
|
|
}
|
|
if ( pvtDerU->Len() > 10 * EPS_SMALL && pvtDerV->Len() < EPS_SMALL) {
|
|
double dUm = dU ;
|
|
if ( nUs == ISurfBezier::FROM_MINUS)
|
|
dUm = ( dU - 100 * EPS_PARAM < 0 ? dU + 100 * EPS_PARAM : dU - 100 * EPS_PARAM) ;
|
|
else
|
|
dUm = ( dU + 100 * EPS_PARAM > m_nSpanU ? dU - 100 * EPS_PARAM : dU + 100 * EPS_PARAM) ;
|
|
Point3d ptTmp ;
|
|
Vector3d vtTmpU, vtTmpV ;
|
|
GetPointD1D2( dUm, dV, nUs, nVs, ptTmp, &vtTmpU, &vtTmpV) ;
|
|
vtN = vtTmpU ^ vtTmpV ;
|
|
if ( vtN.Normalize())
|
|
return true ;
|
|
}
|
|
|
|
// ricalcolo con una piccola variazione di entrambi i parametri
|
|
double dUm = dU ;
|
|
if ( nUs == ISurfBezier::FROM_MINUS)
|
|
dUm = ( dU - 100 * EPS_PARAM < 0 ? dU + 100 * EPS_PARAM : dU - 100 * EPS_PARAM) ;
|
|
else
|
|
dUm = ( dU + 100 * EPS_PARAM > m_nSpanU ? dU - 100 * EPS_PARAM : dU + 100 * EPS_PARAM) ;
|
|
double dVm = dV ;
|
|
if ( nVs == ISurfBezier::FROM_MINUS)
|
|
dVm = ( dV - 100 * EPS_PARAM < 0 ? dV + 100 * EPS_PARAM : dV - 100 * EPS_PARAM) ;
|
|
else
|
|
dVm = ( dV + 100 * EPS_PARAM > m_nSpanV ? dV - 100 * EPS_PARAM : dV + 100 * EPS_PARAM) ;
|
|
Point3d ptTmp ;
|
|
Vector3d vtTmpU, vtTmpV ;
|
|
GetPointD1D2( dUm, dVm, nUs, nVs, ptTmp, &vtTmpU, &vtTmpV) ;
|
|
vtN = vtTmpU ^ vtTmpV ;
|
|
return vtN.Normalize() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
SurfBezier*
|
|
SurfBezier::Clone( void) const
|
|
{
|
|
// alloco oggetto
|
|
SurfBezier* pSbz = new( nothrow) SurfBezier ;
|
|
if ( pSbz != nullptr) {
|
|
if ( ! pSbz->CopyFrom( *this)) {
|
|
delete pSbz ;
|
|
return nullptr ;
|
|
}
|
|
}
|
|
|
|
return pSbz ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::CopyFrom( const IGeoObj* pGObjSrc)
|
|
{
|
|
const SurfBezier* pSbz = GetBasicSurfBezier( pGObjSrc) ;
|
|
if ( pSbz == nullptr)
|
|
return false ;
|
|
return CopyFrom( *pSbz) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::CopyFrom( const SurfBezier& sbSrc)
|
|
{
|
|
if ( &sbSrc == this)
|
|
return true ;
|
|
if ( ! Init( sbSrc.m_nDegU, sbSrc.m_nDegV, sbSrc.m_nSpanU, sbSrc.m_nSpanV, sbSrc.m_bRat))
|
|
return false ;
|
|
m_nStatus = sbSrc.m_nStatus ;
|
|
m_vPtCtrl = sbSrc.m_vPtCtrl ;
|
|
if ( sbSrc.m_bRat)
|
|
m_vWeCtrl = sbSrc.m_vWeCtrl ;
|
|
if ( sbSrc.m_bTrimmed) {
|
|
m_bTrimmed = true ;
|
|
m_pTrimReg = sbSrc.m_pTrimReg->Clone() ;
|
|
}
|
|
#ifndef SAVEFAILEDTRIANGULATION
|
|
if ( sbSrc.GetAuxSurf() != nullptr)
|
|
m_pSTM = sbSrc.GetAuxSurf()->Clone() ;
|
|
#endif
|
|
for ( int i = 0 ; i < int( sbSrc.m_mCCEdge.size()) ; ++i) {
|
|
m_mCCEdge.emplace_back() ;
|
|
for ( int j = 0 ; j < int( sbSrc.m_mCCEdge[i].size()) ; ++j ) {
|
|
m_mCCEdge.back().emplace_back( sbSrc.m_mCCEdge[i][j]->Clone()) ;
|
|
}
|
|
}
|
|
if ( sbSrc.m_bTrimmed) {
|
|
for ( int i = 0 ; i < int( sbSrc.m_vCCLoop.size()) ; ++i)
|
|
m_vCCLoop.emplace_back( sbSrc.m_vCCLoop[i]->Clone());
|
|
}
|
|
m_bClosedU = sbSrc.m_bClosedU ;
|
|
m_bClosedV = sbSrc.m_bClosedV ;
|
|
m_nTempProp[0] = sbSrc.m_nTempProp[0] ;
|
|
m_nTempProp[1] = sbSrc.m_nTempProp[1] ;
|
|
m_dTempParam[0] = sbSrc.m_dTempParam[0] ;
|
|
m_dTempParam[1] = sbSrc.m_dTempParam[1] ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
GeoObjType
|
|
SurfBezier::GetType( void) const
|
|
{
|
|
return static_cast<GeoObjType>( GEOOBJ_GETTYPE( SurfBezier)) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
const string&
|
|
SurfBezier::GetTitle( void) const
|
|
{
|
|
static const string sTitle = "SurfBezier" ;
|
|
return sTitle ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::Dump( string& sOut, bool bMM, const char* szNewLine) const
|
|
{
|
|
// verifico validità superficie
|
|
if ( m_nStatus != OK)
|
|
sOut += string( "Status=Invalid") + szNewLine ;
|
|
// area
|
|
double dArea ;
|
|
GetArea( dArea) ;
|
|
sOut += "Area=" + ToString( GetAreaInUiUnits( dArea, bMM),1) + szNewLine ;
|
|
// altri dati per superficie chiusa
|
|
if ( IsClosed()) {
|
|
double dVolume ;
|
|
GetVolume( dVolume) ;
|
|
sOut += "Closed Volume=" + ToString( GetVolumeInUiUnits( dVolume, bMM), 1) + szNewLine ;
|
|
}
|
|
// parametri : flag razionale
|
|
sOut += ( m_bRat ? "Rat" : "Int") ;
|
|
// flag trimmata
|
|
sOut += ( m_bTrimmed ? " Trim " : " Full") ;
|
|
// gradi in U e V
|
|
sOut += " DegU=" + ToString( m_nDegU) + " DegV=" + ToString( m_nDegV) ;
|
|
// pezze in U e V
|
|
sOut += " SpanU=" + ToString( m_nSpanU) + " SpanV=" + ToString( m_nSpanV) + szNewLine ;
|
|
// ciclo sui punti di controllo ( con pesi se razionale)
|
|
for ( int i = 0 ; i < GetDim() ; ++ i) {
|
|
sOut += "PC(" + ToString( GetInUiUnits( m_vPtCtrl[i], bMM), 3) ;
|
|
if ( m_bRat)
|
|
sOut += "," + ToString( m_vWeCtrl[i], 3) ;
|
|
sOut += string( ")") + szNewLine ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int
|
|
SurfBezier::GetNgeId( void) const
|
|
{
|
|
return GEOOBJ_GETNGEID( SurfBezier) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::Save( NgeWriter& ngeOut) const
|
|
{
|
|
// flag razionale
|
|
if ( ! ngeOut.WriteBool( m_bRat, ";"))
|
|
return false ;
|
|
// flag trimmata
|
|
if ( ! ngeOut.WriteBool( m_bTrimmed, ";"))
|
|
return false ;
|
|
// gradi
|
|
if ( ! ngeOut.WriteInt( m_nDegU, ",") ||
|
|
! ngeOut.WriteInt( m_nDegV, ";", false))
|
|
return false ;
|
|
// pezze
|
|
if ( ! ngeOut.WriteInt( m_nSpanU, ",") ||
|
|
! ngeOut.WriteInt( m_nSpanV, ";", true))
|
|
return false ;
|
|
// ciclo sui punti di controllo ( con pesi se razionale)
|
|
for ( int i = 0 ; i < GetDim() ; ++ i) {
|
|
if ( ! m_bRat) {
|
|
if ( ! ngeOut.WritePoint( m_vPtCtrl[i], ";", true))
|
|
return false ;
|
|
}
|
|
else {
|
|
if ( ! ngeOut.WritePointW( m_vPtCtrl[i], m_vWeCtrl[i], ";", true))
|
|
return false ;
|
|
}
|
|
}
|
|
// se trimmata, scrittura della regione
|
|
if ( m_bTrimmed) {
|
|
// recupero il gestore di lettura/scrittura della regione
|
|
const IGeoObjRW* pSFrRW = dynamic_cast<const IGeoObjRW*>( m_pTrimReg) ;
|
|
if ( pSFrRW == nullptr)
|
|
return false ;
|
|
// salvataggio della regione
|
|
if ( ! pSFrRW->Save( ngeOut))
|
|
return false ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::Load( NgeReader& ngeIn)
|
|
{
|
|
// imposto ricalcolo della grafica
|
|
ResetAuxSurf() ;
|
|
m_OGrMgr.Reset() ;
|
|
// leggo la prossima linea ( 3 parametri)
|
|
// recupero il flag razionale
|
|
bool bIsRat ;
|
|
if ( ! ngeIn.ReadBool( bIsRat, ";"))
|
|
return false ;
|
|
// recupero il flag trimmata
|
|
bool bTrimmed ;
|
|
if ( ! ngeIn.ReadBool( bTrimmed, ";"))
|
|
return false ;
|
|
// recupero i gradi
|
|
int nDegU, nDegV ;
|
|
if ( ! ngeIn.ReadInt( nDegU, ",") ||
|
|
! ngeIn.ReadInt( nDegV, ";"))
|
|
return false ;
|
|
// recupero le pezze
|
|
int nSpanU, nSpanV ;
|
|
if ( ! ngeIn.ReadInt( nSpanU, ",") ||
|
|
! ngeIn.ReadInt( nSpanV, ";", true))
|
|
return false ;
|
|
// inizializzo la superficie di Bezier
|
|
if ( ! Init( nDegU, nDegV, nSpanU, nSpanV, bIsRat))
|
|
return false ;
|
|
// se integrale
|
|
if ( ! bIsRat) {
|
|
// recupero e setto punti di controllo
|
|
Point3d ptP ;
|
|
for ( int i = 0 ; i < GetDim() ; ++ i) {
|
|
// leggo la prossima linea ( un punto)
|
|
if ( ! ngeIn.ReadPoint( ptP, ";", true))
|
|
return false ;
|
|
// lo assegno
|
|
if ( ! SetControlPoint( i, ptP))
|
|
return false ;
|
|
}
|
|
}
|
|
// altrimenti razionale
|
|
else {
|
|
// recupero e setto punti di controllo
|
|
Point3d ptP ;
|
|
double dW ;
|
|
for ( int i = 0 ; i < GetDim() ; ++ i) {
|
|
// leggo la prossima linea ( un punto con peso)
|
|
if ( ! ngeIn.ReadPointW( ptP, dW, ";", true))
|
|
return false ;
|
|
// lo assegno
|
|
if ( ! SetControlPoint( i, ptP, dW))
|
|
return false ;
|
|
}
|
|
}
|
|
// se trimmata, lettura della regione
|
|
if ( bTrimmed) {
|
|
// creo l'oggetto
|
|
ResetTrimRegion() ;
|
|
m_pTrimReg = CreateBasicSurfFlatRegion() ;
|
|
if ( m_pTrimReg == nullptr)
|
|
return false ;
|
|
// ne leggo i dati
|
|
IGeoObjRW* pGObjRW = dynamic_cast<IGeoObjRW*>( m_pTrimReg) ;
|
|
if ( pGObjRW == nullptr || ! pGObjRW->Load( ngeIn))
|
|
return false ;
|
|
m_bTrimmed = true ;
|
|
}
|
|
|
|
#if SAVEISO
|
|
ICURVEPOVECTOR vCrv ;
|
|
GetAllPatchesIsocurves( false, vCrv) ;
|
|
vector<IGeoObj*> vGeo ;
|
|
for ( int i = 0 ; i < ssize(vCrv) ; ++i)
|
|
vGeo.push_back( vCrv[i]->Clone()) ;
|
|
SaveGeoObj( vGeo, "D:\\Temp\\bezier\\ruled\\rebuild\\isoCrv.nge") ;
|
|
#endif
|
|
|
|
// eseguo validazione
|
|
return Validate() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::Validate( void)
|
|
{
|
|
if ( m_nStatus == TO_VERIFY)
|
|
m_nStatus = ( ( m_nDegU * m_nDegV > 0 && ! m_vPtCtrl.empty()) ? OK : ERR) ;
|
|
|
|
return ( m_nStatus == OK) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::GetLocalBBox( BBox3d& b3Loc, int nFlag) const
|
|
{
|
|
// basta approssimato
|
|
if ( ( nFlag & BBF_EXACT) == 0) {
|
|
for ( int i = 0 ; i < GetDim() ; ++ i) {
|
|
Point3d ptTemp = m_vPtCtrl[i] ;
|
|
b3Loc.Add( ptTemp) ;
|
|
}
|
|
return true ;
|
|
}
|
|
// deve essere preciso
|
|
else {
|
|
// verifico esistenza trimesh associata
|
|
if ( m_pSTM == nullptr)
|
|
if ( ! GetAuxSurf())
|
|
return false ;
|
|
// calcolo il box della trimesh
|
|
return m_pSTM->GetLocalBBox( b3Loc, nFlag) ;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::GetBBox( const Frame3d& frRef, BBox3d& b3Ref, int nFlag) const
|
|
{
|
|
// basta approssimato
|
|
if ( ( nFlag & BBF_EXACT) == 0) {
|
|
for ( int i = 0 ; i < GetDim() ; ++ i) {
|
|
Point3d ptTemp = m_vPtCtrl[i] ;
|
|
ptTemp.ToGlob( frRef) ;
|
|
b3Ref.Add( ptTemp) ;
|
|
}
|
|
return true ;
|
|
}
|
|
// deve essere preciso
|
|
else {
|
|
// verifico esistenza trimesh associata
|
|
if ( m_pSTM == nullptr)
|
|
if ( ! GetAuxSurf())
|
|
return false ;
|
|
// calcolo il box della trimesh
|
|
return m_pSTM->GetBBox( frRef, b3Ref, nFlag) ;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::Translate( const Vector3d& vtMove)
|
|
{
|
|
// la superficie deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
ResetAuxSurf() ;
|
|
m_OGrMgr.Reset() ;
|
|
|
|
// traslo i punti di controllo
|
|
for ( auto& ptP : m_vPtCtrl)
|
|
ptP.Translate( vtMove) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::Rotate( const Point3d& ptAx, const Vector3d& vtAx, double dCosAng, double dSinAng)
|
|
{
|
|
// la superficie deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
// verifico validità dell'asse di rotazione
|
|
if ( vtAx.IsSmall())
|
|
return false ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
ResetAuxSurf() ;
|
|
m_OGrMgr.Reset() ;
|
|
|
|
// ruoto i punti di controllo
|
|
for ( auto& ptP : m_vPtCtrl)
|
|
ptP.Rotate( ptAx, vtAx, dCosAng, dSinAng) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::Scale( const Frame3d& frRef, double dCoeffX, double dCoeffY, double dCoeffZ)
|
|
{
|
|
// la superficie deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
// verifico non sia nulla
|
|
if ( abs( dCoeffX) < EPS_ZERO && abs( dCoeffY) < EPS_ZERO && abs( dCoeffZ) < EPS_ZERO)
|
|
return false ;
|
|
|
|
// calcolo bbox allineato con riferimento di scalatura e senza tener conto dello spessore
|
|
// lo scalo per verificare se tutto si riduce a un punto o una linea (solo se diretta come assi ref)
|
|
BBox3d b3Ref ;
|
|
if ( ! GetBBox( frRef, b3Ref))
|
|
return false ;
|
|
Vector3d vtDelta = b3Ref.GetMax() - b3Ref.GetMin() ;
|
|
bool bZeroX = ( abs( vtDelta.x * dCoeffX) < EPS_SMALL) ;
|
|
bool bZeroY = ( abs( vtDelta.y * dCoeffY) < EPS_SMALL) ;
|
|
bool bZeroZ = ( abs( vtDelta.z * dCoeffZ) < EPS_SMALL) ;
|
|
if ( ( bZeroX && bZeroY) || ( bZeroX && bZeroZ) || ( bZeroY && bZeroZ))
|
|
return false ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
ResetAuxSurf() ;
|
|
m_OGrMgr.Reset() ;
|
|
|
|
// scalo i punti di controllo
|
|
for ( auto& ptP : m_vPtCtrl)
|
|
ptP.Scale( frRef, dCoeffX, dCoeffY, dCoeffZ) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::Mirror( const Point3d& ptOn, const Vector3d& vtNorm)
|
|
{
|
|
// la superficie deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
// verifico validità del piano di specchiatura
|
|
if ( vtNorm.IsSmall())
|
|
return false ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
ResetAuxSurf() ;
|
|
m_OGrMgr.Reset() ;
|
|
|
|
// specchio i punti di controllo
|
|
for ( auto& ptP : m_vPtCtrl)
|
|
ptP.Mirror( ptOn, vtNorm) ;
|
|
|
|
// eseguo invert per mantenere l'orientazione
|
|
return Invert() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::Shear( const Point3d& ptOn, const Vector3d& vtNorm, const Vector3d& vtDir, double dCoeff)
|
|
{
|
|
// la superficie deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
// verifico validità dei parametri
|
|
if ( vtNorm.IsSmall() || vtDir.IsSmall())
|
|
return false ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
ResetAuxSurf() ;
|
|
m_OGrMgr.Reset() ;
|
|
|
|
// eseguo scorrimento dei punti di controllo
|
|
for ( auto& ptP : m_vPtCtrl)
|
|
ptP.Shear( ptOn, vtNorm, vtDir, dCoeff) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::ToGlob( const Frame3d& frRef)
|
|
{
|
|
// la superficie deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
// verifico validità del frame
|
|
if ( frRef.GetType() == Frame3d::ERR)
|
|
return false ;
|
|
|
|
// se frame identità, non devo fare alcunché
|
|
if ( IsGlobFrame( frRef))
|
|
return true ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
ResetAuxSurf() ;
|
|
m_OGrMgr.Reset() ;
|
|
|
|
// trasformo i punti di controllo
|
|
for ( auto& ptP : m_vPtCtrl)
|
|
ptP.ToGlob( frRef) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::ToLoc( const Frame3d& frRef)
|
|
{
|
|
// la superficie deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
// verifico validità del frame
|
|
if ( frRef.GetType() == Frame3d::ERR)
|
|
return false ;
|
|
|
|
// se frame identità, non devo fare alcunché
|
|
if ( IsGlobFrame( frRef))
|
|
return true ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
ResetAuxSurf() ;
|
|
m_OGrMgr.Reset() ;
|
|
|
|
// trasformo i punti di controllo
|
|
for ( auto& ptP : m_vPtCtrl)
|
|
ptP.ToLoc( frRef) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::LocToLoc( const Frame3d& frOri, const Frame3d& frDest)
|
|
{
|
|
// la superficie deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
// verifico validità dei frame
|
|
if ( frOri.GetType() == Frame3d::ERR || frDest.GetType() == Frame3d::ERR)
|
|
return false ;
|
|
|
|
// se i due riferimenti coincidono, non devo fare alcunché
|
|
if ( AreSameFrame( frOri, frDest))
|
|
return true ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
ResetAuxSurf() ;
|
|
m_OGrMgr.Reset() ;
|
|
|
|
// trasformo i punti di controllo
|
|
for ( auto& ptP : m_vPtCtrl)
|
|
ptP.LocToLoc( frOri, frDest) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::Invert( void)
|
|
{
|
|
// la superficie deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
ResetAuxSurf() ;
|
|
m_OGrMgr.Reset() ;
|
|
|
|
// inverto i punti del parametro U
|
|
PNTVECTOR vPtCtrl_inv( m_vPtCtrl.size()) ;
|
|
|
|
for ( int j = 0 ; j < m_nDegV * m_nSpanV + 1; ++j) {
|
|
for ( int i = 0 ; i < m_nDegU * m_nSpanU + 1; ++i) {
|
|
vPtCtrl_inv[ i + j * ( m_nDegU * m_nSpanU + 1)] = m_vPtCtrl[ ( m_nDegU * m_nSpanU - i) + j * ( m_nDegU * m_nSpanU + 1)] ;
|
|
}
|
|
}
|
|
m_vPtCtrl = vPtCtrl_inv ;
|
|
|
|
if ( m_bTrimmed) {
|
|
// inverto la flat region di trim
|
|
//( la specchio rispetto all'asse verticale)
|
|
Point3d pt( m_nSpanU * SBZ_TREG_COEFF/2, 0, 0) ;
|
|
Vector3d vt( 1, 0, 0) ;
|
|
m_pTrimReg->Mirror( pt, vt) ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int
|
|
SurfBezier::GetSteps( int nDeg, int nSpan, double dLen, int nQuality) const
|
|
{
|
|
const double dCoeff[] = { 0, 1, 2, 2.4, 2.8, 3, 3, 3, 3, 3, 3, 3} ;
|
|
nDeg = Clamp( nDeg, 0, MAXDEG) ;
|
|
nSpan = max( nSpan, 1) ;
|
|
nQuality = Clamp( nQuality, 1, 10) ;
|
|
double dMult = sqrt( max( dLen / nSpan, 10.)) ;
|
|
return ( nSpan * int( dMult * dCoeff[nDeg] * 2 / nQuality)) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
CurveComposite*
|
|
SurfBezier::GetCurveOnU( double dV) const
|
|
{
|
|
// controlli
|
|
if ( dV < - EPS_PARAM || dV > m_nSpanV + EPS_PARAM)
|
|
return nullptr ;
|
|
dV = Clamp( dV, 0., double( m_nSpanV)) ;
|
|
|
|
// determino l'intervallo di span in V e riduco i parametri in essi
|
|
int nBsV = min( int( dV), m_nSpanV - 1) ;
|
|
double dLocV = dV - nBsV ;
|
|
int nOffsV = nBsV * m_nDegV ;
|
|
|
|
// verifico se il parametro è intero allora semplicemente recupero i punti di controllo
|
|
if ( abs( dV - int( dV)) < EPS_PARAM) {
|
|
int nV = int( round( dV)) ;
|
|
PtrOwner<CurveComposite> pCrvCo( CreateBasicCurveComposite()) ;
|
|
bool bOk = false ;
|
|
if ( ! m_bRat) {
|
|
// ciclo sugli intervalli
|
|
for ( int s = 0 ; s < m_nSpanU ; ++ s) {
|
|
PtrOwner<CurveBezier> pCbz( CreateBasicCurveBezier()) ;
|
|
pCbz->Init( m_nDegU, m_bRat) ;
|
|
for ( int j = 0 ; j < m_nDegU ; ++j)
|
|
pCbz->SetControlPoint( s * m_nDegU + j, GetControlPoint( GetInd( s * m_nDegU + j , nV * m_nDegV), &bOk), GetControlWeight( GetInd( s * m_nDegU + j , nV * m_nDegV), &bOk)) ;
|
|
pCrvCo->AddCurve( Release( pCbz)) ;
|
|
}
|
|
}
|
|
else {
|
|
// ciclo sugli intervalli
|
|
for ( int s = 0 ; s < m_nSpanU ; ++ s) {
|
|
PtrOwner<CurveBezier> pCbz( CreateBasicCurveBezier()) ;
|
|
pCbz->Init( m_nDegU, m_bRat) ;
|
|
for ( int j = 0 ; j < m_nDegU ; ++j)
|
|
pCbz->SetControlPoint( s * m_nDegU + j, GetControlPoint( GetInd( s * m_nDegU + j , nV * m_nDegV), &bOk)) ;
|
|
pCrvCo->AddCurve( Release( pCbz)) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// se forma polinomiale (o integrale)
|
|
if ( ! m_bRat) {
|
|
// preparazione della curva composita
|
|
PtrOwner<CurveComposite> pCrvCo( CreateBasicCurveComposite()) ;
|
|
// ciclo sugli intervalli
|
|
for ( int k = 0 ; k < m_nSpanU ; ++ k) {
|
|
// preparazione della curva di Bezier
|
|
PtrOwner<CurveBezier> pCbz( CreateBasicCurveBezier()) ;
|
|
if ( IsNull( pCbz) || ! pCbz->Init( m_nDegU, false))
|
|
return nullptr ;
|
|
// calcolo dei polinomi di Bernstein per V di grado opportuno
|
|
DBLVECTOR vBernV( m_nDegV + 1) ;
|
|
GetAllBernstein( dLocV, m_nDegV, vBernV) ;
|
|
// calcolo offset in U
|
|
int nOffsU = k * m_nDegU ;
|
|
// calcolo dei punti di controllo della curva
|
|
for ( int i = 0 ; i <= m_nDegU ; ++ i) {
|
|
Point3d ptP = ORIG ;
|
|
for ( int j = 0 ; j <= m_nDegV ; ++ j)
|
|
ptP += vBernV[j] * m_vPtCtrl[GetInd( nOffsU + i, nOffsV + j)] ;
|
|
pCbz->SetControlPoint( i, ptP) ;
|
|
}
|
|
// inserisco la curva della pezza in quella complessiva
|
|
if ( ! IsNull( pCbz))
|
|
pCrvCo->AddCurve( Release( pCbz)) ;
|
|
}
|
|
return Release( pCrvCo) ;
|
|
}
|
|
// altrimenti forma razionale
|
|
else {
|
|
// preparazione della curva composita
|
|
PtrOwner<CurveComposite> pCrvCo( CreateBasicCurveComposite()) ;
|
|
// ciclo sugli intervalli
|
|
for ( int k = 0 ; k < m_nSpanU ; ++ k) {
|
|
// preparazione della curva di Bezier
|
|
PtrOwner<CurveBezier> pCbz( CreateBasicCurveBezier()) ;
|
|
if ( IsNull( pCbz) || ! pCbz->Init( m_nDegU, true))
|
|
return nullptr ;
|
|
// calcolo dei polinomi di Bernstein per V di grado opportuno
|
|
DBLVECTOR vBernV( m_nDegV + 1) ;
|
|
GetAllBernstein( dLocV, m_nDegV, vBernV) ;
|
|
// calcolo offset in U
|
|
int nOffsU = k * m_nDegU ;
|
|
// porto i punti in forma omogenea moltiplicandoli per i pesi
|
|
PNTVECTOR vPtWCtrl( GetLocDim()) ;
|
|
DBLVECTOR vWeCtrl( GetLocDim()) ;
|
|
for ( int j = 0 ; j <= m_nDegV ; ++ j) {
|
|
for ( int i = 0 ; i <= m_nDegU ; ++ i) {
|
|
vPtWCtrl[GetLocInd( i, j)] = m_vWeCtrl[GetInd( nOffsU + i, nOffsV + j)] * m_vPtCtrl[GetInd( nOffsU + i, nOffsV + j)] ;
|
|
vWeCtrl[GetLocInd( i, j)] = m_vWeCtrl[GetInd( nOffsU + i, nOffsV + j)] ;
|
|
}
|
|
}
|
|
// calcolo dei punti di controllo della curva
|
|
for ( int i = 0 ; i <= m_nDegU ; ++ i) {
|
|
Point3d ptP = ORIG ;
|
|
double dW = 0 ;
|
|
for ( int j = 0 ; j <= m_nDegV ; ++ j) {
|
|
ptP += vBernV[j] * vPtWCtrl[GetLocInd( i, j)] ;
|
|
dW += vBernV[j] * vWeCtrl[GetLocInd( i, j)] ;
|
|
}
|
|
double dInvW = 1 / ( ( dW > EPS_ZERO) ? dW : EPS_ZERO) ;
|
|
pCbz->SetControlPoint( i, ptP * dInvW, dW) ;
|
|
}
|
|
// inserisco la curva della pezza in quella complessiva
|
|
if ( ! IsNull( pCbz))
|
|
pCrvCo->AddCurve( Release( pCbz)) ;
|
|
}
|
|
return Release( pCrvCo) ;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
CurveComposite*
|
|
SurfBezier::GetCurveOnV( double dU) const
|
|
{
|
|
// controlli
|
|
if ( dU < - EPS_PARAM || dU > m_nSpanU + EPS_PARAM)
|
|
return nullptr ;
|
|
dU = Clamp( dU, 0., double( m_nSpanU)) ;
|
|
|
|
// determino l'intervallo di span in U e riduco i parametri in essi
|
|
int nBsU = min( int( dU), m_nSpanU - 1) ;
|
|
double dLocU = dU - nBsU ;
|
|
int nOffsU = nBsU * m_nDegU ;
|
|
|
|
// verifico se il parametro è intero allora semplicemente recupero i punti di controllo
|
|
if ( abs( dU - int( dU)) < EPS_PARAM) {
|
|
int nU = int( round( dU)) ;
|
|
PtrOwner<CurveComposite> pCrvCo( CreateBasicCurveComposite()) ;
|
|
bool bOk = false ;
|
|
if ( ! m_bRat) {
|
|
// ciclo sugli intervalli
|
|
for ( int s = 0 ; s < m_nSpanV ; ++ s) {
|
|
PtrOwner<CurveBezier> pCbz( CreateBasicCurveBezier()) ;
|
|
pCbz->Init( m_nDegV, m_bRat) ;
|
|
for ( int j = 0 ; j < m_nDegV ; ++j)
|
|
pCbz->SetControlPoint( s * m_nDegV + j, GetControlPoint( GetInd( s * m_nDegV + j , nU * m_nDegU), &bOk), GetControlWeight( GetInd( s * m_nDegV + j , nU * m_nDegU), &bOk)) ;
|
|
pCrvCo->AddCurve( Release( pCbz)) ;
|
|
}
|
|
}
|
|
else {
|
|
// ciclo sugli intervalli
|
|
for ( int s = 0 ; s < m_nSpanV ; ++ s) {
|
|
PtrOwner<CurveBezier> pCbz( CreateBasicCurveBezier()) ;
|
|
pCbz->Init( m_nDegV, m_bRat) ;
|
|
for ( int j = 0 ; j < m_nDegV ; ++j)
|
|
pCbz->SetControlPoint( s * m_nDegV + j, GetControlPoint( GetInd( s * m_nDegV + j , nU * m_nDegU), &bOk)) ;
|
|
pCrvCo->AddCurve( Release( pCbz)) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// se forma polinomiale (o integrale)
|
|
if ( ! m_bRat) {
|
|
// preparazione della curva composita
|
|
PtrOwner<CurveComposite> pCrvCo( CreateBasicCurveComposite()) ;
|
|
// ciclo sugli intervalli
|
|
for ( int k = 0 ; k < m_nSpanV ; ++ k) {
|
|
// preparazione della curva di Bezier
|
|
PtrOwner<CurveBezier> pCbz( CreateBasicCurveBezier()) ;
|
|
if ( IsNull( pCbz) || ! pCbz->Init( m_nDegV, false))
|
|
return nullptr ;
|
|
// calcolo dei polinomi di Bernstein per U di grado opportuno
|
|
DBLVECTOR vBernU( m_nDegU + 1) ;
|
|
GetAllBernstein( dLocU, m_nDegU, vBernU) ;
|
|
// calcolo offset in V
|
|
int nOffsV = k * m_nDegV ;
|
|
// calcolo dei punti di controllo della curva
|
|
for ( int j = 0 ; j <= m_nDegV ; ++ j) {
|
|
Point3d ptP = ORIG ;
|
|
for ( int i = 0 ; i <= m_nDegU ; ++ i)
|
|
ptP += vBernU[i] * m_vPtCtrl[GetInd( nOffsU + i, nOffsV + j)] ;
|
|
pCbz->SetControlPoint( j, ptP) ;
|
|
}
|
|
// inserisco la curva della pezza in quella complessiva
|
|
if ( ! IsNull( pCbz))
|
|
pCrvCo->AddCurve( Release( pCbz)) ;
|
|
}
|
|
return Release( pCrvCo) ;
|
|
}
|
|
// altrimenti forma razionale
|
|
else {
|
|
// preparazione della curva composita
|
|
PtrOwner<CurveComposite> pCrvCo( CreateBasicCurveComposite()) ;
|
|
// ciclo sugli intervalli
|
|
for ( int k = 0 ; k < m_nSpanV ; ++ k) {
|
|
// preparazione della curva di Bezier
|
|
PtrOwner<CurveBezier> pCbz( CreateBasicCurveBezier()) ;
|
|
if ( IsNull( pCbz) || ! pCbz->Init( m_nDegV, true))
|
|
return nullptr ;
|
|
// calcolo dei polinomi di Bernstein per U di grado opportuno
|
|
DBLVECTOR vBernU( m_nDegU + 1) ;
|
|
GetAllBernstein( dLocU, m_nDegU, vBernU) ;
|
|
// calcolo offset in V
|
|
int nOffsV = k * m_nDegV ;
|
|
// porto i punti in forma omogenea moltiplicandoli per i pesi
|
|
PNTVECTOR vPtWCtrl( GetLocDim()) ;
|
|
DBLVECTOR vWeCtrl( GetLocDim()) ;
|
|
for ( int j = 0 ; j <= m_nDegV ; ++ j) {
|
|
for ( int i = 0 ; i <= m_nDegU ; ++ i) {
|
|
vPtWCtrl[GetLocInd( i, j)] = m_vWeCtrl[GetInd( nOffsU + i, nOffsV + j)] * m_vPtCtrl[GetInd( nOffsU + i, nOffsV + j)] ;
|
|
vWeCtrl[GetLocInd( i, j)] = m_vWeCtrl[GetInd( nOffsU + i, nOffsV + j)] ;
|
|
}
|
|
}
|
|
// calcolo dei punti di controllo della curva
|
|
for ( int j = 0 ; j <= m_nDegV ; ++ j) {
|
|
Point3d ptP = ORIG ;
|
|
double dW = 0 ;
|
|
for ( int i = 0 ; i <= m_nDegU ; ++ i) {
|
|
ptP += vBernU[i] * vPtWCtrl[GetLocInd( i, j)] ;
|
|
dW += vBernU[i] * vWeCtrl[GetLocInd( i, j)] ;
|
|
}
|
|
double dInvW = 1 / ( ( dW > EPS_ZERO) ? dW : EPS_ZERO) ;
|
|
pCbz->SetControlPoint( j, ptP * dInvW, dW) ;
|
|
}
|
|
// inserisco la curva della pezza in quella complessiva
|
|
if ( ! IsNull( pCbz))
|
|
pCrvCo->AddCurve( Release( pCbz)) ;
|
|
}
|
|
return Release( pCrvCo) ;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
CurveComposite*
|
|
SurfBezier::GetLoop( int nLoop) const
|
|
{
|
|
// Il primo loop sono le 4 isoparametriche di bordo concatenate
|
|
if ( ! m_bTrimmed ) {
|
|
if ( nLoop != 0 )
|
|
return nullptr ;
|
|
// Loop
|
|
PtrOwner<CurveComposite> pLoop( CreateBasicCurveComposite()) ;
|
|
// prima curva isoparametrica in U con V=0
|
|
PtrOwner<CurveComposite> pCrvCoU0( GetCurveOnU( 0)) ;
|
|
if ( ! IsNull( pCrvCoU0) && ! pCrvCoU0->IsAPoint())
|
|
pLoop->AddCurve( Release( pCrvCoU0)) ;
|
|
// seconda curva isoparametrica in V con U=m_nSpanU
|
|
PtrOwner<CurveComposite> pCrvCoV1( GetCurveOnV( m_nSpanU)) ;
|
|
if ( ! IsNull( pCrvCoV1) && ! pCrvCoV1->IsAPoint())
|
|
pLoop->AddCurve( Release( pCrvCoV1)) ;
|
|
// terza curva isoparametrica in U con V=m_nSpanV invertita
|
|
PtrOwner<CurveComposite> pCrvCoU1( GetCurveOnU( m_nSpanV)) ;
|
|
if ( ! IsNull( pCrvCoU1) && ! pCrvCoU1->IsAPoint()) {
|
|
pCrvCoU1->Invert() ;
|
|
pLoop->AddCurve( Release( pCrvCoU1)) ;
|
|
}
|
|
// quarta curva isoparametrica in V con U=0 invertita
|
|
PtrOwner<CurveComposite> pCrvCoV0( GetCurveOnV( 0)) ;
|
|
if ( ! IsNull( pCrvCoV0) && ! pCrvCoV0->IsAPoint()) {
|
|
pCrvCoV0->Invert() ;
|
|
pLoop->AddCurve( Release( pCrvCoV0)) ;
|
|
}
|
|
// se loop chiuso lo restituisco, altrimenti errore
|
|
return ( pLoop->IsClosed() ? Release( pLoop) : nullptr) ;
|
|
}
|
|
// la superficie è trimmata, quindi devo cercare nei vari chunck il loop corrispondente
|
|
else {
|
|
if ( nLoop > m_pTrimReg->GetChunkCount())
|
|
return nullptr ;
|
|
else {
|
|
int nLoopCount = 0 ;
|
|
int nChunck = 0, nLoopLoc = 0;
|
|
INTVECTOR nLoopCountPerChunck ;
|
|
for ( int i = 0 ; i < m_pTrimReg->GetChunkCount() && nLoopCount != nLoop ; ++ i) {
|
|
int nLoopCountLoc = 0 ;
|
|
for ( int j = 0 ; j < m_pTrimReg->GetLoopCount( i) ; ++ j) {
|
|
++ nLoopCountLoc ;
|
|
++ nLoopCount ;
|
|
if ( nLoopCount != nLoop ) {
|
|
nChunck = i ;
|
|
nLoopLoc = j ;
|
|
break ;
|
|
}
|
|
}
|
|
nLoopCountPerChunck.push_back( nLoopCountLoc) ;
|
|
}
|
|
if ( nLoopCount < nLoop )
|
|
return nullptr ;
|
|
PtrOwner<CurveComposite> pLoop( GetBasicCurveComposite( m_pTrimReg->GetLoop( nChunck, nLoopLoc))) ;
|
|
return Release( pLoop) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::GetCurveOnU( double dV, int nStep, PolyLine& plCrvU) const
|
|
{
|
|
// controlli
|
|
plCrvU.Clear() ;
|
|
if ( dV < - EPS_PARAM || dV > m_nSpanV + EPS_PARAM)
|
|
return false ;
|
|
dV = Clamp( dV, 0., double( m_nSpanV)) ;
|
|
// recupero la curva
|
|
PtrOwner<CurveComposite> pCrvCo( GetCurveOnU( dV)) ;
|
|
if ( IsNull( pCrvCo))
|
|
return false ;
|
|
// ciclo sulle curve componenti (tutte curve di Bezier)
|
|
int i = 0 ;
|
|
const ICurve* pSCrv = pCrvCo->GetFirstCurve() ;
|
|
while ( pSCrv != nullptr) {
|
|
const CurveBezier* pCbz = GetBasicCurveBezier( pSCrv) ;
|
|
if ( pCbz == NULL)
|
|
return false ;
|
|
int nCurrSpanStep = nStep / m_nSpanU ;
|
|
if ( nCurrSpanStep <= 0) {
|
|
double dLenU = 0 ;
|
|
pCbz->GetApproxLength( dLenU) ;
|
|
nCurrSpanStep = GetSteps( m_nDegU, 1, dLenU, 2) ;
|
|
}
|
|
PolyLine plCurr ;
|
|
if ( ! pCbz->ApproxWithLines( nCurrSpanStep, plCurr))
|
|
return false ;
|
|
plCrvU.Join( plCurr, i) ;
|
|
++ i ;
|
|
pSCrv = pCrvCo->GetNextCurve() ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::GetCurveOnV( double dU, int nStep, PolyLine& plCrvV) const
|
|
{
|
|
// controlli
|
|
plCrvV.Clear() ;
|
|
if ( dU < - EPS_PARAM || dU > m_nSpanU + EPS_PARAM)
|
|
return false ;
|
|
dU = Clamp( dU, 0., double( m_nSpanU)) ;
|
|
// recupero la curva
|
|
PtrOwner<CurveComposite> pCrvCo( GetCurveOnV( dU)) ;
|
|
if ( IsNull( pCrvCo))
|
|
return false ;
|
|
// ciclo sulle curve componenti (tutte curve di Bezier)
|
|
int i = 0 ;
|
|
const ICurve* pSCrv = pCrvCo->GetFirstCurve() ;
|
|
while ( pSCrv != nullptr) {
|
|
const CurveBezier* pCbz = GetBasicCurveBezier( pSCrv) ;
|
|
if ( pCbz == NULL)
|
|
return false ;
|
|
int nCurrSpanStep = nStep / m_nSpanU ;
|
|
if ( nCurrSpanStep <= 0) {
|
|
double dLenV = 0 ;
|
|
pCbz->GetApproxLength( dLenV) ;
|
|
nCurrSpanStep = GetSteps( m_nDegV, 1, dLenV, 2) ;
|
|
}
|
|
PolyLine plCurr ;
|
|
if ( ! pCbz->ApproxWithLines( nCurrSpanStep, plCurr))
|
|
return false ;
|
|
plCrvV.Join( plCurr, i) ;
|
|
++ i ;
|
|
pSCrv = pCrvCo->GetNextCurve() ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::GetControlCurveOnU( int nIndV, PolyLine& plCtrlU) const
|
|
{
|
|
plCtrlU.Clear() ;
|
|
if ( nIndV < 0 || nIndV > m_nDegV * m_nSpanV)
|
|
return false ;
|
|
for ( int i = 0 ; i <= m_nDegU * m_nSpanU ; ++ i)
|
|
plCtrlU.AddUPoint( double( i) / m_nDegU, m_vPtCtrl[GetInd( i, nIndV)]) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::GetControlCurveOnV( int nIndU, PolyLine& plCtrlV) const
|
|
{
|
|
plCtrlV.Clear() ;
|
|
if ( nIndU < 0 || nIndU > m_nDegU * m_nSpanU)
|
|
return false ;
|
|
for ( int j = 0 ; j <= m_nDegV * m_nSpanV ; ++ j)
|
|
plCtrlV.AddUPoint( double( j) / m_nDegV, m_vPtCtrl[GetInd( nIndU, j)]) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
double
|
|
SurfBezier::GetCurveOnUApproxLen( double dV) const
|
|
{
|
|
PtrOwner<CurveComposite> pCrvCo( GetCurveOnU( dV)) ;
|
|
double dLen ;
|
|
if ( IsNull( pCrvCo) || ! pCrvCo->GetApproxLength( dLen))
|
|
return 0 ;
|
|
return dLen ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
double
|
|
SurfBezier::GetCurveOnVApproxLen( double dU) const
|
|
{
|
|
PtrOwner<CurveComposite> pCrvCo( GetCurveOnV( dU)) ;
|
|
double dLen ;
|
|
if ( IsNull( pCrvCo) || ! pCrvCo->GetApproxLength( dLen))
|
|
return 0 ;
|
|
return dLen ;
|
|
}
|
|
|
|
int nSurf = 0 ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
const SurfTriMesh*
|
|
SurfBezier::GetAuxSurf( void) const
|
|
{
|
|
// la superficie deve essere validata
|
|
if ( m_nStatus != OK) {
|
|
ResetAuxSurf() ;
|
|
return nullptr ;
|
|
}
|
|
// se già calcolata
|
|
if ( m_pSTM != nullptr) {
|
|
// se con la stessa tolleranza, la restituisco
|
|
if ( abs( s_dAuxSurfTol - m_pSTM->GetTempParam()) < EPS_SMALL)
|
|
return m_pSTM ;
|
|
// altrimenti la cancello prima di ricalcolarla
|
|
else {
|
|
delete( m_pSTM) ;
|
|
m_pSTM = nullptr ;
|
|
}
|
|
}
|
|
else {
|
|
// se con la stessa precisione di quella di visualizzazione restituisco quella
|
|
if ( m_pSTMRefined != nullptr && s_dAuxSurfTol > m_pSTMRefined->GetTempParam() - EPS_SMALL) {
|
|
m_pSTM = m_pSTMRefined->Clone() ;
|
|
return m_pSTM ;
|
|
}
|
|
}
|
|
// eseguo calcolo
|
|
m_pSTM = GetApproxSurf( s_dAuxSurfTol, 100 * EPS_SMALL, false) ;
|
|
++nSurf ;
|
|
if ( m_pSTM != nullptr)
|
|
m_pSTM->SetTempParam( s_dAuxSurfTol) ;
|
|
return m_pSTM ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
const SurfTriMesh*
|
|
SurfBezier::GetAuxSurfRefined( void) const
|
|
{
|
|
// la superficie deve essere validata
|
|
if ( m_nStatus != OK) {
|
|
ResetAuxSurf() ;
|
|
return nullptr ;
|
|
}
|
|
// se già calcolata, la restituisco
|
|
if ( m_pSTMRefined != nullptr) {
|
|
// se con la stessa tolleranza o superiore alla precedente, la restituisco
|
|
if ( s_dAuxSurfRefinedTol > m_pSTMRefined->GetTempParam() - EPS_SMALL)
|
|
return m_pSTMRefined ;
|
|
// altrimenti la cancello prima di ricalcolarla
|
|
else {
|
|
delete( m_pSTMRefined) ;
|
|
m_pSTMRefined = nullptr ;
|
|
}
|
|
}
|
|
else {
|
|
// se con la stessa precisione di quella di visualizzazione restituisco quella
|
|
if ( m_pSTM != nullptr && s_dAuxSurfRefinedTol > m_pSTM->GetTempParam() - EPS_SMALL) {
|
|
m_pSTMRefined = m_pSTM->Clone() ;
|
|
return m_pSTMRefined ;
|
|
}
|
|
}
|
|
// eseguo calcolo
|
|
m_pSTMRefined = GetApproxSurf( s_dAuxSurfRefinedTol, 100 * EPS_SMALL, true) ;
|
|
if ( m_pSTMRefined != nullptr)
|
|
m_pSTMRefined->SetTempParam( s_dAuxSurfRefinedTol) ;
|
|
return m_pSTMRefined ;
|
|
}
|
|
|
|
#if SAVEFAILEDTRIANGULATION
|
|
static int nErr = 0 ;
|
|
#endif
|
|
|
|
//----------------------------------------------------------------------------
|
|
SurfTriMesh*
|
|
SurfBezier::GetApproxSurf( double dTol, double dSideMin, bool bUpdateEdges) const
|
|
{
|
|
// la superficie deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return nullptr ;
|
|
|
|
// se c'è ausiliaria di visualizzazione con gli stessi parametri, ne restituisco una copia
|
|
if ( m_pSTM != nullptr &&
|
|
abs( dTol - s_dAuxSurfTol) < EPS_SMALL && abs( dSideMin - 100 * EPS_SMALL) < EPS_SMALL)
|
|
return m_pSTM->Clone() ;
|
|
// se c'è ausiliaria e richiesta con gli stessi parametri, ne restituisco una copia
|
|
if ( m_pSTMRefined != nullptr &&
|
|
abs( dTol - s_dAuxSurfRefinedTol) < EPS_SMALL && abs( dSideMin - 100 * EPS_SMALL) < EPS_SMALL)
|
|
return m_pSTMRefined->Clone() ;
|
|
|
|
// costruttore della superficie
|
|
POLYLINEMATRIX vvPL ;
|
|
POLYLINEMATRIX vvPL3d ;
|
|
Tree Tree ;
|
|
if ( ! Tree.SetSurf( this))
|
|
return nullptr ;
|
|
BIPNTVECTOR vTrees ;
|
|
Tree.GetIndependentTrees( vTrees) ;
|
|
// resetto il vettore degli edge
|
|
m_mCCEdge.clear() ;
|
|
m_vCCLoop.clear() ;
|
|
|
|
for ( int i = 0 ; i < (int) vTrees.size() ; ++ i) {
|
|
Point3d ptMin = get<0>( vTrees[i]) ;
|
|
Point3d ptMax = get<1>( vTrees[i]) ;
|
|
Tree.SetSurf( this, ptMin, ptMax) ;
|
|
if ( ! Tree.BuildTree( dTol, dSideMin)) {
|
|
LOG_DBG_ERR( GetEGkLogger(), "ERROR : Bezier Surface parametric space couldn't be split in cells") ;
|
|
return nullptr ;
|
|
}
|
|
if ( ! Tree.GetPolygons( vvPL, vvPL3d, m_mCCEdge, m_vCCLoop, bUpdateEdges))
|
|
continue ;
|
|
|
|
// aggiorno la chiusura della superficie
|
|
m_bClosedU = m_bClosedU || Tree.IsClosedU() ;
|
|
m_bClosedV = m_bClosedV || Tree.IsClosedV() ;
|
|
}
|
|
|
|
if ( vvPL.empty()) {
|
|
LOG_DBG_ERR( GetEGkLogger(), "ERROR : Bezier Surface couldn't be triangulated")
|
|
#if SAVEFAILEDTRIANGULATION
|
|
SaveGeoObj( Clone(),"D:\\Temp\\bezier\\not_triangulated\\" + ToString( nErr) + ".nge") ;
|
|
++nErr ;
|
|
#endif
|
|
}
|
|
|
|
StmFromTriangleSoup stmSoup ;
|
|
if ( ! stmSoup.Start())
|
|
return nullptr ;
|
|
|
|
// prendo i punti di ogni polyline dell'albero, li triangolo e li porto in 3d
|
|
int c = 0 ;
|
|
for ( POLYLINEVECTOR& vPL : vvPL) {
|
|
PNTVECTOR vPnt ;
|
|
INTVECTOR vTria ;
|
|
Triangulate Tri ;
|
|
if ( ! Tri.Make( vPL, vPnt, vTria)) {
|
|
LOG_DBG_ERR( GetEGkLogger(), "ERROR : Triangulation failed in Bezier Surface") ;
|
|
return nullptr ;
|
|
}
|
|
|
|
POLYLINEVECTOR vPL3d = vvPL3d[c] ;
|
|
|
|
PNTVECTOR vPnt3d ;
|
|
for ( int i = 0 ; i < int( vPL3d.size()) ; ++i) {
|
|
PolyLine& pl3d = vPL3d[i] ;
|
|
Point3d pt3d ; pl3d.GetFirstPoint( pt3d) ;
|
|
if ( vPL3d.size() > 1)
|
|
vPnt3d.push_back( pt3d) ;
|
|
while ( pl3d.GetNextPoint( pt3d)) {
|
|
vPnt3d.push_back( pt3d) ;
|
|
}
|
|
}
|
|
|
|
// se ho ottenuto meno triangoli di quelli che avrei dovuto avere allora potrei aver avuto un problema in prossimità di un polo
|
|
// se comunque ho corrispondenza tra vPnt e vPnt3d allora eseguo la trinagolazione in 3d
|
|
int nTriaNumber = ( vPnt.size() - 2) + (2 * (vPL.size() - 1)) - (vPL.size() > 2 ? vPL.size() - 2 : 0) - (vPL.size() != 1 ? vPL.size() : 0) ;
|
|
bool bTriangulationFailedIn2D = nTriaNumber != ( vTria.size()) / 3 ;
|
|
//bool bMismatch2D3D = vPnt.size() != vPnt3d.size() ;
|
|
bool bTriangulatedIn3D = false ;
|
|
if ( bTriangulationFailedIn2D) {
|
|
PNTVECTOR vPntBackup = vPnt ;
|
|
INTVECTOR vTriaBackup = vTria ;
|
|
bool bTriangulationSucceded = true ;
|
|
if ( ! Tri.Make( vPL3d, vPnt, vTria))
|
|
bTriangulationSucceded = false ;
|
|
bTriangulationSucceded = bTriangulationSucceded && ( vPnt.size() - 2) + (2 * (vPL.size() - 1)) - (vPL.size() > 2 ? vPL.size() - 2 : 0) - (vPL.size() != 1 ? vPL.size() : 0) == ( vTria.size() ) / 3 ;
|
|
if ( bTriangulationFailedIn2D) {
|
|
if ( bTriangulationSucceded)
|
|
LOG_INFO( GetEGkLogger(), "Info : Last problem in MakeByEC23(1) RESOLVED")
|
|
else
|
|
LOG_INFO( GetEGkLogger(), "Info : This problem in MakeByEC23(1) is the same as the previous one")
|
|
}
|
|
if ( bTriangulationSucceded) {
|
|
bTriangulatedIn3D = true ;
|
|
// calcolo la normale della polyline per flippare eventualmente i triangoli se hanno la normale sbagliata
|
|
PolyLine& pl3d = vPL3d[0] ;
|
|
Plane3d plPlane ; double dArea = 0 ;
|
|
pl3d.IsClosedAndFlat( plPlane, dArea) ;
|
|
Vector3d vtN = plPlane.GetVersN() ;
|
|
Triangle3d tria ;
|
|
tria.Set( vPnt[vTria[0]], vPnt[vTria[1]], vPnt[vTria[2]]) ;
|
|
if ( tria.GetN() * vtN < 0)
|
|
reverse( vTria.begin(), vTria.end()) ;
|
|
}
|
|
else {
|
|
vPnt = vPntBackup ;
|
|
vTria = vTriaBackup ;
|
|
}
|
|
}
|
|
|
|
// riordino il vettore dei punti su cui non ho fatto la triangolazione
|
|
if ( vPL.size() == 2) {
|
|
//if ( vPnt.size() != vPnt3d.size())
|
|
// return nullptr ;
|
|
PNTVECTOR vPntOrd ;
|
|
if ( bTriangulatedIn3D) {
|
|
ReorderPntVector( vPL3d, true, vPnt, vPL, vPntOrd) ;
|
|
vPnt3d = vPnt ;
|
|
vPnt = vPntOrd ;
|
|
}
|
|
else {
|
|
ReorderPntVector( vPL, false, vPnt, vPL3d, vPntOrd) ;
|
|
vPnt3d = vPntOrd ;
|
|
}
|
|
}
|
|
else if ( bTriangulatedIn3D) {
|
|
if ( vPL.size() == 1) {
|
|
vPnt3d = vPnt ;
|
|
PNTVECTOR vPnt2d ;
|
|
for ( int i = 0 ; i < int( vPL.size()) ; ++i) {
|
|
PolyLine& pl = vPL[i] ;
|
|
Point3d pt ; pl.GetFirstPoint( pt) ;
|
|
//vPnt2D.push_back( pt) ;
|
|
while ( pl.GetNextPoint( pt)) {
|
|
vPnt2d.push_back( pt) ;
|
|
}
|
|
}
|
|
vPnt = vPnt2d ;
|
|
}
|
|
else {
|
|
PNTVECTOR vPntOrd ;
|
|
ReorderPntEnhancedVector( vPL3d, true, vPnt, vPL, vPntOrd) ;
|
|
vPnt3d = vPnt ;
|
|
vPnt = vPntOrd ;
|
|
}
|
|
}
|
|
|
|
// controllo che i due vettori vPnt e vPnt3d abbiano la stessa lunghezza, sennò vuol dire che nel vettore vPnt3d ho avuto dei Rejected e devo ricalcolarli
|
|
// i punti in eccesso verranno poi scartati dalla trimesh
|
|
if ( vPnt.size() != vPnt3d.size()) {
|
|
vPnt3d.clear() ;
|
|
for ( int i = 0 ; i < int( vPnt.size()) ; ++ i) {
|
|
Point3d pt3d ;
|
|
if ( ! GetPointD1D2( vPnt[i].x / SBZ_TREG_COEFF, vPnt[i].y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt3d))
|
|
return nullptr ;
|
|
vPnt3d.push_back( pt3d) ;
|
|
}
|
|
}
|
|
|
|
int nTria = int( vTria.size()) / 3 ;
|
|
for ( int i = 0 ; i < nTria ; ++i) {
|
|
if ( ! stmSoup.AddTriangle( vPnt3d[vTria[3*i]], vPnt3d[vTria[3*i+1]], vPnt3d[vTria[3*i+2]],
|
|
vPnt[vTria[3*i]].x, vPnt[vTria[3*i]].y,
|
|
vPnt[vTria[3*i+1]].x, vPnt[vTria[3*i+1]].y,
|
|
vPnt[vTria[3*i+2]].x, vPnt[vTria[3*i+2]].y))
|
|
return nullptr ;
|
|
}
|
|
++c ;
|
|
}
|
|
|
|
// termino
|
|
if ( ! stmSoup.End())
|
|
return nullptr ;
|
|
// restituisco
|
|
return GetBasicSurfTriMesh( stmSoup.GetSurf()) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::ReorderPntVector( const POLYLINEVECTOR& vPL, bool bTriangulatedIn3D, const PNTVECTOR& vPnt, const POLYLINEVECTOR& vPLToOrd, PNTVECTOR& vPntOrd) const
|
|
{
|
|
BOOLVECTOR vbPolyChecked( vPL.size()) ;
|
|
fill( vbPolyChecked.begin(), vbPolyChecked.end(), false) ;
|
|
for ( int p = 0 ; p < int(vPnt.size()) ; ++p) {
|
|
Point3d pt = vPnt[p] ;
|
|
int nInd = 0 ;
|
|
int nPoly = 0 ;
|
|
int nPoints = 0 ;
|
|
bool bInverted = false ;
|
|
for ( int poly = 0 ; poly < int( vPL.size()) ; ++poly ) {
|
|
if ( vbPolyChecked[poly])
|
|
continue ;
|
|
PolyLine pl = vPL[poly] ;
|
|
nInd = 0 ;
|
|
Point3d ptPoly ; pl.GetFirstPoint( ptPoly) ;
|
|
bool bFound = false ;
|
|
if ( AreSamePointExact( pt, ptPoly)){
|
|
nPoints = pl.GetPointNbr() ;
|
|
nPoly = poly ;
|
|
bFound = true ;
|
|
pl.GetNextPoint( ptPoly) ;
|
|
if ( ! AreSamePointExact( vPnt[p+1], ptPoly))
|
|
bInverted = true ;
|
|
break ;
|
|
}
|
|
while ( pl.GetNextPoint( ptPoly) && ! bFound) {
|
|
++ nInd ;
|
|
if ( AreSamePointExact( pt, ptPoly)) {
|
|
nPoints = pl.GetPointNbr() ;
|
|
nPoly = poly ;
|
|
bFound = true ;
|
|
pl.GetNextPoint( ptPoly) ;
|
|
if ( ! AreSamePointExact( vPnt[p+1], ptPoly))
|
|
bInverted = true ;
|
|
break ;
|
|
}
|
|
}
|
|
if ( bFound)
|
|
break ;
|
|
}
|
|
if ( nInd == 0) {
|
|
Point3d ptPoly ;
|
|
vPLToOrd[nPoly].GetFirstPoint( ptPoly) ;
|
|
vPntOrd.push_back( ptPoly) ;
|
|
while ( vPLToOrd[nPoly].GetNextPoint( ptPoly))
|
|
vPntOrd.push_back( ptPoly) ;
|
|
}
|
|
else if ( nInd == nPoints - 1 ) {
|
|
Point3d ptPoly ;
|
|
vPLToOrd[nPoly].GetLastPoint( ptPoly) ;
|
|
vPntOrd.push_back( ptPoly) ;
|
|
while ( vPLToOrd[nPoly].GetPrevPoint( ptPoly))
|
|
vPntOrd.push_back( ptPoly) ;
|
|
}
|
|
else {
|
|
PNTVECTOR vPntToRotate ;
|
|
Point3d ptPoly ;
|
|
if ( ! bInverted) {
|
|
vPLToOrd[nPoly].GetFirstPoint( ptPoly) ;
|
|
vPntToRotate.push_back( ptPoly) ;
|
|
while ( vPLToOrd[nPoly].GetNextPoint( ptPoly))
|
|
vPntToRotate.push_back( ptPoly) ;
|
|
}
|
|
else {
|
|
vPLToOrd[nPoly].GetLastPoint( ptPoly) ;
|
|
vPntToRotate.push_back( ptPoly) ;
|
|
while ( vPLToOrd[nPoly].GetPrevPoint( ptPoly))
|
|
vPntToRotate.push_back( ptPoly) ;
|
|
}
|
|
vPntToRotate.pop_back() ;
|
|
rotate( vPntToRotate.begin(), vPntToRotate.begin() + nInd, vPntToRotate.end()) ;
|
|
vPntToRotate.push_back( vPntToRotate[0]) ;
|
|
vPntOrd.insert( vPntOrd.end(), vPntToRotate.begin(), vPntToRotate.end()) ;
|
|
}
|
|
vbPolyChecked[nPoly] = true ;
|
|
p += nPoints - 1;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::ReorderPntEnhancedVector( const POLYLINEVECTOR& vPL, bool bTriangulatedIn3D, const PNTVECTOR& vPnt, const POLYLINEVECTOR& vPLToOrd, PNTVECTOR& vPntOrd) const
|
|
{
|
|
vPntOrd.clear() ;
|
|
// costruisco il vettore dei punti da ordinare
|
|
PNTVECTOR vPntPolyToOrd ;
|
|
for ( int i = 0 ; i < int( vPLToOrd.size()) ; ++i) {
|
|
Point3d pt ; vPLToOrd[i].GetFirstPoint( pt) ;
|
|
vPntPolyToOrd.push_back( pt) ;
|
|
while ( vPLToOrd[i].GetNextPoint( pt))
|
|
vPntPolyToOrd.push_back( pt) ;
|
|
}
|
|
// costruisco il vettore con i punti delle polyline in ordine
|
|
PNTVECTOR vPntPoly ;
|
|
for ( int i = 0 ; i < int( vPL.size()) ; ++i) {
|
|
Point3d pt ; vPL[i].GetFirstPoint( pt) ;
|
|
vPntPoly.push_back( pt) ;
|
|
while ( vPL[i].GetNextPoint( pt))
|
|
vPntPoly.push_back( pt) ;
|
|
}
|
|
BOOLVECTOR vbPntChecked( vPnt.size()) ;
|
|
fill( vbPntChecked.begin(), vbPntChecked.end(), false) ;
|
|
// confronto questo vettore con il vettore dei punti in ordine sparso
|
|
for ( int p = 0 ; p < int( vPntPoly.size()) ; ++p) {
|
|
Point3d pt = vPntPoly[p] ;
|
|
for ( int t = 0 ; t < int( vPnt.size()) ; ++t) {
|
|
if ( vbPntChecked[t])
|
|
continue ;
|
|
Point3d ptToCheck = vPnt[t] ;
|
|
if ( AreSamePointExact( pt, ptToCheck)) {
|
|
vbPntChecked[t] = true ;
|
|
vPntOrd.push_back( vPntPolyToOrd[p]) ;
|
|
}
|
|
}
|
|
}
|
|
// applico la stessa trasformazione al vettore dei punti delle polyline vPLToOrd
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::GetLeaves( vector<tuple<int, Point3d, Point3d>>& vLeaves) const
|
|
{
|
|
Tree Tree ;
|
|
if ( ! Tree.SetSurf( this))
|
|
return false ;
|
|
BIPNTVECTOR vTrees ;
|
|
Tree.GetIndependentTrees( vTrees) ;
|
|
for ( int i = 0 ; i < int( vTrees.size()) ; ++ i) {
|
|
Point3d ptMin = get<0>( vTrees[i]) ;
|
|
Point3d ptMax = get<1>( vTrees[i]) ;
|
|
Tree.SetSurf( this, ptMin, ptMax) ;
|
|
Tree.BuildTree( s_dAuxSurfTol, 100 * EPS_SMALL) ;
|
|
vector<Cell> vCells ;
|
|
Tree.GetLeaves( vCells) ;
|
|
for ( int k = 0 ; k < int( vCells.size()) ; ++ k) {
|
|
vLeaves.emplace_back( vCells[k].m_nId, vCells[k].GetBottomLeft(), vCells[k].GetTopRight()) ;
|
|
}
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::GetTriangles2D( vector<tuple<int,Point3d, Point3d, Point3d>>& vTria2D) const
|
|
{
|
|
const ISurfTriMesh* pSTM = GetAuxSurf() ;
|
|
for ( int t = 0 ; t < int(pSTM->GetTriangleCount()) ; ++t ) {
|
|
double dU0, dU1, dU2, dV0, dV1, dV2 ;
|
|
int nVert[3] ;
|
|
pSTM->GetTriangle( t, nVert);
|
|
pSTM->GetVertexParam( nVert[0], dU0, dV0) ;
|
|
pSTM->GetVertexParam( nVert[1], dU1, dV1) ;
|
|
pSTM->GetVertexParam( nVert[2], dU2, dV2) ;
|
|
Point3d pt0(dU0,dV0), pt1(dU1,dV1), pt2(dU2,dV2) ;
|
|
vTria2D.emplace_back( tuple<int,Point3d, Point3d, Point3d>(t, pt0, pt1, pt2)) ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
SurfBezier::ResetAuxSurf( void) const
|
|
{
|
|
if ( m_pSTM != nullptr)
|
|
delete( m_pSTM) ;
|
|
m_pSTM = nullptr ;
|
|
if ( m_pSTMRefined != nullptr)
|
|
delete( m_pSTMRefined) ;
|
|
m_pSTMRefined = nullptr ;
|
|
|
|
m_mCCEdge.clear() ;
|
|
m_vCCLoop.clear() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
SurfBezier::ResetTrimRegion( void)
|
|
{
|
|
if ( m_pTrimReg != nullptr)
|
|
delete( m_pTrimReg) ;
|
|
m_pTrimReg = nullptr ;
|
|
ResetAuxSurf() ;
|
|
m_bTrimmed = false ;
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
m_mCCEdge.clear() ;
|
|
m_vCCLoop.clear() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::IncreaseUV( Point3d& ptUV, Vector3d vtH , Point3d* ptUVCopy, bool bModifyOrig) const
|
|
{
|
|
if ( ptUVCopy != nullptr) {
|
|
IncreaseUV( ptUV.x, vtH.x, true, &(*ptUVCopy).x, bModifyOrig) ;
|
|
IncreaseUV( ptUV.y, vtH.y, true, &(*ptUVCopy).y, bModifyOrig) ;
|
|
}
|
|
else {
|
|
IncreaseUV( ptUV.x, vtH.x, true, nullptr, bModifyOrig) ;
|
|
IncreaseUV( ptUV.y, vtH.y, true, nullptr, bModifyOrig) ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::IncreaseUV( double& dUV, double dxy, bool bUOrV, double* dUVCopy, bool bModifyOrig) const
|
|
{
|
|
double dUVTest ;
|
|
if ( dUVCopy == nullptr && ! bModifyOrig)
|
|
return false ;
|
|
if ( dUVCopy != nullptr) {
|
|
*dUVCopy = dUV + dxy ;
|
|
dUVTest = *dUVCopy ;
|
|
}
|
|
if ( bModifyOrig) {
|
|
dUV += dxy ;
|
|
dUVTest = dUV ;
|
|
}
|
|
|
|
if ( bUOrV) {
|
|
if ( dUVTest < 0)
|
|
dUVTest = 0 ;
|
|
else if ( dUVTest > m_nSpanU )
|
|
dUVTest = m_nSpanU ;
|
|
}
|
|
else {
|
|
if ( dUVTest < 0)
|
|
dUVTest = 0 ;
|
|
else if ( dUVTest > m_nSpanV )
|
|
dUVTest = m_nSpanV ;
|
|
}
|
|
if ( bModifyOrig)
|
|
dUV = dUVTest ;
|
|
if ( dUVCopy != nullptr)
|
|
*dUVCopy = dUVTest ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::UnprojectCurveFromStm( const ICurveComposite* pCC, ICRVCOMPOPVECTOR& vpCC, const Plane3d* pPlCut) const
|
|
{
|
|
// calcolo la superficie se non già calcolata
|
|
if ( m_pSTMRefined == nullptr)
|
|
GetAuxSurfRefined() ;
|
|
|
|
// se necessario calcolo i poli
|
|
if ( m_vbPole.empty())
|
|
CalcPoles() ;
|
|
|
|
// do per scontato che la compo sia una spezzata, visto che arriva dall'intersezione tra un piano e una trimesh
|
|
// creo la chain dei punti che sto riportando nel parametrico
|
|
ChainCurves chainC ;
|
|
double dToler = EPS_SMALL ;
|
|
chainC.Init( false, dToler, 2) ;
|
|
|
|
const ICurve* pCrv0 = pCC->GetCurve( 0) ;
|
|
PolyLine pl ;
|
|
Point3d pt3D, pt2D ; pCrv0->GetStartPoint( pt3D) ;
|
|
Point3d pt3DEnd ; pCrv0->GetEndPoint( pt3DEnd) ;
|
|
bool bThroughEdge = false ;
|
|
BOOLVECTOR vbThroughEdge ;
|
|
if ( ! UnprojectPoint( pt3D, pt2D, pt3DEnd, &bThroughEdge, pPlCut))
|
|
return false ;
|
|
pt2D *= SBZ_TREG_COEFF ;
|
|
vbThroughEdge.push_back( bThroughEdge) ;
|
|
|
|
// aggiungo tutti i successivi
|
|
BIPNTVECTOR vBPnt ;
|
|
|
|
// per il primo punto non mi interessa sapere se è passato attraverso un edge, tanto ha già le coordinate parametriche giuste
|
|
bThroughEdge = false ;
|
|
int nRejected = 0 ;
|
|
for ( int i = 0 ; i < pCC->GetCurveCount() ; ++i) {
|
|
const ICurve* pCrv = pCC->GetCurve( i) ;
|
|
Point3d pt3DPrev = pt3D ;
|
|
Point3d pt2DPrev = pt2D ;
|
|
bool bPrevIsPole = false ;
|
|
bool bHorizontalPole = true ;
|
|
if ( bThroughEdge) {
|
|
// devo cambiare le coordinate di pt2DPrev per periodicità
|
|
// capisco su quale lato è e lo porto sul lato opposto
|
|
if ( m_bClosedU) {
|
|
if ( pt2DPrev.x < 1)
|
|
pt2DPrev.x = m_nSpanU * SBZ_TREG_COEFF ;
|
|
else if ( (m_nSpanU * SBZ_TREG_COEFF - pt2DPrev.x) < 1)
|
|
pt2DPrev.x = 0 ;
|
|
}
|
|
if ( m_bClosedV) {
|
|
if ( pt2DPrev.y < 1)
|
|
pt2DPrev.y = m_nSpanV * SBZ_TREG_COEFF ;
|
|
else if ( (m_nSpanV * SBZ_TREG_COEFF - pt2DPrev.y) < 1)
|
|
pt2DPrev.y = 0 ;
|
|
}
|
|
// verifico se il punto era in un polo
|
|
if ( ( m_vbPole[0] && m_nSpanV * SBZ_TREG_COEFF - pt2DPrev.y < 1 ) ||
|
|
( m_vbPole[2] && pt2DPrev.y < 1 ) ) {
|
|
bPrevIsPole = true ;
|
|
bHorizontalPole = true ;
|
|
}
|
|
if ( ( m_vbPole[1] && pt2DPrev.x < 1 ) ||
|
|
( m_vbPole[3] && m_nSpanU * SBZ_TREG_COEFF - pt2DPrev.x < 1 ) ) {
|
|
bPrevIsPole = true ;
|
|
bHorizontalPole = false ;
|
|
}
|
|
}
|
|
pCrv->GetEndPoint( pt3D) ;
|
|
if ( ! UnprojectPoint( pt3D, pt2D, pt3DPrev, &bThroughEdge, pPlCut))
|
|
return false ;
|
|
pt2D *= SBZ_TREG_COEFF ;
|
|
|
|
// se il precedente era passato attraverso l'edge ed era un edge di polo allora devo sistemare le coordinate
|
|
if ( bPrevIsPole) {
|
|
// se il punto precedente era di polo allora devo correggere le sue coordinate 2D
|
|
if ( bHorizontalPole)
|
|
pt2DPrev.x = pt2D.x ;
|
|
else if ( ! bHorizontalPole)
|
|
pt2DPrev.y = pt2D.y ;
|
|
}
|
|
Vector3d vtDir = pt2D - pt2DPrev ;
|
|
vtDir.Normalize() ;
|
|
// se mi accorgo che sto per tracciare un taglio lungo un bordo posso semplicemente evitarlo
|
|
double dDelta = 10 * EPS_SMALL ;
|
|
if ( ( 1 - abs( vtDir.x) < SQ_EPS_SMALL && ( pt2D.y < dDelta || m_nSpanV * SBZ_TREG_COEFF - pt2D.y < dDelta)) || // parallelo agli edge 0 e 2 e su uno di questi
|
|
( 1 - abs( vtDir.y) < SQ_EPS_SMALL && ( pt2D.x < dDelta || m_nSpanU * SBZ_TREG_COEFF - pt2D.x < dDelta))) { // parallello agli edge 1 e 3 e su uno di questi
|
|
++ nRejected ;
|
|
continue ;
|
|
}
|
|
double dParamH, dParamL ;
|
|
dParamH = m_nSpanV * SBZ_TREG_COEFF ;
|
|
dParamL = m_nSpanU * SBZ_TREG_COEFF ;
|
|
if ( bThroughEdge && vbThroughEdge.back()) {
|
|
// sia questo punto che il precedente sono su un edge, ma il segmento che li unisce non è parallelo ad un edge
|
|
// ( i punti per periodicità hanno coordinate diverse anche se dovrebbero averle uguali, quindi il segmento attraversa tutto lo spazio parametrico, anche se in realtà è lungo il bordo di chiusura)
|
|
// potrei star tracciando un taglio sul bordo di chiusura
|
|
// controllo se sto tracciando una linea che unisce due lati di chiusura, allora in realtà sdtarei tracciando un taglio sull'edge e quindi posso non tracciarlo
|
|
if ( ( abs( vtDir.x) > abs( vtDir.y) && Dist( pt2D, pt2DPrev) > dParamL * 0.5) ||
|
|
( abs( vtDir.y) > abs( vtDir.x) && Dist( pt2D, pt2DPrev) > dParamH * 0.5)) {
|
|
++ nRejected ;
|
|
continue ;
|
|
}
|
|
}
|
|
// se il primo e l'ultimo punto sono entrambi su edge e indicano un attraversamento, controllo che siano da lati opposti del parametrico
|
|
// altrimenti li porto dal lato del punto successivo/precedente
|
|
if ( bThroughEdge && pCC->IsClosed() && i == pCC->GetCurveCount() - 1 && vbThroughEdge[0] && ( m_bClosedU || m_bClosedV)) {
|
|
if ( m_bClosedU) {
|
|
if ( abs( vBPnt[0].first.x - vBPnt[0].second.x) > 0.5 * dParamL){
|
|
if (dParamL - vBPnt[0].second.x < 0.5 * dParamL)
|
|
vBPnt[0].first.x = dParamL ;
|
|
else
|
|
vBPnt[0].first.x = 0 ;
|
|
}
|
|
if ( abs( pt2D.x - pt2DPrev.x) > 0.5 * dParamL){
|
|
if ( dParamL - pt2DPrev.x < 0.5 * dParamL)
|
|
pt2D.x = dParamL ;
|
|
else
|
|
pt2D.x = 0 ;
|
|
}
|
|
}
|
|
if ( m_bClosedV) {
|
|
if ( abs( vBPnt[0].first.y - vBPnt[0].second.y) > 0.5 * dParamH){
|
|
if (dParamH - vBPnt[0].second.y < 0.5 * dParamH)
|
|
vBPnt[0].first.y = dParamH ;
|
|
else
|
|
vBPnt[0].first.y = 0 ;
|
|
}
|
|
if ( abs( pt2D.y - pt2DPrev.y) > 0.5 * dParamH){
|
|
if ( dParamH - pt2DPrev.y < 0.5 * dParamH)
|
|
pt2D.y = dParamH ;
|
|
else
|
|
pt2D.y = 0 ;
|
|
}
|
|
}
|
|
}
|
|
vbThroughEdge.push_back( bThroughEdge) ;
|
|
vBPnt.emplace_back( BIPOINT( pt2DPrev, pt2D)) ;
|
|
if ( ! chainC.AddCurve( i + 1 - nRejected, pt2DPrev, vtDir, pt2D, vtDir))
|
|
return false ;
|
|
}
|
|
// ricostruisco le catene in 2D
|
|
Point3d ptNear ; pCrv0->GetStartPoint( ptNear) ;
|
|
INTVECTOR vId ;
|
|
bool bAdded = true ;
|
|
while ( chainC.GetChainFromNear( pt3D, false, vId)) {
|
|
PtrOwner<ICurveComposite> pCC2D ( CreateCurveComposite()) ;
|
|
if ( IsNull( pCC2D))
|
|
return false ;
|
|
for ( int i = 0 ; i < int( vId.size()) ; ++ i) {
|
|
// creo un segmento di retta
|
|
PtrOwner<ICurveLine> pLine( CreateCurveLine()) ;
|
|
if ( IsNull( pLine))
|
|
return false ;
|
|
// recupero gli estremi (non vanno mai invertiti per opzione di concatenamento)
|
|
int nInd = abs( vId[i]) - 1 ;
|
|
Point3d ptStart = ( bAdded ? vBPnt[nInd].first : ptNear) ;
|
|
Point3d ptEnd = vBPnt[nInd].second ;
|
|
// provo ad accodarlo alla composita
|
|
bAdded = ( Dist( ptStart, ptEnd) > dToler / 2 &&
|
|
pLine->Set( ptStart, ptEnd)) ;
|
|
bAdded = bAdded && pCC2D->AddCurve( Release( pLine), true, dToler) ;
|
|
ptNear = ( bAdded ? ptEnd : ptStart) ;
|
|
}
|
|
if ( pCC2D->IsValid())
|
|
vpCC.emplace_back( Release( pCC2D)) ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::AddCurveCompoToCuts( ICurveComposite* pCrvCompo, ICRVCOMPOPOVECTOR& vpCCOpen, ICRVCOMPOPOVECTOR& vpCCClosed, double dToler, const Plane3d* pPlCut) const
|
|
{
|
|
// se lunghezza curva inferiore a 5 volte la tolleranza, la ignoro e sposto il punto finale nel punto di fine della curva che sto ignorando
|
|
double dCrvLen ;
|
|
if ( ! pCrvCompo->GetLength( dCrvLen) || dCrvLen < 5. * dToler)
|
|
return true ;
|
|
// se curva chiusa entro 5 volte la tolleranza ma considerata aperta, la chiudo bene
|
|
Point3d ptStart, ptEnd ;
|
|
if ( pCrvCompo->GetStartPoint( ptStart) &&
|
|
pCrvCompo->GetEndPoint( ptEnd) &&
|
|
AreSamePointEpsilon( ptStart, ptEnd, 5 * dToler) &&
|
|
! AreSamePointApprox( ptStart, ptEnd)) {
|
|
// porto il punto finale a coincidere esattamente con l'inizio
|
|
pCrvCompo->ModifyEnd( ptStart) ;
|
|
}
|
|
// unisco segmenti allineati
|
|
pCrvCompo->MergeCurves( 0.5 * dToler, ANG_TOL_STD_DEG) ;
|
|
|
|
// porto la curva nello spazio parametrico
|
|
ICRVCOMPOPVECTOR vCC ;
|
|
if ( ! UnprojectCurveFromStm( pCrvCompo, vCC, pPlCut))
|
|
return false ;
|
|
for ( int i = 0 ; i < int( vCC.size()); ++i) {
|
|
// le curve aperte le tengo da parte per giuntarle alla fine col bordo
|
|
if ( ! vCC[i]->IsClosed() )
|
|
vpCCOpen.emplace_back( vCC[i]) ;
|
|
// le curve chiuse le metto tutte insieme subito
|
|
else
|
|
vpCCClosed.emplace_back( vCC[i]) ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
typedef tuple<int,int,int> TRINT ;
|
|
|
|
template<>
|
|
struct hash<TRINT> {
|
|
size_t operator()(const TRINT& t) const
|
|
{
|
|
// Compute individual hash values for first, second and third and combine them using XOR and bit shifting:
|
|
return ((hash<int>()(get<0>(t))) ^ (hash<int>()(get<1>(t)) << 1) >> 1) ^ (hash<int>()(get<2>(t)) << 1) ;
|
|
}
|
|
} ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
ISurfFlatRegion*
|
|
SurfBezier::CreateTrimRegionFromCuts( ICRVCOMPOPOVECTOR& vpCCOpen, ICRVCOMPOPOVECTOR& vpCCClosed) const
|
|
{
|
|
// comincio a creare la superficie aggiungendo i tagli aperti ai bordi attualmente esistenti
|
|
SurfFlatRegionByContours sfrContour ;
|
|
if ( int(vpCCOpen.size()) != 0 ) {
|
|
// recupero la regione attuale
|
|
PtrOwner<ISurfFlatRegion> pNewTrim( CreateBasicSurfFlatRegion()) ;
|
|
if ( m_bTrimmed)
|
|
pNewTrim.Set( GetTrimRegion()->Clone()) ;
|
|
else
|
|
pNewTrim.Set( GetSurfFlatRegionRectangle( SBZ_TREG_COEFF * m_nSpanU, SBZ_TREG_COEFF * m_nSpanV)) ;
|
|
|
|
// costruisco la mappa delle intersezioni, trovando tutte le intersezioni tra i trim e i loop dei vari chunk della flat region
|
|
unordered_map<TRINT,ICCIVECTOR> mInters ;
|
|
int nInters = 0 ;
|
|
bool bStartFound = false ;
|
|
bool bEndFound = false ;
|
|
// trim
|
|
for ( int t = 0 ; t < int( vpCCOpen.size()); ++t) {
|
|
nInters = 0 ;
|
|
bStartFound = false ;
|
|
bEndFound = false ;
|
|
// chunk
|
|
for ( int c = 0 ; c < pNewTrim->GetChunkCount() ; ++c) {
|
|
// loop
|
|
for ( int l = 0 ; l < pNewTrim->GetLoopCount( c) ; ++l) {
|
|
PtrOwner<ICurve> pLoop( pNewTrim->GetLoop( c, l)) ;
|
|
// prima curva è il loop, seconda curva è il trim
|
|
IntersCurveCurve icc( *pLoop, *vpCCOpen[t]) ;
|
|
if ( icc.GetIntersCount() != 0) {
|
|
ICCIVECTOR vICC ;
|
|
for ( int i = 0 ; i < int( icc.GetIntersCount()); ++i) {
|
|
IntCrvCrvInfo iccInfo ;
|
|
icc.GetIntCrvCrvInfo( i, iccInfo) ;
|
|
vICC.emplace_back( iccInfo) ;
|
|
}
|
|
mInters.insert( pair<TRINT,ICCIVECTOR>( TRINT(c,l,t), vICC)) ;
|
|
if ( int( vICC.size() == 2)) {
|
|
bStartFound = true ;
|
|
bEndFound = true ;
|
|
}
|
|
else if ( int(vICC.size() == 1) ) {
|
|
if ( vICC[0].IciB->dU < EPS_SMALL)
|
|
bStartFound = true ;
|
|
else
|
|
bEndFound = true ;
|
|
}
|
|
}
|
|
nInters += int( icc.GetIntersCount()) ;
|
|
}
|
|
}
|
|
if ( nInters != 2) {
|
|
// se un trim non fa 2 intersezioni allora devo estendere la curva allo start e/o all'end per creare le intersezioni
|
|
Point3d ptStart ; vpCCOpen[t]->GetStartPoint( ptStart) ;
|
|
Point3d ptEnd ; vpCCOpen[t]->GetEndPoint( ptEnd) ;
|
|
PtrOwner<ICurve> pCrv( vpCCOpen[t]->Clone()) ;
|
|
double dExtension = m_nSpanU > m_nSpanV ? m_nSpanU : m_nSpanV ;
|
|
dExtension *= SBZ_TREG_COEFF ;
|
|
if ( ! bStartFound)
|
|
pCrv->ExtendStartByLen( dExtension) ;
|
|
if ( ! bEndFound)
|
|
pCrv->ExtendEndByLen( dExtension) ;
|
|
double dDistStart = 1e6, dDistEnd = 1e6 ;
|
|
// vettore per l'intersezione di start
|
|
ICCIVECTOR vICCStart ;
|
|
vICCStart.emplace_back() ;
|
|
// vettore per l'intersezione di end
|
|
ICCIVECTOR vICCEnd ;
|
|
vICCEnd.emplace_back() ;
|
|
TRINT tStart, tEnd ;
|
|
// chunk
|
|
for ( int c = 0 ; c < pNewTrim->GetChunkCount() ; ++c) {
|
|
// loop
|
|
for ( int l = 0 ; l < pNewTrim->GetLoopCount( c) ; ++l) {
|
|
PtrOwner<ICurve> pLoop( pNewTrim->GetLoop( c, l)) ;
|
|
// prima curva è il loop, seconda curva è il trim
|
|
IntersCurveCurve icc( *pLoop, *pCrv) ;
|
|
if ( icc.GetIntersCount() != 0) {
|
|
for ( int i = 0 ; i < int( icc.GetIntersCount()); ++i) {
|
|
IntCrvCrvInfo iccInfo ; icc.GetIntCrvCrvInfo( i, iccInfo) ;
|
|
if ( ! bStartFound && Dist( iccInfo.IciA->ptI, ptStart) < dDistStart) {
|
|
dDistStart = Dist( iccInfo.IciA->ptI, ptStart) ;
|
|
vICCStart[0] = iccInfo ;
|
|
tStart = TRINT( c, l, t) ;
|
|
}
|
|
if ( ! bEndFound && Dist( iccInfo.IciA->ptI, ptEnd) < dDistEnd) {
|
|
dDistEnd = Dist( iccInfo.IciA->ptI, ptEnd) ;
|
|
vICCEnd[0] = iccInfo ;
|
|
tEnd = TRINT( c, l, t) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ricostruisco gli elementi per la mappa mInters
|
|
if ( ! bStartFound && ! bEndFound) {
|
|
// ridefinisco il taglio aperto con la sua versione estesa che arriva a toccare i loop dello spazio parametrico
|
|
vpCCOpen[t].Set( GetCurveComposite(pCrv->CopyParamRange( vICCStart[0].IciB->dU, vICCEnd[0].IciB->dU))) ;
|
|
// correggo il parametro dell'intersezione allo start
|
|
vICCStart[0].IciB->dU = 0 ;
|
|
if ( tStart == tEnd) {
|
|
// se ho intersezione con un loop solo allora accorpo i due vettori delle intersezioni
|
|
vICCStart.emplace_back( vICCEnd[0]) ;
|
|
mInters.insert( pair<TRINT,ICCIVECTOR>(tStart, vICCStart)) ;
|
|
}
|
|
else{
|
|
// se ho intersezione con due loop diverse due entry diverse le inserisco
|
|
mInters.insert( pair<TRINT,ICCIVECTOR>(tStart, vICCStart)) ;
|
|
mInters.insert( pair<TRINT,ICCIVECTOR>(tEnd, vICCEnd)) ;
|
|
}
|
|
}
|
|
else {
|
|
// devo verificare se avevo già trovato una delle due intersezioni e se era sullo stesso loop o no
|
|
if ( ! bStartFound) {
|
|
pCrv->TrimStartAtParam( vICCStart[0].IciB->dU) ;
|
|
vpCCOpen[t].Set( GetCurveComposite( Release( pCrv))) ;
|
|
// correggo il parametro dell'intersezione allo start
|
|
vICCStart[0].IciB->dU = 0 ;
|
|
if ( mInters.count( tStart) == 1)
|
|
mInters[tStart].emplace_back( vICCStart[0]) ;
|
|
else
|
|
mInters.insert( pair<TRINT,ICCIVECTOR>( tStart, vICCStart)) ;
|
|
}
|
|
if ( ! bEndFound) {
|
|
if ( mInters.count( tEnd) == 1)
|
|
mInters[tEnd].emplace_back( vICCEnd[0]) ;
|
|
else
|
|
mInters.insert( pair<TRINT,ICCIVECTOR>( tEnd, vICCEnd)) ;
|
|
pCrv->TrimEndAtParam( vICCEnd[0].IciB->dU) ;
|
|
vpCCOpen[t].Set( GetCurveComposite( Release( pCrv))) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// vettore di flag che mi indica quali tagli aperti sono stati aggiunti al nuovo bordo
|
|
BOOLVECTOR vbAdded( vpCCOpen.size()) ;
|
|
fill( vbAdded.begin(), vbAdded.end(), false) ;
|
|
PtrOwner<ICurveComposite> pCCNewEdge( CreateCurveComposite()) ;
|
|
PtrOwner<ICurveLine> pCL( CreateCurveLine()) ;
|
|
TRINT tiFirstInters ;
|
|
// parto aggiungendo il primo taglio
|
|
int nNewToAdd = 0 ;
|
|
bool bFirstCurveOfEdge = true ;
|
|
while ( nNewToAdd != -1) {
|
|
// aggiungo il taglio
|
|
pCCNewEdge->AddCurve( Release( vpCCOpen[nNewToAdd])) ;
|
|
// aggiorno la lista degli aggiunti
|
|
vbAdded[nNewToAdd] = true ;
|
|
// di questo taglio mi salvo il chunk e loop di start e end
|
|
TRINT tiStart, tiEnd ;
|
|
bool bStartFound = false ;
|
|
bool bEndFound = false ;
|
|
for (const auto& pair : mInters) {
|
|
if ( get<2>(pair.first) == nNewToAdd ) {
|
|
for (int p = 0 ; p < int(pair.second.size()) ; ++p) {
|
|
if ( pair.second[p].IciB->dU < EPS_SMALL) {
|
|
tiStart = pair.first ;
|
|
bStartFound = true ;
|
|
if ( bFirstCurveOfEdge){
|
|
// salvo l'inizio del taglio che è la prima curva di questa curva compo
|
|
tiFirstInters = pair.first ;
|
|
bFirstCurveOfEdge = false ;
|
|
}
|
|
}
|
|
else {
|
|
tiEnd = pair.first ;
|
|
bEndFound = true ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ( ! bEndFound || ! bStartFound)
|
|
return nullptr ;
|
|
// devo trovare fino a che punto seguire il loop che ho trovato come prosecuzione del taglio corrente
|
|
// devo quindi trovare la prossima intersezione con un taglio
|
|
int nInters = -1 ;
|
|
double dNextCut = INFINITO ;
|
|
double dEndCurrentCut = 0 ;
|
|
for ( int i = 0 ; i < int( mInters[tiEnd].size()); ++i) {
|
|
// se ho trovato l'intersezione con la fine del taglio corrente, salvo il parametro sul loop
|
|
if ( mInters[tiEnd][i].IciB->dU > EPS_SMALL)
|
|
dEndCurrentCut = mInters[tiEnd][i].IciA->dU ;
|
|
}
|
|
// se non trovo nessuna altra intersezione prima della fine del loop allora devo ripetere tutto cercando a partire dall'inizio del loop
|
|
for ( const auto& pair : mInters) {
|
|
if ( get<0>(pair.first) == get<0>(tiEnd) && get<1>(pair.first) == get<1>(tiEnd)) {
|
|
for ( int i = 0 ; i < int(pair.second.size()); ++i ) {
|
|
// se trovo una nuova intersezione che incontro prima di quella che mi ero salvato precedentemente allora
|
|
// mi salvo questa nuova che ho trovato
|
|
if ( pair.second[i].IciA->dU < dNextCut && pair.second[i].IciA->dU > dEndCurrentCut) {
|
|
dNextCut = pair.second[i].IciA->dU ;
|
|
nInters = get<2>(pair.first) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ( nInters == -1) {
|
|
dNextCut = INFINITO ;
|
|
for ( const auto& pair : mInters) {
|
|
if ( get<0>(pair.first) == get<0>(tiEnd) && get<1>(pair.first) == get<1>(tiEnd)) {
|
|
for ( int i = 0 ; i < int(pair.second.size()); ++i ) {
|
|
// se trovo una nuova intersezione che incontro prima di quella che mi ero salvato precedentemente allora
|
|
// mi salvo questa nuova che ho trovato
|
|
if ( pair.second[i].IciA->dU < dNextCut) {
|
|
dNextCut = pair.second[i].IciA->dU ;
|
|
nInters = get<2>(pair.first) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// se tutto va bene queste due righe sostituiscono tutto il casino qua sotto
|
|
PtrOwner<ICurve> pLoopTrimmed( pNewTrim->GetLoop( get<0>(tiEnd), get<1>(tiEnd))) ;
|
|
pCCNewEdge->AddCurve(pLoopTrimmed->CopyParamRange( dEndCurrentCut, dNextCut)) ;
|
|
|
|
// se il prossimo taglio identificato è quello da cui sono partito allora aggiungo il bordo ricostruito fino a questo momento
|
|
// alla flat region e comincio a costruire un altro bordo
|
|
// altrimenti continuo ad aggiungere curve al bordo corrente
|
|
if ( nInters == get<2>(tiFirstInters) ) {
|
|
pCCNewEdge->Close() ;
|
|
sfrContour.AddCurve( Release( pCCNewEdge)) ;
|
|
pCCNewEdge.Set( CreateBasicCurveComposite()) ;
|
|
bFirstCurveOfEdge = true ;
|
|
// trovo il prossimo taglio ancora da aggiungere
|
|
nNewToAdd = -1 ;
|
|
for ( int b = 0 ; b < int(vbAdded.size()) ; ++b ) {
|
|
if ( ! vbAdded[b]) {
|
|
nNewToAdd = b ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
nNewToAdd = nInters;
|
|
}
|
|
}
|
|
|
|
// devo verificare se devo aggiungere anche il bordo ( basta verificare se il primo loop chiuso è CCW)
|
|
double dArea ;
|
|
if ( ! vpCCClosed.empty()) {
|
|
vpCCClosed[0]->GetAreaXY( dArea) ;
|
|
if ( dArea < EPS_SMALL ) {
|
|
PolyLine plEdge ;
|
|
plEdge.AddUPoint( 0, ORIG) ;
|
|
plEdge.AddUPoint( 1, Point3d( m_nSpanU * SBZ_TREG_COEFF, 0)) ;
|
|
plEdge.AddUPoint( 2, Point3d( m_nSpanU * SBZ_TREG_COEFF, m_nSpanV * SBZ_TREG_COEFF)) ;
|
|
plEdge.AddUPoint( 3, Point3d( 0, m_nSpanV * SBZ_TREG_COEFF)) ;
|
|
plEdge.Close() ;
|
|
vpCCClosed.emplace_back( CreateCurveComposite()) ;
|
|
vpCCClosed.back()->FromPolyLine( plEdge) ;
|
|
}
|
|
}
|
|
|
|
// aggiungo i loop chiusi
|
|
for ( int i = 0 ; i < int( vpCCClosed.size()); ++i )
|
|
sfrContour.AddCurve( Release( vpCCClosed[i])) ;
|
|
|
|
PtrOwner<ISurfFlatRegion> pSfrTrimReg( sfrContour.GetSurf()) ;
|
|
return Release( pSfrTrimReg) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::Cut( const Plane3d& plPlane, bool bSaveOnEq)
|
|
{
|
|
// faccio l'intersezione della trimesh ausiliaria con il piano posso ottenere: punti, curve 3d e triangoli( coplanari al piano di taglio)
|
|
// i punti li escludo
|
|
// le curve 3d le trasformo in curve 2d e le aggiungo alle curve di trim
|
|
// accorpo eventuali triangoli adiacenti ed estraggo i loop delle regioni ottenute; questi vengono poi portati in 2d e aggiunti alle curve di trim
|
|
|
|
// N.B. : questa funzione non prevede poli interni alla superficie, ma solo lati che sono collassati in poli!!!!
|
|
|
|
// se necessario calcolo i poli
|
|
if ( m_vbPole.empty())
|
|
CalcPoles() ;
|
|
|
|
PNTVECTOR vPnt ;
|
|
BIPNTVECTOR vBPnt ;
|
|
TRIA3DVECTOR vTria ;
|
|
IntersPlaneSurfTm( plPlane, *GetAuxSurfRefined(), vPnt, vBPnt, vTria) ;
|
|
|
|
// concateno le curve 3d
|
|
ChainCurves chainC ;
|
|
double dToler = 10 * EPS_SMALL ;
|
|
chainC.Init( false, dToler, int( vBPnt.size())) ;
|
|
for ( int i = 0 ; i < int( vBPnt.size()) ; ++ i) {
|
|
Vector3d vtDir = vBPnt[i].second - vBPnt[i].first ;
|
|
vtDir.Normalize() ;
|
|
if ( ! chainC.AddCurve( i + 1, vBPnt[i].first, vtDir, vBPnt[i].second, vtDir))
|
|
return false ;
|
|
}
|
|
// GESTIONE DELLE CURVE OTTENUTE DALL'INTERSEZIONE
|
|
|
|
// recupero i percorsi concatenati
|
|
Point3d ptNear = ( vBPnt.empty() ? ORIG : vBPnt[0].first) ;
|
|
INTVECTOR vId ;
|
|
|
|
// separo tra loop chiusi, interni allo spazio parametrico e loop passanti che tagliano lo spazio intersecando i bordi
|
|
ICRVCOMPOPOVECTOR vpCCOpen ;
|
|
ICRVCOMPOPOVECTOR vpCCClosed ;
|
|
|
|
while ( chainC.GetChainFromNear( ptNear, false, vId)) {
|
|
// creo una curva composita
|
|
PtrOwner<ICurveComposite> pCrvCompo( CreateCurveComposite()) ;
|
|
if ( IsNull( pCrvCompo))
|
|
return false ;
|
|
// recupero gli estremi dei segmenti, creo le linee e le inserisco nella composita
|
|
bool bAdded = true ;
|
|
for ( int i = 0 ; i < int( vId.size()) ; ++ i) {
|
|
// creo un segmento di retta
|
|
ICurveLine* pLine( CreateCurveLine()) ;
|
|
if ( pLine == nullptr)
|
|
return false ;
|
|
// recupero gli estremi (non vanno mai invertiti per opzione di concatenamento)
|
|
int nInd = abs( vId[i]) - 1 ;
|
|
Point3d ptStart = ( bAdded ? vBPnt[nInd].first : ptNear) ;
|
|
Point3d ptEnd = vBPnt[nInd].second ;
|
|
// provo ad accodarlo alla composita
|
|
bAdded = ( Dist( ptStart, ptEnd) > dToler / 2 &&
|
|
pLine->Set( ptStart, ptEnd)) ;
|
|
bAdded = bAdded && pCrvCompo->AddCurve( pLine, true, dToler) ;
|
|
ptNear = ( bAdded ? ptEnd : ptStart) ;
|
|
}
|
|
if ( ! AddCurveCompoToCuts( pCrvCompo, vpCCOpen, vpCCClosed, EPS_SMALL, &plPlane))
|
|
return false ;
|
|
}
|
|
|
|
//GESTIONE DEI TRIANGOLI RISULTANTI DALL'INTERSEZIONE
|
|
StmFromTriangleSoup StmFts ;
|
|
if ( ! StmFts.Start())
|
|
return GDB_ID_NULL ;
|
|
for ( int i = 0 ; i < int( vTria.size()) ; ++ i)
|
|
// inserisco il triangolo nella nuova superficie
|
|
StmFts.AddTriangle( vTria[i]) ;
|
|
// valido la superficie e calcolo le adiacenze
|
|
if ( ! StmFts.End())
|
|
return GDB_ID_NULL ;
|
|
// se superficie con triangoli
|
|
PtrOwner<ISurfTriMesh> pNewStm( StmFts.GetSurf()) ;
|
|
POLYLINEVECTOR vPLTria ;
|
|
if ( ! IsNull( pNewStm) && pNewStm->GetTriangleCount() > 0) {
|
|
pNewStm->GetLoops( vPLTria) ;
|
|
}
|
|
|
|
// aggiungo loop derivati dai triangoli
|
|
for ( int i = 0 ; i < int( vPLTria.size()); ++i ) {
|
|
vpCCClosed.emplace_back() ;
|
|
vpCCClosed.back()->FromPolyLine( vPLTria[i]) ;
|
|
}
|
|
|
|
// ora posso chiamare la costruzione dello spazio parametrico trimmato
|
|
PtrOwner<ISurfFlatRegion> pSFR( CreateTrimRegionFromCuts( vpCCOpen, vpCCClosed)) ;
|
|
if ( IsNull( pSFR) || ! pSFR->IsValid())
|
|
return false ;
|
|
|
|
// se la superficie ha normale con z negativa la inverto
|
|
if ( pSFR->GetNormVersor().z < 0)
|
|
pSFR->Invert() ;
|
|
|
|
// verifico se la superficie che ho ottenuto è corretta o devo prendere il complementare ( rispetto allo spazio parametrico totale)
|
|
// per verificarlo prendo un punto su questa superficie e verifico dove sta il suo corrispettivo 3D rispetto al piano di taglio
|
|
int nChunkMin = 0 , nLoopMin = 0 ;
|
|
// sono nello spazio parametrico, quindi le aree delle curve possono essere molto grandi
|
|
double dAreaMin = 1e30 ;
|
|
bool bPos = false ;
|
|
for ( int c = 0 ; c < int( pSFR->GetChunkCount()); ++c) {
|
|
for ( int l = 0 ; l < pSFR->GetLoopCount( c); ++l) {
|
|
PtrOwner<ICurve> pCrv( pSFR->GetLoop( c, l)) ;
|
|
double dArea ; pCrv->GetAreaXY( dArea) ;
|
|
if ( abs( dArea) < dAreaMin) {
|
|
nChunkMin = c ;
|
|
nLoopMin = l ;
|
|
dAreaMin = abs( dArea) ;
|
|
bPos = dArea > 0 ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// aggiorno la superficie di trim
|
|
Point3d ptStart ;
|
|
Vector3d vtDir, vtDirS, vtDirE ;
|
|
PtrOwner<ICurve> pCrv( pSFR->GetLoop( nChunkMin, nLoopMin)) ;
|
|
pCrv->GetStartPoint( ptStart) ;
|
|
pCrv->GetStartDir( vtDirS) ;
|
|
pCrv->GetEndDir( vtDirE) ;
|
|
vtDir = vtDirS + vtDirE ;
|
|
PtrOwner<ICurveLine> pCL( CreateCurveLine()) ;
|
|
pCL->SetPVL( ptStart, vtDir, 1e6) ;
|
|
IntersCurveCurve icc( *pCL, *pCrv) ;
|
|
IntCrvCrvInfo iccInfo ;
|
|
// verifico di guardare verso l'interno ( il numero di intersezioni deve essere pari visto che partivo da un punto sulla curva)
|
|
if ( icc.GetIntersCount()%2 != 0) {
|
|
vtDir = vtDirS - vtDirE ;
|
|
PtrOwner<ICurveLine> pCL2( CreateCurveLine()) ; pCL2->SetPVL( ptStart, vtDir, 1e6) ;
|
|
IntersCurveCurve icc2( *pCL2, *pCrv) ;
|
|
if ( icc2.GetIntersCount()%2 != 0) {
|
|
vtDir = vtDirS ;
|
|
vtDir.Rotate( Z_AX, bPos? 90 : -90) ;
|
|
PtrOwner<ICurveLine> pCL3( CreateCurveLine()) ; pCL3->SetPVL( ptStart, vtDir, 1e6) ;
|
|
IntersCurveCurve icc3( *pCL3, *pCrv) ;
|
|
if ( icc3.GetIntersCount()%2 != 0)
|
|
return false ;
|
|
icc3.GetIntCrvCrvInfo( 1, iccInfo) ;
|
|
}
|
|
else
|
|
icc2.GetIntCrvCrvInfo( 1, iccInfo) ;
|
|
}
|
|
else
|
|
icc.GetIntCrvCrvInfo( 1, iccInfo) ;
|
|
|
|
Point3d ptI = iccInfo.IciA[0].ptI ;
|
|
Point3d ptToCheck = ( ptStart + ptI) / 2 ;
|
|
Point3d pt3D ; GetPointD1D2( ptToCheck.x / SBZ_TREG_COEFF, ptToCheck.y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt3D) ;
|
|
double dDist = DistPointPlane( pt3D, plPlane) ;
|
|
|
|
// ho due casi in cui devo invertire(prendere il complementare rispetto allo spazio parametrico) la superficie:
|
|
// 1. se il punto è sopra il piano ed era dentro una curva CCW
|
|
// 2. se il punto è sotto il piano ed era interno ad una curva CW
|
|
|
|
// la SetTrimRegion controlla se avevo trim precedenti ed eventualmente fa l'intersezione con lo spazio esistente
|
|
if ( ( dDist > 0 && bPos) || ( dDist < 0 && ! bPos)) {
|
|
if ( ! SetTrimRegion( *pSFR, false) || ! m_pTrimReg->IsValid())
|
|
return false ;
|
|
}
|
|
else {
|
|
if ( ! SetTrimRegion( *pSFR) || ! m_pTrimReg->IsValid())
|
|
return false ;
|
|
}
|
|
|
|
//// taglio la trimesh col piano // questa operazione richiederebbe di ricavare anche i nuovi edge 2D e edge3D, che normalmente sarebbero calcolati durante la GetAuxSurf dal tree
|
|
//m_pSTM->Cut( plPlane, bSaveOnEq) ;
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::UnprojectPointFromStm( int nT, const Point3d& ptI, Point3d& ptSP, int nIL) const
|
|
{
|
|
return UnprojectPointFromStm( nT, ptI, ptSP, nIL, P_INVALID) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::UnprojectPointFromStm( int nT, const Point3d& ptI, Point3d& ptSP, int nIL, const Point3d& ptIPrevOrNext, bool* bThroughEdge) const
|
|
{
|
|
// calcolo la superficie se non già calcolata
|
|
if ( m_pSTMRefined == nullptr)
|
|
GetAuxSurfRefined() ;
|
|
|
|
ptSP = ORIG ;
|
|
if ( bThroughEdge != nullptr)
|
|
*bThroughEdge = false ;
|
|
// dato un punto sulla trimesh ausiliaria, ne ricavo le coordinate parametriche
|
|
const ISurfTriMesh* pSurfTm = GetAuxSurfRefined() ;
|
|
int nTriaIndex = nT ;
|
|
INTVECTOR vnT ;
|
|
if ( nT == -1) {
|
|
DistPointSurfTm distPtStm0( ptI, *pSurfTm) ;
|
|
distPtStm0.GetMinDistTriaIndex( nTriaIndex) ;
|
|
distPtStm0.GetMinDistTriaIndices( vnT) ;
|
|
}
|
|
// aggiungo il primo punto
|
|
// devo subito capire se sono in un polo o no
|
|
// se sono in polo e mi hanno passato un punto precedente allora devo prendere il triangolo di quel punto
|
|
bool bIsPole = false ;
|
|
bool bNearPole = false ; // devo capire se il triangolo di riferimento ha un vertice in un polo
|
|
INTVECTOR vInters(4) ;
|
|
fill( vInters.begin(), vInters.end(), 0) ;
|
|
// se necessario calcolo i poli
|
|
if ( m_vbPole.empty())
|
|
CalcPoles() ;
|
|
if ( m_vbPole[0] || m_vbPole[1] || m_vbPole[2] || m_vbPole[3] || m_bClosedU || m_bClosedV) {
|
|
// scorro sugli edge
|
|
for ( int c = 0 ; c < 4 ; ++c) {
|
|
// scorro sui tratti che compongono l'edge
|
|
for ( int i = 0 ; i < int( m_mCCEdge[c].size()) ; ++i) {
|
|
if ( ! m_mCCEdge[c][i]->IsValid()) {
|
|
Point3d pt ;
|
|
if ( ! m_mCCEdge[c][i]->GetOnlyPoint( pt))
|
|
return false ;
|
|
vInters[c] = AreSamePointApprox( pt, ptI) ? 1 : 0 ;
|
|
if ( vInters[c] == 1)
|
|
bIsPole = true ;
|
|
}
|
|
else {
|
|
vInters[c] = m_mCCEdge[c][i]->IsPointOn(ptI) ? 1 : 0 ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// se ho tre intersezioni vuol dire che un lato è collassato in un punto e il punto di cui voglio la controimmagine è esattamente nel polo
|
|
// oppure sono su un lato di chiusura
|
|
if ( bIsPole || ( m_bClosedU && ( vInters[1] == 1 || vInters[3] == 1)) || ( m_bClosedV && ( vInters[0] == 1 || vInters[2] == 1))) {
|
|
// visto che sono in un polo o su un lato di chiusura devo verificare di aver ricevuto il triangolo giusto
|
|
// se è stato passato il punto successivo o precedente mi sposto verso quello e ricalcolo il triangolo di appartenenza
|
|
if ( ! ptIPrevOrNext.IsValid())
|
|
return false ;
|
|
if ( bThroughEdge != nullptr)
|
|
*bThroughEdge = true ;
|
|
Point3d ptI2 = ptI + ( ptIPrevOrNext - ptI) * 10 * EPS_SMALL ;
|
|
// ricalcolo il triangolo di appartenenza
|
|
int nTriaOld = nTriaIndex ;
|
|
DistPointSurfTm dPtStm( ptI2, *pSurfTm) ;
|
|
dPtStm.GetMinDistTriaIndex( nTriaIndex) ;
|
|
// se ho trovato un nuovo triangolo, controllo che questo fosse nella lista dei triangoli equidistanti dal punto originale
|
|
// sennò ripeto il conto con meno scostamento
|
|
if ( nTriaOld != nTriaIndex) {
|
|
auto iter = find( vnT.begin(), vnT.end(),nTriaIndex) ;
|
|
int nIdTria = distance( vnT.begin(), iter) ;
|
|
if ( nIdTria > ssize( vnT) - 1) {
|
|
ptI2 = ptI + ( ptIPrevOrNext - ptI) * 5 * EPS_SMALL ;
|
|
DistPointSurfTm dPtStm2( ptI2, *pSurfTm) ;
|
|
dPtStm2.GetMinDistTriaIndex( nTriaIndex) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// recupero i dati dei vertici del triangolo che fa intersezione
|
|
int nVert[3] ;
|
|
pSurfTm->GetTriangle( nTriaIndex, nVert) ;
|
|
PNTVECTOR vPtPa(3) ;
|
|
pSurfTm->GetVertexParam( nVert[0], vPtPa[0].x, vPtPa[0].y) ;
|
|
vPtPa[0] *= SBZ_TREG_COEFF ;
|
|
pSurfTm->GetVertexParam( nVert[1], vPtPa[1].x, vPtPa[1].y) ;
|
|
vPtPa[1] *= SBZ_TREG_COEFF ;
|
|
pSurfTm->GetVertexParam( nVert[2], vPtPa[2].x, vPtPa[2].y) ;
|
|
vPtPa[2] *= SBZ_TREG_COEFF ;
|
|
PNTVECTOR vPT(3) ;
|
|
pSurfTm->GetVertex( nVert[0], vPT[0]) ;
|
|
pSurfTm->GetVertex( nVert[1], vPT[1]) ;
|
|
pSurfTm->GetVertex( nVert[2], vPT[2]) ;
|
|
// devo capire se il triangolo ha un vertice su un polo
|
|
int nVertOnPole = -1 ;
|
|
int nEdge = -1 ;
|
|
// do per scontato che al più un vertice possa essere in un polo
|
|
if ( m_vbPole[0] || m_vbPole[2]) {
|
|
for ( int p = 0 ; p < 3 ; ++p) {
|
|
if ( ( m_vbPole[0] && vPtPa[p].y > m_nSpanV * SBZ_TREG_COEFF - EPS_SMALL ) ) {
|
|
bNearPole = true ;
|
|
nVertOnPole = p ;
|
|
nEdge = 0 ;
|
|
}
|
|
else if ( m_vbPole[2] && vPtPa[p].y < 0 + EPS_SMALL) {
|
|
bNearPole = true ;
|
|
nVertOnPole = p ;
|
|
nEdge = 2 ;
|
|
}
|
|
}
|
|
}
|
|
else if ( m_vbPole[1] || m_vbPole[3]) {
|
|
for ( int p = 0 ; p < 3 ; ++p) {
|
|
if ( ( m_vbPole[3] && vPtPa[p].x > m_nSpanU * SBZ_TREG_COEFF - EPS_SMALL)) {
|
|
bNearPole = true ;
|
|
nVertOnPole = p ;
|
|
nEdge = 3 ;
|
|
}
|
|
else if ( m_vbPole[1] && vPtPa[p].x < 0 + EPS_SMALL) {
|
|
bNearPole = true ;
|
|
nVertOnPole = p ;
|
|
nEdge = 1 ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// se la superficie è chiusa controllo se devo tenere conto della periodicità nel prendere le coordinate parametriche dei vertici
|
|
double dParamH = 0, dParamL = 0 ;
|
|
INTVECTOR vOn(3) ;
|
|
fill( vOn.begin(), vOn.end(), -1) ;
|
|
bool bOneVertexOnClosureButNotPole = false ;
|
|
if ( m_bClosedU || m_bClosedV) {
|
|
dParamH = m_nSpanV * SBZ_TREG_COEFF ;
|
|
dParamL = m_nSpanU * SBZ_TREG_COEFF ;
|
|
// devo trovare il lato più lungo e confrontarlo con le dimensioni dello spazio parametrico
|
|
Vector3d vtDir ;
|
|
double dDist = 0 ;
|
|
if ( DistXY( vPtPa[0], vPtPa[1]) > DistXY( vPtPa[1], vPtPa[2]) && DistXY( vPtPa[0], vPtPa[1]) > Dist( vPtPa[0], vPtPa[2])){
|
|
vtDir = vPtPa[1] - vPtPa[0] ;
|
|
dDist = DistXY( vPtPa[0], vPtPa[1]) ;
|
|
}
|
|
else if ( DistXY( vPtPa[1], vPtPa[2]) > DistXY( vPtPa[0], vPtPa[1]) && DistXY( vPtPa[1], vPtPa[2]) > Dist( vPtPa[0], vPtPa[2])){
|
|
vtDir = vPtPa[2] - vPtPa[1] ;
|
|
dDist = DistXY( vPtPa[1], vPtPa[2]) ;
|
|
}
|
|
else if ( DistXY( vPtPa[0], vPtPa[2]) > DistXY( vPtPa[0], vPtPa[1]) && DistXY( vPtPa[0], vPtPa[2]) > Dist( vPtPa[1], vPtPa[2])){
|
|
vtDir = vPtPa[2] - vPtPa[0] ;
|
|
dDist = DistXY( vPtPa[0], vPtPa[2]) ;
|
|
}
|
|
vtDir.Normalize() ;
|
|
// se la dimensione maggiore è grande come la dimensione dello spazio parametrico allora potrebbe essere che le coordinate parametriche di un vertice
|
|
// siano da correggere per periodicità
|
|
// do per scontato che se la superficie è chiusa lungo un parametro i lati di chiusura non siano dei poli
|
|
if ( m_bClosedU && abs(vtDir.x) > abs( vtDir.y) && dDist > dParamL * 0.5 ) {
|
|
// trovo se dei vertici del triangolo sono sul bordo dello spazio parametrico
|
|
INTVECTOR vEdgesClosed = { 1, 3} ;
|
|
// scorro sui vertici
|
|
for ( int p = 0 ; p < 3; ++p ) {
|
|
// scorro sugli edge
|
|
for ( int ed : vEdgesClosed) {
|
|
// scorro sui tratti che compongono l'edge
|
|
for ( int i = 0 ; i < int( m_mCCEdge[ed].size()) ; ++i) {
|
|
if (m_mCCEdge[ed][i]->IsPointOn(vPT[p]) && vOn[p] == -1 )
|
|
vOn[p] = ed ;
|
|
}
|
|
}
|
|
}
|
|
// controllo che almeno un vertice sia su un edge e se è l'unico vertice, che non sia su un polo
|
|
if ( vOn[0] > 0 || vOn[1] > 0 || vOn[2] > 0) {
|
|
// se ho più di un vertice sul lato oppure se ne ho solo uno ma non è sul polo allora procedo alla correzione delle coordinate
|
|
bOneVertexOnClosureButNotPole = (vOn[0] > 0 && 0 != nVertOnPole) ||
|
|
(vOn[1] > 0 && 1 != nVertOnPole) ||
|
|
(vOn[2] > 0 && 2 != nVertOnPole) ;
|
|
if ( vOn[0] * vOn[1] * vOn[2] < 0 || bOneVertexOnClosureButNotPole) {
|
|
double dRightX = 0 ;
|
|
// tengo per buone le coordinate dei vertici che NON sono sul bordo dello spazio parametrico
|
|
for ( int p = 0 ; p < 3; ++p) {
|
|
if ( vOn[p] == -1) {
|
|
dRightX = vPtPa[p].x ;
|
|
break ;
|
|
}
|
|
}
|
|
for ( int p = 0 ; p < 3; ++p) {
|
|
//if ( abs(vPtPa[p].x - dRightX) > EPS_SMALL ) {
|
|
if ( abs(vPtPa[p].x - dRightX) > SBZ_TREG_COEFF / 2) {
|
|
if ( vPtPa[p].x < EPS_SMALL)
|
|
vPtPa[p].x = dParamL ;
|
|
else
|
|
vPtPa[p].x = 0 ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if ( m_bClosedV && abs(vtDir.y) > abs(vtDir.x) && dDist > dParamH * 0.5) {
|
|
int nVertOnPole = -1 ;
|
|
INTVECTOR vEdgesClosed = { 0, 2} ;
|
|
// scorro sui vertici
|
|
for ( int p = 0 ; p < 3; ++p ) {
|
|
//scorro sugli edge
|
|
for (int ed : vEdgesClosed) {
|
|
// scorro sui tratti che compongono l'edge
|
|
for ( int i = 0 ; i < int( m_mCCEdge[ed].size()) ; ++i) {
|
|
if ( m_mCCEdge[ed][i]->IsPointOn( vPT[p]) && vOn[p] == -1)
|
|
vOn[p] = ed ;
|
|
}
|
|
}
|
|
}
|
|
// controllo che almeno un vertice sia su un edge
|
|
if ( vOn[0] > 0 || vOn[1] > 0 || vOn[2] > 0) {
|
|
// se ho più un vertice sul lato oppure se ne ho solo uno ma non è sul polo allora procedo alla correzione delle coordinate
|
|
bOneVertexOnClosureButNotPole = (vOn[0] > 0 && 0 != nVertOnPole) ||
|
|
(vOn[1] > 0 && 1 != nVertOnPole) ||
|
|
(vOn[2] > 0 && 2 != nVertOnPole) ;
|
|
if ( vOn[0] * vOn[1] * vOn[2] < 0 || bOneVertexOnClosureButNotPole) {
|
|
double dRightY = 0 ;
|
|
// tengo per buone le coordinate dei vertici che NON sono sul bordo dello spazio parametrico
|
|
for ( int p = 0 ; p < 3; ++p) {
|
|
if ( vOn[p] == -1) {
|
|
dRightY = vPtPa[p].y ;
|
|
break ;
|
|
}
|
|
}
|
|
for ( int p = 0 ; p < 3; ++p) {
|
|
//if ( abs(vPtPa[p].y - dRightY) > EPS_SMALL) {
|
|
if ( abs(vPtPa[p].y - dRightY) > SBZ_TREG_COEFF / 2) {
|
|
if ( vPtPa[p].y < EPS_SMALL)
|
|
vPtPa[p].y = dParamH ;
|
|
else
|
|
vPtPa[p].y = 0 ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
for ( int p = 0 ; p < 3; ++p ) {
|
|
//scorro sugli edge
|
|
for (int ed = 0 ; ed < 4 ; ++ed) {
|
|
// scorro sui tratti che compongono l'edge
|
|
for ( int i = 0 ; i < int( m_mCCEdge[ed].size()) ; ++i) {
|
|
if ( m_mCCEdge[ed][i]->IsPointOn( vPT[p]) && vOn[p] == -1)
|
|
vOn[p] = ed ;
|
|
}
|
|
}
|
|
}
|
|
// anche se non ho un triangolo molto stretchato potrei avere il punto di polo con coordinate parametriche sballate
|
|
bOneVertexOnClosureButNotPole = ((m_bClosedU && (vOn[0] == 1 || vOn[0] == 3)) && 0 != nVertOnPole) ||
|
|
((m_bClosedU && (vOn[1] == 1 || vOn[1] == 3)) && 1 != nVertOnPole) ||
|
|
((m_bClosedU && (vOn[2] == 1 || vOn[2] == 3)) && 2 != nVertOnPole) ||
|
|
((m_bClosedV && (vOn[0] == 0 || vOn[0] == 2)) && 0 != nVertOnPole) ||
|
|
((m_bClosedV && (vOn[1] == 0 || vOn[1] == 2)) && 1 != nVertOnPole) ||
|
|
((m_bClosedV && (vOn[2] == 0 || vOn[2] == 2)) && 2 != nVertOnPole) ;
|
|
}
|
|
}
|
|
// devo anche tener conto della possibilità che i lati siano collassati in poli
|
|
if ( bIsPole || bNearPole) {
|
|
// controllo di aver trovato il lato collassato in polo su cui sta il vertice del triangolo o il punto di intersezione
|
|
if ( nEdge == -1)
|
|
return false ;
|
|
// trovo la coordinata giusta da tenere ( x o y a seconda dell'edge)
|
|
double dRightX = 0, dRightY = 0 ;
|
|
for ( int p = 0 ; p < 3; ++p) {
|
|
if ( p != nVertOnPole) {
|
|
if ( nEdge == 0 || nEdge == 2) {
|
|
dRightY = nEdge == 0 ? dParamH : 0 ;
|
|
if ( vPtPa[p].x > dRightX )
|
|
dRightX= vPtPa[p].x ;
|
|
// se un vertice è su un lato di chiusura, visto che sono vicino ad un polo, mi accerto che un lato del triangolo sia SUL lato di chiusura
|
|
if ( m_bClosedU && bOneVertexOnClosureButNotPole) {
|
|
dRightX = ( dParamL - vPtPa[p].x > vPtPa[p].x ? 0 : dParamL) ;
|
|
break ;
|
|
}
|
|
}
|
|
else if ( nEdge == 1 || nEdge == 3) {
|
|
// se un vertice è su un lato di chiusura, visto che sono vicino ad un polo, mi accerto che un lato del triangolo sia SUL lato di chiusura
|
|
dRightX = nEdge == 1 ? 0 : dParamL ;
|
|
if ( vPtPa[p].y > dRightY )
|
|
dRightY = vPtPa[p].y ;
|
|
if ( m_bClosedV && bOneVertexOnClosureButNotPole) {
|
|
dRightY = ( dParamH - vPtPa[p].y > vPtPa[p].y ? 0 : dParamH) ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// correggo le coordinate del punto sull'edge di polo
|
|
for ( int p = 0 ; p < 3 ; ++p) {
|
|
if ( p == nVertOnPole) {
|
|
vPtPa[p].x = dRightX ;
|
|
vPtPa[p].y = dRightY ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// se l'intersezione era su un vertice ( NON DI POLO) restituisco le coordinate parametriche del vertice
|
|
if ( nIL == IntLineTriaType::ILTT_VERT && ! bIsPole) {
|
|
if ( AreSamePointApprox(ptI, vPT[0]))
|
|
ptSP = vPtPa[0] ;
|
|
else if ( AreSamePointApprox(ptI, vPT[1]))
|
|
ptSP = vPtPa[1] ;
|
|
else if ( AreSamePointApprox(ptI, vPT[2]))
|
|
ptSP = vPtPa[2] ;
|
|
// restituisco il punto nel parametrico riscalato
|
|
ptSP / SBZ_TREG_COEFF ;
|
|
return true ;
|
|
}
|
|
// calcolo approssimativamente le coordinate nello spazio parametrico del punto di intersezione
|
|
// quindi prima calcolo la composizione lineare tra i vertici del triangolo per ottenere il punto di intersezione
|
|
Eigen::Matrix3d mA ;
|
|
mA.col(0) << vPT[0].x, vPT[0].y , vPT[0].z ;
|
|
mA.col(1) << vPT[1].x, vPT[1].y , vPT[1].z ;
|
|
mA.col(2) << vPT[2].x, vPT[2].y , vPT[2].z ;
|
|
int nCount = 0 ;
|
|
Vector3d vtMod( 0, 0, 0) ;
|
|
while ( abs( mA.determinant()) < EPS_SMALL) {
|
|
if ( nCount %3 == 0) {
|
|
mA.row(0) << vPT[0].x + 1, vPT[1].x + 1, vPT[2].x + 1 ;
|
|
vtMod.x += 1 ;
|
|
}
|
|
else if ( nCount %3 == 1) {
|
|
mA.row(1) << vPT[0].y + 1, vPT[1].y + 1, vPT[2].y + 1 ;
|
|
vtMod.y += 1 ;
|
|
}
|
|
else if ( nCount %3 == 2) {
|
|
mA.row(2) << vPT[0].z + 1, vPT[1].z + 1, vPT[2].z + 1 ;
|
|
vtMod.z += 1 ;
|
|
}
|
|
++nCount ;
|
|
if ( nCount == 10)
|
|
return false ;
|
|
}
|
|
Point3d ptNewI = ptI + vtMod ;
|
|
Eigen::Vector3d b ( ptNewI.x, ptNewI.y, ptNewI.z) ;
|
|
Eigen::Vector3d x = mA.fullPivLu().solve(b) ;
|
|
// applico questa composizione alle loro coordinate parametriche
|
|
Eigen::Matrix3d mB ;
|
|
mB.col(0) << vPtPa[0].x, vPtPa[0].y, 0 ;
|
|
mB.col(1) << vPtPa[1].x, vPtPa[1].y, 0 ;
|
|
mB.col(2) << vPtPa[2].x, vPtPa[2].y, 0 ;
|
|
Eigen::Vector3d ptParam = mB * x ;
|
|
// restituisco il punto nel parametrico riscalato
|
|
IncreaseUV( ptSP.x, ptParam.x() / SBZ_TREG_COEFF, true) ;
|
|
IncreaseUV( ptSP.y, ptParam.y() / SBZ_TREG_COEFF, false) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::UnprojectPoint( const Point3d& pt3D, Point3d& ptParam, const Point3d& ptIPrev, bool* bThroughEdge, const Plane3d* pPlCut) const
|
|
{
|
|
// calcolo la superficie se non già calcolata
|
|
if ( m_pSTMRefined == nullptr)
|
|
GetAuxSurfRefined() ;
|
|
|
|
// se necessario calcolo i poli
|
|
if ( m_vbPole.empty())
|
|
CalcPoles() ;
|
|
|
|
// dato il punto pt3D sulla superficie di Bezier si cercano le coordinate parametriche ( ptParam) , iterativamente con Newton
|
|
// trovato un primo candidato ptParam, ne calcolo l'immagine sulla superficie ( ptBez) e ne calcolo la distanza con il punto pt3D
|
|
// ripeto cercando di avvicinarmi il più possibile
|
|
// per trovare il primo punto trovo il triangolo della trimesh ausiliaria più vicino e il punto più vicino
|
|
DistPointSurfTm dptSurfTm( pt3D, *GetAuxSurfRefined()) ;
|
|
Point3d ptI ; dptSurfTm.GetMinDistPoint( ptI) ;
|
|
if ( ! UnprojectPointFromStm( -1, ptI, ptParam, IntLineTriaType::ILTT_IN, ptIPrev, bThroughEdge))
|
|
return false ;
|
|
Point3d ptBez ;
|
|
GetPointD1D2( ptParam.x, ptParam.y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBez) ;
|
|
// usando un algoritmo di newton cerco di avvicinarmi il più possibile al punto
|
|
|
|
double dDistNew = pPlCut == nullptr ? Dist( pt3D, ptBez) : abs(DistPointPlane( ptBez, *pPlCut)) ;
|
|
double dDistPre ;
|
|
double dDist0, dDist1;
|
|
|
|
int nCount = 0 ;
|
|
double dh = EPS_SMALL ;
|
|
// metodo di newton in più dimensioni
|
|
// vario sia il parametro U che il parametro V e verifico se la distanza dalla retta diminuisce per scostamenti positivi o negativi.
|
|
bool bRetry = false ;
|
|
double dApproach = 0.01 ;
|
|
bool bDesperate = false ;
|
|
double dAng = 1 ;
|
|
double dr = 5 ;
|
|
double dfdU, dfdV ;
|
|
|
|
while ( dDistNew > 2 * EPS_SMALL && nCount < 100) {
|
|
|
|
if ( ! bRetry) {
|
|
dDistPre = dDistNew ;
|
|
// derivata in U
|
|
Point3d ptIBzNew1 ;
|
|
double dUh ; IncreaseUV( ptParam.x, dh, true, &dUh, false) ;
|
|
GetPointD1D2( dUh, ptParam.y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptIBzNew1) ;
|
|
dDist0 = pPlCut == nullptr ? Dist( pt3D, ptIBzNew1) : abs(DistPointPlane( ptIBzNew1, *pPlCut)) ;
|
|
dfdU = ( dDist0 - dDistPre) / dh ;
|
|
// derivata in V
|
|
Point3d ptIBzNew2 ;
|
|
double dVh ; IncreaseUV( ptParam.y, dh, false, &dVh, false) ;
|
|
GetPointD1D2( ptParam.x, dVh, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptIBzNew2) ;
|
|
dDist1 = pPlCut == nullptr ? Dist( pt3D, ptIBzNew2) : abs(DistPointPlane( ptIBzNew2, *pPlCut)) ;
|
|
dfdV = ( dDist1 - dDistPre) / dh ;
|
|
}
|
|
// calcolo le nuove coordinate
|
|
Vector3d vtDir ;
|
|
double dASum = abs( dfdU) + abs( dfdV) ;
|
|
double dSSum = sqrt( dfdU * dfdU + dfdV * dfdV) ;
|
|
vtDir.Set( - dfdU, - dfdV, 0) ;
|
|
if ( ! vtDir.Normalize() )
|
|
vtDir.Set( - dfdU / dSSum, - dfdV / dSSum, 0) ;
|
|
if ( ! vtDir.IsValid())
|
|
return false ;
|
|
dr = dDistPre / dASum ;
|
|
// in modalità Retry riduco lo spostamento
|
|
vtDir *= dr * ( bRetry ? 0.1 : 0.5) ;
|
|
if ( bDesperate) {
|
|
// in depserate mode riduco lo spostamento e comincio a cambiare progressivamente la direzione oscillando tra destra e sinistra della direzione "naturale"
|
|
vtDir *= 0.5 ;
|
|
dAng *= -1.25 ;
|
|
// riduco ulteriormente lo spostamento dopo qualche giro in desperate mode
|
|
if ( abs( dAng) > 5)
|
|
vtDir *= 0.5 ;
|
|
vtDir.Rotate( Z_AX, dAng) ;
|
|
}
|
|
Point3d ptCopy = ptParam ;
|
|
IncreaseUV( ptParam, vtDir, nullptr, true) ;
|
|
// calcolo la nuova distanza tra il punto di partenza e quello che sto trovando con le coordinate attuali
|
|
GetPointD1D2( ptParam.x, ptParam.y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBez) ;
|
|
dDistNew = pPlCut == nullptr ? Dist( pt3D, ptBez) : abs(DistPointPlane( ptBez, *pPlCut)) ;
|
|
|
|
dApproach = dDistPre - dDistNew ;
|
|
// se ho peggiorato la situazione rispetto allo step precedente torno indietro e vado in Retry mode
|
|
if ( dApproach < EPS_ZERO) {
|
|
if ( bRetry)
|
|
bDesperate = true ; // entro in desperate mode
|
|
ptParam = ptCopy ;
|
|
bRetry = true ;
|
|
// se ho già fatto 9 giri in desperate mode allora esco
|
|
if ( abs( dAng) > 8)
|
|
break ;
|
|
}
|
|
else {
|
|
bRetry = false ;
|
|
bDesperate = false ;
|
|
dAng = 1 ;
|
|
}
|
|
++nCount ;
|
|
}
|
|
|
|
// se il punto era su un edge allora verifico che sia ancora su un edge, sennò ce lo riporto
|
|
// guardo a quale dei due lati sono più vicino
|
|
// devo distinguere il caso di un triangolo a metà dello spazio, con un vertice su un lato di polo, ma senza vertici su lati di chiusura
|
|
if ( bThroughEdge != nullptr && *bThroughEdge) {
|
|
if ( m_bClosedU) {
|
|
if ( ptParam.x < EPS_SMALL)
|
|
ptParam.x = 0 ;
|
|
else if ( abs( m_nSpanU - ptParam.x) < EPS_SMALL)
|
|
ptParam.x = m_nSpanU ;
|
|
}
|
|
if ( m_bClosedV) {
|
|
if ( ptParam.y < EPS_SMALL)
|
|
ptParam.y = 0 ;
|
|
else if ( abs( m_nSpanV - ptParam.y) < EPS_SMALL)
|
|
ptParam.y = m_nSpanV ;
|
|
}
|
|
}
|
|
|
|
return nCount != 100 || (dDistNew < dDistPre ? dDistNew : dDistPre) < 10 * EPS_SMALL ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::CalcPoles( void) const
|
|
{
|
|
if ( ! m_vbPole.empty())
|
|
return true ;
|
|
// la funzione identifica se degli edge della superficie non trimmata sono in realtà dei poli
|
|
for ( int i = 0 ; i < 4 ; ++i)
|
|
m_vbPole.emplace_back( true) ;
|
|
// scorro i punti di controllo e vedo subito
|
|
bool bOk = false ;
|
|
bool bPole0 = true, bPole1 = true ;
|
|
Point3d ptU0, ptU1 ;
|
|
// controllo l'edge 0 e 2 per vedere se tutti i punti dell'edge sono coincidenti
|
|
Point3d ptP00 = GetControlPoint( 0, &bOk) ;
|
|
Point3d ptP10 = GetControlPoint( m_nDegU * m_nSpanU, &bOk) ;
|
|
for ( int i = 1 ; i < m_nDegV * m_nSpanV + 1 ; ++ i) {
|
|
ptU0 = GetControlPoint( i * ( m_nDegU * m_nSpanU + 1), &bOk) ;
|
|
bPole0 = bPole0 && AreSamePointApprox( ptP00, ptU0) ;
|
|
ptU1 = GetControlPoint( ( i + 1) * ( m_nDegU * m_nSpanU + 1) - 1, &bOk) ;
|
|
bPole1 = bPole1 && AreSamePointApprox( ptP10, ptU1) ;
|
|
if ( ! bPole0 && ! bPole1)
|
|
break ;
|
|
}
|
|
m_vbPole[1] = bPole0 ; // u = 0 corrisponde all'edge 1
|
|
m_vbPole[3] = bPole1 ; // u = 1 corrisponde all'edge 3
|
|
// controllo l'edge 1 e 3 per vedere se tutti i punti dell'edge sono coincidenti
|
|
Point3d ptV0, ptV1 ;
|
|
Point3d ptP01 = GetControlPoint( ( m_nDegU * m_nSpanU + 1) * ( m_nDegV * m_nSpanV), &bOk) ;
|
|
bPole0 = true ;
|
|
bPole1 = true ;
|
|
for ( int i = 1 ; i < m_nDegU * m_nSpanU + 1 ; ++ i) {
|
|
ptV0 = GetControlPoint( i, &bOk) ;
|
|
bPole0 = bPole0 && AreSamePointApprox( ptP00, ptV0) ;
|
|
ptV1 = GetControlPoint( i + ( m_nDegU * m_nSpanU + 1) * ( m_nDegV * m_nSpanV), &bOk) ;
|
|
bPole1 = bPole1 && AreSamePointApprox( ptP01, ptV1) ;
|
|
if ( ! bPole0 && ! bPole1)
|
|
break ;
|
|
}
|
|
m_vbPole[0] = bPole1 ; // v = 1 corrisponde all'edge 0
|
|
m_vbPole[2] = bPole0 ; // v = 0 corrisponde all'edge 2
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::GetLoops( ICRVCOMPOPOVECTOR& vCC, bool bLineOrBezier) const
|
|
{
|
|
// se necessario calcolo i poli
|
|
if ( m_vbPole.empty())
|
|
CalcPoles() ;
|
|
|
|
// se nEdge non è definito ( == -1) allora restituisco tutti gli edge in ordine
|
|
// se bOpenOrAll è true allora restituisco solo gli edge aperti e che non sono di polo
|
|
if ( m_pSTMRefined == nullptr)
|
|
GetAuxSurfRefined() ;
|
|
|
|
// se la superficie non è trimmata mi basta recuperare gli edge della superficie
|
|
if ( ! m_bTrimmed) {
|
|
// se decidessi di non restituire gli edge chiusi e i poli posso discriminare qui
|
|
vCC.emplace_back( CreateCurveComposite()) ;
|
|
if ( ! m_bClosedV ) {
|
|
if ( ! m_vbPole[0])
|
|
vCC.back()->AddCurve( GetSingleEdge3D( bLineOrBezier, 0)) ;
|
|
}
|
|
if ( ! m_bClosedU ) {
|
|
if ( ! m_vbPole[1])
|
|
vCC.back()->AddCurve( GetSingleEdge3D( bLineOrBezier, 1)) ;
|
|
}
|
|
if ( ! m_bClosedV ) {
|
|
if ( ! m_vbPole[2]) {
|
|
// se superficie è chiusa lungo il parametro U, ma non lo è lungo il parametro V allora avrò due curve separate( un cilindro)
|
|
if ( m_bClosedU)
|
|
vCC.emplace_back( CreateCurveComposite()) ;
|
|
vCC.back()->AddCurve( GetSingleEdge3D( bLineOrBezier, 2)) ;
|
|
}
|
|
}
|
|
if ( ! m_bClosedU ) {
|
|
if ( ! m_vbPole[3]) {
|
|
// se superficie è chiusa lungo il parametro V, ma non lo è lungo il parametro U allora avrò due curve separate( un cilindro)
|
|
if ( m_bClosedV)
|
|
vCC.emplace_back( CreateCurveComposite()) ;
|
|
vCC.back()->AddCurve( GetSingleEdge3D( bLineOrBezier, 3)) ;
|
|
}
|
|
}
|
|
}
|
|
// se la superficie è trimmata devo recuperare i loop dello spazio parametrico
|
|
else {
|
|
// devo ricostruire i bordi aperti in caso di superficie chiusa
|
|
// costruisco gli edge
|
|
ICurveLine* pCLU0( CreateCurveLine()) ;
|
|
ICurveLine* pCLU1( CreateCurveLine()) ;
|
|
ICurveLine* pCLV0( CreateCurveLine()) ;
|
|
ICurveLine* pCLV1( CreateCurveLine()) ;
|
|
if ( m_bClosedU ) {
|
|
pCLU0->Set( Point3d( 0, m_nSpanV * SBZ_TREG_COEFF, 0), ORIG) ;
|
|
pCLU1->Set( Point3d( m_nSpanU * SBZ_TREG_COEFF, 0, 0), Point3d( m_nSpanU * SBZ_TREG_COEFF, m_nSpanV * SBZ_TREG_COEFF, 0)) ;
|
|
}
|
|
if ( m_bClosedV ) {
|
|
pCLV0->Set( ORIG, Point3d( m_nSpanU * SBZ_TREG_COEFF, 0, 0)) ;
|
|
pCLV1->Set( Point3d( m_nSpanU * SBZ_TREG_COEFF, m_nSpanV * SBZ_TREG_COEFF, 0), Point3d( 0, m_nSpanV * SBZ_TREG_COEFF, 0)) ;
|
|
}
|
|
ICRVLINEPOVECTOR vEdge ;
|
|
// li metto con l'ordine degli edge
|
|
vEdge.emplace_back( pCLV1) ;
|
|
vEdge.emplace_back( pCLU0) ;
|
|
vEdge.emplace_back( pCLV0) ;
|
|
vEdge.emplace_back( pCLU1) ;
|
|
// costruisco la mappa delle intersezioni, trovando tutte le intersezioni tra i trim e il loop esterno dello spazio parametrico
|
|
// i 4 elementi fanno riferimento ai 4 edge. per ogni loop viene salvato il vettore delle intersezioni con tale edege
|
|
vector<unordered_map<int,ICCIVECTOR>> vmInters(4) ;
|
|
// comincio anche a creare il vettore di vettori associati ad ogni loop che fa almeno un'intersezione con un edge.
|
|
// in ogni vettore verranno salvati l'indice del loop all'interno del vettore dei loop e gli indici di tutti i loop che deriveranno da sue divisioni in più curve
|
|
unordered_map<int,INTVECTOR> mSplitLoop ;
|
|
int nOriginalLoops = int( m_vCCLoop.size()) ;
|
|
for ( int l = 0 ; l < nOriginalLoops ; ++ l) {
|
|
bool bInters = false ;
|
|
// devo controllare se i loop si appoggiano a bordi chiusi
|
|
// se ne ho più di uno che si appoggia allora devo vedere se trovo dei gruppi di loop che in realtà in 3d sono un edge unico, ma nel 2d risultano a cavallo dell'edge di chiusura
|
|
//PtrOwner<ICurveComposite> pLoop( m_vCCLoop[l]->Clone()) ;
|
|
for ( int j = 0 ; j < 4 ; ++j) {
|
|
// il primo è un loop di trim, il secondo è un edge dello spazio parametrico
|
|
IntersCurveCurve icc( *m_vCCLoop[l], *vEdge[j]) ;
|
|
ICCIVECTOR vICC ;
|
|
for ( int i = 0 ; i < int(icc.GetIntersCount()) ; ++i ) {
|
|
IntCrvCrvInfo iccInfo ;
|
|
icc.GetIntCrvCrvInfo( i, iccInfo) ;
|
|
vICC.push_back( iccInfo) ;
|
|
}
|
|
if ( int(vICC.size()) > 0) {
|
|
vmInters[j].insert(pair<int, ICCIVECTOR>(l, vICC)) ;
|
|
bInters = true ;
|
|
}
|
|
}
|
|
if ( bInters)
|
|
mSplitLoop.insert( pair<int,INTVECTOR>( l, INTVECTOR({l}))) ;
|
|
}
|
|
|
|
if ( m_bClosedV) {
|
|
// scorro i loop che fanno intersezioni con l'edge 0 ( V=1) e le riporto sull'edge opposto
|
|
for ( pair<int, ICCIVECTOR> vInters0 : vmInters[0]) {
|
|
// scorro le intersezioni del loop
|
|
for ( IntCrvCrvInfo& inters0 : vInters0.second) {
|
|
if ( ! inters0.bOverlap)
|
|
continue ;
|
|
Point3d ptStart0 = inters0.IciA[0].ptI ;
|
|
Point3d ptEnd0 = inters0.IciA[1].ptI ;
|
|
// porto i punti sull'edge opposto
|
|
ptStart0.y = 0 ;
|
|
ptEnd0.y = 0 ;
|
|
// scorro le intersezioni sull'edge opposto e quando trovo un loop che tra le sue intersezioni contiene uno dei punti che ho appena portato
|
|
// su qusto edge allora cancello la parte comune
|
|
for ( auto& vInters2 : vmInters[2] ) {
|
|
// scorro le intersezioni di questo loop
|
|
for ( IntCrvCrvInfo& inters2 : vInters2.second) {
|
|
// se lo start o end del loop corrente è compreso tra lo start e l'end di un loop che fa intesezione sull'edge opposto allora
|
|
// devo cancellare la parte comune
|
|
Point3d ptStart2 = inters2.IciA[0].ptI ;
|
|
Point3d ptEnd2 = inters2.IciA[1].ptI ;
|
|
// come ptStart2 prendo quello con la x maggiore
|
|
if ( ptStart2.x < ptEnd2.x)
|
|
swap( ptStart2, ptEnd2) ;
|
|
if ( (( ptEnd0.x - EPS_SMALL< ptStart2.x && ptStart2.x < ptStart0.x + EPS_SMALL) || ( ptEnd0.x - EPS_SMALL < ptEnd2.x && ptEnd2.x < ptStart0.x + EPS_SMALL)) ||
|
|
(( ptEnd2.x - EPS_SMALL < ptStart0.x && ptStart0.x < ptStart2.x + EPS_SMALL) || ( ptEnd2.x - EPS_SMALL < ptEnd0.x && ptEnd0.x < ptStart2.x + EPS_SMALL))) {
|
|
PtrOwner<ICurveLine> pCL( CreateBasicCurveLine()) ;
|
|
pCL->Set( ptStart0, ptEnd0) ;
|
|
// devo scorrere su tutte le curve che sono state ottenute dallo split del loop originale
|
|
for ( int w = 0 ; w < int( mSplitLoop[vInters2.first].size()) ; ++w) {
|
|
int nIndex2 = mSplitLoop[vInters2.first][w] ;
|
|
IntersCurveCurve icc( *m_vCCLoop[nIndex2], *pCL) ;
|
|
IntCrvCrvInfo iccInfo ; icc.GetIntCrvCrvInfo( 0, iccInfo) ;
|
|
for ( int k = 0 ; k < icc.GetIntersCount() ; ++k) {
|
|
icc.GetIntCrvCrvInfo( k, iccInfo) ;
|
|
if ( iccInfo.bOverlap)
|
|
break ;
|
|
}
|
|
if ( ! iccInfo.bOverlap)
|
|
continue ;
|
|
// se parto da una curva chiusa semplicemente tolgo un pezzo
|
|
if ( m_vCCLoop[nIndex2]->IsClosed()) {
|
|
ICurveComposite* pCC2( GetCurveComposite( m_vCCLoop[nIndex2]->CopyParamRange( iccInfo.IciA[1].dU, iccInfo.IciA[0].dU))) ;
|
|
m_vCCLoop[nIndex2].Set( pCC2) ;
|
|
}
|
|
else {
|
|
// se la curva era già aperta allora otterrò due curve separate
|
|
ICurveComposite* pCC2a( GetCurveComposite( m_vCCLoop[nIndex2]->Clone())) ;
|
|
bool bDoneA = pCC2a->TrimEndAtParam( iccInfo.IciA[0].dU) ;
|
|
ICurveComposite* pCC2b( GetCurveComposite( m_vCCLoop[nIndex2]->Clone())) ;
|
|
bool bDoneB = pCC2b->TrimStartAtParam( iccInfo.IciA[1].dU) ;
|
|
if ( bDoneA) {
|
|
m_vCCLoop[nIndex2].Set( pCC2a) ;
|
|
if ( bDoneB) {
|
|
m_vCCLoop.emplace_back( pCC2b) ;
|
|
mSplitLoop[vInters2.first].push_back( m_vCCLoop.size() - 1) ;
|
|
}
|
|
}
|
|
else if ( bDoneB)
|
|
m_vCCLoop[nIndex2].Set( pCC2b) ;
|
|
}
|
|
|
|
// per togliere la parte comune al loop corrente devo riportare i punti di intersezione sull'edge di partenza
|
|
Point3d ptOverlapS = iccInfo.IciB[0].ptI ;
|
|
Point3d ptOverlapE = iccInfo.IciB[1].ptI ;
|
|
ptOverlapS.y = m_nSpanV * SBZ_TREG_COEFF ;
|
|
ptOverlapE.y = m_nSpanV * SBZ_TREG_COEFF ;
|
|
double dStart0, dEnd0 ;
|
|
// scorro tutte le curve in cui è stato splittato il loop corrente
|
|
for ( int j = 0 ; j < int( mSplitLoop[vInters0.first].size()) ; ++j ) {
|
|
int nIndex0 = mSplitLoop[vInters0.first][j] ;
|
|
if ( ! m_vCCLoop[nIndex0]->GetParamAtPoint( ptOverlapS, dStart0) || ! m_vCCLoop[nIndex0]->GetParamAtPoint( ptOverlapE, dEnd0))
|
|
continue ;
|
|
// se parto da una curva chiusa semplicemente tolgo un pezzo
|
|
if ( m_vCCLoop[nIndex0]->IsClosed()) {
|
|
ICurveComposite* pCC0( GetCurveComposite( m_vCCLoop[nIndex0]->CopyParamRange( dStart0, dEnd0))) ;
|
|
m_vCCLoop[nIndex0].Set( pCC0) ;
|
|
}
|
|
else {
|
|
// se la curva era già aperta allora otterrò due curve separate
|
|
ICurveComposite* pCC0a( GetCurveComposite( m_vCCLoop[nIndex0]->Clone())) ;
|
|
bool bDoneA = pCC0a->TrimEndAtParam( dEnd0) ;
|
|
ICurveComposite* pCC0b( GetCurveComposite( m_vCCLoop[nIndex0]->Clone())) ;
|
|
bool bDoneB = pCC0b->TrimStartAtParam( dStart0) ;
|
|
if ( bDoneA) {
|
|
m_vCCLoop[nIndex0].Set( pCC0a) ;
|
|
if ( bDoneB) {
|
|
m_vCCLoop.emplace_back( pCC0b) ;
|
|
mSplitLoop[vInters0.first].push_back( m_vCCLoop.size() - 1) ;
|
|
}
|
|
}
|
|
else if ( bDoneB)
|
|
m_vCCLoop[nIndex0].Set( pCC0b) ;
|
|
}
|
|
//break ;
|
|
}
|
|
//break ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( m_bClosedU) {
|
|
// scorro i loop che fanno intersezioni con l'edge 1 ( U=0) e le riporto sull'edge opposto
|
|
for ( auto& vInters1 : vmInters[1]) {
|
|
// scorro le intersezioni del loop
|
|
for ( IntCrvCrvInfo& inters1 : vInters1.second) {
|
|
if ( ! inters1.bOverlap)
|
|
continue ;
|
|
Point3d ptStart1 = inters1.IciA[0].ptI ;
|
|
Point3d ptEnd1 = inters1.IciA[1].ptI ;
|
|
// porto i punti sull'edge opposto
|
|
ptStart1.x = m_nSpanU * SBZ_TREG_COEFF ;
|
|
ptEnd1.x = m_nSpanU * SBZ_TREG_COEFF ;
|
|
// scorro le intersezioni sull'edge opposto e quando trovo un loop che tra le sue intersezioni contiene uno dei punti che ho appena portato
|
|
// su qusto edge allora cancello la parte comune
|
|
for ( pair<int, ICCIVECTOR> vInters3 : vmInters[3] ) {
|
|
// scorro le intersezioni di questo loop
|
|
for ( IntCrvCrvInfo& inters3 : vInters3.second) {
|
|
// se lo start o end del loop corrente è compreso tra lo start e l'end di un loop che fa intesezione sull'edge opposto allora
|
|
// devo cancellare la parte comune
|
|
Point3d ptStart3 = inters3.IciA[0].ptI ;
|
|
Point3d ptEnd3 = inters3.IciA[1].ptI ;
|
|
// come ptStart3 prendo quello con la y maggiore
|
|
if ( ptStart3.y < ptEnd3.y)
|
|
swap( ptStart3, ptEnd3) ;
|
|
if ( (( ptEnd1.y - EPS_SMALL< ptStart3.y && ptStart3.y < ptStart1.y + EPS_SMALL) || ( ptEnd1.y - EPS_SMALL < ptEnd3.y && ptEnd3.y < ptStart1.y + EPS_SMALL)) ||
|
|
(( ptEnd3.y - EPS_SMALL < ptStart1.y && ptStart1.y < ptStart3.y + EPS_SMALL) || ( ptEnd3.y - EPS_SMALL < ptEnd1.y && ptEnd1.y < ptStart3.y + EPS_SMALL))) {
|
|
PtrOwner<ICurveLine> pCL( CreateBasicCurveLine()) ;
|
|
pCL->Set( ptStart1, ptEnd1) ;
|
|
// devo scorrere su tutte le curve che sono state ottenute dallo split del loop originale
|
|
for ( int w = 0 ; w < int( mSplitLoop[vInters3.first].size()) ; ++w) {
|
|
int nIndex3 = mSplitLoop[vInters3.first][w] ;
|
|
IntersCurveCurve icc( *m_vCCLoop[nIndex3], *pCL) ;
|
|
IntCrvCrvInfo iccInfo ;
|
|
for ( int k = 0 ; k < icc.GetIntersCount() ; ++k) {
|
|
icc.GetIntCrvCrvInfo( k, iccInfo) ;
|
|
if ( iccInfo.bOverlap)
|
|
break ;
|
|
}
|
|
if ( ! iccInfo.bOverlap)
|
|
continue ;
|
|
// se parto da una curva chiusa semplicemente tolgo un pezzo
|
|
if ( m_vCCLoop[nIndex3]->IsClosed()) {
|
|
ICurveComposite* pCC3( GetCurveComposite( m_vCCLoop[nIndex3]->CopyParamRange( iccInfo.IciA[1].dU, iccInfo.IciA[0].dU))) ;
|
|
m_vCCLoop[nIndex3].Set( pCC3) ;
|
|
}
|
|
else {
|
|
// se la curva era già aperta allora otterrò due curve separate
|
|
ICurveComposite* pCC3a( GetCurveComposite( m_vCCLoop[nIndex3]->Clone())) ;
|
|
bool bDoneA = pCC3a->TrimEndAtParam( iccInfo.IciA[0].dU) ;
|
|
ICurveComposite* pCC3b( GetCurveComposite( m_vCCLoop[nIndex3]->Clone())) ;
|
|
bool bDoneB = pCC3b->TrimStartAtParam( iccInfo.IciA[1].dU) ;
|
|
if ( bDoneA) {
|
|
m_vCCLoop[nIndex3].Set( pCC3a) ;
|
|
if ( bDoneB) {
|
|
m_vCCLoop.emplace_back( pCC3b) ;
|
|
mSplitLoop[vInters3.first].push_back( m_vCCLoop.size() - 1) ;
|
|
}
|
|
}
|
|
else if ( bDoneB )
|
|
m_vCCLoop[nIndex3].Set( pCC3b) ;
|
|
}
|
|
|
|
// per togliere la parte comune al loop corrente devo riportare i punti di intersezione sull'edge di partenza
|
|
Point3d ptOverlapS = iccInfo.IciB[0].ptI ;
|
|
Point3d ptOverlapE = iccInfo.IciB[1].ptI ;
|
|
ptOverlapS.x = 0 ;
|
|
ptOverlapE.x = 0 ;
|
|
double dStart1, dEnd1 ;
|
|
// scorro tutte le curve in cui è stato splittato il loop iniziale
|
|
for ( int j = 0 ; j < int( mSplitLoop[vInters1.first].size()) ; ++j ) {
|
|
int nIndex1 = mSplitLoop[vInters1.first][j] ;
|
|
if ( ! m_vCCLoop[nIndex1]->GetParamAtPoint( ptOverlapS, dStart1) || ! m_vCCLoop[nIndex1]->GetParamAtPoint( ptOverlapE, dEnd1))
|
|
continue ;
|
|
// se parto da una curva chiusa semplicemente tolgo un pezzo
|
|
if ( m_vCCLoop[nIndex1]->IsClosed()) {
|
|
ICurveComposite* pCC1( GetCurveComposite( m_vCCLoop[nIndex1]->CopyParamRange( dStart1, dEnd1))) ;
|
|
m_vCCLoop[nIndex1].Set( pCC1) ;
|
|
}
|
|
else {
|
|
// se la curva era già aperta allora otterrò due curve separate
|
|
ICurveComposite* pCC1a( GetCurveComposite( m_vCCLoop[nIndex1]->Clone())) ;
|
|
bool bDoneA = pCC1a->TrimEndAtParam( dEnd1) ;
|
|
ICurveComposite* pCC1b( GetCurveComposite( m_vCCLoop[nIndex1]->Clone())) ;
|
|
bool bDoneB = pCC1b->TrimStartAtParam( dStart1) ;
|
|
if ( bDoneA) {
|
|
m_vCCLoop[nIndex1].Set( pCC1a) ;
|
|
if ( bDoneB) {
|
|
m_vCCLoop.emplace_back( pCC1b) ;
|
|
mSplitLoop[vInters1.first].push_back( m_vCCLoop.size() - 1) ;
|
|
}
|
|
}
|
|
else if ( bDoneB)
|
|
m_vCCLoop[nIndex1].Set( pCC1b) ;
|
|
}
|
|
//break ;
|
|
}
|
|
//break ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// qui portei estrarre una funzione che proietta curve dal parametrico al 3D
|
|
// scorro i gruppi di loop 2D formati da loop che partecipano alla formazione dello stesso loop nel 3D
|
|
ICRVCOMPOPOVECTOR vpCCOpen ;
|
|
for ( int i = 0 ; i < int( m_vCCLoop.size()); ++i) {
|
|
vpCCOpen.emplace_back(CreateBasicCurveComposite()) ;
|
|
PolyLine pl3D ;
|
|
// la composita è una spezzata composta da linee, quindi la ricostruisco come polyline in 3D
|
|
Point3d pt ; m_vCCLoop[i]->GetStartPoint( pt) ;
|
|
Point3d pt3D ; GetPointD1D2( pt.x / SBZ_TREG_COEFF, pt.y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt3D) ;
|
|
int nCount = 0 ;
|
|
pl3D.AddUPoint( nCount, pt3D) ;
|
|
++ nCount ;
|
|
// scorro le curve singole della composita
|
|
for ( int k = 0 ; k < m_vCCLoop[i]->GetCurveCount() ; ++k){
|
|
// recupero l'end point della curva e lo porto in 3D
|
|
m_vCCLoop[i]->GetCurve( k)->GetEndPoint( pt) ;
|
|
GetPointD1D2( pt.x / SBZ_TREG_COEFF, pt.y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt3D) ;
|
|
pl3D.AddUPoint( nCount, pt3D) ;
|
|
++ nCount ;
|
|
}
|
|
vpCCOpen.back()->FromPolyLine(pl3D) ;
|
|
}
|
|
// creo la chain a mano con le compo
|
|
BOOLVECTOR vbAdded( vpCCOpen.size()) ;
|
|
fill( vbAdded.begin(), vbAdded.end(), false) ;
|
|
for ( int k = 0 ; k < int( vpCCOpen.size()); ++k ) {
|
|
if ( vbAdded[k])
|
|
continue ;
|
|
PtrOwner<ICurveComposite> pCC( vpCCOpen[k]->Clone()) ;
|
|
vbAdded[k] = true ;
|
|
bool bAddedOne = true ;
|
|
while ( bAddedOne) {
|
|
bAddedOne = false ;
|
|
for ( int t = k ; t < int(vpCCOpen.size()); ++t ) {
|
|
if ( vbAdded[t])
|
|
continue ;
|
|
if ( pCC->AddCurve( vpCCOpen[t]->Clone())) {
|
|
vbAdded[t] = true ;
|
|
bAddedOne = true ;
|
|
}
|
|
}
|
|
}
|
|
// aggiungo la curva agli edge 3d da restituire
|
|
vCC.emplace_back( Release( pCC)) ;
|
|
}
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
ICurveComposite*
|
|
SurfBezier::GetSingleEdge3D( bool bLineOrBezier, int nEdge) const
|
|
{
|
|
// nEdge indica l'edge da restituire
|
|
// gli edge sono numerati a pratire dal bordo superiore dello spazio parametrico: 0 - Top, 1 - Left, 2 - Bottom, 3 - Right
|
|
if ( m_mCCEdge.empty() && bLineOrBezier)
|
|
GetAuxSurfRefined() ;
|
|
// questa funzione dà per scontato che la superficie NON sia trimmata
|
|
if ( nEdge < 0 || nEdge > 3 || m_bTrimmed)
|
|
return nullptr ;
|
|
ICurveComposite* pCrvCompo( CreateBasicCurveComposite()) ;
|
|
switch ( nEdge) {
|
|
case 0 : {
|
|
// se il bool è true allora restituisco gli edge con la loro approssimazione in forma di linea spezzata 3D
|
|
if ( bLineOrBezier)
|
|
pCrvCompo = m_mCCEdge[nEdge][0]->Clone() ;
|
|
// se il bool è falso restituisco le curve Bezier di edge
|
|
else {
|
|
//edge 0, scorro sulle patch in U
|
|
for ( int i = 0 ; i < m_nSpanU ; ++i) {
|
|
PtrOwner<ICurveBezier> pCrvBz0( CreateBasicCurveBezier()) ;
|
|
if ( IsNull(pCrvBz0) || ! pCrvBz0->Init( m_nDegU, m_bRat))
|
|
return nullptr ;
|
|
for ( int p = 0 ; p < m_nDegU + 1 ; ++p ) {
|
|
int nIndex = ( m_nDegU * m_nSpanU + 1) * ( m_nDegV * m_nSpanV) + m_nDegU * i + p ;
|
|
if ( ! m_bRat)
|
|
pCrvBz0->SetControlPoint( p, GetControlPoint( nIndex, nullptr)) ;
|
|
else
|
|
pCrvBz0->SetControlPoint( p, GetControlPoint( nIndex, nullptr), GetControlWeight( nIndex, nullptr)) ;
|
|
}
|
|
pCrvCompo->AddCurve( Release( pCrvBz0)) ;
|
|
}
|
|
pCrvCompo->Invert() ;
|
|
}
|
|
break ;
|
|
}
|
|
case 1 : {
|
|
if ( bLineOrBezier)
|
|
pCrvCompo = m_mCCEdge[nEdge][0]->Clone() ;
|
|
else {
|
|
//edge 1, scorro sulle patch in V
|
|
for ( int i = 0 ; i < m_nSpanV ; ++i) {
|
|
PtrOwner<ICurveBezier> pCrvBz1( CreateBasicCurveBezier()) ;
|
|
if ( IsNull(pCrvBz1) || ! pCrvBz1->Init( m_nDegV, m_bRat))
|
|
return nullptr ;
|
|
for ( int p = 0 ; p < m_nDegU + 1 ; ++p ) {
|
|
int nIndex = ( m_nDegU * m_nSpanU + 1) * p ;
|
|
if ( ! m_bRat)
|
|
pCrvBz1->SetControlPoint( p, GetControlPoint( nIndex, nullptr)) ;
|
|
else
|
|
pCrvBz1->SetControlPoint( p, GetControlPoint( nIndex, nullptr), GetControlWeight( nIndex, nullptr)) ;
|
|
}
|
|
pCrvCompo->AddCurve( Release( pCrvBz1)) ;
|
|
}
|
|
pCrvCompo->Invert() ;
|
|
}
|
|
break ;
|
|
}
|
|
case 2 : {
|
|
if ( bLineOrBezier)
|
|
pCrvCompo = m_mCCEdge[nEdge][0]->Clone() ;
|
|
else {
|
|
// edge 2, scorro sulle patch in U
|
|
for ( int i = 0 ; i < m_nSpanU ; ++i) {
|
|
PtrOwner<ICurveBezier> pCrvBz2( CreateBasicCurveBezier()) ;
|
|
if ( IsNull(pCrvBz2) || ! pCrvBz2->Init( m_nDegU, m_bRat))
|
|
return nullptr ;
|
|
for ( int p = 0 ; p < m_nDegU + 1 ; ++p ) {
|
|
if ( ! m_bRat)
|
|
pCrvBz2->SetControlPoint( p, GetControlPoint(m_nDegU * i + p, nullptr)) ;
|
|
else
|
|
pCrvBz2->SetControlPoint( p, GetControlPoint(m_nDegU * i + p, nullptr), GetControlWeight(m_nDegU * i + p, nullptr)) ;
|
|
}
|
|
pCrvCompo->AddCurve( Release( pCrvBz2)) ;
|
|
}
|
|
}
|
|
break ;
|
|
}
|
|
case 3 : {
|
|
if ( bLineOrBezier)
|
|
pCrvCompo = m_mCCEdge[nEdge][0]->Clone() ;
|
|
else {
|
|
// edge 3, scorro sulle patch in V
|
|
for ( int i = 0 ; i < m_nSpanV ; ++i) {
|
|
PtrOwner<ICurveBezier> pCrvBz3( CreateBasicCurveBezier()) ;
|
|
if ( IsNull(pCrvBz3) || ! pCrvBz3->Init( m_nDegV, m_bRat))
|
|
return nullptr ;
|
|
for ( int p = 0 ; p < m_nDegV + 1 ; ++p ) {
|
|
int nIndex = ( m_nDegU * m_nSpanU + 1) * ( i + p + 1) - 1 ;
|
|
if ( ! m_bRat)
|
|
pCrvBz3->SetControlPoint( p, GetControlPoint( nIndex, nullptr)) ;
|
|
else
|
|
pCrvBz3->SetControlPoint( p, GetControlPoint( nIndex, nullptr), GetControlWeight( nIndex, nullptr)) ;
|
|
}
|
|
pCrvCompo->AddCurve( Release( pCrvBz3)) ;
|
|
}
|
|
}
|
|
break ;
|
|
}
|
|
}
|
|
return pCrvCompo ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::IsPlanar( void) const
|
|
{
|
|
if ( m_nIsPlanar != NOT_CALCULATED) {
|
|
switch ( m_nIsPlanar ) {
|
|
case PLANAR_SURF : return true ; break ;
|
|
case NOT_PLANAR_SURF : return false ; break ;
|
|
}
|
|
}
|
|
|
|
PolyLine plApprox ;
|
|
Plane3d plPlane ;
|
|
if ( ! m_bTrimmed) {
|
|
// costruisco il contorno della superficie unendo gli edge e chiedo se la polyline è piana.
|
|
PtrOwner<ICurveComposite> pCCEdge( GetSingleEdge3D( false, 0)) ;
|
|
pCCEdge->AddCurve( GetSingleEdge3D( false, 1)) ;
|
|
pCCEdge->AddCurve( GetSingleEdge3D( false, 2)) ;
|
|
pCCEdge->AddCurve( GetSingleEdge3D( false, 3)) ;
|
|
pCCEdge->ApproxWithLines( 0.01, 15, 0, plApprox) ;
|
|
if ( ! plApprox.IsFlat( plPlane, 2 * EPS_SMALL)){
|
|
m_nIsPlanar = 0 ;
|
|
return false ;
|
|
}
|
|
// in questo caso se è grado 1 in U e V e ho un unica Patch allora sono sicuro sia piana
|
|
if ( m_nDegU == 1 && m_nSpanU == 1 && m_nDegV == 1 && m_nSpanV == 1) {
|
|
m_nIsPlanar = 1 ;
|
|
return true ;
|
|
}
|
|
}
|
|
else {
|
|
Point3d ptCtrl ;
|
|
bool bOk = true ;
|
|
plApprox.AddUPoint( 0, GetControlPoint(0, &bOk)) ;
|
|
plApprox.AddUPoint( 1, GetControlPoint(m_nDegU * m_nSpanU, &bOk)) ;
|
|
plApprox.AddUPoint( 2, GetControlPoint(( m_nDegU * m_nSpanU + 1) * ( m_nDegV * m_nSpanV + 1), &bOk)) ;
|
|
plApprox.AddUPoint( 3, GetControlPoint(( m_nDegU * m_nSpanU + 1) * ( m_nDegV * m_nSpanV), &bOk)) ;
|
|
}
|
|
|
|
double dULast ; plApprox.GetLastU( dULast) ;
|
|
++ dULast ;
|
|
// altrimenti devo verificare anche all'interno della superficie, prendendo dei punti campione
|
|
DBLVECTOR vSampling { 0.2, 0.4, 0.6, 0.8} ;
|
|
for ( double i : vSampling) {
|
|
for ( double j : vSampling) {
|
|
Point3d ptBez ;
|
|
GetPointD1D2( i * m_nSpanU, j * m_nSpanV, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBez) ;
|
|
if ( plApprox.AddUPoint( dULast, ptBez))
|
|
++ dULast ;
|
|
}
|
|
}
|
|
plPlane.Reset() ;
|
|
if ( plApprox.IsFlat( plPlane, 2 * EPS_SMALL)) {
|
|
m_nIsPlanar = 1 ;
|
|
return true ;
|
|
}
|
|
|
|
// nel dubbio restituisco false
|
|
m_nIsPlanar = 0 ;
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::CreateByFlatContour( const PolyLine& PL)
|
|
{
|
|
Plane3d plPlane ;
|
|
double dArea = 0 ;
|
|
if ( ! PL.IsClosedAndFlat( plPlane, dArea, EPS_SMALL))
|
|
return false ;
|
|
// porto la polyline nel frame del suo piano per trovare gli estremi della sua box in quel piano
|
|
Frame3d frContour ;
|
|
frContour.Set( plPlane.GetPoint(), plPlane.GetVersN()) ;
|
|
PolyLine plFlat = PL ;
|
|
plFlat.ToLoc( frContour) ;
|
|
// creo una superficie piana grande come il box della curva nel suo piano e poi la trimmo
|
|
// recupero il box
|
|
BBox3d bboxContour ;
|
|
plFlat.GetLocalBBox( bboxContour) ;
|
|
// inizializzo la superficie come una bezier di primo grado formata da una sola patch
|
|
int nDegU = 1, nDegV = 1, nSpanU = 1, nSpanV = 1 ;
|
|
bool bRat = false ;
|
|
Init( nDegU, nDegV, nSpanU, nSpanV, bRat) ;
|
|
// i punti di controllo sono i quattro vertici della bbox proiettata sul piano della polyline
|
|
double dPlus = 1 ;
|
|
bboxContour.Expand( dPlus, dPlus, 0) ;
|
|
Point3d ptBL = bboxContour.GetMin() ;
|
|
Point3d ptTR = bboxContour.GetMax() ;
|
|
Point3d ptTl = Point3d( ptBL.x, ptTR.y) ;
|
|
Point3d ptBr = Point3d( ptTR.x, ptBL.y) ;
|
|
ptBL.ToGlob( frContour) ;
|
|
ptTR.ToGlob( frContour) ;
|
|
ptTl.ToGlob( frContour) ;
|
|
ptBr.ToGlob( frContour) ;
|
|
SetControlPoint( 0, ptBL) ;
|
|
SetControlPoint( 1, ptBr) ;
|
|
SetControlPoint( 2, ptTl) ;
|
|
SetControlPoint( 3, ptTR) ;
|
|
//// calcolo il corrispondente parametrico del contorno
|
|
PtrOwner<ICurveComposite> pCCContour( CreateCurveComposite()) ;
|
|
if ( IsNull( pCCContour) || ! pCCContour->FromPolyLine( PL) || ! pCCContour->IsValid())
|
|
return false ;
|
|
|
|
// calcolo gli eventuali poli, necessari per poter chiamare le funzioni di unproject
|
|
CalcPoles() ;
|
|
ICRVCOMPOPOVECTOR vCCOpen ;
|
|
ICRVCOMPOPOVECTOR vCCClosed ;
|
|
AddCurveCompoToCuts( pCCContour, vCCOpen, vCCClosed) ;
|
|
// creo la regione di trim dai loop di trim
|
|
PtrOwner<ISurfFlatRegion> pSfrTrim( CreateTrimRegionFromCuts( vCCOpen, vCCClosed)) ;
|
|
if ( IsNull( pSfrTrim) || ! pSfrTrim->IsValid())
|
|
return false ;
|
|
SetTrimRegion( *pSfrTrim) ;
|
|
|
|
// aggiorno lo stato
|
|
m_nStatus = OK ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::CreateByRegion( const POLYLINEVECTOR& vPL)
|
|
{
|
|
// la regione passata è riferita al parametrico di una superficie quadrata.
|
|
// La superficie viene creata come se fosse una flatregion a partire dai loop passati.
|
|
|
|
// le polyline in input devono essere già ordinate per area e orientate con il verso giusto ( tenendo conto di chunk e isole)
|
|
// la prima polyline quindi è il loop esterno del chunk più grande
|
|
Plane3d plPlane ;
|
|
double dArea = 0 ;
|
|
if ( ! vPL[0].IsClosedAndFlat(plPlane, dArea, EPS_SMALL) )
|
|
return false ;
|
|
// porto la polyline nel frame del suo piano per trovare gli estremi della sua box in quel piano
|
|
Frame3d frContour ;
|
|
frContour.Set( plPlane.GetPoint(), plPlane.GetVersN()) ;
|
|
// creo una superficie piana grande come il box della curva nel suo piano e poi la trimmo
|
|
POLYLINEVECTOR vPLFlat = vPL ;
|
|
BBox3d bboxContour ;
|
|
for ( int i = 0 ; i < int( vPLFlat.size()) ; ++i) {
|
|
// porto le polilinee nel riferimento del loro piano e ne recupero il box
|
|
vPLFlat[i].ToLoc(frContour) ;
|
|
BBox3d bboxLoop ;
|
|
vPLFlat[i].GetLocalBBox(bboxLoop) ;
|
|
bboxContour.Add( bboxLoop) ;
|
|
}
|
|
|
|
// inizializzo la superficie come una bezier di primo grado formata da una sola patch
|
|
int nDegU = 1, nDegV = 1, nSpanU = 1, nSpanV = 1 ;
|
|
bool bRat = false ;
|
|
Init( nDegU, nDegV, nSpanU, nSpanV, bRat) ;
|
|
// i punti di controllo sono i quattro vertici della bbox ( che è piana)
|
|
double dPlus = 1 ;
|
|
bboxContour.Expand( dPlus, dPlus, 0) ;
|
|
Point3d ptBL = bboxContour.GetMin() ;
|
|
Point3d ptTR = bboxContour.GetMax() ;
|
|
Point3d ptTl = Point3d( ptBL.x, ptTR.y) ;
|
|
Point3d ptBr = Point3d( ptTR.x, ptBL.y) ;
|
|
ptBL.ToGlob( frContour) ;
|
|
ptTR.ToGlob( frContour) ;
|
|
ptTl.ToGlob( frContour) ;
|
|
ptBr.ToGlob( frContour) ;
|
|
SetControlPoint( 0, ptBL) ;
|
|
SetControlPoint( 1, ptBr) ;
|
|
SetControlPoint( 2, ptTl) ;
|
|
SetControlPoint( 3, ptTR) ;
|
|
// creo i vettori dei tagli aperti e chiusi
|
|
CalcPoles() ;
|
|
ICRVCOMPOPOVECTOR vCCOpen ;
|
|
ICRVCOMPOPOVECTOR vCCClosed ;
|
|
for ( int i = 0 ; i < int( vPL.size()) ; ++i) {
|
|
ICurveComposite* pCC( CreateBasicCurveComposite()) ;
|
|
if ( pCC == nullptr || ! pCC->FromPolyLine( vPL[i]) || ! pCC->IsValid())
|
|
return false ;
|
|
if ( ! AddCurveCompoToCuts( pCC, vCCOpen, vCCClosed))
|
|
return false ; // o metto un continue?
|
|
}
|
|
// unisco i tagli e creo la regione di trim
|
|
PtrOwner<ISurfFlatRegion> pSfrTrim( CreateTrimRegionFromCuts( vCCOpen, vCCClosed)) ;
|
|
if ( IsNull( pSfrTrim) || ! pSfrTrim->IsValid())
|
|
return false ;
|
|
SetTrimRegion( *pSfrTrim) ;
|
|
|
|
//if ( plPlane.GetVersN().z < EPS_SMALL)
|
|
// Invert() ;
|
|
|
|
// aggiorno lo stato
|
|
m_nStatus = OK ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::CreateByExtrusion( const ICurve* pCrv, const Vector3d& vtExtr)
|
|
{
|
|
if ( pCrv == nullptr)
|
|
return false ;
|
|
|
|
CurveComposite CC ;
|
|
// se composita verifico che curve siano con lo stesso grado e uniformi come tipo
|
|
bool bRat = false ;
|
|
int nDegU = 3 ;
|
|
if ( pCrv->GetType() != CRV_COMPO) {
|
|
CC.AddCurve( CurveToBezierCurve( pCrv, nDegU, bRat)) ;
|
|
}
|
|
else {
|
|
const ICurveComposite* pCCOrig = GetCurveComposite( pCrv) ;
|
|
for ( int i = 0 ; i < pCCOrig->GetCurveCount() ; ++i) {
|
|
if ( pCCOrig->GetCurve( i)->GetType() != CRV_BEZIER)
|
|
CC.AddCurve( CurveToBezierCurve( pCCOrig->GetCurve(i), nDegU, bRat)) ;
|
|
else
|
|
CC.AddCurve( EditBezierCurve( GetCurveBezier( pCCOrig->GetCurve(i)), nDegU, bRat)) ;
|
|
}
|
|
}
|
|
|
|
if ( CC.GetCurveCount() == 0 || ! CC.IsValid())
|
|
return false ;
|
|
|
|
// riempio la matrice dei punti di controllo
|
|
// parto dalla curva che sto estrudendo e mi alzo progressivamente seguendo il vettore vtExtr
|
|
int nDegV = 1 ;
|
|
int nSpanU = CC.GetCurveCount() ;
|
|
int nSpanV = 1 ;
|
|
Init( nDegU, nDegV, nSpanU, nSpanV, bRat) ;
|
|
|
|
for ( int k = 0 ; k < nSpanU ; ++k) {
|
|
const ICurveBezier* pCrvBezier = GetCurveBezier( CC.GetCurve( k)) ;
|
|
for ( int i = 0 ; i < nDegU + 1 ; ++i) {
|
|
if ( k != 0 && i == 0)
|
|
continue ;
|
|
Point3d ptCtrl = pCrvBezier->GetControlPoint( i) ;
|
|
|
|
int nInd = k * nDegU + i ;
|
|
if ( bRat) {
|
|
double dW = pCrvBezier->GetControlWeight( i) ;
|
|
SetControlPoint( nInd, ptCtrl, dW) ;
|
|
}
|
|
else
|
|
SetControlPoint( nInd, ptCtrl) ;
|
|
}
|
|
}
|
|
|
|
Vector3d vtStep = vtExtr / nDegV ;
|
|
// calcolo il vettore di progressione del singolo step per passare dalla curva di partenza alla curva finale
|
|
for ( int j = 1 ; j < nDegV + 1 ; ++j) {
|
|
for ( int k = 0 ; k < nSpanU ; ++k) {
|
|
for ( int i = 0 ; i < nDegU + 1 ; ++i) {
|
|
int nIndPrev = ( j - 1) * ( nDegU * nSpanU + 1) + ( k * nDegU + i) ;
|
|
Point3d ptCtrl = GetControlPoint( nIndPrev, nullptr) ;
|
|
ptCtrl += vtStep ;
|
|
int nInd = j * ( nDegU * nSpanU + 1) + k * nDegU + i ;
|
|
if ( bRat) {
|
|
double dW = GetControlWeight( i, nullptr) ;
|
|
SetControlPoint( nInd, ptCtrl, dW) ;
|
|
}
|
|
else
|
|
SetControlPoint( nInd, ptCtrl) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// aggiorno lo stato
|
|
m_nStatus = OK ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::CreateByScrewing( const ICurve* pCurve, const Point3d& ptAx, const Vector3d& vtAx, double dAngRotDeg, double dMove)
|
|
{
|
|
// verifico validità curva
|
|
if ( pCurve == nullptr || ! pCurve->IsValid())
|
|
return false ;
|
|
// verifico che l'asse di rotazione sia non nullo
|
|
if ( vtAx.IsSmall())
|
|
return false ;
|
|
// verifico che l'angolo di rotazione sia significativo
|
|
if ( abs( dAngRotDeg) < EPS_ANG_SMALL)
|
|
return false ;
|
|
// verifico se solo rivoluzione
|
|
bool bOnlyRev = ( abs( dMove) < EPS_SMALL) ;
|
|
// se solo rivoluzione, limito la rotazione entro un giro
|
|
if ( bOnlyRev && abs( dAngRotDeg) > ANG_FULL)
|
|
dAngRotDeg = _copysign( ANG_FULL, dAngRotDeg) ;
|
|
|
|
// se sto facendo una rivoluzione e la curva è piana, controllo che la curva non attraversi l'asse
|
|
if ( abs( dMove) < EPS_SMALL ) {
|
|
Plane3d plPlane ;
|
|
if ( pCurve->IsFlat( plPlane, false, 10 * EPS_SMALL)) {
|
|
BBox3d b3Crv ;
|
|
pCurve->GetLocalBBox( b3Crv) ;
|
|
double dAxLen = b3Crv.MaxDistFromPoint( ptAx) ;
|
|
CurveLine crvAx ;
|
|
crvAx.Set( ptAx - dAxLen * vtAx, ptAx + dAxLen * vtAx) ;
|
|
IntersCurveCurve icc( *pCurve, crvAx) ;
|
|
Point3d ptStart ; pCurve->GetStartPoint( ptStart) ;
|
|
Point3d ptEnd ; pCurve->GetEndPoint( ptEnd) ;
|
|
for ( int i = 0 ; i < icc.GetIntersCount() ; ++i) {
|
|
IntCrvCrvInfo iccInfo ;
|
|
icc.GetIntCrvCrvInfo( i, iccInfo) ;
|
|
// controllo che sia una vera intersezione in 3D, altrimenti passo alla successiva
|
|
if ( ! AreSamePointApprox( iccInfo.IciA[0].ptI, iccInfo.IciB[0].ptI))
|
|
continue ;
|
|
// se è il punto di inizio o di fine va bene e procedo
|
|
if ( AreSamePointApprox( ptStart, iccInfo.IciA[0].ptI) || AreSamePointApprox( ptEnd, iccInfo.IciA[0].ptI))
|
|
continue ;
|
|
// se la curva oltrepassa l'asse allora mi fermo, se tocca l'asse, ma resta dallo stesso lato, allora vado avanti
|
|
if ( iccInfo.IciA->nPrevTy != iccInfo.IciA->nNextTy)
|
|
return false ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// converto in bezier la curva iniziale
|
|
CurveComposite CrvU ;
|
|
// se la curva è già una bezier singola la tengo, sennò la converto
|
|
if ( pCurve->GetType() != CRV_BEZIER)
|
|
CrvU.AddCurve( CurveToBezierCurve( pCurve, 3, true)) ;
|
|
else {
|
|
if ( GetCurveBezier(pCurve)->IsRational())
|
|
CrvU.AddCurve( pCurve->Clone()) ;
|
|
else {
|
|
ICurveBezier* pCrvCopy = GetCurveBezier( pCurve->Clone()) ;
|
|
pCrvCopy->MakeRational() ;
|
|
CrvU.AddCurve( pCrvCopy) ;
|
|
}
|
|
}
|
|
if ( ! CrvU.IsValid())
|
|
return false ;
|
|
int nSpanU = int( CrvU.GetCurveCount()) ;
|
|
int nDegU = ( GetCurveBezier( CrvU.GetCurve(0)))->GetDegree() ;
|
|
|
|
// creo la spirale su cui fare la rail della curva ( in questo caso sarà la curva di bezier che delimita il bordo sinistro dello spazio parametrico tra il punto P00 e il punto P01)
|
|
CurveComposite CrvVSpiral ;
|
|
// devo trovare un punto che NON stia sull'asse per poter costruire una spirale e sapere quante span in V avrò
|
|
DBLVECTOR vdSpiralW ;
|
|
bool bFound = false ;
|
|
for ( int j = 0 ; j < nSpanU && ! bFound ; ++j) {
|
|
const ICurveBezier* pSubCrvBezU = GetCurveBezier( CrvU.GetCurve( j)) ;
|
|
for ( int i = 0 ; i < nDegU + 1 && ! bFound ; ++i) {
|
|
Point3d ptCtrlU = pSubCrvBezU->GetControlPoint( i) ;
|
|
DistPointLine dpl( ptCtrlU, ptAx, vtAx, 1, false) ;
|
|
if ( ! dpl.IsSmall()) {
|
|
CurveArc crvSpiral ;
|
|
crvSpiral.SetCPAN( ptAx, ptCtrlU, dAngRotDeg, dMove, vtAx) ;
|
|
// converto in bezier la spirale
|
|
CrvVSpiral.AddCurve( ArcToBezierCurve( &crvSpiral, 3 , true)) ;
|
|
const ICurveBezier* pFirstBez = GetCurveBezier( CrvVSpiral.GetCurve( 0)) ;
|
|
int nDeg = pFirstBez->GetDegree() ;
|
|
for ( int k = 0 ; k < nDeg + 1 ; ++k)
|
|
vdSpiralW.push_back( pFirstBez->GetControlWeight( k)) ;
|
|
bFound = true ;
|
|
}
|
|
}
|
|
}
|
|
if ( ! bFound)
|
|
return false ;
|
|
|
|
if ( ! CrvVSpiral.IsValid())
|
|
return false ;
|
|
int nSpanV = CrvVSpiral.GetCurveCount() ;
|
|
int nDegV = GetCurveBezier( CrvVSpiral.GetCurve(0))->GetDegree() ;
|
|
// inizializzo la superficie (deve essere razionale)
|
|
bool bRat = true ;
|
|
Init( nDegU, nDegV, nSpanU, nSpanV, bRat) ;
|
|
|
|
// per ogni punto di controllo della curva di base creo la spirale che rappresenta la screw di quel punto
|
|
// scorro le sottocurve della curva di base
|
|
for ( int k = 0 ; k < nSpanU ; ++k ) {
|
|
const ICurveBezier* pSubCrvBezU = GetCurveBezier( CrvU.GetCurve( k)) ;
|
|
// scorro i punti di controllo
|
|
for ( int i = 0 ; i < nDegU + 1 ; ++i) {
|
|
if ( k != 0 && i == 0)
|
|
continue ;
|
|
Point3d ptCtrlU = pSubCrvBezU->GetControlPoint( i) ;
|
|
double dWU = pSubCrvBezU->GetControlWeight( i) ;
|
|
|
|
CurveComposite CrvV ;
|
|
// verifico se il punto di controllo sta sull'asse
|
|
// in tal caso anziché una spirale creo semplicemente una linea lungo l'asse
|
|
DistPointLine dpl( ptCtrlU, ptAx, vtAx, 1, false) ;
|
|
if ( ! dpl.IsSmall()) {
|
|
// creo la spirale e la converto in bezier
|
|
CurveArc CrvSpiral ;
|
|
CrvSpiral.SetCPAN( ptAx, ptCtrlU, dAngRotDeg, dMove, vtAx) ;
|
|
ICurve* pSpiralBezier( ArcToBezierCurve( &CrvSpiral)) ; // converto in curva bezier di grado 3 perché l'arco è una spirale
|
|
CrvV.AddCurve( pSpiralBezier) ;
|
|
}
|
|
else if ( abs( dMove) > EPS_SMALL){
|
|
// creo un segmento in forma bezier con il giusto numero di span
|
|
CurveLine CL ;
|
|
CL.Set( ptCtrlU, ptCtrlU + vtAx * dMove) ;
|
|
double dStep = 1. / nSpanV ;
|
|
for ( int j = 0 ; j < nSpanV ; ++j) {
|
|
PtrOwner<ICurveLine> pCLSingleSpan( GetCurveLine( CL.CopyParamRange( j * dStep, ( j + 1) * dStep))) ;
|
|
PtrOwner<ICurveBezier> pCrvBezForm( LineToBezierCurve( pCLSingleSpan, 3, true)) ;
|
|
// prima di aggiungere le curve alla composito setto i pesi
|
|
for ( int z = 0 ; z < pCrvBezForm->GetDegree() + 1 ; ++z)
|
|
pCrvBezForm->SetControlWeight( z, vdSpiralW[z]) ;
|
|
CrvV.AddCurve( Release( pCrvBezForm)) ;
|
|
}
|
|
}
|
|
// se sto facendo una rivoluzione ( dMove == 0) e ho un punto di controllo sull'asse allora ho un polo
|
|
// devo aggiungere sempre lo stesso punto per tutta la riga della matrice dei punti di controllo, con i pesi giusti
|
|
else {
|
|
CurveBezier CrvBezier ;
|
|
CrvBezier.Init( nDegV, bRat) ;
|
|
for ( int z = 0 ; z < nDegV + 1 ; ++z) {
|
|
CrvBezier.SetControlPoint( z, ptCtrlU, vdSpiralW[z]) ;
|
|
}
|
|
for ( int j = 0 ; j < nSpanV ; ++j)
|
|
CrvV.AddCurve( CrvBezier.Clone()) ;
|
|
}
|
|
|
|
if ( ! CrvV.IsValid())
|
|
return false ;
|
|
|
|
// aggiungo i punti di controllo
|
|
// scorro le sottocurve della spirale
|
|
for ( int j = 0 ; j < nSpanV ; ++j) {
|
|
const ICurveBezier* pSubCrvBezV = GetCurveBezier( CrvV.GetCurve( j)) ;
|
|
// scorro i punti di controllo
|
|
for ( int z = 0 ; z < nDegV + 1 ; ++z) {
|
|
double dWV = pSubCrvBezV->GetControlWeight( z) ;
|
|
Point3d ptCtrlV = pSubCrvBezV->GetControlPoint( z) ;
|
|
SetControlPoint( nDegU * k + i, nDegV * j + z, ptCtrlV, dWU * dWV) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::CreateByPointCurve( const Point3d& pt, const ICurve* pCurve)
|
|
{
|
|
// converto in bezier la curva iniziale
|
|
CurveComposite CrvU ;
|
|
// se la curva è già una bezier singola la tengo, sennò la converto
|
|
if ( pCurve->GetType() != CRV_BEZIER)
|
|
CrvU.AddCurve( CurveToBezierCurve( pCurve)) ;
|
|
else
|
|
CrvU.AddCurve( pCurve->Clone()) ;
|
|
if ( ! CrvU.IsValid())
|
|
return false ;
|
|
// recupero span e grado nel parametro U
|
|
int nSpanU = int( CrvU.GetCurveCount()) ;
|
|
int nDegU = GetCurveBezier( CrvU.GetCurve(0))->GetDegree() ;
|
|
bool bRat = GetCurveBezier( CrvU.GetCurve(0))->IsRational() ;
|
|
// in V decido che la funzione è una patch di grado 1
|
|
int nSpanV = 1 ;
|
|
int nDegV = 1 ;
|
|
// inizializzo la curva e aggiungo i punti di controllo
|
|
Init( nDegU, nDegV, nSpanU, nSpanV, bRat) ;
|
|
// scorro le patch nel parametro U
|
|
for ( int k = 0 ; k < nSpanU ; ++k) {
|
|
const ICurveBezier* pSubCrvU = GetCurveBezier( CrvU.GetCurve( k)) ;
|
|
// scorro i punti di controllo in U
|
|
for ( int i = 0 ; i < nDegU + 1 ; ++i ) {
|
|
|
|
double dW = pSubCrvU->GetControlWeight( i) ;
|
|
Point3d ptCtrl = i == 0 ? pSubCrvU->GetControlPoint( i) : pt ;
|
|
// scorro sul parametro V // do per scontato di avere una patch di grado 1 ( quindi nel parametro V ho solo due punti)
|
|
for ( int j = 0 ; j < nDegV + 1 ; ++j) {
|
|
if ( ! bRat)
|
|
SetControlPoint( nDegU * k + i, j, ptCtrl) ;
|
|
else
|
|
SetControlPoint( nDegU * k + i, j , ptCtrl, dW) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
static bool
|
|
ChangeStartForClosed( PolyLine& plU0, PolyLine& plU1, ICurveComposite* pCrvU0, ICurveComposite* pCrvU1) {
|
|
// se sono chiuse devo controllare che gli start siano il più allineati possibile, se non lo sono cambio gli start
|
|
if ( plU0.IsClosed() && plU1.IsClosed()) {
|
|
vector<tuple<double,int,Point3d,int,Point3d>> vDistVert ;
|
|
tuple<double,int,Point3d,int,Point3d> tMatch ;
|
|
Point3d pt0 ;
|
|
bool bOk0 = plU0.GetFirstPoint( pt0) ;
|
|
int c0 = 0 ;
|
|
double dMinDist = INFINITO ;
|
|
while ( bOk0) {
|
|
Point3d pt1 ;
|
|
bool bOk1 = plU1.GetFirstPoint( pt1) ;
|
|
int c1 = 0 ;
|
|
while ( bOk1) {
|
|
double dDist = Dist( pt0, pt1) ;
|
|
if ( dDist < dMinDist) {
|
|
tMatch = make_tuple( dDist, c0, pt0, c1, pt1) ;
|
|
dMinDist = dDist ;
|
|
}
|
|
++c1 ;
|
|
bOk1 = plU1.GetNextPoint( pt1) ;
|
|
}
|
|
vDistVert.push_back( tMatch) ;
|
|
dMinDist = INFINITO ;
|
|
c1 = 0 ;
|
|
++c0 ;
|
|
bOk0 = plU0.GetNextPoint( pt0) ;
|
|
}
|
|
int nMin = 0 ;
|
|
dMinDist = INFINITO ;
|
|
for ( int i = 0 ; i < int( vDistVert.size()) ; ++i) {
|
|
if ( get<0>(vDistVert[i]) < dMinDist) {
|
|
dMinDist = get<0>(vDistVert[i]) ;
|
|
nMin = i ;
|
|
}
|
|
}
|
|
ChangePolyLineStart(plU0, get<2>(vDistVert[nMin]), EPS_SMALL) ;
|
|
ChangePolyLineStart(plU1, get<4>(vDistVert[nMin]), EPS_SMALL) ;
|
|
pCrvU0->ChangeStartPoint( double( get<1>(vDistVert[nMin]))) ;
|
|
pCrvU1->ChangeStartPoint( double( get<3>(vDistVert[nMin]))) ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
static bool
|
|
GetEdgeSplitByAngTol( const PolyLine& PL, double dAngTol, INTVECTOR& vEdgeSplit)
|
|
{
|
|
int nPoints = PL.GetPointNbr() ;
|
|
vEdgeSplit.clear() ;
|
|
vEdgeSplit.resize( nPoints) ;
|
|
fill( vEdgeSplit.begin(), vEdgeSplit.end(), false) ;
|
|
bool bClosed = PL.IsClosed() ;
|
|
// Recupero l'insieme di punti associati alla PolyLine
|
|
PNTVECTOR vPoints ; vPoints.reserve( nPoints) ;
|
|
Point3d ptCurr = P_INVALID ;
|
|
// aggiungo come primo punto il penultimo punto della polyline in modo da analizzare direttamente anche la chiusura ( se è una polyline chiusa)
|
|
PL.GetLastPoint( ptCurr) ;
|
|
PL.GetPrevPoint( ptCurr) ;
|
|
vPoints.emplace_back( ptCurr) ;
|
|
bool bFound = PL.GetFirstPoint( ptCurr) ;
|
|
while ( bFound) {
|
|
vPoints.emplace_back( ptCurr) ;
|
|
bFound = PL.GetNextPoint( ptCurr) ;
|
|
}
|
|
Vector3d vtTanCurr = V_INVALID, vtTanNext = V_INVALID ;
|
|
// cos della tolleranza angolare massima
|
|
double dCosTol = cos( dAngTol * DEGTORAD) ;
|
|
for ( int nP = 0 ; nP < nPoints - 2 ; ++ nP) {
|
|
// Recupero il punto corrente e i due punti successivi
|
|
Point3d& ptCurr = vPoints[nP] ;
|
|
Point3d& ptNext = vPoints[nP + 1] ;
|
|
Point3d& ptNextNext = vPoints[nP + 2] ;
|
|
// Recupero i versori tangenti definiti dai tre punti ( ptCurr|ptNext e ptNext|ptNextNext)
|
|
if ( nP == 0) {
|
|
vtTanCurr = ptNext - ptCurr ;
|
|
vtTanCurr.Normalize() ;
|
|
}
|
|
else
|
|
vtTanCurr = vtTanNext ;
|
|
vtTanNext = ptNextNext - ptNext ; vtTanNext.Normalize() ;
|
|
// Calcolo il Coseno tra i due versori
|
|
double dCos = vtTanCurr * vtTanNext ;
|
|
// Se oltre la tolleranza allora ho incontrato un edge
|
|
if ( dCos < dCosTol)
|
|
vEdgeSplit[nP] = true ;
|
|
}
|
|
|
|
if ( ! bClosed)
|
|
vEdgeSplit[0] = false ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::CreateByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, int nRuledType)
|
|
{
|
|
// converto in bezier la curva iniziale
|
|
CurveComposite CrvU0 ;
|
|
// se la curva è già una bezier singola la tengo, sennò la converto
|
|
if ( pCurve0->GetType() != CRV_BEZIER) {
|
|
// se è una compo controllo che siano già tutte bezier
|
|
bool bAlreadyBez = true ;
|
|
if ( pCurve0->GetType() == CRV_COMPO) {
|
|
const ICurveComposite* pCC0 = GetBasicCurveComposite( pCurve0) ;
|
|
for ( int i = 0 ; i < pCC0->GetCurveCount() ; ++i) {
|
|
if ( pCC0->GetCurve( i)->GetType() != CRV_BEZIER) {
|
|
bAlreadyBez = false ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
bAlreadyBez = false ;
|
|
if ( ! bAlreadyBez)
|
|
CrvU0.AddCurve( CurveToBezierCurve( pCurve0)) ;
|
|
else
|
|
CrvU0.AddCurve( pCurve0->Clone()) ;
|
|
}
|
|
else
|
|
CrvU0.AddCurve( pCurve0->Clone()) ;
|
|
if ( ! CrvU0.IsValid())
|
|
return false ;
|
|
// recupero span e grado nel parametro U
|
|
int nSpanU0 = int( CrvU0.GetCurveCount()) ;
|
|
int nDegU0 = ( GetCurveBezier( CrvU0.GetCurve(0)))->GetDegree() ;
|
|
bool bRat0 = (GetCurveBezier( CrvU0.GetCurve(0)))->IsRational() ;
|
|
// se la curva è già una bezier singola la tengo, sennò la converto
|
|
CurveComposite CrvU1 ;
|
|
// se la curva è già una bezier singola la tengo, sennò la converto
|
|
if ( pCurve1->GetType() != CRV_BEZIER) {
|
|
// se è una compo controllo che siano già tutte bezier
|
|
bool bAlreadyBez = true ;
|
|
if ( pCurve1->GetType() == CRV_COMPO) {
|
|
const ICurveComposite* pCC1 = GetBasicCurveComposite( pCurve1) ;
|
|
for ( int i = 0 ; i < pCC1->GetCurveCount() ; ++i) {
|
|
if ( pCC1->GetCurve( i)->GetType() != CRV_BEZIER) {
|
|
bAlreadyBez = false ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
bAlreadyBez = false ;
|
|
if ( ! bAlreadyBez)
|
|
CrvU1.AddCurve( CurveToBezierCurve( pCurve1)) ;
|
|
else
|
|
CrvU1.AddCurve( pCurve1->Clone()) ;
|
|
}
|
|
else
|
|
CrvU1.AddCurve( pCurve1->Clone()) ;
|
|
// recupero span e grado nel parametro U
|
|
int nSpanU1 = int( CrvU1.GetCurveCount()) ;
|
|
int nDegU1 = ( GetCurveBezier( CrvU1.GetCurve(0)))->GetDegree() ;
|
|
bool bRat1 = (GetCurveBezier( CrvU1.GetCurve(0)))->IsRational() ;
|
|
// se le due curve hanno grado diverso allora aumento il grado di quella con grado inferiore
|
|
if ( nDegU0 != nDegU1) {
|
|
while ( nDegU0 < nDegU1) {
|
|
CurveComposite CC ;
|
|
for ( int k = 0 ; k < nSpanU0 ; ++k)
|
|
CC.AddCurve( BezierIncreaseDegree( GetCurveBezier( CrvU0.GetCurve( k)))) ;
|
|
++nDegU0 ;
|
|
CrvU0 = CC ;
|
|
}
|
|
while ( nDegU0 > nDegU1) {
|
|
CurveComposite CC ;
|
|
for ( int k = 0 ; k < nSpanU0 ; ++k)
|
|
CC.AddCurve( BezierIncreaseDegree( GetCurveBezier( CrvU1.GetCurve( k)))) ;
|
|
++nDegU1 ;
|
|
CrvU1 = CC ;
|
|
}
|
|
}
|
|
// omogenizzo la razionalità
|
|
if ( bRat0 != bRat1) {
|
|
if ( ! bRat0) {
|
|
CurveComposite CC ;
|
|
for ( int k = 0 ; k < nSpanU0 ; ++k) {
|
|
ICurveBezier* pCrvBez = GetCurveBezier( CrvU0.GetCurve( k)->Clone()) ;
|
|
pCrvBez->MakeRational() ;
|
|
CC.AddCurve( pCrvBez) ;
|
|
}
|
|
CrvU0 = CC ;
|
|
bRat0 = true ;
|
|
}
|
|
if ( ! bRat1) {
|
|
CurveComposite CC ;
|
|
for ( int k = 0 ; k < nSpanU1 ; ++k) {
|
|
ICurveBezier* pCrvBez = GetCurveBezier( CrvU1.GetCurve( k)->Clone()) ;
|
|
pCrvBez->MakeRational() ;
|
|
CC.AddCurve( pCrvBez) ;
|
|
}
|
|
CrvU1 = CC ;
|
|
bRat1 = true ;
|
|
}
|
|
}
|
|
|
|
if ( nDegU0 != nDegU1)
|
|
return false ;
|
|
|
|
int nDegU = nDegU0 ;
|
|
|
|
// in V decido che la funzione è una patch di grado 1
|
|
int nSpanV = 1 ;
|
|
int nDegV = 1 ;
|
|
|
|
// ho bisogno della rappresentazione delle curve in forma di polyline, con inizio e fine delle sottocurve
|
|
PolyLine plU0, plU1 ;
|
|
int nCount0 = 0 ;
|
|
DBLVECTOR vdW0 ;
|
|
for ( int k = 0 ; k < nSpanU0 ; ++k ) {
|
|
const ICurveBezier* pSubCrv0 = GetCurveBezier( CrvU0.GetCurve( k)) ;
|
|
for ( int i = 0 ; i < nDegU + 1 ; ++i ) {
|
|
if ( i != nDegU && !( i == 0 && k == 0))
|
|
continue ;
|
|
Point3d ptCtrl = pSubCrv0->GetControlPoint( i) ;
|
|
if ( bRat0)
|
|
vdW0.push_back( pSubCrv0->GetControlWeight( i)) ;
|
|
// aggiungo alla polyline solo gli estremi delle sottocurve ( senza ripetizioni)
|
|
if ( plU0.AddUPoint( nCount0, ptCtrl))
|
|
++ nCount0 ;
|
|
}
|
|
}
|
|
int nCount1 = 0 ;
|
|
DBLVECTOR vdW1 ;
|
|
for ( int k = 0 ; k < nSpanU1 ; ++k ) {
|
|
const ICurveBezier* pSubCrv1 = GetCurveBezier( CrvU1.GetCurve( k)) ;
|
|
for ( int i = 0 ; i < nDegU1 + 1 ; ++i ) {
|
|
if ( i != nDegU && !( i == 0 && k == 0))
|
|
continue ;
|
|
Point3d ptCtrl = pSubCrv1->GetControlPoint( i) ;
|
|
if ( bRat1)
|
|
vdW1.push_back( pSubCrv1->GetControlWeight( i)) ;
|
|
if ( plU1.AddUPoint( nCount1, ptCtrl))
|
|
++ nCount1 ;
|
|
}
|
|
}
|
|
|
|
// verifico ci siano almeno due punti diversi per curva
|
|
if ( ( plU0.IsClosed() && plU0.GetPointNbr() < 3) || plU0.GetPointNbr() < 2)
|
|
return false ;
|
|
if ( ( plU1.IsClosed() && plU1.GetPointNbr() < 3) || plU1.GetPointNbr() < 2)
|
|
return false ;
|
|
|
|
// determino il numero di span che avrà la superficie basandomi sulla curva con più sottocurve
|
|
int nSpanU = max( nSpanU0, nSpanU1) ;
|
|
// punti per curva
|
|
int nLastPoint = nDegU + 1 ;
|
|
// definisco la razionalità
|
|
bool bRat = bRat0 && bRat1 ;
|
|
int nSecondRowInd = nDegU * nSpanU + 1 ;
|
|
|
|
// se sono chiuse devo controllare che gli start siano il più allineati possibile, se non lo sono cambio gli start
|
|
ChangeStartForClosed( plU0, plU1, &CrvU0, &CrvU1) ;
|
|
|
|
// se sto usando la ISOPARM o la MINDIST semplice allora collego più span di una curva allo stesso punto
|
|
if ( nRuledType == RLT_B_MINDIST) {
|
|
// creo le liste di punti per le isoparametriche in U
|
|
PNTIVECTOR vPnt0Match, vPnt1Match ;
|
|
bool bCommonPoint = false ;
|
|
|
|
AssociatePolyLinesMinDistPoints( plU0, plU1, vPnt0Match, vPnt1Match, bCommonPoint) ;
|
|
// devo contare il numero di ripetizioni dei match nel mezzo delle curve, perché aumentano il numero di span della superficie!!
|
|
int nRep0 = 0 ;
|
|
int nIndMatch = 0 ;
|
|
int nIndMatchNext = 0 ;
|
|
int nRep1 = int( vPnt1Match.size() - 1) - vPnt0Match.back().second ;
|
|
for ( int i = 0 ; i < int( vPnt0Match.size() - 1) ; ++i) {
|
|
nIndMatch = vPnt0Match[i].second ;
|
|
nIndMatchNext = vPnt0Match[i+1].second ;
|
|
if ( nIndMatch != nIndMatchNext)
|
|
nRep1 += nIndMatchNext - nIndMatch - 1 ;
|
|
if ( nIndMatch == nIndMatchNext)
|
|
++nRep0 ;
|
|
}
|
|
// reinizializzo la superficie con il nuovo numero di span in U
|
|
nSpanU = nSpanU0 + nRep1 ;
|
|
if ( nSpanU != nSpanU1 + nRep0)
|
|
LOG_DBG_ERR( GetEGkLogger(), "There could be an errore in the creation of a ruled surface in mode RLT_B_MINDIST") ;
|
|
if ( nSpanU < max(nSpanU0, nSpanU1))
|
|
nSpanU = max(nSpanU0, nSpanU1) ;
|
|
nSecondRowInd = nDegU * nSpanU + 1 ;
|
|
Init( nDegU, nDegV, nSpanU, nSpanV, bRat) ;
|
|
|
|
// numero di span aggiunte su U0 e U1
|
|
nCount0 = 0 ;
|
|
nCount1 = 0 ;
|
|
|
|
// scorro gli estremi delle sottocurve della curva U0
|
|
for ( int i = 0 ; i < int( vPnt0Match.size() - 1) ; ++i) {
|
|
nIndMatch = vPnt0Match[i].second ;
|
|
nIndMatchNext = vPnt0Match[i+1].second ;
|
|
const ICurveBezier* pSubCrv0 ;
|
|
if ( nIndMatch == nIndMatchNext) {
|
|
pSubCrv0 = GetCurveBezier( CrvU0.GetCurve( i)) ;
|
|
for ( int j = nCount0 == 0 ? 0 : 1 ; j < nLastPoint ; ++j) {
|
|
if ( ! bRat0)
|
|
SetControlPoint( nCount0 * nDegU + j, pSubCrv0->GetControlPoint( j)) ;
|
|
else
|
|
SetControlPoint( nCount0 * nDegU + j, pSubCrv0->GetControlPoint( j), pSubCrv0->GetControlWeight( j)) ;
|
|
}
|
|
++ nCount0 ;
|
|
// ripeto l'ultimo punto aggiunto alla riga U1 della superificie
|
|
int nInd = nIndMatch > 0 ? nIndMatch - 1 : 0 ;
|
|
const ICurveBezier* pSubCrv0 = GetCurveBezier( CrvU1.GetCurve( nInd)) ;
|
|
for ( int j = nCount1 == 0 ? 0 : 1 ; j < nLastPoint ; ++j) {
|
|
int nPoint = nCount1 == 0 ? 0 : nDegU ;
|
|
if ( ! bRat0)
|
|
SetControlPoint( nSecondRowInd + nCount1 * nDegU + j, pSubCrv0->GetControlPoint( nPoint)) ;
|
|
else
|
|
SetControlPoint( nSecondRowInd + nCount1 * nDegU + j, pSubCrv0->GetControlPoint( nPoint), pSubCrv0->GetControlWeight( nPoint)) ;
|
|
}
|
|
++nCount1 ;
|
|
}
|
|
else {
|
|
// qui devo capire se aggiungere la nuova sottocurva prima o dopo la ripetizione dei punti
|
|
// se il match del punto della U1 è uguale al punto a cui ero arrivato sulla U0 allora prima aggiungo la ripetizione di punti
|
|
// se invece il match è più avanti allora aggiuno prima la curva e poi la ripetzione di punti
|
|
bool bSubCurveAddedFirst = true ;
|
|
for ( int z = vPnt0Match[i].second ; z <= vPnt0Match[i+1].second ; ++z)
|
|
bSubCurveAddedFirst = bSubCurveAddedFirst && vPnt1Match[z].second != i ;
|
|
|
|
if ( bSubCurveAddedFirst) {
|
|
// aggiungo una sottocurva dalla curva U0
|
|
pSubCrv0 = GetCurveBezier( CrvU0.GetCurve( i)) ;
|
|
for ( int j = nCount0 == 0 ? 0 : 1 ; j < nLastPoint ; ++j) {
|
|
if ( ! bRat0)
|
|
SetControlPoint( nCount0 * nDegU + j, pSubCrv0->GetControlPoint( j)) ;
|
|
else
|
|
SetControlPoint( nCount0 * nDegU + j, pSubCrv0->GetControlPoint( j), pSubCrv0->GetControlWeight( j)) ;
|
|
}
|
|
++ nCount0 ;
|
|
}
|
|
|
|
// ripeto l'ultimo punto aggiunto per il numero di curve balzate - 1 della curva U1
|
|
for ( int k = 0 ; k < nIndMatchNext - nIndMatch - 1 ; ++k) {
|
|
pSubCrv0 = GetCurveBezier( CrvU0.GetCurve( i != 0 ? i - 1 : i)) ;
|
|
for ( int j = nCount0 == 0 ? 0 : 1 ; j < nLastPoint ; ++j) {
|
|
int nPoint = i == 0 && ! bSubCurveAddedFirst ? 0 : nDegU ;
|
|
if ( ! bRat0)
|
|
SetControlPoint( nCount0 * nDegU + j, pSubCrv0->GetControlPoint( nPoint)) ;
|
|
else
|
|
SetControlPoint( nCount0 * nDegU + j, pSubCrv0->GetControlPoint( nPoint), pSubCrv0->GetControlWeight( nPoint)) ;
|
|
}
|
|
++ nCount0 ;
|
|
}
|
|
// se non l'ho già aggiunta prima aggiungo una sottocurva della U0
|
|
if ( ! bSubCurveAddedFirst) {
|
|
pSubCrv0 = GetCurveBezier( CrvU0.GetCurve( i)) ;
|
|
for ( int j = nCount0 == 0 ? 0 : 1 ; j < nLastPoint ; ++j) {
|
|
if ( ! bRat0)
|
|
SetControlPoint( nCount0 * nDegU + j, pSubCrv0->GetControlPoint( j)) ;
|
|
else
|
|
SetControlPoint( nCount0 * nDegU + j, pSubCrv0->GetControlPoint( j), pSubCrv0->GetControlWeight( j)) ;
|
|
}
|
|
++ nCount0 ;
|
|
}
|
|
|
|
|
|
// aggiungo tutte le sottocurve che ho balzato della curva U1
|
|
for ( int k = 0 ; k < nIndMatchNext - nIndMatch ; ++k) {
|
|
pSubCrv0 = GetCurveBezier( CrvU1.GetCurve( nIndMatch + k)) ;
|
|
for ( int j = nCount1 == 0 ? 0 : 1 ; j < nLastPoint ; ++j ) {
|
|
if ( ! bRat)
|
|
SetControlPoint( nSecondRowInd + nCount1 * nDegU + j, pSubCrv0->GetControlPoint( j)) ;
|
|
else
|
|
SetControlPoint( nSecondRowInd + nCount1 * nDegU + j, pSubCrv0->GetControlPoint( j), pSubCrv0->GetControlWeight( j)) ;
|
|
}
|
|
++ nCount1 ;
|
|
}
|
|
}
|
|
}
|
|
|
|
//controllo se ho aggiunto tutti i punti della curva U1
|
|
if ( vPnt0Match.back().second != nSpanU1) {
|
|
// riaggiungo l'ultimo punto della U0
|
|
const ICurveBezier* pSubCrv0 = GetCurveBezier( CrvU0.GetCurve( nSpanU0 - 1)) ;
|
|
int nPoint = nDegU ;
|
|
while ( nCount0 < nSpanU) {
|
|
for ( int j = 1 ; j < nLastPoint ; ++j) {
|
|
if ( ! bRat0)
|
|
SetControlPoint( nCount0 * nDegU + j, pSubCrv0->GetControlPoint( nPoint)) ;
|
|
else
|
|
SetControlPoint( nCount0 * nDegU + j, pSubCrv0->GetControlPoint( nPoint), pSubCrv0->GetControlWeight( nPoint)) ;
|
|
}
|
|
++ nCount0 ;
|
|
}
|
|
|
|
// aggiungo le restanti sottocurve della curva U1
|
|
int nCrv1 = vPnt0Match.back().second ;
|
|
while ( nCrv1 < nSpanU1) {
|
|
const ICurveBezier* pSubCrv1 = GetCurveBezier( CrvU1.GetCurve( nCrv1)) ;
|
|
for ( int j = 1 ; j < nLastPoint ; ++j) {
|
|
if ( ! bRat1)
|
|
SetControlPoint( nSecondRowInd + nCount1 * nDegU + j, pSubCrv1->GetControlPoint( j)) ;
|
|
else
|
|
SetControlPoint( nSecondRowInd + nCount1 * nDegU + j, pSubCrv1->GetControlPoint( j), pSubCrv1->GetControlWeight( j)) ;
|
|
}
|
|
++ nCount1 ;
|
|
++ nCrv1 ;
|
|
}
|
|
}
|
|
}
|
|
else if ( nRuledType == RLT_B_ISOPAR) {
|
|
// inizializzo la superficie
|
|
Init( nDegU, nDegV, nSpanU, nSpanV, bRat) ;
|
|
Point3d ptP0Start ; CrvU0.GetStartPoint( ptP0Start) ;
|
|
Point3d ptP1Start ; CrvU1.GetStartPoint( ptP1Start) ;
|
|
// setto i primi due punti delle righe
|
|
nCount0 = 0 ; // sottocurva su pCrvU0
|
|
if ( ! bRat)
|
|
SetControlPoint( 0, ptP0Start) ;
|
|
else
|
|
SetControlPoint( 0, ptP0Start, vdW0[0]) ;
|
|
nCount1 = 0 ; // sottocurva su pCrvU1
|
|
if ( ! bRat)
|
|
SetControlPoint( nSecondRowInd, ptP1Start) ;
|
|
else
|
|
SetControlPoint( nSecondRowInd, ptP1Start, vdW1[0]) ;
|
|
|
|
INTVECTOR vMatch ;
|
|
int nLong = 0 ;
|
|
// prendo la polyline con più punti e scelgo a quali punti dell'altra polyline vanno associati
|
|
FindMatchByParam( plU0, plU1, vMatch,nLong) ;
|
|
|
|
for ( int i = 0 ; i < int( vMatch.size() - 1) ; ++i) {
|
|
int nCount = i ; // span in U aggiunte
|
|
// scorro i punti della polyline più lunga
|
|
// se il punto corrente e il successivo sono associati allo stesso punto dell'altra polyline
|
|
// allora devo aggiungere la sottocurva della curva più lunga e ripetere l'ultimo punto aggiunto dell'altra polyline
|
|
// se il corrente e il successivo sono associati a punti successivi
|
|
// allora devo aggiungere una sottocurva per ognuna delle due curve
|
|
if ( vMatch[i] == vMatch[i+1]) {
|
|
// se la curva più lunga è la prima
|
|
if ( nLong == 0) {
|
|
// aggiungo la curva sulla prima riga
|
|
for ( int i = 1 ; i < nLastPoint ; ++i) {
|
|
const ICurveBezier* pSubCrv0 = GetCurveBezier( CrvU0.GetCurve( nCount0)) ;
|
|
Point3d ptCtrl = pSubCrv0->GetControlPoint( i) ;
|
|
if ( ! bRat)
|
|
SetControlPoint( nCount * nDegU + i, ptCtrl) ;
|
|
else {
|
|
double dW = pSubCrv0->GetControlWeight( i) ;
|
|
SetControlPoint( nCount * nDegU + i, ptCtrl, dW) ;
|
|
}
|
|
}
|
|
++ nCount0 ;
|
|
// riaggungo lo start point sulla seconda riga
|
|
// o end point se ho già aggiunto tutte le curve
|
|
int nInd = nCount1 < nSpanU1 ? 0 : nDegU ;
|
|
int nSubCrv = nCount1 < nSpanU1 ? nCount1 : nSpanU1 - 1 ;
|
|
const ICurveBezier* pSubCrv1 = GetCurveBezier( CrvU1.GetCurve( nSubCrv)) ;
|
|
Point3d ptCtrl = pSubCrv1->GetControlPoint( nInd) ;
|
|
for ( int i = 1 ; i < nLastPoint ; ++i) {
|
|
if ( ! bRat)
|
|
SetControlPoint( nSecondRowInd + nCount * nDegU + i, ptCtrl) ;
|
|
else {
|
|
double dW = pSubCrv1->GetControlWeight( i) ;
|
|
SetControlPoint( nSecondRowInd + nCount * nDegU + i, ptCtrl, dW) ;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// aggiungo la curva sulla seconda riga
|
|
for ( int i = 1 ; i < nLastPoint ; ++i) {
|
|
const ICurveBezier* pSubCrv1 = GetCurveBezier( CrvU1.GetCurve( nCount1)) ;
|
|
Point3d ptCtrl = pSubCrv1->GetControlPoint( i) ;
|
|
if ( ! bRat)
|
|
SetControlPoint( nSecondRowInd + nCount * nDegU + i, ptCtrl) ;
|
|
else {
|
|
double dW = pSubCrv1->GetControlWeight( i) ;
|
|
SetControlPoint( nSecondRowInd + nCount * nDegU + i, ptCtrl, dW) ;
|
|
}
|
|
}
|
|
++ nCount1 ;
|
|
// riaggungo lo start point sulla prima riga
|
|
// o end point se ho già aggiunto tutte le curve
|
|
int nInd = nCount0 < nSpanU0 ? 0 : nDegU ;
|
|
int nSubCrv = nCount0 < nSpanU0 ? nCount0 : nSpanU0 - 1 ;
|
|
const ICurveBezier* pSubCrv0 = GetCurveBezier( CrvU0.GetCurve( nSubCrv)) ;
|
|
Point3d ptCtrl = pSubCrv0->GetControlPoint( nInd) ;
|
|
for ( int i = 1 ; i < nLastPoint ; ++i) {
|
|
if ( ! bRat)
|
|
SetControlPoint( nCount * nDegU + i, ptCtrl) ;
|
|
else {
|
|
double dW = pSubCrv0->GetControlWeight( i) ;
|
|
SetControlPoint( nCount * nDegU + i, ptCtrl, dW) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// altrimenti aggiungo una sottocurva da entrambe le curve
|
|
else {
|
|
// aggiungo la curva sulla prima riga
|
|
for ( int i = 1 ; i < nLastPoint ; ++i) {
|
|
const ICurveBezier* pSubCrv0 = GetCurveBezier( CrvU0.GetCurve( nCount0)) ;
|
|
Point3d ptCtrl = pSubCrv0->GetControlPoint( i) ;
|
|
if ( ! bRat)
|
|
SetControlPoint( nCount * nDegU + i, ptCtrl) ;
|
|
else {
|
|
double dW = pSubCrv0->GetControlWeight( i) ;
|
|
SetControlPoint( nCount * nDegU + i, ptCtrl, dW) ;
|
|
}
|
|
}
|
|
++ nCount0 ;
|
|
// aggiungo la curva sulla seconda riga
|
|
for ( int i = 1 ; i < nLastPoint ; ++i) {
|
|
const ICurveBezier* pSubCrv1 = GetCurveBezier( CrvU1.GetCurve( nCount1)) ;
|
|
Point3d ptCtrl = pSubCrv1->GetControlPoint( i) ;
|
|
if ( ! bRat)
|
|
SetControlPoint( nSecondRowInd + nCount * nDegU + i, ptCtrl) ;
|
|
else {
|
|
double dW = pSubCrv1->GetControlWeight( i) ;
|
|
SetControlPoint( nSecondRowInd + nCount * nDegU + i, ptCtrl, dW) ;
|
|
}
|
|
}
|
|
++ nCount1 ;
|
|
}
|
|
}
|
|
}
|
|
// spezzo le curve di bezier dove è necessario aggiungere dei punti
|
|
else if ( nRuledType == RLT_B_MINDIST_PLUS ) {
|
|
// scorro la prima curva e per ogni punto di fine sottocurva cerco il minDistPoint sull'altra curva
|
|
// in quel punto la curva verrà spezzata, a meno che non si trovi una joint già sufficientemente vicina
|
|
|
|
// prima trovo le associazioni senza aggiunte di punti
|
|
bool bIsClosed0 = plU0.IsClosed() ;
|
|
bool bIsClosed1 = plU1.IsClosed() ;
|
|
CurveComposite ccPoly0 ; ccPoly0.FromPolyLine( plU0) ;
|
|
CurveComposite ccPoly1 ; ccPoly1.FromPolyLine( plU1) ;
|
|
Point3d ptP1 ; plU1.GetFirstPoint( ptP1) ;
|
|
vector<pair<Point3d,double>> vMatch1 ;
|
|
PNTVECTOR vPnt1 ; vPnt1.emplace_back( ptP1) ;
|
|
while ( plU1.GetNextPoint( ptP1, true)) {
|
|
Vector3d vtDir ; CrvU1.GetCurve( vPnt1.size() - 1)->GetEndDir( vtDir) ;
|
|
IntersCurvePlane icp( ccPoly0, ptP1, vtDir) ;
|
|
double dParam ;
|
|
Point3d ptJoint ;
|
|
if ( icp.GetIntersCount() > 0)
|
|
icp.GetIntersPointNearTo( ptP1, ptJoint, dParam) ;
|
|
else {
|
|
DistPointCurve dpc( ptP1, CrvU0, false) ;
|
|
int nFlag = 0 ;
|
|
dpc.GetParamAtMinDistPoint( 0, dParam, nFlag) ;
|
|
dpc.GetMinDistPoint( 0, ptJoint, nFlag) ;
|
|
}
|
|
// capisco se il punto avrà bisogno di aggiungere uno split sull'altra curva o no
|
|
int nParam = int( dParam) ;
|
|
Point3d ptNearestJoint ; // punto più vicino di joint già esistente sulla curva U0
|
|
if ( nParam == nSpanU0)
|
|
CrvU0.GetCurve( nParam - 1)->GetEndPoint( ptNearestJoint) ;
|
|
else if ( dParam - nParam > 0.5)
|
|
CrvU0.GetCurve( nParam)->GetEndPoint( ptNearestJoint) ;
|
|
else
|
|
CrvU0.GetCurve( nParam)->GetStartPoint( ptNearestJoint) ;
|
|
//se sono troppo vicino ad uno split esistente allora non faccio nulla
|
|
if ( abs(dParam - round( dParam)) < 100 * EPS_PARAM || Dist( ptJoint, ptNearestJoint) < 50 * EPS_SMALL) {
|
|
dParam = round( dParam) ;
|
|
}
|
|
|
|
vMatch1.push_back( pair<Point3d,double>( ptJoint, dParam)) ;
|
|
vPnt1.emplace_back( ptP1) ;
|
|
}
|
|
plU1.GetLastPoint( ptP1) ;
|
|
vPnt1.emplace_back( ptP1) ;
|
|
Point3d ptP0 ; plU0.GetLastPoint( ptP0) ;
|
|
vMatch1.push_back( pair<Point3d,double>( ptP0, nSpanU0)) ;
|
|
plU0.GetFirstPoint( ptP0) ;
|
|
vector<pair<Point3d,double>> vMatch0 ;
|
|
PNTVECTOR vPnt0 ; vPnt0.emplace_back( ptP0) ;
|
|
while ( plU0.GetNextPoint( ptP0, true)) {
|
|
double dParam ;
|
|
Point3d ptJoint ;
|
|
Vector3d vtDir ; CrvU0.GetCurve( vPnt0.size() - 1)->GetEndDir( vtDir) ;
|
|
IntersCurvePlane icp( ccPoly1, ptP0, vtDir) ;
|
|
if ( icp.GetIntersCount() > 0) {
|
|
icp.GetIntersPointNearTo( ptP0, ptJoint, dParam) ;
|
|
}
|
|
else {
|
|
DistPointCurve dpc( ptP0, CrvU1, false) ;
|
|
int nFlag = 0 ;
|
|
dpc.GetMinDistPoint( 0, ptJoint, nFlag) ;
|
|
dpc.GetParamAtMinDistPoint( 0, dParam, nFlag) ;
|
|
}
|
|
// capisco se il punto avrà bisogno di aggiungere uno split sull'altra curva o no
|
|
int nParam = int( dParam) ;
|
|
Point3d ptNearestJoint ; // punto più vicino di joint già esistente sulla curva U1
|
|
if ( nParam == nSpanU1)
|
|
CrvU1.GetCurve( nParam - 1)->GetEndPoint( ptNearestJoint) ;
|
|
else if ( dParam - nParam > 0.5)
|
|
CrvU1.GetCurve( nParam)->GetEndPoint( ptNearestJoint) ;
|
|
else
|
|
CrvU1.GetCurve( nParam)->GetStartPoint( ptNearestJoint) ;
|
|
// se sono già troppo vicino ad un split esistente allora non faccio nulla
|
|
if ( abs(dParam - round( dParam)) < 100 * EPS_PARAM || Dist( ptJoint, ptNearestJoint) < 50 * EPS_SMALL) {
|
|
dParam = round( dParam) ;
|
|
}
|
|
vMatch0.push_back( pair<Point3d,double>( ptJoint, dParam)) ;
|
|
vPnt0.emplace_back( ptP0) ;
|
|
}
|
|
plU0.GetLastPoint( ptP0) ;
|
|
vPnt0.emplace_back( ptP0) ;
|
|
plU1.GetLastPoint( ptP1) ;
|
|
vMatch0.push_back( pair<Point3d,double>( ptP1, nSpanU1)) ;
|
|
|
|
// verifico la presenza di eventuali "edge" lungo le polyline ( punti di passaggio di un edge e quindi cambi bruschi di direzione della polyline)
|
|
INTVECTOR vEdgeSplit0, vEdgeSplit1 ;
|
|
double dAngTol = 55 ;
|
|
GetEdgeSplitByAngTol( plU0, dAngTol, vEdgeSplit0) ;
|
|
GetEdgeSplitByAngTol( plU1, dAngTol, vEdgeSplit1) ;
|
|
|
|
int c = 0 ;
|
|
double dLastParamMatch0 = 0 ;
|
|
plU0.GetFirstPoint( ptP0) ;
|
|
Point3d ptLastPointMatch0 = ptP0 ;
|
|
DBLVECTOR vdSplit1 ; // split che sono da applicare alla curva U1
|
|
int j = 0 ;
|
|
double dLastParamMatch1 = 0 ;
|
|
plU1.GetFirstPoint( ptP1) ;
|
|
Point3d ptLastPointMatch1 = ptP1 ;
|
|
DBLVECTOR vdSplit0 ; // split che sono da applicare alla curva U0
|
|
INTINTVECTOR vPairs ;
|
|
vPairs.emplace_back( 0, 0) ;
|
|
bool bAdvance = true ;
|
|
// verifico i match effettivi tra le polyline
|
|
while ( bAdvance) {
|
|
if ( c > ssize(vMatch0) - 1 || j > ssize( vMatch1) - 1) {
|
|
LOG_DBG_ERR( GetEGkLogger(), "RLT_B_MINDIST_PLUS: le due curve potrebbero non avere forme coerenti") ;
|
|
return false ;
|
|
}
|
|
double dParam0 = vMatch0[c].second ;
|
|
Point3d ptJoint0 = vMatch0[c].first ;
|
|
double dParam1 = vMatch1[j].second ;
|
|
Point3d ptJoint1 = vMatch1[j].first ;
|
|
if ( bIsClosed1 && dParam0 > nSpanU1 - EPS_SMALL && c < ssize( vMatch0) / 2) {
|
|
dParam0 = 0 ;
|
|
vMatch0[c].second = dParam0 ;
|
|
}
|
|
if ( bIsClosed0 && dParam1 > nSpanU0 - EPS_SMALL && j < ssize( vMatch1) / 2) {
|
|
dParam1 = 0 ;
|
|
vMatch1[j].second = dParam1 ;
|
|
}
|
|
// capisco con quale delle due polyline avanzo
|
|
bool bAdvance0 = dParam0 < j + 1 + EPS_SMALL ;
|
|
bool bAdvance1 = dParam1 < c + 1 + EPS_SMALL ;
|
|
// controllo se ho un match biunivoco
|
|
bool bPerfectMatch = abs( dParam0 - round( dParam0)) < EPS_SMALL && round( dParam0) == j + 1 &&
|
|
abs( dParam1 - round( dParam1)) < EPS_SMALL && round( dParam1) == c + 1 ;
|
|
int nSplit1 = vdSplit1.size() ;
|
|
int nSplit0 = vdSplit0.size() ;
|
|
// se con una polyline sono arrivato alla fine non posso più avanzare
|
|
if ( c == vMatch0.size())
|
|
bAdvance0 = false ;
|
|
if ( j == vMatch1.size())
|
|
bAdvance1 = false ;
|
|
// se trovo che ho uno spigolo allora procedo con la gestione spigoli
|
|
if ( vEdgeSplit0[c+1] && vEdgeSplit1[j+1]) {
|
|
// se ho uno spigolo su entrambe le curve forzo l'accoppiamento
|
|
bAdvance0 = true ;
|
|
bPerfectMatch = true ;
|
|
dParam0 = j + 1 ;
|
|
dParam1 = c + 1 ;
|
|
ptJoint0 = vPnt1[j+1] ;
|
|
ptJoint1 = vPnt0[c+1] ;
|
|
}
|
|
else if (( vEdgeSplit0[c+1] && ! bAdvance1) || (vEdgeSplit1[j+1] && ! bAdvance0)) {
|
|
bAdvance0 = false ;
|
|
bAdvance1 = false ;
|
|
}
|
|
|
|
if ( bAdvance0) {
|
|
if ( c < dLastParamMatch1 + EPS_SMALL)
|
|
++c ;
|
|
// ho match con lo start
|
|
if ( dParam0 < EPS_SMALL) {
|
|
vPairs.emplace_back( c + nSplit0, j + nSplit1) ;
|
|
}
|
|
// ho un match con l'end
|
|
else if ( dParam0 > nSpanU1 - EPS_SMALL ) {
|
|
vPairs.emplace_back( c + nSplit0, j + nSplit1) ;
|
|
}
|
|
if ( dParam0 <= dLastParamMatch0 || AreSamePointApprox( ptJoint0, ptLastPointMatch0)) {
|
|
dParam0 = dLastParamMatch0 ;
|
|
vPairs.emplace_back( c + nSplit0, j + nSplit1) ;
|
|
}
|
|
else {
|
|
// ho un match con una joint esistente
|
|
if ( dParam0 - int( dParam0) < EPS_SMALL) {
|
|
if ( dParam0 > dLastParamMatch0)
|
|
vPairs.emplace_back( c + nSplit0, j + nSplit1 + 1) ;
|
|
else
|
|
vPairs.emplace_back( c + nSplit0, j + nSplit1) ;
|
|
}
|
|
// altrimenti lo aggiungo
|
|
else {
|
|
vdSplit1.push_back( dParam0) ;
|
|
nSplit1 = vdSplit1.size() ;
|
|
vPairs.emplace_back( c + nSplit0, j + nSplit1) ;
|
|
}
|
|
}
|
|
dLastParamMatch0 = dParam0 ;
|
|
ptLastPointMatch0 = ptJoint0 ;
|
|
dLastParamMatch1 = c ;
|
|
ptLastPointMatch1 = vPnt0[c] ;
|
|
if ( bPerfectMatch)
|
|
++j ;
|
|
}
|
|
if ( bAdvance1 && ! bPerfectMatch) {
|
|
if ( j < dLastParamMatch0 + EPS_SMALL)
|
|
++j ;
|
|
// ho un match con lo start
|
|
if ( dParam1 < EPS_SMALL) {
|
|
vPairs.emplace_back( c + nSplit0, j + nSplit1) ;
|
|
}
|
|
// ho un match con l'end
|
|
else if ( dParam1 > nSpanU0 - EPS_SMALL ) {
|
|
vPairs.emplace_back( c + nSplit0, j + nSplit1) ;
|
|
}
|
|
if ( dParam1 <= dLastParamMatch1 || AreSamePointApprox( ptJoint1, ptLastPointMatch1)) {
|
|
dParam1 = dLastParamMatch1 ;
|
|
vPairs.emplace_back( c + nSplit0, j + nSplit1) ;
|
|
}
|
|
else {
|
|
// ho un match con una joint esistente
|
|
if ( dParam1 - int( dParam1) < EPS_SMALL) {
|
|
if ( dParam1 > dLastParamMatch1)
|
|
vPairs.emplace_back( c + nSplit0 + 1, j + nSplit1) ;
|
|
else
|
|
vPairs.emplace_back( c + nSplit0, j + nSplit1) ;
|
|
}
|
|
//altrimenti lo aggiungo
|
|
else {
|
|
vdSplit0.push_back( dParam1) ;
|
|
nSplit0 = vdSplit0.size() ;
|
|
vPairs.emplace_back( c + nSplit0, j + nSplit1) ;
|
|
}
|
|
}
|
|
dLastParamMatch1 = dParam1 ;
|
|
ptLastPointMatch1 = ptJoint1 ;
|
|
dLastParamMatch0 = j ;
|
|
ptLastPointMatch0 = vPnt1[j] ;
|
|
}
|
|
if ( ! bAdvance0 && ! bAdvance1) {
|
|
// sono arrivato ad un caso di incrocio!!
|
|
//1. se sono vicino ad uno spigolo su entrambe le curve allora aggiungo dei rep
|
|
//2. sennò accoppio comunque
|
|
bool bEdgeFoundOnSecond = false ;
|
|
if ( vEdgeSplit0[c+1] && vEdgeSplit1[j+1]) {
|
|
// questo caso non è previsto !!!!! e non mi aspetto che avvenga
|
|
LOG_DBG_ERR( GetEGkLogger(), "RLT_B_MINDIST_PLUS: a not handled mismatch was found, type 0") ;
|
|
}
|
|
if ( vEdgeSplit0[c+1]) {
|
|
++c ;
|
|
++j ;
|
|
//cerco se ho uno split anche su U1 entro una distanza che sia al massimo il doppio di quella che c'è col punto a mindist
|
|
double dDist = 0 ;
|
|
double dMaxDist = Dist( vPnt0[c], vMatch0[c-1].first) * 2 ;
|
|
int j_temp = j ;
|
|
while ( dDist < dMaxDist) {
|
|
if ( vEdgeSplit1[j_temp]) {
|
|
bEdgeFoundOnSecond = true ;
|
|
break ;
|
|
}
|
|
++j_temp ;
|
|
dDist = Dist( vPnt0[c], vPnt1[j_temp]) ;
|
|
}
|
|
if ( bEdgeFoundOnSecond) {
|
|
// collego i due punti in cui ho il passaggio di un edge e tutti i punti che restano non accoppiati li metto come Rep
|
|
for ( int i = 0 ; i < j_temp - j + 1 ; ++i)
|
|
vPairs.emplace_back( c + nSplit0, j + i + nSplit1) ;
|
|
j = j_temp ;
|
|
dLastParamMatch0 = j - 1 ;
|
|
ptLastPointMatch0 = vPnt1[j] ;
|
|
}
|
|
else {
|
|
LOG_DBG_ERR( GetEGkLogger(), "RLT_B_MINDIST_PLUS: a not handled mismatch was found, type 1") ;
|
|
}
|
|
}
|
|
else if ( vEdgeSplit1[j+1]) {
|
|
++c ;
|
|
++j ;
|
|
//cerco se ho uno split anche su U1 entro una distanza che sia al massimo il doppio di quella che c'è col punto a mindist
|
|
double dDist = 0 ;
|
|
double dMaxDist = Dist( vPnt1[j], vMatch1[j-1].first) * 2 ;
|
|
int c_temp = c ;
|
|
while ( dDist < dMaxDist) {
|
|
if ( vEdgeSplit0[c_temp]) {
|
|
bEdgeFoundOnSecond = true ;
|
|
break ;
|
|
}
|
|
++c_temp ;
|
|
dDist = Dist( vPnt1[j], vPnt0[c_temp]) ;
|
|
}
|
|
if ( bEdgeFoundOnSecond) {
|
|
// collego i due punti in cui ho il passaggio di un edge e tutti i punti che restano non accoppiati li metto come Rep
|
|
for ( int i = 0 ; i < c_temp - c + 1 ; ++i)
|
|
vPairs.emplace_back( c + i + nSplit0, j + nSplit1) ;
|
|
c = c_temp ;
|
|
dLastParamMatch1 = c - 1 ;
|
|
ptLastPointMatch1 = vPnt0[c] ;
|
|
}
|
|
else {
|
|
LOG_DBG_ERR( GetEGkLogger(), "RLT_B_MINDIST_PLUS: a not handled mismatch was found, type 2") ;
|
|
}
|
|
}
|
|
else {
|
|
/////////OLD VRESION
|
|
++c ;
|
|
++j ;
|
|
vPairs.emplace_back( c + nSplit0, j + nSplit1) ;
|
|
dLastParamMatch1 = c ;
|
|
ptLastPointMatch1 = vPnt0[c] ;
|
|
dLastParamMatch0 = j ;
|
|
ptLastPointMatch0 = vPnt1[j] ;
|
|
|
|
|
|
|
|
////// potrei avere un mismatch, senza però avere degli spigoli..
|
|
|
|
// // identifico la zona in cui ho il mismatch e parametrizzo localmente
|
|
|
|
// //conto quanti punti ho nel mezzo
|
|
// int c_temp = c, j_temp = j ;
|
|
// bAdvance0 = true ;
|
|
// bAdvance1 = true ;
|
|
// int nParam0, nParam1 ;
|
|
// while ( bAdvance0) {
|
|
// dParam0 = vMatch0[c_temp].second ;
|
|
// nParam0 = int( round( dParam0)) ;
|
|
// dParam1 = vMatch1[nParam0].second ;
|
|
// nParam1 = int( round( dParam1)) ;
|
|
// if ( abs( nParam1 - c_temp) <= 2)
|
|
// bAdvance0 = false ;
|
|
// else
|
|
// ++ c_temp ;
|
|
// }
|
|
// while ( bAdvance1) {
|
|
// dParam1 = vMatch1[j_temp].second ;
|
|
// nParam1 = int( round( dParam1)) ;
|
|
// dParam0 = vMatch0[nParam1].second ;
|
|
// nParam0 = int( round( dParam0)) ;
|
|
// if ( abs( nParam0 - j_temp) <= 2)
|
|
// bAdvance1 = false ;
|
|
// else
|
|
// ++ j_temp ;
|
|
// }
|
|
// // se non sono avanzato, allora mi basta accoppiare i due punti in questione
|
|
// if ( c_temp == c || j_temp == j) {
|
|
// ++c ;
|
|
// ++j ;
|
|
// vPairs.emplace_back( c + nSplit0, j + nSplit1) ;
|
|
// dLastParamMatch1 = c ;
|
|
// ptLastPointMatch1 = vPnt0[c] ;
|
|
// dLastParamMatch0 = j ;
|
|
// ptLastPointMatch0 = vPnt1[j] ;
|
|
// }
|
|
// // se sono dovuto avanzare per trovare delle coppie che tornano a matchare allora ho effettivamente trovato una zona di mismatch
|
|
// else {
|
|
// // determino quale delle due coppie è il confine effettivo con la zona di mismatch e quale sarà la prima dopo il mismamtch
|
|
// dParam0 = vMatch0[c_temp].second ;
|
|
// dParam1 = vMatch1[j_temp].second ;
|
|
// bool bIntParam0 = false ;
|
|
// bool bIntParam1 = false ;
|
|
// if ( abs( dParam0 - round( dParam0)) < EPS_SMALL) {
|
|
// dParam0 = round( dParam0) ;
|
|
// bIntParam0 = true ;
|
|
// }
|
|
// if ( abs( dParam1 - round( dParam1)) < EPS_SMALL) {
|
|
// dParam1 = round( dParam1) ;
|
|
// bIntParam1 = true ;
|
|
// }
|
|
// bAdvance0 = dParam0 < j_temp + 1 + EPS_SMALL ;
|
|
// bAdvance1 = dParam1 < c_temp + 1 + EPS_SMALL ;
|
|
// PtrOwner<ICurve> pCC0 ;
|
|
// PtrOwner<ICurve> pCC1 ;
|
|
// int nPointsBetween0 = 0 ;
|
|
// int nPointsBetween1 = 0 ;
|
|
// if ( bAdvance0 && bAdvance1) {
|
|
// pCC0.Set( CrvU0.CopyParamRange( dLastParamMatch1, c_temp + 1)) ;
|
|
// pCC1.Set( CrvU1.CopyParamRange( dLastParamMatch0, j_temp + 1)) ;
|
|
// nPointsBetween0 = c_temp - c ;
|
|
// nPointsBetween1 = j_temp - j ;
|
|
// }
|
|
// else if ( bAdvance0) {
|
|
// pCC0.Set( CrvU0.CopyParamRange( dLastParamMatch1, c_temp + 1)) ;
|
|
// pCC1.Set( CrvU1.CopyParamRange( dLastParamMatch0, dParam0)) ;
|
|
// nPointsBetween0 = c_temp - c ;
|
|
// nPointsBetween1 = int( dParam0) - ( j + 1) ;
|
|
// if ( bIntParam0)
|
|
// nPointsBetween1 -= 1 ;
|
|
// }
|
|
// else if ( bAdvance1) {
|
|
// pCC0.Set( CrvU0.CopyParamRange( dLastParamMatch1, dParam1)) ;
|
|
// pCC1.Set( CrvU1.CopyParamRange( dLastParamMatch0, j_temp + 1)) ;
|
|
// nPointsBetween0 = int( dParam1) - ( c + 1) ;
|
|
// nPointsBetween1 = j_temp - j ;
|
|
// if ( bIntParam1)
|
|
// nPointsBetween0 -= 1 ;
|
|
// }
|
|
//
|
|
// double dLen0 ; pCC0->GetLength( dLen0) ;
|
|
// double dLen1 ; pCC1->GetLength( dLen1) ;
|
|
// DBLVECTOR vdParamPos0 ; vdParamPos0.reserve( nPointsBetween0) ;
|
|
// DBLVECTOR vdParamPos1 ; vdParamPos1.reserve( nPointsBetween1) ;
|
|
// for ( int k = 0 ; k <= nPointsBetween0 ; ++k) {
|
|
// double dLen = 0 ; pCC0->GetLengthAtParam( k, dLen) ;
|
|
// vdParamPos0.push_back( dLen / dLen0) ;
|
|
// }
|
|
// vdParamPos0.push_back( 1) ;
|
|
// for ( int k = 0 ; k <= nPointsBetween1 ; ++k) {
|
|
// double dLen = 0 ; pCC1->GetLengthAtParam( k, dLen) ;
|
|
// vdParamPos1.push_back( dLen / dLen1) ;
|
|
// }
|
|
// vdParamPos1.push_back( 1) ;
|
|
|
|
// bool bSplitToAdd = true ;
|
|
// int c0 = 1, c1 = 1 ;
|
|
// //debug
|
|
// int nCBerfore = c ;
|
|
// int nJBefore = j ;
|
|
// //debug
|
|
// while ( bSplitToAdd) {
|
|
// if ( c0 > ssize( vdParamPos0) - 1 && c1 > ssize( vdParamPos1) - 1) {
|
|
// LOG_DBG_ERR( GetEGkLogger(), "Surf Bez Ruled Guided: error 1 while reparametrizing some section") ;
|
|
// return false ;
|
|
// }
|
|
// // se ho una corrispondenza tra punti ( e non sono alla fine del tratto) allora non aggiungo split
|
|
// if ( abs( vdParamPos0[c0] - vdParamPos1[c1]) < EPS_PARAM && vdParamPos0[c0] < 1) {
|
|
// ++c0 ;
|
|
// ++c1 ;
|
|
// ++c ;
|
|
// ++j ;
|
|
// vPairs.emplace_back( c + nSplit0, j + nSplit1) ;
|
|
// }
|
|
// // se non ho corrispondenza allora aggiungo uno split sulla curva a cui manca il punto corrispondente
|
|
// else if ( vdParamPos0[c0] < vdParamPos1[c1]) {
|
|
// double dPar ; CrvU1.GetParamAtLength( dLen1 * vdParamPos0[c0], dPar) ;
|
|
// if ( abs( dPar - round( dPar)) > EPS_SMALL) {
|
|
// vdSplit1.push_back( dPar + dLastParamMatch0) ;
|
|
// nSplit1 = vdSplit1.size() ;
|
|
// }
|
|
// else if ( dPar = round( dPar) ; dPar > j){
|
|
// ++ j ;
|
|
// }
|
|
// ++c ;
|
|
// vPairs.emplace_back( c + nSplit0, j + nSplit1) ;
|
|
// ++c0 ;
|
|
// }
|
|
// else if ( vdParamPos0[c0] > vdParamPos1[c1]) {
|
|
// double dPar ; CrvU0.GetParamAtLength( dLen0 * vdParamPos1[c1], dPar) ;
|
|
// // se lo split non è in prossimità di una joint già esistente allora lo aggiungo
|
|
// if ( abs( dPar - round( dPar)) > EPS_SMALL) {
|
|
// vdSplit0.push_back( dPar + dLastParamMatch1) ;
|
|
// nSplit0 = vdSplit0.size() ;
|
|
// }
|
|
// else if ( dPar = round( dPar) ; dPar > c){
|
|
// ++ c ;
|
|
// }
|
|
// ++j ;
|
|
// vPairs.emplace_back( c + nSplit0, j + nSplit1) ;
|
|
// ++c1 ;
|
|
// }
|
|
// else {
|
|
// LOG_DBG_ERR( GetEGkLogger(), "Surf Bez Ruled Guided: error 2 while reparametrizing some section") ;
|
|
// return false ;
|
|
// }
|
|
// bSplitToAdd = ! ( c0 == ssize( vdParamPos0) - 1 && c1 == ssize( vdParamPos1) - 1) ;
|
|
// }
|
|
// // aggiorno i dati dell'ultima aggiunta
|
|
// if ( bAdvance0 && ! bAdvance1) {
|
|
// ptLastPointMatch0 = vMatch0[c_temp].first ;
|
|
// dLastParamMatch0 = vMatch0[c_temp].second ;
|
|
// ptLastPointMatch1 = vPnt0[c_temp] ;
|
|
// dLastParamMatch0 = c_temp ;
|
|
// }
|
|
// else if ( ! bAdvance0 && bAdvance1) {
|
|
// ptLastPointMatch0 = vPnt1[j_temp] ;
|
|
// dLastParamMatch0 = j_temp ;
|
|
// ptLastPointMatch1 = vMatch1[j_temp].first ;
|
|
// dLastParamMatch0 = vMatch1[j_temp].second ;
|
|
// }
|
|
// else {
|
|
// ptLastPointMatch0 = vPnt1[j_temp] ;
|
|
// dLastParamMatch0 = j_temp ;
|
|
// ptLastPointMatch1 = vPnt0[c_temp] ;
|
|
// dLastParamMatch0 = c_temp ;
|
|
// }
|
|
// vPairs.emplace_back( c + nSplit0, j + nSplit1) ;
|
|
// }
|
|
}
|
|
}
|
|
bAdvance = ! ( c >= ssize( vMatch0) - 1 && j >= ssize( vMatch1) - 1) ;
|
|
}
|
|
|
|
// applico effettivamente gli split
|
|
int nUnit = 0 ;
|
|
if ( ! vdSplit1.empty())
|
|
nUnit = int( vdSplit1.back()) ;
|
|
for ( int z = int( vdSplit1.size() - 1) ; z >= 0 ; --z) {
|
|
double dSplit = vdSplit1[z] ;
|
|
int nSplit = int( dSplit) ;
|
|
// se sto cercando di fare uno split sulla stessa curva che ho già splittato al passaggio precedente allora devo
|
|
// riscalare
|
|
if ( nSplit == nUnit && z < int( vdSplit1.size() - 1)) {
|
|
dSplit = nSplit + ( dSplit - nSplit) / (vdSplit1[z+1] - nSplit);
|
|
}
|
|
nUnit = nSplit ;
|
|
CrvU1.AddJoint( dSplit) ;
|
|
}
|
|
if ( ! vdSplit0.empty())
|
|
nUnit = int( vdSplit0.back()) ;
|
|
for ( int z = int( vdSplit0.size() - 1) ; z >= 0 ; --z) {
|
|
double dSplit = vdSplit0[z] ;
|
|
int nSplit = int( dSplit) ;
|
|
// se sto cercando di fare uno split sulla stessa curva che ho già splittato al passaggio precedente allora devo
|
|
// riscalare
|
|
if ( nSplit == nUnit && z < int( vdSplit0.size() - 1)) {
|
|
dSplit = nSplit + ( dSplit - nSplit) / (vdSplit0[z+1] - nSplit);
|
|
}
|
|
nUnit = nSplit ;
|
|
CrvU0.AddJoint( dSplit) ;
|
|
}
|
|
|
|
nSpanU0 = CrvU0.GetCurveCount() ;
|
|
nSpanU1 = CrvU1.GetCurveCount() ;
|
|
// aggiungo l'ultima coppia
|
|
vPairs.emplace_back( nSpanU0, nSpanU1) ;
|
|
|
|
// trovo il numero di span che dovrà avere la superficie
|
|
nSpanU = int(vPairs.size()) - 1 ;
|
|
|
|
nSecondRowInd = nDegU * nSpanU + 1 ;
|
|
// inizializzo la superficie
|
|
Init( nDegU, nDegV, nSpanU, nSpanV, bRat) ;
|
|
|
|
// aggiungo i punti di controllo scorrendo in contemporanea le due curve
|
|
int nAddedSpan = 0 ;
|
|
int nCrv0 = 0 ;
|
|
int nCrv1 = 0 ;
|
|
bool bLast0 = false ;
|
|
bool bLast1 = false ;
|
|
|
|
bool bOk = true ;
|
|
while ( nAddedSpan < nSpanU && bOk) {
|
|
nCrv0 = vPairs[nAddedSpan].first ;
|
|
nCrv1 = vPairs[nAddedSpan].second ;
|
|
bool bRep0 = nCrv0 < nSpanU0 ? nCrv0 == vPairs[nAddedSpan + 1].first : nCrv0 == vPairs[nAddedSpan - 1].first ;
|
|
bool bRep1 = nCrv1 < nSpanU1 ? nCrv1 == vPairs[nAddedSpan + 1].second : nCrv1 == vPairs[nAddedSpan - 1].second ;
|
|
if ( nCrv0 >= nSpanU0){
|
|
nCrv0 = nSpanU0 - 1 ;
|
|
bLast0 = true ;
|
|
}
|
|
if ( nCrv1 >= nSpanU1) {
|
|
nCrv1 = nSpanU1 - 1 ;
|
|
bLast1 = true ;
|
|
}
|
|
const ICurveBezier* pSubCrv0 = GetCurveBezier( CrvU0.GetCurve( nCrv0)) ;
|
|
for ( int i = nAddedSpan == 0 ? 0 : 1 ; i < nLastPoint ; ++ i) {
|
|
int nInd = i ;
|
|
// se ho una ripetizione allora riaggiungo l'ultimo punto. Se sono ancora alla curva 0 invece devo aggiungere lo start della curva U0
|
|
if ( bRep0 || bLast0)
|
|
nInd = ! bLast0 ? 0 : nDegU ;
|
|
if ( ! bRat)
|
|
bOk = SetControlPoint( nAddedSpan * nDegU + i, pSubCrv0->GetControlPoint( nInd)) ;
|
|
else
|
|
bOk = SetControlPoint( nAddedSpan * nDegU + i, pSubCrv0->GetControlPoint( nInd), pSubCrv0->GetControlWeight( nInd)) ;
|
|
}
|
|
const ICurveBezier* pSubCrv1 = GetCurveBezier( CrvU1.GetCurve( nCrv1)) ;
|
|
for ( int i = nAddedSpan == 0 ? 0 : 1 ; i < nLastPoint ; ++ i) {
|
|
int nInd = i ;
|
|
// se ho una ripetizione allora riaggiungo l'ultimo punto. Se sono ancora alla curva 0 invece devo aggiungere lo start della curva U1
|
|
if ( bRep1 || bLast1)
|
|
nInd = ! bLast1 ? 0 : nDegU ;
|
|
if ( ! bRat)
|
|
bOk = SetControlPoint( nSecondRowInd + nAddedSpan * nDegU + i, pSubCrv1->GetControlPoint( nInd)) ;
|
|
else
|
|
bOk = SetControlPoint( nSecondRowInd + nAddedSpan * nDegU + i, pSubCrv1->GetControlPoint( nInd), pSubCrv1->GetControlWeight( nInd)) ;
|
|
}
|
|
++ nAddedSpan ;
|
|
}
|
|
|
|
#if SAVERULEDISO
|
|
//debug
|
|
vector<IGeoObj*> vGeo ;
|
|
ICURVEPOVECTOR vCrv ;
|
|
GetAllPatchesIsocurves( false, vCrv) ;
|
|
for ( int i = 0 ; i < ssize( vCrv) ; ++i) {
|
|
vGeo.push_back( vCrv[i]->Clone()) ;
|
|
}
|
|
vector<Color> vCol( ssize( vCrv)) ;
|
|
fill( vCol.begin(), vCol.end(), Color( 255,0,128)) ;
|
|
SaveGeoObj( vGeo, vCol, "D:/Temp/bezier/ruled/isoCurves.nge") ;
|
|
//debug
|
|
|
|
vGeo.clear() ;
|
|
vGeo.push_back( CrvU0.Clone()) ;
|
|
vGeo.push_back( CrvU1.Clone()) ;
|
|
vCol.clear() ;
|
|
vCol.push_back(Color(0,64,128)) ;
|
|
vCol.push_back(Color(128,64,0)) ;
|
|
SaveGeoObj( vGeo, vCol, "D:/Temp/bezier/ruled/NewCurves.nge") ;
|
|
#endif
|
|
|
|
return bOk ;
|
|
}
|
|
else if ( RLT_B_LENPAR ) {
|
|
// da implementare
|
|
return false ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::FindMatchByParam( const PolyLine& pl0, const PolyLine& pl1, INTVECTOR& vMatch, int& nLong) const
|
|
{
|
|
// per la modalità isoparametrica
|
|
int nPoints0 = pl0.GetPointNbr() ;
|
|
int nPoints1 = pl1.GetPointNbr() ;
|
|
DBLVECTOR vSplit ;
|
|
int nMin = min( nPoints0, nPoints1) ;
|
|
for ( int i = 0 ; i < nMin - 1 ; ++i) {
|
|
// valuto il limite dell'area di influenza dei punti della curva con meno punti
|
|
// per i punti intermedi il limite è la metà tra i punti
|
|
// per il primo e l'ultimo punto aumento il peso di quest'ultimi nel calcolo della media
|
|
double dW = 2./3. ;
|
|
//double dW = 1./2. ;
|
|
if ( i == 0)
|
|
vSplit.push_back( (i * (1- dW) + ( i + 1) * dW) / ( nMin - 1)) ;
|
|
else if ( i == nMin - 2)
|
|
vSplit.push_back( (i * dW + ( i + 1) * ( 1 - dW)) / ( nMin - 1)) ;
|
|
else
|
|
vSplit.push_back( ( 2. * i + 1) / (2 * ( nMin - 1))) ;
|
|
}
|
|
int nCount = 0 ;
|
|
int nMax = max(nPoints0, nPoints1) ;
|
|
nLong = nPoints0 < nPoints1 ? 1 : 0 ;
|
|
for ( double j = 0 ; j < nMax ; ++j) {
|
|
if ( nCount < int(vSplit.size()) && j / ( nMax - 1) > vSplit[nCount] )
|
|
++nCount ;
|
|
vMatch.push_back( nCount) ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
static bool
|
|
ParametrizeByLen( const ICurveComposite* pCurve, DBLVECTOR& vParam)
|
|
{
|
|
int nSpanU = pCurve->GetCurveCount() ;
|
|
DBLVECTOR vLen ;
|
|
double dLenTot = 0 ;
|
|
vParam.push_back( 0) ;
|
|
for ( int i = 0 ; i < nSpanU ; ++i) {
|
|
const ICurve* pSubCrv = pCurve->GetCurve( i) ;
|
|
double dLen ; pSubCrv->GetLength( dLen) ;
|
|
dLenTot += dLen ;
|
|
vLen.push_back( dLenTot) ;
|
|
}
|
|
// determino il parametro di ogni curva rispetto alla lunghezza totale
|
|
for ( int i = 0 ; i < nSpanU ; ++i)
|
|
vParam.push_back( vLen[i] / dLenTot) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
static bool
|
|
BuildCommonParam( const DBLMATRIX& mParam, DBLVECTOR& vCommonParam)
|
|
{
|
|
vCommonParam = mParam[0] ;
|
|
for ( int i = 1 ; i < int( mParam.size()) ; ++i) {
|
|
for ( int j = 0 ; j < int( mParam[i].size()) ; ++j)
|
|
vCommonParam.push_back( mParam[i][j]) ;
|
|
}
|
|
//riordino ed elimino i doppioni entro una certa tolleranza
|
|
sort( vCommonParam.begin(), vCommonParam.end()) ;
|
|
for ( int i = 0 ; i < int(vCommonParam.size()) - 1 ; ++i) {
|
|
for ( int j = i + 1 ; j < int(vCommonParam.size()) ; ++j) {
|
|
if ( vCommonParam[j] - vCommonParam[i] < EPS_SMALL){
|
|
vCommonParam.erase(vCommonParam.begin() + j) ;
|
|
--j ;
|
|
}
|
|
else
|
|
break ;
|
|
}
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
static bool
|
|
SplitByCommonParam( ICURVEPOVECTOR& vCrvBezUnif, DBLVECTOR& vCommonParam, DBLMATRIX& mParam)
|
|
{
|
|
for ( int i = 0 ; i < int( vCrvBezUnif.size()) ; ++i) {
|
|
ICurveComposite* pCC = GetCurveComposite(vCrvBezUnif[i]) ;
|
|
int c = mParam[i].size() - 1 ;
|
|
DBLVECTOR vParam = mParam[i] ;
|
|
for ( int j = vCommonParam.size() - 1 ; j >= 0 ; --j) {
|
|
// capisco su quale sottocurva devo fare lo split e riconverto il parametro rispetto al numero di sottocurve
|
|
while ( vCommonParam[j] < vParam[c])
|
|
--c ;
|
|
if ( vCommonParam[j] - vParam[c] > EPS_SMALL) {
|
|
double dSplit = (vCommonParam[j] - vParam[c]) / (vParam[c+1] - vParam[c]) + c ;
|
|
pCC->AddJoint( dSplit) ;
|
|
vParam.insert( vParam.begin() + c + 1, vCommonParam[j]) ;
|
|
++c ;
|
|
}
|
|
}
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::CreateBySetOfCurves( const ICURVEPOVECTOR& vCrvBez, bool bReduceToDeg3)
|
|
{
|
|
// uniformo le curve e determino il grado e il numero di span condiviso
|
|
bool bRat = false ;
|
|
int nDegU = 3 ;
|
|
ICURVEPOVECTOR vCrvBezUnif ;
|
|
DBLMATRIX mParam ;
|
|
if ( ! bReduceToDeg3) {
|
|
int nDegMax = 1 ;
|
|
//trovo il grado massimo
|
|
for ( int i = 0 ; i < int( vCrvBez.size()) ; ++i) {
|
|
const ICurveComposite* pCC = GetCurveComposite( vCrvBez[i]) ;
|
|
for ( int j = 0 ; j < int( pCC->GetCurveCount()) ; ++j) {
|
|
const ICurveBezier* pCrvBez = GetCurveBezier( pCC->GetCurve( j)) ;
|
|
int nDeg = pCrvBez->GetDegree() ;
|
|
nDegMax = max( nDegMax, nDeg) ;
|
|
}
|
|
}
|
|
// porto tutte le curve al grado massimo
|
|
for ( int i = 0 ; i < int(vCrvBez.size()) ; ++i )
|
|
vCrvBezUnif.emplace_back( EditBezierCurve( GetCurveBezier(vCrvBez[i]), nDegMax, false)) ;
|
|
}
|
|
else {
|
|
// scorro le curve e uniformo tutte in curve di grado 3 non razionale
|
|
for ( int i = 0 ; i < int( vCrvBez.size()) ; ++i) {
|
|
const ICurveComposite* pCCFromSet = GetCurveComposite( vCrvBez[i]) ;
|
|
if ( pCCFromSet == nullptr)
|
|
return false ;
|
|
PtrOwner<ICurveComposite> pCC( CreateCurveComposite()) ;
|
|
for ( int j = 0 ; j < int( pCCFromSet->GetCurveCount()) ; ++j) {
|
|
const ICurveBezier* pCrvBez = GetCurveBezier( pCCFromSet->GetCurve( j)) ;
|
|
if ( pCrvBez == nullptr)
|
|
return false ;
|
|
if ( ! pCC->AddCurve( EditBezierCurve( pCrvBez, nDegU, bRat)))
|
|
return false ;
|
|
}
|
|
mParam.emplace_back() ;
|
|
ParametrizeByLen( pCC, mParam.back()) ;
|
|
vCrvBezUnif.emplace_back( Release( pCC)) ;
|
|
}
|
|
}
|
|
// ora vado a splittare le curve in modo da avere una divisione condivisa
|
|
DBLVECTOR vdCommonPar ;
|
|
BuildCommonParam( mParam, vdCommonPar) ;
|
|
SplitByCommonParam( vCrvBezUnif, vdCommonPar, mParam) ;
|
|
int nSpanU = GetCurveComposite( vCrvBezUnif[0])->GetCurveCount() ;
|
|
|
|
// calcolo i punti di controllo in V
|
|
int nDegV = 3 ;
|
|
int nSpanV = int( vCrvBezUnif.size()) - 1 ;
|
|
|
|
PNTMATRIX vPntCrvs ;
|
|
//versione vecchia
|
|
for ( int j = 0 ; j < nSpanU ; ++j ) {
|
|
PNTVECTOR vPntCtrl0 ;
|
|
PNTVECTOR vPntCtrl1 ;
|
|
for ( int i = 0 ; i < int( vCrvBezUnif.size()) ; ++i) {
|
|
const ICurveComposite* pCC = GetCurveComposite( vCrvBezUnif[i]) ;
|
|
const ICurveBezier* pCrvBez = GetCurveBezier( pCC->GetCurve( j)) ;
|
|
if ( j == 0)
|
|
vPntCtrl0.push_back( pCrvBez->GetControlPoint( 0)) ;
|
|
vPntCtrl1.push_back( pCrvBez->GetControlPoint( nDegU)) ;
|
|
}
|
|
if ( j==0 )
|
|
vPntCrvs.push_back( vPntCtrl0) ;
|
|
vPntCrvs.push_back( vPntCtrl1) ;
|
|
}
|
|
|
|
////versione nuova
|
|
//for ( int j = 0 ; j < nSpanU ; ++j ) {
|
|
// for ( int z = j== 0 ? 0 : 1 ; z < nDegU + 1 ; ++z) {
|
|
// PNTVECTOR vPntCtrl ;
|
|
// for ( int i = 0 ; i < int( vCrvBezUnif.size()) ; ++i) {
|
|
// const ICurveComposite* pCC = GetCurveComposite( vCrvBezUnif[i]) ;
|
|
// const ICurveBezier* pCrvBez = GetCurveBezier( pCC->GetCurve( j)) ;
|
|
// vPntCtrl.push_back( pCrvBez->GetControlPoint( z)) ;
|
|
// }
|
|
// vPntCrvs.push_back( vPntCtrl) ;
|
|
// }
|
|
//}
|
|
|
|
|
|
Init( nDegU, nDegV, nSpanU, nSpanV, false) ;
|
|
// scorro le span
|
|
for ( int s = 0 ; s < int( nSpanU) ; ++s) {
|
|
//// trovo la direzione media del parametro V
|
|
//Point3d ptMean = ORIG ;
|
|
|
|
//// verione vecchia
|
|
//for ( int i = 1 ; i < int( vPntCrvs[0].size()) ; ++i )
|
|
// ptMean += vPntCrvs[s][i] ;
|
|
//ptMean /= int( vPntCrvs[0].size() - 1) ;
|
|
//Vector3d vtDirXGeneral = ptMean - vPntCrvs[s][0] ;
|
|
|
|
|
|
// prendo le curve a gruppi di 3 per costruire la parabola per trovare la pendenza "intuitiva" della superficie in V
|
|
for ( int g = 0 ; g < nSpanV - 1 ; ++g) {
|
|
//// versione nuova
|
|
//Vector3d vtDirXGeneral ;
|
|
//// devo scorrere la matrice a blocchi di nDegU
|
|
//for ( int z = s * nDegU ; z < ( s + 1) * nDegU + 1 ; ++z) {
|
|
// ptMean = ORIG ;
|
|
// for ( int i = g ; i < g + 3 ; ++i)
|
|
// ptMean += vPntCrvs[z][i] ;
|
|
// ptMean /= int( vPntCrvs[0].size() - 1) ;
|
|
// vtDirXGeneral += ptMean - vPntCrvs[z][g] ;
|
|
//}
|
|
const ICurveComposite* pCC0 = GetCurveComposite( vCrvBezUnif[g]) ;
|
|
const ICurveComposite* pCC1 = GetCurveComposite( vCrvBezUnif[g + 1]) ;
|
|
const ICurveComposite* pCC2 = GetCurveComposite( vCrvBezUnif[g + 2]) ;
|
|
// su ognuna di queste 3 curve prendo un punto per ogni punto di controllo ( semplicemente dividendo uniformemente il parametrico)
|
|
for ( int n = s == 0 ? 0 : 1 ; n < nDegU + 1 ; ++n) {
|
|
const ICurveBezier* pCrv0 = GetCurveBezier( pCC0->GetCurve( s)) ;
|
|
const ICurveBezier* pCrv1 = GetCurveBezier( pCC1->GetCurve( s)) ;
|
|
const ICurveBezier* pCrv2 = GetCurveBezier( pCC2->GetCurve( s)) ;
|
|
// setto come punti di controllo i punti delle curve
|
|
Point3d ptCtrl0 = pCrv0->GetControlPoint( n) ;
|
|
Point3d ptCtrl1 = pCrv1->GetControlPoint( n) ;
|
|
Point3d ptCtrl2 = pCrv2->GetControlPoint( n) ;
|
|
if ( g == 0) {
|
|
SetControlPoint( n + (s * nDegU) + (nDegU * nSpanU + 1) * g * 3, ptCtrl0) ;
|
|
SetControlPoint( n + (s * nDegU) + (nDegU * nSpanU + 1) * (g * 3 + 3), ptCtrl1) ;
|
|
}
|
|
SetControlPoint( n + (s * nDegU) + (nDegU * nSpanU + 1) * (g * 3 + 6), ptCtrl2) ;
|
|
//// trovo i punti di controllo intermedi tra le curve usando la parabola che unisce queste tre curve////
|
|
Point3d ptP0 = pCrv0->GetControlPoint( n) ;
|
|
Point3d ptP1 = pCrv1->GetControlPoint( n) ;
|
|
Point3d ptP2 = pCrv2->GetControlPoint( n) ;
|
|
DistPointLine dpl( ptP1, ptP0, ptP2, false) ;
|
|
double dDist = INFINITO ; dpl.GetDist( dDist) ;
|
|
Point3d ptP3, ptP4, ptP5, ptP6 ;
|
|
if ( dDist < EPS_SMALL) {
|
|
// i punti sono allineati quindi mi basta prendere dei punti intermedi su questa retta
|
|
ptP3 = ptP0 * 2/3 + ptP1 * 1/3 ;
|
|
ptP4 = ptP0 * 1/3 + ptP1 * 2/3 ;
|
|
ptP5 = ptP1 * 2/3 + ptP2 * 1/3 ;
|
|
ptP6 = ptP1 * 1/3 + ptP2 * 2/3 ;
|
|
}
|
|
else {
|
|
// calcolo il piano della parabola e porto i punti in quel riferimento
|
|
Plane3d plParab ; plParab.Set( ptP0, ptP1, ptP2) ;
|
|
Point3d ptStartV, ptEndV ;
|
|
DistPointLine dpl( ptP1, ptP0, ptP2, true) ;
|
|
Point3d ptPerp ; dpl.GetMinDistPoint( ptPerp) ;
|
|
Vector3d vtDirY = ptPerp - ptP1 ;
|
|
Frame3d frParab ;
|
|
Point3d ptStart, ptEnd ;
|
|
pCrv1->GetStartPoint( ptStart) ;
|
|
pCrv1->GetEndPoint( ptEnd) ;
|
|
Vector3d vtDirCrv1 = ptEnd - ptStart ;
|
|
Vector3d vtParabNorm = plParab.GetVersN() ;
|
|
Vector3d vtDirZ = vtDirCrv1 * vtParabNorm > 0 ? vtParabNorm : - vtParabNorm ;
|
|
//Vector3d vtDirX = vtDirXGeneral - (vtDirXGeneral * vtDirZ * vtDirZ) ; // versione vecchia
|
|
Vector3d vtDirX = ptP2 - ptP0 ; // versione vecchia vecchia
|
|
if ( ! frParab.Set( ptP0, vtDirX, vtDirY, vtDirZ)) {
|
|
vtDirY = vtDirZ ^ vtDirX ;
|
|
if ( ! frParab.Set( ptP0, vtDirX, vtDirY, vtDirZ))
|
|
return false ;
|
|
}
|
|
// porto i punti nel piano di riferimento della parabola
|
|
Point3d pt0 = ptP0 ; pt0.ToLoc( frParab) ;
|
|
Point3d pt1 = ptP1 ; pt1.ToLoc( frParab) ;
|
|
Point3d pt2 = ptP2 ; pt2.ToLoc( frParab) ;
|
|
|
|
Eigen::Matrix3d mA ;
|
|
mA.col(0) << pt0.x * pt0.x, pt1.x * pt1.x, pt2.x * pt2.x ;
|
|
mA.col(1) << pt0.x, pt1.x , pt2.x ;
|
|
mA.col(2) << 1, 1, 1 ;
|
|
if ( abs( mA.determinant()) < EPS_SMALL)
|
|
return false ;
|
|
Eigen::Vector3d b ( pt0.y, pt1.y, pt2.y) ;
|
|
Eigen::Vector3d coeff = mA.fullPivLu().solve(b) ;
|
|
|
|
// pendenze e termini noti nei punti di contatto
|
|
double dm0 = 2 * coeff.x() * pt0.x + coeff.y() ;
|
|
double dm1 = 2 * coeff.x() * pt1.x + coeff.y() ;
|
|
double dm2 = 2 * coeff.x() * pt2.x + coeff.y() ;
|
|
double dq0 = pt0.y - dm0 * pt0.x ;
|
|
double dq1 = pt1.y - dm1 * pt1.x ;
|
|
double dq2 = pt2.y - dm2 * pt2.x ;
|
|
// trovo le intersezioni a coppie tra le tre rette di tangenza
|
|
Point3d ptI1 , ptI2;
|
|
ptI1.x = (dq1 -dq0) / (dm0 - dm1) ;
|
|
ptI1.y = ptI1.x * dm0 + dq0 ;
|
|
ptI2.x = ( dq2 - dq1) / ( dm1 - dm2) ;
|
|
ptI2.y = ptI2.x * dm1 + dq1 ;
|
|
// porto i punti in globale e trovo i punti medi
|
|
ptI1.ToGlob( frParab) ;
|
|
ptI2.ToGlob( frParab) ;
|
|
|
|
ptP3 = ( ptP0 + ptI1) / 2 ;
|
|
ptP4 = ( ptP1 + ptI1) / 2 ;
|
|
ptP5 = ( ptP1 + ptI2) / 2 ;
|
|
ptP6 = ( ptP2 + ptI2) / 2 ;
|
|
}
|
|
// setto i punti di controllo di collegamento tra le curve passate in input, per il terzetto di curve selezionate
|
|
if ( g == 0)
|
|
SetControlPoint( n + (s * nDegU) + (nDegU * nSpanU + 1) * (g * 3 + 1), ptP3) ;
|
|
SetControlPoint( n + (s * nDegU) + (nDegU * nSpanU + 1) * (g * 3 + 2), ptP4) ;
|
|
SetControlPoint( n + (s * nDegU) + (nDegU * nSpanU + 1) * (g * 3 + 4), ptP5) ;
|
|
SetControlPoint( n + (s * nDegU) + (nDegU * nSpanU + 1) * (g * 3 + 5), ptP6) ;
|
|
}
|
|
}
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
PNTVECTOR
|
|
SurfBezier::GetAllControlPoints( void) const
|
|
{
|
|
PNTVECTOR vPntCtrl = m_vPtCtrl ;
|
|
return vPntCtrl ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::GetAllPatchesIsocurves( bool bUOrV, ICURVEPOVECTOR& vCrv) const
|
|
{
|
|
// restituisce tutte le isocurve di separazione tra patch in un parametro o nell'altro
|
|
if ( bUOrV) {
|
|
for ( int v = 0 ; v <= m_nSpanV ; ++v)
|
|
vCrv.emplace_back( GetCurveOnU( v)) ;
|
|
}
|
|
else {
|
|
for ( int u = 0 ; u <= m_nSpanU ; ++u)
|
|
vCrv.emplace_back( GetCurveOnV( u)) ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
struct IsoParam {
|
|
int nCrv ;
|
|
double dParam0 ;
|
|
double dParam1 ;
|
|
IsoParam( int _nCrv, double _dParam0, double _dParam1) :
|
|
nCrv(_nCrv), dParam0( _dParam0), dParam1( _dParam1){ } ;
|
|
bool operator < ( IsoParam& b)
|
|
{
|
|
return ( abs(dParam0 - b.dParam0) > EPS_SMALL ? dParam0 < b.dParam0 : dParam1 < b.dParam1) ;
|
|
}
|
|
};
|
|
|
|
typedef vector<IsoParam> ISOPARVECT ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, const BIPNTVECTOR& vCrv)
|
|
{
|
|
// vCrv è il vettore delle isocurve (nel parametro V) che si vogliono forzare per la creazione della rigata tra Curve0 e Curve1
|
|
|
|
// controllo che siano entrambe chiuse o entrambe aperte
|
|
if ( pCurve0->IsClosed() != pCurve1->IsClosed())
|
|
return false ;
|
|
|
|
bool bClosed = pCurve0->IsClosed() ;
|
|
|
|
// converto in bezier la curva iniziale
|
|
CurveComposite CrvU0 ; CrvU0.AddCurve( CurveToBezierCurve(pCurve0)) ;
|
|
if ( ! CrvU0.IsValid())
|
|
return false ;
|
|
CurveComposite CrvU1 ; CrvU1.AddCurve( CurveToBezierCurve(pCurve1)) ;
|
|
if ( ! CrvU1.IsValid())
|
|
return false ;
|
|
int nDegU = 3 ;
|
|
int nDegV = 1 ;
|
|
int nSpanV = 1 ;
|
|
int nLastPoint = nDegU + 1 ;
|
|
bool bRat = false ;
|
|
|
|
PNTVECTOR vPnt0, vPnt1 ;
|
|
Point3d pt ; CrvU0.GetStartPoint( pt) ;
|
|
vPnt0.push_back( pt) ;
|
|
for ( int i = 0 ; i < CrvU0.GetCurveCount() ; ++i) {
|
|
CrvU0.GetCurve(i)->GetEndPoint( pt) ;
|
|
vPnt0.push_back( pt) ;
|
|
}
|
|
CrvU1.GetStartPoint( pt) ;
|
|
vPnt1.push_back( pt) ;
|
|
for ( int i = 0 ; i < CrvU1.GetCurveCount() ; ++i) {
|
|
CrvU1.GetCurve(i)->GetEndPoint( pt) ;
|
|
vPnt1.push_back( pt) ;
|
|
}
|
|
|
|
// associo le isocurve passate in input ai relativi punti sulle due curve che generano la rigata
|
|
INTINTVECTOR vPairs ;
|
|
DBLVECTOR vdSplit0, vdSplit1 ;
|
|
int nSplit0 = 0, nSplit1 = 0 ;
|
|
Point3d ptLast0, ptLast1 ;
|
|
double dLastParam0 = 0, dLastParam1 = 0 ;
|
|
double dLenPrev0 = 0 ,dLenPrev1 = 0 ;
|
|
|
|
// costruisco il vettore delle nuove curve isoparamtriche per la nuova superficie
|
|
bool bFirstAdded = false ;
|
|
int nSpanU0 = CrvU0.GetCurveCount() ;
|
|
int nSpanU1 = CrvU1.GetCurveCount() ;
|
|
ISOPARVECT vIso ;
|
|
for ( int i = 0 ; i < ssize( vCrv) ; ++i) {
|
|
Point3d ptU0 = vCrv[i].first ;
|
|
Point3d ptU1 = vCrv[i].second ;
|
|
double dParam0 ; CrvU0.GetParamAtPoint( ptU0, dParam0) ;
|
|
double dParam1 ; CrvU1.GetParamAtPoint( ptU1, dParam1) ;
|
|
if ( bClosed && ( dParam0 < EPS_SMALL || nSpanU0 - dParam0 < EPS_SMALL) &&
|
|
( dParam1 < EPS_SMALL || nSpanU1 - dParam1 < EPS_SMALL)) {
|
|
if ( ! bFirstAdded) {
|
|
dParam0 = 0 ;
|
|
dParam1 = 0 ;
|
|
bFirstAdded = true ;
|
|
}
|
|
else {
|
|
dParam0 = nSpanU0 ;
|
|
dParam1 = nSpanU1 ;
|
|
}
|
|
}
|
|
vIso.emplace_back( i, dParam0, dParam1) ;
|
|
}
|
|
|
|
sort( vIso.begin(), vIso.end()) ;
|
|
|
|
// scorro vIso per verificare che non ci siano curve che si intersecano
|
|
int c = 0 ;
|
|
dLastParam0 = vIso[c].dParam0 ;
|
|
dLastParam1 = vIso[c].dParam1 ;
|
|
++c ;
|
|
while ( c < ssize( vIso)) {
|
|
if ( vIso[c].dParam0 < dLastParam0 || vIso[c].dParam1 < dLastParam1)
|
|
return false ;
|
|
dLastParam0 = vIso[c].dParam0 ;
|
|
dLastParam1 = vIso[c].dParam1 ;
|
|
++c ;
|
|
}
|
|
|
|
dLastParam0 = 0 ;
|
|
dLastParam1 = 0 ;
|
|
if ( vIso[0].dParam0 > 0 || vIso[0].dParam1 > 0)
|
|
vPairs.emplace_back( 0, 0) ;
|
|
for ( int i = 0 ; i < ssize( vIso) ; ++i) {
|
|
const BIPOINT& pCrv = vCrv[vIso[i].nCrv] ;
|
|
Point3d ptU0 = pCrv.first ;
|
|
Point3d ptU1 = pCrv.second ;
|
|
double& dParam0 = vIso[i].dParam0 ;
|
|
double& dParam1 = vIso[i].dParam1 ;
|
|
// se sono vicino ad un'intero allora considero il parametro intero ( uno split già esistente)
|
|
bool bIntParam0 = false ;
|
|
bool bIntParam1 = false ;
|
|
if ( abs( dParam0 - round( dParam0)) < EPS_SMALL) {
|
|
dParam0 = round( dParam0) ;
|
|
bIntParam0 = true ;
|
|
}
|
|
if ( abs( dParam1 - round( dParam1)) < EPS_SMALL) {
|
|
dParam1 = round( dParam1) ;
|
|
bIntParam1 = true ;
|
|
}
|
|
int nParam0 = int( dParam0) ;
|
|
int nParam1 = int( dParam1) ;
|
|
int nLastParam0 = int( dLastParam0) ;
|
|
int nLastParam1 = int( dLastParam1) ;
|
|
double dLenCurr0 ; CrvU0.GetLengthAtParam( dParam0, dLenCurr0) ;
|
|
double dLenCurr1 ; CrvU1.GetLengthAtParam( dParam1, dLenCurr1) ;
|
|
int nPointsBetween0 = 0 ;
|
|
if ( dParam0 - nLastParam0 > 1) {
|
|
if ( ! bIntParam0)
|
|
nPointsBetween0 = int( dParam0 - nLastParam0) ;
|
|
else
|
|
nPointsBetween0 = int( dParam0 - nLastParam0) - 1 ;
|
|
}
|
|
else
|
|
nPointsBetween0 = 0 ;
|
|
int nPointsBetween1 = 0 ;
|
|
if ( dParam1 - nLastParam1 > 1) {
|
|
if ( ! bIntParam1)
|
|
nPointsBetween1 = int( dParam1 - nLastParam1) ;
|
|
else
|
|
nPointsBetween1 = int( dParam1 - nLastParam1) - 1 ;
|
|
}
|
|
else
|
|
nPointsBetween1 = 0 ;
|
|
if ( nPointsBetween0 > 0 || nPointsBetween1 > 0) {
|
|
// calcolo la parametrizzazione locale dei punti compresi tra le due isoparametriche
|
|
double dLen0 = dLenCurr0 - dLenPrev0 ;
|
|
double dLen1 = dLenCurr1 - dLenPrev1 ;
|
|
DBLVECTOR vdParamPos0 ; vdParamPos0.reserve( nPointsBetween0) ;
|
|
DBLVECTOR vdParamPos1 ; vdParamPos1.reserve( nPointsBetween1) ;
|
|
for ( int k = 0 ; k < nPointsBetween0 ; ++k) {
|
|
double dParamIntermed = 0 ; CrvU0.GetParamAtPoint( vPnt0[ nLastParam0 + 1 + k], dParamIntermed) ;
|
|
double dLen = 0 ; CrvU0.GetLengthAtParam( dParamIntermed, dLen) ;
|
|
dLen -= dLenPrev0 ;
|
|
vdParamPos0.push_back( dLen / dLen0) ;
|
|
}
|
|
vdParamPos0.push_back( 1) ;
|
|
for ( int k = 0 ; k < nPointsBetween1 ; ++k) {
|
|
double dParamIntermed = 0 ; CrvU1.GetParamAtPoint( vPnt1[ nLastParam1 + 1 + k], dParamIntermed) ;
|
|
double dLen = 0 ; CrvU1.GetLengthAtParam( dParamIntermed, dLen) ;
|
|
dLen -= dLenPrev1 ;
|
|
vdParamPos1.push_back( dLen / dLen1) ;
|
|
}
|
|
vdParamPos1.push_back( 1) ;
|
|
|
|
bool bSplitToAdd = true ;
|
|
int c0 = 0, c1 = 0 ;
|
|
while ( bSplitToAdd) {
|
|
if ( c0 > ssize( vdParamPos0) - 1 && c1 > ssize( vdParamPos1) - 1) {
|
|
LOG_DBG_ERR( GetEGkLogger(), "Surf Bez Ruled Guided: error while reparametrizing some section") ;
|
|
return false ;
|
|
}
|
|
// se ho una corrispondenza tra punti ( e non sono alla fine del tratto) allora non aggiungo split
|
|
if ( abs( vdParamPos0[c0] - vdParamPos1[c1]) < EPS_PARAM && vdParamPos0[c0] < 1) {
|
|
++c0 ;
|
|
++c1 ;
|
|
++nLastParam0 ;
|
|
++nLastParam1 ;
|
|
vPairs.emplace_back( nLastParam0 + nSplit0, nLastParam1 + nSplit1) ;
|
|
}
|
|
// se non ho corrispondenza allora aggiungo uno split sulla curva a cui manca il punto corrispondente
|
|
else if ( vdParamPos0[c0] < vdParamPos1[c1]) {
|
|
double dPar ; CrvU1.GetParamAtLength( dLenPrev1 + dLen1 * vdParamPos0[c0], dPar) ;
|
|
if ( abs( dPar - round( dPar)) > EPS_SMALL) {
|
|
vdSplit1.push_back( dPar) ;
|
|
nSplit1 = vdSplit1.size() ;
|
|
}
|
|
else if ( dPar = round( dPar) ; dPar > nLastParam1){
|
|
++ nLastParam1 ;
|
|
}
|
|
++nLastParam0 ;
|
|
vPairs.emplace_back( nLastParam0 + nSplit0, nLastParam1 + nSplit1) ;
|
|
++c0 ;
|
|
}
|
|
else if ( vdParamPos0[c0] > vdParamPos1[c1]) {
|
|
double dPar ; CrvU0.GetParamAtLength( dLenPrev0 + dLen0 * vdParamPos1[c1], dPar) ;
|
|
// se lo split non è in prossimità di una joint già esistente allora lo aggiungo
|
|
if ( abs( dPar - round( dPar)) > EPS_SMALL) {
|
|
vdSplit0.push_back( dPar) ;
|
|
nSplit0 = vdSplit0.size() ;
|
|
}
|
|
else if ( dPar = round( dPar) ; dPar > nLastParam0){
|
|
++ nLastParam0 ;
|
|
}
|
|
++nLastParam1 ;
|
|
vPairs.emplace_back( nLastParam0 + nSplit0, nLastParam1 + nSplit1) ;
|
|
++c1 ;
|
|
}
|
|
bSplitToAdd = ! (c0 == ssize( vdParamPos0) - 1 && c1 == ssize( vdParamPos1) - 1) ;
|
|
}
|
|
}
|
|
|
|
// salvo i dati di questo accoppiamento
|
|
dLenPrev0 = dLenCurr0 ;
|
|
dLenPrev1 = dLenCurr1 ;
|
|
if ( ! bIntParam0 && dParam0 > dLastParam0) {
|
|
vdSplit0.push_back( dParam0) ;
|
|
nSplit0 = vdSplit0.size() ;
|
|
}
|
|
if ( ! bIntParam1 && dParam1 > dLastParam1) {
|
|
vdSplit1.push_back( dParam1) ;
|
|
nSplit1 = vdSplit1.size() ;
|
|
}
|
|
dLastParam0 = dParam0 ;
|
|
dLastParam1 = dParam1 ;
|
|
ptLast0 = ptU0 ;
|
|
ptLast1 = ptU1 ;
|
|
vPairs.emplace_back( nParam0 + nSplit0, nParam1 + nSplit1) ;
|
|
}
|
|
|
|
// applico effettivamente gli split
|
|
int nUnit = 0 ;
|
|
if ( ! vdSplit1.empty())
|
|
nUnit = int( vdSplit1.back()) ;
|
|
for ( int z = int( vdSplit1.size() - 1) ; z >= 0 ; --z) {
|
|
double dSplit = vdSplit1[z] ;
|
|
int nSplit = int( dSplit) ;
|
|
// se sto cercando di fare uno split sulla stessa curva che ho già splittato al passaggio precedente allora devo
|
|
// riscalare
|
|
if ( nSplit == nUnit && z < int( vdSplit1.size() - 1)) {
|
|
dSplit = nSplit + ( dSplit - nSplit) / (vdSplit1[z+1] - nSplit);
|
|
}
|
|
nUnit = nSplit ;
|
|
CrvU1.AddJoint( dSplit) ;
|
|
}
|
|
if ( ! vdSplit0.empty())
|
|
nUnit = int( vdSplit0.back()) ;
|
|
for ( int z = int( vdSplit0.size() - 1) ; z >= 0 ; --z) {
|
|
double dSplit = vdSplit0[z] ;
|
|
int nSplit = int( dSplit) ;
|
|
// se sto cercando di fare uno split sulla stessa curva che ho già splittato al passaggio precedente allora devo
|
|
// riscalare
|
|
if ( nSplit == nUnit && z < int( vdSplit0.size() - 1)) {
|
|
dSplit = nSplit + ( dSplit - nSplit) / (vdSplit0[z+1] - nSplit);
|
|
}
|
|
nUnit = nSplit ;
|
|
CrvU0.AddJoint( dSplit) ;
|
|
}
|
|
|
|
nSpanU0 = CrvU0.GetCurveCount() ;
|
|
nSpanU1 = CrvU1.GetCurveCount() ;
|
|
// aggiungo l'ultima coppia
|
|
vPairs.emplace_back( nSpanU0, nSpanU1) ;
|
|
|
|
// trovo il numero di span che dovrà avere la superficie
|
|
int nSpanU = int(vPairs.size()) - 1 ;
|
|
|
|
int nSecondRowInd = nDegU * nSpanU + 1 ;
|
|
// inizializzo la superficie
|
|
Init( nDegU, nDegV, nSpanU, nSpanV, bRat) ;
|
|
|
|
// aggiungo i punti di controllo scorrendo in contemporanea le due curve
|
|
int nAddedSpan = 0 ;
|
|
int nCrv0 = 0 ;
|
|
int nCrv1 = 0 ;
|
|
bool bLast0 = false ;
|
|
bool bLast1 = false ;
|
|
|
|
bool bOk = true ;
|
|
while ( nAddedSpan < nSpanU && bOk) {
|
|
nCrv0 = vPairs[nAddedSpan].first ;
|
|
nCrv1 = vPairs[nAddedSpan].second ;
|
|
bool bRep0 = nCrv0 < nSpanU0 ? nCrv0 == vPairs[nAddedSpan + 1].first : nCrv0 == vPairs[nAddedSpan - 1].first ;
|
|
bool bRep1 = nCrv1 < nSpanU1 ? nCrv1 == vPairs[nAddedSpan + 1].second : nCrv1 == vPairs[nAddedSpan - 1].second ;
|
|
if ( nCrv0 >= nSpanU0){
|
|
nCrv0 = nSpanU0 - 1 ;
|
|
bLast0 = true ;
|
|
}
|
|
if ( nCrv1 >= nSpanU1) {
|
|
nCrv1 = nSpanU1 - 1 ;
|
|
bLast1 = true ;
|
|
}
|
|
const ICurveBezier* pSubCrv0 = GetCurveBezier( CrvU0.GetCurve( nCrv0)) ;
|
|
for ( int i = nAddedSpan == 0 ? 0 : 1 ; i < nLastPoint ; ++ i) {
|
|
int nInd = i ;
|
|
// se ho una ripetizione allora riaggiungo l'ultimo punto. Se sono ancora alla curva 0 invece devo aggiungere lo start della curva U0
|
|
if ( bRep0 || bLast0)
|
|
nInd = ! bLast0 ? 0 : nDegU ;
|
|
if ( ! bRat)
|
|
bOk = SetControlPoint( nAddedSpan * nDegU + i, pSubCrv0->GetControlPoint( nInd)) ;
|
|
else
|
|
bOk = SetControlPoint( nAddedSpan * nDegU + i, pSubCrv0->GetControlPoint( nInd), pSubCrv0->GetControlWeight( nInd)) ;
|
|
}
|
|
const ICurveBezier* pSubCrv1 = GetCurveBezier( CrvU1.GetCurve( nCrv1)) ;
|
|
for ( int i = nAddedSpan == 0 ? 0 : 1 ; i < nLastPoint ; ++ i) {
|
|
int nInd = i ;
|
|
// se ho una ripetizione allora riaggiungo l'ultimo punto. Se sono ancora alla curva 0 invece devo aggiungere lo start della curva U1
|
|
if ( bRep1 || bLast1)
|
|
nInd = ! bLast1 ? 0 : nDegU ;
|
|
if ( ! bRat)
|
|
bOk = SetControlPoint( nSecondRowInd + nAddedSpan * nDegU + i, pSubCrv1->GetControlPoint( nInd)) ;
|
|
else
|
|
bOk = SetControlPoint( nSecondRowInd + nAddedSpan * nDegU + i, pSubCrv1->GetControlPoint( nInd), pSubCrv1->GetControlWeight( nInd)) ;
|
|
}
|
|
++ nAddedSpan ;
|
|
}
|
|
|
|
#if SAVERULEDGUIDEDISO
|
|
//debug
|
|
vector<IGeoObj*> vGeo ;
|
|
ICURVEPOVECTOR vCrvIso ;
|
|
GetAllPatchesIsocurves( false, vCrvIso) ;
|
|
for ( int i = 0 ; i < ssize( vCrvIso) ; ++i) {
|
|
vGeo.push_back( vCrvIso[i]->Clone()) ;
|
|
}
|
|
vector<Color> vCol( ssize( vCrvIso)) ;
|
|
fill( vCol.begin(), vCol.end(), Color( 255,0,128)) ;
|
|
SaveGeoObj( vGeo, vCol, "D:/Temp/bezier/ruled/isoCurves.nge") ;
|
|
//debug
|
|
|
|
vGeo.clear() ;
|
|
vGeo.push_back( CrvU0.Clone()) ;
|
|
vGeo.push_back( CrvU1.Clone()) ;
|
|
vCol.clear() ;
|
|
vCol.push_back(Color(0,64,128)) ;
|
|
vCol.push_back(Color(128,64,0)) ;
|
|
SaveGeoObj( vGeo, vCol, "D:/Temp/bezier/ruled/NewCurves.nge") ;
|
|
#endif
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::RemoveCollapsedSpans( void)
|
|
{
|
|
double dTol = EPS_SMALL ;
|
|
//controllo se ho delle span collassate e le rimuovo
|
|
if ( m_nSpanU > 1 || m_nSpanV > 1) {
|
|
CalcPoles() ;
|
|
if ( ! m_vbPole[2]) {
|
|
// scorro i punti della prima riga
|
|
INTVECTOR vnCollapsedSpan ;
|
|
for ( int i = 0 ; i < m_nSpanU ; ++i) {
|
|
bool bSamePoint = true ;
|
|
Point3d ptFirst = m_vPtCtrl[m_nDegU * i] ;
|
|
// cerco se trovo tutti i punti in U coincidenti in una delle Span
|
|
for ( int j = 1 ; j < m_nDegU + 1 && bSamePoint ; ++j) {
|
|
if ( ! AreSamePointEpsilon( ptFirst, m_vPtCtrl[m_nDegU * i + j], dTol))
|
|
bSamePoint = false ;
|
|
}
|
|
if ( bSamePoint) {
|
|
// se trovo un'altra riga collassata do per scontato che tutta span sia collassata
|
|
ptFirst = m_vPtCtrl[GetInd( m_nDegU * i, 1)] ;
|
|
for ( int j = 1 ; j < m_nDegU + 1 && bSamePoint ; ++j) {
|
|
if ( ! AreSamePointEpsilon( ptFirst, m_vPtCtrl[GetInd( m_nDegU * i + j, 1)], dTol))
|
|
bSamePoint = false ;
|
|
}
|
|
if ( bSamePoint)
|
|
vnCollapsedSpan.push_back( i) ;
|
|
}
|
|
}
|
|
int nOldSpanU = m_nSpanU ;
|
|
if ( ! vnCollapsedSpan.empty()) {
|
|
// cancello le span che risultano collassate
|
|
int nNewSpanU = m_nSpanU - ssize( vnCollapsedSpan) ;
|
|
int nNewDim = ( m_nDegU * nNewSpanU + 1) * ( m_nDegV * m_nSpanV + 1) ;
|
|
PNTVECTOR vNewCtrlPnt( nNewDim) ;
|
|
DBLVECTOR vNewWeight( nNewDim) ;
|
|
int nCurrSkipInd = -1 ;
|
|
int nCurrSkip = -1 ;
|
|
for ( int nIndV = 0 ; nIndV < m_nSpanV * m_nDegV + 1 ; ++nIndV) {
|
|
nCurrSkipInd = 0 ;
|
|
nCurrSkip = vnCollapsedSpan[nCurrSkipInd] ;
|
|
for ( int i = 0 ; i < m_nSpanU ; ++i) {
|
|
if ( i != nCurrSkip) {
|
|
for ( int j = ( i - nCurrSkipInd) ==0 ? 0 : 1 ; j < m_nDegU + 1 ; ++j) {
|
|
vNewCtrlPnt[nIndV * ( m_nDegU * nNewSpanU + 1) + (i - nCurrSkipInd) * m_nDegU + j] = m_vPtCtrl[GetInd( m_nDegU * i + j, nIndV)] ;
|
|
if ( m_bRat) {
|
|
vNewWeight[nIndV * ( m_nDegU * nNewSpanU + 1) + (i - nCurrSkipInd) * m_nDegU + j] = m_vWeCtrl[GetInd( m_nDegU * i + j, nIndV)] ;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
++nCurrSkipInd ;
|
|
if ( nCurrSkipInd > ssize( vnCollapsedSpan) - 1)
|
|
nCurrSkip = -1 ;
|
|
else
|
|
nCurrSkip = vnCollapsedSpan[nCurrSkipInd] ;
|
|
}
|
|
}
|
|
}
|
|
// aggiorno i dati della superficie
|
|
// vettori dei punti e numero di span
|
|
ISurfFlatRegion* pSFRTrim = nullptr ;
|
|
bool bTrimmed = m_bTrimmed ;
|
|
if ( bTrimmed) {
|
|
pSFRTrim = GetTrimRegion() ;
|
|
m_pTrimReg = nullptr ;
|
|
}
|
|
Init( m_nDegU, m_nDegV, nNewSpanU, m_nSpanV, m_bRat) ;
|
|
m_vPtCtrl = vNewCtrlPnt ;
|
|
if ( m_bRat)
|
|
m_vWeCtrl = vNewWeight ;
|
|
if ( bTrimmed) {
|
|
// elimino le span di troppo dallo spazio parametrico
|
|
PtrOwner<ISurfFlatRegion> pNewTrim( pSFRTrim->Clone()) ;
|
|
for ( int i = ssize( vnCollapsedSpan) - 1 ; i >= 0 ; --i) {
|
|
int nSpan = vnCollapsedSpan[i] ;
|
|
// tolgo tutta la parte a destra della colonna da togliere
|
|
PtrOwner<ISurfFlatRegion> pSFRCut ( GetSurfFlatRegionRectangle( ( nOldSpanU - nSpan) * SBZ_TREG_COEFF, m_nSpanV * SBZ_TREG_COEFF + 2)) ;
|
|
if ( nSpan != 0) {
|
|
pSFRCut->Translate( Vector3d( nSpan * SBZ_TREG_COEFF, -1)) ;
|
|
pNewTrim->Subtract( *pSFRCut) ;
|
|
}
|
|
if ( pNewTrim->IsValid()) {
|
|
// ritaglio dal parametrico originale la parte a destra della colonna da eliminare e la incollo alla parte a sinistra
|
|
PtrOwner<ISurfFlatRegion> pRightPart( pSFRTrim->Clone()) ;
|
|
pSFRCut.Set( GetSurfFlatRegionRectangle( ( nSpan + 1) * SBZ_TREG_COEFF, m_nSpanV * SBZ_TREG_COEFF + 2)) ;
|
|
pSFRCut->Translate( Vector3d( nSpan * SBZ_TREG_COEFF, -1)) ;
|
|
if ( pRightPart->Subtract( *pSFRCut) && pRightPart->IsValid()) {
|
|
if ( ! pNewTrim->Add( *pRightPart) || ! pNewTrim->IsValid())
|
|
break ;
|
|
}
|
|
}
|
|
else
|
|
break ;
|
|
}
|
|
SetTrimRegion( *pSFRTrim) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( ! m_vbPole[1]) {
|
|
// scorro i punti della prima colonna
|
|
INTVECTOR vnCollapsedSpan ;
|
|
for ( int i = 0 ; i < m_nSpanV ; ++i) {
|
|
bool bSamePoint = true ;
|
|
Point3d ptFirst = m_vPtCtrl[GetInd( 0, i * m_nDegV)] ;
|
|
// cerco se trovo tutti i punti in U coincidenti in una delle Span
|
|
for ( int j = 1 ; j < m_nDegV + 1 && bSamePoint ; ++j) {
|
|
if ( ! AreSamePointEpsilon( ptFirst, m_vPtCtrl[GetInd( 0, i * m_nDegV + j)], dTol))
|
|
bSamePoint = false ;
|
|
}
|
|
if ( bSamePoint) {
|
|
// se trovo un'altra colonna collassata do per scontato che tutta span sia collassata
|
|
ptFirst = m_vPtCtrl[GetInd( 1, i * m_nDegV)] ;
|
|
for ( int j = 1 ; j < m_nDegV + 1 && bSamePoint ; ++j) {
|
|
if ( ! AreSamePointEpsilon( ptFirst, m_vPtCtrl[GetInd( 1, i * m_nDegV + j)], dTol))
|
|
bSamePoint = false ;
|
|
}
|
|
if ( bSamePoint)
|
|
vnCollapsedSpan.push_back( i) ;
|
|
}
|
|
}
|
|
int nOldSpanV = m_nSpanV ;
|
|
if ( ! vnCollapsedSpan.empty()) {
|
|
// cancello le span che risultano collassate
|
|
int nNewSpanV = m_nSpanV - ssize( vnCollapsedSpan) ;
|
|
int nNewDim = ( m_nDegU * m_nSpanU + 1) * ( m_nDegV * nNewSpanV + 1) ;
|
|
PNTVECTOR vNewCtrlPnt( nNewDim) ;
|
|
DBLVECTOR vNewWeight( nNewDim) ;
|
|
int nCurrSkipInd = 0 ;
|
|
int nCurrSkip = vnCollapsedSpan[nCurrSkipInd] ;
|
|
for ( int nIndV = 0 ; nIndV < m_nSpanV * m_nDegV + 1 ; ++nIndV) {
|
|
if ( nIndV / m_nDegV != nCurrSkip) {
|
|
for ( int i = 0 ; i < m_nSpanU ; ++i) {
|
|
for ( int j = i==0 ? 0 : 1 ; j < m_nDegU + 1 ; ++j) {
|
|
vNewCtrlPnt[( nIndV - ( nCurrSkipInd * m_nDegV)) * ( m_nDegU * m_nSpanU + 1) + i * m_nDegU + j] = m_vPtCtrl[GetInd( m_nDegU * i + j, nIndV)] ;
|
|
if ( m_bRat) {
|
|
vNewWeight[( nIndV - ( nCurrSkipInd * m_nDegV)) * ( m_nDegU * m_nSpanU + 1) + i * m_nDegU + j] = m_vWeCtrl[GetInd( m_nDegU * i + j, nIndV)] ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
nIndV += m_nDegV - 1 ;
|
|
++nCurrSkipInd ;
|
|
if ( nCurrSkipInd > ssize( vnCollapsedSpan) - 1)
|
|
nCurrSkip = -1 ;
|
|
else
|
|
nCurrSkip = vnCollapsedSpan[nCurrSkipInd] ;
|
|
}
|
|
}
|
|
// aggiorno i dati della superficie
|
|
// vettori dei punti e numero di span
|
|
ISurfFlatRegion* pSFRTrim = nullptr ;
|
|
bool bTrimmed = m_bTrimmed ;
|
|
if ( bTrimmed) {
|
|
pSFRTrim = GetTrimRegion() ;
|
|
m_pTrimReg = nullptr ;
|
|
}
|
|
Init( m_nDegU, m_nDegV, m_nSpanU, nNewSpanV, m_bRat) ;
|
|
m_vPtCtrl = vNewCtrlPnt ;
|
|
if ( m_bRat)
|
|
m_vWeCtrl = vNewWeight ;
|
|
if ( bTrimmed) {
|
|
// elimino le span di troppo dallo spazio parametrico
|
|
PtrOwner<ISurfFlatRegion> pNewTrim( pSFRTrim->Clone()) ;
|
|
for ( int i = ssize( vnCollapsedSpan) - 1 ; i >= 0 ; --i) {
|
|
int nSpan = vnCollapsedSpan[i] ;
|
|
// tolgo tutta la parte a sopra la riga da togliere
|
|
PtrOwner<ISurfFlatRegion> pSFRCut ( GetSurfFlatRegionRectangle( m_nSpanU * SBZ_TREG_COEFF + 2, ( nOldSpanV - nSpan) * SBZ_TREG_COEFF)) ;
|
|
if ( nSpan != 0) {
|
|
pSFRCut->Translate( Vector3d( -1, nSpan * SBZ_TREG_COEFF)) ;
|
|
pNewTrim->Subtract( *pSFRCut) ;
|
|
}
|
|
if ( pNewTrim->IsValid()) {
|
|
// ritaglio dal parametrico originale la parte sopra la riga da eliminare e la incollo alla parte sotto la riga
|
|
PtrOwner<ISurfFlatRegion> pUpperPart( pSFRTrim->Clone()) ;
|
|
pSFRCut.Set( GetSurfFlatRegionRectangle( m_nSpanU * SBZ_TREG_COEFF + 2, ( nSpan + 1) * SBZ_TREG_COEFF)) ;
|
|
pSFRCut->Translate( Vector3d( -1, nSpan * SBZ_TREG_COEFF)) ;
|
|
if ( pUpperPart->Subtract( *pSFRCut) && pUpperPart->IsValid()) {
|
|
if ( ! pNewTrim->Add( *pUpperPart) || ! pNewTrim->IsValid())
|
|
break ;
|
|
}
|
|
}
|
|
else
|
|
break ;
|
|
}
|
|
SetTrimRegion( *pSFRTrim) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::SwapParameters( void)
|
|
{
|
|
// inverto il parametro U con il parametro V
|
|
// salvo i vecchi dati
|
|
int nSpanU = m_nSpanV ;
|
|
int nSpanV = m_nSpanU ;
|
|
int nDegU = m_nDegV ;
|
|
int nDegV = m_nDegU ;
|
|
bool bTrimmed = m_bTrimmed ;
|
|
PtrOwner<ISurfFlatRegion> pSFRTRim ;
|
|
if ( m_bTrimmed) {
|
|
pSFRTRim.Set( GetTrimRegion()) ;
|
|
m_pTrimReg = nullptr ;
|
|
}
|
|
|
|
// creo il vettore dei punti di controllo
|
|
PNTVECTOR vNewCtrlPt( GetDim()) ;
|
|
DBLVECTOR vNewWeight( GetDim()) ;
|
|
for ( int j = 0 ; j < m_nDegV * m_nSpanV + 1 ; ++j) {
|
|
for ( int i = 0 ; i < m_nDegU * m_nSpanU + 1 ; ++ i) {
|
|
vNewCtrlPt[i * ( nDegU * nSpanU + 1) + j] = m_vPtCtrl[GetInd(i,j)] ;
|
|
if ( m_bRat)
|
|
vNewWeight[i * ( nDegU * nSpanU + 1) + j] = m_vWeCtrl[GetInd(i,j)] ;
|
|
}
|
|
}
|
|
|
|
Init( nDegU, nDegV, nSpanU, nSpanV, m_bRat) ;
|
|
if ( bTrimmed) {
|
|
pSFRTRim->Mirror( ORIG, Vector3d(1,-1)) ;
|
|
SetTrimRegion( *pSFRTRim) ;
|
|
}
|
|
m_vPtCtrl = vNewCtrlPt ;
|
|
m_vWeCtrl = vNewWeight ;
|
|
|
|
return true ;
|
|
}
|