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-2016 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 <gsl/gsl_nan.h> // for GSL_NAN
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 M_PI, ceil, fabs, floor
26 #include <stdio.h> // for FILE
27 #include <stdlib.h> // for NULL, free
28 #include "hkl-axis-private.h" // for HklAxis
29 #include "hkl-interval-private.h" // for HklInterval, etc
30 #include "hkl-macros-private.h" // for HKL_MALLOC
31 #include "hkl-parameter-private.h" // for _HklParameter, etc
32 #include "hkl-quaternion-private.h" // for hkl_quaternion_fprintf, etc
33 #include "hkl-vector-private.h" // for hkl_vector_fprintf, etc
34 #include "hkl.h" // for HklParameter, TRUE, etc
35 #include "hkl/ccan/container_of/container_of.h" // for container_of
41 static inline HklParameter
*hkl_axis_copy_real(const HklParameter
*base
)
43 HklAxis
*self
= container_of(base
, HklAxis
, parameter
);
46 dup
= HKL_MALLOC(HklAxis
);
50 return &dup
->parameter
;
54 static inline void hkl_axis_free_real(HklParameter
*self
)
56 free(container_of(self
, HklAxis
, parameter
));
59 static inline void hkl_axis_update(HklAxis
*self
)
61 hkl_quaternion_init_from_angle_and_axe(&self
->q
,
62 self
->parameter
._value
,
66 static inline int hkl_axis_init_copy_real(HklParameter
*self
, const HklParameter
*src
,
69 HklAxis
*axis_self
= container_of(self
, HklAxis
, parameter
);
70 HklAxis
*axis_src
= container_of(src
, HklAxis
, parameter
);
72 hkl_error (error
== NULL
|| *error
== NULL
);
74 *axis_self
= *axis_src
;
80 static inline int hkl_axis_set_value_real(HklParameter
*self
, double value
,
81 HklUnitEnum unit_type
, GError
**error
)
83 HklAxis
*axis
= container_of(self
, HklAxis
, parameter
);
85 hkl_error (error
== NULL
|| *error
== NULL
);
87 if(!hkl_parameter_value_set_real(self
, value
, unit_type
, error
)){
88 g_assert (error
== NULL
|| *error
!= NULL
);
91 g_assert (error
== NULL
|| *error
== NULL
);
93 hkl_axis_update(axis
);
98 static inline void hkl_axis_set_value_smallest_in_range_real(HklParameter
*self
)
102 value
= self
->_value
;
103 min
= self
->range
.min
;
106 hkl_axis_set_value_real(self
,
107 value
+ 2*M_PI
*ceil((min
- value
)/(2*M_PI
)),
111 hkl_axis_set_value_real(self
,
112 value
- 2*M_PI
*floor((value
- min
)/(2*M_PI
)),
117 static inline void hkl_axis_randomize_real(HklParameter
*self
)
119 hkl_parameter_randomize_real(self
);
120 hkl_axis_update(container_of(self
, HklAxis
, parameter
));
124 * given a current position of angle a min and max interval find the closest
125 * equivalent angle + n delta_angle in a given direction.
126 * CAUSION angle MUST be in [min, max] otherwise...
128 static void find_angle(double current
, double *angle
, double *distance
,
129 double min
, double max
, double delta_angle
)
131 double new_angle
= *angle
;
134 while(new_angle
>= min
&& new_angle
<= max
) {
135 new_distance
= fabs(new_angle
- current
);
136 if (new_distance
<= *distance
) {
138 *distance
= new_distance
;
140 new_angle
+= delta_angle
;
144 static inline double hkl_axis_get_value_closest_real(const HklParameter
*self
,
145 const HklParameter
*ref
)
147 double angle
= self
->_value
;
149 if(hkl_parameter_is_valid(self
)){
150 if(hkl_interval_length(&self
->range
) >= 2*M_PI
){
152 double current
= ref
->_value
;
153 double distance
= fabs(current
- angle
);
154 double delta
= 2. * M_PI
;
155 double min
= self
->range
.min
;
156 double max
= self
->range
.max
;
160 k
= (int)(floor((max
- angle
) / delta
));
162 find_angle(current
, &angle
, &distance
, min
, max
, -delta
);
163 } else if (angle
< min
) {
164 k
= (int) (ceil((min
- angle
) / delta
));
166 find_angle(current
, &angle
, &distance
, min
, max
, delta
);
168 find_angle(current
, &angle
, &distance
, min
, max
, -delta
);
169 find_angle(current
, &angle
, &distance
, min
, max
, delta
);
179 * check if the angle or its equivalent is in between [min, max]
181 static inline int hkl_axis_is_valid_real(const HklParameter
*self
)
183 double value
= self
->_value
;
185 HklInterval range
= self
->range
;
187 if(hkl_interval_length(&range
) > 2*M_PI
)
190 hkl_interval_angle_restrict_symm(&range
);
191 value
= gsl_sf_angle_restrict_symm(value
);
193 if(range
.min
<= range
.max
){
194 if(range
.min
<= value
&& range
.max
>= value
)
197 if(value
<= range
.max
|| value
>= range
.min
)
204 static inline void hkl_axis_fprintf_real(FILE *f
, const HklParameter
*self
)
206 HklAxis
*axis
= container_of(self
, HklAxis
, parameter
);
208 hkl_parameter_fprintf_real(f
, self
);
209 hkl_vector_fprintf(f
, &axis
->axis_v
);
210 hkl_quaternion_fprintf(f
, &axis
->q
);
213 static inline const HklVector
*hkl_axis_axis_v_get_real(const HklParameter
*self
)
215 return &container_of(self
, HklAxis
, parameter
)->axis_v
;
218 static inline const HklQuaternion
*hkl_axis_quaternion_get_real(const HklParameter
*self
)
220 return &container_of(self
, HklAxis
, parameter
)->q
;
223 static HklParameterOperations hkl_parameter_operations_axis
= {
224 HKL_PARAMETER_OPERATIONS_DEFAULTS
,
225 .copy
= hkl_axis_copy_real
,
226 .free
= hkl_axis_free_real
,
227 .init_copy
= hkl_axis_init_copy_real
,
228 .get_value_closest
= hkl_axis_get_value_closest_real
,
229 .set_value
= hkl_axis_set_value_real
,
230 .set_value_smallest_in_range
= hkl_axis_set_value_smallest_in_range_real
,
231 .randomize
= hkl_axis_randomize_real
,
232 .is_valid
= hkl_axis_is_valid_real
,
233 .fprintf
= hkl_axis_fprintf_real
,
234 .axis_v_get
= hkl_axis_axis_v_get_real
,
235 .quaternion_get
= hkl_axis_quaternion_get_real
238 HklParameter
*hkl_parameter_new_axis(const char *name
, HklVector
const *axis_v
, const HklUnit
*punit
)
241 .parameter
= { HKL_PARAMETER_DEFAULTS_ANGLE
,
244 .ops
= &hkl_parameter_operations_axis
,
247 .q
= {{1., 0., 0., 0.}},
250 HklAxis
*self
= HKL_MALLOC(HklAxis
);
254 return &self
->parameter
;