Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Системы автоматизированного проектирования. Моделирование в машиностроении. Учебное пособие
.pdf
if mass[j]>=mass2[j] then
begin
glVertex3d(j/10,i/10,mass[j]/10);
mass3[j]:=mass[j];
end
else
begin
glVertex3d(j/10,i/10,mass2[j]/10);
mass3[j]:=mass2[j];
end;
end;
glEnd();
end;
for i:=0 to 10 do
begin
glBegin(GL_LINE_STRIP);
glVertex3d(i/10,0,mass3[i]/10);
glVertex3d(i/10,0.9,mass3[i]/10);
glEnd();
end;
glPopMatrix;
SwapBuffers (Canvas.Handle);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
wglMakeCurrent(0, 0);
wglDeleteContext(hrc);
ReleaseDC (Handle, DC);
DeleteDC (DC);
end;
В обработчик события закрытия формы OnDestroy в Object Inspector во
вкладке Events прописать следующий код:
Пример выполненной программы представлен на рисунке 5.24.
81

Рисунок 5.24 – Экранная форма запущенного приложения
5.6.4 Задание на выполнение работы
Проверить работу программного кода и выполнить изменения в нем, по
указанию преподавателя.
Содержание отчета:
– название работы;
– цель работы;
– перечень используемых команд;
– экранные формы;
– листинг программы.
5.6.5 Контрольные вопросы
Что собой представляет поверхность Кунса?
Как построить поверхность Кунса?
Основные этапы построения поверхности Кунса?
Как осуществляется расчет поверхности?
82

5.7 Применение булевых операций для построения сложных
объектов
5.7.1 Цель работы
Целью работы является приобретение навыков применения булевых
операции при построении сложных объектов, используя функции графической библиотеки OpenGL.
5.7.2 Понятие и виды булевых операций
Как и для многих терминов компьютерной графики, термин «булева»
происходит от имени человека, который ввел это понятие (в данном случае
это Джордж Буль). Булевыми операциями называют операции объединения,
пересечения и вычитания тел, так как они выполняют одноименные операции
над внутренними объемами тел.
Булеву операцию объединения тел будем обозначать формулой:
, где А и В - исходные тела, Р - результирующее тело. Булеву операцию
пересечения тел будем обозначать формулой: . Булеву операцию
вычитания тел будем обозначать формулой: . Результатом операции объединения двух тел является тело, которое содержит точки, принадлежащие внутреннему объему или первого, или второго тела. Результатом операции пересечения двух тел является тело, которое содержит точки, принадлежащие внутреннему объему как первого, так и второго тела. Результатом
операции вычитания двух тел является тело, которое содержит точки, принадлежащие внутреннему объему первого, но не принадлежащие внутреннему объему второго тела.
Рассмотрим булеву операцию объединения тел. Кратко суть операции
молено описать следующим образом: нужно найти линии пересечения граней
тел, удалить ту часть первого тела, которая попала внутрь второго тела и ту
часть второго тела, которая попала внутрь первого тела, а из всего остально-
го построить новое тело.
Операцию условно можно разбить на три этапа. На первом этапе стро-
ятся линии пересечения поверхностей граней и на их базе — новые ребра.
Построенные новые ребра будем называть ребрами пересечения, а ребра тел
будут называться старыми ребрами. На втором этапе определяем точки пересечения новых ребер со старыми ребрами и в этих точках разрежем старые
ребра на несколько ребер. На третьем папе операции перестроим циклы пересекшихся граней. После этого добавим к пересекшимся граням тел грани,
типологически связанные ними.
На рисунке 5.25 показан результат операции объединения сферы и куба.
83

