6efb3a6e7f
- corretta funzione di trim di sup. di Bezier con piani, in zone di punti di polo.
2543 lines
95 KiB
C++
2543 lines
95 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 "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/EGkDistPointSurfTm.h"
|
|
#include "/EgtDev/Extern/Eigen/Dense"
|
|
#include "/EgtDev/Include/EGkCurveComposite.h"
|
|
#include "/EgtDev/Include/EGkGeoObjSave.h"
|
|
#include <limits>
|
|
|
|
using namespace std ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
GEOOBJ_REGISTER( SRF_BEZIER, NGE_S_BEZ, SurfBezier) ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
SurfBezier::SurfBezier( void)
|
|
: m_pSTM( 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}
|
|
{
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
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 ;
|
|
|
|
// 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())
|
|
return false ;
|
|
}
|
|
// 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())
|
|
return false ;
|
|
}
|
|
ResetAuxSurf() ;
|
|
// assegno la regione di trim
|
|
m_bTrimmed = true ;
|
|
if ( m_pTrimReg != nullptr ) {
|
|
if ( ! m_pTrimReg->Intersect( *pSfrTrim))
|
|
return false ;
|
|
}
|
|
else
|
|
m_pTrimReg = GetBasicSurfFlatRegion( Release( pSfrTrim)) ;
|
|
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::GetCentroid( Point3d& ptCen) const
|
|
{
|
|
// controllo parametro di ritorno
|
|
if ( &ptCen == nullptr)
|
|
return false ;
|
|
// inizio con centro nell'origine
|
|
ptCen = ORIG ;
|
|
// calcolo il baricentro
|
|
if ( m_pSTM == nullptr)
|
|
if ( ! GetAuxSurf())
|
|
return false ;
|
|
return m_pSTM->GetCentroid( ptCen) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
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 delle due derivate � piccola, mi sposto lungo il relativo parametro e uso le tangenti
|
|
if ( pvtDerU->Len() < EPS_SMALL && pvtDerV->Len() > 10 * EPS_SMALL) {
|
|
double dCoeff = ( dU - 1000 * EPS_PARAM < 0. ? 1 : -1) ;
|
|
double dUm = dU + 1000 * EPS_PARAM * dCoeff ;
|
|
Point3d ptTmp ;
|
|
Vector3d vtTmpU, vtTmpV ;
|
|
GetPointD1D2( dUm, dV, nUs, nVs, ptTmp, &vtTmpU, &vtTmpV) ;
|
|
vtN = ( *pvtDerV ^ vtTmpV) * dCoeff ;
|
|
if ( vtN.Normalize())
|
|
return true ;
|
|
}
|
|
if ( pvtDerU->Len() > 10 * EPS_SMALL && pvtDerV->Len() < EPS_SMALL) {
|
|
double dCoeff = ( dV - 1000 * EPS_PARAM < 0. ? 1 : -1) ;
|
|
double dVm = dV + 1000 * EPS_PARAM * dCoeff ;
|
|
Point3d ptTmp ;
|
|
Vector3d vtTmpU, vtTmpV ;
|
|
GetPointD1D2( dU, dVm, nUs, nVs, ptTmp, &vtTmpU, &vtTmpV) ;
|
|
vtN = ( vtTmpU ^ *pvtDerU) * dCoeff ;
|
|
if ( vtN.Normalize())
|
|
return true ;
|
|
}
|
|
|
|
// ricalcolo con una piccola variazione di entrambi i parametri
|
|
double dUm ;
|
|
if ( dU - 100 * EPS_PARAM < 0.)
|
|
dUm = dU + 100 * EPS_PARAM ;
|
|
else
|
|
dUm = dU - 100 * EPS_PARAM ;
|
|
double dVm ;
|
|
if ( dV - 100 * EPS_PARAM < 0.)
|
|
dVm = dV + 100 * EPS_PARAM ;
|
|
else
|
|
dVm = dV - 100 * EPS_PARAM ;
|
|
Point3d ptTmp ;
|
|
GetPointD1D2( dUm, dVm, nUs, nVs, ptTmp, pvtDerU, pvtDerV) ;
|
|
vtN = *pvtDerU ^ *pvtDerV ;
|
|
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() ;
|
|
}
|
|
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 ;
|
|
// 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) {
|
|
m_bTrimmed = true ;
|
|
// 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 ;
|
|
}
|
|
|
|
// eseguo validazione
|
|
return Validate() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::Validate( void)
|
|
{
|
|
if ( m_nStatus == TO_VERIFY)
|
|
m_nStatus = ( ( m_nDegU * m_nDegV > 0 && m_vPtCtrl.size() > 0) ? 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 ;
|
|
|
|
// 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 ;
|
|
|
|
// 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 ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
const SurfTriMesh*
|
|
SurfBezier::GetAuxSurf( void) const
|
|
{
|
|
// la superficie deve essere validata
|
|
if ( m_nStatus != OK) {
|
|
ResetAuxSurf() ;
|
|
return nullptr ;
|
|
}
|
|
// se già calcolata, la restituisco
|
|
if ( m_pSTM != nullptr)
|
|
return m_pSTM ;
|
|
|
|
// costruttore della superficie
|
|
POLYLINEMATRIX vvPL ;
|
|
//POLYLINEVECTOR vPL ; // per usare i polygon basic
|
|
Tree Tree( this, true) ;
|
|
BIPNTVECTOR vTrees ;
|
|
Tree.GetIndependentTrees( vTrees) ;
|
|
bool bTest = false ; // per debug
|
|
for ( int i = 0 ; i < (int) vTrees.size() ; ++ i) {
|
|
Point3d ptMin = std::get<0>( vTrees[i]) ;
|
|
Point3d ptMax = std::get<1>( vTrees[i]) ;
|
|
Tree.SetSurf( this, true, ptMin, ptMax) ;
|
|
if ( bTest) {
|
|
Tree.BuildTree_test() ; // per debug
|
|
//Tree.BuildTree( 5 * LIN_TOL_FINE, 1) ; // per debug
|
|
Tree.SetTestMode() ;
|
|
}
|
|
else {
|
|
Tree.BuildTree( 5 * LIN_TOL_FINE, 0.1) ;
|
|
}
|
|
Tree.GetPolygons( vvPL) ;
|
|
|
|
//Tree.GetPolygonsBasic( vPL) ; // per usare i polygon basic
|
|
}
|
|
//// per usare i polygon basic//////////////////////
|
|
//for (int k = 0 ; k < (int)vPL.size(); ++k) {
|
|
// vvPL.emplace_back() ;
|
|
// vvPL.back().push_back(vPL[k]) ;
|
|
//}
|
|
//// per usare i polygon basic///////////////////
|
|
|
|
|
|
/////////////////// così facendo sto recuperando gli Edge e la chiusura solo dell'ULTIMO TREE analizzato!!!!! (in caso di trim che creano più chunk analizzo più tree separatamente)///////////////
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// aggiorno la chiusura della superficie
|
|
m_bClosedU = Tree.IsClosedU() ;
|
|
m_bClosedV = Tree.IsClosedV() ;
|
|
//m_vbPole = Tree.GetPoles() ;
|
|
|
|
// salvo i bordi in 3d, che servono in caso si voglia trimmare la superficie DOPO aver costruito la trimesh ausiliaria
|
|
POLYLINEVECTOR vPLEdges ;
|
|
Tree.GetEdge3D( vPLEdges) ;
|
|
bool bComposed = true ;
|
|
for ( int i= 0 ; i < int( vPLEdges.size()); ++i) {
|
|
m_vCCEdge.emplace_back( CreateBasicCurveComposite()) ;
|
|
if ( ! m_vCCEdge.back()->FromPolyLine( vPLEdges[i]))
|
|
bComposed = false ;
|
|
}
|
|
if ( ! bComposed)
|
|
m_vPLEdge = vPLEdges ;
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// qui non sarebbe male stampare un messaggio di errore nel log se avevo un'area da disegnare ma non sono usciti dei poligoni
|
|
if ( int(vvPL.size()) == 0)
|
|
LOG_DBG_ERR( GetEGkLogger(), "ERROR : Bezier Surface couldn't be triangulated, hence wasn't drawn") ;
|
|
|
|
StmFromTriangleSoup stmSoup ;
|
|
if ( ! stmSoup.Start())
|
|
return nullptr ;
|
|
|
|
// prendo i punti di ogni polyline dell'albero, li triangolo e li porto in 3d
|
|
for ( POLYLINEVECTOR vPL : vvPL) {
|
|
PNTVECTOR vPnt ;
|
|
INTVECTOR vTria ;
|
|
Triangulate Tri ;
|
|
if ( ! Tri.Make( vPL, vPnt, vTria))
|
|
return nullptr ;
|
|
|
|
// porto i punti in 3d
|
|
PNTVECTOR vPnt3d ;
|
|
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 ;
|
|
}
|
|
}
|
|
|
|
// la salvo
|
|
if ( ! stmSoup.End())
|
|
return nullptr ;
|
|
m_pSTM = GetBasicSurfTriMesh( stmSoup.GetSurf()) ;
|
|
|
|
return m_pSTM ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::GetLeaves( vector<tuple<int, Point3d, Point3d>>& vLeaves) const
|
|
{
|
|
Tree Tree( this, true) ;
|
|
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, true, ptMin, ptMax) ;
|
|
bool bTest = false ; // per debug
|
|
if ( bTest) {
|
|
Tree.BuildTree_test() ; // per debug
|
|
//Tree.BuildTree( 5 * LIN_TOL_FINE, 1) ; // per debug
|
|
}
|
|
else {
|
|
Tree.BuildTree( 5 * LIN_TOL_FINE, 0.1) ;
|
|
}
|
|
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 ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
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() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
ICurveComposite*
|
|
SurfBezier::UnprojectCurveFromStm( const ICurveComposite* pCC) const
|
|
{
|
|
// do per scontato che la compo sia una spezzata, visto che arriva dall'intersezione tra un piano e una trimesh
|
|
|
|
const ICurve* pCrv0 = pCC->GetCurve( 0) ;
|
|
PolyLine pl ;
|
|
Point3d pt3D, pt2D ; pCrv0->GetStartPoint( pt3D) ;
|
|
DistPointSurfTm distPtStm0( pt3D, *GetAuxSurf()) ;
|
|
// aggiungo il primo punto
|
|
int nTriaIndex ; distPtStm0.GetMinDistTriaIndex( nTriaIndex) ;
|
|
// passo anche i riferimenti del prossimo punto
|
|
Point3d pt3DEnd ; pCrv0->GetEndPoint( pt3DEnd) ;
|
|
DistPointSurfTm distPtStm0End( pt3DEnd, *GetAuxSurf()) ;
|
|
int nTriaIndexNext = -1 ;
|
|
distPtStm0End.GetMinDistTriaIndex( nTriaIndexNext) ;
|
|
if ( ! UnprojectPointFromStm(nTriaIndex, pt3D, pt2D, 5, pt3DEnd, nTriaIndexNext))
|
|
return nullptr ;
|
|
//if ( ! UnprojectPointFromStm(nTriaIndex, pt3D, pt2D)) {
|
|
// Point3d pt3DEnd ; pCrv0->GetEndPoint( pt3DEnd) ;
|
|
// DistPointSurfTm distPtStm0End( pt3DEnd, *GetAuxSurf()) ;
|
|
// int nTriaIndexNext = -1 ;
|
|
// distPtStm0End.GetMinDistTriaIndex( nTriaIndexNext) ;
|
|
// if ( ! UnprojectPointFromStm(nTriaIndex, pt3D, pt2D, 5, nTriaIndexNext))
|
|
// return nullptr ;
|
|
// nTriaIndex = nTriaIndexNext ;
|
|
//}
|
|
pl.AddUPoint( 0, pt2D) ;
|
|
// aggiungo tutti i successivi
|
|
int nTriaIndexPrev = nTriaIndex ;
|
|
for ( int i = 0 ; i < int( pCC->GetCurveCount()) ; ++i) {
|
|
const ICurve* pCrv = pCC->GetCurve( i) ;
|
|
Point3d pt3DPrev = pt3D ;
|
|
pCrv->GetEndPoint( pt3D) ;
|
|
DistPointSurfTm distPtStm( pt3D, *GetAuxSurf()) ;
|
|
distPtStm.GetMinDistTriaIndex( nTriaIndex) ;
|
|
if ( ! UnprojectPointFromStm( nTriaIndex, pt3D, pt2D, 5, pt3DPrev, nTriaIndexPrev))
|
|
return nullptr ;
|
|
pl.AddUPoint( i, pt2D) ;
|
|
nTriaIndexPrev = nTriaIndex ;
|
|
}
|
|
PtrOwner<ICurveComposite> pCC2D ( CreateCurveComposite()) ;
|
|
pCC2D->FromPolyLine( pl) ;
|
|
return Release( pCC2D) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::AddCurveCompoToCuts( ICurveComposite* pCrvCompo, ICRVCOMPOPOVECTOR& vpCCOpen, ICRVCOMPOPOVECTOR& vpCCClosed, double dToler)
|
|
{
|
|
// 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
|
|
PtrOwner<ICurveComposite> pCC( UnprojectCurveFromStm( pCrvCompo)) ;
|
|
if ( IsNull( pCC))
|
|
return false ;
|
|
|
|
// le curve aperte le tengo da parte per giuntarle alla fine col bordo
|
|
if ( ! pCC->IsClosed())
|
|
vpCCOpen.emplace_back( Release( pCC)) ;
|
|
// le curve chiuse le metto tutte insieme subito
|
|
else
|
|
vpCCClosed.emplace_back( Release( pCC)) ;
|
|
return true ;
|
|
}
|
|
|
|
typedef tuple<int,int,int> TRINT ;
|
|
|
|
//static bool operator==(TRINT& ta, TRINT& tb)
|
|
//{
|
|
// return get<0>(ta) == get<0>(tb) && get<1>(ta) == get<1>(tb) && get<2>(ta) == get<2>(tb) ;
|
|
//}
|
|
|
|
template<>
|
|
struct hash<TRINT> {
|
|
std::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) ;
|
|
}
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
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
|
|
|
|
PNTVECTOR vPnt ;
|
|
BIPNTVECTOR vBPnt ;
|
|
TRIA3DVECTOR vTria ;
|
|
//// con queste righe funzionano anche i tagli multipli////////////////////////////////////////////////
|
|
//bool bMod = false ;
|
|
//// ATTENZIONE!!!!! ad ogni "return false" in questa funzione dovrei reimpostare "m_bTrimmed = true" se bMod == true///////////////////////////////////////////////////
|
|
//if ( m_bTrimmed) {
|
|
// m_bTrimmed = false ;
|
|
// ResetAuxSurf() ;
|
|
// bMod = true ;
|
|
//}
|
|
//////i tagli multipli////////////////////////////////////////////////
|
|
IntersPlaneSurfTm( plPlane, *GetAuxSurf(), vPnt, vBPnt, vTria) ;
|
|
|
|
// concateno le curve 3d
|
|
ChainCurves chainC ;
|
|
double dToler = 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 ;
|
|
|
|
// debug/////////////////////////////////////////////////////////
|
|
//vector<IGeoObj*> vGeoObj ;
|
|
//vGeoObj.push_back( static_cast<IGeoObj*>(vCCEdge[1])) ;
|
|
//vGeoObj.push_back( static_cast<IGeoObj*>(vCCEdge[3])) ;
|
|
//SaveGeoObj( vGeoObj, "D:\\Temp\\inters\\sphere_3d_edges.nge") ;
|
|
// debug/////////////////////////////////////////////////////////
|
|
|
|
// 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 ;
|
|
bool bPrevLineThroughEdge = false ;
|
|
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)) ;
|
|
// se la superficie è chiusa devo controllare se sto attraversando un edge con un trim
|
|
if ( (m_bClosedU || m_bClosedV) && ! bPrevLineThroughEdge) {
|
|
IntersCurveCurve icc0( *pLine, *m_vCCEdge[0]) ;
|
|
IntersCurveCurve icc1( *pLine, *m_vCCEdge[1]) ;
|
|
IntersCurveCurve icc2( *pLine, *m_vCCEdge[2]) ;
|
|
IntersCurveCurve icc3( *pLine, *m_vCCEdge[3]) ;
|
|
// se non ho intersezioni proseguo aggiungendo il punto
|
|
if ( icc0.GetIntersCount() == 0 &&
|
|
icc1.GetIntersCount() == 0 &&
|
|
icc2.GetIntersCount() == 0 &&
|
|
icc3.GetIntersCount() == 0) {
|
|
// se non ho intersezioni con gli edge posso aggiungere semplicemente alla compo
|
|
bAdded = bAdded && pCrvCompo->AddCurve( pLine, true, dToler) ;
|
|
ptNear = ( bAdded ? ptEnd : ptStart) ;
|
|
}
|
|
else {
|
|
// recupero la prima intersezione che trovo
|
|
// se ho intersezioni multiple è perché sono edge sovrapposti
|
|
IntCrvCrvInfo iccInfo ;
|
|
if ( icc0.GetIntersCount() != 0)
|
|
icc0.GetIntCrvCrvInfo( 0, iccInfo) ;
|
|
else if ( icc1.GetIntersCount() != 0)
|
|
icc1.GetIntCrvCrvInfo( 0, iccInfo) ;
|
|
else if ( icc2.GetIntersCount() != 0)
|
|
icc2.GetIntCrvCrvInfo( 0, iccInfo) ;
|
|
else if ( icc3.GetIntersCount() != 0)
|
|
icc3.GetIntCrvCrvInfo( 0, iccInfo) ;
|
|
|
|
ICurveLine* pCLPart1 ( CreateCurveLine()) ;
|
|
// spezzo la linea che avrei dovuto inserire, facendola finire dove ho l'intersezione con un edge della cella root
|
|
Vector3d vtDir ; pLine->GetStartDir( vtDir) ;
|
|
Point3d ptBeforeTheEdge = iccInfo.IciA[0].ptI - vtDir * EPS_SMALL * EPS_SMALL ;
|
|
pCLPart1->Set( ptStart, ptBeforeTheEdge) ;
|
|
pCrvCompo->AddCurve( pCLPart1, true, dToler) ;
|
|
bAdded = false ;
|
|
AddCurveCompoToCuts( pCrvCompo, vpCCOpen, vpCCClosed) ;
|
|
pCrvCompo->Clear() ;
|
|
// comincio a costruire una nuova curva partendo oltre l'edge che ho appena attraversato
|
|
// probabilmente mi conviene spostare di poco il punto in modo da aiutare la funzione di Unproject
|
|
//ICurveLine* pCLPart2 ( CreateCurveLine()) ;
|
|
Point3d ptBeyondTheEdge = iccInfo.IciA[0].ptI + vtDir * EPS_SMALL * EPS_SMALL;
|
|
//pCLPart2->Set( ptBeyondTheEdge, ptEnd) ;
|
|
//bAdded = bAdded && pCrvCompo->AddCurve( pCLPart2, true, dToler) ;
|
|
ptNear = ptBeyondTheEdge ;
|
|
bPrevLineThroughEdge = true ;
|
|
}
|
|
}
|
|
// sennò procedo normalmente aggiungendo il punto
|
|
else {
|
|
bAdded = bAdded && pCrvCompo->AddCurve( pLine, true, dToler) ;
|
|
ptNear = ( bAdded ? ptEnd : ptStart) ;
|
|
bPrevLineThroughEdge = false ;
|
|
}
|
|
}
|
|
AddCurveCompoToCuts( pCrvCompo, vpCCOpen, vpCCClosed) ;
|
|
}
|
|
////debug
|
|
//vector<IGeoObj*> vGeoObj ;
|
|
//for ( int i = 0 ; i < int(vpCCOpen.size()); ++i )
|
|
// vGeoObj.emplace_back(static_cast<IGeoObj*>( vpCCOpen[i]->Clone())) ;
|
|
//SaveGeoObj( vGeoObj, "D:\\Temp\\inters\\sphere_openCuts_beforeJoint.nge") ;
|
|
////debug
|
|
if ( int( vpCCOpen.size()) != 0) {
|
|
// devo verificare se devo giuntare la prima curva aperta con l'ultima
|
|
Point3d ptStartOpen, ptEndOpen ;
|
|
vpCCOpen.front()->GetStartPoint( ptStartOpen) ;
|
|
vpCCOpen.back()->GetEndPoint( ptEndOpen) ;
|
|
if ( AreSamePointApprox(ptStartOpen, ptEndOpen) ) {
|
|
vpCCOpen.back()->AddCurve( vpCCOpen.front()) ;
|
|
Release( vpCCOpen[0]) ;
|
|
vpCCOpen.erase( vpCCOpen.begin()) ;
|
|
}
|
|
}
|
|
////debug
|
|
//vector<IGeoObj*> vGeoObj2 ;
|
|
//for ( int i = 0 ; i < int(vpCCOpen.size()); ++i )
|
|
// vGeoObj2.emplace_back(static_cast<IGeoObj*>( vpCCOpen[i]->Clone())) ;
|
|
//SaveGeoObj( vGeoObj2, "D:\\Temp\\inters\\sphere_openCuts_AfterJoint.nge") ;
|
|
////debug
|
|
|
|
//comincio a creare la superficie aggiungendo i tagli aperti ai bordi attualmente esistenti
|
|
SurfFlatRegionByContours sfrContour ;
|
|
if ( int(vpCCOpen.size()) != 0 ) {
|
|
// qui devo aggiungere tutto del codice nuovo per ricostruire in altro modo il nuovo bordo della superficie
|
|
// recupero la regione attuale
|
|
unordered_map<TRINT,ICCIVECTOR> mInters ;
|
|
// costruisco la mappa delle intersezioni
|
|
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)) ;
|
|
////debug
|
|
//PtrOwner<ISurfFlatRegion> pSrfCopy( pNewTrim->Clone()) ;
|
|
//SaveGeoObj( Release(pSrfCopy), "D:\\Temp\\inters\\sphere_actualTrimRegion.nge") ;
|
|
////debug
|
|
|
|
////debug
|
|
//PtrOwner<ICurve> pCrvCopy( pNewTrim->GetLoop(0,0)) ;
|
|
//SaveGeoObj( Release(pCrvCopy), "D:\\Temp\\inters\\sphere_actualTrimRegionEdge.nge") ;
|
|
////debug
|
|
|
|
for ( int c = 0 ; c < pNewTrim->GetChunkCount() ; ++c) {
|
|
for ( int l = 0 ; l < pNewTrim->GetLoopCount( c) ; ++l) {
|
|
for ( int t = 0 ; t < int( vpCCOpen.size()); ++t) {
|
|
PtrOwner<ICurve> pLoop( pNewTrim->GetLoop( c, l)) ;
|
|
// prima curva è il loop, seconda curva è il loop
|
|
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)) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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()) ;
|
|
//bool bAddedAll = false ;
|
|
TRINT tiFirstInters ;
|
|
//double dParamFirstInters = -1 ;
|
|
// parto aggiungendo il primo taglio
|
|
int nNewToAdd = 0 ;
|
|
bool bFirstCurveOfEdge = true ;
|
|
while ( nNewToAdd != -1) {
|
|
// aggiungo il taglio
|
|
//PtrOwner<ICurveComposite> pLastCC( vpCCOpen[nNewToAdd]->Clone()) ;
|
|
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 ;
|
|
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 ;
|
|
if ( bFirstCurveOfEdge){
|
|
// salvo l'inizio del taglio che è la prima curva di questa curva compo
|
|
tiFirstInters = pair.first ;
|
|
//dParamFirstInters = pair.second[p].IciA->dU ; // parametro di intersezione sul loop
|
|
bFirstCurveOfEdge = false ;
|
|
}
|
|
}
|
|
else
|
|
tiEnd = pair.first ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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 = numeric_limits<double>::infinity() ;
|
|
double dEndCurrentCut ;
|
|
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) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//bool bRestart = false ;
|
|
if ( nInters == -1) {
|
|
//bRestart = true ;
|
|
dNextCut = numeric_limits<double>::infinity() ;
|
|
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)) ;
|
|
|
|
/////////////////////////////////////sostituito da CopyParamRange////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//PtrOwner<ICurve> pLoopTrimmed( pNewTrim->GetLoop( get<0>(tiEnd), get<1>(tiEnd))) ;
|
|
//// se i trim che devo fare sono sulla stessa sotto-curva della compo devo riscalare il valore per il trim allo start prima di trimmare l'end
|
|
//if ( int( dNextCut) == int( dEndCurrentCut)) {
|
|
// PtrOwner<ICurveComposite> pLoopCompo( GetCurveComposite( pLoopTrimmed->Clone())) ;
|
|
// const ICurve* pSubCrv = pLoopCompo->GetCurve( int(dNextCut)) ;
|
|
// double dLenAtParam0, dLenAtParam1 ;
|
|
// pSubCrv->GetLengthAtParam( dEndCurrentCut, dLenAtParam0) ;
|
|
// pSubCrv->GetLengthAtParam( dNextCut, dLenAtParam1) ;
|
|
// dEndCurrentCut = dLenAtParam0 / dLenAtParam1 ;
|
|
//}
|
|
//// trimmo il loop che ho trovato come prosecuzione del taglio corrente e la aggiungo al taglio
|
|
//pLoopTrimmed->TrimEndAtParam( dNextCut) ;
|
|
|
|
//// se non sono ripassato per lo start del loop mi basta aggiungere il pezzo di loop che ho trimmato
|
|
//if ( ! bRestart) {
|
|
// pLoopTrimmed->TrimStartAtParam( dEndCurrentCut) ;
|
|
// pCCNewEdge->AddCurve( Release( pLoopTrimmed)) ;
|
|
//}
|
|
//else {
|
|
// // prima di aggiungere il pezzo che ho identificato devo aggiungere quello che dal parametro corrente mi fa
|
|
// // andare al punto finale e quindi tornare al punto iniziale
|
|
// PtrOwner<ICurve> pLoopTrimmed0( pNewTrim->GetLoop( get<0>(tiEnd), get<1>(tiEnd))) ;
|
|
// pLoopTrimmed0->TrimStartAtParam( dEndCurrentCut) ;
|
|
// pCCNewEdge->AddCurve( Release(pLoopTrimmed0)) ;
|
|
// // e poi aggiungo il tratto che ho identificato per arrivare al prossimo taglio
|
|
// pCCNewEdge->AddCurve( Release(pLoopTrimmed)) ;
|
|
//}
|
|
///////////////////////////////////sostituito da CopyParamRange//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// 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 ;
|
|
//vbAdded[b] = true ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
nNewToAdd = nInters;
|
|
}
|
|
}
|
|
|
|
//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 i loop chiusi
|
|
for ( int i = 0 ; i < int( vpCCClosed.size()); ++i )
|
|
sfrContour.AddCurve( Release( vpCCClosed[i])) ;
|
|
// aggiungo loop derivati dai triangoli
|
|
for ( int i = 0 ; i < int( vPLTria.size()); ++i ) {
|
|
PtrOwner<ICurveComposite> pCC( CreateCurveComposite()) ;
|
|
pCC->FromPolyLine( vPLTria[i]) ;
|
|
sfrContour.AddCurve( Release( pCC)) ;
|
|
}
|
|
PtrOwner<ISurfFlatRegion> pSFR( sfrContour.GetSurf()) ;
|
|
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) {
|
|
PtrOwner<ISurfFlatRegion> pSurf( pSFR->CloneChunk( c)) ;
|
|
for ( int l = 0 ; l < pSurf->GetLoopCount( 0); ++l) {
|
|
PtrOwner<ICurve> pCrv( pSurf->GetLoop( 0, l)) ;
|
|
double dArea ; pCrv->GetAreaXY( dArea) ;
|
|
if ( abs( dArea) < dAreaMin) {
|
|
nChunkMin = c ;
|
|
nLoopMin = l ;
|
|
dAreaMin = abs( dArea) ;
|
|
bPos = dArea > 0 ;
|
|
}
|
|
}
|
|
}
|
|
|
|
////debug
|
|
//PtrOwner<ISurfFlatRegion> pSrfFR_Copy0( pSFR->Clone()) ;
|
|
//SaveGeoObj( Release(pSrfFR_Copy0), "D:\\Temp\\inters\\failed_flip.nge", GDB_SV_BIN) ;
|
|
////debug
|
|
|
|
// 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) ;
|
|
//vtDirS.Rotate( Z_AX, bPos? 90 : -90) ;
|
|
vtDir = vtDirS + vtDirE ;
|
|
PtrOwner<ICurveLine> pCL( CreateCurveLine()) ;
|
|
pCL->SetPVL( ptStart, vtDirS, 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
|
|
|
|
////debug
|
|
//PtrOwner<ISurfFlatRegion> pSrfFR_Copy( pSFR->Clone()) ;
|
|
//SaveGeoObj( Release(pSrfFR_Copy), "D:\\Temp\\inters\\failed_trim.nge", GDB_SV_BIN) ;
|
|
////debug
|
|
|
|
// 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 ;
|
|
}
|
|
|
|
// imposto ricalcolo della grafica
|
|
m_OGrMgr.Reset() ;
|
|
|
|
////debug
|
|
//PtrOwner<ISurfFlatRegion> pSrfFR_Copy3( GetTrimRegion()->Clone()) ;
|
|
//SaveGeoObj( Release(pSrfFR_Copy3), "D:\\Temp\\inters\\trimmed_paramSpace.nge", GDB_SV_BIN) ;
|
|
////debug
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::UnprojectPointFromStm( int nT, const Point3d& ptI, Point3d& ptSP, int nIL) const
|
|
{
|
|
return UnprojectPointFromStm( nT, ptI, ptSP, nIL, Point3d(-1,-1,-1), -1) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::UnprojectPointFromStm( int nT, const Point3d& ptI, Point3d& ptSP, int nIL, const Point3d& ptIPrevOrNext, int nTPrev) const
|
|
{
|
|
// dato un punto sulla trimesh ausiliaria, ne ricavo le coordinate parametriche
|
|
const ISurfTriMesh* pSurfTm = GetAuxSurf() ;
|
|
// 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 ;
|
|
int nInters = 0 ;
|
|
INTVECTOR vInters ;
|
|
if ( m_vbPole[0] || m_vbPole[1] || m_vbPole[2] || m_vbPole[3]) {
|
|
for ( int c = 0 ; c < 4 ; ++c) {
|
|
if ( ! m_vCCEdge[c]->IsValid()) {
|
|
Point3d pt ;
|
|
m_vPLEdge[c].GetFirstPoint( pt) ;
|
|
vInters.push_back( AreSamePointApprox( pt, ptI) ? 1 : 0) ;
|
|
nInters += vInters.back() ;
|
|
}
|
|
else {
|
|
vInters.push_back( m_vCCEdge[c]->IsPointOn( ptI) ? 1 : 0) ;
|
|
nInters += vInters.back() ;
|
|
}
|
|
}
|
|
|
|
// se ho tre intersezioni vuol dire che un lato è collassato in un punto e il punto di cui voglio la controimmagine è esattamente nel polo
|
|
if ( nInters == 3) {
|
|
bIsPole = true ;
|
|
//// salvo pure come triangolo di riferimento quello del punto precedente
|
|
//const ISurfTriMesh* pSurfTm2 = GetAuxSurf() ;
|
|
//int nVert[3] ;
|
|
//pSurfTm2->GetTriangle( nT, nVert) ;
|
|
//PNTVECTOR vPtPa(3) ;
|
|
//pSurfTm2->GetVertexParam( nVert[0], vPtPa[0].x,vPtPa[0].y) ;
|
|
//pSurfTm2->GetVertexParam( nVert[1], vPtPa[1].x,vPtPa[1].y) ;
|
|
//pSurfTm2->GetVertexParam( nVert[2], vPtPa[2].x,vPtPa[2].y) ;
|
|
//if ( nTPrev != -1)
|
|
// nT = nTPrev ;
|
|
//else
|
|
// // se non avevo un punto precedente allora vuol dire che mi stanno passando un punto singolo e non posso dire nulla sulle coordinate
|
|
// // parametriche di questo punto
|
|
// return false ;
|
|
|
|
// visto che sono in un polo devo verificare di aver ricevuto il triangolo giusto
|
|
// mi sposto verso il punto successivo o precedente e ricalcolo il triangolo di appartenenza
|
|
Point3d ptI2 = ptI + ( ptIPrevOrNext - ptI) * EPS_SMALL ;
|
|
// ricalcolo il triangolo di appartenenza
|
|
DistPointSurfTm dPtStm( ptI2, *pSurfTm) ;
|
|
dPtStm.GetMinDistTriaIndex( nT) ;
|
|
}
|
|
}
|
|
|
|
// recupero i dati dei vertici del triangolo che fa intersezione
|
|
int nVert[3] ;
|
|
pSurfTm->GetTriangle( nT, nVert) ;
|
|
PNTVECTOR vPtPa(3) ;
|
|
pSurfTm->GetVertexParam( nVert[0], vPtPa[0].x,vPtPa[0].y) ;
|
|
pSurfTm->GetVertexParam( nVert[1], vPtPa[1].x,vPtPa[1].y) ;
|
|
pSurfTm->GetVertexParam( nVert[2], vPtPa[2].x,vPtPa[2].y) ;
|
|
PNTVECTOR vPT(3) ;
|
|
pSurfTm->GetVertex( nVert[0], vPT[0]) ;
|
|
pSurfTm->GetVertex( nVert[1], vPT[1]) ;
|
|
pSurfTm->GetVertex( nVert[2], vPT[2]) ;
|
|
// se la superficie è chiusa controllo se devo tenere conto della periodicità nel prendere le coordinate parametriche dei vertici
|
|
double dParamH, dParamL ;
|
|
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 ;
|
|
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à
|
|
if ( m_bClosedU && abs(vtDir.x) > abs( vtDir.y) && dDist > dParamL * 0.95 ) {
|
|
// trovo se dei punti del triangolo sono sul bordo dello spazio parametrico
|
|
BOOLVECTOR vbOn(3) ;
|
|
for ( int p = 0 ; p < 3; ++p ) {
|
|
if ( ! m_vCCEdge[1]->IsValid()) {
|
|
Point3d pt ;
|
|
m_vPLEdge[1].GetFirstPoint( pt) ;
|
|
vbOn[p] = AreSamePointApprox( pt, vPT[p]) ;
|
|
}
|
|
else
|
|
vbOn[p] = m_vCCEdge[1]->IsPointOn( vPT[p]) ;
|
|
if ( ! m_vCCEdge[3]->IsValid()) {
|
|
Point3d pt ;
|
|
m_vPLEdge[3].GetFirstPoint( pt) ;
|
|
vbOn[p] = vbOn[p] || AreSamePointApprox( pt, vPT[p]) ;
|
|
}
|
|
else
|
|
vbOn[p] = vbOn[p] || m_vCCEdge[3]->IsPointOn( vPT[p]) ;
|
|
}
|
|
// controllo che almeno un punto sia su un edge
|
|
if ( vbOn[0] || vbOn[1] || vbOn[2]) {
|
|
double dRightX ;
|
|
// tengo per buone le coordinate dei punti che NON sono sul bordo dello spazio parametrico
|
|
for ( int p = 0 ; p < 3; ++p) {
|
|
if ( !vbOn[p] ) {
|
|
dRightX = vPtPa[p].x ;
|
|
break ;
|
|
}
|
|
}
|
|
for ( int p = 0 ; p < 3; ++p) {
|
|
if ( abs(vPtPa[p].x - dRightX) > EPS_SMALL ) {
|
|
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.95) {
|
|
BOOLVECTOR vbOn(3) ;
|
|
for ( int p = 0 ; p < 3; ++p ) {
|
|
if ( ! m_vCCEdge[0]->IsValid()) {
|
|
Point3d pt ;
|
|
m_vPLEdge[0].GetFirstPoint( pt) ;
|
|
vbOn[p] = AreSamePointApprox( pt, vPT[p]) ;
|
|
}
|
|
else
|
|
vbOn[p] = m_vCCEdge[0]->IsPointOn( vPT[p]) ;
|
|
if ( ! m_vCCEdge[2]->IsValid()) {
|
|
Point3d pt ;
|
|
m_vPLEdge[2].GetFirstPoint( pt) ;
|
|
vbOn[p] = vbOn[p] || AreSamePointApprox( pt, vPT[p]) ;
|
|
}
|
|
else
|
|
vbOn[p] = vbOn[p] || m_vCCEdge[2]->IsPointOn( vPT[p]) ;
|
|
}
|
|
// controllo che almeno un punto sia su un edge
|
|
if ( vbOn[0] || vbOn[1] || vbOn[2]) {
|
|
double dRightY ;
|
|
// tengo per buone le coordinate dei punti che NON sono sul bordo dello spazio parametrico
|
|
for ( int p = 0 ; p < 3; ++p) {
|
|
if ( ! vbOn[p]) {
|
|
dRightY = vPtPa[p].y ;
|
|
break ;
|
|
}
|
|
}
|
|
for ( int p = 0 ; p < 3; ++p) {
|
|
if ( abs(vPtPa[p].y - dRightY) > EPS_SMALL) {
|
|
if ( vPtPa[p].y < EPS_SMALL)
|
|
vPtPa[p].y = dParamH ;
|
|
else
|
|
vPtPa[p].y = 0 ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// devo anche tener conto della possibilità che i lati siano collassati in poli
|
|
if ( bIsPole) {
|
|
int nInters = -1 ;
|
|
for ( int c = 0 ; c < 4 ; ++c) {
|
|
if ( ( c == 0 && vInters[0] == vInters[3]) ||
|
|
( c != 0 && vInters[c] == vInters[c - 1])){
|
|
nInters = c ;
|
|
break ;
|
|
}
|
|
}
|
|
// se non ho trovato il lato su cui ho il polo
|
|
if ( nInters == -1)
|
|
return false ;
|
|
// trovo quale vertice è sull'edge di polo
|
|
BOOLVECTOR vbOn(3) ;
|
|
fill( vbOn.begin(), vbOn.end(), false) ;
|
|
for ( int p = 0 ; p < 3; ++p ) {
|
|
for ( int c = 0 ; c < 4; ++c) {
|
|
if ( ! m_vCCEdge[c]->IsValid()) {
|
|
Point3d pt ;
|
|
m_vPLEdge[c].GetFirstPoint( pt) ;
|
|
vbOn[p] = vbOn[p] || AreSamePointApprox( pt, vPT[p]) ;
|
|
}
|
|
else
|
|
vbOn[p] = vbOn[p] || m_vCCEdge[c]->IsPointOn( vPT[p]) ;
|
|
}
|
|
}
|
|
// trovo la coordinata giusta da tenere ( x o y a seconda dell'edge)
|
|
double dRightX, dRightY ;
|
|
for ( int p = 0 ; p < 3; ++p) {
|
|
if ( ! vbOn[p]) {
|
|
if ( nInters == 0 || nInters == 2) {
|
|
dRightX = vPtPa[p].x ;
|
|
dRightY = nInters == 0 ? dParamH : 0 ;
|
|
}
|
|
else if ( nInters == 1 || nInters == 3) {
|
|
dRightX = nInters == 1 ? 0 : dParamL ;
|
|
dRightY = vPtPa[p].y ;
|
|
}
|
|
}
|
|
}
|
|
// correggo le coordinate del punto sull'edge di polo
|
|
for ( int p = 0 ; p < 3 ; ++p) {
|
|
if ( vbOn[p]) {
|
|
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 == 3 && ! 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] ;
|
|
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 ;
|
|
Eigen::Vector3d b ( ptI.x, ptI.y, ptI.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 ;
|
|
ptSP.x = ptParam.x() ;
|
|
ptSP.y = ptParam.y() ;
|
|
// controllo se le coordinate sono nello spazio parametrico ed eventualmente se posso sistemarle tenendo conto della periodicità ( se la superficie è chiusa)
|
|
if ( ptSP.x < 0) {
|
|
if ( m_bClosedU)
|
|
ptSP.x += m_nSpanU * SBZ_TREG_COEFF ;
|
|
else
|
|
ptSP.x = 0 ;
|
|
}
|
|
if ( ptSP.x > m_nSpanU * SBZ_TREG_COEFF ) {
|
|
if ( m_bClosedU)
|
|
ptSP.x -= m_nSpanU * SBZ_TREG_COEFF ;
|
|
else
|
|
ptSP.x = m_nSpanU * SBZ_TREG_COEFF ;
|
|
}
|
|
if ( ptSP.y < 0 ) {
|
|
if ( m_bClosedV)
|
|
ptSP.y += m_nSpanV * SBZ_TREG_COEFF ;
|
|
else
|
|
ptSP.y = 0 ;
|
|
}
|
|
if ( ptSP.y > m_nSpanV * SBZ_TREG_COEFF ) {
|
|
if ( m_bClosedU)
|
|
ptSP.y -= m_nSpanV * SBZ_TREG_COEFF ;
|
|
else
|
|
ptSP.y = m_nSpanV * SBZ_TREG_COEFF ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::UnprojectPoint( const Point3d& pt3D, Point3d& ptParam) const
|
|
{
|
|
// 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, *GetAuxSurf()) ;
|
|
int nTriaIndex ; dptSurfTm.GetMinDistTriaIndex( nTriaIndex) ;
|
|
Point3d ptI ; dptSurfTm.GetMinDistPoint( ptI) ;
|
|
if ( ! UnprojectPointFromStm( nTriaIndex, ptI, ptParam))
|
|
return false ;
|
|
Point3d ptBez ;
|
|
GetPointD1D2( ptParam.x / SBZ_TREG_COEFF, ptParam.y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBez) ;
|
|
// usando un algoritmo di newton cerco di avvicinarmi il più possibile al punto
|
|
double dDistNew = Dist( pt3D, ptBez) ;
|
|
double dDistPre = dDistNew ;
|
|
|
|
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.
|
|
while ( dDistNew > EPS_SMALL && nCount < 100) {
|
|
dDistPre = dDistNew ;
|
|
Point3d ptIBzNew1 ;
|
|
GetPointD1D2( ( ptParam.x + dh) / SBZ_TREG_COEFF, ptParam.y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptIBzNew1) ;
|
|
dDistNew = Dist( pt3D, ptIBzNew1) ;
|
|
double dfdU = ( dDistNew - dDistPre) / dh ;
|
|
Point3d ptIBzNew2 ;
|
|
GetPointD1D2( ptParam.x / SBZ_TREG_COEFF, ( ptParam.y + dh) / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptIBzNew2) ;
|
|
dDistNew = Dist( pt3D, ptIBzNew2) ;
|
|
double dfdV = ( dDistNew - dDistPre) / dh ;
|
|
//// opzione 0
|
|
////scelgo h1 e h2 separatamente e in modo da annullare f(x)
|
|
//// opzione 1
|
|
//// valore fisso
|
|
//double dr = EPS_SMALL ;
|
|
//if ( dDistPre > 1)
|
|
// dr = 1 ;
|
|
//else if ( dDistPre > 0.1)
|
|
// dr = 0.1 ;
|
|
//else if ( dDistPre > 0.01)
|
|
// dr = 0.01 ;
|
|
//// opzione 2
|
|
//// valore direttamente vincolato
|
|
//double dr = dDistPre ;
|
|
//// opzione 3
|
|
//// valuto la deformazione locale in base allo spostamento del punto sulla bezier // non serve
|
|
//double dh1 = Dist( ptIBz, ptIBzNew1) ;
|
|
//double dh2 = Dist( ptIBz, ptIBzNew2) ;
|
|
// potrei valutare il nuovo spostamento in base all'ultima variazione di dDist
|
|
// potrei anche vedere se sto uscendo dal triangolo ( definito nello spazio parametrico)
|
|
// mi avvicino cercando di annullare la distanza in un colpo solo
|
|
double dr = - dDistPre / ( dfdU + dfdV) ;
|
|
GetPointD1D2(( ptParam.x + dr * dfdU) / SBZ_TREG_COEFF, ( ptParam.y + dr * dfdV) / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBez) ;
|
|
dDistNew = Dist( pt3D, ptBez) ;
|
|
++nCount ;
|
|
}
|
|
return nCount != 99 ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::CalcPoles( void)
|
|
{
|
|
// controllo se uno o più lati 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 ;
|
|
m_vbPole[3] = bPole1 ;
|
|
// 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] = bPole0 ;
|
|
m_vbPole[2] = bPole1 ;
|
|
|
|
return true ;
|
|
}
|