From dc4bf170662b92f1fff24380071924f4e3a37426 Mon Sep 17 00:00:00 2001 From: fhamonic Date: Thu, 3 Oct 2024 02:15:25 +0200 Subject: [PATCH] bentley-ottmann ok --- .../melon/experimental/bentley_ottmann.hpp | 62 +++++++++++-------- test/bentley_ottmann_test.cpp | 59 +++++++++--------- 2 files changed, 66 insertions(+), 55 deletions(-) diff --git a/include/melon/experimental/bentley_ottmann.hpp b/include/melon/experimental/bentley_ottmann.hpp index 6968b2c..4f1b621 100644 --- a/include/melon/experimental/bentley_ottmann.hpp +++ b/include/melon/experimental/bentley_ottmann.hpp @@ -144,7 +144,9 @@ struct cartesian { determinant))); } static constexpr auto line_slope(const cartesian_line auto & l) { - return rational(std::get<0>(l), std::get<1>(l)); + // return rational(std::get<0>(l), std::get<1>(l)); + return rational(std::get<1>(l) != 0 ? std::get<0>(l) : -1, + std::get<1>(l)); } static constexpr auto segments_intersection( const cartesian_segment auto & A, const cartesian_segment auto & B) { @@ -243,11 +245,9 @@ class bentley_ottmann { std::get<1>(line) * std::get<0>(event_point).denom); } - [[nodiscard]] constexpr auto sweepline_y_intersection( + [[nodiscard]] constexpr const auto & sweepline_y_intersection( const intersection & event_point) const { - // if constexpr(HANDLE_VERTICAL_SEGMENTS) { - // if(std::get<1>(line) == 0) return std::get<1>(event_point); - //} + if(std::get<1>(line) == 0) return std::get<1>(event_point); if(std::get<0>(sweepline_intersection) == std::get<0>(event_point)) return std::get<1>(sweepline_intersection); @@ -334,20 +334,32 @@ class bentley_ottmann { private: void push_segment_start(const intersection & i, const segment_id_type & s) { auto && [it, inserted] = _events_map.try_emplace(i); - if(inserted) _event_heap.push(i); + if(inserted) { + _event_heap.push(i); + // fmt::print("pushed start ({}/{}, {}/{})\n", std::get<0>(i).num, + // std::get<0>(i).denom, std::get<1>(i).num, + // std::get<1>(i).denom); + } it->second.emplace_back(s, event_type::starting); } void push_segment_end(const intersection & i, const segment_id_type & s) { auto && [it, inserted] = _events_map.try_emplace(i); - if(inserted) _event_heap.push(i); + if(inserted) { + _event_heap.push(i); + // fmt::print("pushed end ({}/{}, {}/{})\n", std::get<0>(i).num, + // std::get<0>(i).denom, std::get<1>(i).num, + // std::get<1>(i).denom); + } it->second.emplace_back(s, event_type::ending); } void push_intersection(const intersection & i) { auto && [it, inserted] = _events_map.try_emplace(i); - if(inserted) _event_heap.push(i); - // fmt::print("found ({}/{}, {}/{})\n", std::get<0>(i).num, - // std::get<0>(i).denom, std::get<1>(i).num, - // std::get<1>(i).denom); + if(inserted) { + _event_heap.push(i); + // fmt::print("pushed intersection ({}/{}, {}/{})\n", + // std::get<0>(i).num, std::get<0>(i).denom, + // std::get<1>(i).num, std::get<1>(i).denom); + } } void detect_intersection(const segment_entry & e1, const segment_entry & e2) noexcept { @@ -372,7 +384,7 @@ class bentley_ottmann { const auto & x1_max = std::max(std::get<0>(a), std::get<0>(b)); const auto & x2_max = std::max(std::get<0>(c), std::get<0>(d)); - if(std::get<0>(i) < std::get<0>(_current_event_point) || + if(_event_cmp(i, _current_event_point) || std::get<0>(i) > std::min(x1_max, x2_max)) return; @@ -404,9 +416,6 @@ class bentley_ottmann { } //// _intersections.resize(0); - // fmt::print("({}/{}, {}/{})\n", std::get<0>(i).num, - // std::get<0>(i).denom, - // std::get<1>(i).num, std::get<1>(i).denom); // fmt::print("\ttree\n"); { auto tree_it = _segment_tree.lower_bound(i); @@ -415,9 +424,8 @@ class bentley_ottmann { auto next_it = std::next(tree_it); // const auto & [p1, p2] = _segment_map[tree_it->segment_id]; // fmt::print("\t{} : [({}, {}), ({}, {})] ({}/{})\n", - // tree_it->segment_id, p1.first, p1.second, - // p2.first, p2.second, - // tree_it->sweepline_y_intersection(i).num, + // tree_it->segment_id, p1.first, p1.second, p2.first, + // p2.second, tree_it->sweepline_y_intersection(i).num, // tree_it->sweepline_y_intersection(i).denom); _intersections.emplace_back(tree_it->segment_id); tmp_tree.insert(tmp_tree.begin(), @@ -429,25 +437,22 @@ class bentley_ottmann { // const auto & [p1, p2] = _segment_map[s]; // fmt::print("\t{} : [({}, {}), ({}, {})] ({})\n", s, p1.first, // p1.second, p2.first, p2.second, - // et == event_type::starting ? "starting" : - // "ending"); + // et == event_type::starting ? "starting" : "ending"); _intersections.emplace_back(s); } } // fmt::print("before i segment_tree ({}) : {}\n", well_formed_tree(), // fmt::join(std::views::transform( // _segment_tree, - // [](const auto & e) { return e.segment_id; - // }), + // [](const auto & e) { return e.segment_id; }), // ",")); _current_event_point = i; // fmt::print("after i segment_tree ({}) : {}\n", well_formed_tree(), // fmt::join(std::views::transform( // _segment_tree, - // [](const auto & e) { return e.segment_id; - // }), + // [](const auto & e) { return e.segment_id; }), // ",")); - //// + for(const auto & [s, et] : evts) { if(et == event_type::ending) continue; tmp_tree.emplace( @@ -521,13 +526,16 @@ class bentley_ottmann { const intersection & i = _event_heap.top(); _current_event_it = _events_map.find(i); + // fmt::print("({}/{}, {}/{})\n", std::get<0>(i).num, + // std::get<0>(i).denom, std::get<1>(i).num, + // std::get<1>(i).denom); + handle_event(*_current_event_it); // fmt::print("segment_tree ({}) : {}\n", well_formed_tree(), // fmt::join(std::views::transform(_segment_tree, // [](const auto & e) { - // return - // e.segment_id; + // return e.segment_id; // }), // ",")); diff --git a/test/bentley_ottmann_test.cpp b/test/bentley_ottmann_test.cpp index 24d1548..3daa2d0 100755 --- a/test/bentley_ottmann_test.cpp +++ b/test/bentley_ottmann_test.cpp @@ -56,10 +56,10 @@ auto naive_intersections(const std::vector segments) { // std::pair, std::pair>; // // std::vector segments = { -// // {{0, 0}, {2, 0}}, {{1, 0}, {2, 1}}, {{1, 0}, {2, -1}}, {{0, -1}, {2, 2}}}; -// std::vector segments = {{{0, 0}, {2, 1}}, {{1, 1}, {2, -1}}, -// {{1, 0}, {2, 1}}, {{1, 3}, {3, -1}}, -// {{-1, 0}, {4, 0}}, {{0, -2}, {3, 0}}}; +// // {{0, 0}, {2, 0}}, {{1, 0}, {2, 1}}, {{1, 0}, {2, -1}}, {{0, -1}, +// // {2, 2}}}; +// std::vector segments = {{{0, 0}, {1, 0}}, {{0, -1}, {2, 1}}, +// {{0, 1}, {3, 0}}, {{2, -1}, {2, 4}}}; // auto segments_ids = std::views::iota(0ul, segments.size()); // bentley_ottmann alg(segments_ids, segments); @@ -115,30 +115,36 @@ auto naive_intersections(const std::vector segments) { // } // } -GTEST_TEST(bentley_ottmann, fuzzy_test_no_vertical_no_colinear) { +GTEST_TEST(bentley_ottmann, fuzzy_test_no_colinear) { using segment = std::pair, std::pair>; using intersection = decltype(cartesian::segments_intersection( std::declval(), std::declval()))::value_type; - std::size_t num_tests = 1000; + std::size_t num_tests = 100000; for(std::size_t test_i = 0; test_i < num_tests; ++test_i) { + const std::size_t & num_segments = 10; std::vector segments; - const std::size_t & num_segments = 20; + segments.reserve(num_segments); std::random_device dev; std::mt19937 rng(dev()); - std::uniform_int_distribution dist(-31, 31); + std::uniform_int_distribution dist(-63, 63); while(segments.size() < num_segments) { const auto & s = segments.emplace_back(std::make_pair(dist(rng), dist(rng)), std::make_pair(dist(rng), dist(rng))); - if(s.first.first == s.second.first) { + if(s.first.first == s.second.first && + s.first.second == s.second.second) { segments.pop_back(); continue; } + // if(s.first.first == s.second.first) { + // segments.pop_back(); + // continue; + // } if(std::any_of(segments.begin(), std::prev(segments.end()), [s](auto && s2) { return cartesian::line_slope( @@ -151,36 +157,33 @@ GTEST_TEST(bentley_ottmann, fuzzy_test_no_vertical_no_colinear) { } } - fmt::print("test {}\n", test_i); - for(auto && s : segments) { - auto && [a, b] = s; - auto && [ax, ay] = a; - auto && [bx, by] = b; - fmt::print("{{{{{},{}}},{{{},{}}}}},\n", ax, ay, bx, by); - } + // fmt::print("test {}\n", test_i); + // for(auto && s : segments) { + // auto && [a, b] = s; + // auto && [ax, ay] = a; + // auto && [bx, by] = b; + // fmt::print("{{{{{},{}}},{{{},{}}}}},\n", ax, ay, bx, by); + // } std::vector>> intersections_vec; + intersections_vec.reserve( + static_cast(std::pow(num_segments, 1.5))); for(const auto & [i, intersecting_segments] : bentley_ottmann(std::views::iota(0ul, num_segments), segments)) { intersections_vec.emplace_back(std::make_pair( i, std::vector(intersecting_segments.begin(), intersecting_segments.end()))); + + // fmt::print("({}/{}, {}/{}) : {}\n", std::get<0>(i).num, + // std::get<0>(i).denom, std::get<1>(i).num, + // std::get<1>(i).denom, + // fmt::join(intersecting_segments, " , ")); } auto naive_intersections_vec = naive_intersections(segments); - // if(!EQ_RANGES(std::views::keys(intersections_vec), - // std::views::keys(naive_intersections_vec))) { - // for(auto && s : segments) { - // auto && [a, b] = s; - // auto && [ax, ay] = a; - // auto && [bx, by] = b; - // fmt::print("[({},{}),({},{})]\n", ax, ay, bx, by); - // } - // } - - ASSERT_TRUE(EQ_RANGES(std::views::keys(intersections_vec), - std::views::keys(naive_intersections_vec))); + ASSERT_TRUE(EQ_MULTISETS(std::views::keys(intersections_vec), + std::views::keys(naive_intersections_vec))); const std::size_t num_intersections = intersections_vec.size(); for(std::size_t i = 0; i < num_intersections; ++i) {