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
JavaScript
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