Koordinatsystem

Det som berättas här är speciellt för språket processing. Språket har utvecklats för nybörjare men även de som ville skapa digitala grafiska konstverk och spel. I förgående genomgånger har vi jobbat och räknat mycket med koordinater. Det finns vissa instruktioner som gör livet lite enklare när vi sysslar med just det. Tänk om du har till exempel en lite mer komplex figur bestående av flera element som linjer, rektanglar och cirklar. Exempel: hexagonmönster. Men är det lite fel med storlek, läge eller figuren behöver roteras med ett antal grader blir det rätt så jobbigt att beräkna alla koordinater på nytt.

Än så länge har vi jobbat med ett koordinatsystem som har origo i övre vänstre hörnet och enheten är en pixel. Men vi är inte bunden till det kan ändra det. Det finns flera instruktioner som påverkar koordinasystemet och vi använder det för våra behov. Det är ett välkänt sätt inom spelutvecklingen och moderna grafikkort har specialdesignade processorer för precis det. I alla spel men även i applikationer som CAD måste koordianter räknas om till en bild på skärmen. Det gör man genom att ta spelets/ritningens koordinater och slussar de genom en beräkningsmatris. Här nu ett par instruktioner som påverka denna matris:

Förskjutning

Med translate(x,y) kan vi föskjuter origon. Ett exempel hur man flytta origon till mitten:

:::java void setup(){ size(500,500);

translate(width / 2, height /2 ); rect(0,0,100,50);

// två linjer korsar i origo line(-40,0,40,0); line(0,-40,0,40);

}

Vi ritar nu samma rect(0,0,100,50); tio gånger men med en förskjutning efter varje gång. Tänk på att flera förskjutningnar efter varandra adderas:


void setup(){
  size(500,500);

  for(int i = 0;i < 10;i++){
      translate(10, 20 );
      rect(0,0,100,50);  //OBS! Samma koordinater vare gång
  }
}

Till slut har vi en totalförsjutning med 100 i x-led och 200 i y-led.

Skala

Vi kan även påverka skaleringen av koordinaterna med scale(x, y) . Vi har möjlighet att lägga en faktor på enheterna. Tex gör scale(2,2): en förstoring med 2 i båda riktningar medan scale( 0.9, 0.5);** minskar med 10% i x-led och halvera i y-led.

Även här gäller att flera scale()-instruktioner läggs ihop med med multiplikation. scale(2,3); och scale(5,2); är samma som scale(2 x 5, 3 x 2 ); ==> scale(10, 6);.

Ett litet exempel hur en och samma rect(30,30,10,10); kan ändra läge och storlek med translate och scale:


 void setup(){
  size(500,500);
    translate(50, 150 ); // 

  // två linjer korsar i origo
  line(-40,0,40,0);
  line(0,-40,0,40);

  for(int i = 0;i < 20;i++){
      scale(1.2, 1.1);
      rect(30,30,20,20);
  } 
}

Observera att även ramenar blir tjockare/mindre pga scale-instruktionerna! För att motverkar det kan man minskar linjernas tjocklek med strokeWeight(float);

Negativa värden för scale

Negativa värden vända om axlarnas riktning. så

translate( width /2 , height /2);
scale(1, -1);

sätta koordinatsytemet till mitten och vända om y-axeln. Nu har vi det precis som vi känner det från Matematik eller Fysik. Ett exempel hur axeln vänds om med varje omgång av for-satsen:

void setup(){
  size(700,300);
  translate(50, 150 ); // 

  // två linjer korsar i origo
  line(-40,0,40,0);
  line(0,-40,0,40);

  for(int i = 0;i < 20;i++){
    fill(i*22,255,255);
      scale(1, -1);
      translate(25,0);
      rect(30,30,20,20);
  } 
}

Rotation

Instruktion för att rotera koordinatsytemet är rotate(float); . Ett positivt värde rotera medurs, negativ moturs.
MEN Datorn räknar i radianer och inte i vinklar. Senast i Matte 4 kommer ni läsa om Radianer här nu bara det vi behöver:

Istället för 0 till 360 grader går vi över till 0 till 2PI dvs omkrets av en enhetscirkel. PI** är en inbygg konstant som är just det PI = 3,142459.... . De vanligaste vinklar i radian

Formlar för omräkning

formlar vinkel-radian

Ett liten exempel:

//Variabler

