-
Notifications
You must be signed in to change notification settings - Fork 0
/
sweepline_state.cpp
101 lines (80 loc) · 3.64 KB
/
sweepline_state.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#include "sweepline_state.hpp"
#include "geometry.hpp"
#include "util.hpp"
#include <boost/assert.hpp>
#include <algorithm>
#include <functional>
#include <iostream>
std::ostream& operator<<(std::ostream& rhs, const sweepline_state::edge& lhs)
{
rhs << lhs.first << "->" << lhs.second;
return rhs;
}
bool sweepline_state::edge_comparator(const sweepline_state::edge& lhs,
const sweepline_state::edge& rhs) const
{
const auto& lhs_start = coordinates[lhs.first];
const auto& lhs_end = coordinates[lhs.second];
const auto& rhs_start = coordinates[rhs.first];
const auto& rhs_end = coordinates[rhs.second];
auto lhs_params = geometry::segment_intersection(sweepline_start, sweepline_end, lhs_start, lhs_end);
auto rhs_params = geometry::segment_intersection(sweepline_start, sweepline_end, rhs_start, rhs_end);
auto lhs_x = std::max(lhs_start.x, lhs_end.x);
auto rhs_x = std::max(rhs_start.x, rhs_end.x);
// compare the intersection points on the sweepline
bool result = util::epsilon_compare(1e-10, lhs_params.first_param, rhs_params.first_param) ?
(lhs_x < rhs_x) :
(lhs_params.first_param < rhs_params.first_param);
return result;
}
void sweepline_state::move_sweepline(const coordinate& position)
{
sweepline_end = position;
}
void sweepline_state::insert_edge(const sweepline_state::edge& to_insert)
{
BOOST_ASSERT(to_insert.first < to_insert.second);
auto iter = std::lower_bound(intersecting_edges.begin(), intersecting_edges.end(),
to_insert, std::bind(&sweepline_state::edge_comparator, this,
std::placeholders::_1, std::placeholders::_2));
if (iter == intersecting_edges.end())
{
intersecting_edges.push_back(to_insert);
}
else if (edge_comparator(*iter, to_insert))
{
intersecting_edges.push_front(to_insert);
}
else
{
intersecting_edges.insert(iter, to_insert);
}
}
void sweepline_state::remove_edge(const sweepline_state::edge& to_remove)
{
BOOST_ASSERT(to_remove.first < to_remove.second);
auto iter = std::lower_bound(intersecting_edges.begin(), intersecting_edges.end(),
to_remove, std::bind(&sweepline_state::edge_comparator, this,
std::placeholders::_1, std::placeholders::_2));
// search for the real position, might have hit an itersection
while (iter != intersecting_edges.end() && iter->first != to_remove.first && iter->second != to_remove.second)
{
iter++;
}
BOOST_ASSERT(iter != intersecting_edges.end());
BOOST_ASSERT(iter->first == to_remove.first && iter->second == to_remove.second);
intersecting_edges.erase(iter);
}
sweepline_state::edge_iterator sweepline_state::get_first_intersecting(const coordinate& coord) const
{
BOOST_ASSERT_MSG(geometry::segment_intersection(sweepline_start, sweepline_end,
sweepline_start, coord).colinear,
"Sweepline must be moved forward for intersection search.");
auto iter = std::lower_bound(intersecting_edges.begin(), intersecting_edges.end(), coord,
[this](const edge& lhs, const coordinate& rhs)
{
auto params = geometry::segment_intersection(sweepline_start, rhs, coordinates[lhs.first], coordinates[lhs.second]);
return params.first_param < 1;
});
return iter;
}