Vanetza
 
Loading...
Searching...
No Matches
areas.cpp
1#include "areas.hpp"
2#include <boost/math/constants/constants.hpp>
3#include <boost/units/cmath.hpp>
4#include <GeographicLib/Geocentric.hpp>
5#include <GeographicLib/Geodesic.hpp>
6#include <GeographicLib/LocalCartesian.hpp>
7#include <algorithm>
8#include <cassert>
9#include <limits>
10
11namespace vanetza
12{
13namespace geonet
14{
15
16CartesianPosition operator-(const CartesianPosition& a, const CartesianPosition& b)
17{
18 return CartesianPosition { a.x - b.x, a.y - b.y };
19}
20
21double geometric_function(const Circle& c, const CartesianPosition& p)
22{
23 if (c.r.value() != 0.0) {
24 const double x_over_r = p.x / c.r;
25 const double y_over_r = p.y / c.r;
26 return 1.0 - (x_over_r * x_over_r) - (y_over_r * y_over_r);
27 } else {
28 return -std::numeric_limits<double>::infinity();
29 };
30}
31
32double geometric_function(const Rectangle& r, const CartesianPosition& p)
33{
34 if (r.a.value() != 0.0 && r.b.value() != 0.0) {
35 const double x_over_a = p.x / r.a;
36 const double y_over_b = p.y / r.b;
37 return std::min(1.0 - x_over_a * x_over_a, 1.0 - y_over_b * y_over_b);
38 } else {
39 return -std::numeric_limits<double>::infinity();
40 }
41}
42
43double geometric_function(const Ellipse& e, const CartesianPosition& p)
44{
45 if (e.a.value() != 0.0 && e.b.value() != 0.0) {
46 const double x_over_a = p.x / e.a;
47 const double y_over_b = p.y / e.b;
48 return 1.0 - (x_over_a * x_over_a) - (y_over_b * y_over_b);
49 } else {
50 return -std::numeric_limits<double>::infinity();
51 }
52}
53
54struct geometric_function_visitor : public boost::static_visitor<double>
55{
56 geometric_function_visitor(const CartesianPosition& p) : point(p) {}
57
58 template<class SHAPE>
59 double operator()(const SHAPE& s) const
60 {
61 return geometric_function(s, point);
62 }
63
64 const CartesianPosition& point;
65};
66
67double geometric_function(const decltype(Area::shape)& shape, const CartesianPosition& p)
68{
69 geometric_function_visitor visitor(p);
70 return boost::apply_visitor(visitor, shape);
71}
72
73CartesianPosition local_cartesian(
74 const GeodeticPosition& origin,
75 const GeodeticPosition& position)
76{
77 namespace si = units::si;
78 using namespace GeographicLib;
79 const Geocentric& earth = Geocentric::WGS84();
80 LocalCartesian proj {
81 origin.latitude / units::degree,
82 origin.longitude / units::degree,
83 0.0, earth
84 };
85 double result_x, result_y, unused_z = 0.0;
86 proj.Forward(position.latitude / units::degree,
87 position.longitude / units::degree, 0.0,
88 result_x, result_y, unused_z);
89 return CartesianPosition(result_x * si::meter, result_y * si::meter);
90}
91
92CartesianPosition canonicalize(const CartesianPosition& point, units::Angle azimuth)
93{
94 using namespace boost::math::double_constants;
95 // area.angle is azimuth angle of EN 302 931 V1.1.1
96 const units::Angle zenith = half_pi * units::si::radian - azimuth;
97 const double sin_z = sin(zenith);
98 const double cos_z = cos(zenith);
99 // rotate canonical point around origin clockwise: zenith = 90 deg - azimuth
100 // other interpretation: rotate shape's long side onto abscissa
101 CartesianPosition canonical;
102 canonical.x = cos_z * point.x + sin_z * point.y;
103 canonical.y = -sin_z * point.x + cos_z * point.y;
104 return canonical;
105}
106
107struct area_size_visitor : public boost::static_visitor<units::Area>
108{
109 units::Area operator()(const Circle& circle) const
110 {
111 using namespace boost::math::double_constants;
112 return pi * circle.r * circle.r;
113 }
114
115 units::Area operator()(const Rectangle& rectangle) const
116 {
117 using namespace boost::math::double_constants;
118 return 4.0 * rectangle.a * rectangle.b;
119 }
120
121 units::Area operator()(const Ellipse& ellipse) const
122 {
123 using namespace boost::math::double_constants;
124 return pi * ellipse.a * ellipse.b;
125 }
126};
127
128units::Area area_size(const Area& area)
129{
130 return boost::apply_visitor(area_size_visitor(), area.shape);
131}
132
133units::Length distance(const GeodeticPosition& lhs, const GeodeticPosition& rhs)
134{
135 using namespace GeographicLib;
136 const Geodesic& geod = Geodesic::WGS84();
137 double distance_m = 0.0;
138 geod.Inverse(lhs.latitude / units::degree, lhs.longitude / units::degree,
139 rhs.latitude / units::degree, rhs.longitude / units::degree,
140 distance_m);
141 return (distance_m >= 0.0 ? distance_m : std::numeric_limits<double>::quiet_NaN()) * units::si::meters;
142}
143
144bool inside_or_at_border(const Area& area, const GeodeticPosition& geo_position)
145{
146 using units::si::meter;
147 const CartesianPosition local = local_cartesian(area.position, geo_position);
148 const CartesianPosition canonical = canonicalize(local, area.angle);
149 return !outside_shape(area.shape, canonical);
150}
151
152} // namespace geonet
153} // namespace vanetza
154