@emasoft/svg-matrix 1.0.30 → 1.0.31

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 (45) hide show
  1. package/bin/svg-matrix.js +310 -61
  2. package/bin/svglinter.cjs +102 -3
  3. package/bin/svgm.js +236 -27
  4. package/package.json +1 -1
  5. package/src/animation-optimization.js +137 -17
  6. package/src/animation-references.js +123 -6
  7. package/src/arc-length.js +213 -4
  8. package/src/bezier-analysis.js +217 -21
  9. package/src/bezier-intersections.js +275 -12
  10. package/src/browser-verify.js +237 -4
  11. package/src/clip-path-resolver.js +168 -0
  12. package/src/convert-path-data.js +479 -28
  13. package/src/css-specificity.js +73 -10
  14. package/src/douglas-peucker.js +219 -2
  15. package/src/flatten-pipeline.js +284 -26
  16. package/src/geometry-to-path.js +250 -25
  17. package/src/gjk-collision.js +236 -33
  18. package/src/index.js +261 -3
  19. package/src/inkscape-support.js +86 -28
  20. package/src/logger.js +48 -3
  21. package/src/marker-resolver.js +278 -74
  22. package/src/mask-resolver.js +265 -66
  23. package/src/matrix.js +44 -5
  24. package/src/mesh-gradient.js +352 -102
  25. package/src/off-canvas-detection.js +382 -13
  26. package/src/path-analysis.js +192 -18
  27. package/src/path-data-plugins.js +309 -5
  28. package/src/path-optimization.js +129 -5
  29. package/src/path-simplification.js +188 -32
  30. package/src/pattern-resolver.js +454 -106
  31. package/src/polygon-clip.js +324 -1
  32. package/src/svg-boolean-ops.js +226 -9
  33. package/src/svg-collections.js +7 -5
  34. package/src/svg-flatten.js +386 -62
  35. package/src/svg-parser.js +179 -8
  36. package/src/svg-rendering-context.js +235 -6
  37. package/src/svg-toolbox.js +45 -8
  38. package/src/svg2-polyfills.js +40 -10
  39. package/src/transform-decomposition.js +258 -32
  40. package/src/transform-optimization.js +259 -13
  41. package/src/transforms2d.js +82 -9
  42. package/src/transforms3d.js +62 -10
  43. package/src/use-symbol-resolver.js +286 -42
  44. package/src/vector.js +64 -8
  45. package/src/verification.js +392 -1
package/src/matrix.js CHANGED
@@ -6,8 +6,13 @@ import { Vector } from "./vector.js";
6
6
  * Accepts numbers, strings, or Decimal instances.
7
7
  * @param {number|string|Decimal} x - The value to convert
8
8
  * @returns {Decimal} The Decimal representation
9
+ * @throws {Error} If x is null or undefined
9
10
  */
10
- const D = (x) => (x instanceof Decimal ? x : new Decimal(x));
11
+ const D = (x) => {
12
+ // Validate that x is not null or undefined
13
+ if (x == null) throw new Error("Cannot convert null or undefined to Decimal");
14
+ return x instanceof Decimal ? x : new Decimal(x);
15
+ };
11
16
 
12
17
  /**
13
18
  * Matrix - Decimal-backed matrix class for arbitrary-precision matrix operations.
@@ -34,9 +39,14 @@ export class Matrix {
34
39
  * @throws {Error} If data is not a non-empty 2D array with consistent row lengths
35
40
  */
