Как найти точку пересечения двух прямых, заданных парами точек?
Отрезки уже умею пересекать по факту да/нет. Теперь нужны сами координаты точки пересечения двух прямых (каждая задана двумя точками). Как вывести формулу через косые произведения и что делать с параллельными прямыми?
2 ответа
Удобнее всего через косые произведения. Пусть прямые заданы точками A,B и C,D. Параметризуем первую прямую как A + t*(B-A). Тогда:
// возвращает true и точку пересечения; false если прямые параллельны
bool lineInter(const P& a, const P& b, const P& c, const P& d, pair<double,double>& res) {
long long d1 = (b - a).cross(d - c); // знаменатель
if (d1 == 0) return false; // параллельны (или совпадают)
long long t_num = (c - a).cross(d - c);
double t = (double)t_num / d1;
res = { a.x + t * (b.x - a.x), a.y + t * (b.y - a.y) };
return true;
}
Идея: знаменатель (B-A) × (D-C) равен нулю ровно когда направляющие векторы прямых коллинеарны, то есть прямые параллельны. Если он не ноль, параметр t находится одним делением, и точка пересечения — линейная комбинация.
Числитель и знаменатель считаются в long long точно; деление переводит в double только в самом конце. Сложность O(1). Если нужна точная рациональная точка — храни числитель и знаменатель отдельно и не делай деление вовсе.
Два уточнения. Первое: d1 == 0 означает параллельность, но прямые могут ещё и совпадать — тогда пересечение бесконечно. Чтобы их различить, при нулевом знаменателе проверь orient(a, b, c) == 0: если да — прямые совпадают, иначе просто параллельны и не пересекаются.
Второе: эта формула даёт пересечение прямых, а не отрезков. Если нужно пересечение именно отрезков, после нахождения t проверь 0 <= t <= 1 и аналогичный параметр для второй прямой. Для отрезков чаще удобнее сначала вызвать segInter (да/нет), и только при true — считать координаты.