- priemyselný dizajn a konštrukcia


Zrýchlenie častíc

 



Simuláciu naprogramoval 8.11.2022 Ing. Ladislav Ides, časť skryptu od Josh Bradley https://joshbradley.me/object-collisions-with-canvas

 

Simulácia čatíc podľa zákona hybnosti P


m= hmotnosť
v= rýchlosť
u= rýchlosť po zrážke

P= m * v
m1 * v1 +  m2 * v2 = m1 * u1 +  m2 * u2

 

Viac o zrýchlení častíc sa dozviete tu: https://www.xtream.sk/zakony-vesmiru

 

Ak sa v priestore nachádza viacej častíc o rôznych veľkostiach, tak sa ich hybnosti vyrovnajú. Vyrovná sa teplota v látke. Teda väčšie častice sa budú pohybovať pomalšie a menšie častice rýchlejšie.

Ukážka je zostavená tak, že na začiatku majú najväčšiu rýchlosť veľké častice. Avšak veľmi rýchlo po zrážkach je vidieť ako sa menšie častice od väčších urýchlia a zoberú im časť hybnosti. Rýchlosť častíc sa tak usporiada podľa veľkostí. Teda veľké častice letia v priemere pomalšie ako menšie častice. Častíc nie je až také veľké množstvo ako v realite, takže vzniká tiež značný náhodný faktor, takže sa občas môže stať že niektorá častica letí mimo priemer svojej veľkosti. Avšak čím viac častíc by sa do simulácie dalo, tým stabilnejšie by boli výsledky. 

Stránku si obnovte, aby ste lepšie videli zrýchlenie malých častíc na začiatku.

 

Okrem zrýchlenia častíc sa dá v simulácií pozorovať aj vznik gravitácie, ktoré je vyvolaná tienením si väčších častíc. Princíp vzniku gravitácie nájdete tu. Vznik gravitácie nie je tak viditeľné, lebo častíc je málo a je to len v 2 dimenziách, teda je tam vyššia pravdepodobnosť zrážky častíc ako v 3D priestore, ale aj tak sa dá všimnúť že väčšie častice do seba narážajú a snažia sa byť čo najbližšie k sebe. Samozrejme faktor náhody ich občas aj oddiali, ale väčšia pravdepodobnosť je že sa budú väčšie častice k sebe približovať. V skutočnosti gravitáciu vytvárajú oveľa menšie  častice, ktorých je oveľa viac a majú vyššie rýchlosti, takže nevznikajú také turbulencie a väčšie častice sú stabilnejšie. Vzniká tam potom určitá frekvencia ich dotyku. Pretože čím viac budeme väčšie častice tlačiť k sebe tým silnejšie sa tiež od seba odrazia. Takže všetko je otázka určitej frekvencie a sily dopadu. Zároveň steny pôsobia ako tienidlo, takže väčšie častice majú často tendenciu aj narážať do stien.

 

 

Simulácia môže byť nepresná a časom sa môžu častice zrýchľovať, alebo spomaľovať. Je to zapríčinené tým, že všetko je založené na výpočtoch, ktoré nie sú s dokonalou presnosťou. 

Podobným spôsobom sa dá simulovať gravitácia, avšak je nutné simulovať oveľa viac častíc, aby sa znížil faktor náhodného zásahu väčších častíc. 

Sila gravitácie, teda znalivej príťažlivosti častíc zapríčinenej rozdielnou veľkosťou častíc nastáva vždy pri zrážkach všetkých druhov častíc. Jej účinok však závisí od hustoty a rozdielu veľkostí rôznych druhov častíc. Je možné ju simulovať a vytvoriť tak miniatúrny model vesmíru bez toho aby sme museli do modelu programovať čokoľvek viac ako je akcia a reakcia častíc. Jediný problém je ten, že matematicky nieje možné počítať zrážky častíc s dokonalou presnosťou, pretože pri výpočtoch dochádza k zaokrúhľovaniu hodnôt. 

 

Pri pozorovaní pohybu častíc, to vyzerá ako bunková aktivita. To naznačuje, že pri takomto množstve kombinácií v nekonečnom čase je vznik buniek a teda života nevyhnutný. 

 

HTML kód pre zobrazenie: 

