//---------------------------------------------------------------------------- // 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( 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( 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 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 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 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 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 pLoop( CreateBasicCurveComposite()) ; // prima curva U=0 PtrOwner pCbzU0( GetCurveOnU( 0)) ; if ( ! IsNull( pCbzU0) && ! pCbzU0->IsAPoint()) pLoop->AddCurve( Release( pCbzU0)) ; // seconda curva V=1 PtrOwner pCbzV1( GetCurveOnV( 1)) ; if ( ! IsNull( pCbzV1) && ! pCbzV1->IsAPoint()) pLoop->AddCurve( Release( pCbzV1)) ; // terza curva U=1 invertita PtrOwner pCbzU1( GetCurveOnU( 1)) ; if ( ! IsNull( pCbzU1) && ! pCbzU1->IsAPoint()) { pCbzU1->Invert() ; pLoop->AddCurve( Release( pCbzU1)) ; } // quarta curva V=0 invertita PtrOwner 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 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 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 pCbz( GetCurveOnU( dV)) ; double dLen ; if ( IsNull( pCbz) || ! pCbz->GetApproxLength( dLen)) return 0 ; return dLen ; } //---------------------------------------------------------------------------- double SurfBezier::GetCurveOnVApproxLen( double dU) const { PtrOwner 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 ; }