7. Bølger og rotasjon

Skolekoding.no > Tekstkoding > p5.js > Kurs > 7. Bølger og rotasjon


7.1 Flytte koordinatsystemet – translate()

I p5.js er origo oppe i venstre hjørne. Positiv x-akse er vannrett til høyre, og positiv y-akse er loddrett nedover. Hvis vi ønsker å flytte origo til et annet sted på lerretet, kan vi gjøre det med translate();

Translate(150, 150) flytter origo fra (0, 0) til (150, 150);

Translate tar utgangspunkt i det forrige koordinatsystemet. Hvis origo har blitt flyttet til punktet (50, 50), vil translate(50, 50); flytte origo videre derfra, til det som ville vært (100, 100) i det opprinnelige systemet.

translate(x, y); flytter origo til punktet (x, y)

Skriv dette i editoren:

  • function setup() {
    • createCanvas(600, 400);
  • ​}
  • function draw() {
    • background(220);
    • rect(0, 0, 20, 50); // Rektangel i øvre venstre hjørne
    • translate(50, 50);
    • rect(0, 0, 20, 50); // Samme parametere hver gang
    • translate(50, 50);
    • rect(0, 0, 20, 50);
    • translate(50, 50);
    • rect(0, 0, 20, 50);
    • translate(50, 50);
    • rect(0, 0, 20, 50);
  • }
Alle rektanglene er tegnet med øvre venstre hjørne i origo, men origo flyttes på skrå nedover for hver tegning.

7.2 Oppgave

Bruk translate() for å tegne fire figurer med de samme parametrene men plassert på ulike steder på lerretet.


​7.3  Vinkler i p5.js

Vanligvis er positiv vinkelretning mot klokka. I Processing er positiv y-akse loddrett nedover, derfor er positiv dreieretning med klokka.

90 grader er loddrett nedover. 270 grader er loddrett oppover. 0 grader er mot høyre som vanlig. 180 grader er mot venstre som vanlig.

​Vinkelmålet i p5.js er ikke grader. I stedet brukes radianer. For de som ikke har radianer i blodet, er det greit at det finnes en funksjon som omgjør en vinkel fra radianer til grader: radians()

Radianer er lengden av buen i en sirkelsektor der radien er 1.

Vinkelrotasjon i Processing og p5.js. btk.tillnagel.com

​7.3 Rotere koordinatsystemet – rotate() 

Vi kan rotere figurer ved å rotere hele koordinatsystemet før figuren tegnes. Da bruker vi rotate(). Mellom parentesene skriver vi vinkelen vi vil rotere.

rotate(radianer
eller
rotate(radians(grader))

En positiv vinkel roterer koordinatsystemet mot høyre. En negativ vinkel roterer koordinatsystemet mot venstre. Rotasjonen skjer om origo.  ​

​Hvis rotate() brukes inne i draw(), nullstilles rotasjonen i starten av hver runde.

Hvis vi vil rotere en figur om et annet punkt enn det gjeldende origo, må vi flytte origo (A) før vi roterer (B). Se figur nedenfor.

Hentet fra processing.org
Hentet fra processing.org

Skriv dette i editoren:

  • function setup() {
    • createCanvas(400,400);
    • strokeWeight(5);
  • }
  • function draw() {
    • background(220);
    • fill(0);
    • strokeWeight(3);
    • point(200, 200);
    • text(«(200, 200)», 210, 200);
    • translate(200, 200);
    • fill(255);
    • strokeWeight(1); 
    • rect(10, 10, 50, 100);
    • rotate(radians(30));
    • rect(10, 10, 50, 100);
    • rotate(radians(30));
    • rect(10, 10, 50, 100);
    • rotate(radians(30));
    • rect(10, 10, 50, 100);
    • rotate(radians(30));
    • rect(10, 10, 50, 100);
    • rotate(radians(30));
    • rect(10, 10, 50, 100);
  • }

7.4 Oppgaver

A) Lag en kantete figur som du dreier om et punkt
B) Gjør det samme ved bruke av en for-løkke


