Выбрать главу

6. Затушевать отдельные пиксели.

Первая задача состоит в представлении объекта в виде массива многоугольников, в котором каждая вершина многоугольника описывается в трехмерной мировой системе координат. Вторая задача — применить линейные преобразования к сеточной модели многоугольников. Эти преобразования используются для позиционирования объектов на сцене и создания точки обзора или поверхности отображения (области, которая видима наблюдателю с его точки обзора). Третья задача — отбраковать невидимые поверхности объектов на сцене. Это означает удаление линий, принадлежащих тем частям объектов, которые невидимы с точки обзора. Четвертая задача — преобразовать модель вершин в набор координат пикселей. Пятая задача — удалить любые скрытые поверхности. Если сцена содержит взаимодействующие объекты, например, когда одни объекты заслоняют другие, то скрытые (передними объектами) поверхности должны быть удалены. Шестая задача - наложить на поверхности изображения тень.

Рис. 3.13. Способы разбиения программы на отдельные задачи

Рис. 3.14. Этапы визуализации

Решение каждой задачи представляется в виде отдельного выполняемого файла. Первые три задачи (Taskl, Task2 и Task3) выполняются последовательно, а остальные три (Task4, Task5 и Task6)— параллельно. Реализация первого способа создания программы визуализации приведена в листинге 3.5.

// Листинг 3.5. Использование способа 1 для создания процессов

#include <spawn.h>

#include <stdlib.h>

#include <stdio.h>

#include <sys/wait.h>

#include <errno.h>

#include <unistd.h>

int main(void) {

posix_spawnattr_t Attr;

posix_spawn_file_actions_t FileActions;

char *const argv4[] = {«Task4»,...,NULL};

char *const argv5[] = {«Task5'\...,NULL};

char *const argv6[] = {«Task6»,...,NULL};

pid_t Pid;

int stat;

// Выполняем первые три задачи синхронно,

system(«Taskl . . . ") ;

system(«Task2 . . . ") ;

system(«Task3 . . . ") ;

//иниииализируем структуры

posix_spawnattr_init(&Attr);

posix_spawn_file_actions_init(&FileActions);

// execute last 3 tasks asynchronously

posix_spawn(&Pid,«Task4»,&FileActions,&Attr,argv4,NULL);

posix_spawn(&Pid,«Task5»,&FileActions,&Attr,argv5,NULL);

posix_spawn(&Pid,«Task6»,&FileActions,&Attr,argv6,NULL);

// like a good parent, wait for all your children

wait (&stat);

wait (&stat);

wait (&stat);

return(0);

}

В листинге 3.5 из функции main () с помощью функции system( ) вызываются на выполнение задачи Task1, Task2 и Task3. Каждая из них выполняется синхронно с родительским процессом. Задачи Task4, Task5 и Task6 выполняются асинхронно родительскому процессу благодаря использованию функций posix__spawn( ). Многоточие (... ) используется для обозначения файлов, требуемых задачам. Родительский процесс вызывает три функции wait (), и каждая из них ожидает завершения одной из задач (Task4, Task5 или Task6).

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

Task1 ... && Task2 ... && Task3 Task4 . . . & Task5 . . . & Task6

Здесь благодаря использованию метасимвола && задачи Task1, Task2 и Task3 выполняются последовательно при условии успешного выполнения предыдущей задачи. Задачи же Task4, Task5 и Task6 выполняются одновременно, поскольку использован метасимвол &. Приведем некоторые метасимволы, применяемые при разделении команд в средах UNIX/Linux, и способы выполнения этих команд.

&& Каждая следующая команда будет выполняться только в случае успешного выполнения предыдущей команды.

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

; Команды должны выполняться последовательно.

& Все команды должны выполняться одновременно.

При использовании третьего способа задачи делятся по категориям. При декомпозиции программы следует разобраться, можно ли в ней выделить различные категории задач. Например, одни задачи могут «отвечать» за интерфейс пользователя, т.е. его создание, ввод данных, вывод данных и пр. Другим задачам поручаются вычисления, управление данными и пр. Такой подход весьма полезен не только при проектировании программы, но и при ее реализации. В нашей программе визуализации мы можем разделить задачи по следующим категориям: