UNPKG

ts-useful

Version:

Functions for animation, color transitions, ecliptic, bezier, decasteljau, curves, three dimensional curves, smooth scrolling, random range, randomItem, mobius index, vectors, physics vectors, and easing.

181 lines 5.72 kB
import { Vector } from '../vector'; import { Drag } from '../constants/calculations'; import { DEFAULT_DENSITY, DEFAULT_DISTANCE, DEFAULT_GRAVITY, DEFAULT_MASS, DEFAULT_RESTITUTION } from '../defaults/physicsVectorOptionDefaults'; import { Clamp } from '../clamp'; import { Coordinate } from './coordinate'; import { Between } from '../between'; export class PhysicsVect extends Vector { /** * * @param params PhysicsVectorOptions */ constructor(params) { super(params?.coordinate); /** * * @param m number * @param d number * @returns */ this.volume = (m, d) => m / d; /** * * @param gravity number * @param axis 'x' | 'y" optional * @returns this */ this.addGravity = (gravity, axis) => { return PhysicsVect.addGravity(this, gravity, axis); }; /** * * @param target IPhysicsVector * @returns this */ this.attract = (target) => { return PhysicsVect.attract(this, target); }; /** * * @param force IVector * @returns this */ this.applyForce = (force) => { return PhysicsVect.applyForce(this, force); }; /** * * @param dragOptions dragOptions * @returns this */ this.drag = (dragOptions) => { return PhysicsVect.drag(this, dragOptions); }; /** * * @returns this */ this.updateGravity = () => { return PhysicsVect.updateGravity(this); }; /** * * @param params { min: coordinate, max: coordinate } * @returns void */ this.bindToArea = (params) => { PhysicsVect.bindToArea(this, params); }; const opts = { ...PhysicsVect.defaultOptions, ...params }; this.gravity = opts.gravity; this.mass = opts.mass; this.acceleration = params?.acceleration ?? new Vector(); this.velocity = params?.velocity ?? new Vector(); this.distanceClamp = opts.distanceClamp; this.density = opts.density; this.restitution = opts.restitution; } } PhysicsVect.defaultOptions = { gravity: DEFAULT_GRAVITY, mass: DEFAULT_MASS, density: DEFAULT_DENSITY, restitution: DEFAULT_RESTITUTION, distanceClamp: DEFAULT_DISTANCE, }; /** * * @param primary IPhysicsVector * @param secondary IPhysicsVector * @returns Vector */ PhysicsVect.attract = (primary, secondary) => { if (!primary.mass || isNaN(primary.mass) || !secondary.mass || isNaN(secondary.mass)) { throw new Error('attract: Main and target must have mass.'); } if (!primary.gravity || isNaN(primary.gravity)) { throw new Error('attract: Main must have gravity.'); } let force = new Vector(Coordinate.subtract(primary, secondary)); const distance = Clamp(force.magnitude, primary.distanceClamp.min, primary.distanceClamp.max); force.normalize(); const strength = (primary.gravity * (primary.mass * secondary.mass)) / Math.pow(distance, 2); return force.multiplyAcross(strength); }; /** * * @param vector IPhysicsVector * @param force IVector * @returns IPhysicsVector */ PhysicsVect.applyForce = (vector, force) => { if (!vector.mass || isNaN(vector.mass)) { throw new Error('applyForce: Vector must have mass'); } if (!vector.acceleration) { throw new Error('applyforce: Vector acceleration is undefined'); } const f = Coordinate.divideAcross(force, vector.mass); vector.acceleration.add(f); return vector; }; /** * * @param vector IPhysicsVector * @param dragOptions dragOptions * @returns IPhysicsVector */ PhysicsVect.drag = (vector, dragOptions) => { if (!vector.velocity) return vector; const { density, area, reynolds, coefficient } = dragOptions; const force = Drag(density)({ area, coefficient, reynolds, velocity: vector.velocity.magnitude }); if (force !== 0) { vector.velocity.divideAcross(force); } return vector; }; /** * * @param vector IPhysicsVector * @param gravity number * @param axis 'x' | 'y' default 'y' * @returns IPhysicsVector */ PhysicsVect.addGravity = (vector, gravity, axis = 'y') => { if (!vector.velocity) { throw new Error('Vector velocity is undefined.'); } vector.velocity.add({ x: axis === 'x' ? gravity : 0, y: axis === 'y' ? gravity : 0 }); return vector; }; /** * * @param vector IPhysicsVector * @returns IPhysicsVector */ PhysicsVect.updateGravity = (vector) => { if (!vector.velocity || !vector.acceleration) { throw new Error('Vector velocity or acceleration are undefined.'); } vector.velocity.add(vector.acceleration); vector.add(vector.velocity); vector.acceleration.set(Coordinate.zero); return vector; }; /** * * @param vector * @param params */ PhysicsVect.bindToArea = (vector, params) => { if (!Between(vector.y, { min: params.min.y, max: params.max.y })) { vector.velocity.y *= vector.restitution; vector.y = vector.y > params.max.y ? params.max.y : params.min.y; } if (!Between(vector.x, { min: params.min.x, max: params.max.x })) { vector.velocity.x *= vector.restitution; vector.x = vector.x > params.max.x ? params.max.x : params.min.x; } }; //# sourceMappingURL=physicsVect.js.map