Как найти точку пересечения перпендикулярных отрезков

Butt-Head

Заблокирован

1

Найти точку пересечения отрезка и перпендикуляра, опущенного на отрезок из точки

23.07.2015, 13:33. Показов 15534. Ответов 30

Метки нет (Все метки)


Студворк — интернет-сервис помощи студентам

Привет! Помогите двоишнику, я же тупой батхэд !

Есть отрезок, заданный двумя точками P1 и P2. Есть точка P3. Так вот, нужно найти координаты точки пересечения перпендикуляра, опущенного на заданный отрезок и, собственно этого отрезка, причём, если точка не находится на отрезке – как то просигнализировать …

Нужен рабочий код. Можно использовать С++ 11/14 и Qt, в котором есть

C++
1
static float dotProduct(const QVector2D& v1, const QVector2D& v2);

Миниатюры

Найти точку пересечения отрезка и перпендикуляра, опущенного на отрезок из точки
 



0



Programming

Эксперт

94731 / 64177 / 26122

Регистрация: 12.04.2006

Сообщений: 116,782

23.07.2015, 13:33

Ответы с готовыми решениями:

Найти точку пересечения отрезка и перпендикуляра, опущенного на отрезок из точки
Привет! Помогите двоишнику, я бивис! 😀

Есть отрезок, заданный двумя точками P1 и P2. Есть точка…

Найти основание перпендикуляра, опущенного из точки на прямую
Необходимо решить 2 задачи,но я не понимаю каким образом это можно сделать.
1.Дан метрический…

Написать уравнение перпендикуляра, опущенного из точки на прямую
Доброго времени суток
Прорешиваю практику по экзамена по алгему,попался вопрос,который звучит так…

Написать уравнение перпендикуляра, опущенного из точки на прямую
написать уравнение перпендикуляра, опущенного из точки А(-1;0;3) на прямую (х+1)/3 = (у-1)/2=z/1

30

1471 / 826 / 140

Регистрация: 12.10.2013

Сообщений: 5,456

23.07.2015, 13:53

2

Лучший ответ Сообщение было отмечено Butt-Head как решение

Решение

Хлебнете вы от аналитической геометрии…
Может тут?
Подобие math.h для геометрии
Где-то на форуме была точно помню…
Гуглить вроде “ перпендикуляр на прямую, Координаты перпендикуляра на прямую”?.

Добавлено через 6 минут
Вот ответ.
Перпендикуляр из точки на прямую



1



Butt-Head

Заблокирован

23.07.2015, 14:05

 [ТС]

3

Цитата
Сообщение от Excalibur921
Посмотреть сообщение

Подобие math.h для геометрии

Не… буст в топку

Цитата
Сообщение от Excalibur921
Посмотреть сообщение

Гуглить вроде “ перпендикуляр на прямую, Координаты перпендикуляра на прямую”?.

Да гуглил… Найти расстояние (длину этого перпендикуляра) от этой точки до отрезка – нет проблем, а вот координаты – хз как находить.

Мне собственно нужны даже не совсем координаты, а просто смещение от точки P1 до точки P4, то есть расстояние от начальной точки отрезка, до точки пересечения. Конечно же, зная координаты, я это расстояние найду. Но вроде бы как то можно скалярным произведением всё решить …. Помогите, dotProduct использовать можно !

Добавлено через 6 минут
То есть фактический ответом на мой вопрос будет это: (верно? Excalibur921 ? )

C++
1
2
3
4
5
6
//Прямая задана двумя точками (x1,y1) (x2,y2). Есть третья точка (x3,y3). Из точки нужно опустить перпендикуляр и найти координаты его основания на прямой (x4,y4)
float x1, x2, x3, x4;
float y1, y2, y3, y4;
//...
x4=((x2-x1)*(y2-y1)*(y3-y1)+x1*pow(y2-y1, 2)+x3*pow(x2-x1, 2))/(pow(y2-y1, 2)+pow(x2-x1, 2));
y4=(y2-y1)*(x4-x1)/(x2-x1)+y1;

Добавлено через 1 минуту
Ну ок, а как проверить, есть ли вообще решение? Ну то есть если перпендикуляр опускается на отрезок, но не попадает в его границы (попадает по лучу, а не по отрезку) ?



0



1471 / 826 / 140

Регистрация: 12.10.2013

Сообщений: 5,456

23.07.2015, 14:10

4

Цитата
Сообщение от Butt-Head
Посмотреть сообщение

попадает по лучу, а не по отрезку)

То найдет координаты точки на луче вроде.



1



Butt-Head

Заблокирован

23.07.2015, 14:17

 [ТС]

5

Цитата
Сообщение от Excalibur921
Посмотреть сообщение

То найдет координаты точки на луче вроде.

чта?
Я нахожу координаты точки пересечения перпендикуляра и отрезка. Как теперь мне определить, принадлежать ли эти координаты этому отрезку?



0



1471 / 826 / 140

Регистрация: 12.10.2013

Сообщений: 5,456

23.07.2015, 14:27

6

Цитата
Сообщение от Butt-Head
Посмотреть сообщение

чта?

Найдет координаты точки перпендикуляра на луч за границами отрезка.

Может можно и проще если важна скорость, но нужно очень шарить в геометрии. Надобыло в геометрии создавать…и просить решение в символьной форме.

Цитата
Сообщение от Butt-Head
Посмотреть сообщение

Как теперь мне определить,

Ну наверно проверить принадлежность точки отрезку… вход точки в интервал между X и Y точек P1 и P2. А как еще?

Добавлено через 1 минуту
Может есть еще решение в что то типа высота треугольника…



1



Butt-Head

Заблокирован

23.07.2015, 14:34

 [ТС]

7

Цитата
Сообщение от Excalibur921
Посмотреть сообщение

