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 }};
24RegionType get_type(
const GeographicRegion& reg)
26 struct geograpical_region_visitor :
public boost::static_visitor<RegionType>
28 RegionType operator()(NoneRegion reg)
30 return RegionType::None;
32 RegionType operator()(CircularRegion reg)
34 return RegionType::Circle;
36 RegionType operator()(std::list<RectangularRegion> reg)
38 return RegionType::Rectangle;
40 RegionType operator()(PolygonalRegion reg)
42 return RegionType::Polygon;
44 RegionType operator()(IdentifiedRegion reg)
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);
169size_t get_size(
const PolygonalRegion& reg)
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);
188size_t get_size(
const GeographicRegion& reg)
190 size_t size =
sizeof(RegionType);
192 struct geograpical_region_visitor :
public boost::static_visitor<>
194 void operator()(NoneRegion reg)
198 void operator()(CircularRegion 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);
207 void operator()(PolygonalRegion reg)
209 m_size = get_size(reg);
210 m_size += length_coding_size(m_size);
212 void operator()(IdentifiedRegion reg)
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);
261void serialize(OutputArchive& ar,
const PolygonalRegion& reg)
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);
278void serialize(OutputArchive& ar,
const GeographicRegion& reg)
280 struct geograpical_region_visitor :
public boost::static_visitor<>
282 geograpical_region_visitor(OutputArchive& ar) :
286 void operator()(NoneRegion reg)
290 void operator()(CircularRegion reg)
292 serialize(m_archive, reg);
294 void operator()(std::list<RectangularRegion> reg)
296 serialize(m_archive, reg);
298 void operator()(PolygonalRegion reg)
300 serialize(m_archive, reg);
302 void operator()(IdentifiedRegion 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);
354size_t deserialize(InputArchive& ar, PolygonalRegion& reg)
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);
379size_t deserialize(InputArchive& ar, GeographicRegion& reg)
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: {
403 PolygonalRegion 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");
423bool is_within(
const TwoDLocation& position,
const GeographicRegion& reg)
425 struct geograpical_region_visitor :
public boost::static_visitor<bool>
427 geograpical_region_visitor(
const TwoDLocation& position) :
431 bool operator()(
const NoneRegion& reg)
435 bool operator()(
const CircularRegion& reg)
437 return is_within(m_position, reg);
439 bool operator()(
const std::list<RectangularRegion>& reg)
441 return is_within(m_position, reg);
443 bool operator()(
const PolygonalRegion& reg)
445 return is_within(m_position, reg);
447 bool operator()(
const IdentifiedRegion& reg)
449 return is_within(m_position, reg);
451 const TwoDLocation& m_position;
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) {
507bool is_within(
const TwoDLocation& position,
const PolygonalRegion& region)
519bool is_within(
const GeographicRegion& inner,
const GeographicRegion& outer)
521 struct outer_geograpical_region_visitor :
public boost::static_visitor<bool>
523 outer_geograpical_region_visitor(
const GeographicRegion& inner) :
527 bool operator()(
const NoneRegion& outer)
531 bool operator()(
const CircularRegion& outer)
533 return is_within(inner, outer);
535 bool operator()(
const std::list<RectangularRegion>& outer)
537 return is_within(inner, outer);
539 bool operator()(
const PolygonalRegion& outer)
541 return is_within(inner, outer);
543 bool operator()(
const IdentifiedRegion& outer)
545 return is_within(inner, outer);
547 const GeographicRegion& inner;
550 outer_geograpical_region_visitor visit(inner);
551 return boost::apply_visitor(visit, outer);
554bool is_within(
const GeographicRegion& inner,
const CircularRegion& outer)
556 struct inner_geograpical_region_visitor :
public boost::static_visitor<bool>
558 inner_geograpical_region_visitor(
const CircularRegion& outer) :
562 bool operator()(
const NoneRegion& inner)
566 bool operator()(
const CircularRegion& 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)
597 bool operator()(
const PolygonalRegion& inner)
603 bool operator()(
const IdentifiedRegion& inner)
610 const CircularRegion& outer;
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)
634 bool operator()(
const CircularRegion& inner)
639 bool operator()(
const std::list<RectangularRegion>& inner)
641 if (inner == outer) {
648 bool operator()(
const PolygonalRegion& inner)
653 bool operator()(
const IdentifiedRegion& inner)
658 const std::list<RectangularRegion>& outer;
661 inner_geograpical_region_visitor visit(outer);
662 return boost::apply_visitor(visit, inner);
665bool is_within(
const GeographicRegion& inner,
const PolygonalRegion& outer)
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;
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.