2023-06-15 13:09:04 +10:00
|
|
|
/* SPDX-FileCopyrightText: 2000 `Bruno Levy <levy@loria.fr>`
|
|
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
|
*
|
2012-12-22 18:25:01 +00:00
|
|
|
* The Original Code is:
|
2023-06-15 13:09:04 +10:00
|
|
|
* - GXML/Graphite: Geometry and Graphics Programming Library + Utilities.
|
|
|
|
|
*/
|
2008-04-30 15:41:54 +00:00
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
|
* \ingroup freestyle
|
2012-12-22 18:25:01 +00:00
|
|
|
*/
|
2008-04-30 15:41:54 +00:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
#include "matrix_util.h"
|
2008-04-30 15:41:54 +00:00
|
|
|
|
Cleanup: reduce amount of math-related includes
Using ClangBuildAnalyzer on the whole Blender build, it was pointing
out that BLI_math.h is the heaviest "header hub" (i.e. non tiny file
that is included a lot).
However, there's very little (actually zero) source files in Blender
that need "all the math" (base, colors, vectors, matrices,
quaternions, intersection, interpolation, statistics, solvers and
time). A common use case is source files needing just vectors, or
just vectors & matrices, or just colors etc. Actually, 181 files
were including the whole math thing without needing it at all.
This change removes BLI_math.h completely, and instead in all the
places that need it, includes BLI_math_vector.h or BLI_math_color.h
and so on.
Change from that:
- BLI_math_color.h was included 1399 times -> now 408 (took 114.0sec
to parse -> now 36.3sec)
- BLI_simd.h 1403 -> 418 (109.7sec -> 34.9sec).
Full rebuild of Blender (Apple M1, Xcode, RelWithDebInfo) is not
affected much (342sec -> 334sec). Most of benefit would be when
someone's changing BLI_simd.h or BLI_math_color.h or similar files,
that now there's 3x fewer files result in a recompile.
Pull Request #110944
2023-08-09 11:39:20 +03:00
|
|
|
#include "BLI_math_base.h"
|
2023-08-11 12:51:10 +03:00
|
|
|
#include "BLI_utildefines.h"
|
2014-04-17 12:01:10 +09:00
|
|
|
|
2020-11-07 18:17:12 +05:30
|
|
|
namespace Freestyle::OGF::MatrixUtil {
|
2012-12-22 18:25:01 +00:00
|
|
|
|
|
|
|
|
static const double EPS = 0.00001;
|
|
|
|
|
static int MAX_ITER = 100;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
void semi_definite_symmetric_eigen(const double *mat, int n, double *eigen_vec, double *eigen_val)
|
|
|
|
|
{
|
|
|
|
|
double *a, *v;
|
|
|
|
|
double a_norm, a_normEPS, thr, thr_nn;
|
|
|
|
|
int nb_iter = 0;
|
|
|
|
|
int jj;
|
|
|
|
|
int i, j, k, ij, ik, l, m, lm, mq, lq, ll, mm, imv, im, iq, ilv, il, nn;
|
|
|
|
|
int *index;
|
|
|
|
|
double a_ij, a_lm, a_ll, a_mm, a_im, a_il;
|
|
|
|
|
double a_lm_2;
|
|
|
|
|
double v_ilv, v_imv;
|
|
|
|
|
double x;
|
|
|
|
|
double sinx, sinx_2, cosx, cosx_2, sincos;
|
|
|
|
|
double delta;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
// Number of entries in mat
|
|
|
|
|
nn = (n * (n + 1)) / 2;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
// Step 1: Copy mat to a
|
|
|
|
|
a = new double[nn];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
for (ij = 0; ij < nn; ij++) {
|
|
|
|
|
a[ij] = mat[ij];
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
// Ugly Fortran-porting trick: indices for a are between 1 and n
|
|
|
|
|
a--;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
// Step 2 : Init diagonalization matrix as the unit matrix
|
|
|
|
|
v = new double[n * n];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
ij = 0;
|
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
|
for (j = 0; j < n; j++) {
|
|
|
|
|
if (i == j) {
|
|
|
|
|
v[ij++] = 1.0;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
v[ij++] = 0.0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
// Ugly Fortran-porting trick: indices for v are between 1 and n
|
|
|
|
|
v--;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-17 17:05:14 +02:00
|
|
|
// Step 3 : compute the weight of the non diagonal terms
|
2012-12-22 18:25:01 +00:00
|
|
|
ij = 1;
|
|
|
|
|
a_norm = 0.0;
|
|
|
|
|
for (i = 1; i <= n; i++) {
|
|
|
|
|
for (j = 1; j <= i; j++) {
|
|
|
|
|
if (i != j) {
|
|
|
|
|
a_ij = a[ij];
|
|
|
|
|
a_norm += a_ij * a_ij;
|
|
|
|
|
}
|
|
|
|
|
ij++;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
if (a_norm != 0.0) {
|
|
|
|
|
a_normEPS = a_norm * EPS;
|
|
|
|
|
thr = a_norm;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
// Step 4 : rotations
|
|
|
|
|
while (thr > a_normEPS && nb_iter < MAX_ITER) {
|
|
|
|
|
nb_iter++;
|
|
|
|
|
thr_nn = thr / nn;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
for (l = 1; l < n; l++) {
|
|
|
|
|
for (m = l + 1; m <= n; m++) {
|
|
|
|
|
// compute sinx and cosx
|
|
|
|
|
lq = (l * l - l) / 2;
|
|
|
|
|
mq = (m * m - m) / 2;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
lm = l + mq;
|
|
|
|
|
a_lm = a[lm];
|
|
|
|
|
a_lm_2 = a_lm * a_lm;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
if (a_lm_2 < thr_nn) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
ll = l + lq;
|
|
|
|
|
mm = m + mq;
|
|
|
|
|
a_ll = a[ll];
|
|
|
|
|
a_mm = a[mm];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
delta = a_ll - a_mm;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
if (delta == 0.0) {
|
2022-03-11 16:14:05 +01:00
|
|
|
x = -M_PI_4;
|
2012-12-22 18:25:01 +00:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
x = -atan((a_lm + a_lm) / delta) / 2.0;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
sinx = sin(x);
|
|
|
|
|
cosx = cos(x);
|
|
|
|
|
sinx_2 = sinx * sinx;
|
|
|
|
|
cosx_2 = cosx * cosx;
|
|
|
|
|
sincos = sinx * cosx;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
// rotate L and M columns
|
|
|
|
|
ilv = n * (l - 1);
|
|
|
|
|
imv = n * (m - 1);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
for (i = 1; i <= n; i++) {
|
2020-11-06 12:30:59 +11:00
|
|
|
if (!ELEM(i, l, m)) {
|
2012-12-22 18:25:01 +00:00
|
|
|
iq = (i * i - i) / 2;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
if (i < m) {
|
|
|
|
|
im = i + mq;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
im = m + iq;
|
|
|
|
|
}
|
|
|
|
|
a_im = a[im];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
if (i < l) {
|
|
|
|
|
il = i + lq;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
il = l + iq;
|
|
|
|
|
}
|
|
|
|
|
a_il = a[il];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
a[il] = a_il * cosx - a_im * sinx;
|
|
|
|
|
a[im] = a_il * sinx + a_im * cosx;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
ilv++;
|
|
|
|
|
imv++;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
v_ilv = v[ilv];
|
|
|
|
|
v_imv = v[imv];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
v[ilv] = cosx * v_ilv - sinx * v_imv;
|
|
|
|
|
v[imv] = sinx * v_ilv + cosx * v_imv;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
x = a_lm * sincos;
|
|
|
|
|
x += x;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
a[ll] = a_ll * cosx_2 + a_mm * sinx_2 - x;
|
|
|
|
|
a[mm] = a_ll * sinx_2 + a_mm * cosx_2 + x;
|
|
|
|
|
a[lm] = 0.0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
thr = fabs(thr - a_lm_2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
// Step 5: index conversion and copy eigen values
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
// back from Fortran to C++
|
|
|
|
|
a++;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
|
k = i + (i * (i + 1)) / 2;
|
|
|
|
|
eigen_val[i] = a[k];
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
delete[] a;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
// Step 6: sort the eigen values and eigen vectors
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
index = new int[n];
|
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
|
index[i] = i;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
for (i = 0; i < (n - 1); i++) {
|
|
|
|
|
x = eigen_val[i];
|
|
|
|
|
k = i;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
for (j = i + 1; j < n; j++) {
|
|
|
|
|
if (x < eigen_val[j]) {
|
|
|
|
|
k = j;
|
|
|
|
|
x = eigen_val[j];
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
eigen_val[k] = eigen_val[i];
|
|
|
|
|
eigen_val[i] = x;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
jj = index[k];
|
|
|
|
|
index[k] = index[i];
|
|
|
|
|
index[i] = jj;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-17 17:05:14 +02:00
|
|
|
// Step 7: save the eigen vectors
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-02-04 01:23:48 +01:00
|
|
|
// back from Fortran to C++
|
2012-12-22 18:25:01 +00:00
|
|
|
v++;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
ij = 0;
|
|
|
|
|
for (k = 0; k < n; k++) {
|
|
|
|
|
ik = index[k] * n;
|
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
|
eigen_vec[ij++] = v[ik++];
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-22 18:25:01 +00:00
|
|
|
delete[] v;
|
|
|
|
|
delete[] index;
|
|
|
|
|
}
|
|
|
|
|
|
2008-04-30 15:41:54 +00:00
|
|
|
//_________________________________________________________
|
|
|
|
|
|
2020-11-07 18:17:12 +05:30
|
|
|
} // namespace Freestyle::OGF::MatrixUtil
|