Ну наверно проверить принадлежность точки отрезку… вход точки в интервал между X и Y точек P1 и P2. А как еще?

ну это – то понятно:

C++
1
if((x3 > x1 && x3 < x2) && ... и тд

но дело в том, что у тебя отрезок может быть направлен в отрицательную сторону, тогда у тебя x2 будет меньше x1 и по этому тут нужно сперва всё это перегонять в 1-ю четверть (всего 3 координатные четверти), делать операцию и обратно. Понимаешь? По этому я и спрашиваю готовую формулу, т.к. лень всё делать самому.

В Qt наверняка что – то есть, неужели нет?



0



1471 / 826 / 140

Регистрация: 12.10.2013

Сообщений: 5,456

23.07.2015, 14:41

8

А можно узнать угол отрезка P1 P3 даст Альфа 1 и угол отрезка P1 P2 даст Альфа 2. Повернуть отрезок P1 P3 на Альфа 2 будет как треугольник с горизонтальным основанием(без поворота). Тогда P4=(x1,y3).

Добавлено через 3 минуты

Цитата
Сообщение от Butt-Head
Посмотреть сообщение

В Qt наверняка что – то есть,

Скорей всего…
Тогда надобыло в теме Qt создавать .Или поискать либы по геометрии в Qt…А чем плоха что я кидал либу? Там и 3д есть.



1



Butt-Head

Заблокирован

23.07.2015, 14:49

 [ТС]

9

Цитата
Сообщение от Excalibur921
Посмотреть сообщение

Тогда надобыло в теме Qt создавать

Да толку то …, всё равно все сидят только здесь

Цитата
Сообщение от Excalibur921
Посмотреть сообщение

А чем плоха что я кидал либу?

Тем что её надо изучать.

Ладно, через жопу на Qt реализовал, скоростью и не пахнет, да мне она и не нужна.
Вообще странно, что нет ничего готового для таких стандартных вещей …



0



1471 / 826 / 140

Регистрация: 12.10.2013

Сообщений: 5,456

23.07.2015, 14:57

10

Цитата
Сообщение от Butt-Head
Посмотреть сообщение

Вообще странно, что нет ничего готового для таких стандартных вещей

Я в Qt сначала неделю его ставил… Неверные переменные среды QT 4.8.0 Creator 2.4.1
потом не мог вывести синусоиду никто не подсказал 600 чел смотрели тему…
Синусоида OpenGL и слайдер
Потом ели стер этот Qt еще и с ошибками даже на удалении =).А примеры там это вообще жесть… куча мусора. Как не программист делал примеры туда.



1



Эксперт по математике/физикеЭксперт С++

2013 / 1342 / 382

Регистрация: 16.05.2013

Сообщений: 3,463

Записей в блоге: 6

23.07.2015, 15:01

11

Берете три вектора https://www.cyberforum.ru/cgi-bin/latex.cgi?{vec{r}}_{31}, {vec{r}}_{32} и https://www.cyberforum.ru/cgi-bin/latex.cgi?{vec{r}}_{21}
Что бы перпендикуляр лежал на отрезке достаточно, что бы скалярные произведения https://www.cyberforum.ru/cgi-bin/latex.cgi?({vec{r}}_{31}, {vec{r}}_{21}) и https://www.cyberforum.ru/cgi-bin/latex.cgi?({vec{r}}_{32}, {vec{r}}_{21}) были разных знаков.
Точка пересечения перпендикуляра находится как https://www.cyberforum.ru/cgi-bin/latex.cgi?vec{r} = {vec{r}}_{1} + ({vec{r}}_{31}, {vec{e}}_{21}){vec{e}}_{21}, где https://www.cyberforum.ru/cgi-bin/latex.cgi?{vec{e}}_{21} = frac{{vec{r}}_{21}}{left|{vec{r}}_{21} right|}



1



Butt-Head

Заблокирован

23.07.2015, 15:18

 [ТС]

12

Цитата
Сообщение от Excalibur921
Посмотреть сообщение

потом не мог вывести синусоиду никто не подсказал 600 чел смотрели тему…
Синусоида OpenGL и слайдер

Так там есть же ответ в последнем посте На самом деле сейчас большинство современного софта пишется на Qt, т.к. код на Qt собирается на любой современной ОС. Зря ты от него отказался

Цитата
Сообщение от Ilot
Посмотреть сообщение

Берете три вектора и

Спасибо. Но я не очень понимаю, что значит берёте три вектора.
У меня есть три пары координат (см рисунок в первом посте), вот как из них получить векторы?

Цитата
Сообщение от Ilot
Посмотреть сообщение

Точка пересечения перпендикуляра находится как

А это что, сложение вектора с о скобками, в которых чего? скалярное произведение или что ?

Не могли бы вы в координаты ваши формулы перевести?



0



Эксперт по математике/физикеЭксперт С++

2013 / 1342 / 382

Регистрация: 16.05.2013

Сообщений: 3,463

Записей в блоге: 6

23.07.2015, 15:30

13

