From fb9b1d40ff853e4c88c0bdc6ba4facecd5ccdd2d Mon Sep 17 00:00:00 2001 From: Vissarion Fisikopoulos Date: Tue, 29 Jun 2021 13:20:07 +0300 Subject: [PATCH 01/29] Replace side_by_triangle with side_robust --- .../detail/equals/collect_vectors.hpp | 6 +- .../agnostic/point_in_box_by_side.hpp | 6 +- .../cartesian/distance_segment_box.hpp | 1 - .../strategies/cartesian/intersection.hpp | 4 +- .../cartesian/point_in_poly_winding.hpp | 4 +- .../geometry/strategies/relate/cartesian.hpp | 12 +- .../strategy/cartesian/side_non_robust.hpp | 1 + .../strategy/cartesian/side_robust.hpp | 119 +++++++++++++++--- include/boost/geometry/util/precise_math.hpp | 55 ++++++-- .../geometry/util/select_most_precise.hpp | 40 +++++- .../convex_hull/convex_hull_robust.cpp | 1 + .../convex_hull/test_convex_hull.hpp | 70 +++++++++-- .../overlay/get_turns_linear_linear.cpp | 13 +- .../sym_difference/sym_difference_tupled.cpp | 2 +- 14 files changed, 267 insertions(+), 67 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/equals/collect_vectors.hpp b/include/boost/geometry/algorithms/detail/equals/collect_vectors.hpp index 35ec77a92..b435fff2f 100644 --- a/include/boost/geometry/algorithms/detail/equals/collect_vectors.hpp +++ b/include/boost/geometry/algorithms/detail/equals/collect_vectors.hpp @@ -40,7 +40,7 @@ #include -#include +#include #include #include @@ -62,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; 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..c794a3b23 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 @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include @@ -118,7 +118,7 @@ struct cartesian_point_box_by_side < within::detail::decide_within >(point, box, - strategy::side::side_by_triangle()); + strategy::side::side_robust()); } }; @@ -189,7 +189,7 @@ struct cartesian_point_box_by_side < within::detail::decide_covered_by >(point, box, - strategy::side::side_by_triangle()); + strategy::side::side_robust()); } }; 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..cbf4aa486 100644 --- a/include/boost/geometry/strategies/cartesian/intersection.hpp +++ b/include/boost/geometry/strategies/cartesian/intersection.hpp @@ -44,7 +44,7 @@ #include #include #include -#include +#include #include #include #include @@ -402,7 +402,7 @@ struct cartesian_segments return Policy::disjoint(); } - typedef side::side_by_triangle side_strategy_type; + typedef side::side_robust side_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..3df4bcc44 100644 --- a/include/boost/geometry/strategies/cartesian/point_in_poly_winding.hpp +++ b/include/boost/geometry/strategies/cartesian/point_in_poly_winding.hpp @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include @@ -116,7 +116,7 @@ public: else // count == 2 || count == -2 { // 1 left, -1 right - typedef side::side_by_triangle side_strategy_type; + typedef side::side_robust side_strategy_type; side = side_strategy_type::apply(s1, s2, point); } diff --git a/include/boost/geometry/strategies/relate/cartesian.hpp b/include/boost/geometry/strategies/relate/cartesian.hpp index 16c6853a3..5b418913d 100644 --- a/include/boost/geometry/strategies/relate/cartesian.hpp +++ b/include/boost/geometry/strategies/relate/cartesian.hpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -147,7 +148,7 @@ public: static auto side() { - return strategy::side::side_by_triangle(); + return strategy::side::side_robust(); } // within @@ -372,6 +373,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/strategy/cartesian/side_non_robust.hpp b/include/boost/geometry/strategy/cartesian/side_non_robust.hpp index 2ef109cc1..098cb9bd4 100644 --- a/include/boost/geometry/strategy/cartesian/side_non_robust.hpp +++ b/include/boost/geometry/strategy/cartesian/side_non_robust.hpp @@ -62,6 +62,7 @@ public: * (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 ); } diff --git a/include/boost/geometry/strategy/cartesian/side_robust.hpp b/include/boost/geometry/strategy/cartesian/side_robust.hpp index 4ee4a1726..9e69a0c80 100644 --- a/include/boost/geometry/strategy/cartesian/side_robust.hpp +++ b/include/boost/geometry/strategy/cartesian/side_robust.hpp @@ -5,6 +5,11 @@ // Contributed and/or modified by Tinko Bartels, // as part of Google Summer of Code 2019 program. +// 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 + // 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) @@ -12,9 +17,16 @@ #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 { @@ -22,6 +34,28 @@ namespace boost { namespace geometry namespace strategy { namespace side { +struct eps_equals_policy +{ +public: + + template + static auto apply(T1 a, T2 b, Policy policy) + { + return boost::geometry::math::detail::equals_by_policy(a, b, policy); + } +}; + +struct fp_equals_policy +{ +public: + template + static auto apply(T1 a, T2 b, Policy) + { + 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). @@ -33,57 +67,106 @@ namespace strategy { namespace side template < typename CalculationType = void, + typename EpsPolicy = eps_equals_policy, std::size_t Robustness = 3 > struct side_robust { + 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; + }; + 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) { - typedef ::boost::geometry::detail::precise_math::vec2d vec2d; - vec2d pa { get<0>(p1), get<1>(p1) }; - vec2d pb { get<0>(p2), get<1>(p2) }; - vec2d pc { get<0>(p), get<1>(p) }; + using vec2d = ::boost::geometry::detail::precise_math::vec2d; + vec2d pa; + pa.x = get<0>(p1); + pa.y = get<1>(p1); + vec2d pb; + pb.x = get<0>(p2); + pb.y = get<1>(p2); + vec2d pc; + 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 template - < + < typename P1, typename P2, typename P > 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; + eps_policy + < + boost::geometry::math::detail::equals_factor_policy + > epsp; + + promoted_type sv = side_value(p1, p2, p, epsp); + + promoted_type const zero = promoted_type(); + return EpsPolicy::apply(sv, zero, epsp.policy) ? 0 + : sv > zero ? 1 + : -1; } + #endif }; diff --git a/include/boost/geometry/util/precise_math.hpp b/include/boost/geometry/util/precise_math.hpp index c70762097..eccf08800 100644 --- a/include/boost/geometry/util/precise_math.hpp +++ b/include/boost/geometry/util/precise_math.hpp @@ -5,6 +5,10 @@ // Contributed and/or modified by Tinko Bartels, // as part of Google Summer of Code 2019 program. +// This file was modified by Oracle on 2021. +// Modifications copyright (c) 2021, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fisikopoulos, 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) @@ -157,7 +161,9 @@ inline int fast_expansion_sum_zeroelim( int n = InSize2) { std::array 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,51 @@ 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); - } + auto const x = p3.x; + auto const y = p3.y; + + auto const sx1 = p1.x; + auto const sy1 = p1.y; + auto const sx2 = p2.x; + auto const sy2 = p2.y; + + + auto const dx = sx2 - sx1; + auto const dy = sy2 - sy1; + auto const dpx = x - sx1; + auto const dpy = y - sy1; + + eps_policy = EpsPolicy(dx, dy, dpx, dpy); + 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; + 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 +418,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/select_most_precise.hpp b/include/boost/geometry/util/select_most_precise.hpp index d6c6337b4..3fb8d8a73 100644 --- a/include/boost/geometry/util/select_most_precise.hpp +++ b/include/boost/geometry/util/select_most_precise.hpp @@ -30,7 +30,6 @@ namespace boost { namespace geometry namespace detail { namespace select_most_precise { - // 0 - void // 1 - integral // 2 - floating point @@ -55,6 +54,43 @@ struct type_priority > {}; +/* +// 0 - void +// 1 - integral (int, long int) +// 2 - floating point (float, double) +// 3 - long long int +// 4 - long double +// 5 - non-fundamental +template +struct type_priority + : std::conditional_t + < + std::is_void::value, + std::integral_constant, + std::conditional_t + < + std::is_fundamental::value, + std::conditional_t + < + std::is_same::value, + std::integral_constant, + std::conditional_t + < + std::is_same::value, + std::integral_constant, + std::conditional_t + < + std::is_floating_point::value, + std::integral_constant, + std::integral_constant + > + > + >, + std::integral_constant + > + > +{}; +*/ template struct type_size @@ -119,7 +155,7 @@ struct select_most_precise T2, std::conditional_t // priority1 == priority2 < - (priority1 == 0 || priority1 == 3), // both void or non-fundamental + (priority1 == 0 || priority1 == 5), // both void or non-fundamental T1, std::conditional_t // both fundamental < diff --git a/test/algorithms/convex_hull/convex_hull_robust.cpp b/test/algorithms/convex_hull/convex_hull_robust.cpp index 9ee6e55f4..1a53321fd 100644 --- a/test/algorithms/convex_hull/convex_hull_robust.cpp +++ b/test/algorithms/convex_hull/convex_hull_robust.cpp @@ -82,6 +82,7 @@ void test_all() polygon_wkt3, 5, 4, 1.4210854715202004e-14); test_geometry, non_robust_cartesian_sbt >( polygon_wkt3, 5, 5, 1.69333333333333265e-13); + return ; // missing one point could lead in arbitrary large errors in area auto polygon_wkt4 = "polygon((0.10000000000000001 0.10000000000000001,\ diff --git a/test/algorithms/convex_hull/test_convex_hull.hpp b/test/algorithms/convex_hull/test_convex_hull.hpp index df1b959b0..c901e3c0b 100644 --- a/test/algorithms/convex_hull/test_convex_hull.hpp +++ b/test/algorithms/convex_hull/test_convex_hull.hpp @@ -3,9 +3,10 @@ // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2014, 2015. -// Modifications copyright (c) 2014-2015 Oracle and/or its affiliates. +// This file was modified by Oracle on 2014, 2015, 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 Adam Wulkiewicz, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -43,7 +44,11 @@ struct robust_cartesian : boost::geometry::strategies::detail::cartesian_base { static auto side() { - return boost::geometry::strategy::side::side_robust<>(); + return boost::geometry::strategy::side::side_robust + < + double, + boost::geometry::strategy::side::fp_equals_policy + >(); } }; @@ -159,15 +164,12 @@ struct test_convex_hull std::size_t size_hull_closed, double expected_area, double expected_perimeter, - bool reverse) + bool /*reverse*/) { - bool const is_original_closed = resolve_variant::get_closure(geometry) != bg::open; static bool const is_hull_closed = bg::closure::value != bg::open; // convex_hull_insert() uses the original Geometry as a source of the info // about the order and closure - std::size_t const size_hull_from_orig = is_original_closed ? - size_hull_closed : size_hull_closed - 1; std::size_t const size_hull = is_hull_closed ? size_hull_closed : size_hull_closed - 1; @@ -179,14 +181,19 @@ struct test_convex_hull check_convex_hull(geometry, hull, size_original, size_hull, expected_area, expected_perimeter, false, AreaStrategy()); - // Test version with output iterator and strategy + // Do not test with output iterator since it does not support + // non-default strategy + /* + bool const is_original_closed = resolve_variant::get_closure(geometry) != bg::open; + std::size_t const size_hull_from_orig = is_original_closed ? + size_hull_closed : size_hull_closed - 1; bg::clear(hull); bg::detail::convex_hull::convex_hull_insert( geometry, std::back_inserter(hull.outer()), Strategy()); check_convex_hull(geometry, hull, size_original, size_hull_from_orig, expected_area, expected_perimeter, reverse, AreaStrategy()); - + */ } }; @@ -254,6 +261,49 @@ struct test_convex_hull }; +template +< + typename Hull +> +struct test_convex_hull +{ + template + static void apply(Geometry const& geometry, + std::size_t size_original, + std::size_t size_hull_closed, + double expected_area, + double expected_perimeter, + bool reverse) + { + bool const is_original_closed = resolve_variant::get_closure(geometry) != bg::open; + static bool const is_hull_closed = bg::closure::value != bg::open; + + // convex_hull_insert() uses the original Geometry as a source of the info + // about the order and closure + std::size_t const size_hull_from_orig = is_original_closed ? + size_hull_closed : size_hull_closed - 1; + std::size_t const size_hull = is_hull_closed ? size_hull_closed : + size_hull_closed - 1; + + Hull hull; + + // Test version with strategy + bg::clear(hull); + bg::convex_hull(geometry, hull.outer(), robust_cartesian()); + check_convex_hull(geometry, hull, size_original, size_hull, expected_area, + expected_perimeter, false, precise_cartesian()); + + // Test version with output iterator and strategy + bg::clear(hull); + bg::detail::convex_hull::convex_hull_insert(geometry, + std::back_inserter(hull.outer()), robust_cartesian()); + check_convex_hull(geometry, hull, size_original, size_hull_from_orig, + expected_area, expected_perimeter, reverse, precise_cartesian()); + + } +}; + + template < typename Geometry, @@ -342,6 +392,4 @@ void test_empty_input() BOOST_CHECK_MESSAGE(bg::is_empty(hull), "Output convex hull should be empty" ); } - - #endif diff --git a/test/algorithms/overlay/get_turns_linear_linear.cpp b/test/algorithms/overlay/get_turns_linear_linear.cpp index b6d0c8266..11b1453ea 100644 --- a/test/algorithms/overlay/get_turns_linear_linear.cpp +++ b/test/algorithms/overlay/get_turns_linear_linear.cpp @@ -285,21 +285,12 @@ void test_all() "LINESTRING(2 8,4 0.4,8 1,0 5)", expected("iuu++")("mui=+")("tiu+=")); -#if ! ( defined(BOOST_CLANG) && defined(BOOST_GEOMETRY_COMPILER_MODE_RELEASE) ) - - // In clang/release mode this testcase gives other results - - // assertion failure in 1.57 - // FAILING - no assertion failure but the result is not very good test_geometry("LINESTRING(-2305843009213693956 4611686018427387906, -33 -92, 78 83)", "LINESTRING(31 -97, -46 57, -20 -4)", - expected("")("")); + expected("iuu++")); test_geometry("LINESTRING(31 -97, -46 57, -20 -4)", "LINESTRING(-2305843009213693956 4611686018427387906, -33 -92, 78 83)", - expected("")("")); - -#endif - + expected("iuu++")); } // In 1.57 the results of those combinations was different for MinGW diff --git a/test/algorithms/set_operations/sym_difference/sym_difference_tupled.cpp b/test/algorithms/set_operations/sym_difference/sym_difference_tupled.cpp index 0985ed410..9730935fc 100644 --- a/test/algorithms/set_operations/sym_difference/sym_difference_tupled.cpp +++ b/test/algorithms/set_operations/sym_difference/sym_difference_tupled.cpp @@ -348,7 +348,7 @@ inline void test_aa() "MULTIPOLYGON(((0 0, 0 5, 5 5, 5 0, 0 0),(0 0, 4 1, 4 4, 1 4, 0 0))," "((2 6, 2 8, 8 8, 8 5, 7 5, 7 6, 2 6)))", "MULTIPOLYGON(((0 0, 1 4, 5 4, 5 1, 4 1, 0 0),(0 0, 2 1, 2 2, 1 2, 0 0))," - "((5 0, 5 1, 6 1, 6 4, 5 4, 3 6, 2 5, 2 7, 7 7, 7 0 5 0)))", + "((5 0, 5 1, 6 1, 6 4, 5 4, 3 6, 2 5, 2 7, 7 7, 7 0, 5 0)))", "MULTIPOINT()", "MULTILINESTRING()", "MULTIPOLYGON(((0 0,0 5,4 5,3 6,7 6,7 7,2 7,2 8,8 8,8 5,7 5,7 0,0 0)," From 6b49308808ab123fb22d2a0529b81861a8d9d909 Mon Sep 17 00:00:00 2001 From: Vissarion Fisikopoulos Date: Wed, 30 Jun 2021 12:51:28 +0300 Subject: [PATCH 02/29] Move side_by_triangle to strategy/cartesian --- .../agnostic/point_in_box_by_side.hpp | 6 +- .../strategies/cartesian/intersection.hpp | 2 +- .../cartesian/point_in_poly_winding.hpp | 2 +- .../strategies/cartesian/side_by_triangle.hpp | 270 +----------------- .../strategies/convex_hull/cartesian.hpp | 2 +- .../strategies/intersection_strategies.hpp | 4 +- .../strategies/is_convex/cartesian.hpp | 4 +- .../geometry/strategies/relate/cartesian.hpp | 3 +- .../boost/geometry/strategies/strategies.hpp | 3 +- .../strategy/cartesian/side_by_triangle.hpp | 262 +++++++++++++++++ .../strategy/cartesian/side_non_robust.hpp | 7 +- .../strategy/cartesian/side_robust.hpp | 23 +- .../geometry/util/select_most_precise.hpp | 40 +-- .../convex_hull/convex_hull_robust.cpp | 1 - .../convex_hull/test_convex_hull.hpp | 5 +- test/algorithms/overlay/relative_order.cpp | 4 +- test/strategies/spherical_side.cpp | 2 +- test/strategies/test_within.hpp | 3 +- 18 files changed, 317 insertions(+), 326 deletions(-) create mode 100644 include/boost/geometry/strategy/cartesian/side_by_triangle.hpp 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 c794a3b23..8c3f0ba0a 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 diff --git a/include/boost/geometry/strategies/cartesian/intersection.hpp b/include/boost/geometry/strategies/cartesian/intersection.hpp index cbf4aa486..f81a98998 100644 --- a/include/boost/geometry/strategies/cartesian/intersection.hpp +++ b/include/boost/geometry/strategies/cartesian/intersection.hpp @@ -38,13 +38,13 @@ #include #include #include +#include #include #include #include #include #include -#include #include #include #include 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 3df4bcc44..3268d5a33 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 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..c357ba95e 100644 --- a/include/boost/geometry/strategies/convex_hull/cartesian.hpp +++ b/include/boost/geometry/strategies/convex_hull/cartesian.hpp @@ -10,10 +10,10 @@ #ifndef BOOST_GEOMETRY_STRATEGIES_CONVEX_HULL_CARTESIAN_HPP #define BOOST_GEOMETRY_STRATEGIES_CONVEX_HULL_CARTESIAN_HPP +#include #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..afb1afb5d 100644 --- a/include/boost/geometry/strategies/intersection_strategies.hpp +++ b/include/boost/geometry/strategies/intersection_strategies.hpp @@ -19,12 +19,12 @@ #include #include +#include + #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..d274086ab 100644 --- a/include/boost/geometry/strategies/is_convex/cartesian.hpp +++ b/include/boost/geometry/strategies/is_convex/cartesian.hpp @@ -10,12 +10,14 @@ #ifndef BOOST_GEOMETRY_STRATEGIES_IS_CONVEX_CARTESIAN_HPP #define BOOST_GEOMETRY_STRATEGIES_IS_CONVEX_CARTESIAN_HPP +#include +#include #include -#include #include #include #include + #include diff --git a/include/boost/geometry/strategies/relate/cartesian.hpp b/include/boost/geometry/strategies/relate/cartesian.hpp index 5b418913d..913ef714a 100644 --- a/include/boost/geometry/strategies/relate/cartesian.hpp +++ b/include/boost/geometry/strategies/relate/cartesian.hpp @@ -20,13 +20,14 @@ #include #include #include -#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/strategy/cartesian/side_by_triangle.hpp b/include/boost/geometry/strategy/cartesian/side_by_triangle.hpp new file mode 100644 index 000000000..56436a2a2 --- /dev/null +++ b/include/boost/geometry/strategy/cartesian/side_by_triangle.hpp @@ -0,0 +1,262 @@ +// 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 + +#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); + } +}; + +}} // 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 098cb9bd4..add8e7972 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 @@ -21,7 +21,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 +35,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, @@ -66,7 +64,6 @@ public: return detleft > detright ? 1 : (detleft < detright ? -1 : 0 ); } -#endif }; diff --git a/include/boost/geometry/strategy/cartesian/side_robust.hpp b/include/boost/geometry/strategy/cartesian/side_robust.hpp index 9e69a0c80..61fd6827c 100644 --- a/include/boost/geometry/strategy/cartesian/side_robust.hpp +++ b/include/boost/geometry/strategy/cartesian/side_robust.hpp @@ -17,12 +17,10 @@ #ifndef BOOST_GEOMETRY_STRATEGY_CARTESIAN_SIDE_ROBUST_HPP #define BOOST_GEOMETRY_STRATEGY_CARTESIAN_SIDE_ROBUST_HPP -#include - -#include - #include +#include + #include #include #include @@ -133,7 +131,7 @@ public: #ifndef DOXYGEN_SHOULD_SKIP_THIS template - < + < typename P1, typename P2, typename P @@ -171,6 +169,21 @@ public: }; +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +namespace services +{ + +template +struct default_strategy +{ + typedef side_robust type; +}; + +} + +#endif + }} // namespace strategy::side }} // namespace boost::geometry diff --git a/include/boost/geometry/util/select_most_precise.hpp b/include/boost/geometry/util/select_most_precise.hpp index 3fb8d8a73..d6c6337b4 100644 --- a/include/boost/geometry/util/select_most_precise.hpp +++ b/include/boost/geometry/util/select_most_precise.hpp @@ -30,6 +30,7 @@ namespace boost { namespace geometry namespace detail { namespace select_most_precise { + // 0 - void // 1 - integral // 2 - floating point @@ -54,43 +55,6 @@ struct type_priority > {}; -/* -// 0 - void -// 1 - integral (int, long int) -// 2 - floating point (float, double) -// 3 - long long int -// 4 - long double -// 5 - non-fundamental -template -struct type_priority - : std::conditional_t - < - std::is_void::value, - std::integral_constant, - std::conditional_t - < - std::is_fundamental::value, - std::conditional_t - < - std::is_same::value, - std::integral_constant, - std::conditional_t - < - std::is_same::value, - std::integral_constant, - std::conditional_t - < - std::is_floating_point::value, - std::integral_constant, - std::integral_constant - > - > - >, - std::integral_constant - > - > -{}; -*/ template struct type_size @@ -155,7 +119,7 @@ struct select_most_precise T2, std::conditional_t // priority1 == priority2 < - (priority1 == 0 || priority1 == 5), // both void or non-fundamental + (priority1 == 0 || priority1 == 3), // both void or non-fundamental T1, std::conditional_t // both fundamental < diff --git a/test/algorithms/convex_hull/convex_hull_robust.cpp b/test/algorithms/convex_hull/convex_hull_robust.cpp index 1a53321fd..9ee6e55f4 100644 --- a/test/algorithms/convex_hull/convex_hull_robust.cpp +++ b/test/algorithms/convex_hull/convex_hull_robust.cpp @@ -82,7 +82,6 @@ void test_all() polygon_wkt3, 5, 4, 1.4210854715202004e-14); test_geometry, non_robust_cartesian_sbt >( polygon_wkt3, 5, 5, 1.69333333333333265e-13); - return ; // missing one point could lead in arbitrary large errors in area auto polygon_wkt4 = "polygon((0.10000000000000001 0.10000000000000001,\ diff --git a/test/algorithms/convex_hull/test_convex_hull.hpp b/test/algorithms/convex_hull/test_convex_hull.hpp index c901e3c0b..d1b01bd38 100644 --- a/test/algorithms/convex_hull/test_convex_hull.hpp +++ b/test/algorithms/convex_hull/test_convex_hull.hpp @@ -31,9 +31,10 @@ #include #include -#include -#include #include +#include +#include +#include #include diff --git a/test/algorithms/overlay/relative_order.cpp b/test/algorithms/overlay/relative_order.cpp index 8d2a5b47a..9a7cda29e 100644 --- a/test/algorithms/overlay/relative_order.cpp +++ b/test/algorithms/overlay/relative_order.cpp @@ -31,9 +31,9 @@ # include #endif -#include -#include +#include +#include template void test_with_point(std::string const& /*caseid*/, diff --git a/test/strategies/spherical_side.cpp b/test/strategies/spherical_side.cpp index 2e426fa74..51345dd21 100644 --- a/test/strategies/spherical_side.cpp +++ b/test/strategies/spherical_side.cpp @@ -27,7 +27,7 @@ #include //#include #include -#include +#include #include #include diff --git a/test/strategies/test_within.hpp b/test/strategies/test_within.hpp index f4280beb0..57ffdefa1 100644 --- a/test/strategies/test_within.hpp +++ b/test/strategies/test_within.hpp @@ -21,6 +21,8 @@ #include #include +#include + #include #include #include @@ -28,7 +30,6 @@ #include #include -#include #include // TEMP From e3eb4bae2cbac767ca1ff106dcbce504fcd0771c Mon Sep 17 00:00:00 2001 From: Vissarion Fisikopoulos Date: Fri, 2 Jul 2021 16:35:32 +0300 Subject: [PATCH 03/29] Simplify the use of eps_policy in orient2d --- include/boost/geometry/util/precise_math.hpp | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/include/boost/geometry/util/precise_math.hpp b/include/boost/geometry/util/precise_math.hpp index eccf08800..e14c20fbb 100644 --- a/include/boost/geometry/util/precise_math.hpp +++ b/include/boost/geometry/util/precise_math.hpp @@ -368,28 +368,14 @@ inline RealNumber orient2d(vec2d const& p1, vec2d const& p3, EpsPolicy& eps_policy) { - auto const x = p3.x; - auto const y = p3.y; - - auto const sx1 = p1.x; - auto const sy1 = p1.y; - auto const sx2 = p2.x; - auto const sy2 = p2.y; - - - auto const dx = sx2 - sx1; - auto const dy = sy2 - sy1; - auto const dpx = x - sx1; - auto const dpy = y - sy1; - - eps_policy = EpsPolicy(dx, dy, dpx, dpy); - 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]; From c1f8ab10de002891c34561ff3e756f996171df04 Mon Sep 17 00:00:00 2001 From: Vissarion Fisikopoulos Date: Fri, 2 Jul 2021 18:03:05 +0300 Subject: [PATCH 04/29] Refactoring the policies in side_robust --- .../strategy/cartesian/side_robust.hpp | 43 +++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/include/boost/geometry/strategy/cartesian/side_robust.hpp b/include/boost/geometry/strategy/cartesian/side_robust.hpp index 61fd6827c..9d4ba785d 100644 --- a/include/boost/geometry/strategy/cartesian/side_robust.hpp +++ b/include/boost/geometry/strategy/cartesian/side_robust.hpp @@ -32,12 +32,11 @@ namespace boost { namespace geometry namespace strategy { namespace side { -struct eps_equals_policy +struct epsilon_equals_policy { public: - template - static auto apply(T1 a, T2 b, Policy policy) + static bool apply(T1 const& a, T2 const& b, Policy const& policy) { return boost::geometry::math::detail::equals_by_policy(a, b, policy); } @@ -47,7 +46,7 @@ struct fp_equals_policy { public: template - static auto apply(T1 a, T2 b, Policy) + static bool apply(T1 const& a, T2 const& b, Policy const&) { return a == b; } @@ -65,20 +64,32 @@ public: template < typename CalculationType = void, - typename EpsPolicy = eps_equals_policy, + typename EqualsPolicy = epsilon_equals_policy, std::size_t Robustness = 3 > struct side_robust { - template - struct eps_policy + + template + struct epsilon_policy { - eps_policy() {} + using Policy = boost::geometry::math::detail::equals_factor_policy; + + epsilon_policy() {} + template - eps_policy(Type const& a, Type const& b, Type const& c, Type const& d) - : policy(a, b, c, d) + epsilon_policy(Type const& a, Type const& b, Type const& c, Type const& d) + : m_policy(a, b, c, d) {} - Policy policy; + Policy m_policy; + + public: + + template + bool apply(T1 a, T2 b) const + { + return EqualsPolicy::apply(a, b, m_policy); + } }; public: @@ -152,15 +163,11 @@ public: double >::type; - eps_policy - < - boost::geometry::math::detail::equals_factor_policy - > epsp; - + epsilon_policy epsp; promoted_type sv = side_value(p1, p2, p, epsp); - promoted_type const zero = promoted_type(); - return EpsPolicy::apply(sv, zero, epsp.policy) ? 0 + + return epsp.apply(sv, zero) ? 0 : sv > zero ? 1 : -1; } From 6ca6dadede270d22a746b120a70b30cbbf02e4e2 Mon Sep 17 00:00:00 2001 From: Vissarion Fisikopoulos Date: Tue, 13 Jul 2021 13:58:01 +0300 Subject: [PATCH 05/29] Rewrite non robust side predicate --- .../strategy/cartesian/side_non_robust.hpp | 41 +++++++++++++++---- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/include/boost/geometry/strategy/cartesian/side_non_robust.hpp b/include/boost/geometry/strategy/cartesian/side_non_robust.hpp index add8e7972..9400f9bd6 100644 --- a/include/boost/geometry/strategy/cartesian/side_non_robust.hpp +++ b/include/boost/geometry/strategy/cartesian/side_non_robust.hpp @@ -14,6 +14,8 @@ #include #include +#include + namespace boost { namespace geometry { @@ -49,20 +51,43 @@ 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))); + CoordinateType const x = get<0>(p); + CoordinateType const y = get<1>(p); - return detleft > detright ? 1 : (detleft < detright ? -1 : 0 ); + 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 == 0 ? 0 : sv > zero ? 1 : -1; } }; From 6848b43f97b9c372925f0c2b768d064eeaa8c612 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Mon, 19 Jul 2021 15:18:23 +0200 Subject: [PATCH 06/29] [index] Add minmax/maxmin heap algorithms. --- .../geometry/index/detail/maxmin_heap.hpp | 107 ++++ .../geometry/index/detail/minmax_heap.hpp | 489 ++++++++++++++++++ 2 files changed, 596 insertions(+) create mode 100644 include/boost/geometry/index/detail/maxmin_heap.hpp create mode 100644 include/boost/geometry/index/detail/minmax_heap.hpp 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..18b44d918 --- /dev/null +++ b/include/boost/geometry/index/detail/minmax_heap.hpp @@ -0,0 +1,489 @@ +// 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; + if (size <= 1) + return first; + else if (size == 2) + return (first + 1); + else + return 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 From 0eff8d759d2165233d6dea58955e20a84f13a713 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Mon, 19 Jul 2021 21:18:52 +0200 Subject: [PATCH 07/29] [test][index] Add test for minmax/maxmin heap. --- index/test/Jamfile | 6 +- index/test/minmax_heap.cpp | 282 +++++++++++++++++++++++++++++++++++++ 2 files changed, 287 insertions(+), 1 deletion(-) create mode 100644 index/test/minmax_heap.cpp diff --git a/index/test/Jamfile b/index/test/Jamfile index 2b148a771..48ed5f585 100644 --- a/index/test/Jamfile +++ b/index/test/Jamfile @@ -2,6 +2,9 @@ # # Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. # +# 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) @@ -20,8 +23,9 @@ project boost-geometry-index-test /boost/timer//boost_timer ; -test-suite boost-geometry-index-varray +test-suite boost-geometry-index-detail : + [ run minmax_heap.cpp ] [ run varray_old.cpp ] [ run varray.cpp ] ; diff --git a/index/test/minmax_heap.cpp b/index/test/minmax_heap.cpp new file mode 100644 index 000000000..4dd3a7d82 --- /dev/null +++ b/index/test/minmax_heap.cpp @@ -0,0 +1,282 @@ +// 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 + +#include +#include + +#include +#include +#include + +#include +#include + +using namespace boost::geometry::index::detail; + +struct noncopyable +{ + noncopyable(int i_) : i(i_) {} + noncopyable(noncopyable const&) = delete; + noncopyable& operator=(noncopyable const&) = delete; + noncopyable(noncopyable&&) = default; + noncopyable& operator=(noncopyable&&) = default; + bool operator<(noncopyable const& other) const { return i < other.i; } + operator int() const { return i; } + int i; +}; + +template +struct minmax_default +{ + minmax_default() = default; + minmax_default(std::vector const& vec) + : heap(vec.begin(), vec.end()) + { + make_minmax_heap(heap.begin(), heap.end()); + } + T const& top() const + { + return heap[0]; + } + T const& bottom() const + { + return bottom_minmax_heap(heap.begin(), heap.end()); + } + void push(int i) + { + heap.push_back(T(i)); + push_minmax_heap(heap.begin(), heap.end()); + } + void pop_top() + { + pop_top_minmax_heap(heap.begin(), heap.end()); + heap.pop_back(); + } + void pop_bottom() + { + pop_bottom_minmax_heap(heap.begin(), heap.end()); + heap.pop_back(); + } + bool is_heap() const + { + return is_minmax_heap(heap.begin(), heap.end()); + } + bool empty() const + { + return heap.empty(); + } + std::vector heap; +}; + +template +struct minmax_less +{ + minmax_less() = default; + minmax_less(std::vector const& vec) + : heap(vec.begin(), vec.end()) + { + make_minmax_heap(heap.begin(), heap.end(), std::less<>()); + } + T const& top() const + { + return heap[0]; + } + T const& bottom() const + { + return bottom_minmax_heap(heap.begin(), heap.end(), std::less<>()); + } + void push(int i) + { + heap.push_back(T(i)); + push_minmax_heap(heap.begin(), heap.end(), std::less<>()); + } + void pop_top() + { + pop_top_minmax_heap(heap.begin(), heap.end(), std::less<>()); + heap.pop_back(); + } + void pop_bottom() + { + pop_bottom_minmax_heap(heap.begin(), heap.end(), std::less<>()); + heap.pop_back(); + } + bool is_heap() const + { + return is_minmax_heap(heap.begin(), heap.end(), std::less<>()); + } + bool empty() const + { + return heap.empty(); + } + std::vector heap; +}; + +template +struct maxmin_greater +{ + maxmin_greater() = default; + maxmin_greater(std::vector const& vec) + : heap(vec.begin(), vec.end()) + { + make_maxmin_heap(heap.begin(), heap.end(), std::greater<>()); + } + T const& top() const + { + return heap[0]; + } + T const& bottom() const + { + return bottom_maxmin_heap(heap.begin(), heap.end(), std::greater<>()); + } + void push(int i) + { + heap.push_back(T(i)); + push_maxmin_heap(heap.begin(), heap.end(), std::greater<>()); + } + void pop_top() + { + pop_top_maxmin_heap(heap.begin(), heap.end(), std::greater<>()); + heap.pop_back(); + } + void pop_bottom() + { + pop_bottom_maxmin_heap(heap.begin(), heap.end(), std::greater<>()); + heap.pop_back(); + } + bool is_heap() const + { + return is_maxmin_heap(heap.begin(), heap.end(), std::greater<>()); + } + bool empty() const + { + return heap.empty(); + } + std::vector heap; +}; + +template +struct maxmin_default_switch +{ + maxmin_default_switch() = default; + maxmin_default_switch(std::vector const& vec) + : heap(vec.begin(), vec.end()) + { + make_maxmin_heap(heap.begin(), heap.end()); + } + T const& bottom() const + { + return heap[0]; + } + T const& top() const + { + return bottom_maxmin_heap(heap.begin(), heap.end()); + } + void push(int i) + { + heap.push_back(T(i)); + push_maxmin_heap(heap.begin(), heap.end()); + } + void pop_top() + { + pop_bottom_maxmin_heap(heap.begin(), heap.end()); + heap.pop_back(); + } + void pop_bottom() + { + pop_top_maxmin_heap(heap.begin(), heap.end()); + heap.pop_back(); + } + bool is_heap() const + { + return is_maxmin_heap(heap.begin(), heap.end()); + } + bool empty() const + { + return heap.empty(); + } + std::vector heap; +}; + +template +void test() +{ + std::vector vec; + int const n = 20; + for (int i = 0; i < n; ++i) + { + vec.push_back(rand() % n); + } + + { + std::map map; + Heap heap; + for (int i : vec) + { + heap.push(i); + BOOST_CHECK(heap.is_heap()); + + map[i]++; + BOOST_CHECK_EQUAL(heap.top(), map.begin()->first); + BOOST_CHECK_EQUAL(heap.bottom(), (--map.end())->first); + } + + while (! heap.empty()) + { + int i = heap.top(); + BOOST_CHECK_EQUAL(i, map.begin()->first); + BOOST_CHECK_EQUAL(heap.bottom(), (--map.end())->first); + BOOST_CHECK(map[i] > 0); + map[i]--; + if (map[i] <= 0) + map.erase(i); + + heap.pop_top(); + BOOST_CHECK(heap.is_heap()); + } + + BOOST_CHECK(map.empty()); + } + + { + Heap heap(vec); + BOOST_CHECK(heap.is_heap()); + + std::map map; + for (int i : vec) + map[i]++; + BOOST_CHECK_EQUAL(heap.top(), map.begin()->first); + BOOST_CHECK_EQUAL(heap.bottom(), (--map.end())->first); + + while (! heap.empty()) + { + int i = heap.bottom(); + BOOST_CHECK_EQUAL(heap.top(), map.begin()->first); + BOOST_CHECK_EQUAL(i, (--map.end())->first); + BOOST_CHECK(map[i] > 0); + map[i]--; + if (map[i] <= 0) + map.erase(i); + + heap.pop_bottom(); + BOOST_CHECK(heap.is_heap()); + } + + BOOST_CHECK(map.empty()); + } +} + +int test_main(int, char* []) +{ + test>(); + test>(); + test>(); + test>(); + test>(); + + return 0; +} From c0886c35ae00e5865e8a2587bff598b876519df5 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Tue, 20 Jul 2021 18:51:31 +0200 Subject: [PATCH 08/29] [index] Add priority_dequeue based on maxmin heap. --- .../index/detail/priority_dequeue.hpp | 155 ++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 include/boost/geometry/index/detail/priority_dequeue.hpp 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..0ef7b49b8 --- /dev/null +++ b/include/boost/geometry/index/detail/priority_dequeue.hpp @@ -0,0 +1,155 @@ +// 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 clear() + { + c.clear(); + } + + 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 From 5d9a03a9438a67e8f46755bec8f8881608c2c940 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Tue, 20 Jul 2021 18:53:08 +0200 Subject: [PATCH 09/29] [index] Replace sort with priority_dequeue in iterative knn query. --- .../geometry/index/detail/predicates.hpp | 8 +- .../detail/rtree/visitors/distance_query.hpp | 263 +++++++++--------- .../detail/rtree/visitors/spatial_query.hpp | 41 +-- 3 files changed, 148 insertions(+), 164 deletions(-) diff --git a/include/boost/geometry/index/detail/predicates.hpp b/include/boost/geometry/index/detail/predicates.hpp index 0ae8defe8..22db3bf35 100644 --- a/include/boost/geometry/index/detail/predicates.hpp +++ b/include/boost/geometry/index/detail/predicates.hpp @@ -619,11 +619,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/rtree/visitors/distance_query.hpp b/include/boost/geometry/index/detail/rtree/visitors/distance_query.hpp index a40dbfe84..df48ee0b7 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,10 @@ #ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_DISTANCE_QUERY_HPP #define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_DISTANCE_QUERY_HPP +#include + +#include + namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace visitors { @@ -40,6 +44,16 @@ struct pair_first_greater } }; +template +struct priority_queue : std::priority_queue, Comp> +{ + priority_queue() = default; + void clear() + { + this->c.clear(); + } +}; + template class distance_query_result @@ -140,8 +154,6 @@ 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; - inline distance_query(parameters_type const& parameters, translator_type const& translator, Predicates const& pred, OutIter out_it) : m_parameters(parameters), m_translator(translator) , m_pred(pred) @@ -151,29 +163,26 @@ public: inline void operator()(internal_node const& n) { - typedef typename rtree::elements_type::type elements_type; + namespace id = index::detail; // array of active nodes - typedef typename index::detail::rtree::container_from_elements_type< - elements_type, - std::pair - >::type active_branch_list_type; + using active_branch_list_type = typename index::detail::rtree::container_from_elements_type + < + typename rtree::elements_type::type, + std::pair + >::type; active_branch_list_type active_branch_list; active_branch_list.reserve(m_parameters.get_max_elements()); - elements_type const& elements = rtree::elements(n); + auto const& elements = rtree::elements(n); // fill array of nodes meeting predicates - for (typename elements_type::const_iterator it = elements.begin(); - it != elements.end(); ++it) + for (auto 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) ) + if (id::predicates_check(m_pred, 0, it->first, m_strategy) ) { // calculate node's distance(s) for distance predicate node_distance_type node_distance; @@ -204,8 +213,7 @@ public: 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 ) + for (auto 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() && @@ -245,18 +253,15 @@ public: inline void operator()(leaf const& n) { - typedef typename rtree::elements_type::type elements_type; - elements_type const& elements = rtree::elements(n); + namespace id = index::detail; + + auto 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) + for (auto 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) ) + if (id::predicates_check(m_pred, *it, m_translator(*it), m_strategy)) { // calculate values distance for distance predicate value_distance_type value_distance; @@ -331,88 +336,93 @@ 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 branch_data = std::pair; + using branches_type = priority_queue; + using neighbor_data = std::pair; + using neighbors_type = priority_dequeue, pair_first_greater>; inline distance_query_incremental() - : m_translator(NULL) + : m_translator(nullptr) // , m_pred() - , current_neighbor((std::numeric_limits::max)()) + , m_neighbors_count(0) + , m_neighbor_ptr(nullptr) // , m_strategy_type() {} inline distance_query_incremental(parameters_type const& params, translator_type const& translator, Predicates const& pred) : m_translator(::boost::addressof(translator)) , m_pred(pred) - , current_neighbor((std::numeric_limits::max)()) + , m_neighbors_count(0) + , m_neighbor_ptr(nullptr) , m_strategy(index::detail::get_strategy(params)) - { - BOOST_GEOMETRY_INDEX_ASSERT(0 < max_count(), "k must be greather than 0"); - } + {} const_reference dereference() const { - return *(neighbors[current_neighbor].second); + return *m_neighbor_ptr; } void initialize(node_pointer root) { - rtree::apply_visitor(*this, *root); - increment(); + if (0 < max_count()) + { + rtree::apply_visitor(*this, *root); + 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.first ) { - 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 (m_neighbors_count + m_neighbors.size() == max_count() + && (m_neighbors.empty() || m_neighbors.bottom().first <= closest_branch.first)) { - 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(); + m_branches.pop(); rtree::apply_visitor(*this, *ptr); } @@ -422,17 +432,12 @@ 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 @@ -440,39 +445,37 @@ public: // and aren't further than found neighbours (if there is enough neighbours) inline void operator()(internal_node const& n) { - typedef typename rtree::elements_type::type elements_type; - elements_type const& elements = rtree::elements(n); + namespace id = index::detail; + + auto 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 ) + for (auto it = elements.begin() ; it != elements.end() ; ++it) { - // if current node meets predicates + // if current node doesn't meet predicates // 0 - dummy value - 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)) { - // 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 ( max_count() <= neighbors.size() && - neighbors.back().first <= node_distance ) - { - continue; - } - - // 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()); + continue; } + + // calculate node's distance(s) for distance predicate + node_distance_type node_distance; + // if distance isn't ok + if (! calculate_node_distance::apply(predicate(), it->first, m_strategy, node_distance)) + { + continue; + } + + // if there is enough neighbors and there is no closer branch + if (m_neighbors_count + m_neighbors.size() == max_count() + && (m_neighbors.empty() || m_neighbors.bottom().first <= node_distance)) + { + continue; + } + + // add current node into the queue + m_branches.push(std::make_pair(node_distance, it->second)); } } @@ -481,49 +484,42 @@ public: // 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); + namespace id = index::detail; + + auto 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) + for (auto 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) ) + // if value doesn't meet predicates + if (! id::predicates_check(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) ) - { - // if there is not enough values or current value is closer than furthest neighbour - if ( not_enough_neighbors || value_distance < greatest_distance ) - { - neighbors.push_back(std::make_pair(value_distance, boost::addressof(*it))); - } - } + continue; + } + + // calculate values distance for distance predicate + value_distance_type value_distance; + // if distance isn't ok + if (! calculate_value_distance::apply(predicate(), (*m_translator)(*it), + m_strategy, value_distance)) + { + continue; + } + + // if there is enough neighbors and there is no closer neighbor + if (m_neighbors_count + m_neighbors.size() == max_count() + && (m_neighbors.empty() || m_neighbors.bottom().first <= value_distance)) + { + continue; + } + + // add current value into the queue + m_neighbors.push(std::make_pair(value_distance, boost::addressof(*it))); + if (m_neighbors_count + m_neighbors.size() > max_count()) + { + 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: @@ -541,9 +537,10 @@ private: Predicates m_pred; - internal_heap_type internal_heap; - std::vector< std::pair > neighbors; - size_type current_neighbor; + branches_type m_branches; + neighbors_type m_neighbors; + size_type m_neighbors_count; + const value_type * m_neighbor_ptr; strategy_type m_strategy; }; 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..f4799137e 100644 --- a/include/boost/geometry/index/detail/rtree/visitors/spatial_query.hpp +++ b/include/boost/geometry/index/detail/rtree/visitors/spatial_query.hpp @@ -35,27 +35,22 @@ struct spatial_query 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)) {} inline void operator()(internal_node const& n) { - typedef typename rtree::elements_type::type elements_type; - elements_type const& elements = rtree::elements(n); + namespace id = index::detail; + + auto const& elements = rtree::elements(n); // traverse nodes meeting predicates - for (typename elements_type::const_iterator it = elements.begin(); - it != elements.end(); ++it) + for (auto it = elements.begin(); it != elements.end(); ++it) { // if node meets predicates // 0 - dummy value - if ( index::detail::predicates_check - < - index::detail::bounds_tag, 0, predicates_len - >(pred, 0, it->first, strategy) ) + if (id::predicates_check(pred, 0, it->first, strategy)) { rtree::apply_visitor(*this, *it->second); } @@ -64,18 +59,15 @@ struct spatial_query inline void operator()(leaf const& n) { - typedef typename rtree::elements_type::type elements_type; - elements_type const& elements = rtree::elements(n); + namespace id = index::detail; + + auto const& elements = rtree::elements(n); // get all values meeting predicates - for (typename elements_type::const_iterator it = elements.begin(); - it != elements.end(); ++it) + for (auto it = elements.begin(); it != elements.end(); ++it) { // if value meets predicates - if ( index::detail::predicates_check - < - index::detail::value_tag, 0, predicates_len - >(pred, *it, tr(*it), strategy) ) + if (id::predicates_check(pred, *it, tr(*it), strategy)) { *out_iter = *it; ++out_iter; @@ -119,8 +111,6 @@ 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; - inline spatial_query_incremental() : m_translator(NULL) // , m_pred() @@ -171,6 +161,7 @@ public: void search_value() { + namespace id = index::detail; for (;;) { // if leaf is choosen, move to the next value in leaf @@ -180,10 +171,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; } @@ -214,10 +202,7 @@ public: ++m_internal_stack.back().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)); } From 6daaf2162d762fc344c12a9a4b864d789f4305db Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Thu, 22 Jul 2021 02:02:04 +0200 Subject: [PATCH 10/29] [index] Refactor distance_query, remove recursion, change branches handling. Remove recursion, keep one container of branches to traverse. Replace stack of sorted branches per level with priority_queue. Prioritize branches based on distance and level to traverse the closest and the deepest nodes first. --- .../index/detail/priority_dequeue.hpp | 5 - .../detail/rtree/visitors/distance_query.hpp | 314 +++++++++--------- include/boost/geometry/index/rtree.hpp | 9 +- 3 files changed, 156 insertions(+), 172 deletions(-) diff --git a/include/boost/geometry/index/detail/priority_dequeue.hpp b/include/boost/geometry/index/detail/priority_dequeue.hpp index 0ef7b49b8..bbe563aba 100644 --- a/include/boost/geometry/index/detail/priority_dequeue.hpp +++ b/include/boost/geometry/index/detail/priority_dequeue.hpp @@ -133,11 +133,6 @@ public: return c.size(); } - void clear() - { - c.clear(); - } - void swap(priority_dequeue& other) { using std::swap; 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 df48ee0b7..e4f53ffe6 100644 --- a/include/boost/geometry/index/detail/rtree/visitors/distance_query.hpp +++ b/include/boost/geometry/index/detail/rtree/visitors/distance_query.hpp @@ -45,89 +45,97 @@ struct pair_first_greater }; template -struct priority_queue : std::priority_queue, Comp> +struct priority_dequeue : index::detail::priority_dequeue, Comp> { - priority_queue() = default; + priority_dequeue() = default; + void reserve(typename std::vector::size_type n) + { + this->c.reserve(n); + } void clear() { this->c.clear(); } }; +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(); + } +}; -template +template class distance_query_result { -public: - typedef DistanceType distance_type; + using neighbor_data = std::pair; + using neighbors_type = std::vector; + using size_type = typename neighbors_type::size_type; - inline explicit distance_query_result(size_t k, OutIt out_it) - : m_count(k), m_out_it(out_it) +public: + 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) + 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 + 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; - - std::vector< std::pair > m_neighbors; + size_type m_count; + neighbors_type m_neighbors; }; template < typename MembersHolder, typename Predicates, - std::size_t DistancePredicateIndex, - typename OutIter + std::size_t DistancePredicateIndex > class distance_query : public MembersHolder::visitor_const @@ -154,140 +162,126 @@ public: typedef typename calculate_value_distance::result_type value_distance_type; typedef typename calculate_node_distance::result_type node_distance_type; - inline distance_query(parameters_type const& parameters, translator_type const& translator, Predicates const& pred, OutIter out_it) + typedef typename allocators_type::size_type size_type; + typedef typename allocators_type::node_pointer node_pointer; + + struct branch_data + { + branch_data(node_distance_type d, size_type l, node_pointer p) + : distance(d), level(l), ptr(p) + {} + + node_distance_type distance; + size_type level; + node_pointer ptr; + }; + + struct branch_data_comp + { + bool operator()(branch_data const& b1, branch_data const& b2) const + { + return b1.distance > b2.distance || (b1.distance == b2.distance && b1.level < b2.level); + } + }; + + inline distance_query(parameters_type const& parameters, translator_type const& translator, Predicates const& pred) : m_parameters(parameters), m_translator(translator) , m_pred(pred) - , m_result(nearest_predicate_access::get(m_pred).count, out_it) + , m_result(nearest_predicate_access::get(m_pred).count) , m_strategy(index::detail::get_strategy(parameters)) - {} + { + //m_branches.reserve(m_parameters.get_max_elements() * levels_count); ? + } + + template + size_type apply(node_pointer root, OutIter out_it) + { + m_level = 1; + rtree::apply_visitor(*this, *root); + + for (;;) + { + if (m_branches.empty()) + { + break; + } + + if (m_result.ignore_branch(m_branches.top().distance)) + { + break; + } + + node_pointer ptr = m_branches.top().ptr; + m_level = m_branches.top().level + 1; + m_branches.pop(); + rtree::apply_visitor(*this, *ptr); + } + + return m_result.finish(out_it); + } inline void operator()(internal_node const& n) { namespace id = index::detail; - // array of active nodes - using active_branch_list_type = typename index::detail::rtree::container_from_elements_type - < - typename rtree::elements_type::type, - std::pair - >::type; - - active_branch_list_type active_branch_list; - active_branch_list.reserve(m_parameters.get_max_elements()); - - auto const& elements = rtree::elements(n); - // fill array of nodes meeting predicates - for (auto it = elements.begin(); it != elements.end(); ++it) + for (auto const& p : rtree::elements(n)) { // if current node meets predicates // 0 - dummy value - if (id::predicates_check(m_pred, 0, it->first, m_strategy) ) + if (! id::predicates_check(m_pred, 0, p.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) ); + continue; } + + // 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(), p.first, + m_strategy, node_distance)) + { + continue; + } + + // if current node is further than found neighbors - don't analyze it + if (m_result.ignore_branch(node_distance)) + { + continue; + } + + // add current node's data into the list + m_branches.push(branch_data(node_distance, m_level, p.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 (auto 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(); - //} } inline void operator()(leaf const& n) { namespace id = index::detail; - auto const& elements = rtree::elements(n); - // search leaf for closest value meeting predicates - for (auto it = elements.begin(); it != elements.end(); ++it) + for (auto const& v : rtree::elements(n)) { // if value meets predicates - if (id::predicates_check(m_pred, *it, m_translator(*it), m_strategy)) + if (! id::predicates_check(m_pred, v, m_translator(v), 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); - } + continue; } + + // calculate values distance for distance predicate + value_distance_type value_distance; + // if distance is ok + if (! calculate_value_distance::apply(predicate(), m_translator(v), + m_strategy, value_distance)) + { + continue; + } + + // store value + m_result.store(value_distance, boost::addressof(v)); } } - inline size_t finish() - { - return m_result.finish(); - } - private: - template - static inline bool is_node_prunable(Distance const& greatest_dist, node_distance_type const& d) - { - return greatest_dist <= d; - } - nearest_predicate_type const& predicate() const { return nearest_predicate_access::get(m_pred); @@ -297,7 +291,9 @@ private: translator_type const& m_translator; Predicates m_pred; - distance_query_result m_result; + distance_query_result m_result; + priority_queue m_branches; + size_type m_level; strategy_type m_strategy; }; @@ -343,7 +339,7 @@ public: using branch_data = std::pair; using branches_type = priority_queue; using neighbor_data = std::pair; - using neighbors_type = priority_dequeue, pair_first_greater>; + using neighbors_type = priority_dequeue; inline distance_query_incremental() : m_translator(nullptr) @@ -447,14 +443,12 @@ public: { namespace id = index::detail; - auto const& elements = rtree::elements(n); - // fill active branch list array of nodes meeting predicates - for (auto it = elements.begin() ; it != elements.end() ; ++it) + for (auto const& p : rtree::elements(n)) { // if current node doesn't meet predicates // 0 - dummy value - if (! id::predicates_check(m_pred, 0, it->first, m_strategy)) + if (! id::predicates_check(m_pred, 0, p.first, m_strategy)) { continue; } @@ -462,7 +456,7 @@ public: // calculate node's distance(s) for distance predicate node_distance_type node_distance; // if distance isn't ok - if (! calculate_node_distance::apply(predicate(), it->first, m_strategy, node_distance)) + if (! calculate_node_distance::apply(predicate(), p.first, m_strategy, node_distance)) { continue; } @@ -475,7 +469,7 @@ public: } // add current node into the queue - m_branches.push(std::make_pair(node_distance, it->second)); + m_branches.push(std::make_pair(node_distance, p.second)); } } @@ -486,13 +480,11 @@ public: { namespace id = index::detail; - auto const& elements = rtree::elements(n); - // search leaf for closest value meeting predicates - for (auto it = elements.begin() ; it != elements.end() ; ++it) + for (auto const& v : rtree::elements(n)) { // if value doesn't meet predicates - if (! id::predicates_check(m_pred, *it, (*m_translator)(*it), m_strategy)) + if (! id::predicates_check(m_pred, v, (*m_translator)(v), m_strategy)) { continue; } @@ -500,7 +492,7 @@ public: // calculate values distance for distance predicate value_distance_type value_distance; // if distance isn't ok - if (! calculate_value_distance::apply(predicate(), (*m_translator)(*it), + if (! calculate_value_distance::apply(predicate(), (*m_translator)(v), m_strategy, value_distance)) { continue; @@ -514,7 +506,7 @@ public: } // add current value into the queue - m_neighbors.push(std::make_pair(value_distance, boost::addressof(*it))); + m_neighbors.push(std::make_pair(value_distance, boost::addressof(v))); if (m_neighbors_count + m_neighbors.size() > max_count()) { m_neighbors.pop_bottom(); diff --git a/include/boost/geometry/index/rtree.hpp b/include/boost/geometry/index/rtree.hpp index 2b7e3811d..24eba480f 100644 --- a/include/boost/geometry/index/rtree.hpp +++ b/include/boost/geometry/index/rtree.hpp @@ -1920,13 +1920,10 @@ private: detail::rtree::visitors::distance_query< members_holder, Predicates, - distance_predicate_index, - OutIter - > distance_v(m_members.parameters(), m_members.translator(), predicates, out_it); + distance_predicate_index + > distance_v(m_members.parameters(), m_members.translator(), predicates); - detail::rtree::apply_visitor(distance_v, *m_members.root); - - return distance_v.finish(); + return distance_v.apply(m_members.root, out_it); } /*! From 5701d7bef0a6d167edf259d8c1e0dfe1c253dfd7 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Thu, 22 Jul 2021 14:59:27 +0200 Subject: [PATCH 11/29] [index] Refactor spatial_query, remove recursion. --- .../detail/rtree/visitors/spatial_query.hpp | 39 ++++++++++++++----- include/boost/geometry/index/rtree.hpp | 4 +- 2 files changed, 30 insertions(+), 13 deletions(-) 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 f4799137e..4aa579530 100644 --- a/include/boost/geometry/index/detail/rtree/visitors/spatial_query.hpp +++ b/include/boost/geometry/index/detail/rtree/visitors/spatial_query.hpp @@ -33,26 +33,44 @@ 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; 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)) {} + size_type apply(node_pointer root) + { + rtree::apply_visitor(*this, *root); + + for (;;) + { + if (m_internal_stack.empty()) + { + break; + } + + node_pointer ptr = m_internal_stack.back(); + m_internal_stack.pop_back(); + rtree::apply_visitor(*this, *ptr); + } + + return found_count; + } + inline void operator()(internal_node const& n) { namespace id = index::detail; - auto const& elements = rtree::elements(n); - // traverse nodes meeting predicates - for (auto it = elements.begin(); it != elements.end(); ++it) + for (auto const& p : rtree::elements(n)) { // if node meets predicates // 0 - dummy value - if (id::predicates_check(pred, 0, it->first, strategy)) + if (id::predicates_check(pred, 0, p.first, strategy)) { - rtree::apply_visitor(*this, *it->second); + m_internal_stack.push_back(p.second); } } } @@ -61,15 +79,13 @@ struct spatial_query { namespace id = index::detail; - auto const& elements = rtree::elements(n); - // get all values meeting predicates - for (auto it = elements.begin(); it != elements.end(); ++it) + for (auto const& v : rtree::elements(n)) { // if value meets predicates - if (id::predicates_check(pred, *it, tr(*it), strategy)) + if (id::predicates_check(pred, v, tr(v), strategy)) { - *out_iter = *it; + *out_iter = v; ++out_iter; ++found_count; @@ -77,10 +93,13 @@ struct spatial_query } } +private: translator_type const& tr; Predicates pred; + std::vector m_internal_stack; + OutIter out_iter; size_type found_count; diff --git a/include/boost/geometry/index/rtree.hpp b/include/boost/geometry/index/rtree.hpp index 24eba480f..5a4941cfb 100644 --- a/include/boost/geometry/index/rtree.hpp +++ b/include/boost/geometry/index/rtree.hpp @@ -1900,9 +1900,7 @@ private: 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; + return find_v.apply(m_members.root); } /*! From f838b88a9d852aba997fc073df2ca4ffaf7ebdd0 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Thu, 22 Jul 2021 17:16:35 +0200 Subject: [PATCH 12/29] [index] Simplify rtree query(), qbegin() and qend(). --- .../index/detail/rtree/query_iterators.hpp | 8 +- .../detail/rtree/visitors/distance_query.hpp | 48 ++++--- .../detail/rtree/visitors/spatial_query.hpp | 2 + include/boost/geometry/index/rtree.hpp | 119 ++++++------------ 4 files changed, 69 insertions(+), 108 deletions(-) diff --git a/include/boost/geometry/index/detail/rtree/query_iterators.hpp b/include/boost/geometry/index/detail/rtree/query_iterators.hpp index 8822bcf04..28b19aed0 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, @@ -134,14 +134,14 @@ private: visitor_type m_visitor; }; -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 visitors::distance_query_incremental visitor_type; typedef typename visitor_type::node_pointer node_pointer; public: 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 e4f53ffe6..b7d119f10 100644 --- a/include/boost/geometry/index/detail/rtree/visitors/distance_query.hpp +++ b/include/boost/geometry/index/detail/rtree/visitors/distance_query.hpp @@ -17,6 +17,7 @@ #include +#include #include namespace boost { namespace geometry { namespace index { @@ -48,24 +49,24 @@ 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(); - } + //void reserve(typename std::vector::size_type n) + //{ + // this->c.reserve(n); + //} + //void clear() + //{ + // this->c.clear(); + //} }; template struct priority_queue : std::priority_queue, Comp> { priority_queue() = default; - void reserve(typename std::vector::size_type n) - { - this->c.reserve(n); - } + //void reserve(typename std::vector::size_type n) + //{ + // this->c.reserve(n); + //} void clear() { this->c.clear(); @@ -131,12 +132,7 @@ private: neighbors_type m_neighbors; }; -template -< - typename MembersHolder, - typename Predicates, - std::size_t DistancePredicateIndex -> +template class distance_query : public MembersHolder::visitor_const { @@ -153,7 +149,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; @@ -298,11 +297,7 @@ private: strategy_type m_strategy; }; -template < - typename MembersHolder, - typename Predicates, - std::size_t DistancePredicateIndex -> +template class distance_query_incremental : public MembersHolder::visitor_const { @@ -319,7 +314,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; 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 4aa579530..77ce05ce9 100644 --- a/include/boost/geometry/index/detail/rtree/visitors/spatial_query.hpp +++ b/include/boost/geometry/index/detail/rtree/visitors/spatial_query.hpp @@ -15,6 +15,8 @@ #ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_SPATIAL_QUERY_HPP #define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_SPATIAL_QUERY_HPP +#include + namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace visitors { diff --git a/include/boost/geometry/index/rtree.hpp b/include/boost/geometry/index/rtree.hpp index 5a4941cfb..e0a5e001d 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.root, m_members.parameters(), m_members.translator(), predicates) + : query_iterator_t(m_members.parameters(), m_members.translator(), 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,8 +1849,12 @@ 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); @@ -1909,17 +1868,19 @@ 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 - > distance_v(m_members.parameters(), m_members.translator(), predicates); + detail::rtree::visitors::distance_query + distance_v(m_members.parameters(), m_members.translator(), predicates); return distance_v.apply(m_members.root, out_it); } From 5ceb8a3b2e43eb9749d709b5a918d433edcd2802 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Thu, 22 Jul 2021 22:29:02 +0200 Subject: [PATCH 13/29] [index] Rewrite predicate checks in query visitors. --- .../detail/rtree/visitors/distance_query.hpp | 165 ++++++++---------- .../detail/rtree/visitors/spatial_query.hpp | 28 ++- 2 files changed, 81 insertions(+), 112 deletions(-) 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 b7d119f10..43a943e20 100644 --- a/include/boost/geometry/index/detail/rtree/visitors/distance_query.hpp +++ b/include/boost/geometry/index/detail/rtree/visitors/distance_query.hpp @@ -84,11 +84,10 @@ public: 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); } + // NOTE: Do not call if max_count() == 0 inline void store(DistanceType const& distance, const Value * value_ptr) { if (m_neighbors.size() < m_count) @@ -109,6 +108,7 @@ public: } } + // NOTE: Do not call if max_count() == 0 inline bool ignore_branch(DistanceType const& distance) const { return m_neighbors.size() == m_count @@ -127,6 +127,11 @@ public: return m_neighbors.size(); } + size_type max_count() const + { + return m_count; + } + private: size_type m_count; neighbors_type m_neighbors; @@ -184,28 +189,29 @@ public: }; inline distance_query(parameters_type const& parameters, translator_type const& translator, Predicates const& pred) - : m_parameters(parameters), m_translator(translator) + : m_tr(translator) , m_pred(pred) , m_result(nearest_predicate_access::get(m_pred).count) , m_strategy(index::detail::get_strategy(parameters)) { - //m_branches.reserve(m_parameters.get_max_elements() * levels_count); ? + //m_branches.reserve(parameters.get_max_elements() * levels_count); ? } template size_type apply(node_pointer root, OutIter out_it) { + if (m_result.max_count() <= 0) + { + return 0; + } + m_level = 1; rtree::apply_visitor(*this, *root); for (;;) { - if (m_branches.empty()) - { - break; - } - - if (m_result.ignore_branch(m_branches.top().distance)) + if (m_branches.empty() + || m_result.ignore_branch(m_branches.top().distance)) { break; } @@ -226,30 +232,18 @@ public: // fill array of nodes meeting predicates for (auto const& p : rtree::elements(n)) { - // if current node meets predicates - // 0 - dummy value - if (! id::predicates_check(m_pred, 0, p.first, m_strategy)) - { - continue; - } + node_distance_type node_distance; // for distance predicate - // 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(), p.first, - m_strategy, 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 + && ! m_result.ignore_branch(node_distance)) { - continue; + // add current node's data into the list + m_branches.push(branch_data(node_distance, m_level, p.second)); } - - // if current node is further than found neighbors - don't analyze it - if (m_result.ignore_branch(node_distance)) - { - continue; - } - - // add current node's data into the list - m_branches.push(branch_data(node_distance, m_level, p.second)); } } @@ -260,23 +254,16 @@ public: // 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_translator(v), m_strategy)) + 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)) { - continue; + // store value + m_result.store(value_distance, boost::addressof(v)); } - - // calculate values distance for distance predicate - value_distance_type value_distance; - // if distance is ok - if (! calculate_value_distance::apply(predicate(), m_translator(v), - m_strategy, value_distance)) - { - continue; - } - - // store value - m_result.store(value_distance, boost::addressof(v)); } } @@ -286,10 +273,10 @@ private: return nearest_predicate_access::get(m_pred); } - parameters_type const& m_parameters; - translator_type const& m_translator; + translator_type const& m_tr; Predicates m_pred; + distance_query_result m_result; priority_queue m_branches; size_type m_level; @@ -340,7 +327,7 @@ public: using neighbors_type = priority_dequeue; inline distance_query_incremental() - : m_translator(nullptr) + : m_tr(nullptr) // , m_pred() , m_neighbors_count(0) , m_neighbor_ptr(nullptr) @@ -348,7 +335,7 @@ public: {} inline distance_query_incremental(parameters_type const& params, translator_type const& translator, Predicates const& pred) - : m_translator(::boost::addressof(translator)) + : m_tr(::boost::addressof(translator)) , m_pred(pred) , m_neighbors_count(0) , m_neighbor_ptr(nullptr) @@ -407,8 +394,7 @@ public: 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 (m_neighbors_count + m_neighbors.size() == max_count() - && (m_neighbors.empty() || m_neighbors.bottom().first <= closest_branch.first)) + if (ignore_branch_or_value(closest_branch.first)) { m_branches.clear(); continue; @@ -444,30 +430,18 @@ public: // fill active branch list array of nodes meeting predicates for (auto const& p : rtree::elements(n)) { - // if current node doesn't meet predicates - // 0 - dummy value - if (! id::predicates_check(m_pred, 0, p.first, m_strategy)) - { - continue; - } + node_distance_type node_distance; // for distance predicate - // calculate node's distance(s) for distance predicate - node_distance_type node_distance; - // if distance isn't ok - if (! calculate_node_distance::apply(predicate(), p.first, m_strategy, 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(std::make_pair(node_distance, p.second)); } - - // if there is enough neighbors and there is no closer branch - if (m_neighbors_count + m_neighbors.size() == max_count() - && (m_neighbors.empty() || m_neighbors.bottom().first <= node_distance)) - { - continue; - } - - // add current node into the queue - m_branches.push(std::make_pair(node_distance, p.second)); } } @@ -481,38 +455,35 @@ public: // search leaf for closest value meeting predicates for (auto const& v : rtree::elements(n)) { - // if value doesn't meet predicates - if (! id::predicates_check(m_pred, v, (*m_translator)(v), m_strategy)) - { - continue; - } - - // calculate values distance for distance predicate - value_distance_type value_distance; - // if distance isn't ok - if (! calculate_value_distance::apply(predicate(), (*m_translator)(v), - m_strategy, value_distance)) - { - continue; - } + value_distance_type value_distance; // for distance predicate - // if there is enough neighbors and there is no closer neighbor - if (m_neighbors_count + m_neighbors.size() == max_count() - && (m_neighbors.empty() || m_neighbors.bottom().first <= value_distance)) + // 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)) { - continue; - } + // add current value into the queue + m_neighbors.push(std::make_pair(value_distance, boost::addressof(v))); - // add current value into the queue - m_neighbors.push(std::make_pair(value_distance, boost::addressof(v))); - if (m_neighbors_count + m_neighbors.size() > max_count()) - { - m_neighbors.pop_bottom(); + // remove unneeded value + if (m_neighbors_count + m_neighbors.size() > max_count()) + { + m_neighbors.pop_bottom(); + } } } } private: + template + inline 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); + } + inline std::size_t max_count() const { return nearest_predicate_access::get(m_pred).count; @@ -523,7 +494,7 @@ private: return nearest_predicate_access::get(m_pred); } - const translator_type * m_translator; + const translator_type * m_tr; Predicates m_pred; 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 77ce05ce9..64d7585bf 100644 --- a/include/boost/geometry/index/detail/rtree/visitors/spatial_query.hpp +++ b/include/boost/geometry/index/detail/rtree/visitors/spatial_query.hpp @@ -39,7 +39,7 @@ struct spatial_query typedef typename allocators_type::size_type size_type; 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)) + : m_tr(t), m_pred(p), m_out_iter(out_it), m_found_count(0), m_strategy(index::detail::get_strategy(par)) {} size_type apply(node_pointer root) @@ -58,7 +58,7 @@ struct spatial_query rtree::apply_visitor(*this, *ptr); } - return found_count; + return m_found_count; } inline void operator()(internal_node const& n) @@ -68,9 +68,8 @@ struct spatial_query // traverse nodes meeting predicates for (auto const& p : rtree::elements(n)) { - // if node meets predicates - // 0 - dummy value - if (id::predicates_check(pred, 0, p.first, strategy)) + // if node meets predicates (0 is dummy value) + if (id::predicates_check(m_pred, 0, p.first, m_strategy)) { m_internal_stack.push_back(p.second); } @@ -85,27 +84,26 @@ struct spatial_query for (auto const& v : rtree::elements(n)) { // if value meets predicates - if (id::predicates_check(pred, v, tr(v), strategy)) + if (id::predicates_check(m_pred, v, m_tr(v), m_strategy)) { - *out_iter = v; - ++out_iter; - - ++found_count; + *m_out_iter = v; + ++m_out_iter; + ++m_found_count; } } } private: - translator_type const& tr; + translator_type const& m_tr; - Predicates pred; + Predicates m_pred; std::vector m_internal_stack; - OutIter out_iter; - size_type found_count; + OutIter m_out_iter; + size_type m_found_count; - strategy_type strategy; + strategy_type m_strategy; }; template From 640f2ee3b5cb5685dcee474df270c82dab8f85d1 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Thu, 29 Jul 2021 22:06:37 +0200 Subject: [PATCH 14/29] [index] Traverse nodes differently in iterative distance query. In iterative distance query prioritize also based on level. This should ensure that leafs are reached asap in case there are many internal nodes with the same distance. Replace apply_visitor with get() after manually checking level. This is the first step to support weak nodes - non-variant nodes without an id stored internally to distinguish between internal nodes and leafs. Restore recursion in spatial query because it is faster and will stay at least for now because during destruction the rtree is traversed as well and manual stack could throw bad_alloc. --- .../index/detail/rtree/query_iterators.hpp | 105 ++---- .../detail/rtree/visitors/distance_query.hpp | 319 +++++++++++------- .../detail/rtree/visitors/spatial_query.hpp | 212 ++++++------ include/boost/geometry/index/rtree.hpp | 13 +- 4 files changed, 337 insertions(+), 312 deletions(-) diff --git a/include/boost/geometry/index/detail/rtree/query_iterators.hpp b/include/boost/geometry/index/detail/rtree/query_iterators.hpp index 28b19aed0..4922d06c8 100644 --- a/include/boost/geometry/index/detail/rtree/query_iterators.hpp +++ b/include/boost/geometry/index/detail/rtree/query_iterators.hpp @@ -17,8 +17,6 @@ #include -//#define BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_MOVE - namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace iterators { template @@ -65,13 +63,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 +72,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 +109,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 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 +138,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 +175,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 +266,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 +281,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 +289,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 +305,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/visitors/distance_query.hpp b/include/boost/geometry/index/detail/rtree/visitors/distance_query.hpp index 43a943e20..9b2aad3f1 100644 --- a/include/boost/geometry/index/detail/rtree/visitors/distance_query.hpp +++ b/include/boost/geometry/index/detail/rtree/visitors/distance_query.hpp @@ -73,6 +73,15 @@ struct priority_queue : std::priority_queue, Comp> } }; +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 { @@ -139,14 +148,11 @@ private: 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; @@ -166,129 +172,160 @@ public: typedef typename calculate_value_distance::result_type value_distance_type; typedef typename calculate_node_distance::result_type node_distance_type; - typedef typename allocators_type::size_type size_type; - typedef typename allocators_type::node_pointer node_pointer; + typedef typename MembersHolder::size_type size_type; + typedef typename MembersHolder::node_pointer node_pointer; + + using neighbor_data = std::pair; + using neighbors_type = std::vector; struct branch_data { - branch_data(node_distance_type d, size_type l, node_pointer p) - : distance(d), level(l), ptr(p) + 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 level; + size_type reverse_level; node_pointer ptr; }; + using branches_type = priority_queue; - struct branch_data_comp - { - bool operator()(branch_data const& b1, branch_data const& b2) const - { - return b1.distance > b2.distance || (b1.distance == b2.distance && b1.level < b2.level); - } - }; - - inline distance_query(parameters_type const& parameters, translator_type const& translator, Predicates const& pred) - : m_tr(translator) +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) - , m_strategy(index::detail::get_strategy(parameters)) { - //m_branches.reserve(parameters.get_max_elements() * levels_count); ? + 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? } template - size_type apply(node_pointer root, OutIter out_it) + size_type apply(MembersHolder const& members, OutIter out_it) { - if (m_result.max_count() <= 0) + return apply(members.root, members.leafs_level, out_it); + } + +private: + template + size_type apply(node_pointer ptr, size_type reverse_level, OutIter out_it) + { + namespace id = index::detail; + + if (max_count() <= 0) { return 0; } - m_level = 1; - rtree::apply_visitor(*this, *root); - 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() - || m_result.ignore_branch(m_branches.top().distance)) + || ignore_branch(m_branches.top().distance)) { break; } - node_pointer ptr = m_branches.top().ptr; - m_level = m_branches.top().level + 1; + ptr = m_branches.top().ptr; + reverse_level = m_branches.top().reverse_level; m_branches.pop(); - rtree::apply_visitor(*this, *ptr); } - return m_result.finish(out_it); + for (auto const& p : m_neighbors) + { + *out_it = *(p.second); + ++out_it; + } + + return m_neighbors.size(); } - inline void operator()(internal_node const& n) + bool ignore_branch(node_distance_type const& node_distance) const { - namespace id = index::detail; + return m_neighbors.size() == max_count() + && m_neighbors.front().first <= node_distance; + } - // fill array of nodes meeting predicates - for (auto const& p : rtree::elements(n)) + void store_value(value_distance_type value_distance, const value_type * value_ptr) + { + if (m_neighbors.size() < max_count()) { - node_distance_type node_distance; // for distance predicate + m_neighbors.push_back(std::make_pair(value_distance, value_ptr)); - // 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 - && ! m_result.ignore_branch(node_distance)) + if (m_neighbors.size() == max_count()) { - // add current node's data into the list - m_branches.push(branch_data(node_distance, m_level, p.second)); + std::make_heap(m_neighbors.begin(), m_neighbors.end(), pair_first_less()); } } - } - - inline void operator()(leaf const& n) - { - namespace id = index::detail; - - // search leaf for closest value meeting predicates - for (auto const& v : rtree::elements(n)) + else if (value_distance < m_neighbors.front().first) { - 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 - m_result.store(value_distance, boost::addressof(v)); - } + 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()); } } -private: + std::size_t max_count() const + { + return nearest_predicate_access::get(m_pred).count; + } + nearest_predicate_type const& predicate() const { return nearest_predicate_access::get(m_pred); } translator_type const& m_tr; - - Predicates m_pred; - - distance_query_result m_result; - priority_queue m_branches; - size_type m_level; - strategy_type m_strategy; + + Predicates const& m_pred; + + branches_type m_branches; + neighbors_type m_neighbors; }; 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; @@ -321,25 +358,44 @@ public: typedef typename internal_elements::const_iterator internal_iterator; typedef typename rtree::elements_type::type leaf_elements; - using branch_data = std::pair; - using branches_type = priority_queue; 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_tr(nullptr) +// , m_strategy() // , m_pred() , m_neighbors_count(0) , m_neighbor_ptr(nullptr) -// , m_strategy_type() {} - inline distance_query_incremental(parameters_type const& params, translator_type const& translator, Predicates const& pred) - : m_tr(::boost::addressof(translator)) + inline distance_query_incremental(Predicates const& pred) + : m_tr(nullptr) +// , m_strategy() , m_pred(pred) , m_neighbors_count(0) - , m_neighbor_ptr(nullptr) - , m_strategy(index::detail::get_strategy(params)) + , 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 @@ -347,11 +403,11 @@ public: return *m_neighbor_ptr; } - void initialize(node_pointer root) + void initialize(MembersHolder const& members) { if (0 < max_count()) { - rtree::apply_visitor(*this, *root); + apply(members.root, members.leafs_level); increment(); } } @@ -383,7 +439,7 @@ public: branch_data const& closest_branch = m_branches.top(); // 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.first ) + if (! m_neighbors.empty() && m_neighbors.top().first <= closest_branch.distance ) { m_neighbor_ptr = m_neighbors.top().second; ++m_neighbors_count; @@ -394,17 +450,18 @@ public: 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.first)) + if (ignore_branch_or_value(closest_branch.distance)) { m_branches.clear(); continue; } else { - node_pointer ptr = closest_branch.second; + 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); } } } @@ -420,71 +477,72 @@ public: 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) { namespace id = index::detail; - - // fill active branch list array of nodes meeting predicates - for (auto const& p : rtree::elements(n)) + // 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) { - 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_or_value(node_distance)) + internal_node& n = rtree::get(*ptr); + // fill active branch list array of nodes meeting predicates + for (auto const& p : rtree::elements(n)) { - // add current node into the queue - m_branches.push(std::make_pair(node_distance, p.second)); + 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_or_value(node_distance)) + { + // add current node into the queue + m_branches.push(branch_data(node_distance, reverse_level - 1, p.second)); + } } } - } - - // 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) - { - namespace id = index::detail; - - // search leaf for closest value meeting predicates - for (auto const& v : rtree::elements(n)) + // 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 { - 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)) + leaf& n = rtree::get(*ptr); + // search leaf for closest value meeting predicates + for (auto const& v : rtree::elements(n)) { - // add current value into the queue - m_neighbors.push(std::make_pair(value_distance, boost::addressof(v))); + value_distance_type value_distance; // for distance predicate - // remove unneeded value - if (m_neighbors_count + m_neighbors.size() > max_count()) + // 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)) { - m_neighbors.pop_bottom(); + // 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()) + { + m_neighbors.pop_bottom(); + } } } } } -private: template - inline bool ignore_branch_or_value(Distance const& distance) + 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); } - inline std::size_t max_count() const + std::size_t max_count() const { return nearest_predicate_access::get(m_pred).count; } @@ -495,6 +553,7 @@ private: } const translator_type * m_tr; + strategy_type m_strategy; Predicates m_pred; @@ -502,8 +561,6 @@ private: neighbors_type m_neighbors; size_type m_neighbors_count; const value_type * m_neighbor_ptr; - - strategy_type m_strategy; }; }}} // namespace detail::rtree::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 64d7585bf..855acab0b 100644 --- a/include/boost/geometry/index/detail/rtree/visitors/spatial_query.hpp +++ b/include/boost/geometry/index/detail/rtree/visitors/spatial_query.hpp @@ -23,7 +23,6 @@ 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; @@ -38,77 +37,66 @@ struct spatial_query typedef typename allocators_type::node_pointer node_pointer; typedef typename allocators_type::size_type size_type; - inline spatial_query(parameters_type const& par, translator_type const& t, Predicates const& p, OutIter out_it) - : m_tr(t), m_pred(p), m_out_iter(out_it), m_found_count(0), m_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) {} - size_type apply(node_pointer root) + size_type apply(node_pointer ptr, size_type reverse_level) { - rtree::apply_visitor(*this, *root); - - for (;;) + namespace id = index::detail; + if (reverse_level > 0) { - if (m_internal_stack.empty()) + internal_node& n = rtree::get(*ptr); + // traverse nodes meeting predicates + for (auto const& p : rtree::elements(n)) { - break; + // 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); + } + } + } + else + { + leaf& n = rtree::get(*ptr); + // get all values meeting predicates + for (auto const& v : rtree::elements(n)) + { + // 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; + } } - - node_pointer ptr = m_internal_stack.back(); - m_internal_stack.pop_back(); - rtree::apply_visitor(*this, *ptr); } return m_found_count; } - inline void operator()(internal_node const& n) + size_type apply(MembersHolder const& members) { - namespace id = index::detail; - - // traverse nodes meeting predicates - for (auto const& p : rtree::elements(n)) - { - // if node meets predicates (0 is dummy value) - if (id::predicates_check(m_pred, 0, p.first, m_strategy)) - { - m_internal_stack.push_back(p.second); - } - } - } - - inline void operator()(leaf const& n) - { - namespace id = index::detail; - - // get all values meeting predicates - for (auto const& v : rtree::elements(n)) - { - // 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 apply(members.root, members.leafs_level); } private: translator_type const& m_tr; - - Predicates m_pred; - - std::vector m_internal_stack; - - OutIter m_out_iter; - size_type m_found_count; - strategy_type m_strategy; + + Predicates const& m_pred; + OutIter m_out_iter; + + 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; @@ -117,7 +105,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; @@ -130,35 +117,40 @@ public: typedef typename rtree::elements_type::type leaf_elements; typedef typename rtree::elements_type::type::const_iterator leaf_iterator; - inline spatial_query_incremental() - : m_translator(NULL) -// , m_pred() - , m_values(NULL) - , m_current() + 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; + }; + +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 { @@ -166,9 +158,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(); } @@ -178,6 +170,35 @@ 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; @@ -207,49 +228,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 (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/rtree.hpp b/include/boost/geometry/index/rtree.hpp index e0a5e001d..af3b6f4ee 100644 --- a/include/boost/geometry/index/rtree.hpp +++ b/include/boost/geometry/index/rtree.hpp @@ -1248,8 +1248,8 @@ private: Predicates); return m_members.root - ? query_iterator_t(m_members.root, m_members.parameters(), m_members.translator(), predicates) - : query_iterator_t(m_members.parameters(), m_members.translator(), predicates); + ? query_iterator_t(m_members, predicates) + : query_iterator_t(predicates); } /*! @@ -1857,9 +1857,8 @@ private: 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); - - return find_v.apply(m_members.root); + query(m_members, predicates, out_it); + return query.apply(m_members); } /*! @@ -1880,9 +1879,9 @@ private: Predicates); detail::rtree::visitors::distance_query - distance_v(m_members.parameters(), m_members.translator(), predicates); + distance_v(m_members, predicates); - return distance_v.apply(m_members.root, out_it); + return distance_v.apply(m_members, out_it); } /*! From 5cc1f9019e3b001ef1529a8eb00f6c76e178a589 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Fri, 30 Jul 2021 20:44:13 +0200 Subject: [PATCH 15/29] [index] Refactor minmax heap WRT coding guidelines. --- .../geometry/index/detail/minmax_heap.hpp | 58 ++++++++++++++----- 1 file changed, 44 insertions(+), 14 deletions(-) diff --git a/include/boost/geometry/index/detail/minmax_heap.hpp b/include/boost/geometry/index/detail/minmax_heap.hpp index 18b44d918..1b95f77ea 100644 --- a/include/boost/geometry/index/detail/minmax_heap.hpp +++ b/include/boost/geometry/index/detail/minmax_heap.hpp @@ -45,8 +45,7 @@ inline int level(T i) { ++i; int r = 0; - while (i >>= 1) - ++r; + while (i >>= 1) { ++r; } return r; } @@ -74,10 +73,8 @@ inline int level(T i) #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)); + if (_BitScanReverse(&r, (unsigned long)((i + 1) >> 32))) { r += 32; } + else { _BitScanReverse(&r, (unsigned long)(i + 1)); } #endif return int(r); } @@ -157,7 +154,9 @@ inline void push_heap2(It first, diff_t c, val_t val, Compare comp) { diff_t const g = (c - 3) >> 2; // grandparent index if (! Call()(comp, val, *(first + g))) + { break; + } *(first + c) = std::move(*(first + g)); c = g; } @@ -175,7 +174,9 @@ inline void push_heap1(It first, diff_t c, val_t val, Compare comp) return push_heap2(first, p, std::move(val), comp); } else + { return push_heap2(first, c, std::move(val), comp); + } } template @@ -183,14 +184,20 @@ 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); + } } @@ -208,8 +215,12 @@ inline diff_t pick_grandchild4(It first, diff_t f, Compare comp) //{ // diff_t m = f; // for (++f; f != l; ++f) +// { // if (Call()(comp, *(first + f), *(first + m))) +// { // m = f; +// } +// } // return m; //} @@ -225,7 +236,9 @@ inline void pop_heap1(It first, diff_t p, diff_t size, val_t val, Co diff_t const m = pick_grandchild4(first, ll, comp); if (! Call()(comp, *(first + m), val)) + { break; + } *(first + p) = std::move(*(first + m)); @@ -294,7 +307,9 @@ 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); @@ -305,9 +320,13 @@ inline void pop_heap(It first, It el, It last, Compare comp) 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 @@ -316,7 +335,10 @@ 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) @@ -324,9 +346,14 @@ inline void make_heap(It first, It last, Compare comp) --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; @@ -353,12 +380,16 @@ inline bool is_heap(It first, It last, Compare comp) 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) @@ -367,12 +398,16 @@ inline bool is_heap(It first, It last, Compare comp) if (is_min_level) { if (Call()(comp, *(first + i), *(first + g))) + { return false; + } } else { if (Call()(comp, *(first + g), *(first + i))) + { return false; + } } } } @@ -383,14 +418,9 @@ template inline It bottom_heap(It first, It last, Compare comp) { diff_t const size = last - first; - if (size <= 1) - return first; - else if (size == 2) - return (first + 1); - else - return Call()(comp, *(first + 1), *(first + 2)) - ? (first + 2) - : (first + 1); + return size <= 1 ? first : + size == 2 ? (first + 1) : + Call()(comp, *(first + 1), *(first + 2)) ? (first + 2) : (first + 1); } } // namespace minmax_heap_detail From ac89528a7c31dd08e138cd23d4173997a678cdc3 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Mon, 23 Aug 2021 12:39:08 +0200 Subject: [PATCH 16/29] [ci] Scan index/test dir while getting dependencies. --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index a61e96d1c..8af7fca8a 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 From 38031de1f21f7544693d9160b896a791fbf603b2 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Mon, 23 Aug 2021 13:04:06 +0200 Subject: [PATCH 17/29] [test][index] Drop Bforeach dependency from rtree tests. --- index/test/rtree/rtree_test_generator.cpp | 15 ++- index/test/rtree/test_rtree.hpp | 156 ++++++++++++++-------- 2 files changed, 108 insertions(+), 63 deletions(-) diff --git a/index/test/rtree/rtree_test_generator.cpp b/index/test/rtree/rtree_test_generator.cpp index e1d76ee2f..512ef4306 100644 --- a/index/test/rtree/rtree_test_generator.cpp +++ b/index/test/rtree/rtree_test_generator.cpp @@ -3,6 +3,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) @@ -10,7 +14,6 @@ #include #include #include -#include #include #include @@ -46,13 +49,13 @@ int main() testsets.push_back(std::make_pair("testset::queries", "que")); testsets.push_back(std::make_pair("testset::additional", "add")); - BOOST_FOREACH(P const& p, parameters) + for (P const& p : parameters) { - BOOST_FOREACH(TS const& ts, testsets) + for (TS const& ts : testsets) { - BOOST_FOREACH(std::string const& i, indexables) + for (std::string const& i : indexables) { - BOOST_FOREACH(std::string const& d, dimensions) + for (std::string const& d : dimensions) { // If the I is Segment, generate only for 2d if ( i == "s" && d != "2" ) @@ -60,7 +63,7 @@ int main() continue; } - BOOST_FOREACH(CT const& c, coordinate_types) + for (CT const& c : coordinate_types) { std::string filename = std::string() + "rtree_" + boost::get<1>(p) + '_' + ts.second + '_' + i + d + boost::get<1>(c) + ".cpp"; diff --git a/index/test/rtree/test_rtree.hpp b/index/test/rtree/test_rtree.hpp index 77f1f5312..4b18f65e6 100644 --- a/index/test/rtree/test_rtree.hpp +++ b/index/test/rtree/test_rtree.hpp @@ -14,7 +14,6 @@ #ifndef BOOST_GEOMETRY_INDEX_TEST_RTREE_HPP #define BOOST_GEOMETRY_INDEX_TEST_RTREE_HPP -#include #include #include @@ -681,15 +680,16 @@ void rtree(Rtree & tree, Elements & input, Box & qbox) } // namespace generate -namespace basictest { +namespace basictest +{ // low level test functions template Iter find(Rtree const& rtree, Iter first, Iter last, Value const& value) { - for ( ; first != last ; ++first ) - if ( rtree.value_eq()(value, *first) ) + for (; first != last; ++first) + if (rtree.value_eq()(value, *first)) return first; return first; } @@ -698,12 +698,12 @@ template void compare_outputs(Rtree const& rtree, std::vector const& output, std::vector const& expected_output) { bool are_sizes_ok = (expected_output.size() == output.size()); - BOOST_CHECK( are_sizes_ok ); - if ( are_sizes_ok ) + BOOST_CHECK(are_sizes_ok); + if (are_sizes_ok) { - BOOST_FOREACH(Value const& v, expected_output) + for (Value const& v : expected_output) { - BOOST_CHECK(find(rtree, output.begin(), output.end(), v) != output.end() ); + BOOST_CHECK(find(rtree, output.begin(), output.end(), v) != output.end()); } } } @@ -715,13 +715,13 @@ void exactly_the_same_outputs(Rtree const& rtree, Range1 const& output, Range2 c size_t s2 = std::distance(expected_output.begin(), expected_output.end()); BOOST_CHECK(s1 == s2); - if ( s1 == s2 ) + if (s1 == s2) { typename Range1::const_iterator it1 = output.begin(); typename Range2::const_iterator it2 = expected_output.begin(); - for ( ; it1 != output.end() && it2 != expected_output.end() ; ++it1, ++it2 ) + for (; it1 != output.end() && it2 != expected_output.end(); ++it1, ++it2) { - if ( !rtree.value_eq()(*it1, *it2) ) + if (!rtree.value_eq()(*it1, *it2)) { BOOST_CHECK(false && "rtree.translator().equals(*it1, *it2)"); break; @@ -734,7 +734,7 @@ void exactly_the_same_outputs(Rtree const& rtree, Range1 const& output, Range2 c template void copy_alt(First first, Last last, Out out) { - for ( ; first != last ; ++first, ++out ) + for (; first != last; ++first, ++out) *out = *first; } @@ -759,7 +759,7 @@ void check_fwd_iterators(QItF first, QItL last) #endif QItF it = first; - for ( ; it != last && first != last ; ++it, ++first) + for (; it != last && first != last; ++it, ++first) { BOOST_CHECK(it == first); @@ -775,20 +775,20 @@ void check_fwd_iterators(QItF first, QItL last) template void spatial_query(Rtree & rtree, Predicates const& pred, std::vector const& expected_output) { - BOOST_CHECK( bgi::detail::rtree::utilities::are_levels_ok(rtree) ); - if ( !rtree.empty() ) - BOOST_CHECK( bgi::detail::rtree::utilities::are_boxes_ok(rtree) ); + BOOST_CHECK(bgi::detail::rtree::utilities::are_levels_ok(rtree)); + if (!rtree.empty()) + BOOST_CHECK(bgi::detail::rtree::utilities::are_boxes_ok(rtree)); std::vector output; size_t n = rtree.query(pred, std::back_inserter(output)); - BOOST_CHECK( expected_output.size() == n ); + BOOST_CHECK(expected_output.size() == n); compare_outputs(rtree, output, expected_output); std::vector output2; size_t n2 = query(rtree, pred, std::back_inserter(output2)); - - BOOST_CHECK( n == n2 ); + + BOOST_CHECK(n == n2); exactly_the_same_outputs(rtree, output, output2); exactly_the_same_outputs(rtree, output, rtree | bgi::adaptors::queried(pred)); @@ -827,9 +827,13 @@ void intersects(Rtree const& tree, std::vector const& input, Box const& q { std::vector expected_output; - BOOST_FOREACH(Value const& v, input) - if ( bg::intersects(tree.indexable_get()(v), qbox) ) + for (Value const& v : input) + { + if (bg::intersects(tree.indexable_get()(v), qbox)) + { expected_output.push_back(v); + } + } //spatial_query(tree, qbox, expected_output); spatial_query(tree, bgi::intersects(qbox), expected_output); @@ -851,9 +855,13 @@ void disjoint(Rtree const& tree, std::vector const& input, Box const& qbo { std::vector expected_output; - BOOST_FOREACH(Value const& v, input) - if ( bg::disjoint(tree.indexable_get()(v), qbox) ) + for (Value const& v : input) + { + if (bg::disjoint(tree.indexable_get()(v), qbox)) + { expected_output.push_back(v); + } + } spatial_query(tree, bgi::disjoint(qbox), expected_output); spatial_query(tree, !bgi::intersects(qbox), expected_output); @@ -875,9 +883,13 @@ struct contains_impl { std::vector expected_output; - BOOST_FOREACH(Value const& v, input) - if ( bg::within(qbox, tree.indexable_get()(v)) ) + for (Value const& v : input) + { + if (bg::within(qbox, tree.indexable_get()(v))) + { expected_output.push_back(v); + } + } spatial_query(tree, bgi::contains(qbox), expected_output); @@ -912,7 +924,7 @@ void contains(Rtree const& tree, std::vector const& input, Box const& qbo { contains_impl< typename bg::tag< - typename Rtree::indexable_type + typename Rtree::indexable_type >::type >::apply(tree, input, qbox); } @@ -925,12 +937,12 @@ struct covered_by_impl { std::vector expected_output; - BOOST_FOREACH(Value const& v, input) + for (Value const& v : input) { - if ( bgi::detail::covered_by_bounds( - tree.indexable_get()(v), - qbox, - bgi::detail::get_strategy(tree.parameters())) ) + if (bgi::detail::covered_by_bounds( + tree.indexable_get()(v), + qbox, + bgi::detail::get_strategy(tree.parameters()))) { expected_output.push_back(v); } @@ -961,7 +973,7 @@ void covered_by(Rtree const& tree, std::vector const& input, Box const& q { covered_by_impl< typename bg::tag< - typename Rtree::indexable_type + typename Rtree::indexable_type >::type >::apply(tree, input, qbox); } @@ -974,9 +986,13 @@ struct covers_impl { std::vector expected_output; - BOOST_FOREACH(Value const& v, input) - if ( bg::covered_by(qbox, tree.indexable_get()(v)) ) + for (Value const& v : input) + { + if (bg::covered_by(qbox, tree.indexable_get()(v))) + { expected_output.push_back(v); + } + } spatial_query(tree, bgi::covers(qbox), expected_output); @@ -1011,7 +1027,7 @@ void covers(Rtree const& tree, std::vector const& input, Box const& qbox) { covers_impl< typename bg::tag< - typename Rtree::indexable_type + typename Rtree::indexable_type >::type >::apply(tree, input, qbox); } @@ -1024,9 +1040,13 @@ struct overlaps_impl { std::vector expected_output; - BOOST_FOREACH(Value const& v, input) - if ( bg::overlaps(tree.indexable_get()(v), qbox) ) + for (Value const& v : input) + { + if (bg::overlaps(tree.indexable_get()(v), qbox)) + { expected_output.push_back(v); + } + } spatial_query(tree, bgi::overlaps(qbox), expected_output); @@ -1061,7 +1081,7 @@ void overlaps(Rtree const& tree, std::vector const& input, Box const& qbo { overlaps_impl< typename bg::tag< - typename Rtree::indexable_type + typename Rtree::indexable_type >::type >::apply(tree, input, qbox); } @@ -1082,9 +1102,13 @@ void overlaps(Rtree const& tree, std::vector const& input, Box const& qbo // { // std::vector expected_output; // -// BOOST_FOREACH(Value const& v, input) -// if ( bg::touches(tree.translator()(v), qbox) ) +// for (Value const& v : input) +// { +// if (bg::touches(tree.translator()(v), qbox)) +// { // expected_output.push_back(v); +// } +// } // // spatial_query(tree, bgi::touches(qbox), expected_output); // } @@ -1107,9 +1131,13 @@ struct within_impl { std::vector expected_output; - BOOST_FOREACH(Value const& v, input) - if ( bg::within(tree.indexable_get()(v), qbox) ) + for (Value const& v : input) + { + if (bg::within(tree.indexable_get()(v), qbox)) + { expected_output.push_back(v); + } + } spatial_query(tree, bgi::within(qbox), expected_output); @@ -1172,15 +1200,15 @@ inline void compare_nearest_outputs(Rtree const& rtree, std::vector const { // check output bool are_sizes_ok = (expected_output.size() == output.size()); - BOOST_CHECK( are_sizes_ok ); - if ( are_sizes_ok ) + BOOST_CHECK(are_sizes_ok); + if (are_sizes_ok) { - BOOST_FOREACH(Value const& v, output) + for (Value const& v : output) { // TODO - perform explicit check here? // should all objects which are closest be checked and should exactly the same be found? - if ( find(rtree, expected_output.begin(), expected_output.end(), v) == expected_output.end() ) + if (find(rtree, expected_output.begin(), expected_output.end(), v) == expected_output.end()) { Distance d = bg::comparable_distance(pt, rtree.indexable_get()(v)); BOOST_CHECK(d == greatest_distance); @@ -1195,7 +1223,7 @@ inline void check_sorted_by_distance(Rtree const& rtree, std::vector cons typedef typename bg::default_distance_result::type D; D prev_dist = 0; - BOOST_FOREACH(Value const& v, output) + for (Value const& v : output) { D d = bg::comparable_distance(pt, rtree.indexable_get()(v)); BOOST_CHECK(prev_dist <= d); @@ -1214,25 +1242,31 @@ inline void nearest_query_k(Rtree const& rtree, std::vector const& input, std::vector< std::pair > test_output; // calculate test output - k closest values pairs - BOOST_FOREACH(Value const& v, input) + for (Value const& v : input) { D d = bg::comparable_distance(pt, rtree.indexable_get()(v)); - if ( test_output.size() < k ) + if (test_output.size() < k) + { test_output.push_back(std::make_pair(d, v)); + } else { std::sort(test_output.begin(), test_output.end(), NearestKLess()); - if ( d < test_output.back().first ) + if (d < test_output.back().first) + { test_output.back() = std::make_pair(d, v); + } } } // caluclate biggest distance std::sort(test_output.begin(), test_output.end(), NearestKLess()); D greatest_distance = 0; - if ( !test_output.empty() ) + if (! test_output.empty()) + { greatest_distance = test_output.back().first; + } // transform test output to vector of values std::vector expected_output(test_output.size(), generate::value_default::apply()); @@ -1441,8 +1475,10 @@ void create_insert(Rtree const& tree, std::vector const& input, Box const { Rtree t(tree.parameters(), tree.indexable_get(), tree.value_eq(), tree.get_allocator()); - BOOST_FOREACH(Value const& v, input) + for (Value const& v : input) + { t.insert(v); + } BOOST_CHECK(tree.size() == t.size()); std::vector output; t.query(bgi::intersects(qbox), std::back_inserter(output)); @@ -1490,8 +1526,10 @@ void create_insert(Rtree const& tree, std::vector const& input, Box const { Rtree t(tree.parameters(), tree.indexable_get(), tree.value_eq(), tree.get_allocator()); - BOOST_FOREACH(Value const& v, input) + for (Value const& v : input) + { bgi::insert(t, v); + } BOOST_CHECK(tree.size() == t.size()); std::vector output; bgi::query(t, bgi::intersects(qbox), std::back_inserter(output)); @@ -1538,8 +1576,10 @@ void remove(Rtree const& tree, Box const& qbox) { Rtree t(tree); size_t r = 0; - BOOST_FOREACH(Value const& v, values_to_remove) + for (Value const& v : values_to_remove) + { r += t.remove(v); + } BOOST_CHECK( r == expected_removed_count ); std::vector output; t.query(bgi::disjoint(qbox), std::back_inserter(output)); @@ -1571,8 +1611,10 @@ void remove(Rtree const& tree, Box const& qbox) { Rtree t(tree); size_t r = 0; - BOOST_FOREACH(Value const& v, values_to_remove) + for (Value const& v : values_to_remove) + { r += bgi::remove(t, v); + } BOOST_CHECK( r == expected_removed_count ); std::vector output; bgi::query(t, bgi::disjoint(qbox), std::back_inserter(output)); @@ -1643,7 +1685,7 @@ void range(Rtree & tree, std::vector const& input) BOOST_CHECK(count == tree.size()); count = 0; - BOOST_FOREACH(Value const& v, tree) + for (Value const& v : tree) { boost::ignore_unused(v); ++count; @@ -1777,7 +1819,7 @@ void test_count_rtree_values(Parameters const& parameters, Allocator const& allo size_t values_count = Value::counter(); - BOOST_FOREACH(Value const& v, values_to_remove) + for (Value const& v : values_to_remove) { size_t r = t.remove(v); --values_count; From c67f451fa7c72b92555510379e3d62fac91eb24d Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Mon, 23 Aug 2021 17:32:58 +0200 Subject: [PATCH 18/29] Create license file. --- LICENSE_1_0.txt | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 LICENSE_1_0.txt 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. From a8545eefb1f3f0f176ba56b2288d0b04fca53fb2 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Tue, 24 Aug 2021 19:02:25 +0200 Subject: [PATCH 19/29] [test][index] Fix different sign compare warning. --- index/test/rtree/rtree_non_cartesian.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/index/test/rtree/rtree_non_cartesian.cpp b/index/test/rtree/rtree_non_cartesian.cpp index 6111a2847..cbc4f633a 100644 --- a/index/test/rtree/rtree_non_cartesian.cpp +++ b/index/test/rtree/rtree_non_cartesian.cpp @@ -3,6 +3,10 @@ // Copyright (c) 2016 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) @@ -101,7 +105,7 @@ void test_ticket_12413() size_t num_removed = rtree.remove(std::make_pair(point_t(-0.127592, 51.503407), 796)); - BOOST_CHECK_EQUAL(num_removed, 1); + BOOST_CHECK_EQUAL(num_removed, 1u); } template From 19a742e3bb1439015f7e8b5565f29e9b5ad860a7 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Tue, 24 Aug 2021 19:56:22 +0200 Subject: [PATCH 20/29] [test][index] Fix varray test and counting_value. Explicitly declare ctors and assignments. --- index/test/rtree/test_rtree.hpp | 2 ++ index/test/varray.cpp | 12 ++++++++---- index/test/varray_test.hpp | 16 ++++++++++++---- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/index/test/rtree/test_rtree.hpp b/index/test/rtree/test_rtree.hpp index 4b18f65e6..889f61fac 100644 --- a/index/test/rtree/test_rtree.hpp +++ b/index/test/rtree/test_rtree.hpp @@ -414,6 +414,8 @@ struct counting_value counting_value(counting_value const& c) : indexable(c.indexable) { counter()++; } ~counting_value() { counter()--; } + counting_value& operator=(counting_value const& c) = default; + static size_t & counter() { static size_t c = 0; return c; } Indexable indexable; }; diff --git a/index/test/varray.cpp b/index/test/varray.cpp index d561f1c78..544e8c65f 100644 --- a/index/test/varray.cpp +++ b/index/test/varray.cpp @@ -4,6 +4,10 @@ // Copyright (c) 2012-2014 Adam Wulkiewicz, Lodz, Poland. // Copyright (c) 2012-2013 Andrew Hundt. +// 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) @@ -55,11 +59,11 @@ void test_ctor_nc(size_t n) if ( 1 < n ) { T val10(10); - s[0] = val10; + s[0] = std::move(val10); BOOST_CHECK(T(10) == s[0]); BOOST_CHECK(T(10) == s.at(0)); T val20(20); - s.at(1) = val20; + s.at(1) = std::move(val20); BOOST_CHECK(T(20) == s[1]); BOOST_CHECK(T(20) == s.at(1)); } @@ -103,11 +107,11 @@ void test_resize_nc(size_t n) if ( 1 < n ) { T val10(10); - s[0] = val10; + s[0] = std::move(val10); BOOST_CHECK(T(10) == s[0]); BOOST_CHECK(T(10) == s.at(0)); T val20(20); - s.at(1) = val20; + s.at(1) = std::move(val20); BOOST_CHECK(T(20) == s[1]); BOOST_CHECK(T(20) == s.at(1)); } diff --git a/index/test/varray_test.hpp b/index/test/varray_test.hpp index 4136db7fc..bd9afa8b3 100644 --- a/index/test/varray_test.hpp +++ b/index/test/varray_test.hpp @@ -4,6 +4,10 @@ // Copyright (c) 2012-2013 Adam Wulkiewicz, Lodz, Poland. // Copyright (c) 2012-2013 Andrew Hundt. +// 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) @@ -23,9 +27,11 @@ public: ~value_ndc() {} bool operator==(value_ndc const& v) const { return aa == v.aa; } bool operator<(value_ndc const& v) const { return aa < v.aa; } + value_ndc(value_ndc const&) = delete; + value_ndc & operator=(value_ndc const&) = delete; + value_ndc(value_ndc&&) = default; + value_ndc & operator=(value_ndc&&) = default; private: - value_ndc(value_ndc const&) {} - value_ndc & operator=(value_ndc const&) { return *this; } size_t aa; }; @@ -47,9 +53,11 @@ public: ~value_nc() {} bool operator==(value_nc const& v) const { return aa == v.aa; } bool operator<(value_nc const& v) const { return aa < v.aa; } + value_nc(value_nc const&) = delete; + value_nc & operator=(value_nc const&) = delete; + value_nc(value_nc&&) = default; + value_nc & operator=(value_nc&&) = default; private: - value_nc(value_nc const&) {} - value_nc & operator=(value_ndc const&) { return *this; } size_t aa; }; From 98678b19c0206a1f4f3467a9e2f5f2cb6b8dc733 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Tue, 24 Aug 2021 20:00:47 +0200 Subject: [PATCH 21/29] [test][index] Do not define BOOST_NO_AUTO_PTR in Jamfile to avoid warnings. --- index/test/Jamfile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/index/test/Jamfile b/index/test/Jamfile index 2b148a771..485dc1323 100644 --- a/index/test/Jamfile +++ b/index/test/Jamfile @@ -2,6 +2,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) @@ -16,7 +20,6 @@ project boost-geometry-index-test msvc:on msvc:/bigobj windows,intel:/bigobj - BOOST_NO_AUTO_PTR # disable the deprecated std::auto_ptr support in SmartPtr and Core /boost/timer//boost_timer ; From 8ab41f9f8e1c680f4497d8a44ba37d1e15b3cd8d Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Wed, 1 Sep 2021 15:50:42 +0200 Subject: [PATCH 22/29] [extensions] Fix nsphere concept checks compilation. --- .../nsphere/geometries/concepts/check.hpp | 50 ------------------- .../geometries/concepts/nsphere_concept.hpp | 16 ++++++ .../geometry/extensions/nsphere/nsphere.hpp | 5 +- 3 files changed, 20 insertions(+), 51 deletions(-) delete mode 100644 include/boost/geometry/extensions/nsphere/geometries/concepts/check.hpp diff --git a/include/boost/geometry/extensions/nsphere/geometries/concepts/check.hpp b/include/boost/geometry/extensions/nsphere/geometries/concepts/check.hpp deleted file mode 100644 index ecab04eff..000000000 --- a/include/boost/geometry/extensions/nsphere/geometries/concepts/check.hpp +++ /dev/null @@ -1,50 +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. -// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland. - -// 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_EXTENSIONS_NSPHERE_GEOMETRIES_CONCEPTS_CHECK_HPP -#define BOOST_GEOMETRY_EXTENSIONS_NSPHERE_GEOMETRIES_CONCEPTS_CHECK_HPP - - -#include - - -namespace boost { namespace geometry -{ - - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - -template -struct check - : detail::concept_check::check > -{}; - -template -struct check - : detail::concept_check::check > -{}; - -} // namespace dispatch -#endif - - - - -}} // namespace boost::geometry - - -#endif // BOOST_GEOMETRY_EXTENSIONS_NSPHERE_GEOMETRIES_CONCEPTS_CHECK_HPP diff --git a/include/boost/geometry/extensions/nsphere/geometries/concepts/nsphere_concept.hpp b/include/boost/geometry/extensions/nsphere/geometries/concepts/nsphere_concept.hpp index 7fb631b05..a89528ce4 100644 --- a/include/boost/geometry/extensions/nsphere/geometries/concepts/nsphere_concept.hpp +++ b/include/boost/geometry/extensions/nsphere/geometries/concepts/nsphere_concept.hpp @@ -4,6 +4,10 @@ // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// 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 + // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -117,6 +121,18 @@ public : }; +template +struct concept_type +{ + using type = Nsphere; +}; + +template +struct concept_type +{ + using type = ConstNsphere; +}; + }}} // namespace boost::geometry::concepts diff --git a/include/boost/geometry/extensions/nsphere/nsphere.hpp b/include/boost/geometry/extensions/nsphere/nsphere.hpp index bd0112704..8c2dd2c52 100644 --- a/include/boost/geometry/extensions/nsphere/nsphere.hpp +++ b/include/boost/geometry/extensions/nsphere/nsphere.hpp @@ -5,6 +5,10 @@ // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // 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 + // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -22,7 +26,6 @@ #include #include -#include #include #include From 20840011ce2c7feaf0f6e5093478960495b297a4 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Wed, 1 Sep 2021 15:52:36 +0200 Subject: [PATCH 23/29] [test][extensions] Replace BOOST_FOREACH with range-based for loop. --- extensions/test/algorithms/connect.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/extensions/test/algorithms/connect.cpp b/extensions/test/algorithms/connect.cpp index f8766806b..7d4a274d4 100644 --- a/extensions/test/algorithms/connect.cpp +++ b/extensions/test/algorithms/connect.cpp @@ -3,6 +3,10 @@ // Copyright (c) 2010-2012 Barend Gehrels, Amsterdam, the Netherlands. +// 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) @@ -57,7 +61,7 @@ void test_connect(std::string const& caseid, Geometry const& geometry, std::size_t count = boost::size(connected_vector); std::size_t point_count = 0; - BOOST_FOREACH(GeometryOut& connected, connected_vector) + for (GeometryOut& connected : connected_vector) { bg::unique(connected); length += bg::length(connected); @@ -99,7 +103,7 @@ void test_connect(std::string const& caseid, Geometry const& geometry, mapper.map(geometry, "opacity:0.6;fill:rgb(0,0,255);stroke:rgb(0,0,0);stroke-width:1"); - BOOST_FOREACH(GeometryOut& connected, connected_vector) + for (GeometryOut& connected : connected_vector) { mapper.map(connected, "opacity:0.6;fill:none;stroke:rgb(255,0,0);stroke-width:5"); } From 69230d5c59d649c2c1aa3c579ac1e22d3fe1e1ea Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Wed, 1 Sep 2021 15:54:08 +0200 Subject: [PATCH 24/29] [extensions][test] Add/update includes. --- extensions/test/triangulation/in_circle_robust.cpp | 6 +++++- .../boost/geometry/extensions/algorithms/distance_info.hpp | 7 +++---- .../boost/geometry/extensions/gis/io/wkb/detail/endian.hpp | 6 +++--- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/extensions/test/triangulation/in_circle_robust.cpp b/extensions/test/triangulation/in_circle_robust.cpp index 72668e962..2eb65ec63 100644 --- a/extensions/test/triangulation/in_circle_robust.cpp +++ b/extensions/test/triangulation/in_circle_robust.cpp @@ -6,6 +6,10 @@ // Contributed and/or modified by Tinko Bartels, // as part of Google Summer of Code 2019 program. +// 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) @@ -13,7 +17,7 @@ #include #include -#include +#include template void test_all() diff --git a/include/boost/geometry/extensions/algorithms/distance_info.hpp b/include/boost/geometry/extensions/algorithms/distance_info.hpp index eae5387ce..d64bc2d9e 100644 --- a/include/boost/geometry/extensions/algorithms/distance_info.hpp +++ b/include/boost/geometry/extensions/algorithms/distance_info.hpp @@ -5,8 +5,8 @@ // Copyright (c) 2009-2013 Mateusz Loskot, London, UK. // Copyright (c) 2013 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, @@ -30,10 +30,9 @@ #include -#include #include +#include -#include #include #include diff --git a/include/boost/geometry/extensions/gis/io/wkb/detail/endian.hpp b/include/boost/geometry/extensions/gis/io/wkb/detail/endian.hpp index 33d775f36..9e34f293d 100644 --- a/include/boost/geometry/extensions/gis/io/wkb/detail/endian.hpp +++ b/include/boost/geometry/extensions/gis/io/wkb/detail/endian.hpp @@ -2,8 +2,8 @@ // 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 // Use, modification and distribution is subject to the Boost Software License, @@ -31,7 +31,7 @@ #include #include #include -#include +#include #if CHAR_BIT != 8 #error Platforms with CHAR_BIT != 8 are not supported From f7aaf265af4fb1447c1489499e53f245f0ebe877 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Thu, 2 Sep 2021 15:03:20 +0200 Subject: [PATCH 25/29] [extensions] Update endian detection checks after changing headers from endian to predef. --- .../geometry/extensions/gis/io/wkb/detail/endian.hpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/include/boost/geometry/extensions/gis/io/wkb/detail/endian.hpp b/include/boost/geometry/extensions/gis/io/wkb/detail/endian.hpp index 9e34f293d..b02d9b1c1 100644 --- a/include/boost/geometry/extensions/gis/io/wkb/detail/endian.hpp +++ b/include/boost/geometry/extensions/gis/io/wkb/detail/endian.hpp @@ -50,10 +50,16 @@ namespace detail { namespace endian struct big_endian_tag {}; struct little_endian_tag {}; -#ifdef BOOST_BIG_ENDIAN +#if defined(BOOST_ENDIAN_BIG_BYTE_AVAILABLE) typedef big_endian_tag native_endian_tag; -#else +#elif defined(BOOST_ENDIAN_LITTLE_BYTE_AVAILABLE) typedef little_endian_tag native_endian_tag; +#elif defined(BOOST_ENDIAN_BIG_WORD_BYTE_AVAILABLE) +#error Word-swapped big-endian not supported +#elif defined(BOOST_ENDIAN_LITTLE_WORD_BYTE_AVAILABLE) +#error Word-swapped little-endian not supported +#else +#error Unknown endian memory ordering #endif // Unrolled loops for loading and storing streams of bytes. From f222a8f1d837cb2ed56ce0281eb888d08e00eb62 Mon Sep 17 00:00:00 2001 From: Vissarion Fisikopoulos Date: Tue, 7 Sep 2021 14:05:04 +0300 Subject: [PATCH 26/29] Create collected_vector specialization for side_by_triangle --- .../algorithms/detail/equals/collect_vectors.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/boost/geometry/algorithms/detail/equals/collect_vectors.hpp b/include/boost/geometry/algorithms/detail/equals/collect_vectors.hpp index f95309906..e6606a160 100644 --- a/include/boost/geometry/algorithms/detail/equals/collect_vectors.hpp +++ b/include/boost/geometry/algorithms/detail/equals/collect_vectors.hpp @@ -39,6 +39,7 @@ #include +#include #include #include #include @@ -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 From 03d6e82f264162dd18d21b9d2803d2cfa9c65b7b Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Wed, 8 Sep 2021 11:23:25 +0200 Subject: [PATCH 27/29] [coordinate] deprecate util/promote_floating_point.hpp --- .../algorithms/detail/buffer/piece_border.hpp | 1 - .../geometry/core/coordinate_promotion.hpp | 111 ++++++++++++++++++ .../boost/geometry/core/coordinate_type.hpp | 10 -- include/boost/geometry/core/radian_access.hpp | 3 +- .../robustness/get_rescale_policy.hpp | 2 +- .../policies/robustness/segment_ratio.hpp | 2 +- .../geometry/strategies/cartesian/azimuth.hpp | 2 +- .../strategies/geographic/distance.hpp | 2 +- .../geographic/distance_cross_track.hpp | 2 +- .../geographic/distance_segment_box.hpp | 3 +- .../strategies/geographic/mapping_ssf.hpp | 2 +- .../geometry/strategies/geographic/side.hpp | 2 +- .../spherical/distance_cross_track.hpp | 2 +- .../spherical/distance_haversine.hpp | 2 +- .../strategies/spherical/point_in_point.hpp | 1 + .../spherical/side_by_cross_track.hpp | 2 +- .../geometry/strategies/spherical/ssf.hpp | 2 +- .../strategies/strategy_transform.hpp | 2 +- .../transform/matrix_transformers.hpp | 2 +- .../geometry/util/promote_floating_point.hpp | 32 +---- 20 files changed, 131 insertions(+), 56 deletions(-) create mode 100644 include/boost/geometry/core/coordinate_promotion.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/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/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/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..b1af50ffa 100644 --- a/include/boost/geometry/policies/robustness/segment_ratio.hpp +++ b/include/boost/geometry/policies/robustness/segment_ratio.hpp @@ -19,8 +19,8 @@ #include #include +#include #include -#include namespace boost { namespace geometry { 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/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/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/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/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 From e99cfde120ba347800a1b2472cffed93729e3ad1 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Wed, 8 Sep 2021 11:54:19 +0200 Subject: [PATCH 28/29] [intersection] use balance between distance-to-end and length-of-segments to determine to use a or b --- .../policies/robustness/segment_ratio.hpp | 64 +++++++------- .../strategies/cartesian/intersection.hpp | 85 +++++++++++++------ test/algorithms/buffer/buffer_linestring.cpp | 2 +- .../buffer/buffer_multi_polygon.cpp | 2 +- .../set_operations/difference/difference.cpp | 62 ++++++++------ .../difference/difference_areal_linear.cpp | 4 +- .../difference/difference_multi.cpp | 38 ++++++--- .../difference/difference_multi_spike.cpp | 40 +++------ .../difference/test_difference.hpp | 78 +++++++++++++---- .../sym_difference_areal_areal.cpp | 2 +- 10 files changed, 228 insertions(+), 149 deletions(-) diff --git a/include/boost/geometry/policies/robustness/segment_ratio.hpp b/include/boost/geometry/policies/robustness/segment_ratio.hpp index b1af50ffa..b4797f39c 100644 --- a/include/boost/geometry/policies/robustness/segment_ratio.hpp +++ b/include/boost/geometry/policies/robustness/segment_ratio.hpp @@ -135,11 +135,15 @@ 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 : inline segment_ratio() : m_numerator(0) @@ -221,8 +225,8 @@ public : m_approximation = m_denominator == 0 ? 0 : ( - boost::numeric_cast(m_numerator) * scale() - / boost::numeric_cast(m_denominator) + boost::numeric_cast(m_numerator) * scale() + / boost::numeric_cast(m_denominator) ); } @@ -254,21 +258,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 +312,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 +322,19 @@ 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; } }; diff --git a/include/boost/geometry/strategies/cartesian/intersection.hpp b/include/boost/geometry/strategies/cartesian/intersection.hpp index be7b92e59..2d96b9bef 100644 --- a/include/boost/geometry/strategies/cartesian/intersection.hpp +++ b/include/boost/geometry/strategies/cartesian/intersection.hpp @@ -68,6 +68,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 @@ -180,30 +235,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) { diff --git a/test/algorithms/buffer/buffer_linestring.cpp b/test/algorithms/buffer/buffer_linestring.cpp index b892ec30d..24c257438 100644 --- a/test/algorithms/buffer/buffer_linestring.cpp +++ b/test/algorithms/buffer/buffer_linestring.cpp @@ -430,7 +430,7 @@ int test_main(int, char* []) #endif #if defined(BOOST_GEOMETRY_TEST_FAILURES) - BoostGeometryWriteExpectedFailures(2, 4, 9, 4); + BoostGeometryWriteExpectedFailures(2, 4, 11, 3); #endif return 0; diff --git a/test/algorithms/buffer/buffer_multi_polygon.cpp b/test/algorithms/buffer/buffer_multi_polygon.cpp index 03ab006ae..d14ff436d 100644 --- a/test/algorithms/buffer/buffer_multi_polygon.cpp +++ b/test/algorithms/buffer/buffer_multi_polygon.cpp @@ -686,7 +686,7 @@ int test_main(int, char* []) #endif #if defined(BOOST_GEOMETRY_TEST_FAILURES) - BoostGeometryWriteExpectedFailures(5, 1, 3, 4); + BoostGeometryWriteExpectedFailures(3, 1, 3, 3); #endif return 0; diff --git a/test/algorithms/set_operations/difference/difference.cpp b/test/algorithms/set_operations/difference/difference.cpp index 403c79e83..910cf6df1 100644 --- a/test/algorithms/set_operations/difference/difference.cpp +++ b/test/algorithms/set_operations/difference/difference.cpp @@ -46,8 +46,6 @@ void test_all() { typedef bg::model::polygon

