From e58e9d29189e2d289aa0bc5a6f06f4d3a4c7cef9 Mon Sep 17 00:00:00 2001 From: yzrmn Date: Wed, 10 Jul 2024 15:44:53 +0200 Subject: [PATCH] Add primitive object conversion methods --- packages/redgeometry-app/src/parts/matrix.ts | 4 +- .../redgeometry-app/src/parts/path-area.ts | 2 +- packages/redgeometry/src/core/path.ts | 14 +++- packages/redgeometry/src/primitives/bezier.ts | 74 ++++++++++++++----- packages/redgeometry/src/primitives/box.ts | 24 ++++-- packages/redgeometry/src/primitives/color.ts | 12 ++- .../redgeometry/src/primitives/complex.ts | 19 +++-- packages/redgeometry/src/primitives/edge.ts | 34 ++++++--- packages/redgeometry/src/primitives/point.ts | 39 +++++++--- .../redgeometry/src/primitives/quaternion.ts | 21 ++++-- packages/redgeometry/src/primitives/ray.ts | 36 ++++++--- packages/redgeometry/src/primitives/vector.ts | 60 +++++++++++---- 12 files changed, 252 insertions(+), 87 deletions(-) diff --git a/packages/redgeometry-app/src/parts/matrix.ts b/packages/redgeometry-app/src/parts/matrix.ts index b828ada..89d6456 100644 --- a/packages/redgeometry-app/src/parts/matrix.ts +++ b/packages/redgeometry-app/src/parts/matrix.ts @@ -164,8 +164,8 @@ function transformEdges(edges: Edge3[], m: Matrix4): Edge2[] { for (const e of edges) { const p0 = m.mulPt(e.p0); const p1 = m.mulPt(e.p1); - const pp0 = Point2.from(p0); - const pp1 = Point2.from(p1); + const pp0 = Point2.fromObject(p0); + const pp1 = Point2.fromObject(p1); output.push(new Edge2(pp0, pp1)); } diff --git a/packages/redgeometry-app/src/parts/path-area.ts b/packages/redgeometry-app/src/parts/path-area.ts index 8e323f8..80ecc4b 100644 --- a/packages/redgeometry-app/src/parts/path-area.ts +++ b/packages/redgeometry-app/src/parts/path-area.ts @@ -80,7 +80,7 @@ function updateSystem(world: World): void { const path = createRandomPath(random, generator, count, canvasWidth, canvasHeight); path.close(); - const p = Point2.from(mouse.getCursorPosition()); + const p = Point2.fromObject(mouse.getCursorPosition()); world.writeData({ dataId: "app-part-remote", diff --git a/packages/redgeometry/src/core/path.ts b/packages/redgeometry/src/core/path.ts index b39957a..23951df 100644 --- a/packages/redgeometry/src/core/path.ts +++ b/packages/redgeometry/src/core/path.ts @@ -3,7 +3,7 @@ import { copyCommandsReversed, isWindingInside } from "../internal/path.js"; import { CurveType, type BezierCurve2 } from "../primitives/bezier.js"; import { Box2 } from "../primitives/box.js"; import { Matrix3A, type Matrix3 } from "../primitives/matrix.js"; -import { Point2 } from "../primitives/point.js"; +import { Point2, type Point2Like } from "../primitives/point.js"; import { Polygon2 } from "../primitives/polygon.js"; import { Vector2 } from "../primitives/vector.js"; import { copyArray, copyArrayReversed } from "../utility/array.js"; @@ -76,6 +76,18 @@ export class Path2 implements PathSink2 { return new Path2([], []); } + public static fromObject(obj: { points: Point2Like[]; commands: PathCommand[] }): Path2 { + const commands = obj.commands.map((c) => ({ ...c })); + const points = obj.points.map((p) => Point2.fromObject(p)); + return new Path2(commands, points); + } + + public static toObject(path: Path2): { points: Point2Like[]; commands: PathCommand[] } { + const commands = path.commands.map((c) => ({ ...c })); + const points = path.points.map((p) => Point2.toObject(p)); + return { commands, points }; + } + public addArc(p0: Point2, p1: Point2, p2: Point2): void { this.moveTo(p0); this.arcTo(p1, p2); diff --git a/packages/redgeometry/src/primitives/bezier.ts b/packages/redgeometry/src/primitives/bezier.ts index ed97e50..8f2598a 100644 --- a/packages/redgeometry/src/primitives/bezier.ts +++ b/packages/redgeometry/src/primitives/bezier.ts @@ -11,7 +11,7 @@ import { Interval } from "../utility/interval.js"; import { RootType, solveCubic, solveLinear, solveQuadratic } from "../utility/solve.js"; import { Box2 } from "./box.js"; import { Edge2 } from "./edge.js"; -import { Point2, Point3 } from "./point.js"; +import { Point2, Point3, type Point2Like } from "./point.js"; import { Vector2, type Vector3 } from "./vector.js"; export enum CurveType { @@ -40,10 +40,6 @@ export class Bezier1Curve2 { return CurveType.Bezier1; } - public static from(obj: { p0: Point2; p1: Point2 }): Bezier1Curve2 { - return new Bezier1Curve2(obj.p0, obj.p1); - } - public static fromArray(data: number[], offset = 0): Bezier1Curve2 { const p0 = Point2.fromArray(data, offset); const p1 = Point2.fromArray(data, offset + 2); @@ -51,6 +47,12 @@ export class Bezier1Curve2 { return new Bezier1Curve2(p0, p1); } + public static fromObject(obj: { p0: Point2Like; p1: Point2Like }): Bezier1Curve2 { + const p0 = Point2.fromObject(obj.p0); + const p1 = Point2.fromObject(obj.p1); + return new Bezier1Curve2(p0, p1); + } + public static fromXY(x0: number, y0: number, x1: number, y1: number): Bezier1Curve2 { const p0 = new Point2(x0, y0); const p1 = new Point2(x1, y1); @@ -79,6 +81,12 @@ export class Bezier1Curve2 { return result; } + public static toObject(c: Bezier1Curve2): { p0: Point2Like; p1: Point2Like } { + const p0 = Point2.toObject(c.p0); + const p1 = Point2.toObject(c.p1); + return { p0, p1 }; + } + public clone(): Bezier1Curve2 { return new Bezier1Curve2(this.p0.clone(), this.p1.clone()); } @@ -211,10 +219,6 @@ export class Bezier2Curve2 { return CurveType.Bezier2; } - public static from(obj: { p0: Point2; p1: Point2; p2: Point2 }): Bezier2Curve2 { - return new Bezier2Curve2(obj.p0, obj.p1, obj.p2); - } - public static fromArray(data: number[], offset = 0): Bezier2Curve2 { const p0 = Point2.fromArray(data, offset); const p1 = Point2.fromArray(data, offset + 2); @@ -223,6 +227,13 @@ export class Bezier2Curve2 { return new Bezier2Curve2(p0, p1, p2); } + public static fromObject(obj: { p0: Point2Like; p1: Point2Like; p2: Point2Like }): Bezier2Curve2 { + const p0 = Point2.fromObject(obj.p0); + const p1 = Point2.fromObject(obj.p1); + const p2 = Point2.fromObject(obj.p2); + return new Bezier2Curve2(p0, p1, p2); + } + public static fromXY(x0: number, y0: number, x1: number, y1: number, x2: number, y2: number): Bezier2Curve2 { const p0 = new Point2(x0, y0); const p1 = new Point2(x1, y1); @@ -231,6 +242,13 @@ export class Bezier2Curve2 { return new Bezier2Curve2(p0, p1, p2); } + public static toObject(c: Bezier2Curve2): { p0: Point2Like; p1: Point2Like; p2: Point2Like } { + const p0 = Point2.toObject(c.p0); + const p1 = Point2.toObject(c.p1); + const p2 = Point2.toObject(c.p2); + return { p0, p1, p2 }; + } + public clone(): Bezier2Curve2 { return new Bezier2Curve2(this.p0.clone(), this.p1.clone(), this.p2.clone()); } @@ -567,10 +585,6 @@ export class Bezier3Curve2 { return CurveType.Bezier3; } - public static from(obj: { p0: Point2; p1: Point2; p2: Point2; p3: Point2 }): Bezier3Curve2 { - return new Bezier3Curve2(obj.p0, obj.p1, obj.p2, obj.p3); - } - public static fromArray(data: number[], offset = 0): Bezier3Curve2 { const p0 = Point2.fromArray(data, offset); const p1 = Point2.fromArray(data, offset + 2); @@ -580,6 +594,14 @@ export class Bezier3Curve2 { return new Bezier3Curve2(p0, p1, p2, p3); } + public static fromObject(obj: { p0: Point2Like; p1: Point2Like; p2: Point2Like; p3: Point2Like }): Bezier3Curve2 { + const p0 = Point2.fromObject(obj.p0); + const p1 = Point2.fromObject(obj.p1); + const p2 = Point2.fromObject(obj.p2); + const p3 = Point2.fromObject(obj.p3); + return new Bezier3Curve2(p0, p1, p2, p3); + } + public static fromXY( x0: number, y0: number, @@ -598,6 +620,14 @@ export class Bezier3Curve2 { return new Bezier3Curve2(p0, p1, p2, p3); } + public static toObject(c: Bezier3Curve2): { p0: Point2Like; p1: Point2Like; p2: Point2Like; p3: Point2Like } { + const p0 = Point2.toObject(c.p0); + const p1 = Point2.toObject(c.p1); + const p2 = Point2.toObject(c.p2); + const p3 = Point2.toObject(c.p3); + return { p0, p1, p2, p3 }; + } + public clone(): Bezier3Curve2 { return new Bezier3Curve2(this.p0.clone(), this.p1.clone(), this.p2.clone(), this.p3.clone()); } @@ -931,10 +961,6 @@ export class BezierRCurve2 { return CurveType.BezierR; } - public static from(obj: { p0: Point2; p1: Point2; p2: Point2; w: number }): BezierRCurve2 { - return new BezierRCurve2(obj.p0, obj.p1, obj.p2, obj.w); - } - public static fromArray(data: number[], offset = 0): BezierRCurve2 { const p0 = Point2.fromArray(data, offset); const p1 = Point2.fromArray(data, offset + 2); @@ -952,6 +978,13 @@ export class BezierRCurve2 { return new BezierRCurve2(p0, p1, p2, w); } + public static fromObject(obj: { p0: Point2Like; p1: Point2Like; p2: Point2Like; w: number }): BezierRCurve2 { + const p0 = Point2.fromObject(obj.p0); + const p1 = Point2.fromObject(obj.p1); + const p2 = Point2.fromObject(obj.p2); + return new BezierRCurve2(p0, p1, p2, obj.w); + } + public static fromProjectivePoints(p0: Point3, p1: Point3, p2: Point3): BezierRCurve2 { const pp0 = Point2.fromXYW(p0.x, p0.y, p0.z); const pp1 = Point2.fromXYW(p1.x, p1.y, p1.z); @@ -988,6 +1021,13 @@ export class BezierRCurve2 { return v1.dot(v2) / Math.sqrt(v1.lenSq() * v2.lenSq()); } + public static toObject(c: BezierRCurve2): { p0: Point2Like; p1: Point2Like; p2: Point2Like; w: number } { + const p0 = Point2.toObject(c.p0); + const p1 = Point2.toObject(c.p1); + const p2 = Point2.toObject(c.p2); + return { p0, p1, p2, w: c.w }; + } + public clone(): BezierRCurve2 { return new BezierRCurve2(this.p0.clone(), this.p1.clone(), this.p2.clone(), this.w); } diff --git a/packages/redgeometry/src/primitives/box.ts b/packages/redgeometry/src/primitives/box.ts index ebc6d13..8ae942c 100644 --- a/packages/redgeometry/src/primitives/box.ts +++ b/packages/redgeometry/src/primitives/box.ts @@ -27,14 +27,14 @@ export class Box2 { ); } - public static from(obj: { x0: number; y0: number; x1: number; y1: number }): Box2 { - return new Box2(obj.x0, obj.y0, obj.x1, obj.y1); - } - public static fromArray(data: number[], offset = 0): Box2 { return new Box2(data[offset], data[offset + 1], data[offset + 2], data[offset + 3]); } + public static fromObject(obj: { x0: number; y0: number; x1: number; y1: number }): Box2 { + return new Box2(obj.x0, obj.y0, obj.x1, obj.y1); + } + public static fromPoints(p0: Point2, p1: Point2): Box2 { const x0 = Math.min(p0.x, p1.x); const y0 = Math.min(p0.y, p1.y); @@ -53,6 +53,10 @@ export class Box2 { return new Box2(x0, y0, x1, y1); } + public static toObject(box: Box2): { x0: number; y0: number; x1: number; y1: number } { + return { x0: box.x0, y0: box.y0, x1: box.x1, y1: box.y1 }; + } + public clone(): Box2 { return new Box2(this.x0, this.y0, this.x1, this.y1); } @@ -195,10 +199,6 @@ export class Box3 { ); } - public static from(obj: { x0: number; y0: number; z0: number; x1: number; y1: number; z1: number }): Box3 { - return new Box3(obj.x0, obj.y0, obj.z0, obj.x1, obj.y1, obj.z1); - } - public static fromArray(data: number[], offset = 0): Box3 { return new Box3( data[offset], @@ -210,6 +210,10 @@ export class Box3 { ); } + public static fromObject(obj: { x0: number; y0: number; z0: number; x1: number; y1: number; z1: number }): Box3 { + return new Box3(obj.x0, obj.y0, obj.z0, obj.x1, obj.y1, obj.z1); + } + public static fromPoints(p0: Point3, p1: Point3): Box3 { const x0 = Math.min(p0.x, p1.x); const y0 = Math.min(p0.y, p1.y); @@ -232,6 +236,10 @@ export class Box3 { return new Box3(x0, y0, z0, x1, y1, z1); } + public static toObject(box: Box3): { x0: number; y0: number; z0: number; x1: number; y1: number; z1: number } { + return { x0: box.x0, y0: box.y0, z0: box.z0, x1: box.x1, y1: box.y1, z1: box.z1 }; + } + public clone(): Box3 { return new Box3(this.x0, this.y0, this.z0, this.x1, this.y1, this.z1); } diff --git a/packages/redgeometry/src/primitives/color.ts b/packages/redgeometry/src/primitives/color.ts index 70b0aa5..2c529d5 100644 --- a/packages/redgeometry/src/primitives/color.ts +++ b/packages/redgeometry/src/primitives/color.ts @@ -13,10 +13,6 @@ export class ColorRgba { this.a = a; } - public static from(obj: { r: number; g: number; b: number; a: number }): ColorRgba { - return new ColorRgba(obj.r, obj.g, obj.b, obj.a); - } - public static fromArray(data: number[], offset = 0): ColorRgba { return new ColorRgba(data[offset], data[offset + 1], data[offset + 2], data[offset + 3]); } @@ -55,6 +51,14 @@ export class ColorRgba { return new ColorRgba(r / 255, g / 255, b / 255, a / 255); } + public static fromObject(obj: { r: number; g: number; b: number; a: number }): ColorRgba { + return new ColorRgba(obj.r, obj.g, obj.b, obj.a); + } + + public static toObject(c: ColorRgba): { r: number; g: number; b: number; a: number } { + return { r: c.r, g: c.g, b: c.b, a: c.a }; + } + public clone(): ColorRgba { return new ColorRgba(this.r, this.g, this.b, this.a); } diff --git a/packages/redgeometry/src/primitives/complex.ts b/packages/redgeometry/src/primitives/complex.ts index 636decc..0f54586 100644 --- a/packages/redgeometry/src/primitives/complex.ts +++ b/packages/redgeometry/src/primitives/complex.ts @@ -1,10 +1,15 @@ import { Point2 } from "./point.js"; import { Vector2 } from "./vector.js"; +export interface ComplexLike { + a: number; + b: number; +} + /** * A complex number to be used for 2D rotations. */ -export class Complex { +export class Complex implements ComplexLike { public a: number; public b: number; @@ -17,20 +22,24 @@ export class Complex { return new Complex(1, 0); } - public static from(obj: { a: number; b: number }): Complex { - return new Complex(obj.a, obj.b); - } - public static fromArray(data: number[], offset = 0): Complex { return new Complex(data[offset], data[offset + 1]); } + public static fromObject(obj: ComplexLike): Complex { + return new Complex(obj.a, obj.b); + } + public static fromRotationAngle(angle: number): Complex { const sin = Math.sin(angle); const cos = Math.cos(angle); return new Complex(cos, sin); } + public static toObject(z: Complex): ComplexLike { + return { a: z.a, b: z.b }; + } + public add(z: Complex): Complex { return new Complex(this.a + z.a, this.b + z.b); } diff --git a/packages/redgeometry/src/primitives/edge.ts b/packages/redgeometry/src/primitives/edge.ts index 3c82b30..75da023 100644 --- a/packages/redgeometry/src/primitives/edge.ts +++ b/packages/redgeometry/src/primitives/edge.ts @@ -2,7 +2,7 @@ import { clamp } from "../utility/scalar.js"; import { RootType, solveQuadratic } from "../utility/solve.js"; import { Bezier1Curve2 } from "./bezier.js"; import { Box2, Box3 } from "./box.js"; -import { Point2, Point3 } from "./point.js"; +import { Point2, Point3, type Point2Like, type Point3Like } from "./point.js"; import type { Vector2, Vector3 } from "./vector.js"; export class Edge2 { @@ -41,10 +41,6 @@ export class Edge2 { } } - public static from(obj: { p0: Point2; p1: Point2 }): Edge2 { - return new Edge2(obj.p0, obj.p1); - } - public static fromArray(data: number[], offset = 0): Edge2 { const p0 = Point2.fromArray(data, offset); const p1 = Point2.fromArray(data, offset + 2); @@ -52,6 +48,12 @@ export class Edge2 { return new Edge2(p0, p1); } + public static fromObject(obj: { p0: Point2Like; p1: Point2Like }): Edge2 { + const p0 = Point2.fromObject(obj.p0); + const p1 = Point2.fromObject(obj.p1); + return new Edge2(p0, p1); + } + public static fromXY(x0: number, y0: number, x1: number, y1: number): Edge2 { const p0 = new Point2(x0, y0); const p1 = new Point2(x1, y1); @@ -270,6 +272,12 @@ export class Edge2 { return e1.p0.eq(e2.p1) && e1.p1.eq(e2.p0); } + public static toObject(e: Edge2): { p0: Point2Like; p1: Point2Like } { + const p0 = Point2.toObject(e.p0); + const p1 = Point2.toObject(e.p1); + return { p0, p1 }; + } + public clone(): Edge2 { return new Edge2(this.p0.clone(), this.p1.clone()); } @@ -379,10 +387,6 @@ export class Edge3 { this.p1 = p1; } - public static from(obj: { p0: Point3; p1: Point3 }): Edge3 { - return new Edge3(obj.p0, obj.p1); - } - public static fromArray(data: number[], offset = 0): Edge3 { const p0 = Point3.fromArray(data, offset); const p1 = Point3.fromArray(data, offset + 3); @@ -390,6 +394,12 @@ export class Edge3 { return new Edge3(p0, p1); } + public static fromObject(obj: { p0: Point3Like; p1: Point3Like }): Edge3 { + const p0 = Point3.fromObject(obj.p0); + const p1 = Point3.fromObject(obj.p1); + return new Edge3(p0, p1); + } + public static fromXYZ(x0: number, y0: number, z0: number, x1: number, y1: number, z1: number): Edge3 { const p0 = new Point3(x0, y0, z0); const p1 = new Point3(x1, y1, z1); @@ -409,6 +419,12 @@ export class Edge3 { return e1.p0.eq(e2.p1) && e1.p1.eq(e2.p0); } + public static toObject(e: Edge3): { p0: Point3Like; p1: Point3Like } { + const p0 = Point3.toObject(e.p0); + const p1 = Point3.toObject(e.p1); + return { p0, p1 }; + } + public clone(): Edge3 { return new Edge3(this.p0.clone(), this.p1.clone()); } diff --git a/packages/redgeometry/src/primitives/point.ts b/packages/redgeometry/src/primitives/point.ts index 5fbbd7d..36ae82b 100644 --- a/packages/redgeometry/src/primitives/point.ts +++ b/packages/redgeometry/src/primitives/point.ts @@ -1,7 +1,18 @@ import { lerp, roundToPrecision } from "../utility/scalar.js"; import { Vector2, Vector3 } from "./vector.js"; -export class Point2 { +export interface Point2Like { + x: number; + y: number; +} + +export interface Point3Like { + x: number; + y: number; + z: number; +} + +export class Point2 implements Point2Like { public x: number; public y: number; @@ -17,14 +28,14 @@ export class Point2 { return new Point2(0, 0); } - public static from(obj: { x: number; y: number }): Point2 { - return new Point2(obj.x, obj.y); - } - public static fromArray(data: number[], offset = 0): Point2 { return new Point2(data[offset], data[offset + 1]); } + public static fromObject(obj: Point2Like): Point2 { + return new Point2(obj.x, obj.y); + } + public static fromXYW(x: number, y: number, w: number): Point2 { return new Point2(x / w, y / w); } @@ -67,6 +78,10 @@ export class Point2 { return v1.cross(v2); } + public static toObject(p: Point2): Point2Like { + return { x: p.x, y: p.y }; + } + /** * Returns the sum of the current point and a vector `v`. */ @@ -143,7 +158,7 @@ export class Point2 { } } -export class Point3 { +export class Point3 implements Point3Like { public x: number; public y: number; public z: number; @@ -161,14 +176,14 @@ export class Point3 { return new Point3(0, 0, 0); } - public static from(obj: { x: number; y: number; z: number }): Point3 { - return new Point3(obj.x, obj.y, obj.z); - } - public static fromArray(data: number[], offset = 0): Point3 { return new Point3(data[offset], data[offset + 1], data[offset + 2]); } + public static fromObject(obj: Point3Like): Point3 { + return new Point3(obj.x, obj.y, obj.z); + } + public static fromXY(x: number, y: number): Point3 { return new Point3(x, y, 1); } @@ -201,6 +216,10 @@ export class Point3 { return new Point3(x, y, z); } + public static toObject(p: Point3): Point3Like { + return { x: p.x, y: p.y, z: p.z }; + } + /** * Returns the sum of the current point and a vector `v`. */ diff --git a/packages/redgeometry/src/primitives/quaternion.ts b/packages/redgeometry/src/primitives/quaternion.ts index 3cb6070..3b9f7f9 100644 --- a/packages/redgeometry/src/primitives/quaternion.ts +++ b/packages/redgeometry/src/primitives/quaternion.ts @@ -11,6 +11,13 @@ export enum RotationOrder { ZYX, } +export interface QuaternionLike { + a: number; + b: number; + c: number; + d: number; +} + /** * A quaternion to be used for 3D rotations. * @@ -18,7 +25,7 @@ export enum RotationOrder { * - https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation * - https://danceswithcode.net/engineeringnotes/quaternions/quaternions.html */ -export class Quaternion { +export class Quaternion implements QuaternionLike { public a: number; public b: number; public c: number; @@ -35,14 +42,14 @@ export class Quaternion { return new Quaternion(1, 0, 0, 0); } - public static from(obj: { a: number; b: number; c: number; d: number }): Quaternion { - return new Quaternion(obj.a, obj.b, obj.c, obj.d); - } - public static fromArray(data: number[], offset = 0): Quaternion { return new Quaternion(data[offset], data[offset + 1], data[offset + 2], data[offset + 3]); } + public static fromObject(obj: QuaternionLike): Quaternion { + return new Quaternion(obj.a, obj.b, obj.c, obj.d); + } + public static fromRotationAngleX(angle: number): Quaternion { const sin = Math.sin(0.5 * angle); const cos = Math.cos(0.5 * angle); @@ -173,6 +180,10 @@ export class Quaternion { return new Quaternion(w, x, y, z); } + public static toObject(q: Quaternion): QuaternionLike { + return { a: q.a, b: q.b, c: q.c, d: q.d }; + } + public add(q: Quaternion): Quaternion { return new Quaternion(this.a + q.a, this.b + q.b, this.c + q.c, this.d + q.d); } diff --git a/packages/redgeometry/src/primitives/ray.ts b/packages/redgeometry/src/primitives/ray.ts index 41930de..bf7c74b 100644 --- a/packages/redgeometry/src/primitives/ray.ts +++ b/packages/redgeometry/src/primitives/ray.ts @@ -1,5 +1,5 @@ -import { Point2, Point3 } from "./point.js"; -import { Vector2, Vector3 } from "./vector.js"; +import { Point2, Point3, type Point2Like, type Point3Like } from "./point.js"; +import { Vector2, Vector3, type Vector2Like, type Vector3Like } from "./vector.js"; export class Ray2 { public p: Point2; @@ -10,10 +10,6 @@ export class Ray2 { this.v = v; } - public static from(obj: { p: Point2; v: Vector2 }): Ray2 { - return new Ray2(obj.p, obj.v); - } - public static fromArray(data: number[], offset = 0): Ray2 { const p = Point2.fromArray(data, offset); const v = Vector2.fromArray(data, offset + 2); @@ -21,6 +17,12 @@ export class Ray2 { return new Ray2(p, v); } + public static fromObject(obj: { p: Point2Like; v: Vector2Like }): Ray2 { + const p = Point2.fromObject(obj.p); + const v = Vector2.fromObject(obj.v); + return new Ray2(p, v); + } + public static fromPoints(p0: Point2, p1: Point2): Ray2 { const v = p1.sub(p0); return new Ray2(p0, v); @@ -32,6 +34,12 @@ export class Ray2 { return new Ray2(p, v); } + public static toObject(ray: Ray2): { p: Point2Like; v: Vector2Like } { + const p = Point2.toObject(ray.p); + const v = Vector2.toObject(ray.v); + return { p, v }; + } + public clone(): Ray2 { return new Ray2(this.p.clone(), this.v.clone()); } @@ -91,10 +99,6 @@ export class Ray3 { this.v = v; } - public static from(obj: { p: Point3; v: Vector3 }): Ray3 { - return new Ray3(obj.p, obj.v); - } - public static fromArray(data: number[], offset = 0): Ray3 { const p = Point3.fromArray(data, offset); const v = Vector3.fromArray(data, offset + 3); @@ -102,6 +106,12 @@ export class Ray3 { return new Ray3(p, v); } + public static fromObject(obj: { p: Point3Like; v: Vector3Like }): Ray3 { + const p = Point3.fromObject(obj.p); + const v = Vector3.fromObject(obj.v); + return new Ray3(p, v); + } + public static fromPoints(p0: Point3, p1: Point3): Ray3 { const v = p1.sub(p0); return new Ray3(p0, v); @@ -113,6 +123,12 @@ export class Ray3 { return new Ray3(p, v); } + public static toObject(ray: Ray3): { p: Point3Like; v: Vector3Like } { + const p = Point3.toObject(ray.p); + const v = Vector3.toObject(ray.v); + return { p, v }; + } + public clone(): Ray3 { return new Ray3(this.p.clone(), this.v.clone()); } diff --git a/packages/redgeometry/src/primitives/vector.ts b/packages/redgeometry/src/primitives/vector.ts index e2f6e83..97539de 100644 --- a/packages/redgeometry/src/primitives/vector.ts +++ b/packages/redgeometry/src/primitives/vector.ts @@ -1,7 +1,25 @@ import { clamp, lerp } from "../utility/scalar.js"; import { Point2, Point3 } from "./point.js"; -export class Vector2 { +export interface Vector2Like { + x: number; + y: number; +} + +export interface Vector3Like { + x: number; + y: number; + z: number; +} + +export interface Vector4Like { + w: number; + x: number; + y: number; + z: number; +} + +export class Vector2 implements Vector2Like { public x: number; public y: number; @@ -38,14 +56,14 @@ export class Vector2 { return new Vector2(0, 0); } - public static from(obj: { x: number; y: number }): Vector2 { - return new Vector2(obj.x, obj.y); - } - public static fromArray(data: number[], offset = 0): Vector2 { return new Vector2(data[offset], data[offset + 1]); } + public static fromObject(obj: Vector2Like): Vector2 { + return new Vector2(obj.x, obj.y); + } + public static fromXYW(x: number, y: number, w: number): Vector2 { return new Vector2(x / w, y / w); } @@ -63,6 +81,10 @@ export class Vector2 { } } + public static toObject(v: Vector2): Vector2Like { + return { x: v.x, y: v.y }; + } + /** * Returns the sum of the current vector and a vector `v`. */ @@ -216,7 +238,7 @@ export class Vector2 { } } -export class Vector3 { +export class Vector3 implements Vector3Like { public x: number; public y: number; public z: number; @@ -262,14 +284,14 @@ export class Vector3 { return new Vector3(0, 0, 0); } - public static from(obj: { x: number; y: number; z: number }): Vector3 { - return new Vector3(obj.x, obj.y, obj.z); - } - public static fromArray(data: number[], offset = 0): Vector3 { return new Vector3(data[offset], data[offset + 1], data[offset + 2]); } + public static fromObject(obj: Vector3Like): Vector3 { + return new Vector3(obj.x, obj.y, obj.z); + } + public static fromXY(x: number, y: number): Vector3 { return new Vector3(x, y, 1); } @@ -278,6 +300,10 @@ export class Vector3 { return new Vector3(x / w, y / w, z / w); } + public static toObject(v: Vector3): Vector3Like { + return { x: v.x, y: v.y, z: v.z }; + } + /** * Returns the sum of the current vector and a vector `v`. */ @@ -434,7 +460,7 @@ export class Vector3 { } } -export class Vector4 { +export class Vector4 implements Vector4Like { public w: number; public x: number; public y: number; @@ -489,18 +515,22 @@ export class Vector4 { return new Vector4(0, 0, 0, 0); } - public static from(obj: { x: number; y: number; z: number; w: number }): Vector4 { - return new Vector4(obj.x, obj.y, obj.z, obj.w); - } - public static fromArray(data: number[], offset = 0): Vector4 { return new Vector4(data[offset], data[offset + 1], data[offset + 2], data[offset + 3]); } + public static fromObject(obj: Vector4Like): Vector4 { + return new Vector4(obj.x, obj.y, obj.z, obj.w); + } + public static fromXYZ(x: number, y: number, z: number): Vector4 { return new Vector4(x, y, z, 1); } + public static toObject(v: Vector4): Vector4Like { + return { x: v.x, y: v.y, z: v.z, w: v.w }; + } + /** * Returns the sum of the current vector and a vector `v`. */