Померање цртежа

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

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

    Q-55: Kоје су координате тачке која се налази 10 пиксела лево од тачке (50, 70)?

  • (50, 60)
  • Покушајте поново
  • (50, 80)
  • Покушајте поново
  • (40, 70)
  • Тачно
  • (60, 70)
  • Покушајте поново
  • (40, 60)
  • Покушајте поново

    Q-56: Kоје су координате тачке која се налази 10 пиксела испод тачке (50, 70)?

  • (50, 60)
  • Покушајте поново
  • (50, 80)
  • Тачно
  • (40, 70)
  • Покушајте поново
  • (60, 70)
  • Покушајте поново
  • (40, 60)
  • Покушајте поново

    Q-57: Правоугаоник је нацртан помоћу pg.draw.rect(prozor, boja, (100, 150, 80, 90)). Како се може нацртати правоугаоник исте величине који се налази 30 пиксела лево и 30 пиксела изнад овог правоугаоника?

  • pg.draw.rect(prozor, boja, (70, 120, 50, 60))
  • Покушајте поново
  • pg.draw.rect(prozor, boja, (100, 150, 110, 120))
  • Покушајте поново
  • pg.draw.rect(prozor, boja, (100, 150, 50, 60))
  • Покушајте поново
  • pg.draw.rect(prozor, boja, (70, 120, 80, 90))
  • Тачно
  • pg.draw.rect(prozor, boja, (70, 180, 80, 90))
  • Покушајте поново

    Q-58: Круг је нацртан помоћу pg.draw.circle(prozor, boja, (100, 200), 40). Како се може нацртати круг исте величине који се налази изнад овог круга и додирује га?

  • pg.draw.circle(prozor, boja, (100, 120), 40)
  • Тачно
  • pg.draw.circle(prozor, boja, (100, 160), 40)
  • Покушајте поново
  • pg.draw.circle(prozor, boja, (120, 100), 40)
  • Покушајте поново
  • pg.draw.circle(prozor, boja, (160, 100), 40)
  • Покушајте поново
  • pg.draw.circle(prozor, boja, (20, 120), 40)
  • Покушајте поново

Преправљање непомичног цртежа у помични

Погледајмо како је нацртан облак у следећем примеру:

Облак смо представили помоћу три круга, једног већег у средини и два мања око њега:

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)

Ако бисмо хтели да тај облак нацртамо на различитим висинама, могли бисмо да понављамо ове три наредбе, сваки пут са неком новом вредношћу за \(y\) координату центара ова три круга уместо 200, колико је на почетку. На пример:

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

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

Уместо овога, боље је да направимо функцију и да \(y\) координату центара прослеђујемо као параметар:

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)

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

А како би изгледало померање облака на лево или десно? Требало би \(x\) координате 200, 150, 250 центара кругова све повећати или смањити за исту вредност. На пример, ако бисмо као \(x\) координате уписали 260, 210, 310, цео облак би био померен за 60 пиксела десно.

Било би добро да можемо да помоћу само једног броја задамо и водоравни положај облака. Да бисмо то постигли, приметимо да су центри мањих кругова удаљени по 50 пиксела од центра средњег круга на лево и десно. Ова рaстојања се не мењају при померању облака. То значи да ако са \(X_c\) означимо \(x\) координату центра средњег круга, онда центри мањих кругова имају \(x\) координате \(X_c - 50\) и \(X_c + 50\). Захваљујући овој сталној вези (која не зависи од положаја облака), сада можемо у функцију за цртање облака да уведемо и параметар \(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)

Било који од ова три облака бисмо сада лако могли да померимо на пример 60 пиксела на десно, тако што у позиву функције на месту \(x\) координате (првог параметра) уместо 200 упишемо 260. Једнако лако је и направити цртеж са неколико облака. Боја, односно нијанса сиве, такође може да буде параметар функције. На тај начин неки облаци могу да буду тамнији, а неки светлији.

Када искористимо све поменуто, можемо да направмо програм који црта неколико облака разних нијанси, на пример:

Резимирајмо, уз мала уопштења, шта је потребно да се уради да бисмо могли да прказујемо један цртеж на разним местима:

  • Треба да изаберемо једну тачку чије се координате задају директно. Ову изабрану тачку зваћемо главна тачка, (понекад се ова тачка назива и сидро, енгл. anchor). У примеру облака, главна тачка је центар средњег круга.

  • Након избора главне тачке, координате свих осталих битних тачака одређујемо у односу на њу, тако што на координате главне тачке додајемо или одузимамо одређени померај. У примеру са облаком, да бисмо добили \(x\) координату центра левог круга, од \(x\) координате главне тачке тачке (центра средњег круга) одузимамо 50 пиксела, а за десни круг додајемо 50 пиксела.

