@tscircuit/checks 0.0.122 → 0.0.124

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/dist/index.js CHANGED
@@ -237,7 +237,16 @@ function checkEachPcbPortConnectedToPcbTraces(circuitJson) {
237
237
  }
238
238
 
239
239
  // lib/check-each-pcb-trace-non-overlapping/check-each-pcb-trace-non-overlapping.ts
240
- import { getReadableNameForElement as getReadableNameForElement2, cju } from "@tscircuit/circuit-json-util";
240
+ import { cju, getReadableNameForElement as getReadableNameForElement2 } from "@tscircuit/circuit-json-util";
241
+ import { getPrimaryId } from "@tscircuit/circuit-json-util";
242
+ import {
243
+ segmentToBoundsMinDistance,
244
+ segmentToCircleMinDistance
245
+ } from "@tscircuit/math-utils";
246
+ import { segmentToSegmentMinDistance } from "@tscircuit/math-utils";
247
+ import {
248
+ getFullConnectivityMapFromCircuitJson as getFullConnectivityMapFromCircuitJson2
249
+ } from "circuit-json-to-connectivity-map";
241
250
 
242
251
  // lib/data-structures/SpatialIndex.ts
243
252
  var SpatialObjectIndex = class {
@@ -338,31 +347,6 @@ var SpatialObjectIndex = class {
338
347
  }
339
348
  };
340
349
 
341
- // lib/check-each-pcb-trace-non-overlapping/check-each-pcb-trace-non-overlapping.ts
342
- import {
343
- getFullConnectivityMapFromCircuitJson as getFullConnectivityMapFromCircuitJson2
344
- } from "circuit-json-to-connectivity-map";
345
-
346
- // lib/check-each-pcb-trace-non-overlapping/getCollidableBounds.ts
347
- import { getBoundsOfPcbElements as getBoundsOfPcbElements2 } from "@tscircuit/circuit-json-util";
348
- var getCollidableBounds = (collidable) => {
349
- if (collidable.type === "pcb_trace_segment") {
350
- return {
351
- minX: Math.min(collidable.x1, collidable.x2),
352
- minY: Math.min(collidable.y1, collidable.y2),
353
- maxX: Math.max(collidable.x1, collidable.x2),
354
- maxY: Math.max(collidable.y1, collidable.y2)
355
- };
356
- }
357
- return getBoundsOfPcbElements2([collidable]);
358
- };
359
-
360
- // lib/check-each-pcb-trace-non-overlapping/check-each-pcb-trace-non-overlapping.ts
361
- import {
362
- segmentToBoundsMinDistance,
363
- segmentToCircleMinDistance
364
- } from "@tscircuit/math-utils";
365
-
366
350
  // node_modules/@tscircuit/jlcpcb-manufacturing-specs/lib/jlcpcb-manufacturing-specs.ts
