@tscircuit/checks 0.0.193 → 0.0.195
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 +2 -2
- package/dist/index.js +222 -35
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -57,8 +57,8 @@ declare function checkSourceTracesMatchPcbTraceThickness(circuitJson: AnyCircuit
|
|
|
57
57
|
|
|
58
58
|
/**
|
|
59
59
|
* Check that each source_trace which connects source ports has at least one
|
|
60
|
-
* pcb_trace associated with it
|
|
61
|
-
*
|
|
60
|
+
* pcb_trace associated with it, or its ports physically joined through a
|
|
61
|
+
* same-net copper pour. Otherwise return an error for that source_trace.
|
|
62
62
|
*/
|
|
63
63
|
declare function checkSourceTracesHavePcbTraces(circuitJson: AnyCircuitElement[]): PcbTraceMissingError[];
|
|
64
64
|
|
package/dist/index.js
CHANGED
|
@@ -464,6 +464,169 @@ function getReadableNameForFootprintPad(circuitJson, pad, ordinal) {
|
|
|
464
464
|
return `${padKind} #${ordinal + 1} at ${location}`;
|
|
465
465
|
}
|
|
466
466
|
|
|
467
|
+
// lib/copper-pour-connectivity/get-copper-pour-connectivity.ts
|
|
468
|
+
import {
|
|
469
|
+
getPrimaryId,
|
|
470
|
+
copperPolygonsTouch,
|
|
471
|
+
getPlatedHolePolygon,
|
|
472
|
+
getPourPolygon,
|
|
473
|
+
getSmtPadPolygon,
|
|
474
|
+
getTraceSegmentPolygon,
|
|
475
|
+
getViaPolygon
|
|
476
|
+
} from "@tscircuit/circuit-json-util";
|
|
477
|
+
function getCopperPourConnectivity(circuitJson, connectivity) {
|
|
478
|
+
const scale = 1e6;
|
|
479
|
+
const tolerance = 1e-7 * scale;
|
|
480
|
+
const conductors = [];
|
|
481
|
+
const pouredNets = /* @__PURE__ */ new Set();
|
|
482
|
+
const netForId = (id) => connectivity.getNetConnectedToId(id);
|
|
483
|
+
const add = (conductor) => {
|
|
484
|
+
if (!conductor.polygon.isEmpty()) {
|
|
485
|
+
conductors.push({
|
|
486
|
+
...conductor,
|
|
487
|
+
polygon: conductor.polygon.scale(scale, scale)
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
};
|
|
491
|
+
for (const pour of circuitJson) {
|
|
492
|
+
if (pour.type !== "pcb_copper_pour" || !pour.source_net_id) continue;
|
|
493
|
+
const netId = netForId(pour.source_net_id);
|
|
494
|
+
if (!netId) continue;
|
|
495
|
+
pouredNets.add(netId);
|
|
496
|
+
add({
|
|
497
|
+
polygon: getPourPolygon(pour),
|
|
498
|
+
layers: [pour.layer],
|
|
499
|
+
netId,
|
|
500
|
+
isPour: true
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
const components = new Map(
|
|
504
|
+
circuitJson.filter((e) => e.type === "pcb_component").map((e) => [e.pcb_component_id, e])
|
|
505
|
+
);
|
|
506
|
+
if (pouredNets.size > 0) {
|
|
507
|
+
for (const copper of circuitJson) {
|
|
508
|
+
if (copper.type === "pcb_trace") {
|
|
509
|
+
const netId2 = netForId(copper.pcb_trace_id);
|
|
510
|
+
if (!netId2 || !pouredNets.has(netId2) || copper.route_thickness_mode === "interpolated")
|
|
511
|
+
continue;
|
|
512
|
+
for (let i = 0; i < copper.route.length - 1; i++) {
|
|
513
|
+
const start = copper.route[i];
|
|
514
|
+
const end = copper.route[i + 1];
|
|
515
|
+
if (start.route_type !== "wire" || end.route_type !== "wire" || start.layer !== end.layer)
|
|
516
|
+
continue;
|
|
517
|
+
add({
|
|
518
|
+
polygon: getTraceSegmentPolygon(start, end, start.width),
|
|
519
|
+
layers: [start.layer],
|
|
520
|
+
netId: netId2
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
525
|
+
if (copper.type !== "pcb_smtpad" && copper.type !== "pcb_plated_hole" && copper.type !== "pcb_via")
|
|
526
|
+
continue;
|
|
527
|
+
const netId = netForId(getPrimaryId(copper));
|
|
528
|
+
if (!netId || !pouredNets.has(netId)) continue;
|
|
529
|
+
if (copper.type === "pcb_smtpad") {
|
|
530
|
+
add({
|
|
531
|
+
polygon: getSmtPadPolygon(copper),
|
|
532
|
+
layers: [copper.layer],
|
|
533
|
+
netId,
|
|
534
|
+
portId: copper.pcb_port_id
|
|
535
|
+
});
|
|
536
|
+
} else if (copper.type === "pcb_plated_hole") {
|
|
537
|
+
add({
|
|
538
|
+
polygon: getPlatedHolePolygon(
|
|
539
|
+
copper,
|
|
540
|
+
copper.pcb_component_id ? components.get(copper.pcb_component_id)?.rotation : 0
|
|
541
|
+
),
|
|
542
|
+
layers: copper.layers,
|
|
543
|
+
netId,
|
|
544
|
+
portId: copper.pcb_port_id
|
|
545
|
+
});
|
|
546
|
+
} else {
|
|
547
|
+
add({
|
|
548
|
+
polygon: getViaPolygon(
|
|
549
|
+
copper,
|
|
550
|
+
copper.outer_diameter,
|
|
551
|
+
copper.hole_diameter
|
|
552
|
+
),
|
|
553
|
+
layers: copper.layers,
|
|
554
|
+
netId
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
const parent = conductors.map((_, i) => i);
|
|
560
|
+
const find = (i) => {
|
|
561
|
+
while (parent[i] !== i) {
|
|
562
|
+
parent[i] = parent[parent[i]];
|
|
563
|
+
i = parent[i];
|
|
564
|
+
}
|
|
565
|
+
return i;
|
|
566
|
+
};
|
|
567
|
+
const bounds = conductors.map((c) => c.polygon.box);
|
|
568
|
+
const order = conductors.map((_, i) => i).sort((a, b) => bounds[a].xmin - bounds[b].xmin);
|
|
569
|
+
for (let a = 0; a < order.length; a++) {
|
|
570
|
+
const i = order[a];
|
|
571
|
+
for (let b = a + 1; b < order.length; b++) {
|
|
572
|
+
const j = order[b];
|
|
573
|
+
if (bounds[j].xmin > bounds[i].xmax + tolerance) break;
|
|
574
|
+
if (find(i) === find(j) || conductors[i].netId !== conductors[j].netId)
|
|
575
|
+
continue;
|
|
576
|
+
if (bounds[j].ymin > bounds[i].ymax + tolerance || bounds[j].ymax < bounds[i].ymin - tolerance)
|
|
577
|
+
continue;
|
|
578
|
+
if (!conductors[i].layers.some(
|
|
579
|
+
(layer) => conductors[j].layers.includes(layer)
|
|
580
|
+
))
|
|
581
|
+
continue;
|
|
582
|
+
if (copperPolygonsTouch(
|
|
583
|
+
conductors[i].polygon,
|
|
584
|
+
conductors[j].polygon,
|
|
585
|
+
tolerance
|
|
586
|
+
))
|
|
587
|
+
parent[find(j)] = find(i);
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
const pourRoots = new Set(
|
|
591
|
+
conductors.flatMap((c, i) => c.isPour ? [find(i)] : [])
|
|
592
|
+
);
|
|
593
|
+
const rootsByPort = /* @__PURE__ */ new Map();
|
|
594
|
+
for (const [i, conductor] of conductors.entries()) {
|
|
595
|
+
if (!conductor.portId || !pourRoots.has(find(i))) continue;
|
|
596
|
+
const roots = rootsByPort.get(conductor.portId) ?? /* @__PURE__ */ new Set();
|
|
597
|
+
roots.add(find(i));
|
|
598
|
+
rootsByPort.set(conductor.portId, roots);
|
|
599
|
+
}
|
|
600
|
+
const portsByNet = /* @__PURE__ */ new Map();
|
|
601
|
+
for (const port of circuitJson) {
|
|
602
|
+
if (port.type !== "pcb_port") continue;
|
|
603
|
+
const netId = netForId(port.pcb_port_id);
|
|
604
|
+
if (!netId || !pouredNets.has(netId)) continue;
|
|
605
|
+
const ports = portsByNet.get(netId) ?? [];
|
|
606
|
+
ports.push(port.pcb_port_id);
|
|
607
|
+
portsByNet.set(netId, ports);
|
|
608
|
+
}
|
|
609
|
+
return {
|
|
610
|
+
isPortConnectedToNet(portId, sourceNetIds) {
|
|
611
|
+
const roots = rootsByPort.get(portId);
|
|
612
|
+
return sourceNetIds.every(
|
|
613
|
+
(id) => [...roots ?? []].some(
|
|
614
|
+
(root) => conductors[root].netId === netForId(id) && // Distinct same-net islands are not a physical connection.
|
|
615
|
+
(portsByNet.get(conductors[root].netId) ?? []).every(
|
|
616
|
+
(peer) => rootsByPort.get(peer)?.has(root)
|
|
617
|
+
)
|
|
618
|
+
)
|
|
619
|
+
);
|
|
620
|
+
},
|
|
621
|
+
arePortsConnected(portIds) {
|
|
622
|
+
if (portIds.length < 2) return false;
|
|
623
|
+
return [...rootsByPort.get(portIds[0]) ?? []].some(
|
|
624
|
+
(root) => portIds.every((id) => rootsByPort.get(id)?.has(root))
|
|
625
|
+
);
|
|
626
|
+
}
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
|
|
467
630
|
// lib/check-each-pcb-port-connected-to-pcb-trace.ts
|
|
468
631
|
function checkEachPcbPortConnectedToPcbTraces(circuitJson) {
|
|
469
632
|
addStartAndEndPortIdsIfMissing(circuitJson);
|
|
@@ -479,6 +642,11 @@ function checkEachPcbPortConnectedToPcbTraces(circuitJson) {
|
|
|
479
642
|
const errors = [];
|
|
480
643
|
const connectivityMap = getFullConnectivityMapFromCircuitJson(circuitJson);
|
|
481
644
|
const pcbConnectivityMap = new PcbConnectivityMap(circuitJson);
|
|
645
|
+
let pourConnectivity;
|
|
646
|
+
const getPourConnectivity = () => pourConnectivity ??= getCopperPourConnectivity(
|
|
647
|
+
circuitJson,
|
|
648
|
+
connectivityMap
|
|
649
|
+
);
|
|
482
650
|
const sourcePortToPcbPort = /* @__PURE__ */ new Map();
|
|
483
651
|
for (const pcbPort of pcbPorts) {
|
|
484
652
|
sourcePortToPcbPort.set(pcbPort.source_port_id, pcbPort);
|
|
@@ -494,7 +662,10 @@ function checkEachPcbPortConnectedToPcbTraces(circuitJson) {
|
|
|
494
662
|
const connectedPcbTraces = pcbConnectivityMap.getAllTracesConnectedToPort(
|
|
495
663
|
pcbPort.pcb_port_id
|
|
496
664
|
);
|
|
497
|
-
if (connectedPcbTraces.length === 0)
|
|
665
|
+
if (connectedPcbTraces.length === 0 && !getPourConnectivity().isPortConnectedToNet(
|
|
666
|
+
pcbPort.pcb_port_id,
|
|
667
|
+
sourceTrace.connected_source_net_ids
|
|
668
|
+
)) {
|
|
498
669
|
const connectedNetNames = sourceTrace.connected_source_net_ids.map((sourceNetId) => sourceNetNameById.get(sourceNetId)).filter((name) => Boolean(name));
|
|
499
670
|
const netDescription = connectedNetNames.length > 0 ? `net [${connectedNetNames.join(", ")}]` : "its connected net";
|
|
500
671
|
errors.push({
|
|
@@ -534,7 +705,9 @@ function checkEachPcbPortConnectedToPcbTraces(circuitJson) {
|
|
|
534
705
|
(element) => element.type === "pcb_trace" && ("pcb_trace_id" in element && element.pcb_trace_id === id || "route_id" in element && element.route_id === id)
|
|
535
706
|
)
|
|
536
707
|
);
|
|
537
|
-
if (pcbTraceIds.length === 0)
|
|
708
|
+
if (pcbTraceIds.length === 0 && !getPourConnectivity().arePortsConnected(
|
|
709
|
+
pcbPortsInTrace.map((port) => port.pcb_port_id)
|
|
710
|
+
)) {
|
|
538
711
|
const uniqueComponentIds = new Set(
|
|
539
712
|
pcbPortsInTrace.map((p) => p.pcb_component_id)
|
|
540
713
|
);
|
|
@@ -555,7 +728,7 @@ function checkEachPcbPortConnectedToPcbTraces(circuitJson) {
|
|
|
555
728
|
|
|
556
729
|
// lib/check-each-pcb-trace-non-overlapping/check-each-pcb-trace-non-overlapping.ts
|
|
557
730
|
import { cju as cju2, getReadableNameForElement as getReadableNameForElement2 } from "@tscircuit/circuit-json-util";
|
|
558
|
-
import { getPrimaryId } from "@tscircuit/circuit-json-util";
|
|
731
|
+
import { getPrimaryId as getPrimaryId2 } from "@tscircuit/circuit-json-util";
|
|
559
732
|
import {
|
|
560
733
|
segmentToBoundsMinDistance,
|
|
561
734
|
segmentToCircleMinDistance as segmentToCircleMinDistance2
|
|
@@ -1467,7 +1640,7 @@ function checkEachPcbTraceNonOverlapping(circuitJson, {
|
|
|
1467
1640
|
});
|
|
1468
1641
|
continue;
|
|
1469
1642
|
}
|
|
1470
|
-
const primaryObjId =
|
|
1643
|
+
const primaryObjId = getPrimaryId2(obj);
|
|
1471
1644
|
if (connMap.areIdsConnected(
|
|
1472
1645
|
segmentA.pcb_trace_id,
|
|
1473
1646
|
"pcb_trace_id" in obj ? obj.pcb_trace_id : primaryObjId
|
|
@@ -1519,7 +1692,7 @@ function checkEachPcbTraceNonOverlapping(circuitJson, {
|
|
|
1519
1692
|
error_type: "pcb_trace_error",
|
|
1520
1693
|
message: constructErrorMessage(
|
|
1521
1694
|
getReadableName(segmentA.pcb_trace_id),
|
|
1522
|
-
`${obj.type} "${getReadableName(
|
|
1695
|
+
`${obj.type} "${getReadableName(getPrimaryId2(obj))}"`,
|
|
1523
1696
|
gap2
|
|
1524
1697
|
),
|
|
1525
1698
|
pcb_trace_id: segmentA.pcb_trace_id,
|
|
@@ -1552,7 +1725,7 @@ function checkEachPcbTraceNonOverlapping(circuitJson, {
|
|
|
1552
1725
|
error_type: "pcb_trace_error",
|
|
1553
1726
|
message: constructErrorMessage(
|
|
1554
1727
|
getReadableName(segmentA.pcb_trace_id),
|
|
1555
|
-
`${obj.type} "${getReadableName(
|
|
1728
|
+
`${obj.type} "${getReadableName(getPrimaryId2(obj))}"`,
|
|
1556
1729
|
gap
|
|
1557
1730
|
),
|
|
1558
1731
|
pcb_trace_id: segmentA.pcb_trace_id,
|
|
@@ -2414,8 +2587,8 @@ function checkPcbComponentOverCutout(circuitJson) {
|
|
|
2414
2587
|
}
|
|
2415
2588
|
|
|
2416
2589
|
// lib/check-pcb-copper-over-keepout.ts
|
|
2417
|
-
import { cju as cju3, getPrimaryId as
|
|
2418
|
-
var getErrorOwnerId = (copper) => "pcb_component_id" in copper && copper.pcb_component_id ? copper.pcb_component_id :
|
|
2590
|
+
import { cju as cju3, getPrimaryId as getPrimaryId3 } from "@tscircuit/circuit-json-util";
|
|
2591
|
+
var getErrorOwnerId = (copper) => "pcb_component_id" in copper && copper.pcb_component_id ? copper.pcb_component_id : getPrimaryId3(copper);
|
|
2419
2592
|
var getReadableCopperName = (circuitJson, copper) => {
|
|
2420
2593
|
if ("pcb_component_id" in copper && copper.pcb_component_id) {
|
|
2421
2594
|
const pcbComponent = circuitJson.find(
|
|
@@ -2427,7 +2600,7 @@ var getReadableCopperName = (circuitJson, copper) => {
|
|
|
2427
2600
|
const componentName = sourceComponent?.type === "source_component" && sourceComponent.name ? sourceComponent.name : getReadableNameForComponent(circuitJson, copper.pcb_component_id);
|
|
2428
2601
|
return `component ${componentName}`;
|
|
2429
2602
|
}
|
|
2430
|
-
return copper.type === "pcb_via" ? `via ${copper.pcb_via_id}` : `${copper.type} ${
|
|
2603
|
+
return copper.type === "pcb_via" ? `via ${copper.pcb_via_id}` : `${copper.type} ${getPrimaryId3(copper)}`;
|
|
2431
2604
|
};
|
|
2432
2605
|
function checkPcbCopperOverKeepout(circuitJson) {
|
|
2433
2606
|
const keepouts = cju3(circuitJson).pcb_keepout.list();
|
|
@@ -2675,6 +2848,11 @@ function checkSourceTracesHavePcbTraces(circuitJson) {
|
|
|
2675
2848
|
pcbPorts.map((pcbPort) => [pcbPort.source_port_id, pcbPort])
|
|
2676
2849
|
);
|
|
2677
2850
|
const connectivityMap = getFullConnectivityMapFromCircuitJson6(circuitJson);
|
|
2851
|
+
let pourConnectivity;
|
|
2852
|
+
const getPourConnectivity = () => pourConnectivity ??= getCopperPourConnectivity(
|
|
2853
|
+
circuitJson,
|
|
2854
|
+
connectivityMap
|
|
2855
|
+
);
|
|
2678
2856
|
for (const sourceTrace of sourceTraces) {
|
|
2679
2857
|
if (!sourceTrace.connected_source_port_ids?.length) continue;
|
|
2680
2858
|
if ((sourceTrace.connected_source_net_ids?.length ?? 0) > 0) continue;
|
|
@@ -2687,6 +2865,10 @@ function checkSourceTracesHavePcbTraces(circuitJson) {
|
|
|
2687
2865
|
);
|
|
2688
2866
|
if (!hasPcbTrace) {
|
|
2689
2867
|
const connectedPcbPorts = sourceTrace.connected_source_port_ids.map((sourcePortId) => sourcePortToPcbPort.get(sourcePortId)).filter((pcbPort) => pcbPort !== void 0);
|
|
2868
|
+
if (connectedPcbPorts.length === sourceTrace.connected_source_port_ids.length && getPourConnectivity().arePortsConnected(
|
|
2869
|
+
connectedPcbPorts.map((port) => port.pcb_port_id)
|
|
2870
|
+
))
|
|
2871
|
+
continue;
|
|
2690
2872
|
const connectedPcbComponentIds = Array.from(
|
|
2691
2873
|
new Set(
|
|
2692
2874
|
connectedPcbPorts.map((port) => port.pcb_component_id).filter((id) => id !== void 0)
|
|
@@ -2721,7 +2903,7 @@ import {
|
|
|
2721
2903
|
import {
|
|
2722
2904
|
all_layers as all_layers2
|
|
2723
2905
|
} from "circuit-json";
|
|
2724
|
-
import { getPrimaryId as
|
|
2906
|
+
import { getPrimaryId as getPrimaryId4 } from "@tscircuit/circuit-json-util";
|
|
2725
2907
|
import { pointToSegmentDistance as pointToSegmentDistance2 } from "@tscircuit/math-utils";
|
|
2726
2908
|
var CONTACT_EPSILON = 1e-9;
|
|
2727
2909
|
function getViaContactIndex(circuitJson, connectivity) {
|
|
@@ -2745,7 +2927,7 @@ function getViaContactIndex(circuitJson, connectivity) {
|
|
|
2745
2927
|
const net = connectivity.getNetConnectedToId(id);
|
|
2746
2928
|
if (!net) return;
|
|
2747
2929
|
const touchesPad = pads.some((pad) => {
|
|
2748
|
-
if (connectivity.getNetConnectedToId(
|
|
2930
|
+
if (connectivity.getNetConnectedToId(getPrimaryId4(pad)) !== net || !getLayersOfPcbElement(pad).some((layer) => layers.includes(layer)))
|
|
2749
2931
|
return false;
|
|
2750
2932
|
if (contact.radius === void 0) return isPointInPad(contact, pad);
|
|
2751
2933
|
const viaGeometry = {
|
|
@@ -3336,7 +3518,7 @@ function checkPcbTracesOutOfBoard(circuitJson, config = {}) {
|
|
|
3336
3518
|
import {
|
|
3337
3519
|
cju as cju6,
|
|
3338
3520
|
getBoundsOfPcbElements as getBoundsOfPcbElements5,
|
|
3339
|
-
getPrimaryId as
|
|
3521
|
+
getPrimaryId as getPrimaryId5
|
|
3340
3522
|
} from "@tscircuit/circuit-json-util";
|
|
3341
3523
|
import { doBoundsOverlap as doBoundsOverlap3 } from "@tscircuit/math-utils";
|
|
3342
3524
|
import { getFullConnectivityMapFromCircuitJson as getFullConnectivityMapFromCircuitJson8 } from "circuit-json-to-connectivity-map";
|
|
@@ -3420,7 +3602,7 @@ var formatOverlapElementDescription = (circuitJson, element) => {
|
|
|
3420
3602
|
if ("pcb_port_id" in element && element.pcb_port_id) {
|
|
3421
3603
|
return getReadableNameForPort(circuitJson, element.pcb_port_id);
|
|
3422
3604
|
}
|
|
3423
|
-
const id =
|
|
3605
|
+
const id = getPrimaryId5(element);
|
|
3424
3606
|
const readableName = getReadableNameForElementId(circuitJson, id);
|
|
3425
3607
|
return readableName === "element" ? `[${id}]` : readableName;
|
|
3426
3608
|
};
|
|
@@ -3433,7 +3615,7 @@ function checkPcbComponentOverlap(circuitJson) {
|
|
|
3433
3615
|
const courtyards = circuitJson.filter(isCourtyardElement2);
|
|
3434
3616
|
const componentMap = /* @__PURE__ */ new Map();
|
|
3435
3617
|
for (const pad of smtPads) {
|
|
3436
|
-
const componentId = pad.pcb_component_id || `standalone_pad_${
|
|
3618
|
+
const componentId = pad.pcb_component_id || `standalone_pad_${getPrimaryId5(pad)}`;
|
|
3437
3619
|
if (!componentMap.has(componentId)) {
|
|
3438
3620
|
componentMap.set(componentId, {
|
|
3439
3621
|
component_id: componentId,
|
|
@@ -3443,7 +3625,7 @@ function checkPcbComponentOverlap(circuitJson) {
|
|
|
3443
3625
|
componentMap.get(componentId).elements.push(pad);
|
|
3444
3626
|
}
|
|
3445
3627
|
for (const hole of platedHoles) {
|
|
3446
|
-
const componentId = hole.pcb_component_id || `standalone_plated_hole_${
|
|
3628
|
+
const componentId = hole.pcb_component_id || `standalone_plated_hole_${getPrimaryId5(hole)}`;
|
|
3447
3629
|
if (!componentMap.has(componentId)) {
|
|
3448
3630
|
componentMap.set(componentId, {
|
|
3449
3631
|
component_id: componentId,
|
|
@@ -3453,7 +3635,7 @@ function checkPcbComponentOverlap(circuitJson) {
|
|
|
3453
3635
|
componentMap.get(componentId).elements.push(hole);
|
|
3454
3636
|
}
|
|
3455
3637
|
for (const hole of holes) {
|
|
3456
|
-
const componentId = hole.pcb_component_id || `standalone_hole_${
|
|
3638
|
+
const componentId = hole.pcb_component_id || `standalone_hole_${getPrimaryId5(hole)}`;
|
|
3457
3639
|
if (!componentMap.has(componentId)) {
|
|
3458
3640
|
componentMap.set(componentId, {
|
|
3459
3641
|
component_id: componentId,
|
|
@@ -3489,8 +3671,8 @@ function checkPcbComponentOverlap(circuitJson) {
|
|
|
3489
3671
|
}
|
|
3490
3672
|
for (const elem1 of comp1.elements) {
|
|
3491
3673
|
for (const elem2 of comp2.elements) {
|
|
3492
|
-
const id1 =
|
|
3493
|
-
const id2 =
|
|
3674
|
+
const id1 = getPrimaryId5(elem1);
|
|
3675
|
+
const id2 = getPrimaryId5(elem2);
|
|
3494
3676
|
if ((isCourtyardElement2(elem1) || isCourtyardElement2(elem2)) && !isHoleElement(elem1) && !isHoleElement(elem2)) {
|
|
3495
3677
|
continue;
|
|
3496
3678
|
}
|
|
@@ -3750,7 +3932,7 @@ var checkPcbTraceViaCounts = (circuitJson) => {
|
|
|
3750
3932
|
|
|
3751
3933
|
// lib/check-pad-pad-clearance.ts
|
|
3752
3934
|
import {
|
|
3753
|
-
getPrimaryId as
|
|
3935
|
+
getPrimaryId as getPrimaryId6,
|
|
3754
3936
|
getReadableNameForElement as getReadableNameForElement6
|
|
3755
3937
|
} from "@tscircuit/circuit-json-util";
|
|
3756
3938
|
import { formatMm } from "format-si-unit";
|
|
@@ -3769,17 +3951,17 @@ function checkPadPadClearance(circuitJson, {
|
|
|
3769
3951
|
const spatialIndex = new SpatialObjectIndex({
|
|
3770
3952
|
objects: pads,
|
|
3771
3953
|
getBounds: getPadBounds,
|
|
3772
|
-
getId: (pad) =>
|
|
3954
|
+
getId: (pad) => getPrimaryId6(pad)
|
|
3773
3955
|
});
|
|
3774
3956
|
const errors = /* @__PURE__ */ new Map();
|
|
3775
3957
|
for (const padA of pads) {
|
|
3776
|
-
const padAId =
|
|
3958
|
+
const padAId = getPrimaryId6(padA);
|
|
3777
3959
|
const nearbyPads = spatialIndex.getObjectsInBounds(
|
|
3778
3960
|
getPadBounds(padA),
|
|
3779
3961
|
minClearance
|
|
3780
3962
|
);
|
|
3781
3963
|
for (const padB of nearbyPads) {
|
|
3782
|
-
const padBId =
|
|
3964
|
+
const padBId = getPrimaryId6(padB);
|
|
3783
3965
|
if (padAId === padBId) continue;
|
|
3784
3966
|
if (!getLayersOfPcbElement(padA).some(
|
|
3785
3967
|
(layer) => getLayersOfPcbElement(padB).includes(layer)
|
|
@@ -3815,7 +3997,7 @@ function checkPadPadClearance(circuitJson, {
|
|
|
3815
3997
|
|
|
3816
3998
|
// lib/check-pad-trace-clearance.ts
|
|
3817
3999
|
import {
|
|
3818
|
-
getPrimaryId as
|
|
4000
|
+
getPrimaryId as getPrimaryId7,
|
|
3819
4001
|
getReadableNameForElement as getReadableNameForElement7
|
|
3820
4002
|
} from "@tscircuit/circuit-json-util";
|
|
3821
4003
|
import { formatMm as formatMm2 } from "format-si-unit";
|
|
@@ -3835,7 +4017,7 @@ function checkPadTraceClearance(circuitJson, {
|
|
|
3835
4017
|
const spatialIndex = new SpatialObjectIndex({
|
|
3836
4018
|
objects: pads,
|
|
3837
4019
|
getBounds: getPadBounds,
|
|
3838
|
-
getId: (pad) =>
|
|
4020
|
+
getId: (pad) => getPrimaryId7(pad)
|
|
3839
4021
|
});
|
|
3840
4022
|
const errors = /* @__PURE__ */ new Map();
|
|
3841
4023
|
const overlappingPairIds = /* @__PURE__ */ new Set();
|
|
@@ -3845,7 +4027,7 @@ function checkPadTraceClearance(circuitJson, {
|
|
|
3845
4027
|
minClearance + segment.thickness / 2
|
|
3846
4028
|
);
|
|
3847
4029
|
for (const pad of nearbyPads) {
|
|
3848
|
-
const padId =
|
|
4030
|
+
const padId = getPrimaryId7(pad);
|
|
3849
4031
|
if (!getLayersOfPcbElement(pad).includes(segment.layer)) continue;
|
|
3850
4032
|
if (connMap.areIdsConnected(segment.pcb_trace_id, padId)) continue;
|
|
3851
4033
|
const pairId = `${padId}_${segment.pcb_trace_id}`;
|
|
@@ -3931,7 +4113,7 @@ function checkViaTraceClearance(circuitJson, {
|
|
|
3931
4113
|
|
|
3932
4114
|
// lib/check-via-pad-clearance.ts
|
|
3933
4115
|
import {
|
|
3934
|
-
getPrimaryId as
|
|
4116
|
+
getPrimaryId as getPrimaryId8,
|
|
3935
4117
|
getReadableNameForElement as getReadableNameForElement9
|
|
3936
4118
|
} from "@tscircuit/circuit-json-util";
|
|
3937
4119
|
import { formatMm as formatMm4 } from "format-si-unit";
|
|
@@ -3953,7 +4135,7 @@ function checkViaPadClearance(circuitJson, {
|
|
|
3953
4135
|
const padIndex = new SpatialObjectIndex({
|
|
3954
4136
|
objects: pads,
|
|
3955
4137
|
getBounds: getPadBounds,
|
|
3956
|
-
getId:
|
|
4138
|
+
getId: getPrimaryId8
|
|
3957
4139
|
});
|
|
3958
4140
|
const errors = [];
|
|
3959
4141
|
for (const via of vias) {
|
|
@@ -3962,7 +4144,7 @@ function checkViaPadClearance(circuitJson, {
|
|
|
3962
4144
|
requiredClearance
|
|
3963
4145
|
);
|
|
3964
4146
|
for (const pad of nearbyPads) {
|
|
3965
|
-
const padId =
|
|
4147
|
+
const padId = getPrimaryId8(pad);
|
|
3966
4148
|
if (!getLayersOfPcbElement(via).some(
|
|
3967
4149
|
(layer) => getLayersOfPcbElement(pad).includes(layer)
|
|
3968
4150
|
)) {
|
|
@@ -3987,7 +4169,7 @@ function checkViaPadClearance(circuitJson, {
|
|
|
3987
4169
|
}
|
|
3988
4170
|
|
|
3989
4171
|
// lib/check-vias-in-pads.ts
|
|
3990
|
-
import { getPrimaryId as
|
|
4172
|
+
import { getPrimaryId as getPrimaryId9 } from "@tscircuit/circuit-json-util";
|
|
3991
4173
|
import { getFullConnectivityMapFromCircuitJson as getFullConnectivityMapFromCircuitJson13 } from "circuit-json-to-connectivity-map";
|
|
3992
4174
|
function checkViasInPads(circuitJson) {
|
|
3993
4175
|
const board = getPcbBoard(circuitJson);
|
|
@@ -4001,18 +4183,18 @@ function checkViasInPads(circuitJson) {
|
|
|
4001
4183
|
if (vias.length === 0 || pads.length === 0) return [];
|
|
4002
4184
|
const connMap = getFullConnectivityMapFromCircuitJson13(circuitJson);
|
|
4003
4185
|
const padOrdinals = new Map(
|
|
4004
|
-
pads.map((pad, index) => [
|
|
4186
|
+
pads.map((pad, index) => [getPrimaryId9(pad), index])
|
|
4005
4187
|
);
|
|
4006
4188
|
const padIndex = new SpatialObjectIndex({
|
|
4007
4189
|
objects: pads,
|
|
4008
4190
|
getBounds: getPadBounds,
|
|
4009
|
-
getId:
|
|
4191
|
+
getId: getPrimaryId9
|
|
4010
4192
|
});
|
|
4011
4193
|
const errors = [];
|
|
4012
4194
|
for (const via of vias) {
|
|
4013
4195
|
const nearbyPads = padIndex.getObjectsInBounds(getPadBounds(via));
|
|
4014
4196
|
for (const pad of nearbyPads) {
|
|
4015
|
-
const padId =
|
|
4197
|
+
const padId = getPrimaryId9(pad);
|
|
4016
4198
|
const viaLayers = getLayersOfPcbElement(via);
|
|
4017
4199
|
const padLayers = getLayersOfPcbElement(pad);
|
|
4018
4200
|
if (!viaLayers.some((layer) => padLayers.includes(layer))) continue;
|
|
@@ -4563,12 +4745,12 @@ function checkSchematicComponentPortsOutsideBody(circuitJson) {
|
|
|
4563
4745
|
}
|
|
4564
4746
|
|
|
4565
4747
|
// lib/consolidate-pcb-overlap-errors.ts
|
|
4566
|
-
import { getPrimaryId as
|
|
4748
|
+
import { getPrimaryId as getPrimaryId10 } from "@tscircuit/circuit-json-util";
|
|
4567
4749
|
function consolidatePcbOverlapErrors(circuitJson, errors) {
|
|
4568
4750
|
const ownerByElementId = /* @__PURE__ */ new Map();
|
|
4569
4751
|
const elementById = /* @__PURE__ */ new Map();
|
|
4570
4752
|
for (const element of circuitJson) {
|
|
4571
|
-
const id =
|
|
4753
|
+
const id = getPrimaryId10(element);
|
|
4572
4754
|
elementById.set(id, element);
|
|
4573
4755
|
if ("pcb_component_id" in element && element.pcb_component_id) {
|
|
4574
4756
|
ownerByElementId.set(id, element.pcb_component_id);
|
|
@@ -4885,9 +5067,14 @@ function polygonsOverlap(polyA, polyB) {
|
|
|
4885
5067
|
return false;
|
|
4886
5068
|
}
|
|
4887
5069
|
function checkCourtyardOverlap(circuitJson) {
|
|
5070
|
+
const doNotPlaceComponentIds = new Set(
|
|
5071
|
+
circuitJson.flatMap(
|
|
5072
|
+
(el) => el.type === "pcb_component" && el.do_not_place ? [el.pcb_component_id] : []
|
|
5073
|
+
)
|
|
5074
|
+
);
|
|
4888
5075
|
const courtyards = circuitJson.filter(
|
|
4889
5076
|
(el) => el.type === "pcb_courtyard_rect" || el.type === "pcb_courtyard_circle" || el.type === "pcb_courtyard_outline"
|
|
4890
|
-
);
|
|
5077
|
+
).filter((el) => !doNotPlaceComponentIds.has(el.pcb_component_id));
|
|
4891
5078
|
const byComponent = /* @__PURE__ */ new Map();
|
|
4892
5079
|
for (const el of courtyards) {
|
|
4893
5080
|
const id = el.pcb_component_id;
|