Условие того, что точка лежит внутри отрезка:
https://www.cyberforum.ru/cgi-bin/latex.cgi?left( ({x}_{3} - {x}_{1}) * ({x}_{2} - {x}_{1}) + ({y}_{3} - {y}_{1}) * ({y}_{2} - {y}_{1})right) * left( ({x}_{3} - {x}_{2}) * ({x}_{2} - {x}_{1}) + ({y}_{3} - {y}_{2}) * ({y}_{2} - {y}_{1})right) < 0
Точка пересечения перепендикулляра и отрезка:
https://www.cyberforum.ru/cgi-bin/latex.cgi?x = {x}_{1} +  frac{ ({x}_{3} - {x}_{1}) * ({x}_{2} - {x}_{1}) + ({y}_{3} - {y}_{1}) * ({y}_{2} - {y}_{1})}{sqrt{({x}_{2} - {x}_{1}) * ({x}_{2} - {x}_{1}) + ({y}_{2} - {y}_{1}) * ({y}_{2} - {y}_{1})}} * frac{ ({x}_{2} - {x}_{1})}{sqrt{({x}_{2} - {x}_{1}) * ({x}_{2} - {x}_{1}) + ({y}_{2} - {y}_{1}) * ({y}_{2} - {y}_{1})}}
https://www.cyberforum.ru/cgi-bin/latex.cgi?y = {y}_{1} +  frac{ ({x}_{3} - {x}_{1}) * ({x}_{2} - {x}_{1}) + ({y}_{3} - {y}_{1}) * ({y}_{2} - {y}_{1})}{sqrt{({x}_{2} - {x}_{1}) * ({x}_{2} - {x}_{1}) + ({y}_{2} - {y}_{1}) * ({y}_{2} - {y}_{1})}} * frac{ ({y}_{2} - {y}_{1})}{sqrt{({x}_{2} - {x}_{1}) * ({x}_{2} - {x}_{1}) + ({y}_{2} - {y}_{1}) * ({y}_{2} - {y}_{1})}}
Надеюсь нигде не соврал…
p.s. В последних выражениях корни одинаковые поэтому их можно схлопнуть. Расписал для лучшего понимания.



1



Butt-Head

Заблокирован

23.07.2015, 15:48

 [ТС]

14

Цитата
Сообщение от Ilot
Посмотреть сообщение

Условие

Хмм… а что это за условие?

Результирующие координаты это x и у ?

Добавлено через 2 минуты
Ааа понял, это что б как бы точка принадлежала именно отрезку, а не лучу…
Ну что ж, спасибо, но в итоге это получается намноОого громоздче, нежели

C++
1
2
x4=((x2-x1)*(y2-y1)*(y3-y1)+x1*pow(y2-y1, 2)+x3*pow(x2-x1, 2))/(pow(y2-y1, 2)+pow(x2-x1, 2));
y4=(y2-y1)*(x4-x1)/(x2-x1)+y1;

из 3-го поста …
Всё таки векторная математика – чисто понт, в действительности – то всё идёт через обычные умножения, сложения и тд, но если решать всё с понтом, то решение получится намного сложнее



0



Ilot

Эксперт по математике/физикеЭксперт С++

2013 / 1342 / 382

Регистрация: 16.05.2013

Сообщений: 3,463

Записей в блоге: 6

23.07.2015, 16:03

15

Лучший ответ Сообщение было отмечено Ilot как решение

Решение

Цитата
Сообщение от Butt-Head
Посмотреть сообщение

Ну что ж, спасибо, но в итоге это получается намноОого громоздче, нежели…

Это еще как посмотреть:

C++
1
2
3
k = ((x3-x1) * (x2-x1) + (y3-y1)*(y2-y1))/ (pow(x2-x1, 2) + pow(y2-y1, 2));
x = x1 + k * (x2-x1);
y = y1 + k * (y2-y1);



1



Butt-Head

Заблокирован

23.07.2015, 16:10

 [ТС]

16

Цитата
Сообщение от Ilot
Посмотреть сообщение

Это еще как посмотреть:

Ну в принципе да…
Ладно, спасибо тебе о великий Ilot



0



1471 / 826 / 140

Регистрация: 12.10.2013

Сообщений: 5,456

23.07.2015, 16:53

17

ТС у вас работает?
Решил попробовать и не работает ваш код.
https://www.cyberforum.ru/cgi-bin/latex.cgi?A(x1,y1) вершина
https://www.cyberforum.ru/cgi-bin/latex.cgi?B(x2,y2),C(x3,y3) отрезок
https://www.cyberforum.ru/cgi-bin/latex.cgi?x,y искомая

https://www.cyberforum.ru/cgi-bin/latex.cgi?(x2-x1)=a0  <br />
(y2-y1)=a1   <br />
k=((x3-x1)*a0+(y3-y1)*a1)/(a0^2+a1^2)<br />
x=x1+k*a0<br />
y=y1+k*a1<br />



1



1471 / 826 / 140

Регистрация: 12.10.2013

Сообщений: 5,456

23.07.2015, 17:30

19

Цитата
Сообщение от Butt-Head
Посмотреть сообщение

Работает что?

Второй метод который вы просили расписать через вектора… и который быстрей должен быть.

Цитата
Сообщение от Butt-Head
Посмотреть сообщение

А ты что за формулы привёл?

Второй метод Ilot.

Добавлено через 24 минуты
Получается Butt-Head, использует метод который я предложил, а модератор отметил неработающую формулу как лучший ответ… забавно… =).



1



Butt-Head

Заблокирован

23.07.2015, 17:46

 [ТС]

20

Цитата
Сообщение от Excalibur921
Посмотреть сообщение

Получается Butt-Head, использует метод который я предложил, а модератор отметил неработающую формулу как лучший ответ… забавно… =).

Это не модератор отметил, а я Раз так, снимаю с ИЛОТА лучший ответ. Садись – два Илот .
Ставлю лучший ответ чудо мечу. (и не один, я не жадный ехехе)



0



как вычислить координаты точки пересечения линии и перпендикуляра?



Знаток

(389),
закрыт



11 лет назад

Петр Гришин

Знаток

(260)


13 лет назад

уравнение прямой, проходящей через две точки: y=(x-x1)(y2-y1)/(x2-x1)+y1
уравнение перпендикуляра, проведенного через точку 3: y=(x-x3)(x1-x2)/(y2-y1)+y3
подставляете в уравнения заданные координаты точек 1, 2 и 3 – получаете систему линейных уравнений. разрешаете ее – получаете координаты точки пересечения прямой и перпендикуляра

