@tscircuit/checks 0.0.117 → 0.0.118
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.d.ts +15 -5
- package/dist/index.js +316 -75
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as circuit_json from 'circuit-json';
|
|
2
|
-
import { AnyCircuitElement, PcbPortNotConnectedError, PcbTraceError, PcbPlacementError, PcbComponentOutsideBoardError, PcbViaClearanceError, PcbTraceWarning, PcbTraceMissingError, PcbFootprintOverlapError, SourceComponentPinsUnderspecifiedWarning, SourceNoPowerPinDefinedWarning, SourceNoGroundPinDefinedWarning, PcbConnectorNotInAccessibleOrientationWarning } from 'circuit-json';
|
|
2
|
+
import { AnyCircuitElement, PcbPortNotConnectedError, PcbTraceError, PcbPlacementError, PcbComponentOutsideBoardError, PcbViaClearanceError, PcbTraceWarning, PcbTraceMissingError, PcbFootprintOverlapError, PcbPadPadClearanceError, PcbPadTraceClearanceError, SourceComponentPinsUnderspecifiedWarning, SourceNoPowerPinDefinedWarning, SourceNoGroundPinDefinedWarning, PcbConnectorNotInAccessibleOrientationWarning } from 'circuit-json';
|
|
3
3
|
import { ConnectivityMap } from 'circuit-json-to-connectivity-map';
|
|
4
4
|
|
|
5
5
|
declare function checkEachPcbPortConnectedToPcbTraces(circuitJson: AnyCircuitElement[]): PcbPortNotConnectedError[];
|
|
@@ -61,6 +61,16 @@ declare function checkPcbTracesOutOfBoard(circuitJson: AnyCircuitElement[], conf
|
|
|
61
61
|
*/
|
|
62
62
|
declare function checkPcbComponentOverlap(circuitJson: AnyCircuitElement[]): PcbFootprintOverlapError[];
|
|
63
63
|
|
|
64
|
+
declare function checkPadPadClearance(circuitJson: AnyCircuitElement[], { connMap, minSpacing, }?: {
|
|
65
|
+
connMap?: ConnectivityMap;
|
|
66
|
+
minSpacing?: number;
|
|
67
|
+
}): PcbPadPadClearanceError[];
|
|
68
|
+
|
|
69
|
+
declare function checkPadTraceClearance(circuitJson: AnyCircuitElement[], { connMap, minSpacing, }?: {
|
|
70
|
+
connMap?: ConnectivityMap;
|
|
71
|
+
minSpacing?: number;
|
|
72
|
+
}): PcbPadTraceClearanceError[];
|
|
73
|
+
|
|
64
74
|
type SourcePinMustBeConnectedError = {
|
|
65
75
|
type: "source_pin_must_be_connected_error";
|
|
66
76
|
source_pin_must_be_connected_error_id: string;
|
|
@@ -96,7 +106,7 @@ declare function checkNoPowerPinDefined(circuitJson: AnyCircuitElement[]): Sourc
|
|
|
96
106
|
*/
|
|
97
107
|
declare function checkNoGroundPinDefined(circuitJson: AnyCircuitElement[]): SourceNoGroundPinDefinedWarning[];
|
|
98
108
|
|
|
99
|
-
declare function runAllPlacementChecks(circuitJson: AnyCircuitElement[]): Promise<(circuit_json.PcbPlacementError | circuit_json.PcbComponentOutsideBoardError | circuit_json.PcbFootprintOverlapError | circuit_json.
|
|
109
|
+
declare function runAllPlacementChecks(circuitJson: AnyCircuitElement[]): Promise<(circuit_json.PcbPlacementError | circuit_json.PcbComponentOutsideBoardError | circuit_json.PcbFootprintOverlapError | circuit_json.PcbPadPadClearanceError | circuit_json.PcbPadTraceClearanceError | circuit_json.PcbConnectorNotInAccessibleOrientationWarning | circuit_json.PcbCourtyardOverlapError)[]>;
|
|
100
110
|
declare function runAllNetlistChecks(circuitJson: AnyCircuitElement[]): Promise<{
|
|
101
111
|
type: "source_pin_must_be_connected_error";
|
|
102
112
|
source_pin_must_be_connected_error_id: string;
|
|
@@ -108,7 +118,7 @@ declare function runAllNetlistChecks(circuitJson: AnyCircuitElement[]): Promise<
|
|
|
108
118
|
}[]>;
|
|
109
119
|
declare function runAllPinSpecificationChecks(circuitJson: AnyCircuitElement[]): Promise<(circuit_json.SourceComponentPinsUnderspecifiedWarning | circuit_json.SourceNoPowerPinDefinedWarning | circuit_json.SourceNoGroundPinDefinedWarning)[]>;
|
|
110
120
|
declare function runAllRoutingChecks(circuitJson: AnyCircuitElement[]): Promise<(circuit_json.PcbPortNotConnectedError | circuit_json.PcbTraceError | circuit_json.PcbViaClearanceError | circuit_json.PcbTraceMissingError)[]>;
|
|
111
|
-
declare function runAllChecks(circuitJson: AnyCircuitElement[]): Promise<(circuit_json.PcbPortNotConnectedError | circuit_json.PcbTraceError | circuit_json.PcbPlacementError | circuit_json.PcbComponentOutsideBoardError | circuit_json.PcbViaClearanceError | circuit_json.PcbTraceMissingError | circuit_json.PcbFootprintOverlapError | {
|
|
121
|
+
declare function runAllChecks(circuitJson: AnyCircuitElement[]): Promise<(circuit_json.PcbPortNotConnectedError | circuit_json.PcbTraceError | circuit_json.PcbPlacementError | circuit_json.PcbComponentOutsideBoardError | circuit_json.PcbViaClearanceError | circuit_json.PcbTraceMissingError | circuit_json.PcbFootprintOverlapError | circuit_json.PcbPadPadClearanceError | circuit_json.PcbPadTraceClearanceError | {
|
|
112
122
|
type: "source_pin_must_be_connected_error";
|
|
113
123
|
source_pin_must_be_connected_error_id: string;
|
|
114
124
|
error_type: "source_pin_must_be_connected_error";
|
|
@@ -116,8 +126,8 @@ declare function runAllChecks(circuitJson: AnyCircuitElement[]): Promise<(circui
|
|
|
116
126
|
source_component_id: string;
|
|
117
127
|
source_port_id: string;
|
|
118
128
|
subcircuit_id?: string;
|
|
119
|
-
} | circuit_json.SourceComponentPinsUnderspecifiedWarning | circuit_json.SourceNoPowerPinDefinedWarning | circuit_json.SourceNoGroundPinDefinedWarning | circuit_json.
|
|
129
|
+
} | circuit_json.SourceComponentPinsUnderspecifiedWarning | circuit_json.SourceNoPowerPinDefinedWarning | circuit_json.SourceNoGroundPinDefinedWarning | circuit_json.PcbConnectorNotInAccessibleOrientationWarning | circuit_json.PcbCourtyardOverlapError)[]>;
|
|
120
130
|
|
|
121
131
|
declare function checkConnectorAccessibleOrientation(circuitJson: AnyCircuitElement[]): PcbConnectorNotInAccessibleOrientationWarning[];
|
|
122
132
|
|
|
123
|
-
export { NetManager, checkAllPinsInComponentAreUnderspecified, checkConnectorAccessibleOrientation, checkDifferentNetViaSpacing, checkEachPcbPortConnectedToPcbTraces, checkEachPcbTraceNonOverlapping, checkNoGroundPinDefined, checkNoPowerPinDefined, checkPcbComponentOverlap, checkPcbComponentsOutOfBoard, checkPcbTracesOutOfBoard, checkPinMustBeConnected, checkSameNetViaSpacing, checkSourceTracesHavePcbTraces, checkSourceTracesMatchPcbTraceThickness, checkViasOffBoard, runAllChecks, runAllNetlistChecks, runAllPinSpecificationChecks, runAllPlacementChecks, runAllRoutingChecks };
|
|
133
|
+
export { NetManager, checkAllPinsInComponentAreUnderspecified, checkConnectorAccessibleOrientation, checkDifferentNetViaSpacing, checkEachPcbPortConnectedToPcbTraces, checkEachPcbTraceNonOverlapping, checkNoGroundPinDefined, checkNoPowerPinDefined, checkPadPadClearance, checkPadTraceClearance, checkPcbComponentOverlap, checkPcbComponentsOutOfBoard, checkPcbTracesOutOfBoard, checkPinMustBeConnected, checkSameNetViaSpacing, checkSourceTracesHavePcbTraces, checkSourceTracesMatchPcbTraceThickness, checkViasOffBoard, runAllChecks, runAllNetlistChecks, runAllPinSpecificationChecks, runAllPlacementChecks, runAllRoutingChecks };
|
package/dist/index.js
CHANGED
|
@@ -369,6 +369,8 @@ var DEFAULT_TRACE_THICKNESS = 0.15;
|
|
|
369
369
|
var DEFAULT_VIA_BOARD_MARGIN = 0.3;
|
|
370
370
|
var DEFAULT_SAME_NET_VIA_MARGIN = 0.2;
|
|
371
371
|
var DEFAULT_DIFFERENT_NET_VIA_MARGIN = 0.3;
|
|
372
|
+
var DEFAULT_PAD_PAD_CLEARANCE = 0.1;
|
|
373
|
+
var DEFAULT_PAD_TRACE_CLEARANCE = 0.1;
|
|
372
374
|
var EPSILON = 5e-3;
|
|
373
375
|
|
|
374
376
|
// lib/check-each-pcb-trace-non-overlapping/getPcbPortIdsConnectedToTraces.ts
|
|
@@ -1601,6 +1603,241 @@ function checkPcbComponentOverlap(circuitJson) {
|
|
|
1601
1603
|
return errors;
|
|
1602
1604
|
}
|
|
1603
1605
|
|
|
1606
|
+
// lib/check-pad-pad-clearance.ts
|
|
1607
|
+
import {
|
|
1608
|
+
getPrimaryId as getPrimaryId3,
|
|
1609
|
+
getReadableNameForElement as getReadableNameForElement6
|
|
1610
|
+
} from "@tscircuit/circuit-json-util";
|
|
1611
|
+
import {
|
|
1612
|
+
getFullConnectivityMapFromCircuitJson as getFullConnectivityMapFromCircuitJson7
|
|
1613
|
+
} from "circuit-json-to-connectivity-map";
|
|
1614
|
+
|
|
1615
|
+
// lib/check-pad-clearance/common.ts
|
|
1616
|
+
import {
|
|
1617
|
+
cju as cju5,
|
|
1618
|
+
distanceBetweenCircleAndCircle,
|
|
1619
|
+
distanceBetweenCircleAndPolygon,
|
|
1620
|
+
distanceBetweenPolygonAndPolygon,
|
|
1621
|
+
getBoundsOfPcbElements as getBoundsOfPcbElements5
|
|
1622
|
+
} from "@tscircuit/circuit-json-util";
|
|
1623
|
+
import { midpoint } from "@tscircuit/math-utils";
|
|
1624
|
+
var formatMm = (value) => {
|
|
1625
|
+
const rounded = Math.round(value * 1e3) / 1e3;
|
|
1626
|
+
return `${Number(rounded.toFixed(3))}mm`;
|
|
1627
|
+
};
|
|
1628
|
+
var getPadBounds = (pad) => getBoundsOfPcbElements5([pad]);
|
|
1629
|
+
var getPadCenter = (pad) => {
|
|
1630
|
+
const bounds = getPadBounds(pad);
|
|
1631
|
+
return midpoint(
|
|
1632
|
+
{ x: bounds.minX, y: bounds.minY },
|
|
1633
|
+
{ x: bounds.maxX, y: bounds.maxY }
|
|
1634
|
+
);
|
|
1635
|
+
};
|
|
1636
|
+
var getPadRadius = (pad) => {
|
|
1637
|
+
const bounds = getPadBounds(pad);
|
|
1638
|
+
return Math.min(bounds.maxX - bounds.minX, bounds.maxY - bounds.minY) / 2;
|
|
1639
|
+
};
|
|
1640
|
+
var isCircularPad = (pad) => pad.shape === "circle";
|
|
1641
|
+
var getCircleShape = (pad) => {
|
|
1642
|
+
const center = getPadCenter(pad);
|
|
1643
|
+
return {
|
|
1644
|
+
kind: "circle",
|
|
1645
|
+
x: center.x,
|
|
1646
|
+
y: center.y,
|
|
1647
|
+
radius: getPadRadius(pad)
|
|
1648
|
+
};
|
|
1649
|
+
};
|
|
1650
|
+
var getPolygonShape = (pad) => {
|
|
1651
|
+
const bounds = getPadBounds(pad);
|
|
1652
|
+
return {
|
|
1653
|
+
kind: "polygon",
|
|
1654
|
+
points: [
|
|
1655
|
+
{ x: bounds.minX, y: bounds.minY },
|
|
1656
|
+
{ x: bounds.maxX, y: bounds.minY },
|
|
1657
|
+
{ x: bounds.maxX, y: bounds.maxY },
|
|
1658
|
+
{ x: bounds.minX, y: bounds.maxY }
|
|
1659
|
+
]
|
|
1660
|
+
};
|
|
1661
|
+
};
|
|
1662
|
+
var getPadToPadGap = (padA, padB) => {
|
|
1663
|
+
if (isCircularPad(padA) && isCircularPad(padB)) {
|
|
1664
|
+
return distanceBetweenCircleAndCircle(
|
|
1665
|
+
getCircleShape(padA),
|
|
1666
|
+
getCircleShape(padB)
|
|
1667
|
+
);
|
|
1668
|
+
}
|
|
1669
|
+
if (isCircularPad(padA)) {
|
|
1670
|
+
return distanceBetweenCircleAndPolygon(
|
|
1671
|
+
getCircleShape(padA),
|
|
1672
|
+
getPolygonShape(padB)
|
|
1673
|
+
);
|
|
1674
|
+
}
|
|
1675
|
+
if (isCircularPad(padB)) {
|
|
1676
|
+
return distanceBetweenCircleAndPolygon(
|
|
1677
|
+
getCircleShape(padB),
|
|
1678
|
+
getPolygonShape(padA)
|
|
1679
|
+
);
|
|
1680
|
+
}
|
|
1681
|
+
return distanceBetweenPolygonAndPolygon(
|
|
1682
|
+
getPolygonShape(padA),
|
|
1683
|
+
getPolygonShape(padB)
|
|
1684
|
+
);
|
|
1685
|
+
};
|
|
1686
|
+
var getPads = (circuitJson) => [
|
|
1687
|
+
...cju5(circuitJson).pcb_smtpad.list(),
|
|
1688
|
+
...cju5(circuitJson).pcb_plated_hole.list()
|
|
1689
|
+
];
|
|
1690
|
+
var getTraceSegments = (circuitJson) => {
|
|
1691
|
+
const pcbTraces = cju5(circuitJson).pcb_trace.list();
|
|
1692
|
+
return pcbTraces.flatMap((pcbTrace) => {
|
|
1693
|
+
const segments = [];
|
|
1694
|
+
for (let i = 0; i < pcbTrace.route.length - 1; i++) {
|
|
1695
|
+
const p1 = pcbTrace.route[i];
|
|
1696
|
+
const p2 = pcbTrace.route[i + 1];
|
|
1697
|
+
if (p1.route_type !== "wire") continue;
|
|
1698
|
+
if (p2.route_type !== "wire") continue;
|
|
1699
|
+
if (p1.layer !== p2.layer) continue;
|
|
1700
|
+
segments.push({
|
|
1701
|
+
type: "pcb_trace_segment",
|
|
1702
|
+
pcb_trace_id: pcbTrace.pcb_trace_id,
|
|
1703
|
+
_pcbTrace: pcbTrace,
|
|
1704
|
+
thickness: "width" in p1 ? p1.width : "width" in p2 ? p2.width : DEFAULT_TRACE_THICKNESS,
|
|
1705
|
+
layer: p1.layer,
|
|
1706
|
+
x1: p1.x,
|
|
1707
|
+
y1: p1.y,
|
|
1708
|
+
x2: p2.x,
|
|
1709
|
+
y2: p2.y
|
|
1710
|
+
});
|
|
1711
|
+
}
|
|
1712
|
+
return segments;
|
|
1713
|
+
});
|
|
1714
|
+
};
|
|
1715
|
+
|
|
1716
|
+
// lib/check-pad-pad-clearance.ts
|
|
1717
|
+
function checkPadPadClearance(circuitJson, {
|
|
1718
|
+
connMap,
|
|
1719
|
+
minSpacing = DEFAULT_PAD_PAD_CLEARANCE
|
|
1720
|
+
} = {}) {
|
|
1721
|
+
const pads = getPads(circuitJson);
|
|
1722
|
+
if (pads.length < 2) return [];
|
|
1723
|
+
connMap ??= getFullConnectivityMapFromCircuitJson7(circuitJson);
|
|
1724
|
+
const spatialIndex = new SpatialObjectIndex({
|
|
1725
|
+
objects: pads,
|
|
1726
|
+
getBounds: getPadBounds,
|
|
1727
|
+
getId: (pad) => getPrimaryId3(pad)
|
|
1728
|
+
});
|
|
1729
|
+
const errors = /* @__PURE__ */ new Map();
|
|
1730
|
+
for (const padA of pads) {
|
|
1731
|
+
const padAId = getPrimaryId3(padA);
|
|
1732
|
+
const nearbyPads = spatialIndex.getObjectsInBounds(
|
|
1733
|
+
getPadBounds(padA),
|
|
1734
|
+
minSpacing
|
|
1735
|
+
);
|
|
1736
|
+
for (const padB of nearbyPads) {
|
|
1737
|
+
const padBId = getPrimaryId3(padB);
|
|
1738
|
+
if (padAId === padBId) continue;
|
|
1739
|
+
if (!getLayersOfPcbElement(padA).some(
|
|
1740
|
+
(layer) => getLayersOfPcbElement(padB).includes(layer)
|
|
1741
|
+
)) {
|
|
1742
|
+
continue;
|
|
1743
|
+
}
|
|
1744
|
+
if (connMap.areIdsConnected(padAId, padBId)) continue;
|
|
1745
|
+
const pairId = [padAId, padBId].sort().join("_");
|
|
1746
|
+
const gap = getPadToPadGap(padA, padB);
|
|
1747
|
+
if (gap + EPSILON >= minSpacing) continue;
|
|
1748
|
+
const centerA = getPadCenter(padA);
|
|
1749
|
+
const centerB = getPadCenter(padB);
|
|
1750
|
+
const nextError = {
|
|
1751
|
+
type: "pcb_pad_pad_clearance_error",
|
|
1752
|
+
pcb_pad_pad_clearance_error_id: `pad_pad_clearance_${pairId}`,
|
|
1753
|
+
error_type: "pcb_pad_pad_clearance_error",
|
|
1754
|
+
message: `Pads ${getReadableNameForElement6(circuitJson, padAId)} and ${getReadableNameForElement6(circuitJson, padBId)} are too close (clearance: ${formatMm(gap)}, minimum: ${formatMm(minSpacing)})`,
|
|
1755
|
+
pcb_pad_ids: [padAId, padBId],
|
|
1756
|
+
minimum_clearance: minSpacing,
|
|
1757
|
+
actual_clearance: gap,
|
|
1758
|
+
center: {
|
|
1759
|
+
x: (centerA.x + centerB.x) / 2,
|
|
1760
|
+
y: (centerA.y + centerB.y) / 2
|
|
1761
|
+
}
|
|
1762
|
+
};
|
|
1763
|
+
if (!errors.has(pairId)) {
|
|
1764
|
+
errors.set(pairId, nextError);
|
|
1765
|
+
}
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
return Array.from(errors.values());
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
// lib/check-pad-trace-clearance.ts
|
|
1772
|
+
import {
|
|
1773
|
+
getPrimaryId as getPrimaryId4,
|
|
1774
|
+
getReadableNameForElement as getReadableNameForElement7
|
|
1775
|
+
} from "@tscircuit/circuit-json-util";
|
|
1776
|
+
import {
|
|
1777
|
+
segmentToBoundsMinDistance as segmentToBoundsMinDistance2,
|
|
1778
|
+
segmentToCircleMinDistance as segmentToCircleMinDistance2
|
|
1779
|
+
} from "@tscircuit/math-utils";
|
|
1780
|
+
import {
|
|
1781
|
+
getFullConnectivityMapFromCircuitJson as getFullConnectivityMapFromCircuitJson8
|
|
1782
|
+
} from "circuit-json-to-connectivity-map";
|
|
1783
|
+
function checkPadTraceClearance(circuitJson, {
|
|
1784
|
+
connMap,
|
|
1785
|
+
minSpacing = DEFAULT_PAD_TRACE_CLEARANCE
|
|
1786
|
+
} = {}) {
|
|
1787
|
+
const pads = getPads(circuitJson);
|
|
1788
|
+
const segments = getTraceSegments(circuitJson);
|
|
1789
|
+
if (pads.length === 0 || segments.length === 0) return [];
|
|
1790
|
+
connMap ??= getFullConnectivityMapFromCircuitJson8(circuitJson);
|
|
1791
|
+
const spatialIndex = new SpatialObjectIndex({
|
|
1792
|
+
objects: pads,
|
|
1793
|
+
getBounds: getPadBounds,
|
|
1794
|
+
getId: (pad) => getPrimaryId4(pad)
|
|
1795
|
+
});
|
|
1796
|
+
const errors = /* @__PURE__ */ new Map();
|
|
1797
|
+
for (const segment of segments) {
|
|
1798
|
+
const nearbyPads = spatialIndex.getObjectsInBounds(
|
|
1799
|
+
getCollidableBounds(segment),
|
|
1800
|
+
minSpacing + segment.thickness / 2
|
|
1801
|
+
);
|
|
1802
|
+
for (const pad of nearbyPads) {
|
|
1803
|
+
const padId = getPrimaryId4(pad);
|
|
1804
|
+
if (!getLayersOfPcbElement(pad).includes(segment.layer)) continue;
|
|
1805
|
+
if (connMap.areIdsConnected(segment.pcb_trace_id, padId)) continue;
|
|
1806
|
+
const center = getPadCenter(pad);
|
|
1807
|
+
const gap = isCircularPad(pad) ? segmentToCircleMinDistance2(
|
|
1808
|
+
{ x: segment.x1, y: segment.y1 },
|
|
1809
|
+
{ x: segment.x2, y: segment.y2 },
|
|
1810
|
+
{ x: center.x, y: center.y, radius: getPadRadius(pad) }
|
|
1811
|
+
) - segment.thickness / 2 : segmentToBoundsMinDistance2(
|
|
1812
|
+
{ x: segment.x1, y: segment.y1 },
|
|
1813
|
+
{ x: segment.x2, y: segment.y2 },
|
|
1814
|
+
getPadBounds(pad)
|
|
1815
|
+
) - segment.thickness / 2;
|
|
1816
|
+
if (gap + EPSILON >= minSpacing) continue;
|
|
1817
|
+
const pairId = `${padId}_${segment.pcb_trace_id}`;
|
|
1818
|
+
const nextError = {
|
|
1819
|
+
type: "pcb_pad_trace_clearance_error",
|
|
1820
|
+
pcb_pad_trace_clearance_error_id: `pad_trace_clearance_${pairId}`,
|
|
1821
|
+
error_type: "pcb_pad_trace_clearance_error",
|
|
1822
|
+
message: `Pad ${getReadableNameForElement7(circuitJson, padId)} and trace ${getReadableNameForElement7(circuitJson, segment.pcb_trace_id)} are too close (clearance: ${formatMm(gap)}, minimum: ${formatMm(minSpacing)})`,
|
|
1823
|
+
pcb_pad_id: padId,
|
|
1824
|
+
pcb_trace_id: segment.pcb_trace_id,
|
|
1825
|
+
minimum_clearance: minSpacing,
|
|
1826
|
+
actual_clearance: gap,
|
|
1827
|
+
center: {
|
|
1828
|
+
x: (center.x + (segment.x1 + segment.x2) / 2) / 2,
|
|
1829
|
+
y: (center.y + (segment.y1 + segment.y2) / 2) / 2
|
|
1830
|
+
}
|
|
1831
|
+
};
|
|
1832
|
+
const current = errors.get(pairId);
|
|
1833
|
+
if (!current || gap < current.gap) {
|
|
1834
|
+
errors.set(pairId, { error: nextError, gap });
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1838
|
+
return Array.from(errors.values()).map(({ error }) => error);
|
|
1839
|
+
}
|
|
1840
|
+
|
|
1604
1841
|
// lib/check-pin-must-be-connected.ts
|
|
1605
1842
|
function checkPinMustBeConnected(circuitJson) {
|
|
1606
1843
|
const errors = [];
|
|
@@ -1660,7 +1897,7 @@ function checkPinMustBeConnected(circuitJson) {
|
|
|
1660
1897
|
}
|
|
1661
1898
|
|
|
1662
1899
|
// lib/check-all-pins-in-component-are-underspecified.ts
|
|
1663
|
-
import { cju as
|
|
1900
|
+
import { cju as cju6 } from "@tscircuit/circuit-json-util";
|
|
1664
1901
|
var PIN_ATTRIBUTE_KEYS = [
|
|
1665
1902
|
"must_be_connected",
|
|
1666
1903
|
"provides_power",
|
|
@@ -1705,7 +1942,7 @@ function hasAnyPinAttribute(port) {
|
|
|
1705
1942
|
}
|
|
1706
1943
|
function checkAllPinsInComponentAreUnderspecified(circuitJson) {
|
|
1707
1944
|
const warnings = [];
|
|
1708
|
-
const db =
|
|
1945
|
+
const db = cju6(circuitJson);
|
|
1709
1946
|
const sourceComponents = db.source_component.list();
|
|
1710
1947
|
const sourcePorts = db.source_port.list();
|
|
1711
1948
|
const portsByComponent = /* @__PURE__ */ new Map();
|
|
@@ -1737,10 +1974,10 @@ function checkAllPinsInComponentAreUnderspecified(circuitJson) {
|
|
|
1737
1974
|
}
|
|
1738
1975
|
|
|
1739
1976
|
// lib/check-no-power-pin-defined.ts
|
|
1740
|
-
import { cju as
|
|
1977
|
+
import { cju as cju7 } from "@tscircuit/circuit-json-util";
|
|
1741
1978
|
function checkNoPowerPinDefined(circuitJson) {
|
|
1742
1979
|
const warnings = [];
|
|
1743
|
-
const db =
|
|
1980
|
+
const db = cju7(circuitJson);
|
|
1744
1981
|
const sourceComponents = db.source_component.list();
|
|
1745
1982
|
const sourcePorts = db.source_port.list();
|
|
1746
1983
|
const portsByComponent = /* @__PURE__ */ new Map();
|
|
@@ -1772,10 +2009,10 @@ function checkNoPowerPinDefined(circuitJson) {
|
|
|
1772
2009
|
}
|
|
1773
2010
|
|
|
1774
2011
|
// lib/check-no-ground-pin-defined.ts
|
|
1775
|
-
import { cju as
|
|
2012
|
+
import { cju as cju8 } from "@tscircuit/circuit-json-util";
|
|
1776
2013
|
function checkNoGroundPinDefined(circuitJson) {
|
|
1777
2014
|
const warnings = [];
|
|
1778
|
-
const db =
|
|
2015
|
+
const db = cju8(circuitJson);
|
|
1779
2016
|
const sourceComponents = db.source_component.list();
|
|
1780
2017
|
const sourcePorts = db.source_port.list();
|
|
1781
2018
|
const portsByComponent = /* @__PURE__ */ new Map();
|
|
@@ -1806,6 +2043,75 @@ function checkNoGroundPinDefined(circuitJson) {
|
|
|
1806
2043
|
return warnings;
|
|
1807
2044
|
}
|
|
1808
2045
|
|
|
2046
|
+
// lib/check-connector-accessible-orientation.ts
|
|
2047
|
+
import { getBoardBounds } from "@tscircuit/circuit-json-util";
|
|
2048
|
+
function getFacingDirection(component) {
|
|
2049
|
+
if (!component.center || !component.cable_insertion_center) return null;
|
|
2050
|
+
const dx = component.cable_insertion_center.x - component.center.x;
|
|
2051
|
+
const dy = component.cable_insertion_center.y - component.center.y;
|
|
2052
|
+
if (Math.abs(dx) < 1e-6 && Math.abs(dy) < 1e-6) return null;
|
|
2053
|
+
if (Math.abs(dx) >= Math.abs(dy)) {
|
|
2054
|
+
return dx >= 0 ? "x+" : "x-";
|
|
2055
|
+
}
|
|
2056
|
+
return dy >= 0 ? "y+" : "y-";
|
|
2057
|
+
}
|
|
2058
|
+
function getRecommendedFacingDirection(component, bounds) {
|
|
2059
|
+
if (!component.center) return null;
|
|
2060
|
+
const distances = [
|
|
2061
|
+
{ direction: "x-", distance: component.center.x - bounds.minX },
|
|
2062
|
+
{ direction: "x+", distance: bounds.maxX - component.center.x },
|
|
2063
|
+
{ direction: "y-", distance: component.center.y - bounds.minY },
|
|
2064
|
+
{ direction: "y+", distance: bounds.maxY - component.center.y }
|
|
2065
|
+
];
|
|
2066
|
+
distances.sort((a, b) => a.distance - b.distance);
|
|
2067
|
+
return distances[0]?.direction ?? null;
|
|
2068
|
+
}
|
|
2069
|
+
function checkConnectorAccessibleOrientation(circuitJson) {
|
|
2070
|
+
const board = circuitJson.find(
|
|
2071
|
+
(el) => el.type === "pcb_board"
|
|
2072
|
+
);
|
|
2073
|
+
if (!board) return [];
|
|
2074
|
+
const bounds = (() => {
|
|
2075
|
+
try {
|
|
2076
|
+
return getBoardBounds(board);
|
|
2077
|
+
} catch {
|
|
2078
|
+
return null;
|
|
2079
|
+
}
|
|
2080
|
+
})();
|
|
2081
|
+
if (!bounds) return [];
|
|
2082
|
+
const warnings = [];
|
|
2083
|
+
const components = circuitJson.filter(
|
|
2084
|
+
(el) => el.type === "pcb_component"
|
|
2085
|
+
);
|
|
2086
|
+
for (const component of components) {
|
|
2087
|
+
if (!component.cable_insertion_center) continue;
|
|
2088
|
+
const facingDirection = getFacingDirection(component);
|
|
2089
|
+
const recommendedFacingDirection = getRecommendedFacingDirection(
|
|
2090
|
+
component,
|
|
2091
|
+
bounds
|
|
2092
|
+
);
|
|
2093
|
+
if (!facingDirection || !recommendedFacingDirection) continue;
|
|
2094
|
+
if (facingDirection === recommendedFacingDirection) continue;
|
|
2095
|
+
const componentName = getReadableNameForComponent(
|
|
2096
|
+
circuitJson,
|
|
2097
|
+
component.pcb_component_id
|
|
2098
|
+
);
|
|
2099
|
+
warnings.push({
|
|
2100
|
+
type: "pcb_connector_not_in_accessible_orientation_warning",
|
|
2101
|
+
warning_type: "pcb_connector_not_in_accessible_orientation_warning",
|
|
2102
|
+
pcb_connector_not_in_accessible_orientation_warning_id: `pcb_connector_not_in_accessible_orientation_warning_${component.pcb_component_id}`,
|
|
2103
|
+
message: `${componentName} is facing ${facingDirection} but should face ${recommendedFacingDirection} so the connector is accessible from the board edge`,
|
|
2104
|
+
pcb_component_id: component.pcb_component_id,
|
|
2105
|
+
source_component_id: component.source_component_id,
|
|
2106
|
+
pcb_board_id: board.pcb_board_id,
|
|
2107
|
+
facing_direction: facingDirection,
|
|
2108
|
+
recommended_facing_direction: recommendedFacingDirection,
|
|
2109
|
+
subcircuit_id: component.subcircuit_id
|
|
2110
|
+
});
|
|
2111
|
+
}
|
|
2112
|
+
return warnings;
|
|
2113
|
+
}
|
|
2114
|
+
|
|
1809
2115
|
// lib/check-courtyard-overlap/checkCourtyardOverlap.ts
|
|
1810
2116
|
import {
|
|
1811
2117
|
doSegmentsIntersect,
|
|
@@ -1912,75 +2218,6 @@ function checkCourtyardOverlap(circuitJson) {
|
|
|
1912
2218
|
return errors;
|
|
1913
2219
|
}
|
|
1914
2220
|
|
|
1915
|
-
// lib/check-connector-accessible-orientation.ts
|
|
1916
|
-
import { getBoardBounds } from "@tscircuit/circuit-json-util";
|
|
1917
|
-
function getFacingDirection(component) {
|
|
1918
|
-
if (!component.center || !component.cable_insertion_center) return null;
|
|
1919
|
-
const dx = component.cable_insertion_center.x - component.center.x;
|
|
1920
|
-
const dy = component.cable_insertion_center.y - component.center.y;
|
|
1921
|
-
if (Math.abs(dx) < 1e-6 && Math.abs(dy) < 1e-6) return null;
|
|
1922
|
-
if (Math.abs(dx) >= Math.abs(dy)) {
|
|
1923
|
-
return dx >= 0 ? "x+" : "x-";
|
|
1924
|
-
}
|
|
1925
|
-
return dy >= 0 ? "y+" : "y-";
|
|
1926
|
-
}
|
|
1927
|
-
function getRecommendedFacingDirection(component, bounds) {
|
|
1928
|
-
if (!component.center) return null;
|
|
1929
|
-
const distances = [
|
|
1930
|
-
{ direction: "x-", distance: component.center.x - bounds.minX },
|
|
1931
|
-
{ direction: "x+", distance: bounds.maxX - component.center.x },
|
|
1932
|
-
{ direction: "y-", distance: component.center.y - bounds.minY },
|
|
1933
|
-
{ direction: "y+", distance: bounds.maxY - component.center.y }
|
|
1934
|
-
];
|
|
1935
|
-
distances.sort((a, b) => a.distance - b.distance);
|
|
1936
|
-
return distances[0]?.direction ?? null;
|
|
1937
|
-
}
|
|
1938
|
-
function checkConnectorAccessibleOrientation(circuitJson) {
|
|
1939
|
-
const board = circuitJson.find(
|
|
1940
|
-
(el) => el.type === "pcb_board"
|
|
1941
|
-
);
|
|
1942
|
-
if (!board) return [];
|
|
1943
|
-
const bounds = (() => {
|
|
1944
|
-
try {
|
|
1945
|
-
return getBoardBounds(board);
|
|
1946
|
-
} catch {
|
|
1947
|
-
return null;
|
|
1948
|
-
}
|
|
1949
|
-
})();
|
|
1950
|
-
if (!bounds) return [];
|
|
1951
|
-
const warnings = [];
|
|
1952
|
-
const components = circuitJson.filter(
|
|
1953
|
-
(el) => el.type === "pcb_component"
|
|
1954
|
-
);
|
|
1955
|
-
for (const component of components) {
|
|
1956
|
-
if (!component.cable_insertion_center) continue;
|
|
1957
|
-
const facingDirection = getFacingDirection(component);
|
|
1958
|
-
const recommendedFacingDirection = getRecommendedFacingDirection(
|
|
1959
|
-
component,
|
|
1960
|
-
bounds
|
|
1961
|
-
);
|
|
1962
|
-
if (!facingDirection || !recommendedFacingDirection) continue;
|
|
1963
|
-
if (facingDirection === recommendedFacingDirection) continue;
|
|
1964
|
-
const componentName = getReadableNameForComponent(
|
|
1965
|
-
circuitJson,
|
|
1966
|
-
component.pcb_component_id
|
|
1967
|
-
);
|
|
1968
|
-
warnings.push({
|
|
1969
|
-
type: "pcb_connector_not_in_accessible_orientation_warning",
|
|
1970
|
-
warning_type: "pcb_connector_not_in_accessible_orientation_warning",
|
|
1971
|
-
pcb_connector_not_in_accessible_orientation_warning_id: `pcb_connector_not_in_accessible_orientation_warning_${component.pcb_component_id}`,
|
|
1972
|
-
message: `${componentName} is facing ${facingDirection} but should face ${recommendedFacingDirection} so the connector is accessible from the board edge`,
|
|
1973
|
-
pcb_component_id: component.pcb_component_id,
|
|
1974
|
-
source_component_id: component.source_component_id,
|
|
1975
|
-
pcb_board_id: board.pcb_board_id,
|
|
1976
|
-
facing_direction: facingDirection,
|
|
1977
|
-
recommended_facing_direction: recommendedFacingDirection,
|
|
1978
|
-
subcircuit_id: component.subcircuit_id
|
|
1979
|
-
});
|
|
1980
|
-
}
|
|
1981
|
-
return warnings;
|
|
1982
|
-
}
|
|
1983
|
-
|
|
1984
2221
|
// lib/check-traces-are-contiguous/check-traces-are-contiguous.ts
|
|
1985
2222
|
import { getReadableNameForPcbPort as getReadableNameForPcbPort2 } from "@tscircuit/circuit-json-util";
|
|
1986
2223
|
|
|
@@ -1990,6 +2227,8 @@ async function runAllPlacementChecks(circuitJson) {
|
|
|
1990
2227
|
...checkViasOffBoard(circuitJson),
|
|
1991
2228
|
...checkPcbComponentsOutOfBoard(circuitJson),
|
|
1992
2229
|
...checkPcbComponentOverlap(circuitJson),
|
|
2230
|
+
...checkPadPadClearance(circuitJson),
|
|
2231
|
+
...checkPadTraceClearance(circuitJson),
|
|
1993
2232
|
...checkCourtyardOverlap(circuitJson),
|
|
1994
2233
|
...checkConnectorAccessibleOrientation(circuitJson)
|
|
1995
2234
|
];
|
|
@@ -2032,6 +2271,8 @@ export {
|
|
|
2032
2271
|
checkEachPcbTraceNonOverlapping,
|
|
2033
2272
|
checkNoGroundPinDefined,
|
|
2034
2273
|
checkNoPowerPinDefined,
|
|
2274
|
+
checkPadPadClearance,
|
|
2275
|
+
checkPadTraceClearance,
|
|
2035
2276
|
checkPcbComponentOverlap,
|
|
2036
2277
|
checkPcbComponentsOutOfBoard,
|
|
2037
2278
|
checkPcbTracesOutOfBoard,
|