Скачиваний:
18
Добавлен:
01.05.2014
Размер:
1.61 Mб
Скачать

Санкт - Петербургский государственный электротехнический университет

Отчет по лабораторной работе

“Разработка программы реализующей алгоритм построения выпуклой оболочки при помощи “мостиков”

Выполнил : Павлов Валентин

Никоноров Александр

Группа: 7382

Преподаватель: Ивановский С.А.

Санкт – Петербург

2002

  1. Теоретические материалы

    1. Описание задачи

В лабораторной работе требуется реализовать «Быстрый алгоритм на основе слияния II (с построением “мостиков”)». Этот алгоритм применятся для вычисления выпуклой оболочкиCH(S)для набора точекS.

    1. Описание метода и алгоритма.

Идея алгоритма заключается в разделении массива Sвоображаемой вертикальной прямой линией на два равных по размеру поднабораsL иsR , затем рекурсивно сформировать из нихCH(sL) иCH(sR)и затем объединить их для образованияCH(S).В конечном счете набор будет состоять из одной точки ( |S| = 1 ) и будет просто возвращаться одноугольник, единственная вершина которого принадлежит наборуS.Эта точка является собственной выпуклой оболочкой.

Алгоритм асимптотически эффективен, поскольку выпуклые оболочки СН (sL) иCH(sR)могут быть эффективно объединены за времяO(|S|). Для выполнения слияния нужно удалить правую цепочкуCH(sL) и левую цепочкуCH(sR) и заменить их на верхний мостик и нижний мостик (рис. 1). Такие мостики обязательно существуют, посколькуCH(sL)иСH(sR)разъединены — они лежат по разные стороны воображаемой прямой линии.

Рис. 1.Слияние двух раздельных выпуклых оболочек

Основные этапы алгоритма:

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

Polygon *mergeHull(Point pts[], int n)

{

Point **p = new (Point*)[n] ;

for (int i = 0; i < n; i++) p[i] = &pts[i] ;

msrgeSort(p, n, leftToRightCmp) ;

return mHull(p, n);

}

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

В функции mHullреализуется рекурсивная часть алгоритма:

Polygon *mHull(Point *p[], int n)

{

if (n == 1) (

Polygon *q = new Polygon;

q->insert(*p[0]) ;

return q ;

} else {

int m = n / 2;

Polygon *L = mHull(p, m) ;

Polygon *R = mHull(p+m, n-m);

returnmerge(L,R) ;

}

}

В конечной ситуации (n= =1) функция mHull возвращает одноугольник. В общем случае функция делит набор точек на левый и правый поднаборы точекp[0..m-1] иp[m..n-l], затем формирует для них выпуклые оболочкиLиRи выполняет слияние полученных двух оболочек.

  • Слияние двух выпуклых оболочек (функция merge(L,R))

Обращение к функции merge(L,R), которая объединяет две выпуклые оболочкиL и R,зависит от способа записи мостика.Касательная прямая линия: прямая линияlбудет касательной прямой линией выпуклого полигонаР,если прямая линияlпроходит через вершину полигонаРи внутренняя часть полигонаРцеликом располагается по одну сторону прямой линииl.Прямая линияlбудет мостиком для выпуклых полигонов Р иQ,еслиlявляется касательной прямой линией для обоихРиQ.Прямая линияlбудет верхним мостиком, если оба полигона расположены ниже прямой линииl,или нижним мостиком — если они оба расположены над прямой линиейl.

Для слияния полигонов LиРнам нужно найти верхний мостик, соединяющий некоторую вершинус некоторой вершиной, а также нижний мостик, соединяющий вершиныи.Вершиныделят границы полигонаLна левую и правую цепочки и, аналогично, вершиныделят границы полигонаRна левую и правую цепочки. Для слиянияL и R в CH(S)нам потребуется заменить правую це­почку полигонаLи левую цепочку полигонаRна верхний и нижний мостики.

Функция mergeопределяет общую выпуклую оболочку для выпуклых полигонов L и R и возвращает ее по завершении работы функции. Предполагается, что полигон L расположен слева от полигона R. ПараметрыUPPERиLOWERимеют тип перечисления:

Polygon *merge(Polygon *L, Polygon *R)

{

Vertex *11, *rl, *12, *r2;

Vertex *vl = leastVertex(*L, rightToLeftCmp);

Vertex *vr = leastVertex(*R, leftToRightCmp);

bridge(L, R, 11, rl, UPPER);

L->setV(vl) ;

R->setV(vr) ;

bridge(L, R, 12, r2, LOWER);

L->setV(ll) ;

L->split(rl) ;

R->setV(r2) ;

delete R->split(12);

returnR;

}

При обращениях к функции leastVertexнаходятся самая правая вершина полигона L и самая левая вершина полигона R.

Две операции splitв функцииmergeосуществляют замену правой цепочки полигона L и левой цепочки полигона R на верхний и нижний мостики. Как это делается, показано на рис.2.

Рис. 2.Слияние выпуклых оболочекLиRс помощью двух операцийsplit

  • Функция bridgeнаходит верхний мостик полигоновL иR.

Функция находит некоторую касательную прямую линию для полигона L, затем для полигона Rи последовательно их проверяет до тех пор, пока не будет найдена одна общая касательная прямая линия, т. е. верхний мостик (рис. 3а). Для этого функцияbridgeсначала размещает окноvlна самой правой вершине полигонаLи окноvrна самой левой вершине полигонаR.

Рис. 3.Последовательность поиска верхнего и нижнего мостиков для двух выпуклых полигонов

Затем она итеративно выполняет следующую группу операций до тех пор, пока нельзя будет переместить ни окно vl,ни окноvr:

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

2.Установить окноvrна вершине полигонаS,которой касается прямая.

3. Найти такую касательную прямую линию к полигонуL,которая располагается выше полигонаLи проходит через вершинуvr.

4. Установить окно vlна вершину полигонаL,которой касается прямая.

Нижний мостик для полигонов LиRнаходится аналогично, только с заменой параметра выше на ниже.На рис. 3 показана последовательность определения касательных прямых линий в процессе поиска верхнего и нижнего мостиков.

Функция bridgeнаходит мостик между выпуклыми полигонамиLиR. Вершины, в которых мостик касается полигоновLиR,возвращаются через ссылочные параметры vl и vr соответственно. Параметрtypeуказывает на тип искомого мостика — верхнегоUPPERили нижнегоLOWER. В функции предполагается, что полигонLнаходится слева от полигонаRи что окно vl первоначально расположено на некоторой вершине правой цепочки полигонаL,а окноvr— на некоторой вершине левой цепочки полигонаR:

void bridge(Polygon *L, Polygon *R,

Vertex* &vl. Vertex* &vr, int type)

{

int sides[2] = { LEFT, RIGHT };

int indx = (type = = UPPER) ? 0 : 1;

do {

vl = L->v() ;

vr = R->v() ;

supportingLine(L->point(), R, sides[indx]);

supportingLine(R->point(), L, sides[1-indx]);

} while ( (vl !=L->v()) || (vr !=R->v()));

}

Функция supportingLine- часть алгоритма ввода оболочки.