If you're seeing this message, it means we're having trouble loading external resources on our website.

Ha webszűrőt használsz, győződj meg róla, hogy a *.kastatic.org és a *.kasandbox.org nincsenek blokkolva.

Fő tartalom

Rugóerők

Ennek a fejezetnek az elején az egyszerű harmonikus mozgás modellezésével foglalkoztunk. A szinusz hullámmal generáltunk egy pixel sorozatot, és ugyancsak a szinusz hullám segítségével modelleztél egy súlyt egy rugó végén. A sin() függvény ilyen alkalmazásával gyorsan és egyszerűen elkészíthetünk egy működő alkalmazást, de ez nem elegendő, ha valami olyat akarunk létrehozni, mint például egy rugón lógó súly mozgása a kétdimenziós térben, ami a környezetében fellépő egyéb erőkre is reagál (pl. szél, gravitáció). Egy ilyen szimulációhoz, (ami megegyezik az ingás példával, csak most a súly egy rugóra van felfüggesztve), a rugó által képviselt erő modellezéséhez PVectort fogunk használni.
A rugó erejét Hooke törvénye alapján számítjuk ki. A képletet Robert Hooke angol fizikus dolgozta ki 1660-ban. Hooke eredetileg latinul így fogalmazott: „Ut tensio, sic vis,” azaz „amilyen a nyúlás, olyan az erő”. Ezt fogalmazzuk meg így:
A rugó ereje egyenesen arányos a rugó megnyúlásával.
Más szóval, ha nagyon lehúzod a súlyt, az erő nagy lesz, ha csak kicsit, akkor gyenge lesz. Matematikailag a törvény így fogalmazható meg:
Frugó=kx
  • A k egy konstans, ami az erő nagyságát fogja befolyásolni aszerint, hogy a rugó mennyire rugalmas, vagy merev.
  • x a rugó elmozdulását jelöli, azaz a jelenlegi hossza és a nyugalmi állapotban lévő hossza közötti különbséget. A nyugalmi állapot szerinti hossz definíciója: az egyensúlyi állapotban lévő rugó hossza.
Ne feledd, az erő egy vektor, tehát ki kell számítani mind a hosszát, mind az irányát! Nézzünk meg még egy ábrát a rugóról, amin megjelölünk minden kiinduló adatot, amire programozás közben szükség lehet!
Vezessük be az alábbi három kezdeti változót a fenti ábra alapján, és határozzunk meg észszerű kezdőértékeket!
var anchor = new PVector(100, 10);
var bob = new PVector(110, 100);
var restLength = 20;
Először alkalmazzuk Hooke törvényét az erő nagyságának kiszámítására. Ismernünk kell k és x értékét. A k könnyű; egy egyszerű konstans, úgyhogy találjunk ki rá valamit.
var k = 0{,}1;
Az x ennél egy kicsit bonyolultabb. Tudnunk kell a „jelenlegi és a nyugalmi állapotban mért hossz különbségét". A nyugalmi állapotban mért hosszt a restLength változó tartalmazza. Mi a jelenlegi hossz? A súly és a felfüggesztési pont közötti különbség. Hogyan tudjuk ezt a távolságot kiszámítani? Mit szólnál a felfüggesztési pontból a súlyhoz vezető vektor hosszához? (Figyeld meg, hogy ez ugyanaz az eljárás, amit a Gravitációs vonzás fejezetben a távolság kiszámításához használtunk!)
var dir = PVector.sub(bob, anchor);
var currentLength = dir.mag();
var x = currentLength - restLength;
Most, hogy összeállítottuk a szükséges összetevőket a (-1 * k * x) erő nagyságának kiszámításához, rá kell jönnünk, hogyan tudjuk kiszámítani az irányt, az erő irányába mutató egységvektort. A jó hír az, hogy már rendelkezünk ezzel a vektorral. Igaz? Épp az előbb mondtuk: „Hogy tudjuk kiszámítani a távolságot? Mit szólnál a felfüggesztési ponttól a súlyig vezető vektor hosszához?” Nos, ugyanez a vektor adja meg az erő irányát is!
A fenti ábrán láthatjuk, hogy ha a rúgót kihúzzuk a nyugalmi állapothoz képest, akkor kell egy erő, ami azt visszahúzza a felfüggesztési pont irányába. Ha viszont a nyugalmi állapothoz képest rövidebbre nyomjuk össze, akkor az erőnek el kell tolnia a felfüggesztési ponttól. Ezt az irányváltást biztosítja a képletben a -1. Tehát csak annyit kell tennünk, hogy normalizáljuk a távolság kiszámításához használt PVector-t. Nézzünk rá a kódra, és nevezzük át a PVector változót „force”-nak.
var k = 0{,}01;
var force = PVector.sub(bob, anchor);
var currentLength = force.mag();
var x = currentLength - restLength;
// A rugóerő iránya, egy egységvektor
force.normalize();
// Mindezt összerakjuk: irány és hossz!
force.mult(-1 * k * x);
Most, hogy kidolgoztuk a rugóerő kiszámításához az algoritmust, még ott a kérdés: milyen objektumorientált struktúrát alkalmazzunk? Ez is azon helyzetek egyike, amikor nincs „jó” válasz. Több lehetőségünk van; az, hogy melyiket választjuk, függ a program céljától és a programozó egyéni stílusától. Mivel mindezidáig egy Mover objektummal dolgoztunk, maradjunk ennél a keretrendszernél. Tekintsük most a rugón található „súlyt” a Mover objektumunknak. A rajzvásznon való mozgáshoz a súlynak szüksége van helyzet-, sebesség- és gyorsulásvektorra. Tökéletes, mindez már megvan! Továbbá a súlyra hathat a gravitációs erő az applyForce() metóduson keresztül. Már csak egy lépés van hátra – aktiválnunk kell a rugóerőt:
var bob = new Bob();

