Казахстан |
Заполнение многоугольников и областей
Алгоритм со списком активных ребер
Попробуем несколько видоизменить предыдущий алгоритм. Вместо того чтобы хранить в памяти точки пересечения контура с каждой строкой растра, ограничимся лишь одной строкой - текущей. А именно, организуем список "активных" ребер (САР), в котором будем хранить информацию обо всех ребрах многоугольника, пересекаемых текущей строкой. Удобство такого подхода в том, что при переходе к новой строке не требуется полностью переформировывать САР. Достаточно лишь удалить из него "закончившиеся" ребра (то есть ребра из САР, чей нижний конец оказался выше нового значения y ) и добавить вновь появившиеся.
Перейдем к формальному описанию алгоритма. Для каждого ребра создадим структуру данных:
![y = \lceil y_1 \rceil;](/sites/default/files/tex_cache/2e927efdf6be9f176c298b60d5ce557f.png)
![dx =\frac{x_2 - x_1}{y_2 - y_1};](/sites/default/files/tex_cache/796b2e2bf81e9c95511e8540e991bc3b.png)
![x = x_1 + dx \cdot (y - y_1).](/sites/default/files/tex_cache/8a96b0605cb50a9afe46cefcab29e122.png)
Все такие структуры поместим в список (далее - y-список) и упорядочим его по возрастанию y.
САР = пустой; y = y_список[ первый элемент ].y; do { САР.Добавить( ребра из y-списка, у которых ребро.y = y); // сохраняя упорядоченность САР по возрастанию x y_список.Удалить( ребра, у которых ребро.y = y ); Закрасить промежутки ( x_2i - 1, x_2i ) в строке y; y++; foreach( ребро из САР по порядку ) { if(y > ребро.y2) удалить ребро из САР; else { ребро.x += ребро.dx; while(соседнее_слева_ребро(ребро).x > ребро.x) поменять местами в САР ребро с соседним; } } } while(САР не пуст);Листинг 6.2. Растеризация с САР
Ребра, помещенные в САР, удаляются из y-списка с той целью, чтобы свести проверку наличия в y-списке ребер, начинающихся с данного уровня y, к проверке этого условия для первого ребра в списке (это справедливо в силу упорядоченности списка). Цикл while используется для сохранения упорядоченности САР, которая может нарушиться при изменении значений x на dx.
Пример такой ситуации показан на рис. 6.3. При ее возникновении указанный цикл выполняет локальную сортировку САР методом "пузырька".
Преимущество двух приведенных алгоритмов перед последующими состоит в том, что операции вывода на экран (относительно "медленные" во многих системах) для каждого пикселя выполняются не более одного раза. Недостатком является использование динамических структур данных (списков), что сильно усложняет код и требует дополнительной памяти.
Существует класс систем, в которых использование динамических структур данных нежелательно (вследствие ограниченности ресурса памяти или отсутствия удобных средств разработки программ), в то время как замедление работы из-за частого обращения к видеопамяти некритично (сюда относятся, например, мобильные телефоны и другие портативные устройства, имеющие графический дисплей). В таких системах эффективным будет использование следующих алгоритмов, оперирующих непосредственно с данными в видеобуфере (то есть с "содержимым" экрана).