Площадь многоугольника через векторное произведение может вычислена следующим образом:
double Square(vector<Point>& a){
double s=0;
for(int i=2; i<a.size(); ++i)
s+=(a[i-1]-a[0])^(a[i]-a[0]);
return fabs(s/2);
}
int sign(double a){ return a==0?0:(a<0?-1:1); }
bool isCrossed(Point p1, Point p2, Point p3, Point p4) {
return (max(min(p1.x,p2.x),min(p3.x,p4.x)) <= min(max(p1.x,p2.x),max(p3.x,p4.x)) &&
max(min(p1.y,p2.y),min(p3.y,p4.y)) <= min(max(p1.y,p2.y),max(p3.y,p4.y)) &&
sign((p3-p1)^(p2-p1))*sign((p4-p1)^(p2-p1))<=0 &&
sign((p1-p3)^(p4-p3))*sign((p2-p3)^(p4-p3))<=0);
}
Вариант 1
Проверить, что отрезки пересекаются.
Преобразовать отрезки в коэффициенты прямой Ax+By+C=0
A = s.first.y - s.second.y;
B = s.second.x - s.first.x;
C = -A*s.first.x - B*s.first.y;
Вариант 2 (более простой)
Представить отрезок в форме
{x=x1+α⋅(x2-x1)y=y1+α⋅(y2-y1), где α∈[0;1]
Тогда нужно решить систему уравнений
{x1+α1⋅(x2-x1)=x3+α2⋅(x4-x3)y1+α1⋅(y2-y1)=y3+α2⋅(y4-y3)
и проверить, что α1∈[0;1]∧α2∈[0;1]
Можно использовать для нахождения точки пересечения прямых, прямой и отрезка, лучей и т.д.
{α1⋅(x2-x1)-α2⋅(x4-x3)=x3-x1α1⋅(y2-y1)-α2⋅(y4-y3)=y3-y1
[(x2-x1)-(x4-x3)(y2-y1)-(y4-y3)]
const double EPS=1e-9;
double alpha(Point a, Point b) {
if(fabs(a.x)<=fabs(a.y)) return b.y/a.y;
return b.x/a.x;
}
double minalpha(Point a, Point b, Point c) {
double a1=alpha(a,b),a2=alpha(a,c);
if(a1>a2) swap(a1,a2);
if(a1<=0) return min(a2,0.0);
return a1;
}
optional<pair<double,double>> crossAt(Point p1, Point p2, Point p3, Point p4) {
Point a=p2-p1,b=p3-p4,c=p3-p1;
double d=a^b; // определитель
if(fabs(d)<=EPS) {
if(fabs(c^a)>EPS) return {};
return {{minalpha(a,c,p4-p1),minalpha(b,p3-p2,c)}};
}
return {{(c^b)/d,(a^c)/d}};
}
int main()
{
auto r=crossAt(p1,p2,p3,p4);
if(r) {
Point p=(p2-p1)*r->first+p1;
print("Yes\n{} {}\n",p.x,p.y);
}
else
print("No\n");
}
Методом грубой силы O(N2), а с помощью сканирующей прямой O((N+K)logN), где K – количество точек пересечения (в худшем случае N22).
Алгоритм Бентли-Оттмана находит номера отрезков, которые пересекаются.
При использовании сканирующей прямой сначала нужно упорядочить концы отрезков по координате x.
Далее при движении слева-направо нужно отслеживать 3 типа события:
Номера отрезков, пересекающих сканирующую прямую, должны быть упорядочены по возрастанию координаты y их пересечения с прямой: O(NlogN). В процессе работы отрезки могут добавляться в произвольные места этого упорядоченного множества, удаляться из произвольных места или меняться местами друг с другом.
Пересекаться могут соседние отрезки. Поэтому при добавлении нового отрезка нужно добавить в события
координаты x пересечения с отрезком выше и ниже, если такие есть: O(logN).
При удалении отрезка соседними становятся отрезки выше и ниже, нужно проверить и добавить координату x пересечения, если такое есть: O(logN).
При обработке события пересечения нужно поменять местами отрезки и проверить на появление новых точек пересечения с новыми соседями: O(logN).
В алгоритме нужно учесть вертикальные отрезки, пересечение нескольких отрезков в одной точке, наложение отрезков (можно заменить 1 отрезком).