EgtGeomKernel 2.7k2 :

- aggiunta funzione per il calcolo della curvatura in un vertice per una superficie TriMesh.
This commit is contained in:
Riccardo Elitropi
2025-11-04 16:02:04 +01:00
parent dced59b9a1
commit b3abcf73c3
3 changed files with 155 additions and 0 deletions
BIN
View File
Binary file not shown.
+4
View File
@@ -322,6 +322,10 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW
bool GetEdge( int nInd, int& nV1, int& nV2, int& nFl, int& nFr, double& dAng) const override ;
bool GetEdge( int nInd, Point3d& ptP1, Point3d& ptP2, double& dAng) const override ;
bool GetEdges( ICURVEPOVECTOR& vpCurve) const override ;
bool GetCurvature( int nV,
double& dMinK, Vector3d& vtMinK, double& dMaxK, Vector3d& vtMaxK, bool& bPlanar, Vector3d& vtNorm,
double* dGaussK = nullptr, double* dMeanK = nullptr,
double* dMaxNormK = nullptr, double* dMinNormK = nullptr) const override ;
bool Cut( const Plane3d& plPlane, bool bSaveOnEq) override ;
bool GeneralizedCut( const ICurve& cvCurve, bool bSaveOnEq) override ;
bool Add( const ISurfTriMesh& Other) override ;
+151
View File
@@ -21,6 +21,8 @@
#include <array>
#include <set>
#include <unordered_map>
#define EIGEN_NO_IO
#include "/EgtDev/Extern/Eigen/Dense"
using namespace std ;
@@ -1015,3 +1017,152 @@ SurfTriMesh::GetEdges( ICURVEPOVECTOR& vpCurve) const
}
return true ;
}
//-----------------------------------------------------------------------------
// Funzione per il calcolo della curvatura massima e minima in un vertice della superficie TriMesh
// vtMinK : versore direzione curvatura minima ( dMinK è il suo modulo con segno)
// vtMaxK : versore direzione curvatura massima ( dMaxK è il suo modulo con segno)
// bPlanar : Flag per indicare le superficie localmente piana
// vtNorm : versore normale del piano tangente alla supericie nel vertice
// dGaussK : valore della curvatura gaussiana con segno ( da associarsi a vtNorm)
// dMeanK : valore della curvatura media con segno ( da associarsi a vtNorm)
// dMaxNormK : valore della curvatura normale massima con segno ( da associarsi a vtNorm)
// dMinNormK : valore della curvatura normale minima con segno ( da associarsi a vtNorm)
bool
SurfTriMesh::GetCurvature( int nV,
double& dMinK, Vector3d& vtMinK, double& dMaxK, Vector3d& vtMaxK, bool& bPlanar, Vector3d& vtNorm,
double* dGaussK, double* dMeanK, double* dMaxNormK, double* dMinNormK) const
{
// Controllo la validità della TriMesh e del Vertice
if ( ! IsValid())
return false ;
Point3d ptCurr ;
if ( ! GetVertex( nV, ptCurr))
return false ;
bPlanar = false ;
// Recupero tutti i vertici attorno al vertice corrente ( se presenza di lato libero, allora errore)
INTVECTOR vT ;
bool bCirc ;
if ( ! GetAllTriaAroundVertex( nV, vT, bCirc) || ! bCirc)
return false ;
// Calcolo la normale del vertice pesata mediante angolo sotteso
// [Meyer et al. (2003) Discrete Differential-Geometry Operators for Triangulated 2-Manifolds
// Section 5.4.2. Tip-Angle Weights.]
// [https://www.cs.cmu.edu/~kmcrane/Projects/DDG/paper.pdf]
INTSET setIndTriaNeightbors ;
for ( const int& nT : vT) {
// Recupero le direzioni delle semirette per l'angolo al vertice corrente
Triangle3d Tria ;
int nIdVert[3] ;
if ( ! GetTriangle( nT, Tria) || ! GetTriangle( nT, nIdVert))
return false ;
Vector3d vtDir0 = V_NULL, vtDir1 = V_NULL ;
for ( int i = 0 ; i < 3 ; ++ i) {
if ( AreSamePointApprox( Tria.GetP( i), ptCurr)) {
vtDir0 = Tria.GetP( ( i + 1) % 3) - Tria.GetP( i) ;
vtDir0.Normalize() ;
vtDir1 = Tria.GetP( ( i + 2) % 3) - Tria.GetP( i) ;
vtDir1.Normalize() ;
break ;
}
}
for ( int i = 0 ; i < 3 ; ++ i) {
if ( nV == nIdVert[i]) {
setIndTriaNeightbors.insert( nIdVert[( i + 1) % 3]) ;
setIndTriaNeightbors.insert( nIdVert[( i + 2) % 3]) ;
break ;
}
}
// Calcolo l'angolo sotteso
double dCosTheta = max( -1., min( 1., ( vtDir0 * vtDir1))) ;
double dTheta = acos( dCosTheta) ;
// Aggiorno il contributo della normale al vertice
vtNorm += ( dTheta * Tria.GetN()) ;
}
vtNorm.Normalize() ;
// [ESTIMATING CURVATURE ON TRIANGULAR MESHES, cap. 2.1. Fitting Methods,
// par. 2.1.2. Quadric Fitting]
// [https://people.eecs.berkeley.edu/~jrs/meshpapers/GatzkeGrimm.pdf]
// Definisco il piano tangente al vertice corrente
Plane3d plTan ;
if ( ! plTan.Set( ptCurr, vtNorm))
return false ;
// Proietto i punti Neightbors(1) sul piano tangete ( senza ripeterli)
BIPNTVECTOR vPtPtProj ; vPtPtProj.reserve( setIndTriaNeightbors.size()) ;
for ( auto nIter = setIndTriaNeightbors.begin() ; nIter != setIndTriaNeightbors.end() ; ++ nIter) {
Point3d ptNeightbors ;
if ( ! GetVertex( *nIter, ptNeightbors))
return false ;
vPtPtProj.emplace_back( make_pair( ptNeightbors, ProjectPointOnPlane( ptNeightbors, plTan))) ;
}
// Recupero due versori perpendicolari nel piano definito
Vector3d vtTan1 = V_NULL ;
if ( abs( vtNorm.x) < 1./64. && abs( vtNorm.y) < 1./64.)
vtTan1 = Y_AX ^ vtNorm ;
else
vtTan1 = Z_AX ^ vtNorm ;
vtTan1.Normalize() ;
Vector3d vtTan2 = vtNorm ^ vtTan1 ;
vtTan2.Normalize() ;
// Sistema da risolvere mediante minimi quadrati : z(u,v) = Au^2 + Buv + Cv^2
// Questo sistema è molto più semplice e robusto rispetto a z(u,v) = Au^2 + Buv + Cv^2 + Du + Ev + F
// per il fatto che ora le coordinate sono in locale al piano tangente alla superficie ( mettendo
// quindi a 0 i coefficienti del primo ordine e il termine noto F)
// Definizione della matrice A(Nx3)
const int nPts = int( vPtPtProj.size()) ;
Eigen::MatrixXd mat_A( nPts, 3) ;
Eigen::VectorXd vec_b( nPts) ;
for ( int i = 0 ; i < nPts ; ++ i) {
Vector3d vtEdgeProj = vPtPtProj[i].second - ptCurr ;
Vector3d vtEdge = ( vPtPtProj[i].first - vPtPtProj[i].second) ;
double dU = vtEdgeProj * vtTan1 ;
double dV = vtEdgeProj * vtTan2 ;
double dW = vtEdge * vtNorm ;
mat_A( i, 0) = dU * dU ;
mat_A( i, 1) = dU * dV ;
mat_A( i, 2) = dV * dV ;
vec_b( i) = dW ;
}
// Risoluzione del sistema
Eigen::VectorXd vec_x = mat_A.colPivHouseholderQr().solve( vec_b) ;
// Costruzione della matrice hessiana
Eigen::Matrix2d mat_H ;
mat_H << 2. * vec_x( 0), vec_x( 1),
vec_x( 1), 2. * vec_x( 2) ;
// Calcolo gli autovalori ( quindi le curvature principali) e restituisco i risultati
Eigen::SelfAdjointEigenSolver<Eigen::Matrix2d> Solver( mat_H) ;
dMinK = Solver.eigenvalues()( 0) ;
dMaxK = Solver.eigenvalues()( 1) ;
Eigen::Vector2d dir_Min = Solver.eigenvectors().col( 0) ;
Eigen::Vector2d dir_Max = Solver.eigenvectors().col( 1) ;
vtMinK = dir_Min( 0) * vtTan1 + dir_Min( 1) * vtTan2 ;
vtMaxK = dir_Max( 0) * vtTan1 + dir_Max( 1) * vtTan2 ;
bPlanar = ( abs( dMinK) < EPS_SMALL && abs( dMaxK) < EPS_SMALL) ;
// Se rischiesto calcolo della curvatura Gaussiana
if ( dGaussK != nullptr)
*dGaussK = ( dMinK * dMaxK) ;
// Se richiesto calcolo della curvatura Media
if ( dMeanK != nullptr)
*dMeanK = ( dMinK + dMaxK) / 2. ;
// Se richiesto calcolo della curvatura normale lungo la direzione massima
if ( dMaxNormK != nullptr)
*dMaxNormK = dir_Max.transpose() * mat_H * dir_Max ;
// Se richiesto calcolo della curvatura normale lungo la direzione minima
if ( dMinNormK != nullptr)
*dMinNormK = dir_Min.transpose() * mat_H * dir_Min ;
return true ;
}