#include<bits/stdc++.h>
struct Point {
double x, y;
};
struct Segment {
Point p, q;
int group; // A for figure 1 and B for 2
Segment(Point a, Point b, int g) : group(g) {
if (a.x < b.x || a.x == b.x && a.y <= b.y) {
p = a;
q = b;
}
else {
p = b;
q = a;
}
}
};
// initial position for x
double currentX = 0.0;
// determine y for given x
double getY(const Segment &seg, double x) {
if (seg.p.x == seg.q.x)
return seg.p.y;
double slope = (seg.q.y - seg.p.y) / (seg.q.x - seg.p.x);
return seg.p.y + slope*(x-seg.p.x);
}
// comparator: c
struct SegmentComparator {
bool operator() (const Segment *s1, const Segment *s2) const {
double y1 = getY(*s1, currentX);
double y2 = getY(*s2, currentX);
if (y1 == y2)
return s1 < s2;
return y1 < y2;
}
};
// determine cross product
double cross(const Point &A, const Point &B, const Point &C) {
return (B.x - A.x) * (C.y - A.y) - (B.y - A.y) * (C.x - A.x);
}
// hier I still use formular cross product to see if two sedments is intersected, because I think this is more comprehensive
bool isIntersected(const Segment &s1, const Segment &s2) {
if (s1.group == s2.group)
return false;
const Point &A = s1.p, &B = s1.q, &C = s2.p, &D = s2.q;
double d1 = cross(A, B, C);
double d2 = cross(A, B, C);
double d3 = cross(C, D, A);
double d4 = cross(C, D, B);
if (d1*d2 < 0 && d3*d4 < 0) {
return true;
}
return false;
}
struct Event {
double x;
int type; // 1: left point, -1: right point
Segment *seg;
};
bool eventComparator(const Event &e1, const Event &e2) {
if (e1.x == e2.x)
return e1.type > e2.type;
return e1.x < e2.x;
}
bool sweeplineIntersection(std::vector<Segment> &segments) {
std::vector<Event> events;
for (auto &seg : segments) {
events.push_back(Event{seg.p.x, 1, &seg});
events.push_back(Event{seg.q.x, -1, &seg});
}
std::sort(events.begin(), events.end(), eventComparator);
std::set<Segment *, SegmentComparator> active;
for (auto &event : events) {
currentX = event.x;
if (event.type == 1) {
// insert segment
auto iter = active.insert(event.seg).first;
//check if current one intercept with last one
if (iter != active.begin()) {
auto prev = std::prev(iter);
if (isIntersected(**prev, *event.seg))
return true;
}
//check if current one intercept with next one
auto next = std::next(iter);
if (next != active.end()) {
if (isIntersected(**next, *event.seg))
return true;
}
}
else {
auto iter = active.find(event.seg);
if (iter != active.end()) {
auto prev = (iter == active.begin()) ? active.end() : std::prev(iter);
auto next = std::next(iter);
active.erase(iter);
if (prev != active.end() && next != active.end()) {
if (isIntersected(**prev, **next))
return true;
}
}
}
}
return false;
}
int main() {
std::vector<Segment> segments;
segments.push_back(Segment({0, 0}, {4, 4}, 0));
segments.push_back(Segment({0, 4}, {4, 0}, 1));
bool intersect = sweeplineIntersection(segments);
if (intersect)
std::cout << "two figures is intercepted." << std::endl;
else {
std::cout << "two figures has no cross point. " << std::endl;
}
return 0;
}