36 auto add = [&](
const Ring& r) {
37 for (std::size_t i = 0; i < r.size(); ++i) {
38 edges_.push_back({
to_pt(r[i]),
to_pt(r[(i + 1) % r.size()]), island});
39 verts_.push_back(
to_pt(r[i]));
43 for (
const auto& h : poly.holes) add(h);
46 for (
const auto& e : edges_) {
50 if (box_.empty())
return;
51 nx_ =
static_cast<int>((box_.x1 - box_.x0) / kCell) + 1;
52 ny_ =
static_cast<int>((box_.y1 - box_.y0) / kCell) + 1;
53 nrows_ =
static_cast<int>((box_.y1 - box_.y0) / kRow) + 1;
54 cells_.assign(
static_cast<std::size_t
>(nx_) *
static_cast<std::size_t
>(ny_), {});
55 vcells_.assign(cells_.size(), {});
56 rows_.assign(
static_cast<std::size_t
>(nrows_), {});
57 for (std::size_t i = 0; i < edges_.size(); ++i) {
58 const Edge& e = edges_[i];
59 const int x0 = cell_x(std::min(e.a.
x, e.b.
x)), x1 = cell_x(std::max(e.a.
x, e.b.
x));
60 const int y0 = cell_y(std::min(e.a.
y, e.b.
y)), y1 = cell_y(std::max(e.a.
y, e.b.
y));
61 for (
int cy = y0; cy <= y1; ++cy)
62 for (
int cx = x0; cx <= x1; ++cx) cells_[idx(cx, cy)].push_back(
static_cast<int>(i));
63 if (e.a.
y == e.b.
y)
continue;
64 for (
int r = row_of(std::min(e.a.
y, e.b.
y)); r <= row_of(std::max(e.a.
y, e.b.
y)); ++r) rows_[
static_cast<std::size_t
>(r)].push_back(
static_cast<int>(i));
66 for (std::size_t i = 0; i < verts_.size(); ++i) vcells_[idx(cell_x(verts_[i].x), cell_y(verts_[i].y))].push_back(
static_cast<int>(i));
67 stamp_.assign(edges_.size(), 0);
70 bool empty()
const {
return edges_.empty(); }
79 if (box_.empty())
return;
80 const double cx = (a.
x + b.
x) / 2, cy = (a.
y + b.
y) / 2, r = bound / 2;
81 const int x0 = cell_x(cx - r), x1 = cell_x(cx + r), y0 = cell_y(cy - r), y1 = cell_y(cy + r);
82 for (
int yy = y0; yy <= y1; ++yy)
83 for (
int xx = x0; xx <= x1; ++xx)
84 for (
int vi : vcells_[idx(xx, yy)]) {
85 const Pt& v = verts_[
static_cast<std::size_t
>(vi)];
86 if (
dist(a, v) +
dist(v, b) <= bound) out.push_back(v);
92 if (box_.empty())
return false;
94 const int x0 = cell_x(std::min(a.
x, b.
x)), x1 = cell_x(std::max(a.
x, b.
x)), y0 = cell_y(std::min(a.
y, b.
y)), y1 = cell_y(std::max(a.
y, b.
y));
95 for (
int cy = y0; cy <= y1; ++cy)
96 for (
int cx = x0; cx <= x1; ++cx)
97 for (
int ei : cells_[idx(cx, cy)]) {
98 if (stamp_[
static_cast<std::size_t
>(ei)] == clock_)
continue;
99 stamp_[
static_cast<std::size_t
>(ei)] = clock_;
100 if (proper_cross(a, b, edges_[
static_cast<std::size_t
>(ei)].a, edges_[
static_cast<std::size_t
>(ei)].b))
return true;
108 if (
crosses(a, b))
return false;
109 std::vector<double> ts{0.0, 1.0};
110 const double dx = b.
x - a.
x, dy = b.
y - a.
y, len2 = dx * dx + dy * dy;
112 auto along = [&](
Pt p,
double& t) {
113 t = ((p.
x - a.
x) * dx + (p.
y - a.
y) * dy) / len2;
114 if (t <= 0 || t >= 1)
return false;
115 return dist(p, {a.
x + t * dx, a.
y + t * dy}) < 3.0;
119 const int x0 = cell_x(std::min(a.
x, b.
x)), x1 = cell_x(std::max(a.
x, b.
x)), y0 = cell_y(std::min(a.
y, b.
y)), y1 = cell_y(std::max(a.
y, b.
y));
120 for (
int cy = y0; cy <= y1; ++cy)
121 for (
int cx = x0; cx <= x1; ++cx)
122 for (
int ei : cells_[idx(cx, cy)]) {
123 if (stamp_[
static_cast<std::size_t
>(ei)] == clock_)
continue;
124 stamp_[
static_cast<std::size_t
>(ei)] = clock_;
125 const Edge& e = edges_[
static_cast<std::size_t
>(ei)];
127 if (along(e.a, t)) ts.push_back(t);
128 if (along(e.b, t)) ts.push_back(t);
129 const double ex = e.b.x - e.a.x, ey = e.b.y - e.a.y, den = dx * ey - dy * ex;
130 if (std::fabs(den) > 1e-9 * std::sqrt(len2) * std::hypot(ex, ey)) {
131 const double tt = ((e.a.x - a.
x) * ey - (e.a.y - a.
y) * ex) / den, uu = ((e.a.x - a.
x) * dy - (e.a.y - a.
y) * dx) / den;
132 if (tt > 0 && tt < 1 && uu >= 0 && uu <= 1) ts.push_back(tt);
136 std::sort(ts.begin(), ts.end());
137 for (std::size_t i = 1; i < ts.size(); ++i) {
138 if ((ts[i] - ts[i - 1]) * std::sqrt(len2) < 2.0)
continue;
139 const double m = (ts[i] + ts[i - 1]) / 2;
140 if (!
contains({a.
x + m * dx, a.
y + m * dy}))
return false;
149 if (box_.empty())
return false;
152 const int c0x = cell_x(p.
x), c0y = cell_y(p.
y), maxr =
static_cast<int>(reach /
static_cast<double>(kCell)) + 1;
153 for (
int r = 0; r <= maxr; ++r) {
154 for (
int cy = std::max(0, c0y - r); cy <= std::min(ny_ - 1, c0y + r); ++cy)
155 for (
int cx = std::max(0, c0x - r); cx <= std::min(nx_ - 1, c0x + r); ++cx) {
156 if (std::max(std::abs(cx - c0x), std::abs(cy - c0y)) != r)
continue;
157 for (
int ei : cells_[idx(cx, cy)]) {
159 const double d = distance_to_edge(edges_[
static_cast<std::size_t
>(ei)], p, q);
160 if (d < best || (best_edge >= 0 && d == best && ei < best_edge)) best = d, best_edge = ei, out = q;
163 if (best_edge >= 0 && best <=
static_cast<double>(r) *
static_cast<double>(kCell))
break;
165 return best_edge >= 0;
171 for (
const auto& e : edges_)
172 if (on_edge(e, p))
return e.island;
174 double nearest = std::numeric_limits<double>::infinity();
176 for (
const auto& e : edges_) {
177 if ((e.a.y > p.
y) == (e.b.y > p.
y))
continue;
178 const double x = (e.b.x - e.a.x) * (p.
y - e.a.y) / (e.b.y - e.a.y) + e.a.x;
179 if (x <= p.
x)
continue;
181 if (x < nearest) nearest = x, island = e.island;
183 return in ? island : -1;
186 for (
const auto& e : edges_)
187 if (proper_cross(a, b, e.a, e.b))
return true;
193 for (
const auto& e : edges_) {
195 if (
const double d = distance_to_edge(e, p, q); d < best) best = d, out = q, found =
true;
201 for (
const auto& v : verts_)
202 if (
dist(a, v) +
dist(v, b) <= bound) ++n;
207 static constexpr Coord kCell = 1'000'000;
208 static constexpr Coord kRow = 250'000;
214 static double distance_to_edge(
const Edge& e, Pt p, Pt& q) {
215 const double dx = e.b.x - e.a.x, dy = e.b.y - e.a.y, l2 = dx * dx + dy * dy;
216 const double t = l2 > 0 ? std::clamp(((p.x - e.a.x) * dx + (p.y - e.a.y) * dy) / l2, 0.0, 1.0) : 0.0;
217 q = {e.a.x + t * dx, e.a.y + t * dy};
220 static bool on_edge(
const Edge& e, Pt p) {
221 const double dx = e.b.x - e.a.x, dy = e.b.y - e.a.y, l2 = dx * dx + dy * dy;
222 const double t = l2 > 0 ? std::clamp(((p.x - e.a.x) * dx + (p.y - e.a.y) * dy) / l2, 0.0, 1.0) : 0.0;
223 return dist(p, {e.a.x + t * dx, e.a.y + t * dy}) < 3.0;
225 static double orient(Pt a, Pt b, Pt c) {
return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x); }
227 static bool proper_cross(Pt a, Pt b, Pt c, Pt d) {
228 const double eps = 1e-3 * std::max(1.0, std::max(
dist(a, b),
dist(c, d)));
229 const double o1 = orient(a, b, c), o2 = orient(a, b, d), o3 = orient(c, d, a), o4 = orient(c, d, b);
230 return ((o1 > eps && o2 < -eps) || (o1 < -eps && o2 > eps)) && ((o3 > eps && o4 < -eps) || (o3 < -eps && o4 > eps));
232 std::size_t idx(
int cx,
int cy)
const {
return static_cast<std::size_t
>(cy) *
static_cast<std::size_t
>(nx_) +
static_cast<std::size_t
>(cx); }
233 int cell_x(
double x)
const {
return std::clamp(
static_cast<int>((x -
static_cast<double>(box_.x0)) /
static_cast<double>(kCell)), 0, nx_ - 1); }
234 int cell_y(
double y)
const {
return std::clamp(
static_cast<int>((y -
static_cast<double>(box_.y0)) /
static_cast<double>(kCell)), 0, ny_ - 1); }
235 int row_of(
double y)
const {
return std::clamp(
static_cast<int>((y -
static_cast<double>(box_.y0)) /
static_cast<double>(kRow)), 0, nrows_ - 1); }
240 int locate(Pt p)
const {
241 if (box_.empty() || p.x <
static_cast<double>(box_.x0) - 3 || p.x >
static_cast<double>(box_.x1) + 3 || p.y <
static_cast<double>(box_.y0) - 3 ||
242 p.y >
static_cast<double>(box_.y1) + 3)
244 const int cx = cell_x(p.x), cy = cell_y(p.y);
245 for (
int yy = std::max(0, cy - 1); yy <= std::min(ny_ - 1, cy + 1); ++yy)
246 for (
int xx = std::max(0, cx - 1); xx <= std::min(nx_ - 1, cx + 1); ++xx)
247 for (
int ei : cells_[idx(xx, yy)])
248 if (on_edge(edges_[
static_cast<std::size_t
>(ei)], p))
return edges_[
static_cast<std::size_t
>(ei)].island;
250 double nearest = std::numeric_limits<double>::infinity();
252 for (
int ei : rows_[
static_cast<std::size_t
>(row_of(p.y))]) {
253 const Edge& e = edges_[
static_cast<std::size_t
>(ei)];
254 if ((e.a.y > p.y) == (e.b.y > p.y))
continue;
255 const double x = (e.b.x - e.a.x) * (p.y - e.a.y) / (e.b.y - e.a.y) + e.a.x;
256 if (x <= p.x)
continue;
258 if (x < nearest) nearest = x, island = e.island;
260 return in ? island : -1;
263 std::vector<Edge> edges_;
264 std::vector<Pt> verts_;
266 int nx_ = 0, ny_ = 0, nrows_ = 0;
267 std::vector<std::vector<int>> cells_, vcells_, rows_;
268 mutable std::vector<std::uint32_t> stamp_;
269 mutable std::uint32_t clock_ = 0;