@js-draw/math
Version:
A math library for js-draw.
270 lines (269 loc) • 8.81 kB
TypeScript
/**
* A vector with three components, $\begin{pmatrix} x \\ y \\ z \end{pmatrix}$.
* Can also be used to represent a two-component vector.
*
* A `Vec3` is immutable.
*
* @example
*
* ```ts,runnable,console
* import { Vec3 } from '@js-draw/math';
*
* console.log('Vector addition:', Vec3.of(1, 2, 3).plus(Vec3.of(0, 1, 0)));
* console.log('Scalar multiplication:', Vec3.of(1, 2, 3).times(2));
* console.log('Cross products:', Vec3.unitX.cross(Vec3.unitY));
* console.log('Magnitude:', Vec3.of(1, 2, 3).length(), 'or', Vec3.of(1, 2, 3).magnitude());
* console.log('Square Magnitude:', Vec3.of(1, 2, 3).magnitudeSquared());
* console.log('As an array:', Vec3.unitZ.asArray());
* ```
*/
export interface Vec3 {
readonly x: number;
readonly y: number;
readonly z: number;
/**
* Returns the x, y components of this.
* May be implemented as a getter method.
*/
readonly xy: {
x: number;
y: number;
};
/** Returns the vector's `idx`th component. For example, `Vec3.of(1, 2, 3).at(1) → 2`. */
at(i: number): number;
/** Alias for `.magnitude`. */
length(): number;
/** Returns the length of this vector in ℝ^3. */
magnitude(): number;
magnitudeSquared(): number;
/**
* Interpreting this vector as a point in ℝ^3, computes the square distance
* to another point, `p`.
*
* Equivalent to `.minus(p).magnitudeSquared()`.
*/
squareDistanceTo(other: Vec3): number;
/**
* Interpreting this vector as a point in ℝ³, returns the distance to the point
* `p`.
*
* Equivalent to `.minus(p).magnitude()`.
*/
distanceTo(p: Vec3): number;
/**
* Returns the entry of this with the greatest magnitude.
*
* In other words, returns $\max \{ |x| : x \in {\bf v} \}$, where ${\bf v}$ is the set of
* all entries of this vector.
*
* **Example**:
* ```ts,runnable,console
* import { Vec3 } from '@js-draw/math';
* console.log(Vec3.of(-1, -10, 8).maximumEntryMagnitude()); // -> 10
* ```
*/
maximumEntryMagnitude(): number;
/**
* Return this' angle in the XY plane (treats this as a Vec2).
*
* This is equivalent to `Math.atan2(vec.y, vec.x)`.
*
* As such, observing that `Math.atan2(-0, -1)` $\approx -\pi$ and `Math.atan2(0, -1)` $\approx \pi$
* the resultant angle is in the range $[-\pi, \pi]$.
*
* **Example**:
* ```ts,runnable,console
* import { Vec2 } from '@js-draw/math';
* console.log(Vec2.of(-1, -0).angle()); // atan2(-0, -1)
* console.log(Vec2.of(-1, 0).angle()); // atan2(0, -1)
* ```
*/
angle(): number;
/**
* Returns a unit vector in the same direction as this.
*
* If `this` has zero length, the resultant vector has `NaN` components.
*/
normalized(): Vec3;
/**
* Like {@link normalized}, except returns zero if this has zero magnitude.
*/
normalizedOrZero(): Vec3;
/** @returns A copy of `this` multiplied by a scalar. */
times(c: number): Vec3;
/** Performs vector addition. */
plus(v: Vec3): Vec3;
minus(v: Vec3): Vec3;
/**
* Computes the scalar product between this and `v`.
*
* In particular, `a.dot(b)` is equivalent to `a.x * b.x + a.y * b.y + a.z * b.z`.
*/
dot(v: Vec3): number;
/** Computes the cross product between this and `v` */
cross(v: Vec3): Vec3;
/**
* If `other` is a `Vec3`, multiplies `this` component-wise by `other`. Otherwise,
* if `other is a `number`, returns the result of scalar multiplication.
*
* @example
* ```
* Vec3.of(1, 2, 3).scale(Vec3.of(2, 4, 6)); // → Vec3(2, 8, 18)
* ```
*/
scale(other: Vec3 | number): Vec3;
/**
* Returns a vector orthogonal to this. If this is a Vec2, returns `this` rotated
* 90 degrees counter-clockwise.
*/
orthog(): Vec3;
/** Returns this plus a vector of length `distance` in `direction`. */
extend(distance: number, direction: Vec3): Vec3;
/** Returns a vector `fractionTo` of the way to target from this. */
lerp(target: Vec3, fractionTo: number): Vec3;
/**
* `zip` Maps a component of this and a corresponding component of
* `other` to a component of the output vector.
*
* @example
* ```
* const a = Vec3.of(1, 2, 3);
* const b = Vec3.of(0.5, 2.1, 2.9);
*
* const zipped = a.zip(b, (aComponent, bComponent) => {
* return Math.min(aComponent, bComponent);
* });
*
* console.log(zipped.toString()); // → Vec(0.5, 2, 2.9)
* ```
*/
zip(other: Vec3, zip: (componentInThis: number, componentInOther: number) => number): Vec3;
/**
* Returns a vector with each component acted on by `fn`.
*
* @example
* ```ts,runnable,console
* import { Vec3 } from '@js-draw/math';
* console.log(Vec3.of(1, 2, 3).map(val => val + 1)); // → Vec(2, 3, 4)
* ```
*/
map(fn: (component: number, index: number) => number): Vec3;
asArray(): [number, number, number];
/**
* @param tolerance The maximum difference between two components for this and [other]
* to be considered equal.
*
* @example
* ```
* Vec3.of(1, 2, 3).eq(Vec3.of(4, 5, 6), 100); // → true
* Vec3.of(1, 2, 3).eq(Vec3.of(4, 5, 6), 0.1); // → false
* Vec3.of(1, 2, 3).eq(Vec3.of(4, 5, 6), 3); // → true
* Vec3.of(1, 2, 3).eq(Vec3.of(4, 5, 6), 3.01); // → true
* Vec3.of(1, 2, 3).eq(Vec3.of(4, 5, 6), 2.99); // → false
* ```
*/
eq(other: Vec3, tolerance?: number): boolean;
toString(): string;
}
declare class Vec2Impl implements Vec3 {
readonly x: number;
readonly y: number;
constructor(x: number, y: number);
get z(): number;
get xy(): {
x: number;
y: number;
};
at(idx: number): number;
length(): number;
magnitude(): number;
magnitudeSquared(): number;
squareDistanceTo(p: Vec3): number;
distanceTo(p: Vec3): number;
maximumEntryMagnitude(): number;
angle(): number;
normalized(): Vec3;
normalizedOrZero(): Vec3;
times(c: number): Vec3;
plus(v: Vec3): Vec3;
minus(v: Vec3): Vec3;
dot(other: Vec3): number;
cross(other: Vec3): Vec3;
scale(other: Vec3 | number): Vec3;
orthog(): Vec3;
extend(distance: number, direction: Vec3): Vec3;
lerp(target: Vec3, fractionTo: number): Vec3;
zip(other: Vec3, zip: (componentInThis: number, componentInOther: number) => number): Vec3;
map(fn: (component: number, index: number) => number): Vec3;
asArray(): [number, number, number];
eq(other: Vec3, fuzz?: number): boolean;
toString(): string;
}
/**
* A `Vec2` is a {@link Vec3} optimized for working in a plane. `Vec2`s have an
* always-zero `z` component.
*
* ```ts,runnable,console
* import { Vec2 } from '@js-draw/math';
*
* const v = Vec2.of(1, 2);
* console.log('a Vec2:', v);
* console.log('x component:', v.x);
* console.log('z component:', v.z);
* ```
*/
export declare namespace Vec2 {
/**
* Creates a `Vec2` from an x and y coordinate.
*
* @example
* ```ts,runnable,console
* import { Vec2 } from '@js-draw/math';
* const v = Vec2.of(3, 4); // x=3, y=4.
* ```
*/
const of: (x: number, y: number) => Vec2Impl;
/**
* Creates a `Vec2` from an object containing `x` and `y` coordinates.
*
* @example
* ```ts,runnable,console
* import { Vec2 } from '@js-draw/math';
* const v1 = Vec2.ofXY({ x: 3, y: 4.5 });
* const v2 = Vec2.ofXY({ x: -123.4, y: 1 });
* ```
*/
const ofXY: ({ x, y }: {
x: number;
y: number;
}) => Vec2Impl;
/** A vector of length 1 in the X direction (→). */
const unitX: Vec2Impl;
/** A vector of length 1 in the Y direction (↑). */
const unitY: Vec2Impl;
/** The zero vector: A vector with x=0, y=0. */
const zero: Vec2Impl;
}
/** Contains static methods for constructing a {@link Vec3}. */
export declare namespace Vec3 {
/**
* Construct a vector from three components.
*
* @example
* ```ts,runnable,console
* import { Vec3 } from '@js-draw/math';
* const v1 = Vec3.of(1, 2, 3);
* console.log(v1.plus(Vec3.of(0, 100, 0)));
* ```
*/
const of: (x: number, y: number, z: number) => Vec3;
/** A unit vector in the x direction (`[1, 0, 0]`). */
const unitX: Vec2Impl;
/** A unit vector in the y direction (`[0, 1, 0]`). */
const unitY: Vec2Impl;
/** The zero vector (`[0, 0, 0]`). */
const zero: Vec2Impl;
/** A vector of length 1 in the z direction. */
const unitZ: Vec3;
}
export default Vec3;