@tscircuit/checks 0.0.121 → 0.0.123

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,37 +347,13 @@ 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,
369
- min_via_to_via_clearance: 0.1,
370
- min_trace_to_pad_clearance: 0.1,
371
- min_pad_to_pad_clearance: 0.1,
353
+ min_via_hole_edge_to_via_hole_edge_clearance: 0.1,
354
+ min_plated_hole_drill_edge_to_drill_edge_clearance: 0.15,
355
+ min_trace_to_pad_edge_clearance: 0.1,
356
+ min_pad_edge_to_pad_edge_clearance: 0.1,
372
357
  min_board_edge_clearance: 0.2,
373
358
  min_via_hole_diameter: 0.2,
374
359
  min_via_pad_diameter: 0.3
@@ -379,38 +364,128 @@ var DEFAULT_TRACE_MARGIN = 0.1;
379
364
  var DEFAULT_TRACE_THICKNESS = jlcMinTolerances.min_trace_width;
380
365
  var DEFAULT_VIA_DIAMETER = jlcMinTolerances.min_via_pad_diameter;
381
366
  var DEFAULT_VIA_BOARD_MARGIN = 0.3;
382
- var DEFAULT_SAME_NET_VIA_MARGIN = jlcMinTolerances.min_via_to_via_clearance;
383
- var DEFAULT_DIFFERENT_NET_VIA_MARGIN = jlcMinTolerances.min_via_to_via_clearance;
384
- var DEFAULT_PAD_PAD_CLEARANCE = jlcMinTolerances.min_pad_to_pad_clearance;
385
- var DEFAULT_PAD_TRACE_CLEARANCE = jlcMinTolerances.min_trace_to_pad_clearance;
367
+ var DEFAULT_SAME_NET_VIA_MARGIN = jlcMinTolerances.min_via_hole_edge_to_via_hole_edge_clearance;
368
+ var DEFAULT_DIFFERENT_NET_VIA_MARGIN = jlcMinTolerances.min_via_hole_edge_to_via_hole_edge_clearance;
369
+ var DEFAULT_PAD_PAD_CLEARANCE = jlcMinTolerances.min_pad_edge_to_pad_edge_clearance;
370
+ var DEFAULT_PAD_TRACE_CLEARANCE = jlcMinTolerances.min_trace_to_pad_edge_clearance;
386
371
  var EPSILON = 5e-3;
387
372
 
