Vanetza
Loading...
Searching...
No Matches
region.cpp
1#include <vanetza/common/annotation.hpp>
2#include <vanetza/common/serialization.hpp>
3#include <vanetza/geodesy/geodesy.hpp>
4#include <vanetza/security/exception.hpp>
5#include <vanetza/security/v2/region.hpp>
6#include <vanetza/units/angle.hpp>
7#include <vanetza/units/length.hpp>
8#include <boost/algorithm/clamp.hpp>
9#include <boost/units/cmath.hpp>
10#include <boost/variant/static_visitor.hpp>
11#include <boost/variant/apply_visitor.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 geodesy::GeodeticPosition pos(units::GeoAngle{position.latitude}, units::GeoAngle{position.longitude});
482 geodesy::GeodeticPosition center(units::GeoAngle{circular.center.latitude}, units::GeoAngle{circular.center.longitude});
483 auto dist = geodesy::distance(pos, center);
484 return dist <= circular.radius;
485}
486
487bool is_within(const TwoDLocation& position, const std::list<RectangularRegion>& rectangles)
488{
489 static const unsigned max_rectangles = 6; /*< see TS 103 097 v1.2.1, section 4.2.20 */
490
491 if (rectangles.size() > max_rectangles) {
492 return false;
493 }
494
495 return std::any_of(rectangles.begin(), rectangles.end(),
496 [&position](const RectangularRegion& rect) { return is_within(position, rect); });
497}
498
499bool is_within(const TwoDLocation& position, const RectangularRegion& rectangle)
500{
501 // basic coordinate checks according to TS 103 097 v1.2.1, 4.2.23 and IEEE 1609.2-2016, 6.4.20
502 // - northwest is truly north of southeast (never equal)
503 // - northwest is truly west of southeast (never equal)
504 if (rectangle.northwest.latitude <= rectangle.southeast.latitude) {
505 return false;
506 } else if (rectangle.northwest.longitude >= rectangle.southeast.longitude) {
507 return false;
508 }
509
510 if (rectangle.northwest.latitude < position.latitude) {
511 return false; // position is north of rectangle
512 } else if (rectangle.northwest.longitude > position.longitude) {
513 return false; // position is west of rectangle
514 } else if (rectangle.southeast.latitude > position.latitude) {
515 return false; // position is south of rectangle
516 } else if (rectangle.southeast.longitude < position.longitude) {
517 return false; // position is east of rectangle
518 }
519
520 return true;
521}
522
523bool is_within(const TwoDLocation&, const PolygonalRegion&)
524{
525 // TODO: Add support for polygonal region, see TS 103 097 v1.2.1, section 4.2.24
526 return false;
527}
528
529bool is_within(const TwoDLocation&, const IdentifiedRegion&)
530{
531 // TODO: Add support for identified region, see TS 103 097 v1.2.1, section 4.2.25
532 return false;
533}
534
535bool is_within(const GeographicRegion& inner, const GeographicRegion& outer)
536{
537 struct outer_geograpical_region_visitor : public boost::static_visitor<bool>
538 {
539 outer_geograpical_region_visitor(const GeographicRegion& inner) :
540 inner(inner)
541 {
542 }
543
544 bool operator()(const NoneRegion&)
545 {
546 return true;
547 }
548
549 bool operator()(const CircularRegion& outer)
550 {
551 return is_within(inner, outer);
552 }
553
554 bool operator()(const std::list<RectangularRegion>& outer)
555 {
556 return is_within(inner, outer);
557 }
558
559 bool operator()(const PolygonalRegion& outer)
560 {
561 return is_within(inner, outer);
562 }
563
564 bool operator()(const IdentifiedRegion& outer)
565 {
566 return is_within(inner, outer);
567 }
568
569 const GeographicRegion& inner;
570 };
571
572 outer_geograpical_region_visitor visit(inner);
573 return boost::apply_visitor(visit, outer);
574}
575
576bool is_within(const GeographicRegion& inner, const CircularRegion& outer)
577{
578 struct inner_geograpical_region_visitor : public boost::static_visitor<bool>
579 {
580 inner_geograpical_region_visitor(const CircularRegion& outer) :
581 outer(outer)
582 {
583 }
584
585 bool operator()(const NoneRegion&)
586 {
587 return false;
588 }
589
590 bool operator()(const CircularRegion& inner)
591 {
592 if (inner == outer) {
593 return true;
594 }
595
596 geodesy::GeodeticPosition inner_pos(units::GeoAngle{inner.center.latitude}, units::GeoAngle{inner.center.longitude});
597 geodesy::GeodeticPosition outer_pos(units::GeoAngle{outer.center.latitude}, units::GeoAngle{outer.center.longitude});
598 auto center_dist = geodesy::distance(inner_pos, outer_pos);
599 return center_dist + inner.radius <= outer.radius;
600 }
601
602 bool operator()(const std::list<RectangularRegion>&)
603 {
604 // TODO: Implement check whether reactangles are within the circle
605 /* Note: The rectangles can be converted to a polygon and its implementation be reused then.
606 * Note: Checking whether all corners of a rectangle are within the circle is NOT enough!
607 * Example: The rectangle here is spanning the earth except for a small part within the circle.
608 * ________
609 * / \
610 * _____/__ __\_____
611 * | | | |
612 * _____\__| |__/____
613 * \_________/
614 */
615 return false;
616 }
617
618 bool operator()(const PolygonalRegion&)
619 {
620 // TODO: Implement check whether a polygon is within the circle.
621 // Note: Same thoughts as for rectangles applies.
622 return false;
623
624 }
625
626 bool operator()(const IdentifiedRegion&)
627 {
628 // TODO: Implement check whether an identified region is within the circle.
629 // Note: The identified region can be converted to a polygon and its implementation be reused then.
630 // Note: Same thoughts as for rectangles applies.
631 return false;
632 }
633
634 const CircularRegion& outer;
635 };
636
637 inner_geograpical_region_visitor visit(outer);
638 return boost::apply_visitor(visit, inner);
639}
640
641bool is_within(const GeographicRegion& inner, const std::list<RectangularRegion>& outer)
642{
643 // Note: The rectangles cover an area combined, there's no need for the inner shape to be within a single one!
644 // TODO: Implement check whether inner is within the set of rectangles
645 // Note: The rectangles can be converted to a polygon and its implementation be reused then.
646 // Note: Only exact matches are implemented for now.
647
648 struct inner_geograpical_region_visitor : public boost::static_visitor<bool>
649 {
650 inner_geograpical_region_visitor(const std::list<RectangularRegion>& outer) :
651 outer(outer)
652 {
653 }
654
655 bool operator()(const NoneRegion&)
656 {
657 return false;
658 }
659
660 bool operator()(const CircularRegion&)
661 {
662 // TODO: Implement.
663 return false;
664 }
665
666 bool operator()(const std::list<RectangularRegion>& inner)
667 {
668 if (inner == outer) {
669 return true;
670 }
671
672 // TODO: Implement.
673 return false;
674 }
675
676 bool operator()(const PolygonalRegion&)
677 {
678 // TODO: Implement.
679 return false;
680 }
681
682 bool operator()(const IdentifiedRegion&)
683 {
684 // TODO: Implement.
685 return false;
686 }
687
688 const std::list<RectangularRegion>& outer;
689 };
690
691 inner_geograpical_region_visitor visit(outer);
692 return boost::apply_visitor(visit, inner);
693}
694
695bool is_within(const GeographicRegion& inner, const PolygonalRegion& outer)
696{
697 // TODO: Implement check whether inner is within the polygon
698 mark_unused(inner);
699 mark_unused(outer);
700 return false;
701}
702
703bool is_within(const GeographicRegion& inner, const IdentifiedRegion& outer)
704{
705 // TODO: Implement check whether inner is within the polygon identified by the outer region
706 // Note: The identified region can be converted to a polygon and its implementation be reused then.
707 mark_unused(inner);
708 mark_unused(outer);
709 return false;
710}
711
712ThreeDLocation::Elevation to_elevation(units::Length altitude)
713{
714 using boost::units::isnan;
715
716 // Default to special value for NaN elevation
717 ThreeDLocation::Elevation elevation { ThreeDLocation::unknown_elevation };
718
719 if (!isnan(altitude)) {
720 using boost::algorithm::clamp;
721
722 // see TS 103 097 v1.2.1, section 4.2.19
723 double altitude_dm = std::round(10.0 * (altitude / vanetza::units::si::meter));
724 if (altitude_dm >= 0.0) {
725 altitude_dm = clamp(altitude_dm, 0.0, 61439.0);
726 auto altitude_int = static_cast<std::uint16_t>(altitude_dm);
727 elevation[0] = altitude_int >> 8;
728 elevation[1] = altitude_int & 0xFF;
729 } else {
730 altitude_dm = clamp(altitude_dm, -4095.0, -1.0);
731 auto altitude_int = static_cast<std::int16_t>(altitude_dm);
732 elevation[0] = altitude_int >> 8 | 0xF0;
733 elevation[1] = altitude_int & 0xFF;
734 }
735 }
736
737 return elevation;
738}
739
740} // namespace v2
741} // namespace security
742} // 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