![]() |
|
|
![]()
|
|
| dr.ZmeY |
|
||||||
|
Политолог ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 3892 Регистрация: 26.3.2002 Где: ..::STALINGRAD::. . Репутация: нет Всего: 60 |
Попробую изложить алгоритм... Просто мозги уже кипят и отказываются работать... Чем дальше углубляюсь в проект, тем хуже, возникает куча задач, доселе мною не решённых, и от наступания на грабли - уже лоб весь в шишках
ЗАДАЧА Имеется 3D тело (замкнутая поверхность), состоящее из полигонов (кусочков/треугольников) с координатами углов x1[i] y1[i] z1[i], x2[i] y2[i] z2[i], x3[i] y3[i] z3[i] ( где i - номер полигона). Необходимо определить, точка простарнстава с координатами x0 y0 z0 находится внутри тела (замкнутой поверхности) или вне его... ====== ОБЩАЯ ТЕОРИЯ (научное обоснование Предполагаю, что если провести от этой точки (назовём её P) луч (L) в любую сторону, то, если он будет иметь чётное число пересечений с многогранником М, то это значит, что точка Р лежит вне объекта М, в противном случае - она внутри него, т.е. принадлежит ему и имеет нечётное число пересечений. Луч из точки Р наиболее удобно пускать параллельно какой-либо координате, скажем y... Т.е. имеем луч L (x>x0, y=y0, z=z0). Однако, решать задачу пересечения луча и ограниченной треугольником плоскости - трудоёмко, стоит упростить до пересечения полуплоскости (П) и граней многогранника. Как я сказал, точка Р лежит внутри многогранника, если луч, исходящий из Р, пересекает нечётное число его граней. Прямая L пересекается с многогранником, если она имеет непустое пересечение с какой-либо из его граней. Проведём через луч L плоскость, этот луч делит её на 2 части, вот одна из них и есть полуплоскость П (x>x0, y>y0, z=z0). Есои полуплоскость П не проходит через вершины многогранника М, то прямая L не пересекает этот многогранник тогда и только тогда, когда для каждой грани М полуплоскость П пересекает чётное (0,2,4,6,...) число её рёбер... Так проще, т.к. оперируем одновременно в 3 раза меньшим числом координат, и алгоритм работает быстрее, нежели, если сравнивать луч и грань. попробую изобразить теперь алгоритм, пока что пересечения прямой L и многогранника М: Просматриваем рёбра М, и с ними проводим тест на пересечение с полуплоскостью П. Если ребро и полуплоскость имеют общую точку, то в счётчике граней, которым ребро принадлежит, прибавляется 1 (предварительно счётчик - массив, имеющий ту же размерность, что и список граней, - обнуляется). Если после просмотра всех рёбер хотя бы в одном из счётчиков нечётное число, то L и М пересекаются. Основным в данном алгоритме является тест на пересечение ребра (отрезка) и полуплоскости. Массив координат может быть задан любым способом, это может быть и сплошной массив, где каждые три члена - три координаты узла грани многогранника, а т.к. грань - треугольник, то каждые 9 членов - это грань. Может быть задан списком TList, где каждый член - это x, y, z: GLFloat, как удобно... хоть тремя массивами... Структура многогранника задаётся массивом S рамерности 4*Е, где Е - число рёбер. Здесь S[1, i] и S[2, i] - номера вершин многогранника, являющиеся концами i-го ребра, а S[3, i] и S[4, i] - номера граней, для которых i-е ребро является общим. F - число граней, = V div 3, где V - список, и = V div 9 где V - массив координат (в зависимости от того, как представлять массив, писал выше)... IND[i] = счётчик. Т.е. имеем нечто (Листинг №1):
Теперь, основная задача - принадлежность точки Р многограннику М. Как известно из вышесказанного вот теперь, я подошёл и к алгоритму нахождения решения принадлежности точки к многограннику Сначала проводим тест на пересечение граничных плоскостей Пk и луча L, формируем список признаков INTR(k), где INTR(k):= -1, если пересечения нет, INTR(k):= 0, если Пk пересекает L вблизи точки Р (точность задаётся), и INTR(k):= 1, если пересечение есть. Далее просматриваются рёбра М и , если встречается ребро Еk, у которого только одна из плоскостей Пkj пересеккается с L, проводится тест на пересечение Ek и П. Если пересечение есть, то ребро - отмечается. Подсчитав число отмеченных рёбер (можно брать сумму по mod 2) и определив чётность, выясняется, лежит точка Р вне или внутри М. Тест на пересечение Пk и L примерно так: если уравнение плоскости Пk - следующее x=Bk*y + Ck*z + Dk (такая форма записи всегда возможна, если только L и Пk - непараллельны, а если же они параллельны, то пересечения нет), то L и Пk пересекаются, когда Bk*y0 + Ck*z0 + Dk > x0. Коэффициенты уравнения плоскости, как правило, несложно определить при любом способе многогранника, а по трём точкам (треугольник) плоскость определяется через матрицу. Важно знать, лежит ли Р вблизи границы М с точностью до некоторого числа W. Для граней, у которых INTR(k)=0 нужно завести отдельный счётчик. В случае если ребро пересекается с П и является стороной Fk, прибавить к счётчику Fk единицу. Если на выходе в каком-то из счётчиков - нечет, то Р лежит на этой грани. Добавим к прошлым переменным ещё пару... FP - массив размера 4*F коэффициентов плоскостей, проходящих через грани М. Вот, примерно что должно получиться... (Листинг №2)
SemplaneSegment(П, S[1, i], S[2, i]); - тест на пересечение ребра и полуплоскости. Тут нужно подробнее... Будем рассматривать сучай, когда полуплоскость - суть верхняя полуплоскость 0XY, остальные случаи приводятся к этому вращением пространства. (достаточно 3 вращения вокруг координатных осей, чтобы совместить две полуплоскости) Итак, у нас полуплоскость П: z=z0, y>y0 и ребро Е, задаваемое координаными вершинами V1(x1,y1,z1) и V2(x2,y2,z2). Сопоставим каждой вершине Vi код Сi = 0, 1, 2, 3 по следующему правилу:
Е и П пересекаются, если один из кодов вершин = 0, а другой 3, и могут пересекаться, если С2 = С1 + 2 (mod 4), т.е. (С1, С2) = (0, 2); (2, 0); (1, 3); (3, 1). В остальных случаях - пересечения заведомо нет. Это ж, готовая статья.. нужен только код... У меня мозг полностью отключен... |
||||||
|
|||||||
| Alex |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 4147 Регистрация: 25.3.2002 Где: Москва Репутация: нет Всего: 162 |
Модератор: Название темы должно отражать ее суть!
-------------------- Написать можно все - главное четко представлять, что ты хочешь получить в конце. |
|||
|
||||
| Quadr0 |
|
|||
|
Unregistered |
...
Это сообщение отредактировал(а) Quadr0 - 14.7.2011, 22:45 |
|||
|
||||
| dr.ZmeY |
|
|||
|
Политолог ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 3892 Регистрация: 26.3.2002 Где: ..::STALINGRAD::. . Репутация: нет Всего: 60 |
Скажем так, фигура представляет собой стокан Добавлено @ 16:06 |
|||
|
||||
| Quadr0 |
|
|||
|
Unregistered |
...
Это сообщение отредактировал(а) Quadr0 - 14.7.2011, 22:45 |
|||
|
||||
| dr.ZmeY |
|
|||
|
Политолог ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 3892 Регистрация: 26.3.2002 Где: ..::STALINGRAD::. . Репутация: нет Всего: 60 |
А что, толщина стенок =0? Я об этом не говорил, я сказал "Тело", и "замкнутая поверхность"... Т.е. твой вариант - окажись точка внутри стакана, он покажет её принадлежность ему.... Что в корне не верно. |
|||
|
||||
| Quadr0 |
|
|||
|
Unregistered |
...
Это сообщение отредактировал(а) Quadr0 - 14.7.2011, 22:45 |
|||
|
||||
| dr.ZmeY |
|
||||||||||
|
Политолог ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 3892 Регистрация: 26.3.2002 Где: ..::STALINGRAD::. . Репутация: нет Всего: 60 |
По порядку:
Имеем массив вершин в виде списка, задаём его глобально.
Каждая его запись - это (xi, yi, zi) т.к. каждая грань у нас - это треугольник, то считывать массив нужно сразу по три записи:
Чтобы не было иллюзий по поводу объекта - вот разложенный массив (частично, т.к. целиком - оооочень много) очень простого, очень маленького объекта:
Хмммм... Т.е. тут имеем задачу, пересечения отрезка с полуплоскостю. Повторюсь, для каждой вершины ребра задаём коды Сi...
Попробую изобразить алгоритм:
Должно быть нечто подобное... Почему именно такой алгоритм я выбрал, потому что до этого я пытался рассчитать телесный угол. Цикл по всем узлам и рассчитывал телесный угол со всеми гранями ( треугольниками ) тела. Если этот угол равен 4Пи, то узел находится внутри, в противном случае снаружи. Но такой алгоритм работал 12 часов (при том, что у процесса стоял максимальный приоритет)... После чего вешал систему... Очень неопртимальный вариант... Этот должен на порядок быстрее работать. У меня в системе до 10 миллионов узлов. |
||||||||||
|
|||||||||||
| dr.ZmeY |
|
||||
|
Политолог ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 3892 Регистрация: 26.3.2002 Где: ..::STALINGRAD::. . Репутация: нет Всего: 60 |
И от куда ты знаешь, какая х левая, а какая правая?
Не факт... возможно кольцо... дело в том, что многогранник может быть абсолютно любым правильным многогранником... Это может быть даже 2 или три многогранника не соприкасающиеся или соприкасающиеся друг с другом... |
||||
|
|||||
| Albinos_x |
|
|||
![]() Evil Skynet ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 3288 Регистрация: 28.5.2004 Где: X-6120400 Y-1 4624650 Репутация: нет Всего: 108 |
мда... интересный способ...
а через вектора реализовать не пробовали... -------------------- "Кто владеет информацией, тот владеет миром" Уинстон Черчилль |
|||
|
||||
| Daemon05 |
|
|||
|
Новичок Профиль Группа: Участник Сообщений: 18 Регистрация: 26.5.2005 Репутация: нет Всего: 3 |
Могу предложить следующий оригинальны алгоритм.
Окружаем фигуру кубом(не обязательно соприкасающимся, лишь бы вся фигура поместилась в куб) 1. Точку отмечаем флагом 1 2. От нее проверяем все соседние точки на предмет того не пересеклись ли они с кубом, если пересеклись, то точка наружняя, если нет, то отмечаем ее флагом 1. 3. Рекурсивно от полученных точек проверяем все ближайшие точки, которые не имеют флага 1 и повторяем до исчерпания всех точек. Если так никто с кубом и не пересекся, то точка внутри Набросок function Naruzhnyaya(x,y,z:integer):boolean; var b:boolean; begin b:=false; if PereseklasSFiguroy(x,y,z)=1 then flag[x,y,z]=1; if flag[x,y,z]=1 then else begin flag[x,y,z]=1; if PereseklasSKubom(x,y,z) then b=true else b:=Naruzhnyaya(x-1,y,z0) or Naruzhnyaya(x+1,y,z) or Naruzhnyaya(x,y-1,z) or Naruzhnyaya(x1,y+1,z) or Naruzhnyaya(x,y,z-1) or Naruzhnyaya(x,y,z+1) or Naruzhnyaya(x+1,y+1,z) or Naruzhnyaya(x-1,y+1,z) or Naruzhnyaya(x+1,y-1,z) or Naruzhnyaya(x-1,y-1,z) or Naruzhnyaya(x,y+1,z+1) or Naruzhnyaya(x,y-1,z+1) or Naruzhnyaya(x,y+1,z-1) or Naruzhnyaya(x,y-1,z-1) or Naruzhnyaya(x+1,y,z+1) or Naruzhnyaya(x+1,y,z+1) or Naruzhnyaya(x+1,y,z-1) or Naruzhnyaya(x-1,y,z+1) or Naruzhnyaya(x-1,y,z-1) or Naruzhnyaya(x+1,y+1,z+1) or Naruzhnyaya(x+1,y+1,z-1) or Naruzhnyaya(x+1,y-1,z+1) or Naruzhnyaya(x+1,y-1,z-1) or Naruzhnyaya(x-1,y+1,z+1) or Naruzhnyaya(x-1,y+1,z-1) or Naruzhnyaya(x-1,y-1,z+1) or Naruzhnyaya(x-1,y-1,z-1); end; Naruzhnyaya:=b; end; На пальцах логика алгоритма похожа на фильм ужасов, из точки равномерно распространяется во все стороны некая жуткая субстанция заполняя все флагом 1, единственное, что ее может остановить это стенки фигуры или стенки куба, соответсвенно если точка внутри, то субстанция не дойдет до куба, заполнив только внутренность фигуры. |
|||
|
||||
| Quadr0 |
|
|||
|
Unregistered |
...
Это сообщение отредактировал(а) Quadr0 - 15.7.2011, 00:38 |
|||
|
||||
| dr.ZmeY |
|
||||||||
|
Политолог ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 3892 Регистрация: 26.3.2002 Где: ..::STALINGRAD::. . Репутация: нет Всего: 60 |
Quadr0, OpenGL тут не причём, да хоть Direct3D... Какая разница... Это же математика, а не графика... Ведь фигуру можно просчитывать, не рисуя её... а представив в виде массива её вершин...
Daemon05, попробуем разобрать то, что ты предлагаешь...
Это понятно... просто ограничиваем пространство вокруг многогранника.
Пусть..
Как точка может с чем-нибудь пересечься? Она же точка! Да и предстваь, что создаётся конечноразнстная сетка 1000000х1000000х1000000 узлов, т.е. это габариты куба.
По любому нужно определить, не то, что точка внутри, или нет куба, а фигуры, сложного многогранника. |
||||||||
|
|||||||||
| dr.ZmeY |
|
|||
|
Политолог ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 3892 Регистрация: 26.3.2002 Где: ..::STALINGRAD::. . Репутация: нет Всего: 60 |
А мне непонятно... По какой такой причине это перенесено в раздел "Delphi: Звук, графика и видео"?
|
|||
|
||||
| Daemon05 |
|
|||
|
Новичок Профиль Группа: Участник Сообщений: 18 Регистрация: 26.5.2005 Репутация: нет Всего: 3 |
Этот алгоритм не обязан работать в 2D. В доказательство возьми виток толстой спирали, точка в центре, по твоему алгоритму она получается внутри Прошлый алгоритм явно не годится для таких размеров. Попробуем методы аналитической геометрии. Есть еще метод, но тяжело объяснить без рисунков и чертежей Теория: У каждого треугольника есть три других треугольника, с которыми он имеет общую сторону. 1. Сориентируем поверхность, для этого к каждому треугольнику дадим нормаль, направление которой для первого треугольника выбирается произвольно, допустим обходя контур по часовой стрелке и проводя нормаль буравчиком. Для остальных треугольников нормаль выбирается следующим образом. Допустим мы обошли произвольно треугольник ABC, причем в направлении по контуру от A к B, от B к C, от C к A . Тогда треугольник BCD обходим в направлении C>B>D, аналогично соседний к нему треугольник обходим в направлении D>B>E и т.д. Получаем в памяти набор нормалей, количество которых равно количеству треугольников. 2. Возьмем очевидно наружную точку. Допустим возьмем для этого далекую точку. Ищем ближайшую вершину треугольника. Находим ее. Проводим вектор в направлении от вершины до точки и скалярно множим на вектор найденной в п.1. нормали любого из трех треугольников, которому принадлежит эта ближайшая точка. Что получилось при этом умножении неважно - главное знак - плюс или минус. Допустим плюс. 3. Вот и все. Теперь чтобы определить наружность любой точки, просто находим ближайшую к этой точке вершину, проводим вектор в направлении от ближайшей вершины до точки и скалярно множим этот вектор на нормаль любого из трех треугольников которым принадлежит эта вершина. Опять же интересен только знак если плюс - точка снаружи, если минус то внутри. Преимуществалгоритма простота и скорость - ведь пункт 1 и 2 надо выполнить всего один раз, а пункт 3 потом сколько угодно для любой точки. Не знаю поняли ли вы чего из сказанного выше Тот же алгоритм на пальцах: 1. Мы просто раскрашиваем внутренние стороны каждого треугольника в черный цвет, а наружние в красный. При этом не забываем, что можем ошибится и раскрасить наоборот внутренность треугольников в красный а наружность в черный. 2. Теперь смотрим на ближайший треугольник от явно наружней точки и определяем красного или черного цвета стенку мы видим. Допустим черный - ура, значит наружняя сторона покрашена черным 3. Теперь от нужной нам точки смотрим на ближайший треугольник. Если видим черный цвет то точка внутри фигуры если красный, то снаружи. И совсем на пальцах: Если вас посадить в коробку черного цвета, но при этом обитую внутри красным, то увидев красный цвет вы догадаетесь что находитесь внутри Это сообщение отредактировал(а) Daemon05 - 13.7.2005, 02:53 |
|||
|
||||
![]()
|
| Правила форума "Алгоритмы" | |
|
|
Форум "Алгоритмы" предназначен для обсуждения вопросов, связанных только с алгоритмами и структурами данных, без привязки к конкретному языку программирования и/или программному продукту.
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, maxim1000. |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | Алгоритмы | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |