//---------------------------------------------------------------------------- // 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 "/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" 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_pTrimReg( nullptr) { m_nTempProp[0] = 0 ; m_nTempProp[1] = 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( const ISurfFlatRegion& sfrTrimReg) { // verifico la regione passata if ( &sfrTrimReg == nullptr || ! sfrTrimReg.IsValid()) return false ; // limito la regione allo spazio parametrico della superficie PtrOwner< ISurfFlatRegion> pSfrTrim( GetSurfFlatRegionRectangle( SBZ_TREG_COEFF * m_nSpanU, SBZ_TREG_COEFF * m_nSpanV)) ; if ( IsNull( pSfrTrim) || ! pSfrTrim->Intersect( sfrTrimReg) || ! pSfrTrim->IsValid()) return false ; // assegno la regione di trim m_bTrimmed = true ; delete m_pTrimReg ; m_pTrimReg = GetBasicSurfFlatRegion( Release( pSfrTrim)) ; return true ; } //---------------------------------------------------------------------------- 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 ( ! 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, 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 ; m_nTempProp[0] = sbSrc.m_nTempProp[0] ; m_nTempProp[1] = sbSrc.m_nTempProp[1] ; return true ; } //---------------------------------------------------------------------------- GeoObjType SurfBezier::GetType( void) const { return static_cast( 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( 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 ( m_bTrimmed) { // creo l'oggetto ResetTrimRegion() ; m_pTrimReg = CreateBasicSurfFlatRegion() ; if ( m_pTrimReg == nullptr) return false ; // ne leggo i dati IGeoObjRW* pGObjRW = dynamic_cast( 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 ( ! 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 ; // 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 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 lr = 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[lr] = vWeCtrl[k] ; ++ lr ; } } } swap( m_nDegU, m_nDegV) ; 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 pCrvCo( CreateBasicCurveComposite()) ; // ciclo sugli intervalli for ( int k = 0 ; k < m_nSpanU ; ++ k) { // preparazione della curva di Bezier PtrOwner 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 pCrvCo( CreateBasicCurveComposite()) ; // ciclo sugli intervalli for ( int k = 0 ; k < m_nSpanU ; ++ k) { // preparazione della curva di Bezier PtrOwner 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 pCrvCo( CreateBasicCurveComposite()) ; // ciclo sugli intervalli for ( int k = 0 ; k < m_nSpanV ; ++ k) { // preparazione della curva di Bezier PtrOwner 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 pCrvCo( CreateBasicCurveComposite()) ; // ciclo sugli intervalli for ( int k = 0 ; k < m_nSpanV ; ++ k) { // preparazione della curva di Bezier PtrOwner 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 { // 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 pLoop( CreateBasicCurveComposite()) ; // prima curva isoparametrica in U con V=0 PtrOwner pCrvCoU0( GetCurveOnU( 0)) ; if ( ! IsNull( pCrvCoU0) && ! pCrvCoU0->IsAPoint()) pLoop->AddCurve( Release( pCrvCoU0)) ; // seconda curva isoparametrica in V con U=m_nSpanU PtrOwner pCrvCoV1( GetCurveOnV( m_nSpanU)) ; if ( ! IsNull( pCrvCoV1) && ! pCrvCoV1->IsAPoint()) pLoop->AddCurve( Release( pCrvCoV1)) ; // terza curva isoparametrica in U con V=m_nSpanV invertita PtrOwner 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 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) ; } // altrimenti trimmata, per ora non gestita else return nullptr ; } //---------------------------------------------------------------------------- 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 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 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 pCrvCo( GetCurveOnU( dV)) ; double dLen ; if ( IsNull( pCrvCo) || ! pCrvCo->GetApproxLength( dLen)) return 0 ; return dLen ; } //---------------------------------------------------------------------------- double SurfBezier::GetCurveOnVApproxLen( double dU) const { PtrOwner 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 StmFromTriangleSoup stmSoup ; if ( ! stmSoup.Start()) return nullptr ; // definisco il numero degli step in U e in V double dMaxLenU = 0 ; for ( int j = 0 ; j <= m_nDegV * m_nSpanV ; ++ j) dMaxLenU = max( dMaxLenU, GetCurveOnUApproxLen( double( j) / m_nDegV)) ; int nStepU = GetSteps( m_nDegU, m_nSpanU, dMaxLenU, 2) ; double dMaxLenV = 0 ; for ( int i = 0 ; i <= m_nDegU * m_nSpanU ; ++ i) dMaxLenV = max( dMaxLenV, GetCurveOnVApproxLen( double( i) / m_nDegU)) ; int nStepV = GetSteps( m_nDegV, m_nSpanV, 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) * m_nSpanV / 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 if ( ! stmSoup.End()) return nullptr ; // 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 ; } //---------------------------------------------------------------------------- void SurfBezier::ResetTrimRegion( void) { if ( m_pTrimReg != nullptr) delete( m_pTrimReg) ; m_pTrimReg = nullptr ; }