Как рассчитать вектор нормали отрезка?


177

Предположим, у меня есть отрезок, идущий от (x1, y1) к (x2, y2). Как рассчитать вектор нормали, перпендикулярный линии?

Я могу найти много материала о том, как сделать это для самолетов в 3D, но нет материала 2D.

Пожалуйста, не стесняйтесь в математике (ссылки на проработанные примеры, диаграммы или алгоритмы приветствуются), я программист больше, чем математик;)


2
И если вы хотите узнать о «математике» за этим, вы можете посмотреть мой ответ на stackoverflow.com/a/7470098/189767 . Это в основном то же самое, но более сложное.
Андреас

2
Этот вопрос касается математики, а не программирования.
Чарли

1
Я голосую, чтобы закрыть этот вопрос как не по теме, потому что он касается математики, а не программирования.
Пан

Ответы:


237

если мы определим dx = x2-x1 и dy = y2-y1, то нормалями будут (-dy, dx) и (dy, -dx).

Обратите внимание, что деление не требуется, и поэтому вы не рискуете делить на ноль.


14
Это довольно тонко и мне потребовалось некоторое время, чтобы понять, что normal.x = -dy и normal.y = dx. У меня они были наоборот, потому что это выглядело как опечатка, присваивающая часть x значению y ...
Piku

@OrenTrutner Я до сих пор не понимаю этого; (x', y') = (-y, x)и (x', y') = (y, -x)вроде бы прав, но зачем бы тут dxи dyздесь. Более того, исходя из уклонов, m1 * m2 = -1для прямых угловых линий, отсюда dy' = dx' * (-dx/dy)и dx' = dy' * (-dy/dx)как получается ваше уравнение normal.x = x' = -dy?
legends2k

1
Не могли бы вы рассказать подробнее о том, как дельта играет роль здесь? Я уверен, что я что-то здесь упускаю.
legends2k

7
@ legends2k: дельта - касательный вектор. Нормаль - это направление, перпендикулярное касательной. Переключение значений x / y и отрицание одного становится очевидным, если вы посмотрите на 2D-матрицу для поворота на 90 градусов: en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
geon

@geon: Ааа! Понял, я путал дельту с наклоном, в то время как в аффинной геометрии разница между двумя точками является вектором, а здесь
тангетом

95

Другой способ думать об этом - вычислить единичный вектор для заданного направления, а затем применить поворот на 90 градусов против часовой стрелки, чтобы получить вектор нормали.

Матричное представление общего 2D-преобразования выглядит так:

x' = x cos(t) - y sin(t)
y' = x sin(t) + y cos(t)

где (x, y) - компоненты исходного вектора, а (x ', y') - преобразованные компоненты.

Если t = 90 градусов, то cos (90) = 0 и sin (90) = 1. Подставляя и умножая его, получаем:

x' = -y
y' = +x

Тот же результат, что и ранее, но с небольшим объяснением того, откуда он берется.


2
Огромное спасибо, ломал мне голову о том, как это получалось.
legends2k

1
Хотя я знал формулу вращения раньше, этот ответ вызвал у меня в голове то, что угол является константой (+/- 90), что упрощает ее до простого отрицания и обращения x и y.
legends2k

@duffymo длина результата равна единице?
Мартин Мизер,

Если вектор нормализован до преобразования, он останется таковым и после. Вы должны нормализовать до или после выполнения вращательного преобразования.
duffymo

11

Этот вопрос был опубликован давно, но я нашел альтернативный способ ответить на него. Поэтому я решил поделиться этим здесь.
Во-первых, нужно знать, что: если два вектора перпендикулярны, их скалярное произведение равно нулю.
Вектор нормали (x',y')перпендикулярен линии, соединяющей (x1,y1)и (x2,y2). Эта линия имеет направление (x2-x1,y2-y1), или (dx,dy).
Так,

(x',y').(dx,dy) = 0
x'.dx + y'.dy = 0

Существует множество пар (x ', y'), которые удовлетворяют приведенному выше уравнению. Но лучшая пара , которая всегда удовлетворяет либо (dy,-dx)или(-dy,dx)


7
m1 = (y2 - y1) / (x2 - x1)

если перпендикулярно две линии:

m1*m2 = -1

затем

m2 = -1 / m1 //if (m1 == 0, then your line should have an equation like x = b)

y = m2*x + b //b is offset of new perpendicular line.. 

b - это что-то, если вы хотите передать его из точки, которую вы определили

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.