Socket
Socket
Sign inDemoInstall

@js-draw/math

Package Overview
Dependencies
Maintainers
1
Versions
20
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@js-draw/math - npm Package Compare versions

Comparing version 1.18.0 to 1.19.0

34

dist/cjs/shapes/PointShape2D.d.ts

@@ -21,3 +21,35 @@ import { Point2 } from '../Vec2';

*/
normalAt(_t: number): Vec3;
normalAt(_t: number): {
readonly x: number;
readonly y: number;
readonly z: number;
readonly 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: number | Vec3): 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;
};
tangentAt(_t: number): Vec3;

@@ -24,0 +56,0 @@ splitAt(_t: number): [PointShape2D];

@@ -60,3 +60,35 @@ import LineSegment2 from './LineSegment2';

get height(): number;
get center(): Vec3;
get center(): {
readonly x: number;
readonly y: number;
readonly z: number;
readonly 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: number | Vec3): 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;
};
getEdges(): LineSegment2[];

@@ -67,4 +99,4 @@ intersectsLineSegment(lineSegment: LineSegment2): Point2[];

transformedBoundingBox(affineTransform: Mat33): Rect2;
/** @return true iff this is equal to [other] ± fuzz */
eq(other: Rect2, fuzz?: number): boolean;
/** @return true iff this is equal to `other ± tolerance` */
eq(other: Rect2, tolerance?: number): boolean;
toString(): string;

@@ -71,0 +103,0 @@ static fromCorners(corner1: Point2, corner2: Point2): Rect2;

6

dist/cjs/shapes/Rect2.js

