Files
kicad-zone-resistance/tests/test_geometry.py
T
janik 06c62e04f8 Initial import: KiCad zone resistance plugin
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>
2026-07-14 17:22:00 +07:00

89 lines
3.0 KiB
Python

import json
import math
import numpy as np
from fill_resistance.geometry import (arc_points, linearize_ring,
load_problem, problem_from_json,
save_problem)
from tests.util import make_multilayer, strip_problem
def test_arc_points_quarter_circle():
r = 10_000_000 # 10 mm in nm
start = (r, 0)
mid = (int(r / math.sqrt(2)), int(r / math.sqrt(2)))
end = (0, r)
tol = 50_000 # 50 um
pts = arc_points(start, mid, end, tol)
assert len(pts) >= 3
radii = np.hypot(pts[:, 0].astype(float), pts[:, 1].astype(float))
assert np.allclose(radii, r, rtol=1e-6)
allpts = np.vstack([pts, [end]]).astype(float)
for a, b in zip(allpts[:-1], allpts[1:]):
half_chord = np.hypot(*(b - a)) / 2
sagitta = r - math.sqrt(max(r**2 - half_chord**2, 0.0))
assert sagitta <= tol * 1.01
def test_arc_points_collinear_degrades_to_segment():
pts = arc_points((0, 0), (5_000_000, 0), (10_000_000, 0), 1000)
assert len(pts) == 1
assert tuple(pts[0]) == (0, 0)
def test_linearize_ring_mixed_nodes_and_closure():
nodes = [
("pt", (0, 0)),
("pt", (10, 0)),
("arc", ((10, 0), (17, 7), (10, 14))),
("pt", (0, 14)),
("pt", (0, 0)),
]
ring = linearize_ring(nodes, tol_nm=1)
assert (ring[0] != ring[-1]).any()
assert len(ring) > 4
def test_problem_json_roundtrip_v2(tmp_path):
p = make_multilayer(
[[([(0, 0), (10, 0), (10, 1), (0, 1)], [])],
[([(0, 0), (10, 0), (10, 1), (0, 1)], [])]],
rect1_mm=(0, 0, 1, 1), rect2_mm=(9, 0, 10, 1),
contact1="L0", contact2="L1", vias_mm=[(5.5, 0.5)])
f = tmp_path / "dump.json"
save_problem(p, f)
q = load_problem(f)
assert q.layer_names == ["L0", "L1"]
assert q.electrodes1[0].contact == "L0"
assert q.electrodes2[0].contact == "L1"
assert len(q.vias) == 1 and q.vias[0].drill_nm == p.vias[0].drill_nm
assert q.plating_nm == p.plating_nm
assert np.array_equal(q.layers[0].polygons[0].outline,
p.layers[0].polygons[0].outline)
assert abs(q.sigma_s(0) - p.sigma_s(0)) < 1e-12 * p.sigma_s(0)
def test_v1_schema_still_loads():
p = strip_problem()
v1 = {
"schema_version": 1,
"board_path": "old",
"layer_name": "F.Cu",
"net_name": "GND",
"thickness_nm": 70000,
"thickness_source": "stackup",
"rho_ohm_m": 1.68e-8,
"rect1": {"x0": 0, "y0": 0, "x1": 1000, "y1": 1000,
"layer_name": "User.1"},
"rect2": {"x0": 5000, "y0": 0, "x1": 6000, "y1": 1000,
"layer_name": "User.1"},
"polygons": [{"outline": p.layers[0].polygons[0].outline.tolist(),
"holes": []}],
}
q = problem_from_json(json.loads(json.dumps(v1)))
assert q.layer_names == ["F.Cu"]
assert q.vias == []
assert q.electrodes1[0].contact == "all"
assert q.layers[0].thickness_nm == 70000