]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/geometry/algorithms/detail/envelope/segment.hpp
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / boost / boost / geometry / algorithms / detail / envelope / segment.hpp
CommitLineData
7c673cae
FG
1// Boost.Geometry (aka GGL, Generic Geometry Library)
2
3// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
4// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
5// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
6
b32b8144
FG
7// This file was modified by Oracle on 2015-2017.
8// Modifications copyright (c) 2015-2017, Oracle and/or its affiliates.
7c673cae 9
b32b8144 10// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
7c673cae
FG
11// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
12// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
13
14// Distributed under the Boost Software License, Version 1.0.
15// (See accompanying file LICENSE_1_0.txt or copy at
16// http://www.boost.org/LICENSE_1_0.txt)
17
18#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_SEGMENT_HPP
19#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_SEGMENT_HPP
20
21#include <cstddef>
22#include <utility>
23
24#include <boost/numeric/conversion/cast.hpp>
25
26#include <boost/geometry/core/assert.hpp>
27#include <boost/geometry/core/coordinate_system.hpp>
28#include <boost/geometry/core/coordinate_type.hpp>
29#include <boost/geometry/core/cs.hpp>
30#include <boost/geometry/core/point_type.hpp>
31#include <boost/geometry/core/radian_access.hpp>
32#include <boost/geometry/core/tags.hpp>
33
34#include <boost/geometry/util/math.hpp>
35
36#include <boost/geometry/geometries/helper_geometry.hpp>
37
b32b8144 38#include <boost/geometry/formulas/vertex_latitude.hpp>
7c673cae
FG
39
40#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
7c673cae
FG
41
42#include <boost/geometry/algorithms/detail/envelope/point.hpp>
43#include <boost/geometry/algorithms/detail/envelope/transform_units.hpp>
44
45#include <boost/geometry/algorithms/detail/expand/point.hpp>
46
47#include <boost/geometry/algorithms/dispatch/envelope.hpp>
48
7c673cae
FG
49namespace boost { namespace geometry
50{
51
52#ifndef DOXYGEN_NO_DETAIL
53namespace detail { namespace envelope
54{
55
b32b8144
FG
56template <typename CalculationType, typename CS_Tag>
57struct envelope_segment_call_vertex_latitude
58{
59 template <typename T1, typename T2, typename Strategy>
60 static inline CalculationType apply(T1 const& lat1,
61 T2 const& alp1,
62 Strategy const& )
63 {
64 return geometry::formula::vertex_latitude<CalculationType, CS_Tag>
65 ::apply(lat1, alp1);
66 }
67};
7c673cae 68
b32b8144
FG
69template <typename CalculationType>
70struct envelope_segment_call_vertex_latitude<CalculationType, geographic_tag>
7c673cae 71{
b32b8144
FG
72 template <typename T1, typename T2, typename Strategy>
73 static inline CalculationType apply(T1 const& lat1,
74 T2 const& alp1,
75 Strategy const& strategy)
7c673cae 76 {
b32b8144
FG
77 return geometry::formula::vertex_latitude<CalculationType, geographic_tag>
78 ::apply(lat1, alp1, strategy.model());
7c673cae
FG
79 }
80};
81
b32b8144
FG
82template <typename Units, typename CS_Tag>
83struct envelope_segment_convert_polar
84{
85 template <typename T>
86 static inline void pre(T & , T & ) {}
7c673cae 87
b32b8144
FG
88 template <typename T>
89 static inline void post(T & , T & ) {}
90};
91
92template <typename Units>
93struct envelope_segment_convert_polar<Units, spherical_polar_tag>
7c673cae 94{
b32b8144
FG
95 template <typename T>
96 static inline void pre(T & lat1, T & lat2)
7c673cae 97 {
b32b8144
FG
98 lat1 = math::latitude_convert_ep<Units>(lat1);
99 lat2 = math::latitude_convert_ep<Units>(lat2);
100 }
7c673cae 101
b32b8144
FG
102 template <typename T>
103 static inline void post(T & lat1, T & lat2)
104 {
105 lat1 = math::latitude_convert_ep<Units>(lat1);
106 lat2 = math::latitude_convert_ep<Units>(lat2);
107 std::swap(lat1, lat2);
7c673cae 108 }
b32b8144
FG
109};
110
111template <typename CS_Tag>
112class envelope_segment_impl
113{
114private:
7c673cae
FG
115
116 // degrees or radians
117 template <typename CalculationType>
118 static inline void swap(CalculationType& lon1,
119 CalculationType& lat1,
120 CalculationType& lon2,
121 CalculationType& lat2)
122 {
123 std::swap(lon1, lon2);
124 std::swap(lat1, lat2);
125 }
126
127 // radians
128 template <typename CalculationType>
129 static inline bool contains_pi_half(CalculationType const& a1,
130 CalculationType const& a2)
131 {
132 // azimuths a1 and a2 are assumed to be in radians
133 BOOST_GEOMETRY_ASSERT(! math::equals(a1, a2));
134
135 static CalculationType const pi_half = math::half_pi<CalculationType>();
136
137 return (a1 < a2)
b32b8144
FG
138 ? (a1 < pi_half && pi_half < a2)
139 : (a1 > pi_half && pi_half > a2);
7c673cae
FG
140 }
141
142 // radians or degrees
143 template <typename Units, typename CoordinateType>
144 static inline bool crosses_antimeridian(CoordinateType const& lon1,
145 CoordinateType const& lon2)
146 {
147 typedef math::detail::constants_on_spheroid
148 <
149 CoordinateType, Units
150 > constants;
151
152 return math::abs(lon1 - lon2) > constants::half_period(); // > pi
153 }
154
7c673cae 155 // degrees or radians
b32b8144 156 template <typename Units, typename CalculationType, typename Strategy>
7c673cae
FG
157 static inline void compute_box_corners(CalculationType& lon1,
158 CalculationType& lat1,
159 CalculationType& lon2,
b32b8144
FG
160 CalculationType& lat2,
161 CalculationType a1,
162 CalculationType a2,
163 Strategy const& strategy)
7c673cae
FG
164 {
165 // coordinates are assumed to be in radians
166 BOOST_GEOMETRY_ASSERT(lon1 <= lon2);
167
7c673cae 168 CalculationType lat1_rad = math::as_radian<Units>(lat1);
7c673cae
FG
169 CalculationType lat2_rad = math::as_radian<Units>(lat2);
170
7c673cae
FG
171 if (lat1 > lat2)
172 {
173 std::swap(lat1, lat2);
174 std::swap(lat1_rad, lat2_rad);
b32b8144 175 std::swap(a1, a2);
7c673cae
FG
176 }
177
178 if (math::equals(a1, a2))
179 {
180 // the segment must lie on the equator or is very short
181 return;
182 }
183
184 if (contains_pi_half(a1, a2))
185 {
b32b8144
FG
186 CalculationType p_max = envelope_segment_call_vertex_latitude
187 <CalculationType, CS_Tag>::apply(lat1_rad, a1, strategy);
188
7c673cae
FG
189 CalculationType const mid_lat = lat1 + lat2;
190 if (mid_lat < 0)
191 {
192 // update using min latitude
b32b8144
FG
193 CalculationType const lat_min_rad = -p_max;
194 CalculationType const lat_min
195 = math::from_radian<Units>(lat_min_rad);
7c673cae
FG
196
197 if (lat1 > lat_min)
198 {
199 lat1 = lat_min;
200 }
201 }
b32b8144 202 else
7c673cae
FG
203 {
204 // update using max latitude
b32b8144
FG
205 CalculationType const lat_max_rad = p_max;
206 CalculationType const lat_max
207 = math::from_radian<Units>(lat_max_rad);
7c673cae
FG
208
209 if (lat2 < lat_max)
210 {
211 lat2 = lat_max;
212 }
213 }
214 }
215 }
216
217 template <typename Units, typename CalculationType>
b32b8144
FG
218 static inline void special_cases(CalculationType& lon1,
219 CalculationType& lat1,
220 CalculationType& lon2,
221 CalculationType& lat2)
7c673cae
FG
222 {
223 typedef math::detail::constants_on_spheroid
224 <
225 CalculationType, Units
226 > constants;
227
228 bool is_pole1 = math::equals(math::abs(lat1), constants::max_latitude());
229 bool is_pole2 = math::equals(math::abs(lat2), constants::max_latitude());
230
231 if (is_pole1 && is_pole2)
232 {
233 // both points are poles; nothing more to do:
234 // longitudes are already normalized to 0
235 // but just in case
236 lon1 = 0;
237 lon2 = 0;
238 }
239 else if (is_pole1 && !is_pole2)
240 {
241 // first point is a pole, second point is not:
242 // make the longitude of the first point the same as that
243 // of the second point
244 lon1 = lon2;
245 }
246 else if (!is_pole1 && is_pole2)
247 {
248 // second point is a pole, first point is not:
249 // make the longitude of the second point the same as that
250 // of the first point
251 lon2 = lon1;
252 }
253
254 if (lon1 == lon2)
255 {
256 // segment lies on a meridian
257 if (lat1 > lat2)
258 {
259 std::swap(lat1, lat2);
260 }
261 return;
262 }
263
264 BOOST_GEOMETRY_ASSERT(!is_pole1 && !is_pole2);
265
266 if (lon1 > lon2)
267 {
268 swap(lon1, lat1, lon2, lat2);
269 }
270
271 if (crosses_antimeridian<Units>(lon1, lon2))
272 {
273 lon1 += constants::period();
274 swap(lon1, lat1, lon2, lat2);
275 }
7c673cae
FG
276 }
277
b32b8144
FG
278 template
279 <
280 typename Units,
281 typename CalculationType,
282 typename Box
283 >
284 static inline void create_box(CalculationType lon1,
285 CalculationType lat1,
286 CalculationType lon2,
287 CalculationType lat2,
288 Box& mbr)
7c673cae
FG
289 {
290 typedef typename coordinate_type<Box>::type box_coordinate_type;
291
292 typedef typename helper_geometry
293 <
294 Box, box_coordinate_type, Units
295 >::type helper_box_type;
296
b32b8144 297 helper_box_type helper_mbr;
7c673cae
FG
298
299 geometry::set
300 <
301 min_corner, 0
b32b8144 302 >(helper_mbr, boost::numeric_cast<box_coordinate_type>(lon1));
7c673cae
FG
303
304 geometry::set
305 <
306 min_corner, 1
b32b8144 307 >(helper_mbr, boost::numeric_cast<box_coordinate_type>(lat1));
7c673cae
FG
308
309 geometry::set
310 <
311 max_corner, 0
b32b8144 312 >(helper_mbr, boost::numeric_cast<box_coordinate_type>(lon2));
7c673cae
FG
313
314 geometry::set
315 <
316 max_corner, 1
b32b8144 317 >(helper_mbr, boost::numeric_cast<box_coordinate_type>(lat2));
7c673cae 318
b32b8144 319 transform_units(helper_mbr, mbr);
7c673cae 320 }
7c673cae
FG
321
322
b32b8144
FG
323 template <typename Units, typename CalculationType, typename Strategy>
324 static inline void apply(CalculationType& lon1,
325 CalculationType& lat1,
326 CalculationType& lon2,
327 CalculationType& lat2,
328 Strategy const& strategy)
7c673cae 329 {
b32b8144 330 special_cases<Units>(lon1, lat1, lon2, lat2);
7c673cae 331
b32b8144
FG
332 CalculationType lon1_rad = math::as_radian<Units>(lon1);
333 CalculationType lat1_rad = math::as_radian<Units>(lat1);
334 CalculationType lon2_rad = math::as_radian<Units>(lon2);
335 CalculationType lat2_rad = math::as_radian<Units>(lat2);
336 CalculationType alp1, alp2;
337 strategy.apply(lon1_rad, lat1_rad, lon2_rad, lat2_rad, alp1, alp2);
7c673cae 338
b32b8144
FG
339 compute_box_corners<Units>(lon1, lat1, lon2, lat2, alp1, alp2, strategy);
340 }
7c673cae 341
b32b8144
FG
342 template <typename Units, typename CalculationType, typename Strategy>
343 static inline void apply(CalculationType& lon1,
344 CalculationType& lat1,
345 CalculationType& lon2,
346 CalculationType& lat2,
347 Strategy const& strategy,
348 CalculationType alp1)
349 {
350 special_cases<Units>(lon1, lat1, lon2, lat2);
351
352 CalculationType lon1_rad = math::as_radian<Units>(lon1);
353 CalculationType lat1_rad = math::as_radian<Units>(lat1);
354 CalculationType lon2_rad = math::as_radian<Units>(lon2);
355 CalculationType lat2_rad = math::as_radian<Units>(lat2);
356 CalculationType alp2;
357 strategy.apply(lon2_rad, lat2_rad, lon1_rad, lat1_rad, alp2);
358 alp2 += math::pi<CalculationType>();
359
360 compute_box_corners<Units>(lon1, lat1, lon2, lat2, alp1, alp2, strategy);
7c673cae
FG
361 }
362
b32b8144
FG
363public:
364 template
365 <
366 typename Units,
367 typename CalculationType,
368 typename Box,
369 typename Strategy
370 >
371 static inline void apply(CalculationType lon1,
372 CalculationType lat1,
373 CalculationType lon2,
374 CalculationType lat2,
375 Box& mbr,
376 Strategy const& strategy)
7c673cae 377 {
b32b8144
FG
378 typedef envelope_segment_convert_polar<Units, typename cs_tag<Box>::type> convert_polar;
379
380 convert_polar::pre(lat1, lat2);
381
382 apply<Units>(lon1, lat1, lon2, lat2, strategy);
383
384 convert_polar::post(lat1, lat2);
385
386 create_box<Units>(lon1, lat1, lon2, lat2, mbr);
7c673cae 387 }
7c673cae 388
b32b8144
FG
389 template
390 <
391 typename Units,
392 typename CalculationType,
393 typename Box,
394 typename Strategy
395 >
396 static inline void apply(CalculationType lon1,
397 CalculationType lat1,
398 CalculationType lon2,
399 CalculationType lat2,
400 Box& mbr,
401 Strategy const& strategy,
402 CalculationType alp1)
403 {
404 typedef envelope_segment_convert_polar<Units, typename cs_tag<Box>::type> convert_polar;
7c673cae 405
b32b8144 406 convert_polar::pre(lat1, lat2);
7c673cae 407
b32b8144
FG
408 apply<Units>(lon1, lat1, lon2, lat2, strategy, alp1);
409
410 convert_polar::post(lat1, lat2);
411
412 create_box<Units>(lon1, lat1, lon2, lat2, mbr);
413 }
414};
415
416template <std::size_t Dimension, std::size_t DimensionCount>
417struct envelope_one_segment
418{
419 template<typename Point, typename Box, typename Strategy>
420 static inline void apply(Point const& p1,
421 Point const& p2,
422 Box& mbr,
423 Strategy const& strategy)
424 {
425 envelope_one_point<Dimension, DimensionCount>::apply(p1, mbr, strategy);
426 detail::expand::point_loop
427 <
428 Dimension,
429 DimensionCount
430 >::apply(mbr, p2, strategy);
431 }
432};
7c673cae
FG
433
434
435template <std::size_t DimensionCount>
b32b8144
FG
436struct envelope_segment
437{
438 template <typename Point, typename Box, typename Strategy>
439 static inline void apply(Point const& p1,
440 Point const& p2,
441 Box& mbr,
442 Strategy const& strategy)
443 {
444 // first compute the envelope range for the first two coordinates
445 strategy.apply(p1, p2, mbr);
7c673cae 446
b32b8144
FG
447 // now compute the envelope range for coordinates of
448 // dimension 2 and higher
449 envelope_one_segment<2, DimensionCount>::apply(p1, p2, mbr, strategy);
450 }
7c673cae 451
b32b8144
FG
452 template <typename Segment, typename Box, typename Strategy>
453 static inline void apply(Segment const& segment, Box& mbr,
454 Strategy const& strategy)
455 {
456 typename point_type<Segment>::type p[2];
457 detail::assign_point_from_index<0>(segment, p[0]);
458 detail::assign_point_from_index<1>(segment, p[1]);
459 apply(p[0], p[1], mbr, strategy);
460 }
461};
7c673cae
FG
462
463}} // namespace detail::envelope
464#endif // DOXYGEN_NO_DETAIL
465
466
467#ifndef DOXYGEN_NO_DISPATCH
468namespace dispatch
469{
470
471
b32b8144
FG
472template <typename Segment>
473struct envelope<Segment, segment_tag>
7c673cae 474{
b32b8144
FG
475 template <typename Box, typename Strategy>
476 static inline void apply(Segment const& segment,
477 Box& mbr,
478 Strategy const& strategy)
7c673cae
FG
479 {
480 typename point_type<Segment>::type p[2];
481 detail::assign_point_from_index<0>(segment, p[0]);
482 detail::assign_point_from_index<1>(segment, p[1]);
483 detail::envelope::envelope_segment
484 <
b32b8144
FG
485 dimension<Segment>::value
486 >::apply(p[0], p[1], mbr, strategy);
7c673cae
FG
487 }
488};
489
7c673cae
FG
490} // namespace dispatch
491#endif // DOXYGEN_NO_DISPATCH
492
493}} // namespace boost::geometry
494
495#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_SEGMENT_HPP