ngc3034Знаток (389)

13 лет назад

уравнения не работают
нарисовал пример по клеточкам
просчитал – икс вроде похоже, а игрик нет
думал изза того что точки надо местами поменять – вообще не то получается

Aleksey Vyazmikin:

Вам этой темы мало оказалось?

Нужно найти две функции и построить систему уравнений.

Но забавляет постановка задачи, когда второго отрезка нет, а есть только одна точка. И где же и когда, позвольте спросить, появится вторая точка?

Постановка задачи – вполне нормальная.

Имеется прямая, заданная через две точки.

Надо найти точку ее пересечения с перпендикуляром, проведенным из заданной третьей точки.

Обычная задача на аналитическую геометрию, старшие классы школы.

Уравнение прямой:

(Y-Y1)/(Y2-Y1) = (X-X1)/(X2-X1)

Дальше, блин, не помню… надо рыться в справочниках…

Если нигде не ошибся: уравнение перпендикуляра через третью точку:

Y=(X-X3)(X1-X2)/(Y2-Y1)+Y3

Получаем систему из двух уравнений с двумя неизвестными.

Решаем – получаем точку пересечения.

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

Поэтому – в подборку теории и практики, пригодится, сэкономим блокнот, спасем дерево.

Коэффициенты А, B, C

Все помним со школы формулу:

Latex formula

Тоже самое, но с претензией на образование (некоторые индивидуумы утверждают, что существует такая, и только такая, и никакая другая, формулировка):

Latex formula

Те же фаберже, только сбоку.

В теории надо составить и решить систему уравнений для первой и второй линии, где переменными будут X и Y точки пересечения.

Latex formula

Загвоздка в том, что мы не знаем коэффициенты для обеих линий.

В нашем случае известны координаты двух точек, по которым проходит линия. Поэтому мне, как последователю геометрического агностицизма, более привлекательная следующая формула:

Latex formula

Путем несложных операций приходим к следующей записи:

Latex formula

Глядя на вариант в исполнении высшего образования, получаем следующие формулы для нахождения коэффициентов:

Latex formula

Пока все идет отлично, нигде вероятного деления на ноль не встретилось.

Итак, мы можем легко найти два набора коэффициентов для первой и второй прямых. Переходим к системе уравнений.

Система уравнений

Как правило, подобная система уравнений решается путем выражения одной переменной через другую, подстановкой во второе уравнение, получая таким образом уравнение одной переменной. Далее переменная находится, подставляется, решается. Или определяется, что система решения не имеет.

Но нас интересует метод Крамера. Потому что с помощью этого метода можно получить сразу значения для обеих переменных, без дополнительных телодвижений.

Сразу же запишем метод под нашу систему.

Имеем следующую систему:

Latex formula

Определители будут такими:

Latex formula

Latex formula

Latex formula

Исходя из метода, решение выглядит так:

Latex formula

Latex formula

Ага! Вот и возможное деление на ноль, скажете вы. И правильно! В этой, в высшей степени непозволительной ситуации, когда знаменатель равен нулю, решения нет, прямые либо параллельны, либо совпадают (что, впрочем, частный случай параллельности).  В коде, естественно, этот момент надо учитывать.

Практика 1

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

//*******************************************************

//  Нахождение точки пересечения прямых (p1,p2) и (p3,p4)

//  Результат – факт пересечения

//*******************************************************

function CrossLines(const p1,p2,p3,p4: TxPoint;

  var res: TxPoint): Boolean;

const

  Prec = 0.0001;

var

  a1, a2: Extended;

  b1, b2: Extended;

  c1, c2: Extended;

  v: Extended;

begin

  a1 := p2.y p1.y;

  a2 := p4.y p3.y;

  b1 := p1.x p2.x;

  b2 := p3.x p4.x;

  v := a1*b2 a2*b1;

  Result := (abs(v) > Prec);

  if Result then

  begin

    c1 := p2.x*p1.y p1.x*p2.y;

    c2 := p4.x*p3.y p3.x*p4.y;

    res.X := (c1*b2 c2*b1)/v;

    res.Y := (a1*c2 a2*c1)/v;

  end;

end;

Пересечение прямых, построенных по двум точкам. Точка пересечения принадлежеит обоим отрезкам.

Рис.1. Пересечение прямых

Частные случаи

  • Прямые параллельны: ∆ab = 0
    • (A1B2 – B1A2 = 0);
  • Прямые совпадают:  ∆ab = ∆X = ∆Y = 0 
    • (A1B2 – B1A2 = 0) И (A1C2 — A2C1 = 0) И (C1B2 -B1C2 = 0);
  • Прямые перпендикулярны:
    • (A1 A2 + B1 B2 = 0).

Пересечение перпендикулярных прямых

Рис.2. Пересечение перпендикулярных прямых
Параллельные прямые
Рис.3. Параллельные прямые не пересекаются

Принадлежность точки отрезку

В общем случае, чтобы определить принадлежность точки отрезку, надо установить две вещи:

  1. Точка принадлежит прямой, проходящей через конечные точки отрезка. Для этого достаточно подставить значение X и Y в уравнение прямой и проверить получившееся равенство. В нашем случае, этот пункт уже выполнен, т.к. точка пересечения априори принадлежит обеим прямым.
  2. Проверить факт нахождения точки между концами отрезка.

Займемся пунктом 2. Данный факт можно установить двумя способами:

  • Логически, т.е. (x1 <= x <= x2) ИЛИ (x1 >= x >= x2). На случай «вертикальности» линии добавить проверку на Y:
    • (y1 <= y <= y2) ИЛИ (y1 >= y >= y2).
  • Арифметически. Сумма отрезков |x-x1| + |x-x2| должна быть равна длине отрезка |x1-x2|. Аналогично, на случай «вертикальности» , добавить проверку:
    • |y-y1| + |y-y2| = |y1-y2|

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

