@tscircuit/checks 0.0.182 → 0.0.184

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.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../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/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-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/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-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/check-connector-accessible-orientation.ts","../lib/check-courtyard-overlap/checkCourtyardOverlap.ts","../lib/check-testpoint-accessibility.ts","../lib/run-all-checks.ts"],"sourcesContent":["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: PcbTraceSegment,\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 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 PcbConnectivityMap,\n} from \"circuit-json-to-connectivity-map\"\nimport { getReadableNameForPort } from \"./util/get-readable-names\"\n\nfunction checkEachPcbPortConnectedToPcbTraces(\n circuitJson: AnyCircuitElement[],\n): PcbPortNotConnectedError[] {\n addStartAndEndPortIdsIfMissing(circuitJson)\n const sourceTraces: SourceTrace[] = circuitJson.filter(\n (item) => item.type === \"source_trace\",\n ) as SourceTrace[]\n\n const pcbPorts: PcbPort[] = circuitJson.filter(\n (item) => item.type === \"pcb_port\",\n ) as PcbPort[]\n 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 = getFullConnectivityMapFromCircuitJson(circuitJson)\n const pcbConnectivityMap = new PcbConnectivityMap(circuitJson)\n\n // Create a map from source_port_id to pcb_port for quick lookup\n const sourcePortToPcbPort = new Map<string, PcbPort>()\n for (const pcbPort of pcbPorts) {\n sourcePortToPcbPort.set(pcbPort.source_port_id, pcbPort)\n }\n\n 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 (connectedPcbTraces.length === 0) {\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 (pcbTraceIds.length === 0) {\n // Check if this is a trivial case (only 2 ports on same component)\n const uniqueComponentIds = new Set(\n pcbPortsInTrace.map((p) => p.pcb_component_id),\n )\n\n if (uniqueComponentIds.size > 1) {\n // Ports are on different components but no PCB traces connect them\n errors.push({\n type: \"pcb_port_not_connected_error\",\n message: `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 { 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} 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[] {\n const errors: PcbTraceError[] = []\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).pcb_keepout.list()\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 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\nexport const getPadToPadGap = (\n padA: CopperClearanceElement,\n padB: CopperClearanceElement,\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\n/**\n * Returns the center used to place a trace-related error in circuit-json.\n *\n * Clearance geometry is measured at the closest segment/obstacle points, but\n * placing the error there makes independent traces that pass the same obstacle\n * render on top of one another. Centering each error on its full trace keeps\n * placement deterministic and distinct without requiring renderer-side moves.\n */\nexport const getTraceCenter = (segment: PcbTraceSegment) => {\n const routePoints = segment._pcbTrace.route.flatMap((routePoint) => {\n if (routePoint.route_type === \"through_pad\") {\n return [routePoint.start, routePoint.end]\n }\n\n return [{ x: routePoint.x, y: routePoint.y }]\n })\n const firstPoint = routePoints[0]\n const lastPoint = routePoints[routePoints.length - 1]\n\n if (!firstPoint || !lastPoint) {\n return midpoint(\n { x: segment.x1, y: segment.y1 },\n { x: segment.x2, y: segment.y2 },\n )\n }\n\n return midpoint(firstPoint, lastPoint)\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 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: PcbTraceSegment,\n obstacle: TraceClearanceObstacle,\n): { gap: number; center: { x: number; y: number } } => {\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,\n center: getCenterBetweenCopperEdges({\n tracePoint: clearance.tracePoint,\n obstaclePoint: clearance.obstaclePoint,\n traceRadius,\n obstacleRadius: 0,\n }),\n }\n}\n\nexport const isTraceObstacleOverlap = (gap: number): boolean => gap <= 0\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 * as Flatten from \"@flatten-js/core\"\nimport { jlcMinTolerances } from \"@tscircuit/jlcpcb-manufacturing-specs\"\nimport type {\n AnyCircuitElement,\n PcbBoard,\n PcbComponent,\n PcbCopperPour,\n PcbPlacementError,\n PcbPlatedHole,\n PcbSmtPad,\n PcbVia,\n} from \"circuit-json\"\nimport { getBoardDrcValue, getPcbBoard } from \"lib/drc-defaults\"\nimport { applyToPoint, rotateDEG } from \"transformation-matrix\"\n\ntype CopperElement = PcbVia | PcbSmtPad | PcbPlatedHole | PcbCopperPour\ndeclare const pcbComponentIdBrand: unique symbol\ntype PcbComponentId = string & {\n readonly [pcbComponentIdBrand]: \"PcbComponentId\"\n}\nconst toPcbComponentId = (id: string): PcbComponentId => id as PcbComponentId\ntype CopperShape = Flatten.Circle | Flatten.Polygon\n\ntype CopperGeometry =\n | { kind: \"shapes\"; shapes: CopperShape[] }\n | { kind: \"pill\"; centerLine: Flatten.Segment; radius: number }\n\nconst GEOMETRY_EPSILON = 1e-9\n\nconst pointsToPolygon = (\n points: Array<{ x: number; y: number }>,\n): Flatten.Polygon | null => {\n if (points.length < 3) return null\n return new Flatten.Polygon(points.map(({ x, y }) => new Flatten.Point(x, y)))\n}\n\nconst brepRingToPolygon = (\n vertices: Array<{ x: number; y: number; bulge?: number }>,\n): Flatten.Polygon | null => {\n const ring = vertices.filter((vertex, index) => {\n const previous = vertices[index - 1]\n return (\n !previous ||\n Math.abs(previous.x - vertex.x) > GEOMETRY_EPSILON ||\n Math.abs(previous.y - vertex.y) > GEOMETRY_EPSILON\n )\n })\n if (\n ring.length > 1 &&\n Math.abs(ring[0].x - ring.at(-1)!.x) <= GEOMETRY_EPSILON &&\n Math.abs(ring[0].y - ring.at(-1)!.y) <= GEOMETRY_EPSILON\n ) {\n ring.pop()\n }\n if (ring.length < 3) return null\n\n const edges: Array<Flatten.Segment | Flatten.Arc> = []\n for (let index = 0; index < ring.length; index++) {\n const start = ring[index]\n const end = ring[(index + 1) % ring.length]\n const startPoint = new Flatten.Point(start.x, start.y)\n const endPoint = new Flatten.Point(end.x, end.y)\n const bulge = start.bulge ?? 0\n if (Math.abs(bulge) <= GEOMETRY_EPSILON) {\n edges.push(new Flatten.Segment(startPoint, endPoint))\n continue\n }\n\n const chordLength = startPoint.distanceTo(endPoint)[0]\n if (chordLength <= GEOMETRY_EPSILON) continue\n const midpoint = {\n x: (start.x + end.x) / 2,\n y: (start.y + end.y) / 2,\n }\n const leftNormal = {\n x: -(end.y - start.y) / chordLength,\n y: (end.x - start.x) / chordLength,\n }\n const centerOffset = (chordLength * (1 - bulge * bulge)) / (4 * bulge)\n const center = new Flatten.Point(\n midpoint.x + leftNormal.x * centerOffset,\n midpoint.y + leftNormal.y * centerOffset,\n )\n const radius = (chordLength * (1 + bulge * bulge)) / (4 * Math.abs(bulge))\n edges.push(\n new Flatten.Arc(\n center,\n radius,\n Math.atan2(start.y - center.y, start.x - center.x),\n Math.atan2(end.y - center.y, end.x - center.x),\n bulge > 0,\n ),\n )\n }\n\n if (edges.length < 3) return null\n const polygon = new Flatten.Polygon()\n polygon.addFace(edges)\n return polygon\n}\n\nconst boardToPolygon = (board: PcbBoard): Flatten.Polygon | null => {\n if (board.outline && board.outline.length >= 3) {\n return pointsToPolygon(board.outline)\n }\n\n if (\n !board.center ||\n typeof board.width !== \"number\" ||\n typeof board.height !== \"number\"\n ) {\n return null\n }\n\n const halfWidth = board.width / 2\n const halfHeight = board.height / 2\n return pointsToPolygon([\n { x: board.center.x - halfWidth, y: board.center.y - halfHeight },\n { x: board.center.x + halfWidth, y: board.center.y - halfHeight },\n { x: board.center.x + halfWidth, y: board.center.y + halfHeight },\n { x: board.center.x - halfWidth, y: board.center.y + halfHeight },\n ])\n}\n\nconst getRectanglePolygon = ({\n x,\n y,\n width,\n height,\n ccwRotationDegrees = 0,\n}: {\n x: number\n y: number\n width: number\n height: number\n ccwRotationDegrees?: number\n}): Flatten.Polygon | null => {\n const halfWidth = width / 2\n const halfHeight = height / 2\n const rotationMatrix = rotateDEG(ccwRotationDegrees, x, y)\n return pointsToPolygon(\n [\n { x: x - halfWidth, y: y - halfHeight },\n { x: x + halfWidth, y: y - halfHeight },\n { x: x + halfWidth, y: y + halfHeight },\n { x: x - halfWidth, y: y + halfHeight },\n ].map((point) => applyToPoint(rotationMatrix, point)),\n )\n}\n\n/** Model a rounded rectangle exactly as the union of two bands and its corners. */\nconst roundedRect = ({\n x,\n y,\n width,\n height,\n cornerRadius,\n ccwRotationDegrees = 0,\n}: {\n x: number\n y: number\n width: number\n height: number\n cornerRadius: number\n ccwRotationDegrees?: number\n}): CopperGeometry | null => {\n const radius = Math.max(0, Math.min(cornerRadius, width / 2, height / 2))\n if (radius <= GEOMETRY_EPSILON) {\n const polygon = getRectanglePolygon({\n x,\n y,\n width,\n height,\n ccwRotationDegrees,\n })\n return polygon ? { kind: \"shapes\", shapes: [polygon] } : null\n }\n\n const shapes: CopperShape[] = []\n const innerWidth = width - 2 * radius\n const innerHeight = height - 2 * radius\n if (innerWidth > GEOMETRY_EPSILON) {\n const verticalBand = getRectanglePolygon({\n x,\n y,\n width: innerWidth,\n height,\n ccwRotationDegrees,\n })\n if (verticalBand) shapes.push(verticalBand)\n }\n if (innerHeight > GEOMETRY_EPSILON) {\n const horizontalBand = getRectanglePolygon({\n x,\n y,\n width,\n height: innerHeight,\n ccwRotationDegrees,\n })\n if (horizontalBand) shapes.push(horizontalBand)\n }\n\n const halfInnerWidth = innerWidth / 2\n const halfInnerHeight = innerHeight / 2\n const rotationMatrix = rotateDEG(ccwRotationDegrees, x, y)\n const cornerCenters = [\n { x: x - halfInnerWidth, y: y - halfInnerHeight },\n { x: x + halfInnerWidth, y: y - halfInnerHeight },\n { x: x + halfInnerWidth, y: y + halfInnerHeight },\n { x: x - halfInnerWidth, y: y + halfInnerHeight },\n ]\n .map((point) => applyToPoint(rotationMatrix, point))\n .filter(\n (point, index, points) =>\n points.findIndex(\n (candidate) =>\n Math.abs(candidate.x - point.x) <= GEOMETRY_EPSILON &&\n Math.abs(candidate.y - point.y) <= GEOMETRY_EPSILON,\n ) === index,\n )\n shapes.push(\n ...cornerCenters.map(\n (center) =>\n new Flatten.Circle(new Flatten.Point(center.x, center.y), radius),\n ),\n )\n\n return shapes.length > 0 ? { kind: \"shapes\", shapes } : null\n}\n\nconst pill = ({\n x,\n y,\n width,\n height,\n radius,\n ccwRotationDegrees = 0,\n}: {\n x: number\n y: number\n width: number\n height: number\n radius: number\n ccwRotationDegrees?: number\n}): CopperGeometry => {\n const halfLineLength = Math.max(Math.max(width, height) / 2 - radius, 0)\n const localAxis =\n width >= height ? { x: halfLineLength, y: 0 } : { x: 0, y: halfLineLength }\n const axis = applyToPoint(rotateDEG(ccwRotationDegrees), localAxis)\n\n if (halfLineLength <= GEOMETRY_EPSILON) {\n return {\n kind: \"shapes\",\n shapes: [new Flatten.Circle(new Flatten.Point(x, y), radius)],\n }\n }\n\n return {\n kind: \"pill\",\n centerLine: new Flatten.Segment(\n new Flatten.Point(x - axis.x, y - axis.y),\n new Flatten.Point(x + axis.x, y + axis.y),\n ),\n radius,\n }\n}\n\nconst getSmtPadGeometry = (pad: PcbSmtPad): CopperGeometry | null => {\n switch (pad.shape) {\n case \"circle\":\n return {\n kind: \"shapes\",\n shapes: [\n new Flatten.Circle(new Flatten.Point(pad.x, pad.y), pad.radius),\n ],\n }\n case \"rect\":\n return roundedRect({\n x: pad.x,\n y: pad.y,\n width: pad.width,\n height: pad.height,\n cornerRadius: pad.rect_border_radius ?? pad.corner_radius ?? 0,\n })\n case \"rotated_rect\":\n return roundedRect({\n x: pad.x,\n y: pad.y,\n width: pad.width,\n height: pad.height,\n cornerRadius: pad.rect_border_radius ?? pad.corner_radius ?? 0,\n ccwRotationDegrees: pad.ccw_rotation,\n })\n case \"pill\":\n return pill({\n x: pad.x,\n y: pad.y,\n width: pad.width,\n height: pad.height,\n radius: pad.radius,\n })\n case \"rotated_pill\":\n return pill({\n x: pad.x,\n y: pad.y,\n width: pad.width,\n height: pad.height,\n radius: pad.radius,\n ccwRotationDegrees: pad.ccw_rotation,\n })\n case \"polygon\": {\n const polygon = pointsToPolygon(pad.points)\n return polygon ? { kind: \"shapes\", shapes: [polygon] } : null\n }\n }\n}\n\nconst getPlatedHoleGeometry = (\n platedHole: PcbPlatedHole,\n componentCcwRotationDegrees: number,\n): CopperGeometry | null => {\n switch (platedHole.shape) {\n case \"circle\":\n return {\n kind: \"shapes\",\n shapes: [\n new Flatten.Circle(\n new Flatten.Point(platedHole.x, platedHole.y),\n platedHole.outer_diameter / 2,\n ),\n ],\n }\n case \"oval\":\n case \"pill\":\n return pill({\n x: platedHole.x,\n y: platedHole.y,\n width: platedHole.outer_width,\n height: platedHole.outer_height,\n radius: Math.min(\n platedHole.outer_width / 2,\n platedHole.outer_height / 2,\n ),\n ccwRotationDegrees: platedHole.ccw_rotation,\n })\n case \"circular_hole_with_rect_pad\":\n case \"pill_hole_with_rect_pad\":\n case \"rotated_pill_hole_with_rect_pad\":\n return roundedRect({\n x: platedHole.x,\n y: platedHole.y,\n width: platedHole.rect_pad_width,\n height: platedHole.rect_pad_height,\n cornerRadius: platedHole.rect_border_radius ?? 0,\n ccwRotationDegrees:\n \"rect_ccw_rotation\" in platedHole\n ? (platedHole.rect_ccw_rotation ?? 0)\n : 0,\n })\n case \"hole_with_polygon_pad\": {\n const ccwRotationDegrees =\n platedHole.ccw_rotation ?? componentCcwRotationDegrees\n const rotationMatrix = rotateDEG(ccwRotationDegrees)\n const polygon = pointsToPolygon(\n platedHole.pad_outline.map((point) => {\n const rotatedPoint = applyToPoint(rotationMatrix, point)\n return {\n x: platedHole.x + rotatedPoint.x,\n y: platedHole.y + rotatedPoint.y,\n }\n }),\n )\n return polygon ? { kind: \"shapes\", shapes: [polygon] } : null\n }\n }\n}\n\nconst getCopperGeometry = (\n element: CopperElement,\n componentCcwRotationsById: Map<PcbComponentId, number>,\n): CopperGeometry | null => {\n if (element.type === \"pcb_via\") {\n return {\n kind: \"shapes\",\n shapes: [\n new Flatten.Circle(\n new Flatten.Point(element.x, element.y),\n element.outer_diameter / 2,\n ),\n ],\n }\n }\n if (element.type === \"pcb_smtpad\") return getSmtPadGeometry(element)\n if (element.type === \"pcb_plated_hole\") {\n return getPlatedHoleGeometry(\n element,\n element.pcb_component_id\n ? (componentCcwRotationsById.get(\n toPcbComponentId(element.pcb_component_id),\n ) ?? 0)\n : 0,\n )\n }\n\n let polygon: Flatten.Polygon | null\n switch (element.shape) {\n case \"rect\":\n polygon = getRectanglePolygon({\n x: element.center.x,\n y: element.center.y,\n width: element.width,\n height: element.height,\n ccwRotationDegrees: element.rotation ?? 0,\n })\n break\n case \"polygon\":\n polygon = pointsToPolygon(element.points)\n break\n case \"brep\":\n // Holes remove copper, so only the outer ring can violate the board edge.\n polygon = brepRingToPolygon(element.brep_shape.outer_ring.vertices)\n break\n }\n return polygon ? { kind: \"shapes\", shapes: [polygon] } : null\n}\n\nconst getCopperElementId = (element: CopperElement): string => {\n if (element.type === \"pcb_via\") return element.pcb_via_id\n if (element.type === \"pcb_smtpad\") return element.pcb_smtpad_id\n if (element.type === \"pcb_plated_hole\") return element.pcb_plated_hole_id\n return element.pcb_copper_pour_id\n}\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\nconst measureClearance = (\n board: Flatten.Polygon,\n geometry: CopperGeometry,\n): { isInside: boolean; clearance: number } => {\n if (geometry.kind === \"shapes\") {\n const isInside = geometry.shapes.every((shape) => board.contains(shape))\n return {\n isInside,\n clearance: isInside\n ? Math.min(\n ...geometry.shapes.map((shape) => board.distanceTo(shape)[0]),\n )\n : 0,\n }\n }\n\n const centerLineClearance = board.distanceTo(geometry.centerLine)[0]\n const clearance = centerLineClearance - geometry.radius\n const isInside =\n board.contains(geometry.centerLine) && clearance >= -GEOMETRY_EPSILON\n return {\n isInside,\n clearance: isInside ? Math.max(0, clearance) : 0,\n }\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 const boardPolygon = boardToPolygon(board)\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<PcbComponentId>(\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) => toPcbComponentId(component.pcb_component_id)),\n )\n\n const copperElements = circuitJson.filter(\n (element): element is CopperElement =>\n element.type === \"pcb_via\" ||\n element.type === \"pcb_smtpad\" ||\n element.type === \"pcb_plated_hole\" ||\n element.type === \"pcb_copper_pour\",\n )\n const componentCcwRotationsById = new Map<PcbComponentId, number>(\n circuitJson\n .filter(\n (element): element is PcbComponent => element.type === \"pcb_component\",\n )\n .map((component) => [\n toPcbComponentId(component.pcb_component_id),\n component.rotation,\n ]),\n )\n\n const errors: PcbPlacementError[] = []\n for (const element of copperElements) {\n if (\n (element.type === \"pcb_smtpad\" || element.type === \"pcb_plated_hole\") &&\n element.pcb_component_id &&\n allowedOffBoardComponentIds.has(\n toPcbComponentId(element.pcb_component_id),\n )\n ) {\n continue\n }\n\n const geometry = getCopperGeometry(element, componentCcwRotationsById)\n if (!geometry) continue\n\n const { isInside, clearance } = measureClearance(boardPolygon, geometry)\n if (isInside && clearance + GEOMETRY_EPSILON >= requiredClearance) {\n continue\n }\n\n const id = getCopperElementId(element)\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 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[] {\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>()\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 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 (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 { getFullConnectivityMapFromCircuitJson } from \"circuit-json-to-connectivity-map\"\nimport { containsCircuitJsonId } from \"lib/util/get-readable-names\"\n\n/**\n * Check that each source_trace which connects source ports has at least one\n * pcb_trace associated with it. If a source_trace has no corresponding\n * pcb_trace, return an error for that source_trace.\n */\nfunction checkSourceTracesHavePcbTraces(\n circuitJson: AnyCircuitElement[],\n): PcbTraceMissingError[] {\n const errors: PcbTraceMissingError[] = []\n const sourceTraces = circuitJson.filter(\n (el) => el.type === \"source_trace\",\n ) as SourceTrace[]\n const pcbTraces = circuitJson.filter(\n (el) => el.type === \"pcb_trace\",\n ) as PcbTrace[]\n 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 = getFullConnectivityMapFromCircuitJson(circuitJson)\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 // 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 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 PcbConnectivityMap,\n} from \"circuit-json-to-connectivity-map\"\nimport { getLayersOfPcbElement } from \"../util/getLayersOfPcbElement\"\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): 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 const pcbConnectivityMap = new PcbConnectivityMap(circuitJson)\n let fullConnectivityMap: ConnectivityMap | undefined\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 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 || firstConnectsToLogicallyConnectedTraceCopper\n const lastIsConnected =\n lastConnectsToAnyPad || lastConnectsToLogicallyConnectedTraceCopper\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 { 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 PcbFootprintOverlapError,\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 {\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 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): PcbFootprintOverlapError[] {\n const errors: PcbFootprintOverlapError[] = []\n\n // Build connectivity map to check if components are electrically connected\n const connMap = getFullConnectivityMapFromCircuitJson(circuitJson)\n\n // Get all overlappable elements\n const smtPads = cju(circuitJson).pcb_smtpad.list()\n const platedHoles = cju(circuitJson).pcb_plated_hole.list()\n const holes = cju(circuitJson).pcb_hole.list()\n 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\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 (isCourtyardElement(elem1) || isCourtyardElement(elem2)) &&\n elem1.type !== \"pcb_hole\" &&\n elem2.type !== \"pcb_hole\"\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: PcbFootprintOverlapError = {\n type: \"pcb_footprint_overlap_error\",\n pcb_error_id: `pcb_footprint_overlap_${id1}_${id2}`,\n error_type: \"pcb_footprint_overlap_error\",\n message: `${elem1.type} ${elem1Description} overlaps with ${elem2.type} ${elem2Description}`,\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 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 { getPadToPadGap } from \"lib/check-pad-clearance/common\"\nimport { getLayersOfPcbElement } from \"lib/util/getLayersOfPcbElement\"\n\nexport type OverlappableElement =\n | PcbSmtPad\n | PcbPlatedHole\n | PcbHole\n | PcbCourtyardCircle\n | PcbCourtyardOutline\n | PcbCourtyardPolygon\n | PcbCourtyardRect\n\nfunction getElementLayers(elem: OverlappableElement): string[] {\n if (\n elem.type === \"pcb_courtyard_circle\" ||\n elem.type === \"pcb_courtyard_outline\" ||\n elem.type === \"pcb_courtyard_polygon\" ||\n elem.type === \"pcb_courtyard_rect\"\n ) {\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 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 a warning for every PCB component without a courtyard. */\nexport function checkPcbComponentsMissingCourtyard(\n circuitJson: AnyCircuitElement[],\n): PcbComponentMissingCourtyardWarning[] {\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 )\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 {\n AnyCircuitElement,\n PcbPort,\n PcbTrace,\n PcbTraceRoutePoint,\n PcbTraceTooLongWarning,\n SourceTrace,\n} from \"circuit-json\"\n\nconst DEFAULT_VIA_LENGTH_MM = 1.6\n\nconst getRoutePointPosition = (routePoint: PcbTraceRoutePoint) =>\n routePoint.route_type === \"through_pad\"\n ? routePoint.start\n : { x: routePoint.x, y: routePoint.y }\n\nconst getPcbTraceLength = (pcbTrace: PcbTrace): number => {\n if (pcbTrace.trace_length !== undefined) return pcbTrace.trace_length\n\n let traceLength = 0\n\n for (\n let routePointIndex = 0;\n routePointIndex < pcbTrace.route.length;\n routePointIndex++\n ) {\n const routePoint = pcbTrace.route[routePointIndex]\n if (!routePoint) continue\n\n if (routePoint.route_type === \"via\") {\n traceLength += DEFAULT_VIA_LENGTH_MM\n continue\n }\n\n const nextRoutePoint = pcbTrace.route[routePointIndex + 1]\n if (!nextRoutePoint) continue\n\n const routePointPosition = getRoutePointPosition(routePoint)\n const nextRoutePointPosition = getRoutePointPosition(nextRoutePoint)\n traceLength += Math.hypot(\n nextRoutePointPosition.x - routePointPosition.x,\n nextRoutePointPosition.y - routePointPosition.y,\n )\n }\n\n return traceLength\n}\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 checkPcbTraceLengths = (\n circuitJson: AnyCircuitElement[],\n): PcbTraceTooLongWarning[] => {\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 sourceTracesById = new Map(\n sourceTraces.map((sourceTrace) => [\n sourceTrace.source_trace_id,\n sourceTrace,\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 const warnings: PcbTraceTooLongWarning[] = []\n\n for (const pcbTrace of pcbTraces) {\n if (!pcbTrace.source_trace_id) continue\n\n const sourceTrace = sourceTracesById.get(pcbTrace.source_trace_id)\n if (!sourceTrace) continue\n\n const maximumTraceLength = sourceTrace.max_length\n if (typeof maximumTraceLength !== \"number\") continue\n\n const exactEndpointPcbTraceIds =\n exactEndpointPcbTraceIdsBySourceTraceId.get(sourceTrace.source_trace_id)\n if (\n exactEndpointPcbTraceIds &&\n !exactEndpointPcbTraceIds.has(pcbTrace.pcb_trace_id)\n ) {\n continue\n }\n\n const actualTraceLength = getPcbTraceLength(pcbTrace)\n if (actualTraceLength <= maximumTraceLength) continue\n\n warnings.push({\n type: \"pcb_trace_too_long_warning\",\n pcb_trace_too_long_warning_id: `pcb_trace_too_long_warning_${pcbTrace.pcb_trace_id}`,\n warning_type: \"pcb_trace_too_long_warning\",\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 warnings\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 getTraceCenter,\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 } = 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: getTraceCenter(segment),\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 getTraceCenter,\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 } = 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: getTraceCenter(segment),\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 getPadCenter,\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 const viaCenter = getPadCenter(via)\n const padCenter = getPadCenter(pad)\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: {\n x: (viaCenter.x + padCenter.x) / 2,\n y: (viaCenter.y + padCenter.y) / 2,\n },\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 { 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 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 { 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 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: `${componentName} is facing ${facingDirection} but should face ${recommendedFacingDirection} so the connector is accessible from the board edge`,\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 PcbCourtyardOverlapError,\n PcbCourtyardRect,\n PcbCourtyardCircle,\n PcbCourtyardOutline,\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 courtyards = circuitJson.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\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","import 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 { checkPcbCopperOverKeepout } from \"./check-pcb-copper-over-keepout\"\nimport { checkPcbComponentsOutOfBoard } from \"./check-pcb-components-out-of-board/checkPcbComponentsOutOfBoard\"\nimport { checkPcbComponentOverlap } from \"./check-pcb-components-overlap/checkPcbComponentOverlap\"\nimport { checkPcbComponentsMissingCourtyard } from \"./check-pcb-components-missing-courtyard\"\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 { 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(circuitJson: AnyCircuitElement[]) {\n return [\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}\n\nexport async function runAllNetlistChecks(circuitJson: AnyCircuitElement[]) {\n return [...checkPinMustBeConnected(circuitJson)]\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 return [\n ...checkEachPcbPortConnectedToPcbTraces(circuitJson),\n ...checkSourceTracesHavePcbTraces(circuitJson),\n ...checkPcbTraceLengths(circuitJson),\n ...checkPcbTraceViaCounts(circuitJson),\n ...checkEachPcbTraceNonOverlapping(circuitJson),\n ...checkPadTraceClearance(circuitJson),\n ...checkViaTraceClearance(circuitJson),\n ...checkViaPadClearance(circuitJson),\n ...checkSameNetViaSpacing(circuitJson),\n ...checkDifferentNetViaSpacing(circuitJson),\n ...checkTracesAreContiguous(circuitJson),\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"],"mappings":";AACA,SAAS,8BAA8B;;;ACDvC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,OACK;AASP,IAAM,cAAc,CAAC,OAAc,iBAAgC;AACjE,QAAM,QAAS,eAAe,KAAK,KAAM;AACzC,SAAO;AAAA,IACL,GAAG,MAAM,IAAI,KAAK,IAAI,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK;AAAA,IACvD,GAAG,MAAM,IAAI,KAAK,IAAI,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK;AAAA,EACzD;AACF;AAEO,IAAM,uBAAuB,CAAC;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAMe;AACb,QAAM,YAAY,QAAQ;AAC1B,QAAM,aAAa,SAAS;AAE5B,SAAO;AAAA,IACL,EAAE,GAAG,CAAC,WAAW,GAAG,CAAC,WAAW;AAAA,IAChC,EAAE,GAAG,WAAW,GAAG,CAAC,WAAW;AAAA,IAC/B,EAAE,GAAG,WAAW,GAAG,WAAW;AAAA,IAC9B,EAAE,GAAG,CAAC,WAAW,GAAG,WAAW;AAAA,EACjC,EAAE,IAAI,CAAC,UAAU;AACf,UAAM,UAAU,YAAY,OAAO,WAAW;AAC9C,WAAO,EAAE,GAAG,IAAI,QAAQ,GAAG,GAAG,IAAI,QAAQ,EAAE;AAAA,EAC9C,CAAC;AACH;AAEO,IAAM,0BAA0B,CAAC,QAAiB;AACvD,QAAM,QAAQ,IAAI,SAAS,oBAAoB,IAAI,cAAc,IAAI;AACrE,QAAM,SAAS,IAAI,SAAS,oBAAoB,IAAI,eAAe,IAAI;AACvE,QAAM,SACJ,IAAI,SAAS,oBAAoB,KAAK,IAAI,OAAO,MAAM,IAAI,IAAI,IAAI;AACrE,QAAM,cACJ,IAAI,SAAS,oBACT,IAAI,eACJ,IAAI,UAAU,iBACZ,IAAI,eACJ;AACR,QAAM,iBAAiB,KAAK,IAAI,KAAK,IAAI,OAAO,MAAM,IAAI,IAAI,QAAQ,CAAC;AACvE,QAAM,OACJ,SAAS,SAAS,EAAE,GAAG,gBAAgB,GAAG,EAAE,IAAI,EAAE,GAAG,GAAG,GAAG,eAAe;AAC5E,QAAM,cAAc,YAAY,MAAM,WAAW;AAEjD,SAAO;AAAA,IACL,OAAO,EAAE,GAAG,IAAI,IAAI,YAAY,GAAG,GAAG,IAAI,IAAI,YAAY,EAAE;AAAA,IAC5D,KAAK,EAAE,GAAG,IAAI,IAAI,YAAY,GAAG,GAAG,IAAI,IAAI,YAAY,EAAE;AAAA,IAC1D;AAAA,EACF;AACF;AAEO,IAAM,yBAAyB,CAAC,QAA+B;AACpE,MAAI,IAAI,SAAS,cAAc;AAC7B,QAAI,IAAI,UAAU,UAAW,QAAO,IAAI;AAExC,QAAI,IAAI,UAAU,gBAAgB;AAChC,aAAO,qBAAqB;AAAA,QAC1B,GAAG,IAAI;AAAA,QACP,GAAG,IAAI;AAAA,QACP,OAAO,IAAI;AAAA,QACX,QAAQ,IAAI;AAAA,QACZ,aAAa,IAAI;AAAA,MACnB,CAAC;AAAA,IACH;AAAA,EACF;AAEA,MACE,IAAI,SAAS,qBACb,oBAAoB,OACpB,qBAAqB,KACrB;AACA,WAAO,qBAAqB;AAAA,MAC1B,GAAG,IAAI;AAAA,MACP,GAAG,IAAI;AAAA,MACP,OAAO,IAAI;AAAA,MACX,QAAQ,IAAI;AAAA,MACZ,aACE,uBAAuB,OAAO,OAAO,IAAI,sBAAsB,WAC3D,IAAI,oBACJ;AAAA,IACR,CAAC;AAAA,EACH;AAEA,QAAM,IAAI;AAAA,IACR,wCAAwC,IAAI,IAAI,gBAAgB,IAAI,KAAK;AAAA,EAC3E;AACF;AAEA,IAAM,kBAAkB,CAAC,WACvB,OAAO;AAAA,EACL,CAAC,OAAO,UAAU,CAAC,OAAO,QAAQ,QAAQ,KAAK,OAAO,MAAM,CAAE;AAChE;AAEF,IAAM,kCAAkC,CACtC,IACA,IACA,IACA,OACG;AACH,QAAM,eAAe,uBAAuB,IAAI,IAAI,IAAI,EAAE;AAC1D,MAAI,cAAc;AAChB,WAAO;AAAA,MACL,UAAU;AAAA,MACV,UAAU;AAAA,MACV,UAAU;AAAA,MACV,QAAQ;AAAA,IACV;AAAA,EACF;AAEA,QAAM,aAAa;AAAA,IACjB,EAAE,UAAU,IAAI,UAAU,2BAA2B,IAAI,IAAI,EAAE,EAAE;AAAA,IACjE,EAAE,UAAU,IAAI,UAAU,2BAA2B,IAAI,IAAI,EAAE,EAAE;AAAA,IACjE,EAAE,UAAU,2BAA2B,IAAI,IAAI,EAAE,GAAG,UAAU,GAAG;AAAA,IACjE,EAAE,UAAU,2BAA2B,IAAI,IAAI,EAAE,GAAG,UAAU,GAAG;AAAA,EACnE;AAEA,MAAI,OAAO,WAAW,CAAC;AACvB,MAAI,sBAAsB,OAAO,KAAK,UAAU,KAAK,QAAQ;AAC7D,aAAW,aAAa,WAAW,MAAM,CAAC,GAAG;AAC3C,UAAM,2BAA2B;AAAA,MAC/B,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AACA,QAAI,2BAA2B,qBAAqB;AAClD,aAAO;AACP,4BAAsB;AAAA,IACxB;AAAA,EACF;AAEA,SAAO;AAAA,IACL,UAAU,4BAA4B,IAAI,IAAI,IAAI,EAAE;AAAA,IACpD,UAAU,KAAK;AAAA,IACf,UAAU,KAAK;AAAA,IACf,QAAQ;AAAA,MACN,IAAI,KAAK,SAAS,IAAI,KAAK,SAAS,KAAK;AAAA,MACzC,IAAI,KAAK,SAAS,IAAI,KAAK,SAAS,KAAK;AAAA,IAC3C;AAAA,EACF;AACF;AAEO,IAAM,yCAAyC,CACpD,OACA,KACA,YACG;AACH,MAAI,QAAQ,SAAS,GAAG;AACtB,WAAO;AAAA,MACL,UAAU,OAAO;AAAA,MACjB,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,eAAe;AAAA,IACjB;AAAA,EACF;AAEA,QAAM,gBAAgB,gBAAgB,OAAO,EAC1C;AAAA,IAAI,CAAC,CAAC,WAAW,OAAO,MACvB,uBAAuB,OAAO,KAAK,WAAW,OAAO;AAAA,EACvD,EACC,OAAO,CAAC,UAA0B,UAAU,IAAI;AAEnD,MAAI,cAAc,SAAS,GAAG;AAC5B,UAAM,KAAK,IAAI,IAAI,MAAM;AACzB,UAAM,KAAK,IAAI,IAAI,MAAM;AACzB,UAAM,gBAAgB,KAAK,KAAK,KAAK;AACrC,kBAAc,KAAK,CAAC,GAAG,MAAM;AAC3B,YAAM,OAAO,EAAE,IAAI,MAAM,KAAK,MAAM,EAAE,IAAI,MAAM,KAAK,MAAM;AAC3D,YAAM,OAAO,EAAE,IAAI,MAAM,KAAK,MAAM,EAAE,IAAI,MAAM,KAAK,MAAM;AAC3D,aAAO,KAAK;AAAA,IACd,CAAC;AAED,WAAO;AAAA,MACL,UAAU;AAAA,MACV,QAAQ,cAAc,CAAC;AAAA,MACvB,YAAY,cAAc,CAAC;AAAA,MAC3B,eAAe,cAAc,CAAC;AAAA,IAChC;AAAA,EACF;AAEA,MACE,qBAAqB,OAAO,OAAO,KACnC,qBAAqB,KAAK,OAAO,GACjC;AACA,UAAM,SAAS;AAAA,MACb,IAAI,MAAM,IAAI,IAAI,KAAK;AAAA,MACvB,IAAI,MAAM,IAAI,IAAI,KAAK;AAAA,IACzB;AACA,WAAO;AAAA,MACL,UAAU;AAAA,MACV;AAAA,MACA,YAAY;AAAA,MACZ,eAAe;AAAA,IACjB;AAAA,EACF;AAEA,MAAI,OAAO;AAAA,IACT;AAAA,IACA;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,QAAQ,CAAC;AAAA,EACX;AAEA,aAAW,CAAC,WAAW,OAAO,KAAK,gBAAgB,OAAO,EAAE,MAAM,CAAC,GAAG;AACpE,UAAM,YAAY;AAAA,MAChB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,QAAI,UAAU,WAAW,KAAK,SAAU,QAAO;AAAA,EACjD;AAEA,SAAO;AAAA,IACL,UAAU,KAAK;AAAA,IACf,QAAQ,KAAK;AAAA,IACb,YAAY,KAAK;AAAA,IACjB,eAAe,KAAK;AAAA,EACtB;AACF;AAYO,IAAM,4BAA4B,CACvC,SACA,QACG;AACH,QAAMA,QAAO,wBAAwB,GAAG;AACxC,QAAM,UAAU;AAAA,IACd,EAAE,GAAG,QAAQ,IAAI,GAAG,QAAQ,GAAG;AAAA,IAC/B,EAAE,GAAG,QAAQ,IAAI,GAAG,QAAQ,GAAG;AAAA,IAC/BA,MAAK;AAAA,IACLA,MAAK;AAAA,EACP;AAEA,SAAO;AAAA,IACL,UAAU,QAAQ;AAAA,IAClB,QAAQ,QAAQ;AAAA,IAChB,QAAQA,MAAK;AAAA,IACb,YAAY,QAAQ;AAAA,IACpB,eAAe,QAAQ;AAAA,EACzB;AACF;;;ADxQA,SAAS,yBACP,QACA,QACQ;AACR,SAAO,KAAK,MAAM,OAAO,IAAI,OAAO,MAAM,KAAK,OAAO,IAAI,OAAO,MAAM,CAAC;AAC1E;AAEA,IAAM,gCAAgC;AAKtC,IAAM,4BAA4B;AAElC,SAAS,iBACP,OACA,SACA;AACA,QAAM,gBACH,MAAM,IAAI,QAAQ,MAAM,MAAM,QAAQ,IAAI,IAAI,QAAQ,MAAM,MAC5D,MAAM,IAAI,QAAQ,MAAM,MAAM,QAAQ,IAAI,IAAI,QAAQ,MAAM;AAC/D,MAAI,KAAK,IAAI,YAAY,IAAI,8BAA+B,QAAO;AAEnE,QAAM,cACH,MAAM,IAAI,QAAQ,MAAM,MAAM,QAAQ,IAAI,IAAI,QAAQ,MAAM,MAC5D,MAAM,IAAI,QAAQ,MAAM,MAAM,QAAQ,IAAI,IAAI,QAAQ,MAAM;AAC/D,MAAI,aAAa,CAAC,8BAA+B,QAAO;AAExD,QAAM,iBACH,QAAQ,IAAI,IAAI,QAAQ,MAAM,MAAM,KACpC,QAAQ,IAAI,IAAI,QAAQ,MAAM,MAAM;AACvC,SAAO,cAAc,gBAAgB;AACvC;AAEA,SAAS,iBACP,OACA,SACS;AACT,MAAI,SAAS;AACb,WAAS,IAAI,GAAG,IAAI,QAAQ,SAAS,GAAG,IAAI,QAAQ,QAAQ,IAAI,KAAK;AACnE,UAAM,KAAK,QAAQ,CAAC;AACpB,UAAM,KAAK,QAAQ,CAAC;AACpB,QAAI,iBAAiB,OAAO,EAAE,OAAO,IAAI,KAAK,GAAG,CAAC,EAAG,QAAO;AAE5D,UAAM,aACJ,GAAG,IAAI,MAAM,MAAM,GAAG,IAAI,MAAM,KAChC,MAAM,KAAM,GAAG,IAAI,GAAG,MAAM,MAAM,IAAI,GAAG,MAAO,GAAG,IAAI,GAAG,KAAK,GAAG;AACpE,QAAI,WAAY,UAAS,CAAC;AAAA,EAC5B;AACA,SAAO;AACT;AAEO,SAAS,aACd,OACA,KACS;AACT,MAAI,IAAI,SAAS,cAAc;AAC7B,QAAI,IAAI,UAAU,UAAU;AAC1B,aACE,yBAAyB,OAAO,GAAG,KACnC,IAAI,SAAS;AAAA,IAEjB;AAEA,QAAI,IAAI,UAAU,QAAQ;AACxB,YAAM,YAAY,IAAI,QAAQ;AAC9B,YAAM,aAAa,IAAI,SAAS;AAChC,aACE,KAAK,IAAI,MAAM,IAAI,IAAI,CAAC,KAAK,YAAY,6BACzC,KAAK,IAAI,MAAM,IAAI,IAAI,CAAC,KAAK,aAAa;AAAA,IAE9C;AAEA,QAAI,IAAI,UAAU,gBAAgB;AAChC,aAAO,iBAAiB,OAAO,uBAAuB,GAAG,CAAC;AAAA,IAC5D;AAEA,QAAI,IAAI,UAAU,UAAU,IAAI,UAAU,gBAAgB;AACxD,UAAI,IAAI,UAAU,gBAAgB;AAChC,cAAMC,QAAO,wBAAwB,GAAG;AACxC,eACE,uBAAuB,OAAOA,MAAK,OAAOA,MAAK,GAAG,KAClDA,MAAK,SAAS;AAAA,MAElB;AAEA,YAAM,YAAY,IAAI,QAAQ;AAC9B,YAAM,aAAa,IAAI,SAAS;AAChC,YAAM,SAAS,IAAI;AAEnB,UACE,KAAK,IAAI,MAAM,IAAI,IAAI,CAAC,KACtB,YAAY,SAAS,6BACvB,KAAK,IAAI,MAAM,IAAI,IAAI,CAAC,KAAK,aAAa,2BAC1C;AACA,eAAO;AAAA,MACT;AAEA,YAAM,UAAU,KAAK;AAAA,QACnB,KAAK,IAAI,MAAM,IAAI,IAAI,CAAC,KAAK,YAAY;AAAA,QACzC;AAAA,MACF;AACA,YAAM,UAAU,KAAK;AAAA,QACnB,KAAK,IAAI,MAAM,IAAI,IAAI,CAAC,KAAK,aAAa;AAAA,QAC1C;AAAA,MACF;AACA,YAAM,sBAAsB,SAAS;AACrC,aACE,UAAU,UAAU,UAAU,WAC9B,sBAAsB;AAAA,IAE1B;AAEA,QAAI,IAAI,UAAU,WAAW;AAC3B,aAAO,iBAAiB,OAAO,IAAI,MAAM;AAAA,IAC3C;AAAA,EACF;AAEA,MAAI,IAAI,SAAS,mBAAmB;AAClC,QAAI,IAAI,UAAU,UAAU;AAC1B,aACE,yBAAyB,OAAO,GAAG,KACnC,IAAI,iBAAiB,IAAI;AAAA,IAE7B;AAEA,QAAI,oBAAoB,OAAO,qBAAqB,KAAK;AACvD,aAAO,iBAAiB,OAAO,uBAAuB,GAAG,CAAC;AAAA,IAC5D;AAEA,QAAI,IAAI,UAAU,UAAU,IAAI,UAAU,QAAQ;AAChD,aACE,KAAK,IAAI,MAAM,IAAI,IAAI,CAAC,KACtB,IAAI,cAAc,IAAI,6BACxB,KAAK,IAAI,MAAM,IAAI,IAAI,CAAC,KACtB,IAAI,eAAe,IAAI;AAAA,IAE7B;AAAA,EACF;AAEA,SAAO;AACT;;;AE5IA,SAAS,SAAS,IAAY,IAAY,IAAY,IAAoB;AACxE,SAAO,KAAK,MAAM,KAAK,OAAO,KAAK,KAAK,OAAO,CAAC;AAClD;AAMO,IAAM,iCAAiC,CAC5C,SACS;AACT,QAAM,WAAsB,KAAK,OAAO,CAAC,SAAS,KAAK,SAAS,UAAU;AAC1E,QAAM,aAA0B,KAAK;AAAA,IACnC,CAAC,SAAS,KAAK,SAAS;AAAA,EAC1B;AACA,QAAM,YAAwB,KAAK,OAAO,CAAC,SAAS,KAAK,SAAS,WAAW;AAE7E,WAAS,2BACP,OAIA,UAAiE,CAAC,GACnD;AACf,UAAM,aAAa,QAAQ,cAAc;AACzC,UAAM,aAAa,SAAS;AAAA,MAC1B,CAAC,SAAS,SAAS,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC,IAAI;AAAA,IACzD;AACA,QAAI,WAAY,QAAO,WAAW;AAGlC,QAAI,QAAQ,oBAAoB;AAC9B,YAAM,SAAS,WAAW,KAAK,CAAC,QAAQ;AACtC,YAAI,IAAI,UAAU,QAAQ;AACxB,iBACE,KAAK,IAAI,MAAM,IAAI,IAAI,CAAC,IAAI,IAAI,QAAQ,IAAI,aAAa,KACzD,KAAK,IAAI,MAAM,IAAI,IAAI,CAAC,IAAI,IAAI,SAAS,IAAI,aAAa;AAAA,QAG9D,WAAW,IAAI,UAAU,UAAU;AACjC,iBAAO,SAAS,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI;AAAA,QACxD,WAAW,IAAI,UAAU,UAAU,IAAI,UAAU,gBAAgB;AAC/D,iBAAO,aAAa,OAAO,GAAG;AAAA,QAChC;AAAA,MACF,CAAC;AACD,UAAI,OAAQ,QAAO,OAAO,eAAe;AAAA,IAC3C;AAEA,WAAO;AAAA,EACT;AAGA,aAAW,SAAS,WAAW;AAC7B,aAAS,QAAQ,GAAG,QAAQ,MAAM,MAAM,QAAQ,SAAS;AACvD,YAAM,UAAU,MAAM,MAAM,KAAK;AACjC,YAAM,qBAAqB,UAAU,KAAK,UAAU,MAAM,MAAM,SAAS;AACzE,UAAI,QAAQ,eAAe,QAAQ;AACjC,YAAI,CAAC,QAAQ,qBAAqB,UAAU,GAAG;AAC7C,gBAAM,cAAc,2BAA2B,SAAS;AAAA,YACtD;AAAA,YACA,YAAY,QAAQ;AAAA,UACtB,CAAC;AACD,cAAI,aAAa;AACf,oBAAQ,oBAAoB;AAAA,UAC9B;AAAA,QACF;AACA,YAAI,CAAC,QAAQ,mBAAmB,UAAU,MAAM,MAAM,SAAS,GAAG;AAChE,gBAAM,YAAY,2BAA2B,SAAS;AAAA,YACpD;AAAA,YACA,YAAY,QAAQ;AAAA,UACtB,CAAC;AACD,cAAI,WAAW;AACb,oBAAQ,kBAAkB;AAAA,UAC5B;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;AC9EA;AAAA,EACE;AAAA,EACA;AAAA,OACK;;;ACLP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,IAAM,0BACJ;AAEF,IAAM,uBAAuB,CAC3B,WACA,IACA,kBACW;AACX,MACE,CAAC,aACD,cAAc,MACd,wBAAwB,KAAK,SAAS,GACtC;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,IAAM,oBAAoB,CACxB,YACA,OACW;AACX,aAAW,aAAa,YAAY;AAClC,UAAM,eAAe,qBAAqB,WAAW,IAAI,EAAE;AAC3D,QAAI,aAAc,QAAO;AAAA,EAC3B;AACA,SAAO;AACT;AAEO,IAAM,8BAA8B,CACzC,aACA,mBAEA;AAAA,EACE,0BAA0B,aAAa,cAAc;AAAA,EACrD;AAAA,EACA;AACF;AAEK,IAAM,yBAAyB,CACpC,aACA,cACW;AACX,QAAM,UAAU,YAAY;AAAA,IAC1B,CAAC,YACC,QAAQ,SAAS,cAAc,QAAQ,gBAAgB;AAAA,EAC3D;AAEA,MAAI,SAAS,SAAS,YAAY;AAChC,UAAM,aAAa,YAAY;AAAA,MAC7B,CAAC,YACC,QAAQ,SAAS,iBACjB,QAAQ,mBAAmB,QAAQ;AAAA,IACvC;AAEA,UAAM,kBACJ,YAAY,SAAS,gBACjB,YAAY;AAAA,MACV,CAAC,YACC,QAAQ,SAAS,sBACjB,QAAQ,wBAAwB,WAAW;AAAA,IAC/C,IACA;AAEN,UAAM,8BAA8B;AAAA,MAClC;AAAA,QACE,iBAAiB,SAAS,qBACtB,gBAAgB,OAChB;AAAA,MACN;AAAA,MACA,iBAAiB,SAAS,qBACtB,gBAAgB,sBAChB;AAAA,IACN;AAEA,UAAM,yBAAyB;AAAA,MAC7B;AAAA,QACE,YAAY,SAAS,gBAAgB,WAAW,OAAO;AAAA,QACvD,YAAY,SAAS,gBACjB,WAAW,YAAY,SAAS,IAChC;AAAA,QACJ,YAAY,SAAS,gBAAgB,WAAW,aAAa,CAAC,IAAI;AAAA,MACpE;AAAA,MACA,YAAY,SAAS,gBAAgB,WAAW,iBAAiB;AAAA,IACnE;AAEA,QAAI,+BAA+B,wBAAwB;AACzD,aAAO,GAAG,2BAA2B,IAAI,sBAAsB;AAAA,IACjE;AACA,QAAI,wBAAwB;AAC1B,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AAAA,IACL,0BAA0B,aAAa,SAAS,KAC9C,0BAA0B,aAAa,SAAS;AAAA,IAClD;AAAA,IACA;AAAA,EACF;AACF;AAEO,IAAM,gCAAgC,CAC3C,aACA,gBACW;AACX,QAAM,cAAc;AAAA,IAClB,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ;AAAA,EACF;AACA,MAAI,YAAa,QAAO;AAExB,QAAM,sBAAsB,YAAY,6BAA6B,CAAC,GACnE,IAAI,CAAC,iBAAiB;AACrB,UAAM,UAAU,YAAY;AAAA,MAC1B,CAAC,YACC,QAAQ,SAAS,cACjB,QAAQ,mBAAmB;AAAA,IAC/B;AAEA,QAAI,SAAS,SAAS,YAAY;AAChC,aAAO,uBAAuB,aAAa,QAAQ,WAAW;AAAA,IAChE;AAEA,UAAM,aAAa,YAAY;AAAA,MAC7B,CAAC,YACC,QAAQ,SAAS,iBACjB,QAAQ,mBAAmB;AAAA,IAC/B;AACA,QAAI,YAAY,SAAS,cAAe,QAAO;AAE/C,UAAM,kBAAkB,YAAY;AAAA,MAClC,CAAC,YACC,QAAQ,SAAS,sBACjB,QAAQ,wBAAwB,WAAW;AAAA,IAC/C;AAEA,UAAM,sBACJ,iBAAiB,SAAS,qBACtB;AAAA,MACE,gBAAgB;AAAA,MAChB,gBAAgB;AAAA,MAChB;AAAA,IACF,IACA;AAEN,UAAM,iBAAiB;AAAA,MACrB;AAAA,QACE,WAAW;AAAA,QACX,WAAW,YAAY,SAAS;AAAA,QAChC,WAAW,aAAa,CAAC;AAAA,MAC3B;AAAA,MACA,WAAW;AAAA,IACb;AAEA,QAAI,uBAAuB,gBAAgB;AACzC,aAAO,GAAG,mBAAmB,IAAI,cAAc;AAAA,IACjD;AAEA,WAAO,kBAAkB;AAAA,EAC3B,CAAC,EACA,OAAO,CAAC,SAAyB,QAAQ,IAAI,CAAC;AAEjD,MAAI,mBAAmB,UAAU,GAAG;AAClC,WAAO,GAAG,mBAAmB,CAAC,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAAA,EAC7D;AAEA,MAAI,mBAAmB,WAAW,GAAG;AACnC,WAAO,sBAAsB,mBAAmB,CAAC,CAAC;AAAA,EACpD;AAEA,SAAO,SAAS,YAAY,eAAe;AAC7C;AAEO,IAAM,8BAA8B,CACzC,aACA,cAEA;AAAA,EACE,0BAA0B,aAAa,SAAS;AAAA,EAChD;AAAA,EACA;AACF;AAYK,IAAM,wBAAwB,CAAC,YACpC,wBAAwB,KAAK,OAAO;AAE/B,SAAS,+BACd,aACA,KACA,SACQ;AACR,QAAM,UAAU,IAAI,SAAS,eAAe,YAAY;AACxD,QAAM,UAAU,IAAI,cAChB,uBAAuB,aAAa,IAAI,WAAW,IACnD;AACJ,QAAM,SAAS,uBAAuB,CAAC,GAAG,CAAC;AAC3C,QAAM,WAAW,OAAO,OAAO,OAAO,QAAQ;AAC9C,QAAM,WAAW,OAAO,OAAO,OAAO,QAAQ;AAC9C,QAAM,WAAW,IAAI,QAAQ,QAAQ,CAAC,CAAC,OAAO,QAAQ,QAAQ,CAAC,CAAC;AAEhE,MAAI,QAAS,QAAO,GAAG,OAAO,IAAI,OAAO,OAAO,QAAQ;AACxD,SAAO,GAAG,OAAO,KAAK,UAAU,CAAC,OAAO,QAAQ;AAClD;;;ADpNA,SAAS,qCACP,aAC4B;AAC5B,iCAA+B,WAAW;AAC1C,QAAM,eAA8B,YAAY;AAAA,IAC9C,CAAC,SAAS,KAAK,SAAS;AAAA,EAC1B;AAEA,QAAM,WAAsB,YAAY;AAAA,IACtC,CAAC,SAAS,KAAK,SAAS;AAAA,EAC1B;AACA,QAAM,aAA0B,YAAY;AAAA,IAC1C,CAAC,SAAS,KAAK,SAAS;AAAA,EAC1B;AAEA,QAAM,SAAqC,CAAC;AAG5C,QAAM,kBAAkB,sCAAsC,WAAW;AACzE,QAAM,qBAAqB,IAAI,mBAAmB,WAAW;AAG7D,QAAM,sBAAsB,oBAAI,IAAqB;AACrD,aAAW,WAAW,UAAU;AAC9B,wBAAoB,IAAI,QAAQ,gBAAgB,OAAO;AAAA,EACzD;AAEA,QAAM,oBAAoB,IAAI;AAAA,IAC5B,WAAW,IAAI,CAAC,cAAc,CAAC,UAAU,eAAe,UAAU,IAAI,CAAC;AAAA,EACzE;AAGA,aAAW,eAAe,cAAc;AACtC,UAAM,yBAAyB,YAAY;AAE3C,QACE,uBAAuB,WAAW,KAClC,YAAY,yBAAyB,SAAS,GAC9C;AACA,YAAM,UAAU,oBAAoB,IAAI,uBAAuB,CAAC,CAAC;AACjE,UAAI,CAAC,QAAS;AAEd,YAAM,qBAAqB,mBAAmB;AAAA,QAC5C,QAAQ;AAAA,MACV;AAEA,UAAI,mBAAmB,WAAW,GAAG;AACnC,cAAM,oBAAoB,YAAY,yBACnC,IAAI,CAAC,gBAAgB,kBAAkB,IAAI,WAAW,CAAC,EACvD,OAAO,CAAC,SAAyB,QAAQ,IAAI,CAAC;AACjD,cAAM,iBACJ,kBAAkB,SAAS,IACvB,QAAQ,kBAAkB,KAAK,IAAI,CAAC,MACpC;AAEN,eAAO,KAAK;AAAA,UACV,MAAM;AAAA,UACN,SAAS,SAAS,uBAAuB,aAAa,QAAQ,WAAW,CAAC,yBAAyB,cAAc;AAAA,UACjH,YAAY;AAAA,UACZ,cAAc,CAAC,QAAQ,WAAW;AAAA,UAClC,mBAAmB,QAAQ,mBACvB,CAAC,QAAQ,gBAAgB,IACzB,CAAC;AAAA,UACL,iCAAiC,sCAAsC,YAAY,eAAe;AAAA,QACpG,CAAC;AAAA,MACH;AAEA;AAAA,IACF;AAGA,QAAI,uBAAuB,SAAS,GAAG;AACrC;AAAA,IACF;AAGA,UAAM,kBAA6B,CAAC;AACpC,UAAM,kBAA4B,CAAC;AAEnC,eAAW,gBAAgB,wBAAwB;AACjD,YAAM,UAAU,oBAAoB,IAAI,YAAY;AACpD,UAAI,SAAS;AACX,wBAAgB,KAAK,OAAO;AAAA,MAC9B,OAAO;AACL,wBAAgB,KAAK,YAAY;AAAA,MACnC;AAAA,IACF;AAGA,QAAI,gBAAgB,SAAS,GAAG;AAC9B;AAAA,IACF;AAGA,UAAM,eAAe,gBAAgB,CAAC;AACtC,UAAM,iBAAiB,gBAAgB;AAAA,MACrC,aAAa;AAAA,IACf;AAEA,UAAM,gBAAgB,gBAAgB,qBAAqB,cAAe;AAC1E,UAAM,cAAc,cAAc;AAAA,MAAO,CAAC,OACxC,YAAY;AAAA,QACV,CAAC,YACC,QAAQ,SAAS,gBACf,kBAAkB,WAAW,QAAQ,iBAAiB,MACrD,cAAc,WAAW,QAAQ,aAAa;AAAA,MACrD;AAAA,IACF;AAEA,QAAI,YAAY,WAAW,GAAG;AAE5B,YAAM,qBAAqB,IAAI;AAAA,QAC7B,gBAAgB,IAAI,CAAC,MAAM,EAAE,gBAAgB;AAAA,MAC/C;AAEA,UAAI,mBAAmB,OAAO,GAAG;AAE/B,eAAO,KAAK;AAAA,UACV,MAAM;AAAA,UACN,SAAS,UAAU,gBAAgB,IAAI,CAAC,MAAM,uBAAuB,aAAa,EAAE,WAAW,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA,UAC5G,YAAY;AAAA,UACZ,cAAc,gBAAgB,IAAI,CAAC,MAAM,EAAE,WAAW;AAAA,UACtD,mBAAmB,gBAChB,IAAI,CAAC,MAAM,EAAE,gBAAgB,EAC7B,OAAO,CAAC,OAAqB,OAAO,MAAS;AAAA,UAChD,iCAAiC,sCAAsC,YAAY,eAAe;AAAA,QACpG,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;AElJA,SAAS,OAAAC,MAAK,6BAAAC,kCAAiC;AAC/C,SAAS,oBAAoB;AAC7B;AAAA,EACE;AAAA,EACA,8BAAAC;AAAA,OACK;AACP,SAAS,+BAAAC,oCAAmC;AAQ5C;AAAA,EAEE,yCAAAC;AAAA,OACK;;;ACjBP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,0BAAAC;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA,8BAAAC;AAAA,EACA;AAAA,EACA,+BAAAC;AAAA,OACK;;;ACRA,IAAM,mBAAoC;AAAA,EAC/C,iBAAiB;AAAA,EACjB,8CAA8C;AAAA,EAC9C,oDAAoD;AAAA,EACpD,iCAAiC;AAAA,EACjC,oCAAoC;AAAA,EACpC,0BAA0B;AAAA,EAC1B,uBAAuB;AAAA,EACvB,sBAAsB;AACxB;;;ACNO,IAAM,uBAAuB;AAC7B,IAAM,0BAA0B,iBAAiB;AACjD,IAAM,uBAAuB,iBAAiB;AAC9C,IAAM,2BACX,iBAAiB;AAEZ,IAAM,8BACX,iBAAiB;AACZ,IAAM,mCACX,iBAAiB;AAEZ,IAAM,4BACX,iBAAiB;AAEZ,IAAM,UAAU;AAEhB,IAAM,cAAc,CACzB,gBAEA,YAAY,KAAK,CAAC,OAAuB,GAAG,SAAS,WAAW;AAE3D,IAAM,mBAAmB,CAC9B,OACA,QACkC,QAAQ,GAAG;;;AFIxC,IAAM,eAAe,CAAC,QAAwC;AACnE,MAAI,IAAI,SAAS,eAAe;AAC9B,QAAI,IAAI,UAAU,WAAW;AAC3B,aAAO;AAAA,QACL,MAAM,KAAK,IAAI,GAAG,IAAI,QAAQ,IAAI,CAAC,UAAU,MAAM,CAAC,CAAC;AAAA,QACrD,MAAM,KAAK,IAAI,GAAG,IAAI,QAAQ,IAAI,CAAC,UAAU,MAAM,CAAC,CAAC;AAAA,QACrD,MAAM,KAAK,IAAI,GAAG,IAAI,QAAQ,IAAI,CAAC,UAAU,MAAM,CAAC,CAAC;AAAA,QACrD,MAAM,KAAK,IAAI,GAAG,IAAI,QAAQ,IAAI,CAAC,UAAU,MAAM,CAAC,CAAC;AAAA,MACvD;AAAA,IACF;AAEA,QAAI,IAAI,UAAU,UAAU;AAC1B,aAAO;AAAA,QACL,MAAM,IAAI,OAAO,IAAI,IAAI;AAAA,QACzB,MAAM,IAAI,OAAO,IAAI,IAAI;AAAA,QACzB,MAAM,IAAI,OAAO,IAAI,IAAI;AAAA,QACzB,MAAM,IAAI,OAAO,IAAI,IAAI;AAAA,MAC3B;AAAA,IACF;AAEA,WAAO;AAAA,MACL,MAAM,IAAI,OAAO,IAAI,IAAI,QAAQ;AAAA,MACjC,MAAM,IAAI,OAAO,IAAI,IAAI,SAAS;AAAA,MAClC,MAAM,IAAI,OAAO,IAAI,IAAI,QAAQ;AAAA,MACjC,MAAM,IAAI,OAAO,IAAI,IAAI,SAAS;AAAA,IACpC;AAAA,EACF;AAEA,SAAOC,wBAAuB,CAAC,GAAG,CAAC;AACrC;AAEO,IAAM,eAAe,CAAC,QAAgC;AAC3D,MAAI,IAAI,SAAS,iBAAiB,IAAI,UAAU,UAAW,QAAO,IAAI;AACtE,QAAM,SAAS,aAAa,GAAG;AAC/B,SAAO;AAAA,IACL,EAAE,GAAG,OAAO,MAAM,GAAG,OAAO,KAAK;AAAA,IACjC,EAAE,GAAG,OAAO,MAAM,GAAG,OAAO,KAAK;AAAA,EACnC;AACF;AAEO,IAAM,eAAe,CAAC,QAAgC;AAC3D,MAAI,IAAI,SAAS,iBAAiB,IAAI,UAAU,SAAU,QAAO,IAAI;AACrE,QAAM,SAAS,aAAa,GAAG;AAC/B,SAAO,KAAK,IAAI,OAAO,OAAO,OAAO,MAAM,OAAO,OAAO,OAAO,IAAI,IAAI;AAC1E;AAEO,IAAM,gBAAgB,CAAC,QAC5B,IAAI,SAAS,aAAa,IAAI,UAAU;AAE1C,IAAM,YAAY,CAChB,QAIC,IAAI,SAAS,iBACX,IAAI,UAAU,UAAU,IAAI,UAAU,mBACxC,IAAI,SAAS,sBACX,IAAI,UAAU,UAAU,IAAI,UAAU;AAE3C,IAAM,iBAAiB,CAAC,QAAgC;AACtD,QAAM,SAAS,aAAa,GAAG;AAC/B,SAAO;AAAA,IACL,MAAM;AAAA,IACN,GAAG,OAAO;AAAA,IACV,GAAG,OAAO;AAAA,IACV,QAAQ,aAAa,GAAG;AAAA,EAC1B;AACF;AAEA,IAAM,kBAAkB,CAAC,QAAgC;AACvD,MAAI,IAAI,SAAS,eAAe;AAC9B,QAAI,IAAI,UAAU,WAAW;AAC3B,aAAO;AAAA,QACL,MAAM;AAAA,QACN,QAAQ,IAAI;AAAA,MACd;AAAA,IACF;AAEA,QAAI,IAAI,UAAU,QAAQ;AACxB,YAAM,IAAI,MAAM,qCAAqC,IAAI,KAAK,EAAE;AAAA,IAClE;AAEA,WAAO;AAAA,MACL,MAAM;AAAA,MACN,QAAQ;AAAA,QACN;AAAA,UACE,GAAG,IAAI,OAAO,IAAI,IAAI,QAAQ;AAAA,UAC9B,GAAG,IAAI,OAAO,IAAI,IAAI,SAAS;AAAA,QACjC;AAAA,QACA;AAAA,UACE,GAAG,IAAI,OAAO,IAAI,IAAI,QAAQ;AAAA,UAC9B,GAAG,IAAI,OAAO,IAAI,IAAI,SAAS;AAAA,QACjC;AAAA,QACA;AAAA,UACE,GAAG,IAAI,OAAO,IAAI,IAAI,QAAQ;AAAA,UAC9B,GAAG,IAAI,OAAO,IAAI,IAAI,SAAS;AAAA,QACjC;AAAA,QACA;AAAA,UACE,GAAG,IAAI,OAAO,IAAI,IAAI,QAAQ;AAAA,UAC9B,GAAG,IAAI,OAAO,IAAI,IAAI,SAAS;AAAA,QACjC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,MACE,IAAI,SAAS,iBACZ,IAAI,UAAU,aAAa,IAAI,UAAU,iBAC1C;AACA,WAAO;AAAA,MACL,MAAM;AAAA,MACN,QAAQ,uBAAuB,GAAG;AAAA,IACpC;AAAA,EACF;AAEA,MACE,IAAI,SAAS,qBACb,oBAAoB,OACpB,qBAAqB,KACrB;AACA,WAAO;AAAA,MACL,MAAM;AAAA,MACN,QAAQ,uBAAuB,GAAG;AAAA,IACpC;AAAA,EACF;AAEA,QAAM,SAAS,aAAa,GAAG;AAC/B,SAAO;AAAA,IACL,MAAM;AAAA,IACN,QAAQ;AAAA,MACN,EAAE,GAAG,OAAO,MAAM,GAAG,OAAO,KAAK;AAAA,MACjC,EAAE,GAAG,OAAO,MAAM,GAAG,OAAO,KAAK;AAAA,MACjC,EAAE,GAAG,OAAO,MAAM,GAAG,OAAO,KAAK;AAAA,MACjC,EAAE,GAAG,OAAO,MAAM,GAAG,OAAO,KAAK;AAAA,IACnC;AAAA,EACF;AACF;AAEO,IAAM,iBAAiB,CAC5B,MACA,SACG;AACH,MAAI,UAAU,IAAI,KAAK,UAAU,IAAI,GAAG;AACtC,UAAM,QAAQ,wBAAwB,IAAI;AAC1C,UAAM,QAAQ,wBAAwB,IAAI;AAC1C,WACEC;AAAA,MACE,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,IACR,IACA,MAAM,SACN,MAAM;AAAA,EAEV;AAEA,MAAI,UAAU,IAAI,KAAK,cAAc,IAAI,GAAG;AAC1C,UAAMC,QAAO,wBAAwB,IAAI;AACzC,WACE,2BAA2BA,MAAK,OAAOA,MAAK,KAAK,eAAe,IAAI,CAAC,IACrEA,MAAK;AAAA,EAET;AAEA,MAAI,cAAc,IAAI,KAAK,UAAU,IAAI,GAAG;AAC1C,UAAMA,QAAO,wBAAwB,IAAI;AACzC,WACE,2BAA2BA,MAAK,OAAOA,MAAK,KAAK,eAAe,IAAI,CAAC,IACrEA,MAAK;AAAA,EAET;AAEA,MAAI,UAAU,IAAI,GAAG;AACnB,UAAMA,QAAO,wBAAwB,IAAI;AACzC,WACE;AAAA,MACEA,MAAK;AAAA,MACLA,MAAK;AAAA,MACL,gBAAgB,IAAI,EAAE;AAAA,IACxB,EAAE,WAAWA,MAAK;AAAA,EAEtB;AAEA,MAAI,UAAU,IAAI,GAAG;AACnB,UAAMA,QAAO,wBAAwB,IAAI;AACzC,WACE;AAAA,MACEA,MAAK;AAAA,MACLA,MAAK;AAAA,MACL,gBAAgB,IAAI,EAAE;AAAA,IACxB,EAAE,WAAWA,MAAK;AAAA,EAEtB;AAEA,MAAI,cAAc,IAAI,KAAK,cAAc,IAAI,GAAG;AAC9C,WAAO;AAAA,MACL,eAAe,IAAI;AAAA,MACnB,eAAe,IAAI;AAAA,IACrB;AAAA,EACF;AAEA,MAAI,cAAc,IAAI,GAAG;AACvB,WAAO;AAAA,MACL,eAAe,IAAI;AAAA,MACnB,gBAAgB,IAAI;AAAA,IACtB;AAAA,EACF;AAEA,MAAI,cAAc,IAAI,GAAG;AACvB,WAAO;AAAA,MACL,eAAe,IAAI;AAAA,MACnB,gBAAgB,IAAI;AAAA,IACtB;AAAA,EACF;AAEA,SAAO;AAAA,IACL,gBAAgB,IAAI;AAAA,IACpB,gBAAgB,IAAI;AAAA,EACtB;AACF;AAEO,IAAM,UAAU,CAAC,gBACtB;AAAA,EACE,GAAG,IAAI,WAAW,EAAE,WAAW,KAAK;AAAA,EACpC,GAAG,IAAI,WAAW,EAAE,gBAAgB,KAAK;AAC3C;AAEK,IAAM,mBAAmB,CAC9B,gBACsB;AACtB,QAAM,YAAY,IAAI,WAAW,EAAE,UAAU,KAAK;AAElD,SAAO,UAAU,QAAQ,CAAC,aAAa;AACrC,UAAM,WAA8B,CAAC;AAErC,aAAS,IAAI,GAAG,IAAI,SAAS,MAAM,SAAS,GAAG,KAAK;AAClD,YAAM,KAAK,SAAS,MAAM,CAAC;AAC3B,YAAM,KAAK,SAAS,MAAM,IAAI,CAAC;AAC/B,UAAI,GAAG,eAAe,OAAQ;AAC9B,UAAI,GAAG,eAAe,OAAQ;AAC9B,UAAI,GAAG,UAAU,GAAG,MAAO;AAE3B,eAAS,KAAK;AAAA,QACZ,MAAM;AAAA,QACN,cAAc,SAAS;AAAA,QACvB,WAAW;AAAA,QACX,WACE,WAAW,KACP,GAAG,QACH,WAAW,KACT,GAAG,QACH;AAAA,QACR,OAAO,GAAG;AAAA,QACV,IAAI,GAAG;AAAA,QACP,IAAI,GAAG;AAAA,QACP,IAAI,GAAG;AAAA,QACP,IAAI,GAAG;AAAA,MACT,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT,CAAC;AACH;AAUO,IAAM,iBAAiB,CAAC,YAA6B;AAC1D,QAAM,cAAc,QAAQ,UAAU,MAAM,QAAQ,CAAC,eAAe;AAClE,QAAI,WAAW,eAAe,eAAe;AAC3C,aAAO,CAAC,WAAW,OAAO,WAAW,GAAG;AAAA,IAC1C;AAEA,WAAO,CAAC,EAAE,GAAG,WAAW,GAAG,GAAG,WAAW,EAAE,CAAC;AAAA,EAC9C,CAAC;AACD,QAAM,aAAa,YAAY,CAAC;AAChC,QAAM,YAAY,YAAY,YAAY,SAAS,CAAC;AAEpD,MAAI,CAAC,cAAc,CAAC,WAAW;AAC7B,WAAO;AAAA,MACL,EAAE,GAAG,QAAQ,IAAI,GAAG,QAAQ,GAAG;AAAA,MAC/B,EAAE,GAAG,QAAQ,IAAI,GAAG,QAAQ,GAAG;AAAA,IACjC;AAAA,EACF;AAEA,SAAO,SAAS,YAAY,SAAS;AACvC;AAIA,IAAM,8BAA8B,CAAC;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAKM;AACJ,QAAM,KAAK,cAAc,IAAI,WAAW;AACxC,QAAM,KAAK,cAAc,IAAI,WAAW;AACxC,QAAMC,YAAW,KAAK,MAAM,IAAI,EAAE;AAClC,MAAIA,cAAa,EAAG,QAAO,SAAS,YAAY,aAAa;AAE7D,QAAM,QAAQ,KAAKA;AACnB,QAAM,QAAQ,KAAKA;AACnB,QAAM,YAAY;AAAA,IAChB,GAAG,WAAW,IAAI,QAAQ;AAAA,IAC1B,GAAG,WAAW,IAAI,QAAQ;AAAA,EAC5B;AACA,QAAM,eAAe;AAAA,IACnB,GAAG,cAAc,IAAI,QAAQ;AAAA,IAC7B,GAAG,cAAc,IAAI,QAAQ;AAAA,EAC/B;AAEA,SAAO,SAAS,WAAW,YAAY;AACzC;AAEO,IAAM,4BAA4B,CACvC,SACA,aACsD;AACtD,QAAM,QAAQ,EAAE,GAAG,QAAQ,IAAI,GAAG,QAAQ,GAAG;AAC7C,QAAM,MAAM,EAAE,GAAG,QAAQ,IAAI,GAAG,QAAQ,GAAG;AAC3C,QAAM,cAAc,QAAQ,YAAY;AAExC,MAAI,SAAS,SAAS,aAAa,cAAc,QAAQ,GAAG;AAC1D,UAAM,SACJ,SAAS,SAAS,YACd;AAAA,MACE,GAAG,SAAS;AAAA,MACZ,GAAG,SAAS;AAAA,MACZ,QAAQ,SAAS,iBAAiB;AAAA,IACpC,IACA,eAAe,QAAQ;AAC7B,UAAM,eAAeC,4BAA2B,QAAQ,OAAO,GAAG;AAElE,WAAO;AAAA,MACL,KAAK,2BAA2B,OAAO,KAAK,MAAM,IAAI;AAAA,MACtD,QAAQ,4BAA4B;AAAA,QAClC,YAAY;AAAA,QACZ,eAAe;AAAA,QACf;AAAA,QACA,gBAAgB,OAAO;AAAA,MACzB,CAAC;AAAA,IACH;AAAA,EACF;AAEA,MAAI,UAAU,QAAQ,GAAG;AACvB,UAAMC,aAAY,0BAA0B,SAAS,QAAQ;AAC7D,WAAO;AAAA,MACL,KAAKA,WAAU,WAAW,cAAcA,WAAU;AAAA,MAClD,QAAQ,4BAA4B;AAAA,QAClC,YAAYA,WAAU;AAAA,QACtB,eAAeA,WAAU;AAAA,QACzB;AAAA,QACA,gBAAgBA,WAAU;AAAA,MAC5B,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAM,YAAY;AAAA,IAChB;AAAA,IACA;AAAA,IACA,gBAAgB,QAAQ,EAAE;AAAA,EAC5B;AACA,SAAO;AAAA,IACL,KAAK,UAAU,WAAW;AAAA,IAC1B,QAAQ,4BAA4B;AAAA,MAClC,YAAY,UAAU;AAAA,MACtB,eAAe,UAAU;AAAA,MACzB;AAAA,MACA,gBAAgB;AAAA,IAClB,CAAC;AAAA,EACH;AACF;AAEO,IAAM,yBAAyB,CAAC,QAAyB,OAAO;;;AGxZhE,IAAM,qBAAN,MAA4B;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EAEZ,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAKG;AACD,SAAK,UAAU,oBAAI,IAAI;AACvB,SAAK,cAAc,oBAAI,IAAI;AAC3B,SAAK,YAAY;AACjB,SAAK,QAAQ,UAAU,MAAM,KAAK,WAAW;AAC7C,SAAK,YAAY,aAAa,KAAK;AAEnC,eAAW,OAAO,SAAS;AACzB,WAAK,UAAU,GAAG;AAAA,IACpB;AAAA,EACF;AAAA,EAEA,aAAa;AAAA,EACb,aAAqB;AACnB,WAAO,GAAG,KAAK,YAAY;AAAA,EAC7B;AAAA,EAEA,UAAU,KAAc;AACtB,UAAM,SAAS,KAAK,UAAU,GAAG;AACjC,UAAM,iBAAiB,KAAK,MAAM,GAAG;AACrC,UAAM,YAAY,EAAE,GAAG,KAAK,eAAe;AAK3C,SAAK,YAAY,IAAI,gBAAgB,SAAS;AAG9C,UAAM,aAAa,KAAK,MAAM,OAAO,OAAO,KAAK,SAAS;AAC1D,UAAM,aAAa,KAAK,MAAM,OAAO,OAAO,KAAK,SAAS;AAC1D,UAAM,aAAa,KAAK,MAAM,OAAO,OAAO,KAAK,SAAS;AAC1D,UAAM,aAAa,KAAK,MAAM,OAAO,OAAO,KAAK,SAAS;AAG1D,aAAS,KAAK,YAAY,MAAM,YAAY,MAAM;AAChD,eAAS,KAAK,YAAY,MAAM,YAAY,MAAM;AAChD,cAAM,YAAY,GAAG,EAAE,IAAI,EAAE;AAC7B,cAAM,SAAS,KAAK,QAAQ,IAAI,SAAS;AACzC,YAAI,CAAC,QAAQ;AACX,eAAK,QAAQ,IAAI,WAAW,CAAC,SAAS,CAAC;AAAA,QACzC,OAAO;AACL,iBAAO,KAAK,SAAS;AAAA,QACvB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,aAAa,IAAqB;AAChC,UAAM,MAAM,KAAK,YAAY,IAAI,EAAE;AACnC,QAAI,CAAC,IAAK,QAAO;AAGjB,SAAK,YAAY,OAAO,EAAE;AAG1B,UAAM,SAAS,KAAK,UAAU,GAAG;AACjC,UAAM,aAAa,KAAK,MAAM,OAAO,OAAO,KAAK,SAAS;AAC1D,UAAM,aAAa,KAAK,MAAM,OAAO,OAAO,KAAK,SAAS;AAC1D,UAAM,aAAa,KAAK,MAAM,OAAO,OAAO,KAAK,SAAS;AAC1D,UAAM,aAAa,KAAK,MAAM,OAAO,OAAO,KAAK,SAAS;AAG1D,aAAS,KAAK,YAAY,MAAM,YAAY,MAAM;AAChD,eAAS,KAAK,YAAY,MAAM,YAAY,MAAM;AAChD,cAAM,YAAY,GAAG,EAAE,IAAI,EAAE;AAC7B,cAAM,SAAS,KAAK,QAAQ,IAAI,SAAS;AACzC,YAAI,QAAQ;AACV,gBAAM,QAAQ,OAAO,UAAU,CAAC,SAAS,KAAK,mBAAmB,EAAE;AACnE,cAAI,UAAU,IAAI;AAChB,mBAAO,OAAO,OAAO,CAAC;AACtB,gBAAI,OAAO,WAAW,GAAG;AACvB,mBAAK,QAAQ,OAAO,SAAS;AAAA,YAC/B;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,aAAa,GAAW,GAA6B;AACnD,WAAO,GAAG,KAAK,MAAM,IAAI,KAAK,SAAS,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,SAAS,CAAC;AAAA,EAC5E;AAAA,EAEA,mBAAmB,QAAgB,SAAS,GAAQ;AAClD,UAAM,UAAe,CAAC;AACtB,UAAM,WAAW,oBAAI,IAAY;AAGjC,UAAM,aAAa,KAAK,OAAO,OAAO,OAAO,UAAU,KAAK,SAAS;AACrE,UAAM,aAAa,KAAK,OAAO,OAAO,OAAO,UAAU,KAAK,SAAS;AACrE,UAAM,aAAa,KAAK,OAAO,OAAO,OAAO,UAAU,KAAK,SAAS;AACrE,UAAM,aAAa,KAAK,OAAO,OAAO,OAAO,UAAU,KAAK,SAAS;AAGrE,aAAS,KAAK,YAAY,MAAM,YAAY,MAAM;AAChD,eAAS,KAAK,YAAY,MAAM,YAAY,MAAM;AAChD,cAAM,YAAY,GAAG,EAAE,IAAI,EAAE;AAC7B,cAAM,SAAS,KAAK,QAAQ,IAAI,SAAS,KAAK,CAAC;AAE/C,mBAAW,OAAO,QAAQ;AACxB,gBAAM,KAAK,IAAI;AACf,cAAI,SAAS,IAAI,EAAE,EAAG;AAEtB,mBAAS,IAAI,EAAE;AACf,kBAAQ,KAAK,GAAG;AAAA,QAClB;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF;;;AC7IA,SAAS,kBAAkB;AAEpB,SAAS,sBAAsB,KAA2B;AAC/D,MAAI,IAAI,SAAS,qBAAqB;AACpC,WAAO,CAAC,IAAI,KAAK;AAAA,EACnB;AACA,MAAI,IAAI,SAAS,cAAc;AAC7B,WAAO,CAAC,IAAI,KAAK;AAAA,EACnB;AACA,MAAI,IAAI,SAAS,mBAAmB;AAClC,WAAO,MAAM,QAAQ,IAAI,MAAM,IAAI,IAAI,SAAS,CAAC,GAAG,UAAU;AAAA,EAChE;AACA,MAAI,IAAI,SAAS,YAAY;AAC3B,WAAO,CAAC,GAAG,UAAU;AAAA,EACvB;AACA,MAAI,IAAI,SAAS,WAAW;AAC1B,WAAO,MAAM,QAAQ,IAAI,MAAM,IAAI,IAAI,SAAS,CAAC,GAAG,UAAU;AAAA,EAChE;AACA,MAAI,IAAI,SAAS,eAAe;AAC9B,WAAO,MAAM,QAAQ,IAAI,MAAM,IAAI,IAAI,SAAS,CAAC;AAAA,EACnD;AACA,SAAO,CAAC;AACV;;;ACpBO,IAAM,yCAAyC,CACpD,SACA,WAC6B;AAE7B,QAAM,KAAK,EAAE,GAAG,QAAQ,IAAI,GAAG,QAAQ,GAAG;AAC1C,QAAM,KAAK,EAAE,GAAG,QAAQ,IAAI,GAAG,QAAQ,GAAG;AAG1C,QAAM,OAAO,OAAO;AACpB,QAAM,OAAO,OAAO;AACpB,QAAM,OAAO,OAAO;AACpB,QAAM,OAAO,OAAO;AAGpB,MAAI,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,GAAG;AAElC,UAAM,WAAW,KAAK,IAAI,MAAM,KAAK,IAAI,MAAM,GAAG,CAAC,CAAC;AACpD,UAAM,WAAW,KAAK,IAAI,MAAM,KAAK,IAAI,MAAM,GAAG,CAAC,CAAC;AAGpD,QAAI,aAAa,GAAG,KAAK,aAAa,GAAG,GAAG;AAC1C,aAAO,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AAAA,IAC5B;AAGA,WAAO,EAAE,GAAG,UAAU,GAAG,SAAS;AAAA,EACpC;AAGA,QAAM,KAAK,GAAG,IAAI,GAAG;AACrB,QAAM,KAAK,GAAG,IAAI,GAAG;AAGrB,QAAM,QAAQ,OAAO,KAAK,OAAO,GAAG,KAAK,KAAK,OAAO;AACrD,QAAM,QAAQ,OAAO,KAAK,OAAO,GAAG,KAAK,KAAK,OAAO;AACrD,QAAM,QAAQ,OAAO,KAAK,OAAO,GAAG,KAAK,KAAK,OAAO;AACrD,QAAM,QAAQ,OAAO,KAAK,OAAO,GAAG,KAAK,KAAK,OAAO;AAGrD,QAAM,SAAS,KAAK,IAAI,KAAK,IAAI,OAAO,KAAK,GAAG,KAAK,IAAI,OAAO,KAAK,CAAC;AACtE,QAAM,QAAQ,KAAK,IAAI,KAAK,IAAI,OAAO,KAAK,GAAG,KAAK,IAAI,OAAO,KAAK,CAAC;AAGrE,MAAI,UAAU,SAAS,SAAS,KAAK,UAAU,GAAG;AAEhD,UAAM,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,MAAM,CAAC;AACzC,WAAO;AAAA,MACL,GAAG,GAAG,IAAI,IAAI;AAAA,MACd,GAAG,GAAG,IAAI,IAAI;AAAA,IAChB;AAAA,EACF;AAIA,QAAM,cAAc;AAAA,IAClB,GAAG,KAAK,IAAI,MAAM,KAAK,IAAI,MAAM,GAAG,CAAC,CAAC;AAAA,IACtC,GAAG,KAAK,IAAI,MAAM,KAAK,IAAI,MAAM,GAAG,CAAC,CAAC;AAAA,EACxC;AAEA,QAAM,cAAc;AAAA,IAClB,GAAG,KAAK,IAAI,MAAM,KAAK,IAAI,MAAM,GAAG,CAAC,CAAC;AAAA,IACtC,GAAG,KAAK,IAAI,MAAM,KAAK,IAAI,MAAM,GAAG,CAAC,CAAC;AAAA,EACxC;AAGA,QAAM,mBACH,YAAY,IAAI,GAAG,MAAM,KAAK,YAAY,IAAI,GAAG,MAAM;AAC1D,QAAM,mBACH,YAAY,IAAI,GAAG,MAAM,KAAK,YAAY,IAAI,GAAG,MAAM;AAG1D,QAAM,QAAQ;AAAA,IACZ,EAAE,OAAO,EAAE,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,EAAE,GAAG,MAAM,GAAG,KAAK,EAAE;AAAA;AAAA,IACzD,EAAE,OAAO,EAAE,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,EAAE,GAAG,MAAM,GAAG,KAAK,EAAE;AAAA;AAAA,IACzD,EAAE,OAAO,EAAE,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,EAAE,GAAG,MAAM,GAAG,KAAK,EAAE;AAAA;AAAA,IACzD,EAAE,OAAO,EAAE,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,EAAE,GAAG,MAAM,GAAG,KAAK,EAAE;AAAA;AAAA,EAC3D;AAEA,MAAI,cAAc,KAAK,IAAI,iBAAiB,eAAe;AAC3D,MAAI,eACF,mBAAmB,kBAAkB,cAAc;AAGrD,QAAMC,SAAQ,CAAC,OAAe,KAAa,QAAwB;AACjE,WAAO,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,KAAK,CAAC;AAAA,EAC3C;AAGA,aAAW,QAAQ,OAAO;AAExB,UAAM,KAAK,EAAE,GAAG,GAAG,IAAI,GAAG,GAAG,GAAG,GAAG,IAAI,GAAG,EAAE;AAC5C,UAAM,KAAK,EAAE,GAAG,KAAK,IAAI,IAAI,KAAK,MAAM,GAAG,GAAG,KAAK,IAAI,IAAI,KAAK,MAAM,EAAE;AACxE,UAAM,IAAI,EAAE,GAAG,GAAG,IAAI,KAAK,MAAM,GAAG,GAAG,GAAG,IAAI,KAAK,MAAM,EAAE;AAG3D,UAAM,QAAQ,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG;AACtC,UAAM,QAAQ,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG;AACtC,UAAM,QAAQ,GAAG,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE;AACpC,UAAM,QAAQ,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG;AACtC,UAAM,QAAQ,GAAG,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE;AAGpC,UAAM,cAAc,QAAQ,QAAQ,QAAQ;AAG5C,QAAI,KAAK,IAAI,WAAW,IAAI,MAAO;AAEnC,QAAI,MAAM,QAAQ,QAAQ,QAAQ,SAAS;AAC3C,QAAI,MAAM,QAAQ,QAAQ,QAAQ,SAAS;AAG3C,SAAKA,OAAM,IAAI,GAAG,CAAC;AACnB,SAAKA,OAAM,IAAI,GAAG,CAAC;AAGnB,UAAM,mBAAmB;AAAA,MACvB,GAAG,GAAG,IAAI,KAAK,GAAG;AAAA,MAClB,GAAG,GAAG,IAAI,KAAK,GAAG;AAAA,IACpB;AAEA,UAAM,gBAAgB;AAAA,MACpB,GAAG,KAAK,MAAM,IAAI,KAAK,GAAG;AAAA,MAC1B,GAAG,KAAK,MAAM,IAAI,KAAK,GAAG;AAAA,IAC5B;AAGA,UAAMC,MAAK,iBAAiB,IAAI,cAAc;AAC9C,UAAMC,MAAK,iBAAiB,IAAI,cAAc;AAC9C,UAAM,cAAcD,MAAKA,MAAKC,MAAKA;AAGnC,QAAI,cAAc,aAAa;AAC7B,oBAAc;AACd,qBAAe;AAAA,QACb,IAAI,iBAAiB,IAAI,cAAc,KAAK;AAAA,QAC5C,IAAI,iBAAiB,IAAI,cAAc,KAAK;AAAA,MAC9C;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;AC/IO,IAAM,iCAAiC,CAC5C,UACA,aAC6B;AAE7B,QAAM,KAAK,EAAE,GAAG,SAAS,IAAI,GAAG,SAAS,GAAG;AAC5C,QAAM,KAAK,EAAE,GAAG,SAAS,IAAI,GAAG,SAAS,GAAG;AAC5C,QAAM,KAAK,EAAE,GAAG,SAAS,IAAI,GAAG,SAAS,GAAG;AAC5C,QAAM,KAAK,EAAE,GAAG,SAAS,IAAI,GAAG,SAAS,GAAG;AAG5C,QAAM,KAAK,EAAE,GAAG,GAAG,IAAI,GAAG,GAAG,GAAG,GAAG,IAAI,GAAG,EAAE;AAC5C,QAAM,KAAK,EAAE,GAAG,GAAG,IAAI,GAAG,GAAG,GAAG,GAAG,IAAI,GAAG,EAAE;AAG5C,QAAM,UAAU,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG;AACxC,QAAM,UAAU,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG;AAGxC,MAAI,YAAY,KAAK,YAAY,GAAG;AAClC,QAAI,YAAY,KAAK,YAAY,GAAG;AAGlC,aAAO;AAAA,QACL,IAAI,GAAG,IAAI,GAAG,KAAK;AAAA,QACnB,IAAI,GAAG,IAAI,GAAG,KAAK;AAAA,MACrB;AAAA,IACF;AACA,QAAI,YAAY,GAAG;AAEjB,YAAMC,KAAI;AAAA,UACN,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK;AAAA,QAChD;AAAA,QACA;AAAA,MACF;AACA,YAAMC,cAAa;AAAA,QACjB,GAAG,GAAG,IAAID,KAAI,GAAG;AAAA,QACjB,GAAG,GAAG,IAAIA,KAAI,GAAG;AAAA,MACnB;AAEA,aAAO;AAAA,QACL,IAAI,GAAG,IAAIC,YAAW,KAAK;AAAA,QAC3B,IAAI,GAAG,IAAIA,YAAW,KAAK;AAAA,MAC7B;AAAA,IACF;AAEA,UAAM,IAAI;AAAA,QACN,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK;AAAA,MAChD;AAAA,MACA;AAAA,IACF;AACA,UAAMC,cAAa;AAAA,MACjB,GAAG,GAAG,IAAI,IAAI,GAAG;AAAA,MACjB,GAAG,GAAG,IAAI,IAAI,GAAG;AAAA,IACnB;AAEA,WAAO;AAAA,MACL,IAAIA,YAAW,IAAI,GAAG,KAAK;AAAA,MAC3B,IAAIA,YAAW,IAAI,GAAG,KAAK;AAAA,IAC7B;AAAA,EACF;AAGA,QAAM,IAAI,EAAE,GAAG,GAAG,IAAI,GAAG,GAAG,GAAG,GAAG,IAAI,GAAG,EAAE;AAG3C,QAAM,QAAQ,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG;AACtC,QAAM,QAAQ,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG;AACtC,QAAM,QAAQ,GAAG,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE;AACpC,QAAM,QAAQ,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG;AACtC,QAAM,QAAQ,GAAG,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE;AAGpC,QAAM,cAAc,QAAQ,QAAQ,QAAQ;AAG5C,MAAI,cAAc,OAAO;AACvB,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAGA,MAAI,MAAM,QAAQ,QAAQ,QAAQ,SAAS;AAC3C,MAAI,MAAM,QAAQ,QAAQ,QAAQ,SAAS;AAG3C,OAAK,MAAM,IAAI,GAAG,CAAC;AACnB,OAAK,MAAM,IAAI,GAAG,CAAC;AAGnB,QAAM,KAAK,QAAQ,SAAS;AAC5B,OAAK,MAAM,IAAI,GAAG,CAAC;AAGnB,QAAM,KAAK,QAAQ,SAAS;AAC5B,OAAK,MAAM,IAAI,GAAG,CAAC;AAGnB,QAAM,aAAa;AAAA,IACjB,GAAG,GAAG,IAAI,KAAK,GAAG;AAAA,IAClB,GAAG,GAAG,IAAI,KAAK,GAAG;AAAA,EACpB;AAEA,QAAM,aAAa;AAAA,IACjB,GAAG,GAAG,IAAI,KAAK,GAAG;AAAA,IAClB,GAAG,GAAG,IAAI,KAAK,GAAG;AAAA,EACpB;AAGA,QAAM,KAAK,WAAW,IAAI,WAAW;AACrC,QAAM,KAAK,WAAW,IAAI,WAAW;AACrC,QAAMC,YAAW,KAAK,KAAK,KAAK,KAAK,KAAK,EAAE;AAG5C,QAAM,eAAe;AAAA,IACnB,IAAI,WAAW,IAAI,WAAW,KAAK;AAAA,IACnC,IAAI,WAAW,IAAI,WAAW,KAAK;AAAA,EACrC;AAEA,SAAO;AACT;AAGA,IAAM,gCAAgC,CACpC,IACA,IACA,IACA,IACA,IACA,IACA,SACA,YACG;AAEH,MAAI,OAAO,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK;AACzD,OAAK,MAAM,IAAI,GAAG,CAAC;AACnB,QAAM,YAAY,EAAE,GAAG,GAAG,IAAI,KAAK,GAAG,GAAG,GAAG,GAAG,IAAI,KAAK,GAAG,EAAE;AAG7D,MAAI,QAAQ,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK;AAC1D,QAAM,MAAM,KAAK,GAAG,CAAC;AACrB,QAAM,YAAY,EAAE,GAAG,GAAG,IAAI,MAAM,GAAG,GAAG,GAAG,GAAG,IAAI,MAAM,GAAG,EAAE;AAG/D,MAAI,OAAO,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK;AACzD,OAAK,MAAM,IAAI,GAAG,CAAC;AACnB,QAAM,YAAY,EAAE,GAAG,GAAG,IAAI,KAAK,GAAG,GAAG,GAAG,GAAG,IAAI,KAAK,GAAG,EAAE;AAG7D,MAAI,QAAQ,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK;AAC1D,QAAM,MAAM,KAAK,GAAG,CAAC;AACrB,QAAM,YAAY,EAAE,GAAG,GAAG,IAAI,MAAM,GAAG,GAAG,GAAG,GAAG,IAAI,MAAM,GAAG,EAAE;AAG/D,QAAM,YAAY;AAAA,IAChB;AAAA,MACE,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,UAAU,KAAK;AAAA,SACZ,UAAU,IAAI,GAAG,MAAM,KAAK,UAAU,IAAI,GAAG,MAAM;AAAA,MACtD;AAAA,IACF;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,UAAU,KAAK;AAAA,SACZ,UAAU,IAAI,GAAG,MAAM,KAAK,UAAU,IAAI,GAAG,MAAM;AAAA,MACtD;AAAA,IACF;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,UAAU,KAAK;AAAA,SACZ,GAAG,IAAI,UAAU,MAAM,KAAK,GAAG,IAAI,UAAU,MAAM;AAAA,MACtD;AAAA,IACF;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,UAAU,KAAK;AAAA,SACZ,GAAG,IAAI,UAAU,MAAM,KAAK,GAAG,IAAI,UAAU,MAAM;AAAA,MACtD;AAAA,IACF;AAAA,EACF;AAGA,QAAM,cAAc,UAAU;AAAA,IAAO,CAAC,SAAS,YAC7C,QAAQ,WAAW,QAAQ,WAAW,UAAU;AAAA,EAClD;AAGA,SAAO;AAAA,IACL,IAAI,YAAY,OAAO,IAAI,YAAY,OAAO,KAAK;AAAA,IACnD,IAAI,YAAY,OAAO,IAAI,YAAY,OAAO,KAAK;AAAA,EACrD;AACF;AAGA,IAAM,QAAQ,CAAC,OAAe,KAAa,QAAwB;AACjE,SAAO,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,KAAK,CAAC;AAC3C;;;AClNA,SAAS,0BAAAC,+BAA8B;AA2ChC,IAAM,sBAAsB,CAAC,eAAmC;AACrE,MAAI,WAAW,SAAS,qBAAqB;AAC3C,WAAO;AAAA,MACL,MAAM,KAAK,IAAI,WAAW,IAAI,WAAW,EAAE;AAAA,MAC3C,MAAM,KAAK,IAAI,WAAW,IAAI,WAAW,EAAE;AAAA,MAC3C,MAAM,KAAK,IAAI,WAAW,IAAI,WAAW,EAAE;AAAA,MAC3C,MAAM,KAAK,IAAI,WAAW,IAAI,WAAW,EAAE;AAAA,IAC7C;AAAA,EACF;AAEA,MACE,WAAW,SAAS,gBACpB,WAAW,SAAS,mBACpB;AACA,UAAM,YACH,WAAW,SAAS,iBAClB,WAAW,UAAU,kBACpB,WAAW,UAAU,cACxB,WAAW,SAAS,qBACnB,oBAAoB,cACpB,qBAAqB;AAEzB,QAAI,WAAW;AACb,YAAM,gBAAgB,uBAAuB,UAAU;AACvD,aAAO;AAAA,QACL,MAAM,KAAK,IAAI,GAAG,cAAc,IAAI,CAAC,UAAU,MAAM,CAAC,CAAC;AAAA,QACvD,MAAM,KAAK,IAAI,GAAG,cAAc,IAAI,CAAC,UAAU,MAAM,CAAC,CAAC;AAAA,QACvD,MAAM,KAAK,IAAI,GAAG,cAAc,IAAI,CAAC,UAAU,MAAM,CAAC,CAAC;AAAA,QACvD,MAAM,KAAK,IAAI,GAAG,cAAc,IAAI,CAAC,UAAU,MAAM,CAAC,CAAC;AAAA,MACzD;AAAA,IACF;AAEA,QACE,WAAW,SAAS,gBACpB,WAAW,UAAU,gBACrB;AACA,YAAMC,QAAO,wBAAwB,UAAU;AAC/C,aAAO;AAAA,QACL,MAAM,KAAK,IAAIA,MAAK,MAAM,GAAGA,MAAK,IAAI,CAAC,IAAIA,MAAK;AAAA,QAChD,MAAM,KAAK,IAAIA,MAAK,MAAM,GAAGA,MAAK,IAAI,CAAC,IAAIA,MAAK;AAAA,QAChD,MAAM,KAAK,IAAIA,MAAK,MAAM,GAAGA,MAAK,IAAI,CAAC,IAAIA,MAAK;AAAA,QAChD,MAAM,KAAK,IAAIA,MAAK,MAAM,GAAGA,MAAK,IAAI,CAAC,IAAIA,MAAK;AAAA,MAClD;AAAA,IACF;AAAA,EACF;AAEA,SAAOC,wBAAuB,CAAC,UAAiB,CAAC;AACnD;;;ACxFO,SAAS,mCACd,YACA;AACA,MAAI,WAAW,eAAe,OAAQ,QAAO,CAAC;AAE9C,SAAO,CAAC,WAAW,mBAAmB,WAAW,eAAe,EAAE;AAAA,IAChE,CAAC,WAA6B,QAAQ,MAAM;AAAA,EAC9C;AACF;AAEO,SAAS,8BAA8B,OAAiB;AAC7D,QAAM,oBAAoB,oBAAI,IAAY;AAC1C,aAAW,WAAW,MAAM,OAAO;AACjC,eAAW,UAAU,mCAAmC,OAAO,GAAG;AAChE,wBAAkB,IAAI,MAAM;AAAA,IAC9B;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,iBAAiB;AACrC;AAEO,SAAS,+BAA+B,QAAoB;AACjE,QAAM,iBAAiB,oBAAI,IAAY;AACvC,aAAW,SAAS,QAAQ;AAC1B,eAAW,UAAU,8BAA8B,KAAK,GAAG;AACzD,qBAAe,IAAI,MAAM;AAAA,IAC3B;AAAA,EACF;AACA,SAAO,MAAM,KAAK,cAAc;AAClC;;;ACvBO,IAAM,gCAAgC,CAC3C,QACG;AACH,MAAI,IAAI,SAAS,WAAW;AAC1B,WAAO,IAAI,iBAAiB;AAAA,EAC9B;AACA,MAAI,IAAI,SAAS,qBAAqB,IAAI,UAAU,UAAU;AAC5D,WAAO,IAAI,iBAAiB;AAAA,EAC9B;AACA,MAAI,IAAI,SAAS,cAAc,IAAI,eAAe,UAAU;AAC1D,WAAO,IAAI,gBAAgB;AAAA,EAC7B;AACA,MAAI,IAAI,SAAS,gBAAgB,IAAI,UAAU,UAAU;AACvD,WAAO,IAAI;AAAA,EACb;AACA,QAAM,IAAI;AAAA,IACR,0CAA0C,KAAK,UAAU,GAAG,CAAC;AAAA,EAC/D;AACF;;;AVqBA,IAAM,qCAAqC,CACzC,YACW;AACX,MAAI,QAAQ,SAAS,WAAY,QAAO,QAAQ;AAChD,MAAI,QAAQ,SAAS,aAAc,QAAO,QAAQ;AAClD,SAAO,QAAQ;AACjB;AAEO,SAAS,gCACd,aACA;AAAA,EACE;AAAA,EACA;AACF,IAGI,CAAC,GACY;AACjB,QAAM,SAA0B,CAAC;AACjC,iCAA+B,WAAW;AAC1C,cAAYC,uCAAsC,WAAW;AAC7D,QAAM,QAAQ,YAAY,WAAW;AACrC,mBACE,iBAAiB,OAAO,iCAAiC,KACzD;AAEF,QAAM,YAAYC,KAAI,WAAW,EAAE,UAAU,KAAK;AAClD,QAAM,mBAAmB,UAAU,QAAQ,CAAC,aAAa;AACvD,UAAM,WAA8B,CAAC;AACrC,aAAS,IAAI,GAAG,IAAI,SAAS,MAAM,SAAS,GAAG,KAAK;AAClD,YAAM,KAAK,SAAS,MAAM,CAAC;AAC3B,YAAM,KAAK,SAAS,MAAM,IAAI,CAAC;AAC/B,UAAI,GAAG,eAAe,OAAQ;AAC9B,UAAI,GAAG,eAAe,OAAQ;AAC9B,UAAI,GAAG,UAAU,GAAG,MAAO;AAC3B,eAAS,KAAK;AAAA,QACZ,MAAM;AAAA,QACN,cAAc,SAAS;AAAA,QACvB,WAAW;AAAA,QACX,WACE,WAAW,KACP,GAAG,QACH,WAAW,KACT,GAAG,QACH;AAAA,QACR,OAAO,GAAG;AAAA,QACV,IAAI,GAAG;AAAA,QACP,IAAI,GAAG;AAAA,QACP,IAAI,GAAG;AAAA,QACP,IAAI,GAAG;AAAA,MACT,CAAoB;AAAA,IACtB;AACA,WAAO;AAAA,EACT,CAAC;AACD,QAAM,aAAaA,KAAI,WAAW,EAAE,WAAW,KAAK;AACpD,QAAM,iBAAiBA,KAAI,WAAW,EAAE,gBAAgB,KAAK;AAC7D,QAAM,WAAWA,KAAI,WAAW,EAAE,SAAS,KAAK;AAChD,QAAM,WAAWA,KAAI,WAAW,EAAE,SAAS,KAAK;AAChD,QAAM,UAAUA,KAAI,WAAW,EAAE,QAAQ,KAAK;AAC9C,QAAM,cAAcA,KAAI,WAAW,EAAE,YAAY,KAAK;AAEtD,QAAM,iCAAkE;AAAA,IACtE,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAG;AAAA,EACL;AACA,QAAM,mCAAmC,oBAAI,IAAsB;AACnE,aAAW,WAAW,aAAa;AACjC,UAAM,0BAA0B,IAAI;AAAA,MAClC,QAAQ,8BAA8B,CAAC;AAAA,IACzC;AACA,QAAI,wBAAwB,SAAS,EAAG;AAExC,qCAAiC;AAAA,MAC/B,QAAQ;AAAA,MACR,+BACG;AAAA,QACC,CAAC,YACC,QAAQ,oBACR,wBAAwB,IAAI,QAAQ,gBAAgB;AAAA,MACxD,EACC,IAAI,kCAAkC;AAAA,IAC3C;AAAA,EACF;AAEA,QAAM,aAA2B;AAAA,IAC/B,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAG;AAAA,EACL;AAEA,QAAM,eAAe,IAAI,mBAA+B;AAAA,IACtD,SAAS;AAAA,IACT,WAAW;AAAA,EACb,CAAC;AAED,QAAM,kBAAkB,CAAC,OACvBC,2BAA0B,aAAa,EAAE;AAE3C,QAAM,wBAAwB,CAC5B,WACA,WACA,QACG;AACH,QAAI,uBAAuB,GAAG,GAAG;AAC/B,aAAO,aAAa,SAAS,kBAAkB,SAAS;AAAA,IAC1D;AAEA,WAAO,aAAa,SAAS,oBAAoB,SAAS,UAAU,IAAI,QAAQ,CAAC,CAAC;AAAA,EACpF;AAEA,QAAM,WAAW,oBAAI,IAAY;AAGjC,aAAW,YAAY,kBAAkB;AACvC,UAAM,iBAAiB;AACvB,UAAM,SAAS,oBAAoB,QAAQ;AAC3C,UAAM,gBAAgB,aAAa;AAAA,MACjC;AAAA,MACA,iBAAiB,SAAS,YAAY;AAAA,IACxC;AACA,QAAI,SAAS,OAAO,SAAS,MAAM,SAAS,OAAO,SAAS,GAAI;AAEhE,eAAW,OAAO,eAAe;AAE/B,UAAI,CAAC,sBAAsB,GAAG,EAAE,SAAS,SAAS,KAAK,GAAG;AACxD;AAAA,MACF;AACA,UACE,IAAI,SAAS,kBACZ,iCAAiC,IAAI,IAAI,cAAc,KAAK,CAAC,GAAG;AAAA,QAC/D,CAAC,iBACC,QAAQ,gBAAgB,SAAS,cAAc,YAAY;AAAA,MAC/D,GACA;AACA;AAAA,MACF;AACA,UAAI,IAAI,SAAS,qBAAqB;AACpC,cAAM,WAAW;AAEjB,YAAI,SAAS,UAAU,SAAS,MAAO;AAGvC,YACE,QAAQ,gBAAgB,SAAS,cAAc,SAAS,YAAY;AAEpE;AAEF,cAAMC,OACJC;AAAA,UACE,EAAE,GAAG,SAAS,IAAI,GAAG,SAAS,GAAG;AAAA,UACjC,EAAE,GAAG,SAAS,IAAI,GAAG,SAAS,GAAG;AAAA,UACjC,EAAE,GAAG,SAAS,IAAI,GAAG,SAAS,GAAG;AAAA,UACjC,EAAE,GAAG,SAAS,IAAI,GAAG,SAAS,GAAG;AAAA,QACnC,IACA,SAAS,YAAY,IACrB,SAAS,YAAY;AACvB,YAAID,OAAM,eAAe,QAAS;AAElC,cAAM,qBAAqB,WAAW,SAAS,YAAY,IAAI,SAAS,YAAY;AACpF,cAAM,6BAA6B,WAAW,SAAS,YAAY,IAAI,SAAS,YAAY;AAC5F,YAAI,SAAS,IAAI,kBAAkB,EAAG;AACtC,YAAI,SAAS,IAAI,0BAA0B,EAAG;AAE9C,iBAAS,IAAI,kBAAkB;AAC/B,eAAO,KAAK;AAAA,UACV,MAAM;AAAA,UACN,YAAY;AAAA,UACZ,SAAS;AAAA,YACP,gBAAgB,SAAS,YAAY;AAAA,YACrC,gBAAgB,SAAS,YAAY;AAAA,YACrCA;AAAA,UACF;AAAA,UACA,cAAc,SAAS;AAAA,UACvB,iBAAiB;AAAA,UACjB;AAAA,UACA,mBAAmB,CAAC;AAAA,UACpB,QAAQ,+BAA+B,UAAU,QAAQ;AAAA,UACzD,cAAc,+BAA+B;AAAA,YAC3C,SAAS;AAAA,YACT,SAAS;AAAA,UACX,CAAC;AAAA,QACH,CAAC;AACD;AAAA,MACF;AAEA,YAAM,eAAe,aAAa,GAAU;AAC5C,UACE,QAAQ;AAAA,QACN,SAAS;AAAA,QACT,kBAAkB,MAAO,IAAI,eAA0B;AAAA,MACzD;AAEA;AAEF,UACE,IAAI,SAAS,gBACb,IAAI,SAAS,qBACb,IAAI,SAAS,WACb;AACA,cAAM,EAAE,KAAAA,MAAK,OAAO,IAAI,0BAA0B,UAAU,GAAG;AAC/D,YAAI,CAAC,uBAAuBA,IAAG,EAAG;AAElC,cAAM,qBAAqB,WAAW,SAAS,YAAY,IAAI,YAAY;AAC3E,YAAI,SAAS,IAAI,kBAAkB,EAAG;AACtC,iBAAS,IAAI,kBAAkB;AAC/B,eAAO,KAAK;AAAA,UACV,MAAM;AAAA,UACN,YAAY;AAAA,UACZ,SAAS;AAAA,YACP,gBAAgB,SAAS,YAAY;AAAA,YACrC,GAAG,IAAI,IAAI,KAAK,gBAAgB,YAAY,CAAC;AAAA,YAC7CA;AAAA,UACF;AAAA,UACA,cAAc,SAAS;AAAA,UACvB;AAAA,UACA,iBAAiB;AAAA,UACjB;AAAA,UACA,mBAAmB;AAAA,YACjB,sBAAsB,MACjB,IAAI,mBACL;AAAA,UACN,EAAE,OAAO,OAAO;AAAA,UAChB,cAAc;AAAA,YACZ,GAAG,+BAA+B,CAAC,SAAS,SAAS,CAAC;AAAA,YACtD,iBAAiB,MAAM,IAAI,cAAc;AAAA,UAC3C,EAAE,OAAO,OAAO;AAAA,QAClB,CAAC;AACD;AAAA,MACF;AAEA,YAAM,aAAa,IAAI,SAAS;AAEhC,UAAI,YAAY;AACd,cAAM,SAAS,8BAA8B,GAAG;AAChD,cAAME,YAAWC;AAAA,UACf,EAAE,GAAG,SAAS,IAAI,GAAG,SAAS,GAAG;AAAA,UACjC,EAAE,GAAG,SAAS,IAAI,GAAG,SAAS,GAAG;AAAA,UACjC,EAAE,GAAG,IAAI,GAAG,GAAG,IAAI,GAAG,OAAO;AAAA,QAC/B;AACA,cAAMH,OAAME,YAAW,SAAS,YAAY;AAC5C,YAAIF,OAAM,eAAe,QAAS;AAElC,cAAM,qBAAqB,WAAW,SAAS,YAAY,IAAI,YAAY;AAC3E,YAAI,SAAS,IAAI,kBAAkB,EAAG;AACtC,iBAAS,IAAI,kBAAkB;AAC/B,eAAO,KAAK;AAAA,UACV,MAAM;AAAA,UACN,YAAY;AAAA,UACZ,SAAS;AAAA,YACP,gBAAgB,SAAS,YAAY;AAAA,YACrC,GAAG,IAAI,IAAI,KAAK,gBAAgB,aAAa,GAAG,CAAC,CAAC;AAAA,YAClDA;AAAA,UACF;AAAA,UACA,cAAc,SAAS;AAAA,UACvB,QAAQ;AAAA,YACN;AAAA,YACA,oBAAoB,GAAG;AAAA,UACzB;AAAA,UACA,iBAAiB;AAAA,UACjB;AAAA,UACA,mBAAmB;AAAA,YACjB,sBAAsB,MACjB,IAAI,mBACL;AAAA,UACN,EAAE,OAAO,OAAO;AAAA,UAChB,cAAc;AAAA,YACZ,GAAG,+BAA+B,CAAC,SAAS,SAAS,CAAC;AAAA,YACtD,iBAAiB,MAAM,IAAI,cAAc;AAAA,UAC3C,EAAE,OAAO,OAAO;AAAA,QAClB,CAAC;AAAA,MACH;AAIA,YAAM,MACJ;AAAA,QACE,EAAE,GAAG,SAAS,IAAI,GAAG,SAAS,GAAG;AAAA,QACjC,EAAE,GAAG,SAAS,IAAI,GAAG,SAAS,GAAG;AAAA,QACjC,oBAAoB,GAAG;AAAA,MACzB,IACA,SAAS,YAAY;AACvB,UAAI,MAAM,UAAU,gBAAgB;AAClC,cAAM,qBAAqB,WAAW,SAAS,YAAY,IAAI,YAAY;AAC3E,YAAI,SAAS,IAAI,kBAAkB,EAAG;AACtC,iBAAS,IAAI,kBAAkB;AAC/B,eAAO,KAAK;AAAA,UACV,MAAM;AAAA,UACN,YAAY;AAAA,UACZ,SAAS;AAAA,YACP,gBAAgB,SAAS,YAAY;AAAA,YACrC,GAAG,IAAI,IAAI,KAAK,gBAAgB,aAAa,GAAG,CAAC,CAAC;AAAA,YAClD;AAAA,UACF;AAAA,UACA,cAAc,SAAS;AAAA,UACvB,iBAAiB;AAAA,UACjB;AAAA,UACA,mBAAmB;AAAA,YACjB,sBAAsB,MAAM,IAAI,mBAAmB;AAAA,UACrD,EAAE,OAAO,OAAO;AAAA,UAChB,QAAQ;AAAA,YACN;AAAA,YACA,oBAAoB,GAAG;AAAA,UACzB;AAAA,UACA,cAAc;AAAA,YACZ,GAAG,+BAA+B,CAAC,SAAS,SAAS,CAAC;AAAA,YACtD,iBAAiB,MAAM,IAAI,cAAc;AAAA,UAC3C,EAAE,OAAO,OAAO;AAAA,QAClB,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;;;AW3WO,IAAM,aAAN,MAAiB;AAAA,EACd,WAA6B,oBAAI,IAAI;AAAA,EAE7C,aAAa,OAAuB;AAClC,QAAI,MAAM,SAAS,EAAG;AAEtB,QAAI,gBAAoC;AAGxC,eAAW,WAAW,KAAK,UAAU;AACnC,iBAAW,QAAQ,OAAO;AACxB,YAAI,QAAQ,IAAI,IAAI,GAAG;AACrB,cAAI,kBAAkB,MAAM;AAC1B,4BAAgB;AAAA,UAClB,WAAW,kBAAkB,SAAS;AAEpC,uBAAW,aAAa,SAAS;AAC/B,4BAAc,IAAI,SAAS;AAAA,YAC7B;AACA,iBAAK,SAAS,OAAO,OAAO;AAAA,UAC9B;AACA;AAAA,QACF;AAAA,MACF;AACA,UAAI,kBAAkB,QAAQ,kBAAkB,QAAS;AAAA,IAC3D;AAGA,QAAI,kBAAkB,MAAM;AAC1B,sBAAgB,IAAI,IAAI,KAAK;AAC7B,WAAK,SAAS,IAAI,aAAa;AAAA,IACjC,OAAO;AAEL,iBAAW,QAAQ,OAAO;AACxB,sBAAc,IAAI,IAAI;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AAAA,EAEA,YAAY,OAA0B;AACpC,QAAI,MAAM,SAAS,EAAG,QAAO;AAE7B,eAAW,WAAW,KAAK,UAAU;AACnC,UAAI,MAAM,MAAM,CAAC,SAAS,QAAQ,IAAI,IAAI,CAAC,GAAG;AAC5C,eAAO;AAAA,MACT;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF;;;AClDA,SAAS,6BAAAI,kCAAiC;;;ACA1C,YAAY,aAAa;AAazB,SAAS,cAAc,iBAAiB;AAOxC,IAAM,mBAAmB,CAAC,OAA+B;AAOzD,IAAM,mBAAmB;AAEzB,IAAM,kBAAkB,CACtB,WAC2B;AAC3B,MAAI,OAAO,SAAS,EAAG,QAAO;AAC9B,SAAO,IAAY,gBAAQ,OAAO,IAAI,CAAC,EAAE,GAAG,EAAE,MAAM,IAAY,cAAM,GAAG,CAAC,CAAC,CAAC;AAC9E;AAEA,IAAM,oBAAoB,CACxB,aAC2B;AAC3B,QAAM,OAAO,SAAS,OAAO,CAAC,QAAQ,UAAU;AAC9C,UAAM,WAAW,SAAS,QAAQ,CAAC;AACnC,WACE,CAAC,YACD,KAAK,IAAI,SAAS,IAAI,OAAO,CAAC,IAAI,oBAClC,KAAK,IAAI,SAAS,IAAI,OAAO,CAAC,IAAI;AAAA,EAEtC,CAAC;AACD,MACE,KAAK,SAAS,KACd,KAAK,IAAI,KAAK,CAAC,EAAE,IAAI,KAAK,GAAG,EAAE,EAAG,CAAC,KAAK,oBACxC,KAAK,IAAI,KAAK,CAAC,EAAE,IAAI,KAAK,GAAG,EAAE,EAAG,CAAC,KAAK,kBACxC;AACA,SAAK,IAAI;AAAA,EACX;AACA,MAAI,KAAK,SAAS,EAAG,QAAO;AAE5B,QAAM,QAA8C,CAAC;AACrD,WAAS,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS;AAChD,UAAM,QAAQ,KAAK,KAAK;AACxB,UAAM,MAAM,MAAM,QAAQ,KAAK,KAAK,MAAM;AAC1C,UAAM,aAAa,IAAY,cAAM,MAAM,GAAG,MAAM,CAAC;AACrD,UAAM,WAAW,IAAY,cAAM,IAAI,GAAG,IAAI,CAAC;AAC/C,UAAM,QAAQ,MAAM,SAAS;AAC7B,QAAI,KAAK,IAAI,KAAK,KAAK,kBAAkB;AACvC,YAAM,KAAK,IAAY,gBAAQ,YAAY,QAAQ,CAAC;AACpD;AAAA,IACF;AAEA,UAAM,cAAc,WAAW,WAAW,QAAQ,EAAE,CAAC;AACrD,QAAI,eAAe,iBAAkB;AACrC,UAAMC,YAAW;AAAA,MACf,IAAI,MAAM,IAAI,IAAI,KAAK;AAAA,MACvB,IAAI,MAAM,IAAI,IAAI,KAAK;AAAA,IACzB;AACA,UAAM,aAAa;AAAA,MACjB,GAAG,EAAE,IAAI,IAAI,MAAM,KAAK;AAAA,MACxB,IAAI,IAAI,IAAI,MAAM,KAAK;AAAA,IACzB;AACA,UAAM,eAAgB,eAAe,IAAI,QAAQ,UAAW,IAAI;AAChE,UAAM,SAAS,IAAY;AAAA,MACzBA,UAAS,IAAI,WAAW,IAAI;AAAA,MAC5BA,UAAS,IAAI,WAAW,IAAI;AAAA,IAC9B;AACA,UAAM,SAAU,eAAe,IAAI,QAAQ,UAAW,IAAI,KAAK,IAAI,KAAK;AACxE,UAAM;AAAA,MACJ,IAAY;AAAA,QACV;AAAA,QACA;AAAA,QACA,KAAK,MAAM,MAAM,IAAI,OAAO,GAAG,MAAM,IAAI,OAAO,CAAC;AAAA,QACjD,KAAK,MAAM,IAAI,IAAI,OAAO,GAAG,IAAI,IAAI,OAAO,CAAC;AAAA,QAC7C,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAEA,MAAI,MAAM,SAAS,EAAG,QAAO;AAC7B,QAAM,UAAU,IAAY,gBAAQ;AACpC,UAAQ,QAAQ,KAAK;AACrB,SAAO;AACT;AAEA,IAAM,iBAAiB,CAAC,UAA4C;AAClE,MAAI,MAAM,WAAW,MAAM,QAAQ,UAAU,GAAG;AAC9C,WAAO,gBAAgB,MAAM,OAAO;AAAA,EACtC;AAEA,MACE,CAAC,MAAM,UACP,OAAO,MAAM,UAAU,YACvB,OAAO,MAAM,WAAW,UACxB;AACA,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,MAAM,QAAQ;AAChC,QAAM,aAAa,MAAM,SAAS;AAClC,SAAO,gBAAgB;AAAA,IACrB,EAAE,GAAG,MAAM,OAAO,IAAI,WAAW,GAAG,MAAM,OAAO,IAAI,WAAW;AAAA,IAChE,EAAE,GAAG,MAAM,OAAO,IAAI,WAAW,GAAG,MAAM,OAAO,IAAI,WAAW;AAAA,IAChE,EAAE,GAAG,MAAM,OAAO,IAAI,WAAW,GAAG,MAAM,OAAO,IAAI,WAAW;AAAA,IAChE,EAAE,GAAG,MAAM,OAAO,IAAI,WAAW,GAAG,MAAM,OAAO,IAAI,WAAW;AAAA,EAClE,CAAC;AACH;AAEA,IAAM,sBAAsB,CAAC;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,qBAAqB;AACvB,MAM8B;AAC5B,QAAM,YAAY,QAAQ;AAC1B,QAAM,aAAa,SAAS;AAC5B,QAAM,iBAAiB,UAAU,oBAAoB,GAAG,CAAC;AACzD,SAAO;AAAA,IACL;AAAA,MACE,EAAE,GAAG,IAAI,WAAW,GAAG,IAAI,WAAW;AAAA,MACtC,EAAE,GAAG,IAAI,WAAW,GAAG,IAAI,WAAW;AAAA,MACtC,EAAE,GAAG,IAAI,WAAW,GAAG,IAAI,WAAW;AAAA,MACtC,EAAE,GAAG,IAAI,WAAW,GAAG,IAAI,WAAW;AAAA,IACxC,EAAE,IAAI,CAAC,UAAU,aAAa,gBAAgB,KAAK,CAAC;AAAA,EACtD;AACF;AAGA,IAAM,cAAc,CAAC;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,qBAAqB;AACvB,MAO6B;AAC3B,QAAM,SAAS,KAAK,IAAI,GAAG,KAAK,IAAI,cAAc,QAAQ,GAAG,SAAS,CAAC,CAAC;AACxE,MAAI,UAAU,kBAAkB;AAC9B,UAAM,UAAU,oBAAoB;AAAA,MAClC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AACD,WAAO,UAAU,EAAE,MAAM,UAAU,QAAQ,CAAC,OAAO,EAAE,IAAI;AAAA,EAC3D;AAEA,QAAM,SAAwB,CAAC;AAC/B,QAAM,aAAa,QAAQ,IAAI;AAC/B,QAAM,cAAc,SAAS,IAAI;AACjC,MAAI,aAAa,kBAAkB;AACjC,UAAM,eAAe,oBAAoB;AAAA,MACvC;AAAA,MACA;AAAA,MACA,OAAO;AAAA,MACP;AAAA,MACA;AAAA,IACF,CAAC;AACD,QAAI,aAAc,QAAO,KAAK,YAAY;AAAA,EAC5C;AACA,MAAI,cAAc,kBAAkB;AAClC,UAAM,iBAAiB,oBAAoB;AAAA,MACzC;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,IACF,CAAC;AACD,QAAI,eAAgB,QAAO,KAAK,cAAc;AAAA,EAChD;AAEA,QAAM,iBAAiB,aAAa;AACpC,QAAM,kBAAkB,cAAc;AACtC,QAAM,iBAAiB,UAAU,oBAAoB,GAAG,CAAC;AACzD,QAAM,gBAAgB;AAAA,IACpB,EAAE,GAAG,IAAI,gBAAgB,GAAG,IAAI,gBAAgB;AAAA,IAChD,EAAE,GAAG,IAAI,gBAAgB,GAAG,IAAI,gBAAgB;AAAA,IAChD,EAAE,GAAG,IAAI,gBAAgB,GAAG,IAAI,gBAAgB;AAAA,IAChD,EAAE,GAAG,IAAI,gBAAgB,GAAG,IAAI,gBAAgB;AAAA,EAClD,EACG,IAAI,CAAC,UAAU,aAAa,gBAAgB,KAAK,CAAC,EAClD;AAAA,IACC,CAAC,OAAO,OAAO,WACb,OAAO;AAAA,MACL,CAAC,cACC,KAAK,IAAI,UAAU,IAAI,MAAM,CAAC,KAAK,oBACnC,KAAK,IAAI,UAAU,IAAI,MAAM,CAAC,KAAK;AAAA,IACvC,MAAM;AAAA,EACV;AACF,SAAO;AAAA,IACL,GAAG,cAAc;AAAA,MACf,CAAC,WACC,IAAY,eAAO,IAAY,cAAM,OAAO,GAAG,OAAO,CAAC,GAAG,MAAM;AAAA,IACpE;AAAA,EACF;AAEA,SAAO,OAAO,SAAS,IAAI,EAAE,MAAM,UAAU,OAAO,IAAI;AAC1D;AAEA,IAAM,OAAO,CAAC;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,qBAAqB;AACvB,MAOsB;AACpB,QAAM,iBAAiB,KAAK,IAAI,KAAK,IAAI,OAAO,MAAM,IAAI,IAAI,QAAQ,CAAC;AACvE,QAAM,YACJ,SAAS,SAAS,EAAE,GAAG,gBAAgB,GAAG,EAAE,IAAI,EAAE,GAAG,GAAG,GAAG,eAAe;AAC5E,QAAM,OAAO,aAAa,UAAU,kBAAkB,GAAG,SAAS;AAElE,MAAI,kBAAkB,kBAAkB;AACtC,WAAO;AAAA,MACL,MAAM;AAAA,MACN,QAAQ,CAAC,IAAY,eAAO,IAAY,cAAM,GAAG,CAAC,GAAG,MAAM,CAAC;AAAA,IAC9D;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,YAAY,IAAY;AAAA,MACtB,IAAY,cAAM,IAAI,KAAK,GAAG,IAAI,KAAK,CAAC;AAAA,MACxC,IAAY,cAAM,IAAI,KAAK,GAAG,IAAI,KAAK,CAAC;AAAA,IAC1C;AAAA,IACA;AAAA,EACF;AACF;AAEA,IAAM,oBAAoB,CAAC,QAA0C;AACnE,UAAQ,IAAI,OAAO;AAAA,IACjB,KAAK;AACH,aAAO;AAAA,QACL,MAAM;AAAA,QACN,QAAQ;AAAA,UACN,IAAY,eAAO,IAAY,cAAM,IAAI,GAAG,IAAI,CAAC,GAAG,IAAI,MAAM;AAAA,QAChE;AAAA,MACF;AAAA,IACF,KAAK;AACH,aAAO,YAAY;AAAA,QACjB,GAAG,IAAI;AAAA,QACP,GAAG,IAAI;AAAA,QACP,OAAO,IAAI;AAAA,QACX,QAAQ,IAAI;AAAA,QACZ,cAAc,IAAI,sBAAsB,IAAI,iBAAiB;AAAA,MAC/D,CAAC;AAAA,IACH,KAAK;AACH,aAAO,YAAY;AAAA,QACjB,GAAG,IAAI;AAAA,QACP,GAAG,IAAI;AAAA,QACP,OAAO,IAAI;AAAA,QACX,QAAQ,IAAI;AAAA,QACZ,cAAc,IAAI,sBAAsB,IAAI,iBAAiB;AAAA,QAC7D,oBAAoB,IAAI;AAAA,MAC1B,CAAC;AAAA,IACH,KAAK;AACH,aAAO,KAAK;AAAA,QACV,GAAG,IAAI;AAAA,QACP,GAAG,IAAI;AAAA,QACP,OAAO,IAAI;AAAA,QACX,QAAQ,IAAI;AAAA,QACZ,QAAQ,IAAI;AAAA,MACd,CAAC;AAAA,IACH,KAAK;AACH,aAAO,KAAK;AAAA,QACV,GAAG,IAAI;AAAA,QACP,GAAG,IAAI;AAAA,QACP,OAAO,IAAI;AAAA,QACX,QAAQ,IAAI;AAAA,QACZ,QAAQ,IAAI;AAAA,QACZ,oBAAoB,IAAI;AAAA,MAC1B,CAAC;AAAA,IACH,KAAK,WAAW;AACd,YAAM,UAAU,gBAAgB,IAAI,MAAM;AAC1C,aAAO,UAAU,EAAE,MAAM,UAAU,QAAQ,CAAC,OAAO,EAAE,IAAI;AAAA,IAC3D;AAAA,EACF;AACF;AAEA,IAAM,wBAAwB,CAC5B,YACA,gCAC0B;AAC1B,UAAQ,WAAW,OAAO;AAAA,IACxB,KAAK;AACH,aAAO;AAAA,QACL,MAAM;AAAA,QACN,QAAQ;AAAA,UACN,IAAY;AAAA,YACV,IAAY,cAAM,WAAW,GAAG,WAAW,CAAC;AAAA,YAC5C,WAAW,iBAAiB;AAAA,UAC9B;AAAA,QACF;AAAA,MACF;AAAA,IACF,KAAK;AAAA,IACL,KAAK;AACH,aAAO,KAAK;AAAA,QACV,GAAG,WAAW;AAAA,QACd,GAAG,WAAW;AAAA,QACd,OAAO,WAAW;AAAA,QAClB,QAAQ,WAAW;AAAA,QACnB,QAAQ,KAAK;AAAA,UACX,WAAW,cAAc;AAAA,UACzB,WAAW,eAAe;AAAA,QAC5B;AAAA,QACA,oBAAoB,WAAW;AAAA,MACjC,CAAC;AAAA,IACH,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO,YAAY;AAAA,QACjB,GAAG,WAAW;AAAA,QACd,GAAG,WAAW;AAAA,QACd,OAAO,WAAW;AAAA,QAClB,QAAQ,WAAW;AAAA,QACnB,cAAc,WAAW,sBAAsB;AAAA,QAC/C,oBACE,uBAAuB,aAClB,WAAW,qBAAqB,IACjC;AAAA,MACR,CAAC;AAAA,IACH,KAAK,yBAAyB;AAC5B,YAAM,qBACJ,WAAW,gBAAgB;AAC7B,YAAM,iBAAiB,UAAU,kBAAkB;AACnD,YAAM,UAAU;AAAA,QACd,WAAW,YAAY,IAAI,CAAC,UAAU;AACpC,gBAAM,eAAe,aAAa,gBAAgB,KAAK;AACvD,iBAAO;AAAA,YACL,GAAG,WAAW,IAAI,aAAa;AAAA,YAC/B,GAAG,WAAW,IAAI,aAAa;AAAA,UACjC;AAAA,QACF,CAAC;AAAA,MACH;AACA,aAAO,UAAU,EAAE,MAAM,UAAU,QAAQ,CAAC,OAAO,EAAE,IAAI;AAAA,IAC3D;AAAA,EACF;AACF;AAEA,IAAM,oBAAoB,CACxB,SACA,8BAC0B;AAC1B,MAAI,QAAQ,SAAS,WAAW;AAC9B,WAAO;AAAA,MACL,MAAM;AAAA,MACN,QAAQ;AAAA,QACN,IAAY;AAAA,UACV,IAAY,cAAM,QAAQ,GAAG,QAAQ,CAAC;AAAA,UACtC,QAAQ,iBAAiB;AAAA,QAC3B;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,MAAI,QAAQ,SAAS,aAAc,QAAO,kBAAkB,OAAO;AACnE,MAAI,QAAQ,SAAS,mBAAmB;AACtC,WAAO;AAAA,MACL;AAAA,MACA,QAAQ,mBACH,0BAA0B;AAAA,QACzB,iBAAiB,QAAQ,gBAAgB;AAAA,MAC3C,KAAK,IACL;AAAA,IACN;AAAA,EACF;AAEA,MAAI;AACJ,UAAQ,QAAQ,OAAO;AAAA,IACrB,KAAK;AACH,gBAAU,oBAAoB;AAAA,QAC5B,GAAG,QAAQ,OAAO;AAAA,QAClB,GAAG,QAAQ,OAAO;AAAA,QAClB,OAAO,QAAQ;AAAA,QACf,QAAQ,QAAQ;AAAA,QAChB,oBAAoB,QAAQ,YAAY;AAAA,MAC1C,CAAC;AACD;AAAA,IACF,KAAK;AACH,gBAAU,gBAAgB,QAAQ,MAAM;AACxC;AAAA,IACF,KAAK;AAEH,gBAAU,kBAAkB,QAAQ,WAAW,WAAW,QAAQ;AAClE;AAAA,EACJ;AACA,SAAO,UAAU,EAAE,MAAM,UAAU,QAAQ,CAAC,OAAO,EAAE,IAAI;AAC3D;AAEA,IAAM,qBAAqB,CAAC,YAAmC;AAC7D,MAAI,QAAQ,SAAS,UAAW,QAAO,QAAQ;AAC/C,MAAI,QAAQ,SAAS,aAAc,QAAO,QAAQ;AAClD,MAAI,QAAQ,SAAS,kBAAmB,QAAO,QAAQ;AACvD,SAAO,QAAQ;AACjB;AAEA,IAAM,wBAAwB,CAAC,YAAmC;AAChE,MAAI,QAAQ,SAAS,UAAW,QAAO;AACvC,MAAI,QAAQ,SAAS,aAAc,QAAO;AAC1C,MAAI,QAAQ,SAAS,kBAAmB,QAAO;AAC/C,SAAO;AACT;AAEA,IAAM,mBAAmB,CACvB,OACA,aAC6C;AAC7C,MAAI,SAAS,SAAS,UAAU;AAC9B,UAAMC,YAAW,SAAS,OAAO,MAAM,CAAC,UAAU,MAAM,SAAS,KAAK,CAAC;AACvE,WAAO;AAAA,MACL,UAAAA;AAAA,MACA,WAAWA,YACP,KAAK;AAAA,QACH,GAAG,SAAS,OAAO,IAAI,CAAC,UAAU,MAAM,WAAW,KAAK,EAAE,CAAC,CAAC;AAAA,MAC9D,IACA;AAAA,IACN;AAAA,EACF;AAEA,QAAM,sBAAsB,MAAM,WAAW,SAAS,UAAU,EAAE,CAAC;AACnE,QAAM,YAAY,sBAAsB,SAAS;AACjD,QAAM,WACJ,MAAM,SAAS,SAAS,UAAU,KAAK,aAAa,CAAC;AACvD,SAAO;AAAA,IACL;AAAA,IACA,WAAW,WAAW,KAAK,IAAI,GAAG,SAAS,IAAI;AAAA,EACjD;AACF;AAYO,SAAS,gCACd,aACqB;AACrB,QAAM,QAAQ,YAAY,WAAW;AACrC,MAAI,CAAC,MAAO,QAAO,CAAC;AAEpB,QAAM,eAAe,eAAe,KAAK;AACzC,MAAI,CAAC,aAAc,QAAO,CAAC;AAE3B,QAAM,oBACJ,iBAAiB,OAAO,0BAA0B,KAClD,iBAAiB;AACnB,MAAI,sBAAsB,OAAW,QAAO,CAAC;AAE7C,QAAM,8BAA8B,IAAI;AAAA,IACtC,YACG;AAAA,MACC,CAAC,YAAqC,QAAQ,SAAS;AAAA,IACzD,EACC,OAAO,CAAC,cAAc,UAAU,0BAA0B,EAC1D,IAAI,CAAC,cAAc,iBAAiB,UAAU,gBAAgB,CAAC;AAAA,EACpE;AAEA,QAAM,iBAAiB,YAAY;AAAA,IACjC,CAAC,YACC,QAAQ,SAAS,aACjB,QAAQ,SAAS,gBACjB,QAAQ,SAAS,qBACjB,QAAQ,SAAS;AAAA,EACrB;AACA,QAAM,4BAA4B,IAAI;AAAA,IACpC,YACG;AAAA,MACC,CAAC,YAAqC,QAAQ,SAAS;AAAA,IACzD,EACC,IAAI,CAAC,cAAc;AAAA,MAClB,iBAAiB,UAAU,gBAAgB;AAAA,MAC3C,UAAU;AAAA,IACZ,CAAC;AAAA,EACL;AAEA,QAAM,SAA8B,CAAC;AACrC,aAAW,WAAW,gBAAgB;AACpC,SACG,QAAQ,SAAS,gBAAgB,QAAQ,SAAS,sBACnD,QAAQ,oBACR,4BAA4B;AAAA,MAC1B,iBAAiB,QAAQ,gBAAgB;AAAA,IAC3C,GACA;AACA;AAAA,IACF;AAEA,UAAM,WAAW,kBAAkB,SAAS,yBAAyB;AACrE,QAAI,CAAC,SAAU;AAEf,UAAM,EAAE,UAAU,UAAU,IAAI,iBAAiB,cAAc,QAAQ;AACvE,QAAI,YAAY,YAAY,oBAAoB,mBAAmB;AACjE;AAAA,IACF;AAEA,UAAM,KAAK,mBAAmB,OAAO;AACrC,UAAM,QAAQ,sBAAsB,OAAO;AAC3C,WAAO,KAAK;AAAA,MACV,MAAM;AAAA,MACN,wBAAwB,kCAAkC,EAAE;AAAA,MAC5D,YAAY;AAAA,MACZ,SAAS,GAAG,KAAK,IAAI,EAAE,sDAAsD,UAAU,QAAQ,CAAC,CAAC,gBAAgB,kBAAkB,QAAQ,CAAC,CAAC;AAAA,IAC/I,CAAC;AAAA,EACH;AAEA,SAAO;AACT;;;ADhiBO,SAAS,kBACd,aACqB;AACrB,QAAM,OAAO,YAAY,OAAO,CAAC,YAAY,QAAQ,SAAS,SAAS;AACvE,QAAM,iBAAiB,IAAI;AAAA,IACzB;AAAA,MACE,YAAY;AAAA,QACV,CAAC,YAAY,QAAQ,SAAS,eAAe,QAAQ,SAAS;AAAA,MAChE;AAAA,IACF,EAAE,IAAI,CAAC,UAAU;AAAA,MACf,MAAM,uBAAuB;AAAA,QAC3B;AAAA,QACA;AAAA,MACF;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO,KAAK,QAAQ,CAAC,QAAQ;AAC3B,UAAM,YAAY,eAAe,IAAI,IAAI,UAAU;AACnD,QAAI,CAAC,UAAW,QAAO,CAAC;AAExB,UAAM,UAAUC,2BAA0B,aAAa,IAAI,UAAU;AACrE,WAAO;AAAA,MACL;AAAA,QACE,GAAG;AAAA,QACH,wBAAwB,gBAAgB,IAAI,UAAU;AAAA,QACtD,SAAS,OAAO,OAAO;AAAA,MACzB;AAAA,IACF;AAAA,EACF,CAAC;AACH;;;AE1BA,YAAYC,cAAa;AACzB,SAAS,aAAAC,YAAW,gBAAAC,qBAAoB;AAOxC,SAAS,aAAa,MAAgC;AAEpD,SAAO,KAAK,KAAK,KAAK;AACxB;AAEA,SAAS,iBAAiB;AAAA,EACxB;AAAA,EACA;AAAA,EACA,cAAc;AAChB,GAIoB;AAClB,QAAM,KAAK,OAAO;AAClB,QAAM,KAAK,OAAO;AAClB,QAAM,KAAK,KAAK,QAAQ;AACxB,QAAM,KAAK,KAAK,SAAS;AAEzB,QAAM,UAA2B;AAAA,IAC/B,IAAY,eAAM,KAAK,IAAI,KAAK,EAAE;AAAA,IAClC,IAAY,eAAM,KAAK,IAAI,KAAK,EAAE;AAAA,IAClC,IAAY,eAAM,KAAK,IAAI,KAAK,EAAE;AAAA,IAClC,IAAY,eAAM,KAAK,IAAI,KAAK,EAAE;AAAA,EACpC;AAEA,MAAI,OAAO,IAAY,iBAAQ,OAAO;AAEtC,MAAI,aAAa;AACf,UAAM,SAASD,WAAU,aAAa,IAAI,EAAE;AAC5C,UAAM,iBAAiB,QAAQ,IAAI,CAAC,OAAO;AACzC,YAAM,IAAIC,cAAa,QAAQ,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE,CAAC;AACnD,aAAO,IAAY,eAAM,EAAE,GAAG,EAAE,CAAC;AAAA,IACnC,CAAC;AACD,WAAO,IAAY,iBAAQ,cAAc;AAAA,EAC3C;AAGA,MAAI,CAAC,aAAa,IAAI,EAAG,MAAK,QAAQ;AAEtC,SAAO;AACT;AAEA,SAASC,gBAAe;AAAA,EACtB;AACF,GAE2B;AACzB,MAAI,MAAM,WAAW,MAAM,QAAQ,SAAS,GAAG;AAC7C,UAAM,SAAS,MAAM,QAAQ,IAAI,CAAC,MAAM,IAAY,eAAM,EAAE,GAAG,EAAE,CAAC,CAAC;AACnE,UAAM,OAAO,IAAY,iBAAQ,MAAM;AAEvC,QAAI,CAAC,aAAa,IAAI,GAAG;AACvB,WAAK,QAAQ;AAAA,IACf;AAEA,WAAO;AAAA,EACT;AAEA,MACE,MAAM,UACN,OAAO,MAAM,UAAU,YACvB,OAAO,MAAM,WAAW,UACxB;AACA,WAAO,iBAAiB;AAAA,MACtB,QAAQ,MAAM;AAAA,MACd,MAAM,EAAE,OAAO,MAAM,OAAO,QAAQ,MAAM,OAAO;AAAA,MACjD,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAGA,SAAS,iBAAiB;AAAA,EACxB;AAAA,EACA;AACF,GAGW;AACT,MAAI,UAAU,qBAAqB;AACjC,UAAM,kBAAkB,YAAY;AAAA,MAClC,CAAC,OACC,GAAG,SAAS,sBACZ,GAAG,wBAAwB,UAAU;AAAA,IACzC;AACA,QAAI,mBAAmB,UAAU,mBAAmB,gBAAgB,MAAM;AACxE,aAAO,gBAAgB;AAAA,IACzB;AAAA,EACF;AAEA,SAAO,4BAA4B,aAAa,UAAU,gBAAgB;AAC5E;AAUA,SAAS,uBACP,UACA,WACA,iBACA,gBACA,iBACA,aACQ;AACR,QAAM,cAAc,IAAY,eAAM,gBAAgB,GAAG,gBAAgB,CAAC;AAE1E,MAAI,CAAC,UAAU,SAAS,WAAW,GAAG;AACpC,UAAM,OAAO,UAAU,WAAW,WAAW;AAC7C,WAAO,MAAM,QAAQ,IAAI,IAAI,KAAK,CAAC,IAAI,OAAO,IAAI,KAAK;AAAA,EACzD;AAGA,QAAM,KAAK,iBAAiB;AAC5B,QAAM,KAAK,kBAAkB;AAG7B,QAAM,UAAmB;AAAA,IACvB,EAAE,GAAG,gBAAgB,IAAI,IAAI,GAAG,gBAAgB,IAAI,GAAG;AAAA,IACvD,EAAE,GAAG,gBAAgB,IAAI,IAAI,GAAG,gBAAgB,IAAI,GAAG;AAAA,IACvD,EAAE,GAAG,gBAAgB,IAAI,IAAI,GAAG,gBAAgB,IAAI,GAAG;AAAA,IACvD,EAAE,GAAG,gBAAgB,IAAI,IAAI,GAAG,gBAAgB,IAAI,GAAG;AAAA,EACzD;AAGA,QAAM,YAAqB,CAAC;AAC5B,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,UAAM,QAAQ,IAAI,KAAK;AACvB,cAAU,KAAK;AAAA,MACb,IAAI,QAAQ,CAAC,EAAE,IAAI,QAAQ,IAAI,EAAE,KAAK;AAAA,MACtC,IAAI,QAAQ,CAAC,EAAE,IAAI,QAAQ,IAAI,EAAE,KAAK;AAAA,IACxC,CAAC;AAAA,EACH;AAGA,QAAM,SAASF,WAAU,aAAa,gBAAgB,GAAG,gBAAgB,CAAC;AAC1E,QAAMG,eAAc,CAAC,OAAc;AACjC,UAAM,IAAIF,cAAa,QAAQ,EAAE;AACjC,WAAO,IAAY,eAAM,EAAE,GAAG,EAAE,CAAC;AAAA,EACnC;AAEA,QAAM,gBAAgB,QAAQ,OAAO,SAAS,EAAE,IAAIE,YAAW;AAG/D,MAAI,cAAc;AAClB,aAAW,MAAM,eAAe;AAC9B,QAAI,CAAC,UAAU,SAAS,EAAE,GAAG;AAC3B,YAAM,OAAO,UAAU,WAAW,EAAE;AACpC,YAAM,IAAI,MAAM,QAAQ,IAAI,IAAI,KAAK,CAAC,IAAI,OAAO,IAAI,KAAK;AAC1D,UAAI,IAAI,YAAa,eAAc;AAAA,IACrC;AAAA,EACF;AAEA,MAAI,cAAc,GAAG;AACnB,WAAO;AAAA,EACT;AAGA,MAAI;AACF,UAAM,eAAuB,2BAAkB;AAAA,MAC7C;AAAA,MACA;AAAA,IACF;AAEA,QAAI,mBAAmB;AACvB,QAAI,CAAC,cAAc;AACjB,yBAAmB;AAAA,IACrB,WAAW,MAAM,QAAQ,YAAY,GAAG;AACtC,yBAAmB,aAAa;AAAA,QAC9B,CAAC,KAAK,MAAM,OAAO,OAAO,EAAE,SAAS,aAAa,EAAE,KAAK,IAAI;AAAA,QAC7D;AAAA,MACF;AAAA,IACF,WAAW,OAAQ,aAAqB,SAAS,YAAY;AAC3D,yBAAoB,aAAqB,KAAK;AAAA,IAChD,OAAO;AACL,yBAAmB;AAAA,IACrB;AAEA,UAAM,WAAW,SAAS,KAAK;AAE/B,QAAI,mBAAmB,KAAK,mBAAmB,UAAU;AACvD,YAAM,eAAe,IAAI,mBAAmB;AAC5C,YAAM,YAAY,KAAK,IAAI,cAAc;AACzC,YAAM,aAAa,KAAK,IAAI,eAAe;AAC3C,aAAO,KAAK,IAAI,WAAW,UAAU,IAAI;AAAA,IAC3C,WAAW,qBAAqB,GAAG;AAEjC,aAAO;AAAA,IACT,OAAO;AACL,aAAO;AAAA,IACT;AAAA,EACF,QAAQ;AAEN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,wBAAwB;AAAA,EAC/B;AAAA,EACA;AACF,GAGkB;AAChB,QAAM,WAAW,UAAU;AAC3B,QAAM,eAAe,cAAc;AAEnC,MAAI,SAAS;AACb,MAAI,SAAS;AAEb,MAAI,aAAa,OAAO,SAAS,MAAM;AACrC,aAAS,SAAS,OAAO,aAAa;AAAA,EACxC,WAAW,aAAa,OAAO,SAAS,MAAM;AAC5C,aAAS,SAAS,OAAO,aAAa;AAAA,EACxC;AAEA,MAAI,aAAa,OAAO,SAAS,MAAM;AACrC,aAAS,SAAS,OAAO,aAAa;AAAA,EACxC,WAAW,aAAa,OAAO,SAAS,MAAM;AAC5C,aAAS,SAAS,OAAO,aAAa;AAAA,EACxC;AAEA,MAAI,WAAW,KAAK,WAAW,GAAG;AAChC,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,UAAU,IAAI,UAAU;AACrC,QAAM,OAAO,UAAU,IAAI,OAAO;AAClC,QAAM,QAAQ,KAAK,IAAI,KAAK,MAAM,SAAS,GAAG,IAAI,GAAG;AACrD,QAAM,QAAQ,KAAK,IAAI,KAAK,MAAM,SAAS,GAAG,IAAI,GAAG;AAErD,MAAI,QAAQ,KAAK,QAAQ,GAAG;AAC1B,WAAO,iBAAiB,KAAK,MAAM,IAAI,QAAQ,KAAK,MAAM,IAAI;AAAA,EAChE;AAEA,MAAI,QAAQ,GAAG;AACb,WAAO,iBAAiB,KAAK,MAAM,IAAI;AAAA,EACzC;AAEA,SAAO,iBAAiB,KAAK,MAAM,IAAI;AACzC;AAMO,SAAS,6BACd,aACiC;AACjC,QAAM,QAAQ,YAAY;AAAA,IACxB,CAAC,OAAuB,GAAG,SAAS;AAAA,EACtC;AACA,MAAI,CAAC,MAAO,QAAO,CAAC;AAEpB,QAAM,YAAYD,gBAAe,EAAE,MAAM,CAAC;AAC1C,MAAI,CAAC,UAAW,QAAO,CAAC;AAExB,QAAM,aAAa,YAAY;AAAA,IAC7B,CAAC,OAA2B,GAAG,SAAS;AAAA,EAC1C;AACA,MAAI,WAAW,WAAW,EAAG,QAAO,CAAC;AAErC,QAAM,SAA0C,CAAC;AAEjD,aAAW,KAAK,YAAY;AAC1B,QAAI,EAAE,2BAA4B;AAGlC,QACE,CAAC,EAAE,UACH,OAAO,EAAE,UAAU,YACnB,OAAO,EAAE,WAAW;AAEpB;AAEF,QAAI,EAAE,SAAS,KAAK,EAAE,UAAU,EAAG;AAInC,UAAM,WAAW,iBAAiB;AAAA,MAChC,QAAQ,EAAE;AAAA,MACV,MAAM,EAAE,OAAO,EAAE,OAAO,QAAQ,EAAE,OAAO;AAAA,MACzC,aAAa;AAAA,IACf,CAAC;AAED,QAAI,SAAS,KAAK,MAAM,EAAG;AAI3B,UAAM,WAAW,UAAU,SAAS,QAAQ;AAC5C,QAAI,SAAU;AAGd,UAAM,kBAAkB;AAAA,MACtB;AAAA,MACA;AAAA,MACA,EAAE;AAAA,MACF,EAAE;AAAA,MACF,EAAE;AAAA,MACF;AAAA,IACF;AAEA,UAAM,WAAW,iBAAiB,EAAE,aAAa,WAAW,EAAE,CAAC;AAC/D,UAAM,oBAAoB,KAAK,MAAM,kBAAkB,GAAG,IAAI;AAC9D,UAAM,uBAAuB,wBAAwB;AAAA,MACnD,eAAe;AAAA,MACf;AAAA,IACF,CAAC;AAED,WAAO,KAAK;AAAA,MACV,MAAM;AAAA,MACN,YAAY;AAAA,MACZ,sCAAsC,+BAA+B,EAAE,gBAAgB;AAAA,MACvF,SAAS,aAAa,QAAQ,wCAAwC,iBAAiB,MAAM,uBAAuB,IAAI,oBAAoB,KAAK,EAAE;AAAA,MACnJ,kBAAkB,EAAE;AAAA,MACpB,cAAc,MAAM;AAAA,MACpB,kBAAkB,EAAE;AAAA,MACpB,kBAAkB;AAAA,QAChB,OAAO,SAAS,IAAI;AAAA,QACpB,OAAO,SAAS,IAAI;AAAA,QACpB,OAAO,SAAS,IAAI;AAAA,QACpB,OAAO,SAAS,IAAI;AAAA,MACtB;AAAA,MACA,eAAe,EAAE;AAAA,MACjB,qBAAqB,EAAE;AAAA,IACzB,CAAC;AAAA,EACH;AAEA,SAAO;AACT;;;ACjWA,SAAS,uBAAuB;AAOhC,YAAYE,cAAa;AACzB,SAAS,gBAAAC,eAAc,aAAAC,kBAAiB;AAGxC,IAAM,yBAAyB;AAE/B,SAASC,kBAAiB;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AACb,GAKG;AACD,QAAM,YAAY,QAAQ;AAC1B,QAAM,aAAa,SAAS;AAC5B,QAAM,UAAU;AAAA,IACd,EAAE,GAAG,OAAO,IAAI,WAAW,GAAG,OAAO,IAAI,WAAW;AAAA,IACpD,EAAE,GAAG,OAAO,IAAI,WAAW,GAAG,OAAO,IAAI,WAAW;AAAA,IACpD,EAAE,GAAG,OAAO,IAAI,WAAW,GAAG,OAAO,IAAI,WAAW;AAAA,IACpD,EAAE,GAAG,OAAO,IAAI,WAAW,GAAG,OAAO,IAAI,WAAW;AAAA,EACtD;AACA,QAAM,SAASC,WAAU,UAAU,OAAO,GAAG,OAAO,CAAC;AAErD,SAAO,IAAY;AAAA,IACjB,QAAQ,IAAI,CAAC,WAAW;AACtB,YAAM,UAAU,WAAWC,cAAa,QAAQ,MAAM,IAAI;AAC1D,aAAO,IAAY,eAAM,QAAQ,GAAG,QAAQ,CAAC;AAAA,IAC/C,CAAC;AAAA,EACH;AACF;AAEA,SAAS,cAAc;AAAA,EACrB;AAAA,EACA;AACF,GAGG;AACD,SAAO,IAAY;AAAA,IACjB,MAAM,KAAK,EAAE,QAAQ,uBAAuB,GAAG,CAAC,GAAG,UAAU;AAC3D,YAAM,QAAS,IAAI,KAAK,KAAK,QAAS;AACtC,aAAO,IAAY;AAAA,QACjB,OAAO,IAAI,KAAK,IAAI,KAAK,IAAI;AAAA,QAC7B,OAAO,IAAI,KAAK,IAAI,KAAK,IAAI;AAAA,MAC/B;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAEA,SAAS,gBAAgB,QAA2C;AAClE,MAAI,OAAO,UAAU,QAAQ;AAC3B,WAAOF,kBAAiB;AAAA,MACtB,QAAQ,OAAO;AAAA,MACf,OAAO,OAAO;AAAA,MACd,QAAQ,OAAO;AAAA,MACf,UAAU,OAAO,YAAY;AAAA,IAC/B,CAAC;AAAA,EACH;AAEA,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO,cAAc,EAAE,QAAQ,OAAO,QAAQ,QAAQ,OAAO,OAAO,CAAC;AAAA,EACvE;AAEA,MAAI,OAAO,UAAU,WAAW;AAC9B,WAAO,IAAY;AAAA,MACjB,OAAO,OAAO,IAAI,CAAC,UAAU,IAAY,eAAM,MAAM,GAAG,MAAM,CAAC,CAAC;AAAA,IAClE;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,mBAAmB,SAA0B;AACpD,SAAO;AAAA,IACL,MAAM,QAAQ,IAAI;AAAA,IAClB,MAAM,QAAQ,IAAI;AAAA,IAClB,MAAM,QAAQ,IAAI;AAAA,IAClB,MAAM,QAAQ,IAAI;AAAA,EACpB;AACF;AAEA,SAAS,kBACP,UACA,UACA;AACA,MACE,CAAC,gBAAgB,mBAAmB,QAAQ,GAAG,mBAAmB,QAAQ,CAAC,GAC3E;AACA,WAAO;AAAA,EACT;AACA,MAAI,SAAS,SAAS,QAAQ,KAAK,SAAS,SAAS,QAAQ,EAAG,QAAO;AAEvE,MAAI;AACF,UAAM,gBAAwB,2BAAkB;AAAA,MAC9C;AAAA,MACA;AAAA,IACF;AACA,QAAI,MAAM,QAAQ,aAAa,GAAG;AAChC,aAAO,cAAc,KAAK,CAAC,YAAY,QAAQ,KAAK,IAAI,CAAC;AAAA,IAC3D;AACA,WAAO,cAAc,KAAK,IAAI;AAAA,EAChC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAMO,SAAS,4BACd,aACqB;AACrB,QAAM,UAAU,YAAY;AAAA,IAC1B,CAAC,YAAkC,QAAQ,SAAS;AAAA,EACtD;AACA,QAAM,aAAa,YAAY;AAAA,IAC7B,CAAC,YAAqC,QAAQ,SAAS;AAAA,EACzD;AACA,MAAI,QAAQ,WAAW,KAAK,WAAW,WAAW,EAAG,QAAO,CAAC;AAE7D,QAAM,iBAAiB,QACpB,IAAI,CAAC,YAAY,EAAE,QAAQ,SAAS,gBAAgB,MAAM,EAAE,EAAE,EAC9D;AAAA,IACC,CAAC,UACC,MAAM,YAAY,QAAQ,MAAM,QAAQ,KAAK,IAAI;AAAA,EACrD;AACF,QAAM,SAA8B,CAAC;AAErC,aAAW,aAAa,YAAY;AAClC,QAAI,CAAC,UAAU,UAAU,UAAU,SAAS,KAAK,UAAU,UAAU,GAAG;AACtE;AAAA,IACF;AAEA,UAAM,mBAAmBA,kBAAiB;AAAA,MACxC,QAAQ,UAAU;AAAA,MAClB,OAAO,UAAU;AAAA,MACjB,QAAQ,UAAU;AAAA,IACpB,CAAC;AACD,eAAW,EAAE,QAAQ,SAAS,cAAc,KAAK,gBAAgB;AAC/D,UAAI,OAAO,qBAAqB,UAAU,iBAAkB;AAC5D,UAAI,CAAC,kBAAkB,kBAAkB,aAAa,EAAG;AAEzD,YAAM,gBAAgB;AAAA,QACpB;AAAA,QACA,UAAU;AAAA,MACZ;AACA,YAAM,WAAW,OAAO;AAExB,aAAO,KAAK;AAAA,QACV,MAAM;AAAA,QACN,wBAAwB,yBAAyB,UAAU,gBAAgB,IAAI,QAAQ;AAAA,QACvF,YAAY;AAAA,QACZ,SAAS,aAAa,aAAa,8BAA8B,QAAQ;AAAA,QACzE,eAAe,UAAU;AAAA,MAC3B,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;;;AC3KA,SAAS,OAAAG,MAAK,gBAAAC,qBAAoB;AAgBlC,IAAM,kBAAkB,CAAC,WACvB,sBAAsB,UAAU,OAAO,mBACnC,OAAO,mBACPC,cAAa,MAAM;AAEzB,IAAM,wBAAwB,CAC5B,aACA,WACG;AACH,MAAI,sBAAsB,UAAU,OAAO,kBAAkB;AAC3D,UAAM,eAAe,YAAY;AAAA,MAC/B,CAAC,YACC,QAAQ,SAAS,mBACjB,QAAQ,qBAAqB,OAAO;AAAA,IACxC;AACA,UAAM,kBACJ,cAAc,SAAS,kBACnB,YAAY;AAAA,MACV,CAAC,YACC,QAAQ,SAAS,sBACjB,QAAQ,wBAAwB,aAAa;AAAA,IACjD,IACA;AACN,UAAM,gBACJ,iBAAiB,SAAS,sBAAsB,gBAAgB,OAC5D,gBAAgB,OAChB,4BAA4B,aAAa,OAAO,gBAAgB;AAEtE,WAAO,aAAa,aAAa;AAAA,EACnC;AAEA,SAAO,OAAO,SAAS,YACnB,OAAO,OAAO,UAAU,KACxB,GAAG,OAAO,IAAI,IAAIA,cAAa,MAAM,CAAC;AAC5C;AAEO,SAAS,0BACd,aACqB;AACrB,QAAM,WAAWC,KAAI,WAAW,EAAE,YAAY,KAAK;AACnD,MAAI,SAAS,WAAW,EAAG,QAAO,CAAC;AAEnC,QAAM,SAAgC;AAAA,IACpC,GAAG,QAAQ,WAAW;AAAA,IACtB,GAAIA,KAAI,WAAW,EAAE,QAAQ,KAAK;AAAA,EACpC;AACA,QAAM,SAAS,oBAAI,IAA+B;AAElD,aAAW,WAAW,UAAU;AAC9B,UAAM,uBAAuB,IAAI;AAAA,MAC/B,QAAQ,8BAA8B,CAAC;AAAA,IACzC;AAEA,eAAW,iBAAiB,QAAQ;AAClC,YAAM,oBACJ,sBAAsB,gBAClB,cAAc,mBACd;AACN,UAAI,qBAAqB,qBAAqB,IAAI,iBAAiB,GAAG;AACpE;AAAA,MACF;AAEA,YAAM,eAAe,sBAAsB,aAAa;AACxD,UAAI,CAAC,aAAa,KAAK,CAAC,UAAU,QAAQ,OAAO,SAAS,KAAK,CAAC,GAAG;AACjE;AAAA,MACF;AAEA,UAAI,eAAe,eAAe,OAAO,IAAI,QAAS;AAEtD,YAAM,UAAU,gBAAgB,aAAa;AAC7C,YAAM,UAAU,uBAAuB,OAAO,IAAI,QAAQ,cAAc;AACxE,UAAI,OAAO,IAAI,OAAO,EAAG;AAEzB,aAAO,IAAI,SAAS;AAAA,QAClB,MAAM;AAAA,QACN,wBAAwB;AAAA,QACxB,YAAY;AAAA,QACZ,SAAS,cAAc;AAAA,UACrB;AAAA,UACA;AAAA,QACF,CAAC,aACC,QAAQ,cACJ,gBAAgB,QAAQ,WAAW,MACnC,eACN;AAAA,QACA,eAAe,cAAc,iBAAiB,QAAQ;AAAA,MACxD,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO,CAAC,GAAG,OAAO,OAAO,CAAC;AAC5B;;;AC3GA,SAAS,6BAAAC,kCAAiC;AAM1C;AAAA,EAEE,yCAAAC;AAAA,OACK;;;ACTA,SAASC,UACd,GACA,GACQ;AACR,SAAO,KAAK,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;AACxC;;;ACDO,SAAS,sBAAsB,GAAW,GAAoB;AACnE,SAAOC,UAAS,GAAG,CAAC,KAAK;AAC3B;;;AFSO,SAAS,uBACd,aACA;AAAA,EACE;AAAA,EACA;AACF,IAA0D,CAAC,GACnC;AACxB,QAAM,OAAO,YAAY,OAAO,CAAC,OAAO,GAAG,SAAS,SAAS;AAC7D,MAAI,KAAK,SAAS,EAAG,QAAO,CAAC;AAC7B,QAAM,QAAQ,YAAY,WAAW;AACrC,mBACE,iBAAiB,OAAO,8CAA8C,KACtE,iBAAiB;AACnB,cAAYC,uCAAsC,WAAW;AAC7D,QAAM,SAAiC,CAAC;AACxC,QAAM,WAAW,oBAAI,IAAY;AAEjC,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,aAAS,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACxC,YAAM,OAAO,KAAK,CAAC;AACnB,YAAM,OAAO,KAAK,CAAC;AAEnB,UAAI,sBAAsB,MAAM,IAAI,EAAG;AACvC,UAAI,CAAC,QAAQ,gBAAgB,KAAK,YAAY,KAAK,UAAU,EAAG;AAChE,YAAM,MACJC,UAAS,MAAM,IAAI,IAAI,KAAK,gBAAgB,IAAI,KAAK,gBAAgB;AACvE,UAAI,MAAM,WAAW,aAAe;AACpC,YAAM,SAAS,CAAC,KAAK,YAAY,KAAK,UAAU,EAAE,KAAK,EAAE,KAAK,GAAG;AACjE,UAAI,SAAS,IAAI,MAAM,EAAG;AAC1B,eAAS,IAAI,MAAM;AACnB,aAAO,KAAK;AAAA,QACV,MAAM;AAAA,QACN,cAAc,uBAAuB,MAAM;AAAA,QAC3C,SAAS,QAAQC;AAAA,UACf;AAAA,UACA,KAAK;AAAA,QACP,CAAC,QAAQA;AAAA,UACP;AAAA,UACA,KAAK;AAAA,QACP,CAAC,iCAAiC,IAAI,QAAQ,CAAC,CAAC;AAAA,QAChD,YAAY;AAAA,QACZ,aAAa,CAAC,KAAK,YAAY,KAAK,UAAU;AAAA,QAC9C,mBAAmB;AAAA,QACnB,kBAAkB;AAAA,QAClB,YAAY;AAAA,UACV,IAAI,KAAK,IAAI,KAAK,KAAK;AAAA,UACvB,IAAI,KAAK,IAAI,KAAK,KAAK;AAAA,QACzB;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;;;AGpEA,SAAS,6BAAAC,kCAAiC;AAM1C;AAAA,EAEE,yCAAAC;AAAA,OACK;AAMA,SAAS,4BACd,aACA;AAAA,EACE;AAAA,EACA;AACF,IAA0D,CAAC,GACnC;AACxB,QAAM,OAAO,YAAY,OAAO,CAAC,OAAO,GAAG,SAAS,SAAS;AAC7D,MAAI,KAAK,SAAS,EAAG,QAAO,CAAC;AAC7B,QAAM,QAAQ,YAAY,WAAW;AACrC,mBACE,iBAAiB,OAAO,8CAA8C,KACtE,iBAAiB;AACnB,cAAYC,uCAAsC,WAAW;AAC7D,QAAM,SAAiC,CAAC;AACxC,QAAM,WAAW,oBAAI,IAAY;AAEjC,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,aAAS,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACxC,YAAM,OAAO,KAAK,CAAC;AACnB,YAAM,OAAO,KAAK,CAAC;AAEnB,UAAI,sBAAsB,MAAM,IAAI,EAAG;AACvC,UAAI,QAAQ,gBAAgB,KAAK,YAAY,KAAK,UAAU,EAAG;AAC/D,YAAM,MACJC,UAAS,MAAM,IAAI,IAAI,KAAK,gBAAgB,IAAI,KAAK,gBAAgB;AACvE,UAAI,MAAM,WAAW,aAAe;AACpC,YAAM,SAAS,CAAC,KAAK,YAAY,KAAK,UAAU,EAAE,KAAK,EAAE,KAAK,GAAG;AACjE,UAAI,SAAS,IAAI,MAAM,EAAG;AAC1B,eAAS,IAAI,MAAM;AACnB,aAAO,KAAK;AAAA,QACV,MAAM;AAAA,QACN,cAAc,4BAA4B,MAAM;AAAA,QAChD,SAAS,QAAQC;AAAA,UACf;AAAA,UACA,KAAK;AAAA,QACP,CAAC,QAAQA;AAAA,UACP;AAAA,UACA,KAAK;AAAA,QACP,CAAC,qDAAqD,IAAI;AAAA,UACxD;AAAA,QACF,CAAC;AAAA,QACD,YAAY;AAAA,QACZ,aAAa,CAAC,KAAK,YAAY,KAAK,UAAU;AAAA,QAC9C,mBAAmB;AAAA,QACnB,kBAAkB;AAAA,QAClB,YAAY;AAAA,UACV,IAAI,KAAK,IAAI,KAAK,KAAK;AAAA,UACvB,IAAI,KAAK,IAAI,KAAK,KAAK;AAAA,QACzB;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;;;ACtEA,SAAS,OAAAC,YAAW;AAQpB,SAAS,yCAAAC,8CAA6C;AAG/C,SAAS,wCACd,aACmB;AACnB,QAAM,WAA8B,CAAC;AACrC,QAAM,KAAKC,KAAI,WAAW;AAE1B,QAAM,eAAe,GAAG,aAAa,KAAK;AAC1C,QAAM,YAAY,GAAG,UAAU,KAAK;AACpC,QAAM,WAAW,GAAG,SAAS,KAAK;AAClC,QAAM,kBAAkBC,uCAAsC,WAAW;AAEzE,aAAW,eAAe,cAAc;AACtC,UAAM,qBAAqB,YAAY;AACvC,QAAI,uBAAuB,OAAW;AAEtC,UAAM,oBAAoB,SAAS;AAAA,MAAO,CAAC,YACzC,YAAY,2BAA2B,SAAS,QAAQ,cAAc;AAAA,IACxE;AACA,QAAI,kBAAkB,SAAS,EAAG;AAElC,UAAM,iBAAiB,gBAAgB;AAAA,MACrC,kBAAkB,CAAC,EAAE;AAAA,IACvB;AACA,QAAI,CAAC,eAAgB;AAErB,UAAM,gBAAgB,gBAAgB,qBAAqB,cAAc;AACzE,UAAM,mBAAmB,UAAU;AAAA,MAAO,CAAC,aACzC,cAAc,SAAS,SAAS,YAAY;AAAA,IAC9C;AACA,QAAI,iBAAiB,WAAW,EAAG;AAEnC,UAAM,mBAAmB,iBAAiB;AAAA,MAAQ,CAAC,aACjD,SAAS,MACN,OAAO,CAAC,UAAU,MAAM,eAAe,MAAM,EAC7C,IAAI,CAAC,UAAU,MAAM,KAAK;AAAA,IAC/B;AACA,QAAI,iBAAiB,WAAW,EAAG;AAEnC,UAAM,kBAAkB,KAAK,IAAI,GAAG,gBAAgB;AACpD,QAAI,mBAAmB,mBAAoB;AAE3C,QAAI;AAIJ,eAAW,mBAAmB,kBAAkB;AAC9C,eAAS,IAAI,GAAG,IAAI,gBAAgB,MAAM,SAAS,GAAG,KAAK;AACzD,cAAM,QAAQ,gBAAgB,MAAM,CAAC;AACrC,cAAM,YAAY,gBAAgB,MAAM,IAAI,CAAC;AAC7C,YAAI,CAAC,SAAS,CAAC,UAAW;AAC1B,YAAI,MAAM,eAAe,UAAU,UAAU,eAAe,QAAQ;AAClE;AAAA,QACF;AACA,YAAI,MAAM,UAAU,gBAAiB;AAErC,4BAAoB;AAAA,UAClB,cAAc,gBAAgB;AAAA,UAC9B,QAAQ;AAAA,YACN,IAAI,MAAM,IAAI,UAAU,KAAK;AAAA,YAC7B,IAAI,MAAM,IAAI,UAAU,KAAK;AAAA,UAC/B;AAAA,QACF;AACA;AAAA,MACF;AAEA,UAAI,kBAAmB;AAAA,IACzB;AAEA,QAAI,CAAC,kBAAmB;AAExB,aAAS,KAAK;AAAA,MACZ,MAAM;AAAA,MACN,sBAAsB,qBAAqB,YAAY,eAAe;AAAA,MACtE,cAAc;AAAA,MACd,SAAS,UAAU,8BAA8B,aAAa,WAAW,CAAC,kDAAkD,kBAAkB,eAAe,eAAe;AAAA,MAC5K,QAAQ,kBAAkB;AAAA,MAC1B,iBAAiB,YAAY;AAAA,MAC7B,cAAc,kBAAkB;AAAA,MAChC,mBAAmB,MAAM;AAAA,QACvB,IAAI;AAAA,UACF,kBACG,IAAI,CAAC,YAAY,QAAQ,gBAAgB,EACzC,OAAO,CAAC,OAAqB,OAAO,MAAS;AAAA,QAClD;AAAA,MACF;AAAA,MACA,cAAc,kBAAkB,IAAI,CAAC,YAAY,QAAQ,WAAW;AAAA,IACtE,CAAC;AAAA,EACH;AAEA,SAAO;AACT;;;AC9FA,SAAS,yCAAAC,8CAA6C;AAQtD,SAAS,+BACP,aACwB;AACxB,QAAM,SAAiC,CAAC;AACxC,QAAM,eAAe,YAAY;AAAA,IAC/B,CAAC,OAAO,GAAG,SAAS;AAAA,EACtB;AACA,QAAM,YAAY,YAAY;AAAA,IAC5B,CAAC,OAAO,GAAG,SAAS;AAAA,EACtB;AACA,QAAM,WAAW,YAAY;AAAA,IAC3B,CAAC,OAAO,GAAG,SAAS;AAAA,EACtB;AACA,QAAM,sBAAsB,IAAI;AAAA,IAC9B,SAAS,IAAI,CAAC,YAAY,CAAC,QAAQ,gBAAgB,OAAO,CAAC;AAAA,EAC7D;AACA,QAAM,kBAAkBC,uCAAsC,WAAW;AAEzE,aAAW,eAAe,cAAc;AACtC,QAAI,CAAC,YAAY,2BAA2B,OAAQ;AACpD,SAAK,YAAY,0BAA0B,UAAU,KAAK,EAAG;AAC7D,QAAI,YAAY,0BAA0B,SAAS,EAAG;AAEtD,UAAM,cAAc,UAAU;AAAA,MAAK,CAAC,aAClC,gBAAgB;AAAA,QACd,YAAY;AAAA,QACZ,SAAS;AAAA,MACX;AAAA,IACF;AAEA,QAAI,CAAC,aAAa;AAChB,YAAM,oBAAoB,YAAY,0BACnC,IAAI,CAAC,iBAAiB,oBAAoB,IAAI,YAAY,CAAC,EAC3D,OAAO,CAAC,YAAgC,YAAY,MAAS;AAGhE,YAAM,2BAA2B,MAAM;AAAA,QACrC,IAAI;AAAA,UACF,kBACG,IAAI,CAAC,SAAS,KAAK,gBAAgB,EACnC,OAAO,CAAC,OAAqB,OAAO,MAAS;AAAA,QAClD;AAAA,MACF;AAEA,aAAO,KAAK;AAAA,QACV,MAAM;AAAA,QACN,4BAA4B,qBAAqB,YAAY,eAAe;AAAA,QAC5E,YAAY;AAAA,QACZ,SAAS,UAAU,YAAY,gBAAgB,CAAC,sBAAsB,YAAY,YAAY,IAAI,YAAY,eAAe,OAAO;AAAA,QACpI,iBAAiB,YAAY;AAAA,QAC7B,mBAAmB;AAAA,QACnB,cAAc,kBAAkB,IAAI,CAAC,SAAS,KAAK,WAAW;AAAA,MAChE,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;;;AC/DA,SAAS,0BAAAC,+BAA8B;AAIvC;AAAA,EACE,6BAAAC;AAAA,EACA;AAAA,OACK;AACP;AAAA,EAEE,yCAAAC;AAAA,EACA,sBAAAC;AAAA,OACK;AAsBP,IAAM,2BAA2B;AACjC,IAAM,iCAAiC;AAEvC,SAAS,qBAAqB,OAA2B,KAAa;AACpE,SACE,MAAM,eAAe,UACrB,sBAAsB,GAAG,EAAE,SAAS,MAAM,KAAK,KAC/C,aAAa,OAAO,GAAG;AAE3B;AAEA,SAAS,kCACP,WACA,qBACgC;AAChC,QAAM,wBAAwD,oBAAI,IAAI;AAEtE,aAAW,SAAS,WAAW;AAG7B,QAAI,MAAM,yBAAyB,eAAgB;AAEnD,UAAM,QAAQ,oBAAoB,oBAAoB,MAAM,YAAY;AACxE,QAAI,CAAC,MAAO;AAEZ,aAAS,IAAI,GAAG,IAAI,MAAM,MAAM,SAAS,GAAG,KAAK;AAC/C,YAAM,QAAQ,MAAM,MAAM,CAAC;AAC3B,YAAM,MAAM,MAAM,MAAM,IAAI,CAAC;AAE7B,UAAI,MAAM,eAAe,UAAU,IAAI,eAAe,OAAQ;AAC9D,UAAI,MAAM,UAAU,IAAI,MAAO;AAC/B,UACE,KAAK,MAAM,MAAM,IAAI,IAAI,GAAG,MAAM,IAAI,IAAI,CAAC,KAC3C,gCACA;AACA;AAAA,MACF;AAEA,YAAM,kBAAkB,sBAAsB,IAAI,KAAK,KAAK,oBAAI,IAAI;AACpE,YAAM,WAAW,gBAAgB,IAAI,MAAM,KAAK,KAAK,CAAC;AACtD,eAAS,KAAK,EAAE,OAAO,OAAO,IAAI,CAAC;AACnC,sBAAgB,IAAI,MAAM,OAAO,QAAQ;AACzC,4BAAsB,IAAI,OAAO,eAAe;AAAA,IAClD;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,4BACP,OACA,UACoB;AAGpB,MAAI,MAAM,yBAAyB,eAAgB,QAAO;AAE1D,MAAI,oBAAoB,aAAa,UAAU,IAAI,MAAM,MAAM,SAAS;AACxE,QAAM,YAAY,aAAa,UAAU,IAAI;AAE7C,SAAO,qBAAqB,KAAK,oBAAoB,MAAM,MAAM,SAAS,GAAG;AAC3E,UAAM,eAAe,MAAM,MAAM,iBAAiB;AAClD,UAAM,aAAa,MAAM,MAAM,oBAAoB,CAAC;AAEpD,QACE,cAAc,eAAe,UAC7B,YAAY,eAAe,UAC3B,aAAa,UAAU,WAAW,OAClC;AACA,aAAO;AAAA,IACT;AAEA,QACE,KAAK,MAAM,aAAa,IAAI,WAAW,GAAG,aAAa,IAAI,WAAW,CAAC,IACvE,gCACA;AAEA,aAAO,aAAa;AAAA,IACtB;AAEA,yBAAqB;AAAA,EACvB;AAEA,SAAO;AACT;AAEA,SAAS,+CAA+C;AAAA,EACtD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMY;AACV,MAAI,MAAM,eAAe,OAAQ,QAAO;AAExC,QAAM,aAAa,oBAAoB;AAAA,IACrC,WAAW;AAAA,EACb;AACA,MAAI,CAAC,WAAY,QAAO;AACxB,QAAM,oBACJ,+BAA+B,IAAI,UAAU,GAAG,IAAI,MAAM,KAAK,KAAK,CAAC;AAIvE,aAAW,WAAW,mBAAmB;AACvC,QAAI,QAAQ,MAAM,iBAAiB,WAAW,aAAc;AAE5D,UAAM,yBACJ,2BAA2B,IAC3B,QAAQ,MAAM,QAAQ,IACtB;AACF,QACEC,wBAAuB,OAAO,QAAQ,OAAO,QAAQ,GAAG,KACxD,wBACA;AACA,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,oBAAoB,OAA2B;AACtD,MAAI,MAAM,eAAe,eAAe;AACtC,WAAO;AAAA,MACL,IAAI,MAAM,MAAM,IAAI,MAAM,IAAI,KAAK;AAAA,MACnC,IAAI,MAAM,MAAM,IAAI,MAAM,IAAI,KAAK;AAAA,IACrC;AAAA,EACF;AAEA,SAAO,EAAE,GAAG,MAAM,GAAG,GAAG,MAAM,EAAE;AAClC;AAEA,SAAS,wCACP,OACA,eACA,kBACA,QACA;AACA,SAAO,cAAc,KAAK,CAAC,iBAAiB;AAC1C,QACE,CAAC,aAAa,eACd,aAAa,gBAAgB,kBAC7B;AACA,aAAO;AAAA,IACT;AAEA,UAAM,eAAe,OAAO,IAAI,aAAa,WAAW;AACxD,WACE,cAAc,KAAK,CAAC,QAAQ,qBAAqB,OAAO,GAAG,CAAC,KAAK;AAAA,EAErE,CAAC;AACH;AAEA,SAAS,gCAAgC;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMG;AACD,MAAI;AAGJ,QAAM,iBACJ,WAAW,eAAe,SAAS,aAAa;AAClD,QAAM,gBAAgB,UAAU,eAAe,SAAS,YAAY;AACpE,QAAM,+BAA+B;AAAA,IACnC;AAAA,EACF,EAAE,SAAS,KAAK,WAAW;AAC3B,QAAM,8BAA8B;AAAA,IAClC;AAAA,EACF,EAAE,SAAS,KAAK,WAAW;AAE3B,MAAI,gCAAgC,gBAAgB;AAClD,oBAAgB;AAAA,EAClB,WAAW,+BAA+B,eAAe;AACvD,oBAAgB;AAAA,EAClB,WACE;AAAA,IACE;AAAA,IACA;AAAA,IACA,KAAK;AAAA,IACL;AAAA,EACF,KACA,eACA;AACA,oBAAgB;AAAA,EAClB,WACE;AAAA,IACE;AAAA,IACA;AAAA,IACA,KAAK;AAAA,IACL;AAAA,EACF,KACA,gBACA;AACA,oBAAgB;AAAA,EAClB,WAAW,kBAAkB,eAAe;AAC1C,oBACEC,UAAS,gBAAgB,IAAI,KAAKA,UAAS,eAAe,IAAI,IAC1D,iBACA;AAAA,EACR,WAAW,gBAAgB;AACzB,oBAAgB;AAAA,EAClB,WAAW,eAAe;AACxB,oBAAgB;AAAA,EAClB;AAEA,QAAM,mBAAmB,oBAAoB,UAAU;AACvD,QAAM,kBAAkB,oBAAoB,SAAS;AAErD,SAAO,gBACH,EAAE,GAAG,cAAc,GAAG,GAAG,cAAc,EAAE,IACzC;AAAA,IACE,IAAI,iBAAiB,IAAI,gBAAgB,KAAK;AAAA,IAC9C,IAAI,iBAAiB,IAAI,gBAAgB,KAAK;AAAA,EAChD;AACN;AAEA,SAAS,yBACP,aACiB;AACjB,QAAM,SAA0B,CAAC;AAEjC,QAAM,WAAW,YAAY;AAAA,IAC3B,CAAC,OAAO,GAAG,SAAS;AAAA,EACtB;AACA,QAAM,YAAY,YAAY;AAAA,IAC5B,CAAC,OAAO,GAAG,SAAS;AAAA,EACtB;AACA,QAAM,eAAe,YAAY;AAAA,IAC/B,CAAC,OAAO,GAAG,SAAS;AAAA,EACtB;AACA,QAAM,aAAa,YAAY;AAAA,IAC7B,CAAC,OAAO,GAAG,SAAS;AAAA,EACtB;AACA,QAAM,iBAAiB,YAAY;AAAA,IACjC,CAAC,OAAO,GAAG,SAAS;AAAA,EACtB;AAEA,QAAM,SAAS,oBAAI,IAAyB;AAC5C,QAAM,qBAAqB,IAAIC,oBAAmB,WAAW;AAC7D,MAAI;AACJ,MAAI;AACJ,QAAM,yBAAyB,MAAM;AACnC,4BAAwBC,uCAAsC,WAAW;AACzE,WAAO;AAAA,EACT;AACA,QAAM,2BAA2B,MAAM;AACrC,uCAAmC;AAAA,MACjC;AAAA,MACA,uBAAuB;AAAA,IACzB;AACA,WAAO;AAAA,EACT;AACA,QAAM,wBAAwB,oBAAI,IAAY;AAE9C,aAAW,OAAO,YAAY;AAC5B,QAAI,IAAI,aAAa;AACnB,aAAO,IAAI,IAAI,aAAa,CAAC,GAAI,OAAO,IAAI,IAAI,WAAW,KAAK,CAAC,GAAI,GAAG,CAAC;AAAA,IAC3E;AAAA,EACF;AAEA,aAAW,QAAQ,gBAAgB;AACjC,QAAI,KAAK,aAAa;AACpB,aAAO,IAAI,KAAK,aAAa;AAAA,QAC3B,GAAI,OAAO,IAAI,KAAK,WAAW,KAAK,CAAC;AAAA,QACrC;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAM,0BAA0B,oBAAI,IAA4B;AAChE,QAAM,0BAA0B,oBAAI,IAA4B;AAKhE,aAAW,SAAS,WAAW;AAC7B,UAAM,iBAAiB,oBAAI,IAAe;AAC1C,UAAM,aAAa,MAAM,MAAM,CAAC;AAChC,UAAM,YAAY,MAAM,MAAM,GAAG,EAAE;AAEnC,eAAW,SAAS,CAAC,YAAY,SAAS,GAAG;AAC3C,UAAI,CAAC,MAAO;AAEZ,iBAAW,CAAC,WAAW,IAAI,KAAK,QAAQ;AACtC,YAAI,KAAK,KAAK,CAAC,QAAQ,qBAAqB,OAAO,GAAG,CAAC,GAAG;AACxD,yBAAe,IAAI,SAAS;AAAA,QAC9B;AAAA,MACF;AAAA,IACF;AAEA,4BAAwB,IAAI,MAAM,cAAc,cAAc;AAC9D,eAAW,aAAa,gBAAgB;AACtC,YAAM,WAAW,wBAAwB,IAAI,SAAS,KAAK,oBAAI,IAAI;AACnE,eAAS,IAAI,MAAM,YAAY;AAC/B,8BAAwB,IAAI,WAAW,QAAQ;AAAA,IACjD;AAAA,EACF;AAEA,QAAM,qCAAqC,oBAAI,IAAwB;AACvE,QAAM,+BAA+B,CAAC,eAAqC;AACzE,UAAM,SAAS,mCAAmC;AAAA,MAChD,WAAW;AAAA,IACb;AACA,QAAI,OAAQ,QAAO;AAEnB,UAAM,oBAAoB,oBAAI,IAAY;AAC1C,UAAM,kBAAkB,CAAC,WAAW,YAAY;AAEhD,WAAO,gBAAgB,SAAS,GAAG;AACjC,YAAM,UAAU,gBAAgB,IAAI;AACpC,UAAI,kBAAkB,IAAI,OAAO,EAAG;AACpC,wBAAkB,IAAI,OAAO;AAE7B,iBAAW,kBAAkB,mBAAmB;AAAA,QAC9C;AAAA,MACF,GAAG;AACD,YAAI,CAAC,kBAAkB,IAAI,eAAe,YAAY,GAAG;AACvD,0BAAgB,KAAK,eAAe,YAAY;AAAA,QAClD;AAAA,MACF;AAEA,iBAAW,aAAa,wBAAwB,IAAI,OAAO,KAAK,CAAC,GAAG;AAClE,mBAAW,mBAAmB,wBAAwB,IAAI,SAAS,KACjE,CAAC,GAAG;AACJ,cAAI,CAAC,kBAAkB,IAAI,eAAe,GAAG;AAC3C,4BAAgB,KAAK,eAAe;AAAA,UACtC;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,UAAM,kBAAkB,UAAU;AAAA,MAAO,CAAC,UACxC,kBAAkB,IAAI,MAAM,YAAY;AAAA,IAC1C;AACA,eAAW,SAAS,iBAAiB;AACnC,yCAAmC;AAAA,QACjC,MAAM;AAAA,QACN;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,aAAW,SAAS,WAAW;AAC7B,QAAI,MAAM,MAAM,WAAW,EAAG;AAE9B,UAAM,aAAa,MAAM,MAAM,CAAC;AAChC,UAAM,YAAY,MAAM,MAAM,MAAM,MAAM,SAAS,CAAC;AAEpD,UAAM,cAAc,aAAa;AAAA,MAC/B,CAAC,OAAO,GAAG,oBAAoB,MAAM;AAAA,IACvC;AAEA,UAAM,gBAAgB,cAClB,SAAS;AAAA,MAAO,CAAC,SACf,YAAY,2BAA2B,SAAS,KAAK,cAAc;AAAA,IACrE,IACA,CAAC;AAEL,aAAS,IAAI,GAAG,IAAI,MAAM,MAAM,SAAS,GAAG,KAAK;AAC/C,YAAM,YAAY,MAAM,MAAM,IAAI,CAAC;AACnC,YAAM,eAAe,MAAM,MAAM,CAAC;AAClC,YAAM,YAAY,MAAM,MAAM,IAAI,CAAC;AAEnC,UAAI,aAAa,eAAe,OAAO;AACrC,cAAM,aAAa,UAAU,eAAe;AAC5C,cAAM,aAAa,UAAU,eAAe;AAE5C,YAAI,cAAc,YAAY;AAC5B,gBAAM,cACJ,KAAK,IAAI,UAAU,IAAI,aAAa,CAAC,IAAI,QACzC,KAAK,IAAI,UAAU,IAAI,aAAa,CAAC,IAAI;AAE3C,gBAAM,cACJ,KAAK,IAAI,UAAU,IAAI,aAAa,CAAC,IAAI,QACzC,KAAK,IAAI,UAAU,IAAI,aAAa,CAAC,IAAI;AAE3C,cAAI,CAAC,eAAe,CAAC,aAAa;AAChC,kBAAMC,aAAY;AAAA,cAChB;AAAA,cACA,MAAM;AAAA,YACR;AACA,mBAAO,KAAK;AAAA,cACV,MAAM;AAAA,cACN,SAAS,iBAAiBA,UAAS,mCAAmC,aAAa,CAAC,QAAQ,aAAa,CAAC;AAAA,cAC1G,iBACE,aAAa,mBACb,MAAM,mBACN,IAAI,MAAM,YAAY;AAAA,cACxB,YAAY;AAAA,cACZ,cAAc,MAAM;AAAA,cACpB,oBAAoB,kBAAkB,MAAM,YAAY,IAAI,CAAC;AAAA,cAC7D,mBAAmB,CAAC;AAAA,cACpB,cAAc,CAAC;AAAA,YACjB,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,UAAM,YAAY;AAAA,MAChB;AAAA,MACA,MAAM;AAAA,IACR;AAGA,QAAI,eAAe,cAAc,SAAS,GAAG;AAC3C,UAAI,sBAAsB,IAAI,YAAY,eAAe,EAAG;AAC5D,4BAAsB,IAAI,YAAY,eAAe;AAAA,IACvD;AAEA,eAAW,QAAQ,eAAe;AAChC,UAAI,CAAC,KAAK,YAAa;AAEvB,YAAM,OAAO,OAAO,IAAI,KAAK,WAAW;AAExC,UAAI,CAAC,MAAM,OAAQ;AAEnB,YAAM,iCAAiC;AAAA,QACrC;AAAA,MACF,EAAE;AAAA,QAAK,CAAC,mBACN,wBACG,IAAI,eAAe,YAAY,GAC9B,IAAI,KAAK,WAAW;AAAA,MAC1B;AACA,UAAI,+BAAgC;AAEpC,YAAM,wBAAwB,KAAK;AAAA,QAAK,CAAC,QACvC,qBAAqB,YAAY,GAAG;AAAA,MACtC;AAEA,YAAM,uBAAuB,KAAK;AAAA,QAAK,CAAC,QACtC,qBAAqB,WAAW,GAAG;AAAA,MACrC;AAEA,UAAI,CAAC,yBAAyB,CAAC,sBAAsB;AACnD,cAAM,WAAWC;AAAA,UACf;AAAA,UACA,KAAK;AAAA,QACP,EAAE,QAAQ,YAAY,EAAE;AACxB,cAAM,UAAU,KAAK,CAAC,EAAE,KAAK,QAAQ,QAAQ,EAAE;AAC/C,cAAM,cAAc,gCAAgC;AAAA,UAClD;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,CAAC;AACD,eAAO,KAAK;AAAA,UACV,MAAM;AAAA,UACN,SAAS,UAAU,SAAS,gCAAgC,OAAO,GAAG,QAAQ;AAAA,UAC9E,iBACE,aAAa,mBACb,MAAM,mBACN,IAAI,MAAM,YAAY;AAAA,UACxB,YAAY;AAAA,UACZ,cAAc,MAAM;AAAA,UACpB,oBAAoB,sBAAsB,MAAM,YAAY,IAAI,KAAK,WAAW;AAAA,UAChF,QAAQ;AAAA,UACR,mBAAmB,CAAC;AAAA,UACpB,cAAc,CAAC,KAAK,WAAW;AAAA,QACjC,CAAC;AAAA,MACH;AAAA,IACF;AAGA,QAAI,cAAc,WAAW,GAAG;AAC9B,UAAI,wBAAwB;AAC5B,UAAI,uBAAuB;AAE3B,iBAAW,QAAQ,OAAO,OAAO,GAAG;AAClC,YAAI,KAAK,KAAK,CAAC,QAAQ,qBAAqB,YAAY,GAAG,CAAC,GAAG;AAC7D,kCAAwB;AAAA,QAC1B;AACA,YAAI,KAAK,KAAK,CAAC,QAAQ,qBAAqB,WAAW,GAAG,CAAC,GAAG;AAC5D,iCAAuB;AAAA,QACzB;AAAA,MACF;AAEA,YAAM,gCAAgC,CAAC,wBACnC,4BAA4B,OAAO,OAAO,IAC1C;AACJ,YAAM,+BAA+B,CAAC,uBAClC,4BAA4B,OAAO,KAAK,IACxC;AACJ,YAAM,+CACJ,kCAAkC,UAClC,+CAA+C;AAAA,QAC7C,OAAO;AAAA,QACP,0BAA0B;AAAA,QAC1B,YAAY;AAAA,QACZ,gCAAgC,yBAAyB;AAAA,QACzD,qBAAqB,uBAAuB;AAAA,MAC9C,CAAC;AACH,YAAM,8CACJ,iCAAiC,UACjC,+CAA+C;AAAA,QAC7C,OAAO;AAAA,QACP,0BAA0B;AAAA,QAC1B,YAAY;AAAA,QACZ,gCAAgC,yBAAyB;AAAA,QACzD,qBAAqB,uBAAuB;AAAA,MAC9C,CAAC;AACH,YAAM,mBACJ,yBAAyB;AAC3B,YAAM,kBACJ,wBAAwB;AAC1B,YAAM,mBACJ,WAAW,eAAe,UAC1B,UAAU,eAAe,UACzB,WAAW,UAAU,UAAU,SAC/B,KAAK,MAAM,WAAW,IAAI,UAAU,GAAG,WAAW,IAAI,UAAU,CAAC,KAC/D;AAEJ,UAAI,CAAC,oBAAoB,WAAW,eAAe,QAAQ;AACzD,eAAO,KAAK;AAAA,UACV,MAAM;AAAA,UACN,SAAS,UAAU,SAAS,mCAAmC,WAAW,EAAE,QAAQ,CAAC,CAAC,KAAK,WAAW,EAAE,QAAQ,CAAC,CAAC;AAAA,UAClH,iBACE,aAAa,mBACb,MAAM,mBACN,IAAI,MAAM,YAAY;AAAA,UACxB,YAAY;AAAA,UACZ,cAAc,MAAM;AAAA,UACpB,oBAAoB,yBAAyB,MAAM,YAAY;AAAA,UAC/D,QAAQ,EAAE,GAAG,WAAW,GAAG,GAAG,WAAW,EAAE;AAAA,UAC3C,mBAAmB,CAAC;AAAA,UACpB,cAAc,CAAC;AAAA,QACjB,CAAC;AAAA,MACH;AACA,UACE,CAAC,mBACD,UAAU,eAAe,UACzB,EAAE,oBAAoB,CAAC,mBACvB;AACA,eAAO,KAAK;AAAA,UACV,MAAM;AAAA,UACN,SAAS,UAAU,SAAS,mCAAmC,UAAU,EAAE,QAAQ,CAAC,CAAC,KAAK,UAAU,EAAE,QAAQ,CAAC,CAAC;AAAA,UAChH,iBACE,aAAa,mBACb,MAAM,mBACN,IAAI,MAAM,YAAY;AAAA,UACxB,YAAY;AAAA,UACZ,cAAc,MAAM;AAAA,UACpB,oBAAoB,yBAAyB,MAAM,YAAY;AAAA,UAC/D,QAAQ,EAAE,GAAG,UAAU,GAAG,GAAG,UAAU,EAAE;AAAA,UACzC,mBAAmB,CAAC;AAAA,UACpB,cAAc,CAAC;AAAA,QACjB,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;ACrmBA,SAAS,OAAAC,YAAW;AAEpB,SAAS,+BAAAC,oCAAmC;AA0B5C,SAAS,sBAAsB,OAAiC;AAC9D,MAAI,MAAM,WAAW,MAAM,QAAQ,SAAS,GAAG;AAE7C,WAAO,MAAM,QAAQ,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,GAAG,EAAE,EAAE,EAAE;AAAA,EACtD;AAEA,MACE,MAAM,UACN,OAAO,MAAM,UAAU,YACvB,OAAO,MAAM,WAAW,UACxB;AAEA,UAAM,KAAK,MAAM,OAAO;AACxB,UAAM,KAAK,MAAM,OAAO;AACxB,UAAM,KAAK,MAAM,QAAQ;AACzB,UAAM,KAAK,MAAM,SAAS;AAE1B,WAAO;AAAA,MACL,EAAE,GAAG,KAAK,IAAI,GAAG,KAAK,GAAG;AAAA;AAAA,MACzB,EAAE,GAAG,KAAK,IAAI,GAAG,KAAK,GAAG;AAAA;AAAA,MACzB,EAAE,GAAG,KAAK,IAAI,GAAG,KAAK,GAAG;AAAA;AAAA,MACzB,EAAE,GAAG,KAAK,IAAI,GAAG,KAAK,GAAG;AAAA;AAAA,IAC3B;AAAA,EACF;AAEA,SAAO;AACT;AAMO,SAAS,yBACd,aACA,SAAgC,CAAC,GAChB;AACjB,QAAM,SAA0B,CAAC;AACjC,QAAM,QAAQ,YAAY,WAAW;AACrC,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,SACJ,OAAO,UACP,iBAAiB,OAAO,0BAA0B,KAClD,iBAAiB;AACnB,QAAM,cAAc,sBAAsB,KAAK;AAC/C,MAAI,CAAC,YAAa,QAAO;AAGzB,QAAM,YAAYC,KAAI,WAAW,EAAE,UAAU,KAAK;AAElD,aAAW,SAAS,WAAW;AAC7B,QAAI,MAAM,MAAM,SAAS,EAAG;AAG5B,aAAS,IAAI,GAAG,IAAI,MAAM,MAAM,SAAS,GAAG,KAAK;AAC/C,YAAM,KAAK,MAAM,MAAM,CAAC;AACxB,YAAM,KAAK,MAAM,MAAM,IAAI,CAAC;AAG5B,UAAI,GAAG,eAAe,UAAU,GAAG,eAAe,OAAQ;AAE1D,YAAM,aACJ,WAAW,KAAK,GAAG,QAAQ,WAAW,KAAK,GAAG,QAAQ;AACxD,YAAM,eAAsB,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AAC/C,YAAM,aAAoB,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AAG7C,UAAI,cAAc,OAAO;AACzB,eAAS,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK;AAC3C,cAAM,YAAY,YAAY,CAAC;AAC/B,cAAM,UAAU,aAAa,IAAI,KAAK,YAAY,MAAM;AACxD,cAAMC,YAAWC;AAAA,UACf;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AACA,YAAID,YAAW,aAAa;AAC1B,wBAAcA;AAAA,QAChB;AAAA,MACF;AAEA,YAAM,kBAAkB,aAAa,IAAI;AAEzC,UAAI,cAAc,iBAAiB;AACjC,cAAM,QAAuB;AAAA,UAC3B,MAAM;AAAA,UACN,YAAY;AAAA,UACZ,oBAAoB,4BAA4B,MAAM,YAAY,YAAY,CAAC;AAAA,UAC/E,SAAS,kCAAkC,YAAY,QAAQ,CAAC,CAAC,QAAQ,gBAAgB,QAAQ,CAAC,CAAC,wBAAwB,MAAM;AAAA,UACjI,cAAc,MAAM;AAAA,UACpB,iBAAiB,MAAM,mBAAmB;AAAA,UAC1C,QAAQ;AAAA,YACN,IAAI,aAAa,IAAI,WAAW,KAAK;AAAA,YACrC,IAAI,aAAa,IAAI,WAAW,KAAK;AAAA,UACvC;AAAA,UACA,mBAAmB,CAAC;AAAA,UACpB,cAAc,CAAC;AAAA,QACjB;AACA,eAAO,KAAK,KAAK;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;ACpIA;AAAA,EACE,OAAAE;AAAA,EACA,0BAAAC;AAAA,EACA,gBAAAC;AAAA,OACK;AACP,SAAS,mBAAAC,wBAAuB;AAShC,SAAS,yCAAAC,8CAA6C;;;ACdtD,SAAS,0BAAAC,+BAA8B;AACvC,SAAS,mBAAAC,wBAAuB;AAuBhC,SAAS,iBAAiB,MAAqC;AAC7D,MACE,KAAK,SAAS,0BACd,KAAK,SAAS,2BACd,KAAK,SAAS,2BACd,KAAK,SAAS,sBACd;AACA,WAAO,CAAC,KAAK,KAAK;AAAA,EACpB;AAEA,SAAO,sBAAsB,IAAkB;AACjD;AAEA,SAAS,gBAAgB,SAAmB,SAA4B;AACtE,MAAI,QAAQ,WAAW,KAAK,QAAQ,WAAW,EAAG,QAAO;AACzD,SAAO,QAAQ,KAAK,CAAC,MAAM,QAAQ,SAAS,CAAC,CAAC;AAChD;AAEO,SAAS,qBACd,OACA,OACS;AAET,QAAM,UAAU,iBAAiB,KAAK;AACtC,QAAM,UAAU,iBAAiB,KAAK;AACtC,MAAI,CAAC,gBAAgB,SAAS,OAAO,EAAG,QAAO;AAE/C,MAAI,MAAM,SAAS,gBAAgB,MAAM,SAAS,cAAc;AAC9D,WAAO,eAAe,OAAO,KAAK,KAAK;AAAA,EACzC;AAEA,QAAM,UAAUC,wBAAuB,CAAC,KAAK,CAAC;AAC9C,QAAM,UAAUA,wBAAuB,CAAC,KAAK,CAAC;AAC9C,SAAOC,iBAAgB,SAAS,OAAO;AACzC;;;ADjBA,IAAM,qBAAqB,CACzB,YAEA,QAAQ,SAAS,0BACjB,QAAQ,SAAS,2BACjB,QAAQ,SAAS,2BACjB,QAAQ,SAAS;AAEnB,IAAM,kCAAkC,CACtC,aACA,YACW;AACX,MAAI,iBAAiB,WAAW,QAAQ,aAAa;AACnD,WAAO,uBAAuB,aAAa,QAAQ,WAAW;AAAA,EAChE;AAEA,QAAM,KAAKC,cAAa,OAAO;AAC/B,QAAM,eAAe,4BAA4B,aAAa,EAAE;AAChE,SAAO,iBAAiB,YAAY,IAAI,EAAE,MAAM;AAClD;AAMO,SAAS,yBACd,aAC4B;AAC5B,QAAM,SAAqC,CAAC;AAG5C,QAAM,UAAUC,uCAAsC,WAAW;AAGjE,QAAM,UAAUC,KAAI,WAAW,EAAE,WAAW,KAAK;AACjD,QAAM,cAAcA,KAAI,WAAW,EAAE,gBAAgB,KAAK;AAC1D,QAAM,QAAQA,KAAI,WAAW,EAAE,SAAS,KAAK;AAC7C,QAAM,aAAa,YAAY,OAAO,kBAAkB;AAGxD,QAAM,eAAe,oBAAI,IAAmC;AAG5D,aAAW,OAAO,SAAS;AACzB,UAAM,cACJ,IAAI,oBAAoB,kBAAkBF,cAAa,GAAG,CAAC;AAC7D,QAAI,CAAC,aAAa,IAAI,WAAW,GAAG;AAClC,mBAAa,IAAI,aAAa;AAAA,QAC5B,cAAc;AAAA,QACd,UAAU,CAAC;AAAA,MACb,CAAC;AAAA,IACH;AACA,iBAAa,IAAI,WAAW,EAAG,SAAS,KAAK,GAAG;AAAA,EAClD;AAGA,aAAW,QAAQ,aAAa;AAC9B,UAAM,cACJ,KAAK,oBAAoB,0BAA0BA,cAAa,IAAI,CAAC;AACvE,QAAI,CAAC,aAAa,IAAI,WAAW,GAAG;AAClC,mBAAa,IAAI,aAAa;AAAA,QAC5B,cAAc;AAAA,QACd,UAAU,CAAC;AAAA,MACb,CAAC;AAAA,IACH;AACA,iBAAa,IAAI,WAAW,EAAG,SAAS,KAAK,IAAI;AAAA,EACnD;AAGA,aAAW,QAAQ,OAAO;AACxB,UAAM,cACJ,KAAK,oBAAoB,mBAAmBA,cAAa,IAAI,CAAC;AAChE,QAAI,CAAC,aAAa,IAAI,WAAW,GAAG;AAClC,mBAAa,IAAI,aAAa;AAAA,QAC5B,cAAc;AAAA,QACd,UAAU,CAAC,IAAI;AAAA,MACjB,CAAC;AAAA,IACH;AAAA,EACF;AAEA,aAAW,aAAa,YAAY;AAClC,UAAM,cAAc,UAAU;AAC9B,QAAI,CAAC,aAAa,IAAI,WAAW,GAAG;AAClC,mBAAa,IAAI,aAAa;AAAA,QAC5B,cAAc;AAAA,QACd,UAAU,CAAC;AAAA,MACb,CAAC;AAAA,IACH;AACA,iBAAa,IAAI,WAAW,EAAG,SAAS,KAAK,SAAS;AAAA,EACxD;AAGA,aAAW,CAAC,aAAa,aAAa,KAAK,cAAc;AACvD,QAAI,cAAc,SAAS,SAAS,GAAG;AACrC,oBAAc,SAASG,wBAAuB,cAAc,QAAQ;AAAA,IACtE;AAAA,EACF;AAGA,QAAM,yBAAyB,MAAM,KAAK,aAAa,OAAO,CAAC;AAG/D,WAAS,IAAI,GAAG,IAAI,uBAAuB,QAAQ,KAAK;AACtD,aAAS,IAAI,IAAI,GAAG,IAAI,uBAAuB,QAAQ,KAAK;AAC1D,YAAM,QAAQ,uBAAuB,CAAC;AACtC,YAAM,QAAQ,uBAAuB,CAAC;AAGtC,UAAI,CAAC,MAAM,UAAU,CAAC,MAAM,QAAQ;AAClC;AAAA,MACF;AAEA,UAAI,CAACC,iBAAgB,MAAM,QAAQ,MAAM,MAAM,GAAG;AAChD;AAAA,MACF;AAGA,iBAAW,SAAS,MAAM,UAAU;AAClC,mBAAW,SAAS,MAAM,UAAU;AAClC,gBAAM,MAAMJ,cAAa,KAAK;AAC9B,gBAAM,MAAMA,cAAa,KAAK;AAE9B,eACG,mBAAmB,KAAK,KAAK,mBAAmB,KAAK,MACtD,MAAM,SAAS,cACf,MAAM,SAAS,YACf;AACA;AAAA,UACF;AAIA,cACE,MAAM,SAAS,gBACf,MAAM,SAAS,gBACf,QAAQ,gBAAgB,KAAK,GAAG,GAChC;AACA;AAAA,UACF;AAGA,cAAI,qBAAqB,OAAO,KAAK,GAAG;AACtC,kBAAM,mBAAmB;AAAA,cACvB;AAAA,cACA;AAAA,YACF;AACA,kBAAM,mBAAmB;AAAA,cACvB;AAAA,cACA;AAAA,YACF;AAGA,kBAAM,QAAkC;AAAA,cACtC,MAAM;AAAA,cACN,cAAc,yBAAyB,GAAG,IAAI,GAAG;AAAA,cACjD,YAAY;AAAA,cACZ,SAAS,GAAG,MAAM,IAAI,IAAI,gBAAgB,kBAAkB,MAAM,IAAI,IAAI,gBAAgB;AAAA,YAC5F;AAGA,gBAAI,MAAM,SAAS,gBAAgB,MAAM,SAAS,cAAc;AAC9D,oBAAM,iBAAiB,CAAC;AACxB,kBAAI,MAAM,SAAS,aAAc,OAAM,eAAe,KAAK,GAAG;AAC9D,kBAAI,MAAM,SAAS,aAAc,OAAM,eAAe,KAAK,GAAG;AAAA,YAChE;AAEA,gBACE,MAAM,SAAS,qBACf,MAAM,SAAS,mBACf;AACA,oBAAM,sBAAsB,CAAC;AAC7B,kBAAI,MAAM,SAAS;AACjB,sBAAM,oBAAoB,KAAK,GAAG;AACpC,kBAAI,MAAM,SAAS;AACjB,sBAAM,oBAAoB,KAAK,GAAG;AAAA,YACtC;AAEA,gBAAI,MAAM,SAAS,cAAc,MAAM,SAAS,YAAY;AAC1D,oBAAM,eAAe,CAAC;AACtB,kBAAI,MAAM,SAAS,WAAY,OAAM,aAAa,KAAK,GAAG;AAC1D,kBAAI,MAAM,SAAS,WAAY,OAAM,aAAa,KAAK,GAAG;AAAA,YAC5D;AAEA,mBAAO,KAAK,KAAK;AAAA,UACnB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;AEjOA,IAAM,iBAAiB,oBAAI,IAAI;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAGM,SAAS,mCACd,aACuC;AACvC,QAAM,6BAA6B,IAAI;AAAA,IACrC,YACG,OAAO,CAAC,YAAY,eAAe,IAAI,QAAQ,IAAI,CAAC,EACpD;AAAA,MAAQ,CAAC,YACR,sBAAsB,WAAW,QAAQ,mBACrC,CAAC,QAAQ,gBAAgB,IACzB,CAAC;AAAA,IACP;AAAA,EACJ;AAEA,SAAO,YACJ;AAAA,IACC,CAAC,YAAqC,QAAQ,SAAS;AAAA,EACzD,EACC;AAAA,IACC,CAAC,cACC,CAAC,2BAA2B,IAAI,UAAU,gBAAgB;AAAA,EAC9D,EACC,IAAI,CAAC,cAAc;AAClB,UAAM,kBAAkB,UAAU,sBAC9B,YAAY;AAAA,MACV,CAAC,YACC,QAAQ,SAAS,sBACjB,QAAQ,wBAAwB,UAAU;AAAA,IAC9C,IACA;AACJ,UAAM,gBACJ,iBAAiB,SAAS,qBACtB,gBAAgB,OAChB,4BAA4B,aAAa,UAAU,gBAAgB;AAEzE,WAAO;AAAA,MACL,MAAM;AAAA,MACN,4CAA4C,2CAA2C,UAAU,gBAAgB;AAAA,MACjH,cAAc;AAAA,MACd,SAAS,GAAG,aAAa;AAAA,MACzB,kBAAkB,UAAU;AAAA,MAC5B,qBAAqB,UAAU;AAAA,MAC/B,eAAe,UAAU;AAAA,IAC3B;AAAA,EACF,CAAC;AACL;;;ACnDA,IAAM,wBAAwB;AAE9B,IAAM,wBAAwB,CAAC,eAC7B,WAAW,eAAe,gBACtB,WAAW,QACX,EAAE,GAAG,WAAW,GAAG,GAAG,WAAW,EAAE;AAEzC,IAAM,oBAAoB,CAAC,aAA+B;AACxD,MAAI,SAAS,iBAAiB,OAAW,QAAO,SAAS;AAEzD,MAAI,cAAc;AAElB,WACM,kBAAkB,GACtB,kBAAkB,SAAS,MAAM,QACjC,mBACA;AACA,UAAM,aAAa,SAAS,MAAM,eAAe;AACjD,QAAI,CAAC,WAAY;AAEjB,QAAI,WAAW,eAAe,OAAO;AACnC,qBAAe;AACf;AAAA,IACF;AAEA,UAAM,iBAAiB,SAAS,MAAM,kBAAkB,CAAC;AACzD,QAAI,CAAC,eAAgB;AAErB,UAAM,qBAAqB,sBAAsB,UAAU;AAC3D,UAAM,yBAAyB,sBAAsB,cAAc;AACnE,mBAAe,KAAK;AAAA,MAClB,uBAAuB,IAAI,mBAAmB;AAAA,MAC9C,uBAAuB,IAAI,mBAAmB;AAAA,IAChD;AAAA,EACF;AAEA,SAAO;AACT;AAEA,IAAM,0BAA0B,CAAC,aAAoC;AACnE,QAAM,aAAa,oBAAI,IAAY;AAEnC,aAAW,cAAc,SAAS,OAAO;AACvC,QAAI,WAAW,eAAe,OAAQ;AACtC,QAAI,WAAW,mBAAmB;AAChC,iBAAW,IAAI,WAAW,iBAAiB;AAAA,IAC7C;AACA,QAAI,WAAW,iBAAiB;AAC9B,iBAAW,IAAI,WAAW,eAAe;AAAA,IAC3C;AAAA,EACF;AAEA,SAAO;AACT;AAEO,IAAM,uBAAuB,CAClC,gBAC6B;AAC7B,QAAM,eAAe,YAAY;AAAA,IAC/B,CAAC,YAAoC,QAAQ,SAAS;AAAA,EACxD;AACA,QAAM,YAAY,YAAY;AAAA,IAC5B,CAAC,YAAiC,QAAQ,SAAS;AAAA,EACrD;AACA,QAAM,WAAW,YAAY;AAAA,IAC3B,CAAC,YAAgC,QAAQ,SAAS;AAAA,EACpD;AAEA,QAAM,mBAAmB,IAAI;AAAA,IAC3B,aAAa,IAAI,CAAC,gBAAgB;AAAA,MAChC,YAAY;AAAA,MACZ;AAAA,IACF,CAAC;AAAA,EACH;AACA,QAAM,2BAA2B,oBAAI,IAAyB;AAC9D,aAAW,WAAW,UAAU;AAC9B,QAAI,CAAC,QAAQ,eAAgB;AAC7B,UAAM,aACJ,yBAAyB,IAAI,QAAQ,cAAc,KAAK,oBAAI,IAAY;AAC1E,eAAW,IAAI,QAAQ,WAAW;AAClC,6BAAyB,IAAI,QAAQ,gBAAgB,UAAU;AAAA,EACjE;AAEA,QAAM,2BAA2B,oBAAI,IAAwB;AAC7D,aAAW,YAAY,WAAW;AAChC,QAAI,CAAC,SAAS,gBAAiB;AAC/B,UAAM,oBACJ,yBAAyB,IAAI,SAAS,eAAe,KAAK,CAAC;AAC7D,sBAAkB,KAAK,QAAQ;AAC/B,6BAAyB,IAAI,SAAS,iBAAiB,iBAAiB;AAAA,EAC1E;AAEA,QAAM,0CAA0C,oBAAI,IAAyB;AAC7E,aAAW,eAAe,cAAc;AACtC,QAAI,YAAY,0BAA0B,WAAW,EAAG;AAExD,UAAM,qBAAqB,YAAY,0BAA0B;AAAA,MAC/D,CAAC,iBAAiB,yBAAyB,IAAI,YAAY;AAAA,IAC7D;AACA,QAAI,mBAAmB,KAAK,CAAC,eAAe,CAAC,YAAY,IAAI,EAAG;AAEhE,UAAM,2BAA2B,IAAI;AAAA,OAClC,yBAAyB,IAAI,YAAY,eAAe,KAAK,CAAC,GAC5D,OAAO,CAAC,aAAa;AACpB,cAAM,uBAAuB,wBAAwB,QAAQ;AAC7D,eAAO,mBAAmB;AAAA,UAAM,CAAC,eAC/B,CAAC,GAAG,UAAW,EAAE;AAAA,YAAK,CAAC,cACrB,qBAAqB,IAAI,SAAS;AAAA,UACpC;AAAA,QACF;AAAA,MACF,CAAC,EACA,IAAI,CAAC,aAAa,SAAS,YAAY;AAAA,IAC5C;AAIA,QAAI,yBAAyB,OAAO,GAAG;AACrC,8CAAwC;AAAA,QACtC,YAAY;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,QAAM,WAAqC,CAAC;AAE5C,aAAW,YAAY,WAAW;AAChC,QAAI,CAAC,SAAS,gBAAiB;AAE/B,UAAM,cAAc,iBAAiB,IAAI,SAAS,eAAe;AACjE,QAAI,CAAC,YAAa;AAElB,UAAM,qBAAqB,YAAY;AACvC,QAAI,OAAO,uBAAuB,SAAU;AAE5C,UAAM,2BACJ,wCAAwC,IAAI,YAAY,eAAe;AACzE,QACE,4BACA,CAAC,yBAAyB,IAAI,SAAS,YAAY,GACnD;AACA;AAAA,IACF;AAEA,UAAM,oBAAoB,kBAAkB,QAAQ;AACpD,QAAI,qBAAqB,mBAAoB;AAE7C,aAAS,KAAK;AAAA,MACZ,MAAM;AAAA,MACN,+BAA+B,8BAA8B,SAAS,YAAY;AAAA,MAClF,cAAc;AAAA,MACd,SAAS,gBAAgB,kBAAkB,QAAQ,CAAC,CAAC,0BAA0B,kBAAkB;AAAA,MACjG,cAAc,SAAS;AAAA,MACvB,iBAAiB,YAAY;AAAA,MAC7B,eAAe,YAAY,yBAAyB,CAAC;AAAA,MACrD,qBAAqB;AAAA,MACrB,sBAAsB;AAAA,MACtB,eAAe,SAAS,iBAAiB,YAAY;AAAA,IACvD,CAAC;AAAA,EACH;AAEA,SAAO;AACT;;;ACjKO,IAAM,yBAAyB,CACpC,gBACoB;AACpB,QAAM,eAAe,YAAY;AAAA,IAC/B,CAAC,YAAoC,QAAQ,SAAS;AAAA,EACxD;AACA,QAAM,YAAY,YAAY;AAAA,IAC5B,CAAC,YAAiC,QAAQ,SAAS;AAAA,EACrD;AACA,QAAM,WAAW,YAAY;AAAA,IAC3B,CAAC,YAAgC,QAAQ,SAAS;AAAA,EACpD;AACA,QAAM,SAA0B,CAAC;AAEjC,aAAW,eAAe,cAAc;AACtC,UAAM,kBAAkB,YAAY;AACpC,QAAI,OAAO,oBAAoB,SAAU;AAEzC,UAAM,kBAAkB,UAAU;AAAA,MAChC,CAAC,aAAa,SAAS,oBAAoB,YAAY;AAAA,IACzD;AACA,QAAI,gBAAgB,WAAW,EAAG;AAElC,UAAM,iBAAiB,gBAAgB;AAAA,MACrC,CAAC,UAAU,aACT,WACA,SAAS,MAAM,OAAO,CAAC,eAAe,WAAW,eAAe,KAAK,EAClE;AAAA,MACL;AAAA,IACF;AACA,QAAI,kBAAkB,gBAAiB;AAEvC,UAAM,oBAAoB,SAAS;AAAA,MACjC,CAAC,YACC,QAAQ,mBAAmB,UAC3B,YAAY,0BAA0B,SAAS,QAAQ,cAAc;AAAA,IACzE;AACA,WAAO,KAAK;AAAA,MACV,MAAM;AAAA,MACN,oBAAoB,0BAA0B,YAAY,eAAe;AAAA,MACzE,YAAY;AAAA,MACZ,SAAS,kBAAkB,cAAc,wBAAwB,eAAe;AAAA,MAChF,cAAc,gBAAgB,CAAC,EAAG;AAAA,MAClC,iBAAiB,YAAY;AAAA,MAC7B,mBAAmB;AAAA,QACjB,GAAG,IAAI;AAAA,UACL,kBACG,IAAI,CAAC,YAAY,QAAQ,gBAAgB,EACzC;AAAA,YACC,CAAC,mBACC,mBAAmB;AAAA,UACvB;AAAA,QACJ;AAAA,MACF;AAAA,MACA,cAAc,kBAAkB,IAAI,CAAC,YAAY,QAAQ,WAAW;AAAA,MACpE,eACE,gBAAgB,CAAC,EAAG,iBAAiB,YAAY;AAAA,IACrD,CAAC;AAAA,EACH;AAEA,SAAO;AACT;;;ACtEA;AAAA,EACE,gBAAAK;AAAA,EACA,6BAAAC;AAAA,OACK;AAEP,SAAS,gBAAgB;AACzB;AAAA,EAEE,yCAAAC;AAAA,OACK;AAaA,SAAS,qBACd,aACA;AAAA,EACE;AAAA,EACA;AACF,IAA0D,CAAC,GAChC;AAC3B,QAAM,OAAO,QAAQ,WAAW;AAChC,MAAI,KAAK,SAAS,EAAG,QAAO,CAAC;AAE7B,QAAM,QAAQ,YAAY,WAAW;AACrC,mBACE,iBAAiB,OAAO,oCAAoC,KAC5D,iBAAiB;AACnB,cAAYC,uCAAsC,WAAW;AAC7D,QAAM,eAAe,IAAI,mBAA+B;AAAA,IACtD,SAAS;AAAA,IACT,WAAW;AAAA,IACX,OAAO,CAAC,QAAQC,cAAa,GAAG;AAAA,EAClC,CAAC;AAED,QAAM,SAAS,oBAAI,IAAqC;AAExD,aAAW,QAAQ,MAAM;AACvB,UAAM,SAASA,cAAa,IAAI;AAChC,UAAM,aAAa,aAAa;AAAA,MAC9B,aAAa,IAAI;AAAA,MACjB;AAAA,IACF;AAEA,eAAW,QAAQ,YAAY;AAC7B,YAAM,SAASA,cAAa,IAAI;AAChC,UAAI,WAAW,OAAQ;AACvB,UACE,CAAC,sBAAsB,IAAW,EAAE;AAAA,QAAK,CAAC,UACxC,sBAAsB,IAAW,EAAE,SAAS,KAAK;AAAA,MACnD,GACA;AACA;AAAA,MACF;AACA,UAAI,QAAQ,gBAAgB,QAAQ,MAAM,EAAG;AAE7C,YAAM,SAAS,CAAC,QAAQ,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG;AAC/C,YAAM,MAAM,eAAe,MAAM,IAAI;AACrC,UAAI,MAAM,WAAW,aAAe;AACpC,YAAM,UAAU,aAAa,IAAI;AACjC,YAAM,UAAU,aAAa,IAAI;AAEjC,YAAM,YAAqC;AAAA,QACzC,MAAM;AAAA,QACN,gCAAgC,qBAAqB,MAAM;AAAA,QAC3D,YAAY;AAAA,QACZ,SAAS,QAAQC,2BAA0B,aAAa,MAAM,CAAC,QAAQA,2BAA0B,aAAa,MAAM,CAAC,8BAA8B,SAAS,GAAG,CAAC,cAAc,SAAS,YAAa,CAAC;AAAA,QACrM,aAAa,CAAC,QAAQ,MAAM;AAAA,QAC5B,mBAAmB;AAAA,QACnB,kBAAkB;AAAA,QAClB,QAAQ;AAAA,UACN,IAAI,QAAQ,IAAI,QAAQ,KAAK;AAAA,UAC7B,IAAI,QAAQ,IAAI,QAAQ,KAAK;AAAA,QAC/B;AAAA,MACF;AAEA,UAAI,CAAC,OAAO,IAAI,MAAM,GAAG;AACvB,eAAO,IAAI,QAAQ,SAAS;AAAA,MAC9B;AAAA,IACF;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,OAAO,OAAO,CAAC;AACnC;;;AC3FA;AAAA,EACE,gBAAAC;AAAA,EACA,6BAAAC;AAAA,OACK;AAGP,SAAS,YAAAC,iBAAgB;AACzB;AAAA,EAEE,yCAAAC;AAAA,OACK;AAeA,SAAS,uBACd,aACA;AAAA,EACE;AAAA,EACA;AACF,IAA0D,CAAC,GAC9B;AAC7B,QAAM,OAAO,QAAQ,WAAW;AAChC,QAAM,WAAW,iBAAiB,WAAW;AAC7C,MAAI,KAAK,WAAW,KAAK,SAAS,WAAW,EAAG,QAAO,CAAC;AAExD,QAAM,QAAQ,YAAY,WAAW;AACrC,mBACE,iBAAiB,OAAO,iCAAiC,KACzD,iBAAiB;AACnB,cAAYC,wCAAsC,WAAW;AAC7D,QAAM,eAAe,IAAI,mBAA+B;AAAA,IACtD,SAAS;AAAA,IACT,WAAW;AAAA,IACX,OAAO,CAAC,QAAQC,cAAa,GAAG;AAAA,EAClC,CAAC;AAED,QAAM,SAAS,oBAAI,IAGjB;AACF,QAAM,qBAAqB,oBAAI,IAAY;AAE3C,aAAW,WAAW,UAAU;AAC9B,UAAM,aAAa,aAAa;AAAA,MAC9B,oBAAoB,OAAO;AAAA,MAC3B,eAAgB,QAAQ,YAAY;AAAA,IACtC;AAEA,eAAW,OAAO,YAAY;AAC5B,YAAM,QAAQA,cAAa,GAAG;AAC9B,UAAI,CAAC,sBAAsB,GAAU,EAAE,SAAS,QAAQ,KAAK,EAAG;AAChE,UAAI,QAAQ,gBAAgB,QAAQ,cAAc,KAAK,EAAG;AAC1D,YAAM,SAAS,GAAG,KAAK,IAAI,QAAQ,YAAY;AAC/C,YAAM,EAAE,IAAI,IAAI,0BAA0B,SAAS,GAAG;AACtD,UAAI,uBAAuB,GAAG,GAAG;AAC/B,eAAO,OAAO,MAAM;AACpB,2BAAmB,IAAI,MAAM;AAC7B;AAAA,MACF;AACA,UAAI,mBAAmB,IAAI,MAAM,EAAG;AACpC,UAAI,MAAM,WAAW,aAAe;AAEpC,YAAM,YAAuC;AAAA,QAC3C,MAAM;AAAA,QACN,kCAAkC,uBAAuB,MAAM;AAAA,QAC/D,YAAY;AAAA,QACZ,SAAS,OAAOC,2BAA0B,aAAa,KAAK,CAAC,cAAcA,2BAA0B,aAAa,QAAQ,YAAY,CAAC,8BAA8BC,UAAS,GAAG,CAAC,cAAcA,UAAS,YAAa,CAAC;AAAA,QACvN,YAAY;AAAA,QACZ,cAAc,QAAQ;AAAA,QACtB,mBAAmB;AAAA,QACnB,kBAAkB;AAAA,QAClB,QAAQ,eAAe,OAAO;AAAA,MAChC;AAEA,YAAM,UAAU,OAAO,IAAI,MAAM;AACjC,UAAI,CAAC,WAAW,MAAM,QAAQ,KAAK;AACjC,eAAO,IAAI,QAAQ,EAAE,OAAO,WAAW,IAAI,CAAC;AAAA,MAC9C;AAAA,IACF;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,OAAO,OAAO,CAAC,EAAE,IAAI,CAAC,EAAE,MAAM,MAAM,KAAK;AAC7D;;;AC7FA,SAAS,6BAAAC,kCAAiC;AAO1C,SAAS,YAAAC,iBAAgB;AACzB;AAAA,EAEE,yCAAAC;AAAA,OACK;AAUA,SAAS,uBACd,aACA;AAAA,EACE;AAAA,EACA;AACF,IAA0D,CAAC,GAC9B;AAC7B,QAAM,OAAO,YAAY,OAAO,CAAC,OAAO,GAAG,SAAS,SAAS;AAC7D,QAAM,WAAW,iBAAiB,WAAW;AAC7C,MAAI,KAAK,WAAW,KAAK,SAAS,WAAW,EAAG,QAAO,CAAC;AAExD,QAAM,QAAQ,YAAY,WAAW;AACrC,mBACE,iBAAiB,OAAO,iCAAiC,KACzD,iBAAiB;AACnB,cAAYC,wCAAsC,WAAW;AAC7D,QAAM,SAAS,oBAAI,IAGjB;AACF,QAAM,qBAAqB,oBAAI,IAAY;AAE3C,aAAW,OAAO,MAAM;AACtB,eAAW,WAAW,UAAU;AAC9B,UAAI,CAAC,sBAAsB,GAAG,EAAE,SAAS,QAAQ,KAAK,EAAG;AACzD,UAAI,QAAQ,gBAAgB,QAAQ,cAAc,IAAI,UAAU;AAC9D;AAEF,YAAM,SAAS,GAAG,IAAI,UAAU,IAAI,QAAQ,YAAY;AACxD,YAAM,EAAE,IAAI,IAAI,0BAA0B,SAAS,GAAG;AACtD,UAAI,uBAAuB,GAAG,GAAG;AAC/B,eAAO,OAAO,MAAM;AACpB,2BAAmB,IAAI,MAAM;AAC7B;AAAA,MACF;AACA,UAAI,mBAAmB,IAAI,MAAM,EAAG;AACpC,UAAI,MAAM,WAAW,aAAe;AAEpC,YAAM,YAAuC;AAAA,QAC3C,MAAM;AAAA,QACN,kCAAkC,uBAAuB,MAAM;AAAA,QAC/D,YAAY;AAAA,QACZ,SAAS,OAAOC,2BAA0B,aAAa,IAAI,UAAU,CAAC,cAAcA,2BAA0B,aAAa,QAAQ,YAAY,CAAC,8BAA8BC,UAAS,GAAG,CAAC,cAAcA,UAAS,YAAa,CAAC;AAAA,QAChO,YAAY,IAAI;AAAA,QAChB,cAAc,QAAQ;AAAA,QACtB,mBAAmB;AAAA,QACnB,kBAAkB;AAAA,QAClB,QAAQ,eAAe,OAAO;AAAA,MAChC;AAEA,YAAM,UAAU,OAAO,IAAI,MAAM;AACjC,UAAI,CAAC,WAAW,MAAM,QAAQ,KAAK;AACjC,eAAO,IAAI,QAAQ,EAAE,OAAO,WAAW,IAAI,CAAC;AAAA,MAC9C;AAAA,IACF;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,OAAO,OAAO,CAAC,EAAE,IAAI,CAAC,EAAE,MAAM,MAAM,KAAK;AAC7D;;;AC/EA;AAAA,EACE,gBAAAC;AAAA,EACA,6BAAAC;AAAA,OACK;AAOP,SAAS,YAAAC,iBAAgB;AACzB;AAAA,EAEE,yCAAAC;AAAA,OACK;AAYA,SAAS,qBACd,aACA;AAAA,EACE;AAAA,EACA;AACF,IAA0D,CAAC,GAChC;AAC3B,QAAM,OAAO,YAAY;AAAA,IACvB,CAAC,YAA+B,QAAQ,SAAS;AAAA,EACnD;AACA,QAAM,OAAO,QAAQ,WAAW;AAChC,MAAI,KAAK,WAAW,KAAK,KAAK,WAAW,EAAG,QAAO,CAAC;AAEpD,QAAM,QAAQ,YAAY,WAAW;AACrC,QAAM,oBACJ,gBACA,iBAAiB,OAAO,oCAAoC,KAC5D,iBAAiB;AACnB,cAAYC,wCAAsC,WAAW;AAE7D,QAAM,WAAW,IAAI,mBAA+B;AAAA,IAClD,SAAS;AAAA,IACT,WAAW;AAAA,IACX,OAAOC;AAAA,EACT,CAAC;AACD,QAAM,SAAoC,CAAC;AAE3C,aAAW,OAAO,MAAM;AACtB,UAAM,aAAa,SAAS;AAAA,MAC1B,aAAa,GAAG;AAAA,MAChB;AAAA,IACF;AAEA,eAAW,OAAO,YAAY;AAC5B,YAAM,QAAQA,cAAa,GAAG;AAC9B,UACE,CAAC,sBAAsB,GAAG,EAAE;AAAA,QAAK,CAAC,UAChC,sBAAsB,GAAG,EAAE,SAAS,KAAK;AAAA,MAC3C,GACA;AACA;AAAA,MACF;AACA,UAAI,QAAQ,gBAAgB,IAAI,YAAY,KAAK,EAAG;AAEpD,YAAM,MAAM,eAAe,KAAK,GAAG;AACnC,UAAI,MAAM,WAAW,kBAAmB;AAExC,YAAM,YAAY,aAAa,GAAG;AAClC,YAAM,YAAY,aAAa,GAAG;AAClC,aAAO,KAAK;AAAA,QACV,MAAM;AAAA,QACN,gCAAgC,qBAAqB,IAAI,UAAU,IAAI,KAAK;AAAA,QAC5E,YAAY;AAAA,QACZ,SAAS,OAAOC,2BAA0B,aAAa,IAAI,UAAU,CAAC,YAAYA,2BAA0B,aAAa,KAAK,CAAC,8BAA8BC,UAAS,GAAG,CAAC,cAAcA,UAAS,iBAAiB,CAAC;AAAA,QACnN,aAAa,CAAC,IAAI,YAAY,KAAK;AAAA,QACnC,mBAAmB;AAAA,QACnB,kBAAkB;AAAA,QAClB,QAAQ;AAAA,UACN,IAAI,UAAU,IAAI,UAAU,KAAK;AAAA,UACjC,IAAI,UAAU,IAAI,UAAU,KAAK;AAAA,QACnC;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;;;AC5FA,SAAS,gBAAAC,qBAAoB;AAE7B,SAAS,yCAAAC,+CAA6C;AAY/C,SAAS,gBACd,aACqB;AACrB,QAAM,QAAQ,YAAY,WAAW;AACrC,MACE,SACA,2BAA2B,SAC3B,MAAM,0BAA0B,MAChC;AACA,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,OAAO,YAAY;AAAA,IACvB,CAAC,YAA+B,QAAQ,SAAS;AAAA,EACnD;AACA,QAAM,OAAO,QAAQ,WAAW;AAChC,MAAI,KAAK,WAAW,KAAK,KAAK,WAAW,EAAG,QAAO,CAAC;AACpD,QAAM,UAAUC,wCAAsC,WAAW;AAEjE,QAAM,cAAc,IAAI;AAAA,IACtB,KAAK,IAAI,CAAC,KAAK,UAAU,CAACC,cAAa,GAAG,GAAG,KAAK,CAAC;AAAA,EACrD;AACA,QAAM,WAAW,IAAI,mBAA+B;AAAA,IAClD,SAAS;AAAA,IACT,WAAW;AAAA,IACX,OAAOA;AAAA,EACT,CAAC;AACD,QAAM,SAA8B,CAAC;AAErC,aAAW,OAAO,MAAM;AACtB,UAAM,aAAa,SAAS,mBAAmB,aAAa,GAAG,CAAC;AAEhE,eAAW,OAAO,YAAY;AAC5B,YAAM,QAAQA,cAAa,GAAG;AAC9B,YAAM,YAAY,sBAAsB,GAAG;AAC3C,YAAM,YAAY,sBAAsB,GAAG;AAC3C,UAAI,CAAC,UAAU,KAAK,CAAC,UAAU,UAAU,SAAS,KAAK,CAAC,EAAG;AAC3D,UAAI,QAAQ,gBAAgB,IAAI,YAAY,KAAK,EAAG;AACpD,UAAI,eAAe,KAAK,GAAG,IAAI,EAAG;AAElC,YAAM,aAAa,YAAY,IAAI,KAAK,KAAK;AAC7C,YAAM,UAAU;AAAA,QACd;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAEA,aAAO,KAAK;AAAA,QACV,MAAM;AAAA,QACN,wBAAwB,cAAc,IAAI,UAAU,IAAI,KAAK;AAAA,QAC7D,YAAY;AAAA,QACZ,SAAS,kBAAkB,IAAI,EAAE,QAAQ,CAAC,CAAC,OAAO,IAAI,EAAE,QAAQ,CAAC,CAAC,gBAAgB,OAAO;AAAA,QACzF,eAAe,IAAI,iBAAiB,IAAI;AAAA,MAC1C,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;;;ACzDO,IAAM,qBAAqB,CAChC,WACQ;AACR,QAAM,8BAA8B,oBAAI,IAAY;AAEpD,aAAW,SAAS,QAAuB;AACzC,QACE,MAAM,SAAS,mCACf,OAAO,MAAM,iBAAiB,YAC9B,OAAO,MAAM,eAAe,UAC5B;AACA,kCAA4B;AAAA,QAC1B,WAAW,MAAM,YAAY,IAAI,MAAM,UAAU;AAAA,MACnD;AAAA,IACF;AAEA,QACE,MAAM,SAAS,mCACf,OAAO,MAAM,iBAAiB,YAC9B,OAAO,MAAM,eAAe,UAC5B;AACA,kCAA4B;AAAA,QAC1B,WAAW,MAAM,YAAY,IAAI,MAAM,UAAU;AAAA,MACnD;AAAA,IACF;AAAA,EACF;AAEA,SAAO,OAAO,OAAO,CAAC,YAAY;AAChC,UAAM,QAAQ;AACd,WAAO,EACL,MAAM,SAAS,qBACf,OAAO,MAAM,uBAAuB,YACpC,4BAA4B,IAAI,MAAM,kBAAkB;AAAA,EAE5D,CAAC;AACH;;;ACzBO,SAAS,wBACd,aACiC;AACjC,QAAM,SAA0C,CAAC;AAGjD,QAAM,mBAAmB,YAAY;AAAA,IACnC,CAAC,OACC,yBAAyB,OACxB,GAAG,SAAS,sBAAsB,GAAG,KAAK,WAAW,gBAAgB;AAAA,EAC1E;AACA,QAAM,cAAc,YAAY;AAAA,IAC9B,CAAC,OAAyB,GAAG,SAAS;AAAA,EACxC;AACA,QAAM,eAAe,YAAY;AAAA,IAC/B,CAAC,OAA0B,GAAG,SAAS;AAAA,EACzC;AAGA,QAAM,mBAAmB,oBAAI,IAAY;AACzC,aAAW,SAAS,cAAc;AAChC,eAAW,UAAU,MAAM,6BAA6B,CAAC,GAAG;AAC1D,uBAAiB,IAAI,MAAM;AAAA,IAC7B;AAAA,EACF;AAGA,QAAM,+BAA+B,oBAAI,IAAwB;AACjE,aAAW,aAAa,kBAAkB;AACxC,QACE,0CAA0C,aAC1C,UAAU,sCACV;AACA,mCAA6B;AAAA,QAC3B,UAAU;AAAA,QACV,UAAU;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AAGA,aAAW,kBAAkB,6BAA6B,OAAO,GAAG;AAClE,eAAW,SAAS,gBAAgB;AAClC,UAAI,MAAM,KAAK,CAAC,WAAW,iBAAiB,IAAI,MAAM,CAAC,GAAG;AACxD,mBAAW,UAAU,OAAO;AAC1B,2BAAiB,IAAI,MAAM;AAAA,QAC7B;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,aAAW,QAAQ,aAAa;AAC9B,QAAI,KAAK,sBAAsB,MAAM;AACnC,UAAI,CAAC,iBAAiB,IAAI,KAAK,cAAc,GAAG;AAC9C,cAAM,YAAY,iBAAiB;AAAA,UACjC,CAAC,MAAM,EAAE,wBAAwB,KAAK;AAAA,QACxC;AACA,cAAM,gBAAgB,WAAW,QAAQ;AAEzC,eAAO,KAAK;AAAA,UACV,MAAM;AAAA,UACN,uCAAuC,sCAAsC,KAAK,cAAc;AAAA,UAChG,YAAY;AAAA,UACZ,SAAS,QAAQ,KAAK,IAAI,OAAO,aAAa;AAAA,UAC9C,qBAAqB,KAAK,uBAAuB;AAAA,UACjD,gBAAgB,KAAK;AAAA,UACrB,eAAe,KAAK;AAAA,QACtB,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;ACnGA,SAAS,OAAAC,YAAW;AASpB,IAAM,qBAAqB;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,SAAS,mBAAmB,MAA2B;AACrD,SAAO,mBAAmB,KAAK,CAAC,QAAQ,KAAK,GAAG,MAAM,MAAS;AACjE;AAOO,SAAS,yCACd,aAC4C;AAC5C,QAAM,WAAuD,CAAC;AAC9D,QAAM,KAAKA,KAAI,WAAW;AAE1B,QAAM,mBAAmB,GAAG,iBAAiB,KAAK;AAClD,QAAM,cAAc,GAAG,YAAY,KAAK;AAExC,QAAM,mBAAmB,oBAAI,IAA0B;AACvD,aAAW,QAAQ,aAAa;AAC9B,QAAI,CAAC,KAAK,oBAAqB;AAC/B,UAAM,WAAW,iBAAiB,IAAI,KAAK,mBAAmB,KAAK,CAAC;AACpE,aAAS,KAAK,IAAI;AAClB,qBAAiB,IAAI,KAAK,qBAAqB,QAAQ;AAAA,EACzD;AAEA,aAAW,aAAa,kBAAkB;AACxC,QAAI,UAAU,UAAU,cAAe;AAEvC,UAAM,iBACJ,iBAAiB,IAAI,UAAU,mBAAmB,KAAK,CAAC;AAC1D,QAAI,eAAe,WAAW,EAAG;AAEjC,UAAM,4BAA4B,eAAe;AAAA,MAAK,CAAC,SACrD,mBAAmB,IAAI;AAAA,IACzB;AAEA,QAAI,0BAA2B;AAE/B,aAAS,KAAK;AAAA,MACZ,MAAM;AAAA,MACN,iDAAiD,gDAAgD,UAAU,mBAAmB;AAAA,MAC9H,cAAc;AAAA,MACd,SAAS,eAAe,UAAU,IAAI;AAAA,MACtC,qBAAqB,UAAU;AAAA,MAC/B,iBAAiB,eAAe,IAAI,CAAC,SAAS,KAAK,cAAc;AAAA,MACjE,eAAe,eAAe,CAAC,GAAG;AAAA,IACpC,CAAC;AAAA,EACH;AAEA,SAAO;AACT;;;ACpGA,SAAS,OAAAC,YAAW;;;ACQb,IAAM,iCAAiC,CAC5C,WACA,UAEA,UAAU,UAAU,iBACpB,MAAM,OAAO,CAAC,SAAS,KAAK,mBAAmB,IAAI,EAAE,UAAU;;;ADA1D,SAAS,uBACd,aACkC;AAClC,QAAM,WAA6C,CAAC;AACpD,QAAM,KAAKC,KAAI,WAAW;AAE1B,QAAM,mBAAmB,GAAG,iBAAiB,KAAK;AAClD,QAAM,cAAc,GAAG,YAAY,KAAK;AAExC,QAAM,mBAAmB,oBAAI,IAA0B;AACvD,aAAW,QAAQ,aAAa;AAC9B,QAAI,CAAC,KAAK,oBAAqB;AAC/B,UAAM,WAAW,iBAAiB,IAAI,KAAK,mBAAmB,KAAK,CAAC;AACpE,aAAS,KAAK,IAAI;AAClB,qBAAiB,IAAI,KAAK,qBAAqB,QAAQ;AAAA,EACzD;AAEA,aAAW,aAAa,kBAAkB;AACxC,UAAM,iBACJ,iBAAiB,IAAI,UAAU,mBAAmB,KAAK,CAAC;AAC1D,QAAI,CAAC,+BAA+B,WAAW,cAAc,EAAG;AAEhE,UAAM,sBAAsB,eAAe;AAAA,MACzC,CAAC,SAAS,KAAK,mBAAmB;AAAA,IACpC;AACA,QAAI,oBAAqB;AAEzB,aAAS,KAAK;AAAA,MACZ,MAAM;AAAA,MACN,wCAAwC,uCAAuC,UAAU,mBAAmB;AAAA,MAC5G,cAAc;AAAA,MACd,SAAS,GAAG,UAAU,IAAI;AAAA,MAC1B,qBAAqB,UAAU;AAAA,MAC/B,iBAAiB,eAAe,IAAI,CAAC,SAAS,KAAK,cAAc;AAAA,MACjE,eAAe,eAAe,CAAC,GAAG;AAAA,IACpC,CAAC;AAAA,EACH;AAEA,SAAO;AACT;;;AEpDA,SAAS,OAAAC,YAAW;AAab,SAAS,wBACd,aACmC;AACnC,QAAM,WAA8C,CAAC;AACrD,QAAM,KAAKC,KAAI,WAAW;AAE1B,QAAM,mBAAmB,GAAG,iBAAiB,KAAK;AAClD,QAAM,cAAc,GAAG,YAAY,KAAK;AAExC,QAAM,mBAAmB,oBAAI,IAA0B;AACvD,aAAW,QAAQ,aAAa;AAC9B,QAAI,CAAC,KAAK,oBAAqB;AAC/B,UAAM,WAAW,iBAAiB,IAAI,KAAK,mBAAmB,KAAK,CAAC;AACpE,aAAS,KAAK,IAAI;AAClB,qBAAiB,IAAI,KAAK,qBAAqB,QAAQ;AAAA,EACzD;AAEA,aAAW,aAAa,kBAAkB;AACxC,UAAM,iBACJ,iBAAiB,IAAI,UAAU,mBAAmB,KAAK,CAAC;AAC1D,QAAI,CAAC,+BAA+B,WAAW,cAAc,EAAG;AAEhE,UAAM,uBAAuB,eAAe;AAAA,MAC1C,CAAC,SAAS,KAAK,oBAAoB;AAAA,IACrC;AACA,QAAI,qBAAsB;AAE1B,aAAS,KAAK;AAAA,MACZ,MAAM;AAAA,MACN,yCAAyC,wCAAwC,UAAU,mBAAmB;AAAA,MAC9G,cAAc;AAAA,MACd,SAAS,GAAG,UAAU,IAAI;AAAA,MAC1B,qBAAqB,UAAU;AAAA,MAC/B,iBAAiB,eAAe,IAAI,CAAC,SAAS,KAAK,cAAc;AAAA,MACjE,eAAe,eAAe,CAAC,GAAG;AAAA,IACpC,CAAC;AAAA,EACH;AAEA,SAAO;AACT;;;AC3CA,IAAM,sBAAsB;AAC5B,IAAM,uCAAuC;AAC7C,IAAM,2BAA2B;AAS1B,SAAS,gDACd,aACoC;AACpC,QAAM,sBAAsB,YAAY;AAAA,IACtC,CAAC,YACC,QAAQ,SAAS;AAAA,EACrB;AACA,QAAM,iBAAiB,YAAY;AAAA,IACjC,CAAC,YAAsC,QAAQ,SAAS;AAAA,EAC1D;AACA,QAAM,mBAAmB,YAAY;AAAA,IACnC,CAAC,YACC,QAAQ,SAAS;AAAA,EACrB;AAEA,QAAM,sBAAsB,IAAI;AAAA,IAC9B,iBAAiB,IAAI,CAAC,cAAc;AAAA,MAClC,UAAU;AAAA,MACV;AAAA,IACF,CAAC;AAAA,EACH;AACA,QAAM,qBAAqB,oBAAI,IAA6B;AAE5D,aAAW,QAAQ,gBAAgB;AACjC,QAAI,CAAC,KAAK,uBAAwB;AAClC,UAAM,iBACJ,mBAAmB,IAAI,KAAK,sBAAsB,KAAK,CAAC;AAC1D,mBAAe,KAAK,IAAI;AACxB,uBAAmB,IAAI,KAAK,wBAAwB,cAAc;AAAA,EACpE;AAEA,QAAM,WAA+C,CAAC;AAEtD,aAAW,aAAa,qBAAqB;AAC3C,QAAI,CAAC,UAAU,oBAAoB,UAAU,KAAK,UAAU,EAAG;AAE/D,UAAM,aACJ,mBAAmB,IAAI,UAAU,sBAAsB,KAAK,CAAC,GAC7D;AAAA,MACA,CAAC,SACC,KAAK,sBAAsB,UAAU,KAAK,sBAAsB;AAAA,IACpE;AAGA,QAAI,UAAU,SAAS,EAAG;AAE1B,UAAM,QAAQ,UAAU,IAAI,CAAC,SAAS,KAAK,OAAO,CAAC;AACnD,UAAM,cAAc,KAAK,IAAI,GAAG,KAAK;AACrC,UAAM,aAAa,KAAK,IAAI,GAAG,KAAK;AACpC,UAAM,gBAAgB,UAAU,OAAO,IAAI,UAAU,KAAK,SAAS;AACnE,UAAM,mBAAmB,UAAU,OAAO,IAAI,UAAU,KAAK,SAAS;AACtE,UAAM,aAAa,UAAU,eAAe;AAC5C,UAAM,iBAAiB,aAAa;AACpC,UAAM,gBAA8C;AAAA,MAClD,KAAK,gBAAgB;AAAA,MACrB,QAAQ,aAAa;AAAA,IACvB;AAEA,UAAM,kBAAkB,UAAU,sBAC9B,oBAAoB,IAAI,UAAU,mBAAmB,IACrD;AACJ,UAAM,gBACJ,iBAAiB,QAAQ,UAAU;AAErC,eAAW,QAAQ,CAAC,OAAO,QAAQ,GAAY;AAC7C,YAAM,UAAU,cAAc,IAAI;AAClC,UACE,WAAW,iBAAiB,4BAC5B,WAAW,GACX;AACA;AAAA,MACF;AAEA,YAAM,mBAAmB,SAAS,QAAQ,UAAU;AACpD,YAAM,mBAAmB,aAAa,IAAI;AAE1C,eAAS,KAAK;AAAA,QACZ,MAAM;AAAA,QACN,wCAAwC,uCAAuC,UAAU,sBAAsB,IAAI,gBAAgB;AAAA,QACnI,cAAc;AAAA,QACd,SAAS,GAAG,aAAa,8BAA8B,gBAAgB,cAAc,QAAQ,QAAQ,CAAC,CAAC,iBAAiB,oCAAoC;AAAA,QAC5J,wBAAwB,UAAU;AAAA,QAClC,oBAAoB;AAAA,QACpB,oBAAoB,UAAU,IAAI,CAAC,SAAS,KAAK,iBAAiB;AAAA,QAClE,qBAAqB,UAAU;AAAA,QAC/B,oBAAoB,UAAU;AAAA,QAC9B,eAAe,UAAU;AAAA,MAC3B,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;;;ACvGA,IAAM,gCAAgC,CAAC,SACrC,4BAA4B,KAAK,IAAI;AAEvC,IAAM,8BAA8B,CAClC,eACA,uBACG;AACH,QAAM,EAAE,QAAQ,KAAK,IAAI;AACzB,QAAM,YAAY;AAElB,SACE,cAAc,SAAS,KAAK,OAAO,IAAI,KAAK,QAAQ,IAAI,aACxD,cAAc,SAAS,KAAK,OAAO,IAAI,KAAK,QAAQ,IAAI,aACxD,cAAc,SAAS,KAAK,OAAO,IAAI,KAAK,SAAS,IAAI,aACzD,cAAc,SAAS,KAAK,OAAO,IAAI,KAAK,SAAS,IAAI;AAE7D;AAMO,SAAS,sDACd,aACoC;AACpC,QAAM,sBAAsB,YAAY;AAAA,IACtC,CAAC,YACC,QAAQ,SAAS;AAAA,EACrB;AACA,QAAM,mBAAmB,YAAY;AAAA,IACnC,CAAC,YACC,QAAQ,SAAS;AAAA,EACrB;AACA,QAAM,iBAAiB,YAAY;AAAA,IACjC,CAAC,YAAsC,QAAQ,SAAS;AAAA,EAC1D;AAEA,QAAM,sBAAsB,IAAI;AAAA,IAC9B,iBAAiB,IAAI,CAAC,cAAc;AAAA,MAClC,UAAU;AAAA,MACV;AAAA,IACF,CAAC;AAAA,EACH;AACA,QAAM,6BAA6B,oBAAI,IAAyB;AAChE,QAAM,oBAAqC,CAAC;AAE5C,aAAW,iBAAiB,gBAAgB;AAC1C,QAAI,CAAC,cAAc,wBAAwB;AACzC,UAAI,cAAc,qBAAqB;AACrC,0BAAkB,KAAK,aAAa;AAAA,MACtC;AACA;AAAA,IACF;AAEA,UAAM,iBACJ,2BAA2B,IAAI,cAAc,sBAAsB,KACnE,oBAAI,IAAY;AAClB,mBAAe,IAAI,cAAc,KAAK,KAAK,CAAC;AAC5C,+BAA2B;AAAA,MACzB,cAAc;AAAA,MACd;AAAA,IACF;AAAA,EACF;AAEA,QAAM,WAA+C,CAAC;AAEtD,aAAW,sBAAsB,qBAAqB;AACpD,QAAI,CAAC,mBAAmB,oBAAqB;AAE7C,UAAM,kBAAkB,oBAAoB;AAAA,MAC1C,mBAAmB;AAAA,IACrB;AACA,QAAI,CAAC,gBAAiB;AAEtB,UAAM,uBAAuB,IAAI;AAAA,MAC/B,CAAC,gBAAgB,MAAM,gBAAgB,YAAY,EAChD,IAAI,CAAC,SAAS,MAAM,KAAK,CAAC,EAC1B,OAAO,CAAC,SAAyB,QAAQ,IAAI,CAAC;AAAA,IACnD;AACA,UAAM,iCAAiC,CAAC,GAAG,oBAAoB,EAAE;AAAA,MAC/D,CAAC,wBACC,CAAC,8BAA8B,mBAAmB;AAAA,IACtD;AACA,UAAM,iBAAiB,2BAA2B;AAAA,MAChD,mBAAmB;AAAA,IACrB;AACA,UAAM,6BACJ,CAAC,GAAG,oBAAoB,EAAE;AAAA,MAAK,CAAC,wBAC9B,gBAAgB,IAAI,mBAAmB;AAAA,IACzC,KACA,kBAAkB;AAAA,MAChB,CAAC,kBACC,qBAAqB,IAAI,cAAc,KAAK,KAAK,CAAC,KAClD,4BAA4B,eAAe,kBAAkB;AAAA,IACjE;AAEF,QAAI,kCAAkC,4BAA4B;AAChE;AAAA,IACF;AAEA,UAAM,wBACJ,kCAAkC;AAEpC,aAAS,KAAK;AAAA,MACZ,MAAM;AAAA,MACN,wCAAwC,uCAAuC,mBAAmB,sBAAsB;AAAA,MACxH,cAAc;AAAA,MACd,SAAS,GAAG,qBAAqB;AAAA,MACjC,wBAAwB,mBAAmB;AAAA,MAC3C,oBAAoB;AAAA,MACpB,qBAAqB,mBAAmB;AAAA,MACxC,oBAAoB,mBAAmB;AAAA,MACvC,eAAe,mBAAmB;AAAA,IACpC,CAAC;AAAA,EACH;AAEA,SAAO;AACT;;;ACrHA,IAAMC,4BAA2B;AAEjC,IAAM,eAAe,CAAC,SACpB,KAAK,qBAAqB,OAAO,KAAK,UAAU;AAO3C,SAAS,wCACd,aACoC;AACpC,QAAM,sBAAsB,YAAY;AAAA,IACtC,CAAC,YACC,QAAQ,SAAS;AAAA,EACrB;AACA,QAAM,iBAAiB,YAAY;AAAA,IACjC,CAAC,YAAsC,QAAQ,SAAS;AAAA,EAC1D;AACA,QAAM,mBAAmB,YAAY;AAAA,IACnC,CAAC,YACC,QAAQ,SAAS;AAAA,EACrB;AAEA,QAAM,sBAAsB,IAAI;AAAA,IAC9B,iBAAiB,IAAI,CAAC,cAAc;AAAA,MAClC,UAAU;AAAA,MACV;AAAA,IACF,CAAC;AAAA,EACH;AACA,QAAM,qBAAqB,oBAAI,IAA6B;AAE5D,aAAW,QAAQ,gBAAgB;AACjC,QAAI,CAAC,KAAK,uBAAwB;AAClC,UAAM,iBACJ,mBAAmB,IAAI,KAAK,sBAAsB,KAAK,CAAC;AAC1D,mBAAe,KAAK,IAAI;AACxB,uBAAmB,IAAI,KAAK,wBAAwB,cAAc;AAAA,EACpE;AAEA,QAAM,WAA+C,CAAC;AAEtD,aAAW,aAAa,qBAAqB;AAC3C,QACE,UAAU,qBAAqB,SAC/B,UAAU,KAAK,SAAS,KACxB,UAAU,KAAK,UAAU,GACzB;AACA;AAAA,IACF;AAEA,UAAM,iBAAiB,UAAU,OAAO,IAAI,UAAU,KAAK,QAAQ;AACnE,UAAM,kBAAkB,UAAU,OAAO,IAAI,UAAU,KAAK,QAAQ;AACpE,UAAM,mBAAmB,UAAU,OAAO,IAAI,UAAU,KAAK,SAAS;AACtE,UAAM,gBAAgB,UAAU,OAAO,IAAI,UAAU,KAAK,SAAS;AACnE,UAAM,iBACJ,mBAAmB,IAAI,UAAU,sBAAsB,KAAK,CAAC;AAE/D,UAAM,mBAAmB,eACtB,OAAO,CAAC,SAAS;AAChB,UACE,KAAK,sBAAsB,UAC3B,KAAK,sBAAsB,SAC3B;AACA,eACE,KAAK,OAAO,IAAI,mBAAmBA,6BACnC,KAAK,OAAO,IAAI,gBAAgBA;AAAA,MAEpC;AAEA,UACE,KAAK,sBAAsB,SAC3B,KAAK,sBAAsB,UAC3B;AACA,eACE,KAAK,OAAO,IAAI,iBAAiBA,6BACjC,KAAK,OAAO,IAAI,kBAAkBA;AAAA,MAEtC;AAEA,aAAO;AAAA,IACT,CAAC,EACA,KAAK,CAAC,OAAO,UAAU;AACtB,YAAM,kBACJ,MAAM,sBAAsB,UAC5B,MAAM,sBAAsB;AAC9B,YAAM,kBACJ,MAAM,sBAAsB,UAC5B,MAAM,sBAAsB;AAE9B,UAAI,mBAAmB,iBAAiB;AACtC,eAAO,MAAM,OAAO,IAAI,MAAM,OAAO;AAAA,MACvC;AACA,UAAI,CAAC,mBAAmB,CAAC,iBAAiB;AACxC,eAAO,MAAM,OAAO,IAAI,MAAM,OAAO;AAAA,MACvC;AACA,aAAO,kBAAkB,KAAK;AAAA,IAChC,CAAC;AAEH,QAAI,iBAAiB,WAAW,EAAG;AAEnC,UAAM,iBAAiB,KAAK;AAAA,MAC1B,UAAU,KAAK;AAAA,MACf,GAAG,iBACA;AAAA,QACC,CAAC,SACC,KAAK,sBAAsB,UAC3B,KAAK,sBAAsB;AAAA,MAC/B,EACC,IAAI,CAAC,SAAS,IAAI,KAAK,IAAI,KAAK,OAAO,IAAI,UAAU,OAAO,CAAC,CAAC;AAAA,IACnE;AACA,UAAM,gBAAgB,KAAK;AAAA,MACzB,UAAU,KAAK;AAAA,MACf,GAAG,iBACA;AAAA,QACC,CAAC,SACC,KAAK,sBAAsB,SAC3B,KAAK,sBAAsB;AAAA,MAC/B,EACC,IAAI,CAAC,SAAS,IAAI,KAAK,IAAI,KAAK,OAAO,IAAI,UAAU,OAAO,CAAC,CAAC;AAAA,IACnE;AAEA,UAAM,4BAAsC,CAAC;AAC7C,QAAI,iBAAiB,UAAU,KAAK,SAASA,2BAA0B;AACrE,gCAA0B;AAAA,QACxB,kCAAkC,eAAe,QAAQ,CAAC,CAAC;AAAA,MAC7D;AAAA,IACF;AACA,QAAI,gBAAgB,UAAU,KAAK,QAAQA,2BAA0B;AACnE,gCAA0B;AAAA,QACxB,iCAAiC,cAAc,QAAQ,CAAC,CAAC;AAAA,MAC3D;AAAA,IACF;AAEA,UAAM,kBAAkB,UAAU,sBAC9B,oBAAoB,IAAI,UAAU,mBAAmB,IACrD;AACJ,UAAM,gBACJ,iBAAiB,QAAQ,UAAU;AACrC,UAAM,aAAa,iBAAiB,IAAI,YAAY,EAAE,KAAK,IAAI;AAE/D,aAAS,KAAK;AAAA,MACZ,MAAM;AAAA,MACN,wCAAwC,uCAAuC,UAAU,sBAAsB;AAAA,MAC/G,cAAc;AAAA,MACd,SAAS,GAAG,aAAa,yCAAyC,UAAU,MAAM,0BAA0B,KAAK,OAAO,CAAC;AAAA,MACzH,wBAAwB,UAAU;AAAA,MAClC,oBAAoB;AAAA,MACpB,oBAAoB,iBAAiB;AAAA,QACnC,CAAC,SAAS,KAAK;AAAA,MACjB;AAAA,MACA,qBAAqB,UAAU;AAAA,MAC/B,oBAAoB,UAAU;AAAA,MAC9B,eAAe,UAAU;AAAA,IAC3B,CAAC;AAAA,EACH;AAEA,SAAO;AACT;;;ACxKA,SAAS,sBAAsB;AAW/B,SAAS,yCACP,WACwB;AACxB,UAAQ,UAAU,qBAAqB;AAAA,IACrC,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAEA,SAAS,mBAAmB,WAAiD;AAC3E,MAAI,UAAU,qBAAqB;AACjC,WAAO,yCAAyC,SAAS;AAAA,EAC3D;AAEA,MAAI,CAAC,UAAU,UAAU,CAAC,UAAU,uBAAwB,QAAO;AAEnE,QAAM,KAAK,UAAU,uBAAuB,IAAI,UAAU,OAAO;AACjE,QAAM,KAAK,UAAU,uBAAuB,IAAI,UAAU,OAAO;AAEjE,MAAI,KAAK,IAAI,EAAE,IAAI,QAAQ,KAAK,IAAI,EAAE,IAAI,KAAM,QAAO;AAEvD,MAAI,KAAK,IAAI,EAAE,KAAK,KAAK,IAAI,EAAE,GAAG;AAChC,WAAO,MAAM,IAAI,OAAO;AAAA,EAC1B;AAEA,SAAO,MAAM,IAAI,OAAO;AAC1B;AAEA,SAAS,8BACP,WACA,QACwB;AACxB,MAAI,CAAC,UAAU,OAAQ,QAAO;AAE9B,QAAM,YAAY;AAAA,IAChB,EAAE,WAAW,MAAe,UAAU,UAAU,OAAO,IAAI,OAAO,KAAK;AAAA,IACvE,EAAE,WAAW,MAAe,UAAU,OAAO,OAAO,UAAU,OAAO,EAAE;AAAA,IACvE,EAAE,WAAW,MAAe,UAAU,UAAU,OAAO,IAAI,OAAO,KAAK;AAAA,IACvE,EAAE,WAAW,MAAe,UAAU,OAAO,OAAO,UAAU,OAAO,EAAE;AAAA,EACzE;AAEA,YAAU,KAAK,CAAC,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ;AAChD,SAAO,UAAU,CAAC,GAAG,aAAa;AACpC;AAEO,SAAS,oCACd,aACiD;AACjD,QAAM,QAAQ,YAAY;AAAA,IACxB,CAAC,OAAuB,GAAG,SAAS;AAAA,EACtC;AACA,MAAI,CAAC,MAAO,QAAO,CAAC;AAEpB,QAAM,UAAU,MAAM;AACpB,QAAI;AACF,aAAO,eAAe,KAAK;AAAA,IAC7B,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF,GAAG;AACH,MAAI,CAAC,OAAQ,QAAO,CAAC;AAErB,QAAM,WAA4D,CAAC;AAEnE,QAAM,aAAa,YAAY;AAAA,IAC7B,CAAC,OAA2B,GAAG,SAAS;AAAA,EAC1C;AAEA,aAAW,aAAa,YAAY;AAClC,UAAM,kBAAkB,mBAAmB,SAAS;AACpD,UAAM,6BAA6B;AAAA,MACjC;AAAA,MACA;AAAA,IACF;AAEA,QAAI,CAAC,mBAAmB,CAAC,2BAA4B;AACrD,QAAI,oBAAoB,2BAA4B;AAEpD,UAAM,gBAAgB;AAAA,MACpB;AAAA,MACA,UAAU;AAAA,IACZ;AAEA,aAAS,KAAK;AAAA,MACZ,MAAM;AAAA,MACN,cAAc;AAAA,MACd,wDAAwD,uDAAuD,UAAU,gBAAgB;AAAA,MACzI,SAAS,GAAG,aAAa,cAAc,eAAe,oBAAoB,0BAA0B;AAAA,MACpG,kBAAkB,UAAU;AAAA,MAC5B,qBAAqB,UAAU;AAAA,MAC/B,cAAc,MAAM;AAAA,MACpB,kBAAkB;AAAA,MAClB,8BAA8B;AAAA,MAC9B,eAAe,UAAU;AAAA,IAC3B,CAAC;AAAA,EACH;AAEA,SAAO;AACT;;;ACxHA;AAAA,EACE;AAAA,EACA,wBAAAC;AAAA,OACK;AAcP,SAAS,oBAAoB,IAAkD;AAC7E,MAAI,GAAG,SAAS,sBAAsB;AACpC,UAAM,KAAK,GAAG,QAAQ;AACtB,UAAM,KAAK,GAAG,SAAS;AACvB,UAAM,UAAU;AAAA,MACd,EAAE,GAAG,CAAC,IAAI,GAAG,CAAC,GAAG;AAAA,MACjB,EAAE,GAAG,CAAC,IAAI,GAAG,CAAC,GAAG;AAAA,MACjB,EAAE,GAAG,CAAC,IAAI,GAAG,CAAC,GAAG;AAAA,MACjB,EAAE,GAAG,CAAC,IAAI,GAAG,CAAC,GAAG;AAAA,IACnB;AACA,UAAM,SAAU,GAAG,gBAAgB,KAAK,KAAK,KAAM;AACnD,UAAM,MAAM,KAAK,IAAI,KAAK;AAC1B,UAAM,MAAM,KAAK,IAAI,KAAK;AAC1B,WAAO,QAAQ,IAAI,CAAC,EAAE,GAAG,EAAE,OAAO;AAAA,MAChC,GAAG,GAAG,OAAO,IAAI,IAAI,MAAM,IAAI;AAAA,MAC/B,GAAG,GAAG,OAAO,IAAI,IAAI,MAAM,IAAI;AAAA,IACjC,EAAE;AAAA,EACJ;AACA,MAAI,GAAG,SAAS,wBAAwB;AACtC,UAAM,IAAI;AACV,WAAO,MAAM,KAAK,EAAE,QAAQ,EAAE,GAAG,CAAC,GAAG,MAAM;AACzC,YAAM,IAAK,IAAI,KAAK,KAAK,IAAK;AAC9B,aAAO;AAAA,QACL,GAAG,GAAG,OAAO,IAAI,GAAG,SAAS,KAAK,IAAI,CAAC;AAAA,QACvC,GAAG,GAAG,OAAO,IAAI,GAAG,SAAS,KAAK,IAAI,CAAC;AAAA,MACzC;AAAA,IACF,CAAC;AAAA,EACH;AACA,SAAO,GAAG;AACZ;AAEA,SAASC,kBACP,aACA,gBACQ;AACR,QAAM,eAAe,YAAY;AAAA,IAC/B,CAAC,OACC,GAAG,SAAS,mBAAmB,GAAG,qBAAqB;AAAA,EAC3D;AACA,MAAI,cAAc,SAAS,gBAAiB,QAAO;AACnD,QAAM,kBAAkB,YAAY;AAAA,IAClC,CAAC,OACC,GAAG,SAAS,sBACZ,GAAG,wBAAwB,aAAa;AAAA,EAC5C;AACA,MAAI,iBAAiB,SAAS,sBAAsB,gBAAgB,MAAM;AACxE,WAAO,gBAAgB;AAAA,EACzB;AACA,SAAO;AACT;AAIA,SAAS,gBAAgB,OAAgB,OAAyB;AAEhE,MAAI,MAAM,KAAK,CAAC,MAAMD,sBAAqB,GAAG,KAAK,CAAC,EAAG,QAAO;AAC9D,MAAI,MAAM,KAAK,CAAC,MAAMA,sBAAqB,GAAG,KAAK,CAAC,EAAG,QAAO;AAE9D,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,KAAK,MAAM,CAAC;AAClB,UAAM,KAAK,OAAO,IAAI,KAAK,MAAM,MAAM;AACvC,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,YAAM,KAAK,MAAM,CAAC;AAClB,YAAM,KAAK,OAAO,IAAI,KAAK,MAAM,MAAM;AACvC,UAAI,oBAAoB,IAAI,IAAI,IAAI,EAAE,EAAG,QAAO;AAAA,IAClD;AAAA,EACF;AACA,SAAO;AACT;AAMO,SAAS,sBACd,aAC4B;AAC5B,QAAM,aAAa,YAAY;AAAA,IAC7B,CAAC,OACC,GAAG,SAAS,wBACZ,GAAG,SAAS,0BACZ,GAAG,SAAS;AAAA,EAChB;AAGA,QAAM,cAAc,oBAAI,IAAgC;AACxD,aAAW,MAAM,YAAY;AAC3B,UAAM,KAAK,GAAG;AACd,QAAI,CAAC,YAAY,IAAI,EAAE,EAAG,aAAY,IAAI,IAAI,CAAC,CAAC;AAChD,gBAAY,IAAI,EAAE,EAAG,KAAK,EAAE;AAAA,EAC9B;AAEA,QAAM,eAAe,MAAM,KAAK,YAAY,KAAK,CAAC;AAClD,QAAM,SAAqC,CAAC;AAE5C,WAAS,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;AAC5C,aAAS,IAAI,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;AAChD,YAAM,MAAM,aAAa,CAAC;AAC1B,YAAM,MAAM,aAAa,CAAC;AAE1B,UAAI,cAAc;AAClB,YAAO,YAAW,KAAK,YAAY,IAAI,GAAG,GAAI;AAC5C,mBAAW,KAAK,YAAY,IAAI,GAAG,GAAI;AAErC,cAAI,WAAW,KAAK,WAAW,KAAK,EAAE,UAAU,EAAE,OAAO;AACvD;AAAA,UACF;AACA,gBAAM,QAAQ,oBAAoB,CAAC;AACnC,gBAAM,QAAQ,oBAAoB,CAAC;AACnC,cAAI,gBAAgB,OAAO,KAAK,GAAG;AACjC,0BAAc;AACd,kBAAM;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAEA,UAAI,aAAa;AACf,eAAO,KAAK;AAAA,UACV,MAAM;AAAA,UACN,cAAc,yBAAyB,GAAG,IAAI,GAAG;AAAA,UACjD,YAAY;AAAA,UACZ,SAAS,gBAAgBC,kBAAiB,aAAa,GAAG,CAAC,+BAA+BA,kBAAiB,aAAa,GAAG,CAAC;AAAA,UAC5H,mBAAmB,CAAC,KAAK,GAAG;AAAA,QAC9B,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;AClJA,SAAS,wBAAAC,6BAA4B;AAmBrC,IAAMC,sBAAqB,CACzB,YAEA,QAAQ,SAAS,0BACjB,QAAQ,SAAS,2BACjB,QAAQ,SAAS,2BACjB,QAAQ,SAAS;AAEnB,IAAM,yBAAyB,CAC7B,OACA,cACY;AACZ,MAAI,UAAU,SAAS,wBAAwB;AAC7C,UAAM,KAAK,MAAM,IAAI,UAAU,OAAO;AACtC,UAAM,KAAK,MAAM,IAAI,UAAU,OAAO;AACtC,WAAO,KAAK,KAAK,KAAK,MAAM,UAAU,SAAS,UAAU;AAAA,EAC3D;AAEA,MAAI,UAAU,SAAS,sBAAsB;AAC3C,UAAM,QAAS,MAAM,UAAU,gBAAgB,KAAK,KAAK,KAAM;AAC/D,UAAM,KAAK,MAAM,IAAI,UAAU,OAAO;AACtC,UAAM,KAAK,MAAM,IAAI,UAAU,OAAO;AACtC,UAAM,SAAS,KAAK,KAAK,IAAI,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK;AACzD,UAAM,SAAS,KAAK,KAAK,IAAI,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK;AACzD,WACE,KAAK,IAAI,MAAM,KAAK,UAAU,QAAQ,KACtC,KAAK,IAAI,MAAM,KAAK,UAAU,SAAS;AAAA,EAE3C;AAEA,QAAM,UACJ,UAAU,SAAS,0BACf,UAAU,SACV,UAAU;AAChB,SAAOC,sBAAqB,OAAO,OAAO;AAC5C;AAEA,IAAM,sBAAsB,CAC1B,aACA,mBACW;AACX,QAAM,eAAe,YAAY;AAAA,IAC/B,CAAC,YACC,QAAQ,SAAS,mBACjB,QAAQ,qBAAqB;AAAA,EACjC;AACA,QAAM,kBAAkB,YAAY;AAAA,IAClC,CAAC,YACC,QAAQ,SAAS,sBACjB,QAAQ,wBAAwB,cAAc;AAAA,EAClD;AAEA,UACG,mBAAmB,UAAU,kBAC1B,gBAAgB,OAChB,WAAc,4BAA4B,aAAa,cAAc;AAE7E;AAOO,SAAS,4BACd,aACqB;AACrB,QAAM,mBAAmB,YAAY;AAAA,IACnC,CAAC,YACC,QAAQ,SAAS,sBACjB,QAAQ,UAAU;AAAA,EACtB;AACA,QAAM,qBAAqB,IAAI;AAAA,IAC7B,iBAAiB,IAAI,CAAC,cAAc,UAAU,mBAAmB;AAAA,EACnE;AACA,QAAM,iBAAiB,IAAI;AAAA,IACzB,iBAAiB,IAAI,CAAC,cAAc;AAAA,MAClC,UAAU;AAAA,MACV,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AACA,QAAM,sBAAsB,YAAY;AAAA,IACtC,CAAC,YACC,QAAQ,SAAS,mBACjB,mBAAmB,IAAI,QAAQ,mBAAmB;AAAA,EACtD;AACA,QAAM,aAAa,YAAY,OAAOD,mBAAkB;AACxD,QAAM,SAA8B,CAAC;AACrC,QAAM,yBAAyB,oBAAI,IAAY;AAE/C,aAAW,aAAa,qBAAqB;AAC3C,eAAW,aAAa,YAAY;AAClC,UAAI,UAAU,qBAAqB,UAAU,iBAAkB;AAC/D,UAAI,UAAU,UAAU,UAAU,MAAO;AACzC,UAAI,CAAC,uBAAuB,UAAU,QAAQ,SAAS,EAAG;AAE1D,YAAM,gBAAgB,GAAG,UAAU,gBAAgB,IAAI,UAAU,gBAAgB;AACjF,UAAI,uBAAuB,IAAI,aAAa,EAAG;AAC/C,6BAAuB,IAAI,aAAa;AAExC,YAAM,gBACJ,eAAe,IAAI,UAAU,mBAAmB,KAAK;AACvD,YAAM,2BAA2B;AAAA,QAC/B;AAAA,QACA,UAAU;AAAA,MACZ;AAEA,aAAO,KAAK;AAAA,QACV,MAAM;AAAA,QACN,wBAAwB,0BAA0B,UAAU,gBAAgB,IAAI,UAAU,gBAAgB;AAAA,QAC1G,YAAY;AAAA,QACZ,SAAS,cAAc,aAAa,4DAA4D,wBAAwB;AAAA,QACxH,eAAe,UAAU;AAAA,MAC3B,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;;;ACzGA,eAAsB,sBAAsB,aAAkC;AAC5E,SAAO;AAAA,IACL,GAAG,gCAAgC,WAAW;AAAA,IAC9C,GAAG,gBAAgB,WAAW;AAAA,IAC9B,GAAG,6BAA6B,WAAW;AAAA,IAC3C,GAAG,4BAA4B,WAAW;AAAA,IAC1C,GAAG,0BAA0B,WAAW;AAAA,IACxC,GAAG,yBAAyB,WAAW;AAAA,IACvC,GAAG,mCAAmC,WAAW;AAAA,IACjD,GAAG,qBAAqB,WAAW;AAAA,IACnC,GAAG,sBAAsB,WAAW;AAAA,IACpC,GAAG,oCAAoC,WAAW;AAAA,IAClD,GAAG,4BAA4B,WAAW;AAAA,EAC5C;AACF;AAEA,eAAsB,oBAAoB,aAAkC;AAC1E,SAAO,CAAC,GAAG,wBAAwB,WAAW,CAAC;AACjD;AAEA,eAAsB,sBAAsB,aAAkC;AAC5E,SAAO;AAAA,IACL,GAAG,gDAAgD,WAAW;AAAA,IAC9D,GAAG,sDAAsD,WAAW;AAAA,IACpE,GAAG,wCAAwC,WAAW;AAAA,EACxD;AACF;AAEA,eAAsB,6BACpB,aACA;AACA,SAAO;AAAA,IACL,GAAG,yCAAyC,WAAW;AAAA,IACvD,GAAG,uBAAuB,WAAW;AAAA,IACrC,GAAG,wBAAwB,WAAW;AAAA,EACxC;AACF;AAEA,eAAsB,oBAAoB,aAAkC;AAC1E,SAAO;AAAA,IACL,GAAG,qCAAqC,WAAW;AAAA,IACnD,GAAG,+BAA+B,WAAW;AAAA,IAC7C,GAAG,qBAAqB,WAAW;AAAA,IACnC,GAAG,uBAAuB,WAAW;AAAA,IACrC,GAAG,gCAAgC,WAAW;AAAA,IAC9C,GAAG,uBAAuB,WAAW;AAAA,IACrC,GAAG,uBAAuB,WAAW;AAAA,IACrC,GAAG,qBAAqB,WAAW;AAAA,IACnC,GAAG,uBAAuB,WAAW;AAAA,IACrC,GAAG,4BAA4B,WAAW;AAAA,IAC1C,GAAG,yBAAyB,WAAW;AAAA,IACvC,GAAG,yBAAyB,WAAW;AAAA,EACzC;AACF;AAEA,eAAsB,aAAa,aAAkC;AACnE,SAAO;AAAA,IACL,GAAI,MAAM,sBAAsB,WAAW;AAAA,IAC3C,GAAI,MAAM,sBAAsB,WAAW;AAAA,IAC3C,GAAI,MAAM,oBAAoB,WAAW;AAAA,IACzC,GAAI,MAAM,6BAA6B,WAAW;AAAA,IAClD,GAAI,MAAM,oBAAoB,WAAW;AAAA,EAC3C;AACF;","names":["pill","pill","cju","getReadableNameForElement","segmentToCircleMinDistance","segmentToSegmentMinDistance","getFullConnectivityMapFromCircuitJson","getBoundsOfPcbElements","pointToSegmentClosestPoint","segmentToSegmentMinDistance","getBoundsOfPcbElements","segmentToSegmentMinDistance","pill","distance","pointToSegmentClosestPoint","clearance","clamp","dx","dy","t","closestOnB","closestOnA","distance","getBoundsOfPcbElements","pill","getBoundsOfPcbElements","getFullConnectivityMapFromCircuitJson","cju","getReadableNameForElement","gap","segmentToSegmentMinDistance","distance","segmentToCircleMinDistance","getReadableNameForElement","midpoint","isInside","getReadableNameForElement","Flatten","rotateDEG","applyToPoint","boardToPolygon","rotatePoint","Flatten","applyToPoint","rotateDEG","rectanglePolygon","rotateDEG","applyToPoint","cju","getPrimaryId","getPrimaryId","cju","getReadableNameForElement","getFullConnectivityMapFromCircuitJson","distance","distance","getFullConnectivityMapFromCircuitJson","distance","getReadableNameForElement","getReadableNameForElement","getFullConnectivityMapFromCircuitJson","getFullConnectivityMapFromCircuitJson","distance","getReadableNameForElement","cju","getFullConnectivityMapFromCircuitJson","cju","getFullConnectivityMapFromCircuitJson","getFullConnectivityMapFromCircuitJson","getFullConnectivityMapFromCircuitJson","pointToSegmentDistance","getReadableNameForPcbPort","getFullConnectivityMapFromCircuitJson","PcbConnectivityMap","pointToSegmentDistance","distance","PcbConnectivityMap","getFullConnectivityMapFromCircuitJson","traceName","getReadableNameForPcbPort","cju","segmentToSegmentMinDistance","cju","distance","segmentToSegmentMinDistance","cju","getBoundsOfPcbElements","getPrimaryId","doBoundsOverlap","getFullConnectivityMapFromCircuitJson","getBoundsOfPcbElements","doBoundsOverlap","getBoundsOfPcbElements","doBoundsOverlap","getPrimaryId","getFullConnectivityMapFromCircuitJson","cju","getBoundsOfPcbElements","doBoundsOverlap","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","cju","cju","cju","cju","cju","FLOATING_POINT_TOLERANCE","isPointInsidePolygon","getComponentName","isPointInsidePolygon","isCourtyardElement","isPointInsidePolygon"]}
1
+ {"version":3,"sources":["../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/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-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/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/check-same-name-nets-are-connected.ts","../lib/check-connector-accessible-orientation.ts","../lib/check-courtyard-overlap/checkCourtyardOverlap.ts","../lib/check-testpoint-accessibility.ts","../lib/run-all-checks.ts"],"sourcesContent":["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: PcbTraceSegment,\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 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 PcbConnectivityMap,\n} from \"circuit-json-to-connectivity-map\"\nimport { getReadableNameForPort } from \"./util/get-readable-names\"\n\nfunction checkEachPcbPortConnectedToPcbTraces(\n circuitJson: AnyCircuitElement[],\n): PcbPortNotConnectedError[] {\n addStartAndEndPortIdsIfMissing(circuitJson)\n const sourceTraces: SourceTrace[] = circuitJson.filter(\n (item) => item.type === \"source_trace\",\n ) as SourceTrace[]\n\n const pcbPorts: PcbPort[] = circuitJson.filter(\n (item) => item.type === \"pcb_port\",\n ) as PcbPort[]\n 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 = getFullConnectivityMapFromCircuitJson(circuitJson)\n const pcbConnectivityMap = new PcbConnectivityMap(circuitJson)\n\n // Create a map from source_port_id to pcb_port for quick lookup\n const sourcePortToPcbPort = new Map<string, PcbPort>()\n for (const pcbPort of pcbPorts) {\n sourcePortToPcbPort.set(pcbPort.source_port_id, pcbPort)\n }\n\n 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 (connectedPcbTraces.length === 0) {\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 (pcbTraceIds.length === 0) {\n // Check if this is a trivial case (only 2 ports on same component)\n const uniqueComponentIds = new Set(\n pcbPortsInTrace.map((p) => p.pcb_component_id),\n )\n\n if (uniqueComponentIds.size > 1) {\n // Ports are on different components but no PCB traces connect them\n errors.push({\n type: \"pcb_port_not_connected_error\",\n message: `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 { 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} 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[] {\n const errors: PcbTraceError[] = []\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).pcb_keepout.list()\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 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\nexport const getPadToPadGap = (\n padA: CopperClearanceElement,\n padB: CopperClearanceElement,\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\n/**\n * Returns the center used to place a trace-related error in circuit-json.\n *\n * Clearance geometry is measured at the closest segment/obstacle points, but\n * placing the error there makes independent traces that pass the same obstacle\n * render on top of one another. Centering each error on its full trace keeps\n * placement deterministic and distinct without requiring renderer-side moves.\n */\nexport const getTraceCenter = (segment: PcbTraceSegment) => {\n const routePoints = segment._pcbTrace.route.flatMap((routePoint) => {\n if (routePoint.route_type === \"through_pad\") {\n return [routePoint.start, routePoint.end]\n }\n\n return [{ x: routePoint.x, y: routePoint.y }]\n })\n const firstPoint = routePoints[0]\n const lastPoint = routePoints[routePoints.length - 1]\n\n if (!firstPoint || !lastPoint) {\n return midpoint(\n { x: segment.x1, y: segment.y1 },\n { x: segment.x2, y: segment.y2 },\n )\n }\n\n return midpoint(firstPoint, lastPoint)\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 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: PcbTraceSegment,\n obstacle: TraceClearanceObstacle,\n): { gap: number; center: { x: number; y: number } } => {\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,\n center: getCenterBetweenCopperEdges({\n tracePoint: clearance.tracePoint,\n obstaclePoint: clearance.obstaclePoint,\n traceRadius,\n obstacleRadius: 0,\n }),\n }\n}\n\nexport const isTraceObstacleOverlap = (gap: number): boolean => gap <= 0\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 * as Flatten from \"@flatten-js/core\"\nimport { jlcMinTolerances } from \"@tscircuit/jlcpcb-manufacturing-specs\"\nimport type {\n AnyCircuitElement,\n PcbBoard,\n PcbComponent,\n PcbCopperPour,\n PcbPlacementError,\n PcbPlatedHole,\n PcbSmtPad,\n PcbVia,\n} from \"circuit-json\"\nimport { getBoardDrcValue, getPcbBoard } from \"lib/drc-defaults\"\nimport { applyToPoint, rotateDEG } from \"transformation-matrix\"\n\ntype CopperElement = PcbVia | PcbSmtPad | PcbPlatedHole | PcbCopperPour\ndeclare const pcbComponentIdBrand: unique symbol\ntype PcbComponentId = string & {\n readonly [pcbComponentIdBrand]: \"PcbComponentId\"\n}\nconst toPcbComponentId = (id: string): PcbComponentId => id as PcbComponentId\ntype CopperShape = Flatten.Circle | Flatten.Polygon\n\ntype CopperGeometry =\n | { kind: \"shapes\"; shapes: CopperShape[] }\n | { kind: \"pill\"; centerLine: Flatten.Segment; radius: number }\n\nconst GEOMETRY_EPSILON = 1e-9\n\nconst pointsToPolygon = (\n points: Array<{ x: number; y: number }>,\n): Flatten.Polygon | null => {\n if (points.length < 3) return null\n return new Flatten.Polygon(points.map(({ x, y }) => new Flatten.Point(x, y)))\n}\n\nconst brepRingToPolygon = (\n vertices: Array<{ x: number; y: number; bulge?: number }>,\n): Flatten.Polygon | null => {\n const ring = vertices.filter((vertex, index) => {\n const previous = vertices[index - 1]\n return (\n !previous ||\n Math.abs(previous.x - vertex.x) > GEOMETRY_EPSILON ||\n Math.abs(previous.y - vertex.y) > GEOMETRY_EPSILON\n )\n })\n if (\n ring.length > 1 &&\n Math.abs(ring[0].x - ring.at(-1)!.x) <= GEOMETRY_EPSILON &&\n Math.abs(ring[0].y - ring.at(-1)!.y) <= GEOMETRY_EPSILON\n ) {\n ring.pop()\n }\n if (ring.length < 3) return null\n\n const edges: Array<Flatten.Segment | Flatten.Arc> = []\n for (let index = 0; index < ring.length; index++) {\n const start = ring[index]\n const end = ring[(index + 1) % ring.length]\n const startPoint = new Flatten.Point(start.x, start.y)\n const endPoint = new Flatten.Point(end.x, end.y)\n const bulge = start.bulge ?? 0\n if (Math.abs(bulge) <= GEOMETRY_EPSILON) {\n edges.push(new Flatten.Segment(startPoint, endPoint))\n continue\n }\n\n const chordLength = startPoint.distanceTo(endPoint)[0]\n if (chordLength <= GEOMETRY_EPSILON) continue\n const midpoint = {\n x: (start.x + end.x) / 2,\n y: (start.y + end.y) / 2,\n }\n const leftNormal = {\n x: -(end.y - start.y) / chordLength,\n y: (end.x - start.x) / chordLength,\n }\n const centerOffset = (chordLength * (1 - bulge * bulge)) / (4 * bulge)\n const center = new Flatten.Point(\n midpoint.x + leftNormal.x * centerOffset,\n midpoint.y + leftNormal.y * centerOffset,\n )\n const radius = (chordLength * (1 + bulge * bulge)) / (4 * Math.abs(bulge))\n edges.push(\n new Flatten.Arc(\n center,\n radius,\n Math.atan2(start.y - center.y, start.x - center.x),\n Math.atan2(end.y - center.y, end.x - center.x),\n bulge > 0,\n ),\n )\n }\n\n if (edges.length < 3) return null\n const polygon = new Flatten.Polygon()\n polygon.addFace(edges)\n return polygon\n}\n\nconst boardToPolygon = (board: PcbBoard): Flatten.Polygon | null => {\n if (board.outline && board.outline.length >= 3) {\n return pointsToPolygon(board.outline)\n }\n\n if (\n !board.center ||\n typeof board.width !== \"number\" ||\n typeof board.height !== \"number\"\n ) {\n return null\n }\n\n const halfWidth = board.width / 2\n const halfHeight = board.height / 2\n return pointsToPolygon([\n { x: board.center.x - halfWidth, y: board.center.y - halfHeight },\n { x: board.center.x + halfWidth, y: board.center.y - halfHeight },\n { x: board.center.x + halfWidth, y: board.center.y + halfHeight },\n { x: board.center.x - halfWidth, y: board.center.y + halfHeight },\n ])\n}\n\nconst getRectanglePolygon = ({\n x,\n y,\n width,\n height,\n ccwRotationDegrees = 0,\n}: {\n x: number\n y: number\n width: number\n height: number\n ccwRotationDegrees?: number\n}): Flatten.Polygon | null => {\n const halfWidth = width / 2\n const halfHeight = height / 2\n const rotationMatrix = rotateDEG(ccwRotationDegrees, x, y)\n return pointsToPolygon(\n [\n { x: x - halfWidth, y: y - halfHeight },\n { x: x + halfWidth, y: y - halfHeight },\n { x: x + halfWidth, y: y + halfHeight },\n { x: x - halfWidth, y: y + halfHeight },\n ].map((point) => applyToPoint(rotationMatrix, point)),\n )\n}\n\n/** Model a rounded rectangle exactly as the union of two bands and its corners. */\nconst roundedRect = ({\n x,\n y,\n width,\n height,\n cornerRadius,\n ccwRotationDegrees = 0,\n}: {\n x: number\n y: number\n width: number\n height: number\n cornerRadius: number\n ccwRotationDegrees?: number\n}): CopperGeometry | null => {\n const radius = Math.max(0, Math.min(cornerRadius, width / 2, height / 2))\n if (radius <= GEOMETRY_EPSILON) {\n const polygon = getRectanglePolygon({\n x,\n y,\n width,\n height,\n ccwRotationDegrees,\n })\n return polygon ? { kind: \"shapes\", shapes: [polygon] } : null\n }\n\n const shapes: CopperShape[] = []\n const innerWidth = width - 2 * radius\n const innerHeight = height - 2 * radius\n if (innerWidth > GEOMETRY_EPSILON) {\n const verticalBand = getRectanglePolygon({\n x,\n y,\n width: innerWidth,\n height,\n ccwRotationDegrees,\n })\n if (verticalBand) shapes.push(verticalBand)\n }\n if (innerHeight > GEOMETRY_EPSILON) {\n const horizontalBand = getRectanglePolygon({\n x,\n y,\n width,\n height: innerHeight,\n ccwRotationDegrees,\n })\n if (horizontalBand) shapes.push(horizontalBand)\n }\n\n const halfInnerWidth = innerWidth / 2\n const halfInnerHeight = innerHeight / 2\n const rotationMatrix = rotateDEG(ccwRotationDegrees, x, y)\n const cornerCenters = [\n { x: x - halfInnerWidth, y: y - halfInnerHeight },\n { x: x + halfInnerWidth, y: y - halfInnerHeight },\n { x: x + halfInnerWidth, y: y + halfInnerHeight },\n { x: x - halfInnerWidth, y: y + halfInnerHeight },\n ]\n .map((point) => applyToPoint(rotationMatrix, point))\n .filter(\n (point, index, points) =>\n points.findIndex(\n (candidate) =>\n Math.abs(candidate.x - point.x) <= GEOMETRY_EPSILON &&\n Math.abs(candidate.y - point.y) <= GEOMETRY_EPSILON,\n ) === index,\n )\n shapes.push(\n ...cornerCenters.map(\n (center) =>\n new Flatten.Circle(new Flatten.Point(center.x, center.y), radius),\n ),\n )\n\n return shapes.length > 0 ? { kind: \"shapes\", shapes } : null\n}\n\nconst pill = ({\n x,\n y,\n width,\n height,\n radius,\n ccwRotationDegrees = 0,\n}: {\n x: number\n y: number\n width: number\n height: number\n radius: number\n ccwRotationDegrees?: number\n}): CopperGeometry => {\n const halfLineLength = Math.max(Math.max(width, height) / 2 - radius, 0)\n const localAxis =\n width >= height ? { x: halfLineLength, y: 0 } : { x: 0, y: halfLineLength }\n const axis = applyToPoint(rotateDEG(ccwRotationDegrees), localAxis)\n\n if (halfLineLength <= GEOMETRY_EPSILON) {\n return {\n kind: \"shapes\",\n shapes: [new Flatten.Circle(new Flatten.Point(x, y), radius)],\n }\n }\n\n return {\n kind: \"pill\",\n centerLine: new Flatten.Segment(\n new Flatten.Point(x - axis.x, y - axis.y),\n new Flatten.Point(x + axis.x, y + axis.y),\n ),\n radius,\n }\n}\n\nconst getSmtPadGeometry = (pad: PcbSmtPad): CopperGeometry | null => {\n switch (pad.shape) {\n case \"circle\":\n return {\n kind: \"shapes\",\n shapes: [\n new Flatten.Circle(new Flatten.Point(pad.x, pad.y), pad.radius),\n ],\n }\n case \"rect\":\n return roundedRect({\n x: pad.x,\n y: pad.y,\n width: pad.width,\n height: pad.height,\n cornerRadius: pad.rect_border_radius ?? pad.corner_radius ?? 0,\n })\n case \"rotated_rect\":\n return roundedRect({\n x: pad.x,\n y: pad.y,\n width: pad.width,\n height: pad.height,\n cornerRadius: pad.rect_border_radius ?? pad.corner_radius ?? 0,\n ccwRotationDegrees: pad.ccw_rotation,\n })\n case \"pill\":\n return pill({\n x: pad.x,\n y: pad.y,\n width: pad.width,\n height: pad.height,\n radius: pad.radius,\n })\n case \"rotated_pill\":\n return pill({\n x: pad.x,\n y: pad.y,\n width: pad.width,\n height: pad.height,\n radius: pad.radius,\n ccwRotationDegrees: pad.ccw_rotation,\n })\n case \"polygon\": {\n const polygon = pointsToPolygon(pad.points)\n return polygon ? { kind: \"shapes\", shapes: [polygon] } : null\n }\n }\n}\n\nconst getPlatedHoleGeometry = (\n platedHole: PcbPlatedHole,\n componentCcwRotationDegrees: number,\n): CopperGeometry | null => {\n switch (platedHole.shape) {\n case \"circle\":\n return {\n kind: \"shapes\",\n shapes: [\n new Flatten.Circle(\n new Flatten.Point(platedHole.x, platedHole.y),\n platedHole.outer_diameter / 2,\n ),\n ],\n }\n case \"oval\":\n case \"pill\":\n return pill({\n x: platedHole.x,\n y: platedHole.y,\n width: platedHole.outer_width,\n height: platedHole.outer_height,\n radius: Math.min(\n platedHole.outer_width / 2,\n platedHole.outer_height / 2,\n ),\n ccwRotationDegrees: platedHole.ccw_rotation,\n })\n case \"circular_hole_with_rect_pad\":\n case \"pill_hole_with_rect_pad\":\n case \"rotated_pill_hole_with_rect_pad\":\n return roundedRect({\n x: platedHole.x,\n y: platedHole.y,\n width: platedHole.rect_pad_width,\n height: platedHole.rect_pad_height,\n cornerRadius: platedHole.rect_border_radius ?? 0,\n ccwRotationDegrees:\n \"rect_ccw_rotation\" in platedHole\n ? (platedHole.rect_ccw_rotation ?? 0)\n : 0,\n })\n case \"hole_with_polygon_pad\": {\n const ccwRotationDegrees =\n platedHole.ccw_rotation ?? componentCcwRotationDegrees\n const rotationMatrix = rotateDEG(ccwRotationDegrees)\n const polygon = pointsToPolygon(\n platedHole.pad_outline.map((point) => {\n const rotatedPoint = applyToPoint(rotationMatrix, point)\n return {\n x: platedHole.x + rotatedPoint.x,\n y: platedHole.y + rotatedPoint.y,\n }\n }),\n )\n return polygon ? { kind: \"shapes\", shapes: [polygon] } : null\n }\n }\n}\n\nconst getCopperGeometry = (\n element: CopperElement,\n componentCcwRotationsById: Map<PcbComponentId, number>,\n): CopperGeometry | null => {\n if (element.type === \"pcb_via\") {\n return {\n kind: \"shapes\",\n shapes: [\n new Flatten.Circle(\n new Flatten.Point(element.x, element.y),\n element.outer_diameter / 2,\n ),\n ],\n }\n }\n if (element.type === \"pcb_smtpad\") return getSmtPadGeometry(element)\n if (element.type === \"pcb_plated_hole\") {\n return getPlatedHoleGeometry(\n element,\n element.pcb_component_id\n ? (componentCcwRotationsById.get(\n toPcbComponentId(element.pcb_component_id),\n ) ?? 0)\n : 0,\n )\n }\n\n let polygon: Flatten.Polygon | null\n switch (element.shape) {\n case \"rect\":\n polygon = getRectanglePolygon({\n x: element.center.x,\n y: element.center.y,\n width: element.width,\n height: element.height,\n ccwRotationDegrees: element.rotation ?? 0,\n })\n break\n case \"polygon\":\n polygon = pointsToPolygon(element.points)\n break\n case \"brep\":\n // Holes remove copper, so only the outer ring can violate the board edge.\n polygon = brepRingToPolygon(element.brep_shape.outer_ring.vertices)\n break\n }\n return polygon ? { kind: \"shapes\", shapes: [polygon] } : null\n}\n\nconst getCopperElementId = (element: CopperElement): string => {\n if (element.type === \"pcb_via\") return element.pcb_via_id\n if (element.type === \"pcb_smtpad\") return element.pcb_smtpad_id\n if (element.type === \"pcb_plated_hole\") return element.pcb_plated_hole_id\n return element.pcb_copper_pour_id\n}\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\nconst measureClearance = (\n board: Flatten.Polygon,\n geometry: CopperGeometry,\n): { isInside: boolean; clearance: number } => {\n if (geometry.kind === \"shapes\") {\n const isInside = geometry.shapes.every((shape) => board.contains(shape))\n return {\n isInside,\n clearance: isInside\n ? Math.min(\n ...geometry.shapes.map((shape) => board.distanceTo(shape)[0]),\n )\n : 0,\n }\n }\n\n const centerLineClearance = board.distanceTo(geometry.centerLine)[0]\n const clearance = centerLineClearance - geometry.radius\n const isInside =\n board.contains(geometry.centerLine) && clearance >= -GEOMETRY_EPSILON\n return {\n isInside,\n clearance: isInside ? Math.max(0, clearance) : 0,\n }\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 const boardPolygon = boardToPolygon(board)\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<PcbComponentId>(\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) => toPcbComponentId(component.pcb_component_id)),\n )\n\n const copperElements = circuitJson.filter(\n (element): element is CopperElement =>\n element.type === \"pcb_via\" ||\n element.type === \"pcb_smtpad\" ||\n element.type === \"pcb_plated_hole\" ||\n element.type === \"pcb_copper_pour\",\n )\n const componentCcwRotationsById = new Map<PcbComponentId, number>(\n circuitJson\n .filter(\n (element): element is PcbComponent => element.type === \"pcb_component\",\n )\n .map((component) => [\n toPcbComponentId(component.pcb_component_id),\n component.rotation,\n ]),\n )\n\n const errors: PcbPlacementError[] = []\n for (const element of copperElements) {\n if (\n (element.type === \"pcb_smtpad\" || element.type === \"pcb_plated_hole\") &&\n element.pcb_component_id &&\n allowedOffBoardComponentIds.has(\n toPcbComponentId(element.pcb_component_id),\n )\n ) {\n continue\n }\n\n const geometry = getCopperGeometry(element, componentCcwRotationsById)\n if (!geometry) continue\n\n const { isInside, clearance } = measureClearance(boardPolygon, geometry)\n if (isInside && clearance + GEOMETRY_EPSILON >= requiredClearance) {\n continue\n }\n\n const id = getCopperElementId(element)\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 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[] {\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>()\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 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 (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 { getFullConnectivityMapFromCircuitJson } from \"circuit-json-to-connectivity-map\"\nimport { containsCircuitJsonId } from \"lib/util/get-readable-names\"\n\n/**\n * Check that each source_trace which connects source ports has at least one\n * pcb_trace associated with it. If a source_trace has no corresponding\n * pcb_trace, return an error for that source_trace.\n */\nfunction checkSourceTracesHavePcbTraces(\n circuitJson: AnyCircuitElement[],\n): PcbTraceMissingError[] {\n const errors: PcbTraceMissingError[] = []\n const sourceTraces = circuitJson.filter(\n (el) => el.type === \"source_trace\",\n ) as SourceTrace[]\n const pcbTraces = circuitJson.filter(\n (el) => el.type === \"pcb_trace\",\n ) as PcbTrace[]\n 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 = getFullConnectivityMapFromCircuitJson(circuitJson)\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 // 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 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 PcbConnectivityMap,\n} from \"circuit-json-to-connectivity-map\"\nimport { getLayersOfPcbElement } from \"../util/getLayersOfPcbElement\"\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): 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 const pcbConnectivityMap = new PcbConnectivityMap(circuitJson)\n let fullConnectivityMap: ConnectivityMap | undefined\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 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 || firstConnectsToLogicallyConnectedTraceCopper\n const lastIsConnected =\n lastConnectsToAnyPad || lastConnectsToLogicallyConnectedTraceCopper\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 { 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 PcbFootprintOverlapError,\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 {\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 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): PcbFootprintOverlapError[] {\n const errors: PcbFootprintOverlapError[] = []\n\n // Build connectivity map to check if components are electrically connected\n const connMap = getFullConnectivityMapFromCircuitJson(circuitJson)\n\n // Get all overlappable elements\n const smtPads = cju(circuitJson).pcb_smtpad.list()\n const platedHoles = cju(circuitJson).pcb_plated_hole.list()\n const holes = cju(circuitJson).pcb_hole.list()\n 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\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 (isCourtyardElement(elem1) || isCourtyardElement(elem2)) &&\n elem1.type !== \"pcb_hole\" &&\n elem2.type !== \"pcb_hole\"\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: PcbFootprintOverlapError = {\n type: \"pcb_footprint_overlap_error\",\n pcb_error_id: `pcb_footprint_overlap_${id1}_${id2}`,\n error_type: \"pcb_footprint_overlap_error\",\n message: `${elem1.type} ${elem1Description} overlaps with ${elem2.type} ${elem2Description}`,\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 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 { getPadToPadGap } from \"lib/check-pad-clearance/common\"\nimport { getLayersOfPcbElement } from \"lib/util/getLayersOfPcbElement\"\n\nexport type OverlappableElement =\n | PcbSmtPad\n | PcbPlatedHole\n | PcbHole\n | PcbCourtyardCircle\n | PcbCourtyardOutline\n | PcbCourtyardPolygon\n | PcbCourtyardRect\n\nfunction getElementLayers(elem: OverlappableElement): string[] {\n if (\n elem.type === \"pcb_courtyard_circle\" ||\n elem.type === \"pcb_courtyard_outline\" ||\n elem.type === \"pcb_courtyard_polygon\" ||\n elem.type === \"pcb_courtyard_rect\"\n ) {\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 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 a warning for every PCB component without a courtyard. */\nexport function checkPcbComponentsMissingCourtyard(\n circuitJson: AnyCircuitElement[],\n): PcbComponentMissingCourtyardWarning[] {\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 )\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 {\n AnyCircuitElement,\n PcbPort,\n PcbTrace,\n PcbTraceRoutePoint,\n PcbTraceTooLongWarning,\n SourceTrace,\n} from \"circuit-json\"\n\nconst DEFAULT_VIA_LENGTH_MM = 1.6\n\nconst getRoutePointPosition = (routePoint: PcbTraceRoutePoint) =>\n routePoint.route_type === \"through_pad\"\n ? routePoint.start\n : { x: routePoint.x, y: routePoint.y }\n\nconst getPcbTraceLength = (pcbTrace: PcbTrace): number => {\n if (pcbTrace.trace_length !== undefined) return pcbTrace.trace_length\n\n let traceLength = 0\n\n for (\n let routePointIndex = 0;\n routePointIndex < pcbTrace.route.length;\n routePointIndex++\n ) {\n const routePoint = pcbTrace.route[routePointIndex]\n if (!routePoint) continue\n\n if (routePoint.route_type === \"via\") {\n traceLength += DEFAULT_VIA_LENGTH_MM\n continue\n }\n\n const nextRoutePoint = pcbTrace.route[routePointIndex + 1]\n if (!nextRoutePoint) continue\n\n const routePointPosition = getRoutePointPosition(routePoint)\n const nextRoutePointPosition = getRoutePointPosition(nextRoutePoint)\n traceLength += Math.hypot(\n nextRoutePointPosition.x - routePointPosition.x,\n nextRoutePointPosition.y - routePointPosition.y,\n )\n }\n\n return traceLength\n}\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 checkPcbTraceLengths = (\n circuitJson: AnyCircuitElement[],\n): PcbTraceTooLongWarning[] => {\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 sourceTracesById = new Map(\n sourceTraces.map((sourceTrace) => [\n sourceTrace.source_trace_id,\n sourceTrace,\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 const warnings: PcbTraceTooLongWarning[] = []\n\n for (const pcbTrace of pcbTraces) {\n if (!pcbTrace.source_trace_id) continue\n\n const sourceTrace = sourceTracesById.get(pcbTrace.source_trace_id)\n if (!sourceTrace) continue\n\n const maximumTraceLength = sourceTrace.max_length\n if (typeof maximumTraceLength !== \"number\") continue\n\n const exactEndpointPcbTraceIds =\n exactEndpointPcbTraceIdsBySourceTraceId.get(sourceTrace.source_trace_id)\n if (\n exactEndpointPcbTraceIds &&\n !exactEndpointPcbTraceIds.has(pcbTrace.pcb_trace_id)\n ) {\n continue\n }\n\n const actualTraceLength = getPcbTraceLength(pcbTrace)\n if (actualTraceLength <= maximumTraceLength) continue\n\n warnings.push({\n type: \"pcb_trace_too_long_warning\",\n pcb_trace_too_long_warning_id: `pcb_trace_too_long_warning_${pcbTrace.pcb_trace_id}`,\n warning_type: \"pcb_trace_too_long_warning\",\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 warnings\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 getTraceCenter,\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 } = 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: getTraceCenter(segment),\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 getTraceCenter,\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 } = 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: getTraceCenter(segment),\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 getPadCenter,\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 const viaCenter = getPadCenter(via)\n const padCenter = getPadCenter(pad)\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: {\n x: (viaCenter.x + padCenter.x) / 2,\n y: (viaCenter.y + padCenter.y) / 2,\n },\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 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 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 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: `${componentName} is facing ${facingDirection} but should face ${recommendedFacingDirection} so the connector is accessible from the board edge`,\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 PcbCourtyardOverlapError,\n PcbCourtyardRect,\n PcbCourtyardCircle,\n PcbCourtyardOutline,\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 courtyards = circuitJson.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\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","import { 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(circuitJson: AnyCircuitElement[]) {\n return [\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}\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 return [\n ...checkEachPcbPortConnectedToPcbTraces(circuitJson),\n ...checkSourceTracesHavePcbTraces(circuitJson),\n ...checkPcbTraceLengths(circuitJson),\n ...checkPcbTraceViaCounts(circuitJson),\n ...checkEachPcbTraceNonOverlapping(circuitJson),\n ...checkPadTraceClearance(circuitJson),\n ...checkViaTraceClearance(circuitJson),\n ...checkViaPadClearance(circuitJson),\n ...checkSameNetViaSpacing(circuitJson),\n ...checkDifferentNetViaSpacing(circuitJson),\n ...checkTracesAreContiguous(circuitJson),\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"],"mappings":"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","names":["pill","pill","cju","getReadableNameForElement","segmentToCircleMinDistance","segmentToSegmentMinDistance","getFullConnectivityMapFromCircuitJson","getBoundsOfPcbElements","pointToSegmentClosestPoint","segmentToSegmentMinDistance","getBoundsOfPcbElements","segmentToSegmentMinDistance","pill","distance","pointToSegmentClosestPoint","clearance","clamp","dx","dy","t","closestOnB","closestOnA","distance","getBoundsOfPcbElements","pill","getBoundsOfPcbElements","getFullConnectivityMapFromCircuitJson","cju","getReadableNameForElement","gap","segmentToSegmentMinDistance","distance","segmentToCircleMinDistance","getReadableNameForElement","midpoint","isInside","getReadableNameForElement","Flatten","rotateDEG","applyToPoint","boardToPolygon","rotatePoint","Flatten","applyToPoint","rotateDEG","rectanglePolygon","rotateDEG","applyToPoint","cju","getPrimaryId","getPrimaryId","cju","getReadableNameForElement","getFullConnectivityMapFromCircuitJson","distance","distance","getFullConnectivityMapFromCircuitJson","distance","getReadableNameForElement","getReadableNameForElement","getFullConnectivityMapFromCircuitJson","getFullConnectivityMapFromCircuitJson","distance","getReadableNameForElement","cju","getFullConnectivityMapFromCircuitJson","cju","getFullConnectivityMapFromCircuitJson","getFullConnectivityMapFromCircuitJson","getFullConnectivityMapFromCircuitJson","pointToSegmentDistance","getReadableNameForPcbPort","getFullConnectivityMapFromCircuitJson","PcbConnectivityMap","pointToSegmentDistance","distance","PcbConnectivityMap","getFullConnectivityMapFromCircuitJson","traceName","getReadableNameForPcbPort","cju","segmentToSegmentMinDistance","cju","distance","segmentToSegmentMinDistance","cju","getBoundsOfPcbElements","getPrimaryId","doBoundsOverlap","getFullConnectivityMapFromCircuitJson","getBoundsOfPcbElements","doBoundsOverlap","getBoundsOfPcbElements","doBoundsOverlap","getPrimaryId","getFullConnectivityMapFromCircuitJson","cju","getBoundsOfPcbElements","doBoundsOverlap","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","isPointInsidePolygon","getComponentName","isPointInsidePolygon","isCourtyardElement","isPointInsidePolygon"]}