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-2017 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-detector-private.h"
35 #include "hkl-geometry-private.h" // for _HklGeometry, etc
36 #include "hkl-interval-private.h" // for HklInterval
37 #include "hkl-macros-private.h" // for HKL_MALLOC
38 #include "hkl-parameter-private.h" // for _HklParameter, etc
39 #include "hkl-quaternion-private.h" // for _HklQuaternion, etc
40 #include "hkl-source-private.h" // for HklSource, hkl_source_init
41 #include "hkl-unit-private.h" // for HklUnit, hkl_unit_factor
42 #include "hkl-vector-private.h" // for HklVector, HklQuaternion, etc
43 #include "hkl.h" // for HklGeometry, etc
44 #include "hkl/ccan/container_of/container_of.h" // for container_of
45 #include "hkl/ccan/darray/darray.h" // for darray_foreach, darray_item, etc
48 * Try to add a axis to the axes list,
49 * if a identical axis is present in the list return it
50 * else create a new on and add it to the list.
51 * die if try to add an axis with the same name but a different axis_v
53 static size_t hkl_geometry_add_rotation(HklGeometry
*self
,
54 const char *name
, const HklVector
*axis_v
,
58 HklParameter
**parameter
;
60 /* check if an axis with the same name is on the axis list */
61 darray_foreach(parameter
, self
->axes
){
62 HklAxis
*axis
= container_of(*parameter
, HklAxis
, parameter
);
63 if(!strcmp((*parameter
)->name
, name
)){
64 if (hkl_vector_cmp(&axis
->axis_v
,
66 fprintf(stderr
, "can not add two axis with the same name \"%s\" but different axes <%f, %f, %f> != <%f, %f, %f> into an HklAxes.",
68 axis
->axis_v
.data
[0], axis
->axis_v
.data
[1], axis
->axis_v
.data
[2],
69 axis_v
->data
[0], axis_v
->data
[1], axis_v
->data
[2]);
78 /* no so create and add it to the list */
79 darray_append(self
->axes
, hkl_parameter_new_axis(name
, axis_v
, punit
));
81 return darray_size(self
->axes
) - 1;
88 static struct HklHolderConfig
*hkl_holder_config_new(void)
90 struct HklHolderConfig
*self
;
92 self
= HKL_MALLOC(struct HklHolderConfig
);
101 static struct HklHolderConfig
*hkl_holder_config_ref(struct HklHolderConfig
*self
)
111 static void hkl_holder_config_unref(struct HklHolderConfig
*self
)
127 static HklHolder
*hkl_holder_new(HklGeometry
*geometry
)
129 static HklQuaternion q0
= {{1, 0, 0, 0}};
130 HklHolder
*self
= HKL_MALLOC(HklHolder
);
132 self
->config
= hkl_holder_config_new();
133 self
->geometry
= geometry
;
139 static HklHolder
*hkl_holder_new_copy(HklHolder
*src
, HklGeometry
*geometry
)
141 HklHolder
*self
= HKL_MALLOC(HklHolder
);
143 self
->config
= hkl_holder_config_ref(src
->config
);
144 self
->geometry
= geometry
;
150 static void hkl_holder_free(HklHolder
*self
)
152 hkl_holder_config_unref(self
->config
);
156 static void hkl_holder_update(HklHolder
*self
)
158 static HklQuaternion q0
= {{1, 0, 0, 0}};
162 for(i
=0; i
<self
->config
->len
; ++i
)
163 hkl_quaternion_times_quaternion(&self
->q
,
164 &container_of(darray_item(self
->geometry
->axes
,
165 self
->config
->idx
[i
]),
166 HklAxis
, parameter
)->q
);
169 HklParameter
*hkl_holder_add_rotation_axis(HklHolder
*self
,
170 const char *name
, double x
, double y
, double z
)
172 return hkl_holder_add_rotation_axis_with_punit(self
, name
, x
, y
, z
, &hkl_unit_angle_deg
);
175 HklParameter
*hkl_holder_add_rotation_axis_with_punit(HklHolder
*self
,
176 const char *name
, double x
, double y
, double z
,
177 const HklUnit
*punit
)
179 HklParameter
*axis
= NULL
;
187 idx
= hkl_geometry_add_rotation(self
->geometry
, name
, &axis_v
, punit
);
189 /* check that the axis is not already in the holder */
190 for(i
=0; i
<self
->config
->len
; i
++)
191 if (idx
== self
->config
->idx
[i
])
194 axis
= darray_item(self
->geometry
->axes
, idx
);
195 self
->config
->idx
= realloc(self
->config
->idx
, sizeof(*self
->config
->idx
) * (self
->config
->len
+ 1));
196 self
->config
->idx
[self
->config
->len
++] = idx
;
206 * hkl_geometry_new: (skip)
212 HklGeometry
*hkl_geometry_new(const HklFactory
*factory
)
214 HklGeometry
*g
= NULL
;
216 g
= HKL_MALLOC(HklGeometry
);
218 g
->factory
= factory
;
219 hkl_source_init(&g
->source
, 1.54, 1, 0, 0);
220 darray_init(g
->axes
);
221 darray_init(g
->holders
);
227 * hkl_geometry_new_copy: (skip)
234 HklGeometry
*hkl_geometry_new_copy(const HklGeometry
*src
)
236 HklGeometry
*self
= NULL
;
243 self
= HKL_MALLOC(HklGeometry
);
245 self
->factory
= src
->factory
;
246 self
->source
= src
->source
;
249 darray_init(self
->axes
);
250 darray_foreach(axis
, src
->axes
){
251 darray_append(self
->axes
, hkl_parameter_new_copy(*axis
));
254 /* copy the holders */
255 darray_init(self
->holders
);
256 darray_foreach(holder
, src
->holders
){
257 darray_append(self
->holders
,
258 hkl_holder_new_copy(*holder
, self
));
265 * hkl_geometry_free: (skip)
270 void hkl_geometry_free(HklGeometry
*self
)
275 darray_foreach(axis
, self
->axes
){
276 hkl_parameter_free(*axis
);
278 darray_free(self
->axes
);
280 darray_foreach(holder
, self
->holders
){
281 hkl_holder_free(*holder
);
283 darray_free(self
->holders
);
289 * hkl_geometry_set: (skip)
290 * @self: the this ptr
291 * @src: the other #HklGeometry to set from
293 * Set an #HklGeometry from another one.
295 * Returns: TRUE on success, FALSE if an error occurred
297 int hkl_geometry_set(HklGeometry
*self
, const HklGeometry
*src
)
301 hkl_error(self
->factory
== src
->factory
);
303 self
->source
= src
->source
;
305 /* copy the axes configuration and mark it as dirty */
306 for(i
=0; i
<darray_size(self
->axes
); ++i
)
307 hkl_parameter_init_copy(darray_item(self
->axes
, i
),
308 darray_item(src
->axes
, i
), NULL
);
310 for(i
=0; i
<darray_size(src
->holders
); ++i
)
311 darray_item(self
->holders
, i
)->q
= darray_item(src
->holders
, i
)->q
;
317 * hkl_geometry_axis_names_get:
318 * @self: the this ptr
320 * get all the axes of the given #HklGeometry
322 * Returns: (type gpointer): array of the axes names.
324 const darray_string
*hkl_geometry_axis_names_get(const HklGeometry
*self
)
326 return &self
->factory
->axes
;
330 * hkl_geometry_axis_get:
331 * @self: the this ptr
332 * @name: the name of the axis your are requesting
333 * @error: return location for a GError, or NULL
335 * Return value: (allow-none): the parameter corresponding to the axis name.
337 const HklParameter
*hkl_geometry_axis_get(const HklGeometry
*self
,
343 hkl_error (error
== NULL
|| *error
== NULL
);
345 darray_foreach(axis
, self
->axes
){
346 if (!strcmp((*axis
)->name
, name
))
352 HKL_GEOMETRY_ERROR_AXIS_GET
,
353 "this geometry does not contain this axis \"%s\"",
360 * hkl_geometry_axis_set:
361 * @self: the this ptr
362 * @name: the name of the axis to set
363 * @axis: The #HklParameter to set
364 * @error: return location for a GError, or NULL
366 * Returns: TRUE on success, FALSE if an error occurred
368 int hkl_geometry_axis_set(HklGeometry
*self
, const char *name
,
369 const HklParameter
*axis
,
372 HklParameter
**_axis
;
374 hkl_error (error
== NULL
|| *error
== NULL
);
376 if(name
!= axis
->name
&& strcmp(name
, axis
->name
)){
379 HKL_GEOMETRY_ERROR_AXIS_SET
,
380 "The axis to set \"%s\" is different from the parameter name \"%s\"\n",
385 darray_foreach(_axis
, self
->axes
){
388 if (!strcmp(axis
->name
, (*_axis
)->name
)){
389 hkl_parameter_init_copy(*_axis
, axis
, NULL
);
393 hkl_geometry_update(self
);
399 * hkl_geometry_wavelength_get:
400 * @self: the this ptr
401 * @unit_type: the unit type (default or user) of the returned value
403 * Get the wavelength of the HklGeometry
405 * Returns: the wavelength
407 double hkl_geometry_wavelength_get(const HklGeometry
*self
,
408 HklUnitEnum unit_type
)
410 /* for now there is no unit convertion but the unit_type is
412 return self
->source
.wave_length
;
417 * hkl_geometry_wavelength_set:
420 * @unit_type: the unit type (default or user) of the returned value
421 * @error: return location for a GError, or NULL
423 * Set the wavelength of the geometry
425 * Returns: TRUE on success, FALSE if an error occurred
427 int hkl_geometry_wavelength_set(HklGeometry
*self
, double wavelength
,
428 HklUnitEnum unit_type
, GError
**error
)
430 hkl_error (error
== NULL
|| *error
== NULL
);
432 /* for now there is no unit convertion but the unit_type is
435 self
->source
.wave_length
= wavelength
;
441 * hkl_geometry_init_geometry: (skip)
442 * @self: the this ptr
443 * @src: the #HklGeometry to set from
445 * initilize an HklGeometry
447 * Returns: TRUE on success, FALSE if an error occurred
449 int hkl_geometry_init_geometry(HklGeometry
*self
, const HklGeometry
*src
)
451 return hkl_geometry_set(self
, src
);
455 * hkl_geometry_add_holder: (skip)
458 * add an Holder to the #HklGeometry
462 HklHolder
*hkl_geometry_add_holder(HklGeometry
*self
)
464 HklHolder
*holder
= hkl_holder_new(self
);
465 darray_append(self
->holders
, holder
);
471 * hkl_geometry_update: (skip)
474 * update the geometry internal once an Axis values changed
476 void hkl_geometry_update(HklGeometry
*self
)
481 darray_foreach(axis
, self
->axes
){
482 if ((*axis
)->changed
) {
491 darray_foreach(holder
, self
->holders
){
492 hkl_holder_update(*holder
);
495 darray_foreach(axis
, self
->axes
){
496 (*axis
)->changed
= FALSE
;
501 const char *hkl_geometry_name_get(const HklGeometry
*self
)
503 return hkl_factory_name_get(self
->factory
);
507 * hkl_geometry_get_axis_idx_by_name: (skip)
511 * get the index of the axes named @name in the geometry
513 * Returns: -1 if the axis was not found
515 int hkl_geometry_get_axis_idx_by_name(const HklGeometry
*self
, const char *name
)
523 darray_foreach(axis
, self
->axes
){
524 if (!strcmp((*axis
)->name
, name
))
533 * hkl_geometry_get_axis_by_name:
537 * get an #HklAxis using its name
539 * Returns: (transfer none):
541 HklParameter
*hkl_geometry_get_axis_by_name(HklGeometry
*self
, const char *name
)
545 darray_foreach(axis
, self
->axes
){
546 if (!strcmp((*axis
)->name
, name
))
553 * hkl_geometry_axis_values_get:
554 * @self: the this ptr
555 * @values: (array length=n_values): the values to get
556 * @n_values: the size of the values array.
557 * @unit_type: the unit type (default or user) of the returned value
559 * fill the values array with the #HklGeometry axes.
561 void hkl_geometry_axis_values_get(const HklGeometry
*self
,
562 double values
[], size_t n_values
,
563 HklUnitEnum unit_type
)
568 g_return_if_fail (n_values
== darray_size(self
->axes
));
570 darray_foreach(axis
, self
->axes
){
571 values
[i
++] = hkl_parameter_value_get(*axis
, unit_type
);
576 * hkl_geometry_axis_values_set:
577 * @self: the this ptr
578 * @values: (array length=n_values): the values to set.
579 * @n_values: the length of the values array.
580 * @unit_type: the unit type (default or user) of the returned value
581 * @error: return location for a GError, or NULL
583 * Set the #HklGeometry axes values
585 * Returns: TRUE on success, FALSE if an error occurred
587 int hkl_geometry_axis_values_set(HklGeometry
*self
,
588 double values
[], size_t n_values
,
589 HklUnitEnum unit_type
,
595 hkl_error (error
== NULL
|| *error
== NULL
);
596 g_assert(n_values
== darray_size(self
->axes
));
598 darray_foreach(axis
, self
->axes
){
599 if(!hkl_parameter_value_set(*axis
, values
[i
++], unit_type
, error
)){
600 g_assert (error
== NULL
|| *error
!= NULL
);
604 g_assert (error
== NULL
|| *error
== NULL
);
606 hkl_geometry_update(self
);
612 * hkl_geometry_randomize: (skip)
615 * randomize the #HklGeometry
617 void hkl_geometry_randomize(HklGeometry
*self
)
621 darray_foreach(axis
, self
->axes
){
622 hkl_parameter_randomize(*axis
);
624 hkl_geometry_update(self
);
628 * hkl_geometry_set_values_v: (skip)
630 * @unit_type: the unit type (default or user) of the returned value
634 * set the axes values
638 int hkl_geometry_set_values_v(HklGeometry
*self
, HklUnitEnum unit_type
, GError
**error
, ...)
643 hkl_error (error
== NULL
|| *error
== NULL
);
646 darray_foreach(axis
, self
->axes
){
647 if(!hkl_parameter_value_set(*axis
,
650 g_assert (error
== NULL
|| *error
!= NULL
);
652 hkl_geometry_update(self
);
656 g_assert (error
== NULL
|| *error
== NULL
);
660 hkl_geometry_update(self
);
666 * hkl_geometry_distance:
667 * @self: the this ptr
668 * @ref: the #HklGeometry to compare with
670 * compute the distance between two #HklGeometries
672 * Returns: the distance between the two geometries
674 double hkl_geometry_distance(const HklGeometry
*self
,
675 const HklGeometry
*ref
)
678 double value1
, value2
;
679 double distance
= 0.;
684 for(i
=0; i
<darray_size(self
->axes
); ++i
){
685 value1
= darray_item(self
->axes
, i
)->_value
;
686 value2
= darray_item(ref
->axes
, i
)->_value
;
687 distance
+= fabs(value2
- value1
);
694 * hkl_geometry_distance_orthodromic: (skip)
695 * @self: the this ptr
696 * @ref: the reference #HklGeometry to compare with.
698 * Returns: the orthodromique distance
700 double hkl_geometry_distance_orthodromic(const HklGeometry
*self
,
701 const HklGeometry
*ref
)
704 double value1
, value2
;
705 double distance
= 0.;
710 for(i
=0; i
<darray_size(self
->axes
); ++i
){
713 value1
= darray_item(self
->axes
, i
)->_value
;
714 value2
= darray_item(ref
->axes
, i
)->_value
;
715 d
= fabs(gsl_sf_angle_restrict_symm(value2
) - gsl_sf_angle_restrict_symm(value1
));
716 /* as M_PI and -M_PI are included in the GSL restriction */
726 * hkl_geometry_is_valid: (skip)
729 * check if all axes of the #HklGeometry are valid.
733 int hkl_geometry_is_valid(const HklGeometry
*self
)
737 darray_foreach(axis
, self
->axes
){
738 if(!hkl_parameter_is_valid(*axis
))
746 * hkl_geometry_is_valid_range: (skip)
749 * check if all axes of the #HklGeometry are valid.
750 * (there is a difference for axis)
754 int hkl_geometry_is_valid_range(const HklGeometry
*self
)
758 darray_foreach(axis
, self
->axes
){
759 if(!hkl_parameter_is_valid_range(*axis
))
767 * hkl_geometry_closest_from_geometry_with_range: (skip)
771 * get the closest axes values in the HklInterval compatible with the
772 * current axes values
776 int hkl_geometry_closest_from_geometry_with_range(HklGeometry
*self
,
777 const HklGeometry
*ref
)
780 uint len
= darray_size(self
->axes
);
781 double *values
= alloca(len
* sizeof(*values
));
785 values
[i
] = hkl_parameter_value_get_closest(darray_item(self
->axes
, i
),
786 darray_item(ref
->axes
, i
));
787 if(gsl_isnan(values
[i
])){
794 hkl_parameter_value_set(darray_item(self
->axes
, i
),
796 HKL_UNIT_DEFAULT
, NULL
);
797 hkl_geometry_update(self
);
804 * hkl_geometry_sample_rotation_get:
805 * @self: the self @HklGeometry@
806 * @sample: the rotated sample.
808 * return the rotation part of the given sample in the laboratory basis.
810 * Returns: the rotation express as a quaternion.
812 HklQuaternion
hkl_geometry_sample_rotation_get(const HklGeometry
*self
,
813 const HklSample
*sample
)
815 return darray_item(self
->holders
, 0)->q
;
819 * hkl_geometry_detector_rotation_get:
820 * @self: the self @HklGeometry@
821 * @detector: the @HklDetector@
823 * return the rotation part of the given detector in the laboratory
826 * Returns: the rotation express as a quaternion.
828 HklQuaternion
hkl_geometry_detector_rotation_get(const HklGeometry
*self
,
829 const HklDetector
*detector
)
831 return darray_item(self
->holders
, detector
->idx
)->q
;
836 * hkl_geometry_fprintf: (skip)
840 * print into a file the #HklGeometry
842 void hkl_geometry_fprintf(FILE *file
, const HklGeometry
*self
)
844 fprintf(file
, " HklGeometry type: \"%s\" wavelength: %f",
846 self
->source
.wave_length
);
847 for(unsigned int i
=0; i
<darray_size(self
->axes
); ++i
){
849 hkl_parameter_fprintf(file
, darray_item(self
->axes
, i
));
853 /*******************/
854 /* HklGeometryList */
855 /*******************/
858 * hkl_geometry_list_new: (skip)
864 HklGeometryList
*hkl_geometry_list_new(void)
866 HklGeometryList
*self
;
868 self
= HKL_MALLOC(HklGeometryList
);
870 list_head_init(&self
->items
);
872 self
->multiply
= NULL
;
878 * hkl_geometry_list_new_copy: (skip)
885 HklGeometryList
*hkl_geometry_list_new_copy(const HklGeometryList
*self
)
887 HklGeometryList
*dup
;
888 HklGeometryListItem
*item
;
893 dup
= HKL_MALLOC(HklGeometryList
);
895 list_head_init(&dup
->items
);
896 /* now copy the item arrays */
897 list_for_each(&self
->items
, item
, list
){
898 list_add_tail(&dup
->items
,
899 &hkl_geometry_list_item_new_copy(item
)->list
);
901 dup
->n_items
= self
->n_items
;
902 dup
->multiply
= self
->multiply
;
908 * hkl_geometry_list_free: (skip)
913 void hkl_geometry_list_free(HklGeometryList
*self
)
915 hkl_geometry_list_reset(self
);
920 * hkl_geometry_list_add: (skip)
921 * @self: The current #HklGeometryList
922 * @geometry: the #HklGeometry to add
924 * this method Add a geometry to the geometries
926 * This method try to be clever by allocating memory only if the
927 * current length of the geometries is not large enought. Then it just
928 * set the geometry axes and copy it to the right geometries. We do
929 * not gives the x len as it is equal to the self->axes_len.
931 void hkl_geometry_list_add(HklGeometryList
*self
, HklGeometry
*geometry
)
933 HklGeometryListItem
*item
;
935 /* now check if the geometry is already in the geometry list */
936 list_for_each(&self
->items
, item
, list
){
937 if (hkl_geometry_distance_orthodromic(geometry
,
938 item
->geometry
) < HKL_EPSILON
)
942 list_add_tail(&self
->items
,
943 &hkl_geometry_list_item_new(geometry
)->list
);
948 * hkl_geometry_list_n_items_get: (skip)
949 * @self: the this ptr
951 * get the number of items in the #HklGeometryList
953 * Returns: the number of items in the list
955 size_t hkl_geometry_list_n_items_get(const HklGeometryList
*self
)
957 return self
->n_items
;
961 * hkl_geometry_list_items_first_get: (skip)
962 * @self: the this ptr
964 * get the first solution of the #HklGeometryList
966 * Returns: the first solution of the list
968 const HklGeometryListItem
*hkl_geometry_list_items_first_get(const HklGeometryList
*self
)
970 return list_top(&self
->items
, HklGeometryListItem
, list
);
974 * hkl_geometry_list_items_next_get: (skip)
975 * @self: the this ptr
976 * @item: the current #HklGeometryListItem solution of the #HklGeometryList
978 * get the next solution of the #HklGeometryList from the current item location.
980 * Returns: the next solution of the list
982 const HklGeometryListItem
*hkl_geometry_list_items_next_get(const HklGeometryList
*self
,
983 const HklGeometryListItem
*item
)
985 return list_next(&self
->items
, item
, list
);
989 * hkl_geometry_list_reset: (skip)
990 * @self: the this ptr
992 * reset the HklGeometry, in fact it is a sort of clean method remove
993 * all the items of the list.
995 void hkl_geometry_list_reset(HklGeometryList
*self
)
997 HklGeometryListItem
*item
;
998 HklGeometryListItem
*next
;
1000 list_for_each_safe(&self
->items
, item
, next
, list
)
1001 hkl_geometry_list_item_free(item
);
1003 list_head_init(&self
->items
);
1008 * hkl_geometry_list_sort: (skip)
1012 * sort the #HklGeometryList compare to the distance of the given
1015 void hkl_geometry_list_sort(HklGeometryList
*self
, HklGeometry
*ref
)
1017 double *distances
= alloca(self
->n_items
* sizeof(*distances
));
1018 size_t *idx
= alloca(self
->n_items
* sizeof(*idx
));
1019 HklGeometryListItem
**items
= alloca(self
->n_items
* sizeof(*items
));
1020 HklGeometryListItem
*item
;
1025 /* compute the distances once for all */
1026 list_for_each(&self
->items
, item
, list
){
1027 distances
[i
] = hkl_geometry_distance(ref
, item
->geometry
);
1033 /* insertion sorting */
1034 for(i
=1; i
<self
->n_items
; ++i
){
1036 /* find the smallest idx p lower than i with distance[idx[p]] >= distance[x] */
1037 for(p
= 0; distances
[idx
[p
]] < distances
[x
] && fabs(distances
[idx
[p
]] - distances
[x
]) > HKL_EPSILON
; p
++);
1039 /* move everythings in between p and i */
1040 for(j
=i
-1; j
>=p
; j
--)
1043 idx
[p
] = x
; /* insert the saved idx */
1046 list_head_init(&self
->items
);
1048 for(i
=0; i
<self
->n_items
; ++i
)
1049 list_add_tail(&self
->items
, &items
[idx
[i
]]->list
);
1053 * hkl_geometry_list_fprintf: (skip)
1057 * print to a file the #HklGeometryList
1059 void hkl_geometry_list_fprintf(FILE *f
, const HklGeometryList
*self
)
1067 fprintf(f
, "multiply method: %p \n", self
->multiply
);
1069 HklGeometryListItem
*item
;
1070 HklParameter
**axis
;
1073 darray_foreach(axis
, list_top(&self
->items
, HklGeometryListItem
, list
)->geometry
->axes
){
1074 fprintf(f
, "%19s", (*axis
)->name
);
1078 list_for_each(&self
->items
, item
, list
){
1079 fprintf(f
, "\n%d :", i
++);
1080 darray_foreach(axis
, item
->geometry
->axes
){
1081 value
= hkl_parameter_value_get(*axis
, HKL_UNIT_DEFAULT
);
1083 fprintf(f
, " % 18.15f %s", value
, (*axis
)->punit
->repr
);
1085 fprintf(f
, " % 18.15f", value
);
1089 darray_foreach(axis
, item
->geometry
->axes
){
1090 value
= hkl_parameter_value_get(*axis
, HKL_UNIT_DEFAULT
);
1091 value
= gsl_sf_angle_restrict_symm(value
);
1092 value
*= hkl_unit_factor((*axis
)->unit
,
1095 fprintf(f
, " % 18.15f %s", value
, (*axis
)->punit
->repr
);
1097 fprintf(f
, " % 18.15f", value
);
1105 * hkl_geometry_list_multiply: (skip)
1108 * apply the multiply lenthod to the #HklGeometry
1110 void hkl_geometry_list_multiply(HklGeometryList
*self
)
1113 uint len
= self
->n_items
;
1114 HklGeometryListItem
*item
;
1116 if(!self
|| !self
->multiply
)
1120 * warning this method change the self->len so we need to save it
1121 * before using the recursive perm_r calls
1123 for(i
=0, item
=list_top(&self
->items
, HklGeometryListItem
, list
);
1125 ++i
, item
=list_next(&self
->items
, item
, list
))
1126 self
->multiply(self
, item
);
1129 static void perm_r(HklGeometryList
*self
, const HklGeometry
*ref
,
1130 const HklGeometry
*geometry
, const int perm
[],
1131 const unsigned int axis_idx
)
1133 if (axis_idx
== darray_size(geometry
->axes
)){
1134 if(hkl_geometry_distance(geometry
, ref
) > HKL_EPSILON
){
1135 list_add_tail(&self
->items
,
1136 &hkl_geometry_list_item_new(geometry
)->list
);
1141 HklParameter
*axis
= darray_item(geometry
->axes
, axis_idx
);
1142 const double max
= axis
->range
.max
;;
1143 const double value0
= axis
->_value
;
1148 /* fprintf(stdout, "\n%d %s, %f", axis_idx, hkl_axis_get_name(axis), value * HKL_RADTODEG); */
1149 perm_r(self
, ref
, geometry
, perm
, axis_idx
+ 1);
1151 if(value
<= (max
+ HKL_EPSILON
)){
1152 /* optimisation here: */
1153 /* instead of using set_value
1154 * we directly write the
1155 * HklParameter value, BEWARE
1156 * that it require that
1157 * HklParameter is a rotation
1158 * (for now it is always
1160 axis
->_value
= value
;
1162 }while(value
<= (max
+ HKL_EPSILON
));
1163 /* restore the initial value */
1164 axis
->_value
= value0
;
1166 perm_r(self
, ref
, geometry
, perm
, axis_idx
+ 1);
1170 void hkl_geometry_list_multiply_from_range(HklGeometryList
*self
)
1173 uint len
= self
->n_items
;
1175 const HklGeometryListItem
*item
;
1181 * warning this method change the self->len so we need to save it
1182 * before using the recursive perm_r calls
1185 for(i
=0, item
=list_top(&self
->items
, HklGeometryListItem
, list
);
1187 ++i
, item
=list_next(&self
->items
, item
, list
)){
1188 HklGeometry
*geometry
;
1189 HklParameter
**axis
;
1192 geometry
= hkl_geometry_new_copy(item
->geometry
);
1193 perm
= alloca(darray_size(geometry
->axes
) * sizeof(*perm
));
1195 /* find axes to permute and the first solution of thoses axes */
1196 darray_foreach(axis
, geometry
->axes
){
1197 perm
[j
] = hkl_parameter_is_valid(*axis
);
1198 /* fprintf(stdout, "%d %d\n", j, perm[j]); */
1200 hkl_parameter_value_set_smallest_in_range(*axis
);
1204 * fprintf(stdout, "FIRST SOLUTION\n");
1205 * hkl_geometry_fprintf(stdout, geometry);
1208 perm_r(self
, item
->geometry
, geometry
, perm
, 0);
1209 hkl_geometry_free(geometry
);
1214 * hkl_geometry_list_remove_invalid: (skip)
1217 * remove all invalid #HklGeometry from the #HklGeometryList
1219 void hkl_geometry_list_remove_invalid(HklGeometryList
*self
)
1221 HklGeometryListItem
*item
, *next
;
1223 list_for_each_safe(&self
->items
, item
, next
, list
)
1224 if(!hkl_geometry_is_valid_range(item
->geometry
)){
1225 list_del(&item
->list
);
1227 hkl_geometry_list_item_free(item
);
1231 /***********************/
1232 /* HklGeometryListItem */
1233 /***********************/
1236 * hkl_geometry_list_item_new: (skip)
1243 HklGeometryListItem
*hkl_geometry_list_item_new(const HklGeometry
*geometry
)
1245 HklGeometryListItem
*self
;
1250 self
= HKL_MALLOC(HklGeometryListItem
);
1252 self
->geometry
= hkl_geometry_new_copy(geometry
);
1258 * hkl_geometry_list_item_new_copy: (skip)
1265 HklGeometryListItem
*hkl_geometry_list_item_new_copy(const HklGeometryListItem
*self
)
1267 HklGeometryListItem
*dup
;
1272 dup
= HKL_MALLOC(HklGeometryListItem
);
1274 dup
->geometry
= hkl_geometry_new_copy(self
->geometry
);
1280 * hkl_geometry_list_item_free: (skip)
1285 void hkl_geometry_list_item_free(HklGeometryListItem
*self
)
1290 hkl_geometry_free(self
->geometry
);
1295 * hkl_geometry_list_item_geometry_get:
1296 * @self: the this ptr
1298 * Return value: The geometry contain inside the HklGeometryListItem
1300 const HklGeometry
*hkl_geometry_list_item_geometry_get(const HklGeometryListItem
*self
)
1302 return self
->geometry
;