// Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2014-2015 Samuel Debionne, Grenoble, France. // This file was modified by Oracle on 2015, 2016, 2017. // Modifications copyright (c) 2015-2017, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_POINT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_POINT_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace expand { template struct point_loop { template static inline void apply(Box& box, Point const& source, Strategy const& strategy) { typedef typename select_coordinate_type < Point, Box >::type coordinate_type; std::less less; std::greater greater; coordinate_type const coord = get(source); if (less(coord, get(box))) { set(box, coord); } if (greater(coord, get(box))) { set(box, coord); } point_loop::apply(box, source, strategy); } }; template struct point_loop { template static inline void apply(Box&, Point const&, Strategy const&) {} }; // implementation for the spherical and geographic coordinate systems template struct point_loop_on_spheroid { template static inline void apply(Box& box, Point const& point, Strategy const& strategy) { typedef typename point_type::type box_point_type; typedef typename coordinate_type::type box_coordinate_type; typedef typename coordinate_system::type::units units_type; typedef math::detail::constants_on_spheroid < box_coordinate_type, units_type > constants; // normalize input point and input box Point p_normalized = detail::return_normalized(point); detail::normalize(box, box); // transform input point to be of the same type as the box point box_point_type box_point; detail::envelope::transform_units(p_normalized, box_point); box_coordinate_type p_lon = geometry::get<0>(box_point); box_coordinate_type p_lat = geometry::get<1>(box_point); typename coordinate_type::type b_lon_min = geometry::get(box), b_lat_min = geometry::get(box), b_lon_max = geometry::get(box), b_lat_max = geometry::get(box); if (math::is_latitude_pole(p_lat)) { // the point of expansion is the either the north or the // south pole; the only important coordinate here is the // pole's latitude, as the longitude can be anything; // we, thus, take into account the point's latitude only and return geometry::set(box, (std::min)(p_lat, b_lat_min)); geometry::set(box, (std::max)(p_lat, b_lat_max)); return; } if (math::equals(b_lat_min, b_lat_max) && math::is_latitude_pole(b_lat_min)) { // the box degenerates to either the north or the south pole; // the only important coordinate here is the pole's latitude, // as the longitude can be anything; // we thus take into account the box's latitude only and return geometry::set(box, p_lon); geometry::set(box, (std::min)(p_lat, b_lat_min)); geometry::set(box, p_lon); geometry::set(box, (std::max)(p_lat, b_lat_max)); return; } // update latitudes b_lat_min = (std::min)(b_lat_min, p_lat); b_lat_max = (std::max)(b_lat_max, p_lat); // update longitudes if (math::smaller(p_lon, b_lon_min)) { box_coordinate_type p_lon_shifted = p_lon + constants::period(); if (math::larger(p_lon_shifted, b_lon_max)) { // here we could check using: ! math::larger(.., ..) if (math::smaller(b_lon_min - p_lon, p_lon_shifted - b_lon_max)) { b_lon_min = p_lon; } else { b_lon_max = p_lon_shifted; } } } else if (math::larger(p_lon, b_lon_max)) { // in this case, and since p_lon is normalized in the range // (-180, 180], we must have that b_lon_max <= 180 if (b_lon_min < 0 && math::larger(p_lon - b_lon_max, constants::period() - p_lon + b_lon_min)) { b_lon_min = p_lon; b_lon_max += constants::period(); } else { b_lon_max = p_lon; } } geometry::set(box, b_lon_min); geometry::set(box, b_lat_min); geometry::set(box, b_lon_max); geometry::set(box, b_lat_max); point_loop < 2, DimensionCount >::apply(box, point, strategy); } }; }} // namespace detail::expand #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { // Box + point -> new box containing also point template < typename BoxOut, typename Point, typename CSTagOut, typename CSTag > struct expand < BoxOut, Point, box_tag, point_tag, CSTagOut, CSTag > { BOOST_MPL_ASSERT_MSG((false), NOT_IMPLEMENTED_FOR_THESE_COORDINATE_SYSTEMS, (types())); }; template struct expand < BoxOut, Point, box_tag, point_tag, cartesian_tag, cartesian_tag > : detail::expand::point_loop < 0, dimension::value > {}; template struct expand < BoxOut, Point, box_tag, point_tag, spherical_equatorial_tag, spherical_equatorial_tag > : detail::expand::point_loop_on_spheroid < dimension::value > {}; template struct expand < BoxOut, Point, box_tag, point_tag, spherical_polar_tag, spherical_polar_tag > : detail::expand::point_loop_on_spheroid < dimension::value, false > {}; template < typename BoxOut, typename Point > struct expand < BoxOut, Point, box_tag, point_tag, geographic_tag, geographic_tag > : detail::expand::point_loop_on_spheroid < dimension::value > {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_POINT_HPP