2013.02.25.
14:20

Írta: harsanyireka

PVector

A vektor olyan értékek gyűjtőhelye amik egy relatív helyzetet határoznak meg a térben. A két pont közé rajzolt nyíl a pontok közötti távolságot jelentik: 

Bevezetés

Az első példában nem alkalmazunk még vektort, csak egy olyan mozgó, visszapattanó "labdát" rajzolunk, ami a következő tulajdonságokkal rendelkezik:

- van helyzete, x és y koordinátával

- sebessége, xseep és yspeed változókkal

- gyorsulása, xacceleration és yacceleration változókkal

- cél helyzete, xtarget és ytarget változóval

- hat rá a szél, xwind és ywind változókkal

- és hat rá a surlódás, xfriction és yfriction változókkal

2 dimenzióban ábrázoljuk, de ha 3d-ben akarnánk akkora z tengelyhez is be kellene vezetnünk a változókat.

float x = 100;
float y = 100;
float xspeed = 1;
float yspeed = 3.3;

void setup() {
  size(200,200);
  smooth();
  background(255);
}

void draw() {
  noStroke();
  fill(255,10);
  rect(0,0,width,height);
  
  // pozíció változtatása a sebességgel:
  x = x + xspeed;
  y = y + yspeed;

  // visszapattanás beállítása:
  if ((x > width) || (x < 0)) {
    xspeed = xspeed * -1;
  }
  if ((y > height) || (y < 0)) {
    yspeed = yspeed * -1;
  }

  // x,y helyzetben megjelenítjük a labdát:
  stroke(0);
  fill(175);
  ellipse(x,y,16,16);
}

  

Ezen float változók helyett használhatunk PVectort is, akár fizikai szimulációhoz is jó. Most csak 2d-ben nézzük meg.

Mit jelentenek a vektorok?

Definíciója szerint a két pont közötti távolságot jelenti. Néhány példa a vektrok (mozgás) átfordítására. Korábban ezt a módszert használtuk ha el akartunk mozdítani egy pontot - meghatároztuk mennyivel mozduljon el x és y irányban:

Ezt lecserélhetjük vektorra, megmondhatjuk egyalakzatnak hogy A pontból B pontba mozduljon, az úgynevezett pixel-sebesség (pixel velocity) érték hozzáadásával:

location = location + velocity

Ha a sebességet egy vektorral adjuk meg, akkor a pozíciót is azzal kell meghatározni? Egyrészt a pozíció egy szimpla pont a térben. Másrészt meghatározható egy útvonal részeként is, ebben az esetben már vektroként is értelmezhetjük és létrehozhatunk egy olyan osztályt a mozgásnak, ami jóval kényelmesebb megoldás, mint egyes pontokat meghatározni. 

Határozzunk meg értékeket a pozíciónak és a sebességnek. A pattogólabda példában ezt így csináltuk:

location --> x,y
velocity --> xspeed,yspeed

Ugyanezt megtehetjükegy osztályon belül is:

class PVector {

  float x;
  float y;

  PVector(float x_, float y_) {
    x = x_;
    y = y_;
  }

}

DE a cél pozíció értékeket (float x és y helyett) megadhatjuk vektorban is:

PVector location = new PVector(100,100);
PVector velocity = new PVector(1,3.3);

Ezek után már algoritmust is írhatunk ezekhez az értékekhez, a korábban használt x=x+speed helyett. A pillanatnyi gyorsulás értéket hozáadjuk a pillanatnyi pozícióhoz:

 location = location + velocity;

Habár a + művelet csak primitív értékekkel működik Processingben. Így afenti sort nem tudja értelmezni, ezért a meghatározott függvényekkel tudunk matematikai műveleteket elvégezni: http://processing.org/reference/PVector.html 

Vektorok összeadása: add()

u = (5,2) 
v = (3,4)

(Vektor jelölése félkövér betűvel, vagy a betű feletti nyíllal. Valós számok dőlt betűvel.)


Minden vektornak két eleme van, x és y érték. Ha két vektort össze akarunk adni akkor az x és az y értékeiket kell összeadnunk:

w = u + v esetén:

wx = ux + vx 
wy = uy + vy

