point intersect(line & l, segment s) { double da = fabs(l.dist(s.a)), db = fabs(l.dist(s.b)); if (da + db < eps) { return s.a; } else { double t = da / (da + db); return s.a + (s.b - s.a) * t; } }
result lineIntersectsPolygon(line & l, polygon & P, size_t sz, int k) { int n = (sz + k - 1) / k; double minDist = numeric_limits<double>::max(); int minPoint = -1; unordered_set<int> points; if (n <= 50) { point prev = P->get(0); for (size_t i = k; i < sz; i += k) { point cur = P->get(i); segment s = {prev, cur}; if (lineIntersectsSegment(l, s)) { points.insert(i - k); } else { double dist = fabs(l.dist(cur)); if (minDist > dist) { minDist = dist; minPoint = i; } } prev = cur; } } else { auto ind = lineIntersectsPolygon(l, P, sz, 2 * k); if (ind.points.size() != 0) { for (int i : ind.points) { point p1 = P->get(i - k); point p2 = P->get(i); segment s = {p1, p2}; if (lineIntersectsSegment(l, s)) { points.insert((i - k + sz) % sz); } else { points.insert(i); } } } else { int i = ind.closest; point p1 = P->get(i - 2 * k); point p2 = P->get(i - k); point p3 = P->get(i); point p4 = P->get(i + k); point p5 = P->get(i + 2 * k); point pts[] = {p1, p2, p3, p4, p5}; segment segs[] = {{p1, p2}, {p2, p3}, {p3, p4}, {p4, p5}}; for (int j = 0; j < 4; j++) { if (lineIntersectsSegment(l, segs[j])) { points.insert((i + k * (j - 2) + sz) % sz); } } for (int j = 0; j < 5; j++) { double dist = fabs(l.dist(pts[j])); if (minDist > dist) { minDist = dist; minPoint = (i + k * (j - 2) + sz) % sz; } } } } return {points, minPoint}; }
bool lineIntersectsSegment(line & l, segment & s) { double da = l.dist(s.a), db = l.dist(s.b); return !((da > eps && db > eps) || (da < -eps && db < -eps)); }