1 // Boost.Geometry (aka GGL, Generic Geometry Library)
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 // Copyright (c) 2014-2015 Samuel Debionne, Grenoble, France.
8 // This file was modified by Oracle on 2015, 2016, 2017.
9 // Modifications copyright (c) 2015-2017, Oracle and/or its affiliates.
11 // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
12 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
13 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
15 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
16 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
18 // Distributed under the Boost Software License, Version 1.0.
19 // (See accompanying file LICENSE_1_0.txt or copy at
20 // http://www.boost.org/LICENSE_1_0.txt)
22 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_POINT_HPP
23 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_POINT_HPP
29 #include <boost/mpl/assert.hpp>
30 #include <boost/type_traits/is_same.hpp>
32 #include <boost/geometry/core/access.hpp>
33 #include <boost/geometry/core/coordinate_dimension.hpp>
34 #include <boost/geometry/core/coordinate_system.hpp>
35 #include <boost/geometry/core/coordinate_type.hpp>
36 #include <boost/geometry/core/tags.hpp>
38 #include <boost/geometry/util/math.hpp>
39 #include <boost/geometry/util/select_coordinate_type.hpp>
41 #include <boost/geometry/algorithms/detail/normalize.hpp>
42 #include <boost/geometry/algorithms/detail/envelope/transform_units.hpp>
44 #include <boost/geometry/algorithms/dispatch/expand.hpp>
47 namespace boost { namespace geometry
50 #ifndef DOXYGEN_NO_DETAIL
51 namespace detail { namespace expand
55 template <std::size_t Dimension, std::size_t DimensionCount>
58 template <typename Box, typename Point, typename Strategy>
59 static inline void apply(Box& box, Point const& source, Strategy const& strategy)
61 typedef typename select_coordinate_type
64 >::type coordinate_type;
66 std::less<coordinate_type> less;
67 std::greater<coordinate_type> greater;
69 coordinate_type const coord = get<Dimension>(source);
71 if (less(coord, get<min_corner, Dimension>(box)))
73 set<min_corner, Dimension>(box, coord);
76 if (greater(coord, get<max_corner, Dimension>(box)))
78 set<max_corner, Dimension>(box, coord);
81 point_loop<Dimension + 1, DimensionCount>::apply(box, source, strategy);
86 template <std::size_t DimensionCount>
87 struct point_loop<DimensionCount, DimensionCount>
89 template <typename Box, typename Point, typename Strategy>
90 static inline void apply(Box&, Point const&, Strategy const&) {}
94 // implementation for the spherical and geographic coordinate systems
95 template <std::size_t DimensionCount, bool IsEquatorial = true>
96 struct point_loop_on_spheroid
98 template <typename Box, typename Point, typename Strategy>
99 static inline void apply(Box& box,
101 Strategy const& strategy)
103 typedef typename point_type<Box>::type box_point_type;
104 typedef typename coordinate_type<Box>::type box_coordinate_type;
105 typedef typename coordinate_system<Box>::type::units units_type;
107 typedef math::detail::constants_on_spheroid
113 // normalize input point and input box
114 Point p_normalized = detail::return_normalized<Point>(point);
115 detail::normalize(box, box);
117 // transform input point to be of the same type as the box point
118 box_point_type box_point;
119 detail::envelope::transform_units(p_normalized, box_point);
121 box_coordinate_type p_lon = geometry::get<0>(box_point);
122 box_coordinate_type p_lat = geometry::get<1>(box_point);
124 typename coordinate_type<Box>::type
125 b_lon_min = geometry::get<min_corner, 0>(box),
126 b_lat_min = geometry::get<min_corner, 1>(box),
127 b_lon_max = geometry::get<max_corner, 0>(box),
128 b_lat_max = geometry::get<max_corner, 1>(box);
130 if (math::is_latitude_pole<units_type, IsEquatorial>(p_lat))
132 // the point of expansion is the either the north or the
133 // south pole; the only important coordinate here is the
134 // pole's latitude, as the longitude can be anything;
135 // we, thus, take into account the point's latitude only and return
136 geometry::set<min_corner, 1>(box, (std::min)(p_lat, b_lat_min));
137 geometry::set<max_corner, 1>(box, (std::max)(p_lat, b_lat_max));
141 if (math::equals(b_lat_min, b_lat_max)
142 && math::is_latitude_pole<units_type, IsEquatorial>(b_lat_min))
144 // the box degenerates to either the north or the south pole;
145 // the only important coordinate here is the pole's latitude,
146 // as the longitude can be anything;
147 // we thus take into account the box's latitude only and return
148 geometry::set<min_corner, 0>(box, p_lon);
149 geometry::set<min_corner, 1>(box, (std::min)(p_lat, b_lat_min));
150 geometry::set<max_corner, 0>(box, p_lon);
151 geometry::set<max_corner, 1>(box, (std::max)(p_lat, b_lat_max));
156 b_lat_min = (std::min)(b_lat_min, p_lat);
157 b_lat_max = (std::max)(b_lat_max, p_lat);
160 if (math::smaller(p_lon, b_lon_min))
162 box_coordinate_type p_lon_shifted = p_lon + constants::period();
164 if (math::larger(p_lon_shifted, b_lon_max))
166 // here we could check using: ! math::larger(.., ..)
167 if (math::smaller(b_lon_min - p_lon, p_lon_shifted - b_lon_max))
173 b_lon_max = p_lon_shifted;
177 else if (math::larger(p_lon, b_lon_max))
179 // in this case, and since p_lon is normalized in the range
180 // (-180, 180], we must have that b_lon_max <= 180
182 && math::larger(p_lon - b_lon_max,
183 constants::period() - p_lon + b_lon_min))
186 b_lon_max += constants::period();
194 geometry::set<min_corner, 0>(box, b_lon_min);
195 geometry::set<min_corner, 1>(box, b_lat_min);
196 geometry::set<max_corner, 0>(box, b_lon_max);
197 geometry::set<max_corner, 1>(box, b_lat_max);
202 >::apply(box, point, strategy);
207 }} // namespace detail::expand
208 #endif // DOXYGEN_NO_DETAIL
210 #ifndef DOXYGEN_NO_DISPATCH
215 // Box + point -> new box containing also point
218 typename BoxOut, typename Point,
219 typename CSTagOut, typename CSTag
228 BOOST_MPL_ASSERT_MSG((false),
229 NOT_IMPLEMENTED_FOR_THESE_COORDINATE_SYSTEMS,
230 (types<CSTagOut, CSTag>()));
234 template <typename BoxOut, typename Point>
239 cartesian_tag, cartesian_tag
240 > : detail::expand::point_loop
242 0, dimension<Point>::value
246 template <typename BoxOut, typename Point>
251 spherical_equatorial_tag, spherical_equatorial_tag
252 > : detail::expand::point_loop_on_spheroid
254 dimension<Point>::value
258 template <typename BoxOut, typename Point>
263 spherical_polar_tag, spherical_polar_tag
264 > : detail::expand::point_loop_on_spheroid
266 dimension<Point>::value,
273 typename BoxOut, typename Point
279 geographic_tag, geographic_tag
280 > : detail::expand::point_loop_on_spheroid
282 dimension<Point>::value
287 } // namespace dispatch
288 #endif // DOXYGEN_NO_DISPATCH
290 }} // namespace boost::geometry
292 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_POINT_HPP