ebben az esetben: 

wx = 5 + 3 
wy = 2 + 4

w = (8,6)

PVector-ok összeadása esetén az add() függvényt tudjuk erre használni. Pontszintaxissal működik. Szintaxisa.

Az előző pattogó labda példa átírása vektor összeadással:

Example: Bouncing Ball with PVector!

// float helyett vektort használunk:
PVector location;
PVector velocity;

void setup() {
  size(200,200);
  smooth();
  background(255);
  location = new PVector(100,100);
  velocity = new PVector(2.5,5);
}

void draw() {
  noStroke();
  fill(255,10);
  rect(0,0,width,height);
  
  // pillanatnyi sebességet a pozícióhoz adjuk:
  location.add(velocity);

  // A vektorok értékeit pont szintaxissal érjük el, 
  // (location.x, velocity.y, stb.)
  if ((location.x > width) || (location.x < 0)) {
    velocity.x = velocity.x * -1;
  }
  if ((location.y > height) || (location.y < 0)) {
    velocity.y = velocity.y * -1;
  }

  // kör megjelenítése x pozícióban:
  stroke(0);
  fill(175);
  ellipse(location.x,location.y,16,16);
}

                       

Az ellipse() fügvényben nem tudsz paraméternek megadni PVectort, mivel neki x és y érték is kell, ezért azokat az értékeket ki kell szedni, így:

ellipse(location.x,location.y,16,16);

Ugyanez igaz a for ciklusra is. A pl a location és a velocity vektor esetén:

if ((location.x > width) || (location.x < 0)) {
  velocity.x = velocity.x * -1;
}

Még több algebra

        

Vektorokról: http://aries.ektf.hu/~hz/pdf-tamop/pdf-01/html/ch01.html 

Példa: Vektorok kivonása, egér mozgást követő vonal, a középpontja fix:

void setup() {
  size(200,200);
  smooth();
}

void draw() {
  background(255);
  
  // két PVector, az egyik az egér helyzete a másik az ablak közepe:
  PVector mouse = new PVector(mouseX,mouseY);
  PVector center = new PVector(width/2,height/2);
  
  // PVector-ok kivonása
  mouse.sub(center);
  /*
// PVector osztás: // az eredeti méret fele lesz ha ezt is bele tesszük: mouse.mult(0.5);
*/
// ábrázoljuk a vektort, vonal kirajzolása: 
translate(width/2,height/2);
line(0,0,mouse.x,mouse.y);
}

Vektor hossza: mag()

Pitagorasz tétel segítségével tudjuk meghatározni, amit a következő képlettel írható le:

||v|| = sqrt(vx*vx + vy*vy)

PVector-nál a mag() függvény felel meg ennek, pontszintaxissal működik. A következő példa balfelső sarokba rajzol egy a vektor aktuális hosszának megfelelő szélességű téglalapot:

void setup() {
  size(200,200);
  smooth();
}

