@tscircuit/checks 0.0.186 → 0.0.188
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 +78 -33
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -799,23 +799,6 @@ var getTraceSegments = (circuitJson) => {
|
|
|
799
799
|
return segments;
|
|
800
800
|
});
|
|
801
801
|
};
|
|
802
|
-
var getTraceCenter = (segment) => {
|
|
803
|
-
const routePoints = segment._pcbTrace.route.flatMap((routePoint) => {
|
|
804
|
-
if (routePoint.route_type === "through_pad") {
|
|
805
|
-
return [routePoint.start, routePoint.end];
|
|
806
|
-
}
|
|
807
|
-
return [{ x: routePoint.x, y: routePoint.y }];
|
|
808
|
-
});
|
|
809
|
-
const firstPoint = routePoints[0];
|
|
810
|
-
const lastPoint = routePoints[routePoints.length - 1];
|
|
811
|
-
if (!firstPoint || !lastPoint) {
|
|
812
|
-
return midpoint(
|
|
813
|
-
{ x: segment.x1, y: segment.y1 },
|
|
814
|
-
{ x: segment.x2, y: segment.y2 }
|
|
815
|
-
);
|
|
816
|
-
}
|
|
817
|
-
return midpoint(firstPoint, lastPoint);
|
|
818
|
-
};
|
|
819
802
|
var getCenterBetweenCopperEdges = ({
|
|
820
803
|
tracePoint,
|
|
821
804
|
obstaclePoint,
|
|
@@ -828,6 +811,15 @@ var getCenterBetweenCopperEdges = ({
|
|
|
828
811
|
if (distance3 === 0) return midpoint(tracePoint, obstaclePoint);
|
|
829
812
|
const unitX = dx / distance3;
|
|
830
813
|
const unitY = dy / distance3;
|
|
814
|
+
if (distance3 <= traceRadius + obstacleRadius) {
|
|
815
|
+
const overlapStart = Math.max(-traceRadius, distance3 - obstacleRadius);
|
|
816
|
+
const overlapEnd = Math.min(traceRadius, distance3 + obstacleRadius);
|
|
817
|
+
const offset = (overlapStart + overlapEnd) / 2;
|
|
818
|
+
return {
|
|
819
|
+
x: tracePoint.x + unitX * offset,
|
|
820
|
+
y: tracePoint.y + unitY * offset
|
|
821
|
+
};
|
|
822
|
+
}
|
|
831
823
|
const traceEdge = {
|
|
832
824
|
x: tracePoint.x + unitX * traceRadius,
|
|
833
825
|
y: tracePoint.y + unitY * traceRadius
|
|
@@ -887,6 +879,16 @@ var getTraceObstacleClearance = (segment, obstacle) => {
|
|
|
887
879
|
};
|
|
888
880
|
};
|
|
889
881
|
var isTraceObstacleOverlap = (gap) => gap <= 0;
|
|
882
|
+
var getViaPadClearanceCenter = (via, pad) => getTraceObstacleClearance(
|
|
883
|
+
{
|
|
884
|
+
x1: via.x,
|
|
885
|
+
y1: via.y,
|
|
886
|
+
x2: via.x,
|
|
887
|
+
y2: via.y,
|
|
888
|
+
thickness: via.outer_diameter
|
|
889
|
+
},
|
|
890
|
+
pad
|
|
891
|
+
).center;
|
|
890
892
|
|
|
891
893
|
// lib/data-structures/SpatialIndex.ts
|
|
892
894
|
var SpatialObjectIndex = class {
|
|
@@ -3342,8 +3344,49 @@ import { getFullConnectivityMapFromCircuitJson as getFullConnectivityMapFromCirc
|
|
|
3342
3344
|
// lib/check-pcb-components-overlap/doPcbElementsOverlap.ts
|
|
3343
3345
|
import { getBoundsOfPcbElements as getBoundsOfPcbElements4 } from "@tscircuit/circuit-json-util";
|
|
3344
3346
|
import { doBoundsOverlap as doBoundsOverlap2 } from "@tscircuit/math-utils";
|
|
3347
|
+
var isCourtyardElement = (element) => element.type === "pcb_courtyard_circle" || element.type === "pcb_courtyard_outline" || element.type === "pcb_courtyard_polygon" || element.type === "pcb_courtyard_rect";
|
|
3348
|
+
var getCourtyardId = (courtyard) => {
|
|
3349
|
+
switch (courtyard.type) {
|
|
3350
|
+
case "pcb_courtyard_circle":
|
|
3351
|
+
return courtyard.pcb_courtyard_circle_id;
|
|
3352
|
+
case "pcb_courtyard_outline":
|
|
3353
|
+
return courtyard.pcb_courtyard_outline_id;
|
|
3354
|
+
case "pcb_courtyard_polygon":
|
|
3355
|
+
return courtyard.pcb_courtyard_polygon_id;
|
|
3356
|
+
case "pcb_courtyard_rect":
|
|
3357
|
+
return courtyard.pcb_courtyard_rect_id;
|
|
3358
|
+
}
|
|
3359
|
+
};
|
|
3360
|
+
var courtyardToKeepout = (courtyard) => {
|
|
3361
|
+
const common = {
|
|
3362
|
+
type: "pcb_keepout",
|
|
3363
|
+
pcb_keepout_id: getCourtyardId(courtyard),
|
|
3364
|
+
layers: [courtyard.layer]
|
|
3365
|
+
};
|
|
3366
|
+
if (courtyard.type === "pcb_courtyard_circle") {
|
|
3367
|
+
return {
|
|
3368
|
+
...common,
|
|
3369
|
+
shape: "circle",
|
|
3370
|
+
center: courtyard.center,
|
|
3371
|
+
radius: courtyard.radius
|
|
3372
|
+
};
|
|
3373
|
+
}
|
|
3374
|
+
const outline = courtyard.type === "pcb_courtyard_rect" ? getRotatedRectPoints({
|
|
3375
|
+
x: courtyard.center.x,
|
|
3376
|
+
y: courtyard.center.y,
|
|
3377
|
+
width: courtyard.width,
|
|
3378
|
+
height: courtyard.height,
|
|
3379
|
+
ccwRotation: courtyard.ccw_rotation ?? 0
|
|
3380
|
+
}) : courtyard.type === "pcb_courtyard_polygon" ? courtyard.points : courtyard.outline;
|
|
3381
|
+
return {
|
|
3382
|
+
...common,
|
|
3383
|
+
shape: "outline",
|
|
3384
|
+
outline,
|
|
3385
|
+
stroke_width: 0
|
|
3386
|
+
};
|
|
3387
|
+
};
|
|
3345
3388
|
function getElementLayers(elem) {
|
|
3346
|
-
if (elem
|
|
3389
|
+
if (isCourtyardElement(elem)) {
|
|
3347
3390
|
return [elem.layer];
|
|
3348
3391
|
}
|
|
3349
3392
|
return getLayersOfPcbElement(elem);
|
|
@@ -3359,13 +3402,20 @@ function doPcbElementsOverlap(elem1, elem2) {
|
|
|
3359
3402
|
if (elem1.type === "pcb_smtpad" && elem2.type === "pcb_smtpad") {
|
|
3360
3403
|
return getPadToPadGap(elem1, elem2) <= 0;
|
|
3361
3404
|
}
|
|
3405
|
+
if (elem1.type === "pcb_plated_hole" && isCourtyardElement(elem2)) {
|
|
3406
|
+
return getPadToPadGap(elem1, courtyardToKeepout(elem2)) <= 0;
|
|
3407
|
+
}
|
|
3408
|
+
if (isCourtyardElement(elem1) && elem2.type === "pcb_plated_hole") {
|
|
3409
|
+
return getPadToPadGap(elem2, courtyardToKeepout(elem1)) <= 0;
|
|
3410
|
+
}
|
|
3362
3411
|
const bounds1 = getBoundsOfPcbElements4([elem1]);
|
|
3363
3412
|
const bounds2 = getBoundsOfPcbElements4([elem2]);
|
|
3364
3413
|
return doBoundsOverlap2(bounds1, bounds2);
|
|
3365
3414
|
}
|
|
3366
3415
|
|
|
3367
3416
|
// lib/check-pcb-components-overlap/checkPcbComponentOverlap.ts
|
|
3368
|
-
var
|
|
3417
|
+
var isCourtyardElement2 = (element) => element.type === "pcb_courtyard_circle" || element.type === "pcb_courtyard_outline" || element.type === "pcb_courtyard_polygon" || element.type === "pcb_courtyard_rect";
|
|
3418
|
+
var isHoleElement = (element) => element.type === "pcb_hole" || element.type === "pcb_plated_hole";
|
|
3369
3419
|
var formatOverlapElementDescription = (circuitJson, element) => {
|
|
3370
3420
|
if ("pcb_port_id" in element && element.pcb_port_id) {
|
|
3371
3421
|
return getReadableNameForPort(circuitJson, element.pcb_port_id);
|
|
@@ -3380,7 +3430,7 @@ function checkPcbComponentOverlap(circuitJson) {
|
|
|
3380
3430
|
const smtPads = cju6(circuitJson).pcb_smtpad.list();
|
|
3381
3431
|
const platedHoles = cju6(circuitJson).pcb_plated_hole.list();
|
|
3382
3432
|
const holes = cju6(circuitJson).pcb_hole.list();
|
|
3383
|
-
const courtyards = circuitJson.filter(
|
|
3433
|
+
const courtyards = circuitJson.filter(isCourtyardElement2);
|
|
3384
3434
|
const componentMap = /* @__PURE__ */ new Map();
|
|
3385
3435
|
for (const pad of smtPads) {
|
|
3386
3436
|
const componentId = pad.pcb_component_id || `standalone_pad_${getPrimaryId4(pad)}`;
|
|
@@ -3441,7 +3491,7 @@ function checkPcbComponentOverlap(circuitJson) {
|
|
|
3441
3491
|
for (const elem2 of comp2.elements) {
|
|
3442
3492
|
const id1 = getPrimaryId4(elem1);
|
|
3443
3493
|
const id2 = getPrimaryId4(elem2);
|
|
3444
|
-
if ((
|
|
3494
|
+
if ((isCourtyardElement2(elem1) || isCourtyardElement2(elem2)) && !isHoleElement(elem1) && !isHoleElement(elem2)) {
|
|
3445
3495
|
continue;
|
|
3446
3496
|
}
|
|
3447
3497
|
if (elem1.type === "pcb_smtpad" && elem2.type === "pcb_smtpad" && connMap.areIdsConnected(id1, id2)) {
|
|
@@ -3792,7 +3842,7 @@ function checkPadTraceClearance(circuitJson, {
|
|
|
3792
3842
|
if (!getLayersOfPcbElement(pad).includes(segment.layer)) continue;
|
|
3793
3843
|
if (connMap.areIdsConnected(segment.pcb_trace_id, padId)) continue;
|
|
3794
3844
|
const pairId = `${padId}_${segment.pcb_trace_id}`;
|
|
3795
|
-
const { gap } = getTraceObstacleClearance(segment, pad);
|
|
3845
|
+
const { gap, center } = getTraceObstacleClearance(segment, pad);
|
|
3796
3846
|
if (isTraceObstacleOverlap(gap)) {
|
|
3797
3847
|
errors.delete(pairId);
|
|
3798
3848
|
overlappingPairIds.add(pairId);
|
|
@@ -3809,7 +3859,7 @@ function checkPadTraceClearance(circuitJson, {
|
|
|
3809
3859
|
pcb_trace_id: segment.pcb_trace_id,
|
|
3810
3860
|
minimum_clearance: minClearance,
|
|
3811
3861
|
actual_clearance: gap,
|
|
3812
|
-
center
|
|
3862
|
+
center
|
|
3813
3863
|
};
|
|
3814
3864
|
const current = errors.get(pairId);
|
|
3815
3865
|
if (!current || gap < current.gap) {
|
|
@@ -3844,7 +3894,7 @@ function checkViaTraceClearance(circuitJson, {
|
|
|
3844
3894
|
if (connMap.areIdsConnected(segment.pcb_trace_id, via.pcb_via_id))
|
|
3845
3895
|
continue;
|
|
3846
3896
|
const pairId = `${via.pcb_via_id}_${segment.pcb_trace_id}`;
|
|
3847
|
-
const { gap } = getTraceObstacleClearance(segment, via);
|
|
3897
|
+
const { gap, center } = getTraceObstacleClearance(segment, via);
|
|
3848
3898
|
if (isTraceObstacleOverlap(gap)) {
|
|
3849
3899
|
errors.delete(pairId);
|
|
3850
3900
|
overlappingPairIds.add(pairId);
|
|
@@ -3861,7 +3911,7 @@ function checkViaTraceClearance(circuitJson, {
|
|
|
3861
3911
|
pcb_trace_id: segment.pcb_trace_id,
|
|
3862
3912
|
minimum_clearance: minClearance,
|
|
3863
3913
|
actual_clearance: gap,
|
|
3864
|
-
center
|
|
3914
|
+
center
|
|
3865
3915
|
};
|
|
3866
3916
|
const current = errors.get(pairId);
|
|
3867
3917
|
if (!current || gap < current.gap) {
|
|
@@ -3914,8 +3964,6 @@ function checkViaPadClearance(circuitJson, {
|
|
|
3914
3964
|
if (connMap.areIdsConnected(via.pcb_via_id, padId)) continue;
|
|
3915
3965
|
const gap = getPadToPadGap(via, pad);
|
|
3916
3966
|
if (gap + EPSILON >= requiredClearance) continue;
|
|
3917
|
-
const viaCenter = getPadCenter(via);
|
|
3918
|
-
const padCenter = getPadCenter(pad);
|
|
3919
3967
|
errors.push({
|
|
3920
3968
|
type: "pcb_pad_pad_clearance_error",
|
|
3921
3969
|
pcb_pad_pad_clearance_error_id: `via_pad_clearance_${via.pcb_via_id}_${padId}`,
|
|
@@ -3924,10 +3972,7 @@ function checkViaPadClearance(circuitJson, {
|
|
|
3924
3972
|
pcb_pad_ids: [via.pcb_via_id, padId],
|
|
3925
3973
|
minimum_clearance: requiredClearance,
|
|
3926
3974
|
actual_clearance: gap,
|
|
3927
|
-
center:
|
|
3928
|
-
x: (viaCenter.x + padCenter.x) / 2,
|
|
3929
|
-
y: (viaCenter.y + padCenter.y) / 2
|
|
3930
|
-
}
|
|
3975
|
+
center: getViaPadClearanceCenter(via, pad)
|
|
3931
3976
|
});
|
|
3932
3977
|
}
|
|
3933
3978
|
}
|
|
@@ -4764,7 +4809,7 @@ function checkCourtyardOverlap(circuitJson) {
|
|
|
4764
4809
|
|
|
4765
4810
|
// lib/check-testpoint-accessibility.ts
|
|
4766
4811
|
import { isPointInsidePolygon as isPointInsidePolygon3 } from "@tscircuit/math-utils";
|
|
4767
|
-
var
|
|
4812
|
+
var isCourtyardElement3 = (element) => element.type === "pcb_courtyard_circle" || element.type === "pcb_courtyard_outline" || element.type === "pcb_courtyard_polygon" || element.type === "pcb_courtyard_rect";
|
|
4768
4813
|
var isPointInsideCourtyard = (point, courtyard) => {
|
|
4769
4814
|
if (courtyard.type === "pcb_courtyard_circle") {
|
|
4770
4815
|
const dx = point.x - courtyard.center.x;
|
|
@@ -4807,7 +4852,7 @@ function checkTestPointAccessibility(circuitJson) {
|
|
|
4807
4852
|
const testPointComponents = circuitJson.filter(
|
|
4808
4853
|
(element) => element.type === "pcb_component" && sourceTestPointIds.has(element.source_component_id)
|
|
4809
4854
|
);
|
|
4810
|
-
const courtyards = circuitJson.filter(
|
|
4855
|
+
const courtyards = circuitJson.filter(isCourtyardElement3);
|
|
4811
4856
|
const errors = [];
|
|
4812
4857
|
const reportedComponentPairs = /* @__PURE__ */ new Set();
|
|
4813
4858
|
for (const testPoint of testPointComponents) {
|