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-2015 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_axis_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_axis_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 \"%s\"\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:
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
)
472 darray_foreach(axis
, self
->axes
){
473 if ((*axis
)->changed
) {
482 darray_foreach(holder
, self
->holders
){
483 hkl_holder_update(*holder
);
486 darray_foreach(axis
, self
->axes
){
487 (*axis
)->changed
= FALSE
;
492 const char *hkl_geometry_name_get(const HklGeometry
*self
)
494 return hkl_factory_name_get(self
->factory
);
498 * hkl_geometry_get_axis_idx_by_name: (skip)
502 * get the index of the axes named @name in the geometry
504 * Returns: -1 if the axis was not found
506 int hkl_geometry_get_axis_idx_by_name(const HklGeometry
*self
, const char *name
)
514 darray_foreach(axis
, self
->axes
){
515 if (!strcmp((*axis
)->name
, name
))
524 * hkl_geometry_get_axis_by_name:
528 * get an #HklAxis using its name
530 * Returns: (transfer none):
532 HklParameter
*hkl_geometry_get_axis_by_name(HklGeometry
*self
, const char *name
)
536 darray_foreach(axis
, self
->axes
){
537 if (!strcmp((*axis
)->name
, name
))
544 * hkl_geometry_axis_values_get:
545 * @self: the this ptr
546 * @values: (array length=n_values): the values to get
547 * @n_values: the size of the values array.
548 * @unit_type: the unit type (default or user) of the returned value
550 * fill the values array with the #HklGeometry axes.
552 void hkl_geometry_axis_values_get(const HklGeometry
*self
,
553 double values
[], size_t n_values
,
554 HklUnitEnum unit_type
)
559 g_return_if_fail (n_values
== darray_size(self
->axes
));
561 darray_foreach(axis
, self
->axes
){
562 values
[i
++] = hkl_parameter_value_get(*axis
, unit_type
);
567 * hkl_geometry_axis_values_set:
568 * @self: the this ptr
569 * @values: (array length=n_values): the values to set.
570 * @n_values: the length of the values array.
571 * @unit_type: the unit type (default or user) of the returned value
572 * @error: return location for a GError, or NULL
574 * Set the #HklGeometry axes values
576 * Returns: TRUE on success, FALSE if an error occurred
578 int hkl_geometry_axis_values_set(HklGeometry
*self
,
579 double values
[], size_t n_values
,
580 HklUnitEnum unit_type
,
586 hkl_error (error
== NULL
|| *error
== NULL
);
587 g_assert(n_values
== darray_size(self
->axes
));
589 darray_foreach(axis
, self
->axes
){
590 if(!hkl_parameter_value_set(*axis
, values
[i
++], unit_type
, error
)){
591 g_assert (error
== NULL
|| *error
!= NULL
);
595 g_assert (error
== NULL
|| *error
== NULL
);
597 hkl_geometry_update(self
);
603 * hkl_geometry_randomize: (skip)
606 * randomize the #HklGeometry
608 void hkl_geometry_randomize(HklGeometry
*self
)
612 darray_foreach(axis
, self
->axes
){
613 hkl_parameter_randomize(*axis
);
615 hkl_geometry_update(self
);
619 * hkl_geometry_set_values_v: (skip)
621 * @unit_type: the unit type (default or user) of the returned value
625 * set the axes values
629 int hkl_geometry_set_values_v(HklGeometry
*self
, HklUnitEnum unit_type
, GError
**error
, ...)
634 hkl_error (error
== NULL
|| *error
== NULL
);
637 darray_foreach(axis
, self
->axes
){
638 if(!hkl_parameter_value_set(*axis
,
641 g_assert (error
== NULL
|| *error
!= NULL
);
643 hkl_geometry_update(self
);
647 g_assert (error
== NULL
|| *error
== NULL
);
651 hkl_geometry_update(self
);
657 * hkl_geometry_distance:
658 * @self: the this ptr
659 * @ref: the #HklGeometry to compare with
661 * compute the distance between two #HklGeometries
663 * Returns: the distance between the two geometries
665 double hkl_geometry_distance(const HklGeometry
*self
,
666 const HklGeometry
*ref
)
669 double value1
, value2
;
670 double distance
= 0.;
675 for(i
=0; i
<darray_size(self
->axes
); ++i
){
676 value1
= darray_item(self
->axes
, i
)->_value
;
677 value2
= darray_item(ref
->axes
, i
)->_value
;
678 distance
+= fabs(value2
- value1
);
685 * hkl_geometry_distance_orthodromic: (skip)
686 * @self: the this ptr
687 * @ref: the reference #HklGeometry to compare with.
689 * Returns: the orthodromique distance
691 double hkl_geometry_distance_orthodromic(const HklGeometry
*self
,
692 const HklGeometry
*ref
)
695 double value1
, value2
;
696 double distance
= 0.;
701 for(i
=0; i
<darray_size(self
->axes
); ++i
){
704 value1
= darray_item(self
->axes
, i
)->_value
;
705 value2
= darray_item(ref
->axes
, i
)->_value
;
706 d
= fabs(gsl_sf_angle_restrict_symm(value2
) - gsl_sf_angle_restrict_symm(value1
));
707 /* as M_PI and -M_PI are included in the GSL restriction */
717 * hkl_geometry_is_valid: (skip)
720 * check if all axes of the #HklGeometry are valid.
724 int hkl_geometry_is_valid(const HklGeometry
*self
)
728 darray_foreach(axis
, self
->axes
){
729 if(!hkl_parameter_is_valid(*axis
))
737 * hkl_geometry_closest_from_geometry_with_range: (skip)
741 * get the closest axes values in the HklInterval compatible with the
742 * current axes values
746 int hkl_geometry_closest_from_geometry_with_range(HklGeometry
*self
,
747 const HklGeometry
*ref
)
750 uint len
= darray_size(self
->axes
);
751 double *values
= alloca(len
* sizeof(*values
));
755 values
[i
] = hkl_parameter_value_get_closest(darray_item(self
->axes
, i
),
756 darray_item(ref
->axes
, i
));
757 if(gsl_isnan(values
[i
])){
764 hkl_parameter_value_set(darray_item(self
->axes
, i
),
766 HKL_UNIT_DEFAULT
, NULL
);
767 hkl_geometry_update(self
);
773 * hkl_geometry_fprintf: (skip)
777 * print into a file the #HklGeometry
779 void hkl_geometry_fprintf(FILE *file
, const HklGeometry
*self
)
781 fprintf(file
, " HklGeometry type: \"%s\" wavelength: %f",
783 self
->source
.wave_length
);
784 for(unsigned int i
=0; i
<darray_size(self
->axes
); ++i
){
786 hkl_parameter_fprintf(file
, darray_item(self
->axes
, i
));
790 /*******************/
791 /* HklGeometryList */
792 /*******************/
795 * hkl_geometry_list_new: (skip)
801 HklGeometryList
*hkl_geometry_list_new(void)
803 HklGeometryList
*self
;
805 self
= HKL_MALLOC(HklGeometryList
);
807 list_head_init(&self
->items
);
809 self
->multiply
= NULL
;
815 * hkl_geometry_list_new_copy: (skip)
822 HklGeometryList
*hkl_geometry_list_new_copy(const HklGeometryList
*self
)
824 HklGeometryList
*dup
;
825 HklGeometryListItem
*item
;
830 dup
= HKL_MALLOC(HklGeometryList
);
832 list_head_init(&dup
->items
);
833 /* now copy the item arrays */
834 list_for_each(&self
->items
, item
, list
){
835 list_add_tail(&dup
->items
,
836 &hkl_geometry_list_item_new_copy(item
)->list
);
838 dup
->n_items
= self
->n_items
;
839 dup
->multiply
= self
->multiply
;
845 * hkl_geometry_list_free: (skip)
850 void hkl_geometry_list_free(HklGeometryList
*self
)
852 hkl_geometry_list_reset(self
);
857 * hkl_geometry_list_add: (skip)
858 * @self: The current #HklGeometryList
859 * @geometry: the #HklGeometry to add
861 * this method Add a geometry to the geometries
863 * This method try to be clever by allocating memory only if the
864 * current length of the geometries is not large enought. Then it just
865 * set the geometry axes and copy it to the right geometries. We do
866 * not gives the x len as it is equal to the self->axes_len.
868 void hkl_geometry_list_add(HklGeometryList
*self
, HklGeometry
*geometry
)
870 HklGeometryListItem
*item
;
872 /* now check if the geometry is already in the geometry list */
873 list_for_each(&self
->items
, item
, list
){
874 if (hkl_geometry_distance_orthodromic(geometry
,
875 item
->geometry
) < HKL_EPSILON
)
879 list_add_tail(&self
->items
,
880 &hkl_geometry_list_item_new(geometry
)->list
);
885 * hkl_geometry_list_n_items_get: (skip)
886 * @self: the this ptr
888 * get the number of items in the #HklGeometryList
890 * Returns: the number of items in the list
892 size_t hkl_geometry_list_n_items_get(const HklGeometryList
*self
)
894 return self
->n_items
;
898 * hkl_geometry_list_items_first_get: (skip)
899 * @self: the this ptr
901 * get the first solution of the #HklGeometryList
903 * Returns: the first solution of the list
905 const HklGeometryListItem
*hkl_geometry_list_items_first_get(const HklGeometryList
*self
)
907 return list_top(&self
->items
, HklGeometryListItem
, list
);
911 * hkl_geometry_list_items_next_get: (skip)
912 * @self: the this ptr
913 * @item: the current #HklGeometryListItem solution of the #HklGeometryList
915 * get the next solution of the #HklGeometryList from the current item location.
917 * Returns: the next solution of the list
919 const HklGeometryListItem
*hkl_geometry_list_items_next_get(const HklGeometryList
*self
,
920 const HklGeometryListItem
*item
)
922 return list_next(&self
->items
, item
, list
);
926 * hkl_geometry_list_reset: (skip)
927 * @self: the this ptr
929 * reset the HklGeometry, in fact it is a sort of clean method remove
930 * all the items of the list.
932 void hkl_geometry_list_reset(HklGeometryList
*self
)
934 HklGeometryListItem
*item
;
935 HklGeometryListItem
*next
;
937 list_for_each_safe(&self
->items
, item
, next
, list
)
938 hkl_geometry_list_item_free(item
);
940 list_head_init(&self
->items
);
945 * hkl_geometry_list_sort: (skip)
949 * sort the #HklGeometryList compare to the distance of the given
952 void hkl_geometry_list_sort(HklGeometryList
*self
, HklGeometry
*ref
)
954 double *distances
= alloca(self
->n_items
* sizeof(*distances
));
955 size_t *idx
= alloca(self
->n_items
* sizeof(*idx
));
956 HklGeometryListItem
**items
= alloca(self
->n_items
* sizeof(*items
));
957 HklGeometryListItem
*item
;
962 /* compute the distances once for all */
963 list_for_each(&self
->items
, item
, list
){
964 distances
[i
] = hkl_geometry_distance(ref
, item
->geometry
);
970 /* insertion sorting */
971 for(i
=1; i
<self
->n_items
; ++i
){
973 /* find the smallest idx p lower than i with distance[idx[p]] >= distance[x] */
974 for(p
= 0; distances
[idx
[p
]] < distances
[x
] && fabs(distances
[idx
[p
]] - distances
[x
]) > HKL_EPSILON
; p
++);
976 /* move everythings in between p and i */
977 for(j
=i
-1; j
>=p
; j
--)
980 idx
[p
] = x
; /* insert the saved idx */
983 list_head_init(&self
->items
);
985 for(i
=0; i
<self
->n_items
; ++i
)
986 list_add_tail(&self
->items
, &items
[idx
[i
]]->list
);
990 * hkl_geometry_list_fprintf: (skip)
994 * print to a file the #HklGeometryList
996 void hkl_geometry_list_fprintf(FILE *f
, const HklGeometryList
*self
)
1004 fprintf(f
, "multiply method: %p \n", self
->multiply
);
1006 HklGeometryListItem
*item
;
1007 HklParameter
**axis
;
1010 darray_foreach(axis
, list_top(&self
->items
, HklGeometryListItem
, list
)->geometry
->axes
){
1011 fprintf(f
, "%19s", (*axis
)->name
);
1015 list_for_each(&self
->items
, item
, list
){
1016 fprintf(f
, "\n%d :", i
++);
1017 darray_foreach(axis
, item
->geometry
->axes
){
1018 value
= hkl_parameter_value_get(*axis
, HKL_UNIT_DEFAULT
);
1020 fprintf(f
, " % 18.15f %s", value
, (*axis
)->punit
->repr
);
1022 fprintf(f
, " % 18.15f", value
);
1026 darray_foreach(axis
, item
->geometry
->axes
){
1027 value
= hkl_parameter_value_get(*axis
, HKL_UNIT_DEFAULT
);
1028 value
= gsl_sf_angle_restrict_symm(value
);
1029 value
*= hkl_unit_factor((*axis
)->unit
,
1032 fprintf(f
, " % 18.15f %s", value
, (*axis
)->punit
->repr
);
1034 fprintf(f
, " % 18.15f", value
);
1042 * hkl_geometry_list_multiply: (skip)
1045 * apply the multiply lenthod to the #HklGeometry
1047 void hkl_geometry_list_multiply(HklGeometryList
*self
)
1050 uint len
= self
->n_items
;
1051 HklGeometryListItem
*item
;
1053 if(!self
|| !self
->multiply
)
1057 * warning this method change the self->len so we need to save it
1058 * before using the recursive perm_r calls
1060 for(i
=0, item
=list_top(&self
->items
, HklGeometryListItem
, list
);
1062 ++i
, item
=list_next(&self
->items
, item
, list
))
1063 self
->multiply(self
, item
);
1066 static void perm_r(HklGeometryList
*self
, const HklGeometry
*ref
,
1067 const HklGeometry
*geometry
, const int perm
[],
1068 const unsigned int axis_idx
)
1070 if (axis_idx
== darray_size(geometry
->axes
)){
1071 if(hkl_geometry_distance(geometry
, ref
) > HKL_EPSILON
){
1072 list_add_tail(&self
->items
,
1073 &hkl_geometry_list_item_new(geometry
)->list
);
1078 HklParameter
*axis
= darray_item(geometry
->axes
, axis_idx
);
1079 const double max
= axis
->range
.max
;;
1080 const double value0
= axis
->_value
;
1085 /* fprintf(stdout, "\n%d %s, %f", axis_idx, hkl_axis_get_name(axis), value * HKL_RADTODEG); */
1086 perm_r(self
, ref
, geometry
, perm
, axis_idx
+ 1);
1088 if(value
<= (max
+ HKL_EPSILON
)){
1089 /* optimisation here: */
1090 /* instead of using set_value
1091 * we directly write the
1092 * HklParameter value, BEWARE
1093 * that it require that
1094 * HklParameter is a rotation
1095 * (for now it is always
1097 axis
->_value
= value
;
1099 }while(value
<= (max
+ HKL_EPSILON
));
1100 /* restore the initial value */
1101 axis
->_value
= value0
;
1103 perm_r(self
, ref
, geometry
, perm
, axis_idx
+ 1);
1107 void hkl_geometry_list_multiply_from_range(HklGeometryList
*self
)
1110 uint len
= self
->n_items
;
1112 const HklGeometryListItem
*item
;
1118 * warning this method change the self->len so we need to save it
1119 * before using the recursive perm_r calls
1122 for(i
=0, item
=list_top(&self
->items
, HklGeometryListItem
, list
);
1124 ++i
, item
=list_next(&self
->items
, item
, list
)){
1125 HklGeometry
*geometry
;
1126 HklParameter
**axis
;
1129 geometry
= hkl_geometry_new_copy(item
->geometry
);
1130 perm
= alloca(darray_size(geometry
->axes
) * sizeof(*perm
));
1132 /* find axes to permute and the first solution of thoses axes */
1133 darray_foreach(axis
, geometry
->axes
){
1134 perm
[j
] = hkl_parameter_is_valid(*axis
);
1135 /* fprintf(stdout, "%d %d\n", j, perm[j]); */
1137 hkl_parameter_value_set_smallest_in_range(*axis
);
1141 * fprintf(stdout, "FIRST SOLUTION\n");
1142 * hkl_geometry_fprintf(stdout, geometry);
1145 perm_r(self
, item
->geometry
, geometry
, perm
, 0);
1146 hkl_geometry_free(geometry
);
1151 * hkl_geometry_list_remove_invalid: (skip)
1154 * remove all invalid #HklGeometry from the #HklGeometryList
1156 void hkl_geometry_list_remove_invalid(HklGeometryList
*self
)
1158 HklGeometryListItem
*item
, *next
;
1160 list_for_each_safe(&self
->items
, item
, next
, list
)
1161 if(!hkl_geometry_is_valid(item
->geometry
)){
1162 list_del(&item
->list
);
1164 hkl_geometry_list_item_free(item
);
1168 /***********************/
1169 /* HklGeometryListItem */
1170 /***********************/
1173 * hkl_geometry_list_item_new: (skip)
1180 HklGeometryListItem
*hkl_geometry_list_item_new(const HklGeometry
*geometry
)
1182 HklGeometryListItem
*self
;
1187 self
= HKL_MALLOC(HklGeometryListItem
);
1189 self
->geometry
= hkl_geometry_new_copy(geometry
);
1195 * hkl_geometry_list_item_new_copy: (skip)
1202 HklGeometryListItem
*hkl_geometry_list_item_new_copy(const HklGeometryListItem
*self
)
1204 HklGeometryListItem
*dup
;
1209 dup
= HKL_MALLOC(HklGeometryListItem
);
1211 dup
->geometry
= hkl_geometry_new_copy(self
->geometry
);
1217 * hkl_geometry_list_item_free: (skip)
1222 void hkl_geometry_list_item_free(HklGeometryListItem
*self
)
1227 hkl_geometry_free(self
->geometry
);
1232 * hkl_geometry_list_item_geometry_get:
1233 * @self: the this ptr
1235 * Return value: The geometry contain inside the HklGeometryListItem
1237 const HklGeometry
*hkl_geometry_list_item_geometry_get(const HklGeometryListItem
*self
)
1239 return self
->geometry
;