@tscircuit/checks 0.0.127 → 0.0.129

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
@@ -811,14 +811,17 @@ var getCollidableBounds = (collidable) => {
811
811
  };
812
812
 
813
813
  // lib/check-each-pcb-trace-non-overlapping/getPcbPortIdsConnectedToTraces.ts
814
+ function getPcbPortIdsConnectedToRoutePoint(routePoint) {
815
+ if (routePoint.route_type !== "wire") return [];
816
+ return [routePoint.start_pcb_port_id, routePoint.end_pcb_port_id].filter(
817
+ (portId) => Boolean(portId)
818
+ );
819
+ }
814
820
  function getPcbPortIdsConnectedToTrace(trace) {
815
821
  const connectedPcbPorts = /* @__PURE__ */ new Set();
816
822
  for (const segment of trace.route) {
817
- if (segment.route_type === "wire") {
818
- if (segment.start_pcb_port_id)
819
- connectedPcbPorts.add(segment.start_pcb_port_id);
820
- if (segment.end_pcb_port_id)
821
- connectedPcbPorts.add(segment.end_pcb_port_id);
823
+ for (const portId of getPcbPortIdsConnectedToRoutePoint(segment)) {
824
+ connectedPcbPorts.add(portId);
822
825
  }
823
826
  }
824
827
  return Array.from(connectedPcbPorts);
@@ -1706,6 +1709,9 @@ import { getFullConnectivityMapFromCircuitJson as getFullConnectivityMapFromCirc
1706
1709
  import { getBoundsOfPcbElements as getBoundsOfPcbElements3 } from "@tscircuit/circuit-json-util";
1707
1710
  import { doBoundsOverlap } from "@tscircuit/math-utils";
1708
1711
  function getElementLayers(elem) {
1712
+ if (elem.type === "pcb_courtyard_circle" || elem.type === "pcb_courtyard_outline" || elem.type === "pcb_courtyard_polygon" || elem.type === "pcb_courtyard_rect") {
1713
+ return [elem.layer];
1714
+ }
1709
1715
  return getLayersOfPcbElement(elem);
1710
1716
  }
1711
1717
  function doLayersOverlap(layers1, layers2) {
@@ -1722,6 +1728,7 @@ function doPcbElementsOverlap(elem1, elem2) {
1722
1728
  }
1723
1729
 
1724
1730
  // lib/check-pcb-components-overlap/checkPcbComponentOverlap.ts
1731
+ var isCourtyardElement = (element) => element.type === "pcb_courtyard_circle" || element.type === "pcb_courtyard_outline" || element.type === "pcb_courtyard_polygon" || element.type === "pcb_courtyard_rect";
1725
1732
  var formatOverlapElementDescription = (circuitJson, element) => {
1726
1733
  if ("pcb_port_id" in element && element.pcb_port_id) {
1727
1734
  return getReadableNameForPort(circuitJson, element.pcb_port_id);
@@ -1736,14 +1743,14 @@ function checkPcbComponentOverlap(circuitJson) {
1736
1743
  const smtPads = cju4(circuitJson).pcb_smtpad.list();
1737
1744
  const platedHoles = cju4(circuitJson).pcb_plated_hole.list();
1738
1745
  const holes = cju4(circuitJson).pcb_hole.list();
1746
+ const courtyards = circuitJson.filter(isCourtyardElement);
1739
1747
  const componentMap = /* @__PURE__ */ new Map();
1740
1748
  for (const pad of smtPads) {
1741
1749
  const componentId = pad.pcb_component_id || `standalone_pad_${getPrimaryId2(pad)}`;
1742
1750
  if (!componentMap.has(componentId)) {
1743
1751
  componentMap.set(componentId, {
1744
1752
  component_id: componentId,
1745
- elements: [],
1746
- bounds: { minX: 0, minY: 0, maxX: 0, maxY: 0 }
1753
+ elements: []
1747
1754
  });
1748
1755
  }
1749
1756
  componentMap.get(componentId).elements.push(pad);
@@ -1753,8 +1760,7 @@ function checkPcbComponentOverlap(circuitJson) {
1753
1760
  if (!componentMap.has(componentId)) {
1754
1761
  componentMap.set(componentId, {
1755
1762
  component_id: componentId,
1756
- elements: [],
1757
- bounds: { minX: 0, minY: 0, maxX: 0, maxY: 0 }
1763
+ elements: []
1758
1764
  });
1759
1765
  }
1760
1766
  componentMap.get(componentId).elements.push(hole);
@@ -1763,10 +1769,19 @@ function checkPcbComponentOverlap(circuitJson) {
1763
1769
  const componentId = `standalone_hole_${getPrimaryId2(hole)}`;
1764
1770
  componentMap.set(componentId, {
1765
1771
  component_id: componentId,
1766
- elements: [hole],
1767
- bounds: { minX: 0, minY: 0, maxX: 0, maxY: 0 }
1772
+ elements: [hole]
1768
1773
  });
1769
1774
  }
1775
+ for (const courtyard of courtyards) {
1776
+ const componentId = courtyard.pcb_component_id;
1777
+ if (!componentMap.has(componentId)) {
1778
+ componentMap.set(componentId, {
1779
+ component_id: componentId,
1780
+ elements: []
1781
+ });
1782
+ }
1783
+ componentMap.get(componentId).elements.push(courtyard);
1784
+ }
1770
1785
  for (const [componentId, componentData] of componentMap) {
1771
1786
  if (componentData.elements.length > 0) {
1772
1787
  componentData.bounds = getBoundsOfPcbElements4(componentData.elements);
@@ -1777,6 +1792,9 @@ function checkPcbComponentOverlap(circuitJson) {
1777
1792
  for (let j = i + 1; j < componentsWithElements.length; j++) {
1778
1793
  const comp1 = componentsWithElements[i];
1779
1794
  const comp2 = componentsWithElements[j];
1795
+ if (!comp1.bounds || !comp2.bounds) {
1796
+ continue;
1797
+ }
1780
1798
  if (!doBoundsOverlap2(comp1.bounds, comp2.bounds)) {
1781
1799
  continue;
1782
1800
  }
@@ -1784,6 +1802,9 @@ function checkPcbComponentOverlap(circuitJson) {
1784
1802
  for (const elem2 of comp2.elements) {
1785
1803
  const id1 = getPrimaryId2(elem1);
1786
1804
  const id2 = getPrimaryId2(elem2);
1805
+ if ((isCourtyardElement(elem1) || isCourtyardElement(elem2)) && elem1.type !== "pcb_hole" && elem2.type !== "pcb_hole") {
1806
+ continue;
1807
+ }
1787
1808
  if (elem1.type === "pcb_smtpad" && elem2.type === "pcb_smtpad" && connMap.areIdsConnected(id1, id2)) {
1788
1809
  continue;
1789
1810
  }
@@ -2626,6 +2647,64 @@ import {
2626
2647
  getReadableNameForPcbPort as getReadableNameForPcbPort2,
2627
2648
  getReadableNameForPcbTrace
2628
2649
  } from "@tscircuit/circuit-json-util";
2650
+ function routePointConnectsToAnotherExpectedPort(point, expectedPorts, missingPcbPortId, padMap) {
2651
+ if (point.route_type !== "wire") return false;
2652
+ return expectedPorts.some((expectedPort) => {
2653
+ if (!expectedPort.pcb_port_id || expectedPort.pcb_port_id === missingPcbPortId) {
2654
+ return false;
2655
+ }
2656
+ const expectedPads = padMap.get(expectedPort.pcb_port_id);
2657
+ return expectedPads?.some(
2658
+ (pad) => isPointInPad({ x: point.x, y: point.y }, pad)
2659
+ ) ?? false;
2660
+ });
2661
+ }
2662
+ function getMissingConnectionErrorCenter({
2663
+ firstPoint,
2664
+ lastPoint,
2665
+ port,
2666
+ expectedPorts,
2667
+ padMap
2668
+ }) {
2669
+ let errorLocation;
2670
+ const firstWirePoint = firstPoint.route_type === "wire" ? firstPoint : void 0;
2671
+ const lastWirePoint = lastPoint.route_type === "wire" ? lastPoint : void 0;
2672
+ const firstWirePointReferencesPort = getPcbPortIdsConnectedToRoutePoint(
2673
+ firstPoint
2674
+ ).includes(port.pcb_port_id);
2675
+ const lastWirePointReferencesPort = getPcbPortIdsConnectedToRoutePoint(
2676
+ lastPoint
2677
+ ).includes(port.pcb_port_id);
2678
+ if (firstWirePointReferencesPort && firstWirePoint) {
2679
+ errorLocation = firstWirePoint;
2680
+ } else if (lastWirePointReferencesPort && lastWirePoint) {
2681
+ errorLocation = lastWirePoint;
2682
+ } else if (routePointConnectsToAnotherExpectedPort(
2683
+ firstPoint,
2684
+ expectedPorts,
2685
+ port.pcb_port_id,
2686
+ padMap
2687
+ ) && lastWirePoint) {
2688
+ errorLocation = lastWirePoint;
2689
+ } else if (routePointConnectsToAnotherExpectedPort(
2690
+ lastPoint,
2691
+ expectedPorts,
2692
+ port.pcb_port_id,
2693
+ padMap
2694
+ ) && firstWirePoint) {
2695
+ errorLocation = firstWirePoint;
2696
+ } else if (firstWirePoint && lastWirePoint) {
2697
+ errorLocation = distance2(firstWirePoint, port) <= distance2(lastWirePoint, port) ? firstWirePoint : lastWirePoint;
2698
+ } else if (firstWirePoint) {
2699
+ errorLocation = firstWirePoint;
2700
+ } else if (lastWirePoint) {
2701
+ errorLocation = lastWirePoint;
2702
+ }
2703
+ return errorLocation ? { x: errorLocation.x, y: errorLocation.y } : {
2704
+ x: (firstPoint.x + lastPoint.x) / 2,
2705
+ y: (firstPoint.y + lastPoint.y) / 2
2706
+ };
2707
+ }
2629
2708
  function checkTracesAreContiguous(circuitJson) {
2630
2709
  const errors = [];
2631
2710
  const pcbPorts = circuitJson.filter(
@@ -2716,10 +2795,13 @@ function checkTracesAreContiguous(circuitJson) {
2716
2795
  port.pcb_port_id
2717
2796
  ).replace("pcb_port", "");
2718
2797
  const padType = pads[0].type.replace(/pcb_/, "");
2719
- const errorCenter = {
2720
- x: (firstPoint.x + lastPoint.x) / 2,
2721
- y: (firstPoint.y + lastPoint.y) / 2
2722
- };
2798
+ const errorCenter = getMissingConnectionErrorCenter({
2799
+ firstPoint,
2800
+ lastPoint,
2801
+ port,
2802
+ expectedPorts,
2803
+ padMap
2804
+ });
2723
2805
  errors.push({
2724
2806
  type: "pcb_trace_error",
2725
2807
  message: `Trace [${traceName}] is missing a connection to ${padType}${portName}`,