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