General: reorganization of header files
[marnav.git] / src / marnav / ais / angle.cpp
blob26ecac8d1075fdd200f45c8330323a5928d6172b
1 #include <marnav/ais/angle.hpp>
2 #include <limits>
3 #include <cmath>
4 #include <cassert>
6 namespace marnav
8 namespace ais
10 /// @cond DEV
11 namespace
13 /// Returns the numeric scale for the specified enumeration.
14 static double scale_value(angle_scale scale)
16 switch (scale) {
17 case angle_scale::I1:
18 return 10.0;
19 case angle_scale::I3:
20 return 1000.0;
21 case angle_scale::I4:
22 return 10000.0;
24 return 1.0;
27 /// Converts the specified value into an angle (unit: degrees) according
28 /// to the encoded angle in AIS messages. The specified value is a signed value.
29 ///
30 /// This conversion function is suitable for both, latitudes and longitudes.
31 ///
32 /// @param[in] value The value from the AIS message to convert.
33 /// @param[in] bits Number of bits of information.
34 /// @param[in] scale Angle scaling.
35 /// @return The converted angle, positive and negative values possible.
36 static double deg_from(uint32_t value, std::size_t bits, angle_scale scale)
38 assert(bits > 0);
39 assert(bits < 33);
41 const uint32_t t = 1u << (bits - 1);
42 if (value & t) {
43 // treat negative values
44 uint32_t mask = std::numeric_limits<uint32_t>::max();
45 mask <<= bits;
46 value |= mask;
48 return (1.0 / (60.0 * scale_value(scale))) * static_cast<int32_t>(value);
51 /// Converts angles in degrees to I4 values, used in AIS messages.
52 ///
53 /// This conversion function is suitable for both, latitudes and longitudes.
54 ///
55 /// @param[in] value The angle to convert, may be positive or negative.
56 /// @param[in] bits Number of bits of information in the AIS message.
57 /// @param[in] scale Angle scaling.
58 /// @return The converted angle to be used in AIS messages.
59 static uint32_t deg_to(double value, std::size_t bits, angle_scale scale)
61 assert(bits > 0);
62 assert(bits < 33);
64 uint32_t mask = std::numeric_limits<uint32_t>::max();
65 mask <<= bits;
66 return static_cast<uint32_t>(floor((60.0 * scale_value(scale)) * value)) & ~mask;
69 // used only with static constant values, therefore compile time computation.
70 template <unsigned int n> double exp_10()
72 return 10.0 * exp_10<n - 1>();
74 template <> double exp_10<0>()
76 return 1.0;
79 template <unsigned int n> double round_n(double value)
81 const double factor = exp_10<n>();
82 return std::round(value * factor) / factor;
85 /// @endcond
87 /// Convertes the specified value (commin in AIS data) to latitude.
88 marnav::geo::latitude to_geo_latitude(
89 uint32_t latitude_minutes, std::size_t bits, angle_scale scale)
91 return geo::latitude{round_n<6>(deg_from(latitude_minutes, bits, scale))};
94 /// Converts a latitude to latitude minutes, which is commonly used in AIS data.
95 uint32_t to_latitude_minutes(
96 const marnav::geo::latitude & lat, std::size_t bits, angle_scale scale)
98 return deg_to(lat.get(), bits, scale);
101 /// Convertes the specified value (commin in AIS data) to longitude.
102 marnav::geo::longitude to_geo_longitude(
103 uint32_t longitude_minutes, std::size_t bits, angle_scale scale)
105 return geo::longitude{round_n<6>(deg_from(longitude_minutes, bits, scale))};
108 /// Converts a longitude to longitude minutes, which is commonly used in AIS data.
109 uint32_t to_longitude_minutes(
110 const marnav::geo::longitude & lon, std::size_t bits, angle_scale scale)
112 return deg_to(lon.get(), bits, scale);