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 // Licensed under the Boost Software License version 1.0.
8 // http://www.boost.org/users/license.html
9 
10 #ifndef BOOST_GEOMETRY_UTIL_NORMALIZE_SPHEROIDAL_BOX_COORDINATES_HPP
11 #define BOOST_GEOMETRY_UTIL_NORMALIZE_SPHEROIDAL_BOX_COORDINATES_HPP
12 
13 #include <boost/geometry/core/assert.hpp>
14 #include <boost/geometry/util/math.hpp>
15 #include <boost/geometry/util/normalize_spheroidal_coordinates.hpp>
16 
17 
18 namespace boost { namespace geometry
19 {
20 
21 namespace math
22 {
23 
24 #ifndef DOXYGEN_NO_DETAIL
25 namespace detail
26 {
27 
28 
29 template <typename Units, typename CoordinateType>
30 class normalize_spheroidal_box_coordinates
31 {
32 private:
33     typedef normalize_spheroidal_coordinates<Units, CoordinateType> normalize;
34     typedef constants_on_spheroid<CoordinateType, Units> constants;
35 
is_band(CoordinateType const & longitude1,CoordinateType const & longitude2)36     static inline bool is_band(CoordinateType const& longitude1,
37                                CoordinateType const& longitude2)
38     {
39         return ! math::smaller(math::abs(longitude1 - longitude2),
40                                constants::period());
41     }
42 
43 public:
apply(CoordinateType & longitude1,CoordinateType & latitude1,CoordinateType & longitude2,CoordinateType & latitude2,bool band)44     static inline void apply(CoordinateType& longitude1,
45                              CoordinateType& latitude1,
46                              CoordinateType& longitude2,
47                              CoordinateType& latitude2,
48                              bool band)
49     {
50         normalize::apply(longitude1, latitude1, false);
51         normalize::apply(longitude2, latitude2, false);
52 
53         if (math::equals(latitude1, constants::min_latitude())
54             && math::equals(latitude2, constants::min_latitude()))
55         {
56             // box degenerates to the south pole
57             longitude1 = longitude2 = CoordinateType(0);
58         }
59         else if (math::equals(latitude1, constants::max_latitude())
60                  && math::equals(latitude2, constants::max_latitude()))
61         {
62             // box degenerates to the north pole
63             longitude1 = longitude2 = CoordinateType(0);
64         }
65         else if (band)
66         {
67             // the box is a band between two small circles (parallel
68             // to the equator) on the spheroid
69             longitude1 = constants::min_longitude();
70             longitude2 = constants::max_longitude();
71         }
72         else if (longitude1 > longitude2)
73         {
74             // the box crosses the antimeridian, so we need to adjust
75             // the longitudes
76             longitude2 += constants::period();
77         }
78 
79 #ifdef BOOST_GEOMETRY_NORMALIZE_LATITUDE
80         BOOST_GEOMETRY_ASSERT(! math::larger(latitude1, latitude2));
81         BOOST_GEOMETRY_ASSERT(! math::smaller(latitude1, constants::min_latitude()));
82         BOOST_GEOMETRY_ASSERT(! math::larger(latitude2, constants::max_latitude()));
83 #endif
84 
85         BOOST_GEOMETRY_ASSERT(! math::larger(longitude1, longitude2));
86         BOOST_GEOMETRY_ASSERT(! math::smaller(longitude1, constants::min_longitude()));
87         BOOST_GEOMETRY_ASSERT
88             (! math::larger(longitude2 - longitude1, constants::period()));
89     }
90 
apply(CoordinateType & longitude1,CoordinateType & latitude1,CoordinateType & longitude2,CoordinateType & latitude2)91     static inline void apply(CoordinateType& longitude1,
92                              CoordinateType& latitude1,
93                              CoordinateType& longitude2,
94                              CoordinateType& latitude2)
95     {
96         bool const band = is_band(longitude1, longitude2);
97 
98         apply(longitude1, latitude1, longitude2, latitude2, band);
99     }
100 };
101 
102 
103 } // namespace detail
104 #endif // DOXYGEN_NO_DETAIL
105 
106 
107 /*!
108 \brief Short utility to normalize the coordinates of a box on a spheroid
109 \tparam Units The units of the coordindate system in the spheroid
110 \tparam CoordinateType The type of the coordinates
111 \param longitude1 Minimum longitude of the box
112 \param latitude1 Minimum latitude of the box
113 \param longitude2 Maximum longitude of the box
114 \param latitude2 Maximum latitude of the box
115 \ingroup utility
116 */
117 template <typename Units, typename CoordinateType>
normalize_spheroidal_box_coordinates(CoordinateType & longitude1,CoordinateType & latitude1,CoordinateType & longitude2,CoordinateType & latitude2)118 inline void normalize_spheroidal_box_coordinates(CoordinateType& longitude1,
119                                                  CoordinateType& latitude1,
120                                                  CoordinateType& longitude2,
121                                                  CoordinateType& latitude2)
122 {
123     detail::normalize_spheroidal_box_coordinates
124         <
125             Units, CoordinateType
126         >::apply(longitude1, latitude1, longitude2, latitude2);
127 }
128 
129 /*!
130 \brief Short utility to normalize the coordinates of a box on a spheroid
131 \tparam Units The units of the coordindate system in the spheroid
132 \tparam CoordinateType The type of the coordinates
133 \param longitude1 Minimum longitude of the box
134 \param latitude1 Minimum latitude of the box
135 \param longitude2 Maximum longitude of the box
136 \param latitude2 Maximum latitude of the box
137 \param band Indicates whether the box should be treated as a band or
138        not and avoid the computation done in the other version of the function
139 \ingroup utility
140 */
141 template <typename Units, typename CoordinateType>
normalize_spheroidal_box_coordinates(CoordinateType & longitude1,CoordinateType & latitude1,CoordinateType & longitude2,CoordinateType & latitude2,bool band)142 inline void normalize_spheroidal_box_coordinates(CoordinateType& longitude1,
143                                                  CoordinateType& latitude1,
144                                                  CoordinateType& longitude2,
145                                                  CoordinateType& latitude2,
146                                                  bool band)
147 {
148     detail::normalize_spheroidal_box_coordinates
149         <
150             Units, CoordinateType
151         >::apply(longitude1, latitude1, longitude2, latitude2, band);
152 }
153 
154 
155 } // namespace math
156 
157 
158 }} // namespace boost::geometry
159 
160 #endif // BOOST_GEOMETRY_UTIL_NORMALIZE_SPHEROIDAL_BOX_COORDINATES_HPP
161