Ponca  5b0151ad2869758185d699615c3cca5855cc2cee
Point Cloud Analysis library
Loading...
Searching...
No Matches
cncFormulaEigen.h
1
62#pragma once
63
64#include <Eigen/Dense>
65
66namespace Ponca::internal {
67
72template<typename DataPoint>
73struct CNCEigen {
74 using MatrixType = typename DataPoint::MatrixType;
75 using Scalar = typename DataPoint::Scalar;
76 using VectorType = typename DataPoint::VectorType;
78 static constexpr Scalar epsilon = Eigen::NumTraits<Scalar>::epsilon();
79
83 static bool isDegenerate(const VectorType& a, const VectorType& b, const VectorType& c) {
84 Scalar d[3] = {(a - b).norm(), (a - c).norm(), (b - c).norm()};
85 // Checks that the spherical triangle is small or thin.
86 if ((d[0] < epsilon) || (d[1] < epsilon) || (d[2] < epsilon))
87 return true;
88 // Checks that the spherical triangle is flat.
89 size_t m = 0;
90 if (d[1] > d[m]) m = 1;
91 if (d[2] > d[m]) m = 2;
92 return (fabs(d[m] - d[(m + 1) % 3] - d[(m + 2) % 3]) < epsilon);
93 }
94
96 static void polarTriangle(
97 const VectorType& a, const VectorType& b, const VectorType& c,
98 VectorType& Ap , VectorType& Bp , VectorType& Cp
99 ) {
100 Ap = b.cross(c);
101 Bp = c.cross(a);
102 Cp = a.cross(b);
103 // Reorient points.
104 if (Ap.dot(a) < 0.0) Ap = -Ap;
105 if (Bp.dot(b) < 0.0) Bp = -Bp;
106 if (Cp.dot(c) < 0.0) Cp = -Cp;
107 }
108
113 static void interiorAngles(
114 const VectorType& a, const VectorType& b, const VectorType& c,
115 Scalar& alpha , Scalar& beta , Scalar& gamma
116 ) {
117 VectorType Ta, Tb, Tc;
118 polarTriangle(a, b, c, Ta, Tb, Tc);
119 Ta /= Ta.norm();
120 Tb /= Tb.norm();
121 Tc /= Tc.norm();
122 if (Ta == VectorType::Zero() || Tb == VectorType::Zero() || Tc == VectorType::Zero())
123 alpha = beta = gamma = Scalar(0.0);
124 else
125 {
126 Scalar ca = std::max(Scalar(-1.0), std::min(Scalar(1.0), Tb.dot(Tc)));
127 Scalar cb = std::max(Scalar(-1.0), std::min(Scalar(1.0), Tc.dot(Ta)));
128 Scalar cc = std::max(Scalar(-1.0), std::min(Scalar(1.0), Ta.dot(Tb)));
129 alpha = acos(ca);
130 beta = acos(cb);
131 gamma = acos(cc);
132 }
133 }
134
136 static Scalar area(const VectorType& a, const VectorType& b, const VectorType& c) {
137 Scalar alpha, beta, gamma;
138 if (isDegenerate(a, b, c)) return 0.0;
139 interiorAngles(a, b, c, alpha, beta, gamma);
140 return ((fabs(alpha) < epsilon)
141 || (fabs(beta) < epsilon)
142 || (fabs(gamma) < epsilon))
143 ? Scalar(0.0)
144 : 2.0 * M_PI - alpha - beta - gamma;
145 }
146
148 static Scalar algebraicArea(const VectorType& a, const VectorType& b, const VectorType& c) {
149 Scalar S = area(a, b, c);
150 VectorType M = a + b + c;
151 VectorType X = (b - a).cross(c - a);
152 if (M.template lpNorm<1>() <= epsilon || X.template lpNorm<1>() <= epsilon) return 0.0;
153 return M.dot(X) < 0.0 ? -S : S;
154 }
155 };
156
157
158 // ---------------------- Main functions ----------------
159public:
162
175 static Scalar mu0InterpolatedU(
176 const VectorType& a,
177 const VectorType& b,
178 const VectorType& c,
179 const VectorType& ua,
180 const VectorType& ub,
181 const VectorType& uc,
182 bool unit_u = false
183 ) {
184 // MU0=1/2*det( uM, B-A, C-A )
185 // = 1/2 < ( (u_A + u_B + u_C)/3.0 ) | (AB x AC ) >
186 VectorType uM = (ua + ub + uc) / 3.0;
187 if (unit_u) {
188 auto uM_norm = uM.norm();
189 uM = uM_norm == 0.0 ? uM : uM / uM_norm;
190 }
191 return 0.5 * ((b - a).cross(c - a)).dot(uM);
192 }
193
194
207 static Scalar mu1InterpolatedU(
208 const VectorType& a,
209 const VectorType& b,
210 const VectorType& c,
211 const VectorType& ua,
212 const VectorType& ub,
213 const VectorType& uc,
214 bool unit_u = false
215 ) {
216 // MU1=1/2( | uM u_C-u_B A | + | uM u_A-u_C B | + | uM u_B-u_A C |
217 VectorType uM = (ua + ub + uc) / 3.0;
218 if (unit_u) uM /= uM.norm();
219 return 0.25 * (uM.cross(uc - ub).dot(a)
220 + uM.cross(ua - uc).dot(b)
221 + uM.cross(ub - ua).dot(c));
222 }
223
224
237 static Scalar mu2InterpolatedU(
238 const VectorType& a,
239 const VectorType& b,
240 const VectorType& c,
241 const VectorType& ua,
242 const VectorType& ub,
243 const VectorType& uc,
244 bool unit_u = false
245 ) {
246 // Using non unitary interpolated normals give
247 // MU2=1/2*det( uA, uB, uC )
248 // When normals are unitary, it is the area of a spherical triangle.
249 if (unit_u)
250 return SphericalTriangle::algebraicArea(ua, ub, uc);
251 else
252 return 0.5 * (ua.cross(ub).dot(uc));
253 }
254
255
265 static MatrixType muXYInterpolatedU(
266 const VectorType& a,
267 const VectorType& b,
268 const VectorType& c,
269 const VectorType& ua,
270 const VectorType& ub,
271 const VectorType& uc,
272 bool unit_u = false
273 ) {
274 MatrixType T = MatrixType::Zero();
275 VectorType uM = (ua + ub + uc) / 3.0;
276 if (unit_u) uM /= uM.norm();
277 const VectorType uac = uc - ua;
278 const VectorType uab = ub - ua;
279 const VectorType ab = b - a;
280 const VectorType ac = c - a;
281 for (size_t i = 0; i < 3; ++i) {
282 VectorType X = VectorType::Zero();
283 X(i) = 1.0;
284 for (size_t j = 0; j < 3; ++j) {
285 // Since RealVector Y = RealVector::base( j, 1.0 );
286 // < Y | uac > = uac[ j ]
287 const Scalar tij =
288 0.5 * uM.dot(uac[j] * X.cross(ab)
289 - uab[j] * X.cross(ac));
290 T(i, j) = tij;
291 }
292 }
293 return T;
294 }
295
297
298 // ---------------------- Helper functions ----------------
299public:
302
308 static std::pair<VectorType, VectorType> curvDirFromTensor(
309 const MatrixType& tensor,
310 const Scalar area,
311 const VectorType& N
312 ) {
313 auto Mt = tensor.transpose();
314 auto M = tensor;
315 M += Mt;
316 M *= 0.5;
317 const Scalar coef_N = 1000.0 * area;
318 // Adding 1000 area n x n to anisotropic measure
319 for (int j = 0; j < 3; j++)
320 for (int k = 0; k < 3; k++)
321 M(j, k) += coef_N * N[j] * N[k];
322
323 Eigen::SelfAdjointEigenSolver<MatrixType> eigensolver(M);
324 if (eigensolver.info() != Eigen::Success) abort();
325
326 //SelfAdjointEigenSolver returns sorted eigenvalues, no
327 //need to reorder the eigenvectors.
328 assert(eigensolver.eigenvalues()(0) <= eigensolver.eigenvalues()(1));
329 assert(eigensolver.eigenvalues()(1) <= eigensolver.eigenvalues()(2));
330 VectorType v1 = eigensolver.eigenvectors().col(1);
331 VectorType v2 = eigensolver.eigenvectors().col(0);
332 return std::pair<VectorType, VectorType>(v1, v2);
333 }
334
340 static std::tuple<Scalar, Scalar, VectorType, VectorType> curvaturesFromTensor(
341 const MatrixType& tensor,
342 const Scalar area,
343 const VectorType& N
344 ) {
345 auto Mt = tensor.transpose();
346 auto M = tensor;
347 M += Mt;
348 M *= 0.5;
349 const Scalar coef_N = 1000.0 * area;
350 // Adding 1000 area n x n to anisotropic measure
351 for (int j = 0; j < 3; j++)
352 for (int k = 0; k < 3; k++)
353 M(j, k) += coef_N * N[j] * N[k];
354
355 Eigen::SelfAdjointEigenSolver<MatrixType> eigensolver(M);
356 if (eigensolver.info() == Eigen::Success) {
357 // SelfAdjointEigenSolver returns sorted eigenvalues, no
358 // need to reorder the eigenvectors.
359 assert(eigensolver.eigenvalues()(0) <= eigensolver.eigenvalues()(1));
360 assert(eigensolver.eigenvalues()(1) <= eigensolver.eigenvalues()(2));
361 VectorType v1 = eigensolver.eigenvectors().col(0);
362 VectorType v2 = eigensolver.eigenvectors().col(1);
363 return std::make_tuple(-eigensolver.eigenvalues()(0),
364 -eigensolver.eigenvalues()(1),
365 v1, v2);
366 } else {
367 std::cerr << "Incorrect diagonalization for tensor " << M << std::endl;
368 VectorType v1, v2;
369 return std::make_tuple(Scalar(0.0), Scalar(0.0), v1, v2);
370 }
371 }
372
374}; // struct CNCEigen
375
376}
Copyright (c) 2022 Jacques-Olivier Lachaud (jacques-olivier.lachaud@univ-savoie.fr) Laboratory of Mat...
Represents a triangle on a sphere of radius one.
static void polarTriangle(const VectorType &a, const VectorType &b, const VectorType &c, VectorType &Ap, VectorType &Bp, VectorType &Cp)
static Scalar area(const VectorType &a, const VectorType &b, const VectorType &c)
static Scalar algebraicArea(const VectorType &a, const VectorType &b, const VectorType &c)
static bool isDegenerate(const VectorType &a, const VectorType &b, const VectorType &c)
Spherical point data type.
static void interiorAngles(const VectorType &a, const VectorType &b, const VectorType &c, Scalar &alpha, Scalar &beta, Scalar &gamma)
Returns the interior angles of the spherical triangle ABC.
This class contains some stand-alone CorrectedNormalCurrent formulas for triangles,...
static Scalar mu2InterpolatedU(const VectorType &a, const VectorType &b, const VectorType &c, const VectorType &ua, const VectorType &ub, const VectorType &uc, bool unit_u=false)
Computes mu2 measure (Gaussian curvature) of triangle abc given an interpolated corrected normal vect...
static Scalar mu0InterpolatedU(const VectorType &a, const VectorType &b, const VectorType &c, const VectorType &ua, const VectorType &ub, const VectorType &uc, bool unit_u=false)
Computes mu0 measure (area) of triangle abc given an interpolated corrected normal vector ua,...
static MatrixType muXYInterpolatedU(const VectorType &a, const VectorType &b, const VectorType &c, const VectorType &ua, const VectorType &ub, const VectorType &uc, bool unit_u=false)
Computes muXY measure (anisotropic curvature) of triangle abc given an interpolated corrected normal ...
static std::tuple< Scalar, Scalar, VectorType, VectorType > curvaturesFromTensor(const MatrixType &tensor, const Scalar area, const VectorType &N)
Computing principal curvatures k1 and k2 from tensor.
static Scalar mu1InterpolatedU(const VectorType &a, const VectorType &b, const VectorType &c, const VectorType &ua, const VectorType &ub, const VectorType &uc, bool unit_u=false)
Computes mu1 measure (mean curvature) of triangle abc given an interpolated corrected normal vector u...
static constexpr Scalar epsilon
Small constant used to approximate zero.
static std::pair< VectorType, VectorType > curvDirFromTensor(const MatrixType &tensor, const Scalar area, const VectorType &N)
Computing principal curvatures k1 and k2 from tensor.