1#include <vanetza/common/serialization.hpp>
2#include <vanetza/security/exception.hpp>
3#include <vanetza/security/v2/region.hpp>
4#include <vanetza/units/angle.hpp>
5#include <vanetza/units/length.hpp>
6#include <boost/algorithm/clamp.hpp>
7#include <boost/units/cmath.hpp>
8#include <boost/variant/static_visitor.hpp>
9#include <boost/variant/apply_visitor.hpp>
10#include <GeographicLib/Geodesic.hpp>
20const ThreeDLocation::Elevation ThreeDLocation::unknown_elevation {{ 0xF0, 0x00 }};
21const ThreeDLocation::Elevation ThreeDLocation::min_elevation {{ 0xF0, 0x01 }};
22const ThreeDLocation::Elevation ThreeDLocation::max_elevation {{ 0xEF, 0xFF }};
26 struct geograpical_region_visitor :
public boost::static_visitor<RegionType>
28 RegionType operator()(NoneRegion reg)
30 return RegionType::None;
34 return RegionType::Circle;
36 RegionType operator()(std::list<RectangularRegion> reg)
38 return RegionType::Rectangle;
42 return RegionType::Polygon;
46 return RegionType::ID;
50 geograpical_region_visitor visit;
51 return boost::apply_visitor(visit, reg);
54bool TwoDLocation::operator==(
const TwoDLocation& other)
const
56 return this->latitude == other.latitude && this->longitude == other.longitude;
59bool TwoDLocation::operator!=(
const TwoDLocation& other)
const
61 return !(*
this == other);
66 return this->latitude == other.latitude && this->longitude == other.longitude && this->elevation == other.elevation;
71 return !(*
this == other);
74bool NoneRegion::operator==(
const NoneRegion& other)
const
79bool NoneRegion::operator!=(
const NoneRegion& other)
const
81 return !(*
this == other);
86 return this->center == other.center && this->radius == other.radius;
91 return !(*
this == other);
96 return this->northwest == other.northwest && this->southeast == other.southeast;
101 return !(*
this == other);
106 return this->region_dictionary == other.region_dictionary
107 && this->region_identifier == other.region_identifier
108 && this->local_region == other.local_region;
113 return !(*
this == other);
119 size +=
sizeof(loc.latitude);
120 size +=
sizeof(loc.longitude);
127 size +=
sizeof(loc.latitude);
128 size +=
sizeof(loc.longitude);
129 size += loc.elevation.size();
136 size += get_size(reg.center);
137 size +=
sizeof(reg.radius);
144 size += get_size(reg.northwest);
145 size += get_size(reg.southeast);
149size_t get_size(
const std::list<CircularRegion>& list)
152 for (
auto& circularRegion : list) {
153 size += get_size(circularRegion.center);
154 size +=
sizeof(circularRegion.radius);
159size_t get_size(
const std::list<RectangularRegion>& list)
162 for (
auto& rectangularRegion : list) {
163 size += get_size(rectangularRegion.northwest);
164 size += get_size(rectangularRegion.southeast);
172 for (
auto& twoDLocation : reg) {
173 size +=
sizeof(twoDLocation.latitude);
174 size +=
sizeof(twoDLocation.longitude);
182 size +=
sizeof(reg.region_dictionary);
183 size +=
sizeof(reg.region_identifier);
184 size += get_size(reg.local_region);
190 size_t size =
sizeof(RegionType);
192 struct geograpical_region_visitor :
public boost::static_visitor<>
194 void operator()(NoneRegion reg)
200 m_size = get_size(reg);
202 void operator()(std::list<RectangularRegion> reg)
204 m_size = get_size(reg);
205 m_size += length_coding_size(m_size);
209 m_size = get_size(reg);
210 m_size += length_coding_size(m_size);
214 m_size = get_size(reg);
219 geograpical_region_visitor visit;
220 boost::apply_visitor(visit, reg);
221 size += visit.m_size;
225void serialize(OutputArchive& ar,
const TwoDLocation& loc)
227 serialize(ar, loc.latitude);
228 serialize(ar, loc.longitude);
233 serialize(ar, loc.latitude);
234 serialize(ar, loc.longitude);
235 ar << loc.elevation[0];
236 ar << loc.elevation[1];
241 serialize(ar, reg.center);
242 serialize(ar, reg.radius);
247 serialize(ar, reg.northwest);
248 serialize(ar, reg.southeast);
251void serialize(OutputArchive& ar,
const std::list<RectangularRegion>& list)
254 size = get_size(list);
255 serialize_length(ar, size);
256 for (
auto& rectangularRegion : list) {
257 serialize(ar, rectangularRegion);
264 size = get_size(reg);
265 serialize_length(ar, size);
266 for (
auto& twoDLocation : reg) {
267 serialize(ar, twoDLocation);
273 serialize(ar, reg.region_dictionary);
274 serialize(ar, host_cast(reg.region_identifier));
275 serialize(ar, reg.local_region);
280 struct geograpical_region_visitor :
public boost::static_visitor<>
282 geograpical_region_visitor(OutputArchive& ar) :
286 void operator()(NoneRegion reg)
292 serialize(m_archive, reg);
294 void operator()(std::list<RectangularRegion> reg)
296 serialize(m_archive, reg);
300 serialize(m_archive, reg);
304 serialize(m_archive, reg);
306 OutputArchive& m_archive;
309 RegionType type = get_type(reg);
311 geograpical_region_visitor visit(ar);
312 boost::apply_visitor(visit, reg);
317 deserialize(ar, loc.latitude);
318 deserialize(ar, loc.longitude);
319 return get_size(loc);
324 deserialize(ar, loc.latitude);
325 deserialize(ar, loc.longitude);
326 ar >> loc.elevation[0];
327 ar >> loc.elevation[1];
328 return get_size(loc);
334 size += deserialize(ar, reg.center);
335 deserialize(ar, reg.radius);
336 size +=
sizeof(reg.radius);
340size_t deserialize(InputArchive& ar, std::list<RectangularRegion>& list)
342 size_t size, ret_size;
343 size = deserialize_length(ar);
347 size -= deserialize(ar, reg.northwest);
348 size -= deserialize(ar, reg.southeast);
356 size_t size, ret_size;
357 size = deserialize_length(ar);
361 size -= deserialize(ar, loc);
370 deserialize(ar, reg.region_dictionary);
371 size +=
sizeof(RegionDictionary);
372 deserialize(ar, reg.region_identifier);
373 size +=
sizeof(reg.region_identifier);
374 deserialize(ar, reg.local_region);
375 size += get_size(reg.local_region);
382 deserialize(ar, type);
383 size_t size =
sizeof(RegionType);
385 case RegionType::None:
389 case RegionType::Circle: {
391 size += deserialize(ar, circle);
395 case RegionType::Rectangle: {
396 std::list<RectangularRegion> list;
397 size += deserialize(ar, list);
398 size += length_coding_size(size);
402 case RegionType::Polygon: {
404 size += deserialize(ar, polygon);
405 size += length_coding_size(size);
409 case RegionType::ID: {
411 size += deserialize(ar,
id);
416 throw deserialization_error(
"Unknown RegionType");
425 struct geograpical_region_visitor :
public boost::static_visitor<bool>
427 geograpical_region_visitor(
const TwoDLocation& position) :
431 bool operator()(
const NoneRegion& reg)
437 return is_within(m_position, reg);
439 bool operator()(
const std::list<RectangularRegion>& reg)
441 return is_within(m_position, reg);
445 return is_within(m_position, reg);
449 return is_within(m_position, reg);
454 geograpical_region_visitor visit(position);
455 return boost::apply_visitor(visit, reg);
460 const auto& geod = GeographicLib::Geodesic::WGS84();
462 const units::GeoAngle pos_lat { position.latitude };
463 const units::GeoAngle pos_lon { position.longitude };
464 const units::GeoAngle center_lat { circular.center.latitude };
465 const units::GeoAngle center_lon { circular.center.longitude };
466 geod.Inverse(pos_lat / units::degree, pos_lon / units::degree,
467 center_lat / units::degree, center_lon / units::degree, dist);
468 return dist <= circular.radius / units::si::meter;
471bool is_within(
const TwoDLocation& position,
const std::list<RectangularRegion>& rectangles)
473 static const unsigned max_rectangles = 6;
475 if (rectangles.size() > max_rectangles) {
479 return std::any_of(rectangles.begin(), rectangles.end(),
480 [&position](
const RectangularRegion& rect) { return is_within(position, rect); });
488 if (rectangle.northwest.latitude <= rectangle.southeast.latitude) {
490 }
else if (rectangle.northwest.longitude >= rectangle.southeast.longitude) {
494 if (rectangle.northwest.latitude < position.latitude) {
496 }
else if (rectangle.northwest.longitude > position.longitude) {
498 }
else if (rectangle.southeast.latitude > position.latitude) {
500 }
else if (rectangle.southeast.longitude < position.longitude) {
521 struct outer_geograpical_region_visitor :
public boost::static_visitor<bool>
527 bool operator()(
const NoneRegion& outer)
533 return is_within(inner, outer);
535 bool operator()(
const std::list<RectangularRegion>& outer)
537 return is_within(inner, outer);
541 return is_within(inner, outer);
545 return is_within(inner, outer);
550 outer_geograpical_region_visitor visit(inner);
551 return boost::apply_visitor(visit, outer);
556 struct inner_geograpical_region_visitor :
public boost::static_visitor<bool>
562 bool operator()(
const NoneRegion& inner)
568 if (inner == outer) {
572 const auto& geod = GeographicLib::Geodesic::WGS84();
573 double center_dist = 0.0;
574 const units::GeoAngle inner_lat { inner.center.latitude };
575 const units::GeoAngle inner_long { inner.center.longitude };
576 const units::GeoAngle outer_lat { outer.center.latitude };
577 const units::GeoAngle outer_long { outer.center.longitude };
578 geod.Inverse(inner_lat / units::degree, inner_long / units::degree,
579 outer_lat / units::degree, outer_long / units::degree, center_dist);
580 return center_dist + inner.radius / units::si::meter <= outer.radius / units::si::meter;
582 bool operator()(
const std::list<RectangularRegion>& inner)
613 inner_geograpical_region_visitor visit(outer);
614 return boost::apply_visitor(visit, inner);
617bool is_within(
const GeographicRegion& inner,
const std::list<RectangularRegion>& outer)
624 struct inner_geograpical_region_visitor :
public boost::static_visitor<bool>
626 inner_geograpical_region_visitor(
const std::list<RectangularRegion>& outer) :
630 bool operator()(
const NoneRegion& inner)
639 bool operator()(
const std::list<RectangularRegion>& inner)
641 if (inner == outer) {
658 const std::list<RectangularRegion>& outer;
661 inner_geograpical_region_visitor visit(outer);
662 return boost::apply_visitor(visit, inner);
678ThreeDLocation::Elevation to_elevation(units::Length altitude)
680 using boost::units::isnan;
683 ThreeDLocation::Elevation elevation { ThreeDLocation::unknown_elevation };
685 if (!isnan(altitude)) {
686 using boost::algorithm::clamp;
689 double altitude_dm = std::round(10.0 * (altitude / vanetza::units::si::meter));
690 if (altitude_dm >= 0.0) {
691 altitude_dm = clamp(altitude_dm, 0.0, 61439.0);
692 auto altitude_int =
static_cast<std::uint16_t
>(altitude_dm);
693 elevation[0] = altitude_int >> 8;
694 elevation[1] = altitude_int & 0xFF;
696 altitude_dm = clamp(altitude_dm, -4095.0, -1.0);
697 auto altitude_int =
static_cast<std::int16_t
>(altitude_dm);
698 elevation[0] = altitude_int >> 8 | 0xF0;
699 elevation[1] = altitude_int & 0xFF;