curve-ops 0.0.1
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/LICENSE +21 -0
- package/README.md +46 -0
- package/index.d.ts +280 -0
- package/index.js +1 -0
- package/package.json +29 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 David Evans
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Curve Ops
|
|
2
|
+
|
|
3
|
+
A collection of mathematical utilities for working with curves (primarily Bézier
|
|
4
|
+
curves). This is designed for vector drawing tools, but also exposes various
|
|
5
|
+
underlying abilities such as matrix operations which may be useful elsewhere.
|
|
6
|
+
|
|
7
|
+
This library is dependency free and designed to work with tree shaking (dead
|
|
8
|
+
code removal) for minimal deployed code size.
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- 2D point / vector operations
|
|
13
|
+
- Type-safe matrix operations
|
|
14
|
+
- multiplication
|
|
15
|
+
- inversion (up to size 4x4)
|
|
16
|
+
- Polynomial root finding (1st, 2nd, 3rd, and 6th order)
|
|
17
|
+
- Various shapes
|
|
18
|
+
- Axis-Aligned Bounding Boxes
|
|
19
|
+
- Rectangles
|
|
20
|
+
- Circles
|
|
21
|
+
- Lines (line segments)
|
|
22
|
+
- Quadratic Béziers
|
|
23
|
+
- Cubic Béziers
|
|
24
|
+
- Shape overlap detection
|
|
25
|
+
- Shape intersection
|
|
26
|
+
- Least squares curve fitting with optional fixed endpoints and direction
|
|
27
|
+
|
|
28
|
+
## Installing
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
npm install --save curve-ops
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Usage
|
|
35
|
+
|
|
36
|
+
TODO
|
|
37
|
+
|
|
38
|
+
## References
|
|
39
|
+
|
|
40
|
+
Many of the Bézier capabilities in this library are based on the following
|
|
41
|
+
sources:
|
|
42
|
+
|
|
43
|
+
- <https://pomax.github.io/bezierinfo/>
|
|
44
|
+
- <https://raphlinus.github.io/>
|
|
45
|
+
- <https://raphlinus.github.io/curves/2018/12/28/bezier-arclength.html>
|
|
46
|
+
- <https://raphlinus.github.io/curves/2021/03/11/bezier-fitting.html>
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
interface Pt {
|
|
2
|
+
readonly x: number;
|
|
3
|
+
readonly y: number;
|
|
4
|
+
z?: never;
|
|
5
|
+
}
|
|
6
|
+
interface PtWithDist extends Pt {
|
|
7
|
+
readonly d: number;
|
|
8
|
+
}
|
|
9
|
+
declare function ptPolyline(points: Pt[]): PtWithDist[];
|
|
10
|
+
declare const PT0: {
|
|
11
|
+
readonly x: 0;
|
|
12
|
+
readonly y: 0;
|
|
13
|
+
};
|
|
14
|
+
declare const ptDot: (a: Pt, b: Pt) => number;
|
|
15
|
+
declare const ptCross: (a: Pt, b: Pt) => number;
|
|
16
|
+
declare const ptLen2: ({ x, y }: Pt) => number;
|
|
17
|
+
declare const ptLen: ({ x, y }: Pt) => number;
|
|
18
|
+
declare const ptDist2: (a: Pt, b: Pt) => number;
|
|
19
|
+
declare const ptDist: (a: Pt, b: Pt) => number;
|
|
20
|
+
declare const ptNorm: (pt: Pt) => {
|
|
21
|
+
x: number;
|
|
22
|
+
y: number;
|
|
23
|
+
};
|
|
24
|
+
declare const ptRot90: ({ x, y }: Pt) => {
|
|
25
|
+
x: number;
|
|
26
|
+
y: number;
|
|
27
|
+
};
|
|
28
|
+
declare const ptAdd: (a: Pt, b: Pt) => {
|
|
29
|
+
x: number;
|
|
30
|
+
y: number;
|
|
31
|
+
};
|
|
32
|
+
declare const ptMul: (pt: Pt, m: number) => {
|
|
33
|
+
x: number;
|
|
34
|
+
y: number;
|
|
35
|
+
};
|
|
36
|
+
declare const ptMad: (a: Pt, m: number, b: Pt) => {
|
|
37
|
+
x: number;
|
|
38
|
+
y: number;
|
|
39
|
+
};
|
|
40
|
+
declare const ptSub: (a: Pt, b: Pt) => {
|
|
41
|
+
x: number;
|
|
42
|
+
y: number;
|
|
43
|
+
};
|
|
44
|
+
declare const ptLerp: (a: Pt, b: Pt, t: number) => {
|
|
45
|
+
x: number;
|
|
46
|
+
y: number;
|
|
47
|
+
};
|
|
48
|
+
declare const ptMid: (a: Pt, b: Pt) => {
|
|
49
|
+
x: number;
|
|
50
|
+
y: number;
|
|
51
|
+
};
|
|
52
|
+
declare const ptTransform: (mxx: number, mxy: number, dx: number, myx: number, myy: number, dy: number) => (pt: Pt) => {
|
|
53
|
+
x: number;
|
|
54
|
+
y: number;
|
|
55
|
+
};
|
|
56
|
+
declare const ptSVG: (pt: Pt, precision?: number) => string;
|
|
57
|
+
|
|
58
|
+
interface AxisAlignedBox {
|
|
59
|
+
readonly l: Pt;
|
|
60
|
+
readonly h: Pt;
|
|
61
|
+
}
|
|
62
|
+
declare function aaBoxFromXY(x: number[], y: number[]): AxisAlignedBox;
|
|
63
|
+
declare const aaBoxMidpoint: ({ l, h }: AxisAlignedBox) => {
|
|
64
|
+
x: number;
|
|
65
|
+
y: number;
|
|
66
|
+
};
|
|
67
|
+
declare const aaBoxArea: ({ l, h }: AxisAlignedBox) => number;
|
|
68
|
+
declare const aaBoxSVG: ({ l, h }: AxisAlignedBox, precision?: number | undefined) => string;
|
|
69
|
+
|
|
70
|
+
interface Circle {
|
|
71
|
+
readonly c: Pt;
|
|
72
|
+
readonly r: number;
|
|
73
|
+
}
|
|
74
|
+
declare const circleArea: ({ r }: Circle) => number;
|
|
75
|
+
declare const circleCircumference: ({ r }: Circle) => number;
|
|
76
|
+
declare const circleBounds: ({ c, r }: Circle) => AxisAlignedBox;
|
|
77
|
+
declare const circleSVG: ({ c, r }: Circle, precision?: number | undefined) => string;
|
|
78
|
+
|
|
79
|
+
interface Line {
|
|
80
|
+
readonly p0: Pt;
|
|
81
|
+
readonly p1: Pt;
|
|
82
|
+
}
|
|
83
|
+
declare const lineFromPts: (p0: Pt, p1: Pt) => Line;
|
|
84
|
+
declare const lineAt: ({ p0, p1 }: Line, t: number) => {
|
|
85
|
+
x: number;
|
|
86
|
+
y: number;
|
|
87
|
+
};
|
|
88
|
+
declare const lineDerivative: ({ p0, p1 }: Line) => {
|
|
89
|
+
x: number;
|
|
90
|
+
y: number;
|
|
91
|
+
};
|
|
92
|
+
declare const lineMidpoint: ({ p0, p1 }: Line) => {
|
|
93
|
+
x: number;
|
|
94
|
+
y: number;
|
|
95
|
+
};
|
|
96
|
+
declare const lineNormal: ({ p0, p1 }: Line) => {
|
|
97
|
+
x: number;
|
|
98
|
+
y: number;
|
|
99
|
+
};
|
|
100
|
+
declare const lineTranslate: ({ p0, p1 }: Line, shift: Pt) => Line;
|
|
101
|
+
declare const lineLength: ({ p0, p1 }: Line) => number;
|
|
102
|
+
declare const lineSVG: ({ p0, p1 }: Line, precision?: number | undefined, prefix?: string, mode?: string) => string;
|
|
103
|
+
|
|
104
|
+
interface QuadraticBezier {
|
|
105
|
+
readonly p0: Pt;
|
|
106
|
+
readonly c1: Pt;
|
|
107
|
+
readonly p2: Pt;
|
|
108
|
+
}
|
|
109
|
+
declare const bezier2FromPts: (p0: Pt, c1: Pt, p2: Pt) => QuadraticBezier;
|
|
110
|
+
declare const bezier2FromLine: ({ p0, p1 }: Line) => QuadraticBezier;
|
|
111
|
+
declare function bezier2At({ p0, c1, p2 }: QuadraticBezier, t: number): Pt;
|
|
112
|
+
declare function bezier2XAt({ p0, c1, p2 }: QuadraticBezier, t: number): number;
|
|
113
|
+
declare function bezier2YAt({ p0, c1, p2 }: QuadraticBezier, t: number): number;
|
|
114
|
+
declare const bezier2Derivative: ({ p0, c1, p2 }: QuadraticBezier) => Line;
|
|
115
|
+
declare const bezier2Translate: ({ p0, c1, p2 }: QuadraticBezier, shift: Pt) => QuadraticBezier;
|
|
116
|
+
declare function bezier2LengthEstimate(curve: QuadraticBezier, maxError?: number, recursionLimit?: number): LengthEstimate$1;
|
|
117
|
+
declare function bezier2Bisect({ p0, c1, p2 }: QuadraticBezier, t?: number): [QuadraticBezier, QuadraticBezier];
|
|
118
|
+
declare function bezier2Split({ p0, c1, p2 }: QuadraticBezier, splits: number[], minRange?: number): QuadraticBezier[];
|
|
119
|
+
declare const bezier2SVG: ({ p0, c1, p2 }: QuadraticBezier, precision?: number | undefined, prefix?: string, mode?: string) => string;
|
|
120
|
+
interface LengthEstimate$1 {
|
|
121
|
+
best: number;
|
|
122
|
+
maxError: number;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
interface CubicBezier {
|
|
126
|
+
readonly p0: Pt;
|
|
127
|
+
readonly c1: Pt;
|
|
128
|
+
readonly c2: Pt;
|
|
129
|
+
readonly p3: Pt;
|
|
130
|
+
}
|
|
131
|
+
declare const bezier3FromPts: (p0: Pt, c1: Pt, c2: Pt, p3: Pt) => CubicBezier;
|
|
132
|
+
declare const bezier3FromBezier2: ({ p0, c1, p2, }: QuadraticBezier) => CubicBezier;
|
|
133
|
+
declare const bezier3FromLine: ({ p0, p1 }: Line) => CubicBezier;
|
|
134
|
+
declare function bezier3At({ p0, c1, c2, p3 }: CubicBezier, t: number): Pt;
|
|
135
|
+
declare function bezier3XAt({ p0, c1, c2, p3 }: CubicBezier, t: number): number;
|
|
136
|
+
declare function bezier3YAt({ p0, c1, c2, p3 }: CubicBezier, t: number): number;
|
|
137
|
+
declare const bezier3Derivative: ({ p0, c1, c2, p3, }: CubicBezier) => QuadraticBezier;
|
|
138
|
+
declare const bezier3TangentAt: (curve: CubicBezier, t: number) => Pt;
|
|
139
|
+
declare const bezier3NormalAt: (curve: CubicBezier, t: number) => Pt;
|
|
140
|
+
declare const bezier3Translate: ({ p0, c1, c2, p3 }: CubicBezier, shift: Pt) => CubicBezier;
|
|
141
|
+
declare function bezier3TsAtXEq({ p0, c1, c2, p3 }: CubicBezier, x: number): number[];
|
|
142
|
+
declare function bezier3TsAtYEq({ p0, c1, c2, p3 }: CubicBezier, x: number): number[];
|
|
143
|
+
declare function bezier3XTurningPointTs({ p0, c1, c2, p3 }: CubicBezier): number[];
|
|
144
|
+
declare function bezier3YTurningPointTs({ p0, c1, c2, p3 }: CubicBezier): number[];
|
|
145
|
+
declare const bezier3Bounds: (curve: CubicBezier) => AxisAlignedBox;
|
|
146
|
+
declare function bezier3LengthEstimate(curve: CubicBezier, maxError?: number, recursionLimit?: number): LengthEstimate;
|
|
147
|
+
declare function bezier3Bisect(curve: CubicBezier, t?: number): [CubicBezier, CubicBezier];
|
|
148
|
+
declare function bezier3Split({ p0, c1, c2, p3 }: CubicBezier, splits: number[], minRange?: number): CubicBezier[];
|
|
149
|
+
declare const bezier3SVG: (curve: CubicBezier, precision?: number | undefined, prefix?: string, mode?: string) => string;
|
|
150
|
+
interface LengthEstimate {
|
|
151
|
+
best: number;
|
|
152
|
+
maxError: number;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
interface Rectangle {
|
|
156
|
+
readonly c: Pt;
|
|
157
|
+
readonly d: Pt;
|
|
158
|
+
readonly aspect: number;
|
|
159
|
+
}
|
|
160
|
+
declare function rectFromLine(line: Line, width: number): Rectangle;
|
|
161
|
+
declare const rectFromAABox: (box: AxisAlignedBox) => Rectangle;
|
|
162
|
+
declare const rectArea: ({ d, aspect }: Rectangle) => number;
|
|
163
|
+
declare function rectBounds({ c, d, aspect }: Rectangle): AxisAlignedBox;
|
|
164
|
+
declare function rectSVG({ c, d, aspect }: Rectangle, precision?: number | undefined): string;
|
|
165
|
+
|
|
166
|
+
declare const isOverlapAABoxCircle: (aaBox: AxisAlignedBox, { c, r }: Circle) => boolean;
|
|
167
|
+
declare function intersectBezier3Line({ p0, c1, c2, p3 }: CubicBezier, line: Line): {
|
|
168
|
+
t1: number;
|
|
169
|
+
t2: number;
|
|
170
|
+
}[];
|
|
171
|
+
declare function intersectBezier3Rect({ p0, c1, c2, p3 }: CubicBezier, { c, d, aspect }: Rectangle): {
|
|
172
|
+
t1: number;
|
|
173
|
+
d1: Sign;
|
|
174
|
+
}[];
|
|
175
|
+
declare const intersectBezier3Circle: (curve: CubicBezier, circle: Circle, maxError?: number | undefined) => {
|
|
176
|
+
t1: number;
|
|
177
|
+
d1: Sign;
|
|
178
|
+
}[];
|
|
179
|
+
declare function intersectBezier3CircleFn(curve: CubicBezier): (center: Pt, rad2: number, maxError?: number | undefined) => {
|
|
180
|
+
t1: number;
|
|
181
|
+
d1: Sign;
|
|
182
|
+
}[];
|
|
183
|
+
declare const intersectNBezier3Circle: (curve: CubicBezier, circle: Circle, maxError?: number | undefined) => {
|
|
184
|
+
t1: number;
|
|
185
|
+
d1: Sign;
|
|
186
|
+
}[];
|
|
187
|
+
declare function intersectNBezier3CircleFn(curve: CubicBezier): (center: Pt, rad2: number, maxError?: number | undefined) => {
|
|
188
|
+
t1: number;
|
|
189
|
+
d1: Sign;
|
|
190
|
+
}[];
|
|
191
|
+
type Sign = -1 | 0 | 1;
|
|
192
|
+
|
|
193
|
+
declare function leastSquaresFitQuadratic(points: PtWithDist[]): QuadraticBezier | null;
|
|
194
|
+
declare function leastSquaresFitCubic(points: PtWithDist[]): CubicBezier | null;
|
|
195
|
+
declare function leastSquaresFitCubicFixEnds(points: PtWithDist[], prevControl?: Pt | null): CubicBezier | null;
|
|
196
|
+
|
|
197
|
+
interface Matrix<M extends number = number, N extends number = number> {
|
|
198
|
+
readonly v: ReadonlyArray<number>;
|
|
199
|
+
readonly m: M;
|
|
200
|
+
readonly n: N;
|
|
201
|
+
}
|
|
202
|
+
declare const matFrom: <const V extends number[][]>(v: V) => Matrix<V["length"], V[number]["length"]>;
|
|
203
|
+
declare const matZero: <M extends number, N extends number>(m: M, n: N) => Matrix<M, N>;
|
|
204
|
+
declare const matDiag: <const D extends number[]>(...diag: D) => Matrix<D["length"], D["length"]>;
|
|
205
|
+
declare const matIdent: <S extends number>(s: S) => Matrix<S, S>;
|
|
206
|
+
declare function matPrint(mat: Matrix | null, precision?: number, width?: number): string;
|
|
207
|
+
declare function matToPtArray<N extends number>({ v, m, }: Matrix<N, 2>): SizedArray<Pt, N>;
|
|
208
|
+
declare function ptArrayToMat<const T extends Pt[]>(pts: T): Matrix<T['length'], 2>;
|
|
209
|
+
declare function arrayToMat<Dim extends number>(values: number[], dim: Dim): Matrix<number, Dim>;
|
|
210
|
+
declare function array2DToMat<const V extends number[][]>(values: V): Matrix<V['length'], V[number]['length']>;
|
|
211
|
+
declare const fnToMat: <const I extends unknown[], const V extends number[]>(values: I, fn: (x: I[number]) => V) => Matrix<I["length"], V["length"]>;
|
|
212
|
+
declare function matReshape<Dim extends number>({ v, m, n }: Matrix, newN: Dim): Matrix<number, Dim>;
|
|
213
|
+
declare const matScale: <M extends number, N extends number>({ v, m, n }: Matrix<M, N>, s: number) => Matrix<M, N>;
|
|
214
|
+
declare function matMul<M extends number, N extends number, S1 extends number, S2 extends S1 = S1>(a: Matrix<M, S1>, b: Matrix<S2, N>): Matrix<M, N>;
|
|
215
|
+
declare function matMulATransposeB<M extends number, N extends number, S1 extends number, S2 extends S1 = S1>(aT: Matrix<S1, M>, b: Matrix<S2, N>): Matrix<M, N>;
|
|
216
|
+
declare function matInv<N extends number>(mat: Matrix<N, NoInfer<N>>): Matrix<N, N> | null;
|
|
217
|
+
declare function mat1Inv({ v: [v00] }: Matrix<1, 1>): Matrix<1, 1> | null;
|
|
218
|
+
declare function mat2Inv({ v: [v00, v01, v10, v11], }: Matrix<2, 2>): Matrix<2, 2> | null;
|
|
219
|
+
declare function mat3Inv({ v: [v00, v01, v02, v10, v11, v12, v20, v21, v22], }: Matrix<3, 3>): Matrix<3, 3> | null;
|
|
220
|
+
declare function mat4Inv({ v: [v00, v01, v02, v03, v10, v11, v12, v13, v20, v21, v22, v23, v30, v31, v32, v33,], }: Matrix<4, 4>): Matrix<4, 4> | null;
|
|
221
|
+
type SizedArray<T, N extends number> = N extends 0 ? [] : N extends 1 ? [T] : N extends 2 ? [T, T] : N extends 3 ? [T, T, T] : N extends 4 ? [T, T, T, T] : T[];
|
|
222
|
+
|
|
223
|
+
interface NormalisedCubicBezier extends CubicBezier {
|
|
224
|
+
readonly p0: {
|
|
225
|
+
readonly x: 0;
|
|
226
|
+
readonly y: 0;
|
|
227
|
+
};
|
|
228
|
+
readonly p3: {
|
|
229
|
+
readonly x: number;
|
|
230
|
+
readonly y: 0;
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
declare function bezier3Normalise({ p0, c1, c2, p3 }: CubicBezier): {
|
|
234
|
+
scale2: number;
|
|
235
|
+
curve: NormalisedCubicBezier;
|
|
236
|
+
fn: (pt: Pt) => Pt;
|
|
237
|
+
};
|
|
238
|
+
declare function nBezier3At({ c1, c2, p3 }: NormalisedCubicBezier, t: number): Pt;
|
|
239
|
+
declare function nBezier3XAt({ c1, c2, p3 }: NormalisedCubicBezier, t: number): number;
|
|
240
|
+
declare function nBezier3YAt({ c1, c2 }: NormalisedCubicBezier, t: number): number;
|
|
241
|
+
declare const nBezier3Derivative: ({ c1, c2, p3, }: NormalisedCubicBezier) => QuadraticBezier;
|
|
242
|
+
declare function nBezier3Curvature(curve: NormalisedCubicBezier): (t: number) => number;
|
|
243
|
+
declare function nBezier3InflectionTs({ c1, c2, p3 }: NormalisedCubicBezier): number[];
|
|
244
|
+
declare function nBezier3Area({ c1, c2, p3 }: NormalisedCubicBezier): number;
|
|
245
|
+
declare function nBezier3Moment({ c1, c2, p3 }: NormalisedCubicBezier): number;
|
|
246
|
+
|
|
247
|
+
declare function solveLinear(f1: number, f0: number): number[];
|
|
248
|
+
declare function solveQuadratic(f2: number, f1: number, f0: number): number[];
|
|
249
|
+
declare function solveCubic(f3: number, f2: number, f1: number, f0: number): number[];
|
|
250
|
+
declare function solveO6(f6: number, f5: number, f4: number, f3: number, f2: number, f1: number, f0: number, { min, max, maxError }?: {
|
|
251
|
+
min?: number | undefined;
|
|
252
|
+
max?: number | undefined;
|
|
253
|
+
maxError?: number | undefined;
|
|
254
|
+
}): [number, 1 | -1][];
|
|
255
|
+
|
|
256
|
+
declare class CurveDrawer {
|
|
257
|
+
private readonly onBegin;
|
|
258
|
+
private readonly onSegment;
|
|
259
|
+
private readonly onLive;
|
|
260
|
+
private readonly onDone;
|
|
261
|
+
private readonly onCancel;
|
|
262
|
+
private readonly minStep;
|
|
263
|
+
private readonly maxN;
|
|
264
|
+
private _state;
|
|
265
|
+
private readonly _minError;
|
|
266
|
+
private readonly _maxError;
|
|
267
|
+
constructor(onBegin: (pt: Pt) => void, onSegment: (curve: CubicBezier, points: number) => void, onLive: (curve: CubicBezier) => void, onDone: () => void, onCancel: () => void, minStep: number, maxN: number, minError: number, maxError: number);
|
|
268
|
+
_fit(points: PtWithDist[], prevControl: Pt | null): Fit;
|
|
269
|
+
begin: (pt: Pt) => void;
|
|
270
|
+
draw: (pt: Pt, done?: boolean) => void;
|
|
271
|
+
cancel: () => void;
|
|
272
|
+
}
|
|
273
|
+
interface Fit {
|
|
274
|
+
readonly n: number;
|
|
275
|
+
readonly c: CubicBezier;
|
|
276
|
+
readonly d: number;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export { CurveDrawer, PT0, aaBoxArea, aaBoxFromXY, aaBoxMidpoint, aaBoxSVG, array2DToMat, arrayToMat, bezier2At, bezier2Bisect, bezier2Derivative, bezier2FromLine, bezier2FromPts, bezier2LengthEstimate, bezier2SVG, bezier2Split, bezier2Translate, bezier2XAt, bezier2YAt, bezier3At, bezier3Bisect, bezier3Bounds, bezier3Derivative, bezier3FromBezier2, bezier3FromLine, bezier3FromPts, bezier3LengthEstimate, bezier3NormalAt, bezier3Normalise, bezier3SVG, bezier3Split, bezier3TangentAt, bezier3Translate, bezier3TsAtXEq, bezier3TsAtYEq, bezier3XAt, bezier3XTurningPointTs, bezier3YAt, bezier3YTurningPointTs, circleArea, circleBounds, circleCircumference, circleSVG, fnToMat, intersectBezier3Circle, intersectBezier3CircleFn, intersectBezier3Line, intersectBezier3Rect, intersectNBezier3Circle, intersectNBezier3CircleFn, isOverlapAABoxCircle, leastSquaresFitCubic, leastSquaresFitCubicFixEnds, leastSquaresFitQuadratic, lineAt, lineDerivative, lineFromPts, lineLength, lineMidpoint, lineNormal, lineSVG, lineTranslate, mat1Inv, mat2Inv, mat3Inv, mat4Inv, matDiag, matFrom, matIdent, matInv, matMul, matMulATransposeB, matPrint, matReshape, matScale, matToPtArray, matZero, nBezier3Area, nBezier3At, nBezier3Curvature, nBezier3Derivative, nBezier3InflectionTs, nBezier3Moment, nBezier3XAt, nBezier3YAt, ptAdd, ptArrayToMat, ptCross, ptDist, ptDist2, ptDot, ptLen, ptLen2, ptLerp, ptMad, ptMid, ptMul, ptNorm, ptPolyline, ptRot90, ptSVG, ptSub, ptTransform, rectArea, rectBounds, rectFromAABox, rectFromLine, rectSVG, solveCubic, solveLinear, solveO6, solveQuadratic };
|
|
280
|
+
export type { AxisAlignedBox, Circle, CubicBezier, Line, Matrix, NormalisedCubicBezier, Pt, PtWithDist, QuadraticBezier, Rectangle };
|
package/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function t(t){if(!t.length)return[];let n=0,c=t[0];const r=[{...c,d:0}];for(let o=1;o<t.length;++o){const s=t[o];n+=u(c,s),r.push({...s,d:n}),c=s}return r}const n={x:0,y:0},c=(t,n)=>t.x*n.x+t.y*n.y,r=(t,n)=>t.x*n.y-t.y*n.x,o=({x:t,y:n})=>t*t+n*n,s=({x:t,y:n})=>Math.hypot(t,n),e=(t,n)=>(t.x-n.x)*(t.x-n.x)+(t.y-n.y)*(t.y-n.y),u=(t,n)=>Math.hypot(t.x-n.x,t.y-n.y),i=t=>l(t,1/s(t)),p=({x:t,y:n})=>({x:-n,y:t}),f=(t,n)=>({x:t.x+n.x,y:t.y+n.y}),l=(t,n)=>({x:t.x*n,y:t.y*n}),a=(t,n,c)=>({x:t.x*n+c.x,y:t.y*n+c.y}),h=(t,n)=>({x:t.x-n.x,y:t.y-n.y}),x=(t,n,c)=>({x:t.x+(n.x-t.x)*c,y:t.y+(n.y-t.y)*c}),m=(t,n)=>({x:.5*(t.x+n.x),y:.5*(t.y+n.y)}),M=(t,n,c,r,o,s)=>e=>({x:e.x*t+e.y*n+c,y:e.x*r+e.y*o+s}),$=(t,n=6)=>`${t.x.toFixed(n)} ${t.y.toFixed(n)}`;function v(t,n){const c=Math.min(...t),r=Math.max(...t);return{l:{x:c,y:Math.min(...n)},h:{x:r,y:Math.max(...n)}}}const d=({l:t,h:n})=>m(t,n),y=({l:t,h:n})=>(n.x-t.x)*(n.y-t.y),w=({l:t,h:n},c)=>`M${$(t,c)}H${n.x}V${n.y}H${t.x}Z`,E=({r:t})=>Math.PI*t*t,b=({r:t})=>2*Math.PI*t,g=({c:t,r:n})=>({l:{x:t.x-n,y:t.y-n},h:{x:t.x+n,y:t.y+n}}),N=({c:t,r:n},c)=>`M${$({x:t.x,y:t.y-n},c)}a${n} ${n} 0 0 0 0 ${2*n}a${n} ${n} 0 0 0 0 ${2*-n}Z`,_=(t,n,c)=>({p0:t,c1:n,p2:c}),A=({p0:t,p1:n})=>({p0:t,c1:m(t,n),p2:n});function C({p0:t,c1:n,p2:c},r){const o=1-r;return a(a(t,o,l(n,2*r)),o,l(c,r*r))}function L({p0:t,c1:n,p2:c},r){const o=1-r;return t.x*o*o+(2*n.x*o+c.x*r)*r}function Z({p0:t,c1:n,p2:c},r){const o=1-r;return t.y*o*o+(2*n.y*o+c.y*r)*r}const z=({p0:t,c1:n,p2:c})=>({p0:h(n,t),p1:h(c,n)}),H=({p0:t,c1:n,p2:c},r)=>({p0:f(t,r),c1:f(n,r),p2:f(c,r)});function S(t,n=Number.POSITIVE_INFINITY,c=10){const r=u(t.p2,t.p0),o=u(t.p0,t.c1)+u(t.c1,t.p2),s=2/3*(o-r);if(s>n&&c>0){const[r,o]=q(t),s=c-1,e=S(r,.5*n,s),u=S(o,n-e.maxError,s);return{best:e.best+u.best,maxError:e.maxError+u.maxError}}return{best:(2*r+o)*(1/3),maxError:s}}function q({p0:t,c1:n,p2:c},r=.5){const o=x(t,n,r),s=x(n,c,r),e=x(o,s,r);return[{p0:t,c1:o,p2:e},{p0:e,c1:s,p2:c}]}function B({p0:t,c1:n,p2:c},r,o=1e-6){let s=t,e=n;const u=c;let i=0;const p=[];for(const t of r.filter(t=>t>0&&t<1).sort()){if(t<=i+o)continue;const n=(t-i)/(1-i),c=x(s,e,n),r=x(e,u,n),f=x(c,r,n);p.push({p0:s,c1:c,p2:f}),s=f,e=r,i=t}return p.push({p0:s,c1:e,p2:u}),p}const D=({p0:t,c1:n,p2:c},r,o="M",s="Q")=>`${o}${$(t,r)}${s}${$(n,r)} ${$(c,r)}`;function Q(t,n){return t?[-n/t]:[]}function V(t,n,c){if(!t)return Q(n,c);const r=n*n-4*t*c,o=.5/t;if(r>0){const t=Math.sqrt(r);return[(-n+t)*o,(-n-t)*o]}return r?[]:[-n*o]}function j(t,n,c,r){if(!t)return V(n,c,r);const o=1/t,s=n*o*(1/3),e=c*o*(1/3)-s*s,u=e*e*e,i=.5*(s*(2*s*s-c*o)+r*o),p=i*i+u;if(p<0){const t=Math.sqrt(-u),n=Math.acos(Math.max(-1,Math.min(1,-i/t)))*(1/3),c=2*Math.cbrt(t);return[c*Math.cos(n-Math.PI*(2/3))-s,c*Math.cos(n)-s,c*Math.cos(n+Math.PI*(2/3))-s]}if(!p){const t=Math.cbrt(i);return[-2*t-s,t-s]}const f=Math.sqrt(p);return[Math.cbrt(f-i)-Math.cbrt(f+i)-s]}function k(t,n,c,r,o,s,e,{min:u=0,max:i=1,maxError:p=1e-4}={}){const f=6*t,l=5*n,a=4*c,h=3*r,x=2*o,m=s,M=5*f,$=4*l,v=3*a,d=2*h,y=x,w=j(4*M,3*$,2*v,d).filter(t=>t>u&&t<i).sort();function E(u){const i=u*u,p=i*u,w=i*i,E=p*i;return{y:e+s*u+o*i+r*p+c*w+n*E+t*(p*p),d:m+x*u+h*i+a*p+l*w+f*E,dd:y+d*u+v*i+$*p+M*w}}function b(t,n){const c=t.y<0,r=t.d<0;return c!==n.y<0||r!==c&&c===n.d<0||t.dd<0!==r&&r===n.dd<0}w.push(i);const g=[];function N(t,n,c,r){if(n-t>p){const o=.5*(t+n),s=E(o);b(c,s)&&N(t,o,c,s),b(s,r)&&N(o,n,s,r)}else c.y<0!=r.y<0&&g.push([t+(n-t)*c.y/(c.y-r.y),c.y<0?1:-1])}let _=u,A=E(u);for(const t of w){const n=E(t);b(A,n)&&N(_,t,A,n),_=t,A=n}return g}const F=(t,n,c,r)=>({p0:t,c1:n,c2:c,p3:r}),G=({p0:t,c1:n,p2:c})=>({p0:t,c1:x(t,n,2/3),c2:x(n,c,1/3),p3:c}),I=({p0:t,p1:n})=>({p0:t,c1:x(t,n,1/3),c2:x(t,n,2/3),p3:n});function J({p0:t,c1:n,c2:c,p3:r},o){const s=1-o;return a(a(t,s*s,a(n,3*o*s,l(c,3*o*o))),s,l(r,o*o*o))}function K({p0:t,c1:n,c2:c,p3:r},o){const s=1-o;return t.x*s*s*s+(3*s*(n.x*s+c.x*o)+r.x*o*o)*o}function O({p0:t,c1:n,c2:c,p3:r},o){const s=1-o;return t.y*s*s*s+(3*s*(n.y*s+c.y*o)+r.y*o*o)*o}const P=({p0:t,c1:n,c2:c,p3:r})=>({p0:l(h(n,t),3),c1:l(h(c,n),3),p2:l(h(r,c),3)}),R=(t,n)=>i(C(P(t),n)),T=(t,n)=>p(i(C(P(t),n))),U=({p0:t,c1:n,c2:c,p3:r},o)=>({p0:f(t,o),c1:f(n,o),c2:f(c,o),p3:f(r,o)});function W({p0:t,c1:n,c2:c,p3:r},o){return j(r.x-t.x+3*(n.x-c.x),3*(t.x+c.x)-6*n.x,3*(n.x-t.x),t.x-o)}function X({p0:t,c1:n,c2:c,p3:r},o){return j(r.y-t.y+3*(n.y-c.y),3*(t.y+c.y)-6*n.y,3*(n.y-t.y),t.y-o)}function Y({p0:t,c1:n,c2:c,p3:r}){return V(r.x-t.x+3*(n.x-c.x),2*(t.x+c.x)-4*n.x,n.x-t.x)}function tt({p0:t,c1:n,c2:c,p3:r}){return V(r.y-t.y+3*(n.y-c.y),2*(t.y+c.y)-4*n.y,n.y-t.y)}const nt=t=>v([t.p0.x,t.p3.x,...Y(t).filter(t=>t>0&&t<1).map(K.bind(null,t))],[t.p0.y,t.p3.y,...tt(t).filter(t=>t>0&&t<1).map(O.bind(null,t))]);function ct(t,n=Number.POSITIVE_INFINITY,c=10){const r=h(t.c1,t.p0),e=h(t.c2,t.c1),i=h(t.p3,t.c2),p=u(t.p0,t.p3),x=s(r)+s(e)+s(i)-p,m=h(e,r),M=h(i,e),$=a(f(r,i),.5,e),v=f(M,m),d=h(M,m);let y=0;for(const[t,n]of et){const c=a(d,n*n*.5,$);y+=t*(o(a(d,n,v))/o(a(v,n,c))+o(a(d,-n,v))/o(a(v,-n,c)))}y*=y*y;let w=et,E=Math.min(25e-7*y,.03)*x;if(E>n&&(w=ut,E=Math.min(y*y*15e-12,.009)*x,E>n&&(w=it,E=Math.min(y*y*y*35e-17,.0035)*x,E>n&&c>0))){const[r,o]=rt(t),s=c-1,e=ct(r,.5*n,s),u=ct(o,n-e.maxError,s);return{best:e.best+u.best,maxError:e.maxError+u.maxError}}let b=0;for(const[t,n]of w){const c=a(d,n*n*.5,$),r=l(v,n);b+=t*(s(f(c,r))+u(c,r))}return{best:.75*b,maxError:E}}function rt(t,n=.5){const c=x(t.p0,t.c1,n),r=x(t.c1,t.c2,n),o=x(t.c2,t.p3,n),s=x(c,r,n),e=x(r,o,n),u=x(s,e,n);return[{p0:t.p0,c1:c,c2:s,p3:u},{p0:u,c1:e,c2:o,p3:t.p3}]}function ot({p0:t,c1:n,c2:c,p3:r},o,s=1e-6){let e=t,u=n,i=c;const p=r;let f=0;const l=[];for(const t of o.filter(t=>t>0&&t<1).sort()){if(t<=f+s)continue;const n=(t-f)/(1-f),c=x(e,u,n),r=x(u,i,n),o=x(i,p,n),a=x(c,r,n),h=x(r,o,n),m=x(a,h,n);l.push({p0:e,c1:c,c2:a,p3:m}),e=m,u=h,i=o,f=t}return l.push({p0:e,c1:u,c2:i,p3:p}),l}const st=(t,n,c="M",r="C")=>`${c}${$(t.p0,n)}${r}${$(t.c1,n)} ${$(t.c2,n)} ${$(t.p3,n)}`,et=[[.362683783378362,.1834346424956498],[.3137066458778873,.525532409916329],[.2223810344533745,.7966664774136267],[.1012285362903763,.9602898564975363]],ut=[[.1894506104550685,.0950125098376374],[.1826034150449236,.2816035507792589],[.1691565193950025,.4580167776572274],[.1495959888165767,.6178762444026438],[.1246289712555339,.755404408355003],[.0951585116824928,.8656312023878318],[.0622535239386479,.9445750230732326],[.0271524594117541,.9894009349916499]],it=[[.1279381953467522,.0640568928626056],[.1258374563468283,.1911188674736163],[.1216704729278034,.3150426796961634],[.1155056680537256,.4337935076260451],[.1074442701159656,.5454214713888396],[.0976186521041139,.6480936519369755],[.0861901615319533,.7401241915785544],[.0733464814110803,.820001985973903],[.0592985849154368,.8864155270044011],[.0442774388174198,.9382745520027328],[.0285313886289337,.9747285559713095],[.0123412297999872,.9951872199970213]],pt=(t,n)=>({p0:t,p1:n}),ft=({p0:t,p1:n},c)=>x(t,n,c),lt=({p0:t,p1:n})=>h(n,t),at=({p0:t,p1:n})=>m(t,n),ht=({p0:t,p1:n})=>i(p(h(n,t))),xt=({p0:t,p1:n},c)=>({p0:f(t,c),p1:f(n,c)}),mt=({p0:t,p1:n})=>u(n,t);function Mt({p0:t,p1:n}){const c=h(n,t),r=o(c);if(!r)return null;const s=l(c,1/r);return{scale2:r,fn:M(s.x,s.y,-t.x*s.x-t.y*s.y,-s.y,s.x,t.x*s.y-t.y*s.x)}}const $t=({p0:t,p1:n},c,r="M",o="L")=>`${r}${$(t,c)}${o}${$(n,c)}`;function vt({p0:t,c1:c,c2:r,p3:o}){const s=Mt({p0:t,p1:o})??Mt({p0:t,p1:c})??Mt({p0:t,p1:r});return s?{...s,curve:{p0:n,c1:s.fn(c),c2:s.fn(r),p3:{x:s.fn(o).x,y:0}}}:{scale2:1,curve:{p0:n,c1:n,c2:n,p3:n},fn:n=>h(n,t)}}function dt({c1:t,c2:n,p3:c},r){const o=1-r;return a(a(t,3*r*o,l(n,3*r*r)),o,l(c,r*r*r))}function yt({c1:t,c2:n,p3:c},r){const o=1-r;return(3*o*(t.x*o+n.x*r)+c.x*r*r)*r}function wt({c1:t,c2:n},c){const r=1-c;return 3*r*(t.y*r+n.y*c)*c}const Et=({c1:t,c2:n,p3:c})=>({p0:l(t,3),c1:l(h(n,t),3),p2:l(h(c,n),3)});function bt(t){const n=Et(t),c=z(n);return t=>{const o=C(n,t),e=ft(c,t),u=s(o);return r(o,e)/(u*u*u)}}function gt({c1:t,c2:n,p3:c}){const o=r(t,n);return V(3*o+(2*t.y-n.y)*c.x,-3*o-t.y*c.x,o)}function Nt({c1:t,c2:n,p3:c}){return.15*((c.x+n.x)*t.y+(2*c.x-t.x)*n.y)}function _t({c1:t,c2:n,p3:c}){const r=c.x,o=t.x,s=t.y,e=r-n.x,u=n.y;return 1/280*(+(34*s+50*u)*r*r+(15*(o*s-e*u)+9*o*u-33*s*e)*r+9*(s*e+o*u)*(e-o))}const At=(t,{c:n,r:c})=>Ct(t,n,c*c);function Ct({l:t,h:n},c,r){const o=Math.max(0,t.x-c.x,c.x-n.x),s=Math.max(0,t.y-c.y,c.y-n.y);return o*o+s*s<=r}function Lt({p0:t,c1:n,c2:c,p3:r},o){const s=Mt(o);if(!s)return[];const e={p0:s.fn(t),c1:s.fn(n),c2:s.fn(c),p3:s.fn(r)},u=X(e,0),i=[];for(const t of u)if(t>=0&&t<=1){const n=K(e,t);n>=0&&n<=1&&i.push({t1:t,t2:n})}return i}function Zt({p0:t,c1:n,c2:c,p3:r},{c:o,d:s,aspect:e}){const u=Mt({p0:o,p1:f(o,s)});if(!u)return[];const i={p0:u.fn(t),c1:u.fn(n),c2:u.fn(c),p3:u.fn(r)},p=P(i),l=.5*e,a=[];for(const t of X(i,-l)){const n=K(i,t);t>=0&&t<=1&&n>=-.5&&n<=.5&&a.push({t1:t,d1:Bt(-Z(p,t))})}for(const t of X(i,l)){const n=K(i,t);t>=0&&t<=1&&n>=-.5&&n<=.5&&a.push({t1:t,d1:Bt(Z(p,t))})}for(const t of W(i,-.5)){const n=O(i,t);t>=0&&t<=1&&n>=-l&&n<=l&&a.push({t1:t,d1:Bt(-L(p,t))})}for(const t of W(i,.5)){const n=O(i,t);t>=0&&t<=1&&n>=-l&&n<=l&&a.push({t1:t,d1:Bt(L(p,t))})}return a}const zt=(t,n,c)=>Ht(t)(n.c,n.r*n.r,c);function Ht(t){const n=vt(t),c=qt(n.curve);return(t,r,o)=>c(n.fn(t),r/n.scale2,o)}const St=(t,n,c)=>qt(t)(n.c,n.r*n.r,c);function qt(t){const n=nt(t),{c1:r,c2:s,p3:e}=t,u=9*o(r),i=18*c(r,s),p=6*c(r,e)+9*o(s),f=6*c(s,e),l=u-i+p-f+o(e),a=-4*u+3*i-2*p+f,h=6*u-3*i+p,x=-4*u+i;return(t,i,p)=>{if(!Ct(n,t,i))return[];const f=6*c(r,t),m=6*c(s,t);return k(l,a,h,x-f+m-2*c(e,t),u+2*f-m,-f,o(t)-i,{min:0,max:1,maxError:p}).map(([t,n])=>({t1:t,d1:n}))}}const Bt=t=>Math.sign(t),Dt=t=>({v:t.flat(),m:t.length,n:t[0]?.length??0}),Qt=(t,n)=>({v:new Array(t*n).fill(0),m:t,n}),Vt=(...t)=>{const n=t.length,c=new Array(n*n).fill(0);for(let r=0;r<n;++r)c[r*(n+1)]=t[r];return{v:c,m:n,n}},jt=t=>{const n=new Array(t*t).fill(0);for(let c=0;c<t;++c)n[c*(t+1)]=1;return{v:n,m:t,n:t}};function kt(t,n=3,c=n+5){if(!t)return"(null)";const{v:r,m:o,n:s}=t;let e=[];for(let t=0;t<o;++t){const o=[];for(let e=0;e<s;++e)o.push(r[t*s+e].toFixed(n).padStart(c," "));e.push(o.join(" "))}return`[ ${e.join("\n ")} ] (${o}x${s})`}function Ft({v:t,m:n}){const c=[];for(let r=0;r<n;++r)c.push({x:t[2*r],y:t[2*r+1]});return c}function Gt(t){const n=[];for(const c of t)n.push(c.x,c.y);return{v:n,m:t.length,n:2}}function It(t,n){if(t.length%n)throw new Error("invalid array length for matrix");return{v:t,m:t.length/n,n}}function Jt(t){const n=t.flat();if(n.length%t.length)throw new Error("inconsistent matrix size");return{v:n,m:t.length,n:n.length/t.length}}const Kt=(t,n)=>Jt(t.map(n));function Ot({v:t,m:n,n:c},r){const o=n*c;if(o%r)throw new Error("invalid matrix reshaping");return{v:t,m:o/r,n:r}}const Pt=({v:t,m:n,n:c},r)=>({v:t.map(t=>t*r),m:n,n:c});function Rt(t,n){const c=t.m,r=n.n,o=t.n;if(n.m!==o)throw new Error(`invalid matrix multiplication (${t.m} x ${t.n}) * (${n.m} x ${n.n})`);const s=[];for(let e=0;e<c;++e)for(let c=0;c<r;++c){let u=0;for(let s=0;s<o;++s)u+=t.v[e*o+s]*n.v[s*r+c];s.push(u)}return{v:s,m:c,n:r}}function Tt(t,n){const c=t.n,r=n.n,o=t.m;if(n.m!==o)throw new Error(`invalid matrix multiplication (${t.n} x ${t.m}) * (${n.m} x ${n.n})`);const s=[];for(let e=0;e<c;++e)for(let u=0;u<r;++u){let i=0;for(let s=0;s<o;++s)i+=t.v[s*c+e]*n.v[s*r+u];s.push(i)}return{v:s,m:c,n:r}}function Ut(t){const n=t.m;if(n!==t.n)throw new Error("matrix is not square");switch(n){case 1:return Wt(t);case 2:return Xt(t);case 3:return Yt(t);case 4:return tn(t);default:throw new Error("unsupported matrix size")}}function Wt({v:[t]}){return Math.abs(t)<1e-8?null:{v:[1/t],m:1,n:1}}function Xt({v:[t,n,c,r]}){const o=t*r-c*n;if(Math.abs(o)<1e-8)return null;const s=1/o;return{v:[r*s,-n*s,-c*s,t*s],m:2,n:2}}function Yt({v:[t,n,c,r,o,s,e,u,i]}){const p=i*o-s*u,f=s*e-i*r,l=u*r-o*e,a=t*p+n*f+c*l;if(Math.abs(a)<1e-8)return null;const h=1/a;return{v:[p*h,(c*u-i*n)*h,(s*n-c*o)*h,f*h,(i*t-c*e)*h,(c*r-s*t)*h,l*h,(n*e-u*t)*h,(o*t-n*r)*h],m:3,n:3}}function tn({v:[t,n,c,r,o,s,e,u,i,p,f,l,a,h,x,m]}){const M=t*s-n*o,$=t*e-c*o,v=t*u-r*o,d=n*e-c*s,y=n*u-r*s,w=c*u-r*e,E=i*h-p*a,b=i*x-f*a,g=i*m-l*a,N=p*x-f*h,_=p*m-l*h,A=f*m-l*x,C=M*A-$*_+v*N+d*g-y*b+w*E;if(Math.abs(C)<1e-8)return null;const L=1/C;return{v:[(s*A-e*_+u*N)*L,(c*_-n*A-r*N)*L,(h*w-x*y+m*d)*L,(f*y-p*w-l*d)*L,(e*g-o*A-u*b)*L,(t*A-c*g+r*b)*L,(x*v-a*w-m*$)*L,(i*w-f*v+l*$)*L,(o*_-s*g+u*E)*L,(n*g-t*_-r*E)*L,(a*y-h*v+m*M)*L,(p*v-i*y-l*M)*L,(s*b-o*N-e*E)*L,(t*N-n*b+c*E)*L,(h*$-a*d-x*M)*L,(i*d-p*$+f*M)*L],m:4,n:4}}function nn(t){if(!t.length)return null;const n=t[0],c=t[t.length-1];if(t.length>=3){const r=n.d,o=1/(c.d-r),s=Gt(t),e=Kt(t,({d:t})=>{const n=(t-r)*o;return[1,n,n*n]}),u=Yt(Tt(e,e));if(u){const t=Rt(on,Rt(u,Tt(e,s)));return _(...Ft(t))}}return A({p0:n,p1:c})}function cn(t){if(!t.length)return null;if(t.length>=4){const n=t[0],c=t[t.length-1],r=n.d,o=1/(c.d-r),s=Gt(t),e=Kt(t,({d:t})=>{const n=(t-r)*o,c=n*n;return[1,n,c,c*n]}),u=tn(Tt(e,e));if(u){const t=Rt(en,Rt(u,Tt(e,s)));return F(...Ft(t))}}const n=nn(t);return n?G(n):null}function rn(t,n=null){if(0===t.length)return null;const r=t[0],u=t[t.length-1],p=h(u,r),x=r.d,m=1/(u.d-x);if(t.length>=4){if(n&&e(r,n)){const s=i(h(r,n)),e=o(p)?c(s,i(p))**2:1,l=[],M=[];for(let n=1;n<t.length-1;++n){const c=t[n],o=(c.d-x)*m,s=j(.5*e-.5,1.5-1.5*e,e,-o).filter(t=>t>=0&&t<=1)[0]??o,u=s*s,i=u*s;l.push(a(p,-i,h(c,r))),M.push([s-u,s-i])}const $=Gt(l),v=Kt(M,([t,n])=>{const c=n-t;return[s.x*(t-c),c,0,s.y*(t-c),0,c]}),d=Ot($,1),y=Ot(v,3),w=Yt(Tt(y,y));if(w){const t=Pt(Rt(w,Tt(y,d)),1/3),[n,c,o]=t.v;if(n>0)return{p0:r,c1:a(s,n,r),c2:f(r,{x:c,y:o}),p3:u}}}const s=[],l=[];for(let n=1;n<t.length-1;++n){const c=t[n],o=(c.d-x)*m,e=o*o,u=e*o;s.push(a(p,-u,h(c,r))),l.push([o-e,o-u])}const M=Gt(s),$=Jt(l),v=Xt(Tt($,$));if(v){const t=Rt(un,Rt(v,Tt($,M))),[n,c]=Ft(t);return{p0:r,c1:f(r,n),c2:f(r,c),p3:u}}}if(t.length>=3){if(n&&e(r,n)){const s=i(h(r,n)),e=o(p)?c(s,i(p))**2:1,f=[],l=[];for(let n=1;n<t.length-1;++n){const c=t[n],o=(c.d-x)*m,s=V(1-.5*e,.5*e,-o).filter(t=>t>=0&&t<=1)[0]??o,u=s*s;f.push(a(p,-u,h(c,r))),l.push(s-u)}const M=Gt(f),$=Kt(l,t=>[s.x*t,s.y*t]),v=Ot(M,1),d=Ot($,1),y=Wt(Tt(d,d));if(y){const t=Rt(sn,Rt(y,Tt(d,v))),[n]=t.v;if(n>0)return G({p0:r,c1:a(s,n,r),p2:u})}}const s=[],l=[];for(let n=1;n<t.length-1;++n){const c=t[n],o=(c.d-x)*m,e=o*o;s.push(a(p,-e,h(c,r))),l.push(o-e)}const M=Gt(s),$=It(l,1),v=Wt(Tt($,$));if(v){const t=Rt(sn,Rt(v,Tt($,M))),[n]=Ft(t);return G({p0:r,c1:f(r,n),p2:u})}}if(t.length>=2&&n&&e(r,n)){const t=h(u,r),o=s(u),e=i(h(r,n)),p=o?Math.max(c(e,l(t,1/o)),0):1;return G({p0:r,c1:a(e,p*o*(1/3),r),p2:u})}return I({p0:r,p1:u})}const on=/*@__PURE__*/Dt([[1,0,0],[1,.5,0],[1,1,1]]),sn=/*@__PURE__*/Dt([[.5]]),en=/*@__PURE__*/Dt([[1,0,0,0],[1,1/3,0,0],[1,2/3,1/3,0],[1,1,1,1]]),un=/*@__PURE__*/Dt([[1/3,1/3],[1/3,2/3]]);function pn(t,n){const c=lt(t);return{c:at(t),d:c,aspect:n/s(c)}}const fn=t=>({c:d(t),d:{x:0,y:t.h.y-t.l.y},aspect:(t.h.x-t.l.x)/(t.h.y-t.l.y)}),ln=({d:t,aspect:n})=>o(t)*n;function an({c:t,d:n,aspect:c}){const r=Math.abs(n.x),o=Math.abs(n.y),s=.5*(r+o*c),e=.5*(o+o*c);return{l:{x:t.x-s,y:t.y-e},h:{x:t.x+s,y:t.y+e}}}function hn({c:t,d:n,aspect:c},r){const o={x:.5*(n.x-n.y*c),y:.5*(n.y+n.x*c)},s={x:.5*(n.x+n.y*c),y:.5*(n.y-n.x*c)};return`M${$(f(t,o),r)}L${$(f(t,s),r)} ${$(h(t,o),r)} ${$(h(t,s),r)}Z`}class xn{onBegin;onSegment;onLive;onDone;onCancel;minStep;maxN;constructor(t,n,c,r,o,s,e,u,i){this.onBegin=t,this.onSegment=n,this.onLive=c,this.onDone=r,this.onCancel=o,this.minStep=s,this.maxN=e,this.t=u*u,this.o=i*i,this.u=void 0}i(t,n){if(!t.length)throw new Error("nothing to fit");const c=t[0],r=t[t.length-1],o=rn(t,n);if(!o||t.length<2)return{n:t.length,c:{p0:c,c1:c,c2:r,p3:r},d:Number.POSITIVE_INFINITY};const s=vt(o);let e=0;const u=r.d-c.d;let i=s.fn(c);for(let n=1;n<t.length;++n){const c=s.fn(t[n]);e+=(c.x-i.x)*(i.y+c.y)/2,i=c}const p=Math.sqrt(s.scale2),f=(e-Nt(s.curve))*p,l=u-ct(o,.01*p).best;return{n:t.length,c:o,d:f*f+l*l}}begin=t=>{const n={...t,d:0};this.u={p:[n],M:null,$:this.i([n],null)},this.onBegin(t)};draw=(t,n=!1)=>{const c=this.u;if(!c)return;const r=c.p,o=r[r.length-1],s=u(o,t);if(!n&&s<this.minStep)return;const e={...t,d:o.d+s};r.push(e);let i=this.i(r,c.M);(i.d<this.t||c.$.n<2||i.d<c.$.d)&&(c.$=i),(i.d>this.o||r.length>this.maxN)&&(this.onSegment(c.$.c,c.$.n),r.splice(0,c.$.n-1),c.M=c.$.c.c2,i=this.i(r,c.M),c.$=i),n?r.length>1&&(this.onSegment(i.c,i.n),this.onDone()):this.onLive(i.c)};cancel=()=>{this.u=void 0,this.onCancel()}}export{xn as CurveDrawer,n as PT0,y as aaBoxArea,v as aaBoxFromXY,d as aaBoxMidpoint,w as aaBoxSVG,Jt as array2DToMat,It as arrayToMat,C as bezier2At,q as bezier2Bisect,z as bezier2Derivative,A as bezier2FromLine,_ as bezier2FromPts,S as bezier2LengthEstimate,D as bezier2SVG,B as bezier2Split,H as bezier2Translate,L as bezier2XAt,Z as bezier2YAt,J as bezier3At,rt as bezier3Bisect,nt as bezier3Bounds,P as bezier3Derivative,G as bezier3FromBezier2,I as bezier3FromLine,F as bezier3FromPts,ct as bezier3LengthEstimate,T as bezier3NormalAt,vt as bezier3Normalise,st as bezier3SVG,ot as bezier3Split,R as bezier3TangentAt,U as bezier3Translate,W as bezier3TsAtXEq,X as bezier3TsAtYEq,K as bezier3XAt,Y as bezier3XTurningPointTs,O as bezier3YAt,tt as bezier3YTurningPointTs,E as circleArea,g as circleBounds,b as circleCircumference,N as circleSVG,Kt as fnToMat,zt as intersectBezier3Circle,Ht as intersectBezier3CircleFn,Lt as intersectBezier3Line,Zt as intersectBezier3Rect,St as intersectNBezier3Circle,qt as intersectNBezier3CircleFn,At as isOverlapAABoxCircle,cn as leastSquaresFitCubic,rn as leastSquaresFitCubicFixEnds,nn as leastSquaresFitQuadratic,ft as lineAt,lt as lineDerivative,pt as lineFromPts,mt as lineLength,at as lineMidpoint,ht as lineNormal,$t as lineSVG,xt as lineTranslate,Wt as mat1Inv,Xt as mat2Inv,Yt as mat3Inv,tn as mat4Inv,Vt as matDiag,Dt as matFrom,jt as matIdent,Ut as matInv,Rt as matMul,Tt as matMulATransposeB,kt as matPrint,Ot as matReshape,Pt as matScale,Ft as matToPtArray,Qt as matZero,Nt as nBezier3Area,dt as nBezier3At,bt as nBezier3Curvature,Et as nBezier3Derivative,gt as nBezier3InflectionTs,_t as nBezier3Moment,yt as nBezier3XAt,wt as nBezier3YAt,f as ptAdd,Gt as ptArrayToMat,r as ptCross,u as ptDist,e as ptDist2,c as ptDot,s as ptLen,o as ptLen2,x as ptLerp,a as ptMad,m as ptMid,l as ptMul,i as ptNorm,t as ptPolyline,p as ptRot90,$ as ptSVG,h as ptSub,M as ptTransform,ln as rectArea,an as rectBounds,fn as rectFromAABox,pn as rectFromLine,hn as rectSVG,j as solveCubic,Q as solveLinear,k as solveO6,V as solveQuadratic};
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "curve-ops",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "a collection of mathematical utilities for working with curves (primarily Bézier curves)",
|
|
5
|
+
"author": "David Evans",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"vector",
|
|
9
|
+
"matrix",
|
|
10
|
+
"root",
|
|
11
|
+
"curve",
|
|
12
|
+
"bezier",
|
|
13
|
+
"bézier",
|
|
14
|
+
"math",
|
|
15
|
+
"maths"
|
|
16
|
+
],
|
|
17
|
+
"type": "module",
|
|
18
|
+
"main": "./index.js",
|
|
19
|
+
"types": "./index.d.ts",
|
|
20
|
+
"sideEffects": false,
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/davidje13/curve-ops.git"
|
|
24
|
+
},
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/davidje13/curve-ops/issues"
|
|
27
|
+
},
|
|
28
|
+
"homepage": "https://github.com/davidje13/curve-ops#readme"
|
|
29
|
+
}
|