@tscircuit/checks 0.0.147 → 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
@@ -3179,6 +3179,79 @@ function checkCourtyardOverlap(circuitJson) {
3179
3179
  return errors;
3180
3180
  }
3181
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
+
3182
3255
  // lib/run-all-checks.ts
3183
3256
  async function runAllPlacementChecks(circuitJson) {
3184
3257
  return [
@@ -3187,7 +3260,8 @@ async function runAllPlacementChecks(circuitJson) {
3187
3260
  ...checkPcbComponentOverlap(circuitJson),
3188
3261
  ...checkPadPadClearance(circuitJson),
3189
3262
  ...checkCourtyardOverlap(circuitJson),
3190
- ...checkConnectorAccessibleOrientation(circuitJson)
3263
+ ...checkConnectorAccessibleOrientation(circuitJson),
3264
+ ...checkTestPointAccessibility(circuitJson)
3191
3265
  ];
3192
3266
  }
3193
3267
  async function runAllNetlistChecks(circuitJson) {
@@ -3241,6 +3315,7 @@ export {
3241
3315
  checkSameNetViaSpacing,
3242
3316
  checkSourceTracesHavePcbTraces,
3243
3317
  checkSourceTracesMatchPcbTraceThickness,
3318
+ checkTestPointAccessibility,
3244
3319
  checkTracesAreContiguous,
3245
3320
  checkViaTraceClearance,
3246
3321
  checkViasOffBoard,