Загрузка [MathJax]/jax/output/HTML-CSS/fonts/TeX/fontdata.js

Подразделы

Другие разделы

Дата и время

01/04/2025 04:52:12

Авторизация

Имя:
Пароль:
Зарегистрироваться
Восстановить пароль
 

printВычислительная геометрия

printАлгоритмы

Площадь многоугольника

Площадь многоугольника через векторное произведение может вычислена следующим образом:

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

Реализация

  1. Проверить, что отрезки пересекаются.

  2. Преобразовать отрезки в коэффициенты прямой 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;
  1. Найти точку пересечения прямых

Вариант 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");
}

Точки пересечения для N отрезков.

width:150px;float:right|Задача

Методом грубой силы O(N2), а с помощью сканирующей прямой O((N+K)logN), где K – количество точек пересечения (в худшем случае N22).

Алгоритм Бентли-Оттмана находит номера отрезков, которые пересекаются.


width:150px;float:right|Статус При использовании сканирующей прямой сначала нужно упорядочить концы отрезков по координате x. Далее при движении слева-направо нужно отслеживать 3 типа события:

  • начался новый отрезок
  • два отрезка пересеклись
  • отрезок закончился

Номера отрезков, пересекающих сканирующую прямую, должны быть упорядочены по возрастанию координаты y их пересечения с прямой: O(NlogN). В процессе работы отрезки могут добавляться в произвольные места этого упорядоченного множества, удаляться из произвольных места или меняться местами друг с другом.


width:150px;float:right|Статус Пересекаться могут соседние отрезки. Поэтому при добавлении нового отрезка нужно добавить в события координаты x пересечения с отрезком выше и ниже, если такие есть: O(logN).

При удалении отрезка соседними становятся отрезки выше и ниже, нужно проверить и добавить координату x пересечения, если такое есть: O(logN).

При обработке события пересечения нужно поменять местами отрезки и проверить на появление новых точек пересечения с новыми соседями: O(logN).

В алгоритме нужно учесть вертикальные отрезки, пересечение нескольких отрезков в одной точке, наложение отрезков (можно заменить 1 отрезком).

loading