Processing math: 100%

Prijavi problem


Obeleži sve kategorije koje odgovaraju problemu

Još detalja - opišite nam problem


Uspešno ste prijavili problem!
Status problema i sve dodatne informacije možete pratiti klikom na link.
Nažalost nismo trenutno u mogućnosti da obradimo vaš zahtev.
Molimo vas da pokušate kasnije.

Час 6 - релативне координате - утврђивање

На прошлом часу смо се упознали са релативно задатим координатама и предностима тог механизма цртања. Утврдимо ово кроз још неколико примера.

Кућа - положај

Рецимо да сте написали овај програм, а циљ вам је да преправите програм тако да кућица може једноставно да се премешта:

 
1
import pygame as pg
2
3
pg.init()                          # uključivanje rada biblioteke PyGame
4
pg.display.set_caption("Кућа")     # podešavamo naslov prozora
5
(sirina, visina) = (300, 300)      # otvaramo prozor dimenzije 300x300
6
prozor = pg.display.set_mode((sirina, visina))
7
8
prozor.fill(pg.Color("darkgreen")) # bojimo pozadinu ekrana u svetlo plavo
9
10
pg.draw.polygon(prozor, pg.Color("red"), [(50, 150), (120, 100), (190, 150)]) # krov
11
pg.draw.rect(prozor, pg.Color("khaki"), ( 50, 150, 140, 100))  # kuca
12
pg.draw.rect(prozor, pg.Color("brown"), ( 60, 170,  30,  30))  # levi prozor
13
pg.draw.rect(prozor, pg.Color("brown"), (150, 170,  30,  30))  # desni prozor
14
pg.draw.rect(prozor, pg.Color("brown"), (100, 180,  40,  70))  # vrata
15
16
pg.display.update()   # prikazujemo nacrtano na ekranu
17
18
# petlja obrade događaja - čekamo dok korisnik ne isključi prozor
19
while pg.event.wait().type != pg.QUIT:
20
    pass
21
22
# isključivanje rada biblioteke PyGame
23
pg.quit()
24

(PyGame_house_detailed_fixed)

Нека је главна тачка (сидро) (x, y) = (50, 150). Довршите започето преправљање програма у пољу испод, у коме се цртање обавља у функцији kuca(x, y, boja_zidova). Када се уверите да цртежи у два програма изгледају исто (осим што су прозори различите величине), замените позив kuca(50, 150, pg.Color("khaki")) са следећа 4, да бисте добили слику као кад се кликне на дугме „Прикажи пример”:

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"))
26
 
1
import pygame as pg
2
3
pg.init()                          # uključivanje rada biblioteke PyGame
4
pg.display.set_caption("Кућа")     # podešavamo naslov prozora
5
(sirina, visina) = (500, 300)      # otvaramo prozor dimenzije 500x300
6
prozor = pg.display.set_mode((sirina, visina))
7
8
prozor.fill(pg.Color("darkgreen")) # bojimo pozadinu ekrana u tamno zeleno
9
10
def kuca(x, y, boja_zidova):
11
    pg.draw.polygon(prozor, pg.Color("red"), [(x, y), (x+???, y-???), (x+140, y)]) # krov
12
    pg.draw.rect(prozor, boja_zidova,       (x,       y,     140, 100))   # kuca
13
    pg.draw.rect(prozor, pg.Color("brown"), (x + ???, y + ???,  30,  30)) # levi prozor
14
    pg.draw.rect(prozor, pg.Color("brown"), (x + ???, y + ???, ???, ???)) # desni prozor
15
    pg.draw.rect(prozor, pg.Color("brown"), (x + ???, y + ???, ???, ???)) # vrata
16
17
kuca( 50, 150, pg.Color("khaki"))
18
pg.display.update()   # prikazujemo nacrtano na ekranu
19
20
# petlja obrade događaja - čekamo dok korisnik ne isključi prozor
21
while pg.event.wait().type != pg.QUIT:
22
    pass
23
24
# isključivanje rada biblioteke PyGame
25
pg.quit()
26

(PyGame_house_detailed_movable)

Саобраћајни знак од једнакостраничних троуглова

Напиши програм који исцртава саобраћајни знак укрштања са путем са првенством пролаза који је у облику жутог једнакостраничног троугла са црвеном ивицом, окренутог тако да му је хоризонтална основица горе.

Ефекат троугла који је жуте боје и има дебелу црвену ивицу постићи ћемо тако што ћемо нацртати прво већи црвени троугао, а затим мањи жути троугао. Та два троугла ћемо поставити тако да им се тежишта (уједно и све значајне тачке) поклапају и да су идентично оријентисани.