Рисунок 5.25 – Результат операции объединения
Суть булевой операции пересечения тел можно описать следующим
образом: нужно найти линии пересечения тел, удалить ту часть первого тела,
которая не попала внутрь второго, и ту часть второго тела, которая не попала
внутрь первого, а из всего остального построить новое тело.
Операцию разобьем на три этапа. Первый и второй этапы операции пересечения тел полностью совпадают с соответствующими этапами операции
объединения тел. Третий этап операции пересечения тол выполняется аналогично третьему этапу операции объединения тел, но имеет одно отличие в
том, с каким флагом входят в циклы ребра пересечения. Ребра пересечения
входят в перестроенные циклы граней первого тола с положительным фла-
гом, а в перестроенные циклы граней второго тела — с отрицательным фла-
гом (в объединении тел флаги ребер пересечения в циклах имеют противоположное значение). Все остальные действия над гранями обоих тел в обеих
операциях одинаковы. На рисунке 5.26 изображен результат операции пере-
сечения сферы и куба.
84

Рисунок 5.26 – Результат операции пересечения
Суть булевой операции вычитания тел можно описать следующим образом: нужно найти линии пересечения тел, удалить ту часть первого тела,
которая попала внутрь второго, и ту часть второго тела, которая не попала
внутрь первого, а из всего остального построить новое тело.
Булева операция вычитания тел сводится к булевой операции пересечения уменьшаемого тела и вывернутого наизнанку вычитаемого тела. Вывернутое наизнанку тело мы получим из исходного тела путем переориентации направлений нормалей граней и направлений циклов граней. Переориентация направления нормали грани производится изменением признака совпадения нормали поверхности и нормали ее грани. Переориентация направления цикла грани производится перестроением списка ребер (изменением на
обратный порядок следования ребер в списке) и заменой на противополож-
ные ребра в списках. Для вывернутого тела внутренним объемом является
часть пространства, находящаяся вне его оболочки. Поэтому при пересечении уменьшаемого тела и вывернутого наизнанку вычитаемого тела результирующая оболочка будет содержать ту часть объема уменьшаемого тела,
которая лежит вне вычитаемого тела. На рисунке 5.27 приведен результат
операции разности тел. В верхней части рисунка показан результат вычита-
ния куба из сферы, а в нижней - сферы из куба.
85

Рисунок 5.27 – Результат операции вычитания: сверху – вычитание куба
из сферы, снизу – сферы из куба
5.7.3 Ход работы
Для реализации булевых операций в OpenGl используется буфер тра-
фарета. Выполнение теста трафарета разрешается командой glEnable с аргументом GL_STENCIL_TEST. Команда glStencilFunc отвечает за сравнение, а
команда glStencilop позволяет определить действия, базирующиеся на ре-
зультате проверки трафарета. Программа демонстрирует, как использовать
буфер трафарета для реализации логических операций с твердыми телами.
Рисование фигур вынесено в отдельные процедуры, для манипуляций с ними
введены еще две процедуры.
По конструкции, программа демонстрирующая работу буфера трафарета, а соответственно и булевы операции, будет довольна проста. Состоять она
будет из одного RadioGroup, в котором будут отображаться названия булевых операций, RadioGroup в котором пользователь сможет выбрать вокруг
какой оси вращать сцену и двух «кнопок» BitBtn, с помощью которых предо-
86

ставляется выбор направления вращения получившейся в результате булевой
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, OpenGL, StdCtrls;
private
{ Private declarations }
DC : HDC;
hrc: HGLRC;
ry : GLfloat;
implementation
uses DGLUT;
{$R *.DFM}
type
proctype = procedure;
операции фигуры. Рассмотрим структуру приложения более подробно.
Создайте в среде программирования Delphi новый проект. Переместите
в каталог с программой файл DGLUT.pas.
В разделе uses программы подключаем библиотеку OpenGL:
В разделе private инициализировать следующие переменные и процедуры:
Подключаем библиотеку DGLUT и введем процедурный тип:
Добавим на форму компонент RadioGroup. Активировав свойство Cap-
tion в Object Inspector, впишем «Выберете операцию». Затем активируем
свойство Items и впишем 4 строки, содержание которых соответствует названиям операций (рисунок 28). Свойству Columns присвоим значение 4 (задаем
количество столбцов RadioGroup, это необходимо чтобы переключатели располагались горизонтально).
Добавим на форму еще один компонент RadioGroup. В свойстве
Caption впишем «Вращать вокруг оси». В Items вписываем X, Y, Z в отдельных строках.
Добавить на форму два компонента BitBtn взятых с вкладки Additional,
выбрать для них желаемые пиктограммы активировав свойство Glyph в Ob-
ject Inspector и инициализировать события OnClick двойным щелчком мыши
по данным компонентам, после чего вписать код:
87

