@tscircuit/checks 0.0.207 → 0.0.208
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +179 -62
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../lib/check-copper-pour-shorts.ts","../node_modules/@tscircuit/circuit-json-to-flattenjs/lib/geometry.ts","../node_modules/@tscircuit/circuit-json-to-flattenjs/lib/layers.ts","../node_modules/@tscircuit/circuit-json-to-flattenjs/lib/pads.ts","../node_modules/@tscircuit/circuit-json-to-flattenjs/lib/traces.ts","../node_modules/@tscircuit/circuit-json-to-flattenjs/lib/convert.ts","../node_modules/@tscircuit/circuit-json-to-flattenjs/lib/polygon-to-svg.ts","../node_modules/@tscircuit/circuit-json-to-flattenjs/lib/render-svg.ts","../lib/util/create-indexed-pcb-connectivity-map.ts","../lib/check-traces-are-contiguous/is-point-in-pad.ts","../lib/check-each-pcb-trace-non-overlapping/segment-to-polygon-clearance.ts","../lib/add-start-and-end-port-ids-if-missing.ts","../lib/check-each-pcb-port-connected-to-pcb-trace.ts","../lib/util/get-readable-names.ts","../lib/copper-pour-connectivity/create-copper-polygon-contact-tester.ts","../lib/copper-pour-connectivity/get-copper-pour-connectivity.ts","../lib/check-each-pcb-trace-non-overlapping/check-each-pcb-trace-non-overlapping.ts","../lib/check-pad-clearance/common.ts","../node_modules/@tscircuit/jlcpcb-manufacturing-specs/lib/jlcpcb-manufacturing-specs.ts","../lib/drc-defaults.ts","../lib/data-structures/SpatialIndex.ts","../lib/util/getLayersOfPcbElement.ts","../lib/check-each-pcb-trace-non-overlapping/getClosestPointBetweenSegmentAndBounds.ts","../lib/check-each-pcb-trace-non-overlapping/getClosestPointBetweenSegments.ts","../lib/check-each-pcb-trace-non-overlapping/getCollidableBounds.ts","../lib/check-each-pcb-trace-non-overlapping/getPcbPortIdsConnectedToTraces.ts","../lib/check-each-pcb-trace-non-overlapping/getRadiusOfCircuitJsonElement.ts","../lib/net-manager.ts","../lib/check-pcb-components-out-of-board/checkViasOffBoard.ts","../lib/check-copper-to-board-edge-clearance.ts","../lib/check-pcb-components-out-of-board/checkPcbComponentsOutOfBoard.ts","../lib/check-pcb-component-over-cutout.ts","../lib/check-pcb-copper-over-keepout.ts","../lib/check-same-net-via-spacing.ts","../lib/util/distance.ts","../lib/util/viasAreAtSameLocation.ts","../lib/check-different-net-via-spacing.ts","../lib/check-source-traces-match-pcb-trace-thickness.ts","../lib/check-source-traces-have-pcb-traces.ts","../lib/check-traces-are-contiguous/check-traces-are-contiguous.ts","../lib/check-traces-are-contiguous/via-contact-index.ts","../lib/check-trace-out-of-board/checkTraceOutOfBoard.ts","../lib/check-pcb-components-overlap/checkPcbComponentOverlap.ts","../lib/check-pcb-components-overlap/doPcbElementsOverlap.ts","../lib/check-pcb-components-missing-courtyard.ts","../lib/util/get-pcb-trace-length.ts","../lib/check-pcb-trace-lengths.ts","../lib/check-pcb-trace-via-counts.ts","../lib/check-pad-pad-clearance.ts","../lib/check-pad-trace-clearance.ts","../lib/check-via-trace-clearance.ts","../lib/check-via-pad-clearance.ts","../lib/check-vias-in-pads.ts","../lib/dedupe-pcb-drc-errors.ts","../lib/check-pin-must-be-connected.ts","../lib/check-two-terminal-switch-contacts-on-different-nets.ts","../lib/check-all-pins-in-component-are-underspecified.ts","../lib/check-no-power-pin-defined.ts","../lib/util/should-check-chip-power-ground-pins.ts","../lib/check-no-ground-pin-defined.ts","../lib/check-schematic-component-excessive-vertical-padding.ts","../lib/check-schematic-component-missing-reference-designator-text.ts","../lib/check-schematic-component-ports-outside-body.ts","../lib/run-all-checks.ts","../lib/check-pcb-bus-length-skew.ts","../lib/consolidate-pcb-overlap-errors.ts","../lib/check-same-name-nets-are-connected.ts","../lib/check-connector-accessible-orientation.ts","../lib/check-courtyard-overlap/checkCourtyardOverlap.ts","../lib/check-testpoint-accessibility.ts"],"sourcesContent":["import Flatbush from \"flatbush\"\nimport * as Flatten from \"@flatten-js/core\"\nimport { getReadableNameForElement } from \"@tscircuit/circuit-json-util\"\nimport {\n convertCircuitJsonToFlattenJs,\n type FlattenElement,\n} from \"@tscircuit/circuit-json-to-flattenjs\"\nimport type { AnyCircuitElement, PcbPlacementError } from \"circuit-json\"\nimport {\n type ConnectivityMap,\n getFullConnectivityMapFromCircuitJson,\n} from \"circuit-json-to-connectivity-map\"\n\n/** Filled polygons include their holes, so copper wholly in a cutout is safe. */\nfunction touchesPour(\n pour: Flatten.Polygon,\n geometry: Flatten.Polygon,\n): boolean {\n if (!pour.box.intersect(geometry.box)) return false\n // distanceTo can report zero between tiny BRep segments and distant arcs.\n // Test actual boundary intersections and containment instead. Once boundaries\n // are disjoint, one point per face suffices; walking every pour vertex is costly.\n return (\n pour.intersect(geometry).length > 0 ||\n [...geometry.faces].some((face) => pour.contains(face.first.start)) ||\n [...pour.faces].some((face) => geometry.contains(face.first.start))\n )\n}\n\n/** Detect accidental copper contact, rather than enforcing a clearance margin. */\nexport function checkCopperPourShorts(\n circuitJson: AnyCircuitElement[],\n { connMap }: { connMap?: ConnectivityMap } = {},\n): PcbPlacementError[] {\n if (!circuitJson.some((e) => e.type === \"pcb_copper_pour\")) return []\n connMap ??= getFullConnectivityMapFromCircuitJson(circuitJson)\n const { elements: copper } = convertCircuitJsonToFlattenJs(circuitJson, {\n elementTypes: [\n \"pcb_smtpad\",\n \"pcb_plated_hole\",\n \"pcb_via\",\n \"pcb_trace\",\n \"pcb_copper_pour\",\n ],\n strict: true,\n })\n // Index individual shapes, not whole trace bounds, separately on each layer.\n // A long routed trace can have a large bounding box but few nearby segments.\n const layers = new Map<\n string | null,\n { element: FlattenElement; shape: Flatten.Polygon }[]\n >()\n for (const element of copper) {\n const entries = layers.get(element.layer) ?? []\n for (const shape of element.shapes) entries.push({ element, shape })\n layers.set(element.layer, entries)\n }\n const indexes = new Map(\n [...layers].map(([layer, entries]) => {\n const index = new Flatbush(entries.length)\n for (const { shape } of entries) {\n const b = shape.box\n index.add(b.xmin, b.ymin, b.xmax, b.ymax)\n }\n index.finish()\n return [layer, { index, entries }] as const\n }),\n )\n const netNames = new Map(\n circuitJson\n .filter((e) => e.type === \"source_net\")\n .map((e) => [e.source_net_id, e.name]),\n )\n const errors = new Map<string, PcbPlacementError>()\n for (const pour of copper) {\n const element = pour.sourceElement\n if (element.type !== \"pcb_copper_pour\") continue\n const netId = element.source_net_id\n const { index, entries } = indexes.get(pour.layer)!\n const candidates = new Set<number>()\n for (const shape of pour.shapes) {\n const b = shape.box\n for (const i of index.search(b.xmin, b.ymin, b.xmax, b.ymax))\n candidates.add(i)\n }\n // Preserve source order so error output is deterministic across index layouts.\n for (const i of [...candidates].sort((a, b) => a - b)) {\n const { element: other, shape: otherShape } = entries[i]\n if (pour.elementId === other.elementId) continue\n const otherNetId =\n other.sourceElement.type === \"pcb_copper_pour\"\n ? other.sourceElement.source_net_id\n : other.elementId\n if (\n netId &&\n otherNetId &&\n (netId === otherNetId || connMap.areIdsConnected(netId, otherNetId))\n )\n continue\n const id = `copper_pour_short_${[pour.elementId, other.elementId].sort().join(\"_\")}`\n if (\n errors.has(id) ||\n !pour.shapes.some((shape) => touchesPour(shape, otherShape))\n )\n continue\n errors.set(id, {\n type: \"pcb_placement_error\",\n pcb_placement_error_id: id,\n error_type: \"pcb_placement_error\",\n message: `Copper pour ${pour.elementId} (${netNames.get(netId!) ?? netId ?? \"unassigned net\"}) shorts to ${getReadableNameForElement(circuitJson, other.elementId)} (${other.elementId}) on ${pour.layer} (accidental copper contact)`,\n subcircuit_id: element.subcircuit_id,\n })\n }\n }\n return [...errors.values()]\n}\n","import * as F from \"@flatten-js/core\"\n\nexport type XY = { x: number; y: number }\nexport type Vertex = XY & { bulge?: number }\nconst EPS = 1e-9\nexport const point = (p: XY) => new F.Point(p.x, p.y)\n\nexport function positive(value: number, name: string): number {\n if (!Number.isFinite(value) || value <= 0)\n throw new Error(`${name} must be finite and positive`)\n return value\n}\n\nexport function circle(center: XY, radius: number): F.Polygon {\n positive(radius, \"radius\")\n return new F.Polygon(new F.Circle(point(center), radius))\n}\n\n/** Straight and circular edges, including two-vertex rings made of two arcs. */\nexport function ring(vertices: readonly Vertex[]): F.Polygon {\n const clean = vertices.filter(\n (p, i) => i === 0 || point(p).distanceTo(point(vertices[i - 1]))[0] > EPS,\n )\n if (\n clean.length > 1 &&\n point(clean[0]).distanceTo(point(clean.at(-1)!))[0] <= EPS\n )\n clean.pop()\n if (clean.length < 2)\n throw new Error(\"A ring needs at least two distinct vertices\")\n const edges: (F.Segment | F.Arc)[] = clean.map((a, i) => {\n const b = clean[(i + 1) % clean.length]\n if (![a.x, a.y, a.bulge ?? 0].every(Number.isFinite))\n throw new Error(\"Non-finite ring vertex\")\n const bulge = a.bulge ?? 0\n if (Math.abs(bulge) <= EPS) return new F.Segment(point(a), point(b))\n const dx = b.x - a.x,\n dy = b.y - a.y\n const length = Math.hypot(dx, dy)\n const offset = (length * (1 - bulge * bulge)) / (4 * bulge)\n const center = new F.Point(\n (a.x + b.x) / 2 - (dy / length) * offset,\n (a.y + b.y) / 2 + (dx / length) * offset,\n )\n return new F.Arc(\n center,\n (length * (1 + bulge * bulge)) / (4 * Math.abs(bulge)),\n Math.atan2(a.y - center.y, a.x - center.x),\n Math.atan2(b.y - center.y, b.x - center.x),\n bulge > 0,\n )\n })\n const polygon = new F.Polygon()\n polygon.addFace(edges)\n if (polygon.area() <= EPS)\n throw new Error(\"A ring must enclose a non-zero area\")\n return polygon\n}\n\n/** Exact rounded boundary: one face, not overlapping bands and circles. */\nexport function rectangle(\n center: XY,\n width: number,\n height: number,\n rotation = 0,\n radius = 0,\n): F.Polygon {\n positive(width, \"width\")\n positive(height, \"height\")\n if (!Number.isFinite(rotation) || !Number.isFinite(radius) || radius < 0)\n throw new Error(\"Invalid rectangle rotation or corner radius\")\n const r = Math.min(radius, width / 2, height / 2)\n const x = width / 2,\n y = height / 2\n let polygon: F.Polygon\n if (r <= EPS)\n polygon = ring([\n { x: -x, y: -y },\n { x, y: -y },\n { x, y },\n { x: -x, y },\n ])\n else {\n const corners = [\n new F.Point(x - r, -y + r),\n new F.Point(x - r, y - r),\n new F.Point(-x + r, y - r),\n new F.Point(-x + r, -y + r),\n ]\n const edges: (F.Arc | F.Segment)[] = []\n for (let i = 0; i < 4; i++) {\n const angle = -Math.PI / 2 + (i * Math.PI) / 2\n const arc = new F.Arc(corners[i], r, angle, angle + Math.PI / 2, true)\n const next = corners[(i + 1) % 4]\n const nextStart = new F.Point(\n next.x + r * Math.cos(angle + Math.PI / 2),\n next.y + r * Math.sin(angle + Math.PI / 2),\n )\n edges.push(arc)\n if (arc.end.distanceTo(nextStart)[0] > EPS)\n edges.push(new F.Segment(arc.end, nextStart))\n }\n polygon = new F.Polygon()\n polygon.addFace(edges)\n }\n return polygon\n .rotate((rotation * Math.PI) / 180)\n .translate(new F.Vector(center.x, center.y))\n}\n\n/** Capsule / convex hull of endpoint discs. Equal radii give a round trace. */\nexport function stroke(\n a: XY,\n b: XY,\n widthA: number,\n widthB = widthA,\n): F.Polygon {\n const r1 = positive(widthA, \"trace width\") / 2,\n r2 = positive(widthB, \"trace width\") / 2\n const d = point(a).distanceTo(point(b))[0]\n if (d <= Math.abs(r1 - r2) + EPS)\n return circle(r1 >= r2 ? a : b, Math.max(r1, r2))\n const theta = Math.atan2(b.y - a.y, b.x - a.x)\n const alpha = Math.acos((r1 - r2) / d)\n const low = theta - alpha,\n high = theta + alpha\n const p = (c: XY, r: number, angle: number) =>\n new F.Point(c.x + r * Math.cos(angle), c.y + r * Math.sin(angle))\n const polygon = new F.Polygon()\n polygon.addFace([\n new F.Segment(p(a, r1, low), p(b, r2, low)),\n new F.Arc(point(b), r2, low, high, true),\n new F.Segment(p(b, r2, high), p(a, r1, high)),\n new F.Arc(point(a), r1, high, low, true),\n ])\n return polygon\n}\n\n/** Add an interior void with winding opposite to the outer boundary. */\nexport function withHoles(\n outer: F.Polygon,\n holes: readonly F.Polygon[],\n): F.Polygon {\n const result = outer.clone()\n const orientation = [...result.faces][0].orientation()\n for (const hole of holes) {\n const copy = hole.clone()\n if ([...copy.faces][0].orientation() === orientation) copy.reverse()\n for (const face of copy.faces) result.addFace(face.shapes)\n }\n return result\n}\n\n/** FlattenJS has no ellipse primitive. Bound chord error in millimetres. */\nexport function ellipse(\n center: XY,\n width: number,\n height: number,\n rotation = 0,\n tolerance = 0.001,\n): F.Polygon {\n positive(width, \"ellipse width\")\n positive(height, \"ellipse height\")\n positive(tolerance, \"curveTolerance\")\n if (Math.abs(width - height) < EPS) return circle(center, width / 2)\n const radius = Math.max(width, height) / 2\n const count = Math.max(\n 16,\n Math.ceil(Math.PI / Math.acos(Math.max(-1, 1 - tolerance / radius))),\n )\n if (count > 100000)\n throw new Error(\"curveTolerance requires more than 100000 ellipse segments\")\n return ring(\n Array.from({ length: count }, (_, i) => ({\n x: (width / 2) * Math.cos((i * 2 * Math.PI) / count),\n y: (height / 2) * Math.sin((i * 2 * Math.PI) / count),\n })),\n )\n .rotate((rotation * Math.PI) / 180)\n .translate(new F.Vector(center.x, center.y))\n}\n","import type { AnyCircuitElement, LayerRef } from \"circuit-json\"\nimport type { ConversionOptions } from \"./types\"\n\nexport function getCopperLayers(\n json: readonly AnyCircuitElement[],\n options: ConversionOptions,\n): LayerRef[] {\n if (options.copperLayers) {\n if (\n !options.copperLayers.length ||\n new Set(options.copperLayers).size !== options.copperLayers.length\n )\n throw new Error(\n \"copperLayers must be a non-empty list without duplicates\",\n )\n return [...options.copperLayers]\n }\n const board = json.find((e) => e.type === \"pcb_board\")\n let count = board?.num_layers ?? 2\n for (const element of json) {\n const layers =\n \"layers\" in element\n ? element.layers\n : \"layer\" in element\n ? [element.layer]\n : []\n if (Array.isArray(layers))\n for (const layer of layers) {\n const match = typeof layer === \"string\" && /^inner(\\d+)$/.exec(layer)\n if (match) count = Math.max(count, Number(match[1]) + 2)\n }\n if (element.type === \"pcb_trace\")\n for (const p of element.route) {\n for (const layer of p.route_type === \"wire\"\n ? [p.layer]\n : p.route_type === \"via\"\n ? [p.from_layer, p.to_layer]\n : [p.start_layer, p.end_layer]) {\n const match = /^inner(\\d+)$/.exec(layer)\n if (match) count = Math.max(count, Number(match[1]) + 2)\n }\n }\n }\n if (!Number.isInteger(count) || count < 1 || count > 10)\n throw new Error(\"Supported copper layer count is 1–10\")\n return count === 1\n ? [\"top\"]\n : [\n \"top\",\n ...Array.from(\n { length: count - 2 },\n (_, i) => `inner${i + 1}` as LayerRef,\n ),\n \"bottom\",\n ]\n}\n\n/** Through copper spans the physical stack between its outermost named layers. */\nexport function spanLayers(\n layers: readonly string[],\n stack: readonly LayerRef[],\n): string[] {\n if (!layers.length) return []\n const indices = layers.map((layer) => stack.indexOf(layer as LayerRef))\n if (indices.some((i) => i < 0))\n throw new Error(`Layer is missing from copperLayers: ${layers.join(\", \")}`)\n return stack.slice(Math.min(...indices), Math.max(...indices) + 1)\n}\n","import { Vector, type Polygon } from \"@flatten-js/core\"\nimport type { PcbPlatedHole, PcbSmtPad, PcbHole } from \"circuit-json\"\nimport { circle, ellipse, rectangle, ring, withHoles } from \"./geometry\"\n\nexport function smtPad(pad: PcbSmtPad): Polygon {\n switch (pad.shape) {\n case \"circle\":\n return circle(pad, pad.radius)\n case \"polygon\":\n return ring(pad.points)\n case \"rect\":\n case \"rotated_rect\":\n return rectangle(\n pad,\n pad.width,\n pad.height,\n \"ccw_rotation\" in pad ? pad.ccw_rotation : 0,\n pad.rect_border_radius ?? pad.corner_radius ?? 0,\n )\n case \"pill\":\n case \"rotated_pill\":\n return rectangle(\n pad,\n pad.width,\n pad.height,\n \"ccw_rotation\" in pad ? pad.ccw_rotation : 0,\n pad.radius,\n )\n }\n}\n\nexport function nonPlatedHole(hole: PcbHole, tolerance: number): Polygon {\n switch (hole.hole_shape) {\n case \"circle\":\n return circle(hole, hole.hole_diameter / 2)\n case \"square\":\n return rectangle(hole, hole.hole_diameter, hole.hole_diameter)\n case \"rect\":\n return rectangle(hole, hole.hole_width, hole.hole_height)\n case \"oval\":\n return ellipse(hole, hole.hole_width, hole.hole_height, 0, tolerance)\n case \"pill\":\n case \"rotated_pill\":\n return rectangle(\n hole,\n hole.hole_width,\n hole.hole_height,\n \"ccw_rotation\" in hole ? hole.ccw_rotation : 0,\n Math.min(hole.hole_width, hole.hole_height) / 2,\n )\n }\n}\n\nexport function platedHole(\n hole: PcbPlatedHole,\n componentRotation: number,\n includeDrill: boolean,\n tolerance: number,\n): Polygon {\n let outer: Polygon\n let drill: Polygon\n const drillCenter = {\n x: hole.x + (\"hole_offset_x\" in hole ? (hole.hole_offset_x ?? 0) : 0),\n y: hole.y + (\"hole_offset_y\" in hole ? (hole.hole_offset_y ?? 0) : 0),\n }\n switch (hole.shape) {\n case \"circle\":\n outer = circle(hole, hole.outer_diameter / 2)\n drill = circle(hole, hole.hole_diameter / 2)\n break\n case \"oval\":\n outer = ellipse(\n hole,\n hole.outer_width,\n hole.outer_height,\n hole.ccw_rotation,\n tolerance,\n )\n drill = ellipse(\n hole,\n hole.hole_width,\n hole.hole_height,\n hole.ccw_rotation,\n tolerance,\n )\n break\n case \"pill\":\n outer = rectangle(\n hole,\n hole.outer_width,\n hole.outer_height,\n hole.ccw_rotation,\n Math.min(hole.outer_width, hole.outer_height) / 2,\n )\n drill = rectangle(\n hole,\n hole.hole_width,\n hole.hole_height,\n hole.ccw_rotation,\n Math.min(hole.hole_width, hole.hole_height) / 2,\n )\n break\n case \"circular_hole_with_rect_pad\":\n case \"pill_hole_with_rect_pad\":\n case \"rotated_pill_hole_with_rect_pad\":\n outer = rectangle(\n hole,\n hole.rect_pad_width,\n hole.rect_pad_height,\n \"rect_ccw_rotation\" in hole ? hole.rect_ccw_rotation : 0,\n hole.rect_border_radius ?? 0,\n )\n drill =\n hole.shape === \"circular_hole_with_rect_pad\"\n ? circle(drillCenter, hole.hole_diameter / 2)\n : rectangle(\n drillCenter,\n hole.hole_width,\n hole.hole_height,\n \"hole_ccw_rotation\" in hole ? hole.hole_ccw_rotation : 0,\n Math.min(hole.hole_width, hole.hole_height) / 2,\n )\n break\n case \"hole_with_polygon_pad\": {\n const rotation = hole.ccw_rotation ?? componentRotation\n outer = ring(hole.pad_outline)\n .rotate((rotation * Math.PI) / 180)\n .translate(new Vector(hole.x, hole.y))\n drill =\n hole.hole_shape === \"circle\"\n ? circle(drillCenter, hole.hole_diameter! / 2)\n : hole.hole_shape === \"oval\"\n ? ellipse(\n drillCenter,\n hole.hole_width!,\n hole.hole_height!,\n rotation,\n tolerance,\n )\n : rectangle(\n drillCenter,\n hole.hole_width!,\n hole.hole_height!,\n rotation,\n Math.min(hole.hole_width!, hole.hole_height!) / 2,\n )\n break\n }\n }\n return includeDrill ? withHoles(outer, [drill]) : outer\n}\n","import { BooleanOperations, type Polygon } from \"@flatten-js/core\"\nimport type { LayerRef, PcbTrace } from \"circuit-json\"\nimport { circle, ring, stroke, withHoles, positive, type XY } from \"./geometry\"\nimport { spanLayers } from \"./layers\"\n\ntype TraceSegment = {\n start: XY\n end: XY\n layer: string\n startWidth: number\n endWidth: number\n}\nconst samePoint = (a: XY, b: XY) => a.x === b.x && a.y === b.y\nconst unit = (x: number, y: number) => {\n const length = Math.hypot(x, y)\n return length ? { x: x / length, y: y / length } : { x: 1, y: 0 }\n}\n\n/** Interpolated traces use flat caps and averaged directions at bends. */\nfunction interpolatedPolygon(segments: TraceSegment[]): Polygon {\n const points = [\n { ...segments[0].start, width: segments[0].startWidth },\n ...segments.map((s) => ({ ...s.end, width: s.endWidth })),\n ]\n const directions = segments.map((s) =>\n unit(s.end.x - s.start.x, s.end.y - s.start.y),\n )\n const left: XY[] = [],\n right: XY[] = []\n for (let i = 0; i < points.length; i++) {\n const p = points[i]\n positive(p.width, \"interpolated trace width\")\n const before = directions[Math.max(0, i - 1)],\n after = directions[Math.min(i, directions.length - 1)]\n const d = unit(before.x + after.x, before.y + after.y)\n const nx = (-d.y * p.width) / 2,\n ny = (d.x * p.width) / 2\n left.push({ x: p.x + nx, y: p.y + ny })\n right.push({ x: p.x - nx, y: p.y - ny })\n }\n return ring([...left, ...right.reverse()])\n}\n\nexport function traceGeometry(\n trace: PcbTrace,\n stack: readonly LayerRef[],\n includeDrill: boolean,\n): Map<string, Polygon[]> {\n const result = new Map<string, Polygon[]>()\n const drills = new Map<string, Polygon[]>()\n const segments: TraceSegment[] = []\n const add = (layer: string, shape: Polygon) =>\n result.set(layer, [...(result.get(layer) ?? []), shape])\n for (const p of trace.route) {\n if (p.route_type === \"via\") {\n const legacy = p as typeof p & {\n via_diameter?: number\n via_hole_diameter?: number\n }\n const outerDiameter = p.outer_diameter ?? legacy.via_diameter\n if (outerDiameter === undefined) continue\n const holeDiameter = p.hole_diameter ?? legacy.via_hole_diameter\n const shape = circle(p, outerDiameter / 2)\n const drill =\n includeDrill && holeDiameter ? circle(p, holeDiameter / 2) : undefined\n for (const layer of spanLayers([p.from_layer, p.to_layer], stack)) {\n add(layer, drill ? withHoles(shape, [drill]) : shape)\n if (drill) drills.set(layer, [...(drills.get(layer) ?? []), drill])\n }\n }\n if (p.route_type === \"through_pad\") {\n for (const layer of new Set([p.start_layer, p.end_layer]))\n add(layer, stroke(p.start, p.end, p.width))\n }\n }\n for (let i = 0; i < trace.route.length - 1; i++) {\n const a = trace.route[i],\n b = trace.route[i + 1]\n const start = a.route_type === \"through_pad\" ? a.end : a\n const end = b.route_type === \"through_pad\" ? b.start : b\n if (samePoint(start, end)) continue\n // Via from/to fields describe its span, not the direction of route traversal.\n const startLayers =\n a.route_type === \"wire\"\n ? [a.layer]\n : a.route_type === \"via\"\n ? spanLayers([a.from_layer, a.to_layer], stack)\n : [a.end_layer]\n const endLayers =\n b.route_type === \"wire\"\n ? [b.layer]\n : b.route_type === \"via\"\n ? spanLayers([b.from_layer, b.to_layer], stack)\n : [b.start_layer]\n const sharedLayers = startLayers.filter((layer) =>\n endLayers.includes(layer as never),\n )\n if (sharedLayers.length !== 1)\n throw new Error(\n `Cannot determine one wire layer between route points ${i} and ${i + 1}`,\n )\n const startLayer = sharedLayers[0]\n const width = \"width\" in a ? a.width : \"width\" in b ? b.width : undefined\n if (width === undefined || samePoint(start, end)) continue\n segments.push({\n start,\n end,\n layer: startLayer,\n startWidth: width,\n endWidth: \"width\" in b ? b.width : width,\n })\n }\n if (trace.route_thickness_mode === \"interpolated\") {\n let group: TraceSegment[] = []\n const flush = () => {\n if (group.length) {\n add(group[0].layer, interpolatedPolygon(group))\n group = []\n }\n }\n for (const segment of segments) {\n const last = group.at(-1)\n if (\n last &&\n (last.layer !== segment.layer ||\n !samePoint(last.end, segment.start) ||\n last.endWidth !== segment.startWidth)\n )\n flush()\n group.push(segment)\n }\n flush()\n } else\n for (const s of segments) add(s.layer, stroke(s.start, s.end, s.startWidth))\n // Drilling removes material from the adjoining wire as well as the annular pad.\n for (const [layer, holes] of drills) {\n result.set(\n layer,\n result\n .get(layer)!\n .map((shape) =>\n holes.reduce(\n (shape, hole) => BooleanOperations.subtract(shape, hole),\n shape,\n ),\n )\n .filter((shape) => shape.faces.size > 0),\n )\n }\n return result\n}\n","import type { Polygon } from \"@flatten-js/core\"\nimport type { AnyCircuitElement, PcbCutout } from \"circuit-json\"\nimport { circle, rectangle, ring, stroke, withHoles } from \"./geometry\"\nimport { getCopperLayers, spanLayers } from \"./layers\"\nimport { nonPlatedHole, platedHole, smtPad } from \"./pads\"\nimport { traceGeometry } from \"./traces\"\nimport type {\n ConversionOptions,\n FlattenConversionResult,\n FlattenElement,\n GeometryRole,\n} from \"./types\"\n\nexport const supportedElementTypes = [\n \"pcb_board\",\n \"pcb_smtpad\",\n \"pcb_plated_hole\",\n \"pcb_hole\",\n \"pcb_via\",\n \"pcb_trace\",\n \"pcb_copper_pour\",\n \"pcb_cutout\",\n \"pcb_keepout\",\n \"pcb_courtyard_rect\",\n \"pcb_courtyard_circle\",\n \"pcb_courtyard_pill\",\n \"pcb_courtyard_polygon\",\n \"pcb_courtyard_outline\",\n] as const\n\nfunction cutoutGeometry(cutout: PcbCutout): Polygon[] {\n switch (cutout.shape) {\n case \"circle\":\n return [circle(cutout.center, cutout.radius)]\n case \"rect\":\n return [\n rectangle(\n cutout.center,\n cutout.width,\n cutout.height,\n cutout.rotation,\n cutout.corner_radius,\n ),\n ]\n case \"polygon\":\n return [ring(cutout.points)]\n case \"path\": {\n if (\n cutout.slot_length !== undefined ||\n cutout.space_between_slots !== undefined ||\n cutout.slot_corner_radius !== undefined\n ) {\n throw new Error(\n \"Patterned/custom-corner path cutouts are not supported; use explicit rect/polygon cutouts\",\n )\n }\n return cutout.route\n .slice(1)\n .map((p, i) => stroke(cutout.route[i], p, cutout.slot_width))\n }\n }\n}\n\nexport function convertCircuitJsonToFlattenJs(\n json: readonly AnyCircuitElement[],\n options: ConversionOptions = {},\n): FlattenConversionResult {\n if (options.layer && options.layers)\n throw new Error(\"Specify layer or layers, not both\")\n const selectedLayers = options.layer ? [options.layer] : options.layers\n const stack = getCopperLayers(json, options)\n const result: FlattenConversionResult = {\n elements: [],\n warnings: [],\n bounds: undefined,\n copperLayers: stack,\n }\n const rotations = new Map(\n json\n .filter((e) => e.type === \"pcb_component\")\n .map((e) => [e.pcb_component_id, e.rotation]),\n )\n const tolerance = options.curveTolerance ?? 0.001\n if (!Number.isFinite(tolerance) || tolerance <= 0)\n throw new Error(\"curveTolerance must be finite and positive\")\n const includeDrill = options.includeDrillHoles !== false\n for (const element of json) {\n if (!(supportedElementTypes as readonly string[]).includes(element.type))\n continue\n const elementId = (element as unknown as Record<string, unknown>)[\n `${element.type}_id`\n ] as string\n if (options.elementTypes && !options.elementTypes.includes(element.type))\n continue\n if (options.elementIds && !options.elementIds.includes(elementId)) continue\n let role: GeometryRole = \"copper\"\n let layers: (string | null)[] = [null]\n let shapes: Polygon[] = []\n let byLayer: Map<string, Polygon[]> | undefined\n try {\n switch (element.type) {\n case \"pcb_smtpad\":\n layers = [element.layer]\n shapes = [smtPad(element)]\n break\n case \"pcb_plated_hole\":\n layers = spanLayers(element.layers, stack)\n shapes = [\n platedHole(\n element,\n rotations.get(element.pcb_component_id ?? \"\") ?? 0,\n includeDrill,\n tolerance,\n ),\n ]\n break\n case \"pcb_via\": {\n layers = spanLayers(element.layers, stack)\n const outer = circle(element, element.outer_diameter / 2)\n shapes = [\n includeDrill\n ? withHoles(outer, [circle(element, element.hole_diameter / 2)])\n : outer,\n ]\n break\n }\n case \"pcb_trace\":\n byLayer = traceGeometry(element, stack, includeDrill)\n layers = [...byLayer.keys()]\n break\n case \"pcb_copper_pour\":\n layers = [element.layer]\n shapes = [\n element.shape === \"rect\"\n ? rectangle(\n element.center,\n element.width,\n element.height,\n element.rotation,\n )\n : element.shape === \"polygon\"\n ? ring(element.points)\n : withHoles(\n ring(element.brep_shape.outer_ring.vertices),\n element.brep_shape.inner_rings.map(\n (h: { vertices: import(\"./geometry\").Vertex[] }) =>\n ring(h.vertices),\n ),\n ),\n ]\n break\n case \"pcb_board\":\n role = \"board\"\n shapes = [\n element.outline?.length\n ? ring(element.outline)\n : rectangle(element.center, element.width!, element.height!),\n ]\n break\n case \"pcb_hole\":\n role = \"drill\"\n shapes = [nonPlatedHole(element, tolerance)]\n break\n case \"pcb_cutout\":\n role = \"cutout\"\n shapes = cutoutGeometry(element)\n break\n case \"pcb_keepout\":\n role = \"keepout\"\n layers = element.layers\n shapes = [\n element.shape === \"circle\"\n ? circle(element.center, element.radius)\n : element.shape === \"rect\"\n ? rectangle(element.center, element.width, element.height)\n : ring(element.outline),\n ]\n break\n case \"pcb_courtyard_rect\":\n role = \"courtyard\"\n layers = [element.layer]\n shapes = [\n rectangle(\n element.center,\n element.width,\n element.height,\n element.ccw_rotation,\n ),\n ]\n break\n case \"pcb_courtyard_circle\":\n role = \"courtyard\"\n layers = [element.layer]\n shapes = [circle(element.center, element.radius)]\n break\n case \"pcb_courtyard_pill\":\n role = \"courtyard\"\n layers = [element.layer]\n shapes = [\n rectangle(\n element.center,\n element.width,\n element.height,\n 0,\n element.radius,\n ),\n ]\n break\n case \"pcb_courtyard_polygon\":\n role = \"courtyard\"\n layers = [element.layer]\n shapes = [ring(element.points)]\n break\n case \"pcb_courtyard_outline\":\n role = \"courtyard\"\n layers = [element.layer]\n shapes = [ring(element.outline)]\n break\n }\n if (options.roles && !options.roles.includes(role)) continue\n const convertedElements: FlattenElement[] = []\n for (const layer of new Set(layers)) {\n if (\n layer === null\n ? options.includeLayerless === false\n : selectedLayers && !selectedLayers.includes(layer as never)\n )\n continue\n const layerShapes = byLayer?.get(layer!) ?? shapes\n if (!layerShapes.length) continue\n const bounds = layerShapes.reduce(\n (box, shape) => box.merge(shape.box),\n layerShapes[0].box,\n )\n if (\n ![bounds.xmin, bounds.ymin, bounds.xmax, bounds.ymax].every(\n Number.isFinite,\n )\n )\n throw new Error(\"Non-finite geometry bounds\")\n const converted: FlattenElement = {\n elementId,\n elementType: element.type,\n sourceElement: element,\n role,\n layer,\n shapes: layerShapes,\n bounds,\n }\n convertedElements.push(converted)\n }\n for (const converted of convertedElements) {\n result.elements.push(converted)\n result.bounds = result.bounds\n ? result.bounds.merge(converted.bounds)\n : converted.bounds\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n if (options.strict) throw new Error(`${elementId}: ${message}`)\n result.warnings.push({ elementId, elementType: element.type, message })\n }\n }\n return result\n}\n\n/** Provide the enclosing circuit for board stackup and component-local polygon pads. */\nexport function convertCircuitJsonElementToFlattenJs(\n element: AnyCircuitElement,\n options: ConversionOptions & {\n circuitJson?: readonly AnyCircuitElement[]\n } = {},\n): FlattenConversionResult {\n const { circuitJson = [], ...conversionOptions } = options\n const id = (element as unknown as Record<string, unknown>)[\n `${element.type}_id`\n ] as string\n const context = circuitJson.filter(\n (e) =>\n e !== element &&\n (e as unknown as Record<string, unknown>)[`${e.type}_id`] !== id,\n )\n return convertCircuitJsonToFlattenJs([...context, element], {\n ...conversionOptions,\n elementIds: [id],\n })\n}\n","import { Arc, type Polygon, type Point } from \"@flatten-js/core\"\n\n// SVG precision is intentionally separate from the full-precision geometry.\n// Normalize -0 and libm rounding differences across supported JS platforms.\nconst number = (value: number) => String(Number(value.toFixed(8)))\nconst point = (p: Point) => `${number(p.x)},${number(p.y)}`\n\nexport function polygonToSvg(\n polygon: Polygon,\n attrs: { fill: string; stroke: string; strokeWidth?: number },\n): string {\n const paths = [...polygon.faces].map((face) => {\n const edges = face.shapes\n if (!edges.length) return \"\"\n const commands = [`M${point(edges[0].start)}`]\n for (const shape of edges) {\n if (shape instanceof Arc) {\n const sweep = shape.counterClockwise ? 1 : 0\n const arc = (end: Point, large = 0) =>\n `A${number(shape.r)},${number(shape.r)} 0 ${large},${sweep} ${point(end)}`\n if (shape.sweep >= 2 * Math.PI - 1e-9) {\n commands.push(arc(shape.middle()), arc(shape.end))\n } else {\n // A semicircle can land just above pi on one platform and below on\n // another. Either flag draws it identically, so canonicalize it.\n commands.push(arc(shape.end, shape.sweep > Math.PI + 1e-9 ? 1 : 0))\n }\n } else commands.push(`L${point(shape.end)}`)\n }\n return `${commands.join(\" \")} Z`\n })\n return `<path fill=\"${attrs.fill}\" stroke=\"${attrs.stroke}\" stroke-width=\"${attrs.strokeWidth ?? 0}\" fill-rule=\"evenodd\" d=\"${paths.join(\" \")}\"/>`\n}\n","import { polygonToSvg } from \"./polygon-to-svg\"\nimport type { FlattenConversionResult, GeometryRole } from \"./types\"\nexport interface FlattenSvgOptions {\n width?: number\n height?: number\n padding?: number\n background?: string\n viewport?: { minX: number; minY: number; maxX: number; maxY: number }\n colors?: Partial<Record<GeometryRole, string>>\n}\nconst escape = (text: string) =>\n text\n .replaceAll(\"&\", \"&\")\n .replaceAll('\"', \""\")\n .replaceAll(\"<\", \"<\")\n .replaceAll(\">\", \">\")\n\n/** SVG generated only from FlattenJS polygons; +Y remains up in circuit coordinates. */\nexport function renderFlattenJsToSvg(\n result: FlattenConversionResult,\n options: FlattenSvgOptions = {},\n): string {\n const width = options.width ?? 500,\n height = options.height ?? 360\n const padding = options.padding ?? 1\n const b = result.bounds\n const v = options.viewport ?? {\n minX: (b?.xmin ?? -1) - padding,\n minY: (b?.ymin ?? -1) - padding,\n maxX: (b?.xmax ?? 1) + padding,\n maxY: (b?.ymax ?? 1) + padding,\n }\n const colors = {\n copper: \"#c87828\",\n board: \"#59726b\",\n drill: \"#0b1018\",\n cutout: \"#0b1018\",\n keepout: \"#e85872\",\n courtyard: \"#a879e8\",\n ...options.colors,\n }\n const order: GeometryRole[] = [\n \"board\",\n \"copper\",\n \"keepout\",\n \"courtyard\",\n \"drill\",\n \"cutout\",\n ]\n const content = [...result.elements]\n .sort((a, b) => order.indexOf(a.role) - order.indexOf(b.role))\n .map((e) => {\n const outline = e.role === \"board\" || e.role === \"courtyard\"\n const attrs = {\n fill: outline ? \"none\" : escape(colors[e.role]),\n stroke: outline ? escape(colors[e.role]) : \"none\",\n strokeWidth: e.role === \"courtyard\" ? 0.05 : 0.1,\n fillRule: \"evenodd\" as const,\n }\n return `<g data-element-id=\"${escape(e.elementId)}\" data-layer=\"${escape(e.layer ?? \"all\")}\">${e.shapes.map((shape) => polygonToSvg(shape, attrs)).join(\"\")}</g>`\n })\n .join(\"\")\n // Display drilled voids using the drill color without changing polygon topology.\n const drillVoids = result.elements\n .filter((e) =>\n [\"pcb_via\", \"pcb_plated_hole\", \"pcb_trace\"].includes(e.elementType),\n )\n .flatMap((e) =>\n e.shapes.flatMap((shape) => {\n const faces = [...shape.faces]\n if (faces.length < 2) return []\n const outerOrientation = faces[0].orientation()\n return faces\n .filter((face) => face.orientation() !== outerOrientation)\n .map((face) =>\n polygonToSvg(face.toPolygon(), {\n fill: escape(colors.drill),\n stroke: \"none\",\n }),\n )\n }),\n )\n .join(\"\")\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${width}\" height=\"${height}\" viewBox=\"${v.minX} ${-v.maxY} ${v.maxX - v.minX} ${v.maxY - v.minY}\"><rect x=\"${v.minX}\" y=\"${-v.maxY}\" width=\"${v.maxX - v.minX}\" height=\"${v.maxY - v.minY}\" fill=\"${escape(options.background ?? \"#0b1018\")}\"/><g transform=\"scale(1,-1)\">${content}${drillVoids}</g></svg>`\n}\n","import type { AnyCircuitElement } from \"circuit-json\"\nimport {\n ConnectivityMap,\n findConnectedNetworks,\n PcbConnectivityMap,\n} from \"circuit-json-to-connectivity-map\"\nimport Flatbush from \"flatbush\"\n\ntype TraceBounds = {\n traceIndex: number\n minX: number\n minY: number\n maxX: number\n maxY: number\n}\n\n/** Same physical connectivity as PcbConnectivityMap, with spatial candidate lookup. */\nexport function createIndexedPcbConnectivityMap(\n circuitJson: AnyCircuitElement[],\n): PcbConnectivityMap {\n // Construct empty to avoid the dependency's all-pairs scan. Keep its exact\n // intersection predicate and query methods, including cross-net contacts.\n const map = new PcbConnectivityMap()\n map.circuitJson = circuitJson\n for (const element of circuitJson) {\n if (element.type === \"pcb_trace\") {\n map.traceIdToElm.set(element.pcb_trace_id, element)\n } else if (element.type === \"pcb_port\") {\n map.portIdToElm.set(element.pcb_port_id, element)\n }\n }\n const traces = [...map.traceIdToElm.values()]\n const boundsByLayer = new Map<string, TraceBounds[]>()\n for (const [traceIndex, trace] of traces.entries()) {\n const boundsForTrace = new Map<string, TraceBounds>()\n for (let i = 0; i < trace.route.length - 1; i++) {\n const a = trace.route[i]\n const b = trace.route[i + 1]\n if (\n a.route_type !== \"wire\" ||\n b.route_type !== \"wire\" ||\n a.layer !== b.layer\n )\n continue\n const bounds = boundsForTrace.get(a.layer) ?? {\n traceIndex,\n minX: Infinity,\n minY: Infinity,\n maxX: -Infinity,\n maxY: -Infinity,\n }\n // The exact predicate uses the first point's width for each segment.\n // A small conservative margin avoids excluding contacts at rounding boundaries.\n const radius = a.width / 2 + 1e-9\n bounds.minX = Math.min(bounds.minX, a.x - radius, b.x - radius)\n bounds.minY = Math.min(bounds.minY, a.y - radius, b.y - radius)\n bounds.maxX = Math.max(bounds.maxX, a.x + radius, b.x + radius)\n bounds.maxY = Math.max(bounds.maxY, a.y + radius, b.y + radius)\n boundsForTrace.set(a.layer, bounds)\n }\n for (const [layer, bounds] of boundsForTrace) {\n const entries = boundsByLayer.get(layer) ?? []\n entries.push(bounds)\n boundsByLayer.set(layer, entries)\n }\n }\n const candidates = traces.map(() => new Set<number>())\n for (const bounds of boundsByLayer.values()) {\n const index = new Flatbush(bounds.length)\n for (const box of bounds) index.add(box.minX, box.minY, box.maxX, box.maxY)\n index.finish()\n for (const box of bounds) {\n for (const hit of index.search(box.minX, box.minY, box.maxX, box.maxY)) {\n const other = bounds[hit].traceIndex\n if (other > box.traceIndex) candidates[box.traceIndex].add(other)\n }\n }\n }\n const connections: string[][] = []\n // Preserve the original pair order for stable net IDs and diagnostics.\n for (const [i, neighbors] of candidates.entries()) {\n for (const j of [...neighbors].sort((a, b) => a - b)) {\n if (map._arePcbTracesConnected(traces[i], traces[j])) {\n connections.push([traces[i].pcb_trace_id, traces[j].pcb_trace_id])\n }\n }\n }\n const connectionsByPort = new Map<string, string[][]>()\n for (const trace of traces) {\n for (const point of trace.route) {\n if (point.route_type !== \"wire\") continue\n for (const portId of new Set([\n point.start_pcb_port_id,\n point.end_pcb_port_id,\n ])) {\n if (!portId || !map.portIdToElm.has(portId)) continue\n const entries = connectionsByPort.get(portId) ?? []\n entries.push(\n point.start_pcb_port_id === portId\n ? [portId, trace.pcb_trace_id]\n : [trace.pcb_trace_id, portId],\n )\n connectionsByPort.set(portId, entries)\n }\n }\n }\n for (const portId of map.portIdToElm.keys()) {\n for (const connection of connectionsByPort.get(portId) ?? [])\n connections.push(connection)\n }\n map.connMap = new ConnectivityMap(findConnectedNetworks(connections))\n return map\n}\n","import type { PcbSmtPad, PcbPlatedHole } from \"circuit-json\"\nimport { pointToSegmentDistance } from \"@tscircuit/math-utils\"\nimport {\n getPillCenterLineForPad,\n getPolygonPointsForPad,\n} from \"lib/check-each-pcb-trace-non-overlapping/segment-to-polygon-clearance\"\n\nfunction getDistanceBetweenPoints(\n pointA: { x: number; y: number },\n pointB: { x: number; y: number },\n): number {\n return Math.sqrt((pointB.x - pointA.x) ** 2 + (pointB.y - pointA.y) ** 2)\n}\n\nconst POINT_ON_SEGMENT_TOLERANCE_MM = 1e-9\n\n// Circuit coordinates commonly reach pad boundaries through separate decimal\n// calculations. Allow their sub-nanometer floating-point residue while keeping\n// physical gaps outside the pad.\nconst POINT_IN_PAD_TOLERANCE_MM = 1e-9\n\nfunction isPointOnSegment(\n point: { x: number; y: number },\n segment: { start: { x: number; y: number }; end: { x: number; y: number } },\n) {\n const crossProduct =\n (point.y - segment.start.y) * (segment.end.x - segment.start.x) -\n (point.x - segment.start.x) * (segment.end.y - segment.start.y)\n if (Math.abs(crossProduct) > POINT_ON_SEGMENT_TOLERANCE_MM) return false\n\n const dotProduct =\n (point.x - segment.start.x) * (segment.end.x - segment.start.x) +\n (point.y - segment.start.y) * (segment.end.y - segment.start.y)\n if (dotProduct < -POINT_ON_SEGMENT_TOLERANCE_MM) return false\n\n const squaredLength =\n (segment.end.x - segment.start.x) ** 2 +\n (segment.end.y - segment.start.y) ** 2\n return dotProduct <= squaredLength + POINT_ON_SEGMENT_TOLERANCE_MM\n}\n\nfunction isPointInPolygon(\n point: { x: number; y: number },\n polygon: Array<{ x: number; y: number }>,\n): boolean {\n let inside = false\n for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {\n const pi = polygon[i]\n const pj = polygon[j]\n if (isPointOnSegment(point, { start: pi, end: pj })) return true\n\n const intersects =\n pi.y > point.y !== pj.y > point.y &&\n point.x < ((pj.x - pi.x) * (point.y - pi.y)) / (pj.y - pi.y) + pi.x\n if (intersects) inside = !inside\n }\n return inside\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 (\n getDistanceBetweenPoints(point, pad) <=\n pad.radius + POINT_IN_PAD_TOLERANCE_MM\n )\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 + POINT_IN_PAD_TOLERANCE_MM &&\n Math.abs(point.y - pad.y) <= halfHeight + POINT_IN_PAD_TOLERANCE_MM\n )\n }\n\n if (pad.shape === \"rotated_rect\") {\n return isPointInPolygon(point, getPolygonPointsForPad(pad))\n }\n\n if (pad.shape === \"pill\" || pad.shape === \"rotated_pill\") {\n if (pad.shape === \"rotated_pill\") {\n const pill = getPillCenterLineForPad(pad)\n return (\n pointToSegmentDistance(point, pill.start, pill.end) <=\n pill.radius + POINT_IN_PAD_TOLERANCE_MM\n )\n }\n\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) <=\n halfWidth - radius + POINT_IN_PAD_TOLERANCE_MM &&\n Math.abs(point.y - pad.y) <= halfHeight + POINT_IN_PAD_TOLERANCE_MM\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 const radiusWithTolerance = radius + POINT_IN_PAD_TOLERANCE_MM\n return (\n cornerX * cornerX + cornerY * cornerY <=\n radiusWithTolerance * radiusWithTolerance\n )\n }\n\n if (pad.shape === \"polygon\") {\n return isPointInPolygon(point, pad.points)\n }\n }\n\n if (pad.type === \"pcb_plated_hole\") {\n if (pad.shape === \"circle\") {\n return (\n getDistanceBetweenPoints(point, pad) <=\n pad.outer_diameter / 2 + POINT_IN_PAD_TOLERANCE_MM\n )\n }\n\n if (\"rect_pad_width\" in pad && \"rect_pad_height\" in pad) {\n return isPointInPolygon(point, getPolygonPointsForPad(pad))\n }\n\n if (pad.shape === \"oval\" || pad.shape === \"pill\") {\n return (\n Math.abs(point.x - pad.x) <=\n pad.outer_width / 2 + POINT_IN_PAD_TOLERANCE_MM &&\n Math.abs(point.y - pad.y) <=\n pad.outer_height / 2 + POINT_IN_PAD_TOLERANCE_MM\n )\n }\n }\n\n return false\n}\n","import {\n distSq,\n getSegmentIntersection,\n isPointInsidePolygon,\n type Point,\n pointToSegmentClosestPoint,\n segmentToSegmentMinDistance,\n} from \"@tscircuit/math-utils\"\nimport type { PcbPlatedHole, PcbSmtPad } from \"circuit-json\"\nimport type { PcbTraceSegment } from \"./getCollidableBounds\"\n\ntype PolygonalPad = PcbSmtPad | PcbPlatedHole\ntype PillPad =\n | Extract<PcbSmtPad, { shape: \"pill\" | \"rotated_pill\" }>\n | Extract<PcbPlatedHole, { shape: \"oval\" | \"pill\" }>\n\nconst rotatePoint = (point: Point, angleDegrees: number): Point => {\n const angle = (angleDegrees * Math.PI) / 180\n return {\n x: point.x * Math.cos(angle) - point.y * Math.sin(angle),\n y: point.x * Math.sin(angle) + point.y * Math.cos(angle),\n }\n}\n\nexport const getRotatedRectPoints = ({\n x,\n y,\n width,\n height,\n ccwRotation,\n}: {\n x: number\n y: number\n width: number\n height: number\n ccwRotation: number\n}): Point[] => {\n const halfWidth = width / 2\n const halfHeight = height / 2\n\n return [\n { x: -halfWidth, y: -halfHeight },\n { x: halfWidth, y: -halfHeight },\n { x: halfWidth, y: halfHeight },\n { x: -halfWidth, y: halfHeight },\n ].map((point) => {\n const rotated = rotatePoint(point, ccwRotation)\n return { x: x + rotated.x, y: y + rotated.y }\n })\n}\n\nexport const getPillCenterLineForPad = (pad: PillPad) => {\n const width = pad.type === \"pcb_plated_hole\" ? pad.outer_width : pad.width\n const height = pad.type === \"pcb_plated_hole\" ? pad.outer_height : pad.height\n const radius =\n pad.type === \"pcb_plated_hole\" ? Math.min(width, height) / 2 : pad.radius\n const ccwRotation =\n pad.type === \"pcb_plated_hole\"\n ? pad.ccw_rotation\n : pad.shape === \"rotated_pill\"\n ? pad.ccw_rotation\n : 0\n const halfLineLength = Math.max(Math.max(width, height) / 2 - radius, 0)\n const axis =\n width >= height ? { x: halfLineLength, y: 0 } : { x: 0, y: halfLineLength }\n const rotatedAxis = rotatePoint(axis, ccwRotation)\n\n return {\n start: { x: pad.x - rotatedAxis.x, y: pad.y - rotatedAxis.y },\n end: { x: pad.x + rotatedAxis.x, y: pad.y + rotatedAxis.y },\n radius,\n }\n}\n\nexport const getPolygonPointsForPad = (pad: PolygonalPad): Point[] => {\n if (pad.type === \"pcb_smtpad\") {\n if (pad.shape === \"polygon\") return pad.points\n\n if (pad.shape === \"rotated_rect\") {\n return getRotatedRectPoints({\n x: pad.x,\n y: pad.y,\n width: pad.width,\n height: pad.height,\n ccwRotation: pad.ccw_rotation,\n })\n }\n }\n\n if (\n pad.type === \"pcb_plated_hole\" &&\n \"rect_pad_width\" in pad &&\n \"rect_pad_height\" in pad\n ) {\n return getRotatedRectPoints({\n x: pad.x,\n y: pad.y,\n width: pad.rect_pad_width,\n height: pad.rect_pad_height,\n ccwRotation:\n \"rect_ccw_rotation\" in pad && typeof pad.rect_ccw_rotation === \"number\"\n ? pad.rect_ccw_rotation\n : 0,\n })\n }\n\n throw new Error(\n `Expected polygonal pad geometry, got ${pad.type} with shape \"${pad.shape}\"`,\n )\n}\n\nconst getPolygonEdges = (points: Point[]) =>\n points.map(\n (point, index) => [point, points[(index + 1) % points.length]!] as const,\n )\n\nconst getClosestPointsBetweenSegments = (\n a1: Point,\n a2: Point,\n b1: Point,\n b2: Point,\n) => {\n const intersection = getSegmentIntersection(a1, a2, b1, b2)\n if (intersection) {\n return {\n distance: 0,\n pointOnA: intersection,\n pointOnB: intersection,\n center: intersection,\n }\n }\n\n const candidates = [\n { pointOnA: a1, pointOnB: pointToSegmentClosestPoint(a1, b1, b2) },\n { pointOnA: a2, pointOnB: pointToSegmentClosestPoint(a2, b1, b2) },\n { pointOnA: pointToSegmentClosestPoint(b1, a1, a2), pointOnB: b1 },\n { pointOnA: pointToSegmentClosestPoint(b2, a1, a2), pointOnB: b2 },\n ]\n\n let best = candidates[0]!\n let bestDistanceSquared = distSq(best.pointOnA, best.pointOnB)\n for (const candidate of candidates.slice(1)) {\n const candidateDistanceSquared = distSq(\n candidate.pointOnA,\n candidate.pointOnB,\n )\n if (candidateDistanceSquared < bestDistanceSquared) {\n best = candidate\n bestDistanceSquared = candidateDistanceSquared\n }\n }\n\n return {\n distance: segmentToSegmentMinDistance(a1, a2, b1, b2),\n pointOnA: best.pointOnA,\n pointOnB: best.pointOnB,\n center: {\n x: (best.pointOnA.x + best.pointOnB.x) / 2,\n y: (best.pointOnA.y + best.pointOnB.y) / 2,\n },\n }\n}\n\nexport const getSegmentToPolygonClearanceFromPoints = (\n start: Point,\n end: Point,\n polygon: Point[],\n) => {\n if (polygon.length < 3) {\n return {\n distance: Number.POSITIVE_INFINITY,\n center: start,\n tracePoint: start,\n obstaclePoint: start,\n }\n }\n\n const intersections = getPolygonEdges(polygon)\n .map(([edgeStart, edgeEnd]) =>\n getSegmentIntersection(start, end, edgeStart, edgeEnd),\n )\n .filter((point): point is Point => point !== null)\n\n if (intersections.length > 0) {\n const dx = end.x - start.x\n const dy = end.y - start.y\n const lengthSquared = dx * dx + dy * dy\n intersections.sort((a, b) => {\n const ta = ((a.x - start.x) * dx + (a.y - start.y) * dy) / lengthSquared\n const tb = ((b.x - start.x) * dx + (b.y - start.y) * dy) / lengthSquared\n return ta - tb\n })\n\n return {\n distance: 0,\n center: intersections[0]!,\n tracePoint: intersections[0]!,\n obstaclePoint: intersections[0]!,\n }\n }\n\n if (\n isPointInsidePolygon(start, polygon) ||\n isPointInsidePolygon(end, polygon)\n ) {\n const center = {\n x: (start.x + end.x) / 2,\n y: (start.y + end.y) / 2,\n }\n return {\n distance: 0,\n center,\n tracePoint: center,\n obstaclePoint: center,\n }\n }\n\n let best = getClosestPointsBetweenSegments(\n start,\n end,\n polygon[0]!,\n polygon[1]!,\n )\n\n for (const [edgeStart, edgeEnd] of getPolygonEdges(polygon).slice(1)) {\n const candidate = getClosestPointsBetweenSegments(\n start,\n end,\n edgeStart,\n edgeEnd,\n )\n if (candidate.distance < best.distance) best = candidate\n }\n\n return {\n distance: best.distance,\n center: best.center,\n tracePoint: best.pointOnA,\n obstaclePoint: best.pointOnB,\n }\n}\n\nexport const getSegmentToPolygonClearance = (\n segment: PcbTraceSegment,\n polygon: Point[],\n) =>\n getSegmentToPolygonClearanceFromPoints(\n { x: segment.x1, y: segment.y1 },\n { x: segment.x2, y: segment.y2 },\n polygon,\n )\n\nexport const getSegmentToPillClearance = (\n segment: Pick<PcbTraceSegment, \"x1\" | \"y1\" | \"x2\" | \"y2\">,\n pad: PillPad,\n) => {\n const pill = getPillCenterLineForPad(pad)\n const closest = getClosestPointsBetweenSegments(\n { x: segment.x1, y: segment.y1 },\n { x: segment.x2, y: segment.y2 },\n pill.start,\n pill.end,\n )\n\n return {\n distance: closest.distance,\n center: closest.center,\n radius: pill.radius,\n tracePoint: closest.pointOnA,\n obstaclePoint: closest.pointOnB,\n }\n}\n","import type {\n PcbPort,\n PcbTrace,\n AnyCircuitElement,\n PcbSmtPad,\n} from \"circuit-json\"\nimport { isPointInPad } from \"lib/check-traces-are-contiguous/is-point-in-pad\"\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 } else if (pad.shape === \"pill\" || pad.shape === \"rotated_pill\") {\n return isPointInPad(point, pad)\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 { createIndexedPcbConnectivityMap } from \"lib/util/create-indexed-pcb-connectivity-map\"\nimport type {\n PcbPort,\n SourceTrace,\n AnyCircuitElement,\n PcbPortNotConnectedError,\n SourceNet,\n} from \"circuit-json\"\nimport { addStartAndEndPortIdsIfMissing } from \"./add-start-and-end-port-ids-if-missing\"\nimport {\n getFullConnectivityMapFromCircuitJson,\n type PcbConnectivityMap,\n type ConnectivityMap,\n} from \"circuit-json-to-connectivity-map\"\nimport { getReadableNameForPort } from \"./util/get-readable-names\"\nimport { getCopperPourConnectivity } from \"./copper-pour-connectivity/get-copper-pour-connectivity\"\n\nfunction checkEachPcbPortConnectedToPcbTraces(\n circuitJson: AnyCircuitElement[],\n {\n connMap,\n pcbConnectivityMap,\n }: {\n connMap?: ConnectivityMap\n pcbConnectivityMap?: PcbConnectivityMap\n } = {},\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 const sourceNets: SourceNet[] = circuitJson.filter(\n (item) => item.type === \"source_net\",\n ) as SourceNet[]\n\n const errors: PcbPortNotConnectedError[] = []\n\n // Generate the connectivity map from the circuit\n const connectivityMap =\n connMap ?? getFullConnectivityMapFromCircuitJson(circuitJson)\n pcbConnectivityMap ??= createIndexedPcbConnectivityMap(circuitJson)\n let pourConnectivity: ReturnType<typeof getCopperPourConnectivity> | undefined\n const getPourConnectivity = () =>\n (pourConnectivity ??= getCopperPourConnectivity(\n circuitJson,\n connectivityMap,\n ))\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 const sourceNetNameById = new Map(\n sourceNets.map((sourceNet) => [sourceNet.source_net_id, sourceNet.name]),\n )\n\n // Process each source trace\n for (const sourceTrace of sourceTraces) {\n const connectedSourcePortIds = sourceTrace.connected_source_port_ids\n\n if (\n connectedSourcePortIds.length === 1 &&\n sourceTrace.connected_source_net_ids.length > 0\n ) {\n const pcbPort = sourcePortToPcbPort.get(connectedSourcePortIds[0])\n if (!pcbPort) continue\n\n const connectedPcbTraces = pcbConnectivityMap.getAllTracesConnectedToPort(\n pcbPort.pcb_port_id,\n )\n\n if (\n connectedPcbTraces.length === 0 &&\n !getPourConnectivity().isPortConnectedToNet(\n pcbPort.pcb_port_id,\n sourceTrace.connected_source_net_ids,\n )\n ) {\n const connectedNetNames = sourceTrace.connected_source_net_ids\n .map((sourceNetId) => sourceNetNameById.get(sourceNetId))\n .filter((name): name is string => Boolean(name))\n const netDescription =\n connectedNetNames.length > 0\n ? `net [${connectedNetNames.join(\", \")}]`\n : \"its connected net\"\n\n errors.push({\n type: \"pcb_port_not_connected_error\",\n message: `Port [${getReadableNameForPort(circuitJson, pcbPort.pcb_port_id)}] is not connected to ${netDescription} by a PCB trace.`,\n error_type: \"pcb_port_not_connected_error\",\n pcb_port_ids: [pcbPort.pcb_port_id],\n pcb_component_ids: pcbPort.pcb_component_id\n ? [pcbPort.pcb_component_id]\n : [],\n pcb_port_not_connected_error_id: `pcb_port_not_connected_error_trace_${sourceTrace.source_trace_id}`,\n })\n }\n\n continue\n }\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 (\n pcbTraceIds.length === 0 &&\n !getPourConnectivity().arePortsConnected(\n pcbPortsInTrace.map((port) => port.pcb_port_id),\n )\n ) {\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: `Ports [${pcbPortsInTrace.map((p) => getReadableNameForPort(circuitJson, 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 {\n AnyCircuitElement,\n PcbPlatedHole,\n PcbSmtPad,\n SourceTrace,\n} from \"circuit-json\"\nimport {\n getReadableNameForElement,\n getReadableNameForPcbPort,\n getBoundsOfPcbElements,\n} from \"@tscircuit/circuit-json-util\"\n\nconst CIRCUIT_JSON_ID_PATTERN =\n /\\b(?:pcb|source|schematic|subcircuit)_[a-z0-9_]+\\b/i\n\nconst sanitizeReadableName = (\n candidate: string | null | undefined,\n id: string,\n fallbackLabel: string,\n): string => {\n if (\n !candidate ||\n candidate === id ||\n CIRCUIT_JSON_ID_PATTERN.test(candidate)\n ) {\n return fallbackLabel\n }\n return candidate\n}\n\nconst firstReadableName = (\n candidates: Array<string | null | undefined>,\n id: string,\n): string => {\n for (const candidate of candidates) {\n const readableName = sanitizeReadableName(candidate, id, \"\")\n if (readableName) return readableName\n }\n return \"\"\n}\n\nexport const getReadableNameForComponent = (\n circuitJson: AnyCircuitElement[],\n pcbComponentId: string,\n): string =>\n sanitizeReadableName(\n getReadableNameForElement(circuitJson, pcbComponentId),\n pcbComponentId,\n \"component\",\n )\n\nexport const getReadableNameForPort = (\n circuitJson: AnyCircuitElement[],\n pcbPortId: string,\n): string => {\n const pcbPort = circuitJson.find(\n (element) =>\n element.type === \"pcb_port\" && element.pcb_port_id === pcbPortId,\n )\n\n if (pcbPort?.type === \"pcb_port\") {\n const sourcePort = circuitJson.find(\n (element) =>\n element.type === \"source_port\" &&\n element.source_port_id === pcbPort.source_port_id,\n )\n\n const sourceComponent =\n sourcePort?.type === \"source_port\"\n ? circuitJson.find(\n (element) =>\n element.type === \"source_component\" &&\n element.source_component_id === sourcePort.source_component_id,\n )\n : null\n\n const readableSourceComponentName = firstReadableName(\n [\n sourceComponent?.type === \"source_component\"\n ? sourceComponent.name\n : null,\n ],\n sourceComponent?.type === \"source_component\"\n ? sourceComponent.source_component_id\n : \"\",\n )\n\n const readableSourcePortName = firstReadableName(\n [\n sourcePort?.type === \"source_port\" ? sourcePort.name : null,\n sourcePort?.type === \"source_port\"\n ? sourcePort.pin_number?.toString()\n : null,\n sourcePort?.type === \"source_port\" ? sourcePort.port_hints?.[0] : null,\n ],\n sourcePort?.type === \"source_port\" ? sourcePort.source_port_id : \"\",\n )\n\n if (readableSourceComponentName && readableSourcePortName) {\n return `${readableSourceComponentName}.${readableSourcePortName}`\n }\n if (readableSourcePortName) {\n return readableSourcePortName\n }\n }\n\n return sanitizeReadableName(\n getReadableNameForPcbPort(circuitJson, pcbPortId) ??\n getReadableNameForElement(circuitJson, pcbPortId),\n pcbPortId,\n \"port\",\n )\n}\n\nexport const getReadableNameForSourceTrace = (\n circuitJson: AnyCircuitElement[],\n sourceTrace: SourceTrace,\n): string => {\n const displayName = sanitizeReadableName(\n sourceTrace.display_name,\n sourceTrace.source_trace_id,\n \"\",\n )\n if (displayName) return displayName\n\n const connectedPortNames = (sourceTrace.connected_source_port_ids ?? [])\n .map((sourcePortId) => {\n const pcbPort = circuitJson.find(\n (element) =>\n element.type === \"pcb_port\" &&\n element.source_port_id === sourcePortId,\n )\n\n if (pcbPort?.type === \"pcb_port\") {\n return getReadableNameForPort(circuitJson, pcbPort.pcb_port_id)\n }\n\n const sourcePort = circuitJson.find(\n (element) =>\n element.type === \"source_port\" &&\n element.source_port_id === sourcePortId,\n )\n if (sourcePort?.type !== \"source_port\") return null\n\n const sourceComponent = circuitJson.find(\n (element) =>\n element.type === \"source_component\" &&\n element.source_component_id === sourcePort.source_component_id,\n )\n\n const sourceComponentName =\n sourceComponent?.type === \"source_component\"\n ? sanitizeReadableName(\n sourceComponent.name,\n sourceComponent.source_component_id,\n \"\",\n )\n : \"\"\n\n const sourcePortName = firstReadableName(\n [\n sourcePort.name,\n sourcePort.pin_number?.toString(),\n sourcePort.port_hints?.[0],\n ],\n sourcePort.source_port_id,\n )\n\n if (sourceComponentName && sourcePortName) {\n return `${sourceComponentName}.${sourcePortName}`\n }\n\n return sourcePortName || null\n })\n .filter((name): name is string => Boolean(name))\n\n if (connectedPortNames.length >= 2) {\n return `${connectedPortNames[0]} to ${connectedPortNames[1]}`\n }\n\n if (connectedPortNames.length === 1) {\n return `trace connected to ${connectedPortNames[0]}`\n }\n\n return `trace ${sourceTrace.source_trace_id}`\n}\n\nexport const getReadableNameForElementId = (\n circuitJson: AnyCircuitElement[],\n elementId: string,\n): string =>\n sanitizeReadableName(\n getReadableNameForElement(circuitJson, elementId),\n elementId,\n \"element\",\n )\n\nexport const getReadableNameForGroup = (\n circuitJson: AnyCircuitElement[],\n groupId: string,\n): string =>\n sanitizeReadableName(\n getReadableNameForElement(circuitJson, groupId),\n groupId,\n \"group\",\n )\n\nexport const containsCircuitJsonId = (message: string): boolean =>\n CIRCUIT_JSON_ID_PATTERN.test(message)\n\nexport function getReadableNameForFootprintPad(\n circuitJson: AnyCircuitElement[],\n pad: PcbSmtPad | PcbPlatedHole,\n ordinal: number,\n): string {\n const padKind = pad.type === \"pcb_smtpad\" ? \"SMD pad\" : \"through-hole pad\"\n const portRef = pad.pcb_port_id\n ? getReadableNameForPort(circuitJson, pad.pcb_port_id)\n : null\n const bounds = getBoundsOfPcbElements([pad])\n const centerX = (bounds.minX + bounds.maxX) / 2\n const centerY = (bounds.minY + bounds.maxY) / 2\n const location = `(${centerX.toFixed(2)}mm, ${centerY.toFixed(2)}mm)`\n\n if (portRef) return `${padKind} ${portRef} at ${location}`\n return `${padKind} #${ordinal + 1} at ${location}`\n}\n","import {\n Box,\n type Arc,\n type Point,\n type Polygon,\n type PolygonEdge,\n type Segment,\n} from \"@flatten-js/core\"\n\ninterface PolygonGeometry {\n box: Box\n facePoints: Point[]\n edges: (Segment | Arc)[]\n edgeIndex: Polygon[\"edges\"]\n}\n\n/** Cache only for one connectivity pass: the input polygons must remain unchanged. */\nexport function createCopperPolygonContactTester(tolerance: number) {\n const cache = new WeakMap<Polygon, PolygonGeometry>()\n const getGeometry = (polygon: Polygon): PolygonGeometry => {\n let geometry = cache.get(polygon)\n if (!geometry) {\n geometry = {\n box: polygon.box,\n facePoints: [...polygon.faces].map((face) => face.first.start),\n edges: [...polygon.edges].map((edge) => edge.shape),\n edgeIndex: polygon.edges,\n }\n cache.set(polygon, geometry)\n }\n return geometry\n }\n return (a: Polygon, b: Polygon): boolean => {\n if (a.isEmpty() || b.isEmpty()) return false\n const ga = getGeometry(a)\n const gb = getGeometry(b)\n if (\n ga.box.xmin > gb.box.xmax + tolerance ||\n ga.box.xmax < gb.box.xmin - tolerance ||\n ga.box.ymin > gb.box.ymax + tolerance ||\n ga.box.ymax < gb.box.ymin - tolerance\n )\n return false\n\n // With disjoint boundaries, one point per face determines containment.\n // If boundaries cross elsewhere, the edge tests below detect the contact.\n // Polygon.contains retains the polygon's holes and separate faces.\n if (\n ga.facePoints.some(\n (point) => gb.box.contains(point) && b.contains(point),\n ) ||\n gb.facePoints.some((point) => ga.box.contains(point) && a.contains(point))\n )\n return true\n\n // Search the larger boundary using the smaller one's edges. Expanded\n // boxes include near contacts; the exact arc/segment distance decides.\n const [small, large] =\n ga.edges.length <= gb.edges.length ? [ga, gb] : [gb, ga]\n for (const edge of small.edges) {\n const box = edge.box\n const queryBox = new Box(\n box.xmin - tolerance,\n box.ymin - tolerance,\n box.xmax + tolerance,\n box.ymax + tolerance,\n )\n // Polygon.edges is already an indexed PlanarSet of PolygonEdge objects.\n // Flatten's generic search declaration returns AnyShape[], so narrow it\n // to the actual element type of this polygon-owned collection.\n const candidates = large.edgeIndex.search(\n queryBox,\n ) as unknown as PolygonEdge[]\n for (const candidate of candidates) {\n if (edge.distanceTo(candidate.shape)[0] <= tolerance) return true\n }\n }\n return false\n }\n}\n","import { createCopperPolygonContactTester } from \"./create-copper-polygon-contact-tester\"\nimport type { Polygon } from \"@flatten-js/core\"\nimport type {\n AnyCircuitElement,\n LayerRef,\n PcbPort,\n SourceNet,\n} from \"circuit-json\"\nimport type { ConnectivityMap } from \"circuit-json-to-connectivity-map\"\nimport {\n getPrimaryId,\n getPlatedHolePolygon,\n getPourPolygon,\n getSmtPadPolygon,\n getTraceSegmentPolygon,\n getViaPolygon,\n} from \"@tscircuit/circuit-json-util\"\n\ntype NetId = NonNullable<ReturnType<ConnectivityMap[\"getNetConnectedToId\"]>>\ntype PcbPortId = PcbPort[\"pcb_port_id\"]\ninterface Conductor {\n polygon: Polygon\n layers: LayerRef[]\n netId: NetId\n portIds?: PcbPortId[]\n isPour?: boolean\n}\n\n/** Physical pour connectivity in board-world mm (+X right, +Y up).\n * Only touching copper on a common layer forms an edge. Plated pads and vias\n * bridge their emitted layers; logical net membership never joins islands.\n * Constant-width wire copper can connect pours. Interpolated traces and inline\n * via inference are left to the existing trace checks; emitted barrels bridge layers.\n */\nexport function getCopperPourConnectivity(\n circuitJson: AnyCircuitElement[],\n connectivity: ConnectivityMap,\n) {\n // Scale before geometric predicates to preserve tiny edges in solver BReps.\n const scale = 1e6\n const tolerance = 1e-7 * scale\n const copperPolygonsTouch = createCopperPolygonContactTester(tolerance)\n const conductors: Conductor[] = []\n const pouredNets = new Set<NetId>()\n const netForId = (id: string) => connectivity.getNetConnectedToId(id)\n const add = (conductor: Conductor) => {\n if (!conductor.polygon.isEmpty()) {\n conductors.push({\n ...conductor,\n polygon: conductor.polygon.scale(scale, scale),\n })\n }\n }\n for (const pour of circuitJson) {\n if (pour.type !== \"pcb_copper_pour\" || !pour.source_net_id) continue\n const netId = netForId(pour.source_net_id)\n if (!netId) continue\n pouredNets.add(netId)\n add({\n polygon: getPourPolygon(pour),\n layers: [pour.layer],\n netId,\n isPour: true,\n })\n }\n const components = new Map(\n circuitJson\n .filter((e) => e.type === \"pcb_component\")\n .map((e) => [e.pcb_component_id, e]),\n )\n if (pouredNets.size > 0) {\n for (const copper of circuitJson) {\n if (copper.type === \"pcb_trace\") {\n const netId = netForId(copper.pcb_trace_id)\n if (\n !netId ||\n !pouredNets.has(netId) ||\n copper.route_thickness_mode === \"interpolated\"\n )\n continue\n for (let i = 0; i < copper.route.length - 1; i++) {\n const start = copper.route[i]\n const end = copper.route[i + 1]\n if (\n start.route_type !== \"wire\" ||\n end.route_type !== \"wire\" ||\n start.layer !== end.layer\n )\n continue\n add({\n polygon: getTraceSegmentPolygon(start, end, start.width),\n layers: [start.layer],\n netId,\n })\n }\n continue\n }\n if (\n copper.type !== \"pcb_smtpad\" &&\n copper.type !== \"pcb_plated_hole\" &&\n copper.type !== \"pcb_via\"\n )\n continue\n const netId = netForId(getPrimaryId(copper))\n if (!netId || !pouredNets.has(netId)) continue\n if (copper.type === \"pcb_smtpad\") {\n add({\n polygon: getSmtPadPolygon(copper),\n layers: [copper.layer],\n netId,\n portIds: copper.pcb_port_id ? [copper.pcb_port_id] : [],\n })\n } else if (copper.type === \"pcb_plated_hole\") {\n add({\n polygon: getPlatedHolePolygon(\n copper,\n copper.pcb_component_id\n ? components.get(copper.pcb_component_id)?.rotation\n : 0,\n ),\n layers: copper.layers,\n netId,\n portIds: copper.pcb_port_id ? [copper.pcb_port_id] : [],\n })\n } else {\n add({\n polygon: getViaPolygon(\n copper,\n copper.outer_diameter,\n copper.hole_diameter,\n ),\n layers: copper.layers,\n netId,\n portIds: copper.pcb_port_ids,\n })\n }\n }\n }\n\n const parent = conductors.map((_, i) => i)\n const find = (i: number): number => {\n while (parent[i] !== i) {\n parent[i] = parent[parent[i]]\n i = parent[i]\n }\n return i\n }\n const bounds = conductors.map((c) => c.polygon.box)\n const order = conductors\n .map((_, i) => i)\n .sort((a, b) => bounds[a].xmin - bounds[b].xmin)\n for (let a = 0; a < order.length; a++) {\n const i = order[a]\n for (let b = a + 1; b < order.length; b++) {\n const j = order[b]\n if (bounds[j].xmin > bounds[i].xmax + tolerance) break\n if (find(i) === find(j) || conductors[i].netId !== conductors[j].netId)\n continue\n if (\n bounds[j].ymin > bounds[i].ymax + tolerance ||\n bounds[j].ymax < bounds[i].ymin - tolerance\n )\n continue\n if (\n !conductors[i].layers.some((layer) =>\n conductors[j].layers.includes(layer),\n )\n )\n continue\n if (copperPolygonsTouch(conductors[i].polygon, conductors[j].polygon))\n parent[find(j)] = find(i)\n }\n }\n const pourRoots = new Set(\n conductors.flatMap((c, i) => (c.isPour ? [find(i)] : [])),\n )\n const rootsByPort = new Map<PcbPortId, Set<number>>()\n for (const [i, conductor] of conductors.entries()) {\n if (!pourRoots.has(find(i))) continue\n for (const portId of conductor.portIds ?? []) {\n const roots = rootsByPort.get(portId) ?? new Set<number>()\n roots.add(find(i))\n rootsByPort.set(portId, roots)\n }\n }\n const portsByNet = new Map<NetId, PcbPortId[]>()\n for (const port of circuitJson) {\n if (port.type !== \"pcb_port\") continue\n const netId = netForId(port.pcb_port_id)\n if (!netId || !pouredNets.has(netId)) continue\n const ports = portsByNet.get(netId) ?? []\n ports.push(port.pcb_port_id)\n portsByNet.set(netId, ports)\n }\n return {\n isPortConnectedToNet(\n portId: PcbPortId,\n sourceNetIds: SourceNet[\"source_net_id\"][],\n ) {\n const roots = rootsByPort.get(portId)\n return sourceNetIds.every((id) =>\n [...(roots ?? [])].some(\n (root) =>\n conductors[root].netId === netForId(id) &&\n // Distinct same-net islands are not a physical connection.\n (portsByNet.get(conductors[root].netId) ?? []).every((peer) =>\n rootsByPort.get(peer)?.has(root),\n ),\n ),\n )\n },\n arePortsConnected(portIds: PcbPortId[]) {\n if (portIds.length < 2) return false\n return [...(rootsByPort.get(portIds[0]) ?? [])].some((root) =>\n portIds.every((id) => rootsByPort.get(id)?.has(root)),\n )\n },\n }\n}\n","import { cju, getReadableNameForElement } from \"@tscircuit/circuit-json-util\"\nimport { getPrimaryId } from \"@tscircuit/circuit-json-util\"\nimport {\n segmentToBoundsMinDistance,\n segmentToCircleMinDistance,\n} from \"@tscircuit/math-utils\"\nimport { segmentToSegmentMinDistance } from \"@tscircuit/math-utils\"\nimport type {\n AnyCircuitElement,\n PcbPlatedHole,\n PcbPort,\n PcbSmtPad,\n PcbTraceError,\n PcbKeepoutOverlapWarning,\n} from \"circuit-json\"\nimport {\n type ConnectivityMap,\n getFullConnectivityMapFromCircuitJson,\n} from \"circuit-json-to-connectivity-map\"\nimport { addStartAndEndPortIdsIfMissing } from \"lib/add-start-and-end-port-ids-if-missing\"\nimport {\n getTraceObstacleClearance,\n isTraceObstacleOverlap,\n} from \"lib/check-pad-clearance/common\"\nimport {\n type Bounds,\n SpatialObjectIndex,\n} from \"lib/data-structures/SpatialIndex\"\nimport {\n DEFAULT_TRACE_MARGIN,\n DEFAULT_TRACE_THICKNESS,\n EPSILON,\n getBoardDrcValue,\n getPcbBoard,\n} from \"lib/drc-defaults\"\nimport { getLayersOfPcbElement } from \"../util/getLayersOfPcbElement\"\nimport { getClosestPointBetweenSegmentAndBounds } from \"./getClosestPointBetweenSegmentAndBounds\"\nimport { getClosestPointBetweenSegments } from \"./getClosestPointBetweenSegments\"\nimport {\n type Collidable,\n type PcbTraceSegment,\n getCollidableBounds,\n} from \"./getCollidableBounds\"\nimport { getPcbPortIdsConnectedToTraces } from \"./getPcbPortIdsConnectedToTraces\"\nimport { getRadiusOfCircuitJsonElement } from \"./getRadiusOfCircuitJsonElement\"\n\ntype PcbComponentConnectionElement = PcbPort | PcbSmtPad | PcbPlatedHole\n\nconst getPcbComponentConnectionElementId = (\n element: PcbComponentConnectionElement,\n): string => {\n if (element.type === \"pcb_port\") return element.pcb_port_id\n if (element.type === \"pcb_smtpad\") return element.pcb_smtpad_id\n return element.pcb_plated_hole_id\n}\n\nexport function checkEachPcbTraceNonOverlapping(\n circuitJson: AnyCircuitElement[],\n {\n connMap,\n minClearance,\n }: {\n connMap?: ConnectivityMap\n minClearance?: number\n } = {},\n): (PcbTraceError | PcbKeepoutOverlapWarning)[] {\n const errors: (PcbTraceError | PcbKeepoutOverlapWarning)[] = []\n addStartAndEndPortIdsIfMissing(circuitJson)\n connMap ??= getFullConnectivityMapFromCircuitJson(circuitJson)\n const board = getPcbBoard(circuitJson)\n minClearance ??=\n getBoardDrcValue(board, \"min_trace_to_pad_edge_clearance\") ??\n DEFAULT_TRACE_MARGIN\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 pcbPorts = cju(circuitJson).pcb_port.list()\n const pcbHoles = cju(circuitJson).pcb_hole.list()\n const pcbVias = cju(circuitJson).pcb_via.list()\n const pcbKeepouts = cju(circuitJson)\n .pcb_keepout.list()\n .filter((keepout) => !keepout.allow_traces)\n\n const pcbComponentConnectionElements: PcbComponentConnectionElement[] = [\n ...pcbPorts,\n ...pcbSmtPads,\n ...pcbPlatedHoles,\n ]\n const excludedConnectionIdsByKeepoutId = new Map<string, string[]>()\n for (const keepout of pcbKeepouts) {\n const excludedPcbComponentIds = new Set(\n keepout.excluded_pcb_component_ids ?? [],\n )\n if (excludedPcbComponentIds.size === 0) continue\n\n excludedConnectionIdsByKeepoutId.set(\n keepout.pcb_keepout_id,\n pcbComponentConnectionElements\n .filter(\n (element) =>\n element.pcb_component_id &&\n excludedPcbComponentIds.has(element.pcb_component_id),\n )\n .map(getPcbComponentConnectionElementId),\n )\n }\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 constructErrorMessage = (\n traceName: string,\n otherName: string,\n gap: number,\n ) => {\n if (isTraceObstacleOverlap(gap)) {\n return `PCB trace ${traceName} overlaps with ${otherName} (accidental contact)`\n }\n\n return `PCB trace ${traceName} is too close to ${otherName} (gap: ${gap.toFixed(3)}mm)`\n }\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 = minClearance\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 (\n obj.type === \"pcb_keepout\" &&\n (excludedConnectionIdsByKeepoutId.get(obj.pcb_keepout_id) ?? []).some(\n (connectionId) =>\n connMap.areIdsConnected(segmentA.pcb_trace_id, connectionId),\n )\n ) {\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 > minClearance - 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: constructErrorMessage(\n getReadableName(segmentA.pcb_trace_id),\n getReadableName(segmentB.pcb_trace_id),\n gap,\n ),\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 if (\n obj.type === \"pcb_smtpad\" ||\n obj.type === \"pcb_plated_hole\" ||\n obj.type === \"pcb_via\"\n ) {\n const { gap, center } = getTraceObstacleClearance(segmentA, obj)\n if (!isTraceObstacleOverlap(gap)) 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: constructErrorMessage(\n getReadableName(segmentA.pcb_trace_id),\n `${obj.type} \"${getReadableName(primaryObjId)}\"`,\n gap,\n ),\n pcb_trace_id: segmentA.pcb_trace_id,\n center,\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 continue\n }\n\n const isCircular = obj.type === \"pcb_hole\"\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 > minClearance - 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: constructErrorMessage(\n getReadableName(segmentA.pcb_trace_id),\n `${obj.type} \"${getReadableName(getPrimaryId(obj))}\"`,\n gap,\n ),\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 if (obj.type === \"pcb_keepout\" && obj.warning_only) {\n errors.push({\n type: \"pcb_keepout_overlap_warning\",\n warning_type: \"pcb_keepout_overlap_warning\",\n pcb_keepout_overlap_warning_id: `pcb_keepout_overlap_warning_${pcb_trace_error_id}`,\n pcb_keepout_id: obj.pcb_keepout_id,\n pcb_trace_ids: [segmentA.pcb_trace_id],\n message: `PCB trace ${getReadableName(segmentA.pcb_trace_id)} violates advisory PCB keepout \"${obj.description ?? obj.pcb_keepout_id}\"`,\n center: getClosestPointBetweenSegmentAndBounds(\n segmentA,\n getCollidableBounds(obj),\n ),\n subcircuit_id:\n segmentA._pcbTrace.subcircuit_id ?? obj.subcircuit_id,\n })\n continue\n }\n errors.push({\n type: \"pcb_trace_error\",\n error_type: \"pcb_trace_error\",\n message: constructErrorMessage(\n getReadableName(segmentA.pcb_trace_id),\n `${obj.type} \"${getReadableName(getPrimaryId(obj))}\"`,\n gap,\n ),\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","import {\n cju,\n distanceBetweenCircleAndCircle,\n distanceBetweenCircleAndPolygon,\n distanceBetweenPolygonAndPolygon,\n getBoundsOfPcbElements,\n} from \"@tscircuit/circuit-json-util\"\nimport {\n midpoint,\n pointToSegmentClosestPoint,\n segmentToCircleMinDistance,\n segmentToSegmentMinDistance,\n} from \"@tscircuit/math-utils\"\nimport type {\n AnyCircuitElement,\n PCBKeepout,\n PcbPlatedHole,\n PcbSmtPad,\n PcbTrace,\n PcbVia,\n} from \"circuit-json\"\nimport type { PcbTraceSegment } from \"lib/check-each-pcb-trace-non-overlapping/getCollidableBounds\"\nimport {\n getPillCenterLineForPad,\n getPolygonPointsForPad,\n getSegmentToPillClearance,\n getSegmentToPolygonClearanceFromPoints,\n} from \"lib/check-each-pcb-trace-non-overlapping/segment-to-polygon-clearance\"\nimport type { Bounds } from \"lib/data-structures/SpatialIndex\"\nimport { DEFAULT_TRACE_THICKNESS } from \"lib/drc-defaults\"\n\nexport type PadElement = PcbSmtPad | PcbPlatedHole\nexport type PadClearanceElement = PadElement | PcbVia\nexport type CopperClearanceElement = PadClearanceElement | PCBKeepout\n\nexport const getPadBounds = (pad: CopperClearanceElement): Bounds => {\n if (pad.type === \"pcb_keepout\") {\n if (pad.shape === \"outline\") {\n return {\n minX: Math.min(...pad.outline.map((point) => point.x)),\n minY: Math.min(...pad.outline.map((point) => point.y)),\n maxX: Math.max(...pad.outline.map((point) => point.x)),\n maxY: Math.max(...pad.outline.map((point) => point.y)),\n }\n }\n\n if (pad.shape === \"circle\") {\n return {\n minX: pad.center.x - pad.radius,\n minY: pad.center.y - pad.radius,\n maxX: pad.center.x + pad.radius,\n maxY: pad.center.y + pad.radius,\n }\n }\n\n return {\n minX: pad.center.x - pad.width / 2,\n minY: pad.center.y - pad.height / 2,\n maxX: pad.center.x + pad.width / 2,\n maxY: pad.center.y + pad.height / 2,\n }\n }\n\n return getBoundsOfPcbElements([pad])\n}\n\nexport const getPadCenter = (pad: CopperClearanceElement) => {\n if (pad.type === \"pcb_keepout\" && pad.shape !== \"outline\") return pad.center\n const bounds = getPadBounds(pad)\n return midpoint(\n { x: bounds.minX, y: bounds.minY },\n { x: bounds.maxX, y: bounds.maxY },\n )\n}\n\nexport const getPadRadius = (pad: CopperClearanceElement) => {\n if (pad.type === \"pcb_keepout\" && pad.shape === \"circle\") return pad.radius\n const bounds = getPadBounds(pad)\n return Math.min(bounds.maxX - bounds.minX, bounds.maxY - bounds.minY) / 2\n}\n\nexport const isCircularPad = (pad: CopperClearanceElement) =>\n pad.type === \"pcb_via\" || pad.shape === \"circle\"\n\nconst isPillPad = (\n pad: CopperClearanceElement,\n): pad is\n | Extract<PcbSmtPad, { shape: \"pill\" | \"rotated_pill\" }>\n | Extract<PcbPlatedHole, { shape: \"oval\" | \"pill\" }> =>\n (pad.type === \"pcb_smtpad\" &&\n (pad.shape === \"pill\" || pad.shape === \"rotated_pill\")) ||\n (pad.type === \"pcb_plated_hole\" &&\n (pad.shape === \"oval\" || pad.shape === \"pill\"))\n\nconst getCircleShape = (pad: CopperClearanceElement) => {\n const center = getPadCenter(pad)\n return {\n kind: \"circle\" as const,\n x: center.x,\n y: center.y,\n radius: getPadRadius(pad),\n }\n}\n\nconst getPolygonShape = (pad: CopperClearanceElement) => {\n if (pad.type === \"pcb_keepout\") {\n if (pad.shape === \"outline\") {\n return {\n kind: \"polygon\" as const,\n points: pad.outline,\n }\n }\n\n if (pad.shape !== \"rect\") {\n throw new Error(`Expected rectangular keepout, got ${pad.shape}`)\n }\n\n return {\n kind: \"polygon\" as const,\n points: [\n {\n x: pad.center.x - pad.width / 2,\n y: pad.center.y - pad.height / 2,\n },\n {\n x: pad.center.x + pad.width / 2,\n y: pad.center.y - pad.height / 2,\n },\n {\n x: pad.center.x + pad.width / 2,\n y: pad.center.y + pad.height / 2,\n },\n {\n x: pad.center.x - pad.width / 2,\n y: pad.center.y + pad.height / 2,\n },\n ],\n }\n }\n\n if (\n pad.type === \"pcb_smtpad\" &&\n (pad.shape === \"polygon\" || pad.shape === \"rotated_rect\")\n ) {\n return {\n kind: \"polygon\" as const,\n points: getPolygonPointsForPad(pad),\n }\n }\n\n if (\n pad.type === \"pcb_plated_hole\" &&\n \"rect_pad_width\" in pad &&\n \"rect_pad_height\" in pad\n ) {\n return {\n kind: \"polygon\" as const,\n points: getPolygonPointsForPad(pad),\n }\n }\n\n const bounds = getPadBounds(pad)\n return {\n kind: \"polygon\" as const,\n points: [\n { x: bounds.minX, y: bounds.minY },\n { x: bounds.maxX, y: bounds.minY },\n { x: bounds.maxX, y: bounds.maxY },\n { x: bounds.minX, y: bounds.maxY },\n ],\n }\n}\n\n// A rounded rectangle is an inset rectangle expanded by corner_radius.\n// At the maximum radius its inset collapses, so use the existing pill geometry.\nconst getRoundedPadCore = (pad: CopperClearanceElement) => {\n if (\n pad.type !== \"pcb_smtpad\" ||\n (pad.shape !== \"rect\" && pad.shape !== \"rotated_rect\") ||\n !pad.corner_radius ||\n pad.corner_radius <= 0\n )\n return null\n\n const radius = Math.min(pad.corner_radius, pad.width / 2, pad.height / 2)\n if (radius === Math.min(pad.width, pad.height) / 2) {\n const core: PcbSmtPad = {\n ...pad,\n shape: \"rotated_pill\",\n radius,\n ccw_rotation: pad.shape === \"rotated_rect\" ? pad.ccw_rotation : 0,\n }\n return { core, radius: 0 }\n }\n return {\n core: {\n ...pad,\n width: pad.width - 2 * radius,\n height: pad.height - 2 * radius,\n corner_radius: 0,\n },\n radius,\n }\n}\n\nexport const getPadToPadGap = (\n padA: CopperClearanceElement,\n padB: CopperClearanceElement,\n): number => {\n const roundedA = getRoundedPadCore(padA)\n const roundedB = getRoundedPadCore(padB)\n if (roundedA || roundedB) {\n return (\n getPadToPadGap(roundedA?.core ?? padA, roundedB?.core ?? padB) -\n (roundedA?.radius ?? 0) -\n (roundedB?.radius ?? 0)\n )\n }\n if (isPillPad(padA) && isPillPad(padB)) {\n const pillA = getPillCenterLineForPad(padA)\n const pillB = getPillCenterLineForPad(padB)\n return (\n segmentToSegmentMinDistance(\n pillA.start,\n pillA.end,\n pillB.start,\n pillB.end,\n ) -\n pillA.radius -\n pillB.radius\n )\n }\n\n if (isPillPad(padA) && isCircularPad(padB)) {\n const pill = getPillCenterLineForPad(padA)\n return (\n segmentToCircleMinDistance(pill.start, pill.end, getCircleShape(padB)) -\n pill.radius\n )\n }\n\n if (isCircularPad(padA) && isPillPad(padB)) {\n const pill = getPillCenterLineForPad(padB)\n return (\n segmentToCircleMinDistance(pill.start, pill.end, getCircleShape(padA)) -\n pill.radius\n )\n }\n\n if (isPillPad(padA)) {\n const pill = getPillCenterLineForPad(padA)\n return (\n getSegmentToPolygonClearanceFromPoints(\n pill.start,\n pill.end,\n getPolygonShape(padB).points,\n ).distance - pill.radius\n )\n }\n\n if (isPillPad(padB)) {\n const pill = getPillCenterLineForPad(padB)\n return (\n getSegmentToPolygonClearanceFromPoints(\n pill.start,\n pill.end,\n getPolygonShape(padA).points,\n ).distance - pill.radius\n )\n }\n\n if (isCircularPad(padA) && isCircularPad(padB)) {\n return distanceBetweenCircleAndCircle(\n getCircleShape(padA),\n getCircleShape(padB),\n )\n }\n\n if (isCircularPad(padA)) {\n return distanceBetweenCircleAndPolygon(\n getCircleShape(padA),\n getPolygonShape(padB),\n )\n }\n\n if (isCircularPad(padB)) {\n return distanceBetweenCircleAndPolygon(\n getCircleShape(padB),\n getPolygonShape(padA),\n )\n }\n\n return distanceBetweenPolygonAndPolygon(\n getPolygonShape(padA),\n getPolygonShape(padB),\n )\n}\n\nexport const getPads = (circuitJson: AnyCircuitElement[]) =>\n [\n ...cju(circuitJson).pcb_smtpad.list(),\n ...cju(circuitJson).pcb_plated_hole.list(),\n ] as PadElement[]\n\nexport const getTraceSegments = (\n circuitJson: AnyCircuitElement[],\n): PcbTraceSegment[] => {\n const pcbTraces = cju(circuitJson).pcb_trace.list()\n\n return pcbTraces.flatMap((pcbTrace) => {\n const segments: PcbTraceSegment[] = []\n\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\n segments.push({\n type: \"pcb_trace_segment\",\n pcb_trace_id: pcbTrace.pcb_trace_id,\n _pcbTrace: pcbTrace as 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 })\n }\n\n return segments\n })\n}\n\nexport type TraceClearanceObstacle = PadElement | PcbVia\n\nconst getCenterBetweenCopperEdges = ({\n tracePoint,\n obstaclePoint,\n traceRadius,\n obstacleRadius,\n}: {\n tracePoint: { x: number; y: number }\n obstaclePoint: { x: number; y: number }\n traceRadius: number\n obstacleRadius: number\n}) => {\n const dx = obstaclePoint.x - tracePoint.x\n const dy = obstaclePoint.y - tracePoint.y\n const distance = Math.hypot(dx, dy)\n if (distance === 0) return midpoint(tracePoint, obstaclePoint)\n\n const unitX = dx / distance\n const unitY = dy / distance\n // For overlapping copper, choose a point in the shared interval. This also\n // handles one circle containing the other without placing the marker outside\n // the smaller shape. A polygon's nearest boundary has obstacleRadius=0.\n if (distance <= traceRadius + obstacleRadius) {\n const overlapStart = Math.max(-traceRadius, distance - obstacleRadius)\n const overlapEnd = Math.min(traceRadius, distance + obstacleRadius)\n const offset = (overlapStart + overlapEnd) / 2\n return {\n x: tracePoint.x + unitX * offset,\n y: tracePoint.y + unitY * offset,\n }\n }\n\n const traceEdge = {\n x: tracePoint.x + unitX * traceRadius,\n y: tracePoint.y + unitY * traceRadius,\n }\n const obstacleEdge = {\n x: obstaclePoint.x - unitX * obstacleRadius,\n y: obstaclePoint.y - unitY * obstacleRadius,\n }\n\n return midpoint(traceEdge, obstacleEdge)\n}\n\nexport const getTraceObstacleClearance = (\n segment: Pick<PcbTraceSegment, \"x1\" | \"y1\" | \"x2\" | \"y2\" | \"thickness\">,\n obstacle: TraceClearanceObstacle,\n): { gap: number; center: { x: number; y: number } } => {\n const rounded = getRoundedPadCore(obstacle)\n if (rounded) obstacle = rounded.core\n const obstacleRadius = rounded?.radius ?? 0\n const start = { x: segment.x1, y: segment.y1 }\n const end = { x: segment.x2, y: segment.y2 }\n const traceRadius = segment.thickness / 2\n\n if (obstacle.type === \"pcb_via\" || isCircularPad(obstacle)) {\n const circle =\n obstacle.type === \"pcb_via\"\n ? {\n x: obstacle.x,\n y: obstacle.y,\n radius: obstacle.outer_diameter / 2,\n }\n : getCircleShape(obstacle)\n const closestPoint = pointToSegmentClosestPoint(circle, start, end)\n\n return {\n gap: segmentToCircleMinDistance(start, end, circle) - traceRadius,\n center: getCenterBetweenCopperEdges({\n tracePoint: closestPoint,\n obstaclePoint: circle,\n traceRadius,\n obstacleRadius: circle.radius,\n }),\n }\n }\n\n if (isPillPad(obstacle)) {\n const clearance = getSegmentToPillClearance(segment, obstacle)\n return {\n gap: clearance.distance - traceRadius - clearance.radius,\n center: getCenterBetweenCopperEdges({\n tracePoint: clearance.tracePoint,\n obstaclePoint: clearance.obstaclePoint,\n traceRadius,\n obstacleRadius: clearance.radius,\n }),\n }\n }\n\n const clearance = getSegmentToPolygonClearanceFromPoints(\n start,\n end,\n getPolygonShape(obstacle).points,\n )\n return {\n gap: clearance.distance - traceRadius - obstacleRadius,\n center: getCenterBetweenCopperEdges({\n tracePoint: clearance.tracePoint,\n obstaclePoint: clearance.obstaclePoint,\n traceRadius,\n obstacleRadius,\n }),\n }\n}\n\nexport const isTraceObstacleOverlap = (gap: number): boolean => gap <= 0\n\n/** A via is a zero-length segment with the width of its outer copper.\n * Use the same nearest-copper geometry as trace clearance markers. */\nexport const getViaPadClearanceCenter = (via: PcbVia, pad: PadElement) =>\n getTraceObstacleClearance(\n {\n x1: via.x,\n y1: via.y,\n x2: via.x,\n y2: via.y,\n thickness: via.outer_diameter,\n },\n pad,\n ).center\n","import type { PcbBoard } from \"circuit-json\"\n\nexport type JlcToleranceMap = Partial<Record<keyof PcbBoard, number>>\n\nexport const jlcMinTolerances: JlcToleranceMap = {\n min_trace_width: 0.1,\n min_via_hole_edge_to_via_hole_edge_clearance: 0.1,\n min_plated_hole_drill_edge_to_drill_edge_clearance: 0.15,\n min_trace_to_pad_edge_clearance: 0.1,\n min_pad_edge_to_pad_edge_clearance: 0.1,\n min_board_edge_clearance: 0.2,\n min_via_hole_diameter: 0.2,\n min_via_pad_diameter: 0.3,\n}\n\n// TODO: Update these values\nexport const jlcPreferredTolerances: JlcToleranceMap = {\n min_trace_width: 0.2,\n min_via_hole_edge_to_via_hole_edge_clearance: 0.2,\n min_plated_hole_drill_edge_to_drill_edge_clearance: 0.2,\n min_trace_to_pad_edge_clearance: 0.2,\n min_pad_edge_to_pad_edge_clearance: 0.2,\n min_board_edge_clearance: 0.2,\n min_via_hole_diameter: 0.4,\n min_via_pad_diameter: 0.6,\n}\n","import { jlcMinTolerances } from \"@tscircuit/jlcpcb-manufacturing-specs\"\nimport type {\n AnyCircuitElement,\n ManufacturingDrcProperties,\n PcbBoard,\n} from \"circuit-json\"\n\nexport const DEFAULT_TRACE_MARGIN = 0.1\nexport const DEFAULT_TRACE_THICKNESS = jlcMinTolerances.min_trace_width\nexport const DEFAULT_VIA_DIAMETER = jlcMinTolerances.min_via_pad_diameter\nexport const DEFAULT_VIA_BOARD_MARGIN =\n jlcMinTolerances.min_board_edge_clearance!\n\nexport const DEFAULT_SAME_NET_VIA_MARGIN =\n jlcMinTolerances.min_via_hole_edge_to_via_hole_edge_clearance!\nexport const DEFAULT_DIFFERENT_NET_VIA_MARGIN =\n jlcMinTolerances.min_via_hole_edge_to_via_hole_edge_clearance!\n\nexport const DEFAULT_PAD_PAD_CLEARANCE =\n jlcMinTolerances.min_pad_edge_to_pad_edge_clearance!\n\nexport const EPSILON = 0.005\n\nexport const getPcbBoard = (\n circuitJson: AnyCircuitElement[],\n): PcbBoard | undefined =>\n circuitJson.find((el): el is PcbBoard => el.type === \"pcb_board\")\n\nexport const getBoardDrcValue = <K extends keyof ManufacturingDrcProperties>(\n board: PcbBoard | undefined,\n key: K,\n): ManufacturingDrcProperties[K] => board?.[key]\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 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","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 { 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 { 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\"\nimport {\n getPillCenterLineForPad,\n getPolygonPointsForPad,\n} from \"./segment-to-polygon-clearance\"\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\n if (\n collidable.type === \"pcb_smtpad\" ||\n collidable.type === \"pcb_plated_hole\"\n ) {\n const isPolygon =\n (collidable.type === \"pcb_smtpad\" &&\n (collidable.shape === \"rotated_rect\" ||\n collidable.shape === \"polygon\")) ||\n (collidable.type === \"pcb_plated_hole\" &&\n \"rect_pad_width\" in collidable &&\n \"rect_pad_height\" in collidable)\n\n if (isPolygon) {\n const polygonPoints = getPolygonPointsForPad(collidable)\n return {\n minX: Math.min(...polygonPoints.map((point) => point.x)),\n minY: Math.min(...polygonPoints.map((point) => point.y)),\n maxX: Math.max(...polygonPoints.map((point) => point.x)),\n maxY: Math.max(...polygonPoints.map((point) => point.y)),\n }\n }\n\n if (\n collidable.type === \"pcb_smtpad\" &&\n collidable.shape === \"rotated_pill\"\n ) {\n const pill = getPillCenterLineForPad(collidable)\n return {\n minX: Math.min(pill.start.x, pill.end.x) - pill.radius,\n minY: Math.min(pill.start.y, pill.end.y) - pill.radius,\n maxX: Math.max(pill.start.x, pill.end.x) + pill.radius,\n maxY: Math.max(pill.start.y, pill.end.y) + pill.radius,\n }\n }\n }\n\n return getBoundsOfPcbElements([collidable as any])\n}\n","import type { PcbTrace } from \"circuit-json\"\n\nexport function getPcbPortIdsConnectedToRoutePoint(\n routePoint: PcbTrace[\"route\"][number],\n) {\n if (routePoint.route_type !== \"wire\") return []\n\n return [routePoint.start_pcb_port_id, routePoint.end_pcb_port_id].filter(\n (portId): portId is string => Boolean(portId),\n )\n}\n\nexport function getPcbPortIdsConnectedToTrace(trace: PcbTrace) {\n const connectedPcbPorts = new Set<string>()\n for (const segment of trace.route) {\n for (const portId of getPcbPortIdsConnectedToRoutePoint(segment)) {\n connectedPcbPorts.add(portId)\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 {\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","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 { getReadableNameForElement } from \"@tscircuit/circuit-json-util\"\nimport type { AnyCircuitElement, PcbPlacementError } from \"circuit-json\"\nimport { checkCopperToBoardEdgeClearance } from \"lib/check-copper-to-board-edge-clearance\"\n\nexport function checkViasOffBoard(\n circuitJson: AnyCircuitElement[],\n): PcbPlacementError[] {\n const vias = circuitJson.filter((element) => element.type === \"pcb_via\")\n const violationsById = new Map(\n checkCopperToBoardEdgeClearance(\n circuitJson.filter(\n (element) => element.type === \"pcb_board\" || element.type === \"pcb_via\",\n ),\n ).map((error) => [\n error.pcb_placement_error_id.replace(\n \"copper_too_close_to_board_edge_\",\n \"\",\n ),\n error,\n ]),\n )\n\n return vias.flatMap((via) => {\n const violation = violationsById.get(via.pcb_via_id)\n if (!violation) return []\n\n const viaName = getReadableNameForElement(circuitJson, via.pcb_via_id)\n return [\n {\n ...violation,\n pcb_placement_error_id: `out_of_board_${via.pcb_via_id}`,\n message: `Via ${viaName} is outside or crossing the board boundary`,\n },\n ]\n })\n}\n","import { jlcMinTolerances } from \"@tscircuit/jlcpcb-manufacturing-specs\"\nimport type {\n AnyCircuitElement,\n PcbComponent,\n PcbPlacementError,\n} from \"circuit-json\"\nimport { getBoardDrcValue, getPcbBoard } from \"lib/drc-defaults\"\nimport { convertCircuitJsonToFlattenJs } from \"@tscircuit/circuit-json-to-flattenjs\"\ntype CopperElement = Extract<\n AnyCircuitElement,\n { type: \"pcb_via\" | \"pcb_smtpad\" | \"pcb_plated_hole\" | \"pcb_copper_pour\" }\n>\n\nconst GEOMETRY_EPSILON = 1e-9\n\nconst getCopperElementLabel = (element: CopperElement): string => {\n if (element.type === \"pcb_via\") return \"Via\"\n if (element.type === \"pcb_smtpad\") return \"SMT pad\"\n if (element.type === \"pcb_plated_hole\") return \"Plated hole\"\n return \"Copper pour\"\n}\n\n/**\n * Checks the finished copper geometry of every via, SMT pad, plated hole, and\n * copper pour against the real board outline and its configured edge-clearance\n * rule.\n *\n * Component and footprint rotations are normally composed into Circuit JSON's\n * absolute coordinates and `ccw_rotation` fields. Polygon-pad plated holes are\n * the exception: their outline stays local, so it is translated and rotated by\n * the owning component here.\n */\nexport function checkCopperToBoardEdgeClearance(\n circuitJson: AnyCircuitElement[],\n): PcbPlacementError[] {\n const board = getPcbBoard(circuitJson)\n if (!board) return []\n\n // Schematic-only/empty boards may have no dimensions yet. There is no\n // copper-to-edge distance to measure until copper geometry exists.\n if (\n !circuitJson.some(\n (element) =>\n element.type === \"pcb_via\" ||\n element.type === \"pcb_smtpad\" ||\n element.type === \"pcb_plated_hole\" ||\n element.type === \"pcb_copper_pour\",\n )\n )\n return []\n\n const boardPolygon = convertCircuitJsonToFlattenJs([board], { strict: true })\n .elements[0]?.shapes[0]\n if (!boardPolygon) return []\n\n const requiredClearance =\n getBoardDrcValue(board, \"min_board_edge_clearance\") ??\n jlcMinTolerances.min_board_edge_clearance\n if (requiredClearance === undefined) return []\n\n const allowedOffBoardComponentIds = new Set<string>(\n circuitJson\n .filter(\n (element): element is PcbComponent => element.type === \"pcb_component\",\n )\n .filter((component) => component.is_allowed_to_be_off_board)\n .map((component) => component.pcb_component_id),\n )\n\n const { elements: copperElements } = convertCircuitJsonToFlattenJs(\n circuitJson,\n {\n elementTypes: [\n \"pcb_via\",\n \"pcb_smtpad\",\n \"pcb_plated_hole\",\n \"pcb_copper_pour\",\n ],\n includeDrillHoles: false,\n strict: true,\n },\n )\n const errors: PcbPlacementError[] = []\n const seen = new Set<string>()\n for (const geometry of copperElements) {\n if (seen.has(geometry.elementId)) continue\n seen.add(geometry.elementId)\n const element = geometry.sourceElement as CopperElement\n if (\n (element.type === \"pcb_smtpad\" || element.type === \"pcb_plated_hole\") &&\n element.pcb_component_id &&\n allowedOffBoardComponentIds.has(element.pcb_component_id)\n ) {\n continue\n }\n\n const isInside = geometry.shapes.every((shape) =>\n boardPolygon.contains(shape),\n )\n const clearance = isInside\n ? Math.min(\n ...geometry.shapes.map((shape) => boardPolygon.distanceTo(shape)[0]),\n )\n : 0\n if (isInside && clearance + GEOMETRY_EPSILON >= requiredClearance) {\n continue\n }\n\n const id = geometry.elementId\n const label = getCopperElementLabel(element)\n errors.push({\n type: \"pcb_placement_error\",\n pcb_placement_error_id: `copper_too_close_to_board_edge_${id}`,\n error_type: \"pcb_placement_error\",\n message: `${label} ${id} violates copper-to-board-edge clearance (measured ${clearance.toFixed(3)}mm, required ${requiredClearance.toFixed(3)}mm)`,\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 { getReadableNameForComponent } from \"lib/util/get-readable-names\"\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}: {\n board: PcbBoard\n}): 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 getReadableNameForComponent(circuitJson, component.pcb_component_id)\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\nfunction getRepositionSuggestion({\n componentPoly,\n boardPoly,\n}: {\n componentPoly: Flatten.Polygon\n boardPoly: Flatten.Polygon\n}): string | null {\n const boardBox = boardPoly.box\n const componentBox = componentPoly.box\n\n let deltaX = 0\n let deltaY = 0\n\n if (componentBox.xmin < boardBox.xmin) {\n deltaX = boardBox.xmin - componentBox.xmin\n } else if (componentBox.xmax > boardBox.xmax) {\n deltaX = boardBox.xmax - componentBox.xmax\n }\n\n if (componentBox.ymin < boardBox.ymin) {\n deltaY = boardBox.ymin - componentBox.ymin\n } else if (componentBox.ymax > boardBox.ymax) {\n deltaY = boardBox.ymax - componentBox.ymax\n }\n\n if (deltaX === 0 && deltaY === 0) {\n return null\n }\n\n const xDir = deltaX >= 0 ? \"right\" : \"left\"\n const yDir = deltaY >= 0 ? \"up\" : \"down\"\n const absDx = Math.abs(Math.round(deltaX * 100) / 100)\n const absDy = Math.abs(Math.round(deltaY * 100) / 100)\n\n if (absDx > 0 && absDy > 0) {\n return `Try moving it ${absDx}mm ${xDir} and ${absDy}mm ${yDir} to fit within the board edge.`\n }\n\n if (absDx > 0) {\n return `Try moving it ${absDx}mm ${xDir} to fit within the board edge.`\n }\n\n return `Try moving it ${absDy}mm ${yDir} to fit within the board edge.`\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 if (c.is_allowed_to_be_off_board) continue\n\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 // c.width and c.height store the world-coordinate AABB dimensions (post-rotation),\n // so we must NOT re-apply rotation here.\n const compPoly = rectanglePolygon({\n center: c.center,\n size: { width: c.width, height: c.height },\n rotationDeg: 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 0,\n )\n\n const compName = getComponentName({ circuitJson, component: c })\n const overlapDistanceMm = Math.round(overlapDistance * 100) / 100\n const repositionSuggestion = getRepositionSuggestion({\n componentPoly: compPoly,\n boardPoly,\n })\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} extends outside board boundaries by ${overlapDistanceMm}mm.${repositionSuggestion ? ` ${repositionSuggestion}` : \"\"}`,\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 { doBoundsOverlap } from \"@tscircuit/math-utils\"\nimport type {\n AnyCircuitElement,\n PcbComponent,\n PcbCutout,\n PcbPlacementError,\n} from \"circuit-json\"\nimport * as Flatten from \"@flatten-js/core\"\nimport { applyToPoint, rotateDEG } from \"transformation-matrix\"\nimport { getReadableNameForComponent } from \"lib/util/get-readable-names\"\n\nconst CUTOUT_CIRCLE_SEGMENTS = 32\n\nfunction rectanglePolygon({\n center,\n width,\n height,\n rotation = 0,\n}: {\n center: { x: number; y: number }\n width: number\n height: number\n rotation?: number\n}) {\n const halfWidth = width / 2\n const halfHeight = height / 2\n const corners = [\n { x: center.x - halfWidth, y: center.y - halfHeight },\n { x: center.x + halfWidth, y: center.y - halfHeight },\n { x: center.x + halfWidth, y: center.y + halfHeight },\n { x: center.x - halfWidth, y: center.y + halfHeight },\n ]\n const matrix = rotateDEG(rotation, center.x, center.y)\n\n return new Flatten.Polygon(\n corners.map((corner) => {\n const rotated = rotation ? applyToPoint(matrix, corner) : corner\n return new Flatten.Point(rotated.x, rotated.y)\n }),\n )\n}\n\nfunction circlePolygon({\n center,\n radius,\n}: {\n center: { x: number; y: number }\n radius: number\n}) {\n return new Flatten.Polygon(\n Array.from({ length: CUTOUT_CIRCLE_SEGMENTS }, (_, index) => {\n const angle = (2 * Math.PI * index) / CUTOUT_CIRCLE_SEGMENTS\n return new Flatten.Point(\n center.x + Math.cos(angle) * radius,\n center.y + Math.sin(angle) * radius,\n )\n }),\n )\n}\n\nfunction cutoutToPolygon(cutout: PcbCutout): Flatten.Polygon | null {\n if (cutout.shape === \"rect\") {\n return rectanglePolygon({\n center: cutout.center,\n width: cutout.width,\n height: cutout.height,\n rotation: cutout.rotation ?? 0,\n })\n }\n\n if (cutout.shape === \"circle\") {\n return circlePolygon({ center: cutout.center, radius: cutout.radius })\n }\n\n if (cutout.shape === \"polygon\") {\n return new Flatten.Polygon(\n cutout.points.map((point) => new Flatten.Point(point.x, point.y)),\n )\n }\n\n return null\n}\n\nfunction polygonBoxToBounds(polygon: Flatten.Polygon) {\n return {\n minX: polygon.box.xmin,\n minY: polygon.box.ymin,\n maxX: polygon.box.xmax,\n maxY: polygon.box.ymax,\n }\n}\n\nfunction doPolygonsOverlap(\n polygonA: Flatten.Polygon,\n polygonB: Flatten.Polygon,\n) {\n if (\n !doBoundsOverlap(polygonBoxToBounds(polygonA), polygonBoxToBounds(polygonB))\n ) {\n return false\n }\n if (polygonA.contains(polygonB) || polygonB.contains(polygonA)) return true\n\n try {\n const intersections = Flatten.BooleanOperations.intersect(\n polygonA,\n polygonB,\n )\n if (Array.isArray(intersections)) {\n return intersections.some((polygon) => polygon.area() > 0)\n }\n return intersections.area() > 0\n } catch {\n return false\n }\n}\n\n/**\n * Cutouts remove PCB material on every layer, so a component body or SMT pad\n * overlapping a cutout is invalid on both top and bottom.\n */\nexport function checkPcbComponentOverCutout(\n circuitJson: AnyCircuitElement[],\n): PcbPlacementError[] {\n const cutouts = circuitJson.filter(\n (element): element is PcbCutout => element.type === \"pcb_cutout\",\n )\n const components = circuitJson.filter(\n (element): element is PcbComponent => element.type === \"pcb_component\",\n )\n if (cutouts.length === 0 || components.length === 0) return []\n\n const cutoutPolygons = cutouts\n .map((cutout) => ({ cutout, polygon: cutoutToPolygon(cutout) }))\n .filter(\n (entry): entry is { cutout: PcbCutout; polygon: Flatten.Polygon } =>\n entry.polygon !== null && entry.polygon.area() > 0,\n )\n const errors: PcbPlacementError[] = []\n\n for (const component of components) {\n if (!component.center || component.width <= 0 || component.height <= 0) {\n continue\n }\n\n const componentPolygon = rectanglePolygon({\n center: component.center,\n width: component.width,\n height: component.height,\n })\n for (const { cutout, polygon: cutoutPolygon } of cutoutPolygons) {\n if (cutout.pcb_component_id === component.pcb_component_id) continue\n if (!doPolygonsOverlap(componentPolygon, cutoutPolygon)) continue\n\n const componentName = getReadableNameForComponent(\n circuitJson,\n component.pcb_component_id,\n )\n const cutoutId = cutout.pcb_cutout_id\n\n errors.push({\n type: \"pcb_placement_error\",\n pcb_placement_error_id: `component_over_cutout_${component.pcb_component_id}_${cutoutId}`,\n error_type: \"pcb_placement_error\",\n message: `Component ${componentName} overlaps with pcb_cutout [${cutoutId}]`,\n subcircuit_id: component.subcircuit_id,\n })\n }\n }\n\n return errors\n}\n","import { cju, getPrimaryId } from \"@tscircuit/circuit-json-util\"\nimport type {\n AnyCircuitElement,\n PCBKeepout,\n PcbPlacementError,\n PcbKeepoutOverlapWarning,\n PcbVia,\n} from \"circuit-json\"\nimport {\n type PadClearanceElement,\n getPadToPadGap,\n getPads,\n} from \"./check-pad-clearance/common\"\nimport { EPSILON } from \"./drc-defaults\"\nimport { getReadableNameForComponent } from \"./util/get-readable-names\"\nimport { getLayersOfPcbElement } from \"./util/getLayersOfPcbElement\"\n\nconst getErrorOwnerId = (copper: PadClearanceElement) =>\n \"pcb_component_id\" in copper && copper.pcb_component_id\n ? copper.pcb_component_id\n : getPrimaryId(copper)\n\nconst getReadableCopperName = (\n circuitJson: AnyCircuitElement[],\n copper: PadClearanceElement,\n) => {\n if (\"pcb_component_id\" in copper && copper.pcb_component_id) {\n const pcbComponent = circuitJson.find(\n (element) =>\n element.type === \"pcb_component\" &&\n element.pcb_component_id === copper.pcb_component_id,\n )\n const sourceComponent =\n pcbComponent?.type === \"pcb_component\"\n ? circuitJson.find(\n (element) =>\n element.type === \"source_component\" &&\n element.source_component_id === pcbComponent.source_component_id,\n )\n : undefined\n const componentName =\n sourceComponent?.type === \"source_component\" && sourceComponent.name\n ? sourceComponent.name\n : getReadableNameForComponent(circuitJson, copper.pcb_component_id)\n\n return `component ${componentName}`\n }\n\n return copper.type === \"pcb_via\"\n ? `via ${copper.pcb_via_id}`\n : `${copper.type} ${getPrimaryId(copper)}`\n}\n\nexport function checkPcbCopperOverKeepout(\n circuitJson: AnyCircuitElement[],\n): (PcbPlacementError | PcbKeepoutOverlapWarning)[] {\n const keepouts = cju(circuitJson).pcb_keepout.list() as PCBKeepout[]\n if (keepouts.length === 0) return []\n\n const copper: PadClearanceElement[] = [\n ...getPads(circuitJson),\n ...(cju(circuitJson).pcb_via.list() as PcbVia[]),\n ]\n const errors = new Map<string, PcbPlacementError | PcbKeepoutOverlapWarning>()\n\n for (const keepout of keepouts) {\n const excludedComponentIds = new Set(\n keepout.excluded_pcb_component_ids ?? [],\n )\n\n for (const copperElement of copper) {\n if (keepout.allow_placements && copperElement.type !== \"pcb_via\") continue\n\n const copperComponentId =\n \"pcb_component_id\" in copperElement\n ? copperElement.pcb_component_id\n : undefined\n if (copperComponentId && excludedComponentIds.has(copperComponentId)) {\n continue\n }\n\n const copperLayers = getLayersOfPcbElement(copperElement)\n if (!copperLayers.some((layer) => keepout.layers.includes(layer))) {\n continue\n }\n\n if (getPadToPadGap(copperElement, keepout) > EPSILON) continue\n\n const ownerId = getErrorOwnerId(copperElement)\n const errorId = `copper_over_keepout_${ownerId}_${keepout.pcb_keepout_id}`\n if (keepout.warning_only) {\n const copperIdField =\n copperElement.type === \"pcb_smtpad\"\n ? \"pcb_smtpad_ids\"\n : copperElement.type === \"pcb_plated_hole\"\n ? \"pcb_plated_hole_ids\"\n : \"pcb_via_ids\"\n const existing = errors.get(errorId)\n if (existing?.type === \"pcb_keepout_overlap_warning\") {\n existing[copperIdField] = Array.from(\n new Set([\n ...(existing[copperIdField] ?? []),\n getPrimaryId(copperElement),\n ]),\n )\n } else {\n errors.set(errorId, {\n type: \"pcb_keepout_overlap_warning\",\n warning_type: \"pcb_keepout_overlap_warning\",\n pcb_keepout_overlap_warning_id: `pcb_keepout_overlap_warning_${errorId}`,\n pcb_keepout_id: keepout.pcb_keepout_id,\n message: `Copper for ${getReadableCopperName(circuitJson, copperElement)} overlaps advisory PCB keepout \"${keepout.description ?? keepout.pcb_keepout_id}\"`,\n ...(copperComponentId\n ? { pcb_component_ids: [copperComponentId] }\n : {}),\n [copperIdField]: [getPrimaryId(copperElement)],\n subcircuit_id: copperElement.subcircuit_id ?? keepout.subcircuit_id,\n })\n }\n continue\n }\n if (errors.has(errorId)) continue\n\n errors.set(errorId, {\n type: \"pcb_placement_error\",\n pcb_placement_error_id: errorId,\n error_type: \"pcb_placement_error\",\n message: `Copper for ${getReadableCopperName(\n circuitJson,\n copperElement,\n )} overlaps ${\n keepout.description\n ? `PCB keepout \"${keepout.description}\"`\n : \"a PCB keepout\"\n }`,\n subcircuit_id: copperElement.subcircuit_id ?? keepout.subcircuit_id,\n })\n }\n }\n\n return [...errors.values()]\n}\n","import { getReadableNameForElement } from \"@tscircuit/circuit-json-util\"\nimport type {\n AnyCircuitElement,\n PcbVia,\n PcbViaClearanceError,\n} from \"circuit-json\"\nimport {\n type ConnectivityMap,\n getFullConnectivityMapFromCircuitJson,\n} from \"circuit-json-to-connectivity-map\"\nimport { EPSILON, getBoardDrcValue, getPcbBoard } from \"lib/drc-defaults\"\nimport { distance } from \"lib/util/distance\"\nimport { viasAreAtSameLocation } from \"lib/util/viasAreAtSameLocation\"\nimport { jlcMinTolerances } from \"@tscircuit/jlcpcb-manufacturing-specs\"\n\nexport function checkSameNetViaSpacing(\n circuitJson: AnyCircuitElement[],\n {\n connMap,\n minClearance,\n }: { connMap?: ConnectivityMap; minClearance?: number } = {},\n): PcbViaClearanceError[] {\n const vias = circuitJson.filter((el) => el.type === \"pcb_via\") as PcbVia[]\n if (vias.length < 2) return []\n const board = getPcbBoard(circuitJson)\n minClearance ??=\n getBoardDrcValue(board, \"min_via_hole_edge_to_via_hole_edge_clearance\") ??\n jlcMinTolerances.min_via_hole_edge_to_via_hole_edge_clearance\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 // TODO: It is a very inefficient piece of code, the way to fix it is to use flatbush.\n if (viasAreAtSameLocation(viaA, viaB)) continue\n if (!connMap.areIdsConnected(viaA.pcb_via_id, viaB.pcb_via_id)) continue\n const gap =\n distance(viaA, viaB) - viaA.hole_diameter / 2 - viaB.hole_diameter / 2\n if (gap + EPSILON >= minClearance!) 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: minClearance,\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","export function distance(\n a: { x: number; y: number },\n b: { x: number; y: number },\n): number {\n return Math.hypot(a.x - b.x, a.y - b.y)\n}\n","import type { PcbVia } from \"circuit-json\"\nimport { distance } from \"./distance\"\nimport { EPSILON } from \"lib/drc-defaults\"\n\nexport function viasAreAtSameLocation(a: PcbVia, b: PcbVia): boolean {\n return distance(a, b) <= EPSILON\n}\n","import { getReadableNameForElement } from \"@tscircuit/circuit-json-util\"\nimport type {\n AnyCircuitElement,\n PcbVia,\n PcbViaClearanceError,\n} from \"circuit-json\"\nimport {\n type ConnectivityMap,\n getFullConnectivityMapFromCircuitJson,\n} from \"circuit-json-to-connectivity-map\"\nimport { EPSILON, getBoardDrcValue, getPcbBoard } from \"lib/drc-defaults\"\nimport { distance } from \"lib/util/distance\"\nimport { viasAreAtSameLocation } from \"lib/util/viasAreAtSameLocation\"\nimport { jlcMinTolerances } from \"@tscircuit/jlcpcb-manufacturing-specs\"\n\nexport function checkDifferentNetViaSpacing(\n circuitJson: AnyCircuitElement[],\n {\n connMap,\n minClearance,\n }: { connMap?: ConnectivityMap; minClearance?: number } = {},\n): PcbViaClearanceError[] {\n const vias = circuitJson.filter((el) => el.type === \"pcb_via\") as PcbVia[]\n if (vias.length < 2) return []\n const board = getPcbBoard(circuitJson)\n minClearance ??=\n getBoardDrcValue(board, \"min_via_hole_edge_to_via_hole_edge_clearance\") ??\n jlcMinTolerances.min_via_hole_edge_to_via_hole_edge_clearance\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 // TODO: It is a very inefficient piece of code, the way to fix it is to use flatbush.\n if (viasAreAtSameLocation(viaA, viaB)) continue\n if (connMap.areIdsConnected(viaA.pcb_via_id, viaB.pcb_via_id)) continue\n const gap =\n distance(viaA, viaB) - viaA.hole_diameter / 2 - viaB.hole_diameter / 2\n if (gap + EPSILON >= minClearance!) 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: minClearance,\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 { cju } from \"@tscircuit/circuit-json-util\"\nimport type {\n AnyCircuitElement,\n PcbPort,\n PcbTrace,\n PcbTraceWarning,\n SourceTrace,\n} from \"circuit-json\"\nimport { getFullConnectivityMapFromCircuitJson } from \"circuit-json-to-connectivity-map\"\nimport { getReadableNameForSourceTrace } from \"lib/util/get-readable-names\"\n\nexport function checkSourceTracesMatchPcbTraceThickness(\n circuitJson: AnyCircuitElement[],\n): PcbTraceWarning[] {\n const warnings: PcbTraceWarning[] = []\n const db = cju(circuitJson)\n\n const sourceTraces = db.source_trace.list() as SourceTrace[]\n const pcbTraces = db.pcb_trace.list() as PcbTrace[]\n const pcbPorts = db.pcb_port.list() as PcbPort[]\n const connectivityMap = getFullConnectivityMapFromCircuitJson(circuitJson)\n\n for (const sourceTrace of sourceTraces) {\n const requestedThickness = sourceTrace.min_trace_thickness\n if (requestedThickness === undefined) continue\n\n const connectedPcbPorts = pcbPorts.filter((pcbPort) =>\n sourceTrace.connected_source_port_ids?.includes(pcbPort.source_port_id),\n )\n if (connectedPcbPorts.length < 2) continue\n\n const referenceNetId = connectivityMap.getNetConnectedToId(\n connectedPcbPorts[0].pcb_port_id,\n )\n if (!referenceNetId) continue\n\n const netElementIds = connectivityMap.getIdsConnectedToNet(referenceNetId)\n const relatedPcbTraces = pcbTraces.filter((pcbTrace) =>\n netElementIds.includes(pcbTrace.pcb_trace_id),\n )\n if (relatedPcbTraces.length === 0) continue\n\n const actualWireWidths = relatedPcbTraces.flatMap((pcbTrace) =>\n pcbTrace.route\n .filter((point) => point.route_type === \"wire\")\n .map((point) => point.width),\n )\n if (actualWireWidths.length === 0) continue\n\n const actualThickness = Math.min(...actualWireWidths)\n if (actualThickness >= requestedThickness) continue\n\n let undersizedSegment:\n | { pcb_trace_id: string; center: { x: number; y: number } }\n | undefined\n\n for (const relatedPcbTrace of relatedPcbTraces) {\n for (let i = 0; i < relatedPcbTrace.route.length - 1; i++) {\n const point = relatedPcbTrace.route[i]\n const nextPoint = relatedPcbTrace.route[i + 1]\n if (!point || !nextPoint) continue\n if (point.route_type !== \"wire\" || nextPoint.route_type !== \"wire\") {\n continue\n }\n if (point.width !== actualThickness) continue\n\n undersizedSegment = {\n pcb_trace_id: relatedPcbTrace.pcb_trace_id,\n center: {\n x: (point.x + nextPoint.x) / 2,\n y: (point.y + nextPoint.y) / 2,\n },\n }\n break\n }\n\n if (undersizedSegment) break\n }\n\n if (!undersizedSegment) continue\n\n warnings.push({\n type: \"pcb_trace_warning\",\n pcb_trace_warning_id: `pcb_trace_warning_${sourceTrace.source_trace_id}`,\n warning_type: \"pcb_trace_warning\",\n message: `Trace [${getReadableNameForSourceTrace(circuitJson, sourceTrace)}] is routed thinner than requested (requested: ${requestedThickness}mm, actual: ${actualThickness}mm).`,\n center: undersizedSegment.center,\n source_trace_id: sourceTrace.source_trace_id,\n pcb_trace_id: undersizedSegment.pcb_trace_id,\n pcb_component_ids: Array.from(\n new Set(\n connectedPcbPorts\n .map((pcbPort) => pcbPort.pcb_component_id)\n .filter((id): id is string => id !== undefined),\n ),\n ),\n pcb_port_ids: connectedPcbPorts.map((pcbPort) => pcbPort.pcb_port_id),\n })\n }\n\n return warnings\n}\n","import type {\n AnyCircuitElement,\n PcbPort,\n PcbTrace,\n PcbTraceMissingError,\n SourceTrace,\n} from \"circuit-json\"\nimport {\n type ConnectivityMap,\n getFullConnectivityMapFromCircuitJson,\n} from \"circuit-json-to-connectivity-map\"\nimport { containsCircuitJsonId } from \"lib/util/get-readable-names\"\nimport { getCopperPourConnectivity } from \"./copper-pour-connectivity/get-copper-pour-connectivity\"\n\n/**\n * Check that each source_trace which connects source ports has at least one\n * pcb_trace associated with it, or its ports physically joined through a\n * same-net copper pour. Otherwise return an error for that source_trace.\n */\nfunction checkSourceTracesHavePcbTraces(\n circuitJson: AnyCircuitElement[],\n { connMap }: { connMap?: ConnectivityMap } = {},\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 const pcbPorts = circuitJson.filter(\n (el) => el.type === \"pcb_port\",\n ) as PcbPort[]\n const sourcePortToPcbPort = new Map(\n pcbPorts.map((pcbPort) => [pcbPort.source_port_id, pcbPort]),\n )\n const connectivityMap =\n connMap ?? getFullConnectivityMapFromCircuitJson(circuitJson)\n let pourConnectivity: ReturnType<typeof getCopperPourConnectivity> | undefined\n const getPourConnectivity = () =>\n (pourConnectivity ??= getCopperPourConnectivity(\n circuitJson,\n connectivityMap,\n ))\n\n for (const sourceTrace of sourceTraces) {\n if (!sourceTrace.connected_source_port_ids?.length) continue\n if ((sourceTrace.connected_source_net_ids?.length ?? 0) > 0) continue\n if (sourceTrace.connected_source_port_ids.length < 2) continue\n\n const hasPcbTrace = pcbTraces.some((pcbTrace) =>\n connectivityMap.areIdsConnected(\n sourceTrace.source_trace_id,\n pcbTrace.pcb_trace_id,\n ),\n )\n\n if (!hasPcbTrace) {\n const connectedPcbPorts = sourceTrace.connected_source_port_ids\n .map((sourcePortId) => sourcePortToPcbPort.get(sourcePortId))\n .filter((pcbPort): pcbPort is PcbPort => pcbPort !== undefined)\n\n if (\n connectedPcbPorts.length ===\n sourceTrace.connected_source_port_ids.length &&\n getPourConnectivity().arePortsConnected(\n connectedPcbPorts.map((port) => port.pcb_port_id),\n )\n )\n continue\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 && !containsCircuitJsonId(sourceTrace.display_name) ? sourceTrace.display_name : \"trace\"}] 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 { createIndexedPcbConnectivityMap } from \"lib/util/create-indexed-pcb-connectivity-map\"\nimport type {\n AnyCircuitElement,\n PcbTraceError,\n PcbPort,\n PcbTrace,\n SourceTrace,\n PcbSmtPad,\n PcbPlatedHole,\n} from \"circuit-json\"\nimport { pointToSegmentDistance } from \"@tscircuit/math-utils\"\nimport { isPointInPad } from \"./is-point-in-pad\"\nimport { distance } from \"../util/distance\"\nimport { getPcbPortIdsConnectedToRoutePoint } from \"../check-each-pcb-trace-non-overlapping/getPcbPortIdsConnectedToTraces\"\nimport {\n getReadableNameForPcbPort,\n getReadableNameForPcbTrace,\n} from \"@tscircuit/circuit-json-util\"\nimport {\n type ConnectivityMap,\n getFullConnectivityMapFromCircuitJson,\n type PcbConnectivityMap,\n} from \"circuit-json-to-connectivity-map\"\nimport { getLayersOfPcbElement } from \"../util/getLayersOfPcbElement\"\nimport { endpointTouchesVia, getViaContactIndex } from \"./via-contact-index\"\n\ntype PcbPortId = PcbPort[\"pcb_port_id\"]\ntype PcbTraceRoutePoint = PcbTrace[\"route\"][number]\ntype PcbTraceWireRoutePoint = Extract<\n PcbTraceRoutePoint,\n { route_type: \"wire\" }\n>\ntype PcbPad = PcbSmtPad | PcbPlatedHole\n\ninterface TraceWireSegment {\n trace: PcbTrace\n start: PcbTraceWireRoutePoint\n end: PcbTraceWireRoutePoint\n}\n\ntype TraceWireSegmentsByNetAndLayer = Map<\n string,\n Map<string, TraceWireSegment[]>\n>\n\nconst ENDPOINT_CONTACT_EPSILON = 1e-9\nconst TRACE_SEGMENT_GEOMETRY_EPSILON = 1e-9\n\nfunction routePointTouchesPad(point: PcbTraceRoutePoint, pad: PcbPad) {\n return (\n point.route_type === \"wire\" &&\n getLayersOfPcbElement(pad).includes(point.layer) &&\n isPointInPad(point, pad)\n )\n}\n\nfunction getTraceWireSegmentsByNetAndLayer(\n pcbTraces: PcbTrace[],\n fullConnectivityMap: ConnectivityMap,\n): TraceWireSegmentsByNetAndLayer {\n const segmentsByNetAndLayer: TraceWireSegmentsByNetAndLayer = new Map()\n\n for (const trace of pcbTraces) {\n // Interpolated segments need position-dependent width evaluation. Keep\n // this focused fix conservative until that geometry is available here.\n if (trace.route_thickness_mode === \"interpolated\") continue\n\n const netId = fullConnectivityMap.getNetConnectedToId(trace.pcb_trace_id)\n if (!netId) continue\n\n for (let i = 0; i < trace.route.length - 1; i++) {\n const start = trace.route[i]\n const end = trace.route[i + 1]\n\n if (start.route_type !== \"wire\" || end.route_type !== \"wire\") continue\n if (start.layer !== end.layer) continue\n if (\n Math.hypot(start.x - end.x, start.y - end.y) <=\n TRACE_SEGMENT_GEOMETRY_EPSILON\n ) {\n continue\n }\n\n const segmentsByLayer = segmentsByNetAndLayer.get(netId) ?? new Map()\n const segments = segmentsByLayer.get(start.layer) ?? []\n segments.push({ trace, start, end })\n segmentsByLayer.set(start.layer, segments)\n segmentsByNetAndLayer.set(netId, segmentsByLayer)\n }\n }\n\n return segmentsByNetAndLayer\n}\n\nfunction getEndpointTraceCopperWidth(\n trace: PcbTrace,\n endpoint: \"start\" | \"end\",\n): number | undefined {\n // Interpolated traces have flat longitudinal ends, so a point-radius contact\n // test would overestimate their endpoint copper.\n if (trace.route_thickness_mode === \"interpolated\") return undefined\n\n let segmentStartIndex = endpoint === \"start\" ? 0 : trace.route.length - 2\n const indexStep = endpoint === \"start\" ? 1 : -1\n\n while (segmentStartIndex >= 0 && segmentStartIndex < trace.route.length - 1) {\n const segmentStart = trace.route[segmentStartIndex]\n const segmentEnd = trace.route[segmentStartIndex + 1]\n\n if (\n segmentStart?.route_type !== \"wire\" ||\n segmentEnd?.route_type !== \"wire\" ||\n segmentStart.layer !== segmentEnd.layer\n ) {\n return undefined\n }\n\n if (\n Math.hypot(segmentStart.x - segmentEnd.x, segmentStart.y - segmentEnd.y) >\n TRACE_SEGMENT_GEOMETRY_EPSILON\n ) {\n // A constant-width segment takes its thickness from its start route point.\n return segmentStart.width\n }\n\n segmentStartIndex += indexStep\n }\n\n return undefined\n}\n\nfunction routePointTouchesLogicallyConnectedTraceCopper({\n point,\n endpointTraceCopperWidth,\n ownerTrace,\n traceWireSegmentsByNetAndLayer,\n fullConnectivityMap,\n}: {\n point: PcbTraceRoutePoint\n endpointTraceCopperWidth: number\n ownerTrace: PcbTrace\n traceWireSegmentsByNetAndLayer: TraceWireSegmentsByNetAndLayer\n fullConnectivityMap: ConnectivityMap\n}): boolean {\n if (point.route_type !== \"wire\") return false\n\n const ownerNetId = fullConnectivityMap.getNetConnectedToId(\n ownerTrace.pcb_trace_id,\n )\n if (!ownerNetId) return false\n const candidateSegments =\n traceWireSegmentsByNetAndLayer.get(ownerNetId)?.get(point.layer) ?? []\n\n // Logical connectivity selects the eligible net. Geometry must still prove\n // that this exact endpoint directly touches copper outside its owner trace.\n for (const segment of candidateSegments) {\n if (segment.trace.pcb_trace_id === ownerTrace.pcb_trace_id) continue\n\n const maximumContactDistance =\n endpointTraceCopperWidth / 2 +\n segment.start.width / 2 +\n ENDPOINT_CONTACT_EPSILON\n if (\n pointToSegmentDistance(point, segment.start, segment.end) <=\n maximumContactDistance\n ) {\n return true\n }\n }\n\n return false\n}\n\nfunction getRoutePointCenter(point: PcbTraceRoutePoint) {\n if (point.route_type === \"through_pad\") {\n return {\n x: (point.start.x + point.end.x) / 2,\n y: (point.start.y + point.end.y) / 2,\n }\n }\n\n return { x: point.x, y: point.y }\n}\n\nfunction routePointConnectsToAnotherExpectedPort(\n point: PcbTraceRoutePoint,\n expectedPorts: PcbPort[],\n missingPcbPortId: PcbPortId,\n padMap: Map<PcbPortId, PcbPad[]>,\n) {\n return expectedPorts.some((expectedPort) => {\n if (\n !expectedPort.pcb_port_id ||\n expectedPort.pcb_port_id === missingPcbPortId\n ) {\n return false\n }\n\n const expectedPads = padMap.get(expectedPort.pcb_port_id)\n return (\n expectedPads?.some((pad) => routePointTouchesPad(point, pad)) ?? false\n )\n })\n}\n\nfunction getMissingConnectionErrorCenter({\n firstPoint,\n lastPoint,\n port,\n expectedPorts,\n padMap,\n}: {\n firstPoint: PcbTrace[\"route\"][number]\n lastPoint: PcbTrace[\"route\"][number]\n port: PcbPort\n expectedPorts: PcbPort[]\n padMap: Map<PcbPortId, PcbPad[]>\n}) {\n let errorLocation:\n | Extract<PcbTrace[\"route\"][number], { route_type: \"wire\" }>\n | undefined\n const firstWirePoint =\n firstPoint.route_type === \"wire\" ? firstPoint : undefined\n const lastWirePoint = lastPoint.route_type === \"wire\" ? lastPoint : undefined\n const firstWirePointReferencesPort = getPcbPortIdsConnectedToRoutePoint(\n firstPoint,\n ).includes(port.pcb_port_id)\n const lastWirePointReferencesPort = getPcbPortIdsConnectedToRoutePoint(\n lastPoint,\n ).includes(port.pcb_port_id)\n\n if (firstWirePointReferencesPort && firstWirePoint) {\n errorLocation = firstWirePoint\n } else if (lastWirePointReferencesPort && lastWirePoint) {\n errorLocation = lastWirePoint\n } else if (\n routePointConnectsToAnotherExpectedPort(\n firstPoint,\n expectedPorts,\n port.pcb_port_id,\n padMap,\n ) &&\n lastWirePoint\n ) {\n errorLocation = lastWirePoint\n } else if (\n routePointConnectsToAnotherExpectedPort(\n lastPoint,\n expectedPorts,\n port.pcb_port_id,\n padMap,\n ) &&\n firstWirePoint\n ) {\n errorLocation = firstWirePoint\n } else if (firstWirePoint && lastWirePoint) {\n errorLocation =\n distance(firstWirePoint, port) <= distance(lastWirePoint, port)\n ? firstWirePoint\n : lastWirePoint\n } else if (firstWirePoint) {\n errorLocation = firstWirePoint\n } else if (lastWirePoint) {\n errorLocation = lastWirePoint\n }\n\n const firstPointCenter = getRoutePointCenter(firstPoint)\n const lastPointCenter = getRoutePointCenter(lastPoint)\n\n return errorLocation\n ? { x: errorLocation.x, y: errorLocation.y }\n : {\n x: (firstPointCenter.x + lastPointCenter.x) / 2,\n y: (firstPointCenter.y + lastPointCenter.y) / 2,\n }\n}\n\nfunction checkTracesAreContiguous(\n circuitJson: AnyCircuitElement[],\n {\n connMap,\n pcbConnectivityMap,\n }: {\n connMap?: ConnectivityMap\n pcbConnectivityMap?: PcbConnectivityMap\n } = {},\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<PcbPortId, PcbPad[]>()\n pcbConnectivityMap ??= createIndexedPcbConnectivityMap(circuitJson)\n let fullConnectivityMap: ConnectivityMap | undefined = connMap\n let traceWireSegmentsByNetAndLayer: TraceWireSegmentsByNetAndLayer | undefined\n const getFullConnectivityMap = () => {\n fullConnectivityMap ??= getFullConnectivityMapFromCircuitJson(circuitJson)\n return fullConnectivityMap\n }\n const getTraceWireSegmentIndex = () => {\n traceWireSegmentsByNetAndLayer ??= getTraceWireSegmentsByNetAndLayer(\n pcbTraces,\n getFullConnectivityMap(),\n )\n return traceWireSegmentsByNetAndLayer\n }\n let viaContactIndex: ReturnType<typeof getViaContactIndex> | undefined\n const getViaIndex = () => {\n viaContactIndex ??= getViaContactIndex(\n circuitJson,\n getFullConnectivityMap(),\n )\n return viaContactIndex\n }\n const checkedSourceTraceIds = new Set<string>()\n\n for (const pad of pcbSmtPads) {\n if (pad.pcb_port_id) {\n padMap.set(pad.pcb_port_id, [...(padMap.get(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, [\n ...(padMap.get(hole.pcb_port_id) ?? []),\n hole,\n ])\n }\n }\n\n const touchedPortIdsByTraceId = new Map<string, Set<PcbPortId>>()\n const traceIdsByTouchedPortId = new Map<PcbPortId, Set<string>>()\n\n // Route attribution can change when a logical net is converted into an MST.\n // Record the PCB ports each routed trace physically reaches so contiguity can\n // follow the copper network instead of relying on singular source_trace_ids.\n for (const trace of pcbTraces) {\n const touchedPortIds = new Set<PcbPortId>()\n const firstPoint = trace.route[0]\n const lastPoint = trace.route.at(-1)\n\n for (const point of [firstPoint, lastPoint]) {\n if (!point) continue\n\n for (const [pcbPortId, pads] of padMap) {\n if (pads.some((pad) => routePointTouchesPad(point, pad))) {\n touchedPortIds.add(pcbPortId)\n }\n }\n }\n\n touchedPortIdsByTraceId.set(trace.pcb_trace_id, touchedPortIds)\n for (const pcbPortId of touchedPortIds) {\n const traceIds = traceIdsByTouchedPortId.get(pcbPortId) ?? new Set()\n traceIds.add(trace.pcb_trace_id)\n traceIdsByTouchedPortId.set(pcbPortId, traceIds)\n }\n }\n\n const physicallyConnectedTracesByTraceId = new Map<string, PcbTrace[]>()\n const getPhysicallyConnectedTraces = (startTrace: PcbTrace): PcbTrace[] => {\n const cached = physicallyConnectedTracesByTraceId.get(\n startTrace.pcb_trace_id,\n )\n if (cached) return cached\n\n const connectedTraceIds = new Set<string>()\n const pendingTraceIds = [startTrace.pcb_trace_id]\n\n while (pendingTraceIds.length > 0) {\n const traceId = pendingTraceIds.pop()!\n if (connectedTraceIds.has(traceId)) continue\n connectedTraceIds.add(traceId)\n\n for (const connectedTrace of pcbConnectivityMap.getAllTracesConnectedToTrace(\n traceId,\n )) {\n if (!connectedTraceIds.has(connectedTrace.pcb_trace_id)) {\n pendingTraceIds.push(connectedTrace.pcb_trace_id)\n }\n }\n\n for (const pcbPortId of touchedPortIdsByTraceId.get(traceId) ?? []) {\n for (const touchingTraceId of traceIdsByTouchedPortId.get(pcbPortId) ??\n []) {\n if (!connectedTraceIds.has(touchingTraceId)) {\n pendingTraceIds.push(touchingTraceId)\n }\n }\n }\n }\n\n const connectedTraces = pcbTraces.filter((trace) =>\n connectedTraceIds.has(trace.pcb_trace_id),\n )\n for (const trace of connectedTraces) {\n physicallyConnectedTracesByTraceId.set(\n trace.pcb_trace_id,\n connectedTraces,\n )\n }\n return connectedTraces\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.01 &&\n Math.abs(prevPoint.y - currentPoint.y) < 0.01\n\n const nextAligned =\n Math.abs(nextPoint.x - currentPoint.x) < 0.01 &&\n Math.abs(nextPoint.y - currentPoint.y) < 0.01\n\n if (!prevAligned || !nextAligned) {\n const traceName = getReadableNameForPcbTrace(\n circuitJson,\n trace.pcb_trace_id,\n )\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: `misaligned_via_${trace.pcb_trace_id}_${i}`,\n pcb_component_ids: [],\n pcb_port_ids: [],\n })\n }\n }\n }\n }\n\n const traceName = getReadableNameForPcbTrace(\n circuitJson,\n trace.pcb_trace_id,\n )\n\n // Validate required ports once for the complete routed source trace.\n if (sourceTrace && expectedPorts.length > 0) {\n if (checkedSourceTraceIds.has(sourceTrace.source_trace_id)) continue\n checkedSourceTraceIds.add(sourceTrace.source_trace_id)\n }\n\n for (const port of expectedPorts) {\n if (!port.pcb_port_id) continue\n\n const pads = padMap.get(port.pcb_port_id)\n\n if (!pads?.length) continue\n\n const isConnectedByRoutedSourceTrace = getPhysicallyConnectedTraces(\n trace,\n ).some((candidateTrace) =>\n touchedPortIdsByTraceId\n .get(candidateTrace.pcb_trace_id)\n ?.has(port.pcb_port_id),\n )\n if (isConnectedByRoutedSourceTrace) continue\n\n const isFirstPointConnected = pads.some((pad) =>\n routePointTouchesPad(firstPoint, pad),\n )\n\n const isLastPointConnected = pads.some((pad) =>\n routePointTouchesPad(lastPoint, pad),\n )\n\n if (!isFirstPointConnected && !isLastPointConnected) {\n const portName = getReadableNameForPcbPort(\n circuitJson,\n port.pcb_port_id,\n ).replace(\"pcb_port\", \"\")\n const padType = pads[0].type.replace(/pcb_/, \"\")\n const errorCenter = getMissingConnectionErrorCenter({\n firstPoint,\n lastPoint,\n port,\n expectedPorts,\n padMap,\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: `missing_connection_${trace.pcb_trace_id}_${port.pcb_port_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 pads of padMap.values()) {\n if (pads.some((pad) => routePointTouchesPad(firstPoint, pad))) {\n firstConnectsToAnyPad = true\n }\n if (pads.some((pad) => routePointTouchesPad(lastPoint, pad))) {\n lastConnectsToAnyPad = true\n }\n }\n\n const firstEndpointTraceCopperWidth = !firstConnectsToAnyPad\n ? getEndpointTraceCopperWidth(trace, \"start\")\n : undefined\n const lastEndpointTraceCopperWidth = !lastConnectsToAnyPad\n ? getEndpointTraceCopperWidth(trace, \"end\")\n : undefined\n const firstConnectsToLogicallyConnectedTraceCopper =\n firstEndpointTraceCopperWidth !== undefined &&\n routePointTouchesLogicallyConnectedTraceCopper({\n point: firstPoint,\n endpointTraceCopperWidth: firstEndpointTraceCopperWidth,\n ownerTrace: trace,\n traceWireSegmentsByNetAndLayer: getTraceWireSegmentIndex(),\n fullConnectivityMap: getFullConnectivityMap(),\n })\n const lastConnectsToLogicallyConnectedTraceCopper =\n lastEndpointTraceCopperWidth !== undefined &&\n routePointTouchesLogicallyConnectedTraceCopper({\n point: lastPoint,\n endpointTraceCopperWidth: lastEndpointTraceCopperWidth,\n ownerTrace: trace,\n traceWireSegmentsByNetAndLayer: getTraceWireSegmentIndex(),\n fullConnectivityMap: getFullConnectivityMap(),\n })\n const firstIsConnected =\n firstConnectsToAnyPad ||\n firstConnectsToLogicallyConnectedTraceCopper ||\n (firstEndpointTraceCopperWidth !== undefined &&\n endpointTouchesVia({\n point: firstPoint,\n width: firstEndpointTraceCopperWidth,\n ownerTrace: trace,\n index: getViaIndex(),\n connectivity: getFullConnectivityMap(),\n }))\n const lastIsConnected =\n lastConnectsToAnyPad ||\n lastConnectsToLogicallyConnectedTraceCopper ||\n (lastEndpointTraceCopperWidth !== undefined &&\n endpointTouchesVia({\n point: lastPoint,\n width: lastEndpointTraceCopperWidth,\n ownerTrace: trace,\n index: getViaIndex(),\n connectivity: getFullConnectivityMap(),\n }))\n const endpointsAreSame =\n firstPoint.route_type === \"wire\" &&\n lastPoint.route_type === \"wire\" &&\n firstPoint.layer === lastPoint.layer &&\n Math.hypot(firstPoint.x - lastPoint.x, firstPoint.y - lastPoint.y) <=\n ENDPOINT_CONTACT_EPSILON\n\n if (!firstIsConnected && firstPoint.route_type === \"wire\") {\n errors.push({\n type: \"pcb_trace_error\",\n message: `Trace [${traceName}] has disconnected endpoint at (${firstPoint.x.toFixed(2)}, ${firstPoint.y.toFixed(2)})`,\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: `disconnected_endpoint_${trace.pcb_trace_id}_start`,\n center: { x: firstPoint.x, y: firstPoint.y },\n pcb_component_ids: [],\n pcb_port_ids: [],\n })\n }\n if (\n !lastIsConnected &&\n lastPoint.route_type === \"wire\" &&\n !(endpointsAreSame && !firstIsConnected)\n ) {\n errors.push({\n type: \"pcb_trace_error\",\n message: `Trace [${traceName}] has disconnected endpoint at (${lastPoint.x.toFixed(2)}, ${lastPoint.y.toFixed(2)})`,\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: `disconnected_endpoint_${trace.pcb_trace_id}_end`,\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 {\n all_layers,\n type AnyCircuitElement,\n type PcbTrace,\n type PcbVia,\n} from \"circuit-json\"\nimport type { ConnectivityMap } from \"circuit-json-to-connectivity-map\"\nimport { getPrimaryId } from \"@tscircuit/circuit-json-util\"\nimport { pointToSegmentDistance } from \"@tscircuit/math-utils\"\nimport { getPads, getPadToPadGap } from \"../check-pad-clearance/common\"\nimport { isPointInPad } from \"./is-point-in-pad\"\nimport { getLayersOfPcbElement } from \"../util/getLayersOfPcbElement\"\n\ntype ViaContact = {\n x: number\n y: number\n ownerTraceId?: string\n radius?: number\n touchesPad: boolean\n touchingTraceIds: Set<string>\n}\n\ntype ViaContactIndex = Map<string, Map<string, ViaContact[]>>\nconst CONTACT_EPSILON = 1e-9\n\n/** Index actual via copper independently of lateral trace segments. */\nexport function getViaContactIndex(\n circuitJson: AnyCircuitElement[],\n connectivity: ConnectivityMap,\n): ViaContactIndex {\n const index: ViaContactIndex = new Map()\n const pads = getPads(circuitJson)\n const traces = circuitJson.filter((element) => element.type === \"pcb_trace\")\n const vias = circuitJson.filter((element) => element.type === \"pcb_via\")\n const board = circuitJson.find((element) => element.type === \"pcb_board\")\n const layerCount = board?.num_layers\n const innerLayers = all_layers.filter((layer) => layer.startsWith(\"inner\"))\n const stack = [\n \"top\",\n ...innerLayers.slice(\n 0,\n layerCount === undefined ? undefined : Math.max(0, layerCount - 2),\n ),\n ...(layerCount === 1 ? [] : [\"bottom\"]),\n ]\n const add = (\n id: string,\n layers: string[],\n contact: Omit<ViaContact, \"touchesPad\" | \"touchingTraceIds\">,\n ) => {\n if (![contact.x, contact.y].every(Number.isFinite)) return\n const net = connectivity.getNetConnectedToId(id)\n if (!net) return\n const touchesPad = pads.some((pad) => {\n if (\n connectivity.getNetConnectedToId(getPrimaryId(pad)) !== net ||\n !getLayersOfPcbElement(pad).some((layer) => layers.includes(layer))\n )\n return false\n if (contact.radius === undefined) return isPointInPad(contact, pad)\n const viaGeometry = {\n type: \"pcb_via\",\n pcb_via_id: id,\n x: contact.x,\n y: contact.y,\n outer_diameter: contact.radius * 2,\n hole_diameter: 0,\n layers,\n } as PcbVia\n return getPadToPadGap(viaGeometry, pad) <= CONTACT_EPSILON\n })\n const touchingTraceIds = new Set<string>()\n for (const trace of traces) {\n if (\n trace.route_thickness_mode === \"interpolated\" ||\n connectivity.getNetConnectedToId(trace.pcb_trace_id) !== net\n )\n continue\n for (let i = 1; i < trace.route.length; i++) {\n const a = trace.route[i - 1]!,\n b = trace.route[i]!\n if (\n a.route_type !== \"wire\" ||\n b.route_type !== \"wire\" ||\n a.layer !== b.layer ||\n !layers.includes(a.layer) ||\n !Number.isFinite(a.width) ||\n a.width <= 0 ||\n Math.hypot(a.x - b.x, a.y - b.y) <= CONTACT_EPSILON\n )\n continue\n const reach =\n contact.radius === undefined ? 0 : contact.radius + a.width / 2\n if (pointToSegmentDistance(contact, a, b) <= reach + CONTACT_EPSILON) {\n touchingTraceIds.add(trace.pcb_trace_id)\n break\n }\n }\n }\n const copper: ViaContact = { ...contact, touchesPad, touchingTraceIds }\n const byLayer = index.get(net) ?? new Map<string, ViaContact[]>()\n for (const layer of layers) {\n const contacts = byLayer.get(layer) ?? []\n contacts.push(copper)\n byLayer.set(layer, contacts)\n }\n index.set(net, byLayer)\n }\n\n for (const via of vias) {\n if (!Number.isFinite(via.outer_diameter) || via.outer_diameter <= 0)\n continue\n add(via.pcb_via_id, getLayersOfPcbElement(via), {\n x: via.x,\n y: via.y,\n ownerTraceId: via.pcb_trace_id,\n radius: via.outer_diameter / 2,\n })\n }\n\n // Route-only inputs may not have materialized pcb_via records yet. Expand\n // their physical span using the board stack, including intermediate layers.\n for (const trace of circuitJson) {\n if (trace.type !== \"pcb_trace\") continue\n for (const point of trace.route) {\n if (point.route_type !== \"via\") continue\n if (\n vias.some(\n (via) =>\n Math.hypot(via.x - point.x, via.y - point.y) <= CONTACT_EPSILON &&\n (via.pcb_trace_id === trace.pcb_trace_id ||\n (!via.pcb_trace_id &&\n connectivity.areIdsConnected(\n via.pcb_via_id,\n trace.pcb_trace_id,\n ))),\n )\n )\n continue\n const from = stack.indexOf(point.from_layer)\n const to = stack.indexOf(point.to_layer)\n if (from < 0 || to < 0) continue\n const diameter = point.outer_diameter\n if (\n diameter !== undefined &&\n (!Number.isFinite(diameter) || diameter <= 0)\n )\n continue\n add(\n trace.pcb_trace_id,\n stack.slice(Math.min(from, to), Math.max(from, to) + 1),\n {\n x: point.x,\n y: point.y,\n ownerTraceId: trace.pcb_trace_id,\n radius: diameter === undefined ? undefined : diameter / 2,\n },\n )\n }\n }\n return index\n}\n\nexport function endpointTouchesVia({\n point,\n width,\n ownerTrace,\n index,\n connectivity,\n}: {\n point: PcbTrace[\"route\"][number]\n width: number\n ownerTrace: PcbTrace\n index: ViaContactIndex\n connectivity: ConnectivityMap\n}): boolean {\n if (point.route_type !== \"wire\" || !Number.isFinite(width) || width <= 0)\n return false\n const net = connectivity.getNetConnectedToId(ownerTrace.pcb_trace_id)\n if (!net) return false\n return (index.get(net)?.get(point.layer) ?? []).some((via) => {\n if (via.ownerTraceId === ownerTrace.pcb_trace_id) return false\n // A lone via does not establish an onward connection. Its barrel must\n // reach a same-net pad or another nondegenerate trace on a physical layer.\n if (\n !via.touchesPad &&\n ![...via.touchingTraceIds].some((id) => id !== ownerTrace.pcb_trace_id)\n )\n return false\n // When a route-only via has no diameter, certify exact center contact only.\n const contactDistance =\n via.radius === undefined ? 0 : via.radius + width / 2\n return (\n Math.hypot(point.x - via.x, point.y - via.y) <=\n contactDistance + CONTACT_EPSILON\n )\n })\n}\n","import { cju } from \"@tscircuit/circuit-json-util\"\nimport type { Point, Polygon } from \"@tscircuit/math-utils\"\nimport { segmentToSegmentMinDistance } from \"@tscircuit/math-utils\"\nimport type {\n AnyCircuitElement,\n PcbBoard,\n PcbTrace,\n PcbTraceError,\n} from \"circuit-json\"\nimport { getBoardDrcValue, getPcbBoard } from \"lib/drc-defaults\"\nimport { jlcMinTolerances } from \"@tscircuit/jlcpcb-manufacturing-specs\"\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 board = getPcbBoard(circuitJson)\n if (!board) return errors\n const margin =\n config.margin ??\n getBoardDrcValue(board, \"min_board_edge_clearance\") ??\n jlcMinTolerances.min_board_edge_clearance\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 = Number.POSITIVE_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 {\n cju,\n getBoundsOfPcbElements,\n getPrimaryId,\n} from \"@tscircuit/circuit-json-util\"\nimport { doBoundsOverlap } from \"@tscircuit/math-utils\"\nimport type {\n AnyCircuitElement,\n PcbCourtyardCircle,\n PcbCourtyardOutline,\n PcbCourtyardPolygon,\n PcbCourtyardRect,\n} from \"circuit-json\"\nimport { getFullConnectivityMapFromCircuitJson } from \"circuit-json-to-connectivity-map\"\nimport {\n getReadableNameForElementId,\n getReadableNameForPort,\n} from \"lib/util/get-readable-names\"\nimport type { PcbComponentOverlapError } from \"../consolidate-pcb-overlap-errors\"\nimport {\n type OverlappableElement,\n doPcbElementsOverlap,\n} from \"./doPcbElementsOverlap\"\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\ntype CourtyardElement =\n | PcbCourtyardCircle\n | PcbCourtyardOutline\n | PcbCourtyardPolygon\n | PcbCourtyardRect\n\nconst isCourtyardElement = (\n element: AnyCircuitElement,\n): element is CourtyardElement =>\n element.type === \"pcb_courtyard_circle\" ||\n element.type === \"pcb_courtyard_outline\" ||\n element.type === \"pcb_courtyard_polygon\" ||\n element.type === \"pcb_courtyard_rect\"\n\nconst isHoleElement = (element: OverlappableElement): boolean =>\n element.type === \"pcb_hole\" || element.type === \"pcb_plated_hole\"\n\nconst formatOverlapElementDescription = (\n circuitJson: AnyCircuitElement[],\n element: OverlappableElement,\n): string => {\n if (\"pcb_port_id\" in element && element.pcb_port_id) {\n return getReadableNameForPort(circuitJson, element.pcb_port_id)\n }\n\n const id = getPrimaryId(element)\n const readableName = getReadableNameForElementId(circuitJson, id)\n return readableName === \"element\" ? `[${id}]` : readableName\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): PcbComponentOverlapError[] {\n const errors: PcbComponentOverlapError[] = []\n\n const doNotPlaceComponentIds = new Set(\n circuitJson.flatMap((element) =>\n element.type === \"pcb_component\" && element.do_not_place\n ? [element.pcb_component_id]\n : [],\n ),\n )\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 const courtyards = circuitJson.filter(isCourtyardElement)\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 })\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 })\n }\n componentMap.get(componentId)!.elements.push(hole)\n }\n\n // Group holes by component when possible, otherwise treat each as standalone\n for (const hole of holes) {\n const componentId =\n hole.pcb_component_id || `standalone_hole_${getPrimaryId(hole)}`\n if (!componentMap.has(componentId)) {\n componentMap.set(componentId, {\n component_id: componentId,\n elements: [hole],\n })\n }\n }\n\n for (const courtyard of courtyards) {\n const componentId = courtyard.pcb_component_id\n if (!componentMap.has(componentId)) {\n componentMap.set(componentId, {\n component_id: componentId,\n elements: [],\n })\n }\n componentMap.get(componentId)!.elements.push(courtyard)\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 const pairIncludesDoNotPlaceComponent =\n doNotPlaceComponentIds.has(comp1.component_id) ||\n doNotPlaceComponentIds.has(comp2.component_id)\n\n // First check if component bounds overlap\n if (!comp1.bounds || !comp2.bounds) {\n continue\n }\n\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 if (\n pairIncludesDoNotPlaceComponent &&\n (isCourtyardElement(elem1) || isCourtyardElement(elem2))\n ) {\n continue\n }\n\n if (\n (isCourtyardElement(elem1) || isCourtyardElement(elem2)) &&\n !isHoleElement(elem1) &&\n !isHoleElement(elem2)\n ) {\n continue\n }\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 const elem1Description = formatOverlapElementDescription(\n circuitJson,\n elem1,\n )\n const elem2Description = formatOverlapElementDescription(\n circuitJson,\n elem2,\n )\n\n // Create error object\n const error: PcbComponentOverlapError = {\n type: \"pcb_footprint_overlap_error\",\n pcb_error_id: `pcb_footprint_overlap_${id1}_${id2}`,\n error_type: \"pcb_footprint_overlap_error\",\n message: `${elem1.type} ${elem1Description} overlaps with ${elem2.type} ${elem2Description}`,\n pcb_component_ids: [\n elem1.pcb_component_id,\n elem2.pcb_component_id,\n ].filter((id): id is string => Boolean(id)),\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 { getBoundsOfPcbElements } from \"@tscircuit/circuit-json-util\"\nimport { doBoundsOverlap } from \"@tscircuit/math-utils\"\nimport type {\n PCBKeepout,\n PcbCourtyardCircle,\n PcbCourtyardOutline,\n PcbCourtyardPolygon,\n PcbCourtyardRect,\n PcbHole,\n PcbPlatedHole,\n PcbSmtPad,\n} from \"circuit-json\"\nimport type { Collidable } from \"lib/check-each-pcb-trace-non-overlapping/getCollidableBounds\"\nimport { getRotatedRectPoints } from \"lib/check-each-pcb-trace-non-overlapping/segment-to-polygon-clearance\"\nimport { getPadToPadGap } from \"lib/check-pad-clearance/common\"\nimport { getLayersOfPcbElement } from \"lib/util/getLayersOfPcbElement\"\n\ntype CourtyardElement =\n | PcbCourtyardCircle\n | PcbCourtyardOutline\n | PcbCourtyardPolygon\n | PcbCourtyardRect\n\nexport type OverlappableElement =\n | PcbSmtPad\n | PcbPlatedHole\n | PcbHole\n | CourtyardElement\n\nconst isCourtyardElement = (\n element: OverlappableElement,\n): element is CourtyardElement =>\n element.type === \"pcb_courtyard_circle\" ||\n element.type === \"pcb_courtyard_outline\" ||\n element.type === \"pcb_courtyard_polygon\" ||\n element.type === \"pcb_courtyard_rect\"\n\nconst getCourtyardId = (courtyard: CourtyardElement): string => {\n switch (courtyard.type) {\n case \"pcb_courtyard_circle\":\n return courtyard.pcb_courtyard_circle_id\n case \"pcb_courtyard_outline\":\n return courtyard.pcb_courtyard_outline_id\n case \"pcb_courtyard_polygon\":\n return courtyard.pcb_courtyard_polygon_id\n case \"pcb_courtyard_rect\":\n return courtyard.pcb_courtyard_rect_id\n }\n}\n\n/**\n * Reuse the copper-clearance geometry for plated-hole/courtyard checks.\n * Rectangular courtyards become polygons so their rotation is preserved.\n */\nconst courtyardToKeepout = (courtyard: CourtyardElement): PCBKeepout => {\n const common = {\n type: \"pcb_keepout\" as const,\n pcb_keepout_id: getCourtyardId(courtyard),\n layers: [courtyard.layer],\n }\n\n if (courtyard.type === \"pcb_courtyard_circle\") {\n return {\n ...common,\n shape: \"circle\",\n center: courtyard.center,\n radius: courtyard.radius,\n }\n }\n\n const outline =\n courtyard.type === \"pcb_courtyard_rect\"\n ? getRotatedRectPoints({\n x: courtyard.center.x,\n y: courtyard.center.y,\n width: courtyard.width,\n height: courtyard.height,\n ccwRotation: courtyard.ccw_rotation ?? 0,\n })\n : courtyard.type === \"pcb_courtyard_polygon\"\n ? courtyard.points\n : courtyard.outline\n\n return {\n ...common,\n shape: \"outline\",\n outline,\n stroke_width: 0,\n }\n}\n\nfunction getElementLayers(elem: OverlappableElement): string[] {\n if (isCourtyardElement(elem)) {\n return [elem.layer]\n }\n\n return getLayersOfPcbElement(elem as Collidable)\n}\n\nfunction doLayersOverlap(layers1: string[], layers2: string[]): boolean {\n if (layers1.length === 0 || layers2.length === 0) return true\n return layers1.some((l) => layers2.includes(l))\n}\n\nexport function doPcbElementsOverlap(\n elem1: OverlappableElement,\n elem2: OverlappableElement,\n): boolean {\n // If the elements are on completely different layers they cannot overlap\n const layers1 = getElementLayers(elem1)\n const layers2 = getElementLayers(elem2)\n if (!doLayersOverlap(layers1, layers2)) return false\n\n if (elem1.type === \"pcb_smtpad\" && elem2.type === \"pcb_smtpad\") {\n return getPadToPadGap(elem1, elem2) <= 0\n }\n\n if (elem1.type === \"pcb_plated_hole\" && isCourtyardElement(elem2)) {\n return getPadToPadGap(elem1, courtyardToKeepout(elem2)) <= 0\n }\n\n if (isCourtyardElement(elem1) && elem2.type === \"pcb_plated_hole\") {\n return getPadToPadGap(elem2, courtyardToKeepout(elem1)) <= 0\n }\n\n const bounds1 = getBoundsOfPcbElements([elem1])\n const bounds2 = getBoundsOfPcbElements([elem2])\n return doBoundsOverlap(bounds1, bounds2)\n}\n","import type {\n AnyCircuitElement,\n PcbComponent,\n PcbComponentMissingCourtyardWarning,\n} from \"circuit-json\"\nimport { getReadableNameForComponent } from \"./util/get-readable-names\"\n\nconst courtyardTypes = new Set([\n \"pcb_courtyard_circle\",\n \"pcb_courtyard_outline\",\n \"pcb_courtyard_polygon\",\n \"pcb_courtyard_pill\",\n \"pcb_courtyard_rect\",\n])\n\n/** Returns warnings for PCB components without courtyards, excluding manually placed vias. */\nexport function checkPcbComponentsMissingCourtyard(\n circuitJson: AnyCircuitElement[],\n): PcbComponentMissingCourtyardWarning[] {\n const manuallyPlacedViaSourceIds = new Set(\n circuitJson\n .filter((element) => element.type === \"source_manually_placed_via\")\n .map((element) => element.source_manually_placed_via_id),\n )\n const componentIdsWithCourtyards = new Set(\n circuitJson\n .filter((element) => courtyardTypes.has(element.type))\n .flatMap((element) =>\n \"pcb_component_id\" in element && element.pcb_component_id\n ? [element.pcb_component_id]\n : [],\n ),\n )\n\n return circuitJson\n .filter(\n (element): element is PcbComponent => element.type === \"pcb_component\",\n )\n .filter(\n (component) =>\n !componentIdsWithCourtyards.has(component.pcb_component_id) &&\n (!component.source_component_id ||\n !manuallyPlacedViaSourceIds.has(component.source_component_id)),\n )\n .map((component) => {\n const sourceComponent = component.source_component_id\n ? circuitJson.find(\n (element) =>\n element.type === \"source_component\" &&\n element.source_component_id === component.source_component_id,\n )\n : undefined\n const componentName =\n sourceComponent?.type === \"source_component\"\n ? sourceComponent.name\n : getReadableNameForComponent(circuitJson, component.pcb_component_id)\n\n return {\n type: \"pcb_component_missing_courtyard_warning\" as const,\n pcb_component_missing_courtyard_warning_id: `pcb_component_missing_courtyard_warning_${component.pcb_component_id}`,\n warning_type: \"pcb_component_missing_courtyard_warning\" as const,\n message: `${componentName} has no courtyard`,\n pcb_component_id: component.pcb_component_id,\n source_component_id: component.source_component_id,\n subcircuit_id: component.subcircuit_id,\n }\n })\n}\n","import type { PcbTrace } from \"circuit-json\"\n\n/** Use the router's length when supplied; otherwise measure the route in mm.\n * Via depth defaults to 1.6mm, matching the existing trace length check.\n */\nexport const getPcbTraceLength = (trace: PcbTrace): number => {\n if (trace.trace_length !== undefined) return trace.trace_length\n let length = 0\n let previousEnd: { x: number; y: number } | undefined\n for (const point of trace.route) {\n const start = point.route_type === \"through_pad\" ? point.start : point\n if (previousEnd)\n length += Math.hypot(start.x - previousEnd.x, start.y - previousEnd.y)\n if (point.route_type === \"via\") length += 1.6\n if (point.route_type === \"through_pad\") {\n length += Math.hypot(\n point.end.x - point.start.x,\n point.end.y - point.start.y,\n )\n previousEnd = point.end\n } else {\n previousEnd = point\n }\n }\n return length\n}\n","import { getPcbTraceLength } from \"./util/get-pcb-trace-length\"\nimport type {\n AnyCircuitElement,\n PcbPort,\n PcbTrace,\n PcbTraceTooLongError,\n SourceTrace,\n} from \"circuit-json\"\n\nconst getReferencedPcbPortIds = (pcbTrace: PcbTrace): Set<string> => {\n const pcbPortIds = new Set<string>()\n\n for (const routePoint of pcbTrace.route) {\n if (routePoint.route_type !== \"wire\") continue\n if (routePoint.start_pcb_port_id) {\n pcbPortIds.add(routePoint.start_pcb_port_id)\n }\n if (routePoint.end_pcb_port_id) {\n pcbPortIds.add(routePoint.end_pcb_port_id)\n }\n }\n\n return pcbPortIds\n}\n\nexport const getPcbTracesBySourceTraceId = (\n circuitJson: AnyCircuitElement[],\n) => {\n const sourceTraces = circuitJson.filter(\n (element): element is SourceTrace => element.type === \"source_trace\",\n )\n const pcbTraces = circuitJson.filter(\n (element): element is PcbTrace => element.type === \"pcb_trace\",\n )\n const pcbPorts = circuitJson.filter(\n (element): element is PcbPort => element.type === \"pcb_port\",\n )\n\n const pcbPortIdsBySourcePortId = new Map<string, Set<string>>()\n for (const pcbPort of pcbPorts) {\n if (!pcbPort.source_port_id) continue\n const pcbPortIds =\n pcbPortIdsBySourcePortId.get(pcbPort.source_port_id) ?? new Set<string>()\n pcbPortIds.add(pcbPort.pcb_port_id)\n pcbPortIdsBySourcePortId.set(pcbPort.source_port_id, pcbPortIds)\n }\n\n const pcbTracesBySourceTraceId = new Map<string, PcbTrace[]>()\n for (const pcbTrace of pcbTraces) {\n if (!pcbTrace.source_trace_id) continue\n const matchingPcbTraces =\n pcbTracesBySourceTraceId.get(pcbTrace.source_trace_id) ?? []\n matchingPcbTraces.push(pcbTrace)\n pcbTracesBySourceTraceId.set(pcbTrace.source_trace_id, matchingPcbTraces)\n }\n\n const exactEndpointPcbTraceIdsBySourceTraceId = new Map<string, Set<string>>()\n for (const sourceTrace of sourceTraces) {\n if (sourceTrace.connected_source_port_ids.length !== 2) continue\n\n const endpointPcbPortIds = sourceTrace.connected_source_port_ids.map(\n (sourcePortId) => pcbPortIdsBySourcePortId.get(sourcePortId),\n )\n if (endpointPcbPortIds.some((pcbPortIds) => !pcbPortIds?.size)) continue\n\n const exactEndpointPcbTraceIds = new Set(\n (pcbTracesBySourceTraceId.get(sourceTrace.source_trace_id) ?? [])\n .filter((pcbTrace) => {\n const referencedPcbPortIds = getReferencedPcbPortIds(pcbTrace)\n return endpointPcbPortIds.every((pcbPortIds) =>\n [...pcbPortIds!].some((pcbPortId) =>\n referencedPcbPortIds.has(pcbPortId),\n ),\n )\n })\n .map((pcbTrace) => pcbTrace.pcb_trace_id),\n )\n\n // Keep the existing behavior when the route does not expose one PCB trace\n // joining both explicit endpoints (for example through-pad-only routes).\n if (exactEndpointPcbTraceIds.size > 0) {\n exactEndpointPcbTraceIdsBySourceTraceId.set(\n sourceTrace.source_trace_id,\n exactEndpointPcbTraceIds,\n )\n }\n }\n for (const [id, exactIds] of exactEndpointPcbTraceIdsBySourceTraceId) {\n pcbTracesBySourceTraceId.set(\n id,\n pcbTracesBySourceTraceId\n .get(id)!\n .filter((trace) => exactIds.has(trace.pcb_trace_id)),\n )\n }\n return pcbTracesBySourceTraceId\n}\n\nexport const checkPcbTraceLengths = (\n circuitJson: AnyCircuitElement[],\n): PcbTraceTooLongError[] => {\n const sourceTracesById = new Map(\n circuitJson\n .filter((e): e is SourceTrace => e.type === \"source_trace\")\n .map((e) => [e.source_trace_id, e]),\n )\n const pcbTracesBySourceTraceId = getPcbTracesBySourceTraceId(circuitJson)\n const errors: PcbTraceTooLongError[] = []\n\n for (const [sourceTraceId, pcbTraces] of pcbTracesBySourceTraceId) {\n const pcbTrace = pcbTraces[0]!\n const sourceTrace = sourceTracesById.get(sourceTraceId)\n if (!sourceTrace) continue\n\n const maximumTraceLength = sourceTrace.max_length\n if (typeof maximumTraceLength !== \"number\") continue\n\n const actualTraceLength = pcbTraces.reduce(\n (sum, trace) => sum + getPcbTraceLength(trace),\n 0,\n )\n if (actualTraceLength <= maximumTraceLength + 1e-9) continue\n\n errors.push({\n type: \"pcb_trace_too_long_error\",\n pcb_trace_too_long_error_id: `pcb_trace_too_long_error_${pcbTrace.pcb_trace_id}`,\n error_type: \"pcb_trace_too_long_error\",\n message: `PCB trace is ${actualTraceLength.toFixed(2)}mm long, exceeding the ${maximumTraceLength}mm maximum`,\n pcb_trace_id: pcbTrace.pcb_trace_id,\n source_trace_id: sourceTrace.source_trace_id,\n source_net_id: sourceTrace.connected_source_net_ids[0],\n actual_trace_length: actualTraceLength,\n maximum_trace_length: maximumTraceLength,\n subcircuit_id: pcbTrace.subcircuit_id ?? sourceTrace.subcircuit_id,\n })\n }\n\n return errors\n}\n","import type {\n AnyCircuitElement,\n PcbPort,\n PcbTrace,\n PcbTraceError,\n SourceTrace,\n} from \"circuit-json\"\n\n/** Return a routing error when a source trace exceeds its maximum via count. */\nexport const checkPcbTraceViaCounts = (\n circuitJson: AnyCircuitElement[],\n): PcbTraceError[] => {\n const sourceTraces = circuitJson.filter(\n (element): element is SourceTrace => element.type === \"source_trace\",\n )\n const pcbTraces = circuitJson.filter(\n (element): element is PcbTrace => element.type === \"pcb_trace\",\n )\n const pcbPorts = circuitJson.filter(\n (element): element is PcbPort => element.type === \"pcb_port\",\n )\n const errors: PcbTraceError[] = []\n\n for (const sourceTrace of sourceTraces) {\n const maximumViaCount = sourceTrace.max_via_count\n if (typeof maximumViaCount !== \"number\") continue\n\n const routedPcbTraces = pcbTraces.filter(\n (pcbTrace) => pcbTrace.source_trace_id === sourceTrace.source_trace_id,\n )\n if (routedPcbTraces.length === 0) continue\n\n const actualViaCount = routedPcbTraces.reduce(\n (viaCount, pcbTrace) =>\n viaCount +\n pcbTrace.route.filter((routePoint) => routePoint.route_type === \"via\")\n .length,\n 0,\n )\n if (actualViaCount <= maximumViaCount) continue\n\n const connectedPcbPorts = pcbPorts.filter(\n (pcbPort) =>\n pcbPort.source_port_id !== undefined &&\n sourceTrace.connected_source_port_ids.includes(pcbPort.source_port_id),\n )\n errors.push({\n type: \"pcb_trace_error\",\n pcb_trace_error_id: `max_via_count_exceeded_${sourceTrace.source_trace_id}`,\n error_type: \"pcb_trace_error\",\n message: `PCB trace uses ${actualViaCount} vias, exceeding the ${maximumViaCount} maximum`,\n pcb_trace_id: routedPcbTraces[0]!.pcb_trace_id,\n source_trace_id: sourceTrace.source_trace_id,\n pcb_component_ids: [\n ...new Set(\n connectedPcbPorts\n .map((pcbPort) => pcbPort.pcb_component_id)\n .filter(\n (pcbComponentId): pcbComponentId is string =>\n pcbComponentId !== undefined,\n ),\n ),\n ],\n pcb_port_ids: connectedPcbPorts.map((pcbPort) => pcbPort.pcb_port_id),\n subcircuit_id:\n routedPcbTraces[0]!.subcircuit_id ?? sourceTrace.subcircuit_id,\n })\n }\n\n return errors\n}\n","import {\n getPrimaryId,\n getReadableNameForElement,\n} from \"@tscircuit/circuit-json-util\"\nimport type { AnyCircuitElement, PcbPadPadClearanceError } from \"circuit-json\"\nimport { formatMm } from \"format-si-unit\"\nimport {\n type ConnectivityMap,\n getFullConnectivityMapFromCircuitJson,\n} from \"circuit-json-to-connectivity-map\"\nimport { SpatialObjectIndex } from \"lib/data-structures/SpatialIndex\"\nimport { EPSILON, getBoardDrcValue, getPcbBoard } from \"lib/drc-defaults\"\nimport { getLayersOfPcbElement } from \"lib/util/getLayersOfPcbElement\"\nimport {\n type PadElement,\n getPadBounds,\n getPadCenter,\n getPadToPadGap,\n getPads,\n} from \"./check-pad-clearance/common\"\nimport { jlcMinTolerances } from \"@tscircuit/jlcpcb-manufacturing-specs\"\n\nexport function checkPadPadClearance(\n circuitJson: AnyCircuitElement[],\n {\n connMap,\n minClearance,\n }: { connMap?: ConnectivityMap; minClearance?: number } = {},\n): PcbPadPadClearanceError[] {\n const pads = getPads(circuitJson)\n if (pads.length < 2) return []\n\n const board = getPcbBoard(circuitJson)\n minClearance ??=\n getBoardDrcValue(board, \"min_pad_edge_to_pad_edge_clearance\") ??\n jlcMinTolerances.min_pad_edge_to_pad_edge_clearance\n connMap ??= getFullConnectivityMapFromCircuitJson(circuitJson)\n const spatialIndex = new SpatialObjectIndex<PadElement>({\n objects: pads,\n getBounds: getPadBounds,\n getId: (pad) => getPrimaryId(pad),\n })\n\n const errors = new Map<string, PcbPadPadClearanceError>()\n\n for (const padA of pads) {\n const padAId = getPrimaryId(padA)\n const nearbyPads = spatialIndex.getObjectsInBounds(\n getPadBounds(padA),\n minClearance,\n )\n\n for (const padB of nearbyPads) {\n const padBId = getPrimaryId(padB)\n if (padAId === padBId) continue\n if (\n !getLayersOfPcbElement(padA as any).some((layer) =>\n getLayersOfPcbElement(padB as any).includes(layer),\n )\n ) {\n continue\n }\n if (connMap.areIdsConnected(padAId, padBId)) continue\n\n const pairId = [padAId, padBId].sort().join(\"_\")\n const gap = getPadToPadGap(padA, padB)\n if (gap + EPSILON >= minClearance!) continue\n const centerA = getPadCenter(padA)\n const centerB = getPadCenter(padB)\n\n const nextError: PcbPadPadClearanceError = {\n type: \"pcb_pad_pad_clearance_error\",\n pcb_pad_pad_clearance_error_id: `pad_pad_clearance_${pairId}`,\n error_type: \"pcb_pad_pad_clearance_error\",\n message: `Pads ${getReadableNameForElement(circuitJson, padAId)} and ${getReadableNameForElement(circuitJson, padBId)} are too close (clearance: ${formatMm(gap)}, minimum: ${formatMm(minClearance!)})`,\n pcb_pad_ids: [padAId, padBId] as [string, string],\n minimum_clearance: minClearance,\n actual_clearance: gap,\n center: {\n x: (centerA.x + centerB.x) / 2,\n y: (centerA.y + centerB.y) / 2,\n },\n }\n\n if (!errors.has(pairId)) {\n errors.set(pairId, nextError)\n }\n }\n }\n\n return Array.from(errors.values())\n}\n","import {\n getPrimaryId,\n getReadableNameForElement,\n} from \"@tscircuit/circuit-json-util\"\nimport { jlcMinTolerances } from \"@tscircuit/jlcpcb-manufacturing-specs\"\nimport type { AnyCircuitElement, PcbPadTraceClearanceError } from \"circuit-json\"\nimport { formatMm } from \"format-si-unit\"\nimport {\n type ConnectivityMap,\n getFullConnectivityMapFromCircuitJson,\n} from \"circuit-json-to-connectivity-map\"\nimport { getCollidableBounds } from \"lib/check-each-pcb-trace-non-overlapping/getCollidableBounds\"\nimport { SpatialObjectIndex } from \"lib/data-structures/SpatialIndex\"\nimport { EPSILON, getBoardDrcValue, getPcbBoard } from \"lib/drc-defaults\"\nimport { getLayersOfPcbElement } from \"lib/util/getLayersOfPcbElement\"\nimport {\n type PadElement,\n getPadBounds,\n getPads,\n getTraceObstacleClearance,\n getTraceSegments,\n isTraceObstacleOverlap,\n} from \"./check-pad-clearance/common\"\n\nexport function checkPadTraceClearance(\n circuitJson: AnyCircuitElement[],\n {\n connMap,\n minClearance,\n }: { connMap?: ConnectivityMap; minClearance?: number } = {},\n): PcbPadTraceClearanceError[] {\n const pads = getPads(circuitJson)\n const segments = getTraceSegments(circuitJson)\n if (pads.length === 0 || segments.length === 0) return []\n\n const board = getPcbBoard(circuitJson)\n minClearance ??=\n getBoardDrcValue(board, \"min_trace_to_pad_edge_clearance\") ??\n jlcMinTolerances.min_trace_to_pad_edge_clearance\n connMap ??= getFullConnectivityMapFromCircuitJson(circuitJson)\n const spatialIndex = new SpatialObjectIndex<PadElement>({\n objects: pads,\n getBounds: getPadBounds,\n getId: (pad) => getPrimaryId(pad),\n })\n\n const errors = new Map<\n string,\n { error: PcbPadTraceClearanceError; gap: number }\n >()\n const overlappingPairIds = new Set<string>()\n\n for (const segment of segments) {\n const nearbyPads = spatialIndex.getObjectsInBounds(\n getCollidableBounds(segment),\n minClearance! + segment.thickness / 2,\n )\n\n for (const pad of nearbyPads) {\n const padId = getPrimaryId(pad)\n if (!getLayersOfPcbElement(pad as any).includes(segment.layer)) continue\n if (connMap.areIdsConnected(segment.pcb_trace_id, padId)) continue\n const pairId = `${padId}_${segment.pcb_trace_id}`\n const { gap, center } = getTraceObstacleClearance(segment, pad)\n if (isTraceObstacleOverlap(gap)) {\n errors.delete(pairId)\n overlappingPairIds.add(pairId)\n continue\n }\n if (overlappingPairIds.has(pairId)) continue\n if (gap + EPSILON >= minClearance!) continue\n\n const nextError: PcbPadTraceClearanceError = {\n type: \"pcb_pad_trace_clearance_error\" as const,\n pcb_pad_trace_clearance_error_id: `pad_trace_clearance_${pairId}`,\n error_type: \"pcb_pad_trace_clearance_error\",\n message: `Pad ${getReadableNameForElement(circuitJson, padId)} and trace ${getReadableNameForElement(circuitJson, segment.pcb_trace_id)} are too close (clearance: ${formatMm(gap)}, minimum: ${formatMm(minClearance!)})`,\n pcb_pad_id: padId,\n pcb_trace_id: segment.pcb_trace_id,\n minimum_clearance: minClearance,\n actual_clearance: gap,\n center,\n }\n\n const current = errors.get(pairId)\n if (!current || gap < current.gap) {\n errors.set(pairId, { error: nextError, gap })\n }\n }\n }\n\n return Array.from(errors.values()).map(({ error }) => error)\n}\n","import { getReadableNameForElement } from \"@tscircuit/circuit-json-util\"\nimport { jlcMinTolerances } from \"@tscircuit/jlcpcb-manufacturing-specs\"\nimport type {\n AnyCircuitElement,\n PcbVia,\n PcbViaTraceClearanceError,\n} from \"circuit-json\"\nimport { formatMm } from \"format-si-unit\"\nimport {\n type ConnectivityMap,\n getFullConnectivityMapFromCircuitJson,\n} from \"circuit-json-to-connectivity-map\"\nimport { EPSILON, getBoardDrcValue, getPcbBoard } from \"lib/drc-defaults\"\nimport { getLayersOfPcbElement } from \"lib/util/getLayersOfPcbElement\"\nimport {\n getTraceObstacleClearance,\n getTraceSegments,\n isTraceObstacleOverlap,\n} from \"./check-pad-clearance/common\"\n\nexport function checkViaTraceClearance(\n circuitJson: AnyCircuitElement[],\n {\n connMap,\n minClearance,\n }: { connMap?: ConnectivityMap; minClearance?: number } = {},\n): PcbViaTraceClearanceError[] {\n const vias = circuitJson.filter((el) => el.type === \"pcb_via\") as PcbVia[]\n const segments = getTraceSegments(circuitJson)\n if (vias.length === 0 || segments.length === 0) return []\n\n const board = getPcbBoard(circuitJson)\n minClearance ??=\n getBoardDrcValue(board, \"min_trace_to_pad_edge_clearance\") ??\n jlcMinTolerances.min_trace_to_pad_edge_clearance\n connMap ??= getFullConnectivityMapFromCircuitJson(circuitJson)\n const errors = new Map<\n string,\n { error: PcbViaTraceClearanceError; gap: number }\n >()\n const overlappingPairIds = new Set<string>()\n\n for (const via of vias) {\n for (const segment of segments) {\n if (!getLayersOfPcbElement(via).includes(segment.layer)) continue\n if (connMap.areIdsConnected(segment.pcb_trace_id, via.pcb_via_id))\n continue\n\n const pairId = `${via.pcb_via_id}_${segment.pcb_trace_id}`\n const { gap, center } = getTraceObstacleClearance(segment, via)\n if (isTraceObstacleOverlap(gap)) {\n errors.delete(pairId)\n overlappingPairIds.add(pairId)\n continue\n }\n if (overlappingPairIds.has(pairId)) continue\n if (gap + EPSILON >= minClearance!) continue\n\n const nextError: PcbViaTraceClearanceError = {\n type: \"pcb_via_trace_clearance_error\",\n pcb_via_trace_clearance_error_id: `via_trace_clearance_${pairId}`,\n error_type: \"pcb_via_trace_clearance_error\",\n message: `Via ${getReadableNameForElement(circuitJson, via.pcb_via_id)} and trace ${getReadableNameForElement(circuitJson, segment.pcb_trace_id)} are too close (clearance: ${formatMm(gap)}, minimum: ${formatMm(minClearance!)})`,\n pcb_via_id: via.pcb_via_id,\n pcb_trace_id: segment.pcb_trace_id,\n minimum_clearance: minClearance,\n actual_clearance: gap,\n center,\n }\n\n const current = errors.get(pairId)\n if (!current || gap < current.gap) {\n errors.set(pairId, { error: nextError, gap })\n }\n }\n }\n\n return Array.from(errors.values()).map(({ error }) => error)\n}\n","import {\n getPrimaryId,\n getReadableNameForElement,\n} from \"@tscircuit/circuit-json-util\"\nimport { jlcMinTolerances } from \"@tscircuit/jlcpcb-manufacturing-specs\"\nimport type {\n AnyCircuitElement,\n PcbPadPadClearanceError,\n PcbVia,\n} from \"circuit-json\"\nimport { formatMm } from \"format-si-unit\"\nimport {\n type ConnectivityMap,\n getFullConnectivityMapFromCircuitJson,\n} from \"circuit-json-to-connectivity-map\"\nimport { SpatialObjectIndex } from \"lib/data-structures/SpatialIndex\"\nimport { EPSILON, getBoardDrcValue, getPcbBoard } from \"lib/drc-defaults\"\nimport { getLayersOfPcbElement } from \"lib/util/getLayersOfPcbElement\"\nimport {\n type PadElement,\n getPadBounds,\n getViaPadClearanceCenter,\n getPadToPadGap,\n getPads,\n} from \"./check-pad-clearance/common\"\n\nexport function checkViaPadClearance(\n circuitJson: AnyCircuitElement[],\n {\n connMap,\n minClearance,\n }: { connMap?: ConnectivityMap; minClearance?: number } = {},\n): PcbPadPadClearanceError[] {\n const vias = circuitJson.filter(\n (element): element is PcbVia => element.type === \"pcb_via\",\n )\n const pads = getPads(circuitJson)\n if (vias.length === 0 || pads.length === 0) return []\n\n const board = getPcbBoard(circuitJson)\n const requiredClearance =\n minClearance ??\n getBoardDrcValue(board, \"min_pad_edge_to_pad_edge_clearance\") ??\n jlcMinTolerances.min_pad_edge_to_pad_edge_clearance!\n connMap ??= getFullConnectivityMapFromCircuitJson(circuitJson)\n\n const padIndex = new SpatialObjectIndex<PadElement>({\n objects: pads,\n getBounds: getPadBounds,\n getId: getPrimaryId,\n })\n const errors: PcbPadPadClearanceError[] = []\n\n for (const via of vias) {\n const nearbyPads = padIndex.getObjectsInBounds(\n getPadBounds(via),\n requiredClearance,\n )\n\n for (const pad of nearbyPads) {\n const padId = getPrimaryId(pad)\n if (\n !getLayersOfPcbElement(via).some((layer) =>\n getLayersOfPcbElement(pad).includes(layer),\n )\n ) {\n continue\n }\n if (connMap.areIdsConnected(via.pcb_via_id, padId)) continue\n\n const gap = getPadToPadGap(via, pad)\n if (gap + EPSILON >= requiredClearance) continue\n\n errors.push({\n type: \"pcb_pad_pad_clearance_error\",\n pcb_pad_pad_clearance_error_id: `via_pad_clearance_${via.pcb_via_id}_${padId}`,\n error_type: \"pcb_pad_pad_clearance_error\",\n message: `Via ${getReadableNameForElement(circuitJson, via.pcb_via_id)} and pad ${getReadableNameForElement(circuitJson, padId)} are too close (clearance: ${formatMm(gap)}, minimum: ${formatMm(requiredClearance)})`,\n pcb_pad_ids: [via.pcb_via_id, padId],\n minimum_clearance: requiredClearance,\n actual_clearance: gap,\n center: getViaPadClearanceCenter(via, pad),\n })\n }\n }\n\n return errors\n}\n","import { getPrimaryId } from \"@tscircuit/circuit-json-util\"\nimport type { AnyCircuitElement, PcbPlacementError, PcbVia } from \"circuit-json\"\nimport { getFullConnectivityMapFromCircuitJson } from \"circuit-json-to-connectivity-map\"\nimport {\n type PadElement,\n getPadBounds,\n getPadToPadGap,\n getPads,\n} from \"./check-pad-clearance/common\"\nimport { SpatialObjectIndex } from \"./data-structures/SpatialIndex\"\nimport { getPcbBoard } from \"./drc-defaults\"\nimport { getLayersOfPcbElement } from \"./util/getLayersOfPcbElement\"\nimport { getReadableNameForFootprintPad } from \"./util/get-readable-names\"\n\nexport function checkViasInPads(\n circuitJson: AnyCircuitElement[],\n): PcbPlacementError[] {\n const board = getPcbBoard(circuitJson)\n if (\n board &&\n \"is_via_in_pad_allowed\" in board &&\n board.is_via_in_pad_allowed === true\n ) {\n return []\n }\n\n const vias = circuitJson.filter(\n (element): element is PcbVia => element.type === \"pcb_via\",\n )\n const pads = getPads(circuitJson)\n if (vias.length === 0 || pads.length === 0) return []\n const connMap = getFullConnectivityMapFromCircuitJson(circuitJson)\n\n const padOrdinals = new Map(\n pads.map((pad, index) => [getPrimaryId(pad), index]),\n )\n const padIndex = new SpatialObjectIndex<PadElement>({\n objects: pads,\n getBounds: getPadBounds,\n getId: getPrimaryId,\n })\n const errors: PcbPlacementError[] = []\n\n for (const via of vias) {\n const nearbyPads = padIndex.getObjectsInBounds(getPadBounds(via))\n\n for (const pad of nearbyPads) {\n const padId = getPrimaryId(pad)\n const viaLayers = getLayersOfPcbElement(via)\n const padLayers = getLayersOfPcbElement(pad)\n if (!viaLayers.some((layer) => padLayers.includes(layer))) continue\n if (connMap.areIdsConnected(via.pcb_via_id, padId)) continue\n if (getPadToPadGap(via, pad) > 0) continue\n\n const padOrdinal = padOrdinals.get(padId) ?? 0\n const padName = getReadableNameForFootprintPad(\n circuitJson,\n pad,\n padOrdinal,\n )\n\n errors.push({\n type: \"pcb_placement_error\",\n pcb_placement_error_id: `via_in_pad_${via.pcb_via_id}_${padId}`,\n error_type: \"pcb_placement_error\",\n message: `Via copper at (${via.x.toFixed(2)}mm, ${via.y.toFixed(2)}mm) overlaps ${padName}`,\n subcircuit_id: via.subcircuit_id ?? pad.subcircuit_id,\n })\n }\n }\n\n return errors\n}\n","import type { AnyCircuitElement } from \"circuit-json\"\n\ntype DrcRecord = AnyCircuitElement & Record<string, unknown>\n\n/**\n * Removes generic pcb_trace_error records when a more specific pad-trace or\n * via-trace clearance error describes the same physical pair.\n *\n * The specific record is retained because it includes the measured and\n * required clearance. Trace-trace and all other generic errors are untouched.\n *\n * @deprecated Aggregate runners now classify trace-obstacle pairs as either\n * overlap or clearance before combining results, so they no longer need this\n * post-processing step. Kept for callers combining results from older checks.\n */\nexport const dedupePcbDrcErrors = <T extends AnyCircuitElement>(\n errors: T[],\n): T[] => {\n const specificallyReportedPairIds = new Set<string>()\n\n for (const error of errors as DrcRecord[]) {\n if (\n error.type === \"pcb_pad_trace_clearance_error\" &&\n typeof error.pcb_trace_id === \"string\" &&\n typeof error.pcb_pad_id === \"string\"\n ) {\n specificallyReportedPairIds.add(\n `overlap_${error.pcb_trace_id}_${error.pcb_pad_id}`,\n )\n }\n\n if (\n error.type === \"pcb_via_trace_clearance_error\" &&\n typeof error.pcb_trace_id === \"string\" &&\n typeof error.pcb_via_id === \"string\"\n ) {\n specificallyReportedPairIds.add(\n `overlap_${error.pcb_trace_id}_${error.pcb_via_id}`,\n )\n }\n }\n\n return errors.filter((element) => {\n const error = element as DrcRecord\n return !(\n error.type === \"pcb_trace_error\" &&\n typeof error.pcb_trace_error_id === \"string\" &&\n specificallyReportedPairIds.has(error.pcb_trace_error_id)\n )\n })\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 {\n type AnyCircuitElement,\n type SchematicPort,\n type SourceComponentMisconfiguredError,\n type SourcePort,\n type SourceSimplePushButton,\n type SourceSimpleSwitch,\n source_component_misconfigured_error,\n} from \"circuit-json\"\n\ntype SwitchingComponent = SourceSimplePushButton | SourceSimpleSwitch\n\nexport function checkTwoTerminalSwitchContactsOnDifferentNets(\n circuitJson: AnyCircuitElement[],\n): SourceComponentMisconfiguredError[] {\n const switchingComponents = circuitJson.filter(\n (element): element is SwitchingComponent =>\n element.type === \"source_component\" &&\n (element.ftype === \"simple_push_button\" ||\n element.ftype === \"simple_switch\"),\n )\n const sourcePorts = circuitJson.filter(\n (element): element is SourcePort => element.type === \"source_port\",\n )\n const schematicPorts = circuitJson.filter(\n (element): element is SchematicPort => element.type === \"schematic_port\",\n )\n const errors: SourceComponentMisconfiguredError[] = []\n\n for (const switchingComponent of switchingComponents) {\n const schematicContactSourcePorts = schematicPorts.flatMap(\n (schematicPort) => {\n const sourcePort = sourcePorts.find(\n (sourcePort) =>\n sourcePort.source_port_id === schematicPort.source_port_id &&\n sourcePort.source_component_id ===\n switchingComponent.source_component_id,\n )\n if (!sourcePort) return []\n return [sourcePort]\n },\n )\n if (schematicContactSourcePorts.length !== 2) continue\n\n const firstContactConnectivityKey =\n schematicContactSourcePorts[0].subcircuit_connectivity_map_key\n const secondContactConnectivityKey =\n schematicContactSourcePorts[1].subcircuit_connectivity_map_key\n if (!firstContactConnectivityKey) continue\n if (firstContactConnectivityKey !== secondContactConnectivityKey) continue\n\n errors.push(\n source_component_misconfigured_error.parse({\n type: \"source_component_misconfigured_error\",\n message: `Switch ${switchingComponent.name} has both schematic contacts connected to the same net. Check internallyConnectedPins and the footprint pin mapping.`,\n source_component_ids: [switchingComponent.source_component_id],\n source_port_ids: schematicContactSourcePorts.map(\n (sourcePort) => sourcePort.source_port_id,\n ),\n is_fatal: true,\n }),\n )\n }\n\n return errors\n}\n","import { cju } from \"@tscircuit/circuit-json-util\"\nimport type {\n AnyCircuitElement,\n SourceComponentPinsUnderspecifiedWarning,\n SourcePinAttributes,\n SourcePort,\n SourceComponentBase,\n} from \"circuit-json\"\n\nconst PIN_ATTRIBUTE_KEYS = [\n \"must_be_connected\",\n \"provides_power\",\n \"requires_power\",\n \"provides_ground\",\n \"requires_ground\",\n \"provides_voltage\",\n \"requires_voltage\",\n \"do_not_connect\",\n \"include_in_board_pinout\",\n \"can_use_internal_pullup\",\n \"is_using_internal_pullup\",\n \"needs_external_pullup\",\n \"can_use_internal_pulldown\",\n \"is_using_internal_pulldown\",\n \"needs_external_pulldown\",\n \"can_use_open_drain\",\n \"is_using_open_drain\",\n \"can_use_push_pull\",\n \"is_using_push_pull\",\n \"should_have_decoupling_capacitor\",\n \"recommended_decoupling_capacitor_capacitance\",\n \"is_configured_for_i2c_sda\",\n \"is_configured_for_i2c_scl\",\n \"is_configured_for_spi_mosi\",\n \"is_configured_for_spi_miso\",\n \"is_configured_for_spi_sck\",\n \"is_configured_for_spi_cs\",\n \"is_configured_for_uart_tx\",\n \"is_configured_for_uart_rx\",\n \"supports_i2c_sda\",\n \"supports_i2c_scl\",\n \"supports_spi_mosi\",\n \"supports_spi_miso\",\n \"supports_spi_sck\",\n \"supports_spi_cs\",\n \"supports_uart_tx\",\n \"supports_uart_rx\",\n] as const satisfies readonly (keyof SourcePinAttributes)[]\n\nfunction hasAnyPinAttribute(port: SourcePort): boolean {\n return PIN_ATTRIBUTE_KEYS.some((key) => port[key] !== undefined)\n}\n\n/**\n * Check that each component with ports has at least one pin attribute\n * specified across its ports. Returns a warning when all pins are\n * underspecified (no SourcePinAttributes fields set on any port).\n */\nexport function checkAllPinsInComponentAreUnderspecified(\n circuitJson: AnyCircuitElement[],\n): SourceComponentPinsUnderspecifiedWarning[] {\n const warnings: SourceComponentPinsUnderspecifiedWarning[] = []\n const db = cju(circuitJson)\n\n const sourceComponents = db.source_component.list() as SourceComponentBase[]\n const sourcePorts = db.source_port.list() as SourcePort[]\n\n const portsByComponent = new Map<string, SourcePort[]>()\n for (const port of sourcePorts) {\n if (!port.source_component_id) continue\n const existing = portsByComponent.get(port.source_component_id) ?? []\n existing.push(port)\n portsByComponent.set(port.source_component_id, existing)\n }\n\n for (const component of sourceComponents) {\n if (component.ftype !== \"simple_chip\") continue\n\n const componentPorts =\n portsByComponent.get(component.source_component_id) ?? []\n if (componentPorts.length === 0) continue\n\n const hasAnySpecifiedAttributes = componentPorts.some((port) =>\n hasAnyPinAttribute(port),\n )\n\n if (hasAnySpecifiedAttributes) continue\n\n warnings.push({\n type: \"source_component_pins_underspecified_warning\",\n source_component_pins_underspecified_warning_id: `source_component_pins_underspecified_warning_${component.source_component_id}`,\n warning_type: \"source_component_pins_underspecified_warning\",\n message: `All pins on ${component.name} are underspecified (no pinAttributes set)`,\n source_component_id: component.source_component_id,\n source_port_ids: componentPorts.map((port) => port.source_port_id),\n subcircuit_id: componentPorts[0]?.subcircuit_id,\n })\n }\n\n return warnings\n}\n","import { cju } from \"@tscircuit/circuit-json-util\"\nimport type {\n AnyCircuitElement,\n SourceComponentBase,\n SourceNoPowerPinDefinedWarning,\n SourcePort,\n} from \"circuit-json\"\nimport { shouldCheckChipPowerGroundPins } from \"./util/should-check-chip-power-ground-pins\"\n\n/**\n * Check that each chip has at least one pin marked as requires_power=true.\n * Returns warnings for chips where no pin declares requires_power.\n */\nexport function checkNoPowerPinDefined(\n circuitJson: AnyCircuitElement[],\n): SourceNoPowerPinDefinedWarning[] {\n const warnings: SourceNoPowerPinDefinedWarning[] = []\n const db = cju(circuitJson)\n\n const sourceComponents = db.source_component.list() as SourceComponentBase[]\n const sourcePorts = db.source_port.list() as SourcePort[]\n\n const portsByComponent = new Map<string, SourcePort[]>()\n for (const port of sourcePorts) {\n if (!port.source_component_id) continue\n const existing = portsByComponent.get(port.source_component_id) ?? []\n existing.push(port)\n portsByComponent.set(port.source_component_id, existing)\n }\n\n for (const component of sourceComponents) {\n const componentPorts =\n portsByComponent.get(component.source_component_id) ?? []\n if (!shouldCheckChipPowerGroundPins(component, componentPorts)) continue\n\n const hasRequiredPowerPin = componentPorts.some(\n (port) => port.requires_power === true,\n )\n if (hasRequiredPowerPin) continue\n\n warnings.push({\n type: \"source_no_power_pin_defined_warning\",\n source_no_power_pin_defined_warning_id: `source_no_power_pin_defined_warning_${component.source_component_id}`,\n warning_type: \"source_no_power_pin_defined_warning\",\n message: `${component.name} has no pin with requires_power=true`,\n source_component_id: component.source_component_id,\n source_port_ids: componentPorts.map((port) => port.source_port_id),\n subcircuit_id: componentPorts[0]?.subcircuit_id,\n })\n }\n\n return warnings\n}\n","import type { SourceComponentBase, SourcePort } from \"circuit-json\"\n\n/**\n * Power and ground pin-role checks only apply when a chip exposes enough\n * connectable pins to define both roles. One-port passives such as chip\n * antennas can have additional package pads explicitly marked do-not-connect,\n * but cannot truthfully declare power and ground pins.\n */\nexport const shouldCheckChipPowerGroundPins = (\n component: SourceComponentBase,\n ports: SourcePort[],\n): boolean =>\n component.ftype === \"simple_chip\" &&\n ports.filter((port) => port.do_not_connect !== true).length >= 2\n","import { cju } from \"@tscircuit/circuit-json-util\"\nimport type {\n AnyCircuitElement,\n SourceComponentBase,\n SourceNoGroundPinDefinedWarning,\n SourcePort,\n} from \"circuit-json\"\nimport { shouldCheckChipPowerGroundPins } from \"./util/should-check-chip-power-ground-pins\"\n\n/**\n * Check that each chip has at least one pin marked as requires_ground=true.\n * Returns warnings for chips where no pin declares requires_ground.\n */\nexport function checkNoGroundPinDefined(\n circuitJson: AnyCircuitElement[],\n): SourceNoGroundPinDefinedWarning[] {\n const warnings: SourceNoGroundPinDefinedWarning[] = []\n const db = cju(circuitJson)\n\n const sourceComponents = db.source_component.list() as SourceComponentBase[]\n const sourcePorts = db.source_port.list() as SourcePort[]\n\n const portsByComponent = new Map<string, SourcePort[]>()\n for (const port of sourcePorts) {\n if (!port.source_component_id) continue\n const existing = portsByComponent.get(port.source_component_id) ?? []\n existing.push(port)\n portsByComponent.set(port.source_component_id, existing)\n }\n\n for (const component of sourceComponents) {\n const componentPorts =\n portsByComponent.get(component.source_component_id) ?? []\n if (!shouldCheckChipPowerGroundPins(component, componentPorts)) continue\n\n const hasRequiredGroundPin = componentPorts.some(\n (port) => port.requires_ground === true,\n )\n if (hasRequiredGroundPin) continue\n\n warnings.push({\n type: \"source_no_ground_pin_defined_warning\",\n source_no_ground_pin_defined_warning_id: `source_no_ground_pin_defined_warning_${component.source_component_id}`,\n warning_type: \"source_no_ground_pin_defined_warning\",\n message: `${component.name} has no pin with requires_ground=true`,\n source_component_id: component.source_component_id,\n source_port_ids: componentPorts.map((port) => port.source_port_id),\n subcircuit_id: componentPorts[0]?.subcircuit_id,\n })\n }\n\n return warnings\n}\n","import type {\n AnyCircuitElement,\n SchematicComponent,\n SchematicComponentStylingWarning,\n SchematicPort,\n} from \"circuit-json\"\n\ntype SourceComponent = Extract<AnyCircuitElement, { type: \"source_component\" }>\n\nconst DEFAULT_PIN_SPACING = 0.2\nconst MAX_VERTICAL_PADDING_IN_PIN_SPACINGS = 3\nconst FLOATING_POINT_TOLERANCE = 1e-9\n\ntype VerticalSide = \"top\" | \"bottom\"\n\n/**\n * Warns when the left/right pins of a box-style schematic component leave\n * excessive empty space above or below their vertical span. This commonly\n * happens when an unnecessarily large schematic height is set on a component.\n */\nexport function checkSchematicComponentExcessiveVerticalPadding(\n circuitJson: AnyCircuitElement[],\n): SchematicComponentStylingWarning[] {\n const schematicComponents = circuitJson.filter(\n (element): element is SchematicComponent =>\n element.type === \"schematic_component\",\n )\n const schematicPorts = circuitJson.filter(\n (element): element is SchematicPort => element.type === \"schematic_port\",\n )\n const sourceComponents = circuitJson.filter(\n (element): element is SourceComponent =>\n element.type === \"source_component\",\n )\n\n const sourceComponentById = new Map(\n sourceComponents.map((component) => [\n component.source_component_id,\n component,\n ]),\n )\n const portsByComponentId = new Map<string, SchematicPort[]>()\n\n for (const port of schematicPorts) {\n if (!port.schematic_component_id) continue\n const componentPorts =\n portsByComponentId.get(port.schematic_component_id) ?? []\n componentPorts.push(port)\n portsByComponentId.set(port.schematic_component_id, componentPorts)\n }\n\n const warnings: SchematicComponentStylingWarning[] = []\n\n for (const component of schematicComponents) {\n if (!component.is_box_with_pins || component.size.height <= 0) continue\n\n const sidePorts = (\n portsByComponentId.get(component.schematic_component_id) ?? []\n ).filter(\n (port) =>\n port.side_of_component === \"left\" || port.side_of_component === \"right\",\n )\n\n // A single side pin does not establish a meaningful vertical pin group.\n if (sidePorts.length < 2) continue\n\n const pinYs = sidePorts.map((port) => port.center.y)\n const highestPinY = Math.max(...pinYs)\n const lowestPinY = Math.min(...pinYs)\n const componentTopY = component.center.y + component.size.height / 2\n const componentBottomY = component.center.y - component.size.height / 2\n const pinSpacing = component.pin_spacing ?? DEFAULT_PIN_SPACING\n const maximumPadding = pinSpacing * MAX_VERTICAL_PADDING_IN_PIN_SPACINGS\n const paddingBySide: Record<VerticalSide, number> = {\n top: componentTopY - highestPinY,\n bottom: lowestPinY - componentBottomY,\n }\n\n const sourceComponent = component.source_component_id\n ? sourceComponentById.get(component.source_component_id)\n : undefined\n const componentName =\n sourceComponent?.name ?? component.schematic_component_id\n\n for (const side of [\"top\", \"bottom\"] as const) {\n const padding = paddingBySide[side]\n if (\n padding <= maximumPadding + FLOATING_POINT_TOLERANCE ||\n padding <= 0\n ) {\n continue\n }\n\n const relativePosition = side === \"top\" ? \"above\" : \"below\"\n const stylingIssueType = `excessive_${side}_padding`\n\n warnings.push({\n type: \"schematic_component_styling_warning\",\n schematic_component_styling_warning_id: `schematic_component_styling_warning_${component.schematic_component_id}_${stylingIssueType}`,\n warning_type: \"schematic_component_styling_warning\",\n message: `${componentName} has excessive empty space ${relativePosition} its pins (${padding.toFixed(2)}mm, more than ${MAX_VERTICAL_PADDING_IN_PIN_SPACINGS} pin spacings)`,\n schematic_component_id: component.schematic_component_id,\n styling_issue_type: stylingIssueType,\n schematic_port_ids: sidePorts.map((port) => port.schematic_port_id),\n source_component_id: component.source_component_id,\n schematic_sheet_id: component.schematic_sheet_id,\n subcircuit_id: component.subcircuit_id,\n })\n }\n }\n\n return warnings\n}\n","import type {\n AnyCircuitElement,\n SchematicComponent,\n SchematicComponentStylingWarning,\n SchematicText,\n} from \"circuit-json\"\n\ntype SourceComponent = Extract<AnyCircuitElement, { type: \"source_component\" }>\n\nconst isFallbackReferenceDesignator = (name: string) =>\n /^unnamed_[a-z0-9_-]+\\d+$/i.test(name)\n\nconst isTextWithinComponentBounds = (\n schematicText: SchematicText,\n schematicComponent: SchematicComponent,\n) => {\n const { center, size } = schematicComponent\n const tolerance = 1e-9\n\n return (\n schematicText.position.x >= center.x - size.width / 2 - tolerance &&\n schematicText.position.x <= center.x + size.width / 2 + tolerance &&\n schematicText.position.y >= center.y - size.height / 2 - tolerance &&\n schematicText.position.y <= center.y + size.height / 2 + tolerance\n )\n}\n\n/**\n * Warns when a schematic component does not have attached text displaying its\n * reference designator (or the component's display-name override).\n */\nexport function checkSchematicComponentMissingReferenceDesignatorText(\n circuitJson: AnyCircuitElement[],\n): SchematicComponentStylingWarning[] {\n const schematicComponents = circuitJson.filter(\n (element): element is SchematicComponent =>\n element.type === \"schematic_component\",\n )\n const sourceComponents = circuitJson.filter(\n (element): element is SourceComponent =>\n element.type === \"source_component\",\n )\n const schematicTexts = circuitJson.filter(\n (element): element is SchematicText => element.type === \"schematic_text\",\n )\n\n const sourceComponentById = new Map(\n sourceComponents.map((component) => [\n component.source_component_id,\n component,\n ]),\n )\n const textBySchematicComponentId = new Map<string, Set<string>>()\n const customSymbolTexts: SchematicText[] = []\n\n for (const schematicText of schematicTexts) {\n if (!schematicText.schematic_component_id) {\n if (schematicText.schematic_symbol_id) {\n customSymbolTexts.push(schematicText)\n }\n continue\n }\n\n const componentTexts =\n textBySchematicComponentId.get(schematicText.schematic_component_id) ??\n new Set<string>()\n componentTexts.add(schematicText.text.trim())\n textBySchematicComponentId.set(\n schematicText.schematic_component_id,\n componentTexts,\n )\n }\n\n const warnings: SchematicComponentStylingWarning[] = []\n\n for (const schematicComponent of schematicComponents) {\n // Named symbols provide their own reference text without schematic_text.\n if (schematicComponent.symbol_name) continue\n\n // Schematic boxes always provide their own reference designator.\n if (schematicComponent.is_box_with_pins) continue\n\n if (!schematicComponent.source_component_id) continue\n\n const sourceComponent = sourceComponentById.get(\n schematicComponent.source_component_id,\n )\n if (!sourceComponent) continue\n\n const referenceDesignators = new Set(\n [sourceComponent.name, sourceComponent.display_name]\n .map((name) => name?.trim())\n .filter((name): name is string => Boolean(name)),\n )\n const nonFallbackReferenceDesignator = [...referenceDesignators].find(\n (referenceDesignator) =>\n !isFallbackReferenceDesignator(referenceDesignator),\n )\n const componentTexts = textBySchematicComponentId.get(\n schematicComponent.schematic_component_id,\n )\n const hasReferenceDesignatorText =\n [...referenceDesignators].some((referenceDesignator) =>\n componentTexts?.has(referenceDesignator),\n ) ||\n customSymbolTexts.some(\n (schematicText) =>\n referenceDesignators.has(schematicText.text.trim()) &&\n isTextWithinComponentBounds(schematicText, schematicComponent),\n )\n\n if (nonFallbackReferenceDesignator && hasReferenceDesignatorText) {\n continue\n }\n\n const readableComponentName =\n nonFallbackReferenceDesignator ?? \"Schematic component\"\n\n warnings.push({\n type: \"schematic_component_styling_warning\",\n schematic_component_styling_warning_id: `schematic_component_styling_warning_${schematicComponent.schematic_component_id}_missing_reference_designator_text`,\n warning_type: \"schematic_component_styling_warning\",\n message: `${readableComponentName} is missing schematic reference designator text. For a custom symbol, add name=\"{REFDES}\" inside the symbol.`,\n schematic_component_id: schematicComponent.schematic_component_id,\n styling_issue_type: \"missing_reference_designator_text\",\n source_component_id: schematicComponent.source_component_id,\n schematic_sheet_id: schematicComponent.schematic_sheet_id,\n subcircuit_id: schematicComponent.subcircuit_id,\n })\n }\n\n return warnings\n}\n","import type {\n AnyCircuitElement,\n SchematicComponent,\n SchematicComponentStylingWarning,\n SchematicPort,\n} from \"circuit-json\"\n\ntype SourceComponent = Extract<AnyCircuitElement, { type: \"source_component\" }>\n\nconst FLOATING_POINT_TOLERANCE = 1e-9\n\nconst getPortLabel = (port: SchematicPort) =>\n port.display_pin_label ?? `pin ${port.pin_number}`\n\n/**\n * Warns when a box-style component's pins are positioned beyond the body edge\n * they enter. Left/right pins are checked against the body's vertical span,\n * while top/bottom pins are checked against its horizontal span.\n */\nexport function checkSchematicComponentPortsOutsideBody(\n circuitJson: AnyCircuitElement[],\n): SchematicComponentStylingWarning[] {\n const schematicComponents = circuitJson.filter(\n (element): element is SchematicComponent =>\n element.type === \"schematic_component\",\n )\n const schematicPorts = circuitJson.filter(\n (element): element is SchematicPort => element.type === \"schematic_port\",\n )\n const sourceComponents = circuitJson.filter(\n (element): element is SourceComponent =>\n element.type === \"source_component\",\n )\n\n const sourceComponentById = new Map(\n sourceComponents.map((component) => [\n component.source_component_id,\n component,\n ]),\n )\n const portsByComponentId = new Map<string, SchematicPort[]>()\n\n for (const port of schematicPorts) {\n if (!port.schematic_component_id) continue\n const componentPorts =\n portsByComponentId.get(port.schematic_component_id) ?? []\n componentPorts.push(port)\n portsByComponentId.set(port.schematic_component_id, componentPorts)\n }\n\n const warnings: SchematicComponentStylingWarning[] = []\n\n for (const component of schematicComponents) {\n if (\n component.is_box_with_pins === false ||\n component.size.width <= 0 ||\n component.size.height <= 0\n ) {\n continue\n }\n\n const componentLeftX = component.center.x - component.size.width / 2\n const componentRightX = component.center.x + component.size.width / 2\n const componentBottomY = component.center.y - component.size.height / 2\n const componentTopY = component.center.y + component.size.height / 2\n const componentPorts =\n portsByComponentId.get(component.schematic_component_id) ?? []\n\n const portsOutsideBody = componentPorts\n .filter((port) => {\n if (\n port.side_of_component === \"left\" ||\n port.side_of_component === \"right\"\n ) {\n return (\n port.center.y < componentBottomY - FLOATING_POINT_TOLERANCE ||\n port.center.y > componentTopY + FLOATING_POINT_TOLERANCE\n )\n }\n\n if (\n port.side_of_component === \"top\" ||\n port.side_of_component === \"bottom\"\n ) {\n return (\n port.center.x < componentLeftX - FLOATING_POINT_TOLERANCE ||\n port.center.x > componentRightX + FLOATING_POINT_TOLERANCE\n )\n }\n\n return false\n })\n .sort((portA, portB) => {\n const portAIsVertical =\n portA.side_of_component === \"left\" ||\n portA.side_of_component === \"right\"\n const portBIsVertical =\n portB.side_of_component === \"left\" ||\n portB.side_of_component === \"right\"\n\n if (portAIsVertical && portBIsVertical) {\n return portB.center.y - portA.center.y\n }\n if (!portAIsVertical && !portBIsVertical) {\n return portA.center.x - portB.center.x\n }\n return portAIsVertical ? -1 : 1\n })\n\n if (portsOutsideBody.length === 0) continue\n\n const requiredHeight = Math.max(\n component.size.height,\n ...portsOutsideBody\n .filter(\n (port) =>\n port.side_of_component === \"left\" ||\n port.side_of_component === \"right\",\n )\n .map((port) => 2 * Math.abs(port.center.y - component.center.y)),\n )\n const requiredWidth = Math.max(\n component.size.width,\n ...portsOutsideBody\n .filter(\n (port) =>\n port.side_of_component === \"top\" ||\n port.side_of_component === \"bottom\",\n )\n .map((port) => 2 * Math.abs(port.center.x - component.center.x)),\n )\n\n const suggestedDimensionChanges: string[] = []\n if (requiredHeight > component.size.height + FLOATING_POINT_TOLERANCE) {\n suggestedDimensionChanges.push(\n `increase schHeight to at least ${requiredHeight.toFixed(2)}mm`,\n )\n }\n if (requiredWidth > component.size.width + FLOATING_POINT_TOLERANCE) {\n suggestedDimensionChanges.push(\n `increase schWidth to at least ${requiredWidth.toFixed(2)}mm`,\n )\n }\n\n const sourceComponent = component.source_component_id\n ? sourceComponentById.get(component.source_component_id)\n : undefined\n const componentName =\n sourceComponent?.name ?? component.schematic_component_id\n const portLabels = portsOutsideBody.map(getPortLabel).join(\", \")\n\n warnings.push({\n type: \"schematic_component_styling_warning\",\n schematic_component_styling_warning_id: `schematic_component_styling_warning_${component.schematic_component_id}_ports_outside_body`,\n warning_type: \"schematic_component_styling_warning\",\n message: `${componentName} has schematic pins outside its body (${portLabels}); ${suggestedDimensionChanges.join(\" and \")}`,\n schematic_component_id: component.schematic_component_id,\n styling_issue_type: \"ports_outside_body\",\n schematic_port_ids: portsOutsideBody.map(\n (port) => port.schematic_port_id,\n ),\n source_component_id: component.source_component_id,\n schematic_sheet_id: component.schematic_sheet_id,\n subcircuit_id: component.subcircuit_id,\n })\n }\n\n return warnings\n}\n","import { createIndexedPcbConnectivityMap } from \"lib/util/create-indexed-pcb-connectivity-map\"\nimport { getFullConnectivityMapFromCircuitJson } from \"circuit-json-to-connectivity-map\"\nimport { addStartAndEndPortIdsIfMissing } from \"./add-start-and-end-port-ids-if-missing\"\nimport { checkCopperPourShorts } from \"./check-copper-pour-shorts\"\nimport { checkPcbBusLengthSkew } from \"./check-pcb-bus-length-skew\"\nimport { consolidatePcbOverlapErrors } from \"./consolidate-pcb-overlap-errors\"\nimport { checkSameNameNetsAreConnected } from \"./check-same-name-nets-are-connected\"\nimport type { AnyCircuitElement } from \"circuit-json\"\nimport { checkAllPinsInComponentAreUnderspecified } from \"./check-all-pins-in-component-are-underspecified\"\nimport { checkConnectorAccessibleOrientation } from \"./check-connector-accessible-orientation\"\nimport { checkCopperToBoardEdgeClearance } from \"./check-copper-to-board-edge-clearance\"\nimport { checkCourtyardOverlap } from \"./check-courtyard-overlap/checkCourtyardOverlap\"\nimport { checkDifferentNetViaSpacing } from \"./check-different-net-via-spacing\"\nimport { 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 { checkNoGroundPinDefined } from \"./check-no-ground-pin-defined\"\nimport { checkNoPowerPinDefined } from \"./check-no-power-pin-defined\"\nimport { checkPadPadClearance } from \"./check-pad-pad-clearance\"\nimport { checkPadTraceClearance } from \"./check-pad-trace-clearance\"\nimport { checkPcbComponentOverCutout } from \"./check-pcb-component-over-cutout\"\nimport { checkPcbComponentsMissingCourtyard } from \"./check-pcb-components-missing-courtyard\"\nimport { checkPcbComponentsOutOfBoard } from \"./check-pcb-components-out-of-board/checkPcbComponentsOutOfBoard\"\nimport { checkPcbComponentOverlap } from \"./check-pcb-components-overlap/checkPcbComponentOverlap\"\nimport { checkPcbCopperOverKeepout } from \"./check-pcb-copper-over-keepout\"\nimport { checkPcbTraceLengths } from \"./check-pcb-trace-lengths\"\nimport { checkPcbTraceViaCounts } from \"./check-pcb-trace-via-counts\"\nimport { checkPinMustBeConnected } from \"./check-pin-must-be-connected\"\nimport { checkSameNetViaSpacing } from \"./check-same-net-via-spacing\"\nimport { checkSchematicComponentExcessiveVerticalPadding } from \"./check-schematic-component-excessive-vertical-padding\"\nimport { checkSchematicComponentMissingReferenceDesignatorText } from \"./check-schematic-component-missing-reference-designator-text\"\nimport { checkSchematicComponentPortsOutsideBody } from \"./check-schematic-component-ports-outside-body\"\nimport { checkSourceTracesHavePcbTraces } from \"./check-source-traces-have-pcb-traces\"\nimport { checkTestPointAccessibility } from \"./check-testpoint-accessibility\"\nimport { checkPcbTracesOutOfBoard } from \"./check-trace-out-of-board/checkTraceOutOfBoard\"\nimport { checkTracesAreContiguous } from \"./check-traces-are-contiguous/check-traces-are-contiguous\"\nimport { checkTwoTerminalSwitchContactsOnDifferentNets } from \"./check-two-terminal-switch-contacts-on-different-nets\"\nimport { checkViaPadClearance } from \"./check-via-pad-clearance\"\nimport { checkViaTraceClearance } from \"./check-via-trace-clearance\"\nimport { checkViasInPads } from \"./check-vias-in-pads\"\n\nexport async function runAllPlacementChecks(\n circuitJson: AnyCircuitElement[],\n { consolidateOverlaps = true } = {},\n) {\n const errors = [\n ...checkCopperToBoardEdgeClearance(circuitJson),\n ...checkViasInPads(circuitJson),\n ...checkPcbComponentsOutOfBoard(circuitJson),\n ...checkPcbComponentOverCutout(circuitJson),\n ...checkPcbCopperOverKeepout(circuitJson),\n ...checkPcbComponentOverlap(circuitJson),\n ...checkPcbComponentsMissingCourtyard(circuitJson),\n ...checkPadPadClearance(circuitJson),\n ...checkCourtyardOverlap(circuitJson),\n ...checkConnectorAccessibleOrientation(circuitJson),\n ...checkTestPointAccessibility(circuitJson),\n ]\n return consolidateOverlaps\n ? consolidatePcbOverlapErrors(circuitJson, errors)\n : errors\n}\n\nexport async function runAllNetlistChecks(circuitJson: AnyCircuitElement[]) {\n return [\n ...checkPinMustBeConnected(circuitJson),\n ...checkSameNameNetsAreConnected(circuitJson),\n ...checkTwoTerminalSwitchContactsOnDifferentNets(circuitJson),\n ]\n}\n\nexport async function runAllSchematicChecks(circuitJson: AnyCircuitElement[]) {\n return [\n ...checkSchematicComponentExcessiveVerticalPadding(circuitJson),\n ...checkSchematicComponentMissingReferenceDesignatorText(circuitJson),\n ...checkSchematicComponentPortsOutsideBody(circuitJson),\n ]\n}\n\nexport async function runAllPinSpecificationChecks(\n circuitJson: AnyCircuitElement[],\n) {\n return [\n ...checkAllPinsInComponentAreUnderspecified(circuitJson),\n ...checkNoPowerPinDefined(circuitJson),\n ...checkNoGroundPinDefined(circuitJson),\n ]\n}\n\nexport async function runAllRoutingChecks(circuitJson: AnyCircuitElement[]) {\n // Infer endpoint IDs before taking connectivity snapshots. Keep these maps\n // local to this pass so edits to the same circuit array cannot leave stale data.\n addStartAndEndPortIdsIfMissing(circuitJson)\n const connectivity = {\n connMap: getFullConnectivityMapFromCircuitJson(circuitJson),\n pcbConnectivityMap: createIndexedPcbConnectivityMap(circuitJson),\n }\n return [\n ...checkEachPcbPortConnectedToPcbTraces(circuitJson, connectivity),\n ...checkSourceTracesHavePcbTraces(circuitJson, connectivity),\n ...checkPcbTraceLengths(circuitJson),\n ...checkPcbBusLengthSkew(circuitJson),\n ...checkPcbTraceViaCounts(circuitJson),\n ...checkEachPcbTraceNonOverlapping(circuitJson, connectivity),\n ...checkCopperPourShorts(circuitJson, connectivity),\n ...checkPadTraceClearance(circuitJson, connectivity),\n ...checkViaTraceClearance(circuitJson, connectivity),\n ...checkViaPadClearance(circuitJson, connectivity),\n ...checkSameNetViaSpacing(circuitJson, connectivity),\n ...checkDifferentNetViaSpacing(circuitJson, connectivity),\n ...checkTracesAreContiguous(circuitJson, connectivity),\n ...checkPcbTracesOutOfBoard(circuitJson),\n ]\n}\n\nexport async function runAllChecks(circuitJson: AnyCircuitElement[]) {\n return [\n ...(await runAllPlacementChecks(circuitJson)),\n ...(await runAllSchematicChecks(circuitJson)),\n ...(await runAllNetlistChecks(circuitJson)),\n ...(await runAllPinSpecificationChecks(circuitJson)),\n ...(await runAllRoutingChecks(circuitJson)),\n ]\n}\n","import type {\n AnyCircuitElement,\n PcbBusLengthSkewError,\n SourceBus,\n} from \"circuit-json\"\nimport { getPcbTracesBySourceTraceId } from \"./check-pcb-trace-lengths\"\nimport { getPcbTraceLength } from \"./util/get-pcb-trace-length\"\n\n/** Compare total routed lengths of resolved bus members. Unrouted members are\n * left to connectivity checks, never treated as zero-length routes.\n */\nexport const checkPcbBusLengthSkew = (\n circuitJson: AnyCircuitElement[],\n): PcbBusLengthSkewError[] => {\n const buses = circuitJson.filter(\n (e): e is SourceBus => e.type === \"source_bus\",\n )\n const tracesBySource = getPcbTracesBySourceTraceId(circuitJson)\n const errors: PcbBusLengthSkewError[] = []\n for (const bus of buses) {\n if (bus.max_length_skew === undefined) continue\n const members = [...new Set(bus.source_trace_ids)].flatMap((id) => {\n const traces = tracesBySource\n .get(id)\n ?.filter((t) => t.trace_length !== undefined || t.route.length > 1)\n if (!traces?.length) return []\n return [\n {\n id,\n traces,\n length: traces.reduce((sum, t) => sum + getPcbTraceLength(t), 0),\n },\n ]\n })\n if (members.length < 2) continue\n const skew =\n Math.max(...members.map((m) => m.length)) -\n Math.min(...members.map((m) => m.length))\n // Ignore rounding noise at the inclusive boundary.\n if (skew <= bus.max_length_skew + 1e-9) continue\n errors.push({\n type: \"pcb_bus_length_skew_error\",\n pcb_bus_length_skew_error_id: `pcb_bus_length_skew_error_${bus.source_bus_id}`,\n error_type: \"pcb_bus_length_skew_error\",\n message: `PCB bus ${bus.name ?? bus.source_bus_id} has ${skew.toFixed(2)}mm length skew, exceeding the ${bus.max_length_skew}mm maximum`,\n source_bus_id: bus.source_bus_id,\n source_trace_ids: members.map((m) => m.id),\n pcb_trace_ids: members.flatMap((m) =>\n m.traces.map((t) => t.pcb_trace_id),\n ),\n actual_length_skew: skew,\n maximum_length_skew: bus.max_length_skew,\n subcircuit_id: bus.subcircuit_id,\n })\n }\n return errors\n}\n","import { getPrimaryId } from \"@tscircuit/circuit-json-util\"\nimport type {\n AnyCircuitElement,\n PcbFootprintOverlapError,\n PcbPadPadClearanceError,\n PcbCourtyardOverlapError,\n} from \"circuit-json\"\n\n/** Additional diagnostic context supplied by checks; the base error remains\n * compatible with existing Circuit JSON renderers. */\nexport interface PcbComponentOverlapError extends PcbFootprintOverlapError {\n pcb_component_ids?: string[]\n related_errors?: PlacementOverlapError[]\n}\n\ntype PlacementOverlapError =\n | PcbComponentOverlapError\n | PcbPadPadClearanceError\n | PcbCourtyardOverlapError\n\n/**\n * Consolidate placement conflicts for the same exact pair of components, only\n * when a footprint overlap was detected. Keep raw details and all affected\n * pad/hole IDs on one renderer-compatible error. Unrelated checks, standalone\n * elements, same-component clearance errors and clearance-only pairs survive.\n * Does not mutate inputs; safe to apply again when combining check runners.\n */\nexport function consolidatePcbOverlapErrors<T extends AnyCircuitElement>(\n circuitJson: AnyCircuitElement[],\n errors: T[],\n): (T | PcbComponentOverlapError)[]\nexport function consolidatePcbOverlapErrors(\n circuitJson: AnyCircuitElement[],\n errors: AnyCircuitElement[],\n): AnyCircuitElement[] {\n const ownerByElementId = new Map<string, string>()\n const elementById = new Map<string, AnyCircuitElement>()\n for (const element of circuitJson) {\n const id = getPrimaryId(element)\n elementById.set(id, element)\n if (\"pcb_component_id\" in element && element.pcb_component_id) {\n ownerByElementId.set(id, element.pcb_component_id)\n }\n }\n\n const rawErrors = errors.flatMap<AnyCircuitElement>((error) =>\n error.type === \"pcb_footprint_overlap_error\"\n ? ((error as PcbComponentOverlapError).related_errors ?? [error])\n : [error],\n )\n const groups = new Map<string, PlacementOverlapError[]>()\n const keyByError = new Map<AnyCircuitElement, string>()\n for (const error of rawErrors) {\n let componentIds: string[]\n if (error.type === \"pcb_footprint_overlap_error\") {\n // Keepout errors describe a different constraint, even if pads are named.\n if (error.pcb_keepout_ids?.length) continue\n const overlap = error as PcbComponentOverlapError\n const elementIds = [\n ...(error.pcb_smtpad_ids ?? []),\n ...(error.pcb_plated_hole_ids ?? []),\n ...(error.pcb_hole_ids ?? []),\n ]\n if (elementIds.some((id) => !ownerByElementId.has(id))) continue\n componentIds =\n overlap.pcb_component_ids ??\n elementIds.map((id) => ownerByElementId.get(id)!)\n } else if (error.type === \"pcb_pad_pad_clearance_error\") {\n if (error.pcb_pad_ids.some((id) => !ownerByElementId.has(id))) continue\n componentIds = error.pcb_pad_ids.map((id) => ownerByElementId.get(id)!)\n } else if (error.type === \"pcb_courtyard_overlap_error\") {\n componentIds = error.pcb_component_ids\n } else {\n continue\n }\n componentIds = [...new Set(componentIds)].sort()\n if (componentIds.length !== 2) continue\n const key = JSON.stringify(componentIds)\n keyByError.set(error, key)\n const group = groups.get(key) ?? []\n group.push(error)\n groups.set(key, group)\n }\n\n const summaries = new Map<string, PcbComponentOverlapError>()\n for (const [key, group] of groups) {\n const overlaps = group.filter(\n (e) => e.type === \"pcb_footprint_overlap_error\",\n )\n if (group.length < 2 || overlaps.length === 0) continue\n const componentIds: string[] = JSON.parse(key)\n const names = componentIds.map((id) => {\n const component = elementById.get(id)\n const source =\n component?.type === \"pcb_component\"\n ? elementById.get(component.source_component_id)\n : undefined\n return source?.type === \"source_component\" ? source.name : id\n })\n const counts = [\n [overlaps.length, \"footprint overlap\"],\n [\n group.filter((e) => e.type === \"pcb_pad_pad_clearance_error\").length,\n \"pad clearance violation\",\n ],\n [\n group.filter((e) => e.type === \"pcb_courtyard_overlap_error\").length,\n \"courtyard conflict\",\n ],\n ] as const\n const details = counts\n .filter(([count]) => count > 0)\n .map(([count, label]) => `${count} ${label}${count === 1 ? \"\" : \"s\"}`)\n const summary: PcbComponentOverlapError = {\n type: \"pcb_footprint_overlap_error\",\n error_type: \"pcb_footprint_overlap_error\",\n pcb_error_id: `pcb_component_overlap_${componentIds.join(\"_\")}`,\n pcb_component_ids: componentIds,\n message: `${names.join(\" overlaps \")}: ${details.join(\", \")}. Move the components apart.`,\n related_errors: group,\n }\n if (group.some((error) => error.is_fatal)) summary.is_fatal = true\n const affectedIds = new Set<string>()\n for (const error of group) {\n if (error.type === \"pcb_footprint_overlap_error\") {\n for (const id of [\n ...(error.pcb_smtpad_ids ?? []),\n ...(error.pcb_plated_hole_ids ?? []),\n ...(error.pcb_hole_ids ?? []),\n ])\n affectedIds.add(id)\n } else if (error.type === \"pcb_pad_pad_clearance_error\") {\n for (const id of error.pcb_pad_ids) affectedIds.add(id)\n }\n }\n for (const [field, type] of [\n [\"pcb_smtpad_ids\", \"pcb_smtpad\"],\n [\"pcb_plated_hole_ids\", \"pcb_plated_hole\"],\n [\"pcb_hole_ids\", \"pcb_hole\"],\n ] as const) {\n const ids = [...affectedIds]\n .filter((id) => elementById.get(id)?.type === type)\n .sort()\n if (ids.length) summary[field] = ids\n }\n summaries.set(key, summary)\n }\n\n const emitted = new Set<string>()\n return rawErrors.flatMap<AnyCircuitElement>((error) => {\n const key = keyByError.get(error)\n const summary = key === undefined ? undefined : summaries.get(key)\n if (!summary || key === undefined) return [error]\n if (emitted.has(key)) return []\n emitted.add(key)\n return [summary]\n })\n}\n","import type {\n AnyCircuitElement,\n SourceConfusingNetNameWarning,\n SourceNet,\n} from \"circuit-json\"\n\n/** Warn once per name when its source nets belong to multiple electrical islands. */\nexport function checkSameNameNetsAreConnected(\n circuitJson: AnyCircuitElement[],\n): SourceConfusingNetNameWarning[] {\n const parents = new Map<string, string>()\n const find = (id: string): string => {\n let root = id\n while (parents.has(root) && parents.get(root) !== root) {\n root = parents.get(root)!\n }\n while (parents.has(id) && parents.get(id) !== root) {\n const next = parents.get(id)!\n parents.set(id, root)\n id = next\n }\n return root\n }\n const connect = (ids: string[]) => {\n if (ids.length < 2) return\n const root = find(ids[0]!)\n for (const id of ids.slice(1)) parents.set(find(id), root)\n }\n const netsByName = new Map<string, SourceNet[]>()\n for (const element of circuitJson) {\n if (element.type === \"source_net\" && element.name.trim()) {\n const nets = netsByName.get(element.name) ?? []\n nets.push(element)\n netsByName.set(element.name, nets)\n }\n if (element.type === \"source_trace\") {\n connect([\n ...element.connected_source_net_ids.map((id) => `net:${id}`),\n ...element.connected_source_port_ids.map((id) => `port:${id}`),\n ])\n }\n if (element.type === \"source_component_internal_connection\") {\n connect(element.source_port_ids.map((id) => `port:${id}`))\n }\n if (element.type === \"source_component\") {\n for (const ids of element.internally_connected_source_port_ids ?? []) {\n connect(ids.map((id) => `port:${id}`))\n }\n }\n }\n\n const warnings: SourceConfusingNetNameWarning[] = []\n for (const [name, nets] of netsByName) {\n const islands = new Set(nets.map((net) => find(`net:${net.source_net_id}`)))\n if (islands.size < 2) continue\n const ids = nets.map((net) => net.source_net_id).sort()\n warnings.push({\n type: \"source_confusing_net_name_warning\",\n source_confusing_net_name_warning_id: `source_confusing_net_name_warning_${ids[0]}`,\n warning_type: \"source_confusing_net_name_warning\",\n message: `Nets named \"${name}\" are not all connected (${islands.size} separate electrical networks). Connect them or use distinct names to avoid confusion.`,\n source_net_ids: ids,\n net_name: name,\n ...(nets.every((net) => net.subcircuit_id === nets[0]!.subcircuit_id)\n ? { subcircuit_id: nets[0]!.subcircuit_id }\n : {}),\n })\n }\n return warnings\n}\n","import { getBoardBounds } from \"@tscircuit/circuit-json-util\"\nimport type {\n AnyCircuitElement,\n PcbBoard,\n PcbComponent,\n PcbConnectorNotInAccessibleOrientationWarning,\n} from \"circuit-json\"\nimport { getReadableNameForComponent } from \"./util/get-readable-names\"\n\ntype FacingDirection = \"x-\" | \"x+\" | \"y+\" | \"y-\"\n\nfunction getFacingDirectionFromInsertionDirection(\n component: PcbComponent,\n): FacingDirection | null {\n switch (component.insertion_direction) {\n case \"from_left\":\n return \"x-\"\n case \"from_right\":\n return \"x+\"\n case \"from_top\":\n return \"y+\"\n case \"from_bottom\":\n return \"y-\"\n case \"from_above\":\n case \"from_below\":\n return null\n default:\n return null\n }\n}\n\nfunction getFacingDirection(component: PcbComponent): FacingDirection | null {\n if (component.insertion_direction) {\n return getFacingDirectionFromInsertionDirection(component)\n }\n\n if (!component.center || !component.cable_insertion_center) return null\n\n const dx = component.cable_insertion_center.x - component.center.x\n const dy = component.cable_insertion_center.y - component.center.y\n\n if (Math.abs(dx) < 1e-6 && Math.abs(dy) < 1e-6) return null\n\n if (Math.abs(dx) >= Math.abs(dy)) {\n return dx >= 0 ? \"x+\" : \"x-\"\n }\n\n return dy >= 0 ? \"y+\" : \"y-\"\n}\n\nfunction getRecommendedFacingDirection(\n component: PcbComponent,\n bounds: { minX: number; maxX: number; minY: number; maxY: number },\n): FacingDirection | null {\n if (!component.center) return null\n\n const distances = [\n { direction: \"x-\" as const, distance: component.center.x - bounds.minX },\n { direction: \"x+\" as const, distance: bounds.maxX - component.center.x },\n { direction: \"y-\" as const, distance: component.center.y - bounds.minY },\n { direction: \"y+\" as const, distance: bounds.maxY - component.center.y },\n ]\n\n distances.sort((a, b) => a.distance - b.distance)\n return distances[0]?.direction ?? null\n}\n\nexport function checkConnectorAccessibleOrientation(\n circuitJson: AnyCircuitElement[],\n): PcbConnectorNotInAccessibleOrientationWarning[] {\n const board = circuitJson.find(\n (el): el is PcbBoard => el.type === \"pcb_board\",\n )\n if (!board) return []\n\n const bounds = (() => {\n try {\n return getBoardBounds(board)\n } catch {\n return null\n }\n })()\n if (!bounds) return []\n\n const warnings: PcbConnectorNotInAccessibleOrientationWarning[] = []\n\n const components = circuitJson.filter(\n (el): el is PcbComponent => el.type === \"pcb_component\",\n )\n\n for (const component of components) {\n const facingDirection = getFacingDirection(component)\n const recommendedFacingDirection = getRecommendedFacingDirection(\n component,\n bounds,\n )\n\n if (!facingDirection || !recommendedFacingDirection) continue\n if (facingDirection === recommendedFacingDirection) continue\n\n const componentName = getReadableNameForComponent(\n circuitJson,\n component.pcb_component_id,\n )\n\n const message = component.insertion_direction\n ? `${componentName} is facing ${facingDirection} but should face ${recommendedFacingDirection} so the connector is accessible from the board edge`\n : `${componentName} is inferred to face ${facingDirection} from its cable insertion center because no explicit footprint insertionDirection is defined, but should face ${recommendedFacingDirection} so the connector is accessible from the board edge. Set insertionDirection on the <footprint> to specify the actual direction in the footprint's unrotated orientation; for example, <footprint insertionDirection=\"from_above\"> for a connector accessed from above the PCB (+Z).`\n\n warnings.push({\n type: \"pcb_connector_not_in_accessible_orientation_warning\",\n warning_type: \"pcb_connector_not_in_accessible_orientation_warning\",\n pcb_connector_not_in_accessible_orientation_warning_id: `pcb_connector_not_in_accessible_orientation_warning_${component.pcb_component_id}`,\n message,\n pcb_component_id: component.pcb_component_id,\n source_component_id: component.source_component_id,\n pcb_board_id: board.pcb_board_id,\n facing_direction: facingDirection,\n recommended_facing_direction: recommendedFacingDirection,\n subcircuit_id: component.subcircuit_id,\n })\n }\n\n return warnings\n}\n","import {\n doSegmentsIntersect,\n isPointInsidePolygon,\n} from \"@tscircuit/math-utils\"\nimport type {\n AnyCircuitElement,\n PcbCourtyardCircle,\n PcbCourtyardOutline,\n PcbCourtyardOverlapError,\n PcbCourtyardRect,\n} from \"circuit-json\"\n\ntype CourtyardElement =\n | PcbCourtyardRect\n | PcbCourtyardCircle\n | PcbCourtyardOutline\n\nfunction getCourtyardPolygon(el: CourtyardElement): { x: number; y: number }[] {\n if (el.type === \"pcb_courtyard_rect\") {\n const hw = el.width / 2\n const hh = el.height / 2\n const corners = [\n { x: -hw, y: -hh },\n { x: +hw, y: -hh },\n { x: +hw, y: +hh },\n { x: -hw, y: +hh },\n ]\n const angle = ((el.ccw_rotation ?? 0) * Math.PI) / 180\n const cos = Math.cos(angle)\n const sin = Math.sin(angle)\n return corners.map(({ x, y }) => ({\n x: el.center.x + x * cos - y * sin,\n y: el.center.y + x * sin + y * cos,\n }))\n }\n if (el.type === \"pcb_courtyard_circle\") {\n const N = 32\n return Array.from({ length: N }, (_, i) => {\n const a = (2 * Math.PI * i) / N\n return {\n x: el.center.x + el.radius * Math.cos(a),\n y: el.center.y + el.radius * Math.sin(a),\n }\n })\n }\n return el.outline\n}\n\nfunction getComponentName(\n circuitJson: AnyCircuitElement[],\n pcbComponentId: string,\n): string {\n const pcbComponent = circuitJson.find(\n (el) =>\n el.type === \"pcb_component\" && el.pcb_component_id === pcbComponentId,\n )\n if (pcbComponent?.type !== \"pcb_component\") return pcbComponentId\n const sourceComponent = circuitJson.find(\n (el) =>\n el.type === \"source_component\" &&\n el.source_component_id === pcbComponent.source_component_id,\n )\n if (sourceComponent?.type === \"source_component\" && sourceComponent.name) {\n return sourceComponent.name\n }\n return pcbComponentId\n}\n\ntype Point = { x: number; y: number }\n\nfunction polygonsOverlap(polyA: Point[], polyB: Point[]): boolean {\n // Check if any vertex of A is inside B or vice versa\n if (polyA.some((p) => isPointInsidePolygon(p, polyB))) return true\n if (polyB.some((p) => isPointInsidePolygon(p, polyA))) return true\n // Check if any edge of A intersects any edge of B\n for (let i = 0; i < polyA.length; i++) {\n const a1 = polyA[i]\n const a2 = polyA[(i + 1) % polyA.length]\n for (let j = 0; j < polyB.length; j++) {\n const b1 = polyB[j]\n const b2 = polyB[(j + 1) % polyB.length]\n if (doSegmentsIntersect(a1, a2, b1, b2)) return true\n }\n }\n return false\n}\n\n/**\n * Check for overlapping PCB component courtyards.\n * Returns one error per pair of components whose courtyard elements overlap.\n */\nexport function checkCourtyardOverlap(\n circuitJson: AnyCircuitElement[],\n): PcbCourtyardOverlapError[] {\n const doNotPlaceComponentIds = new Set(\n circuitJson.flatMap((el) =>\n el.type === \"pcb_component\" && el.do_not_place\n ? [el.pcb_component_id]\n : [],\n ),\n )\n\n const courtyards = circuitJson\n .filter(\n (el): el is CourtyardElement =>\n el.type === \"pcb_courtyard_rect\" ||\n el.type === \"pcb_courtyard_circle\" ||\n el.type === \"pcb_courtyard_outline\",\n )\n .filter((el) => !doNotPlaceComponentIds.has(el.pcb_component_id))\n\n // Group by component\n const byComponent = new Map<string, CourtyardElement[]>()\n for (const el of courtyards) {\n const id = el.pcb_component_id\n if (!byComponent.has(id)) byComponent.set(id, [])\n byComponent.get(id)!.push(el)\n }\n\n const componentIds = Array.from(byComponent.keys())\n const errors: PcbCourtyardOverlapError[] = []\n\n for (let i = 0; i < componentIds.length; i++) {\n for (let j = i + 1; j < componentIds.length; j++) {\n const idA = componentIds[i]\n const idB = componentIds[j]\n\n let overlapping = false\n outer: for (const a of byComponent.get(idA)!) {\n for (const b of byComponent.get(idB)!) {\n // Skip overlap check if courtyards are on different layers\n if (\"layer\" in a && \"layer\" in b && a.layer !== b.layer) {\n continue\n }\n const polyA = getCourtyardPolygon(a)\n const polyB = getCourtyardPolygon(b)\n if (polygonsOverlap(polyA, polyB)) {\n overlapping = true\n break outer\n }\n }\n }\n\n if (overlapping) {\n errors.push({\n type: \"pcb_courtyard_overlap_error\",\n pcb_error_id: `pcb_courtyard_overlap_${idA}_${idB}`,\n error_type: \"pcb_courtyard_overlap_error\",\n message: `Courtyard of ${getComponentName(circuitJson, idA)} overlaps with courtyard of ${getComponentName(circuitJson, idB)}`,\n pcb_component_ids: [idA, idB],\n })\n }\n }\n }\n\n return errors\n}\n","import { isPointInsidePolygon } from \"@tscircuit/math-utils\"\nimport type {\n AnyCircuitElement,\n PcbComponent,\n PcbCourtyardCircle,\n PcbCourtyardOutline,\n PcbCourtyardPolygon,\n PcbCourtyardRect,\n PcbPlacementError,\n SourceSimpleTestPoint,\n} from \"circuit-json\"\nimport { getReadableNameForComponent } from \"./util/get-readable-names\"\n\ntype CourtyardElement =\n | PcbCourtyardCircle\n | PcbCourtyardOutline\n | PcbCourtyardPolygon\n | PcbCourtyardRect\n\nconst isCourtyardElement = (\n element: AnyCircuitElement,\n): element is CourtyardElement =>\n element.type === \"pcb_courtyard_circle\" ||\n element.type === \"pcb_courtyard_outline\" ||\n element.type === \"pcb_courtyard_polygon\" ||\n element.type === \"pcb_courtyard_rect\"\n\nconst isPointInsideCourtyard = (\n point: { x: number; y: number },\n courtyard: CourtyardElement,\n): boolean => {\n if (courtyard.type === \"pcb_courtyard_circle\") {\n const dx = point.x - courtyard.center.x\n const dy = point.y - courtyard.center.y\n return dx * dx + dy * dy <= courtyard.radius * courtyard.radius\n }\n\n if (courtyard.type === \"pcb_courtyard_rect\") {\n const angle = (-1 * (courtyard.ccw_rotation ?? 0) * Math.PI) / 180\n const dx = point.x - courtyard.center.x\n const dy = point.y - courtyard.center.y\n const localX = dx * Math.cos(angle) - dy * Math.sin(angle)\n const localY = dx * Math.sin(angle) + dy * Math.cos(angle)\n return (\n Math.abs(localX) <= courtyard.width / 2 &&\n Math.abs(localY) <= courtyard.height / 2\n )\n }\n\n const polygon =\n courtyard.type === \"pcb_courtyard_polygon\"\n ? courtyard.points\n : courtyard.outline\n return isPointInsidePolygon(point, polygon)\n}\n\nconst getPcbComponentName = (\n circuitJson: AnyCircuitElement[],\n pcbComponentId: string,\n): string => {\n const pcbComponent = circuitJson.find(\n (element): element is PcbComponent =>\n element.type === \"pcb_component\" &&\n element.pcb_component_id === pcbComponentId,\n )\n const sourceComponent = circuitJson.find(\n (element) =>\n element.type === \"source_component\" &&\n element.source_component_id === pcbComponent?.source_component_id,\n )\n\n return (\n (sourceComponent && \"name\" in sourceComponent\n ? sourceComponent.name\n : undefined) ?? getReadableNameForComponent(circuitJson, pcbComponentId)\n )\n}\n\n/**\n * Test points are intended to be contacted from their PCB side. A test point\n * whose access center is covered by another component's courtyard cannot be\n * reliably reached by a probe after assembly.\n */\nexport function checkTestPointAccessibility(\n circuitJson: AnyCircuitElement[],\n): PcbPlacementError[] {\n const sourceTestPoints = circuitJson.filter(\n (element): element is SourceSimpleTestPoint =>\n element.type === \"source_component\" &&\n element.ftype === \"simple_test_point\",\n )\n const sourceTestPointIds = new Set(\n sourceTestPoints.map((testPoint) => testPoint.source_component_id),\n )\n const testPointNames = new Map(\n sourceTestPoints.map((testPoint) => [\n testPoint.source_component_id,\n testPoint.name,\n ]),\n )\n const testPointComponents = circuitJson.filter(\n (element): element is PcbComponent =>\n element.type === \"pcb_component\" &&\n sourceTestPointIds.has(element.source_component_id),\n )\n const courtyards = circuitJson.filter(isCourtyardElement)\n const errors: PcbPlacementError[] = []\n const reportedComponentPairs = new Set<string>()\n\n for (const testPoint of testPointComponents) {\n for (const courtyard of courtyards) {\n if (courtyard.pcb_component_id === testPoint.pcb_component_id) continue\n if (courtyard.layer !== testPoint.layer) continue\n if (!isPointInsideCourtyard(testPoint.center, courtyard)) continue\n\n const componentPair = `${testPoint.pcb_component_id}:${courtyard.pcb_component_id}`\n if (reportedComponentPairs.has(componentPair)) continue\n reportedComponentPairs.add(componentPair)\n\n const testPointName =\n testPointNames.get(testPoint.source_component_id) ?? \"Test point\"\n const obstructingComponentName = getPcbComponentName(\n circuitJson,\n courtyard.pcb_component_id,\n )\n\n errors.push({\n type: \"pcb_placement_error\",\n pcb_placement_error_id: `testpoint_in_courtyard_${testPoint.pcb_component_id}_${courtyard.pcb_component_id}`,\n error_type: \"pcb_placement_error\",\n message: `Test point ${testPointName} is not accessible because it is inside the courtyard of ${obstructingComponentName}`,\n subcircuit_id: testPoint.subcircuit_id,\n })\n }\n }\n\n return errors\n}\n"],"mappings":"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","names":["Vector","Arc","shape","Flatbush","point","point","point","point","smtPad","getFullConnectivityMapFromCircuitJson","getReadableNameForElement","point","netId","getFullConnectivityMapFromCircuitJson","cju","getReadableNameForElement","getPrimaryId","segmentToCircleMinDistance","segmentToSegmentMinDistance","getFullConnectivityMapFromCircuitJson","getBoundsOfPcbElements","pointToSegmentClosestPoint","segmentToSegmentMinDistance","point","getBoundsOfPcbElements","segmentToSegmentMinDistance","distance","circle","pointToSegmentClosestPoint","clearance","clamp","dx","dy","t","closestOnB","closestOnA","distance","getBoundsOfPcbElements","point","getBoundsOfPcbElements","getFullConnectivityMapFromCircuitJson","cju","getReadableNameForElement","gap","segmentToSegmentMinDistance","getPrimaryId","distance","segmentToCircleMinDistance","getReadableNameForElement","getReadableNameForElement","Flatten","rotatePoint","Flatten","applyToPoint","rotateDEG","rectanglePolygon","rotateDEG","applyToPoint","point","cju","getPrimaryId","getPrimaryId","cju","getReadableNameForElement","getFullConnectivityMapFromCircuitJson","distance","distance","getFullConnectivityMapFromCircuitJson","distance","getReadableNameForElement","getReadableNameForElement","getFullConnectivityMapFromCircuitJson","getFullConnectivityMapFromCircuitJson","distance","getReadableNameForElement","cju","getFullConnectivityMapFromCircuitJson","cju","getFullConnectivityMapFromCircuitJson","point","getFullConnectivityMapFromCircuitJson","getFullConnectivityMapFromCircuitJson","pointToSegmentDistance","getReadableNameForPcbPort","getFullConnectivityMapFromCircuitJson","all_layers","getPrimaryId","pointToSegmentDistance","all_layers","getPrimaryId","pointToSegmentDistance","point","point","pointToSegmentDistance","distance","getFullConnectivityMapFromCircuitJson","traceName","getReadableNameForPcbPort","cju","segmentToSegmentMinDistance","cju","distance","segmentToSegmentMinDistance","cju","getBoundsOfPcbElements","getPrimaryId","doBoundsOverlap","getFullConnectivityMapFromCircuitJson","getBoundsOfPcbElements","doBoundsOverlap","getBoundsOfPcbElements","doBoundsOverlap","isCourtyardElement","getPrimaryId","getFullConnectivityMapFromCircuitJson","cju","getBoundsOfPcbElements","doBoundsOverlap","point","getPrimaryId","getReadableNameForElement","getFullConnectivityMapFromCircuitJson","getFullConnectivityMapFromCircuitJson","getPrimaryId","getReadableNameForElement","getPrimaryId","getReadableNameForElement","formatMm","getFullConnectivityMapFromCircuitJson","getFullConnectivityMapFromCircuitJson","getPrimaryId","getReadableNameForElement","formatMm","getReadableNameForElement","formatMm","getFullConnectivityMapFromCircuitJson","getFullConnectivityMapFromCircuitJson","getReadableNameForElement","formatMm","getPrimaryId","getReadableNameForElement","formatMm","getFullConnectivityMapFromCircuitJson","getFullConnectivityMapFromCircuitJson","getPrimaryId","getReadableNameForElement","formatMm","getPrimaryId","getFullConnectivityMapFromCircuitJson","getFullConnectivityMapFromCircuitJson","getPrimaryId","sourcePort","cju","cju","cju","cju","cju","FLOATING_POINT_TOLERANCE","getFullConnectivityMapFromCircuitJson","getPrimaryId","isPointInsidePolygon","getComponentName","isPointInsidePolygon","isCourtyardElement","point","isPointInsidePolygon","getFullConnectivityMapFromCircuitJson"]}
|
|
1
|
+
{"version":3,"sources":["../lib/check-copper-pour-shorts.ts","../node_modules/@tscircuit/circuit-json-to-flattenjs/lib/geometry.ts","../node_modules/@tscircuit/circuit-json-to-flattenjs/lib/layers.ts","../node_modules/@tscircuit/circuit-json-to-flattenjs/lib/pads.ts","../node_modules/@tscircuit/circuit-json-to-flattenjs/lib/traces.ts","../node_modules/@tscircuit/circuit-json-to-flattenjs/lib/convert.ts","../node_modules/@tscircuit/circuit-json-to-flattenjs/lib/polygon-to-svg.ts","../node_modules/@tscircuit/circuit-json-to-flattenjs/lib/render-svg.ts","../lib/util/create-indexed-pcb-connectivity-map.ts","../lib/util/get-via-and-pour-connections.ts","../lib/copper-pour-connectivity/create-copper-polygon-contact-tester.ts","../lib/check-traces-are-contiguous/is-point-in-pad.ts","../lib/check-each-pcb-trace-non-overlapping/segment-to-polygon-clearance.ts","../lib/add-start-and-end-port-ids-if-missing.ts","../lib/check-each-pcb-port-connected-to-pcb-trace.ts","../lib/util/get-readable-names.ts","../lib/copper-pour-connectivity/get-copper-pour-connectivity.ts","../lib/check-each-pcb-trace-non-overlapping/check-each-pcb-trace-non-overlapping.ts","../lib/check-pad-clearance/common.ts","../node_modules/@tscircuit/jlcpcb-manufacturing-specs/lib/jlcpcb-manufacturing-specs.ts","../lib/drc-defaults.ts","../lib/data-structures/SpatialIndex.ts","../lib/util/getLayersOfPcbElement.ts","../lib/check-each-pcb-trace-non-overlapping/getClosestPointBetweenSegmentAndBounds.ts","../lib/check-each-pcb-trace-non-overlapping/getClosestPointBetweenSegments.ts","../lib/check-each-pcb-trace-non-overlapping/getCollidableBounds.ts","../lib/check-each-pcb-trace-non-overlapping/getPcbPortIdsConnectedToTraces.ts","../lib/check-each-pcb-trace-non-overlapping/getRadiusOfCircuitJsonElement.ts","../lib/net-manager.ts","../lib/check-pcb-components-out-of-board/checkViasOffBoard.ts","../lib/check-copper-to-board-edge-clearance.ts","../lib/check-pcb-components-out-of-board/checkPcbComponentsOutOfBoard.ts","../lib/check-pcb-component-over-cutout.ts","../lib/check-pcb-copper-over-keepout.ts","../lib/check-same-net-via-spacing.ts","../lib/util/distance.ts","../lib/util/viasAreAtSameLocation.ts","../lib/check-different-net-via-spacing.ts","../lib/check-source-traces-match-pcb-trace-thickness.ts","../lib/check-source-traces-have-pcb-traces.ts","../lib/check-traces-are-contiguous/check-traces-are-contiguous.ts","../lib/check-traces-are-contiguous/via-contact-index.ts","../lib/check-trace-out-of-board/checkTraceOutOfBoard.ts","../lib/check-pcb-components-overlap/checkPcbComponentOverlap.ts","../lib/check-pcb-components-overlap/doPcbElementsOverlap.ts","../lib/check-pcb-components-missing-courtyard.ts","../lib/util/get-pcb-trace-length.ts","../lib/check-pcb-trace-lengths.ts","../lib/check-pcb-trace-via-counts.ts","../lib/check-pad-pad-clearance.ts","../lib/check-pad-trace-clearance.ts","../lib/check-via-trace-clearance.ts","../lib/check-via-pad-clearance.ts","../lib/check-vias-in-pads.ts","../lib/dedupe-pcb-drc-errors.ts","../lib/check-pin-must-be-connected.ts","../lib/check-two-terminal-switch-contacts-on-different-nets.ts","../lib/check-all-pins-in-component-are-underspecified.ts","../lib/check-no-power-pin-defined.ts","../lib/util/should-check-chip-power-ground-pins.ts","../lib/check-no-ground-pin-defined.ts","../lib/check-schematic-component-excessive-vertical-padding.ts","../lib/check-schematic-component-missing-reference-designator-text.ts","../lib/check-schematic-component-ports-outside-body.ts","../lib/run-all-checks.ts","../lib/check-pcb-bus-length-skew.ts","../lib/consolidate-pcb-overlap-errors.ts","../lib/check-same-name-nets-are-connected.ts","../lib/check-connector-accessible-orientation.ts","../lib/check-courtyard-overlap/checkCourtyardOverlap.ts","../lib/check-testpoint-accessibility.ts"],"sourcesContent":["import Flatbush from \"flatbush\"\nimport * as Flatten from \"@flatten-js/core\"\nimport { getReadableNameForElement } from \"@tscircuit/circuit-json-util\"\nimport {\n convertCircuitJsonToFlattenJs,\n type FlattenElement,\n} from \"@tscircuit/circuit-json-to-flattenjs\"\nimport type { AnyCircuitElement, PcbPlacementError } from \"circuit-json\"\nimport {\n type ConnectivityMap,\n getFullConnectivityMapFromCircuitJson,\n} from \"circuit-json-to-connectivity-map\"\n\n/** Filled polygons include their holes, so copper wholly in a cutout is safe. */\nfunction touchesPour(\n pour: Flatten.Polygon,\n geometry: Flatten.Polygon,\n): boolean {\n if (!pour.box.intersect(geometry.box)) return false\n // distanceTo can report zero between tiny BRep segments and distant arcs.\n // Test actual boundary intersections and containment instead. Once boundaries\n // are disjoint, one point per face suffices; walking every pour vertex is costly.\n return (\n pour.intersect(geometry).length > 0 ||\n [...geometry.faces].some((face) => pour.contains(face.first.start)) ||\n [...pour.faces].some((face) => geometry.contains(face.first.start))\n )\n}\n\n/** Detect accidental copper contact, rather than enforcing a clearance margin. */\nexport function checkCopperPourShorts(\n circuitJson: AnyCircuitElement[],\n { connMap }: { connMap?: ConnectivityMap } = {},\n): PcbPlacementError[] {\n if (!circuitJson.some((e) => e.type === \"pcb_copper_pour\")) return []\n connMap ??= getFullConnectivityMapFromCircuitJson(circuitJson)\n const { elements: copper } = convertCircuitJsonToFlattenJs(circuitJson, {\n elementTypes: [\n \"pcb_smtpad\",\n \"pcb_plated_hole\",\n \"pcb_via\",\n \"pcb_trace\",\n \"pcb_copper_pour\",\n ],\n strict: true,\n })\n // Index individual shapes, not whole trace bounds, separately on each layer.\n // A long routed trace can have a large bounding box but few nearby segments.\n const layers = new Map<\n string | null,\n { element: FlattenElement; shape: Flatten.Polygon }[]\n >()\n for (const element of copper) {\n const entries = layers.get(element.layer) ?? []\n for (const shape of element.shapes) entries.push({ element, shape })\n layers.set(element.layer, entries)\n }\n const indexes = new Map(\n [...layers].map(([layer, entries]) => {\n const index = new Flatbush(entries.length)\n for (const { shape } of entries) {\n const b = shape.box\n index.add(b.xmin, b.ymin, b.xmax, b.ymax)\n }\n index.finish()\n return [layer, { index, entries }] as const\n }),\n )\n const netNames = new Map(\n circuitJson\n .filter((e) => e.type === \"source_net\")\n .map((e) => [e.source_net_id, e.name]),\n )\n const errors = new Map<string, PcbPlacementError>()\n for (const pour of copper) {\n const element = pour.sourceElement\n if (element.type !== \"pcb_copper_pour\") continue\n const netId = element.source_net_id\n const { index, entries } = indexes.get(pour.layer)!\n const candidates = new Set<number>()\n for (const shape of pour.shapes) {\n const b = shape.box\n for (const i of index.search(b.xmin, b.ymin, b.xmax, b.ymax))\n candidates.add(i)\n }\n // Preserve source order so error output is deterministic across index layouts.\n for (const i of [...candidates].sort((a, b) => a - b)) {\n const { element: other, shape: otherShape } = entries[i]\n if (pour.elementId === other.elementId) continue\n const otherNetId =\n other.sourceElement.type === \"pcb_copper_pour\"\n ? other.sourceElement.source_net_id\n : other.elementId\n if (\n netId &&\n otherNetId &&\n (netId === otherNetId || connMap.areIdsConnected(netId, otherNetId))\n )\n continue\n const id = `copper_pour_short_${[pour.elementId, other.elementId].sort().join(\"_\")}`\n if (\n errors.has(id) ||\n !pour.shapes.some((shape) => touchesPour(shape, otherShape))\n )\n continue\n errors.set(id, {\n type: \"pcb_placement_error\",\n pcb_placement_error_id: id,\n error_type: \"pcb_placement_error\",\n message: `Copper pour ${pour.elementId} (${netNames.get(netId!) ?? netId ?? \"unassigned net\"}) shorts to ${getReadableNameForElement(circuitJson, other.elementId)} (${other.elementId}) on ${pour.layer} (accidental copper contact)`,\n subcircuit_id: element.subcircuit_id,\n })\n }\n }\n return [...errors.values()]\n}\n","import * as F from \"@flatten-js/core\"\n\nexport type XY = { x: number; y: number }\nexport type Vertex = XY & { bulge?: number }\nconst EPS = 1e-9\nexport const point = (p: XY) => new F.Point(p.x, p.y)\n\nexport function positive(value: number, name: string): number {\n if (!Number.isFinite(value) || value <= 0)\n throw new Error(`${name} must be finite and positive`)\n return value\n}\n\nexport function circle(center: XY, radius: number): F.Polygon {\n positive(radius, \"radius\")\n return new F.Polygon(new F.Circle(point(center), radius))\n}\n\n/** Straight and circular edges, including two-vertex rings made of two arcs. */\nexport function ring(vertices: readonly Vertex[]): F.Polygon {\n const clean = vertices.filter(\n (p, i) => i === 0 || point(p).distanceTo(point(vertices[i - 1]))[0] > EPS,\n )\n if (\n clean.length > 1 &&\n point(clean[0]).distanceTo(point(clean.at(-1)!))[0] <= EPS\n )\n clean.pop()\n if (clean.length < 2)\n throw new Error(\"A ring needs at least two distinct vertices\")\n const edges: (F.Segment | F.Arc)[] = clean.map((a, i) => {\n const b = clean[(i + 1) % clean.length]\n if (![a.x, a.y, a.bulge ?? 0].every(Number.isFinite))\n throw new Error(\"Non-finite ring vertex\")\n const bulge = a.bulge ?? 0\n if (Math.abs(bulge) <= EPS) return new F.Segment(point(a), point(b))\n const dx = b.x - a.x,\n dy = b.y - a.y\n const length = Math.hypot(dx, dy)\n const offset = (length * (1 - bulge * bulge)) / (4 * bulge)\n const center = new F.Point(\n (a.x + b.x) / 2 - (dy / length) * offset,\n (a.y + b.y) / 2 + (dx / length) * offset,\n )\n return new F.Arc(\n center,\n (length * (1 + bulge * bulge)) / (4 * Math.abs(bulge)),\n Math.atan2(a.y - center.y, a.x - center.x),\n Math.atan2(b.y - center.y, b.x - center.x),\n bulge > 0,\n )\n })\n const polygon = new F.Polygon()\n polygon.addFace(edges)\n if (polygon.area() <= EPS)\n throw new Error(\"A ring must enclose a non-zero area\")\n return polygon\n}\n\n/** Exact rounded boundary: one face, not overlapping bands and circles. */\nexport function rectangle(\n center: XY,\n width: number,\n height: number,\n rotation = 0,\n radius = 0,\n): F.Polygon {\n positive(width, \"width\")\n positive(height, \"height\")\n if (!Number.isFinite(rotation) || !Number.isFinite(radius) || radius < 0)\n throw new Error(\"Invalid rectangle rotation or corner radius\")\n const r = Math.min(radius, width / 2, height / 2)\n const x = width / 2,\n y = height / 2\n let polygon: F.Polygon\n if (r <= EPS)\n polygon = ring([\n { x: -x, y: -y },\n { x, y: -y },\n { x, y },\n { x: -x, y },\n ])\n else {\n const corners = [\n new F.Point(x - r, -y + r),\n new F.Point(x - r, y - r),\n new F.Point(-x + r, y - r),\n new F.Point(-x + r, -y + r),\n ]\n const edges: (F.Arc | F.Segment)[] = []\n for (let i = 0; i < 4; i++) {\n const angle = -Math.PI / 2 + (i * Math.PI) / 2\n const arc = new F.Arc(corners[i], r, angle, angle + Math.PI / 2, true)\n const next = corners[(i + 1) % 4]\n const nextStart = new F.Point(\n next.x + r * Math.cos(angle + Math.PI / 2),\n next.y + r * Math.sin(angle + Math.PI / 2),\n )\n edges.push(arc)\n if (arc.end.distanceTo(nextStart)[0] > EPS)\n edges.push(new F.Segment(arc.end, nextStart))\n }\n polygon = new F.Polygon()\n polygon.addFace(edges)\n }\n return polygon\n .rotate((rotation * Math.PI) / 180)\n .translate(new F.Vector(center.x, center.y))\n}\n\n/** Capsule / convex hull of endpoint discs. Equal radii give a round trace. */\nexport function stroke(\n a: XY,\n b: XY,\n widthA: number,\n widthB = widthA,\n): F.Polygon {\n const r1 = positive(widthA, \"trace width\") / 2,\n r2 = positive(widthB, \"trace width\") / 2\n const d = point(a).distanceTo(point(b))[0]\n if (d <= Math.abs(r1 - r2) + EPS)\n return circle(r1 >= r2 ? a : b, Math.max(r1, r2))\n const theta = Math.atan2(b.y - a.y, b.x - a.x)\n const alpha = Math.acos((r1 - r2) / d)\n const low = theta - alpha,\n high = theta + alpha\n const p = (c: XY, r: number, angle: number) =>\n new F.Point(c.x + r * Math.cos(angle), c.y + r * Math.sin(angle))\n const polygon = new F.Polygon()\n polygon.addFace([\n new F.Segment(p(a, r1, low), p(b, r2, low)),\n new F.Arc(point(b), r2, low, high, true),\n new F.Segment(p(b, r2, high), p(a, r1, high)),\n new F.Arc(point(a), r1, high, low, true),\n ])\n return polygon\n}\n\n/** Add an interior void with winding opposite to the outer boundary. */\nexport function withHoles(\n outer: F.Polygon,\n holes: readonly F.Polygon[],\n): F.Polygon {\n const result = outer.clone()\n const orientation = [...result.faces][0].orientation()\n for (const hole of holes) {\n const copy = hole.clone()\n if ([...copy.faces][0].orientation() === orientation) copy.reverse()\n for (const face of copy.faces) result.addFace(face.shapes)\n }\n return result\n}\n\n/** FlattenJS has no ellipse primitive. Bound chord error in millimetres. */\nexport function ellipse(\n center: XY,\n width: number,\n height: number,\n rotation = 0,\n tolerance = 0.001,\n): F.Polygon {\n positive(width, \"ellipse width\")\n positive(height, \"ellipse height\")\n positive(tolerance, \"curveTolerance\")\n if (Math.abs(width - height) < EPS) return circle(center, width / 2)\n const radius = Math.max(width, height) / 2\n const count = Math.max(\n 16,\n Math.ceil(Math.PI / Math.acos(Math.max(-1, 1 - tolerance / radius))),\n )\n if (count > 100000)\n throw new Error(\"curveTolerance requires more than 100000 ellipse segments\")\n return ring(\n Array.from({ length: count }, (_, i) => ({\n x: (width / 2) * Math.cos((i * 2 * Math.PI) / count),\n y: (height / 2) * Math.sin((i * 2 * Math.PI) / count),\n })),\n )\n .rotate((rotation * Math.PI) / 180)\n .translate(new F.Vector(center.x, center.y))\n}\n","import type { AnyCircuitElement, LayerRef } from \"circuit-json\"\nimport type { ConversionOptions } from \"./types\"\n\nexport function getCopperLayers(\n json: readonly AnyCircuitElement[],\n options: ConversionOptions,\n): LayerRef[] {\n if (options.copperLayers) {\n if (\n !options.copperLayers.length ||\n new Set(options.copperLayers).size !== options.copperLayers.length\n )\n throw new Error(\n \"copperLayers must be a non-empty list without duplicates\",\n )\n return [...options.copperLayers]\n }\n const board = json.find((e) => e.type === \"pcb_board\")\n let count = board?.num_layers ?? 2\n for (const element of json) {\n const layers =\n \"layers\" in element\n ? element.layers\n : \"layer\" in element\n ? [element.layer]\n : []\n if (Array.isArray(layers))\n for (const layer of layers) {\n const match = typeof layer === \"string\" && /^inner(\\d+)$/.exec(layer)\n if (match) count = Math.max(count, Number(match[1]) + 2)\n }\n if (element.type === \"pcb_trace\")\n for (const p of element.route) {\n for (const layer of p.route_type === \"wire\"\n ? [p.layer]\n : p.route_type === \"via\"\n ? [p.from_layer, p.to_layer]\n : [p.start_layer, p.end_layer]) {\n const match = /^inner(\\d+)$/.exec(layer)\n if (match) count = Math.max(count, Number(match[1]) + 2)\n }\n }\n }\n if (!Number.isInteger(count) || count < 1 || count > 10)\n throw new Error(\"Supported copper layer count is 1–10\")\n return count === 1\n ? [\"top\"]\n : [\n \"top\",\n ...Array.from(\n { length: count - 2 },\n (_, i) => `inner${i + 1}` as LayerRef,\n ),\n \"bottom\",\n ]\n}\n\n/** Through copper spans the physical stack between its outermost named layers. */\nexport function spanLayers(\n layers: readonly string[],\n stack: readonly LayerRef[],\n): string[] {\n if (!layers.length) return []\n const indices = layers.map((layer) => stack.indexOf(layer as LayerRef))\n if (indices.some((i) => i < 0))\n throw new Error(`Layer is missing from copperLayers: ${layers.join(\", \")}`)\n return stack.slice(Math.min(...indices), Math.max(...indices) + 1)\n}\n","import { Vector, type Polygon } from \"@flatten-js/core\"\nimport type { PcbPlatedHole, PcbSmtPad, PcbHole } from \"circuit-json\"\nimport { circle, ellipse, rectangle, ring, withHoles } from \"./geometry\"\n\nexport function smtPad(pad: PcbSmtPad): Polygon {\n switch (pad.shape) {\n case \"circle\":\n return circle(pad, pad.radius)\n case \"polygon\":\n return ring(pad.points)\n case \"rect\":\n case \"rotated_rect\":\n return rectangle(\n pad,\n pad.width,\n pad.height,\n \"ccw_rotation\" in pad ? pad.ccw_rotation : 0,\n pad.rect_border_radius ?? pad.corner_radius ?? 0,\n )\n case \"pill\":\n case \"rotated_pill\":\n return rectangle(\n pad,\n pad.width,\n pad.height,\n \"ccw_rotation\" in pad ? pad.ccw_rotation : 0,\n pad.radius,\n )\n }\n}\n\nexport function nonPlatedHole(hole: PcbHole, tolerance: number): Polygon {\n switch (hole.hole_shape) {\n case \"circle\":\n return circle(hole, hole.hole_diameter / 2)\n case \"square\":\n return rectangle(hole, hole.hole_diameter, hole.hole_diameter)\n case \"rect\":\n return rectangle(hole, hole.hole_width, hole.hole_height)\n case \"oval\":\n return ellipse(hole, hole.hole_width, hole.hole_height, 0, tolerance)\n case \"pill\":\n case \"rotated_pill\":\n return rectangle(\n hole,\n hole.hole_width,\n hole.hole_height,\n \"ccw_rotation\" in hole ? hole.ccw_rotation : 0,\n Math.min(hole.hole_width, hole.hole_height) / 2,\n )\n }\n}\n\nexport function platedHole(\n hole: PcbPlatedHole,\n componentRotation: number,\n includeDrill: boolean,\n tolerance: number,\n): Polygon {\n let outer: Polygon\n let drill: Polygon\n const drillCenter = {\n x: hole.x + (\"hole_offset_x\" in hole ? (hole.hole_offset_x ?? 0) : 0),\n y: hole.y + (\"hole_offset_y\" in hole ? (hole.hole_offset_y ?? 0) : 0),\n }\n switch (hole.shape) {\n case \"circle\":\n outer = circle(hole, hole.outer_diameter / 2)\n drill = circle(hole, hole.hole_diameter / 2)\n break\n case \"oval\":\n outer = ellipse(\n hole,\n hole.outer_width,\n hole.outer_height,\n hole.ccw_rotation,\n tolerance,\n )\n drill = ellipse(\n hole,\n hole.hole_width,\n hole.hole_height,\n hole.ccw_rotation,\n tolerance,\n )\n break\n case \"pill\":\n outer = rectangle(\n hole,\n hole.outer_width,\n hole.outer_height,\n hole.ccw_rotation,\n Math.min(hole.outer_width, hole.outer_height) / 2,\n )\n drill = rectangle(\n hole,\n hole.hole_width,\n hole.hole_height,\n hole.ccw_rotation,\n Math.min(hole.hole_width, hole.hole_height) / 2,\n )\n break\n case \"circular_hole_with_rect_pad\":\n case \"pill_hole_with_rect_pad\":\n case \"rotated_pill_hole_with_rect_pad\":\n outer = rectangle(\n hole,\n hole.rect_pad_width,\n hole.rect_pad_height,\n \"rect_ccw_rotation\" in hole ? hole.rect_ccw_rotation : 0,\n hole.rect_border_radius ?? 0,\n )\n drill =\n hole.shape === \"circular_hole_with_rect_pad\"\n ? circle(drillCenter, hole.hole_diameter / 2)\n : rectangle(\n drillCenter,\n hole.hole_width,\n hole.hole_height,\n \"hole_ccw_rotation\" in hole ? hole.hole_ccw_rotation : 0,\n Math.min(hole.hole_width, hole.hole_height) / 2,\n )\n break\n case \"hole_with_polygon_pad\": {\n const rotation = hole.ccw_rotation ?? componentRotation\n outer = ring(hole.pad_outline)\n .rotate((rotation * Math.PI) / 180)\n .translate(new Vector(hole.x, hole.y))\n drill =\n hole.hole_shape === \"circle\"\n ? circle(drillCenter, hole.hole_diameter! / 2)\n : hole.hole_shape === \"oval\"\n ? ellipse(\n drillCenter,\n hole.hole_width!,\n hole.hole_height!,\n rotation,\n tolerance,\n )\n : rectangle(\n drillCenter,\n hole.hole_width!,\n hole.hole_height!,\n rotation,\n Math.min(hole.hole_width!, hole.hole_height!) / 2,\n )\n break\n }\n }\n return includeDrill ? withHoles(outer, [drill]) : outer\n}\n","import { BooleanOperations, type Polygon } from \"@flatten-js/core\"\nimport type { LayerRef, PcbTrace } from \"circuit-json\"\nimport { circle, ring, stroke, withHoles, positive, type XY } from \"./geometry\"\nimport { spanLayers } from \"./layers\"\n\ntype TraceSegment = {\n start: XY\n end: XY\n layer: string\n startWidth: number\n endWidth: number\n}\nconst samePoint = (a: XY, b: XY) => a.x === b.x && a.y === b.y\nconst unit = (x: number, y: number) => {\n const length = Math.hypot(x, y)\n return length ? { x: x / length, y: y / length } : { x: 1, y: 0 }\n}\n\n/** Interpolated traces use flat caps and averaged directions at bends. */\nfunction interpolatedPolygon(segments: TraceSegment[]): Polygon {\n const points = [\n { ...segments[0].start, width: segments[0].startWidth },\n ...segments.map((s) => ({ ...s.end, width: s.endWidth })),\n ]\n const directions = segments.map((s) =>\n unit(s.end.x - s.start.x, s.end.y - s.start.y),\n )\n const left: XY[] = [],\n right: XY[] = []\n for (let i = 0; i < points.length; i++) {\n const p = points[i]\n positive(p.width, \"interpolated trace width\")\n const before = directions[Math.max(0, i - 1)],\n after = directions[Math.min(i, directions.length - 1)]\n const d = unit(before.x + after.x, before.y + after.y)\n const nx = (-d.y * p.width) / 2,\n ny = (d.x * p.width) / 2\n left.push({ x: p.x + nx, y: p.y + ny })\n right.push({ x: p.x - nx, y: p.y - ny })\n }\n return ring([...left, ...right.reverse()])\n}\n\nexport function traceGeometry(\n trace: PcbTrace,\n stack: readonly LayerRef[],\n includeDrill: boolean,\n): Map<string, Polygon[]> {\n const result = new Map<string, Polygon[]>()\n const drills = new Map<string, Polygon[]>()\n const segments: TraceSegment[] = []\n const add = (layer: string, shape: Polygon) =>\n result.set(layer, [...(result.get(layer) ?? []), shape])\n for (const p of trace.route) {\n if (p.route_type === \"via\") {\n const legacy = p as typeof p & {\n via_diameter?: number\n via_hole_diameter?: number\n }\n const outerDiameter = p.outer_diameter ?? legacy.via_diameter\n if (outerDiameter === undefined) continue\n const holeDiameter = p.hole_diameter ?? legacy.via_hole_diameter\n const shape = circle(p, outerDiameter / 2)\n const drill =\n includeDrill && holeDiameter ? circle(p, holeDiameter / 2) : undefined\n for (const layer of spanLayers([p.from_layer, p.to_layer], stack)) {\n add(layer, drill ? withHoles(shape, [drill]) : shape)\n if (drill) drills.set(layer, [...(drills.get(layer) ?? []), drill])\n }\n }\n if (p.route_type === \"through_pad\") {\n for (const layer of new Set([p.start_layer, p.end_layer]))\n add(layer, stroke(p.start, p.end, p.width))\n }\n }\n for (let i = 0; i < trace.route.length - 1; i++) {\n const a = trace.route[i],\n b = trace.route[i + 1]\n const start = a.route_type === \"through_pad\" ? a.end : a\n const end = b.route_type === \"through_pad\" ? b.start : b\n if (samePoint(start, end)) continue\n // Via from/to fields describe its span, not the direction of route traversal.\n const startLayers =\n a.route_type === \"wire\"\n ? [a.layer]\n : a.route_type === \"via\"\n ? spanLayers([a.from_layer, a.to_layer], stack)\n : [a.end_layer]\n const endLayers =\n b.route_type === \"wire\"\n ? [b.layer]\n : b.route_type === \"via\"\n ? spanLayers([b.from_layer, b.to_layer], stack)\n : [b.start_layer]\n const sharedLayers = startLayers.filter((layer) =>\n endLayers.includes(layer as never),\n )\n if (sharedLayers.length !== 1)\n throw new Error(\n `Cannot determine one wire layer between route points ${i} and ${i + 1}`,\n )\n const startLayer = sharedLayers[0]\n const width = \"width\" in a ? a.width : \"width\" in b ? b.width : undefined\n if (width === undefined || samePoint(start, end)) continue\n segments.push({\n start,\n end,\n layer: startLayer,\n startWidth: width,\n endWidth: \"width\" in b ? b.width : width,\n })\n }\n if (trace.route_thickness_mode === \"interpolated\") {\n let group: TraceSegment[] = []\n const flush = () => {\n if (group.length) {\n add(group[0].layer, interpolatedPolygon(group))\n group = []\n }\n }\n for (const segment of segments) {\n const last = group.at(-1)\n if (\n last &&\n (last.layer !== segment.layer ||\n !samePoint(last.end, segment.start) ||\n last.endWidth !== segment.startWidth)\n )\n flush()\n group.push(segment)\n }\n flush()\n } else\n for (const s of segments) add(s.layer, stroke(s.start, s.end, s.startWidth))\n // Drilling removes material from the adjoining wire as well as the annular pad.\n for (const [layer, holes] of drills) {\n result.set(\n layer,\n result\n .get(layer)!\n .map((shape) =>\n holes.reduce(\n (shape, hole) => BooleanOperations.subtract(shape, hole),\n shape,\n ),\n )\n .filter((shape) => shape.faces.size > 0),\n )\n }\n return result\n}\n","import type { Polygon } from \"@flatten-js/core\"\nimport type { AnyCircuitElement, PcbCutout } from \"circuit-json\"\nimport { circle, rectangle, ring, stroke, withHoles } from \"./geometry\"\nimport { getCopperLayers, spanLayers } from \"./layers\"\nimport { nonPlatedHole, platedHole, smtPad } from \"./pads\"\nimport { traceGeometry } from \"./traces\"\nimport type {\n ConversionOptions,\n FlattenConversionResult,\n FlattenElement,\n GeometryRole,\n} from \"./types\"\n\nexport const supportedElementTypes = [\n \"pcb_board\",\n \"pcb_smtpad\",\n \"pcb_plated_hole\",\n \"pcb_hole\",\n \"pcb_via\",\n \"pcb_trace\",\n \"pcb_copper_pour\",\n \"pcb_cutout\",\n \"pcb_keepout\",\n \"pcb_courtyard_rect\",\n \"pcb_courtyard_circle\",\n \"pcb_courtyard_pill\",\n \"pcb_courtyard_polygon\",\n \"pcb_courtyard_outline\",\n] as const\n\nfunction cutoutGeometry(cutout: PcbCutout): Polygon[] {\n switch (cutout.shape) {\n case \"circle\":\n return [circle(cutout.center, cutout.radius)]\n case \"rect\":\n return [\n rectangle(\n cutout.center,\n cutout.width,\n cutout.height,\n cutout.rotation,\n cutout.corner_radius,\n ),\n ]\n case \"polygon\":\n return [ring(cutout.points)]\n case \"path\": {\n if (\n cutout.slot_length !== undefined ||\n cutout.space_between_slots !== undefined ||\n cutout.slot_corner_radius !== undefined\n ) {\n throw new Error(\n \"Patterned/custom-corner path cutouts are not supported; use explicit rect/polygon cutouts\",\n )\n }\n return cutout.route\n .slice(1)\n .map((p, i) => stroke(cutout.route[i], p, cutout.slot_width))\n }\n }\n}\n\nexport function convertCircuitJsonToFlattenJs(\n json: readonly AnyCircuitElement[],\n options: ConversionOptions = {},\n): FlattenConversionResult {\n if (options.layer && options.layers)\n throw new Error(\"Specify layer or layers, not both\")\n const selectedLayers = options.layer ? [options.layer] : options.layers\n const stack = getCopperLayers(json, options)\n const result: FlattenConversionResult = {\n elements: [],\n warnings: [],\n bounds: undefined,\n copperLayers: stack,\n }\n const rotations = new Map(\n json\n .filter((e) => e.type === \"pcb_component\")\n .map((e) => [e.pcb_component_id, e.rotation]),\n )\n const tolerance = options.curveTolerance ?? 0.001\n if (!Number.isFinite(tolerance) || tolerance <= 0)\n throw new Error(\"curveTolerance must be finite and positive\")\n const includeDrill = options.includeDrillHoles !== false\n for (const element of json) {\n if (!(supportedElementTypes as readonly string[]).includes(element.type))\n continue\n const elementId = (element as unknown as Record<string, unknown>)[\n `${element.type}_id`\n ] as string\n if (options.elementTypes && !options.elementTypes.includes(element.type))\n continue\n if (options.elementIds && !options.elementIds.includes(elementId)) continue\n let role: GeometryRole = \"copper\"\n let layers: (string | null)[] = [null]\n let shapes: Polygon[] = []\n let byLayer: Map<string, Polygon[]> | undefined\n try {\n switch (element.type) {\n case \"pcb_smtpad\":\n layers = [element.layer]\n shapes = [smtPad(element)]\n break\n case \"pcb_plated_hole\":\n layers = spanLayers(element.layers, stack)\n shapes = [\n platedHole(\n element,\n rotations.get(element.pcb_component_id ?? \"\") ?? 0,\n includeDrill,\n tolerance,\n ),\n ]\n break\n case \"pcb_via\": {\n layers = spanLayers(element.layers, stack)\n const outer = circle(element, element.outer_diameter / 2)\n shapes = [\n includeDrill\n ? withHoles(outer, [circle(element, element.hole_diameter / 2)])\n : outer,\n ]\n break\n }\n case \"pcb_trace\":\n byLayer = traceGeometry(element, stack, includeDrill)\n layers = [...byLayer.keys()]\n break\n case \"pcb_copper_pour\":\n layers = [element.layer]\n shapes = [\n element.shape === \"rect\"\n ? rectangle(\n element.center,\n element.width,\n element.height,\n element.rotation,\n )\n : element.shape === \"polygon\"\n ? ring(element.points)\n : withHoles(\n ring(element.brep_shape.outer_ring.vertices),\n element.brep_shape.inner_rings.map(\n (h: { vertices: import(\"./geometry\").Vertex[] }) =>\n ring(h.vertices),\n ),\n ),\n ]\n break\n case \"pcb_board\":\n role = \"board\"\n shapes = [\n element.outline?.length\n ? ring(element.outline)\n : rectangle(element.center, element.width!, element.height!),\n ]\n break\n case \"pcb_hole\":\n role = \"drill\"\n shapes = [nonPlatedHole(element, tolerance)]\n break\n case \"pcb_cutout\":\n role = \"cutout\"\n shapes = cutoutGeometry(element)\n break\n case \"pcb_keepout\":\n role = \"keepout\"\n layers = element.layers\n shapes = [\n element.shape === \"circle\"\n ? circle(element.center, element.radius)\n : element.shape === \"rect\"\n ? rectangle(element.center, element.width, element.height)\n : ring(element.outline),\n ]\n break\n case \"pcb_courtyard_rect\":\n role = \"courtyard\"\n layers = [element.layer]\n shapes = [\n rectangle(\n element.center,\n element.width,\n element.height,\n element.ccw_rotation,\n ),\n ]\n break\n case \"pcb_courtyard_circle\":\n role = \"courtyard\"\n layers = [element.layer]\n shapes = [circle(element.center, element.radius)]\n break\n case \"pcb_courtyard_pill\":\n role = \"courtyard\"\n layers = [element.layer]\n shapes = [\n rectangle(\n element.center,\n element.width,\n element.height,\n 0,\n element.radius,\n ),\n ]\n break\n case \"pcb_courtyard_polygon\":\n role = \"courtyard\"\n layers = [element.layer]\n shapes = [ring(element.points)]\n break\n case \"pcb_courtyard_outline\":\n role = \"courtyard\"\n layers = [element.layer]\n shapes = [ring(element.outline)]\n break\n }\n if (options.roles && !options.roles.includes(role)) continue\n const convertedElements: FlattenElement[] = []\n for (const layer of new Set(layers)) {\n if (\n layer === null\n ? options.includeLayerless === false\n : selectedLayers && !selectedLayers.includes(layer as never)\n )\n continue\n const layerShapes = byLayer?.get(layer!) ?? shapes\n if (!layerShapes.length) continue\n const bounds = layerShapes.reduce(\n (box, shape) => box.merge(shape.box),\n layerShapes[0].box,\n )\n if (\n ![bounds.xmin, bounds.ymin, bounds.xmax, bounds.ymax].every(\n Number.isFinite,\n )\n )\n throw new Error(\"Non-finite geometry bounds\")\n const converted: FlattenElement = {\n elementId,\n elementType: element.type,\n sourceElement: element,\n role,\n layer,\n shapes: layerShapes,\n bounds,\n }\n convertedElements.push(converted)\n }\n for (const converted of convertedElements) {\n result.elements.push(converted)\n result.bounds = result.bounds\n ? result.bounds.merge(converted.bounds)\n : converted.bounds\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n if (options.strict) throw new Error(`${elementId}: ${message}`)\n result.warnings.push({ elementId, elementType: element.type, message })\n }\n }\n return result\n}\n\n/** Provide the enclosing circuit for board stackup and component-local polygon pads. */\nexport function convertCircuitJsonElementToFlattenJs(\n element: AnyCircuitElement,\n options: ConversionOptions & {\n circuitJson?: readonly AnyCircuitElement[]\n } = {},\n): FlattenConversionResult {\n const { circuitJson = [], ...conversionOptions } = options\n const id = (element as unknown as Record<string, unknown>)[\n `${element.type}_id`\n ] as string\n const context = circuitJson.filter(\n (e) =>\n e !== element &&\n (e as unknown as Record<string, unknown>)[`${e.type}_id`] !== id,\n )\n return convertCircuitJsonToFlattenJs([...context, element], {\n ...conversionOptions,\n elementIds: [id],\n })\n}\n","import { Arc, type Polygon, type Point } from \"@flatten-js/core\"\n\n// SVG precision is intentionally separate from the full-precision geometry.\n// Normalize -0 and libm rounding differences across supported JS platforms.\nconst number = (value: number) => String(Number(value.toFixed(8)))\nconst point = (p: Point) => `${number(p.x)},${number(p.y)}`\n\nexport function polygonToSvg(\n polygon: Polygon,\n attrs: { fill: string; stroke: string; strokeWidth?: number },\n): string {\n const paths = [...polygon.faces].map((face) => {\n const edges = face.shapes\n if (!edges.length) return \"\"\n const commands = [`M${point(edges[0].start)}`]\n for (const shape of edges) {\n if (shape instanceof Arc) {\n const sweep = shape.counterClockwise ? 1 : 0\n const arc = (end: Point, large = 0) =>\n `A${number(shape.r)},${number(shape.r)} 0 ${large},${sweep} ${point(end)}`\n if (shape.sweep >= 2 * Math.PI - 1e-9) {\n commands.push(arc(shape.middle()), arc(shape.end))\n } else {\n // A semicircle can land just above pi on one platform and below on\n // another. Either flag draws it identically, so canonicalize it.\n commands.push(arc(shape.end, shape.sweep > Math.PI + 1e-9 ? 1 : 0))\n }\n } else commands.push(`L${point(shape.end)}`)\n }\n return `${commands.join(\" \")} Z`\n })\n return `<path fill=\"${attrs.fill}\" stroke=\"${attrs.stroke}\" stroke-width=\"${attrs.strokeWidth ?? 0}\" fill-rule=\"evenodd\" d=\"${paths.join(\" \")}\"/>`\n}\n","import { polygonToSvg } from \"./polygon-to-svg\"\nimport type { FlattenConversionResult, GeometryRole } from \"./types\"\nexport interface FlattenSvgOptions {\n width?: number\n height?: number\n padding?: number\n background?: string\n viewport?: { minX: number; minY: number; maxX: number; maxY: number }\n colors?: Partial<Record<GeometryRole, string>>\n}\nconst escape = (text: string) =>\n text\n .replaceAll(\"&\", \"&\")\n .replaceAll('\"', \""\")\n .replaceAll(\"<\", \"<\")\n .replaceAll(\">\", \">\")\n\n/** SVG generated only from FlattenJS polygons; +Y remains up in circuit coordinates. */\nexport function renderFlattenJsToSvg(\n result: FlattenConversionResult,\n options: FlattenSvgOptions = {},\n): string {\n const width = options.width ?? 500,\n height = options.height ?? 360\n const padding = options.padding ?? 1\n const b = result.bounds\n const v = options.viewport ?? {\n minX: (b?.xmin ?? -1) - padding,\n minY: (b?.ymin ?? -1) - padding,\n maxX: (b?.xmax ?? 1) + padding,\n maxY: (b?.ymax ?? 1) + padding,\n }\n const colors = {\n copper: \"#c87828\",\n board: \"#59726b\",\n drill: \"#0b1018\",\n cutout: \"#0b1018\",\n keepout: \"#e85872\",\n courtyard: \"#a879e8\",\n ...options.colors,\n }\n const order: GeometryRole[] = [\n \"board\",\n \"copper\",\n \"keepout\",\n \"courtyard\",\n \"drill\",\n \"cutout\",\n ]\n const content = [...result.elements]\n .sort((a, b) => order.indexOf(a.role) - order.indexOf(b.role))\n .map((e) => {\n const outline = e.role === \"board\" || e.role === \"courtyard\"\n const attrs = {\n fill: outline ? \"none\" : escape(colors[e.role]),\n stroke: outline ? escape(colors[e.role]) : \"none\",\n strokeWidth: e.role === \"courtyard\" ? 0.05 : 0.1,\n fillRule: \"evenodd\" as const,\n }\n return `<g data-element-id=\"${escape(e.elementId)}\" data-layer=\"${escape(e.layer ?? \"all\")}\">${e.shapes.map((shape) => polygonToSvg(shape, attrs)).join(\"\")}</g>`\n })\n .join(\"\")\n // Display drilled voids using the drill color without changing polygon topology.\n const drillVoids = result.elements\n .filter((e) =>\n [\"pcb_via\", \"pcb_plated_hole\", \"pcb_trace\"].includes(e.elementType),\n )\n .flatMap((e) =>\n e.shapes.flatMap((shape) => {\n const faces = [...shape.faces]\n if (faces.length < 2) return []\n const outerOrientation = faces[0].orientation()\n return faces\n .filter((face) => face.orientation() !== outerOrientation)\n .map((face) =>\n polygonToSvg(face.toPolygon(), {\n fill: escape(colors.drill),\n stroke: \"none\",\n }),\n )\n }),\n )\n .join(\"\")\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${width}\" height=\"${height}\" viewBox=\"${v.minX} ${-v.maxY} ${v.maxX - v.minX} ${v.maxY - v.minY}\"><rect x=\"${v.minX}\" y=\"${-v.maxY}\" width=\"${v.maxX - v.minX}\" height=\"${v.maxY - v.minY}\" fill=\"${escape(options.background ?? \"#0b1018\")}\"/><g transform=\"scale(1,-1)\">${content}${drillVoids}</g></svg>`\n}\n","import type { AnyCircuitElement } from \"circuit-json\"\nimport {\n ConnectivityMap,\n findConnectedNetworks,\n PcbConnectivityMap,\n} from \"circuit-json-to-connectivity-map\"\nimport Flatbush from \"flatbush\"\nimport { getViaAndPourConnections } from \"./get-via-and-pour-connections\"\n\ntype TraceBounds = {\n traceIndex: number\n minX: number\n minY: number\n maxX: number\n maxY: number\n}\n\n/** Physical trace connectivity, including plated via barrels and copper pours. */\nexport function createIndexedPcbConnectivityMap(\n circuitJson: AnyCircuitElement[],\n): PcbConnectivityMap {\n // Construct empty to avoid the dependency's all-pairs scan. Keep its exact\n // intersection predicate and query methods, including cross-net contacts.\n const map = new PcbConnectivityMap()\n map.circuitJson = circuitJson\n for (const element of circuitJson) {\n if (element.type === \"pcb_trace\") {\n map.traceIdToElm.set(element.pcb_trace_id, element)\n } else if (element.type === \"pcb_port\") {\n map.portIdToElm.set(element.pcb_port_id, element)\n }\n }\n const traces = [...map.traceIdToElm.values()]\n const boundsByLayer = new Map<string, TraceBounds[]>()\n for (const [traceIndex, trace] of traces.entries()) {\n const boundsForTrace = new Map<string, TraceBounds>()\n for (let i = 0; i < trace.route.length - 1; i++) {\n const a = trace.route[i]\n const b = trace.route[i + 1]\n if (\n a.route_type !== \"wire\" ||\n b.route_type !== \"wire\" ||\n a.layer !== b.layer\n )\n continue\n const bounds = boundsForTrace.get(a.layer) ?? {\n traceIndex,\n minX: Infinity,\n minY: Infinity,\n maxX: -Infinity,\n maxY: -Infinity,\n }\n // The exact predicate uses the first point's width for each segment.\n // A small conservative margin avoids excluding contacts at rounding boundaries.\n const radius = a.width / 2 + 1e-9\n bounds.minX = Math.min(bounds.minX, a.x - radius, b.x - radius)\n bounds.minY = Math.min(bounds.minY, a.y - radius, b.y - radius)\n bounds.maxX = Math.max(bounds.maxX, a.x + radius, b.x + radius)\n bounds.maxY = Math.max(bounds.maxY, a.y + radius, b.y + radius)\n boundsForTrace.set(a.layer, bounds)\n }\n for (const [layer, bounds] of boundsForTrace) {\n const entries = boundsByLayer.get(layer) ?? []\n entries.push(bounds)\n boundsByLayer.set(layer, entries)\n }\n }\n const candidates = traces.map(() => new Set<number>())\n for (const bounds of boundsByLayer.values()) {\n const index = new Flatbush(bounds.length)\n for (const box of bounds) index.add(box.minX, box.minY, box.maxX, box.maxY)\n index.finish()\n for (const box of bounds) {\n for (const hit of index.search(box.minX, box.minY, box.maxX, box.maxY)) {\n const other = bounds[hit].traceIndex\n if (other > box.traceIndex) candidates[box.traceIndex].add(other)\n }\n }\n }\n const connections: string[][] = []\n // Preserve the original pair order for stable net IDs and diagnostics.\n for (const [i, neighbors] of candidates.entries()) {\n for (const j of [...neighbors].sort((a, b) => a - b)) {\n if (map._arePcbTracesConnected(traces[i], traces[j])) {\n connections.push([traces[i].pcb_trace_id, traces[j].pcb_trace_id])\n }\n }\n }\n const connectionsByPort = new Map<string, string[][]>()\n for (const trace of traces) {\n for (const point of trace.route) {\n if (point.route_type !== \"wire\") continue\n for (const portId of new Set([\n point.start_pcb_port_id,\n point.end_pcb_port_id,\n ])) {\n if (!portId || !map.portIdToElm.has(portId)) continue\n const entries = connectionsByPort.get(portId) ?? []\n entries.push(\n point.start_pcb_port_id === portId\n ? [portId, trace.pcb_trace_id]\n : [trace.pcb_trace_id, portId],\n )\n connectionsByPort.set(portId, entries)\n }\n }\n }\n for (const portId of map.portIdToElm.keys()) {\n for (const connection of connectionsByPort.get(portId) ?? [])\n connections.push(connection)\n }\n connections.push(...getViaAndPourConnections(circuitJson))\n map.connMap = new ConnectivityMap(findConnectedNetworks(connections))\n return map\n}\n","import type { Polygon } from \"@flatten-js/core\"\nimport { all_layers, type AnyCircuitElement, type PcbVia } from \"circuit-json\"\nimport {\n getPourPolygon,\n getTraceSegmentPolygon,\n getViaPolygon,\n} from \"@tscircuit/circuit-json-util\"\nimport Flatbush from \"flatbush\"\nimport { createCopperPolygonContactTester } from \"../copper-pour-connectivity/create-copper-polygon-contact-tester\"\n\ntype Conductor = {\n id: string\n layers: string[]\n polygon: Polygon\n bridges: boolean\n}\n\n/** Add physical barrel/pour edges in board-world mm. Logical net membership\n * never joins copper; holes in pours and the emitted via layer span are retained.\n * Wire/wire intersections remain handled by the existing trace index.\n * Pads stay in the dedicated port/pour checks: adding their IDs here would\n * let a partial pour connection satisfy a named-net port prematurely.\n */\nexport function getViaAndPourConnections(\n circuit: AnyCircuitElement[],\n): string[][] {\n if (\n !circuit.some(\n (e) =>\n e.type === \"pcb_via\" ||\n e.type === \"pcb_copper_pour\" ||\n (e.type === \"pcb_trace\" && e.route.some((p) => p.route_type === \"via\")),\n )\n )\n return []\n const conductors: Conductor[] = []\n const connections: string[][] = []\n const scale = 1e6\n const tolerance = 1e-7 * scale\n const touches = createCopperPolygonContactTester(tolerance)\n const add = (\n id: string,\n layers: string[],\n polygon: Polygon,\n bridges = false,\n ) => {\n if (!polygon.isEmpty())\n conductors.push({\n id,\n layers,\n polygon: polygon.scale(scale, scale),\n bridges,\n })\n }\n const vias = circuit.filter((e) => e.type === \"pcb_via\")\n const board = circuit.find((e) => e.type === \"pcb_board\")\n const stack = [\n \"top\",\n ...all_layers\n .filter((l) => l.startsWith(\"inner\"))\n .slice(0, board ? Math.max(0, board.num_layers - 2) : undefined),\n ...(board?.num_layers === 1 ? [] : [\"bottom\"]),\n ]\n for (const copper of circuit) {\n if (copper.type === \"pcb_via\") {\n add(\n copper.pcb_via_id,\n copper.layers,\n getViaPolygon(copper, copper.outer_diameter, 0),\n true,\n )\n if (copper.pcb_trace_id)\n connections.push([copper.pcb_via_id, copper.pcb_trace_id])\n } else if (copper.type === \"pcb_copper_pour\") {\n add(\n copper.pcb_copper_pour_id,\n [copper.layer],\n getPourPolygon(copper),\n true,\n )\n } else if (copper.type === \"pcb_trace\") {\n if (copper.route_thickness_mode === \"interpolated\") continue\n for (let i = 0; i < copper.route.length; i++) {\n const a = copper.route[i],\n b = copper.route[i + 1]\n if (\n a.route_type === \"wire\" &&\n b?.route_type === \"wire\" &&\n a.layer === b.layer &&\n (a.x !== b.x || a.y !== b.y)\n ) {\n add(\n copper.pcb_trace_id,\n [a.layer],\n getTraceSegmentPolygon(a, b, a.width),\n )\n } else if (a.route_type === \"via\") {\n // A materialized via is authoritative (especially for blind/buried spans).\n if (\n vias.some(\n (v) =>\n v.pcb_trace_id === copper.pcb_trace_id &&\n Math.hypot(v.x - a.x, v.y - a.y) < 1e-9,\n )\n )\n continue\n const from = stack.indexOf(a.from_layer),\n to = stack.indexOf(a.to_layer)\n if (from < 0 || to < 0 || !a.outer_diameter) continue\n const via = {\n type: \"pcb_via\",\n pcb_via_id: `${copper.pcb_trace_id}_via_${i}`,\n x: a.x,\n y: a.y,\n outer_diameter: a.outer_diameter,\n hole_diameter: 0,\n layers: stack.slice(Math.min(from, to), Math.max(from, to) + 1),\n } as PcbVia\n add(\n copper.pcb_trace_id,\n via.layers,\n getViaPolygon(via, via.outer_diameter, 0),\n true,\n )\n }\n }\n }\n }\n if (!conductors.length) return connections\n const index = new Flatbush(conductors.length)\n for (const { polygon } of conductors) {\n const b = polygon.box\n index.add(b.xmin, b.ymin, b.xmax, b.ymax)\n }\n index.finish()\n for (const [i, a] of conductors.entries()) {\n if (!a.bridges) continue\n const box = a.polygon.box\n for (const j of index.search(\n box.xmin - tolerance,\n box.ymin - tolerance,\n box.xmax + tolerance,\n box.ymax + tolerance,\n )) {\n const b = conductors[j]\n if (\n i === j ||\n a.id === b.id ||\n (b.bridges && j < i) ||\n !a.layers.some((l) => b.layers.includes(l))\n )\n continue\n if (touches(a.polygon, b.polygon)) connections.push([a.id, b.id])\n }\n }\n return connections\n}\n","import {\n Box,\n type Arc,\n type Point,\n type Polygon,\n type PolygonEdge,\n type Segment,\n} from \"@flatten-js/core\"\n\ninterface PolygonGeometry {\n box: Box\n facePoints: Point[]\n edges: (Segment | Arc)[]\n edgeIndex: Polygon[\"edges\"]\n}\n\n/** Cache only for one connectivity pass: the input polygons must remain unchanged. */\nexport function createCopperPolygonContactTester(tolerance: number) {\n const cache = new WeakMap<Polygon, PolygonGeometry>()\n const getGeometry = (polygon: Polygon): PolygonGeometry => {\n let geometry = cache.get(polygon)\n if (!geometry) {\n geometry = {\n box: polygon.box,\n facePoints: [...polygon.faces].map((face) => face.first.start),\n edges: [...polygon.edges].map((edge) => edge.shape),\n edgeIndex: polygon.edges,\n }\n cache.set(polygon, geometry)\n }\n return geometry\n }\n return (a: Polygon, b: Polygon): boolean => {\n if (a.isEmpty() || b.isEmpty()) return false\n const ga = getGeometry(a)\n const gb = getGeometry(b)\n if (\n ga.box.xmin > gb.box.xmax + tolerance ||\n ga.box.xmax < gb.box.xmin - tolerance ||\n ga.box.ymin > gb.box.ymax + tolerance ||\n ga.box.ymax < gb.box.ymin - tolerance\n )\n return false\n\n // With disjoint boundaries, one point per face determines containment.\n // If boundaries cross elsewhere, the edge tests below detect the contact.\n // Polygon.contains retains the polygon's holes and separate faces.\n if (\n ga.facePoints.some(\n (point) => gb.box.contains(point) && b.contains(point),\n ) ||\n gb.facePoints.some((point) => ga.box.contains(point) && a.contains(point))\n )\n return true\n\n // Search the larger boundary using the smaller one's edges. Expanded\n // boxes include near contacts; the exact arc/segment distance decides.\n const [small, large] =\n ga.edges.length <= gb.edges.length ? [ga, gb] : [gb, ga]\n for (const edge of small.edges) {\n const box = edge.box\n const queryBox = new Box(\n box.xmin - tolerance,\n box.ymin - tolerance,\n box.xmax + tolerance,\n box.ymax + tolerance,\n )\n // Polygon.edges is already an indexed PlanarSet of PolygonEdge objects.\n // Flatten's generic search declaration returns AnyShape[], so narrow it\n // to the actual element type of this polygon-owned collection.\n const candidates = large.edgeIndex.search(\n queryBox,\n ) as unknown as PolygonEdge[]\n for (const candidate of candidates) {\n if (edge.distanceTo(candidate.shape)[0] <= tolerance) return true\n }\n }\n return false\n }\n}\n","import type { PcbSmtPad, PcbPlatedHole } from \"circuit-json\"\nimport { pointToSegmentDistance } from \"@tscircuit/math-utils\"\nimport {\n getPillCenterLineForPad,\n getPolygonPointsForPad,\n} from \"lib/check-each-pcb-trace-non-overlapping/segment-to-polygon-clearance\"\n\nfunction getDistanceBetweenPoints(\n pointA: { x: number; y: number },\n pointB: { x: number; y: number },\n): number {\n return Math.sqrt((pointB.x - pointA.x) ** 2 + (pointB.y - pointA.y) ** 2)\n}\n\nconst POINT_ON_SEGMENT_TOLERANCE_MM = 1e-9\n\n// Circuit coordinates commonly reach pad boundaries through separate decimal\n// calculations. Allow their sub-nanometer floating-point residue while keeping\n// physical gaps outside the pad.\nconst POINT_IN_PAD_TOLERANCE_MM = 1e-9\n\nfunction isPointOnSegment(\n point: { x: number; y: number },\n segment: { start: { x: number; y: number }; end: { x: number; y: number } },\n) {\n const crossProduct =\n (point.y - segment.start.y) * (segment.end.x - segment.start.x) -\n (point.x - segment.start.x) * (segment.end.y - segment.start.y)\n if (Math.abs(crossProduct) > POINT_ON_SEGMENT_TOLERANCE_MM) return false\n\n const dotProduct =\n (point.x - segment.start.x) * (segment.end.x - segment.start.x) +\n (point.y - segment.start.y) * (segment.end.y - segment.start.y)\n if (dotProduct < -POINT_ON_SEGMENT_TOLERANCE_MM) return false\n\n const squaredLength =\n (segment.end.x - segment.start.x) ** 2 +\n (segment.end.y - segment.start.y) ** 2\n return dotProduct <= squaredLength + POINT_ON_SEGMENT_TOLERANCE_MM\n}\n\nfunction isPointInPolygon(\n point: { x: number; y: number },\n polygon: Array<{ x: number; y: number }>,\n): boolean {\n let inside = false\n for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {\n const pi = polygon[i]\n const pj = polygon[j]\n if (isPointOnSegment(point, { start: pi, end: pj })) return true\n\n const intersects =\n pi.y > point.y !== pj.y > point.y &&\n point.x < ((pj.x - pi.x) * (point.y - pi.y)) / (pj.y - pi.y) + pi.x\n if (intersects) inside = !inside\n }\n return inside\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 (\n getDistanceBetweenPoints(point, pad) <=\n pad.radius + POINT_IN_PAD_TOLERANCE_MM\n )\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 + POINT_IN_PAD_TOLERANCE_MM &&\n Math.abs(point.y - pad.y) <= halfHeight + POINT_IN_PAD_TOLERANCE_MM\n )\n }\n\n if (pad.shape === \"rotated_rect\") {\n return isPointInPolygon(point, getPolygonPointsForPad(pad))\n }\n\n if (pad.shape === \"pill\" || pad.shape === \"rotated_pill\") {\n if (pad.shape === \"rotated_pill\") {\n const pill = getPillCenterLineForPad(pad)\n return (\n pointToSegmentDistance(point, pill.start, pill.end) <=\n pill.radius + POINT_IN_PAD_TOLERANCE_MM\n )\n }\n\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) <=\n halfWidth - radius + POINT_IN_PAD_TOLERANCE_MM &&\n Math.abs(point.y - pad.y) <= halfHeight + POINT_IN_PAD_TOLERANCE_MM\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 const radiusWithTolerance = radius + POINT_IN_PAD_TOLERANCE_MM\n return (\n cornerX * cornerX + cornerY * cornerY <=\n radiusWithTolerance * radiusWithTolerance\n )\n }\n\n if (pad.shape === \"polygon\") {\n return isPointInPolygon(point, pad.points)\n }\n }\n\n if (pad.type === \"pcb_plated_hole\") {\n if (pad.shape === \"circle\") {\n return (\n getDistanceBetweenPoints(point, pad) <=\n pad.outer_diameter / 2 + POINT_IN_PAD_TOLERANCE_MM\n )\n }\n\n if (\"rect_pad_width\" in pad && \"rect_pad_height\" in pad) {\n return isPointInPolygon(point, getPolygonPointsForPad(pad))\n }\n\n if (pad.shape === \"oval\" || pad.shape === \"pill\") {\n return (\n Math.abs(point.x - pad.x) <=\n pad.outer_width / 2 + POINT_IN_PAD_TOLERANCE_MM &&\n Math.abs(point.y - pad.y) <=\n pad.outer_height / 2 + POINT_IN_PAD_TOLERANCE_MM\n )\n }\n }\n\n return false\n}\n","import {\n distSq,\n getSegmentIntersection,\n isPointInsidePolygon,\n type Point,\n pointToSegmentClosestPoint,\n segmentToSegmentMinDistance,\n} from \"@tscircuit/math-utils\"\nimport type { PcbPlatedHole, PcbSmtPad } from \"circuit-json\"\nimport type { PcbTraceSegment } from \"./getCollidableBounds\"\n\ntype PolygonalPad = PcbSmtPad | PcbPlatedHole\ntype PillPad =\n | Extract<PcbSmtPad, { shape: \"pill\" | \"rotated_pill\" }>\n | Extract<PcbPlatedHole, { shape: \"oval\" | \"pill\" }>\n\nconst rotatePoint = (point: Point, angleDegrees: number): Point => {\n const angle = (angleDegrees * Math.PI) / 180\n return {\n x: point.x * Math.cos(angle) - point.y * Math.sin(angle),\n y: point.x * Math.sin(angle) + point.y * Math.cos(angle),\n }\n}\n\nexport const getRotatedRectPoints = ({\n x,\n y,\n width,\n height,\n ccwRotation,\n}: {\n x: number\n y: number\n width: number\n height: number\n ccwRotation: number\n}): Point[] => {\n const halfWidth = width / 2\n const halfHeight = height / 2\n\n return [\n { x: -halfWidth, y: -halfHeight },\n { x: halfWidth, y: -halfHeight },\n { x: halfWidth, y: halfHeight },\n { x: -halfWidth, y: halfHeight },\n ].map((point) => {\n const rotated = rotatePoint(point, ccwRotation)\n return { x: x + rotated.x, y: y + rotated.y }\n })\n}\n\nexport const getPillCenterLineForPad = (pad: PillPad) => {\n const width = pad.type === \"pcb_plated_hole\" ? pad.outer_width : pad.width\n const height = pad.type === \"pcb_plated_hole\" ? pad.outer_height : pad.height\n const radius =\n pad.type === \"pcb_plated_hole\" ? Math.min(width, height) / 2 : pad.radius\n const ccwRotation =\n pad.type === \"pcb_plated_hole\"\n ? pad.ccw_rotation\n : pad.shape === \"rotated_pill\"\n ? pad.ccw_rotation\n : 0\n const halfLineLength = Math.max(Math.max(width, height) / 2 - radius, 0)\n const axis =\n width >= height ? { x: halfLineLength, y: 0 } : { x: 0, y: halfLineLength }\n const rotatedAxis = rotatePoint(axis, ccwRotation)\n\n return {\n start: { x: pad.x - rotatedAxis.x, y: pad.y - rotatedAxis.y },\n end: { x: pad.x + rotatedAxis.x, y: pad.y + rotatedAxis.y },\n radius,\n }\n}\n\nexport const getPolygonPointsForPad = (pad: PolygonalPad): Point[] => {\n if (pad.type === \"pcb_smtpad\") {\n if (pad.shape === \"polygon\") return pad.points\n\n if (pad.shape === \"rotated_rect\") {\n return getRotatedRectPoints({\n x: pad.x,\n y: pad.y,\n width: pad.width,\n height: pad.height,\n ccwRotation: pad.ccw_rotation,\n })\n }\n }\n\n if (\n pad.type === \"pcb_plated_hole\" &&\n \"rect_pad_width\" in pad &&\n \"rect_pad_height\" in pad\n ) {\n return getRotatedRectPoints({\n x: pad.x,\n y: pad.y,\n width: pad.rect_pad_width,\n height: pad.rect_pad_height,\n ccwRotation:\n \"rect_ccw_rotation\" in pad && typeof pad.rect_ccw_rotation === \"number\"\n ? pad.rect_ccw_rotation\n : 0,\n })\n }\n\n throw new Error(\n `Expected polygonal pad geometry, got ${pad.type} with shape \"${pad.shape}\"`,\n )\n}\n\nconst getPolygonEdges = (points: Point[]) =>\n points.map(\n (point, index) => [point, points[(index + 1) % points.length]!] as const,\n )\n\nconst getClosestPointsBetweenSegments = (\n a1: Point,\n a2: Point,\n b1: Point,\n b2: Point,\n) => {\n const intersection = getSegmentIntersection(a1, a2, b1, b2)\n if (intersection) {\n return {\n distance: 0,\n pointOnA: intersection,\n pointOnB: intersection,\n center: intersection,\n }\n }\n\n const candidates = [\n { pointOnA: a1, pointOnB: pointToSegmentClosestPoint(a1, b1, b2) },\n { pointOnA: a2, pointOnB: pointToSegmentClosestPoint(a2, b1, b2) },\n { pointOnA: pointToSegmentClosestPoint(b1, a1, a2), pointOnB: b1 },\n { pointOnA: pointToSegmentClosestPoint(b2, a1, a2), pointOnB: b2 },\n ]\n\n let best = candidates[0]!\n let bestDistanceSquared = distSq(best.pointOnA, best.pointOnB)\n for (const candidate of candidates.slice(1)) {\n const candidateDistanceSquared = distSq(\n candidate.pointOnA,\n candidate.pointOnB,\n )\n if (candidateDistanceSquared < bestDistanceSquared) {\n best = candidate\n bestDistanceSquared = candidateDistanceSquared\n }\n }\n\n return {\n distance: segmentToSegmentMinDistance(a1, a2, b1, b2),\n pointOnA: best.pointOnA,\n pointOnB: best.pointOnB,\n center: {\n x: (best.pointOnA.x + best.pointOnB.x) / 2,\n y: (best.pointOnA.y + best.pointOnB.y) / 2,\n },\n }\n}\n\nexport const getSegmentToPolygonClearanceFromPoints = (\n start: Point,\n end: Point,\n polygon: Point[],\n) => {\n if (polygon.length < 3) {\n return {\n distance: Number.POSITIVE_INFINITY,\n center: start,\n tracePoint: start,\n obstaclePoint: start,\n }\n }\n\n const intersections = getPolygonEdges(polygon)\n .map(([edgeStart, edgeEnd]) =>\n getSegmentIntersection(start, end, edgeStart, edgeEnd),\n )\n .filter((point): point is Point => point !== null)\n\n if (intersections.length > 0) {\n const dx = end.x - start.x\n const dy = end.y - start.y\n const lengthSquared = dx * dx + dy * dy\n intersections.sort((a, b) => {\n const ta = ((a.x - start.x) * dx + (a.y - start.y) * dy) / lengthSquared\n const tb = ((b.x - start.x) * dx + (b.y - start.y) * dy) / lengthSquared\n return ta - tb\n })\n\n return {\n distance: 0,\n center: intersections[0]!,\n tracePoint: intersections[0]!,\n obstaclePoint: intersections[0]!,\n }\n }\n\n if (\n isPointInsidePolygon(start, polygon) ||\n isPointInsidePolygon(end, polygon)\n ) {\n const center = {\n x: (start.x + end.x) / 2,\n y: (start.y + end.y) / 2,\n }\n return {\n distance: 0,\n center,\n tracePoint: center,\n obstaclePoint: center,\n }\n }\n\n let best = getClosestPointsBetweenSegments(\n start,\n end,\n polygon[0]!,\n polygon[1]!,\n )\n\n for (const [edgeStart, edgeEnd] of getPolygonEdges(polygon).slice(1)) {\n const candidate = getClosestPointsBetweenSegments(\n start,\n end,\n edgeStart,\n edgeEnd,\n )\n if (candidate.distance < best.distance) best = candidate\n }\n\n return {\n distance: best.distance,\n center: best.center,\n tracePoint: best.pointOnA,\n obstaclePoint: best.pointOnB,\n }\n}\n\nexport const getSegmentToPolygonClearance = (\n segment: PcbTraceSegment,\n polygon: Point[],\n) =>\n getSegmentToPolygonClearanceFromPoints(\n { x: segment.x1, y: segment.y1 },\n { x: segment.x2, y: segment.y2 },\n polygon,\n )\n\nexport const getSegmentToPillClearance = (\n segment: Pick<PcbTraceSegment, \"x1\" | \"y1\" | \"x2\" | \"y2\">,\n pad: PillPad,\n) => {\n const pill = getPillCenterLineForPad(pad)\n const closest = getClosestPointsBetweenSegments(\n { x: segment.x1, y: segment.y1 },\n { x: segment.x2, y: segment.y2 },\n pill.start,\n pill.end,\n )\n\n return {\n distance: closest.distance,\n center: closest.center,\n radius: pill.radius,\n tracePoint: closest.pointOnA,\n obstaclePoint: closest.pointOnB,\n }\n}\n","import type {\n PcbPort,\n PcbTrace,\n AnyCircuitElement,\n PcbSmtPad,\n} from \"circuit-json\"\nimport { isPointInPad } from \"lib/check-traces-are-contiguous/is-point-in-pad\"\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 } else if (pad.shape === \"pill\" || pad.shape === \"rotated_pill\") {\n return isPointInPad(point, pad)\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 { createIndexedPcbConnectivityMap } from \"lib/util/create-indexed-pcb-connectivity-map\"\nimport type {\n PcbPort,\n SourceTrace,\n AnyCircuitElement,\n PcbPortNotConnectedError,\n SourceNet,\n} from \"circuit-json\"\nimport { addStartAndEndPortIdsIfMissing } from \"./add-start-and-end-port-ids-if-missing\"\nimport {\n getFullConnectivityMapFromCircuitJson,\n type PcbConnectivityMap,\n type ConnectivityMap,\n} from \"circuit-json-to-connectivity-map\"\nimport { getReadableNameForPort } from \"./util/get-readable-names\"\nimport { getCopperPourConnectivity } from \"./copper-pour-connectivity/get-copper-pour-connectivity\"\n\nfunction checkEachPcbPortConnectedToPcbTraces(\n circuitJson: AnyCircuitElement[],\n {\n connMap,\n pcbConnectivityMap,\n }: {\n connMap?: ConnectivityMap\n pcbConnectivityMap?: PcbConnectivityMap\n } = {},\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 const sourceNets: SourceNet[] = circuitJson.filter(\n (item) => item.type === \"source_net\",\n ) as SourceNet[]\n\n const errors: PcbPortNotConnectedError[] = []\n\n // Generate the connectivity map from the circuit\n const connectivityMap =\n connMap ?? getFullConnectivityMapFromCircuitJson(circuitJson)\n pcbConnectivityMap ??= createIndexedPcbConnectivityMap(circuitJson)\n let pourConnectivity: ReturnType<typeof getCopperPourConnectivity> | undefined\n const getPourConnectivity = () =>\n (pourConnectivity ??= getCopperPourConnectivity(\n circuitJson,\n connectivityMap,\n ))\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 const sourceNetNameById = new Map(\n sourceNets.map((sourceNet) => [sourceNet.source_net_id, sourceNet.name]),\n )\n\n // Process each source trace\n for (const sourceTrace of sourceTraces) {\n const connectedSourcePortIds = sourceTrace.connected_source_port_ids\n\n if (\n connectedSourcePortIds.length === 1 &&\n sourceTrace.connected_source_net_ids.length > 0\n ) {\n const pcbPort = sourcePortToPcbPort.get(connectedSourcePortIds[0])\n if (!pcbPort) continue\n\n const connectedPcbTraces = pcbConnectivityMap.getAllTracesConnectedToPort(\n pcbPort.pcb_port_id,\n )\n\n if (\n connectedPcbTraces.length === 0 &&\n !getPourConnectivity().isPortConnectedToNet(\n pcbPort.pcb_port_id,\n sourceTrace.connected_source_net_ids,\n )\n ) {\n const connectedNetNames = sourceTrace.connected_source_net_ids\n .map((sourceNetId) => sourceNetNameById.get(sourceNetId))\n .filter((name): name is string => Boolean(name))\n const netDescription =\n connectedNetNames.length > 0\n ? `net [${connectedNetNames.join(\", \")}]`\n : \"its connected net\"\n\n errors.push({\n type: \"pcb_port_not_connected_error\",\n message: `Port [${getReadableNameForPort(circuitJson, pcbPort.pcb_port_id)}] is not connected to ${netDescription} by a PCB trace.`,\n error_type: \"pcb_port_not_connected_error\",\n pcb_port_ids: [pcbPort.pcb_port_id],\n pcb_component_ids: pcbPort.pcb_component_id\n ? [pcbPort.pcb_component_id]\n : [],\n pcb_port_not_connected_error_id: `pcb_port_not_connected_error_trace_${sourceTrace.source_trace_id}`,\n })\n }\n\n continue\n }\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 (\n pcbTraceIds.length === 0 &&\n !getPourConnectivity().arePortsConnected(\n pcbPortsInTrace.map((port) => port.pcb_port_id),\n )\n ) {\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: `Ports [${pcbPortsInTrace.map((p) => getReadableNameForPort(circuitJson, 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 {\n AnyCircuitElement,\n PcbPlatedHole,\n PcbSmtPad,\n SourceTrace,\n} from \"circuit-json\"\nimport {\n getReadableNameForElement,\n getReadableNameForPcbPort,\n getBoundsOfPcbElements,\n} from \"@tscircuit/circuit-json-util\"\n\nconst CIRCUIT_JSON_ID_PATTERN =\n /\\b(?:pcb|source|schematic|subcircuit)_[a-z0-9_]+\\b/i\n\nconst sanitizeReadableName = (\n candidate: string | null | undefined,\n id: string,\n fallbackLabel: string,\n): string => {\n if (\n !candidate ||\n candidate === id ||\n CIRCUIT_JSON_ID_PATTERN.test(candidate)\n ) {\n return fallbackLabel\n }\n return candidate\n}\n\nconst firstReadableName = (\n candidates: Array<string | null | undefined>,\n id: string,\n): string => {\n for (const candidate of candidates) {\n const readableName = sanitizeReadableName(candidate, id, \"\")\n if (readableName) return readableName\n }\n return \"\"\n}\n\nexport const getReadableNameForComponent = (\n circuitJson: AnyCircuitElement[],\n pcbComponentId: string,\n): string =>\n sanitizeReadableName(\n getReadableNameForElement(circuitJson, pcbComponentId),\n pcbComponentId,\n \"component\",\n )\n\nexport const getReadableNameForPort = (\n circuitJson: AnyCircuitElement[],\n pcbPortId: string,\n): string => {\n const pcbPort = circuitJson.find(\n (element) =>\n element.type === \"pcb_port\" && element.pcb_port_id === pcbPortId,\n )\n\n if (pcbPort?.type === \"pcb_port\") {\n const sourcePort = circuitJson.find(\n (element) =>\n element.type === \"source_port\" &&\n element.source_port_id === pcbPort.source_port_id,\n )\n\n const sourceComponent =\n sourcePort?.type === \"source_port\"\n ? circuitJson.find(\n (element) =>\n element.type === \"source_component\" &&\n element.source_component_id === sourcePort.source_component_id,\n )\n : null\n\n const readableSourceComponentName = firstReadableName(\n [\n sourceComponent?.type === \"source_component\"\n ? sourceComponent.name\n : null,\n ],\n sourceComponent?.type === \"source_component\"\n ? sourceComponent.source_component_id\n : \"\",\n )\n\n const readableSourcePortName = firstReadableName(\n [\n sourcePort?.type === \"source_port\" ? sourcePort.name : null,\n sourcePort?.type === \"source_port\"\n ? sourcePort.pin_number?.toString()\n : null,\n sourcePort?.type === \"source_port\" ? sourcePort.port_hints?.[0] : null,\n ],\n sourcePort?.type === \"source_port\" ? sourcePort.source_port_id : \"\",\n )\n\n if (readableSourceComponentName && readableSourcePortName) {\n return `${readableSourceComponentName}.${readableSourcePortName}`\n }\n if (readableSourcePortName) {\n return readableSourcePortName\n }\n }\n\n return sanitizeReadableName(\n getReadableNameForPcbPort(circuitJson, pcbPortId) ??\n getReadableNameForElement(circuitJson, pcbPortId),\n pcbPortId,\n \"port\",\n )\n}\n\nexport const getReadableNameForSourceTrace = (\n circuitJson: AnyCircuitElement[],\n sourceTrace: SourceTrace,\n): string => {\n const displayName = sanitizeReadableName(\n sourceTrace.display_name,\n sourceTrace.source_trace_id,\n \"\",\n )\n if (displayName) return displayName\n\n const connectedPortNames = (sourceTrace.connected_source_port_ids ?? [])\n .map((sourcePortId) => {\n const pcbPort = circuitJson.find(\n (element) =>\n element.type === \"pcb_port\" &&\n element.source_port_id === sourcePortId,\n )\n\n if (pcbPort?.type === \"pcb_port\") {\n return getReadableNameForPort(circuitJson, pcbPort.pcb_port_id)\n }\n\n const sourcePort = circuitJson.find(\n (element) =>\n element.type === \"source_port\" &&\n element.source_port_id === sourcePortId,\n )\n if (sourcePort?.type !== \"source_port\") return null\n\n const sourceComponent = circuitJson.find(\n (element) =>\n element.type === \"source_component\" &&\n element.source_component_id === sourcePort.source_component_id,\n )\n\n const sourceComponentName =\n sourceComponent?.type === \"source_component\"\n ? sanitizeReadableName(\n sourceComponent.name,\n sourceComponent.source_component_id,\n \"\",\n )\n : \"\"\n\n const sourcePortName = firstReadableName(\n [\n sourcePort.name,\n sourcePort.pin_number?.toString(),\n sourcePort.port_hints?.[0],\n ],\n sourcePort.source_port_id,\n )\n\n if (sourceComponentName && sourcePortName) {\n return `${sourceComponentName}.${sourcePortName}`\n }\n\n return sourcePortName || null\n })\n .filter((name): name is string => Boolean(name))\n\n if (connectedPortNames.length >= 2) {\n return `${connectedPortNames[0]} to ${connectedPortNames[1]}`\n }\n\n if (connectedPortNames.length === 1) {\n return `trace connected to ${connectedPortNames[0]}`\n }\n\n return `trace ${sourceTrace.source_trace_id}`\n}\n\nexport const getReadableNameForElementId = (\n circuitJson: AnyCircuitElement[],\n elementId: string,\n): string =>\n sanitizeReadableName(\n getReadableNameForElement(circuitJson, elementId),\n elementId,\n \"element\",\n )\n\nexport const getReadableNameForGroup = (\n circuitJson: AnyCircuitElement[],\n groupId: string,\n): string =>\n sanitizeReadableName(\n getReadableNameForElement(circuitJson, groupId),\n groupId,\n \"group\",\n )\n\nexport const containsCircuitJsonId = (message: string): boolean =>\n CIRCUIT_JSON_ID_PATTERN.test(message)\n\nexport function getReadableNameForFootprintPad(\n circuitJson: AnyCircuitElement[],\n pad: PcbSmtPad | PcbPlatedHole,\n ordinal: number,\n): string {\n const padKind = pad.type === \"pcb_smtpad\" ? \"SMD pad\" : \"through-hole pad\"\n const portRef = pad.pcb_port_id\n ? getReadableNameForPort(circuitJson, pad.pcb_port_id)\n : null\n const bounds = getBoundsOfPcbElements([pad])\n const centerX = (bounds.minX + bounds.maxX) / 2\n const centerY = (bounds.minY + bounds.maxY) / 2\n const location = `(${centerX.toFixed(2)}mm, ${centerY.toFixed(2)}mm)`\n\n if (portRef) return `${padKind} ${portRef} at ${location}`\n return `${padKind} #${ordinal + 1} at ${location}`\n}\n","import { createCopperPolygonContactTester } from \"./create-copper-polygon-contact-tester\"\nimport type { Polygon } from \"@flatten-js/core\"\nimport type {\n AnyCircuitElement,\n LayerRef,\n PcbPort,\n SourceNet,\n} from \"circuit-json\"\nimport type { ConnectivityMap } from \"circuit-json-to-connectivity-map\"\nimport {\n getPrimaryId,\n getPlatedHolePolygon,\n getPourPolygon,\n getSmtPadPolygon,\n getTraceSegmentPolygon,\n getViaPolygon,\n} from \"@tscircuit/circuit-json-util\"\n\ntype NetId = NonNullable<ReturnType<ConnectivityMap[\"getNetConnectedToId\"]>>\ntype PcbPortId = PcbPort[\"pcb_port_id\"]\ninterface Conductor {\n polygon: Polygon\n layers: LayerRef[]\n netId: NetId\n portIds?: PcbPortId[]\n isPour?: boolean\n}\n\n/** Physical pour connectivity in board-world mm (+X right, +Y up).\n * Only touching copper on a common layer forms an edge. Plated pads and vias\n * bridge their emitted layers; logical net membership never joins islands.\n * Constant-width wire copper can connect pours. Interpolated traces and inline\n * via inference are left to the existing trace checks; emitted barrels bridge layers.\n */\nexport function getCopperPourConnectivity(\n circuitJson: AnyCircuitElement[],\n connectivity: ConnectivityMap,\n) {\n // Scale before geometric predicates to preserve tiny edges in solver BReps.\n const scale = 1e6\n const tolerance = 1e-7 * scale\n const copperPolygonsTouch = createCopperPolygonContactTester(tolerance)\n const conductors: Conductor[] = []\n const pouredNets = new Set<NetId>()\n const netForId = (id: string) => connectivity.getNetConnectedToId(id)\n const add = (conductor: Conductor) => {\n if (!conductor.polygon.isEmpty()) {\n conductors.push({\n ...conductor,\n polygon: conductor.polygon.scale(scale, scale),\n })\n }\n }\n for (const pour of circuitJson) {\n if (pour.type !== \"pcb_copper_pour\" || !pour.source_net_id) continue\n const netId = netForId(pour.source_net_id)\n if (!netId) continue\n pouredNets.add(netId)\n add({\n polygon: getPourPolygon(pour),\n layers: [pour.layer],\n netId,\n isPour: true,\n })\n }\n const components = new Map(\n circuitJson\n .filter((e) => e.type === \"pcb_component\")\n .map((e) => [e.pcb_component_id, e]),\n )\n if (pouredNets.size > 0) {\n for (const copper of circuitJson) {\n if (copper.type === \"pcb_trace\") {\n const netId = netForId(copper.pcb_trace_id)\n if (\n !netId ||\n !pouredNets.has(netId) ||\n copper.route_thickness_mode === \"interpolated\"\n )\n continue\n for (let i = 0; i < copper.route.length - 1; i++) {\n const start = copper.route[i]\n const end = copper.route[i + 1]\n if (\n start.route_type !== \"wire\" ||\n end.route_type !== \"wire\" ||\n start.layer !== end.layer\n )\n continue\n add({\n polygon: getTraceSegmentPolygon(start, end, start.width),\n layers: [start.layer],\n netId,\n })\n }\n continue\n }\n if (\n copper.type !== \"pcb_smtpad\" &&\n copper.type !== \"pcb_plated_hole\" &&\n copper.type !== \"pcb_via\"\n )\n continue\n const netId = netForId(getPrimaryId(copper))\n if (!netId || !pouredNets.has(netId)) continue\n if (copper.type === \"pcb_smtpad\") {\n add({\n polygon: getSmtPadPolygon(copper),\n layers: [copper.layer],\n netId,\n portIds: copper.pcb_port_id ? [copper.pcb_port_id] : [],\n })\n } else if (copper.type === \"pcb_plated_hole\") {\n add({\n polygon: getPlatedHolePolygon(\n copper,\n copper.pcb_component_id\n ? components.get(copper.pcb_component_id)?.rotation\n : 0,\n ),\n layers: copper.layers,\n netId,\n portIds: copper.pcb_port_id ? [copper.pcb_port_id] : [],\n })\n } else {\n add({\n polygon: getViaPolygon(\n copper,\n copper.outer_diameter,\n copper.hole_diameter,\n ),\n layers: copper.layers,\n netId,\n portIds: copper.pcb_port_ids,\n })\n }\n }\n }\n\n const parent = conductors.map((_, i) => i)\n const find = (i: number): number => {\n while (parent[i] !== i) {\n parent[i] = parent[parent[i]]\n i = parent[i]\n }\n return i\n }\n const bounds = conductors.map((c) => c.polygon.box)\n const order = conductors\n .map((_, i) => i)\n .sort((a, b) => bounds[a].xmin - bounds[b].xmin)\n for (let a = 0; a < order.length; a++) {\n const i = order[a]\n for (let b = a + 1; b < order.length; b++) {\n const j = order[b]\n if (bounds[j].xmin > bounds[i].xmax + tolerance) break\n if (find(i) === find(j) || conductors[i].netId !== conductors[j].netId)\n continue\n if (\n bounds[j].ymin > bounds[i].ymax + tolerance ||\n bounds[j].ymax < bounds[i].ymin - tolerance\n )\n continue\n if (\n !conductors[i].layers.some((layer) =>\n conductors[j].layers.includes(layer),\n )\n )\n continue\n if (copperPolygonsTouch(conductors[i].polygon, conductors[j].polygon))\n parent[find(j)] = find(i)\n }\n }\n const pourRoots = new Set(\n conductors.flatMap((c, i) => (c.isPour ? [find(i)] : [])),\n )\n const rootsByPort = new Map<PcbPortId, Set<number>>()\n for (const [i, conductor] of conductors.entries()) {\n if (!pourRoots.has(find(i))) continue\n for (const portId of conductor.portIds ?? []) {\n const roots = rootsByPort.get(portId) ?? new Set<number>()\n roots.add(find(i))\n rootsByPort.set(portId, roots)\n }\n }\n const portsByNet = new Map<NetId, PcbPortId[]>()\n for (const port of circuitJson) {\n if (port.type !== \"pcb_port\") continue\n const netId = netForId(port.pcb_port_id)\n if (!netId || !pouredNets.has(netId)) continue\n const ports = portsByNet.get(netId) ?? []\n ports.push(port.pcb_port_id)\n portsByNet.set(netId, ports)\n }\n return {\n isPortConnectedToNet(\n portId: PcbPortId,\n sourceNetIds: SourceNet[\"source_net_id\"][],\n ) {\n const roots = rootsByPort.get(portId)\n return sourceNetIds.every((id) =>\n [...(roots ?? [])].some(\n (root) =>\n conductors[root].netId === netForId(id) &&\n // Distinct same-net islands are not a physical connection.\n (portsByNet.get(conductors[root].netId) ?? []).every((peer) =>\n rootsByPort.get(peer)?.has(root),\n ),\n ),\n )\n },\n arePortsConnected(portIds: PcbPortId[]) {\n if (portIds.length < 2) return false\n return [...(rootsByPort.get(portIds[0]) ?? [])].some((root) =>\n portIds.every((id) => rootsByPort.get(id)?.has(root)),\n )\n },\n }\n}\n","import { cju, getReadableNameForElement } from \"@tscircuit/circuit-json-util\"\nimport { getPrimaryId } from \"@tscircuit/circuit-json-util\"\nimport {\n segmentToBoundsMinDistance,\n segmentToCircleMinDistance,\n} from \"@tscircuit/math-utils\"\nimport { segmentToSegmentMinDistance } from \"@tscircuit/math-utils\"\nimport type {\n AnyCircuitElement,\n PcbPlatedHole,\n PcbPort,\n PcbSmtPad,\n PcbTraceError,\n PcbKeepoutOverlapWarning,\n} from \"circuit-json\"\nimport {\n type ConnectivityMap,\n getFullConnectivityMapFromCircuitJson,\n} from \"circuit-json-to-connectivity-map\"\nimport { addStartAndEndPortIdsIfMissing } from \"lib/add-start-and-end-port-ids-if-missing\"\nimport {\n getTraceObstacleClearance,\n isTraceObstacleOverlap,\n} from \"lib/check-pad-clearance/common\"\nimport {\n type Bounds,\n SpatialObjectIndex,\n} from \"lib/data-structures/SpatialIndex\"\nimport {\n DEFAULT_TRACE_MARGIN,\n DEFAULT_TRACE_THICKNESS,\n EPSILON,\n getBoardDrcValue,\n getPcbBoard,\n} from \"lib/drc-defaults\"\nimport { getLayersOfPcbElement } from \"../util/getLayersOfPcbElement\"\nimport { getClosestPointBetweenSegmentAndBounds } from \"./getClosestPointBetweenSegmentAndBounds\"\nimport { getClosestPointBetweenSegments } from \"./getClosestPointBetweenSegments\"\nimport {\n type Collidable,\n type PcbTraceSegment,\n getCollidableBounds,\n} from \"./getCollidableBounds\"\nimport { getPcbPortIdsConnectedToTraces } from \"./getPcbPortIdsConnectedToTraces\"\nimport { getRadiusOfCircuitJsonElement } from \"./getRadiusOfCircuitJsonElement\"\n\ntype PcbComponentConnectionElement = PcbPort | PcbSmtPad | PcbPlatedHole\n\nconst getPcbComponentConnectionElementId = (\n element: PcbComponentConnectionElement,\n): string => {\n if (element.type === \"pcb_port\") return element.pcb_port_id\n if (element.type === \"pcb_smtpad\") return element.pcb_smtpad_id\n return element.pcb_plated_hole_id\n}\n\nexport function checkEachPcbTraceNonOverlapping(\n circuitJson: AnyCircuitElement[],\n {\n connMap,\n minClearance,\n }: {\n connMap?: ConnectivityMap\n minClearance?: number\n } = {},\n): (PcbTraceError | PcbKeepoutOverlapWarning)[] {\n const errors: (PcbTraceError | PcbKeepoutOverlapWarning)[] = []\n addStartAndEndPortIdsIfMissing(circuitJson)\n connMap ??= getFullConnectivityMapFromCircuitJson(circuitJson)\n const board = getPcbBoard(circuitJson)\n minClearance ??=\n getBoardDrcValue(board, \"min_trace_to_pad_edge_clearance\") ??\n DEFAULT_TRACE_MARGIN\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 pcbPorts = cju(circuitJson).pcb_port.list()\n const pcbHoles = cju(circuitJson).pcb_hole.list()\n const pcbVias = cju(circuitJson).pcb_via.list()\n const pcbKeepouts = cju(circuitJson)\n .pcb_keepout.list()\n .filter((keepout) => !keepout.allow_traces)\n\n const pcbComponentConnectionElements: PcbComponentConnectionElement[] = [\n ...pcbPorts,\n ...pcbSmtPads,\n ...pcbPlatedHoles,\n ]\n const excludedConnectionIdsByKeepoutId = new Map<string, string[]>()\n for (const keepout of pcbKeepouts) {\n const excludedPcbComponentIds = new Set(\n keepout.excluded_pcb_component_ids ?? [],\n )\n if (excludedPcbComponentIds.size === 0) continue\n\n excludedConnectionIdsByKeepoutId.set(\n keepout.pcb_keepout_id,\n pcbComponentConnectionElements\n .filter(\n (element) =>\n element.pcb_component_id &&\n excludedPcbComponentIds.has(element.pcb_component_id),\n )\n .map(getPcbComponentConnectionElementId),\n )\n }\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 constructErrorMessage = (\n traceName: string,\n otherName: string,\n gap: number,\n ) => {\n if (isTraceObstacleOverlap(gap)) {\n return `PCB trace ${traceName} overlaps with ${otherName} (accidental contact)`\n }\n\n return `PCB trace ${traceName} is too close to ${otherName} (gap: ${gap.toFixed(3)}mm)`\n }\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 = minClearance\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 (\n obj.type === \"pcb_keepout\" &&\n (excludedConnectionIdsByKeepoutId.get(obj.pcb_keepout_id) ?? []).some(\n (connectionId) =>\n connMap.areIdsConnected(segmentA.pcb_trace_id, connectionId),\n )\n ) {\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 > minClearance - 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: constructErrorMessage(\n getReadableName(segmentA.pcb_trace_id),\n getReadableName(segmentB.pcb_trace_id),\n gap,\n ),\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 if (\n obj.type === \"pcb_smtpad\" ||\n obj.type === \"pcb_plated_hole\" ||\n obj.type === \"pcb_via\"\n ) {\n const { gap, center } = getTraceObstacleClearance(segmentA, obj)\n if (!isTraceObstacleOverlap(gap)) 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: constructErrorMessage(\n getReadableName(segmentA.pcb_trace_id),\n `${obj.type} \"${getReadableName(primaryObjId)}\"`,\n gap,\n ),\n pcb_trace_id: segmentA.pcb_trace_id,\n center,\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 continue\n }\n\n const isCircular = obj.type === \"pcb_hole\"\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 > minClearance - 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: constructErrorMessage(\n getReadableName(segmentA.pcb_trace_id),\n `${obj.type} \"${getReadableName(getPrimaryId(obj))}\"`,\n gap,\n ),\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 if (obj.type === \"pcb_keepout\" && obj.warning_only) {\n errors.push({\n type: \"pcb_keepout_overlap_warning\",\n warning_type: \"pcb_keepout_overlap_warning\",\n pcb_keepout_overlap_warning_id: `pcb_keepout_overlap_warning_${pcb_trace_error_id}`,\n pcb_keepout_id: obj.pcb_keepout_id,\n pcb_trace_ids: [segmentA.pcb_trace_id],\n message: `PCB trace ${getReadableName(segmentA.pcb_trace_id)} violates advisory PCB keepout \"${obj.description ?? obj.pcb_keepout_id}\"`,\n center: getClosestPointBetweenSegmentAndBounds(\n segmentA,\n getCollidableBounds(obj),\n ),\n subcircuit_id:\n segmentA._pcbTrace.subcircuit_id ?? obj.subcircuit_id,\n })\n continue\n }\n errors.push({\n type: \"pcb_trace_error\",\n error_type: \"pcb_trace_error\",\n message: constructErrorMessage(\n getReadableName(segmentA.pcb_trace_id),\n `${obj.type} \"${getReadableName(getPrimaryId(obj))}\"`,\n gap,\n ),\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","import {\n cju,\n distanceBetweenCircleAndCircle,\n distanceBetweenCircleAndPolygon,\n distanceBetweenPolygonAndPolygon,\n getBoundsOfPcbElements,\n} from \"@tscircuit/circuit-json-util\"\nimport {\n midpoint,\n pointToSegmentClosestPoint,\n segmentToCircleMinDistance,\n segmentToSegmentMinDistance,\n} from \"@tscircuit/math-utils\"\nimport type {\n AnyCircuitElement,\n PCBKeepout,\n PcbPlatedHole,\n PcbSmtPad,\n PcbTrace,\n PcbVia,\n} from \"circuit-json\"\nimport type { PcbTraceSegment } from \"lib/check-each-pcb-trace-non-overlapping/getCollidableBounds\"\nimport {\n getPillCenterLineForPad,\n getPolygonPointsForPad,\n getSegmentToPillClearance,\n getSegmentToPolygonClearanceFromPoints,\n} from \"lib/check-each-pcb-trace-non-overlapping/segment-to-polygon-clearance\"\nimport type { Bounds } from \"lib/data-structures/SpatialIndex\"\nimport { DEFAULT_TRACE_THICKNESS } from \"lib/drc-defaults\"\n\nexport type PadElement = PcbSmtPad | PcbPlatedHole\nexport type PadClearanceElement = PadElement | PcbVia\nexport type CopperClearanceElement = PadClearanceElement | PCBKeepout\n\nexport const getPadBounds = (pad: CopperClearanceElement): Bounds => {\n if (pad.type === \"pcb_keepout\") {\n if (pad.shape === \"outline\") {\n return {\n minX: Math.min(...pad.outline.map((point) => point.x)),\n minY: Math.min(...pad.outline.map((point) => point.y)),\n maxX: Math.max(...pad.outline.map((point) => point.x)),\n maxY: Math.max(...pad.outline.map((point) => point.y)),\n }\n }\n\n if (pad.shape === \"circle\") {\n return {\n minX: pad.center.x - pad.radius,\n minY: pad.center.y - pad.radius,\n maxX: pad.center.x + pad.radius,\n maxY: pad.center.y + pad.radius,\n }\n }\n\n return {\n minX: pad.center.x - pad.width / 2,\n minY: pad.center.y - pad.height / 2,\n maxX: pad.center.x + pad.width / 2,\n maxY: pad.center.y + pad.height / 2,\n }\n }\n\n return getBoundsOfPcbElements([pad])\n}\n\nexport const getPadCenter = (pad: CopperClearanceElement) => {\n if (pad.type === \"pcb_keepout\" && pad.shape !== \"outline\") return pad.center\n const bounds = getPadBounds(pad)\n return midpoint(\n { x: bounds.minX, y: bounds.minY },\n { x: bounds.maxX, y: bounds.maxY },\n )\n}\n\nexport const getPadRadius = (pad: CopperClearanceElement) => {\n if (pad.type === \"pcb_keepout\" && pad.shape === \"circle\") return pad.radius\n const bounds = getPadBounds(pad)\n return Math.min(bounds.maxX - bounds.minX, bounds.maxY - bounds.minY) / 2\n}\n\nexport const isCircularPad = (pad: CopperClearanceElement) =>\n pad.type === \"pcb_via\" || pad.shape === \"circle\"\n\nconst isPillPad = (\n pad: CopperClearanceElement,\n): pad is\n | Extract<PcbSmtPad, { shape: \"pill\" | \"rotated_pill\" }>\n | Extract<PcbPlatedHole, { shape: \"oval\" | \"pill\" }> =>\n (pad.type === \"pcb_smtpad\" &&\n (pad.shape === \"pill\" || pad.shape === \"rotated_pill\")) ||\n (pad.type === \"pcb_plated_hole\" &&\n (pad.shape === \"oval\" || pad.shape === \"pill\"))\n\nconst getCircleShape = (pad: CopperClearanceElement) => {\n const center = getPadCenter(pad)\n return {\n kind: \"circle\" as const,\n x: center.x,\n y: center.y,\n radius: getPadRadius(pad),\n }\n}\n\nconst getPolygonShape = (pad: CopperClearanceElement) => {\n if (pad.type === \"pcb_keepout\") {\n if (pad.shape === \"outline\") {\n return {\n kind: \"polygon\" as const,\n points: pad.outline,\n }\n }\n\n if (pad.shape !== \"rect\") {\n throw new Error(`Expected rectangular keepout, got ${pad.shape}`)\n }\n\n return {\n kind: \"polygon\" as const,\n points: [\n {\n x: pad.center.x - pad.width / 2,\n y: pad.center.y - pad.height / 2,\n },\n {\n x: pad.center.x + pad.width / 2,\n y: pad.center.y - pad.height / 2,\n },\n {\n x: pad.center.x + pad.width / 2,\n y: pad.center.y + pad.height / 2,\n },\n {\n x: pad.center.x - pad.width / 2,\n y: pad.center.y + pad.height / 2,\n },\n ],\n }\n }\n\n if (\n pad.type === \"pcb_smtpad\" &&\n (pad.shape === \"polygon\" || pad.shape === \"rotated_rect\")\n ) {\n return {\n kind: \"polygon\" as const,\n points: getPolygonPointsForPad(pad),\n }\n }\n\n if (\n pad.type === \"pcb_plated_hole\" &&\n \"rect_pad_width\" in pad &&\n \"rect_pad_height\" in pad\n ) {\n return {\n kind: \"polygon\" as const,\n points: getPolygonPointsForPad(pad),\n }\n }\n\n const bounds = getPadBounds(pad)\n return {\n kind: \"polygon\" as const,\n points: [\n { x: bounds.minX, y: bounds.minY },\n { x: bounds.maxX, y: bounds.minY },\n { x: bounds.maxX, y: bounds.maxY },\n { x: bounds.minX, y: bounds.maxY },\n ],\n }\n}\n\n// A rounded rectangle is an inset rectangle expanded by corner_radius.\n// At the maximum radius its inset collapses, so use the existing pill geometry.\nconst getRoundedPadCore = (pad: CopperClearanceElement) => {\n if (\n pad.type !== \"pcb_smtpad\" ||\n (pad.shape !== \"rect\" && pad.shape !== \"rotated_rect\") ||\n !pad.corner_radius ||\n pad.corner_radius <= 0\n )\n return null\n\n const radius = Math.min(pad.corner_radius, pad.width / 2, pad.height / 2)\n if (radius === Math.min(pad.width, pad.height) / 2) {\n const core: PcbSmtPad = {\n ...pad,\n shape: \"rotated_pill\",\n radius,\n ccw_rotation: pad.shape === \"rotated_rect\" ? pad.ccw_rotation : 0,\n }\n return { core, radius: 0 }\n }\n return {\n core: {\n ...pad,\n width: pad.width - 2 * radius,\n height: pad.height - 2 * radius,\n corner_radius: 0,\n },\n radius,\n }\n}\n\nexport const getPadToPadGap = (\n padA: CopperClearanceElement,\n padB: CopperClearanceElement,\n): number => {\n const roundedA = getRoundedPadCore(padA)\n const roundedB = getRoundedPadCore(padB)\n if (roundedA || roundedB) {\n return (\n getPadToPadGap(roundedA?.core ?? padA, roundedB?.core ?? padB) -\n (roundedA?.radius ?? 0) -\n (roundedB?.radius ?? 0)\n )\n }\n if (isPillPad(padA) && isPillPad(padB)) {\n const pillA = getPillCenterLineForPad(padA)\n const pillB = getPillCenterLineForPad(padB)\n return (\n segmentToSegmentMinDistance(\n pillA.start,\n pillA.end,\n pillB.start,\n pillB.end,\n ) -\n pillA.radius -\n pillB.radius\n )\n }\n\n if (isPillPad(padA) && isCircularPad(padB)) {\n const pill = getPillCenterLineForPad(padA)\n return (\n segmentToCircleMinDistance(pill.start, pill.end, getCircleShape(padB)) -\n pill.radius\n )\n }\n\n if (isCircularPad(padA) && isPillPad(padB)) {\n const pill = getPillCenterLineForPad(padB)\n return (\n segmentToCircleMinDistance(pill.start, pill.end, getCircleShape(padA)) -\n pill.radius\n )\n }\n\n if (isPillPad(padA)) {\n const pill = getPillCenterLineForPad(padA)\n return (\n getSegmentToPolygonClearanceFromPoints(\n pill.start,\n pill.end,\n getPolygonShape(padB).points,\n ).distance - pill.radius\n )\n }\n\n if (isPillPad(padB)) {\n const pill = getPillCenterLineForPad(padB)\n return (\n getSegmentToPolygonClearanceFromPoints(\n pill.start,\n pill.end,\n getPolygonShape(padA).points,\n ).distance - pill.radius\n )\n }\n\n if (isCircularPad(padA) && isCircularPad(padB)) {\n return distanceBetweenCircleAndCircle(\n getCircleShape(padA),\n getCircleShape(padB),\n )\n }\n\n if (isCircularPad(padA)) {\n return distanceBetweenCircleAndPolygon(\n getCircleShape(padA),\n getPolygonShape(padB),\n )\n }\n\n if (isCircularPad(padB)) {\n return distanceBetweenCircleAndPolygon(\n getCircleShape(padB),\n getPolygonShape(padA),\n )\n }\n\n return distanceBetweenPolygonAndPolygon(\n getPolygonShape(padA),\n getPolygonShape(padB),\n )\n}\n\nexport const getPads = (circuitJson: AnyCircuitElement[]) =>\n [\n ...cju(circuitJson).pcb_smtpad.list(),\n ...cju(circuitJson).pcb_plated_hole.list(),\n ] as PadElement[]\n\nexport const getTraceSegments = (\n circuitJson: AnyCircuitElement[],\n): PcbTraceSegment[] => {\n const pcbTraces = cju(circuitJson).pcb_trace.list()\n\n return pcbTraces.flatMap((pcbTrace) => {\n const segments: PcbTraceSegment[] = []\n\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\n segments.push({\n type: \"pcb_trace_segment\",\n pcb_trace_id: pcbTrace.pcb_trace_id,\n _pcbTrace: pcbTrace as 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 })\n }\n\n return segments\n })\n}\n\nexport type TraceClearanceObstacle = PadElement | PcbVia\n\nconst getCenterBetweenCopperEdges = ({\n tracePoint,\n obstaclePoint,\n traceRadius,\n obstacleRadius,\n}: {\n tracePoint: { x: number; y: number }\n obstaclePoint: { x: number; y: number }\n traceRadius: number\n obstacleRadius: number\n}) => {\n const dx = obstaclePoint.x - tracePoint.x\n const dy = obstaclePoint.y - tracePoint.y\n const distance = Math.hypot(dx, dy)\n if (distance === 0) return midpoint(tracePoint, obstaclePoint)\n\n const unitX = dx / distance\n const unitY = dy / distance\n // For overlapping copper, choose a point in the shared interval. This also\n // handles one circle containing the other without placing the marker outside\n // the smaller shape. A polygon's nearest boundary has obstacleRadius=0.\n if (distance <= traceRadius + obstacleRadius) {\n const overlapStart = Math.max(-traceRadius, distance - obstacleRadius)\n const overlapEnd = Math.min(traceRadius, distance + obstacleRadius)\n const offset = (overlapStart + overlapEnd) / 2\n return {\n x: tracePoint.x + unitX * offset,\n y: tracePoint.y + unitY * offset,\n }\n }\n\n const traceEdge = {\n x: tracePoint.x + unitX * traceRadius,\n y: tracePoint.y + unitY * traceRadius,\n }\n const obstacleEdge = {\n x: obstaclePoint.x - unitX * obstacleRadius,\n y: obstaclePoint.y - unitY * obstacleRadius,\n }\n\n return midpoint(traceEdge, obstacleEdge)\n}\n\nexport const getTraceObstacleClearance = (\n segment: Pick<PcbTraceSegment, \"x1\" | \"y1\" | \"x2\" | \"y2\" | \"thickness\">,\n obstacle: TraceClearanceObstacle,\n): { gap: number; center: { x: number; y: number } } => {\n const rounded = getRoundedPadCore(obstacle)\n if (rounded) obstacle = rounded.core\n const obstacleRadius = rounded?.radius ?? 0\n const start = { x: segment.x1, y: segment.y1 }\n const end = { x: segment.x2, y: segment.y2 }\n const traceRadius = segment.thickness / 2\n\n if (obstacle.type === \"pcb_via\" || isCircularPad(obstacle)) {\n const circle =\n obstacle.type === \"pcb_via\"\n ? {\n x: obstacle.x,\n y: obstacle.y,\n radius: obstacle.outer_diameter / 2,\n }\n : getCircleShape(obstacle)\n const closestPoint = pointToSegmentClosestPoint(circle, start, end)\n\n return {\n gap: segmentToCircleMinDistance(start, end, circle) - traceRadius,\n center: getCenterBetweenCopperEdges({\n tracePoint: closestPoint,\n obstaclePoint: circle,\n traceRadius,\n obstacleRadius: circle.radius,\n }),\n }\n }\n\n if (isPillPad(obstacle)) {\n const clearance = getSegmentToPillClearance(segment, obstacle)\n return {\n gap: clearance.distance - traceRadius - clearance.radius,\n center: getCenterBetweenCopperEdges({\n tracePoint: clearance.tracePoint,\n obstaclePoint: clearance.obstaclePoint,\n traceRadius,\n obstacleRadius: clearance.radius,\n }),\n }\n }\n\n const clearance = getSegmentToPolygonClearanceFromPoints(\n start,\n end,\n getPolygonShape(obstacle).points,\n )\n return {\n gap: clearance.distance - traceRadius - obstacleRadius,\n center: getCenterBetweenCopperEdges({\n tracePoint: clearance.tracePoint,\n obstaclePoint: clearance.obstaclePoint,\n traceRadius,\n obstacleRadius,\n }),\n }\n}\n\nexport const isTraceObstacleOverlap = (gap: number): boolean => gap <= 0\n\n/** A via is a zero-length segment with the width of its outer copper.\n * Use the same nearest-copper geometry as trace clearance markers. */\nexport const getViaPadClearanceCenter = (via: PcbVia, pad: PadElement) =>\n getTraceObstacleClearance(\n {\n x1: via.x,\n y1: via.y,\n x2: via.x,\n y2: via.y,\n thickness: via.outer_diameter,\n },\n pad,\n ).center\n","import type { PcbBoard } from \"circuit-json\"\n\nexport type JlcToleranceMap = Partial<Record<keyof PcbBoard, number>>\n\nexport const jlcMinTolerances: JlcToleranceMap = {\n min_trace_width: 0.1,\n min_via_hole_edge_to_via_hole_edge_clearance: 0.1,\n min_plated_hole_drill_edge_to_drill_edge_clearance: 0.15,\n min_trace_to_pad_edge_clearance: 0.1,\n min_pad_edge_to_pad_edge_clearance: 0.1,\n min_board_edge_clearance: 0.2,\n min_via_hole_diameter: 0.2,\n min_via_pad_diameter: 0.3,\n}\n\n// TODO: Update these values\nexport const jlcPreferredTolerances: JlcToleranceMap = {\n min_trace_width: 0.2,\n min_via_hole_edge_to_via_hole_edge_clearance: 0.2,\n min_plated_hole_drill_edge_to_drill_edge_clearance: 0.2,\n min_trace_to_pad_edge_clearance: 0.2,\n min_pad_edge_to_pad_edge_clearance: 0.2,\n min_board_edge_clearance: 0.2,\n min_via_hole_diameter: 0.4,\n min_via_pad_diameter: 0.6,\n}\n","import { jlcMinTolerances } from \"@tscircuit/jlcpcb-manufacturing-specs\"\nimport type {\n AnyCircuitElement,\n ManufacturingDrcProperties,\n PcbBoard,\n} from \"circuit-json\"\n\nexport const DEFAULT_TRACE_MARGIN = 0.1\nexport const DEFAULT_TRACE_THICKNESS = jlcMinTolerances.min_trace_width\nexport const DEFAULT_VIA_DIAMETER = jlcMinTolerances.min_via_pad_diameter\nexport const DEFAULT_VIA_BOARD_MARGIN =\n jlcMinTolerances.min_board_edge_clearance!\n\nexport const DEFAULT_SAME_NET_VIA_MARGIN =\n jlcMinTolerances.min_via_hole_edge_to_via_hole_edge_clearance!\nexport const DEFAULT_DIFFERENT_NET_VIA_MARGIN =\n jlcMinTolerances.min_via_hole_edge_to_via_hole_edge_clearance!\n\nexport const DEFAULT_PAD_PAD_CLEARANCE =\n jlcMinTolerances.min_pad_edge_to_pad_edge_clearance!\n\nexport const EPSILON = 0.005\n\nexport const getPcbBoard = (\n circuitJson: AnyCircuitElement[],\n): PcbBoard | undefined =>\n circuitJson.find((el): el is PcbBoard => el.type === \"pcb_board\")\n\nexport const getBoardDrcValue = <K extends keyof ManufacturingDrcProperties>(\n board: PcbBoard | undefined,\n key: K,\n): ManufacturingDrcProperties[K] => board?.[key]\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 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","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 { 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 { 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\"\nimport {\n getPillCenterLineForPad,\n getPolygonPointsForPad,\n} from \"./segment-to-polygon-clearance\"\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\n if (\n collidable.type === \"pcb_smtpad\" ||\n collidable.type === \"pcb_plated_hole\"\n ) {\n const isPolygon =\n (collidable.type === \"pcb_smtpad\" &&\n (collidable.shape === \"rotated_rect\" ||\n collidable.shape === \"polygon\")) ||\n (collidable.type === \"pcb_plated_hole\" &&\n \"rect_pad_width\" in collidable &&\n \"rect_pad_height\" in collidable)\n\n if (isPolygon) {\n const polygonPoints = getPolygonPointsForPad(collidable)\n return {\n minX: Math.min(...polygonPoints.map((point) => point.x)),\n minY: Math.min(...polygonPoints.map((point) => point.y)),\n maxX: Math.max(...polygonPoints.map((point) => point.x)),\n maxY: Math.max(...polygonPoints.map((point) => point.y)),\n }\n }\n\n if (\n collidable.type === \"pcb_smtpad\" &&\n collidable.shape === \"rotated_pill\"\n ) {\n const pill = getPillCenterLineForPad(collidable)\n return {\n minX: Math.min(pill.start.x, pill.end.x) - pill.radius,\n minY: Math.min(pill.start.y, pill.end.y) - pill.radius,\n maxX: Math.max(pill.start.x, pill.end.x) + pill.radius,\n maxY: Math.max(pill.start.y, pill.end.y) + pill.radius,\n }\n }\n }\n\n return getBoundsOfPcbElements([collidable as any])\n}\n","import type { PcbTrace } from \"circuit-json\"\n\nexport function getPcbPortIdsConnectedToRoutePoint(\n routePoint: PcbTrace[\"route\"][number],\n) {\n if (routePoint.route_type !== \"wire\") return []\n\n return [routePoint.start_pcb_port_id, routePoint.end_pcb_port_id].filter(\n (portId): portId is string => Boolean(portId),\n )\n}\n\nexport function getPcbPortIdsConnectedToTrace(trace: PcbTrace) {\n const connectedPcbPorts = new Set<string>()\n for (const segment of trace.route) {\n for (const portId of getPcbPortIdsConnectedToRoutePoint(segment)) {\n connectedPcbPorts.add(portId)\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 {\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","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 { getReadableNameForElement } from \"@tscircuit/circuit-json-util\"\nimport type { AnyCircuitElement, PcbPlacementError } from \"circuit-json\"\nimport { checkCopperToBoardEdgeClearance } from \"lib/check-copper-to-board-edge-clearance\"\n\nexport function checkViasOffBoard(\n circuitJson: AnyCircuitElement[],\n): PcbPlacementError[] {\n const vias = circuitJson.filter((element) => element.type === \"pcb_via\")\n const violationsById = new Map(\n checkCopperToBoardEdgeClearance(\n circuitJson.filter(\n (element) => element.type === \"pcb_board\" || element.type === \"pcb_via\",\n ),\n ).map((error) => [\n error.pcb_placement_error_id.replace(\n \"copper_too_close_to_board_edge_\",\n \"\",\n ),\n error,\n ]),\n )\n\n return vias.flatMap((via) => {\n const violation = violationsById.get(via.pcb_via_id)\n if (!violation) return []\n\n const viaName = getReadableNameForElement(circuitJson, via.pcb_via_id)\n return [\n {\n ...violation,\n pcb_placement_error_id: `out_of_board_${via.pcb_via_id}`,\n message: `Via ${viaName} is outside or crossing the board boundary`,\n },\n ]\n })\n}\n","import { jlcMinTolerances } from \"@tscircuit/jlcpcb-manufacturing-specs\"\nimport type {\n AnyCircuitElement,\n PcbComponent,\n PcbPlacementError,\n} from \"circuit-json\"\nimport { getBoardDrcValue, getPcbBoard } from \"lib/drc-defaults\"\nimport { convertCircuitJsonToFlattenJs } from \"@tscircuit/circuit-json-to-flattenjs\"\ntype CopperElement = Extract<\n AnyCircuitElement,\n { type: \"pcb_via\" | \"pcb_smtpad\" | \"pcb_plated_hole\" | \"pcb_copper_pour\" }\n>\n\nconst GEOMETRY_EPSILON = 1e-9\n\nconst getCopperElementLabel = (element: CopperElement): string => {\n if (element.type === \"pcb_via\") return \"Via\"\n if (element.type === \"pcb_smtpad\") return \"SMT pad\"\n if (element.type === \"pcb_plated_hole\") return \"Plated hole\"\n return \"Copper pour\"\n}\n\n/**\n * Checks the finished copper geometry of every via, SMT pad, plated hole, and\n * copper pour against the real board outline and its configured edge-clearance\n * rule.\n *\n * Component and footprint rotations are normally composed into Circuit JSON's\n * absolute coordinates and `ccw_rotation` fields. Polygon-pad plated holes are\n * the exception: their outline stays local, so it is translated and rotated by\n * the owning component here.\n */\nexport function checkCopperToBoardEdgeClearance(\n circuitJson: AnyCircuitElement[],\n): PcbPlacementError[] {\n const board = getPcbBoard(circuitJson)\n if (!board) return []\n\n // Schematic-only/empty boards may have no dimensions yet. There is no\n // copper-to-edge distance to measure until copper geometry exists.\n if (\n !circuitJson.some(\n (element) =>\n element.type === \"pcb_via\" ||\n element.type === \"pcb_smtpad\" ||\n element.type === \"pcb_plated_hole\" ||\n element.type === \"pcb_copper_pour\",\n )\n )\n return []\n\n const boardPolygon = convertCircuitJsonToFlattenJs([board], { strict: true })\n .elements[0]?.shapes[0]\n if (!boardPolygon) return []\n\n const requiredClearance =\n getBoardDrcValue(board, \"min_board_edge_clearance\") ??\n jlcMinTolerances.min_board_edge_clearance\n if (requiredClearance === undefined) return []\n\n const allowedOffBoardComponentIds = new Set<string>(\n circuitJson\n .filter(\n (element): element is PcbComponent => element.type === \"pcb_component\",\n )\n .filter((component) => component.is_allowed_to_be_off_board)\n .map((component) => component.pcb_component_id),\n )\n\n const { elements: copperElements } = convertCircuitJsonToFlattenJs(\n circuitJson,\n {\n elementTypes: [\n \"pcb_via\",\n \"pcb_smtpad\",\n \"pcb_plated_hole\",\n \"pcb_copper_pour\",\n ],\n includeDrillHoles: false,\n strict: true,\n },\n )\n const errors: PcbPlacementError[] = []\n const seen = new Set<string>()\n for (const geometry of copperElements) {\n if (seen.has(geometry.elementId)) continue\n seen.add(geometry.elementId)\n const element = geometry.sourceElement as CopperElement\n if (\n (element.type === \"pcb_smtpad\" || element.type === \"pcb_plated_hole\") &&\n element.pcb_component_id &&\n allowedOffBoardComponentIds.has(element.pcb_component_id)\n ) {\n continue\n }\n\n const isInside = geometry.shapes.every((shape) =>\n boardPolygon.contains(shape),\n )\n const clearance = isInside\n ? Math.min(\n ...geometry.shapes.map((shape) => boardPolygon.distanceTo(shape)[0]),\n )\n : 0\n if (isInside && clearance + GEOMETRY_EPSILON >= requiredClearance) {\n continue\n }\n\n const id = geometry.elementId\n const label = getCopperElementLabel(element)\n errors.push({\n type: \"pcb_placement_error\",\n pcb_placement_error_id: `copper_too_close_to_board_edge_${id}`,\n error_type: \"pcb_placement_error\",\n message: `${label} ${id} violates copper-to-board-edge clearance (measured ${clearance.toFixed(3)}mm, required ${requiredClearance.toFixed(3)}mm)`,\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 { getReadableNameForComponent } from \"lib/util/get-readable-names\"\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}: {\n board: PcbBoard\n}): 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 getReadableNameForComponent(circuitJson, component.pcb_component_id)\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\nfunction getRepositionSuggestion({\n componentPoly,\n boardPoly,\n}: {\n componentPoly: Flatten.Polygon\n boardPoly: Flatten.Polygon\n}): string | null {\n const boardBox = boardPoly.box\n const componentBox = componentPoly.box\n\n let deltaX = 0\n let deltaY = 0\n\n if (componentBox.xmin < boardBox.xmin) {\n deltaX = boardBox.xmin - componentBox.xmin\n } else if (componentBox.xmax > boardBox.xmax) {\n deltaX = boardBox.xmax - componentBox.xmax\n }\n\n if (componentBox.ymin < boardBox.ymin) {\n deltaY = boardBox.ymin - componentBox.ymin\n } else if (componentBox.ymax > boardBox.ymax) {\n deltaY = boardBox.ymax - componentBox.ymax\n }\n\n if (deltaX === 0 && deltaY === 0) {\n return null\n }\n\n const xDir = deltaX >= 0 ? \"right\" : \"left\"\n const yDir = deltaY >= 0 ? \"up\" : \"down\"\n const absDx = Math.abs(Math.round(deltaX * 100) / 100)\n const absDy = Math.abs(Math.round(deltaY * 100) / 100)\n\n if (absDx > 0 && absDy > 0) {\n return `Try moving it ${absDx}mm ${xDir} and ${absDy}mm ${yDir} to fit within the board edge.`\n }\n\n if (absDx > 0) {\n return `Try moving it ${absDx}mm ${xDir} to fit within the board edge.`\n }\n\n return `Try moving it ${absDy}mm ${yDir} to fit within the board edge.`\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 if (c.is_allowed_to_be_off_board) continue\n\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 // c.width and c.height store the world-coordinate AABB dimensions (post-rotation),\n // so we must NOT re-apply rotation here.\n const compPoly = rectanglePolygon({\n center: c.center,\n size: { width: c.width, height: c.height },\n rotationDeg: 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 0,\n )\n\n const compName = getComponentName({ circuitJson, component: c })\n const overlapDistanceMm = Math.round(overlapDistance * 100) / 100\n const repositionSuggestion = getRepositionSuggestion({\n componentPoly: compPoly,\n boardPoly,\n })\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} extends outside board boundaries by ${overlapDistanceMm}mm.${repositionSuggestion ? ` ${repositionSuggestion}` : \"\"}`,\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 { doBoundsOverlap } from \"@tscircuit/math-utils\"\nimport type {\n AnyCircuitElement,\n PcbComponent,\n PcbCutout,\n PcbPlacementError,\n} from \"circuit-json\"\nimport * as Flatten from \"@flatten-js/core\"\nimport { applyToPoint, rotateDEG } from \"transformation-matrix\"\nimport { getReadableNameForComponent } from \"lib/util/get-readable-names\"\n\nconst CUTOUT_CIRCLE_SEGMENTS = 32\n\nfunction rectanglePolygon({\n center,\n width,\n height,\n rotation = 0,\n}: {\n center: { x: number; y: number }\n width: number\n height: number\n rotation?: number\n}) {\n const halfWidth = width / 2\n const halfHeight = height / 2\n const corners = [\n { x: center.x - halfWidth, y: center.y - halfHeight },\n { x: center.x + halfWidth, y: center.y - halfHeight },\n { x: center.x + halfWidth, y: center.y + halfHeight },\n { x: center.x - halfWidth, y: center.y + halfHeight },\n ]\n const matrix = rotateDEG(rotation, center.x, center.y)\n\n return new Flatten.Polygon(\n corners.map((corner) => {\n const rotated = rotation ? applyToPoint(matrix, corner) : corner\n return new Flatten.Point(rotated.x, rotated.y)\n }),\n )\n}\n\nfunction circlePolygon({\n center,\n radius,\n}: {\n center: { x: number; y: number }\n radius: number\n}) {\n return new Flatten.Polygon(\n Array.from({ length: CUTOUT_CIRCLE_SEGMENTS }, (_, index) => {\n const angle = (2 * Math.PI * index) / CUTOUT_CIRCLE_SEGMENTS\n return new Flatten.Point(\n center.x + Math.cos(angle) * radius,\n center.y + Math.sin(angle) * radius,\n )\n }),\n )\n}\n\nfunction cutoutToPolygon(cutout: PcbCutout): Flatten.Polygon | null {\n if (cutout.shape === \"rect\") {\n return rectanglePolygon({\n center: cutout.center,\n width: cutout.width,\n height: cutout.height,\n rotation: cutout.rotation ?? 0,\n })\n }\n\n if (cutout.shape === \"circle\") {\n return circlePolygon({ center: cutout.center, radius: cutout.radius })\n }\n\n if (cutout.shape === \"polygon\") {\n return new Flatten.Polygon(\n cutout.points.map((point) => new Flatten.Point(point.x, point.y)),\n )\n }\n\n return null\n}\n\nfunction polygonBoxToBounds(polygon: Flatten.Polygon) {\n return {\n minX: polygon.box.xmin,\n minY: polygon.box.ymin,\n maxX: polygon.box.xmax,\n maxY: polygon.box.ymax,\n }\n}\n\nfunction doPolygonsOverlap(\n polygonA: Flatten.Polygon,\n polygonB: Flatten.Polygon,\n) {\n if (\n !doBoundsOverlap(polygonBoxToBounds(polygonA), polygonBoxToBounds(polygonB))\n ) {\n return false\n }\n if (polygonA.contains(polygonB) || polygonB.contains(polygonA)) return true\n\n try {\n const intersections = Flatten.BooleanOperations.intersect(\n polygonA,\n polygonB,\n )\n if (Array.isArray(intersections)) {\n return intersections.some((polygon) => polygon.area() > 0)\n }\n return intersections.area() > 0\n } catch {\n return false\n }\n}\n\n/**\n * Cutouts remove PCB material on every layer, so a component body or SMT pad\n * overlapping a cutout is invalid on both top and bottom.\n */\nexport function checkPcbComponentOverCutout(\n circuitJson: AnyCircuitElement[],\n): PcbPlacementError[] {\n const cutouts = circuitJson.filter(\n (element): element is PcbCutout => element.type === \"pcb_cutout\",\n )\n const components = circuitJson.filter(\n (element): element is PcbComponent => element.type === \"pcb_component\",\n )\n if (cutouts.length === 0 || components.length === 0) return []\n\n const cutoutPolygons = cutouts\n .map((cutout) => ({ cutout, polygon: cutoutToPolygon(cutout) }))\n .filter(\n (entry): entry is { cutout: PcbCutout; polygon: Flatten.Polygon } =>\n entry.polygon !== null && entry.polygon.area() > 0,\n )\n const errors: PcbPlacementError[] = []\n\n for (const component of components) {\n if (!component.center || component.width <= 0 || component.height <= 0) {\n continue\n }\n\n const componentPolygon = rectanglePolygon({\n center: component.center,\n width: component.width,\n height: component.height,\n })\n for (const { cutout, polygon: cutoutPolygon } of cutoutPolygons) {\n if (cutout.pcb_component_id === component.pcb_component_id) continue\n if (!doPolygonsOverlap(componentPolygon, cutoutPolygon)) continue\n\n const componentName = getReadableNameForComponent(\n circuitJson,\n component.pcb_component_id,\n )\n const cutoutId = cutout.pcb_cutout_id\n\n errors.push({\n type: \"pcb_placement_error\",\n pcb_placement_error_id: `component_over_cutout_${component.pcb_component_id}_${cutoutId}`,\n error_type: \"pcb_placement_error\",\n message: `Component ${componentName} overlaps with pcb_cutout [${cutoutId}]`,\n subcircuit_id: component.subcircuit_id,\n })\n }\n }\n\n return errors\n}\n","import { cju, getPrimaryId } from \"@tscircuit/circuit-json-util\"\nimport type {\n AnyCircuitElement,\n PCBKeepout,\n PcbPlacementError,\n PcbKeepoutOverlapWarning,\n PcbVia,\n} from \"circuit-json\"\nimport {\n type PadClearanceElement,\n getPadToPadGap,\n getPads,\n} from \"./check-pad-clearance/common\"\nimport { EPSILON } from \"./drc-defaults\"\nimport { getReadableNameForComponent } from \"./util/get-readable-names\"\nimport { getLayersOfPcbElement } from \"./util/getLayersOfPcbElement\"\n\nconst getErrorOwnerId = (copper: PadClearanceElement) =>\n \"pcb_component_id\" in copper && copper.pcb_component_id\n ? copper.pcb_component_id\n : getPrimaryId(copper)\n\nconst getReadableCopperName = (\n circuitJson: AnyCircuitElement[],\n copper: PadClearanceElement,\n) => {\n if (\"pcb_component_id\" in copper && copper.pcb_component_id) {\n const pcbComponent = circuitJson.find(\n (element) =>\n element.type === \"pcb_component\" &&\n element.pcb_component_id === copper.pcb_component_id,\n )\n const sourceComponent =\n pcbComponent?.type === \"pcb_component\"\n ? circuitJson.find(\n (element) =>\n element.type === \"source_component\" &&\n element.source_component_id === pcbComponent.source_component_id,\n )\n : undefined\n const componentName =\n sourceComponent?.type === \"source_component\" && sourceComponent.name\n ? sourceComponent.name\n : getReadableNameForComponent(circuitJson, copper.pcb_component_id)\n\n return `component ${componentName}`\n }\n\n return copper.type === \"pcb_via\"\n ? `via ${copper.pcb_via_id}`\n : `${copper.type} ${getPrimaryId(copper)}`\n}\n\nexport function checkPcbCopperOverKeepout(\n circuitJson: AnyCircuitElement[],\n): (PcbPlacementError | PcbKeepoutOverlapWarning)[] {\n const keepouts = cju(circuitJson).pcb_keepout.list() as PCBKeepout[]\n if (keepouts.length === 0) return []\n\n const copper: PadClearanceElement[] = [\n ...getPads(circuitJson),\n ...(cju(circuitJson).pcb_via.list() as PcbVia[]),\n ]\n const errors = new Map<string, PcbPlacementError | PcbKeepoutOverlapWarning>()\n\n for (const keepout of keepouts) {\n const excludedComponentIds = new Set(\n keepout.excluded_pcb_component_ids ?? [],\n )\n\n for (const copperElement of copper) {\n if (keepout.allow_placements && copperElement.type !== \"pcb_via\") continue\n\n const copperComponentId =\n \"pcb_component_id\" in copperElement\n ? copperElement.pcb_component_id\n : undefined\n if (copperComponentId && excludedComponentIds.has(copperComponentId)) {\n continue\n }\n\n const copperLayers = getLayersOfPcbElement(copperElement)\n if (!copperLayers.some((layer) => keepout.layers.includes(layer))) {\n continue\n }\n\n if (getPadToPadGap(copperElement, keepout) > EPSILON) continue\n\n const ownerId = getErrorOwnerId(copperElement)\n const errorId = `copper_over_keepout_${ownerId}_${keepout.pcb_keepout_id}`\n if (keepout.warning_only) {\n const copperIdField =\n copperElement.type === \"pcb_smtpad\"\n ? \"pcb_smtpad_ids\"\n : copperElement.type === \"pcb_plated_hole\"\n ? \"pcb_plated_hole_ids\"\n : \"pcb_via_ids\"\n const existing = errors.get(errorId)\n if (existing?.type === \"pcb_keepout_overlap_warning\") {\n existing[copperIdField] = Array.from(\n new Set([\n ...(existing[copperIdField] ?? []),\n getPrimaryId(copperElement),\n ]),\n )\n } else {\n errors.set(errorId, {\n type: \"pcb_keepout_overlap_warning\",\n warning_type: \"pcb_keepout_overlap_warning\",\n pcb_keepout_overlap_warning_id: `pcb_keepout_overlap_warning_${errorId}`,\n pcb_keepout_id: keepout.pcb_keepout_id,\n message: `Copper for ${getReadableCopperName(circuitJson, copperElement)} overlaps advisory PCB keepout \"${keepout.description ?? keepout.pcb_keepout_id}\"`,\n ...(copperComponentId\n ? { pcb_component_ids: [copperComponentId] }\n : {}),\n [copperIdField]: [getPrimaryId(copperElement)],\n subcircuit_id: copperElement.subcircuit_id ?? keepout.subcircuit_id,\n })\n }\n continue\n }\n if (errors.has(errorId)) continue\n\n errors.set(errorId, {\n type: \"pcb_placement_error\",\n pcb_placement_error_id: errorId,\n error_type: \"pcb_placement_error\",\n message: `Copper for ${getReadableCopperName(\n circuitJson,\n copperElement,\n )} overlaps ${\n keepout.description\n ? `PCB keepout \"${keepout.description}\"`\n : \"a PCB keepout\"\n }`,\n subcircuit_id: copperElement.subcircuit_id ?? keepout.subcircuit_id,\n })\n }\n }\n\n return [...errors.values()]\n}\n","import { getReadableNameForElement } from \"@tscircuit/circuit-json-util\"\nimport type {\n AnyCircuitElement,\n PcbVia,\n PcbViaClearanceError,\n} from \"circuit-json\"\nimport {\n type ConnectivityMap,\n getFullConnectivityMapFromCircuitJson,\n} from \"circuit-json-to-connectivity-map\"\nimport { EPSILON, getBoardDrcValue, getPcbBoard } from \"lib/drc-defaults\"\nimport { distance } from \"lib/util/distance\"\nimport { viasAreAtSameLocation } from \"lib/util/viasAreAtSameLocation\"\nimport { jlcMinTolerances } from \"@tscircuit/jlcpcb-manufacturing-specs\"\n\nexport function checkSameNetViaSpacing(\n circuitJson: AnyCircuitElement[],\n {\n connMap,\n minClearance,\n }: { connMap?: ConnectivityMap; minClearance?: number } = {},\n): PcbViaClearanceError[] {\n const vias = circuitJson.filter((el) => el.type === \"pcb_via\") as PcbVia[]\n if (vias.length < 2) return []\n const board = getPcbBoard(circuitJson)\n minClearance ??=\n getBoardDrcValue(board, \"min_via_hole_edge_to_via_hole_edge_clearance\") ??\n jlcMinTolerances.min_via_hole_edge_to_via_hole_edge_clearance\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 // TODO: It is a very inefficient piece of code, the way to fix it is to use flatbush.\n if (viasAreAtSameLocation(viaA, viaB)) continue\n if (!connMap.areIdsConnected(viaA.pcb_via_id, viaB.pcb_via_id)) continue\n const gap =\n distance(viaA, viaB) - viaA.hole_diameter / 2 - viaB.hole_diameter / 2\n if (gap + EPSILON >= minClearance!) 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: minClearance,\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","export function distance(\n a: { x: number; y: number },\n b: { x: number; y: number },\n): number {\n return Math.hypot(a.x - b.x, a.y - b.y)\n}\n","import type { PcbVia } from \"circuit-json\"\nimport { distance } from \"./distance\"\nimport { EPSILON } from \"lib/drc-defaults\"\n\nexport function viasAreAtSameLocation(a: PcbVia, b: PcbVia): boolean {\n return distance(a, b) <= EPSILON\n}\n","import { getReadableNameForElement } from \"@tscircuit/circuit-json-util\"\nimport type {\n AnyCircuitElement,\n PcbVia,\n PcbViaClearanceError,\n} from \"circuit-json\"\nimport {\n type ConnectivityMap,\n getFullConnectivityMapFromCircuitJson,\n} from \"circuit-json-to-connectivity-map\"\nimport { EPSILON, getBoardDrcValue, getPcbBoard } from \"lib/drc-defaults\"\nimport { distance } from \"lib/util/distance\"\nimport { viasAreAtSameLocation } from \"lib/util/viasAreAtSameLocation\"\nimport { jlcMinTolerances } from \"@tscircuit/jlcpcb-manufacturing-specs\"\n\nexport function checkDifferentNetViaSpacing(\n circuitJson: AnyCircuitElement[],\n {\n connMap,\n minClearance,\n }: { connMap?: ConnectivityMap; minClearance?: number } = {},\n): PcbViaClearanceError[] {\n const vias = circuitJson.filter((el) => el.type === \"pcb_via\") as PcbVia[]\n if (vias.length < 2) return []\n const board = getPcbBoard(circuitJson)\n minClearance ??=\n getBoardDrcValue(board, \"min_via_hole_edge_to_via_hole_edge_clearance\") ??\n jlcMinTolerances.min_via_hole_edge_to_via_hole_edge_clearance\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 // TODO: It is a very inefficient piece of code, the way to fix it is to use flatbush.\n if (viasAreAtSameLocation(viaA, viaB)) continue\n if (connMap.areIdsConnected(viaA.pcb_via_id, viaB.pcb_via_id)) continue\n const gap =\n distance(viaA, viaB) - viaA.hole_diameter / 2 - viaB.hole_diameter / 2\n if (gap + EPSILON >= minClearance!) 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: minClearance,\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 { cju } from \"@tscircuit/circuit-json-util\"\nimport type {\n AnyCircuitElement,\n PcbPort,\n PcbTrace,\n PcbTraceWarning,\n SourceTrace,\n} from \"circuit-json\"\nimport { getFullConnectivityMapFromCircuitJson } from \"circuit-json-to-connectivity-map\"\nimport { getReadableNameForSourceTrace } from \"lib/util/get-readable-names\"\n\nexport function checkSourceTracesMatchPcbTraceThickness(\n circuitJson: AnyCircuitElement[],\n): PcbTraceWarning[] {\n const warnings: PcbTraceWarning[] = []\n const db = cju(circuitJson)\n\n const sourceTraces = db.source_trace.list() as SourceTrace[]\n const pcbTraces = db.pcb_trace.list() as PcbTrace[]\n const pcbPorts = db.pcb_port.list() as PcbPort[]\n const connectivityMap = getFullConnectivityMapFromCircuitJson(circuitJson)\n\n for (const sourceTrace of sourceTraces) {\n const requestedThickness = sourceTrace.min_trace_thickness\n if (requestedThickness === undefined) continue\n\n const connectedPcbPorts = pcbPorts.filter((pcbPort) =>\n sourceTrace.connected_source_port_ids?.includes(pcbPort.source_port_id),\n )\n if (connectedPcbPorts.length < 2) continue\n\n const referenceNetId = connectivityMap.getNetConnectedToId(\n connectedPcbPorts[0].pcb_port_id,\n )\n if (!referenceNetId) continue\n\n const netElementIds = connectivityMap.getIdsConnectedToNet(referenceNetId)\n const relatedPcbTraces = pcbTraces.filter((pcbTrace) =>\n netElementIds.includes(pcbTrace.pcb_trace_id),\n )\n if (relatedPcbTraces.length === 0) continue\n\n const actualWireWidths = relatedPcbTraces.flatMap((pcbTrace) =>\n pcbTrace.route\n .filter((point) => point.route_type === \"wire\")\n .map((point) => point.width),\n )\n if (actualWireWidths.length === 0) continue\n\n const actualThickness = Math.min(...actualWireWidths)\n if (actualThickness >= requestedThickness) continue\n\n let undersizedSegment:\n | { pcb_trace_id: string; center: { x: number; y: number } }\n | undefined\n\n for (const relatedPcbTrace of relatedPcbTraces) {\n for (let i = 0; i < relatedPcbTrace.route.length - 1; i++) {\n const point = relatedPcbTrace.route[i]\n const nextPoint = relatedPcbTrace.route[i + 1]\n if (!point || !nextPoint) continue\n if (point.route_type !== \"wire\" || nextPoint.route_type !== \"wire\") {\n continue\n }\n if (point.width !== actualThickness) continue\n\n undersizedSegment = {\n pcb_trace_id: relatedPcbTrace.pcb_trace_id,\n center: {\n x: (point.x + nextPoint.x) / 2,\n y: (point.y + nextPoint.y) / 2,\n },\n }\n break\n }\n\n if (undersizedSegment) break\n }\n\n if (!undersizedSegment) continue\n\n warnings.push({\n type: \"pcb_trace_warning\",\n pcb_trace_warning_id: `pcb_trace_warning_${sourceTrace.source_trace_id}`,\n warning_type: \"pcb_trace_warning\",\n message: `Trace [${getReadableNameForSourceTrace(circuitJson, sourceTrace)}] is routed thinner than requested (requested: ${requestedThickness}mm, actual: ${actualThickness}mm).`,\n center: undersizedSegment.center,\n source_trace_id: sourceTrace.source_trace_id,\n pcb_trace_id: undersizedSegment.pcb_trace_id,\n pcb_component_ids: Array.from(\n new Set(\n connectedPcbPorts\n .map((pcbPort) => pcbPort.pcb_component_id)\n .filter((id): id is string => id !== undefined),\n ),\n ),\n pcb_port_ids: connectedPcbPorts.map((pcbPort) => pcbPort.pcb_port_id),\n })\n }\n\n return warnings\n}\n","import type {\n AnyCircuitElement,\n PcbPort,\n PcbTrace,\n PcbTraceMissingError,\n SourceTrace,\n} from \"circuit-json\"\nimport {\n type ConnectivityMap,\n getFullConnectivityMapFromCircuitJson,\n} from \"circuit-json-to-connectivity-map\"\nimport { containsCircuitJsonId } from \"lib/util/get-readable-names\"\nimport { getCopperPourConnectivity } from \"./copper-pour-connectivity/get-copper-pour-connectivity\"\n\n/**\n * Check that each source_trace which connects source ports has at least one\n * pcb_trace associated with it, or its ports physically joined through a\n * same-net copper pour. Otherwise return an error for that source_trace.\n */\nfunction checkSourceTracesHavePcbTraces(\n circuitJson: AnyCircuitElement[],\n { connMap }: { connMap?: ConnectivityMap } = {},\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 const pcbPorts = circuitJson.filter(\n (el) => el.type === \"pcb_port\",\n ) as PcbPort[]\n const sourcePortToPcbPort = new Map(\n pcbPorts.map((pcbPort) => [pcbPort.source_port_id, pcbPort]),\n )\n const connectivityMap =\n connMap ?? getFullConnectivityMapFromCircuitJson(circuitJson)\n let pourConnectivity: ReturnType<typeof getCopperPourConnectivity> | undefined\n const getPourConnectivity = () =>\n (pourConnectivity ??= getCopperPourConnectivity(\n circuitJson,\n connectivityMap,\n ))\n\n for (const sourceTrace of sourceTraces) {\n if (!sourceTrace.connected_source_port_ids?.length) continue\n if ((sourceTrace.connected_source_net_ids?.length ?? 0) > 0) continue\n if (sourceTrace.connected_source_port_ids.length < 2) continue\n\n const hasPcbTrace = pcbTraces.some((pcbTrace) =>\n connectivityMap.areIdsConnected(\n sourceTrace.source_trace_id,\n pcbTrace.pcb_trace_id,\n ),\n )\n\n if (!hasPcbTrace) {\n const connectedPcbPorts = sourceTrace.connected_source_port_ids\n .map((sourcePortId) => sourcePortToPcbPort.get(sourcePortId))\n .filter((pcbPort): pcbPort is PcbPort => pcbPort !== undefined)\n\n if (\n connectedPcbPorts.length ===\n sourceTrace.connected_source_port_ids.length &&\n getPourConnectivity().arePortsConnected(\n connectedPcbPorts.map((port) => port.pcb_port_id),\n )\n )\n continue\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 && !containsCircuitJsonId(sourceTrace.display_name) ? sourceTrace.display_name : \"trace\"}] 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 { createIndexedPcbConnectivityMap } from \"lib/util/create-indexed-pcb-connectivity-map\"\nimport type {\n AnyCircuitElement,\n PcbTraceError,\n PcbPort,\n PcbTrace,\n SourceTrace,\n PcbSmtPad,\n PcbPlatedHole,\n} from \"circuit-json\"\nimport { pointToSegmentDistance } from \"@tscircuit/math-utils\"\nimport { isPointInPad } from \"./is-point-in-pad\"\nimport { distance } from \"../util/distance\"\nimport { getPcbPortIdsConnectedToRoutePoint } from \"../check-each-pcb-trace-non-overlapping/getPcbPortIdsConnectedToTraces\"\nimport {\n getReadableNameForPcbPort,\n getReadableNameForPcbTrace,\n} from \"@tscircuit/circuit-json-util\"\nimport {\n type ConnectivityMap,\n getFullConnectivityMapFromCircuitJson,\n type PcbConnectivityMap,\n} from \"circuit-json-to-connectivity-map\"\nimport { getLayersOfPcbElement } from \"../util/getLayersOfPcbElement\"\nimport { endpointTouchesVia, getViaContactIndex } from \"./via-contact-index\"\n\ntype PcbPortId = PcbPort[\"pcb_port_id\"]\ntype PcbTraceRoutePoint = PcbTrace[\"route\"][number]\ntype PcbTraceWireRoutePoint = Extract<\n PcbTraceRoutePoint,\n { route_type: \"wire\" }\n>\ntype PcbPad = PcbSmtPad | PcbPlatedHole\n\ninterface TraceWireSegment {\n trace: PcbTrace\n start: PcbTraceWireRoutePoint\n end: PcbTraceWireRoutePoint\n}\n\ntype TraceWireSegmentsByNetAndLayer = Map<\n string,\n Map<string, TraceWireSegment[]>\n>\n\nconst ENDPOINT_CONTACT_EPSILON = 1e-9\nconst TRACE_SEGMENT_GEOMETRY_EPSILON = 1e-9\n\nfunction routePointTouchesPad(point: PcbTraceRoutePoint, pad: PcbPad) {\n return (\n point.route_type === \"wire\" &&\n getLayersOfPcbElement(pad).includes(point.layer) &&\n isPointInPad(point, pad)\n )\n}\n\nfunction getTraceWireSegmentsByNetAndLayer(\n pcbTraces: PcbTrace[],\n fullConnectivityMap: ConnectivityMap,\n): TraceWireSegmentsByNetAndLayer {\n const segmentsByNetAndLayer: TraceWireSegmentsByNetAndLayer = new Map()\n\n for (const trace of pcbTraces) {\n // Interpolated segments need position-dependent width evaluation. Keep\n // this focused fix conservative until that geometry is available here.\n if (trace.route_thickness_mode === \"interpolated\") continue\n\n const netId = fullConnectivityMap.getNetConnectedToId(trace.pcb_trace_id)\n if (!netId) continue\n\n for (let i = 0; i < trace.route.length - 1; i++) {\n const start = trace.route[i]\n const end = trace.route[i + 1]\n\n if (start.route_type !== \"wire\" || end.route_type !== \"wire\") continue\n if (start.layer !== end.layer) continue\n if (\n Math.hypot(start.x - end.x, start.y - end.y) <=\n TRACE_SEGMENT_GEOMETRY_EPSILON\n ) {\n continue\n }\n\n const segmentsByLayer = segmentsByNetAndLayer.get(netId) ?? new Map()\n const segments = segmentsByLayer.get(start.layer) ?? []\n segments.push({ trace, start, end })\n segmentsByLayer.set(start.layer, segments)\n segmentsByNetAndLayer.set(netId, segmentsByLayer)\n }\n }\n\n return segmentsByNetAndLayer\n}\n\nfunction getEndpointTraceCopperWidth(\n trace: PcbTrace,\n endpoint: \"start\" | \"end\",\n): number | undefined {\n // Interpolated traces have flat longitudinal ends, so a point-radius contact\n // test would overestimate their endpoint copper.\n if (trace.route_thickness_mode === \"interpolated\") return undefined\n\n let segmentStartIndex = endpoint === \"start\" ? 0 : trace.route.length - 2\n const indexStep = endpoint === \"start\" ? 1 : -1\n\n while (segmentStartIndex >= 0 && segmentStartIndex < trace.route.length - 1) {\n const segmentStart = trace.route[segmentStartIndex]\n const segmentEnd = trace.route[segmentStartIndex + 1]\n\n if (\n segmentStart?.route_type !== \"wire\" ||\n segmentEnd?.route_type !== \"wire\" ||\n segmentStart.layer !== segmentEnd.layer\n ) {\n return undefined\n }\n\n if (\n Math.hypot(segmentStart.x - segmentEnd.x, segmentStart.y - segmentEnd.y) >\n TRACE_SEGMENT_GEOMETRY_EPSILON\n ) {\n // A constant-width segment takes its thickness from its start route point.\n return segmentStart.width\n }\n\n segmentStartIndex += indexStep\n }\n\n return undefined\n}\n\nfunction routePointTouchesLogicallyConnectedTraceCopper({\n point,\n endpointTraceCopperWidth,\n ownerTrace,\n traceWireSegmentsByNetAndLayer,\n fullConnectivityMap,\n}: {\n point: PcbTraceRoutePoint\n endpointTraceCopperWidth: number\n ownerTrace: PcbTrace\n traceWireSegmentsByNetAndLayer: TraceWireSegmentsByNetAndLayer\n fullConnectivityMap: ConnectivityMap\n}): boolean {\n if (point.route_type !== \"wire\") return false\n\n const ownerNetId = fullConnectivityMap.getNetConnectedToId(\n ownerTrace.pcb_trace_id,\n )\n if (!ownerNetId) return false\n const candidateSegments =\n traceWireSegmentsByNetAndLayer.get(ownerNetId)?.get(point.layer) ?? []\n\n // Logical connectivity selects the eligible net. Geometry must still prove\n // that this exact endpoint directly touches copper outside its owner trace.\n for (const segment of candidateSegments) {\n if (segment.trace.pcb_trace_id === ownerTrace.pcb_trace_id) continue\n\n const maximumContactDistance =\n endpointTraceCopperWidth / 2 +\n segment.start.width / 2 +\n ENDPOINT_CONTACT_EPSILON\n if (\n pointToSegmentDistance(point, segment.start, segment.end) <=\n maximumContactDistance\n ) {\n return true\n }\n }\n\n return false\n}\n\nfunction getRoutePointCenter(point: PcbTraceRoutePoint) {\n if (point.route_type === \"through_pad\") {\n return {\n x: (point.start.x + point.end.x) / 2,\n y: (point.start.y + point.end.y) / 2,\n }\n }\n\n return { x: point.x, y: point.y }\n}\n\nfunction routePointConnectsToAnotherExpectedPort(\n point: PcbTraceRoutePoint,\n expectedPorts: PcbPort[],\n missingPcbPortId: PcbPortId,\n padMap: Map<PcbPortId, PcbPad[]>,\n) {\n return expectedPorts.some((expectedPort) => {\n if (\n !expectedPort.pcb_port_id ||\n expectedPort.pcb_port_id === missingPcbPortId\n ) {\n return false\n }\n\n const expectedPads = padMap.get(expectedPort.pcb_port_id)\n return (\n expectedPads?.some((pad) => routePointTouchesPad(point, pad)) ?? false\n )\n })\n}\n\nfunction getMissingConnectionErrorCenter({\n firstPoint,\n lastPoint,\n port,\n expectedPorts,\n padMap,\n}: {\n firstPoint: PcbTrace[\"route\"][number]\n lastPoint: PcbTrace[\"route\"][number]\n port: PcbPort\n expectedPorts: PcbPort[]\n padMap: Map<PcbPortId, PcbPad[]>\n}) {\n let errorLocation:\n | Extract<PcbTrace[\"route\"][number], { route_type: \"wire\" }>\n | undefined\n const firstWirePoint =\n firstPoint.route_type === \"wire\" ? firstPoint : undefined\n const lastWirePoint = lastPoint.route_type === \"wire\" ? lastPoint : undefined\n const firstWirePointReferencesPort = getPcbPortIdsConnectedToRoutePoint(\n firstPoint,\n ).includes(port.pcb_port_id)\n const lastWirePointReferencesPort = getPcbPortIdsConnectedToRoutePoint(\n lastPoint,\n ).includes(port.pcb_port_id)\n\n if (firstWirePointReferencesPort && firstWirePoint) {\n errorLocation = firstWirePoint\n } else if (lastWirePointReferencesPort && lastWirePoint) {\n errorLocation = lastWirePoint\n } else if (\n routePointConnectsToAnotherExpectedPort(\n firstPoint,\n expectedPorts,\n port.pcb_port_id,\n padMap,\n ) &&\n lastWirePoint\n ) {\n errorLocation = lastWirePoint\n } else if (\n routePointConnectsToAnotherExpectedPort(\n lastPoint,\n expectedPorts,\n port.pcb_port_id,\n padMap,\n ) &&\n firstWirePoint\n ) {\n errorLocation = firstWirePoint\n } else if (firstWirePoint && lastWirePoint) {\n errorLocation =\n distance(firstWirePoint, port) <= distance(lastWirePoint, port)\n ? firstWirePoint\n : lastWirePoint\n } else if (firstWirePoint) {\n errorLocation = firstWirePoint\n } else if (lastWirePoint) {\n errorLocation = lastWirePoint\n }\n\n const firstPointCenter = getRoutePointCenter(firstPoint)\n const lastPointCenter = getRoutePointCenter(lastPoint)\n\n return errorLocation\n ? { x: errorLocation.x, y: errorLocation.y }\n : {\n x: (firstPointCenter.x + lastPointCenter.x) / 2,\n y: (firstPointCenter.y + lastPointCenter.y) / 2,\n }\n}\n\nfunction checkTracesAreContiguous(\n circuitJson: AnyCircuitElement[],\n {\n connMap,\n pcbConnectivityMap,\n }: {\n connMap?: ConnectivityMap\n pcbConnectivityMap?: PcbConnectivityMap\n } = {},\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<PcbPortId, PcbPad[]>()\n pcbConnectivityMap ??= createIndexedPcbConnectivityMap(circuitJson)\n let fullConnectivityMap: ConnectivityMap | undefined = connMap\n let traceWireSegmentsByNetAndLayer: TraceWireSegmentsByNetAndLayer | undefined\n const getFullConnectivityMap = () => {\n fullConnectivityMap ??= getFullConnectivityMapFromCircuitJson(circuitJson)\n return fullConnectivityMap\n }\n const getTraceWireSegmentIndex = () => {\n traceWireSegmentsByNetAndLayer ??= getTraceWireSegmentsByNetAndLayer(\n pcbTraces,\n getFullConnectivityMap(),\n )\n return traceWireSegmentsByNetAndLayer\n }\n let viaContactIndex: ReturnType<typeof getViaContactIndex> | undefined\n const getViaIndex = () => {\n viaContactIndex ??= getViaContactIndex(\n circuitJson,\n getFullConnectivityMap(),\n )\n return viaContactIndex\n }\n const checkedSourceTraceIds = new Set<string>()\n\n for (const pad of pcbSmtPads) {\n if (pad.pcb_port_id) {\n padMap.set(pad.pcb_port_id, [...(padMap.get(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, [\n ...(padMap.get(hole.pcb_port_id) ?? []),\n hole,\n ])\n }\n }\n\n const touchedPortIdsByTraceId = new Map<string, Set<PcbPortId>>()\n const traceIdsByTouchedPortId = new Map<PcbPortId, Set<string>>()\n\n // Route attribution can change when a logical net is converted into an MST.\n // Record the PCB ports each routed trace physically reaches so contiguity can\n // follow the copper network instead of relying on singular source_trace_ids.\n for (const trace of pcbTraces) {\n const touchedPortIds = new Set<PcbPortId>()\n const firstPoint = trace.route[0]\n const lastPoint = trace.route.at(-1)\n\n for (const point of [firstPoint, lastPoint]) {\n if (!point) continue\n\n for (const [pcbPortId, pads] of padMap) {\n if (pads.some((pad) => routePointTouchesPad(point, pad))) {\n touchedPortIds.add(pcbPortId)\n }\n }\n }\n\n touchedPortIdsByTraceId.set(trace.pcb_trace_id, touchedPortIds)\n for (const pcbPortId of touchedPortIds) {\n const traceIds = traceIdsByTouchedPortId.get(pcbPortId) ?? new Set()\n traceIds.add(trace.pcb_trace_id)\n traceIdsByTouchedPortId.set(pcbPortId, traceIds)\n }\n }\n\n const physicallyConnectedTracesByTraceId = new Map<string, PcbTrace[]>()\n const getPhysicallyConnectedTraces = (startTrace: PcbTrace): PcbTrace[] => {\n const cached = physicallyConnectedTracesByTraceId.get(\n startTrace.pcb_trace_id,\n )\n if (cached) return cached\n\n const connectedTraceIds = new Set<string>()\n const pendingTraceIds = [startTrace.pcb_trace_id]\n\n while (pendingTraceIds.length > 0) {\n const traceId = pendingTraceIds.pop()!\n if (connectedTraceIds.has(traceId)) continue\n connectedTraceIds.add(traceId)\n\n for (const connectedTrace of pcbConnectivityMap.getAllTracesConnectedToTrace(\n traceId,\n )) {\n if (!connectedTraceIds.has(connectedTrace.pcb_trace_id)) {\n pendingTraceIds.push(connectedTrace.pcb_trace_id)\n }\n }\n\n for (const pcbPortId of touchedPortIdsByTraceId.get(traceId) ?? []) {\n for (const touchingTraceId of traceIdsByTouchedPortId.get(pcbPortId) ??\n []) {\n if (!connectedTraceIds.has(touchingTraceId)) {\n pendingTraceIds.push(touchingTraceId)\n }\n }\n }\n }\n\n const connectedTraces = pcbTraces.filter((trace) =>\n connectedTraceIds.has(trace.pcb_trace_id),\n )\n for (const trace of connectedTraces) {\n physicallyConnectedTracesByTraceId.set(\n trace.pcb_trace_id,\n connectedTraces,\n )\n }\n return connectedTraces\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.01 &&\n Math.abs(prevPoint.y - currentPoint.y) < 0.01\n\n const nextAligned =\n Math.abs(nextPoint.x - currentPoint.x) < 0.01 &&\n Math.abs(nextPoint.y - currentPoint.y) < 0.01\n\n if (!prevAligned || !nextAligned) {\n const traceName = getReadableNameForPcbTrace(\n circuitJson,\n trace.pcb_trace_id,\n )\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: `misaligned_via_${trace.pcb_trace_id}_${i}`,\n pcb_component_ids: [],\n pcb_port_ids: [],\n })\n }\n }\n }\n }\n\n const traceName = getReadableNameForPcbTrace(\n circuitJson,\n trace.pcb_trace_id,\n )\n\n // Validate required ports once for the complete routed source trace.\n if (sourceTrace && expectedPorts.length > 0) {\n if (checkedSourceTraceIds.has(sourceTrace.source_trace_id)) continue\n checkedSourceTraceIds.add(sourceTrace.source_trace_id)\n }\n\n for (const port of expectedPorts) {\n if (!port.pcb_port_id) continue\n\n const pads = padMap.get(port.pcb_port_id)\n\n if (!pads?.length) continue\n\n const isConnectedByRoutedSourceTrace = getPhysicallyConnectedTraces(\n trace,\n ).some((candidateTrace) =>\n touchedPortIdsByTraceId\n .get(candidateTrace.pcb_trace_id)\n ?.has(port.pcb_port_id),\n )\n if (isConnectedByRoutedSourceTrace) continue\n\n const isFirstPointConnected = pads.some((pad) =>\n routePointTouchesPad(firstPoint, pad),\n )\n\n const isLastPointConnected = pads.some((pad) =>\n routePointTouchesPad(lastPoint, pad),\n )\n\n if (!isFirstPointConnected && !isLastPointConnected) {\n const portName = getReadableNameForPcbPort(\n circuitJson,\n port.pcb_port_id,\n ).replace(\"pcb_port\", \"\")\n const padType = pads[0].type.replace(/pcb_/, \"\")\n const errorCenter = getMissingConnectionErrorCenter({\n firstPoint,\n lastPoint,\n port,\n expectedPorts,\n padMap,\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: `missing_connection_${trace.pcb_trace_id}_${port.pcb_port_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 pads of padMap.values()) {\n if (pads.some((pad) => routePointTouchesPad(firstPoint, pad))) {\n firstConnectsToAnyPad = true\n }\n if (pads.some((pad) => routePointTouchesPad(lastPoint, pad))) {\n lastConnectsToAnyPad = true\n }\n }\n\n const firstEndpointTraceCopperWidth = !firstConnectsToAnyPad\n ? getEndpointTraceCopperWidth(trace, \"start\")\n : undefined\n const lastEndpointTraceCopperWidth = !lastConnectsToAnyPad\n ? getEndpointTraceCopperWidth(trace, \"end\")\n : undefined\n const firstConnectsToLogicallyConnectedTraceCopper =\n firstEndpointTraceCopperWidth !== undefined &&\n routePointTouchesLogicallyConnectedTraceCopper({\n point: firstPoint,\n endpointTraceCopperWidth: firstEndpointTraceCopperWidth,\n ownerTrace: trace,\n traceWireSegmentsByNetAndLayer: getTraceWireSegmentIndex(),\n fullConnectivityMap: getFullConnectivityMap(),\n })\n const lastConnectsToLogicallyConnectedTraceCopper =\n lastEndpointTraceCopperWidth !== undefined &&\n routePointTouchesLogicallyConnectedTraceCopper({\n point: lastPoint,\n endpointTraceCopperWidth: lastEndpointTraceCopperWidth,\n ownerTrace: trace,\n traceWireSegmentsByNetAndLayer: getTraceWireSegmentIndex(),\n fullConnectivityMap: getFullConnectivityMap(),\n })\n const firstIsConnected =\n firstConnectsToAnyPad ||\n firstConnectsToLogicallyConnectedTraceCopper ||\n (firstEndpointTraceCopperWidth !== undefined &&\n endpointTouchesVia({\n point: firstPoint,\n width: firstEndpointTraceCopperWidth,\n ownerTrace: trace,\n index: getViaIndex(),\n connectivity: getFullConnectivityMap(),\n }))\n const lastIsConnected =\n lastConnectsToAnyPad ||\n lastConnectsToLogicallyConnectedTraceCopper ||\n (lastEndpointTraceCopperWidth !== undefined &&\n endpointTouchesVia({\n point: lastPoint,\n width: lastEndpointTraceCopperWidth,\n ownerTrace: trace,\n index: getViaIndex(),\n connectivity: getFullConnectivityMap(),\n }))\n const endpointsAreSame =\n firstPoint.route_type === \"wire\" &&\n lastPoint.route_type === \"wire\" &&\n firstPoint.layer === lastPoint.layer &&\n Math.hypot(firstPoint.x - lastPoint.x, firstPoint.y - lastPoint.y) <=\n ENDPOINT_CONTACT_EPSILON\n\n if (!firstIsConnected && firstPoint.route_type === \"wire\") {\n errors.push({\n type: \"pcb_trace_error\",\n message: `Trace [${traceName}] has disconnected endpoint at (${firstPoint.x.toFixed(2)}, ${firstPoint.y.toFixed(2)})`,\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: `disconnected_endpoint_${trace.pcb_trace_id}_start`,\n center: { x: firstPoint.x, y: firstPoint.y },\n pcb_component_ids: [],\n pcb_port_ids: [],\n })\n }\n if (\n !lastIsConnected &&\n lastPoint.route_type === \"wire\" &&\n !(endpointsAreSame && !firstIsConnected)\n ) {\n errors.push({\n type: \"pcb_trace_error\",\n message: `Trace [${traceName}] has disconnected endpoint at (${lastPoint.x.toFixed(2)}, ${lastPoint.y.toFixed(2)})`,\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: `disconnected_endpoint_${trace.pcb_trace_id}_end`,\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 {\n all_layers,\n type AnyCircuitElement,\n type PcbTrace,\n type PcbVia,\n} from \"circuit-json\"\nimport type { ConnectivityMap } from \"circuit-json-to-connectivity-map\"\nimport { getPrimaryId } from \"@tscircuit/circuit-json-util\"\nimport { pointToSegmentDistance } from \"@tscircuit/math-utils\"\nimport { getPads, getPadToPadGap } from \"../check-pad-clearance/common\"\nimport { isPointInPad } from \"./is-point-in-pad\"\nimport { getLayersOfPcbElement } from \"../util/getLayersOfPcbElement\"\n\ntype ViaContact = {\n x: number\n y: number\n ownerTraceId?: string\n radius?: number\n touchesPad: boolean\n touchingTraceIds: Set<string>\n}\n\ntype ViaContactIndex = Map<string, Map<string, ViaContact[]>>\nconst CONTACT_EPSILON = 1e-9\n\n/** Index actual via copper independently of lateral trace segments. */\nexport function getViaContactIndex(\n circuitJson: AnyCircuitElement[],\n connectivity: ConnectivityMap,\n): ViaContactIndex {\n const index: ViaContactIndex = new Map()\n const pads = getPads(circuitJson)\n const traces = circuitJson.filter((element) => element.type === \"pcb_trace\")\n const vias = circuitJson.filter((element) => element.type === \"pcb_via\")\n const board = circuitJson.find((element) => element.type === \"pcb_board\")\n const layerCount = board?.num_layers\n const innerLayers = all_layers.filter((layer) => layer.startsWith(\"inner\"))\n const stack = [\n \"top\",\n ...innerLayers.slice(\n 0,\n layerCount === undefined ? undefined : Math.max(0, layerCount - 2),\n ),\n ...(layerCount === 1 ? [] : [\"bottom\"]),\n ]\n const add = (\n id: string,\n layers: string[],\n contact: Omit<ViaContact, \"touchesPad\" | \"touchingTraceIds\">,\n ) => {\n if (![contact.x, contact.y].every(Number.isFinite)) return\n const net = connectivity.getNetConnectedToId(id)\n if (!net) return\n const touchesPad = pads.some((pad) => {\n if (\n connectivity.getNetConnectedToId(getPrimaryId(pad)) !== net ||\n !getLayersOfPcbElement(pad).some((layer) => layers.includes(layer))\n )\n return false\n if (contact.radius === undefined) return isPointInPad(contact, pad)\n const viaGeometry = {\n type: \"pcb_via\",\n pcb_via_id: id,\n x: contact.x,\n y: contact.y,\n outer_diameter: contact.radius * 2,\n hole_diameter: 0,\n layers,\n } as PcbVia\n return getPadToPadGap(viaGeometry, pad) <= CONTACT_EPSILON\n })\n const touchingTraceIds = new Set<string>()\n for (const trace of traces) {\n if (\n trace.route_thickness_mode === \"interpolated\" ||\n connectivity.getNetConnectedToId(trace.pcb_trace_id) !== net\n )\n continue\n for (let i = 1; i < trace.route.length; i++) {\n const a = trace.route[i - 1]!,\n b = trace.route[i]!\n if (\n a.route_type !== \"wire\" ||\n b.route_type !== \"wire\" ||\n a.layer !== b.layer ||\n !layers.includes(a.layer) ||\n !Number.isFinite(a.width) ||\n a.width <= 0 ||\n Math.hypot(a.x - b.x, a.y - b.y) <= CONTACT_EPSILON\n )\n continue\n const reach =\n contact.radius === undefined ? 0 : contact.radius + a.width / 2\n if (pointToSegmentDistance(contact, a, b) <= reach + CONTACT_EPSILON) {\n touchingTraceIds.add(trace.pcb_trace_id)\n break\n }\n }\n }\n const copper: ViaContact = { ...contact, touchesPad, touchingTraceIds }\n const byLayer = index.get(net) ?? new Map<string, ViaContact[]>()\n for (const layer of layers) {\n const contacts = byLayer.get(layer) ?? []\n contacts.push(copper)\n byLayer.set(layer, contacts)\n }\n index.set(net, byLayer)\n }\n\n for (const via of vias) {\n if (!Number.isFinite(via.outer_diameter) || via.outer_diameter <= 0)\n continue\n add(via.pcb_via_id, getLayersOfPcbElement(via), {\n x: via.x,\n y: via.y,\n ownerTraceId: via.pcb_trace_id,\n radius: via.outer_diameter / 2,\n })\n }\n\n // Route-only inputs may not have materialized pcb_via records yet. Expand\n // their physical span using the board stack, including intermediate layers.\n for (const trace of circuitJson) {\n if (trace.type !== \"pcb_trace\") continue\n for (const point of trace.route) {\n if (point.route_type !== \"via\") continue\n if (\n vias.some(\n (via) =>\n Math.hypot(via.x - point.x, via.y - point.y) <= CONTACT_EPSILON &&\n (via.pcb_trace_id === trace.pcb_trace_id ||\n (!via.pcb_trace_id &&\n connectivity.areIdsConnected(\n via.pcb_via_id,\n trace.pcb_trace_id,\n ))),\n )\n )\n continue\n const from = stack.indexOf(point.from_layer)\n const to = stack.indexOf(point.to_layer)\n if (from < 0 || to < 0) continue\n const diameter = point.outer_diameter\n if (\n diameter !== undefined &&\n (!Number.isFinite(diameter) || diameter <= 0)\n )\n continue\n add(\n trace.pcb_trace_id,\n stack.slice(Math.min(from, to), Math.max(from, to) + 1),\n {\n x: point.x,\n y: point.y,\n ownerTraceId: trace.pcb_trace_id,\n radius: diameter === undefined ? undefined : diameter / 2,\n },\n )\n }\n }\n return index\n}\n\nexport function endpointTouchesVia({\n point,\n width,\n ownerTrace,\n index,\n connectivity,\n}: {\n point: PcbTrace[\"route\"][number]\n width: number\n ownerTrace: PcbTrace\n index: ViaContactIndex\n connectivity: ConnectivityMap\n}): boolean {\n if (point.route_type !== \"wire\" || !Number.isFinite(width) || width <= 0)\n return false\n const net = connectivity.getNetConnectedToId(ownerTrace.pcb_trace_id)\n if (!net) return false\n return (index.get(net)?.get(point.layer) ?? []).some((via) => {\n if (via.ownerTraceId === ownerTrace.pcb_trace_id) return false\n // A lone via does not establish an onward connection. Its barrel must\n // reach a same-net pad or another nondegenerate trace on a physical layer.\n if (\n !via.touchesPad &&\n ![...via.touchingTraceIds].some((id) => id !== ownerTrace.pcb_trace_id)\n )\n return false\n // When a route-only via has no diameter, certify exact center contact only.\n const contactDistance =\n via.radius === undefined ? 0 : via.radius + width / 2\n return (\n Math.hypot(point.x - via.x, point.y - via.y) <=\n contactDistance + CONTACT_EPSILON\n )\n })\n}\n","import { cju } from \"@tscircuit/circuit-json-util\"\nimport type { Point, Polygon } from \"@tscircuit/math-utils\"\nimport { segmentToSegmentMinDistance } from \"@tscircuit/math-utils\"\nimport type {\n AnyCircuitElement,\n PcbBoard,\n PcbTrace,\n PcbTraceError,\n} from \"circuit-json\"\nimport { getBoardDrcValue, getPcbBoard } from \"lib/drc-defaults\"\nimport { jlcMinTolerances } from \"@tscircuit/jlcpcb-manufacturing-specs\"\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 board = getPcbBoard(circuitJson)\n if (!board) return errors\n const margin =\n config.margin ??\n getBoardDrcValue(board, \"min_board_edge_clearance\") ??\n jlcMinTolerances.min_board_edge_clearance\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 = Number.POSITIVE_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 {\n cju,\n getBoundsOfPcbElements,\n getPrimaryId,\n} from \"@tscircuit/circuit-json-util\"\nimport { doBoundsOverlap } from \"@tscircuit/math-utils\"\nimport type {\n AnyCircuitElement,\n PcbCourtyardCircle,\n PcbCourtyardOutline,\n PcbCourtyardPolygon,\n PcbCourtyardRect,\n} from \"circuit-json\"\nimport { getFullConnectivityMapFromCircuitJson } from \"circuit-json-to-connectivity-map\"\nimport {\n getReadableNameForElementId,\n getReadableNameForPort,\n} from \"lib/util/get-readable-names\"\nimport type { PcbComponentOverlapError } from \"../consolidate-pcb-overlap-errors\"\nimport {\n type OverlappableElement,\n doPcbElementsOverlap,\n} from \"./doPcbElementsOverlap\"\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\ntype CourtyardElement =\n | PcbCourtyardCircle\n | PcbCourtyardOutline\n | PcbCourtyardPolygon\n | PcbCourtyardRect\n\nconst isCourtyardElement = (\n element: AnyCircuitElement,\n): element is CourtyardElement =>\n element.type === \"pcb_courtyard_circle\" ||\n element.type === \"pcb_courtyard_outline\" ||\n element.type === \"pcb_courtyard_polygon\" ||\n element.type === \"pcb_courtyard_rect\"\n\nconst isHoleElement = (element: OverlappableElement): boolean =>\n element.type === \"pcb_hole\" || element.type === \"pcb_plated_hole\"\n\nconst formatOverlapElementDescription = (\n circuitJson: AnyCircuitElement[],\n element: OverlappableElement,\n): string => {\n if (\"pcb_port_id\" in element && element.pcb_port_id) {\n return getReadableNameForPort(circuitJson, element.pcb_port_id)\n }\n\n const id = getPrimaryId(element)\n const readableName = getReadableNameForElementId(circuitJson, id)\n return readableName === \"element\" ? `[${id}]` : readableName\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): PcbComponentOverlapError[] {\n const errors: PcbComponentOverlapError[] = []\n\n const doNotPlaceComponentIds = new Set(\n circuitJson.flatMap((element) =>\n element.type === \"pcb_component\" && element.do_not_place\n ? [element.pcb_component_id]\n : [],\n ),\n )\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 const courtyards = circuitJson.filter(isCourtyardElement)\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 })\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 })\n }\n componentMap.get(componentId)!.elements.push(hole)\n }\n\n // Group holes by component when possible, otherwise treat each as standalone\n for (const hole of holes) {\n const componentId =\n hole.pcb_component_id || `standalone_hole_${getPrimaryId(hole)}`\n if (!componentMap.has(componentId)) {\n componentMap.set(componentId, {\n component_id: componentId,\n elements: [hole],\n })\n }\n }\n\n for (const courtyard of courtyards) {\n const componentId = courtyard.pcb_component_id\n if (!componentMap.has(componentId)) {\n componentMap.set(componentId, {\n component_id: componentId,\n elements: [],\n })\n }\n componentMap.get(componentId)!.elements.push(courtyard)\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 const pairIncludesDoNotPlaceComponent =\n doNotPlaceComponentIds.has(comp1.component_id) ||\n doNotPlaceComponentIds.has(comp2.component_id)\n\n // First check if component bounds overlap\n if (!comp1.bounds || !comp2.bounds) {\n continue\n }\n\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 if (\n pairIncludesDoNotPlaceComponent &&\n (isCourtyardElement(elem1) || isCourtyardElement(elem2))\n ) {\n continue\n }\n\n if (\n (isCourtyardElement(elem1) || isCourtyardElement(elem2)) &&\n !isHoleElement(elem1) &&\n !isHoleElement(elem2)\n ) {\n continue\n }\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 const elem1Description = formatOverlapElementDescription(\n circuitJson,\n elem1,\n )\n const elem2Description = formatOverlapElementDescription(\n circuitJson,\n elem2,\n )\n\n // Create error object\n const error: PcbComponentOverlapError = {\n type: \"pcb_footprint_overlap_error\",\n pcb_error_id: `pcb_footprint_overlap_${id1}_${id2}`,\n error_type: \"pcb_footprint_overlap_error\",\n message: `${elem1.type} ${elem1Description} overlaps with ${elem2.type} ${elem2Description}`,\n pcb_component_ids: [\n elem1.pcb_component_id,\n elem2.pcb_component_id,\n ].filter((id): id is string => Boolean(id)),\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 { getBoundsOfPcbElements } from \"@tscircuit/circuit-json-util\"\nimport { doBoundsOverlap } from \"@tscircuit/math-utils\"\nimport type {\n PCBKeepout,\n PcbCourtyardCircle,\n PcbCourtyardOutline,\n PcbCourtyardPolygon,\n PcbCourtyardRect,\n PcbHole,\n PcbPlatedHole,\n PcbSmtPad,\n} from \"circuit-json\"\nimport type { Collidable } from \"lib/check-each-pcb-trace-non-overlapping/getCollidableBounds\"\nimport { getRotatedRectPoints } from \"lib/check-each-pcb-trace-non-overlapping/segment-to-polygon-clearance\"\nimport { getPadToPadGap } from \"lib/check-pad-clearance/common\"\nimport { getLayersOfPcbElement } from \"lib/util/getLayersOfPcbElement\"\n\ntype CourtyardElement =\n | PcbCourtyardCircle\n | PcbCourtyardOutline\n | PcbCourtyardPolygon\n | PcbCourtyardRect\n\nexport type OverlappableElement =\n | PcbSmtPad\n | PcbPlatedHole\n | PcbHole\n | CourtyardElement\n\nconst isCourtyardElement = (\n element: OverlappableElement,\n): element is CourtyardElement =>\n element.type === \"pcb_courtyard_circle\" ||\n element.type === \"pcb_courtyard_outline\" ||\n element.type === \"pcb_courtyard_polygon\" ||\n element.type === \"pcb_courtyard_rect\"\n\nconst getCourtyardId = (courtyard: CourtyardElement): string => {\n switch (courtyard.type) {\n case \"pcb_courtyard_circle\":\n return courtyard.pcb_courtyard_circle_id\n case \"pcb_courtyard_outline\":\n return courtyard.pcb_courtyard_outline_id\n case \"pcb_courtyard_polygon\":\n return courtyard.pcb_courtyard_polygon_id\n case \"pcb_courtyard_rect\":\n return courtyard.pcb_courtyard_rect_id\n }\n}\n\n/**\n * Reuse the copper-clearance geometry for plated-hole/courtyard checks.\n * Rectangular courtyards become polygons so their rotation is preserved.\n */\nconst courtyardToKeepout = (courtyard: CourtyardElement): PCBKeepout => {\n const common = {\n type: \"pcb_keepout\" as const,\n pcb_keepout_id: getCourtyardId(courtyard),\n layers: [courtyard.layer],\n }\n\n if (courtyard.type === \"pcb_courtyard_circle\") {\n return {\n ...common,\n shape: \"circle\",\n center: courtyard.center,\n radius: courtyard.radius,\n }\n }\n\n const outline =\n courtyard.type === \"pcb_courtyard_rect\"\n ? getRotatedRectPoints({\n x: courtyard.center.x,\n y: courtyard.center.y,\n width: courtyard.width,\n height: courtyard.height,\n ccwRotation: courtyard.ccw_rotation ?? 0,\n })\n : courtyard.type === \"pcb_courtyard_polygon\"\n ? courtyard.points\n : courtyard.outline\n\n return {\n ...common,\n shape: \"outline\",\n outline,\n stroke_width: 0,\n }\n}\n\nfunction getElementLayers(elem: OverlappableElement): string[] {\n if (isCourtyardElement(elem)) {\n return [elem.layer]\n }\n\n return getLayersOfPcbElement(elem as Collidable)\n}\n\nfunction doLayersOverlap(layers1: string[], layers2: string[]): boolean {\n if (layers1.length === 0 || layers2.length === 0) return true\n return layers1.some((l) => layers2.includes(l))\n}\n\nexport function doPcbElementsOverlap(\n elem1: OverlappableElement,\n elem2: OverlappableElement,\n): boolean {\n // If the elements are on completely different layers they cannot overlap\n const layers1 = getElementLayers(elem1)\n const layers2 = getElementLayers(elem2)\n if (!doLayersOverlap(layers1, layers2)) return false\n\n if (elem1.type === \"pcb_smtpad\" && elem2.type === \"pcb_smtpad\") {\n return getPadToPadGap(elem1, elem2) <= 0\n }\n\n if (elem1.type === \"pcb_plated_hole\" && isCourtyardElement(elem2)) {\n return getPadToPadGap(elem1, courtyardToKeepout(elem2)) <= 0\n }\n\n if (isCourtyardElement(elem1) && elem2.type === \"pcb_plated_hole\") {\n return getPadToPadGap(elem2, courtyardToKeepout(elem1)) <= 0\n }\n\n const bounds1 = getBoundsOfPcbElements([elem1])\n const bounds2 = getBoundsOfPcbElements([elem2])\n return doBoundsOverlap(bounds1, bounds2)\n}\n","import type {\n AnyCircuitElement,\n PcbComponent,\n PcbComponentMissingCourtyardWarning,\n} from \"circuit-json\"\nimport { getReadableNameForComponent } from \"./util/get-readable-names\"\n\nconst courtyardTypes = new Set([\n \"pcb_courtyard_circle\",\n \"pcb_courtyard_outline\",\n \"pcb_courtyard_polygon\",\n \"pcb_courtyard_pill\",\n \"pcb_courtyard_rect\",\n])\n\n/** Returns warnings for PCB components without courtyards, excluding manually placed vias. */\nexport function checkPcbComponentsMissingCourtyard(\n circuitJson: AnyCircuitElement[],\n): PcbComponentMissingCourtyardWarning[] {\n const manuallyPlacedViaSourceIds = new Set(\n circuitJson\n .filter((element) => element.type === \"source_manually_placed_via\")\n .map((element) => element.source_manually_placed_via_id),\n )\n const componentIdsWithCourtyards = new Set(\n circuitJson\n .filter((element) => courtyardTypes.has(element.type))\n .flatMap((element) =>\n \"pcb_component_id\" in element && element.pcb_component_id\n ? [element.pcb_component_id]\n : [],\n ),\n )\n\n return circuitJson\n .filter(\n (element): element is PcbComponent => element.type === \"pcb_component\",\n )\n .filter(\n (component) =>\n !componentIdsWithCourtyards.has(component.pcb_component_id) &&\n (!component.source_component_id ||\n !manuallyPlacedViaSourceIds.has(component.source_component_id)),\n )\n .map((component) => {\n const sourceComponent = component.source_component_id\n ? circuitJson.find(\n (element) =>\n element.type === \"source_component\" &&\n element.source_component_id === component.source_component_id,\n )\n : undefined\n const componentName =\n sourceComponent?.type === \"source_component\"\n ? sourceComponent.name\n : getReadableNameForComponent(circuitJson, component.pcb_component_id)\n\n return {\n type: \"pcb_component_missing_courtyard_warning\" as const,\n pcb_component_missing_courtyard_warning_id: `pcb_component_missing_courtyard_warning_${component.pcb_component_id}`,\n warning_type: \"pcb_component_missing_courtyard_warning\" as const,\n message: `${componentName} has no courtyard`,\n pcb_component_id: component.pcb_component_id,\n source_component_id: component.source_component_id,\n subcircuit_id: component.subcircuit_id,\n }\n })\n}\n","import type { PcbTrace } from \"circuit-json\"\n\n/** Use the router's length when supplied; otherwise measure the route in mm.\n * Via depth defaults to 1.6mm, matching the existing trace length check.\n */\nexport const getPcbTraceLength = (trace: PcbTrace): number => {\n if (trace.trace_length !== undefined) return trace.trace_length\n let length = 0\n let previousEnd: { x: number; y: number } | undefined\n for (const point of trace.route) {\n const start = point.route_type === \"through_pad\" ? point.start : point\n if (previousEnd)\n length += Math.hypot(start.x - previousEnd.x, start.y - previousEnd.y)\n if (point.route_type === \"via\") length += 1.6\n if (point.route_type === \"through_pad\") {\n length += Math.hypot(\n point.end.x - point.start.x,\n point.end.y - point.start.y,\n )\n previousEnd = point.end\n } else {\n previousEnd = point\n }\n }\n return length\n}\n","import { getPcbTraceLength } from \"./util/get-pcb-trace-length\"\nimport type {\n AnyCircuitElement,\n PcbPort,\n PcbTrace,\n PcbTraceTooLongError,\n SourceTrace,\n} from \"circuit-json\"\n\nconst getReferencedPcbPortIds = (pcbTrace: PcbTrace): Set<string> => {\n const pcbPortIds = new Set<string>()\n\n for (const routePoint of pcbTrace.route) {\n if (routePoint.route_type !== \"wire\") continue\n if (routePoint.start_pcb_port_id) {\n pcbPortIds.add(routePoint.start_pcb_port_id)\n }\n if (routePoint.end_pcb_port_id) {\n pcbPortIds.add(routePoint.end_pcb_port_id)\n }\n }\n\n return pcbPortIds\n}\n\nexport const getPcbTracesBySourceTraceId = (\n circuitJson: AnyCircuitElement[],\n) => {\n const sourceTraces = circuitJson.filter(\n (element): element is SourceTrace => element.type === \"source_trace\",\n )\n const pcbTraces = circuitJson.filter(\n (element): element is PcbTrace => element.type === \"pcb_trace\",\n )\n const pcbPorts = circuitJson.filter(\n (element): element is PcbPort => element.type === \"pcb_port\",\n )\n\n const pcbPortIdsBySourcePortId = new Map<string, Set<string>>()\n for (const pcbPort of pcbPorts) {\n if (!pcbPort.source_port_id) continue\n const pcbPortIds =\n pcbPortIdsBySourcePortId.get(pcbPort.source_port_id) ?? new Set<string>()\n pcbPortIds.add(pcbPort.pcb_port_id)\n pcbPortIdsBySourcePortId.set(pcbPort.source_port_id, pcbPortIds)\n }\n\n const pcbTracesBySourceTraceId = new Map<string, PcbTrace[]>()\n for (const pcbTrace of pcbTraces) {\n if (!pcbTrace.source_trace_id) continue\n const matchingPcbTraces =\n pcbTracesBySourceTraceId.get(pcbTrace.source_trace_id) ?? []\n matchingPcbTraces.push(pcbTrace)\n pcbTracesBySourceTraceId.set(pcbTrace.source_trace_id, matchingPcbTraces)\n }\n\n const exactEndpointPcbTraceIdsBySourceTraceId = new Map<string, Set<string>>()\n for (const sourceTrace of sourceTraces) {\n if (sourceTrace.connected_source_port_ids.length !== 2) continue\n\n const endpointPcbPortIds = sourceTrace.connected_source_port_ids.map(\n (sourcePortId) => pcbPortIdsBySourcePortId.get(sourcePortId),\n )\n if (endpointPcbPortIds.some((pcbPortIds) => !pcbPortIds?.size)) continue\n\n const exactEndpointPcbTraceIds = new Set(\n (pcbTracesBySourceTraceId.get(sourceTrace.source_trace_id) ?? [])\n .filter((pcbTrace) => {\n const referencedPcbPortIds = getReferencedPcbPortIds(pcbTrace)\n return endpointPcbPortIds.every((pcbPortIds) =>\n [...pcbPortIds!].some((pcbPortId) =>\n referencedPcbPortIds.has(pcbPortId),\n ),\n )\n })\n .map((pcbTrace) => pcbTrace.pcb_trace_id),\n )\n\n // Keep the existing behavior when the route does not expose one PCB trace\n // joining both explicit endpoints (for example through-pad-only routes).\n if (exactEndpointPcbTraceIds.size > 0) {\n exactEndpointPcbTraceIdsBySourceTraceId.set(\n sourceTrace.source_trace_id,\n exactEndpointPcbTraceIds,\n )\n }\n }\n for (const [id, exactIds] of exactEndpointPcbTraceIdsBySourceTraceId) {\n pcbTracesBySourceTraceId.set(\n id,\n pcbTracesBySourceTraceId\n .get(id)!\n .filter((trace) => exactIds.has(trace.pcb_trace_id)),\n )\n }\n return pcbTracesBySourceTraceId\n}\n\nexport const checkPcbTraceLengths = (\n circuitJson: AnyCircuitElement[],\n): PcbTraceTooLongError[] => {\n const sourceTracesById = new Map(\n circuitJson\n .filter((e): e is SourceTrace => e.type === \"source_trace\")\n .map((e) => [e.source_trace_id, e]),\n )\n const pcbTracesBySourceTraceId = getPcbTracesBySourceTraceId(circuitJson)\n const errors: PcbTraceTooLongError[] = []\n\n for (const [sourceTraceId, pcbTraces] of pcbTracesBySourceTraceId) {\n const pcbTrace = pcbTraces[0]!\n const sourceTrace = sourceTracesById.get(sourceTraceId)\n if (!sourceTrace) continue\n\n const maximumTraceLength = sourceTrace.max_length\n if (typeof maximumTraceLength !== \"number\") continue\n\n const actualTraceLength = pcbTraces.reduce(\n (sum, trace) => sum + getPcbTraceLength(trace),\n 0,\n )\n if (actualTraceLength <= maximumTraceLength + 1e-9) continue\n\n errors.push({\n type: \"pcb_trace_too_long_error\",\n pcb_trace_too_long_error_id: `pcb_trace_too_long_error_${pcbTrace.pcb_trace_id}`,\n error_type: \"pcb_trace_too_long_error\",\n message: `PCB trace is ${actualTraceLength.toFixed(2)}mm long, exceeding the ${maximumTraceLength}mm maximum`,\n pcb_trace_id: pcbTrace.pcb_trace_id,\n source_trace_id: sourceTrace.source_trace_id,\n source_net_id: sourceTrace.connected_source_net_ids[0],\n actual_trace_length: actualTraceLength,\n maximum_trace_length: maximumTraceLength,\n subcircuit_id: pcbTrace.subcircuit_id ?? sourceTrace.subcircuit_id,\n })\n }\n\n return errors\n}\n","import type {\n AnyCircuitElement,\n PcbPort,\n PcbTrace,\n PcbTraceError,\n SourceTrace,\n} from \"circuit-json\"\n\n/** Return a routing error when a source trace exceeds its maximum via count. */\nexport const checkPcbTraceViaCounts = (\n circuitJson: AnyCircuitElement[],\n): PcbTraceError[] => {\n const sourceTraces = circuitJson.filter(\n (element): element is SourceTrace => element.type === \"source_trace\",\n )\n const pcbTraces = circuitJson.filter(\n (element): element is PcbTrace => element.type === \"pcb_trace\",\n )\n const pcbPorts = circuitJson.filter(\n (element): element is PcbPort => element.type === \"pcb_port\",\n )\n const errors: PcbTraceError[] = []\n\n for (const sourceTrace of sourceTraces) {\n const maximumViaCount = sourceTrace.max_via_count\n if (typeof maximumViaCount !== \"number\") continue\n\n const routedPcbTraces = pcbTraces.filter(\n (pcbTrace) => pcbTrace.source_trace_id === sourceTrace.source_trace_id,\n )\n if (routedPcbTraces.length === 0) continue\n\n const actualViaCount = routedPcbTraces.reduce(\n (viaCount, pcbTrace) =>\n viaCount +\n pcbTrace.route.filter((routePoint) => routePoint.route_type === \"via\")\n .length,\n 0,\n )\n if (actualViaCount <= maximumViaCount) continue\n\n const connectedPcbPorts = pcbPorts.filter(\n (pcbPort) =>\n pcbPort.source_port_id !== undefined &&\n sourceTrace.connected_source_port_ids.includes(pcbPort.source_port_id),\n )\n errors.push({\n type: \"pcb_trace_error\",\n pcb_trace_error_id: `max_via_count_exceeded_${sourceTrace.source_trace_id}`,\n error_type: \"pcb_trace_error\",\n message: `PCB trace uses ${actualViaCount} vias, exceeding the ${maximumViaCount} maximum`,\n pcb_trace_id: routedPcbTraces[0]!.pcb_trace_id,\n source_trace_id: sourceTrace.source_trace_id,\n pcb_component_ids: [\n ...new Set(\n connectedPcbPorts\n .map((pcbPort) => pcbPort.pcb_component_id)\n .filter(\n (pcbComponentId): pcbComponentId is string =>\n pcbComponentId !== undefined,\n ),\n ),\n ],\n pcb_port_ids: connectedPcbPorts.map((pcbPort) => pcbPort.pcb_port_id),\n subcircuit_id:\n routedPcbTraces[0]!.subcircuit_id ?? sourceTrace.subcircuit_id,\n })\n }\n\n return errors\n}\n","import {\n getPrimaryId,\n getReadableNameForElement,\n} from \"@tscircuit/circuit-json-util\"\nimport type { AnyCircuitElement, PcbPadPadClearanceError } from \"circuit-json\"\nimport { formatMm } from \"format-si-unit\"\nimport {\n type ConnectivityMap,\n getFullConnectivityMapFromCircuitJson,\n} from \"circuit-json-to-connectivity-map\"\nimport { SpatialObjectIndex } from \"lib/data-structures/SpatialIndex\"\nimport { EPSILON, getBoardDrcValue, getPcbBoard } from \"lib/drc-defaults\"\nimport { getLayersOfPcbElement } from \"lib/util/getLayersOfPcbElement\"\nimport {\n type PadElement,\n getPadBounds,\n getPadCenter,\n getPadToPadGap,\n getPads,\n} from \"./check-pad-clearance/common\"\nimport { jlcMinTolerances } from \"@tscircuit/jlcpcb-manufacturing-specs\"\n\nexport function checkPadPadClearance(\n circuitJson: AnyCircuitElement[],\n {\n connMap,\n minClearance,\n }: { connMap?: ConnectivityMap; minClearance?: number } = {},\n): PcbPadPadClearanceError[] {\n const pads = getPads(circuitJson)\n if (pads.length < 2) return []\n\n const board = getPcbBoard(circuitJson)\n minClearance ??=\n getBoardDrcValue(board, \"min_pad_edge_to_pad_edge_clearance\") ??\n jlcMinTolerances.min_pad_edge_to_pad_edge_clearance\n connMap ??= getFullConnectivityMapFromCircuitJson(circuitJson)\n const spatialIndex = new SpatialObjectIndex<PadElement>({\n objects: pads,\n getBounds: getPadBounds,\n getId: (pad) => getPrimaryId(pad),\n })\n\n const errors = new Map<string, PcbPadPadClearanceError>()\n\n for (const padA of pads) {\n const padAId = getPrimaryId(padA)\n const nearbyPads = spatialIndex.getObjectsInBounds(\n getPadBounds(padA),\n minClearance,\n )\n\n for (const padB of nearbyPads) {\n const padBId = getPrimaryId(padB)\n if (padAId === padBId) continue\n if (\n !getLayersOfPcbElement(padA as any).some((layer) =>\n getLayersOfPcbElement(padB as any).includes(layer),\n )\n ) {\n continue\n }\n if (connMap.areIdsConnected(padAId, padBId)) continue\n\n const pairId = [padAId, padBId].sort().join(\"_\")\n const gap = getPadToPadGap(padA, padB)\n if (gap + EPSILON >= minClearance!) continue\n const centerA = getPadCenter(padA)\n const centerB = getPadCenter(padB)\n\n const nextError: PcbPadPadClearanceError = {\n type: \"pcb_pad_pad_clearance_error\",\n pcb_pad_pad_clearance_error_id: `pad_pad_clearance_${pairId}`,\n error_type: \"pcb_pad_pad_clearance_error\",\n message: `Pads ${getReadableNameForElement(circuitJson, padAId)} and ${getReadableNameForElement(circuitJson, padBId)} are too close (clearance: ${formatMm(gap)}, minimum: ${formatMm(minClearance!)})`,\n pcb_pad_ids: [padAId, padBId] as [string, string],\n minimum_clearance: minClearance,\n actual_clearance: gap,\n center: {\n x: (centerA.x + centerB.x) / 2,\n y: (centerA.y + centerB.y) / 2,\n },\n }\n\n if (!errors.has(pairId)) {\n errors.set(pairId, nextError)\n }\n }\n }\n\n return Array.from(errors.values())\n}\n","import {\n getPrimaryId,\n getReadableNameForElement,\n} from \"@tscircuit/circuit-json-util\"\nimport { jlcMinTolerances } from \"@tscircuit/jlcpcb-manufacturing-specs\"\nimport type { AnyCircuitElement, PcbPadTraceClearanceError } from \"circuit-json\"\nimport { formatMm } from \"format-si-unit\"\nimport {\n type ConnectivityMap,\n getFullConnectivityMapFromCircuitJson,\n} from \"circuit-json-to-connectivity-map\"\nimport { getCollidableBounds } from \"lib/check-each-pcb-trace-non-overlapping/getCollidableBounds\"\nimport { SpatialObjectIndex } from \"lib/data-structures/SpatialIndex\"\nimport { EPSILON, getBoardDrcValue, getPcbBoard } from \"lib/drc-defaults\"\nimport { getLayersOfPcbElement } from \"lib/util/getLayersOfPcbElement\"\nimport {\n type PadElement,\n getPadBounds,\n getPads,\n getTraceObstacleClearance,\n getTraceSegments,\n isTraceObstacleOverlap,\n} from \"./check-pad-clearance/common\"\n\nexport function checkPadTraceClearance(\n circuitJson: AnyCircuitElement[],\n {\n connMap,\n minClearance,\n }: { connMap?: ConnectivityMap; minClearance?: number } = {},\n): PcbPadTraceClearanceError[] {\n const pads = getPads(circuitJson)\n const segments = getTraceSegments(circuitJson)\n if (pads.length === 0 || segments.length === 0) return []\n\n const board = getPcbBoard(circuitJson)\n minClearance ??=\n getBoardDrcValue(board, \"min_trace_to_pad_edge_clearance\") ??\n jlcMinTolerances.min_trace_to_pad_edge_clearance\n connMap ??= getFullConnectivityMapFromCircuitJson(circuitJson)\n const spatialIndex = new SpatialObjectIndex<PadElement>({\n objects: pads,\n getBounds: getPadBounds,\n getId: (pad) => getPrimaryId(pad),\n })\n\n const errors = new Map<\n string,\n { error: PcbPadTraceClearanceError; gap: number }\n >()\n const overlappingPairIds = new Set<string>()\n\n for (const segment of segments) {\n const nearbyPads = spatialIndex.getObjectsInBounds(\n getCollidableBounds(segment),\n minClearance! + segment.thickness / 2,\n )\n\n for (const pad of nearbyPads) {\n const padId = getPrimaryId(pad)\n if (!getLayersOfPcbElement(pad as any).includes(segment.layer)) continue\n if (connMap.areIdsConnected(segment.pcb_trace_id, padId)) continue\n const pairId = `${padId}_${segment.pcb_trace_id}`\n const { gap, center } = getTraceObstacleClearance(segment, pad)\n if (isTraceObstacleOverlap(gap)) {\n errors.delete(pairId)\n overlappingPairIds.add(pairId)\n continue\n }\n if (overlappingPairIds.has(pairId)) continue\n if (gap + EPSILON >= minClearance!) continue\n\n const nextError: PcbPadTraceClearanceError = {\n type: \"pcb_pad_trace_clearance_error\" as const,\n pcb_pad_trace_clearance_error_id: `pad_trace_clearance_${pairId}`,\n error_type: \"pcb_pad_trace_clearance_error\",\n message: `Pad ${getReadableNameForElement(circuitJson, padId)} and trace ${getReadableNameForElement(circuitJson, segment.pcb_trace_id)} are too close (clearance: ${formatMm(gap)}, minimum: ${formatMm(minClearance!)})`,\n pcb_pad_id: padId,\n pcb_trace_id: segment.pcb_trace_id,\n minimum_clearance: minClearance,\n actual_clearance: gap,\n center,\n }\n\n const current = errors.get(pairId)\n if (!current || gap < current.gap) {\n errors.set(pairId, { error: nextError, gap })\n }\n }\n }\n\n return Array.from(errors.values()).map(({ error }) => error)\n}\n","import { getReadableNameForElement } from \"@tscircuit/circuit-json-util\"\nimport { jlcMinTolerances } from \"@tscircuit/jlcpcb-manufacturing-specs\"\nimport type {\n AnyCircuitElement,\n PcbVia,\n PcbViaTraceClearanceError,\n} from \"circuit-json\"\nimport { formatMm } from \"format-si-unit\"\nimport {\n type ConnectivityMap,\n getFullConnectivityMapFromCircuitJson,\n} from \"circuit-json-to-connectivity-map\"\nimport { EPSILON, getBoardDrcValue, getPcbBoard } from \"lib/drc-defaults\"\nimport { getLayersOfPcbElement } from \"lib/util/getLayersOfPcbElement\"\nimport {\n getTraceObstacleClearance,\n getTraceSegments,\n isTraceObstacleOverlap,\n} from \"./check-pad-clearance/common\"\n\nexport function checkViaTraceClearance(\n circuitJson: AnyCircuitElement[],\n {\n connMap,\n minClearance,\n }: { connMap?: ConnectivityMap; minClearance?: number } = {},\n): PcbViaTraceClearanceError[] {\n const vias = circuitJson.filter((el) => el.type === \"pcb_via\") as PcbVia[]\n const segments = getTraceSegments(circuitJson)\n if (vias.length === 0 || segments.length === 0) return []\n\n const board = getPcbBoard(circuitJson)\n minClearance ??=\n getBoardDrcValue(board, \"min_trace_to_pad_edge_clearance\") ??\n jlcMinTolerances.min_trace_to_pad_edge_clearance\n connMap ??= getFullConnectivityMapFromCircuitJson(circuitJson)\n const errors = new Map<\n string,\n { error: PcbViaTraceClearanceError; gap: number }\n >()\n const overlappingPairIds = new Set<string>()\n\n for (const via of vias) {\n for (const segment of segments) {\n if (!getLayersOfPcbElement(via).includes(segment.layer)) continue\n if (connMap.areIdsConnected(segment.pcb_trace_id, via.pcb_via_id))\n continue\n\n const pairId = `${via.pcb_via_id}_${segment.pcb_trace_id}`\n const { gap, center } = getTraceObstacleClearance(segment, via)\n if (isTraceObstacleOverlap(gap)) {\n errors.delete(pairId)\n overlappingPairIds.add(pairId)\n continue\n }\n if (overlappingPairIds.has(pairId)) continue\n if (gap + EPSILON >= minClearance!) continue\n\n const nextError: PcbViaTraceClearanceError = {\n type: \"pcb_via_trace_clearance_error\",\n pcb_via_trace_clearance_error_id: `via_trace_clearance_${pairId}`,\n error_type: \"pcb_via_trace_clearance_error\",\n message: `Via ${getReadableNameForElement(circuitJson, via.pcb_via_id)} and trace ${getReadableNameForElement(circuitJson, segment.pcb_trace_id)} are too close (clearance: ${formatMm(gap)}, minimum: ${formatMm(minClearance!)})`,\n pcb_via_id: via.pcb_via_id,\n pcb_trace_id: segment.pcb_trace_id,\n minimum_clearance: minClearance,\n actual_clearance: gap,\n center,\n }\n\n const current = errors.get(pairId)\n if (!current || gap < current.gap) {\n errors.set(pairId, { error: nextError, gap })\n }\n }\n }\n\n return Array.from(errors.values()).map(({ error }) => error)\n}\n","import {\n getPrimaryId,\n getReadableNameForElement,\n} from \"@tscircuit/circuit-json-util\"\nimport { jlcMinTolerances } from \"@tscircuit/jlcpcb-manufacturing-specs\"\nimport type {\n AnyCircuitElement,\n PcbPadPadClearanceError,\n PcbVia,\n} from \"circuit-json\"\nimport { formatMm } from \"format-si-unit\"\nimport {\n type ConnectivityMap,\n getFullConnectivityMapFromCircuitJson,\n} from \"circuit-json-to-connectivity-map\"\nimport { SpatialObjectIndex } from \"lib/data-structures/SpatialIndex\"\nimport { EPSILON, getBoardDrcValue, getPcbBoard } from \"lib/drc-defaults\"\nimport { getLayersOfPcbElement } from \"lib/util/getLayersOfPcbElement\"\nimport {\n type PadElement,\n getPadBounds,\n getViaPadClearanceCenter,\n getPadToPadGap,\n getPads,\n} from \"./check-pad-clearance/common\"\n\nexport function checkViaPadClearance(\n circuitJson: AnyCircuitElement[],\n {\n connMap,\n minClearance,\n }: { connMap?: ConnectivityMap; minClearance?: number } = {},\n): PcbPadPadClearanceError[] {\n const vias = circuitJson.filter(\n (element): element is PcbVia => element.type === \"pcb_via\",\n )\n const pads = getPads(circuitJson)\n if (vias.length === 0 || pads.length === 0) return []\n\n const board = getPcbBoard(circuitJson)\n const requiredClearance =\n minClearance ??\n getBoardDrcValue(board, \"min_pad_edge_to_pad_edge_clearance\") ??\n jlcMinTolerances.min_pad_edge_to_pad_edge_clearance!\n connMap ??= getFullConnectivityMapFromCircuitJson(circuitJson)\n\n const padIndex = new SpatialObjectIndex<PadElement>({\n objects: pads,\n getBounds: getPadBounds,\n getId: getPrimaryId,\n })\n const errors: PcbPadPadClearanceError[] = []\n\n for (const via of vias) {\n const nearbyPads = padIndex.getObjectsInBounds(\n getPadBounds(via),\n requiredClearance,\n )\n\n for (const pad of nearbyPads) {\n const padId = getPrimaryId(pad)\n if (\n !getLayersOfPcbElement(via).some((layer) =>\n getLayersOfPcbElement(pad).includes(layer),\n )\n ) {\n continue\n }\n if (connMap.areIdsConnected(via.pcb_via_id, padId)) continue\n\n const gap = getPadToPadGap(via, pad)\n if (gap + EPSILON >= requiredClearance) continue\n\n errors.push({\n type: \"pcb_pad_pad_clearance_error\",\n pcb_pad_pad_clearance_error_id: `via_pad_clearance_${via.pcb_via_id}_${padId}`,\n error_type: \"pcb_pad_pad_clearance_error\",\n message: `Via ${getReadableNameForElement(circuitJson, via.pcb_via_id)} and pad ${getReadableNameForElement(circuitJson, padId)} are too close (clearance: ${formatMm(gap)}, minimum: ${formatMm(requiredClearance)})`,\n pcb_pad_ids: [via.pcb_via_id, padId],\n minimum_clearance: requiredClearance,\n actual_clearance: gap,\n center: getViaPadClearanceCenter(via, pad),\n })\n }\n }\n\n return errors\n}\n","import { getPrimaryId } from \"@tscircuit/circuit-json-util\"\nimport type { AnyCircuitElement, PcbPlacementError, PcbVia } from \"circuit-json\"\nimport { getFullConnectivityMapFromCircuitJson } from \"circuit-json-to-connectivity-map\"\nimport {\n type PadElement,\n getPadBounds,\n getPadToPadGap,\n getPads,\n} from \"./check-pad-clearance/common\"\nimport { SpatialObjectIndex } from \"./data-structures/SpatialIndex\"\nimport { getPcbBoard } from \"./drc-defaults\"\nimport { getLayersOfPcbElement } from \"./util/getLayersOfPcbElement\"\nimport { getReadableNameForFootprintPad } from \"./util/get-readable-names\"\n\nexport function checkViasInPads(\n circuitJson: AnyCircuitElement[],\n): PcbPlacementError[] {\n const board = getPcbBoard(circuitJson)\n if (\n board &&\n \"is_via_in_pad_allowed\" in board &&\n board.is_via_in_pad_allowed === true\n ) {\n return []\n }\n\n const vias = circuitJson.filter(\n (element): element is PcbVia => element.type === \"pcb_via\",\n )\n const pads = getPads(circuitJson)\n if (vias.length === 0 || pads.length === 0) return []\n const connMap = getFullConnectivityMapFromCircuitJson(circuitJson)\n\n const padOrdinals = new Map(\n pads.map((pad, index) => [getPrimaryId(pad), index]),\n )\n const padIndex = new SpatialObjectIndex<PadElement>({\n objects: pads,\n getBounds: getPadBounds,\n getId: getPrimaryId,\n })\n const errors: PcbPlacementError[] = []\n\n for (const via of vias) {\n const nearbyPads = padIndex.getObjectsInBounds(getPadBounds(via))\n\n for (const pad of nearbyPads) {\n const padId = getPrimaryId(pad)\n const viaLayers = getLayersOfPcbElement(via)\n const padLayers = getLayersOfPcbElement(pad)\n if (!viaLayers.some((layer) => padLayers.includes(layer))) continue\n if (connMap.areIdsConnected(via.pcb_via_id, padId)) continue\n if (getPadToPadGap(via, pad) > 0) continue\n\n const padOrdinal = padOrdinals.get(padId) ?? 0\n const padName = getReadableNameForFootprintPad(\n circuitJson,\n pad,\n padOrdinal,\n )\n\n errors.push({\n type: \"pcb_placement_error\",\n pcb_placement_error_id: `via_in_pad_${via.pcb_via_id}_${padId}`,\n error_type: \"pcb_placement_error\",\n message: `Via copper at (${via.x.toFixed(2)}mm, ${via.y.toFixed(2)}mm) overlaps ${padName}`,\n subcircuit_id: via.subcircuit_id ?? pad.subcircuit_id,\n })\n }\n }\n\n return errors\n}\n","import type { AnyCircuitElement } from \"circuit-json\"\n\ntype DrcRecord = AnyCircuitElement & Record<string, unknown>\n\n/**\n * Removes generic pcb_trace_error records when a more specific pad-trace or\n * via-trace clearance error describes the same physical pair.\n *\n * The specific record is retained because it includes the measured and\n * required clearance. Trace-trace and all other generic errors are untouched.\n *\n * @deprecated Aggregate runners now classify trace-obstacle pairs as either\n * overlap or clearance before combining results, so they no longer need this\n * post-processing step. Kept for callers combining results from older checks.\n */\nexport const dedupePcbDrcErrors = <T extends AnyCircuitElement>(\n errors: T[],\n): T[] => {\n const specificallyReportedPairIds = new Set<string>()\n\n for (const error of errors as DrcRecord[]) {\n if (\n error.type === \"pcb_pad_trace_clearance_error\" &&\n typeof error.pcb_trace_id === \"string\" &&\n typeof error.pcb_pad_id === \"string\"\n ) {\n specificallyReportedPairIds.add(\n `overlap_${error.pcb_trace_id}_${error.pcb_pad_id}`,\n )\n }\n\n if (\n error.type === \"pcb_via_trace_clearance_error\" &&\n typeof error.pcb_trace_id === \"string\" &&\n typeof error.pcb_via_id === \"string\"\n ) {\n specificallyReportedPairIds.add(\n `overlap_${error.pcb_trace_id}_${error.pcb_via_id}`,\n )\n }\n }\n\n return errors.filter((element) => {\n const error = element as DrcRecord\n return !(\n error.type === \"pcb_trace_error\" &&\n typeof error.pcb_trace_error_id === \"string\" &&\n specificallyReportedPairIds.has(error.pcb_trace_error_id)\n )\n })\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 {\n type AnyCircuitElement,\n type SchematicPort,\n type SourceComponentMisconfiguredError,\n type SourcePort,\n type SourceSimplePushButton,\n type SourceSimpleSwitch,\n source_component_misconfigured_error,\n} from \"circuit-json\"\n\ntype SwitchingComponent = SourceSimplePushButton | SourceSimpleSwitch\n\nexport function checkTwoTerminalSwitchContactsOnDifferentNets(\n circuitJson: AnyCircuitElement[],\n): SourceComponentMisconfiguredError[] {\n const switchingComponents = circuitJson.filter(\n (element): element is SwitchingComponent =>\n element.type === \"source_component\" &&\n (element.ftype === \"simple_push_button\" ||\n element.ftype === \"simple_switch\"),\n )\n const sourcePorts = circuitJson.filter(\n (element): element is SourcePort => element.type === \"source_port\",\n )\n const schematicPorts = circuitJson.filter(\n (element): element is SchematicPort => element.type === \"schematic_port\",\n )\n const errors: SourceComponentMisconfiguredError[] = []\n\n for (const switchingComponent of switchingComponents) {\n const schematicContactSourcePorts = schematicPorts.flatMap(\n (schematicPort) => {\n const sourcePort = sourcePorts.find(\n (sourcePort) =>\n sourcePort.source_port_id === schematicPort.source_port_id &&\n sourcePort.source_component_id ===\n switchingComponent.source_component_id,\n )\n if (!sourcePort) return []\n return [sourcePort]\n },\n )\n if (schematicContactSourcePorts.length !== 2) continue\n\n const firstContactConnectivityKey =\n schematicContactSourcePorts[0].subcircuit_connectivity_map_key\n const secondContactConnectivityKey =\n schematicContactSourcePorts[1].subcircuit_connectivity_map_key\n if (!firstContactConnectivityKey) continue\n if (firstContactConnectivityKey !== secondContactConnectivityKey) continue\n\n errors.push(\n source_component_misconfigured_error.parse({\n type: \"source_component_misconfigured_error\",\n message: `Switch ${switchingComponent.name} has both schematic contacts connected to the same net. Check internallyConnectedPins and the footprint pin mapping.`,\n source_component_ids: [switchingComponent.source_component_id],\n source_port_ids: schematicContactSourcePorts.map(\n (sourcePort) => sourcePort.source_port_id,\n ),\n is_fatal: true,\n }),\n )\n }\n\n return errors\n}\n","import { cju } from \"@tscircuit/circuit-json-util\"\nimport type {\n AnyCircuitElement,\n SourceComponentPinsUnderspecifiedWarning,\n SourcePinAttributes,\n SourcePort,\n SourceComponentBase,\n} from \"circuit-json\"\n\nconst PIN_ATTRIBUTE_KEYS = [\n \"must_be_connected\",\n \"provides_power\",\n \"requires_power\",\n \"provides_ground\",\n \"requires_ground\",\n \"provides_voltage\",\n \"requires_voltage\",\n \"do_not_connect\",\n \"include_in_board_pinout\",\n \"can_use_internal_pullup\",\n \"is_using_internal_pullup\",\n \"needs_external_pullup\",\n \"can_use_internal_pulldown\",\n \"is_using_internal_pulldown\",\n \"needs_external_pulldown\",\n \"can_use_open_drain\",\n \"is_using_open_drain\",\n \"can_use_push_pull\",\n \"is_using_push_pull\",\n \"should_have_decoupling_capacitor\",\n \"recommended_decoupling_capacitor_capacitance\",\n \"is_configured_for_i2c_sda\",\n \"is_configured_for_i2c_scl\",\n \"is_configured_for_spi_mosi\",\n \"is_configured_for_spi_miso\",\n \"is_configured_for_spi_sck\",\n \"is_configured_for_spi_cs\",\n \"is_configured_for_uart_tx\",\n \"is_configured_for_uart_rx\",\n \"supports_i2c_sda\",\n \"supports_i2c_scl\",\n \"supports_spi_mosi\",\n \"supports_spi_miso\",\n \"supports_spi_sck\",\n \"supports_spi_cs\",\n \"supports_uart_tx\",\n \"supports_uart_rx\",\n] as const satisfies readonly (keyof SourcePinAttributes)[]\n\nfunction hasAnyPinAttribute(port: SourcePort): boolean {\n return PIN_ATTRIBUTE_KEYS.some((key) => port[key] !== undefined)\n}\n\n/**\n * Check that each component with ports has at least one pin attribute\n * specified across its ports. Returns a warning when all pins are\n * underspecified (no SourcePinAttributes fields set on any port).\n */\nexport function checkAllPinsInComponentAreUnderspecified(\n circuitJson: AnyCircuitElement[],\n): SourceComponentPinsUnderspecifiedWarning[] {\n const warnings: SourceComponentPinsUnderspecifiedWarning[] = []\n const db = cju(circuitJson)\n\n const sourceComponents = db.source_component.list() as SourceComponentBase[]\n const sourcePorts = db.source_port.list() as SourcePort[]\n\n const portsByComponent = new Map<string, SourcePort[]>()\n for (const port of sourcePorts) {\n if (!port.source_component_id) continue\n const existing = portsByComponent.get(port.source_component_id) ?? []\n existing.push(port)\n portsByComponent.set(port.source_component_id, existing)\n }\n\n for (const component of sourceComponents) {\n if (component.ftype !== \"simple_chip\") continue\n\n const componentPorts =\n portsByComponent.get(component.source_component_id) ?? []\n if (componentPorts.length === 0) continue\n\n const hasAnySpecifiedAttributes = componentPorts.some((port) =>\n hasAnyPinAttribute(port),\n )\n\n if (hasAnySpecifiedAttributes) continue\n\n warnings.push({\n type: \"source_component_pins_underspecified_warning\",\n source_component_pins_underspecified_warning_id: `source_component_pins_underspecified_warning_${component.source_component_id}`,\n warning_type: \"source_component_pins_underspecified_warning\",\n message: `All pins on ${component.name} are underspecified (no pinAttributes set)`,\n source_component_id: component.source_component_id,\n source_port_ids: componentPorts.map((port) => port.source_port_id),\n subcircuit_id: componentPorts[0]?.subcircuit_id,\n })\n }\n\n return warnings\n}\n","import { cju } from \"@tscircuit/circuit-json-util\"\nimport type {\n AnyCircuitElement,\n SourceComponentBase,\n SourceNoPowerPinDefinedWarning,\n SourcePort,\n} from \"circuit-json\"\nimport { shouldCheckChipPowerGroundPins } from \"./util/should-check-chip-power-ground-pins\"\n\n/**\n * Check that each chip has at least one pin marked as requires_power=true.\n * Returns warnings for chips where no pin declares requires_power.\n */\nexport function checkNoPowerPinDefined(\n circuitJson: AnyCircuitElement[],\n): SourceNoPowerPinDefinedWarning[] {\n const warnings: SourceNoPowerPinDefinedWarning[] = []\n const db = cju(circuitJson)\n\n const sourceComponents = db.source_component.list() as SourceComponentBase[]\n const sourcePorts = db.source_port.list() as SourcePort[]\n\n const portsByComponent = new Map<string, SourcePort[]>()\n for (const port of sourcePorts) {\n if (!port.source_component_id) continue\n const existing = portsByComponent.get(port.source_component_id) ?? []\n existing.push(port)\n portsByComponent.set(port.source_component_id, existing)\n }\n\n for (const component of sourceComponents) {\n const componentPorts =\n portsByComponent.get(component.source_component_id) ?? []\n if (!shouldCheckChipPowerGroundPins(component, componentPorts)) continue\n\n const hasRequiredPowerPin = componentPorts.some(\n (port) => port.requires_power === true,\n )\n if (hasRequiredPowerPin) continue\n\n warnings.push({\n type: \"source_no_power_pin_defined_warning\",\n source_no_power_pin_defined_warning_id: `source_no_power_pin_defined_warning_${component.source_component_id}`,\n warning_type: \"source_no_power_pin_defined_warning\",\n message: `${component.name} has no pin with requires_power=true`,\n source_component_id: component.source_component_id,\n source_port_ids: componentPorts.map((port) => port.source_port_id),\n subcircuit_id: componentPorts[0]?.subcircuit_id,\n })\n }\n\n return warnings\n}\n","import type { SourceComponentBase, SourcePort } from \"circuit-json\"\n\n/**\n * Power and ground pin-role checks only apply when a chip exposes enough\n * connectable pins to define both roles. One-port passives such as chip\n * antennas can have additional package pads explicitly marked do-not-connect,\n * but cannot truthfully declare power and ground pins.\n */\nexport const shouldCheckChipPowerGroundPins = (\n component: SourceComponentBase,\n ports: SourcePort[],\n): boolean =>\n component.ftype === \"simple_chip\" &&\n ports.filter((port) => port.do_not_connect !== true).length >= 2\n","import { cju } from \"@tscircuit/circuit-json-util\"\nimport type {\n AnyCircuitElement,\n SourceComponentBase,\n SourceNoGroundPinDefinedWarning,\n SourcePort,\n} from \"circuit-json\"\nimport { shouldCheckChipPowerGroundPins } from \"./util/should-check-chip-power-ground-pins\"\n\n/**\n * Check that each chip has at least one pin marked as requires_ground=true.\n * Returns warnings for chips where no pin declares requires_ground.\n */\nexport function checkNoGroundPinDefined(\n circuitJson: AnyCircuitElement[],\n): SourceNoGroundPinDefinedWarning[] {\n const warnings: SourceNoGroundPinDefinedWarning[] = []\n const db = cju(circuitJson)\n\n const sourceComponents = db.source_component.list() as SourceComponentBase[]\n const sourcePorts = db.source_port.list() as SourcePort[]\n\n const portsByComponent = new Map<string, SourcePort[]>()\n for (const port of sourcePorts) {\n if (!port.source_component_id) continue\n const existing = portsByComponent.get(port.source_component_id) ?? []\n existing.push(port)\n portsByComponent.set(port.source_component_id, existing)\n }\n\n for (const component of sourceComponents) {\n const componentPorts =\n portsByComponent.get(component.source_component_id) ?? []\n if (!shouldCheckChipPowerGroundPins(component, componentPorts)) continue\n\n const hasRequiredGroundPin = componentPorts.some(\n (port) => port.requires_ground === true,\n )\n if (hasRequiredGroundPin) continue\n\n warnings.push({\n type: \"source_no_ground_pin_defined_warning\",\n source_no_ground_pin_defined_warning_id: `source_no_ground_pin_defined_warning_${component.source_component_id}`,\n warning_type: \"source_no_ground_pin_defined_warning\",\n message: `${component.name} has no pin with requires_ground=true`,\n source_component_id: component.source_component_id,\n source_port_ids: componentPorts.map((port) => port.source_port_id),\n subcircuit_id: componentPorts[0]?.subcircuit_id,\n })\n }\n\n return warnings\n}\n","import type {\n AnyCircuitElement,\n SchematicComponent,\n SchematicComponentStylingWarning,\n SchematicPort,\n} from \"circuit-json\"\n\ntype SourceComponent = Extract<AnyCircuitElement, { type: \"source_component\" }>\n\nconst DEFAULT_PIN_SPACING = 0.2\nconst MAX_VERTICAL_PADDING_IN_PIN_SPACINGS = 3\nconst FLOATING_POINT_TOLERANCE = 1e-9\n\ntype VerticalSide = \"top\" | \"bottom\"\n\n/**\n * Warns when the left/right pins of a box-style schematic component leave\n * excessive empty space above or below their vertical span. This commonly\n * happens when an unnecessarily large schematic height is set on a component.\n */\nexport function checkSchematicComponentExcessiveVerticalPadding(\n circuitJson: AnyCircuitElement[],\n): SchematicComponentStylingWarning[] {\n const schematicComponents = circuitJson.filter(\n (element): element is SchematicComponent =>\n element.type === \"schematic_component\",\n )\n const schematicPorts = circuitJson.filter(\n (element): element is SchematicPort => element.type === \"schematic_port\",\n )\n const sourceComponents = circuitJson.filter(\n (element): element is SourceComponent =>\n element.type === \"source_component\",\n )\n\n const sourceComponentById = new Map(\n sourceComponents.map((component) => [\n component.source_component_id,\n component,\n ]),\n )\n const portsByComponentId = new Map<string, SchematicPort[]>()\n\n for (const port of schematicPorts) {\n if (!port.schematic_component_id) continue\n const componentPorts =\n portsByComponentId.get(port.schematic_component_id) ?? []\n componentPorts.push(port)\n portsByComponentId.set(port.schematic_component_id, componentPorts)\n }\n\n const warnings: SchematicComponentStylingWarning[] = []\n\n for (const component of schematicComponents) {\n if (!component.is_box_with_pins || component.size.height <= 0) continue\n\n const sidePorts = (\n portsByComponentId.get(component.schematic_component_id) ?? []\n ).filter(\n (port) =>\n port.side_of_component === \"left\" || port.side_of_component === \"right\",\n )\n\n // A single side pin does not establish a meaningful vertical pin group.\n if (sidePorts.length < 2) continue\n\n const pinYs = sidePorts.map((port) => port.center.y)\n const highestPinY = Math.max(...pinYs)\n const lowestPinY = Math.min(...pinYs)\n const componentTopY = component.center.y + component.size.height / 2\n const componentBottomY = component.center.y - component.size.height / 2\n const pinSpacing = component.pin_spacing ?? DEFAULT_PIN_SPACING\n const maximumPadding = pinSpacing * MAX_VERTICAL_PADDING_IN_PIN_SPACINGS\n const paddingBySide: Record<VerticalSide, number> = {\n top: componentTopY - highestPinY,\n bottom: lowestPinY - componentBottomY,\n }\n\n const sourceComponent = component.source_component_id\n ? sourceComponentById.get(component.source_component_id)\n : undefined\n const componentName =\n sourceComponent?.name ?? component.schematic_component_id\n\n for (const side of [\"top\", \"bottom\"] as const) {\n const padding = paddingBySide[side]\n if (\n padding <= maximumPadding + FLOATING_POINT_TOLERANCE ||\n padding <= 0\n ) {\n continue\n }\n\n const relativePosition = side === \"top\" ? \"above\" : \"below\"\n const stylingIssueType = `excessive_${side}_padding`\n\n warnings.push({\n type: \"schematic_component_styling_warning\",\n schematic_component_styling_warning_id: `schematic_component_styling_warning_${component.schematic_component_id}_${stylingIssueType}`,\n warning_type: \"schematic_component_styling_warning\",\n message: `${componentName} has excessive empty space ${relativePosition} its pins (${padding.toFixed(2)}mm, more than ${MAX_VERTICAL_PADDING_IN_PIN_SPACINGS} pin spacings)`,\n schematic_component_id: component.schematic_component_id,\n styling_issue_type: stylingIssueType,\n schematic_port_ids: sidePorts.map((port) => port.schematic_port_id),\n source_component_id: component.source_component_id,\n schematic_sheet_id: component.schematic_sheet_id,\n subcircuit_id: component.subcircuit_id,\n })\n }\n }\n\n return warnings\n}\n","import type {\n AnyCircuitElement,\n SchematicComponent,\n SchematicComponentStylingWarning,\n SchematicText,\n} from \"circuit-json\"\n\ntype SourceComponent = Extract<AnyCircuitElement, { type: \"source_component\" }>\n\nconst isFallbackReferenceDesignator = (name: string) =>\n /^unnamed_[a-z0-9_-]+\\d+$/i.test(name)\n\nconst isTextWithinComponentBounds = (\n schematicText: SchematicText,\n schematicComponent: SchematicComponent,\n) => {\n const { center, size } = schematicComponent\n const tolerance = 1e-9\n\n return (\n schematicText.position.x >= center.x - size.width / 2 - tolerance &&\n schematicText.position.x <= center.x + size.width / 2 + tolerance &&\n schematicText.position.y >= center.y - size.height / 2 - tolerance &&\n schematicText.position.y <= center.y + size.height / 2 + tolerance\n )\n}\n\n/**\n * Warns when a schematic component does not have attached text displaying its\n * reference designator (or the component's display-name override).\n */\nexport function checkSchematicComponentMissingReferenceDesignatorText(\n circuitJson: AnyCircuitElement[],\n): SchematicComponentStylingWarning[] {\n const schematicComponents = circuitJson.filter(\n (element): element is SchematicComponent =>\n element.type === \"schematic_component\",\n )\n const sourceComponents = circuitJson.filter(\n (element): element is SourceComponent =>\n element.type === \"source_component\",\n )\n const schematicTexts = circuitJson.filter(\n (element): element is SchematicText => element.type === \"schematic_text\",\n )\n\n const sourceComponentById = new Map(\n sourceComponents.map((component) => [\n component.source_component_id,\n component,\n ]),\n )\n const textBySchematicComponentId = new Map<string, Set<string>>()\n const customSymbolTexts: SchematicText[] = []\n\n for (const schematicText of schematicTexts) {\n if (!schematicText.schematic_component_id) {\n if (schematicText.schematic_symbol_id) {\n customSymbolTexts.push(schematicText)\n }\n continue\n }\n\n const componentTexts =\n textBySchematicComponentId.get(schematicText.schematic_component_id) ??\n new Set<string>()\n componentTexts.add(schematicText.text.trim())\n textBySchematicComponentId.set(\n schematicText.schematic_component_id,\n componentTexts,\n )\n }\n\n const warnings: SchematicComponentStylingWarning[] = []\n\n for (const schematicComponent of schematicComponents) {\n // Named symbols provide their own reference text without schematic_text.\n if (schematicComponent.symbol_name) continue\n\n // Schematic boxes always provide their own reference designator.\n if (schematicComponent.is_box_with_pins) continue\n\n if (!schematicComponent.source_component_id) continue\n\n const sourceComponent = sourceComponentById.get(\n schematicComponent.source_component_id,\n )\n if (!sourceComponent) continue\n\n const referenceDesignators = new Set(\n [sourceComponent.name, sourceComponent.display_name]\n .map((name) => name?.trim())\n .filter((name): name is string => Boolean(name)),\n )\n const nonFallbackReferenceDesignator = [...referenceDesignators].find(\n (referenceDesignator) =>\n !isFallbackReferenceDesignator(referenceDesignator),\n )\n const componentTexts = textBySchematicComponentId.get(\n schematicComponent.schematic_component_id,\n )\n const hasReferenceDesignatorText =\n [...referenceDesignators].some((referenceDesignator) =>\n componentTexts?.has(referenceDesignator),\n ) ||\n customSymbolTexts.some(\n (schematicText) =>\n referenceDesignators.has(schematicText.text.trim()) &&\n isTextWithinComponentBounds(schematicText, schematicComponent),\n )\n\n if (nonFallbackReferenceDesignator && hasReferenceDesignatorText) {\n continue\n }\n\n const readableComponentName =\n nonFallbackReferenceDesignator ?? \"Schematic component\"\n\n warnings.push({\n type: \"schematic_component_styling_warning\",\n schematic_component_styling_warning_id: `schematic_component_styling_warning_${schematicComponent.schematic_component_id}_missing_reference_designator_text`,\n warning_type: \"schematic_component_styling_warning\",\n message: `${readableComponentName} is missing schematic reference designator text. For a custom symbol, add name=\"{REFDES}\" inside the symbol.`,\n schematic_component_id: schematicComponent.schematic_component_id,\n styling_issue_type: \"missing_reference_designator_text\",\n source_component_id: schematicComponent.source_component_id,\n schematic_sheet_id: schematicComponent.schematic_sheet_id,\n subcircuit_id: schematicComponent.subcircuit_id,\n })\n }\n\n return warnings\n}\n","import type {\n AnyCircuitElement,\n SchematicComponent,\n SchematicComponentStylingWarning,\n SchematicPort,\n} from \"circuit-json\"\n\ntype SourceComponent = Extract<AnyCircuitElement, { type: \"source_component\" }>\n\nconst FLOATING_POINT_TOLERANCE = 1e-9\n\nconst getPortLabel = (port: SchematicPort) =>\n port.display_pin_label ?? `pin ${port.pin_number}`\n\n/**\n * Warns when a box-style component's pins are positioned beyond the body edge\n * they enter. Left/right pins are checked against the body's vertical span,\n * while top/bottom pins are checked against its horizontal span.\n */\nexport function checkSchematicComponentPortsOutsideBody(\n circuitJson: AnyCircuitElement[],\n): SchematicComponentStylingWarning[] {\n const schematicComponents = circuitJson.filter(\n (element): element is SchematicComponent =>\n element.type === \"schematic_component\",\n )\n const schematicPorts = circuitJson.filter(\n (element): element is SchematicPort => element.type === \"schematic_port\",\n )\n const sourceComponents = circuitJson.filter(\n (element): element is SourceComponent =>\n element.type === \"source_component\",\n )\n\n const sourceComponentById = new Map(\n sourceComponents.map((component) => [\n component.source_component_id,\n component,\n ]),\n )\n const portsByComponentId = new Map<string, SchematicPort[]>()\n\n for (const port of schematicPorts) {\n if (!port.schematic_component_id) continue\n const componentPorts =\n portsByComponentId.get(port.schematic_component_id) ?? []\n componentPorts.push(port)\n portsByComponentId.set(port.schematic_component_id, componentPorts)\n }\n\n const warnings: SchematicComponentStylingWarning[] = []\n\n for (const component of schematicComponents) {\n if (\n component.is_box_with_pins === false ||\n component.size.width <= 0 ||\n component.size.height <= 0\n ) {\n continue\n }\n\n const componentLeftX = component.center.x - component.size.width / 2\n const componentRightX = component.center.x + component.size.width / 2\n const componentBottomY = component.center.y - component.size.height / 2\n const componentTopY = component.center.y + component.size.height / 2\n const componentPorts =\n portsByComponentId.get(component.schematic_component_id) ?? []\n\n const portsOutsideBody = componentPorts\n .filter((port) => {\n if (\n port.side_of_component === \"left\" ||\n port.side_of_component === \"right\"\n ) {\n return (\n port.center.y < componentBottomY - FLOATING_POINT_TOLERANCE ||\n port.center.y > componentTopY + FLOATING_POINT_TOLERANCE\n )\n }\n\n if (\n port.side_of_component === \"top\" ||\n port.side_of_component === \"bottom\"\n ) {\n return (\n port.center.x < componentLeftX - FLOATING_POINT_TOLERANCE ||\n port.center.x > componentRightX + FLOATING_POINT_TOLERANCE\n )\n }\n\n return false\n })\n .sort((portA, portB) => {\n const portAIsVertical =\n portA.side_of_component === \"left\" ||\n portA.side_of_component === \"right\"\n const portBIsVertical =\n portB.side_of_component === \"left\" ||\n portB.side_of_component === \"right\"\n\n if (portAIsVertical && portBIsVertical) {\n return portB.center.y - portA.center.y\n }\n if (!portAIsVertical && !portBIsVertical) {\n return portA.center.x - portB.center.x\n }\n return portAIsVertical ? -1 : 1\n })\n\n if (portsOutsideBody.length === 0) continue\n\n const requiredHeight = Math.max(\n component.size.height,\n ...portsOutsideBody\n .filter(\n (port) =>\n port.side_of_component === \"left\" ||\n port.side_of_component === \"right\",\n )\n .map((port) => 2 * Math.abs(port.center.y - component.center.y)),\n )\n const requiredWidth = Math.max(\n component.size.width,\n ...portsOutsideBody\n .filter(\n (port) =>\n port.side_of_component === \"top\" ||\n port.side_of_component === \"bottom\",\n )\n .map((port) => 2 * Math.abs(port.center.x - component.center.x)),\n )\n\n const suggestedDimensionChanges: string[] = []\n if (requiredHeight > component.size.height + FLOATING_POINT_TOLERANCE) {\n suggestedDimensionChanges.push(\n `increase schHeight to at least ${requiredHeight.toFixed(2)}mm`,\n )\n }\n if (requiredWidth > component.size.width + FLOATING_POINT_TOLERANCE) {\n suggestedDimensionChanges.push(\n `increase schWidth to at least ${requiredWidth.toFixed(2)}mm`,\n )\n }\n\n const sourceComponent = component.source_component_id\n ? sourceComponentById.get(component.source_component_id)\n : undefined\n const componentName =\n sourceComponent?.name ?? component.schematic_component_id\n const portLabels = portsOutsideBody.map(getPortLabel).join(\", \")\n\n warnings.push({\n type: \"schematic_component_styling_warning\",\n schematic_component_styling_warning_id: `schematic_component_styling_warning_${component.schematic_component_id}_ports_outside_body`,\n warning_type: \"schematic_component_styling_warning\",\n message: `${componentName} has schematic pins outside its body (${portLabels}); ${suggestedDimensionChanges.join(\" and \")}`,\n schematic_component_id: component.schematic_component_id,\n styling_issue_type: \"ports_outside_body\",\n schematic_port_ids: portsOutsideBody.map(\n (port) => port.schematic_port_id,\n ),\n source_component_id: component.source_component_id,\n schematic_sheet_id: component.schematic_sheet_id,\n subcircuit_id: component.subcircuit_id,\n })\n }\n\n return warnings\n}\n","import { createIndexedPcbConnectivityMap } from \"lib/util/create-indexed-pcb-connectivity-map\"\nimport { getFullConnectivityMapFromCircuitJson } from \"circuit-json-to-connectivity-map\"\nimport { addStartAndEndPortIdsIfMissing } from \"./add-start-and-end-port-ids-if-missing\"\nimport { checkCopperPourShorts } from \"./check-copper-pour-shorts\"\nimport { checkPcbBusLengthSkew } from \"./check-pcb-bus-length-skew\"\nimport { consolidatePcbOverlapErrors } from \"./consolidate-pcb-overlap-errors\"\nimport { checkSameNameNetsAreConnected } from \"./check-same-name-nets-are-connected\"\nimport type { AnyCircuitElement } from \"circuit-json\"\nimport { checkAllPinsInComponentAreUnderspecified } from \"./check-all-pins-in-component-are-underspecified\"\nimport { checkConnectorAccessibleOrientation } from \"./check-connector-accessible-orientation\"\nimport { checkCopperToBoardEdgeClearance } from \"./check-copper-to-board-edge-clearance\"\nimport { checkCourtyardOverlap } from \"./check-courtyard-overlap/checkCourtyardOverlap\"\nimport { checkDifferentNetViaSpacing } from \"./check-different-net-via-spacing\"\nimport { 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 { checkNoGroundPinDefined } from \"./check-no-ground-pin-defined\"\nimport { checkNoPowerPinDefined } from \"./check-no-power-pin-defined\"\nimport { checkPadPadClearance } from \"./check-pad-pad-clearance\"\nimport { checkPadTraceClearance } from \"./check-pad-trace-clearance\"\nimport { checkPcbComponentOverCutout } from \"./check-pcb-component-over-cutout\"\nimport { checkPcbComponentsMissingCourtyard } from \"./check-pcb-components-missing-courtyard\"\nimport { checkPcbComponentsOutOfBoard } from \"./check-pcb-components-out-of-board/checkPcbComponentsOutOfBoard\"\nimport { checkPcbComponentOverlap } from \"./check-pcb-components-overlap/checkPcbComponentOverlap\"\nimport { checkPcbCopperOverKeepout } from \"./check-pcb-copper-over-keepout\"\nimport { checkPcbTraceLengths } from \"./check-pcb-trace-lengths\"\nimport { checkPcbTraceViaCounts } from \"./check-pcb-trace-via-counts\"\nimport { checkPinMustBeConnected } from \"./check-pin-must-be-connected\"\nimport { checkSameNetViaSpacing } from \"./check-same-net-via-spacing\"\nimport { checkSchematicComponentExcessiveVerticalPadding } from \"./check-schematic-component-excessive-vertical-padding\"\nimport { checkSchematicComponentMissingReferenceDesignatorText } from \"./check-schematic-component-missing-reference-designator-text\"\nimport { checkSchematicComponentPortsOutsideBody } from \"./check-schematic-component-ports-outside-body\"\nimport { checkSourceTracesHavePcbTraces } from \"./check-source-traces-have-pcb-traces\"\nimport { checkTestPointAccessibility } from \"./check-testpoint-accessibility\"\nimport { checkPcbTracesOutOfBoard } from \"./check-trace-out-of-board/checkTraceOutOfBoard\"\nimport { checkTracesAreContiguous } from \"./check-traces-are-contiguous/check-traces-are-contiguous\"\nimport { checkTwoTerminalSwitchContactsOnDifferentNets } from \"./check-two-terminal-switch-contacts-on-different-nets\"\nimport { checkViaPadClearance } from \"./check-via-pad-clearance\"\nimport { checkViaTraceClearance } from \"./check-via-trace-clearance\"\nimport { checkViasInPads } from \"./check-vias-in-pads\"\n\nexport async function runAllPlacementChecks(\n circuitJson: AnyCircuitElement[],\n { consolidateOverlaps = true } = {},\n) {\n const errors = [\n ...checkCopperToBoardEdgeClearance(circuitJson),\n ...checkViasInPads(circuitJson),\n ...checkPcbComponentsOutOfBoard(circuitJson),\n ...checkPcbComponentOverCutout(circuitJson),\n ...checkPcbCopperOverKeepout(circuitJson),\n ...checkPcbComponentOverlap(circuitJson),\n ...checkPcbComponentsMissingCourtyard(circuitJson),\n ...checkPadPadClearance(circuitJson),\n ...checkCourtyardOverlap(circuitJson),\n ...checkConnectorAccessibleOrientation(circuitJson),\n ...checkTestPointAccessibility(circuitJson),\n ]\n return consolidateOverlaps\n ? consolidatePcbOverlapErrors(circuitJson, errors)\n : errors\n}\n\nexport async function runAllNetlistChecks(circuitJson: AnyCircuitElement[]) {\n return [\n ...checkPinMustBeConnected(circuitJson),\n ...checkSameNameNetsAreConnected(circuitJson),\n ...checkTwoTerminalSwitchContactsOnDifferentNets(circuitJson),\n ]\n}\n\nexport async function runAllSchematicChecks(circuitJson: AnyCircuitElement[]) {\n return [\n ...checkSchematicComponentExcessiveVerticalPadding(circuitJson),\n ...checkSchematicComponentMissingReferenceDesignatorText(circuitJson),\n ...checkSchematicComponentPortsOutsideBody(circuitJson),\n ]\n}\n\nexport async function runAllPinSpecificationChecks(\n circuitJson: AnyCircuitElement[],\n) {\n return [\n ...checkAllPinsInComponentAreUnderspecified(circuitJson),\n ...checkNoPowerPinDefined(circuitJson),\n ...checkNoGroundPinDefined(circuitJson),\n ]\n}\n\nexport async function runAllRoutingChecks(circuitJson: AnyCircuitElement[]) {\n // Infer endpoint IDs before taking connectivity snapshots. Keep these maps\n // local to this pass so edits to the same circuit array cannot leave stale data.\n addStartAndEndPortIdsIfMissing(circuitJson)\n const connectivity = {\n connMap: getFullConnectivityMapFromCircuitJson(circuitJson),\n pcbConnectivityMap: createIndexedPcbConnectivityMap(circuitJson),\n }\n return [\n ...checkEachPcbPortConnectedToPcbTraces(circuitJson, connectivity),\n ...checkSourceTracesHavePcbTraces(circuitJson, connectivity),\n ...checkPcbTraceLengths(circuitJson),\n ...checkPcbBusLengthSkew(circuitJson),\n ...checkPcbTraceViaCounts(circuitJson),\n ...checkEachPcbTraceNonOverlapping(circuitJson, connectivity),\n ...checkCopperPourShorts(circuitJson, connectivity),\n ...checkPadTraceClearance(circuitJson, connectivity),\n ...checkViaTraceClearance(circuitJson, connectivity),\n ...checkViaPadClearance(circuitJson, connectivity),\n ...checkSameNetViaSpacing(circuitJson, connectivity),\n ...checkDifferentNetViaSpacing(circuitJson, connectivity),\n ...checkTracesAreContiguous(circuitJson, connectivity),\n ...checkPcbTracesOutOfBoard(circuitJson),\n ]\n}\n\nexport async function runAllChecks(circuitJson: AnyCircuitElement[]) {\n return [\n ...(await runAllPlacementChecks(circuitJson)),\n ...(await runAllSchematicChecks(circuitJson)),\n ...(await runAllNetlistChecks(circuitJson)),\n ...(await runAllPinSpecificationChecks(circuitJson)),\n ...(await runAllRoutingChecks(circuitJson)),\n ]\n}\n","import type {\n AnyCircuitElement,\n PcbBusLengthSkewError,\n SourceBus,\n} from \"circuit-json\"\nimport { getPcbTracesBySourceTraceId } from \"./check-pcb-trace-lengths\"\nimport { getPcbTraceLength } from \"./util/get-pcb-trace-length\"\n\n/** Compare total routed lengths of resolved bus members. Unrouted members are\n * left to connectivity checks, never treated as zero-length routes.\n */\nexport const checkPcbBusLengthSkew = (\n circuitJson: AnyCircuitElement[],\n): PcbBusLengthSkewError[] => {\n const buses = circuitJson.filter(\n (e): e is SourceBus => e.type === \"source_bus\",\n )\n const tracesBySource = getPcbTracesBySourceTraceId(circuitJson)\n const errors: PcbBusLengthSkewError[] = []\n for (const bus of buses) {\n if (bus.max_length_skew === undefined) continue\n const members = [...new Set(bus.source_trace_ids)].flatMap((id) => {\n const traces = tracesBySource\n .get(id)\n ?.filter((t) => t.trace_length !== undefined || t.route.length > 1)\n if (!traces?.length) return []\n return [\n {\n id,\n traces,\n length: traces.reduce((sum, t) => sum + getPcbTraceLength(t), 0),\n },\n ]\n })\n if (members.length < 2) continue\n const skew =\n Math.max(...members.map((m) => m.length)) -\n Math.min(...members.map((m) => m.length))\n // Ignore rounding noise at the inclusive boundary.\n if (skew <= bus.max_length_skew + 1e-9) continue\n errors.push({\n type: \"pcb_bus_length_skew_error\",\n pcb_bus_length_skew_error_id: `pcb_bus_length_skew_error_${bus.source_bus_id}`,\n error_type: \"pcb_bus_length_skew_error\",\n message: `PCB bus ${bus.name ?? bus.source_bus_id} has ${skew.toFixed(2)}mm length skew, exceeding the ${bus.max_length_skew}mm maximum`,\n source_bus_id: bus.source_bus_id,\n source_trace_ids: members.map((m) => m.id),\n pcb_trace_ids: members.flatMap((m) =>\n m.traces.map((t) => t.pcb_trace_id),\n ),\n actual_length_skew: skew,\n maximum_length_skew: bus.max_length_skew,\n subcircuit_id: bus.subcircuit_id,\n })\n }\n return errors\n}\n","import { getPrimaryId } from \"@tscircuit/circuit-json-util\"\nimport type {\n AnyCircuitElement,\n PcbFootprintOverlapError,\n PcbPadPadClearanceError,\n PcbCourtyardOverlapError,\n} from \"circuit-json\"\n\n/** Additional diagnostic context supplied by checks; the base error remains\n * compatible with existing Circuit JSON renderers. */\nexport interface PcbComponentOverlapError extends PcbFootprintOverlapError {\n pcb_component_ids?: string[]\n related_errors?: PlacementOverlapError[]\n}\n\ntype PlacementOverlapError =\n | PcbComponentOverlapError\n | PcbPadPadClearanceError\n | PcbCourtyardOverlapError\n\n/**\n * Consolidate placement conflicts for the same exact pair of components, only\n * when a footprint overlap was detected. Keep raw details and all affected\n * pad/hole IDs on one renderer-compatible error. Unrelated checks, standalone\n * elements, same-component clearance errors and clearance-only pairs survive.\n * Does not mutate inputs; safe to apply again when combining check runners.\n */\nexport function consolidatePcbOverlapErrors<T extends AnyCircuitElement>(\n circuitJson: AnyCircuitElement[],\n errors: T[],\n): (T | PcbComponentOverlapError)[]\nexport function consolidatePcbOverlapErrors(\n circuitJson: AnyCircuitElement[],\n errors: AnyCircuitElement[],\n): AnyCircuitElement[] {\n const ownerByElementId = new Map<string, string>()\n const elementById = new Map<string, AnyCircuitElement>()\n for (const element of circuitJson) {\n const id = getPrimaryId(element)\n elementById.set(id, element)\n if (\"pcb_component_id\" in element && element.pcb_component_id) {\n ownerByElementId.set(id, element.pcb_component_id)\n }\n }\n\n const rawErrors = errors.flatMap<AnyCircuitElement>((error) =>\n error.type === \"pcb_footprint_overlap_error\"\n ? ((error as PcbComponentOverlapError).related_errors ?? [error])\n : [error],\n )\n const groups = new Map<string, PlacementOverlapError[]>()\n const keyByError = new Map<AnyCircuitElement, string>()\n for (const error of rawErrors) {\n let componentIds: string[]\n if (error.type === \"pcb_footprint_overlap_error\") {\n // Keepout errors describe a different constraint, even if pads are named.\n if (error.pcb_keepout_ids?.length) continue\n const overlap = error as PcbComponentOverlapError\n const elementIds = [\n ...(error.pcb_smtpad_ids ?? []),\n ...(error.pcb_plated_hole_ids ?? []),\n ...(error.pcb_hole_ids ?? []),\n ]\n if (elementIds.some((id) => !ownerByElementId.has(id))) continue\n componentIds =\n overlap.pcb_component_ids ??\n elementIds.map((id) => ownerByElementId.get(id)!)\n } else if (error.type === \"pcb_pad_pad_clearance_error\") {\n if (error.pcb_pad_ids.some((id) => !ownerByElementId.has(id))) continue\n componentIds = error.pcb_pad_ids.map((id) => ownerByElementId.get(id)!)\n } else if (error.type === \"pcb_courtyard_overlap_error\") {\n componentIds = error.pcb_component_ids\n } else {\n continue\n }\n componentIds = [...new Set(componentIds)].sort()\n if (componentIds.length !== 2) continue\n const key = JSON.stringify(componentIds)\n keyByError.set(error, key)\n const group = groups.get(key) ?? []\n group.push(error)\n groups.set(key, group)\n }\n\n const summaries = new Map<string, PcbComponentOverlapError>()\n for (const [key, group] of groups) {\n const overlaps = group.filter(\n (e) => e.type === \"pcb_footprint_overlap_error\",\n )\n if (group.length < 2 || overlaps.length === 0) continue\n const componentIds: string[] = JSON.parse(key)\n const names = componentIds.map((id) => {\n const component = elementById.get(id)\n const source =\n component?.type === \"pcb_component\"\n ? elementById.get(component.source_component_id)\n : undefined\n return source?.type === \"source_component\" ? source.name : id\n })\n const counts = [\n [overlaps.length, \"footprint overlap\"],\n [\n group.filter((e) => e.type === \"pcb_pad_pad_clearance_error\").length,\n \"pad clearance violation\",\n ],\n [\n group.filter((e) => e.type === \"pcb_courtyard_overlap_error\").length,\n \"courtyard conflict\",\n ],\n ] as const\n const details = counts\n .filter(([count]) => count > 0)\n .map(([count, label]) => `${count} ${label}${count === 1 ? \"\" : \"s\"}`)\n const summary: PcbComponentOverlapError = {\n type: \"pcb_footprint_overlap_error\",\n error_type: \"pcb_footprint_overlap_error\",\n pcb_error_id: `pcb_component_overlap_${componentIds.join(\"_\")}`,\n pcb_component_ids: componentIds,\n message: `${names.join(\" overlaps \")}: ${details.join(\", \")}. Move the components apart.`,\n related_errors: group,\n }\n if (group.some((error) => error.is_fatal)) summary.is_fatal = true\n const affectedIds = new Set<string>()\n for (const error of group) {\n if (error.type === \"pcb_footprint_overlap_error\") {\n for (const id of [\n ...(error.pcb_smtpad_ids ?? []),\n ...(error.pcb_plated_hole_ids ?? []),\n ...(error.pcb_hole_ids ?? []),\n ])\n affectedIds.add(id)\n } else if (error.type === \"pcb_pad_pad_clearance_error\") {\n for (const id of error.pcb_pad_ids) affectedIds.add(id)\n }\n }\n for (const [field, type] of [\n [\"pcb_smtpad_ids\", \"pcb_smtpad\"],\n [\"pcb_plated_hole_ids\", \"pcb_plated_hole\"],\n [\"pcb_hole_ids\", \"pcb_hole\"],\n ] as const) {\n const ids = [...affectedIds]\n .filter((id) => elementById.get(id)?.type === type)\n .sort()\n if (ids.length) summary[field] = ids\n }\n summaries.set(key, summary)\n }\n\n const emitted = new Set<string>()\n return rawErrors.flatMap<AnyCircuitElement>((error) => {\n const key = keyByError.get(error)\n const summary = key === undefined ? undefined : summaries.get(key)\n if (!summary || key === undefined) return [error]\n if (emitted.has(key)) return []\n emitted.add(key)\n return [summary]\n })\n}\n","import type {\n AnyCircuitElement,\n SourceConfusingNetNameWarning,\n SourceNet,\n} from \"circuit-json\"\n\n/** Warn once per name when its source nets belong to multiple electrical islands. */\nexport function checkSameNameNetsAreConnected(\n circuitJson: AnyCircuitElement[],\n): SourceConfusingNetNameWarning[] {\n const parents = new Map<string, string>()\n const find = (id: string): string => {\n let root = id\n while (parents.has(root) && parents.get(root) !== root) {\n root = parents.get(root)!\n }\n while (parents.has(id) && parents.get(id) !== root) {\n const next = parents.get(id)!\n parents.set(id, root)\n id = next\n }\n return root\n }\n const connect = (ids: string[]) => {\n if (ids.length < 2) return\n const root = find(ids[0]!)\n for (const id of ids.slice(1)) parents.set(find(id), root)\n }\n const netsByName = new Map<string, SourceNet[]>()\n for (const element of circuitJson) {\n if (element.type === \"source_net\" && element.name.trim()) {\n const nets = netsByName.get(element.name) ?? []\n nets.push(element)\n netsByName.set(element.name, nets)\n }\n if (element.type === \"source_trace\") {\n connect([\n ...element.connected_source_net_ids.map((id) => `net:${id}`),\n ...element.connected_source_port_ids.map((id) => `port:${id}`),\n ])\n }\n if (element.type === \"source_component_internal_connection\") {\n connect(element.source_port_ids.map((id) => `port:${id}`))\n }\n if (element.type === \"source_component\") {\n for (const ids of element.internally_connected_source_port_ids ?? []) {\n connect(ids.map((id) => `port:${id}`))\n }\n }\n }\n\n const warnings: SourceConfusingNetNameWarning[] = []\n for (const [name, nets] of netsByName) {\n const islands = new Set(nets.map((net) => find(`net:${net.source_net_id}`)))\n if (islands.size < 2) continue\n const ids = nets.map((net) => net.source_net_id).sort()\n warnings.push({\n type: \"source_confusing_net_name_warning\",\n source_confusing_net_name_warning_id: `source_confusing_net_name_warning_${ids[0]}`,\n warning_type: \"source_confusing_net_name_warning\",\n message: `Nets named \"${name}\" are not all connected (${islands.size} separate electrical networks). Connect them or use distinct names to avoid confusion.`,\n source_net_ids: ids,\n net_name: name,\n ...(nets.every((net) => net.subcircuit_id === nets[0]!.subcircuit_id)\n ? { subcircuit_id: nets[0]!.subcircuit_id }\n : {}),\n })\n }\n return warnings\n}\n","import { getBoardBounds } from \"@tscircuit/circuit-json-util\"\nimport type {\n AnyCircuitElement,\n PcbBoard,\n PcbComponent,\n PcbConnectorNotInAccessibleOrientationWarning,\n} from \"circuit-json\"\nimport { getReadableNameForComponent } from \"./util/get-readable-names\"\n\ntype FacingDirection = \"x-\" | \"x+\" | \"y+\" | \"y-\"\n\nfunction getFacingDirectionFromInsertionDirection(\n component: PcbComponent,\n): FacingDirection | null {\n switch (component.insertion_direction) {\n case \"from_left\":\n return \"x-\"\n case \"from_right\":\n return \"x+\"\n case \"from_top\":\n return \"y+\"\n case \"from_bottom\":\n return \"y-\"\n case \"from_above\":\n case \"from_below\":\n return null\n default:\n return null\n }\n}\n\nfunction getFacingDirection(component: PcbComponent): FacingDirection | null {\n if (component.insertion_direction) {\n return getFacingDirectionFromInsertionDirection(component)\n }\n\n if (!component.center || !component.cable_insertion_center) return null\n\n const dx = component.cable_insertion_center.x - component.center.x\n const dy = component.cable_insertion_center.y - component.center.y\n\n if (Math.abs(dx) < 1e-6 && Math.abs(dy) < 1e-6) return null\n\n if (Math.abs(dx) >= Math.abs(dy)) {\n return dx >= 0 ? \"x+\" : \"x-\"\n }\n\n return dy >= 0 ? \"y+\" : \"y-\"\n}\n\nfunction getRecommendedFacingDirection(\n component: PcbComponent,\n bounds: { minX: number; maxX: number; minY: number; maxY: number },\n): FacingDirection | null {\n if (!component.center) return null\n\n const distances = [\n { direction: \"x-\" as const, distance: component.center.x - bounds.minX },\n { direction: \"x+\" as const, distance: bounds.maxX - component.center.x },\n { direction: \"y-\" as const, distance: component.center.y - bounds.minY },\n { direction: \"y+\" as const, distance: bounds.maxY - component.center.y },\n ]\n\n distances.sort((a, b) => a.distance - b.distance)\n return distances[0]?.direction ?? null\n}\n\nexport function checkConnectorAccessibleOrientation(\n circuitJson: AnyCircuitElement[],\n): PcbConnectorNotInAccessibleOrientationWarning[] {\n const board = circuitJson.find(\n (el): el is PcbBoard => el.type === \"pcb_board\",\n )\n if (!board) return []\n\n const bounds = (() => {\n try {\n return getBoardBounds(board)\n } catch {\n return null\n }\n })()\n if (!bounds) return []\n\n const warnings: PcbConnectorNotInAccessibleOrientationWarning[] = []\n\n const components = circuitJson.filter(\n (el): el is PcbComponent => el.type === \"pcb_component\",\n )\n\n for (const component of components) {\n const facingDirection = getFacingDirection(component)\n const recommendedFacingDirection = getRecommendedFacingDirection(\n component,\n bounds,\n )\n\n if (!facingDirection || !recommendedFacingDirection) continue\n if (facingDirection === recommendedFacingDirection) continue\n\n const componentName = getReadableNameForComponent(\n circuitJson,\n component.pcb_component_id,\n )\n\n const message = component.insertion_direction\n ? `${componentName} is facing ${facingDirection} but should face ${recommendedFacingDirection} so the connector is accessible from the board edge`\n : `${componentName} is inferred to face ${facingDirection} from its cable insertion center because no explicit footprint insertionDirection is defined, but should face ${recommendedFacingDirection} so the connector is accessible from the board edge. Set insertionDirection on the <footprint> to specify the actual direction in the footprint's unrotated orientation; for example, <footprint insertionDirection=\"from_above\"> for a connector accessed from above the PCB (+Z).`\n\n warnings.push({\n type: \"pcb_connector_not_in_accessible_orientation_warning\",\n warning_type: \"pcb_connector_not_in_accessible_orientation_warning\",\n pcb_connector_not_in_accessible_orientation_warning_id: `pcb_connector_not_in_accessible_orientation_warning_${component.pcb_component_id}`,\n message,\n pcb_component_id: component.pcb_component_id,\n source_component_id: component.source_component_id,\n pcb_board_id: board.pcb_board_id,\n facing_direction: facingDirection,\n recommended_facing_direction: recommendedFacingDirection,\n subcircuit_id: component.subcircuit_id,\n })\n }\n\n return warnings\n}\n","import {\n doSegmentsIntersect,\n isPointInsidePolygon,\n} from \"@tscircuit/math-utils\"\nimport type {\n AnyCircuitElement,\n PcbCourtyardCircle,\n PcbCourtyardOutline,\n PcbCourtyardOverlapError,\n PcbCourtyardRect,\n} from \"circuit-json\"\n\ntype CourtyardElement =\n | PcbCourtyardRect\n | PcbCourtyardCircle\n | PcbCourtyardOutline\n\nfunction getCourtyardPolygon(el: CourtyardElement): { x: number; y: number }[] {\n if (el.type === \"pcb_courtyard_rect\") {\n const hw = el.width / 2\n const hh = el.height / 2\n const corners = [\n { x: -hw, y: -hh },\n { x: +hw, y: -hh },\n { x: +hw, y: +hh },\n { x: -hw, y: +hh },\n ]\n const angle = ((el.ccw_rotation ?? 0) * Math.PI) / 180\n const cos = Math.cos(angle)\n const sin = Math.sin(angle)\n return corners.map(({ x, y }) => ({\n x: el.center.x + x * cos - y * sin,\n y: el.center.y + x * sin + y * cos,\n }))\n }\n if (el.type === \"pcb_courtyard_circle\") {\n const N = 32\n return Array.from({ length: N }, (_, i) => {\n const a = (2 * Math.PI * i) / N\n return {\n x: el.center.x + el.radius * Math.cos(a),\n y: el.center.y + el.radius * Math.sin(a),\n }\n })\n }\n return el.outline\n}\n\nfunction getComponentName(\n circuitJson: AnyCircuitElement[],\n pcbComponentId: string,\n): string {\n const pcbComponent = circuitJson.find(\n (el) =>\n el.type === \"pcb_component\" && el.pcb_component_id === pcbComponentId,\n )\n if (pcbComponent?.type !== \"pcb_component\") return pcbComponentId\n const sourceComponent = circuitJson.find(\n (el) =>\n el.type === \"source_component\" &&\n el.source_component_id === pcbComponent.source_component_id,\n )\n if (sourceComponent?.type === \"source_component\" && sourceComponent.name) {\n return sourceComponent.name\n }\n return pcbComponentId\n}\n\ntype Point = { x: number; y: number }\n\nfunction polygonsOverlap(polyA: Point[], polyB: Point[]): boolean {\n // Check if any vertex of A is inside B or vice versa\n if (polyA.some((p) => isPointInsidePolygon(p, polyB))) return true\n if (polyB.some((p) => isPointInsidePolygon(p, polyA))) return true\n // Check if any edge of A intersects any edge of B\n for (let i = 0; i < polyA.length; i++) {\n const a1 = polyA[i]\n const a2 = polyA[(i + 1) % polyA.length]\n for (let j = 0; j < polyB.length; j++) {\n const b1 = polyB[j]\n const b2 = polyB[(j + 1) % polyB.length]\n if (doSegmentsIntersect(a1, a2, b1, b2)) return true\n }\n }\n return false\n}\n\n/**\n * Check for overlapping PCB component courtyards.\n * Returns one error per pair of components whose courtyard elements overlap.\n */\nexport function checkCourtyardOverlap(\n circuitJson: AnyCircuitElement[],\n): PcbCourtyardOverlapError[] {\n const doNotPlaceComponentIds = new Set(\n circuitJson.flatMap((el) =>\n el.type === \"pcb_component\" && el.do_not_place\n ? [el.pcb_component_id]\n : [],\n ),\n )\n\n const courtyards = circuitJson\n .filter(\n (el): el is CourtyardElement =>\n el.type === \"pcb_courtyard_rect\" ||\n el.type === \"pcb_courtyard_circle\" ||\n el.type === \"pcb_courtyard_outline\",\n )\n .filter((el) => !doNotPlaceComponentIds.has(el.pcb_component_id))\n\n // Group by component\n const byComponent = new Map<string, CourtyardElement[]>()\n for (const el of courtyards) {\n const id = el.pcb_component_id\n if (!byComponent.has(id)) byComponent.set(id, [])\n byComponent.get(id)!.push(el)\n }\n\n const componentIds = Array.from(byComponent.keys())\n const errors: PcbCourtyardOverlapError[] = []\n\n for (let i = 0; i < componentIds.length; i++) {\n for (let j = i + 1; j < componentIds.length; j++) {\n const idA = componentIds[i]\n const idB = componentIds[j]\n\n let overlapping = false\n outer: for (const a of byComponent.get(idA)!) {\n for (const b of byComponent.get(idB)!) {\n // Skip overlap check if courtyards are on different layers\n if (\"layer\" in a && \"layer\" in b && a.layer !== b.layer) {\n continue\n }\n const polyA = getCourtyardPolygon(a)\n const polyB = getCourtyardPolygon(b)\n if (polygonsOverlap(polyA, polyB)) {\n overlapping = true\n break outer\n }\n }\n }\n\n if (overlapping) {\n errors.push({\n type: \"pcb_courtyard_overlap_error\",\n pcb_error_id: `pcb_courtyard_overlap_${idA}_${idB}`,\n error_type: \"pcb_courtyard_overlap_error\",\n message: `Courtyard of ${getComponentName(circuitJson, idA)} overlaps with courtyard of ${getComponentName(circuitJson, idB)}`,\n pcb_component_ids: [idA, idB],\n })\n }\n }\n }\n\n return errors\n}\n","import { isPointInsidePolygon } from \"@tscircuit/math-utils\"\nimport type {\n AnyCircuitElement,\n PcbComponent,\n PcbCourtyardCircle,\n PcbCourtyardOutline,\n PcbCourtyardPolygon,\n PcbCourtyardRect,\n PcbPlacementError,\n SourceSimpleTestPoint,\n} from \"circuit-json\"\nimport { getReadableNameForComponent } from \"./util/get-readable-names\"\n\ntype CourtyardElement =\n | PcbCourtyardCircle\n | PcbCourtyardOutline\n | PcbCourtyardPolygon\n | PcbCourtyardRect\n\nconst isCourtyardElement = (\n element: AnyCircuitElement,\n): element is CourtyardElement =>\n element.type === \"pcb_courtyard_circle\" ||\n element.type === \"pcb_courtyard_outline\" ||\n element.type === \"pcb_courtyard_polygon\" ||\n element.type === \"pcb_courtyard_rect\"\n\nconst isPointInsideCourtyard = (\n point: { x: number; y: number },\n courtyard: CourtyardElement,\n): boolean => {\n if (courtyard.type === \"pcb_courtyard_circle\") {\n const dx = point.x - courtyard.center.x\n const dy = point.y - courtyard.center.y\n return dx * dx + dy * dy <= courtyard.radius * courtyard.radius\n }\n\n if (courtyard.type === \"pcb_courtyard_rect\") {\n const angle = (-1 * (courtyard.ccw_rotation ?? 0) * Math.PI) / 180\n const dx = point.x - courtyard.center.x\n const dy = point.y - courtyard.center.y\n const localX = dx * Math.cos(angle) - dy * Math.sin(angle)\n const localY = dx * Math.sin(angle) + dy * Math.cos(angle)\n return (\n Math.abs(localX) <= courtyard.width / 2 &&\n Math.abs(localY) <= courtyard.height / 2\n )\n }\n\n const polygon =\n courtyard.type === \"pcb_courtyard_polygon\"\n ? courtyard.points\n : courtyard.outline\n return isPointInsidePolygon(point, polygon)\n}\n\nconst getPcbComponentName = (\n circuitJson: AnyCircuitElement[],\n pcbComponentId: string,\n): string => {\n const pcbComponent = circuitJson.find(\n (element): element is PcbComponent =>\n element.type === \"pcb_component\" &&\n element.pcb_component_id === pcbComponentId,\n )\n const sourceComponent = circuitJson.find(\n (element) =>\n element.type === \"source_component\" &&\n element.source_component_id === pcbComponent?.source_component_id,\n )\n\n return (\n (sourceComponent && \"name\" in sourceComponent\n ? sourceComponent.name\n : undefined) ?? getReadableNameForComponent(circuitJson, pcbComponentId)\n )\n}\n\n/**\n * Test points are intended to be contacted from their PCB side. A test point\n * whose access center is covered by another component's courtyard cannot be\n * reliably reached by a probe after assembly.\n */\nexport function checkTestPointAccessibility(\n circuitJson: AnyCircuitElement[],\n): PcbPlacementError[] {\n const sourceTestPoints = circuitJson.filter(\n (element): element is SourceSimpleTestPoint =>\n element.type === \"source_component\" &&\n element.ftype === \"simple_test_point\",\n )\n const sourceTestPointIds = new Set(\n sourceTestPoints.map((testPoint) => testPoint.source_component_id),\n )\n const testPointNames = new Map(\n sourceTestPoints.map((testPoint) => [\n testPoint.source_component_id,\n testPoint.name,\n ]),\n )\n const testPointComponents = circuitJson.filter(\n (element): element is PcbComponent =>\n element.type === \"pcb_component\" &&\n sourceTestPointIds.has(element.source_component_id),\n )\n const courtyards = circuitJson.filter(isCourtyardElement)\n const errors: PcbPlacementError[] = []\n const reportedComponentPairs = new Set<string>()\n\n for (const testPoint of testPointComponents) {\n for (const courtyard of courtyards) {\n if (courtyard.pcb_component_id === testPoint.pcb_component_id) continue\n if (courtyard.layer !== testPoint.layer) continue\n if (!isPointInsideCourtyard(testPoint.center, courtyard)) continue\n\n const componentPair = `${testPoint.pcb_component_id}:${courtyard.pcb_component_id}`\n if (reportedComponentPairs.has(componentPair)) continue\n reportedComponentPairs.add(componentPair)\n\n const testPointName =\n testPointNames.get(testPoint.source_component_id) ?? \"Test point\"\n const obstructingComponentName = getPcbComponentName(\n circuitJson,\n courtyard.pcb_component_id,\n )\n\n errors.push({\n type: \"pcb_placement_error\",\n pcb_placement_error_id: `testpoint_in_courtyard_${testPoint.pcb_component_id}_${courtyard.pcb_component_id}`,\n error_type: \"pcb_placement_error\",\n message: `Test point ${testPointName} is not accessible because it is inside the courtyard of ${obstructingComponentName}`,\n subcircuit_id: testPoint.subcircuit_id,\n })\n }\n }\n\n return errors\n}\n"],"mappings":"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","names":["Vector","Arc","shape","Flatbush","Flatbush","point","Flatbush","Flatbush","point","point","point","point","smtPad","getFullConnectivityMapFromCircuitJson","getReadableNameForElement","getPourPolygon","getTraceSegmentPolygon","getViaPolygon","netId","getFullConnectivityMapFromCircuitJson","cju","getReadableNameForElement","getPrimaryId","segmentToCircleMinDistance","segmentToSegmentMinDistance","getFullConnectivityMapFromCircuitJson","getBoundsOfPcbElements","pointToSegmentClosestPoint","segmentToSegmentMinDistance","point","getBoundsOfPcbElements","segmentToSegmentMinDistance","distance","circle","pointToSegmentClosestPoint","clearance","all_layers","clamp","dx","dy","t","closestOnB","closestOnA","distance","getBoundsOfPcbElements","point","getBoundsOfPcbElements","getFullConnectivityMapFromCircuitJson","cju","getReadableNameForElement","gap","segmentToSegmentMinDistance","getPrimaryId","distance","segmentToCircleMinDistance","getReadableNameForElement","getReadableNameForElement","Flatten","rotatePoint","Flatten","applyToPoint","rotateDEG","rectanglePolygon","rotateDEG","applyToPoint","point","cju","getPrimaryId","getPrimaryId","cju","getReadableNameForElement","getFullConnectivityMapFromCircuitJson","distance","distance","getFullConnectivityMapFromCircuitJson","distance","getReadableNameForElement","getReadableNameForElement","getFullConnectivityMapFromCircuitJson","getFullConnectivityMapFromCircuitJson","distance","getReadableNameForElement","cju","getFullConnectivityMapFromCircuitJson","cju","getFullConnectivityMapFromCircuitJson","point","getFullConnectivityMapFromCircuitJson","getFullConnectivityMapFromCircuitJson","pointToSegmentDistance","getReadableNameForPcbPort","getFullConnectivityMapFromCircuitJson","all_layers","getPrimaryId","pointToSegmentDistance","all_layers","getPrimaryId","pointToSegmentDistance","point","point","pointToSegmentDistance","distance","getFullConnectivityMapFromCircuitJson","traceName","getReadableNameForPcbPort","cju","segmentToSegmentMinDistance","cju","distance","segmentToSegmentMinDistance","cju","getBoundsOfPcbElements","getPrimaryId","doBoundsOverlap","getFullConnectivityMapFromCircuitJson","getBoundsOfPcbElements","doBoundsOverlap","getBoundsOfPcbElements","doBoundsOverlap","isCourtyardElement","getPrimaryId","getFullConnectivityMapFromCircuitJson","cju","getBoundsOfPcbElements","doBoundsOverlap","point","getPrimaryId","getReadableNameForElement","getFullConnectivityMapFromCircuitJson","getFullConnectivityMapFromCircuitJson","getPrimaryId","getReadableNameForElement","getPrimaryId","getReadableNameForElement","formatMm","getFullConnectivityMapFromCircuitJson","getFullConnectivityMapFromCircuitJson","getPrimaryId","getReadableNameForElement","formatMm","getReadableNameForElement","formatMm","getFullConnectivityMapFromCircuitJson","getFullConnectivityMapFromCircuitJson","getReadableNameForElement","formatMm","getPrimaryId","getReadableNameForElement","formatMm","getFullConnectivityMapFromCircuitJson","getFullConnectivityMapFromCircuitJson","getPrimaryId","getReadableNameForElement","formatMm","getPrimaryId","getFullConnectivityMapFromCircuitJson","getFullConnectivityMapFromCircuitJson","getPrimaryId","sourcePort","cju","cju","cju","cju","cju","FLOATING_POINT_TOLERANCE","getFullConnectivityMapFromCircuitJson","getPrimaryId","isPointInsidePolygon","getComponentName","isPointInsidePolygon","isCourtyardElement","point","isPointInsidePolygon","getFullConnectivityMapFromCircuitJson"]}
|