Приликом цртања саобраћајног знака потребно је да одредимо поступак којим се црта једнакостранични троугао ако му је познато сидро постављено у тежиште T за које ћемо претпоставити да има координате (tx,ty) и ако му је позната димензија (то може бити било дужина странице a, било висина h, јер се из једне од ових димензија друга једноставно израчунава на основу чувене везе h=a32, која се лако изводи применом Питагорине теореме на правоугли троугао чија је једна катета висина једнакостраничног троугла, друга половина странице, а хипотенуза је страница једнакостраничног троугла).

../_images/jednakostranicanTrougaoZnak.png

Пошто, како из математике знамо, тежиште троугла дели тежишну дуж (у овом случају то је уједно и висина) у односу 2:1, координате темена A и B су у односу на ову тачку померене (транслиране) на горе за 13h, док је тачка C померена на доле за 23h.

Координате x ових тачака одређујемо у односу на тачку T, односно дужину странице a. Тачка А је померена од тежишта за а2 ка левој ивици прозора. Тачка В је померена од тежишта за а2 средину ка десној ивици. Тачка C се хоризонално налази на линији тежишта.

Дакле, тачка A има координате (txa2,tyh3), тачка B има координате (tx+a2,tyh3), док тачка C има координате (tx,ty+2h3).

Пошто је потребно да нацртамо два троугла, можемо дефинисати функцију за цртање троугла и позвати је два пута (за исто тежиште, али различите боје и димензије). Тежиште ћемо поставити хоризонтално на средину прозора, док ћемо га вертикално поставити тако да троугао делује центриран по средини екрана. Оставићемо простор (маргину) од по 30 пиксела изнад и испод троугла, а тежиште троугла ћемо поставити тако да преосталу висину дели у односу 1:2.

На основу претходне дискусије допуни наредни програм.

26
 
1
import math
2
import pygame as pg
3
import pygamebg
4
5
(sirina, visina) = (300, 300) # otvaramo prozor
6
prozor = pygamebg.open_window(sirina, visina, "Саобраћајни знак")
7
8
def jedakostranicni_trougao(tx, ty, h, boja):
9
    a = h * 2 / math.sqrt(3)       # dužina stranice
10
    # koordinate temena - težiste deli visinu u odnosu 1 : 2
11
    A = (tx - a/2, ty - h/3)
12
    B = (???, ???)
13
    C = (???, ???)
14
    pg.draw.polygon(prozor, ???, ???)
15
16
# bojimo pozadinu prozora u belo
17
prozor.fill(pg.Color("white"))
18
margina = 30
19
h = visina - 2*margina
20
(tx, ty) = (sirina / 2, margina + h / 3)
21
jedakostranicni_trougao(tx, ty, h, pg.Color("red"))
22
jedakostranicni_trougao(tx, ty, 0.65*h, pg.Color("yellow"))
23
24
# prikazujemo prozor i čekamo da ga korisnik isključi
25
pygamebg.wait_loop()
26

(obojeni_trougao)

Проблеми приликом израчунавања параметара кругова

Подсетимо се да за разлику од функција за цртање линија и правоугаоника које примају и реалне аргументе, функција за цртање кругова захтева да су координате центра круга и дужина полупречника искључиво цели бројеви. Ово може довести до одређених проблема у програмима у којима се ти аргументи израчунавају у програму. Када видиш поруку TypeError: integer argument expected, got float, тада знај да је проблем у томе што је функцији за цртање круга уместо целог прослеђен неки реалан број и тај проблем можеш лако решити коришћењем неког облика заокруживања бројева.

