curvy 2.0.0-alpha.13 → 2.0.0-alpha.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/characteristic/index.mjs +1 -1
- package/dist/curve/cubic2d.d.ts +102 -3
- package/dist/curve/curve2d.d.ts +81 -0
- package/dist/curve/index.mjs +1 -1
- package/dist/curve/linear2d.d.ts +122 -3
- package/dist/curve/quadratic2d.d.ts +103 -3
- package/dist/curve/rationalCubic2d.d.ts +100 -38
- package/dist/interval/index.mjs +2 -2
- package/dist/matrix/index.mjs +47 -1
- package/dist/matrix/index.mjs.map +1 -1
- package/dist/matrix/matrix3x3.d.ts +87 -1
- package/dist/matrix/matrix4x4.d.ts +57 -6
- package/dist/matrix/traits.d.ts +34 -0
- package/dist/monotonicity/index.mjs +1 -1
- package/dist/monotonicity/monotonicity.d.ts +25 -0
- package/dist/number.d.ts +53 -0
- package/dist/number.mjs +56 -1
- package/dist/number.mjs.map +1 -1
- package/dist/path/cubic2d.d.ts +22 -0
- package/dist/path/index.mjs +25 -149
- package/dist/path/index.mjs.map +1 -1
- package/dist/path/linear2d.d.ts +24 -0
- package/dist/path/path2d.d.ts +54 -0
- package/dist/path/quadratic2d.d.ts +22 -0
- package/dist/path/rationalCubic2d.d.ts +21 -0
- package/dist/polynomial/index.mjs +2 -2
- package/dist/shared/affine2d-Dvna84gc.mjs +332 -0
- package/dist/shared/affine2d-Dvna84gc.mjs.map +1 -0
- package/dist/shared/{characteristic-BkEr-rr8.mjs → characteristic--7nC4Q_a.mjs} +4 -5
- package/dist/shared/characteristic--7nC4Q_a.mjs.map +1 -0
- package/dist/shared/{cubic-BL6dpuHh.mjs → cubic-BiGuAnZ0.mjs} +56 -27
- package/dist/shared/cubic-BiGuAnZ0.mjs.map +1 -0
- package/dist/shared/{interval-Dm35Xhy4.mjs → interval-Dcqpo73t.mjs} +5 -5
- package/dist/shared/interval-Dcqpo73t.mjs.map +1 -0
- package/dist/shared/{interval2d-AtneyI45.mjs → interval2d-C2Pk66-2.mjs} +3 -3
- package/dist/shared/{interval2d-AtneyI45.mjs.map → interval2d-C2Pk66-2.mjs.map} +1 -1
- package/dist/shared/matrix3x3.internal-Cod-r7H3.mjs +233 -0
- package/dist/shared/matrix3x3.internal-Cod-r7H3.mjs.map +1 -0
- package/dist/shared/{matrix4x4-BWmf4lZM.mjs → matrix4x4-BrqgYZCD.mjs} +72 -223
- package/dist/shared/matrix4x4-BrqgYZCD.mjs.map +1 -0
- package/dist/shared/monotonicity-DNxBoC7F.mjs +64 -0
- package/dist/shared/monotonicity-DNxBoC7F.mjs.map +1 -0
- package/dist/shared/{quadratic-DPrUsFCp.mjs → quadratic-BmMqkvxx.mjs} +2 -2
- package/dist/shared/{quadratic-DPrUsFCp.mjs.map → quadratic-BmMqkvxx.mjs.map} +1 -1
- package/dist/shared/{rationalCubic2d-CeHgpNht.mjs → rationalCubic2d-CZSwwKtS.mjs} +591 -125
- package/dist/shared/rationalCubic2d-CZSwwKtS.mjs.map +1 -0
- package/dist/shared/{rationalCubic2d-H1J2Fjyy.mjs → rationalCubic2d-bveuGqBZ.mjs} +282 -326
- package/dist/shared/rationalCubic2d-bveuGqBZ.mjs.map +1 -0
- package/dist/shared/{solution-B2JdOZpe.mjs → solution-BW0BBMXI.mjs} +22 -6
- package/dist/shared/solution-BW0BBMXI.mjs.map +1 -0
- package/dist/shared/{vector2-CSkaMXvp.mjs → vector2-DuA3EmfL.mjs} +5 -3
- package/dist/shared/vector2-DuA3EmfL.mjs.map +1 -0
- package/dist/shared/{vector2.internal-DP1nTBdS.mjs → vector2.internal-rPnW0RCx.mjs} +10 -5
- package/dist/shared/vector2.internal-rPnW0RCx.mjs.map +1 -0
- package/dist/shared/{vector3-CR2LPV03.mjs → vector3-oxtggkDp.mjs} +2 -2
- package/dist/shared/{vector3-CR2LPV03.mjs.map → vector3-oxtggkDp.mjs.map} +1 -1
- package/dist/shared/vector3.internal-CfWHl9SG.mjs +135 -0
- package/dist/shared/vector3.internal-CfWHl9SG.mjs.map +1 -0
- package/dist/shared/{vector4-PO_7EYd-.mjs → vector4-DGHuCvTV.mjs} +2 -2
- package/dist/shared/{vector4-PO_7EYd-.mjs.map → vector4-DGHuCvTV.mjs.map} +1 -1
- package/dist/shared/vector4.internal-DH5DzNYO.mjs +116 -0
- package/dist/shared/vector4.internal-DH5DzNYO.mjs.map +1 -0
- package/dist/solution/index.mjs +1 -1
- package/dist/solution/solution.d.ts +16 -0
- package/dist/splines/basis2d.d.ts +64 -0
- package/dist/splines/bezier2d.d.ts +72 -0
- package/dist/splines/cardinal2d.d.ts +78 -0
- package/dist/splines/hermite2d.d.ts +76 -0
- package/dist/splines/index.mjs +109 -15
- package/dist/splines/index.mjs.map +1 -1
- package/dist/splines/linear2d.d.ts +65 -0
- package/dist/splines/rationalBezier2d.d.ts +76 -0
- package/dist/transform/affine2d.d.ts +339 -0
- package/dist/transform/affine2d.internal.d.ts +2 -0
- package/dist/transform/index.d.ts +3 -0
- package/dist/transform/index.mjs +2 -0
- package/dist/transform/traits.d.ts +19 -0
- package/dist/vector/index.mjs +3 -3
- package/dist/vector/vector2.d.ts +49 -0
- package/package.json +5 -1
- package/dist/shared/characteristic-BkEr-rr8.mjs.map +0 -1
- package/dist/shared/cubic-BL6dpuHh.mjs.map +0 -1
- package/dist/shared/interval-Dm35Xhy4.mjs.map +0 -1
- package/dist/shared/matrix4x4-BWmf4lZM.mjs.map +0 -1
- package/dist/shared/monotonicity-BdebFOtv.mjs +0 -34
- package/dist/shared/monotonicity-BdebFOtv.mjs.map +0 -1
- package/dist/shared/rationalCubic2d-CeHgpNht.mjs.map +0 -1
- package/dist/shared/rationalCubic2d-H1J2Fjyy.mjs.map +0 -1
- package/dist/shared/solution-B2JdOZpe.mjs.map +0 -1
- package/dist/shared/vector2-CSkaMXvp.mjs.map +0 -1
- package/dist/shared/vector2.internal-DP1nTBdS.mjs.map +0 -1
- package/dist/shared/vector4.internal-BJ1QN2Ck.mjs +0 -246
- package/dist/shared/vector4.internal-BJ1QN2Ck.mjs.map +0 -1
package/dist/path/linear2d.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { Interval2d } from '../interval/interval2d.ts';
|
|
|
2
2
|
import type { LinearCurve2d } from '../curve/linear2d.ts';
|
|
3
3
|
import type { Closed } from '../interval/interval.ts';
|
|
4
4
|
import type * as Solution from '../solution/solution.ts';
|
|
5
|
+
import type { Affine2d } from '../transform/affine2d.ts';
|
|
5
6
|
import type { Pipeable } from '../utils.ts';
|
|
6
7
|
import type { Vector2 } from '../vector/vector2.ts';
|
|
7
8
|
import type { LinearPath2dTypeId } from './linear2d.internal.ts';
|
|
@@ -243,3 +244,26 @@ export declare const solveAtY: {
|
|
|
243
244
|
* @since 2.0.0
|
|
244
245
|
*/
|
|
245
246
|
export declare const boundingBox: (p: LinearPath2d) => Interval2d<Closed, Closed>;
|
|
247
|
+
export declare const transform: {
|
|
248
|
+
/**
|
|
249
|
+
* Applies an `Affine2d` transform to every curve in a `LinearPath2d`,
|
|
250
|
+
* returning a new path whose image is the affine image of the original.
|
|
251
|
+
* Trait brands are dropped — affine maps can flip the sense of monotonicity
|
|
252
|
+
* (a reflection turns `IncreasingX` into `DecreasingX`), so any brands the
|
|
253
|
+
* caller still wants must be reasserted on the result.
|
|
254
|
+
*
|
|
255
|
+
* @param p - The linear path.
|
|
256
|
+
* @param a - The affine transform.
|
|
257
|
+
* @returns A new unbranded `LinearPath2d` whose curves are the affine images of the input's.
|
|
258
|
+
* @since 2.0.0
|
|
259
|
+
*/
|
|
260
|
+
(p: LinearPath2d, a: Affine2d): LinearPath2d;
|
|
261
|
+
/**
|
|
262
|
+
* Applies an `Affine2d` transform to every curve in a `LinearPath2d`.
|
|
263
|
+
*
|
|
264
|
+
* @param a - The affine transform.
|
|
265
|
+
* @returns A function that takes a `LinearPath2d` and returns the transformed path.
|
|
266
|
+
* @since 2.0.0
|
|
267
|
+
*/
|
|
268
|
+
(a: Affine2d): (p: LinearPath2d) => LinearPath2d;
|
|
269
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { Curve2dOps } from '../curve/curve2d.ts';
|
|
2
|
+
import * as Interval from '../interval/interval.ts';
|
|
3
|
+
import * as Interval2d from '../interval/interval2d.ts';
|
|
4
|
+
import * as Solution from '../solution/solution.ts';
|
|
5
|
+
import type { Affine2d } from '../transform/affine2d.ts';
|
|
6
|
+
import { Pipeable } from '../utils.ts';
|
|
7
|
+
import type { Vector2 } from '../vector/vector2.ts';
|
|
8
|
+
import { PathTraits, type Continuous, type DecreasingX, type DecreasingY, type IncreasingX, type IncreasingY, type MonotonicX, type MonotonicY } from './traits.ts';
|
|
9
|
+
/**
|
|
10
|
+
* Generic 2D path — a sequence of curves of a single kind `C` plus optional
|
|
11
|
+
* trait brands (`Continuous`, `MonotonicX`, etc.) tracking properties of the
|
|
12
|
+
* path as a whole.
|
|
13
|
+
*
|
|
14
|
+
* Each concrete path kind (`LinearPath2d`, `QuadraticPath2d`, `CubicPath2d`)
|
|
15
|
+
* is a `Path2d<TheirCurveKind, Trait>` plus a per-kind `TypeId` slot for
|
|
16
|
+
* cheap runtime identification. The per-kind modules re-export an operation
|
|
17
|
+
* surface derived from {@link makeMethods} over their curve's
|
|
18
|
+
* {@link Curve2dOps}.
|
|
19
|
+
*
|
|
20
|
+
* @since 2.0.0
|
|
21
|
+
*/
|
|
22
|
+
export interface Path2d<C, Trait = unknown> extends Pipeable, Iterable<C> {
|
|
23
|
+
readonly [PathTraits]: Trait;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Builds the bundle of generic path operations for a curve kind `C`, given
|
|
27
|
+
* that curve's {@link Curve2dOps} and the per-kind `TypeId` symbol. Each
|
|
28
|
+
* polynomial-degree path module calls this once and re-exports the returned
|
|
29
|
+
* functions with curve-narrowed signatures.
|
|
30
|
+
*
|
|
31
|
+
* `ops` and `typeId` are captured by closure, so the returned operations
|
|
32
|
+
* incur no per-call lookup overhead.
|
|
33
|
+
*
|
|
34
|
+
* @since 2.0.0
|
|
35
|
+
*/
|
|
36
|
+
export declare const makeMethods: <C>(typeId: symbol, ops: Curve2dOps<C>) => {
|
|
37
|
+
fromArray: (curves: ReadonlyArray<C>) => Path2d<C>;
|
|
38
|
+
make: (...curves: ReadonlyArray<C>) => Path2d<C>;
|
|
39
|
+
append: ((c: C) => (p: Path2d<C>) => Path2d<C>) & ((p: Path2d<C>, c: C) => Path2d<C>);
|
|
40
|
+
length: (p: Path2d<C>) => number;
|
|
41
|
+
solve: ((u: number) => (p: Path2d<C>) => Vector2) & ((p: Path2d<C>, u: number) => Vector2);
|
|
42
|
+
toPathData: (p: Path2d<C>) => string;
|
|
43
|
+
isContinuous: <T>(p: Path2d<C, T>) => p is Path2d<C, T & Continuous>;
|
|
44
|
+
isIncreasingX: <T>(p: Path2d<C, T>) => p is Path2d<C, T & IncreasingX>;
|
|
45
|
+
isDecreasingX: <T>(p: Path2d<C, T>) => p is Path2d<C, T & DecreasingX>;
|
|
46
|
+
isMonotonicX: <T>(p: Path2d<C, T>) => p is Path2d<C, T & MonotonicX>;
|
|
47
|
+
isIncreasingY: <T>(p: Path2d<C, T>) => p is Path2d<C, T & IncreasingY>;
|
|
48
|
+
isDecreasingY: <T>(p: Path2d<C, T>) => p is Path2d<C, T & DecreasingY>;
|
|
49
|
+
isMonotonicY: <T>(p: Path2d<C, T>) => p is Path2d<C, T & MonotonicY>;
|
|
50
|
+
solveAtX: ((...args: Array<any>) => any) & ((p: Path2d<C>, x: number) => Solution.AtMostOne<number>);
|
|
51
|
+
solveAtY: ((...args: Array<any>) => any) & ((p: Path2d<C>, y: number) => Solution.AtMostOne<number>);
|
|
52
|
+
boundingBox: (p: Path2d<C>) => Interval2d.Interval2d<Interval.Closed, Interval.Closed>;
|
|
53
|
+
transform: ((a: Affine2d) => (p: Path2d<C>) => Path2d<C>) & ((p: Path2d<C>, a: Affine2d) => Path2d<C>);
|
|
54
|
+
};
|
|
@@ -2,6 +2,7 @@ import type { Interval2d } from '../interval/interval2d.ts';
|
|
|
2
2
|
import type { QuadraticCurve2d } from '../curve/quadratic2d.ts';
|
|
3
3
|
import type { Closed } from '../interval/interval.ts';
|
|
4
4
|
import type * as Solution from '../solution/solution.ts';
|
|
5
|
+
import type { Affine2d } from '../transform/affine2d.ts';
|
|
5
6
|
import type { Pipeable } from '../utils.ts';
|
|
6
7
|
import type { Vector2 } from '../vector/vector2.ts';
|
|
7
8
|
import type { QuadraticPath2dTypeId } from './quadratic2d.internal.ts';
|
|
@@ -232,3 +233,24 @@ export declare const solveAtY: {
|
|
|
232
233
|
* @since 2.0.0
|
|
233
234
|
*/
|
|
234
235
|
export declare const boundingBox: (p: QuadraticPath2d) => Interval2d<Closed, Closed>;
|
|
236
|
+
export declare const transform: {
|
|
237
|
+
/**
|
|
238
|
+
* Applies an `Affine2d` transform to every curve in a `QuadraticPath2d`,
|
|
239
|
+
* returning a new path whose image is the affine image of the original.
|
|
240
|
+
* Trait brands are dropped.
|
|
241
|
+
*
|
|
242
|
+
* @param p - The quadratic path.
|
|
243
|
+
* @param a - The affine transform.
|
|
244
|
+
* @returns A new unbranded `QuadraticPath2d` whose curves are the affine images of the input's.
|
|
245
|
+
* @since 2.0.0
|
|
246
|
+
*/
|
|
247
|
+
(p: QuadraticPath2d, a: Affine2d): QuadraticPath2d;
|
|
248
|
+
/**
|
|
249
|
+
* Applies an `Affine2d` transform to every curve in a `QuadraticPath2d`.
|
|
250
|
+
*
|
|
251
|
+
* @param a - The affine transform.
|
|
252
|
+
* @returns A function that takes a `QuadraticPath2d` and returns the transformed path.
|
|
253
|
+
* @since 2.0.0
|
|
254
|
+
*/
|
|
255
|
+
(a: Affine2d): (p: QuadraticPath2d) => QuadraticPath2d;
|
|
256
|
+
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { RationalCubicCurve2d } from '../curve/rationalCubic2d.ts';
|
|
2
2
|
import type { Closed } from '../interval/interval.ts';
|
|
3
3
|
import type { Interval2d } from '../interval/interval2d.ts';
|
|
4
|
+
import type { Affine2d } from '../transform/affine2d.ts';
|
|
4
5
|
import type { Pipeable } from '../utils.ts';
|
|
5
6
|
import type { Vector2 } from '../vector/vector2.ts';
|
|
6
7
|
import type { CubicPath2d } from './cubic2d.ts';
|
|
@@ -141,3 +142,23 @@ export declare const approximateAsCubicPath: {
|
|
|
141
142
|
*/
|
|
142
143
|
(tolerance: number): (p: RationalCubicPath2d) => CubicPath2d;
|
|
143
144
|
};
|
|
145
|
+
export declare const transform: {
|
|
146
|
+
/**
|
|
147
|
+
* Applies an `Affine2d` transform to every curve in a `RationalCubicPath2d`,
|
|
148
|
+
* returning a new path whose image is the affine image of the original.
|
|
149
|
+
*
|
|
150
|
+
* @param p - The rational cubic path.
|
|
151
|
+
* @param a - The affine transform.
|
|
152
|
+
* @returns A new `RationalCubicPath2d` whose curves are the affine images of the input's.
|
|
153
|
+
* @since 2.0.0
|
|
154
|
+
*/
|
|
155
|
+
(p: RationalCubicPath2d, a: Affine2d): RationalCubicPath2d;
|
|
156
|
+
/**
|
|
157
|
+
* Applies an `Affine2d` transform to every curve in a `RationalCubicPath2d`.
|
|
158
|
+
*
|
|
159
|
+
* @param a - The affine transform.
|
|
160
|
+
* @returns A function that takes a `RationalCubicPath2d` and returns the transformed path.
|
|
161
|
+
* @since 2.0.0
|
|
162
|
+
*/
|
|
163
|
+
(a: Affine2d): (p: RationalCubicPath2d) => RationalCubicPath2d;
|
|
164
|
+
};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { t as cubic_exports } from "../shared/cubic-
|
|
2
|
-
import { o as quadratic_exports, p as linear_exports } from "../shared/quadratic-
|
|
1
|
+
import { t as cubic_exports } from "../shared/cubic-BiGuAnZ0.mjs";
|
|
2
|
+
import { o as quadratic_exports, p as linear_exports } from "../shared/quadratic-BmMqkvxx.mjs";
|
|
3
3
|
export { cubic_exports as CubicPolynomial, linear_exports as LinearPolynomial, quadratic_exports as QuadraticPolynomial };
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
import { t as __exportAll } from "./chunk-25Hzd3z8.mjs";
|
|
2
|
+
import { Pipeable, dual, invariant } from "../utils.mjs";
|
|
3
|
+
import { EPSILON, RELATIVE_TOLERANCE, coincident } from "../number.mjs";
|
|
4
|
+
import { g as make, h as magnitude } from "./vector2.internal-rPnW0RCx.mjs";
|
|
5
|
+
import { M as make$2, c as inverse$2, f as make$1, i as equals$2, l as inverseUnsafe$2, m as multiply, s as identity$2, u as isInvertible$2 } from "./matrix3x3.internal-Cod-r7H3.mjs";
|
|
6
|
+
import { c as one, i as isNone, s as none } from "./solution-BW0BBMXI.mjs";
|
|
7
|
+
//#region src/transform/affine2d.internal.ts
|
|
8
|
+
const Affine2dTypeId = Symbol.for("curvy/transform/affine2d");
|
|
9
|
+
var Affine2dImpl = class extends Pipeable {
|
|
10
|
+
[Affine2dTypeId] = Affine2dTypeId;
|
|
11
|
+
matrix;
|
|
12
|
+
constructor(matrix) {
|
|
13
|
+
super();
|
|
14
|
+
this.matrix = matrix;
|
|
15
|
+
}
|
|
16
|
+
get [Symbol.toStringTag]() {
|
|
17
|
+
const m = this.matrix;
|
|
18
|
+
return `Affine2d([${m.m00}, ${m.m01}, ${m.m02}], [${m.m10}, ${m.m11}, ${m.m12}])`;
|
|
19
|
+
}
|
|
20
|
+
get [Symbol.for("nodejs.util.inspect.custom")]() {
|
|
21
|
+
return this[Symbol.toStringTag];
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
/** @internal */
|
|
25
|
+
const isAffine2d$1 = (a) => typeof a === "object" && a !== null && Affine2dTypeId in a;
|
|
26
|
+
/** @internal */
|
|
27
|
+
const fromMatrix$1 = (matrix) => {
|
|
28
|
+
const zeroTolerance = EPSILON + RELATIVE_TOLERANCE * Math.max(Math.abs(matrix.m00), Math.abs(matrix.m01), Math.abs(matrix.m02), Math.abs(matrix.m10), Math.abs(matrix.m11), Math.abs(matrix.m12));
|
|
29
|
+
invariant(coincident(matrix.m20, 0, zeroTolerance) && coincident(matrix.m21, 0, zeroTolerance) && coincident(matrix.m22, 1), "Affine2d requires the third row of its matrix to be [0, 0, 1]");
|
|
30
|
+
return new Affine2dImpl(matrix);
|
|
31
|
+
};
|
|
32
|
+
/** @internal */
|
|
33
|
+
const identity$1 = new Affine2dImpl(identity$2);
|
|
34
|
+
/** @internal */
|
|
35
|
+
const translate$1 = (tx, ty) => new Affine2dImpl(make$1(1, 0, tx, 0, 1, ty, 0, 0, 1));
|
|
36
|
+
/** @internal */
|
|
37
|
+
const translateBy$1 = (v) => translate$1(v.x, v.y);
|
|
38
|
+
/** @internal */
|
|
39
|
+
const scale$1 = (sx, sy) => {
|
|
40
|
+
return new Affine2dImpl(make$1(sx, 0, 0, 0, sy ?? sx, 0, 0, 0, 1));
|
|
41
|
+
};
|
|
42
|
+
/** @internal */
|
|
43
|
+
const scaleAround$1 = (sx, sy, origin) => {
|
|
44
|
+
return new Affine2dImpl(make$1(sx, 0, origin.x * (1 - sx), 0, sy, origin.y * (1 - sy), 0, 0, 1));
|
|
45
|
+
};
|
|
46
|
+
/** @internal */
|
|
47
|
+
const rotate$1 = (theta) => {
|
|
48
|
+
const c = Math.cos(theta);
|
|
49
|
+
const s = Math.sin(theta);
|
|
50
|
+
return new Affine2dImpl(make$1(c, -s, 0, s, c, 0, 0, 0, 1));
|
|
51
|
+
};
|
|
52
|
+
/** @internal */
|
|
53
|
+
const rotateAround$1 = (theta, origin) => {
|
|
54
|
+
const c = Math.cos(theta);
|
|
55
|
+
const s = Math.sin(theta);
|
|
56
|
+
return new Affine2dImpl(make$1(c, -s, origin.x - origin.x * c + origin.y * s, s, c, origin.y - origin.x * s - origin.y * c, 0, 0, 1));
|
|
57
|
+
};
|
|
58
|
+
/** @internal */
|
|
59
|
+
const reflectX$1 = new Affine2dImpl(make$1(1, 0, 0, 0, -1, 0, 0, 0, 1));
|
|
60
|
+
/** @internal */
|
|
61
|
+
const reflectY$1 = new Affine2dImpl(make$1(-1, 0, 0, 0, 1, 0, 0, 0, 1));
|
|
62
|
+
/** @internal */
|
|
63
|
+
const reflectAcrossLine$1 = (origin, direction) => {
|
|
64
|
+
const mag = magnitude(direction);
|
|
65
|
+
invariant(mag > 0, "reflectAcrossLine requires a non-zero direction vector");
|
|
66
|
+
const dx = direction.x / mag;
|
|
67
|
+
const dy = direction.y / mag;
|
|
68
|
+
const a = dx * dx - dy * dy;
|
|
69
|
+
const b = 2 * dx * dy;
|
|
70
|
+
const negA = -a;
|
|
71
|
+
return new Affine2dImpl(make$1(a, b, origin.x - a * origin.x - b * origin.y, b, negA, origin.y - b * origin.x - negA * origin.y, 0, 0, 1));
|
|
72
|
+
};
|
|
73
|
+
/** @internal */
|
|
74
|
+
const shear$1 = (kx, ky) => new Affine2dImpl(make$1(1, kx, 0, ky, 1, 0, 0, 0, 1));
|
|
75
|
+
/** @internal */
|
|
76
|
+
const andThen$1 = dual(2, (a, b) => new Affine2dImpl(multiply(b.matrix, a.matrix)));
|
|
77
|
+
/** @internal */
|
|
78
|
+
const isInvertible$1 = (a) => isInvertible$2(a.matrix);
|
|
79
|
+
/** @internal */
|
|
80
|
+
const asInvertible$1 = (a) => {
|
|
81
|
+
invariant(isInvertible$1(a), "affine2d is not invertible");
|
|
82
|
+
return a;
|
|
83
|
+
};
|
|
84
|
+
/** @internal */
|
|
85
|
+
const inverse$1 = (a) => {
|
|
86
|
+
const inv = inverse$2(a.matrix);
|
|
87
|
+
if (isNone(inv)) return none;
|
|
88
|
+
return one(new Affine2dImpl(inv.value));
|
|
89
|
+
};
|
|
90
|
+
/** @internal */
|
|
91
|
+
const inverseUnsafe$1 = (a) => new Affine2dImpl(inverseUnsafe$2(a.matrix));
|
|
92
|
+
/** @internal */
|
|
93
|
+
const apply$1 = dual(2, (a, p) => {
|
|
94
|
+
const m = a.matrix;
|
|
95
|
+
return make(m.m00 * p.x + m.m01 * p.y + m.m02, m.m10 * p.x + m.m11 * p.y + m.m12);
|
|
96
|
+
});
|
|
97
|
+
/** @internal */
|
|
98
|
+
const applyTo$1 = (a) => (p) => apply$1(a, p);
|
|
99
|
+
/** @internal */
|
|
100
|
+
const linear$1 = (a) => {
|
|
101
|
+
const m = a.matrix;
|
|
102
|
+
return make$2(m.m00, m.m01, m.m10, m.m11);
|
|
103
|
+
};
|
|
104
|
+
/** @internal */
|
|
105
|
+
const translation$1 = (a) => make(a.matrix.m02, a.matrix.m12);
|
|
106
|
+
/** @internal */
|
|
107
|
+
const linearPart$1 = (a) => {
|
|
108
|
+
const m = a.matrix;
|
|
109
|
+
return new Affine2dImpl(make$1(m.m00, m.m01, 0, m.m10, m.m11, 0, 0, 0, 1));
|
|
110
|
+
};
|
|
111
|
+
/** @internal */
|
|
112
|
+
const equals$1 = dual(2, (a, b) => equals$2(a.matrix, b.matrix));
|
|
113
|
+
//#endregion
|
|
114
|
+
//#region src/transform/affine2d.ts
|
|
115
|
+
var affine2d_exports = /* @__PURE__ */ __exportAll({
|
|
116
|
+
andThen: () => andThen,
|
|
117
|
+
apply: () => apply,
|
|
118
|
+
applyTo: () => applyTo,
|
|
119
|
+
asInvertible: () => asInvertible,
|
|
120
|
+
equals: () => equals,
|
|
121
|
+
fromMatrix: () => fromMatrix,
|
|
122
|
+
identity: () => identity,
|
|
123
|
+
inverse: () => inverse,
|
|
124
|
+
inverseUnsafe: () => inverseUnsafe,
|
|
125
|
+
isAffine2d: () => isAffine2d,
|
|
126
|
+
isInvertible: () => isInvertible,
|
|
127
|
+
linear: () => linear,
|
|
128
|
+
linearPart: () => linearPart,
|
|
129
|
+
reflectAcrossLine: () => reflectAcrossLine,
|
|
130
|
+
reflectX: () => reflectX,
|
|
131
|
+
reflectY: () => reflectY,
|
|
132
|
+
rotate: () => rotate,
|
|
133
|
+
rotateAround: () => rotateAround,
|
|
134
|
+
scale: () => scale,
|
|
135
|
+
scaleAround: () => scaleAround,
|
|
136
|
+
shear: () => shear,
|
|
137
|
+
translate: () => translate,
|
|
138
|
+
translateBy: () => translateBy,
|
|
139
|
+
translation: () => translation
|
|
140
|
+
});
|
|
141
|
+
/**
|
|
142
|
+
* Checks if a value is an `Affine2d`.
|
|
143
|
+
*
|
|
144
|
+
* @param a - The value to check.
|
|
145
|
+
* @returns `true` if the value is an `Affine2d`, `false` otherwise.
|
|
146
|
+
* @since 2.0.0
|
|
147
|
+
*/
|
|
148
|
+
const isAffine2d = isAffine2d$1;
|
|
149
|
+
/**
|
|
150
|
+
* Lifts a `Matrix3x3` into an `Affine2d` after asserting its last row is
|
|
151
|
+
* `[0, 0, 1]`. Use this when constructing affine transforms from an already-
|
|
152
|
+
* built matrix; prefer the named constructors below for ordinary usage.
|
|
153
|
+
*
|
|
154
|
+
* @param matrix - The matrix to lift. Must have a last row of `[0, 0, 1]`.
|
|
155
|
+
* @returns A new `Affine2d` wrapping the matrix.
|
|
156
|
+
* @throws If the matrix's last row is not `[0, 0, 1]` within tolerance.
|
|
157
|
+
* @since 2.0.0
|
|
158
|
+
*/
|
|
159
|
+
const fromMatrix = fromMatrix$1;
|
|
160
|
+
/**
|
|
161
|
+
* The identity transform — leaves every point fixed.
|
|
162
|
+
*
|
|
163
|
+
* @since 2.0.0
|
|
164
|
+
*/
|
|
165
|
+
const identity = identity$1;
|
|
166
|
+
/**
|
|
167
|
+
* Creates an `Affine2d` that translates by `(tx, ty)`.
|
|
168
|
+
*
|
|
169
|
+
* @param tx - The x translation.
|
|
170
|
+
* @param ty - The y translation.
|
|
171
|
+
* @returns A new translating `Affine2d`.
|
|
172
|
+
* @since 2.0.0
|
|
173
|
+
*/
|
|
174
|
+
const translate = translate$1;
|
|
175
|
+
/**
|
|
176
|
+
* Creates an `Affine2d` that translates by the components of a `Vector2`.
|
|
177
|
+
*
|
|
178
|
+
* @param v - The vector whose components define the translation.
|
|
179
|
+
* @returns A new translating `Affine2d`.
|
|
180
|
+
* @since 2.0.0
|
|
181
|
+
*/
|
|
182
|
+
const translateBy = translateBy$1;
|
|
183
|
+
const scale = scale$1;
|
|
184
|
+
/**
|
|
185
|
+
* Creates an `Affine2d` that scales by `(sx, sy)` about `origin`. Points at
|
|
186
|
+
* `origin` are left fixed; every other point moves toward or away from
|
|
187
|
+
* `origin` along the corresponding axis.
|
|
188
|
+
*
|
|
189
|
+
* @param sx - The x scale factor.
|
|
190
|
+
* @param sy - The y scale factor.
|
|
191
|
+
* @param origin - The fixed point of the scaling.
|
|
192
|
+
* @returns A new scaling `Affine2d`.
|
|
193
|
+
* @since 2.0.0
|
|
194
|
+
*/
|
|
195
|
+
const scaleAround = scaleAround$1;
|
|
196
|
+
/**
|
|
197
|
+
* Creates an `Affine2d` that rotates by `theta` radians around the origin.
|
|
198
|
+
* Counter-clockwise in the standard mathematical orientation (with y up); if
|
|
199
|
+
* your coordinate system has y down, rotation is clockwise.
|
|
200
|
+
*
|
|
201
|
+
* @param theta - The rotation angle in radians.
|
|
202
|
+
* @returns A new rotating `Affine2d`.
|
|
203
|
+
* @since 2.0.0
|
|
204
|
+
*/
|
|
205
|
+
const rotate = rotate$1;
|
|
206
|
+
/**
|
|
207
|
+
* Creates an `Affine2d` that rotates by `theta` radians around `origin`.
|
|
208
|
+
*
|
|
209
|
+
* @param theta - The rotation angle in radians.
|
|
210
|
+
* @param origin - The fixed point of the rotation.
|
|
211
|
+
* @returns A new rotating `Affine2d`.
|
|
212
|
+
* @since 2.0.0
|
|
213
|
+
*/
|
|
214
|
+
const rotateAround = rotateAround$1;
|
|
215
|
+
/**
|
|
216
|
+
* Reflects points across the x axis: `(x, y) → (x, -y)`.
|
|
217
|
+
*
|
|
218
|
+
* @since 2.0.0
|
|
219
|
+
*/
|
|
220
|
+
const reflectX = reflectX$1;
|
|
221
|
+
/**
|
|
222
|
+
* Reflects points across the y axis: `(x, y) → (-x, y)`.
|
|
223
|
+
*
|
|
224
|
+
* @since 2.0.0
|
|
225
|
+
*/
|
|
226
|
+
const reflectY = reflectY$1;
|
|
227
|
+
/**
|
|
228
|
+
* Creates an `Affine2d` that reflects across the line passing through
|
|
229
|
+
* `origin` in the direction `direction`. `direction` need not be unit length;
|
|
230
|
+
* it is normalized internally.
|
|
231
|
+
*
|
|
232
|
+
* @param origin - A point on the mirror line.
|
|
233
|
+
* @param direction - A non-zero vector parallel to the mirror line.
|
|
234
|
+
* @returns A new reflecting `Affine2d`.
|
|
235
|
+
* @throws If `direction` is the zero vector.
|
|
236
|
+
* @since 2.0.0
|
|
237
|
+
*/
|
|
238
|
+
const reflectAcrossLine = reflectAcrossLine$1;
|
|
239
|
+
/**
|
|
240
|
+
* Creates an `Affine2d` shear with `kx` horizontal shear (x gains `kx · y`)
|
|
241
|
+
* and `ky` vertical shear (y gains `ky · x`).
|
|
242
|
+
*
|
|
243
|
+
* @param kx - The horizontal shear factor.
|
|
244
|
+
* @param ky - The vertical shear factor.
|
|
245
|
+
* @returns A new shearing `Affine2d`.
|
|
246
|
+
* @since 2.0.0
|
|
247
|
+
*/
|
|
248
|
+
const shear = shear$1;
|
|
249
|
+
const andThen = andThen$1;
|
|
250
|
+
const inverse = inverse$1;
|
|
251
|
+
/**
|
|
252
|
+
* Inverts an `Affine2d`. Throws when the transform is singular (e.g. a scale
|
|
253
|
+
* with a zero factor). Useful when invertibility has already been validated
|
|
254
|
+
* out-of-band; otherwise prefer {@link inverse}.
|
|
255
|
+
*
|
|
256
|
+
* @param a - The transform to invert.
|
|
257
|
+
* @returns The inverse transform.
|
|
258
|
+
* @throws If `a` is singular.
|
|
259
|
+
* @since 2.0.0
|
|
260
|
+
*/
|
|
261
|
+
const inverseUnsafe = inverseUnsafe$1;
|
|
262
|
+
/**
|
|
263
|
+
* Type-narrowing predicate: refines an `Affine2d<T>` to
|
|
264
|
+
* `Affine2d<T & Invertible>` when the underlying matrix is invertible
|
|
265
|
+
* (determinant non-zero within the default absolute tolerance).
|
|
266
|
+
*
|
|
267
|
+
* @param a - The transform to check.
|
|
268
|
+
* @returns `true` when `a` is invertible.
|
|
269
|
+
* @since 2.0.0
|
|
270
|
+
*/
|
|
271
|
+
const isInvertible = isInvertible$1;
|
|
272
|
+
/**
|
|
273
|
+
* Asserts that the transform is invertible, throwing on a singular transform.
|
|
274
|
+
*
|
|
275
|
+
* @param a - The transform to assert against.
|
|
276
|
+
* @returns The same transform, typed with the `Invertible` brand.
|
|
277
|
+
* @throws When `a` is singular.
|
|
278
|
+
* @since 2.0.0
|
|
279
|
+
*/
|
|
280
|
+
const asInvertible = asInvertible$1;
|
|
281
|
+
const apply = apply$1;
|
|
282
|
+
/**
|
|
283
|
+
* Returns a `Vector2 → Vector2` function that applies `a` to its argument.
|
|
284
|
+
* Designed as the bridge to per-point mappers like `Bezier2d.mapPoints`:
|
|
285
|
+
*
|
|
286
|
+
* ```ts
|
|
287
|
+
* Bezier2d.mapPoints(spline, Affine2d.applyTo(transform))
|
|
288
|
+
* ```
|
|
289
|
+
*
|
|
290
|
+
* @param a - The transform to lift.
|
|
291
|
+
* @returns A function that applies `a` to a point.
|
|
292
|
+
* @since 2.0.0
|
|
293
|
+
*/
|
|
294
|
+
const applyTo = applyTo$1;
|
|
295
|
+
/**
|
|
296
|
+
* Extracts the 2×2 linear part of an `Affine2d` — the upper-left block of
|
|
297
|
+
* its homogeneous matrix, ignoring translation. Maps direction vectors
|
|
298
|
+
* (tangents, differences of points) under the transform.
|
|
299
|
+
*
|
|
300
|
+
* @param a - The transform.
|
|
301
|
+
* @returns The 2×2 linear part.
|
|
302
|
+
* @since 2.0.0
|
|
303
|
+
*/
|
|
304
|
+
const linear = linear$1;
|
|
305
|
+
/**
|
|
306
|
+
* Extracts the translation vector of an `Affine2d` — the third column of its
|
|
307
|
+
* homogeneous matrix, ignoring the linear part.
|
|
308
|
+
*
|
|
309
|
+
* @param a - The transform.
|
|
310
|
+
* @returns The translation vector.
|
|
311
|
+
* @since 2.0.0
|
|
312
|
+
*/
|
|
313
|
+
const translation = translation$1;
|
|
314
|
+
/**
|
|
315
|
+
* Returns the `Affine2d` corresponding to `a`'s linear part with translation
|
|
316
|
+
* zeroed. Equivalent to building an affine from {@link linear} but stays in
|
|
317
|
+
* the `Affine2d` type so it can be applied via {@link apply} or {@link applyTo}.
|
|
318
|
+
*
|
|
319
|
+
* Use this to transform anything that is *not* a position — tangent vectors
|
|
320
|
+
* in Hermite control data, or the higher-degree coefficients of a polynomial
|
|
321
|
+
* curve, both of which see only the linear part of an affine map.
|
|
322
|
+
*
|
|
323
|
+
* @param a - The transform.
|
|
324
|
+
* @returns The translation-free `Affine2d`.
|
|
325
|
+
* @since 2.0.0
|
|
326
|
+
*/
|
|
327
|
+
const linearPart = linearPart$1;
|
|
328
|
+
const equals = equals$1;
|
|
329
|
+
//#endregion
|
|
330
|
+
export { linearPart as i, apply as n, applyTo as r, affine2d_exports as t };
|
|
331
|
+
|
|
332
|
+
//# sourceMappingURL=affine2d-Dvna84gc.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"affine2d-Dvna84gc.mjs","names":["isAffine2d","fromMatrix","identity","matrix3x3.identity","translate","matrix3x3.make","translateBy","scale","scaleAround","rotate","rotateAround","reflectX","reflectY","reflectAcrossLine","vector2.magnitude","shear","andThen","matrix3x3.multiply","isInvertible","matrix3x3.isInvertible","asInvertible","inverse","matrix3x3.inverse","Solution.isNone","Solution.none","Solution.one","inverseUnsafe","matrix3x3.inverseUnsafe","apply","vector2.make","applyTo","linear","matrix2x2.make","translation","linearPart","equals","matrix3x3.equals","internal.isAffine2d","internal.fromMatrix","internal.identity","internal.translate","internal.translateBy","internal.scale","internal.scaleAround","internal.rotate","internal.rotateAround","internal.reflectX","internal.reflectY","internal.reflectAcrossLine","internal.shear","internal.andThen","internal.inverse","internal.inverseUnsafe","internal.isInvertible","internal.asInvertible","internal.apply","internal.applyTo","internal.linear","internal.translation","internal.linearPart","internal.equals"],"sources":["../../src/transform/affine2d.internal.ts","../../src/transform/affine2d.ts"],"sourcesContent":["import * as matrix2x2 from '../matrix/matrix2x2.internal.ts'\nimport type { Matrix2x2 } from '../matrix/matrix2x2.ts'\nimport * as matrix3x3 from '../matrix/matrix3x3.internal.ts'\nimport type { Matrix3x3 } from '../matrix/matrix3x3.ts'\nimport { coincident, EPSILON, RELATIVE_TOLERANCE } from '../number.ts'\nimport * as Solution from '../solution/solution.ts'\nimport { dual, invariant, Pipeable } from '../utils.ts'\nimport * as vector2 from '../vector/vector2.internal.ts'\nimport type { Vector2 } from '../vector/vector2.ts'\nimport type { Affine2d } from './affine2d.ts'\nimport type { Invertible } from './traits.ts'\nimport { AffineTraits } from './traits.ts'\n\nexport const Affine2dTypeId: unique symbol = Symbol.for('curvy/transform/affine2d')\nexport type Affine2dTypeId = typeof Affine2dTypeId\n\nclass Affine2dImpl extends Pipeable implements Affine2d<unknown> {\n readonly [Affine2dTypeId]: Affine2dTypeId = Affine2dTypeId\n declare readonly [AffineTraits]: unknown\n readonly matrix: Matrix3x3\n\n constructor(matrix: Matrix3x3) {\n super()\n this.matrix = matrix\n }\n\n get [Symbol.toStringTag]() {\n const m = this.matrix\n return `Affine2d([${m.m00}, ${m.m01}, ${m.m02}], [${m.m10}, ${m.m11}, ${m.m12}])`\n }\n\n get [Symbol.for('nodejs.util.inspect.custom')]() {\n return this[Symbol.toStringTag]\n }\n}\n\n/** @internal */\nexport const isAffine2d = (a: unknown): a is Affine2d =>\n typeof a === 'object' && a !== null && Affine2dTypeId in a\n\n/** @internal */\nexport const fromMatrix = (matrix: Matrix3x3): Affine2d => {\n // The last row of an affine matrix is structural — anything else is a\n // projective transform, which doesn't preserve the polynomial form of a\n // curve's control points. The zero checks widen with the magnitude of the\n // matrix's other entries: a transform with large terms carries\n // proportionally large rounding noise in every computed slot, so \"zero\"\n // there means \"zero at this matrix's scale\".\n const scale = Math.max(\n Math.abs(matrix.m00),\n Math.abs(matrix.m01),\n Math.abs(matrix.m02),\n Math.abs(matrix.m10),\n Math.abs(matrix.m11),\n Math.abs(matrix.m12),\n )\n const zeroTolerance = EPSILON + RELATIVE_TOLERANCE * scale\n invariant(\n coincident(matrix.m20, 0, zeroTolerance) &&\n coincident(matrix.m21, 0, zeroTolerance) &&\n coincident(matrix.m22, 1),\n 'Affine2d requires the third row of its matrix to be [0, 0, 1]',\n )\n return new Affine2dImpl(matrix)\n}\n\n/** @internal */\nexport const identity: Affine2d = new Affine2dImpl(matrix3x3.identity)\n\n/** @internal */\nexport const translate = (tx: number, ty: number): Affine2d =>\n new Affine2dImpl(matrix3x3.make(1, 0, tx, 0, 1, ty, 0, 0, 1))\n\n/** @internal */\nexport const translateBy = (v: Vector2): Affine2d => translate(v.x, v.y)\n\n/** @internal */\nexport const scale = (sx: number, sy?: number): Affine2d => {\n const y = sy ?? sx\n return new Affine2dImpl(matrix3x3.make(sx, 0, 0, 0, y, 0, 0, 0, 1))\n}\n\n/** @internal */\nexport const scaleAround = (sx: number, sy: number, origin: Vector2): Affine2d => {\n // T(o) · S(sx, sy) · T(-o), expanded so the third row stays exact.\n return new Affine2dImpl(\n matrix3x3.make(sx, 0, origin.x * (1 - sx), 0, sy, origin.y * (1 - sy), 0, 0, 1),\n )\n}\n\n/** @internal */\nexport const rotate = (theta: number): Affine2d => {\n const c = Math.cos(theta)\n const s = Math.sin(theta)\n return new Affine2dImpl(matrix3x3.make(c, -s, 0, s, c, 0, 0, 0, 1))\n}\n\n/** @internal */\nexport const rotateAround = (theta: number, origin: Vector2): Affine2d => {\n // T(o) · R(θ) · T(-o), expanded.\n const c = Math.cos(theta)\n const s = Math.sin(theta)\n return new Affine2dImpl(\n matrix3x3.make(\n c,\n -s,\n origin.x - origin.x * c + origin.y * s,\n s,\n c,\n origin.y - origin.x * s - origin.y * c,\n 0,\n 0,\n 1,\n ),\n )\n}\n\n/** @internal */\nexport const reflectX: Affine2d = new Affine2dImpl(matrix3x3.make(1, 0, 0, 0, -1, 0, 0, 0, 1))\n\n/** @internal */\nexport const reflectY: Affine2d = new Affine2dImpl(matrix3x3.make(-1, 0, 0, 0, 1, 0, 0, 0, 1))\n\n/** @internal */\nexport const reflectAcrossLine = (origin: Vector2, direction: Vector2): Affine2d => {\n const mag = vector2.magnitude(direction)\n invariant(mag > 0, 'reflectAcrossLine requires a non-zero direction vector')\n const dx = direction.x / mag\n const dy = direction.y / mag\n\n // Householder-style reflection across the line through `origin` with unit\n // direction (dx, dy):\n // M = [dx² - dy², 2 dx dy ]\n // [ 2 dx dy, dy² - dx² ]\n // Then translate so the line passes through `origin` instead of the origin.\n const a = dx * dx - dy * dy\n const b = 2 * dx * dy\n const negA = -a // dy² - dx²\n\n return new Affine2dImpl(\n matrix3x3.make(\n a,\n b,\n origin.x - a * origin.x - b * origin.y,\n b,\n negA,\n origin.y - b * origin.x - negA * origin.y,\n 0,\n 0,\n 1,\n ),\n )\n}\n\n/** @internal */\nexport const shear = (kx: number, ky: number): Affine2d =>\n new Affine2dImpl(matrix3x3.make(1, kx, 0, ky, 1, 0, 0, 0, 1))\n\n/** @internal */\nexport const andThen = dual<\n (b: Affine2d) => (a: Affine2d) => Affine2d,\n (a: Affine2d, b: Affine2d) => Affine2d\n>(\n 2,\n // `andThen(a, b)` (or `a.pipe(andThen(b))`) means \"apply `a` first, then\n // `b`\". For column-vector points that is `b · a`.\n (a: Affine2d, b: Affine2d) => new Affine2dImpl(matrix3x3.multiply(b.matrix, a.matrix)),\n)\n\n/** @internal */\nexport const isInvertible = <T>(a: Affine2d<T>): a is Affine2d<T & Invertible> =>\n matrix3x3.isInvertible(a.matrix)\n\n/** @internal */\nexport const asInvertible = <T>(a: Affine2d<T>): Affine2d<T & Invertible> => {\n invariant(isInvertible(a), 'affine2d is not invertible')\n return a\n}\n\n// On `Invertible`-branded transforms the empty branch is provably unreachable,\n// but TS can't see that — the cast at the public overload pairs the type-level\n// promise with the runtime brand check.\n/** @internal */\nexport const inverse = <T>(a: Affine2d<T>): Solution.AtMostOne<Affine2d<T>> => {\n const inv = matrix3x3.inverse(a.matrix)\n if (Solution.isNone(inv)) {\n return Solution.none\n }\n return Solution.one(new Affine2dImpl(inv.value) as Affine2d<T>)\n}\n\n/** @internal */\nexport const inverseUnsafe = (a: Affine2d): Affine2d =>\n new Affine2dImpl(matrix3x3.inverseUnsafe(a.matrix))\n\n/** @internal */\nexport const apply = dual<\n (p: Vector2) => (a: Affine2d) => Vector2,\n (a: Affine2d, p: Vector2) => Vector2\n>(2, (a: Affine2d, p: Vector2) => {\n const m = a.matrix\n return vector2.make(m.m00 * p.x + m.m01 * p.y + m.m02, m.m10 * p.x + m.m11 * p.y + m.m12)\n})\n\n/** @internal */\nexport const applyTo =\n (a: Affine2d) =>\n (p: Vector2): Vector2 =>\n apply(a, p)\n\n/** @internal */\nexport const linear = (a: Affine2d): Matrix2x2 => {\n const m = a.matrix\n return matrix2x2.make(m.m00, m.m01, m.m10, m.m11)\n}\n\n/** @internal */\nexport const translation = (a: Affine2d): Vector2 => vector2.make(a.matrix.m02, a.matrix.m12)\n\n/** @internal */\nexport const linearPart = (a: Affine2d): Affine2d => {\n const m = a.matrix\n return new Affine2dImpl(matrix3x3.make(m.m00, m.m01, 0, m.m10, m.m11, 0, 0, 0, 1))\n}\n\n/** @internal */\nexport const equals = dual<\n (b: Affine2d) => (a: Affine2d) => boolean,\n (a: Affine2d, b: Affine2d) => boolean\n>(2, (a: Affine2d, b: Affine2d) => matrix3x3.equals(a.matrix, b.matrix))\n","import type { Matrix2x2 } from '../matrix/matrix2x2.ts'\nimport type { Matrix3x3 } from '../matrix/matrix3x3.ts'\nimport type * as Solution from '../solution/solution.ts'\nimport type { Pipeable } from '../utils.ts'\nimport type { Vector2 } from '../vector/vector2.ts'\nimport type { Affine2dTypeId } from './affine2d.internal.ts'\nimport * as internal from './affine2d.internal.ts'\nimport type { AffineTraits, Invertible } from './traits.ts'\n\nexport type { Invertible } from './traits.ts'\n\n/**\n * A 2D affine transformation — the most general map of the form\n *\n * ```\n * x' = a · x + b · y + tx\n * y' = c · x + d · y + ty\n * ```\n *\n * Represented internally as a 3×3 matrix in homogeneous form (the third row is\n * always `[0, 0, 1]`), so that composition is matrix multiplication and a\n * single instance can describe any chain of translates, scales, rotations,\n * reflections, and shears.\n *\n * Affine maps commute with polynomial evaluation: transforming a spline's\n * control points and then sampling produces the same point as sampling first\n * and then transforming. Concrete spline modules expose `transform(s, a)`\n * helpers that take advantage of this.\n *\n * The `Traits` type parameter is a phantom marker that accumulates trait\n * brands as the transform is refined via `isInvertible` / `asInvertible`. The\n * runtime value carries no trait data — `Traits` only flows through the type\n * system to enable tighter return types on operations like {@link inverse}.\n *\n * @since 2.0.0\n */\nexport interface Affine2d<out Traits = unknown> extends Pipeable {\n readonly [Affine2dTypeId]: Affine2dTypeId\n readonly [AffineTraits]: Traits\n /**\n * The underlying 3×3 homogeneous matrix. Last row is always `[0, 0, 1]`.\n */\n readonly matrix: Matrix3x3\n}\n\n/**\n * Checks if a value is an `Affine2d`.\n *\n * @param a - The value to check.\n * @returns `true` if the value is an `Affine2d`, `false` otherwise.\n * @since 2.0.0\n */\nexport const isAffine2d: (a: unknown) => a is Affine2d = internal.isAffine2d\n\n/**\n * Lifts a `Matrix3x3` into an `Affine2d` after asserting its last row is\n * `[0, 0, 1]`. Use this when constructing affine transforms from an already-\n * built matrix; prefer the named constructors below for ordinary usage.\n *\n * @param matrix - The matrix to lift. Must have a last row of `[0, 0, 1]`.\n * @returns A new `Affine2d` wrapping the matrix.\n * @throws If the matrix's last row is not `[0, 0, 1]` within tolerance.\n * @since 2.0.0\n */\nexport const fromMatrix: (matrix: Matrix3x3) => Affine2d = internal.fromMatrix\n\n/**\n * The identity transform — leaves every point fixed.\n *\n * @since 2.0.0\n */\nexport const identity: Affine2d = internal.identity\n\n/**\n * Creates an `Affine2d` that translates by `(tx, ty)`.\n *\n * @param tx - The x translation.\n * @param ty - The y translation.\n * @returns A new translating `Affine2d`.\n * @since 2.0.0\n */\nexport const translate: (tx: number, ty: number) => Affine2d = internal.translate\n\n/**\n * Creates an `Affine2d` that translates by the components of a `Vector2`.\n *\n * @param v - The vector whose components define the translation.\n * @returns A new translating `Affine2d`.\n * @since 2.0.0\n */\nexport const translateBy: (v: Vector2) => Affine2d = internal.translateBy\n\nexport const scale: {\n /**\n * Creates an `Affine2d` that scales uniformly by `xy` on both axes,\n * centered on the origin.\n *\n * @param xy - The uniform scale factor.\n * @returns A new scaling `Affine2d`.\n * @since 2.0.0\n */\n (xy: number): Affine2d\n /**\n * Creates an `Affine2d` that scales by `sx` on the x axis and `sy` on the\n * y axis, centered on the origin.\n *\n * @param sx - The x scale factor.\n * @param sy - The y scale factor.\n * @returns A new scaling `Affine2d`.\n * @since 2.0.0\n */\n (sx: number, sy: number): Affine2d\n} = internal.scale\n\n/**\n * Creates an `Affine2d` that scales by `(sx, sy)` about `origin`. Points at\n * `origin` are left fixed; every other point moves toward or away from\n * `origin` along the corresponding axis.\n *\n * @param sx - The x scale factor.\n * @param sy - The y scale factor.\n * @param origin - The fixed point of the scaling.\n * @returns A new scaling `Affine2d`.\n * @since 2.0.0\n */\nexport const scaleAround: (sx: number, sy: number, origin: Vector2) => Affine2d =\n internal.scaleAround\n\n/**\n * Creates an `Affine2d` that rotates by `theta` radians around the origin.\n * Counter-clockwise in the standard mathematical orientation (with y up); if\n * your coordinate system has y down, rotation is clockwise.\n *\n * @param theta - The rotation angle in radians.\n * @returns A new rotating `Affine2d`.\n * @since 2.0.0\n */\nexport const rotate: (theta: number) => Affine2d = internal.rotate\n\n/**\n * Creates an `Affine2d` that rotates by `theta` radians around `origin`.\n *\n * @param theta - The rotation angle in radians.\n * @param origin - The fixed point of the rotation.\n * @returns A new rotating `Affine2d`.\n * @since 2.0.0\n */\nexport const rotateAround: (theta: number, origin: Vector2) => Affine2d = internal.rotateAround\n\n/**\n * Reflects points across the x axis: `(x, y) → (x, -y)`.\n *\n * @since 2.0.0\n */\nexport const reflectX: Affine2d = internal.reflectX\n\n/**\n * Reflects points across the y axis: `(x, y) → (-x, y)`.\n *\n * @since 2.0.0\n */\nexport const reflectY: Affine2d = internal.reflectY\n\n/**\n * Creates an `Affine2d` that reflects across the line passing through\n * `origin` in the direction `direction`. `direction` need not be unit length;\n * it is normalized internally.\n *\n * @param origin - A point on the mirror line.\n * @param direction - A non-zero vector parallel to the mirror line.\n * @returns A new reflecting `Affine2d`.\n * @throws If `direction` is the zero vector.\n * @since 2.0.0\n */\nexport const reflectAcrossLine: (origin: Vector2, direction: Vector2) => Affine2d =\n internal.reflectAcrossLine\n\n/**\n * Creates an `Affine2d` shear with `kx` horizontal shear (x gains `kx · y`)\n * and `ky` vertical shear (y gains `ky · x`).\n *\n * @param kx - The horizontal shear factor.\n * @param ky - The vertical shear factor.\n * @returns A new shearing `Affine2d`.\n * @since 2.0.0\n */\nexport const shear: (kx: number, ky: number) => Affine2d = internal.shear\n\nexport const andThen: {\n /**\n * Sequences two `Affine2d` transforms, applying `a` first and then `b`.\n * Designed for pipe chains:\n *\n * ```ts\n * import * as Affine2d from 'curvy/transform'\n *\n * const t = Affine2d.identity.pipe(\n * Affine2d.andThen(Affine2d.translate(1, 0)),\n * Affine2d.andThen(Affine2d.rotate(Math.PI / 2)),\n * )\n * // applying t = translate first, then rotate\n * ```\n *\n * In matrix terms this returns `b · a`, the matrix that yields the same\n * result as applying `a` then `b` to a column-vector point.\n *\n * @param a - The transform applied first.\n * @param b - The transform applied second.\n * @returns A new combined `Affine2d`.\n * @since 2.0.0\n */\n (a: Affine2d, b: Affine2d): Affine2d\n /**\n * Pipe-friendly form of {@link andThen}. `andThen(b)(a)` applies `a` then\n * `b`.\n *\n * @param b - The transform applied after the piped-in transform.\n * @returns A function that takes the transform to apply first and returns the sequenced transform.\n * @since 2.0.0\n */\n (b: Affine2d): (a: Affine2d) => Affine2d\n} = internal.andThen\n\n// The implementation always runs the same singular check. For\n// `Invertible`-branded transforms the empty branch is provably unreachable,\n// but TS can't see that — the cast pairs the type-level promise with the\n// runtime brand check.\nexport const inverse: {\n /**\n * Inverts an `Invertible`-branded `Affine2d`. Because the brand guarantees\n * non-singularity, the result is always a single transform — wrapped in\n * `Solution.One`.\n *\n * @param a - The transform to invert.\n * @since 2.0.0\n */\n <T extends Invertible>(a: Affine2d<T>): Solution.One<Affine2d<T>>\n /**\n * Inverts an `Affine2d`. Returns `Solution.none` if the transform is\n * singular (e.g. a scale with a zero factor). Use {@link asInvertible} or\n * {@link isInvertible} to refine the type and tighten the return to\n * `Solution.One`, or use {@link inverseUnsafe} if you want the throwing form.\n *\n * @param a - The transform to invert.\n * @since 2.0.0\n */\n <T>(a: Affine2d<T>): Solution.AtMostOne<Affine2d<T>>\n} = internal.inverse as never\n\n/**\n * Inverts an `Affine2d`. Throws when the transform is singular (e.g. a scale\n * with a zero factor). Useful when invertibility has already been validated\n * out-of-band; otherwise prefer {@link inverse}.\n *\n * @param a - The transform to invert.\n * @returns The inverse transform.\n * @throws If `a` is singular.\n * @since 2.0.0\n */\nexport const inverseUnsafe: (a: Affine2d) => Affine2d = internal.inverseUnsafe\n\n/**\n * Type-narrowing predicate: refines an `Affine2d<T>` to\n * `Affine2d<T & Invertible>` when the underlying matrix is invertible\n * (determinant non-zero within the default absolute tolerance).\n *\n * @param a - The transform to check.\n * @returns `true` when `a` is invertible.\n * @since 2.0.0\n */\nexport const isInvertible: <T>(a: Affine2d<T>) => a is Affine2d<T & Invertible> =\n internal.isInvertible\n\n/**\n * Asserts that the transform is invertible, throwing on a singular transform.\n *\n * @param a - The transform to assert against.\n * @returns The same transform, typed with the `Invertible` brand.\n * @throws When `a` is singular.\n * @since 2.0.0\n */\nexport const asInvertible: <T>(a: Affine2d<T>) => Affine2d<T & Invertible> = internal.asInvertible\n\nexport const apply: {\n /**\n * Applies an `Affine2d` to a `Vector2`, returning the transformed point.\n *\n * @param a - The transform to apply.\n * @param p - The point to transform.\n * @returns The transformed point.\n * @since 2.0.0\n */\n (a: Affine2d, p: Vector2): Vector2\n /**\n * Applies an `Affine2d` to a `Vector2`.\n *\n * @param p - The point to transform.\n * @returns A function that takes the transform and returns the transformed point.\n * @since 2.0.0\n */\n (p: Vector2): (a: Affine2d) => Vector2\n} = internal.apply\n\n/**\n * Returns a `Vector2 → Vector2` function that applies `a` to its argument.\n * Designed as the bridge to per-point mappers like `Bezier2d.mapPoints`:\n *\n * ```ts\n * Bezier2d.mapPoints(spline, Affine2d.applyTo(transform))\n * ```\n *\n * @param a - The transform to lift.\n * @returns A function that applies `a` to a point.\n * @since 2.0.0\n */\nexport const applyTo: (a: Affine2d) => (p: Vector2) => Vector2 = internal.applyTo\n\n/**\n * Extracts the 2×2 linear part of an `Affine2d` — the upper-left block of\n * its homogeneous matrix, ignoring translation. Maps direction vectors\n * (tangents, differences of points) under the transform.\n *\n * @param a - The transform.\n * @returns The 2×2 linear part.\n * @since 2.0.0\n */\nexport const linear: (a: Affine2d) => Matrix2x2 = internal.linear\n\n/**\n * Extracts the translation vector of an `Affine2d` — the third column of its\n * homogeneous matrix, ignoring the linear part.\n *\n * @param a - The transform.\n * @returns The translation vector.\n * @since 2.0.0\n */\nexport const translation: (a: Affine2d) => Vector2 = internal.translation\n\n/**\n * Returns the `Affine2d` corresponding to `a`'s linear part with translation\n * zeroed. Equivalent to building an affine from {@link linear} but stays in\n * the `Affine2d` type so it can be applied via {@link apply} or {@link applyTo}.\n *\n * Use this to transform anything that is *not* a position — tangent vectors\n * in Hermite control data, or the higher-degree coefficients of a polynomial\n * curve, both of which see only the linear part of an affine map.\n *\n * @param a - The transform.\n * @returns The translation-free `Affine2d`.\n * @since 2.0.0\n */\nexport const linearPart: (a: Affine2d) => Affine2d = internal.linearPart\n\nexport const equals: {\n /**\n * Checks if two `Affine2d` instances are approximately equal within the\n * default absolute tolerance.\n *\n * @param a - The first transform.\n * @param b - The second transform.\n * @returns `true` when each matrix entry is within tolerance.\n * @since 2.0.0\n */\n (a: Affine2d, b: Affine2d): boolean\n /**\n * Checks if two `Affine2d` instances are approximately equal.\n *\n * @param b - The second transform.\n * @returns A function that takes the first transform and returns the comparison.\n * @since 2.0.0\n */\n (b: Affine2d): (a: Affine2d) => boolean\n} = internal.equals\n"],"mappings":"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"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { t as __exportAll } from "./chunk-25Hzd3z8.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { r as fromVector } from "./cubic-BL6dpuHh.mjs";
|
|
2
|
+
import { a as vectorProductLeft, n as make } from "./matrix4x4-BrqgYZCD.mjs";
|
|
3
|
+
import { r as fromVector } from "./cubic-BiGuAnZ0.mjs";
|
|
5
4
|
//#region src/characteristic/characteristic.ts
|
|
6
5
|
var characteristic_exports = /* @__PURE__ */ __exportAll({
|
|
7
6
|
apply: () => apply,
|
|
@@ -41,7 +40,7 @@ const cubicHermite = make(1, 0, 0, 0, 0, 1, 0, 0, -3, -2, 3, -1, 2, 1, -2, 1);
|
|
|
41
40
|
*
|
|
42
41
|
* @since 2.0.0
|
|
43
42
|
*/
|
|
44
|
-
const cubicBasisSpline = make(1 / 6, 4 / 6,
|
|
43
|
+
const cubicBasisSpline = make(1 / 6, 4 / 6, 1 / 6, 0, -.5, 0, .5, 0, .5, -1, .5, 0, -1 / 6, .5, -.5, 1 / 6);
|
|
45
44
|
const cardinalCache = /* @__PURE__ */ new Map();
|
|
46
45
|
/**
|
|
47
46
|
* The cubic Cardinal spline characteristic matrix, parameterized by tension.
|
|
@@ -101,4 +100,4 @@ const apply = (matrix, ...channels) => {
|
|
|
101
100
|
//#endregion
|
|
102
101
|
export { cubicHermite as a, cubicBezier as i, characteristic_exports as n, cubicBasisSpline as r, apply as t };
|
|
103
102
|
|
|
104
|
-
//# sourceMappingURL=characteristic
|
|
103
|
+
//# sourceMappingURL=characteristic--7nC4Q_a.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"characteristic--7nC4Q_a.mjs","names":["Matrix4x4.make","CubicPolynomial.fromVector","Matrix4x4.vectorProductLeft"],"sources":["../../src/characteristic/characteristic.ts"],"sourcesContent":["import * as Matrix4x4 from '../matrix/matrix4x4.ts'\nimport * as CubicPolynomial from '../polynomial/cubic.ts'\nimport type * as Vector4 from '../vector/vector4.ts'\n\n/**\n * The cubic Bézier characteristic matrix.\n *\n * Maps Bernstein-basis control points `(P₀, P₁, P₂, P₃)` to monomial cubic\n * coefficients `(c₀, c₁, c₂, c₃)` for `c₀ + c₁·t + c₂·t² + c₃·t³`. The matrix\n * IS the Bézier spline family — combined with control points (via {@link apply}),\n * it produces the cubic polynomial that parameterizes the curve.\n *\n * @since 2.0.0\n */\nexport const cubicBezier: Matrix4x4.Matrix4x4 = Matrix4x4.make(\n 1,\n 0,\n 0,\n 0,\n -3,\n 3,\n 0,\n 0,\n 3,\n -6,\n 3,\n 0,\n -1,\n 3,\n -3,\n 1,\n)\n\n/**\n * The cubic Hermite characteristic matrix.\n *\n * Maps Hermite control data `(P₀, V₀, P₁, V₁)` — two endpoints and two\n * tangent vectors — to monomial cubic coefficients.\n *\n * @since 2.0.0\n */\nexport const cubicHermite: Matrix4x4.Matrix4x4 = Matrix4x4.make(\n 1,\n 0,\n 0,\n 0,\n 0,\n 1,\n 0,\n 0,\n -3,\n -2,\n 3,\n -1,\n 2,\n 1,\n -2,\n 1,\n)\n\n/**\n * The uniform cubic B-spline (basis spline) characteristic matrix.\n *\n * Maps a window of four control points to the monomial cubic coefficients\n * of one segment of the corresponding uniform cubic B-spline. Stride-1\n * application produces a C² piecewise spline; the curve does not generally\n * pass through the control points.\n *\n * @since 2.0.0\n */\nexport const cubicBasisSpline: Matrix4x4.Matrix4x4 = Matrix4x4.make(\n 1 / 6,\n 4 / 6,\n 1 / 6,\n 0,\n -0.5,\n 0,\n 0.5,\n 0,\n 0.5,\n -1,\n 0.5,\n 0,\n -1 / 6,\n 0.5,\n -0.5,\n 1 / 6,\n)\n\nconst cardinalCache = new Map<number, Matrix4x4.Matrix4x4>()\n\n/**\n * The cubic Cardinal spline characteristic matrix, parameterized by tension.\n *\n * Maps four control points to the monomial cubic coefficients of one\n * Cardinal segment. The tension `s` controls how tightly the curve hugs\n * the control points: `s = 0` produces straight-line segments between\n * adjacent points, `s = 0.5` is the Catmull-Rom variant (see\n * {@link cubicCatmullRom}), and higher values produce looser, more curved\n * shapes.\n *\n * Cached per tension value — repeated calls with the same tension return\n * the same matrix instance.\n *\n * @param tension - The tension parameter.\n * @returns The characteristic matrix for that tension.\n * @since 2.0.0\n */\nexport const cubicCardinal = (tension: number): Matrix4x4.Matrix4x4 => {\n let m = cardinalCache.get(tension)\n if (m === undefined) {\n m = Matrix4x4.make(\n 0,\n 1,\n 0,\n 0,\n -tension,\n 0,\n tension,\n 0,\n 2 * tension,\n tension - 3,\n 3 - 2 * tension,\n -tension,\n -tension,\n 2 - tension,\n tension - 2,\n tension,\n )\n cardinalCache.set(tension, m)\n }\n return m\n}\n\n/**\n * The cubic Catmull-Rom characteristic matrix — Cardinal with tension `0.5`.\n * The most common Cardinal-family variant; reused widely enough to deserve\n * a constant.\n *\n * @since 2.0.0\n */\nexport const cubicCatmullRom: Matrix4x4.Matrix4x4 = cubicCardinal(0.5)\n\n/**\n * Applies a characteristic matrix to N channels of control values, producing\n * N cubic polynomials in monomial form.\n *\n * Each channel is a `Vector4` packing one axis's values across the four\n * control points: `(v₀, v₁, v₂, v₃)`. The result tuple has the same arity\n * as the input.\n *\n * The polynomial 2D spline pipeline applies this with two channels (x, y);\n * the rational 2D pipeline uses three (x, y, w) where `w` is the projective\n * denominator. Higher channel counts generalize to 3D, rational 3D, and\n * beyond — the characteristic matrix doesn't care about the geometric\n * domain, only about how to combine four samples per channel.\n *\n * @param matrix - The characteristic matrix of the spline family.\n * @param channels - One `Vector4` per output polynomial, packing the four control values for that channel.\n * @returns A tuple of cubic polynomials, one per input channel.\n * @since 2.0.0\n */\nexport const apply = <const Channels extends ReadonlyArray<Vector4.Vector4>>(\n matrix: Matrix4x4.Matrix4x4,\n ...channels: Channels\n): { readonly [K in keyof Channels]: CubicPolynomial.CubicPolynomial } => {\n const result = channels.map((c) =>\n CubicPolynomial.fromVector(Matrix4x4.vectorProductLeft(matrix, c)),\n )\n return result as { readonly [K in keyof Channels]: CubicPolynomial.CubicPolynomial }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAcA,MAAa,cAAmCA,KAC9C,GACA,GACA,GACA,GACA,IACA,GACA,GACA,GACA,GACA,IACA,GACA,GACA,IACA,GACA,IACA,EACD;;;;;;;;;AAUD,MAAa,eAAoCA,KAC/C,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,IACA,IACA,GACA,IACA,GACA,GACA,IACA,EACD;;;;;;;;;;;AAYD,MAAa,mBAAwCA,KACnD,IAAI,GACJ,IAAI,GACJ,IAAI,GACJ,GACA,KACA,GACA,IACA,GACA,IACA,IACA,IACA,GACA,KAAK,GACL,IACA,KACA,IAAI,EACL;AAED,MAAM,gCAAgB,IAAI,KAAkC;;;;;;;;;;;;;;;;;;AAmB5D,MAAa,iBAAiB,YAAyC;CACrE,IAAI,IAAI,cAAc,IAAI,QAAQ;CAClC,IAAI,MAAM,KAAA,GAAW;EACnB,IAAIA,KACF,GACA,GACA,GACA,GACA,CAAC,SACD,GACA,SACA,GACA,IAAI,SACJ,UAAU,GACV,IAAI,IAAI,SACR,CAAC,SACD,CAAC,SACD,IAAI,SACJ,UAAU,GACV,QACD;EACD,cAAc,IAAI,SAAS,EAAE;;CAE/B,OAAO;;;;;;;;;AAUT,MAAa,kBAAuC,cAAc,GAAI;;;;;;;;;;;;;;;;;;;;AAqBtE,MAAa,SACX,QACA,GAAG,aACqE;CAIxE,OAHe,SAAS,KAAK,MAC3BC,WAA2BC,kBAA4B,QAAQ,EAAE,CAAC,CAEvD"}
|