367
351
  var jlcMinTolerances = {
368
352
  min_trace_width: 0.1,
@@ -379,39 +363,131 @@ var jlcMinTolerances = {
379
363
  var DEFAULT_TRACE_MARGIN = 0.1;
380
364
  var DEFAULT_TRACE_THICKNESS = jlcMinTolerances.min_trace_width;
381
365
  var DEFAULT_VIA_DIAMETER = jlcMinTolerances.min_via_pad_diameter;
382
- var DEFAULT_VIA_BOARD_MARGIN = 0.3;
366
+ var DEFAULT_VIA_BOARD_MARGIN = jlcMinTolerances.min_board_edge_clearance;
383
367
  var DEFAULT_SAME_NET_VIA_MARGIN = jlcMinTolerances.min_via_hole_edge_to_via_hole_edge_clearance;
384
368
  var DEFAULT_DIFFERENT_NET_VIA_MARGIN = jlcMinTolerances.min_via_hole_edge_to_via_hole_edge_clearance;
385
369
  var DEFAULT_PAD_PAD_CLEARANCE = jlcMinTolerances.min_pad_edge_to_pad_edge_clearance;
386
370
  var DEFAULT_PAD_TRACE_CLEARANCE = jlcMinTolerances.min_trace_to_pad_edge_clearance;
387
371
  var EPSILON = 5e-3;
372
+ var getPcbBoard = (circuitJson) => circuitJson.find((el) => el.type === "pcb_board");
373
+ var getBoardDrcValue = (board, key) => board?.[key];
388
374
 
389
- // lib/check-each-pcb-trace-non-overlapping/getPcbPortIdsConnectedToTraces.ts
390
- function getPcbPortIdsConnectedToTrace(trace) {
391
- const connectedPcbPorts = /* @__PURE__ */ new Set();
392
- for (const segment of trace.route) {
393
- if (segment.route_type === "wire") {
394
- if (segment.start_pcb_port_id)
395
- connectedPcbPorts.add(segment.start_pcb_port_id);
396
- if (segment.end_pcb_port_id)
397
- connectedPcbPorts.add(segment.end_pcb_port_id);
398
- }
375
+ // lib/util/getLayersOfPcbElement.ts
376
+ import { all_layers } from "circuit-json";
377
+ function getLayersOfPcbElement(obj) {
378
+ if (obj.type === "pcb_trace_segment") {
379
+ return [obj.layer];
399
380
  }
400
- return Array.from(connectedPcbPorts);
401
- }
402
- function getPcbPortIdsConnectedToTraces(traces) {
403
- const connectedPorts = /* @__PURE__ */ new Set();
404
- for (const trace of traces) {
405
- for (const portId of getPcbPortIdsConnectedToTrace(trace)) {
406
- connectedPorts.add(portId);
407
- }
381
+ if (obj.type === "pcb_smtpad") {
382
+ return [obj.layer];
408
383
  }
409
- return Array.from(connectedPorts);
384
+ if (obj.type === "pcb_plated_hole") {
385
+ return Array.isArray(obj.layers) ? obj.layers : [...all_layers];
386
+ }
387
+ if (obj.type === "pcb_hole") {
388
+ return [...all_layers];
389
+ }
390
+ if (obj.type === "pcb_via") {
391
+ return Array.isArray(obj.layers) ? obj.layers : [...all_layers];
392
+ }
393
+ if (obj.type === "pcb_keepout") {
394
+ return Array.isArray(obj.layers) ? obj.layers : [];
395
+ }
396
+ return [];
410
397
  }
411
398
 
412
- // lib/check-each-pcb-trace-non-overlapping/check-each-pcb-trace-non-overlapping.ts
413
- import { segmentToSegmentMinDistance } from "@tscircuit/math-utils";
414
- import { getPrimaryId } from "@tscircuit/circuit-json-util";
399
+ // lib/check-each-pcb-trace-non-overlapping/getClosestPointBetweenSegmentAndBounds.ts
400
+ var getClosestPointBetweenSegmentAndBounds = (segment, bounds) => {
401
+ const p1 = { x: segment.x1, y: segment.y1 };
402
+ const p2 = { x: segment.x2, y: segment.y2 };
403
+ const minX = bounds.minX;
404
+ const minY = bounds.minY;
405
+ const maxX = bounds.maxX;
406
+ const maxY = bounds.maxY;
407
+ if (p1.x === p2.x && p1.y === p2.y) {
408
+ const closestX = Math.max(minX, Math.min(maxX, p1.x));
409
+ const closestY = Math.max(minY, Math.min(maxY, p1.y));
410
+ if (closestX === p1.x && closestY === p1.y) {
411
+ return { x: p1.x, y: p1.y };
412
+ }
413
+ return { x: closestX, y: closestY };
414
+ }
415
+ const dx = p2.x - p1.x;
416
+ const dy = p2.y - p1.y;
417
+ const tMinX = dx !== 0 ? (minX - p1.x) / dx : Number.NEGATIVE_INFINITY;
418
+ const tMaxX = dx !== 0 ? (maxX - p1.x) / dx : Number.POSITIVE_INFINITY;
419
+ const tMinY = dy !== 0 ? (minY - p1.y) / dy : Number.NEGATIVE_INFINITY;
420
+ const tMaxY = dy !== 0 ? (maxY - p1.y) / dy : Number.POSITIVE_INFINITY;
421
+ const tEnter = Math.max(Math.min(tMinX, tMaxX), Math.min(tMinY, tMaxY));
422
+ const tExit = Math.min(Math.max(tMinX, tMaxX), Math.max(tMinY, tMaxY));
423
+ if (tEnter <= tExit && tExit >= 0 && tEnter <= 1) {
424
+ const t = Math.max(0, Math.min(1, tEnter));
425
+ return {
426
+ x: p1.x + t * dx,
427
+ y: p1.y + t * dy
428
+ };
429
+ }
430
+ const closestToP1 = {
431
+ x: Math.max(minX, Math.min(maxX, p1.x)),
432
+ y: Math.max(minY, Math.min(maxY, p1.y))
433
+ };
434
+ const closestToP2 = {
435
+ x: Math.max(minX, Math.min(maxX, p2.x)),
436
+ y: Math.max(minY, Math.min(maxY, p2.y))
437
+ };
438
+ const distToP1Squared = (closestToP1.x - p1.x) ** 2 + (closestToP1.y - p1.y) ** 2;
439
+ const distToP2Squared = (closestToP2.x - p2.x) ** 2 + (closestToP2.y - p2.y) ** 2;
440
+ const edges = [
441
+ { start: { x: minX, y: minY }, end: { x: maxX, y: minY } },
442
+ // Bottom edge
443
+ { start: { x: maxX, y: minY }, end: { x: maxX, y: maxY } },
444
+ // Right edge
445
+ { start: { x: maxX, y: maxY }, end: { x: minX, y: maxY } },
446
+ // Top edge
447
+ { start: { x: minX, y: maxY }, end: { x: minX, y: minY } }
448
+ // Left edge
449
+ ];
450
+ let minDistance = Math.min(distToP1Squared, distToP2Squared);
451
+ let closestPoint = distToP1Squared <= distToP2Squared ? closestToP1 : closestToP2;
452
+ const clamp2 = (value, min, max) => {
453
+ return Math.max(min, Math.min(max, value));
454
+ };
455
+ for (const edge of edges) {
456
+ const va = { x: p2.x - p1.x, y: p2.y - p1.y };
457
+ const vb = { x: edge.end.x - edge.start.x, y: edge.end.y - edge.start.y };
458
+ const w = { x: p1.x - edge.start.x, y: p1.y - edge.start.y };
459
+ const dotAA = va.x * va.x + va.y * va.y;
460
+ const dotAB = va.x * vb.x + va.y * vb.y;
461
+ const dotAW = va.x * w.x + va.y * w.y;
462
+ const dotBB = vb.x * vb.x + vb.y * vb.y;
463
+ const dotBW = vb.x * w.x + vb.y * w.y;
464
+ const denominator = dotAA * dotBB - dotAB * dotAB;
465
+ if (Math.abs(denominator) < 1e-10) continue;
466
+ let tA = (dotAB * dotBW - dotBB * dotAW) / denominator;
467
+ let tB = (dotAA * dotBW - dotAB * dotAW) / denominator;
468
+ tA = clamp2(tA, 0, 1);
469
+ tB = clamp2(tB, 0, 1);
470
+ const closestOnSegment = {
471
+ x: p1.x + tA * va.x,
472
+ y: p1.y + tA * va.y
473
+ };
474
+ const closestOnEdge = {
475
+ x: edge.start.x + tB * vb.x,
476
+ y: edge.start.y + tB * vb.y
477
+ };
478
+ const dx2 = closestOnSegment.x - closestOnEdge.x;
479
+ const dy2 = closestOnSegment.y - closestOnEdge.y;
480
+ const distSquared = dx2 * dx2 + dy2 * dy2;
481
+ if (distSquared < minDistance) {
482
+ minDistance = distSquared;
483
+ closestPoint = {
484
+ x: (closestOnSegment.x + closestOnEdge.x) / 2,
485
+ y: (closestOnSegment.y + closestOnEdge.y) / 2
486
+ };
487
+ }
488
+ }
489
+ return closestPoint;
490
+ };
415
491
 
416
492
  // lib/check-each-pcb-trace-non-overlapping/getClosestPointBetweenSegments.ts
417
493
  var getClosestPointBetweenSegments = (segmentA, segmentB) => {
@@ -558,6 +634,43 @@ var clamp = (value, min, max) => {
558
634
  return Math.max(min, Math.min(max, value));
559
635
  };
560
636
 
637
+ // lib/check-each-pcb-trace-non-overlapping/getCollidableBounds.ts
638
+ import { getBoundsOfPcbElements as getBoundsOfPcbElements2 } from "@tscircuit/circuit-json-util";
639
+ var getCollidableBounds = (collidable) => {
640
+ if (collidable.type === "pcb_trace_segment") {
641
+ return {
642
+ minX: Math.min(collidable.x1, collidable.x2),
643
+ minY: Math.min(collidable.y1, collidable.y2),
644
+ maxX: Math.max(collidable.x1, collidable.x2),
645
+ maxY: Math.max(collidable.y1, collidable.y2)
646
+ };
647
+ }
648
+ return getBoundsOfPcbElements2([collidable]);
649
+ };
650
+
651
+ // lib/check-each-pcb-trace-non-overlapping/getPcbPortIdsConnectedToTraces.ts
652
+ function getPcbPortIdsConnectedToTrace(trace) {
653
+ const connectedPcbPorts = /* @__PURE__ */ new Set();
654
+ for (const segment of trace.route) {
655
+ if (segment.route_type === "wire") {
656
+ if (segment.start_pcb_port_id)
657
+ connectedPcbPorts.add(segment.start_pcb_port_id);
658
+ if (segment.end_pcb_port_id)
659
+ connectedPcbPorts.add(segment.end_pcb_port_id);
660
+ }
661
+ }
662
+ return Array.from(connectedPcbPorts);
663
+ }
664
+ function getPcbPortIdsConnectedToTraces(traces) {
665
+ const connectedPorts = /* @__PURE__ */ new Set();
666
+ for (const trace of traces) {
667
+ for (const portId of getPcbPortIdsConnectedToTrace(trace)) {
668
+ connectedPorts.add(portId);
669
+ }
670
+ }
671
+ return Array.from(connectedPorts);
672
+ }
673
+
561
674
  // lib/check-each-pcb-trace-non-overlapping/getRadiusOfCircuitJsonElement.ts
562
675
  var getRadiusOfCircuitJsonElement = (obj) => {
563
676
  if (obj.type === "pcb_via") {
@@ -577,123 +690,6 @@ var getRadiusOfCircuitJsonElement = (obj) => {
577
690
  );
578
691
  };
579
692
 
580
- // lib/check-each-pcb-trace-non-overlapping/getClosestPointBetweenSegmentAndBounds.ts
581
- var getClosestPointBetweenSegmentAndBounds = (segment, bounds) => {
582
- const p1 = { x: segment.x1, y: segment.y1 };
583
- const p2 = { x: segment.x2, y: segment.y2 };
584
- const minX = bounds.minX;
585
- const minY = bounds.minY;
586
- const maxX = bounds.maxX;
587
- const maxY = bounds.maxY;
588
- if (p1.x === p2.x && p1.y === p2.y) {
589
- const closestX = Math.max(minX, Math.min(maxX, p1.x));
590
- const closestY = Math.max(minY, Math.min(maxY, p1.y));
591
- if (closestX === p1.x && closestY === p1.y) {
592
- return { x: p1.x, y: p1.y };
593
- }
594
- return { x: closestX, y: closestY };
595
- }
596
- const dx = p2.x - p1.x;
597
- const dy = p2.y - p1.y;
598
- const tMinX = dx !== 0 ? (minX - p1.x) / dx : Number.NEGATIVE_INFINITY;
599
- const tMaxX = dx !== 0 ? (maxX - p1.x) / dx : Number.POSITIVE_INFINITY;
600
- const tMinY = dy !== 0 ? (minY - p1.y) / dy : Number.NEGATIVE_INFINITY;
601
- const tMaxY = dy !== 0 ? (maxY - p1.y) / dy : Number.POSITIVE_INFINITY;
602
- const tEnter = Math.max(Math.min(tMinX, tMaxX), Math.min(tMinY, tMaxY));
603
- const tExit = Math.min(Math.max(tMinX, tMaxX), Math.max(tMinY, tMaxY));
604
- if (tEnter <= tExit && tExit >= 0 && tEnter <= 1) {
605
- const t = Math.max(0, Math.min(1, tEnter));
606
- return {
607
- x: p1.x + t * dx,
608
- y: p1.y + t * dy
609
- };
610
- }
611
- const closestToP1 = {
612
- x: Math.max(minX, Math.min(maxX, p1.x)),
613
- y: Math.max(minY, Math.min(maxY, p1.y))
614
- };
615
- const closestToP2 = {
616
- x: Math.max(minX, Math.min(maxX, p2.x)),
617
- y: Math.max(minY, Math.min(maxY, p2.y))
618
- };
619
- const distToP1Squared = (closestToP1.x - p1.x) ** 2 + (closestToP1.y - p1.y) ** 2;
620
- const distToP2Squared = (closestToP2.x - p2.x) ** 2 + (closestToP2.y - p2.y) ** 2;
621
- const edges = [
622
- { start: { x: minX, y: minY }, end: { x: maxX, y: minY } },
623
- // Bottom edge
624
- { start: { x: maxX, y: minY }, end: { x: maxX, y: maxY } },
625
- // Right edge
626
- { start: { x: maxX, y: maxY }, end: { x: minX, y: maxY } },
627
- // Top edge
628
- { start: { x: minX, y: maxY }, end: { x: minX, y: minY } }
629
- // Left edge
630
- ];
631
- let minDistance = Math.min(distToP1Squared, distToP2Squared);
632
- let closestPoint = distToP1Squared <= distToP2Squared ? closestToP1 : closestToP2;
633
- const clamp2 = (value, min, max) => {
634
- return Math.max(min, Math.min(max, value));
635
- };
636
- for (const edge of edges) {
637
- const va = { x: p2.x - p1.x, y: p2.y - p1.y };
638
- const vb = { x: edge.end.x - edge.start.x, y: edge.end.y - edge.start.y };
639
- const w = { x: p1.x - edge.start.x, y: p1.y - edge.start.y };
640
- const dotAA = va.x * va.x + va.y * va.y;
641
- const dotAB = va.x * vb.x + va.y * vb.y;
642
- const dotAW = va.x * w.x + va.y * w.y;
643
- const dotBB = vb.x * vb.x + vb.y * vb.y;
644
- const dotBW = vb.x * w.x + vb.y * w.y;
645
- const denominator = dotAA * dotBB - dotAB * dotAB;
646
- if (Math.abs(denominator) < 1e-10) continue;
647
- let tA = (dotAB * dotBW - dotBB * dotAW) / denominator;
648
- let tB = (dotAA * dotBW - dotAB * dotAW) / denominator;
649
- tA = clamp2(tA, 0, 1);
650
- tB = clamp2(tB, 0, 1);
651
- const closestOnSegment = {
652
- x: p1.x + tA * va.x,
653
- y: p1.y + tA * va.y
654
- };
655
- const closestOnEdge = {
656
- x: edge.start.x + tB * vb.x,
657
- y: edge.start.y + tB * vb.y
658
- };
659
- const dx2 = closestOnSegment.x - closestOnEdge.x;
660
- const dy2 = closestOnSegment.y - closestOnEdge.y;
661
- const distSquared = dx2 * dx2 + dy2 * dy2;
662
- if (distSquared < minDistance) {
663
- minDistance = distSquared;
664
- closestPoint = {
665
- x: (closestOnSegment.x + closestOnEdge.x) / 2,
666
- y: (closestOnSegment.y + closestOnEdge.y) / 2
667
- };
668
- }
669
- }
670
- return closestPoint;
671
- };
672
-
673
- // lib/util/getLayersOfPcbElement.ts
674
- import { all_layers } from "circuit-json";
675
- function getLayersOfPcbElement(obj) {
676
- if (obj.type === "pcb_trace_segment") {
677
- return [obj.layer];
678
- }
679
- if (obj.type === "pcb_smtpad") {
680
- return [obj.layer];
681
- }
682
- if (obj.type === "pcb_plated_hole") {
683
- return Array.isArray(obj.layers) ? obj.layers : [...all_layers];
684
- }
685
- if (obj.type === "pcb_hole") {
686
- return [...all_layers];
687
- }
688
- if (obj.type === "pcb_via") {
689
- return Array.isArray(obj.layers) ? obj.layers : [...all_layers];
690
- }
691
- if (obj.type === "pcb_keepout") {
692
- return Array.isArray(obj.layers) ? obj.layers : [];
693
- }
694
- return [];
695
- }
696
-
697
693
  // lib/check-each-pcb-trace-non-overlapping/check-each-pcb-trace-non-overlapping.ts
698
694
  function checkEachPcbTraceNonOverlapping(circuitJson, {
699
695
  connMap,
@@ -743,6 +739,12 @@ function checkEachPcbTraceNonOverlapping(circuitJson, {
743
739
  getBounds: getCollidableBounds
744
740
  });
745
741
  const getReadableName = (id) => getReadableNameForElement2(circuitJson, id);
742
+ const constructErrorMessage = (traceName, otherName, gap) => {
743
+ if (gap < 0) {
744
+ return `PCB trace ${traceName} overlaps with ${otherName} (accidental contact)`;
745
+ }
746
+ return `PCB trace ${traceName} is too close to ${otherName} (gap: ${gap.toFixed(3)}mm)`;
747
+ };
746
748
  const errorIds = /* @__PURE__ */ new Set();
747
749
  for (const segmentA of pcbTraceSegments) {
748
750
  const requiredMargin = minClearance;
@@ -776,7 +778,11 @@ function checkEachPcbTraceNonOverlapping(circuitJson, {
776
778
  errors.push({
777
779
  type: "pcb_trace_error",
778
780
  error_type: "pcb_trace_error",
779
- message: `PCB trace ${getReadableName(segmentA.pcb_trace_id)} overlaps with ${getReadableName(segmentB.pcb_trace_id)} ${gap2 < 0 ? "(accidental contact)" : `(gap: ${gap2.toFixed(3)}mm)`}`,
781
+ message: constructErrorMessage(
782
+ getReadableName(segmentA.pcb_trace_id),
783
+ getReadableName(segmentB.pcb_trace_id),
784
+ gap2
785
+ ),
780
786
  pcb_trace_id: segmentA.pcb_trace_id,
781
787
  source_trace_id: "",
782
788
  pcb_trace_error_id,
@@ -811,7 +817,11 @@ function checkEachPcbTraceNonOverlapping(circuitJson, {
811
817
  errors.push({
812
818
  type: "pcb_trace_error",
813
819
  error_type: "pcb_trace_error",
814
- message: `PCB trace ${getReadableName(segmentA.pcb_trace_id)} overlaps with ${obj.type} "${getReadableName(getPrimaryId(obj))}" ${gap2 < 0 ? "(accidental contact)" : `(gap: ${gap2.toFixed(3)}mm)`}`,
820
+ message: constructErrorMessage(
821
+ getReadableName(segmentA.pcb_trace_id),
822
+ `${obj.type} "${getReadableName(getPrimaryId(obj))}"`,
823
+ gap2
824
+ ),
815
825
  pcb_trace_id: segmentA.pcb_trace_id,
816
826
  center: getClosestPointBetweenSegmentAndBounds(
817
827
  segmentA,
@@ -840,7 +850,11 @@ function checkEachPcbTraceNonOverlapping(circuitJson, {
840
850
  errors.push({
841
851
  type: "pcb_trace_error",
842
852
  error_type: "pcb_trace_error",
843
- message: `PCB trace ${getReadableName(segmentA.pcb_trace_id)} overlaps with ${obj.type} "${getReadableName(getPrimaryId(obj))}" ${gap < 0 ? "(accidental contact)" : `(gap: ${gap.toFixed(3)}mm)`}`,
853
+ message: constructErrorMessage(
854
+ getReadableName(segmentA.pcb_trace_id),
855
+ `${obj.type} "${getReadableName(getPrimaryId(obj))}"`,
856
+ gap
857
+ ),
844
858
  pcb_trace_id: segmentA.pcb_trace_id,
845
859
  source_trace_id: "",
846
860
  pcb_trace_error_id,
@@ -907,11 +921,12 @@ var NetManager = class {
907
921
  // lib/check-pcb-components-out-of-board/checkViasOffBoard.ts
908
922
  import { getReadableNameForElement as getReadableNameForElement3 } from "@tscircuit/circuit-json-util";
909
923
  function checkViasOffBoard(circuitJson) {
910
- const board = circuitJson.find((el) => el.type === "pcb_board");
924
+ const board = getPcbBoard(circuitJson);
911
925
  if (!board) return [];
912
926
  const vias = circuitJson.filter((el) => el.type === "pcb_via");
913
927
  if (vias.length === 0) return [];
914
928
  if (board.width === void 0 || board.height === void 0) return [];
929
+ const boardEdgeClearance = getBoardDrcValue(board, "min_board_edge_clearance") ?? jlcMinTolerances.min_board_edge_clearance;
915
930
  const boardMinX = board.center.x - board.width / 2;
916
931
  const boardMaxX = board.center.x + board.width / 2;
917
932
  const boardMinY = board.center.y - board.height / 2;
@@ -923,7 +938,7 @@ function checkViasOffBoard(circuitJson) {
923
938
  const viaMaxX = via.x + viaRadius;
924
939
  const viaMinY = via.y - viaRadius;
925
940
  const viaMaxY = via.y + viaRadius;
926
- if (viaMinX < boardMinX + DEFAULT_VIA_BOARD_MARGIN || viaMaxX > boardMaxX - DEFAULT_VIA_BOARD_MARGIN || viaMinY < boardMinY + DEFAULT_VIA_BOARD_MARGIN || viaMaxY > boardMaxY - DEFAULT_VIA_BOARD_MARGIN) {
941
+ if (viaMinX < boardMinX + boardEdgeClearance || viaMaxX > boardMaxX - boardEdgeClearance || viaMinY < boardMinY + boardEdgeClearance || viaMaxY > boardMaxY - boardEdgeClearance) {
927
942
  const viaName = getReadableNameForElement3(circuitJson, via.pcb_via_id);
928
943
  errors.push({
929
944
  type: "pcb_placement_error",
@@ -1187,10 +1202,12 @@ function viasAreAtSameLocation(a, b) {
1187
1202
  // lib/check-same-net-via-spacing.ts
1188
1203
  function checkSameNetViaSpacing(circuitJson, {
1189
1204
  connMap,
1190
- minClearance = DEFAULT_SAME_NET_VIA_MARGIN
1205
+ minClearance
1191
1206
  } = {}) {
1192
1207
  const vias = circuitJson.filter((el) => el.type === "pcb_via");
1193
1208
  if (vias.length < 2) return [];
1209
+ const board = getPcbBoard(circuitJson);
1210
+ minClearance ??= getBoardDrcValue(board, "min_via_hole_edge_to_via_hole_edge_clearance") ?? jlcMinTolerances.min_via_hole_edge_to_via_hole_edge_clearance;
1194
1211
  connMap ??= getFullConnectivityMapFromCircuitJson3(circuitJson);
1195
1212
  const errors = [];
1196
1213
  const reported = /* @__PURE__ */ new Set();
@@ -1200,7 +1217,7 @@ function checkSameNetViaSpacing(circuitJson, {
1200
1217
  const viaB = vias[j];
1201
1218
  if (viasAreAtSameLocation(viaA, viaB)) continue;
1202
1219
  if (!connMap.areIdsConnected(viaA.pcb_via_id, viaB.pcb_via_id)) continue;
1203
- const gap = distance2(viaA, viaB) - viaA.outer_diameter / 2 - viaB.outer_diameter / 2;
1220
+ const gap = distance2(viaA, viaB) - viaA.hole_diameter / 2 - viaB.hole_diameter / 2;
1204
1221
  if (gap + EPSILON >= minClearance) continue;
1205
1222
  const pairId = [viaA.pcb_via_id, viaB.pcb_via_id].sort().join("_");
1206
1223
  if (reported.has(pairId)) continue;
@@ -1236,10 +1253,12 @@ import {
1236
1253
  } from "circuit-json-to-connectivity-map";
1237
1254
  function checkDifferentNetViaSpacing(circuitJson, {
1238
1255
  connMap,
1239
- minClearance = DEFAULT_DIFFERENT_NET_VIA_MARGIN
1256
+ minClearance
1240
1257
  } = {}) {
1241
1258
  const vias = circuitJson.filter((el) => el.type === "pcb_via");
1242
1259
  if (vias.length < 2) return [];
1260
+ const board = getPcbBoard(circuitJson);
1261
+ minClearance ??= getBoardDrcValue(board, "min_via_hole_edge_to_via_hole_edge_clearance") ?? jlcMinTolerances.min_via_hole_edge_to_via_hole_edge_clearance;
1243
1262
  connMap ??= getFullConnectivityMapFromCircuitJson4(circuitJson);
1244
1263
  const errors = [];
1245
1264
  const reported = /* @__PURE__ */ new Set();
@@ -1249,7 +1268,7 @@ function checkDifferentNetViaSpacing(circuitJson, {
1249
1268
  const viaB = vias[j];
1250
1269
  if (viasAreAtSameLocation(viaA, viaB)) continue;
1251
1270
  if (connMap.areIdsConnected(viaA.pcb_via_id, viaB.pcb_via_id)) continue;
1252
- const gap = distance2(viaA, viaB) - viaA.outer_diameter / 2 - viaB.outer_diameter / 2;
1271
+ const gap = distance2(viaA, viaB) - viaA.hole_diameter / 2 - viaB.hole_diameter / 2;
1253
1272
  if (gap + EPSILON >= minClearance) continue;
1254
1273
  const pairId = [viaA.pcb_via_id, viaB.pcb_via_id].sort().join("_");
1255
1274
  if (reported.has(pairId)) continue;
@@ -1402,7 +1421,6 @@ function checkSourceTracesHavePcbTraces(circuitJson) {
1402
1421
  // lib/check-trace-out-of-board/checkTraceOutOfBoard.ts
1403
1422
  import { cju as cju3 } from "@tscircuit/circuit-json-util";
1404
1423
  import { segmentToSegmentMinDistance as segmentToSegmentMinDistance2 } from "@tscircuit/math-utils";
1405
- var DEFAULT_BOARD_MARGIN = 0.2;
1406
1424
  function getBoardPolygonPoints(board) {
1407
1425
  if (board.outline && board.outline.length > 0) {
1408
1426
  return board.outline.map((p) => ({ x: p.x, y: p.y }));
@@ -1427,11 +1445,9 @@ function getBoardPolygonPoints(board) {
1427
1445
  }
1428
1446
  function checkPcbTracesOutOfBoard(circuitJson, config = {}) {
1429
1447
  const errors = [];
1430
- const margin = config.margin ?? DEFAULT_BOARD_MARGIN;
1431
- const board = circuitJson.find(
1432
- (el) => el.type === "pcb_board"
1433
- );
1448
+ const board = getPcbBoard(circuitJson);
1434
1449
  if (!board) return errors;
1450
+ const margin = config.margin ?? getBoardDrcValue(board, "min_board_edge_clearance") ?? jlcMinTolerances.min_board_edge_clearance;
1435
1451
  const boardPoints = getBoardPolygonPoints(board);
1436
1452
  if (!boardPoints) return errors;
1437
1453
  const pcbTraces = cju3(circuitJson).pcb_trace.list();
@@ -1444,7 +1460,7 @@ function checkPcbTracesOutOfBoard(circuitJson, config = {}) {
1444
1460
  const traceWidth = "width" in p1 ? p1.width : "width" in p2 ? p2.width : 0.1;
1445
1461
  const segmentStart = { x: p1.x, y: p1.y };
1446
1462
  const segmentEnd = { x: p2.x, y: p2.y };
1447
- let minDistance = Infinity;
1463
+ let minDistance = Number.POSITIVE_INFINITY;
1448
1464
  for (let j = 0; j < boardPoints.length; j++) {
1449
1465
  const edgeStart = boardPoints[j];
1450
1466
  const edgeEnd = boardPoints[(j + 1) % boardPoints.length];
@@ -1729,10 +1745,12 @@ var getTraceSegments = (circuitJson) => {
1729
1745
  // lib/check-pad-pad-clearance.ts
1730
1746
  function checkPadPadClearance(circuitJson, {
1731
1747
  connMap,
1732
- minClearance = DEFAULT_PAD_PAD_CLEARANCE
1748
+ minClearance
1733
1749
  } = {}) {
1734
1750
  const pads = getPads(circuitJson);
1735
1751
  if (pads.length < 2) return [];
1752
+ const board = getPcbBoard(circuitJson);
1753
+ minClearance ??= getBoardDrcValue(board, "min_pad_edge_to_pad_edge_clearance") ?? jlcMinTolerances.min_pad_edge_to_pad_edge_clearance;
1736
1754
  connMap ??= getFullConnectivityMapFromCircuitJson7(circuitJson);
1737
1755
  const spatialIndex = new SpatialObjectIndex({
1738
1756
  objects: pads,
@@ -1795,11 +1813,13 @@ import {
1795
1813
  } from "circuit-json-to-connectivity-map";
1796
1814
  function checkPadTraceClearance(circuitJson, {
1797
1815
  connMap,
1798
- minClearance = DEFAULT_PAD_TRACE_CLEARANCE
1816
+ minClearance
1799
1817
  } = {}) {
1800
1818
  const pads = getPads(circuitJson);
1801
1819
  const segments = getTraceSegments(circuitJson);
1802
1820
  if (pads.length === 0 || segments.length === 0) return [];
1821
+ const board = getPcbBoard(circuitJson);
1822
+ minClearance ??= getBoardDrcValue(board, "min_trace_to_pad_edge_clearance") ?? jlcMinTolerances.min_trace_to_pad_edge_clearance;
1803
1823
  connMap ??= getFullConnectivityMapFromCircuitJson8(circuitJson);
1804
1824
  const spatialIndex = new SpatialObjectIndex({
1805
1825
  objects: pads,
@@ -1876,11 +1896,13 @@ var getClosestPointOnSegment = (point, segmentStart, segmentEnd) => {
1876
1896
  };
1877
1897
  function checkViaTraceClearance(circuitJson, {
1878
1898
  connMap,
1879
- minClearance = DEFAULT_PAD_TRACE_CLEARANCE
1899
+ minClearance
1880
1900
  } = {}) {
1881
1901
  const vias = circuitJson.filter((el) => el.type === "pcb_via");
1882
1902
  const segments = getTraceSegments(circuitJson);
1883
1903
  if (vias.length === 0 || segments.length === 0) return [];
1904
+ const board = getPcbBoard(circuitJson);
1905
+ minClearance ??= getBoardDrcValue(board, "min_trace_to_pad_edge_clearance") ?? jlcMinTolerances.min_trace_to_pad_edge_clearance;
1884
1906
  connMap ??= getFullConnectivityMapFromCircuitJson9(circuitJson);
1885
1907
  const errors = /* @__PURE__ */ new Map();
1886
1908
  for (const via of vias) {