@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 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.type === "pcb_courtyard_circle" || elem.type === "pcb_courtyard_outline" || elem.type === "pcb_courtyard_polygon" || elem.type === "pcb_courtyard_rect") {
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 isCourtyardElement = (element) => element.type === "pcb_courtyard_circle" || element.type === "pcb_courtyard_outline" || element.type === "pcb_courtyard_polygon" || element.type === "pcb_courtyard_rect";
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(isCourtyardElement);
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 ((isCourtyardElement(elem1) || isCourtyardElement(elem2)) && elem1.type !== "pcb_hole" && elem2.type !== "pcb_hole") {
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: getTraceCenter(segment)
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: getTraceCenter(segment)
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 isCourtyardElement2 = (element) => element.type === "pcb_courtyard_circle" || element.type === "pcb_courtyard_outline" || element.type === "pcb_courtyard_polygon" || element.type === "pcb_courtyard_rect";
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(isCourtyardElement2);
4855
+ const courtyards = circuitJson.filter(isCourtyardElement3);
4811
4856
  const errors = [];
4812
4857
  const reportedComponentPairs = /* @__PURE__ */ new Set();
4813
4858
  for (const testPoint of testPointComponents) {