diff --git a/include/boost/geometry/algorithms/detail/assign_values.hpp b/include/boost/geometry/algorithms/detail/assign_values.hpp index b9fdcc741..64ab9fa83 100644 --- a/include/boost/geometry/algorithms/detail/assign_values.hpp +++ b/include/boost/geometry/algorithms/detail/assign_values.hpp @@ -7,6 +7,11 @@ // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2018. +// Modifications copyright (c) 2018, Oracle and/or its affiliates. + +// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle + // Use, modification and distribution is subject to 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) @@ -34,6 +39,7 @@ #include +#include #include @@ -86,10 +92,10 @@ struct assign_inverse_box_or_segment typedef typename coordinate_type::type bound_type; initialize<0, 0, dimension::type::value>::apply( - geometry, boost::numeric::bounds::highest() + geometry, geometry::bounds::highest() ); initialize<1, 0, dimension::type::value>::apply( - geometry, boost::numeric::bounds::lowest() + geometry, geometry::bounds::lowest() ); } diff --git a/include/boost/geometry/algorithms/detail/envelope/box.hpp b/include/boost/geometry/algorithms/detail/envelope/box.hpp index 33b43da25..cf039a292 100644 --- a/include/boost/geometry/algorithms/detail/envelope/box.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/box.hpp @@ -4,8 +4,8 @@ // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. -// This file was modified by Oracle on 2015, 2016, 2017. -// Modifications copyright (c) 2015-2017, Oracle and/or its affiliates. +// This file was modified by Oracle on 2015-2018. +// Modifications copyright (c) 2015-2018, 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 @@ -124,7 +124,12 @@ struct envelope_box_on_spheroid BoxOut& mbr, Strategy const&) { - BoxIn box_in_normalized = detail::return_normalized(box_in); + BoxIn box_in_normalized = box_in; + + if (!is_inverse_spheroidal_coordinates(box_in)) + { + box_in_normalized = detail::return_normalized(box_in); + } envelope_indexed_box_on_spheroid < diff --git a/include/boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp b/include/boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp index 9b9e2f85d..92d1fe395 100644 --- a/include/boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2015-2017, Oracle and/or its affiliates. +// Copyright (c) 2015-2018, 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 @@ -272,6 +272,11 @@ struct envelope_range_of_boxes it != boost::end(range_of_boxes); ++it) { + if (is_inverse_spheroidal_coordinates(*it)) + { + continue; + } + coordinate_type lat_min = geometry::get(*it); coordinate_type lat_max = geometry::get(*it); if (math::equals(lat_min, constants::max_latitude()) diff --git a/include/boost/geometry/algorithms/detail/expand/point.hpp b/include/boost/geometry/algorithms/detail/expand/point.hpp index 2d8b0feff..88ebe75db 100644 --- a/include/boost/geometry/algorithms/detail/expand/point.hpp +++ b/include/boost/geometry/algorithms/detail/expand/point.hpp @@ -5,8 +5,8 @@ // 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. +// This file was modified by Oracle on 2015-2018. +// Modifications copyright (c) 2015-2018, 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 @@ -35,6 +35,7 @@ #include #include +#include #include #include @@ -43,7 +44,6 @@ #include - namespace boost { namespace geometry { @@ -112,95 +112,106 @@ struct point_loop_on_spheroid // 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)) + if (is_inverse_spheroidal_coordinates(box)) { - // 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; - } + geometry::set_from_radian(box, geometry::get_as_radian<0>(p_normalized)); + geometry::set_from_radian(box, geometry::get_as_radian<1>(p_normalized)); + geometry::set_from_radian(box, geometry::get_as_radian<0>(p_normalized)); + geometry::set_from_radian(box, geometry::get_as_radian<1>(p_normalized)); - 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; - } + } else { - // update latitudes - b_lat_min = (std::min)(b_lat_min, p_lat); - b_lat_max = (std::max)(b_lat_max, p_lat); + detail::normalize(box, box); - // update longitudes - if (math::smaller(p_lon, b_lon_min)) - { - box_coordinate_type p_lon_shifted = p_lon + constants::period(); + box_coordinate_type p_lon = geometry::get<0>(box_point); + box_coordinate_type p_lat = geometry::get<1>(box_point); - if (math::larger(p_lon_shifted, b_lon_max)) + 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)) { - // here we could check using: ! math::larger(.., ..) - if (math::smaller(b_lon_min - p_lon, p_lon_shifted - b_lon_max)) + // 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_shifted; + b_lon_max = p_lon; } } - } - 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); + 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); - } + } }; diff --git a/include/boost/geometry/iterators/closing_iterator.hpp b/include/boost/geometry/iterators/closing_iterator.hpp index a0ec6a5c9..1477ea6e2 100644 --- a/include/boost/geometry/iterators/closing_iterator.hpp +++ b/include/boost/geometry/iterators/closing_iterator.hpp @@ -38,10 +38,24 @@ struct closing_iterator < closing_iterator, typename boost::range_value::type const, - boost::random_access_traversal_tag + boost::random_access_traversal_tag, + typename boost::range_reference::type, + typename boost::range_difference::type > { - typedef typename boost::range_difference::type difference_type; +private: + typedef boost::iterator_facade + < + closing_iterator, + typename boost::range_value::type const, + boost::random_access_traversal_tag, + typename boost::range_reference::type, + typename boost::range_difference::type + > base_type; + +public: + typedef typename base_type::reference reference; + typedef typename base_type::difference_type difference_type; /// Constructor including the range it is based on explicit inline closing_iterator(Range& range) @@ -71,7 +85,7 @@ struct closing_iterator private: friend class boost::iterator_core_access; - inline typename boost::range_value::type const& dereference() const + inline reference dereference() const { return *m_iterator; } diff --git a/include/boost/geometry/iterators/ever_circling_iterator.hpp b/include/boost/geometry/iterators/ever_circling_iterator.hpp index 569688aac..4d72bed2c 100644 --- a/include/boost/geometry/iterators/ever_circling_iterator.hpp +++ b/include/boost/geometry/iterators/ever_circling_iterator.hpp @@ -100,9 +100,22 @@ struct ever_circling_range_iterator < ever_circling_range_iterator, typename boost::range_value::type const, - boost::random_access_traversal_tag + boost::random_access_traversal_tag, + typename boost::range_reference::type, + typename boost::range_difference::type > { +private: + typedef boost::iterator_facade + < + ever_circling_range_iterator, + typename boost::range_value::type const, + boost::random_access_traversal_tag, + typename boost::range_reference::type, + typename boost::range_difference::type + > base_type; + +public: /// Constructor including the range it is based on explicit inline ever_circling_range_iterator(Range& range) : m_range(&range) @@ -118,12 +131,13 @@ struct ever_circling_range_iterator , m_index(0) {} - typedef std::ptrdiff_t difference_type; + typedef typename base_type::reference reference; + typedef typename base_type::difference_type difference_type; private: friend class boost::iterator_core_access; - inline typename boost::range_value::type const& dereference() const + inline reference dereference() const { return *m_iterator; } diff --git a/include/boost/geometry/util/is_inverse_spheroidal_coordinates.hpp b/include/boost/geometry/util/is_inverse_spheroidal_coordinates.hpp new file mode 100644 index 000000000..d67251254 --- /dev/null +++ b/include/boost/geometry/util/is_inverse_spheroidal_coordinates.hpp @@ -0,0 +1,43 @@ +// Boost.Geometry + +// Copyright (c) 2018 Oracle and/or its affiliates. + +// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle + +// Use, modification and distribution is subject to 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_UTIL_IS_INVERSE_SPHEROIDAL_COORDINATES_HPP +#define BOOST_GEOMETRY_UTIL_IS_INVERSE_SPHEROIDAL_COORDINATES_HPP + +#include + +namespace boost { namespace geometry +{ + +template +struct bounds +{ + static CT lowest () { return boost::numeric::bounds::lowest(); } + static CT highest () { return boost::numeric::bounds::highest(); } +}; + +template +bool is_inverse_spheroidal_coordinates(Box const& box) +{ + typedef typename point_type::type point_type; + typedef typename coordinate_type::type bound_type; + + bound_type high = bounds::highest(); + bound_type low = bounds::lowest(); + + return (geometry::get<0, 0>(box) == high) && + (geometry::get<0, 1>(box) == high) && + (geometry::get<1, 0>(box) == low) && + (geometry::get<1, 1>(box) == low); +} + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_UTIL_IS_INVERSE_SPHEROIDAL_COORDINATES_HPP diff --git a/test/algorithms/envelope_expand/expand_on_spheroid.cpp b/test/algorithms/envelope_expand/expand_on_spheroid.cpp index 1c535aa87..b192cf7e7 100644 --- a/test/algorithms/envelope_expand/expand_on_spheroid.cpp +++ b/test/algorithms/envelope_expand/expand_on_spheroid.cpp @@ -1,7 +1,7 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Unit Test -// Copyright (c) 2015-2017, Oracle and/or its affiliates. +// Copyright (c) 2015-2018, 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 @@ -42,6 +42,7 @@ #include #include #include +#include #include #include "test_envelope_expand_on_spheroid.hpp" @@ -241,20 +242,32 @@ private: tolerance); other_mbr_type other_box; - bg::detail::indexed_point_view p_min(box); - bg::detail::indexed_point_view p_max(box); - bg::detail::indexed_point_view - < - other_mbr_type, 0 - > other_min(other_box); - bg::detail::indexed_point_view - < - other_mbr_type, 1 - > other_max(other_box); + //if the input box is the special one made from make_inverse + //do not convert coordinates + if (!is_inverse_spheroidal_coordinates(box)) + { + bg::detail::indexed_point_view p_min(box); + bg::detail::indexed_point_view p_max(box); - bg::transform(p_min, other_min); - bg::transform(p_max, other_max); + bg::detail::indexed_point_view + < + other_mbr_type, 0 + > other_min(other_box); + + bg::detail::indexed_point_view + < + other_mbr_type, 1 + > other_max(other_box); + + bg::transform(p_min, other_min); + bg::transform(p_max, other_max); + } else { + bg::set(other_box, bg::get<0, 0>(box)); + bg::set(other_box, bg::get<0, 1>(box)); + bg::set(other_box, bg::get<1, 0>(box)); + bg::set(other_box, bg::get<1, 1>(box)); + } base_test(case_id, other_box, geometry, other::convert(lon_min1), @@ -1043,6 +1056,39 @@ BOOST_AUTO_TEST_CASE( expand_box ) test_expand_box >(); } +template +void test_expand_make_inverse() +{ + typedef bg::model::point point_type; + typedef bg::model::box box_type; + typedef bg::model::segment segment_type; + typedef test_expand_on_spheroid tester; + + box_type box = boost::geometry::make_inverse(); + + tester::apply("bi01", + box, + from_wkt("BOX(10 10,20 20)"), + 10, 10, 20, 20); + tester::apply("bi02", + box, + from_wkt("POINT(0 0)"), + 0, 0, 0, 0); + tester::apply("bi03", + box, + from_wkt("POINT(5 0)"), + 5, 0, 5, 0); + tester::apply("bi04", + box, + from_wkt("SEGMENT(5 0,0 5)"), + 0, 0, 5, 5); +} + +BOOST_AUTO_TEST_CASE( expand_make_inverse ) +{ + test_expand_make_inverse >(); + test_expand_make_inverse >(); +} template void test_expand_box_with_height() diff --git a/test/iterators/closing_iterator.cpp b/test/iterators/closing_iterator.cpp index 1221eb257..9ac43634b 100644 --- a/test/iterators/closing_iterator.cpp +++ b/test/iterators/closing_iterator.cpp @@ -26,6 +26,8 @@ #include #include +#include + // The closing iterator should also work on normal std:: containers void test_empty_non_geometry() @@ -73,6 +75,36 @@ void test_non_geometry() BOOST_CHECK_EQUAL(out.str(), "1231"); } +void test_transformed_non_geometry() +{ + std::vector v; + v.push_back(-1); + v.push_back(-2); + v.push_back(-3); + + typedef boost::transformed_range + < + std::negate, + std::vector + > transformed_range; + + typedef bg::closing_iterator + < + transformed_range const + > closing_iterator; + + transformed_range v2 = v | boost::adaptors::transformed(std::negate()); + closing_iterator it(v2); + closing_iterator end(v2, true); + + std::ostringstream out; + for (; it != end; ++it) + { + out << *it; + } + BOOST_CHECK_EQUAL(out.str(), "1231"); +} + @@ -129,6 +161,7 @@ void test_all() { test_empty_non_geometry(); test_non_geometry(); + test_transformed_non_geometry(); test_geometry >("POLYGON((1 1,1 4,4 4,4 1))"); } diff --git a/test/iterators/ever_circling_iterator.cpp b/test/iterators/ever_circling_iterator.cpp index 1e4c254fd..835a7b5a3 100644 --- a/test/iterators/ever_circling_iterator.cpp +++ b/test/iterators/ever_circling_iterator.cpp @@ -23,12 +23,14 @@ #include #include #include +#include + +#include + template -void test_geometry(std::string const& wkt) +void test_geometry(G const& geo) { - G geo; - bg::read_wkt(wkt, geo); typedef typename boost::range_iterator::type iterator_type; @@ -74,7 +76,7 @@ void test_geometry(std::string const& wkt) // Check the range_iterator-one { std::ostringstream out; - bg::ever_circling_range_iterator it(geo); + bg::ever_circling_range_iterator it(geo); for (std::size_t i = 0; i < n; ++i, ++it) { out << bg::get<0>(*it); @@ -83,10 +85,54 @@ void test_geometry(std::string const& wkt) } } +template +void test_geometry(std::string const& wkt) +{ + G geo; + bg::read_wkt(wkt, geo); + test_geometry(geo); +} + + +template +P transform_point(P const& p) +{ + P result; + bg::set<0>(result, bg::get<0>(p) + 1); + bg::set<1>(result, bg::get<1>(p) + 1); + return result; +} + +template +struct transformed_geometry_type +{ + typedef typename bg::point_type::type point_type; + typedef boost::transformed_range type; +}; + +template +void test_transformed_geometry(G const& geo) +{ + typedef typename bg::point_type::type point_type; + test_geometry(geo | boost::adaptors::transformed(&transform_point)); +} + +template +void test_transformed_geometry(std::string const& wkt) +{ + G geo; + bg::read_wkt(wkt, geo); + test_transformed_geometry(geo); +} + + +BOOST_GEOMETRY_REGISTER_LINESTRING(transformed_geometry_type< bg::model::linestring< bg::model::d2::point_xy > >::type) + template void test_all() { test_geometry >("linestring(1 1,2 2,3 3,4 4,5 5)"); + test_transformed_geometry >("linestring(0 0,1 1,2 2,3 3,4 4)"); } int test_main(int, char* []) diff --git a/test/strategies/segment_intersection_geo.cpp b/test/strategies/segment_intersection_geo.cpp index c0f275abf..e0ab9f6af 100644 --- a/test/strategies/segment_intersection_geo.cpp +++ b/test/strategies/segment_intersection_geo.cpp @@ -407,7 +407,6 @@ void test_geographic_radian() typedef bg::model::point > point_t; typedef bg::model::segment segment_t; - T const d2r = bg::math::d2r(); bg::strategy::intersection::geographic_segments strategy; // https://github.com/boostorg/geometry/issues/470