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:
. Výsledkem je matice typu
.
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
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 r
a.
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