1 // Boost.Geometry (aka GGL, Generic Geometry Library)
3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
5 // This file was modified by Oracle on 2017.
6 // Modifications copyright (c) 2017, Oracle and/or its affiliates.
8 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
10 // Use, modification and distribution is subject to the Boost Software License,
11 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
12 // http://www.boost.org/LICENSE_1_0.txt)
14 #ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_COMPARE_HPP
15 #define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_COMPARE_HPP
18 #include <boost/mpl/if.hpp>
19 #include <boost/mpl/min.hpp>
21 #include <boost/type_traits/is_same.hpp>
23 #include <boost/geometry/core/access.hpp>
24 #include <boost/geometry/core/coordinate_dimension.hpp>
25 #include <boost/geometry/core/coordinate_system.hpp>
26 #include <boost/geometry/core/coordinate_type.hpp>
27 #include <boost/geometry/core/cs.hpp>
28 #include <boost/geometry/core/tags.hpp>
30 #include <boost/geometry/strategies/compare.hpp>
32 #include <boost/geometry/util/math.hpp>
33 #include <boost/geometry/util/normalize_spheroidal_coordinates.hpp>
36 namespace boost { namespace geometry
40 namespace strategy { namespace compare
44 #ifndef DOXYGEN_NO_DETAIL
48 template <std::size_t I, typename P>
49 static inline typename geometry::coordinate_type<P>::type
50 get(P const& p, boost::true_type /*same units*/)
52 return geometry::get<I>(p);
55 template <std::size_t I, typename P>
56 static inline typename geometry::coordinate_type<P>::type
57 get(P const& p, boost::false_type /*different units*/)
59 return geometry::get_as_radian<I>(p);
64 typename ComparePolicy,
67 std::size_t DimensionCount
69 struct spherical_latitude
71 typedef typename geometry::coordinate_type<Point1>::type coordinate1_type;
72 typedef typename geometry::coordinate_system<Point1>::type::units units1_type;
73 typedef typename geometry::coordinate_type<Point2>::type coordinate2_type;
74 typedef typename geometry::coordinate_system<Point2>::type::units units2_type;
75 typedef typename boost::is_same<units1_type, units2_type>::type same_units_type;
77 template <typename T1, typename T2>
78 static inline bool apply(Point1 const& left, Point2 const& right,
79 T1 const& l1, T2 const& r1)
82 if (math::equals(l1, r1))
84 return compare::detail::compare_loop
86 ComparePolicy, 2, DimensionCount
87 >::apply(left, right);
91 return ComparePolicy::apply(l1, r1);
95 static inline bool apply(Point1 const& left, Point2 const& right)
97 coordinate1_type const& l1 = compare::detail::get<1>(left, same_units_type());
98 coordinate2_type const& r1 = compare::detail::get<1>(right, same_units_type());
100 return apply(left, right, l1, r1);
106 typename ComparePolicy,
110 struct spherical_latitude<ComparePolicy, Point1, Point2, 1>
112 template <typename T1, typename T2>
113 static inline bool apply(Point1 const& left, Point2 const& right,
114 T1 const& , T2 const& )
116 return apply(left, right);
119 static inline bool apply(Point1 const& left, Point2 const& right)
121 return compare::detail::compare_loop
124 >::apply(left, right);
130 typename ComparePolicy,
133 std::size_t DimensionCount
135 struct spherical_longitude
137 typedef typename geometry::coordinate_type<Point1>::type coordinate1_type;
138 typedef typename geometry::coordinate_system<Point1>::type::units units1_type;
139 typedef typename geometry::coordinate_type<Point2>::type coordinate2_type;
140 typedef typename geometry::coordinate_system<Point2>::type::units units2_type;
141 typedef typename boost::is_same<units1_type, units2_type>::type same_units_type;
142 typedef typename boost::mpl::if_<same_units_type, units1_type, geometry::radian>::type units_type;
144 static const bool is_equatorial = ! boost::is_same
146 typename geometry::cs_tag<Point1>::type,
147 geometry::spherical_polar_tag
150 static inline bool are_both_at_antimeridian(coordinate1_type const& l0,
151 coordinate2_type const& r0,
155 is_left_at = math::is_longitude_antimeridian<units_type>(l0);
156 is_right_at = math::is_longitude_antimeridian<units_type>(r0);
157 return is_left_at && is_right_at;
160 static inline bool apply(Point1 const& left, Point2 const& right)
162 // if units are different the coordinates are in radians
163 coordinate1_type const& l0 = compare::detail::get<0>(left, same_units_type());
164 coordinate2_type const& r0 = compare::detail::get<0>(right, same_units_type());
165 coordinate1_type const& l1 = compare::detail::get<1>(left, same_units_type());
166 coordinate2_type const& r1 = compare::detail::get<1>(right, same_units_type());
168 bool is_left_at_antimeridian = false;
169 bool is_right_at_antimeridian = false;
172 if (math::equals(l0, r0)
173 // both at antimeridian
174 || are_both_at_antimeridian(l0, r0, is_left_at_antimeridian, is_right_at_antimeridian)
176 || (math::equals(l1, r1)
177 && math::is_latitude_pole<units_type, is_equatorial>(l1)))
179 return spherical_latitude
181 ComparePolicy, Point1, Point2, DimensionCount
182 >::apply(left, right, l1, r1);
184 // if left is at antimeridian and right is not at antimeridian
185 // then left is greater than right
186 else if (is_left_at_antimeridian)
188 // less/equal_to -> false, greater -> true
189 return ComparePolicy::apply(1, 0);
191 // if right is at antimeridian and left is not at antimeridian
192 // then left is lesser than right
193 else if (is_right_at_antimeridian)
195 // less -> true, equal_to/greater -> false
196 return ComparePolicy::apply(0, 1);
200 return ComparePolicy::apply(l0, r0);
206 } // namespace detail
207 #endif // DOXYGEN_NO_DETAIL
211 \brief Compare strategy for spherical coordinates
213 \tparam Point point-type
214 \tparam Dimension dimension
218 typename ComparePolicy,
222 : cartesian<ComparePolicy, Dimension>
225 #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
226 // all dimensions starting from longitude
227 template <typename ComparePolicy>
228 struct spherical<ComparePolicy, -1>
230 template <typename Point1, typename Point2>
231 static inline bool apply(Point1 const& left, Point2 const& right)
233 return compare::detail::spherical_longitude
240 geometry::dimension<Point1>,
241 geometry::dimension<Point2>
243 >::apply(left, right);
247 // only longitudes (and latitudes to check poles)
248 template <typename ComparePolicy>
249 struct spherical<ComparePolicy, 0>
251 template <typename Point1, typename Point2>
252 static inline bool apply(Point1 const& left, Point2 const& right)
254 return compare::detail::spherical_longitude
256 ComparePolicy, Point1, Point2, 1
257 >::apply(left, right);
262 template <typename ComparePolicy>
263 struct spherical<ComparePolicy, 1>
265 template <typename Point1, typename Point2>
266 static inline bool apply(Point1 const& left, Point2 const& right)
268 return compare::detail::spherical_latitude
270 ComparePolicy, Point1, Point2, 2
271 >::apply(left, right);
275 #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
282 template <typename ComparePolicy, typename Point1, typename Point2, int Dimension>
283 struct default_strategy
285 ComparePolicy, Point1, Point2, Dimension,
286 spherical_polar_tag, spherical_polar_tag
289 typedef compare::spherical<ComparePolicy, Dimension> type;
292 template <typename ComparePolicy, typename Point1, typename Point2, int Dimension>
293 struct default_strategy
295 ComparePolicy, Point1, Point2, Dimension,
296 spherical_equatorial_tag, spherical_equatorial_tag
299 typedef compare::spherical<ComparePolicy, Dimension> type;
302 template <typename ComparePolicy, typename Point1, typename Point2, int Dimension>
303 struct default_strategy
305 ComparePolicy, Point1, Point2, Dimension,
306 geographic_tag, geographic_tag
309 typedef compare::spherical<ComparePolicy, Dimension> type;
313 } // namespace services
316 }} // namespace strategy::compare
319 }} // namespace boost::geometry
321 #endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_COMPARE_HPP