diff --git a/.circleci/config.yml b/.circleci/config.yml index a61e96d1c..7df421c70 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -60,7 +60,7 @@ jobs: git submodule update --init tools/build git submodule update --init libs/config git submodule update --init tools/boostdep - python tools/boostdep/depinst/depinst.py geometry + python tools/boostdep/depinst/depinst.py geometry -I index/test ./bootstrap.sh ./b2 headers - run: mkdir $COVERAGE_DIR @@ -407,15 +407,15 @@ jobs: root: ~/project paths: - shared-coverage/index_rtree_exceptions - index_varray: + index_detail: <<: *config steps: - *attach_workspace - - run: ./$BOOST_DIR/libs/geometry/.circleci/run_test.sh index_varray index/test//boost-geometry-index-varray + - run: ./$BOOST_DIR/libs/geometry/.circleci/run_test.sh index_detail index/test//boost-geometry-index-detail - persist_to_workspace: root: ~/project paths: - - shared-coverage/index_varray + - shared-coverage/index_detail coverage: <<: *config @@ -494,7 +494,7 @@ requires_4: &requires_4 - index_rtree - index_rtree_b2d - index_rtree_exceptions - - index_varray + - index_detail - cs_undefined only_master_develop: &only_master_develop @@ -630,7 +630,7 @@ workflows: - index_rtree_exceptions: <<: *requires_3 <<: *only_master_develop - - index_varray: + - index_detail: <<: *requires_3 <<: *only_master_develop - cs_undefined: diff --git a/LICENSE_1_0.txt b/LICENSE_1_0.txt new file mode 100644 index 000000000..36b7cd93c --- /dev/null +++ b/LICENSE_1_0.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/doc/src/examples/algorithms/is_valid_failure.cpp b/doc/src/examples/algorithms/is_valid_failure.cpp index f566e23a2..9569ba6ad 100644 --- a/doc/src/examples/algorithms/is_valid_failure.cpp +++ b/doc/src/examples/algorithms/is_valid_failure.cpp @@ -32,7 +32,7 @@ int main() // if the invalidity is only due to lack of closing points and/or wrongly oriented rings, then bg::correct can fix it bool could_be_fixed = (failure == boost::geometry::failure_not_closed - || boost::geometry::failure_wrong_orientation); + || failure == boost::geometry::failure_wrong_orientation); std::cout << "is valid? " << (valid ? "yes" : "no") << std::endl; if (! valid) { diff --git a/example/with_external_libs/CMakeLists.txt b/example/with_external_libs/CMakeLists.txt new file mode 100644 index 000000000..1d60eb866 --- /dev/null +++ b/example/with_external_libs/CMakeLists.txt @@ -0,0 +1,34 @@ +# Boost.Geometry +# Example CMakeLists.txt building the Boost.Geometry with wxWidget example +# +# Copyright (c) 2021-2021 Barend Gehrels, Amsterdam, the Netherlands. + +# 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) + +cmake_minimum_required(VERSION 3.10) + +project(with_external_libs) + +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +# Set BOOST_ROOT in your environment (this is cmake default) +find_package(Boost) + +# Set WX_ROOT, similarly, also in your environment +set(WX_ROOT $ENV{WX_ROOT}) +message(STATUS "Using wxWidgets from this folder: " $ENV{WX_ROOT}) + +# WX Widgets +link_directories(${WX_ROOT}/lib) +add_executable(wx x04_wxwidgets_world_mapper.cpp) +target_include_directories(wx PRIVATE ${Boost_INCLUDE_DIRS}) +target_include_directories(wx PRIVATE ${WX_ROOT}/include) +target_include_directories(wx PRIVATE ${WX_ROOT}/include/wx-3.1) + +# WX configuration (get the values using wx-config --cxxflags and wx-config --libs) +target_compile_definitions(wx PRIVATE WXUSINGDLL __WXGTK2__ __WXGTK__) +target_link_libraries(wx PRIVATE wx_gtk2u_html-3.1 wx_gtk2u_core-3.1 wx_baseu_net-3.1 wx_baseu-3.1) + diff --git a/example/with_external_libs/x04_wxwidgets_world_mapper.cpp b/example/with_external_libs/x04_wxwidgets_world_mapper.cpp index 49bf0878b..ac3f6322e 100644 --- a/example/with_external_libs/x04_wxwidgets_world_mapper.cpp +++ b/example/with_external_libs/x04_wxwidgets_world_mapper.cpp @@ -1,115 +1,62 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) +// Boost.Geometry // -// Copyright (c) 2010-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2010-2021 Barend Gehrels, Amsterdam, the Netherlands. // 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) // // wxWidgets World Mapper example +// +// It will show a basic wxWidgets window, displaying world countries, +// highlighting the country under the mouse, and indicating position +// of the mouse in latitude/longitude and in pixels. +// To compile this program: +// Install wxWidgets (if not done before) +// export BOOST_ROOT=..... +// export WX_ROOT=.... (for example /home/myname/mylib/wxWidgets/Linux/x86_64) +// mkdir build +// cd build +// cmake .. -G Ninja +// ninja +// If necessary, CMakeLists.txt should be adapted, the options for wx +// are provided by "wx-config --cxxflags" and "... --libs" +// and might need a change in CMakeLists.txt -// #define EXAMPLE_WX_USE_GRAPHICS_CONTEXT 1 +//#define EXAMPLE_WX_USE_GRAPHICS_CONTEXT 1 #include #include -#include -#include -#include - #include #include #include -#include +#include #include #include -#include - - -// wxWidgets, if these headers are NOT found, adapt include path (and lib path) #include "wx/wx.h" #include "wx/math.h" #include "wx/stockitem.h" - #ifdef EXAMPLE_WX_USE_GRAPHICS_CONTEXT #include "wx/graphics.h" #include "wx/dcgraph.h" #endif -typedef boost::geometry::model::d2::point_xy point_2d; -typedef boost::geometry::model::multi_polygon + +using point_2d = boost::geometry::model::d2::point_xy; +using country_type = boost::geometry::model::multi_polygon < boost::geometry::model::polygon - > country_type; + >; // Adapt wxWidgets points to Boost.Geometry points such that they can be used // in e.g. transformations (see below) BOOST_GEOMETRY_REGISTER_POINT_2D(wxPoint, int, cs::cartesian, x, y) BOOST_GEOMETRY_REGISTER_POINT_2D(wxRealPoint, double, cs::cartesian, x, y) - -// wxWidgets draws using wxPoint*, so we HAVE to use that. -// Therefore have to make a wxPoint* array -// 1) compatible with Boost.Geometry -// 2) compatible with Boost.Range (required by Boost.Geometry) -// 3) compatible with std::back_inserter (required by Boost.Geometry) - -// For compatible 2): -typedef std::pair wxPointPointerPair; - -// For compatible 1): -BOOST_GEOMETRY_REGISTER_RING(wxPointPointerPair); - - -// For compatible 3): -// Specialize back_insert_iterator for the wxPointPointerPair -// (has to be done within "namespace std") -namespace std -{ - -template <> -class back_insert_iterator -{ -public: - typedef std::output_iterator_tag iterator_category; - typedef void value_type; - typedef void difference_type; - typedef void pointer; - typedef void reference; - - typedef wxPointPointerPair container_type; - - explicit back_insert_iterator(wxPointPointerPair& x) - : current(boost::begin(x)) - , end(boost::end(x)) - {} - - inline back_insert_iterator& - operator=(wxPoint const& value) - { - // Check if not passed beyond - if (current != end) - { - *current++ = value; - } - return *this; - } - - // Boiler-plate - inline back_insert_iterator& operator*() { return *this; } - inline back_insert_iterator& operator++() { return *this; } - inline back_insert_iterator& operator++(int) { return *this; } - -private: - boost::range_iterator::type current, end; -}; - -} // namespace std - - // ---------------------------------------------------------------------------- // Read an ASCII file containing WKT's // ---------------------------------------------------------------------------- @@ -161,26 +108,29 @@ private: void OnPaint(wxPaintEvent& ); void OnMouseMove(wxMouseEvent&); - typedef boost::geometry::strategy::transform::map_transformer + using map_transformer_type = boost::geometry::strategy::transform::map_transformer < double, 2, 2, true, true - > map_transformer_type; + >; - typedef boost::geometry::strategy::transform::inverse_transformer + using inverse_transformer_type = boost::geometry::strategy::transform::inverse_transformer < double, 2, 2 - > inverse_transformer_type; + >; - boost::shared_ptr m_map_transformer; - boost::shared_ptr m_inverse_transformer; + std::shared_ptr m_map_transformer; + std::shared_ptr m_inverse_transformer; boost::geometry::model::box m_box; std::vector m_countries; - int m_focus; + int m_focus = -1; - wxBrush m_orange; - wxFrame* m_owner; + wxBrush m_orange = wxBrush(wxColour(255, 128, 0), wxBRUSHSTYLE_SOLID); + wxBrush m_blue = wxBrush(wxColour(0, 128, 255), wxBRUSHSTYLE_SOLID); + wxBrush m_green = wxBrush(wxColour(0, 255, 0), wxBRUSHSTYLE_SOLID); + + wxFrame* m_owner = nullptr; DECLARE_EVENT_TABLE() }; @@ -244,19 +194,14 @@ void HelloWorldFrame::OnCloseWindow(wxCloseEvent& ) HelloWorldCanvas::HelloWorldCanvas(wxFrame *frame) : wxWindow(frame, wxID_ANY) , m_owner(frame) - , m_focus(-1) { boost::geometry::assign_inverse(m_box); read_wkt("../data/world.wkt", m_countries, m_box); - m_orange = wxBrush(wxColour(255, 128, 0), wxSOLID); } - void HelloWorldCanvas::OnMouseMove(wxMouseEvent &event) { - namespace bg = boost::geometry; - if (m_inverse_transformer) { // Boiler-plate wxWidgets code @@ -264,19 +209,21 @@ void HelloWorldCanvas::OnMouseMove(wxMouseEvent &event) PrepareDC(dc); m_owner->PrepareDC(dc); - // Transform the point to Lon/Lat + // Transform the point opn the screen back to Lon/Lat point_2d point; - bg::transform(event.GetPosition(), point, *m_inverse_transformer); + boost::geometry::transform(event.GetPosition(), point, + *m_inverse_transformer); // Determine selected object int i = 0; int previous_focus = m_focus; m_focus = -1; - BOOST_FOREACH(country_type const& country, m_countries) + for (country_type const& country : m_countries) { - if (bg::selected(country, point, 0)) + if (boost::geometry::within(point, country)) { m_focus = i; + break; } i++; } @@ -287,7 +234,7 @@ void HelloWorldCanvas::OnMouseMove(wxMouseEvent &event) // Undraw old focus if (previous_focus >= 0) { - dc.SetBrush(*wxWHITE_BRUSH); + dc.SetBrush(m_green); DrawCountry(dc, m_countries[previous_focus]); } // Draw new focus @@ -309,6 +256,11 @@ void HelloWorldCanvas::OnMouseMove(wxMouseEvent &event) void HelloWorldCanvas::OnPaint(wxPaintEvent& ) { + if (m_countries.empty()) + { + return; + } + #if defined(EXAMPLE_WX_USE_GRAPHICS_CONTEXT) wxPaintDC pdc(this); wxGCDC gdc(pdc); @@ -340,11 +292,12 @@ void HelloWorldCanvas::DrawCountries(wxDC& dc) { namespace bg = boost::geometry; - dc.SetBackground(*wxLIGHT_GREY_BRUSH); + dc.SetBackground(m_blue); dc.Clear(); - BOOST_FOREACH(country_type const& country, m_countries) + for (country_type const& country : m_countries) { + dc.SetBrush(m_green); DrawCountry(dc, country); } if (m_focus != -1) @@ -357,27 +310,23 @@ void HelloWorldCanvas::DrawCountries(wxDC& dc) void HelloWorldCanvas::DrawCountry(wxDC& dc, country_type const& country) { - namespace bg = boost::geometry; - - BOOST_FOREACH(bg::model::polygon const& poly, country) + for (auto const& poly : country) { - // Use only exterior ring, holes are (for the moment) ignored. This would need - // a holey-polygon compatible wx object + // Use only exterior ring, holes are (for the moment) ignored. + // This would need a holey-polygon compatible wx object - std::size_t n = boost::size(bg::exterior_ring(poly)); - - boost::scoped_array points(new wxPoint[n]); - - wxPointPointerPair pair = std::make_pair(points.get(), points.get() + n); - bg::transform(bg::exterior_ring(poly), pair, *m_map_transformer); - - dc.DrawPolygon(n, points.get()); + // Define a Boost.Geometry ring of wxPoints + // Behind the scenes that is a vector, and a vector has .data(), + // can be used for the *wxPoint pointer needed for wxWidget DrawPolygon + boost::geometry::model::ring ring; + boost::geometry::transform(boost::geometry::exterior_ring(poly), ring, + *m_map_transformer); + dc.DrawPolygon(ring.size(), ring.data()); } } // ---------------------------------------------------------------------------- - BEGIN_EVENT_TABLE(HelloWorldFrame, wxFrame) EVT_CLOSE(HelloWorldFrame::OnCloseWindow) EVT_MENU(wxID_EXIT, HelloWorldFrame::OnExit) diff --git a/example/with_external_libs/x04_wxwidgets_world_mapper_readme.txt b/example/with_external_libs/x04_wxwidgets_world_mapper_readme.txt deleted file mode 100644 index cba0c8eeb..000000000 --- a/example/with_external_libs/x04_wxwidgets_world_mapper_readme.txt +++ /dev/null @@ -1,23 +0,0 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) -// -// Copyright Barend Gehrels 2010, Geodan, Amsterdam, the Netherlands -// 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) - - - -wxWidgets World Mapper example - -It will show a basic wxWidgets window, displaying world countries, highlighting the country under -the mouse, and indicating position of the mouse in latitude/longitude and in pixels. - - -To compile this program: - -Install wxWidgets (if not done before) - -Using Linux/gcc - - check if installation is OK, http://wiki.wxwidgets.org/Installing_and_configuring_under_Ubuntu - - compile using e.g. gcc -o x04_wxwidgets -I../../../.. x04_wxwidgets_world_mapper.cpp `wx-config --cxxflags` `wx-config --libs` - diff --git a/include/boost/geometry/algorithms/azimuth.hpp b/include/boost/geometry/algorithms/azimuth.hpp index 28e5491e7..26c9a5530 100644 --- a/include/boost/geometry/algorithms/azimuth.hpp +++ b/include/boost/geometry/algorithms/azimuth.hpp @@ -23,6 +23,8 @@ #include #include +#include + #include #include #include diff --git a/include/boost/geometry/algorithms/centroid.hpp b/include/boost/geometry/algorithms/centroid.hpp index 621a4f5c0..291560d34 100644 --- a/include/boost/geometry/algorithms/centroid.hpp +++ b/include/boost/geometry/algorithms/centroid.hpp @@ -28,9 +28,6 @@ #include #include #include -#include -#include -#include #include #include @@ -41,15 +38,18 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include +#include // For backward compatibility #include #include @@ -61,6 +61,7 @@ #include #include +#include #include @@ -540,9 +541,9 @@ struct centroid } // namespace resolve_strategy -namespace resolve_variant { +namespace resolve_dynamic { -template +template ::type> struct centroid { template @@ -553,37 +554,22 @@ struct centroid } }; -template -struct centroid > +template +struct centroid { template - struct visitor: boost::static_visitor + static inline void apply(Geometry const& geometry, + Point& out, + Strategy const& strategy) { - Point& m_out; - Strategy const& m_strategy; - - visitor(Point& out, Strategy const& strategy) - : m_out(out), m_strategy(strategy) - {} - - template - void operator()(Geometry const& geometry) const + traits::visit::apply([&](auto const& g) { - centroid::apply(geometry, m_out, m_strategy); - } - }; - - template - static inline void - apply(boost::variant const& geometry, - Point& out, - Strategy const& strategy) - { - boost::apply_visitor(visitor(out, strategy), geometry); + centroid>::apply(g, out, strategy); + }, geometry); } }; -} // namespace resolve_variant +} // namespace resolve_dynamic /*! @@ -604,10 +590,9 @@ struct centroid > */ template -inline void centroid(Geometry const& geometry, Point& c, - Strategy const& strategy) +inline void centroid(Geometry const& geometry, Point& c, Strategy const& strategy) { - resolve_variant::centroid::apply(geometry, c, strategy); + resolve_dynamic::centroid::apply(geometry, c, strategy); } diff --git a/include/boost/geometry/algorithms/correct.hpp b/include/boost/geometry/algorithms/correct.hpp index 3c338916b..9d1f246a6 100644 --- a/include/boost/geometry/algorithms/correct.hpp +++ b/include/boost/geometry/algorithms/correct.hpp @@ -5,8 +5,8 @@ // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // Copyright (c) 2014-2017 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2017-2020. -// Modifications copyright (c) 2017-2020 Oracle and/or its affiliates. +// This file was modified by Oracle on 2017-2021. +// Modifications copyright (c) 2017-2021 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library @@ -28,12 +28,11 @@ #include #include -#include -#include -#include - +#include #include #include +#include +#include #include #include @@ -42,12 +41,18 @@ #include #include #include +#include +#include // For backward compatibility #include -#include -#include -#include +#include +#include +#include +#include + +#include + namespace boost { namespace geometry { @@ -62,92 +67,56 @@ namespace boost { namespace geometry namespace detail { namespace correct { -template struct correct_nop { - template + template static inline void apply(Geometry& , Strategy const& ) {} }; -template -struct correct_box_loop -{ - typedef typename coordinate_type::type coordinate_type; - - static inline void apply(Box& box) - { - if (get(box) > get(box)) - { - // Swap the coordinates - coordinate_type max_value = get(box); - coordinate_type min_value = get(box); - set(box, min_value); - set(box, max_value); - } - - correct_box_loop - < - Box, Dimension + 1, DimensionCount - >::apply(box); - } -}; - - - -template -struct correct_box_loop -{ - static inline void apply(Box& ) - {} - -}; - - // Correct a box: make min/max correct -template struct correct_box { - template + template static inline void apply(Box& box, Strategy const& ) { + using coordinate_type = typename geometry::coordinate_type::type; + // Currently only for Cartesian coordinates // (or spherical without crossing dateline) // Future version: adapt using strategies - correct_box_loop - < - Box, 0, dimension::type::value - >::apply(box); + detail::for_each_dimension([&](auto dimension) + { + if (get(box) > get(box)) + { + // Swap the coordinates + coordinate_type max_value = get(box); + coordinate_type min_value = get(box); + set(box, min_value); + set(box, max_value); + } + }); } }; // Close a ring, if not closed -template class Predicate> +template > struct correct_ring { - typedef typename point_type::type point_type; - typedef typename coordinate_type::type coordinate_type; - - template + template static inline void apply(Ring& r, Strategy const& strategy) { // Correct closure if necessary - detail::correct_closure::close_or_open_ring::apply(r); + detail::correct_closure::close_or_open_ring::apply(r); + + // NOTE: calculate_point_order should probably be used here instead. // Check area - typedef typename area_result::type area_result_type; - Predicate predicate; - area_result_type const zero = 0; - if (predicate(detail::area::ring_area::apply( - r, - // TEMP - in the future (umbrella) strategy will be passed - geometry::strategies::area::services::strategy_converter - < - Strategy - >::get(strategy)), - zero)) + using area_t = typename area_result::type; + area_t const zero = 0; + if (Predicate()(detail::area::ring_area::apply(r, strategy), zero)) { std::reverse(boost::begin(r), boost::end(r)); } @@ -156,30 +125,18 @@ struct correct_ring // Correct a polygon: normalizes all rings, sets outer ring clockwise, sets all // inner rings counter clockwise (or vice versa depending on orientation) -template struct correct_polygon { - typedef typename ring_type::type ring_type; - - template + template static inline void apply(Polygon& poly, Strategy const& strategy) { - correct_ring - < - ring_type, - std::less - >::apply(exterior_ring(poly), strategy); + correct_ring>::apply(exterior_ring(poly), strategy); - typename interior_return_type::type - rings = interior_rings(poly); - for (typename detail::interior_iterator::type - it = boost::begin(rings); it != boost::end(rings); ++it) + auto&& rings = interior_rings(poly); + auto const end = boost::end(rings); + for (auto it = boost::begin(rings); it != end; ++it) { - correct_ring - < - ring_type, - std::greater - >::apply(*it, strategy); + correct_ring>::apply(*it, strategy); } } }; @@ -199,62 +156,51 @@ struct correct: not_implemented template struct correct - : detail::correct::correct_nop + : detail::correct::correct_nop {}; template struct correct - : detail::correct::correct_nop + : detail::correct::correct_nop {}; template struct correct - : detail::correct::correct_nop + : detail::correct::correct_nop {}; template struct correct - : detail::correct::correct_box + : detail::correct::correct_box {}; template struct correct - : detail::correct::correct_ring - < - Ring, - std::less - > + : detail::correct::correct_ring<> {}; template struct correct - : detail::correct::correct_polygon + : detail::correct::correct_polygon {}; template struct correct - : detail::correct::correct_nop + : detail::correct::correct_nop {}; template struct correct - : detail::correct::correct_nop + : detail::correct::correct_nop {}; template struct correct - : detail::multi_modify - < - Geometry, - detail::correct::correct_polygon - < - typename boost::range_value::type - > - > + : detail::multi_modify {}; @@ -262,45 +208,96 @@ struct correct #endif // DOXYGEN_NO_DISPATCH -namespace resolve_variant { +namespace resolve_strategy +{ -template +template +< + typename Strategy, + bool IsUmbrella = strategies::detail::is_umbrella_strategy::value +> +struct correct +{ + template + static inline void apply(Geometry& geometry, Strategy const& strategy) + { + dispatch::correct::apply(geometry, strategy); + } +}; + +template +struct correct +{ + template + static inline void apply(Geometry& geometry, Strategy const& strategy) + { + // NOTE: calculate_point_order strategy should probably be used here instead. + using geometry::strategies::area::services::strategy_converter; + dispatch::correct::apply(geometry, strategy_converter::get(strategy)); + } +}; + +template <> +struct correct +{ + template + static inline void apply(Geometry& geometry, default_strategy const& ) + { + // NOTE: calculate_point_order strategy should probably be used here instead. + using strategy_type = typename strategies::area::services::default_strategy + < + Geometry + >::type; + dispatch::correct::apply(geometry, strategy_type()); + } +}; + +} // namespace resolve_strategy + + +namespace resolve_dynamic +{ + +template ::type> struct correct { template static inline void apply(Geometry& geometry, Strategy const& strategy) { - concepts::check(); - dispatch::correct::apply(geometry, strategy); + concepts::check(); + resolve_strategy::correct::apply(geometry, strategy); } }; -template -struct correct > +template +struct correct { template - struct visitor: boost::static_visitor + static inline void apply(Geometry& geometry, Strategy const& strategy) { - Strategy const& m_strategy; - - visitor(Strategy const& strategy): m_strategy(strategy) {} - - template - void operator()(Geometry& geometry) const + traits::visit::apply([&](auto & g) { - correct::apply(geometry, m_strategy); - } - }; - - template - static inline void - apply(boost::variant& geometry, Strategy const& strategy) - { - boost::apply_visitor(visitor(strategy), geometry); + correct>::apply(g, strategy); + }, geometry); } }; -} // namespace resolve_variant +template +struct correct +{ + template + static inline void apply(Geometry& geometry, Strategy const& strategy) + { + detail::visit_breadth_first([&](auto & g) + { + correct>::apply(g, strategy); + return true; + }, geometry); + } +}; + + +} // namespace resolve_dynamic /*! @@ -318,14 +315,7 @@ struct correct > template inline void correct(Geometry& geometry) { - typedef typename point_type::type point_type; - - typedef typename strategy::area::services::default_strategy - < - typename cs_tag::type - >::type strategy_type; - - resolve_variant::correct::apply(geometry, strategy_type()); + resolve_dynamic::correct::apply(geometry, default_strategy()); } /*! @@ -347,7 +337,7 @@ inline void correct(Geometry& geometry) template inline void correct(Geometry& geometry, Strategy const& strategy) { - resolve_variant::correct::apply(geometry, strategy); + resolve_dynamic::correct::apply(geometry, strategy); } #if defined(_MSC_VER) diff --git a/include/boost/geometry/algorithms/correct_closure.hpp b/include/boost/geometry/algorithms/correct_closure.hpp index 4160f256f..60b8beef5 100644 --- a/include/boost/geometry/algorithms/correct_closure.hpp +++ b/include/boost/geometry/algorithms/correct_closure.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2017 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2020. -// Modifications copyright (c) 2020 Oracle and/or its affiliates. +// This file was modified by Oracle on 2020-2021. +// Modifications copyright (c) 2020-2021 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, @@ -15,16 +15,9 @@ #include -#include -#include -#include -#include - -#include -#include -#include - #include +#include +#include #include #include @@ -32,10 +25,11 @@ #include #include +#include #include -#include -#include +#include +#include namespace boost { namespace geometry { @@ -50,59 +44,55 @@ namespace boost { namespace geometry namespace detail { namespace correct_closure { -template struct nop { + template static inline void apply(Geometry& ) {} }; - // Close a ring, if not closed, or open it -template struct close_or_open_ring { + template static inline void apply(Ring& r) { - if (boost::size(r) <= 2) + auto size = boost::size(r); + if (size <= 2) { return; } - bool const disjoint = geometry::disjoint(*boost::begin(r), - *(boost::end(r) - 1)); - closure_selector const s = geometry::closure::value; + // TODO: This requires relate(pt, pt) strategy + bool const disjoint = geometry::disjoint(*boost::begin(r), *(boost::end(r) - 1)); + closure_selector const closure = geometry::closure::value; - if (disjoint && s == closed) + if (disjoint && closure == closed) { // Close it by adding first point geometry::append(r, *boost::begin(r)); } - else if (! disjoint && s != closed) + else if (! disjoint && closure == open) { // Open it by removing last point - geometry::traits::resize::apply(r, boost::size(r) - 1); + range::resize(r, size - 1); } } }; // Close/open exterior ring and all its interior rings -template struct close_or_open_polygon { - typedef typename ring_type::type ring_type; - + template static inline void apply(Polygon& poly) { - close_or_open_ring::apply(exterior_ring(poly)); + close_or_open_ring::apply(exterior_ring(poly)); - typename interior_return_type::type - rings = interior_rings(poly); - - for (typename detail::interior_iterator::type - it = boost::begin(rings); it != boost::end(rings); ++it) + auto&& rings = interior_rings(poly); + auto const end = boost::end(rings); + for (auto it = boost::begin(rings); it != end; ++it) { - close_or_open_ring::apply(*it); + close_or_open_ring::apply(*it); } } }; @@ -121,45 +111,45 @@ struct correct_closure: not_implemented template struct correct_closure - : detail::correct_closure::nop + : detail::correct_closure::nop {}; template struct correct_closure - : detail::correct_closure::nop + : detail::correct_closure::nop {}; template struct correct_closure - : detail::correct_closure::nop + : detail::correct_closure::nop {}; template struct correct_closure - : detail::correct_closure::nop + : detail::correct_closure::nop {}; template struct correct_closure - : detail::correct_closure::close_or_open_ring + : detail::correct_closure::close_or_open_ring {}; template struct correct_closure - : detail::correct_closure::close_or_open_polygon + : detail::correct_closure::close_or_open_polygon {}; template struct correct_closure - : detail::correct_closure::nop + : detail::correct_closure::nop {}; template struct correct_closure - : detail::correct_closure::nop + : detail::correct_closure::nop {}; @@ -167,11 +157,7 @@ template struct correct_closure : detail::multi_modify < - Geometry, detail::correct_closure::close_or_open_polygon - < - typename boost::range_value::type - > > {}; @@ -183,7 +169,7 @@ struct correct_closure namespace resolve_variant { -template +template ::type> struct correct_closure { static inline void apply(Geometry& geometry) @@ -193,29 +179,37 @@ struct correct_closure } }; -template -struct correct_closure > +template +struct correct_closure { - struct visitor: boost::static_visitor + static void apply(Geometry& geometry) { - template - void operator()(Geometry& geometry) const + traits::visit::apply([](auto & g) { - correct_closure::apply(geometry); - } - }; + correct_closure>::apply(g); + }, geometry); + } +}; - static inline void - apply(boost::variant& geometry) +template +struct correct_closure +{ + static void apply(Geometry& geometry) { - visitor vis; - boost::apply_visitor(vis, geometry); + detail::visit_breadth_first([](auto & g) + { + correct_closure>::apply(g); + return true; + }, geometry); } }; } // namespace resolve_variant +// TODO: This algorithm should use relate(pt, pt) strategy + + /*! \brief Closes or opens a geometry, according to its type \details Corrects a geometry w.r.t. closure points to all rings which do not diff --git a/include/boost/geometry/algorithms/densify.hpp b/include/boost/geometry/algorithms/densify.hpp index d601bd3c8..84e32bb2f 100644 --- a/include/boost/geometry/algorithms/densify.hpp +++ b/include/boost/geometry/algorithms/densify.hpp @@ -11,8 +11,14 @@ #define BOOST_GEOMETRY_ALGORITHMS_DENSIFY_HPP +#include +#include +#include + #include +#include #include +#include #include #include #include @@ -20,6 +26,8 @@ #include #include #include +#include +#include // For backward compatibility #include #include #include @@ -28,11 +36,6 @@ #include #include -#include -#include - -#include - namespace boost { namespace geometry { @@ -146,6 +149,15 @@ struct densify_ring : densify_range {}; +struct densify_convert +{ + template + static void apply(GeometryIn const& in, GeometryOut &out, + T const& , Strategy const& ) + { + geometry::convert(in, out); + } +}; }} // namespace detail::densify #endif // DOXYGEN_NO_DETAIL @@ -167,6 +179,26 @@ struct densify : not_implemented {}; +template +struct densify + : geometry::detail::densify::densify_convert +{}; + +template +struct densify + : geometry::detail::densify::densify_convert +{}; + +template +struct densify + : geometry::detail::densify::densify_convert +{}; + +template +struct densify + : geometry::detail::densify::densify_convert +{}; + template struct densify : geometry::detail::densify::densify_range<> @@ -328,9 +360,9 @@ struct densify } // namespace resolve_strategy -namespace resolve_variant { +namespace resolve_dynamic { -template +template ::type> struct densify { template @@ -346,43 +378,48 @@ struct densify } }; -template -struct densify > +template +struct densify { - template - struct visitor: boost::static_visitor - { - Distance const& m_max_distance; - Strategy const& m_strategy; - - visitor(Distance const& max_distance, Strategy const& strategy) - : m_max_distance(max_distance) - , m_strategy(strategy) - {} - - template - void operator()(Geometry const& geometry, Geometry& out) const - { - densify::apply(geometry, out, m_max_distance, m_strategy); - } - }; - template static inline void - apply(boost::variant const& geometry, - boost::variant& out, + apply(Geometry const& geometry, + Geometry& out, Distance const& max_distance, Strategy const& strategy) { - boost::apply_visitor( - visitor(max_distance, strategy), - geometry, - out - ); + traits::visit::apply([&](auto const& g) + { + using geom_t = util::remove_cref_t; + geom_t o; + densify::apply(g, o, max_distance, strategy); + out = std::move(o); + }, geometry); } }; -} // namespace resolve_variant +template +struct densify +{ + template + static inline void + apply(Geometry const& geometry, + Geometry& out, + Distance const& max_distance, + Strategy const& strategy) + { + detail::visit_breadth_first([&](auto const& g) + { + using geom_t = util::remove_cref_t; + geom_t o; + densify::apply(g, o, max_distance, strategy); + traits::emplace_back::apply(out, std::move(o)); + return true; + }, geometry); + } +}; + +} // namespace resolve_dynamic /*! @@ -428,7 +465,7 @@ inline void densify(Geometry const& geometry, geometry::clear(out); - resolve_variant::densify + resolve_dynamic::densify < Geometry >::apply(geometry, out, max_distance, strategy); diff --git a/include/boost/geometry/algorithms/detail/as_range.hpp b/include/boost/geometry/algorithms/detail/as_range.hpp deleted file mode 100644 index fe2016be5..000000000 --- a/include/boost/geometry/algorithms/detail/as_range.hpp +++ /dev/null @@ -1,91 +0,0 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) - -// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. -// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. - -// This file was modified by Oracle on 2020-2021. -// Modifications copyright (c) 2020-2021 Oracle and/or its affiliates. -// 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. - -// 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_ALGORITHMS_DETAIL_AS_RANGE_HPP -#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_AS_RANGE_HPP - - -#include - -#include -#include -#include -#include - - -namespace boost { namespace geometry -{ - - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - - -template ::type> -struct as_range : not_implemented -{}; - -template -struct as_range -{ - static inline typename ring_return_type::type get(Geometry& geometry) - { - return geometry; - } -}; - -template -struct as_range - : as_range -{}; - -template -struct as_range -{ - static inline typename ring_return_type::type get(Geometry& geometry) - { - return exterior_ring(geometry); - } -}; - - -} // namespace dispatch -#endif // DOXYGEN_NO_DISPATCH - -// Will probably be replaced by the more generic "view_as", therefore in detail -namespace detail -{ - -/*! -\brief Function getting either the range (ring, linestring) itself -or the outer ring (polygon) -\details Utility to handle polygon's outer ring as a range -\ingroup utility -*/ -template -inline typename ring_return_type::type as_range(Geometry& geometry) -{ - return dispatch::as_range::get(geometry); -} - -} - -}} // namespace boost::geometry - - -#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_AS_RANGE_HPP diff --git a/include/boost/geometry/algorithms/detail/buffer/piece_border.hpp b/include/boost/geometry/algorithms/detail/buffer/piece_border.hpp index ecd03d9c8..13d388e4e 100644 --- a/include/boost/geometry/algorithms/detail/buffer/piece_border.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/piece_border.hpp @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/include/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp b/include/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp index f51bd2900..6e66d2283 100644 --- a/include/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp @@ -175,7 +175,7 @@ public: // unit tests of hard cases start to fail (5 in multi_polygon) // But it is acknowlegded that such a threshold depends on the // scale of the input. - if (state.m_min_distance > 1.0e-5 || ! state.m_close_to_offset) + if (state.m_min_distance > 1.0e-4 || ! state.m_close_to_offset) { Turn& mutable_turn = m_turns[turn.turn_index]; mutable_turn.is_turn_traversable = false; diff --git a/include/boost/geometry/algorithms/detail/convex_hull/graham_andrew.hpp b/include/boost/geometry/algorithms/detail/convex_hull/graham_andrew.hpp index 9584f6a2f..9e59927f5 100644 --- a/include/boost/geometry/algorithms/detail/convex_hull/graham_andrew.hpp +++ b/include/boost/geometry/algorithms/detail/convex_hull/graham_andrew.hpp @@ -23,20 +23,19 @@ #include #include -#include -#include -#include -#include - #include #include +#include #include #include +#include #include #include #include #include +#include + namespace boost { namespace geometry { @@ -45,13 +44,15 @@ namespace boost { namespace geometry namespace detail { namespace convex_hull { -template -inline void get_extremes(Geometry const& geometry, +// TODO: All of the copies could be avoided if this function stored pointers to points. +// But would it be possible considering that a range can return proxy reference? +template +inline void get_extremes(InputProxy const& in_proxy, Point& left, Point& right, Less const& less) { bool first = true; - geometry::detail::for_each_range(geometry, [&](auto const& range) + in_proxy.for_each_range([&](auto const& range) { if (boost::empty(range)) { @@ -107,19 +108,13 @@ inline void get_extremes(Geometry const& geometry, } -template -< - typename Geometry, - typename Point, - typename Container, - typename SideStrategy -> -inline void assign_ranges(Geometry const& geometry, +template +inline void assign_ranges(InputProxy const& in_proxy, Point const& most_left, Point const& most_right, Container& lower_points, Container& upper_points, SideStrategy const& side) { - geometry::detail::for_each_range(geometry, [&](auto const& range) + in_proxy.for_each_range([&](auto const& range) { // Put points in one of the two output sequences for (auto it = boost::begin(range); it != boost::end(range); ++it) @@ -145,34 +140,17 @@ inline void assign_ranges(Geometry const& geometry, } -template -inline void sort(Range& range, Less const& less) -{ - std::sort(boost::begin(range), boost::end(range), less); -} - -} // namespace convex_hull - - /*! \brief Graham scan algorithm to calculate convex hull */ -template +template class graham_andrew { -public : - typedef OutputPoint point_type; - typedef InputGeometry geometry_type; - -private: - - typedef typename cs_tag::type cs_tag; - + typedef InputPoint point_type; typedef typename std::vector container_type; typedef typename std::vector::const_iterator iterator; typedef typename std::vector::const_reverse_iterator rev_iterator; - class partitions { friend class graham_andrew; @@ -182,14 +160,23 @@ private: container_type m_copied_input; }; - public: - typedef partitions state_type; + template + static void apply(InputProxy const& in_proxy, OutputRing & out_ring, Strategy& strategy) + { + partitions state; - template - inline void apply(InputGeometry const& geometry, - partitions& state, - Strategy& strategy) const + apply(in_proxy, state, strategy); + + result(state, + range::back_inserter(out_ring), + geometry::point_order::value == clockwise, + geometry::closure::value != open); + } + +private: + template + static void apply(InputProxy const& in_proxy, partitions& state, Strategy& strategy) { // First pass. // Get min/max (in most cases left / right) points @@ -203,14 +190,12 @@ public: // For symmetry and to get often more balanced lower/upper halves // we keep it. - typedef typename geometry::point_type::type point_type; - point_type most_left, most_right; // TODO: User-defined CS-specific less-compare geometry::less less; - detail::convex_hull::get_extremes(geometry, most_left, most_right, less); + detail::convex_hull::get_extremes(in_proxy, most_left, most_right, less); container_type lower_points, upper_points; @@ -219,13 +204,13 @@ public: // Bounding left/right points // Second pass, now that extremes are found, assign all points // in either lower, either upper - detail::convex_hull::assign_ranges(geometry, most_left, most_right, + detail::convex_hull::assign_ranges(in_proxy, most_left, most_right, lower_points, upper_points, side_strategy); // Sort both collections, first on x(, then on y) - detail::convex_hull::sort(lower_points, less); - detail::convex_hull::sort(upper_points, less); + std::sort(boost::begin(lower_points), boost::end(lower_points), less); + std::sort(boost::begin(upper_points), boost::end(upper_points), less); // And decide which point should be in the final hull build_half_hull<-1>(lower_points, state.m_lower_hull, @@ -236,26 +221,6 @@ public: side_strategy); } - - template - inline void result(partitions const& state, - OutputIterator out, - bool clockwise, - bool closed) const - { - if (clockwise) - { - output_ranges(state.m_upper_hull, state.m_lower_hull, out, closed); - } - else - { - output_ranges(state.m_lower_hull, state.m_upper_hull, out, closed); - } - } - - -private: - template static inline void build_half_hull(container_type const& input, container_type& output, @@ -300,6 +265,19 @@ private: } + template + static void result(partitions const& state, OutputIterator out, bool clockwise, bool closed) + { + if (clockwise) + { + output_ranges(state.m_upper_hull, state.m_lower_hull, out, closed); + } + else + { + output_ranges(state.m_lower_hull, state.m_upper_hull, out, closed); + } + } + template static inline void output_ranges(container_type const& first, container_type const& second, @@ -327,7 +305,7 @@ private: }; -} // namespace detail +}} // namespace detail::convex_hull #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry diff --git a/include/boost/geometry/algorithms/detail/convex_hull/interface.hpp b/include/boost/geometry/algorithms/detail/convex_hull/interface.hpp index ce61c9980..0fa011282 100644 --- a/include/boost/geometry/algorithms/detail/convex_hull/interface.hpp +++ b/include/boost/geometry/algorithms/detail/convex_hull/interface.hpp @@ -21,86 +21,171 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_CONVEX_HULL_INTERFACE_HPP #define BOOST_GEOMETRY_ALGORITHMS_CONVEX_HULL_INTERFACE_HPP -#include +#include -#include -#include -#include - -#include #include #include +#include +#include +#include +#include #include #include #include #include +#include #include #include +#include +#include +#include +#include // For backward compatibility #include +#include -#include +#include +#include +#include #include #include +#include +#include +#include namespace boost { namespace geometry { +// TODO: This file is named interface.hpp but the code below is not the interface. +// It's the implementation of the algorithm. #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace convex_hull { -template -struct hull_insert +// Abstraction representing ranges/rings of a geometry +template +struct input_geometry_proxy { - // Member template function (to avoid inconvenient declaration - // of output-iterator-type, from hull_to_geometry) - template - static inline OutputIterator apply(Geometry const& geometry, - OutputIterator out, - Strategy const& strategy) + input_geometry_proxy(Geometry const& geometry) + : m_geometry(geometry) + {} + + template + inline void for_each_range(UnaryFunction fun) const { - typedef graham_andrew - < - Geometry, - typename point_type::type - > ConvexHullAlgorithm; - - ConvexHullAlgorithm algorithm; - typename ConvexHullAlgorithm::state_type state; - - algorithm.apply(geometry, state, strategy); - algorithm.result(state, out, Order == clockwise, Closure != open); - - return out; + geometry::detail::for_each_range(m_geometry, fun); } + + Geometry const& m_geometry; }; -struct hull_to_geometry +// Abstraction representing ranges/rings of subgeometries of geometry collection +// with boxes converted to rings +template +struct input_geometry_collection_proxy { - template - static inline void apply(Geometry const& geometry, OutputGeometry& out, - Strategy const& strategy) + input_geometry_collection_proxy(Geometry const& geometry, BoxRings const& box_rings) + : m_geometry(geometry) + , m_box_rings(box_rings) + {} + + template + inline void for_each_range(UnaryFunction fun) const { - // TODO: Why not handle multi-polygon here? - // TODO: detail::as_range() is only used in this place in the whole library - // it should probably be located here. - // NOTE: A variable is created here because this can be a proxy range - // and back_insert_iterator<> can store a pointer to it. - // Handle linestring, ring and polygon the same: - auto&& range = detail::as_range(out); - hull_insert - < - geometry::point_order::value, - geometry::closure::value - >::apply(geometry, range::back_inserter(range), strategy); + detail::visit_breadth_first([&](auto const& g) + { + input_geometry_collection_proxy::call_for_non_boxes(g, fun); + return true; + }, m_geometry); + + for (auto const& r : m_box_rings) + { + geometry::detail::for_each_range(r, fun); + } } + +private: + template ::value, int> = 0> + static inline void call_for_non_boxes(G const& g, F & f) + { + geometry::detail::for_each_range(g, f); + } + template ::value, int> = 0> + static inline void call_for_non_boxes(G const&, F &) + {} + + Geometry const& m_geometry; + BoxRings const& m_box_rings; }; + +// TODO: Or just implement point_type<> for GeometryCollection +// and enforce the same point_type used in the whole sequence in check(). +template ::type> +struct default_strategy +{ + using type = typename strategies::convex_hull::services::default_strategy + < + Geometry + >::type; +}; + +template +struct default_strategy + : default_strategy::type> +{}; + + +// Utilities for output GC and DG +template +struct output_polygonal_less +{ + template + using priority = std::integral_constant + < + int, + (util::is_ring::value ? 0 : + util::is_polygon::value ? 1 : + util::is_multi_polygon::value ? 2 : 3) + >; + + static const bool value = priority::value < priority::value; +}; + +template +struct output_linear_less +{ + template + using priority = std::integral_constant + < + int, + (util::is_segment::value ? 0 : + util::is_linestring::value ? 1 : + util::is_multi_linestring::value ? 2 : 3) + >; + + static const bool value = priority::value < priority::value; +}; + +template +struct output_pointlike_less +{ + template + using priority = std::integral_constant + < + int, + (util::is_point::value ? 0 : + util::is_multi_point::value ? 1 : 2) + >; + + static const bool value = priority::value < priority::value; +}; + + }} // namespace detail::convex_hull #endif // DOXYGEN_NO_DETAIL @@ -116,39 +201,289 @@ template typename Tag = typename tag::type > struct convex_hull - : detail::convex_hull::hull_to_geometry -{}; +{ + template + static inline void apply(Geometry const& geometry, + OutputGeometry& out, + Strategy const& strategy) + { + detail::convex_hull::input_geometry_proxy in_proxy(geometry); + detail::convex_hull::graham_andrew + < + typename point_type::type + >::apply(in_proxy, out, strategy); + } +}; -// TODO: This is not correct in spherical and geographic CS + +// A hull for boxes is trivial. Any strategy is (currently) skipped. +// TODO: This is not correct in spherical and geographic CS. template struct convex_hull { template static inline void apply(Box const& box, OutputGeometry& out, - Strategy const& ) + Strategy const& strategy) { static bool const Close = geometry::closure::value == closed; static bool const Reverse = geometry::point_order::value == counterclockwise; - // A hull for boxes is trivial. Any strategy is (currently) skipped. - boost::array::type, 4> range; - geometry::detail::assign_box_corners_oriented(box, range); - geometry::append(out, range); + std::array::type, 4> arr; + // TODO: This assigns only 2d cooridnates! + // And it is also used in box_view<>! + geometry::detail::assign_box_corners_oriented(box, arr); + + std::move(arr.begin(), arr.end(), range::back_inserter(out)); if (BOOST_GEOMETRY_CONDITION(Close)) { - geometry::append(out, *boost::begin(range)); + range::push_back(out, range::front(out)); } } }; +template +struct convex_hull +{ + template + static inline void apply(GeometryCollection const& geometry, + OutputGeometry& out, + Strategy const& strategy) + { + // Assuming that single point_type is used by the GeometryCollection + using subgeometry_type = typename detail::first_geometry_type::type; + using point_type = typename geometry::point_type::type; + using ring_type = model::ring; -template -struct convex_hull_insert - : detail::convex_hull::hull_insert + // Calculate box rings once + std::vector box_rings; + detail::visit_breadth_first([&](auto const& g) + { + convex_hull::add_ring_for_box(box_rings, g, strategy); + return true; + }, geometry); + + detail::convex_hull::input_geometry_collection_proxy + < + GeometryCollection, std::vector + > in_proxy(geometry, box_rings); + + detail::convex_hull::graham_andrew + < + point_type + >::apply(in_proxy, out, strategy); + } + +private: + template + < + typename Ring, typename SubGeometry, typename Strategy, + std::enable_if_t::value, int> = 0 + > + static inline void add_ring_for_box(std::vector & rings, SubGeometry const& box, + Strategy const& strategy) + { + Ring ring; + convex_hull::apply(box, ring, strategy); + rings.push_back(std::move(ring)); + } + template + < + typename Ring, typename SubGeometry, typename Strategy, + std::enable_if_t::value, int> = 0 + > + static inline void add_ring_for_box(std::vector & , SubGeometry const& , + Strategy const& ) + {} +}; + + +template ::type> +struct convex_hull_out +{ + BOOST_GEOMETRY_STATIC_ASSERT_FALSE("This OutputGeometry is not supported.", OutputGeometry, Tag); +}; + +template +struct convex_hull_out +{ + template + static inline void apply(Geometry const& geometry, + OutputGeometry& out, + Strategies const& strategies) + { + dispatch::convex_hull::apply(geometry, out, strategies); + } +}; + +template +struct convex_hull_out +{ + template + static inline void apply(Geometry const& geometry, + OutputGeometry& out, + Strategies const& strategies) + { + auto&& ring = exterior_ring(out); + dispatch::convex_hull::apply(geometry, ring, strategies); + } +}; + +template +struct convex_hull_out +{ + template + static inline void apply(Geometry const& geometry, + OutputGeometry& out, + Strategies const& strategies) + { + typename boost::range_value::type polygon; + auto&& ring = exterior_ring(polygon); + dispatch::convex_hull::apply(geometry, ring, strategies); + // Empty input is checked so the output shouldn't be empty + range::push_back(out, std::move(polygon)); + } +}; + +template +struct convex_hull_out +{ + using polygonal_t = typename util::sequence_min_element + < + typename traits::geometry_types::type, + detail::convex_hull::output_polygonal_less + >::type; + using linear_t = typename util::sequence_min_element + < + typename traits::geometry_types::type, + detail::convex_hull::output_linear_less + >::type; + using pointlike_t = typename util::sequence_min_element + < + typename traits::geometry_types::type, + detail::convex_hull::output_pointlike_less + >::type; + + // select_element may define different kind of geometry than the one that is desired + BOOST_GEOMETRY_STATIC_ASSERT(util::is_polygonal::value, + "It must be possible to store polygonal geometry in OutputGeometry.", polygonal_t); + BOOST_GEOMETRY_STATIC_ASSERT(util::is_linear::value, + "It must be possible to store linear geometry in OutputGeometry.", linear_t); + BOOST_GEOMETRY_STATIC_ASSERT(util::is_pointlike::value, + "It must be possible to store pointlike geometry in OutputGeometry.", pointlike_t); + + template + static inline void apply(Geometry const& geometry, + OutputGeometry& out, + Strategies const& strategies) + { + polygonal_t polygonal; + convex_hull_out::apply(geometry, polygonal, strategies); + // Empty input is checked so the output shouldn't be empty + auto&& out_ring = ring(polygonal); + + if (boost::size(out_ring) == detail::minimum_ring_size::value) + { + using detail::equals::equals_point_point; + if (equals_point_point(range::front(out_ring), range::at(out_ring, 1), strategies)) + { + pointlike_t pointlike; + move_to_pointlike(out_ring, pointlike); + move_to_out(pointlike, out); + return; + } + if (equals_point_point(range::front(out_ring), range::at(out_ring, 2), strategies)) + { + linear_t linear; + move_to_linear(out_ring, linear); + move_to_out(linear, out); + return; + } + } + + move_to_out(polygonal, out); + } + +private: + template = 0> + static decltype(auto) ring(Polygonal const& polygonal) + { + return polygonal; + } + template = 0> + static decltype(auto) ring(Polygonal const& polygonal) + { + return exterior_ring(polygonal); + } + template = 0> + static decltype(auto) ring(Polygonal const& polygonal) + { + return exterior_ring(range::front(polygonal)); + } + + template = 0> + static void move_to_linear(Range & out_range, Linear & seg) + { + detail::assign_point_to_index<0>(range::front(out_range), seg); + detail::assign_point_to_index<1>(range::at(out_range, 1), seg); + } + template = 0> + static void move_to_linear(Range & out_range, Linear & ls) + { + std::move(boost::begin(out_range), boost::begin(out_range) + 2, range::back_inserter(ls)); + } + template = 0> + static void move_to_linear(Range & out_range, Linear & mls) + { + typename boost::range_value::type ls; + std::move(boost::begin(out_range), boost::begin(out_range) + 2, range::back_inserter(ls)); + range::push_back(mls, std::move(ls)); + } + + template = 0> + static void move_to_pointlike(Range & out_range, PointLike & pt) + { + pt = range::front(out_range); + } + template = 0> + static void move_to_pointlike(Range & out_range, PointLike & mpt) + { + range::push_back(mpt, std::move(range::front(out_range))); + } + + template + < + typename Geometry, typename OutputGeometry_, + util::enable_if_geometry_collection_t = 0 + > + static void move_to_out(Geometry & g, OutputGeometry_ & out) + { + range::emplace_back(out, std::move(g)); + } + template + < + typename Geometry, typename OutputGeometry_, + util::enable_if_dynamic_geometry_t = 0 + > + static void move_to_out(Geometry & g, OutputGeometry_ & out) + { + out = std::move(g); + } +}; + +template +struct convex_hull_out + : convex_hull_out +{}; + + +// For backward compatibility +template +struct convex_hull_out + : convex_hull_out {}; @@ -158,66 +493,42 @@ struct convex_hull_insert namespace resolve_strategy { +template struct convex_hull { - template - static inline void apply(Geometry const& geometry, - OutputGeometry& out, - Strategy const& strategy) - { - //BOOST_CONCEPT_ASSERT( (geometry::concepts::ConvexHullStrategy) ); - dispatch::convex_hull::apply(geometry, out, strategy); - } - template static inline void apply(Geometry const& geometry, OutputGeometry& out, - default_strategy) + Strategies const& strategies) { - typedef typename strategies::convex_hull::services::default_strategy - < - Geometry - >::type strategy_type; - - apply(geometry, out, strategy_type()); + dispatch::convex_hull_out::apply(geometry, out, strategies); } }; -struct convex_hull_insert +template <> +struct convex_hull { - template - static inline OutputIterator apply(Geometry const& geometry, - OutputIterator& out, - Strategy const& strategy) + template + static inline void apply(Geometry const& geometry, + OutputGeometry& out, + default_strategy const&) { - //BOOST_CONCEPT_ASSERT( (geometry::concepts::ConvexHullStrategy) ); - - return dispatch::convex_hull_insert< - geometry::point_order::value, - geometry::closure::value - >::apply(geometry, out, strategy); - } - - template - static inline OutputIterator apply(Geometry const& geometry, - OutputIterator& out, - default_strategy) - { - typedef typename strategies::convex_hull::services::default_strategy + using strategy_type = typename detail::convex_hull::default_strategy < Geometry - >::type strategy_type; + >::type; - return apply(geometry, out, strategy_type()); + dispatch::convex_hull_out::apply(geometry, out, strategy_type()); } }; + } // namespace resolve_strategy -namespace resolve_variant { +namespace resolve_dynamic { -template +template ::type> struct convex_hull { template @@ -230,88 +541,27 @@ struct convex_hull OutputGeometry >(); - resolve_strategy::convex_hull::apply(geometry, out, strategy); - } -}; - -template -struct convex_hull > -{ - template - struct visitor: boost::static_visitor - { - OutputGeometry& m_out; - Strategy const& m_strategy; - - visitor(OutputGeometry& out, Strategy const& strategy) - : m_out(out), m_strategy(strategy) - {} - - template - void operator()(Geometry const& geometry) const - { - convex_hull::apply(geometry, m_out, m_strategy); - } - }; - - template - static inline void - apply(boost::variant const& geometry, - OutputGeometry& out, - Strategy const& strategy) - { - boost::apply_visitor(visitor(out, strategy), - geometry); + resolve_strategy::convex_hull::apply(geometry, out, strategy); } }; template -struct convex_hull_insert +struct convex_hull { - template - static inline OutputIterator apply(Geometry const& geometry, - OutputIterator& out, - Strategy const& strategy) + template + static inline void apply(Geometry const& geometry, + OutputGeometry& out, + Strategy const& strategy) { - // Concept: output point type = point type of input geometry - concepts::check(); - concepts::check::type>(); - - return resolve_strategy::convex_hull_insert::apply(geometry, out, strategy); - } -}; - -template -struct convex_hull_insert > -{ - template - struct visitor: boost::static_visitor - { - OutputIterator& m_out; - Strategy const& m_strategy; - - visitor(OutputIterator& out, Strategy const& strategy) - : m_out(out), m_strategy(strategy) - {} - - template - OutputIterator operator()(Geometry const& geometry) const + traits::visit::apply([&](auto const& g) { - return convex_hull_insert::apply(geometry, m_out, m_strategy); - } - }; - - template - static inline OutputIterator - apply(boost::variant const& geometry, - OutputIterator& out, - Strategy const& strategy) - { - return boost::apply_visitor(visitor(out, strategy), geometry); + convex_hull>::apply(g, out, strategy); + }, geometry); } }; -} // namespace resolve_variant + +} // namespace resolve_dynamic /*! @@ -330,8 +580,7 @@ struct convex_hull_insert > \qbk{[include reference/algorithms/convex_hull.qbk]} */ template -inline void convex_hull(Geometry const& geometry, - OutputGeometry& out, Strategy const& strategy) +inline void convex_hull(Geometry const& geometry, OutputGeometry& out, Strategy const& strategy) { if (geometry::is_empty(geometry)) { @@ -339,7 +588,7 @@ inline void convex_hull(Geometry const& geometry, return; } - resolve_variant::convex_hull::apply(geometry, out, strategy); + resolve_dynamic::convex_hull::apply(geometry, out, strategy); } @@ -355,52 +604,11 @@ inline void convex_hull(Geometry const& geometry, \qbk{[include reference/algorithms/convex_hull.qbk]} */ template -inline void convex_hull(Geometry const& geometry, - OutputGeometry& hull) +inline void convex_hull(Geometry const& geometry, OutputGeometry& hull) { geometry::convex_hull(geometry, hull, default_strategy()); } -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace convex_hull -{ - - -template -inline OutputIterator convex_hull_insert(Geometry const& geometry, - OutputIterator out, Strategy const& strategy) -{ - return resolve_variant::convex_hull_insert - < - Geometry - >::apply(geometry, out, strategy); -} - - -/*! -\brief Calculate the convex hull of a geometry, output-iterator version -\ingroup convex_hull -\tparam Geometry the input geometry type -\tparam OutputIterator: an output-iterator -\param geometry the geometry to calculate convex hull from -\param out an output iterator outputing points of the convex hull -\note This overloaded version outputs to an output iterator. -In this case, nothing is known about its point-type or - about its clockwise order. Therefore, the input point-type - and order are copied - - */ -template -inline OutputIterator convex_hull_insert(Geometry const& geometry, - OutputIterator out) -{ - return convex_hull_insert(geometry, out, default_strategy()); -} - - -}} // namespace detail::convex_hull -#endif // DOXYGEN_NO_DETAIL - }} // namespace boost::geometry diff --git a/include/boost/geometry/algorithms/detail/direction_code.hpp b/include/boost/geometry/algorithms/detail/direction_code.hpp index 269e9b476..966efc3f8 100644 --- a/include/boost/geometry/algorithms/detail/direction_code.hpp +++ b/include/boost/geometry/algorithms/detail/direction_code.hpp @@ -79,7 +79,8 @@ struct direction_code_impl } calc_t const sv = arithmetic::side_value(line, point); - return sv == 0 ? 0 : sv > 0 ? 1 : -1; + static calc_t const zero = 0; + return sv == zero ? 0 : sv > zero ? 1 : -1; } }; diff --git a/include/boost/geometry/algorithms/detail/distance/geometry_collection.hpp b/include/boost/geometry/algorithms/detail/distance/geometry_collection.hpp new file mode 100644 index 000000000..f23095843 --- /dev/null +++ b/include/boost/geometry/algorithms/detail/distance/geometry_collection.hpp @@ -0,0 +1,237 @@ +// Boost.Geometry + +// Copyright (c) 2021 Oracle and/or its affiliates. +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_GEOMETRY_COLLECTION_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_GEOMETRY_COLLECTION_HPP + + +#include + +#include +#include +#include +#include +#include +#include +#include + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace distance +{ + + +template +inline auto geometry_to_collection(Geometry const& geometry, + GeometryCollection const& collection, + Strategies const& strategies) +{ + using result_t = typename geometry::distance_result::type; + result_t result = 0; + bool is_first = true; + detail::visit_breadth_first([&](auto const& g) + { + result_t r = dispatch::distance + < + Geometry, util::remove_cref_t, Strategies + >::apply(geometry, g, strategies); + if (is_first) + { + result = r; + is_first = false; + } + else if (r < result) + { + result = r; + } + return result > result_t(0); + }, collection); + + return result; +} + +template +inline auto collection_to_collection(GeometryCollection1 const& collection1, + GeometryCollection2 const& collection2, + Strategies const& strategies) +{ + using result_t = typename geometry::distance_result::type; + + using point1_t = typename geometry::point_type::type; + using box1_t = model::box; + using point2_t = typename geometry::point_type::type; + using box2_t = model::box; + + using rtree_value_t = std::pair::type>; + using rtree_params_t = index::parameters, Strategies>; + using rtree_t = index::rtree; + + rtree_params_t rtree_params(index::rstar<4>(), strategies); + rtree_t rtree(rtree_params); + + // Build rtree of boxes and iterators of elements of GC1 + // TODO: replace this with visit_breadth_first_iterator to avoid creating an unnecessary container? + { + std::vector values; + visit_breadth_first_impl::apply([&](auto & g1, auto it) + { + box1_t b1 = geometry::return_envelope(g1, strategies); + geometry::detail::expand_by_epsilon(b1); + values.emplace_back(b1, it); + return true; + }, collection1); + rtree_t rt(values.begin(), values.end(), rtree_params); + rtree = std::move(rt); + } + + result_t const zero = 0; + auto const rtree_qend = rtree.qend(); + + result_t result = 0; + bool is_first = true; + visit_breadth_first([&](auto const& g2) + { + box2_t b2 = geometry::return_envelope(g2, strategies); + geometry::detail::expand_by_epsilon(b2); + + for (auto it = rtree.qbegin(index::nearest(b2, rtree.size())) ; it != rtree_qend ; ++it) + { + // If the distance between boxes is greater than or equal to previously found + // distance between geometries then stop processing the current b2 because no + // closer b1 will be found + if (! is_first) + { + result_t const bd = dispatch::distance + < + box1_t, box2_t, Strategies + >::apply(it->first, b2, strategies); + if (bd >= result) + { + break; + } + } + + // Boxes are closer than the previously found distance (or it's the first time), + // calculate the new distance between geometries and check if it's closer (or assign it). + traits::iter_visit::apply([&](auto const& g1) + { + result_t const d = dispatch::distance + < + util::remove_cref_t, util::remove_cref_t, + Strategies + >::apply(g1, g2, strategies); + if (is_first) + { + result = d; + is_first = false; + } + else if (d < result) + { + result = d; + } + }, it->second); + + // The smallest possible distance found, end searching. + if (! is_first && result <= zero) + { + return false; + } + } + + // Just in case + return is_first || result > zero; + }, collection2); + + return result; +} + + +}} // namespace detail::distance +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template +< + typename Geometry, typename GeometryCollection, typename Strategies, typename Tag1 +> +struct distance + < + Geometry, GeometryCollection, Strategies, + Tag1, geometry_collection_tag, void, false + > +{ + static inline auto apply(Geometry const& geometry, + GeometryCollection const& collection, + Strategies const& strategies) + { + assert_dimension_equal(); + + return detail::distance::geometry_to_collection(geometry, collection, strategies); + } +}; + +template +< + typename GeometryCollection, typename Geometry, typename Strategies, typename Tag2 +> +struct distance + < + GeometryCollection, Geometry, Strategies, + geometry_collection_tag, Tag2, void, false + > +{ + static inline auto apply(GeometryCollection const& collection, + Geometry const& geometry, + Strategies const& strategies) + { + assert_dimension_equal(); + + return detail::distance::geometry_to_collection(geometry, collection, strategies); + } +}; + +template +< + typename GeometryCollection1, typename GeometryCollection2, typename Strategies +> +struct distance + < + GeometryCollection1, GeometryCollection2, Strategies, + geometry_collection_tag, geometry_collection_tag, void, false + > +{ + static inline auto apply(GeometryCollection1 const& collection1, + GeometryCollection2 const& collection2, + Strategies const& strategies) + { + assert_dimension_equal(); + + // Build the rtree for the smaller GC (ignoring recursive GCs) + return boost::size(collection1) <= boost::size(collection2) + ? detail::distance::collection_to_collection(collection1, collection2, strategies) + : detail::distance::collection_to_collection(collection2, collection1, strategies); + } +}; + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_BOX_HPP diff --git a/include/boost/geometry/algorithms/detail/distance/implementation.hpp b/include/boost/geometry/algorithms/detail/distance/implementation.hpp index 91b1d817b..8dfe4fec7 100644 --- a/include/boost/geometry/algorithms/detail/distance/implementation.hpp +++ b/include/boost/geometry/algorithms/detail/distance/implementation.hpp @@ -7,9 +7,9 @@ // This file was modified by Oracle on 2014-2021. // Modifications copyright (c) 2014-2021, 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. @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/geometry/algorithms/detail/distance/interface.hpp b/include/boost/geometry/algorithms/detail/distance/interface.hpp index f39f50554..5fdb66bea 100644 --- a/include/boost/geometry/algorithms/detail/distance/interface.hpp +++ b/include/boost/geometry/algorithms/detail/distance/interface.hpp @@ -8,7 +8,6 @@ // This file was modified by Oracle on 2014-2021. // Modifications copyright (c) 2014-2021, Oracle and/or its affiliates. - // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -28,6 +27,7 @@ #include #include +#include #include // For backward compatibility #include @@ -92,10 +92,9 @@ template struct distance { template - static inline typename distance_result::type - apply(Geometry1 const& geometry1, - Geometry2 const& geometry2, - Strategy const& strategy) + static inline auto apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { return dispatch::distance < @@ -123,11 +122,9 @@ struct distance typename Geometry1, typename Geometry2, typename S, std::enable_if_t::value, int> = 0 > - static inline - typename distance_result::type - apply(Geometry1 const& geometry1, - Geometry2 const& geometry2, - S const& strategy) + static inline auto apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + S const& strategy) { typedef strategies::distance::services::strategy_converter converter; typedef decltype(converter::get(strategy)) strategy_type; @@ -143,11 +140,9 @@ struct distance typename Geometry1, typename Geometry2, typename S, std::enable_if_t::value, int> = 0 > - static inline - typename distance_result::type - apply(Geometry1 const& geometry1, - Geometry2 const& geometry2, - S const& strategy) + static inline auto apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + S const& strategy) { typedef strategies::distance::services::custom_strategy_converter < @@ -166,11 +161,9 @@ template <> struct distance { template - static inline - typename distance_result::type - apply(Geometry1 const& geometry1, - Geometry2 const& geometry2, - default_strategy) + static inline auto apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + default_strategy) { typedef typename strategies::distance::services::default_strategy < @@ -187,18 +180,22 @@ struct distance } // namespace resolve_strategy -namespace resolve_variant +namespace resolve_dynamic { -template +template +< + typename Geometry1, typename Geometry2, + typename Tag1 = typename geometry::tag::type, + typename Tag2 = typename geometry::tag::type +> struct distance { template - static inline typename distance_result::type - apply(Geometry1 const& geometry1, - Geometry2 const& geometry2, - Strategy const& strategy) + static inline auto apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { return resolve_strategy::distance < @@ -208,174 +205,72 @@ struct distance }; -template -struct distance, Geometry2> +template +struct distance { template - struct visitor: static_visitor - < - typename distance_result - < - variant, - Geometry2, - Strategy - >::type - > + static inline auto apply(DynamicGeometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { - Geometry2 const& m_geometry2; - Strategy const& m_strategy; - - visitor(Geometry2 const& geometry2, - Strategy const& strategy) - : m_geometry2(geometry2), - m_strategy(strategy) - {} - - template - typename distance_result::type - operator()(Geometry1 const& geometry1) const + using result_t = typename geometry::distance_result::type; + result_t result = 0; + traits::visit::apply([&](auto const& g1) { - return distance - < - Geometry1, - Geometry2 - >::template apply - < - Strategy - >(geometry1, m_geometry2, m_strategy); - } - }; - - template - static inline typename distance_result - < - variant, - Geometry2, - Strategy - >::type - apply(variant const& geometry1, - Geometry2 const& geometry2, - Strategy const& strategy) - { - return boost::apply_visitor(visitor(geometry2, strategy), geometry1); + result = resolve_strategy::distance + < + Strategy + >::apply(g1, geometry2, strategy); + }, geometry1); + return result; } }; -template -struct distance > +template +struct distance { template - struct visitor: static_visitor - < - typename distance_result - < - Geometry1, - variant, - Strategy - >::type - > + static inline auto apply(Geometry1 const& geometry1, + DynamicGeometry2 const& geometry2, + Strategy const& strategy) { - Geometry1 const& m_geometry1; - Strategy const& m_strategy; - - visitor(Geometry1 const& geometry1, - Strategy const& strategy) - : m_geometry1(geometry1), - m_strategy(strategy) - {} - - template - typename distance_result::type - operator()(Geometry2 const& geometry2) const + using result_t = typename geometry::distance_result::type; + result_t result = 0; + traits::visit::apply([&](auto const& g2) { - return distance - < - Geometry1, - Geometry2 - >::template apply - < - Strategy - >(m_geometry1, geometry2, m_strategy); - } - }; - - template - static inline typename distance_result - < - Geometry1, - variant, - Strategy - >::type - apply( - Geometry1 const& geometry1, - const variant& geometry2, - Strategy const& strategy) - { - return boost::apply_visitor(visitor(geometry1, strategy), geometry2); + result = resolve_strategy::distance + < + Strategy + >::apply(geometry1, g2, strategy); + }, geometry2); + return result; } }; -template -< - BOOST_VARIANT_ENUM_PARAMS(typename T1), - BOOST_VARIANT_ENUM_PARAMS(typename T2) -> -struct distance - < - boost::variant, - boost::variant - > +template +struct distance { template - struct visitor: static_visitor - < - typename distance_result - < - boost::variant, - boost::variant, - Strategy - >::type - > + static inline auto apply(DynamicGeometry1 const& geometry1, + DynamicGeometry2 const& geometry2, + Strategy const& strategy) { - Strategy const& m_strategy; - - visitor(Strategy const& strategy) - : m_strategy(strategy) - {} - - template - typename distance_result::type - operator()(Geometry1 const& geometry1, Geometry2 const& geometry2) const + using result_t = typename geometry::distance_result::type; + result_t result = 0; + traits::visit::apply([&](auto const& g1, auto const& g2) { - return distance - < - Geometry1, - Geometry2 - >::template apply - < - Strategy - >(geometry1, geometry2, m_strategy); - } - }; - - template - static inline typename distance_result - < - boost::variant, - boost::variant, - Strategy - >::type - apply(boost::variant const& geometry1, - boost::variant const& geometry2, - Strategy const& strategy) - { - return boost::apply_visitor(visitor(strategy), geometry1, geometry2); + result = resolve_strategy::distance + < + Strategy + >::apply(g1, g2, strategy); + }, geometry1, geometry2); + return result; } }; -} // namespace resolve_variant +} // namespace resolve_dynamic /*! @@ -415,10 +310,9 @@ for distance, it is probably so that there is no specialization for return_type<...> for your strategy. */ template -inline typename distance_result::type -distance(Geometry1 const& geometry1, - Geometry2 const& geometry2, - Strategy const& strategy) +inline auto distance(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy) { concepts::check(); concepts::check(); @@ -426,7 +320,7 @@ distance(Geometry1 const& geometry1, detail::throw_on_empty_input(geometry1); detail::throw_on_empty_input(geometry2); - return resolve_variant::distance + return resolve_dynamic::distance < Geometry1, Geometry2 @@ -448,13 +342,9 @@ distance(Geometry1 const& geometry1, \qbk{[include reference/algorithms/distance.qbk]} */ template -inline typename default_distance_result::type -distance(Geometry1 const& geometry1, - Geometry2 const& geometry2) +inline auto distance(Geometry1 const& geometry1, + Geometry2 const& geometry2) { - concepts::check(); - concepts::check(); - return geometry::distance(geometry1, geometry2, default_strategy()); } diff --git a/include/boost/geometry/algorithms/detail/envelope/geometry_collection.hpp b/include/boost/geometry/algorithms/detail/envelope/geometry_collection.hpp new file mode 100644 index 000000000..cf3d044f3 --- /dev/null +++ b/include/boost/geometry/algorithms/detail/envelope/geometry_collection.hpp @@ -0,0 +1,63 @@ +// Boost.Geometry + +// Copyright (c) 2021, Oracle and/or its affiliates. +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +// 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_ENVELOPE_GEOMETRY_COLLECTION_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_GEOMETRY_COLLECTION_HPP + + +#include +#include +#include + +#include + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template +struct envelope +{ + template + static inline void apply(Geometry const& geometry, + Box& mbr, + Strategy const& strategy) + { + using strategy_t = decltype(strategy.envelope(geometry, mbr)); + using state_t = typename strategy_t::template multi_state; + + state_t state; + detail::visit_breadth_first([&](auto const& g) + { + if (! geometry::is_empty(g)) + { + Box b; + envelope>::apply(g, b, strategy); + state.apply(b); + } + return true; + }, geometry); + state.result(mbr); + } +}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_GEOMETRY_COLLECTION_HPP diff --git a/include/boost/geometry/algorithms/detail/envelope/implementation.hpp b/include/boost/geometry/algorithms/detail/envelope/implementation.hpp index 569c77b03..cb4108d16 100644 --- a/include/boost/geometry/algorithms/detail/envelope/implementation.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/implementation.hpp @@ -6,9 +6,9 @@ // This file was modified by Oracle on 2015-2021. // Modifications copyright (c) 2015-2021, 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. @@ -28,6 +28,7 @@ #include #include +#include #include #include #include diff --git a/include/boost/geometry/algorithms/detail/envelope/interface.hpp b/include/boost/geometry/algorithms/detail/envelope/interface.hpp index 3f6dece38..70679dd91 100644 --- a/include/boost/geometry/algorithms/detail/envelope/interface.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/interface.hpp @@ -22,16 +22,14 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_INTERFACE_HPP -#include -#include -#include - #include #include #include #include +#include +#include // For backward compatibility #include #include @@ -39,6 +37,7 @@ #include #include +#include namespace boost { namespace geometry @@ -98,10 +97,10 @@ struct envelope } // namespace resolve_strategy -namespace resolve_variant +namespace resolve_dynamic { -template +template ::type> struct envelope { template @@ -117,38 +116,22 @@ struct envelope }; -template -struct envelope > +template +struct envelope { template - struct visitor: boost::static_visitor + static inline void apply(Geometry const& geometry, + Box& box, + Strategy const& strategy) { - Box& m_box; - Strategy const& m_strategy; - - visitor(Box& box, Strategy const& strategy) - : m_box(box) - , m_strategy(strategy) - {} - - template - void operator()(Geometry const& geometry) const + traits::visit::apply([&](auto const& g) { - envelope::apply(geometry, m_box, m_strategy); - } - }; - - template - static inline void - apply(boost::variant const& geometry, - Box& box, - Strategy const& strategy) - { - boost::apply_visitor(visitor(box, strategy), geometry); + envelope>::apply(g, box, strategy); + }, geometry); } }; -} // namespace resolve_variant +} // namespace resolve_dynamic /*! @@ -172,7 +155,7 @@ struct envelope > template inline void envelope(Geometry const& geometry, Box& mbr, Strategy const& strategy) { - resolve_variant::envelope::apply(geometry, mbr, strategy); + resolve_dynamic::envelope::apply(geometry, mbr, strategy); } /*! @@ -193,7 +176,7 @@ inline void envelope(Geometry const& geometry, Box& mbr, Strategy const& strateg template inline void envelope(Geometry const& geometry, Box& mbr) { - resolve_variant::envelope::apply(geometry, mbr, default_strategy()); + resolve_dynamic::envelope::apply(geometry, mbr, default_strategy()); } @@ -219,7 +202,7 @@ template inline Box return_envelope(Geometry const& geometry, Strategy const& strategy) { Box mbr; - resolve_variant::envelope::apply(geometry, mbr, strategy); + resolve_dynamic::envelope::apply(geometry, mbr, strategy); return mbr; } @@ -242,7 +225,7 @@ template inline Box return_envelope(Geometry const& geometry) { Box mbr; - resolve_variant::envelope::apply(geometry, mbr, default_strategy()); + resolve_dynamic::envelope::apply(geometry, mbr, default_strategy()); return mbr; } diff --git a/include/boost/geometry/algorithms/detail/equals/collect_vectors.hpp b/include/boost/geometry/algorithms/detail/equals/collect_vectors.hpp index f2e1c7eb4..e6606a160 100644 --- a/include/boost/geometry/algorithms/detail/equals/collect_vectors.hpp +++ b/include/boost/geometry/algorithms/detail/equals/collect_vectors.hpp @@ -39,7 +39,8 @@ #include -#include +#include +#include #include #include @@ -61,11 +62,11 @@ struct collected_vector : nyi::not_implemented_tag {}; -// compatible with side_by_triangle cartesian strategy +// compatible with side_robust cartesian strategy template struct collected_vector < - T, Geometry, strategy::side::side_by_triangle, CSTag + T, Geometry, strategy::side::side_robust, CSTag > { typedef T type; @@ -156,6 +157,14 @@ private: //T dx_0, dy_0; }; +template +struct collected_vector + < + T, Geometry, strategy::side::side_by_triangle, CSTag + > + : collected_vector, CSTag> +{}; + // Compatible with spherical_side_formula which currently // is the default spherical_equatorial and geographic strategy // so CSTag is spherical_equatorial_tag or geographic_tag diff --git a/include/boost/geometry/algorithms/detail/expand/interface.hpp b/include/boost/geometry/algorithms/detail/expand/interface.hpp index 442a4e011..d2cdf97e7 100644 --- a/include/boost/geometry/algorithms/detail/expand/interface.hpp +++ b/include/boost/geometry/algorithms/detail/expand/interface.hpp @@ -22,22 +22,23 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_INTERFACE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_INTERFACE_HPP -#include -#include -#include #include #include #include #include +#include +#include // For backward compatibility #include #include #include #include +#include + namespace boost { namespace geometry { @@ -97,10 +98,10 @@ struct expand } //namespace resolve_strategy -namespace resolve_variant +namespace resolve_dynamic { -template +template ::type> struct expand { template @@ -116,68 +117,24 @@ struct expand } }; -template -struct expand > +template +struct expand { - template - struct visitor: boost::static_visitor - { - Box& m_box; - Strategy const& m_strategy; - - visitor(Box& box, Strategy const& strategy) - : m_box(box) - , m_strategy(strategy) - {} - - template - void operator()(Geometry const& geometry) const - { - return expand::apply(m_box, geometry, m_strategy); - } - }; - template - static inline void - apply(Box& box, - boost::variant const& geometry, - Strategy const& strategy) + static inline void apply(Box& box, + Geometry const& geometry, + Strategy const& strategy) { - return boost::apply_visitor(visitor(box, strategy), - geometry); + traits::visit::apply([&](auto const& g) + { + expand>::apply(box, g, strategy); + }, geometry); } }; -} // namespace resolve_variant +} // namespace resolve_dynamic -/*** -*! -\brief Expands a box using the extend (envelope) of another geometry (box, point) -\ingroup expand -\tparam Box type of the box -\tparam Geometry of second geometry, to be expanded with the box -\param box box to expand another geometry with, might be changed -\param geometry other geometry -\param strategy_less -\param strategy_greater -\note Strategy is currently ignored - * -template -< - typename Box, typename Geometry, - typename StrategyLess, typename StrategyGreater -> -inline void expand(Box& box, Geometry const& geometry, - StrategyLess const& strategy_less, - StrategyGreater const& strategy_greater) -{ - concepts::check_concepts_and_equal_dimensions(); - - dispatch::expand::apply(box, geometry); -} -***/ - /*! \brief Expands (with strategy) \ingroup expand @@ -195,7 +152,7 @@ will be added to the box template inline void expand(Box& box, Geometry const& geometry, Strategy const& strategy) { - resolve_variant::expand::apply(box, geometry, strategy); + resolve_dynamic::expand::apply(box, geometry, strategy); } /*! @@ -213,7 +170,7 @@ added to the box template inline void expand(Box& box, Geometry const& geometry) { - resolve_variant::expand::apply(box, geometry, default_strategy()); + resolve_dynamic::expand::apply(box, geometry, default_strategy()); } }} // namespace boost::geometry diff --git a/include/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp b/include/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp index 6c33961b3..b12c42c8e 100644 --- a/include/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp +++ b/include/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014-2020, Oracle and/or its affiliates. +// Copyright (c) 2014-2021, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -54,11 +54,6 @@ private: CSTag >::type rescale_policy_type; - typedef detail::overlay::get_turn_info - < - detail::overlay::assign_null_policy - > turn_policy; - public: typedef detail::overlay::turn_info < @@ -88,12 +83,11 @@ public: > interrupt_policy; // Calculate self-turns, skipping adjacent segments - detail::self_get_turn_points::self_turns(geometry, - strategy, - robust_policy, - turns, - interrupt_policy, - 0, true); + detail::self_get_turn_points::self_turns + < + false, detail::overlay::assign_null_policy + >(geometry, strategy, robust_policy, turns, interrupt_policy, + 0, true); if (interrupt_policy.has_intersections) { diff --git a/include/boost/geometry/algorithms/detail/is_valid/interface.hpp b/include/boost/geometry/algorithms/detail/is_valid/interface.hpp index 4f8d1f543..7ee7b38af 100644 --- a/include/boost/geometry/algorithms/detail/is_valid/interface.hpp +++ b/include/boost/geometry/algorithms/detail/is_valid/interface.hpp @@ -1,6 +1,6 @@ // Boost.Geometry -// Copyright (c) 2014-2020, Oracle and/or its affiliates. +// Copyright (c) 2014-2021, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -14,12 +14,11 @@ #include #include -#include -#include -#include - +#include #include #include +#include +#include // For backward compatibility #include #include #include @@ -90,10 +89,10 @@ struct is_valid } // namespace resolve_strategy -namespace resolve_variant +namespace resolve_dynamic { -template +template ::type> struct is_valid { template @@ -110,39 +109,42 @@ struct is_valid } }; -template -struct is_valid > +template +struct is_valid { template - struct visitor : boost::static_visitor + static inline bool apply(Geometry const& geometry, + VisitPolicy& policy_visitor, + Strategy const& strategy) { - visitor(VisitPolicy& policy, Strategy const& strategy) - : m_policy(policy) - , m_strategy(strategy) - {} - - template - bool operator()(Geometry const& geometry) const + bool result = true; + traits::visit::apply([&](auto const& g) { - return is_valid::apply(geometry, m_policy, m_strategy); - } - - VisitPolicy& m_policy; - Strategy const& m_strategy; - }; - - template - static inline bool - apply(boost::variant const& geometry, - VisitPolicy& policy_visitor, - Strategy const& strategy) - { - return boost::apply_visitor(visitor(policy_visitor, strategy), - geometry); + result = is_valid>::apply(g, policy_visitor, strategy); + }, geometry); + return result; } }; -} // namespace resolve_variant +template +struct is_valid +{ + template + static inline bool apply(Geometry const& geometry, + VisitPolicy& policy_visitor, + Strategy const& strategy) + { + bool result = true; + detail::visit_breadth_first([&](auto const& g) + { + result = is_valid>::apply(g, policy_visitor, strategy); + return result; + }, geometry); + return result; + } +}; + +} // namespace resolve_dynamic // Undocumented for now @@ -151,7 +153,7 @@ inline bool is_valid(Geometry const& geometry, VisitPolicy& visitor, Strategy const& strategy) { - return resolve_variant::is_valid::apply(geometry, visitor, strategy); + return resolve_dynamic::is_valid::apply(geometry, visitor, strategy); } @@ -175,7 +177,7 @@ template inline bool is_valid(Geometry const& geometry, Strategy const& strategy) { is_valid_default_policy<> visitor; - return resolve_variant::is_valid::apply(geometry, visitor, strategy); + return resolve_dynamic::is_valid::apply(geometry, visitor, strategy); } /*! @@ -220,7 +222,7 @@ template inline bool is_valid(Geometry const& geometry, validity_failure_type& failure, Strategy const& strategy) { failure_type_policy<> visitor; - bool result = resolve_variant::is_valid::apply(geometry, visitor, strategy); + bool result = resolve_dynamic::is_valid::apply(geometry, visitor, strategy); failure = visitor.failure(); return result; } @@ -271,7 +273,7 @@ inline bool is_valid(Geometry const& geometry, std::string& message, Strategy co { std::ostringstream stream; failing_reason_policy<> visitor(stream); - bool result = resolve_variant::is_valid::apply(geometry, visitor, strategy); + bool result = resolve_dynamic::is_valid::apply(geometry, visitor, strategy); message = stream.str(); return result; } diff --git a/include/boost/geometry/algorithms/detail/multi_modify.hpp b/include/boost/geometry/algorithms/detail/multi_modify.hpp index 9c2f18006..58597ed6f 100644 --- a/include/boost/geometry/algorithms/detail/multi_modify.hpp +++ b/include/boost/geometry/algorithms/detail/multi_modify.hpp @@ -4,8 +4,8 @@ // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. -// This file was modified by Oracle on 2017-2020. -// Modifications copyright (c) 2017-2020 Oracle and/or its affiliates. +// This file was modified by Oracle on 2017-2021. +// Modifications copyright (c) 2017-2021 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library @@ -32,27 +32,24 @@ namespace detail { -template +template struct multi_modify { + template static inline void apply(MultiGeometry& multi) { - typedef typename boost::range_iterator::type iterator_type; - for (iterator_type it = boost::begin(multi); - it != boost::end(multi); - ++it) + auto const end = boost::end(multi); + for (auto it = boost::begin(multi); it != end; ++it) { Policy::apply(*it); } } - template + template static inline void apply(MultiGeometry& multi, Strategy const& strategy) { - typedef typename boost::range_iterator::type iterator_type; - for (iterator_type it = boost::begin(multi); - it != boost::end(multi); - ++it) + auto const end = boost::end(multi); + for (auto it = boost::begin(multi); it != end; ++it) { Policy::apply(*it, strategy); } diff --git a/include/boost/geometry/algorithms/detail/overlay/approximately_equals.hpp b/include/boost/geometry/algorithms/detail/overlay/approximately_equals.hpp index d28a04ee8..1f41085dc 100644 --- a/include/boost/geometry/algorithms/detail/overlay/approximately_equals.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/approximately_equals.hpp @@ -23,7 +23,7 @@ namespace detail { namespace overlay template inline bool approximately_equals(Point1 const& a, Point2 const& b, - E const& multiplier) + E const& epsilon_multiplier) { using coor_t = typename select_coordinate_type::type; using calc_t = typename geometry::select_most_precise::type; @@ -34,7 +34,7 @@ inline bool approximately_equals(Point1 const& a, Point2 const& b, calc_t const& b1 = geometry::get<1>(b); math::detail::equals_factor_policy policy(a0, b0, a1, b1); - policy.factor *= multiplier; + policy.multiply_epsilon(epsilon_multiplier); return math::detail::equals_by_policy(a0, b0, policy) && math::detail::equals_by_policy(a1, b1, policy); diff --git a/include/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp b/include/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp index 58ab4fcdd..7e2b0d0f2 100644 --- a/include/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp @@ -3,9 +3,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2017-2020. +// This file was modified by Oracle on 2017-2021. // Modifications copyright (c) 2017-2020 Oracle and/or its affiliates. - // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, @@ -353,21 +352,20 @@ inline typename geometry::coordinate_type::type template inline void calculate_remaining_distance(Turns& turns) { - typedef typename boost::range_value::type turn_type; - typedef typename turn_type::turn_operation_type op_type; + using turn_type = typename boost::range_value::type; + using op_type = typename turn_type::turn_operation_type; - for (typename boost::range_iterator::type - it = boost::begin(turns); - it != boost::end(turns); - ++it) + typename op_type::comparable_distance_type const zero_distance = 0; + + for (auto it = boost::begin(turns); it != boost::end(turns); ++it) { turn_type& turn = *it; op_type& op0 = turn.operations[0]; op_type& op1 = turn.operations[1]; - if (op0.remaining_distance != 0 - || op1.remaining_distance != 0) + if (op0.remaining_distance != zero_distance + || op1.remaining_distance != zero_distance) { continue; } diff --git a/include/boost/geometry/algorithms/detail/overlay/get_clusters.hpp b/include/boost/geometry/algorithms/detail/overlay/get_clusters.hpp index 1e612d657..bb6077ad8 100644 --- a/include/boost/geometry/algorithms/detail/overlay/get_clusters.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/get_clusters.hpp @@ -39,7 +39,8 @@ struct sweep_equal_policy static inline bool equals(P const& p1, P const& p2) { // Points within a kilo epsilon are considered as equal - return approximately_equals(p1, p2, 1000.0); + using coor_t = typename coordinate_type

