Maatriksarvutused joonistamisel Korrutamine, nihutamine, keeramine, toimingute ühendamine Enamiku joonistamiseks tarvilikku saab välja mõelda põhikoolimatemaatika ning terve talupojamõistuse abil. Kuni on tegemist üksikute paigal seisvate või sirgelt liikuvate punktidega, siis polegi enamasti muud vaja. Kui aga teisendusi ning kujundeid palju saab, siis muutub nii programmi kirjutamine kui töötamine järjest mahukamaks ning tuleb abivahendeid otsida. Keerukama kujundi kuhugi paigutamine taandub enamasti hulga punktide ümbertõstmisele. Keeramise korral tuleb selleks teha töömahukaid trigonomeetrilisi arvutusi. Kui üksteisele järgneb mitu nihutamist ning mitu keeramist, siis kasvab töö maht päris suureks ning suure punktide hulga korral seda enam. Üheks võimaluseks arvutuste kiirendamisel on tõenäoliselt vaja minevate keerulisemate arvutuste tulemused varem välja arvutada ning neid vajadusel mälust otsida. Kuna siinuse arvutamine on vähemalt tuhat korda aeglasem kui tavaline liitmine või mälust lugemine, siis juba paari tuhande punkti juures on pildi keeramisel vahe märgata. Kuigi põhimõtteliselt võib olla vaja arvutada igasugu nurki, piisab joonistamiste juures siiski enamasti vaid ühekraadisest täpsusest. Nii on vaja eelnevalt välja arvutada siinused vaid 360 kraadi jaoks, asendusvalemeid kasutades võib kergesti piirduda ka veerandiga sellest. Kui veel veidi edasi mõtelda, siis kuna koosinus jookseb siinusest täisnurga jagu taga, siis saab samade 90 kraadi jagu välja arvutatud siinuste abil arvuti tarvis kiirete liitmis-ja lahutustehete abil leida mõlema funktsiooni väärtusi kogu olemasolevas vahemikus. Graafikaarvutusi saab märgatavalt kiirendada ning osalt grupeerimise teel vähendada maatriksite abil. Muidu kipub nende sageli õppekavas kohustuslike tabelitega suhteliselt vähe igapäevaülesannete juures otse peale hakata olema, aga kui on vaja vähegi keerukamaid kujundeid pinnal või ruumis ümber paigutada, siis parajasti sobiva abiliidese puudumisel jõuab lõpuks paratamatult maatriksiteni välja. Silma on hakanud nende järgmised head omadused: Ühe kujundi puhul on vaja töömahukaid arvutusi sooritada vaid korra, ülejäänud juhtudel saab uue koordinaadi välja arvutada paari liitmis- ning korrutustehtega. Soovi korral võib kogu kujundi punkte käsitleda koos Nihutamisi, suurendamisi ja keeramisi saab vaadelda tervikoperatsioonidena, ei teki lootusetut killustatust. Iga operatsiooni saab kirjeldada ühe maatriksina ning järjestikused operatsioonid saab ühendada lihtsalt üksteise järel seisvaid maatrikseid korrutades. Lähemad selgitused näidete varal. Väike meeldetuletus, kuidas maatrikseid korrutatakse. Korrutatavad maatriksid paremal ning vastus vasakul. Vasakpoolse maatriksi ridadel asuvad elemendid korrutatakse parempoolse maatriksi vastavatel veergudel olevate väärtustega. Sellest järeldub, et korrutamisel peab olema vasakpoolse maatriksi ridu sama palju kui parempoolse maatriksi veerge ning korrutise tulemusena tekkivas maatriksis on ridu nii palju kui esimeses ja veerge nagu teises maatriksis. Samad väärtused õnnestub korrutada, kui maatriksite read ja veerud ning järjekord vahetada. Arvutades koordinaate ümber järgneva valemi järgi , saab selle kirja panna maatriksitena . Kui punkte on vaja üle kanda korraga rohkem kui üks, siis saab selle ette võtta järgmise korrutise abil: . Iga punkti kohta tuleb lihtsalt esimeses maatriksis üks rida. Arvestades enne toodud üldvalemit, saab välja tuua mõned erijuhud. ehk uue x-i arvutamisel on vana x-i kordaja 1 ning uue y-i arvutamisel on vana y-i kordaja 1, pikemalt ehk ehk koordinaadid jäävad muutumatuks. ehk ehk y-koordinaat muutub vastupidiseks ning punkt või joonis peegeldatakse x-telje suhtes. Soovides järjestikku kõigepealt venitada joonist x-telge pidi kaks korda pikemaks ning seejärel y-telge pidi kaks korda pikemaks , võib kõigepealt kaks tekkinud muutust kokku korrutada ehk ning alles siis punkti koordinaadid tulemusega läbi korrutada ning otse lõpptulemus saada. Järgnevalt koodinäide, kuidas etteantud maatriksi järgi algsetel koordinaatidel asuvat ringi uude kohta transportida valemi järgi x1=2x ning y1=-y. Maatriksiks on 2x2 algväärtustatud massiiv nimega m. Muutujad x ja y tähistavad punkti algseid koordinaate, keskx ja kesky näitavad joonistatava ala keskpunkti ekraanipunktides ning neid läheb vaja vaid joonistamisel. Meetod joonistaTeljed tõmbab ekraanile keskpunktis ristuvad horisontaal- ning vertikaaljoone. Käsk joonistaKujund loob etteantud koordinaatidele ringi, nii et ringi keskpunkt jääb soovitud kohale. Joonistamise arvutamine jääb käsu paint sisse. Uued koordinaadid leitakse algseid muutusmaatriksiga korrutades . Lahtiseletatult korrutatakse algsed koordinaadid x ja y kõigepealt parempoolse maatriksi vasakpoolse veeru väärtustega ning tulemuseks saadakse uue x-i koordinaat x1. Edasi korrutatakse algsete koordinaatide maatriks teisendusmaatriksi parema veeruga ning saadakse uus y-koordinaat y1. . Kui tühjad liikmed maha arvata, siis jääb järele, ehk tulemus, mida soovisimegi saavutada. Massiivile võib anda elemendid algväärtustamisel. Kui ühemõõtmelise massiivi algväärtustamisel võis väärtused paigutada lihtsalt komadega eraldatult loogeliste sulgude vahele, siis kahemõõtmelise puhul tuleb ka iga rida eraldi loogeliste sulgude vahele panna ning komadega eraldada. Nii nagu veergude elemendid on üksteisest komadega eraldatuna rida moodustavas plokis, nii loovad read üheskoos komadega eraldatult ridade massiivi ning kokku tulebki kahemõõtmeline massiiv, kus esimene indeks näitab rea- ning teine veeru numbrit. int[][] m=new int[][]{ {2, 0}, //teisendus x=2x {0, -1} // y=-y }; Korrutamine (uue x-i ja y-i arvutamine): int ux=x*m[0][0]+y*m[1][0]; int uy=x*m[0][1]+y*m[1][1]; Kuna massiivi elemendid algavad nullist, siis on maatriksi esimese rea number 0, teise rea number 1, samuti veergude puhul. Nii korrutataksegi uue x-i leidmiseks kõigepealt vana x maatriksi esimese veeru esimese elemendiga ning siis liidetakse tulemusele vana y-i korrutis teise rea esimese elemendiga. Uue y-i leidmisel sama lugu, vaid korrutatakse algsed x ja y maatriksi teise veeru elementidega. Kogu programm näeks välja järgmine: import java.applet.Applet; import java.awt.*; public class Maatriks1 extends Applet{ int[][] m=new int[][]{ //teisendus x=2x {2, 0}, // y=-y {0, -1} }; int x=30, y=10; int keskx=150, kesky=150; public void joonistaTeljed(Graphics g){ g.drawLine(keskx, 0, keskx, 2*kesky); g.drawLine(0, kesky, 2*keskx, kesky); } public void joonistaKujund(Graphics g, int kx, int ky){ g.drawOval(keskx+kx-5, kesky-ky-5, 10, 10); } public void paint(Graphics g){ joonistaTeljed(g); joonistaKujund(g, x, y); int ux=x*m[0][0]+y*m[1][0]; int uy=x*m[0][1]+y*m[1][1]; g.setColor(Color.blue); joonistaKujund(g, ux, uy); } public static void main(String argumendid[]){ Frame f=new Frame(); f.add(new Maatriks1()); f.setSize(300, 300); f.setVisible(true); } } Klass maatriksarvutuste tarvis. Kui teisendusi tuleb programmi sisse enam, siis kõiki ükshaaval lahti kirjutades tuleb arvutuste peale kokku ikka palju ridu ning maatriksite lisamine ei pruugigi kuigi palju kasu tuua, pigem lihtsalt veel üks tülin juures millega arvestada. Mida rohkem ridu programmis, seda kergem on ka kusagile vigu teha. Enamlevinumate maatriksarvutuste ning ka maatriksi andmete hoidmiseks võib paaril lehel kirjutada vastava klassi või kirjutuslaiskuse puhul enesele võrgu pealt sobiv otsida. Siin näites on loodud klass suvalise soovitavate ridade ja veergude arvuga maatriksi tarvis. Peotäis konstruktoreid enamlevinud kujul andmete sisestamiseks ning meetod kahe maatriksi korrutamiseks, tegevus, mida graafikaarvutuste puhul enim vaja läheb. Lisaks staatilised meetodid üherealise maatriksi loomiseks, et kergemini punkti asukohta määravat maatriksit koostada. Nagu korrutamise puhul näha, tuleb seal kokku kolm tsüklit üksteise sisse paigutada. Kaks tükki ridade ning veergude läbi käimiseks ning kolmas, et arvutatava lahtri tarvis tehtavad korrutised kokku liita. Maatriksi sees olevaid andmeid hoitakse ja arvutatakse reaalarvudena arvutuste täpsuse huvides, joonistamise koordinaadid neile vastavatest pesadest aga küsitakse välja täisarvudena, et oleks kergem tulemusi täisarvulistele ekraanikoordinaatidele paigutada. public class Maatriks{ double m[][]; public Maatriks(int ridu, int veerge){ m=new double[ridu][veerge]; } public Maatriks(double a11, double a12, double a21, double a22){ m=new double[][]{ {a11, a12}, {a21, a22} }; } public Maatriks( double a11, double a12, double a13, double a21, double a22, double a23, double a31, double a32, double a33 ){ m=new double[][]{ {a11, a12, a13}, {a21, a22, a23}, {a31, a32, a33} }; } /** * Luuakse ühe rea ning kahe veeruga maatriks, algväärtusteks parameetritena * antud väärtused. Tarvitatakse arvutigraafikas tasandil suurendamise * ning keeramise tarvis. */ static Maatriks XY(double x, double y){ Maatriks m1=new Maatriks(1, 2); m1.m[0][0]=x; m1.m[0][1]=y; return m1; } static Maatriks XYZ(double x, double y, double z){ Maatriks m1=new Maatriks(1, 3); m1.m[0][0]=x; m1.m[0][1]=y; m1.m[0][2]=z; return m1; } public int X(){ return (int)m[0][0];} public int Y(){ return (int)m[0][1];} public int ridadeArv(){return m.length;} public int veergudeArv(){return m[0].length;} public Maatriks korruta(Maatriks m2){ if(veergudeArv()!=m2.ridadeArv()) throw new ArithmeticException("Vigane maatriksite suurus "+ veergudeArv()+" "+m2.ridadeArv()); Maatriks m3=new Maatriks(ridadeArv(), m2.veergudeArv()); for(int i=0; i