AIS: message 22 returns now optional positions, depending on availability of information.
[marnav.git] / src / marnav / ais / message_22.cpp
bloba37fa44660eadc1095b64b99fb071b084d93cc50
1 #include "message_22.hpp"
2 #include <algorithm>
3 #include <cmath>
4 #include <marnav/ais/angle.hpp>
6 namespace marnav
8 namespace ais
10 MARNAV_AIS_DEFINE_MESSAGE_PARSE_FUNC(message_22)
12 message_22::message_22()
13 : message(ID)
17 message_22::message_22(const raw & bits)
18 : message(ID)
20 if (bits.size() != SIZE_BITS)
21 throw std::invalid_argument{"invalid number of bits in message_22"};
22 read_data(bits);
25 void message_22::read_data(const raw & bits)
27 get(bits, repeat_indicator);
28 get(bits, mmsi);
29 get(bits, channel_a);
30 get(bits, channel_b);
31 get(bits, txrx_mode);
32 get(bits, power);
33 get(bits, addressed);
34 get(bits, band_a);
35 get(bits, band_b);
36 get(bits, zone_size);
38 if (addressed) {
39 get(bits, mmsi_1);
40 get(bits, mmsi_2);
41 } else {
42 get(bits, ne_lon);
43 get(bits, ne_lat);
44 get(bits, sw_lon);
45 get(bits, sw_lat);
49 raw message_22::get_data() const
51 raw bits{SIZE_BITS};
53 bits.set(type(), 0, 6);
54 set(bits, repeat_indicator);
55 set(bits, mmsi);
56 set(bits, channel_a);
57 set(bits, channel_b);
58 set(bits, txrx_mode);
59 set(bits, power);
60 set(bits, addressed);
61 set(bits, band_a);
62 set(bits, band_b);
63 set(bits, zone_size);
65 if (addressed) {
66 set(bits, mmsi_1);
67 set(bits, mmsi_2);
68 } else {
69 set(bits, ne_lon);
70 set(bits, ne_lat);
71 set(bits, sw_lon);
72 set(bits, sw_lat);
75 return bits;
78 utils::optional<geo::position> message_22::get_position_ne() const
80 if ((ne_lat == latitude_not_available_short) || (ne_lon == longitude_not_available_short))
81 return utils::make_optional<geo::position>();
83 // TODO: investigate lat/lon range (lon values of 385.xxx discovered in the wild)
85 return utils::make_optional<geo::position>(
86 geo::latitude{ne_lat / (60.0 * 10.0)}, geo::longitude{ne_lon / (60.0 * 10.0)});
89 utils::optional<geo::position> message_22::get_position_sw() const
91 if ((sw_lat == latitude_not_available_short) || (sw_lon == longitude_not_available_short))
92 return utils::make_optional<geo::position>();
94 // TODO: investigate lat/lon range
96 return utils::make_optional<geo::position>(
97 geo::latitude{sw_lat / (60.0 * 10.0)}, geo::longitude{sw_lon / (60.0 * 10.0)});
100 void message_22::set_position_ne(const geo::position & t) noexcept
102 ne_lat = std::floor(60.0 * 10.0 * t.lat());
103 ne_lon = std::floor(60.0 * 10.0 * t.lon());
106 void message_22::set_position_sw(const geo::position & t) noexcept
108 sw_lat = std::floor(60.0 * 10.0 * t.lat());
109 sw_lon = std::floor(60.0 * 10.0 * t.lon());