Pomeranje crteža

U prethodnim primerima smo napravili nekoliko crteža sastavljenih od osnovnih oblika. Pri tome je za svaki od tih oblika bilo potrebno odrediti tačan položaj da bi se svi delovi uklopili u celinu. Za neke crteže je bilo moguće (a u pojedinim zadacima i potrebno) da se koordinate pojedinih tačaka izračunaju na osnovu poznatih koordinata drugih tačaka. To računanje se moglo obaviti i van programa, a zatim u program samo uneti izračunate koordinate. Bolje je, međutim, da se takva računanja obave u samom programu, i to iz više razloga:

Sada ćemo još malo sistematizovati računanje koordinata i upotrebiti ga za jednostavnije pomeranje nacrtanih objekata. Pre nego što počnemo, bilo bi dobro da proverite potrebno predznanje i odgovorite na ova pitanja:

    Q-55: Koje su koordinate tačke koja se nalazi 10 piksela levo od tačke (50, 70)?

  • (50, 60)
  • Pokušajte ponovo
  • (50, 80)
  • Pokušajte ponovo
  • (40, 70)
  • Tačno
  • (60, 70)
  • Pokušajte ponovo
  • (40, 60)
  • Pokušajte ponovo

    Q-56: Koje su koordinate tačke koja se nalazi 10 piksela ispod tačke (50, 70)?

  • (50, 60)
  • Pokušajte ponovo
  • (50, 80)
  • Tačno
  • (40, 70)
  • Pokušajte ponovo
  • (60, 70)
  • Pokušajte ponovo
  • (40, 60)
  • Pokušajte ponovo

    Q-57: Pravougaonik je nacrtan pomoću pg.draw.rect(prozor, boja, (100, 150, 80, 90)). Kako se može nacrtati pravougaonik iste veličine koji se nalazi 30 piksela levo i 30 piksela iznad ovog pravougaonika?

  • pg.draw.rect(prozor, boja, (70, 120, 50, 60))
  • Pokušajte ponovo
  • pg.draw.rect(prozor, boja, (100, 150, 110, 120))
  • Pokušajte ponovo
  • pg.draw.rect(prozor, boja, (100, 150, 50, 60))
  • Pokušajte ponovo
  • pg.draw.rect(prozor, boja, (70, 120, 80, 90))
  • Tačno
  • pg.draw.rect(prozor, boja, (70, 180, 80, 90))
  • Pokušajte ponovo

    Q-58: Krug je nacrtan pomoću pg.draw.circle(prozor, boja, (100, 200), 40). Kako se može nacrtati krug iste veličine koji se nalazi iznad ovog kruga i dodiruje ga?

  • pg.draw.circle(prozor, boja, (100, 120), 40)
  • Tačno
  • pg.draw.circle(prozor, boja, (100, 160), 40)
  • Pokušajte ponovo
  • pg.draw.circle(prozor, boja, (120, 100), 40)
  • Pokušajte ponovo
  • pg.draw.circle(prozor, boja, (160, 100), 40)
  • Pokušajte ponovo
  • pg.draw.circle(prozor, boja, (20, 120), 40)
  • Pokušajte ponovo

Prepravljanje nepomičnog crteža u pomični

Pogledajmo kako je nacrtan oblak u sledećem primeru:

Oblak smo predstavili pomoću tri kruga, jednog većeg u sredini i dva manja oko njega:

pg.draw.circle(prozor, pg.Color("white"), (200, 200), 50)
pg.draw.circle(prozor, pg.Color("white"), (150, 200), 30)
pg.draw.circle(prozor, pg.Color("white"), (250, 200), 30)

Ako bismo hteli da taj oblak nacrtamo na različitim visinama, mogli bismo da ponavljamo ove tri naredbe, svaki put sa nekom novom vrednošću za \(y\) koordinatu centara ova tri kruga umesto 200, koliko je na početku. Na primer:

pg.draw.circle(prozor, pg.Color("white"), (200, 200), 50)
pg.draw.circle(prozor, pg.Color("white"), (150, 200), 30)
pg.draw.circle(prozor, pg.Color("white"), (250, 200), 30)

pg.draw.circle(prozor, pg.Color("white"), (200, 80), 50)
pg.draw.circle(prozor, pg.Color("white"), (150, 80), 30)
pg.draw.circle(prozor, pg.Color("white"), (250, 80), 30)

pg.draw.circle(prozor, pg.Color("white"), (200, 320), 50)
pg.draw.circle(prozor, pg.Color("white"), (150, 320), 30)
pg.draw.circle(prozor, pg.Color("white"), (250, 320), 30)
../_images/clouds.png

Na ovaj način, ne samo da program raste brže nego što mora, nego i svaku promenu treba da napravimo na tri mesta (na primer, ako umesto 320 želimo da probamo 330, tu promenu treba napraviti na tri mesta). Tri izmene nije mnogo, ali ako usvojimo takav način rada, na složenijim crtežima (i složenijim programima uopšte) bismo imali sve više problema.

Umesto ovoga, bolje je da napravimo funkciju i da \(y\) koordinatu centara prosleđujemo kao parametar:

