# Copyright (C) 2002-2006 Alexei Gilchrist and Paul Cochrane # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # $Id: electronics.py,v 1.14 2006/04/24 14:24:03 paultcochrane Exp $ """ PyScript electronics objects library Thanks to Adrian Jonstone's lcircuit macros from CTAN for the ideas and names """ __revision__ = '$Revision: 1.14 $' from pyscript import P, Group, Path, Circle, C, Rectangle, Color class Gate(Group): """ Generic gate class """ def __init__(self, **options): # initialise the base class Group.__init__(self, **options) self.height = 2.0 self.width = 3.0 self.angle = 0.0 self.pinLength = 0.5 self.fg = Color(0) self.bg = Color(1) # AND gate class AndGate(Gate): """ Generates an AND gate @ivar height: gate height @type height: float @ivar width: gate width @type width: float @ivar angle: gate angle @type angle: float @ivar pinLength: length of pins into and out of gate @type pinLength: float @ivar fg: foreground colour @type fg: L{Color} object @ivar bg: background colour @type bg: L{Color} object """ def __init__(self, **options): # initialise the base class Gate.__init__(self, **options) # process the options if any self.height = options.get("height", self.height) self.width = options.get("width", self.width) self.angle = options.get("angle", self.angle) self.pinLength = options.get("pinLength", self.pinLength) self.fg = options.get("fg", self.fg) self.bg = options.get("bg", self.bg) # now draw the gate buff = 0.0 pinEdgeDist = 0.1*self.height bodyHeight = self.height pl = self.pinLength bodyWidth = self.width - 2.0*pl gateBody = Group( Path( P(pl, buff+0), P(pl, buff+bodyHeight), P(pl+bodyWidth/2.0, buff+bodyHeight)), Circle(c=P(pl+bodyWidth/2.0, buff+bodyHeight/2.0), r=bodyHeight/2.0, start=0, end=180), Path( P(pl+bodyWidth/2.0, buff+0), P(pl, buff+0))) gatePinIn1 = Path( P(0, bodyHeight-pinEdgeDist), P(pl, bodyHeight-pinEdgeDist)) gatePinIn2 = Path( P(0, pinEdgeDist), P(pl, pinEdgeDist)) gatePinOut = Path( P(bodyWidth+pl, bodyHeight/2.0), P(bodyWidth+2.0*pl, bodyHeight/2.0)) # collect the objects together obj = Group(gateBody, gatePinIn1, gatePinIn2, gatePinOut) # apply the colours obj.apply(fg=self.fg, bg=self.bg) # rotate if necessary if self.angle != 0.0: obj.rotate(self.angle, p=obj.bbox().c) # now set the object to myself self.append(obj) # NAND gate class NandGate(Gate): """ Generates a NAND gate @ivar height: gate height @type height: float @ivar width: gate width @type width: float @ivar angle: gate angle @type angle: float @ivar pinLength: length of pins into and out of gate @type pinLength: float @ivar fg: foreground colour @type fg: L{Color} object @ivar bg: background colour @type bg: L{Color} object """ def __init__(self, **options): # initialise the base class Gate.__init__(self, **options) # process the options if any self.height = options.get("height", self.height) self.width = options.get("width", self.width) self.angle = options.get("angle", self.angle) self.pinLength = options.get("pinLength", self.pinLength) self.fg = options.get("fg", self.fg) self.bg = options.get("bg", self.bg) # now draw the gate buff = 0.0 pinEdgeDist = 0.1*self.height pl = self.pinLength bodyHeight = self.height bodyWidth = self.width - 2.0*pl rad = 0.1 gateBody = Group( Path( P(pl, buff+0), P(pl, buff+bodyHeight), P(pl+bodyWidth/2., buff+bodyHeight)), Circle(c=P(pl+bodyWidth/2., buff+bodyHeight/2.), r=bodyHeight/2., start=0, end=180), Path( P(pl+bodyWidth/2., buff+0), P(pl, buff+0))) gatePinIn1 = Path( P(0, bodyHeight-pinEdgeDist), P(pl, bodyHeight-pinEdgeDist)) gatePinIn2 = Path( P(0, pinEdgeDist), P(pl, pinEdgeDist)) gatePinOut = Group( Circle(c=P(bodyWidth+pl+rad, bodyHeight/2.), r=rad), Path( P(bodyWidth+pl+2.*rad, bodyHeight/2.), P(bodyWidth+2.*rad+2.*pl, bodyHeight/2.))) # collect the objects together obj = Group(gateBody, gatePinIn1, gatePinIn2, gatePinOut) # apply the colours obj.apply(fg=self.fg, bg=self.bg) # rotate if necessary if self.angle != 0.0: obj.rotate(self.angle, p=obj.c) # now set the object to myself self.append(obj) # OR gate class OrGate(Gate): """ Generates an OR gate @ivar height: gate height @type height: float @ivar width: gate width @type width: float @ivar angle: gate angle @type angle: float @ivar pinLength: length of pins into and out of gate @type pinLength: float @ivar fg: foreground colour @type fg: L{Color} object @ivar bg: background colour @type bg: L{Color} object """ def __init__(self, **options): # initialise the base class Gate.__init__(self, **options) # process the options if any self.height = options.get("height", self.height) self.width = options.get("width", self.width) self.angle = options.get("angle", self.angle) self.pinLength = options.get("pinLength", self.pinLength) self.fg = options.get("fg", self.fg) self.bg = options.get("bg", self.bg) # now draw the gate pinEdgeDist = 0.1*self.height pl = self.pinLength pinBackDist = -0.08*self.width bodyHeight = self.height bodyWidth = self.width - 2.0*pl gateBody = Group( Path( P(-pinBackDist, -pinEdgeDist), C(90, 225), P(1.25*bodyWidth, bodyHeight/2.0), C(-45, 90), P(-pinBackDist, bodyHeight+pinEdgeDist), C(140, 40), closed=1, ) ) gatePinIn1 = Path( P(0, bodyHeight-pinEdgeDist), P(pl, bodyHeight-pinEdgeDist)) gatePinIn2 = Path( P(0, pinEdgeDist), P(pl, pinEdgeDist)) gatePinOut = Path( gateBody.e, gateBody.e+P(pl, 0)) # collect the objects together obj = Group(gateBody, gatePinIn1, gatePinIn2, gatePinOut) # apply the colours obj.apply(fg=self.fg, bg=self.bg) # rotate if necessary if self.angle != 0.0: obj.rotate(self.angle, p=obj.c) # now set the object to myself self.append(obj) # NOR gate class NorGate(Gate): """ Generates a NOR gate @ivar height: gate height @type height: float @ivar width: gate width @type width: float @ivar angle: gate angle @type angle: float @ivar pinLength: length of pins into and out of gate @type pinLength: float @ivar fg: foreground colour @type fg: L{Color} object @ivar bg: background colour @type bg: L{Color} object """ def __init__(self, **options): # initialise the base class Gate.__init__(self, **options) # process the options if any self.height = options.get("height", self.height) self.width = options.get("width", self.width) self.angle = options.get("angle", self.angle) self.pinLength = options.get("pinLength", self.pinLength) self.fg = options.get("fg", self.fg) self.bg = options.get("bg", self.bg) # now draw the gate pl = self.pinLength pinEdgeDist = 0.1*self.height pinBackDist = -0.08*self.width bodyHeight = self.height bodyWidth = self.width - 2.0*pl rad = 0.1 gateBody = Group( Path( P(-pinBackDist, -pinEdgeDist), C(90, 225), P(1.25*bodyWidth, bodyHeight/2.0), C(-45, 90), P(-pinBackDist, bodyHeight+pinEdgeDist), C(140, 40), closed=1, ) ) gatePinIn1 = Path( P(0, bodyHeight-pinEdgeDist), P(pl, bodyHeight-pinEdgeDist)) gatePinIn2 = Path( P(0, pinEdgeDist), P(pl, pinEdgeDist)) gatePinOut = Group( Circle(w=gateBody.e, r=rad), Path( gateBody.e+P(0.2, 0), gateBody.e+P(pl+0.2, 0)), ) # collect the objects together obj = Group(gateBody, gatePinIn1, gatePinIn2, gatePinOut) # apply the colours obj.apply(fg=self.fg, bg=self.bg) # rotate if necessary if self.angle != 0.0: obj.rotate(self.angle, p=obj.c) # nwo set the object to myself self.append(obj) # XOR gate class XorGate(Gate): """ Generates an XOR gate @ivar height: gate height @type height: float @ivar width: gate width @type width: float @ivar angle: gate angle @type angle: float @ivar pinLength: length of pins into and out of gate @type pinLength: float @ivar fg: foreground colour @type fg: L{Color} object @ivar bg: background colour @type bg: L{Color} object """ def __init__(self, **options): # initialise the base class Gate.__init__(self, **options) # process the options if any self.height = options.get("height", self.height) self.width = options.get("width", self.width) self.angle = options.get("angle", self.angle) self.pinLength = options.get("pinLength", self.pinLength) self.fg = options.get("fg", self.fg) self.bg = options.get("bg", self.bg) # now draw the gate pinEdgeDist = 0.1*self.height pinBackDist = -0.08*self.width xBit = 0.2 pl = self.pinLength bodyHeight = self.height bodyWidth = self.width - 2.0*pl gateBody = Group( Path( P(-pinBackDist+xBit, -pinEdgeDist), C(90, 225), P(1.4*bodyWidth, bodyHeight/2.), C(-45, 90), P(-pinBackDist+xBit, bodyHeight+pinEdgeDist), C(140, 40), P(-pinBackDist+xBit, -pinEdgeDist), ), Path( P(-pinBackDist, bodyHeight+pinEdgeDist), C(140, 40), P(-pinBackDist, -pinEdgeDist) ), ) gatePinIn1 = Path( P(0, bodyHeight-pinEdgeDist), P(pl, bodyHeight-pinEdgeDist)) gatePinIn2 = Path( P(0, pinEdgeDist), P(pl, pinEdgeDist)) gatePinOut = Path( gateBody.e, gateBody.e+P(pl, 0)) # collect the objects together obj = Group(gateBody, gatePinIn1, gatePinIn2, gatePinOut) # apply the colours obj.apply(fg=self.fg, bg=self.bg) # rotate if necessary if self.angle != 0.0: obj.rotate(self.angle, p=obj.c) # now set the object to myself self.append(obj) # NXOR gate class NxorGate(Gate): """ Generates a NXOR gate @ivar height: gate height @type height: float @ivar width: gate width @type width: float @ivar angle: gate angle @type angle: float @ivar pinLength: length of pins into and out of gate @type pinLength: float @ivar fg: foreground colour @type fg: L{Color} object @ivar bg: background colour @type bg: L{Color} object """ def __init__(self, **options): # initialise the base class Gate.__init__(self, **options) # process the options if any self.height = options.get("height", self.height) self.width = options.get("width", self.width) self.angle = options.get("angle", self.angle) self.pinLength = options.get("pinLength", self.pinLength) self.fg = options.get("fg", self.fg) self.bg = options.get("bg", self.bg) # now draw the gate pinEdgeDist = 0.1*self.height pinBackDist = -0.08*self.width xBit = 0.2 rad = 0.1 pl = self.pinLength bodyHeight = self.height bodyWidth = self.width - 2.0*pl gateBody = Group( Path( P(-pinBackDist+xBit, -pinEdgeDist), C(90, 225), P(1.4*bodyWidth, bodyHeight/2.), C(-45, 90), P(-pinBackDist+xBit, bodyHeight+pinEdgeDist), C(140, 40), P(-pinBackDist+xBit, -pinEdgeDist), ), Path( P(-pinBackDist, bodyHeight+pinEdgeDist), C(140, 40), P(-pinBackDist, -pinEdgeDist) ), ) gatePinIn1 = Path( P(0, bodyHeight-pinEdgeDist), P(pl, bodyHeight-pinEdgeDist)) gatePinIn2 = Path( P(0, pinEdgeDist), P(pl, pinEdgeDist)) gatePinOut = Group( Circle(w=gateBody.e, r=rad), Path( gateBody.e+P(0.2, 0), gateBody.e+P(pl+0.2, 0)), ) # collect the objects together obj = Group(gateBody, gatePinIn1, gatePinIn2, gatePinOut) # apply the colours obj.apply(fg=self.fg, bg=self.bg) # rotate if necessary if self.angle != 0.0: obj.rotate(self.angle, p=obj.c) # now set the object to myself self.append(obj) # NOT gate class NotGate(Gate): """ Generates a NOT gate @ivar height: gate height @type height: float @ivar width: gate width @type width: float @ivar angle: gate angle @type angle: float @ivar pinLength: length of pins into and out of gate @type pinLength: float @ivar fg: foreground colour @type fg: L{Color} object @ivar bg: background colour @type bg: L{Color} object """ def __init__(self, **options): # initialise the base class Gate.__init__(self, **options) # process the options if any self.height = options.get("height", self.height) self.width = options.get("width", self.width) self.angle = options.get("angle", self.angle) self.pinLength = options.get("pinLength", self.pinLength) self.fg = options.get("fg", self.fg) self.bg = options.get("bg", self.bg) # now draw the gate buff = 0 pl = self.pinLength pinEdgeDist = 0.1*self.height bodyHeight = self.height bodyWidth = self.width - 2.0*pl rad = 0.1 gateBody = Group( Path( P(pl, buff+0), P(pl, buff+bodyHeight), P(pl+0.707106781*bodyWidth, buff+bodyHeight/2.), P(pl, buff+0) ) ) gatePinIn1 = Path( P(0, bodyHeight-pinEdgeDist), P(pl, bodyHeight-pinEdgeDist)) gatePinIn2 = Path( P(0, pinEdgeDist), P(pl, pinEdgeDist)) gatePinOut = Group( Circle(w=gateBody.e, r=rad), Path( gateBody.e+P(2.*rad, 0), gateBody.e+P(2.*rad+pl, 0)) ) # collect the objects together obj = Group(gateBody, gatePinIn1, gatePinIn2, gatePinOut) # apply the colours obj.apply(fg=self.fg, bg=self.bg) # rotate if necessary if self.angle != 0.0: obj.rotate(self.angle, p=obj.c) # now set the object to myself self.append(obj) # resistor class Resistor(Group): """ Generates a box resistor @ivar length: length of resistor @type length: float @ivar width: width of resistor @type width: float @ivar angle: gate angle @type angle: float @ivar pinLength: length of pins into and out of resistor @type pinLength: float @ivar fg: foreground colour @type fg: L{Color} object @ivar bg: background colour @type bg: L{Color} object """ def __init__(self, **options): # intitialise base class Group.__init__(self, **options) self.length = 3.0 self.width = 1.0 self.angle = 0.0 self.pinLength = 0.5 self.fg = Color(0) self.bg = Color(1) # process the options if any self.length = options.get("length", self.length) self.width = options.get("width", self.width) self.angle = options.get("angle", self.angle) self.pinLength = options.get("pinLength", self.pinLength) self.fg = options.get("fg", self.fg) self.bg = options.get("bg", self.bg) pinIn = Group( Path( P(0, 0), P(self.pinLength, 0) ) ) resistor = Rectangle(w=pinIn.e, width=self.length, height=self.width) pinOut = Path( resistor.e, resistor.e+P(self.pinLength, 0)) # collect the objects together obj = Group(pinIn, pinOut, resistor) # apply the colours obj.apply(fg=self.fg, bg=self.bg) # rotate if necessary if self.angle != 0.0: obj.rotate(self.angle, p=obj.c) # return object to myself self.append(obj) # capacitor class Capacitor(Group): """ Generates a capacitor @ivar width: width of capacitor @type width: float @ivar sep: separation of the plates of the capacitor @type sep: float @ivar angle: gate angle @type angle: float @ivar pinLength: length of pins into and out of capacitor @type pinLength: float @ivar fg: foreground colour @type fg: L{Color} object @ivar bg: background colour @type bg: L{Color} object """ def __init__(self, **options): # intitialise base class Group.__init__(self, **options) self.sep = 0.25 self.width = 1.0 self.angle = 0.0 self.pinLength = 0.5 self.fg = Color(0) self.bg = Color(1) # process the options if any self.sep = options.get("sep", self.sep) self.width = options.get("width", self.width) self.angle = options.get("angle", self.angle) self.pinLength = options.get("pinLength", self.pinLength) self.fg = options.get("fg", self.fg) self.bg = options.get("bg", self.bg) pinIn = Group( Path( P(0, 0), P(self.pinLength, 0), ) ) cap = Group( Path(pinIn.e+P(0, -self.width/2.0), pinIn.e+P(0, self.width/2.0)), Path(pinIn.e+P(self.sep, -self.width/2.0), pinIn.e+P(self.sep, self.width/2.0)), ) pinOut = Path( cap.e, cap.e+P(self.pinLength, 0)) # group the objects together obj = Group(pinIn, pinOut, cap) # apply the colours obj.apply(fg=self.fg, bg=self.bg) # rotate if necessary if self.angle != 0.0: obj.rotate(self.angle, p=obj.c) # set the object to myself self.append(obj) # vim: expandtab shiftwidth=4: