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>
16CartesianPosition operator-(
const CartesianPosition& a,
const CartesianPosition& b)
18 return CartesianPosition { a.x - b.x, a.y - b.y };
21double geometric_function(
const Circle& c,
const CartesianPosition& p)
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);
28 return -std::numeric_limits<double>::infinity();
32double geometric_function(
const Rectangle& r,
const CartesianPosition& p)
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);
39 return -std::numeric_limits<double>::infinity();
43double geometric_function(
const Ellipse& e,
const CartesianPosition& p)
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);
50 return -std::numeric_limits<double>::infinity();
54struct geometric_function_visitor :
public boost::static_visitor<double>
56 geometric_function_visitor(
const CartesianPosition& p) : point(p) {}
59 double operator()(
const SHAPE& s)
const
61 return geometric_function(s, point);
64 const CartesianPosition& point;
67double geometric_function(
const decltype(Area::shape)& shape,
const CartesianPosition& p)
69 geometric_function_visitor visitor(p);
70 return boost::apply_visitor(visitor, shape);
73CartesianPosition local_cartesian(
74 const GeodeticPosition& origin,
75 const GeodeticPosition& position)
77 namespace si = units::si;
78 using namespace GeographicLib;
79 const Geocentric& earth = Geocentric::WGS84();
81 origin.latitude / units::degree,
82 origin.longitude / units::degree,
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);
92CartesianPosition canonicalize(
const CartesianPosition& point, units::Angle azimuth)
94 using namespace boost::math::double_constants;
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);
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;
107struct area_size_visitor :
public boost::static_visitor<units::Area>
109 units::Area operator()(
const Circle& circle)
const
111 using namespace boost::math::double_constants;
112 return pi * circle.r * circle.r;
115 units::Area operator()(
const Rectangle& rectangle)
const
117 using namespace boost::math::double_constants;
118 return 4.0 * rectangle.a * rectangle.b;
121 units::Area operator()(
const Ellipse& ellipse)
const
123 using namespace boost::math::double_constants;
124 return pi * ellipse.a * ellipse.b;
128units::Area area_size(
const Area& area)
130 return boost::apply_visitor(area_size_visitor(), area.shape);
133units::Length distance(
const GeodeticPosition& lhs,
const GeodeticPosition& rhs)
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,
141 return (distance_m >= 0.0 ? distance_m : std::numeric_limits<double>::quiet_NaN()) * units::si::meters;
144bool inside_or_at_border(
const Area& area,
const GeodeticPosition& geo_position)
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);