@tscircuit/checks 0.0.86 → 0.0.88

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 CHANGED
@@ -58,6 +58,30 @@ declare function checkPcbTracesOutOfBoard(circuitJson: AnyCircuitElement[], conf
58
58
  */
59
59
  declare function checkPcbComponentOverlap(circuitJson: AnyCircuitElement[]): PcbFootprintOverlapError[];
60
60
 
61
- declare function runAllChecks(circuitJson: AnyCircuitElement[]): Promise<(circuit_json.PcbPortNotConnectedError | circuit_json.PcbTraceError | circuit_json.PcbPlacementError | circuit_json.PcbComponentOutsideBoardError | circuit_json.PcbViaClearanceError | circuit_json.PcbTraceMissingError | circuit_json.PcbFootprintOverlapError)[]>;
61
+ type SourcePinMustBeConnectedError = {
62
+ type: "source_pin_must_be_connected_error";
63
+ source_pin_must_be_connected_error_id: string;
64
+ error_type: "source_pin_must_be_connected_error";
65
+ message: string;
66
+ source_component_id: string;
67
+ source_port_id: string;
68
+ subcircuit_id?: string;
69
+ };
70
+ /**
71
+ * Check that each source port with must_be_connected attribute is actually
72
+ * connected to a trace. Returns errors for any pins that are marked as
73
+ * must_be_connected but are floating (not connected to any trace).
74
+ */
75
+ declare function checkPinMustBeConnected(circuitJson: AnyCircuitElement[]): SourcePinMustBeConnectedError[];
76
+
77
+ declare function runAllChecks(circuitJson: AnyCircuitElement[]): Promise<(circuit_json.PcbPortNotConnectedError | circuit_json.PcbTraceError | circuit_json.PcbPlacementError | circuit_json.PcbComponentOutsideBoardError | circuit_json.PcbViaClearanceError | circuit_json.PcbTraceMissingError | circuit_json.PcbFootprintOverlapError | {
78
+ type: "source_pin_must_be_connected_error";
79
+ source_pin_must_be_connected_error_id: string;
80
+ error_type: "source_pin_must_be_connected_error";
81
+ message: string;
82
+ source_component_id: string;
83
+ source_port_id: string;
84
+ subcircuit_id?: string;
85
+ })[]>;
62
86
 
63
- export { NetManager, checkDifferentNetViaSpacing, checkEachPcbPortConnectedToPcbTraces, checkEachPcbTraceNonOverlapping, checkPcbComponentOverlap, checkPcbComponentsOutOfBoard, checkPcbTracesOutOfBoard, checkSameNetViaSpacing, checkSourceTracesHavePcbTraces, checkViasOffBoard, runAllChecks };
87
+ export { NetManager, checkDifferentNetViaSpacing, checkEachPcbPortConnectedToPcbTraces, checkEachPcbTraceNonOverlapping, checkPcbComponentOverlap, checkPcbComponentsOutOfBoard, checkPcbTracesOutOfBoard, checkPinMustBeConnected, checkSameNetViaSpacing, checkSourceTracesHavePcbTraces, checkViasOffBoard, runAllChecks };
package/dist/index.js CHANGED
@@ -565,6 +565,7 @@ function checkEachPcbTraceNonOverlapping(circuitJson, {
565
565
  connMap
566
566
  } = {}) {
567
567
  const errors = [];
568
+ addStartAndEndPortIdsIfMissing(circuitJson);
568
569
  connMap ??= getFullConnectivityMapFromCircuitJson2(circuitJson);
569
570
  const pcbTraces = cju(circuitJson).pcb_trace.list();
570
571
  const pcbTraceSegments = pcbTraces.flatMap((pcbTrace) => {
@@ -1323,6 +1324,64 @@ function checkPcbComponentOverlap(circuitJson) {
1323
1324
  return errors;
1324
1325
  }
1325
1326
 
1327
+ // lib/check-pin-must-be-connected.ts
1328
+ function checkPinMustBeConnected(circuitJson) {
1329
+ const errors = [];
1330
+ const sourceComponents = circuitJson.filter(
1331
+ (el) => "source_component_id" in el && (el.type === "source_component" || el.type.startsWith("source_simple_"))
1332
+ );
1333
+ const sourcePorts = circuitJson.filter(
1334
+ (el) => el.type === "source_port"
1335
+ );
1336
+ const sourceTraces = circuitJson.filter(
1337
+ (el) => el.type === "source_trace"
1338
+ );
1339
+ const connectedPortIds = /* @__PURE__ */ new Set();
1340
+ for (const trace of sourceTraces) {
1341
+ for (const portId of trace.connected_source_port_ids ?? []) {
1342
+ connectedPortIds.add(portId);
1343
+ }
1344
+ }
1345
+ const componentInternalConnections = /* @__PURE__ */ new Map();
1346
+ for (const component of sourceComponents) {
1347
+ if ("internally_connected_source_port_ids" in component && component.internally_connected_source_port_ids) {
1348
+ componentInternalConnections.set(
1349
+ component.source_component_id,
1350
+ component.internally_connected_source_port_ids
1351
+ );
1352
+ }
1353
+ }
1354
+ for (const internalGroups of componentInternalConnections.values()) {
1355
+ for (const group of internalGroups) {
1356
+ if (group.some((portId) => connectedPortIds.has(portId))) {
1357
+ for (const portId of group) {
1358
+ connectedPortIds.add(portId);
1359
+ }
1360
+ }
1361
+ }
1362
+ }
1363
+ for (const port of sourcePorts) {
1364
+ if (port.must_be_connected === true) {
1365
+ if (!connectedPortIds.has(port.source_port_id)) {
1366
+ const component = sourceComponents.find(
1367
+ (c) => c.source_component_id === port.source_component_id
1368
+ );
1369
+ const componentName = component?.name ?? "Unknown";
1370
+ errors.push({
1371
+ type: "source_pin_must_be_connected_error",
1372
+ source_pin_must_be_connected_error_id: `source_pin_must_be_connected_error_${port.source_port_id}`,
1373
+ error_type: "source_pin_must_be_connected_error",
1374
+ message: `Port ${port.name} on ${componentName} must be connected but is floating`,
1375
+ source_component_id: port.source_component_id ?? "",
1376
+ source_port_id: port.source_port_id,
1377
+ subcircuit_id: port.subcircuit_id
1378
+ });
1379
+ }
1380
+ }
1381
+ }
1382
+ return errors;
1383
+ }
1384
+
1326
1385
  // lib/check-traces-are-contiguous/is-point-in-pad.ts
1327
1386
  function distance4(x1, y1, x2, y2) {
1328
1387
  return Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
@@ -1530,7 +1589,8 @@ async function runAllChecks(circuitJson) {
1530
1589
  ...checkTracesAreContiguous(circuitJson),
1531
1590
  ...checkSourceTracesHavePcbTraces(circuitJson),
1532
1591
  ...checkPcbTracesOutOfBoard(circuitJson),
1533
- ...checkPcbComponentOverlap(circuitJson)
1592
+ ...checkPcbComponentOverlap(circuitJson),
1593
+ ...checkPinMustBeConnected(circuitJson)
1534
1594
  ];
1535
1595
  }
1536
1596
  export {
@@ -1541,6 +1601,7 @@ export {
1541
1601
  checkPcbComponentOverlap,
1542
1602
  checkPcbComponentsOutOfBoard,
1543
1603
  checkPcbTracesOutOfBoard,
1604
+ checkPinMustBeConnected,
1544
1605
  checkSameNetViaSpacing,
1545
1606
  checkSourceTracesHavePcbTraces,
1546
1607
  checkViasOffBoard,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../lib/add-start-and-end-port-ids-if-missing.ts","../lib/check-each-pcb-port-connected-to-pcb-trace.ts","../lib/check-each-pcb-trace-non-overlapping/check-each-pcb-trace-non-overlapping.ts","../lib/data-structures/SpatialIndex.ts","../lib/check-each-pcb-trace-non-overlapping/getCollidableBounds.ts","../lib/drc-defaults.ts","../lib/check-each-pcb-trace-non-overlapping/getPcbPortIdsConnectedToTraces.ts","../lib/check-each-pcb-trace-non-overlapping/getClosestPointBetweenSegments.ts","../lib/check-each-pcb-trace-non-overlapping/getRadiusOfCircuitJsonElement.ts","../lib/check-each-pcb-trace-non-overlapping/getClosestPointBetweenSegmentAndBounds.ts","../lib/util/getLayersOfPcbElement.ts","../lib/net-manager.ts","../lib/check-pcb-components-out-of-board/checkViasOffBoard.ts","../lib/check-pcb-components-out-of-board/checkPcbComponentsOutOfBoard.ts","../lib/check-same-net-via-spacing.ts","../lib/check-different-net-via-spacing.ts","../lib/check-source-traces-have-pcb-traces.ts","../lib/check-trace-out-of-board/checkTraceOutOfBoard.ts","../lib/check-pcb-components-overlap/checkPcbComponentOverlap.ts","../lib/check-traces-are-contiguous/is-point-in-pad.ts","../lib/check-traces-are-contiguous/check-traces-are-contiguous.ts","../lib/run-all-checks.ts"],"sourcesContent":["import type {\n PcbPort,\n PcbTrace,\n AnyCircuitElement,\n PcbSmtPad,\n} from \"circuit-json\"\n\nfunction distance(x1: number, y1: number, x2: number, y2: number): number {\n return Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)\n}\n\n/**\n * HACK: this whole method and all usage of it is a hack because of this issue:\n * https://github.com/tscircuit/tscircuit/issues/291\n */\nexport const addStartAndEndPortIdsIfMissing = (\n soup: AnyCircuitElement[],\n): void => {\n const pcbPorts: PcbPort[] = soup.filter((item) => item.type === \"pcb_port\")\n const pcbSmtPads: PcbSmtPad[] = soup.filter(\n (item) => item.type === \"pcb_smtpad\",\n )\n const pcbTraces: PcbTrace[] = soup.filter((item) => item.type === \"pcb_trace\")\n\n function findPortIdOverlappingPoint(\n point: {\n x: number\n y: number\n },\n options: { isFirstOrLastPoint?: boolean; traceWidth?: number } = {},\n ): string | null {\n const traceWidth = options.traceWidth || 0\n const directPort = pcbPorts.find(\n (port) => distance(port.x, port.y, point.x, point.y) < 0.01,\n )\n if (directPort) return directPort.pcb_port_id\n\n // If it starts or ends inside an smtpad, we'll connect it to the por\n if (options.isFirstOrLastPoint) {\n const smtPad = pcbSmtPads.find((pad) => {\n if (pad.shape === \"rect\") {\n return (\n Math.abs(point.x - pad.x) < pad.width / 2 + traceWidth / 2 &&\n Math.abs(point.y - pad.y) < pad.height / 2 + traceWidth / 2\n )\n // biome-ignore lint/style/noUselessElse: <explanation>\n } else if (pad.shape === \"circle\") {\n return distance(point.x, point.y, pad.x, pad.y) < pad.radius\n }\n })\n if (smtPad) return smtPad.pcb_port_id ?? null\n }\n\n return null\n }\n\n // Add start_pcb_port_id and end_pcb_port_id if not present\n for (const trace of pcbTraces) {\n for (let index = 0; index < trace.route.length; index++) {\n const segment = trace.route[index]\n const isFirstOrLastPoint = index === 0 || index === trace.route.length - 1\n if (segment.route_type === \"wire\") {\n if (!segment.start_pcb_port_id && index === 0) {\n const startPortId = findPortIdOverlappingPoint(segment, {\n isFirstOrLastPoint,\n traceWidth: segment.width,\n })\n if (startPortId) {\n segment.start_pcb_port_id = startPortId\n }\n }\n if (!segment.end_pcb_port_id && index === trace.route.length - 1) {\n const endPortId = findPortIdOverlappingPoint(segment, {\n isFirstOrLastPoint,\n traceWidth: segment.width,\n })\n if (endPortId) {\n segment.end_pcb_port_id = endPortId\n }\n }\n }\n }\n }\n}\n","import type {\n PcbPort,\n SourceTrace,\n AnyCircuitElement,\n PcbPortNotConnectedError,\n} from \"circuit-json\"\nimport { addStartAndEndPortIdsIfMissing } from \"./add-start-and-end-port-ids-if-missing\"\nimport { getFullConnectivityMapFromCircuitJson } from \"circuit-json-to-connectivity-map\"\n\nfunction checkEachPcbPortConnectedToPcbTraces(\n circuitJson: AnyCircuitElement[],\n): PcbPortNotConnectedError[] {\n addStartAndEndPortIdsIfMissing(circuitJson)\n const sourceTraces: SourceTrace[] = circuitJson.filter(\n (item) => item.type === \"source_trace\",\n ) as SourceTrace[]\n\n const pcbPorts: PcbPort[] = circuitJson.filter(\n (item) => item.type === \"pcb_port\",\n ) as PcbPort[]\n\n const errors: PcbPortNotConnectedError[] = []\n\n // Generate the connectivity map from the circuit\n const connectivityMap = getFullConnectivityMapFromCircuitJson(circuitJson)\n\n // Create a map from source_port_id to pcb_port for quick lookup\n const sourcePortToPcbPort = new Map<string, PcbPort>()\n for (const pcbPort of pcbPorts) {\n sourcePortToPcbPort.set(pcbPort.source_port_id, pcbPort)\n }\n\n // Process each source trace\n for (const sourceTrace of sourceTraces) {\n const connectedSourcePortIds = sourceTrace.connected_source_port_ids\n\n // Skip traces with less than 2 ports (nothing to connect)\n if (connectedSourcePortIds.length < 2) {\n continue\n }\n\n // Find corresponding PCB ports for all source ports in this trace\n const pcbPortsInTrace: PcbPort[] = []\n const missingPcbPorts: string[] = []\n\n for (const sourcePortId of connectedSourcePortIds) {\n const pcbPort = sourcePortToPcbPort.get(sourcePortId)\n if (pcbPort) {\n pcbPortsInTrace.push(pcbPort)\n } else {\n missingPcbPorts.push(sourcePortId)\n }\n }\n\n // Skip if we don't have at least 2 PCB ports to connect\n if (pcbPortsInTrace.length < 2) {\n continue\n }\n\n // Get the net ID for the first PCB port as reference\n const firstPcbPort = pcbPortsInTrace[0]\n const referenceNetId = connectivityMap.getNetConnectedToId(\n firstPcbPort.pcb_port_id,\n )\n\n const netElementIds = connectivityMap.getIdsConnectedToNet(referenceNetId!)\n const pcbTraceIds = netElementIds.filter((id) =>\n circuitJson.some(\n (element) =>\n element.type === \"pcb_trace\" &&\n ((\"pcb_trace_id\" in element && element.pcb_trace_id === id) ||\n (\"route_id\" in element && element.route_id === id)),\n ),\n )\n\n if (pcbTraceIds.length === 0) {\n // Check if this is a trivial case (only 2 ports on same component)\n const uniqueComponentIds = new Set(\n pcbPortsInTrace.map((p) => p.pcb_component_id),\n )\n\n if (uniqueComponentIds.size > 1) {\n // Ports are on different components but no PCB traces connect them\n errors.push({\n type: \"pcb_port_not_connected_error\",\n message: `pcb_port_not_connected_error: Pcb ports [${pcbPortsInTrace.map((p) => p.pcb_port_id).join(\", \")}] are not connected together through the same net.`,\n error_type: \"pcb_port_not_connected_error\",\n pcb_port_ids: pcbPortsInTrace.map((p) => p.pcb_port_id),\n pcb_component_ids: pcbPortsInTrace\n .map((p) => p.pcb_component_id)\n .filter((id): id is string => id !== undefined),\n pcb_port_not_connected_error_id: `pcb_port_not_connected_error_trace_${sourceTrace.source_trace_id}`,\n })\n }\n }\n }\n\n return errors\n}\n\nexport { checkEachPcbPortConnectedToPcbTraces }\n","import type { AnyCircuitElement, PcbTraceError } from \"circuit-json\"\nimport { getReadableNameForElement, cju } from \"@tscircuit/circuit-json-util\"\nimport {\n SpatialObjectIndex,\n type Bounds,\n} from \"lib/data-structures/SpatialIndex\"\nimport {\n getFullConnectivityMapFromCircuitJson,\n type ConnectivityMap,\n} from \"circuit-json-to-connectivity-map\"\nimport {\n getCollidableBounds,\n type Collidable,\n type PcbTraceSegment,\n} from \"./getCollidableBounds\"\nimport {\n segmentToBoundsMinDistance,\n segmentToCircleMinDistance,\n} from \"@tscircuit/math-utils\"\nimport {\n DEFAULT_TRACE_MARGIN,\n DEFAULT_TRACE_THICKNESS,\n EPSILON,\n} from \"lib/drc-defaults\"\nimport { getPcbPortIdsConnectedToTraces } from \"./getPcbPortIdsConnectedToTraces\"\nimport { segmentToSegmentMinDistance } from \"@tscircuit/math-utils\"\nimport { areBoundsOverlapping } from \"./areBoundsOverlapping\"\nimport { getPrimaryId } from \"@tscircuit/circuit-json-util\"\nimport { getCenterOfBoundsPair } from \"./getCenterOfBoundsPair\"\nimport { getClosestPointBetweenSegments } from \"./getClosestPointBetweenSegments\"\nimport { getCenterOfBounds } from \"./getCenterOfBounds\"\nimport { getRadiusOfCircuitJsonElement } from \"./getRadiusOfCircuitJsonElement\"\nimport { getClosestPointBetweenSegmentAndBounds } from \"./getClosestPointBetweenSegmentAndBounds\"\nimport { getLayersOfPcbElement } from \"../util/getLayersOfPcbElement\"\n\nexport function checkEachPcbTraceNonOverlapping(\n circuitJson: AnyCircuitElement[],\n {\n connMap,\n }: {\n connMap?: ConnectivityMap\n } = {},\n): PcbTraceError[] {\n const errors: PcbTraceError[] = []\n connMap ??= getFullConnectivityMapFromCircuitJson(circuitJson)\n\n const pcbTraces = cju(circuitJson).pcb_trace.list()\n const pcbTraceSegments = pcbTraces.flatMap((pcbTrace) => {\n const segments: PcbTraceSegment[] = []\n for (let i = 0; i < pcbTrace.route.length - 1; i++) {\n const p1 = pcbTrace.route[i]\n const p2 = pcbTrace.route[i + 1]\n if (p1.route_type !== \"wire\") continue\n if (p2.route_type !== \"wire\") continue\n if (p1.layer !== p2.layer) continue\n segments.push({\n type: \"pcb_trace_segment\",\n pcb_trace_id: pcbTrace.pcb_trace_id,\n _pcbTrace: pcbTrace,\n thickness:\n \"width\" in p1\n ? p1.width\n : \"width\" in p2\n ? p2.width\n : DEFAULT_TRACE_THICKNESS,\n layer: p1.layer,\n x1: p1.x,\n y1: p1.y,\n x2: p2.x,\n y2: p2.y,\n } as PcbTraceSegment)\n }\n return segments\n })\n const pcbSmtPads = cju(circuitJson).pcb_smtpad.list()\n const pcbPlatedHoles = cju(circuitJson).pcb_plated_hole.list()\n const pcbHoles = cju(circuitJson).pcb_hole.list()\n const pcbVias = cju(circuitJson).pcb_via.list()\n const pcbKeepouts = cju(circuitJson).pcb_keepout.list()\n\n const allObjects: Collidable[] = [\n ...pcbTraceSegments,\n ...pcbSmtPads,\n ...pcbPlatedHoles,\n ...pcbHoles,\n ...pcbVias,\n ...pcbKeepouts,\n ]\n\n const spatialIndex = new SpatialObjectIndex<Collidable>({\n objects: allObjects,\n getBounds: getCollidableBounds,\n })\n\n const getReadableName = (id: string) =>\n getReadableNameForElement(circuitJson, id)\n\n const errorIds = new Set<string>()\n\n // For each segment, check it if overlaps with anything collidable\n for (const segmentA of pcbTraceSegments) {\n const requiredMargin = DEFAULT_TRACE_MARGIN\n const bounds = getCollidableBounds(segmentA)\n const nearbyObjects = spatialIndex.getObjectsInBounds(\n bounds,\n requiredMargin + segmentA.thickness / 2,\n )\n if (segmentA.x1 === segmentA.x2 && segmentA.y1 === segmentA.y2) continue\n\n for (const obj of nearbyObjects) {\n // ignore obstacles not on the trace's layer (except vias)\n if (!getLayersOfPcbElement(obj).includes(segmentA.layer)) {\n continue\n }\n if (obj.type === \"pcb_trace_segment\") {\n const segmentB = obj\n\n if (segmentA.layer !== segmentB.layer) continue\n\n // Check if the segments are overlapping\n if (\n connMap.areIdsConnected(segmentA.pcb_trace_id, segmentB.pcb_trace_id)\n )\n continue\n\n const gap =\n segmentToSegmentMinDistance(\n { x: segmentA.x1, y: segmentA.y1 },\n { x: segmentA.x2, y: segmentA.y2 },\n { x: segmentB.x1, y: segmentB.y1 },\n { x: segmentB.x2, y: segmentB.y2 },\n ) -\n segmentA.thickness / 2 -\n segmentB.thickness / 2\n if (gap > DEFAULT_TRACE_MARGIN - EPSILON) continue\n\n const pcb_trace_error_id = `overlap_${segmentA.pcb_trace_id}_${segmentB.pcb_trace_id}`\n const pcb_trace_error_id_reverse = `overlap_${segmentB.pcb_trace_id}_${segmentA.pcb_trace_id}`\n if (errorIds.has(pcb_trace_error_id)) continue\n if (errorIds.has(pcb_trace_error_id_reverse)) continue\n\n errorIds.add(pcb_trace_error_id)\n errors.push({\n type: \"pcb_trace_error\",\n error_type: \"pcb_trace_error\",\n message: `PCB trace ${getReadableName(segmentA.pcb_trace_id)} overlaps with ${getReadableName(segmentB.pcb_trace_id)} ${gap < 0 ? \"(accidental contact)\" : `(gap: ${gap.toFixed(3)}mm)`}`,\n pcb_trace_id: segmentA.pcb_trace_id,\n source_trace_id: \"\",\n pcb_trace_error_id,\n pcb_component_ids: [],\n center: getClosestPointBetweenSegments(segmentA, segmentB),\n pcb_port_ids: getPcbPortIdsConnectedToTraces([\n segmentA._pcbTrace,\n segmentB._pcbTrace,\n ]),\n })\n continue\n }\n\n const primaryObjId = getPrimaryId(obj as any)\n if (\n connMap.areIdsConnected(\n segmentA.pcb_trace_id,\n \"pcb_trace_id\" in obj ? (obj.pcb_trace_id as string) : primaryObjId,\n )\n )\n continue\n\n const isCircular =\n obj.type === \"pcb_via\" ||\n (obj.type === \"pcb_plated_hole\" && obj.shape === \"circle\") ||\n obj.type === \"pcb_hole\" ||\n (obj.type === \"pcb_smtpad\" && obj.shape === \"circle\")\n\n if (isCircular) {\n const radius = getRadiusOfCircuitJsonElement(obj)\n const distance = segmentToCircleMinDistance(\n { x: segmentA.x1, y: segmentA.y1 },\n { x: segmentA.x2, y: segmentA.y2 },\n { x: obj.x, y: obj.y, radius },\n )\n const gap = distance - segmentA.thickness / 2\n if (gap > DEFAULT_TRACE_MARGIN - EPSILON) continue\n\n const pcb_trace_error_id = `overlap_${segmentA.pcb_trace_id}_${primaryObjId}`\n if (errorIds.has(pcb_trace_error_id)) continue\n errorIds.add(pcb_trace_error_id)\n errors.push({\n type: \"pcb_trace_error\",\n error_type: \"pcb_trace_error\",\n message: `PCB trace ${getReadableName(segmentA.pcb_trace_id)} overlaps with ${obj.type} \"${getReadableName(getPrimaryId(obj as any))}\" ${gap < 0 ? \"(accidental contact)\" : `(gap: ${gap.toFixed(3)}mm)`}`,\n pcb_trace_id: segmentA.pcb_trace_id,\n center: getClosestPointBetweenSegmentAndBounds(\n segmentA,\n getCollidableBounds(obj),\n ),\n source_trace_id: \"\",\n pcb_trace_error_id,\n pcb_component_ids: [\n \"pcb_component_id\" in obj\n ? (obj.pcb_component_id as string)\n : undefined,\n ].filter(Boolean) as string[],\n pcb_port_ids: [\n ...getPcbPortIdsConnectedToTraces([segmentA._pcbTrace]),\n \"pcb_port_id\" in obj ? obj.pcb_port_id : undefined,\n ].filter(Boolean) as string[],\n })\n }\n\n // Handle generic case of hitting the bounds of any collidable obstacle\n // using the bounds of the collidable obstacle\n const gap =\n segmentToBoundsMinDistance(\n { x: segmentA.x1, y: segmentA.y1 },\n { x: segmentA.x2, y: segmentA.y2 },\n getCollidableBounds(obj),\n ) -\n segmentA.thickness / 2\n if (gap + EPSILON < requiredMargin) {\n const pcb_trace_error_id = `overlap_${segmentA.pcb_trace_id}_${primaryObjId}`\n if (errorIds.has(pcb_trace_error_id)) continue\n errorIds.add(pcb_trace_error_id)\n errors.push({\n type: \"pcb_trace_error\",\n error_type: \"pcb_trace_error\",\n message: `PCB trace ${getReadableName(segmentA.pcb_trace_id)} overlaps with ${obj.type} \"${getReadableName(getPrimaryId(obj as any))}\" ${gap < 0 ? \"(accidental contact)\" : `(gap: ${gap.toFixed(3)}mm)`}`,\n pcb_trace_id: segmentA.pcb_trace_id,\n source_trace_id: \"\",\n pcb_trace_error_id,\n pcb_component_ids: [\n \"pcb_component_id\" in obj ? obj.pcb_component_id : undefined,\n ].filter(Boolean) as string[],\n center: getClosestPointBetweenSegmentAndBounds(\n segmentA,\n getCollidableBounds(obj),\n ),\n pcb_port_ids: [\n ...getPcbPortIdsConnectedToTraces([segmentA._pcbTrace]),\n \"pcb_port_id\" in obj ? obj.pcb_port_id : undefined,\n ].filter(Boolean) as string[],\n })\n }\n }\n }\n return errors\n}\n","export type BucketCoordinate = `${number}x${number}`\n\nexport interface Bounds {\n minX: number\n minY: number\n maxX: number\n maxY: number\n}\n\nexport type GetBoundsFn<T> = (obj: T) => Bounds\nexport type GetIdFn<T> = (obj: T) => string\n\nexport class SpatialObjectIndex<T> {\n buckets: Map<BucketCoordinate, Array<T & { spatialIndexId: string }>>\n objectsById: Map<string, T & { spatialIndexId: string }>\n getBounds: GetBoundsFn<T>\n getId: GetIdFn<T>\n CELL_SIZE = 0.4\n\n constructor({\n objects,\n getBounds,\n getId,\n CELL_SIZE,\n }: {\n objects: T[]\n getBounds: GetBoundsFn<T>\n getId?: GetIdFn<T>\n CELL_SIZE?: number\n }) {\n this.buckets = new Map()\n this.objectsById = new Map()\n this.getBounds = getBounds\n this.getId = getId ?? (() => this._getNextId())\n this.CELL_SIZE = CELL_SIZE ?? this.CELL_SIZE\n\n for (const obj of objects) {\n this.addObject(obj)\n }\n }\n\n _idCounter = 0\n _getNextId(): string {\n return `${this._idCounter++}`\n }\n\n addObject(obj: T): void {\n const bounds = this.getBounds(obj)\n const spatialIndexId = this.getId(obj)\n const objWithId = { ...obj, spatialIndexId } as T & {\n spatialIndexId: string\n }\n\n // Store in objectsById for quick lookup\n this.objectsById.set(spatialIndexId, objWithId)\n\n // Calculate the bucket coordinates that cover the object's bounds\n const minBucketX = Math.floor(bounds.minX / this.CELL_SIZE)\n const minBucketY = Math.floor(bounds.minY / this.CELL_SIZE)\n const maxBucketX = Math.floor(bounds.maxX / this.CELL_SIZE)\n const maxBucketY = Math.floor(bounds.maxY / this.CELL_SIZE)\n\n // Add the object to all buckets it intersects with\n for (let bx = minBucketX; bx <= maxBucketX; bx++) {\n for (let by = minBucketY; by <= maxBucketY; by++) {\n const bucketKey = `${bx}x${by}` as BucketCoordinate\n const bucket = this.buckets.get(bucketKey)\n if (!bucket) {\n this.buckets.set(bucketKey, [objWithId])\n } else {\n bucket.push(objWithId)\n }\n }\n }\n }\n\n removeObject(id: string): boolean {\n const obj = this.objectsById.get(id)\n if (!obj) return false\n\n // Remove from objectsById\n this.objectsById.delete(id)\n\n // Calculate the bucket coordinates that cover the object's bounds\n const bounds = this.getBounds(obj)\n const minBucketX = Math.floor(bounds.minX / this.CELL_SIZE)\n const minBucketY = Math.floor(bounds.minY / this.CELL_SIZE)\n const maxBucketX = Math.floor(bounds.maxX / this.CELL_SIZE)\n const maxBucketY = Math.floor(bounds.maxY / this.CELL_SIZE)\n\n // Remove the object from all buckets it might be in\n for (let bx = minBucketX; bx <= maxBucketX; bx++) {\n for (let by = minBucketY; by <= maxBucketY; by++) {\n const bucketKey = `${bx}x${by}` as BucketCoordinate\n const bucket = this.buckets.get(bucketKey)\n if (bucket) {\n const index = bucket.findIndex((item) => item.spatialIndexId === id)\n if (index !== -1) {\n bucket.splice(index, 1)\n if (bucket.length === 0) {\n this.buckets.delete(bucketKey)\n }\n }\n }\n }\n }\n\n return true\n }\n\n getBucketKey(x: number, y: number): BucketCoordinate {\n return `${Math.floor(x / this.CELL_SIZE)}x${Math.floor(y / this.CELL_SIZE)}`\n }\n\n getObjectsInBounds(bounds: Bounds, margin = 0): T[] {\n const objects: T[] = []\n const addedIds = new Set<string>()\n\n // Calculate the bucket coordinates that cover the requested bounds with margin\n const minBucketX = Math.floor((bounds.minX - margin) / this.CELL_SIZE)\n const minBucketY = Math.floor((bounds.minY - margin) / this.CELL_SIZE)\n const maxBucketX = Math.floor((bounds.maxX + margin) / this.CELL_SIZE)\n const maxBucketY = Math.floor((bounds.maxY + margin) / this.CELL_SIZE)\n\n // Collect objects from all buckets that intersect the bounds\n for (let bx = minBucketX; bx <= maxBucketX; bx++) {\n for (let by = minBucketY; by <= maxBucketY; by++) {\n const bucketKey = `${bx}x${by}` as BucketCoordinate\n const bucket = this.buckets.get(bucketKey) || []\n\n for (const obj of bucket) {\n const id = obj.spatialIndexId\n if (addedIds.has(id)) continue\n\n addedIds.add(id)\n objects.push(obj)\n }\n }\n }\n\n return objects\n }\n}\n","import { getBoundsOfPcbElements } from \"@tscircuit/circuit-json-util\"\nimport type {\n AnyCircuitElement,\n PcbHole,\n PCBKeepout,\n PcbPlatedHole,\n PcbSmtPad,\n PcbTrace,\n PcbTraceError,\n PcbVia,\n} from \"circuit-json\"\n\ninterface Bounds {\n minX: number\n minY: number\n maxX: number\n maxY: number\n}\n\nexport type PcbTraceSegment = {\n type: \"pcb_trace_segment\"\n _pcbTrace: PcbTrace\n pcb_trace_id: string\n thickness: number\n layer: string\n x1: number\n y1: number\n x2: number\n y2: number\n}\n\nexport type Collidable =\n | PcbTraceSegment\n | PcbSmtPad\n | PcbPlatedHole\n | PcbHole\n | PcbVia\n | PCBKeepout\n\nexport const getCollidableBounds = (collidable: Collidable): Bounds => {\n if (collidable.type === \"pcb_trace_segment\") {\n return {\n minX: Math.min(collidable.x1, collidable.x2),\n minY: Math.min(collidable.y1, collidable.y2),\n maxX: Math.max(collidable.x1, collidable.x2),\n maxY: Math.max(collidable.y1, collidable.y2),\n }\n }\n return getBoundsOfPcbElements([collidable as any])\n}\n","export const DEFAULT_TRACE_MARGIN = 0.1\nexport const DEFAULT_TRACE_THICKNESS = 0.15\nexport const DEFAULT_VIA_DIAMETER = 0.6\nexport const DEFAULT_VIA_BOARD_MARGIN = 0.3\n\nexport const DEFAULT_SAME_NET_VIA_MARGIN = 0.2\nexport const DEFAULT_DIFFERENT_NET_VIA_MARGIN = 0.3\n\nexport const EPSILON = 0.005\n","import type { PcbTrace } from \"circuit-json\"\n\nexport function getPcbPortIdsConnectedToTrace(trace: PcbTrace) {\n const connectedPcbPorts = new Set<string>()\n for (const segment of trace.route) {\n if (segment.route_type === \"wire\") {\n if (segment.start_pcb_port_id)\n connectedPcbPorts.add(segment.start_pcb_port_id)\n if (segment.end_pcb_port_id)\n connectedPcbPorts.add(segment.end_pcb_port_id)\n }\n }\n\n return Array.from(connectedPcbPorts)\n}\n\nexport function getPcbPortIdsConnectedToTraces(traces: PcbTrace[]) {\n const connectedPorts = new Set<string>()\n for (const trace of traces) {\n for (const portId of getPcbPortIdsConnectedToTrace(trace)) {\n connectedPorts.add(portId)\n }\n }\n return Array.from(connectedPorts)\n}\n","import type { PcbTraceSegment } from \"./getCollidableBounds\"\n\nexport const getClosestPointBetweenSegments = (\n segmentA: PcbTraceSegment,\n segmentB: PcbTraceSegment,\n): { x: number; y: number } => {\n // Define points for each segment\n const a1 = { x: segmentA.x1, y: segmentA.y1 }\n const a2 = { x: segmentA.x2, y: segmentA.y2 }\n const b1 = { x: segmentB.x1, y: segmentB.y1 }\n const b2 = { x: segmentB.x2, y: segmentB.y2 }\n\n // Calculate direction vectors for each segment\n const va = { x: a2.x - a1.x, y: a2.y - a1.y }\n const vb = { x: b2.x - b1.x, y: b2.y - b1.y }\n\n // Calculate squared lengths of segments\n const lenSqrA = va.x * va.x + va.y * va.y\n const lenSqrB = vb.x * vb.x + vb.y * vb.y\n\n // If either segment is a point (zero length), handle as special case\n if (lenSqrA === 0 || lenSqrB === 0) {\n if (lenSqrA === 0 && lenSqrB === 0) {\n // Both segments are points, return the distance between them\n // Calculate the average point\n return {\n x: (a1.x + b1.x) / 2,\n y: (a1.y + b1.y) / 2,\n }\n }\n if (lenSqrA === 0) {\n // First segment is a point, find closest point on second segment\n const t = clamp(\n ((a1.x - b1.x) * vb.x + (a1.y - b1.y) * vb.y) / lenSqrB,\n 0,\n 1,\n )\n const closestOnB = {\n x: b1.x + t * vb.x,\n y: b1.y + t * vb.y,\n }\n // Calculate the average point\n return {\n x: (a1.x + closestOnB.x) / 2,\n y: (a1.y + closestOnB.y) / 2,\n }\n }\n // Second segment is a point, find closest point on first segment\n const t = clamp(\n ((b1.x - a1.x) * va.x + (b1.y - a1.y) * va.y) / lenSqrA,\n 0,\n 1,\n )\n const closestOnA = {\n x: a1.x + t * va.x,\n y: a1.y + t * va.y,\n }\n // Calculate the average point\n return {\n x: (closestOnA.x + b1.x) / 2,\n y: (closestOnA.y + b1.y) / 2,\n }\n }\n\n // Vector between segment starting points\n const w = { x: a1.x - b1.x, y: a1.y - b1.y }\n\n // Calculate dot products\n const dotAA = va.x * va.x + va.y * va.y\n const dotAB = va.x * vb.x + va.y * vb.y\n const dotAW = va.x * w.x + va.y * w.y\n const dotBB = vb.x * vb.x + vb.y * vb.y\n const dotBW = vb.x * w.x + vb.y * w.y\n\n // Calculate parametric positions (t values) along each segment\n const denominator = dotAA * dotBB - dotAB * dotAB\n\n // If segments are parallel, handle separately\n if (denominator < 1e-10) {\n return closestPointsParallelSegments(\n a1,\n a2,\n b1,\n b2,\n va,\n vb,\n lenSqrA,\n lenSqrB,\n )\n }\n\n // Calculate parameters for closest points\n let tA = (dotAB * dotBW - dotBB * dotAW) / denominator\n let tB = (dotAA * dotBW - dotAB * dotAW) / denominator\n\n // Clamp parameters to segment bounds\n tA = clamp(tA, 0, 1)\n tB = clamp(tB, 0, 1)\n\n // Recalculate tB if tA was clamped\n tB = (tA * dotAB + dotBW) / dotBB\n tB = clamp(tB, 0, 1)\n\n // Recalculate tA if tB was clamped\n tA = (tB * dotAB - dotAW) / dotAA\n tA = clamp(tA, 0, 1)\n\n // Calculate closest points on each segment\n const closestOnA = {\n x: a1.x + tA * va.x,\n y: a1.y + tA * va.y,\n }\n\n const closestOnB = {\n x: b1.x + tB * vb.x,\n y: b1.y + tB * vb.y,\n }\n\n // Calculate distance between closest points\n const dx = closestOnA.x - closestOnB.x\n const dy = closestOnA.y - closestOnB.y\n const distance = Math.sqrt(dx * dx + dy * dy)\n\n // Calculate the average of the closest points\n const averagePoint = {\n x: (closestOnA.x + closestOnB.x) / 2,\n y: (closestOnA.y + closestOnB.y) / 2,\n }\n\n return averagePoint\n}\n\n// Helper function for handling parallel segments\nconst closestPointsParallelSegments = (\n a1: { x: number; y: number },\n a2: { x: number; y: number },\n b1: { x: number; y: number },\n b2: { x: number; y: number },\n va: { x: number; y: number },\n vb: { x: number; y: number },\n lenSqrA: number,\n lenSqrB: number,\n) => {\n // Project b1 onto segment A\n let tA = ((b1.x - a1.x) * va.x + (b1.y - a1.y) * va.y) / lenSqrA\n tA = clamp(tA, 0, 1)\n const pointOnA1 = { x: a1.x + tA * va.x, y: a1.y + tA * va.y }\n\n // Project b2 onto segment A\n let tA2 = ((b2.x - a1.x) * va.x + (b2.y - a1.y) * va.y) / lenSqrA\n tA2 = clamp(tA2, 0, 1)\n const pointOnA2 = { x: a1.x + tA2 * va.x, y: a1.y + tA2 * va.y }\n\n // Project a1 onto segment B\n let tB = ((a1.x - b1.x) * vb.x + (a1.y - b1.y) * vb.y) / lenSqrB\n tB = clamp(tB, 0, 1)\n const pointOnB1 = { x: b1.x + tB * vb.x, y: b1.y + tB * vb.y }\n\n // Project a2 onto segment B\n let tB2 = ((a2.x - b1.x) * vb.x + (a2.y - b1.y) * vb.y) / lenSqrB\n tB2 = clamp(tB2, 0, 1)\n const pointOnB2 = { x: b1.x + tB2 * vb.x, y: b1.y + tB2 * vb.y }\n\n // Calculate all possible distances between end points and their projections\n const distances = [\n {\n pointA: pointOnA1,\n pointB: b1,\n distance: Math.sqrt(\n (pointOnA1.x - b1.x) ** 2 + (pointOnA1.y - b1.y) ** 2,\n ),\n },\n {\n pointA: pointOnA2,\n pointB: b2,\n distance: Math.sqrt(\n (pointOnA2.x - b2.x) ** 2 + (pointOnA2.y - b2.y) ** 2,\n ),\n },\n {\n pointA: a1,\n pointB: pointOnB1,\n distance: Math.sqrt(\n (a1.x - pointOnB1.x) ** 2 + (a1.y - pointOnB1.y) ** 2,\n ),\n },\n {\n pointA: a2,\n pointB: pointOnB2,\n distance: Math.sqrt(\n (a2.x - pointOnB2.x) ** 2 + (a2.y - pointOnB2.y) ** 2,\n ),\n },\n ]\n\n // Find closest pair\n const closestPair = distances.reduce((closest, current) =>\n current.distance < closest.distance ? current : closest,\n )\n\n // Calculate the average of the closest points\n return {\n x: (closestPair.pointA.x + closestPair.pointB.x) / 2,\n y: (closestPair.pointA.y + closestPair.pointB.y) / 2,\n }\n}\n\n// Helper function to clamp a value between min and max\nconst clamp = (value: number, min: number, max: number): number => {\n return Math.max(min, Math.min(max, value))\n}\n","import type {\n AnyCircuitElement,\n PcbHole,\n PcbPlatedHole,\n PcbVia,\n PcbSmtPad,\n} from \"circuit-json\"\n\nexport const getRadiusOfCircuitJsonElement = (\n obj: PcbVia | PcbPlatedHole | PcbHole | PcbSmtPad,\n) => {\n if (obj.type === \"pcb_via\") {\n return obj.outer_diameter / 2\n }\n if (obj.type === \"pcb_plated_hole\" && obj.shape === \"circle\") {\n return obj.outer_diameter / 2\n }\n if (obj.type === \"pcb_hole\" && obj.hole_shape === \"circle\") {\n return obj.hole_diameter / 2\n }\n if (obj.type === \"pcb_smtpad\" && obj.shape === \"circle\") {\n return obj.radius\n }\n throw new Error(\n `Could not determine radius of element: ${JSON.stringify(obj)}`,\n )\n}\n","import type { Bounds } from \"lib/data-structures/SpatialIndex\"\nimport type { PcbTraceSegment } from \"./getCollidableBounds\"\n\nexport const getClosestPointBetweenSegmentAndBounds = (\n segment: PcbTraceSegment,\n bounds: Bounds,\n): { x: number; y: number } => {\n // Define segment points\n const p1 = { x: segment.x1, y: segment.y1 }\n const p2 = { x: segment.x2, y: segment.y2 }\n\n // Define bounds corners\n const minX = bounds.minX\n const minY = bounds.minY\n const maxX = bounds.maxX\n const maxY = bounds.maxY\n\n // Check if segment is a point\n if (p1.x === p2.x && p1.y === p2.y) {\n // For a point, find the closest point on the bounds\n const closestX = Math.max(minX, Math.min(maxX, p1.x))\n const closestY = Math.max(minY, Math.min(maxY, p1.y))\n\n // If the point is inside the bounds, return the point itself\n if (closestX === p1.x && closestY === p1.y) {\n return { x: p1.x, y: p1.y }\n }\n\n // Otherwise, return the closest point on the bounds\n return { x: closestX, y: closestY }\n }\n\n // Calculate direction vector of the segment\n const dx = p2.x - p1.x\n const dy = p2.y - p1.y\n\n // Calculate parameter values for intersection with each boundary\n const tMinX = dx !== 0 ? (minX - p1.x) / dx : Number.NEGATIVE_INFINITY\n const tMaxX = dx !== 0 ? (maxX - p1.x) / dx : Number.POSITIVE_INFINITY\n const tMinY = dy !== 0 ? (minY - p1.y) / dy : Number.NEGATIVE_INFINITY\n const tMaxY = dy !== 0 ? (maxY - p1.y) / dy : Number.POSITIVE_INFINITY\n\n // Find the entering and exiting parameters\n const tEnter = Math.max(Math.min(tMinX, tMaxX), Math.min(tMinY, tMaxY))\n const tExit = Math.min(Math.max(tMinX, tMaxX), Math.max(tMinY, tMaxY))\n\n // Check if segment intersects the bounds\n if (tEnter <= tExit && tExit >= 0 && tEnter <= 1) {\n // Segment intersects bounds, clamp parameter to segment\n const t = Math.max(0, Math.min(1, tEnter))\n return {\n x: p1.x + t * dx,\n y: p1.y + t * dy,\n }\n }\n\n // Segment doesn't intersect bounds, find closest point\n // Check each endpoint of the segment against the bounds\n const closestToP1 = {\n x: Math.max(minX, Math.min(maxX, p1.x)),\n y: Math.max(minY, Math.min(maxY, p1.y)),\n }\n\n const closestToP2 = {\n x: Math.max(minX, Math.min(maxX, p2.x)),\n y: Math.max(minY, Math.min(maxY, p2.y)),\n }\n\n // Calculate distances\n const distToP1Squared =\n (closestToP1.x - p1.x) ** 2 + (closestToP1.y - p1.y) ** 2\n const distToP2Squared =\n (closestToP2.x - p2.x) ** 2 + (closestToP2.y - p2.y) ** 2\n\n // Check each edge of the bounds against the segment\n const edges = [\n { start: { x: minX, y: minY }, end: { x: maxX, y: minY } }, // Bottom edge\n { start: { x: maxX, y: minY }, end: { x: maxX, y: maxY } }, // Right edge\n { start: { x: maxX, y: maxY }, end: { x: minX, y: maxY } }, // Top edge\n { start: { x: minX, y: maxY }, end: { x: minX, y: minY } }, // Left edge\n ]\n\n let minDistance = Math.min(distToP1Squared, distToP2Squared)\n let closestPoint =\n distToP1Squared <= distToP2Squared ? closestToP1 : closestToP2\n\n // Helper function to clamp a value between min and max\n const clamp = (value: number, min: number, max: number): number => {\n return Math.max(min, Math.min(max, value))\n }\n\n // Check each edge\n for (const edge of edges) {\n // Calculate direction vectors\n const va = { x: p2.x - p1.x, y: p2.y - p1.y }\n const vb = { x: edge.end.x - edge.start.x, y: edge.end.y - edge.start.y }\n const w = { x: p1.x - edge.start.x, y: p1.y - edge.start.y }\n\n // Calculate dot products\n const dotAA = va.x * va.x + va.y * va.y\n const dotAB = va.x * vb.x + va.y * vb.y\n const dotAW = va.x * w.x + va.y * w.y\n const dotBB = vb.x * vb.x + vb.y * vb.y\n const dotBW = vb.x * w.x + vb.y * w.y\n\n // Calculate parameters for closest points\n const denominator = dotAA * dotBB - dotAB * dotAB\n\n // Skip if lines are parallel\n if (Math.abs(denominator) < 1e-10) continue\n\n let tA = (dotAB * dotBW - dotBB * dotAW) / denominator\n let tB = (dotAA * dotBW - dotAB * dotAW) / denominator\n\n // Clamp parameters to segment bounds\n tA = clamp(tA, 0, 1)\n tB = clamp(tB, 0, 1)\n\n // Calculate closest points\n const closestOnSegment = {\n x: p1.x + tA * va.x,\n y: p1.y + tA * va.y,\n }\n\n const closestOnEdge = {\n x: edge.start.x + tB * vb.x,\n y: edge.start.y + tB * vb.y,\n }\n\n // Calculate distance\n const dx = closestOnSegment.x - closestOnEdge.x\n const dy = closestOnSegment.y - closestOnEdge.y\n const distSquared = dx * dx + dy * dy\n\n // Update if this is closer\n if (distSquared < minDistance) {\n minDistance = distSquared\n closestPoint = {\n x: (closestOnSegment.x + closestOnEdge.x) / 2,\n y: (closestOnSegment.y + closestOnEdge.y) / 2,\n }\n }\n }\n\n return closestPoint\n}\n","import type { Collidable } from \"lib/check-each-pcb-trace-non-overlapping/getCollidableBounds\"\nimport { all_layers } from \"circuit-json\"\n\nexport function getLayersOfPcbElement(obj: Collidable): string[] {\n if (obj.type === \"pcb_trace_segment\") {\n return [obj.layer]\n }\n if (obj.type === \"pcb_smtpad\") {\n return [obj.layer]\n }\n if (obj.type === \"pcb_plated_hole\") {\n return Array.isArray(obj.layers) ? obj.layers : [...all_layers]\n }\n if (obj.type === \"pcb_hole\") {\n return [...all_layers]\n }\n if (obj.type === \"pcb_via\") {\n return Array.isArray(obj.layers) ? obj.layers : [...all_layers]\n }\n if (obj.type === \"pcb_keepout\") {\n return Array.isArray(obj.layers) ? obj.layers : []\n }\n return []\n}\n","export class NetManager {\n private networks: Set<Set<string>> = new Set()\n\n setConnected(nodes: string[]): void {\n if (nodes.length < 2) return\n\n let targetNetwork: Set<string> | null = null\n\n // Check if any of the nodes are already in a network\n for (const network of this.networks) {\n for (const node of nodes) {\n if (network.has(node)) {\n if (targetNetwork === null) {\n targetNetwork = network\n } else if (targetNetwork !== network) {\n // Merge networks\n for (const mergeNode of network) {\n targetNetwork.add(mergeNode)\n }\n this.networks.delete(network)\n }\n break\n }\n }\n if (targetNetwork !== null && targetNetwork !== network) break\n }\n\n // If no existing network found, create a new one\n if (targetNetwork === null) {\n targetNetwork = new Set(nodes)\n this.networks.add(targetNetwork)\n } else {\n // Add all nodes to the target network\n for (const node of nodes) {\n targetNetwork.add(node)\n }\n }\n }\n\n isConnected(nodes: string[]): boolean {\n if (nodes.length < 2) return true\n\n for (const network of this.networks) {\n if (nodes.every((node) => network.has(node))) {\n return true\n }\n }\n\n return false\n }\n}\n","import type {\n AnyCircuitElement,\n PcbBoard,\n PcbVia,\n PcbPlacementError,\n} from \"circuit-json\"\nimport { getReadableNameForElement } from \"@tscircuit/circuit-json-util\"\nimport { DEFAULT_VIA_BOARD_MARGIN } from \"lib/drc-defaults\"\n\nexport function checkViasOffBoard(\n circuitJson: AnyCircuitElement[],\n): PcbPlacementError[] {\n const board = circuitJson.find((el) => el.type === \"pcb_board\") as PcbBoard\n\n if (!board) return []\n\n const vias = circuitJson.filter((el) => el.type === \"pcb_via\") as PcbVia[]\n\n if (vias.length === 0) return []\n\n if (board.width === undefined || board.height === undefined) return []\n\n const boardMinX = board.center.x - board.width / 2\n const boardMaxX = board.center.x + board.width / 2\n const boardMinY = board.center.y - board.height / 2\n const boardMaxY = board.center.y + board.height / 2\n\n const errors: PcbPlacementError[] = []\n\n for (const via of vias) {\n const viaRadius = via.outer_diameter / 2\n const viaMinX = via.x - viaRadius\n const viaMaxX = via.x + viaRadius\n const viaMinY = via.y - viaRadius\n const viaMaxY = via.y + viaRadius\n\n if (\n viaMinX < boardMinX + DEFAULT_VIA_BOARD_MARGIN ||\n viaMaxX > boardMaxX - DEFAULT_VIA_BOARD_MARGIN ||\n viaMinY < boardMinY + DEFAULT_VIA_BOARD_MARGIN ||\n viaMaxY > boardMaxY - DEFAULT_VIA_BOARD_MARGIN\n ) {\n const viaName = getReadableNameForElement(circuitJson, via.pcb_via_id)\n errors.push({\n type: \"pcb_placement_error\",\n pcb_placement_error_id: `out_of_board_${via.pcb_via_id}`,\n message: `Via ${viaName} is outside or crossing the board boundary`,\n error_type: \"pcb_placement_error\",\n })\n }\n }\n\n return errors\n}\n","import type {\n AnyCircuitElement,\n PcbBoard,\n PcbComponent,\n AnySourceComponent,\n PcbComponentOutsideBoardError,\n} from \"circuit-json\"\nimport { getReadableNameForElement } from \"@tscircuit/circuit-json-util\"\nimport type { Point } from \"@tscircuit/math-utils\"\nimport * as Flatten from \"@flatten-js/core\"\nimport { rotateDEG, applyToPoint } from \"transformation-matrix\"\n\n/**\n * Create a rectangle polygon centered at (cx,cy) with given width/height and rotation (degrees).\n * Uses transformation-matrix to rotate around the center and returns a Flatten.Polygon.\n */\n\nfunction isPolygonCCW(poly: Flatten.Polygon): boolean {\n // @ts-ignore\n return poly.area() >= 0\n}\n\nfunction rectanglePolygon({\n center,\n size,\n rotationDeg = 0,\n}: {\n center: Point\n size: { width: number; height: number }\n rotationDeg?: number\n}): Flatten.Polygon {\n const cx = center.x\n const cy = center.y\n const hw = size.width / 2\n const hh = size.height / 2\n\n const corners: Flatten.Point[] = [\n new Flatten.Point(cx - hw, cy - hh),\n new Flatten.Point(cx + hw, cy - hh),\n new Flatten.Point(cx + hw, cy + hh),\n new Flatten.Point(cx - hw, cy + hh),\n ]\n\n let poly = new Flatten.Polygon(corners)\n\n if (rotationDeg) {\n const matrix = rotateDEG(rotationDeg, cx, cy)\n const rotatedCorners = corners.map((pt) => {\n const p = applyToPoint(matrix, { x: pt.x, y: pt.y })\n return new Flatten.Point(p.x, p.y)\n })\n poly = new Flatten.Polygon(rotatedCorners)\n }\n\n // Ensure CCW order\n if (!isPolygonCCW(poly)) poly.reverse()\n\n return poly\n}\n\nfunction boardToPolygon({\n board,\n}: { board: PcbBoard }): Flatten.Polygon | null {\n if (board.outline && board.outline.length > 0) {\n const points = board.outline.map((p) => new Flatten.Point(p.x, p.y))\n const poly = new Flatten.Polygon(points)\n\n if (!isPolygonCCW(poly)) {\n poly.reverse()\n }\n\n return poly\n }\n\n if (\n board.center &&\n typeof board.width === \"number\" &&\n typeof board.height === \"number\"\n ) {\n return rectanglePolygon({\n center: board.center,\n size: { width: board.width, height: board.height },\n rotationDeg: 0,\n })\n }\n\n return null\n}\n\n/** Get human-readable component name from circuit JSON */\nfunction getComponentName({\n circuitJson,\n component,\n}: {\n circuitJson: AnyCircuitElement[]\n component: PcbComponent\n}): string {\n if (component.source_component_id) {\n const sourceComponent = circuitJson.find(\n (el): el is AnySourceComponent =>\n el.type === \"source_component\" &&\n el.source_component_id === component.source_component_id,\n )\n if (sourceComponent && \"name\" in sourceComponent && sourceComponent.name) {\n return sourceComponent.name\n }\n }\n\n return (\n getReadableNameForElement(circuitJson, component.pcb_component_id) ||\n \"Unknown\"\n )\n}\n\n/**\n * Compute overlap distance based on polygon containment and distances.\n * - If component center is outside board, distance is from center to board polygon.\n * - Samples rotated rectangle corners and edge midpoints; for any outside points,\n * computes distance to board polygon and returns the maximum.\n * - Falls back to intersection area ratio heuristic if needed.\n * - Returns small epsilon if fully inside.\n */\nfunction computeOverlapDistance(\n compPoly: Flatten.Polygon,\n boardPoly: Flatten.Polygon,\n componentCenter: Point,\n componentWidth: number,\n componentHeight: number,\n rotationDeg: number,\n): number {\n const centerPoint = new Flatten.Point(componentCenter.x, componentCenter.y)\n // If center is outside board polygon, return distance to board polygon\n if (!boardPoly.contains(centerPoint)) {\n const dist = boardPoly.distanceTo(centerPoint)\n return Array.isArray(dist) ? dist[0] : Number(dist) || 0\n }\n\n // Sample corners and edge midpoints of rotated rectangle\n const hw = componentWidth / 2\n const hh = componentHeight / 2\n\n // Original corners\n const corners: Point[] = [\n { x: componentCenter.x - hw, y: componentCenter.y - hh },\n { x: componentCenter.x + hw, y: componentCenter.y - hh },\n { x: componentCenter.x + hw, y: componentCenter.y + hh },\n { x: componentCenter.x - hw, y: componentCenter.y + hh },\n ]\n\n // Edge midpoints\n const midpoints: Point[] = []\n for (let i = 0; i < 4; i++) {\n const next = (i + 1) % 4\n midpoints.push({\n x: (corners[i].x + corners[next].x) / 2,\n y: (corners[i].y + corners[next].y) / 2,\n })\n }\n\n // Rotate points around center by rotationDeg\n const matrix = rotateDEG(rotationDeg, componentCenter.x, componentCenter.y)\n const rotatePoint = (pt: Point) => {\n const p = applyToPoint(matrix, pt)\n return new Flatten.Point(p.x, p.y)\n }\n\n const rotatedPoints = corners.concat(midpoints).map(rotatePoint)\n\n // For any point outside board polygon, compute distance to board polygon\n let maxDistance = 0\n for (const pt of rotatedPoints) {\n if (!boardPoly.contains(pt)) {\n const dist = boardPoly.distanceTo(pt)\n const d = Array.isArray(dist) ? dist[0] : Number(dist) || 0\n if (d > maxDistance) maxDistance = d\n }\n }\n\n if (maxDistance > 0) {\n return maxDistance\n }\n\n // Fallback: use intersection area ratio heuristic\n try {\n const intersection = Flatten.BooleanOperations.intersect(\n compPoly,\n boardPoly,\n )\n\n let intersectionArea = 0\n if (!intersection) {\n intersectionArea = 0\n } else if (Array.isArray(intersection)) {\n intersectionArea = intersection.reduce(\n (sum, p) => sum + (typeof p.area === \"function\" ? p.area() : 0),\n 0,\n )\n } else if (typeof (intersection as any).area === \"function\") {\n intersectionArea = (intersection as any).area()\n } else {\n intersectionArea = 0\n }\n\n const compArea = compPoly.area()\n\n if (intersectionArea > 0 && intersectionArea < compArea) {\n const overlapRatio = 1 - intersectionArea / compArea\n const compWidth = Math.abs(componentWidth)\n const compHeight = Math.abs(componentHeight)\n return Math.min(compWidth, compHeight) * overlapRatio\n } else if (intersectionArea === 0) {\n // completely outside (should not happen here), return small epsilon\n return 0.1\n } else {\n return 0.1\n }\n } catch {\n // If boolean ops fail (unlikely), return small epsilon\n return 0.1\n }\n}\n\n/**\n * Main function — polygon-first: construct polygons, test containment / intersection,\n * compute overlap distance using boolean intersection area or geometric distance.\n */\nexport function checkPcbComponentsOutOfBoard(\n circuitJson: AnyCircuitElement[],\n): PcbComponentOutsideBoardError[] {\n const board = circuitJson.find(\n (el): el is PcbBoard => el.type === \"pcb_board\",\n )\n if (!board) return []\n\n const boardPoly = boardToPolygon({ board })\n if (!boardPoly) return []\n\n const components = circuitJson.filter(\n (el): el is PcbComponent => el.type === \"pcb_component\",\n )\n if (components.length === 0) return []\n\n const errors: PcbComponentOutsideBoardError[] = []\n\n for (const c of components) {\n // need center, width, height\n if (\n !c.center ||\n typeof c.width !== \"number\" ||\n typeof c.height !== \"number\"\n )\n continue\n\n if (c.width <= 0 || c.height <= 0) continue\n\n const compPoly = rectanglePolygon({\n center: c.center,\n size: { width: c.width, height: c.height },\n rotationDeg: c.rotation || 0,\n })\n\n if (compPoly.area() === 0) continue\n\n // If component is entirely inside board polygon -> OK\n // Flatten.Polygon.contains accepts shapes; this is the correct polygon containment check.\n const isInside = boardPoly.contains(compPoly)\n if (isInside) continue\n\n // Component is at least partially outside. Compute overlapDistance:\n const overlapDistance = computeOverlapDistance(\n compPoly,\n boardPoly,\n c.center,\n c.width,\n c.height,\n c.rotation || 0,\n )\n\n const compName = getComponentName({ circuitJson, component: c })\n const overlapDistanceMm = Math.round(overlapDistance * 100) / 100\n\n errors.push({\n type: \"pcb_component_outside_board_error\",\n error_type: \"pcb_component_outside_board_error\",\n pcb_component_outside_board_error_id: `pcb_component_outside_board_${c.pcb_component_id}`,\n message: `Component ${compName} (${c.pcb_component_id}) extends outside board boundaries by ${overlapDistanceMm}mm`,\n pcb_component_id: c.pcb_component_id,\n pcb_board_id: board.pcb_board_id,\n component_center: c.center,\n component_bounds: {\n min_x: compPoly.box.xmin,\n max_x: compPoly.box.xmax,\n min_y: compPoly.box.ymin,\n max_y: compPoly.box.ymax,\n },\n subcircuit_id: c.subcircuit_id,\n source_component_id: c.source_component_id,\n })\n }\n\n return errors\n}\n","import type {\n AnyCircuitElement,\n PcbVia,\n PcbViaClearanceError,\n} from \"circuit-json\"\nimport { getReadableNameForElement } from \"@tscircuit/circuit-json-util\"\nimport {\n getFullConnectivityMapFromCircuitJson,\n type ConnectivityMap,\n} from \"circuit-json-to-connectivity-map\"\nimport { DEFAULT_SAME_NET_VIA_MARGIN, EPSILON } from \"lib/drc-defaults\"\n\nfunction distance(a: PcbVia, b: PcbVia): number {\n return Math.hypot(a.x - b.x, a.y - b.y)\n}\n\nexport function checkSameNetViaSpacing(\n circuitJson: AnyCircuitElement[],\n {\n connMap,\n minSpacing = DEFAULT_SAME_NET_VIA_MARGIN,\n }: { connMap?: ConnectivityMap; minSpacing?: number } = {},\n): PcbViaClearanceError[] {\n const vias = circuitJson.filter((el) => el.type === \"pcb_via\") as PcbVia[]\n if (vias.length < 2) return []\n connMap ??= getFullConnectivityMapFromCircuitJson(circuitJson)\n const errors: PcbViaClearanceError[] = []\n const reported = new Set<string>()\n\n for (let i = 0; i < vias.length; i++) {\n for (let j = i + 1; j < vias.length; j++) {\n const viaA = vias[i]\n const viaB = vias[j]\n if (!connMap.areIdsConnected(viaA.pcb_via_id, viaB.pcb_via_id)) continue\n const gap =\n distance(viaA, viaB) - viaA.outer_diameter / 2 - viaB.outer_diameter / 2\n if (gap + EPSILON >= minSpacing) continue\n const pairId = [viaA.pcb_via_id, viaB.pcb_via_id].sort().join(\"_\")\n if (reported.has(pairId)) continue\n reported.add(pairId)\n errors.push({\n type: \"pcb_via_clearance_error\",\n pcb_error_id: `same_net_vias_close_${pairId}`,\n message: `Vias ${getReadableNameForElement(\n circuitJson,\n viaA.pcb_via_id,\n )} and ${getReadableNameForElement(\n circuitJson,\n viaB.pcb_via_id,\n )} are too close together (gap: ${gap.toFixed(3)}mm)`,\n error_type: \"pcb_via_clearance_error\",\n pcb_via_ids: [viaA.pcb_via_id, viaB.pcb_via_id],\n minimum_clearance: minSpacing,\n actual_clearance: gap,\n pcb_center: {\n x: (viaA.x + viaB.x) / 2,\n y: (viaA.y + viaB.y) / 2,\n },\n })\n }\n }\n\n return errors\n}\n","import type {\n AnyCircuitElement,\n PcbVia,\n PcbViaClearanceError,\n} from \"circuit-json\"\nimport { getReadableNameForElement } from \"@tscircuit/circuit-json-util\"\nimport {\n getFullConnectivityMapFromCircuitJson,\n type ConnectivityMap,\n} from \"circuit-json-to-connectivity-map\"\nimport { DEFAULT_DIFFERENT_NET_VIA_MARGIN, EPSILON } from \"lib/drc-defaults\"\n\nfunction distance(a: PcbVia, b: PcbVia): number {\n return Math.hypot(a.x - b.x, a.y - b.y)\n}\n\nexport function checkDifferentNetViaSpacing(\n circuitJson: AnyCircuitElement[],\n {\n connMap,\n minSpacing = DEFAULT_DIFFERENT_NET_VIA_MARGIN,\n }: { connMap?: ConnectivityMap; minSpacing?: number } = {},\n): PcbViaClearanceError[] {\n const vias = circuitJson.filter((el) => el.type === \"pcb_via\") as PcbVia[]\n if (vias.length < 2) return []\n connMap ??= getFullConnectivityMapFromCircuitJson(circuitJson)\n const errors: PcbViaClearanceError[] = []\n const reported = new Set<string>()\n\n for (let i = 0; i < vias.length; i++) {\n for (let j = i + 1; j < vias.length; j++) {\n const viaA = vias[i]\n const viaB = vias[j]\n if (connMap.areIdsConnected(viaA.pcb_via_id, viaB.pcb_via_id)) continue\n const gap =\n distance(viaA, viaB) - viaA.outer_diameter / 2 - viaB.outer_diameter / 2\n if (gap + EPSILON >= minSpacing) continue\n const pairId = [viaA.pcb_via_id, viaB.pcb_via_id].sort().join(\"_\")\n if (reported.has(pairId)) continue\n reported.add(pairId)\n errors.push({\n type: \"pcb_via_clearance_error\",\n pcb_error_id: `different_net_vias_close_${pairId}`,\n message: `Vias ${getReadableNameForElement(\n circuitJson,\n viaA.pcb_via_id,\n )} and ${getReadableNameForElement(\n circuitJson,\n viaB.pcb_via_id,\n )} from different nets are too close together (gap: ${gap.toFixed(\n 3,\n )}mm)`,\n error_type: \"pcb_via_clearance_error\",\n pcb_via_ids: [viaA.pcb_via_id, viaB.pcb_via_id],\n minimum_clearance: minSpacing,\n actual_clearance: gap,\n pcb_center: {\n x: (viaA.x + viaB.x) / 2,\n y: (viaA.y + viaB.y) / 2,\n },\n })\n }\n }\n\n return errors\n}\n","import type {\n AnyCircuitElement,\n PcbTraceMissingError,\n SourceTrace,\n PcbTrace,\n PcbPort,\n} from \"circuit-json\"\n\n/**\n * Check that each source_trace which connects source ports has at least one\n * pcb_trace associated with it. If a source_trace has no corresponding\n * pcb_trace, return an error for that source_trace.\n */\nfunction checkSourceTracesHavePcbTraces(\n circuitJson: AnyCircuitElement[],\n): PcbTraceMissingError[] {\n const errors: PcbTraceMissingError[] = []\n const sourceTraces = circuitJson.filter(\n (el) => el.type === \"source_trace\",\n ) as SourceTrace[]\n const pcbTraces = circuitJson.filter(\n (el) => el.type === \"pcb_trace\",\n ) as PcbTrace[]\n\n for (const sourceTrace of sourceTraces) {\n if (!sourceTrace.connected_source_port_ids?.length) continue\n const hasPcbTrace = pcbTraces.some(\n (pcbTrace) => pcbTrace.source_trace_id === sourceTrace.source_trace_id,\n )\n if (!hasPcbTrace) {\n // Get PCB ports connected to this source trace\n const connectedPcbPorts = circuitJson.filter(\n (el) =>\n el.type === \"pcb_port\" &&\n sourceTrace.connected_source_port_ids.includes(el.source_port_id),\n ) as PcbPort[]\n\n // Find PCB components that these ports belong to\n const connectedPcbComponentIds = Array.from(\n new Set(\n connectedPcbPorts\n .map((port) => port.pcb_component_id)\n .filter((id): id is string => id !== undefined),\n ),\n )\n\n errors.push({\n type: \"pcb_trace_missing_error\",\n pcb_trace_missing_error_id: `pcb_trace_missing_${sourceTrace.source_trace_id}`,\n error_type: \"pcb_trace_missing_error\",\n message: `Trace [${sourceTrace.display_name ?? sourceTrace.source_trace_id}] is not connected (it has no PCB trace)`,\n source_trace_id: sourceTrace.source_trace_id,\n pcb_component_ids: connectedPcbComponentIds,\n pcb_port_ids: connectedPcbPorts.map((port) => port.pcb_port_id),\n })\n }\n }\n\n return errors\n}\n\nexport { checkSourceTracesHavePcbTraces }\n","import type {\n AnyCircuitElement,\n PcbBoard,\n PcbTrace,\n PcbTraceError,\n} from \"circuit-json\"\nimport { cju } from \"@tscircuit/circuit-json-util\"\nimport type { Point, Polygon } from \"@tscircuit/math-utils\"\nimport { segmentToSegmentMinDistance } from \"@tscircuit/math-utils\"\n\n/**\n * Default margin for trace clearance from board edge (in mm)\n */\nconst DEFAULT_BOARD_MARGIN = 0.2\n\n/**\n * Configuration for trace board boundary checking\n */\nexport interface TraceBoardCheckConfig {\n /** Minimum distance from trace center to board edge (in mm) */\n margin?: number\n}\n\n/**\n * Create a board polygon representation using math-utils Polygon type\n */\nfunction getBoardPolygonPoints(board: PcbBoard): Polygon | null {\n if (board.outline && board.outline.length > 0) {\n // Use custom board outline\n return board.outline.map((p) => ({ x: p.x, y: p.y }))\n }\n\n if (\n board.center &&\n typeof board.width === \"number\" &&\n typeof board.height === \"number\"\n ) {\n // Create rectangular board outline\n const cx = board.center.x\n const cy = board.center.y\n const hw = board.width / 2\n const hh = board.height / 2\n\n return [\n { x: cx - hw, y: cy - hh }, // bottom-left\n { x: cx + hw, y: cy - hh }, // bottom-right\n { x: cx + hw, y: cy + hh }, // top-right\n { x: cx - hw, y: cy + hh }, // top-left\n ]\n }\n\n return null\n}\n\n/**\n * Check if any trace segment is too close to or outside the board outline\n * Uses segment-to-polygon distance with configurable margin\n */\nexport function checkPcbTracesOutOfBoard(\n circuitJson: AnyCircuitElement[],\n config: TraceBoardCheckConfig = {},\n): PcbTraceError[] {\n const errors: PcbTraceError[] = []\n const margin = config.margin ?? DEFAULT_BOARD_MARGIN\n\n // Find the board\n const board = circuitJson.find(\n (el): el is PcbBoard => el.type === \"pcb_board\",\n )\n if (!board) return errors\n\n // Create board polygon using math-utils Point type\n const boardPoints = getBoardPolygonPoints(board)\n if (!boardPoints) return errors\n\n // Get all PCB traces\n const pcbTraces = cju(circuitJson).pcb_trace.list()\n\n for (const trace of pcbTraces) {\n if (trace.route.length < 2) continue\n\n // Check each segment of the trace\n for (let i = 0; i < trace.route.length - 1; i++) {\n const p1 = trace.route[i]\n const p2 = trace.route[i + 1]\n\n // Only check wire segments\n if (p1.route_type !== \"wire\" || p2.route_type !== \"wire\") continue\n\n const traceWidth =\n \"width\" in p1 ? p1.width : \"width\" in p2 ? p2.width : 0.1\n const segmentStart: Point = { x: p1.x, y: p1.y }\n const segmentEnd: Point = { x: p2.x, y: p2.y }\n\n // Calculate minimum distance from trace segment to board polygon\n let minDistance = Infinity\n for (let j = 0; j < boardPoints.length; j++) {\n const edgeStart = boardPoints[j]\n const edgeEnd = boardPoints[(j + 1) % boardPoints.length]\n const distance = segmentToSegmentMinDistance(\n segmentStart,\n segmentEnd,\n edgeStart,\n edgeEnd,\n )\n if (distance < minDistance) {\n minDistance = distance\n }\n }\n\n const minimumDistance = traceWidth / 2 + margin\n\n if (minDistance < minimumDistance) {\n const error: PcbTraceError = {\n type: \"pcb_trace_error\",\n error_type: \"pcb_trace_error\",\n pcb_trace_error_id: `trace_too_close_to_board_${trace.pcb_trace_id}_segment_${i}`,\n message: `Trace too close to board edge (${minDistance.toFixed(3)}mm < ${minimumDistance.toFixed(3)}mm required, margin: ${margin}mm)`,\n pcb_trace_id: trace.pcb_trace_id,\n source_trace_id: trace.source_trace_id || \"\",\n center: {\n x: (segmentStart.x + segmentEnd.x) / 2,\n y: (segmentStart.y + segmentEnd.y) / 2,\n },\n pcb_component_ids: [],\n pcb_port_ids: [],\n }\n errors.push(error)\n }\n }\n }\n\n return errors\n}\n","import type {\n AnyCircuitElement,\n PcbFootprintOverlapError,\n PcbSmtPad,\n PcbPlatedHole,\n PcbHole,\n PcbComponent,\n} from \"circuit-json\"\nimport {\n cju,\n getBoundsOfPcbElements,\n getPrimaryId,\n} from \"@tscircuit/circuit-json-util\"\nimport { doBoundsOverlap } from \"@tscircuit/math-utils\"\nimport {\n getFullConnectivityMapFromCircuitJson,\n type ConnectivityMap,\n} from \"circuit-json-to-connectivity-map\"\n\ntype OverlappableElement = PcbSmtPad | PcbPlatedHole | PcbHole\n\ninterface ComponentWithElements {\n component_id: string\n elements: OverlappableElement[]\n bounds: {\n minX: number\n minY: number\n maxX: number\n maxY: number\n }\n}\n\n/**\n * Check if two PCB elements overlap\n * Currently uses simple bounds overlap, but can be extended to handle\n * more precise overlap detection for rotated rects, pills, circles, etc.\n */\nfunction doPcbElementsOverlap(\n elem1: OverlappableElement,\n elem2: OverlappableElement,\n): boolean {\n const bounds1 = getBoundsOfPcbElements([elem1])\n const bounds2 = getBoundsOfPcbElements([elem2])\n return doBoundsOverlap(bounds1, bounds2)\n}\n\n/**\n * Check for overlapping PCB components\n * Returns errors for components that overlap inappropriately\n */\nexport function checkPcbComponentOverlap(\n circuitJson: AnyCircuitElement[],\n): PcbFootprintOverlapError[] {\n const errors: PcbFootprintOverlapError[] = []\n\n // Build connectivity map to check if components are electrically connected\n const connMap = getFullConnectivityMapFromCircuitJson(circuitJson)\n\n // Get all overlappable elements\n const smtPads = cju(circuitJson).pcb_smtpad.list()\n const platedHoles = cju(circuitJson).pcb_plated_hole.list()\n const holes = cju(circuitJson).pcb_hole.list()\n\n // Group elements by component (or treat standalone elements as their own \"component\")\n const componentMap = new Map<string, ComponentWithElements>()\n\n // Group SMT pads by component (or treat as standalone)\n for (const pad of smtPads) {\n const componentId =\n pad.pcb_component_id || `standalone_pad_${getPrimaryId(pad)}`\n if (!componentMap.has(componentId)) {\n componentMap.set(componentId, {\n component_id: componentId,\n elements: [],\n bounds: { minX: 0, minY: 0, maxX: 0, maxY: 0 },\n })\n }\n componentMap.get(componentId)!.elements.push(pad)\n }\n\n // Group plated holes by component (or treat as standalone)\n for (const hole of platedHoles) {\n const componentId =\n hole.pcb_component_id || `standalone_plated_hole_${getPrimaryId(hole)}`\n if (!componentMap.has(componentId)) {\n componentMap.set(componentId, {\n component_id: componentId,\n elements: [],\n bounds: { minX: 0, minY: 0, maxX: 0, maxY: 0 },\n })\n }\n componentMap.get(componentId)!.elements.push(hole)\n }\n\n // Holes typically don't have pcb_component_id, treat each as standalone\n for (const hole of holes) {\n const componentId = `standalone_hole_${getPrimaryId(hole)}`\n componentMap.set(componentId, {\n component_id: componentId,\n elements: [hole],\n bounds: { minX: 0, minY: 0, maxX: 0, maxY: 0 },\n })\n }\n\n // Compute bounds for each component\n for (const [componentId, componentData] of componentMap) {\n if (componentData.elements.length > 0) {\n componentData.bounds = getBoundsOfPcbElements(componentData.elements)\n }\n }\n\n // Convert map to array for pairwise iteration\n const componentsWithElements = Array.from(componentMap.values())\n\n // Pairwise check: only check elements if component bounds overlap\n for (let i = 0; i < componentsWithElements.length; i++) {\n for (let j = i + 1; j < componentsWithElements.length; j++) {\n const comp1 = componentsWithElements[i]\n const comp2 = componentsWithElements[j]\n\n // First check if component bounds overlap\n if (!doBoundsOverlap(comp1.bounds, comp2.bounds)) {\n continue\n }\n\n // Component bounds overlap, now check individual elements\n for (const elem1 of comp1.elements) {\n for (const elem2 of comp2.elements) {\n const id1 = getPrimaryId(elem1)\n const id2 = getPrimaryId(elem2)\n\n // Check if both are SMT pads and are electrically connected (same net) - if so, skip\n // This allows pads with the same subcircuit connectivity to be in contact\n if (\n elem1.type === \"pcb_smtpad\" &&\n elem2.type === \"pcb_smtpad\" &&\n connMap.areIdsConnected(id1, id2)\n ) {\n continue\n }\n\n // Check if element bounds overlap\n if (doPcbElementsOverlap(elem1, elem2)) {\n // Create error object\n const error: PcbFootprintOverlapError = {\n type: \"pcb_footprint_overlap_error\",\n pcb_error_id: `pcb_footprint_overlap_${id1}_${id2}`,\n error_type: \"pcb_footprint_overlap_error\",\n message: `PCB component ${elem1.type} \"${id1}\" overlaps with ${elem2.type} \"${id2}\"`,\n }\n\n // Add relevant IDs based on element types\n if (elem1.type === \"pcb_smtpad\" || elem2.type === \"pcb_smtpad\") {\n error.pcb_smtpad_ids = []\n if (elem1.type === \"pcb_smtpad\") error.pcb_smtpad_ids.push(id1)\n if (elem2.type === \"pcb_smtpad\") error.pcb_smtpad_ids.push(id2)\n }\n\n if (\n elem1.type === \"pcb_plated_hole\" ||\n elem2.type === \"pcb_plated_hole\"\n ) {\n error.pcb_plated_hole_ids = []\n if (elem1.type === \"pcb_plated_hole\")\n error.pcb_plated_hole_ids.push(id1)\n if (elem2.type === \"pcb_plated_hole\")\n error.pcb_plated_hole_ids.push(id2)\n }\n\n if (elem1.type === \"pcb_hole\" || elem2.type === \"pcb_hole\") {\n error.pcb_hole_ids = []\n if (elem1.type === \"pcb_hole\") error.pcb_hole_ids.push(id1)\n if (elem2.type === \"pcb_hole\") error.pcb_hole_ids.push(id2)\n }\n\n errors.push(error)\n }\n }\n }\n }\n }\n\n return errors\n}\n","import type { PcbSmtPad, PcbPlatedHole } from \"circuit-json\"\n\nfunction distance(x1: number, y1: number, x2: number, y2: number): number {\n return Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)\n}\n\nexport function isPointInPad(\n point: { x: number; y: number },\n pad: PcbSmtPad | PcbPlatedHole,\n): boolean {\n if (pad.type === \"pcb_smtpad\") {\n if (pad.shape === \"circle\") {\n return distance(point.x, point.y, pad.x, pad.y) <= pad.radius\n }\n\n if (pad.shape === \"rect\") {\n const halfWidth = pad.width / 2\n const halfHeight = pad.height / 2\n return (\n Math.abs(point.x - pad.x) <= halfWidth &&\n Math.abs(point.y - pad.y) <= halfHeight\n )\n }\n\n if (pad.shape === \"rotated_rect\") {\n const dx = point.x - pad.x\n const dy = point.y - pad.y\n const angle = -pad.ccw_rotation\n const rotatedX = dx * Math.cos(angle) - dy * Math.sin(angle)\n const rotatedY = dx * Math.sin(angle) + dy * Math.cos(angle)\n return (\n Math.abs(rotatedX) <= pad.width / 2 &&\n Math.abs(rotatedY) <= pad.height / 2\n )\n }\n\n if (pad.shape === \"pill\") {\n const halfWidth = pad.width / 2\n const halfHeight = pad.height / 2\n const radius = pad.radius\n\n if (\n Math.abs(point.x - pad.x) <= halfWidth - radius &&\n Math.abs(point.y - pad.y) <= halfHeight\n ) {\n return true\n }\n\n const cornerX = Math.max(\n Math.abs(point.x - pad.x) - (halfWidth - radius),\n 0,\n )\n const cornerY = Math.max(\n Math.abs(point.y - pad.y) - (halfHeight - radius),\n 0,\n )\n return cornerX * cornerX + cornerY * cornerY <= radius * radius\n }\n }\n\n if (pad.type === \"pcb_plated_hole\") {\n if (pad.shape === \"circle\") {\n return distance(point.x, point.y, pad.x, pad.y) <= pad.outer_diameter / 2\n }\n\n if (pad.shape === \"oval\" || pad.shape === \"pill\") {\n return (\n Math.abs(point.x - pad.x) <= pad.outer_width / 2 &&\n Math.abs(point.y - pad.y) <= pad.outer_height / 2\n )\n }\n\n if (pad.shape === \"circular_hole_with_rect_pad\") {\n return (\n Math.abs(point.x - pad.x) <= pad.rect_pad_width / 2 &&\n Math.abs(point.y - pad.y) <= pad.rect_pad_height / 2\n )\n }\n\n if (pad.shape === \"pill_hole_with_rect_pad\") {\n return (\n Math.abs(point.x - pad.x) <= pad.rect_pad_width / 2 &&\n Math.abs(point.y - pad.y) <= pad.rect_pad_height / 2\n )\n }\n }\n\n return false\n}\n","import type {\n AnyCircuitElement,\n PcbTraceError,\n PcbPort,\n PcbTrace,\n SourceTrace,\n PcbSmtPad,\n PcbPlatedHole,\n} from \"circuit-json\"\nimport { isPointInPad } from \"./is-point-in-pad\"\nimport { getReadableNameForPcbPort } from \"@tscircuit/circuit-json-util\"\n\nfunction checkTracesAreContiguous(\n circuitJson: AnyCircuitElement[],\n): PcbTraceError[] {\n const errors: PcbTraceError[] = []\n\n const pcbPorts = circuitJson.filter(\n (el) => el.type === \"pcb_port\",\n ) as PcbPort[]\n const pcbTraces = circuitJson.filter(\n (el) => el.type === \"pcb_trace\",\n ) as PcbTrace[]\n const sourceTraces = circuitJson.filter(\n (el) => el.type === \"source_trace\",\n ) as SourceTrace[]\n const pcbSmtPads = circuitJson.filter(\n (el) => el.type === \"pcb_smtpad\",\n ) as PcbSmtPad[]\n const pcbPlatedHoles = circuitJson.filter(\n (el) => el.type === \"pcb_plated_hole\",\n ) as PcbPlatedHole[]\n\n const padMap = new Map<string, PcbSmtPad | PcbPlatedHole>()\n\n for (const pad of pcbSmtPads) {\n if (pad.pcb_port_id) {\n padMap.set(pad.pcb_port_id, pad)\n }\n }\n\n for (const hole of pcbPlatedHoles) {\n if (hole.pcb_port_id) {\n padMap.set(hole.pcb_port_id, hole)\n }\n }\n\n for (const trace of pcbTraces) {\n if (trace.route.length === 0) continue\n\n const firstPoint = trace.route[0]\n const lastPoint = trace.route[trace.route.length - 1]\n\n const sourceTrace = sourceTraces.find(\n (st) => st.source_trace_id === trace.source_trace_id,\n )\n\n const expectedPorts = sourceTrace\n ? pcbPorts.filter((port) =>\n sourceTrace.connected_source_port_ids?.includes(port.source_port_id),\n )\n : []\n\n for (let i = 1; i < trace.route.length - 1; i++) {\n const prevPoint = trace.route[i - 1]\n const currentPoint = trace.route[i]\n const nextPoint = trace.route[i + 1]\n\n if (currentPoint.route_type === \"via\") {\n const prevIsWire = prevPoint.route_type === \"wire\"\n const nextIsWire = nextPoint.route_type === \"wire\"\n\n if (prevIsWire && nextIsWire) {\n const prevAligned =\n Math.abs(prevPoint.x - currentPoint.x) < 0.001 &&\n Math.abs(prevPoint.y - currentPoint.y) < 0.001\n\n const nextAligned =\n Math.abs(nextPoint.x - currentPoint.x) < 0.001 &&\n Math.abs(nextPoint.y - currentPoint.y) < 0.001\n\n if (!prevAligned || !nextAligned) {\n const traceName =\n sourceTrace?.display_name || trace.source_trace_id || \"unknown\"\n errors.push({\n type: \"pcb_trace_error\",\n message: `Via in trace [${traceName}] is misaligned at position {x: ${currentPoint.x}, y: ${currentPoint.y}}.`,\n source_trace_id:\n sourceTrace?.source_trace_id ||\n trace.source_trace_id ||\n `!${trace.pcb_trace_id}`,\n error_type: \"pcb_trace_error\",\n pcb_trace_id: trace.pcb_trace_id,\n pcb_trace_error_id: \"\",\n pcb_component_ids: [],\n pcb_port_ids: [],\n })\n }\n }\n }\n }\n\n const traceName =\n sourceTrace?.display_name || trace.source_trace_id || \"unknown\"\n\n // For traces with known expected ports, check specific connections\n for (const port of expectedPorts) {\n if (!port.pcb_port_id) continue\n\n const pad = padMap.get(port.pcb_port_id)\n\n if (!pad) continue\n\n const isFirstPointConnected =\n firstPoint.route_type === \"wire\" &&\n isPointInPad({ x: firstPoint.x, y: firstPoint.y }, pad)\n\n const isLastPointConnected =\n lastPoint.route_type === \"wire\" &&\n isPointInPad({ x: lastPoint.x, y: lastPoint.y }, pad)\n\n if (!isFirstPointConnected && !isLastPointConnected) {\n const portName = getReadableNameForPcbPort(\n circuitJson,\n port.pcb_port_id,\n ).replace(\"pcb_port\", \"\")\n const padType = pad.type.replace(/pcb_/, \"\")\n // Use the midpoint between trace endpoints as error location\n const errorCenter = {\n x: (firstPoint.x + lastPoint.x) / 2,\n y: (firstPoint.y + lastPoint.y) / 2,\n }\n errors.push({\n type: \"pcb_trace_error\",\n message: `Trace [${traceName}] is missing a connection to ${padType}${portName}`,\n source_trace_id:\n sourceTrace?.source_trace_id ||\n trace.source_trace_id ||\n `!${trace.pcb_trace_id}`,\n error_type: \"pcb_trace_error\",\n pcb_trace_id: trace.pcb_trace_id,\n pcb_trace_error_id: \"\",\n center: errorCenter,\n pcb_component_ids: [],\n pcb_port_ids: [port.pcb_port_id],\n })\n }\n }\n\n // For net-level traces (no expected ports), check if endpoints are floating\n if (expectedPorts.length === 0) {\n let firstConnectsToAnyPad = false\n let lastConnectsToAnyPad = false\n\n for (const [portId, pad] of padMap) {\n if (\n firstPoint.route_type === \"wire\" &&\n isPointInPad({ x: firstPoint.x, y: firstPoint.y }, pad)\n ) {\n firstConnectsToAnyPad = true\n }\n if (\n lastPoint.route_type === \"wire\" &&\n isPointInPad({ x: lastPoint.x, y: lastPoint.y }, pad)\n ) {\n lastConnectsToAnyPad = true\n }\n }\n\n if (!firstConnectsToAnyPad && firstPoint.route_type === \"wire\") {\n errors.push({\n type: \"pcb_trace_error\",\n message: `Trace [${traceName}] has disconnected endpoint at (${firstPoint.x}, ${firstPoint.y})`,\n source_trace_id:\n sourceTrace?.source_trace_id ||\n trace.source_trace_id ||\n `!${trace.pcb_trace_id}`,\n error_type: \"pcb_trace_error\",\n pcb_trace_id: trace.pcb_trace_id,\n pcb_trace_error_id: \"\",\n center: { x: firstPoint.x, y: firstPoint.y },\n pcb_component_ids: [],\n pcb_port_ids: [],\n })\n }\n if (!lastConnectsToAnyPad && lastPoint.route_type === \"wire\") {\n errors.push({\n type: \"pcb_trace_error\",\n message: `Trace [${traceName}] has disconnected endpoint at (${lastPoint.x}, ${lastPoint.y})`,\n source_trace_id:\n sourceTrace?.source_trace_id ||\n trace.source_trace_id ||\n `!${trace.pcb_trace_id}`,\n error_type: \"pcb_trace_error\",\n pcb_trace_id: trace.pcb_trace_id,\n pcb_trace_error_id: \"\",\n center: { x: lastPoint.x, y: lastPoint.y },\n pcb_component_ids: [],\n pcb_port_ids: [],\n })\n }\n }\n }\n\n return errors\n}\n\nexport { checkTracesAreContiguous }\n","import { checkEachPcbPortConnectedToPcbTraces } from \"./check-each-pcb-port-connected-to-pcb-trace\"\nimport { checkEachPcbTraceNonOverlapping } from \"./check-each-pcb-trace-non-overlapping/check-each-pcb-trace-non-overlapping\"\nimport { checkSameNetViaSpacing } from \"./check-same-net-via-spacing\"\nimport { checkDifferentNetViaSpacing } from \"./check-different-net-via-spacing\"\nimport { checkViasOffBoard } from \"./check-pcb-components-out-of-board/checkViasOffBoard\"\nimport { checkPcbComponentsOutOfBoard } from \"./check-pcb-components-out-of-board/checkPcbComponentsOutOfBoard\"\nimport { checkTracesAreContiguous } from \"./check-traces-are-contiguous/check-traces-are-contiguous\"\nimport { checkSourceTracesHavePcbTraces } from \"./check-source-traces-have-pcb-traces\"\nimport { checkPcbTracesOutOfBoard } from \"./check-trace-out-of-board/checkTraceOutOfBoard\"\nimport { checkPcbComponentOverlap } from \"./check-pcb-components-overlap/checkPcbComponentOverlap\"\nimport type { AnyCircuitElement } from \"circuit-json\"\n\nexport async function runAllChecks(circuitJson: AnyCircuitElement[]) {\n return [\n ...checkEachPcbPortConnectedToPcbTraces(circuitJson),\n ...checkEachPcbTraceNonOverlapping(circuitJson),\n ...checkSameNetViaSpacing(circuitJson),\n ...checkDifferentNetViaSpacing(circuitJson),\n ...checkViasOffBoard(circuitJson),\n ...checkPcbComponentsOutOfBoard(circuitJson),\n ...checkTracesAreContiguous(circuitJson),\n ...checkSourceTracesHavePcbTraces(circuitJson),\n ...checkPcbTracesOutOfBoard(circuitJson),\n ...checkPcbComponentOverlap(circuitJson),\n ]\n}\n"],"mappings":"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","names":["getFullConnectivityMapFromCircuitJson","t","closestOnB","closestOnA","distance","clamp","dx","dy","getFullConnectivityMapFromCircuitJson","gap","distance","getReadableNameForElement","getReadableNameForElement","getReadableNameForElement","getReadableNameForElement","getFullConnectivityMapFromCircuitJson","distance","getFullConnectivityMapFromCircuitJson","getReadableNameForElement","getReadableNameForElement","getFullConnectivityMapFromCircuitJson","distance","getFullConnectivityMapFromCircuitJson","getReadableNameForElement","cju","segmentToSegmentMinDistance","distance","cju","getBoundsOfPcbElements","getPrimaryId","getFullConnectivityMapFromCircuitJson","distance","traceName"]}
1
+ {"version":3,"sources":["../lib/add-start-and-end-port-ids-if-missing.ts","../lib/check-each-pcb-port-connected-to-pcb-trace.ts","../lib/check-each-pcb-trace-non-overlapping/check-each-pcb-trace-non-overlapping.ts","../lib/data-structures/SpatialIndex.ts","../lib/check-each-pcb-trace-non-overlapping/getCollidableBounds.ts","../lib/drc-defaults.ts","../lib/check-each-pcb-trace-non-overlapping/getPcbPortIdsConnectedToTraces.ts","../lib/check-each-pcb-trace-non-overlapping/getClosestPointBetweenSegments.ts","../lib/check-each-pcb-trace-non-overlapping/getRadiusOfCircuitJsonElement.ts","../lib/check-each-pcb-trace-non-overlapping/getClosestPointBetweenSegmentAndBounds.ts","../lib/util/getLayersOfPcbElement.ts","../lib/net-manager.ts","../lib/check-pcb-components-out-of-board/checkViasOffBoard.ts","../lib/check-pcb-components-out-of-board/checkPcbComponentsOutOfBoard.ts","../lib/check-same-net-via-spacing.ts","../lib/check-different-net-via-spacing.ts","../lib/check-source-traces-have-pcb-traces.ts","../lib/check-trace-out-of-board/checkTraceOutOfBoard.ts","../lib/check-pcb-components-overlap/checkPcbComponentOverlap.ts","../lib/check-pin-must-be-connected.ts","../lib/check-traces-are-contiguous/is-point-in-pad.ts","../lib/check-traces-are-contiguous/check-traces-are-contiguous.ts","../lib/run-all-checks.ts"],"sourcesContent":["import type {\n PcbPort,\n PcbTrace,\n AnyCircuitElement,\n PcbSmtPad,\n} from \"circuit-json\"\n\nfunction distance(x1: number, y1: number, x2: number, y2: number): number {\n return Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)\n}\n\n/**\n * HACK: this whole method and all usage of it is a hack because of this issue:\n * https://github.com/tscircuit/tscircuit/issues/291\n */\nexport const addStartAndEndPortIdsIfMissing = (\n soup: AnyCircuitElement[],\n): void => {\n const pcbPorts: PcbPort[] = soup.filter((item) => item.type === \"pcb_port\")\n const pcbSmtPads: PcbSmtPad[] = soup.filter(\n (item) => item.type === \"pcb_smtpad\",\n )\n const pcbTraces: PcbTrace[] = soup.filter((item) => item.type === \"pcb_trace\")\n\n function findPortIdOverlappingPoint(\n point: {\n x: number\n y: number\n },\n options: { isFirstOrLastPoint?: boolean; traceWidth?: number } = {},\n ): string | null {\n const traceWidth = options.traceWidth || 0\n const directPort = pcbPorts.find(\n (port) => distance(port.x, port.y, point.x, point.y) < 0.01,\n )\n if (directPort) return directPort.pcb_port_id\n\n // If it starts or ends inside an smtpad, we'll connect it to the por\n if (options.isFirstOrLastPoint) {\n const smtPad = pcbSmtPads.find((pad) => {\n if (pad.shape === \"rect\") {\n return (\n Math.abs(point.x - pad.x) < pad.width / 2 + traceWidth / 2 &&\n Math.abs(point.y - pad.y) < pad.height / 2 + traceWidth / 2\n )\n // biome-ignore lint/style/noUselessElse: <explanation>\n } else if (pad.shape === \"circle\") {\n return distance(point.x, point.y, pad.x, pad.y) < pad.radius\n }\n })\n if (smtPad) return smtPad.pcb_port_id ?? null\n }\n\n return null\n }\n\n // Add start_pcb_port_id and end_pcb_port_id if not present\n for (const trace of pcbTraces) {\n for (let index = 0; index < trace.route.length; index++) {\n const segment = trace.route[index]\n const isFirstOrLastPoint = index === 0 || index === trace.route.length - 1\n if (segment.route_type === \"wire\") {\n if (!segment.start_pcb_port_id && index === 0) {\n const startPortId = findPortIdOverlappingPoint(segment, {\n isFirstOrLastPoint,\n traceWidth: segment.width,\n })\n if (startPortId) {\n segment.start_pcb_port_id = startPortId\n }\n }\n if (!segment.end_pcb_port_id && index === trace.route.length - 1) {\n const endPortId = findPortIdOverlappingPoint(segment, {\n isFirstOrLastPoint,\n traceWidth: segment.width,\n })\n if (endPortId) {\n segment.end_pcb_port_id = endPortId\n }\n }\n }\n }\n }\n}\n","import type {\n PcbPort,\n SourceTrace,\n AnyCircuitElement,\n PcbPortNotConnectedError,\n} from \"circuit-json\"\nimport { addStartAndEndPortIdsIfMissing } from \"./add-start-and-end-port-ids-if-missing\"\nimport { getFullConnectivityMapFromCircuitJson } from \"circuit-json-to-connectivity-map\"\n\nfunction checkEachPcbPortConnectedToPcbTraces(\n circuitJson: AnyCircuitElement[],\n): PcbPortNotConnectedError[] {\n addStartAndEndPortIdsIfMissing(circuitJson)\n const sourceTraces: SourceTrace[] = circuitJson.filter(\n (item) => item.type === \"source_trace\",\n ) as SourceTrace[]\n\n const pcbPorts: PcbPort[] = circuitJson.filter(\n (item) => item.type === \"pcb_port\",\n ) as PcbPort[]\n\n const errors: PcbPortNotConnectedError[] = []\n\n // Generate the connectivity map from the circuit\n const connectivityMap = getFullConnectivityMapFromCircuitJson(circuitJson)\n\n // Create a map from source_port_id to pcb_port for quick lookup\n const sourcePortToPcbPort = new Map<string, PcbPort>()\n for (const pcbPort of pcbPorts) {\n sourcePortToPcbPort.set(pcbPort.source_port_id, pcbPort)\n }\n\n // Process each source trace\n for (const sourceTrace of sourceTraces) {\n const connectedSourcePortIds = sourceTrace.connected_source_port_ids\n\n // Skip traces with less than 2 ports (nothing to connect)\n if (connectedSourcePortIds.length < 2) {\n continue\n }\n\n // Find corresponding PCB ports for all source ports in this trace\n const pcbPortsInTrace: PcbPort[] = []\n const missingPcbPorts: string[] = []\n\n for (const sourcePortId of connectedSourcePortIds) {\n const pcbPort = sourcePortToPcbPort.get(sourcePortId)\n if (pcbPort) {\n pcbPortsInTrace.push(pcbPort)\n } else {\n missingPcbPorts.push(sourcePortId)\n }\n }\n\n // Skip if we don't have at least 2 PCB ports to connect\n if (pcbPortsInTrace.length < 2) {\n continue\n }\n\n // Get the net ID for the first PCB port as reference\n const firstPcbPort = pcbPortsInTrace[0]\n const referenceNetId = connectivityMap.getNetConnectedToId(\n firstPcbPort.pcb_port_id,\n )\n\n const netElementIds = connectivityMap.getIdsConnectedToNet(referenceNetId!)\n const pcbTraceIds = netElementIds.filter((id) =>\n circuitJson.some(\n (element) =>\n element.type === \"pcb_trace\" &&\n ((\"pcb_trace_id\" in element && element.pcb_trace_id === id) ||\n (\"route_id\" in element && element.route_id === id)),\n ),\n )\n\n if (pcbTraceIds.length === 0) {\n // Check if this is a trivial case (only 2 ports on same component)\n const uniqueComponentIds = new Set(\n pcbPortsInTrace.map((p) => p.pcb_component_id),\n )\n\n if (uniqueComponentIds.size > 1) {\n // Ports are on different components but no PCB traces connect them\n errors.push({\n type: \"pcb_port_not_connected_error\",\n message: `pcb_port_not_connected_error: Pcb ports [${pcbPortsInTrace.map((p) => p.pcb_port_id).join(\", \")}] are not connected together through the same net.`,\n error_type: \"pcb_port_not_connected_error\",\n pcb_port_ids: pcbPortsInTrace.map((p) => p.pcb_port_id),\n pcb_component_ids: pcbPortsInTrace\n .map((p) => p.pcb_component_id)\n .filter((id): id is string => id !== undefined),\n pcb_port_not_connected_error_id: `pcb_port_not_connected_error_trace_${sourceTrace.source_trace_id}`,\n })\n }\n }\n }\n\n return errors\n}\n\nexport { checkEachPcbPortConnectedToPcbTraces }\n","import type { AnyCircuitElement, PcbTraceError } from \"circuit-json\"\nimport { getReadableNameForElement, cju } from \"@tscircuit/circuit-json-util\"\nimport {\n SpatialObjectIndex,\n type Bounds,\n} from \"lib/data-structures/SpatialIndex\"\nimport {\n getFullConnectivityMapFromCircuitJson,\n type ConnectivityMap,\n} from \"circuit-json-to-connectivity-map\"\nimport {\n getCollidableBounds,\n type Collidable,\n type PcbTraceSegment,\n} from \"./getCollidableBounds\"\nimport {\n segmentToBoundsMinDistance,\n segmentToCircleMinDistance,\n} from \"@tscircuit/math-utils\"\nimport {\n DEFAULT_TRACE_MARGIN,\n DEFAULT_TRACE_THICKNESS,\n EPSILON,\n} from \"lib/drc-defaults\"\nimport { getPcbPortIdsConnectedToTraces } from \"./getPcbPortIdsConnectedToTraces\"\nimport { segmentToSegmentMinDistance } from \"@tscircuit/math-utils\"\nimport { areBoundsOverlapping } from \"./areBoundsOverlapping\"\nimport { getPrimaryId } from \"@tscircuit/circuit-json-util\"\nimport { getCenterOfBoundsPair } from \"./getCenterOfBoundsPair\"\nimport { getClosestPointBetweenSegments } from \"./getClosestPointBetweenSegments\"\nimport { getCenterOfBounds } from \"./getCenterOfBounds\"\nimport { getRadiusOfCircuitJsonElement } from \"./getRadiusOfCircuitJsonElement\"\nimport { getClosestPointBetweenSegmentAndBounds } from \"./getClosestPointBetweenSegmentAndBounds\"\nimport { getLayersOfPcbElement } from \"../util/getLayersOfPcbElement\"\nimport { addStartAndEndPortIdsIfMissing } from \"lib/add-start-and-end-port-ids-if-missing\"\n\nexport function checkEachPcbTraceNonOverlapping(\n circuitJson: AnyCircuitElement[],\n {\n connMap,\n }: {\n connMap?: ConnectivityMap\n } = {},\n): PcbTraceError[] {\n const errors: PcbTraceError[] = []\n addStartAndEndPortIdsIfMissing(circuitJson)\n connMap ??= getFullConnectivityMapFromCircuitJson(circuitJson)\n\n const pcbTraces = cju(circuitJson).pcb_trace.list()\n const pcbTraceSegments = pcbTraces.flatMap((pcbTrace) => {\n const segments: PcbTraceSegment[] = []\n for (let i = 0; i < pcbTrace.route.length - 1; i++) {\n const p1 = pcbTrace.route[i]\n const p2 = pcbTrace.route[i + 1]\n if (p1.route_type !== \"wire\") continue\n if (p2.route_type !== \"wire\") continue\n if (p1.layer !== p2.layer) continue\n segments.push({\n type: \"pcb_trace_segment\",\n pcb_trace_id: pcbTrace.pcb_trace_id,\n _pcbTrace: pcbTrace,\n thickness:\n \"width\" in p1\n ? p1.width\n : \"width\" in p2\n ? p2.width\n : DEFAULT_TRACE_THICKNESS,\n layer: p1.layer,\n x1: p1.x,\n y1: p1.y,\n x2: p2.x,\n y2: p2.y,\n } as PcbTraceSegment)\n }\n return segments\n })\n const pcbSmtPads = cju(circuitJson).pcb_smtpad.list()\n const pcbPlatedHoles = cju(circuitJson).pcb_plated_hole.list()\n const pcbHoles = cju(circuitJson).pcb_hole.list()\n const pcbVias = cju(circuitJson).pcb_via.list()\n const pcbKeepouts = cju(circuitJson).pcb_keepout.list()\n\n const allObjects: Collidable[] = [\n ...pcbTraceSegments,\n ...pcbSmtPads,\n ...pcbPlatedHoles,\n ...pcbHoles,\n ...pcbVias,\n ...pcbKeepouts,\n ]\n\n const spatialIndex = new SpatialObjectIndex<Collidable>({\n objects: allObjects,\n getBounds: getCollidableBounds,\n })\n\n const getReadableName = (id: string) =>\n getReadableNameForElement(circuitJson, id)\n\n const errorIds = new Set<string>()\n\n // For each segment, check it if overlaps with anything collidable\n for (const segmentA of pcbTraceSegments) {\n const requiredMargin = DEFAULT_TRACE_MARGIN\n const bounds = getCollidableBounds(segmentA)\n const nearbyObjects = spatialIndex.getObjectsInBounds(\n bounds,\n requiredMargin + segmentA.thickness / 2,\n )\n if (segmentA.x1 === segmentA.x2 && segmentA.y1 === segmentA.y2) continue\n\n for (const obj of nearbyObjects) {\n // ignore obstacles not on the trace's layer (except vias)\n if (!getLayersOfPcbElement(obj).includes(segmentA.layer)) {\n continue\n }\n if (obj.type === \"pcb_trace_segment\") {\n const segmentB = obj\n\n if (segmentA.layer !== segmentB.layer) continue\n\n // Check if the segments are overlapping\n if (\n connMap.areIdsConnected(segmentA.pcb_trace_id, segmentB.pcb_trace_id)\n )\n continue\n\n const gap =\n segmentToSegmentMinDistance(\n { x: segmentA.x1, y: segmentA.y1 },\n { x: segmentA.x2, y: segmentA.y2 },\n { x: segmentB.x1, y: segmentB.y1 },\n { x: segmentB.x2, y: segmentB.y2 },\n ) -\n segmentA.thickness / 2 -\n segmentB.thickness / 2\n if (gap > DEFAULT_TRACE_MARGIN - EPSILON) continue\n\n const pcb_trace_error_id = `overlap_${segmentA.pcb_trace_id}_${segmentB.pcb_trace_id}`\n const pcb_trace_error_id_reverse = `overlap_${segmentB.pcb_trace_id}_${segmentA.pcb_trace_id}`\n if (errorIds.has(pcb_trace_error_id)) continue\n if (errorIds.has(pcb_trace_error_id_reverse)) continue\n\n errorIds.add(pcb_trace_error_id)\n errors.push({\n type: \"pcb_trace_error\",\n error_type: \"pcb_trace_error\",\n message: `PCB trace ${getReadableName(segmentA.pcb_trace_id)} overlaps with ${getReadableName(segmentB.pcb_trace_id)} ${gap < 0 ? \"(accidental contact)\" : `(gap: ${gap.toFixed(3)}mm)`}`,\n pcb_trace_id: segmentA.pcb_trace_id,\n source_trace_id: \"\",\n pcb_trace_error_id,\n pcb_component_ids: [],\n center: getClosestPointBetweenSegments(segmentA, segmentB),\n pcb_port_ids: getPcbPortIdsConnectedToTraces([\n segmentA._pcbTrace,\n segmentB._pcbTrace,\n ]),\n })\n continue\n }\n\n const primaryObjId = getPrimaryId(obj as any)\n if (\n connMap.areIdsConnected(\n segmentA.pcb_trace_id,\n \"pcb_trace_id\" in obj ? (obj.pcb_trace_id as string) : primaryObjId,\n )\n )\n continue\n\n const isCircular =\n obj.type === \"pcb_via\" ||\n (obj.type === \"pcb_plated_hole\" && obj.shape === \"circle\") ||\n obj.type === \"pcb_hole\" ||\n (obj.type === \"pcb_smtpad\" && obj.shape === \"circle\")\n\n if (isCircular) {\n const radius = getRadiusOfCircuitJsonElement(obj)\n const distance = segmentToCircleMinDistance(\n { x: segmentA.x1, y: segmentA.y1 },\n { x: segmentA.x2, y: segmentA.y2 },\n { x: obj.x, y: obj.y, radius },\n )\n const gap = distance - segmentA.thickness / 2\n if (gap > DEFAULT_TRACE_MARGIN - EPSILON) continue\n\n const pcb_trace_error_id = `overlap_${segmentA.pcb_trace_id}_${primaryObjId}`\n if (errorIds.has(pcb_trace_error_id)) continue\n errorIds.add(pcb_trace_error_id)\n errors.push({\n type: \"pcb_trace_error\",\n error_type: \"pcb_trace_error\",\n message: `PCB trace ${getReadableName(segmentA.pcb_trace_id)} overlaps with ${obj.type} \"${getReadableName(getPrimaryId(obj as any))}\" ${gap < 0 ? \"(accidental contact)\" : `(gap: ${gap.toFixed(3)}mm)`}`,\n pcb_trace_id: segmentA.pcb_trace_id,\n center: getClosestPointBetweenSegmentAndBounds(\n segmentA,\n getCollidableBounds(obj),\n ),\n source_trace_id: \"\",\n pcb_trace_error_id,\n pcb_component_ids: [\n \"pcb_component_id\" in obj\n ? (obj.pcb_component_id as string)\n : undefined,\n ].filter(Boolean) as string[],\n pcb_port_ids: [\n ...getPcbPortIdsConnectedToTraces([segmentA._pcbTrace]),\n \"pcb_port_id\" in obj ? obj.pcb_port_id : undefined,\n ].filter(Boolean) as string[],\n })\n }\n\n // Handle generic case of hitting the bounds of any collidable obstacle\n // using the bounds of the collidable obstacle\n const gap =\n segmentToBoundsMinDistance(\n { x: segmentA.x1, y: segmentA.y1 },\n { x: segmentA.x2, y: segmentA.y2 },\n getCollidableBounds(obj),\n ) -\n segmentA.thickness / 2\n if (gap + EPSILON < requiredMargin) {\n const pcb_trace_error_id = `overlap_${segmentA.pcb_trace_id}_${primaryObjId}`\n if (errorIds.has(pcb_trace_error_id)) continue\n errorIds.add(pcb_trace_error_id)\n errors.push({\n type: \"pcb_trace_error\",\n error_type: \"pcb_trace_error\",\n message: `PCB trace ${getReadableName(segmentA.pcb_trace_id)} overlaps with ${obj.type} \"${getReadableName(getPrimaryId(obj as any))}\" ${gap < 0 ? \"(accidental contact)\" : `(gap: ${gap.toFixed(3)}mm)`}`,\n pcb_trace_id: segmentA.pcb_trace_id,\n source_trace_id: \"\",\n pcb_trace_error_id,\n pcb_component_ids: [\n \"pcb_component_id\" in obj ? obj.pcb_component_id : undefined,\n ].filter(Boolean) as string[],\n center: getClosestPointBetweenSegmentAndBounds(\n segmentA,\n getCollidableBounds(obj),\n ),\n pcb_port_ids: [\n ...getPcbPortIdsConnectedToTraces([segmentA._pcbTrace]),\n \"pcb_port_id\" in obj ? obj.pcb_port_id : undefined,\n ].filter(Boolean) as string[],\n })\n }\n }\n }\n return errors\n}\n","export type BucketCoordinate = `${number}x${number}`\n\nexport interface Bounds {\n minX: number\n minY: number\n maxX: number\n maxY: number\n}\n\nexport type GetBoundsFn<T> = (obj: T) => Bounds\nexport type GetIdFn<T> = (obj: T) => string\n\nexport class SpatialObjectIndex<T> {\n buckets: Map<BucketCoordinate, Array<T & { spatialIndexId: string }>>\n objectsById: Map<string, T & { spatialIndexId: string }>\n getBounds: GetBoundsFn<T>\n getId: GetIdFn<T>\n CELL_SIZE = 0.4\n\n constructor({\n objects,\n getBounds,\n getId,\n CELL_SIZE,\n }: {\n objects: T[]\n getBounds: GetBoundsFn<T>\n getId?: GetIdFn<T>\n CELL_SIZE?: number\n }) {\n this.buckets = new Map()\n this.objectsById = new Map()\n this.getBounds = getBounds\n this.getId = getId ?? (() => this._getNextId())\n this.CELL_SIZE = CELL_SIZE ?? this.CELL_SIZE\n\n for (const obj of objects) {\n this.addObject(obj)\n }\n }\n\n _idCounter = 0\n _getNextId(): string {\n return `${this._idCounter++}`\n }\n\n addObject(obj: T): void {\n const bounds = this.getBounds(obj)\n const spatialIndexId = this.getId(obj)\n const objWithId = { ...obj, spatialIndexId } as T & {\n spatialIndexId: string\n }\n\n // Store in objectsById for quick lookup\n this.objectsById.set(spatialIndexId, objWithId)\n\n // Calculate the bucket coordinates that cover the object's bounds\n const minBucketX = Math.floor(bounds.minX / this.CELL_SIZE)\n const minBucketY = Math.floor(bounds.minY / this.CELL_SIZE)\n const maxBucketX = Math.floor(bounds.maxX / this.CELL_SIZE)\n const maxBucketY = Math.floor(bounds.maxY / this.CELL_SIZE)\n\n // Add the object to all buckets it intersects with\n for (let bx = minBucketX; bx <= maxBucketX; bx++) {\n for (let by = minBucketY; by <= maxBucketY; by++) {\n const bucketKey = `${bx}x${by}` as BucketCoordinate\n const bucket = this.buckets.get(bucketKey)\n if (!bucket) {\n this.buckets.set(bucketKey, [objWithId])\n } else {\n bucket.push(objWithId)\n }\n }\n }\n }\n\n removeObject(id: string): boolean {\n const obj = this.objectsById.get(id)\n if (!obj) return false\n\n // Remove from objectsById\n this.objectsById.delete(id)\n\n // Calculate the bucket coordinates that cover the object's bounds\n const bounds = this.getBounds(obj)\n const minBucketX = Math.floor(bounds.minX / this.CELL_SIZE)\n const minBucketY = Math.floor(bounds.minY / this.CELL_SIZE)\n const maxBucketX = Math.floor(bounds.maxX / this.CELL_SIZE)\n const maxBucketY = Math.floor(bounds.maxY / this.CELL_SIZE)\n\n // Remove the object from all buckets it might be in\n for (let bx = minBucketX; bx <= maxBucketX; bx++) {\n for (let by = minBucketY; by <= maxBucketY; by++) {\n const bucketKey = `${bx}x${by}` as BucketCoordinate\n const bucket = this.buckets.get(bucketKey)\n if (bucket) {\n const index = bucket.findIndex((item) => item.spatialIndexId === id)\n if (index !== -1) {\n bucket.splice(index, 1)\n if (bucket.length === 0) {\n this.buckets.delete(bucketKey)\n }\n }\n }\n }\n }\n\n return true\n }\n\n getBucketKey(x: number, y: number): BucketCoordinate {\n return `${Math.floor(x / this.CELL_SIZE)}x${Math.floor(y / this.CELL_SIZE)}`\n }\n\n getObjectsInBounds(bounds: Bounds, margin = 0): T[] {\n const objects: T[] = []\n const addedIds = new Set<string>()\n\n // Calculate the bucket coordinates that cover the requested bounds with margin\n const minBucketX = Math.floor((bounds.minX - margin) / this.CELL_SIZE)\n const minBucketY = Math.floor((bounds.minY - margin) / this.CELL_SIZE)\n const maxBucketX = Math.floor((bounds.maxX + margin) / this.CELL_SIZE)\n const maxBucketY = Math.floor((bounds.maxY + margin) / this.CELL_SIZE)\n\n // Collect objects from all buckets that intersect the bounds\n for (let bx = minBucketX; bx <= maxBucketX; bx++) {\n for (let by = minBucketY; by <= maxBucketY; by++) {\n const bucketKey = `${bx}x${by}` as BucketCoordinate\n const bucket = this.buckets.get(bucketKey) || []\n\n for (const obj of bucket) {\n const id = obj.spatialIndexId\n if (addedIds.has(id)) continue\n\n addedIds.add(id)\n objects.push(obj)\n }\n }\n }\n\n return objects\n }\n}\n","import { getBoundsOfPcbElements } from \"@tscircuit/circuit-json-util\"\nimport type {\n AnyCircuitElement,\n PcbHole,\n PCBKeepout,\n PcbPlatedHole,\n PcbSmtPad,\n PcbTrace,\n PcbTraceError,\n PcbVia,\n} from \"circuit-json\"\n\ninterface Bounds {\n minX: number\n minY: number\n maxX: number\n maxY: number\n}\n\nexport type PcbTraceSegment = {\n type: \"pcb_trace_segment\"\n _pcbTrace: PcbTrace\n pcb_trace_id: string\n thickness: number\n layer: string\n x1: number\n y1: number\n x2: number\n y2: number\n}\n\nexport type Collidable =\n | PcbTraceSegment\n | PcbSmtPad\n | PcbPlatedHole\n | PcbHole\n | PcbVia\n | PCBKeepout\n\nexport const getCollidableBounds = (collidable: Collidable): Bounds => {\n if (collidable.type === \"pcb_trace_segment\") {\n return {\n minX: Math.min(collidable.x1, collidable.x2),\n minY: Math.min(collidable.y1, collidable.y2),\n maxX: Math.max(collidable.x1, collidable.x2),\n maxY: Math.max(collidable.y1, collidable.y2),\n }\n }\n return getBoundsOfPcbElements([collidable as any])\n}\n","export const DEFAULT_TRACE_MARGIN = 0.1\nexport const DEFAULT_TRACE_THICKNESS = 0.15\nexport const DEFAULT_VIA_DIAMETER = 0.6\nexport const DEFAULT_VIA_BOARD_MARGIN = 0.3\n\nexport const DEFAULT_SAME_NET_VIA_MARGIN = 0.2\nexport const DEFAULT_DIFFERENT_NET_VIA_MARGIN = 0.3\n\nexport const EPSILON = 0.005\n","import type { PcbTrace } from \"circuit-json\"\n\nexport function getPcbPortIdsConnectedToTrace(trace: PcbTrace) {\n const connectedPcbPorts = new Set<string>()\n for (const segment of trace.route) {\n if (segment.route_type === \"wire\") {\n if (segment.start_pcb_port_id)\n connectedPcbPorts.add(segment.start_pcb_port_id)\n if (segment.end_pcb_port_id)\n connectedPcbPorts.add(segment.end_pcb_port_id)\n }\n }\n\n return Array.from(connectedPcbPorts)\n}\n\nexport function getPcbPortIdsConnectedToTraces(traces: PcbTrace[]) {\n const connectedPorts = new Set<string>()\n for (const trace of traces) {\n for (const portId of getPcbPortIdsConnectedToTrace(trace)) {\n connectedPorts.add(portId)\n }\n }\n return Array.from(connectedPorts)\n}\n","import type { PcbTraceSegment } from \"./getCollidableBounds\"\n\nexport const getClosestPointBetweenSegments = (\n segmentA: PcbTraceSegment,\n segmentB: PcbTraceSegment,\n): { x: number; y: number } => {\n // Define points for each segment\n const a1 = { x: segmentA.x1, y: segmentA.y1 }\n const a2 = { x: segmentA.x2, y: segmentA.y2 }\n const b1 = { x: segmentB.x1, y: segmentB.y1 }\n const b2 = { x: segmentB.x2, y: segmentB.y2 }\n\n // Calculate direction vectors for each segment\n const va = { x: a2.x - a1.x, y: a2.y - a1.y }\n const vb = { x: b2.x - b1.x, y: b2.y - b1.y }\n\n // Calculate squared lengths of segments\n const lenSqrA = va.x * va.x + va.y * va.y\n const lenSqrB = vb.x * vb.x + vb.y * vb.y\n\n // If either segment is a point (zero length), handle as special case\n if (lenSqrA === 0 || lenSqrB === 0) {\n if (lenSqrA === 0 && lenSqrB === 0) {\n // Both segments are points, return the distance between them\n // Calculate the average point\n return {\n x: (a1.x + b1.x) / 2,\n y: (a1.y + b1.y) / 2,\n }\n }\n if (lenSqrA === 0) {\n // First segment is a point, find closest point on second segment\n const t = clamp(\n ((a1.x - b1.x) * vb.x + (a1.y - b1.y) * vb.y) / lenSqrB,\n 0,\n 1,\n )\n const closestOnB = {\n x: b1.x + t * vb.x,\n y: b1.y + t * vb.y,\n }\n // Calculate the average point\n return {\n x: (a1.x + closestOnB.x) / 2,\n y: (a1.y + closestOnB.y) / 2,\n }\n }\n // Second segment is a point, find closest point on first segment\n const t = clamp(\n ((b1.x - a1.x) * va.x + (b1.y - a1.y) * va.y) / lenSqrA,\n 0,\n 1,\n )\n const closestOnA = {\n x: a1.x + t * va.x,\n y: a1.y + t * va.y,\n }\n // Calculate the average point\n return {\n x: (closestOnA.x + b1.x) / 2,\n y: (closestOnA.y + b1.y) / 2,\n }\n }\n\n // Vector between segment starting points\n const w = { x: a1.x - b1.x, y: a1.y - b1.y }\n\n // Calculate dot products\n const dotAA = va.x * va.x + va.y * va.y\n const dotAB = va.x * vb.x + va.y * vb.y\n const dotAW = va.x * w.x + va.y * w.y\n const dotBB = vb.x * vb.x + vb.y * vb.y\n const dotBW = vb.x * w.x + vb.y * w.y\n\n // Calculate parametric positions (t values) along each segment\n const denominator = dotAA * dotBB - dotAB * dotAB\n\n // If segments are parallel, handle separately\n if (denominator < 1e-10) {\n return closestPointsParallelSegments(\n a1,\n a2,\n b1,\n b2,\n va,\n vb,\n lenSqrA,\n lenSqrB,\n )\n }\n\n // Calculate parameters for closest points\n let tA = (dotAB * dotBW - dotBB * dotAW) / denominator\n let tB = (dotAA * dotBW - dotAB * dotAW) / denominator\n\n // Clamp parameters to segment bounds\n tA = clamp(tA, 0, 1)\n tB = clamp(tB, 0, 1)\n\n // Recalculate tB if tA was clamped\n tB = (tA * dotAB + dotBW) / dotBB\n tB = clamp(tB, 0, 1)\n\n // Recalculate tA if tB was clamped\n tA = (tB * dotAB - dotAW) / dotAA\n tA = clamp(tA, 0, 1)\n\n // Calculate closest points on each segment\n const closestOnA = {\n x: a1.x + tA * va.x,\n y: a1.y + tA * va.y,\n }\n\n const closestOnB = {\n x: b1.x + tB * vb.x,\n y: b1.y + tB * vb.y,\n }\n\n // Calculate distance between closest points\n const dx = closestOnA.x - closestOnB.x\n const dy = closestOnA.y - closestOnB.y\n const distance = Math.sqrt(dx * dx + dy * dy)\n\n // Calculate the average of the closest points\n const averagePoint = {\n x: (closestOnA.x + closestOnB.x) / 2,\n y: (closestOnA.y + closestOnB.y) / 2,\n }\n\n return averagePoint\n}\n\n// Helper function for handling parallel segments\nconst closestPointsParallelSegments = (\n a1: { x: number; y: number },\n a2: { x: number; y: number },\n b1: { x: number; y: number },\n b2: { x: number; y: number },\n va: { x: number; y: number },\n vb: { x: number; y: number },\n lenSqrA: number,\n lenSqrB: number,\n) => {\n // Project b1 onto segment A\n let tA = ((b1.x - a1.x) * va.x + (b1.y - a1.y) * va.y) / lenSqrA\n tA = clamp(tA, 0, 1)\n const pointOnA1 = { x: a1.x + tA * va.x, y: a1.y + tA * va.y }\n\n // Project b2 onto segment A\n let tA2 = ((b2.x - a1.x) * va.x + (b2.y - a1.y) * va.y) / lenSqrA\n tA2 = clamp(tA2, 0, 1)\n const pointOnA2 = { x: a1.x + tA2 * va.x, y: a1.y + tA2 * va.y }\n\n // Project a1 onto segment B\n let tB = ((a1.x - b1.x) * vb.x + (a1.y - b1.y) * vb.y) / lenSqrB\n tB = clamp(tB, 0, 1)\n const pointOnB1 = { x: b1.x + tB * vb.x, y: b1.y + tB * vb.y }\n\n // Project a2 onto segment B\n let tB2 = ((a2.x - b1.x) * vb.x + (a2.y - b1.y) * vb.y) / lenSqrB\n tB2 = clamp(tB2, 0, 1)\n const pointOnB2 = { x: b1.x + tB2 * vb.x, y: b1.y + tB2 * vb.y }\n\n // Calculate all possible distances between end points and their projections\n const distances = [\n {\n pointA: pointOnA1,\n pointB: b1,\n distance: Math.sqrt(\n (pointOnA1.x - b1.x) ** 2 + (pointOnA1.y - b1.y) ** 2,\n ),\n },\n {\n pointA: pointOnA2,\n pointB: b2,\n distance: Math.sqrt(\n (pointOnA2.x - b2.x) ** 2 + (pointOnA2.y - b2.y) ** 2,\n ),\n },\n {\n pointA: a1,\n pointB: pointOnB1,\n distance: Math.sqrt(\n (a1.x - pointOnB1.x) ** 2 + (a1.y - pointOnB1.y) ** 2,\n ),\n },\n {\n pointA: a2,\n pointB: pointOnB2,\n distance: Math.sqrt(\n (a2.x - pointOnB2.x) ** 2 + (a2.y - pointOnB2.y) ** 2,\n ),\n },\n ]\n\n // Find closest pair\n const closestPair = distances.reduce((closest, current) =>\n current.distance < closest.distance ? current : closest,\n )\n\n // Calculate the average of the closest points\n return {\n x: (closestPair.pointA.x + closestPair.pointB.x) / 2,\n y: (closestPair.pointA.y + closestPair.pointB.y) / 2,\n }\n}\n\n// Helper function to clamp a value between min and max\nconst clamp = (value: number, min: number, max: number): number => {\n return Math.max(min, Math.min(max, value))\n}\n","import type {\n AnyCircuitElement,\n PcbHole,\n PcbPlatedHole,\n PcbVia,\n PcbSmtPad,\n} from \"circuit-json\"\n\nexport const getRadiusOfCircuitJsonElement = (\n obj: PcbVia | PcbPlatedHole | PcbHole | PcbSmtPad,\n) => {\n if (obj.type === \"pcb_via\") {\n return obj.outer_diameter / 2\n }\n if (obj.type === \"pcb_plated_hole\" && obj.shape === \"circle\") {\n return obj.outer_diameter / 2\n }\n if (obj.type === \"pcb_hole\" && obj.hole_shape === \"circle\") {\n return obj.hole_diameter / 2\n }\n if (obj.type === \"pcb_smtpad\" && obj.shape === \"circle\") {\n return obj.radius\n }\n throw new Error(\n `Could not determine radius of element: ${JSON.stringify(obj)}`,\n )\n}\n","import type { Bounds } from \"lib/data-structures/SpatialIndex\"\nimport type { PcbTraceSegment } from \"./getCollidableBounds\"\n\nexport const getClosestPointBetweenSegmentAndBounds = (\n segment: PcbTraceSegment,\n bounds: Bounds,\n): { x: number; y: number } => {\n // Define segment points\n const p1 = { x: segment.x1, y: segment.y1 }\n const p2 = { x: segment.x2, y: segment.y2 }\n\n // Define bounds corners\n const minX = bounds.minX\n const minY = bounds.minY\n const maxX = bounds.maxX\n const maxY = bounds.maxY\n\n // Check if segment is a point\n if (p1.x === p2.x && p1.y === p2.y) {\n // For a point, find the closest point on the bounds\n const closestX = Math.max(minX, Math.min(maxX, p1.x))\n const closestY = Math.max(minY, Math.min(maxY, p1.y))\n\n // If the point is inside the bounds, return the point itself\n if (closestX === p1.x && closestY === p1.y) {\n return { x: p1.x, y: p1.y }\n }\n\n // Otherwise, return the closest point on the bounds\n return { x: closestX, y: closestY }\n }\n\n // Calculate direction vector of the segment\n const dx = p2.x - p1.x\n const dy = p2.y - p1.y\n\n // Calculate parameter values for intersection with each boundary\n const tMinX = dx !== 0 ? (minX - p1.x) / dx : Number.NEGATIVE_INFINITY\n const tMaxX = dx !== 0 ? (maxX - p1.x) / dx : Number.POSITIVE_INFINITY\n const tMinY = dy !== 0 ? (minY - p1.y) / dy : Number.NEGATIVE_INFINITY\n const tMaxY = dy !== 0 ? (maxY - p1.y) / dy : Number.POSITIVE_INFINITY\n\n // Find the entering and exiting parameters\n const tEnter = Math.max(Math.min(tMinX, tMaxX), Math.min(tMinY, tMaxY))\n const tExit = Math.min(Math.max(tMinX, tMaxX), Math.max(tMinY, tMaxY))\n\n // Check if segment intersects the bounds\n if (tEnter <= tExit && tExit >= 0 && tEnter <= 1) {\n // Segment intersects bounds, clamp parameter to segment\n const t = Math.max(0, Math.min(1, tEnter))\n return {\n x: p1.x + t * dx,\n y: p1.y + t * dy,\n }\n }\n\n // Segment doesn't intersect bounds, find closest point\n // Check each endpoint of the segment against the bounds\n const closestToP1 = {\n x: Math.max(minX, Math.min(maxX, p1.x)),\n y: Math.max(minY, Math.min(maxY, p1.y)),\n }\n\n const closestToP2 = {\n x: Math.max(minX, Math.min(maxX, p2.x)),\n y: Math.max(minY, Math.min(maxY, p2.y)),\n }\n\n // Calculate distances\n const distToP1Squared =\n (closestToP1.x - p1.x) ** 2 + (closestToP1.y - p1.y) ** 2\n const distToP2Squared =\n (closestToP2.x - p2.x) ** 2 + (closestToP2.y - p2.y) ** 2\n\n // Check each edge of the bounds against the segment\n const edges = [\n { start: { x: minX, y: minY }, end: { x: maxX, y: minY } }, // Bottom edge\n { start: { x: maxX, y: minY }, end: { x: maxX, y: maxY } }, // Right edge\n { start: { x: maxX, y: maxY }, end: { x: minX, y: maxY } }, // Top edge\n { start: { x: minX, y: maxY }, end: { x: minX, y: minY } }, // Left edge\n ]\n\n let minDistance = Math.min(distToP1Squared, distToP2Squared)\n let closestPoint =\n distToP1Squared <= distToP2Squared ? closestToP1 : closestToP2\n\n // Helper function to clamp a value between min and max\n const clamp = (value: number, min: number, max: number): number => {\n return Math.max(min, Math.min(max, value))\n }\n\n // Check each edge\n for (const edge of edges) {\n // Calculate direction vectors\n const va = { x: p2.x - p1.x, y: p2.y - p1.y }\n const vb = { x: edge.end.x - edge.start.x, y: edge.end.y - edge.start.y }\n const w = { x: p1.x - edge.start.x, y: p1.y - edge.start.y }\n\n // Calculate dot products\n const dotAA = va.x * va.x + va.y * va.y\n const dotAB = va.x * vb.x + va.y * vb.y\n const dotAW = va.x * w.x + va.y * w.y\n const dotBB = vb.x * vb.x + vb.y * vb.y\n const dotBW = vb.x * w.x + vb.y * w.y\n\n // Calculate parameters for closest points\n const denominator = dotAA * dotBB - dotAB * dotAB\n\n // Skip if lines are parallel\n if (Math.abs(denominator) < 1e-10) continue\n\n let tA = (dotAB * dotBW - dotBB * dotAW) / denominator\n let tB = (dotAA * dotBW - dotAB * dotAW) / denominator\n\n // Clamp parameters to segment bounds\n tA = clamp(tA, 0, 1)\n tB = clamp(tB, 0, 1)\n\n // Calculate closest points\n const closestOnSegment = {\n x: p1.x + tA * va.x,\n y: p1.y + tA * va.y,\n }\n\n const closestOnEdge = {\n x: edge.start.x + tB * vb.x,\n y: edge.start.y + tB * vb.y,\n }\n\n // Calculate distance\n const dx = closestOnSegment.x - closestOnEdge.x\n const dy = closestOnSegment.y - closestOnEdge.y\n const distSquared = dx * dx + dy * dy\n\n // Update if this is closer\n if (distSquared < minDistance) {\n minDistance = distSquared\n closestPoint = {\n x: (closestOnSegment.x + closestOnEdge.x) / 2,\n y: (closestOnSegment.y + closestOnEdge.y) / 2,\n }\n }\n }\n\n return closestPoint\n}\n","import type { Collidable } from \"lib/check-each-pcb-trace-non-overlapping/getCollidableBounds\"\nimport { all_layers } from \"circuit-json\"\n\nexport function getLayersOfPcbElement(obj: Collidable): string[] {\n if (obj.type === \"pcb_trace_segment\") {\n return [obj.layer]\n }\n if (obj.type === \"pcb_smtpad\") {\n return [obj.layer]\n }\n if (obj.type === \"pcb_plated_hole\") {\n return Array.isArray(obj.layers) ? obj.layers : [...all_layers]\n }\n if (obj.type === \"pcb_hole\") {\n return [...all_layers]\n }\n if (obj.type === \"pcb_via\") {\n return Array.isArray(obj.layers) ? obj.layers : [...all_layers]\n }\n if (obj.type === \"pcb_keepout\") {\n return Array.isArray(obj.layers) ? obj.layers : []\n }\n return []\n}\n","export class NetManager {\n private networks: Set<Set<string>> = new Set()\n\n setConnected(nodes: string[]): void {\n if (nodes.length < 2) return\n\n let targetNetwork: Set<string> | null = null\n\n // Check if any of the nodes are already in a network\n for (const network of this.networks) {\n for (const node of nodes) {\n if (network.has(node)) {\n if (targetNetwork === null) {\n targetNetwork = network\n } else if (targetNetwork !== network) {\n // Merge networks\n for (const mergeNode of network) {\n targetNetwork.add(mergeNode)\n }\n this.networks.delete(network)\n }\n break\n }\n }\n if (targetNetwork !== null && targetNetwork !== network) break\n }\n\n // If no existing network found, create a new one\n if (targetNetwork === null) {\n targetNetwork = new Set(nodes)\n this.networks.add(targetNetwork)\n } else {\n // Add all nodes to the target network\n for (const node of nodes) {\n targetNetwork.add(node)\n }\n }\n }\n\n isConnected(nodes: string[]): boolean {\n if (nodes.length < 2) return true\n\n for (const network of this.networks) {\n if (nodes.every((node) => network.has(node))) {\n return true\n }\n }\n\n return false\n }\n}\n","import type {\n AnyCircuitElement,\n PcbBoard,\n PcbVia,\n PcbPlacementError,\n} from \"circuit-json\"\nimport { getReadableNameForElement } from \"@tscircuit/circuit-json-util\"\nimport { DEFAULT_VIA_BOARD_MARGIN } from \"lib/drc-defaults\"\n\nexport function checkViasOffBoard(\n circuitJson: AnyCircuitElement[],\n): PcbPlacementError[] {\n const board = circuitJson.find((el) => el.type === \"pcb_board\") as PcbBoard\n\n if (!board) return []\n\n const vias = circuitJson.filter((el) => el.type === \"pcb_via\") as PcbVia[]\n\n if (vias.length === 0) return []\n\n if (board.width === undefined || board.height === undefined) return []\n\n const boardMinX = board.center.x - board.width / 2\n const boardMaxX = board.center.x + board.width / 2\n const boardMinY = board.center.y - board.height / 2\n const boardMaxY = board.center.y + board.height / 2\n\n const errors: PcbPlacementError[] = []\n\n for (const via of vias) {\n const viaRadius = via.outer_diameter / 2\n const viaMinX = via.x - viaRadius\n const viaMaxX = via.x + viaRadius\n const viaMinY = via.y - viaRadius\n const viaMaxY = via.y + viaRadius\n\n if (\n viaMinX < boardMinX + DEFAULT_VIA_BOARD_MARGIN ||\n viaMaxX > boardMaxX - DEFAULT_VIA_BOARD_MARGIN ||\n viaMinY < boardMinY + DEFAULT_VIA_BOARD_MARGIN ||\n viaMaxY > boardMaxY - DEFAULT_VIA_BOARD_MARGIN\n ) {\n const viaName = getReadableNameForElement(circuitJson, via.pcb_via_id)\n errors.push({\n type: \"pcb_placement_error\",\n pcb_placement_error_id: `out_of_board_${via.pcb_via_id}`,\n message: `Via ${viaName} is outside or crossing the board boundary`,\n error_type: \"pcb_placement_error\",\n })\n }\n }\n\n return errors\n}\n","import type {\n AnyCircuitElement,\n PcbBoard,\n PcbComponent,\n AnySourceComponent,\n PcbComponentOutsideBoardError,\n} from \"circuit-json\"\nimport { getReadableNameForElement } from \"@tscircuit/circuit-json-util\"\nimport type { Point } from \"@tscircuit/math-utils\"\nimport * as Flatten from \"@flatten-js/core\"\nimport { rotateDEG, applyToPoint } from \"transformation-matrix\"\n\n/**\n * Create a rectangle polygon centered at (cx,cy) with given width/height and rotation (degrees).\n * Uses transformation-matrix to rotate around the center and returns a Flatten.Polygon.\n */\n\nfunction isPolygonCCW(poly: Flatten.Polygon): boolean {\n // @ts-ignore\n return poly.area() >= 0\n}\n\nfunction rectanglePolygon({\n center,\n size,\n rotationDeg = 0,\n}: {\n center: Point\n size: { width: number; height: number }\n rotationDeg?: number\n}): Flatten.Polygon {\n const cx = center.x\n const cy = center.y\n const hw = size.width / 2\n const hh = size.height / 2\n\n const corners: Flatten.Point[] = [\n new Flatten.Point(cx - hw, cy - hh),\n new Flatten.Point(cx + hw, cy - hh),\n new Flatten.Point(cx + hw, cy + hh),\n new Flatten.Point(cx - hw, cy + hh),\n ]\n\n let poly = new Flatten.Polygon(corners)\n\n if (rotationDeg) {\n const matrix = rotateDEG(rotationDeg, cx, cy)\n const rotatedCorners = corners.map((pt) => {\n const p = applyToPoint(matrix, { x: pt.x, y: pt.y })\n return new Flatten.Point(p.x, p.y)\n })\n poly = new Flatten.Polygon(rotatedCorners)\n }\n\n // Ensure CCW order\n if (!isPolygonCCW(poly)) poly.reverse()\n\n return poly\n}\n\nfunction boardToPolygon({\n board,\n}: { board: PcbBoard }): Flatten.Polygon | null {\n if (board.outline && board.outline.length > 0) {\n const points = board.outline.map((p) => new Flatten.Point(p.x, p.y))\n const poly = new Flatten.Polygon(points)\n\n if (!isPolygonCCW(poly)) {\n poly.reverse()\n }\n\n return poly\n }\n\n if (\n board.center &&\n typeof board.width === \"number\" &&\n typeof board.height === \"number\"\n ) {\n return rectanglePolygon({\n center: board.center,\n size: { width: board.width, height: board.height },\n rotationDeg: 0,\n })\n }\n\n return null\n}\n\n/** Get human-readable component name from circuit JSON */\nfunction getComponentName({\n circuitJson,\n component,\n}: {\n circuitJson: AnyCircuitElement[]\n component: PcbComponent\n}): string {\n if (component.source_component_id) {\n const sourceComponent = circuitJson.find(\n (el): el is AnySourceComponent =>\n el.type === \"source_component\" &&\n el.source_component_id === component.source_component_id,\n )\n if (sourceComponent && \"name\" in sourceComponent && sourceComponent.name) {\n return sourceComponent.name\n }\n }\n\n return (\n getReadableNameForElement(circuitJson, component.pcb_component_id) ||\n \"Unknown\"\n )\n}\n\n/**\n * Compute overlap distance based on polygon containment and distances.\n * - If component center is outside board, distance is from center to board polygon.\n * - Samples rotated rectangle corners and edge midpoints; for any outside points,\n * computes distance to board polygon and returns the maximum.\n * - Falls back to intersection area ratio heuristic if needed.\n * - Returns small epsilon if fully inside.\n */\nfunction computeOverlapDistance(\n compPoly: Flatten.Polygon,\n boardPoly: Flatten.Polygon,\n componentCenter: Point,\n componentWidth: number,\n componentHeight: number,\n rotationDeg: number,\n): number {\n const centerPoint = new Flatten.Point(componentCenter.x, componentCenter.y)\n // If center is outside board polygon, return distance to board polygon\n if (!boardPoly.contains(centerPoint)) {\n const dist = boardPoly.distanceTo(centerPoint)\n return Array.isArray(dist) ? dist[0] : Number(dist) || 0\n }\n\n // Sample corners and edge midpoints of rotated rectangle\n const hw = componentWidth / 2\n const hh = componentHeight / 2\n\n // Original corners\n const corners: Point[] = [\n { x: componentCenter.x - hw, y: componentCenter.y - hh },\n { x: componentCenter.x + hw, y: componentCenter.y - hh },\n { x: componentCenter.x + hw, y: componentCenter.y + hh },\n { x: componentCenter.x - hw, y: componentCenter.y + hh },\n ]\n\n // Edge midpoints\n const midpoints: Point[] = []\n for (let i = 0; i < 4; i++) {\n const next = (i + 1) % 4\n midpoints.push({\n x: (corners[i].x + corners[next].x) / 2,\n y: (corners[i].y + corners[next].y) / 2,\n })\n }\n\n // Rotate points around center by rotationDeg\n const matrix = rotateDEG(rotationDeg, componentCenter.x, componentCenter.y)\n const rotatePoint = (pt: Point) => {\n const p = applyToPoint(matrix, pt)\n return new Flatten.Point(p.x, p.y)\n }\n\n const rotatedPoints = corners.concat(midpoints).map(rotatePoint)\n\n // For any point outside board polygon, compute distance to board polygon\n let maxDistance = 0\n for (const pt of rotatedPoints) {\n if (!boardPoly.contains(pt)) {\n const dist = boardPoly.distanceTo(pt)\n const d = Array.isArray(dist) ? dist[0] : Number(dist) || 0\n if (d > maxDistance) maxDistance = d\n }\n }\n\n if (maxDistance > 0) {\n return maxDistance\n }\n\n // Fallback: use intersection area ratio heuristic\n try {\n const intersection = Flatten.BooleanOperations.intersect(\n compPoly,\n boardPoly,\n )\n\n let intersectionArea = 0\n if (!intersection) {\n intersectionArea = 0\n } else if (Array.isArray(intersection)) {\n intersectionArea = intersection.reduce(\n (sum, p) => sum + (typeof p.area === \"function\" ? p.area() : 0),\n 0,\n )\n } else if (typeof (intersection as any).area === \"function\") {\n intersectionArea = (intersection as any).area()\n } else {\n intersectionArea = 0\n }\n\n const compArea = compPoly.area()\n\n if (intersectionArea > 0 && intersectionArea < compArea) {\n const overlapRatio = 1 - intersectionArea / compArea\n const compWidth = Math.abs(componentWidth)\n const compHeight = Math.abs(componentHeight)\n return Math.min(compWidth, compHeight) * overlapRatio\n } else if (intersectionArea === 0) {\n // completely outside (should not happen here), return small epsilon\n return 0.1\n } else {\n return 0.1\n }\n } catch {\n // If boolean ops fail (unlikely), return small epsilon\n return 0.1\n }\n}\n\n/**\n * Main function — polygon-first: construct polygons, test containment / intersection,\n * compute overlap distance using boolean intersection area or geometric distance.\n */\nexport function checkPcbComponentsOutOfBoard(\n circuitJson: AnyCircuitElement[],\n): PcbComponentOutsideBoardError[] {\n const board = circuitJson.find(\n (el): el is PcbBoard => el.type === \"pcb_board\",\n )\n if (!board) return []\n\n const boardPoly = boardToPolygon({ board })\n if (!boardPoly) return []\n\n const components = circuitJson.filter(\n (el): el is PcbComponent => el.type === \"pcb_component\",\n )\n if (components.length === 0) return []\n\n const errors: PcbComponentOutsideBoardError[] = []\n\n for (const c of components) {\n // need center, width, height\n if (\n !c.center ||\n typeof c.width !== \"number\" ||\n typeof c.height !== \"number\"\n )\n continue\n\n if (c.width <= 0 || c.height <= 0) continue\n\n const compPoly = rectanglePolygon({\n center: c.center,\n size: { width: c.width, height: c.height },\n rotationDeg: c.rotation || 0,\n })\n\n if (compPoly.area() === 0) continue\n\n // If component is entirely inside board polygon -> OK\n // Flatten.Polygon.contains accepts shapes; this is the correct polygon containment check.\n const isInside = boardPoly.contains(compPoly)\n if (isInside) continue\n\n // Component is at least partially outside. Compute overlapDistance:\n const overlapDistance = computeOverlapDistance(\n compPoly,\n boardPoly,\n c.center,\n c.width,\n c.height,\n c.rotation || 0,\n )\n\n const compName = getComponentName({ circuitJson, component: c })\n const overlapDistanceMm = Math.round(overlapDistance * 100) / 100\n\n errors.push({\n type: \"pcb_component_outside_board_error\",\n error_type: \"pcb_component_outside_board_error\",\n pcb_component_outside_board_error_id: `pcb_component_outside_board_${c.pcb_component_id}`,\n message: `Component ${compName} (${c.pcb_component_id}) extends outside board boundaries by ${overlapDistanceMm}mm`,\n pcb_component_id: c.pcb_component_id,\n pcb_board_id: board.pcb_board_id,\n component_center: c.center,\n component_bounds: {\n min_x: compPoly.box.xmin,\n max_x: compPoly.box.xmax,\n min_y: compPoly.box.ymin,\n max_y: compPoly.box.ymax,\n },\n subcircuit_id: c.subcircuit_id,\n source_component_id: c.source_component_id,\n })\n }\n\n return errors\n}\n","import type {\n AnyCircuitElement,\n PcbVia,\n PcbViaClearanceError,\n} from \"circuit-json\"\nimport { getReadableNameForElement } from \"@tscircuit/circuit-json-util\"\nimport {\n getFullConnectivityMapFromCircuitJson,\n type ConnectivityMap,\n} from \"circuit-json-to-connectivity-map\"\nimport { DEFAULT_SAME_NET_VIA_MARGIN, EPSILON } from \"lib/drc-defaults\"\n\nfunction distance(a: PcbVia, b: PcbVia): number {\n return Math.hypot(a.x - b.x, a.y - b.y)\n}\n\nexport function checkSameNetViaSpacing(\n circuitJson: AnyCircuitElement[],\n {\n connMap,\n minSpacing = DEFAULT_SAME_NET_VIA_MARGIN,\n }: { connMap?: ConnectivityMap; minSpacing?: number } = {},\n): PcbViaClearanceError[] {\n const vias = circuitJson.filter((el) => el.type === \"pcb_via\") as PcbVia[]\n if (vias.length < 2) return []\n connMap ??= getFullConnectivityMapFromCircuitJson(circuitJson)\n const errors: PcbViaClearanceError[] = []\n const reported = new Set<string>()\n\n for (let i = 0; i < vias.length; i++) {\n for (let j = i + 1; j < vias.length; j++) {\n const viaA = vias[i]\n const viaB = vias[j]\n if (!connMap.areIdsConnected(viaA.pcb_via_id, viaB.pcb_via_id)) continue\n const gap =\n distance(viaA, viaB) - viaA.outer_diameter / 2 - viaB.outer_diameter / 2\n if (gap + EPSILON >= minSpacing) continue\n const pairId = [viaA.pcb_via_id, viaB.pcb_via_id].sort().join(\"_\")\n if (reported.has(pairId)) continue\n reported.add(pairId)\n errors.push({\n type: \"pcb_via_clearance_error\",\n pcb_error_id: `same_net_vias_close_${pairId}`,\n message: `Vias ${getReadableNameForElement(\n circuitJson,\n viaA.pcb_via_id,\n )} and ${getReadableNameForElement(\n circuitJson,\n viaB.pcb_via_id,\n )} are too close together (gap: ${gap.toFixed(3)}mm)`,\n error_type: \"pcb_via_clearance_error\",\n pcb_via_ids: [viaA.pcb_via_id, viaB.pcb_via_id],\n minimum_clearance: minSpacing,\n actual_clearance: gap,\n pcb_center: {\n x: (viaA.x + viaB.x) / 2,\n y: (viaA.y + viaB.y) / 2,\n },\n })\n }\n }\n\n return errors\n}\n","import type {\n AnyCircuitElement,\n PcbVia,\n PcbViaClearanceError,\n} from \"circuit-json\"\nimport { getReadableNameForElement } from \"@tscircuit/circuit-json-util\"\nimport {\n getFullConnectivityMapFromCircuitJson,\n type ConnectivityMap,\n} from \"circuit-json-to-connectivity-map\"\nimport { DEFAULT_DIFFERENT_NET_VIA_MARGIN, EPSILON } from \"lib/drc-defaults\"\n\nfunction distance(a: PcbVia, b: PcbVia): number {\n return Math.hypot(a.x - b.x, a.y - b.y)\n}\n\nexport function checkDifferentNetViaSpacing(\n circuitJson: AnyCircuitElement[],\n {\n connMap,\n minSpacing = DEFAULT_DIFFERENT_NET_VIA_MARGIN,\n }: { connMap?: ConnectivityMap; minSpacing?: number } = {},\n): PcbViaClearanceError[] {\n const vias = circuitJson.filter((el) => el.type === \"pcb_via\") as PcbVia[]\n if (vias.length < 2) return []\n connMap ??= getFullConnectivityMapFromCircuitJson(circuitJson)\n const errors: PcbViaClearanceError[] = []\n const reported = new Set<string>()\n\n for (let i = 0; i < vias.length; i++) {\n for (let j = i + 1; j < vias.length; j++) {\n const viaA = vias[i]\n const viaB = vias[j]\n if (connMap.areIdsConnected(viaA.pcb_via_id, viaB.pcb_via_id)) continue\n const gap =\n distance(viaA, viaB) - viaA.outer_diameter / 2 - viaB.outer_diameter / 2\n if (gap + EPSILON >= minSpacing) continue\n const pairId = [viaA.pcb_via_id, viaB.pcb_via_id].sort().join(\"_\")\n if (reported.has(pairId)) continue\n reported.add(pairId)\n errors.push({\n type: \"pcb_via_clearance_error\",\n pcb_error_id: `different_net_vias_close_${pairId}`,\n message: `Vias ${getReadableNameForElement(\n circuitJson,\n viaA.pcb_via_id,\n )} and ${getReadableNameForElement(\n circuitJson,\n viaB.pcb_via_id,\n )} from different nets are too close together (gap: ${gap.toFixed(\n 3,\n )}mm)`,\n error_type: \"pcb_via_clearance_error\",\n pcb_via_ids: [viaA.pcb_via_id, viaB.pcb_via_id],\n minimum_clearance: minSpacing,\n actual_clearance: gap,\n pcb_center: {\n x: (viaA.x + viaB.x) / 2,\n y: (viaA.y + viaB.y) / 2,\n },\n })\n }\n }\n\n return errors\n}\n","import type {\n AnyCircuitElement,\n PcbTraceMissingError,\n SourceTrace,\n PcbTrace,\n PcbPort,\n} from \"circuit-json\"\n\n/**\n * Check that each source_trace which connects source ports has at least one\n * pcb_trace associated with it. If a source_trace has no corresponding\n * pcb_trace, return an error for that source_trace.\n */\nfunction checkSourceTracesHavePcbTraces(\n circuitJson: AnyCircuitElement[],\n): PcbTraceMissingError[] {\n const errors: PcbTraceMissingError[] = []\n const sourceTraces = circuitJson.filter(\n (el) => el.type === \"source_trace\",\n ) as SourceTrace[]\n const pcbTraces = circuitJson.filter(\n (el) => el.type === \"pcb_trace\",\n ) as PcbTrace[]\n\n for (const sourceTrace of sourceTraces) {\n if (!sourceTrace.connected_source_port_ids?.length) continue\n const hasPcbTrace = pcbTraces.some(\n (pcbTrace) => pcbTrace.source_trace_id === sourceTrace.source_trace_id,\n )\n if (!hasPcbTrace) {\n // Get PCB ports connected to this source trace\n const connectedPcbPorts = circuitJson.filter(\n (el) =>\n el.type === \"pcb_port\" &&\n sourceTrace.connected_source_port_ids.includes(el.source_port_id),\n ) as PcbPort[]\n\n // Find PCB components that these ports belong to\n const connectedPcbComponentIds = Array.from(\n new Set(\n connectedPcbPorts\n .map((port) => port.pcb_component_id)\n .filter((id): id is string => id !== undefined),\n ),\n )\n\n errors.push({\n type: \"pcb_trace_missing_error\",\n pcb_trace_missing_error_id: `pcb_trace_missing_${sourceTrace.source_trace_id}`,\n error_type: \"pcb_trace_missing_error\",\n message: `Trace [${sourceTrace.display_name ?? sourceTrace.source_trace_id}] is not connected (it has no PCB trace)`,\n source_trace_id: sourceTrace.source_trace_id,\n pcb_component_ids: connectedPcbComponentIds,\n pcb_port_ids: connectedPcbPorts.map((port) => port.pcb_port_id),\n })\n }\n }\n\n return errors\n}\n\nexport { checkSourceTracesHavePcbTraces }\n","import type {\n AnyCircuitElement,\n PcbBoard,\n PcbTrace,\n PcbTraceError,\n} from \"circuit-json\"\nimport { cju } from \"@tscircuit/circuit-json-util\"\nimport type { Point, Polygon } from \"@tscircuit/math-utils\"\nimport { segmentToSegmentMinDistance } from \"@tscircuit/math-utils\"\n\n/**\n * Default margin for trace clearance from board edge (in mm)\n */\nconst DEFAULT_BOARD_MARGIN = 0.2\n\n/**\n * Configuration for trace board boundary checking\n */\nexport interface TraceBoardCheckConfig {\n /** Minimum distance from trace center to board edge (in mm) */\n margin?: number\n}\n\n/**\n * Create a board polygon representation using math-utils Polygon type\n */\nfunction getBoardPolygonPoints(board: PcbBoard): Polygon | null {\n if (board.outline && board.outline.length > 0) {\n // Use custom board outline\n return board.outline.map((p) => ({ x: p.x, y: p.y }))\n }\n\n if (\n board.center &&\n typeof board.width === \"number\" &&\n typeof board.height === \"number\"\n ) {\n // Create rectangular board outline\n const cx = board.center.x\n const cy = board.center.y\n const hw = board.width / 2\n const hh = board.height / 2\n\n return [\n { x: cx - hw, y: cy - hh }, // bottom-left\n { x: cx + hw, y: cy - hh }, // bottom-right\n { x: cx + hw, y: cy + hh }, // top-right\n { x: cx - hw, y: cy + hh }, // top-left\n ]\n }\n\n return null\n}\n\n/**\n * Check if any trace segment is too close to or outside the board outline\n * Uses segment-to-polygon distance with configurable margin\n */\nexport function checkPcbTracesOutOfBoard(\n circuitJson: AnyCircuitElement[],\n config: TraceBoardCheckConfig = {},\n): PcbTraceError[] {\n const errors: PcbTraceError[] = []\n const margin = config.margin ?? DEFAULT_BOARD_MARGIN\n\n // Find the board\n const board = circuitJson.find(\n (el): el is PcbBoard => el.type === \"pcb_board\",\n )\n if (!board) return errors\n\n // Create board polygon using math-utils Point type\n const boardPoints = getBoardPolygonPoints(board)\n if (!boardPoints) return errors\n\n // Get all PCB traces\n const pcbTraces = cju(circuitJson).pcb_trace.list()\n\n for (const trace of pcbTraces) {\n if (trace.route.length < 2) continue\n\n // Check each segment of the trace\n for (let i = 0; i < trace.route.length - 1; i++) {\n const p1 = trace.route[i]\n const p2 = trace.route[i + 1]\n\n // Only check wire segments\n if (p1.route_type !== \"wire\" || p2.route_type !== \"wire\") continue\n\n const traceWidth =\n \"width\" in p1 ? p1.width : \"width\" in p2 ? p2.width : 0.1\n const segmentStart: Point = { x: p1.x, y: p1.y }\n const segmentEnd: Point = { x: p2.x, y: p2.y }\n\n // Calculate minimum distance from trace segment to board polygon\n let minDistance = Infinity\n for (let j = 0; j < boardPoints.length; j++) {\n const edgeStart = boardPoints[j]\n const edgeEnd = boardPoints[(j + 1) % boardPoints.length]\n const distance = segmentToSegmentMinDistance(\n segmentStart,\n segmentEnd,\n edgeStart,\n edgeEnd,\n )\n if (distance < minDistance) {\n minDistance = distance\n }\n }\n\n const minimumDistance = traceWidth / 2 + margin\n\n if (minDistance < minimumDistance) {\n const error: PcbTraceError = {\n type: \"pcb_trace_error\",\n error_type: \"pcb_trace_error\",\n pcb_trace_error_id: `trace_too_close_to_board_${trace.pcb_trace_id}_segment_${i}`,\n message: `Trace too close to board edge (${minDistance.toFixed(3)}mm < ${minimumDistance.toFixed(3)}mm required, margin: ${margin}mm)`,\n pcb_trace_id: trace.pcb_trace_id,\n source_trace_id: trace.source_trace_id || \"\",\n center: {\n x: (segmentStart.x + segmentEnd.x) / 2,\n y: (segmentStart.y + segmentEnd.y) / 2,\n },\n pcb_component_ids: [],\n pcb_port_ids: [],\n }\n errors.push(error)\n }\n }\n }\n\n return errors\n}\n","import type {\n AnyCircuitElement,\n PcbFootprintOverlapError,\n PcbSmtPad,\n PcbPlatedHole,\n PcbHole,\n PcbComponent,\n} from \"circuit-json\"\nimport {\n cju,\n getBoundsOfPcbElements,\n getPrimaryId,\n} from \"@tscircuit/circuit-json-util\"\nimport { doBoundsOverlap } from \"@tscircuit/math-utils\"\nimport {\n getFullConnectivityMapFromCircuitJson,\n type ConnectivityMap,\n} from \"circuit-json-to-connectivity-map\"\n\ntype OverlappableElement = PcbSmtPad | PcbPlatedHole | PcbHole\n\ninterface ComponentWithElements {\n component_id: string\n elements: OverlappableElement[]\n bounds: {\n minX: number\n minY: number\n maxX: number\n maxY: number\n }\n}\n\n/**\n * Check if two PCB elements overlap\n * Currently uses simple bounds overlap, but can be extended to handle\n * more precise overlap detection for rotated rects, pills, circles, etc.\n */\nfunction doPcbElementsOverlap(\n elem1: OverlappableElement,\n elem2: OverlappableElement,\n): boolean {\n const bounds1 = getBoundsOfPcbElements([elem1])\n const bounds2 = getBoundsOfPcbElements([elem2])\n return doBoundsOverlap(bounds1, bounds2)\n}\n\n/**\n * Check for overlapping PCB components\n * Returns errors for components that overlap inappropriately\n */\nexport function checkPcbComponentOverlap(\n circuitJson: AnyCircuitElement[],\n): PcbFootprintOverlapError[] {\n const errors: PcbFootprintOverlapError[] = []\n\n // Build connectivity map to check if components are electrically connected\n const connMap = getFullConnectivityMapFromCircuitJson(circuitJson)\n\n // Get all overlappable elements\n const smtPads = cju(circuitJson).pcb_smtpad.list()\n const platedHoles = cju(circuitJson).pcb_plated_hole.list()\n const holes = cju(circuitJson).pcb_hole.list()\n\n // Group elements by component (or treat standalone elements as their own \"component\")\n const componentMap = new Map<string, ComponentWithElements>()\n\n // Group SMT pads by component (or treat as standalone)\n for (const pad of smtPads) {\n const componentId =\n pad.pcb_component_id || `standalone_pad_${getPrimaryId(pad)}`\n if (!componentMap.has(componentId)) {\n componentMap.set(componentId, {\n component_id: componentId,\n elements: [],\n bounds: { minX: 0, minY: 0, maxX: 0, maxY: 0 },\n })\n }\n componentMap.get(componentId)!.elements.push(pad)\n }\n\n // Group plated holes by component (or treat as standalone)\n for (const hole of platedHoles) {\n const componentId =\n hole.pcb_component_id || `standalone_plated_hole_${getPrimaryId(hole)}`\n if (!componentMap.has(componentId)) {\n componentMap.set(componentId, {\n component_id: componentId,\n elements: [],\n bounds: { minX: 0, minY: 0, maxX: 0, maxY: 0 },\n })\n }\n componentMap.get(componentId)!.elements.push(hole)\n }\n\n // Holes typically don't have pcb_component_id, treat each as standalone\n for (const hole of holes) {\n const componentId = `standalone_hole_${getPrimaryId(hole)}`\n componentMap.set(componentId, {\n component_id: componentId,\n elements: [hole],\n bounds: { minX: 0, minY: 0, maxX: 0, maxY: 0 },\n })\n }\n\n // Compute bounds for each component\n for (const [componentId, componentData] of componentMap) {\n if (componentData.elements.length > 0) {\n componentData.bounds = getBoundsOfPcbElements(componentData.elements)\n }\n }\n\n // Convert map to array for pairwise iteration\n const componentsWithElements = Array.from(componentMap.values())\n\n // Pairwise check: only check elements if component bounds overlap\n for (let i = 0; i < componentsWithElements.length; i++) {\n for (let j = i + 1; j < componentsWithElements.length; j++) {\n const comp1 = componentsWithElements[i]\n const comp2 = componentsWithElements[j]\n\n // First check if component bounds overlap\n if (!doBoundsOverlap(comp1.bounds, comp2.bounds)) {\n continue\n }\n\n // Component bounds overlap, now check individual elements\n for (const elem1 of comp1.elements) {\n for (const elem2 of comp2.elements) {\n const id1 = getPrimaryId(elem1)\n const id2 = getPrimaryId(elem2)\n\n // Check if both are SMT pads and are electrically connected (same net) - if so, skip\n // This allows pads with the same subcircuit connectivity to be in contact\n if (\n elem1.type === \"pcb_smtpad\" &&\n elem2.type === \"pcb_smtpad\" &&\n connMap.areIdsConnected(id1, id2)\n ) {\n continue\n }\n\n // Check if element bounds overlap\n if (doPcbElementsOverlap(elem1, elem2)) {\n // Create error object\n const error: PcbFootprintOverlapError = {\n type: \"pcb_footprint_overlap_error\",\n pcb_error_id: `pcb_footprint_overlap_${id1}_${id2}`,\n error_type: \"pcb_footprint_overlap_error\",\n message: `PCB component ${elem1.type} \"${id1}\" overlaps with ${elem2.type} \"${id2}\"`,\n }\n\n // Add relevant IDs based on element types\n if (elem1.type === \"pcb_smtpad\" || elem2.type === \"pcb_smtpad\") {\n error.pcb_smtpad_ids = []\n if (elem1.type === \"pcb_smtpad\") error.pcb_smtpad_ids.push(id1)\n if (elem2.type === \"pcb_smtpad\") error.pcb_smtpad_ids.push(id2)\n }\n\n if (\n elem1.type === \"pcb_plated_hole\" ||\n elem2.type === \"pcb_plated_hole\"\n ) {\n error.pcb_plated_hole_ids = []\n if (elem1.type === \"pcb_plated_hole\")\n error.pcb_plated_hole_ids.push(id1)\n if (elem2.type === \"pcb_plated_hole\")\n error.pcb_plated_hole_ids.push(id2)\n }\n\n if (elem1.type === \"pcb_hole\" || elem2.type === \"pcb_hole\") {\n error.pcb_hole_ids = []\n if (elem1.type === \"pcb_hole\") error.pcb_hole_ids.push(id1)\n if (elem2.type === \"pcb_hole\") error.pcb_hole_ids.push(id2)\n }\n\n errors.push(error)\n }\n }\n }\n }\n }\n\n return errors\n}\n","import type { AnyCircuitElement } from \"circuit-json\"\n\ntype SourceComponent = Extract<\n AnyCircuitElement,\n { source_component_id: string; name: string }\n>\n\ntype SourcePort = Extract<AnyCircuitElement, { type: \"source_port\" }>\ntype SourceTrace = Extract<AnyCircuitElement, { type: \"source_trace\" }>\n\ntype SourcePinMustBeConnectedError = {\n type: \"source_pin_must_be_connected_error\"\n source_pin_must_be_connected_error_id: string\n error_type: \"source_pin_must_be_connected_error\"\n message: string\n source_component_id: string\n source_port_id: string\n subcircuit_id?: string\n}\n\n/**\n * Check that each source port with must_be_connected attribute is actually\n * connected to a trace. Returns errors for any pins that are marked as\n * must_be_connected but are floating (not connected to any trace).\n */\nexport function checkPinMustBeConnected(\n circuitJson: AnyCircuitElement[],\n): SourcePinMustBeConnectedError[] {\n const errors: SourcePinMustBeConnectedError[] = []\n\n // Get all source components, ports, and traces\n const sourceComponents = circuitJson.filter(\n (el): el is SourceComponent =>\n \"source_component_id\" in el &&\n (el.type === \"source_component\" || el.type.startsWith(\"source_simple_\")),\n )\n const sourcePorts = circuitJson.filter(\n (el): el is SourcePort => el.type === \"source_port\",\n )\n const sourceTraces = circuitJson.filter(\n (el): el is SourceTrace => el.type === \"source_trace\",\n )\n\n // Build a set of connected source port IDs\n const connectedPortIds = new Set<string>()\n for (const trace of sourceTraces) {\n for (const portId of trace.connected_source_port_ids ?? []) {\n connectedPortIds.add(portId)\n }\n }\n\n // Build a map of internally connected port groups for each component\n const componentInternalConnections = new Map<string, string[][]>()\n for (const component of sourceComponents) {\n if (\n \"internally_connected_source_port_ids\" in component &&\n component.internally_connected_source_port_ids\n ) {\n componentInternalConnections.set(\n component.source_component_id,\n component.internally_connected_source_port_ids,\n )\n }\n }\n\n // For each internal group, if any port is connected, mark all ports in the group as connected\n for (const internalGroups of componentInternalConnections.values()) {\n for (const group of internalGroups) {\n if (group.some((portId) => connectedPortIds.has(portId))) {\n for (const portId of group) {\n connectedPortIds.add(portId)\n }\n }\n }\n }\n\n // Check each port for must_be_connected attribute\n for (const port of sourcePorts) {\n if (port.must_be_connected === true) {\n if (!connectedPortIds.has(port.source_port_id)) {\n const component = sourceComponents.find(\n (c) => c.source_component_id === port.source_component_id,\n )\n const componentName = component?.name ?? \"Unknown\"\n\n errors.push({\n type: \"source_pin_must_be_connected_error\",\n source_pin_must_be_connected_error_id: `source_pin_must_be_connected_error_${port.source_port_id}`,\n error_type: \"source_pin_must_be_connected_error\",\n message: `Port ${port.name} on ${componentName} must be connected but is floating`,\n source_component_id: port.source_component_id ?? \"\",\n source_port_id: port.source_port_id,\n subcircuit_id: port.subcircuit_id,\n })\n }\n }\n }\n\n return errors\n}\n","import type { PcbSmtPad, PcbPlatedHole } from \"circuit-json\"\n\nfunction distance(x1: number, y1: number, x2: number, y2: number): number {\n return Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)\n}\n\nexport function isPointInPad(\n point: { x: number; y: number },\n pad: PcbSmtPad | PcbPlatedHole,\n): boolean {\n if (pad.type === \"pcb_smtpad\") {\n if (pad.shape === \"circle\") {\n return distance(point.x, point.y, pad.x, pad.y) <= pad.radius\n }\n\n if (pad.shape === \"rect\") {\n const halfWidth = pad.width / 2\n const halfHeight = pad.height / 2\n return (\n Math.abs(point.x - pad.x) <= halfWidth &&\n Math.abs(point.y - pad.y) <= halfHeight\n )\n }\n\n if (pad.shape === \"rotated_rect\") {\n const dx = point.x - pad.x\n const dy = point.y - pad.y\n const angle = -pad.ccw_rotation\n const rotatedX = dx * Math.cos(angle) - dy * Math.sin(angle)\n const rotatedY = dx * Math.sin(angle) + dy * Math.cos(angle)\n return (\n Math.abs(rotatedX) <= pad.width / 2 &&\n Math.abs(rotatedY) <= pad.height / 2\n )\n }\n\n if (pad.shape === \"pill\") {\n const halfWidth = pad.width / 2\n const halfHeight = pad.height / 2\n const radius = pad.radius\n\n if (\n Math.abs(point.x - pad.x) <= halfWidth - radius &&\n Math.abs(point.y - pad.y) <= halfHeight\n ) {\n return true\n }\n\n const cornerX = Math.max(\n Math.abs(point.x - pad.x) - (halfWidth - radius),\n 0,\n )\n const cornerY = Math.max(\n Math.abs(point.y - pad.y) - (halfHeight - radius),\n 0,\n )\n return cornerX * cornerX + cornerY * cornerY <= radius * radius\n }\n }\n\n if (pad.type === \"pcb_plated_hole\") {\n if (pad.shape === \"circle\") {\n return distance(point.x, point.y, pad.x, pad.y) <= pad.outer_diameter / 2\n }\n\n if (pad.shape === \"oval\" || pad.shape === \"pill\") {\n return (\n Math.abs(point.x - pad.x) <= pad.outer_width / 2 &&\n Math.abs(point.y - pad.y) <= pad.outer_height / 2\n )\n }\n\n if (pad.shape === \"circular_hole_with_rect_pad\") {\n return (\n Math.abs(point.x - pad.x) <= pad.rect_pad_width / 2 &&\n Math.abs(point.y - pad.y) <= pad.rect_pad_height / 2\n )\n }\n\n if (pad.shape === \"pill_hole_with_rect_pad\") {\n return (\n Math.abs(point.x - pad.x) <= pad.rect_pad_width / 2 &&\n Math.abs(point.y - pad.y) <= pad.rect_pad_height / 2\n )\n }\n }\n\n return false\n}\n","import type {\n AnyCircuitElement,\n PcbTraceError,\n PcbPort,\n PcbTrace,\n SourceTrace,\n PcbSmtPad,\n PcbPlatedHole,\n} from \"circuit-json\"\nimport { isPointInPad } from \"./is-point-in-pad\"\nimport { getReadableNameForPcbPort } from \"@tscircuit/circuit-json-util\"\n\nfunction checkTracesAreContiguous(\n circuitJson: AnyCircuitElement[],\n): PcbTraceError[] {\n const errors: PcbTraceError[] = []\n\n const pcbPorts = circuitJson.filter(\n (el) => el.type === \"pcb_port\",\n ) as PcbPort[]\n const pcbTraces = circuitJson.filter(\n (el) => el.type === \"pcb_trace\",\n ) as PcbTrace[]\n const sourceTraces = circuitJson.filter(\n (el) => el.type === \"source_trace\",\n ) as SourceTrace[]\n const pcbSmtPads = circuitJson.filter(\n (el) => el.type === \"pcb_smtpad\",\n ) as PcbSmtPad[]\n const pcbPlatedHoles = circuitJson.filter(\n (el) => el.type === \"pcb_plated_hole\",\n ) as PcbPlatedHole[]\n\n const padMap = new Map<string, PcbSmtPad | PcbPlatedHole>()\n\n for (const pad of pcbSmtPads) {\n if (pad.pcb_port_id) {\n padMap.set(pad.pcb_port_id, pad)\n }\n }\n\n for (const hole of pcbPlatedHoles) {\n if (hole.pcb_port_id) {\n padMap.set(hole.pcb_port_id, hole)\n }\n }\n\n for (const trace of pcbTraces) {\n if (trace.route.length === 0) continue\n\n const firstPoint = trace.route[0]\n const lastPoint = trace.route[trace.route.length - 1]\n\n const sourceTrace = sourceTraces.find(\n (st) => st.source_trace_id === trace.source_trace_id,\n )\n\n const expectedPorts = sourceTrace\n ? pcbPorts.filter((port) =>\n sourceTrace.connected_source_port_ids?.includes(port.source_port_id),\n )\n : []\n\n for (let i = 1; i < trace.route.length - 1; i++) {\n const prevPoint = trace.route[i - 1]\n const currentPoint = trace.route[i]\n const nextPoint = trace.route[i + 1]\n\n if (currentPoint.route_type === \"via\") {\n const prevIsWire = prevPoint.route_type === \"wire\"\n const nextIsWire = nextPoint.route_type === \"wire\"\n\n if (prevIsWire && nextIsWire) {\n const prevAligned =\n Math.abs(prevPoint.x - currentPoint.x) < 0.001 &&\n Math.abs(prevPoint.y - currentPoint.y) < 0.001\n\n const nextAligned =\n Math.abs(nextPoint.x - currentPoint.x) < 0.001 &&\n Math.abs(nextPoint.y - currentPoint.y) < 0.001\n\n if (!prevAligned || !nextAligned) {\n const traceName =\n sourceTrace?.display_name || trace.source_trace_id || \"unknown\"\n errors.push({\n type: \"pcb_trace_error\",\n message: `Via in trace [${traceName}] is misaligned at position {x: ${currentPoint.x}, y: ${currentPoint.y}}.`,\n source_trace_id:\n sourceTrace?.source_trace_id ||\n trace.source_trace_id ||\n `!${trace.pcb_trace_id}`,\n error_type: \"pcb_trace_error\",\n pcb_trace_id: trace.pcb_trace_id,\n pcb_trace_error_id: \"\",\n pcb_component_ids: [],\n pcb_port_ids: [],\n })\n }\n }\n }\n }\n\n const traceName =\n sourceTrace?.display_name || trace.source_trace_id || \"unknown\"\n\n // For traces with known expected ports, check specific connections\n for (const port of expectedPorts) {\n if (!port.pcb_port_id) continue\n\n const pad = padMap.get(port.pcb_port_id)\n\n if (!pad) continue\n\n const isFirstPointConnected =\n firstPoint.route_type === \"wire\" &&\n isPointInPad({ x: firstPoint.x, y: firstPoint.y }, pad)\n\n const isLastPointConnected =\n lastPoint.route_type === \"wire\" &&\n isPointInPad({ x: lastPoint.x, y: lastPoint.y }, pad)\n\n if (!isFirstPointConnected && !isLastPointConnected) {\n const portName = getReadableNameForPcbPort(\n circuitJson,\n port.pcb_port_id,\n ).replace(\"pcb_port\", \"\")\n const padType = pad.type.replace(/pcb_/, \"\")\n // Use the midpoint between trace endpoints as error location\n const errorCenter = {\n x: (firstPoint.x + lastPoint.x) / 2,\n y: (firstPoint.y + lastPoint.y) / 2,\n }\n errors.push({\n type: \"pcb_trace_error\",\n message: `Trace [${traceName}] is missing a connection to ${padType}${portName}`,\n source_trace_id:\n sourceTrace?.source_trace_id ||\n trace.source_trace_id ||\n `!${trace.pcb_trace_id}`,\n error_type: \"pcb_trace_error\",\n pcb_trace_id: trace.pcb_trace_id,\n pcb_trace_error_id: \"\",\n center: errorCenter,\n pcb_component_ids: [],\n pcb_port_ids: [port.pcb_port_id],\n })\n }\n }\n\n // For net-level traces (no expected ports), check if endpoints are floating\n if (expectedPorts.length === 0) {\n let firstConnectsToAnyPad = false\n let lastConnectsToAnyPad = false\n\n for (const [portId, pad] of padMap) {\n if (\n firstPoint.route_type === \"wire\" &&\n isPointInPad({ x: firstPoint.x, y: firstPoint.y }, pad)\n ) {\n firstConnectsToAnyPad = true\n }\n if (\n lastPoint.route_type === \"wire\" &&\n isPointInPad({ x: lastPoint.x, y: lastPoint.y }, pad)\n ) {\n lastConnectsToAnyPad = true\n }\n }\n\n if (!firstConnectsToAnyPad && firstPoint.route_type === \"wire\") {\n errors.push({\n type: \"pcb_trace_error\",\n message: `Trace [${traceName}] has disconnected endpoint at (${firstPoint.x}, ${firstPoint.y})`,\n source_trace_id:\n sourceTrace?.source_trace_id ||\n trace.source_trace_id ||\n `!${trace.pcb_trace_id}`,\n error_type: \"pcb_trace_error\",\n pcb_trace_id: trace.pcb_trace_id,\n pcb_trace_error_id: \"\",\n center: { x: firstPoint.x, y: firstPoint.y },\n pcb_component_ids: [],\n pcb_port_ids: [],\n })\n }\n if (!lastConnectsToAnyPad && lastPoint.route_type === \"wire\") {\n errors.push({\n type: \"pcb_trace_error\",\n message: `Trace [${traceName}] has disconnected endpoint at (${lastPoint.x}, ${lastPoint.y})`,\n source_trace_id:\n sourceTrace?.source_trace_id ||\n trace.source_trace_id ||\n `!${trace.pcb_trace_id}`,\n error_type: \"pcb_trace_error\",\n pcb_trace_id: trace.pcb_trace_id,\n pcb_trace_error_id: \"\",\n center: { x: lastPoint.x, y: lastPoint.y },\n pcb_component_ids: [],\n pcb_port_ids: [],\n })\n }\n }\n }\n\n return errors\n}\n\nexport { checkTracesAreContiguous }\n","import { checkEachPcbPortConnectedToPcbTraces } from \"./check-each-pcb-port-connected-to-pcb-trace\"\nimport { checkEachPcbTraceNonOverlapping } from \"./check-each-pcb-trace-non-overlapping/check-each-pcb-trace-non-overlapping\"\nimport { checkSameNetViaSpacing } from \"./check-same-net-via-spacing\"\nimport { checkDifferentNetViaSpacing } from \"./check-different-net-via-spacing\"\nimport { checkViasOffBoard } from \"./check-pcb-components-out-of-board/checkViasOffBoard\"\nimport { checkPcbComponentsOutOfBoard } from \"./check-pcb-components-out-of-board/checkPcbComponentsOutOfBoard\"\nimport { checkTracesAreContiguous } from \"./check-traces-are-contiguous/check-traces-are-contiguous\"\nimport { checkSourceTracesHavePcbTraces } from \"./check-source-traces-have-pcb-traces\"\nimport { checkPcbTracesOutOfBoard } from \"./check-trace-out-of-board/checkTraceOutOfBoard\"\nimport { checkPcbComponentOverlap } from \"./check-pcb-components-overlap/checkPcbComponentOverlap\"\nimport { checkPinMustBeConnected } from \"./check-pin-must-be-connected\"\nimport type { AnyCircuitElement } from \"circuit-json\"\n\nexport async function runAllChecks(circuitJson: AnyCircuitElement[]) {\n return [\n ...checkEachPcbPortConnectedToPcbTraces(circuitJson),\n ...checkEachPcbTraceNonOverlapping(circuitJson),\n ...checkSameNetViaSpacing(circuitJson),\n ...checkDifferentNetViaSpacing(circuitJson),\n ...checkViasOffBoard(circuitJson),\n ...checkPcbComponentsOutOfBoard(circuitJson),\n ...checkTracesAreContiguous(circuitJson),\n ...checkSourceTracesHavePcbTraces(circuitJson),\n ...checkPcbTracesOutOfBoard(circuitJson),\n ...checkPcbComponentOverlap(circuitJson),\n ...checkPinMustBeConnected(circuitJson),\n ]\n}\n"],"mappings":"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","names":["getFullConnectivityMapFromCircuitJson","t","closestOnB","closestOnA","distance","clamp","dx","dy","getFullConnectivityMapFromCircuitJson","gap","distance","getReadableNameForElement","getReadableNameForElement","getReadableNameForElement","getReadableNameForElement","getFullConnectivityMapFromCircuitJson","distance","getFullConnectivityMapFromCircuitJson","getReadableNameForElement","getReadableNameForElement","getFullConnectivityMapFromCircuitJson","distance","getFullConnectivityMapFromCircuitJson","getReadableNameForElement","cju","segmentToSegmentMinDistance","distance","cju","getBoundsOfPcbElements","getPrimaryId","getFullConnectivityMapFromCircuitJson","distance","traceName"]}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@tscircuit/checks",
3
3
  "type": "module",
4
4
  "main": "./dist/index.js",
5
- "version": "0.0.86",
5
+ "version": "0.0.88",
6
6
  "files": [
7
7
  "dist"
8
8
  ],