У општем случају, на цртежу може бити и других облика осим кругова. Тачке које одређују положаје тих облика су:

  • за дуж: њени крајеви

  • за многоугао: његова темена

  • за круг: његов центар

  • за правоугаоник: његово горње лево теме

  • за елипсу: горње лево теме правоугаоника у који је уписана та елипса

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

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

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

    Која наредба треба да замени дату?

  • pg.draw.circle(prozor, pg.Color("red"), (x, y), 50, 1)
  • Покушајте поново
  • pg.draw.circle(prozor, pg.Color("red"), (x+120, y+90), 50, 1)
  • Покушајте поново
  • pg.draw.circle(prozor, pg.Color("red"), (x+20, y-10), 50, 1)
  • Тачно
  • pg.draw.circle(prozor, pg.Color("red"), (x-20, y+10), 50, 1)
  • Покушајте поново

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

    Која наредба треба да замени дату?

  • pg.draw.line(prozor, pg.Color("red"), (x-50, y-50), (150, 150))
  • Покушајте поново
  • pg.draw.line(prozor, pg.Color("red"), (x-50, y-50), (x+50, y+50))
  • Тачно
  • pg.draw.line(prozor, pg.Color("red"), (x-50, x+50), (y-50, y+50))
  • Покушајте поново
  • pg.draw.line(prozor, pg.Color("red"), (x+50, y+50), (x+150, y+150))
  • Покушајте поново

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

    Која наредба треба да замени дату?

  • pg.draw.rect(prozor, pg.Color("red"), (x-50, y-50, x, y))
  • Покушајте поново
  • pg.draw.rect(prozor, pg.Color("red"), (x, y, 100, 100))
  • Покушајте поново
  • pg.draw.rect(prozor, pg.Color("red"), (x+50, y+50, 100, 100))
  • Покушајте поново
  • pg.draw.rect(prozor, pg.Color("red"), (x-50, y-50, 100, 100))
  • Тачно

    Q-62: Желимо да померимо цртеж који се састоји од неколико облика надесно за 100 пиксела. Означите тачна тврђења.

  • Уместо pg.draw.circle(prozor, boja, (x, y), r, d) позваћемо pg.draw.circle(prozor, boja, (x+100, y), r, d).
  • Тачно
  • Уместо pg.draw.circle(prozor, boja, (x, y), r, d) позваћемо pg.draw.circle(prozor, boja, (x-100, y-100), r, d).
  • Покушајте поново
  • Уместо pg.draw.rect(prozor, boja, (x, y, w, h), d) позваћемо pg.draw.circle(prozor, boja, (x+100, y, w+100, h), d).
  • Покушајте поново
  • Уместо pg.draw.rect(prozor, boja, (x, y, w, h), d) позваћемо pg.draw.rect(prozor, boja, (x+100, y, w, h), d).
  • Тачно
  • Уместо pg.draw.rect(prozor, boja, (x, y, w, h), d) позваћемо pg.draw.rect(prozor, boja, (x-100, y, w, h), d).
  • Покушајте поново

Следе још неки примери претварања фиксног цртежа у помични.

Меда - положај

Дат је следећи програм, који приказује главу медведића играчке:

У програму се седам пута позива функција uokviren_krug, која задати круг уоквирује црном бојом (мада је за три мала црна круга могла је да буде позвана и само функција circle). Да бисмо могли да мењамо положај цртежа, изаберимо главну тачку (сидро). Нека то буде центар великог круга, то јест главе медведића. Координате ове тачке су (250, 150). Сада је потребно да координате центара свих осталих кругова изразимо полазећи од главне тачке, померајући се за потребан број пиксела у смеру \(x\) и \(y\) осе. Узмимо као пример десно уво медведића.

\(x\) координата центра десног увета је \(310 = 250 + 60\), док је \(y\) координата \(80 = 150 - 70\). Одавде се види да координате центра десног увета можемо у програму да напишемо као (cx + 60,  cy - 70), где су (cx, cy) координате главне тачке. Спроведите исти поступак за остале кругове и довршите функцију crtaj_medu.

Овако написан програм нам омогућава да једноставно приказујемо медведиће на разним местима на екрану. На пример, можете да позив функције

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

која црта медведића са главном тачком у центру прозора (као што је и био), замените са следећа два:

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

Испробајте ово! Било би знатно теже нацртати другог медеведића да нисмо почетни програм прилагодили за овакву употребу.

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

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

Нека је главна тачка (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"))