@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.
- package/bin/svg-matrix.js +310 -61
- package/bin/svglinter.cjs +102 -3
- package/bin/svgm.js +236 -27
- package/package.json +1 -1
- package/src/animation-optimization.js +137 -17
- package/src/animation-references.js +123 -6
- package/src/arc-length.js +213 -4
- package/src/bezier-analysis.js +217 -21
- package/src/bezier-intersections.js +275 -12
- package/src/browser-verify.js +237 -4
- package/src/clip-path-resolver.js +168 -0
- package/src/convert-path-data.js +479 -28
- package/src/css-specificity.js +73 -10
- package/src/douglas-peucker.js +219 -2
- package/src/flatten-pipeline.js +284 -26
- package/src/geometry-to-path.js +250 -25
- package/src/gjk-collision.js +236 -33
- package/src/index.js +261 -3
- package/src/inkscape-support.js +86 -28
- package/src/logger.js +48 -3
- package/src/marker-resolver.js +278 -74
- package/src/mask-resolver.js +265 -66
- package/src/matrix.js +44 -5
- package/src/mesh-gradient.js +352 -102
- package/src/off-canvas-detection.js +382 -13
- package/src/path-analysis.js +192 -18
- package/src/path-data-plugins.js +309 -5
- package/src/path-optimization.js +129 -5
- package/src/path-simplification.js +188 -32
- package/src/pattern-resolver.js +454 -106
- package/src/polygon-clip.js +324 -1
- package/src/svg-boolean-ops.js +226 -9
- package/src/svg-collections.js +7 -5
- package/src/svg-flatten.js +386 -62
- package/src/svg-parser.js +179 -8
- package/src/svg-rendering-context.js +235 -6
- package/src/svg-toolbox.js +45 -8
- package/src/svg2-polyfills.js +40 -10
- package/src/transform-decomposition.js +258 -32
- package/src/transform-optimization.js +259 -13
- package/src/transforms2d.js +82 -9
- package/src/transforms3d.js +62 -10
- package/src/use-symbol-resolver.js +286 -42
- package/src/vector.js +64 -8
- package/src/verification.js +392 -1
|
@@ -71,6 +71,28 @@ export function lineLineIntersection(line1, line2) {
|
|
|
71
71
|
throw new Error("lineLineIntersection: line2 must be an array of 2 points");
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
// WHY: Validate point structure to prevent undefined access errors
|
|
75
|
+
if (
|
|
76
|
+
!Array.isArray(line1[0]) ||
|
|
77
|
+
line1[0].length < 2 ||
|
|
78
|
+
!Array.isArray(line1[1]) ||
|
|
79
|
+
line1[1].length < 2
|
|
80
|
+
) {
|
|
81
|
+
throw new Error(
|
|
82
|
+
"lineLineIntersection: line1 points must be arrays with at least 2 elements [x, y]",
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
if (
|
|
86
|
+
!Array.isArray(line2[0]) ||
|
|
87
|
+
line2[0].length < 2 ||
|
|
88
|
+
!Array.isArray(line2[1]) ||
|
|
89
|
+
line2[1].length < 2
|
|
90
|
+
) {
|
|
91
|
+
throw new Error(
|
|
92
|
+
"lineLineIntersection: line2 points must be arrays with at least 2 elements [x, y]",
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
74
96
|
const [x1, y1] = [D(line1[0][0]), D(line1[0][1])];
|
|
75
97
|
const [x2, y2] = [D(line1[1][0]), D(line1[1][1])];
|
|
76
98
|
const [x3, y3] = [D(line2[0][0]), D(line2[0][1])];
|
|
@@ -147,6 +169,38 @@ export function bezierLineIntersection(bezier, line, options = {}) {
|
|
|
147
169
|
);
|
|
148
170
|
}
|
|
149
171
|
|
|
172
|
+
// WHY: Validate options parameters to prevent invalid behavior
|
|
173
|
+
if (
|
|
174
|
+
typeof samplesPerDegree !== "number" ||
|
|
175
|
+
samplesPerDegree <= 0 ||
|
|
176
|
+
!isFinite(samplesPerDegree)
|
|
177
|
+
) {
|
|
178
|
+
throw new Error(
|
|
179
|
+
"bezierLineIntersection: samplesPerDegree must be a positive finite number",
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// WHY: Validate line point structure to prevent undefined access
|
|
184
|
+
if (
|
|
185
|
+
!Array.isArray(line[0]) ||
|
|
186
|
+
line[0].length < 2 ||
|
|
187
|
+
!Array.isArray(line[1]) ||
|
|
188
|
+
line[1].length < 2
|
|
189
|
+
) {
|
|
190
|
+
throw new Error(
|
|
191
|
+
"bezierLineIntersection: line points must be arrays with at least 2 elements [x, y]",
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// WHY: Validate bezier control points structure
|
|
196
|
+
for (let i = 0; i < bezier.length; i++) {
|
|
197
|
+
if (!Array.isArray(bezier[i]) || bezier[i].length < 2) {
|
|
198
|
+
throw new Error(
|
|
199
|
+
`bezierLineIntersection: bezier control point ${i} must be an array with at least 2 elements [x, y]`,
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
150
204
|
const [lx0, ly0] = [D(line[0][0]), D(line[0][1])];
|
|
151
205
|
const [lx1, ly1] = [D(line[1][0]), D(line[1][1])];
|
|
152
206
|
|
|
@@ -232,6 +286,25 @@ export function bezierLineIntersection(bezier, line, options = {}) {
|
|
|
232
286
|
* @returns {Decimal} Refined parameter value
|
|
233
287
|
*/
|
|
234
288
|
function refineBezierLineRoot(bezier, line, t0, t1, tol) {
|
|
289
|
+
// WHY: Validate inputs to prevent undefined behavior in internal function
|
|
290
|
+
if (!bezier || !Array.isArray(bezier) || bezier.length < 2) {
|
|
291
|
+
throw new Error(
|
|
292
|
+
"refineBezierLineRoot: bezier must have at least 2 control points",
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
if (!line || !Array.isArray(line) || line.length !== 2) {
|
|
296
|
+
throw new Error("refineBezierLineRoot: line must be an array of 2 points");
|
|
297
|
+
}
|
|
298
|
+
if (t0 === undefined || t0 === null) {
|
|
299
|
+
throw new Error("refineBezierLineRoot: t0 is required");
|
|
300
|
+
}
|
|
301
|
+
if (t1 === undefined || t1 === null) {
|
|
302
|
+
throw new Error("refineBezierLineRoot: t1 is required");
|
|
303
|
+
}
|
|
304
|
+
if (tol === undefined || tol === null) {
|
|
305
|
+
throw new Error("refineBezierLineRoot: tol is required");
|
|
306
|
+
}
|
|
307
|
+
|
|
235
308
|
const [lx0, ly0] = [D(line[0][0]), D(line[0][1])];
|
|
236
309
|
const [lx1, ly1] = [D(line[1][0]), D(line[1][1])];
|
|
237
310
|
const dlx = lx1.minus(lx0);
|
|
@@ -246,7 +319,6 @@ function refineBezierLineRoot(bezier, line, t0, t1, tol) {
|
|
|
246
319
|
};
|
|
247
320
|
|
|
248
321
|
let fLo = evalDist(lo);
|
|
249
|
-
let _fHi = evalDist(hi);
|
|
250
322
|
|
|
251
323
|
// WHY: Use named constant instead of magic number for clarity and maintainability
|
|
252
324
|
for (let i = 0; i < MAX_BISECTION_ITERATIONS; i++) {
|
|
@@ -265,7 +337,6 @@ function refineBezierLineRoot(bezier, line, t0, t1, tol) {
|
|
|
265
337
|
fLo = fMid;
|
|
266
338
|
} else {
|
|
267
339
|
hi = mid;
|
|
268
|
-
_fHi = fMid;
|
|
269
340
|
}
|
|
270
341
|
}
|
|
271
342
|
|
|
@@ -308,6 +379,36 @@ export function bezierBezierIntersection(bezier1, bezier2, options = {}) {
|
|
|
308
379
|
);
|
|
309
380
|
}
|
|
310
381
|
|
|
382
|
+
// WHY: Validate maxDepth to prevent infinite recursion or invalid behavior
|
|
383
|
+
if (
|
|
384
|
+
typeof maxDepth !== "number" ||
|
|
385
|
+
maxDepth <= 0 ||
|
|
386
|
+
!isFinite(maxDepth) ||
|
|
387
|
+
Math.floor(maxDepth) !== maxDepth
|
|
388
|
+
) {
|
|
389
|
+
throw new Error(
|
|
390
|
+
"bezierBezierIntersection: maxDepth must be a positive integer",
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// WHY: Validate control point structure for bezier1
|
|
395
|
+
for (let i = 0; i < bezier1.length; i++) {
|
|
396
|
+
if (!Array.isArray(bezier1[i]) || bezier1[i].length < 2) {
|
|
397
|
+
throw new Error(
|
|
398
|
+
`bezierBezierIntersection: bezier1 control point ${i} must be an array with at least 2 elements [x, y]`,
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// WHY: Validate control point structure for bezier2
|
|
404
|
+
for (let i = 0; i < bezier2.length; i++) {
|
|
405
|
+
if (!Array.isArray(bezier2[i]) || bezier2[i].length < 2) {
|
|
406
|
+
throw new Error(
|
|
407
|
+
`bezierBezierIntersection: bezier2 control point ${i} must be an array with at least 2 elements [x, y]`,
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
311
412
|
const tol = D(tolerance);
|
|
312
413
|
const results = [];
|
|
313
414
|
|
|
@@ -381,6 +482,27 @@ export function bezierBezierIntersection(bezier1, bezier2, options = {}) {
|
|
|
381
482
|
* @returns {Object|null} Refined intersection or null
|
|
382
483
|
*/
|
|
383
484
|
function refineIntersection(bez1, bez2, t1, t2, tol) {
|
|
485
|
+
// WHY: Validate inputs to prevent undefined behavior in internal function
|
|
486
|
+
if (!bez1 || !Array.isArray(bez1) || bez1.length < 2) {
|
|
487
|
+
throw new Error(
|
|
488
|
+
"refineIntersection: bez1 must have at least 2 control points",
|
|
489
|
+
);
|
|
490
|
+
}
|
|
491
|
+
if (!bez2 || !Array.isArray(bez2) || bez2.length < 2) {
|
|
492
|
+
throw new Error(
|
|
493
|
+
"refineIntersection: bez2 must have at least 2 control points",
|
|
494
|
+
);
|
|
495
|
+
}
|
|
496
|
+
if (t1 === undefined || t1 === null) {
|
|
497
|
+
throw new Error("refineIntersection: t1 is required");
|
|
498
|
+
}
|
|
499
|
+
if (t2 === undefined || t2 === null) {
|
|
500
|
+
throw new Error("refineIntersection: t2 is required");
|
|
501
|
+
}
|
|
502
|
+
if (tol === undefined || tol === null) {
|
|
503
|
+
throw new Error("refineIntersection: tol is required");
|
|
504
|
+
}
|
|
505
|
+
|
|
384
506
|
let currentT1 = D(t1);
|
|
385
507
|
let currentT2 = D(t2);
|
|
386
508
|
|
|
@@ -469,6 +591,39 @@ function bboxOverlap(bbox1, bbox2) {
|
|
|
469
591
|
return false; // No overlap if either bbox is missing
|
|
470
592
|
}
|
|
471
593
|
|
|
594
|
+
// WHY: Validate bbox objects have required properties with proper types
|
|
595
|
+
// WHY: Cannot use !bbox1.xmin as it fails for Decimal(0). Must check for undefined/null explicitly.
|
|
596
|
+
if (
|
|
597
|
+
bbox1.xmin === undefined ||
|
|
598
|
+
bbox1.xmin === null ||
|
|
599
|
+
bbox1.xmax === undefined ||
|
|
600
|
+
bbox1.xmax === null ||
|
|
601
|
+
bbox1.ymin === undefined ||
|
|
602
|
+
bbox1.ymin === null ||
|
|
603
|
+
bbox1.ymax === undefined ||
|
|
604
|
+
bbox1.ymax === null ||
|
|
605
|
+
typeof bbox1.xmin.lt !== "function"
|
|
606
|
+
) {
|
|
607
|
+
throw new Error(
|
|
608
|
+
"bboxOverlap: bbox1 must have xmin, xmax, ymin, ymax Decimal properties",
|
|
609
|
+
);
|
|
610
|
+
}
|
|
611
|
+
if (
|
|
612
|
+
bbox2.xmin === undefined ||
|
|
613
|
+
bbox2.xmin === null ||
|
|
614
|
+
bbox2.xmax === undefined ||
|
|
615
|
+
bbox2.xmax === null ||
|
|
616
|
+
bbox2.ymin === undefined ||
|
|
617
|
+
bbox2.ymin === null ||
|
|
618
|
+
bbox2.ymax === undefined ||
|
|
619
|
+
bbox2.ymax === null ||
|
|
620
|
+
typeof bbox2.xmin.lt !== "function"
|
|
621
|
+
) {
|
|
622
|
+
throw new Error(
|
|
623
|
+
"bboxOverlap: bbox2 must have xmin, xmax, ymin, ymax Decimal properties",
|
|
624
|
+
);
|
|
625
|
+
}
|
|
626
|
+
|
|
472
627
|
return !(
|
|
473
628
|
bbox1.xmax.lt(bbox2.xmin) ||
|
|
474
629
|
bbox1.xmin.gt(bbox2.xmax) ||
|
|
@@ -484,9 +639,43 @@ function bboxOverlap(bbox1, bbox2) {
|
|
|
484
639
|
* @returns {Array} Array of unique intersections
|
|
485
640
|
*/
|
|
486
641
|
function deduplicateIntersections(intersections, tol) {
|
|
642
|
+
// WHY: Validate inputs to prevent cryptic errors from invalid data
|
|
643
|
+
if (!intersections || !Array.isArray(intersections)) {
|
|
644
|
+
throw new Error("deduplicateIntersections: intersections must be an array");
|
|
645
|
+
}
|
|
646
|
+
if (tol === undefined || tol === null) {
|
|
647
|
+
throw new Error("deduplicateIntersections: tol is required");
|
|
648
|
+
}
|
|
649
|
+
|
|
487
650
|
const result = [];
|
|
488
651
|
|
|
489
652
|
for (const isect of intersections) {
|
|
653
|
+
// WHY: Validate each intersection has required properties
|
|
654
|
+
if (!isect || typeof isect !== "object") {
|
|
655
|
+
throw new Error(
|
|
656
|
+
"deduplicateIntersections: intersection must be an object",
|
|
657
|
+
);
|
|
658
|
+
}
|
|
659
|
+
// WHY: Cannot use !isect.t1 as it fails for Decimal(0). Must check for undefined/null explicitly.
|
|
660
|
+
if (
|
|
661
|
+
isect.t1 === undefined ||
|
|
662
|
+
isect.t1 === null ||
|
|
663
|
+
typeof isect.t1.minus !== "function"
|
|
664
|
+
) {
|
|
665
|
+
throw new Error(
|
|
666
|
+
"deduplicateIntersections: intersection must have t1 Decimal property",
|
|
667
|
+
);
|
|
668
|
+
}
|
|
669
|
+
if (
|
|
670
|
+
isect.t2 === undefined ||
|
|
671
|
+
isect.t2 === null ||
|
|
672
|
+
typeof isect.t2.minus !== "function"
|
|
673
|
+
) {
|
|
674
|
+
throw new Error(
|
|
675
|
+
"deduplicateIntersections: intersection must have t2 Decimal property",
|
|
676
|
+
);
|
|
677
|
+
}
|
|
678
|
+
|
|
490
679
|
let isDuplicate = false;
|
|
491
680
|
|
|
492
681
|
for (const existing of result) {
|
|
@@ -538,12 +727,33 @@ export function bezierSelfIntersection(bezier, options = {}) {
|
|
|
538
727
|
const minSep = D(minSeparation);
|
|
539
728
|
|
|
540
729
|
// Input validation
|
|
541
|
-
if (!bezier || bezier.length < 2) {
|
|
730
|
+
if (!bezier || !Array.isArray(bezier) || bezier.length < 2) {
|
|
542
731
|
throw new Error(
|
|
543
|
-
"bezierSelfIntersection: bezier must
|
|
732
|
+
"bezierSelfIntersection: bezier must be an array with at least 2 control points",
|
|
544
733
|
);
|
|
545
734
|
}
|
|
546
735
|
|
|
736
|
+
// WHY: Validate maxDepth to prevent infinite recursion or invalid behavior
|
|
737
|
+
if (
|
|
738
|
+
typeof maxDepth !== "number" ||
|
|
739
|
+
maxDepth <= 0 ||
|
|
740
|
+
!isFinite(maxDepth) ||
|
|
741
|
+
Math.floor(maxDepth) !== maxDepth
|
|
742
|
+
) {
|
|
743
|
+
throw new Error(
|
|
744
|
+
"bezierSelfIntersection: maxDepth must be a positive integer",
|
|
745
|
+
);
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
// WHY: Validate control point structure
|
|
749
|
+
for (let i = 0; i < bezier.length; i++) {
|
|
750
|
+
if (!Array.isArray(bezier[i]) || bezier[i].length < 2) {
|
|
751
|
+
throw new Error(
|
|
752
|
+
`bezierSelfIntersection: control point ${i} must be an array with at least 2 elements [x, y]`,
|
|
753
|
+
);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
|
|
547
757
|
// Self-intersections only possible for cubic and higher
|
|
548
758
|
if (bezier.length < 4) {
|
|
549
759
|
return [];
|
|
@@ -648,6 +858,25 @@ export function bezierSelfIntersection(bezier, options = {}) {
|
|
|
648
858
|
* @returns {Object|null} Refined intersection or null if failed
|
|
649
859
|
*/
|
|
650
860
|
function refineSelfIntersection(bezier, t1Init, t2Init, tol, minSep) {
|
|
861
|
+
// WHY: Validate inputs to prevent undefined behavior in internal function
|
|
862
|
+
if (!bezier || !Array.isArray(bezier) || bezier.length < 2) {
|
|
863
|
+
throw new Error(
|
|
864
|
+
"refineSelfIntersection: bezier must have at least 2 control points",
|
|
865
|
+
);
|
|
866
|
+
}
|
|
867
|
+
if (t1Init === undefined || t1Init === null) {
|
|
868
|
+
throw new Error("refineSelfIntersection: t1Init is required");
|
|
869
|
+
}
|
|
870
|
+
if (t2Init === undefined || t2Init === null) {
|
|
871
|
+
throw new Error("refineSelfIntersection: t2Init is required");
|
|
872
|
+
}
|
|
873
|
+
if (tol === undefined || tol === null) {
|
|
874
|
+
throw new Error("refineSelfIntersection: tol is required");
|
|
875
|
+
}
|
|
876
|
+
if (minSep === undefined || minSep === null) {
|
|
877
|
+
throw new Error("refineSelfIntersection: minSep is required");
|
|
878
|
+
}
|
|
879
|
+
|
|
651
880
|
let t1 = D(t1Init);
|
|
652
881
|
let t2 = D(t2Init);
|
|
653
882
|
|
|
@@ -888,6 +1117,13 @@ export function verifyIntersection(
|
|
|
888
1117
|
if (!intersection) {
|
|
889
1118
|
throw new Error("verifyIntersection: intersection object is required");
|
|
890
1119
|
}
|
|
1120
|
+
// WHY: Validate intersection has required t1 and t2 properties before using them
|
|
1121
|
+
if (intersection.t1 === undefined || intersection.t1 === null) {
|
|
1122
|
+
throw new Error("verifyIntersection: intersection.t1 is required");
|
|
1123
|
+
}
|
|
1124
|
+
if (intersection.t2 === undefined || intersection.t2 === null) {
|
|
1125
|
+
throw new Error("verifyIntersection: intersection.t2 is required");
|
|
1126
|
+
}
|
|
891
1127
|
|
|
892
1128
|
const tol = D(tolerance);
|
|
893
1129
|
|
|
@@ -942,8 +1178,15 @@ export function verifyLineLineIntersection(
|
|
|
942
1178
|
|
|
943
1179
|
const tol = D(tolerance);
|
|
944
1180
|
|
|
945
|
-
|
|
946
|
-
|
|
1181
|
+
// WHY: Validate all required intersection properties before using them
|
|
1182
|
+
if (intersection.t1 === undefined || intersection.t1 === null) {
|
|
1183
|
+
return { valid: false, reason: "intersection.t1 is missing" };
|
|
1184
|
+
}
|
|
1185
|
+
if (intersection.t2 === undefined || intersection.t2 === null) {
|
|
1186
|
+
return { valid: false, reason: "intersection.t2 is missing" };
|
|
1187
|
+
}
|
|
1188
|
+
if (!intersection.point || !Array.isArray(intersection.point) || intersection.point.length < 2) {
|
|
1189
|
+
return { valid: false, reason: "intersection.point is missing or invalid" };
|
|
947
1190
|
}
|
|
948
1191
|
|
|
949
1192
|
const [x1, y1] = [D(line1[0][0]), D(line1[0][1])];
|
|
@@ -1065,8 +1308,15 @@ export function verifyBezierLineIntersection(
|
|
|
1065
1308
|
|
|
1066
1309
|
const tol = D(tolerance);
|
|
1067
1310
|
|
|
1068
|
-
|
|
1069
|
-
|
|
1311
|
+
// WHY: Validate all required intersection properties before using them
|
|
1312
|
+
if (intersection.t1 === undefined || intersection.t1 === null) {
|
|
1313
|
+
return { valid: false, reason: "intersection.t1 is missing" };
|
|
1314
|
+
}
|
|
1315
|
+
if (intersection.t2 === undefined || intersection.t2 === null) {
|
|
1316
|
+
return { valid: false, reason: "intersection.t2 is missing" };
|
|
1317
|
+
}
|
|
1318
|
+
if (!intersection.point || !Array.isArray(intersection.point) || intersection.point.length < 2) {
|
|
1319
|
+
return { valid: false, reason: "intersection.point is missing or invalid" };
|
|
1070
1320
|
}
|
|
1071
1321
|
|
|
1072
1322
|
const t1 = D(intersection.t1);
|
|
@@ -1167,8 +1417,12 @@ export function verifyBezierBezierIntersection(
|
|
|
1167
1417
|
|
|
1168
1418
|
const tol = D(tolerance);
|
|
1169
1419
|
|
|
1170
|
-
|
|
1171
|
-
|
|
1420
|
+
// WHY: Validate all required intersection properties before using them
|
|
1421
|
+
if (intersection.t1 === undefined || intersection.t1 === null) {
|
|
1422
|
+
return { valid: false, reason: "intersection.t1 is missing" };
|
|
1423
|
+
}
|
|
1424
|
+
if (intersection.t2 === undefined || intersection.t2 === null) {
|
|
1425
|
+
return { valid: false, reason: "intersection.t2 is missing" };
|
|
1172
1426
|
}
|
|
1173
1427
|
|
|
1174
1428
|
const t1 = D(intersection.t1);
|
|
@@ -1267,8 +1521,12 @@ export function verifySelfIntersection(
|
|
|
1267
1521
|
const tol = D(tolerance);
|
|
1268
1522
|
const minSep = D(minSeparation);
|
|
1269
1523
|
|
|
1270
|
-
|
|
1271
|
-
|
|
1524
|
+
// WHY: Validate all required intersection properties before using them
|
|
1525
|
+
if (intersection.t1 === undefined || intersection.t1 === null) {
|
|
1526
|
+
return { valid: false, reason: "intersection.t1 is missing" };
|
|
1527
|
+
}
|
|
1528
|
+
if (intersection.t2 === undefined || intersection.t2 === null) {
|
|
1529
|
+
return { valid: false, reason: "intersection.t2 is missing" };
|
|
1272
1530
|
}
|
|
1273
1531
|
|
|
1274
1532
|
const t1 = D(intersection.t1);
|
|
@@ -1423,6 +1681,11 @@ export function verifyPathPathIntersection(
|
|
|
1423
1681
|
* @returns {{allPassed: boolean, results: Object}}
|
|
1424
1682
|
*/
|
|
1425
1683
|
export function verifyAllIntersectionFunctions(tolerance = "1e-30") {
|
|
1684
|
+
// WHY: Validate tolerance parameter to prevent invalid configuration
|
|
1685
|
+
if (tolerance === undefined || tolerance === null) {
|
|
1686
|
+
throw new Error("verifyAllIntersectionFunctions: tolerance cannot be undefined or null");
|
|
1687
|
+
}
|
|
1688
|
+
|
|
1426
1689
|
const results = {};
|
|
1427
1690
|
let allPassed = true;
|
|
1428
1691
|
|