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