@tscircuit/checks 0.0.146 → 0.0.148

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/README.md CHANGED
@@ -10,6 +10,7 @@ and output an array of arrays for any issues found.
10
10
  | Function | Description |
11
11
  | --- | --- |
12
12
  | [`checkConnectorAccessibleOrientation`](./lib/check-connector-accessible-orientation.ts) | Returns `pcb_accessibility_error` for connectors whose orientation makes them inaccessible. |
13
+ | [`checkTestPointAccessibility`](./lib/check-testpoint-accessibility.ts) | Returns `pcb_placement_error` when a test point is inside another component's courtyard on the same PCB side. |
13
14
  | [`checkAllPinsInComponentAreUnderspecified`](./lib/check-all-pins-in-component-are-underspecified.ts) | Returns `source_component_pins_underspecified_warning` when every pin on a chip lacks pin attributes. |
14
15
  | [`checkNoPowerPinDefined`](./lib/check-no-power-pin-defined.ts) | Returns `source_no_power_pin_defined_warning` when a chip has no pin with `requires_power=true`. |
15
16
  | [`checkNoGroundPinDefined`](./lib/check-no-ground-pin-defined.ts) | Returns `source_no_ground_pin_defined_warning` when a chip has no pin with `requires_ground=true`. |
@@ -31,7 +32,7 @@ and output an array of arrays for any issues found.
31
32
 
32
33
  | Function | Description |
33
34
  | --- | --- |
34
- | [`runAllPlacementChecks`](./lib/run-all-checks.ts) | Runs placement checks (`checkViasOffBoard`, `checkPcbComponentsOutOfBoard`, `checkPcbComponentOverlap`, `checkPadPadClearance`, and `checkConnectorAccessibleOrientation`). |
35
+ | [`runAllPlacementChecks`](./lib/run-all-checks.ts) | Runs placement checks (`checkViasOffBoard`, `checkPcbComponentsOutOfBoard`, `checkPcbComponentOverlap`, `checkPadPadClearance`, `checkCourtyardOverlap`, `checkConnectorAccessibleOrientation`, and `checkTestPointAccessibility`). |
35
36
  | [`runAllNetlistChecks`](./lib/run-all-checks.ts) | Runs netlist connectivity checks (currently `checkPinMustBeConnected`). |
36
37
  | [`runAllPinSpecificationChecks`](./lib/run-all-checks.ts) | Runs pin specification checks (e.g. `checkAllPinsInComponentAreUnderspecified`, `checkNoPowerPinDefined`, and `checkNoGroundPinDefined`). |
37
38
  | [`runAllRoutingChecks`](./lib/run-all-checks.ts) | Runs all routing checks currently enabled (`checkEachPcbPortConnectedToPcbTraces`, `checkSourceTracesHavePcbTraces`, `checkEachPcbTraceNonOverlapping`, `checkPadTraceClearance`, `checkViaTraceClearance`, same/different net via spacing, and `checkPcbTracesOutOfBoard`). Trace-obstacle pairs are classified before aggregation, so each pair produces one overlap or clearance diagnostic, never both. |
