@tscircuit/checks 0.0.207 → 0.0.209

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
@@ -1,3 +1,321 @@
1
+ // lib/check-pcb-trace-self-shorts.ts
2
+ import { cju } from "@tscircuit/circuit-json-util";
3
+ import { segmentToSegmentMinDistance } from "@tscircuit/math-utils";
4
+ import {
5
+ all_layers
6
+ } from "circuit-json";
7
+
8
+ // lib/check-each-pcb-trace-non-overlapping/getClosestPointBetweenSegments.ts
9
+ var getClosestPointBetweenSegments = (segmentA, segmentB) => {
10
+ const a1 = { x: segmentA.x1, y: segmentA.y1 };
11
+ const a2 = { x: segmentA.x2, y: segmentA.y2 };
12
+ const b1 = { x: segmentB.x1, y: segmentB.y1 };
13
+ const b2 = { x: segmentB.x2, y: segmentB.y2 };
14
+ const va = { x: a2.x - a1.x, y: a2.y - a1.y };
15
+ const vb = { x: b2.x - b1.x, y: b2.y - b1.y };
16
+ const lenSqrA = va.x * va.x + va.y * va.y;
17
+ const lenSqrB = vb.x * vb.x + vb.y * vb.y;
18
+ if (lenSqrA === 0 || lenSqrB === 0) {
19
+ if (lenSqrA === 0 && lenSqrB === 0) {
20
+ return {
21
+ x: (a1.x + b1.x) / 2,
22
+ y: (a1.y + b1.y) / 2
23
+ };
24
+ }
25
+ if (lenSqrA === 0) {
26
+ const t2 = clamp(
27
+ ((a1.x - b1.x) * vb.x + (a1.y - b1.y) * vb.y) / lenSqrB,
28
+ 0,
29
+ 1
30
+ );
31
+ const closestOnB2 = {
32
+ x: b1.x + t2 * vb.x,
33
+ y: b1.y + t2 * vb.y
34
+ };
35
+ return {
36
+ x: (a1.x + closestOnB2.x) / 2,
37
+ y: (a1.y + closestOnB2.y) / 2
38
+ };
39
+ }
40
+ const t = clamp(
41
+ ((b1.x - a1.x) * va.x + (b1.y - a1.y) * va.y) / lenSqrA,
42
+ 0,
43
+ 1
44
+ );
45
+ const closestOnA2 = {
46
+ x: a1.x + t * va.x,
47
+ y: a1.y + t * va.y
48
+ };
49
+ return {
50
+ x: (closestOnA2.x + b1.x) / 2,
51
+ y: (closestOnA2.y + b1.y) / 2
52
+ };
53
+ }
54
+ const w = { x: a1.x - b1.x, y: a1.y - b1.y };
55
+ const dotAA = va.x * va.x + va.y * va.y;
56
+ const dotAB = va.x * vb.x + va.y * vb.y;
57
+ const dotAW = va.x * w.x + va.y * w.y;
58
+ const dotBB = vb.x * vb.x + vb.y * vb.y;
59
+ const dotBW = vb.x * w.x + vb.y * w.y;
60
+ const denominator = dotAA * dotBB - dotAB * dotAB;
61
+ if (denominator < 1e-10) {
62
+ return closestPointsParallelSegments(
63
+ a1,
64
+ a2,
65
+ b1,
66
+ b2,
67
+ va,
68
+ vb,
69
+ lenSqrA,
70
+ lenSqrB
71
+ );
72
+ }
73
+ let tA = (dotAB * dotBW - dotBB * dotAW) / denominator;
74
+ let tB = (dotAA * dotBW - dotAB * dotAW) / denominator;
75
+ tA = clamp(tA, 0, 1);
76
+ tB = clamp(tB, 0, 1);
77
+ tB = (tA * dotAB + dotBW) / dotBB;
78
+ tB = clamp(tB, 0, 1);
79
+ tA = (tB * dotAB - dotAW) / dotAA;
80
+ tA = clamp(tA, 0, 1);
81
+ const closestOnA = {
82
+ x: a1.x + tA * va.x,
83
+ y: a1.y + tA * va.y
84
+ };
85
+ const closestOnB = {
86
+ x: b1.x + tB * vb.x,
87
+ y: b1.y + tB * vb.y
88
+ };
89
+ const dx = closestOnA.x - closestOnB.x;
90
+ const dy = closestOnA.y - closestOnB.y;
91
+ const distance3 = Math.sqrt(dx * dx + dy * dy);
92
+ const averagePoint = {
93
+ x: (closestOnA.x + closestOnB.x) / 2,
94
+ y: (closestOnA.y + closestOnB.y) / 2
95
+ };
96
+ return averagePoint;
97
+ };
98
+ var closestPointsParallelSegments = (a1, a2, b1, b2, va, vb, lenSqrA, lenSqrB) => {
99
+ let tA = ((b1.x - a1.x) * va.x + (b1.y - a1.y) * va.y) / lenSqrA;
100
+ tA = clamp(tA, 0, 1);
101
+ const pointOnA1 = { x: a1.x + tA * va.x, y: a1.y + tA * va.y };
102
+ let tA2 = ((b2.x - a1.x) * va.x + (b2.y - a1.y) * va.y) / lenSqrA;
103
+ tA2 = clamp(tA2, 0, 1);
104
+ const pointOnA2 = { x: a1.x + tA2 * va.x, y: a1.y + tA2 * va.y };
105
+ let tB = ((a1.x - b1.x) * vb.x + (a1.y - b1.y) * vb.y) / lenSqrB;
106
+ tB = clamp(tB, 0, 1);
107
+ const pointOnB1 = { x: b1.x + tB * vb.x, y: b1.y + tB * vb.y };
108
+ let tB2 = ((a2.x - b1.x) * vb.x + (a2.y - b1.y) * vb.y) / lenSqrB;
109
+ tB2 = clamp(tB2, 0, 1);
110
+ const pointOnB2 = { x: b1.x + tB2 * vb.x, y: b1.y + tB2 * vb.y };
111
+ const distances = [
112
+ {
113
+ pointA: pointOnA1,
114
+ pointB: b1,
115
+ distance: Math.sqrt(
116
+ (pointOnA1.x - b1.x) ** 2 + (pointOnA1.y - b1.y) ** 2
117
+ )
118
+ },
119
+ {
120
+ pointA: pointOnA2,
121
+ pointB: b2,
122
+ distance: Math.sqrt(
123
+ (pointOnA2.x - b2.x) ** 2 + (pointOnA2.y - b2.y) ** 2
124
+ )
125
+ },
126
+ {
127
+ pointA: a1,
128
+ pointB: pointOnB1,
129
+ distance: Math.sqrt(
130
+ (a1.x - pointOnB1.x) ** 2 + (a1.y - pointOnB1.y) ** 2
131
+ )
132
+ },
133
+ {
134
+ pointA: a2,
135
+ pointB: pointOnB2,
136
+ distance: Math.sqrt(
137
+ (a2.x - pointOnB2.x) ** 2 + (a2.y - pointOnB2.y) ** 2
138
+ )
139
+ }
140
+ ];
141
+ const closestPair = distances.reduce(
142
+ (closest, current) => current.distance < closest.distance ? current : closest
143
+ );
144
+ return {
145
+ x: (closestPair.pointA.x + closestPair.pointB.x) / 2,
146
+ y: (closestPair.pointA.y + closestPair.pointB.y) / 2
147
+ };
148
+ };
149
+ var clamp = (value, min, max) => {
150
+ return Math.max(min, Math.min(max, value));
151
+ };
152
+
153
+ // lib/check-each-pcb-trace-non-overlapping/getPcbPortIdsConnectedToTraces.ts
154
+ function getPcbPortIdsConnectedToRoutePoint(routePoint) {
155
+ if (routePoint.route_type !== "wire") return [];
156
+ return [routePoint.start_pcb_port_id, routePoint.end_pcb_port_id].filter(
157
+ (portId) => Boolean(portId)
158
+ );
159
+ }
160
+ function getPcbPortIdsConnectedToTrace(trace) {
161
+ const connectedPcbPorts = /* @__PURE__ */ new Set();
162
+ for (const segment of trace.route) {
163
+ for (const portId of getPcbPortIdsConnectedToRoutePoint(segment)) {
164
+ connectedPcbPorts.add(portId);
165
+ }
166
+ }
167
+ return Array.from(connectedPcbPorts);
168
+ }
169
+ function getPcbPortIdsConnectedToTraces(traces) {
170
+ const connectedPorts = /* @__PURE__ */ new Set();
171
+ for (const trace of traces) {
172
+ for (const portId of getPcbPortIdsConnectedToTrace(trace)) {
173
+ connectedPorts.add(portId);
174
+ }
175
+ }
176
+ return Array.from(connectedPorts);
177
+ }
178
+
179
+ // lib/check-pcb-trace-self-shorts.ts
180
+ function checkPcbTraceSelfShorts(circuitJson) {
181
+ const matchedSourceTraceIds = new Set(
182
+ circuitJson.flatMap(
183
+ (element) => element.type === "source_bus" && element.max_length_skew !== void 0 ? element.source_trace_ids : []
184
+ )
185
+ );
186
+ const db = cju(circuitJson);
187
+ const errors = [];
188
+ for (const trace of circuitJson) {
189
+ if (trace.type !== "pcb_trace") continue;
190
+ if (!trace.source_trace_id || !matchedSourceTraceIds.has(trace.source_trace_id))
191
+ continue;
192
+ const segments = [];
193
+ const routeDistances = [];
194
+ let distance3 = 0;
195
+ let run = 0;
196
+ for (let i = 0; i < trace.route.length - 1; i++) {
197
+ routeDistances[i] = distance3;
198
+ const a = trace.route[i];
199
+ const b = trace.route[i + 1];
200
+ if (a.route_type !== "wire" || b.route_type !== "wire" || a.layer !== b.layer) {
201
+ run++;
202
+ continue;
203
+ }
204
+ const length = Math.hypot(b.x - a.x, b.y - a.y);
205
+ if (length === 0) continue;
206
+ segments.push({
207
+ type: "pcb_trace_segment",
208
+ _pcbTrace: trace,
209
+ pcb_trace_id: trace.pcb_trace_id,
210
+ thickness: a.width,
211
+ layer: a.layer,
212
+ x1: a.x,
213
+ y1: a.y,
214
+ x2: b.x,
215
+ y2: b.y,
216
+ run,
217
+ startDistance: distance3,
218
+ endDistance: distance3 + length
219
+ });
220
+ distance3 += length;
221
+ }
222
+ routeDistances[trace.route.length - 1] = distance3;
223
+ let shortCenter;
224
+ pairs: for (let i = 0; i < segments.length; i++) {
225
+ const a = segments[i];
226
+ for (let j = i + 1; j < segments.length; j++) {
227
+ const b = segments[j];
228
+ if (a.layer !== b.layer) continue;
229
+ const contactDistance = (a.thickness + b.thickness) / 2;
230
+ const dot = (a.x2 - a.x1) * (b.x2 - b.x1) + (a.y2 - a.y1) * (b.y2 - b.y1);
231
+ const cross = (a.x2 - a.x1) * (b.y2 - b.y1) - (a.y2 - a.y1) * (b.x2 - b.x1);
232
+ const adjacent = a.run === b.run && b.startDistance === a.endDistance;
233
+ if (adjacent && !(dot < 0 && Math.abs(cross) < 1e-9)) continue;
234
+ if (!adjacent && a.run === b.run && b.startDistance - a.endDistance < contactDistance && dot >= 0)
235
+ continue;
236
+ const gap = segmentToSegmentMinDistance(
237
+ { x: a.x1, y: a.y1 },
238
+ { x: a.x2, y: a.y2 },
239
+ { x: b.x1, y: b.y1 },
240
+ { x: b.x2, y: b.y2 }
241
+ ) - contactDistance;
242
+ if (gap > 1e-9) continue;
243
+ shortCenter = getClosestPointBetweenSegments(a, b);
244
+ break pairs;
245
+ }
246
+ }
247
+ if (!shortCenter) {
248
+ const board = circuitJson.find((e) => e.type === "pcb_board");
249
+ const stack = [
250
+ "top",
251
+ ...all_layers.filter((layer) => layer.startsWith("inner")).slice(0, board ? Math.max(0, board.num_layers - 2) : void 0),
252
+ ...board?.num_layers === 1 ? [] : ["bottom"]
253
+ ];
254
+ vias: for (let i = 0; i < trace.route.length; i++) {
255
+ const point2 = trace.route[i];
256
+ if (point2.route_type !== "via") continue;
257
+ const materialized = db.pcb_via.list().find(
258
+ (via) => (via.pcb_trace_id === trace.pcb_trace_id || !via.pcb_trace_id && via.source_trace_id === trace.source_trace_id) && Math.hypot(via.x - point2.x, via.y - point2.y) <= 1e-9
259
+ );
260
+ const diameter = materialized?.outer_diameter ?? point2.outer_diameter;
261
+ if (diameter === void 0 || !Number.isFinite(diameter) || diameter <= 0)
262
+ continue;
263
+ const from = stack.indexOf(point2.from_layer);
264
+ const to = stack.indexOf(point2.to_layer);
265
+ const layers = materialized?.layers ?? (from >= 0 && to >= 0 ? stack.slice(Math.min(from, to), Math.max(from, to) + 1) : []);
266
+ for (const segment of segments) {
267
+ if (!layers.includes(segment.layer)) continue;
268
+ const reach = (diameter + segment.thickness) / 2;
269
+ const alongRouteGap = Math.max(
270
+ segment.startDistance - routeDistances[i],
271
+ routeDistances[i] - segment.endDistance,
272
+ 0
273
+ );
274
+ if (alongRouteGap <= reach + 1e-9) continue;
275
+ const viaSegment = {
276
+ ...segment,
277
+ x1: point2.x,
278
+ y1: point2.y,
279
+ x2: point2.x,
280
+ y2: point2.y
281
+ };
282
+ const gap = segmentToSegmentMinDistance(
283
+ point2,
284
+ point2,
285
+ { x: segment.x1, y: segment.y1 },
286
+ { x: segment.x2, y: segment.y2 }
287
+ ) - reach;
288
+ if (gap > 1e-9) continue;
289
+ shortCenter = getClosestPointBetweenSegments(segment, viaSegment);
290
+ break vias;
291
+ }
292
+ }
293
+ }
294
+ if (shortCenter) {
295
+ const sourceTrace = db.source_trace.get(trace.source_trace_id);
296
+ const endpointNames = (sourceTrace?.connected_source_port_ids ?? []).map((id) => {
297
+ const port = db.source_port.get(id);
298
+ const component = port?.source_component_id ? db.source_component.get(port.source_component_id) : void 0;
299
+ return component?.name && port?.name ? `${component.name}.${port.name}` : void 0;
300
+ }).filter((name) => Boolean(name));
301
+ const traceName = sourceTrace?.name || sourceTrace?.display_name || endpointNames.join(" \u2192 ") || "unnamed";
302
+ errors.push({
303
+ type: "pcb_trace_error",
304
+ error_type: "pcb_trace_error",
305
+ pcb_trace_error_id: `self_short_${trace.pcb_trace_id}`,
306
+ pcb_trace_id: trace.pcb_trace_id,
307
+ source_trace_id: trace.source_trace_id,
308
+ message: `PCB trace "${traceName}" shorts to itself, bypassing part of its length-matched route`,
309
+ center: shortCenter,
310
+ pcb_component_ids: [],
311
+ pcb_port_ids: getPcbPortIdsConnectedToTraces([trace]),
312
+ subcircuit_id: trace.subcircuit_id
313
+ });
314
+ }
315
+ }
316
+ return errors;
317
+ }
318
+
1
319
  // lib/check-copper-pour-shorts.ts
