OpenKalman
Inclination.hpp
Go to the documentation of this file.
1 /* This file is part of OpenKalman, a header-only C++ library for
2  * Kalman filters and other recursive filters.
3  *
4  * Copyright (c) 2018-2021 Christopher Lee Ogden <ogden@gatech.edu>
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0. If a copy of the MPL was not distributed with this
8  * file, You can obtain one at https://mozilla.org/MPL/2.0/.
9  */
10 
16 #ifndef OPENKALMAN_COEFFICIENTS_INCLINATION_HPP
17 #define OPENKALMAN_COEFFICIENTS_INCLINATION_HPP
18 
19 #include <type_traits>
20 #ifdef __cpp_concepts
21 #include <concepts>
22 #endif
23 #include <cmath>
24 #include "../../../basics/compatibility/language-features.hpp"
27 #include "values/functions/internal/update_real_part.hpp"
28 #include "values/math/abs.hpp"
29 #include "values/math/sin.hpp"
30 #include "values/math/cos.hpp"
31 #include "values/math/atan2.hpp"
33 #include "linear-algebra/coordinates/interfaces/coordinate_descriptor_traits.hpp"
34 
35 
37 {
48 #ifdef __cpp_concepts
49  template<values::fixed Down = values::fixed_minus_half_pi<long double>, values::fixed Up = values::fixed_half_pi<long double>>
50  requires (values::fixed_number_of_v<Up> - values::fixed_number_of_v<Down> > 0) and
51  (values::fixed_number_of_v<Down> <= 0) and (values::fixed_number_of_v<Up> >= 0)
52 #else
53  template<typename Down = values::fixed_minus_half_pi<long double>, typename Up = values::fixed_half_pi<long double>>
54 #endif
55  struct Inclination
56  {
57 #ifndef __cpp_concepts
58  static_assert(values::fixed<Down>);
59  static_assert(values::fixed<Up>);
60  static_assert(values::fixed_number_of_v<Up> - values::fixed_number_of_v<Down> > 0);
61  static_assert(values::fixed_number_of_v<Down> <= 0);
62  static_assert(values::fixed_number_of_v<Up> >= 0);
63 #endif
64  };
65 
66 
68  namespace inclination
69  {
72 
73 
76 
77 
78  namespace detail
79  {
80  template<typename T>
81  struct is_inclination : std::false_type {};
82 
83  template<typename Down, typename Up>
84  struct is_inclination<Inclination<Down, Up>> : std::true_type {};
85  }
86 
87 
91  template<typename T>
92 #ifdef __cpp_concepts
93  concept inclination =
94 #else
95  static constexpr bool inclination =
96 #endif
98 
99  } // namespace inclination
100 
101 } // namespace OpenKalman::coordinates
102 
103 
104 namespace OpenKalman::interface
105 {
110  template<typename Down, typename Up>
111  struct coordinate_descriptor_traits<coordinates::Inclination<Down, Up>>
112  {
113  private:
114 
116  static constexpr auto down = values::fixed_number_of_v<Down>;
117  static constexpr auto up = values::fixed_number_of_v<Up>;
118 
119  public:
120 
121  static constexpr bool is_specialized = true;
122 
123 
124  static constexpr auto
125  dimension(const T&) { return std::integral_constant<std::size_t, 1>{}; };
126 
127 
128  static constexpr auto
129  stat_dimension(const T&) { return std::integral_constant<std::size_t, 2>{}; };
130 
131 
132  static constexpr auto
133  is_euclidean(const T&) { return std::false_type{}; }
134 
135 
136  static constexpr auto
137  hash_code(const T&)
138  {
139  constexpr auto down_float = static_cast<float>(down);
140  constexpr auto up_float = static_cast<float>(up);
141  constexpr float a = (down_float * 3.f + up_float * 2.f) / (up_float - down_float);
142  constexpr auto bits = std::numeric_limits<std::size_t>::digits;
143  if constexpr (bits < 32) return 0x8CE6_uz + static_cast<std::size_t>(a * a * 0x1.p2f);
144  else if constexpr (bits < 64) return 0x8CE6267E_uz + static_cast<std::size_t>(a * a * 0x1.p4f);
145  else return 0x8CE6267E341642F7_uz + static_cast<std::size_t>(a * a * 0x1.p8f);
146  }
147 
148 
156 #ifdef __cpp_concepts
157  static constexpr values::value auto
158  to_euclidean_component(const T& t, const auto& g, const values::index auto& euclidean_local_index)
159  requires requires(std::size_t i){ {g(i)} -> values::value; }
160 #else
161  template<typename Getter, typename L, std::enable_if_t<values::index<L> and
162  values::value<typename std::invoke_result<const Getter&, std::size_t>::type>, int> = 0>
163  static constexpr auto
164  to_euclidean_component(const T& t, const Getter& g, const L& euclidean_local_index)
165 #endif
166  {
167  using Scalar = std::decay_t<decltype(g(0_uz))>;
168  using R = std::decay_t<decltype(values::real(std::declval<Scalar>()))>;
169  const Scalar cf {numbers::pi_v<R> / (up - down)};
170  const Scalar horiz {R{up + down} * R{0.5}};
171 
172  Scalar theta = cf * (g(0_uz) - horiz); // Convert to radians
173 
174  if (euclidean_local_index == 0) return values::cos(theta);
175  else return values::sin(theta);
176  }
177 
178 
183 #ifdef __cpp_concepts
184  static constexpr values::value auto
185  from_euclidean_component(const T& t, const auto& g, const values::index auto& local_index)
186  requires requires(std::size_t i){ {g(i)} -> values::value; }
187 #else
188  template<typename Getter, typename L, std::enable_if_t<values::index<L> and
189  values::value<typename std::invoke_result<const Getter&, std::size_t>::type>, int> = 0>
190  static constexpr auto
191  from_euclidean_component(const T& t, const Getter& g, const L& local_index)
192 #endif
193  {
194  using Scalar = std::decay_t<decltype(g(0_uz))>;
195  using R = std::decay_t<decltype(values::real(std::declval<Scalar>()))>;
196  const Scalar cf {numbers::pi_v<R> / (up - down)};
197  const Scalar horiz {R{up + down} * R{0.5}};
198 
199  Scalar x = g(0_uz);
200  // In Euclidean space, (the real part of) x must be non-negative since the inclination is in range [-½pi,½pi].
201  Scalar pos_x = values::internal::update_real_part(x, values::abs(values::real(x)));
202  Scalar y = g(1_uz);
203 
204  if constexpr (values::complex<Scalar>) return values::atan2(y, pos_x) / cf + horiz;
205  else { return values::atan2(y, pos_x) / cf + horiz; }
206  }
207 
208  private:
209 
210  template<typename A>
211  static constexpr std::decay_t<A> wrap_impl(A&& a)
212  {
213  auto ap = values::real(a);
214  if (ap >= down and ap <= up)
215  {
216  return std::forward<decltype(a)>(a);
217  }
218  else
219  {
220  using R = std::decay_t<decltype(ap)>;
221  constexpr R range {up - down};
222  constexpr R period {range * 2};
223  using std::fmod;
224  auto ar = fmod(ap - R{down}, period);
225 
226  if (ar < 0) return values::internal::update_real_part(std::forward<decltype(a)>(a), R{down} + ar + period);
227  else if (ar > range) return values::internal::update_real_part(std::forward<decltype(a)>(a), R{down} - ar + period);
228  else return values::internal::update_real_part(std::forward<decltype(a)>(a), R{down} + ar);
229  }
230  }
231 
232  public:
233 
237 #ifdef __cpp_concepts
238  static constexpr values::value auto
239  get_wrapped_component(const T& t, const auto& g, const values::index auto& local_index)
240  requires requires(std::size_t i){ {g(i)} -> values::value; }
241 #else
242  template<typename Getter, typename L, std::enable_if_t<values::index<L> and
243  values::value<typename std::invoke_result<const Getter&, std::size_t>::type>, int> = 0>
244  static constexpr auto
245  get_wrapped_component(const T& t, const Getter& g, const L& local_index)
246 #endif
247  {
248  return wrap_impl(g(0_uz));
249  };
250 
251 
255 #ifdef __cpp_concepts
256  static constexpr void
257  set_wrapped_component(const T& t, const auto& s, const auto& g, const values::value auto& x, const values::index auto& local_index)
258  requires requires(std::size_t i){ s(x, i); s(g(i), i); }
259 #else
260  template<typename Setter, typename Getter, typename X, typename L, std::enable_if_t<values::value<X> and values::index<L> and
261  std::is_invocable<const Setter&, const X&, std::size_t>::value and
262  std::is_invocable<const Setter&, typename std::invoke_result<const Getter&, std::size_t>::type, std::size_t>::value, int> = 0>
263  static constexpr void
264  set_wrapped_component(const T& t, const Setter& s, const Getter& g, const X& x, const L& local_index)
265 #endif
266  {
267  s(wrap_impl(x), 0_uz);
268  }
269 
270  };
271 
272 
273 } // namespace OpenKalman::interface
274 
275 
276 #endif //OPENKALMAN_COEFFICIENTS_INCLINATION_HPP
Definition for values::floating.
static constexpr auto to_euclidean_component(const T &t, const Getter &g, const L &euclidean_local_index)
Definition: Inclination.hpp:164
Definition: basics.hpp:41
A positive or negative real number φ representing an inclination or declination from the horizon...
Definition: Inclination.hpp:55
constexpr bool value
T is numerical value or is reducible to a numerical value.
Definition: value.hpp:31
constexpr auto sin(const Arg &arg)
Constexpr alternative to the std::sin function.
Definition: sin.hpp:43
constexpr auto cos(const Arg &arg, std::enable_if_t< values::value< Arg >, int >=0)
Constexpr alternative to the std::cos function.
Definition: cos.hpp:43
Definition: compares_with.hpp:28
constexpr auto fixed_number_of_v
Helper template for fixed_number_of.
Definition: fixed_number_of.hpp:84
constexpr auto atan2(const Y &y_arg, const X &x_arg)
Constexpr alternative to the std::atan2 function.
Definition: atan2.hpp:46
static constexpr auto from_euclidean_component(const T &t, const Getter &g, const L &local_index)
Definition: Inclination.hpp:191
constexpr auto real(Arg arg)
A constexpr function to obtain the real part of a (complex) number.
Definition: real.hpp:40
Traits for coordinates::pattern objects.
Definition: coordinate_descriptor_traits.hpp:41
Definition: Fixed.hpp:36
constexpr auto abs(const Arg &arg)
A constexpr alternative to std::abs.
Definition: abs.hpp:38
static constexpr void set_wrapped_component(const T &t, const Setter &s, const Getter &g, const X &x, const L &local_index)
Definition: Inclination.hpp:264
constexpr bool index
T is an index value.
Definition: index.hpp:56
static constexpr auto get_wrapped_component(const T &t, const Getter &g, const L &local_index)
Definition: Inclination.hpp:245
A matrix with typed rows and columns.
Definition: forward-class-declarations.hpp:448