@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.
Files changed (55) hide show
  1. package/bin/svg-matrix.js +7 -6
  2. package/bin/svgm.js +109 -40
  3. package/dist/svg-matrix.min.js +7 -7
  4. package/dist/svg-toolbox.min.js +148 -228
  5. package/dist/svgm.min.js +152 -232
  6. package/dist/version.json +5 -5
  7. package/package.json +1 -1
  8. package/scripts/postinstall.js +72 -41
  9. package/scripts/test-postinstall.js +18 -16
  10. package/scripts/version-sync.js +78 -60
  11. package/src/animation-optimization.js +190 -98
  12. package/src/animation-references.js +11 -3
  13. package/src/arc-length.js +23 -20
  14. package/src/bezier-analysis.js +9 -13
  15. package/src/bezier-intersections.js +18 -4
  16. package/src/browser-verify.js +35 -8
  17. package/src/clip-path-resolver.js +285 -114
  18. package/src/convert-path-data.js +20 -8
  19. package/src/css-specificity.js +33 -9
  20. package/src/douglas-peucker.js +272 -141
  21. package/src/geometry-to-path.js +79 -22
  22. package/src/gjk-collision.js +287 -126
  23. package/src/index.js +56 -21
  24. package/src/inkscape-support.js +122 -101
  25. package/src/logger.js +43 -27
  26. package/src/marker-resolver.js +201 -121
  27. package/src/mask-resolver.js +231 -98
  28. package/src/matrix.js +9 -5
  29. package/src/mesh-gradient.js +22 -14
  30. package/src/off-canvas-detection.js +53 -17
  31. package/src/path-optimization.js +356 -171
  32. package/src/path-simplification.js +671 -256
  33. package/src/pattern-resolver.js +1 -3
  34. package/src/polygon-clip.js +396 -78
  35. package/src/svg-boolean-ops.js +90 -23
  36. package/src/svg-collections.js +1546 -667
  37. package/src/svg-flatten.js +152 -38
  38. package/src/svg-matrix-lib.js +2 -2
  39. package/src/svg-parser.js +5 -1
  40. package/src/svg-rendering-context.js +3 -1
  41. package/src/svg-toolbox-lib.js +2 -2
  42. package/src/svg-toolbox.js +99 -457
  43. package/src/svg-validation-data.js +513 -345
  44. package/src/svg2-polyfills.js +156 -93
  45. package/src/svgm-lib.js +8 -4
  46. package/src/transform-optimization.js +168 -51
  47. package/src/transforms2d.js +73 -40
  48. package/src/transforms3d.js +34 -27
  49. package/src/use-symbol-resolver.js +175 -76
  50. package/src/vector.js +80 -44
  51. package/src/vendor/inkscape-hatch-polyfill.js +143 -108
  52. package/src/vendor/inkscape-hatch-polyfill.min.js +291 -1
  53. package/src/vendor/inkscape-mesh-polyfill.js +953 -766
  54. package/src/vendor/inkscape-mesh-polyfill.min.js +896 -1
  55. package/src/verification.js +3 -4
package/src/vector.js CHANGED
@@ -1,4 +1,4 @@
1
- import Decimal from 'decimal.js';
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(`Cannot convert ${x === null ? 'null' : 'undefined'} to Decimal`);
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('Vector requires array');
46
- if (components.length === 0) throw new Error('Vector requires at least one component');
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(`Vector component at index ${i} is ${c === null ? 'null' : 'undefined'}`);
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(`Vector.from: argument is ${arr === null ? 'null' : 'undefined'}`);
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('add: argument must be a Vector');
123
+ throw new Error("add: argument must be a Vector");
117
124
  }
118
125
  if (this.length !== other.length) {
119
- throw new Error(`add: dimension mismatch (${this.length} vs ${other.length})`);
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('sub: argument must be a Vector');
141
+ throw new Error("sub: argument must be a Vector");
133
142
  }
134
143
  if (this.length !== other.length) {
135
- throw new Error(`sub: dimension mismatch (${this.length} vs ${other.length})`);
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(`scale: scalar is ${scalar === null ? 'null' : 'undefined'}`);
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('dot: argument must be a Vector');
188
+ throw new Error("dot: argument must be a Vector");
176
189
  }
177
190
  if (this.length !== other.length) {
178
- throw new Error(`dot: dimension mismatch (${this.length} vs ${other.length})`);
191
+ throw new Error(
192
+ `dot: dimension mismatch (${this.length} vs ${other.length})`,
193
+ );
179
194
  }
180
- return this.data.reduce((acc, v, i) => acc.plus(v.mul(other.data[i])), new Decimal(0));
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('outer: argument must be a Vector');
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('outer: cannot compute outer product with empty vector');
218
+ throw new Error("outer: cannot compute outer product with empty vector");
201
219
  }
202
- const rows = this.length, cols = other.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('cross: argument must be a Vector');
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(`cross: requires 3D vectors (got ${this.length}D and ${other.length}D)`);
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('Cannot normalize zero vector');
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('angleBetween: argument must be a Vector');
281
+ throw new Error("angleBetween: argument must be a Vector");
261
282
  }
262
283
  if (this.length !== other.length) {
263
- throw new Error(`angleBetween: dimension mismatch (${this.length} vs ${other.length})`);
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('angleBetween: angle with zero vector is undefined');
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('projectOnto: argument must be a Vector');
309
+ throw new Error("projectOnto: argument must be a Vector");
287
310
  }
288
311
  if (this.length !== other.length) {
289
- throw new Error(`projectOnto: dimension mismatch (${this.length} vs ${other.length})`);
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('projectOnto: cannot project onto zero vector');
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('orthogonal: cannot find orthogonal vector to zero vector');
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({ length: this.length }, (_, j) => new Decimal(j === i ? 1 : 0));
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('orthogonal: unable to find orthogonal vector (degenerate case)');
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('isOrthogonalTo: argument must be a Vector');
369
+ throw new Error("isOrthogonalTo: argument must be a Vector");
338
370
  }
339
371
  if (this.length !== other.length) {
340
- throw new Error(`isOrthogonalTo: dimension mismatch (${this.length} vs ${other.length})`);
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('distance: argument must be a Vector');
387
+ throw new Error("distance: argument must be a Vector");
354
388
  }
355
389
  if (this.length !== other.length) {
356
- throw new Error(`distance: dimension mismatch (${this.length} vs ${other.length})`);
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('equals: tolerance cannot be null');
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('equals: tolerance cannot be NaN');
414
+ throw new Error("equals: tolerance cannot be NaN");
379
415
  }
380
416
  if (tol.isNegative()) {
381
- throw new Error('equals: tolerance must be non-negative');
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}`);