2
320
  import Flatbush from "flatbush";
3
321
  import "@flatten-js/core";
@@ -696,25 +1014,190 @@ function checkCopperPourShorts(circuitJson, { connMap } = {}) {
696
1014
  const id = `copper_pour_short_${[pour.elementId, other.elementId].sort().join("_")}`;
697
1015
  if (errors.has(id) || !pour.shapes.some((shape) => touchesPour(shape, otherShape)))
698
1016
  continue;
699
- errors.set(id, {
700
- type: "pcb_placement_error",
701
- pcb_placement_error_id: id,
702
- error_type: "pcb_placement_error",
703
- message: `Copper pour ${pour.elementId} (${netNames.get(netId) ?? netId ?? "unassigned net"}) shorts to ${getReadableNameForElement(circuitJson, other.elementId)} (${other.elementId}) on ${pour.layer} (accidental copper contact)`,
704
- subcircuit_id: element.subcircuit_id
705
- });
1017
+ errors.set(id, {
1018
+ type: "pcb_placement_error",
1019
+ pcb_placement_error_id: id,
1020
+ error_type: "pcb_placement_error",
1021
+ message: `Copper pour ${pour.elementId} (${netNames.get(netId) ?? netId ?? "unassigned net"}) shorts to ${getReadableNameForElement(circuitJson, other.elementId)} (${other.elementId}) on ${pour.layer} (accidental copper contact)`,
1022
+ subcircuit_id: element.subcircuit_id
1023
+ });
1024
+ }
1025
+ }
1026
+ return [...errors.values()];
1027
+ }
1028
+
1029
+ // lib/util/create-indexed-pcb-connectivity-map.ts
1030
+ import {
1031
+ ConnectivityMap,
1032
+ findConnectedNetworks,
1033
+ PcbConnectivityMap
1034
+ } from "circuit-json-to-connectivity-map";
1035
+ import Flatbush3 from "flatbush";
1036
+
1037
+ // lib/util/get-via-and-pour-connections.ts
1038
+ import { all_layers as all_layers2 } from "circuit-json";
1039
+ import {
1040
+ getPourPolygon,
1041
+ getTraceSegmentPolygon,
1042
+ getViaPolygon
1043
+ } from "@tscircuit/circuit-json-util";
1044
+ import Flatbush2 from "flatbush";
1045
+
1046
+ // lib/copper-pour-connectivity/create-copper-polygon-contact-tester.ts
1047
+ import {
1048
+ Box
1049
+ } from "@flatten-js/core";
1050
+ function createCopperPolygonContactTester(tolerance) {
1051
+ const cache = /* @__PURE__ */ new WeakMap();
1052
+ const getGeometry = (polygon) => {
1053
+ let geometry = cache.get(polygon);
1054
+ if (!geometry) {
1055
+ geometry = {
1056
+ box: polygon.box,
1057
+ facePoints: [...polygon.faces].map((face) => face.first.start),
1058
+ edges: [...polygon.edges].map((edge) => edge.shape),
1059
+ edgeIndex: polygon.edges
1060
+ };
1061
+ cache.set(polygon, geometry);
1062
+ }
1063
+ return geometry;
1064
+ };
1065
+ return (a, b) => {
1066
+ if (a.isEmpty() || b.isEmpty()) return false;
1067
+ const ga = getGeometry(a);
1068
+ const gb = getGeometry(b);
1069
+ 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)
1070
+ return false;
1071
+ if (ga.facePoints.some(
1072
+ (point2) => gb.box.contains(point2) && b.contains(point2)
1073
+ ) || gb.facePoints.some((point2) => ga.box.contains(point2) && a.contains(point2)))
1074
+ return true;
1075
+ const [small, large] = ga.edges.length <= gb.edges.length ? [ga, gb] : [gb, ga];
1076
+ for (const edge of small.edges) {
1077
+ const box = edge.box;
1078
+ const queryBox = new Box(
1079
+ box.xmin - tolerance,
1080
+ box.ymin - tolerance,
1081
+ box.xmax + tolerance,
1082
+ box.ymax + tolerance
1083
+ );
1084
+ const candidates = large.edgeIndex.search(
1085
+ queryBox
1086
+ );
1087
+ for (const candidate of candidates) {
1088
+ if (edge.distanceTo(candidate.shape)[0] <= tolerance) return true;
1089
+ }
1090
+ }
1091
+ return false;
1092
+ };
1093
+ }
1094
+
1095
+ // lib/util/get-via-and-pour-connections.ts
1096
+ function getViaAndPourConnections(circuit) {
1097
+ if (!circuit.some(
1098
+ (e) => e.type === "pcb_via" || e.type === "pcb_copper_pour" || e.type === "pcb_trace" && e.route.some((p) => p.route_type === "via")
1099
+ ))
1100
+ return [];
1101
+ const conductors = [];
1102
+ const connections = [];
1103
+ const scale = 1e6;
1104
+ const tolerance = 1e-7 * scale;
1105
+ const touches = createCopperPolygonContactTester(tolerance);
1106
+ const add = (id, layers, polygon, bridges = false) => {
1107
+ if (!polygon.isEmpty())
1108
+ conductors.push({
1109
+ id,
1110
+ layers,
1111
+ polygon: polygon.scale(scale, scale),
1112
+ bridges
1113
+ });
1114
+ };
1115
+ const vias = circuit.filter((e) => e.type === "pcb_via");
1116
+ const board = circuit.find((e) => e.type === "pcb_board");
1117
+ const stack = [
1118
+ "top",
1119
+ ...all_layers2.filter((l) => l.startsWith("inner")).slice(0, board ? Math.max(0, board.num_layers - 2) : void 0),
1120
+ ...board?.num_layers === 1 ? [] : ["bottom"]
1121
+ ];
1122
+ for (const copper of circuit) {
1123
+ if (copper.type === "pcb_via") {
1124
+ add(
1125
+ copper.pcb_via_id,
1126
+ copper.layers,
1127
+ getViaPolygon(copper, copper.outer_diameter, 0),
1128
+ true
1129
+ );
1130
+ if (copper.pcb_trace_id)
1131
+ connections.push([copper.pcb_via_id, copper.pcb_trace_id]);
1132
+ } else if (copper.type === "pcb_copper_pour") {
1133
+ add(
1134
+ copper.pcb_copper_pour_id,
1135
+ [copper.layer],
1136
+ getPourPolygon(copper),
1137
+ true
1138
+ );
1139
+ } else if (copper.type === "pcb_trace") {
1140
+ if (copper.route_thickness_mode === "interpolated") continue;
1141
+ for (let i = 0; i < copper.route.length; i++) {
1142
+ const a = copper.route[i], b = copper.route[i + 1];
1143
+ if (a.route_type === "wire" && b?.route_type === "wire" && a.layer === b.layer && (a.x !== b.x || a.y !== b.y)) {
1144
+ add(
1145
+ copper.pcb_trace_id,
1146
+ [a.layer],
1147
+ getTraceSegmentPolygon(a, b, a.width)
1148
+ );
1149
+ } else if (a.route_type === "via") {
1150
+ if (vias.some(
1151
+ (v) => v.pcb_trace_id === copper.pcb_trace_id && Math.hypot(v.x - a.x, v.y - a.y) < 1e-9
1152
+ ))
1153
+ continue;
1154
+ const from = stack.indexOf(a.from_layer), to = stack.indexOf(a.to_layer);
1155
+ if (from < 0 || to < 0 || !a.outer_diameter) continue;
1156
+ const via = {
1157
+ type: "pcb_via",
1158
+ pcb_via_id: `${copper.pcb_trace_id}_via_${i}`,
1159
+ x: a.x,
1160
+ y: a.y,
1161
+ outer_diameter: a.outer_diameter,
1162
+ hole_diameter: 0,
1163
+ layers: stack.slice(Math.min(from, to), Math.max(from, to) + 1)
1164
+ };
1165
+ add(
1166
+ copper.pcb_trace_id,
1167
+ via.layers,
1168
+ getViaPolygon(via, via.outer_diameter, 0),
1169
+ true
1170
+ );
1171
+ }
1172
+ }
1173
+ }
1174
+ }
1175
+ if (!conductors.length) return connections;
1176
+ const index = new Flatbush2(conductors.length);
1177
+ for (const { polygon } of conductors) {
1178
+ const b = polygon.box;
1179
+ index.add(b.xmin, b.ymin, b.xmax, b.ymax);
1180
+ }
1181
+ index.finish();
1182
+ for (const [i, a] of conductors.entries()) {
1183
+ if (!a.bridges) continue;
1184
+ const box = a.polygon.box;
1185
+ for (const j of index.search(
1186
+ box.xmin - tolerance,
1187
+ box.ymin - tolerance,
1188
+ box.xmax + tolerance,
1189
+ box.ymax + tolerance
1190
+ )) {
1191
+ const b = conductors[j];
1192
+ if (i === j || a.id === b.id || b.bridges && j < i || !a.layers.some((l) => b.layers.includes(l)))
1193
+ continue;
1194
+ if (touches(a.polygon, b.polygon)) connections.push([a.id, b.id]);
706
1195
  }
707
1196
  }
708
- return [...errors.values()];
1197
+ return connections;
709
1198
  }