388
- // lib/check-each-pcb-trace-non-overlapping/getPcbPortIdsConnectedToTraces.ts
389
- function getPcbPortIdsConnectedToTrace(trace) {
390
- const connectedPcbPorts = /* @__PURE__ */ new Set();
391
- for (const segment of trace.route) {
392
- if (segment.route_type === "wire") {
393
- if (segment.start_pcb_port_id)
394
- connectedPcbPorts.add(segment.start_pcb_port_id);
395
- if (segment.end_pcb_port_id)
396
- connectedPcbPorts.add(segment.end_pcb_port_id);
397
- }
373
+ // lib/util/getLayersOfPcbElement.ts
374
+ import { all_layers } from "circuit-json";
375
+ function getLayersOfPcbElement(obj) {
376
+ if (obj.type === "pcb_trace_segment") {
377
+ return [obj.layer];
398
378
  }
399
- return Array.from(connectedPcbPorts);
400
- }
401
- function getPcbPortIdsConnectedToTraces(traces) {
402
- const connectedPorts = /* @__PURE__ */ new Set();
403
- for (const trace of traces) {
404
- for (const portId of getPcbPortIdsConnectedToTrace(trace)) {
405
- connectedPorts.add(portId);
406
- }
379
+ if (obj.type === "pcb_smtpad") {
380
+ return [obj.layer];
407
381
  }
408
- return Array.from(connectedPorts);
382
+ if (obj.type === "pcb_plated_hole") {
383
+ return Array.isArray(obj.layers) ? obj.layers : [...all_layers];
384
+ }
385
+ if (obj.type === "pcb_hole") {
386
+ return [...all_layers];
387
+ }
388
+ if (obj.type === "pcb_via") {
389
+ return Array.isArray(obj.layers) ? obj.layers : [...all_layers];
390
+ }
391
+ if (obj.type === "pcb_keepout") {
392
+ return Array.isArray(obj.layers) ? obj.layers : [];
393
+ }
394
+ return [];
409
395
  }
410
396
 
411
- // lib/check-each-pcb-trace-non-overlapping/check-each-pcb-trace-non-overlapping.ts
412
- import { segmentToSegmentMinDistance } from "@tscircuit/math-utils";
413
- import { getPrimaryId } from "@tscircuit/circuit-json-util";
397
+ // lib/check-each-pcb-trace-non-overlapping/getClosestPointBetweenSegmentAndBounds.ts
398
+ var getClosestPointBetweenSegmentAndBounds = (segment, bounds) => {
399
+ const p1 = { x: segment.x1, y: segment.y1 };
400
+ const p2 = { x: segment.x2, y: segment.y2 };
401
+ const minX = bounds.minX;
402
+ const minY = bounds.minY;
403
+ const maxX = bounds.maxX;
404
+ const maxY = bounds.maxY;
405
+ if (p1.x === p2.x && p1.y === p2.y) {
406
+ const closestX = Math.max(minX, Math.min(maxX, p1.x));
407
+ const closestY = Math.max(minY, Math.min(maxY, p1.y));
408
+ if (closestX === p1.x && closestY === p1.y) {
409
+ return { x: p1.x, y: p1.y };
410
+ }
411
+ return { x: closestX, y: closestY };
412
+ }
413
+ const dx = p2.x - p1.x;
414
+ const dy = p2.y - p1.y;
415
+ const tMinX = dx !== 0 ? (minX - p1.x) / dx : Number.NEGATIVE_INFINITY;
416
+ const tMaxX = dx !== 0 ? (maxX - p1.x) / dx : Number.POSITIVE_INFINITY;
417
+ const tMinY = dy !== 0 ? (minY - p1.y) / dy : Number.NEGATIVE_INFINITY;
418
+ const tMaxY = dy !== 0 ? (maxY - p1.y) / dy : Number.POSITIVE_INFINITY;
419
+ const tEnter = Math.max(Math.min(tMinX, tMaxX), Math.min(tMinY, tMaxY));
420
+ const tExit = Math.min(Math.max(tMinX, tMaxX), Math.max(tMinY, tMaxY));
421
+ if (tEnter <= tExit && tExit >= 0 && tEnter <= 1) {
422
+ const t = Math.max(0, Math.min(1, tEnter));
423
+ return {
424
+ x: p1.x + t * dx,
425
+ y: p1.y + t * dy
426
+ };
427
+ }
428
+ const closestToP1 = {
429
+ x: Math.max(minX, Math.min(maxX, p1.x)),
430
+ y: Math.max(minY, Math.min(maxY, p1.y))
431
+ };
432
+ const closestToP2 = {
433
+ x: Math.max(minX, Math.min(maxX, p2.x)),
434
+ y: Math.max(minY, Math.min(maxY, p2.y))
435
+ };
436
+ const distToP1Squared = (closestToP1.x - p1.x) ** 2 + (closestToP1.y - p1.y) ** 2;
437
+ const distToP2Squared = (closestToP2.x - p2.x) ** 2 + (closestToP2.y - p2.y) ** 2;
438
+ const edges = [
439
+ { start: { x: minX, y: minY }, end: { x: maxX, y: minY } },
440
+ // Bottom edge
441
+ { start: { x: maxX, y: minY }, end: { x: maxX, y: maxY } },
442
+ // Right edge
443
+ { start: { x: maxX, y: maxY }, end: { x: minX, y: maxY } },
444
+ // Top edge
445
+ { start: { x: minX, y: maxY }, end: { x: minX, y: minY } }
446
+ // Left edge
447
+ ];
448
+ let minDistance = Math.min(distToP1Squared, distToP2Squared);
449
+ let closestPoint = distToP1Squared <= distToP2Squared ? closestToP1 : closestToP2;
450
+ const clamp2 = (value, min, max) => {
451
+ return Math.max(min, Math.min(max, value));
452
+ };
453
+ for (const edge of edges) {
454
+ const va = { x: p2.x - p1.x, y: p2.y - p1.y };
455
+ const vb = { x: edge.end.x - edge.start.x, y: edge.end.y - edge.start.y };
456
+ const w = { x: p1.x - edge.start.x, y: p1.y - edge.start.y };
457
+ const dotAA = va.x * va.x + va.y * va.y;
458
+ const dotAB = va.x * vb.x + va.y * vb.y;
459
+ const dotAW = va.x * w.x + va.y * w.y;
460
+ const dotBB = vb.x * vb.x + vb.y * vb.y;
461
+ const dotBW = vb.x * w.x + vb.y * w.y;
462
+ const denominator = dotAA * dotBB - dotAB * dotAB;
463
+ if (Math.abs(denominator) < 1e-10) continue;
464
+ let tA = (dotAB * dotBW - dotBB * dotAW) / denominator;
465
+ let tB = (dotAA * dotBW - dotAB * dotAW) / denominator;
466
+ tA = clamp2(tA, 0, 1);
467
+ tB = clamp2(tB, 0, 1);
468
+ const closestOnSegment = {
469
+ x: p1.x + tA * va.x,
470
+ y: p1.y + tA * va.y
471
+ };
472
+ const closestOnEdge = {
473
+ x: edge.start.x + tB * vb.x,
474
+ y: edge.start.y + tB * vb.y
475
+ };
476
+ const dx2 = closestOnSegment.x - closestOnEdge.x;
477
+ const dy2 = closestOnSegment.y - closestOnEdge.y;
478
+ const distSquared = dx2 * dx2 + dy2 * dy2;
479
+ if (distSquared < minDistance) {
480
+ minDistance = distSquared;
481
+ closestPoint = {
482
+ x: (closestOnSegment.x + closestOnEdge.x) / 2,
483
+ y: (closestOnSegment.y + closestOnEdge.y) / 2
484
+ };
485
+ }
486
+ }
487
+ return closestPoint;
488
+ };
414
489
 
415
490
  // lib/check-each-pcb-trace-non-overlapping/getClosestPointBetweenSegments.ts
416
491
  var getClosestPointBetweenSegments = (segmentA, segmentB) => {
@@ -557,6 +632,43 @@ var clamp = (value, min, max) => {
557
632
  return Math.max(min, Math.min(max, value));
558
633
  };
559
634
 
635
+ // lib/check-each-pcb-trace-non-overlapping/getCollidableBounds.ts
636
+ import { getBoundsOfPcbElements as getBoundsOfPcbElements2 } from "@tscircuit/circuit-json-util";
637
+ var getCollidableBounds = (collidable) => {
638
+ if (collidable.type === "pcb_trace_segment") {
639
+ return {
640
+ minX: Math.min(collidable.x1, collidable.x2),
641
+ minY: Math.min(collidable.y1, collidable.y2),
642
+ maxX: Math.max(collidable.x1, collidable.x2),
643
+ maxY: Math.max(collidable.y1, collidable.y2)
644
+ };
645
+ }
646
+ return getBoundsOfPcbElements2([collidable]);
647
+ };
648
+
649
+ // lib/check-each-pcb-trace-non-overlapping/getPcbPortIdsConnectedToTraces.ts
650
+ function getPcbPortIdsConnectedToTrace(trace) {
651
+ const connectedPcbPorts = /* @__PURE__ */ new Set();
652
+ for (const segment of trace.route) {
653
+ if (segment.route_type === "wire") {
654
+ if (segment.start_pcb_port_id)
655
+ connectedPcbPorts.add(segment.start_pcb_port_id);
656
+ if (segment.end_pcb_port_id)
657
+ connectedPcbPorts.add(segment.end_pcb_port_id);
658
+ }
659
+ }
660
+ return Array.from(connectedPcbPorts);
661
+ }
662
+ function getPcbPortIdsConnectedToTraces(traces) {
663
+ const connectedPorts = /* @__PURE__ */ new Set();
664
+ for (const trace of traces) {
665
+ for (const portId of getPcbPortIdsConnectedToTrace(trace)) {
666
+ connectedPorts.add(portId);
667
+ }
668
+ }
669
+ return Array.from(connectedPorts);
670
+ }
671
+
560
672
  // lib/check-each-pcb-trace-non-overlapping/getRadiusOfCircuitJsonElement.ts
561
673
  var getRadiusOfCircuitJsonElement = (obj) => {
562
674
  if (obj.type === "pcb_via") {
@@ -576,123 +688,6 @@ var getRadiusOfCircuitJsonElement = (obj) => {
576
688
  );
577
689
  };
578
690
 
579
- // lib/check-each-pcb-trace-non-overlapping/getClosestPointBetweenSegmentAndBounds.ts
580
- var getClosestPointBetweenSegmentAndBounds = (segment, bounds) => {
581
- const p1 = { x: segment.x1, y: segment.y1 };
582
- const p2 = { x: segment.x2, y: segment.y2 };
583
- const minX = bounds.minX;
584
- const minY = bounds.minY;
585
- const maxX = bounds.maxX;
586
- const maxY = bounds.maxY;
587
- if (p1.x === p2.x && p1.y === p2.y) {
588
- const closestX = Math.max(minX, Math.min(maxX, p1.x));
589
- const closestY = Math.max(minY, Math.min(maxY, p1.y));
590
- if (closestX === p1.x && closestY === p1.y) {
591
- return { x: p1.x, y: p1.y };
592
- }
593
- return { x: closestX, y: closestY };
594
- }
595
- const dx = p2.x - p1.x;
596
- const dy = p2.y - p1.y;
597
- const tMinX = dx !== 0 ? (minX - p1.x) / dx : Number.NEGATIVE_INFINITY;
598
- const tMaxX = dx !== 0 ? (maxX - p1.x) / dx : Number.POSITIVE_INFINITY;
599
- const tMinY = dy !== 0 ? (minY - p1.y) / dy : Number.NEGATIVE_INFINITY;
600
- const tMaxY = dy !== 0 ? (maxY - p1.y) / dy : Number.POSITIVE_INFINITY;
601
- const tEnter = Math.max(Math.min(tMinX, tMaxX), Math.min(tMinY, tMaxY));
602
- const tExit = Math.min(Math.max(tMinX, tMaxX), Math.max(tMinY, tMaxY));
603
- if (tEnter <= tExit && tExit >= 0 && tEnter <= 1) {
604
- const t = Math.max(0, Math.min(1, tEnter));
605
- return {
606
- x: p1.x + t * dx,
607
- y: p1.y + t * dy
608
- };
609
- }
610
- const closestToP1 = {
611
- x: Math.max(minX, Math.min(maxX, p1.x)),
612
- y: Math.max(minY, Math.min(maxY, p1.y))
613
- };
614
- const closestToP2 = {
615
- x: Math.max(minX, Math.min(maxX, p2.x)),
616
- y: Math.max(minY, Math.min(maxY, p2.y))
617
- };
618
- const distToP1Squared = (closestToP1.x - p1.x) ** 2 + (closestToP1.y - p1.y) ** 2;
619
- const distToP2Squared = (closestToP2.x - p2.x) ** 2 + (closestToP2.y - p2.y) ** 2;
620
- const edges = [
621
- { start: { x: minX, y: minY }, end: { x: maxX, y: minY } },
622
- // Bottom edge
623
- { start: { x: maxX, y: minY }, end: { x: maxX, y: maxY } },
624
- // Right edge
625
- { start: { x: maxX, y: maxY }, end: { x: minX, y: maxY } },
626
- // Top edge
627
- { start: { x: minX, y: maxY }, end: { x: minX, y: minY } }
628
- // Left edge
629
- ];
630
- let minDistance = Math.min(distToP1Squared, distToP2Squared);
631
- let closestPoint = distToP1Squared <= distToP2Squared ? closestToP1 : closestToP2;
632
- const clamp2 = (value, min, max) => {
633
- return Math.max(min, Math.min(max, value));
634
- };
635
- for (const edge of edges) {
636
- const va = { x: p2.x - p1.x, y: p2.y - p1.y };
637
- const vb = { x: edge.end.x - edge.start.x, y: edge.end.y - edge.start.y };
638
- const w = { x: p1.x - edge.start.x, y: p1.y - edge.start.y };
639
- const dotAA = va.x * va.x + va.y * va.y;
640
- const dotAB = va.x * vb.x + va.y * vb.y;
641
- const dotAW = va.x * w.x + va.y * w.y;
642
- const dotBB = vb.x * vb.x + vb.y * vb.y;
643
- const dotBW = vb.x * w.x + vb.y * w.y;
644
- const denominator = dotAA * dotBB - dotAB * dotAB;
645
- if (Math.abs(denominator) < 1e-10) continue;
646
- let tA = (dotAB * dotBW - dotBB * dotAW) / denominator;
647
- let tB = (dotAA * dotBW - dotAB * dotAW) / denominator;
648
- tA = clamp2(tA, 0, 1);
649
- tB = clamp2(tB, 0, 1);
650
- const closestOnSegment = {
651
- x: p1.x + tA * va.x,
652
- y: p1.y + tA * va.y
653
- };
654
- const closestOnEdge = {
655
- x: edge.start.x + tB * vb.x,
656
- y: edge.start.y + tB * vb.y
657
- };
658
- const dx2 = closestOnSegment.x - closestOnEdge.x;
659
- const dy2 = closestOnSegment.y - closestOnEdge.y;
660
- const distSquared = dx2 * dx2 + dy2 * dy2;
661
- if (distSquared < minDistance) {
662
- minDistance = distSquared;
663
- closestPoint = {
664
- x: (closestOnSegment.x + closestOnEdge.x) / 2,
665
- y: (closestOnSegment.y + closestOnEdge.y) / 2
666
- };
667
- }
668
- }
669
- return closestPoint;
670
- };
671
-
672
- // lib/util/getLayersOfPcbElement.ts
673
- import { all_layers } from "circuit-json";
674
- function getLayersOfPcbElement(obj) {
675
- if (obj.type === "pcb_trace_segment") {
676
- return [obj.layer];
677
- }
678
- if (obj.type === "pcb_smtpad") {
679
- return [obj.layer];
680
- }
681
- if (obj.type === "pcb_plated_hole") {
682
- return Array.isArray(obj.layers) ? obj.layers : [...all_layers];
683
- }
684
- if (obj.type === "pcb_hole") {
685
- return [...all_layers];
686
- }
687
- if (obj.type === "pcb_via") {
688
- return Array.isArray(obj.layers) ? obj.layers : [...all_layers];
689
- }
690
- if (obj.type === "pcb_keepout") {
691
- return Array.isArray(obj.layers) ? obj.layers : [];
692
- }
693
- return [];
694
- }
695
-
696
691
  // lib/check-each-pcb-trace-non-overlapping/check-each-pcb-trace-non-overlapping.ts
697
692
  function checkEachPcbTraceNonOverlapping(circuitJson, {
698
693
  connMap,
@@ -742,6 +737,12 @@ function checkEachPcbTraceNonOverlapping(circuitJson, {
742
737
  getBounds: getCollidableBounds
743
738
  });
744
739
  const getReadableName = (id) => getReadableNameForElement2(circuitJson, id);
740
+ const constructErrorMessage = (traceName, otherName, gap) => {
741
+ if (gap < 0) {
742
+ return `PCB trace ${traceName} overlaps with ${otherName} (accidental contact)`;
743
+ }
744
+ return `PCB trace ${traceName} is too close to ${otherName} (gap: ${gap.toFixed(3)}mm)`;
745
+ };
745
746
  const errorIds = /* @__PURE__ */ new Set();
746
747
  for (const segmentA of pcbTraceSegments) {
747
748
  const requiredMargin = minClearance;
@@ -775,7 +776,11 @@ function checkEachPcbTraceNonOverlapping(circuitJson, {
775
776
  errors.push({
776
777
  type: "pcb_trace_error",
777
778
  error_type: "pcb_trace_error",
778
- message: `PCB trace ${getReadableName(segmentA.pcb_trace_id)} overlaps with ${getReadableName(segmentB.pcb_trace_id)} ${gap2 < 0 ? "(accidental contact)" : `(gap: ${gap2.toFixed(3)}mm)`}`,
779
+ message: constructErrorMessage(
780
+ getReadableName(segmentA.pcb_trace_id),
781
+ getReadableName(segmentB.pcb_trace_id),
782
+ gap2
783
+ ),
779
784
  pcb_trace_id: segmentA.pcb_trace_id,
780
785
  source_trace_id: "",
781
786
  pcb_trace_error_id,
@@ -810,7 +815,11 @@ function checkEachPcbTraceNonOverlapping(circuitJson, {
810
815
  errors.push({
811
816
  type: "pcb_trace_error",
812
817
  error_type: "pcb_trace_error",
813
- message: `PCB trace ${getReadableName(segmentA.pcb_trace_id)} overlaps with ${obj.type} "${getReadableName(getPrimaryId(obj))}" ${gap2 < 0 ? "(accidental contact)" : `(gap: ${gap2.toFixed(3)}mm)`}`,
818
+ message: constructErrorMessage(
819
+ getReadableName(segmentA.pcb_trace_id),
820
+ `${obj.type} "${getReadableName(getPrimaryId(obj))}"`,
821
+ gap2
822
+ ),
814
823
  pcb_trace_id: segmentA.pcb_trace_id,
815
824
  center: getClosestPointBetweenSegmentAndBounds(
816
825
  segmentA,
@@ -839,7 +848,11 @@ function checkEachPcbTraceNonOverlapping(circuitJson, {
839
848
  errors.push({
840
849
  type: "pcb_trace_error",
841
850
  error_type: "pcb_trace_error",
842
- message: `PCB trace ${getReadableName(segmentA.pcb_trace_id)} overlaps with ${obj.type} "${getReadableName(getPrimaryId(obj))}" ${gap < 0 ? "(accidental contact)" : `(gap: ${gap.toFixed(3)}mm)`}`,
851
+ message: constructErrorMessage(
852
+ getReadableName(segmentA.pcb_trace_id),
853
+ `${obj.type} "${getReadableName(getPrimaryId(obj))}"`,
854
+ gap
855
+ ),
843
856
  pcb_trace_id: segmentA.pcb_trace_id,
844
857
  source_trace_id: "",
845
858
  pcb_trace_error_id,
@@ -2134,7 +2147,26 @@ function checkNoGroundPinDefined(circuitJson) {
2134
2147
 
2135
2148
  // lib/check-connector-accessible-orientation.ts
2136
2149
  import { getBoardBounds } from "@tscircuit/circuit-json-util";
2150
+ function getFacingDirectionFromInsertionDirection(component) {
2151
+ switch (component.insertion_direction) {
2152
+ case "from_left":
2153
+ return "x-";
2154
+ case "from_right":
2155
+ return "x+";
2156
+ case "from_front":
2157
+ return "y+";
2158
+ case "from_back":
2159
+ return "y-";
2160
+ case "from_above":
2161
+ return null;
2162
+ default:
2163
+ return null;
2164
+ }
2165
+ }
2137
2166
  function getFacingDirection(component) {
2167
+ if (component.insertion_direction) {
2168
+ return getFacingDirectionFromInsertionDirection(component);
2169
+ }
2138
2170
  if (!component.center || !component.cable_insertion_center) return null;
2139
2171
  const dx = component.cable_insertion_center.x - component.center.x;
2140
2172
  const dy = component.cable_insertion_center.y - component.center.y;
@@ -2173,7 +2205,6 @@ function checkConnectorAccessibleOrientation(circuitJson) {
2173
2205
  (el) => el.type === "pcb_component"
2174
2206
  );
2175
2207
  for (const component of components) {
2176
- if (!component.cable_insertion_center) continue;
2177
2208
  const facingDirection = getFacingDirection(component);
2178
2209
  const recommendedFacingDirection = getRecommendedFacingDirection(
2179
2210
  component,