Vanetza
Loading...
Searching...
No Matches
region.cpp
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>
12#include <cmath>
13
14namespace vanetza
15{
16namespace security
17{
18namespace v2
19{
20
21const ThreeDLocation::Elevation ThreeDLocation::unknown_elevation {{ 0xF0, 0x00 }};
22const ThreeDLocation::Elevation ThreeDLocation::min_elevation {{ 0xF0, 0x01 }};
23const ThreeDLocation::Elevation ThreeDLocation::max_elevation {{ 0xEF, 0xFF }};
24
25RegionType get_type(const GeographicRegion& reg)
26{
27 struct geograpical_region_visitor : public boost::static_visitor<RegionType>
28 {
29 RegionType operator()(const NoneRegion&)
30 {
31 return RegionType::None;
32 }
33
34 RegionType operator()(const CircularRegion&)
35 {
36 return RegionType::Circle;
37 }
38
39 RegionType operator()(const std::list<RectangularRegion>&)
40 {
41 return RegionType::Rectangle;
42 }
43
44 RegionType operator()(const PolygonalRegion&)
45 {
46 return RegionType::Polygon;
47 }
48
49 RegionType operator()(const IdentifiedRegion&)
50 {
51 return RegionType::ID;
52 }
53 };
54
55 geograpical_region_visitor visit;
56 return boost::apply_visitor(visit, reg);
57}
58
59bool TwoDLocation::operator==(const TwoDLocation& other) const
60{
61 return this->latitude == other.latitude && this->longitude == other.longitude;
62}
63
64bool TwoDLocation::operator!=(const TwoDLocation& other) const
65{
66 return !(*this == other);
67}
68
69bool ThreeDLocation::operator==(const ThreeDLocation& other) const
70{
71 return this->latitude == other.latitude && this->longitude == other.longitude && this->elevation == other.elevation;
72}
73
74bool ThreeDLocation::operator!=(const ThreeDLocation& other) const
75{
76 return !(*this == other);
77}
78
79bool NoneRegion::operator==(const NoneRegion&) const
80{
81 return true;
82}
83
84bool NoneRegion::operator!=(const NoneRegion& other) const
85{
86 return !(*this == other);
87}
88
89bool CircularRegion::operator==(const CircularRegion& other) const
90{
91 return this->center == other.center && this->radius == other.radius;
92}
93
94bool CircularRegion::operator!=(const CircularRegion& other) const
95{
96 return !(*this == other);
97}
98
99bool RectangularRegion::operator==(const RectangularRegion& other) const
100{
101 return this->northwest == other.northwest && this->southeast == other.southeast;
102}
103
104bool RectangularRegion::operator!=(const RectangularRegion& other) const
105{
106 return !(*this == other);
107}
108
109bool IdentifiedRegion::operator==(const IdentifiedRegion& other) const
110{
111 return this->region_dictionary == other.region_dictionary
112 && this->region_identifier == other.region_identifier
113 && this->local_region == other.local_region;
114}
115
116bool IdentifiedRegion::operator!=(const IdentifiedRegion& other) const
117{
118 return !(*this == other);
119}
120
121size_t get_size(const TwoDLocation& loc)
122{
123 size_t size = 0;
124 size += sizeof(loc.latitude);
125 size += sizeof(loc.longitude);
126 return size;
127}
128
129size_t get_size(const ThreeDLocation& loc)
130{
131 size_t size = 0;
132 size += sizeof(loc.latitude);
133 size += sizeof(loc.longitude);
134 size += loc.elevation.size();
135 return size;
136}
137
138size_t get_size(const CircularRegion& reg)
139{
140 size_t size = 0;
141 size += get_size(reg.center);
142 size += sizeof(reg.radius);
143 return size;
144}
145
146size_t get_size(const RectangularRegion& reg)
147{
148 size_t size = 0;
149 size += get_size(reg.northwest);
150 size += get_size(reg.southeast);
151 return size;
152}
153
154size_t get_size(const std::list<CircularRegion>& list)
155{
156 size_t size = 0;
157 for (auto& circularRegion : list) {
158 size += get_size(circularRegion.center);
159 size += sizeof(circularRegion.radius);
160 }
161 return size;
162}
163
164size_t get_size(const std::list<RectangularRegion>& list)
165{
166 size_t size = 0;
167 for (auto& rectangularRegion : list) {
168 size += get_size(rectangularRegion.northwest);
169 size += get_size(rectangularRegion.southeast);
170 }
171 return size;
172}
173
174size_t get_size(const PolygonalRegion& reg)
175{
176 size_t size = 0;
177 for (auto& twoDLocation : reg) {
178 size += sizeof(twoDLocation.latitude);
179 size += sizeof(twoDLocation.longitude);
180 }
181 return size;
182}
183
184size_t get_size(const IdentifiedRegion& reg)
185{
186 size_t size = 0;
187 size += sizeof(reg.region_dictionary);
188 size += sizeof(reg.region_identifier);
189 size += get_size(reg.local_region);
190 return size;
191}
192
193size_t get_size(const GeographicRegion& reg)
194{
195 size_t size = sizeof(RegionType);
196
197 struct geograpical_region_visitor : public boost::static_visitor<>
198 {
199 void operator()(const NoneRegion&)
200 {
201 m_size = 0;
202 }
203
204 void operator()(const CircularRegion& reg)
205 {
206 m_size = get_size(reg);
207 }
208
209 void operator()(const std::list<RectangularRegion>& reg)
210 {
211 m_size = get_size(reg);
212 m_size += length_coding_size(m_size);
213 }
214
215 void operator()(const PolygonalRegion& reg)
216 {
217 m_size = get_size(reg);
218 m_size += length_coding_size(m_size);
219 }
220
221 void operator()(const IdentifiedRegion& reg)
222 {
223 m_size = get_size(reg);
224 }
225
226 size_t m_size;
227 };
228
229 geograpical_region_visitor visit;
230 boost::apply_visitor(visit, reg);
231 size += visit.m_size;
232 return size;
233}
234
235void serialize(OutputArchive& ar, const TwoDLocation& loc)
236{
237 serialize(ar, loc.latitude);
238 serialize(ar, loc.longitude);
239}
240
241void serialize(OutputArchive& ar, const ThreeDLocation& loc)
242{
243 serialize(ar, loc.latitude);
244 serialize(ar, loc.longitude);
245 ar << loc.elevation[0];
246 ar << loc.elevation[1];
247}
248
249void serialize(OutputArchive& ar, const CircularRegion& reg)
250{
251 serialize(ar, reg.center);
252 serialize(ar, reg.radius);
253}
254
255void serialize(OutputArchive& ar, const RectangularRegion& reg)
256{
257 serialize(ar, reg.northwest);
258 serialize(ar, reg.southeast);
259}
260
261void serialize(OutputArchive& ar, const std::list<RectangularRegion>& list)
262{
263 size_t size;
264 size = get_size(list);
265 serialize_length(ar, size);
266 for (auto& rectangularRegion : list) {
267 serialize(ar, rectangularRegion);
268 }
269}
270
271void serialize(OutputArchive& ar, const PolygonalRegion& reg)
272{
273 size_t size;
274 size = get_size(reg);
275 serialize_length(ar, size);
276 for (auto& twoDLocation : reg) {
277 serialize(ar, twoDLocation);
278 }
279}
280
281void serialize(OutputArchive& ar, const IdentifiedRegion& reg)
282{
283 serialize(ar, reg.region_dictionary);
284 serialize(ar, host_cast(reg.region_identifier));
285 serialize(ar, reg.local_region);
286}
287
288void serialize(OutputArchive& ar, const GeographicRegion& reg)
289{
290 struct geograpical_region_visitor : public boost::static_visitor<>
291 {
292 geograpical_region_visitor(OutputArchive& ar) :
293 m_archive(ar)
294 {
295 }
296
297 void operator()(const NoneRegion&)
298 {
299 // nothing to do
300 }
301
302 void operator()(const CircularRegion& reg)
303 {
304 serialize(m_archive, reg);
305 }
306
307 void operator()(const std::list<RectangularRegion>& reg)
308 {
309 serialize(m_archive, reg);
310 }
311
312 void operator()(const PolygonalRegion& reg)
313 {
314 serialize(m_archive, reg);
315 }
316
317 void operator()(const IdentifiedRegion& reg)
318 {
319 serialize(m_archive, reg);
320 }
321
322 OutputArchive& m_archive;
323 };
324
325 RegionType type = get_type(reg);
326 serialize(ar, type);
327 geograpical_region_visitor visit(ar);
328 boost::apply_visitor(visit, reg);
329}
330
331size_t deserialize(InputArchive& ar, TwoDLocation& loc)
332{
333 deserialize(ar, loc.latitude);
334 deserialize(ar, loc.longitude);
335 return get_size(loc);
336}
337
338size_t deserialize(InputArchive& ar, ThreeDLocation& loc)
339{
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);
345}
346
347size_t deserialize(InputArchive& ar, CircularRegion& reg)
348{
349 size_t size = 0;
350 size += deserialize(ar, reg.center);
351 deserialize(ar, reg.radius);
352 size += sizeof(reg.radius);
353 return size;
354}
355
356size_t deserialize(InputArchive& ar, std::list<RectangularRegion>& list)
357{
358 size_t size, ret_size;
359 size = deserialize_length(ar);
360 ret_size = size;
361 while (size > 0) {
363 size -= deserialize(ar, reg.northwest);
364 size -= deserialize(ar, reg.southeast);
365 list.push_back(reg);
366 }
367 return ret_size;
368}
369
370size_t deserialize(InputArchive& ar, PolygonalRegion& reg)
371{
372 size_t size, ret_size;
373 size = deserialize_length(ar);
374 ret_size = size;
375 while (size > 0) {
376 TwoDLocation loc;
377 size -= deserialize(ar, loc);
378 reg.push_back(loc);
379 }
380 return ret_size;
381}
382
383size_t deserialize(InputArchive& ar, IdentifiedRegion& reg)
384{
385 size_t size = 0;
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);
392 return size;
393}
394
395size_t deserialize(InputArchive& ar, GeographicRegion& reg)
396{
397 RegionType type;
398 deserialize(ar, type);
399 size_t size = sizeof(RegionType);
400 switch (type) {
401 case RegionType::None:
402 NoneRegion none;
403 reg = none;
404 break;
405 case RegionType::Circle: {
406 CircularRegion circle;
407 size += deserialize(ar, circle);
408 reg = circle;
409 break;
410 }
411 case RegionType::Rectangle: {
412 std::list<RectangularRegion> list;
413 size += deserialize(ar, list);
414 size += length_coding_size(size);
415 reg = list;
416 break;
417 }
418 case RegionType::Polygon: {
419 PolygonalRegion polygon;
420 size += deserialize(ar, polygon);
421 size += length_coding_size(size);
422 reg = polygon;
423 break;
424 }
425 case RegionType::ID: {
427 size += deserialize(ar, id);
428 reg = id;
429 break;
430 }
431 default: {
432 throw deserialization_error("Unknown RegionType");
433 break;
434 }
435 }
436 return (size);
437}
438
439bool is_within(const TwoDLocation& position, const GeographicRegion& reg)
440{
441 struct geograpical_region_visitor : public boost::static_visitor<bool>
442 {
443 geograpical_region_visitor(const TwoDLocation& position) :
444 m_position(position)
445 {
446 }
447 bool operator()(const NoneRegion&)
448 {
449 return true;
450 }
451
452 bool operator()(const CircularRegion& reg)
453 {
454 return is_within(m_position, reg);
455 }
456
457 bool operator()(const std::list<RectangularRegion>& reg)
458 {
459 return is_within(m_position, reg);
460 }
461
462 bool operator()(const PolygonalRegion& reg)
463 {
464 return is_within(m_position, reg);
465 }
466
467 bool operator()(const IdentifiedRegion& reg)
468 {
469 return is_within(m_position, reg);
470 }
471
472 const TwoDLocation& m_position;
473 };
474
475 geograpical_region_visitor visit(position);
476 return boost::apply_visitor(visit, reg);
477}
478
479bool is_within(const TwoDLocation& position, const CircularRegion& circular)
480{
481 const auto& geod = GeographicLib::Geodesic::WGS84();
482 double dist = 0.0;
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;
490}
491
492bool is_within(const TwoDLocation& position, const std::list<RectangularRegion>& rectangles)
493{
494 static const unsigned max_rectangles = 6; /*< see TS 103 097 v1.2.1, section 4.2.20 */
495
496 if (rectangles.size() > max_rectangles) {
497 return false;
498 }
499
500 return std::any_of(rectangles.begin(), rectangles.end(),
501 [&position](const RectangularRegion& rect) { return is_within(position, rect); });
502}
503
504bool is_within(const TwoDLocation& position, const RectangularRegion& rectangle)
505{
506 // basic coordinate checks according to TS 103 097 v1.2.1, 4.2.23 and IEEE 1609.2-2016, 6.4.20
507 // - northwest is truly north of southeast (never equal)
508 // - northwest is truly west of southeast (never equal)
509 if (rectangle.northwest.latitude <= rectangle.southeast.latitude) {
510 return false;
511 } else if (rectangle.northwest.longitude >= rectangle.southeast.longitude) {
512 return false;
513 }
514
515 if (rectangle.northwest.latitude < position.latitude) {
516 return false; // position is north of rectangle
517 } else if (rectangle.northwest.longitude > position.longitude) {
518 return false; // position is west of rectangle
519 } else if (rectangle.southeast.latitude > position.latitude) {
520 return false; // position is south of rectangle
521 } else if (rectangle.southeast.longitude < position.longitude) {
522 return false; // position is east of rectangle
523 }
524
525 return true;
526}
527
528bool is_within(const TwoDLocation&, const PolygonalRegion&)
529{
530 // TODO: Add support for polygonal region, see TS 103 097 v1.2.1, section 4.2.24
531 return false;
532}
533
534bool is_within(const TwoDLocation&, const IdentifiedRegion&)
535{
536 // TODO: Add support for identified region, see TS 103 097 v1.2.1, section 4.2.25
537 return false;
538}
539
540bool is_within(const GeographicRegion& inner, const GeographicRegion& outer)
541{
542 struct outer_geograpical_region_visitor : public boost::static_visitor<bool>
543 {
544 outer_geograpical_region_visitor(const GeographicRegion& inner) :
545 inner(inner)
546 {
547 }
548
549 bool operator()(const NoneRegion&)
550 {
551 return true;
552 }
553
554 bool operator()(const CircularRegion& outer)
555 {
556 return is_within(inner, outer);
557 }
558
559 bool operator()(const std::list<RectangularRegion>& outer)
560 {
561 return is_within(inner, outer);
562 }
563
564 bool operator()(const PolygonalRegion& outer)
565 {
566 return is_within(inner, outer);
567 }
568
569 bool operator()(const IdentifiedRegion& outer)
570 {
571 return is_within(inner, outer);
572 }
573
574 const GeographicRegion& inner;
575 };
576
577 outer_geograpical_region_visitor visit(inner);
578 return boost::apply_visitor(visit, outer);
579}
580
581bool is_within(const GeographicRegion& inner, const CircularRegion& outer)
582{
583 struct inner_geograpical_region_visitor : public boost::static_visitor<bool>
584 {
585 inner_geograpical_region_visitor(const CircularRegion& outer) :
586 outer(outer)
587 {
588 }
589
590 bool operator()(const NoneRegion&)
591 {
592 return false;
593 }
594
595 bool operator()(const CircularRegion& inner)
596 {
597 if (inner == outer) {
598 return true;
599 }
600
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;
610 }
611
612 bool operator()(const std::list<RectangularRegion>&)
613 {
614 // TODO: Implement check whether reactangles are within the circle
615 /* Note: The rectangles can be converted to a polygon and its implementation be reused then.
616 * Note: Checking whether all corners of a rectangle are within the circle is NOT enough!
617 * Example: The rectangle here is spanning the earth except for a small part within the circle.
618 * ________
619 * / \
620 * _____/__ __\_____
621 * | | | |
622 * _____\__| |__/____
623 * \_________/
624 */
625 return false;
626 }
627
628 bool operator()(const PolygonalRegion&)
629 {
630 // TODO: Implement check whether a polygon is within the circle.
631 // Note: Same thoughts as for rectangles applies.
632 return false;
633
634 }
635
636 bool operator()(const IdentifiedRegion&)
637 {
638 // TODO: Implement check whether an identified region is within the circle.
639 // Note: The identified region can be converted to a polygon and its implementation be reused then.
640 // Note: Same thoughts as for rectangles applies.
641 return false;
642 }
643
644 const CircularRegion& outer;
645 };
646
647 inner_geograpical_region_visitor visit(outer);
648 return boost::apply_visitor(visit, inner);
649}
650
651bool is_within(const GeographicRegion& inner, const std::list<RectangularRegion>& outer)
652{
653 // Note: The rectangles cover an area combined, there's no need for the inner shape to be within a single one!
654 // TODO: Implement check whether inner is within the set of rectangles
655 // Note: The rectangles can be converted to a polygon and its implementation be reused then.
656 // Note: Only exact matches are implemented for now.
657
658 struct inner_geograpical_region_visitor : public boost::static_visitor<bool>
659 {
660 inner_geograpical_region_visitor(const std::list<RectangularRegion>& outer) :
661 outer(outer)
662 {
663 }
664
665 bool operator()(const NoneRegion&)
666 {
667 return false;
668 }
669
670 bool operator()(const CircularRegion&)
671 {
672 // TODO: Implement.
673 return false;
674 }
675
676 bool operator()(const std::list<RectangularRegion>& inner)
677 {
678 if (inner == outer) {
679 return true;
680 }
681
682 // TODO: Implement.
683 return false;
684 }
685
686 bool operator()(const PolygonalRegion&)
687 {
688 // TODO: Implement.
689 return false;
690 }
691
692 bool operator()(const IdentifiedRegion&)
693 {
694 // TODO: Implement.
695 return false;
696 }
697
698 const std::list<RectangularRegion>& outer;
699 };
700
701 inner_geograpical_region_visitor visit(outer);
702 return boost::apply_visitor(visit, inner);
703}
704
705bool is_within(const GeographicRegion& inner, const PolygonalRegion& outer)
706{
707 // TODO: Implement check whether inner is within the polygon
708 mark_unused(inner);
709 mark_unused(outer);
710 return false;
711}
712
713bool is_within(const GeographicRegion& inner, const IdentifiedRegion& outer)
714{
715 // TODO: Implement check whether inner is within the polygon identified by the outer region
716 // Note: The identified region can be converted to a polygon and its implementation be reused then.
717 mark_unused(inner);
718 mark_unused(outer);
719 return false;
720}
721
722ThreeDLocation::Elevation to_elevation(units::Length altitude)
723{
724 using boost::units::isnan;
725
726 // Default to special value for NaN elevation
727 ThreeDLocation::Elevation elevation { ThreeDLocation::unknown_elevation };
728
729 if (!isnan(altitude)) {
730 using boost::algorithm::clamp;
731
732 // see TS 103 097 v1.2.1, section 4.2.19
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;
739 } else {
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;
744 }
745 }
746
747 return elevation;
748}
749
750} // namespace v2
751} // namespace security
752} // namespace vanetza
thrown when a deserialization error occurred
Definition exception.hpp:20
CircularRegion specified in TS 103 097 v1.2.1, section 4.2.22.
Definition region.hpp:74
IdentifiedRegion specified in TS 103 097 v1.2.1, section 4.2.25.
Definition region.hpp:110
Specified in TS 103 097 v1.2.1, section 4.2.20.
Definition region.hpp:65
RectangularRegion specified in TS 103 097 v1.2.1, section 4.2.23.
Definition region.hpp:90
ThreeDLocation specified in TS 103 097 v1.2.1, section 4.2.19.
Definition region.hpp:21
TwoDLocation specified in TS 103 097 v1.2.1, section 4.2.18.
Definition region.hpp:47