void setup(){

  size(500,500);
  background(80,100,255);

  translate(200,300);
  line(-100,0,100,0);  //Markera origo
  line(0,-100,0,100);

  for(int i = 0; i < 12;i++){
    fill(i*20,0,0);
    rect(120,-3,50,6);
    rotate(PI/6);  //motsvarar 30 grader
  }


}

Och det blir så här:

Laboration 1

1 Ändra förgående exempelklocka efter smak och lägger till 60 korta sträck eller dylikt så att det är likt ett siffarblad av en klocka. Lägg sedan till två långa sträck som visa den aktuella tiden. Gör så här :
Skapa två variabler (timme, minut) och sätt in aktuell tid
Fundera/Designa en tim-pekare som peka på kl 12. Samma för minutpekaren
Inn du rita den rotera koordinasystemet till rätt timme,(PI/6 för varje timme) rita timvisaren,
rotera tillbaka till noll,
Rotera för rätt minut (PI/30 för varje minut) och rita minutpekaren.

1.1 Reda sedan ut hur muskoordinater påverkas. Du kan tex lägga till en mousePressed() - block och kolla om koordinaterna blir 0,0 om du klicka på den nya origon i klockan. Kolla


2 Försök att få till det här med scale och rotate: Figur 2. Den här låtsaskoden ska beskriva hur det kan går till:

Pseudokod
Sätt fönstret på 510,510
Flytta origo till mitten
Gör 10 gånger
   Rita kvadrat med kantlängd 500 symetrisk kring origo
   rotera med 45 grad (= PI/4)
   skala ner och rita igen.

För att lista ut faktorn för att skala ner kvadraten kan du lista ut samband mellan a och b i det här. Glöm inte höja strokeWeight() efter varje omgång för all linjerna ska bli lika tjocka. Du får gärna lägga till en färg som ändra sig med varje kvadrat, text vit stegvis till röd.


3 (quite difficult) Koden nedan rita en enda hexagon (honeycomb). I det här fallet är origon precis i mitten. Och man ser att det är krångliga koordinater. De kan beräknas med hjälp av det här. Samma beräkningar sker i koden nedan.


Uppgift: fyll fönstret med ett hexagonmönster. Tanken är i princip samma som med tegelväggen (se kapitel Iteration). Rita en rad hexagoner genom att använda en loop med rita och translate. sedan nästa rad, men förskjuten med en half hexagon till vänster. OSV.

Koden för en hexagon:

```
//Variabler

void setup(){
  size(640,720);
  translate(width / 2, height / 2 ); // flytta origo till mitten

  // Beräkningar enligt figuren
  float D = 100;  // Hexagons höjd 
  float a = D /4; // a i stället för alpha
  float b = sqrt(3) * a;

    //Hexagon kring origo
    line(0,-2*a,b,-a); // nordost
    line(b,-a,b,a); 
    line(b,a,0,2*a); //sydost
    line(0,2*a,-b,a); // underkant
    line(-b,a,-b,-a); // sydväst
    line(-b,-a,0,-2*a); // nordväst

  } // end setup

```

Nollställ

Om translate(x,y), scale(x,y) eller rotate(v) används i draw-blocket så nollställs ändringar av koordinasystemet till övre vänstre hörnet, scala 1 och ingen rotation efter varje omgång av draw!

Ett annat sätt är att använda pushMatrix(); och popMatrix(); med push kan du lägga undan befintliga inställningar och hämtar tillbaka med pop. Ett Exempel


        void setup(){
          size(500,500);
           translate(150,100  ); // flytta origo till mitten (läge 1)
        pushMatrix();  // lägga undan befintlig parametrar för translate,scale och rotate

          for(int i = 0;i < 10;i++){
              translate(10, 20 );
              rotate(PI/30);
              rect(0,0,100,50);  //OBS! Samma koordinater vare gång
          }
          popMatrix();  // hämta tillbaka inställningar för läge 1
          fill(200,0,0);    // markera med röd vad som ritas sist. 
          rect(0,0,100,50);
        }


Ett litet exempel vad man kan göra med rotate och lite extra parameter:


float k = 0.5;

void setup() {
  size(800, 800);
  frameRate(30);
}

void draw() {
  background(0);
  k += 0.0005;
  translate( width /2, height /2);


  for (int j = 0; j < 12; j++) {
    for (int i = 0; i < 12; i++) {
      fill(j*20, 128, 25);
      ellipse(60+ j*30 , 0, 30+j*10, 30+j*10);
      rotate(PI/6-k);  //motsvarar 30 grader
    }
  }
}