app
Fusion - the Fusion 360 Bridge
Public Made by Adomby adom
Drive Autodesk Fusion 360 from the cloud via Adom Bridge: component libraries, IPC package generation, board layout, exports (STEP/Gerbers/BOM/CPL), fast APS cloud search, and parametric modeling.
master
John Lauer
Add native thermal-pour expansion experiment, finite-difference comparison and recording scripts
33c4ac5
1mo ago
import json,math,xml.etree.ElementTree as ET
from collections import Counter
from shapely.geometry import box
from shapely.ops import unary_union
from analyze import P,regions,copper
base=P.parent/'thermal/recording-02/bq25792-astra-thermal-routed.brd';final=P/'recording/bq25792-expanded-thermal.brd';candidate=P/'expansion-03/expansion-03-filled.brd'
def primitives(f,kind):
b=ET.parse(f).find('drawing/board');out=[]
attrs=['x1','y1','x2','y2','width','layer','curve'] if kind=='wire' else ['x','y','diameter','drill','extent']
for s in b.findall('signals/signal'):
for e in s.findall(kind):
values=[]
for k in attrs:
v=e.get(k,'0')
try:v=round(float(v),6)
except ValueError:pass
values.append(v)
out.append((s.get('name'),*values))
return Counter(out)
for kind in ['wire','via']:assert primitives(base,kind)==primitives(final,kind),kind
for n,r in regions(final).items():assert r['geometry'].symmetric_difference(regions(candidate)[n]['geometry']).area<1e-4,n
b=ET.parse(final).find('drawing/board');off=[]
for s in b.findall('signals/signal'):
for w in s.findall('wire'):
a=math.degrees(math.atan2(float(w.get('y2'))-float(w.get('y1')),float(w.get('x2'))-float(w.get('x1'))))%180
if abs(a-round(a/45)*45)>.02:off.append(w.attrib)
assert not off
coverage={}
for tag,f in [('before',base),('after',final)]:
coverage[tag]={str(l):unary_union(list(copper(f,l).values())).intersection(box(0,0,50.4,26.4)).area/(50.4*26.4)*100 for l in [1,2,15,16]}
drc=json.loads((P/'recording/final-drc.json').read_text())['drc']
assert drc['airwireCount']==drc['warningCount']==0 and [e['signature'] for e in drc['errors']]==['5,1,f10227fd41e0ab5d']
r={'segments':sum(primitives(final,'wire').values()),'vias':sum(primitives(final,'via').values()),'pours':len(b.findall('signals/signal/polygonpour')),'originalRoutesUnchanged':True,'matchesAnalyzedCandidate':True,'offAngleCount':0,'drc':drc,'estimatedCoveragePercentByLayer':coverage}
(P/'audit.json').write_text(json.dumps(r,indent=2));print(json.dumps(r,indent=2))