Jak již bylo zmíněno, po nahrání stránky do prohlížeče se zavolá funkce init():
function init() { rot = get_rotation_matrix(r,angle); // Spocita matici rotace pro zadany smer osy a uhel o kolik se ma otacet. setInterval(animate,100); // Nastavi, aby se funkce animate volala kazdy 100ms. };Ta nejprve zavolá funkci get_rotation_matrix(r,angle), která spočítá matici rotace rot, a pak nastaví, aby se funkce animate() volala každých 100ms.
K výpočtu matici rotace rot využijeme faktu, že umíme rotovat s vektory v okolo počátku o zadaný úhel .
Nechť je libovolná uspořádaná ortonormální báze v . Matici lineárního zobrazení takového otočení vzhledem k bázi jsme viděli na přednášce:
Nechť nyní
je libovolná uspořádaná ortonormální báze .
Matici otáčení v rovině můžeme snadno rozšířit i do 3D prostoru tak, aby otáčela vektory kolem osy dané
vektorem . Při takové rotaci totiž zůstává třetí souřadnice konstantní a první dvě se otočí jako v rovině.
Matice rotace vzhledem ke bázi kolem osy dané je tedy takováto matice:
Nechť je libovolný vektor v se souřadnicemi vzhledem k . Podobně jako předtím v rovině, pokud chceme najít souřadnice otočeného vektoru vzhledem k bázi , stačí spočítat výraz .
Matice umí tedy otáčet vektory kolem osy dané vektorem . Nicméně na to abychom ji mohli použít
na otočení vektoru
, musíme znát jeho souřadnice v bázi . Vektor máme typicky zadán pomocí
souřadnic vhledem ke standardní bázi
. Jeho souřadnice vzhledem k bázi získáme pomocí
matice přechodu od k . Označme
,
a
,
tj. jsou souřadnice vzhledem k . Pak snadno získáme matici přechodu od k . Je to totiž
matice identického zobrazení vzhledem k bázím a , tzn. její sloupce jsou tvořeny souřadnicemi vektorů
vzhledem k , tj.
Pokud chceme naopak přepočítat souřadnice
z do , stačí vynásobit předchozí rovnost
zleva (což je matice přechodu od k ), tj. pokud
vím, že
, pak
Nyní chceme umět otočit libovolný vektor
podle osy dané . Složky uspořádané trojice
odpovídají souřadnicím vektoru vzhledem k bázi . Otočený vektor
získáme takto:
Teď jsme připraveni si vysvětlit, co funkce get_rotation_matrix(r,angle) vlastně dělá. Funkce používá následující proměnné:
var coor_matrix = Matrix.create([ [0,0,0],[0,0,0],[0,0,0] ]); var rot_matrix = Matrix.create([ [0,0,0],[0,0,0],[0,0,0] ]); var a = Vector.create([0,0,0]); var b = Vector.create([0,0,0]);Proměnná coor_matrix je proměnná pro matici přechodu a rot_matrix je proměnná pro transponovanou matici rotace . Dále zde máme dva pomocné vektory .
Na začátku funkce testuje, jestli není vektor osy rotace r nulový. V případě, že ano, nastaví r na .
if (r.eql(Vector.Zero(3))) { r.setElements([1,1,1]); alert("Vektor osy rotace nemuze byt nulovy!"); }
Nyní je potřeba zkonstruovat libovolnou uspořádanou ortonormální bázi, jejíž třetí vektor je r (libovolnou až na pořadí prvních dvou bázových vektorů, jímž můžeme ovlivnit směr výsledné rotace). Takže potřebujeme najít dva navzájem kolmé vektory a,b délky , které budou kolmé na vektor r. Nejprve uděláme z r vektor délky . Pak zvolíme libovolný vektor a délky , který je na r kolmý. Nechť r . Pokud , pak takový vektor je např. . Pokud alespoň jedno z je nenulové, můžeme vzít např. vektor a udělat z něj vektor délky . Nakonec najdeme vektor b délky , který je kolmý na a i r pomocí vektorového součinu ra. Výše uvedený postup je obsahem následujícího kusu kódu:
r = r.toUnitVector(); if (r.e(1)!=0 || r.e(2)!=0) { a.setElements([-r.e(2),r.e(1),0]); a = a.toUnitVector(); } else { a.setElements([1,0,0]); } b = r.cross(a);
Uspořádaná trojice =(a,b,r) tvoří uspořádanou ortonormální bázi, jejíž třetí vektor je směrový vektor osy rotace. Sestavíme matici přechodu od k .
coor_matrix.setElements([ [a.e(1),b.e(1),r.e(1)], [a.e(2),b.e(2),r.e(2)], [a.e(3),b.e(3),r.e(3)] ]);
Do proměnné rot_matrix zadáme matici s úhlem angle:
rot_matrix.setElements([ [ Math.cos(angle), Math.sin(angle),0], [-Math.sin(angle), Math.cos(angle),0], [ 0, 0,1] ]);
Nakonec spočítáme součin (viz rovnice (2)) a jeho výsledek vrátíme jako výstup funkce:
rot_matrix = rot_matrix.multiply(coor_matrix.transpose()); // rot_matrix*(coor_matrix)^T rot_matrix = coor_matrix.multiply(rot_matrix); // coor_matrix*(rot_matrix*(coor_matrix)^T) return(rot_matrix);
Rostislav Horcik 2009-01-04