def oblak(yc):
    pg.draw.circle(prozor, pg.Color("white"), (200, yc), 50)
    pg.draw.circle(prozor, pg.Color("white"), (150, yc), 30)
    pg.draw.circle(prozor, pg.Color("white"), (250, yc), 30)

oblak(200)
oblak(80)
oblak(320)

Novi program je pregledniji i lakši za dalje menjanje i isprobavanje. Za više oblaka, ili složenije oblake, prednost ovakvog pristupa bi bila još veća.

A kako bi izgledalo pomeranje oblaka na levo ili desno? Trebalo bi \(x\) koordinate 200, 150, 250 centara krugova sve povećati ili smanjiti za istu vrednost. Na primer, ako bismo kao \(x\) koordinate upisali 260, 210, 310, ceo oblak bi bio pomeren za 60 piksela desno.

Bilo bi dobro da možemo da pomoću samo jednog broja zadamo i vodoravni položaj oblaka. Da bismo to postigli, primetimo da su centri manjih krugova udaljeni po 50 piksela od centra srednjeg kruga na levo i desno. Ova rastojanja se ne menjaju pri pomeranju oblaka. To znači da ako sa \(X_c\) označimo \(x\) koordinatu centra srednjeg kruga, onda centri manjih krugova imaju \(x\) koordinate \(X_c - 50\) i \(X_c + 50\). Zahvaljujući ovoj stalnoj vezi (koja ne zavisi od položaja oblaka), sada možemo u funkciju za crtanje oblaka da uvedemo i parametar \(x\):

def oblak(xc, yc):
    pg.draw.circle(prozor, pg.Color("white"), (xc, yc), 50)
    pg.draw.circle(prozor, pg.Color("white"), (xc - 50, yc), 30)
    pg.draw.circle(prozor, pg.Color("white"), (xc + 50, yc), 30)

oblak(200, 200)
oblak(200, 80)
oblak(200, 320)

Bilo koji od ova tri oblaka bismo sada lako mogli da pomerimo na primer 60 piksela na desno, tako što u pozivu funkcije na mestu \(x\) koordinate (prvog parametra) umesto 200 upišemo 260. Jednako lako je i napraviti crtež sa nekoliko oblaka. Boja, odnosno nijansa sive, takođe može da bude parametar funkcije. Na taj način neki oblaci mogu da budu tamniji, a neki svetliji.

Kada iskoristimo sve pomenuto, možemo da napravmo program koji crta nekoliko oblaka raznih nijansi, na primer:

Rezimirajmo, uz mala uopštenja, šta je potrebno da se uradi da bismo mogli da prkazujemo jedan crtež na raznim mestima:

  • Treba da izaberemo jednu tačku čije se koordinate zadaju direktno. Ovu izabranu tačku zvaćemo glavna tačka, (ponekad se ova tačka naziva i sidro, engl. anchor). U primeru oblaka, glavna tačka je centar srednjeg kruga.

  • Nakon izbora glavne tačke, koordinate svih ostalih bitnih tačaka određujemo u odnosu na nju, tako što na koordinate glavne tačke dodajemo ili oduzimamo određeni pomeraj. U primeru sa oblakom, da bismo dobili \(x\) koordinatu centra levog kruga, od \(x\) koordinate glavne tačke tačke (centra srednjeg kruga) oduzimamo 50 piksela, a za desni krug dodajemo 50 piksela.

U opštem slučaju, na crtežu može biti i drugih oblika osim krugova. Tačke koje određuju položaje tih oblika su:

  • za duž: njeni krajevi

  • za mnogougao: njegova temena

  • za krug: njegov centar

  • za pravougaonik: njegovo gornje levo teme

  • za elipsu: gornje levo teme pravougaonika u koji je upisana ta elipsa

Sve ove tačke treba zadati u odnosu na glavnu tačku, to jest izraziti njihove koordinate kao koordinate glavne tačke uvećane ili umanjene za neku vrednost.