7.5 Skalere koordinatsysteme – scale() 

Vi kan forstørre og forminske koordinatsystemet med scale(skaleringsgrad). 

scale(2) gjør at koordinatsystemet skaleres opp til dobbel størrelse. Rutenettet blir dobbelt så stort. Figurer blir dobbelt så brede og dobbelt så høye.

Skriv dette i editoren:

  • function setup() {
    • createCanvas(400, 400);
    • background(240);
  • }
  • function draw() {
    • fill(0, 0, 255); // Blå
    • rect(0, 0, 100, 100); // Blått lite kvadrat ligger bak det røde
    • scale(2); // Skalaen på x- og y-aksen dobles
    • fill(255, 0, 0, 155); // Rød gjennomskinelig (155)
    • rect(0, 0, 100, 100); // Rødt stort kvadrat
  • }

7.6 Oppgave

​Tegn en figur som du skalerer i tre ulike skalaer.


7.7 Speiling – scale(-1, 1)

Ved å bruke to parametere kan vi skalere x-aksen og y-aksen hver for seg.

scale(2, 0.5). Her dobles lengden i x-retning, mens lengden i y-retning halveres. Det usynlige rutenettet består ikke lenger av kvadratiske ruter, men av liggende rektangler.

Hvis vi bruker negative verdier i scale() snur vi aksene. 

  • scale(-1, 1)

Her skjer det ingen endring i størrelse, men x-aksen endrer retning. Nå er positiv x-retning mot venstre utenfor lerretet.

For å speile om en vannrett eller loddrett linje, må vi først flytte origo med translate(). Deretter tegner vi opp linja langs x- eller y-aksen. Så tegner vi den ene figuren. Deretter flipper vi med scale(), og tegner den andre figuren med de samme parameterne. 

​​Hvis vi vil speile om en skrå linje må vi, i tillegg til å flytte origo med translate(), også rotere med rotate().

Speiling om ett punkt er det samme som å rotere 180 grader. Da flytter vi origo til det punktet vi vil rotere om og tegner første figur. Deretter roterer vi 180 grader og tegner andre figur med de samme parameterne.

Skriv dette i editoren:

  • function setup() {
    • createCanvas(400, 400);
  • }
  • function draw() {
    • translate(width/2, 0); // Flytter origo til midt på x-aksen. 
    • line(0, 0, 0, 300); // Speilingslinje (den nye y-aksen)
    • triangle(0, 0, 0, 50, 50, 50);
    • translate(0, 50); // Flytter origo til (0, 50)
    • scale(-1, 1); // x-aksen snus, y-aksen er som den er
    • triangle(0, 0, 0, 50, 50, 50);
    • translate(0, 50);
    • scale(-1, 1); // x-aksen snus tilbake til opprinnelig
    • triangle(0, 0, 0, 50, 50, 50);
    • translate(0, 50);
    • scale(-1, 1);
    • triangle(0, 0, 0, 50, 50, 50);
    • translate(0, 50);
    • scale(-1, 1);
    • triangle(0, 0, 0, 50, 50, 50);
  • }

7.8 Oppgaver

A) Skriv om programmet over med for-løkke.
B) Flytt y-aksen til midt på lerretet. Tegn en figur som du speiler om y-aksen.
C) Tegn en figur som du speiler om en skrå linje.


7.6 Ta vare på koordinatsystemet – pushMatrix();

Vi kan få p5.js til å huske plasseringen av koordinatsystemet, slik at det kan hentes det fram igjen seinere. Funksjonen push() lagrer koordinatsystemet. Funksjonen pop() henter det fram igjen.

