import xml.etree.ElementTree as ET, re, glob, json, os SVG="http://www.w3.org/2000/svg"; ETM="https://etm-powersync.fr/ns/schema" INK="http://www.inkscape.org/namespaces/inkscape" SODI="http://sodipodi.sourceforge.net/DTD/sodipodi-0.0" def ln(t): return t.split('}')[-1] def parse_tf(s): M=[1,0,0,1,0,0] if not s: return M for name,args in re.findall(r'(\w+)\s*\(([^)]*)\)', s): n=[float(x) for x in re.split(r'[,\s]+',args.strip()) if x!=''] if name=='translate': m=[1,0,0,1,n[0],n[1] if len(n)>1 else 0] elif name=='scale': m=[n[0],0,0,(n[1] if len(n)>1 else n[0]),0,0] elif name=='matrix': m=n else: m=[1,0,0,1,0,0] a,b,c,d,e,f=M; a2,b2,c2,d2,e2,f2=m M=[a*a2+c*b2,b*a2+d*b2,a*c2+c*d2,b*c2+d*d2,a*e2+c*f2+e,b*e2+d*f2+f] return M def comp(M1,M2): a,b,c,d,e,f=M1;a2,b2,c2,d2,e2,f2=M2 return [a*a2+c*b2,b*a2+d*b2,a*c2+c*d2,b*c2+d*d2,a*e2+c*f2+e,b*e2+d*f2+f] def app(M,x,y): a,b,c,d,e,f=M; return (round(a*x+c*y+e,1),round(b*x+d*y+f,1)) def pos(el): if ln(el.tag) in("circle","ellipse"): return float(el.get("cx",0)),float(el.get("cy",0)) if ln(el.tag)=="text": return float(el.get("x",0) or 0),float(el.get("y",0) or 0) if ln(el.tag)=="path" and el.get(f"{{{SODI}}}type")=="arc": return float(el.get(f"{{{SODI}}}cx",0)),float(el.get(f"{{{SODI}}}cy",0)) return None lib={} for fn in sorted(glob.glob("symbol-*.svg")): root=ET.parse(fn).getroot() c=root.find(f".//{{{ETM}}}component") ctype=c.get("type") if c is not None else None if not ctype: # repli : deduire du nom de fichier stem=os.path.basename(fn)[:-4] for pre in ("symbol-","block-"): if stem.startswith(pre): stem=stem[len(pre):] ctype=stem.replace("-","_") terms={}; labels={} def walk(el,M): M=comp(M,parse_tf(el.get("transform"))) lab=el.get(f"{{{INK}}}label"); p=pos(el) # inkscape:label term:/lbl: if lab and p: x,y=app(M,*p) if lab.startswith("term:"): terms[lab[5:]]={"x":x,"y":y} elif lab.startswith("lbl:"): anchor=(el.get("text-anchor") or "start") labels[lab[4:]]={"x":x,"y":y,"anchor":anchor} # repli etm:terminal / etm:label et=el.get(f"{{{ETM}}}terminal") if et and p and et not in terms: terms[et]=dict(zip(("x","y"),app(M,*p))) el_lbl=el.get(f"{{{ETM}}}label") if el_lbl and p and el_lbl not in labels: x,y=app(M,*p); labels[el_lbl]={"x":x,"y":y,"anchor":el.get("text-anchor") or "start"} for ch in el: walk(ch,M) walk(root,[1,0,0,1,0,0]) lib[fn]={"type":ctype,"terminals":terms,"labels":labels} json.dump(lib, open("library.json","w"), indent=2, ensure_ascii=False) # rapport print(f"{'fichier':30} {'type':14} terminaux / labels") for fn,d in lib.items(): t=",".join(d["terminals"]) or "—" l=",".join(d["labels"]) or "—" miss="" if d["type"] else " [TYPE MANQUANT]" print(f"{fn:30} {str(d['type']):14} T[{t}] L[{l}]{miss}")