Proverite koliko ste razumeli prethodna objašnjenja i odgorovite na pitanja.

    Q-59: Želimo da prilagodimo crtež koji se sastoji od nekoliko oblika, tako da se sve crta u odnosu na sidro sa koordinatama x=100, y=100. Jedna od naredbi koje formiraju crtež je

    Koja naredba treba da zameni datu?

  • pg.draw.circle(prozor, pg.Color("red"), (x, y), 50, 1)
  • Pokušajte ponovo
  • pg.draw.circle(prozor, pg.Color("red"), (x+120, y+90), 50, 1)
  • Pokušajte ponovo
  • pg.draw.circle(prozor, pg.Color("red"), (x+20, y-10), 50, 1)
  • Tačno
  • pg.draw.circle(prozor, pg.Color("red"), (x-20, y+10), 50, 1)
  • Pokušajte ponovo

    Q-60: Želimo da prilagodimo crtež koji se sastoji od nekoliko oblika, tako da se sve crta u odnosu na sidro sa koordinatama x=100, y=100. Jedna od naredbi koje formiraju crtež je

    Koja naredba treba da zameni datu?

  • pg.draw.line(prozor, pg.Color("red"), (x-50, y-50), (150, 150))
  • Pokušajte ponovo
  • pg.draw.line(prozor, pg.Color("red"), (x-50, y-50), (x+50, y+50))
  • Tačno
  • pg.draw.line(prozor, pg.Color("red"), (x-50, x+50), (y-50, y+50))
  • Pokušajte ponovo
  • pg.draw.line(prozor, pg.Color("red"), (x+50, y+50), (x+150, y+150))
  • Pokušajte ponovo

    Q-61: Želimo da prilagodimo crtež koji se sastoji od nekoliko oblika, tako da se sve crta u odnosu na sidro sa koordinatama x=100, y=100. Jedna od naredbi koje formiraju crtež je

    Koja naredba treba da zameni datu?

  • pg.draw.rect(prozor, pg.Color("red"), (x-50, y-50, x, y))
  • Pokušajte ponovo
  • pg.draw.rect(prozor, pg.Color("red"), (x, y, 100, 100))
  • Pokušajte ponovo
  • pg.draw.rect(prozor, pg.Color("red"), (x+50, y+50, 100, 100))
  • Pokušajte ponovo
  • pg.draw.rect(prozor, pg.Color("red"), (x-50, y-50, 100, 100))
  • Tačno

    Q-62: Želimo da pomerimo crtež koji se sastoji od nekoliko oblika nadesno za 100 piksela. Označite tačna tvrđenja.

  • Umesto pg.draw.circle(prozor, boja, (x, y), r, d) pozvaćemo pg.draw.circle(prozor, boja, (x+100, y), r, d).
  • Tačno
  • Umesto pg.draw.circle(prozor, boja, (x, y), r, d) pozvaćemo pg.draw.circle(prozor, boja, (x-100, y-100), r, d).
  • Pokušajte ponovo
  • Umesto pg.draw.rect(prozor, boja, (x, y, w, h), d) pozvaćemo pg.draw.circle(prozor, boja, (x+100, y, w+100, h), d).
  • Pokušajte ponovo
  • Umesto pg.draw.rect(prozor, boja, (x, y, w, h), d) pozvaćemo pg.draw.rect(prozor, boja, (x+100, y, w, h), d).
  • Tačno
  • Umesto pg.draw.rect(prozor, boja, (x, y, w, h), d) pozvaćemo pg.draw.rect(prozor, boja, (x-100, y, w, h), d).
  • Pokušajte ponovo

Slede još neki primeri pretvaranja fiksnog crteža u pomični.

Meda - položaj

Dat je sledeći program, koji prikazuje glavu medvedića igračke:

U programu se sedam puta poziva funkcija uokviren_krug, koja zadati krug uokviruje crnom bojom (mada je za tri mala crna kruga mogla je da bude pozvana i samo funkcija circle). Da bismo mogli da menjamo položaj crteža, izaberimo glavnu tačku (sidro). Neka to bude centar velikog kruga, to jest glave medvedića. Koordinate ove tačke su (250, 150). Sada je potrebno da koordinate centara svih ostalih krugova izrazimo polazeći od glavne tačke, pomerajući se za potreban broj piksela u smeru \(x\) i \(y\) ose. Uzmimo kao primer desno uvo medvedića.

\(x\) koordinata centra desnog uveta je \(310 = 250 + 60\), dok je \(y\) koordinata \(80 = 150 - 70\). Odavde se vidi da koordinate centra desnog uveta možemo u programu da napišemo kao (cx + 60,  cy - 70), gde su (cx, cy) koordinate glavne tačke. Sprovedite isti postupak za ostale krugove i dovršite funkciju crtaj_medu.

Ovako napisan program nam omogućava da jednostavno prikazujemo medvediće na raznim mestima na ekranu. Na primer, možete da poziv funkcije

crtaj_medu(sirina // 2, visina // 2)

koja crta medvedića sa glavnom tačkom u centru prozora (kao što je i bio), zamenite sa sledeća dva:

crtaj_medu(sirina // 2 - 120, visina // 2)
crtaj_medu(sirina // 2 + 120, visina // 2)

Isprobajte ovo! Bilo bi znatno teže nacrtati drugog medevedića da nismo početni program prilagodili za ovakvu upotrebu.

Kuća - položaj

Recimo da ste napisali ovaj program, a cilj vam je da prepravite program tako da kućica može jednostavno da se premešta:

Neka je glavna tačka (x, y) = (50, 150). Dovršite započeto prepravljanje programa u polju ispod, u kome se crtanje obavlja u funkciji kuca(x, y, boja_zidova). Kada se uverite da crteži u dva programa izgledaju isto (osim što su prozori u kojima se crta različite veličine), zamenite poziv kuca( 50, 150, pg.Color("khaki")) sa sledeća 4, da biste dobili sliku kao kad se klikne na dugme „Prikaži primer”:

kuca(150,  90, pg.Color(220, 220, 220))
kuca(220, 130, pg.Color("white"))
kuca(350, 160, (255,255,150))
kuca( 50, 150, pg.Color("khaki"))