Skriv dette i editoren:

  • function setup() {
    • createCanvas(400, 400);
    • background(200);
  • }
  • function draw() {
    • fill(255);
    • rect(0, 0, 20, 50);
    • push(); // Lagrer koordinatssystemet
    • translate(50, 50);
    • rect(0, 0, 20, 50);
    • translate(50, 50);
    • rect(0, 0, 20, 50);
    • translate(50, 50);
    • rect(0, 0, 20, 50);
    • translate(50, 50);
    • rect(0, 0, 20, 50);
    • pop(); // henter fram det lagrede koordinatsystemet
    • fill(0, 255, 0); // Grønn
    • rect(200, 0, 20, 50); 
  • }

7.7 Bølge/puls – sin(vinkel)

Sinusverdien til en vinkel
For å skape en bølgende bevegelse, er det nyttig å bruke trigonometriske funksjoner. Trigonometriske funksjoner er pensum på noen matematikkkurs på videregående skole. Her skal vi først og fremst konsentrer oss om en av dem: sinus.

sin(vinkel) gir oss alltid en verdi mellom -1 og 1

I en rettvinklet trekant er sinusverdien til en vinkel lik:
sinus til vinkel = motstående katet dividert med hypotenusen.

Hypotenusen er alltid den lengste siden i trekanten, derfor er sinusverdien en verdi mellom 0 og 1. Tar vi med negative vinkler, eller vinkler større enn 180 grader,  har sinus verdier fra -1 til 1. Uansett hvilken vinkel vi setter inn, vil sin() returnere en verdi mellom -1 og 1. Dette gjør synsfunksjonen ideell til å lage bølgende eller pulserende bevegelser.

Sinusverdien til en vinkel er lik lengden av motstående katet dividert med lengden av hypotenusen.
Sirkelens radius er lik 1 (enhetssirkelen). Sinusverdien (rød linje, motstående katet) øker mot 1 (90°), minker mot 0 (180°), minker videre mot -1 (270°), øker mot 0 (360°), og øker på nytt mot 1 (90°).

Skriv dette i editoren:

  • let x = 0;
  • let y = 0;
  • let v = 0;
  • function setup() {
    • createCanvas(600, 400);
  • }
  • function draw() {
    • ellipse(x, y, 20, 20);
    • x = x + 1; // x øker med 1 for hver runde
    • y = sin(v); // y får en verdi mellom -1 og 1
    • v = v + radians(20); // Vinkelen v øker med 20 grader
  • }

Dette gir en bølge av punkter der x- koordinaten øker med 1, og  y-koordinaten veksler mellom -1 og 1. Dette blir en veldig unnselig bølge. Vi må gjøre noen justeringer.

Likevektslinje og amplitude
​Fordi sin() returnerer en verdi mellom -1 og 1 må vi gjøre minst to justeringer for at resultatet skal bli bra. En bevegelse på to punkter der halvparten er utenfor lerretet er ikke mye å rope hurra for.

Vi må justere likevekstlinjen og amplituden (maksimumsutslaget).

Uten justering er likevektslinjen  y = 0. Ved å legge til et tall, flytter vi likevektslinjen nedover på lerretet.

​y = likevektslinje + sin(v)

Uten justering er amplituden 1. Vi justerer ved å multiplisere med den amplituden vi vil ha.

y = likevektslinje + sin(v) * amplituden

På engelsk skrives det ofte slik:
y = offset + sin(v) * scalar

7.1 Flytte koordinatsystemet – translate()

I p5.js er origo oppe i venstre hjørne. Positiv x-akse er vannrett til høyre, og positiv y-akse er loddrett nedover. Hvis vi ønsker å flytte origo til et annet sted på lerretet, kan vi gjøre det med translate();

Translate(150, 150) flytter origo fra (0, 0) til (150, 150);

Translate tar utgangspunkt i det forrige koordinatsystemet. Hvis origo har blitt flyttet til punktet (50, 50), vil translate(50, 50); flytte origo videre derfra, til det som ville vært (100, 100) i det opprinnelige systemet.

translate(x, y); flytter origo til punktet (x, y)

