imrishabh18/corne-keyboard

The code defines and renders two surface-mount chip components with SMT pads, silkscreen outlines, and 3D CAD models (OBJ and STEP) for PCB assembly.

Version
2.0.21
License
unset
Stars
1

vendor/checks/upstream.patch

diff --git a/lib/check-copper-to-board-edge-clearance.ts b/lib/check-copper-to-board-edge-clearance.ts
index c552c50..231ca3b 100644
--- a/lib/check-copper-to-board-edge-clearance.ts
+++ b/lib/check-copper-to-board-edge-clearance.ts
@@ -34,21 +34,26 @@ const pointsToPolygon = (
   return new Flatten.Polygon(points.map(({ x, y }) => new Flatten.Point(x, y)))
 }
 
-const brepRingToPolygon = (
+export const brepRingToPolygon = (
   vertices: Array<{ x: number; y: number; bulge?: number }>,
 ): Flatten.Polygon | null => {
-  const ring = vertices.filter((vertex, index) => {
-    const previous = vertices[index - 1]
-    return (
+  // Flatten rejects a line whose endpoints compare equal under its own
+  // tolerance. Use that same predicate before constructing polygon edges.
+  const ring: typeof vertices = []
+  for (const vertex of vertices) {
+    const previous = ring.at(-1)
+    if (
       !previous ||
-      Math.abs(previous.x - vertex.x) > GEOMETRY_EPSILON ||
-      Math.abs(previous.y - vertex.y) > GEOMETRY_EPSILON
-    )
-  })
+      !new Flatten.Point(previous.x, previous.y).equalTo(
+        new Flatten.Point(vertex.x, vertex.y),
+      )
+    ) ring.push(vertex)
+  }
   if (
     ring.length > 1 &&
-    Math.abs(ring[0].x - ring.at(-1)!.x) <= GEOMETRY_EPSILON &&
-    Math.abs(ring[0].y - ring.at(-1)!.y) <= GEOMETRY_EPSILON
+    new Flatten.Point(ring[0].x, ring[0].y).equalTo(
+      new Flatten.Point(ring.at(-1)!.x, ring.at(-1)!.y),
+    )
   ) {
     ring.pop()
   }
@@ -265,7 +270,7 @@ const pill = ({
   }
 }
 
-const getSmtPadGeometry = (pad: PcbSmtPad): CopperGeometry | null => {
+export const getSmtPadGeometry = (pad: PcbSmtPad): CopperGeometry | null => {
   switch (pad.shape) {
     case "circle":
       return {
@@ -315,7 +320,7 @@ const getSmtPadGeometry = (pad: PcbSmtPad): CopperGeometry | null => {
   }
 }
 
-const getPlatedHoleGeometry = (
+export const getPlatedHoleGeometry = (
   platedHole: PcbPlatedHole,
   componentCcwRotationDegrees: number,
 ): CopperGeometry | null => {
diff --git a/lib/check-each-pcb-port-connected-to-pcb-trace.ts b/lib/check-each-pcb-port-connected-to-pcb-trace.ts
index 7ac0cd0..a7c2d6b 100644
--- a/lib/check-each-pcb-port-connected-to-pcb-trace.ts
+++ b/lib/check-each-pcb-port-connected-to-pcb-trace.ts
@@ -10,6 +10,7 @@ import {
   getFullConnectivityMapFromCircuitJson,
   PcbConnectivityMap,
 } from "circuit-json-to-connectivity-map"
+import { CopperPourConnectivity } from "./util/copper-pour-connectivity"
 import { getReadableNameForPort } from "./util/get-readable-names"
 
 function checkEachPcbPortConnectedToPcbTraces(
@@ -32,6 +33,12 @@ function checkEachPcbPortConnectedToPcbTraces(
   // Generate the connectivity map from the circuit
   const connectivityMap = getFullConnectivityMapFromCircuitJson(circuitJson)
   const pcbConnectivityMap = new PcbConnectivityMap(circuitJson)
+  let pourConnectivity: CopperPourConnectivity | undefined
+  const getPourConnectivity = () =>
+    (pourConnectivity ??= new CopperPourConnectivity(
+      circuitJson,
+      connectivityMap,
+    ))
 
   // Create a map from source_port_id to pcb_port for quick lookup
   const sourcePortToPcbPort = new Map<string, PcbPort>()
@@ -58,7 +65,10 @@ function checkEachPcbPortConnectedToPcbTraces(
         pcbPort.pcb_port_id,
       )
 
-      if (connectedPcbTraces.length === 0) {
+      if (
+        connectedPcbTraces.length === 0 &&
+        !getPourConnectivity().portConnectedToPourNet(pcbPort.pcb_port_id)
+      ) {
         const connectedNetNames = sourceTrace.connected_source_net_ids
           .map((sourceNetId) => sourceNetNameById.get(sourceNetId))
           .filter((name): name is string => Boolean(name))
@@ -121,7 +131,12 @@ function checkEachPcbPortConnectedToPcbTraces(
       ),
     )
 
-    if (pcbTraceIds.length === 0) {
+    if (
+      pcbTraceIds.length === 0 &&
+      !getPourConnectivity().portsConnectedThroughPour(
+        pcbPortsInTrace.map((p) => p.pcb_port_id),
+      )
+    ) {
       // Check if this is a trivial case (only 2 ports on same component)
       const uniqueComponentIds = new Set(
         pcbPortsInTrace.map((p) => p.pcb_component_id),
diff --git a/lib/check-traces-are-contiguous/check-traces-are-contiguous.ts b/lib/check-traces-are-contiguous/check-traces-are-contiguous.ts
index 62534d0..632f54a 100644
--- a/lib/check-traces-are-contiguous/check-traces-are-contiguous.ts
+++ b/lib/check-traces-are-contiguous/check-traces-are-contiguous.ts
@@ -21,6 +21,7 @@ import {
   PcbConnectivityMap,
 } from "circuit-json-to-connectivity-map"
 import { getLayersOfPcbElement } from "../util/getLayersOfPcbElement"
+import { CopperPourConnectivity } from "../util/copper-pour-connectivity"
 import { endpointTouchesVia, getViaContactIndex } from "./via-contact-index"
 
 type PcbPortId = PcbPort["pcb_port_id"]
@@ -318,6 +319,12 @@ function checkTracesAreContiguous(
     )
     return viaContactIndex
   }
+  let pourConnectivity: CopperPourConnectivity | undefined
+  const getPourConnectivity = () =>
+    (pourConnectivity ??= new CopperPourConnectivity(
+      circuitJson,
+      getFullConnectivityMap(),
+    ))
   const checkedSourceTraceIds = new Set<string>()
 
   for (const pad of pcbSmtPads) {
@@ -491,7 +498,14 @@ function checkTracesAreContiguous(
           .get(candidateTrace.pcb_trace_id)
           ?.has(port.pcb_port_id),
       )
-      if (isConnectedByRoutedSourceTrace) continue
+      if (
+        isConnectedByRoutedSourceTrace ||
+        getPourConnectivity().traceConnectedToPortThroughPour(
+          trace.pcb_trace_id,
+          port.pcb_port_id,
+        )
+      )
+        continue
 
       const isFirstPointConnected = pads.some((pad) =>
         routePointTouchesPad(firstPoint, pad),
@@ -572,6 +586,11 @@ function checkTracesAreContiguous(
       const firstIsConnected =
         firstConnectsToAnyPad ||
         firstConnectsToLogicallyConnectedTraceCopper ||
+        getPourConnectivity().endpointTouchesConnectedPour(
+          firstPoint,
+          trace.pcb_trace_id,
+          firstEndpointTraceCopperWidth ?? 0,
+        ) ||
         (firstEndpointTraceCopperWidth !== undefined &&
           endpointTouchesVia({
             point: firstPoint,
@@ -583,6 +602,11 @@ function checkTracesAreContiguous(
       const lastIsConnected =
         lastConnectsToAnyPad ||
         lastConnectsToLogicallyConnectedTraceCopper ||
+        getPourConnectivity().endpointTouchesConnectedPour(
+          lastPoint,
+          trace.pcb_trace_id,
+          lastEndpointTraceCopperWidth ?? 0,
+        ) ||
         (lastEndpointTraceCopperWidth !== undefined &&
           endpointTouchesVia({
             point: lastPoint,
diff --git a/lib/util/copper-pour-connectivity.ts b/lib/util/copper-pour-connectivity.ts
new file mode 100644
index 0000000..b360193
--- /dev/null
+++ b/lib/util/copper-pour-connectivity.ts
@@ -0,0 +1,482 @@
+import * as Flatten from "@flatten-js/core"
+import type {
+  AnyCircuitElement,
+  PcbCopperPour,
+  PcbPort,
+  PcbTrace,
+  PcbPlatedHole,
+} from "circuit-json"
+import { getPrimaryId } from "@tscircuit/circuit-json-util"
+import type { ConnectivityMap } from "circuit-json-to-connectivity-map"
+import {
+  brepRingToPolygon,
+  getSmtPadGeometry,
+  getPlatedHoleGeometry,
+} from "../check-copper-to-board-edge-clearance"
+import {
+  getRotatedRectPoints,
+  getPillCenterLineForPad,
+} from "../check-each-pcb-trace-non-overlapping/segment-to-polygon-clearance"
+import { getLayersOfPcbElement } from "./getLayersOfPcbElement"
+import {
+  SpatialObjectIndex,
+  type Bounds,
+} from "../data-structures/SpatialIndex"
+
+type Shape = Flatten.Polygon | Flatten.Segment | Flatten.Point
+// A segment/point with a radius is exact constant-width trace/circular copper.
+type Geometry = { shape: Shape; radius: number }
+type Copper = Geometry & {
+  index: number
+  id: string
+  net: string
+  layers: string[]
+  bounds: Bounds
+  isPour: boolean
+  portId?: string
+}
+const EPSILON = 1e-9
+
+const polygonFromPoints = (points: { x: number; y: number }[]) =>
+  new Flatten.Polygon(points.map(({ x, y }) => new Flatten.Point(x, y)))
+
+function pourPolygon(pour: PcbCopperPour): Flatten.Polygon | undefined {
+  if (pour.shape === "polygon") return polygonFromPoints(pour.points)
+  if (pour.shape === "rect")
+    return polygonFromPoints(
+      getRotatedRectPoints({
+        x: pour.center.x,
+        y: pour.center.y,
+        width: pour.width,
+        height: pour.height,
+        ccwRotation: pour.rotation ?? 0,
+      }),
+    )
+  const polygon = brepRingToPolygon(pour.brep_shape.outer_ring.vertices)
+  if (!polygon) return
+  for (const ring of pour.brep_shape.inner_rings) {
+    const hole = brepRingToPolygon(ring.vertices)
+    // An unrecognized hole must not be silently turned into conducting copper.
+    if (!hole) return
+    for (const face of hole.faces) polygon.addFace(face.shapes)
+  }
+  return polygon
+}
+
+function capsulePolygon(
+  start: Flatten.Point,
+  end: Flatten.Point,
+  radius: number,
+): Flatten.Polygon {
+  if (start.distanceTo(end)[0] <= EPSILON)
+    return new Flatten.Polygon(new Flatten.Circle(start, radius))
+  const angle = Math.atan2(end.y - start.y, end.x - start.x) + Math.PI / 2
+  const dx = radius * Math.cos(angle),
+    dy = radius * Math.sin(angle)
+  return new Flatten.Polygon([
+    new Flatten.Segment(
+      new Flatten.Point(start.x + dx, start.y + dy),
+      new Flatten.Point(end.x + dx, end.y + dy),
+    ),
+    new Flatten.Arc(end, radius, angle, angle - Math.PI, false),
+    new Flatten.Segment(
+      new Flatten.Point(end.x - dx, end.y - dy),
+      new Flatten.Point(start.x - dx, start.y - dy),
+    ),
+    new Flatten.Arc(start, radius, angle - Math.PI, angle - 2 * Math.PI, false),
+  ])
+}
+
+function platedHoleDrill(pad: PcbPlatedHole): Flatten.Polygon | undefined {
+  const x = pad.x + ("hole_offset_x" in pad ? pad.hole_offset_x : 0)
+  const y = pad.y + ("hole_offset_y" in pad ? pad.hole_offset_y : 0)
+  if ("hole_diameter" in pad && pad.hole_diameter !== undefined)
+    return pad.hole_diameter > 0
+      ? new Flatten.Polygon(
+          new Flatten.Circle(new Flatten.Point(x, y), pad.hole_diameter / 2),
+        )
+      : undefined
+  if (
+    !("hole_width" in pad && "hole_height" in pad) ||
+    pad.hole_width === undefined ||
+    pad.hole_height === undefined
+  )
+    return undefined
+  const rotation =
+    "hole_ccw_rotation" in pad
+      ? pad.hole_ccw_rotation
+      : "ccw_rotation" in pad
+        ? (pad.ccw_rotation ?? 0)
+        : 0
+  const line = getPillCenterLineForPad({
+    type: "pcb_smtpad",
+    pcb_smtpad_id: "drill",
+    shape: "rotated_pill",
+    layer: "top",
+    x,
+    y,
+    width: pad.hole_width,
+    height: pad.hole_height,
+    radius: Math.min(pad.hole_width, pad.hole_height) / 2,
+    ccw_rotation: rotation,
+  })
+  return capsulePolygon(
+    new Flatten.Point(line.start.x, line.start.y),
+    new Flatten.Point(line.end.x, line.end.y),
+    line.radius,
+  )
+}
+
+function platedCopperPolygon(
+  geometry: NonNullable<ReturnType<typeof getSmtPadGeometry>>,
+  drill: Flatten.Polygon | undefined,
+): Flatten.Polygon {
+  const shapes =
+    geometry.kind === "pill"
+      ? [
+          capsulePolygon(
+            geometry.centerLine.start,
+            geometry.centerLine.end,
+            geometry.radius,
+          ),
+        ]
+      : geometry.shapes.map((s) =>
+          s instanceof Flatten.Circle ? new Flatten.Polygon(s) : s,
+        )
+  const outer = shapes.reduce((a, b) => Flatten.BooleanOperations.unify(a, b))
+  return drill ? Flatten.BooleanOperations.subtract(outer, drill) : outer
+}
+
+function representativePoints(shape: Shape): Flatten.Point[] {
+  if (shape instanceof Flatten.Point) return [shape]
+  if (shape instanceof Flatten.Segment) return [shape.start, shape.end]
+  return shape.vertices
+}
+
+function touches(a: Geometry, b: Geometry): boolean {
+  const aShape = a.shape,
+    bShape = b.shape
+  if (
+    aShape instanceof Flatten.Polygon &&
+    representativePoints(bShape).some((p) => aShape.contains(p))
+  )
+    return true
+  if (
+    bShape instanceof Flatten.Polygon &&
+    representativePoints(aShape).some((p) => bShape.contains(p))
+  )
+    return true
+  return a.shape.distanceTo(b.shape)[0] <= a.radius + b.radius + EPSILON
+}
+
+function bounds({ shape, radius }: Geometry): Bounds {
+  const box = shape.box
+  return {
+    minX: box.xmin - radius,
+    minY: box.ymin - radius,
+    maxX: box.xmax + radius,
+    maxY: box.ymax + radius,
+  }
+}
+
+function overlap(a: Bounds, b: Bounds) {
+  return (
+    a.minX <= b.maxX + EPSILON &&
+    a.maxX + EPSILON >= b.minX &&
+    a.minY <= b.maxY + EPSILON &&
+    a.maxY + EPSILON >= b.minY
+  )
+}
+
+/**
+ * Physical copper connectivity for nets containing a pour. Logical net IDs only
+ * select eligible copper; every union requires actual contact on a common layer.
+ * Pours remain separate islands, including their BRep holes and circular arcs.
+ */
+export class CopperPourConnectivity {
+  private nodes: Copper[] = []
+  private parents: number[] = []
+  private byId = new Map<string, Copper[]>()
+  private poursByNet = new Map<string, Copper[]>()
+  private portsByNet = new Map<string, PcbPort[]>()
+  private groupsWithPour = new Set<number>()
+  private groupsWithPort = new Set<number>()
+  private sourceNetByPort = new Map<string, string>()
+
+  constructor(
+    circuitJson: AnyCircuitElement[],
+    private connectivity: ConnectivityMap,
+  ) {
+    const pours = circuitJson.filter((e) => e.type === "pcb_copper_pour")
+    const netIds = new Set(
+      pours.map((p) =>
+        p.source_net_id
+          ? connectivity.getNetConnectedToId(p.source_net_id)
+          : undefined,
+      ),
+    )
+    netIds.delete(undefined)
+    const add = (
+      id: string,
+      layers: string[],
+      geometry: Geometry,
+      net: string | undefined,
+      isPour = false,
+      portId?: string,
+    ) => {
+      if (!net || !netIds.has(net)) return
+      const node: Copper = {
+        ...geometry,
+        index: this.nodes.length,
+        id,
+        layers,
+        net,
+        isPour,
+        portId,
+        bounds: bounds(geometry),
+      }
+      if (!Object.values(node.bounds).every(Number.isFinite)) return
+      this.nodes.push(node)
+      this.parents.push(node.index)
+      this.byId.set(id, [...(this.byId.get(id) ?? []), node])
+      if (isPour)
+        this.poursByNet.set(net, [...(this.poursByNet.get(net) ?? []), node])
+    }
+    const addShapes = (
+      id: string,
+      layers: string[],
+      geometry: ReturnType<typeof getSmtPadGeometry>,
+      net: string | undefined,
+      portId?: string,
+    ) => {
+      if (!geometry) return
+      if (geometry.kind === "pill")
+        add(
+          id,
+          layers,
+          { shape: geometry.centerLine, radius: geometry.radius },
+          net,
+          false,
+          portId,
+        )
+      else
+        for (const shape of geometry.shapes)
+          add(
+            id,
+            layers,
+            shape instanceof Flatten.Circle
+              ? { shape: shape.center, radius: shape.r }
+              : { shape, radius: 0 },
+            net,
+            false,
+            portId,
+          )
+    }
+    for (const element of circuitJson) {
+      if (element.type === "pcb_port") {
+        const net = connectivity.getNetConnectedToId(element.pcb_port_id)
+        if (net && netIds.has(net)) {
+          this.sourceNetByPort.set(element.pcb_port_id, net)
+          this.portsByNet.set(net, [
+            ...(this.portsByNet.get(net) ?? []),
+            element,
+          ])
+        }
+      }
+      if (element.type === "pcb_copper_pour") {
+        const polygon = pourPolygon(element)
+        if (polygon)
+          add(
+            element.pcb_copper_pour_id,
+            [element.layer],
+            { shape: polygon, radius: 0 },
+            element.source_net_id
+              ? connectivity.getNetConnectedToId(element.source_net_id)
+              : undefined,
+            true,
+          )
+      }
+      if (element.type === "pcb_smtpad" || element.type === "pcb_plated_hole") {
+        const id = getPrimaryId(element)
+        const net =
+          connectivity.getNetConnectedToId(id) ??
+          (element.pcb_port_id
+            ? connectivity.getNetConnectedToId(element.pcb_port_id)
+            : undefined)
+        if (!net || !netIds.has(net)) continue
+        const geometry =
+          element.type === "pcb_smtpad"
+            ? getSmtPadGeometry(element)
+            : getPlatedHoleGeometry(element, 0)
+        if (element.type === "pcb_plated_hole" && geometry) {
+          const copper = platedCopperPolygon(geometry, platedHoleDrill(element))
+          if (!copper.isEmpty())
+            add(
+              id,
+              getLayersOfPcbElement(element),
+              { shape: copper, radius: 0 },
+              net,
+              false,
+              element.pcb_port_id,
+            )
+        } else
+          addShapes(
+            id,
+            getLayersOfPcbElement(element),
+            geometry,
+            net,
+            element.pcb_port_id,
+          )
+      }
+      if (element.type === "pcb_via") {
+        const net =
+          connectivity.getNetConnectedToId(element.pcb_via_id) ??
+          (element.pcb_trace_id
+            ? connectivity.getNetConnectedToId(element.pcb_trace_id)
+            : undefined)
+        if (!net || !netIds.has(net) || element.outer_diameter <= 0) continue
+        const center = new Flatten.Point(element.x, element.y)
+        const outer = new Flatten.Polygon(
+          new Flatten.Circle(center, element.outer_diameter / 2),
+        )
+        const copper =
+          element.hole_diameter > 0
+            ? Flatten.BooleanOperations.subtract(
+                outer,
+                new Flatten.Polygon(
+                  new Flatten.Circle(center, element.hole_diameter / 2),
+                ),
+              )
+            : outer
+        if (!copper.isEmpty())
+          add(
+            element.pcb_via_id,
+            getLayersOfPcbElement(element),
+            { shape: copper, radius: 0 },
+            net,
+          )
+      }
+      if (element.type === "pcb_trace") {
+        // Interpolated traces need their actual variable-width outline. Do not
+        // infer a contact from the larger endpoint's circular cap.
+        if (element.route_thickness_mode === "interpolated") continue
+        const net = connectivity.getNetConnectedToId(element.pcb_trace_id)
+        if (!net || !netIds.has(net)) continue
+        for (let i = 1; i < element.route.length; i++) {
+          const a = element.route[i - 1]!,
+            b = element.route[i]!
+          if (
+            a.route_type !== "wire" ||
+            b.route_type !== "wire" ||
+            a.layer !== b.layer ||
+            a.width <= 0
+          )
+            continue
+          add(
+            element.pcb_trace_id,
+            [a.layer],
+            {
+              shape: new Flatten.Segment(
+                new Flatten.Point(a.x, a.y),
+                new Flatten.Point(b.x, b.y),
+              ),
+              radius: a.width / 2,
+            },
+            net,
+          )
+        }
+      }
+    }
+    const spatial = new SpatialObjectIndex<Copper>({
+      objects: this.nodes,
+      getBounds: (n) => n.bounds,
+      getId: (n) => String(n.index),
+      CELL_SIZE: 5,
+    })
+    for (const a of this.nodes) {
+      for (const b of spatial.getObjectsInBounds(a.bounds, EPSILON)) {
+        if (
+          b.index >= a.index ||
+          a.net !== b.net ||
+          !a.layers.some((l) => b.layers.includes(l)) ||
+          !overlap(a.bounds, b.bounds)
+        )
+          continue
+        if (this.root(a.index) === this.root(b.index)) continue
+        if (touches(a, b)) this.parents[this.root(a.index)] = this.root(b.index)
+      }
+    }
+    for (const node of this.nodes) {
+      if (node.isPour) this.groupsWithPour.add(this.root(node.index))
+      if (node.portId) this.groupsWithPort.add(this.root(node.index))
+    }
+  }
+
+  private root(index: number): number {
+    if (this.parents[index] !== index)
+      this.parents[index] = this.root(this.parents[index])
+    return this.parents[index]
+  }
+
+  private portGroups(portId: string): Set<number> {
+    return new Set(
+      this.nodes
+        .filter((n) => n.portId === portId)
+        .map((n) => this.root(n.index)),
+    )
+  }
+
+  /** A pour connection must physically reach the other required ports. */
+  portsConnectedThroughPour(portIds: string[]): boolean {
+    const first = portIds[0]
+    if (!first) return false
+    const groups = [...this.portGroups(first)].filter((group) =>
+      this.groupsWithPour.has(group),
+    )
+    return groups.some((group) =>
+      portIds.every((id) => this.portGroups(id).has(group)),
+    )
+  }
+
+  portConnectedToPourNet(portId: string): boolean {
+    const net = this.sourceNetByPort.get(portId)
+    if (!net) return false
+    const ports = this.portsByNet.get(net) ?? []
+    return (
+      ports.length > 0 &&
+      this.portsConnectedThroughPour(ports.map((p) => p.pcb_port_id))
+    )
+  }
+
+  traceConnectedToPortThroughPour(traceId: string, portId: string): boolean {
+    const groups = this.portGroups(portId)
+    return (this.byId.get(traceId) ?? []).some(
+      (node) =>
+        this.groupsWithPour.has(this.root(node.index)) &&
+        groups.has(this.root(node.index)),
+    )
+  }
+
+  endpointTouchesConnectedPour(
+    point: PcbTrace["route"][number],
+    traceId: string,
+    width: number,
+  ): boolean {
+    if (point.route_type !== "wire" || !Number.isFinite(width) || width < 0)
+      return false
+    const net = this.connectivity.getNetConnectedToId(traceId)
+    if (!net) return false
+    const endpoint = {
+      shape: new Flatten.Point(point.x, point.y),
+      radius: width / 2,
+    }
+    const endpointBounds = bounds(endpoint)
+    return (this.poursByNet.get(net) ?? []).some(
+      (pour) =>
+        pour.layers.includes(point.layer) &&
+        this.groupsWithPort.has(this.root(pour.index)) &&
+        overlap(endpointBounds, pour.bounds) &&
+        touches(endpoint, pour),
+    )
+  }
+}
diff --git a/tests/lib/copper-pour-connectivity.test.ts b/tests/lib/copper-pour-connectivity.test.ts
new file mode 100644
index 0000000..e2539c5
--- /dev/null
+++ b/tests/lib/copper-pour-connectivity.test.ts
@@ -0,0 +1,459 @@
+import { describe, expect, test } from "bun:test"
+import type { AnyCircuitElement, PcbCopperPour, PcbTrace } from "circuit-json"
+import { checkEachPcbPortConnectedToPcbTraces } from "lib/check-each-pcb-port-connected-to-pcb-trace"
+import { CopperPourConnectivity } from "lib/util/copper-pour-connectivity"
+import { getFullConnectivityMapFromCircuitJson } from "circuit-json-to-connectivity-map"
+import { checkTracesAreContiguous } from "lib/check-traces-are-contiguous/check-traces-are-contiguous"
+
+type Layer = "top" | "bottom"
+const net = "source_net_ground"
+const wire = (
+  x: number,
+  y: number,
+  layer: Layer = "bottom",
+): PcbTrace["route"][number] => ({
+  route_type: "wire",
+  x,
+  y,
+  layer,
+  width: 0.1,
+})
+function pad(
+  id: string,
+  x: number,
+  y: number,
+  layer: Layer = "bottom",
+  sourceNetId = net,
+): AnyCircuitElement[] {
+  return [
+    {
+      type: "source_trace",
+      source_trace_id: `source_trace_${id}`,
+      connected_source_port_ids: [`source_port_${id}`],
+      connected_source_net_ids: [sourceNetId],
+    },
+    {
+      type: "pcb_port",
+      pcb_port_id: `pcb_port_${id}`,
+      source_port_id: `source_port_${id}`,
+      pcb_component_id: `pcb_component_${id}`,
+      x,
+      y,
+      layers: [layer],
+    },
+    {
+      type: "pcb_smtpad",
+      pcb_smtpad_id: `pcb_smtpad_${id}`,
+      pcb_port_id: `pcb_port_${id}`,
+      pcb_component_id: `pcb_component_${id}`,
+      shape: "rect",
+      x,
+      y,
+      width: 0.3,
+      height: 0.3,
+      layer,
+    },
+  ]
+}
+function rect(
+  id: string,
+  x: number,
+  y: number,
+  width = 2,
+  height = 2,
+  layer: Layer = "bottom",
+  sourceNetId = net,
+): PcbCopperPour {
+  return {
+    type: "pcb_copper_pour",
+    covered_with_solder_mask: true,
+    pcb_copper_pour_id: `pcb_copper_pour_${id}`,
+    shape: "rect",
+    center: { x, y },
+    width,
+    height,
+    layer,
+    source_net_id: sourceNetId,
+  }
+}
+function trace(
+  route: PcbTrace["route"],
+  sourceNetId = net,
+): AnyCircuitElement[] {
+  return [
+    {
+      type: "source_trace",
+      source_trace_id: "source_trace_bridge",
+      connected_source_port_ids: [],
+      connected_source_net_ids: [sourceNetId],
+    },
+    {
+      type: "pcb_trace",
+      pcb_trace_id: "pcb_trace_bridge",
+      source_trace_id: "source_trace_bridge",
+      route,
+    },
+  ]
+}
+const endpointErrors = (circuit: AnyCircuitElement[]) =>
+  checkTracesAreContiguous(circuit).filter(
+    (e) => e.pcb_trace_id === "pcb_trace_bridge",
+  )
+function rectangleVertices(x: number, y: number, half: number) {
+  return [
+    { x: x - half, y: y - half },
+    { x: x + half, y: y - half },
+    { x: x + half, y: y + half },
+    { x: x - half, y: y + half },
+  ]
+}
+function holedPour(): PcbCopperPour {
+  return {
+    type: "pcb_copper_pour",
+    covered_with_solder_mask: true,
+    pcb_copper_pour_id: "pcb_copper_pour_hole",
+    source_net_id: net,
+    shape: "brep",
+    layer: "bottom",
+    brep_shape: {
+      outer_ring: { vertices: rectangleVertices(0, 0, 4) },
+      inner_rings: [{ vertices: rectangleVertices(0, 0, 1) }],
+    },
+  }
+}
+
+describe("physical copper-pour connectivity", () => {
+  test("connects port-to-net traces through same-layer copper with no PCB traces", () => {
+    expect(
+      checkEachPcbPortConnectedToPcbTraces([
+        ...pad("a", -1, 0),
+        ...pad("b", 1, 0),
+        rect("all", 0, 0, 4, 2),
+      ]),
+    ).toEqual([])
+  })
+
+  test("connects an explicit two-port source trace entirely through a pour", () => {
+    const circuit: AnyCircuitElement[] = [
+      ...pad("a", -1, 0),
+      ...pad("b", 1, 0),
+      rect("all", 0, 0, 4, 2),
+    ].filter((e) => e.type !== "source_trace")
+    circuit.push({
+      type: "source_trace",
+      source_trace_id: "source_trace_pair",
+      connected_source_port_ids: ["source_port_a", "source_port_b"],
+      connected_source_net_ids: [net],
+    })
+    expect(checkEachPcbPortConnectedToPcbTraces(circuit)).toEqual([])
+  })
+
+  test("does not connect two separate islands just because they have the same net ID", () => {
+    expect(
+      checkEachPcbPortConnectedToPcbTraces([
+        ...pad("a", -2, 0),
+        ...pad("b", 2, 0),
+        rect("left", -2, 0),
+        rect("right", 2, 0),
+      ]),
+    ).toHaveLength(2)
+  })
+
+  test.each(["wrong net", "wrong layer"])(
+    "does not connect a pad using a pour on the %s",
+    (reason) => {
+      expect(
+        checkEachPcbPortConnectedToPcbTraces([
+          ...pad("a", 0, 0),
+          rect(
+            "wrong",
+            0,
+            0,
+            2,
+            2,
+            reason === "wrong layer" ? "top" : "bottom",
+            reason === "wrong net" ? "source_net_other" : net,
+          ),
+        ]),
+      ).toHaveLength(1)
+    },
+  )
+
+  test("keeps a pad entirely inside a BRep hole disconnected", () => {
+    expect(
+      checkEachPcbPortConnectedToPcbTraces([
+        ...pad("a", 0, 0),
+        ...pad("b", 2, 0),
+        holedPour(),
+      ]),
+    ).toHaveLength(2)
+  })
+
+  test("joins islands through actual same-layer trace copper", () => {
+    const circuit = [
+      ...pad("a", -2, 0),
+      ...pad("b", 2, 0),
+      rect("left", -2, 0),
+      rect("right", 2, 0),
+      ...trace([wire(-1.5, 0), wire(1.5, 0)]),
+    ]
+    expect(checkEachPcbPortConnectedToPcbTraces(circuit)).toEqual([])
+    expect(endpointErrors(circuit)).toEqual([])
+  })
+
+  test("does not join islands through a bridge on the wrong layer", () => {
+    const circuit = [
+      ...pad("a", -2, 0),
+      ...pad("b", 2, 0),
+      rect("left", -2, 0),
+      rect("right", 2, 0),
+      ...trace([wire(-1.5, 0, "top"), wire(1.5, 0, "top")]),
+    ]
+    expect(checkEachPcbPortConnectedToPcbTraces(circuit)).toHaveLength(2)
+    expect(endpointErrors(circuit)).toHaveLength(2)
+  })
+
+  test("joins top and bottom pours through a plated via", () => {
+    const circuit: AnyCircuitElement[] = [
+      ...pad("a", -2, 0, "top"),
+      ...pad("b", 2, 0),
+      rect("left", -1, 0, 4, 2, "top"),
+      rect("right", 1, 0, 4, 2),
+      ...trace([wire(-0.5, 0, "top"), wire(0, 0, "top")]),
+      {
+        type: "pcb_via",
+        pcb_via_id: "pcb_via_bridge",
+        pcb_trace_id: "pcb_trace_bridge",
+        x: 0,
+        y: 0,
+        outer_diameter: 0.4,
+        hole_diameter: 0.2,
+        layers: ["top", "bottom"],
+      },
+    ]
+    expect(checkEachPcbPortConnectedToPcbTraces(circuit)).toEqual([])
+    expect(
+      checkEachPcbPortConnectedToPcbTraces(
+        circuit.filter((e) => e.type !== "pcb_via"),
+      ),
+    ).toHaveLength(2)
+  })
+
+  test("recognizes a pour contact at an endpoint directly adjacent to a via", () => {
+    const circuit = [
+      ...pad("a", -2, 0),
+      rect("all", 0, 0, 6, 4),
+      ...trace([
+        wire(-2, 0),
+        {
+          route_type: "via",
+          x: -2,
+          y: 0,
+          from_layer: "bottom",
+          to_layer: "top",
+          outer_diameter: 0.4,
+        },
+        wire(-2, 0, "top"),
+        wire(0, 0, "top"),
+        {
+          route_type: "via",
+          x: 0,
+          y: 0,
+          from_layer: "top",
+          to_layer: "bottom",
+          outer_diameter: 0.4,
+        },
+        wire(0, 0),
+      ]),
+    ]
+    expect(endpointErrors(circuit)).toEqual([])
+  })
+
+  test("preserves a real floating endpoint even when another part of the net reaches a pour", () => {
+    const circuit = [
+      ...pad("a", -2, 0),
+      rect("left", -2, 0),
+      ...trace([wire(-2, 0), wire(0, 0)]),
+    ]
+    expect(endpointErrors(circuit).map((e) => e.pcb_trace_error_id)).toEqual([
+      "disconnected_endpoint_pcb_trace_bridge_end",
+    ])
+  })
+
+  test("keeps an endpoint inside a BRep hole disconnected", () => {
+    const circuit = [
+      ...pad("a", -2, 0),
+      holedPour(),
+      ...trace([wire(-2, 0), wire(0, 0)]),
+    ]
+    expect(endpointErrors(circuit).map((e) => e.pcb_trace_error_id)).toEqual([
+      "disconnected_endpoint_pcb_trace_bridge_end",
+    ])
+  })
+
+  test("does not treat a floating pour and trace loop as a pad connection", () => {
+    const circuit = [
+      ...pad("a", -4, 0),
+      rect("floating", 0, 0),
+      ...trace([wire(-0.5, 0), wire(0.5, 0)]),
+    ]
+    expect(endpointErrors(circuit)).toHaveLength(2)
+    expect(checkEachPcbPortConnectedToPcbTraces(circuit)).toHaveLength(1)
+  })
+
+  test.each(["wrong net", "wrong layer"])(
+    "keeps endpoint contact with the %s as a real error",
+    (reason) => {
+      const circuit = [
+        ...pad("a", -2, 0),
+        ...pad(
+          "b",
+          0,
+          0.5,
+          reason === "wrong layer" ? "top" : "bottom",
+          reason === "wrong net" ? "source_net_other" : net,
+        ),
+        rect(
+          "wrong",
+          0,
+          0,
+          2,
+          2,
+          reason === "wrong layer" ? "top" : "bottom",
+          reason === "wrong net" ? "source_net_other" : net,
+        ),
+        ...trace([wire(-2, 0), wire(0, 0)]),
+      ]
+      expect(endpointErrors(circuit).map((e) => e.pcb_trace_error_id)).toEqual([
+        "disconnected_endpoint_pcb_trace_bridge_end",
+      ])
+    },
+  )
+
+  test("follows a routed trace through the pour to its expected destination pad", () => {
+    const circuit = [
+      ...pad("a", -3, 0),
+      ...pad("b", 1, 0),
+      rect("right", 1, 0, 3, 2),
+      ...trace([wire(-3, 0), wire(0, 0)]),
+    ]
+    const source = circuit.find(
+      (e) =>
+        e.type === "source_trace" &&
+        e.source_trace_id === "source_trace_bridge",
+    )!
+    if (source.type === "source_trace")
+      source.connected_source_port_ids = ["source_port_a", "source_port_b"]
+    expect(endpointErrors(circuit)).toEqual([])
+    expect(
+      endpointErrors(circuit.filter((e) => e.type !== "pcb_copper_pour")),
+    ).toHaveLength(1)
+  })
+})
+
+describe("copper region holes and arcs", () => {
+  test.each(["via", "plated pad"])(
+    "does not bridge copper through the empty drill of a %s",
+    (kind) => {
+      const circuit: AnyCircuitElement[] = [
+        ...pad("a", 0, 0),
+        ...pad("b", 2, 0, "top"),
+        rect("top", 1, 0, 4, 2, "top"),
+        ...trace([wire(1, 0, "top"), wire(2, 0, "top")]),
+      ]
+      if (kind === "via")
+        circuit.push({
+          type: "pcb_via",
+          pcb_via_id: "pcb_via_annular",
+          pcb_trace_id: "pcb_trace_bridge",
+          x: 0,
+          y: 0,
+          outer_diameter: 2,
+          hole_diameter: 1,
+          layers: ["top", "bottom"],
+        })
+      else
+        circuit.push(
+          ...pad("annular", 0, 0).filter((e) => e.type !== "pcb_smtpad"),
+          {
+            type: "pcb_plated_hole",
+            pcb_plated_hole_id: "pcb_plated_hole_annular",
+            pcb_port_id: "pcb_port_annular",
+            shape: "circle",
+            x: 0,
+            y: 0,
+            outer_diameter: 2,
+            hole_diameter: 1,
+            layers: ["top", "bottom"],
+          },
+        )
+      const graph = new CopperPourConnectivity(
+        circuit,
+        getFullConnectivityMapFromCircuitJson(circuit),
+      )
+      expect(
+        graph.portsConnectedThroughPour(["pcb_port_a", "pcb_port_b"]),
+      ).toBe(false)
+    },
+  )
+
+  test("retains curved BRep copper between an arc and its chord", () => {
+    const bulge = Math.tan(Math.PI / 8)
+    const pour: PcbCopperPour = {
+      type: "pcb_copper_pour",
+      covered_with_solder_mask: true,
+      pcb_copper_pour_id: "pcb_copper_pour_curved",
+      source_net_id: net,
+      layer: "bottom",
+      shape: "brep",
+      brep_shape: {
+        outer_ring: {
+          vertices: [
+            { x: 2, y: 0, bulge },
+            { x: 0, y: 2, bulge },
+            { x: -2, y: 0, bulge },
+            { x: 0, y: -2, bulge },
+          ],
+        },
+        inner_rings: [],
+      },
+    }
+    expect(
+      checkEachPcbPortConnectedToPcbTraces([
+        ...pad("a", 0, 0),
+        ...pad("b", 1.3, 1.3),
+        pour,
+      ]),
+    ).toEqual([])
+    expect(
+      checkEachPcbPortConnectedToPcbTraces([
+        ...pad("a", 0, 0),
+        ...pad("b", 1.6, 1.6),
+        pour,
+      ]),
+    ).toHaveLength(2)
+  })
+
+  test("never equates a polygon pour bounding box with its copper", () => {
+    const pour: PcbCopperPour = {
+      type: "pcb_copper_pour",
+      covered_with_solder_mask: true,
+      pcb_copper_pour_id: "pcb_copper_pour_triangle",
+      source_net_id: net,
+      layer: "bottom",
+      shape: "polygon",
+      points: [
+        { x: -2, y: -2 },
+        { x: 2, y: -2 },
+        { x: -2, y: 2 },
+      ],
+    }
+    expect(
+      checkEachPcbPortConnectedToPcbTraces([
+        ...pad("a", -1, -1),
+        ...pad("b", 1, 1),
+        pour,
+      ]),
+    ).toHaveLength(2)
+  })
+})
diff --git a/tests/lib/brep-short-edge.test.ts b/tests/lib/brep-short-edge.test.ts
new file mode 100644
index 0000000..73372c6
--- /dev/null
+++ b/tests/lib/brep-short-edge.test.ts
@@ -0,0 +1,18 @@
+import { expect, test } from "bun:test"
+import Flatten from "@flatten-js/core"
+import { brepRingToPolygon } from "../../lib/check-copper-to-board-edge-clearance"
+
+test("pour edges below the geometry library tolerance do not crash distance checks", () => {
+  const polygon = brepRingToPolygon([
+    { x: 0, y: 0 },
+    { x: 2, y: 0 },
+    { x: 2, y: 0.0000008 },
+    { x: 2, y: 2 },
+    { x: 0, y: 2 },
+    { x: 0.0000008, y: 0.0000008 },
+  ])!
+  const obstacle = new Flatten.Circle(new Flatten.Point(3, 0.0000004), 0.2)
+  expect(polygon.distanceTo(obstacle)[0]).toBeCloseTo(0.8, 6)
+  expect(polygon.contains(new Flatten.Point(1, 1))).toBe(true)
+  expect(polygon.contains(new Flatten.Point(3, 1))).toBe(false)
+})