On OK the dialog closed and nothing appeared until the figures did,
which on a real board is minutes of looking like the plugin did
nothing. Put a small always-on-top window up for that stretch: the
stage now running, elapsed seconds, and Cancel.
Qt only repaints while the event loop runs and the solve owns the
thread, so the window pumps events itself - from inside the CG/AMG
iteration callback, which is where the time actually goes. That is
also where Cancel is noticed. The state is module-level because the
tick happens several frames deep in scipy/pyamg, and threading a
handle through those signatures for a progress bar is not worth it;
it stays inert until start(), so the standalone runner and the tests
are unaffected.
The window covers the figure work too, not just the solve: laying out
labels and writing four PNGs at full DPI is seconds on a real board -
10-15 of them on a large one - and closing before that left the same
silent gap one step later.
After a solve, the per-layer current-density maps can be pushed into
the open board as reference images on User.9..User.12 (stackup order,
top first) - visible right in the editor, toggled like any layer,
never plotted to gerbers. Dialog checkbox, default OFF; every push
replaces all reference images on those layers.
Rendering (fill_resistance/overlay.py, KiCad-free and tested headless):
one pixel per grid cell, opaque over copper with the log scale lifted
off the colormap's near-black bottom (dark canvas), transparent
elsewhere, one pixel of half-alpha edge bleed so the overlay reaches
the drawn outline instead of stopping half a cell short. Pushing lives
in board_io (ReferenceImage via the IPC API, KiCad >= 10.0.1; scale =
width / (pixels * 1 inch / 300 PPI), position = image center); kipy
0.7.1 swallows creation errors, so the per-item status is read from
the raw CreateItemsResponse. pipeline.run takes an optional overlay
callback; failures are reported, never fatal.
tools/kicad_overlay_test.py pushes a fiducial alignment pattern (KiCad
bbox readback verified placement to half a pixel); tools/
kicad_heatmap_overlay.py runs the whole thing headless against the
open board, filtering marker rectangles of other nets' analyses via
the exact copper test.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Refuse the uniform contact model when the fills form multiple
disconnected copper groups that each touch both terminals: the
prescribed injection split is ill-posed and the grounded system was
singular, silently returning garbage (e.g. negative gigaohms).
connected_restrict now reports the component count; a power-balance
backstop (SolverError) catches any other inconsistent solve.
- Connect via/pad barrels to the nearest fill copper within the pad
footprint (+1 cell) instead of only the exact center cell, so
thermal-relief spokes still stitch layers; barrels that reach fill on
fewer than two layers are warned about. ViaLink gains pad_nm
(extracted from the padstack, JSON-roundtripped).
- Validate dialog input on OK (layers, current > 0, cell > 0, parseable
frequency, extra Cu >= 0) with an inline error instead of silently
substituting defaults; parse_frequency raises on garbage; pipeline
rejects i_test <= 0; choose_cell_size rejects non-positive overrides.
- Warn when a contact part is dropped by the connectivity restriction;
floor instead of truncate in cell_of; correct the uniform-model
summary line; drop an unused variable; refresh plugin.json wording.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
DC/AC resistance, power dissipation, and via/injection-area currents of
copper zone fills. KiCad 10 IPC-API plugin (kicad-python/kipy):
multi-layer via-coupled FDM solver, multi-part terminals via User.1/User.2
marker layers, pads as contacts, uniform-injection and equipotential
contact models, per-foil skin effect, optional solder/copper buildup on
mask openings. 54-case test suite incl. exact analytic references.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>