//*****************************************************

//  Проверка факта нахождения точки res между

//  концами отрезка (p1,p2).

//  Решение с помощью условных операторов и

//  коэффициентов A=(y2-y1) B=(x1-x2).

//  Выступают в качестве параметров, чтобы не тратить

//  время на их подсчет, т.к. в вызывающей стороне

//  они уже посчитаны

//*****************************************************

function CheckCrossPoint(const p1, p2, res: TxPoint;

  const A,B: Extended): Boolean;

begin

  Result :=

    (((B<0) and (p1.X < res.X) and (p2.X > res.X)) or

     ((B>0) and (p1.X > res.X) and (p2.X < res.X)) or

     ((A<0) and (p1.y > res.Y) and (p2.Y < res.Y)) or

     ((A>0) and (p1.y < res.Y) and (p2.Y > res.Y)));

end;

//*****************************************************

//  Проверить факт нахождения точки res между

//  концами отрезка (p1,p2)

//  Арифметическое решение без коэффициентов

//*****************************************************

function CheckCrossPoint(const p1, p2, res: TxPoint): Boolean;

begin

  Result :=

    (abs(p2.xp1.x)>= abs(p2.xres.x) + abs(p1.xres.x)) and

    (abs(p2.yp1.y)>= abs(p2.yres.y) + abs(p1.yres.y));

end;

Практика показывает, что арифметический способ быстрее примерно в 3 раза. Когда-то я считал, что операции сравнения самые быстрые. Это давно уже не так.

Задача нахождения принадлежности точки P(x,y) отрезку, заданного двумя точками с координатами P1(x1, y1) и P2(x2, y2) подробно рассмотрена в отдельной статье.

Угол пересечения прямых

Угол пересечения прямых — это угол пересечения направляющих векторов. Т.е., взяв уже знакомые ранее точки p1 и p2, получим направляющий вектор V(p1,p2), и аналогично второй вектор M(p3,p4). В теории мы должны вычислить достаточно «затратную» функцию, с корнями, квадратами, дробями и арккосинусом.

Давайте не будем останавливаться на ней, она долгая, нудная и в нашем случае ненужная. Рассмотрим вектор:

Вектор из точки p1 в точку p2 с указанием расстояний по Y и X

Рис.4. Вектор V(p1,p2)

α — угол наклона вектора к оси X, который можно найти, как:

α = arctan (A1 / B1)

Где расстояния:

A1 = (y1 — y2)

B1 = (x2 — x1)

Что-то знакомое? Да это ни что иное, как коэффициенты в уравнении прямой от образованных фанатов. Может они и правы в своем испепеляющем фанатизме…

Одним словом, коэффициенты (расстояния) у нас уже есть по обеим прямым.

Пересекающиеся векторы

Рис.5. Пересекающиеся вектор V(p1,p2) и вектор M(p3,p4)

Судя по рисунку, угол между векторами, это сумма углов наклона векторов к оси X. Ммм… не совсем так, на самом деле это разность.

Пересекающиеся векторы

Рис.6. Пересекающиеся векторы в положительной Y

По рисунку явно видно, что угол между векторам это γ = (βα).

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

От теории к практике

Теперь в плане практического применения. Мне нужно точно знать, откуда, куда и в каком направлении этот угол. В теории, углом между прямыми считается наименьший из пары γ и (180-γ). Так вот, нам это не надо. Какой угол получится – такой нам и нужен.

Поэтому, под углом между векторами понимаем угол от вектора V(p1,p2) к вектору M(p3,p4). Если знак угла – отрицательный, понимаем, что он против часовой стрелки, иначе – по часовой стрелке.

Следует заметить, что, зная коэффициенты, для нахождения угла пересечения, координаты уже не нужны. Листинг таков:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

//**********************************************************

// Посчитать угол пересечения векторов по коэфф-ам А и B

//**********************************************************

function CalcCrossAngle(const a1,b1: Extended;

  const a2,b2: Extended): Extended;

var

  c1, c2: Extended;

begin

  c1 := ArcTan2(a1,b1);

  c2 := ArcTan2(a2,b2);

  Result := c2c1;

  if Result < pi then

    Result := 2*pi + Result;

  if Result > pi then

    Result := Result 2*pi;

end;

Тут ситуация с вертикальной прямой, т.е. когда теоретически происходит деление на ноль, явно не обрабатывается. Она корректно обрабатывается функцией ArcTan2, которая вернет в этом случае и знак, и 90 градусов.  

Пересечение перпендикулярных векторов с верным подсчетом особого "вертикального" случая.

Рис.7. Пересечение перпендикулярных векторов

Практика 2

В дополнение к функции нахождения точки пересечения, напишем «продвинутую» функцию, которая находит эту точку, определяет нахождение на каждом из отрезков, и определяет угол между направляющими векторами. Или же определяет, что прямые параллельны/совпадают.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

//**********************************************************

//  Тип пересечения прямых (p1,p2) и (p3,p4)

//**********************************************************

type

  TxCrossLineResult = (

    xclrEqual    = 32// эквивалентны

   ,xclrParallel = 16// параллельны

   ,xclrOk       = 0  // как минимум пересечение есть

   ,xclrFirst    = 1  // попадает в первый отрезок

   ,xclrSecond   = 2  // попадает во второй отрезок

   ,xclrBoth     = 3  // попадает в оба

   ,xclrPerpend  = 4  // перпендикулярны

   // можно найти по маске через AND, но для полноты картины

   ,xclrFirstP   = 5  // перпендикулярны и попадает в первый

   ,xclrSecondP  = 6  // перпендикулярны и попадает в второй

   ,xclrBothP    = 7  // перпендикулярны и попадает в оба

   );

