EduBrick

Касательные к окружности

Точки касания из внешней точки находятся без тригонометрии: проекция и сдвиг вдоль перпендикуляра.

2 мин

Из точки вне окружности к ней проходят две касательные, из точки на окружности - одна, изнутри - ни одной. Найти точки касания можно одной формулой, без углов.

Построение

Пусть CC - центр, rr - радиус, PP - точка, d=PC\vec{d} = P - C, d2=d2d^2 = |\vec{d}|^2.

Точки касания лежат на окружности и видны из CC под прямым углом к касательной. Их общая хорда перпендикулярна d\vec{d} и удалена от центра на r2/dr^2/d. Значит:

B=C+r2d2d,h=rd2r2d2,B = C + \frac{r^2}{d^2}\,\vec{d}, \qquad h = \frac{r\sqrt{d^2 - r^2}}{d^2},

а сами точки - это B±hdB \pm h \cdot \vec{d}^{\perp}, где d=(dy,dx)\vec{d}^{\perp} = (-d_y, d_x).

Long d2 = dot(d, d);
if (d2 < (Long)r * r) { нет касательных }
if (d2 == (Long)r * r) { одна, и это сама точка P }
Real base = (Real)r * r / d2;
Real h = (Real)r * std::sqrt((Real)(d2 - (Long)r * r)) / d2;
P1 = {C.x + base * d.x - h * d.y, C.y + base * d.y + h * d.x};
P2 = {C.x + base * d.x + h * d.y, C.y + base * d.y - h * d.x};

Обратите внимание: сравнение «внутри или снаружи» делается в целых числах - d2d^2 против r2r^2. Ни корня, ни эпсилона здесь не нужно, и граничный случай «точка ровно на окружности» определяется точно.

Почему не через углы

Школьный способ - найти угол arccos(r/d)\arccos(r/d) и повернуть вектор. Он работает, но требует двух тригонометрических вызовов и матрицы поворота, а на границе (точка почти на окружности) аргумент арккосинуса из-за погрешности может выскочить за единицу.

Формула выше состоит из умножений и одного корня, причём подкоренное выражение целое и неотрицательное по построению.

Общие касательные к двум окружностям

Задача сводится к предыдущей приёмом «сдуть окружности». Чтобы найти внешние касательные, уменьшим оба радиуса на min(r1,r2)\min(r_1, r_2): одна из окружностей превратится в точку, и останется провести касательные из точки к другой окружности, а потом сдвинуть прямые обратно на min(r1,r2)\min(r_1, r_2).

Для внутренних касательных то же самое, но радиусы меняются в разные стороны: r1tr_1 - t и r2+tr_2 + t.

Смежное