Skriv dette i editoren:

  • function setup() {
    • createCanvas(600, 400);
  • ​}
  • function draw() {
    • background(220);
    • rect(0, 0, 20, 50); // Rektangel i øvre venstre hjørne
    • translate(50, 50);
    • rect(0, 0, 20, 50); // Samme parametere hver gang
    • translate(50, 50);
    • rect(0, 0, 20, 50);
    • translate(50, 50);
    • rect(0, 0, 20, 50);
    • translate(50, 50);
    • rect(0, 0, 20, 50);
  • }
Alle rektanglene er tegnet med øvre venstre hjørne i origo, men origo flyttes på skrå nedover for hver tegning.

7.2 Oppgave

Bruk translate() for å tegne fire figurer med de samme parametrene men plassert på ulike steder på lerretet.


​7.3  Vinkler i p5.js

Vanligvis er positiv vinkelretning mot klokka. I Processing er positiv y-akse loddrett nedover, derfor er positiv dreieretning med klokka.

90 grader er loddrett nedover. 270 grader er loddrett oppover. 0 grader er mot høyre som vanlig. 180 grader er mot venstre som vanlig.

​Vinkelmålet i p5.js er ikke grader. I stedet brukes radianer. For de som ikke har radianer i blodet, er det greit at det finnes en funksjon som omgjør en vinkel fra radianer til grader: radians()

Radianer er lengden av buen i en sirkelsektor der radien er 1.

Vinkelrotasjon i Processing og p5.js. btk.tillnagel.com

​7.3 Rotere koordinatsystemet – rotate() 

Vi kan rotere figurer ved å rotere hele koordinatsystemet før figuren tegnes. Da bruker vi rotate(). Mellom parentesene skriver vi vinkelen vi vil rotere.

rotate(radianer
eller
rotate(radians(grader))

En positiv vinkel roterer koordinatsystemet mot høyre. En negativ vinkel roterer koordinatsystemet mot venstre. Rotasjonen skjer om origo.  ​

​Hvis rotate() brukes inne i draw(), nullstilles rotasjonen i starten av hver runde.

Hvis vi vil rotere en figur om et annet punkt enn det gjeldende origo, må vi flytte origo (A) før vi roterer (B). Se figur nedenfor fra https://processing.org/tutorials/transform2d/.

Skriv dette i editoren:

  • function setup() {
    • createCanvas(400,400);
    • strokeWeight(5);
  • }
  • function draw() {
    • background(220);
    • fill(0);
    • strokeWeight(3);
    • point(200, 200);
    • text(«(200, 200)», 210, 200);
    • translate(200, 200);
    • fill(255);
    • strokeWeight(1); 
    • rect(10, 10, 50, 100);
    • rotate(radians(30));
    • rect(10, 10, 50, 100);
    • rotate(radians(30));
    • rect(10, 10, 50, 100);
    • rotate(radians(30));
    • rect(10, 10, 50, 100);
    • rotate(radians(30));
    • rect(10, 10, 50, 100);
    • rotate(radians(30));
    • rect(10, 10, 50, 100);
  • }

7.4 Oppgaver

A) Lag en kantete figur som du dreier om et punkt
B) Gjør det samme ved bruke av en for-løkke


7.5 Skalere koordinatsysteme – scale() 

Vi kan forstørre og forminske koordinatsystemet med scale(skaleringsgrad). 

scale(2) gjør at koordinatsystemet skaleres opp til dobbel størrelse. Rutenettet blir dobbelt så stort. Figurer blir dobbelt så brede og dobbelt så høye.

Skriv dette i editoren:

  • function setup() {
    • createCanvas(400, 400);
    • background(240);
  • }
  • function draw() {
    • fill(0, 0, 255); // Blå
    • rect(0, 0, 100, 100); // Blått lite kvadrat ligger bak det røde
    • scale(2); // Skalaen på x- og y-aksen dobles
    • fill(255, 0, 0, 155); // Rød gjennomsiktig (155)
    • rect(0, 0, 100, 100); // Rødt stort kvadrat
  • }