//**********************************************************

//  Нахождение точки пересечения прямых (p1,p2) и (p3,p4)

//  Определяет параллельность, совпадение,

//  перпендикулярность, пересечение.

//  Определяет, каким отрезкам принадлежит.

//  Находит угол(рад.) от (p1,p2) к (p3,p4):

//    отрицательное значение – против часовой

//    положительное – по часовой

//**********************************************************

function CrossLines(const p1,p2,p3,p4: TxPoint;

  var res: TxPoint; var Angle: Extended): TxCrossLineResult;

const

  Prec = 0.0001;

var

  a1, a2: Extended;

  b1, b2: Extended;

  c1, c2: Extended;

  v: Extended;

begin

  Angle := 0;

  a1 := p2.y p1.y;

  a2 := p4.y p3.y;

  b1 := p1.x p2.x;

  b2 := p3.x p4.x;

  c1 := p2.x*p1.y p1.x*p2.y;

  c2 := p4.x*p3.y p3.x*p4.y;

  v := a1*b2 a2*b1;

  if abs(v) > Prec then

  begin

    Result := xclrOk;

    res.X := (c1*b2 c2*b1)/v;

    res.Y := (a1*c2 a2*c1)/v;

    if CheckCrossPoint(p1,p2,res) then

      Result := TxCrossLineResult(Integer(Result) +

        Integer(xclrFirst));

    if CheckCrossPoint(p3,p4,res) then

      Result := TxCrossLineResult(Integer(Result) +

        Integer(xclrSecond));

    if (abs(a1*a2 + b1*b2) < Prec) then

      Result := TxCrossLineResult(Integer(Result) +

        Integer(xclrPerpend));

    Angle := CalcCrossAngle(a1,b1,a2,b2);

  end else

  begin

    Result := xclrParallel;

    if ((abs(c1*b2 c2*b1) < Prec) and

       (abs(a1*c2 a2*c1) < Prec))

    then

      Result := xclrEqual;

  end;

end;

Исходники

Небольшие комментарии по интерфейсу.

Интерфейс программы

Рис.8. Интерфейс программы

Скачать (219 Кб): Исходники (Delphi XE 7-10)

Скачать (1.14 Мб): Исполняемый файл

При запуске генерируется случайным образом 4 точки, по две на прямую. Точки и отрезки можно перетаскивать мышкой. Также, слева присутствует панель, на которой можно ввести координаты точек или коэффициенты уравнения прямой. При нажатии «Enter» или когда элемент ввода теряет фокус, происходит перерасчет и перерисовка.

Внизу есть 4 кнопки переключения режимов отображения. Начиная со второй, помимо координат точки пересечений в верхнем левом углу будет отображаться текущий угол пересечения между направляющими векторами.

Если точка пересечений попадает в какой-либо из отрезков, соответствующий заголовок линии отрезка станет жирным. На рисунке это зеленая линия 2.

По умолчанию, рабочее поле системы координат имеет размерность [-10..10], которую можно изменить ползунком в нижнем правом углу.

Заранее извиняюсь, если ошибся с разделом, но просто пишу на си, поэтому и алгоритм хотел бы на нём =)

Так вот, у меня всю жизнь было плохо с математикой и столкнулся с такой проблемой. Есть два отрезка с совершенно рандомными координатами от -10000 до +10000, нужно определить пересекаются ли данные отрезки или нет. В интернете пытался найти готовый алгоритм – не получилось. Видимо, задача тривиальна..

У кого есть идеи или кто сталкивался с таким вопросом, подскажите пожалуйста. От готового решения также не откажусь =) Заранее, спасибо!

24 ответа

5

17 марта 2009 года

hardcase

4.5K / / 09.08.2005

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

Находим точку пересечения двух прямых, и если она есть, проверяем, лежит ли она на обоих отрезках.
Найти пересечение элементарно – нужно решить систему уравнений прямых.

318

17 марта 2009 года

nof

193 / / 03.04.2006

Находим точку пересечения двух прямых, и если она есть, проверяем, лежит ли она на обоих отрезках.
Найти пересечение элементарно – нужно решить систему уравнений прямых.

Это при условие, что у нас есть уравнения описывающие данные отрезки. Но у нас есть только начальные и конечные точки отрезков.

397

17 марта 2009 года

SergPas

527 / / 03.02.2007

Есть такая замечательная книга Френсиса Хилла “OpenGL. Программирование компьютерной графики”. В ней есть решение задачи определения точки пересечения 2-х отрезков прямой, заданных в параметрической (то что нужно) и/или в точечной нормальной формах…

Это при условие, что у нас есть уравнения описывающие данные отрезки. Но у нас есть только начальные и конечные точки отрезков.

уравнение прямой y= k*x + b
где k тангенс угла наклона прямой (отношение противолежащего катета к прилежащему, катеты можно легко найти, зная координаты точек отрезка)
b – некая постоянная (то значение Y где прямая пересекает ось OY)

5

17 марта 2009 года

hardcase

4.5K / / 09.08.2005

Это при условие, что у нас есть уравнения описывающие данные отрезки. Но у нас есть только начальные и конечные точки отрезков.

Внимаетельно смотрим на формулы. Там есть ответы на все ваши вопросы.

Берем канонические уравнения:

таковые легко получить имея две точки прямой (x1, y1, z1), (x2, y2, z2)

(x-x1) (y-y1) (z-z1)
——= —– = ——
(x2-x1) (y2-y1) (z2-z1)

где знаменатели дробей соответственно равны m, n и p

Для двух прямых имеем:

