Create a gist now

Instantly share code, notes, and snippets.

anonymous /r-array-gen.py
Created Oct 24, 2016

What would you like to do?
Small script to generate resistor-arrays for fritzing. See http://forum.fritzing.org/t/2079 for more information.
#!/usr/bin/env python
# coding=utf-8
# This script generates resistor-arrays of various sizes.
# See: http://forum.fritzing.org/t/2079
import svgwrite as svg
from svgwrite.base import BaseElement
from svgwrite.mixins import Presentation, Markers, Transform
import os
import shutil
import zipfile
import getopt
import sys
# The star type has resistors that are connected to a common pin (bussed).
STAR = 1
BUSSED = STAR
# The parallel type has isolated resistors that aren't connected to each other.
PARALLEL = 3
ISOLATED = PARALLEL
# Generates the descriptive part file.
# @param output Target file for saving
# @param resistors Number of resistors
# @param circuittype Type of circuit (STAR or PARALLEL, BUSSED or ISOLATED)
# @param resistance Resistance-value
# @param img_icon Name of the icon-file
# @param img_breaboard Name of the breadboard-file
# @param img_schematic Name of the schematics-file
# @param img_pcb Name of the pcb-file
def gen_fzp(output, resistors, circuittype, resistance, img_icon, img_bredboard, img_schematic, img_pcb):
pins = pin_number(resistors, circuittype)
fzp = '<?xml version="1.0" encoding="UTF-8"?>\n' \
'<module fritzingVersion="0.9.3b" moduleId="Resistor'
fzp += 'Bussed' if circuittype == STAR else 'Isolated'
fzp += str(resistors)
fzp += 'SIP_ResistorModuleID">\n' \
' <version>4</version>\n' \
' <title>'
fzp += 'Bussed' if circuittype == STAR else 'Isolated'
fzp += str(resistors)
fzp += ' Resistor-'
fzp += str(resistors)
fzp += ' (SIP-'
fzp += str(pins)
fzp += ')</title>\n' \
' <label>R</label>\n' \
' <date>Mon Sep 26 2016</date>\n' \
' <author>Stephen Lilley</author>\n' \
' <tags>\n' \
' <tag>resistor</tag>\n' \
' <tag>'
fzp += 'parallel' if circuittype == PARALLEL else 'star'
fzp += '</tag>\n' \
' <tag>array</tag>\n' \
' <tag>network</tag>\n' \
' <tag>'
fzp += 'bussed' if circuittype == STAR else 'isolated'
fzp += '</tag>\n' \
' </tags>\n' \
' <properties>\n' \
' <property name="family">Resistor (Networks / Arrays)</property>\n' \
' <property name="package">SIP-'
fzp += str(pins)
fzp += '</property>\n' \
' <property name="circuit type">Bussed</property>\n' \
' <property name="pins">'
fzp += str(pins)
fzp += '</property>\n' \
' <property name="resistors">'
fzp += str(resistors)
fzp += '</property>\n' \
' <property showInLabel="yes" name="Resistance">'
fzp += str(resistance)
fzp += '</property>\n' \
' <property showInLabel="yes" name="power"></property>\n' \
' <property showInLabel="no" name="tolerance">&#177;5%</property>\n' \
' <property name="part number"></property>\n' \
' <property name="variant">variant 1</property>\n' \
' </properties>\n' \
' <taxonomy>discreteParts.resistor.'
fzp += str(resistance)
fzp += '</taxonomy>\n' \
' <description>A resistor array is a single package which contains more than one resistor. They are typically used for convenience when several resistors are needed together in the same place in a circuit.</description>\n' \
' <spice><line>RA{instanceTitle} {net connector0} {net connector1} {resistance}</line>\n' \
' </spice>\n' \
' <views>\n' \
' <iconView>\n' \
' <layers image="icon/' + img_icon + '">\n' \
' <layer layerId="icon"/>\n' \
' </layers>\n' \
' </iconView>\n' \
' <breadboardView>\n' \
' <layers image="breadboard/' + img_bredboard + '">\n' \
' <layer layerId="breadboard"/>\n' \
' </layers>\n' \
' </breadboardView>\n' \
' <schematicView>\n' \
' <layers image="schematic/' + img_schematic + '">\n' \
' <layer layerId="schematic"/>\n' \
' </layers>\n' \
' </schematicView>\n' \
' <pcbView>\n' \
' <layers image="pcb/' + img_pcb + '">\n' \
' <layer layerId="copper0"/>\n' \
' <layer layerId="copper1"/>\n' \
' <layer layerId="silkscreen"/>\n' \
' </layers>\n' \
' </pcbView>\n' \
' </views>\n' \
' <connectors>\n'
for i in range(pins):
fzp += ' <connector id="connector' + str(i) + '" type="male" name="Pin ' + str(i) + '">\n' \
' <description>Pin' + str(i) + '</description>\n' \
' <views>\n' \
' <breadboardView>\n' \
' <p svgId="connector' + str(i) + 'pin" layer="breadboard"/>\n' \
' </breadboardView>\n' \
' <schematicView>\n' \
' <p terminalId="connector' + str(i) + 'terminal" svgId="connector' + str(i) + 'pin" layer="schematic"/>\n' \
' </schematicView>\n' \
' <pcbView>\n' \
' <p svgId="connector' + str(i) + 'pin" layer="copper0"/>\n' \
' <p svgId="connector' + str(i) + 'pin" layer="copper1"/>\n' \
' </pcbView>\n' \
' </views>\n' \
' </connector>\n'
fzp += ' </connectors>\n' \
'</module>\n'
with open(output, "w") as f:
f.write(fzp)
# Generates a breadboard-view of the element and saves it to a file.
# @param output Target file for saving
# @param resistors Number of resistors
# @param circuittype Type of circuit (STAR or PARALLEL, BUSSED or ISOLATED)
# @param resistance Resistance-value
def gen_breadboard(output, resistors, circuittype, resistance):
dx = 26494 # Difference between each pin
min_width = 73017 # Base width of the viewbox for a three-pin-object
width_multiplicator = 0.275642 / min_width
# Used to calculate the width of the SVG in inches
pins = pin_number(resistors, circuittype)
# Calculate the viewbox
width = min_width + (pins - 3) * dx
temp_name = "temp.svg"
draw = svg.Drawing(temp_name,
size = (str(width * width_multiplicator) + "in", "0.334972in"),
viewBox = "0 0 " + str(width) + " 88734")
# Center expandable body
expand = (pins - 3) * dx
path = [
("M", 48808 + expand, 41602),
("l", -123, 17, -24247 - expand, 0, 0, -41521),
("c", 7776, -115, 16651, -123, 24370 + expand, -17),
("l", 0, 41530, 0, -8),
("z")
]
draw.add(draw.path(d = path, fill = "#EB9922"))
path = [
("M", 24439, 97),
("c", 7768, -115, 16634, -131, 24370 + expand, -25),
("l", 0, 2756),
("c", -7735, -106, -16602, -91, -24370 - expand, 25),
("l", 0, -2756),
("z")
]
draw.add(draw.path(d = path, fill = "#D3891E"))
# Right end
path = [
("M", 72013 + expand, 41315),
"c0,3109 -1862,5085 -5094,5085l-8186 0c-4643,-7243 11558,0 0,0 -1887,-2937 -5176,-4889 -8924,-4889 -452,0 -894,25 -1329,82l0 -41530c9056,131 16487,418 18440,885 2731,664 4159,2568 5094,5094 2256,6119 0,35263 0,35263l-1 9z"
]
draw.add(draw.path(d = path, fill = "#EB9922"))
path = [
("M", 48488 + expand, 73),
"c9121,123 16602,418 18563,894 2731,664 4159,2568 5094,5094 821,2215 985,7710 796,13345 -41,-4650 -115,-8727 -796,-10581 -935,-2526 -2354,-4429 -5094,-5094 -1961,-467 -9441,-762 -18563,-894l0 -2756 0 -7zm23525 41242c0,3109 -1862,5085 -5094,5085 -14371,0 -5340,0 -8186,0 -1887,-2937 -5176,-4889 -8924,-4889 -452,0 -894,25 -1329,82l0 -6545c452,-66 894,-98 1329,-98 3790,0 8440,2666 11016,5930 1124,1477 -6414,-8047 -378,-140 2149,2756 5250,1083 6184,590 2633,-1681 3748,-3683 4151,-5340 1066,-4331 2018,-11271 2158,-22861 197,10753 -935,28184 -935,28184l7 1z"
]
draw.add(draw.path(d = path, fill = "#D3891E"))
path = [
("M", 68921 + expand, 5142),
"c-2067,-1542 -8219,-394 -8252,1944 6365,3822 5766,21466 5709,23680 8,4773 2838,5266 3076,5274 2108,41 4700,-26986 -533,-30899l0 1z"
]
draw.add(draw.path(d = path, fill = "#FEFEFE", fill_opacity="0.549020", enable_background="new"))
# Generate the bottom pins
params = { "fill": "none", "stroke": "#96989A", "stroke_width": "5297.99", "stroke_linecap": "round" }
for i in range(pins):
x = 10076 + dx * i
# Generate the repeated middle content
if (i >= 2):
shift = dx * (i - 2)
path = [
("M", 49808 + shift, 41520),
"c-3748,0 -7046,1944 -8924,4889l-8637 0c-1887,-2937 -5176,-4889 -8924,-4889l0 0 0 -10376 26494 0 0 10376 -8 0z"
]
draw.add(draw.path(d = path, fill = "#EB9922"))
path = [
("M", 49808 + shift, 34958),
"l0 6562c-3748,0 -7046,1944 -8924,4889l-8637 0c-1887,-2937 -5176,-4889 -8924,-4889l0 0 0 -6562 0 0c3765,0 8449,2657 11016,5930 1477,1969 2969,1895 4463,0 2559,-3256 7226,-5930 11016,-5930l-9 0z"
]
draw.add(draw.path(d = path, fill = "#D3891E"))
# Place the actual legs
draw.add(draw.line((x, 51937), (x, 86085), **params))
draw.add(draw.rect((x - 5906, 46401), (11804, 5299), fill = "#727376"))
draw.add(draw.rect((x - 4209, 46401), (1591, 5299), fill = "#E6E7E8"))
# Place the connector
draw.add(draw.rect((x - 2649, 78136), (5299, 10598), id = "connector" + str(i) + "pin", fill = "none"))
# Left end
draw.add(draw.path(fill = "#EB9922", d = "M24766 41618c-476,-66 -951,-98 -1443,-98 -3748,0 -7046,1944 -8924,4889l-8440 0c-3289,0 -5094,-4905 -5094,-5094 0,0 -1944,-29143 0,-35255 853,-2682 2608,-4618 5094,-5094 2280,-435 9794,-730 18816,-870l0 41521 -8 -1z"))
draw.add(draw.path(fill = "#D3891E", d = "M24766 41618c-467,-66 -951,-98 -1443,-98 -3748,0 -7046,1944 -8924,4889l-8440 0c-3289,0 -5094,-4905 -5094,-5094 0,0 -1017,-15273 -845,-26027 303,9728 812,18924 1214,20367 762,2822 2108,4036 4577,5815 1961,878 4249,1870 6496,-575 2568,-3264 7251,-5930 11016,-5930 467,0 951,41 1443,123l0 6537 -1 -8zm-24640 -22278c-41,-5800 148,-11057 861,-13279 853,-2682 2608,-4618 5094,-5094 2273,-435 9720,-730 18686,-870l0 2756c-8965,140 -16413,435 -18686,870 -2485,476 -4240,2411 -5094,5094 -590,1862 -821,5864 -861,10524l0 -1z"))
draw.add(draw.path(fill = "#FEFEFE", fill_opacity="0.549020", enable_background = "new", d="M4817 4511c3249,-1452 10196,-229 10057,2322 -8005,0 -5356,18357 -7653,23591 -1615,3675 -2256,4675 -4749,5577 -1239,-353 -3232,-28996 2346,-31490z"))
draw.add(draw.circle((11133, 31398), r = 2649))
# Add the text on top
label = gen_label(resistors, circuittype, resistance)
draw.add(draw.text(label, x = [ 13782 ], y = [ 31398 ], fill = "#5F6160", font_weight = "normal", font_size = "18395.9", font_family = "Droid Sans"))
# Save the file
draw.save()
add_linebreaks(temp_name, output, True)
# Generates a correct label for the pcb-view based on the circuit
# @param resistors Number of resistors
# @param circuittype Type of circuit (STAR or PARALLEL, BUSSED or ISOLATED)
# @param resistance Resistance-value
# @returns The generated label
def gen_label(resistors, circuittype, resistance):
res = str(resistance)
res_code = res[:2] + str(len(res) - 2)
n = pin_number(resistors, circuittype)
return "L {:02d} {} {}".format(n, circuittype, res_code)
# Determines how many pins are needed to create a given circuit.
# @param resistors Number of resistors
# @param circuittype Type of circuit (STAR or PARALLEL, BUSSED or ISOLATED)
# @returns Number of pins
def pin_number(resistors, circuittype):
return resistors + 1 if circuittype == STAR else resistors * 2
# Load the file to add linebreaks
# @param input File that should be modified
# @param output Location to save result to
# @param remove_input Remove inputfile after successful output-generation
def add_linebreaks(input, output, remove_input = False):
with open(output, "wt") as fout:
with open(input, "rt") as fin:
for line in fin:
fout.write(line.replace(">", ">\r\n"))
if (remove_input): os.remove(input)
# Generates an icon of the element and saves it to a file.
# @param output Target file for saving
# @param resistors Number of resistors
# @param circuittype Type of circuit (STAR or PARALLEL, BUSSED or ISOLATED)
# @param resistance Resistance-value
def gen_icon(output, resistors, circuittype, resistance):
gen_breadboard(output, resistors, circuittype, resistance)
# Generates a pcb-view of the element and saves it to a file.
# @param output Target file for saving
# @param resistors Number of resistors
# @param circuittype Type of circuit (STAR or PARALLEL, BUSSED or ISOLATED)
# @param resistance Resistance-value
def gen_pcb(output, resistors, circuittype, resistance):
dx = 2793 # Difference between each pin
min_width = 8657 # Base width of the viewbox for a three-pin-object
width_multiplicator = 0.309984 / min_width
# Used to calculate the width of the SVG in inches
pins = pin_number(resistors, circuittype)
# Calculate the viewbox
width = min_width + (pins - 3) * dx
temp_name = "temp.svg"
draw = svg.Drawing(temp_name,
size = (str(width * width_multiplicator) + "in", "0.11in"),
viewBox = "0 0 " + str(width) + " 3072")
# Structure
g_pcb = svg.container.Group(id = "pcb")
draw.add(g_pcb)
# Silkscreen
g_silk = svg.container.Group(id = "silkscreen")
g_silk.add(draw.rect((140, 140), (dx * pins + 2, 2793), fill = "none", stroke = "#FEFEFE", stroke_width = "279.267"))
g_silk.add(draw.line((1117, 2932), (140, 1955), fill = "none", stroke = "white", stroke_width = "139.629"))
g_pcb.add(g_silk)
# Copper 1
g_cop_par = svg.container.Group(id = "copper1")
g_pcb.add(g_cop_par)
# Copper 0
g_cop = svg.container.Group(id = "copper0")
g_cop_par.add(g_cop)
# Add Pins
for i in range(pins):
g_cop.add(draw.circle((dx * i + 1536, 1536), id = "connector{}pin".format(i), fill = "none", stroke = "#FFBF00", stroke_width = "558.514", r = 810))
# Save the file
draw.save()
add_linebreaks(temp_name, output, True)
# Generates the schematics-view and saves it to a file.
# @param output Target file for saving
# @param resistors Number of resistors
# @param circuittype Type of circuit (STAR or PARALLEL, BUSSED or ISOLATED)
# @param resistance Resistance-value
def gen_schematics(output, resistors, circuittype, resistance):
dy = 7370 # Difference between each pin
min_height = 29993 # Base height of the viewbox for a three-pin-object
height_multiplicator = 0.406945 / min_height
# Used to calculate the height of the SVG in inches
pins = pin_number(resistors, circuittype)
# Calculate the viewbox
height = min_height + (pins - 3) * dy
temp_name = "temp.svg"
draw = svg.Drawing(temp_name,
size = ("0.508346in", str(height * height_multiplicator) + "in"),
viewBox = "0 0 37467 " + str(height))
# Expandable body
expand = (pins - 3) * dy
draw.add(draw.rect((7730, 256), (29481, 29481 + expand), fill = "#FEFEFE", stroke = "#373435", stroke_width = "511.857", stroke_linecap = "round"))
if (circuittype == STAR): draw.add(draw.line((33525, 7626), (33525, 22366 + expand), fill = "none", stroke = "#606062", stroke_width = "511.857", stroke_linecap = "round"))
# External pins
for i in range(pins):
y = dy * i
draw.add(draw.line((358, 7626 + y), (7720, 7626 + y), id = "connector{}pin".format(i), fill = "none", stroke = "#787878", stroke_width = "716.426", stroke_linecap = "round"))
draw.add(draw.rect((321, 7589 + y), (74, 74), fill = "none", id = "connector{}terminal".format(i)))
draw.add(draw.text(str(i + 1), x = [ 3057.2 ], y = [ 6551.4 + y ], fill = "#606062", font_weight = "normal", font_size = "3582.71", font_family = "Droid Sans"))
# Internal pins
for i in range(0, pins, 2):
y = dy * i
draw.add(draw.line((7730, 7625 + y), (33526, 7625 + y), fill = "none", stroke = "#606062", stroke_width = "511.857", stroke_linecap = "round"))
if (circuittype == STAR): break
draw.add(draw.line((33526, 7625 + y), (33526, 7625 + y + dy), fill = "none", stroke = "#606062", stroke_width = "511.857", stroke_linecap = "round"))
# Internal resistors
for i in range(1, pins):
if (circuittype == PARALLEL and not i % 2): continue
y = dy * (i - 1)
path = [
("M", 27998, 14996 + y),
"l5527 0m-6265 2949l737 -2949m-2579 -2948l1842 5897m-3685 0l1843 -5897m-3685 0l1842 5897m-3685 0l1843 -5897m-3685 0l1842 5897m-3685 0l1843 -5897m-3685 0l1842 5897m-2948 -2949l1106 -2948m-6633 2948l5527 0"
]
draw.add(draw.path(fill = "none", stroke = "#606062", stroke_width = "511.857", stroke_linecap = "round", d = path))
# Connectordots
if (circuittype == STAR):
for i in range(1, pins - 1):
y = dy * (i - 1)
draw.add(draw.circle((33451, 14996 + y), r = 663, fill = "#606062", stroke = "#606062", stroke_width = "221.109"))
# Save the file
draw.save()
add_linebreaks(temp_name, output, True)
# Generates the complete part-package ready for inmport to fritzing.
# @param output Target file for saving
# @param resistors Number of resistors
# @param circuittype Type of circuit (STAR or PARALLEL, BUSSED or ISOLATED)
# @param resistance Resistance-value
def gen_part(output, resistors, circuittype, resistance):
name = 'resistor-'
name += 'bussed' if circuittype == PARALLEL else 'isolated'
name += '-' + str(resistors) + '-sip'
basedir = "temp/"
if (os.path.exists(basedir)): shutil.rmtree(basedir)
os.makedirs(basedir)
f_icon = "svg.icon." + name + "_icon.svg"
f_breadboard = "svg.breadboard." + name + "_breadboard.svg"
f_schematic = "svg.schematic." + name + "_schematic.svg"
f_pcb = "svg.pcb." + name + "_pcb.svg"
f_fzp = "part." + name + ".fzp"
gen_icon(basedir + f_icon, resistors, circuittype, resistance)
gen_breadboard(basedir + f_breadboard, resistors, circuittype, resistance)
gen_schematics(basedir + f_schematic, resistors, circuittype, resistance)
gen_pcb(basedir + f_pcb, resistors, circuittype, resistance)
gen_fzp(basedir + f_fzp, resistors, circuittype, resistance, name + "_icon.svg", name + "_breadboard.svg", name + "_schematic.svg", name + "_pcb.svg")
f_zip = zipfile.ZipFile(output, 'w')
for f in [f_icon, f_breadboard, f_schematic, f_pcb, f_fzp]:
f_zip.write(basedir + f, f)
f_zip.close()
shutil.rmtree(basedir)
# Function that get's called once the script is called in the console.
# @param argv Console-parameters.
def main(argv):
try:
opts, args = getopt.getopt(argv, "ho:n:r:pbis", ["help", "output=", "resistors=", "number=", "resistance=", "value=", "parallel", "isolated", "star", "bussed"])
except getopt.GetoptError:
print("Type", sys.argv[0], "-h for usage-information.")
sys.exit(2)
circuittype = 0
output = ""
resistors = 0
resistance = 0
for opt, arg in opts:
if opt in ("-h", "--help"):
print("Small script, that generates resistor-arrays of various sizes.")
print("See: http://forum.fritzing.org/t/2079")
print()
print("Example:", sys.argv[0], "-o test.fzpz -n 5 -p -r 10000")
print()
print("Parameters:")
print("-h, --help: ", "Outputs this help.")
print("-o, --output: ", "Output file to save to.")
print("-n, --resistors, --number n ", "Number of resistors in the circuit (not pins!).")
print("-r, --resistance, --value r ", "Resistance value (e.g. 10000 for 10kOhm).")
print("-p, --parallel, -i, --isolated", "Isolated/Parallel circuit-type.")
print("-s, --star, -b, --bussed ", "Bussed/Star circuit-type.")
sys.exit(0)
elif opt in ("-o", "--output"):
output = arg
elif opt in ("-n", "--resistors", "--number"):
resistors = int(arg)
elif opt in ("-r", "--resistance", "--value"):
resistance = int(arg)
elif opt in ("-p", "--parallel", "-i", "--isolated"):
circuittype = PARALLEL
elif opt in ("-s", "--star", "-b", "--bussed"):
circuittype = STAR
else:
print("Type", sys.argv[0], "-h for usage-information.")
sys.exit(3)
if (circuittype in (STAR, PARALLEL)) and output != "" and resistors > 0 and resistance > 0:
gen_part(output, resistors, circuittype, resistance)
sys.exit(0)
print("Type", sys.argv[0], "-h for usage-information.")
sys.exit(3)
# Call the main function upon launch.
if __name__ == "__main__": main(sys.argv[1:])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment