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
- add() -- vektorok összeadása
- sub() -- vektorok kivonása
- mult() -- vektorok szorzása
- div() -- vektorok osztása
- mag() -- vektor terjedelmének/hosszának kiszámítása
- normalize() -- egység hosszúságúra normalizálja a vektort
- limit() -- limitálja a vektor terjedelmét/hosszát
- heading2D() -- a vektro iránya fokban kifejezve
- dist() -- az euklédészi* távolság két vektor között (pontban)
*http://wiki.prog.hu/wiki/Euklid%C3%A9szi_algoritmus_(algoritmus) - angleBetween() -- két vektoráltal bezárt szög
- dot() -- két vektor skaláris szorzata
- cross() -- két vektor vektorális szorzata
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/