Praktični primjer

Koordinatni sustav

Kao što ste mogli primjetiti kod prijašnjeg dijela "Biblioteke" susrećemo se sa problemom da moramo na 2D canvasu prikazati 3D objekte. Drugi problem su koordinate samog Canvas elementa u HTML5. Iz slike možemo vidjeti da canvas predstavlja zapravo samo jedan kvadrant koordinatnog sustava. cord Problemi su sljedeći:
  1. ishodište nije u sredini, već u gornjem lijevom uglu
  2. poseban problem je os y na kojoj vrijednosti rastu prema dolje
  3. kako je rezolucija uvijek konačna, tako je i raspon koordinata obično ograničen sa postavkama koje smo postavili kod definiranja canvas elementa (npr.width="500" height="500")
Da bi pretvorili koordinate canvas u Kartezijev koordinatni sustav trebamo u svakom JavaScriptu s kojim crtamo objekte, prije samog crtanja objekata napraviti određene postupke za realizaciju Kartezijevog koordinatnog sustava, implementirati metode za crtanje, rotaciju, translaciju i sl.
Zbog toga smo napravili metodu koja nam olakšava transformaciju Canvas koordinatnog sustava u Kartezijev koordinatni sustav.
 
function Ortho(g,xmin, xmax, ymin, ymax, xsize, ysize) 
    {
        sx = xsize/(xmax-xmin);
        sy = ysize/(ymin-ymax);
        px = -sx*xmin;
        py = -sy*ymax;
        gr = g;
        XMIN = xmin;
        XMAX = xmax;
        YMIN = ymin;
        YMAX = ymax;
    }
XMIN, XMAX,YMIN i YMAX nam služe da bi odredili duljine X i Y osi. Argumenti xsize i ysize predstavljaju širinu i dužinu canvas elementa koji smo kreirali prije (npr.width="500" height="500").
Sada kada smo to kreirali željeni koordinatni sustav i želimo nešto nacrtati u njemu opet nam se javlja problem jer koordinate nisu u dobrim kvadrantima (npr. (1,1) je u 4. kvadrantu i sl.). Uoubičajeni kod za crtanje linija nije dobar.
Canvasova metoda za crtanje
canvas = document.getElementById("naziv_naseg_canvasa");
c = canvas.getContext('2d');
c.moveTo(x1,y1);
c.lineTo(x2,y2); 

Trebaju nam vlastite metode za pretvorbu naših kordinata na koordinate zaslona. Nakon što kreiramo metode koje nam to pretvaraju moramo također implementirati funkcije koja će zamjeniti "moveTo" i "lineTo" metode. Sve ovo dodatno popraćuje matrica (4x4 zbog translacije) koja omogućava translaciju, rotaciju i skaliranje kod crtanja.
    function x_to_pix(x) 
    {
        return parseInt(sx*x+px);
    }
    
    function y_to_pix(y) 
    {
        return parseInt(sy*y+py);
    }
    
   function postaviNa(x, y, z) 
    {
        xLast = matrica[0][0]*x + matrica[0][1]*y + matrica[0][2]*z+matrica[0][3];
        yLast = matrica[1][0]*x + matrica[1][1]*y + matrica[1][2]*z+matrica[1][3];
        zLast = matrica[2][0]*x + matrica[2][1]*y + matrica[2][2]*z+matrica[2][3];
    }   
    
    function linijaDo(x, y, z) 
    {
        var x1, y1, x2, y2;
        x1 = x_to_pix(xLast);
        y1 = y_to_pix(yLast);
        xLast = matrica[0][0]*x + matrica[0][1]*y + matrica[0][2]*z+matrica[0][3];
        yLast = matrica[1][0]*x + matrica[1][1]*y + matrica[1][2]*z+matrica[1][3];
        zLast = matrica[2][0]*x + matrica[2][1]*y + matrica[2][2]*z+matrica[2][3];
        x2 = x_to_pix(xLast);
        y2 = y_to_pix(yLast);
        
        c.lineWidth = 1;
        c.beginPath();        
        c.moveTo(x1,y1);
        c.lineTo(x2,y2);
        
        c.stroke();
        
    }    

Metode potrebne za crtanje i rotaciju/translaciju 3D objekata.

Nakon što smo imeplementirali metode za realizaciju koordinatnog sustava, pretvorbi točaka i metoda za crtanje preostaje nam samo još implementirati metode za translaciju i rotaciju objekata (pošto su one jedine bile potrebne u ovom projektu).
Metoda za rotaciju oko osi X
function rotirajX (kut)
    {        
        var fi = kut * Math.PI / 180;
        var cosfi=Math.cos(fi);
        var sinfi=Math.sin(fi); 
        
        var m1  = izradiMatricu(4,4,0);
        m1[0][0]=1;
        m1[1][1]=cosfi;
        m1[1][2]=-sinfi;
        m1[2][1]=sinfi;
        m1[2][2]=cosfi;
        m1[3][3]=1;
        
        mult(m1);
    }

Metoda za rotaciju oko osi Y
function rotirajY (kut)
    {
        var fi = kut * Math.PI / 180;
        var cosfi=Math.cos(fi);
        var sinfi=Math.sin(fi);    

        var m1  = izradiMatricu(4,4,0);
        m1[0][0]=cosfi;
        m1[0][2]=sinfi;
        m1[1][1]=1;
        m1[2][0]=-sinfi;
        m1[2][2]=cosfi;
        m1[3][3]=1;
        mult(m1);
    }

