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-2010 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>
25 #include <gsl/gsl_math.h>
27 #include <hkl/hkl-vector.h>
28 #include <hkl/hkl-matrix.h>
29 #include <hkl/hkl-quaternion.h>
33 * @self: the #HklVector to initialize.
34 * @x: the first coordinate value
35 * @y: the second coordinate value
36 * @z: the third coordinate value
38 * initialize an #HklVector
40 void hkl_vector_init(HklVector
*self
, double x
, double y
, double z
)
49 * @file: the stream to print into
50 * @self: the #HklVector to print.
52 * print an #HklVector into a stream
54 void hkl_vector_fprintf(FILE *file
, const HklVector
*self
)
56 fprintf(file
, "|%f, %f, %f|", self
->data
[0], self
->data
[1], self
->data
[2]);
61 * @self: the first vector
62 * @vector: th vector to compare with
64 * compare two #HklVector. this comparison use HKL_EPSILON
65 * to do the comparison.
67 * Returns: HKL_FALSE if both are equals, HKL_TRUE otherwise.
69 int hkl_vector_cmp(const HklVector
*self
, const HklVector
*vector
)
74 if ( fabs(self
->data
[i
] - vector
->data
[i
]) > HKL_EPSILON
)
80 int hkl_vector_is_opposite(const HklVector
*self
, const HklVector
*vector
)
85 if ( fabs(self
->data
[i
] + vector
->data
[i
]) > HKL_EPSILON
)
91 * hkl_vector_add_vector:
92 * @self: the modified #HklVector
93 * @vector: the #hklvector to add
95 * add an #HklVector to another one.
97 void hkl_vector_add_vector(HklVector
*self
, const HklVector
*vector
)
101 self
->data
[i
] += vector
->data
[i
];
105 * hkl_vector_minus_vector:
106 * @self: the modified #HklVector
107 * @vector: the #hklvector to substract
109 * substract an #HklVector to another one.
111 void hkl_vector_minus_vector(HklVector
*self
, const HklVector
*vector
)
115 self
->data
[i
] -= vector
->data
[i
];
119 * hkl_vector_div_double:
120 * @self: the #HklVector to divide.
121 * @d: constant use to divide the #HklVector
123 * divide an #HklVector by constant.
125 void hkl_vector_div_double(HklVector
*self
, const double d
)
133 * hkl_vector_times_double:
134 * @self: the #HklVector to modify
135 * @d: the multiply factor
137 * multiply an #HklVector by a constant value.
139 void hkl_vector_times_double(HklVector
*self
, const double d
)
147 * hkl_vector_times_vector:
148 * @self: the #HklVector to modify
149 * @vector: the #HklVector use to modify the first one
151 * multiply an #HklVector by another one. This method multiply
152 * coordinate by coordinate.
154 void hkl_vector_times_vector(HklVector
*self
, const HklVector
*vector
)
158 self
->data
[i
] *= vector
->data
[i
];
162 * hkl_vector_times_smatrix:
163 * @self: the #HklVector to multiply
164 * @m: the #HklMatrix use to multiply the #HklVector
166 * multiply an #HklVector by an #HklMatrix.
169 void hkl_vector_times_matrix(HklVector
*self
, const HklMatrix
*m
)
174 self
->data
[0] = tmp
.data
[0] *m
->data
[0][0] + tmp
.data
[1] *m
->data
[1][0] + tmp
.data
[2] *m
->data
[2][0];
175 self
->data
[1] = tmp
.data
[0] *m
->data
[0][1] + tmp
.data
[1] *m
->data
[1][1] + tmp
.data
[2] *m
->data
[2][1];
176 self
->data
[2] = tmp
.data
[0] *m
->data
[0][2] + tmp
.data
[1] *m
->data
[1][2] + tmp
.data
[2] *m
->data
[2][2];
181 * @self: the #HklVector to sum.
183 * compute the #HklVector sum of all its elements.
185 * Returns: the sum of all elements.
187 double hkl_vector_sum(const HklVector
*self
)
189 return self
->data
[0] + self
->data
[1] + self
->data
[2];
193 * hkl_vector_scalar_product:
194 * @self: the first #HklVector
195 * @vector: the second #HklVector
197 * compute the scalar product of two #HklVector
199 * Returns: the scalar product.
201 double hkl_vector_scalar_product(const HklVector
*self
, const HklVector
*vector
)
207 scalar
+= self
->data
[i
] *vector
->data
[i
];
212 * hkl_vector_vectorial_product:
213 * @self: the first #HklVector (modify)
214 * @vector: the second #HklVector
216 * compute the vectorial product of two vectors
218 void hkl_vector_vectorial_product(HklVector
*self
, const HklVector
*vector
)
223 self
->data
[0] = tmp
.data
[1] * vector
->data
[2] - tmp
.data
[2] * vector
->data
[1];
224 self
->data
[1] = tmp
.data
[2] * vector
->data
[0] - tmp
.data
[0] * vector
->data
[2];
225 self
->data
[2] = tmp
.data
[0] * vector
->data
[1] - tmp
.data
[1] * vector
->data
[0];
231 * @self: the fist #HklVector
232 * @vector: the second #HklVector
234 * compute the angles beetween two #HklVector
236 * Returns: the return value is in beetween [0, pi]
238 double hkl_vector_angle(const HklVector
*self
, const HklVector
*vector
)
246 norm_self
= hkl_vector_norm2(self
);
247 norm_vector
= hkl_vector_norm2(vector
);
249 if (norm_self
< HKL_EPSILON
|| norm_vector
< HKL_EPSILON
)
252 norm
= norm_self
* norm_vector
;
254 cos_angle
= hkl_vector_scalar_product(self
, vector
) / norm
;
256 /* problem with round */
260 if (cos_angle
<= -1 )
263 angle
= acos(cos_angle
);
268 * hkl_vector_oriented_angle:
269 * @self: the first #HklVector
270 * @vector: the second #HklVector
271 * @ref: the reference #HklVector
273 * compute the angles beetween two #HklVector and use
274 * a reference #HklVector to orientate the space. That's
275 * way the return value can be in beetween [-pi, pi].
276 * the (self, vector, ref) is a right oriented base.
278 * Returns: the angles [-pi, pi]
280 double hkl_vector_oriented_angle(const HklVector
*self
,
281 const HklVector
*vector
,
282 const HklVector
*ref
)
288 angle
= hkl_vector_angle(self
, vector
);
290 hkl_vector_vectorial_product(&tmp
, vector
);
291 hkl_vector_normalize(&tmp
);
293 hkl_vector_normalize(&ref_u
);
294 if (hkl_vector_is_opposite(&tmp
, &ref_u
))
299 * hkl_vector_oriented_angle_points:
300 * @self: the first point
301 * @p2: the second point
302 * @p2: the third point
303 * @ref: the reference #HklVector
305 * compute the angles beetween three points (p1, p2, p3) and use
306 * a reference #HklVector to orientate the space. That's
307 * way the return value can be in beetween [-pi, pi].
308 * the (self, vector, ref) is a right oriented base.
310 * Returns: the angles [-pi, pi]
312 double hkl_vector_oriented_angle_points(const HklVector
*self
,
315 const HklVector
*ref
)
322 hkl_vector_minus_vector(&v1
, p2
);
323 hkl_vector_minus_vector(&v2
, p2
);
324 return hkl_vector_oriented_angle(&v1
, &v2
, ref
);
328 * hkl_vector_normalize:
329 * @self: the #HklVector to normalize
331 * normalize a hkl_vector
333 * Returns: HKL_SUCCESS if the #HklVector can be normalized, HKL_FAIL otherwise
335 int hkl_vector_normalize(HklVector
*self
)
337 int status
= HKL_FAIL
;
339 double norm
= hkl_vector_norm2(self
);
340 if ( norm
> HKL_EPSILON
)
342 hkl_vector_div_double(self
, norm
);
343 status
= HKL_SUCCESS
;
350 * hkl_vector_is_colinear:
351 * @self: the first #HklVector
352 * @vector: the second #HklVector
354 * check if two #HklVector are colinears
356 * Returns: HKL_TRUE if both are colinear.
358 int hkl_vector_is_colinear(const HklVector
*self
, const HklVector
*vector
)
361 HklVector tmp
= *self
;
363 hkl_vector_vectorial_product(&tmp
, vector
);
364 if (hkl_vector_norm2(&tmp
) < HKL_EPSILON
)
372 * hkl_vector_randomize:
373 * @self: the #HklVector to randomize
375 * initialize a vector with random values.
376 * coordinates range [-1, 1]
378 void hkl_vector_randomize(HklVector
*self
)
380 self
->data
[0] = -1 + 2 *rand()/(RAND_MAX
+1.0);
381 self
->data
[1] = -1 + 2 *rand()/(RAND_MAX
+1.0);
382 self
->data
[2] = -1 + 2 *rand()/(RAND_MAX
+1.0);
386 * hkl_vector_randomize_vector:
387 * @self: the #HklVector to randomize
388 * @vector: the #HklVector result to avoid
390 * randomize an #HklVector an be sure that it is not equal
391 * to the #HklVector vector.
393 void hkl_vector_randomize_vector(HklVector
*self
, const HklVector
*vector
)
396 hkl_vector_randomize(self
);
397 while (!hkl_vector_cmp(self
, vector
));
401 * hkl_vector_randomize_vector_vector:
402 * @self: the #HklVector to randomize
403 * @vector1: the first #HklVector solution to avoid
404 * @vector2: the second #HklVector solution to avoid
406 * randomize an #HklVector an be sure that it is not equal
407 * to the #HklVector vector1 and vector2.
410 void hkl_vector_randomize_vector_vector(HklVector
*self
,
411 const HklVector
*vector1
,
412 const HklVector
*vector2
)
415 hkl_vector_randomize(self
);
416 while (!hkl_vector_cmp(self
, vector1
) || !hkl_vector_cmp(self
, vector2
));
420 * hkl_vector_rotated_around_vector:
421 * @self: the #HklVector to rotate
422 * @axe: the axe of rotation
423 * @angle: the angle of the rotation
425 * rotate a vector around another one with a given angle.
427 void hkl_vector_rotated_around_vector(HklVector
*self
,
428 const HklVector
*axe
, double angle
)
430 double c
= cos(angle
);
431 double s
= sin(angle
);
436 hkl_vector_normalize(&axe_n
);
440 self
->data
[0] = (c
+ (1 - c
) * axe_n
.data
[0] * axe_n
.data
[0]) * tmp
.data
[0];
441 self
->data
[0] += ((1 - c
) * axe_n
.data
[0] * axe_n
.data
[1] - axe_n
.data
[2] * s
) * tmp
.data
[1];
442 self
->data
[0] += ((1 - c
) * axe_n
.data
[0] * axe_n
.data
[2] + axe_n
.data
[1] * s
) * tmp
.data
[2];
444 self
->data
[1] = ((1 - c
) * axe_n
.data
[0] * axe_n
.data
[1] + axe_n
.data
[2] * s
) * tmp
.data
[0];
445 self
->data
[1] += (c
+ (1 - c
) * axe_n
.data
[1] * axe_n
.data
[1]) * tmp
.data
[1];
446 self
->data
[1] += ((1 - c
) * axe_n
.data
[1] * axe_n
.data
[2] - axe_n
.data
[0] * s
) * tmp
.data
[2];
448 self
->data
[2] = ((1 - c
) * axe_n
.data
[0] * axe_n
.data
[2] - axe_n
.data
[1] * s
) * tmp
.data
[0];
449 self
->data
[2] += ((1 - c
) * axe_n
.data
[1] * axe_n
.data
[2] + axe_n
.data
[0] * s
) * tmp
.data
[1];
450 self
->data
[2] += (c
+ (1 - c
) * axe_n
.data
[2] * axe_n
.data
[2]) * tmp
.data
[2];
455 * @self: the #hklvector use to compute the norm2
457 * compute the norm2 of an #HklVector
459 * Returns: the sqrt(|v|)
461 double hkl_vector_norm2(const HklVector
*self
)
463 return sqrt(self
->data
[0] * self
->data
[0]
464 + self
->data
[1] * self
->data
[1]
465 + self
->data
[2] * self
->data
[2]);
469 * hkl_vector_rotated_quaternion:
470 * @self: the #HklVector to rotate
471 * @qr: the #HklQuaternion use to rotate the vector
473 * rotate an #HklVector using an #HklQuaternion.
475 void hkl_vector_rotated_quaternion(HklVector
*self
, const HklQuaternion
*qr
)
477 double v1
= self
->data
[0];
478 double v2
= self
->data
[1];
479 double v3
= self
->data
[2];
480 double a
= qr
->data
[0];
481 double b
= qr
->data
[1];
482 double c
= qr
->data
[2];
483 double d
= qr
->data
[3];
495 self
->data
[0] = 2*( (t8
+ t10
)*v1
+ (t6
- t4
)*v2
+ (t3
+ t7
)*v3
) + v1
;
496 self
->data
[1] = 2*( (t4
+ t6
)*v1
+ (t5
+ t10
)*v2
+ (t9
- t2
)*v3
) + v2
;
497 self
->data
[2] = 2*( (t7
- t3
)*v1
+ (t2
+ t9
)*v2
+ (t5
+ t8
)*v3
) + v3
;
501 * hkl_vector_rotated_around_line:
502 * @self: the point to rotate around a line
503 * @angle: the angle of the rotation
504 * @c1: the fist point of the line
505 * @c2: the second point of the line
507 * This method rotate a point around a line defined by two points
508 * of a certain amount of angle. The rotation is right handed.
509 * this mean that c2 - c1 gives the direction of the rotation.
511 void hkl_vector_rotated_around_line(HklVector
*self
, double angle
,
512 const HklVector
*c1
, const HklVector
*c2
)
516 if (!self
|| !c1
|| !c2
|| fabs(angle
) < HKL_EPSILON
)
520 hkl_vector_minus_vector(&axis
, c1
);
521 /* the c2 - c1 vector must be non null */
523 hkl_vector_minus_vector(self
, c1
);
524 hkl_vector_rotated_around_vector(self
, &axis
, angle
);
525 hkl_vector_add_vector(self
, c1
);
529 * hkl_vector_is_null:
530 * @self: the #hklvector to check
532 * check if all the coordinates of an #HklVector are null.
534 * Returns: HKl_TRUE if all |elements| are below HKL_EPSILON, HKl_FALSE otherwise
538 int hkl_vector_is_null(const HklVector
*self
)
542 if ( fabs(self
->data
[i
]) > HKL_EPSILON
)
548 * hkl_vector_project_on_plan:
549 * @self: the vector to project (modify)
550 * @normal: the normal of the plane.
552 * project an #HklVector on a plan of normal #normal which contain
553 * the origin [0, 0, 0]
556 void hkl_vector_project_on_plan(HklVector
*self
,
557 const HklVector
*normal
)
565 hkl_vector_normalize(&tmp
);
566 hkl_vector_times_double(&tmp
, hkl_vector_scalar_product(self
, &tmp
));
567 hkl_vector_minus_vector(self
, &tmp
);
571 * hkl_vector_project_on_plan_with_point:
572 * @self: the vector to project (modify)
573 * @normal: the normal of the plane.
574 * @point: a point of the plan.
576 * project an #HklVector on a plan of normal #normal which contain #point.
578 void hkl_vector_project_on_plan_with_point(HklVector
*self
,
579 const HklVector
*normal
,
580 const HklVector
*point
)
585 if(!self
|| !normal
|| !point
)
589 hkl_vector_normalize(&tmp
);
590 d1
= hkl_vector_scalar_product(self
, &tmp
);
591 d2
= hkl_vector_scalar_product(point
, &tmp
);
592 hkl_vector_times_double(&tmp
, d1
- d2
);
593 hkl_vector_minus_vector(self
, &tmp
);