package/dist/index.d.ts CHANGED
@@ -152,4 +152,11 @@ declare function runAllChecks(circuitJson: AnyCircuitElement[]): Promise<(circui
152
152
 
153
153
  declare function checkConnectorAccessibleOrientation(circuitJson: AnyCircuitElement[]): PcbConnectorNotInAccessibleOrientationWarning[];
154
154
 
155
- export { NetManager, checkAllPinsInComponentAreUnderspecified, checkConnectorAccessibleOrientation, checkDifferentNetViaSpacing, checkEachPcbPortConnectedToPcbTraces, checkEachPcbTraceNonOverlapping, checkNoGroundPinDefined, checkNoPowerPinDefined, checkPadPadClearance, checkPadTraceClearance, checkPcbComponentOverlap, checkPcbComponentsOutOfBoard, checkPcbTraceLengths, checkPcbTracesOutOfBoard, checkPinMustBeConnected, checkSameNetViaSpacing, checkSourceTracesHavePcbTraces, checkSourceTracesMatchPcbTraceThickness, checkTracesAreContiguous, checkViaTraceClearance, checkViasOffBoard, dedupePcbDrcErrors, runAllChecks, runAllNetlistChecks, runAllPinSpecificationChecks, runAllPlacementChecks, runAllRoutingChecks };
155
+ /**
156
+ * Test points are intended to be contacted from their PCB side. A test point
157
+ * whose access center is covered by another component's courtyard cannot be
158
+ * reliably reached by a probe after assembly.
159
+ */
160
+ declare function checkTestPointAccessibility(circuitJson: AnyCircuitElement[]): PcbPlacementError[];
161
+
162
+ export { NetManager, checkAllPinsInComponentAreUnderspecified, checkConnectorAccessibleOrientation, checkDifferentNetViaSpacing, checkEachPcbPortConnectedToPcbTraces, checkEachPcbTraceNonOverlapping, checkNoGroundPinDefined, checkNoPowerPinDefined, checkPadPadClearance, checkPadTraceClearance, checkPcbComponentOverlap, checkPcbComponentsOutOfBoard, checkPcbTraceLengths, checkPcbTracesOutOfBoard, checkPinMustBeConnected, checkSameNetViaSpacing, checkSourceTracesHavePcbTraces, checkSourceTracesMatchPcbTraceThickness, checkTestPointAccessibility, checkTracesAreContiguous, checkViaTraceClearance, checkViasOffBoard, dedupePcbDrcErrors, runAllChecks, runAllNetlistChecks, runAllPinSpecificationChecks, runAllPlacementChecks, runAllRoutingChecks };
package/dist/index.js CHANGED
@@ -1232,6 +1232,11 @@ var getRadiusOfCircuitJsonElement = (obj) => {
1232
1232
  };
1233
1233
 
1234
1234
  // lib/check-each-pcb-trace-non-overlapping/check-each-pcb-trace-non-overlapping.ts
1235
+ var getPcbComponentConnectionElementId = (element) => {
1236
+ if (element.type === "pcb_port") return element.pcb_port_id;
1237
+ if (element.type === "pcb_smtpad") return element.pcb_smtpad_id;
1238
+ return element.pcb_plated_hole_id;
1239
+ };
1235
1240
  function checkEachPcbTraceNonOverlapping(circuitJson, {
1236
1241
  connMap,
1237
1242
  minClearance
@@ -1266,9 +1271,28 @@ function checkEachPcbTraceNonOverlapping(circuitJson, {
1266
1271
  });
1267
1272
  const pcbSmtPads = cju2(circuitJson).pcb_smtpad.list();
1268
1273
  const pcbPlatedHoles = cju2(circuitJson).pcb_plated_hole.list();
1274
+ const pcbPorts = cju2(circuitJson).pcb_port.list();
1269
1275
  const pcbHoles = cju2(circuitJson).pcb_hole.list();
1270
1276
  const pcbVias = cju2(circuitJson).pcb_via.list();
1271
1277
  const pcbKeepouts = cju2(circuitJson).pcb_keepout.list();
1278
+ const pcbComponentConnectionElements = [
1279
+ ...pcbPorts,
1280
+ ...pcbSmtPads,
1281
+ ...pcbPlatedHoles
1282
+ ];
1283
+ const excludedConnectionIdsByKeepoutId = /* @__PURE__ */ new Map();
1284
+ for (const keepout of pcbKeepouts) {
1285
+ const excludedPcbComponentIds = new Set(
1286
+ keepout.excluded_pcb_component_ids ?? []
1287
+ );
1288
+ if (excludedPcbComponentIds.size === 0) continue;
1289
+ excludedConnectionIdsByKeepoutId.set(
1290
+ keepout.pcb_keepout_id,
1291
+ pcbComponentConnectionElements.filter(
1292
+ (element) => element.pcb_component_id && excludedPcbComponentIds.has(element.pcb_component_id)
1293
+ ).map(getPcbComponentConnectionElementId)
1294
+ );
1295
+ }
1272
1296
  const allObjects = [
1273
1297
  ...pcbTraceSegments,
1274
1298
  ...pcbSmtPads,
@@ -1301,6 +1325,11 @@ function checkEachPcbTraceNonOverlapping(circuitJson, {
1301
1325
  if (!getLayersOfPcbElement(obj).includes(segmentA.layer)) {
1302
1326
  continue;
1303
1327
  }
1328
+ if (obj.type === "pcb_keepout" && (excludedConnectionIdsByKeepoutId.get(obj.pcb_keepout_id) ?? []).some(
1329
+ (connectionId) => connMap.areIdsConnected(segmentA.pcb_trace_id, connectionId)
1330
+ )) {
1331
+ continue;
1332
+ }
1304
1333
  if (obj.type === "pcb_trace_segment") {
1305
1334
  const segmentB = obj;
1306
1335
  if (segmentA.layer !== segmentB.layer) continue;
@@ -3150,6 +3179,79 @@ function checkCourtyardOverlap(circuitJson) {
3150
3179
  return errors;
3151
3180
  }
3152
3181
 
3182
+ // lib/check-testpoint-accessibility.ts
3183
+ import { isPointInsidePolygon as isPointInsidePolygon3 } from "@tscircuit/math-utils";
3184
+ var isCourtyardElement2 = (element) => element.type === "pcb_courtyard_circle" || element.type === "pcb_courtyard_outline" || element.type === "pcb_courtyard_polygon" || element.type === "pcb_courtyard_rect";
3185
+ var isPointInsideCourtyard = (point, courtyard) => {
3186
+ if (courtyard.type === "pcb_courtyard_circle") {
3187
+ const dx = point.x - courtyard.center.x;
3188
+ const dy = point.y - courtyard.center.y;
3189
+ return dx * dx + dy * dy <= courtyard.radius * courtyard.radius;
3190
+ }
3191
+ if (courtyard.type === "pcb_courtyard_rect") {
3192
+ const angle = -1 * (courtyard.ccw_rotation ?? 0) * Math.PI / 180;
3193
+ const dx = point.x - courtyard.center.x;
3194
+ const dy = point.y - courtyard.center.y;
3195
+ const localX = dx * Math.cos(angle) - dy * Math.sin(angle);
3196
+ const localY = dx * Math.sin(angle) + dy * Math.cos(angle);
3197
+ return Math.abs(localX) <= courtyard.width / 2 && Math.abs(localY) <= courtyard.height / 2;
3198
+ }
3199
+ const polygon = courtyard.type === "pcb_courtyard_polygon" ? courtyard.points : courtyard.outline;
3200
+ return isPointInsidePolygon3(point, polygon);
3201
+ };
3202
+ var getPcbComponentName = (circuitJson, pcbComponentId) => {
3203
+ const pcbComponent = circuitJson.find(
3204
+ (element) => element.type === "pcb_component" && element.pcb_component_id === pcbComponentId
3205
+ );
3206
+ const sourceComponent = circuitJson.find(
3207
+ (element) => element.type === "source_component" && element.source_component_id === pcbComponent?.source_component_id
3208
+ );
3209
+ return (sourceComponent && "name" in sourceComponent ? sourceComponent.name : void 0) ?? getReadableNameForComponent(circuitJson, pcbComponentId);
3210
+ };
3211
+ function checkTestPointAccessibility(circuitJson) {
3212
+ const sourceTestPoints = circuitJson.filter(
3213
+ (element) => element.type === "source_component" && element.ftype === "simple_test_point"
3214
+ );
3215
+ const sourceTestPointIds = new Set(
3216
+ sourceTestPoints.map((testPoint) => testPoint.source_component_id)
3217
+ );
3218
+ const testPointNames = new Map(
3219
+ sourceTestPoints.map((testPoint) => [
3220
+ testPoint.source_component_id,
3221
+ testPoint.name
3222
+ ])
3223
+ );
3224
+ const testPointComponents = circuitJson.filter(
3225
+ (element) => element.type === "pcb_component" && sourceTestPointIds.has(element.source_component_id)
3226
+ );
3227
+ const courtyards = circuitJson.filter(isCourtyardElement2);
3228
+ const errors = [];
3229
+ const reportedComponentPairs = /* @__PURE__ */ new Set();
3230
+ for (const testPoint of testPointComponents) {
3231
+ for (const courtyard of courtyards) {
3232
+ if (courtyard.pcb_component_id === testPoint.pcb_component_id) continue;
3233
+ if (courtyard.layer !== testPoint.layer) continue;
3234
+ if (!isPointInsideCourtyard(testPoint.center, courtyard)) continue;
3235
+ const componentPair = `${testPoint.pcb_component_id}:${courtyard.pcb_component_id}`;
3236
+ if (reportedComponentPairs.has(componentPair)) continue;
3237
+ reportedComponentPairs.add(componentPair);
3238
+ const testPointName = testPointNames.get(testPoint.source_component_id) ?? "Test point";
3239
+ const obstructingComponentName = getPcbComponentName(
3240
+ circuitJson,
3241
+ courtyard.pcb_component_id
3242
+ );
3243
+ errors.push({
3244
+ type: "pcb_placement_error",
3245
+ pcb_placement_error_id: `testpoint_in_courtyard_${testPoint.pcb_component_id}_${courtyard.pcb_component_id}`,
3246
+ error_type: "pcb_placement_error",
3247
+ message: `Test point ${testPointName} is not accessible because it is inside the courtyard of ${obstructingComponentName}`,
3248
+ subcircuit_id: testPoint.subcircuit_id
3249
+ });
3250
+ }
3251
+ }
3252
+ return errors;
3253
+ }
3254
+
3153
3255
  // lib/run-all-checks.ts
3154
3256
  async function runAllPlacementChecks(circuitJson) {
3155
3257
  return [
@@ -3158,7 +3260,8 @@ async function runAllPlacementChecks(circuitJson) {
3158
3260
  ...checkPcbComponentOverlap(circuitJson),
3159
3261
  ...checkPadPadClearance(circuitJson),
3160
3262
  ...checkCourtyardOverlap(circuitJson),
3161
- ...checkConnectorAccessibleOrientation(circuitJson)
3263
+ ...checkConnectorAccessibleOrientation(circuitJson),
3264
+ ...checkTestPointAccessibility(circuitJson)
3162
3265
  ];
3163
3266
  }
3164
3267
  async function runAllNetlistChecks(circuitJson) {
@@ -3212,6 +3315,7 @@ export {
3212
3315
  checkSameNetViaSpacing,
3213
3316
  checkSourceTracesHavePcbTraces,
3214
3317
  checkSourceTracesMatchPcbTraceThickness,
3318
+ checkTestPointAccessibility,
3215
3319
  checkTracesAreContiguous,
3216
3320
  checkViaTraceClearance,
3217
3321
  checkViasOffBoard,