Когда подобные вещи выполняются в компьютерных программах, одной из проблем, с которыми вам, возможно, придется столкнуться, является выполнение этих вычислений только с использованием целочисленной арифметики (или в максимально возможной степени), предполагая, что ввод вводится в целых числах. Делать это как можно больше в целых числах - это отдельная проблема, которую я не буду здесь освещать.
Ниже приведено «математическое» решение, которое в буквальном смысле потребует вычислений с плавающей запятой. Я не знаю, приемлемо ли это в вашем случае. Вы можете оптимизировать его по своему вкусу.
(1) Представьте вашу линию L
на
A * x + B * y + C = 0
уравнение. Обратите внимание, что вектор (A, B)
является вектором нормали этой линии.
Например, если линия определяется двумя точками X1(x1, y1)
и X2(x2, y2)
, то
A = y2 - y1
B = -(x2 - x1)
C = -A * x1 - B * y1
(2) Нормализовать уравнение путем деления всех коэффициентов на длину вектора (A, B)
. То есть рассчитать длину
M = sqrt(A * A + B * B)
и затем вычислите значения
A' = A / M
B' = B / M
C' = C / M
Уравнение
A' * x + B' * y + C' = 0
по-прежнему является эквивалентным уравнением вашей линии L
за исключением того, что теперь нормальный вектор (A', B')
является единичным вектором.
(3) Возьмите свою точку P(px, py)
и вычислите значение
D = A' * px + B' * py + C'
Это даст вам подписанное расстояние D
от вашей точки P
до вашей линии L
. Другими словами, это расстояние от P
до ближайшей точки на L
(нас не интересует сама ближайшая точка, нам просто нужно расстояние).
Знак говорит, на какой стороне линии L
находится точка P
. Если P
лежит на той же стороне, на которую указывает вектор (A', B')
(«положительная» сторона), расстояние будет положительным. Если P
лежит на другой стороне («отрицательной» стороне), расстояние будет отрицательным.
(4) Чтобы найти точку зеркала P'(px', py')
, вам необходимо переместить вашу точку P
на абсолютное расстояние |2 * D|
через линию L
в другую сторону.
«Через линию» действительно означает, что если точка P
лежала на «положительной» стороне L
, то мы должны переместить ее против направления вектора (A', B')
в «отрицательную» сторону. И наоборот, если точка P
лежала на «отрицательной» стороне L
, то мы должны переместить ее в направлении вектора (A', B')
в «положительную» сторону.
Это может быть просто выражено как перемещение точки на расстояние -2 * D
(обратите внимание на минус) в направлении вектора (A', B')
.
Это означает, что
px' = px - 2 * A' * D
py' = py - 2 * B' * D
дает вам точку зеркала P'(px', py')
.
В качестве альтернативы вы можете использовать подход, основанный на нахождении фактической ближайшей точки N
на линии L
, а затем отражении вашей точки P
относительно N
. Это уже предлагается в других ответах, я просто опишу, как я это сделаю.
(1) Построить уравнение
A*x + B*y + C = 0
для вашей линии L
точно так же, как описано в шаге 1 выше. Нет необходимости нормализовать это уравнение.
(2) Постройте уравнение для перпендикулярной линии, проходящей через P
. Допустим, что перпендикулярная линия представлена
D*x + E*y + F = 0
Коэффициенты D
и E
известны сразу
D = B
E = -A
, в то время как F
можно рассчитать, подставив точку P
в уравнение
F = -D*px - E*py
(3) Найти пересечение этих двух линий, решая систему двух линейных уравнений
A*x + B*y = -C
D*x + E*y = -F
Правило Крамера в этом случае работает очень хорошо. Формула, приведенная в статье Пересечение линий в Википедии, является не чем иным, как применением правила Крамера к этой системе.
Решение дает вам ближайшую точку N(nx, ny)
, которую мы искали.
(4) Теперь просто посчитайте
px' = nx + (nx - px)
py' = ny + (ny - py)
чтобы найти свою точку P'(px', py')
.
Обратите внимание, что этот подход может быть почти полностью реализован в целых числах.Единственный шаг, который может потерять точность, - это разделение внутри правила Крамера на шаге 3. Конечно, как обычно, цена, которую вам придется заплатить за «почти интегральное» решение, - это необходимость арифметики большого числа.Даже коэффициенты C
и F
могут переполниться, даже не упоминая вычисления внутри формул правила Крамера.