Stride Reference Manual  - generated for commit 9643b11
GeoAggregator.h
Go to the documentation of this file.
1 /*
2  * This is free software: you can redistribute it and/or modify it
3  * under the terms of the GNU General Public License as published by
4  * the Free Software Foundation, either version 3 of the License, or
5  * any later version.
6  * The software is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9  * GNU General Public License for more details.
10  * You should have received a copy of the GNU General Public License
11  * along with the software. If not, see <http://www.gnu.org/licenses/>.
12  *
13  * Copyright 2018, 2019, Jan Broeckhove and Bistromatics group.
14  */
15 
16 #pragma once
17 
18 #include "KdTree.h"
19 #include "KdTree2DPoint.h"
20 
21 #include <boost/geometry/algorithms/within.hpp>
22 #include <boost/geometry/core/access.hpp>
23 #include <boost/geometry/geometries/box.hpp>
24 #include <boost/geometry/geometries/polygon.hpp>
25 #include <boost/geometry/geometries/register/box.hpp>
26 
27 #include <tuple>
28 
29 BOOST_GEOMETRY_REGISTER_BOX_TEMPLATED(geopop::AABBox, lower, upper)
30 
32 
33 inline double RadianToDegree(double rad) { return rad / M_PI * 180.0; }
34 
35 inline double DegreeToRadian(double deg) { return deg / 180.0 * M_PI; }
36 
37 } // namespace geoaggregator_detail
38 
39 namespace geopop {
40 
41 class Location;
42 
44 template <typename InsertIter, typename T>
45 class Collector
46 {
47 public:
48  explicit Collector(const InsertIter& ins) : m_ins(ins) {}
49 
51  void operator()(T elem) { *m_ins = std::move(elem); }
52 
53 private:
54  InsertIter m_ins;
55 };
56 
58 template <typename InsertIter, typename T = typename InsertIter::container_type::value_type>
60 {
61  return Collector<InsertIter, T>(ins);
62 }
63 
75 template <typename Policy, typename... F>
77 {
78  static_assert(sizeof...(F) <= 1, "Should have at most one functor type");
79 };
80 
84 template <typename Policy>
85 class GeoAggregator<Policy>
86 {
87 public:
88  GeoAggregator(const KdTree<geogrid_detail::KdTree2DPoint>& tree, typename Policy::Args&& args)
89  : m_policy(std::forward<typename Policy::Args>(args)), m_tree(tree)
90  {
91  }
92 
94  template <typename F>
95  void operator()(F f)
96  {
97  auto box = m_policy.GetBoundingBox();
98  m_tree.Apply(
99  [&f, this](const geogrid_detail::KdTree2DPoint& pt) -> bool {
100  if (m_policy.Contains(pt)) {
101  f(pt.GetLocation());
102  }
103  return true;
104  },
105  box);
106  }
107 
108 private:
109  Policy m_policy;
111 };
112 
116 template <typename Policy, typename F>
117 class GeoAggregator<Policy, F> : public GeoAggregator<Policy>
118 {
119 public:
120  GeoAggregator(const KdTree<geogrid_detail::KdTree2DPoint>& tree, F f, typename Policy::Args&& args)
121  : GeoAggregator<Policy>(tree, std::forward<typename Policy::Args&&>(args)), m_functor(std::move(f))
122  {
123  }
124 
127 
128 private:
130 };
131 
137 {
138 public:
139  using Args = std::tuple<geogrid_detail::KdTree2DPoint, double>;
140 
141  explicit RadiusPolicy(Args args) : m_center(std::move(std::get<0>(args))), m_radius(std::get<1>(args)) {}
142 
144  {
145  using namespace geoaggregator_detail;
146 
148 
149  // As of boost 1.66, there's seems no way to do this in Boost.Geometry
150  constexpr double EARTH_RADIUS_KM = 6371.0;
151  const double scaled_radius = m_radius / EARTH_RADIUS_KM;
152 
153  const double startlon = m_center.Get<0>();
154  const double startlat = m_center.Get<1>();
155  const double londiff = RadianToDegree(scaled_radius / std::cos(DegreeToRadian(startlat)));
156  const double latdiff = RadianToDegree(scaled_radius);
157 
158  box.upper = geogrid_detail::KdTree2DPoint(startlon + londiff, startlat + latdiff);
159  box.lower = geogrid_detail::KdTree2DPoint(startlon - londiff, startlat - latdiff);
160 
161  return box;
162  }
163 
164  bool Contains(const geogrid_detail::KdTree2DPoint& pt) const { return pt.InRadius(m_center, m_radius); }
165 
166 private:
168  double m_radius;
169 };
170 
175 {
176 public:
177  using Args = std::tuple<double, double, double, double>;
178 
179  explicit BoxPolicy(Args args) : m_args(std::move(args)) {}
180 
182  {
183  using std::get;
184  return {{get<0>(m_args), get<1>(m_args)}, {get<2>(m_args), get<3>(m_args)}};
185  }
186 
187  bool Contains(const geogrid_detail::KdTree2DPoint&) const { return true; }
188 
189 private:
191 };
192 
197 {
198 public:
199  using Args = boost::geometry::model::polygon<Coordinate, true>;
200 
201  explicit PolygonPolicy(boost::geometry::model::polygon<Coordinate, true> args) : m_poly(std::move(args)) {}
202 
204  {
205  using boost::geometry::get;
206  AABBox<Coordinate> boostbox;
207  boost::geometry::envelope(m_poly, boostbox);
208  AABBox<geogrid_detail::KdTree2DPoint> box{{get<0>(boostbox.lower), get<1>(boostbox.lower)},
209  {get<0>(boostbox.upper), get<1>(boostbox.upper)}};
210  return box;
211  }
212 
214  {
215  return boost::geometry::within(pt.GetPoint(), m_poly);
216  }
217 
218 private:
220 };
221 
222 } // namespace geopop
std::tuple< geogrid_detail::KdTree2DPoint, double > Args
double RadianToDegree(double rad)
Definition: GeoAggregator.h:33
bool Contains(const geogrid_detail::KdTree2DPoint &pt) const
Collector< InsertIter, T > MakeCollector(const InsertIter &ins)
Build a Collector, useful for type inference.
Definition: GeoAggregator.h:59
boost::geometry::model::polygon< Coordinate, true > Args
AxisAlignedBoundingBox (hyperrectangle defined by lower and upper bound for every dimension)...
Definition: AABBox.h:24
BoxPolicy(Args args)
bool InRadius(const KdTree2DPoint &start, double radius) const
Does the point lie within radius km from start?
const Location * GetLocation() const
Retrieve the location.
Definition: KdTree2DPoint.h:69
Coordinate GetPoint() const
Get the coordinate for this Location.
Definition: KdTree2DPoint.h:72
void operator()(F f)
Aggregate over the area specified by the policy with the functor f.
Definition: GeoAggregator.h:95
const KdTree< geogrid_detail::KdTree2DPoint > & m_tree
A GeoAggregator can either be instantiated with a functor, or be called with one every time...
Definition: GeoAggregator.h:76
PolygonPolicy(boost::geometry::model::polygon< Coordinate, true > args)
STL namespace.
AABBox< geogrid_detail::KdTree2DPoint > GetBoundingBox() const
Aggregates into a vector that must should remain alive for the usage duration of the Collector...
Definition: GeoAggregator.h:45
Namespace for the geographic and demograhic classes.
Definition: Coordinate.h:21
bool Contains(const geogrid_detail::KdTree2DPoint &) const
P lower
The lower bound for every dimension.
Definition: AABBox.h:27
Collector(const InsertIter &ins)
Definition: GeoAggregator.h:48
P upper
The upper bound for every dimension.
Definition: AABBox.h:29
InsertIter m_ins
The (back_)insert_iterator that receives new elements.
Definition: GeoAggregator.h:54
KdTree for some more information on methods.
Definition: KdTree2DPoint.h:31
bool Contains(const geogrid_detail::KdTree2DPoint &pt) const
void operator()(T elem)
Collect a new element.
Definition: GeoAggregator.h:51
void operator()()
Aggregate over the policy with the functor specified at construction time.
double DegreeToRadian(double deg)
Definition: GeoAggregator.h:35
AABBox< geogrid_detail::KdTree2DPoint > GetBoundingBox() const
GeoAggregator Policy that aggregates locations within a radius (in km) of a center point...
geogrid_detail::KdTree2DPoint m_center
A GeoAggregator Policy that aggregates over a (clockwise) polygon.
GeoAggregator(const KdTree< geogrid_detail::KdTree2DPoint > &tree, typename Policy::Args &&args)
Definition: GeoAggregator.h:88
std::tuple< double, double, double, double > Args
lon1, lat1, lon2, lat2
GeoAggregator Policy that aggregates over an axis aligned bounding box.
GeoAggregator(const KdTree< geogrid_detail::KdTree2DPoint > &tree, F f, typename Policy::Args &&args)
AABBox< geogrid_detail::KdTree2DPoint > GetBoundingBox() const