Files
EgtGeomKernel/SurfAux.cpp
T
Daniele Bariletti a5714cc85d EgtGeomKernel :
- correzione alla conversione da sup NURBS a Bezier.
2023-10-19 12:44:31 +02:00

561 lines
20 KiB
C++

//----------------------------------------------------------------------------
// EgalTech 2023-2023
//----------------------------------------------------------------------------
// File : SurfAux.cpp Data : 09.08.23 Versione :
// Contenuto : Implementazione di alcune funzioni di utilit? per le Superfici.
//
//
//
// Modifiche : 09.08.23 DB Creazione modulo.
//
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "CurveAux.h"
#include "GeoConst.h"
#include "CurveLine.h"
#include "CurveArc.h"
#include "CurveBezier.h"
#include "CurveComposite.h"
#include "/EgtDev/Include/EgtPointerOwner.h"
#include "/EgtDev/Include/EGkSurf.h"
#include "/EgtDev/Include/EGkSurfAux.h"
#include "/EgtDev/Include/EGkSurfBezier.h"
using namespace std ;
bool
NurbsSurfaceCanonicalize( SNurbsSurfData& snData)
{
// per rendere una superficie non periodica devo recuperare i punti di controllo, suddivisi in isoparametriche lungo una direzione
// e applicare la trasformazione ad ogni isoparametrica, sostituendola poi a quella originale. ( si mantiene il numero di punti)
if ( snData.bPeriodicU ) {
bool bIsRational = snData.bRat ;
// vettore dei nodi
DBLVECTOR vU ;
int nKnot = (int) snData.vU.size() ;
for ( int k = 0 ; k < nKnot ; ++k ) {
double dKnot = snData.vU[k] ;
vU.push_back( dKnot) ;
}
for( int j = 0 ; j < snData.nCPV ; ++j) {
CNurbsData nuCurve ;
nuCurve.bPeriodic = true ;
nuCurve.nDeg = snData.nDegU ;
nuCurve.vU = vU ;
// vettore dei punti di controllo
PNTVECTOR vPtCtrl ;
// vettore dei pesi
DBLVECTOR vWeCtrl ;
for ( int i = 0 ; i < snData.nCPU ; ++i ) {
if ( bIsRational) {
vPtCtrl.push_back( snData.mCP[i][j] / snData.mW[i][j]) ;
vWeCtrl.push_back( snData.mW[i][j]) ;
}
else
vPtCtrl.push_back( snData.mCP[i][j]) ;
}
nuCurve.vCP = vPtCtrl ;
nuCurve.vW = vWeCtrl ;
// i punti dell' oggetto nuCurve devono essere in forma non omogenea
NurbsCurveCanonicalize( nuCurve) ;
for ( int i = 0 ; i < snData.nCPU ; ++i) {
snData.mCP[i][j] = nuCurve.vCP[i] ;
}
snData.vU = nuCurve.vU ;
}
snData.bPeriodicU = false ;
}
if ( snData.bPeriodicV ) {
bool bIsRational = snData.bRat ;
// vettore dei nodi
DBLVECTOR vV ;
int nKnot = (int) snData.vV.size() ;
for ( int k = 0 ; k < nKnot ; ++k ) {
double dKnot = snData.vV[k] ;
vV.push_back( dKnot) ;
}
for( int i = 0 ; i < snData.nCPU ; ++i) {
CNurbsData nuCurve ;
nuCurve.bPeriodic = true ;
nuCurve.nDeg = snData.nDegV ;
nuCurve.vU = vV ;
// vettore dei punti di controllo
PNTVECTOR vPtCtrl ;
// vettore dei pesi
DBLVECTOR vWeCtrl ;
for ( int j = 0 ; j < snData.nCPV ; ++j ) {
if ( bIsRational) {
vPtCtrl.push_back( snData.mCP[i][j] / snData.mW[i][j]) ;
vWeCtrl.push_back( snData.mW[i][j]) ;
}
else
vPtCtrl.push_back( snData.mCP[i][j]) ;
}
nuCurve.vCP = vPtCtrl ;
nuCurve.vW = vWeCtrl ;
// i punti dell' oggetto nuCurve devono essere in forma non omogenea
NurbsCurveCanonicalize( nuCurve) ;
for ( int j = 0 ; j < snData.nCPV ; ++j ) {
snData.mCP[i][j] = nuCurve.vCP[j] ;
}
snData.vV = nuCurve.vU ;
}
snData.bPeriodicV = false ;
}
return true;
}
//----------------------------------------------------------------------------
ISurf*
NurbsToBezierSurface(const SNurbsSurfData& snData)
{
//INTVECTOR vInt_sub( 10) ;
//INTMATRIX vInt( 10, vInt_sub) ;
//for ( int i = 0 ; i < 10 ; ++i ) {
// for ( int j = 0 ; j < 10 ; ++j ) {
// vInt[i][j] = i + 10 * j ;
// }
//}
//vInt_sub.resize( 20) ;
//vInt[0].resize( 20) ;
// la superficie Nurbs deve essere in forma canonica
if ( snData.bPeriodicU || snData.bPeriodicV || snData.bExtraKnotes )
return nullptr ;
// controllo sul numero dei nodi
int nU = snData.nCPU + snData.nDegU - 1 ;
int nV = snData.nCPV + snData.nDegV - 1 ;
// controllo nodi e punti di controllo
//if ( nU != int( snData.vU.size()) || nV != int( snData.vV.size()) || snData.nCPU * snData.nCPV != int( snData.vCP.size()))
if ( nU != int(snData.vU.size()) || nV != int(snData.vV.size())) {
return nullptr ;
}
//// numero degli intervalli
//int nInt = nU - 2 * snData.nDeg + 1 ;
// verifico le condizioni agli estremi sui nodi (i primi nDeg nodi e gli ultimi nDeg nodi devono essere uguali tra loro)
bool bOk = true ;
// direzione U
for ( int i = 1 ; i < snData.nDegU ; ++ i) {
if ( abs( snData.vU[i] - snData.vU[0]) >= EPS_ZERO)
bOk = false ;
}
for ( int i = 1 ; i < snData.nDegU ; ++ i) {
if ( abs( snData.vU[nU - 1 - i] - snData.vU[nU - 1]) >= EPS_ZERO)
bOk = false ;
}
// direzione V
for ( int i = 1 ; i < snData.nDegV ; ++ i) {
if ( abs( snData.vV[i] - snData.vV[0]) >= EPS_ZERO)
bOk = false ;
}
for ( int i = 1 ; i < snData.nDegV ; ++ i) {
if ( abs( snData.vV[nV - 1 - i] - snData.vV[nV - 1]) >= EPS_ZERO)
bOk = false ;
}
if ( ! bOk)
return nullptr ;
//// se 1 solo intervallo, la Nurbs ? gi? una curva di Bezier
//if ( nInt == 1) {
// // creo la curva di Bezier
// PtrOwner<ICurveBezier> pCrvBez( CreateCurveBezier()) ;
// if ( IsNull( pCrvBez))
// return nullptr ;
// // la inizializzo
// if ( ! pCrvBez->Init( snData.nDeg, snData.bRat))
// return nullptr ;
// for ( int i = 0 ; i <= snData.nDeg ; ++ i) {
// if ( ! snData.bRat) {
// if ( ! pCrvBez->SetControlPoint( i, snData.vCP[i]))
// return nullptr ;
// }
// else {
// if ( ! pCrvBez->SetControlPoint( i, snData.vCP[i], snData.vW[i]))
// return nullptr ;
// }
// }
// // se non ? una curva ma un punto, la invalido
// if ( pCrvBez->IsAPoint())
// pCrvBez->Init( snData.nDeg, snData.bRat) ;
// // restituisco la curva
// return Release( pCrvBez) ;
//}
// algoritmo 5.7 del libro "The NURBS book"//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// creazione delle strips nella direzione U ( trasformo le curve iso con U costante in bezier)
int a = snData.nDegU - 1 ;
int b = snData.nDegU ;
int nb = 0 ; // numero di strisce in U ( lunghezza con U costante)
//PNTVECTOR vBC ;
//vBC.resize( snData.nCPV * snData.nDegU) ;
//for (int row = 0 ; row < snData.nCPV ; ++row ) {
// for ( int i = 0 ; i <= snData.nDegU ; ++i ) {
// vBC[nDegU*row + i] = ( snData.vCP[nCPU*row + i]) ;
// }
//}
vector<Point3d> vCPV( snData.nCPV) ;
vector< vector<Point3d>> mBC (snData.nDegU + 1,vCPV ) ;
vector< vector<Point3d>> mBC_next (snData.nDegU - 1, vCPV) ;
vector< vector<Point3d>> mPC_strip(snData.nDegU + 1, vCPV) ; // matrice che verr? ingrandita e conterr? la superficie met? bezier e met? NURBS
DBLVECTOR vV_W( snData.nCPV) ;
vector<DBLVECTOR> mW( snData.nDegU + 1, vV_W) ;
vector<DBLVECTOR> mW_next( snData.nDegU - 1, vV_W) ;
vector<DBLVECTOR> mW_strip( snData.nDegU + 1, vV_W) ;
DBLVECTOR vAlpha ;
vAlpha.resize( snData.nDegU - 1) ;
if ( ! snData.bRat ) {
for ( int i = 0 ; i <= snData.nDegU ; ++i ) {
for ( int row = 0 ; row < snData.nCPV ; ++row ) {
mBC[i][row] = snData.mCP[i][row] ;
}
}
}
else {
for ( int i = 0 ; i <= snData.nDegU ; ++i ) {
for (int row = 0 ; row < snData.nCPV ; ++ row) {
mW[i][row] = snData.mW[i][row] ;
mBC[i][row] = snData.mCP[i][row] * snData.mW[i][row] ;
}
}
}
bool bRef = false ;
// se la superficie è lineare nel parametro U allora è già in forma di Bezier in questo parametro
if ( b == nU - 1 ) {
nb = 1 ;
}
while ( b < nU - 1) { // qui correggo un probabile errore, mettendo nU anzich nCPV, come indicato nell'algoritmo
int i = b ;
while ( b < nU - 1 && abs( snData.vU[b+1] - snData.vU[b]) < EPS_ZERO)
++ b ;
int mult = b - i + 1 ;
if ( mult < snData.nDegU ) {
bRef = true ;
// calcolo numeratore e alpha
double numer = snData.vU[b] - snData.vU[a] ;
for ( int j = snData.nDegU ; j > mult ; -- j)
vAlpha[j-mult-1] = numer / ( snData.vU[a+j] - snData.vU[a]) ;
int r = snData.nDegU - mult ;
for ( int j = 1 ; j <= snData.nDegU - mult ; ++j ) {
int save = r - j ;
int s = mult + j ;
//for ( int row = 0 ; row < snData.nCPV ; ++row) {
// for ( int k = snData.nDegU ; k >= s ; --k ) {
// vBC[nCPU*row + k] = vAlpha[k-s]*vBC[nCPU*row + k] + ( 1 - vAlfa[k-s]) * vBC[nCPU*row + k - 1]
// }
//}
if ( ! snData.bRat ) {
for ( int k = snData.nDegU ; k >= s ; --k ) {
for ( int row = 0 ; row < snData.nCPV ; ++row) {
mBC[k][row] = vAlpha[k-s] * mBC[k][row] + ( 1 - vAlpha[k-s]) * mBC[k-1][row] ;
}
}
}
else {
for ( int k = snData.nDegU ; k >= s ; --k ) {
for ( int row = 0 ; row < snData.nCPV ; ++row) {
mBC[k][row] = vAlpha[k-s] * mBC[k][row] + ( 1 - vAlpha[k-s]) * mBC[k-1][row] ;
mW[k][row] = vAlpha[k-s] * mW[k][row] + ( 1 - vAlpha[k-s]) * mW[k-1][row] ;
}
}
}
if ( b < nU - 1 ) {
for ( int row = 0 ; row < snData.nCPV ; ++row) {
mBC_next[save][row] = mBC[snData.nDegU][row] ;
}
if ( snData.bRat )
for ( int row = 0 ; row < snData.nCPV ; ++row) {
mW_next[save][row] = mW[snData.nDegU][row] ;
}
}
}
}
mPC_strip.resize( snData.nDegU * ( nb + 1) + 1 , vCPV) ;
mW_strip.resize( snData.nDegU * ( nb + 1) + 1, vV_W) ;
if ( ! snData.bRat)
for ( int i = 0 ; i <= snData.nDegU ; ++i) {
for ( int row = 0 ; row < snData.nCPV ; ++row ) {
mPC_strip[i+ nb * snData.nDegU][row] = mBC[i][row] ;
}
}
else {
for ( int i = 0 ; i <= snData.nDegU ; ++i) {
for ( int row = 0 ; row < snData.nCPV ; ++row ) {
mPC_strip[i+ nb * snData.nDegU][row] = mBC[i][row]/mW[i][row] ;
mW_strip[i+ nb * snData.nDegU][row] = mW[i][row] ;
}
}
}
++ nb ;
// ho finito di definire la patch di Bezier attuale e passo alla successiva
// aggiorno mBC con i valori della prossima pezza di Bezier // corrisponde a nb = nb + 1
if ( ! snData.bRat){
for (int i = 0 ; i < snData.nDegU - 1 ; ++ i) {
for ( int row = 0 ; row < snData.nCPV ; ++row) {
mBC[i][row] = mBC_next[i][row] ;
}
}
}
else {
for (int i = 0 ; i < snData.nDegU - 1 ; ++ i) {
for ( int row = 0 ; row < snData.nCPV ; ++row) {
mBC[i][row] = mBC_next[i][row] ;
mW[i][row] = mW_next[i][row] ;
}
}
}
if ( b < nU - 1 ) {
for ( int i = snData.nDegU - mult ; i <= snData.nDegU ; ++ i) {
for (int row = 0 ; row < snData.nCPV ; ++ row ) {
mBC[i][row] = snData.mCP[b - snData.nDegU + i + 1][row] ;
}
}
if ( snData.bRat ) {
for ( int i = snData.nDegU - mult ; i <= snData.nDegU ; ++ i) {
for (int row = 0 ; row < snData.nCPV ; ++ row ) {
mW[i][row] = snData.mW[b - snData.nDegU + i + 1][row] ;
}
}
}
a = b ;
++b ;
}
}
// se non ho raffinato allora tutti i nodi avevano gi? molteplicit? massima. Converto direttamente in Bezier la dir U
int nCPU_ref ; // numero dei punti di controllo in U dopo il raffinamento
if ( ! bRef ) {
nCPU_ref = snData.nCPU ;
mPC_strip.resize( snData.nCPU, vCPV) ;
mW_strip.resize( snData.nCPU, vV_W) ;
if ( ! snData.bRat) {
for ( int i = 0 ; i < nCPU_ref ; ++i) {
for ( int row = 0 ; row < snData.nCPV ; ++ row) {
mPC_strip[i][row] = snData.mCP[i][row] ;
}
}
}
else {
for ( int i = 0 ; i < nCPU_ref ; ++i) {
for ( int row = 0 ; row < snData.nCPV ; ++ row) {
mPC_strip[i][row] = snData.mCP[i][row] ;
mW_strip[i][row] = snData.mW[i][row] ;
}
}
}
// devo vedere quante patch ci stanno prendendo i punti che ci sono
//nb = (snData.nCPU - 1) / snData.nDegU ;
}
else
nCPU_ref = snData.nDegU * nb + 1 ; // numero dei punti di controllo in U dopo il raffinamento
// ora ho ottenuto le strisce nDegU x nCPV
// devo ripetere la procedura, sulla dir V, per ottenere le patch nDegU x nDegV
a = snData.nDegV - 1 ;
b = snData.nDegV ;
int nc = 0 ; // numero di strisce in V ( lunghezza con V costante)
vector<Point3d> vDegV(snData.nDegV + 1) ;
vector<Point3d> vDegV_1(snData.nDegV - 1) ;
vector< vector<Point3d>> m_BC1( nCPU_ref, vDegV) ;
vector< vector<Point3d>> m_BC1_next( nCPU_ref, vDegV_1) ;
DBLVECTOR vV1_W(snData.nDegV + 1) ;
DBLVECTOR vV2_W(snData.nDegV - 1) ;
vector<DBLVECTOR> mW1( nCPU_ref, vV1_W) ;
vector<DBLVECTOR> mW1_next( nCPU_ref, vV2_W) ;
DBLVECTOR vAlpha1( snData.nDegV - 1) ;
vector<vector<Point3d>> mPC_tot( nCPU_ref, vDegV) ;
vector<DBLVECTOR> mW_tot( nCPU_ref, vV1_W) ;
if ( ! snData.bRat ) {
for ( int i = 0 ; i < nCPU_ref ; ++i ) {
for ( int row = 0 ; row <= snData.nDegV ; ++row ) {
m_BC1[i][row] = mPC_strip[i][row] ;
}
}
}
else {
for ( int i = 0 ; i < nCPU_ref ; ++i ) {
for (int row = 0 ; row <= snData.nDegV ; ++ row) {
mW1[i][row] = mW_strip[i][row] ;
m_BC1[i][row] = mPC_strip[i][row] * mW_strip[i][row] ;
}
}
}
bRef = false ;
// se la superficie è lineare nel parametro V allora è già in forma di Bezier in questo parametro
if ( b == nV - 1 ) {
nc = 1 ;
}
while ( b < nV - 1) { // qui correggo un probabile errore, mettendo nU anzich nCPV, come indicato nell'algoritmo
int i = b ;
while ( b < nV - 1 && abs( snData.vV[b+1] - snData.vV[b]) < EPS_ZERO)
++ b ;
int mult = b - i + 1 ;
if ( mult < snData.nDegV ) {
bRef = true ;
// calcolo numeratore e alpha
double numer = snData.vV[b] - snData.vV[a] ;
for ( int j = snData.nDegV ; j > mult ; -- j)
vAlpha1[j-mult-1] = numer / ( snData.vV[a+j] - snData.vV[a]) ;
int r = snData.nDegV - mult ;
for ( int j = 1 ; j <= snData.nDegV - mult ; ++j ) {
int save = r - j ;
int s = mult + j ;
//for ( int row = 0 ; row < snData.nCPV ; ++row) {
// for ( int k = snData.nDegU ; k >= s ; --k ) {
// vBC[nCPU*row + k] = vAlpha1[k-s]*vBC[nCPU*row + k] + ( 1 - vAlpha1[k-s]) * vBC[nCPU*row + k - 1]
// }
//}
if ( ! snData.bRat) {
for ( int k = 0 ; k < nCPU_ref ; ++k) {
for ( int row = snData.nDegV ; row >= s ; --row ) {
m_BC1[k][row] = vAlpha1[row-s] * m_BC1[k][row] + ( 1 - vAlpha1[row-s]) * m_BC1[k][row-1] ;
}
}
}
else {
for ( int k = 0 ; k < nCPU_ref ; ++k) {
for ( int row = snData.nDegV ; row >= s ; --row ) {
m_BC1[k][row] = vAlpha1[row-s] * m_BC1[k][row] + ( 1 - vAlpha1[row-s]) * m_BC1[k][row-1] ;
mW1[k][row] = vAlpha1[row-s] * mW1[k][row] + ( 1 - vAlpha1[row-s]) * mW1[k][row-1] ;
}
}
}
if ( b < nV - 1 ) {
if ( !snData.bRat ){
for ( int i = 0 ; i < nCPU_ref ; ++i) {
m_BC1_next[i][save] = m_BC1[i][snData.nDegV] ;
}
}
else {
for ( int i = 0 ; i < nCPU_ref ; ++i) {
m_BC1_next[i][save] = m_BC1[i][snData.nDegV] ;
mW1_next[save] = mW1[snData.nDegV] ;
}
}
}
}
}
int nRef = snData.nDegV * ( nc + 1) + 1 ;
for ( int k = 0 ; k < nCPU_ref; ++k){
mPC_tot[k].resize( nRef) ;
mW_tot[k].resize( nRef) ;
}
if ( ! snData.bRat)
for ( int i = 0 ; i < nCPU_ref ; ++i) {
for ( int row = 0 ; row <= snData.nDegV ; ++row ) {
mPC_tot[i][row + nc * snData.nDegV] = m_BC1[i][row] ;
}
}
else {
for ( int i = 0 ; i < nCPU_ref ; ++i) {
for ( int row = 0 ; row <= snData.nDegV ; ++row ) {
mPC_tot[i][row + nc * snData.nDegV] = m_BC1[i][row]/mW1[i][row] ;
mW_tot[i][row + nc * snData.nDegV] = mW1[i][row] ;
}
}
}
++ nc ;
// ho finito di definire la patch di Bezier attuale e passo alla successiva
// aggiorno mBC con i valori della prossima pezza di Bezier // corrisponde a nc = nc + 1
if ( ! snData.bRat){
for (int i = 0 ; i < nCPU_ref ; ++ i) {
for ( int row = 0 ; row < snData.nDegV - 1 ; ++row) {
m_BC1[i][row] = m_BC1_next[i][row] ;
}
}
}
else {
for (int i = 0 ; i < nCPU_ref ; ++ i) {
for ( int row = 0 ; row < snData.nDegV - 1 ; ++row) {
m_BC1[i][row] = m_BC1_next[i][row] ;
mW1[i][row] = mW1_next[i][row] ;
}
}
}
if ( b < nV - 1) {
for (int i = 0 ; i < nCPU_ref ; ++ i ) {
for ( int row = snData.nDegV - mult ; row <= snData.nDegV ; ++ row) {
//m_BC1[i][row] = snData.mCP[i][b - snData.nDegV + row + 1] ;
m_BC1[i][row] = mPC_strip[i][b - snData.nDegV + row + 1] ;
}
}
if ( snData.bRat ) {
for (int i = 0 ; i < nCPU_ref ; ++ i ) {
for ( int row = snData.nDegV - mult ; row <= snData.nDegV ; ++ row) {
//mW1[i][row] = snData.mW[i][b - snData.nDegV + row + 1] ;
mW1[i][row] = mW_strip[i][b - snData.nDegV + row + 1] ;
}
}
}
a = b ;
++b ;
}
}
// se non ho raffinato allora aggiungo direttamente alle matrici della superficie totale
int nCPV_ref ; // numero dei punti di controllo in V dopo il raffinamento
if ( ! bRef) {
nCPV_ref = snData.nCPV ;
for ( int k = 0 ; k < nCPU_ref ; ++k){
mPC_tot[k].resize( snData.nCPV) ;
mW_tot[k].resize( snData.nCPV) ;
}
if ( ! snData.bRat) {
for ( int i = 0 ; i < nCPU_ref ; ++i) {
for ( int row = 0 ; row < nCPV_ref ; ++ row) {
mPC_tot[i][row] = mPC_strip[i][row] ;
}
}
}
else {
for ( int i = 0 ; i < nCPU_ref ; ++i) {
for ( int row = 0 ; row < nCPV_ref ; ++ row) {
mPC_tot[i][row] = mPC_strip[i][row] ;
mW_tot[i][row] = mW_strip[i][row] ;
}
}
}
// devo vedere quante patch ci stanno prendendo i punti che ci sono
//nc = (snData.nCPV - 1) / snData.nDegV ;
}
else
nCPV_ref = snData.nDegV * nc + 1 ;
// finalmente setto la superficie di bezier totale divisa in nb patch in U e nc patch in V
PtrOwner<ISurfBezier> pSrfBz( CreateSurfBezier()) ;
if ( IsNull( pSrfBz))
return nullptr ;
pSrfBz->Init(snData.nDegU, snData.nDegV, nb, nc, snData.bRat) ;
if ( !snData.bRat ) {
for ( int i = 0 ; i < nCPU_ref; ++ i) {
for (int j = 0 ; j < nCPV_ref; ++j) {
pSrfBz->SetControlPoint( i + nCPU_ref * j, mPC_tot[i][j]) ;
}
}
}
else {
for ( int i = 0 ; i < nCPU_ref; ++ i) {
for (int j = 0 ; j < nCPV_ref; ++j) {
pSrfBz->SetControlPoint( i + nCPU_ref * j, mPC_tot[i][j] / mW_tot[i][j], mW_tot[i][j]) ;
}
}
}
return Release( pSrfBz) ;
}