m1, n1, p1
m2, n2, p2

Если отношения m1/m2 равно n1/n2 и равно p1/p2, то прямые параллельны, в потивном случае они пересекаются.

Для двумерного случая дробь с координатой z не нужна.

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

Цитата:

Находим точку пересечения двух прямых, и если она есть, проверяем, лежит ли она на обоих отрезках.
Найти пересечение элементарно – нужно решить систему уравнений прямых.

Есть такая замечательная книга Френсиса Хилла “OpenGL. Программирование компьютерной графики”. В ней есть решение задачи определения точки пересечения 2-х отрезков прямой, заданных в параметрической (то что нужно) и/или в точечной нормальной формах…

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

Я бы посоветовал книгу Дмитрия Письменного “Конспект лекций по высшей математике” ( 1-ю часть). Там есть аналитическая геометрия, к которой как раз и относится первоначальный вопрос. К тому же в весьма доступной форме. Да и вообще по аналитической геометрии в недрах паутины материала предостаточно.

276

17 марта 2009 года

Rebbit

1.1K / / 01.08.2005

уравнение прямой y= k*x + b
где k тангенс угла наклона прямой

Только такое уравнение не подходит для вертикальных прямых так как у 90 градусов нет тангенса. Ето надо учитывать.

(x-x1) (y-y1) (z-z1)
——= —– = ——
(x2-x1) (y2-y1) (z2-z1)

Ну и тут по сути надо учитывать то же самое. В знаменателе может и 0 получится.

ЗЫ. Также не забудьте что если прямые и паралельни, то отрезки всеровно могут иметь общую точку, а возможно и частично накладываться.

397

17 марта 2009 года

SergPas

527 / / 03.02.2007

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

Я бы посоветовал книгу Дмитрия Письменного “Конспект лекций по высшей математике” ( 1-ю часть). Там есть аналитическая геометрия, к которой как раз и относится первоначальный вопрос. К тому же в весьма доступной форме. Да и вообще по аналитической геометрии в недрах паутины материала предостаточно.

Я не говорю о бумажной версии этой книги, я говорю об электронном варианте, который найти в рунете как расплюнуть…;) В ней как раз и рассматриваются вопросы по сабжу… Также обсуждаются вопросы и перекрывающихся прямых, и т.д. и т.п. Да и представленные в ней алгоритмы универсальны…

318

17 марта 2009 года

nof

193 / / 03.04.2006

Ребят, извините мою безграмотность + я ещё не начал проверять на практике то, что вы описали, но на глаз: речь ведь идёт об отрезках, а вы все пишите о прямых. Мне не нужно искать точку пересечения прямых, мне нужно знать пересекаются отрезки или нет.

276

17 марта 2009 года

Rebbit

1.1K / / 01.08.2005

Тоесть отрезки не на плоскости или в пространстве, а на прямой ?? Ги-ги. Ето же тривиально. Можно написать пару ифов. Типа если начало второго отрезка лежит после начала первого и конец……. и так далее. А можно просто взять 4 точки и…. Короче примерно так как я писал тут с отрезками времени

240

17 марта 2009 года

aks

2.5K / / 14.07.2006

Блин, автор ну перечитай еще раз что тебе уже посоветовал hardcase. И должно быть стыдно – ибо в данной задаче программирования то особо нету, а есть только школьная геометрия, не более.

276

17 марта 2009 года

Rebbit

1.1K / / 01.08.2005

Блин, автор ну перечитай еще раз что тебе уже посоветовал hardcase. И должно быть стыдно – ибо в данной задаче программирования то особо нету, а есть только школьная геометрия, не более.

Да нет там геометрии если я правильно понял. У нево только одна координата Х. Отрезки в одномерном пространстве.

397

17 марта 2009 года

SergPas

527 / / 03.02.2007

Ребят, извините мою безграмотность + я ещё не начал проверять на практике то, что вы описали, но на глаз: речь ведь идёт об отрезках, а вы все пишите о прямых. Мне не нужно искать точку пересечения прямых, мне нужно знать пересекаются отрезки или нет.

Вы и не будете искать точку пересечения, если это не надо… Вы найдёте один единственный параметр и если он будет лежать вне интервала [0;1], то отрезки прямых не пересекаются. Короче, читайте, учите, ищите, разбирайтесь… Литературу Вам указали…

Пипец, все такие умные, но ничего конкретного человеку так и не предложили. Всё почитай, да поищи, да этоже элементарно. Если элементарно, так напиши.
Короче вот функция на java (с портированием на C я думаю проблем не будет :), определяющая пересекаются ли два отрезка на плоскости:

Код:

boolean transection (double ax1, double ay1, double ax2, double ay2, double bx1, double by1, double bx2, double by2)
{
    double v1=(bx2-bx1)*(ay1-by1)-(by2-by1)*(ax1-bx1);
    double v2=(bx2-bx1)*(ay2-by1)-(by2-by1)*(ax2-bx1);
    double v3=(ax2-ax1)*(by1-ay1)-(ay2-ay1)*(bx1-ax1);
    double v4=(ax2-ax1)*(by2-ay1)-(ay2-ay1)*(bx2-ax1);
    return ((v1*v2<=0) && (v3*v4<=0));
}

Функция возвращает true если отрезки A и B пересекаются.
ax1, ay1 – координаты первой точки отрезка A ну и т.д.

Вот ищу нечто подобное для определения пересекает ли отрезок круг.
Если известны координаты отрезка, координаты центра круга и его радиус.

5

21 декабря 2009 года

hardcase

4.5K / / 09.08.2005

Пипец, все такие умные, но ничего конкретного человеку так и не предложили. Всё почитай, да поищи, да этоже элементарно. Если элементарно, так напиши.