<script type="text/javascript">sem vložíte zdrojový kód</script>

  <body onload="draw();">
  <canvas id="canvas" width="600" height="600"></canvas>
  </body>


 

Zdrojový kód simulácie: 

//pohyb castic simulacia graviacie 600x600
class State {
  constructor(display, actors) {
    this.display = display;
    this.actors = actors;
  }

  update(time) {

    /**
     * provide an update ID to let actors update other actors only once
     * used with collision detection
     */
    const updateId = Math.floor(Math.random() * 1000000);
    const actors = this.actors.map(actor => {
      return actor.update(this, time, updateId);
    });
    return new State(this.display, actors);
  }
}


class Vector {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  add(vector) {
    return new Vector(this.x + vector.x, this.y + vector.y);
  }

  subtract(vector) {
    return new Vector(this.x - vector.x, this.y - vector.y);
  }

  multiply(scalar) {
    return new Vector(this.x * scalar, this.y * scalar);
  }

  dotProduct(vector) {
    return this.x * vector.x + this.y * vector.y;
  }

  get magnitude() {
    return Math.sqrt(this.x ** 2 + this.y ** 2);
  }

  get direction() {
    return Math.atan2(this.x, this.y);
  }
}

 //ctx = document.getElementById('canvas').getContext('2d');

class Canvas {
  constructor(parent = document.body, width = 10, height = 10) {
    this.canvas = document.createElement('canvas');
    this.canvas.width = width;
    this.canvas.height = height;
    parent.appendChild(this.canvas);
    this.ctx =document.getElementById('canvas').getContext('2d');
  }

  sync(state) {
    this.clearDisplay();
    this.drawActors(state.actors);
  }

  clearDisplay() {

    // opacity controls the trail effect set to 1 to remove
    this.ctx.fillStyle = 'rgba(255, 255, 255, .4)';
    this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
    this.ctx.strokeStyle = 'black';
    this.ctx.strokeRect(0, 0, this.canvas.width, this.canvas.height);
  }

  drawActors(actors) {
    for (let actor of actors) {
      if (actor.type === 'circle') {
        this.drawCircle(actor);
      }
    }
  }

  drawCircle(actor) {
    this.ctx.beginPath();
    this.ctx.arc(actor.position.x, actor.position.y, actor.radius, 0, Math.PI * 2);
    this.ctx.closePath();
    this.ctx.fillStyle = actor.color;
    this.ctx.fill();
  }
}

class Ball {
  constructor(config) {
    Object.assign(this,
      {
        id: Math.floor(Math.random() * 1000000),
        type: 'circle',
        position: new Vector(100, 100),
        velocity: new Vector(3, 3),
        radius: 25,
        color: 'blue',
        collisions: [],
      },
      config
    );
  }

  update(state, time, updateId) {

    /**
     * if slice occurs on too many elements, it starts to lag
     * collisions is an array to allow multiple collisions at once
     */
    if (this.collisions.length > 10) {
      this.collisions = this.collisions.slice(this.collisions.length - 3);
    }

    /**
     * this is the most stable solution to avoid overlap
     * but it is slightly inaccurate
     */
    for (let actor of state.actors) {
      if (this === actor || this.collisions.includes(actor.id + updateId)) {
        continue;
      }

      /**
       * check if actors collide in the next frame and update now if they do
       * innaccurate, but it is the easiest solution to the sticky collision bug
       */
      const distance = this.position.add(this.velocity).subtract(actor.position.add(actor.velocity)).magnitude;

      if (distance <= this.radius + actor.radius) {
        const v1 = collisionVector(this, actor);
        const v2 = collisionVector(actor, this);
        this.velocity = v1;
        actor.velocity = v2;
        this.collisions.push(actor.id + updateId);
        actor.collisions.push(this.id + updateId);
      }
    }

    // setting bounds on the canvas prevents balls from overlapping on update
    const upperLimit = new Vector(state.display.canvas.width - this.radius, state.display.canvas.height - this.radius);
    const lowerLimit = new Vector(0 + this.radius, 0 + this.radius);

    //check if hitting left or right of container
    if (this.position.x >= upperLimit.x || this.position.x <= lowerLimit.x) {
     this.velocity = new Vector(-this.velocity.x, this.velocity.y);
    }

    //if (this.position.x >= upperLimit.x) {//moje
    // this.position.x=lowerLimit.x+1;
    //}

    //if (this.position.x <= lowerLimit.x) {//moje
    // this.position.x=upperLimit.x;
    //}

    // check if hitting top or bottom of container
    if (this.position.y >= upperLimit.y || this.position.y <= lowerLimit.y) {
      this.velocity = new Vector(this.velocity.x, -this.velocity.y);
    }


    //if (this.position.y >= upperLimit.y) {//moje
    // this.position.y=lowerLimit.y+1;
    //}

    //if (this.position.y <= lowerLimit.y) {//moje
    // this.position.y=upperLimit.y;
    //}



 

const newX = Math.max(Math.min(this.position.x + this.velocity.x, upperLimit.x), lowerLimit.x);
const newY = Math.max(Math.min(this.position.y + this.velocity.y, upperLimit.y), lowerLimit.y);

return new Ball({
...this,
position: new Vector(newX, newY),
});
}

get area() {
return Math.PI * this.radius ** 2;
}

get sphereArea() {
return 4 * Math.PI * this.radius ** 2;
}
}

