Четырехугольник |
1. Заголовок темы должен быть информативным. В противном случае тема удаляется ...
2. Все тексты программ должны помещаться в теги [code=pas] ... [/code], либо быть опубликованы на нашем PasteBin в режиме вечного хранения.
3. Прежде чем задавать вопрос, см. "FAQ", если там не нашли ответа, воспользуйтесь ПОИСКОМ, возможно такую задачу уже решали!
4. Не предлагайте свои решения на других языках, кроме Паскаля (исключение - только с согласия модератора).
5. НЕ используйте форум для личного общения, все что не относится к обсуждению темы - на PM!
6. Одна тема - один вопрос (задача)
7. Проверяйте программы перед тем, как разместить их на форуме!!!
8. Спрашивайте и отвечайте четко и по существу!!!
Четырехугольник |
Andy |
Сообщение
#21
|
Новичок Группа: Пользователи Сообщений: 23 Пол: Мужской Репутация: 0 |
Не воспринимает точку, которая лежит на линии (хотя в предыдущем примере, ответ был верный, если взять точку на прямой), т.е глючит : например,
(X:1;Y:2), (X:1;Y:4), (X:3;Y:4), (X:3;Y:2) Check1: TPoint = (X:1; Y:3); Или Check1: TPoint = (X:1; Y:3); Ответ b=false. А точка принадлежит. Или я что-то не так понял в работе программы? (cм. предыдущее сообщение) |
volvo |
Сообщение
#22
|
Гость |
Andy
Да, у меня тоже начало глючить (причем в самых неожиданных местах)... Значит тот алгоритм был со сбоями. Ладно, найдем другой :yes: |
Andy |
Сообщение
#23
|
Новичок Группа: Пользователи Сообщений: 23 Пол: Мужской Репутация: 0 |
Volvo
В принципе алгоритм с лучом (тот, который ты переводил с англ.) 100%. Тут я, так понимаю, надо все линии записать в виде уравнений прямых, луч, кстати, тоже надо записать как прямую (т.е. все-таки его ограничить). И брать по отдельности каждую прямую четырехугольника вместе с лучом. Решить систему уравнений. Получим точку, или точки, или вообще ничего не получим и сделать соответствующие выводы после перебора всех линий четырехугольника (четное число точек пересечения => не принадлежит, нечетное => принадлежит). Здесь вся фишка в поиске точки пересечения. Пока сложновато, если учесть, что прямая представляется в виде Ax+By+C=0… Тут, кстати тоже не решена проблема: если точка принадлежит прямой По данному алгоритму она будет считаться как лежащая вне четырехугольника. Наверное, надо будет просто определить эту принадлежность. Вот, вроде все сформулировал к решению задачи, но че-то все не клеится. |
volvo |
Сообщение
#24
|
Гость |
Andy
проверь РМ... ;) Добавлено Вот та функция, о которой я говорил... Сообщение отредактировано: volvo - Прикрепленные файлы ANDY.PAS ( 3.07 килобайт ) Кол-во скачиваний: 336 |
Andy |
Сообщение
#25
|
Новичок Группа: Пользователи Сообщений: 23 Пол: Мужской Репутация: 0 |
Да, пока работает. Но надо еще попроверять <_< .
Я хотел узнать. Я сначала для решения этой задачи использовал алгоритм векторного произведения, т.е.: Брал четырехугольник - это 4 вектора V(4). Причем конец каждого вектора смотрит в начало следующего. Направление обхода - против часовой стрелки. Для каждого вектора V: 1) Вычислить вектор U начало которого совпадает с V а конец с искомой точкой. 2) Векторное произведение (U,V) должно быть положитным для всех четырех случаев. Если оно отрицательно, значит точка по правую сторону от вектора V. То есть НЕ ПРИНАДЛЕЖИТ четырехугольнику. Но он явно глючит. Я даже просто сам руками просчитывал и получалось, что точка не принадлежала четырехугольнику, но по координатам должна была принадлежать. Вопрос такой: этот алгоритм применим для любых многоугольников (значит, я все-таки в чем-то ошибся при вычислении) без пересечений или нет (значит надо подальше выбросить эту чушь из головы)? |
volvo |
Сообщение
#26
|
Гость |
Andy
Я никогда не встречал, чтобы этот алгоритм использовали применительно к многоугольникам. Обычно его применяют после триангуляции (разбиения на треугольники) для проверки принадлежности точки к каждому треугольнику. |
Andy |
Сообщение
#27
|
Новичок Группа: Пользователи Сообщений: 23 Пол: Мужской Репутация: 0 |
Да, я тоже не встречал. Мне его порекомендовали и сказали, что он применим для всех многоугольников без пересечений.
Ладно, похоже что более двух дней я потерял попусту |
Флогримм |
Сообщение
#28
|
Бывалый Группа: Пользователи Сообщений: 253 Пол: Мужской Репутация: 4 |
Цитата Какую погрешность ты хочешь вычислить? компьютер представляет число в виде десятичной дроби, поэтому, когда мы вычисляем значение площади или длинны ребра, мы получаем именно такое значение, но ведь часть его сокращается, тем более дробь может быть с периодом и т.д. опоэтому, когда мы будем сравнивать результаты Код flag:= ( S(len(x1,y1,x2,y2),len(x2,y2,x3,y3),len(x3,y3,x1,y1))= S(len(x1,y1,x2,y2),len(x2,y2,x4,y4),len(x4,y4,x1,y1))+ S(len(x2,y2,x3,y3),len(x3,y3,x4,y4),len(x4,y4,x2,y2))+ S(len(x1,y1,x4,y4),len(x4,y4,x3,y3),len(x3,y3,x1,y1)) ); S основного треугольника никогда не будет равна сумме S тех 3х треугольников, которые образуются при соединении четвертой точки и вершин треуголика, поэтому нужно найти погрешность и сравнить как-то по-другому надеюсь понял, что я имею в виду -------------------- Я не буду жить с этой злобой внутри / Я не буду частью смертельной цепи / Я не буду потребителем твоих идей / Я не буду никогда убивать зверей (Unconform)
|
Флогримм |
Сообщение
#29
|
Бывалый Группа: Пользователи Сообщений: 253 Пол: Мужской Репутация: 4 |
Цитата ...Четырехугольники бывают разные. Например, такой (не знаю как прикреплять картинки, поэтому даю в точках) T1(2,2) T2( 4,3) T3(4,6) T4(6,2). По этим точкам построен четырехугольник... когда создаешь тему или отправляешь сообщение на форум просто прикрепляй графическое изображение(с помощью "Прикрепить файл") оно автоматически вставиться в конец сообщения -------------------- Я не буду жить с этой злобой внутри / Я не буду частью смертельной цепи / Я не буду потребителем твоих идей / Я не буду никогда убивать зверей (Unconform)
|
volvo |
Сообщение
#30
|
Гость |
Флогримм
Можно уменьшить погрешность вычисления площадей переходом от типа real(11-12 значащих цифр) к типу extended(19-20 значащих цифр). Хотя практически это ничего не меняет (все вычисления и так ведутся в extended), но если описАть переменные, как extended, то не будет происходить усечение до размеров real (дополнительные 7-8 знаков после запятой добавят точности). Плюс ко всему - real очень медленный тип (он был оптимизирован для работы без сопроцессора, а если сопроцессор имеется, то его использование приведет к преобразованию real->extended, затем вычисления, а после этого - назад: extended->real) Я думаю, точности 19 знаков после запятой должно хватить, тем более, что абсолютной точности добиться невозможно... |
Guest |
Сообщение
#31
|
Гость |
volvo, у меня есть решение к задаче, там написано так:
Код ... flag:= ( 1.000001*S(len(x1,y1,x2,y2),len(x2,y2,x3,y3),len(x3,y3,x1,y1))< S(len(x1,y1,x2,y2),len(x2,y2,x4,y4),len(x4,y4,x1,y1))+ S(len(x2,y2,x3,y3),len(x3,y3,x4,y4),len(x4,y4,x2,y2))+ S(len(x1,y1,x4,y4),len(x4,y4,x3,y3),len(x3,y3,x1,y1)) ); writeln('[',x4,';',y4,'] - ',flag); ... обрати внимание: умножаем на некий коэффициент(почему именно такой?) и прверяем не на равенство, а на то, какая величина больше почему? в упор не понимаю... вот весь код моей проги: Код program tri; uses crt; function len(a1,b1,a2,b2:byte):real; begin len:=sqrt(sqr(a1-a2)+sqr(b1-b2)); end; function S(l1,l2,l3:real):real; var p:real; begin p:=(l1+l2+l3)/2; S:=sqrt(abs(p*((p-l1)*(p-l2)*(p-l3))); end; var x1,x2,x3,x4,y1,y2,y3,y4:byte; flag:boolean; begin clrscr; write('x1,y1> '); readln(x1,y1); write('x2,y2> '); readln(x2,y2); write('x3,y3> '); readln(x3,y3); write('x4,y4> '); readln(x4,y4); flag:= ( 1.000001*S(len(x1,y1,x2,y2),len(x2,y2,x3,y3),len(x3,y3,x1,y1))< S(len(x1,y1,x2,y2),len(x2,y2,x4,y4),len(x4,y4,x1,y1))+ S(len(x2,y2,x3,y3),len(x3,y3,x4,y4),len(x4,y4,x2,y2))+ S(len(x1,y1,x4,y4),len(x4,y4,x3,y3),len(x3,y3,x1,y1)) ); writeln('[',x4,';',y4,'] - ',flag); end. |
Andy |
Сообщение
#32
|
Новичок Группа: Пользователи Сообщений: 23 Пол: Мужской Репутация: 0 |
Кстати, все те кто решает через площадь! Вы находите площадь четырехугольника, предварительно, разделив его на треугольники. Но см. рис. Случай “Г”. Здесь соединяешь диагональ 1 – 3 (или 2 – 4) и находишь площадь треугольника. А вот в случае «А», «Б», «В» такой способ деления на треугольники не подходит. Т.К. для случая «А» верна диагональ только 2 – 4 (а, не 1 – 3),
для случая «Б» верна диагональ только 1– 4 (а, не 2 – 3), для случая «В» верна диагональ только 3– 4 (а, не 1 – 2). Как можно распознавать такие четырехугольники (случаи «А», «Б», «В») Сообщение отредактировано: Andy - Эскизы прикрепленных изображений |
volvo |
Сообщение
#33
|
Гость |
Andy
Цитата Как можно распознавать такие четырехугольники Заметь: «А», «Б», «В» - невыпуклые, т.е. надо проверять на выпуклость... |
Andy |
Сообщение
#34
|
Новичок Группа: Пользователи Сообщений: 23 Пол: Мужской Репутация: 0 |
А именно? Там должно, наверное, свойство выпуклости какое-то существовать. Я что-то не припоминаю.... :p2:
|
volvo |
Сообщение
#35
|
Гость |
Andy
Смотри вот тут... По-моему, алгоритм должен работать, но если не будет - говори, найдем ошибки |
Andy |
Сообщение
#36
|
Новичок Группа: Пользователи Сообщений: 23 Пол: Мужской Репутация: 0 |
Спасибо, всем участникам. Я позавчера все-таки написал эту программу, используя алгоритм от Volvo (мои особые благодарности).
Единственное, что смущает: никак толком полностью не могу уловить смысл этой функции PointInSidebar (алгоритм работы). Буду очень признателен, если подскажите. Вот эта функция: Код Function PointInSidebar(Const SideBar: Array Of TPoint; p: TPoint; Count: Integer): Boolean; Var x1,y1,x2,y2: Double; x0, y0, sum, divisor: Double; i: integer; Begin sum := 0; y0 := p.y; x0 := p.x; For i := 0 to Pred(count-1) do Begin x1:=sidebar[i].x; y1:=sidebar[i].y; x2:=sidebar[i+1].x; y2:=sidebar[i+1].y; divisor:=y1*x2-x1*y2-y0*x2+y0*x1+x0*y2-x0*y1; divisor := divisor + 1.0E-10; Sum := sum + ( -arctan( (-x2*x1+x1*x0+y0*y1-x2*x0+x2*x2-y2*y0+y2*y2-y1*y2 )/divisor)+ arctan( (-x1*x1+x2*x1+x1*x0+y0*y1+y1*y2-x2*x0-y1*y1-y2*y0 )/divisor) ); End; x1:=sidebar[count-1].x; y1:=sidebar[count-1].y; x2:=sidebar[0].x; y2:=sidebar[0].y; divisor:=y1*x2-x1*y2-y0*x2+y0*x1+x0*y2-x0*y1; divisor := divisor + 1.0E-10; Sum := sum + ( -arctan((-x2*x1+x1*x0+y0*y1-x2*x0+x2*x2-y2*y0+y2*y2-y1*y2)/divisor)+ arctan((-x1*x1+x2*x1+x1*x0+y0*y1+y1*y2-x2*x0-y1*y1-y2*y0)/divisor) ); pointinsidebar := not (abs(Sum) < 0.0001) End; Спасибо. |
Текстовая версия | 11.01.2025 15:48 |