@@ -230,5 +230,5 @@ "use strict";

}
/** @return true iff this is equal to [other] ± fuzz */
eq(other, fuzz = 0) {
return this.topLeft.eq(other.topLeft, fuzz) && this.size.eq(other.size, fuzz);
/** @return true iff this is equal to `other ± tolerance` */
eq(other, tolerance = 0) {
return this.topLeft.eq(other.topLeft, tolerance) && this.size.eq(other.size, tolerance);
}

@@ -235,0 +235,0 @@ toString() {

@@ -1,42 +0,5 @@

import Vec3 from './Vec3';
/**
* Utility functions that facilitate treating `Vec3`s as 2D vectors.
*
* @example
* ```ts,runnable,console
* import { Vec2 } from '@js-draw/math';
* console.log(Vec2.of(1, 2));
* ```
*/
export declare namespace Vec2 {
/**
* Creates a `Vec2` from an x and y coordinate.
*
* For example,
* ```ts
* const v = Vec2.of(3, 4); // x=3, y=4.
* ```
*/
const of: (x: number, y: number) => Vec2;
/**
* Creates a `Vec2` from an object containing x and y coordinates.
*
* For example,
* ```ts
* 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;
}) => Vec2;
/** A vector of length 1 in the X direction (→). */
const unitX: Vec3;
/** A vector of length 1 in the Y direction (↑). */
const unitY: Vec3;
/** The zero vector: A vector with x=0, y=0. */
const zero: Vec3;
}
import { Vec3, Vec2 } from './Vec3';
export type Point2 = Vec3;
export type Vec2 = Vec3;
export { Vec3, Vec2 };
export default Vec2;
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Vec2 = void 0;
const Vec3_1 = __importDefault(require("./Vec3"));
/**
* Utility functions that facilitate treating `Vec3`s as 2D vectors.
*
* @example
* ```ts,runnable,console
* import { Vec2 } from '@js-draw/math';
* console.log(Vec2.of(1, 2));
* ```
*/
var Vec2;
(function (Vec2) {
/**
* Creates a `Vec2` from an x and y coordinate.
*
* For example,
* ```ts
* const v = Vec2.of(3, 4); // x=3, y=4.
* ```
*/
Vec2.of = (x, y) => {
return Vec3_1.default.of(x, y, 0);
};
/**
* Creates a `Vec2` from an object containing x and y coordinates.
*
* For example,
* ```ts
* const v1 = Vec2.ofXY({ x: 3, y: 4.5 });
* const v2 = Vec2.ofXY({ x: -123.4, y: 1 });
* ```
*/
Vec2.ofXY = ({ x, y }) => {
return Vec3_1.default.of(x, y, 0);
};
/** A vector of length 1 in the X direction (→). */
Vec2.unitX = Vec2.of(1, 0);
/** A vector of length 1 in the Y direction (↑). */
Vec2.unitY = Vec2.of(0, 1);
/** The zero vector: A vector with x=0, y=0. */
Vec2.zero = Vec2.of(0, 0);
})(Vec2 || (exports.Vec2 = Vec2 = {}));
exports.Vec2 = exports.Vec3 = void 0;
// Internally, we define Vec2 as a namespace within Vec3 --
// this allows referencing Vec2s from Vec3 constructors without
// cyclic references.
const Vec3_1 = require("./Vec3");
Object.defineProperty(exports, "Vec3", { enumerable: true, get: function () { return Vec3_1.Vec3; } });
Object.defineProperty(exports, "Vec2", { enumerable: true, get: function () { return Vec3_1.Vec2; } });
exports.default = Vec3_1.Vec2;

@@ -20,18 +20,19 @@ /**

*/
export declare class Vec3 {
export interface Vec3 {
readonly x: number;
readonly y: number;
readonly z: number;
private constructor();
/** Returns the x, y components of this. */
get xy(): {
/**
* Returns the x, y components of this.
* May be implemented as a getter method.
*/
readonly xy: {
x: number;
y: number;
};
/** Construct a vector from three components. */
static of(x: number, y: number, z: number): Vec3;
/** Returns this' `idx`th component. For example, `Vec3.of(1, 2, 3).at(1) → 2`. */
at(idx: number): number;
/** Alias for this.magnitude. */
/** 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;

@@ -45,3 +46,3 @@ magnitudeSquared(): number;

*/
squareDistanceTo(p: Vec3): number;
squareDistanceTo(other: Vec3): number;
/**

@@ -95,7 +96,14 @@ * Interpreting this vector as a point in ℝ³, returns the distance to the point

times(c: number): Vec3;
/** Performs vector addition. */
plus(v: Vec3): Vec3;
minus(v: Vec3): Vec3;
dot(other: Vec3): number;
cross(other: 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,

@@ -160,9 +168,97 @@ * if `other is a `number`, returns the result of scalar multiplication.

*/
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;
static unitX: Vec3;
static unitY: Vec3;
static unitZ: Vec3;
static zero: Vec3;
}
/**
* A `Vec2` is a `Vec3` optimized for working in a plane. As such, they have an
* always-zero `z` component.
*
* ```ts,runnable,console
* import { Vec2 } from '@js-draw/math';
* console.log(Vec2.of(1, 2));
* ```
*/
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;
}
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);
* ```
*/
const of: (x: number, y: number, z: number) => Vec3;
const unitX: Vec2Impl;
const unitY: Vec2Impl;
const zero: Vec2Impl;
/** A vector of length 1 in the z direction. */
const unitZ: Vec3;
}
export default Vec3;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Vec3 = void 0;
/**
* 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());
* ```
*/
class Vec3 {
exports.Vec3 = exports.Vec2 = void 0;
const defaultEqlTolerance = 1e-10;
class Vec3Impl {
constructor(x, y, z) {

@@ -29,3 +11,2 @@ this.x = x;

}
/** Returns the x, y components of this. */
get xy() {

@@ -38,6 +19,2 @@ // Useful for APIs that behave differently if .z is present.

}
/** Construct a vector from three components. */
static of(x, y, z) {
return new Vec3(x, y, z);
}
/** Returns this' `idx`th component. For example, `Vec3.of(1, 2, 3).at(1) → 2`. */

@@ -53,3 +30,2 @@ at(idx) {

}
/** Alias for this.magnitude. */
length() {

@@ -59,13 +35,7 @@ return this.magnitude();

magnitude() {
return Math.sqrt(this.dot(this));
return Math.sqrt(this.magnitudeSquared());
}
magnitudeSquared() {
return this.dot(this);
return this.x * this.x + this.y * this.y + this.z * this.z;
}
/**
* Interpreting this vector as a point in ℝ^3, computes the square distance
* to another point, `p`.
*
* Equivalent to `.minus(p).magnitudeSquared()`.
*/
squareDistanceTo(p) {

@@ -77,49 +47,11 @@ const dx = this.x - p.x;

}
/**
* Interpreting this vector as a point in ℝ³, returns the distance to the point
* `p`.
*
* Equivalent to `.minus(p).magnitude()`.
*/
distanceTo(p) {
return Math.sqrt(this.squareDistanceTo(p));
}
/**
* 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() {
return Math.max(Math.abs(this.x), Math.max(Math.abs(this.y), Math.abs(this.z)));
}
/**
* 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() {
return Math.atan2(this.y, this.x);
}
/**
* Returns a unit vector in the same direction as this.
*
* If `this` has zero length, the resultant vector has `NaN` components.
*/
normalized() {

@@ -129,5 +61,2 @@ const norm = this.magnitude();

}
/**
* Like {@link normalized}, except returns zero if this has zero magnitude.
*/
normalizedOrZero() {

@@ -139,3 +68,2 @@ if (this.eq(Vec3.zero)) {

}
/** @returns A copy of `this` multiplied by a scalar. */
times(c) {

@@ -159,11 +87,2 @@ return Vec3.of(this.x * c, this.y * c, this.z * c);

}
/**
* 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) {

@@ -175,6 +94,2 @@ if (typeof other === 'number') {

}
/**
* Returns a vector orthogonal to this. If this is a Vec2, returns `this` rotated
* 90 degrees counter-clockwise.
*/
orthog() {

@@ -187,38 +102,11 @@ // If parallel to the z-axis

}
/** Returns this plus a vector of length `distance` in `direction`. */
extend(distance, direction) {
return this.plus(direction.normalized().times(distance));
}
/** Returns a vector `fractionTo` of the way to target from this. */
lerp(target, fractionTo) {
return this.times(1 - fractionTo).plus(target.times(fractionTo));
}
/**
* `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, zip) {
return Vec3.of(zip(other.x, this.x), zip(other.y, this.y), zip(other.z, this.z));
}
/**
* 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) {

@@ -230,16 +118,3 @@ return Vec3.of(fn(this.x, 0), fn(this.y, 1), fn(this.z, 2));

}
/**
* [fuzz] 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, fuzz = 1e-10) {
eq(other, fuzz = defaultEqlTolerance) {
return (Math.abs(other.x - this.x) <= fuzz

@@ -253,7 +128,180 @@ && Math.abs(other.y - this.y) <= fuzz

}
exports.Vec3 = Vec3;
Vec3.unitX = Vec3.of(1, 0, 0);
Vec3.unitY = Vec3.of(0, 1, 0);
Vec3.unitZ = Vec3.of(0, 0, 1);
Vec3.zero = Vec3.of(0, 0, 0);
class Vec2Impl {
constructor(x, y) {
this.x = x;
this.y = y;
}
get z() { return 0; }
get xy() {
// Useful for APIs that behave differently if .z is present.
return {
x: this.x,
y: this.y,
};
}
at(idx) {
if (idx === 0)
return this.x;
if (idx === 1)
return this.y;
if (idx === 2)
return 0;
throw new Error(`${idx} out of bounds!`);
}
length() {
return this.magnitude();
}
magnitude() {
return Math.sqrt(this.x * this.x + this.y * this.y);
}
magnitudeSquared() {
return this.x * this.x + this.y * this.y;
}
squareDistanceTo(p) {
const dx = this.x - p.x;
const dy = this.y - p.y;
return dx * dx + dy * dy + p.z * p.z;
}
distanceTo(p) {
return Math.sqrt(this.squareDistanceTo(p));
}
maximumEntryMagnitude() {
return Math.max(Math.abs(this.x), Math.abs(this.y));
}
angle() {
return Math.atan2(this.y, this.x);
}
normalized() {
const norm = this.magnitude();
return Vec2.of(this.x / norm, this.y / norm);
}
normalizedOrZero() {
if (this.eq(Vec3.zero)) {
return Vec3.zero;
}
return this.normalized();
}
times(c) {
return Vec2.of(this.x * c, this.y * c);
}
plus(v) {
return Vec3.of(this.x + v.x, this.y + v.y, v.z);
}
minus(v) {
return Vec3.of(this.x - v.x, this.y - v.y, -v.z);
}
dot(other) {
return this.x * other.x + this.y * other.y;
}
cross(other) {
// | i j k |
// | x1 y1 z1| = (i)(y1z2 - y2z1) - (j)(x1z2 - x2z1) + (k)(x1y2 - x2y1)
// | x2 y2 z2|
return Vec3.of(this.y * other.z, -this.x * other.z, this.x * other.y - other.x * this.y);
}
scale(other) {
if (typeof other === 'number') {
return this.times(other);
}
return Vec2.of(this.x * other.x, this.y * other.y);
}
orthog() {
// If parallel to the z-axis
if (this.dot(Vec3.unitX) === 0 && this.dot(Vec3.unitY) === 0) {
return this.dot(Vec3.unitX) === 0 ? Vec3.unitX : this.cross(Vec3.unitX).normalized();
}
return this.cross(Vec3.unitZ.times(-1)).normalized();
}
extend(distance, direction) {
return this.plus(direction.normalized().times(distance));
}
lerp(target, fractionTo) {
return this.times(1 - fractionTo).plus(target.times(fractionTo));
}
zip(other, zip) {
return Vec3.of(zip(other.x, this.x), zip(other.y, this.y), zip(other.z, 0));
}
map(fn) {
return Vec3.of(fn(this.x, 0), fn(this.y, 1), fn(0, 2));
}
asArray() {
return [this.x, this.y, 0];
}
eq(other, fuzz = defaultEqlTolerance) {
return (Math.abs(other.x - this.x) <= fuzz
&& Math.abs(other.y - this.y) <= fuzz
&& Math.abs(other.z) <= fuzz);
}
toString() {
return `Vec(${this.x}, ${this.y})`;
}
}
/**
* A `Vec2` is a `Vec3` optimized for working in a plane. As such, they have an
* always-zero `z` component.
*
* ```ts,runnable,console
* import { Vec2 } from '@js-draw/math';
* console.log(Vec2.of(1, 2));
* ```
*/
var Vec2;
(function (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.
* ```
*/
Vec2.of = (x, y) => {
return new Vec2Impl(x, y);
};
/**
* 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 });
* ```
*/
Vec2.ofXY = ({ x, y }) => {
return Vec2.of(x, y);
};
/** A vector of length 1 in the X direction (→). */
Vec2.unitX = Vec2.of(1, 0);
/** A vector of length 1 in the Y direction (↑). */
Vec2.unitY = Vec2.of(0, 1);
/** The zero vector: A vector with x=0, y=0. */
Vec2.zero = Vec2.of(0, 0);
})(Vec2 || (exports.Vec2 = Vec2 = {}));
var Vec3;
(function (Vec3) {
/**
* Construct a vector from three components.
*
* @example
* ```ts,runnable,console
* import { Vec3 } from '@js-draw/math';
* const v1 = Vec3.of(1, 2, 3);
* ```
*/
Vec3.of = (x, y, z) => {
if (z === 0) {
return Vec2.of(x, y);
}
else {
return new Vec3Impl(x, y, z);
}
};
Vec3.unitX = Vec2.unitX;
Vec3.unitY = Vec2.unitY;
Vec3.zero = Vec2.zero;
/** A vector of length 1 in the z direction. */
Vec3.unitZ = Vec3.of(0, 0, 1);
})(Vec3 || (exports.Vec3 = Vec3 = {}));
exports.default = Vec3;

@@ -21,3 +21,35 @@ import { Point2 } from '../Vec2';

*/
normalAt(_t: number): Vec3;
normalAt(_t: number): {
readonly x: number;
readonly y: number;
readonly z: number;
readonly 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: number | Vec3): 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;
};
tangentAt(_t: number): Vec3;

@@ -24,0 +56,0 @@ splitAt(_t: number): [PointShape2D];

@@ -60,3 +60,35 @@ import LineSegment2 from './LineSegment2';

get height(): number;
get center(): Vec3;
get center(): {
readonly x: number;
readonly y: number;
readonly z: number;
readonly 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: number | Vec3): 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;
};
getEdges(): LineSegment2[];

@@ -67,4 +99,4 @@ intersectsLineSegment(lineSegment: LineSegment2): Point2[];

transformedBoundingBox(affineTransform: Mat33): Rect2;
/** @return true iff this is equal to [other] ± fuzz */
eq(other: Rect2, fuzz?: number): boolean;
/** @return true iff this is equal to `other ± tolerance` */
eq(other: Rect2, tolerance?: number): boolean;
toString(): string;

@@ -71,0 +103,0 @@ static fromCorners(corner1: Point2, corner2: Point2): Rect2;

@@ -1,42 +0,5 @@

import Vec3 from './Vec3';
/**
* Utility functions that facilitate treating `Vec3`s as 2D vectors.
*
* @example
* ```ts,runnable,console
* import { Vec2 } from '@js-draw/math';
* console.log(Vec2.of(1, 2));
* ```
*/
export declare namespace Vec2 {
/**
* Creates a `Vec2` from an x and y coordinate.
*
* For example,
* ```ts
* const v = Vec2.of(3, 4); // x=3, y=4.
* ```
*/
const of: (x: number, y: number) => Vec2;
/**
* Creates a `Vec2` from an object containing x and y coordinates.
*
* For example,
* ```ts
* 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;
}) => Vec2;
/** A vector of length 1 in the X direction (→). */
const unitX: Vec3;
/** A vector of length 1 in the Y direction (↑). */
const unitY: Vec3;
/** The zero vector: A vector with x=0, y=0. */
const zero: Vec3;
}
import { Vec3, Vec2 } from './Vec3';
export type Point2 = Vec3;
export type Vec2 = Vec3;
export { Vec3, Vec2 };
export default Vec2;

@@ -20,18 +20,19 @@ /**

*/
export declare class Vec3 {
export interface Vec3 {
readonly x: number;
readonly y: number;
readonly z: number;
private constructor();
/** Returns the x, y components of this. */
get xy(): {
/**
* Returns the x, y components of this.
* May be implemented as a getter method.
*/
readonly xy: {
x: number;
y: number;
};
/** Construct a vector from three components. */
static of(x: number, y: number, z: number): Vec3;
/** Returns this' `idx`th component. For example, `Vec3.of(1, 2, 3).at(1) → 2`. */
at(idx: number): number;
/** Alias for this.magnitude. */
/** 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;

@@ -45,3 +46,3 @@ magnitudeSquared(): number;

*/
squareDistanceTo(p: Vec3): number;
squareDistanceTo(other: Vec3): number;
/**

@@ -95,7 +96,14 @@ * Interpreting this vector as a point in ℝ³, returns the distance to the point

times(c: number): Vec3;
/** Performs vector addition. */
plus(v: Vec3): Vec3;
minus(v: Vec3): Vec3;
dot(other: Vec3): number;
cross(other: 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,

@@ -160,9 +168,97 @@ * if `other is a `number`, returns the result of scalar multiplication.

*/
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;
static unitX: Vec3;
static unitY: Vec3;
static unitZ: Vec3;
static zero: Vec3;
}
/**
* A `Vec2` is a `Vec3` optimized for working in a plane. As such, they have an
* always-zero `z` component.
*
* ```ts,runnable,console
* import { Vec2 } from '@js-draw/math';
* console.log(Vec2.of(1, 2));
* ```
*/
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;
}
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);
* ```
*/
const of: (x: number, y: number, z: number) => Vec3;
const unitX: Vec2Impl;
const unitY: Vec2Impl;
const zero: Vec2Impl;
/** A vector of length 1 in the z direction. */
const unitZ: Vec3;
}
export default Vec3;
{
"name": "@js-draw/math",
"version": "1.18.0",
"version": "1.19.0",
"description": "A math library for js-draw. ",

@@ -31,3 +31,3 @@ "types": "./dist/mjs/lib.d.ts",

"devDependencies": {
"@js-draw/build-tool": "^1.17.0",
"@js-draw/build-tool": "^1.19.0",
"@types/bezier-js": "4.1.0",

@@ -49,3 +49,3 @@ "@types/jest": "29.5.5",

],
"gitHead": "73c0d802a8439b5d408ba1e60f91be029db7e402"
"gitHead": "50fa44a2bb68b93d24efea433760a5e45c56293f"
}

@@ -301,5 +301,5 @@ import LineSegment2 from './LineSegment2';

/** @return true iff this is equal to [other] ± fuzz */
public eq(other: Rect2, fuzz: number = 0): boolean {
return this.topLeft.eq(other.topLeft, fuzz) && this.size.eq(other.size, fuzz);
/** @return true iff this is equal to `other ± tolerance` */
public eq(other: Rect2, tolerance: number = 0): boolean {
return this.topLeft.eq(other.topLeft, tolerance) && this.size.eq(other.size, tolerance);
}

@@ -306,0 +306,0 @@

@@ -11,2 +11,3 @@ import { Vec2 } from './Vec2';

expect(Vec2.of(1, 2).plus(Vec2.of(3, 4))).objEq(Vec2.of(4, 6));
expect(Vec2.of(1, 2).plus(Vec3.of(3, 4, 1))).objEq(Vec3.of(4, 6, 1));
});

@@ -16,2 +17,3 @@

expect(Vec2.of(1, -1).times(22)).objEq(Vec2.of(22, -22));
expect(Vec2.of(1, -1).scale(Vec3.of(-1, 2, 3))).objEq(Vec2.of(-1, -2));
});

@@ -28,6 +30,6 @@

it('Perpindicular', () => {
const fuzz = 0.001;
expect(Vec2.unitX.cross(Vec3.unitZ)).objEq(Vec2.unitY.times(-1), fuzz);
expect(Vec2.unitX.orthog()).objEq(Vec2.unitY, fuzz);
const tolerance = 0.001;
expect(Vec2.unitX.cross(Vec3.unitZ)).objEq(Vec2.unitY.times(-1), tolerance);
expect(Vec2.unitX.orthog()).objEq(Vec2.unitY, tolerance);
});
});

@@ -1,49 +0,9 @@

import Vec3 from './Vec3';
// Internally, we define Vec2 as a namespace within Vec3 --
// this allows referencing Vec2s from Vec3 constructors without
// cyclic references.
import { Vec3, Vec2 } from './Vec3';
/**
* Utility functions that facilitate treating `Vec3`s as 2D vectors.
*
* @example
* ```ts,runnable,console
* import { Vec2 } from '@js-draw/math';
* console.log(Vec2.of(1, 2));
* ```
*/
export namespace Vec2 {
/**
* Creates a `Vec2` from an x and y coordinate.
*
* For example,
* ```ts
* const v = Vec2.of(3, 4); // x=3, y=4.
* ```
*/
export const of = (x: number, y: number): Vec2 => {
return Vec3.of(x, y, 0);
};
/**
* Creates a `Vec2` from an object containing x and y coordinates.
*
* For example,
* ```ts
* const v1 = Vec2.ofXY({ x: 3, y: 4.5 });
* const v2 = Vec2.ofXY({ x: -123.4, y: 1 });
* ```
*/
export const ofXY = ({x, y}: { x: number, y: number }): Vec2 => {
return Vec3.of(x, y, 0);
};
/** A vector of length 1 in the X direction (→). */
export const unitX = Vec2.of(1, 0);
/** A vector of length 1 in the Y direction (↑). */
export const unitY = Vec2.of(0, 1);
/** The zero vector: A vector with x=0, y=0. */
export const zero = Vec2.of(0, 0);
}
export type Point2 = Vec3;
export type Vec2 = Vec3; // eslint-disable-line
export type Vec2 = Vec3;
export { Vec3, Vec2 };
export default Vec2;

@@ -22,4 +22,177 @@

*/
export class Vec3 {
private constructor(
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 ];
/**
* [fuzz] 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;
}
const defaultEqlTolerance = 1e-10;
class Vec3Impl implements Vec3 {
public constructor(
public readonly x: number,

@@ -31,3 +204,2 @@ public readonly y: number,

/** Returns the x, y components of this. */
public get xy(): { x: number; y: number } {

@@ -41,7 +213,2 @@ // Useful for APIs that behave differently if .z is present.

/** Construct a vector from three components. */
public static of(x: number, y: number, z: number): Vec3 {
return new Vec3(x, y, z);
}
/** Returns this' `idx`th component. For example, `Vec3.of(1, 2, 3).at(1) → 2`. */

@@ -56,3 +223,2 @@ public at(idx: number): number {

/** Alias for this.magnitude. */
public length(): number {

@@ -63,15 +229,9 @@ return this.magnitude();

public magnitude(): number {
return Math.sqrt(this.dot(this));
return Math.sqrt(this.magnitudeSquared());
}
public magnitudeSquared(): number {
return this.dot(this);
return this.x * this.x + this.y * this.y + this.z * this.z;
}
/**
* Interpreting this vector as a point in ℝ^3, computes the square distance
* to another point, `p`.
*
* Equivalent to `.minus(p).magnitudeSquared()`.
*/
public squareDistanceTo(p: Vec3) {

@@ -84,8 +244,2 @@ const dx = this.x - p.x;

/**
* Interpreting this vector as a point in ℝ³, returns the distance to the point
* `p`.
*
* Equivalent to `.minus(p).magnitude()`.
*/
public distanceTo(p: Vec3) {

@@ -95,14 +249,2 @@ return Math.sqrt(this.squareDistanceTo(p));

/**
* 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
* ```
*/
public maximumEntryMagnitude(): number {

@@ -112,17 +254,2 @@ return Math.max(Math.abs(this.x), Math.max(Math.abs(this.y), Math.abs(this.z)));

/**
* 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)
* ```
*/
public angle(): number {

@@ -132,7 +259,2 @@ return Math.atan2(this.y, this.x);

/**
* Returns a unit vector in the same direction as this.
*
* If `this` has zero length, the resultant vector has `NaN` components.
*/
public normalized(): Vec3 {

@@ -143,5 +265,2 @@ const norm = this.magnitude();

/**
* Like {@link normalized}, except returns zero if this has zero magnitude.
*/
public normalizedOrZero(): Vec3 {

@@ -155,3 +274,2 @@ if (this.eq(Vec3.zero)) {

/** @returns A copy of `this` multiplied by a scalar. */
public times(c: number): Vec3 {

@@ -180,15 +298,6 @@ return Vec3.of(this.x * c, this.y * c, this.z * c);

other.x * this.z - this.x * other.z,
this.x * other.y - other.x * this.y
this.x * other.y - other.x * this.y,
);
}
/**
* 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)
* ```
*/
public scale(other: Vec3|number): Vec3 {

@@ -206,6 +315,2 @@ if (typeof other === 'number') {

/**
* Returns a vector orthogonal to this. If this is a Vec2, returns `this` rotated
* 90 degrees counter-clockwise.
*/
public orthog(): Vec3 {

@@ -220,3 +325,2 @@ // If parallel to the z-axis

/** Returns this plus a vector of length `distance` in `direction`. */
public extend(distance: number, direction: Vec3): Vec3 {

@@ -226,3 +330,2 @@ return this.plus(direction.normalized().times(distance));

/** Returns a vector `fractionTo` of the way to target from this. */
public lerp(target: Vec3, fractionTo: number): Vec3 {

@@ -232,18 +335,2 @@ return this.times(1 - fractionTo).plus(target.times(fractionTo));

/**
* `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)
* ```
*/
public zip(

@@ -259,15 +346,4 @@ other: Vec3, zip: (componentInThis: number, componentInOther: number)=> number

/**
* 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)
* ```
*/
public map(fn: (component: number, index: number)=> number): Vec3 {
return Vec3.of(
fn(this.x, 0), fn(this.y, 1), fn(this.z, 2)
);
return Vec3.of(fn(this.x, 0), fn(this.y, 1), fn(this.z, 2));
}

@@ -279,16 +355,3 @@

/**
* [fuzz] 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
* ```
*/
public eq(other: Vec3, fuzz: number = 1e-10): boolean {
public eq(other: Vec3, fuzz: number = defaultEqlTolerance): boolean {
return (

@@ -304,9 +367,233 @@ Math.abs(other.x - this.x) <= fuzz

}
}
class Vec2Impl implements Vec3 {
public constructor(
public readonly x: number,
public readonly y: number,
) {
}
public static unitX = Vec3.of(1, 0, 0);
public static unitY = Vec3.of(0, 1, 0);
public static unitZ = Vec3.of(0, 0, 1);
public static zero = Vec3.of(0, 0, 0);
public get z() { return 0; }
public get xy(): { x: number; y: number } {
// Useful for APIs that behave differently if .z is present.
return {
x: this.x,
y: this.y,
};
}
public at(idx: number): number {
if (idx === 0) return this.x;
if (idx === 1) return this.y;
if (idx === 2) return 0;
throw new Error(`${idx} out of bounds!`);
}
public length(): number {
return this.magnitude();
}
public magnitude(): number {
return Math.sqrt(this.x * this.x + this.y * this.y);
}
public magnitudeSquared(): number {
return this.x * this.x + this.y * this.y;
}
public squareDistanceTo(p: Vec3) {
const dx = this.x - p.x;
const dy = this.y - p.y;
return dx * dx + dy * dy + p.z * p.z;
}
public distanceTo(p: Vec3) {
return Math.sqrt(this.squareDistanceTo(p));
}
public maximumEntryMagnitude(): number {
return Math.max(Math.abs(this.x), Math.abs(this.y));
}
public angle(): number {
return Math.atan2(this.y, this.x);
}
public normalized(): Vec3 {
const norm = this.magnitude();
return Vec2.of(this.x / norm, this.y / norm);
}
public normalizedOrZero(): Vec3 {
if (this.eq(Vec3.zero)) {
return Vec3.zero;
}
return this.normalized();
}
public times(c: number): Vec3 {
return Vec2.of(this.x * c, this.y * c);
}
public plus(v: Vec3): Vec3 {
return Vec3.of(this.x + v.x, this.y + v.y, v.z);
}
public minus(v: Vec3): Vec3 {
return Vec3.of(this.x - v.x, this.y - v.y, -v.z);
}
public dot(other: Vec3): number {
return this.x * other.x + this.y * other.y;
}
public cross(other: Vec3): Vec3 {
// | i j k |
// | x1 y1 z1| = (i)(y1z2 - y2z1) - (j)(x1z2 - x2z1) + (k)(x1y2 - x2y1)
// | x2 y2 z2|
return Vec3.of(
this.y * other.z,
-this.x * other.z,
this.x * other.y - other.x * this.y,
);
}
public scale(other: Vec3|number): Vec3 {
if (typeof other === 'number') {
return this.times(other);
}
return Vec2.of(
this.x * other.x,
this.y * other.y,
);
}
public orthog(): Vec3 {
// If parallel to the z-axis
if (this.dot(Vec3.unitX) === 0 && this.dot(Vec3.unitY) === 0) {
return this.dot(Vec3.unitX) === 0 ? Vec3.unitX : this.cross(Vec3.unitX).normalized();
}
return this.cross(Vec3.unitZ.times(-1)).normalized();
}
public extend(distance: number, direction: Vec3): Vec3 {
return this.plus(direction.normalized().times(distance));
}
public lerp(target: Vec3, fractionTo: number): Vec3 {
return this.times(1 - fractionTo).plus(target.times(fractionTo));
}
public zip(
other: Vec3, zip: (componentInThis: number, componentInOther: number)=> number
): Vec3 {
return Vec3.of(
zip(other.x, this.x),
zip(other.y, this.y),
zip(other.z, 0),
);
}
public map(fn: (component: number, index: number)=> number): Vec3 {
return Vec3.of(
fn(this.x, 0), fn(this.y, 1), fn(0, 2)
);
}
public asArray(): [ number, number, number ] {
return [this.x, this.y, 0];
}
public eq(other: Vec3, fuzz: number = defaultEqlTolerance): boolean {
return (
Math.abs(other.x - this.x) <= fuzz
&& Math.abs(other.y - this.y) <= fuzz
&& Math.abs(other.z) <= fuzz
);
}
public toString(): string {
return `Vec(${this.x}, ${this.y})`;
}
}
/**
* A `Vec2` is a `Vec3` optimized for working in a plane. As such, they have an
* always-zero `z` component.
*
* ```ts,runnable,console
* import { Vec2 } from '@js-draw/math';
* console.log(Vec2.of(1, 2));
* ```
*/
export 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.
* ```
*/
export const of = (x: number, y: number) => {
return new Vec2Impl(x, y);
};
/**
* 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 });
* ```
*/
export const ofXY = ({x, y}: {x: number, y: number}) => {
return Vec2.of(x, y);
};
/** A vector of length 1 in the X direction (→). */
export const unitX = Vec2.of(1, 0);
/** A vector of length 1 in the Y direction (↑). */
export const unitY = Vec2.of(0, 1);
/** The zero vector: A vector with x=0, y=0. */
export const zero = Vec2.of(0, 0);
}
export 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);
* ```
*/
export const of = (x: number, y: number, z: number): Vec3 => {
if (z === 0) {
return Vec2.of(x, y);
} else {
return new Vec3Impl(x, y, z);
}
};
export const unitX = Vec2.unitX;
export const unitY = Vec2.unitY;
export const zero = Vec2.zero;
/** A vector of length 1 in the z direction. */
export const unitZ = Vec3.of(0, 0, 1);
}
export default Vec3;

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc