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 <alloca.h> // for alloca
23 #include <gsl/gsl_sf_trig.h> // for gsl_sf_angle_restrict_symm
24 #include <gsl/gsl_sys.h> // for gsl_isnan
25 #include <math.h> // for fabs, M_PI
26 #include <stdarg.h> // for va_arg, va_end, va_list, etc
27 #include <stddef.h> // for size_t
28 #include <stdio.h> // for fprintf, FILE, stderr
29 #include <stdlib.h> // for free, exit, realloc
30 #include <string.h> // for NULL, strcmp, memcpy
31 #include <sys/types.h> // for uint
32 #include "hkl-factory-private.h"
33 #include "hkl-axis-private.h" // for HklAxis, etc
34 #include "hkl-geometry-private.h" // for _HklGeometry, etc
35 #include "hkl-interval-private.h" // for HklInterval
36 #include "hkl-macros-private.h" // for HKL_MALLOC
37 #include "hkl-parameter-private.h" // for _HklParameter, etc
38 #include "hkl-quaternion-private.h" // for _HklQuaternion, etc
39 #include "hkl-source-private.h" // for HklSource, hkl_source_init
40 #include "hkl-unit-private.h" // for HklUnit, hkl_unit_factor
41 #include "hkl-vector-private.h" // for HklVector, HklQuaternion, etc
42 #include "hkl.h" // for HklGeometry, etc
43 #include "hkl/ccan/container_of/container_of.h" // for container_of
44 #include "hkl/ccan/darray/darray.h" // for darray_foreach, darray_item, etc
47 * Try to add a axis to the axes list,
48 * if a identical axis is present in the list return it
49 * else create a new on and add it to the list.
50 * die if try to add an axis with the same name but a different axis_v
52 static size_t hkl_geometry_add_rotation(HklGeometry
*self
,
53 const char *name
, const HklVector
*axis_v
)
56 HklParameter
**parameter
;
58 /* check if an axis with the same name is on the axis list */
59 darray_foreach(parameter
, self
->axes
){
60 HklAxis
*axis
= container_of(*parameter
, HklAxis
, parameter
);
61 if(!strcmp((*parameter
)->name
, name
)){
62 if (hkl_vector_cmp(&axis
->axis_v
,
64 fprintf(stderr
, "can not add two axis with the same name \"%s\" but different axes <%f, %f, %f> != <%f, %f, %f> into an HklAxes.",
66 axis
->axis_v
.data
[0], axis
->axis_v
.data
[1], axis
->axis_v
.data
[2],
67 axis_v
->data
[0], axis_v
->data
[1], axis_v
->data
[2]);
76 /* no so create and add it to the list */
77 darray_append(self
->axes
, hkl_parameter_new_axis(name
, axis_v
));
79 return darray_size(self
->axes
) - 1;
86 static struct HklHolderConfig
*hkl_holder_config_new(void)
88 struct HklHolderConfig
*self
;
90 self
= HKL_MALLOC(struct HklHolderConfig
);
99 static struct HklHolderConfig
*hkl_holder_config_ref(struct HklHolderConfig
*self
)
109 static void hkl_holder_config_unref(struct HklHolderConfig
*self
)
125 static HklHolder
*hkl_holder_new(HklGeometry
*geometry
)
127 static HklQuaternion q0
= {{1, 0, 0, 0}};
128 HklHolder
*self
= HKL_MALLOC(HklHolder
);
130 self
->config
= hkl_holder_config_new();
131 self
->geometry
= geometry
;
137 static HklHolder
*hkl_holder_new_copy(HklHolder
*src
, HklGeometry
*geometry
)
139 HklHolder
*self
= HKL_MALLOC(HklHolder
);
141 self
->config
= hkl_holder_config_ref(src
->config
);
142 self
->geometry
= geometry
;
148 static void hkl_holder_free(HklHolder
*self
)
150 hkl_holder_config_unref(self
->config
);
154 static void hkl_holder_update(HklHolder
*self
)
156 static HklQuaternion q0
= {{1, 0, 0, 0}};
160 for(i
=0; i
<self
->config
->len
; ++i
)
161 hkl_quaternion_times_quaternion(&self
->q
,
162 &container_of(darray_item(self
->geometry
->axes
,
163 self
->config
->idx
[i
]),
164 HklAxis
, parameter
)->q
);
167 HklParameter
*hkl_holder_add_rotation_axis(HklHolder
*self
,
168 const char *name
, double x
, double y
, double z
)
170 HklParameter
*axis
= NULL
;
178 idx
= hkl_geometry_add_rotation(self
->geometry
, name
, &axis_v
);
180 /* check that the axis is not already in the holder */
181 for(i
=0; i
<self
->config
->len
; i
++)
182 if (idx
== self
->config
->idx
[i
])
185 axis
= darray_item(self
->geometry
->axes
, idx
);
186 self
->config
->idx
= realloc(self
->config
->idx
, sizeof(*self
->config
->idx
) * (self
->config
->len
+ 1));
187 self
->config
->idx
[self
->config
->len
++] = idx
;
197 * hkl_geometry_new: (skip)
203 HklGeometry
*hkl_geometry_new(const HklFactory
*factory
)
205 HklGeometry
*g
= NULL
;
207 g
= HKL_MALLOC(HklGeometry
);
209 g
->factory
= factory
;
210 hkl_source_init(&g
->source
, 1.54, 1, 0, 0);
211 darray_init(g
->axes
);
212 darray_init(g
->holders
);
218 * hkl_geometry_new_copy: (skip)
225 HklGeometry
*hkl_geometry_new_copy(const HklGeometry
*src
)
227 HklGeometry
*self
= NULL
;
234 self
= HKL_MALLOC(HklGeometry
);
236 self
->factory
= src
->factory
;
237 self
->source
= src
->source
;
240 darray_init(self
->axes
);
241 darray_foreach(axis
, src
->axes
){
242 darray_append(self
->axes
, hkl_parameter_new_copy(*axis
));
245 /* copy the holders */
246 darray_init(self
->holders
);
247 darray_foreach(holder
, src
->holders
){
248 darray_append(self
->holders
,
249 hkl_holder_new_copy(*holder
, self
));
256 * hkl_geometry_free: (skip)
261 void hkl_geometry_free(HklGeometry
*self
)
266 darray_foreach(axis
, self
->axes
){
267 hkl_parameter_free(*axis
);
269 darray_free(self
->axes
);
271 darray_foreach(holder
, self
->holders
){
272 hkl_holder_free(*holder
);
274 darray_free(self
->holders
);
280 * hkl_geometry_set: (skip)
281 * @self: the this ptr
282 * @src: the other #HklGeometry to set from
284 * Set an #HklGeometry from another one.
286 * Returns: TRUE on success, FALSE if an error occurred
288 int hkl_geometry_set(HklGeometry
*self
, const HklGeometry
*src
)
292 hkl_error(self
->factory
== src
->factory
);
294 self
->source
= src
->source
;
296 /* copy the axes configuration and mark it as dirty */
297 for(i
=0; i
<darray_size(self
->axes
); ++i
)
298 hkl_parameter_init_copy(darray_item(self
->axes
, i
),
299 darray_item(src
->axes
, i
), NULL
);
301 for(i
=0; i
<darray_size(src
->holders
); ++i
)
302 darray_item(self
->holders
, i
)->q
= darray_item(src
->holders
, i
)->q
;
308 * hkl_geometry_axes_names_get:
309 * @self: the this ptr
311 * get all the axes of the given #HklGeometry
313 * Returns: (type gpointer): array of the axes names.
315 const darray_string
*hkl_geometry_axes_names_get(const HklGeometry
*self
)
317 return &self
->factory
->axes
;
321 * hkl_geometry_axis_get:
322 * @self: the this ptr
323 * @name: the name of the axis your are requesting
324 * @error: return location for a GError, or NULL
326 * Return value: (allow-none): the parameter corresponding to the axis name.
328 const HklParameter
*hkl_geometry_axis_get(const HklGeometry
*self
,
334 hkl_error (error
== NULL
|| *error
== NULL
);
336 darray_foreach(axis
, self
->axes
){
337 if (!strcmp((*axis
)->name
, name
))
343 HKL_GEOMETRY_ERROR_AXIS_GET
,
344 "this geometry does not contain this axis \"%s\"",
351 * hkl_geometry_axis_set:
352 * @self: the this ptr
353 * @name: the name of the axis to set
354 * @axis: The #HklParameter to set
355 * @error: return location for a GError, or NULL
357 * Returns: TRUE on success, FALSE if an error occurred
359 int hkl_geometry_axis_set(HklGeometry
*self
, const char *name
,
360 const HklParameter
*axis
,
363 HklParameter
**_axis
;
365 hkl_error (error
== NULL
|| *error
== NULL
);
367 if(name
!= axis
->name
&& strcmp(name
, axis
->name
)){
370 HKL_GEOMETRY_ERROR_AXIS_SET
,
371 "The axis to set \"%s\" is different from the parameter name \"\"\n",
376 darray_foreach(_axis
, self
->axes
){
379 if (!strcmp(axis
->name
, (*_axis
)->name
)){
380 hkl_parameter_init_copy(*_axis
, axis
, NULL
);
384 hkl_geometry_update(self
);
390 * hkl_geometry_wavelength_get: (skip)
391 * @self: the this ptr
392 * @unit_type: the unit type (default or user) of the returned value
394 * Get the wavelength of the HklGeometry
396 * Returns: the wavelength
398 double hkl_geometry_wavelength_get(const HklGeometry
*self
,
399 HklUnitEnum unit_type
)
401 /* for now there is no unit convertion but the unit_type is
403 return self
->source
.wave_length
;
408 * hkl_geometry_wavelength_set:
411 * @unit_type: the unit type (default or user) of the returned value
412 * @error: return location for a GError, or NULL
414 * Set the wavelength of the geometry
416 * Returns: TRUE on success, FALSE if an error occurred
418 int hkl_geometry_wavelength_set(HklGeometry
*self
, double wavelength
,
419 HklUnitEnum unit_type
, GError
**error
)
421 hkl_error (error
== NULL
|| *error
== NULL
);
423 /* for now there is no unit convertion but the unit_type is
426 self
->source
.wave_length
= wavelength
;
432 * hkl_geometry_init_geometry: (skip)
433 * @self: the this ptr
434 * @src: the #HklGeometry to set from
436 * initilize an HklGeometry
438 * Returns: TRUE on success, FALSE if an error occurred
440 int hkl_geometry_init_geometry(HklGeometry
*self
, const HklGeometry
*src
)
442 return hkl_geometry_set(self
, src
);
446 * hkl_geometry_add_holder: (skip)
449 * add an Holder to the #HklGeometry
453 HklHolder
*hkl_geometry_add_holder(HklGeometry
*self
)
455 HklHolder
*holder
= hkl_holder_new(self
);
456 darray_append(self
->holders
, holder
);
462 * hkl_geometry_update: (skip)
465 * update the geometry internal once an Axis values changed
467 void hkl_geometry_update(HklGeometry
*self
)
473 darray_foreach(axis
, self
->axes
){
474 if ((*axis
)->changed
) {
483 darray_foreach(holder
, self
->holders
){
484 hkl_holder_update(*holder
);
487 darray_foreach(axis
, self
->axes
){
488 (*axis
)->changed
= FALSE
;
493 const char *hkl_geometry_name_get(const HklGeometry
*self
)
495 return hkl_factory_name_get(self
->factory
);
499 * hkl_geometry_get_axis_idx_by_name: (skip)
503 * get the index of the axes named @name in the geometry
505 * Returns: -1 if the axis was not found
507 int hkl_geometry_get_axis_idx_by_name(const HklGeometry
*self
, const char *name
)
515 darray_foreach(axis
, self
->axes
){
516 if (!strcmp((*axis
)->name
, name
))
525 * hkl_geometry_get_axis_by_name:
529 * get an #HklAxis using its name
531 * Returns: (transfer none):
533 HklParameter
*hkl_geometry_get_axis_by_name(HklGeometry
*self
, const char *name
)
537 darray_foreach(axis
, self
->axes
){
538 if (!strcmp((*axis
)->name
, name
))
545 * hkl_geometry_axes_values_get:
546 * @self: the this ptr
547 * @values: (array length=n_values): the values to get
548 * @n_values: the size of the values array.
549 * @unit_type: the unit type (default or user) of the returned value
551 * fill the values array with the #HklGeometry axes.
553 void hkl_geometry_axes_values_get(const HklGeometry
*self
,
554 double values
[], size_t n_values
,
555 HklUnitEnum unit_type
)
560 g_return_if_fail (n_values
== darray_size(self
->axes
));
562 darray_foreach(axis
, self
->axes
){
563 values
[i
++] = hkl_parameter_value_get(*axis
, unit_type
);
568 * hkl_geometry_axes_values_set:
569 * @self: the this ptr
570 * @values: (array length=n_values): the values to set.
571 * @n_values: the length of the values array.
572 * @unit_type: the unit type (default or user) of the returned value
573 * @error: return location for a GError, or NULL
575 * Set the #HklGeometry axes values
577 * Returns: TRUE on success, FALSE if an error occurred
579 int hkl_geometry_axes_values_set(HklGeometry
*self
,
580 double values
[], size_t n_values
,
581 HklUnitEnum unit_type
,
587 hkl_error (error
== NULL
|| *error
== NULL
);
588 g_assert(n_values
== darray_size(self
->axes
));
590 darray_foreach(axis
, self
->axes
){
591 if(!hkl_parameter_value_set(*axis
, values
[i
++], unit_type
, error
)){
592 g_assert (error
== NULL
|| *error
!= NULL
);
596 g_assert (error
== NULL
|| *error
== NULL
);
598 hkl_geometry_update(self
);
604 * hkl_geometry_randomize: (skip)
607 * randomize the #HklGeometry
609 void hkl_geometry_randomize(HklGeometry
*self
)
613 darray_foreach(axis
, self
->axes
){
614 hkl_parameter_randomize(*axis
);
616 hkl_geometry_update(self
);
620 * hkl_geometry_set_values_v: (skip)
622 * @unit_type: the unit type (default or user) of the returned value
626 * set the axes values
630 int hkl_geometry_set_values_v(HklGeometry
*self
, HklUnitEnum unit_type
, GError
**error
, ...)
635 hkl_error (error
== NULL
|| *error
== NULL
);
638 darray_foreach(axis
, self
->axes
){
639 if(!hkl_parameter_value_set(*axis
,
642 g_assert (error
== NULL
|| *error
!= NULL
);
644 hkl_geometry_update(self
);
648 g_assert (error
== NULL
|| *error
== NULL
);
652 hkl_geometry_update(self
);
658 * hkl_geometry_distance:
659 * @self: the this ptr
660 * @ref: the #HklGeometry to compare with
662 * compute the distance between two #HklGeometries
664 * Returns: the distance between the two geometries
666 double hkl_geometry_distance(const HklGeometry
*self
,
667 const HklGeometry
*ref
)
670 double value1
, value2
;
671 double distance
= 0.;
676 for(i
=0; i
<darray_size(self
->axes
); ++i
){
677 value1
= darray_item(self
->axes
, i
)->_value
;
678 value2
= darray_item(ref
->axes
, i
)->_value
;
679 distance
+= fabs(value2
- value1
);
686 * hkl_geometry_distance_orthodromic: (skip)
687 * @self: the this ptr
688 * @ref: the reference #HklGeometry to compare with.
690 * Returns: the orthodromique distance
692 double hkl_geometry_distance_orthodromic(const HklGeometry
*self
,
693 const HklGeometry
*ref
)
696 double value1
, value2
;
697 double distance
= 0.;
702 for(i
=0; i
<darray_size(self
->axes
); ++i
){
705 value1
= darray_item(self
->axes
, i
)->_value
;
706 value2
= darray_item(ref
->axes
, i
)->_value
;
707 d
= fabs(gsl_sf_angle_restrict_symm(value2
) - gsl_sf_angle_restrict_symm(value1
));
708 /* as M_PI and -M_PI are included in the GSL restriction */
718 * hkl_geometry_is_valid: (skip)
721 * check if all axes of the #HklGeometry are valid.
725 int hkl_geometry_is_valid(const HklGeometry
*self
)
729 darray_foreach(axis
, self
->axes
){
730 if(!hkl_parameter_is_valid(*axis
))
738 * hkl_geometry_closest_from_geometry_with_range: (skip)
742 * get the closest axes values in the HklInterval compatible with the
743 * current axes values
747 int hkl_geometry_closest_from_geometry_with_range(HklGeometry
*self
,
748 const HklGeometry
*ref
)
751 uint len
= darray_size(self
->axes
);
752 double *values
= alloca(len
* sizeof(*values
));
756 values
[i
] = hkl_parameter_value_get_closest(darray_item(self
->axes
, i
),
757 darray_item(ref
->axes
, i
));
758 if(gsl_isnan(values
[i
])){
765 hkl_parameter_value_set(darray_item(self
->axes
, i
),
767 HKL_UNIT_DEFAULT
, NULL
);
768 hkl_geometry_update(self
);
774 * hkl_geometry_fprintf: (skip)
778 * print into a file the #HklGeometry
780 void hkl_geometry_fprintf(FILE *file
, const HklGeometry
*self
)
782 fprintf(file
, " HklGeometry type: \"%s\" wavelength: %f",
784 self
->source
.wave_length
);
785 for(unsigned int i
=0; i
<darray_size(self
->axes
); ++i
){
787 hkl_parameter_fprintf(file
, darray_item(self
->axes
, i
));
791 /*******************/
792 /* HklGeometryList */
793 /*******************/
796 * hkl_geometry_list_new: (skip)
802 HklGeometryList
*hkl_geometry_list_new(void)
804 HklGeometryList
*self
;
806 self
= HKL_MALLOC(HklGeometryList
);
808 list_head_init(&self
->items
);
810 self
->multiply
= NULL
;
816 * hkl_geometry_list_new_copy: (skip)
823 HklGeometryList
*hkl_geometry_list_new_copy(const HklGeometryList
*self
)
825 HklGeometryList
*dup
;
826 HklGeometryListItem
*item
;
831 dup
= HKL_MALLOC(HklGeometryList
);
833 list_head_init(&dup
->items
);
834 /* now copy the item arrays */
835 list_for_each(&self
->items
, item
, list
){
836 list_add_tail(&dup
->items
,
837 &hkl_geometry_list_item_new_copy(item
)->list
);
839 dup
->n_items
= self
->n_items
;
840 dup
->multiply
= self
->multiply
;
846 * hkl_geometry_list_free: (skip)
851 void hkl_geometry_list_free(HklGeometryList
*self
)
853 hkl_geometry_list_reset(self
);
858 * hkl_geometry_list_add: (skip)
859 * @self: The current #HklGeometryList
860 * @geometry: the #HklGeometry to add
862 * this method Add a geometry to the geometries
864 * This method try to be clever by allocating memory only if the
865 * current length of the geometries is not large enought. Then it just
866 * set the geometry axes and copy it to the right geometries. We do
867 * not gives the x len as it is equal to the self->axes_len.
869 void hkl_geometry_list_add(HklGeometryList
*self
, HklGeometry
*geometry
)
871 HklGeometryListItem
*item
;
873 /* now check if the geometry is already in the geometry list */
874 list_for_each(&self
->items
, item
, list
){
875 if (hkl_geometry_distance_orthodromic(geometry
,
876 item
->geometry
) < HKL_EPSILON
)
880 list_add_tail(&self
->items
,
881 &hkl_geometry_list_item_new(geometry
)->list
);
886 * hkl_geometry_list_n_items_get: (skip)
887 * @self: the this ptr
889 * get the number of items in the #HklGeometryList
891 * Returns: the number of items in the list
893 size_t hkl_geometry_list_n_items_get(const HklGeometryList
*self
)
895 return self
->n_items
;
899 * hkl_geometry_list_items_first_get: (skip)
900 * @self: the this ptr
902 * get the first solution of the #HklGeometryList
904 * Returns: the first solution of the list
906 const HklGeometryListItem
*hkl_geometry_list_items_first_get(const HklGeometryList
*self
)
908 return list_top(&self
->items
, HklGeometryListItem
, list
);
912 * hkl_geometry_list_items_next_get: (skip)
913 * @self: the this ptr
914 * @item: the current #HklGeometryListItem solution of the #HklGeometryList
916 * get the next solution of the #HklGeometryList from the current item location.
918 * Returns: the next solution of the list
920 const HklGeometryListItem
*hkl_geometry_list_items_next_get(const HklGeometryList
*self
,
921 const HklGeometryListItem
*item
)
923 return list_next(&self
->items
, item
, list
);
927 * hkl_geometry_list_reset: (skip)
928 * @self: the this ptr
930 * reset the HklGeometry, in fact it is a sort of clean method remove
931 * all the items of the list.
933 void hkl_geometry_list_reset(HklGeometryList
*self
)
935 HklGeometryListItem
*item
;
936 HklGeometryListItem
*next
;
938 list_for_each_safe(&self
->items
, item
, next
, list
)
939 hkl_geometry_list_item_free(item
);
941 list_head_init(&self
->items
);
946 * hkl_geometry_list_sort: (skip)
950 * sort the #HklGeometryList compare to the distance of the given
953 void hkl_geometry_list_sort(HklGeometryList
*self
, HklGeometry
*ref
)
955 double *distances
= alloca(self
->n_items
* sizeof(*distances
));
956 size_t *idx
= alloca(self
->n_items
* sizeof(*idx
));
957 HklGeometryListItem
**items
= alloca(self
->n_items
* sizeof(*items
));
958 HklGeometryListItem
*item
;
959 HklGeometryListItem
*next
;
964 /* compute the distances once for all */
965 list_for_each(&self
->items
, item
, list
){
966 distances
[i
] = hkl_geometry_distance(ref
, item
->geometry
);
972 /* insertion sorting */
973 for(i
=1; i
<self
->n_items
; ++i
){
975 /* find the smallest idx p lower than i with distance[idx[p]] >= distance[x] */
976 for(p
= 0; distances
[idx
[p
]] < distances
[x
] && fabs(distances
[idx
[p
]] - distances
[x
]) > HKL_EPSILON
; p
++);
978 /* move everythings in between p and i */
979 for(j
=i
-1; j
>=p
; j
--)
982 idx
[p
] = x
; /* insert the saved idx */
985 list_head_init(&self
->items
);
987 for(i
=0; i
<self
->n_items
; ++i
)
988 list_add_tail(&self
->items
, &items
[idx
[i
]]->list
);
992 * hkl_geometry_list_fprintf: (skip)
996 * print to a file the #HklGeometryList
998 void hkl_geometry_list_fprintf(FILE *f
, const HklGeometryList
*self
)
1007 fprintf(f
, "multiply method: %p \n", self
->multiply
);
1009 HklGeometryListItem
*item
;
1010 HklParameter
**axis
;
1013 darray_foreach(axis
, list_top(&self
->items
, HklGeometryListItem
, list
)->geometry
->axes
){
1014 fprintf(f
, "%19s", (*axis
)->name
);
1018 list_for_each(&self
->items
, item
, list
){
1019 fprintf(f
, "\n%d :", i
++);
1020 darray_foreach(axis
, item
->geometry
->axes
){
1021 value
= hkl_parameter_value_get(*axis
, HKL_UNIT_DEFAULT
);
1023 fprintf(f
, " % 18.15f %s", value
, (*axis
)->punit
->repr
);
1025 fprintf(f
, " % 18.15f", value
);
1029 darray_foreach(axis
, item
->geometry
->axes
){
1030 value
= hkl_parameter_value_get(*axis
, HKL_UNIT_DEFAULT
);
1031 value
= gsl_sf_angle_restrict_symm(value
);
1032 value
*= hkl_unit_factor((*axis
)->unit
,
1035 fprintf(f
, " % 18.15f %s", value
, (*axis
)->punit
->repr
);
1037 fprintf(f
, " % 18.15f", value
);
1045 * hkl_geometry_list_multiply: (skip)
1048 * apply the multiply lenthod to the #HklGeometry
1050 void hkl_geometry_list_multiply(HklGeometryList
*self
)
1053 uint len
= self
->n_items
;
1054 HklGeometryListItem
*item
;
1056 if(!self
|| !self
->multiply
)
1060 * warning this method change the self->len so we need to save it
1061 * before using the recursive perm_r calls
1063 for(i
=0, item
=list_top(&self
->items
, HklGeometryListItem
, list
);
1065 ++i
, item
=list_next(&self
->items
, item
, list
))
1066 self
->multiply(self
, item
);
1069 static void perm_r(HklGeometryList
*self
, const HklGeometry
*ref
,
1070 const HklGeometry
*geometry
, const int perm
[],
1071 const unsigned int axis_idx
)
1073 if (axis_idx
== darray_size(geometry
->axes
)){
1074 if(hkl_geometry_distance(geometry
, ref
) > HKL_EPSILON
){
1075 list_add_tail(&self
->items
,
1076 &hkl_geometry_list_item_new(geometry
)->list
);
1081 HklParameter
*axis
= darray_item(geometry
->axes
, axis_idx
);
1082 const double max
= axis
->range
.max
;;
1083 const double value0
= axis
->_value
;
1088 /* fprintf(stdout, "\n%d %s, %f", axis_idx, hkl_axis_get_name(axis), value * HKL_RADTODEG); */
1089 perm_r(self
, ref
, geometry
, perm
, axis_idx
+ 1);
1091 if(value
<= (max
+ HKL_EPSILON
)){
1092 /* optimisation here: */
1093 /* instead of using set_value
1094 * we directly write the
1095 * HklParameter value, BEWARE
1096 * that it require that
1097 * HklParameter is a rotation
1098 * (for now it is always
1100 axis
->_value
= value
;
1102 }while(value
<= (max
+ HKL_EPSILON
));
1103 /* restore the initial value */
1104 axis
->_value
= value0
;
1106 perm_r(self
, ref
, geometry
, perm
, axis_idx
+ 1);
1110 void hkl_geometry_list_multiply_from_range(HklGeometryList
*self
)
1113 uint len
= self
->n_items
;
1115 const HklGeometryListItem
*item
;
1121 * warning this method change the self->len so we need to save it
1122 * before using the recursive perm_r calls
1125 for(i
=0, item
=list_top(&self
->items
, HklGeometryListItem
, list
);
1127 ++i
, item
=list_next(&self
->items
, item
, list
)){
1128 HklGeometry
*geometry
;
1129 HklParameter
**axis
;
1132 geometry
= hkl_geometry_new_copy(item
->geometry
);
1133 perm
= alloca(darray_size(geometry
->axes
) * sizeof(*perm
));
1135 /* find axes to permute and the first solution of thoses axes */
1136 darray_foreach(axis
, geometry
->axes
){
1137 perm
[j
] = hkl_parameter_is_valid(*axis
);
1138 /* fprintf(stdout, "%d %d\n", j, perm[j]); */
1140 hkl_parameter_value_set_smallest_in_range(*axis
);
1144 * fprintf(stdout, "FIRST SOLUTION\n");
1145 * hkl_geometry_fprintf(stdout, geometry);
1148 perm_r(self
, item
->geometry
, geometry
, perm
, 0);
1149 hkl_geometry_free(geometry
);
1154 * hkl_geometry_list_remove_invalid: (skip)
1157 * remove all invalid #HklGeometry from the #HklGeometryList
1159 void hkl_geometry_list_remove_invalid(HklGeometryList
*self
)
1161 HklGeometryListItem
*item
, *next
;
1163 list_for_each_safe(&self
->items
, item
, next
, list
)
1164 if(!hkl_geometry_is_valid(item
->geometry
)){
1165 list_del(&item
->list
);
1167 hkl_geometry_list_item_free(item
);
1171 /***********************/
1172 /* HklGeometryListItem */
1173 /***********************/
1176 * hkl_geometry_list_item_new: (skip)
1183 HklGeometryListItem
*hkl_geometry_list_item_new(const HklGeometry
*geometry
)
1185 HklGeometryListItem
*self
;
1190 self
= HKL_MALLOC(HklGeometryListItem
);
1192 self
->geometry
= hkl_geometry_new_copy(geometry
);
1198 * hkl_geometry_list_item_new_copy: (skip)
1205 HklGeometryListItem
*hkl_geometry_list_item_new_copy(const HklGeometryListItem
*self
)
1207 HklGeometryListItem
*dup
;
1212 dup
= HKL_MALLOC(HklGeometryListItem
);
1214 dup
->geometry
= hkl_geometry_new_copy(self
->geometry
);
1220 * hkl_geometry_list_item_free: (skip)
1225 void hkl_geometry_list_item_free(HklGeometryListItem
*self
)
1230 hkl_geometry_free(self
->geometry
);
1235 * hkl_geometry_list_item_geometry_get:
1236 * @self: the this ptr
1238 * Return value: The geometry contain inside the HklGeometryListItem
1240 const HklGeometry
*hkl_geometry_list_item_geometry_get(const HklGeometryListItem
*self
)
1242 return self
->geometry
;