Monado OpenXR Runtime
Loading...
Searching...
No Matches
eig3x3known0.h
Go to the documentation of this file.
1// Copyright 2019, Philipp Zabel
2// Copyright 2026, Beyley Cardellio
3// SPDX-License-Identifier: BSL-1.0
4/*!
5 * @file
6 * @brief Eigenvalue solver for 3x3 symmetric matrices with known zero eigenvalue, specialized for P3P solving.
7 * @author Philipp Zabel <philipp.zabel@gmail.com>
8 * @author Beyley Cardellio <ep1cm1n10n123@gmail.com>
9 * @ingroup xrt_iface
10 */
11
12#pragma once
13
14#include "quadratic.h"
15
16#include <math.h>
17
18
19/*
20 * This implements algorithm 2 "eig3x3known0" described in the paper "Lambda
21 * Twist: An Accurate Fast Robust Perspective Three Point (P3P) Solver." by
22 * Mikael Persson and Klas Nordberg. See the paper for details.
23 *
24 * 1: function GETEIGVECTOR(m, r)
25 * this is open coded below, since it is called twice, and intermediate
26 * values are reused
27 *
28 * 7: function EIG3X3KNOWN0(M)
29 * this function does not write E[2,5,8]
30 */
31static inline void
32eig3x3known0(const double *M, double *E, double *sigma)
33{
34 /* 8: b₃ = M(:,2) x M(:,3); */
35 /* 9: b₃ = b₃ / |b₃| */
36 /* we skip steps 8 and 9 */
37
38 /*
39 * 10: m = M(:)
40 *
41 * we are passed just the upper triangular part of symmetric matrix M:
42 *
43 * ⎛ m₁ m₂ m₃ ⎞
44 * M = ⎜ m₅ m₆ ⎟
45 * ⎝ m₈ ⎠
46 */
47 const double m1 = M[0];
48 const double m2 = M[1];
49 const double m3 = M[2];
50 const double m5 = M[3];
51 const double m6 = M[4];
52 const double m9 = M[5];
53
54 /* reusable intermediate values */
55 const double m2_sq = m2 * m2;
56 const double m1_plus_m5 = m1 + m5;
57
58 /* 11: p₁ = m₁ - m₅ - m₉ */
59 /* -- */
60 const double p1 = -m1_plus_m5 - m9;
61
62 /* 12: p₀ = -m₂² - m₃² - m₆² + m₁m₅ + m₉ + m₅m₉ */
63 /* --------- */
64 const double p0 = -m2_sq - m3 * m3 - m6 * m6 + m1 * (m5 + m9) + m5 * m9;
65
66 /* 13: [σ₁, σ₂] as the roots of σ² + p₁σ + p₀ = 0 */
67 double sigma1 = 0.0;
68 double sigma2 = 0.0;
69 reduced_quadratic_real_roots(p1, p0, &sigma1, &sigma2);
70
71 if (fabs(sigma1) > fabs(sigma2)) {
72 sigma[0] = sigma1;
73 sigma[1] = sigma2;
74 } else {
75 sigma[0] = sigma2;
76 sigma[1] = sigma1;
77 }
78
79 const double r1 = sigma[0];
80 const double r2 = sigma[1];
81
82 /*
83 * 14: b₁ = GETEIGVECTOR(m, σ₁)
84 * 15: b₂ = GETEIGVECTOR(m, σ₂)
85 * 16: if |σ₁| > |σ₂| then
86 * 17: Return ([b1, b2, b3], σ₁, σ₂)
87 * 18: else
88 * 19: Return ([b2, b1, b3], σ₂, σ₁)
89 */
90
91 /* reusable intermediate values */
92 const double m1m5_minus_m2sq = m1 * m5 - m2_sq;
93 const double m2m6_minus_m3m5 = m2 * m6 - m3 * m5;
94 const double m2m3_minus_m1m6 = m2 * m3 - m1 * m6;
95
96 /* 1: function GETEIGVECTOR(m, r) */
97 /* 2: c = (r² + m₁m₅ - r(m₁ + m₅) - m₂²) */
98 const double tmp1 = 1.0 / (r1 * (r1 - m1_plus_m5) + m1m5_minus_m2sq);
99 const double tmp2 = 1.0 / (r2 * (r2 - m1_plus_m5) + m1m5_minus_m2sq);
100 /* 3: a₁ = (rm₃ + m₂m₆ - m₃m₅) / c */
101 /* 4: a₂ = (rm₆ + m₂m₃ - m₁m₆) / c */
102 double a11 = (r1 * m3 + m2m6_minus_m3m5) * tmp1;
103 double a12 = (r1 * m6 + m2m3_minus_m1m6) * tmp1;
104 double a21 = (r2 * m3 + m2m6_minus_m3m5) * tmp2;
105 double a22 = (r2 * m6 + m2m3_minus_m1m6) * tmp2;
106 /* 5: v = (a₁ a₂ 1) */
107 /* 6: Return v / |v| */
108 const double rnorm1 = 1.0 / sqrt(a11 * a11 + a12 * a12 + 1.0);
109 const double rnorm2 = 1.0 / sqrt(a21 * a21 + a22 * a22 + 1.0);
110
111 E[0] = a11 * rnorm1;
112 E[3] = a12 * rnorm1;
113 E[6] = rnorm1;
114
115 E[1] = a21 * rnorm2;
116 E[4] = a22 * rnorm2;
117 E[7] = rnorm2;
118}
Quadratic root finder, specialized for P3P solving.