void draw() {
  background(255);
  
  PVector mouse = new PVector(mouseX,mouseY);
  PVector center = new PVector(width/2,height/2);
  mouse.sub(center);

//a vektor hosszát változóként meghatározzuk: float m = mouse.mag(); fill(0); rect(0,0,m,10); translate(width/2,height/2); line(0,0,mouse.x,mouse.y); }

Normalizálás

Szabványosítja a vektort, egységnyi hosszúra alakítja. 

A nagyságával osztjuk el a vektrort ilyenkor. (De 0-val nem oszthatjuk el! Nem működik.)

Példa:

void setup() {
  size(200,200);
  smooth();
}

void draw() {
  background(255);
  
  PVector mouse = new PVector(mouseX,mouseY);
  PVector center = new PVector(width/2,height/2);
  mouse.sub(center);
  
  // normalizáljuk a vektort, majd megszorozzuk 50-nel  
  // Nem számít hol van az egér,mert fix lesz a vektor hossza,
  // a normalizálásnak köszönhetően.
  mouse.normalize();
  mouse.mult(50);

  translate(width/2,height/2);
  line(0,0,mouse.x,mouse.y);
  
}

Mozgás

A pattogó labdánál meghatároztuk a labda helyzetét és sebességét és ezeket adtuk össze hogy megkapjuk a labda aktuális pozícióját.

location.add(velocity);

Ezután kirajzoltuk a labdát a megfelelő helyen:

ellipse(location.x,location.y,16,16);

Setupban és loopban határoztuk meg ezeket. Most ezeket tegyük át egy osztályba! (OOP) A két változót két vektorként defíniáljuk!

class Mover {
  
  PVector location;
  PVector velocity;
void update() {
///aktuálispozícióba mozgatás location.add(velocity); } void display() {
////megjelenítés stroke(0); fill(175); ellipse(location.x,location.y,16,16); } }

Ebből a kódból még hiányzik egy fontos rész, a konstruktor! Ugyanazon a néven, függvényben megadjuk:

 Mover() {
    location = new PVector(random(width),random(height));
    velocity = new PVector(random(-2,2),random(-2,2));
  }

Ugyanebben a "mozgó" osztályban határozzuk meg mi történjen ha az ibjektum az ablakunk széléhez ér! Ha kimegy az egyik oldalon jöjjön be a másikon egyből:      

void checkEdges() {

    if (location.x > width) {
      location.x = 0;
    } else if (location.x < 0) {
      location.x = width;
    }

    if (location.y > height) {
      location.y = 0;
    } else if (location.y < 0) {
      location.y = height;
    }

  }

Most hogy kész van az osztály, már hivatkozhatunk rá. Deklaráljuk:

Mover mover;

Setupban:

 mover = new Mover();

Drawban:

mover.update(); 
mover.checkEdges();
mover.display();

TELJES PÉLDA

// Mover objektum deklarálása
Mover mover;

void setup() {
  size(200,200);
  smooth();
  background(255);
  // Mover objektum létre hozása
  mover = new Mover(); 
}

void draw() {
  noStroke();
  fill(255,10);
  rect(0,0,width,height);
  
  // fügvények meghívása Mover objektumhoz:
  mover.update();
  mover.checkEdges();
  mover.display(); 
}

class Mover {

  //két PVectors: location-pozíció, velocity-sebesség:
  PVector location;
  PVector velocity;

  Mover() {
    location = new PVector(random(width),random(height));
    velocity = new PVector(random(-2,2),random(-2,2));
  }

  void update() {
    // mozgás:pozíció+sebesség
    location.add(velocity);
  }

  void display() {
    stroke(0);
    fill(175);
    ellipse(location.x,location.y,16,16);
  }

  void checkEdges() {

    if (location.x > width) {
      location.x = 0;
    } else if (location.x < 0) {
      location.x = width;
    }
    
    if (location.y > height) {
      location.y = 0;
    } else if (location.y < 0) {
      location.y = height;
    }

  }

}

Ennél érdekesebb mozgást úgy érhetünk el ha a gyorsulásnak is megadunk egy PVektort, és ezt hozzáadjuk a sebességhez:  

  velocity.add(acceleration);
  location.add(velocity);

De használhatunk algoritmusokat is. Lehet a gyorsulás egyenletes vagy random, zajos vagy egérmozgásnak megfelelő is akár.

         

The source code contained in this tutorial is also available for download.

forrás: http://processing.org/learning/pvector/ 

 

3 komment

A bejegyzés trackback címe:

https://processing.blog.hu/api/trackback/id/tr455095803

Kommentek:

A hozzászólások a vonatkozó jogszabályok  értelmében felhasználói tartalomnak minősülnek, értük a szolgáltatás technikai  üzemeltetője semmilyen felelősséget nem vállal, azokat nem ellenőrzi. Kifogás esetén forduljon a blog szerkesztőjéhez. Részletek a  Felhasználási feltételekben és az adatvédelmi tájékoztatóban.

Cica72 2014.04.22. 18:21:16

Szia, én az alábbi (www.processing.org/examples/bouncybubbles.html) tutoriált próbálgattam és értelmeztem, de a collide() sok a homályos rész. Az if-ig "értem" legalábbis azt hiszem, viszont onnantól lefele nem értem, hogy mit miért számol. Nem tudnád nekem elmagyarázni?

Köszönöm, Cica
süti beállítások módosítása