src/libais/ais8_366_22.cpp
// Defined sort of by Nav55, but being tweaked by the USCG and
// will hopefully become a RTCM standard. Also hoping that this
// will be harmonized with the IMO Circ 289.
#include <cmath>
#include <string>
#include "ais.h"
namespace libais {
const char *shape_names[8] = {"Circle/Pt", "Rect", "Sector", "Polyline",
"Polygon", "Text", "Reserved_6", "Reserved_7"};
const char *ais8_366_22_notice_names[AIS8_366_22_NUM_NAMES] = {
"Caution Area: Marine mammals habitat (no whales obs)", // 0
"Caution Area: Marine mammals in area – reduce speed", // 1
"Caution Area: Marine mammals in area – stay clear", // 2
"Caution Area: Marine mammals in area – report sightings", // 3
"Caution Area: Protected habitat – reduce speed", // 4
"Caution Area: Protected habitat – stay clear", // 5
"Caution Area: Protected habitat – no fishing or anchoring", // 6
"Caution Area: Derelicts (drifting objects)", // 7
"Caution Area: Traffic congestion", // 8
"Caution Area: Marine event", // 9
"Caution Area: Divers down", // 10
"Caution Area: Swim area", // 11
"Caution Area: Dredge operations", // 12
"Caution Area: Survey operations", // 13
"Caution Area: Underwater operation", // 14
"Caution Area: Seaplane operations", // 15
"Caution Area: Fishery – nets in water", // 16
"Caution Area: Cluster of fishing vessels", // 17
"Caution Area: Fairway closed", // 18
"Caution Area: Harbour closed", // 19
"Caution Area: Risk (define in Associated text field)", // 20
"Caution Area: Underwater vehicle operation", // 21
"(reserved for future use)", // 22
"Environmental Caution Area: Storm front (line squall)", // 23
"Environmental Caution Area: Hazardous sea ice", // 24
"Environmental Caution Area: Storm warning (cell or line of storms)", // 25
"Environmental Caution Area: High wind", // 26
"Environmental Caution Area: High waves", // 27
"Environmental Caution Area: Restricted visibility (fog, rain, etc.)", // 28
"Environmental Caution Area: Strong currents", // 29
"Environmental Caution Area: Heavy icing", // 30
"(reserved for future use)", // 31
"Restricted Area: Fishing prohibited", // 32
"Restricted Area: No anchoring.", // 33
"Restricted Area: Entry approval required prior to transit", // 34
"Restricted Area: Entry prohibited", // 35
"Restricted Area: Active military OPAREA", // 36
"Restricted Area: Firing – danger area.", // 37
"Restricted Area: Drifting Mines", // 38
"(reserved for future use)", // 39
"Anchorage Area: Anchorage open", // 40
"Anchorage Area: Anchorage closed", // 41
"Anchorage Area: Anchoring prohibited", // 42
"Anchorage Area: Deep draft anchorage", // 43
"Anchorage Area: Shallow draft anchorage", // 44
"Anchorage Area: Vessel transfer operations", // 45
"(reserved for future use)", // 46
"(reserved for future use)", // 47
"(reserved for future use)", // 48
"(reserved for future use)", // 49
"(reserved for future use)", // 50
"(reserved for future use)", // 51
"(reserved for future use)", // 52
"(reserved for future use)", // 53
"(reserved for future use)", // 54
"(reserved for future use)", // 55
"Security Alert – Level 1", // 56
"Security Alert – Level 2", // 57
"Security Alert – Level 3", // 58
"(reserved for future use)", // 59
"(reserved for future use)", // 60
"(reserved for future use)", // 61
"(reserved for future use)", // 62
"(reserved for future use)", // 63
"Distress Area: Vessel disabled and adrift", // 64
"Distress Area: Vessel sinking", // 65
"Distress Area: Vessel abandoning ship", // 66
"Distress Area: Vessel requests medical assistance", // 67
"Distress Area: Vessel flooding", // 68
"Distress Area: Vessel fire/explosion", // 69
"Distress Area: Vessel grounding", // 70
"Distress Area: Vessel collision", // 71
"Distress Area: Vessel listing/capsizing", // 72
"Distress Area: Vessel under assault", // 73
"Distress Area: Person overboard", // 74
"Distress Area: SAR area", // 75
"Distress Area: Pollution response area", // 76
"(reserved for future use)", // 77
"(reserved for future use)", // 78
"(reserved for future use)", // 79
"Instruction: Contact VTS at this point/juncture", // 80
"Instruction: Contact Port Administration at this point/juncture", // 81
"Instruction: Do not proceed beyond this point/juncture", // 82
"Instruction: Await instructions prior to proceeding beyond "
"this point/juncture", // 83
"Proceed to this location – await instructions", // 84
"Clearance granted – proceed to berth", // 85
"(reserved for future use)", // 86
"(reserved for future use)", // 87
"Information: Pilot boarding position", // 88
"Information: Icebreaker waiting area", // 89
"Information: Places of refuge", // 90
"Information: Position of icebreakers", // 91
"Information: Location of response units", // 92
"VTS active target", // 93
"Rogue or suspicious vessel", // 94
"Vessel requesting non-distress assistance", // 95
"Chart Feature: Sunken vessel", // 96
"Chart Feature: Submerged object", // 97
"Chart Feature: Semi-submerged object", // 98
"Chart Feature: Shoal area", // 99
"Chart Feature: Shoal area due north", // 100
"Chart Feature: Shoal area due east", // 101
"Chart Feature: Shoal area due south", // 102
"Chart Feature: Shoal area due west", // 103
"Chart Feature: Channel obstruction", // 104
"Chart Feature: Reduced vertical clearance", // 105
"Chart Feature: Bridge closed", // 106
"Chart Feature: Bridge partially open", // 107
"Chart Feature: Bridge fully open", // 108
"(reserved for future use)", // 109
"(reserved for future use)", // 110
"(reserved for future use)", // 111
"Report from ship: Icing info", // 112
"(reserved for future use)", // 113
"Report from ship: Misc information - see associated text field", // 114
"(reserved for future use)", // 115
"(reserved for future use)", // 116
"(reserved for future use)", // 117
"(reserved for future use)", // 118
"(reserved for future use)", // 119
"Route: Recommended route", // 120
"Route: Alternative route", // 121
"Route: Recommended route through ice", // 122
"(reserved for future use)", // 123
"(reserved for future use)", // 124
"Other – Define in associated text field", // 125
"Cancellation – cancel area as identified by Message Linkage ID", // 126
"Undefined (default)" // 127
};
Ais8_366_22::Ais8_366_22(const char *nmea_payload, const size_t pad)
: Ais8(nmea_payload, pad), link_id(0), notice_type(0), month(0), day(0),
utc_hour(0), utc_minute(0), duration_minutes(0) {
assert(dac == 366);
assert(fi == 22);
if (!CheckStatus()) {
return;
}
if (num_bits <= 208 || num_bits >= 1020) {
status = AIS_ERR_BAD_BIT_COUNT;
return;
}
link_id = bits.ToUnsignedInt(56, 10);
notice_type = bits.ToUnsignedInt(66, 7);
month = bits.ToUnsignedInt(73, 4);
day = bits.ToUnsignedInt(77, 5);
utc_hour = bits.ToUnsignedInt(82, 5);
utc_minute = bits.ToUnsignedInt(87, 6);
duration_minutes = bits.ToUnsignedInt(93, 18);
const int num_sub_areas = static_cast<int>(floor((num_bits - 111)/90.));
for (int area_idx = 0; area_idx < num_sub_areas; area_idx++) {
std::unique_ptr<Ais8_366_22_SubArea> area =
ais8_366_22_subarea_factory(bits, 111 + 90*area_idx);
if (area) {
sub_areas.push_back(std::move(area));
} else {
status = AIS_ERR_BAD_SUB_SUB_MSG;
return;
}
}
assert(bits.GetRemaining() == 0);
status = AIS_OK;
}
// Lookup table for the scale factors to decode the length / distance fields.
// The index is the "Scale Factor"
static int scale_multipliers[4] = {1, 10, 100, 1000};
Ais8_366_22_Circle::Ais8_366_22_Circle(const AisBitset &bits,
const size_t offset) {
const int scale_factor = bits.ToUnsignedInt(offset + 3, 2);
position = bits.ToAisPoint(offset + 5, 55);
// TODO(schwehr): precision? And bit counts for radius and spare?
// TODO(schwehr): collapse these numbers
radius_m =
bits.ToUnsignedInt(offset + 60, 12) * scale_multipliers[scale_factor];
spare = bits.ToUnsignedInt(offset + 72, 16);
}
Ais8_366_22_Rect::Ais8_366_22_Rect(const AisBitset &bits,
const size_t offset) {
const int scale_factor = bits.ToUnsignedInt(offset + 3, 2);
position = bits.ToAisPoint(offset + 5, 55);
e_dim_m =
bits.ToUnsignedInt(offset + 60, 8) * scale_multipliers[scale_factor];
n_dim_m =
bits.ToUnsignedInt(offset + 68, 8) * scale_multipliers[scale_factor];
orient_deg = bits.ToUnsignedInt(offset + 76, 9);
spare = bits.ToUnsignedInt(offset + 85, 5);
}
Ais8_366_22_Sector::Ais8_366_22_Sector(const AisBitset &bits,
const size_t offset) {
const int scale_factor = bits.ToUnsignedInt(offset + 3, 2);
position = bits.ToAisPoint(offset + 5, 55);
radius_m =
bits.ToUnsignedInt(offset + 60, 12) * scale_multipliers[scale_factor];
left_bound_deg = bits.ToUnsignedInt(offset + 72, 9);
right_bound_deg = bits.ToUnsignedInt(offset + 81, 9);
}
Ais8_366_22_Polyline::Ais8_366_22_Polyline(const AisBitset &bits,
const size_t offset) {
const int scale_factor = bits.ToUnsignedInt(offset + 3, 2);
for (size_t i = 0; i < 4; i++) {
const int angle = bits.ToUnsignedInt(offset + 5 + (i*21), 10);
const int dist = bits.ToUnsignedInt(offset + 15 + (i*21), 11) *
scale_multipliers[scale_factor];
if (dist == 0) {
break;
}
angles.push_back(angle);
dists_m.push_back(dist);
}
spare = bits[offset + 89];
}
// TODO(schwehr): Merge with Polyline.
Ais8_366_22_Polygon::Ais8_366_22_Polygon(const AisBitset &bits,
const size_t offset) {
const int scale_factor = bits.ToUnsignedInt(offset + 3, 2);
for (size_t i = 0; i < 4; i++) {
const int angle = bits.ToUnsignedInt(offset + 5 + (i*21), 10);
const int dist = bits.ToUnsignedInt(offset + 15 + (i*21), 11) *
scale_multipliers[scale_factor];
if (dist == 0) {
break;
}
angles.push_back(angle);
dists_m.push_back(dist);
}
spare = bits[offset + 89];
}
Ais8_366_22_Text::Ais8_366_22_Text(const AisBitset &bits,
const size_t offset) {
text = std::string(bits.ToString(offset + 3, 84));
spare = bits.ToUnsignedInt(offset + 87, 3);
}
// Call the appropriate constructor
std::unique_ptr<Ais8_366_22_SubArea>
ais8_366_22_subarea_factory(const AisBitset &bits,
const size_t offset) {
const Ais8_366_22_AreaShapeEnum area_shape =
(Ais8_366_22_AreaShapeEnum)bits.ToUnsignedInt(offset, 3);
switch (area_shape) {
case AIS8_366_22_SHAPE_CIRCLE:
return std::unique_ptr<Ais8_366_22_SubArea>(new Ais8_366_22_Circle(bits, offset));
case AIS8_366_22_SHAPE_RECT:
return std::unique_ptr<Ais8_366_22_SubArea>(new Ais8_366_22_Rect(bits, offset));
case AIS8_366_22_SHAPE_SECTOR:
return std::unique_ptr<Ais8_366_22_SubArea>(new Ais8_366_22_Sector(bits, offset));
case AIS8_366_22_SHAPE_POLYLINE:
return std::unique_ptr<Ais8_366_22_SubArea>(new Ais8_366_22_Polyline(bits, offset));
case AIS8_366_22_SHAPE_POLYGON:
return std::unique_ptr<Ais8_366_22_SubArea>(new Ais8_366_22_Polygon(bits, offset));
case AIS8_366_22_SHAPE_TEXT:
return std::unique_ptr<Ais8_366_22_SubArea>(new Ais8_366_22_Text(bits, offset));
case AIS8_366_22_SHAPE_RESERVED_6: // FALLTHROUGH
case AIS8_366_22_SHAPE_RESERVED_7: // FALLTHROUGH
// Leave area as 0 to indicate error
break;
case AIS8_366_22_SHAPE_ERROR:
break;
default:
assert(false);
}
return {};
}
} // namespace libais