Ссылка на решение задачи была дана в #6. Автор, кстати, просил хотя бы алгоритм.

Вот ищу нечто подобное для определения пересекает ли отрезок круг.
Если известны координаты отрезка, координаты центра круга и его радиус.

Решите аналитически систему уравнений:
а) окружности
б) прямой
“Линейка”, первый курс.

Если “программист” не в сосотоянии прочитать простые формулы из справочника и/или выполнить тривиальные выкладки, то ему наверняка нужно подыскивать новую специальность.

Ссылка на решение задачи была дана в #6. Автор, кстати, просил хотя бы алгоритм.

Это ссылка не на решение задачи, а на статью Википедии о прямой.
И естественно никаких алгоритмов там нет.

Решите аналитически систему уравнений:
а) окружности
б) прямой
“Линейка”, первый курс.

Очень “полезный” совет, никогдаб не догадался.

5

21 декабря 2009 года

hardcase

4.5K / / 09.08.2005

Это ссылка не на решение задачи, а на статью Википедии о прямой.

Переходим по ссылке, находим подраздел “Взаимное расположение нескольких прямых на плоскости” и (о чудо!) обнаруживаем там формулу, которую вы записали в своем предыдущем посте. А как найти коэффициенты канонического уравнения? – спросите вы. А очень просто: на той же самой странице есть уравнение прямой проходящей через две заданные точки. Имеющий глаза да узрит решение.

И естественно никаких алгоритмов там нет.

С каких это пор язык математики перестал выражать суть исполняемых компьютером действий?

Для общего развития: слова алгоритм и арифметика восходят к одному корню.

Очень “полезный” совет, никогдаб не догадался.

Ну так и вперед! Че, лень пошевелить мозгами, ага?

[quote=”некто”]
Зачем тогда вообще отвечать на форуме? Можно просто на все посты давать две ссылки на википедию и на Google
[/quote]
Каков вопрос – таков ответ.

9.0K

21 декабря 2009 года

grag63

71 / / 23.01.2006

Надеюсь следующие рассуждения помогут в решении задачи:
исходные данные: отрезок AB, радиус R.
Возможные варианты:
1) растояния до точек отрезка < R -> отрезок внутри окружности
2) одно из растояний до отрезка > R, а другое < R -> ответ очевиден
3) AR & BR > R – строим перпендикуляр от центра окружности к отрезку (точка C)
CR > R -> отрезок находится за пределами окружности.

397

22 декабря 2009 года

SergPas

527 / / 03.02.2007

Цитата:

исходные данные: отрезок AB, радиус R.

А центр окружности разве не нужен? 😀

Надеюсь следующие рассуждения помогут в решении задачи:
исходные данные: отрезок AB, радиус R.
Возможные варианты:
1) растояния до точек отрезка < R -> отрезок внутри окружности
2) одно из растояний до отрезка > R, а другое < R -> ответ очевиден
3) AR & BR > R – строим перпендикуляр от центра окружности к отрезку (точка C)
CR > R -> отрезок находится за пределами окружности.

А решить одно квадратное уравнение с одним неизвестным уже не по силам? 😉

9.0K

23 декабря 2009 года

grag63

71 / / 23.01.2006

А центр окружности разве не нужен?
а как же без него?
И точку С необходимо проверит на принадлежность отрезку, и…

А решить одно квадратное уравнение с одним неизвестным уже не по силам?
Может проще привести уравнение, чем каждый раз отвечать вопросом на вопрос???

1.9K

23 декабря 2009 года

GreenRiver

451 / / 20.07.2008

Господин топик-стартер не желает не только решать уравнения уровня третьего класса,
он даже не желает набрать в гугле пересечение отрезков и выбрать из десятков готовых решений…

Есть готовая функция на C# для нахождения точки пересечения двух отрезков, заданных точками, один из которых горизонтальный или вертикальный, может кому пригодится. http://pastie.org/1819393

Код:

// нахождение точки пересечения отрезка, заданного точками p1 p2 c вертикальным/горизонтальным отрезком, заданным точками p3 p4
        public Point Crossing(Point p1, Point p2, Point p3, Point p4)
        {
            if (p3.X == p4.X)   // вертикаль
            {
                double y = p1.Y + ((p2.Y – p1.Y) * (p3.X – p1.X)) / (p2.X – p1.X);
                if (y > Math.Max(p3.Y, p4.Y) || y < Math.Min(p3.Y, p4.Y) || y > Math.Max(p1.Y, p2.Y) || y < Math.Min(p1.Y, p2.Y))   // если за пределами отрезков
                    return new Point(0, 0);
                else
                    return new Point(p3.X, (int)y);
            }
            else            // горизонталь
            {
                double x = p1.X + ((p2.X – p1.X) * (p3.Y – p1.Y)) / (p2.Y – p1.Y);
                if (x > Math.Max(p3.X, p4.X) || x < Math.Min(p3.X, p4.X) || x > Math.Max(p1.X, p2.X) || x < Math.Min(p1.X, p2.X))   // если за пределами отрезков
                    return new Point(0, 0);
                else
                    return new Point((int)x, p3.Y);
            }
        }

98K

17 января 2017 года

freddyspb

1 / / 17.01.2017

Код выше не работает для перпендикулярных отрезков.
Вот пример получения точки пересечения для 2 перпендикулярных отрезков (может кому пригодится):

Код:

function getCrossPoint(p1, p2, p3, p4) {

 
    if ( Math.min(p1.x, p2.x) > p3.x || Math.max(p1.x, p2.x) < p3.x
      || Math.min(p3.y, p4.y) > p1.y || Math.max(p3.y, p4.y) < p1.y) {    
      // не пересекаются
      return {x: 0, y: 0};
    } else
      return {x: p3.x, y: p1.y};    
  }

Добавить комментарий