05. Geometria na kružnici

Úloha 1

Na rozcvičenie, vytvorte program, ktorý vygeneruje 2 náhodné pozície na obrazovke, na prvú pozíciu vykreslí zelený krúžok, na druhú pozíciu červený krúžok. Použite vektory.

Rozšírte program tak, aby medzi týmito dvomi pozíciami nakreslil 5 menších bodov:

Riešenie
// Pocet kruzkov
int n = 5;

// Dve nahodne pozicie: a, b
PVector a = new PVector(random(width), random(height));
PVector b = new PVector(random(width), random(height));

// Vykreslenie a
fill(0,255,0);
circle(a.x, a.y, 30);

// Vykreslenie b
fill(255, 0, 0);
circle(b.x, b.y, 30);

// Jeden dielik cesty medzi a a b
PVector d = PVector.sub(b,a).div(n-1);

// Vykreslenie postupne kruzkov medzi a a b
for (int i = 0; i < n; i++)
{
  // Pozicia i-teho kruzku: p = a + d*i
  PVector p = PVector.add(a, PVector.mult(d, i));
  
  // Vykreslenie kruzku
  fill(255);
  circle(p.x, p.y, 10);
}

Úloha 2

Program v Úlohe 1 funguje tak, že má daný počet dielikov a podľa neho vyrátava dĺžku jedného dieliku medzi a a b. Čo ak by sme chceli, aby bola pevne daná vzdialenosť dielikov a podľa nej by sme vypočítali počet dielikov?

Dlzka dielika = 10, pocet kruzkov s tomu prisposobi

Budeme potrebovať vypočítať dĺžku trasy medzi a a b a vydeliť ju dĺžkou jedného dielika.

Na výpočet celej dĺžky medzi a a b použijeme funkciu mag:

float celaDlzka = PVector.sub(b,a).mag();

Potom vypočítame počet krúžkov ako celá deleno dĺžka dielika. A k tomu ešte pripočítame 1, lebo počet krúžkov je o 1 viac ako počet dielikov:

int n = int( celaDlzka/dlzkaDielika) + 1;

Tu je celý kód:

// Dlzka jedneho dielika
float dlzkaDielika = 10;

size(400, 400);
background(0);

// Dve nahodne pozicie: a, b
PVector a = new PVector(random(width), random(height));
PVector b = new PVector(random(width), random(height));

// Vykreslenie a
fill(0,255,0);
circle(a.x, a.y, 30);

// Vykreslenie b
fill(255, 0, 0);
circle(b.x, b.y, 30);

// Vypocet poctu kruzkov medzi a a b
float celaDlzka = PVector.sub(b,a).mag(); 
int n = int( celaDlzka/dlzkaDielika) + 1;

// Jeden dielik cesty medzi a a b
PVector d = PVector.sub(b,a).div(n-1);

// Vykreslenie postupne kruzkov medzi a a b
for (int i = 0; i < n; i++)
{
  // Pozicia i-teho kruzku: p = a + d*i
  PVector p = PVector.add(a, PVector.mult(d, i));
  
  // Vykreslenie kruzku
  fill(255);
  circle(p.x, p.y, 10);
}

Geometria na kružnici

Doterajšie úlohy boli zamerané na pohyb a rozmiestňovanie bodov na úsečke, alebo smerom, ktorý je zarovnaný s osami X a Y. Napríklad takto sme vykreslili 10 čísel vedľa seba:

size(400, 200);
background(0);

int n = 10;     // Pocet cisel
float dx = 30;  // Dielik o ktory sa posuvame na osi x 

for (int i = 0; i < n; i++)
{
  float x = dx * i;  // x pozicia
  float y = 100;     // y pozicia
  text( i, x, y);    // Vypisanie textu i na poziciu x,y
}

Keby sme chceli tieto čísla vypísať nie vedľa seba horizontálne, ale dokola na kružnicu, tak nám už doterajšie znalosti nevystačia a musíme sa naučit niečo nové. Skúste tento kód:

size(400, 400);
background(0);

int n = 10;      // Pocet cisel
float du = 0.4;  // Dielik o ktory sa posuvame po kruznici 

