МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ
Національний університет “Львівська політехніка”
кафедра САПР
З В І Т
до лабораторної роботи №2
з курсу: “Геометричне моделювання у конструюванні інженерних об’єктів і систем”
на тему: “Афінні перетворення та анімація засобами мови TURBO PASCAL 7.0.”
Львів – 2005
МЕТА РОБОТИ
Мета роботи – ознайомитись із законами руху геометричних об’єктів на прощині та у
просторі. Оволодіти математичною мовою опису динаміки та візуалізації на основі
закономірностей геометричних перетворень. Набути практичних навиків розробки графічних
процедур у середовищі Turbo Pascal в графічному режимі.
КОРОТКІ ТЕОРЕТИЧНІ ВІДОМОСТІ
ГЕОМЕТРИЧНІ ПЕРЕТВОРЕННЯ ОСНОВНІ ПОНЯТТЯ ТА СПІВВІДНОШЕННЯ
Геометричне перетворення – це відображення p'= f ( p) точки p ∈ Rn n-мірного простору образу в точку p'∈ Rn' n'-мірного простору перетворення (де Rn - евклідів простір розмірності n.
Геометричне перетворення поділяються на нелінійні (наприклад, відображення у кривому дзеркалі) та лінійні.
Лінійне перетворення точки описується векторним рівнянням: p'= pA + B з матрицями перетворення A∈ Rn×n' та B ∈ R1×n' , що не залежать від вектора p. У залежності від розмірності просторів n, n' та властивостей матриці А лінійні перетворення поділяються на невироджені (афінні) та вироджені (проективні).
Властивості афінного перетворення:
n = n',rang(A) = n (де rang(A) – ранг матриці А, рівний числу її лінійно незалежних строк чи стовпців), що означає квадратність та невиродженість матриці А. Існування зворотної матриці А-1 дозволяє по точці p' відновити точку образу p:
p = ( p'−B)A−1 При проективному перетворенні m<n та не існує оберненої матриці А-1, тому
однозначне відновлення образу за прообразом неможливе через втрату інформації про одну чи
декілька координат образу.
Рис. 1 Геометричні перетворення: афінне ( R3→ R3 ) та проективне ( R3→ R2 )
АФІННІ ПЕРЕТВОРЕННЯ
Афінні перетворення (від англ. affinity – подібність) – точкові взаємно однозначні відображення площини (простору) на себе, при яких прямі переходять у прямі. Якщо на площині задана декартова система координат, то кожне афінне перетворення цієї площини
може бути визначене за допомогою так званого невирожденого лінійного перетворення координат х та у точок цієї площини.
Загальний вид формул двовимірних афінних перетворень:
х' = а11х + а12у + а13,
y' = а21x + а22y + а23
з додатковою вимогою
де x,y – координати початкового об’єкту, х', y' – координати перетвореного об’єкта.
Коефіцієнти перетворень aij зберігають у виді матриці, розширеної до квадратної:
, при цьому дуже просто обчислюються коефіцієнти довільного складного перетворення, якщо відомі коефіцієнти перетворень, його складових. Для цього просто перемножують відповідні матриці коефіцієнтів. Аналогічно, кожне афінний простір може бути визначений за допомогою невирождених лінійних перетворень координат точок простору. Сукупність усіх афінних перетворень
площини (простору) на себе утворить групу афінних перетворень. Це означає, зокрема , що послідовне проведення двох афінни перетворень еквівалентно деякому одному афіннму перетворенню.
Прикладами афінних перетворень можуть бути ортогональне перетворення (це перетворення є переміщення чи площини чи простору, переміщення із дзеркальним відображенням); перетворення подоби; рівномірне „стиснення”.
Рис.2 Приклад афінного перетворення
Рівномірне „стиснення” з коефіцієнтом k площини π до розташованого на ній прямої а– перетворення, при якому точки а залишаються на місці, а кожна точка М, що не лежить на а площини π зміщається по променю, що проходить через М перпендикулярно а, у таку точку
M', що відношення відстаней від М и М 'до а дорівнює k; аналогічно визначається рівномірне "стиснення" простору до площини. Всяке афінне перетворення площини можна одержати, виконавши деяке ортогональне перетворення і послідовне „стиснення” до деяких двох
перпендикулярним прямим. Кожне афінне перетворення простору можна здійснити за допомогою деякого ортогонального перетворення і послідовних „стиснень” до деяких трьох взаємно перпендикулярним площинам. При афінному перетворенні паралельні прямі та
площини перетворяться в паралельні прямі та площини. Властивості афінних перетворень широко використовуються в різних розділах математики, механіки і теоретичної фізики. Так, у геометрії афінні перетворення застосовуються для так званої афінної класифікації фігур. У механіці афінні перетворення використовуються при вивченні малих деформацій безупинного суцільного середовища; при таких деформаціях малі елементи середовища в першому наближенні піддаються афінному перетворенню.
Афінне перетворення має наступні властивості:
1) відображає n-мірний об’єкт у n'-мірний – точку в точку, лінію в лінію, поверхню у поверхню;
2) зберігає паралельність ліній та плоскостей;
3) зберігає пропорції паралельних об’єктів – довжин відрізків на паралельних прамих та площин на паралельних площинах.
Ці властивості дозволяють будувати прообрази полігонів на площині та поліедрів у просторі по кінцевому набору m точок їх вершин:
Індивідуальне завдання:
20. Написати імітаційну програму з застосуванням афінних перетворень, яка дозволяє в автоматичному режимі та при ручному керуванні створювати динамічно змінну візуалізацію при якій моделюється каркасна форма додекаедра (див. рис.), що складається з 12 п’ятикутників – 30 ребер, 20 вершин.
Алгоритм рішення задачі:
Для того щоб побудувати додекаедр потрібно використати лише два типи афінних перетворень, це: переміщення і поворот.
Алгоритм рішення буде включати такі кроки:
Обчислюємо координати вершин основного п’ятикутника(п’ятикутник який знаходиться найближче), кут між сторонами(він буде потрібний для обрахунку кутів повертання), координати вершин всіх інших п’ятикутників приймаємо рівними координатам вершин основного п’ятикутника.
Малюємо основний п’ятикутник
Обчислюємо координати ін. п’ятикутника, тобто проводимо афінне перетворення, наприклад, п’ятикутник який знаходиться справа від основного утворюється як результат повертання основного відносно осі Х на кут, який рівний різниці кута між сторонами п’ятикутника і прямого кута(пі/2), відносно осі Y на кут, який рівний різниці між кутом пі і кутом між сторонами п’ятикутника, відносно осі Z на кут, який рівний подвійній різниці кута між сторонами п’ятикутника і прямим кутом. Після цього по знайдених координатах вершин малюємо п’ятикутник.
Крок 4 повторюємо для кожного п’ятикутника, обчислюючи для кожного з них свої величини кутів повертання.
Код програми:
program laba2;
uses
crt, graph;
type
koordynaty=record
x: integer;
y: integer;
z: integer;
end;
const
n = 5;
var
DETECT, radius_kola, center_x, center_y:integer;
main_kytnyk: array[1..n] of koordynaty;
kytnyky: array[1..12,1..n] of koordynaty;
r,a, matr_b: array[1..4,1..4] of real;
sec, kyt_st : real;
procedure clear_r;
var
i, j :integer;
begin
for i:=1 to 4 do
begin
for j:=1 to 4 do
r[i,j] := 0;
r[i,i]:= 1;
end;
end;
procedure mult_a_r;
var
i,j,k : integer;
suma: real;
begin
for i :=1 to 4 do
for j:=1 to 4 do begin
suma:=0;
for k :=1 to 4 do
suma:= suma+ a[i,j]*r[k,j];
matr_b[i,j] := suma;
end;
for i:=1 to 4 do
for j:=1 to 4 do
r[i,j] := matr_b[i,j];
end;
procedure moving(dx, dy, dz:real);
var
i,j:integer;
begin
for i:=1 to 4 do
begin
for j:=1 to 4 do
a[i,j]:=0;
a[i,i]:=1;
end;
a[1,4] := dx;
a[2,4] := dy;
a[3,4] := dz;
mult_a_r;
end;
procedure rotate_kyt( kyt:real; visj: integer);
var
i,j, ax1,ax2 : integer;
c, s :real;
begin
for i:=1 to 4 do
for j:=1 to 4 do
a[i,j]:=0;
a[4,4] := 1;
a[visj, visj] := 1;
ax1 := visj +1;
if (ax1=4) then ax1:=1;
ax2 := ax1 + 1;
if (ax2=4) then ax2 :=1;
c := cos(kyt);
a[ax1, ax1] := c;
a[ax2, ax2] := c;
s := sin(kyt);
a[ax1, ax2] := -s;
a[ax2, ax1] := s;
mult_a_r;
end;
procedure scale(sx, sy, sz:real);
var
i,j :integer;
begin
for i:=1 to 4 do
for j:=1 to 4 do
a[i, j] := 0;
a[1, 1]:= sx;
a[2, 2] := sy;
a[3, 3] := sz;
a[4, 4] := 1;
mult_a_r;
end;
procedure look_on_screen(kyt_x, kyt_y, kyt_z, dx, dy, dz, sx, sy, sz: real; num:integer);
var
x_temp, y_temp, z_temp:real;
i : integer;
begin
clear_r;
rotate_kyt(kyt_x, 1);
rotate_kyt(kyt_y, 2);
rotate_kyt(kyt_z, 3);
moving(dx, dy, dz);
scale(sx, sy, sz);
if num = 0 then
begin
for i := 1 to n do
begin
x_temp:=main_kytnyk[i].x*r[1,1]+main_kytnyk[i].y*r[1,2]+main_kytnyk[i].z*r[1,3]+r[1,4];
y_temp:=main_kytnyk[i].x*r[2,1]+main_kytnyk[i].y*r[2,2]+main_kytnyk[i].z*r[2,3]+r[2,4];
z_temp:=main_kytnyk[i].x*r[3,1]+main_kytnyk[i].y*r[3,2]+main_kytnyk[i].z*r[3,3]+r[3,4];
main_kytnyk[i].x:=round(x_temp);
main_kytnyk[i].y:=round(y_temp);
main_kytnyk[i].z:=round(z_temp);
end;
end
else
begin
for i := 1 to n do
begin x_temp:=kytnyky[num,i].x*r[1,1]+kytnyky[num,i].y*r[1,2]+kytnyky[num,i].z*r[1,3]+r[1,4];
y_temp:=kytnyky[num,i].x*r[2,1]+kytnyky[num,i].y*r[2,2]+kytnyky[num,i].z*r[2,3]+r[2,4];
z_temp:=kytnyky[num,i].x*r[3,1]+kytnyky[num,i].y*r[3,2]+kytnyky[num,i].z*r[3,3]+r[3,4];
kytnyky[num,i].x:=round(x_temp);
kytnyky[num,i].y:=round(y_temp);
kytnyky[num,i].z:=round(z_temp);
end;
end;
clear_r;
end;
procedure draw_kytnyk(num: integer);
var
i,d,temp_x,temp_x1, temp_y1, temp_y : integer;
begin
d := 1500;
if num = 0 then
begin
for i:=1 to n-1 do
begin
temp_x := round(main_kytnyk[i].x{*d/(main_kytnyk[i].z)});
temp_x1 := round(main_kytnyk[i+1].x{*d/(main_kytnyk[i+1].z)});
temp_y := round(main_kytnyk[i].y{*d/(main_kytnyk[i].z)});
temp_y1 := round(main_kytnyk[i+1].y{*d/(main_kytnyk[i+1].z)});
if i = 1 then
begin
setcolor(2)
end
else
begin
setcolor(15);
end;
line(temp_x,temp_y,temp_x1,temp_y1);
end;
temp_x := round(main_kytnyk[n].x{*d/(main_kytnyk[n].z)});
temp_x1 := round(main_kytnyk[1].x{*d/(main_kytnyk[1].z)});
temp_y := round(main_kytnyk[n].y{*d/(main_kytnyk[n].z)});
temp_y1 := round(main_kytnyk[1].y{*d/(main_kytnyk[1].z)});
line(temp_x,temp_y,temp_x1,temp_y1);
end
else
begin
for i:=1 to n-1 do
begin
temp_x := round(kytnyky[num,i].x{*d/kytnyky[num,i].z});
temp_x1 := round(kytnyky[num,i+1].x{*d/kytnyky[num,i+1].z});
temp_y := round(kytnyky[num,i].y{*d/kytnyky[num,i].z});
temp_y1 := round(kytnyky[num,i+1].y{*d/kytnyky[num,i+1].z});
if i = 1 then
begin
setcolor(2)
end
else
begin
setcolor(15);
end;
line(temp_x,temp_y,temp_x1,temp_y1);
end;
temp_x := round(kytnyky[num,n].x{*d/kytnyky[num,n].z});
temp_x1 := round(kytnyky[num,1].x{*d/kytnyky[num,1].z});
temp_y := round(kytnyky[num,n].y{*d/kytnyky[num,n].z});
temp_y1 := round(kytnyky[num,1].y{*d/kytnyky[num,1].z});
line(temp_x,temp_y,temp_x1,temp_y1);
{for i:=1 to n-1 do line(kytnyky[num,i].x,kytnyky[num,i].y,kytnyky[num,i+1].x,kytnyky[num,i+1].y);
line(kytnyky[num,n].x,kytnyky[num,n].y,kytnyky[num,1].x,kytnyky[num,1].y);}
end;
end;
procedure calculate_koordynaty(x,y,z:integer; radius: integer);
var
i,j : integer;
begin
sec := 2*pi/n;
for j := 1 to n do begin
main_kytnyk[j].x := x + round(radius * cos(j*sec+pi/2));
main_kytnyk[j].y := y + round(radius * sin(j*sec+pi/2));
main_kytnyk[j].z := z;
end;
for i := 1 to 12 do
for j := 1 to n do begin
kytnyky[i,j].x := main_kytnyk[j].x;
kytnyky[i,j].y := main_kytnyk[j].y;
kytnyky[i,j].z := main_kytnyk[j].z;
end;
end;
procedure calc_new_xy(num:integer);
var
i:integer;
begin
for i:=1 to n do begin
kytnyky[num,i].x:=round(kytnyky[num,i].x*r[1,1]+kytnyky[num,i].y*r[1,2]+kytnyky[num,i].z*r[1,3]+r[1,4]);
kytnyky[num,i].y:=round(kytnyky[num,i].x*r[2,1]+kytnyky[num,i].y*r[2,2]+kytnyky[num,i].z*r[2,3]+r[2,4]);
kytnyky[num,i].z:=round(kytnyky[num,i].x*r[3,1]+kytnyky[num,i].y*r[3,2]+kytnyky[num,i].z*r[3,3]+r[3,4]);
end;
end;
begin
clrscr;
{write('Input radius main ciorcle:');
readln(radius_kola );}
radius_kola := 50;
initgraph(DETECT, DETECT, '');
center_x := round(getmaxX/2);
center_y := round(getmaxY/2);
clear_r;
calculate_koordynaty(center_x, center_y, 1, radius_kola);
kyt_st := pi - sec;
{look_on_screen(0,1,1,30,80,1000,2,2,2,0);}
draw_kytnyk(0);
clear_r;
moving(-center_x, -center_y, -1);
calc_new_xy(1);
clear_r;
rotate_kyt(kyt_st ,1);
calc_new_xy(1);
clear_r;
moving(center_x, center_y-51,1);
calc_new_xy(1);
draw_kytnyk(1);
clear_r;
moving(-center_x, -center_y,-1);
calc_new_xy(2);
clear_r;
rotate_kyt(kyt_st, 2);
calc_new_xy(2);
clear_r;
rotate_kyt((kyt_st-pi/2), 3);
calc_new_xy(2);
clear_r;
rotate_kyt(kyt_st - pi/2, 1);
calc_new_xy(2);
clear_r;
moving(center_x-55, center_y-10,1);
calc_new_xy(2);
draw_kytnyk(2);
clear_r;
moving(-center_x, -center_y, -1);
calc_new_xy(3);
clear_r;
rotate_kyt(-(kyt_st-pi/2), 3);
calc_new_xy(3);
clear_r;
rotate_kyt(kyt_st-pi/2,1);
calc_new_xy(3);
clear_r;
rotate_kyt(pi-kyt_st, 2);
calc_new_xy(3);
clear_r;
moving(center_x+55, center_y-12, 1);
calc_new_xy(3);
draw_kytnyk(3);
clear_r;
moving(-center_x, -center_y, -1);
calc_new_xy(4);
clear_r;
rotate_kyt(-(kyt_st - pi/2), 3);
calc_new_xy(4);
clear_r;
rotate_kyt((pi-kyt_st),1);
calc_new_xy(4);
{clear_r;
rotate_kyt(pi-kyt_st, 2);
calc_new_xy(4);}
clear_r;
moving(center_x+40, center_y+60, 1);
calc_new_xy(4);
draw_kytnyk(4);
readkey;
closegraph;
end.
Висновок: В даній лабораторній роботі я навчився використовувати афінні перетворення для моделювання трьохвимірних об’єктів. Також була реалізована програма моделювання додекаедра з використанням афінного перетворення “переміщення” і “поворот”, що моделює трьохвимірний об’єкт.