Metoda za rotaciju oko osi Z
function rotirajZ (kut)
    {
        var fi = kut * Math.PI / 180;
        var cosfi=Math.cos(fi);
        var sinfi=Math.sin(fi);  

        var m1  = izradiMatricu(4,4,0);
        m1[0][0]=cosfi;
        m1[0][1]=-sinfi;
        m1[1][0]=sinfi;
        m1[1][1]=cosfi;
        m1[2][2]=1;
        m1[3][3]=1;
        mult(m1);
    }

Metoda za translaciju
function pomakni(px, py, pz)
    {
        var m1  = izradiMatricu(4,4,0);
        m1[0][0]=1;
        m1[1][1]=1;
        m1[2][2]=1;
        m1[3][3]=1;
        m1[0][3]=px;
        m1[1][3]=py;
        m1[2][3]=pz;
        mult(m1);
    }

Iz ovih 4 metoda vidimo da nam se javljaju još dvije metode "izradiMatricu(a,b,c)" i "mult(m)" pa ćemo ih stoga objasniti. Metoda "izradiMatricu(a,b,c)" nam kreira dvodimenzionalnu matricu pošto JavaScript nema dvodimenzionalne matrice kao tip podataka. Argumenti a b označavaju dimenzije matrice a vrijednost c označuje inicijalne vrijednosti svakog elementa matrice (izradiMatricu(4,4,0) smo mi koristili u našem primjeru. Metoda "mult(m)" nam služi za zapisivanje određenih transformacija u matricu tako da bi poslije kod crtanja znali da li smo rotirali, premjestili ili oboje prije samog crtanja objekta.

Matrične reprezentacije geometrijskih transformacija u 3D

U ovom dijelu ćemo Vam prikazati na koji način ručno nacrtati 3D objekte u 2D Canvas-u.

Prvo je trebalo na 2d ekranu (500x500) omogućiti prikaz modela sa 3 dimenzije. Ovo se realiziralo na način da se z-os ignorira te se 3D efekat dobije tek nakon rotiranja objekta. Praktičan primjer možete vidjeti na primjeru kocke.

Primjer pretvorbe modela kocke iz 2D u 3D

Kontrole (velika slova):
OS X = +H -Z
OS Y = +J -U
OS Z = +K -I
Reset = R


JavaScript kod

Primjer rotacije kocke oko proizvoljne osi

Na sljedećom Canvas elementu možete vidjeti kocku koja na početku izgleda kao kvadrat. Na slici je također prikazan i pravac koji je određen točkom (x1,y1,z1) i svojim vektorom smijera(u1,u2,u3). Da bi se vidjela 3d rotacija oko proizvoljnog pravca trebate pritisnuti tipku "A" da bi se kut rotacije povećao za 1 stupanj. Ukoliko želite da cijela stvar izgleda kao animacija tada je potrebno držati pritisnutu navedenu tipku.


JavaScript kod

Primjer rotacije kocke oko proizvoljne osi - animacija slijeda

Na sljedećom Canvas elementu možete vidjeti kocku koja na početku izgleda kao kvadrat. Na slici je također prikazan i pravac koji je određen točkom (x1,y1,z1) i svojim vektorom smijera(u1,u2,u3). Za pokretanje animacije slijeda pritisnite tipku "S". Svake dvije sekunde će se odvijati jedna od 7 transformacija koje su potrebne da bi mogli ostvariti 3D rotaciju objekta oko proizvoljne osi.


Da bi cijela stvar bila moguća trebamo odrediti gde ćemo nacrtati kocku i pravac oko kojeg ćemo ju rotirati. U našem primjeru kocka se nalazi u središtu koordinatnog sustava sa duljinom stranice 2 (njezine koordinate vrhova su (2,2,2),(2,2,-2) itd). Da bi odredili pravac u 3D prostoru možemo ga definirat na više načina:

  1. točkom i vektorom smijera
  2. dvjema točkama na pravcu
  3. itd...
Mi smo odredili naš pravac na drugi način:
  1. Točka na pravcu1: (2,-5,3)
  2. Točka na pravcu2: (-3,5-3)

Cijela stvar se realizira na način da se prije crtanja kocke odrade transformacije translacije i rotacije te nakon toga se crta 3D objekt. Postupak se sastoji od 7 koraka

  1. Korak 1: pomakni(2,-5,2);
  2. Korak 2: rotirajX(-alfa);
  3. Korak 3: rotirajY(beta);
  4. Korak 4: rotirajZ(fi);
  5. Korak 5: rotirajY(-beta);
  6. Korak 6: rotirajX(alfa);
  7. Korak 7: pomakni(-2,5,-2);
Da bi dobili kuteve alfa i beta (kut fi je kut rotacije objekta koji mi zadajemo) trebamo ih izračunati. Implementirali smo vlastite funkcije koje nam to računaju te ih možete vidjeti odmah ispod:
function izracunaj(x1,y1,z1,x2,y2,z2)
    {
        var nazivnik = Math.sqrt(((x2-x1)*(x2-x1))+((y2-y1)*(y2-y1))+((z2-z1)*(z2-z1)));
        u1=(x2-x1)/nazivnik;
        u2=(y2-y1)/nazivnik;
        u3=(z2-z1)/nazivnik;

        var fi =nas_zadani_kut;
        var d = Math.sqrt((u2*u2)+(u3*u3));

        var alfa=(Math.asin(u2/d))*(180/3.14);
        var beta=(Math.asin(u1))*(180/3.14);
        
    }

Za pokretanje animacije slijeda pritisnite tipku "S".

JavaScript kod