PVector c = new PVector(width/2, height/2); // Stred
float r = 150;   // Polomer

for (int i = 0; i < n; i++)
{
  float x = c.x + r * cos(du * i);
  float y = c.y + r * sin(du * i);
  text( i, x, y);
}

Všimnite si, v čom sa tento program podobá programu na horizontálny výpis čísel.

Vyskúšajte meniť hodnoty polomera r alebo hodnotu dielika du. Čo tieto premenné odvplyvňujú na výsledkom vzhľade obrázka?

Karteziánske a polárne súradnice

Doteraz sme na zadefinovanie pozície nejakého objektu používali súradnice x,y a vystačili sme si s tým. X znamenalo ako ďaleko je bod od ľavého okraja obrazovky. Y znamenalo ako ďaleko je bod od horného okraja obrazovky. Tomu sa hovorí aj pravouhlé alebo karteziánske súradnice:

Bod P na súradniciach [3,2] v karteziánskej sústave.

Pri rozmiestňovaní bodov na kružnicu nám prídu vhod iné súradnice. Nie také, ktoré sú pravouhlé, ale také, ktoré vyjadrujú vzdialenosť bodu od stredu kružnice a uhol o koľko je bod otočený:

Ten istý bod P ale vyjadrený pomocou vzdialenosti od stredu a uhla otočenia.

Súradnice, ktoré popisujú polohu bodu pomocou stredu kružnice, polomeru tejto kružnice a uhla na tejto kružnici, sa volajú aj polárne.

Ak máte takto pomocou stredu C, uhla u, a polomeru r vyjadrenú polohu bodu, tak vieme robiť veci ako:

  • otáčať bodom, ak meníme hodnotu uhla u.

  • približovať a vzdaľovať bod k stredu, ak meníme hodnotu polomera r.

Keď chceme vykresľovať na obrazovku, tak budeme ale tak či tak potrebovať z polárnych súradníc na kruhu prejsť do karteziánskych na obrazovke, lebo obrazovka pozostáva z pixelov v pravouhlej karteziánskej mriežke a Processing od nás očakáva súradnice príkazov ako rect(), ellipse() alebo text() v tejto pixelovej mriežke.

Ak poznáme stred C, polomer r a uhol u, tak z toho vieme vypočítať hodnoty x,y na obrazovke nasledovne:

  float x = C.x + r * cos(u);
  float y = C.y + r * sin(u);

Úloha 3

Tu je jednoduchý program na vyskúšanie. Meňte v programe hodnoty stredu polomeru r a uhla u a sledujte ako sa mení výsledok.

size(400, 400);
background(0);
fill(255);

// Polarne suradnice bodu
PVector C = new PVector(width/2, height/2); // Stred je v strede obrazovky
float r = 50;   // Polomer
float u = 4;    // Uhol

// Vypocet pozicie na obrazovke
float x = C.x + r * cos(u);
float y = C.y + r * sin(u);

// Vykreslenie bodu
circle(x, y, 10);
text("P", x-10,y-10);

