AnasSarkiz/NEMA14_RP2040
A NEMA motor assembly concept with a controller board, four proposed M3 screws and spacers, motor lead splices, and a JST 4-pin connector harness.
- Version
- 1.13.0
- License
- ISC
- Stars
- 0
scripts/prune-redundant-copper.py
"""Remove redundant ordinary copper only on physically complete nets."""
import json,math,hashlib
import verify_supplier_connectivity as g
removed=[];skipped=[]
def signature(net):
es,rs=g.groups(net);sets={}
for e,r in zip(es,rs):
if e.get('pcb_port_id'):sets.setdefault(r,set()).add(e['pcb_port_id'])
return sorted(tuple(sorted(v)) for v in sets.values())
def length(t,layer=None):
return sum(math.dist((a['x'],a['y']),(b['x'],b['y'])) for a,b in zip(t['route'],t['route'][1:]) if a['route_type']==b['route_type']=='wire' and a['layer']==b['layer'] and (layer is None or a['layer']==layer))
for net,name in g.nets.items():
if name in ['GND','USB_DP','USB_DM','MCU_DP','MCU_DM','XIN','XOUT','XTAL_OUT']:continue
sig=signature(net)
if len(sig)!=1:skipped.append(name);continue
candidates=[e for e in g.j if e['type']=='pcb_trace' and g.key(e)==net and not e['pcb_trace_id'].startswith(('usb_','oscillator_','reviewed_local_','review_escape_'))]
for e in sorted(candidates,key=lambda t:(length(t,'inner1'),length(t)),reverse=True):
i=g.j.index(e);g.j.pop(i)
if signature(net)==sig:removed.append({'trace':e['pcb_trace_id'],'net':name,'length_mm':length(e),'inner1_mm':length(e,'inner1')})
else:g.j.insert(i,e)
g.path.write_text(json.dumps(g.j,indent=2)+'\n');out=g.ROOT/'artifacts/opposite-edge/redundant-copper-pruning.json';history=json.loads(out.read_text()) if out.exists() else [];history.append({'removed':removed,'open_nets_left_untouched':skipped,'actual_pad_partitions_preserved':True,'board_sha256':hashlib.sha256(g.path.read_bytes()).hexdigest()});out.write_text(json.dumps(history,indent=2)+'\n');print('Removed redundant traces',len(removed),'sum mm',sum(e['length_mm'] for e in removed),'inner1',sum(e['inner1_mm'] for e in removed),flush=True)