на начало
На главную страницу
Форум   

Статья :: Рекурсивное деление

 

Рекурсивное деление

Добавим возможность дальнейшего деления треугольников и образования фигур, приближающихся к сфере. Осуществление предельного перехода возможно в математике непрерывных величин, но невозможно в дискретной математике и тем более в реализациях ее алгоритмов, где все множества должны быть конечными. Однако мы можем применить конечную рекурсию для дальнейшего деления треугольников. Замените функцию split на ее рекурсивную версию. Вы, конечно, помните, что рекурсивная функция вызывает сама себя до тех пор, пока не выполнится некоторое условие. Здесь условием выхода из цепи рекурсивных вызовов является равенство нулю последнего параметра depth, который определяет текущую глубину рекурсии:

void Split(double *vl, double *v2, double *v3,long depth)

{

double v12[3], v23[3], v31[3];

if (depth == 0)

{

//====== Рисование наименьших треугольников

setTria(vl, v2, v3);

//====== и выход из цепи рекурсивных вызовов

return;

}

//====== Разбиение треугольника

for (int i = 0; i < 3; i++)

{

v12[i] = vl[i]+v2[i];

v23[i] = v2[i]+v3[ij;

v31[i] = v3[i]+vl[i];

}

//====== Дотягивание до сферы

Scale(v12);

Scale(v23);

Scale(v31); //====== Рекурсивное разбиение на

//====== четыре внутренних треугольника

Split(vl, v!2, v31, depth-1);

Split(v2, v23, v12, depth-1);

Split(v3, v31, v23, depth-1);

Split(v!2, v23, v31, depth-1);

}

Внесите также изменение в ту строку программы, где происходит вызов Split. Надо добавить параметр, задающий глубину рекурсии. Если функцию вызвать с нулевой глубиной, то получим икосаэдр, если увеличивать глубину, то будем получать фигуры, более близкие к шару:

for (int i = 0; i < 20; i++)

Split (v[id[i) [0]], v[id[i][l]], v[id[i] [2]], 3);

Запустите и проверьте, нажимая клавишу N. Попробуйте изменить глубину рекурсии, только не переусердствуйте. Если задать глубину более 10, то можно не дождаться ответа. Рекурсия дорого стоит, поэтому исследованный подход абсолютно неприемлем для создания сферы. Аналогичный вывод справедлив для других объемных изображений, создаваемых с помощью задания вершин большого числа геометрических примитивов.

В данный момент для иллюстрации процесса приближения изображаемой фигуры к сфере напрашивается такой сценарий: пользователь нажимает клавишу — пробел, глубина рекурсии изменяется и изображение пересчитывается. Алгоритм управления глубиной рекурсии, очевидно, следует выбрать таким, чтобы, оставаясь в рамках допустимых значений, можно было проходить весь диапазон в обе стороны. Введите в функцию main обработку нажатия клавиши пробела:

auxKeyFunc(AOX_SPACE, KeySpace);

и создайте функцию обработки:

void _stdcall KeySpace()

{

//====== Флаг роста числа разбиений

static bool bGrow = true;

//====== Продолжаем разбивать до глубины 4

if (bGrow SS giDepth < 4)

{

giDepth += 1;

}

//====== Смена знака при глубине 4

else if (giDepth > 0)

{

bGrow = false;

giDepth == 1;

}

//====== Смена знака при глубине О

else

{

bGrow = true;

giDepth += 1;

}

DrawScene () ;

}

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

//====== Глубина рекурсии

int giDepth;

В функции DrawScene замените параметр 3 (при вызове Split) на giDepth и запустите на выполнение.

Примечание

Не знаю, как объяснить, но в Visual Studio б этот код почему-то работает, не-— смотря на явный промах, который типичен не только для начинающих программистов. Опытный читатель, конечно же, заметил, что мы создаем новые списки изображений, не уничтожая старые. Такие действия классифицируются как утечка памяти (memory lickage). Для ее устранения вставьте следующий фрагмент в функцию DrawScene перед вызовом glNewList:

//====== Если существует 1-й список,

if (gllsList(1))

//====== то освобождаем память

glDeleteLists (1,1);

Разъяснения можно найти в справке по функциям gllsList и glDeleteLists. He ошибитесь при выборе места вставки фрагмента, так как операции с памятью имеют особую важность. Запустите приложение и, нажимая на пробел, наблюдайте за изменением изображения, которое сначала приближается к сфере, затем постепенно возвращает свой первоначальный облик икосаэдра. Периодически нажимайте клавишу N для того, чтобы оценить влияние точного вычисления нормалей.

 

Рекурсивное деление

страницы в данном разделе 
Урок 6. Графика OpenGL Графика OpenGL
Обзор возможностей библиотеки OpenGL Подключаемые библиотеки
Ограничения Microsoft Примитивы OpenGL
OpenGL — автомат с конечным числом состояний Конвейер передачи OpenGL
Основные этапы Анимация
Другие функции OpenGL Контекст передачи изображения
Подготовка окна Создание консольного проекта
Штриховка линий Штриховка полигонов
Как убирать внутренние линии Перспективная проекция
Вносим свет Интерактивное управление положением и ориентацией
Двойная буферизация Использование списков
Интерполяция цвета Строим икосаэдр
Как создать сферу Выбор способа вычисления нормалей
Рекурсивное деление Массивы вершин, нормалей и цветов
Создание сферы >  


Содержание сайта (выборка)
Apache
Протоколы TCP/IP (принципы, протоколы и архитектура)



PHP, PELR, JSP
PHP
JavaServer Pages (JSP)

Базы данных
Основы mysql
СУБД INFORMIX
СУБД POSTGRES
Основы проектирования реляционных баз данных

HTML, javascript
Спецификация HTML 4.01
Каскадные Таблицы Стилей, Уровень 2
Клиентский JavaScript. Справочник.
JavaScript руководство пользователя
Серверный JavaScript 1.4. Руководство по Использованию.

Паскаль, C, C++, C#
GCC (примеры)
FAQ Валентинa Озеровa DELPHI
C



 
© faq.pp.ru, справочник программиста