36
41
  constructor(data) {
42
+ // Validate data is a non-empty array
37
43
  if (!Array.isArray(data) || data.length === 0)
38
44
  throw new Error("Matrix requires non-empty 2D array");
45
+ // Validate first row exists and is non-empty
46
+ if (!Array.isArray(data[0]) || data[0].length === 0)
47
+ throw new Error("Matrix rows must be non-empty arrays");
39
48
  const cols = data[0].length;
49
+ // Validate all rows have the same length
40
50
  for (const row of data) {
41
51
  if (!Array.isArray(row) || row.length !== cols)
42
52
  throw new Error("All rows must have same length");
@@ -60,8 +70,14 @@ export class Matrix {
60
70
  * @param {number} r - Number of rows
61
71
  * @param {number} c - Number of columns
62
72
  * @returns {Matrix} New r×c zero matrix
73
+ * @throws {Error} If r or c are not positive integers
63
74
  */
64
75
  static zeros(r, c) {
76
+ // Validate r and c are positive integers
77
+ if (!Number.isInteger(r) || r <= 0)
78
+ throw new Error("rows must be a positive integer");
79
+ if (!Number.isInteger(c) || c <= 0)
80
+ throw new Error("cols must be a positive integer");
65
81
  const out = Array.from({ length: r }, () =>
66
82
  Array.from({ length: c }, () => new Decimal(0)),
67
83
  );
@@ -72,8 +88,12 @@ export class Matrix {
72
88
  * Create an identity matrix.
73
89
  * @param {number} n - Size of the square identity matrix
74
90
  * @returns {Matrix} New n×n identity matrix
91
+ * @throws {Error} If n is not a positive integer
75
92
  */
76
93
  static identity(n) {
94
+ // Validate n is a positive integer
95
+ if (!Number.isInteger(n) || n <= 0)
96
+ throw new Error("size must be a positive integer");
77
97
  const out = Array.from({ length: n }, (_, i) =>
78
98
  Array.from({ length: n }, (_, j) =>
79
99
  (i === j ? new Decimal(1) : new Decimal(0)),
@@ -259,11 +279,15 @@ export class Matrix {
259
279
  * @param {Matrix} other - Matrix to compare with
260
280
  * @param {number|string|Decimal} [tolerance=0] - Maximum allowed difference per element
261
281
  * @returns {boolean} True if matrices are equal within tolerance
282
+ * @throws {Error} If tolerance is negative
262
283
  */
263
284
  equals(other, tolerance = 0) {
264
285
  if (!(other instanceof Matrix)) return false;
265
286
  if (this.rows !== other.rows || this.cols !== other.cols) return false;
266
287
  const tol = D(tolerance);
288
+ // Validate tolerance is non-negative
289
+ if (tol.isNegative())
290
+ throw new Error("tolerance must be non-negative");
267
291
  for (let i = 0; i < this.rows; i++) {
268
292
  for (let j = 0; j < this.cols; j++) {
269
293
  const diff = this.data[i][j].minus(other.data[i][j]).abs();
@@ -472,6 +496,9 @@ export class Matrix {
472
496
  // Back substitution
473
497
  const x = Array.from({ length: n }, () => new Decimal(0));
474
498
  for (let i = n - 1; i >= 0; i--) {
499
+ // Check for zero diagonal element (should not happen after forward elimination)
500
+ if (aug[i][i].isZero())
501
+ throw new Error("Zero diagonal element in back substitution: system is singular");
475
502
  let sum = new Decimal(0);
476
503
  for (let j = i + 1; j < n; j++) sum = sum.plus(aug[i][j].mul(x[j]));
477
504
  x[i] = aug[i][n].minus(sum).div(aug[i][i]);
@@ -546,7 +573,7 @@ export class Matrix {
546
573
  * @param {number} [options.maxIter=120] - Maximum Taylor series iterations
547
574
  * @param {string} [options.tolerance='1e-40'] - Convergence tolerance
548
575
  * @returns {Matrix} The matrix exponential exp(A)
549
- * @throws {Error} If matrix is not square
576
+ * @throws {Error} If matrix is not square or options are invalid
550
577
  */
551
578
  exp(options = {}) {
552
579
  const n = this.rows;
@@ -554,6 +581,16 @@ export class Matrix {
554
581
  throw new Error("Matrix exponential requires square matrix");
555
582
  const ident = Matrix.identity(n);
556
583
 
584
+ // Validate and set maxIter
585
+ const maxIter = options.maxIter || 120;
586
+ if (!Number.isInteger(maxIter) || maxIter <= 0)
587
+ throw new Error("maxIter must be a positive integer");
588
+
589
+ // Validate and set tolerance
590
+ const tol = new Decimal(options.tolerance || "1e-40");
591
+ if (tol.isNegative() || tol.isZero())
592
+ throw new Error("tolerance must be positive");
593
+
557
594
  // Compute infinity norm
558
595
  const normInf = (M) => {
559
596
  let max = new Decimal(0);
@@ -571,14 +608,16 @@ export class Matrix {
571
608
  let s = 0;
572
609
  if (maxNorm.greaterThan(new Decimal(1))) {
573
610
  const ratio = maxNorm.div(new Decimal(1));
574
- s = Math.max(0, Math.ceil(Math.log2(ratio.toNumber())));
611
+ const logVal = ratio.toNumber();
612
+ // Guard against Infinity or NaN from logarithm
613
+ if (!isFinite(logVal))
614
+ throw new Error("Matrix norm too large for exponential computation");
615
+ s = Math.max(0, Math.ceil(Math.log2(logVal)));
575
616
  }
576
617
  let A = this;
577
618
  if (s > 0) A = this.mul(new Decimal(1).div(new Decimal(2).pow(s)));
578
619
 
579
620
  // Taylor series
580
- const maxIter = options.maxIter || 120;
581
- const tol = new Decimal(options.tolerance || "1e-40");
582
621
  let term = ident.clone();
583
622
  let result = ident.clone();
584
623
  for (let k = 1; k < maxIter; k++) {