@tscircuit/checks 0.0.157 → 0.0.159
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 +7 -1
- package/dist/index.js +132 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -23,6 +23,12 @@ declare function checkViasOffBoard(circuitJson: AnyCircuitElement[]): PcbPlaceme
|
|
|
23
23
|
*/
|
|
24
24
|
declare function checkPcbComponentsOutOfBoard(circuitJson: AnyCircuitElement[]): PcbComponentOutsideBoardError[];
|
|
25
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Cutouts remove PCB material on every layer, so a component body or SMT pad
|
|
28
|
+
* overlapping a cutout is invalid on both top and bottom.
|
|
29
|
+
*/
|
|
30
|
+
declare function checkPcbComponentOverCutout(circuitJson: AnyCircuitElement[]): PcbPlacementError[];
|
|
31
|
+
|
|
26
32
|
declare function checkSameNetViaSpacing(circuitJson: AnyCircuitElement[], { connMap, minClearance, }?: {
|
|
27
33
|
connMap?: ConnectivityMap;
|
|
28
34
|
minClearance?: number;
|
|
@@ -166,4 +172,4 @@ declare function checkConnectorAccessibleOrientation(circuitJson: AnyCircuitElem
|
|
|
166
172
|
*/
|
|
167
173
|
declare function checkTestPointAccessibility(circuitJson: AnyCircuitElement[]): PcbPlacementError[];
|
|
168
174
|
|
|
169
|
-
export { NetManager, checkAllPinsInComponentAreUnderspecified, checkConnectorAccessibleOrientation, checkDifferentNetViaSpacing, checkEachPcbPortConnectedToPcbTraces, checkEachPcbTraceNonOverlapping, checkNoGroundPinDefined, checkNoPowerPinDefined, checkPadPadClearance, checkPadTraceClearance, checkPcbComponentOverlap, checkPcbComponentsOutOfBoard, checkPcbTraceLengths, checkPcbTracesOutOfBoard, checkPinMustBeConnected, checkSameNetViaSpacing, checkSourceTracesHavePcbTraces, checkSourceTracesMatchPcbTraceThickness, checkTestPointAccessibility, checkTracesAreContiguous, checkViaPadClearance, checkViaTraceClearance, checkViasInPads, checkViasOffBoard, dedupePcbDrcErrors, runAllChecks, runAllNetlistChecks, runAllPinSpecificationChecks, runAllPlacementChecks, runAllRoutingChecks };
|
|
175
|
+
export { NetManager, checkAllPinsInComponentAreUnderspecified, checkConnectorAccessibleOrientation, checkDifferentNetViaSpacing, checkEachPcbPortConnectedToPcbTraces, checkEachPcbTraceNonOverlapping, checkNoGroundPinDefined, checkNoPowerPinDefined, checkPadPadClearance, checkPadTraceClearance, checkPcbComponentOverCutout, checkPcbComponentOverlap, checkPcbComponentsOutOfBoard, checkPcbTraceLengths, checkPcbTracesOutOfBoard, checkPinMustBeConnected, checkSameNetViaSpacing, checkSourceTracesHavePcbTraces, checkSourceTracesMatchPcbTraceThickness, checkTestPointAccessibility, checkTracesAreContiguous, checkViaPadClearance, checkViaTraceClearance, checkViasInPads, checkViasOffBoard, dedupePcbDrcErrors, runAllChecks, runAllNetlistChecks, runAllPinSpecificationChecks, runAllPlacementChecks, runAllRoutingChecks };
|
package/dist/index.js
CHANGED
|
@@ -1789,6 +1789,132 @@ function checkPcbComponentsOutOfBoard(circuitJson) {
|
|
|
1789
1789
|
return errors;
|
|
1790
1790
|
}
|
|
1791
1791
|
|
|
1792
|
+
// lib/check-pcb-component-over-cutout.ts
|
|
1793
|
+
import { doBoundsOverlap } from "@tscircuit/math-utils";
|
|
1794
|
+
import * as Flatten2 from "@flatten-js/core";
|
|
1795
|
+
import { applyToPoint as applyToPoint2, rotateDEG as rotateDEG2 } from "transformation-matrix";
|
|
1796
|
+
var CUTOUT_CIRCLE_SEGMENTS = 32;
|
|
1797
|
+
function rectanglePolygon2({
|
|
1798
|
+
center,
|
|
1799
|
+
width,
|
|
1800
|
+
height,
|
|
1801
|
+
rotation = 0
|
|
1802
|
+
}) {
|
|
1803
|
+
const halfWidth = width / 2;
|
|
1804
|
+
const halfHeight = height / 2;
|
|
1805
|
+
const corners = [
|
|
1806
|
+
{ x: center.x - halfWidth, y: center.y - halfHeight },
|
|
1807
|
+
{ x: center.x + halfWidth, y: center.y - halfHeight },
|
|
1808
|
+
{ x: center.x + halfWidth, y: center.y + halfHeight },
|
|
1809
|
+
{ x: center.x - halfWidth, y: center.y + halfHeight }
|
|
1810
|
+
];
|
|
1811
|
+
const matrix = rotateDEG2(rotation, center.x, center.y);
|
|
1812
|
+
return new Flatten2.Polygon(
|
|
1813
|
+
corners.map((corner) => {
|
|
1814
|
+
const rotated = rotation ? applyToPoint2(matrix, corner) : corner;
|
|
1815
|
+
return new Flatten2.Point(rotated.x, rotated.y);
|
|
1816
|
+
})
|
|
1817
|
+
);
|
|
1818
|
+
}
|
|
1819
|
+
function circlePolygon({
|
|
1820
|
+
center,
|
|
1821
|
+
radius
|
|
1822
|
+
}) {
|
|
1823
|
+
return new Flatten2.Polygon(
|
|
1824
|
+
Array.from({ length: CUTOUT_CIRCLE_SEGMENTS }, (_, index) => {
|
|
1825
|
+
const angle = 2 * Math.PI * index / CUTOUT_CIRCLE_SEGMENTS;
|
|
1826
|
+
return new Flatten2.Point(
|
|
1827
|
+
center.x + Math.cos(angle) * radius,
|
|
1828
|
+
center.y + Math.sin(angle) * radius
|
|
1829
|
+
);
|
|
1830
|
+
})
|
|
1831
|
+
);
|
|
1832
|
+
}
|
|
1833
|
+
function cutoutToPolygon(cutout) {
|
|
1834
|
+
if (cutout.shape === "rect") {
|
|
1835
|
+
return rectanglePolygon2({
|
|
1836
|
+
center: cutout.center,
|
|
1837
|
+
width: cutout.width,
|
|
1838
|
+
height: cutout.height,
|
|
1839
|
+
rotation: cutout.rotation ?? 0
|
|
1840
|
+
});
|
|
1841
|
+
}
|
|
1842
|
+
if (cutout.shape === "circle") {
|
|
1843
|
+
return circlePolygon({ center: cutout.center, radius: cutout.radius });
|
|
1844
|
+
}
|
|
1845
|
+
if (cutout.shape === "polygon") {
|
|
1846
|
+
return new Flatten2.Polygon(
|
|
1847
|
+
cutout.points.map((point) => new Flatten2.Point(point.x, point.y))
|
|
1848
|
+
);
|
|
1849
|
+
}
|
|
1850
|
+
return null;
|
|
1851
|
+
}
|
|
1852
|
+
function polygonBoxToBounds(polygon) {
|
|
1853
|
+
return {
|
|
1854
|
+
minX: polygon.box.xmin,
|
|
1855
|
+
minY: polygon.box.ymin,
|
|
1856
|
+
maxX: polygon.box.xmax,
|
|
1857
|
+
maxY: polygon.box.ymax
|
|
1858
|
+
};
|
|
1859
|
+
}
|
|
1860
|
+
function doPolygonsOverlap(polygonA, polygonB) {
|
|
1861
|
+
if (!doBoundsOverlap(polygonBoxToBounds(polygonA), polygonBoxToBounds(polygonB))) {
|
|
1862
|
+
return false;
|
|
1863
|
+
}
|
|
1864
|
+
if (polygonA.contains(polygonB) || polygonB.contains(polygonA)) return true;
|
|
1865
|
+
try {
|
|
1866
|
+
const intersections = Flatten2.BooleanOperations.intersect(
|
|
1867
|
+
polygonA,
|
|
1868
|
+
polygonB
|
|
1869
|
+
);
|
|
1870
|
+
if (Array.isArray(intersections)) {
|
|
1871
|
+
return intersections.some((polygon) => polygon.area() > 0);
|
|
1872
|
+
}
|
|
1873
|
+
return intersections.area() > 0;
|
|
1874
|
+
} catch {
|
|
1875
|
+
return false;
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1878
|
+
function checkPcbComponentOverCutout(circuitJson) {
|
|
1879
|
+
const cutouts = circuitJson.filter(
|
|
1880
|
+
(element) => element.type === "pcb_cutout"
|
|
1881
|
+
);
|
|
1882
|
+
const components = circuitJson.filter(
|
|
1883
|
+
(element) => element.type === "pcb_component"
|
|
1884
|
+
);
|
|
1885
|
+
if (cutouts.length === 0 || components.length === 0) return [];
|
|
1886
|
+
const cutoutPolygons = cutouts.map((cutout) => ({ cutout, polygon: cutoutToPolygon(cutout) })).filter(
|
|
1887
|
+
(entry) => entry.polygon !== null && entry.polygon.area() > 0
|
|
1888
|
+
);
|
|
1889
|
+
const errors = [];
|
|
1890
|
+
for (const component of components) {
|
|
1891
|
+
if (!component.center || component.width <= 0 || component.height <= 0) {
|
|
1892
|
+
continue;
|
|
1893
|
+
}
|
|
1894
|
+
const componentPolygon = rectanglePolygon2({
|
|
1895
|
+
center: component.center,
|
|
1896
|
+
width: component.width,
|
|
1897
|
+
height: component.height
|
|
1898
|
+
});
|
|
1899
|
+
for (const { cutout, polygon: cutoutPolygon } of cutoutPolygons) {
|
|
1900
|
+
if (!doPolygonsOverlap(componentPolygon, cutoutPolygon)) continue;
|
|
1901
|
+
const componentName = getReadableNameForComponent(
|
|
1902
|
+
circuitJson,
|
|
1903
|
+
component.pcb_component_id
|
|
1904
|
+
);
|
|
1905
|
+
const cutoutId = cutout.pcb_cutout_id;
|
|
1906
|
+
errors.push({
|
|
1907
|
+
type: "pcb_placement_error",
|
|
1908
|
+
pcb_placement_error_id: `component_over_cutout_${component.pcb_component_id}_${cutoutId}`,
|
|
1909
|
+
error_type: "pcb_placement_error",
|
|
1910
|
+
message: `Component ${componentName} overlaps with pcb_cutout [${cutoutId}]`,
|
|
1911
|
+
subcircuit_id: component.subcircuit_id
|
|
1912
|
+
});
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
return errors;
|
|
1916
|
+
}
|
|
1917
|
+
|
|
1792
1918
|
// lib/check-same-net-via-spacing.ts
|
|
1793
1919
|
import { getReadableNameForElement as getReadableNameForElement4 } from "@tscircuit/circuit-json-util";
|
|
1794
1920
|
import {
|
|
@@ -2377,12 +2503,12 @@ import {
|
|
|
2377
2503
|
getBoundsOfPcbElements as getBoundsOfPcbElements5,
|
|
2378
2504
|
getPrimaryId as getPrimaryId2
|
|
2379
2505
|
} from "@tscircuit/circuit-json-util";
|
|
2380
|
-
import { doBoundsOverlap as
|
|
2506
|
+
import { doBoundsOverlap as doBoundsOverlap3 } from "@tscircuit/math-utils";
|
|
2381
2507
|
import { getFullConnectivityMapFromCircuitJson as getFullConnectivityMapFromCircuitJson7 } from "circuit-json-to-connectivity-map";
|
|
2382
2508
|
|
|
2383
2509
|
// lib/check-pcb-components-overlap/doPcbElementsOverlap.ts
|
|
2384
2510
|
import { getBoundsOfPcbElements as getBoundsOfPcbElements4 } from "@tscircuit/circuit-json-util";
|
|
2385
|
-
import { doBoundsOverlap } from "@tscircuit/math-utils";
|
|
2511
|
+
import { doBoundsOverlap as doBoundsOverlap2 } from "@tscircuit/math-utils";
|
|
2386
2512
|
function getElementLayers(elem) {
|
|
2387
2513
|
if (elem.type === "pcb_courtyard_circle" || elem.type === "pcb_courtyard_outline" || elem.type === "pcb_courtyard_polygon" || elem.type === "pcb_courtyard_rect") {
|
|
2388
2514
|
return [elem.layer];
|
|
@@ -2402,7 +2528,7 @@ function doPcbElementsOverlap(elem1, elem2) {
|
|
|
2402
2528
|
}
|
|
2403
2529
|
const bounds1 = getBoundsOfPcbElements4([elem1]);
|
|
2404
2530
|
const bounds2 = getBoundsOfPcbElements4([elem2]);
|
|
2405
|
-
return
|
|
2531
|
+
return doBoundsOverlap2(bounds1, bounds2);
|
|
2406
2532
|
}
|
|
2407
2533
|
|
|
2408
2534
|
// lib/check-pcb-components-overlap/checkPcbComponentOverlap.ts
|
|
@@ -2475,7 +2601,7 @@ function checkPcbComponentOverlap(circuitJson) {
|
|
|
2475
2601
|
if (!comp1.bounds || !comp2.bounds) {
|
|
2476
2602
|
continue;
|
|
2477
2603
|
}
|
|
2478
|
-
if (!
|
|
2604
|
+
if (!doBoundsOverlap3(comp1.bounds, comp2.bounds)) {
|
|
2479
2605
|
continue;
|
|
2480
2606
|
}
|
|
2481
2607
|
for (const elem1 of comp1.elements) {
|
|
@@ -3385,6 +3511,7 @@ async function runAllPlacementChecks(circuitJson) {
|
|
|
3385
3511
|
...checkViasOffBoard(circuitJson),
|
|
3386
3512
|
...checkViasInPads(circuitJson),
|
|
3387
3513
|
...checkPcbComponentsOutOfBoard(circuitJson),
|
|
3514
|
+
...checkPcbComponentOverCutout(circuitJson),
|
|
3388
3515
|
...checkPcbComponentOverlap(circuitJson),
|
|
3389
3516
|
...checkPadPadClearance(circuitJson),
|
|
3390
3517
|
...checkCourtyardOverlap(circuitJson),
|
|
@@ -3436,6 +3563,7 @@ export {
|
|
|
3436
3563
|
checkNoPowerPinDefined,
|
|
3437
3564
|
checkPadPadClearance,
|
|
3438
3565
|
checkPadTraceClearance,
|
|
3566
|
+
checkPcbComponentOverCutout,
|
|
3439
3567
|
checkPcbComponentOverlap,
|
|
3440
3568
|
checkPcbComponentsOutOfBoard,
|
|
3441
3569
|
checkPcbTraceLengths,
|