1 /* This file is part of the hkl library.
3 * The hkl library is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
8 * The hkl library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with the hkl library. If not, see <http://www.gnu.org/licenses/>.
16 * Copyright (C) 2003-2014 Synchrotron SOLEIL
17 * L'Orme des Merisiers Saint-Aubin
18 * BP 48 91192 GIF-sur-YVETTE CEDEX
20 * Authors: Picca Frédéric-Emmanuel <picca@synchrotron-soleil.fr>
22 #include <math.h> // for fabs, sin, M_PI, acos, cos, etc
23 #include <stdio.h> // for fprintf, FILE
24 #include <stdlib.h> // for free
25 #include <string.h> // for memcpy, memset
26 #include "hkl-macros-private.h" // for hkl_assert, HKL_MALLOC
27 #include "hkl-matrix-private.h" // for _HklMatrix
28 #include "hkl-quaternion-private.h" // for _HklQuaternion
29 #include "hkl-vector-private.h" // for HklQuaternion, HklVector, etc
30 #include "hkl.h" // for HklMatrix, HKL_EPSILON, etc
34 * hkl_quaternion_dup: (skip)
41 HklQuaternion
*hkl_quaternion_dup(const HklQuaternion
* self
)
45 dup
= HKL_MALLOC(HklQuaternion
);
46 memcpy(dup
, self
, sizeof(*self
));
52 * hkl_quaternion_free: (skip)
57 void hkl_quaternion_free(HklQuaternion
*self
)
66 * hkl_quaternion_init:
67 * @self: the #HklQuaternion to initialize
68 * @a: the 1st element value
69 * @b: the 2nd element value
70 * @c: the 3rd element value
71 * @d: the 4th element value
73 * initialize the four elements of an #HklQuaternion
75 void hkl_quaternion_init(HklQuaternion
*self
,
76 double a
, double b
, double c
, double d
)
85 * hkl_quaternion_fprintf:
86 * @file: the file to send the #HklQuaternion into
87 * @self: the #HklQuaternion to write into the file stream.
89 * print an #HklQuaternion into a FILE stream
91 void hkl_quaternion_fprintf(FILE *file
, HklQuaternion
const *self
)
96 fprintf(file
, "<%f, %f, %f, %f>", Q
[0], Q
[1], Q
[2], Q
[3]);
100 * hkl_quaternion_init_from_vector:
101 * @self: the #HklQuaternion to set
102 * @v: the #HklVector used to set the self #HklQuaternion
104 * initialize an #HklQuaternion from an #HklVector
106 void hkl_quaternion_init_from_vector(HklQuaternion
*self
, HklVector
const *v
)
109 memcpy(&self
->data
[1], &v
->data
[0], sizeof(v
->data
));
113 * hkl_quaternion_init_from_angle_and_axe:
114 * @self: the #HklQuaternion to set
115 * @angle: the angles of the rotation
116 * @v: the axe of rotation
118 * initialize an #HklQuaternion from a vector and a angle.
120 void hkl_quaternion_init_from_angle_and_axe(HklQuaternion
*self
,
121 double angle
, HklVector
const *v
)
127 /* check that parameters are ok. */
128 norm
= hkl_vector_norm2(v
);
131 s
= sin(angle
/ 2.) / norm
;
134 self
->data
[1] = s
* v
->data
[0];
135 self
->data
[2] = s
* v
->data
[1];
136 self
->data
[3] = s
* v
->data
[2];
140 * hkl_quaternion_cmp:
141 * @self: the first #HklQuaternion
142 * @q: the second #HklQuaternion
144 * compare two #HklQuaternion.
146 * Returns: #TRUE if both are equal, #FALSE otherwise.
148 int hkl_quaternion_cmp(HklQuaternion
const *self
, HklQuaternion
const *q
)
153 if ( fabs(self
->data
[i
] - q
->data
[i
]) > HKL_EPSILON
)
159 * hkl_quaternion_minus_quaternion:
160 * @self: the #HklQuaternion to modify.
161 * @q: the #HklQuaternion to substract
163 * substract two #HklQuaternions
166 void hkl_quaternion_minus_quaternion(HklQuaternion
*self
, const HklQuaternion
*q
)
171 self
->data
[i
] -= q
->data
[i
];
175 * hkl_quaternion_times_quaternion:
176 * @self: the #HklQuaternion to modify
177 * @q: the #HklQuaternion to multiply by
179 * multiply two quaternions
181 void hkl_quaternion_times_quaternion(HklQuaternion
*self
, const HklQuaternion
*q
)
189 self
->data
[0] = Q
[0]*Q
[0] - Q
[1]*Q
[1] - Q
[2]*Q
[2] - Q
[3]*Q
[3];
190 self
->data
[1] = Q
[0]*Q
[1] + Q
[1]*Q
[0] + Q
[2]*Q
[3] - Q
[3]*Q
[2];
191 self
->data
[2] = Q
[0]*Q
[2] - Q
[1]*Q
[3] + Q
[2]*Q
[0] + Q
[3]*Q
[1];
192 self
->data
[3] = Q
[0]*Q
[3] + Q
[1]*Q
[2] - Q
[2]*Q
[1] + Q
[3]*Q
[0];
194 double const *Q1
= q
->data
;
195 self
->data
[0] = Q
[0]*Q1
[0] - Q
[1]*Q1
[1] - Q
[2]*Q1
[2] - Q
[3]*Q1
[3];
196 self
->data
[1] = Q
[0]*Q1
[1] + Q
[1]*Q1
[0] + Q
[2]*Q1
[3] - Q
[3]*Q1
[2];
197 self
->data
[2] = Q
[0]*Q1
[2] - Q
[1]*Q1
[3] + Q
[2]*Q1
[0] + Q
[3]*Q1
[1];
198 self
->data
[3] = Q
[0]*Q1
[3] + Q
[1]*Q1
[2] - Q
[2]*Q1
[1] + Q
[3]*Q1
[0];
203 * hkl_quaternion_norm2:
204 * @self: the quaternion use to compute the norm
206 * compute the norm2 of an #HklQuaternion
208 * Returns: the self #hklquaternion norm
210 double hkl_quaternion_norm2(const HklQuaternion
*self
)
215 sum2
+= self
->data
[i
] *self
->data
[i
];
220 * hkl_quaternion_conjugate:
221 * @self: the #HklQuaternion to conjugate
223 * compute the conjugate of a quaternion
225 void hkl_quaternion_conjugate(HklQuaternion
*self
)
229 self
->data
[i
] = -self
->data
[i
];
233 * hkl_quaternion_to_matrix:
234 * @self: the #HklQuaternion use to compute the #HklMatrix
235 * @m: the #HklMatrix return.
237 * Compute the rotation matrix of a Quaternion.
239 * compute the rotation matrix corresponding to the unitary quaternion.
240 * \f$ q = a + b \cdot i + c \cdot j + d \cdot k \f$
245 * a^2+b^2-c^2-d^2 & 2bc-2ad & 2ac+2bd\\
246 * 2ad+2bc & a^2-b^2+c^2-d^2 & 2cd-2ab\\
247 * 2bd-2ac & 2ab+2cd & a^2-b^2-c^2+d^2
253 void hkl_quaternion_to_matrix(const HklQuaternion
*self
, HklMatrix
*m
)
257 /* check that parameters are ok. */
258 hkl_assert(fabs(hkl_quaternion_norm2(self
) - 1) < HKL_EPSILON
);
262 m
->data
[0][0] = Q
[0]*Q
[0] + Q
[1]*Q
[1] - Q
[2]*Q
[2] - Q
[3]*Q
[3];
263 m
->data
[0][1] = 2 * (Q
[1]*Q
[2] - Q
[0]*Q
[3]);
264 m
->data
[0][2] = 2 * (Q
[0]*Q
[2] + Q
[1]*Q
[3]);
266 m
->data
[1][0] = 2 * (Q
[0]*Q
[3] + Q
[1]*Q
[2]);
267 m
->data
[1][1] = Q
[0]*Q
[0] - Q
[1]*Q
[1] + Q
[2]*Q
[2] - Q
[3]*Q
[3];
268 m
->data
[1][2] = 2 * (Q
[2]*Q
[3] - Q
[0]*Q
[1]);
270 m
->data
[2][0] = 2 * (Q
[1]*Q
[3] - Q
[0]*Q
[2]);
271 m
->data
[2][1] = 2 * (Q
[0]*Q
[1] + Q
[2]*Q
[3]);
272 m
->data
[2][2] = Q
[0]*Q
[0] - Q
[1]*Q
[1] - Q
[2]*Q
[2] + Q
[3]*Q
[3];
276 * hkl_quaternion_to_angle_and_axe:
277 * @self: The #HklQuaternion use to compute the angle and the roation axis.
278 * @angle: the returned angle of the rotation.
279 * @v: the returned axis of the rotation.
281 * compute the axe and angle of the unitary quaternion angle [-pi, pi]
282 * if q is the (1, 0, 0, 0) quaternion return the (0,0,0) axe and a 0 angle
284 void hkl_quaternion_to_angle_and_axe(HklQuaternion
const *self
,
285 double *angle
, HklVector
*v
)
291 /* check that parameters are ok. (norm must be equal to 1) */
292 hkl_assert(fabs(hkl_quaternion_norm2(self
) - 1) < HKL_EPSILON
);
294 /* compute the angle */
295 cos_angle_2
= self
->data
[0];
296 angle_2
= acos(cos_angle_2
);
298 /* we want an angle between -pi, pi */
299 if (*angle
> M_PI
) *angle
-= 2 *M_PI
;
301 /* compute the axe */
302 sin_angle_2
= sin(angle_2
);
303 if (fabs(sin_angle_2
) > HKL_EPSILON
) {
304 /* compute the axe using the vector part of the unitary quaterninon */
305 memcpy(v
->data
, &self
->data
[1], sizeof(v
->data
));
306 hkl_vector_div_double(v
, sin_angle_2
);
309 memset(v
->data
, 0, sizeof(v
->data
));