Blender V4.3
IK_Math.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#pragma once
10
11#include <Eigen/Core>
12#include <Eigen/Geometry>
13
14#include <cmath>
15
16using Eigen::Affine3d;
17using Eigen::Matrix3d;
18using Eigen::MatrixXd;
19using Eigen::Vector3d;
20using Eigen::VectorXd;
21
22static const double IK_EPSILON = 1e-20;
23
24static inline bool FuzzyZero(double x)
25{
26 return fabs(x) < IK_EPSILON;
27}
28
29static inline double Clamp(const double x, const double min, const double max)
30{
31 return (x < min) ? min : (x > max) ? max : x;
32}
33
34static inline Eigen::Matrix3d CreateMatrix(double xx,
35 double xy,
36 double xz,
37 double yx,
38 double yy,
39 double yz,
40 double zx,
41 double zy,
42 double zz)
43{
44 Eigen::Matrix3d M;
45 M(0, 0) = xx;
46 M(0, 1) = xy;
47 M(0, 2) = xz;
48 M(1, 0) = yx;
49 M(1, 1) = yy;
50 M(1, 2) = yz;
51 M(2, 0) = zx;
52 M(2, 1) = zy;
53 M(2, 2) = zz;
54 return M;
55}
56
57static inline Eigen::Matrix3d RotationMatrix(double sine, double cosine, int axis)
58{
59 if (axis == 0) {
60 return CreateMatrix(1.0, 0.0, 0.0, 0.0, cosine, -sine, 0.0, sine, cosine);
61 }
62 else if (axis == 1) {
63 return CreateMatrix(cosine, 0.0, sine, 0.0, 1.0, 0.0, -sine, 0.0, cosine);
64 }
65 else {
66 return CreateMatrix(cosine, -sine, 0.0, sine, cosine, 0.0, 0.0, 0.0, 1.0);
67 }
68}
69
70static inline Eigen::Matrix3d RotationMatrix(double angle, int axis)
71{
72 return RotationMatrix(sin(angle), cos(angle), axis);
73}
74
75static inline double EulerAngleFromMatrix(const Eigen::Matrix3d &R, int axis)
76{
77 double t = sqrt(R(0, 0) * R(0, 0) + R(0, 1) * R(0, 1));
78
79 if (t > 16.0 * IK_EPSILON) {
80 if (axis == 0) {
81 return -atan2(R(1, 2), R(2, 2));
82 }
83 else if (axis == 1) {
84 return atan2(-R(0, 2), t);
85 }
86 else {
87 return -atan2(R(0, 1), R(0, 0));
88 }
89 }
90 else {
91 if (axis == 0) {
92 return -atan2(-R(2, 1), R(1, 1));
93 }
94 else if (axis == 1) {
95 return atan2(-R(0, 2), t);
96 }
97 else {
98 return 0.0f;
99 }
100 }
101}
102
103static inline double safe_acos(double f)
104{
105 // acos that does not return NaN with rounding errors
106 if (f <= -1.0) {
107 return M_PI;
108 }
109 else if (f >= 1.0) {
110 return 0.0;
111 }
112 else {
113 return acos(f);
114 }
115}
116
117static inline Eigen::Vector3d normalize(const Eigen::Vector3d &v)
118{
119 // a sane normalize function that doesn't give (1, 0, 0) in case
120 // of a zero length vector
121 double len = v.norm();
122 return FuzzyZero(len) ? Eigen::Vector3d(0, 0, 0) : Eigen::Vector3d(v / len);
123}
124
125static inline double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
126{
127 return safe_acos(v1.dot(v2));
128}
129
130static inline double ComputeTwist(const Eigen::Matrix3d &R)
131{
132 // qy and qw are the y and w components of the quaternion from R
133 double qy = R(0, 2) - R(2, 0);
134 double qw = R(0, 0) + R(1, 1) + R(2, 2) + 1;
135
136 double tau = 2.0 * atan2(qy, qw);
137
138 return tau;
139}
140
141static inline Eigen::Matrix3d ComputeTwistMatrix(double tau)
142{
143 return RotationMatrix(tau, 1);
144}
145
146static inline void RemoveTwist(Eigen::Matrix3d &R)
147{
148 // compute twist parameter
149 double tau = ComputeTwist(R);
150
151 // compute twist matrix
152 Eigen::Matrix3d T = ComputeTwistMatrix(tau);
153
154 // remove twist
155 R = R * T.transpose();
156}
157
158static inline Eigen::Vector3d SphericalRangeParameters(const Eigen::Matrix3d &R)
159{
160 // compute twist parameter
161 double tau = ComputeTwist(R);
162
163 // compute swing parameters
164 double num = 2.0 * (1.0 + R(1, 1));
165
166 // singularity at pi
167 if (fabs(num) < IK_EPSILON) {
168 // TODO: this does now rotation of size pi over z axis, but could
169 // be any axis, how to deal with this I'm not sure, maybe don't
170 // enforce limits at all then.
171 return Eigen::Vector3d(0.0, tau, 1.0);
172 }
173
174 num = 1.0 / sqrt(num);
175 double ax = -R(2, 1) * num;
176 double az = R(0, 1) * num;
177
178 return Eigen::Vector3d(ax, tau, az);
179}
180
181static inline Eigen::Matrix3d ComputeSwingMatrix(double ax, double az)
182{
183 // length of (ax, 0, az) = sin(theta/2)
184 double sine2 = ax * ax + az * az;
185 double cosine2 = sqrt((sine2 >= 1.0) ? 0.0 : 1.0 - sine2);
186
187 // compute swing matrix
188 Eigen::Matrix3d S(Eigen::Quaterniond(-cosine2, ax, 0.0, az));
189
190 return S;
191}
192
193static inline Eigen::Vector3d MatrixToAxisAngle(const Eigen::Matrix3d &R)
194{
195 Eigen::Vector3d delta = Eigen::Vector3d(R(2, 1) - R(1, 2), R(0, 2) - R(2, 0), R(1, 0) - R(0, 1));
196
197 double c = safe_acos((R(0, 0) + R(1, 1) + R(2, 2) - 1) / 2);
198 double l = delta.norm();
199
200 if (!FuzzyZero(l)) {
201 delta *= c / l;
202 }
203
204 return delta;
205}
206
207static inline bool EllipseClamp(double &ax, double &az, double *amin, double *amax)
208{
209 double xlim, zlim, x, z;
210
211 if (ax < 0.0) {
212 x = -ax;
213 xlim = -amin[0];
214 }
215 else {
216 x = ax;
217 xlim = amax[0];
218 }
219
220 if (az < 0.0) {
221 z = -az;
222 zlim = -amin[1];
223 }
224 else {
225 z = az;
226 zlim = amax[1];
227 }
228
229 if (FuzzyZero(xlim) || FuzzyZero(zlim)) {
230 if (x <= xlim && z <= zlim) {
231 return false;
232 }
233
234 if (x > xlim) {
235 x = xlim;
236 }
237 if (z > zlim) {
238 z = zlim;
239 }
240 }
241 else {
242 double invx = 1.0 / (xlim * xlim);
243 double invz = 1.0 / (zlim * zlim);
244
245 if ((x * x * invx + z * z * invz) <= 1.0) {
246 return false;
247 }
248
249 if (FuzzyZero(x)) {
250 x = 0.0;
251 z = zlim;
252 }
253 else {
254 double rico = z / x;
255 double old_x = x;
256 x = sqrt(1.0 / (invx + invz * rico * rico));
257 if (old_x < 0.0) {
258 x = -x;
259 }
260 z = rico * x;
261 }
262 }
263
264 ax = (ax < 0.0) ? -x : x;
265 az = (az < 0.0) ? -z : z;
266
267 return true;
268}
sqrt(x)+1/max(0
#define M_PI
static double EulerAngleFromMatrix(const Eigen::Matrix3d &R, int axis)
Definition IK_Math.h:75
static void RemoveTwist(Eigen::Matrix3d &R)
Definition IK_Math.h:146
static bool EllipseClamp(double &ax, double &az, double *amin, double *amax)
Definition IK_Math.h:207
static Eigen::Matrix3d CreateMatrix(double xx, double xy, double xz, double yx, double yy, double yz, double zx, double zy, double zz)
Definition IK_Math.h:34
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:125
static Eigen::Vector3d MatrixToAxisAngle(const Eigen::Matrix3d &R)
Definition IK_Math.h:193
static const double IK_EPSILON
Definition IK_Math.h:22
static double ComputeTwist(const Eigen::Matrix3d &R)
Definition IK_Math.h:130
static double safe_acos(double f)
Definition IK_Math.h:103
static Eigen::Matrix3d RotationMatrix(double sine, double cosine, int axis)
Definition IK_Math.h:57
static Eigen::Matrix3d ComputeTwistMatrix(double tau)
Definition IK_Math.h:141
static Eigen::Vector3d SphericalRangeParameters(const Eigen::Matrix3d &R)
Definition IK_Math.h:158
static Eigen::Matrix3d ComputeSwingMatrix(double ax, double az)
Definition IK_Math.h:181
static bool FuzzyZero(double x)
Definition IK_Math.h:24
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
SIMD_FORCE_INLINE btVector3 & normalize()
Normalize this vector x^2 + y^2 + z^2 = 1.
Definition btVector3.h:303
int len
ccl_device_inline float2 fabs(const float2 a)
ccl_device_inline float3 cos(float3 v)
#define M
#define R
#define min(a, b)
Definition sort.c:32
float max
int xy[2]
Definition wm_draw.cc:170