better 3x3 doc
This commit is contained in:
@@ -0,0 +1,489 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Génère matrice_3x3.fzz : maquette 3x3 sur plaque à pastilles (vue platine)
|
||||
+ schéma électrique (vue schéma). Coordonnées en px Fritzing (90 dpi)."""
|
||||
import math, sys, zipfile, os
|
||||
from xml.sax.saxutils import escape
|
||||
|
||||
PARTS = "/usr/share/fritzing/fritzing-parts/core/"
|
||||
P = 9.0 # pas 0,1 pouce
|
||||
|
||||
# ---------------------------------------------------------------- modèle
|
||||
instances = [] # dict: id, module, path, title, props, views{view:{...}}
|
||||
idx = [1000]
|
||||
def nid():
|
||||
idx[0] += 1
|
||||
return idx[0]
|
||||
|
||||
conns = {} # (inst_id, view, connector) -> list of (other_id, other_connector, other_layer)
|
||||
def link(view, a, ca, la, b, cb, lb):
|
||||
conns.setdefault((a, view, ca), []).append((b, cb, lb))
|
||||
conns.setdefault((b, view, cb), []).append((a, ca, la))
|
||||
|
||||
# ---------------------------------------------------------------- géométries des pièces
|
||||
LED = dict(module="d4d5af9700923b8a114f57961f29a8a0ColorLEDModuleID",
|
||||
path=PARTS + "led-rgb-4pin-cathode_v5.fzp",
|
||||
legs={"connector0": (1.35, 40.6875), "connector1": (10.35, 40.6875),
|
||||
"connector2": (19.35, 40.6875), "connector3": (28.35, 40.6875)},
|
||||
size=(0.33 * 90, 0.4521 * 90))
|
||||
NPN = dict(module="2244EBEC10e", path=PARTS + "transistor_signal_NPN_TO92_CBE.fzp",
|
||||
# connector2 = C (gauche), connector1 = B, connector0 = E (droite)
|
||||
legs={"connector2": (1.35, 30.101), "connector1": (10.326, 30.101),
|
||||
"connector0": (19.309, 30.101)},
|
||||
size=(0.22954 * 90, 0.3344583 * 90))
|
||||
RES = dict(module="ResistorModuleID", path=PARTS + "resistor.fzp",
|
||||
legs={"connector0": (2.619, 4.5405), "connector1": (36.0063, 4.5405)},
|
||||
size=(0.42917 * 90, 0.0971 * 90))
|
||||
ARDUINO = dict(module="arduino_Uno_Rev3(fix)", path=PARTS + "arduino_Uno_Rev3(fix).fzp",
|
||||
size=(2.94961 * 90, 2.1 * 90))
|
||||
ARD_PIN = { # broche -> (connector id, x, y) dans le repère de la carte (non tournée)
|
||||
"D2": ("connector63", 229.47, 9.0), "D3": ("connector64", 220.46, 9.0),
|
||||
"D4": ("connector65", 211.46, 9.0), "D5": ("connector66", 202.46, 9.0),
|
||||
"D6": ("connector67", 193.46, 9.0), "D7": ("connector68", 184.47, 9.0),
|
||||
"D8": ("connector51", 170.06, 9.0), "D9": ("connector52", 161.06, 9.0),
|
||||
"D10": ("connector53", 152.06, 9.0), "D11": ("connector54", 143.06, 9.0),
|
||||
"D12": ("connector55", 134.06, 9.0), "D13": ("connector56", 125.06, 9.0),
|
||||
"GND": ("connector57", 116.06, 9.0),
|
||||
}
|
||||
|
||||
def rot_matrix(deg, w, h):
|
||||
"""Rotation autour du centre (w/2, h/2), au format QTransform de Fritzing."""
|
||||
cx, cy = w / 2, h / 2
|
||||
a = math.radians(deg)
|
||||
c, s = round(math.cos(a), 9), round(math.sin(a), 9)
|
||||
m11, m12, m21, m22 = c, s, -s, c
|
||||
m31 = cx - (m11 * cx + m21 * cy)
|
||||
m32 = cy - (m12 * cx + m22 * cy)
|
||||
return (m11, m12, m21, m22, m31, m32)
|
||||
|
||||
def apply(m, x, y):
|
||||
m11, m12, m21, m22, m31, m32 = m
|
||||
return (m11 * x + m21 * y + m31, m12 * x + m22 * y + m32)
|
||||
|
||||
def inv_apply(m, u, v):
|
||||
m11, m12, m21, m22, m31, m32 = m
|
||||
u, v = u - m31, v - m32
|
||||
det = m11 * m22 - m12 * m21
|
||||
return ((m22 * u - m21 * v) / det, (-m12 * u + m11 * v) / det)
|
||||
|
||||
# ---------------------------------------------------------------- vue platine (plaque à pastilles)
|
||||
COLS, ROWS = 32, 34
|
||||
BOARD = dict(id=nid(), module=f"{COLS}.{ROWS}PerfboardModuleID",
|
||||
path=":/resources/parts/core/perfboard.fzp", title="Plaque à pastilles",
|
||||
props={"size": f"{COLS}.{ROWS}"}, views={})
|
||||
BOARD["views"]["breadboardView"] = dict(layer="breadboardbreadboard", x=0, y=0, z=1.5)
|
||||
instances.append(BOARD)
|
||||
|
||||
def hole(c, r):
|
||||
return (9 + P * c, 9 + P * r)
|
||||
|
||||
def hole_id(c, r):
|
||||
return f"connector{r * 1000 + c}"
|
||||
|
||||
def add_part(spec, title, bb_pos, bb_rot=0, props=None, sch=None, legs_to=None):
|
||||
"""legs_to : {connector: (col, row)} trous de la plaque où arrivent les pattes."""
|
||||
inst = dict(id=nid(), module=spec["module"], path=spec["path"], title=title,
|
||||
props=props or {}, views={}, legs={})
|
||||
w, h = spec["size"]
|
||||
m = rot_matrix(bb_rot, w, h) if bb_rot else None
|
||||
inst["views"]["breadboardView"] = dict(layer="breadboard", x=bb_pos[0], y=bb_pos[1],
|
||||
z=2.5, m=m)
|
||||
if legs_to:
|
||||
for con, (c, r) in legs_to.items():
|
||||
sx, sy = spec["legs"][con]
|
||||
hx, hy = hole(c, r)
|
||||
u, v = hx - bb_pos[0], hy - bb_pos[1]
|
||||
lx, ly = inv_apply(m, u, v) if m else (u, v)
|
||||
inst["legs"][con] = ((sx, sy), (lx - sx, ly - sy))
|
||||
link("breadboardView", inst["id"], con, "breadboard", BOARD["id"],
|
||||
hole_id(c, r), "breadboardbreadboard")
|
||||
inst["sch"] = sch
|
||||
inst["holes"] = legs_to or {}
|
||||
instances.append(inst)
|
||||
return inst
|
||||
|
||||
def place_on_holes(spec, title, holes, rot=0, lift=1.0, props=None):
|
||||
"""Place la pièce pour que ses pattes soient au-dessus des trous, puis plie les
|
||||
pattes vers les trous. lift = longueur de patte visible, en pas de 0,1 po."""
|
||||
cons = list(holes)
|
||||
# centre des trous visés, centre des départs de pattes
|
||||
hx = sum(hole(*holes[c])[0] for c in cons) / len(cons)
|
||||
hy = sum(hole(*holes[c])[1] for c in cons) / len(cons)
|
||||
sx = sum(spec["legs"][c][0] for c in cons) / len(cons)
|
||||
sy = sum(spec["legs"][c][1] for c in cons) / len(cons)
|
||||
w, h = spec["size"]
|
||||
m = rot_matrix(rot, w, h) if rot else None
|
||||
tx, ty = apply(m, sx, sy) if m else (sx, sy)
|
||||
if rot == 0:
|
||||
pos = (hx - tx, hy - ty - lift * P)
|
||||
else:
|
||||
pos = (hx - tx, hy - ty)
|
||||
return add_part(spec, title, pos, rot, props, legs_to=holes)
|
||||
|
||||
wires = []
|
||||
board_wires = [] # (trou a, trou b, couleur) pour le plan d'implantation
|
||||
def bb_wire(a, b, color, title=None):
|
||||
"""Fil entre deux trous de la plaque (a, b = (col, row))."""
|
||||
(x1, y1), (x2, y2) = hole(*a), hole(*b)
|
||||
board_wires.append((a, b, color))
|
||||
w = dict(id=nid(), title=title or f"Fil{len(wires) + 1}", view="breadboardView",
|
||||
x=x1, y=y1, dx=x2 - x1, dy=y2 - y1, color=color, flags=64,
|
||||
layer="breadboardWire", z=(1.8 if color == NU else 3.5))
|
||||
for k, (c, r) in enumerate((a, b)):
|
||||
link("breadboardView", w["id"], f"connector{k}", "breadboardWire",
|
||||
BOARD["id"], hole_id(c, r), "breadboardbreadboard")
|
||||
wires.append(w)
|
||||
return w
|
||||
|
||||
ARD_POS = (40.0, -280.0)
|
||||
ARD_M = rot_matrix(180, *ARDUINO["size"])
|
||||
ARD = dict(id=nid(), module=ARDUINO["module"], path=ARDUINO["path"], title="Arduino Uno",
|
||||
props={}, views={}, legs={})
|
||||
ARD["views"]["breadboardView"] = dict(layer="breadboardbreadboard", x=ARD_POS[0],
|
||||
y=ARD_POS[1], z=1.6, m=ARD_M)
|
||||
instances.append(ARD)
|
||||
|
||||
def ard_pin_xy(name):
|
||||
_, px, py = ARD_PIN[name]
|
||||
u, v = apply(ARD_M, px, py)
|
||||
return (ARD_POS[0] + u, ARD_POS[1] + v)
|
||||
|
||||
def ard_wire(pin, hole_cr, color):
|
||||
x1, y1 = ard_pin_xy(pin)
|
||||
x2, y2 = hole(*hole_cr)
|
||||
w = dict(id=nid(), title=f"Fil {pin}", view="breadboardView", x=x1, y=y1,
|
||||
dx=x2 - x1, dy=y2 - y1, color=color, flags=64, layer="breadboardWire")
|
||||
link("breadboardView", w["id"], "connector0", "breadboardWire", ARD["id"],
|
||||
ARD_PIN[pin][0], "breadboardbreadboard")
|
||||
link("breadboardView", w["id"], "connector1", "breadboardWire", BOARD["id"],
|
||||
hole_id(*hole_cr), "breadboardbreadboard")
|
||||
wires.append(w)
|
||||
|
||||
# couleurs de fils Fritzing
|
||||
NU = "#a8a8a8" # fil nu étamé, côté soudure
|
||||
ROUGE, VERT, BLEU = "#cc1414", "#47cc79", "#418dd9"
|
||||
NOIR, JAUNE, ORANGE = "#404040", "#ffe24d", "#ff7033"
|
||||
|
||||
# --- implantation -------------------------------------------------------------
|
||||
PAS = 6 # pas entre LED, en trous (6 × 2,54 = 15,24 mm)
|
||||
X0, Y_LED = 2, (18, 24, 30) # LED (ligne r, colonne c) : pattes R K G B
|
||||
COUL = {"R": 0, "G": 2, "B": 3} # décalage de la patte dans la LED
|
||||
PIN_ANODE = {(c, k): f"D{2 + 3 * c + i}" for c in range(3) for i, k in enumerate("RGB")}
|
||||
RES_VAL = {"R": "220Ω", "G": "150Ω", "B": "150Ω"}
|
||||
COUL_FIL = {"R": ROUGE, "G": VERT, "B": BLEU}
|
||||
ard_jobs = [] # (broche, trou, couleur) routés à la fin
|
||||
|
||||
leds = {}
|
||||
for r in range(3):
|
||||
for c in range(3):
|
||||
x = X0 + PAS * c
|
||||
leds[(r, c)] = place_on_holes(
|
||||
LED, f"LED L{r}C{c}",
|
||||
{"connector0": (x, Y_LED[r]), "connector1": (x + 1, Y_LED[r]),
|
||||
"connector2": (x + 2, Y_LED[r]), "connector3": (x + 3, Y_LED[r])},
|
||||
lift=0.6)
|
||||
|
||||
res_anode = {}
|
||||
for c in range(3):
|
||||
for k, off in COUL.items():
|
||||
col = X0 + PAS * c + off
|
||||
top, bot = (2, 6) if k in "RG" else (7, 11)
|
||||
res_anode[(c, k)] = place_on_holes(
|
||||
RES, f"R {k}{c}", {"connector0": (col, top), "connector1": (col, bot)},
|
||||
rot=90, props={"resistance": RES_VAL[k]})
|
||||
bb_wire((col, 1), (col, top), NU)
|
||||
ard_jobs.append((PIN_ANODE[(c, k)], (col, 1), COUL_FIL[k]))
|
||||
bb_wire((col, bot), (col, Y_LED[0]), NU)
|
||||
bb_wire((col, Y_LED[0]), (col, Y_LED[1]), NU)
|
||||
bb_wire((col, Y_LED[1]), (col, Y_LED[2]), NU)
|
||||
|
||||
XC, XB, XE = 21, 22, 23 # pattes C, B, E
|
||||
X_GND = 30
|
||||
trans, res_base = {}, {}
|
||||
for r in range(3):
|
||||
y = Y_LED[r] + 1
|
||||
for c in range(3):
|
||||
xk = X0 + PAS * c + 1
|
||||
bb_wire((xk, Y_LED[r]), (xk, y), NU)
|
||||
bb_wire((X0 + 1, y), (X0 + 1 + PAS, y), NOIR)
|
||||
bb_wire((X0 + 1 + PAS, y), (X0 + 1 + 2 * PAS, y), NOIR)
|
||||
bb_wire((X0 + 1 + 2 * PAS, y), (XC - 1, y), NOIR)
|
||||
bb_wire((XC - 1, y), (XC, y), NU)
|
||||
trans[r] = place_on_holes(NPN, f"T{r} (BC337)",
|
||||
{"connector2": (XC, y), "connector1": (XB, y),
|
||||
"connector0": (XE, y)}, lift=0.6)
|
||||
res_base[r] = place_on_holes(RES, f"Rb{r}",
|
||||
{"connector0": (XB, y + 1), "connector1": (XB + 4, y + 1)},
|
||||
lift=0.0, props={"resistance": "1kΩ"})
|
||||
bb_wire((XB, y), (XB, y + 1), NU)
|
||||
xw = XB + 5 + r
|
||||
bb_wire((XB + 4, y + 1), (xw, y + 1), NU)
|
||||
ard_jobs.append((f"D{11 + r}", (xw, y + 1), JAUNE))
|
||||
bb_wire((XE, y), (X_GND, y), NU)
|
||||
yg = Y_LED[0] - 1
|
||||
bb_wire((X_GND, yg), (X_GND, Y_LED[0] + 1), NU)
|
||||
bb_wire((X_GND, Y_LED[0] + 1), (X_GND, Y_LED[1] + 1), NU)
|
||||
bb_wire((X_GND, Y_LED[1] + 1), (X_GND, Y_LED[2] + 1), NU)
|
||||
ard_jobs.append(("GND", (X_GND, yg), NOIR))
|
||||
|
||||
# routage des fils Arduino : descente, palier horizontal, descente (fils coudés)
|
||||
def chain(points, color, pin, hole_cr):
|
||||
ids = []
|
||||
for i in range(len(points) - 1):
|
||||
(x1, y1), (x2, y2) = points[i], points[i + 1]
|
||||
w = dict(id=nid(), title=f"Fil {pin}", view="breadboardView", x=x1, y=y1,
|
||||
dx=x2 - x1, dy=y2 - y1, color=color, flags=64, layer="breadboardWire")
|
||||
wires.append(w)
|
||||
ids.append(w["id"])
|
||||
link("breadboardView", ids[0], "connector0", "breadboardWire", ARD["id"],
|
||||
ARD_PIN[pin][0], "breadboardbreadboard")
|
||||
link("breadboardView", ids[-1], "connector1", "breadboardWire", BOARD["id"],
|
||||
hole_id(*hole_cr), "breadboardbreadboard")
|
||||
for a_, b_ in zip(ids, ids[1:]):
|
||||
link("breadboardView", a_, "connector1", "breadboardWire", b_, "connector0",
|
||||
"breadboardWire")
|
||||
|
||||
header_y = ard_pin_xy("D2")[1]
|
||||
jobs = [(pin, h, col, ard_pin_xy(pin)[0], hole(*h)[0]) for pin, h, col in ard_jobs]
|
||||
droite = sorted([j for j in jobs if j[4] > j[3] + 0.5], key=lambda j: j[3])
|
||||
gauche = sorted([j for j in jobs if j[4] < j[3] - 0.5], key=lambda j: -j[3])
|
||||
niveau = {}
|
||||
for groupe in (droite, gauche):
|
||||
n = len(groupe)
|
||||
for i, j in enumerate(groupe): # le plus à l'extérieur descend le plus bas
|
||||
niveau[j[0]] = n - i
|
||||
for pin, h, col, xp, xh in jobs:
|
||||
yp = header_y
|
||||
if pin in niveau:
|
||||
yl = header_y + 18 + 9 * niveau[pin]
|
||||
chain([(xp, yp), (xp, yl), (xh, yl), hole(*h)], col, pin, h)
|
||||
else:
|
||||
chain([(xp, yp), hole(*h)], col, pin, h)
|
||||
|
||||
# ---------------------------------------------------------------- vue schéma
|
||||
K = 90 / 96 # px Inkscape -> px Fritzing (SVG en pouces)
|
||||
SCH = { # terminaux dans le repère du symbole (px Fritzing)
|
||||
"LED": {"connector0": (5.126, 35.457), "connector2": (23.172, 35.457),
|
||||
"connector3": (41.297, 35.457), "connector1": (23.225, 1.5)},
|
||||
"NPN": {"connector1": (0.4375, 18.4375), "connector2": (18.4375, 0.4375),
|
||||
"connector0": (18.4375, 36.4375)},
|
||||
"RES": {"connector0": (0.4375, 3.87), "connector1": (36.4375, 3.87)},
|
||||
"RES_SIZE": (0.409722 * 90, 0.086 * 90),
|
||||
}
|
||||
def ard_sch(name):
|
||||
con = ARD_PIN[name][0]
|
||||
if name == "GND":
|
||||
return (72.0, 207.0)
|
||||
n = {"D2": 0, "D3": 1, "D4": 2, "D5": 3, "D6": 4, "D7": 5, "D8": 6, "D9": 7,
|
||||
"D10": 8, "D11": 9, "D12": 10, "D13": 11}[name]
|
||||
return (135.0, 54.0 + 9 * n)
|
||||
|
||||
def set_sch(inst, pos, rot=0, size=None):
|
||||
m = rot_matrix(rot, *size) if rot else None
|
||||
inst["views"]["schematicView"] = dict(layer="schematic", x=pos[0], y=pos[1], z=2.5, m=m)
|
||||
inst["sch_pos"], inst["sch_m"] = pos, m
|
||||
|
||||
def place_sch(inst, table, con, target, rot=0, size=None):
|
||||
"""Place le symbole pour que le terminal `con` tombe sur `target`."""
|
||||
m = rot_matrix(rot, *size) if rot else None
|
||||
lx, ly = SCH[table][con]
|
||||
if m:
|
||||
lx, ly = apply(m, lx, ly)
|
||||
set_sch(inst, (target[0] - lx, target[1] - ly), rot, size)
|
||||
|
||||
def term(inst, table, con):
|
||||
lx, ly = SCH[table][con]
|
||||
if inst.get("sch_m"):
|
||||
lx, ly = apply(inst["sch_m"], lx, ly)
|
||||
return (inst["sch_pos"][0] + lx, inst["sch_pos"][1] + ly)
|
||||
|
||||
ends = {} # point arrondi -> [(wire_id, connector)]
|
||||
def sch_poly(points, start=None, end=None):
|
||||
ids = []
|
||||
for (x1, y1), (x2, y2) in zip(points, points[1:]):
|
||||
w = dict(id=nid(), title="Fil", view="schematicView", x=x1, y=y1, dx=x2 - x1,
|
||||
dy=y2 - y1, color="#404040", flags=128, layer="schematicTrace",
|
||||
mils="9.7222", z=5.5)
|
||||
wires.append(w)
|
||||
ids.append(w["id"])
|
||||
for a_, b_ in zip(ids, ids[1:]):
|
||||
link("schematicView", a_, "connector1", "schematicTrace", b_, "connector0",
|
||||
"schematicTrace")
|
||||
if start:
|
||||
link("schematicView", ids[0], "connector0", "schematicTrace", start[0]["id"],
|
||||
start[1], "schematic")
|
||||
else:
|
||||
ends.setdefault((round(points[0][0], 2), round(points[0][1], 2)), []).append(
|
||||
(ids[0], "connector0"))
|
||||
if end:
|
||||
link("schematicView", ids[-1], "connector1", "schematicTrace", end[0]["id"],
|
||||
end[1], "schematic")
|
||||
else:
|
||||
ends.setdefault((round(points[-1][0], 2), round(points[-1][1], 2)), []).append(
|
||||
(ids[-1], "connector1"))
|
||||
|
||||
A_POS = (0.0, 450.0)
|
||||
ARD["views"]["schematicView"] = dict(layer="schematic", x=A_POS[0], y=A_POS[1], z=2.5)
|
||||
def apin(name):
|
||||
x, y = ard_sch(name)
|
||||
return (A_POS[0] + x, A_POS[1] + y)
|
||||
ARDP = lambda name: (ARD, ARD_PIN[name][0])
|
||||
|
||||
MX, MY, PASS = 225.0, 60.0, 90.0
|
||||
BUS_OFF = {"R": -27.0, "G": -18.0, "B": -9.0}
|
||||
PROF = {"R": 9.0, "G": 18.0, "B": 27.0}
|
||||
LEDCON = {"R": "connector0", "G": "connector2", "B": "connector3"}
|
||||
RES_TOP = {"R": 315.0, "G": 360.0, "B": 405.0}
|
||||
for (r, c), led in leds.items():
|
||||
set_sch(led, (MX + PASS * c, MY + PASS * r))
|
||||
for c in range(3):
|
||||
for k in "RGB":
|
||||
bx = MX + PASS * c + BUS_OFF[k]
|
||||
res = res_anode[(c, k)]
|
||||
# patte 1 (connector0) côté Arduino, en bas ; patte 2 côté LED, en haut
|
||||
place_sch(res, "RES", "connector1", (bx, RES_TOP[k]), rot=270, size=SCH["RES_SIZE"])
|
||||
top, bot = term(res, "RES", "connector1"), term(res, "RES", "connector0")
|
||||
pin = PIN_ANODE[(c, k)]
|
||||
px, py = apin(pin)
|
||||
sch_poly([(px, py), (bx, py), bot], start=ARDP(pin), end=(res, "connector0"))
|
||||
# bus : résistance -> jonctions des lignes 2, 1, 0
|
||||
pts = [top] + [(bx, MY + PASS * r + 35.457 + PROF[k]) for r in (2, 1, 0)]
|
||||
for i, (a_, b_) in enumerate(zip(pts, pts[1:])):
|
||||
sch_poly([a_, b_], start=(res, "connector1") if i == 0 else None)
|
||||
for r in range(3):
|
||||
led = leds[(r, c)]
|
||||
tx, ty = term(led, "LED", LEDCON[k])
|
||||
jy = MY + PASS * r + 35.457 + PROF[k]
|
||||
sch_poly([(tx, ty), (tx, jy), (bx, jy)], start=(led, LEDCON[k]))
|
||||
|
||||
XT = 545.0
|
||||
XV = {0: 462.0, 1: 471.0, 2: 480.0}
|
||||
X_GND_S, Y_GND_S = XT + 45.0, 690.0
|
||||
for r in range(3):
|
||||
yrl = MY + PASS * r + 1.5 - 9.0
|
||||
ks = [term(leds[(r, c)], "LED", "connector1") for c in range(3)]
|
||||
for c in range(3):
|
||||
sch_poly([ks[c], (ks[c][0], yrl)], start=(leds[(r, c)], "connector1"))
|
||||
t = trans[r]
|
||||
set_sch(t, (XT, yrl + 18.0 - 0.4375))
|
||||
cpt, bpt, ept = term(t, "NPN", "connector2"), term(t, "NPN", "connector1"), term(t, "NPN", "connector0")
|
||||
sch_poly([(ks[0][0], yrl), (ks[1][0], yrl)])
|
||||
sch_poly([(ks[1][0], yrl), (ks[2][0], yrl)])
|
||||
sch_poly([(ks[2][0], yrl), (cpt[0], yrl), cpt], end=(t, "connector2"))
|
||||
rb = res_base[r]
|
||||
# patte 1 (connector0) côté base, patte 2 côté Arduino
|
||||
place_sch(rb, "RES", "connector0", (bpt[0] - 9.0, bpt[1]), rot=180, size=SCH["RES_SIZE"])
|
||||
rbase, rard = term(rb, "RES", "connector0"), term(rb, "RES", "connector1")
|
||||
sch_poly([rbase, bpt], start=(rb, "connector0"), end=(t, "connector1"))
|
||||
pin = f"D{11 + r}"
|
||||
px, py = apin(pin)
|
||||
sch_poly([(px, py), (XV[r], py), (XV[r], rard[1]), rard], start=ARDP(pin), end=(rb, "connector1"))
|
||||
sch_poly([ept, (X_GND_S, ept[1])], start=(t, "connector0"))
|
||||
yE = ept[1]
|
||||
if r == 0:
|
||||
y_e0 = yE
|
||||
else:
|
||||
sch_poly([(X_GND_S, prev_e), (X_GND_S, yE)])
|
||||
prev_e = yE
|
||||
gx, gy = apin("GND")
|
||||
sch_poly([(X_GND_S, prev_e), (X_GND_S, Y_GND_S), (gx, Y_GND_S), (gx, gy)], end=ARDP("GND"))
|
||||
|
||||
for pt, lst in ends.items():
|
||||
for i in range(len(lst)):
|
||||
for j in range(i + 1, len(lst)):
|
||||
link("schematicView", lst[i][0], lst[i][1], "schematicTrace", lst[j][0],
|
||||
lst[j][1], "schematicTrace")
|
||||
|
||||
# ---------------------------------------------------------------- écriture XML
|
||||
def fmt(v):
|
||||
return f"{v:.4f}".rstrip("0").rstrip(".") if isinstance(v, float) else str(v)
|
||||
|
||||
def connects_xml(inst_id, view, con, indent):
|
||||
out = []
|
||||
for (oid, ocon, olayer) in conns.get((inst_id, view, con), []):
|
||||
out.append(f'{indent}<connect connectorId="{ocon}" modelIndex="{oid}" layer="{olayer}"/>')
|
||||
return "\n".join(out)
|
||||
|
||||
def part_xml(inst):
|
||||
L = []
|
||||
L.append(f'<instance moduleIdRef="{escape(inst["module"])}" modelIndex="{inst["id"]}" '
|
||||
f'path="{escape(inst["path"])}">')
|
||||
for k, v in inst["props"].items():
|
||||
L.append(f' <property name="{k}" value="{escape(v)}"/>')
|
||||
L.append(f' <title>{escape(inst["title"])}</title>')
|
||||
L.append(' <views>')
|
||||
for view, g in inst["views"].items():
|
||||
L.append(f' <{view} layer="{g["layer"]}">')
|
||||
if g.get("m"):
|
||||
m11, m12, m21, m22, m31, m32 = g["m"]
|
||||
L.append(f' <geometry z="{g["z"]}" x="{fmt(g["x"])}" y="{fmt(g["y"])}">')
|
||||
L.append(f' <transform m11="{fmt(m11)}" m12="{fmt(m12)}" m13="0" '
|
||||
f'm21="{fmt(m21)}" m22="{fmt(m22)}" m23="0" m31="{fmt(m31)}" '
|
||||
f'm32="{fmt(m32)}" m33="1"/>')
|
||||
L.append(' </geometry>')
|
||||
else:
|
||||
L.append(f' <geometry z="{g["z"]}" x="{fmt(g["x"])}" y="{fmt(g["y"])}"/>')
|
||||
cons = sorted({c for (i, v, c) in conns if i == inst["id"] and v == view}
|
||||
| (set(inst.get("legs", {})) if view == "breadboardView" else set()))
|
||||
if cons:
|
||||
L.append(' <connectors>')
|
||||
for con in cons:
|
||||
L.append(f' <connector connectorId="{con}" layer="{g["layer"]}">')
|
||||
if view == "breadboardView" and con in inst.get("legs", {}):
|
||||
(sx, sy), (lx, ly) = inst["legs"][con]
|
||||
L.append(f' <geometry x="{fmt(sx)}" y="{fmt(sy)}"/>')
|
||||
L.append(' <leg><point x="0" y="0"/><bezier/>'
|
||||
f'<point x="{fmt(lx)}" y="{fmt(ly)}"/><bezier/></leg>')
|
||||
else:
|
||||
L.append(' <geometry x="0" y="0"/>')
|
||||
L.append(' <connects>')
|
||||
L.append(connects_xml(inst["id"], view, con, " "))
|
||||
L.append(' </connects>')
|
||||
L.append(' </connector>')
|
||||
L.append(' </connectors>')
|
||||
L.append(f' </{view}>')
|
||||
L.append(' </views>')
|
||||
L.append('</instance>')
|
||||
return "\n".join(L)
|
||||
|
||||
def wire_xml(w):
|
||||
view, layer = w["view"], w["layer"]
|
||||
L = [f'<instance moduleIdRef="WireModuleID" modelIndex="{w["id"]}" '
|
||||
f'path=":/resources/parts/core/wire.fzp">',
|
||||
f' <title>{escape(w["title"])}</title>', ' <views>',
|
||||
f' <{view} layer="{layer}">',
|
||||
f' <geometry z="{w.get("z", 3.5)}" x="{fmt(w["x"])}" y="{fmt(w["y"])}" x1="0" y1="0" '
|
||||
f'x2="{fmt(w["dx"])}" y2="{fmt(w["dy"])}" wireFlags="{w["flags"]}"/>',
|
||||
f' <wireExtras mils="{w.get("mils", "22.2222")}" color="{w["color"]}" '
|
||||
f'opacity="1" banded="0"/>',
|
||||
' <connectors>']
|
||||
for k in ("connector0", "connector1"):
|
||||
L.append(f' <connector connectorId="{k}" layer="{layer}">')
|
||||
L.append(' <geometry x="0" y="0"/>')
|
||||
L.append(' <connects>')
|
||||
L.append(connects_xml(w["id"], view, k, " "))
|
||||
L.append(' </connects>')
|
||||
L.append(' </connector>')
|
||||
L += [' </connectors>', f' </{view}>', ' </views>', '</instance>']
|
||||
return "\n".join(L)
|
||||
|
||||
def build(out_path, ino_path=None):
|
||||
head = '''<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module fritzingVersion="1.0.5" icon=".png">
|
||||
<views>
|
||||
<view name="breadboardView" backgroundColor="#ffffff" gridSize="0.1in" showGrid="1" alignToGrid="1" viewFromBelow="0" colorWiresByLength="0"/>
|
||||
<view name="schematicView" backgroundColor="#ffffff" gridSize="0.1in" showGrid="1" alignToGrid="1" viewFromBelow="0"/>
|
||||
<view name="pcbView" backgroundColor="#333333" gridSize="0.05in" showGrid="1" alignToGrid="1" viewFromBelow="0"/>
|
||||
</views>
|
||||
<instances>
|
||||
'''
|
||||
body = "\n".join(part_xml(i) for i in instances) + "\n" + "\n".join(wire_xml(w) for w in wires)
|
||||
xml = head + body + "\n</instances>\n</module>\n"
|
||||
name = os.path.splitext(os.path.basename(out_path))[0]
|
||||
with zipfile.ZipFile(out_path, "w", zipfile.ZIP_DEFLATED) as z:
|
||||
z.writestr(name + ".fz", xml)
|
||||
if ino_path:
|
||||
z.write(ino_path, os.path.basename(ino_path))
|
||||
|
||||
if __name__ == "__main__" and sys.argv[1] != "/dev/null":
|
||||
build(sys.argv[1], sys.argv[2] if len(sys.argv) > 2 else None)
|
||||
print(len(instances), "pièces,", len(wires), "fils")
|
||||
Reference in New Issue
Block a user