behaviors_PenaltyCollision.js
const NearBehavior = require("./NearBehavior");
/**
* `Collision` is a `NearBehavior` that calculates collision interactions between a particle and its nearby particles using softer penalty forces.
* Collisions are basically spring constraints between particles when they collide. High stiffness values can lead to energy inconsistency, whereas
* lower stiffness can cause poor colliding behavior between particles. Overall, this method is more stable in high density stacking simulations,
* but performs worse in more dynamic scenarios.
* @extends {NearBehavior}
*/
class PenaltyCollision extends NearBehavior {
/**
* Instantiates new PenaltyCollision behavior object
* @constructor
*/
constructor(stiffness) {
super();
this.hasCorrection = false;
this.stiffness = stiffness;
}
/**
* Perform the collision update of a `Particle` by calculating impulse based velocity and position changes.
* @override
* @param {Particle} particle - particle with collision check
* @param {Particle[]} particles - nearby particles that interact with `particle`
* @param {Number} timeStep
*/
applyBehavior(particle, timeStep, particles) {
let impulse = new Vector2D(0,0);
let position = particle.pos;
let mass = particle.mass;
let velocity = particle.vel;
let bounciness = particle.bounciness;
let radius = particle.radius;
for (let circ of particles) {
if (circ != particle) {
let c_position = circ.pos;
let c_mass = circ.mass;
let c_velocity = circ.vel;
let c_radius = circ.radius;
let dp = position.sub(c_position);
let posDiffMagSqr = dp.magSqr();
if (posDiffMagSqr < (radius + c_radius) * (radius + c_radius)) {
let dpMag = dp.mag();
dp.multTo(1 / dpMag);
let dxMag = radius + c_radius - dpMag;
let force = dp.mult(-this.stiffness * dxMag);
const a1 = force.mult(1 / c_mass);
const a2 = force.mult(1 / mass);
a1.multTo(timeStep * timeStep);
a2.multTo(timeStep * timeStep);
impulse.addTo(a2);
circ.pos.addTo(a1);
}
}
}
//velocity.subTo(impulse.mult(bounciness));
position.subTo(impulse.mult(bounciness));
}
/**
* This class does not require final position corrections
* @override
* @param {Particle} particle - particle with collision check
* @param {Particle[]} particles - nearby particles that interact with `particle`
*/
applyCorrection(particle, particles) {
return;
}
/**
* @override
* @returns {null}
*/
range() {
return null;
}
/**
* A static method that checks whether two particles are colliding
* @param {Particle} p1
* @param {Particle} p2
* @returns boolean
* @static
*/
static isCollide(p1, p2) {
let position = p1.pos;
let radius = p1.radius;
let c_position = p2.pos;
let c_radius = p2.radius;
let posDiff1 = position.sub(c_position);
return posDiff1.magSqr() < (radius + c_radius) * (radius + c_radius);
}
}
module.exports = PenaltyCollision;