@tscircuit/checks 0.0.206 → 0.0.208
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 +181 -19
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -714,7 +714,172 @@ import {
|
|
|
714
714
|
findConnectedNetworks,
|
|
715
715
|
PcbConnectivityMap
|
|
716
716
|
} from "circuit-json-to-connectivity-map";
|
|
717
|
+
import Flatbush3 from "flatbush";
|
|
718
|
+
|
|
719
|
+
// lib/util/get-via-and-pour-connections.ts
|
|
720
|
+
import { all_layers } from "circuit-json";
|
|
721
|
+
import {
|
|
722
|
+
getPourPolygon,
|
|
723
|
+
getTraceSegmentPolygon,
|
|
724
|
+
getViaPolygon
|
|
725
|
+
} from "@tscircuit/circuit-json-util";
|
|
717
726
|
import Flatbush2 from "flatbush";
|
|
727
|
+
|
|
728
|
+
// lib/copper-pour-connectivity/create-copper-polygon-contact-tester.ts
|
|
729
|
+
import {
|
|
730
|
+
Box
|
|
731
|
+
} from "@flatten-js/core";
|
|
732
|
+
function createCopperPolygonContactTester(tolerance) {
|
|
733
|
+
const cache = /* @__PURE__ */ new WeakMap();
|
|
734
|
+
const getGeometry = (polygon) => {
|
|
735
|
+
let geometry = cache.get(polygon);
|
|
736
|
+
if (!geometry) {
|
|
737
|
+
geometry = {
|
|
738
|
+
box: polygon.box,
|
|
739
|
+
facePoints: [...polygon.faces].map((face) => face.first.start),
|
|
740
|
+
edges: [...polygon.edges].map((edge) => edge.shape),
|
|
741
|
+
edgeIndex: polygon.edges
|
|
742
|
+
};
|
|
743
|
+
cache.set(polygon, geometry);
|
|
744
|
+
}
|
|
745
|
+
return geometry;
|
|
746
|
+
};
|
|
747
|
+
return (a, b) => {
|
|
748
|
+
if (a.isEmpty() || b.isEmpty()) return false;
|
|
749
|
+
const ga = getGeometry(a);
|
|
750
|
+
const gb = getGeometry(b);
|
|
751
|
+
if (ga.box.xmin > gb.box.xmax + tolerance || ga.box.xmax < gb.box.xmin - tolerance || ga.box.ymin > gb.box.ymax + tolerance || ga.box.ymax < gb.box.ymin - tolerance)
|
|
752
|
+
return false;
|
|
753
|
+
if (ga.facePoints.some(
|
|
754
|
+
(point2) => gb.box.contains(point2) && b.contains(point2)
|
|
755
|
+
) || gb.facePoints.some((point2) => ga.box.contains(point2) && a.contains(point2)))
|
|
756
|
+
return true;
|
|
757
|
+
const [small, large] = ga.edges.length <= gb.edges.length ? [ga, gb] : [gb, ga];
|
|
758
|
+
for (const edge of small.edges) {
|
|
759
|
+
const box = edge.box;
|
|
760
|
+
const queryBox = new Box(
|
|
761
|
+
box.xmin - tolerance,
|
|
762
|
+
box.ymin - tolerance,
|
|
763
|
+
box.xmax + tolerance,
|
|
764
|
+
box.ymax + tolerance
|
|
765
|
+
);
|
|
766
|
+
const candidates = large.edgeIndex.search(
|
|
767
|
+
queryBox
|
|
768
|
+
);
|
|
769
|
+
for (const candidate of candidates) {
|
|
770
|
+
if (edge.distanceTo(candidate.shape)[0] <= tolerance) return true;
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
return false;
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
// lib/util/get-via-and-pour-connections.ts
|
|
778
|
+
function getViaAndPourConnections(circuit) {
|
|
779
|
+
if (!circuit.some(
|
|
780
|
+
(e) => e.type === "pcb_via" || e.type === "pcb_copper_pour" || e.type === "pcb_trace" && e.route.some((p) => p.route_type === "via")
|
|
781
|
+
))
|
|
782
|
+
return [];
|
|
783
|
+
const conductors = [];
|
|
784
|
+
const connections = [];
|
|
785
|
+
const scale = 1e6;
|
|
786
|
+
const tolerance = 1e-7 * scale;
|
|
787
|
+
const touches = createCopperPolygonContactTester(tolerance);
|
|
788
|
+
const add = (id, layers, polygon, bridges = false) => {
|
|
789
|
+
if (!polygon.isEmpty())
|
|
790
|
+
conductors.push({
|
|
791
|
+
id,
|
|
792
|
+
layers,
|
|
793
|
+
polygon: polygon.scale(scale, scale),
|
|
794
|
+
bridges
|
|
795
|
+
});
|
|
796
|
+
};
|
|
797
|
+
const vias = circuit.filter((e) => e.type === "pcb_via");
|
|
798
|
+
const board = circuit.find((e) => e.type === "pcb_board");
|
|
799
|
+
const stack = [
|
|
800
|
+
"top",
|
|
801
|
+
...all_layers.filter((l) => l.startsWith("inner")).slice(0, board ? Math.max(0, board.num_layers - 2) : void 0),
|
|
802
|
+
...board?.num_layers === 1 ? [] : ["bottom"]
|
|
803
|
+
];
|
|
804
|
+
for (const copper of circuit) {
|
|
805
|
+
if (copper.type === "pcb_via") {
|
|
806
|
+
add(
|
|
807
|
+
copper.pcb_via_id,
|
|
808
|
+
copper.layers,
|
|
809
|
+
getViaPolygon(copper, copper.outer_diameter, 0),
|
|
810
|
+
true
|
|
811
|
+
);
|
|
812
|
+
if (copper.pcb_trace_id)
|
|
813
|
+
connections.push([copper.pcb_via_id, copper.pcb_trace_id]);
|
|
814
|
+
} else if (copper.type === "pcb_copper_pour") {
|
|
815
|
+
add(
|
|
816
|
+
copper.pcb_copper_pour_id,
|
|
817
|
+
[copper.layer],
|
|
818
|
+
getPourPolygon(copper),
|
|
819
|
+
true
|
|
820
|
+
);
|
|
821
|
+
} else if (copper.type === "pcb_trace") {
|
|
822
|
+
if (copper.route_thickness_mode === "interpolated") continue;
|
|
823
|
+
for (let i = 0; i < copper.route.length; i++) {
|
|
824
|
+
const a = copper.route[i], b = copper.route[i + 1];
|
|
825
|
+
if (a.route_type === "wire" && b?.route_type === "wire" && a.layer === b.layer && (a.x !== b.x || a.y !== b.y)) {
|
|
826
|
+
add(
|
|
827
|
+
copper.pcb_trace_id,
|
|
828
|
+
[a.layer],
|
|
829
|
+
getTraceSegmentPolygon(a, b, a.width)
|
|
830
|
+
);
|
|
831
|
+
} else if (a.route_type === "via") {
|
|
832
|
+
if (vias.some(
|
|
833
|
+
(v) => v.pcb_trace_id === copper.pcb_trace_id && Math.hypot(v.x - a.x, v.y - a.y) < 1e-9
|
|
834
|
+
))
|
|
835
|
+
continue;
|
|
836
|
+
const from = stack.indexOf(a.from_layer), to = stack.indexOf(a.to_layer);
|
|
837
|
+
if (from < 0 || to < 0 || !a.outer_diameter) continue;
|
|
838
|
+
const via = {
|
|
839
|
+
type: "pcb_via",
|
|
840
|
+
pcb_via_id: `${copper.pcb_trace_id}_via_${i}`,
|
|
841
|
+
x: a.x,
|
|
842
|
+
y: a.y,
|
|
843
|
+
outer_diameter: a.outer_diameter,
|
|
844
|
+
hole_diameter: 0,
|
|
845
|
+
layers: stack.slice(Math.min(from, to), Math.max(from, to) + 1)
|
|
846
|
+
};
|
|
847
|
+
add(
|
|
848
|
+
copper.pcb_trace_id,
|
|
849
|
+
via.layers,
|
|
850
|
+
getViaPolygon(via, via.outer_diameter, 0),
|
|
851
|
+
true
|
|
852
|
+
);
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
if (!conductors.length) return connections;
|
|
858
|
+
const index = new Flatbush2(conductors.length);
|
|
859
|
+
for (const { polygon } of conductors) {
|
|
860
|
+
const b = polygon.box;
|
|
861
|
+
index.add(b.xmin, b.ymin, b.xmax, b.ymax);
|
|
862
|
+
}
|
|
863
|
+
index.finish();
|
|
864
|
+
for (const [i, a] of conductors.entries()) {
|
|
865
|
+
if (!a.bridges) continue;
|
|
866
|
+
const box = a.polygon.box;
|
|
867
|
+
for (const j of index.search(
|
|
868
|
+
box.xmin - tolerance,
|
|
869
|
+
box.ymin - tolerance,
|
|
870
|
+
box.xmax + tolerance,
|
|
871
|
+
box.ymax + tolerance
|
|
872
|
+
)) {
|
|
873
|
+
const b = conductors[j];
|
|
874
|
+
if (i === j || a.id === b.id || b.bridges && j < i || !a.layers.some((l) => b.layers.includes(l)))
|
|
875
|
+
continue;
|
|
876
|
+
if (touches(a.polygon, b.polygon)) connections.push([a.id, b.id]);
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
return connections;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
// lib/util/create-indexed-pcb-connectivity-map.ts
|
|
718
883
|
function createIndexedPcbConnectivityMap(circuitJson) {
|
|
719
884
|
const map = new PcbConnectivityMap();
|
|
720
885
|
map.circuitJson = circuitJson;
|
|
@@ -756,7 +921,7 @@ function createIndexedPcbConnectivityMap(circuitJson) {
|
|
|
756
921
|
}
|
|
757
922
|
const candidates = traces.map(() => /* @__PURE__ */ new Set());
|
|
758
923
|
for (const bounds of boundsByLayer.values()) {
|
|
759
|
-
const index = new
|
|
924
|
+
const index = new Flatbush3(bounds.length);
|
|
760
925
|
for (const box of bounds) index.add(box.minX, box.minY, box.maxX, box.maxY);
|
|
761
926
|
index.finish();
|
|
762
927
|
for (const box of bounds) {
|
|
@@ -795,6 +960,7 @@ function createIndexedPcbConnectivityMap(circuitJson) {
|
|
|
795
960
|
for (const connection of connectionsByPort.get(portId) ?? [])
|
|
796
961
|
connections.push(connection);
|
|
797
962
|
}
|
|
963
|
+
connections.push(...getViaAndPourConnections(circuitJson));
|
|
798
964
|
map.connMap = new ConnectivityMap(findConnectedNetworks(connections));
|
|
799
965
|
return map;
|
|
800
966
|
}
|
|
@@ -1267,16 +1433,16 @@ function getReadableNameForFootprintPad(circuitJson, pad, ordinal) {
|
|
|
1267
1433
|
// lib/copper-pour-connectivity/get-copper-pour-connectivity.ts
|
|
1268
1434
|
import {
|
|
1269
1435
|
getPrimaryId,
|
|
1270
|
-
copperPolygonsTouch,
|
|
1271
1436
|
getPlatedHolePolygon,
|
|
1272
|
-
getPourPolygon,
|
|
1437
|
+
getPourPolygon as getPourPolygon2,
|
|
1273
1438
|
getSmtPadPolygon,
|
|
1274
|
-
getTraceSegmentPolygon,
|
|
1275
|
-
getViaPolygon
|
|
1439
|
+
getTraceSegmentPolygon as getTraceSegmentPolygon2,
|
|
1440
|
+
getViaPolygon as getViaPolygon2
|
|
1276
1441
|
} from "@tscircuit/circuit-json-util";
|
|
1277
1442
|
function getCopperPourConnectivity(circuitJson, connectivity) {
|
|
1278
1443
|
const scale = 1e6;
|
|
1279
1444
|
const tolerance = 1e-7 * scale;
|
|
1445
|
+
const copperPolygonsTouch = createCopperPolygonContactTester(tolerance);
|
|
1280
1446
|
const conductors = [];
|
|
1281
1447
|
const pouredNets = /* @__PURE__ */ new Set();
|
|
1282
1448
|
const netForId = (id) => connectivity.getNetConnectedToId(id);
|
|
@@ -1294,7 +1460,7 @@ function getCopperPourConnectivity(circuitJson, connectivity) {
|
|
|
1294
1460
|
if (!netId) continue;
|
|
1295
1461
|
pouredNets.add(netId);
|
|
1296
1462
|
add({
|
|
1297
|
-
polygon:
|
|
1463
|
+
polygon: getPourPolygon2(pour),
|
|
1298
1464
|
layers: [pour.layer],
|
|
1299
1465
|
netId,
|
|
1300
1466
|
isPour: true
|
|
@@ -1315,7 +1481,7 @@ function getCopperPourConnectivity(circuitJson, connectivity) {
|
|
|
1315
1481
|
if (start.route_type !== "wire" || end.route_type !== "wire" || start.layer !== end.layer)
|
|
1316
1482
|
continue;
|
|
1317
1483
|
add({
|
|
1318
|
-
polygon:
|
|
1484
|
+
polygon: getTraceSegmentPolygon2(start, end, start.width),
|
|
1319
1485
|
layers: [start.layer],
|
|
1320
1486
|
netId: netId2
|
|
1321
1487
|
});
|
|
@@ -1345,7 +1511,7 @@ function getCopperPourConnectivity(circuitJson, connectivity) {
|
|
|
1345
1511
|
});
|
|
1346
1512
|
} else {
|
|
1347
1513
|
add({
|
|
1348
|
-
polygon:
|
|
1514
|
+
polygon: getViaPolygon2(
|
|
1349
1515
|
copper,
|
|
1350
1516
|
copper.outer_diameter,
|
|
1351
1517
|
copper.hole_diameter
|
|
@@ -1380,11 +1546,7 @@ function getCopperPourConnectivity(circuitJson, connectivity) {
|
|
|
1380
1546
|
(layer) => conductors[j].layers.includes(layer)
|
|
1381
1547
|
))
|
|
1382
1548
|
continue;
|
|
1383
|
-
if (copperPolygonsTouch(
|
|
1384
|
-
conductors[i].polygon,
|
|
1385
|
-
conductors[j].polygon,
|
|
1386
|
-
tolerance
|
|
1387
|
-
))
|
|
1549
|
+
if (copperPolygonsTouch(conductors[i].polygon, conductors[j].polygon))
|
|
1388
1550
|
parent[find(j)] = find(i);
|
|
1389
1551
|
}
|
|
1390
1552
|
}
|
|
@@ -2000,7 +2162,7 @@ var SpatialObjectIndex = class {
|
|
|
2000
2162
|
};
|
|
2001
2163
|
|
|
2002
2164
|
// lib/util/getLayersOfPcbElement.ts
|
|
2003
|
-
import { all_layers } from "circuit-json";
|
|
2165
|
+
import { all_layers as all_layers2 } from "circuit-json";
|
|
2004
2166
|
function getLayersOfPcbElement(obj) {
|
|
2005
2167
|
if (obj.type === "pcb_trace_segment") {
|
|
2006
2168
|
return [obj.layer];
|
|
@@ -2009,13 +2171,13 @@ function getLayersOfPcbElement(obj) {
|
|
|
2009
2171
|
return [obj.layer];
|
|
2010
2172
|
}
|
|
2011
2173
|
if (obj.type === "pcb_plated_hole") {
|
|
2012
|
-
return Array.isArray(obj.layers) ? obj.layers : [...
|
|
2174
|
+
return Array.isArray(obj.layers) ? obj.layers : [...all_layers2];
|
|
2013
2175
|
}
|
|
2014
2176
|
if (obj.type === "pcb_hole") {
|
|
2015
|
-
return [...
|
|
2177
|
+
return [...all_layers2];
|
|
2016
2178
|
}
|
|
2017
2179
|
if (obj.type === "pcb_via") {
|
|
2018
|
-
return Array.isArray(obj.layers) ? obj.layers : [...
|
|
2180
|
+
return Array.isArray(obj.layers) ? obj.layers : [...all_layers2];
|
|
2019
2181
|
}
|
|
2020
2182
|
if (obj.type === "pcb_keepout") {
|
|
2021
2183
|
return Array.isArray(obj.layers) ? obj.layers : [];
|
|
@@ -3444,7 +3606,7 @@ import {
|
|
|
3444
3606
|
|
|
3445
3607
|
// lib/check-traces-are-contiguous/via-contact-index.ts
|
|
3446
3608
|
import {
|
|
3447
|
-
all_layers as
|
|
3609
|
+
all_layers as all_layers3
|
|
3448
3610
|
} from "circuit-json";
|
|
3449
3611
|
import { getPrimaryId as getPrimaryId4 } from "@tscircuit/circuit-json-util";
|
|
3450
3612
|
import { pointToSegmentDistance as pointToSegmentDistance2 } from "@tscircuit/math-utils";
|
|
@@ -3456,7 +3618,7 @@ function getViaContactIndex(circuitJson, connectivity) {
|
|
|
3456
3618
|
const vias = circuitJson.filter((element) => element.type === "pcb_via");
|
|
3457
3619
|
const board = circuitJson.find((element) => element.type === "pcb_board");
|
|
3458
3620
|
const layerCount = board?.num_layers;
|
|
3459
|
-
const innerLayers =
|
|
3621
|
+
const innerLayers = all_layers3.filter((layer) => layer.startsWith("inner"));
|
|
3460
3622
|
const stack = [
|
|
3461
3623
|
"top",
|
|
3462
3624
|
...innerLayers.slice(
|