A single <copperpour> whose fill is split by traces produces one pcb_copper_pour record per disjoint fill fragment, and the KiCad exporter (correctly, given its input) emits one (zone) per record. On a real board we got 65+ GND zones from one pour. Minimal repro (a full-width trace splits the pour; GND anchors on both sides keep both fragments):
export default () => (
<board width="20mm" height="20mm">
<resistor name="R1" resistance="1k" footprint="0402" pcbX={-9} pcbY={-5} />
<resistor name="R2" resistance="1k" footprint="0402" pcbX={9} pcbY={-5} />
<resistor name="R3" resistance="1k" footprint="0402" pcbX={0} pcbY={5} />
<trace from=".R1 > .pin2" to=".R2 > .pin1" />
<trace from=".R3 > .pin1" to="net.GND" />
<via connectsTo="net.GND" holeDiameter="0.3mm" outerDiameter="0.6mm"
fromLayer="top" toLayer="bottom" pcbX={0} pcbY={-8} />
<copperpour connectsTo="net.GND" layer="top" clearance="0.3mm" />
</board>
)
Circuit json: 2 pcb_copper_pour records (brep outer rings spanning y[-9.7,-5.38] and y[-4.62,9.7]). KiCad export: 2 zones, each (net_name GND), each outline being one fragment's computed fill shape.
Expected: one zone per <copperpour> whose outline is the requested pour region, with the fill left for KiCad to compute.
Why it matters: in KiCad the zone outline is design intent and the fill is derived. With outline == previous fill fragment, any refill (edit + B, or a pcbnew script) reapplies clearances inside the already-shrunk outline, so copper shrinks every refill and fragments that split further are deleted as islands. Dozens of independent zones per pour also make the file uneditable, and a script that unions fragments into one zone cannot save the result (a KiCad zone keeps a single outline).
Cause: CopperPour.doInitialPcbCopperPourRender (lib/components/primitive-components/CopperPour/CopperPour.ts:73-87) inserts one record per solver brep_shape, drops the source region, and the records carry no id linking them to the pour element, so downstream cannot even union them per pour.
Suggested fix: store the requested pour region on the pcb_copper_pour (one record per pour element), with the solver's computed fragments in a separate fill field or in records referencing the pour id, so viewers render fills while exporters emit the region.
A single
<copperpour>whose fill is split by traces produces onepcb_copper_pourrecord per disjoint fill fragment, and the KiCad exporter (correctly, given its input) emits one(zone)per record. On a real board we got 65+ GND zones from one pour. Minimal repro (a full-width trace splits the pour; GND anchors on both sides keep both fragments):Circuit json: 2
pcb_copper_pourrecords (brep outer rings spanning y[-9.7,-5.38] and y[-4.62,9.7]). KiCad export: 2 zones, each(net_name GND), each outline being one fragment's computed fill shape.Expected: one zone per
<copperpour>whose outline is the requested pour region, with the fill left for KiCad to compute.Why it matters: in KiCad the zone outline is design intent and the fill is derived. With outline == previous fill fragment, any refill (edit + B, or a pcbnew script) reapplies clearances inside the already-shrunk outline, so copper shrinks every refill and fragments that split further are deleted as islands. Dozens of independent zones per pour also make the file uneditable, and a script that unions fragments into one zone cannot save the result (a KiCad zone keeps a single outline).
Cause:
CopperPour.doInitialPcbCopperPourRender(lib/components/primitive-components/CopperPour/CopperPour.ts:73-87) inserts one record per solverbrep_shape, drops the source region, and the records carry no id linking them to the pour element, so downstream cannot even union them per pour.Suggested fix: store the requested pour region on the
pcb_copper_pour(one record per pour element), with the solver's computed fragments in a separate fill field or in records referencing the pour id, so viewers render fills while exporters emit the region.