7.6 Oppgave

​Tegn en figur som du skalerer i tre ulike skalaer.


7.7 Speiling – scale(-1, 1)

Ved å bruke to parametere kan vi skalere x-aksen og y-aksen hver for seg.

scale(2, 0.5). Her dobles lengden i x-retning, mens lengden i y-retning halveres. Det usynlige rutenettet består ikke lenger av kvadratiske ruter, men av liggende rektangler.

Hvis vi bruker negative verdier i scale() snur vi aksene. 

scale(-1, 1). Her skjer det ingen endring i størrelse, men x-aksen endrer retning. Nå er positiv x-retning mot venstre utenfor lerretet.

For å speile om en vannrett eller loddrett linje, må vi først flytte origo med translate(). Deretter tegner vi opp linja langs x- eller y-aksen. Så tegner vi den ene figuren. Deretter flipper vi med scale(), og tegner den andre figuren med de samme parameterne. 

​​Hvis vi vil speile om en skrå linje må vi, i tillegg til å flytte origo med translate(), også rotere med rotate().

Speiling om ett punkt er det samme som å rotere 180 grader. Da flytter vi origo til det punktet vi vil rotere om og tegner første figur. Deretter roterer vi 180 grader og tegner andre figur med de samme parameterne.

Skriv dette i editoren:

  • function setup() {
    • createCanvas(400, 400);
  • }
  • function draw() {
    • translate(width/2, 0); // Flytter origo til midt på x-aksen. 
    • line(0, 0, 0, 300); // Speilingslinje (den nye y-aksen)
    • triangle(0, 0, 0, 50, 50, 50);
    • translate(0, 50); // Flytter origo til (0, 50)
    • scale(-1, 1); // x-aksen snus, y-aksen er som den er
    • triangle(0, 0, 0, 50, 50, 50);
    • translate(0, 50);
    • scale(-1, 1); // x-aksen snus tilbake til opprinnelig
    • triangle(0, 0, 0, 50, 50, 50);
    • translate(0, 50);
    • scale(-1, 1);
    • triangle(0, 0, 0, 50, 50, 50);
    • translate(0, 50);
    • scale(-1, 1);
    • triangle(0, 0, 0, 50, 50, 50);
  • }

7.8 Oppgaver

A) Skriv om programmet over med for-løkke.
B) Flytt y-aksen til midt på lerretet. Tegn en figur som du speiler om y-aksen.
C) Tegn en figur som du speiler om en skrå linje.


7.6 Ta vare på koordinatsystemet – pushMatrix();

Vi kan få p5.js til å huske plasseringen av koordinatsystemet, slik at det kan hentes det fram igjen seinere. Funksjonen push() lagrer koordinatsystemet. Funksjonen pop() henter det fram igjen.

Skriv dette i editoren:

  • function setup() {
    • createCanvas(400, 400);
    • background(200);
  • }
  • function draw() {
    • fill(255);
    • rect(0, 0, 20, 50);
    • push(); // Lagrer koordinatssystemet
    • translate(50, 50);
    • rect(0, 0, 20, 50);
    • translate(50, 50);
    • rect(0, 0, 20, 50);
    • translate(50, 50);
    • rect(0, 0, 20, 50);
    • translate(50, 50);
    • rect(0, 0, 20, 50);
    • pop(); // henter fram det lagrede koordinatsystemet
    • fill(0, 255, 0); // Grønn
    • rect(200, 0, 20, 50); 
  • }

7.7 Bølge/puls – sin(vinkel)

Sinusverdien til en vinkel
For å skape en bølgende bevegelse, er det nyttig å bruke trigonometriske funksjoner. Trigonometriske funksjoner er pensum på noen matematikkkurs på videregående skole. Her skal vi først og fremst konsentrer oss om en av dem: sinus.

