ППЛГ и РСДС (PSLG и DCEL): определение, построение РСДС множества прямых — различия между версиями
Igorjan94 (обсуждение | вклад) м (→Построение РСДС множества прямых) |
Tiss93 (обсуждение | вклад) |
||
Строка 13: | Строка 13: | ||
==РСДС== | ==РСДС== | ||
− | === | + | ===Формальное описание=== |
Реберный список с двойными связями особенно удобен для представления ППЛГ. | Реберный список с двойными связями особенно удобен для представления ППЛГ. | ||
Пусть задан граф <tex>G = (V, E)</tex>, <tex>V = \{v_1, v_2... v_n\}</tex>, а <tex>E = \{e_1, e_2... e_n\}</tex>. Главная компонента РСДС для планарного графа это ''реберный узел''. Между ребрами графа и реберными узлами РСДС существует взаимно однозначное соответствие, т.е. каждое ребро представлено в РСДС ровно один раз. Реберный узел РСДС, соответствующий ребру графа, например, <tex>e_k = \{v_1, v_2\} </tex> имеет 4 поля (<tex>V1, V2, F1, F2</tex>) и 2 указателя (<tex>P1, P2</tex>). Поле <tex>V1</tex> содержит начало ребра, а поле <tex>V2</tex> содержит его конец (так изначально неориентированное ребро получает условную ориентацию). Поля <tex>F1</tex> и <tex>F2</tex> содержат имена граней, лежащих слева и справа от ориентированного ребра (<tex>v_1, v_2</tex>). Указатель <tex>P1</tex> (соответственно <tex>P2</tex>) задает реберный узел, содержащий первое ребро, встречаемое вслед за ребром (<tex>v_1, v_2</tex>), при повороте от него против часовой стрелки вокруг <tex>v_1</tex> (соответственно <tex>v_2</tex>). | Пусть задан граф <tex>G = (V, E)</tex>, <tex>V = \{v_1, v_2... v_n\}</tex>, а <tex>E = \{e_1, e_2... e_n\}</tex>. Главная компонента РСДС для планарного графа это ''реберный узел''. Между ребрами графа и реберными узлами РСДС существует взаимно однозначное соответствие, т.е. каждое ребро представлено в РСДС ровно один раз. Реберный узел РСДС, соответствующий ребру графа, например, <tex>e_k = \{v_1, v_2\} </tex> имеет 4 поля (<tex>V1, V2, F1, F2</tex>) и 2 указателя (<tex>P1, P2</tex>). Поле <tex>V1</tex> содержит начало ребра, а поле <tex>V2</tex> содержит его конец (так изначально неориентированное ребро получает условную ориентацию). Поля <tex>F1</tex> и <tex>F2</tex> содержат имена граней, лежащих слева и справа от ориентированного ребра (<tex>v_1, v_2</tex>). Указатель <tex>P1</tex> (соответственно <tex>P2</tex>) задает реберный узел, содержащий первое ребро, встречаемое вслед за ребром (<tex>v_1, v_2</tex>), при повороте от него против часовой стрелки вокруг <tex>v_1</tex> (соответственно <tex>v_2</tex>). | ||
[[Файл:DCEL4.png|300px|thumb|right|Ко второму описанию]] | [[Файл:DCEL4.png|300px|thumb|right|Ко второму описанию]] | ||
− | === | + | ===Неформальное описание=== |
РСДС состоит из 3 компонент: | РСДС состоит из 3 компонент: | ||
*''Vertex'' {{---}} это точка сочленения. Содержит координаты точки. А также указатель на инцидентное ребро. | *''Vertex'' {{---}} это точка сочленения. Содержит координаты точки. А также указатель на инцидентное ребро. | ||
Строка 86: | Строка 86: | ||
==См. также== | ==См. также== | ||
− | [http://cs.stackexchange.com/a/18167 | + | [http://cs.stackexchange.com/a/18167 Источник.] |
Версия 21:38, 10 марта 2014
ППЛГ — Плоский прямолинейный граф.
РСДС — Реберный список с двойными связями.
Содержание
ППЛГ
Планарный граф, уложенный на плоскости, принято называть плоским. Плоская укладка планарного графа — это отображение каждой вершины из в точку на плоскости, а каждого ребра из в простую линию, соединяющую пару образов концевых вершин этого ребра так, чтобы образы ребер пересекались только в своих концевых точках. Хорошо известно, что любой планарный граф можно уложить на плоскости так, чтобы все ребра отобразились в прямолинейные отрезки.
РСДС
Формальное описание
Реберный список с двойными связями особенно удобен для представления ППЛГ. Пусть задан граф
, , а . Главная компонента РСДС для планарного графа это реберный узел. Между ребрами графа и реберными узлами РСДС существует взаимно однозначное соответствие, т.е. каждое ребро представлено в РСДС ровно один раз. Реберный узел РСДС, соответствующий ребру графа, например, имеет 4 поля ( ) и 2 указателя ( ). Поле содержит начало ребра, а поле содержит его конец (так изначально неориентированное ребро получает условную ориентацию). Поля и содержат имена граней, лежащих слева и справа от ориентированного ребра ( ). Указатель (соответственно ) задает реберный узел, содержащий первое ребро, встречаемое вслед за ребром ( ), при повороте от него против часовой стрелки вокруг (соответственно ).Неформальное описание
РСДС состоит из 3 компонент:
- Vertex — это точка сочленения. Содержит координаты точки. А также указатель на инцидентное ребро.
- Face — содержит указатель на наружную компоненту (некоторое ребро на его границе). Для неограниченных поверхностей это nil. Так же содержит внутреннюю компоненту, которая есть указатель на некое ребро, с которого можно начать описывать внутреннюю область (опять же, может быть nil).
- Half-edge — это ребро. Содержит указатели на точку, откуда исходит (origin), указатель на ребро близнец (twin)(направленное в другую сторону), инцидентную поверхность (incident_face), и указатели на следующее и предыдущие ребра.
struct vertex { x, y; half_edge *rep; /* rep->origin == this */ };
struct face { outer_component *out; inner_components *in; (список какой-нибудь) };
struct half_edge { half_edge *prev; /* prev->next == this */ half_edge *next; /* next->prev == this */ half_edge *twin; /* twin->twin == this */ vertex *origin; /* twin->next->origin == origin && prev->twin->origin == origin */ face *incident_face; /* prev->incident_face == incident_face && next->incident_face == incident_face */ };
Построение РСДС множества прямых
У нас есть множество прямых. Мы хотим представить это множество в виде РСДС.
Будем добавлять прямые по одной. Изначально у нас есть фэйс, который представляет собой всю плоскость. Алгоритм будет такой:
- Локализовать рандомную точку прямой в face
- Найти half-edge'и, которые пересекает эта прямая(их будет не больше 2, если считать пересечение в точке за одно ребро)
- Разбить текущий face на два face1 и face2
- Если пересечение не в точке, разбиваем ребра на два — a, b и c, d, так как пересечения два
- Создаем два half-edge — отрезок прямой, попадающий в фэйс
- Перекидываем ссылки этих half-edgeй как надо
- Не забываем поменять у half-edgeй исходного face поле incident_face на face1 и face2 соответственно
- Мы знаем куда(в какие фэйсы — edge->twin->incident_face) пошла наша прямая. Запускаемся от них и разбиваем их аналогично. Если пересечение было в точке, перебираем faceы(next_face = edge->prev->twin->incident_face), пока не найдем нужный. Если фэйс бесконечный — идем только в одну сторону
Вот эти ссылки надо не забыть поменять:
half_edge1->origin = A; half_edge2->origin = B; half_edge1->twin = half_edge2; half_edge2->twin = half_edge1; half_edge1->incident_face = face1; half_edge2->incident_face = face2; half_edge1->next = b; b->prev = half_edge1; half_edge1->prev = d; d->next = half_edge1; half_edge2->next = c; c->prev = half_edge2; half_edge2->prev = a; a->next = half_edge2;