#!/usr/bin/env python3 import re import math import gerbonara.cad.kicad.pcb as pcb r = 85 cx, cy = 150, 100 si_prefixes = {'k': 1e3, 'M': 1e6, 'G': 1e9, 'm': 1e-3, 'u': 1e-6, 'µ': 1e-6, 'n': 1e-9, 'p': 1e-12, '.': 1, 'r': 1} def parse_si(s, unit=''): if not (match := re.fullmatch(f'([0-9]*)(([.pPnNuUµmrRkKMgG])([0-9]*))?([pPnNuUµmrRkKMgG]?)({unit})?', s)): raise ValueError(f'{s} is not a valid number with an SI prefix') left, _1, dot, right, prefix, _unit = match.groups() prefix = prefix or dot or '.' multiplier = si_prefixes.get(prefix, si_prefixes.get(prefix.upper(), si_prefixes.get(prefix.lower()))) return float(f'{left}.{right or ""}0') * multiplier b = pcb.Board.open('self-balancing-test-a.kicad_pcb') b.unfill_zones() matches = list(b.find_footprints(name='Package_TO_SOT_SMD:SOT-23', sheetfile='resistor_bank.kicad_sch')) for i, fp in enumerate(matches): alpha = 2*math.pi * i/len(matches) fp.at.x, fp.at.y = cx+r, cy fp.set_rotation(0) fp.rotate(alpha, cx, cy) res1, res2 = fp.pads_by_number[3].find_connected(name='Resistor_SMD.*') if parse_si(res1.property_value('Value')) > parse_si(res2.property_value('Value')): res1, res2 = res2, res1 res1.at.x, res1.at.y = cx+r+5, cy+2 res1.set_rotation(0) res1.rotate(alpha, cx, cy) res2.at.x, res2.at.y = cx+r+5, cy-2 res2.set_rotation(0) res2.rotate(alpha, cx, cy) b.write('self-balancing-test-a.testout.kicad_pcb')