Skip to content

Commit

Permalink
bentley-ottmann ok
Browse files Browse the repository at this point in the history
  • Loading branch information
fhamonic committed Oct 3, 2024
1 parent 873bb0d commit dc4bf17
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 55 deletions.
62 changes: 35 additions & 27 deletions include/melon/experimental/bentley_ottmann.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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 {
Expand All @@ -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;

Expand Down Expand Up @@ -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);
Expand All @@ -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(),
Expand All @@ -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(
Expand Down Expand Up @@ -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;
// }),
// ","));

Expand Down
59 changes: 31 additions & 28 deletions test/bentley_ottmann_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,10 @@ auto naive_intersections(const std::vector<S> segments) {
// std::pair<std::pair<int64_t, int64_t>, std::pair<int64_t, int64_t>>;

// // std::vector<segment> segments = {
// // {{0, 0}, {2, 0}}, {{1, 0}, {2, 1}}, {{1, 0}, {2, -1}}, {{0, -1}, {2, 2}}};
// std::vector<segment> 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<segment> 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);
Expand Down Expand Up @@ -115,30 +115,36 @@ auto naive_intersections(const std::vector<S> 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<int64_t, int64_t>, std::pair<int64_t, int64_t>>;
using intersection = decltype(cartesian::segments_intersection(
std::declval<segment>(), std::declval<segment>()))::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<segment> segments;
const std::size_t & num_segments = 20;
segments.reserve(num_segments);

std::random_device dev;
std::mt19937 rng(dev());
std::uniform_int_distribution<int64_t> dist(-31, 31);
std::uniform_int_distribution<int64_t> 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(
Expand All @@ -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<std::pair<intersection, std::vector<std::size_t>>>
intersections_vec;
intersections_vec.reserve(
static_cast<std::size_t>(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<std::size_t>(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) {
Expand Down

0 comments on commit dc4bf17

Please sign in to comment.