Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /////////////////////////////////////////////////////////////////////////////////////////////////////
- // JAVA primjer za crtanje geometrijskih likova
- // Autor: Kristijan Burnik, udruga informatičara Božo Težak
- // Mail: kristijanburnik [at] gmail [dot] com
- /////////////////////////////////////////////////////////////////////////////////////////////////////
- // Sljedeći java program nije testiran tako da zasigurno ima pogrešaka
- // međutim svrha je pokazati kako riješiti određeni problem pomoću objektno orijentiranog programiranja
- //
- // Program je veoma jednostavan primjer geometrijskog crtanja.
- // Cilj je pokazati kako pomoću klasa i objekata reprezentirati geometrijske likove i druge entitete
- // te ostvariti osnovno ponašanje istih i pružati mogućnost iscrtavanja na neki medij pomoću raster grafike
- // ista implementacija se može lako prilagoditi i za vektorsko iscrtavanje.
- //
- // Napominjem da ovo nije funkcionalna implementacija nego služi više kao skup smjernica
- // kod izrade programa u objektno orijentiranoj paradigmi - čitatelju se preporuča da rabi ovaj primjer
- // isključivo kao uzorak pomoću kojeg piše vlastite programe rabeći i poštujući svojstva objektne pardigme
- //
- // Ispravke i pitanja molim slati na gore naveden e-mail
- /////////////////////////////////////////////////////////////////////////////////////////////////////
- // veoma jednostavna klasa koja predstavlja bilo kakvu točku u ravnini
- public class Tocka {
- // ovo su zaštićene varijable (x i y),
- // što znači da se smiju čitati i pisati samo
- // iz ove klase i svake klase koja se nasljeduje iz ove (npr. kvadrat)
- // to radimo namjerno kako bi promjenu x ili y koordinate mogli pratiti
- // te ne dopustiti vanjskim pozivateljima da izravno mijenjaju vrijednosti ovih varijabli
- // dakle nije moguće napisati Tocka t = new Tocka(); t.x = 100; jer je varijabla x zaštićena
- protected float x; // X koordinata u ravnini
- protected float y; // Y koordinata u ravnini
- // definiramo konstruktor za tocku, to je metoda koja se poziva jednom kada stvorimo objekt
- // tj. pomoću nje možemo inicijalizirati varijable i pripremiti objekt za upotrebu
- public Tocka() {
- x = 0;
- y = 0;
- // mogli smo pozvati i metodu Pomakni(0,0) umjesto ručnog podešavanja
- }
- // mozemo imati vise od jednog konstruktora (npr. kada unaprijed znamo koordinate točke)
- // međutim pri stvaranju objekta (sa ključnom riječi "new") možemo pozvati isključivo jedan konstruktor
- // tako možemo pisati Tocka t = new Tocka(); ako želimo točku na poziciji (x = 0, y = 0)
- // ili možeemo pisati Tocka t = new Tocka(100,300); ako želimo točku na poziciji (x = 100, y = 300)
- public Tocka(float pocetniX, float pocetniY) {
- x = pocetniX;
- y = pocetniY;
- // mogli smo pozvati i metodu Pomakni(pocetniX,pocetniY) umjesto ručnog podešavanja
- }
- // vraća x koordinatu (Getter za X)
- // budući je varijabla x zaštićena, ne možemo je drukčije pročitati izvan ove klase
- // a ovaj način čitanja zaštićenih varijabli, tj. metoda se naziva "Getter" jer pomoću nje dobivamo vrijednost nekog svojstva
- // isto tako po potrebi postoji i tzv. "Setter" metoda kojom možemo postaviti vrijednost nekoj zaštićenoj varijabli (svojstvu)
- public float X() {
- return x;
- }
- // vraća y koordinatu (Getter za Y)
- public float Y() {
- return y;
- }
- // metoda kojom pomičemo točku
- // (npr. želimo napraviti da se pri pomaku dogodi crtanje lika ili sl. )
- // ovu metodu bi teoretski mogli zvati "Setterom" međutim Setter metode utječu isključivo na jedno svojstvo,
- // a ovdje mijenjamo oba svojstva X i Y
- public void Pomakni(float noviX, float noviY) {
- x = noviX;
- y = noviY;
- }
- }
- // Platno je klasa koju koristimo za crtanje bilo na ekran, bilo u PDF, u datoteku, na printer - nije vazno.
- public class Platno {
- // visina i sirina povrsine na kojoj crtamo
- private int sirina;
- private int visina;
- // popis geometrijskih likova koji ce se crtati na platnu
- private ArrayList<GeometrijskiLik> likovi = new ArrayList<GeometrijskiLik>();
- // matrica koja predstavlja crtež (raster)
- // tu matricu možemo kasnije proslijediti na ekran, u datoteku, na printer itd. kako bi se sve iscrtalo
- boolean[][] matrica;
- // metoda kojom brišemo "ekran"
- public void Brisi() {
- for (int i = 0 ; i < sirina; i++) {
- for (int j = 0 ; j < visina; j++) {
- // ovaj pixel postaje "bijeli"
- matrica[i][j] = false;
- }
- }
- }
- // konstruktor za platno, moramo znati dimenzije
- public Platno(int sirina, int visina) {
- this.sirina = sirina;
- this.visina = visina;
- // pripremamo matricu na kojoj ce se sve "crtati"
- matrica = new boolean[sirina][visina];
- // brisemo "ekran" - iako ce vec biti "prazan"
- Brisi();
- }
- // vraca matricu koja predstavlja "ekran", "papir" ili štoveć
- // tu metodu će pozivati objekt koji će u konačnici crtati sve što je na platnu
- // tj. tu matricu možemo proslijediti na printer ili u datoteku i sl.
- public boolean[][] Matrica() {
- return matrica;
- }
- // dodajemo novi lik na platno
- public void DodajLik(GeometrijskiLik geolik) {
- likovi.Add(geolik);
- }
- // metoda kojom crtamo sve likove na platno
- public void Crtaj() {
- // prvo brisemo platno kako ne bi imali zaostatke od "prijašnjih" crtanja
- Brisi();
- // crtaj likove redom kako su bili dodani
- for (int i = 0; i < likovi.size() ; i++) {
- // pozivamo metodu crtaj, naravno prosljeđujemo "ovo" platno jer se na njemu sve crta
- likovi.get(i).Crtaj(this);
- }
- }
- // pomocu ovih metoda se likovi mogu crtati
- public void CrtajLiniju(Tocka pocetna, Tocka krajnja) {
- // naredbe za crtanje linije
- // potrebno je rijesiti jednadzbu za pravac kroz dvije točke
- // svaka x i y koordinata koja zadovoljava jednadžbu će biti crtana kao točka
- }
- public void CrtajKruznicu (Tocka srediste, float polumjer) {
- // naredbe za crtanje kruznice
- // potrebno riješiti jednadžbu za kružnicu
- // svaka x i y koordinata koja zadovoljava jednadžbu će biti nacrtana
- }
- public void CrtajTocku(Tocka t) {
- // dovoljno je postaviti pixel na toj poziciji u "crnu" boju
- matrica[(int) t.X()][ (int) t.Y()] = true
- }
- }
- // definiramo klasu koja može predstavljati bilo koji geometrijski lik u ravnini (dakle veoma općenito)
- // nasljedujemo svojstva od točke budući geometrijski lik ima HVATIŠTE, odnosno točku koja predstavlja njegovu poziciju u ravnini
- // to znači da klasa GeometrijskiLik i sve klase koje ju "extend-aju" (nasljeđuju, tj. proširuju)
- // također imaju javno dostupne metode:
- // - X()
- // - Y()
- // - pomakni(float noviX, float noviY)
- public class GeometrijskiLik extends Tocka {
- // koristimo ovu varijablu kako bi mogli rotirati lik
- protected float stupnjevi = 0;
- // ne znamo o kojem geometrijskom liku se radi, niti kako se crta (jer ovo je veoma općenita klasa)
- // međutim znamo da bi se svaki KONKRETNI geometrijski lik trebao moći nacrtati stoga bi svaka KONKRETNA KLASA
- // koja nasljeduje ovu klasu trebala IMPLEMENTIRATI OVU METODU (imati naredbe za crtanje)
- // da bi smo crtali lik, moramo znati gdje ga crtamo, pa je potrebno definirati i platno na kojem ce biti crtan
- // apstraktne metode kao takve nemaju implementaciju (nemaju tijelo funkcije, odnosno vitičaste zagrade)
- public abstract void Crtaj(Platno platno);
- // jednako tako ne znamo kako će se računati površina, međutim svaki lik ima površinu
- public abstract float Povrsina();
- // isto tretiramo i opseg
- public abstract float Opseg();
- // isto tako bi bilo korisni dobiti težište lika:
- public abstract Tocka Teziste();
- // korisno je imati i metodu kojom možemo povećati ili smanjiti lik
- // međutim posebno treba implementirati za kvadrat, kružnicu, pravokutnik, elipsu itd.
- public abstract void Skaliraj(float faktorSkaliranja);
- // znamo da bi bilo korisno da možemo rotirati bilo koji geometrijski lik
- // općenito je dovoljno imati pojam o tome za koliko stupnjeva je zarotiran lik od svoje uobičajene rotacije
- // s obzirom na svoje hvatište
- public void Rotiraj(float zaKolikoStupnjeva) {
- stupnjevi += zaKolikoStupnjeva;
- stupnjevi %= 360;
- }
- }
- // klasa Kvadrat nasljeđuje apstraktnu klasu GeometrijskiLik te ubacuje dodatne metode
- // dakle Kvadrat samim time što "extend-a" GeometrijskiLik već ima ugrađene javne metode:
- // nasljeđeno od Tocka:
- // - X()
- // - Y()
- // - pomakni(float noviX, float noviY)
- // nasljeđeno od GeometrijskiLik:
- // - Crtaj(Platno platno)
- // - Povrsina()
- // - Opseg()
- // - Teziste()
- // - Skaliraj()
- // - Rotiraj()
- // a također nasljeđuje i zaštićene varijable (x i y koordinate od točke) te varijablu stupnjevi iz GeometrijskiLik
- // kada kažemo da se nešto nasljeđuje (metoda ili varijabla), to znači da je to isto također dio i nasljeđujuće klase
- public class Kvadrat extends GeometrijskiLik {
- // rotaciju necemo implementirati u ovom primjeru
- // Kvadrat je dovoljno opisati sa dvije točke
- // jedna je njegovo hvatište (nasljedeno iz klase Tocka koju nasljeđuje GeometrijskiLik)
- // nazovimo to gornjim lijevim vrhom
- // a druga je tocka donji desni vrh
- // varijablu označujemo privatnom, a to znači da isključivo klasa Kvadrat ima pristup ovoj varijabli
- // dakle kad bismo napravili klasu PosebanKvadrat koja nasljeduje Kvadrat, ona ne bi mogla pristupiti ovoj varijabli
- private Tocka DonjiDesniVrh;
- // definiramo konstruktor za kvadrat, dovoljno je znati točku hvatišta i duljinu stranice
- // kako bismo jedinstveno odredili bilo koji konkretni kvadrat
- public Kvadrat(Tocka GornjiLijeviVrh, float duljinaStranice) {
- // budući Kvadrat nasljeđuje sve iz klase Tocka preko klase GeometrijskiLik, možemo pomaknuti "ovu" točku
- // možemo još reći i da je Kvadrat djelomično sastavljen i od točke (hvatišta)!
- this.pomakni(GornjiLijeviVrh.X(), GornjiLijeviVrh.Y());
- DonjiDesniVrh = new Tocka(GornjiLijeviVrh.X() + duljinaStranice, GornjiLijeviVrh.Y() + duljinaStranice);
- }
- // ova metoda prepisuje (override-a) metodu Crtaj iz GeometrijskiLik
- // dakle Crtaj u klasi Kvadrat sada više nije apstraktna metoda koja ne radi ništa
- // već implementiramo postupak potreban za iscrtavanje (implementirati == funkcionalno ostvariti postupak)
- public void Crtaj(Platno platno) {
- // kvadrat crtamo pomoću četiri linije // "this" predstavlja ovaj objekt (samog sebe)
- Tocka goreLijevo = new Tocka(this.X(), this.Y());
- Tocka goreDesno = new Tocka(DonjiDesniVrh.X(), this.Y());
- Tocka doljeLijevo = new Tocka(this.X(),DonjiDesniVrh.Y());
- Tocka doljeDesno = DonjiDesniVrh;
- // crtamo redom linije: gore, desno, dolje, lijevo
- // prosljeđujemo točke vrhova jer se linija crta pomoću dvije krajnje točke
- platno.CrtajLiniju( goreLijevo, goreDesno );
- platno.CrtajLiniju( goreDesno, doljeDesno );
- platno.CrtajLiniju( doljeDesno, doljeLijevo );
- platno.CrtajLiniju( doljeLijevo, goreLijevo );
- }
- // kvadrat ima svoju stranicu, a to je svojstveno za mnogokute, međutim ne i za krivulje poput kružnice
- public float Stranica() {
- return DonjiDesniVrh.X() - X();
- }
- // mozda je korisno znati i dijagonalu : stranica * (korijen iz 2)
- public float DuljinaDijagonale() {
- return Stranica() * Math.sqrt( 2);
- }
- // povrsinu "override-amo" - pisemo jednostavnu formulu za povrsinu kvadrata
- public float Povrsina() {
- return Stranica() * Stranica() ;
- }
- // slično tretiramo i opseg
- public float Opseg() {
- return Stranica() * 4;
- }
- // Težište kvadrata je središnja točka
- public Tocka Teziste() {
- return new Tocka( X() + Stranica() / 2 , Y() + Stranica() / 2 );
- }
- // Skaliramo tako da pomicemo tocku donjeg desnog vrha
- // dakle znamo da se tako to radi za kvadrat,
- // međutim za druge likove je implementacija drukčija
- // npr. za kružnicu bi bilo dovoljno pomnožiti polumjer s faktorom skaliranja
- public void Skaliraj(float faktorSkaliranja) {
- DonjiDesniVrh.Pomakni( DonjiDesniVrh.X() * faktorSkaliranja, DonjiDesniVrh.Y() * faktorSkaliranja );
- }
- }
- // definiramo klasu Kruznica koja je također geometrijski lik
- // međutim ona se malo drukčije ponaša i ima drukčija svojstva od kvadrata
- public class Kruznica extends GeometrijskiLik {
- // broj PI je konstanta koja je javno dostupna
- // to je statička varijabla što znači da joj možemo pristupiti direktno preko klase (ne moramo stvarati instancu kružnice)
- // npr. ako želimo dohvatiti ovu konstantu, dovoljno je bilo gdje u programu pisati Kruznica.PI
- public static final float PI = 3.14159;
- // štitimo polumjer kružnice,
- private float polumjer;
- // konstruktor za kružnicu, slično kao i za kvadrat
- public Kruznica(Tocka srediste, float polumjerKruznice) {
- this.Pomakni(srediste.X(),srediste.Y());
- polumjer = polumjerKruznice;
- }
- // metoda za crtanje kružnice je već "implementirana" u klasi platno
- public void Crtaj(Platno platno) {
- platno.CrtajKruznicu( Srediste() , polumjer);
- }
- // ovo je "Getter" metoda za polumjer
- public float Polumjer() {
- return polumjer;
- }
- // imamo i središte koja je ista kao i hvatište
- public Tocka Srediste() {
- return new Tocka(X(),Y());
- }
- // - povrsinu "override-amo" - pisemo jednostavnu formulu za povrsinu kružnice r^2 * PI
- public float Povrsina() {
- return polumjer * polumjer * PI ;
- }
- // - slično tretiramo i opseg // 2 * r * Pi
- public float Opseg() {
- return 2 * polumjer * PI ;
- }
- // Težište kružnice je središnja točka
- public Tocka Teziste() {
- return Srediste();
- }
- // za kružnicu je dovoljno pomnožiti polumjer s faktorom skaliranja
- public void Skaliraj(float faktorSkaliranja) {
- polumjer *= faktorSkaliranja;
- }
- }
- // glava klasa tj klasa koja se poziva pri pokretanju programa
- class GlavnaKlasa
- {
- public static void main(String args[])
- {
- // kreiramo novo platno, to znači da stvaramo NOVI OBJEKT, tj. instancu klase Platno
- Platno platno = new Platno(1024,768);
- // kreiramo nekoliko kvadrata, ovdje dolaze do izražaja konstruktori za točku i kvadrat
- Kvadrat a = new Kvadrat( new Tocka(10,10), 100 );
- Kvadrat b = new Kvadrat( new Tocka(200,200), 200 );
- Kvadrat c = new Kvadrat( new Tocka(200,0), 30 );
- // kreiramo nekoliko kruznica, konstruktor je veoma sličan: točka hvatišta te polumjer
- Kruznica d = new Kruznica( new Tocka (300,500), 300 );
- Kruznica e = new Kruznica( new Tocka (300,500), 100 );
- // postavljamo sve likove na platno, neovisno da li je to kvadrat, kružnica ili neki drugi konkretni lik
- platno.DodajLik(a);
- platno.DodajLik(b);
- platno.DodajLik(c);
- platno.DodajLik(d);
- platno.DodajLik(e);
- // iscrtavamo platno (sve likove na njemu)
- platno.Crtaj();
- // matricu od platna šaljemo na printer
- Printer printer = new Printer(" [LPT1] /* Canon Pixma MX300 */");
- printer.PostaviMatricu( platno.Matrica() );
- printer.ZapocniIspis();
- // Klasa printer kao takva ne postoji, ali zamišljamo da je nešto poput:
- /*
- public class Printer {
- private boolean[][] matrica;
- private String opisnik; // opisnik pomocu kojeg hardverski identificiramo printer
- public Printer(String opisnikPrintera) {
- opisnik = opisnikPrintera;
- // povezivanje sa stvarnim printerom
- // ...
- }
- public void PostaviMatricu(boolean[][] mat) {
- matrica = mat;
- }
- public void ZapocniIspis() {
- // naredbe za slanje informacija na stvarni printer
- // ...
- }
- }
- */
- // Sada zelimo ispisati povrsinu i opseg svakog geometrijskog lika na konzolu
- // prvo napravimo polje gdje ubacimo sve likove
- GeometrijskiLik[] likovi = { a, b, c, d, e};
- // uočiti da iako su varijable a,b i c tipa Kvadrat, a "d" i "e" Kruznica,
- // svi zajedno su instance klase GeometrijskiLik te ih u tom smislu možemo tako tretirati
- // te znamo da svi imaju metode za opseg i površinu
- // sličan primjer je implementiran u klasi Platno gdje ono sadrži ArrayList geometrijskih likova
- // a samom platnu uopće nije važno da li crta kvadrat, kružnicu ili nešto treće
- // - njoj je jedino važno da taj lik implementira metodu "Crtaj", a za pojedinosti crtanja se brine
- // taj konkretni geometrijski lik.
- for (int i = 0; i < 5; i++) {
- // budući ne znamo kojeg je tipa trenutni geometrijski lik (likovi[i])
- // moramo rabiti ključnu riječ "instanceof" kako bi znali da je nešto Kvadat, Kruznica ili nešto drugo
- if ( likovi[i] instanceof Kvadrat ) {
- System.out.println("Kvadat");
- } else if ( likovi[i] instanceof Kruznica ) {
- System.out.println("Kruznica");
- } else {
- System.out.println("Neki drugi geometrijski lik");
- }
- System.out.print( "Opseg je " );
- System.out.print( likovi[i].Opseg() );
- System.out.println();
- System.out.print( "Povrsina je " );
- System.out.print( likovi[i].Povrsina() );
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement