Sensor Scol plugin
Multi platform sensors for handled devices
SO3Util.cpp
1
2#include "tools/SO3Util.h"
3
4
5/* Retourne la matrice de rotation de la rotation (a.b).
6 */
7void SO3Util::sO3FromTwoVec(Vector3d a, Vector3d b, Matrix3x3d &result)
8{
9 Vector3d sO3FromTwoVecN;
10 Vector3d sO3FromTwoVecRotationAxis;
11 Vector3d sO3FromTwoVecA;
12 Vector3d sO3FromTwoVecB;
13
14 Vector3d::cross(a, b, sO3FromTwoVecN);
15 if (sO3FromTwoVecN.length() == 0.0)
16 {
17 double dot = Vector3d::dot(a, b);
18 if (dot >= 0.0)
19 {
20 result.setIdentity();
21 }
22 else
23 {
24 Vector3d::ortho(a, sO3FromTwoVecRotationAxis);
25 rotationPiAboutAxis(sO3FromTwoVecRotationAxis, result);
26 }
27 return;
28 }
29
30 sO3FromTwoVecA.set(a);
31 sO3FromTwoVecB.set(b);
32
33 sO3FromTwoVecN.normalize();
34 sO3FromTwoVecA.normalize();
35 sO3FromTwoVecB.normalize();
36
37 Matrix3x3d r1;
38 r1.setColumn(0, sO3FromTwoVecA);
39 r1.setColumn(1, sO3FromTwoVecN);
40
41 Vector3d temp31;
42 Vector3d::cross(sO3FromTwoVecN, sO3FromTwoVecA, temp31);
43 r1.setColumn(2, temp31);
44
45 Matrix3x3d r2;
46 r2.setColumn(0, sO3FromTwoVecB);
47 r2.setColumn(1, sO3FromTwoVecN);
48 Vector3d::cross(sO3FromTwoVecN, sO3FromTwoVecB, temp31);
49 r2.setColumn(2, temp31);
50
51 r1.transpose();
52 Matrix3x3d::mult(r2, r1, result);
53}
54
55/* Retourne la matrice de rotation d'une rotation autour de v de 180° (= PI)
56 */
57void SO3Util::rotationPiAboutAxis(Vector3d v, Matrix3x3d &result)
58{
59 Vector3d rotationPiAboutAxisTemp;
60 rotationPiAboutAxisTemp.set(v);
61 rotationPiAboutAxisTemp.scale(3.141592653589793 / rotationPiAboutAxisTemp.length());
62 double invTheta = 0.3183098861837907;
63 double kA = 0.0;
64 double kB = 0.2026423672846756;
65 rodriguesSo3Exp(rotationPiAboutAxisTemp, kA, kB, result);
66}
67
68/* retourne la matrice de rotation qui correspond à un vecteur
69 * Dans un soucis d'optimisation, on stocke les rotations sous forme de vecteur.
70 * Question: comment est stocké l'angle? à rechercher!!!
71 */
72void SO3Util::sO3FromMu(Vector3d w, Matrix3x3d &result)
73{
74 double thetaSq = Vector3d::dot(w, w);
75 double theta = sqrt(thetaSq);
76 double kA, kB;
77 if (thetaSq < 1.0E-08)
78 {
79 kA = 1.0 - 0.16666667163372 * thetaSq;
80 kB = 0.5;
81 }
82 else
83 {
84 if (thetaSq < 1.0E-06)
85 {
86 kB = 0.5 - 0.0416666679084301 * thetaSq;
87 kA = 1.0 - thetaSq * 0.16666667163372 * (1.0 - 0.16666667163372 * thetaSq);
88 }
89 else
90 {
91 double invTheta = 1.0 / theta;
92 kA = sin(theta) * invTheta;
93 kB = (1.0 - cos(theta)) * (invTheta * invTheta);
94 }
95 }
96 rodriguesSo3Exp(w, kA, kB, result);
97}
98
99/* retourne le vecteur qui correspond à la matrice de rotation
100 * Dans un soucis d'optimisation, on stocke les rotations sous forme de vecteur.
101 * Question: comment est stocké l'angle? à rechercher!!!
102 */
103void SO3Util::muFromSO3(Matrix3x3d so3, Vector3d &result)
104{
105 double cosAngle = (so3.get(0, 0) + so3.get(1, 1) + so3.get(2, 2) - 1.0) * 0.5;
106
107 result.set((so3.get(2, 1) - so3.get(1, 2)) / 2.0, (so3.get(0, 2) - so3.get(2, 0)) / 2.0, (so3.get(1, 0) - so3.get(0, 1)) / 2.0);
108
109 double sinAngleAbs = result.length();
110 if (cosAngle > 0.7071067811865476)
111 {
112 if (sinAngleAbs > 0.0)
113 result.scale(asin(sinAngleAbs) / sinAngleAbs);
114 }
115 else if (cosAngle > -0.7071067811865476)
116 {
117 double angle = acos(cosAngle);
118 result.scale(angle / sinAngleAbs);
119 }
120 else
121 {
122 double angle = 3.141592653589793 - asin(sinAngleAbs);
123 double d0 = so3.get(0, 0) - cosAngle;
124 double d1 = so3.get(1, 1) - cosAngle;
125 double d2 = so3.get(2, 2) - cosAngle;
126
127 Vector3d r2;
128 if ((d0 * d0 > d1 * d1) && (d0 * d0 > d2 * d2))
129 {
130 r2.set(d0, (so3.get(1, 0) + so3.get(0, 1)) / 2.0, (so3.get(0, 2) + so3.get(2, 0)) / 2.0);
131 }
132 else if (d1 * d1 > d2 * d2)
133 {
134 r2.set((so3.get(1, 0) + so3.get(0, 1)) / 2.0, d1, (so3.get(2, 1) + so3.get(1, 2)) / 2.0);
135 }
136 else
137 {
138 r2.set((so3.get(0, 2) + so3.get(2, 0)) / 2.0, (so3.get(2, 1) + so3.get(1, 2)) / 2.0, d2);
139 }
140
141 if (Vector3d::dot(r2, result) < 0.0)
142 {
143 r2.scale(-1.0);
144 }
145
146 r2.normalize();
147 r2.scale(angle);
148 result.set(r2);
149 }
150}
151
152/* Formule de rodrigues.
153 * Calcul la matrice de rotation (axe, angle)
154 * Question: pourquoi ka et kb?
155 */
156void SO3Util::rodriguesSo3Exp(Vector3d w, double kA, double kB, Matrix3x3d &result)
157{
158 double wx2 = w.x * w.x;
159 double wy2 = w.y * w.y;
160 double wz2 = w.z * w.z;
161
162 result.set(0, 0, 1.0 - kB * (wy2 + wz2));
163 result.set(1, 1, 1.0 - kB * (wx2 + wz2));
164 result.set(2, 2, 1.0 - kB * (wx2 + wy2));
165
166 double a, b;
167 a = kA * w.z;
168 b = kB * (w.x * w.y);
169 result.set(0, 1, b - a);
170 result.set(1, 0, b + a);
171
172 a = kA * w.y;
173 b = kB * (w.x * w.z);
174 result.set(0, 2, b + a);
175 result.set(2, 0, b - a);
176
177 a = kA * w.x;
178 b = kB * (w.y * w.z);
179 result.set(1, 2, b - a);
180 result.set(2, 1, b + a);
181}
182
183void SO3Util::generatorField(int i, Matrix3x3d pos, Matrix3x3d &result)
184{
185 result.set(i, 0, 0.0);
186 result.set((i + 1) % 3, 0, -pos.get((i + 2) % 3, 0));
187 result.set((i + 2) % 3, 0, pos.get((i + 1) % 3, 0));
188}