AIS: use vessel dimension instead of individual lengths
[marnav.git] / src / marnav / ais / message_18.cpp
blob6b7d6ad5507df7a1328130e76e0cdcb3d1392289
1 #include <marnav/ais/message_18.hpp>
2 #include <marnav/ais/angle.hpp>
3 #include <cmath>
5 namespace marnav
7 namespace ais
9 constexpr message_id message_18::ID;
10 constexpr std::size_t message_18::SIZE_BITS;
12 message_18::message_18()
13 : message_18(ID)
17 message_18::message_18(message_id id)
18 : message(id)
22 message_18::message_18(const raw & bits)
23 : message_18(ID)
25 if (bits.size() != SIZE_BITS)
26 throw std::invalid_argument{"invalid number of bits in message_18"};
27 read_data(bits);
30 void message_18::read_data(const raw & bits)
32 get(bits, repeat_indicator);
33 get(bits, mmsi);
34 get(bits, sog);
35 get(bits, position_accuracy);
36 get(bits, longitude_minutes);
37 get(bits, latitude_minutes);
38 get(bits, cog);
39 get(bits, hdg);
40 get(bits, timestamp);
41 get(bits, cs_unit);
42 get(bits, display_flag);
43 get(bits, dsc_flag);
44 get(bits, band_flag);
45 get(bits, message_22_flag);
46 get(bits, assigned);
47 get(bits, raim);
48 get(bits, radio_status);
51 raw message_18::get_data() const
53 raw bits(SIZE_BITS);
55 bits.set(type(), 0, 6);
56 set(bits, repeat_indicator);
57 set(bits, mmsi);
58 set(bits, sog);
59 set(bits, position_accuracy);
60 set(bits, longitude_minutes);
61 set(bits, latitude_minutes);
62 set(bits, cog);
63 set(bits, hdg);
64 set(bits, timestamp);
65 set(bits, cs_unit);
66 set(bits, display_flag);
67 set(bits, dsc_flag);
68 set(bits, band_flag);
69 set(bits, message_22_flag);
70 set(bits, assigned);
71 set(bits, raim);
72 set(bits, radio_status);
74 return bits;
77 utils::optional<geo::longitude> message_18::get_lon() const
79 if (longitude_minutes == longitude_not_available)
80 return utils::make_optional<geo::longitude>();
81 return to_geo_longitude(longitude_minutes, longitude_minutes.count, angle_scale::I4);
84 utils::optional<geo::latitude> message_18::get_lat() const
86 if (latitude_minutes == latitude_not_available)
87 return utils::make_optional<geo::latitude>();
88 return to_geo_latitude(latitude_minutes, latitude_minutes.count, angle_scale::I4);
91 void message_18::set_lon_unavailable()
93 longitude_minutes = longitude_not_available;
96 void message_18::set_lat_unavailable()
98 latitude_minutes = latitude_not_available;
101 void message_18::set_lon(const geo::longitude & t)
103 longitude_minutes = to_longitude_minutes(t, longitude_minutes.count, angle_scale::I4);
106 void message_18::set_lat(const geo::latitude & t)
108 latitude_minutes = to_latitude_minutes(t, latitude_minutes.count, angle_scale::I4);
111 utils::optional<units::knots> message_18::get_sog() const noexcept
113 // ignores special value of 1022 = 102.2 knots or faster
115 if (sog == sog_not_available)
116 return {};
117 return units::knots{0.1 * sog};
120 void message_18::set_sog_unavailable()
122 sog = sog_not_available;
125 void message_18::set_sog(units::velocity t)
127 if (t.value() < 0.0)
128 throw std::invalid_argument{"SOG less than zero"};
130 const auto v = t.get<units::knots>();
131 sog = std::min(sog_max, static_cast<uint32_t>(round(v * 10).value()));
134 /// Returns course over ground in degrees true north.
135 utils::optional<double> message_18::get_cog() const noexcept
137 if (cog == cog_not_available)
138 return {};
139 return 0.1 * cog;
142 void message_18::set_cog(utils::optional<double> t) noexcept
144 cog = !t ? cog_not_available : static_cast<uint32_t>(std::round(*t / 0.1));
147 /// Returns heading in degrees.
148 utils::optional<uint32_t> message_18::get_hdg() const noexcept
150 if (hdg == hdg_not_available)
151 return {};
152 return {hdg};
155 void message_18::set_hdg(utils::optional<uint32_t> t) noexcept
157 hdg = !t ? hdg_not_available : *t;