procedure TForm1.BitBtn1Click(Sender: TObject);
begin
ry:=ry-5.0; // Вращаем сцену по часовой стрелке
end;
procedure TForm1.BitBtn2Click(Sender: TObject);
begin
ry:=ry+5.0; // Вращаем сцену против часовой стре лки
end;
Пример получившейся формы представлен на рисунке 5.28.
Рисунок 5.28 – Экранная форма создаваемого приложения
88

Зададим формат пиксела:
procedure TForm1.SetDCPixelFormat;
var
nPixelFormat: Integer;
pfd: TPixelFormatDescriptor;
begin
FillChar(pfd, SizeOf(pfd), 0);
pfd.dwFlags := PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or
PFD_DOUBLEBUFFER; // множество битовых флагов,определяющих
устройство и интерфейс
nPixelFormat := ChoosePixelFormat(DC, @pfd); // устанавливаем формат пик-
селей в контексте устройства
SetPixelFormat(DC, nPixelFormat, @pfd);
end;
procedure TForm1.FormCreate(Sender: TObject);
const
lightposition : Array [0..3] of GLfloat = ( -3.0, 3.0, 3.0, 0.0 );
begin
DC := GetDC (Handle);
SetDCPixelFormat(DC);
hrc := wglCreateContext(DC);
wglMakeCurrent(DC, hrc);
glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHT0);
glEnable(GL_LIGHTING);
glLightfv(GL_LIGHT0, GL_POSITION, @lightposition);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_CULL_FACE);
glClearColor(1.0, 1.0, 1.0, 0.0);
ry:=0.0;
end;
Перейдите к конструктору и сделайте двойной щелчок клавишей мыши
на форме – создастся функция обработчика события загрузки формы
FormCreate. В ней мы поместим следующий код:
OnResize. Для этого необходимо в Object Inspector перейти на вкладку Events,
где щелкнуть по вышеперечисленным событиям два раза.
Инициализировать обработчики событий OnDestroy, OnPaint,
В обработчики событий добавить следующий код:
89

OnDestroy:
procedure TForm1.FormDestroy(Sender: TObject);
begin
wglMakeCurrent(0, 0);
wglDeleteContext(hrc);
ReleaseDC(Handle, DC);
DeleteDC (DC);
end;
procedure TForm1.FormPaint(Sender: TObject);
var
x,y,z: single;
begin
glClear (GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT or
GL_STENCIL_BUFFER_BIT); // очистка буфера цвета
glPushMatrix;
x:=0.0;
y:=0.0;
z:=0.0;
if radiobutton1.Checked then x:=1.0;
if radiobutton2.Checked then y:=1.0;
if radiobutton3.Checked then z:=1.0;
glRotatef (ry, x, y, z);
glTranslatef (0.0, 0.0, 0.0);
//Объединение А и В
if RadioGroup1.ItemIndex=0 then
begin
glPushAttrib(GL_ALL_ATTRIB_BITS);
glEnable(GL_DEPTH_TEST);
B;
A;
glPopAttrib;
end;
//Вычитание А-В
if RadioGroup1.ItemIndex=1 then
begin
inside(A, B, GL_FRONT, GL_NOTEQUAL);
fixup(B);
inside(B, A, GL_BACK, GL_EQUAL);
end;
//Пересечение А и В
if RadioGroup1.ItemIndex=2 then
OnPaint:
90
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
