2c6ebdadca
- correzioni, migliorie e d estensioni alle superfici di Bezier - in Release cambiate opzioni di ottimizzazione da /Ox a /O2.
1267 lines
39 KiB
C++
1267 lines
39 KiB
C++
//----------------------------------------------------------------------------
|
|
// EgalTech 2020-2020
|
|
//----------------------------------------------------------------------------
|
|
// File : SurfBezier.cpp Data : 22.03.20 Versione : 2.2c3
|
|
// Contenuto : Implementazione della classe Superfici Bezier.
|
|
//
|
|
//
|
|
//
|
|
// Modifiche : 22.03.20 DS Creazione modulo.
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
//--------------------------- 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 "/EgtDev/Include/EGkStmFromTriangleSoup.h"
|
|
#include "/EgtDev/Include/EGkStringUtils3d.h"
|
|
#include "/EgtDev/Include/EGkUiUnits.h"
|
|
#include "/EgtDev/Include/EgtNumUtils.h"
|
|
#include "/EgtDev/Include/EgtPointerOwner.h"
|
|
|
|
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_bRat( false), m_bTrimmed( false), m_nTempProp( 0)
|
|
{
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
SurfBezier::~SurfBezier( void)
|
|
{
|
|
m_OGrMgr.Reset() ;
|
|
ResetAuxSurf() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::Init( int nDegU, int nDegV, bool bIsRational)
|
|
{
|
|
// verifico validità grado
|
|
if ( nDegU < 1 || nDegU > MAXDEG || nDegV < 1 || nDegV > MAXDEG)
|
|
return false ;
|
|
|
|
// imposto gradi e flag di razionale
|
|
m_nDegU = nDegU ;
|
|
m_nDegV = nDegV ;
|
|
m_bRat = bIsRational ;
|
|
m_bTrimmed = false ;
|
|
|
|
// 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::GetInfo( int& nDegU, int& nDegV, 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 ;
|
|
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 ( ! 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 ( ! GetAuxSurf())
|
|
return false ;
|
|
return m_pSTM->GetCentroid( ptCen) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::GetPointD1D2( double dU, double dV, 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 1
|
|
dU = Clamp( dU, 0., 1.) ;
|
|
dV = Clamp( dV, 0., 1.) ;
|
|
|
|
// se forma polinomiale (o integrale)
|
|
if ( ! m_bRat) {
|
|
|
|
// calcolo dei polinomi di Bernstein per U di grado opportuno
|
|
DBLVECTOR vBernU( m_nDegU + 1) ;
|
|
GetAllBernstein( dU, 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( dU, 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( i+1, j)] - m_vPtCtrl[GetInd( i, j)]) ;
|
|
vtTemp1[j] *= m_nDegU ;
|
|
}
|
|
}
|
|
|
|
// aumento il grado
|
|
IncreaseAllBernsteinOneDegree( dU, 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( i, j)] ;
|
|
}
|
|
|
|
// calcolo dei polinomi di Bernstein per V di grado opportuno
|
|
DBLVECTOR vBernV( m_nDegV + 1) ;
|
|
GetAllBernstein( dV, 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( dV, 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( GetDim()) ;
|
|
for ( int i = 0 ; i < GetDim() ; ++ i)
|
|
vPtWCtrl[i] = m_vWeCtrl[i] * m_vPtCtrl[i] ;
|
|
|
|
// calcolo dei polinomi di Bernstein di grado opportuno
|
|
DBLVECTOR vBernU( m_nDegU + 1) ;
|
|
GetAllBernstein( dU, 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( dU, 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[GetInd( i+1, j)] - vPtWCtrl[GetInd( i, j)]) ;
|
|
dTemp1[j] += vBernU[i] * ( m_vWeCtrl[GetInd( i+1, j)] - m_vWeCtrl[GetInd( i, j)]) ;
|
|
}
|
|
vtTemp1[j] *= m_nDegU ;
|
|
dTemp1[j] *= m_nDegU ;
|
|
}
|
|
}
|
|
|
|
// aumento il grado
|
|
IncreaseAllBernsteinOneDegree( dU, 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[GetInd( i, j)] ;
|
|
dTempW[j] += vBernU[i] * m_vWeCtrl[GetInd( i, j)] ;
|
|
}
|
|
}
|
|
|
|
// calcolo dei polinomi di Bernstein per V di grado opportuno
|
|
DBLVECTOR vBernV( m_nDegV + 1) ;
|
|
GetAllBernstein( dV, 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( dV, 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, Point3d& ptPos, Vector3d& vtN,
|
|
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 1
|
|
dU = Clamp( dU, 0., 1.) ;
|
|
dV = Clamp( dV, 0., 1.) ;
|
|
|
|
// 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, 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, 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, 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, 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 = dynamic_cast<const SurfBezier*>( 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_bRat))
|
|
return false ;
|
|
m_nStatus = sbSrc.m_nStatus ;
|
|
m_vPtCtrl = sbSrc.m_vPtCtrl ;
|
|
if ( sbSrc.m_bRat)
|
|
m_vWeCtrl = sbSrc.m_vWeCtrl ;
|
|
m_nTempProp = sbSrc.m_nTempProp ;
|
|
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) + 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, ";", 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 ;
|
|
}
|
|
}
|
|
|
|
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, ";", true))
|
|
return false ;
|
|
// inizializzo la superficie di Bezier
|
|
if ( ! Init( nDegU, nDegV, 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 ;
|
|
}
|
|
}
|
|
|
|
// 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 ( ! 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 ( ! 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 ;
|
|
|
|
// 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 ;
|
|
|
|
// 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
|
|
PNTVECTOR vPtCtrl = m_vPtCtrl ;
|
|
int l = 0 ;
|
|
for ( int i = 0 ; i <= m_nDegU ; ++ i) {
|
|
for ( int j = 0 ; j <= m_nDegV ; ++ j) {
|
|
int k = i + ( m_nDegU + 1) * j ;
|
|
m_vPtCtrl[l] = vPtCtrl[k] ;
|
|
++ l ;
|
|
}
|
|
}
|
|
if ( m_bRat) {
|
|
DBLVECTOR vWeCtrl = m_vWeCtrl ;
|
|
int l = 0 ;
|
|
for ( int i = 0 ; i <= m_nDegU ; ++ i) {
|
|
for ( int j = 0 ; j <= m_nDegV ; ++ j) {
|
|
int k = i + ( m_nDegU + 1) * j ;
|
|
m_vWeCtrl[l] = vWeCtrl[k] ;
|
|
++ l ;
|
|
}
|
|
}
|
|
}
|
|
swap( m_nDegU, m_nDegV) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int
|
|
SurfBezier::GetSteps( int nDeg, 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) ;
|
|
nQuality = Clamp( nQuality, 1, 3) ;
|
|
double dMult = sqrt( max( dLen, 10.)) ;
|
|
return int( nQuality * dMult * dCoeff[nDeg]) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
CurveBezier*
|
|
SurfBezier::GetCurveOnU( double dV) const
|
|
{
|
|
// controlli
|
|
if ( dV < - EPS_PARAM || dV > 1 + EPS_PARAM)
|
|
return false ;
|
|
dV = Clamp( dV, 0., 1.) ;
|
|
|
|
// se forma polinomiale (o integrale)
|
|
if ( ! m_bRat) {
|
|
// 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( dV, m_nDegV, vBernV) ;
|
|
// 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( i, j)] ;
|
|
pCbz->SetControlPoint( i, ptP) ;
|
|
}
|
|
return Release( pCbz) ;
|
|
}
|
|
// altrimenti forma razionale
|
|
else {
|
|
// 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( dV, m_nDegV, vBernV) ;
|
|
// calcolo dei punti di controllo della curva
|
|
PNTVECTOR vPtWCtrl( GetDim()) ;
|
|
for ( int i = 0 ; i < GetDim() ; ++ i)
|
|
vPtWCtrl[i] = m_vWeCtrl[i] * m_vPtCtrl[i] ;
|
|
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[GetInd( i, j)] ;
|
|
dW += vBernV[j] * m_vWeCtrl[GetInd( i, j)] ;
|
|
}
|
|
double dInvW = 1 / ( ( dW > EPS_ZERO) ? dW : EPS_ZERO) ;
|
|
pCbz->SetControlPoint( i, ptP * dInvW, dW) ;
|
|
}
|
|
return Release( pCbz) ;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
CurveBezier*
|
|
SurfBezier::GetCurveOnV( double dU) const
|
|
{
|
|
// controlli
|
|
if ( dU < - EPS_PARAM || dU > 1 + EPS_PARAM)
|
|
return false ;
|
|
dU = Clamp( dU, 0., 1.) ;
|
|
|
|
// se forma polinomiale (o integrale)
|
|
if ( ! m_bRat) {
|
|
// 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( dU, m_nDegU, vBernU) ;
|
|
// 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( i, j)] ;
|
|
pCbz->SetControlPoint( j, ptP) ;
|
|
}
|
|
return Release( pCbz) ;
|
|
}
|
|
// altrimenti forma razionale
|
|
else {
|
|
// 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( dU, m_nDegU, vBernU) ;
|
|
// calcolo dei punti di controllo della curva
|
|
PNTVECTOR vPtWCtrl( GetDim()) ;
|
|
for ( int i = 0 ; i < GetDim() ; ++ i)
|
|
vPtWCtrl[i] = m_vWeCtrl[i] * m_vPtCtrl[i] ;
|
|
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[GetInd( i, j)] ;
|
|
dW += vBernU[i] * m_vWeCtrl[GetInd( i, j)] ;
|
|
}
|
|
double dInvW = 1 / ( ( dW > EPS_ZERO) ? dW : EPS_ZERO) ;
|
|
pCbz->SetControlPoint( j, ptP * dInvW, dW) ;
|
|
}
|
|
return Release( pCbz) ;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
ICurve*
|
|
SurfBezier::GetLoop( int nLoop) const
|
|
{
|
|
// Se superficie completa, basta concatenare le 4 isoparametriche di bordo
|
|
if ( ! m_bTrimmed) {
|
|
// Esiste solo il loop esterno
|
|
if ( nLoop |= 0)
|
|
return nullptr ;
|
|
// Loop
|
|
PtrOwner<CurveComposite> pLoop( CreateBasicCurveComposite()) ;
|
|
// prima curva U=0
|
|
PtrOwner<CurveBezier> pCbzU0( GetCurveOnU( 0)) ;
|
|
if ( ! IsNull( pCbzU0) && ! pCbzU0->IsAPoint())
|
|
pLoop->AddCurve( Release( pCbzU0)) ;
|
|
// seconda curva V=1
|
|
PtrOwner<CurveBezier> pCbzV1( GetCurveOnV( 1)) ;
|
|
if ( ! IsNull( pCbzV1) && ! pCbzV1->IsAPoint())
|
|
pLoop->AddCurve( Release( pCbzV1)) ;
|
|
// terza curva U=1 invertita
|
|
PtrOwner<CurveBezier> pCbzU1( GetCurveOnU( 1)) ;
|
|
if ( ! IsNull( pCbzU1) && ! pCbzU1->IsAPoint()) {
|
|
pCbzU1->Invert() ;
|
|
pLoop->AddCurve( Release( pCbzU1)) ;
|
|
}
|
|
// quarta curva V=0 invertita
|
|
PtrOwner<CurveBezier> pCbzV0( GetCurveOnV( 0)) ;
|
|
if ( ! IsNull( pCbzV0) && ! pCbzV0->IsAPoint()) {
|
|
pCbzV0->Invert() ;
|
|
pLoop->AddCurve( Release( pCbzV0)) ;
|
|
}
|
|
// se loop chiuso lo restituisco, altrimenti errore
|
|
return ( pLoop->IsClosed() ? Release( pLoop) : nullptr) ;
|
|
}
|
|
// altrimenti trimmata, per ora non gestita
|
|
else
|
|
return nullptr ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::GetCurveOnU( double dV, int nStep, PolyLine& plCrvU) const
|
|
{
|
|
plCrvU.Clear() ;
|
|
if ( dV < - EPS_PARAM || dV > 1 + EPS_PARAM)
|
|
return false ;
|
|
dV = Clamp( dV, 0., 1.) ;
|
|
PtrOwner<CurveBezier> pCbz( GetCurveOnU( dV)) ;
|
|
if ( IsNull( pCbz))
|
|
return false ;
|
|
if ( nStep <= 0) {
|
|
double dLenU = 0 ;
|
|
pCbz->GetApproxLength( dLenU) ;
|
|
nStep = GetSteps( m_nDegU, dLenU, 2) ;
|
|
}
|
|
return pCbz->ApproxWithLines( nStep, plCrvU) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::GetCurveOnV( double dU, int nStep, PolyLine& plCrvV) const
|
|
{
|
|
plCrvV.Clear() ;
|
|
if ( dU < - EPS_PARAM || dU > 1 + EPS_PARAM)
|
|
return false ;
|
|
dU = Clamp( dU, 0., 1.) ;
|
|
PtrOwner<CurveBezier> pCbz( GetCurveOnV( dU)) ;
|
|
if ( IsNull( pCbz))
|
|
return false ;
|
|
if ( nStep <= 0) {
|
|
double dLenV = 0 ;
|
|
pCbz->GetApproxLength( dLenV) ;
|
|
nStep = GetSteps( m_nDegV, dLenV, 2) ;
|
|
}
|
|
return pCbz->ApproxWithLines( nStep, plCrvV) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfBezier::GetControlCurveOnU( int nIndV, PolyLine& plCtrlU) const
|
|
{
|
|
plCtrlU.Clear() ;
|
|
if ( nIndV < 0 || nIndV > m_nDegV)
|
|
return false ;
|
|
for ( int i = 0 ; i <= m_nDegU ; ++ 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)
|
|
return false ;
|
|
for ( int j = 0 ; j <= m_nDegV ; ++ j)
|
|
plCtrlV.AddUPoint( double( j) / m_nDegV, m_vPtCtrl[GetInd( nIndU, j)]) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
double
|
|
SurfBezier::GetCurveOnUApproxLen( double dV) const
|
|
{
|
|
PtrOwner<CurveBezier> pCbz( GetCurveOnU( dV)) ;
|
|
double dLen ;
|
|
if ( IsNull( pCbz) || ! pCbz->GetApproxLength( dLen))
|
|
return 0 ;
|
|
return dLen ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
double
|
|
SurfBezier::GetCurveOnVApproxLen( double dU) const
|
|
{
|
|
PtrOwner<CurveBezier> pCbz( GetCurveOnV( dU)) ;
|
|
double dLen ;
|
|
if ( IsNull( pCbz) || ! pCbz->GetApproxLength( dLen))
|
|
return 0 ;
|
|
return dLen ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
const ISurfTriMesh*
|
|
SurfBezier::GetAuxSurf( void) const
|
|
{
|
|
// la superficie deve essere validata
|
|
if ( m_nStatus != OK) {
|
|
m_pSTM = nullptr ;
|
|
return nullptr ;
|
|
}
|
|
// se già calcolata, la restituisco
|
|
if ( m_pSTM != nullptr)
|
|
return m_pSTM ;
|
|
// costruttore della superficie
|
|
StmFromTriangleSoup stmSoup ;
|
|
stmSoup.Start() ;
|
|
// definisco il numero degli step in U e in V
|
|
double dMaxLenU = 0 ;
|
|
for ( int j = 0 ; j <= m_nDegV ; ++ j)
|
|
dMaxLenU = max( dMaxLenU, GetCurveOnUApproxLen( double( j) / m_nDegV)) ;
|
|
int nStepU = GetSteps( m_nDegU, dMaxLenU, 2) ;
|
|
double dMaxLenV = 0 ;
|
|
for ( int i = 0 ; i <= m_nDegU ; ++ i)
|
|
dMaxLenV = max( dMaxLenV, GetCurveOnVApproxLen( double( i) / m_nDegU)) ;
|
|
int nStepV = GetSteps( m_nDegV, dMaxLenV, 2) ;
|
|
// prima curva isoparametrica (potrebbe essere un solo punto)
|
|
PolyLine PL1 ;
|
|
GetCurveOnU( 0, nStepU, PL1) ;
|
|
bool bSingle1 = ( PL1.GetPointNbr() == 1) ;
|
|
// ciclo sulle isoparametriche
|
|
for ( int i = 1 ; i <= nStepV ; ++ i) {
|
|
// seconda curva isoparametrica (con tanti punti quanti la prima, oppure uno solo)
|
|
double dV = double( i) / nStepV ;
|
|
PolyLine PL2 ;
|
|
GetCurveOnU( dV, nStepU, PL2) ;
|
|
bool bSingle2 = ( PL2.GetPointNbr() == 1) ;
|
|
// inserisco i triangoli della striscia nel costruttore della TriMesh
|
|
Point3d ptP1c, ptP2c ;
|
|
Point3d ptP1n, ptP2n ;
|
|
bool bNext = PL1.GetFirstPoint( ptP1c) && PL2.GetFirstPoint( ptP2c) ;
|
|
if ( bNext) {
|
|
if ( bSingle1 && bSingle2)
|
|
bNext = false ;
|
|
if ( bSingle1)
|
|
ptP1n = ptP1c ;
|
|
else
|
|
bNext = bNext && PL1.GetNextPoint( ptP1n) ;
|
|
if ( bSingle2)
|
|
ptP2n = ptP2c ;
|
|
else
|
|
bNext = bNext && PL2.GetNextPoint( ptP2n) ;
|
|
}
|
|
while ( bNext) {
|
|
// eventuale primo triangolo (con base sui correnti e vertice su P2 successivo)
|
|
if ( ! AreSamePointApprox( ptP1c, ptP2c))
|
|
stmSoup.AddTriangle( ptP2c, ptP1c, ptP2n) ;
|
|
// eventuale secondo triangolo (con vertice su P1 corrente e base sui successivi)
|
|
if ( ! AreSamePointApprox( ptP1n, ptP2n))
|
|
stmSoup.AddTriangle( ptP1c, ptP1n, ptP2n) ;
|
|
// passo alla successiva coppia
|
|
ptP1c = ptP1n ;
|
|
ptP2c = ptP2n ;
|
|
bNext = ( bSingle1 || PL1.GetNextPoint( ptP1n)) && ( bSingle2 || PL2.GetNextPoint( ptP2n)) ;
|
|
}
|
|
// salvo isoparametrica PL2 in PL1
|
|
PL1.GetUPointList().swap( PL2.GetUPointList()) ;
|
|
bSingle1 = bSingle2 ;
|
|
}
|
|
// la completo
|
|
stmSoup.End() ;
|
|
// la salvo
|
|
m_pSTM = GetBasicSurfTriMesh( stmSoup.GetSurf()) ;
|
|
return m_pSTM ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
SurfBezier::ResetAuxSurf( void) const
|
|
{
|
|
if ( m_pSTM != nullptr)
|
|
delete( m_pSTM) ;
|
|
m_pSTM = nullptr ;
|
|
}
|