@tscircuit/checks 0.0.123 → 0.0.125
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 +236 -24
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -363,12 +363,14 @@ var jlcMinTolerances = {
|
|
|
363
363
|
var DEFAULT_TRACE_MARGIN = 0.1;
|
|
364
364
|
var DEFAULT_TRACE_THICKNESS = jlcMinTolerances.min_trace_width;
|
|
365
365
|
var DEFAULT_VIA_DIAMETER = jlcMinTolerances.min_via_pad_diameter;
|
|
366
|
-
var DEFAULT_VIA_BOARD_MARGIN =
|
|
366
|
+
var DEFAULT_VIA_BOARD_MARGIN = jlcMinTolerances.min_board_edge_clearance;
|
|
367
367
|
var DEFAULT_SAME_NET_VIA_MARGIN = jlcMinTolerances.min_via_hole_edge_to_via_hole_edge_clearance;
|
|
368
368
|
var DEFAULT_DIFFERENT_NET_VIA_MARGIN = jlcMinTolerances.min_via_hole_edge_to_via_hole_edge_clearance;
|
|
369
369
|
var DEFAULT_PAD_PAD_CLEARANCE = jlcMinTolerances.min_pad_edge_to_pad_edge_clearance;
|
|
370
370
|
var DEFAULT_PAD_TRACE_CLEARANCE = jlcMinTolerances.min_trace_to_pad_edge_clearance;
|
|
371
371
|
var EPSILON = 5e-3;
|
|
372
|
+
var getPcbBoard = (circuitJson) => circuitJson.find((el) => el.type === "pcb_board");
|
|
373
|
+
var getBoardDrcValue = (board, key) => board?.[key];
|
|
372
374
|
|
|
373
375
|
// lib/util/getLayersOfPcbElement.ts
|
|
374
376
|
import { all_layers } from "circuit-json";
|
|
@@ -570,7 +572,7 @@ var getClosestPointBetweenSegments = (segmentA, segmentB) => {
|
|
|
570
572
|
};
|
|
571
573
|
const dx = closestOnA.x - closestOnB.x;
|
|
572
574
|
const dy = closestOnA.y - closestOnB.y;
|
|
573
|
-
const
|
|
575
|
+
const distance4 = Math.sqrt(dx * dx + dy * dy);
|
|
574
576
|
const averagePoint = {
|
|
575
577
|
x: (closestOnA.x + closestOnB.x) / 2,
|
|
576
578
|
y: (closestOnA.y + closestOnB.y) / 2
|
|
@@ -802,12 +804,12 @@ function checkEachPcbTraceNonOverlapping(circuitJson, {
|
|
|
802
804
|
const isCircular = obj.type === "pcb_via" || obj.type === "pcb_plated_hole" && obj.shape === "circle" || obj.type === "pcb_hole" || obj.type === "pcb_smtpad" && obj.shape === "circle";
|
|
803
805
|
if (isCircular) {
|
|
804
806
|
const radius = getRadiusOfCircuitJsonElement(obj);
|
|
805
|
-
const
|
|
807
|
+
const distance4 = segmentToCircleMinDistance(
|
|
806
808
|
{ x: segmentA.x1, y: segmentA.y1 },
|
|
807
809
|
{ x: segmentA.x2, y: segmentA.y2 },
|
|
808
810
|
{ x: obj.x, y: obj.y, radius }
|
|
809
811
|
);
|
|
810
|
-
const gap2 =
|
|
812
|
+
const gap2 = distance4 - segmentA.thickness / 2;
|
|
811
813
|
if (gap2 > minClearance - EPSILON) continue;
|
|
812
814
|
const pcb_trace_error_id = `overlap_${segmentA.pcb_trace_id}_${primaryObjId}`;
|
|
813
815
|
if (errorIds.has(pcb_trace_error_id)) continue;
|
|
@@ -919,11 +921,12 @@ var NetManager = class {
|
|
|
919
921
|
// lib/check-pcb-components-out-of-board/checkViasOffBoard.ts
|
|
920
922
|
import { getReadableNameForElement as getReadableNameForElement3 } from "@tscircuit/circuit-json-util";
|
|
921
923
|
function checkViasOffBoard(circuitJson) {
|
|
922
|
-
const board = circuitJson
|
|
924
|
+
const board = getPcbBoard(circuitJson);
|
|
923
925
|
if (!board) return [];
|
|
924
926
|
const vias = circuitJson.filter((el) => el.type === "pcb_via");
|
|
925
927
|
if (vias.length === 0) return [];
|
|
926
928
|
if (board.width === void 0 || board.height === void 0) return [];
|
|
929
|
+
const boardEdgeClearance = getBoardDrcValue(board, "min_board_edge_clearance") ?? jlcMinTolerances.min_board_edge_clearance;
|
|
927
930
|
const boardMinX = board.center.x - board.width / 2;
|
|
928
931
|
const boardMaxX = board.center.x + board.width / 2;
|
|
929
932
|
const boardMinY = board.center.y - board.height / 2;
|
|
@@ -935,7 +938,7 @@ function checkViasOffBoard(circuitJson) {
|
|
|
935
938
|
const viaMaxX = via.x + viaRadius;
|
|
936
939
|
const viaMinY = via.y - viaRadius;
|
|
937
940
|
const viaMaxY = via.y + viaRadius;
|
|
938
|
-
if (viaMinX < boardMinX +
|
|
941
|
+
if (viaMinX < boardMinX + boardEdgeClearance || viaMaxX > boardMaxX - boardEdgeClearance || viaMinY < boardMinY + boardEdgeClearance || viaMaxY > boardMaxY - boardEdgeClearance) {
|
|
939
942
|
const viaName = getReadableNameForElement3(circuitJson, via.pcb_via_id);
|
|
940
943
|
errors.push({
|
|
941
944
|
type: "pcb_placement_error",
|
|
@@ -1199,10 +1202,12 @@ function viasAreAtSameLocation(a, b) {
|
|
|
1199
1202
|
// lib/check-same-net-via-spacing.ts
|
|
1200
1203
|
function checkSameNetViaSpacing(circuitJson, {
|
|
1201
1204
|
connMap,
|
|
1202
|
-
minClearance
|
|
1205
|
+
minClearance
|
|
1203
1206
|
} = {}) {
|
|
1204
1207
|
const vias = circuitJson.filter((el) => el.type === "pcb_via");
|
|
1205
1208
|
if (vias.length < 2) return [];
|
|
1209
|
+
const board = getPcbBoard(circuitJson);
|
|
1210
|
+
minClearance ??= getBoardDrcValue(board, "min_via_hole_edge_to_via_hole_edge_clearance") ?? jlcMinTolerances.min_via_hole_edge_to_via_hole_edge_clearance;
|
|
1206
1211
|
connMap ??= getFullConnectivityMapFromCircuitJson3(circuitJson);
|
|
1207
1212
|
const errors = [];
|
|
1208
1213
|
const reported = /* @__PURE__ */ new Set();
|
|
@@ -1212,7 +1217,7 @@ function checkSameNetViaSpacing(circuitJson, {
|
|
|
1212
1217
|
const viaB = vias[j];
|
|
1213
1218
|
if (viasAreAtSameLocation(viaA, viaB)) continue;
|
|
1214
1219
|
if (!connMap.areIdsConnected(viaA.pcb_via_id, viaB.pcb_via_id)) continue;
|
|
1215
|
-
const gap = distance2(viaA, viaB) - viaA.
|
|
1220
|
+
const gap = distance2(viaA, viaB) - viaA.hole_diameter / 2 - viaB.hole_diameter / 2;
|
|
1216
1221
|
if (gap + EPSILON >= minClearance) continue;
|
|
1217
1222
|
const pairId = [viaA.pcb_via_id, viaB.pcb_via_id].sort().join("_");
|
|
1218
1223
|
if (reported.has(pairId)) continue;
|
|
@@ -1248,10 +1253,12 @@ import {
|
|
|
1248
1253
|
} from "circuit-json-to-connectivity-map";
|
|
1249
1254
|
function checkDifferentNetViaSpacing(circuitJson, {
|
|
1250
1255
|
connMap,
|
|
1251
|
-
minClearance
|
|
1256
|
+
minClearance
|
|
1252
1257
|
} = {}) {
|
|
1253
1258
|
const vias = circuitJson.filter((el) => el.type === "pcb_via");
|
|
1254
1259
|
if (vias.length < 2) return [];
|
|
1260
|
+
const board = getPcbBoard(circuitJson);
|
|
1261
|
+
minClearance ??= getBoardDrcValue(board, "min_via_hole_edge_to_via_hole_edge_clearance") ?? jlcMinTolerances.min_via_hole_edge_to_via_hole_edge_clearance;
|
|
1255
1262
|
connMap ??= getFullConnectivityMapFromCircuitJson4(circuitJson);
|
|
1256
1263
|
const errors = [];
|
|
1257
1264
|
const reported = /* @__PURE__ */ new Set();
|
|
@@ -1261,7 +1268,7 @@ function checkDifferentNetViaSpacing(circuitJson, {
|
|
|
1261
1268
|
const viaB = vias[j];
|
|
1262
1269
|
if (viasAreAtSameLocation(viaA, viaB)) continue;
|
|
1263
1270
|
if (connMap.areIdsConnected(viaA.pcb_via_id, viaB.pcb_via_id)) continue;
|
|
1264
|
-
const gap = distance2(viaA, viaB) - viaA.
|
|
1271
|
+
const gap = distance2(viaA, viaB) - viaA.hole_diameter / 2 - viaB.hole_diameter / 2;
|
|
1265
1272
|
if (gap + EPSILON >= minClearance) continue;
|
|
1266
1273
|
const pairId = [viaA.pcb_via_id, viaB.pcb_via_id].sort().join("_");
|
|
1267
1274
|
if (reported.has(pairId)) continue;
|
|
@@ -1414,7 +1421,6 @@ function checkSourceTracesHavePcbTraces(circuitJson) {
|
|
|
1414
1421
|
// lib/check-trace-out-of-board/checkTraceOutOfBoard.ts
|
|
1415
1422
|
import { cju as cju3 } from "@tscircuit/circuit-json-util";
|
|
1416
1423
|
import { segmentToSegmentMinDistance as segmentToSegmentMinDistance2 } from "@tscircuit/math-utils";
|
|
1417
|
-
var DEFAULT_BOARD_MARGIN = 0.2;
|
|
1418
1424
|
function getBoardPolygonPoints(board) {
|
|
1419
1425
|
if (board.outline && board.outline.length > 0) {
|
|
1420
1426
|
return board.outline.map((p) => ({ x: p.x, y: p.y }));
|
|
@@ -1439,11 +1445,9 @@ function getBoardPolygonPoints(board) {
|
|
|
1439
1445
|
}
|
|
1440
1446
|
function checkPcbTracesOutOfBoard(circuitJson, config = {}) {
|
|
1441
1447
|
const errors = [];
|
|
1442
|
-
const
|
|
1443
|
-
const board = circuitJson.find(
|
|
1444
|
-
(el) => el.type === "pcb_board"
|
|
1445
|
-
);
|
|
1448
|
+
const board = getPcbBoard(circuitJson);
|
|
1446
1449
|
if (!board) return errors;
|
|
1450
|
+
const margin = config.margin ?? getBoardDrcValue(board, "min_board_edge_clearance") ?? jlcMinTolerances.min_board_edge_clearance;
|
|
1447
1451
|
const boardPoints = getBoardPolygonPoints(board);
|
|
1448
1452
|
if (!boardPoints) return errors;
|
|
1449
1453
|
const pcbTraces = cju3(circuitJson).pcb_trace.list();
|
|
@@ -1456,18 +1460,18 @@ function checkPcbTracesOutOfBoard(circuitJson, config = {}) {
|
|
|
1456
1460
|
const traceWidth = "width" in p1 ? p1.width : "width" in p2 ? p2.width : 0.1;
|
|
1457
1461
|
const segmentStart = { x: p1.x, y: p1.y };
|
|
1458
1462
|
const segmentEnd = { x: p2.x, y: p2.y };
|
|
1459
|
-
let minDistance =
|
|
1463
|
+
let minDistance = Number.POSITIVE_INFINITY;
|
|
1460
1464
|
for (let j = 0; j < boardPoints.length; j++) {
|
|
1461
1465
|
const edgeStart = boardPoints[j];
|
|
1462
1466
|
const edgeEnd = boardPoints[(j + 1) % boardPoints.length];
|
|
1463
|
-
const
|
|
1467
|
+
const distance4 = segmentToSegmentMinDistance2(
|
|
1464
1468
|
segmentStart,
|
|
1465
1469
|
segmentEnd,
|
|
1466
1470
|
edgeStart,
|
|
1467
1471
|
edgeEnd
|
|
1468
1472
|
);
|
|
1469
|
-
if (
|
|
1470
|
-
minDistance =
|
|
1473
|
+
if (distance4 < minDistance) {
|
|
1474
|
+
minDistance = distance4;
|
|
1471
1475
|
}
|
|
1472
1476
|
}
|
|
1473
1477
|
const minimumDistance = traceWidth / 2 + margin;
|
|
@@ -1741,10 +1745,12 @@ var getTraceSegments = (circuitJson) => {
|
|
|
1741
1745
|
// lib/check-pad-pad-clearance.ts
|
|
1742
1746
|
function checkPadPadClearance(circuitJson, {
|
|
1743
1747
|
connMap,
|
|
1744
|
-
minClearance
|
|
1748
|
+
minClearance
|
|
1745
1749
|
} = {}) {
|
|
1746
1750
|
const pads = getPads(circuitJson);
|
|
1747
1751
|
if (pads.length < 2) return [];
|
|
1752
|
+
const board = getPcbBoard(circuitJson);
|
|
1753
|
+
minClearance ??= getBoardDrcValue(board, "min_pad_edge_to_pad_edge_clearance") ?? jlcMinTolerances.min_pad_edge_to_pad_edge_clearance;
|
|
1748
1754
|
connMap ??= getFullConnectivityMapFromCircuitJson7(circuitJson);
|
|
1749
1755
|
const spatialIndex = new SpatialObjectIndex({
|
|
1750
1756
|
objects: pads,
|
|
@@ -1807,11 +1813,13 @@ import {
|
|
|
1807
1813
|
} from "circuit-json-to-connectivity-map";
|
|
1808
1814
|
function checkPadTraceClearance(circuitJson, {
|
|
1809
1815
|
connMap,
|
|
1810
|
-
minClearance
|
|
1816
|
+
minClearance
|
|
1811
1817
|
} = {}) {
|
|
1812
1818
|
const pads = getPads(circuitJson);
|
|
1813
1819
|
const segments = getTraceSegments(circuitJson);
|
|
1814
1820
|
if (pads.length === 0 || segments.length === 0) return [];
|
|
1821
|
+
const board = getPcbBoard(circuitJson);
|
|
1822
|
+
minClearance ??= getBoardDrcValue(board, "min_trace_to_pad_edge_clearance") ?? jlcMinTolerances.min_trace_to_pad_edge_clearance;
|
|
1815
1823
|
connMap ??= getFullConnectivityMapFromCircuitJson8(circuitJson);
|
|
1816
1824
|
const spatialIndex = new SpatialObjectIndex({
|
|
1817
1825
|
objects: pads,
|
|
@@ -1888,11 +1896,13 @@ var getClosestPointOnSegment = (point, segmentStart, segmentEnd) => {
|
|
|
1888
1896
|
};
|
|
1889
1897
|
function checkViaTraceClearance(circuitJson, {
|
|
1890
1898
|
connMap,
|
|
1891
|
-
minClearance
|
|
1899
|
+
minClearance
|
|
1892
1900
|
} = {}) {
|
|
1893
1901
|
const vias = circuitJson.filter((el) => el.type === "pcb_via");
|
|
1894
1902
|
const segments = getTraceSegments(circuitJson);
|
|
1895
1903
|
if (vias.length === 0 || segments.length === 0) return [];
|
|
1904
|
+
const board = getPcbBoard(circuitJson);
|
|
1905
|
+
minClearance ??= getBoardDrcValue(board, "min_trace_to_pad_edge_clearance") ?? jlcMinTolerances.min_trace_to_pad_edge_clearance;
|
|
1896
1906
|
connMap ??= getFullConnectivityMapFromCircuitJson9(circuitJson);
|
|
1897
1907
|
const errors = /* @__PURE__ */ new Map();
|
|
1898
1908
|
for (const via of vias) {
|
|
@@ -2338,8 +2348,210 @@ function checkCourtyardOverlap(circuitJson) {
|
|
|
2338
2348
|
return errors;
|
|
2339
2349
|
}
|
|
2340
2350
|
|
|
2351
|
+
// lib/check-traces-are-contiguous/is-point-in-pad.ts
|
|
2352
|
+
function distance3(x1, y1, x2, y2) {
|
|
2353
|
+
return Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
|
|
2354
|
+
}
|
|
2355
|
+
function isPointInPad(point, pad) {
|
|
2356
|
+
if (pad.type === "pcb_smtpad") {
|
|
2357
|
+
if (pad.shape === "circle") {
|
|
2358
|
+
return distance3(point.x, point.y, pad.x, pad.y) <= pad.radius;
|
|
2359
|
+
}
|
|
2360
|
+
if (pad.shape === "rect") {
|
|
2361
|
+
const halfWidth = pad.width / 2;
|
|
2362
|
+
const halfHeight = pad.height / 2;
|
|
2363
|
+
return Math.abs(point.x - pad.x) <= halfWidth && Math.abs(point.y - pad.y) <= halfHeight;
|
|
2364
|
+
}
|
|
2365
|
+
if (pad.shape === "rotated_rect") {
|
|
2366
|
+
const dx = point.x - pad.x;
|
|
2367
|
+
const dy = point.y - pad.y;
|
|
2368
|
+
const angle = -pad.ccw_rotation;
|
|
2369
|
+
const rotatedX = dx * Math.cos(angle) - dy * Math.sin(angle);
|
|
2370
|
+
const rotatedY = dx * Math.sin(angle) + dy * Math.cos(angle);
|
|
2371
|
+
return Math.abs(rotatedX) <= pad.width / 2 && Math.abs(rotatedY) <= pad.height / 2;
|
|
2372
|
+
}
|
|
2373
|
+
if (pad.shape === "pill") {
|
|
2374
|
+
const halfWidth = pad.width / 2;
|
|
2375
|
+
const halfHeight = pad.height / 2;
|
|
2376
|
+
const radius = pad.radius;
|
|
2377
|
+
if (Math.abs(point.x - pad.x) <= halfWidth - radius && Math.abs(point.y - pad.y) <= halfHeight) {
|
|
2378
|
+
return true;
|
|
2379
|
+
}
|
|
2380
|
+
const cornerX = Math.max(
|
|
2381
|
+
Math.abs(point.x - pad.x) - (halfWidth - radius),
|
|
2382
|
+
0
|
|
2383
|
+
);
|
|
2384
|
+
const cornerY = Math.max(
|
|
2385
|
+
Math.abs(point.y - pad.y) - (halfHeight - radius),
|
|
2386
|
+
0
|
|
2387
|
+
);
|
|
2388
|
+
return cornerX * cornerX + cornerY * cornerY <= radius * radius;
|
|
2389
|
+
}
|
|
2390
|
+
}
|
|
2391
|
+
if (pad.type === "pcb_plated_hole") {
|
|
2392
|
+
if (pad.shape === "circle") {
|
|
2393
|
+
return distance3(point.x, point.y, pad.x, pad.y) <= pad.outer_diameter / 2;
|
|
2394
|
+
}
|
|
2395
|
+
if (pad.shape === "oval" || pad.shape === "pill") {
|
|
2396
|
+
return Math.abs(point.x - pad.x) <= pad.outer_width / 2 && Math.abs(point.y - pad.y) <= pad.outer_height / 2;
|
|
2397
|
+
}
|
|
2398
|
+
if (pad.shape === "circular_hole_with_rect_pad") {
|
|
2399
|
+
return Math.abs(point.x - pad.x) <= pad.rect_pad_width / 2 && Math.abs(point.y - pad.y) <= pad.rect_pad_height / 2;
|
|
2400
|
+
}
|
|
2401
|
+
if (pad.shape === "pill_hole_with_rect_pad") {
|
|
2402
|
+
return Math.abs(point.x - pad.x) <= pad.rect_pad_width / 2 && Math.abs(point.y - pad.y) <= pad.rect_pad_height / 2;
|
|
2403
|
+
}
|
|
2404
|
+
}
|
|
2405
|
+
return false;
|
|
2406
|
+
}
|
|
2407
|
+
|
|
2341
2408
|
// lib/check-traces-are-contiguous/check-traces-are-contiguous.ts
|
|
2342
|
-
import {
|
|
2409
|
+
import {
|
|
2410
|
+
getReadableNameForPcbPort as getReadableNameForPcbPort2,
|
|
2411
|
+
getReadableNameForPcbTrace
|
|
2412
|
+
} from "@tscircuit/circuit-json-util";
|
|
2413
|
+
function checkTracesAreContiguous(circuitJson) {
|
|
2414
|
+
const errors = [];
|
|
2415
|
+
const pcbPorts = circuitJson.filter(
|
|
2416
|
+
(el) => el.type === "pcb_port"
|
|
2417
|
+
);
|
|
2418
|
+
const pcbTraces = circuitJson.filter(
|
|
2419
|
+
(el) => el.type === "pcb_trace"
|
|
2420
|
+
);
|
|
2421
|
+
const sourceTraces = circuitJson.filter(
|
|
2422
|
+
(el) => el.type === "source_trace"
|
|
2423
|
+
);
|
|
2424
|
+
const pcbSmtPads = circuitJson.filter(
|
|
2425
|
+
(el) => el.type === "pcb_smtpad"
|
|
2426
|
+
);
|
|
2427
|
+
const pcbPlatedHoles = circuitJson.filter(
|
|
2428
|
+
(el) => el.type === "pcb_plated_hole"
|
|
2429
|
+
);
|
|
2430
|
+
const padMap = /* @__PURE__ */ new Map();
|
|
2431
|
+
for (const pad of pcbSmtPads) {
|
|
2432
|
+
if (pad.pcb_port_id) {
|
|
2433
|
+
padMap.set(pad.pcb_port_id, pad);
|
|
2434
|
+
}
|
|
2435
|
+
}
|
|
2436
|
+
for (const hole of pcbPlatedHoles) {
|
|
2437
|
+
if (hole.pcb_port_id) {
|
|
2438
|
+
padMap.set(hole.pcb_port_id, hole);
|
|
2439
|
+
}
|
|
2440
|
+
}
|
|
2441
|
+
for (const trace of pcbTraces) {
|
|
2442
|
+
if (trace.route.length === 0) continue;
|
|
2443
|
+
const firstPoint = trace.route[0];
|
|
2444
|
+
const lastPoint = trace.route[trace.route.length - 1];
|
|
2445
|
+
const sourceTrace = sourceTraces.find(
|
|
2446
|
+
(st) => st.source_trace_id === trace.source_trace_id
|
|
2447
|
+
);
|
|
2448
|
+
const expectedPorts = sourceTrace ? pcbPorts.filter(
|
|
2449
|
+
(port) => sourceTrace.connected_source_port_ids?.includes(port.source_port_id)
|
|
2450
|
+
) : [];
|
|
2451
|
+
for (let i = 1; i < trace.route.length - 1; i++) {
|
|
2452
|
+
const prevPoint = trace.route[i - 1];
|
|
2453
|
+
const currentPoint = trace.route[i];
|
|
2454
|
+
const nextPoint = trace.route[i + 1];
|
|
2455
|
+
if (currentPoint.route_type === "via") {
|
|
2456
|
+
const prevIsWire = prevPoint.route_type === "wire";
|
|
2457
|
+
const nextIsWire = nextPoint.route_type === "wire";
|
|
2458
|
+
if (prevIsWire && nextIsWire) {
|
|
2459
|
+
const prevAligned = Math.abs(prevPoint.x - currentPoint.x) < 0.01 && Math.abs(prevPoint.y - currentPoint.y) < 0.01;
|
|
2460
|
+
const nextAligned = Math.abs(nextPoint.x - currentPoint.x) < 0.01 && Math.abs(nextPoint.y - currentPoint.y) < 0.01;
|
|
2461
|
+
if (!prevAligned || !nextAligned) {
|
|
2462
|
+
const traceName2 = getReadableNameForPcbTrace(
|
|
2463
|
+
circuitJson,
|
|
2464
|
+
trace.pcb_trace_id
|
|
2465
|
+
);
|
|
2466
|
+
errors.push({
|
|
2467
|
+
type: "pcb_trace_error",
|
|
2468
|
+
message: `Via in trace [${traceName2}] is misaligned at position {x: ${currentPoint.x}, y: ${currentPoint.y}}.`,
|
|
2469
|
+
source_trace_id: sourceTrace?.source_trace_id || trace.source_trace_id || `!${trace.pcb_trace_id}`,
|
|
2470
|
+
error_type: "pcb_trace_error",
|
|
2471
|
+
pcb_trace_id: trace.pcb_trace_id,
|
|
2472
|
+
pcb_trace_error_id: `misaligned_via_${trace.pcb_trace_id}_${i}`,
|
|
2473
|
+
pcb_component_ids: [],
|
|
2474
|
+
pcb_port_ids: []
|
|
2475
|
+
});
|
|
2476
|
+
}
|
|
2477
|
+
}
|
|
2478
|
+
}
|
|
2479
|
+
}
|
|
2480
|
+
const traceName = getReadableNameForPcbTrace(
|
|
2481
|
+
circuitJson,
|
|
2482
|
+
trace.pcb_trace_id
|
|
2483
|
+
);
|
|
2484
|
+
for (const port of expectedPorts) {
|
|
2485
|
+
if (!port.pcb_port_id) continue;
|
|
2486
|
+
const pad = padMap.get(port.pcb_port_id);
|
|
2487
|
+
if (!pad) continue;
|
|
2488
|
+
const isFirstPointConnected = firstPoint.route_type === "wire" && isPointInPad({ x: firstPoint.x, y: firstPoint.y }, pad);
|
|
2489
|
+
const isLastPointConnected = lastPoint.route_type === "wire" && isPointInPad({ x: lastPoint.x, y: lastPoint.y }, pad);
|
|
2490
|
+
if (!isFirstPointConnected && !isLastPointConnected) {
|
|
2491
|
+
const portName = getReadableNameForPcbPort2(
|
|
2492
|
+
circuitJson,
|
|
2493
|
+
port.pcb_port_id
|
|
2494
|
+
).replace("pcb_port", "");
|
|
2495
|
+
const padType = pad.type.replace(/pcb_/, "");
|
|
2496
|
+
const errorCenter = {
|
|
2497
|
+
x: (firstPoint.x + lastPoint.x) / 2,
|
|
2498
|
+
y: (firstPoint.y + lastPoint.y) / 2
|
|
2499
|
+
};
|
|
2500
|
+
errors.push({
|
|
2501
|
+
type: "pcb_trace_error",
|
|
2502
|
+
message: `Trace [${traceName}] is missing a connection to ${padType}${portName}`,
|
|
2503
|
+
source_trace_id: sourceTrace?.source_trace_id || trace.source_trace_id || `!${trace.pcb_trace_id}`,
|
|
2504
|
+
error_type: "pcb_trace_error",
|
|
2505
|
+
pcb_trace_id: trace.pcb_trace_id,
|
|
2506
|
+
pcb_trace_error_id: `missing_connection_${trace.pcb_trace_id}_${port.pcb_port_id}`,
|
|
2507
|
+
center: errorCenter,
|
|
2508
|
+
pcb_component_ids: [],
|
|
2509
|
+
pcb_port_ids: [port.pcb_port_id]
|
|
2510
|
+
});
|
|
2511
|
+
}
|
|
2512
|
+
}
|
|
2513
|
+
if (expectedPorts.length === 0) {
|
|
2514
|
+
let firstConnectsToAnyPad = false;
|
|
2515
|
+
let lastConnectsToAnyPad = false;
|
|
2516
|
+
const endpointsAreSame = firstPoint.route_type === "wire" && lastPoint.route_type === "wire" && Math.abs(firstPoint.x - lastPoint.x) < 0.01 && Math.abs(firstPoint.y - lastPoint.y) < 0.01;
|
|
2517
|
+
for (const [portId, pad] of padMap) {
|
|
2518
|
+
if (firstPoint.route_type === "wire" && isPointInPad({ x: firstPoint.x, y: firstPoint.y }, pad)) {
|
|
2519
|
+
firstConnectsToAnyPad = true;
|
|
2520
|
+
}
|
|
2521
|
+
if (lastPoint.route_type === "wire" && isPointInPad({ x: lastPoint.x, y: lastPoint.y }, pad)) {
|
|
2522
|
+
lastConnectsToAnyPad = true;
|
|
2523
|
+
}
|
|
2524
|
+
}
|
|
2525
|
+
if (!firstConnectsToAnyPad && firstPoint.route_type === "wire") {
|
|
2526
|
+
errors.push({
|
|
2527
|
+
type: "pcb_trace_error",
|
|
2528
|
+
message: `Trace [${traceName}] has disconnected endpoint at (${firstPoint.x.toFixed(2)}, ${firstPoint.y.toFixed(2)})`,
|
|
2529
|
+
source_trace_id: sourceTrace?.source_trace_id || trace.source_trace_id || `!${trace.pcb_trace_id}`,
|
|
2530
|
+
error_type: "pcb_trace_error",
|
|
2531
|
+
pcb_trace_id: trace.pcb_trace_id,
|
|
2532
|
+
pcb_trace_error_id: `disconnected_endpoint_${trace.pcb_trace_id}_start`,
|
|
2533
|
+
center: { x: firstPoint.x, y: firstPoint.y },
|
|
2534
|
+
pcb_component_ids: [],
|
|
2535
|
+
pcb_port_ids: []
|
|
2536
|
+
});
|
|
2537
|
+
}
|
|
2538
|
+
if (!lastConnectsToAnyPad && lastPoint.route_type === "wire" && !(endpointsAreSame && !firstConnectsToAnyPad)) {
|
|
2539
|
+
errors.push({
|
|
2540
|
+
type: "pcb_trace_error",
|
|
2541
|
+
message: `Trace [${traceName}] has disconnected endpoint at (${lastPoint.x.toFixed(2)}, ${lastPoint.y.toFixed(2)})`,
|
|
2542
|
+
source_trace_id: sourceTrace?.source_trace_id || trace.source_trace_id || `!${trace.pcb_trace_id}`,
|
|
2543
|
+
error_type: "pcb_trace_error",
|
|
2544
|
+
pcb_trace_id: trace.pcb_trace_id,
|
|
2545
|
+
pcb_trace_error_id: `disconnected_endpoint_${trace.pcb_trace_id}_end`,
|
|
2546
|
+
center: { x: lastPoint.x, y: lastPoint.y },
|
|
2547
|
+
pcb_component_ids: [],
|
|
2548
|
+
pcb_port_ids: []
|
|
2549
|
+
});
|
|
2550
|
+
}
|
|
2551
|
+
}
|
|
2552
|
+
}
|
|
2553
|
+
return errors;
|
|
2554
|
+
}
|
|
2343
2555
|
|
|
2344
2556
|
// lib/run-all-checks.ts
|
|
2345
2557
|
async function runAllPlacementChecks(circuitJson) {
|
|
@@ -2371,7 +2583,7 @@ async function runAllRoutingChecks(circuitJson) {
|
|
|
2371
2583
|
...checkViaTraceClearance(circuitJson),
|
|
2372
2584
|
...checkSameNetViaSpacing(circuitJson),
|
|
2373
2585
|
...checkDifferentNetViaSpacing(circuitJson),
|
|
2374
|
-
|
|
2586
|
+
...checkTracesAreContiguous(circuitJson),
|
|
2375
2587
|
...checkPcbTracesOutOfBoard(circuitJson)
|
|
2376
2588
|
];
|
|
2377
2589
|
}
|