]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/geometry/strategies/spherical/envelope_multipoint.hpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / boost / geometry / strategies / spherical / envelope_multipoint.hpp
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2
3 // Copyright (c) 2015-2018, Oracle and/or its affiliates.
4
5 // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
6 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
7 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
8
9 // Distributed under the Boost Software License, Version 1.0.
10 // (See accompanying file LICENSE_1_0.txt or copy at
11 // http://www.boost.org/LICENSE_1_0.txt)
12
13 #ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_ENVELOPE_MULTIPOINT_HPP
14 #define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_ENVELOPE_MULTIPOINT_HPP
15
16 #include <cstddef>
17 #include <algorithm>
18 #include <utility>
19 #include <vector>
20
21 #include <boost/algorithm/minmax_element.hpp>
22 #include <boost/range.hpp>
23
24 #include <boost/geometry/core/access.hpp>
25 #include <boost/geometry/core/assert.hpp>
26 #include <boost/geometry/core/coordinate_system.hpp>
27 #include <boost/geometry/core/coordinate_type.hpp>
28 #include <boost/geometry/core/tags.hpp>
29
30 #include <boost/geometry/util/math.hpp>
31 #include <boost/geometry/util/range.hpp>
32
33 #include <boost/geometry/geometries/helper_geometry.hpp>
34
35 #include <boost/geometry/algorithms/detail/envelope/box.hpp>
36 #include <boost/geometry/algorithms/detail/envelope/initialize.hpp>
37 #include <boost/geometry/algorithms/detail/envelope/range.hpp>
38 #include <boost/geometry/algorithms/detail/expand/point.hpp>
39
40 #include <boost/geometry/strategies/cartesian/envelope_point.hpp>
41 #include <boost/geometry/strategies/normalize.hpp>
42 #include <boost/geometry/strategies/spherical/envelope_box.hpp>
43 #include <boost/geometry/strategies/spherical/envelope_point.hpp>
44
45
46 namespace boost { namespace geometry
47 {
48
49 namespace strategy { namespace envelope
50 {
51
52 class spherical_multipoint
53 {
54 private:
55 template <std::size_t Dim>
56 struct coordinate_less
57 {
58 template <typename Point>
59 inline bool operator()(Point const& point1, Point const& point2) const
60 {
61 return math::smaller(geometry::get<Dim>(point1),
62 geometry::get<Dim>(point2));
63 }
64 };
65
66 template <typename Constants, typename MultiPoint, typename OutputIterator>
67 static inline void analyze_point_coordinates(MultiPoint const& multipoint,
68 bool& has_south_pole,
69 bool& has_north_pole,
70 OutputIterator oit)
71 {
72 typedef typename boost::range_value<MultiPoint>::type point_type;
73 typedef typename boost::range_iterator
74 <
75 MultiPoint const
76 >::type iterator_type;
77
78 // analyze point coordinates:
79 // (1) normalize point coordinates
80 // (2) check if any point is the north or the south pole
81 // (3) put all non-pole points in a container
82 //
83 // notice that at this point in the algorithm, we have at
84 // least two points on the spheroid
85 has_south_pole = false;
86 has_north_pole = false;
87
88 for (iterator_type it = boost::begin(multipoint);
89 it != boost::end(multipoint);
90 ++it)
91 {
92 point_type point;
93 normalize::spherical_point::apply(*it, point);
94
95 if (math::equals(geometry::get<1>(point),
96 Constants::min_latitude()))
97 {
98 has_south_pole = true;
99 }
100 else if (math::equals(geometry::get<1>(point),
101 Constants::max_latitude()))
102 {
103 has_north_pole = true;
104 }
105 else
106 {
107 *oit++ = point;
108 }
109 }
110 }
111
112 template <typename SortedRange, typename Value>
113 static inline Value maximum_gap(SortedRange const& sorted_range,
114 Value& max_gap_left,
115 Value& max_gap_right)
116 {
117 typedef typename boost::range_iterator
118 <
119 SortedRange const
120 >::type iterator_type;
121
122 iterator_type it1 = boost::begin(sorted_range), it2 = it1;
123 ++it2;
124 max_gap_left = geometry::get<0>(*it1);
125 max_gap_right = geometry::get<0>(*it2);
126
127 Value max_gap = max_gap_right - max_gap_left;
128 for (++it1, ++it2; it2 != boost::end(sorted_range); ++it1, ++it2)
129 {
130 Value gap = geometry::get<0>(*it2) - geometry::get<0>(*it1);
131 if (math::larger(gap, max_gap))
132 {
133 max_gap_left = geometry::get<0>(*it1);
134 max_gap_right = geometry::get<0>(*it2);
135 max_gap = gap;
136 }
137 }
138
139 return max_gap;
140 }
141
142 template
143 <
144 typename Constants,
145 typename PointRange,
146 typename LongitudeLess,
147 typename CoordinateType
148 >
149 static inline void get_min_max_longitudes(PointRange& range,
150 LongitudeLess const& lon_less,
151 CoordinateType& lon_min,
152 CoordinateType& lon_max)
153 {
154 typedef typename boost::range_iterator
155 <
156 PointRange const
157 >::type iterator_type;
158
159 // compute min and max longitude values
160 std::pair<iterator_type, iterator_type> min_max_longitudes
161 = boost::minmax_element(boost::begin(range),
162 boost::end(range),
163 lon_less);
164
165 lon_min = geometry::get<0>(*min_max_longitudes.first);
166 lon_max = geometry::get<0>(*min_max_longitudes.second);
167
168 // if the longitude span is "large" compute the true maximum gap
169 if (math::larger(lon_max - lon_min, Constants::half_period()))
170 {
171 std::sort(boost::begin(range), boost::end(range), lon_less);
172
173 CoordinateType max_gap_left = 0, max_gap_right = 0;
174 CoordinateType max_gap
175 = maximum_gap(range, max_gap_left, max_gap_right);
176
177 CoordinateType complement_gap
178 = Constants::period() + lon_min - lon_max;
179
180 if (math::larger(max_gap, complement_gap))
181 {
182 lon_min = max_gap_right;
183 lon_max = max_gap_left + Constants::period();
184 }
185 }
186 }
187
188 template
189 <
190 typename Constants,
191 typename Iterator,
192 typename LatitudeLess,
193 typename CoordinateType
194 >
195 static inline void get_min_max_latitudes(Iterator const first,
196 Iterator const last,
197 LatitudeLess const& lat_less,
198 bool has_south_pole,
199 bool has_north_pole,
200 CoordinateType& lat_min,
201 CoordinateType& lat_max)
202 {
203 if (has_south_pole && has_north_pole)
204 {
205 lat_min = Constants::min_latitude();
206 lat_max = Constants::max_latitude();
207 }
208 else if (has_south_pole)
209 {
210 lat_min = Constants::min_latitude();
211 lat_max
212 = geometry::get<1>(*std::max_element(first, last, lat_less));
213 }
214 else if (has_north_pole)
215 {
216 lat_min
217 = geometry::get<1>(*std::min_element(first, last, lat_less));
218 lat_max = Constants::max_latitude();
219 }
220 else
221 {
222 std::pair<Iterator, Iterator> min_max_latitudes
223 = boost::minmax_element(first, last, lat_less);
224
225 lat_min = geometry::get<1>(*min_max_latitudes.first);
226 lat_max = geometry::get<1>(*min_max_latitudes.second);
227 }
228 }
229
230 public:
231 template <typename MultiPoint, typename Box>
232 static inline void apply(MultiPoint const& multipoint, Box& mbr)
233 {
234 typedef typename point_type<MultiPoint>::type point_type;
235 typedef typename coordinate_type<MultiPoint>::type coordinate_type;
236 typedef typename boost::range_iterator
237 <
238 MultiPoint const
239 >::type iterator_type;
240
241 typedef math::detail::constants_on_spheroid
242 <
243 coordinate_type,
244 typename geometry::detail::cs_angular_units<MultiPoint>::type
245 > constants;
246
247 if (boost::empty(multipoint))
248 {
249 geometry::detail::envelope::initialize<Box, 0, dimension<Box>::value>::apply(mbr);
250 return;
251 }
252
253 geometry::detail::envelope::initialize<Box, 0, 2>::apply(mbr);
254
255 if (boost::size(multipoint) == 1)
256 {
257 return dispatch::envelope
258 <
259 typename boost::range_value<MultiPoint>::type
260 >::apply(range::front(multipoint), mbr, strategy::envelope::spherical_point());
261 }
262
263 // analyze the points and put the non-pole ones in the
264 // points vector
265 std::vector<point_type> points;
266 bool has_north_pole = false, has_south_pole = false;
267
268 analyze_point_coordinates<constants>(multipoint,
269 has_south_pole, has_north_pole,
270 std::back_inserter(points));
271
272 coordinate_type lon_min, lat_min, lon_max, lat_max;
273 if (points.size() == 1)
274 {
275 // we have one non-pole point and at least one pole point
276 lon_min = geometry::get<0>(range::front(points));
277 lon_max = geometry::get<0>(range::front(points));
278 lat_min = has_south_pole
279 ? constants::min_latitude()
280 : constants::max_latitude();
281 lat_max = has_north_pole
282 ? constants::max_latitude()
283 : constants::min_latitude();
284 }
285 else if (points.empty())
286 {
287 // all points are pole points
288 BOOST_GEOMETRY_ASSERT(has_south_pole || has_north_pole);
289 lon_min = coordinate_type(0);
290 lon_max = coordinate_type(0);
291 lat_min = has_south_pole
292 ? constants::min_latitude()
293 : constants::max_latitude();
294 lat_max = (has_north_pole)
295 ? constants::max_latitude()
296 : constants::min_latitude();
297 }
298 else
299 {
300 get_min_max_longitudes<constants>(points,
301 coordinate_less<0>(),
302 lon_min,
303 lon_max);
304
305 get_min_max_latitudes<constants>(points.begin(),
306 points.end(),
307 coordinate_less<1>(),
308 has_south_pole,
309 has_north_pole,
310 lat_min,
311 lat_max);
312 }
313
314 typedef typename helper_geometry
315 <
316 Box,
317 coordinate_type,
318 typename geometry::detail::cs_angular_units<MultiPoint>::type
319 >::type helper_box_type;
320
321 helper_box_type helper_mbr;
322
323 geometry::set<min_corner, 0>(helper_mbr, lon_min);
324 geometry::set<min_corner, 1>(helper_mbr, lat_min);
325 geometry::set<max_corner, 0>(helper_mbr, lon_max);
326 geometry::set<max_corner, 1>(helper_mbr, lat_max);
327
328 // now transform to output MBR (per index)
329 geometry::detail::envelope::envelope_indexed_box_on_spheroid<min_corner, 2>::apply(helper_mbr, mbr);
330 geometry::detail::envelope::envelope_indexed_box_on_spheroid<max_corner, 2>::apply(helper_mbr, mbr);
331
332 // compute envelope for higher coordinates
333 iterator_type it = boost::begin(multipoint);
334 geometry::detail::envelope::envelope_one_point<2, dimension<Box>::value>::apply(*it, mbr);
335
336 for (++it; it != boost::end(multipoint); ++it)
337 {
338 strategy::expand::detail::point_loop
339 <
340 2, dimension<Box>::value
341 >::apply(mbr, *it);
342 }
343 }
344 };
345
346
347 #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
348
349 namespace services
350 {
351
352 template <typename CalculationType>
353 struct default_strategy<multi_point_tag, spherical_equatorial_tag, CalculationType>
354 {
355 typedef strategy::envelope::spherical_multipoint type;
356 };
357
358 template <typename CalculationType>
359 struct default_strategy<multi_point_tag, spherical_polar_tag, CalculationType>
360 {
361 typedef strategy::envelope::spherical_multipoint type;
362 };
363
364 template <typename CalculationType>
365 struct default_strategy<multi_point_tag, geographic_tag, CalculationType>
366 {
367 typedef strategy::envelope::spherical_multipoint type;
368 };
369
370 } // namespace services
371
372 #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
373
374
375 }} // namespace strategy::envelope
376
377 }} // namespace boost::geometry
378
379 #endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_ENVELOPE_MULTIPOINT_HPP