copperpour: two same-layer pours on different nets each fill the whole board (silent short)
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 58
- Forks
- 203
- Avg merge
- 7h 39m
- Merged PRs (30d)
- 286
Description
Summary
Two <copperpour> elements on the same layer connected to different nets each fill essentially the whole board. Each pour carves out only the other net's pads, not the other pour, so the two copper regions overlap across almost the entire board and the two nets end up physically connected. No error or warning is emitted.
Reproduced on core at c2441aa1 with @tscircuit/copper-pour-solver 0.0.42.
Repro
import { getTestFixture } from "tests/fixtures/get-test-fixture"
const { circuit } = getTestFixture()
circuit.add(
<board width="20mm" height="14mm">
<net name="GND" />
<net name="VCC" />
<resistor
name="R1"
resistance="10k"
footprint="0805"
pcbX={0}
pcbY={0}
connections={{ pin1: "net.VCC", pin2: "net.GND" }}
/>
<copperpour connectsTo="net.GND" layer="top" />
<copperpour connectsTo="net.VCC" layer="top" />
</board>,
)
await circuit.renderUntilSettled()
Rendering each pour on its own shows each one covering the full board, with only a small notch bitten out around the other net's pad.
Measurement
Sampling a 200x140 grid over the board interior:
- default outlines (above): 2 pours (GND, VCC). 93.4% of the board is covered by both nets at once, 95.2% by at least one. That 93.4% shared area is a direct GND to VCC short.
- explicit disjoint outlines (below): 0% overlap.
Control that behaves correctly, GND on the left half and VCC on the right:
<copperpour connectsTo="net.GND" layer="top"
outline={[{x:-9,y:-6},{x:-1,y:-6},{x:-1,y:6},{x:-9,y:6}]} />
<copperpour connectsTo="net.VCC" layer="top"
outline={[{x:1,y:-6},{x:9,y:-6},{x:9,y:6},{x:1,y:6}]} />
This mirrors tests/components/primitive-components/copperpour-multiple-outlines.test.tsx, so multi-pour on one layer works when each pour has its own non-overlapping outline. The failure is specific to the default full-board fill.
Root cause
CopperPour.doInitialPcbCopperPourRender() (in lib/components/primitive-components/CopperPour/CopperPour.ts) queues one async effect per pour. Each effect snapshots db.toArray() and calls convertCircuitJsonToInputProblem(circuitJson, { source_net_id: <own net>, ... }) from @tscircuit/copper-pour-solver, then inserts the resulting shapes.
Inside the solver, the pour region is the full board (or the given outline) and the only obstacles subtracted are the pads, traces, holes, cutouts and vias whose connectivity key differs from the pour's own net. Existing pcb_copper_pour records are never read, so one pour is never a keep-out for another. With the default full-board outline, both pours fill the whole board minus the other net's pads and so overlap everywhere else.
The two async effects also each read db independently, so neither sees the other's output regardless of render order.
Suggested direction
Two options, happy to send a PR for whichever matches the intended design:
- Handle same-layer contention in
@tscircuit/copper-pour-solver: when more than one region on a layer belongs to different nets, partition the shared area (nearest-net or an explicit pour priority) so the pours do not overlap. - Or keep explicit outlines as the supported way to place multiple planes on one layer, then add a guard in core: when two same-layer pours on different nets both use the default outline, emit a warning or error that points at
outlinerather than silently producing a short.
Either way, a physical short that renders with no diagnostic seems worth surfacing.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in lib/components/primitive-components/CopperPour/CopperPour.ts and reproduce with the provided two-pour example; compare it with tests/components/primitive-components/copperpour-multiple-outlines.test.tsx. Determine whether same-layer default pours should be partitioned or rejected, then add coverage so different-net pours cannot silently overlap and either produce separate regions or a clear diagnostic.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100