::type; + return approximately_equals(p1, p2, coor_t(1000)); } template @@ -47,7 +48,8 @@ struct sweep_equal_policy { // This threshold is an arbitrary value // as long as it is than the used kilo-epsilon - return value > 1.0e-3; + T const limit = T(1) / T(1000); + return value > limit; } }; diff --git a/include/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp b/include/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp index fcd3635fd..839ba7211 100644 --- a/include/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp @@ -128,7 +128,8 @@ struct base_turn_handler } auto const dm = get_distance_measure(range_p.at(range_index), range_p.at(range_index + 1), range_q.at(point_index)); - return dm.measure == 0 ? 0 : dm.measure > 0 ? 1 : -1; + static decltype(dm.measure) const zero = 0; + return dm.measure == zero ? 0 : dm.measure > zero ? 1 : -1; } template @@ -241,33 +242,45 @@ struct base_turn_handler BOOST_GEOMETRY_ASSERT(index_q > 0 && index_q <= 2); #if ! defined(BOOST_GEOMETRY_USE_RESCALING) - ti.operations[IndexP].remaining_distance = distance_measure(ti.point, range_p.at(index_p)); - ti.operations[IndexQ].remaining_distance = distance_measure(ti.point, range_q.at(index_q)); + bool const p_in_range = index_p < range_p.size(); + bool const q_in_range = index_q < range_q.size(); + ti.operations[IndexP].remaining_distance + = p_in_range + ? distance_measure(ti.point, range_p.at(index_p)) + : 0; + ti.operations[IndexQ].remaining_distance + = q_in_range + ? distance_measure(ti.point, range_q.at(index_q)) + : 0; - // pk/q2 is considered as collinear, but there might be - // a tiny measurable difference. If so, use that. - // Calculate pk // qj-qk - bool const p_closer = - ti.operations[IndexP].remaining_distance - < ti.operations[IndexQ].remaining_distance; - auto const dm + if (p_in_range && q_in_range) + { + // pk/q2 is considered as collinear, but there might be + // a tiny measurable difference. If so, use that. + // Calculate pk // qj-qk + bool const p_closer + = ti.operations[IndexP].remaining_distance + < ti.operations[IndexQ].remaining_distance; + auto const dm = p_closer ? get_distance_measure(range_q.at(index_q - 1), range_q.at(index_q), range_p.at(index_p)) : get_distance_measure(range_p.at(index_p - 1), range_p.at(index_p), range_q.at(index_q)); - if (! dm.is_zero()) - { - // Not truely collinear, distinguish for union/intersection - // If p goes left (positive), take that for a union - bool const p_left = p_closer ? dm.is_positive() : dm.is_negative(); + if (! dm.is_zero()) + { + // Not truely collinear, distinguish for union/intersection + // If p goes left (positive), take that for a union + bool const p_left + = p_closer ? dm.is_positive() : dm.is_negative(); - ti.operations[IndexP].operation = p_left - ? operation_union : operation_intersection; - ti.operations[IndexQ].operation = p_left - ? operation_intersection : operation_union; - return; + ti.operations[IndexP].operation = p_left + ? operation_union : operation_intersection; + ti.operations[IndexQ].operation = p_left + ? operation_intersection : operation_union; + return; + } } #endif diff --git a/include/boost/geometry/algorithms/detail/overlay/is_self_turn.hpp b/include/boost/geometry/algorithms/detail/overlay/is_self_turn.hpp index 448c04404..1606c31e9 100644 --- a/include/boost/geometry/algorithms/detail/overlay/is_self_turn.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/is_self_turn.hpp @@ -26,8 +26,7 @@ struct is_self_turn_check template static inline bool apply(Turn const& turn) { - return turn.operations[0].seg_id.source_index - == turn.operations[1].seg_id.source_index; + return turn.is_self(); } }; diff --git a/include/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp b/include/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp index 0845390a9..519c88328 100644 --- a/include/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp @@ -3,9 +3,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2017-2020. -// Modifications copyright (c) 2017-2020 Oracle and/or its affiliates. - +// This file was modified by Oracle on 2017-2021. +// Modifications copyright (c) 2017-2021 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, @@ -33,6 +32,9 @@ #include #include +#include +#include + #include @@ -271,6 +273,85 @@ struct self_get_turn_points #endif // DOXYGEN_NO_DISPATCH +namespace resolve_strategy +{ + +template +< + bool Reverse, + typename AssignPolicy, + typename Strategies, + bool IsUmbrella = strategies::detail::is_umbrella_strategy::value +> +struct self_get_turn_points +{ + template + < + typename Geometry, + typename RobustPolicy, + typename Turns, + typename InterruptPolicy + > + static inline void apply(Geometry const& geometry, + Strategies const& strategies, + RobustPolicy const& robust_policy, + Turns& turns, + InterruptPolicy& interrupt_policy, + int source_index, + bool skip_adjacent) + { + using turn_policy = detail::overlay::get_turn_info; + + dispatch::self_get_turn_points + < + Reverse, + typename tag::type, + Geometry, + turn_policy + >::apply(geometry, strategies, robust_policy, turns, interrupt_policy, + source_index, skip_adjacent); + } +}; + +template +struct self_get_turn_points +{ + template + < + typename Geometry, + typename RobustPolicy, + typename Turns, + typename InterruptPolicy + > + static inline void apply(Geometry const& geometry, + Strategy const& strategy, + RobustPolicy const& robust_policy, + Turns& turns, + InterruptPolicy& interrupt_policy, + int source_index, + bool skip_adjacent) + { + using strategies::relate::services::strategy_converter; + + self_get_turn_points + < + Reverse, + AssignPolicy, + decltype(strategy_converter::get(strategy)) + >::apply(geometry, + strategy_converter::get(strategy), + robust_policy, + turns, + interrupt_policy, + source_index, + skip_adjacent); + } +}; + + +} // namespace resolve_strategy + + #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace self_get_turn_points { @@ -282,13 +363,13 @@ template bool Reverse, typename AssignPolicy, typename Geometry, - typename IntersectionStrategy, + typename Strategy, typename RobustPolicy, typename Turns, typename InterruptPolicy > inline void self_turns(Geometry const& geometry, - IntersectionStrategy const& strategy, + Strategy const& strategy, RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& interrupt_policy, @@ -297,14 +378,9 @@ inline void self_turns(Geometry const& geometry, { concepts::check(); - typedef detail::overlay::get_turn_info turn_policy; - - dispatch::self_get_turn_points + resolve_strategy::self_get_turn_points < - Reverse, - typename tag::type, - Geometry, - turn_policy + Reverse, AssignPolicy, Strategy >::apply(geometry, strategy, robust_policy, turns, interrupt_policy, source_index, skip_adjacent); } @@ -351,12 +427,11 @@ inline void self_turns(Geometry const& geometry, geometry::point_order::value >::value; - detail::self_get_turn_points::self_turns + resolve_strategy::self_get_turn_points < - reverse, - AssignPolicy - >(geometry, strategy, robust_policy, turns, interrupt_policy, - source_index, skip_adjacent); + reverse, AssignPolicy, Strategy + >::apply(geometry, strategy, robust_policy, turns, interrupt_policy, + source_index, skip_adjacent); } diff --git a/include/boost/geometry/algorithms/detail/overlay/sort_by_side.hpp b/include/boost/geometry/algorithms/detail/overlay/sort_by_side.hpp index 49e676186..9656285ab 100644 --- a/include/boost/geometry/algorithms/detail/overlay/sort_by_side.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/sort_by_side.hpp @@ -316,7 +316,15 @@ public : // then take a point (or more) further back. // The limit of offset avoids theoretical infinite loops. // In practice it currently walks max 1 point back in all cases. - double const tolerance = 1.0e9; + // Use the coordinate type, but if it is too small (e.g. std::int16), use a double + using ct_type = typename geometry::select_most_precise + < + typename geometry::coordinate_type::type, + double + >::type; + + ct_type const tolerance = 1000000000; + int offset = 0; while (approximately_equals(point_from, turn.point, tolerance) && offset > -10) diff --git a/include/boost/geometry/algorithms/detail/overlay/traversal.hpp b/include/boost/geometry/algorithms/detail/overlay/traversal.hpp index a0149789c..b65f00424 100644 --- a/include/boost/geometry/algorithms/detail/overlay/traversal.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/traversal.hpp @@ -621,31 +621,32 @@ public : return m_turns[rp.turn_index].operations[rp.operation_index]; } - inline sort_by_side::rank_type select_rank(sbs_type const& sbs, - bool skip_isolated) const + inline sort_by_side::rank_type select_rank(sbs_type const& sbs) const { + static bool const is_intersection + = target_operation == operation_intersection; + // Take the first outgoing rank corresponding to incoming region, // or take another region if it is not isolated - turn_operation_type const& incoming_op - = operation_from_rank(sbs.m_ranked_points.front()); + auto const& in_op = operation_from_rank(sbs.m_ranked_points.front()); for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++) { - typename sbs_type::rp const& rp = sbs.m_ranked_points[i]; + auto const& rp = sbs.m_ranked_points[i]; if (rp.rank == 0 || rp.direction == sort_by_side::dir_from) { continue; } - turn_operation_type const& op = operation_from_rank(rp); + auto const& out_op = operation_from_rank(rp); - if (op.operation != target_operation - && op.operation != operation_continue) + if (out_op.operation != target_operation + && out_op.operation != operation_continue) { continue; } - if (op.enriched.region_id == incoming_op.enriched.region_id - || (skip_isolated && ! op.enriched.isolated)) + if (in_op.enriched.region_id == out_op.enriched.region_id + || (is_intersection && ! out_op.enriched.isolated)) { // Region corresponds to incoming region, or (for intersection) // there is a non-isolated other region which should be taken @@ -660,7 +661,7 @@ public : int& op_index, sbs_type const& sbs, signed_size_type start_turn_index, int start_op_index) const { - sort_by_side::rank_type const selected_rank = select_rank(sbs, false); + sort_by_side::rank_type const selected_rank = select_rank(sbs); int current_priority = 0; for (std::size_t i = 1; i < sbs.m_ranked_points.size(); i++) @@ -688,49 +689,59 @@ public : inline bool analyze_cluster_intersection(signed_size_type& turn_index, int& op_index, sbs_type const& sbs) const { - sort_by_side::rank_type const selected_rank = select_rank(sbs, true); + // Select the rank based on regions and isolation + sort_by_side::rank_type const selected_rank = select_rank(sbs); - if (selected_rank > 0) + if (selected_rank <= 0) { - typename turn_operation_type::comparable_distance_type - min_remaining_distance = 0; + return false; + } - std::size_t selected_index = sbs.m_ranked_points.size(); - for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++) + // From these ranks, select the index: the first, or the one with + // the smallest remaining distance + typename turn_operation_type::comparable_distance_type + min_remaining_distance = 0; + + std::size_t selected_index = sbs.m_ranked_points.size(); + for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++) + { + auto const& ranked_point = sbs.m_ranked_points[i]; + + if (ranked_point.rank > selected_rank) { - typename sbs_type::rp const& ranked_point = sbs.m_ranked_points[i]; - - if (ranked_point.rank == selected_rank) - { - turn_operation_type const& op = operation_from_rank(ranked_point); - - if (op.visited.finalized()) - { - // This direction is already traveled before, the same - // cannot be traveled again - continue; - } - - // Take turn with the smallest remaining distance - if (selected_index == sbs.m_ranked_points.size() - || op.remaining_distance < min_remaining_distance) - { - selected_index = i; - min_remaining_distance = op.remaining_distance; - } - } + break; } - - if (selected_index < sbs.m_ranked_points.size()) + else if (ranked_point.rank == selected_rank) { - typename sbs_type::rp const& ranked_point = sbs.m_ranked_points[selected_index]; - turn_index = ranked_point.turn_index; - op_index = ranked_point.operation_index; - return true; + auto const& op = operation_from_rank(ranked_point); + + if (op.visited.finalized()) + { + // This direction is already traveled, + // it cannot be traveled again + continue; + } + + if (selected_index == sbs.m_ranked_points.size() + || op.remaining_distance < min_remaining_distance) + { + // It was unassigned or it is better + selected_index = i; + min_remaining_distance = op.remaining_distance; + } } } - return false; + if (selected_index == sbs.m_ranked_points.size()) + { + // Should not happen, there must be points with the selected rank + return false; + } + + auto const& ranked_point = sbs.m_ranked_points[selected_index]; + turn_index = ranked_point.turn_index; + op_index = ranked_point.operation_index; + return true; } inline bool fill_sbs(sbs_type& sbs, @@ -819,6 +830,7 @@ public : return result; } + // Analyzes a non-clustered "ii" intersection, as if it is clustered. inline bool analyze_ii_intersection(signed_size_type& turn_index, int& op_index, turn_type const& current_turn, segment_identifier const& previous_seg_id) diff --git a/include/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp b/include/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp index ad248826d..be0f2bcd8 100644 --- a/include/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp @@ -89,7 +89,6 @@ struct traversal_switch_detector enum isolation_type { - isolation_unknown = -1, isolation_no = 0, isolation_yes = 1, isolation_multiple = 2 @@ -121,7 +120,7 @@ struct traversal_switch_detector struct region_properties { signed_size_type region_id = -1; - isolation_type isolated = isolation_unknown; + isolation_type isolated = isolation_no; set_type unique_turn_ids; connection_map connected_region_counts; }; @@ -374,7 +373,7 @@ struct traversal_switch_detector { region_properties& properties = key_val.second; - if (properties.isolated == isolation_unknown + if (properties.isolated == isolation_no && has_only_isolated_children(properties)) { properties.isolated = isolation_yes; @@ -388,13 +387,36 @@ struct traversal_switch_detector { for (turn_type& turn : m_turns) { + // For difference, for the input walked through in reverse, + // the meaning is reversed: what is isolated is actually not, + // and vice versa. + bool const reverseMeaningInTurn + = (Reverse1 || Reverse2) + && ! turn.is_self() + && ! turn.is_clustered() + && uu_or_ii(turn) + && turn.operations[0].enriched.region_id + != turn.operations[1].enriched.region_id; + for (auto& op : turn.operations) { auto mit = m_connected_regions.find(op.enriched.region_id); if (mit != m_connected_regions.end()) { + bool const reverseMeaningInOp + = reverseMeaningInTurn + && ((op.seg_id.source_index == 0 && Reverse1) + || (op.seg_id.source_index == 1 && Reverse2)); + + // It is assigned to isolated if it's property is "Yes", + // (one connected interior, or chained). + // "Multiple" doesn't count for isolation, + // neither for intersection, neither for difference. region_properties const& prop = mit->second; - op.enriched.isolated = prop.isolated == isolation_yes; + op.enriched.isolated + = reverseMeaningInOp + ? false + : prop.isolated == isolation_yes; } } } @@ -478,8 +500,12 @@ struct traversal_switch_detector // Discarded turns don't connect rings to the same region // Also xx are not relevant // (otherwise discarded colocated uu turn could make a connection) - return ! turn.discarded - && ! turn.both(operation_blocked); + return ! turn.discarded && ! turn.both(operation_blocked); + } + + inline bool uu_or_ii(turn_type const& turn) const + { + return turn.both(operation_union) || turn.both(operation_intersection); } inline bool connects_same_region(turn_type const& turn) const @@ -492,7 +518,7 @@ struct traversal_switch_detector if (! turn.is_clustered()) { // If it is a uu/ii-turn (non clustered), it is never same region - return ! (turn.both(operation_union) || turn.both(operation_intersection)); + return ! uu_or_ii(turn); } if (BOOST_GEOMETRY_CONDITION(target_operation == operation_union)) @@ -565,10 +591,83 @@ struct traversal_switch_detector } } +#if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR) + void debug_show_results() + { + auto isolation_to_string = [](isolation_type const& iso) -> std::string + { + switch(iso) + { + case isolation_no : return "no"; + case isolation_yes : return "yes"; + case isolation_multiple : return "multiple"; + } + return "error"; + }; + auto set_to_string = [](auto const& s) -> std::string + { + std::ostringstream result; + for (auto item : s) { result << " " << item; } + return result.str(); + }; + + for (auto const& kv : m_connected_regions) + { + auto const& prop = kv.second; + + std::ostringstream sub; + sub << "[turns" << set_to_string(prop.unique_turn_ids) + << "] regions"; + for (auto const& kvs : prop.connected_region_counts) + { + sub << " { " << kvs.first + << " : via [" << set_to_string(kvs.second.unique_turn_ids) + << " ] }"; + } + + std::cout << "REGION " << prop.region_id + << " " << isolation_to_string(prop.isolated) + << " " << sub.str() + << std::endl; + } + + for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index) + { + turn_type const& turn = m_turns[turn_index]; + + if (uu_or_ii(turn) && ! turn.is_clustered()) + { + std::cout << (turn.both(operation_union) ? "UU" : "II") + << " " << turn_index + << " (" << geometry::get<0>(turn.point) + << ", " << geometry::get<1>(turn.point) << ")" + << " -> " << std::boolalpha + << " [" << turn.operations[0].seg_id.source_index + << "/" << turn.operations[1].seg_id.source_index << "] " + << "(" << turn.operations[0].enriched.region_id + << " " << turn.operations[0].enriched.isolated + << ") / (" << turn.operations[1].enriched.region_id + << " " << turn.operations[1].enriched.isolated << ")" + << std::endl; + } + } + + for (auto const& key_val : m_clusters) + { + cluster_info const& cinfo = key_val.second; + std::cout << "CL RESULT " << key_val.first + << " -> " << cinfo.open_count << std::endl; + } + } +#endif + void iterate() { #if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR) - std::cout << "BEGIN SWITCH DETECTOR (region_ids and isolation)" << std::endl; + std::cout << "BEGIN SWITCH DETECTOR (region_ids and isolation)" + << (Reverse1 ? " REVERSE_1" : "") + << (Reverse2 ? " REVERSE_2" : "") + << std::endl; #endif // Collect turns per ring @@ -608,33 +707,7 @@ struct traversal_switch_detector #if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR) std::cout << "END SWITCH DETECTOR" << std::endl; - - for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index) - { - turn_type const& turn = m_turns[turn_index]; - - if ((turn.both(operation_union) || turn.both(operation_intersection)) - && ! turn.is_clustered()) - { - std::cout << (turn.both(operation_union) ? "UU" : "II") - << " " << turn_index - << " (" << geometry::get<0>(turn.point) - << ", " << geometry::get<1>(turn.point) << ")" - << " -> " << std::boolalpha - << "(" << turn.operations[0].enriched.region_id - << " " << turn.operations[0].enriched.isolated - << ") / (" << turn.operations[1].enriched.region_id - << " " << turn.operations[1].enriched.isolated << ")" - << std::endl; - } - } - - for (auto const& key_val : m_clusters) - { - cluster_info const& cinfo = key_val.second; - std::cout << "CL RESULT " << key_val.first - << " -> " << cinfo.open_count << std::endl; - } + debug_show_results(); #endif } diff --git a/include/boost/geometry/algorithms/detail/overlay/turn_info.hpp b/include/boost/geometry/algorithms/detail/overlay/turn_info.hpp index 7dcbf4c8e..08cb516cf 100644 --- a/include/boost/geometry/algorithms/detail/overlay/turn_info.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/turn_info.hpp @@ -138,6 +138,11 @@ struct turn_info { return cluster_id > 0; } + inline bool is_self() const + { + return operations[0].seg_id.source_index + == operations[1].seg_id.source_index; + } private : inline bool has12(operation_type type1, operation_type type2) const diff --git a/include/boost/geometry/algorithms/detail/sections/sectionalize.hpp b/include/boost/geometry/algorithms/detail/sections/sectionalize.hpp index e98536e3f..8d230573c 100644 --- a/include/boost/geometry/algorithms/detail/sections/sectionalize.hpp +++ b/include/boost/geometry/algorithms/detail/sections/sectionalize.hpp @@ -783,22 +783,24 @@ inline void enlarge_sections(Sections& sections, Strategy const&) // It makes section a tiny bit too large, which might cause (a small number) // of more comparisons - for (typename boost::range_iterator::type it = boost::begin(sections); - it != boost::end(sections); - ++it) + for (auto& section : sections) { #if defined(BOOST_GEOMETRY_USE_RESCALING) detail::sectionalize::expand_by_epsilon < typename Strategy::cs_tag - >::apply(it->bounding_box); + >::apply(section.bounding_box); #else // Expand the box to avoid missing any intersection. The amount is // should be larger than epsilon. About the value itself: the smaller // it is, the higher the risk to miss intersections. The larger it is, // the more comparisons are made. So it should be on the high side. - detail::buffer::buffer_box(it->bounding_box, 0.001, it->bounding_box); + using gt = decltype(section.bounding_box); + using ct = typename geometry::coordinate_type::type; + ct const tolerance = ct(1) / ct(1000); + detail::buffer::buffer_box(section.bounding_box, tolerance, + section.bounding_box); #endif } } diff --git a/include/boost/geometry/algorithms/detail/select_geometry_type.hpp b/include/boost/geometry/algorithms/detail/select_geometry_type.hpp index 2e94ae73e..5592fa5c4 100644 --- a/include/boost/geometry/algorithms/detail/select_geometry_type.hpp +++ b/include/boost/geometry/algorithms/detail/select_geometry_type.hpp @@ -11,6 +11,9 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SELECT_GEOMETRY_TYPE_HPP #include +#include +#include +#include #include #include @@ -21,29 +24,33 @@ namespace boost { namespace geometry namespace detail { -template -< - typename Geometry, - template class LessPred, - bool IsDynamicOrCollection = util::is_dynamic_geometry::value - || util::is_geometry_collection::value -> -struct select_geometry_type + +template ::type> +struct first_geometry_type { using type = Geometry; }; -template -< - typename Geometry, - template class LessPred -> -struct select_geometry_type - : util::select_element +template +struct first_geometry_type +{ + template + using pred = util::bool_constant < - typename traits::geometry_types>::type, - LessPred - > + ! util::is_dynamic_geometry::value + && ! util::is_geometry_collection::value + >; + + using type = typename util::sequence_find_if + < + typename traits::geometry_types::type, + pred + >::type; +}; + +template +struct first_geometry_type + : first_geometry_type {}; @@ -65,6 +72,32 @@ struct geometry_types }; +template +< + typename Geometry, + template class LessPred, + bool IsDynamicOrCollection = util::is_dynamic_geometry::value + || util::is_geometry_collection::value +> +struct select_geometry_type +{ + using type = Geometry; +}; + +template +< + typename Geometry, + template class LessPred +> +struct select_geometry_type + : util::sequence_min_element + < + typename traits::geometry_types>::type, + LessPred + > +{}; + + template < typename Geometry1, typename Geometry2, @@ -89,10 +122,13 @@ template template class LessPred > struct select_geometry_types - : util::select_combination_element + : util::sequence_min_element < - typename geometry_types::type, - typename geometry_types::type, + typename util::sequence_combine + < + typename geometry_types::type, + typename geometry_types::type + >::type, LessPred > {}; diff --git a/include/boost/geometry/algorithms/detail/visit.hpp b/include/boost/geometry/algorithms/detail/visit.hpp index 60958f4b4..7cbf9e231 100644 --- a/include/boost/geometry/algorithms/detail/visit.hpp +++ b/include/boost/geometry/algorithms/detail/visit.hpp @@ -181,20 +181,16 @@ struct visit_breadth_first } }; -// NOTE: This specialization works partially like std::visit and partially like -// std::ranges::for_each. If the argument is rvalue reference then the elements -// are passed into the function as rvalue references as well. This is consistent -// with std::visit but different than std::ranges::for_each. It's done this way -// because visit_breadth_first is also specialized for static and dynamic geometries -// which and references for them has to be propagated like that. If this is not -// desireable then the support for other kinds of geometries should be dropped and -// this algorithm should work only for geometry collection. -// This is not a problem right now because only non-rvalue references are passed -// but in the future there might be some issues. Consider e.g. passing a temporary -// mutable proxy range as geometry collection. In such case the elements would be -// passed as rvalue references which would be incorrect. -template -struct visit_breadth_first +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +template +struct visit_breadth_first_impl { template static bool apply(F function, Geom && geom) @@ -217,7 +213,8 @@ struct visit_breadth_first bool result = true; traits::iter_visit>::apply([&](auto && g) { - result = visit_or_enqueue(function, std::forward(g), queue, it); + result = visit_breadth_first_impl::visit_or_enqueue( + function, std::forward(g), queue, it); }, it); if (! result) @@ -235,7 +232,7 @@ struct visit_breadth_first // so this call can be avoided. traits::iter_visit>::apply([&](auto && g) { - set_iterators(std::forward(g), it, end); + visit_breadth_first_impl::set_iterators(std::forward(g), it, end); }, queue.front()); queue.pop_front(); } @@ -246,7 +243,7 @@ struct visit_breadth_first private: template < - typename F, typename Geom, typename Iterator, + bool PassIter, typename F, typename Geom, typename Iterator, std::enable_if_t::value, int> = 0 > static bool visit_or_enqueue(F &, Geom &&, std::deque & queue, Iterator iter) @@ -256,13 +253,22 @@ private: } template < - typename F, typename Geom, typename Iterator, - std::enable_if_t::value, int> = 0 + bool PassIter, typename F, typename Geom, typename Iterator, + std::enable_if_t::value && ! PassIter, int> = 0 > static bool visit_or_enqueue(F & f, Geom && g, std::deque & , Iterator) { return f(std::forward(g)); } + template + < + bool PassIter, typename F, typename Geom, typename Iterator, + std::enable_if_t::value && PassIter, int> = 0 + > + static bool visit_or_enqueue(F & f, Geom && g, std::deque & , Iterator iter) + { + return f(std::forward(g), iter); + } template < @@ -283,6 +289,32 @@ private: {} }; +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +// NOTE: This specialization works partially like std::visit and partially like +// std::ranges::for_each. If the argument is rvalue reference then the elements +// are passed into the function as rvalue references as well. This is consistent +// with std::visit but different than std::ranges::for_each. It's done this way +// because visit_breadth_first is also specialized for static and dynamic geometries +// and references for them has to be propagated like that. If this is not +// desireable then the support for other kinds of geometries should be dropped and +// this algorithm should work only for geometry collection. Or forwarding of rvalue +// references should simply be dropped entirely. +// This is not a problem right now because only non-rvalue references are passed +// but in the future there might be some issues. Consider e.g. passing a temporary +// mutable proxy range as geometry collection. In such case the elements would be +// passed as rvalue references which would be incorrect. +template +struct visit_breadth_first + : detail::visit_breadth_first_impl<> +{}; + } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH diff --git a/include/boost/geometry/algorithms/dispatch/distance.hpp b/include/boost/geometry/algorithms/dispatch/distance.hpp index 4d56a3aa0..eb9cd92f6 100644 --- a/include/boost/geometry/algorithms/dispatch/distance.hpp +++ b/include/boost/geometry/algorithms/dispatch/distance.hpp @@ -68,6 +68,29 @@ struct distance_strategy_type {}; +template +< + typename Geometry1, typename Geometry2, typename Strategies, + bool IsDynamicOrGC = util::is_dynamic_geometry::value + || util::is_dynamic_geometry::value + || util::is_geometry_collection::value + || util::is_geometry_collection::value +> +struct distance_strategy_tag +{ + using type = void; +}; + +template +struct distance_strategy_tag +{ + using type = typename strategy::distance::services::tag + < + typename distance_strategy_type::type + >::type; +}; + + template < typename Geometry1, typename Geometry2, @@ -91,11 +114,11 @@ template linear_tag, areal_tag >::type, - typename StrategyTag = typename strategy::distance::services::tag + typename StrategyTag = typename distance_strategy_tag < - typename distance_strategy_type::type + Geometry1, Geometry2, Strategy >::type, - bool Reverse = reverse_dispatch::type::value + bool Reverse = reverse_dispatch::value > struct distance : not_implemented {}; diff --git a/include/boost/geometry/algorithms/is_convex.hpp b/include/boost/geometry/algorithms/is_convex.hpp index 036b0d6b8..0d54111c9 100644 --- a/include/boost/geometry/algorithms/is_convex.hpp +++ b/include/boost/geometry/algorithms/is_convex.hpp @@ -17,12 +17,9 @@ #include -#include -#include -#include - #include #include +#include #include #include #include @@ -30,6 +27,8 @@ #include #include #include +#include +#include // For backward compatibility #include #include #include @@ -53,10 +52,7 @@ struct ring_is_convex static inline bool apply(Ring const& ring, Strategies const& strategies) { std::size_t n = boost::size(ring); - if (boost::size(ring) < core_detail::closure::minimum_ring_size - < - geometry::closure::value - >::value) + if (n < detail::minimum_ring_size::value) { // (Too) small rings are considered as non-concave, is convex return true; @@ -137,6 +133,17 @@ struct polygon_is_convex } }; +struct multi_polygon_is_convex +{ + template + static inline bool apply(MultiPolygon const& multi_polygon, Strategies const& strategies) + { + auto const size = boost::size(multi_polygon); + return size == 0 // For consistency with ring_is_convex + || (size == 1 && polygon_is_convex::apply(range::front(multi_polygon), strategies)); + } +}; + }} // namespace detail::is_convex #endif // DOXYGEN_NO_DETAIL @@ -151,14 +158,29 @@ template typename Geometry, typename Tag = typename tag::type > -struct is_convex : not_implemented -{}; +struct is_convex +{ + template + static inline bool apply(Geometry const&, Strategies const&) + { + // Convexity is not defined for PointLike and Linear geometries. + // We could implement this because the following definitions would work: + // - no line segment between two points on the interior or boundary ever goes outside. + // - convex_hull of geometry is equal to the original geometry, this implies equal + // topological dimension. + // For MultiPoint we'd have to check whether or not an arbitrary number of equal points + // is stored. + // MultiPolygon we'd have to check for continuous chain of Linestrings which would require + // the use of relate(pt, seg) or distance(pt, pt) strategy. + return false; + } +}; template struct is_convex { - template - static inline bool apply(Box const& , Strategy const& ) + template + static inline bool apply(Box const& , Strategies const& ) { // Any box is convex (TODO: consider spherical boxes) // TODO: in spherical and geographic the answer would be "false" most of the time. @@ -187,6 +209,10 @@ template struct is_convex : detail::is_convex::polygon_is_convex {}; +template +struct is_convex : detail::is_convex::multi_polygon_is_convex +{}; + } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH @@ -238,9 +264,9 @@ struct is_convex } // namespace resolve_strategy -namespace resolve_variant { +namespace resolve_dynamic { -template +template ::type> struct is_convex { template @@ -251,38 +277,50 @@ struct is_convex } }; -template -struct is_convex > +template +struct is_convex { template - struct visitor: boost::static_visitor + static inline bool apply(Geometry const& geometry, Strategy const& strategy) { - Strategy const& m_strategy; - - visitor(Strategy const& strategy) : m_strategy(strategy) {} - - template - bool operator()(Geometry const& geometry) const + bool result = false; + traits::visit::apply([&](auto const& g) { - return is_convex::apply(geometry, m_strategy); - } - }; - - template - static inline bool apply(boost::variant const& geometry, - Strategy const& strategy) - { - return boost::apply_visitor(visitor(strategy), geometry); + result = is_convex>::apply(g, strategy); + }, geometry); + return result; } }; -} // namespace resolve_variant +// NOTE: This is a simple implementation checking if a GC contains single convex geometry. +// Technically a GC could store e.g. polygons touching with edges and together creating a convex +// region. To check this we'd require relate() strategy and the algorithm would be quite complex. +template +struct is_convex +{ + template + static inline bool apply(Geometry const& geometry, Strategy const& strategy) + { + bool result = false; + bool is_first = true; + detail::visit_breadth_first([&](auto const& g) + { + result = is_first + && is_convex>::apply(g, strategy); + is_first = false; + return result; + }, geometry); + return result; + } +}; + +} // namespace resolve_dynamic // TODO: documentation / qbk template inline bool is_convex(Geometry const& geometry) { - return resolve_variant::is_convex + return resolve_dynamic::is_convex < Geometry >::apply(geometry, geometry::default_strategy()); @@ -292,7 +330,7 @@ inline bool is_convex(Geometry const& geometry) template inline bool is_convex(Geometry const& geometry, Strategy const& strategy) { - return resolve_variant::is_convex::apply(geometry, strategy); + return resolve_dynamic::is_convex::apply(geometry, strategy); } diff --git a/include/boost/geometry/algorithms/is_empty.hpp b/include/boost/geometry/algorithms/is_empty.hpp index 3fe5359fa..52c308214 100644 --- a/include/boost/geometry/algorithms/is_empty.hpp +++ b/include/boost/geometry/algorithms/is_empty.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2015-2020, Oracle and/or its affiliates. +// Copyright (c) 2015-2021, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -15,21 +15,21 @@ #include #include -#include -#include -#include +#include +#include +#include #include +#include #include #include #include +#include -#include - -#include - +#include // For backward compatibility #include +#include namespace boost { namespace geometry { @@ -152,10 +152,10 @@ struct is_empty #endif // DOXYGEN_NO_DISPATCH -namespace resolve_variant +namespace resolve_dynamic { -template +template ::type> struct is_empty { static inline bool apply(Geometry const& geometry) @@ -166,26 +166,36 @@ struct is_empty } }; -template -struct is_empty > +template +struct is_empty { - struct visitor : boost::static_visitor + static inline bool apply(Geometry const& geometry) { - template - inline bool operator()(Geometry const& geometry) const + bool result = true; + traits::visit::apply([&](auto const& g) { - return is_empty::apply(geometry); - } - }; - - static bool - apply(boost::variant const& geometry) - { - return boost::apply_visitor(visitor(), geometry); + result = is_empty>::apply(g); + }, geometry); + return result; } }; -} // namespace resolve_variant +template +struct is_empty +{ + static inline bool apply(Geometry const& geometry) + { + bool result = true; + detail::visit_breadth_first([&](auto const& g) + { + result = is_empty>::apply(g); + return result; + }, geometry); + return result; + } +}; + +} // namespace resolve_dynamic /*! @@ -200,7 +210,7 @@ struct is_empty > template inline bool is_empty(Geometry const& geometry) { - return resolve_variant::is_empty::apply(geometry); + return resolve_dynamic::is_empty::apply(geometry); } diff --git a/include/boost/geometry/algorithms/num_points.hpp b/include/boost/geometry/algorithms/num_points.hpp index a5d46833f..ee1609dc7 100644 --- a/include/boost/geometry/algorithms/num_points.hpp +++ b/include/boost/geometry/algorithms/num_points.hpp @@ -5,8 +5,8 @@ // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2014-2020. -// Modifications copyright (c) 2014-2020, Oracle and/or its affiliates. +// This file was modified by Oracle on 2014-2021. +// Modifications copyright (c) 2014-2021, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -26,21 +26,20 @@ #include #include -#include -#include -#include +#include +#include +#include #include #include #include #include +#include -#include - -#include - +#include // For backward compatibility #include +#include namespace boost { namespace geometry { @@ -140,48 +139,54 @@ struct num_points #endif -namespace resolve_variant +namespace resolve_dynamic { -template +template ::type> struct num_points { - static inline std::size_t apply(Geometry const& geometry, - bool add_for_open) + static inline std::size_t apply(Geometry const& geometry, bool add_for_open) { concepts::check(); return add_for_open - ? dispatch::num_points::apply(geometry) - : dispatch::num_points::apply(geometry); + ? dispatch::num_points::apply(geometry) + : dispatch::num_points::apply(geometry); } }; -template -struct num_points > +template +struct num_points { - struct visitor: boost::static_visitor + static inline std::size_t apply(Geometry const& geometry, bool add_for_open) { - bool m_add_for_open; - - visitor(bool add_for_open): m_add_for_open(add_for_open) {} - - template - inline std::size_t operator()(Geometry const& geometry) const + std::size_t result = 0; + traits::visit::apply([&](auto const& g) { - return num_points::apply(geometry, m_add_for_open); - } - }; - - static inline std::size_t - apply(boost::variant const& geometry, - bool add_for_open) - { - return boost::apply_visitor(visitor(add_for_open), geometry); + result = num_points>::apply(g, add_for_open); + }, geometry); + return result; } }; -} // namespace resolve_variant + +template +struct num_points +{ + static inline std::size_t apply(Geometry const& geometry, bool add_for_open) + { + std::size_t result = 0; + detail::visit_breadth_first([&](auto const& g) + { + result += num_points>::apply(g, add_for_open); + return true; + }, geometry); + return result; + } +}; + + +} // namespace resolve_dynamic /*! @@ -198,7 +203,7 @@ struct num_points > template inline std::size_t num_points(Geometry const& geometry, bool add_for_open = false) { - return resolve_variant::num_points::apply(geometry, add_for_open); + return resolve_dynamic::num_points::apply(geometry, add_for_open); } #if defined(_MSC_VER) diff --git a/include/boost/geometry/algorithms/num_segments.hpp b/include/boost/geometry/algorithms/num_segments.hpp index 4868c09dc..556f8bfe9 100644 --- a/include/boost/geometry/algorithms/num_segments.hpp +++ b/include/boost/geometry/algorithms/num_segments.hpp @@ -1,6 +1,6 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014-2020, Oracle and/or its affiliates. +// Copyright (c) 2014-2021, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -16,22 +16,19 @@ #include #include -#include -#include -#include +#include +#include +#include #include #include #include +#include -#include - +#include // For backward compatibility #include -#include - -#include - +#include namespace boost { namespace geometry { @@ -140,11 +137,11 @@ struct num_segments -namespace resolve_variant +namespace resolve_dynamic { -template +template ::type> struct num_segments { static inline std::size_t apply(Geometry const& geometry) @@ -156,27 +153,38 @@ struct num_segments }; -template -struct num_segments > +template +struct num_segments { - struct visitor: boost::static_visitor + static inline std::size_t apply(Geometry const& geometry) { - template - inline std::size_t operator()(Geometry const& geometry) const + std::size_t result = 0; + traits::visit::apply([&](auto const& g) { - return num_segments::apply(geometry); - } - }; - - static inline std::size_t - apply(boost::variant const& geometry) - { - return boost::apply_visitor(visitor(), geometry); + result = num_segments>::apply(g); + }, geometry); + return result; } }; -} // namespace resolve_variant +template +struct num_segments +{ + static inline std::size_t apply(Geometry const& geometry) + { + std::size_t result = 0; + detail::visit_breadth_first([&](auto const& g) + { + result += num_segments>::apply(g); + return true; + }, geometry); + return result; + } +}; + + +} // namespace resolve_dynamic @@ -193,7 +201,7 @@ struct num_segments > template inline std::size_t num_segments(Geometry const& geometry) { - return resolve_variant::num_segments::apply(geometry); + return resolve_dynamic::num_segments::apply(geometry); } diff --git a/include/boost/geometry/algorithms/perimeter.hpp b/include/boost/geometry/algorithms/perimeter.hpp index ff88857ed..290caeb41 100644 --- a/include/boost/geometry/algorithms/perimeter.hpp +++ b/include/boost/geometry/algorithms/perimeter.hpp @@ -21,20 +21,19 @@ #include -#include -#include -#include - #include #include #include #include // #include +#include #include #include #include +#include +#include // For backward compatibility #include #include @@ -162,9 +161,9 @@ struct perimeter } // namespace resolve_strategy -namespace resolve_variant { +namespace resolve_dynamic { -template +template ::type> struct perimeter { template @@ -176,39 +175,40 @@ struct perimeter } }; -template -struct perimeter > +template +struct perimeter { - typedef typename default_length_result - < - boost::variant - >::type result_type; - template - struct visitor: boost::static_visitor + static inline typename default_length_result::type + apply(Geometry const& geometry, Strategy const& strategy) { - Strategy const& m_strategy; - - visitor(Strategy const& strategy): m_strategy(strategy) {} - - template - typename default_length_result::type - operator()(Geometry const& geometry) const + typename default_length_result::type result = 0; + traits::visit::apply([&](auto const& g) { - return perimeter::apply(geometry, m_strategy); - } - }; - - template - static inline result_type - apply(boost::variant const& geometry, - Strategy const& strategy) - { - return boost::apply_visitor(visitor(strategy), geometry); + result = perimeter>::apply(g, strategy); + }, geometry); + return result; } }; -} // namespace resolve_variant +template +struct perimeter +{ + template + static inline typename default_length_result::type + apply(Geometry const& geometry, Strategy const& strategy) + { + typename default_length_result::type result = 0; + detail::visit_breadth_first([&](auto const& g) + { + result += perimeter>::apply(g, strategy); + return true; + }, geometry); + return result; + } +}; + +} // namespace resolve_dynamic /*! @@ -232,7 +232,7 @@ inline typename default_length_result::type perimeter( Geometry const& geometry) { // detail::throw_on_empty_input(geometry); - return resolve_variant::perimeter::apply(geometry, default_strategy()); + return resolve_dynamic::perimeter::apply(geometry, default_strategy()); } /*! @@ -254,7 +254,7 @@ inline typename default_length_result::type perimeter( Geometry const& geometry, Strategy const& strategy) { // detail::throw_on_empty_input(geometry); - return resolve_variant::perimeter::apply(geometry, strategy); + return resolve_dynamic::perimeter::apply(geometry, strategy); } }} // namespace boost::geometry diff --git a/include/boost/geometry/algorithms/reverse.hpp b/include/boost/geometry/algorithms/reverse.hpp index f124ee615..2fc4b1ccb 100644 --- a/include/boost/geometry/algorithms/reverse.hpp +++ b/include/boost/geometry/algorithms/reverse.hpp @@ -5,8 +5,8 @@ // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2020. -// Modifications copyright (c) 2020 Oracle and/or its affiliates. +// This file was modified by Oracle on 2020-2021. +// Modifications copyright (c) 2020-2021 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library @@ -24,15 +24,15 @@ #include #include -#include -#include -#include - #include #include +#include #include #include +#include +#include // For backward compatibility #include +#include namespace boost { namespace geometry @@ -61,11 +61,9 @@ struct polygon_reverse: private range_reverse { range_reverse::apply(exterior_ring(polygon)); - typename interior_return_type::type - rings = interior_rings(polygon); - - for (typename detail::interior_iterator::type - it = boost::begin(rings); it != boost::end(rings); ++it) + auto&& rings = interior_rings(polygon); + auto const end = boost::end(rings); + for (auto it = boost::begin(rings); it != end; ++it) { range_reverse::apply(*it); } @@ -110,21 +108,13 @@ struct reverse template struct reverse - : detail::multi_modify - < - Geometry, - detail::reverse::range_reverse - > + : detail::multi_modify {}; template struct reverse - : detail::multi_modify - < - Geometry, - detail::reverse::polygon_reverse - > + : detail::multi_modify {}; @@ -133,10 +123,10 @@ struct reverse #endif -namespace resolve_variant +namespace resolve_dynamic { -template +template ::type> struct reverse { static void apply(Geometry& geometry) @@ -146,25 +136,32 @@ struct reverse } }; -template -struct reverse > +template +struct reverse { - struct visitor: boost::static_visitor + static void apply(Geometry& geometry) { - template - void operator()(Geometry& geometry) const + traits::visit::apply([](auto & g) { - reverse::apply(geometry); - } - }; - - static inline void apply(boost::variant& geometry) - { - boost::apply_visitor(visitor(), geometry); + reverse>::apply(g); + }, geometry); } }; -} // namespace resolve_variant +template +struct reverse +{ + static void apply(Geometry& geometry) + { + detail::visit_breadth_first([](auto & g) + { + reverse>::apply(g); + return true; + }, geometry); + } +}; + +} // namespace resolve_dynamic /*! @@ -181,7 +178,7 @@ struct reverse > template inline void reverse(Geometry& geometry) { - resolve_variant::reverse::apply(geometry); + resolve_dynamic::reverse::apply(geometry); } }} // namespace boost::geometry diff --git a/include/boost/geometry/algorithms/simplify.hpp b/include/boost/geometry/algorithms/simplify.hpp index bea8f6cba..18626e9bf 100644 --- a/include/boost/geometry/algorithms/simplify.hpp +++ b/include/boost/geometry/algorithms/simplify.hpp @@ -31,15 +31,13 @@ #include #include #include -#include -#include -#include #include #include #include #include #include +#include #include #include #include @@ -50,7 +48,9 @@ #include #include #include +#include +#include // For backward compatibility #include #include @@ -60,6 +60,8 @@ #include #include +#include + #ifdef BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER #include #endif @@ -301,6 +303,23 @@ struct simplify_range_insert }; +struct simplify_copy_assign +{ + template + < + typename In, typename Out, typename Distance, + typename Impl, typename Strategies + > + static inline void apply(In const& in, Out& out, + Distance const& , + Impl const& , + Strategies const& ) + { + out = in; + } +}; + + struct simplify_copy { template @@ -615,6 +634,17 @@ struct simplify } }; +template +struct simplify + : detail::simplify::simplify_copy_assign +{}; + +template +struct simplify + : detail::simplify::simplify_copy_assign +{}; + + // Linestring, keep 2 points (unless those points are the same) template struct simplify @@ -803,9 +833,9 @@ struct simplify_insert } // namespace resolve_strategy -namespace resolve_variant { +namespace resolve_dynamic { -template +template ::type> struct simplify { template @@ -818,43 +848,46 @@ struct simplify } }; -template -struct simplify > +template +struct simplify { template - struct visitor: boost::static_visitor + static inline void apply(Geometry const& geometry, + Geometry& out, + Distance const& max_distance, + Strategy const& strategy) { - Distance const& m_max_distance; - Strategy const& m_strategy; - - visitor(Distance const& max_distance, Strategy const& strategy) - : m_max_distance(max_distance) - , m_strategy(strategy) - {} - - template - void operator()(Geometry const& geometry, Geometry& out) const + traits::visit::apply([&](auto const& g) { - simplify::apply(geometry, out, m_max_distance, m_strategy); - } - }; - - template - static inline void - apply(boost::variant const& geometry, - boost::variant& out, - Distance const& max_distance, - Strategy const& strategy) - { - boost::apply_visitor( - visitor(max_distance, strategy), - geometry, - out - ); + using geom_t = util::remove_cref_t; + geom_t o; + simplify::apply(g, o, max_distance, strategy); + out = std::move(o); + }, geometry); } }; -} // namespace resolve_variant +template +struct simplify +{ + template + static inline void apply(Geometry const& geometry, + Geometry& out, + Distance const& max_distance, + Strategy const& strategy) + { + detail::visit_breadth_first([&](auto const& g) + { + using geom_t = util::remove_cref_t; + geom_t o; + simplify::apply(g, o, max_distance, strategy); + traits::emplace_back::apply(out, std::move(o)); + return true; + }, geometry); + } +}; + +} // namespace resolve_dynamic /*! @@ -882,7 +915,7 @@ inline void simplify(Geometry const& geometry, Geometry& out, geometry::clear(out); - resolve_variant::simplify::apply(geometry, out, max_distance, strategy); + resolve_dynamic::simplify::apply(geometry, out, max_distance, strategy); } diff --git a/include/boost/geometry/core/config.hpp b/include/boost/geometry/core/config.hpp index 1c6fab8e0..3066586c4 100644 --- a/include/boost/geometry/core/config.hpp +++ b/include/boost/geometry/core/config.hpp @@ -1,6 +1,6 @@ // Boost.Geometry -// Copyright (c) 2019 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2019-2021 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2018-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -23,10 +23,6 @@ #define BOOST_GEOMETRY_CXX11_TUPLE #endif -// Defining this selects Kramer rule for segment-intersection -// That is default behaviour. -#define BOOST_GEOMETRY_USE_KRAMER_RULE - // Rescaling is turned on, unless NO_ROBUSTNESS is defined // In future versions of Boost.Geometry, it will be turned off by default #if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) diff --git a/include/boost/geometry/core/coordinate_promotion.hpp b/include/boost/geometry/core/coordinate_promotion.hpp new file mode 100644 index 000000000..efbcdff7d --- /dev/null +++ b/include/boost/geometry/core/coordinate_promotion.hpp @@ -0,0 +1,111 @@ +// Boost.Geometry + +// Copyright (c) 2021 Barend Gehrels, Amsterdam, the Netherlands. + +// 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_CORE_COORDINATE_PROMOTION_HPP +#define BOOST_GEOMETRY_CORE_COORDINATE_PROMOTION_HPP + +#include + +// TODO: move this to a future headerfile implementing traits for these types +#include +#include +#include + +namespace boost { namespace geometry +{ + +namespace traits +{ + +// todo + +} // namespace traits + +/*! + \brief Meta-function converting, if necessary, to "a floating point" type + \details + - if input type is integer, type is double + - else type is input type + \ingroup utility + */ +// TODO: replace with, or call, promoted_to_floating_point +template +struct promote_floating_point +{ + typedef std::conditional_t + < + std::is_integral::value, + PromoteIntegerTo, + T + > type; +}; + +// TODO: replace with promoted_to_floating_point +template +struct fp_coordinate_type +{ + typedef typename promote_floating_point + < + typename coordinate_type::type + >::type type; +}; + +namespace detail +{ + +// Promote any integral type to double. Floating point +// and other user defined types stay as they are, unless specialized. +// TODO: we shold add a coordinate_promotion traits for promotion to +// floating point or (larger) integer types. +template +struct promoted_to_floating_point +{ + using type = std::conditional_t + < + std::is_integral::value, double, Type + >; +}; + +// Boost.Rational goes to double +template +struct promoted_to_floating_point> +{ + using type = double; +}; + +// Any Boost.Multiprecision goes to double (for example int128_t), +// unless specialized +template +struct promoted_to_floating_point> +{ + using type = double; +}; + +// Boost.Multiprecision binary floating point numbers are used as FP. +template +struct promoted_to_floating_point + < + boost::multiprecision::number + < + boost::multiprecision::cpp_bin_float + > + > +{ + using type = boost::multiprecision::number + < + boost::multiprecision::cpp_bin_float + >; +}; + +} + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_CORE_COORDINATE_PROMOTION_HPP diff --git a/include/boost/geometry/core/coordinate_type.hpp b/include/boost/geometry/core/coordinate_type.hpp index e4c391ec4..760b122ad 100644 --- a/include/boost/geometry/core/coordinate_type.hpp +++ b/include/boost/geometry/core/coordinate_type.hpp @@ -22,7 +22,6 @@ #include #include #include -#include #include @@ -94,15 +93,6 @@ struct coordinate_type >::type type; }; -template -struct fp_coordinate_type -{ - typedef typename promote_floating_point - < - typename coordinate_type::type - >::type type; -}; - /*! \brief assert_coordinate_type_equal, a compile-time check for equality of two coordinate types \ingroup utility diff --git a/include/boost/geometry/core/geometry_id.hpp b/include/boost/geometry/core/geometry_id.hpp index 27901eca4..2c68cedcd 100644 --- a/include/boost/geometry/core/geometry_id.hpp +++ b/include/boost/geometry/core/geometry_id.hpp @@ -45,39 +45,43 @@ struct geometry_id template <> -struct geometry_id : std::integral_constant {}; +struct geometry_id : std::integral_constant {}; template <> -struct geometry_id : std::integral_constant {}; +struct geometry_id : std::integral_constant {}; template <> -struct geometry_id : std::integral_constant {}; +struct geometry_id : std::integral_constant {}; template <> -struct geometry_id : std::integral_constant {}; +struct geometry_id : std::integral_constant {}; template <> -struct geometry_id : std::integral_constant {}; +struct geometry_id : std::integral_constant {}; template <> -struct geometry_id : std::integral_constant {}; +struct geometry_id : std::integral_constant {}; template <> -struct geometry_id : std::integral_constant {}; +struct geometry_id : std::integral_constant {}; template <> -struct geometry_id : std::integral_constant {}; +struct geometry_id : std::integral_constant {}; template <> -struct geometry_id : std::integral_constant {}; +struct geometry_id : std::integral_constant {}; + + +template <> +struct geometry_id : std::integral_constant {}; } // namespace core_dispatch diff --git a/include/boost/geometry/core/point_type.hpp b/include/boost/geometry/core/point_type.hpp index 696e1e56a..f5d282372 100644 --- a/include/boost/geometry/core/point_type.hpp +++ b/include/boost/geometry/core/point_type.hpp @@ -4,8 +4,8 @@ // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. -// This file was modified by Oracle on 2020. -// Modifications copyright (c) 2020 Oracle and/or its affiliates. +// This file was modified by Oracle on 2020-2021. +// Modifications copyright (c) 2020-2021 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library @@ -21,10 +21,12 @@ #include +#include #include #include #include #include +#include #include @@ -137,6 +139,36 @@ struct point_type }; +template +struct point_type +{ + using geometry_t = typename util::sequence_front + < + typename traits::geometry_types::type + >::type; + using type = typename point_type + < + typename tag::type, + typename util::remove_cptrref::type + >::type; +}; + + +template +struct point_type +{ + using geometry_t = typename util::sequence_front + < + typename traits::geometry_types::type + >::type; + using type = typename point_type + < + typename tag::type, + typename util::remove_cptrref::type + >::type; +}; + + } // namespace core_dispatch #endif // DOXYGEN_NO_DISPATCH diff --git a/include/boost/geometry/core/radian_access.hpp b/include/boost/geometry/core/radian_access.hpp index 993a6cc4c..c2f00552d 100644 --- a/include/boost/geometry/core/radian_access.hpp +++ b/include/boost/geometry/core/radian_access.hpp @@ -27,8 +27,7 @@ #include #include -#include - +#include #include diff --git a/include/boost/geometry/geometries/adapted/boost_variant.hpp b/include/boost/geometry/geometries/adapted/boost_variant.hpp index cc21da59c..35660c6fc 100644 --- a/include/boost/geometry/geometries/adapted/boost_variant.hpp +++ b/include/boost/geometry/geometries/adapted/boost_variant.hpp @@ -38,16 +38,6 @@ namespace boost { namespace geometry namespace detail { -template -struct parameter_pack_first_type {}; - -template -struct parameter_pack_first_type -{ - typedef T type; -}; - - template > struct boost_variant_types; @@ -78,7 +68,7 @@ template struct point_type > : point_type < - typename detail::parameter_pack_first_type + typename util::pack_front < BOOST_VARIANT_ENUM_PARAMS(T) >::type diff --git a/include/boost/geometry/geometries/concepts/check.hpp b/include/boost/geometry/geometries/concepts/check.hpp index 5f5923864..34eb74032 100644 --- a/include/boost/geometry/geometries/concepts/check.hpp +++ b/include/boost/geometry/geometries/concepts/check.hpp @@ -22,6 +22,8 @@ #include #include +#include + #include #include #include @@ -39,7 +41,6 @@ namespace boost { namespace geometry { namespace concepts { - /*! \brief Checks, in compile-time, the concept of any geometry \ingroup concepts @@ -69,7 +70,11 @@ inline void check_concepts_and_equal_dimensions() { check(); check(); - assert_dimension_equal(); + assert_dimension_equal + < + typename geometry::detail::first_geometry_type::type, + typename geometry::detail::first_geometry_type::type + >(); } diff --git a/include/boost/geometry/index/detail/algorithms/bounds.hpp b/include/boost/geometry/index/detail/algorithms/bounds.hpp index 1828a2467..999246d9c 100644 --- a/include/boost/geometry/index/detail/algorithms/bounds.hpp +++ b/include/boost/geometry/index/detail/algorithms/bounds.hpp @@ -4,8 +4,8 @@ // // Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland. // -// This file was modified by Oracle on 2019-2020. -// Modifications copyright (c) 2019-2020 Oracle and/or its affiliates. +// This file was modified by Oracle on 2019-2021. +// Modifications copyright (c) 2019-2021 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // // Use, modification and distribution is subject to the Boost Software License, @@ -15,6 +15,11 @@ #ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_BOUNDS_HPP #define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_BOUNDS_HPP +#include +#include +#include +#include + #include namespace boost { namespace geometry { namespace index { namespace detail diff --git a/include/boost/geometry/index/detail/algorithms/comparable_distance_centroid.hpp b/include/boost/geometry/index/detail/algorithms/comparable_distance_centroid.hpp index c4e44cae1..6afe03eec 100644 --- a/include/boost/geometry/index/detail/algorithms/comparable_distance_centroid.hpp +++ b/include/boost/geometry/index/detail/algorithms/comparable_distance_centroid.hpp @@ -4,6 +4,10 @@ // // Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland. // +// This file was modified by Oracle on 2021. +// Modifications copyright (c) 2021 Oracle and/or its affiliates. +// Contributed and/or modified by Adam Wulkiewicz, 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) @@ -11,6 +15,9 @@ #ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_CENTROID_HPP #define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_CENTROID_HPP +#include +#include + #include #include diff --git a/include/boost/geometry/index/detail/algorithms/comparable_distance_far.hpp b/include/boost/geometry/index/detail/algorithms/comparable_distance_far.hpp index 214fbf6aa..102ac545e 100644 --- a/include/boost/geometry/index/detail/algorithms/comparable_distance_far.hpp +++ b/include/boost/geometry/index/detail/algorithms/comparable_distance_far.hpp @@ -4,6 +4,10 @@ // // Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland. // +// This file was modified by Oracle on 2021. +// Modifications copyright (c) 2021 Oracle and/or its affiliates. +// Contributed and/or modified by Adam Wulkiewicz, 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) @@ -11,6 +15,9 @@ #ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_FAR_HPP #define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_FAR_HPP +#include +#include + #include #include diff --git a/include/boost/geometry/index/detail/algorithms/comparable_distance_near.hpp b/include/boost/geometry/index/detail/algorithms/comparable_distance_near.hpp index 15368a7d2..4f2905f3a 100644 --- a/include/boost/geometry/index/detail/algorithms/comparable_distance_near.hpp +++ b/include/boost/geometry/index/detail/algorithms/comparable_distance_near.hpp @@ -4,6 +4,10 @@ // // Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland. // +// This file was modified by Oracle on 2021. +// Modifications copyright (c) 2021 Oracle and/or its affiliates. +// Contributed and/or modified by Adam Wulkiewicz, 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) @@ -11,6 +15,9 @@ #ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_NEAR_HPP #define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_NEAR_HPP +#include +#include + #include namespace boost { namespace geometry { namespace index { namespace detail { diff --git a/include/boost/geometry/index/detail/algorithms/content.hpp b/include/boost/geometry/index/detail/algorithms/content.hpp index 7833ae377..d698a3208 100644 --- a/include/boost/geometry/index/detail/algorithms/content.hpp +++ b/include/boost/geometry/index/detail/algorithms/content.hpp @@ -4,8 +4,8 @@ // // Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland. // -// This file was modified by Oracle on 2020. -// Modifications copyright (c) 2020 Oracle and/or its affiliates. +// This file was modified by Oracle on 2020-2021. +// Modifications copyright (c) 2020-2021 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // // Use, modification and distribution is subject to the Boost Software License, @@ -15,7 +15,12 @@ #ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_CONTENT_HPP #define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_CONTENT_HPP +#include +#include #include +#include +#include +#include namespace boost { namespace geometry { namespace index { namespace detail { diff --git a/include/boost/geometry/index/detail/algorithms/intersection_content.hpp b/include/boost/geometry/index/detail/algorithms/intersection_content.hpp index 880540bc0..1a2cd28bc 100644 --- a/include/boost/geometry/index/detail/algorithms/intersection_content.hpp +++ b/include/boost/geometry/index/detail/algorithms/intersection_content.hpp @@ -4,8 +4,8 @@ // // Copyright (c) 2011-2018 Adam Wulkiewicz, Lodz, Poland. // -// This file was modified by Oracle on 2019-2020. -// Modifications copyright (c) 2019-2020 Oracle and/or its affiliates. +// This file was modified by Oracle on 2019-2021. +// Modifications copyright (c) 2019-2021 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // // Use, modification and distribution is subject to the Boost Software License, @@ -20,6 +20,9 @@ #include +#include +#include + namespace boost { namespace geometry { namespace index { namespace detail { // Util to distinguish between default and non-default index strategy diff --git a/include/boost/geometry/index/detail/algorithms/is_valid.hpp b/include/boost/geometry/index/detail/algorithms/is_valid.hpp index 0d57ed57e..5cd241c29 100644 --- a/include/boost/geometry/index/detail/algorithms/is_valid.hpp +++ b/include/boost/geometry/index/detail/algorithms/is_valid.hpp @@ -4,8 +4,8 @@ // // Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland. // -// This file was modified by Oracle on 2020. -// Modifications copyright (c) 2020 Oracle and/or its affiliates. +// This file was modified by Oracle on 2020-2021. +// Modifications copyright (c) 2020-2021 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // // Use, modification and distribution is subject to the Boost Software License, @@ -18,6 +18,7 @@ #include #include +#include #include namespace boost { namespace geometry { namespace index { namespace detail { diff --git a/include/boost/geometry/index/detail/algorithms/margin.hpp b/include/boost/geometry/index/detail/algorithms/margin.hpp index 2033f4a53..5a05d3c02 100644 --- a/include/boost/geometry/index/detail/algorithms/margin.hpp +++ b/include/boost/geometry/index/detail/algorithms/margin.hpp @@ -4,8 +4,8 @@ // // Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland. // -// This file was modified by Oracle on 2020. -// Modifications copyright (c) 2020 Oracle and/or its affiliates. +// This file was modified by Oracle on 2020-2021. +// Modifications copyright (c) 2020-2021 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // // Use, modification and distribution is subject to the Boost Software License, @@ -15,7 +15,12 @@ #ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_MARGIN_HPP #define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_MARGIN_HPP +#include +#include #include +#include +#include +#include // WARNING! comparable_margin() will work only if the same Geometries are compared // so it shouldn't be used in the case of Variants! diff --git a/include/boost/geometry/index/detail/algorithms/path_intersection.hpp b/include/boost/geometry/index/detail/algorithms/path_intersection.hpp index 4803f5914..ab0860349 100644 --- a/include/boost/geometry/index/detail/algorithms/path_intersection.hpp +++ b/include/boost/geometry/index/detail/algorithms/path_intersection.hpp @@ -4,8 +4,8 @@ // // Copyright (c) 2011-2017 Adam Wulkiewicz, Lodz, Poland. // -// This file was modified by Oracle on 2020. -// Modifications copyright (c) 2020 Oracle and/or its affiliates. +// This file was modified by Oracle on 2020-2021. +// Modifications copyright (c) 2020-2021 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // // Use, modification and distribution is subject to the Boost Software License, @@ -20,6 +20,7 @@ #include +#include #include diff --git a/include/boost/geometry/index/detail/algorithms/segment_intersection.hpp b/include/boost/geometry/index/detail/algorithms/segment_intersection.hpp index a2717d26e..674d9f5f8 100644 --- a/include/boost/geometry/index/detail/algorithms/segment_intersection.hpp +++ b/include/boost/geometry/index/detail/algorithms/segment_intersection.hpp @@ -4,8 +4,8 @@ // // Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland. // -// This file was modified by Oracle on 2020. -// Modifications copyright (c) 2020, Oracle and/or its affiliates. +// This file was modified by Oracle on 2020-2021. +// Modifications copyright (c) 2020-2021, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // // Use, modification and distribution is subject to the Boost Software License, @@ -15,9 +15,14 @@ #ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_SEGMENT_INTERSECTION_HPP #define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_SEGMENT_INTERSECTION_HPP +#include #include +#include +#include #include +#include +#include namespace boost { namespace geometry { namespace index { namespace detail { diff --git a/include/boost/geometry/index/detail/distance_predicates.hpp b/include/boost/geometry/index/detail/distance_predicates.hpp index dcd8d1243..69ce45633 100644 --- a/include/boost/geometry/index/detail/distance_predicates.hpp +++ b/include/boost/geometry/index/detail/distance_predicates.hpp @@ -5,8 +5,8 @@ // // Copyright (c) 2011-2015 Adam Wulkiewicz, Lodz, Poland. // -// This file was modified by Oracle on 2019-2020. -// Modifications copyright (c) 2019-2020 Oracle and/or its affiliates. +// This file was modified by Oracle on 2019-2021. +// Modifications copyright (c) 2019-2021 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // // Use, modification and distribution is subject to the Boost Software License, @@ -22,7 +22,7 @@ #include #include #include - +#include #include namespace boost { namespace geometry { namespace index { namespace detail { diff --git a/include/boost/geometry/index/detail/maxmin_heap.hpp b/include/boost/geometry/index/detail/maxmin_heap.hpp new file mode 100644 index 000000000..01ae54ae2 --- /dev/null +++ b/include/boost/geometry/index/detail/maxmin_heap.hpp @@ -0,0 +1,107 @@ +// Boost.Geometry + +// Copyright (c) 2021, Oracle and/or its affiliates. +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_MAXMIN_HEAP_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_MAXMIN_HEAP_HPP + +#include + +namespace boost { namespace geometry { namespace index { namespace detail +{ + +template +inline void push_maxmin_heap(It first, It last, Compare comp) +{ + using namespace minmax_heap_detail; + minmax_heap_detail::push_heap(first, last, comp); +} + +template +inline void push_maxmin_heap(It first, It last) +{ + using namespace minmax_heap_detail; + minmax_heap_detail::push_heap(first, last, std::less<>()); +} + +template +inline void pop_top_maxmin_heap(It first, It last, Compare comp) +{ + using namespace minmax_heap_detail; + pop_heap(first, first, last, comp); +} + +template +inline void pop_top_maxmin_heap(It first, It last) +{ + using namespace minmax_heap_detail; + pop_heap(first, first, last, std::less<>()); +} + +template +inline void pop_bottom_maxmin_heap(It first, It last, Compare comp) +{ + using namespace minmax_heap_detail; + It bottom = minmax_heap_detail::bottom_heap(first, last, comp); + pop_heap(first, bottom, last, comp); +} + +template +inline void pop_bottom_maxmin_heap(It first, It last) +{ + using namespace minmax_heap_detail; + auto&& comp = std::less<>(); + It bottom = minmax_heap_detail::bottom_heap(first, last, comp); + pop_heap(first, bottom, last, comp); +} + +template +inline void make_maxmin_heap(It first, It last, Compare comp) +{ + using namespace minmax_heap_detail; + return minmax_heap_detail::make_heap(first, last, comp); +} + +template +inline void make_maxmin_heap(It first, It last) +{ + using namespace minmax_heap_detail; + return minmax_heap_detail::make_heap(first, last, std::less<>()); +} + +template +inline bool is_maxmin_heap(It first, It last, Compare comp) +{ + using namespace minmax_heap_detail; + return minmax_heap_detail::is_heap(first, last, comp); +} + +template +inline bool is_maxmin_heap(It first, It last) +{ + using namespace minmax_heap_detail; + return minmax_heap_detail::is_heap(first, last, std::less<>()); +} + +template +inline decltype(auto) bottom_maxmin_heap(It first, It last, Compare comp) +{ + using namespace minmax_heap_detail; + return *minmax_heap_detail::bottom_heap(first, last, comp); +} + +template +inline decltype(auto) bottom_maxmin_heap(It first, It last) +{ + using namespace minmax_heap_detail; + return *minmax_heap_detail::bottom_heap(first, last, std::less<>()); +} + + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_MAXMIN_HEAP_HPP diff --git a/include/boost/geometry/index/detail/minmax_heap.hpp b/include/boost/geometry/index/detail/minmax_heap.hpp new file mode 100644 index 000000000..1b95f77ea --- /dev/null +++ b/include/boost/geometry/index/detail/minmax_heap.hpp @@ -0,0 +1,519 @@ +// Boost.Geometry + +// Copyright (c) 2021, Oracle and/or its affiliates. +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_MINMAX_HEAP_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_MINMAX_HEAP_HPP + +#include +#include +#include + +#ifdef _MSC_VER // msvc and clang-win +#include +#endif + +namespace boost { namespace geometry { namespace index { namespace detail +{ + +// Resources: +// https://en.wikipedia.org/wiki/Min-max_heap +// http://akira.ruc.dk/~keld/teaching/algoritmedesign_f03/Artikler/02/Atkinson86.pdf +// https://probablydance.com/2020/08/31/on-modern-hardware-the-min-max-heap-beats-a-binary-heap/ +// https://stackoverflow.com/questions/6531543/efficient-implementation-of-binary-heaps +// https://stackoverflow.com/questions/994593/how-to-do-an-integer-log2-in-c + +namespace minmax_heap_detail +{ + +template +using bitsize = std::integral_constant; + +template +using diff_t = typename std::iterator_traits::difference_type; +template +using val_t = typename std::iterator_traits::value_type; + +// TODO: In C++20 use std::bit_width() + +template ::value || (bitsize::value != 32 && bitsize::value != 64), int> = 0> +inline int level(T i) +{ + ++i; + int r = 0; + while (i >>= 1) { ++r; } + return r; +} + +//template +//inline int level(T i) +//{ +// using std::log2; +// return int(log2(i + 1)); +//} + +#ifdef _MSC_VER // msvc and clang-win + +template ::value && bitsize::value == 32, int> = 0> +inline int level(T i) +{ + unsigned long r = 0; + _BitScanReverse(&r, (unsigned long)(i + 1)); + return int(r); +} + +template ::value && bitsize::value == 64, int> = 0> +inline int level(T i) +{ + unsigned long r = 0; +#ifdef _WIN64 + _BitScanReverse64(&r, (unsigned long long)(i + 1)); +#else + if (_BitScanReverse(&r, (unsigned long)((i + 1) >> 32))) { r += 32; } + else { _BitScanReverse(&r, (unsigned long)(i + 1)); } +#endif + return int(r); +} + +#elif defined(__clang__) || defined(__GNUC__) +// Only available in gcc-10 and clang-10 +//#elif defined(__has_builtin) && __has_builtin(__builtin_clzl) && __has_builtin(__builtin_clzll) + +template ::value && bitsize::value == 32, int> = 0> +inline int level(T i) +{ + return 31 - __builtin_clzl((unsigned long)(i + 1)); +} + +template ::value && bitsize::value == 64, int> = 0> +inline int level(T i) +{ + return 63 - __builtin_clzll((unsigned long long)(i + 1)); +} + +#else + +template ::value && bitsize::value == 32, int> = 0> +inline int level(T i) +{ + ++i; + int r = 0; + if (i >= 65536) { r += 16; i >>= 16; } + if (i >= 256) { r += 8; i >>= 8; } + if (i >= 16) { r += 4; i >>= 4; } + if (i >= 4) { r += 2; i >>= 2; } + if (i >= 2) { r += 1; i >>= 1; } + return r; +} + +template ::value && bitsize::value == 64, int> = 0> +inline int level(T i) +{ + ++i; + int r = 0; + if (i >= 4294967296ll) { r += 32; i >>= 32; } + if (i >= 65536ll) { r += 16; i >>= 16; } + if (i >= 256ll) { r += 8; i >>= 8; } + if (i >= 16ll) { r += 4; i >>= 4; } + if (i >= 4ll) { r += 2; i >>= 2; } + if (i >= 2ll) { r += 1; i >>= 1; } + return r; +} + +#endif + + +// min/max functions only differ in the order of arguments in comp +struct min_call +{ + template + bool operator()(Compare&& comp, T1 const& v1, T2 const& v2) const + { + return comp(v1, v2); + } +}; + +struct max_call +{ + template + bool operator()(Compare&& comp, T1 const& v1, T2 const& v2) const + { + return comp(v2, v1); + } +}; + + +template +inline void push_heap2(It first, diff_t c, val_t val, Compare comp) +{ + while (c > 2) + { + diff_t const g = (c - 3) >> 2; // grandparent index + if (! Call()(comp, val, *(first + g))) + { + break; + } + *(first + c) = std::move(*(first + g)); + c = g; + } + + *(first + c) = std::move(val); +} + +template +inline void push_heap1(It first, diff_t c, val_t val, Compare comp) +{ + diff_t const p = (c - 1) >> 1; // parent index + if (MinCall()(comp, *(first + p), val)) + { + *(first + c) = std::move(*(first + p)); + return push_heap2(first, p, std::move(val), comp); + } + else + { + return push_heap2(first, c, std::move(val), comp); + } +} + +template +inline void push_heap(It first, It last, Compare comp) +{ + diff_t const size = last - first; + if (size < 2) + { + return; + } + + diff_t c = size - 1; // back index + val_t val = std::move(*(first + c)); + if (level(c) % 2 == 0) // is min level + { + push_heap1(first, c, std::move(val), comp); + } + else + { + push_heap1(first, c, std::move(val), comp); + } +} + + +template +inline diff_t pick_grandchild4(It first, diff_t f, Compare comp) +{ + It it = first + f; + diff_t m1 = Call()(comp, *(it), *(it + 1)) ? f : f + 1; + diff_t m2 = Call()(comp, *(it + 2), *(it + 3)) ? f + 2 : f + 3; + return Call()(comp, *(first + m1), *(first + m2)) ? m1 : m2; +} + +//template +//inline diff_t pick_descendant(It first, diff_t f, diff_t l, Compare comp) +//{ +// diff_t m = f; +// for (++f; f != l; ++f) +// { +// if (Call()(comp, *(first + f), *(first + m))) +// { +// m = f; +// } +// } +// return m; +//} + +template +inline void pop_heap1(It first, diff_t p, diff_t size, val_t val, Compare comp) +{ + if (size >= 7) // grandparent of 4 grandchildren is possible + { + diff_t const last_g = (size - 3) >> 2; // grandparent of the element behind back + while (p < last_g) // p is grandparent of 4 grandchildren + { + diff_t const ll = 4 * p + 3; + diff_t const m = pick_grandchild4(first, ll, comp); + + if (! Call()(comp, *(first + m), val)) + { + break; + } + + *(first + p) = std::move(*(first + m)); + + diff_t par = (m - 1) >> 1; + if (Call()(comp, *(first + par), val)) + { + using std::swap; + swap(*(first + par), val); + } + + p = m; + } + } + + if (size >= 2 && p <= ((size - 2) >> 1)) // at least one child + { + diff_t const l = 2 * p + 1; + diff_t m = l; // left child + if (size >= 3 && p <= ((size - 3) >> 1)) // at least two children + { + // m = left child + diff_t m2 = l + 1; // right child + if (size >= 4 && p <= ((size - 4) >> 2)) // at least two children and one grandchild + { + diff_t const ll = 2 * l + 1; + m = ll; // left most grandchild + // m2 = right child + if (size >= 5 && p <= ((size - 5) >> 2)) // at least two children and two grandchildren + { + m = Call()(comp, *(first + ll), *(first + ll + 1)) ? ll : (ll + 1); // greater of the left grandchildren + // m2 = right child + if (size >= 6 && p <= ((size - 6) >> 2)) // at least two children and three grandchildren + { + // m = greater of the left grandchildren + m2 = ll + 2; // third grandchild + } + } + } + + m = Call()(comp, *(first + m), *(first + m2)) ? m : m2; + } + + if (Call()(comp, *(first + m), val)) + { + *(first + p) = std::move(*(first + m)); + + if (m >= 3 && p <= ((m - 3) >> 2)) // is p grandparent of m + { + diff_t par = (m - 1) >> 1; + if (Call()(comp, *(first + par), val)) + { + using std::swap; + swap(*(first + par), val); + } + } + + p = m; + } + } + + *(first + p) = std::move(val); +} + +template +inline void pop_heap(It first, It el, It last, Compare comp) +{ + diff_t size = last - first; + if (size < 2) + { + return; + } + + --last; + val_t val = std::move(*last); + *last = std::move(*el); + + // Ignore the last element + --size; + + diff_t p = el - first; + if (level(p) % 2 == 0) // is min level + { + pop_heap1(first, p, size, std::move(val), comp); + } + else + { + pop_heap1(first, p, size, std::move(val), comp); + } +} + +template +inline void make_heap(It first, It last, Compare comp) +{ + diff_t size = last - first; + diff_t p = size / 2; + if (p <= 0) + { + return; + } + + int level_p = level(p - 1); + diff_t level_f = (diff_t(1) << level_p) - 1; + while (p > 0) + { + --p; + val_t val = std::move(*(first + p)); + if (level_p % 2 == 0) // is min level + { + pop_heap1(first, p, size, std::move(val), comp); + } + else + { + pop_heap1(first, p, size, std::move(val), comp); + } + + if (p == level_f) + { + --level_p; + level_f >>= 1; + } + } +} + +template +inline bool is_heap(It first, It last, Compare comp) +{ + diff_t const size = last - first; + diff_t pow2 = 4; + bool is_min_level = false; + for (diff_t i = 1; i < size; ++i) + { + if (i == pow2 - 1) + { + pow2 *= 2; + is_min_level = ! is_min_level; + } + + diff_t const p = (i - 1) >> 1; + if (is_min_level) + { + if (Call()(comp, *(first + p), *(first + i))) + { + return false; + } + } + else + { + if (Call()(comp, *(first + i), *(first + p))) + { + return false; + } + } + + if (i >= 3) + { + diff_t const g = (p - 1) >> 1; + if (is_min_level) + { + if (Call()(comp, *(first + i), *(first + g))) + { + return false; + } + } + else + { + if (Call()(comp, *(first + g), *(first + i))) + { + return false; + } + } + } + } + return true; +} + +template +inline It bottom_heap(It first, It last, Compare comp) +{ + diff_t const size = last - first; + return size <= 1 ? first : + size == 2 ? (first + 1) : + Call()(comp, *(first + 1), *(first + 2)) ? (first + 2) : (first + 1); +} + +} // namespace minmax_heap_detail + + +template +inline void push_minmax_heap(It first, It last, Compare comp) +{ + using namespace minmax_heap_detail; + minmax_heap_detail::push_heap(first, last, comp); +} + +template +inline void push_minmax_heap(It first, It last) +{ + using namespace minmax_heap_detail; + minmax_heap_detail::push_heap(first, last, std::less<>()); +} + +template +inline void pop_top_minmax_heap(It first, It last, Compare comp) +{ + using namespace minmax_heap_detail; + pop_heap(first, first, last, comp); +} + +template +inline void pop_top_minmax_heap(It first, It last) +{ + using namespace minmax_heap_detail; + pop_heap(first, first, last, std::less<>()); +} + +template +inline void pop_bottom_minmax_heap(It first, It last, Compare comp) +{ + using namespace minmax_heap_detail; + It bottom = minmax_heap_detail::bottom_heap(first, last, comp); + pop_heap(first, bottom, last, comp); +} + +template +inline void pop_bottom_minmax_heap(It first, It last) +{ + using namespace minmax_heap_detail; + auto&& comp = std::less<>(); + It bottom = minmax_heap_detail::bottom_heap(first, last, comp); + pop_heap(first, bottom, last, comp); +} + +template +inline void make_minmax_heap(It first, It last, Compare comp) +{ + using namespace minmax_heap_detail; + return minmax_heap_detail::make_heap(first, last, comp); +} + +template +inline void make_minmax_heap(It first, It last) +{ + using namespace minmax_heap_detail; + return minmax_heap_detail::make_heap(first, last, std::less<>()); +} + +template +inline bool is_minmax_heap(It first, It last, Compare comp) +{ + using namespace minmax_heap_detail; + return minmax_heap_detail::is_heap(first, last, comp); +} + +template +inline bool is_minmax_heap(It first, It last) +{ + using namespace minmax_heap_detail; + return minmax_heap_detail::is_heap(first, last, std::less<>()); +} + +template +inline decltype(auto) bottom_minmax_heap(It first, It last, Compare comp) +{ + using namespace minmax_heap_detail; + return *minmax_heap_detail::bottom_heap(first, last, comp); +} + +template +inline decltype(auto) bottom_minmax_heap(It first, It last) +{ + using namespace minmax_heap_detail; + return *minmax_heap_detail::bottom_heap(first, last, std::less<>()); +} + + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_MINMAX_HEAP_HPP diff --git a/include/boost/geometry/index/detail/predicates.hpp b/include/boost/geometry/index/detail/predicates.hpp index 0ae8defe8..bba53aa25 100644 --- a/include/boost/geometry/index/detail/predicates.hpp +++ b/include/boost/geometry/index/detail/predicates.hpp @@ -20,9 +20,13 @@ //#include #include +#include +#include #include +#include + namespace boost { namespace geometry { namespace index { namespace detail { namespace predicates { @@ -31,10 +35,10 @@ namespace predicates { // predicates // ------------------------------------------------------------------ // -template +template ::value> struct satisfies_impl { - satisfies_impl() : fun(NULL) {} + satisfies_impl() : fun(nullptr) {} satisfies_impl(Fun f) : fun(f) {} Fun * fun; }; @@ -42,20 +46,19 @@ struct satisfies_impl template struct satisfies_impl { - satisfies_impl() {} + satisfies_impl() = default; satisfies_impl(Fun const& f) : fun(f) {} Fun fun; }; template -struct satisfies - : satisfies_impl::value> +struct satisfies : satisfies_impl { - typedef satisfies_impl::value> base; + using base_t = satisfies_impl; - satisfies() {} - satisfies(Fun const& f) : base(f) {} - satisfies(base const& b) : base(b) {} + satisfies() = default; + satisfies(Fun const& f) : base_t(f) {} + satisfies(base_t const& b) : base_t(b) {} }; // ------------------------------------------------------------------ // @@ -619,11 +622,13 @@ struct predicates_check_impl, Tag, First, Last> } }; -template +template inline bool predicates_check(Predicates const& p, Value const& v, Indexable const& i, Strategy const& s) { - return detail::predicates_check_impl - ::apply(p, v, i, s); + return detail::predicates_check_impl + < + Predicates, Tag, 0, predicates_length::value + >::apply(p, v, i, s); } // ------------------------------------------------------------------ // diff --git a/include/boost/geometry/index/detail/priority_dequeue.hpp b/include/boost/geometry/index/detail/priority_dequeue.hpp new file mode 100644 index 000000000..bbe563aba --- /dev/null +++ b/include/boost/geometry/index/detail/priority_dequeue.hpp @@ -0,0 +1,150 @@ +// Boost.Geometry + +// Copyright (c) 2021, Oracle and/or its affiliates. +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_PRIORITY_DEQUEUE_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_PRIORITY_DEQUEUE_HPP + +#include + +#include + +namespace boost { namespace geometry { namespace index { namespace detail +{ + +template +< + typename T, + typename Container = std::vector, + typename Compare = std::less +> +class priority_dequeue +{ +public: + using container_type = Container; + using value_compare = Compare; + using value_type = typename Container::value_type; + using size_type = typename Container::size_type; + using reference = typename Container::reference; + using const_reference = typename Container::const_reference; + + priority_dequeue() + : c(), comp() + {} + + explicit priority_dequeue(Compare const& compare) + : c(), comp(compare) + {} + + priority_dequeue(Compare const& compare, Container const& cont) + : c(cont), comp(compare) + { + make_maxmin_heap(c.begin(), c.end(), comp); + } + + priority_dequeue(Compare const& compare, Container&& cont) + : c(std::move(cont)), comp(compare) + { + make_maxmin_heap(c.begin(), c.end(), comp); + } + + template + priority_dequeue(It first, It last) + : c(first, last), comp() + { + make_maxmin_heap(c.begin(), c.end(), comp); + } + + template + priority_dequeue(It first, It last, Compare const& compare) + : c(first, last), comp(compare) + { + make_maxmin_heap(c.begin(), c.end(), comp); + } + + template + priority_dequeue(It first, It last, Compare const& compare, Container const& cont) + : c(cont), comp(compare) + { + c.insert(first, last); + make_maxmin_heap(c.begin(), c.end(), comp); + } + + template + priority_dequeue(It first, It last, Compare const& compare, Container&& cont) + : c(std::move(cont)), comp(compare) + { + c.insert(first, last); + make_maxmin_heap(c.begin(), c.end(), comp); + } + + const_reference top() const + { + return *c.begin(); + } + + const_reference bottom() const + { + return bottom_maxmin_heap(c.begin(), c.end(), comp); + } + + void push(const value_type& value) + { + c.push_back(value); + push_maxmin_heap(c.begin(), c.end(), comp); + } + + void push(value_type&& value) + { + c.push_back(std::move(value)); + push_maxmin_heap(c.begin(), c.end(), comp); + } + + template + void emplace(Args&& ...args) + { + c.emplace_back(std::forward(args)...); + push_maxmin_heap(c.begin(), c.end(), comp); + } + + void pop_top() + { + pop_top_maxmin_heap(c.begin(), c.end(), comp); + c.pop_back(); + } + + void pop_bottom() + { + pop_bottom_maxmin_heap(c.begin(), c.end(), comp); + c.pop_back(); + } + + bool empty() const + { + return c.empty(); + } + + size_t size() const + { + return c.size(); + } + + void swap(priority_dequeue& other) + { + using std::swap; + std::swap(c, other.c); + std::swap(comp, other.comp); + } + +protected: + Container c; + Compare comp; +}; + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_PRIORITY_DEQUEUE_HPP diff --git a/include/boost/geometry/index/detail/rtree/adaptors.hpp b/include/boost/geometry/index/detail/rtree/adaptors.hpp index 4e0eb9ba0..4da3d7b94 100644 --- a/include/boost/geometry/index/detail/rtree/adaptors.hpp +++ b/include/boost/geometry/index/detail/rtree/adaptors.hpp @@ -4,6 +4,10 @@ // // Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. // +// This file was modified by Oracle on 2021. +// Modifications copyright (c) 2021 Oracle and/or its affiliates. +// Contributed and/or modified by Adam Wulkiewicz, 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) @@ -11,13 +15,13 @@ #ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_ADAPTORS_HPP #define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_ADAPTORS_HPP -#include -#include +#include #include namespace boost { namespace geometry { namespace index { +// Forward declaration template class rtree; diff --git a/include/boost/geometry/index/detail/rtree/iterators.hpp b/include/boost/geometry/index/detail/rtree/iterators.hpp index a47dd7ea4..1d5cd1a23 100644 --- a/include/boost/geometry/index/detail/rtree/iterators.hpp +++ b/include/boost/geometry/index/detail/rtree/iterators.hpp @@ -4,6 +4,10 @@ // // Copyright (c) 2011-2015 Adam Wulkiewicz, Lodz, Poland. // +// This file was modified by Oracle on 2021. +// Modifications copyright (c) 2021 Oracle and/or its affiliates. +// Contributed and/or modified by Adam Wulkiewicz, 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) @@ -11,6 +15,10 @@ #ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_ITERATORS_HPP #define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_ITERATORS_HPP +#include + +#include + namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace iterators { template diff --git a/include/boost/geometry/index/detail/rtree/kmeans/kmeans.hpp b/include/boost/geometry/index/detail/rtree/kmeans/kmeans.hpp index 3f61482b2..34edcfa7c 100644 --- a/include/boost/geometry/index/detail/rtree/kmeans/kmeans.hpp +++ b/include/boost/geometry/index/detail/rtree/kmeans/kmeans.hpp @@ -4,6 +4,10 @@ // // Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. // +// This file was modified by Oracle on 2021. +// Modifications copyright (c) 2021 Oracle and/or its affiliates. +// Contributed and/or modified by Adam Wulkiewicz, 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) @@ -11,6 +15,6 @@ #ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_KMEANS_KMEANS_HPP #define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_KMEANS_KMEANS_HPP -#include +#include #endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_KMEANS_KMEANS_HPP diff --git a/include/boost/geometry/index/detail/rtree/kmeans/split.hpp b/include/boost/geometry/index/detail/rtree/kmeans/split.hpp index f19654972..aa9dfbba4 100644 --- a/include/boost/geometry/index/detail/rtree/kmeans/split.hpp +++ b/include/boost/geometry/index/detail/rtree/kmeans/split.hpp @@ -4,6 +4,10 @@ // // Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. // +// This file was modified by Oracle on 2021. +// Modifications copyright (c) 2021 Oracle and/or its affiliates. +// Contributed and/or modified by Adam Wulkiewicz, 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) @@ -11,13 +15,17 @@ #ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_KMEANS_SPLIT_HPP #define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_KMEANS_SPLIT_HPP -#include -#include +#include +#include namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { +// TODO: This should be defined in options.hpp +// For now it's defined here to satisfy Boost header policy +struct split_kmeans_tag {}; + namespace kmeans { // some details @@ -56,25 +64,34 @@ namespace kmeans { // 4. Pamietac o parametryzacji kontenera z nadmiarowymi elementami // PS. Z R* reinsertami moze byc masakra -template -class split +template +class split { protected: - typedef typename rtree::node::type node; - typedef typename rtree::internal_node::type internal_node; - typedef typename rtree::leaf::type leaf; + typedef typename MembersHolder::parameters_type parameters_type; + typedef typename MembersHolder::box_type box_type; + typedef typename MembersHolder::translator_type translator_type; + typedef typename MembersHolder::allocators_type allocators_type; + typedef typename MembersHolder::size_type size_type; - typedef typename Options::parameters_type parameters_type; + typedef typename MembersHolder::node node; + typedef typename MembersHolder::internal_node internal_node; + typedef typename MembersHolder::leaf leaf; public: + typedef index::detail::varray + < + typename rtree::elements_type::type::value_type, + 1 + > nodes_container_type; + template - static inline void apply(node* & root_node, - size_t & leafs_level, + static inline void apply(nodes_container_type & additional_nodes, Node & n, - internal_node *parent_node, - size_t current_child_index, - Translator const& tr, - Allocators & allocators) + box_type & n_box, + parameters_type const& parameters, + translator_type const& translator, + allocators_type & allocators) { } diff --git a/include/boost/geometry/index/detail/rtree/node/node_elements.hpp b/include/boost/geometry/index/detail/rtree/node/node_elements.hpp index 0e5848987..ca034a8d7 100644 --- a/include/boost/geometry/index/detail/rtree/node/node_elements.hpp +++ b/include/boost/geometry/index/detail/rtree/node/node_elements.hpp @@ -4,6 +4,10 @@ // // Copyright (c) 2011-2015 Adam Wulkiewicz, Lodz, Poland. // +// This file was modified by Oracle on 2021. +// Modifications copyright (c) 2021 Oracle and/or its affiliates. +// Contributed and/or modified by Adam Wulkiewicz, 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) @@ -15,6 +19,7 @@ #include #include #include +#include namespace boost { namespace geometry { namespace index { diff --git a/include/boost/geometry/index/detail/rtree/node/scoped_deallocator.hpp b/include/boost/geometry/index/detail/rtree/node/scoped_deallocator.hpp index 0062402d4..a63aad884 100644 --- a/include/boost/geometry/index/detail/rtree/node/scoped_deallocator.hpp +++ b/include/boost/geometry/index/detail/rtree/node/scoped_deallocator.hpp @@ -4,6 +4,10 @@ // // Copyright (c) 2011-2018 Adam Wulkiewicz, Lodz, Poland. // +// This file was modified by Oracle on 2021. +// Modifications copyright (c) 2021 Oracle and/or its affiliates. +// Contributed and/or modified by Adam Wulkiewicz, 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) @@ -11,6 +15,8 @@ #ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_SCOPED_DEALLOCATOR_HPP #define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_SCOPED_DEALLOCATOR_HPP +#include + namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { diff --git a/include/boost/geometry/index/detail/rtree/node/variant_dynamic.hpp b/include/boost/geometry/index/detail/rtree/node/variant_dynamic.hpp index 52b253ccf..e871e6f19 100644 --- a/include/boost/geometry/index/detail/rtree/node/variant_dynamic.hpp +++ b/include/boost/geometry/index/detail/rtree/node/variant_dynamic.hpp @@ -4,6 +4,10 @@ // // Copyright (c) 2011-2018 Adam Wulkiewicz, Lodz, Poland. // +// This file was modified by Oracle on 2021. +// Modifications copyright (c) 2021 Oracle and/or its affiliates. +// Contributed and/or modified by Adam Wulkiewicz, 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) @@ -11,7 +15,15 @@ #ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_VARIANT_DYNAMIC_HPP #define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_VARIANT_DYNAMIC_HPP +#include +#include #include +#include +#include + +#include +#include +#include namespace boost { namespace geometry { namespace index { diff --git a/include/boost/geometry/index/detail/rtree/node/variant_static.hpp b/include/boost/geometry/index/detail/rtree/node/variant_static.hpp index c30998d68..624ce472e 100644 --- a/include/boost/geometry/index/detail/rtree/node/variant_static.hpp +++ b/include/boost/geometry/index/detail/rtree/node/variant_static.hpp @@ -4,6 +4,10 @@ // // Copyright (c) 2011-2018 Adam Wulkiewicz, Lodz, Poland. // +// This file was modified by Oracle on 2021. +// Modifications copyright (c) 2021 Oracle and/or its affiliates. +// Contributed and/or modified by Adam Wulkiewicz, 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) @@ -11,6 +15,9 @@ #ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_VARIANT_STATIC_HPP #define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_VARIANT_STATIC_HPP +#include +#include + namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { diff --git a/include/boost/geometry/index/detail/rtree/node/weak_dynamic.hpp b/include/boost/geometry/index/detail/rtree/node/weak_dynamic.hpp index eadda62a9..9a3220183 100644 --- a/include/boost/geometry/index/detail/rtree/node/weak_dynamic.hpp +++ b/include/boost/geometry/index/detail/rtree/node/weak_dynamic.hpp @@ -4,6 +4,10 @@ // // Copyright (c) 2011-2018 Adam Wulkiewicz, Lodz, Poland. // +// This file was modified by Oracle on 2021. +// Modifications copyright (c) 2021 Oracle and/or its affiliates. +// Contributed and/or modified by Adam Wulkiewicz, 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) @@ -11,10 +15,24 @@ #ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_WEAK_DYNAMIC_HPP #define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_WEAK_DYNAMIC_HPP +#include +#include +#include + +#include +#include +#include +#include + namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { +// TODO: This should be defined in options.hpp +// For now it's defined here to satisfy Boost header policy +struct node_weak_dynamic_tag {}; +struct node_weak_static_tag {}; + template struct weak_internal_node : public weak_node @@ -87,7 +105,7 @@ struct visitor struct internal_node_alloc { - typedef typename internal_nod + typedef typename internal_node < Value, Parameters, Box, allocators, @@ -116,6 +134,22 @@ struct leaf_alloc >::template rebind_alloc type; }; +template +struct node_alloc +{ + typedef typename weak_node + < + Value, Parameters, Box, + allocators, + Tag + >::type node_type; + + typedef typename ::boost::container::allocator_traits + < + Allocator + >::template rebind_alloc type; +}; + template class allocators : public internal_node_alloc::type diff --git a/include/boost/geometry/index/detail/rtree/node/weak_static.hpp b/include/boost/geometry/index/detail/rtree/node/weak_static.hpp index ac9e69cec..65b80266d 100644 --- a/include/boost/geometry/index/detail/rtree/node/weak_static.hpp +++ b/include/boost/geometry/index/detail/rtree/node/weak_static.hpp @@ -4,6 +4,10 @@ // // Copyright (c) 2011-2018 Adam Wulkiewicz, Lodz, Poland. // +// This file was modified by Oracle on 2021. +// Modifications copyright (c) 2021 Oracle and/or its affiliates. +// Contributed and/or modified by Adam Wulkiewicz, 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) @@ -11,6 +15,9 @@ #ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_WEAK_STATIC_HPP #define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_WEAK_STATIC_HPP +#include +#include + namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { diff --git a/include/boost/geometry/index/detail/rtree/node/weak_visitor.hpp b/include/boost/geometry/index/detail/rtree/node/weak_visitor.hpp index 08d84778e..a6beaf090 100644 --- a/include/boost/geometry/index/detail/rtree/node/weak_visitor.hpp +++ b/include/boost/geometry/index/detail/rtree/node/weak_visitor.hpp @@ -4,6 +4,10 @@ // // Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland. // +// This file was modified by Oracle on 2021. +// Modifications copyright (c) 2021 Oracle and/or its affiliates. +// Contributed and/or modified by Adam Wulkiewicz, 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) @@ -11,6 +15,8 @@ #ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_WEAK_VISITOR_HPP #define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_WEAK_VISITOR_HPP +#include + namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { diff --git a/include/boost/geometry/index/detail/rtree/pack_create.hpp b/include/boost/geometry/index/detail/rtree/pack_create.hpp index 4cfd39669..6a8ffe6aa 100644 --- a/include/boost/geometry/index/detail/rtree/pack_create.hpp +++ b/include/boost/geometry/index/detail/rtree/pack_create.hpp @@ -5,8 +5,8 @@ // Copyright (c) 2011-2017 Adam Wulkiewicz, Lodz, Poland. // Copyright (c) 2020 Caian Benedicto, Campinas, Brazil. // -// This file was modified by Oracle on 2019. -// Modifications copyright (c) 2019 Oracle and/or its affiliates. +// This file was modified by Oracle on 2019-2021. +// Modifications copyright (c) 2019-2021 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // // Use, modification and distribution is subject to the Boost Software License, @@ -18,12 +18,15 @@ #include +#include #include + +#include #include #include +#include #include - -#include +#include namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { diff --git a/include/boost/geometry/index/detail/rtree/query_iterators.hpp b/include/boost/geometry/index/detail/rtree/query_iterators.hpp index 8822bcf04..c3a41a010 100644 --- a/include/boost/geometry/index/detail/rtree/query_iterators.hpp +++ b/include/boost/geometry/index/detail/rtree/query_iterators.hpp @@ -4,8 +4,8 @@ // // Copyright (c) 2011-2015 Adam Wulkiewicz, Lodz, Poland. // -// This file was modified by Oracle on 2019. -// Modifications copyright (c) 2019 Oracle and/or its affiliates. +// This file was modified by Oracle on 2019-2021. +// Modifications copyright (c) 2019-2021 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // // Use, modification and distribution is subject to the Boost Software License, @@ -17,7 +17,9 @@ #include -//#define BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_MOVE +#include +#include +#include namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace iterators { @@ -65,13 +67,8 @@ struct end_query_iterator template class spatial_query_iterator { - typedef typename MembersHolder::parameters_type parameters_type; - typedef typename MembersHolder::translator_type translator_type; typedef typename MembersHolder::allocators_type allocators_type; - typedef visitors::spatial_query_incremental visitor_type; - typedef typename visitor_type::node_pointer node_pointer; - public: typedef std::forward_iterator_tag iterator_category; typedef typename MembersHolder::value_type value_type; @@ -79,32 +76,31 @@ public: typedef typename allocators_type::difference_type difference_type; typedef typename allocators_type::const_pointer pointer; - inline spatial_query_iterator() + spatial_query_iterator() = default; + + explicit spatial_query_iterator(Predicates const& pred) + : m_impl(pred) {} - inline spatial_query_iterator(parameters_type const& par, translator_type const& t, Predicates const& p) - : m_visitor(par, t, p) - {} - - inline spatial_query_iterator(node_pointer root, parameters_type const& par, translator_type const& t, Predicates const& p) - : m_visitor(par, t, p) + spatial_query_iterator(MembersHolder const& members, Predicates const& pred) + : m_impl(members, pred) { - m_visitor.initialize(root); + m_impl.initialize(members); } reference operator*() const { - return m_visitor.dereference(); + return m_impl.dereference(); } const value_type * operator->() const { - return boost::addressof(m_visitor.dereference()); + return boost::addressof(m_impl.dereference()); } spatial_query_iterator & operator++() { - m_visitor.increment(); + m_impl.increment(); return *this; } @@ -117,33 +113,28 @@ public: friend bool operator==(spatial_query_iterator const& l, spatial_query_iterator const& r) { - return l.m_visitor == r.m_visitor; + return l.m_impl == r.m_impl; } friend bool operator==(spatial_query_iterator const& l, end_query_iterator const& /*r*/) { - return l.m_visitor.is_end(); + return l.m_impl.is_end(); } friend bool operator==(end_query_iterator const& /*l*/, spatial_query_iterator const& r) { - return r.m_visitor.is_end(); + return r.m_impl.is_end(); } private: - visitor_type m_visitor; + visitors::spatial_query_incremental m_impl; }; -template +template class distance_query_iterator { - typedef typename MembersHolder::parameters_type parameters_type; - typedef typename MembersHolder::translator_type translator_type; typedef typename MembersHolder::allocators_type allocators_type; - typedef visitors::distance_query_incremental visitor_type; - typedef typename visitor_type::node_pointer node_pointer; - public: typedef std::forward_iterator_tag iterator_category; typedef typename MembersHolder::value_type value_type; @@ -151,32 +142,31 @@ public: typedef typename allocators_type::difference_type difference_type; typedef typename allocators_type::const_pointer pointer; - inline distance_query_iterator() + distance_query_iterator() = default; + + explicit distance_query_iterator(Predicates const& pred) + : m_impl(pred) {} - inline distance_query_iterator(parameters_type const& par, translator_type const& t, Predicates const& p) - : m_visitor(par, t, p) - {} - - inline distance_query_iterator(node_pointer root, parameters_type const& par, translator_type const& t, Predicates const& p) - : m_visitor(par, t, p) + distance_query_iterator(MembersHolder const& members, Predicates const& pred) + : m_impl(members, pred) { - m_visitor.initialize(root); + m_impl.initialize(members); } reference operator*() const { - return m_visitor.dereference(); + return m_impl.dereference(); } const value_type * operator->() const { - return boost::addressof(m_visitor.dereference()); + return boost::addressof(m_impl.dereference()); } distance_query_iterator & operator++() { - m_visitor.increment(); + m_impl.increment(); return *this; } @@ -189,21 +179,21 @@ public: friend bool operator==(distance_query_iterator const& l, distance_query_iterator const& r) { - return l.m_visitor == r.m_visitor; + return l.m_impl == r.m_impl; } friend bool operator==(distance_query_iterator const& l, end_query_iterator const& /*r*/) { - return l.m_visitor.is_end(); + return l.m_impl.is_end(); } friend bool operator==(end_query_iterator const& /*l*/, distance_query_iterator const& r) { - return r.m_visitor.is_end(); + return r.m_impl.is_end(); } private: - visitor_type m_visitor; + visitors::distance_query_incremental m_impl; }; @@ -280,8 +270,7 @@ public: typedef typename Allocators::difference_type difference_type; typedef typename Allocators::const_pointer pointer; - query_iterator() - {} + query_iterator() = default; template query_iterator(It const& it) @@ -296,7 +285,6 @@ public: : m_ptr(o.m_ptr.get() ? o.m_ptr->clone() : 0) {} -#ifndef BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_MOVE query_iterator & operator=(query_iterator const& o) { if ( this != boost::addressof(o) ) @@ -305,12 +293,13 @@ public: } return *this; } -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + query_iterator(query_iterator && o) : m_ptr(0) { m_ptr.swap(o.m_ptr); } + query_iterator & operator=(query_iterator && o) { if ( this != boost::addressof(o) ) @@ -320,34 +309,6 @@ public: } return *this; } -#endif -#else // !BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_MOVE -private: - BOOST_COPYABLE_AND_MOVABLE(query_iterator) -public: - query_iterator & operator=(BOOST_COPY_ASSIGN_REF(query_iterator) o) - { - if ( this != boost::addressof(o) ) - { - m_ptr.reset(o.m_ptr.get() ? o.m_ptr->clone() : 0); - } - return *this; - } - query_iterator(BOOST_RV_REF(query_iterator) o) - : m_ptr(0) - { - m_ptr.swap(o.m_ptr); - } - query_iterator & operator=(BOOST_RV_REF(query_iterator) o) - { - if ( this != boost::addressof(o) ) - { - m_ptr.swap(o.m_ptr); - o.m_ptr.reset(); - } - return *this; - } -#endif // BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_MOVE reference operator*() const { diff --git a/include/boost/geometry/index/detail/rtree/rstar/choose_next_node.hpp b/include/boost/geometry/index/detail/rtree/rstar/choose_next_node.hpp index 7ba5f0f99..4ea9060f8 100644 --- a/include/boost/geometry/index/detail/rtree/rstar/choose_next_node.hpp +++ b/include/boost/geometry/index/detail/rtree/rstar/choose_next_node.hpp @@ -4,8 +4,8 @@ // // Copyright (c) 2011-2019 Adam Wulkiewicz, Lodz, Poland. // -// This file was modified by Oracle on 2019. -// Modifications copyright (c) 2019 Oracle and/or its affiliates. +// This file was modified by Oracle on 2019-2021. +// Modifications copyright (c) 2019-2021 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // // Use, modification and distribution is subject to the Boost Software License, @@ -27,6 +27,8 @@ #include #include +#include +#include #include namespace boost { namespace geometry { namespace index { diff --git a/include/boost/geometry/index/detail/rtree/rstar/insert.hpp b/include/boost/geometry/index/detail/rtree/rstar/insert.hpp index 8517b7f1b..ce830007a 100644 --- a/include/boost/geometry/index/detail/rtree/rstar/insert.hpp +++ b/include/boost/geometry/index/detail/rtree/rstar/insert.hpp @@ -19,7 +19,12 @@ #include +#include + #include +#include +#include +#include namespace boost { namespace geometry { namespace index { diff --git a/include/boost/geometry/index/detail/rtree/utilities/gl_draw.hpp b/include/boost/geometry/index/detail/rtree/utilities/gl_draw.hpp index bdabebf22..44933dac4 100644 --- a/include/boost/geometry/index/detail/rtree/utilities/gl_draw.hpp +++ b/include/boost/geometry/index/detail/rtree/utilities/gl_draw.hpp @@ -4,8 +4,8 @@ // // Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. // -// This file was modified by Oracle on 2019-2020. -// Modifications copyright (c) 2019-2020 Oracle and/or its affiliates. +// This file was modified by Oracle on 2019-2021. +// Modifications copyright (c) 2019-2021 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // // Use, modification and distribution is subject to the Boost Software License, @@ -15,7 +15,16 @@ #ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_GL_DRAW_HPP #define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_GL_DRAW_HPP +#include + +#include +#include +#include #include +#include +#include + +#include namespace boost { namespace geometry { namespace index { namespace detail { diff --git a/include/boost/geometry/index/detail/rtree/utilities/print.hpp b/include/boost/geometry/index/detail/rtree/utilities/print.hpp index 2ed71a6b8..15d618eb6 100644 --- a/include/boost/geometry/index/detail/rtree/utilities/print.hpp +++ b/include/boost/geometry/index/detail/rtree/utilities/print.hpp @@ -4,8 +4,8 @@ // // Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. // -// This file was modified by Oracle on 2019-2020. -// Modifications copyright (c) 2019-2020 Oracle and/or its affiliates. +// This file was modified by Oracle on 2019-2021. +// Modifications copyright (c) 2019-2021 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // // Use, modification and distribution is subject to the Boost Software License, @@ -17,7 +17,11 @@ #include +#include +#include #include +#include +#include namespace boost { namespace geometry { namespace index { namespace detail { diff --git a/include/boost/geometry/index/detail/rtree/visitors/distance_query.hpp b/include/boost/geometry/index/detail/rtree/visitors/distance_query.hpp index a40dbfe84..7845326d8 100644 --- a/include/boost/geometry/index/detail/rtree/visitors/distance_query.hpp +++ b/include/boost/geometry/index/detail/rtree/visitors/distance_query.hpp @@ -15,6 +15,15 @@ #ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_DISTANCE_QUERY_HPP #define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_DISTANCE_QUERY_HPP +#include + +#include +#include +#include +#include +#include +#include + namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace visitors { @@ -40,90 +49,114 @@ struct pair_first_greater } }; +template +struct priority_dequeue : index::detail::priority_dequeue, Comp> +{ + priority_dequeue() = default; + //void reserve(typename std::vector::size_type n) + //{ + // this->c.reserve(n); + //} + //void clear() + //{ + // this->c.clear(); + //} +}; -template +template +struct priority_queue : std::priority_queue, Comp> +{ + priority_queue() = default; + //void reserve(typename std::vector::size_type n) + //{ + // this->c.reserve(n); + //} + void clear() + { + this->c.clear(); + } +}; + +struct branch_data_comp +{ + template + bool operator()(BranchData const& b1, BranchData const& b2) const + { + return b1.distance > b2.distance || (b1.distance == b2.distance && b1.reverse_level > b2.reverse_level); + } +}; + +template class distance_query_result { + using neighbor_data = std::pair; + using neighbors_type = std::vector; + using size_type = typename neighbors_type::size_type; + public: - typedef DistanceType distance_type; - - inline explicit distance_query_result(size_t k, OutIt out_it) - : m_count(k), m_out_it(out_it) + inline distance_query_result(size_type k) + : m_count(k) { - BOOST_GEOMETRY_INDEX_ASSERT(0 < m_count, "Number of neighbors should be greater than 0"); - m_neighbors.reserve(m_count); } - inline void store(Value const& val, distance_type const& curr_comp_dist) + // NOTE: Do not call if max_count() == 0 + inline void store(DistanceType const& distance, const Value * value_ptr) { - if ( m_neighbors.size() < m_count ) + if (m_neighbors.size() < m_count) { - m_neighbors.push_back(std::make_pair(curr_comp_dist, val)); + m_neighbors.push_back(std::make_pair(distance, value_ptr)); - if ( m_neighbors.size() == m_count ) - std::make_heap(m_neighbors.begin(), m_neighbors.end(), pair_first_less()); - } - else - { - if ( curr_comp_dist < m_neighbors.front().first ) + if (m_neighbors.size() == m_count) { - std::pop_heap(m_neighbors.begin(), m_neighbors.end(), pair_first_less()); - m_neighbors.back().first = curr_comp_dist; - m_neighbors.back().second = val; - std::push_heap(m_neighbors.begin(), m_neighbors.end(), pair_first_less()); + std::make_heap(m_neighbors.begin(), m_neighbors.end(), pair_first_less()); } } + else if (distance < m_neighbors.front().first) + { + std::pop_heap(m_neighbors.begin(), m_neighbors.end(), pair_first_less()); + m_neighbors.back().first = distance; + m_neighbors.back().second = value_ptr; + std::push_heap(m_neighbors.begin(), m_neighbors.end(), pair_first_less()); + } } - inline bool has_enough_neighbors() const + // NOTE: Do not call if max_count() == 0 + inline bool ignore_branch(DistanceType const& distance) const { - return m_count <= m_neighbors.size(); + return m_neighbors.size() == m_count + && m_neighbors.front().first <= distance; } - inline distance_type greatest_comparable_distance() const + template + inline size_type finish(OutIt out_it) const { - // greatest distance is in the first neighbor only - // if there is at least m_count values found - // this is just for safety reasons since is_comparable_distance_valid() is checked earlier - // TODO - may be replaced by ASSERT - return m_neighbors.size() < m_count - ? (std::numeric_limits::max)() - : m_neighbors.front().first; - } - - inline size_t finish() - { - typedef typename std::vector< std::pair >::const_iterator neighbors_iterator; - for ( neighbors_iterator it = m_neighbors.begin() ; it != m_neighbors.end() ; ++it, ++m_out_it ) - *m_out_it = it->second; + for (auto const& p : m_neighbors) + { + *out_it = *(p.second); + ++out_it; + } return m_neighbors.size(); } -private: - size_t m_count; - OutIt m_out_it; + size_type max_count() const + { + return m_count; + } - std::vector< std::pair > m_neighbors; +private: + size_type m_count; + neighbors_type m_neighbors; }; -template -< - typename MembersHolder, - typename Predicates, - std::size_t DistancePredicateIndex, - typename OutIter -> +template class distance_query - : public MembersHolder::visitor_const { -public: typedef typename MembersHolder::value_type value_type; typedef typename MembersHolder::box_type box_type; typedef typename MembersHolder::parameters_type parameters_type; typedef typename MembersHolder::translator_type translator_type; - typedef typename MembersHolder::allocators_type allocators_type; typedef typename index::detail::strategy_type::type strategy_type; @@ -131,7 +164,10 @@ public: typedef typename MembersHolder::internal_node internal_node; typedef typename MembersHolder::leaf leaf; - typedef index::detail::predicates_element nearest_predicate_access; + typedef index::detail::predicates_element + < + index::detail::predicates_find_distance::value, Predicates + > nearest_predicate_access; typedef typename nearest_predicate_access::type nearest_predicate_type; typedef typename indexable_type::type indexable_type; @@ -140,147 +176,141 @@ public: typedef typename calculate_value_distance::result_type value_distance_type; typedef typename calculate_node_distance::result_type node_distance_type; - static const std::size_t predicates_len = index::detail::predicates_length::value; + typedef typename MembersHolder::size_type size_type; + typedef typename MembersHolder::node_pointer node_pointer; - inline distance_query(parameters_type const& parameters, translator_type const& translator, Predicates const& pred, OutIter out_it) - : m_parameters(parameters), m_translator(translator) + using neighbor_data = std::pair; + using neighbors_type = std::vector; + + struct branch_data + { + branch_data(node_distance_type d, size_type rl, node_pointer p) + : distance(d), reverse_level(rl), ptr(p) + {} + + node_distance_type distance; + size_type reverse_level; + node_pointer ptr; + }; + using branches_type = priority_queue; + +public: + distance_query(MembersHolder const& members, Predicates const& pred) + : m_tr(members.translator()) + , m_strategy(index::detail::get_strategy(members.parameters())) , m_pred(pred) - , m_result(nearest_predicate_access::get(m_pred).count, out_it) - , m_strategy(index::detail::get_strategy(parameters)) - {} - - inline void operator()(internal_node const& n) { - typedef typename rtree::elements_type::type elements_type; - - // array of active nodes - typedef typename index::detail::rtree::container_from_elements_type< - elements_type, - std::pair - >::type active_branch_list_type; - - active_branch_list_type active_branch_list; - active_branch_list.reserve(m_parameters.get_max_elements()); - - elements_type const& elements = rtree::elements(n); - - // fill array of nodes meeting predicates - for (typename elements_type::const_iterator it = elements.begin(); - it != elements.end(); ++it) - { - // if current node meets predicates - // 0 - dummy value - if ( index::detail::predicates_check - < - index::detail::bounds_tag, 0, predicates_len - >(m_pred, 0, it->first, m_strategy) ) - { - // calculate node's distance(s) for distance predicate - node_distance_type node_distance; - // if distance isn't ok - move to the next node - if ( !calculate_node_distance::apply(predicate(), it->first, - m_strategy, node_distance) ) - { - continue; - } - - // if current node is further than found neighbors - don't analyze it - if ( m_result.has_enough_neighbors() && - is_node_prunable(m_result.greatest_comparable_distance(), node_distance) ) - { - continue; - } - - // add current node's data into the list - active_branch_list.push_back( std::make_pair(node_distance, it->second) ); - } - } - - // if there aren't any nodes in ABL - return - if ( active_branch_list.empty() ) - return; - - // sort array - std::sort(active_branch_list.begin(), active_branch_list.end(), pair_first_less()); - - // recursively visit nodes - for ( typename active_branch_list_type::const_iterator it = active_branch_list.begin(); - it != active_branch_list.end() ; ++it ) - { - // if current node is further than furthest neighbor, the rest of nodes also will be further - if ( m_result.has_enough_neighbors() && - is_node_prunable(m_result.greatest_comparable_distance(), it->first) ) - break; - - rtree::apply_visitor(*this, *(it->second)); - } - - // ALTERNATIVE VERSION - use heap instead of sorted container - // It seems to be faster for greater MaxElements and slower otherwise - // CONSIDER: using one global container/heap for active branches - // instead of a sorted container per level - // This would also change the way how branches are traversed! - // The same may be applied to the iterative version which btw suffers - // from the copying of the whole containers on resize of the ABLs container - - //// make a heap - //std::make_heap(active_branch_list.begin(), active_branch_list.end(), pair_first_greater()); - - //// recursively visit nodes - //while ( !active_branch_list.empty() ) - //{ - // //if current node is further than furthest neighbor, the rest of nodes also will be further - // if ( m_result.has_enough_neighbors() - // && is_node_prunable(m_result.greatest_comparable_distance(), active_branch_list.front().first) ) - // { - // break; - // } - - // rtree::apply_visitor(*this, *(active_branch_list.front().second)); - - // std::pop_heap(active_branch_list.begin(), active_branch_list.end(), pair_first_greater()); - // active_branch_list.pop_back(); - //} + m_neighbors.reserve((std::min)(members.values_count, size_type(max_count()))); + //m_branches.reserve(members.parameters().get_min_elements() * members.leafs_level); ? + // min, max or average? } - inline void operator()(leaf const& n) + template + size_type apply(MembersHolder const& members, OutIter out_it) { - typedef typename rtree::elements_type::type elements_type; - elements_type const& elements = rtree::elements(n); - - // search leaf for closest value meeting predicates - for (typename elements_type::const_iterator it = elements.begin(); - it != elements.end(); ++it) - { - // if value meets predicates - if ( index::detail::predicates_check - < - index::detail::value_tag, 0, predicates_len - >(m_pred, *it, m_translator(*it), m_strategy) ) - { - // calculate values distance for distance predicate - value_distance_type value_distance; - // if distance is ok - if ( calculate_value_distance::apply(predicate(), m_translator(*it), - m_strategy, value_distance) ) - { - // store value - m_result.store(*it, value_distance); - } - } - } - } - - inline size_t finish() - { - return m_result.finish(); + return apply(members.root, members.leafs_level, out_it); } private: - template - static inline bool is_node_prunable(Distance const& greatest_dist, node_distance_type const& d) + template + size_type apply(node_pointer ptr, size_type reverse_level, OutIter out_it) { - return greatest_dist <= d; + namespace id = index::detail; + + if (max_count() <= 0) + { + return 0; + } + + for (;;) + { + if (reverse_level > 0) + { + internal_node& n = rtree::get(*ptr); + // fill array of nodes meeting predicates + for (auto const& p : rtree::elements(n)) + { + node_distance_type node_distance; // for distance predicate + + // if current node meets predicates (0 is dummy value) + if (id::predicates_check(m_pred, 0, p.first, m_strategy) + // and if distance is ok + && calculate_node_distance::apply(predicate(), p.first, m_strategy, node_distance) + // and if current node is closer than the furthest neighbor + && ! ignore_branch(node_distance)) + { + // add current node's data into the list + m_branches.push(branch_data(node_distance, reverse_level - 1, p.second)); + } + } + } + else + { + leaf& n = rtree::get(*ptr); + // search leaf for closest value meeting predicates + for (auto const& v : rtree::elements(n)) + { + value_distance_type value_distance; // for distance predicate + + // if value meets predicates + if (id::predicates_check(m_pred, v, m_tr(v), m_strategy) + // and if distance is ok + && calculate_value_distance::apply(predicate(), m_tr(v), m_strategy, value_distance)) + { + // store value + store_value(value_distance, boost::addressof(v)); + } + } + } + + if (m_branches.empty() + || ignore_branch(m_branches.top().distance)) + { + break; + } + + ptr = m_branches.top().ptr; + reverse_level = m_branches.top().reverse_level; + m_branches.pop(); + } + + for (auto const& p : m_neighbors) + { + *out_it = *(p.second); + ++out_it; + } + + return m_neighbors.size(); + } + + bool ignore_branch(node_distance_type const& node_distance) const + { + return m_neighbors.size() == max_count() + && m_neighbors.front().first <= node_distance; + } + + void store_value(value_distance_type value_distance, const value_type * value_ptr) + { + if (m_neighbors.size() < max_count()) + { + m_neighbors.push_back(std::make_pair(value_distance, value_ptr)); + + if (m_neighbors.size() == max_count()) + { + std::make_heap(m_neighbors.begin(), m_neighbors.end(), pair_first_less()); + } + } + else if (value_distance < m_neighbors.front().first) + { + std::pop_heap(m_neighbors.begin(), m_neighbors.end(), pair_first_less()); + m_neighbors.back() = std::make_pair(value_distance, value_ptr); + std::push_heap(m_neighbors.begin(), m_neighbors.end(), pair_first_less()); + } + } + + std::size_t max_count() const + { + return nearest_predicate_access::get(m_pred).count; } nearest_predicate_type const& predicate() const @@ -288,24 +318,18 @@ private: return nearest_predicate_access::get(m_pred); } - parameters_type const& m_parameters; - translator_type const& m_translator; - - Predicates m_pred; - distance_query_result m_result; - + translator_type const& m_tr; strategy_type m_strategy; + + Predicates const& m_pred; + + branches_type m_branches; + neighbors_type m_neighbors; }; -template < - typename MembersHolder, - typename Predicates, - std::size_t DistancePredicateIndex -> +template class distance_query_incremental - : public MembersHolder::visitor_const { -public: typedef typename MembersHolder::value_type value_type; typedef typename MembersHolder::box_type box_type; typedef typename MembersHolder::parameters_type parameters_type; @@ -318,7 +342,10 @@ public: typedef typename MembersHolder::internal_node internal_node; typedef typename MembersHolder::leaf leaf; - typedef index::detail::predicates_element nearest_predicate_access; + typedef index::detail::predicates_element + < + index::detail::predicates_find_distance::value, Predicates + > nearest_predicate_access; typedef typename nearest_predicate_access::type nearest_predicate_type; typedef typename indexable_type::type indexable_type; @@ -331,90 +358,114 @@ public: typedef typename allocators_type::const_reference const_reference; typedef typename allocators_type::node_pointer node_pointer; - static const std::size_t predicates_len = index::detail::predicates_length::value; - typedef typename rtree::elements_type::type internal_elements; typedef typename internal_elements::const_iterator internal_iterator; typedef typename rtree::elements_type::type leaf_elements; - typedef std::pair branch_data; - typedef std::vector internal_heap_type; + using neighbor_data = std::pair; + using neighbors_type = priority_dequeue; + struct branch_data + { + branch_data(node_distance_type d, size_type rl, node_pointer p) + : distance(d), reverse_level(rl), ptr(p) + {} + + node_distance_type distance; + size_type reverse_level; + node_pointer ptr; + }; + using branches_type = priority_queue; + +public: inline distance_query_incremental() - : m_translator(NULL) + : m_tr(nullptr) +// , m_strategy() // , m_pred() - , current_neighbor((std::numeric_limits::max)()) -// , m_strategy_type() + , m_neighbors_count(0) + , m_neighbor_ptr(nullptr) {} - inline distance_query_incremental(parameters_type const& params, translator_type const& translator, Predicates const& pred) - : m_translator(::boost::addressof(translator)) + inline distance_query_incremental(Predicates const& pred) + : m_tr(nullptr) +// , m_strategy() , m_pred(pred) - , current_neighbor((std::numeric_limits::max)()) - , m_strategy(index::detail::get_strategy(params)) - { - BOOST_GEOMETRY_INDEX_ASSERT(0 < max_count(), "k must be greather than 0"); - } + , m_neighbors_count(0) + , m_neighbor_ptr(nullptr) + {} + + inline distance_query_incremental(MembersHolder const& members, Predicates const& pred) + : m_tr(::boost::addressof(members.translator())) + , m_strategy(index::detail::get_strategy(members.parameters())) + , m_pred(pred) + , m_neighbors_count(0) + , m_neighbor_ptr(nullptr) + {} const_reference dereference() const { - return *(neighbors[current_neighbor].second); + return *m_neighbor_ptr; } - void initialize(node_pointer root) + void initialize(MembersHolder const& members) { - rtree::apply_visitor(*this, *root); - increment(); + if (0 < max_count()) + { + apply(members.root, members.leafs_level); + increment(); + } } void increment() { for (;;) { - size_type new_neighbor = current_neighbor == (std::numeric_limits::max)() ? 0 : current_neighbor + 1; - - if ( internal_heap.empty() ) + if (m_branches.empty()) { - if ( new_neighbor < neighbors.size() ) - current_neighbor = new_neighbor; + // there exists a next closest neighbor so we can increment + if (! m_neighbors.empty()) + { + m_neighbor_ptr = m_neighbors.top().second; + ++m_neighbors_count; + m_neighbors.pop_top(); + } else { - current_neighbor = (std::numeric_limits::max)(); - // clear() is used to disable the condition above - neighbors.clear(); + // there aren't any neighbors left, end + m_neighbor_ptr = nullptr; + m_neighbors_count = max_count(); } return; } else { - branch_data const& closest_branch = internal_heap.front(); - node_distance_type const& closest_distance = closest_branch.first; + branch_data const& closest_branch = m_branches.top(); - // if there are no nodes which can have closer values, set new value - if ( new_neighbor < neighbors.size() && - // NOTE: In order to use <= current neighbor can't be sorted again - neighbors[new_neighbor].first <= closest_distance ) + // if next neighbor is closer or as close as the closest branch, set next neighbor + if (! m_neighbors.empty() && m_neighbors.top().first <= closest_branch.distance ) { - current_neighbor = new_neighbor; + m_neighbor_ptr = m_neighbors.top().second; + ++m_neighbors_count; + m_neighbors.pop_top(); return; } - // if node is further than the furthest neighbor, following nodes will also be further - BOOST_GEOMETRY_INDEX_ASSERT(neighbors.size() <= max_count(), "unexpected neighbors count"); - if ( max_count() <= neighbors.size() && - neighbors.back().first <= closest_distance ) + BOOST_GEOMETRY_INDEX_ASSERT(m_neighbors_count + m_neighbors.size() <= max_count(), "unexpected neighbors count"); + + // if there is enough neighbors and there is no closer branch + if (ignore_branch_or_value(closest_branch.distance)) { - internal_heap.clear(); + m_branches.clear(); continue; } else { - node_pointer ptr = closest_branch.second; - std::pop_heap(internal_heap.begin(), internal_heap.end(), pair_first_greater()); - internal_heap.pop_back(); + node_pointer ptr = closest_branch.ptr; + size_type reverse_level = closest_branch.reverse_level; + m_branches.pop(); - rtree::apply_visitor(*this, *ptr); + apply(ptr, reverse_level); } } } @@ -422,112 +473,80 @@ public: bool is_end() const { - return (std::numeric_limits::max)() == current_neighbor; + return m_neighbor_ptr == nullptr; } friend bool operator==(distance_query_incremental const& l, distance_query_incremental const& r) { - BOOST_GEOMETRY_INDEX_ASSERT(l.current_neighbor != r.current_neighbor || - (std::numeric_limits::max)() == l.current_neighbor || - (std::numeric_limits::max)() == r.current_neighbor || - l.neighbors[l.current_neighbor].second == r.neighbors[r.current_neighbor].second, - "not corresponding iterators"); - return l.current_neighbor == r.current_neighbor; + return l.m_neighbors_count == r.m_neighbors_count; } - // Put node's elements into the list of active branches if those elements meets predicates - // and distance predicates(currently not used) - // and aren't further than found neighbours (if there is enough neighbours) - inline void operator()(internal_node const& n) +private: + void apply(node_pointer ptr, size_type reverse_level) { - typedef typename rtree::elements_type::type elements_type; - elements_type const& elements = rtree::elements(n); - - // fill active branch list array of nodes meeting predicates - for ( typename elements_type::const_iterator it = elements.begin() ; it != elements.end() ; ++it ) + namespace id = index::detail; + // Put node's elements into the list of active branches if those elements meets predicates + // and distance predicates(currently not used) + // and aren't further than found neighbours (if there is enough neighbours) + if (reverse_level > 0) { - // if current node meets predicates - // 0 - dummy value - if ( index::detail::predicates_check - < - index::detail::bounds_tag, 0, predicates_len - >(m_pred, 0, it->first, m_strategy) ) + internal_node& n = rtree::get(*ptr); + // fill active branch list array of nodes meeting predicates + for (auto const& p : rtree::elements(n)) { - // calculate node's distance(s) for distance predicate - node_distance_type node_distance; - // if distance isn't ok - move to the next node - if ( !calculate_node_distance::apply(predicate(), it->first, - m_strategy, node_distance) ) - { - continue; - } + node_distance_type node_distance; // for distance predicate - // if current node is further than found neighbors - don't analyze it - if ( max_count() <= neighbors.size() && - neighbors.back().first <= node_distance ) + // if current node meets predicates (0 is dummy value) + if (id::predicates_check(m_pred, 0, p.first, m_strategy) + // and if distance is ok + && calculate_node_distance::apply(predicate(), p.first, m_strategy, node_distance) + // and if current node is closer than the furthest neighbor + && ! ignore_branch_or_value(node_distance)) { - continue; + // add current node into the queue + m_branches.push(branch_data(node_distance, reverse_level - 1, p.second)); } - - // add current node's data into the queue - internal_heap.push_back(std::make_pair(node_distance, it->second)); - std::push_heap(internal_heap.begin(), internal_heap.end(), pair_first_greater()); } } - } - - // Put values into the list of neighbours if those values meets predicates - // and distance predicates(currently not used) - // and aren't further than already found neighbours (if there is enough neighbours) - inline void operator()(leaf const& n) - { - typedef typename rtree::elements_type::type elements_type; - elements_type const& elements = rtree::elements(n); - - // store distance to the furthest neighbour - bool not_enough_neighbors = neighbors.size() < max_count(); - value_distance_type greatest_distance = !not_enough_neighbors ? neighbors.back().first : (std::numeric_limits::max)(); - - // search leaf for closest value meeting predicates - for ( typename elements_type::const_iterator it = elements.begin() ; it != elements.end() ; ++it) + // Put values into the list of neighbours if those values meets predicates + // and distance predicates(currently not used) + // and aren't further than already found neighbours (if there is enough neighbours) + else { - // if value meets predicates - if ( index::detail::predicates_check - < - index::detail::value_tag, 0, predicates_len - >(m_pred, *it, (*m_translator)(*it), m_strategy) ) + leaf& n = rtree::get(*ptr); + // search leaf for closest value meeting predicates + for (auto const& v : rtree::elements(n)) { - // calculate values distance for distance predicate - value_distance_type value_distance; - // if distance is ok - if ( calculate_value_distance::apply(predicate(), (*m_translator)(*it), - m_strategy, value_distance) ) + value_distance_type value_distance; // for distance predicate + + // if value meets predicates + if (id::predicates_check(m_pred, v, (*m_tr)(v), m_strategy) + // and if distance is ok + && calculate_value_distance::apply(predicate(), (*m_tr)(v), m_strategy, value_distance) + // and if current value is closer than the furthest neighbor + && ! ignore_branch_or_value(value_distance)) { - // if there is not enough values or current value is closer than furthest neighbour - if ( not_enough_neighbors || value_distance < greatest_distance ) + // add current value into the queue + m_neighbors.push(std::make_pair(value_distance, boost::addressof(v))); + + // remove unneeded value + if (m_neighbors_count + m_neighbors.size() > max_count()) { - neighbors.push_back(std::make_pair(value_distance, boost::addressof(*it))); + m_neighbors.pop_bottom(); } } } } - - // TODO: sort is probably suboptimal. - // An alternative would be std::set, but it'd probably add constant cost. - // Ideally replace this with double-ended priority queue, e.g. min-max heap. - // NOTE: A condition in increment() relies on the fact that current neighbor doesn't - // participate in sorting anymore. - - // sort array - size_type sort_first = current_neighbor == (std::numeric_limits::max)() ? 0 : current_neighbor + 1; - std::sort(neighbors.begin() + sort_first, neighbors.end(), pair_first_less()); - // remove furthest values - if ( max_count() < neighbors.size() ) - neighbors.resize(max_count()); } -private: - inline std::size_t max_count() const + template + bool ignore_branch_or_value(Distance const& distance) + { + return m_neighbors_count + m_neighbors.size() == max_count() + && (m_neighbors.empty() || m_neighbors.bottom().first <= distance); + } + + std::size_t max_count() const { return nearest_predicate_access::get(m_pred).count; } @@ -537,15 +556,15 @@ private: return nearest_predicate_access::get(m_pred); } - const translator_type * m_translator; + const translator_type * m_tr; + strategy_type m_strategy; Predicates m_pred; - internal_heap_type internal_heap; - std::vector< std::pair > neighbors; - size_type current_neighbor; - - strategy_type m_strategy; + branches_type m_branches; + neighbors_type m_neighbors; + size_type m_neighbors_count; + const value_type * m_neighbor_ptr; }; }}} // namespace detail::rtree::visitors diff --git a/include/boost/geometry/index/detail/rtree/visitors/insert.hpp b/include/boost/geometry/index/detail/rtree/visitors/insert.hpp index 8b32c8176..5d158bc7d 100644 --- a/include/boost/geometry/index/detail/rtree/visitors/insert.hpp +++ b/include/boost/geometry/index/detail/rtree/visitors/insert.hpp @@ -4,8 +4,8 @@ // // Copyright (c) 2011-2015 Adam Wulkiewicz, Lodz, Poland. // -// This file was modified by Oracle on 2019-2020. -// Modifications copyright (c) 2019-2020 Oracle and/or its affiliates. +// This file was modified by Oracle on 2019-2021. +// Modifications copyright (c) 2019-2021 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // // Use, modification and distribution is subject to the Boost Software License, @@ -21,12 +21,14 @@ #include #include -#include #include #include - +#include #include +#include + +#include namespace boost { namespace geometry { namespace index { diff --git a/include/boost/geometry/index/detail/rtree/visitors/iterator.hpp b/include/boost/geometry/index/detail/rtree/visitors/iterator.hpp index 621231ae9..71127dcbe 100644 --- a/include/boost/geometry/index/detail/rtree/visitors/iterator.hpp +++ b/include/boost/geometry/index/detail/rtree/visitors/iterator.hpp @@ -4,6 +4,10 @@ // // Copyright (c) 2011-2015 Adam Wulkiewicz, Lodz, Poland. // +// This file was modified by Oracle on 2021. +// Modifications copyright (c) 2021 Oracle and/or its affiliates. +// Contributed and/or modified by Adam Wulkiewicz, 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) @@ -11,6 +15,9 @@ #ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_ITERATOR_HPP #define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_ITERATOR_HPP +#include +#include + namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace visitors { diff --git a/include/boost/geometry/index/detail/rtree/visitors/remove.hpp b/include/boost/geometry/index/detail/rtree/visitors/remove.hpp index 59f486163..7cdbb0344 100644 --- a/include/boost/geometry/index/detail/rtree/visitors/remove.hpp +++ b/include/boost/geometry/index/detail/rtree/visitors/remove.hpp @@ -4,8 +4,8 @@ // // Copyright (c) 2011-2017 Adam Wulkiewicz, Lodz, Poland. // -// This file was modified by Oracle on 2019. -// Modifications copyright (c) 2019 Oracle and/or its affiliates. +// This file was modified by Oracle on 2019-2021. +// Modifications copyright (c) 2019-2021 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // // Use, modification and distribution is subject to the Boost Software License, @@ -15,11 +15,13 @@ #ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_REMOVE_HPP #define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_REMOVE_HPP +#include + +#include +#include #include #include -#include - namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace visitors { diff --git a/include/boost/geometry/index/detail/rtree/visitors/spatial_query.hpp b/include/boost/geometry/index/detail/rtree/visitors/spatial_query.hpp index f0d30162c..48ada100b 100644 --- a/include/boost/geometry/index/detail/rtree/visitors/spatial_query.hpp +++ b/include/boost/geometry/index/detail/rtree/visitors/spatial_query.hpp @@ -15,13 +15,16 @@ #ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_SPATIAL_QUERY_HPP #define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_SPATIAL_QUERY_HPP +#include +#include +#include + namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace visitors { template struct spatial_query - : public MembersHolder::visitor_const { typedef typename MembersHolder::parameters_type parameters_type; typedef typename MembersHolder::translator_type translator_type; @@ -33,71 +36,69 @@ struct spatial_query typedef typename MembersHolder::internal_node internal_node; typedef typename MembersHolder::leaf leaf; + typedef typename allocators_type::node_pointer node_pointer; typedef typename allocators_type::size_type size_type; - static const std::size_t predicates_len = index::detail::predicates_length::value; - - inline spatial_query(parameters_type const& par, translator_type const& t, Predicates const& p, OutIter out_it) - : tr(t), pred(p), out_iter(out_it), found_count(0), strategy(index::detail::get_strategy(par)) + spatial_query(MembersHolder const& members, Predicates const& p, OutIter out_it) + : m_tr(members.translator()) + , m_strategy(index::detail::get_strategy(members.parameters())) + , m_pred(p) + , m_out_iter(out_it) + , m_found_count(0) {} - inline void operator()(internal_node const& n) + size_type apply(node_pointer ptr, size_type reverse_level) { - typedef typename rtree::elements_type::type elements_type; - elements_type const& elements = rtree::elements(n); - - // traverse nodes meeting predicates - for (typename elements_type::const_iterator it = elements.begin(); - it != elements.end(); ++it) + namespace id = index::detail; + if (reverse_level > 0) { - // if node meets predicates - // 0 - dummy value - if ( index::detail::predicates_check - < - index::detail::bounds_tag, 0, predicates_len - >(pred, 0, it->first, strategy) ) + internal_node& n = rtree::get(*ptr); + // traverse nodes meeting predicates + for (auto const& p : rtree::elements(n)) { - rtree::apply_visitor(*this, *it->second); + // if node meets predicates (0 is dummy value) + if (id::predicates_check(m_pred, 0, p.first, m_strategy)) + { + apply(p.second, reverse_level - 1); + } } } - } - - inline void operator()(leaf const& n) - { - typedef typename rtree::elements_type::type elements_type; - elements_type const& elements = rtree::elements(n); - - // get all values meeting predicates - for (typename elements_type::const_iterator it = elements.begin(); - it != elements.end(); ++it) + else { - // if value meets predicates - if ( index::detail::predicates_check - < - index::detail::value_tag, 0, predicates_len - >(pred, *it, tr(*it), strategy) ) + leaf& n = rtree::get(*ptr); + // get all values meeting predicates + for (auto const& v : rtree::elements(n)) { - *out_iter = *it; - ++out_iter; - - ++found_count; + // if value meets predicates + if (id::predicates_check(m_pred, v, m_tr(v), m_strategy)) + { + *m_out_iter = v; + ++m_out_iter; + ++m_found_count; + } } } + + return m_found_count; } - translator_type const& tr; + size_type apply(MembersHolder const& members) + { + return apply(members.root, members.leafs_level); + } - Predicates pred; +private: + translator_type const& m_tr; + strategy_type m_strategy; - OutIter out_iter; - size_type found_count; + Predicates const& m_pred; + OutIter m_out_iter; - strategy_type strategy; + size_type m_found_count; }; template class spatial_query_incremental - : public MembersHolder::visitor_const { typedef typename MembersHolder::value_type value_type; typedef typename MembersHolder::parameters_type parameters_type; @@ -106,7 +107,6 @@ class spatial_query_incremental typedef typename index::detail::strategy_type::type strategy_type; -public: typedef typename MembersHolder::node node; typedef typename MembersHolder::internal_node internal_node; typedef typename MembersHolder::leaf leaf; @@ -119,37 +119,40 @@ public: typedef typename rtree::elements_type::type leaf_elements; typedef typename rtree::elements_type::type::const_iterator leaf_iterator; - static const std::size_t predicates_len = index::detail::predicates_length::value; + struct internal_data + { + internal_data(internal_iterator f, internal_iterator l, size_type rl) + : first(f), last(l), reverse_level(rl) + {} + internal_iterator first; + internal_iterator last; + size_type reverse_level; + }; - inline spatial_query_incremental() - : m_translator(NULL) -// , m_pred() - , m_values(NULL) - , m_current() +public: + spatial_query_incremental() + : m_translator(nullptr) // , m_strategy() - {} - - inline spatial_query_incremental(parameters_type const& params, translator_type const& t, Predicates const& p) - : m_translator(::boost::addressof(t)) - , m_pred(p) - , m_values(NULL) +// , m_pred() + , m_values(nullptr) , m_current() - , m_strategy(index::detail::get_strategy(params)) {} - inline void operator()(internal_node const& n) - { - typedef typename rtree::elements_type::type elements_type; - elements_type const& elements = rtree::elements(n); + spatial_query_incremental(Predicates const& p) + : m_translator(nullptr) +// , m_strategy() + , m_pred(p) + , m_values(nullptr) + , m_current() + {} - m_internal_stack.push_back(std::make_pair(elements.begin(), elements.end())); - } - - inline void operator()(leaf const& n) - { - m_values = ::boost::addressof(rtree::elements(n)); - m_current = rtree::elements(n).begin(); - } + spatial_query_incremental(MembersHolder const& members, Predicates const& p) + : m_translator(::boost::addressof(members.translator())) + , m_strategy(index::detail::get_strategy(members.parameters())) + , m_pred(p) + , m_values(nullptr) + , m_current() + {} const_reference dereference() const { @@ -157,9 +160,9 @@ public: return *m_current; } - void initialize(node_pointer root) + void initialize(MembersHolder const& members) { - rtree::apply_visitor(*this, *root); + apply(members.root, members.leafs_level); search_value(); } @@ -169,8 +172,38 @@ public: search_value(); } + bool is_end() const + { + return 0 == m_values; + } + + friend bool operator==(spatial_query_incremental const& l, spatial_query_incremental const& r) + { + return (l.m_values == r.m_values) && (0 == l.m_values || l.m_current == r.m_current); + } + +private: + void apply(node_pointer ptr, size_type reverse_level) + { + namespace id = index::detail; + + if (reverse_level > 0) + { + internal_node& n = rtree::get(*ptr); + auto const& elements = rtree::elements(n); + m_internal_stack.push_back(internal_data(elements.begin(), elements.end(), reverse_level - 1)); + } + else + { + leaf& n = rtree::get(*ptr); + m_values = ::boost::addressof(rtree::elements(n)); + m_current = rtree::elements(n).begin(); + } + } + void search_value() { + namespace id = index::detail; for (;;) { // if leaf is choosen, move to the next value in leaf @@ -180,10 +213,7 @@ public: { // return if next value is found value_type const& v = *m_current; - if (index::detail::predicates_check - < - index::detail::value_tag, 0, predicates_len - >(m_pred, v, (*m_translator)(v), m_strategy)) + if (id::predicates_check(m_pred, v, (*m_translator)(v), m_strategy)) { return; } @@ -200,52 +230,40 @@ public: else { // return if there is no more nodes to traverse - if ( m_internal_stack.empty() ) + if (m_internal_stack.empty()) + { return; + } - // no more children in current node, remove it from stack - if ( m_internal_stack.back().first == m_internal_stack.back().second ) + internal_data& current_data = m_internal_stack.back(); + + // no more children in current node, remove it from stack + if (current_data.first == current_data.last) { m_internal_stack.pop_back(); continue; } - internal_iterator it = m_internal_stack.back().first; - ++m_internal_stack.back().first; + internal_iterator it = current_data.first; + ++current_data.first; // next node is found, push it to the stack - if (index::detail::predicates_check - < - index::detail::bounds_tag, 0, predicates_len - >(m_pred, 0, it->first, m_strategy)) + if (id::predicates_check(m_pred, 0, it->first, m_strategy)) { - rtree::apply_visitor(*this, *(it->second)); + apply(it->second, current_data.reverse_level); } } } } - - bool is_end() const - { - return 0 == m_values; - } - - friend bool operator==(spatial_query_incremental const& l, spatial_query_incremental const& r) - { - return (l.m_values == r.m_values) && (0 == l.m_values || l.m_current == r.m_current ); - } - -private: - + const translator_type * m_translator; + strategy_type m_strategy; Predicates m_pred; - std::vector< std::pair > m_internal_stack; + std::vector m_internal_stack; const leaf_elements * m_values; leaf_iterator m_current; - - strategy_type m_strategy; }; }}} // namespace detail::rtree::visitors diff --git a/include/boost/geometry/index/detail/serialization.hpp b/include/boost/geometry/index/detail/serialization.hpp index 71902d19f..909c38e3c 100644 --- a/include/boost/geometry/index/detail/serialization.hpp +++ b/include/boost/geometry/index/detail/serialization.hpp @@ -2,6 +2,10 @@ // // Copyright (c) 2011-2015 Adam Wulkiewicz, Lodz, Poland. // +// This file was modified by Oracle on 2021. +// Modifications copyright (c) 2021 Oracle and/or its affiliates. +// Contributed and/or modified by Adam Wulkiewicz, 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) @@ -9,11 +13,21 @@ #ifndef BOOST_GEOMETRY_INDEX_DETAIL_SERIALIZATION_HPP #define BOOST_GEOMETRY_INDEX_DETAIL_SERIALIZATION_HPP +#include +#include + //#include #include #include //#include +#include +#include + +#include +#include +#include + // TODO // how about using the unsigned type capable of storing Max in compile-time versions? @@ -26,7 +40,13 @@ // each geometry save without this info // TODO - move to index/detail/serialization.hpp -namespace boost { namespace geometry { namespace index { namespace detail { +namespace boost { namespace geometry { namespace index { + +// Forward declaration +template +class rtree; + +namespace detail { // TODO - use boost::move? template diff --git a/include/boost/geometry/index/detail/translator.hpp b/include/boost/geometry/index/detail/translator.hpp index 34960d226..900be6e73 100644 --- a/include/boost/geometry/index/detail/translator.hpp +++ b/include/boost/geometry/index/detail/translator.hpp @@ -2,8 +2,8 @@ // // Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. // -// This file was modified by Oracle on 2019-2020. -// Modifications copyright (c) 2019-2020 Oracle and/or its affiliates. +// This file was modified by Oracle on 2019-2021. +// Modifications copyright (c) 2019-2021 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // // Use, modification and distribution is subject to the Boost Software License, @@ -15,6 +15,8 @@ #include +#include + namespace boost { namespace geometry { namespace index { namespace detail { diff --git a/include/boost/geometry/index/parameters.hpp b/include/boost/geometry/index/parameters.hpp index fdaef9284..477518866 100644 --- a/include/boost/geometry/index/parameters.hpp +++ b/include/boost/geometry/index/parameters.hpp @@ -4,8 +4,8 @@ // // Copyright (c) 2011-2017 Adam Wulkiewicz, Lodz, Poland. // -// This file was modified by Oracle on 2019-2020. -// Modifications copyright (c) 2019-2020 Oracle and/or its affiliates. +// This file was modified by Oracle on 2019-2021. +// Modifications copyright (c) 2019-2021 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // // Use, modification and distribution is subject to the Boost Software License, @@ -15,13 +15,13 @@ #ifndef BOOST_GEOMETRY_INDEX_PARAMETERS_HPP #define BOOST_GEOMETRY_INDEX_PARAMETERS_HPP - #include #include #include +#include namespace boost { namespace geometry { namespace index { diff --git a/include/boost/geometry/index/rtree.hpp b/include/boost/geometry/index/rtree.hpp index 2b7e3811d..af3b6f4ee 100644 --- a/include/boost/geometry/index/rtree.hpp +++ b/include/boost/geometry/index/rtree.hpp @@ -1079,17 +1079,9 @@ public: template size_type query(Predicates const& predicates, OutIter out_it) const { - if ( !m_members.root ) - return 0; - - static const std::size_t distance_predicates_count = detail::predicates_count_distance::value; - static const bool is_distance_predicate = 0 < distance_predicates_count; - BOOST_GEOMETRY_STATIC_ASSERT((distance_predicates_count <= 1), - "Only one distance predicate can be passed.", - Predicates); - - return query_dispatch(predicates, out_it, - std::integral_constant()); + return m_members.root + ? query_dispatch(predicates, out_it) + : 0; } /*! @@ -1183,6 +1175,15 @@ public: return const_query_iterator(); } +private: + template + using query_iterator_t = std::conditional_t + < + detail::predicates_count_distance::value == 0, + detail::rtree::iterators::spatial_query_iterator, + detail::rtree::iterators::distance_query_iterator + >; + #ifndef BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL private: #endif @@ -1240,38 +1241,15 @@ private: \return The iterator pointing at the begin of the query range. */ template - std::conditional_t - < - detail::predicates_count_distance::value == 0, - detail::rtree::iterators::spatial_query_iterator, - detail::rtree::iterators::distance_query_iterator - < - members_holder, Predicates, - detail::predicates_find_distance::value - > - > - qbegin_(Predicates const& predicates) const + query_iterator_t qbegin_(Predicates const& predicates) const { - static const std::size_t distance_predicates_count = detail::predicates_count_distance::value; - BOOST_GEOMETRY_STATIC_ASSERT((distance_predicates_count <= 1), + BOOST_GEOMETRY_STATIC_ASSERT((detail::predicates_count_distance::value <= 1), "Only one distance predicate can be passed.", Predicates); - typedef std::conditional_t - < - detail::predicates_count_distance::value == 0, - detail::rtree::iterators::spatial_query_iterator, - detail::rtree::iterators::distance_query_iterator - < - members_holder, Predicates, - detail::predicates_find_distance::value - > - > iterator_type; - - if ( !m_members.root ) - return iterator_type(m_members.parameters(), m_members.translator(), predicates); - - return iterator_type(m_members.root, m_members.parameters(), m_members.translator(), predicates); + return m_members.root + ? query_iterator_t(m_members, predicates) + : query_iterator_t(predicates); } /*! @@ -1307,35 +1285,13 @@ private: \return The iterator pointing at the end of the query range. */ template - std::conditional_t - < - detail::predicates_count_distance::value == 0, - detail::rtree::iterators::spatial_query_iterator, - detail::rtree::iterators::distance_query_iterator - < - members_holder, Predicates, - detail::predicates_find_distance::value - > - > - qend_(Predicates const& predicates) const + query_iterator_t qend_(Predicates const& predicates) const { - static const std::size_t distance_predicates_count = detail::predicates_count_distance::value; - BOOST_GEOMETRY_STATIC_ASSERT((distance_predicates_count <= 1), + BOOST_GEOMETRY_STATIC_ASSERT((detail::predicates_count_distance::value <= 1), "Only one distance predicate can be passed.", Predicates); - typedef std::conditional_t - < - detail::predicates_count_distance::value == 0, - detail::rtree::iterators::spatial_query_iterator, - detail::rtree::iterators::distance_query_iterator - < - members_holder, Predicates, - detail::predicates_find_distance::value - > - > iterator_type; - - return iterator_type(m_members.parameters(), m_members.translator(), predicates); + return query_iterator_t(m_members.parameters(), m_members.translator(), predicates); } /*! @@ -1436,10 +1392,9 @@ public: */ const_iterator begin() const { - if ( !m_members.root ) - return const_iterator(); - - return const_iterator(m_members.root); + return m_members.root + ? const_iterator(m_members.root) + : const_iterator(); } /*! @@ -1894,15 +1849,16 @@ private: \par Exception-safety strong */ - template - size_type query_dispatch(Predicates const& predicates, OutIter out_it, std::false_type /*is_distance_predicate*/) const + template + < + typename Predicates, typename OutIter, + std::enable_if_t<(detail::predicates_count_distance::value == 0), int> = 0 + > + size_type query_dispatch(Predicates const& predicates, OutIter out_it) const { detail::rtree::visitors::spatial_query - find_v(m_members.parameters(), m_members.translator(), predicates, out_it); - - detail::rtree::apply_visitor(find_v, *m_members.root); - - return find_v.found_count; + query(m_members, predicates, out_it); + return query.apply(m_members); } /*! @@ -1911,22 +1867,21 @@ private: \par Exception-safety strong */ - template - size_type query_dispatch(Predicates const& predicates, OutIter out_it, std::true_type /*is_distance_predicate*/) const + template + < + typename Predicates, typename OutIter, + std::enable_if_t<(detail::predicates_count_distance::value > 0), int> = 0 + > + size_type query_dispatch(Predicates const& predicates, OutIter out_it) const { - BOOST_GEOMETRY_INDEX_ASSERT(m_members.root, "The root must exist"); + BOOST_GEOMETRY_STATIC_ASSERT((detail::predicates_count_distance::value == 1), + "Only one distance predicate can be passed.", + Predicates); - static const std::size_t distance_predicate_index = detail::predicates_find_distance::value; - detail::rtree::visitors::distance_query< - members_holder, - Predicates, - distance_predicate_index, - OutIter - > distance_v(m_members.parameters(), m_members.translator(), predicates, out_it); + detail::rtree::visitors::distance_query + distance_v(m_members, predicates); - detail::rtree::apply_visitor(distance_v, *m_members.root); - - return distance_v.finish(); + return distance_v.apply(m_members, out_it); } /*! diff --git a/include/boost/geometry/io/wkt/write.hpp b/include/boost/geometry/io/wkt/write.hpp index aa52d072f..73b374c9e 100644 --- a/include/boost/geometry/io/wkt/write.hpp +++ b/include/boost/geometry/io/wkt/write.hpp @@ -478,9 +478,10 @@ struct wkt static inline void apply(OutputStream& os, Geometry const& geometry, bool force_closure) { - output_or_recursive_call(os, geometry, force_closure); + wkt::output_or_recursive_call(os, geometry, force_closure); } +private: template < typename OutputStream, typename Geom, @@ -501,7 +502,7 @@ struct wkt traits::iter_visit::apply([&](auto const& g) { - output_or_recursive_call(os, g, force_closure); + wkt::output_or_recursive_call(os, g, force_closure); }, it); } diff --git a/include/boost/geometry/policies/robustness/get_rescale_policy.hpp b/include/boost/geometry/policies/robustness/get_rescale_policy.hpp index 66f949fe4..5e1dd5e4d 100644 --- a/include/boost/geometry/policies/robustness/get_rescale_policy.hpp +++ b/include/boost/geometry/policies/robustness/get_rescale_policy.hpp @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -37,7 +38,6 @@ #include #include #include -#include #include // TEMP diff --git a/include/boost/geometry/policies/robustness/segment_ratio.hpp b/include/boost/geometry/policies/robustness/segment_ratio.hpp index 07c74cc43..6d50a5b89 100644 --- a/include/boost/geometry/policies/robustness/segment_ratio.hpp +++ b/include/boost/geometry/policies/robustness/segment_ratio.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2013 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2016-2020. -// Modifications copyright (c) 2016-2020 Oracle and/or its affiliates. +// This file was modified by Oracle on 2016-2021. +// Modifications copyright (c) 2016-2021 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, @@ -19,8 +19,8 @@ #include #include +#include #include -#include namespace boost { namespace geometry { @@ -53,8 +53,8 @@ struct less template static inline bool apply(Ratio const& lhs, Ratio const& rhs) { - BOOST_GEOMETRY_ASSERT(lhs.denominator() != 0); - BOOST_GEOMETRY_ASSERT(rhs.denominator() != 0); + BOOST_GEOMETRY_ASSERT(lhs.denominator() != Type(0)); + BOOST_GEOMETRY_ASSERT(rhs.denominator() != Type(0)); Type const a = lhs.numerator() / lhs.denominator(); Type const b = rhs.numerator() / rhs.denominator(); return ! geometry::math::equals(a, b) @@ -86,8 +86,8 @@ struct equal template static inline bool apply(Ratio const& lhs, Ratio const& rhs) { - BOOST_GEOMETRY_ASSERT(lhs.denominator() != 0); - BOOST_GEOMETRY_ASSERT(rhs.denominator() != 0); + BOOST_GEOMETRY_ASSERT(lhs.denominator() != Type(0)); + BOOST_GEOMETRY_ASSERT(rhs.denominator() != Type(0)); Type const a = lhs.numerator() / lhs.denominator(); Type const b = rhs.numerator() / rhs.denominator(); return geometry::math::equals(a, b); @@ -119,7 +119,8 @@ struct possibly_collinear template static inline bool apply(Ratio const& ratio, Threshold) { - return ratio.denominator() == 0; + static Type const zero = 0; + return ratio.denominator() == zero; } }; @@ -135,11 +136,16 @@ struct possibly_collinear template class segment_ratio { -public : - typedef Type numeric_type; + // Type used for the approximation (a helper value) + // and for the edge value (0..1) (a helper function). + using floating_point_type = + typename detail::promoted_to_floating_point::type; // Type-alias for the type itself - typedef segment_ratio thistype; + using thistype = segment_ratio; + +public: + using int_type = Type; inline segment_ratio() : m_numerator(0) @@ -212,31 +218,31 @@ public : { // Minimal normalization // 1/-4 => -1/4, -1/-4 => 1/4 - if (m_denominator < 0) + if (m_denominator < zero_instance()) { m_numerator = -m_numerator; m_denominator = -m_denominator; } m_approximation = - m_denominator == 0 ? 0 + m_denominator == zero_instance() ? 0 : ( - boost::numeric_cast(m_numerator) * scale() - / boost::numeric_cast(m_denominator) + boost::numeric_cast(m_numerator) * scale() + / boost::numeric_cast(m_denominator) ); } - inline bool is_zero() const { return math::equals(m_numerator, 0); } + inline bool is_zero() const { return math::equals(m_numerator, Type(0)); } inline bool is_one() const { return math::equals(m_numerator, m_denominator); } inline bool on_segment() const { // e.g. 0/4 or 4/4 or 2/4 - return m_numerator >= 0 && m_numerator <= m_denominator; + return m_numerator >= zero_instance() && m_numerator <= m_denominator; } inline bool in_segment() const { // e.g. 1/4 - return m_numerator > 0 && m_numerator < m_denominator; + return m_numerator > zero_instance() && m_numerator < m_denominator; } inline bool on_end() const { @@ -246,7 +252,7 @@ public : inline bool left() const { // e.g. -1/4 - return m_numerator < 0; + return m_numerator < zero_instance(); } inline bool right() const { @@ -254,21 +260,16 @@ public : return m_numerator > m_denominator; } - inline bool near_end() const + //! Returns a value between 0.0 and 1.0 + //! 0.0 means: exactly in the middle + //! 1.0 means: exactly on one of the edges (or even over it) + inline floating_point_type edge_value() const { - if (left() || right()) - { - return false; - } - - static fp_type const small_part_of_scale = scale() / 100; - return m_approximation < small_part_of_scale - || m_approximation > scale() - small_part_of_scale; - } - - inline bool close_to(thistype const& other) const - { - return geometry::math::abs(m_approximation - other.m_approximation) < 50; + using fp = floating_point_type; + fp const one{1.0}; + floating_point_type const result + = fp(2) * geometry::math::abs(fp(0.5) - m_approximation / scale()); + return result > one ? one : result; } template @@ -313,19 +314,7 @@ public : } #endif - - private : - // NOTE: if this typedef is used then fp_type is non-fundamental type - // if Type is non-fundamental type - //typedef typename promote_floating_point::type fp_type; - - // TODO: What with user-defined numeric types? - // Shouldn't here is_integral be checked? - typedef std::conditional_t - < - std::is_floating_point::value, Type, double - > fp_type; Type m_numerator; Type m_denominator; @@ -335,12 +324,24 @@ private : // Boost.Rational is used if the approximations are close. // Reason: performance, Boost.Rational does a GCD by default and also the // comparisons contain while-loops. - fp_type m_approximation; + floating_point_type m_approximation; - - static inline fp_type scale() + inline bool close_to(thistype const& other) const { - return 1000000.0; + static floating_point_type const threshold{50.0}; + return geometry::math::abs(m_approximation - other.m_approximation) + < threshold; + } + + static inline floating_point_type scale() + { + static floating_point_type const fp_scale{1000000.0}; + return fp_scale; + } + + static inline Type zero_instance() + { + return 0; } }; diff --git a/include/boost/geometry/strategies/agnostic/point_in_box_by_side.hpp b/include/boost/geometry/strategies/agnostic/point_in_box_by_side.hpp index 5ea58736e..448ae4393 100644 --- a/include/boost/geometry/strategies/agnostic/point_in_box_by_side.hpp +++ b/include/boost/geometry/strategies/agnostic/point_in_box_by_side.hpp @@ -20,12 +20,16 @@ #include #include + #include #include + #include + +#include + #include #include -#include #include #include @@ -114,11 +118,14 @@ struct cartesian_point_box_by_side template static inline bool apply(Point const& point, Box const& box) { + using side_strategy_type + = typename strategy::side::services::default_strategy + ::type; + return within::detail::point_in_box_by_side < within::detail::decide_within - >(point, box, - strategy::side::side_by_triangle()); + >(point, box, side_strategy_type()); } }; @@ -185,11 +192,13 @@ struct cartesian_point_box_by_side template static bool apply(Point const& point, Box const& box) { + using side_strategy_type + = typename strategy::side::services::default_strategy + ::type; return within::detail::point_in_box_by_side < within::detail::decide_covered_by - >(point, box, - strategy::side::side_by_triangle()); + >(point, box, side_strategy_type()); } }; diff --git a/include/boost/geometry/strategies/area/geographic.hpp b/include/boost/geometry/strategies/area/geographic.hpp index 342ba45f3..a8d806c39 100644 --- a/include/boost/geometry/strategies/area/geographic.hpp +++ b/include/boost/geometry/strategies/area/geographic.hpp @@ -86,8 +86,11 @@ struct strategy_converter > : strategies::area::geographic(spheroid) {} + using strategies::area::geographic::area; + template - auto area(Geometry const&) const + auto area(Geometry const&, + std::enable_if_t::value> * = nullptr) const { return strategy::area::geographic(this->m_spheroid); } diff --git a/include/boost/geometry/strategies/cartesian/azimuth.hpp b/include/boost/geometry/strategies/cartesian/azimuth.hpp index 74a9ea12b..9035fdddc 100644 --- a/include/boost/geometry/strategies/cartesian/azimuth.hpp +++ b/include/boost/geometry/strategies/cartesian/azimuth.hpp @@ -14,10 +14,10 @@ #include #include +#include #include -#include #include namespace boost { namespace geometry diff --git a/include/boost/geometry/strategies/cartesian/distance_segment_box.hpp b/include/boost/geometry/strategies/cartesian/distance_segment_box.hpp index c00e426a4..ab3aab726 100644 --- a/include/boost/geometry/strategies/cartesian/distance_segment_box.hpp +++ b/include/boost/geometry/strategies/cartesian/distance_segment_box.hpp @@ -17,7 +17,6 @@ #include #include #include -#include namespace boost { namespace geometry { diff --git a/include/boost/geometry/strategies/cartesian/intersection.hpp b/include/boost/geometry/strategies/cartesian/intersection.hpp index be7b92e59..dbfa08224 100644 --- a/include/boost/geometry/strategies/cartesian/intersection.hpp +++ b/include/boost/geometry/strategies/cartesian/intersection.hpp @@ -44,7 +44,6 @@ #include #include #include -#include #include #include #include @@ -68,6 +67,61 @@ namespace boost { namespace geometry namespace strategy { namespace intersection { +namespace detail_usage +{ + +// When calculating the intersection, the information of "a" or "b" can be used. +// Theoretically this gives equal results, but due to floating point precision +// there might be tiny differences. These are edge cases. +// This structure is to determine if "a" or "b" should be used. +// Prefer the segment closer to the endpoint. +// If both are about equally close, then prefer the longer segment +// To avoid hard thresholds, behavior is made fluent. +// Calculate comparable length indications, +// the longer the segment (relatively), the lower the value +// such that the shorter lengths are evaluated higher and will +// be preferred. +template +struct use_a +{ + template + static bool apply(Ct const& cla, Ct const& clb, Ev const& eva, Ev const& evb) + { + auto const clm = (std::max)(cla, clb); + if (clm <= 0) + { + return true; + } + + // Relative comparible length + auto const rcla = Ct(1.0) - cla / clm; + auto const rclb = Ct(1.0) - clb / clm; + + // Multipliers for edgevalue (ev) and relative comparible length (rcl) + // They determine the balance between edge value (should be larger) + // and segment length. In 99.9xx% of the cases there is no difference + // at all (if either a or b is used). Therefore the values of the + // constants are not sensitive for the majority of the situations. + // One known case is #mysql_23023665_6 (difference) which needs mev >= 2 + Ev const mev = 5; + Ev const mrcl = 1; + + return mev * eva + mrcl * rcla > mev * evb + mrcl * rclb; + } +}; + +// Specialization for non arithmetic types. They will always use "a" +template <> +struct use_a +{ + template + static bool apply(Ct const& , Ct const& , Ev const& , Ev const& ) + { + return true; + } +}; + +} /*! \see http://mathworld.wolfram.com/Line-LineIntersection.html @@ -119,7 +173,7 @@ struct cartesian_segments // Up to now, division was postponed. Here we divide using numerator/ // denominator. In case of integer this results in an integer // division. - BOOST_GEOMETRY_ASSERT(ratio.denominator() != 0); + BOOST_GEOMETRY_ASSERT(ratio.denominator() != typename SegmentRatio::int_type(0)); typedef typename promote_integral::type calc_type; @@ -180,30 +234,12 @@ struct cartesian_segments template void calculate(Point& point, Segment1 const& a, Segment2 const& b) const { - bool use_a = true; - - // Prefer one segment if one is on or near an endpoint - bool const a_near_end = robust_ra.near_end(); - bool const b_near_end = robust_rb.near_end(); - if (a_near_end && ! b_near_end) - { - use_a = true; - } - else if (b_near_end && ! a_near_end) - { - use_a = false; - } - else - { - // Prefer shorter segment - promoted_type const len_a = comparable_length_a(); - promoted_type const len_b = comparable_length_b(); - if (len_b < len_a) - { - use_a = false; - } - // else use_a is true but was already assigned like that - } + bool const use_a + = detail_usage::use_a + < + std::is_arithmetic::value + >::apply(comparable_length_a(), comparable_length_b(), + robust_ra.edge_value(), robust_rb.edge_value()); if (use_a) { @@ -402,7 +438,9 @@ struct cartesian_segments return Policy::disjoint(); } - typedef side::side_by_triangle side_strategy_type; + using side_strategy_type + = typename side::services::default_strategy + ::type; side_info sides; sides.set<0>(side_strategy_type::apply(q1, q2, p1), side_strategy_type::apply(q1, q2, p2)); diff --git a/include/boost/geometry/strategies/cartesian/point_in_poly_winding.hpp b/include/boost/geometry/strategies/cartesian/point_in_poly_winding.hpp index b3556741c..1f989dd43 100644 --- a/include/boost/geometry/strategies/cartesian/point_in_poly_winding.hpp +++ b/include/boost/geometry/strategies/cartesian/point_in_poly_winding.hpp @@ -24,10 +24,10 @@ #include #include +#include #include #include -#include #include #include @@ -116,7 +116,9 @@ public: else // count == 2 || count == -2 { // 1 left, -1 right - typedef side::side_by_triangle side_strategy_type; + using side_strategy_type + = typename side::services::default_strategy + ::type; side = side_strategy_type::apply(s1, s2, point); } diff --git a/include/boost/geometry/strategies/cartesian/side_by_triangle.hpp b/include/boost/geometry/strategies/cartesian/side_by_triangle.hpp index 989f3fbb1..848570fd9 100644 --- a/include/boost/geometry/strategies/cartesian/side_by_triangle.hpp +++ b/include/boost/geometry/strategies/cartesian/side_by_triangle.hpp @@ -1,275 +1,21 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) +// Boost.Geometry -// 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) 2021, Oracle and/or its affiliates. -// This file was modified by Oracle on 2015-2021. -// Modifications copyright (c) 2015-2021, 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. - -// 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) +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html #ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_SIDE_BY_TRIANGLE_HPP #define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_SIDE_BY_TRIANGLE_HPP -#include - -#include - -#include - -#include -#include -#include -#include - -#include - -#include +#include +BOOST_PRAGMA_MESSAGE("This include file is deprecated and will be removed in the future.") -namespace boost { namespace geometry -{ - -namespace strategy { namespace side -{ - -/*! -\brief Check at which side of a segment a point lies: - left of segment (> 0), right of segment (< 0), on segment (0) -\ingroup strategies -\tparam CalculationType \tparam_calculation - */ -template -class side_by_triangle -{ - template - struct eps_policy - { - eps_policy() {} - template - eps_policy(Type const& a, Type const& b, Type const& c, Type const& d) - : policy(a, b, c, d) - {} - Policy policy; - }; - - struct eps_empty - { - eps_empty() {} - template - eps_empty(Type const&, Type const&, Type const&, Type const&) {} - }; - -public : - typedef cartesian_tag cs_tag; - - // Template member function, because it is not always trivial - // or convenient to explicitly mention the typenames in the - // strategy-struct itself. - - // Types can be all three different. Therefore it is - // not implemented (anymore) as "segment" - - template - < - typename CoordinateType, - typename PromotedType, - typename P1, - typename P2, - typename P, - typename EpsPolicy - > - static inline - PromotedType side_value(P1 const& p1, P2 const& p2, P const& p, EpsPolicy & eps_policy) - { - CoordinateType const x = get<0>(p); - CoordinateType const y = get<1>(p); - - CoordinateType const sx1 = get<0>(p1); - CoordinateType const sy1 = get<1>(p1); - CoordinateType const sx2 = get<0>(p2); - CoordinateType const sy2 = get<1>(p2); - - PromotedType const dx = sx2 - sx1; - PromotedType const dy = sy2 - sy1; - PromotedType const dpx = x - sx1; - PromotedType const dpy = y - sy1; - - eps_policy = EpsPolicy(dx, dy, dpx, dpy); - - return geometry::detail::determinant - ( - dx, dy, - dpx, dpy - ); - - } - - template - < - typename CoordinateType, - typename PromotedType, - typename P1, - typename P2, - typename P - > - static inline - PromotedType side_value(P1 const& p1, P2 const& p2, P const& p) - { - eps_empty dummy; - return side_value(p1, p2, p, dummy); - } - - - template - < - typename CoordinateType, - typename PromotedType, - bool AreAllIntegralCoordinates - > - struct compute_side_value - { - template - static inline PromotedType apply(P1 const& p1, P2 const& p2, P const& p, EpsPolicy & epsp) - { - return side_value(p1, p2, p, epsp); - } - }; - - template - struct compute_side_value - { - template - static inline PromotedType apply(P1 const& p1, P2 const& p2, P const& p, EpsPolicy & epsp) - { - // For robustness purposes, first check if any two points are - // the same; in this case simply return that the points are - // collinear - if (equals_point_point(p1, p2) - || equals_point_point(p1, p) - || equals_point_point(p2, p)) - { - return PromotedType(0); - } - - // The side_by_triangle strategy computes the signed area of - // the point triplet (p1, p2, p); as such it is (in theory) - // invariant under cyclic permutations of its three arguments. - // - // In the context of numerical errors that arise in - // floating-point computations, and in order to make the strategy - // consistent with respect to cyclic permutations of its three - // arguments, we cyclically permute them so that the first - // argument is always the lexicographically smallest point. - - typedef compare::cartesian less; - - if (less::apply(p, p1)) - { - if (less::apply(p, p2)) - { - // p is the lexicographically smallest - return side_value(p, p1, p2, epsp); - } - else - { - // p2 is the lexicographically smallest - return side_value(p2, p, p1, epsp); - } - } - - if (less::apply(p1, p2)) - { - // p1 is the lexicographically smallest - return side_value(p1, p2, p, epsp); - } - else - { - // p2 is the lexicographically smallest - return side_value(p2, p, p1, epsp); - } - } - }; - - - template - static inline int apply(P1 const& p1, P2 const& p2, P const& p) - { - typedef typename coordinate_type::type coordinate_type1; - typedef typename coordinate_type::type coordinate_type2; - typedef typename coordinate_type

::type coordinate_type3; - - typedef std::conditional_t - < - std::is_void::value, - typename select_most_precise - < - coordinate_type1, - coordinate_type2, - coordinate_type3 - >::type, - CalculationType - > coordinate_type; - - // Promote float->double, small int->int - typedef typename select_most_precise - < - coordinate_type, - double - >::type promoted_type; - - bool const are_all_integral_coordinates = - std::is_integral::value - && std::is_integral::value - && std::is_integral::value; - - eps_policy< math::detail::equals_factor_policy > epsp; - promoted_type s = compute_side_value - < - coordinate_type, promoted_type, are_all_integral_coordinates - >::apply(p1, p2, p, epsp); - - promoted_type const zero = promoted_type(); - return math::detail::equals_by_policy(s, zero, epsp.policy) ? 0 - : s > zero ? 1 - : -1; - } - -private: - template - static inline bool equals_point_point(P1 const& p1, P2 const& p2) - { - return strategy::within::cartesian_point_point::apply(p1, p2); - } -}; - - -#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS -namespace services -{ - -template -struct default_strategy -{ - typedef side_by_triangle type; -}; - -} -#endif - -}} // namespace strategy::side - -}} // namespace boost::geometry +#include #endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_SIDE_BY_TRIANGLE_HPP diff --git a/include/boost/geometry/strategies/convex_hull/cartesian.hpp b/include/boost/geometry/strategies/convex_hull/cartesian.hpp index 1bef4e389..87814e14d 100644 --- a/include/boost/geometry/strategies/convex_hull/cartesian.hpp +++ b/include/boost/geometry/strategies/convex_hull/cartesian.hpp @@ -1,8 +1,9 @@ // Boost.Geometry -// Copyright (c) 2020, Oracle and/or its affiliates. +// Copyright (c) 2020-2021, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html @@ -10,10 +11,13 @@ #ifndef BOOST_GEOMETRY_STRATEGIES_CONVEX_HULL_CARTESIAN_HPP #define BOOST_GEOMETRY_STRATEGIES_CONVEX_HULL_CARTESIAN_HPP +#include +#include #include #include -#include +#include + namespace boost { namespace geometry { @@ -25,9 +29,23 @@ template class cartesian : public strategies::detail::cartesian_base { public: + template + static auto relate(Geometry1 const&, Geometry2 const&, + std::enable_if_t + < + util::is_pointlike::value + && util::is_pointlike::value + > * = nullptr) + { + return strategy::within::cartesian_point_point(); + } + static auto side() { - return strategy::side::side_robust(); + using side_strategy_type + = typename strategy::side::services::default_strategy + ::type; + return side_strategy_type(); } }; diff --git a/include/boost/geometry/strategies/convex_hull/geographic.hpp b/include/boost/geometry/strategies/convex_hull/geographic.hpp index 9f4a367eb..cb7445db4 100644 --- a/include/boost/geometry/strategies/convex_hull/geographic.hpp +++ b/include/boost/geometry/strategies/convex_hull/geographic.hpp @@ -1,8 +1,9 @@ // Boost.Geometry -// Copyright (c) 2020, Oracle and/or its affiliates. +// Copyright (c) 2020-2021, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html @@ -14,6 +15,8 @@ #include #include #include +#include +#include namespace boost { namespace geometry @@ -39,6 +42,17 @@ public: : base_t(spheroid) {} + template + static auto relate(Geometry1 const&, Geometry2 const&, + std::enable_if_t + < + util::is_pointlike::value + && util::is_pointlike::value + > * = nullptr) + { + return strategy::within::spherical_point_point(); + } + auto side() const { return strategy::side::geographic diff --git a/include/boost/geometry/strategies/convex_hull/spherical.hpp b/include/boost/geometry/strategies/convex_hull/spherical.hpp index 0eec8ee82..a637a0248 100644 --- a/include/boost/geometry/strategies/convex_hull/spherical.hpp +++ b/include/boost/geometry/strategies/convex_hull/spherical.hpp @@ -1,8 +1,9 @@ // Boost.Geometry -// Copyright (c) 2020, Oracle and/or its affiliates. +// Copyright (c) 2020-2021, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html @@ -13,7 +14,9 @@ #include #include +#include #include +#include namespace boost { namespace geometry @@ -26,6 +29,17 @@ template class spherical : public strategies::detail::spherical_base { public: + template + static auto relate(Geometry1 const&, Geometry2 const&, + std::enable_if_t + < + util::is_pointlike::value + && util::is_pointlike::value + > * = nullptr) + { + return strategy::within::spherical_point_point(); + } + static auto side() { return strategy::side::spherical_side_formula(); diff --git a/include/boost/geometry/strategies/distance/comparable.hpp b/include/boost/geometry/strategies/distance/comparable.hpp index 34a828cfe..3a6d8300b 100644 --- a/include/boost/geometry/strategies/distance/comparable.hpp +++ b/include/boost/geometry/strategies/distance/comparable.hpp @@ -14,6 +14,8 @@ #include #include +#include + namespace boost { namespace geometry { diff --git a/include/boost/geometry/strategies/distance/services.hpp b/include/boost/geometry/strategies/distance/services.hpp index 4ac35c6dd..5ce3cd98b 100644 --- a/include/boost/geometry/strategies/distance/services.hpp +++ b/include/boost/geometry/strategies/distance/services.hpp @@ -14,6 +14,8 @@ #include #include +#include + namespace boost { namespace geometry { diff --git a/include/boost/geometry/strategies/envelope/cartesian.hpp b/include/boost/geometry/strategies/envelope/cartesian.hpp index 3bce5dbc3..3d3605a62 100644 --- a/include/boost/geometry/strategies/envelope/cartesian.hpp +++ b/include/boost/geometry/strategies/envelope/cartesian.hpp @@ -68,6 +68,13 @@ struct cartesian { return strategy::envelope::cartesian(); } + + template + static auto envelope(Geometry const&, Box const&, + typename util::enable_if_geometry_collection_t * = nullptr) + { + return strategy::envelope::cartesian(); + } }; diff --git a/include/boost/geometry/strategies/envelope/geographic.hpp b/include/boost/geometry/strategies/envelope/geographic.hpp index 96940c470..5b824aded 100644 --- a/include/boost/geometry/strategies/envelope/geographic.hpp +++ b/include/boost/geometry/strategies/envelope/geographic.hpp @@ -86,6 +86,16 @@ public: FormulaPolicy, Spheroid, CalculationType >(base_t::m_spheroid); } + + template + auto envelope(Geometry const&, Box const&, + typename util::enable_if_geometry_collection_t * = nullptr) const + { + return strategy::envelope::geographic + < + FormulaPolicy, Spheroid, CalculationType + >(base_t::m_spheroid); + } }; diff --git a/include/boost/geometry/strategies/envelope/spherical.hpp b/include/boost/geometry/strategies/envelope/spherical.hpp index 0c5aad62b..cf174ea16 100644 --- a/include/boost/geometry/strategies/envelope/spherical.hpp +++ b/include/boost/geometry/strategies/envelope/spherical.hpp @@ -79,6 +79,13 @@ struct spherical { return strategy::envelope::spherical(); } + + template + static auto envelope(Geometry const&, Box const&, + typename util::enable_if_geometry_collection_t * = nullptr) + { + return strategy::envelope::spherical(); + } }; diff --git a/include/boost/geometry/strategies/geographic/buffer_point_circle.hpp b/include/boost/geometry/strategies/geographic/buffer_point_circle.hpp index 8d6643d73..d9efba917 100644 --- a/include/boost/geometry/strategies/geographic/buffer_point_circle.hpp +++ b/include/boost/geometry/strategies/geographic/buffer_point_circle.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2018-2019 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2020. -// Modifications copyright (c) 2020 Oracle and/or its affiliates. +// This file was modified by Oracle on 2020-2021. +// Modifications copyright (c) 2020-2021 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, @@ -17,12 +17,12 @@ #include +#include +#include +#include #include #include -#include - - namespace boost { namespace geometry { diff --git a/include/boost/geometry/strategies/geographic/distance.hpp b/include/boost/geometry/strategies/geographic/distance.hpp index 41e3cd7aa..3602a631a 100644 --- a/include/boost/geometry/strategies/geographic/distance.hpp +++ b/include/boost/geometry/strategies/geographic/distance.hpp @@ -17,6 +17,7 @@ #define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_DISTANCE_HPP +#include #include #include #include @@ -32,7 +33,6 @@ #include #include -#include #include #include diff --git a/include/boost/geometry/strategies/geographic/distance_cross_track.hpp b/include/boost/geometry/strategies/geographic/distance_cross_track.hpp index e269703ef..a32d0429f 100644 --- a/include/boost/geometry/strategies/geographic/distance_cross_track.hpp +++ b/include/boost/geometry/strategies/geographic/distance_cross_track.hpp @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -37,7 +38,6 @@ #include #include -#include #include #include diff --git a/include/boost/geometry/strategies/geographic/distance_segment_box.hpp b/include/boost/geometry/strategies/geographic/distance_segment_box.hpp index 3b076b72d..552bfcdbe 100644 --- a/include/boost/geometry/strategies/geographic/distance_segment_box.hpp +++ b/include/boost/geometry/strategies/geographic/distance_segment_box.hpp @@ -13,6 +13,8 @@ #include +#include + #include #include @@ -26,7 +28,6 @@ #include #include -#include #include namespace boost { namespace geometry diff --git a/include/boost/geometry/strategies/geographic/mapping_ssf.hpp b/include/boost/geometry/strategies/geographic/mapping_ssf.hpp index 20a052361..57fd985a9 100644 --- a/include/boost/geometry/strategies/geographic/mapping_ssf.hpp +++ b/include/boost/geometry/strategies/geographic/mapping_ssf.hpp @@ -17,10 +17,10 @@ #include +#include #include #include -#include #include #include diff --git a/include/boost/geometry/strategies/geographic/side.hpp b/include/boost/geometry/strategies/geographic/side.hpp index f9a6b23ab..a0b4abc81 100644 --- a/include/boost/geometry/strategies/geographic/side.hpp +++ b/include/boost/geometry/strategies/geographic/side.hpp @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -32,7 +33,6 @@ #include #include -#include #include namespace boost { namespace geometry diff --git a/include/boost/geometry/strategies/intersection_result.hpp b/include/boost/geometry/strategies/intersection_result.hpp index 4b5aa1c46..94aae51d8 100644 --- a/include/boost/geometry/strategies/intersection_result.hpp +++ b/include/boost/geometry/strategies/intersection_result.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2015, 2016. -// Modifications copyright (c) 2015-2016 Oracle and/or its affiliates. +// This file was modified by Oracle on 2015-2021. +// Modifications copyright (c) 2015-2021 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, @@ -15,9 +15,9 @@ #include +#include #include - namespace boost { namespace geometry { diff --git a/include/boost/geometry/strategies/intersection_strategies.hpp b/include/boost/geometry/strategies/intersection_strategies.hpp index bba6545c9..e9a17305a 100644 --- a/include/boost/geometry/strategies/intersection_strategies.hpp +++ b/include/boost/geometry/strategies/intersection_strategies.hpp @@ -22,9 +22,7 @@ #include #include #include - #include -#include #include #include diff --git a/include/boost/geometry/strategies/is_convex/cartesian.hpp b/include/boost/geometry/strategies/is_convex/cartesian.hpp index 4297c223b..c6c340fbd 100644 --- a/include/boost/geometry/strategies/is_convex/cartesian.hpp +++ b/include/boost/geometry/strategies/is_convex/cartesian.hpp @@ -11,12 +11,11 @@ #define BOOST_GEOMETRY_STRATEGIES_IS_CONVEX_CARTESIAN_HPP -#include -#include #include #include #include -#include +#include +#include namespace boost { namespace geometry @@ -25,21 +24,10 @@ namespace boost { namespace geometry namespace strategies { namespace is_convex { + template -class cartesian : public strategies::convex_hull::cartesian -{ -public: - template - static auto relate(Geometry1 const&, Geometry2 const&, - std::enable_if_t - < - util::is_pointlike::value - && util::is_pointlike::value - > * = nullptr) - { - return strategy::within::cartesian_point_point(); - } -}; +using cartesian = strategies::convex_hull::cartesian; + namespace services { diff --git a/include/boost/geometry/strategies/is_convex/geographic.hpp b/include/boost/geometry/strategies/is_convex/geographic.hpp index 66660138f..dd27c981a 100644 --- a/include/boost/geometry/strategies/is_convex/geographic.hpp +++ b/include/boost/geometry/strategies/is_convex/geographic.hpp @@ -14,8 +14,6 @@ #include #include #include -#include -#include namespace boost { namespace geometry @@ -24,34 +22,15 @@ namespace boost { namespace geometry namespace strategies { namespace is_convex { + template < typename FormulaPolicy = strategy::andoyer, typename Spheroid = srs::spheroid, typename CalculationType = void > -class geographic : public strategies::convex_hull::geographic -{ - using base_t = strategies::convex_hull::geographic; +using geographic = strategies::convex_hull::geographic; -public: - geographic() = default; - - explicit geographic(Spheroid const& spheroid) - : base_t(spheroid) - {} - - template - static auto relate(Geometry1 const&, Geometry2 const&, - std::enable_if_t - < - util::is_pointlike::value - && util::is_pointlike::value - > * = nullptr) - { - return strategy::within::spherical_point_point(); - } -}; namespace services { diff --git a/include/boost/geometry/strategies/is_convex/spherical.hpp b/include/boost/geometry/strategies/is_convex/spherical.hpp index 06ff3fae8..c6e97d16d 100644 --- a/include/boost/geometry/strategies/is_convex/spherical.hpp +++ b/include/boost/geometry/strategies/is_convex/spherical.hpp @@ -14,8 +14,6 @@ #include #include #include -#include -#include namespace boost { namespace geometry @@ -24,21 +22,10 @@ namespace boost { namespace geometry namespace strategies { namespace is_convex { + template -class spherical : public strategies::convex_hull::spherical -{ -public: - template - static auto relate(Geometry1 const&, Geometry2 const&, - std::enable_if_t - < - util::is_pointlike::value - && util::is_pointlike::value - > * = nullptr) - { - return strategy::within::spherical_point_point(); - } -}; +using spherical = strategies::convex_hull::spherical; + namespace services { diff --git a/include/boost/geometry/strategies/relate/cartesian.hpp b/include/boost/geometry/strategies/relate/cartesian.hpp index 532e75368..8613e6800 100644 --- a/include/boost/geometry/strategies/relate/cartesian.hpp +++ b/include/boost/geometry/strategies/relate/cartesian.hpp @@ -26,6 +26,8 @@ #include #include +#include +#include #include #include @@ -156,7 +158,10 @@ public: static auto side() { - return strategy::side::side_by_triangle(); + using side_strategy_type + = typename strategy::side::services::default_strategy + ::type; + return side_strategy_type(); } // within @@ -381,6 +386,15 @@ struct strategy_converter> } }; +template +struct strategy_converter> +{ + static auto get(strategy::side::side_robust const&) + { + return strategies::relate::cartesian(); + } +}; + } // namespace services diff --git a/include/boost/geometry/strategies/relate/geographic.hpp b/include/boost/geometry/strategies/relate/geographic.hpp index 60c6b9e58..4f556e953 100644 --- a/include/boost/geometry/strategies/relate/geographic.hpp +++ b/include/boost/geometry/strategies/relate/geographic.hpp @@ -13,6 +13,7 @@ // TEMP - move to strategy #include +#include #include #include #include diff --git a/include/boost/geometry/strategies/simplify/spherical.hpp b/include/boost/geometry/strategies/simplify/spherical.hpp index 0858087f3..4ff51b38c 100644 --- a/include/boost/geometry/strategies/simplify/spherical.hpp +++ b/include/boost/geometry/strategies/simplify/spherical.hpp @@ -12,6 +12,7 @@ #include +#include #include #include diff --git a/include/boost/geometry/strategies/spherical/distance_cross_track.hpp b/include/boost/geometry/strategies/spherical/distance_cross_track.hpp index f543a01c5..16bc70823 100644 --- a/include/boost/geometry/strategies/spherical/distance_cross_track.hpp +++ b/include/boost/geometry/strategies/spherical/distance_cross_track.hpp @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -36,7 +37,6 @@ #include #include -#include #include #ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK diff --git a/include/boost/geometry/strategies/spherical/distance_haversine.hpp b/include/boost/geometry/strategies/spherical/distance_haversine.hpp index bd46a93c6..389277259 100644 --- a/include/boost/geometry/strategies/spherical/distance_haversine.hpp +++ b/include/boost/geometry/strategies/spherical/distance_haversine.hpp @@ -17,6 +17,7 @@ #include +#include #include #include @@ -26,7 +27,6 @@ #include #include -#include #include diff --git a/include/boost/geometry/strategies/spherical/point_in_point.hpp b/include/boost/geometry/strategies/spherical/point_in_point.hpp index f0857c9f6..dc25d0d59 100644 --- a/include/boost/geometry/strategies/spherical/point_in_point.hpp +++ b/include/boost/geometry/strategies/spherical/point_in_point.hpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/geometry/strategies/spherical/side_by_cross_track.hpp b/include/boost/geometry/strategies/spherical/side_by_cross_track.hpp index b5cdb032b..d17de3077 100644 --- a/include/boost/geometry/strategies/spherical/side_by_cross_track.hpp +++ b/include/boost/geometry/strategies/spherical/side_by_cross_track.hpp @@ -16,6 +16,7 @@ #define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_SIDE_BY_CROSS_TRACK_HPP #include +#include #include #include @@ -26,7 +27,6 @@ #include #include -#include #include namespace boost { namespace geometry diff --git a/include/boost/geometry/strategies/spherical/ssf.hpp b/include/boost/geometry/strategies/spherical/ssf.hpp index d1e0e1352..2d29c400c 100644 --- a/include/boost/geometry/strategies/spherical/ssf.hpp +++ b/include/boost/geometry/strategies/spherical/ssf.hpp @@ -16,10 +16,10 @@ #include #include +#include #include #include -#include #include #include diff --git a/include/boost/geometry/strategies/strategies.hpp b/include/boost/geometry/strategies/strategies.hpp index 66cbc9383..541ae1d25 100644 --- a/include/boost/geometry/strategies/strategies.hpp +++ b/include/boost/geometry/strategies/strategies.hpp @@ -67,7 +67,6 @@ #include #include #include -#include #include #include @@ -135,6 +134,8 @@ #include #include #include +#include +#include #include #include diff --git a/include/boost/geometry/strategies/strategy_transform.hpp b/include/boost/geometry/strategies/strategy_transform.hpp index fe94c14f8..ee2216ac7 100644 --- a/include/boost/geometry/strategies/strategy_transform.hpp +++ b/include/boost/geometry/strategies/strategy_transform.hpp @@ -30,10 +30,10 @@ #include #include #include +#include #include #include -#include #include namespace boost { namespace geometry diff --git a/include/boost/geometry/strategies/transform/matrix_transformers.hpp b/include/boost/geometry/strategies/transform/matrix_transformers.hpp index 36e60f3b6..70f11b889 100644 --- a/include/boost/geometry/strategies/transform/matrix_transformers.hpp +++ b/include/boost/geometry/strategies/transform/matrix_transformers.hpp @@ -33,9 +33,9 @@ #include #include +#include #include #include -#include #include #include diff --git a/include/boost/geometry/strategy/cartesian/side_by_triangle.hpp b/include/boost/geometry/strategy/cartesian/side_by_triangle.hpp new file mode 100644 index 000000000..410b1000a --- /dev/null +++ b/include/boost/geometry/strategy/cartesian/side_by_triangle.hpp @@ -0,0 +1,277 @@ +// 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. + +// This file was modified by Oracle on 2015-2021. +// Modifications copyright (c) 2015-2021, 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. + +// 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_STRATEGY_CARTESIAN_SIDE_BY_TRIANGLE_HPP +#define BOOST_GEOMETRY_STRATEGY_CARTESIAN_SIDE_BY_TRIANGLE_HPP + + +#include + +#include +#include + +#include + +#include +#include +#include + +#include + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace side +{ + +/*! +\brief Check at which side of a segment a point lies: + left of segment (> 0), right of segment (< 0), on segment (0) +\ingroup strategies +\tparam CalculationType \tparam_calculation + */ +template +class side_by_triangle +{ + template + struct eps_policy + { + eps_policy() {} + template + eps_policy(Type const& a, Type const& b, Type const& c, Type const& d) + : policy(a, b, c, d) + {} + Policy policy; + }; + + struct eps_empty + { + eps_empty() {} + template + eps_empty(Type const&, Type const&, Type const&, Type const&) {} + }; + +public : + typedef cartesian_tag cs_tag; + + // Template member function, because it is not always trivial + // or convenient to explicitly mention the typenames in the + // strategy-struct itself. + + // Types can be all three different. Therefore it is + // not implemented (anymore) as "segment" + + template + < + typename CoordinateType, + typename PromotedType, + typename P1, + typename P2, + typename P, + typename EpsPolicy + > + static inline + PromotedType side_value(P1 const& p1, P2 const& p2, P const& p, EpsPolicy & eps_policy) + { + CoordinateType const x = get<0>(p); + CoordinateType const y = get<1>(p); + + CoordinateType const sx1 = get<0>(p1); + CoordinateType const sy1 = get<1>(p1); + CoordinateType const sx2 = get<0>(p2); + CoordinateType const sy2 = get<1>(p2); + + PromotedType const dx = sx2 - sx1; + PromotedType const dy = sy2 - sy1; + PromotedType const dpx = x - sx1; + PromotedType const dpy = y - sy1; + + eps_policy = EpsPolicy(dx, dy, dpx, dpy); + + return geometry::detail::determinant + ( + dx, dy, + dpx, dpy + ); + + } + + template + < + typename CoordinateType, + typename PromotedType, + typename P1, + typename P2, + typename P + > + static inline + PromotedType side_value(P1 const& p1, P2 const& p2, P const& p) + { + eps_empty dummy; + return side_value(p1, p2, p, dummy); + } + + + template + < + typename CoordinateType, + typename PromotedType, + bool AreAllIntegralCoordinates + > + struct compute_side_value + { + template + static inline PromotedType apply(P1 const& p1, P2 const& p2, P const& p, EpsPolicy & epsp) + { + return side_value(p1, p2, p, epsp); + } + }; + + template + struct compute_side_value + { + template + static inline PromotedType apply(P1 const& p1, P2 const& p2, P const& p, EpsPolicy & epsp) + { + // For robustness purposes, first check if any two points are + // the same; in this case simply return that the points are + // collinear + if (equals_point_point(p1, p2) + || equals_point_point(p1, p) + || equals_point_point(p2, p)) + { + return PromotedType(0); + } + + // The side_by_triangle strategy computes the signed area of + // the point triplet (p1, p2, p); as such it is (in theory) + // invariant under cyclic permutations of its three arguments. + // + // In the context of numerical errors that arise in + // floating-point computations, and in order to make the strategy + // consistent with respect to cyclic permutations of its three + // arguments, we cyclically permute them so that the first + // argument is always the lexicographically smallest point. + + typedef compare::cartesian less; + + if (less::apply(p, p1)) + { + if (less::apply(p, p2)) + { + // p is the lexicographically smallest + return side_value(p, p1, p2, epsp); + } + else + { + // p2 is the lexicographically smallest + return side_value(p2, p, p1, epsp); + } + } + + if (less::apply(p1, p2)) + { + // p1 is the lexicographically smallest + return side_value(p1, p2, p, epsp); + } + else + { + // p2 is the lexicographically smallest + return side_value(p2, p, p1, epsp); + } + } + }; + + + template + static inline int apply(P1 const& p1, P2 const& p2, P const& p) + { + typedef typename coordinate_type::type coordinate_type1; + typedef typename coordinate_type::type coordinate_type2; + typedef typename coordinate_type

::type coordinate_type3; + + typedef std::conditional_t + < + std::is_void::value, + typename select_most_precise + < + coordinate_type1, + coordinate_type2, + coordinate_type3 + >::type, + CalculationType + > coordinate_type; + + // Promote float->double, small int->int + typedef typename select_most_precise + < + coordinate_type, + double + >::type promoted_type; + + bool const are_all_integral_coordinates = + std::is_integral::value + && std::is_integral::value + && std::is_integral::value; + + eps_policy< math::detail::equals_factor_policy > epsp; + promoted_type s = compute_side_value + < + coordinate_type, promoted_type, are_all_integral_coordinates + >::apply(p1, p2, p, epsp); + + promoted_type const zero = promoted_type(); + return math::detail::equals_by_policy(s, zero, epsp.policy) ? 0 + : s > zero ? 1 + : -1; + } + +private: + template + static inline bool equals_point_point(P1 const& p1, P2 const& p2) + { + return strategy::within::cartesian_point_point::apply(p1, p2); + } +}; + +#if ! defined(BOOST_GEOMETRY_USE_RESCALING) +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +namespace services +{ + +template +struct default_strategy +{ + typedef side_by_triangle type; +}; + +} + +#endif +#endif + +}} // namespace strategy::side + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGY_CARTESIAN_SIDE_BY_TRIANGLE_HPP diff --git a/include/boost/geometry/strategy/cartesian/side_non_robust.hpp b/include/boost/geometry/strategy/cartesian/side_non_robust.hpp index 2ef109cc1..25074cc89 100644 --- a/include/boost/geometry/strategy/cartesian/side_non_robust.hpp +++ b/include/boost/geometry/strategy/cartesian/side_non_robust.hpp @@ -1,6 +1,6 @@ // Boost.Geometry -// Copyright (c) 2020, Oracle and/or its affiliates. +// Copyright (c) 2020-2021, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle @@ -14,6 +14,8 @@ #include #include +#include + namespace boost { namespace geometry { @@ -21,7 +23,7 @@ namespace strategy { namespace side { /*! -\brief Adaptive precision predicate to check at which side of a segment a point lies: +\brief Predicate to check at which side of a segment a point lies: left of segment (>0), right of segment (< 0), on segment (0). \ingroup strategies \tparam CalculationType \tparam_calculation @@ -35,8 +37,6 @@ struct side_non_robust { public: //! \brief Computes double the signed area of the CCW triangle p1, p2, p - -#ifndef DOXYGEN_SHOULD_SKIP_THIS template < typename P1, @@ -51,21 +51,44 @@ public: P1, P2, P - >::type coordinate_type; + >::type CoordinateType; typedef typename select_most_precise < - coordinate_type, + CoordinateType, double - >::type promoted_type; + >::type PromotedType; - auto detleft = (promoted_type(get<0>(p1)) - promoted_type(get<0>(p))) - * (promoted_type(get<1>(p2)) - promoted_type(get<1>(p))); - auto detright = (promoted_type(get<1>(p1)) - promoted_type(get<1>(p))) - * (promoted_type(get<0>(p2)) - promoted_type(get<0>(p))); - return detleft > detright ? 1 : (detleft < detright ? -1 : 0 ); + CoordinateType const x = get<0>(p); + CoordinateType const y = get<1>(p); + CoordinateType const sx1 = get<0>(p1); + CoordinateType const sy1 = get<1>(p1); + CoordinateType const sx2 = get<0>(p2); + CoordinateType const sy2 = get<1>(p2); + + //non-robust 1 + //the following is 2x slower in some generic cases when compiled with g++ + //(tested versions 9 and 10) + // + //auto detleft = (sx1 - x) * (sy2 - y); + //auto detright = (sy1 - y) * (sx2 - x); + //return detleft > detright ? 1 : (detleft < detright ? -1 : 0 ); + + //non-robust 2 + PromotedType const dx = sx2 - sx1; + PromotedType const dy = sy2 - sy1; + PromotedType const dpx = x - sx1; + PromotedType const dpy = y - sy1; + + PromotedType sv = geometry::detail::determinant + ( + dx, dy, + dpx, dpy + ); + PromotedType const zero = PromotedType(); + + return sv == zero ? 0 : sv > zero ? 1 : -1; } -#endif }; diff --git a/include/boost/geometry/strategy/cartesian/side_robust.hpp b/include/boost/geometry/strategy/cartesian/side_robust.hpp index 5362ed068..61eccb0af 100644 --- a/include/boost/geometry/strategy/cartesian/side_robust.hpp +++ b/include/boost/geometry/strategy/cartesian/side_robust.hpp @@ -7,6 +7,7 @@ // This file was modified by Oracle on 2021. // Modifications copyright (c) 2021, Oracle and/or its affiliates. + // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -17,9 +18,15 @@ #ifndef BOOST_GEOMETRY_STRATEGY_CARTESIAN_SIDE_ROBUST_HPP #define BOOST_GEOMETRY_STRATEGY_CARTESIAN_SIDE_ROBUST_HPP +#include +#include + +#include + #include #include #include +#include namespace boost { namespace geometry { @@ -27,6 +34,27 @@ namespace boost { namespace geometry namespace strategy { namespace side { +struct epsilon_equals_policy +{ +public: + template + static bool apply(T1 const& a, T2 const& b, Policy const& policy) + { + return boost::geometry::math::detail::equals_by_policy(a, b, policy); + } +}; + +struct fp_equals_policy +{ +public: + template + static bool apply(T1 const& a, T2 const& b, Policy const&) + { + return a == b; + } +}; + + /*! \brief Adaptive precision predicate to check at which side of a segment a point lies: left of segment (>0), right of segment (< 0), on segment (0). @@ -38,21 +66,52 @@ namespace strategy { namespace side template < typename CalculationType = void, + typename EqualsPolicy = epsilon_equals_policy, std::size_t Robustness = 3 > struct side_robust { + + template + struct epsilon_policy + { + using Policy = boost::geometry::math::detail::equals_factor_policy; + + epsilon_policy() {} + + template + epsilon_policy(Type const& a, Type const& b, Type const& c, Type const& d) + : m_policy(a, b, c, d) + {} + Policy m_policy; + + public: + + template + bool apply(T1 a, T2 b) const + { + return EqualsPolicy::apply(a, b, m_policy); + } + }; + public: - //! \brief Computes double the signed area of the CCW triangle p1, p2, p + + typedef cartesian_tag cs_tag; + + //! \brief Computes the sign of the CCW triangle p1, p2, p template < typename PromotedType, typename P1, typename P2, - typename P + typename P, + typename EpsPolicyInternal, + std::enable_if_t::value, int> = 0 > - static inline PromotedType side_value(P1 const& p1, P2 const& p2, - P const& p) + static inline PromotedType side_value(P1 const& p1, + P2 const& p2, + P const& p, + EpsPolicyInternal& eps_policy) { using vec2d = ::boost::geometry::detail::precise_math::vec2d; vec2d pa; @@ -65,7 +124,22 @@ public: pc.x = get<0>(p); pc.y = get<1>(p); return ::boost::geometry::detail::precise_math::orient2d - (pa, pb, pc); + (pa, pb, pc, eps_policy); + } + + template + < + typename PromotedType, + typename P1, + typename P2, + typename P, + typename EpsPolicyInternal, + std::enable_if_t::value, int> = 0 + > + static inline auto side_value(P1 const& p1, P2 const& p2, P const& p, + EpsPolicyInternal&) + { + return side_non_robust<>::apply(p1, p2, p); } #ifndef DOXYGEN_SHOULD_SKIP_THIS @@ -77,28 +151,50 @@ public: > static inline int apply(P1 const& p1, P2 const& p2, P const& p) { - typedef typename select_calculation_type_alt + using coordinate_type = typename select_calculation_type_alt < CalculationType, P1, P2, P - >::type coordinate_type; - typedef typename select_most_precise + >::type; + + using promoted_type = typename select_most_precise < coordinate_type, double - >::type promoted_type; + >::type; - promoted_type sv = side_value(p1, p2, p); - return sv > 0 ? 1 - : sv < 0 ? -1 - : 0; + epsilon_policy epsp; + promoted_type sv = side_value(p1, p2, p, epsp); + promoted_type const zero = promoted_type(); + + return epsp.apply(sv, zero) ? 0 + : sv > zero ? 1 + : -1; } + #endif }; +#ifdef BOOST_GEOMETRY_USE_RESCALING +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +namespace services +{ + +template +struct default_strategy +{ + typedef side_robust type; +}; + +} + +#endif +#endif + }} // namespace strategy::side }} // namespace boost::geometry diff --git a/include/boost/geometry/util/math.hpp b/include/boost/geometry/util/math.hpp index fc9d7a3be..c39341a20 100644 --- a/include/boost/geometry/util/math.hpp +++ b/include/boost/geometry/util/math.hpp @@ -139,6 +139,12 @@ struct equals_factor_policy return factor; } + template + void multiply_epsilon(E const& multiplier) + { + factor *= multiplier; + } + T factor; }; @@ -153,6 +159,8 @@ struct equals_factor_policy { return T(1); } + + void multiply_epsilon(T const& ) {} }; template Qh; - int i_e = 0, i_f = 0, i_h = 0; + int i_e = 0; + int i_f = 0; + int i_h = 0; if (std::abs(f[0]) > std::abs(e[0])) { Qh[0] = e[i_e++]; @@ -282,14 +288,16 @@ inline RealNumber orient2dtail(vec2d const& p1, std::array& t4, std::array& t5_01, std::array& t6_01, - RealNumber const& magnitude - ) + RealNumber const& magnitude) { t5_01[1] = two_product_tail(t1[0], t2[0], t5_01[0]); t6_01[1] = two_product_tail(t3[0], t4[0], t6_01[0]); std::array tA_03 = two_two_expansion_diff(t5_01, t6_01); RealNumber det = std::accumulate(tA_03.begin(), tA_03.end(), static_cast(0)); - if(Robustness == 1) return det; + if (Robustness == 1) + { + return det; + } // see p.39, mind the different definition of epsilon for error bound RealNumber B_relative_bound = (1 + 3 * std::numeric_limits::epsilon()) @@ -347,29 +355,37 @@ inline RealNumber orient2dtail(vec2d const& p1, return(D[D_nz - 1]); } -// see page 38, Figure 21 for the calculations, notation follows the notation in the figure. +// see page 38, Figure 21 for the calculations, notation follows the notation +// in the figure. template < typename RealNumber, - std::size_t Robustness = 3 + std::size_t Robustness = 3, + typename EpsPolicy > inline RealNumber orient2d(vec2d const& p1, vec2d const& p2, - vec2d const& p3) + vec2d const& p3, + EpsPolicy& eps_policy) { - if(Robustness == 0) - { - return (p1.x - p3.x) * (p2.y - p3.y) - (p1.y - p3.y) * (p2.x - p3.x); - } std::array t1, t2, t3, t4; t1[0] = p1.x - p3.x; t2[0] = p2.y - p3.y; t3[0] = p1.y - p3.y; t4[0] = p2.x - p3.x; + + eps_policy = EpsPolicy(t1[0], t2[0], t3[0], t4[0]); + std::array t5_01, t6_01; t5_01[0] = t1[0] * t2[0]; t6_01[0] = t3[0] * t4[0]; RealNumber det = t5_01[0] - t6_01[0]; + + if (Robustness == 0) + { + return det; + } + RealNumber const magnitude = std::abs(t5_01[0]) + std::abs(t6_01[0]); // see p.39, mind the different definition of epsilon for error bound @@ -388,7 +404,8 @@ inline RealNumber orient2d(vec2d const& p1, //obvious return det; } - return orient2dtail(p1, p2, p3, t1, t2, t3, t4, t5_01, t6_01, magnitude); + return orient2dtail(p1, p2, p3, t1, t2, t3, t4, + t5_01, t6_01, magnitude); } // This method adaptively computes increasingly precise approximations of the following diff --git a/include/boost/geometry/util/promote_floating_point.hpp b/include/boost/geometry/util/promote_floating_point.hpp index a005adee6..d38109116 100644 --- a/include/boost/geometry/util/promote_floating_point.hpp +++ b/include/boost/geometry/util/promote_floating_point.hpp @@ -18,35 +18,9 @@ #ifndef BOOST_GEOMETRY_UTIL_PROMOTE_FLOATING_POINT_HPP #define BOOST_GEOMETRY_UTIL_PROMOTE_FLOATING_POINT_HPP +#include +BOOST_HEADER_DEPRECATED("boost/geometry/core/coordinate_promotion.hpp") -#include - - -namespace boost { namespace geometry -{ - - -/*! - \brief Meta-function converting, if necessary, to "a floating point" type - \details - - if input type is integer, type is double - - else type is input type - \ingroup utility - */ - -template -struct promote_floating_point -{ - typedef std::conditional_t - < - std::is_integral::value, - PromoteIntegerTo, - T - > type; -}; - - -}} // namespace boost::geometry - +#include #endif // BOOST_GEOMETRY_UTIL_PROMOTE_FLOATING_POINT_HPP diff --git a/include/boost/geometry/util/sequence.hpp b/include/boost/geometry/util/sequence.hpp index 80e3b7b23..2f8e7b51b 100644 --- a/include/boost/geometry/util/sequence.hpp +++ b/include/boost/geometry/util/sequence.hpp @@ -1,6 +1,6 @@ // Boost.Geometry -// Copyright (c) 2020, Oracle and/or its affiliates. +// Copyright (c) 2020-2021, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -62,13 +62,13 @@ struct sequence_element {}; template struct sequence_element> { - typedef typename sequence_element>::type type; + using type = typename sequence_element>::type; }; template struct sequence_element<0, type_sequence> { - typedef T type; + using type = T; }; template @@ -86,6 +86,19 @@ struct sequence_element<0, std::integer_sequence> {}; +template +struct pack_front +{ + static_assert(sizeof...(Ts) > 0, "Parameter pack can not be empty."); +}; + +template +struct pack_front +{ + typedef T type; +}; + + template struct sequence_front : sequence_element<0, Sequence> @@ -112,6 +125,7 @@ struct sequence_empty {}; +// Defines type member for the first type in sequence that satisfies UnaryPred. template < typename Sequence, @@ -138,77 +152,71 @@ template