1#include <vanetza/common/annotation.hpp>
2#include <vanetza/common/serialization.hpp>
3#include <vanetza/security/exception.hpp>
4#include <vanetza/security/v2/region.hpp>
5#include <vanetza/units/angle.hpp>
6#include <vanetza/units/length.hpp>
7#include <boost/algorithm/clamp.hpp>
8#include <boost/units/cmath.hpp>
9#include <boost/variant/static_visitor.hpp>
10#include <boost/variant/apply_visitor.hpp>
11#include <GeographicLib/Geodesic.hpp>
25RegionType get_type(
const GeographicRegion& reg)
27 struct geograpical_region_visitor :
public boost::static_visitor<RegionType>
31 return RegionType::None;
36 return RegionType::Circle;
39 RegionType operator()(
const std::list<RectangularRegion>&)
41 return RegionType::Rectangle;
44 RegionType operator()(
const PolygonalRegion&)
46 return RegionType::Polygon;
51 return RegionType::ID;
55 geograpical_region_visitor visit;
56 return boost::apply_visitor(visit, reg);
61 return this->latitude == other.latitude &&
this->longitude == other.longitude;
66 return !(*
this == other);
71 return this->latitude == other.latitude &&
this->longitude == other.longitude &&
this->elevation == other.elevation;
76 return !(*
this == other);
86 return !(*
this == other);
91 return this->center == other.center &&
this->radius == other.radius;
96 return !(*
this == other);
101 return this->northwest == other.northwest &&
this->southeast == other.southeast;
106 return !(*
this == other);
111 return this->region_dictionary == other.region_dictionary
112 &&
this->region_identifier == other.region_identifier
113 &&
this->local_region == other.local_region;
118 return !(*
this == other);
124 size +=
sizeof(loc.latitude);
125 size +=
sizeof(loc.longitude);
132 size +=
sizeof(loc.latitude);
133 size +=
sizeof(loc.longitude);
134 size += loc.elevation.size();
141 size += get_size(reg.center);
142 size +=
sizeof(reg.radius);
149 size += get_size(reg.northwest);
150 size += get_size(reg.southeast);
154size_t get_size(
const std::list<CircularRegion>& list)
157 for (
auto& circularRegion : list) {
158 size += get_size(circularRegion.center);
159 size +=
sizeof(circularRegion.radius);
164size_t get_size(
const std::list<RectangularRegion>& list)
167 for (
auto& rectangularRegion : list) {
168 size += get_size(rectangularRegion.northwest);
169 size += get_size(rectangularRegion.southeast);
174size_t get_size(
const PolygonalRegion& reg)
177 for (
auto& twoDLocation : reg) {
178 size +=
sizeof(twoDLocation.latitude);
179 size +=
sizeof(twoDLocation.longitude);
187 size +=
sizeof(reg.region_dictionary);
188 size +=
sizeof(reg.region_identifier);
189 size += get_size(reg.local_region);
193size_t get_size(
const GeographicRegion& reg)
195 size_t size =
sizeof(RegionType);
197 struct geograpical_region_visitor :
public boost::static_visitor<>
206 m_size = get_size(reg);
209 void operator()(
const std::list<RectangularRegion>& reg)
211 m_size = get_size(reg);
212 m_size += length_coding_size(m_size);
215 void operator()(
const PolygonalRegion& reg)
217 m_size = get_size(reg);
218 m_size += length_coding_size(m_size);
223 m_size = get_size(reg);
229 geograpical_region_visitor visit;
230 boost::apply_visitor(visit, reg);
231 size += visit.m_size;
237 serialize(ar, loc.latitude);
238 serialize(ar, loc.longitude);
243 serialize(ar, loc.latitude);
244 serialize(ar, loc.longitude);
245 ar << loc.elevation[0];
246 ar << loc.elevation[1];
251 serialize(ar, reg.center);
252 serialize(ar, reg.radius);
257 serialize(ar, reg.northwest);
258 serialize(ar, reg.southeast);
261void serialize(
OutputArchive& ar,
const std::list<RectangularRegion>& list)
264 size = get_size(list);
265 serialize_length(ar, size);
266 for (
auto& rectangularRegion : list) {
267 serialize(ar, rectangularRegion);
274 size = get_size(reg);
275 serialize_length(ar, size);
276 for (
auto& twoDLocation : reg) {
277 serialize(ar, twoDLocation);
283 serialize(ar, reg.region_dictionary);
284 serialize(ar, host_cast(reg.region_identifier));
285 serialize(ar, reg.local_region);
288void serialize(
OutputArchive& ar,
const GeographicRegion& reg)
290 struct geograpical_region_visitor :
public boost::static_visitor<>
304 serialize(m_archive, reg);
307 void operator()(
const std::list<RectangularRegion>& reg)
309 serialize(m_archive, reg);
312 void operator()(
const PolygonalRegion& reg)
314 serialize(m_archive, reg);
319 serialize(m_archive, reg);
325 RegionType type = get_type(reg);
327 geograpical_region_visitor visit(ar);
328 boost::apply_visitor(visit, reg);
333 deserialize(ar, loc.latitude);
334 deserialize(ar, loc.longitude);
335 return get_size(loc);
340 deserialize(ar, loc.latitude);
341 deserialize(ar, loc.longitude);
342 ar >> loc.elevation[0];
343 ar >> loc.elevation[1];
344 return get_size(loc);
350 size += deserialize(ar, reg.center);
351 deserialize(ar, reg.radius);
352 size +=
sizeof(reg.radius);
356size_t deserialize(
InputArchive& ar, std::list<RectangularRegion>& list)
358 size_t size, ret_size;
359 size = deserialize_length(ar);
363 size -= deserialize(ar, reg.northwest);
364 size -= deserialize(ar, reg.southeast);
370size_t deserialize(
InputArchive& ar, PolygonalRegion& reg)
372 size_t size, ret_size;
373 size = deserialize_length(ar);
377 size -= deserialize(ar, loc);
386 deserialize(ar, reg.region_dictionary);
387 size +=
sizeof(RegionDictionary);
388 deserialize(ar, reg.region_identifier);
389 size +=
sizeof(reg.region_identifier);
390 deserialize(ar, reg.local_region);
391 size += get_size(reg.local_region);
395size_t deserialize(
InputArchive& ar, GeographicRegion& reg)
398 deserialize(ar, type);
399 size_t size =
sizeof(RegionType);
401 case RegionType::None:
405 case RegionType::Circle: {
407 size += deserialize(ar, circle);
411 case RegionType::Rectangle: {
412 std::list<RectangularRegion> list;
413 size += deserialize(ar, list);
414 size += length_coding_size(size);
418 case RegionType::Polygon: {
419 PolygonalRegion polygon;
420 size += deserialize(ar, polygon);
421 size += length_coding_size(size);
425 case RegionType::ID: {
427 size += deserialize(ar, id);
439bool is_within(
const TwoDLocation& position,
const GeographicRegion& reg)
441 struct geograpical_region_visitor :
public boost::static_visitor<
bool>
443 geograpical_region_visitor(
const TwoDLocation& position) :
454 return is_within(m_position, reg);
457 bool operator()(
const std::list<RectangularRegion>& reg)
459 return is_within(m_position, reg);
462 bool operator()(
const PolygonalRegion& reg)
464 return is_within(m_position, reg);
469 return is_within(m_position, reg);
475 geograpical_region_visitor visit(position);
476 return boost::apply_visitor(visit, reg);
481 const auto& geod = GeographicLib::Geodesic::WGS84();
483 const units::GeoAngle pos_lat { position.latitude };
484 const units::GeoAngle pos_lon { position.longitude };
485 const units::GeoAngle center_lat { circular.center.latitude };
486 const units::GeoAngle center_lon { circular.center.longitude };
487 geod.Inverse(pos_lat / units::degree, pos_lon / units::degree,
488 center_lat / units::degree, center_lon / units::degree, dist);
489 return dist <= circular.radius / units::si::meter;
492bool is_within(
const TwoDLocation& position,
const std::list<RectangularRegion>& rectangles)
494 static const unsigned max_rectangles = 6;
496 if (rectangles.size() > max_rectangles) {
500 return std::any_of(rectangles.begin(), rectangles.end(),
501 [&position](
const RectangularRegion& rect) {
return is_within(position, rect); });
509 if (rectangle.northwest.latitude <= rectangle.southeast.latitude) {
511 }
else if (rectangle.northwest.longitude >= rectangle.southeast.longitude) {
515 if (rectangle.northwest.latitude < position.latitude) {
517 }
else if (rectangle.northwest.longitude > position.longitude) {
519 }
else if (rectangle.southeast.latitude > position.latitude) {
521 }
else if (rectangle.southeast.longitude < position.longitude) {
528bool is_within(
const TwoDLocation&,
const PolygonalRegion&)
540bool is_within(
const GeographicRegion& inner,
const GeographicRegion& outer)
542 struct outer_geograpical_region_visitor :
public boost::static_visitor<
bool>
544 outer_geograpical_region_visitor(
const GeographicRegion& inner) :
556 return is_within(inner, outer);
559 bool operator()(
const std::list<RectangularRegion>& outer)
561 return is_within(inner, outer);
564 bool operator()(
const PolygonalRegion& outer)
566 return is_within(inner, outer);
571 return is_within(inner, outer);
574 const GeographicRegion& inner;
577 outer_geograpical_region_visitor visit(inner);
578 return boost::apply_visitor(visit, outer);
581bool is_within(
const GeographicRegion& inner,
const CircularRegion& outer)
583 struct inner_geograpical_region_visitor :
public boost::static_visitor<
bool>
597 if (inner == outer) {
601 const auto& geod = GeographicLib::Geodesic::WGS84();
602 double center_dist = 0.0;
603 const units::GeoAngle inner_lat { inner.center.latitude };
604 const units::GeoAngle inner_long { inner.center.longitude };
605 const units::GeoAngle outer_lat { outer.center.latitude };
606 const units::GeoAngle outer_long { outer.center.longitude };
607 geod.Inverse(inner_lat / units::degree, inner_long / units::degree,
608 outer_lat / units::degree, outer_long / units::degree, center_dist);
609 return center_dist + inner.radius / units::si::meter <= outer.radius / units::si::meter;
612 bool operator()(
const std::list<RectangularRegion>&)
616
617
618
619
620
621
622
623
624
628 bool operator()(
const PolygonalRegion&)
647 inner_geograpical_region_visitor visit(outer);
648 return boost::apply_visitor(visit, inner);
651bool is_within(
const GeographicRegion& inner,
const std::list<RectangularRegion>& outer)
658 struct inner_geograpical_region_visitor :
public boost::static_visitor<
bool>
660 inner_geograpical_region_visitor(
const std::list<RectangularRegion>& outer) :
676 bool operator()(
const std::list<RectangularRegion>& inner)
678 if (inner == outer) {
686 bool operator()(
const PolygonalRegion&)
698 const std::list<RectangularRegion>& outer;
701 inner_geograpical_region_visitor visit(outer);
702 return boost::apply_visitor(visit, inner);
705bool is_within(
const GeographicRegion& inner,
const PolygonalRegion& outer)
724 using boost::units::isnan;
727 ThreeDLocation::Elevation elevation { ThreeDLocation::unknown_elevation };
729 if (!isnan(altitude)) {
730 using boost::algorithm::clamp;
733 double altitude_dm = std::round(10.0 * (altitude / vanetza::units::si::meter));
734 if (altitude_dm >= 0.0) {
735 altitude_dm = clamp(altitude_dm, 0.0, 61439.0);
736 auto altitude_int =
static_cast<std::uint16_t>(altitude_dm);
737 elevation[0] = altitude_int >> 8;
738 elevation[1] = altitude_int & 0xFF;
740 altitude_dm = clamp(altitude_dm, -4095.0, -1.0);
741 auto altitude_int =
static_cast<std::int16_t>(altitude_dm);
742 elevation[0] = altitude_int >> 8 | 0xF0;
743 elevation[1] = altitude_int & 0xFF;
thrown when a deserialization error occurred
CircularRegion specified in TS 103 097 v1.2.1, section 4.2.22.
IdentifiedRegion specified in TS 103 097 v1.2.1, section 4.2.25.
Specified in TS 103 097 v1.2.1, section 4.2.20.
RectangularRegion specified in TS 103 097 v1.2.1, section 4.2.23.
ThreeDLocation specified in TS 103 097 v1.2.1, section 4.2.19.
TwoDLocation specified in TS 103 097 v1.2.1, section 4.2.18.