// see elastic collision: https://en.wikipedia.org/wiki/Elastic_collision
const collisionVector = (particle1, particle2) => {
return particle1.velocity
.subtract(particle1.position
.subtract(particle2.position)
.multiply(particle1.velocity
.subtract(particle2.velocity)
.dotProduct(particle1.position.subtract(particle2.position))
/ particle1.position.subtract(particle2.position).magnitude ** 2/1.002 // lomeno 1.002 je spomalenie na vyrovnanie chyby výpočtu
)

// add mass to the system
.multiply((2 * particle2.sphereArea) / (particle1.sphereArea + particle2.sphereArea))
);
};

const isMovingTowards = (particle1, particle2) => {
return particle2.position.subtract(particle1.position).dotProduct(particle1.velocity) > 0;
};

const runAnimation = animation => {
let lastTime = null;
const frame = time => {
if (lastTime !== null) {
const timeStep = Math.min(100, time - lastTime) / 1000;

// return false from animation to stop
if (animation(timeStep) === false) {
return;
}
}
lastTime = time;
requestAnimationFrame(frame);
};
requestAnimationFrame(frame);
};

const random = (max = 9, min = 0) => {
return Math.floor(Math.random() * (max - min + 1) + min);
};

const colors = ['red', 'green', 'blue', 'purple', 'orange'];

const collidingBalls = ({ width = 600, height = 600, parent = document.body, count = 10 } = {}) => {
const display = new Canvas(parent, width, height);
const balls = [];
for (let i = 0; i < 10; i++) {
balls.push(new Ball({
radius: 7,
color: colors[1],
position: new Vector(random(width - 10, 10), random(height - 10, 10)),
velocity: new Vector(random(3, -3), random(3, -3)),
}));
}

//velke
for (let i = 0; i < 2; i++) {
balls.push(new Ball({
radius: 30,
color: colors[2],
position: new Vector(random(width - 10, 10), random(height - 10, 10)),
velocity: new Vector(5, 0),
}));
}

for (let i = 0; i < 2; i++) {
balls.push(new Ball({
radius: 30,
color: colors[2],
position: new Vector(random(width - 10, 10), random(height - 10, 10)),
velocity: new Vector(0,5),
}));
}
for (let i = 0; i < 2; i++) {
balls.push(new Ball({
radius: 30,
color: colors[2],
position: new Vector(random(width - 10, 10), random(height - 10, 10)),
velocity: new Vector(0, -5),
}));
}
for (let i = 0; i < 2; i++) {
balls.push(new Ball({
radius: 30,
color: colors[2],
position: new Vector(random(width - 10, 10), random(height - 10, 10)),
velocity: new Vector(-5, 0),
}));
}
//kioniec velke
for (let i = 0; i < 500; i++) {
balls.push(new Ball({
radius: 3,
color: colors[0],
position: new Vector(random(width - 10, 10), random(height - 10, 10)),
velocity: new Vector(random(3, -3), random(3, -3)),
}));
}

let state = new State(display, balls);
runAnimation(time => {
state = state.update(time);
display.sync(state);
});
};

function draw() {
collidingBalls();
}


    


    
Všetky práva vyhradené. Kopírovanie textu a obrázkov je povolené len so súhlasom XTREAM a.s. a uvedením zdroja www.xtream.sk