sin(vinkel) gir oss alltid en verdi mellom -1 og 1

I en rettvinklet trekant er sinusverdien til en vinkel lik:
sinus til vinkel = motstående katet dividert med hypotenusen.

Hypotenusen er alltid den lengste siden i trekanten, derfor er sinusverdien en verdi mellom 0 og 1. Tar vi med negative vinkler, eller vinkler større enn 180 grader,  har sinus verdier fra -1 til 1. Uansett hvilken vinkel vi setter inn, vil sin() returnere en verdi mellom -1 og 1. Dette gjør synsfunksjonen ideell til å lage bølgende eller pulserende bevegelser.

Sinusverdien til en vinkel er lik lengden av motstående katet dividert med lengden av hypotenusen.
Sirkelens radius er lik 1 (enhetssirkelen). Sinusverdien (rød linje, motstående katet) øker mot 1 (90°), minker mot 0 (180°), minker videre mot -1 (270°), øker mot 0 (360°), og øker på nytt mot 1 (90°).

Skriv dette i editoren:

  • let x = 0;
  • let y = 0;
  • let v = 0;
  • function setup() {
    • createCanvas(600, 400);
  • }
  • function draw() {
    • ellipse(x, y, 10, 10);
    • x = x + 1; // x øker med 1 for hver runde
    • y = sin(v); // y får en verdi mellom -1 og 1
    • v = v + radians(20); // Vinkelen v øker med 20 grader
  • }

Dette gir en bølge av punkter der x- koordinaten øker med 1, og  y-koordinaten veksler mellom -1 og 1. Dette blir en veldig unnselig bølge. Vi må gjøre noen justeringer.


7.8 Likevektslinje og amplitude

​Fordi sin() returnerer en verdi mellom -1 og 1 må vi gjøre minst to justeringer for at resultatet skal bli bra. En bevegelse på to punkter der halvparten er utenfor lerretet er ikke mye å rope hurra for.

Vi må justere likevekstlinjen og amplituden (maksimumsutslaget).

Uten justering er likevektslinjen  y = 0. Ved å legge til et tall, flytter vi likevektslinjen nedover på lerretet.

​y = likevektslinje + sin(v)

Uten justering er amplituden 1. Vi justerer ved å multiplisere med den amplituden vi vil ha.

y = likevektslinje + sin(v) * amplituden

På engelsk skrives det ofte slik:
y = offset + sin(v) * scalar

Skriv dette i editoren:

  • let x = 0;
  • let y = 0;
  • let v = 0;
  • function setup() {
    • createCanvas(600, 400);
  • }
  • function draw() {
    • ellipse(x, y, 10, 10);
    • x = x + 10; // x øker med 1 for hver runde
    • y = 200 + sin(v)*20; // y får en verdi mellom -1 og 1
    • v = v + radians(20); // Vinkelen v øker med 20 grader
  • }

7.9 Oppgave

Gjør endringer i de uthevede verdiene i forrige eksempel


7.10 Pulserende sirkler

Skriv dette i editoren (fra processing.org):

  • let radius;
  • let vinkel = 0;
  • function setup() {
    • createCanvas(640, 360);
    • radius = height – 10;
    • noStroke();
    • fill(255, 204, 0);
  • }
  • function draw() {
    • background(0);
    • let d1 = 10 + (sin(vinkel) * radius) + radius;
    • let d2 = 10 + (sin(vinkel + PI/2) * radius) + radius;
    • let d3 = 10 + (sin(vinkel + PI) * radius) + radius;
    • circle(0, height/2, d1/2);
    • circle(width/2, height/2, d2/2);
    • circle(width, height/2, d3/2);
    • vinkel = vinkel + 0.02;
  • }

7.11 Oppgaver

A) Gjør endringer i de uthevede variablene og funksjonsparameterne i forrige eksempel.
B) Sett ulik farge på sirklene.


skolekoding.no
Stein Olav Kivle