// Pre nazornost vykreslime aj stred a kruznicu:
text("C", C.x, C.y);
stroke(#FFAB03);
noFill();
circle(C.x, C.y, 2*r);

Nájdite také hodnoty u a r, aby ste umiestnili bod P na nasledujúce pozície:

Na pravý okraj kružnice
Na spodný okraj obrazovky

Koľko má kruh dokola?

Asi ste prišli na to, že na pravom okraji kružnice je uhol u = 0. Na spodný okraj to bolo ťažšie nájsť, ale ak ste prišli na niečo ako u = 1.55, tak ste skoro trafili.

Celý kruh dokola má 360°, ale Processing nefunguje v stupňoch. Processing funguje v tzv. radiánoch, alebo inými slovami, dokola celého kruhu nie je uhol veľký 360 ale je to uhol veľký 2*PI. Polovica kruhu je PI a štvrtina kruhu je PI/2. Celý kruh má dokola 2*PI a je to taký istý uhol ako 0.

Rozmiestnenie na kružnici

Keď už vieme, aký veľký uhol je dokola celej kružnice, môžeme tento uhol rozdeliť na rovnaké uhlové dieliky a rozmiestňovať objekty na kružnici:

size(400, 400);
background(0);
fill(255);

PVector C = new PVector(width/2, height/2);
float r = width/3;

int n = 18;          // Pocet objektov
float du = 2*PI/n;   // Jeden dielik

for (int i = 0; i < n; i++)
{
  float u = i*du;    // Uhol je i krat dielik
  float x = C.x + r * cos(u);
  float y = C.y + r * sin(u);
  circle(x,y,10);  
}

Úloha 4

Upravte predošlý program tak, aby namiesto krúžkov vypisoval čísla od 1 do 12

Otáčanie po kružnici

V predošlej úlohe ste vytvorili niečo ako ciferník hodín. Lenže ozajstné hodiny majú hore číslo 12 a tieto naše hodiny majú hore číslo 10. Potrebovali by sme pootočiť súradnice po kružnici tak, aby 12ka bola hore.

Keď vo výpočte súradníc:

  float x = C.x + r * cos(u);
  float y = C.y + r * sin(u);

Pridáme dovnútra funkcií cos a sin nejaký uhol navyše, docielime otočenie o tento uhol. Napríklad tu sme pridali uhol PI/4, čo je 45°:

  float x = C.x + r * cos(u + PI/4);
  float y = C.y + r * sin(u + PI/4);

Úloha 5

Skúšajte pridávať rôzne uhly. Do ktorého smeru otáčajú hodiny kladné uhly? Do ktorého smeru otáčajú kružnicu záporné uhly?

Úloha 6

Vymyslite, o aký uhol potrebujeme pootočiť náš program, aby mali hodiny 12ku hore:

Animácia po kružnici

Keď vieme pridávaním uhla otáčať polohy bodov na kružnici, vieme tento pridávaný uhol v animácii aj meniť a docieliť tak otáčanie. Tu je jednoduchý skeč so setup() a draw(), ktorý vykreslí zatiaľ len statický bod:

PVector C;
float u = 0;
float r = 150;

void setup()
{
  size(400,400);
  C = new PVector(width/2, height/2);  
}

void draw()
{
  background(0);
  
  float x = C.x + r * cos(u);
  float y = C.y + r * sin(u);
  
  circle(x,y,20);  
}

Uhol u môžem teraz v draw() postupne zvyšovať a sledujme animáciu:

void draw()
{
  background(0);
  
  float x = C.x + r * cos(u);
  float y = C.y + r * sin(u);
  
  circle(x,y,20);  
  
  u = u + 0.05;
}

Úloha 7

Upravte predošlý program tak, aby sa bod otáčal v opačnom smere a pomalšie:

Úloha 8

Napíšte nový skeč, ktorý vykreslí na obvode kružnice 15 bodov. Pridajte do cos() a sin() animovaný uhol tak, aby sa otáčali:

Riešenie
PVector C;
float u = 0;
float r = 150;
int n = 15;

void setup()
{
  size(400,400);
  C = new PVector(width/2, height/2);  
}

void draw()
{
  background(0);

  float du = 2*PI/n;
  
  for (int i = 0; i < n; i++)
  {
    float x = C.x + r * cos(i*du + u);
    float y = C.y + r * sin(i*du + u);  
    
    circle(x,y,20);       
  }
  
  u = u - 0.01;  
}

Pohyb po špirále

Keď už vieme kružnicu, je jednoduché naučiť sa aj špirálu. Špirála je ako kružnica, ale postupne sa jej zväčšuje polomer. Začnime od programu z Úlohy 7:

PVector C;
float u = 0;
float r = 150;

void setup()
{
  size(400,400);
  C = new PVector(width/2, height/2);  
}

void draw()
{
  background(0);
  
  float x = C.x + r * cos(u);
  float y = C.y + r * sin(u);
  
  circle(x,y,20);  
  
  u = u - 0.01;
}

A upravme tento program tak, aby polomer r začínal nie na hodnote 150, ale na 0:

PVector C;
float u = 0;
float r = 0;

A postupne v draw() ho budeme zväčšovať, podobne ako meníme u :

void draw()
{
  background(0);
  
  float x = C.x + r * cos(u);
  float y = C.y + r * sin(u);
  
  circle(x,y,20);  
  
  u = u - 0.01;
  r = r + 0.2;
}

Docielime tak, že sa bod nepohybuje po kružnici, ale po špirále:

Úloha 9

Upravte Úlohu 8 tak, aby sa body nehýbali po kružnici, ale po špirále:

Riešenie
PVector C;
float u = 0;
float r = 0;
int n = 15;

void setup()
{
  size(400,400);
  C = new PVector(width/2, height/2);  
}

void draw()
{
  background(0);

  float du = 2*PI/n;
  
  for (int i = 0; i < n; i++)
  {
    float x = C.x + r * cos(i*du + u);
    float y = C.y + r * sin(i*du + u);  
    
    circle(x,y,20);       
  }
  
  u = u - 0.01;
  r = r + 1;
}

Spájanie bodov

Už vieme, že ak si kruh rozdelíme na n dielikov, tak vo for cykle vieme vypočítať i-tu pozíciu v poradí takto:

  float du = 2*PI/n;
  
  for (int i = 0; i < n; i++)
  {
    float x = C.x + r * cos(i*du);
    float y = C.y + r * sin(i*du);  
    
    circle(x,y,20);       
  }

Vieme tak vykresliť izolovaných n bodov na kružnici. Čo ak ich chceme pospájať? To znamená, že nakresliť čiaru medzi i-tym bodom a i+prvým bodom.

Vytvoríme si druhú dvojicu súradníc a vypočítame ich polohu tak, že namiesto i použijeme (i+1):

  float du = 2*PI/n;
  
  for (int i = 0; i < n; i++)
  {
    float x1 = C.x + r * cos(i*du);
    float y1 = C.y + r * sin(i*du);
    
    float x2 = C.x + r * cos((i+1)*du);
    float y2 = C.y + r * sin((i+1)*du);
       
    line(x1, y1, x2, y2);       
  }

Úloha 10

Vytvorte skeč, ktorý nakreslí po obvode kružnice n bodov a pospája ich čiarami.

Riešenie
PVector C;
float r = 150;
int n = 20;

void setup()
{
  size(400,400);
  C = new PVector(width/2, height/2); 
  stroke(255);
}

void draw()
{
  background(0);

  float du = 2*PI/n;
  
  for (int i = 0; i < n; i++)
  {
    float x1 = C.x + r * cos(i*du);
    float y1 = C.y + r * sin(i*du);
    
    float x2 = C.x + r * cos((i+1)*du);
    float y2 = C.y + r * sin((i+1)*du);

    circle(x1,y1,10);
    line(x1, y1, x2, y2);       
  }
}

Úloha 11

Vytvorte program, ktorý vykreslí päťuholník:

Úloha 12

Upravte uhly tak, aby mal päťuholník vrchol nahor:

Pospájaná špirála

Keď sme chceli vypočítať nasledujúci bod po i-tom bode, tak sme vo vzorci na výpočet súradníc zväčšili i na i+1. Ak by tieto body boli na špirále, tak musíme pri druhom bode zväčšiť aj r:

size(400, 400);
background(0);
stroke(255);

PVector C = new PVector(width/2, height/2);
float r = 0;
int n = 20;

float du = 2*PI/n;
float dr = 5; // O kolko sa zvacsuje r v kazdom kroku

for (int i = 0; i < n; i++)
{
  float x1 = C.x + r * cos(i*du);
  float y1 = C.y + r * sin(i*du);

  float x2 = C.x + (r+dr) * cos((i+1)*du);
  float y2 = C.y + (r+dr) * sin((i+1)*du);

  line(x1, y1, x2, y2);

  r = r + dr;
}

Vyskúšajte rôzne hodnoty dr. Čo robí tento parameter s tvarom špirály?

Úloha 13

Upravte for cyklus v programe tak, aby nešiel iba do i<n ale až do i<3*n . Čo to urobí so špirálou?

Skúšajte rôzne kombinácie počtu otáčok a hrúbky špirály dr.

Last updated