Лекция 16 Вычислительная геометрия

Post on 11-Feb-2017

100 views 4 download

Transcript of Лекция 16 Вычислительная геометрия

Анализ комбинаторных алгоритмов

Лекция № 16Вычислительная геометрия

Аффинные преобразования

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

X* = x cos - y sin , Y* = x sin + y cos . Растяжение (сжатие) вдоль координатных осей:

X* = x, Y* = y, >0, >0. Отражение (относительно оси абсцисс):

X* = x, Y* = -y. Перенос:

X* = x + , Y* = y + .

Аффинные преобразования

М

М*

М

М*

М*

М

М

М*

Аффинные преобразования

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

X* = x + y + ,Y* = x + y + .

В матричной записи:

100

*)1 (1 **

yxyx

Аффинные преобразования

1000cossin0sincos

R

1000000

][

D

100010001

][M

1010001

][

T

Матрица вращения Матрица растяжения

Матрица отражения Матрица переноса

Термины и определения

Выпуклой комбинацией двух точек p1 (x1,y1), p2(x2,y2) называется любая точка p3(x3,y3), для которой

x3 = x1+(1- )x2, y3 = y1+(1- )y2 Совокупность всех выпуклых комбинаций

для точек p1, p2 называют отрезком p1p2. Если порядок точек p1 и p2 имеет значение,

то отрезок направленный. Направленный отрезок у которого p1 = (0,0)

(начало координат) называется вектором.

Термины и определения

Под векторным произведением на плоскости понимается площадь параллелограмма, образованного точками (0,0), p1, p2, p1+p2 = (x1+x2, y1+y2).

122121

2121 det yxyx

yyxx

pp

1221 pppp

Направление поворота

В какую сторону нужно поворачивать вектор p1,чтобы совместить его с p2 (в смысле наименьшего угла)?Если p1 x p2 положительно, то против часовой стрелки, если отрицательно – то по часовой.

В какую сторону производится поворот при движении по ломанной p0p1p2?Если p1 x p2 положительно, то направо, если отрицательно – то налево, если равно 0, то либо не поворачиваем, либо поворачиваем назад.

Пересечение отрезков

Определение пересечения отрезков происходит в два этапа.

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

Ограничивающим прямоугольником называется наименьший из прямоугольников со сторонами параллельными осям координат, содержащих данную фигуру.

(x2≥x3)Λ(x4≥x1)Λ(y2≥y3)Λ(y4≥y1)

Пересечение отрезков

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

С помощью векторных произведений это проверяется следующим образом:[(p3-p1) x (p2-p1)] * [(p4-p1) x (p2-p1)] ≤ 0

и[(p1-p3) x (p4-p3)] * [(p2-p3) x (p4-p3)] ≤ 0

Пересечение отрезков

Метод движущейся прямой состоит в том, что воображаемая прямая движется слева направо мимо рассматриваемых объектов.

Метод движущейся прямой хранит следующую информацию: Состояние дел у прямой задается

упорядоченным множеством объектов, пересекаемых движущейся прямой.

Расписание представляет собой последовательность моментов времени (критических точек), в которых состояние может измениться

Пересечение отрезков

Состояние дел у прямой хранится как упорядоченное множество отрезков, с которым можно выполнять следующие операции: Insert(s) – добавить отрезок Delete(s) – удалить отрезок Above(s) – указать отрезок располагающийся

непосредственно выше s Below(s) – указать отрезок располагающийся

непосредственно ниже s

Пересечение отрезков

AnySegmentIntersect(S){ T = ǿ; Отсортировать концы отрезков в порядке возрастания абсцисс (если абсциссы равны, то по возрастанию ординат) Проверка совпадений среди концов отрезков for(каждой точки p из S){ if(p – левый конец отрезка){ Insert(s); if(Above(s) существует и пересекает s) ||(Below(s) существует и пересекает s) return TRUE; } if(p – правый конец отрезка){ if(Above(s) существует) ||(Below(s) существует)||(Above(s) пересекает Below(s)) return TRUE; Delete(s);}y }}

Пересечение отрезков

a

b

c

de

f

a ab

acb

cb

dcb

db

edb

edbf

edf

Отыскание пары ближайших точек

Данную задачу можно решить используя метод «разделяй и властвуй».

Входными данными рекурсивного алгоритма являются множество точек P и массивы X и Y, содержащие точки из P. X отсортирован по абсциссам, Y по ординатам.

Если в P находятся только 3 или 2 точки находим расстояния (и сравниваем их попарно).

Отыскание пары ближайших точек

Если |P|>3, находим вертикальную прямую разделяющую P на два подмножества Pl и Pr половинного размера. Разделяем массивы X и Y сохраняя порядок элементов.

Выполняем два рекурсивных вызова и находим пару ближайших точек в Pl и Pr и расстояния между этими точками δl и δr. Полагаем δ = min(δl, δr)

Отыскание пары ближайших точек

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

Для нахождения «приграничной» пары: Создаем Y’, сохранив порядок, с точками

попавшими в приграничную полосу толщиной 2δ Для каждой точки из Y’ находим расстояние от

нее до каждой из 7 точек следующих за ней. Находим наименьшее расстояние δ’ между точками в приграничной зоне.

Отыскание пары ближайших точек

2 δ

δ δ

δ δ

2 точки

Построение выпуклой оболочки

Выпуклой оболочкой конечного множества точек Q (CH(Q)) называется наименьший выпуклый многоугольник, содержащий все точки из Q.

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

Построение выпуклой оболочки

void GrahamScan(Q){ Множество Q отсортировано так, что Q[0]- точка с наименьшей ординатой, а остальные расположены в порядке возрастания полярного угла. Stack S; S->Push(Q[0]); S->Push(Q[1]); S->Push(Q[2]); for(i=3;i<=n;i++){ while(при движении по ломанной S->NextToTop(), S->Top, Q[i] движение происходит прямо или направо) S->Pop() S->Push(Q[i])}}

Построение выпуклой оболочки

p0p1

p2

p3

p4p5

p6

p7 p0p1

p2

p3

p4p5

p6

p7

p0p1

p2

p3

p4p5

p6

p7 p0p1

p2

p3

p4p5

p6

p7

Просмотр Грэхема

Построение выпуклой оболочки

void WrappingScan(Q){ //Q[0] - точка с наименьшей ординатой //Pmax – точка с наибольшей ординатой Pmax = GetMinPoint(Q); i=1; while(Q[i]!=Pmax){ minw = maxint; for(k=1; k<N; k++){ if(k==i) w = maxint; else w = CalculatePolarLeft(Q[i],Q[k]); if(minw>w){p = Q[k]} } Pop(p); i++;} while(Q[i]!=Pmax){ minw = maxint; for(k=1; k<N; k++){ if(k==i) w = maxint; else w = CalculatePolarRight(Q[i],Q[k]); if(minw>w){p = Q[k]} } Pop(p); i++;}}

Построение выпуклой оболочки

p0p1

p2

p3

p4

p5

p6

Проход Джарвиса