710
1199
 
711
1200
  // lib/util/create-indexed-pcb-connectivity-map.ts
712
- import {
713
- ConnectivityMap,
714
- findConnectedNetworks,
715
- PcbConnectivityMap
716
- } from "circuit-json-to-connectivity-map";
717
- import Flatbush2 from "flatbush";
718
1201
  function createIndexedPcbConnectivityMap(circuitJson) {
719
1202
  const map = new PcbConnectivityMap();
720
1203
  map.circuitJson = circuitJson;
@@ -756,7 +1239,7 @@ function createIndexedPcbConnectivityMap(circuitJson) {
756
1239
  }
757
1240
  const candidates = traces.map(() => /* @__PURE__ */ new Set());
758
1241
  for (const bounds of boundsByLayer.values()) {
759
- const index = new Flatbush2(bounds.length);
1242
+ const index = new Flatbush3(bounds.length);
760
1243
  for (const box of bounds) index.add(box.minX, box.minY, box.maxX, box.maxY);
761
1244
  index.finish();
762
1245
  for (const box of bounds) {
@@ -795,6 +1278,7 @@ function createIndexedPcbConnectivityMap(circuitJson) {
795
1278
  for (const connection of connectionsByPort.get(portId) ?? [])
796
1279
  connections.push(connection);
797
1280
  }
1281
+ connections.push(...getViaAndPourConnections(circuitJson));
798
1282
  map.connMap = new ConnectivityMap(findConnectedNetworks(connections));
799
1283
  return map;
800
1284
  }
@@ -808,7 +1292,7 @@ import {
808
1292
  getSegmentIntersection,
809
1293
  isPointInsidePolygon,
810
1294
  pointToSegmentClosestPoint,
811
- segmentToSegmentMinDistance
1295
+ segmentToSegmentMinDistance as segmentToSegmentMinDistance2
812
1296
  } from "@tscircuit/math-utils";
813
1297
  var rotatePoint = (point2, angleDegrees) => {
814
1298
  const angle = angleDegrees * Math.PI / 180;
@@ -908,7 +1392,7 @@ var getClosestPointsBetweenSegments = (a1, a2, b1, b2) => {
908
1392
  }
909
1393
  }
910
1394
  return {
911
- distance: segmentToSegmentMinDistance(a1, a2, b1, b2),
1395
+ distance: segmentToSegmentMinDistance2(a1, a2, b1, b2),
912
1396
  pointOnA: best.pointOnA,
913
1397
  pointOnB: best.pointOnB,
914
1398
  center: {
@@ -1264,63 +1748,14 @@ function getReadableNameForFootprintPad(circuitJson, pad, ordinal) {
1264
1748
  return `${padKind} #${ordinal + 1} at ${location}`;
1265
1749
  }
1266
1750
 
1267
- // lib/copper-pour-connectivity/create-copper-polygon-contact-tester.ts
1268
- import {
1269
- Box
1270
- } from "@flatten-js/core";
1271
- function createCopperPolygonContactTester(tolerance) {
1272
- const cache = /* @__PURE__ */ new WeakMap();
1273
- const getGeometry = (polygon) => {
1274
- let geometry = cache.get(polygon);
1275
- if (!geometry) {
1276
- geometry = {
1277
- box: polygon.box,
1278
- facePoints: [...polygon.faces].map((face) => face.first.start),
1279
- edges: [...polygon.edges].map((edge) => edge.shape),
1280
- edgeIndex: polygon.edges
1281
- };
1282
- cache.set(polygon, geometry);
1283
- }
1284
- return geometry;
1285
- };
1286
- return (a, b) => {
1287
- if (a.isEmpty() || b.isEmpty()) return false;
1288
- const ga = getGeometry(a);
1289
- const gb = getGeometry(b);
1290
- 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)
1291
- return false;
1292
- if (ga.facePoints.some(
1293
- (point2) => gb.box.contains(point2) && b.contains(point2)
1294
- ) || gb.facePoints.some((point2) => ga.box.contains(point2) && a.contains(point2)))
1295
- return true;
1296
- const [small, large] = ga.edges.length <= gb.edges.length ? [ga, gb] : [gb, ga];
1297
- for (const edge of small.edges) {
1298
- const box = edge.box;
1299
- const queryBox = new Box(
1300
- box.xmin - tolerance,
1301
- box.ymin - tolerance,
1302
- box.xmax + tolerance,
1303
- box.ymax + tolerance
1304
- );
1305
- const candidates = large.edgeIndex.search(
1306
- queryBox
1307
- );
1308
- for (const candidate of candidates) {
1309
- if (edge.distanceTo(candidate.shape)[0] <= tolerance) return true;
1310
- }
1311
- }
1312
- return false;
1313
- };
1314
- }
1315
-
1316
1751
  // lib/copper-pour-connectivity/get-copper-pour-connectivity.ts
1317
1752
  import {
1318
1753
  getPrimaryId,
1319
1754
  getPlatedHolePolygon,
1320
- getPourPolygon,
1755
+ getPourPolygon as getPourPolygon2,
1321
1756
  getSmtPadPolygon,
1322
- getTraceSegmentPolygon,
1323
- getViaPolygon
1757
+ getTraceSegmentPolygon as getTraceSegmentPolygon2,
1758
+ getViaPolygon as getViaPolygon2
1324
1759
  } from "@tscircuit/circuit-json-util";
1325
1760
  function getCopperPourConnectivity(circuitJson, connectivity) {
1326
1761
  const scale = 1e6;
@@ -1343,7 +1778,7 @@ function getCopperPourConnectivity(circuitJson, connectivity) {
1343
1778
  if (!netId) continue;
1344
1779
  pouredNets.add(netId);
1345
1780
  add({
1346
- polygon: getPourPolygon(pour),
1781
+ polygon: getPourPolygon2(pour),
1347
1782
  layers: [pour.layer],
1348
1783
  netId,
1349
1784
  isPour: true
@@ -1364,7 +1799,7 @@ function getCopperPourConnectivity(circuitJson, connectivity) {
1364
1799
  if (start.route_type !== "wire" || end.route_type !== "wire" || start.layer !== end.layer)
1365
1800
  continue;
1366
1801
  add({
1367
- polygon: getTraceSegmentPolygon(start, end, start.width),
1802
+ polygon: getTraceSegmentPolygon2(start, end, start.width),
1368
1803
  layers: [start.layer],
1369
1804
  netId: netId2
1370
1805
  });
@@ -1394,7 +1829,7 @@ function getCopperPourConnectivity(circuitJson, connectivity) {
1394
1829
  });
1395
1830
  } else {
1396
1831
  add({
1397
- polygon: getViaPolygon(
1832
+ polygon: getViaPolygon2(
1398
1833
  copper,
1399
1834
  copper.outer_diameter,
1400
1835
  copper.hole_diameter
@@ -1578,20 +2013,20 @@ function checkEachPcbPortConnectedToPcbTraces(circuitJson, {
1578
2013
  }
1579
2014
 
1580
2015
  // lib/check-each-pcb-trace-non-overlapping/check-each-pcb-trace-non-overlapping.ts
1581
- import { cju as cju2, getReadableNameForElement as getReadableNameForElement3 } from "@tscircuit/circuit-json-util";
2016
+ import { cju as cju3, getReadableNameForElement as getReadableNameForElement3 } from "@tscircuit/circuit-json-util";
1582
2017
  import { getPrimaryId as getPrimaryId2 } from "@tscircuit/circuit-json-util";
1583
2018
  import {
1584
2019
  segmentToBoundsMinDistance,
1585
2020
  segmentToCircleMinDistance as segmentToCircleMinDistance2
1586
2021
  } from "@tscircuit/math-utils";
1587
- import { segmentToSegmentMinDistance as segmentToSegmentMinDistance3 } from "@tscircuit/math-utils";
2022
+ import { segmentToSegmentMinDistance as segmentToSegmentMinDistance4 } from "@tscircuit/math-utils";
1588
2023
  import {
1589
2024
  getFullConnectivityMapFromCircuitJson as getFullConnectivityMapFromCircuitJson3
1590
2025
  } from "circuit-json-to-connectivity-map";
1591
2026
 
1592
2027
  // lib/check-pad-clearance/common.ts
1593
2028
  import {
1594
- cju,
2029
+ cju as cju2,
1595
2030
  distanceBetweenCircleAndCircle,
1596
2031
  distanceBetweenCircleAndPolygon,
1597
2032
  distanceBetweenPolygonAndPolygon,
@@ -1601,7 +2036,7 @@ import {
1601
2036
  midpoint,
1602
2037
  pointToSegmentClosestPoint as pointToSegmentClosestPoint2,
1603
2038
  segmentToCircleMinDistance,
1604
- segmentToSegmentMinDistance as segmentToSegmentMinDistance2
2039
+ segmentToSegmentMinDistance as segmentToSegmentMinDistance3
1605
2040
  } from "@tscircuit/math-utils";
1606
2041
 
1607
2042
  // node_modules/@tscircuit/jlcpcb-manufacturing-specs/lib/jlcpcb-manufacturing-specs.ts
@@ -1768,7 +2203,7 @@ var getPadToPadGap = (padA, padB) => {
1768
2203
  if (isPillPad(padA) && isPillPad(padB)) {
1769
2204
  const pillA = getPillCenterLineForPad(padA);
1770
2205
  const pillB = getPillCenterLineForPad(padB);
1771
- return segmentToSegmentMinDistance2(
2206
+ return segmentToSegmentMinDistance3(
1772
2207
  pillA.start,
1773
2208
  pillA.end,
1774
2209
  pillB.start,
@@ -1823,11 +2258,11 @@ var getPadToPadGap = (padA, padB) => {
1823
2258
  );
1824
2259
  };
1825
2260
  var getPads = (circuitJson) => [
1826
- ...cju(circuitJson).pcb_smtpad.list(),
1827
- ...cju(circuitJson).pcb_plated_hole.list()
2261
+ ...cju2(circuitJson).pcb_smtpad.list(),
2262
+ ...cju2(circuitJson).pcb_plated_hole.list()
1828
2263
  ];
1829
2264
  var getTraceSegments = (circuitJson) => {
1830
- const pcbTraces = cju(circuitJson).pcb_trace.list();
2265
+ const pcbTraces = cju2(circuitJson).pcb_trace.list();
1831
2266
  return pcbTraces.flatMap((pcbTrace) => {
1832
2267
  const segments = [];
1833
2268
  for (let i = 0; i < pcbTrace.route.length - 1; i++) {
@@ -2045,7 +2480,7 @@ var SpatialObjectIndex = class {
2045
2480
  };
2046
2481
 
2047
2482
  // lib/util/getLayersOfPcbElement.ts
2048
- import { all_layers } from "circuit-json";
2483
+ import { all_layers as all_layers3 } from "circuit-json";
2049
2484
  function getLayersOfPcbElement(obj) {
2050
2485
  if (obj.type === "pcb_trace_segment") {
2051
2486
  return [obj.layer];
@@ -2054,13 +2489,13 @@ function getLayersOfPcbElement(obj) {
2054
2489
  return [obj.layer];
2055
2490
  }
2056
2491
  if (obj.type === "pcb_plated_hole") {
2057
- return Array.isArray(obj.layers) ? obj.layers : [...all_layers];
2492
+ return Array.isArray(obj.layers) ? obj.layers : [...all_layers3];
2058
2493
  }
2059
2494
  if (obj.type === "pcb_hole") {
2060
- return [...all_layers];
2495
+ return [...all_layers3];
2061
2496
  }
2062
2497
  if (obj.type === "pcb_via") {
2063
- return Array.isArray(obj.layers) ? obj.layers : [...all_layers];
2498
+ return Array.isArray(obj.layers) ? obj.layers : [...all_layers3];
2064
2499
  }
2065
2500
  if (obj.type === "pcb_keepout") {
2066
2501
  return Array.isArray(obj.layers) ? obj.layers : [];
@@ -2161,151 +2596,6 @@ var getClosestPointBetweenSegmentAndBounds = (segment, bounds) => {
2161
2596
  return closestPoint;
2162
2597
  };
2163
2598
 
2164
- // lib/check-each-pcb-trace-non-overlapping/getClosestPointBetweenSegments.ts
2165
- var getClosestPointBetweenSegments = (segmentA, segmentB) => {
2166
- const a1 = { x: segmentA.x1, y: segmentA.y1 };
2167
- const a2 = { x: segmentA.x2, y: segmentA.y2 };
2168
- const b1 = { x: segmentB.x1, y: segmentB.y1 };
2169
- const b2 = { x: segmentB.x2, y: segmentB.y2 };
2170
- const va = { x: a2.x - a1.x, y: a2.y - a1.y };
2171
- const vb = { x: b2.x - b1.x, y: b2.y - b1.y };
2172
- const lenSqrA = va.x * va.x + va.y * va.y;
2173
- const lenSqrB = vb.x * vb.x + vb.y * vb.y;
2174
- if (lenSqrA === 0 || lenSqrB === 0) {
2175
- if (lenSqrA === 0 && lenSqrB === 0) {
2176
- return {
2177
- x: (a1.x + b1.x) / 2,
2178
- y: (a1.y + b1.y) / 2
2179
- };
2180
- }
2181
- if (lenSqrA === 0) {
2182
- const t2 = clamp(
2183
- ((a1.x - b1.x) * vb.x + (a1.y - b1.y) * vb.y) / lenSqrB,
2184
- 0,
2185
- 1
2186
- );
2187
- const closestOnB2 = {
2188
- x: b1.x + t2 * vb.x,
2189
- y: b1.y + t2 * vb.y
2190
- };
2191
- return {
2192
- x: (a1.x + closestOnB2.x) / 2,
2193
- y: (a1.y + closestOnB2.y) / 2
2194
- };
2195
- }
2196
- const t = clamp(
2197
- ((b1.x - a1.x) * va.x + (b1.y - a1.y) * va.y) / lenSqrA,
2198
- 0,
2199
- 1
2200
- );
2201
- const closestOnA2 = {
2202
- x: a1.x + t * va.x,
2203
- y: a1.y + t * va.y
2204
- };
2205
- return {
2206
- x: (closestOnA2.x + b1.x) / 2,
2207
- y: (closestOnA2.y + b1.y) / 2
2208
- };
2209
- }
2210
- const w = { x: a1.x - b1.x, y: a1.y - b1.y };
2211
- const dotAA = va.x * va.x + va.y * va.y;
2212
- const dotAB = va.x * vb.x + va.y * vb.y;
2213
- const dotAW = va.x * w.x + va.y * w.y;
2214
- const dotBB = vb.x * vb.x + vb.y * vb.y;
2215
- const dotBW = vb.x * w.x + vb.y * w.y;
2216
- const denominator = dotAA * dotBB - dotAB * dotAB;
2217
- if (denominator < 1e-10) {
2218
- return closestPointsParallelSegments(
2219
- a1,
2220
- a2,
2221
- b1,
2222
- b2,
2223
- va,
2224
- vb,
2225
- lenSqrA,
2226
- lenSqrB
2227
- );
2228
- }
2229
- let tA = (dotAB * dotBW - dotBB * dotAW) / denominator;
2230
- let tB = (dotAA * dotBW - dotAB * dotAW) / denominator;
2231
- tA = clamp(tA, 0, 1);
2232
- tB = clamp(tB, 0, 1);
2233
- tB = (tA * dotAB + dotBW) / dotBB;
2234
- tB = clamp(tB, 0, 1);
2235
- tA = (tB * dotAB - dotAW) / dotAA;
2236
- tA = clamp(tA, 0, 1);
2237
- const closestOnA = {
2238
- x: a1.x + tA * va.x,
2239
- y: a1.y + tA * va.y
2240
- };
2241
- const closestOnB = {
2242
- x: b1.x + tB * vb.x,
2243
- y: b1.y + tB * vb.y
2244
- };
2245
- const dx = closestOnA.x - closestOnB.x;
2246
- const dy = closestOnA.y - closestOnB.y;
2247
- const distance3 = Math.sqrt(dx * dx + dy * dy);
2248
- const averagePoint = {
2249
- x: (closestOnA.x + closestOnB.x) / 2,
2250
- y: (closestOnA.y + closestOnB.y) / 2
2251
- };
2252
- return averagePoint;
2253
- };
2254
- var closestPointsParallelSegments = (a1, a2, b1, b2, va, vb, lenSqrA, lenSqrB) => {
2255
- let tA = ((b1.x - a1.x) * va.x + (b1.y - a1.y) * va.y) / lenSqrA;
2256
- tA = clamp(tA, 0, 1);
2257
- const pointOnA1 = { x: a1.x + tA * va.x, y: a1.y + tA * va.y };
2258
- let tA2 = ((b2.x - a1.x) * va.x + (b2.y - a1.y) * va.y) / lenSqrA;
2259
- tA2 = clamp(tA2, 0, 1);
2260
- const pointOnA2 = { x: a1.x + tA2 * va.x, y: a1.y + tA2 * va.y };
2261
- let tB = ((a1.x - b1.x) * vb.x + (a1.y - b1.y) * vb.y) / lenSqrB;
2262
- tB = clamp(tB, 0, 1);
2263
- const pointOnB1 = { x: b1.x + tB * vb.x, y: b1.y + tB * vb.y };
2264
- let tB2 = ((a2.x - b1.x) * vb.x + (a2.y - b1.y) * vb.y) / lenSqrB;
2265
- tB2 = clamp(tB2, 0, 1);
2266
- const pointOnB2 = { x: b1.x + tB2 * vb.x, y: b1.y + tB2 * vb.y };
2267
- const distances = [
2268
- {
2269
- pointA: pointOnA1,
2270
- pointB: b1,
2271
- distance: Math.sqrt(
2272
- (pointOnA1.x - b1.x) ** 2 + (pointOnA1.y - b1.y) ** 2
2273
- )
2274
- },
2275
- {
2276
- pointA: pointOnA2,
2277
- pointB: b2,
2278
- distance: Math.sqrt(
2279
- (pointOnA2.x - b2.x) ** 2 + (pointOnA2.y - b2.y) ** 2
2280
- )
2281
- },
2282
- {
2283
- pointA: a1,
2284
- pointB: pointOnB1,
2285
- distance: Math.sqrt(
2286
- (a1.x - pointOnB1.x) ** 2 + (a1.y - pointOnB1.y) ** 2
2287
- )
2288
- },
2289
- {
2290
- pointA: a2,
2291
- pointB: pointOnB2,
2292
- distance: Math.sqrt(
2293
- (a2.x - pointOnB2.x) ** 2 + (a2.y - pointOnB2.y) ** 2
2294
- )
2295
- }
2296
- ];
2297
- const closestPair = distances.reduce(
2298
- (closest, current) => current.distance < closest.distance ? current : closest
2299
- );
2300
- return {
2301
- x: (closestPair.pointA.x + closestPair.pointB.x) / 2,
2302
- y: (closestPair.pointA.y + closestPair.pointB.y) / 2
2303
- };
2304
- };
2305
- var clamp = (value, min, max) => {
2306
- return Math.max(min, Math.min(max, value));
2307
- };
2308
-
2309
2599
  // lib/check-each-pcb-trace-non-overlapping/getCollidableBounds.ts
2310
2600
  import { getBoundsOfPcbElements as getBoundsOfPcbElements3 } from "@tscircuit/circuit-json-util";
2311
2601
  var getCollidableBounds = (collidable) => {
@@ -2341,32 +2631,6 @@ var getCollidableBounds = (collidable) => {
2341
2631
  return getBoundsOfPcbElements3([collidable]);
2342
2632
  };
2343
2633
 
2344
- // lib/check-each-pcb-trace-non-overlapping/getPcbPortIdsConnectedToTraces.ts
2345
- function getPcbPortIdsConnectedToRoutePoint(routePoint) {
2346
- if (routePoint.route_type !== "wire") return [];
2347
- return [routePoint.start_pcb_port_id, routePoint.end_pcb_port_id].filter(
2348
- (portId) => Boolean(portId)
2349
- );
2350
- }
2351
- function getPcbPortIdsConnectedToTrace(trace) {
2352
- const connectedPcbPorts = /* @__PURE__ */ new Set();
2353
- for (const segment of trace.route) {
2354
- for (const portId of getPcbPortIdsConnectedToRoutePoint(segment)) {
2355
- connectedPcbPorts.add(portId);
2356
- }
2357
- }
2358
- return Array.from(connectedPcbPorts);
2359
- }
2360
- function getPcbPortIdsConnectedToTraces(traces) {
2361
- const connectedPorts = /* @__PURE__ */ new Set();
2362
- for (const trace of traces) {
2363
- for (const portId of getPcbPortIdsConnectedToTrace(trace)) {
2364
- connectedPorts.add(portId);
2365
- }
2366
- }
2367
- return Array.from(connectedPorts);
2368
- }
2369
-
2370
2634
  // lib/check-each-pcb-trace-non-overlapping/getRadiusOfCircuitJsonElement.ts
2371
2635
  var getRadiusOfCircuitJsonElement = (obj) => {
2372
2636
  if (obj.type === "pcb_via") {
@@ -2396,12 +2660,12 @@ function checkEachPcbTraceNonOverlapping(circuitJson, {
2396
2660
  connMap,
2397
2661
  minClearance
2398
2662
  } = {}) {
2399
- const errors = [];
2663
+ const errors = checkPcbTraceSelfShorts(circuitJson);
2400
2664
  addStartAndEndPortIdsIfMissing(circuitJson);
2401
2665
  connMap ??= getFullConnectivityMapFromCircuitJson3(circuitJson);
2402
2666
  const board = getPcbBoard(circuitJson);
2403
2667
  minClearance ??= getBoardDrcValue(board, "min_trace_to_pad_edge_clearance") ?? DEFAULT_TRACE_MARGIN;
2404
- const pcbTraces = cju2(circuitJson).pcb_trace.list();
2668
+ const pcbTraces = cju3(circuitJson).pcb_trace.list();
2405
2669
  const pcbTraceSegments = pcbTraces.flatMap((pcbTrace) => {
2406
2670
  const segments = [];
2407
2671
  for (let i = 0; i < pcbTrace.route.length - 1; i++) {
@@ -2424,12 +2688,12 @@ function checkEachPcbTraceNonOverlapping(circuitJson, {
2424
2688
  }
2425
2689
  return segments;
2426
2690
  });
2427
- const pcbSmtPads = cju2(circuitJson).pcb_smtpad.list();
2428
- const pcbPlatedHoles = cju2(circuitJson).pcb_plated_hole.list();
2429
- const pcbPorts = cju2(circuitJson).pcb_port.list();
2430
- const pcbHoles = cju2(circuitJson).pcb_hole.list();
2431
- const pcbVias = cju2(circuitJson).pcb_via.list();
2432
- const pcbKeepouts = cju2(circuitJson).pcb_keepout.list().filter((keepout) => !keepout.allow_traces);
2691
+ const pcbSmtPads = cju3(circuitJson).pcb_smtpad.list();
2692
+ const pcbPlatedHoles = cju3(circuitJson).pcb_plated_hole.list();
2693
+ const pcbPorts = cju3(circuitJson).pcb_port.list();
2694
+ const pcbHoles = cju3(circuitJson).pcb_hole.list();
2695
+ const pcbVias = cju3(circuitJson).pcb_via.list();
2696
+ const pcbKeepouts = cju3(circuitJson).pcb_keepout.list().filter((keepout) => !keepout.allow_traces);
2433
2697
  const pcbComponentConnectionElements = [
2434
2698
  ...pcbPorts,
2435
2699
  ...pcbSmtPads,
@@ -2490,7 +2754,7 @@ function checkEachPcbTraceNonOverlapping(circuitJson, {
2490
2754
  if (segmentA.layer !== segmentB.layer) continue;
2491
2755
  if (connMap.areIdsConnected(segmentA.pcb_trace_id, segmentB.pcb_trace_id))
2492
2756
  continue;
2493
- const gap2 = segmentToSegmentMinDistance3(
2757
+ const gap2 = segmentToSegmentMinDistance4(
2494
2758
  { x: segmentA.x1, y: segmentA.y1 },
2495
2759
  { x: segmentA.x2, y: segmentA.y2 },
2496
2760
  { x: segmentB.x1, y: segmentB.y1 },
@@ -3149,7 +3413,7 @@ function checkPcbComponentOverCutout(circuitJson) {
3149
3413
  }
3150
3414
 
3151
3415
  // lib/check-pcb-copper-over-keepout.ts
3152
- import { cju as cju3, getPrimaryId as getPrimaryId3 } from "@tscircuit/circuit-json-util";
3416
+ import { cju as cju4, getPrimaryId as getPrimaryId3 } from "@tscircuit/circuit-json-util";
3153
3417
  var getErrorOwnerId = (copper) => "pcb_component_id" in copper && copper.pcb_component_id ? copper.pcb_component_id : getPrimaryId3(copper);
3154
3418
  var getReadableCopperName = (circuitJson, copper) => {
3155
3419
  if ("pcb_component_id" in copper && copper.pcb_component_id) {
@@ -3165,11 +3429,11 @@ var getReadableCopperName = (circuitJson, copper) => {
3165
3429
  return copper.type === "pcb_via" ? `via ${copper.pcb_via_id}` : `${copper.type} ${getPrimaryId3(copper)}`;
3166
3430
  };
3167
3431
  function checkPcbCopperOverKeepout(circuitJson) {
3168
- const keepouts = cju3(circuitJson).pcb_keepout.list();
3432
+ const keepouts = cju4(circuitJson).pcb_keepout.list();
3169
3433
  if (keepouts.length === 0) return [];
3170
3434
  const copper = [
3171
3435
  ...getPads(circuitJson),
3172
- ...cju3(circuitJson).pcb_via.list()
3436
+ ...cju4(circuitJson).pcb_via.list()
3173
3437
  ];
3174
3438
  const errors = /* @__PURE__ */ new Map();
3175
3439
  for (const keepout of keepouts) {
@@ -3346,11 +3610,11 @@ function checkDifferentNetViaSpacing(circuitJson, {
3346
3610
  }
3347
3611
 
3348
3612
  // lib/check-source-traces-match-pcb-trace-thickness.ts
3349
- import { cju as cju4 } from "@tscircuit/circuit-json-util";
3613
+ import { cju as cju5 } from "@tscircuit/circuit-json-util";
3350
3614
  import { getFullConnectivityMapFromCircuitJson as getFullConnectivityMapFromCircuitJson6 } from "circuit-json-to-connectivity-map";
3351
3615
  function checkSourceTracesMatchPcbTraceThickness(circuitJson) {
3352
3616
  const warnings = [];
3353
- const db = cju4(circuitJson);
3617
+ const db = cju5(circuitJson);
3354
3618
  const sourceTraces = db.source_trace.list();
3355
3619
  const pcbTraces = db.pcb_trace.list();
3356
3620
  const pcbPorts = db.pcb_port.list();
@@ -3489,7 +3753,7 @@ import {
3489
3753
 
3490
3754
  // lib/check-traces-are-contiguous/via-contact-index.ts
3491
3755
  import {
3492
- all_layers as all_layers2
3756
+ all_layers as all_layers4
3493
3757
  } from "circuit-json";
3494
3758
  import { getPrimaryId as getPrimaryId4 } from "@tscircuit/circuit-json-util";
3495
3759
  import { pointToSegmentDistance as pointToSegmentDistance2 } from "@tscircuit/math-utils";
@@ -3501,7 +3765,7 @@ function getViaContactIndex(circuitJson, connectivity) {
3501
3765
  const vias = circuitJson.filter((element) => element.type === "pcb_via");
3502
3766
  const board = circuitJson.find((element) => element.type === "pcb_board");
3503
3767
  const layerCount = board?.num_layers;
3504
- const innerLayers = all_layers2.filter((layer) => layer.startsWith("inner"));
3768
+ const innerLayers = all_layers4.filter((layer) => layer.startsWith("inner"));
3505
3769
  const stack = [
3506
3770
  "top",
3507
3771
  ...innerLayers.slice(
@@ -4027,8 +4291,8 @@ function checkTracesAreContiguous(circuitJson, {
4027
4291
  }
4028
4292
 
4029
4293
  // lib/check-trace-out-of-board/checkTraceOutOfBoard.ts
4030
- import { cju as cju5 } from "@tscircuit/circuit-json-util";
4031
- import { segmentToSegmentMinDistance as segmentToSegmentMinDistance4 } from "@tscircuit/math-utils";
4294
+ import { cju as cju6 } from "@tscircuit/circuit-json-util";
4295
+ import { segmentToSegmentMinDistance as segmentToSegmentMinDistance5 } from "@tscircuit/math-utils";
4032
4296
  function getBoardPolygonPoints(board) {
4033
4297
  if (board.outline && board.outline.length > 0) {
4034
4298
  return board.outline.map((p) => ({ x: p.x, y: p.y }));
@@ -4058,7 +4322,7 @@ function checkPcbTracesOutOfBoard(circuitJson, config = {}) {
4058
4322
  const margin = config.margin ?? getBoardDrcValue(board, "min_board_edge_clearance") ?? jlcMinTolerances.min_board_edge_clearance;
4059
4323
  const boardPoints = getBoardPolygonPoints(board);
4060
4324
  if (!boardPoints) return errors;
4061
- const pcbTraces = cju5(circuitJson).pcb_trace.list();
4325
+ const pcbTraces = cju6(circuitJson).pcb_trace.list();
4062
4326
  for (const trace of pcbTraces) {
4063
4327
  if (trace.route.length < 2) continue;
4064
4328
  for (let i = 0; i < trace.route.length - 1; i++) {
@@ -4072,7 +4336,7 @@ function checkPcbTracesOutOfBoard(circuitJson, config = {}) {
4072
4336
  for (let j = 0; j < boardPoints.length; j++) {
4073
4337
  const edgeStart = boardPoints[j];
4074
4338
  const edgeEnd = boardPoints[(j + 1) % boardPoints.length];
4075
- const distance3 = segmentToSegmentMinDistance4(
4339
+ const distance3 = segmentToSegmentMinDistance5(
4076
4340
  segmentStart,
4077
4341
  segmentEnd,
4078
4342
  edgeStart,
@@ -4107,7 +4371,7 @@ function checkPcbTracesOutOfBoard(circuitJson, config = {}) {
4107
4371
 
4108
4372
  // lib/check-pcb-components-overlap/checkPcbComponentOverlap.ts
4109
4373
  import {
4110
- cju as cju6,
4374
+ cju as cju7,
4111
4375
  getBoundsOfPcbElements as getBoundsOfPcbElements5,
4112
4376
  getPrimaryId as getPrimaryId5
4113
4377
  } from "@tscircuit/circuit-json-util";
@@ -4205,9 +4469,9 @@ function checkPcbComponentOverlap(circuitJson) {
4205
4469
  )
4206
4470
  );
4207
4471
  const connMap = getFullConnectivityMapFromCircuitJson9(circuitJson);
4208
- const smtPads = cju6(circuitJson).pcb_smtpad.list();
4209
- const platedHoles = cju6(circuitJson).pcb_plated_hole.list();
4210
- const holes = cju6(circuitJson).pcb_hole.list();
4472
+ const smtPads = cju7(circuitJson).pcb_smtpad.list();
4473
+ const platedHoles = cju7(circuitJson).pcb_plated_hole.list();
4474
+ const holes = cju7(circuitJson).pcb_hole.list();
4211
4475
  const courtyards = circuitJson.filter(isCourtyardElement2);
4212
4476
  const componentMap = /* @__PURE__ */ new Map();
4213
4477
  for (const pad of smtPads) {
@@ -4949,7 +5213,7 @@ function checkTwoTerminalSwitchContactsOnDifferentNets(circuitJson) {
4949
5213
  }
4950
5214
 
4951
5215
  // lib/check-all-pins-in-component-are-underspecified.ts
4952
- import { cju as cju7 } from "@tscircuit/circuit-json-util";
5216
+ import { cju as cju8 } from "@tscircuit/circuit-json-util";
4953
5217
  var PIN_ATTRIBUTE_KEYS = [
4954
5218
  "must_be_connected",
4955
5219
  "provides_power",
@@ -4994,7 +5258,7 @@ function hasAnyPinAttribute(port) {
4994
5258
  }
4995
5259
  function checkAllPinsInComponentAreUnderspecified(circuitJson) {
4996
5260
  const warnings = [];
4997
- const db = cju7(circuitJson);
5261
+ const db = cju8(circuitJson);
4998
5262
  const sourceComponents = db.source_component.list();
4999
5263
  const sourcePorts = db.source_port.list();
5000
5264
  const portsByComponent = /* @__PURE__ */ new Map();
@@ -5026,7 +5290,7 @@ function checkAllPinsInComponentAreUnderspecified(circuitJson) {
5026
5290
  }
5027
5291
 
5028
5292
  // lib/check-no-power-pin-defined.ts
5029
- import { cju as cju8 } from "@tscircuit/circuit-json-util";
5293
+ import { cju as cju9 } from "@tscircuit/circuit-json-util";
5030
5294
 
5031
5295
  // lib/util/should-check-chip-power-ground-pins.ts
5032
5296
  var shouldCheckChipPowerGroundPins = (component, ports) => component.ftype === "simple_chip" && ports.filter((port) => port.do_not_connect !== true).length >= 2;
@@ -5034,7 +5298,7 @@ var shouldCheckChipPowerGroundPins = (component, ports) => component.ftype === "
5034
5298
  // lib/check-no-power-pin-defined.ts
5035
5299
  function checkNoPowerPinDefined(circuitJson) {
5036
5300
  const warnings = [];
5037
- const db = cju8(circuitJson);
5301
+ const db = cju9(circuitJson);
5038
5302
  const sourceComponents = db.source_component.list();
5039
5303
  const sourcePorts = db.source_port.list();
5040
5304
  const portsByComponent = /* @__PURE__ */ new Map();
@@ -5065,10 +5329,10 @@ function checkNoPowerPinDefined(circuitJson) {
5065
5329
  }
5066
5330
 
5067
5331
  // lib/check-no-ground-pin-defined.ts
5068
- import { cju as cju9 } from "@tscircuit/circuit-json-util";
5332
+ import { cju as cju10 } from "@tscircuit/circuit-json-util";
5069
5333
  function checkNoGroundPinDefined(circuitJson) {
5070
5334
  const warnings = [];
5071
- const db = cju9(circuitJson);
5335
+ const db = cju10(circuitJson);
5072
5336
  const sourceComponents = db.source_component.list();
5073
5337
  const sourcePorts = db.source_port.list();
5074
5338
  const portsByComponent = /* @__PURE__ */ new Map();
@@ -5929,6 +6193,7 @@ export {
5929
6193
  checkPcbComponentsOutOfBoard,
5930
6194
  checkPcbCopperOverKeepout,
5931
6195
  checkPcbTraceLengths,
6196
+ checkPcbTraceSelfShorts,
5932
6197
  checkPcbTraceViaCounts,
5933
6198
  checkPcbTracesOutOfBoard,
5934
6199
  checkPinMustBeConnected,