polygon; - typedef typename bg::coordinate_type

::type ct; - test_one("simplex_normal", simplex_normal[0], simplex_normal[1], 3, 12, 2.52636706856656, @@ -68,10 +66,15 @@ void test_all() 1, 5, 8.0, 1, 5, 8.0); - test_one("star_comb_15", - star_comb_15[0], star_comb_15[1], - 30, -1, 227.658275102812, - 30, -1, 480.485775259312); + { + ut_settings settings; + settings.validity_false_negative_sym = true; + test_one("star_comb_15", + star_comb_15[0], star_comb_15[1], + 30, -1, 227.658275102812, + 30, -1, 480.485775259312, + settings); + } test_one("new_hole", new_hole[0], new_hole[1], @@ -106,7 +109,7 @@ void test_all() { ut_settings settings; - settings.sym_difference_validity = BG_IF_RESCALED(true, false); + settings.validity_false_negative_sym = true; test_one("only_hole_intersections1", only_hole_intersections[0], only_hole_intersections[1], @@ -114,7 +117,7 @@ void test_all() 4, 16, 10.9090909, settings); - test_one("only_hole_intersection2", + test_one("only_hole_intersections2", only_hole_intersections[0], only_hole_intersections[2], 3, 20, 30.9090909, 4, 16, 10.9090909, @@ -144,7 +147,7 @@ void test_all() { ut_settings settings; - settings.sym_difference_validity = BG_IF_RESCALED(false, true); + settings.validity_of_sym = BG_IF_RESCALED(false, true); test_one("intersect_holes_intersect_and_disjoint", intersect_holes_intersect_and_disjoint[0], intersect_holes_intersect_and_disjoint[1], 2, 16, 15.75, @@ -180,7 +183,6 @@ void test_all() { ut_settings settings; - settings.sym_difference_validity = BG_IF_RESCALED(false, true); test_one("intersect_holes_intersect", intersect_holes_intersect[0], intersect_holes_intersect[1], 2, 16, 15.75, @@ -295,10 +297,9 @@ void test_all() 1, 61, 10.2717, 1, 61, 10.2717); - if ( BOOST_GEOMETRY_CONDITION((std::is_same::value)) ) { ut_settings settings; - settings.sym_difference_validity = BG_IF_RESCALED(true, false); + settings.validity_false_negative_sym = true; TEST_DIFFERENCE_WITH(buffer_mp2, 1, 12.09857, 1, 24.19714, count_set(1, 2), settings); } @@ -319,7 +320,7 @@ void test_all() ut_settings settings; settings.percentage = BG_IF_RESCALED(0.001, 0.1); settings.set_test_validity(BG_IF_RESCALED(true, false)); - settings.sym_difference = BG_IF_RESCALED(true, false); + settings.sym_difference = false; // Isovist - the # output polygons differ per compiler/pointtype, (very) small // rings might be discarded. We check area only @@ -330,18 +331,24 @@ void test_all() test_one("isovist", isovist1[0], isovist1[1], - ignore_count(), -1, 0.279132, + ignore_count(), -1, expectation_limits(0.279128, 0.279132), ignore_count(), -1, 224.8892, settings); } #if ! defined(BOOST_GEOMETRY_USE_RESCALING) || defined(BOOST_GEOMETRY_TEST_FAILURES) - // SQL Server gives: 0.28937764436705 and 0.000786406897532288 with 44/35 rings - // PostGIS gives: 0.30859375 and 0.033203125 with 35/35 rings - TEST_DIFFERENCE_WITH(geos_1, - ignore_count(), expectation_limits(0.20705, 0.29172), - ignore_count(), expectation_limits(0.00060440758, 0.00076856), - ignore_count(), ut_settings(0.1, false)); + { + ut_settings settings(0.1); + settings.set_test_validity(BG_IF_RESCALED(false, true)); + settings.validity_false_negative_sym = BG_IF_RESCALED(true, false); + + // SQL Server gives: 0.28937764436705 and 0.000786406897532288 with 44/35 rings + // PostGIS gives: 0.30859375 and 0.033203125 with 35/35 rings + TEST_DIFFERENCE_WITH(geos_1, + ignore_count(), expectation_limits(0.20705, 0.29172), + ignore_count(), expectation_limits(0.00060440758, 0.00076856), + ignore_count(), settings); + } #endif { @@ -425,7 +432,7 @@ void test_all() // With rescaling, difference of output a-b and a sym b is invalid ut_settings settings; settings.set_test_validity(BG_IF_RESCALED(false, true)); - settings.sym_difference_validity = BG_IF_RESCALED(false, true); + settings.validity_of_sym = BG_IF_RESCALED(false, true); TEST_DIFFERENCE_WITH(ggl_list_20190307_matthieu_1, count_set(1, 2), 0.18461532, count_set(1, 2), 0.617978, @@ -563,6 +570,7 @@ void test_all() { ut_settings settings; settings.set_test_validity(BG_IF_RESCALED(true, false)); + settings.validity_false_negative_a = true; TEST_DIFFERENCE_WITH(issue_838, count_set(1, 2), expectation_limits(0.000026, 0.0002823), count_set(1, 2), expectation_limits(0.67257, 0.67499), @@ -583,12 +591,16 @@ void test_all() TEST_DIFFERENCE(mysql_23023665_3, 1, 225.0, 1, 66.0, 2); TEST_DIFFERENCE(mysql_23023665_5, 2, 165.23735, 2, 105.73735, 4); { - // Without recaling it is invalid + // Without rescaling it is invalid ut_settings settings; - settings.set_test_validity(BG_IF_RESCALED(true, false)); + settings.set_test_validity(true); TEST_DIFFERENCE_WITH(mysql_23023665_6, 2, 105.68756, 3, 10.18756, 5, settings); } - TEST_DIFFERENCE(mysql_23023665_13, 3, 99.74526, 3, 37.74526, 6); + { + ut_settings settings; + settings.validity_false_negative_sym = true; + TEST_DIFFERENCE_WITH(mysql_23023665_13, 3, 99.74526, 3, 37.74526, 6, settings); + } } @@ -633,7 +645,7 @@ int test_main(int, char* []) // Not yet fully tested for float and long double. // The difference algorithm can generate (additional) slivers // Many of the failures are self-intersection points. - BoostGeometryWriteExpectedFailures(19, 10, 17, 12); + BoostGeometryWriteExpectedFailures(15, 5, 17, 10); #endif return 0; diff --git a/test/algorithms/set_operations/difference/difference_areal_linear.cpp b/test/algorithms/set_operations/difference/difference_areal_linear.cpp index 046b8c800..6fa40fd7d 100644 --- a/test/algorithms/set_operations/difference/difference_areal_linear.cpp +++ b/test/algorithms/set_operations/difference/difference_areal_linear.cpp @@ -240,8 +240,8 @@ int test_main(int, char* []) test_all >(); test_ticket_10835 - ("MULTILINESTRING((5239 2113,5233 2114),(4794 2205,1020 2986))", - "MULTILINESTRING((5239 2113,5233 2114),(4794 2205,1460 2895))"); + ("MULTILINESTRING((5239 2113,5232 2115),(4794 2205,1020 2986))", + "MULTILINESTRING((5239 2113,5232 2115),(4794 2205,1460 2895))"); test_ticket_10835 ("MULTILINESTRING((5239 2113,5232.52 2114.34),(4794.39 2205,1020 2986))", diff --git a/test/algorithms/set_operations/difference/difference_multi.cpp b/test/algorithms/set_operations/difference/difference_multi.cpp index 7d7cad485..2d1a9fcc6 100644 --- a/test/algorithms/set_operations/difference/difference_multi.cpp +++ b/test/algorithms/set_operations/difference/difference_multi.cpp @@ -155,10 +155,12 @@ void test_areal() #if ! defined(BOOST_GEOMETRY_USE_RESCALING) || defined(BOOST_GEOMETRY_TEST_FAILURES) { // 1: Very small sliver for B (discarded when rescaling) - // 2: sym difference is not considered as valid + // 2: sym difference is not considered as valid (without rescaling + // this is a false negative) // 3: with rescaling A is considered as invalid (robustness problem) ut_settings settings; - settings.sym_difference_validity = false; + settings.validity_of_sym = BG_IF_RESCALED(false, true); + settings.validity_false_negative_sym = true; TEST_DIFFERENCE_WITH(0, 1, bug_21155501, (count_set(1, 4)), expectation_limits(3.75893, 3.75894), (count_set(1, 4)), (expectation_limits(1.776357e-15, 7.661281e-15)), @@ -172,7 +174,7 @@ void test_areal() // Without rescaling, one ring is missing (for a and s) ut_settings settings; settings.set_test_validity(BG_IF_RESCALED(false, true)); - settings.sym_difference_validity = BG_IF_RESCALED(false, true); + settings.validity_of_sym = BG_IF_RESCALED(false, true); TEST_DIFFERENCE_WITH(0, 1, ticket_9081, 2, 0.0907392476356186, 4, 0.126018011439877, @@ -211,9 +213,12 @@ void test_areal() TEST_DIFFERENCE(issue_888_34, 22, 0.2506824, 6, 0.0253798, 28); // a went wrong TEST_DIFFERENCE(issue_888_37, 15, 0.0451408, 65, 0.3014843, 80); // b went wrong -#if defined(BOOST_GEOMETRY_TEST_FAILURES) - TEST_DIFFERENCE(issue_888_53, 117, 0.2973268, 17, 0.0525798, 134); // a goes wrong -#endif + { + ut_settings settings; + settings.validity_false_negative_a = true; + settings.validity_false_negative_sym = true; + TEST_DIFFERENCE_WITH(0, 1, issue_888_53, 117, 0.2973268, 17, 0.0525798, 134); + } // Areas and #clips correspond with POSTGIS (except sym case) test_one("case_101_multi", @@ -472,24 +477,29 @@ void test_specific_areal() { const std::string a_min_b = - TEST_DIFFERENCE(ticket_10661, 2, 1441632.5, 2, 13167454, 4); + test_one("ticket_10661", + ticket_10661[0], ticket_10661[1], + 2, -1, expectation_limits(1441632, 1441855), + 2, -1, expectation_limits(13167454, 13182415), + count_set(3, 4)); test_one("ticket_10661_2", a_min_b, ticket_10661[2], 1, 8, 825192.0, - 1, 10, expectation_limits(27226370, 27842812), - 1, -1, 825192.0 + 27226370.5); + 1, 10, expectation_limits(27226148, 27842812), + count_set(1, 2)); } { ut_settings settings; settings.sym_difference = false; - TEST_DIFFERENCE_WITH(0, 1, ticket_9942, 4, expectation_limits(7427727.5), 4, - expectation_limits(130083, 131507), 4); + TEST_DIFFERENCE_WITH(0, 1, ticket_9942, 4, + expectation_limits(7427727, 7428108), 4, + expectation_limits(130083, 131823), 4); TEST_DIFFERENCE_WITH(0, 1, ticket_9942a, 2, - expectation_limits(412676, 413184), 2, - expectation_limits(76779, 76925), 4); + expectation_limits(412676, 413469), 2, + expectation_limits(76779, 77038), 4); } } @@ -516,7 +526,7 @@ int test_main(int, char* []) #if defined(BOOST_GEOMETRY_TEST_FAILURES) // Not yet fully tested for float. // The difference algorithm can generate (additional) slivers - BoostGeometryWriteExpectedFailures(28, 15, 19, 10); + BoostGeometryWriteExpectedFailures(24, 11, 21, 7); #endif return 0; diff --git a/test/algorithms/set_operations/difference/difference_multi_spike.cpp b/test/algorithms/set_operations/difference/difference_multi_spike.cpp index a8c711e3c..0a9308d3a 100644 --- a/test/algorithms/set_operations/difference/difference_multi_spike.cpp +++ b/test/algorithms/set_operations/difference/difference_multi_spike.cpp @@ -20,6 +20,7 @@ void test_spikes_in_ticket_8364() { ut_settings ignore_validity; ignore_validity.set_test_validity(false); + ignore_validity.validity_of_sym = false; // See: https://svn.boost.org/trac/boost/ticket/8364 //_TPolygon polygon( "MULTIPOLYGON(((1031 1056,3232 1056,3232 2856,1031 2856)))" ); @@ -30,44 +31,27 @@ void test_spikes_in_ticket_8364() //polygon -= _TPolygon( "MULTIPOLYGON(((1032 2556,1032 2130,1778 2556)),((3234 2580,2136 2760,1778 2556,3234 2556)))" ); USED IN STEP 4 // NOTE: polygons below are closed and clockwise - typedef typename bg::coordinate_type

::type ct; typedef bg::model::polygon polygon; typedef bg::model::multi_polygon multi_polygon; // The difference of polygons below result in a spike. The spike should be there, it was also generated in ttmath, // and (e.g.) in SQL Server. However, using int-coordinates, the spike makes the polygon invalid. Therefore it is now (since August 2013) checked and removed. -#ifdef BOOST_GEOMETRY_TEST_FAILURES - // TODO: commented working at ii/validity, this changes the area slightly, to be checked // So using int's, the spike is removed automatically. Therefore there is one polygon less, and less points. Also area differs test_one("ticket_8364_step3", "MULTIPOLYGON(((3232 2532,2136 2790,1032 1764,1032 1458,1032 1212,2136 2328,3232 2220,3232 1056,1031 1056,1031 2856,3232 2856,3232 2532)))", "MULTIPOLYGON(((1032 2130,2052 2712,1032 1764,1032 2130)),((3234 2580,3234 2532,2558 2690,3234 2580)),((2558 2690,2136 2760,2052 2712,2136 2790,2558 2690)))", - 2, - if_typed(19, 22), - if_typed(2775595.5, 2775256.487954), // SQL Server: 2775256.47588724 - 3, - -1, // don't check point-count - if_typed(7893.0, 7810.487954), // SQL Server: 7810.48711165739 - if_typed(1, 5), - -1, - if_typed(2783349.5, 2775256.487954 + 7810.487954), - ignore_validity); -#endif + count_set(2, 3), -1, expectation_limits(2775256, 2775610), // SQL Server: 2775256.47588724 + 3, -1, expectation_limits(7810, 7893), // SQL Server: 7810.48711165739 + count_set(2, 6), ignore_validity); // TODO: behaviour is not good yet. It is changed at introduction of self-turns. test_one("ticket_8364_step4", "MULTIPOLYGON(((2567 2688,2136 2790,2052 2712,1032 2130,1032 1764,1032 1458,1032 1212,2136 2328,3232 2220,3232 1056,1031 1056,1031 2856,3232 2856,3232 2580,2567 2688)))", "MULTIPOLYGON(((1032 2556,1778 2556,1032 2130,1032 2556)),((3234 2580,3234 2556,1778 2556,2136 2760,3234 2580)))", - if_typed(1, 2), - if_typed(17, 20), - if_typed(2615783.5, 2616029.559567), // SQL Server: 2616029.55616044 - 1, - if_typed(9, 11), - if_typed(161133.5, 161054.559567), // SQL Server: 161054.560110092 - if_typed(1, 3), - if_typed(25, 31), - if_typed(2776875.5, 2616029.559567 + 161054.559567)); + count_set(1, 2), -1, expectation_limits(2615783, 2616030), // SQL Server: 2616029.55616044 + 1, -1, expectation_limits(161054, 161134), // SQL Server: 161054.560110092 + count_set(1, 3)); } template @@ -76,7 +60,6 @@ void test_spikes_in_ticket_8365() // See: https://svn.boost.org/trac/boost/ticket/8365 // NOTE: polygons below are closed and clockwise - typedef typename bg::coordinate_type

::type ct; typedef bg::model::polygon polygon; typedef bg::model::multi_polygon multi_polygon; @@ -85,13 +68,11 @@ void test_spikes_in_ticket_8365() "MULTIPOLYGON(((5388 1560,4650 1722,3912 1884,4650 1398)),((2442 3186,1704 3348,966 2700,1704 3024)))", 2, 18, - if_typed(7975092.5, 7975207.6047877), // SQL Server: + expectation_limits(7975092.5, 7975207.6047877), 2, -1, - if_typed(196.5, 197.1047877), // SQL Server: - if_typed(3, 4), - -1, - if_typed(7975092.5 + 196.5, 7975207.6047877 + 197.1047877)); + expectation_limits(196.5, 198.5), + count_set(2, 4)); } @@ -109,6 +90,7 @@ int test_main(int, char* []) test_spikes_in_ticket_8364, false, false>(); test_spikes_in_ticket_8365, true, true >(); test_spikes_in_ticket_8365, false, false >(); + return 0; } diff --git a/test/algorithms/set_operations/difference/test_difference.hpp b/test/algorithms/set_operations/difference/test_difference.hpp index 2dfc542a2..3ec8dfa24 100644 --- a/test/algorithms/set_operations/difference/test_difference.hpp +++ b/test/algorithms/set_operations/difference/test_difference.hpp @@ -59,20 +59,45 @@ # include #endif +enum difference_type +{ + difference_a, difference_b, difference_sym +}; struct ut_settings : ut_base_settings { double percentage; bool sym_difference; - bool sym_difference_validity = true; + bool validity_of_sym = true; bool remove_spikes = false; + // The validity check gives sometimes false negatives. + // boost::geometry::is_valid can return FALSE while it is valid. + // (especially at touch in combination with a u/u turn) + // For now, the cases where this is the case are skipped for validity check. + bool validity_false_negative_a = false; + bool validity_false_negative_b = false; + bool validity_false_negative_sym = false; + explicit ut_settings(double p = 0.0001, bool validity = true, bool sd = true) : ut_base_settings(validity) , percentage(p) , sym_difference(sd) {} + bool test_validity_of_diff(difference_type dtype) const + { + bool const sym = dtype == difference_sym; + bool const a = dtype == difference_a; + bool const b = dtype == difference_b; + + return sym && validity_false_negative_sym ? false + : a && validity_false_negative_a ? false + : b && validity_false_negative_b ? false + : sym ? (validity_of_sym || BG_IF_TEST_FAILURES) + : test_validity(); + } + }; inline ut_settings tolerance(double percentage) @@ -137,7 +162,7 @@ std::string test_difference(std::string const& caseid, G1 const& g1, G2 const& g const count_set& expected_count, int expected_rings_count, int expected_point_count, expectation_limits const& expected_area, - bool sym, + difference_type dtype, ut_settings const& settings) { typedef typename bg::coordinate_type::type coordinate_type; @@ -145,8 +170,7 @@ std::string test_difference(std::string const& caseid, G1 const& g1, G2 const& g bg::model::multi_polygon result; - - if (sym) + if (dtype == difference_sym) { bg::sym_difference(g1, g2, result); } @@ -167,7 +191,7 @@ std::string test_difference(std::string const& caseid, G1 const& g1, G2 const& g < G1, G2 >::type strategy_type; - if (sym) + if (dtype == difference_sym) { bg::sym_difference(g1, g2, result_s, strategy_type()); } @@ -191,12 +215,7 @@ std::string test_difference(std::string const& caseid, G1 const& g1, G2 const& g typename bg::default_area_result::type const area = bg::area(result); #if ! defined(BOOST_GEOMETRY_NO_BOOST_TEST) - bool const test_validity - = sym - ? (settings.sym_difference_validity || BG_IF_TEST_FAILURES) - : settings.test_validity(); - - if (test_validity) + if (settings.test_validity_of_diff(dtype)) { // std::cout << bg::dsv(result) << std::endl; typedef bg::model::multi_polygon result_type; @@ -218,7 +237,7 @@ std::string test_difference(std::string const& caseid, G1 const& g1, G2 const& g typename setop_output_type::type inserted, array_with_one_empty_geometry; array_with_one_empty_geometry.push_back(OutputType()); - if (sym) + if (dtype == difference_sym) { boost::copy(array_with_one_empty_geometry, bg::detail::sym_difference::sym_difference_insert @@ -287,12 +306,12 @@ template std::string test_difference(std::string const& caseid, G1 const& g1, G2 const& g2, const count_set& expected_count, int expected_point_count, expectation_limits const& expected_area, - bool sym, + difference_type dtype, ut_settings const& settings) { return test_difference(caseid, g1, g2, expected_count, -1, expected_point_count, expected_area, - sym, settings); + dtype, settings); } #ifdef BOOST_GEOMETRY_CHECK_WITH_POSTGIS @@ -331,7 +350,7 @@ std::string test_one(std::string const& caseid, #if ! defined(BOOST_GEOMETRY_TEST_DIFFERENCE_ONLY_B) result = test_difference(caseid + "_a", g1, g2, expected_count1, expected_rings_count1, expected_point_count1, - expected_area1, false, settings); + expected_area1, difference_a, settings); #endif #if defined(BOOST_GEOMETRY_TEST_DIFFERENCE_ONLY_A) return result; @@ -339,7 +358,7 @@ std::string test_one(std::string const& caseid, test_difference(caseid + "_b", g2, g1, expected_count2, expected_rings_count2, expected_point_count2, - expected_area2, false, settings); + expected_area2, difference_b, settings); #if defined(BOOST_GEOMETRY_TEST_DIFFERENCE_ONLY_B) return result; @@ -354,7 +373,7 @@ std::string test_one(std::string const& caseid, expected_rings_count_s, expected_point_count_s, expected_area_s, - true, settings); + difference_sym, settings); } return result; } @@ -383,6 +402,7 @@ std::string test_one(std::string const& caseid, settings); } +// Version with expectations of symmetric: all specified template std::string test_one(std::string const& caseid, std::string const& wkt1, std::string const& wkt2, @@ -404,6 +424,30 @@ std::string test_one(std::string const& caseid, settings); } +// Version with expectations of symmetric: specify only count +template +std::string test_one(std::string const& caseid, + std::string const& wkt1, std::string const& wkt2, + const count_set& expected_count1, + int expected_point_count1, + expectation_limits const& expected_area1, + const count_set& expected_count2, + int expected_point_count2, + expectation_limits const& expected_area2, + const count_set& expected_count_s, + ut_settings const& settings = ut_settings()) +{ + return test_one(caseid, wkt1, wkt2, + expected_count1, -1, expected_point_count1, expected_area1, + expected_count2, -1, expected_point_count2, expected_area2, + expected_count_s, -1, + expected_point_count1 >= 0 && expected_point_count2 >= 0 + ? (expected_point_count1 + expected_point_count2) : -1, + expected_area1 + expected_area2, + settings); +} + +// Version with expectations of symmetric: all automatically template std::string test_one(std::string const& caseid, std::string const& wkt1, std::string const& wkt2, diff --git a/test/algorithms/set_operations/sym_difference/sym_difference_areal_areal.cpp b/test/algorithms/set_operations/sym_difference/sym_difference_areal_areal.cpp index b0b386c1f..c6107f360 100644 --- a/test/algorithms/set_operations/sym_difference/sym_difference_areal_areal.cpp +++ b/test/algorithms/set_operations/sym_difference/sym_difference_areal_areal.cpp @@ -75,7 +75,7 @@ struct test_sym_difference_of_areal_geometries PolygonOut >(case_id, areal1, areal2, expected_polygon_count, expected_point_count, expected_area, - true, settings); + difference_sym, settings); } }; From 716c7913657f8d4d6cac7cdc60dfc98e8b6d8b1f Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Wed, 8 Sep 2021 14:39:49 +0200 Subject: [PATCH 29/29] [test] enhance/fix robustness tests --- .../general_intersection_precision.cpp | 86 +++++++++------ .../areal_areal/interior_triangles.cpp | 10 +- .../overlay/areal_areal/intersection_pies.cpp | 8 +- .../areal_areal/intersection_stars.cpp | 16 ++- .../overlay/areal_areal/intersects.cpp | 19 +++- .../areal_areal/random_ellipses_stars.cpp | 14 ++- .../areal_areal/recursive_polygons.cpp | 9 +- .../overlay/areal_areal/star_comb.cpp | 9 +- .../overlay/areal_areal/test_overlay_p_q.hpp | 103 ++++++++++-------- .../buffer/recursive_polygons_buffer.cpp | 4 +- 10 files changed, 177 insertions(+), 101 deletions(-) diff --git a/test/robustness/overlay/areal_areal/general_intersection_precision.cpp b/test/robustness/overlay/areal_areal/general_intersection_precision.cpp index afd1bdbac..dc7527ae9 100644 --- a/test/robustness/overlay/areal_areal/general_intersection_precision.cpp +++ b/test/robustness/overlay/areal_areal/general_intersection_precision.cpp @@ -1,7 +1,7 @@ // Boost.Geometry // Robustness Test -// Copyright (c) 2019 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2019-2021 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2021. // Modifications copyright (c) 2021, Oracle and/or its affiliates. @@ -11,6 +11,8 @@ // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#define BOOST_GEOMETRY_NO_ROBUSTNESS + #include #include #include @@ -42,11 +44,22 @@ static std::string case_c[2] = "MULTIPOLYGON(((1 1,0 1,0 3,1 3,1 1)))" }; +struct test_settings +{ + bool verbose{false}; + bool do_output{false}; + + // Settings currently not modifiable, and still giving quite some errors + double start_bound{1.0e-2}; + double step_factor{50.0}; // on each side -> 100 steps per factor + int max_factor{10000}; +}; + template bool test_overlay(std::string const& caseid, Geometry const& g1, Geometry const& g2, double expected_area, - bool do_output) + test_settings const& settings) { typedef typename boost::range_value::type geometry_out; @@ -62,9 +75,9 @@ bool test_overlay(std::string const& caseid, OverlayType > overlay; - typedef typename bg::strategy::intersection::services::default_strategy + typedef typename bg::strategies::relate::services::default_strategy < - typename bg::cs_tag::type + Geometry, Geometry >::type strategy_type; strategy_type strategy; @@ -86,7 +99,7 @@ bool test_overlay(std::string const& caseid, const double detected_area = bg::area(result); if (std::fabs(detected_area - expected_area) > 0.01) { - if (do_output) + if (settings.do_output) { std::cout << "ERROR: " << caseid << std::setprecision(18) << " detected=" << detected_area @@ -118,9 +131,9 @@ template std::size_t test_case(std::size_t& error_count, std::size_t case_index, std::size_t i, std::size_t j, std::size_t min_vertex_index, std::size_t max_vertex_index, - double x, double y, double expectation, + double offset_x, double offset_y, double expectation, MultiPolygon const& poly1, MultiPolygon const& poly2, - bool do_output) + test_settings const settings) { std::size_t n = 0; for (std::size_t k = min_vertex_index; k <= max_vertex_index; k++, ++n) @@ -130,21 +143,23 @@ std::size_t test_case(std::size_t& error_count, switch (case_index) { case 2 : - update(bg::interior_rings(poly2_adapted.front()).front(), x, y, k); + update(bg::interior_rings(poly2_adapted.front()).front(), offset_x, offset_y, k); break; default : - update(bg::exterior_ring(poly2_adapted.front()), x, y, k); + update(bg::exterior_ring(poly2_adapted.front()), offset_x, offset_y, k); break; } std::ostringstream out; out << "case_" << i << "_" << j << "_" << k; - if (! test_overlay(out.str(), poly1, poly2_adapted, expectation, do_output)) + if (! test_overlay(out.str(), poly1, poly2_adapted, expectation, settings)) { - if (error_count == 0) + if (error_count == 0 && ! settings.do_output) { // First failure is always reported - test_overlay(out.str(), poly1, poly2_adapted, expectation, true); + test_settings adapted = settings; + adapted.do_output = true; + test_overlay(out.str(), poly1, poly2_adapted, expectation, adapted); } error_count++; } @@ -155,7 +170,7 @@ std::size_t test_case(std::size_t& error_count, template std::size_t test_all(std::size_t case_index, std::size_t min_vertex_index, std::size_t max_vertex_index, - double expectation, bool do_output) + double expectation, test_settings const& settings) { typedef bg::model::point point_type; typedef bg::model::polygon polygon; @@ -177,21 +192,25 @@ std::size_t test_all(std::size_t case_index, std::size_t min_vertex_index, std::size_t error_count = 0; std::size_t n = 0; - for (double factor = 1.0; factor > 1.0e-10; factor /= 10.0) + for (int factor = 1; factor < settings.max_factor; factor *= 2) { std::size_t i = 0; - double const bound = 1.0e-5 * factor; - double const step = 1.0e-6 * factor; - for (double x = -bound; x <= bound; x += step, ++i) + double const bound = settings.start_bound / factor; + double const step = bound / settings.step_factor; + if (settings.verbose) + { + std::cout << "--> use " << bound << " " << step << std::endl; + } + for (double offset_x = -bound; offset_x <= bound; offset_x += step, ++i) { std::size_t j = 0; - for (double y = -bound; y <= bound; y += step, ++j, ++n) + for (double offset_y = -bound; offset_y <= bound; offset_y += step, ++j, ++n) { n += test_case(error_count, case_index, i, j, - min_vertex_index, max_vertex_index, - x, y, expectation, - poly1, poly2, do_output); + min_vertex_index, max_vertex_index, + offset_x, offset_y, expectation, + poly1, poly2, settings); } } } @@ -205,22 +224,17 @@ std::size_t test_all(std::size_t case_index, std::size_t min_vertex_index, int test_main(int argc, char** argv) { - typedef double coordinate_type; + BoostGeometryWriteTestConfiguration(); + using coor_t = default_test_type; - const double factor = argc > 1 ? atof(argv[1]) : 2.0; - const bool do_output = argc > 2 && atol(argv[2]) == 1; + test_settings settings; + settings.do_output = argc > 2 && atol(argv[2]) == 1; - std::cout << std::endl << " -> TESTING " - << string_from_type::name() - << " " << factor - << std::endl; - - test_all(1, 0, 3, 22.0, do_output); - test_all(2, 0, 3, 73.0, do_output); - test_all(3, 1, 2, 2.0, do_output); - test_all(3, 1, 2, 14.0, do_output); + // Test three polygons, for the last test two types of intersections + test_all(1, 0, 3, 22.0, settings); + test_all(2, 0, 3, 73.0, settings); + test_all(3, 1, 2, 2.0, settings); + test_all(3, 1, 2, 14.0, settings); return 0; - } - - +} diff --git a/test/robustness/overlay/areal_areal/interior_triangles.cpp b/test/robustness/overlay/areal_areal/interior_triangles.cpp index f8f52f44a..95275e9fe 100644 --- a/test/robustness/overlay/areal_areal/interior_triangles.cpp +++ b/test/robustness/overlay/areal_areal/interior_triangles.cpp @@ -1,13 +1,17 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Robustness Test -// Copyright (c) 2009-2020 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2009-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) #define BOOST_GEOMETRY_NO_BOOST_TEST +#define BOOST_GEOMETRY_NO_ROBUSTNESS +#define BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE + +// NOTE: there is no randomness here. Count is to measure performance #include @@ -113,8 +117,10 @@ int main(int argc, char** argv) ("count_y", po::value(&count_y)->default_value(10), "Triangle count in y-direction") ("offset", po::value(&offset)->default_value(0), "Offset of second triangle in x-direction") ("diff", po::value(&settings.also_difference)->default_value(false), "Include testing on difference") +#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE) ("ccw", po::value(&ccw)->default_value(false), "Counter clockwise polygons") ("open", po::value(&open)->default_value(false), "Open polygons") +#endif ("wkt", po::value(&settings.wkt)->default_value(false), "Create a WKT of the inputs, for all tests") ("svg", po::value(&settings.svg)->default_value(false), "Create a SVG for all tests") ; @@ -129,6 +135,7 @@ int main(int argc, char** argv) return 1; } +#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE) if (ccw && open) { test_all(count, count_x, count_y, offset, settings); @@ -142,6 +149,7 @@ int main(int argc, char** argv) test_all(count, count_x, count_y, offset, settings); } else +#endif { test_all(count, count_x, count_y, offset, settings); } diff --git a/test/robustness/overlay/areal_areal/intersection_pies.cpp b/test/robustness/overlay/areal_areal/intersection_pies.cpp index 2312d4cb2..e38e90d76 100644 --- a/test/robustness/overlay/areal_areal/intersection_pies.cpp +++ b/test/robustness/overlay/areal_areal/intersection_pies.cpp @@ -1,13 +1,15 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Robustness Test -// Copyright (c) 2009-2020 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2009-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) #define BOOST_GEOMETRY_NO_BOOST_TEST +#define BOOST_GEOMETRY_NO_ROBUSTNESS +#define BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE #include @@ -256,8 +258,10 @@ int main(int argc, char** argv) ("help", "Help message") ("multi", po::value(&multi)->default_value(false), "Multiple tangencies at one point") ("diff", po::value(&settings.also_difference)->default_value(false), "Include testing on difference") +#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE) ("ccw", po::value(&ccw)->default_value(false), "Counter clockwise polygons") ("open", po::value(&open)->default_value(false), "Open polygons") +#endif ("wkt", po::value(&settings.wkt)->default_value(false), "Create a WKT of the inputs, for all tests") ("svg", po::value(&settings.svg)->default_value(false), "Create a SVG for all tests") ; @@ -273,6 +277,7 @@ int main(int argc, char** argv) } // template par's are: CoordinateType, Clockwise, Closed +#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE) if (ccw && open) { test_all(multi, single_selftangent, settings); @@ -286,6 +291,7 @@ int main(int argc, char** argv) test_all(multi, single_selftangent, settings); } else +#endif { test_all(multi, single_selftangent, settings); } diff --git a/test/robustness/overlay/areal_areal/intersection_stars.cpp b/test/robustness/overlay/areal_areal/intersection_stars.cpp index 368857f44..6a8ed8ed1 100644 --- a/test/robustness/overlay/areal_areal/intersection_stars.cpp +++ b/test/robustness/overlay/areal_areal/intersection_stars.cpp @@ -1,13 +1,17 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Robustness Test -// Copyright (c) 2009-2020 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2009-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) #define BOOST_GEOMETRY_NO_BOOST_TEST +#define BOOST_GEOMETRY_NO_ROBUSTNESS +#define BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE + +// NOTE: there is no randomness here. Count is to measure performance #include @@ -109,12 +113,14 @@ void test_type(int count, int min_points, int max_points, T rotation, p_q_settin template void test_all(std::string const& type, int count, int min_points, int max_points, T rotation, p_q_settings settings) { +#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE) if (type == "float") { settings.tolerance = 1.0e-3; test_type(count, min_points, max_points, rotation, settings); } else if (type == "double") +#endif { test_type(count, min_points, max_points, rotation, settings); } @@ -130,7 +136,7 @@ int main(int argc, char** argv) int count = 1; //int seed = static_cast(std::time(0)); - std::string type = "float"; + std::string type = "double"; int min_points = 9; int max_points = 9; bool ccw = false; @@ -140,15 +146,17 @@ int main(int argc, char** argv) description.add_options() ("help", "Help message") - //("seed", po::value(&seed), "Initialization seed for random generator") + // ("seed", po::value(&seed), "Initialization seed for random generator") ("count", po::value(&count)->default_value(1), "Number of tests") ("diff", po::value(&settings.also_difference)->default_value(false), "Include testing on difference") ("min_points", po::value(&min_points)->default_value(9), "Minimum number of points") ("max_points", po::value(&max_points)->default_value(9), "Maximum number of points") ("rotation", po::value(&rotation)->default_value(1.0e-13), "Rotation angle") +#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE) ("ccw", po::value(&ccw)->default_value(false), "Counter clockwise polygons") ("open", po::value(&open)->default_value(false), "Open polygons") - ("type", po::value(&type)->default_value("float"), "Type (float,double)") + ("type", po::value(&type)->default_value("double"), "Type (float,double)") +#endif ("wkt", po::value(&settings.wkt)->default_value(false), "Create a WKT of the inputs, for all tests") ("svg", po::value(&settings.svg)->default_value(false), "Create a SVG for all tests") ; diff --git a/test/robustness/overlay/areal_areal/intersects.cpp b/test/robustness/overlay/areal_areal/intersects.cpp index 8f9031317..21ab6a265 100644 --- a/test/robustness/overlay/areal_areal/intersects.cpp +++ b/test/robustness/overlay/areal_areal/intersects.cpp @@ -1,13 +1,17 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Robustness Test -// Copyright (c) 2011-2020 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2011-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) #define BOOST_GEOMETRY_NO_BOOST_TEST +#define BOOST_GEOMETRY_NO_ROBUSTNESS +#define BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE + +// NOTE: there is no randomness here. Count is to measure performance #include @@ -43,9 +47,8 @@ inline void make_polygon(MultiPolygon& mp, int count_x, int count_y, int index, } - template -void test_intersects(int count_x, int count_y, int width_x, p_q_settings const& settings) +void test_intersects(int index, int count_x, int count_y, int width_x, p_q_settings const& settings) { MultiPolygon mp; @@ -64,6 +67,10 @@ void test_intersects(int count_x, int count_y, int width_x, p_q_settings const& std::ostringstream filename; filename << "intersects_" << string_from_type::name() + << "_" << index + << "_" << count_x + << "_" << count_y + << "_" << width_x << ".svg"; std::ofstream svg(filename.str().c_str()); @@ -92,7 +99,7 @@ void test_all(int count, int count_x, int count_y, int width_x, p_q_settings con for(int i = 0; i < count; i++) { - test_intersects(count_x, count_y, width_x, settings); + test_intersects(i, count_x, count_y, width_x, settings); } auto const t = std::chrono::high_resolution_clock::now(); auto const elapsed_ms = std::chrono::duration_cast(t - t0).count(); @@ -123,8 +130,10 @@ int main(int argc, char** argv) ("count_x", po::value(&count_x)->default_value(10), "Triangle count in x-direction") ("count_y", po::value(&count_y)->default_value(10), "Triangle count in y-direction") ("width_x", po::value(&width_x)->default_value(7), "Width of triangle in x-direction") +#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE) ("ccw", po::value(&ccw)->default_value(false), "Counter clockwise polygons") ("open", po::value(&open)->default_value(false), "Open polygons") +#endif ("wkt", po::value(&settings.wkt)->default_value(false), "Create a WKT of the inputs, for all tests") ("svg", po::value(&settings.svg)->default_value(false), "Create a SVG for all tests") ; @@ -139,6 +148,7 @@ int main(int argc, char** argv) return 1; } +#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE) if (ccw && open) { test_all(count, count_x, count_y, width_x, settings); @@ -152,6 +162,7 @@ int main(int argc, char** argv) test_all(count, count_x, count_y, width_x, settings); } else +#endif { test_all(count, count_x, count_y, width_x, settings); } diff --git a/test/robustness/overlay/areal_areal/random_ellipses_stars.cpp b/test/robustness/overlay/areal_areal/random_ellipses_stars.cpp index f7e9fdfb9..59054b092 100644 --- a/test/robustness/overlay/areal_areal/random_ellipses_stars.cpp +++ b/test/robustness/overlay/areal_areal/random_ellipses_stars.cpp @@ -1,13 +1,15 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Robustness Test -// Copyright (c) 2009-2020 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2009-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) #define BOOST_GEOMETRY_NO_BOOST_TEST +#define BOOST_GEOMETRY_NO_ROBUSTNESS +#define BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE #include @@ -166,11 +168,13 @@ void test_type(int seed, int count, p_q_settings const& settings) template void test_all(std::string const& type, int seed, int count, p_q_settings settings) { +#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE) if (type == "float") { test_type(seed, count, settings); } else if (type == "double") +#endif { test_type(seed, count, settings); } @@ -187,7 +191,7 @@ int main(int argc, char** argv) int count = 1; int seed = static_cast(std::time(0)); - std::string type = "float"; + std::string type = "double"; bool ccw = false; bool open = false; p_q_settings settings; @@ -197,9 +201,11 @@ int main(int argc, char** argv) ("seed", po::value(&seed), "Initialization seed for random generator") ("count", po::value(&count)->default_value(1), "Number of tests") ("diff", po::value(&settings.also_difference)->default_value(false), "Include testing on difference") +#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE) ("ccw", po::value(&ccw)->default_value(false), "Counter clockwise polygons") ("open", po::value(&open)->default_value(false), "Open polygons") - ("type", po::value(&type)->default_value("float"), "Type (float,double)") + ("type", po::value(&type)->default_value("double"), "Type (float,double)") +#endif ("wkt", po::value(&settings.wkt)->default_value(false), "Create a WKT of the inputs, for all tests") ("svg", po::value(&settings.svg)->default_value(false), "Create a SVG for all tests") ; @@ -214,6 +220,7 @@ int main(int argc, char** argv) return 1; } +#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE) if (ccw && open) { test_all(type, seed, count, settings); @@ -227,6 +234,7 @@ int main(int argc, char** argv) test_all(type, seed, count, settings); } else +#endif { test_all(type, seed, count, settings); } diff --git a/test/robustness/overlay/areal_areal/recursive_polygons.cpp b/test/robustness/overlay/areal_areal/recursive_polygons.cpp index a2cc17db8..f97becafe 100644 --- a/test/robustness/overlay/areal_areal/recursive_polygons.cpp +++ b/test/robustness/overlay/areal_areal/recursive_polygons.cpp @@ -1,13 +1,15 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Robustness Test -// Copyright (c) 2009-2020 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2009-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) #define BOOST_GEOMETRY_NO_BOOST_TEST +#define BOOST_GEOMETRY_NO_ROBUSTNESS +#define BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE #include @@ -174,8 +176,10 @@ int main(int argc, char** argv) ("level", po::value(&level)->default_value(3), "Level to reach (higher->slower)") ("size", po::value(&field_size)->default_value(10), "Size of the field") ("form", po::value(&form)->default_value("box"), "Form of the polygons (box, triangle)") +#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE) ("ccw", po::value(&ccw)->default_value(false), "Counter clockwise polygons") ("open", po::value(&open)->default_value(false), "Open polygons") +#endif ("wkt", po::value(&settings.wkt)->default_value(false), "Create a WKT of the inputs, for all tests") ("svg", po::value(&settings.svg)->default_value(false), "Create a SVG for all tests") ; @@ -193,7 +197,7 @@ int main(int argc, char** argv) bool triangular = form != "box"; - +#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE) if (ccw && open) { test_all(seed, count, field_size, level, triangular, settings); @@ -207,6 +211,7 @@ int main(int argc, char** argv) test_all(seed, count, field_size, level, triangular, settings); } else +#endif { test_all(seed, count, field_size, level, triangular, settings); } diff --git a/test/robustness/overlay/areal_areal/star_comb.cpp b/test/robustness/overlay/areal_areal/star_comb.cpp index 19e5350a2..90a7d0d05 100644 --- a/test/robustness/overlay/areal_areal/star_comb.cpp +++ b/test/robustness/overlay/areal_areal/star_comb.cpp @@ -1,13 +1,15 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Robustness Test -// Copyright (c) 2009-2020 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2009-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) #define BOOST_GEOMETRY_NO_BOOST_TEST +#define BOOST_GEOMETRY_NO_ROBUSTNESS +#define BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE #include @@ -98,8 +100,10 @@ int main(int argc, char** argv) ("count", po::value(&count)->default_value(1), "Number of tests") ("point_count", po::value(&point_count)->default_value(1), "Number of points in the star") ("diff", po::value(&settings.also_difference)->default_value(false), "Include testing on difference") +#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE) ("ccw", po::value(&ccw)->default_value(false), "Counter clockwise polygons") ("open", po::value(&open)->default_value(false), "Open polygons") +#endif ("wkt", po::value(&settings.wkt)->default_value(false), "Create a WKT of the inputs, for all tests") ("svg", po::value(&settings.svg)->default_value(false), "Create a SVG for all tests") ; @@ -117,7 +121,7 @@ int main(int argc, char** argv) int star_point_count = point_count * 2 + 1; int comb_comb_count = point_count; - +#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE) if (ccw && open) { test_all(count, star_point_count, comb_comb_count, factor1, factor2, do_union, settings); @@ -131,6 +135,7 @@ int main(int argc, char** argv) test_all(count, star_point_count, comb_comb_count, factor1, factor2, do_union, settings); } else +#endif { test_all(count, star_point_count, comb_comb_count, factor1, factor2, do_union, settings); } diff --git a/test/robustness/overlay/areal_areal/test_overlay_p_q.hpp b/test/robustness/overlay/areal_areal/test_overlay_p_q.hpp index 2e1f421ce..af0ec8264 100644 --- a/test/robustness/overlay/areal_areal/test_overlay_p_q.hpp +++ b/test/robustness/overlay/areal_areal/test_overlay_p_q.hpp @@ -1,7 +1,7 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Robustness Test -// Copyright (c) 2009-2020 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2009-2021 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2021. // Modifications copyright (c) 2021, Oracle and/or its affiliates. @@ -40,21 +40,16 @@ struct p_q_settings { - bool svg; - bool also_difference; - bool validity; - bool wkt; - bool verify_area; - double tolerance; + bool svg{false}; + bool also_difference{false}; + bool validity{false}; + bool wkt{false}; + bool verify_area{false}; + double tolerance{1.0e-3}; + bool verbose{false}; - p_q_settings() - : svg(false) - , also_difference(false) - , validity(false) - , wkt(false) - , verify_area(false) - , tolerance(1.0e-3) // since rescaling to integer the tolerance should be less. Was originally 1.0e-6 - {} + // NOTE: since rescaling to integer the tolerance is less. + // Was originally 1.0e-6 TODO: restore }; template @@ -209,6 +204,7 @@ static bool test_overlay_p_q(std::string const& caseid, } bool svg = settings.svg; + bool wkt = settings.wkt; if (wrong || settings.wkt) { @@ -216,53 +212,66 @@ static bool test_overlay_p_q(std::string const& caseid, { result = false; svg = true; + wkt = true; } - bg::unique(out_i); - bg::unique(out_u); - std::cout - << "type: " << string_from_type::name() - << " id: " << caseid - << " area i: " << area_i - << " area u: " << area_u - << " area p: " << area_p - << " area q: " << area_q - << " sum: " << sum; - - if (settings.also_difference) + if (settings.verbose) { std::cout - << " area d1: " << area_d1 - << " area d2: " << area_d2; - } - std::cout - << std::endl - << std::setprecision(9) - << " p: " << bg::wkt(p) << std::endl - << " q: " << bg::wkt(q) << std::endl - << " i: " << bg::wkt(out_i) << std::endl - << " u: " << bg::wkt(out_u) << std::endl - ; + << "type: " << string_from_type::name() + << " id: " << caseid + << " area i: " << area_i + << " area u: " << area_u + << " area p: " << area_p + << " area q: " << area_q + << " sum: " << sum; + if (settings.also_difference) + { + std::cout + << " area d1: " << area_d1 + << " area d2: " << area_d2; + } + std::cout + << std::endl + << std::setprecision(9) + << " p: " << bg::wkt(p) << std::endl + << " q: " << bg::wkt(q) << std::endl + << " i: " << bg::wkt(out_i) << std::endl + << " u: " << bg::wkt(out_u) << std::endl; + } } - if(svg) + std::string filename; { - std::ostringstream filename; - filename << "overlay_" << caseid << "_" + std::ostringstream out; + out << "overlay_" << caseid << "_" << string_from_type::name(); if (!std::is_same::value) { - filename << string_from_type::name(); + out << string_from_type::name(); } - - filename + out #if defined(BOOST_GEOMETRY_USE_RESCALING) - << "_rescaled" + << "_rescaled" #endif - << ".svg"; + << "."; + filename = out.str(); + } - std::ofstream svg(filename.str().c_str()); + if (wkt) + { + std::ofstream stream(filename + "wkt"); + // Stream input WKT's + stream << bg::wkt(p) << std::endl; + stream << bg::wkt(q) << std::endl; + // If you need the output WKT, then stream out_i and out_u + } + + + if (svg) + { + std::ofstream svg(filename + "svg"); bg::svg_mapper mapper(svg, 500, 500); diff --git a/test/robustness/overlay/buffer/recursive_polygons_buffer.cpp b/test/robustness/overlay/buffer/recursive_polygons_buffer.cpp index 13dba836b..330d78bbf 100644 --- a/test/robustness/overlay/buffer/recursive_polygons_buffer.cpp +++ b/test/robustness/overlay/buffer/recursive_polygons_buffer.cpp @@ -1,7 +1,7 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Robustness Test -// Copyright (c) 2012-2020 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2012-2021 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2015-2021. // Modifications copyright (c) 2015-2021 Oracle and/or its affiliates. @@ -13,6 +13,8 @@ // http://www.boost.org/LICENSE_1_0.txt) #define BOOST_GEOMETRY_NO_BOOST_TEST +#define BOOST_GEOMETRY_NO_ROBUSTNESS +#define BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE #if defined(_MSC_VER) # pragma warning( disable : 4244 )