draw = function()  {
  // „Csináljunk egy gravitációs erőt”
  var gravity = new PVector(0, 1);
  bob.applyForce(gravity);
  // El kell készíteni és aktiválni kell a rugóerőt!
  var spring = ????
  bob.applyForce(spring);

  // A szokásos update() és display() metódusok
  bob.update();
  bob.display();
};
Az egyik opció az, hogy a rugóerő kódját beépítjük a draw() főprogram ciklusába. De ha előre gondolkodunk arra az esetre, ha több súly lóg különböző rugókon, akkor értelmesebb egy új objektumot elkészíteni, egy Spring objektumot. Ahogy a fenti ábrán látható, a Bob objektum tartja nyilván a súly mozgását, míg a Spring objektum tárolja a felfüggesztési pontot és a nyugalmi hosszt, és itt számítjuk ki a súlyra ható rugóerőt is.
Így összekötve elegáns kódot kapunk:
var bob = new Bob();
var spring = new Spring();

draw = function()  {
  //  „Csináljunk egy gravitációs erőt"
  var gravity = new PVector(0, 1);
  bob.applyForce(gravity);
  // Spring.connect() összeköti
  // a rugóerő kiszámítását és aktiválását
  spring.connect(bob);

  // A szokásos update() és display() metódusok
  bob.update();
  bob.display();
};
Észrevehetted, hogy ez itt nagyon hasonlít ahhoz, amit a Gravitáció fejezetben csináltunk az Attractor objektummal. Ott valami ilyet mondtunk:
var force = attractor.calculateAttraction(mover);
mover.applyForce(force);
Itt az analóg viselkedés a rugóval ilyen lenne:
var force = spring.calculateForce(bob);
bob.applyForce(force);
Ettől függetlenül ebben a példában csak ennyit tettünk:
spring.connect(bob);
Mi hibázik? Miért nem kell meghívni az applyForce() metódust a súlyra? A válasz az, hogy persze, hogy meg kell hívni az applyForce() metódust a súlyra! Csak ahelyett, hogy a draw()-ban hívnánk meg, azt akarjuk megmutatni, hogy teljesen észszerű (és néha kívánatos) alternatíva a connect() metóduson belül meghívni az applyForce() metódust a súlyra.
Spring.prototype.connect(bob) {
  var force = /* valami tetszés szerinti számítás */;
  bob.applyForce(force);
};
Miért csináljuk a Spring esetében másképp, mint az Attractor objektumban? Amikor először találkoztunk az erőkkel, egyszerűbb volt az összes erőt a fő draw() ciklusban aktiválni, és remélhetőleg ez megkönnyítette az erők összeadódásának megértését. Most már megbarátkoztál ezzel, és talán egyszerűbb egyes részleteket magukba az objektumokba rejteni.
Akkor most rakjunk össze mindent! Az alábbi programban néhány dolgot még hozzáadtunk: (1) a Bob objektum tartalmaz egérkezelést, hogy a súlyt mozgatni lehessen a képernyőn, és (2) a Spring objektum tartalmaz egy függvényt, ami a súly távolságát egy minimum és egy maximum közé korlátozza. (A programban található megjegyzések: 1. sor: Dan Shiffman, natureofcode.com példája alapján; 9. sor: Kiszámolja és aktiválja a rugóerőt; 11. sor: A felfüggesztési pontból a súly felé mutató vektor; 13. sor: Mi a távolság; 15. sor: Stretch a jelenlegi és a nyugalmi állapot közötti távolság; 18. sor: Erő számítása Hooke törvénye alapján; 19. sor: F = k · stretch; 25. sor: A súly és a felfüggesztési pont közötti távolság korlátozása a min és a max között; 33. sor: Helyzet visszaállítása és a mozgás megszüntetése (fizikai értelemben nem valósághű); 61. sor: Bob objektum, hasonló a szokásos Moverhez (helyzet, sebesség, gyorsulás, tömeg); 68. sor: Tetszőleges csillapítás a súrlódás / elhúzás szimulációjához; 70. sor: Felhasználói interakció; 75. sor: Szokásos Euler összesítés; 83. sor: Newton törvénye: F = M · A; 90. sor: Súly rajzolása; 121. sor: Tárgyak megjelenítése a kiindulási helyzetben; 122. sor: Figyeld meg, a Spring konstruktorának harmadik paramétere a „nyugalmi állapotban mért rugóhossz”; 128. sor: Gravitációs erő aktiválása a súlyra; 132. sor: A súly és a rugó összekötése (és az erő kiszámítása); 134. sor: A rugó távolságának korlátozása a minimum és maximum közé; 137. sor: Súly módosítása; 140. sor: Mindent megrajzolunk; 141. sor: Vonalat rajzolunk a rugó és a súly közé.)

Ez a „Természetes szimulációk" tananyag a Daniel Shiffman által készített „The Nature of Code” alapján készült, a Creative Commons Attribution-NonCommercial 3.0 Unported License szerint.

Szeretnél részt venni a beszélgetésben?

Még nincs hozzászólás.
Tudsz angolul? Kattints ide, ha meg szeretnéd nézni, milyen beszélgetések folynak a Khan Academy angol nyelvű oldalán.