WikiSort.ru - Не сортированное

ПОИСК ПО САЙТУ | о проекте

Алгоритм Лианга — Барски — алгоритм, используемый в компьютерной графике для отсечения отрезков в некоторой прямоугольной области. Был разработан Ю-Донг Лиангом[en] и Брайаном Барски[en] в 1984 году[1] и усовершенствован в 1992 году[2]. Данный алгоритм использует параметрическое представление линии и неравенства для определения того, какая часть отрезка попадает в заданную прямоугольную область.

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

Рассмотрим обычную параметрическую форму отрезка:

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

Точка линии находится в окне, если:

Разбивая каждое из неравенств на два, получаем неравенства для четырёх сторон окна:

где

(левая граница окна)
(правая граница окна)
(верхняя граница окна)
(нижняя граница окна)

Правила для вычисления отсечённого отрезка:

  1. Для линии, параллельной границе окна, для неравенства этой границы.
  2. Если для данного , , то линия находится вне рассматриваемой области и не должна быть изображена.
  3. Если , то линия ориентирована с невидимой части области на видимую, и, если , то линия ориентирована с видимой части области в невидимую.
  4. Для ненулевого , даёт точку пересечения границы и искомой линии.
  5. Для каждой границы вычисляем и .
    1. Для , отбираем те границы, в которых (то есть ориентирована с невидимой части области на видимую). Выбираем как наибольшее из .
    2. Для , отбираем те границы, в которых (то есть линия ориентирована с видимой части области в невидимую). Выбираем как наименьшее из .
    3. Если , то линия находится вне рассматриваемой области и не должна быть изображена.

Реализация на языке C++

Ниже представлена реализация алгоритма на языке C++ с использованием библиотеки winbgim:

// Алгоритм Лианга-Барски отсечения отрезка
#include<iostream>
#include<math.h>
#include<graphics.h>

using namespace std;

// Функция, возвращающая минимум в массиве
float mini(const float arr[], int n) {
    float m = 0;
    for (int i = 0; i < n; ++i)
        if (m < arr[i])
            m = arr[i];
    return m;
}

// Функция, возвращающая максимум в массиве
float maxi(const float arr[], int n) {
    float m = 1;
    for (int i = 0; i < n; ++i)
        if (m > arr[i])
            m = arr[i];
    return m;
}

void liang_barsky_clipper(float xmin, float ymin, float xmax, float ymax,
                          float x1, float y1, float x2, float y2) {
    // Объявление переменных
    float p1 = -(x2 - x1);
    float p2 = -p1;
    float p3 = -(y2 - y1);
    float p4 = -p3;

    float q1 = x1 - xmin;
    float q2 = xmax - x1;
    float q3 = y1 - ymin;
    float q4 = ymax - y1;

    float posarr[5], negarr[5];
    int posind = 1, negind = 1;
    posarr[0] = 1;
    negarr[0] = 0;

    rectangle(int(round(xmin)), int(round(467 - ymin)), int(round(xmax)),
              int(round(467 - ymax))); // Рисование отсекающего окна

    if ((p1 == 0 && q1 < 0) || (p3 == 0 && q3 < 0)) {
        outtextxy(80, 80, "Line is parallel to clipping window!");
        return;
    }
    if (p1 != 0) {
        float r1 = q1 / p1;
        float r2 = q2 / p2;
        if (p1 < 0) {
            negarr[negind++] = r1; // При отрицательном p1, добавляем r1 к отрицательному массиву
            posarr[posind++] = r2; // и добавляем r2 к положительному массиву
        } else {
            negarr[negind++] = r2;
            posarr[posind++] = r1;
        }
    }
    if (p3 != 0) {
        float r3 = q3 / p3;
        float r4 = q4 / p4;
        if (p3 < 0) {
            negarr[negind++] = r3;
            posarr[posind++] = r4;
        } else {
            negarr[negind++] = r4;
            posarr[posind++] = r3;
        }
    }

    float xn1, yn1, xn2, yn2;
    float rn1, rn2;
    rn1 = maxi(negarr, negind); // Максимум отрицательного массива
    rn2 = mini(posarr, posind); // Минимум положительного массива

    if (rn1 > rn2) { // Отклоняем
        outtextxy(80, 80, "Line is outside the clipping window!");
        return;
    }

    xn1 = x1 + p2 * rn1;
    yn1 = y1 + p4 * rn1; // Вычисляем новые точки

    xn2 = x1 + p2 * rn2;
    yn2 = y1 + p4 * rn2;

    setcolor(CYAN);

    line(int(round(xn1)), int(round(467 - yn1)), int(round(xn2)), int(round(467 - yn2))); // Рисование новой линии

    setlinestyle(1, 1, 0);

    line(int(round(x1)), int(round(467 - y1)), int(round(xn1)), int(round(467 - yn1)));
    line(int(round(x2)), int(round(467 - y2)), int(round(xn2)), int(round(467 - yn2)));
}

int main() {
    cout << "\nLiang-Barsky line clipping";
    cout << "\nThe system window outlay is: (0,0) at bottom left and (631, 467) at top right";
    cout << "\nEnter the co-ordinates of the window(wxmin, wxmax, wymin, wymax):";
    float xmin, xmax, ymin, ymax;
    cin >> xmin >> ymin >> xmax >> ymax;
    cout << "\nEnter the end points of the line (x1, y1) and (x2, y2):";
    float x1, y1, x2, y2;
    cin >> x1 >> y1 >> x2 >> y2;

    int gd = DETECT, gm;

    // Инициализация графического режима
    initgraph(&gd, &gm, "");
    liang_barsky_clipper(xmin, ymin, xmax, ymax, x1, y1, x2, y2);
    getch();
    closegraph();
}

Другие алгоритмы отсечения отрезков

Примечания

  1. Liang, Y. D., and Barsky, B., «A New Concept and Method for Line Clipping», ACM Transactions on Graphics, 3(1):1-22, January 1984
  2. Liang, YD, BA, Barsky, and M. Slater, Some Improvements to a Parametric Line Clipping Algorithm, CSD-92-688, Computer Science Division, University of California, Berkeley, 1992.

Ссылки

Данная страница на сайте WikiSort.ru содержит текст со страницы сайта "Википедия".

Если Вы хотите её отредактировать, то можете сделать это на странице редактирования в Википедии.

Если сделанные Вами правки не будут кем-нибудь удалены, то через несколько дней они появятся на сайте WikiSort.ru .




Текст в блоке "Читать" взят с сайта "Википедия" и доступен по лицензии Creative Commons Attribution-ShareAlike; в отдельных случаях могут действовать дополнительные условия.

Другой контент может иметь иную лицензию. Перед использованием материалов сайта WikiSort.ru внимательно изучите правила лицензирования конкретных элементов наполнения сайта.

2019-2025
WikiSort.ru - проект по пересортировке и дополнению контента Википедии