Отрезок можно задать двумя точками своих концов. В любом порядке — ведь он, в отличие от вектора, неориентирован.
struct segment {
r p, q;
};
В вычислительной геометрии часто требуется уметь определять взаимное положение геометрических объектов. Например, проверять, пересекаются ли отрезки. В этом нам поможет скалярное и векторное произведение, а также небольшой разбор случаев:

В терминах произведений, «концы отрезка лежат по разные стороны относительно другого отрезка», например, записывается как:
Записав ещё одно дополнительное условие, относительно в качестве разделительного отрезка, мы получим легко вычислимый предикат, который верен тогда и только тогда, когда отрезки пересекаются.
#Лучи и прямые
Луч — это отрезок, бесконечный в одном из направлений. Его можно хранить как точку и либо явный вектор направления, либо любую другую его точку.
С прямыми дела обстоят немного сложнее. Здесь есть целых 4 имеющих право на жизнь способа их хранить:
- Нормальным уравнением: .
- Двумя точками.
- Точкой и направляющим вектором (любым): .
- Точкой и нормальным вектором (любым).
Также их иногда удобно хранить уравнением , как в школе, однако для вертикальных прямых придётся делать отдельный костыль.
Часто во входе прямые заданы в одном виде, но удобнее работать с другим. Реализуются основные переходы так:
- : достаточно найти любое решение системы из 2 уравнений и 3 неизвестных.
- : если прямая задаётся уравнением, то вектор — направляющий к прямой (важно помнить, что у прямой есть два «направления»).
- : если прямая задаётся уравнением, то вектор — нормальный к прямой (важно помнить, что упрямой есть 2 «направления нормали»).
- : нужно решить систему из 1 уравнения и 1 неизвестного, раз уж из предыдущих пунктов мы уже знаем подходящие и .
- : достаточно выбрать любые две точки на прямой — например:
// даны A, B, C (A^2 + B^2 != 0)
r a, b;
if (eq(A, 0)) // если это горизонтальная прямая
a = {0, -C/B}, b = {1, -C/B);
else
a = {-C/A, 0}, b = {-(C+B)/A, 1);
#Проверки
Для способов 2-4 все проверки почти такие же, как для отрезков. На самом деле, в геометрических задачах часто можно ввести «bounding box» — квадрат с очень далекими границами, все точки за пределами которого считаются «бесконечностью». Тогда бесконечные прямые и лучи можно заменить на отрезки, упирающиеся в эти бесконечные границы, и делать все проверки как с обычными отрезками.
В случае прямых, заданных формулой, всё совсем по-другому.
#Расстояние от точки до прямой
Заметим, что если прямая задается уравнением вида , то полуплоскость можно задать таким же неравенством. Это можно сразу использовать для проверки, по какую сторону от прямой находится точка.
Вектор нормали этой прямой будет иметь координаты . Он перпендикулярен прямой, а в случае с полуплоскостью будет указывать в сторону самой полуплоскости.
Чтобы найти расстояние от точки до прямой , можно воспользоваться следующей формулой:
Об этой формуле можно думать как о скалярном произведении вектора-точки на нормированный () вектор нормали, геометрически равный проекции точки на него.
Если же прямая задана 2 точками, то можно выразить высоту из формулы для площади треугольника:
И посчитать эту высоту так:Обратите внимание, что в числителе стоит векторное произведение — мы воспользовались тем, что по модулю оно равно удвоенной площади треугольника ,
#Точка пересечения прямых
Найти точку пересечения двух прямых — это то же самое, что и найти точку, которая удовлетворяет обоим условиям их уравнений:
Если выразить из обоих уравнений и приравнять, то получаетсяАналогично, (обратите внимание на знаки).
Заметим, что знаменатель может оказаться нулем. Это означает, что векторное произведение векторов нормали нулевое, а значит прямые параллельны — тогда точек пересечения либо нет, либо, в случае совпадающих прямых, бесконечность. Этот случай нужно обрабатывать отдельно.
Приведем несколько примеров конструктивного подхода.
#Проекция точки на прямую
Чтобы спроецировать точку на прямую , достаточно прибавить к ней нормальный вектор прямой, приведённый к длине и направленный от точки к прямой. Поскольку нормальный вектор может быть направлен в двух разных (но противоположных друг другу!) направлениях, то достаточно попробовать оба варианта, и принять тот, в котором расстояние от получившейся точки до прямой будет меньше.
#Отражение от прямой
Пусть нам надо отразить точку симметрично относительно заданной прямой .
Чисто в педагогических целях, начнём решать эту задачу как математики, чтобы никогда потом так не делать.
Геометрический смысл: длина на единичный вектор направления.
Мы не хотим раскрывать эти формулы покоординатно и предъявлять готовый ответ. Мы знаем, что он получится громоздким. Нам не жалко посчитать всё по частям — здесь нет смысла заниматься оптимизациями. Также мы хотим делать всё по частям, потому что так становится более наглядной логика алгоритма, и, как следствие, его проще дебажить.
// прямая r = at + b, точка c
r pr(r a, r b, r c) {
c -= b; // пусть c и a выходят из одной точки
return b + (a * b / len(a) / len(a)) * a;
}
r reflect(r a, r b, r c) {
return c + 2*(pr(a, b, c)-c);
}