Зато ћемо често у задацима у којима цртамо кругове, за израчунавање координата центара и полупречника кругова уместо реалног дељења (оператора /) користити целобројно дељење (оператор //) или ћемо користити заокруживање реалних бројева (функцијом round или функцијом int).

Провери да ли ово разумеш тако што ћеш одговорити на наредно питање.

Q-44: Након позива pg.draw.circle(prozor, boja, (x, y), r) пријављена је грешка TypeError: integer argument expected, got float. Шта може бити узрок те грешке?







Наредни програм црта цвет састављен од кругова, али не ради исправно и твој задатак је да га поправиш.

Цвет

Напиши програм који исцртава цвет који се састоји од централног жутог круга пречника 100 пиксела, око којег се налази 6 правилно распоређених латица розе боје, свака у облику круга, такође пречника 100 пиксела (центри латица се налазе у теменима правилног шестоугла, чији је центар у центру цвета, а дужина странице је 100 пиксела).

../_images/roze_cvet.png

За цртање круга потребно је знати координате центра и дужину полупречника круга. Пречник свих кругова је једнак, самим тим и полупречник r=a2. Нека је тачка О центар жутог, централног круга. Координате ове тачке означимо са (cx,cy). Ова тачка се налази у центру прозора и њене координате једнаке су половини висине, односно ширине прозора. Координате осталих центара кругова изразићемо такође преко координата (cx,cy) . Координате тачке А1 означимо са (x1,y1). Тачка А1 је за a померена (транслирана) од тачке О по оси x, тако да је x1, прва координата ове тачке једнака x1=cx+a, а друга координата ове тачке y1 једнака је y координати тачке О, тј. y1=cy. Координате тачке А2 означимо са (x2,y2). Ова тачка је у односу на тачку О померена (транслирана) за a2 по оси x, односно за висину h=a32 једнакостраничног троугла OA1A2 по оси y. На основу овога закључујемо да су координате тачке А2, (x2,y2)=(cx+a2,cy+h). Координате центра осталих кругова одређујемо на сличан начин.

На основу претходне дискусије, допуни наредни програм и поправи грешке везане за тип података бројева.

56
 
1
import math
2
import pygame as pg, pygamebg
3
4
(sirina, visina) = (400, 400)  # uključujemo prozor dimenzije 400x400 piksela
5
prozor = pygamebg.open_window(400, 400, "Blue circle")
6
7
# boje koje ćemo koristiti
8
BELA = (255, 255, 255)
9
ZUTA = (255, 255, 0)
10
ROZE = (255, 200, 200)
11
12
# bojimo pozadinu u belo
13
prozor.fill(BELA)
14
15
# koordinate centra prozora
16
(cx, cy) = (sirina / 2, visina / 2)
17
18
# precnici krugova - duzina stranice pravilnog sestougla u cijim se
19
# temenima nalaze centri krugova
20
a = 100
21
# visina karakteristicnog trougla sestougla
22
h = a * math.sqrt(3) / 2
23
24
# sva temena šestougla dele ove koordinate
25
x1 = cx - a
26
x2 = cx - a/2
27
x3 = cx + a/2
28
x4 = cx + a
29
y1 = ???
30
y2 = cy
31
y3 = ???
32
33
# koordinate temena šestougla
34
O = (cx, cy)
35
A1 = (x1, y2)
36
A2 = (???, ???)
37
A3 = (???, ???)
38
A4 = (???, ???)
39
A5 = (???, ???)
40
A6 = (???, ???)
41
42
# poluprecnik krugova
43
r = a / 2
44
45
# iscrtavamo krugove
46
pg.draw.circle(prozor, ZUTA, O, r)
47
pg.draw.circle(prozor, ROZE, A1, r)
48
pg.draw.circle(prozor, ROZE, A2, ???)
49
pg.draw.circle(prozor, ROZE, ???, ???)
50
pg.draw.circle(prozor, ROZE, ???, ???)
51
pg.draw.circle(prozor, ROZE, ???, ???)
52
pg.draw.circle(prozor, ROZE, ???, ???)
53
54
# prikazujemo prozor i čekamo da ga korisnik isključi
55
pygamebg.wait_loop()
56

(cvet)

Прелазак са апсолутних на релативне координате

Иако цртеже који се задају у односу на неко сидро обично креирамо имајући ово у старту у виду, постоји систематичан поступак којим од цртежа који је задат у апсолутним координатама можемо доћи до цртежа који је нацртан у односу на неко задато сидро (можемо усидрити цртеж). Покушајмо да резимирамо како можемо да уведемо сидро тј. да од цртежа у ком се јављају апсолутне координате уведемо релативне координате.

На пример, ако се црта круг помоћу pg.draw.circle(prozor, boja, (cx, cy), r), тада га можемо усидрити у тачку (x, y) тиме што позив заменимо са pg.draw.circle(prozor, boja, (x + (cx - x), y + (cy - y)), r). На пример, Ако круг нацртан помоћу pg.draw.circle(prozor, boja, (100, 50), r) желимо да усидримо у тачку (x, y) = (50, 100), тада ћемо га цртати помоћу pg.draw.circle(prozor, boja, (x + 50, y - 50), r). Слично можемо урадити и у случају осталих облика.

Провери да ли ово разумеш тако што ћеш одговорити на наредних неколико питања.

Q-45: Желимо да прилагодимо цртеж који се састоји од наредних облика, тако да се све црта у односу на сидро са координатама x=100, y=100.

5
 
1
pg.draw.circle(prozor, pg.Color("red"), (100, 100), 50, 1)
2
pg.draw.line(prozor, pg.Color("red"), (50, 50), (150, 150))
3
pg.draw.line(prozor, pg.Color("red"), (150, 50), (50, 150))
4
pg.draw.rect(prozor, pg.Color("red"), (50, 50, 100, 100))
5

(pygame_quiz_uvodjenje_sidra_code)

Које наредбе ће бити део прилагођеног цртежа?






Q-46: Круг нацртан наредбом pg.draw.circle(prozor, boja, (180, 80), 60) део је цртежа који желимо да прилагодимо тако да му основна тачка (сидро) буде у одређено променљивама x = 100 и y = 100. Која наредба ће бити део тако прилагођеног цртежа?







Покрени сада наредни програм и видећеш лице човечуљка. Прилагоди цртеж тако да се црта релативно у односу на сидро које се налази у центру плавог круга (у почетку је то (100,100)). Покретањем програма провери да ли ти је решење добро. Ако је све урађено како треба, цртеж ће се исправно померати док се миш помера.

35
 
1
import pygame as pg
2
import pygamebg
3
4
(sirina, visina) = (300, 300) # otvaramo prozor
5
prozor = pygamebg.open_window(sirina, visina, "Релативно цртање")
6
7
x = sirina // 2
8
y = visina // 2
9
a = 5
10
11
def crtanje():
12
    prozor.fill(pg.Color("white"))
13
    pg.draw.circle(prozor, pg.Color("blue"), (100, 100), 60)
14
    pg.draw.circle(prozor, pg.Color("yellow"), (75, 75), 15)
15
    pg.draw.circle(prozor, pg.Color("black"), (80, 80), 5)
16
    pg.draw.circle(prozor, pg.Color("yellow"), (125, 75), 15)
17
    pg.draw.circle(prozor, pg.Color("black"), (120, 80), 5)
18
    pg.draw.ellipse(prozor, pg.Color("red"), (75, 110, 50, 10))
19
20
def obradi_dogadjaj(dogadjaj):
21
    global x, y, a
22
    if dogadjaj.type == pg.MOUSEMOTION:
23
            (x, y) = dogadjaj.pos
24
            return True
25
    elif dogadjaj.type == pg.MOUSEBUTTONDOWN:
26
        if dogadjaj.button == 1:
27
            a += 1
28
            return True
29
        elif dogadjaj.button == 3:
30
            a -= 1
31
            return True
32
    return False
33
34
pygamebg.event_loop(crtanje, obradi_dogadjaj)
35

(PyGame_movable)

Размотримо сада како да поред цртања у односу на неки релативан положај (сидро) направимо наше цртеже скалабилним, тј. да се цртају у односу на релативно задату димензију.

Q-47: Круг нацртан наредбом pg.draw.circle(prozor, boja, (180, 80), 60) део је цртежа који желимо да прилагодимо тако да му главна тачка (сидро) буде у одређено променљивама x = 100 и y = 100, и да му основна величина буде a=5. Која наредба ће бити део тако прилагођеног цртежа?







Прилагоди сада додатно програм тако да се све црта релативно и у односу на јединичну величину (нека у почетку то буде 5). Ако је све урађено како треба, величина ће му се мењати кликом на лево тј. десно дугме миша.

35
 
1
import pygame as pg
2
import pygamebg
3
4
(sirina, visina) = (300, 300) # otvaramo prozor
5
prozor = pygamebg.open_window(sirina, visina, "Релативно цртање")
6
7
x = sirina // 2
8
y = visina // 2
9
a = 5
10
11
def crtanje():
12
    prozor.fill(pg.Color("white"))
13
    pg.draw.circle(prozor, pg.Color("blue"), (100, 100), 60)
14
    pg.draw.circle(prozor, pg.Color("yellow"), (75, 75), 15)
15
    pg.draw.circle(prozor, pg.Color("black"), (80, 80), 5)
16
    pg.draw.circle(prozor, pg.Color("yellow"), (125, 75), 15)
17
    pg.draw.circle(prozor, pg.Color("black"), (120, 80), 5)
18
    pg.draw.ellipse(prozor, pg.Color("red"), (75, 110, 50, 10))
19
20
def obradi_dogadjaj(dogadjaj):
21
    global x, y, a
22
    if dogadjaj.type == pg.MOUSEMOTION:
23
            (x, y) = dogadjaj.pos
24
            return True
25
    elif dogadjaj.type == pg.MOUSEBUTTONDOWN:
26
        if dogadjaj.button == 1:
27
            a += 1
28
            return True
29
        elif dogadjaj.button == 3:
30
            a -= 1
31
            return True
32
    return False
33
34
pygamebg.event_loop(crtanje, obradi_dogadjaj)
35

(PyGame_movable_scalable)