@emasoft/svg-matrix 1.1.0 → 1.2.0
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/bin/svg-matrix.js +7 -6
- package/bin/svgm.js +109 -40
- package/dist/svg-matrix.min.js +7 -7
- package/dist/svg-toolbox.min.js +148 -228
- package/dist/svgm.min.js +152 -232
- package/dist/version.json +5 -5
- package/package.json +1 -1
- package/scripts/postinstall.js +72 -41
- package/scripts/test-postinstall.js +18 -16
- package/scripts/version-sync.js +78 -60
- package/src/animation-optimization.js +190 -98
- package/src/animation-references.js +11 -3
- package/src/arc-length.js +23 -20
- package/src/bezier-analysis.js +9 -13
- package/src/bezier-intersections.js +18 -4
- package/src/browser-verify.js +35 -8
- package/src/clip-path-resolver.js +285 -114
- package/src/convert-path-data.js +20 -8
- package/src/css-specificity.js +33 -9
- package/src/douglas-peucker.js +272 -141
- package/src/geometry-to-path.js +79 -22
- package/src/gjk-collision.js +287 -126
- package/src/index.js +56 -21
- package/src/inkscape-support.js +122 -101
- package/src/logger.js +43 -27
- package/src/marker-resolver.js +201 -121
- package/src/mask-resolver.js +231 -98
- package/src/matrix.js +9 -5
- package/src/mesh-gradient.js +22 -14
- package/src/off-canvas-detection.js +53 -17
- package/src/path-optimization.js +356 -171
- package/src/path-simplification.js +671 -256
- package/src/pattern-resolver.js +1 -3
- package/src/polygon-clip.js +396 -78
- package/src/svg-boolean-ops.js +90 -23
- package/src/svg-collections.js +1546 -667
- package/src/svg-flatten.js +152 -38
- package/src/svg-matrix-lib.js +2 -2
- package/src/svg-parser.js +5 -1
- package/src/svg-rendering-context.js +3 -1
- package/src/svg-toolbox-lib.js +2 -2
- package/src/svg-toolbox.js +99 -457
- package/src/svg-validation-data.js +513 -345
- package/src/svg2-polyfills.js +156 -93
- package/src/svgm-lib.js +8 -4
- package/src/transform-optimization.js +168 -51
- package/src/transforms2d.js +73 -40
- package/src/transforms3d.js +34 -27
- package/src/use-symbol-resolver.js +175 -76
- package/src/vector.js +80 -44
- package/src/vendor/inkscape-hatch-polyfill.js +143 -108
- package/src/vendor/inkscape-hatch-polyfill.min.js +291 -1
- package/src/vendor/inkscape-mesh-polyfill.js +953 -766
- package/src/vendor/inkscape-mesh-polyfill.min.js +896 -1
- package/src/verification.js +3 -4
package/src/vector.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import Decimal from
|
|
1
|
+
import Decimal from "decimal.js";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Helper to convert any numeric input to Decimal.
|
|
@@ -7,9 +7,11 @@ import Decimal from 'decimal.js';
|
|
|
7
7
|
* @returns {Decimal} The Decimal representation
|
|
8
8
|
* @throws {Error} If x is null, undefined, or cannot be converted to Decimal
|
|
9
9
|
*/
|
|
10
|
-
const D = x => {
|
|
10
|
+
const D = (x) => {
|
|
11
11
|
if (x === null || x === undefined) {
|
|
12
|
-
throw new Error(
|
|
12
|
+
throw new Error(
|
|
13
|
+
`Cannot convert ${x === null ? "null" : "undefined"} to Decimal`,
|
|
14
|
+
);
|
|
13
15
|
}
|
|
14
16
|
if (x instanceof Decimal) return x;
|
|
15
17
|
try {
|
|
@@ -42,12 +44,15 @@ export class Vector {
|
|
|
42
44
|
* @throws {Error} If components is not an array, is empty, or contains invalid values
|
|
43
45
|
*/
|
|
44
46
|
constructor(components) {
|
|
45
|
-
if (!Array.isArray(components)) throw new Error(
|
|
46
|
-
if (components.length === 0)
|
|
47
|
+
if (!Array.isArray(components)) throw new Error("Vector requires array");
|
|
48
|
+
if (components.length === 0)
|
|
49
|
+
throw new Error("Vector requires at least one component");
|
|
47
50
|
try {
|
|
48
51
|
this.data = components.map((c, i) => {
|
|
49
52
|
if (c === null || c === undefined) {
|
|
50
|
-
throw new Error(
|
|
53
|
+
throw new Error(
|
|
54
|
+
`Vector component at index ${i} is ${c === null ? "null" : "undefined"}`,
|
|
55
|
+
);
|
|
51
56
|
}
|
|
52
57
|
return D(c);
|
|
53
58
|
});
|
|
@@ -65,7 +70,9 @@ export class Vector {
|
|
|
65
70
|
*/
|
|
66
71
|
static from(arr) {
|
|
67
72
|
if (arr === null || arr === undefined) {
|
|
68
|
-
throw new Error(
|
|
73
|
+
throw new Error(
|
|
74
|
+
`Vector.from: argument is ${arr === null ? "null" : "undefined"}`,
|
|
75
|
+
);
|
|
69
76
|
}
|
|
70
77
|
return new Vector(arr);
|
|
71
78
|
}
|
|
@@ -75,7 +82,7 @@ export class Vector {
|
|
|
75
82
|
* @returns {Vector} New Vector with copied values
|
|
76
83
|
*/
|
|
77
84
|
clone() {
|
|
78
|
-
return new Vector(this.data.map(v => new Decimal(v)));
|
|
85
|
+
return new Vector(this.data.map((v) => new Decimal(v)));
|
|
79
86
|
}
|
|
80
87
|
|
|
81
88
|
/**
|
|
@@ -93,7 +100,7 @@ export class Vector {
|
|
|
93
100
|
* @returns {number[]} Array of number values
|
|
94
101
|
*/
|
|
95
102
|
toNumberArray() {
|
|
96
|
-
return this.data.map(v => v.toNumber());
|
|
103
|
+
return this.data.map((v) => v.toNumber());
|
|
97
104
|
}
|
|
98
105
|
|
|
99
106
|
/**
|
|
@@ -102,7 +109,7 @@ export class Vector {
|
|
|
102
109
|
* @returns {string[]} Array of string values
|
|
103
110
|
*/
|
|
104
111
|
toStringArray() {
|
|
105
|
-
return this.data.map(v => v.toString());
|
|
112
|
+
return this.data.map((v) => v.toString());
|
|
106
113
|
}
|
|
107
114
|
|
|
108
115
|
/**
|
|
@@ -113,10 +120,12 @@ export class Vector {
|
|
|
113
120
|
*/
|
|
114
121
|
add(other) {
|
|
115
122
|
if (!other || !(other instanceof Vector)) {
|
|
116
|
-
throw new Error(
|
|
123
|
+
throw new Error("add: argument must be a Vector");
|
|
117
124
|
}
|
|
118
125
|
if (this.length !== other.length) {
|
|
119
|
-
throw new Error(
|
|
126
|
+
throw new Error(
|
|
127
|
+
`add: dimension mismatch (${this.length} vs ${other.length})`,
|
|
128
|
+
);
|
|
120
129
|
}
|
|
121
130
|
return new Vector(this.data.map((v, i) => v.plus(other.data[i])));
|
|
122
131
|
}
|
|
@@ -129,10 +138,12 @@ export class Vector {
|
|
|
129
138
|
*/
|
|
130
139
|
sub(other) {
|
|
131
140
|
if (!other || !(other instanceof Vector)) {
|
|
132
|
-
throw new Error(
|
|
141
|
+
throw new Error("sub: argument must be a Vector");
|
|
133
142
|
}
|
|
134
143
|
if (this.length !== other.length) {
|
|
135
|
-
throw new Error(
|
|
144
|
+
throw new Error(
|
|
145
|
+
`sub: dimension mismatch (${this.length} vs ${other.length})`,
|
|
146
|
+
);
|
|
136
147
|
}
|
|
137
148
|
return new Vector(this.data.map((v, i) => v.minus(other.data[i])));
|
|
138
149
|
}
|
|
@@ -145,7 +156,9 @@ export class Vector {
|
|
|
145
156
|
*/
|
|
146
157
|
scale(scalar) {
|
|
147
158
|
if (scalar === null || scalar === undefined) {
|
|
148
|
-
throw new Error(
|
|
159
|
+
throw new Error(
|
|
160
|
+
`scale: scalar is ${scalar === null ? "null" : "undefined"}`,
|
|
161
|
+
);
|
|
149
162
|
}
|
|
150
163
|
let s;
|
|
151
164
|
try {
|
|
@@ -153,7 +166,7 @@ export class Vector {
|
|
|
153
166
|
} catch (err) {
|
|
154
167
|
throw new Error(`scale: invalid scalar - ${err.message}`);
|
|
155
168
|
}
|
|
156
|
-
return new Vector(this.data.map(v => v.mul(s)));
|
|
169
|
+
return new Vector(this.data.map((v) => v.mul(s)));
|
|
157
170
|
}
|
|
158
171
|
|
|
159
172
|
/**
|
|
@@ -161,7 +174,7 @@ export class Vector {
|
|
|
161
174
|
* @returns {Vector} New Vector with negated components
|
|
162
175
|
*/
|
|
163
176
|
negate() {
|
|
164
|
-
return new Vector(this.data.map(v => v.negated()));
|
|
177
|
+
return new Vector(this.data.map((v) => v.negated()));
|
|
165
178
|
}
|
|
166
179
|
|
|
167
180
|
/**
|
|
@@ -172,12 +185,17 @@ export class Vector {
|
|
|
172
185
|
*/
|
|
173
186
|
dot(other) {
|
|
174
187
|
if (!other || !(other instanceof Vector)) {
|
|
175
|
-
throw new Error(
|
|
188
|
+
throw new Error("dot: argument must be a Vector");
|
|
176
189
|
}
|
|
177
190
|
if (this.length !== other.length) {
|
|
178
|
-
throw new Error(
|
|
191
|
+
throw new Error(
|
|
192
|
+
`dot: dimension mismatch (${this.length} vs ${other.length})`,
|
|
193
|
+
);
|
|
179
194
|
}
|
|
180
|
-
return this.data.reduce(
|
|
195
|
+
return this.data.reduce(
|
|
196
|
+
(acc, v, i) => acc.plus(v.mul(other.data[i])),
|
|
197
|
+
new Decimal(0),
|
|
198
|
+
);
|
|
181
199
|
}
|
|
182
200
|
|
|
183
201
|
/**
|
|
@@ -194,14 +212,15 @@ export class Vector {
|
|
|
194
212
|
*/
|
|
195
213
|
outer(other) {
|
|
196
214
|
if (!other || !(other instanceof Vector)) {
|
|
197
|
-
throw new Error(
|
|
215
|
+
throw new Error("outer: argument must be a Vector");
|
|
198
216
|
}
|
|
199
217
|
if (this.length === 0 || other.length === 0) {
|
|
200
|
-
throw new Error(
|
|
218
|
+
throw new Error("outer: cannot compute outer product with empty vector");
|
|
201
219
|
}
|
|
202
|
-
const rows = this.length,
|
|
220
|
+
const rows = this.length,
|
|
221
|
+
cols = other.length;
|
|
203
222
|
const out = Array.from({ length: rows }, (_, i) =>
|
|
204
|
-
Array.from({ length: cols }, (_, j) => this.data[i].mul(other.data[j]))
|
|
223
|
+
Array.from({ length: cols }, (_, j) => this.data[i].mul(other.data[j])),
|
|
205
224
|
);
|
|
206
225
|
return out;
|
|
207
226
|
}
|
|
@@ -214,17 +233,19 @@ export class Vector {
|
|
|
214
233
|
*/
|
|
215
234
|
cross(other) {
|
|
216
235
|
if (!other || !(other instanceof Vector)) {
|
|
217
|
-
throw new Error(
|
|
236
|
+
throw new Error("cross: argument must be a Vector");
|
|
218
237
|
}
|
|
219
238
|
if (this.length !== 3 || other.length !== 3) {
|
|
220
|
-
throw new Error(
|
|
239
|
+
throw new Error(
|
|
240
|
+
`cross: requires 3D vectors (got ${this.length}D and ${other.length}D)`,
|
|
241
|
+
);
|
|
221
242
|
}
|
|
222
243
|
const [a1, a2, a3] = this.data;
|
|
223
244
|
const [b1, b2, b3] = other.data;
|
|
224
245
|
return new Vector([
|
|
225
246
|
a2.mul(b3).minus(a3.mul(b2)),
|
|
226
247
|
a3.mul(b1).minus(a1.mul(b3)),
|
|
227
|
-
a1.mul(b2).minus(a2.mul(b1))
|
|
248
|
+
a1.mul(b2).minus(a2.mul(b1)),
|
|
228
249
|
]);
|
|
229
250
|
}
|
|
230
251
|
|
|
@@ -245,7 +266,7 @@ export class Vector {
|
|
|
245
266
|
*/
|
|
246
267
|
normalize() {
|
|
247
268
|
const n = this.norm();
|
|
248
|
-
if (n.isZero()) throw new Error(
|
|
269
|
+
if (n.isZero()) throw new Error("Cannot normalize zero vector");
|
|
249
270
|
return this.scale(new Decimal(1).div(n));
|
|
250
271
|
}
|
|
251
272
|
|
|
@@ -257,16 +278,18 @@ export class Vector {
|
|
|
257
278
|
*/
|
|
258
279
|
angleBetween(other) {
|
|
259
280
|
if (!other || !(other instanceof Vector)) {
|
|
260
|
-
throw new Error(
|
|
281
|
+
throw new Error("angleBetween: argument must be a Vector");
|
|
261
282
|
}
|
|
262
283
|
if (this.length !== other.length) {
|
|
263
|
-
throw new Error(
|
|
284
|
+
throw new Error(
|
|
285
|
+
`angleBetween: dimension mismatch (${this.length} vs ${other.length})`,
|
|
286
|
+
);
|
|
264
287
|
}
|
|
265
288
|
const dotProduct = this.dot(other);
|
|
266
289
|
const n1 = this.norm();
|
|
267
290
|
const n2 = other.norm();
|
|
268
291
|
if (n1.isZero() || n2.isZero()) {
|
|
269
|
-
throw new Error(
|
|
292
|
+
throw new Error("angleBetween: angle with zero vector is undefined");
|
|
270
293
|
}
|
|
271
294
|
// Clamp cosine to [-1, 1] for numerical safety
|
|
272
295
|
const cosv = dotProduct.div(n1.mul(n2));
|
|
@@ -283,14 +306,16 @@ export class Vector {
|
|
|
283
306
|
*/
|
|
284
307
|
projectOnto(other) {
|
|
285
308
|
if (!other || !(other instanceof Vector)) {
|
|
286
|
-
throw new Error(
|
|
309
|
+
throw new Error("projectOnto: argument must be a Vector");
|
|
287
310
|
}
|
|
288
311
|
if (this.length !== other.length) {
|
|
289
|
-
throw new Error(
|
|
312
|
+
throw new Error(
|
|
313
|
+
`projectOnto: dimension mismatch (${this.length} vs ${other.length})`,
|
|
314
|
+
);
|
|
290
315
|
}
|
|
291
316
|
const denom = other.dot(other);
|
|
292
317
|
if (denom.isZero()) {
|
|
293
|
-
throw new Error(
|
|
318
|
+
throw new Error("projectOnto: cannot project onto zero vector");
|
|
294
319
|
}
|
|
295
320
|
const coef = this.dot(other).div(denom);
|
|
296
321
|
return other.scale(coef);
|
|
@@ -306,7 +331,9 @@ export class Vector {
|
|
|
306
331
|
orthogonal() {
|
|
307
332
|
const n = this.norm();
|
|
308
333
|
if (n.isZero()) {
|
|
309
|
-
throw new Error(
|
|
334
|
+
throw new Error(
|
|
335
|
+
"orthogonal: cannot find orthogonal vector to zero vector",
|
|
336
|
+
);
|
|
310
337
|
}
|
|
311
338
|
if (this.length === 2) {
|
|
312
339
|
// 2D perpendicular: rotate 90 degrees counterclockwise [-y, x]
|
|
@@ -315,7 +342,10 @@ export class Vector {
|
|
|
315
342
|
// For n > 2: find a standard basis vector not parallel to this,
|
|
316
343
|
// then use Gram-Schmidt orthogonalization
|
|
317
344
|
for (let i = 0; i < this.length; i++) {
|
|
318
|
-
const ei = Array.from(
|
|
345
|
+
const ei = Array.from(
|
|
346
|
+
{ length: this.length },
|
|
347
|
+
(_, j) => new Decimal(j === i ? 1 : 0),
|
|
348
|
+
);
|
|
319
349
|
const candidate = new Vector(ei);
|
|
320
350
|
// Project candidate out of this vector's direction
|
|
321
351
|
const proj = candidate.projectOnto(this);
|
|
@@ -323,7 +353,9 @@ export class Vector {
|
|
|
323
353
|
const orthNorm = orth.norm();
|
|
324
354
|
if (!orthNorm.isZero()) return orth.normalize();
|
|
325
355
|
}
|
|
326
|
-
throw new Error(
|
|
356
|
+
throw new Error(
|
|
357
|
+
"orthogonal: unable to find orthogonal vector (degenerate case)",
|
|
358
|
+
);
|
|
327
359
|
}
|
|
328
360
|
|
|
329
361
|
/**
|
|
@@ -334,10 +366,12 @@ export class Vector {
|
|
|
334
366
|
*/
|
|
335
367
|
isOrthogonalTo(other) {
|
|
336
368
|
if (!other || !(other instanceof Vector)) {
|
|
337
|
-
throw new Error(
|
|
369
|
+
throw new Error("isOrthogonalTo: argument must be a Vector");
|
|
338
370
|
}
|
|
339
371
|
if (this.length !== other.length) {
|
|
340
|
-
throw new Error(
|
|
372
|
+
throw new Error(
|
|
373
|
+
`isOrthogonalTo: dimension mismatch (${this.length} vs ${other.length})`,
|
|
374
|
+
);
|
|
341
375
|
}
|
|
342
376
|
return this.dot(other).isZero();
|
|
343
377
|
}
|
|
@@ -350,10 +384,12 @@ export class Vector {
|
|
|
350
384
|
*/
|
|
351
385
|
distance(other) {
|
|
352
386
|
if (!other || !(other instanceof Vector)) {
|
|
353
|
-
throw new Error(
|
|
387
|
+
throw new Error("distance: argument must be a Vector");
|
|
354
388
|
}
|
|
355
389
|
if (this.length !== other.length) {
|
|
356
|
-
throw new Error(
|
|
390
|
+
throw new Error(
|
|
391
|
+
`distance: dimension mismatch (${this.length} vs ${other.length})`,
|
|
392
|
+
);
|
|
357
393
|
}
|
|
358
394
|
return this.sub(other).norm();
|
|
359
395
|
}
|
|
@@ -369,16 +405,16 @@ export class Vector {
|
|
|
369
405
|
if (!(other instanceof Vector)) return false;
|
|
370
406
|
if (other.length !== this.length) return false;
|
|
371
407
|
if (tolerance === null) {
|
|
372
|
-
throw new Error(
|
|
408
|
+
throw new Error("equals: tolerance cannot be null");
|
|
373
409
|
}
|
|
374
410
|
let tol;
|
|
375
411
|
try {
|
|
376
412
|
tol = D(tolerance);
|
|
377
413
|
if (tol.isNaN()) {
|
|
378
|
-
throw new Error(
|
|
414
|
+
throw new Error("equals: tolerance cannot be NaN");
|
|
379
415
|
}
|
|
380
416
|
if (tol.isNegative()) {
|
|
381
|
-
throw new Error(
|
|
417
|
+
throw new Error("equals: tolerance must be non-negative");
|
|
382
418
|
}
|
|
383
419
|
} catch (err) {
|
|
384
420
|
throw new Error(`equals: invalid tolerance - ${err.message}`);
|