NMEA: changed interface of sentences containing position information.
[marnav.git] / src / marnav / geo / angle.cpp
blobf175730f0950d703fc1af4d99c5b48dd8e29f582
1 #include "angle.hpp"
2 #include <algorithm>
3 #include <stdexcept>
4 #include <cmath>
5 #include <marnav/math/floatingpoint.hpp>
7 namespace marnav
9 namespace geo
11 /// Returns the degrees of this angle. This value is always positive.
12 uint32_t angle::degrees() const noexcept
14 auto a = std::abs(get());
15 a = std::floor(a);
16 return static_cast<uint32_t>(a);
19 /// Returns the minutes of this angle. This value is always positive
20 /// and is between 0 and 59.
21 uint32_t angle::minutes() const noexcept
23 auto a = std::abs(get());
24 a -= std::floor(a);
25 a *= 60.0;
26 a += epsilon;
27 return static_cast<uint32_t>(a);
30 /// Returns the seconds of this angle.
31 double angle::seconds() const noexcept
33 auto a = std::abs(get());
34 a -= std::floor(a);
35 a *= 60.0;
36 a += epsilon;
37 a -= std::floor(a);
38 a *= 60.0;
39 return a;
42 void swap(angle & a, angle & b) noexcept { std::swap(a.value, b.value); }
44 bool operator==(const angle & a, const angle & b) noexcept
46 return (&a == &b) || math::is_same(a.value, b.value, angle::epsilon);
49 bool operator!=(const angle & a, const angle & b) noexcept { return !(a == b); }
51 /// Constructs a latitude with the specified angle in degrees.
52 latitude::latitude(double deg)
53 : angle(deg)
55 check(get());
58 /// Initializes the object with the specified angle.
59 /// Corrects the stored value according to the specified hemisphere.
60 ///
61 /// @param[in] degrees Angle in degrees.
62 /// @param[in] h Hemisphere
63 latitude::latitude(double degrees, hemisphere h)
64 : angle(degrees)
66 check(get());
68 switch (h) {
69 case hemisphere::north:
70 if (hem() == hemisphere::south)
71 set(-get());
72 break;
73 case hemisphere::south:
74 if (hem() == hemisphere::north)
75 set(-get());
76 break;
80 latitude::latitude(uint32_t d, uint32_t m, uint32_t s, hemisphere h)
81 : angle((static_cast<double>(d) + static_cast<double>(m) / 60.0
82 + static_cast<double>(s) / 3600.0)
83 * ((h == hemisphere::south) ? -1.0 : 1.0))
85 check(get());
88 bool operator==(const latitude & a, const latitude & b) noexcept
90 return (&a == &b) || math::is_same(a.get(), b.get(), angle::epsilon);
93 bool operator!=(const latitude & a, const latitude & b) noexcept { return !(a == b); }
95 void latitude::check(double a)
97 if ((a < min) || (a > max))
98 throw std::invalid_argument{"invalid value for nmea::latitude"};
101 std::string to_string(latitude::hemisphere h)
103 switch (h) {
104 case latitude::hemisphere::north:
105 return "N";
106 case latitude::hemisphere::south:
107 return "S";
109 return "?";
112 /// Constructs a longitude with the specified angle in degrees.
113 longitude::longitude(double deg)
114 : angle(deg)
116 check(get());
119 /// Initializes the object with the specified angle.
120 /// Corrects the stored value according to the specified hemisphere.
122 /// @param[in] degrees Angle in degrees.
123 /// @param[in] h Hemisphere
124 longitude::longitude(double degrees, hemisphere h)
125 : angle(degrees)
127 check(get());
129 switch (h) {
130 case hemisphere::east:
131 if (hem() == hemisphere::west)
132 set(-get());
133 break;
134 case hemisphere::west:
135 if (hem() == hemisphere::east)
136 set(-get());
137 break;
141 longitude::longitude(uint32_t d, uint32_t m, uint32_t s, hemisphere h)
142 : angle((static_cast<double>(d) + static_cast<double>(m) / 60.0
143 + static_cast<double>(s) / 3600.0)
144 * ((h == hemisphere::east) ? +1.0 : -1.0))
146 check(get());
149 bool operator==(const longitude & a, const longitude & b) noexcept
151 return (&a == &b) || math::is_same(a.get(), b.get(), angle::epsilon);
154 bool operator!=(const longitude & a, const longitude & b) noexcept { return !(a == b); }
156 void longitude::check(double a)
158 if ((a < min) || (a > max))
159 throw std::invalid_argument{"invalid value for nmea::longitude"};
162 std::string to_string(longitude::hemisphere h)
164 switch (h) {
165 case longitude::hemisphere::east:
166 return "E";
167 case longitude::hemisphere::west:
168 return "W";
170 return "?";