From c1e0a8d067095d527eacf6350670a6361ec619d9 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 14 Sep 2014 18:29:10 +0200 Subject: [PATCH] Patch for the Python footprint wizard helpers. This adds a few more drawing functions, such as for circles, and also uses a matrix-based transform stack with greatly simplifies constructing footprints consisting of regularly spaced elements (e.g. in lines, grids, circles, or some list of points that you specify). This fixes bug #1366299 --- .../plugins/FPC_(SMD_type)_footprintwizard.py | 2 +- .../plugins/FootprintWizardDrawingAids.py | 435 ++++++++++++++++-- .../plugins/HelpfulFootprintWizardPlugin.py | 126 +++-- pcbnew/scripting/plugins/PadArray.py | 218 +++++++-- pcbnew/scripting/plugins/__init__.py | 1 + pcbnew/scripting/plugins/bga_wizard.py | 41 +- pcbnew/scripting/plugins/pad_arrays.py | 77 ++++ pcbnew/scripting/plugins/qfp_wizard.py | 75 ++- pcbnew/scripting/plugins/sdip_wizard.py | 81 ++-- 9 files changed, 860 insertions(+), 196 deletions(-) create mode 100644 pcbnew/scripting/plugins/__init__.py create mode 100644 pcbnew/scripting/plugins/pad_arrays.py diff --git a/pcbnew/scripting/plugins/FPC_(SMD_type)_footprintwizard.py b/pcbnew/scripting/plugins/FPC_(SMD_type)_footprintwizard.py index 8a43a34b89..2c2cb4fdc5 100644 --- a/pcbnew/scripting/plugins/FPC_(SMD_type)_footprintwizard.py +++ b/pcbnew/scripting/plugins/FPC_(SMD_type)_footprintwizard.py @@ -30,7 +30,7 @@ class FPCFootprintWizard(FootprintWizardPlugin): pad.SetSize(size) pad.SetShape(PAD_RECT) pad.SetAttribute(PAD_SMD) - pad.SetLayerSet( pad.StandardMask() ) + pad.SetLayerSet( pad.SMDMask() ) pad.SetPos0(pos) pad.SetPosition(pos) pad.SetPadName(name) diff --git a/pcbnew/scripting/plugins/FootprintWizardDrawingAids.py b/pcbnew/scripting/plugins/FootprintWizardDrawingAids.py index d1046bdafb..ba82ebec8b 100644 --- a/pcbnew/scripting/plugins/FootprintWizardDrawingAids.py +++ b/pcbnew/scripting/plugins/FootprintWizardDrawingAids.py @@ -14,7 +14,11 @@ # MA 02110-1301, USA. # +from __future__ import division + import pcbnew +import math + class FootprintWizardDrawingAids: """ @@ -24,31 +28,291 @@ class FootprintWizardDrawingAids: A "drawing context" is provided which can be used to set and retain settings such as line width and layer """ + + # directions (in degrees, compass-like) + dirN = 0 + dirNE = 45 + dirE = 90 + dirSE = 135 + dirS = 180 + dirSW = 225 + dirW = 270 + dirNW = 315 + + # flip constants + flipNone = 0 + flipX = 1 # flip X values, i.e. about Y + flipY = 2 # flip Y valuersabout X + flipBoth = 3 + + xfrmIDENTITY = [1, 0, 0, 0, 1, 0] # no transform + def __init__(self, module): self.module = module - #drawing context defaults + # drawing context defaults self.dc = { - 'layer': pcbnew.SILKSCREEN_N_FRONT, - 'width': pcbnew.FromMM(0.2) + 'layer': pcbnew.F_SilkS, + 'width': pcbnew.FromMM(0.2), + 'transforms': [], + 'transform': self.xfrmIDENTITY } + def PushTransform(self, mat): + """ + Add a transform to the top of the stack and recompute the + overall transform + """ + self.dc['transforms'].append(mat) + self.RecomputeTransforms() + + def PopTransform(self, num=1): + """ + Remove a transform from the top of the stack and recompute the + overall transform + """ + + for i in range(num): + mat = self.dc['transforms'].pop() + self.RecomputeTransforms() + return mat + + def ResetTransform(self): + """ + Reset the transform stack to the identity matrix + """ + self.dc['transforms'] = [] + self.RecomputeTransforms() + + def _ComposeMatricesWithIdentity(self, mats): + """ + Compose a sequence of matrices together by sequential + pre-mutiplciation with the identity matrix + """ + + x = self.xfrmIDENTITY + + for mat in mats: + #precompose with each transform in turn + x = [ + x[0] * mat[0] + x[1] * mat[3], + x[0] * mat[1] + x[1] * mat[4], + x[0] * mat[2] + x[1] * mat[5] + x[2], + x[3] * mat[0] + x[4] * mat[3], + x[3] * mat[1] + x[4] * mat[4], + x[3] * mat[2] + x[4] * mat[5] + x[5]] + + return x + + def RecomputeTransforms(self): + """ + Re-compute the transform stack into a single transform and + store in the DC + """ + self.dc['transform'] = self._ComposeMatricesWithIdentity( + self.dc['transforms']) + + def TransformTranslate(self, x, y, push=True): + """ + Set up and return a transform matrix representing a translartion + optionally pushing onto the stack + + ( 1 0 x ) + ( 0 1 y ) + """ + mat = [1, 0, x, 0, 1, y] + + if push: + self.PushTransform(mat) + return mat + + def TransformFlipOrigin(self, flip, push=True): + """ + Set up and return a transform matrix representing a horizontal, + vertical or both flip about the origin + """ + mat = None + if flip == self.flipX: + mat = [-1, 0, 0, 0, 1, 0] + elif flip == self.flipY: + mat = [1, 0, 0, 0, -1, 0] + elif flip == self.flipBoth: + mat = [-1, 0, 0, 0, -1, 0] + elif flip == self.flipNone: + mat = self.xfrmIDENTITY + else: + raise ValueError + + if push: + self.PushTransform(mat) + return mat + + def TransformFlip(self, x, y, flip=flipNone, push=True): + """ + Set up and return a transform matrix representing a horizontal, + vertical or both flip about a point (x,y) + + This is performed by a translate-to-origin, flip, translate- + back sequence + """ + mats = [self.TransformTranslate(x, y, push=False), + self.TransformFlipOrigin(flip, push=False), + self.TransformTranslate(-x, -y, push=False)] + + #distill into a single matrix + mat = self._ComposeMatricesWithIdentity(mats) + + if push: + self.PushTransform(mat) + return mat + + def TransformRotationOrigin(self, rot, push=True): + """ + Set up and return a transform matrix representing a rotation + about the origin, and optionally push onto the stack + + ( cos(t) -sin(t) 0 ) + ( sin(t) cos(t) 0 ) + """ + rads = rot * math.pi / 180 + mat = [math.cos(rads), -math.sin(rads), 0, + math.sin(rads), math.cos(rads), 0] + + if push: + self.PushTransform(mat) + return mat + + def TransformRotation(self, x, y, rot, push=True): + """ + Set up and return a transform matrix representing a rotation + about the pooint (x,y), and optionally push onto the stack + + This is performed by a translate-to-origin, rotate, translate- + back sequence + """ + + mats = [self.TransformTranslate(x, y, push=False), + self.TransformRotationOrigin(rot, push=False), + self.TransformTranslate(-x, -y, push=False)] + + #distill into a single matrix + mat = self._ComposeMatricesWithIdentity(mats) + + if push: + self.PushTransform(mat) + return mat + + def TransformScaleOrigin(self, sx, sy=None, push=True): + """ + Set up and return a transform matrix representing a scale about + the origin, and optionally push onto the stack + + ( sx 0 0 ) + ( 0 sy 0 ) + """ + + if sy is None: + sy = sx + + mat = [sx, 0, 0, 0, sy, 0] + + if push: + self.PushTransform(mat) + return mat + + def TransformPoint(self, x, y, mat=None): + """ + Return a point (x, y) transformed by the given matrix, or if + that is not given, the drawing context transform + """ + + if not mat: + mat = self.dc['transform'] + + return pcbnew.wxPoint(x * mat[0] + y * mat[1] + mat[2], + x * mat[3] + y * mat[4] + mat[5]) + def SetWidth(self, width): + """ + Set the current pen width used for subsequent drawing + operations + """ self.dc['width'] = width + def GetWidth(self): + """ + Get the current drawing context width + """ + return self.dc['width'] + def SetLayer(self, layer): + """ + Set the current drawing layer, used for subsequent drawing + operations + """ self.dc['layer'] = layer def Line(self, x1, y1, x2, y2): + """ + Draw a line from (x1, y1) to (x2, y2) + """ outline = pcbnew.EDGE_MODULE(self.module) outline.SetWidth(self.dc['width']) outline.SetLayer(self.dc['layer']) outline.SetShape(pcbnew.S_SEGMENT) - start = pcbnew.wxPoint(x1, y1) - end = pcbnew.wxPoint(x2, y2) + start = self.TransformPoint(x1, y1) + end = self.TransformPoint(x2, y2) outline.SetStartEnd(start, end) self.module.Add(outline) + def Circle(self, x, y, r, filled=False): + """ + Draw a circle at (x,y) of radius r + + If filled is true, the width and radius of the line will be set + such that the circle appears filled + """ + circle = pcbnew.EDGE_MODULE(self.module) + start = self.TransformPoint(x, y) + + if filled: + circle.SetWidth(r) + end = self.TransformPoint(x, y + r/2) + else: + circle.SetWidth(self.dc['width']) + end = self.TransformPoint(x, y + r) + + circle.SetLayer(self.dc['layer']) + circle.SetShape(pcbnew.S_CIRCLE) + circle.SetStartEnd(start, end) + self.module.Add(circle) + + def Arc(self, cx, cy, sx, sy, a): + """ + Draw an arc based on centre, start and angle + + The transform matrix is applied + + Note that this won't work properly if the result is not a + circular arc (eg a horzontal scale) + """ + circle = pcbnew.EDGE_MODULE(self.module) + circle.SetWidth(self.dc['width']) + + center = self.TransformPoint(cx, cy) + start = self.TransformPoint(sx, sy) + + circle.SetLayer(self.dc['layer']) + circle.SetShape(pcbnew.S_ARC) + + # check if the angle needs to be reverse (a flip scaling) + if cmp(self.dc['transform'][0], 0) != cmp(self.dc['transform'][4], 0): + a = -a + + circle.SetAngle(a) + circle.SetStartEnd(center, start) + self.module.Add(circle) + # extends from (x1,y1) right def HLine(self, x, y, l): """ @@ -62,13 +326,34 @@ class FootprintWizardDrawingAids: """ self.Line(x, y, x, y + l) - def Polyline(self, pts): + def Polyline(self, pts, mirrorX=None, mirrorY=None): + """ + Draw a polyline, optinally mirroring around the given points + """ - if len(pts) < 2: - return + def _PolyLineInternal(pts): + if len(pts) < 2: + return - for i in range(0, len(pts) - 1): - self.Line(pts[i][0], pts[i][1], pts[i+1][0], pts[i+1][1]) + for i in range(0, len(pts) - 1): + self.Line(pts[i][0], pts[i][1], pts[i+1][0], pts[i+1][1]) + + _PolyLineInternal(pts) # original + + if mirrorX is not None: + self.TransformFlip(mirrorX, 0, self.flipX) + _PolyLineInternal(pts) + self.PopTransform() + + if mirrorY is not None: + self.TransformFlipOrigin(0, mirrorY, self.flipY) + _PolyLineInternal(pts) + self.PopTransform() + + if mirrorX is not None and mirrorY is not None: + self.TransformFlip(mirrorX, mirrorY, self.flipBoth) # both + _PolyLineInternal(pts) + self.PopTransform() def Reference(self, x, y, size): """ @@ -80,8 +365,9 @@ class FootprintWizardDrawingAids: text_size = pcbnew.wxSize(size, size) - self.module.Reference().SetPos0(pcbnew.wxPoint(x, y)) - self.module.Reference().SetTextPosition(self.module.Reference().GetPos0()) + self.module.Reference().SetPos0(self.TransformPoint(x, y)) + self.module.Reference().SetTextPosition( + self.module.Reference().GetPos0()) self.module.Reference().SetSize(text_size) def Value(self, x, y, size): @@ -90,7 +376,7 @@ class FootprintWizardDrawingAids: """ text_size = pcbnew.wxSize(size, size) - self.module.Value().SetPos0(pcbnew.wxPoint(x, y)) + self.module.Value().SetPos0(self.TransformPoint(x, y)) self.module.Value().SetTextPosition(self.module.Value().GetPos0()) self.module.Value().SetSize(text_size) @@ -99,36 +385,115 @@ class FootprintWizardDrawingAids: Draw a rectangular box, centred at (x,y), with given width and height """ - self.VLine(x - w/2, y - h/2, h) # left - self.VLine(x + w/2, y - h/2, h) # right - self.HLine(x - w/2, y + h/2, w) # bottom - self.HLine(x - w/2, y - h/2, w) # top + + pts = [[x - w/2, y - h/2], # left + [x + w/2, y - h/2], # right + [x + w/2, y + h/2], # bottom + [x - w/2, y + h/2], # top + [x - w/2, y - h/2]] # close + + self.Polyline(pts) + + def NotchedCircle(self, x, y, r, notch_w, notch_h): + """ + Circle radus r centred at (x, y) with a raised or depressed notch + at the top + + Notch height is measured from the top of the circle radius + """ + # find the angle where the notch vertical meets the circle + angle_intercept = math.asin(notch_w/(2 * r)) + + # and find the co-ords of this point + sx = math.sin(angle_intercept) * r + sy = -math.cos(angle_intercept) * r + + # NOTE: this may be out by a factor of ten one day + arc_angle = (math.pi * 2 - angle_intercept * 2) * (1800/math.pi) + + self.Arc(x,y, sx, sy, arc_angle) + + pts = [[sx, sy], + [sx, -r - notch_h], + [-sx, -r - notch_h], + [-sx, sy]] + + self.Polyline(pts) def NotchedBox(self, x, y, w, h, notchW, notchH): """ Draw a box with a notch in the top edge """ - #limit to half the overall width + # limit to half the overall width notchW = min(x + w/2, notchW) # draw notch - self.Polyline([ #three sides of box - (x - w/2, y - h/2), - (x - w/2, y + h/2), - (x + w/2, y + h/2), - (x + w/2, y - h/2), - #the notch - (notchW/2, y - h/2), - (notchW/2, y - h/2 + notchH), - (-notchW/2, y - h/2 + notchH), - (-notchW/2, y - h/2), - (x - w/2, y - h/2) - ]) + self.Polyline([ # three sides of box + (x - w/2, y - h/2), + (x - w/2, y + h/2), + (x + w/2, y + h/2), + (x + w/2, y - h/2), + # the notch + (notchW/2, y - h/2), + (notchW/2, y - h/2 + notchH), + (-notchW/2, y - h/2 + notchH), + (-notchW/2, y - h/2), + (x - w/2, y - h/2) + ]) - def BoxWithDiagonalAtCorner(self, x, y, w, h, diagSetback): + def BoxWithDiagonalAtCorner(self, x, y, w, h, + setback=pcbnew.FromMM(1.27), flip=flipNone): + """ + Draw a box with a diagonal at the top left corner + """ - self.Box(x, y, w, h) + self.TransformFlip(x, y, flip, push=True) - #diagonal corner - self.Line(x - w/2 + diagSetback, x - h/2, x - w/2, - x - h/2 + diagSetback) + pts = [[x - w/2 + setback, y - h/2], + [x - w/2, y - h/2 + setback], + [x - w/2, y + h/2], + [x + w/2, y + h/2], + [x + w/2, y - h/2], + [x - w/2 + setback, y - h/2]] + + self.Polyline(pts) + + self.PopTransform() + + def BoxWithOpenCorner(self, x, y, w, h, + setback=pcbnew.FromMM(1.27), flip=flipNone): + """ + Draw a box with an opening at the top left corner + """ + + self.TransformTranslate(x, y) + self.TransformFlipOrigin(flip) + + pts = [[- w/2, - h/2 + setback], + [- w/2, + h/2], + [+ w/2, + h/2], + [+ w/2, - h/2], + [- w/2 + setback, - h/2]] + + self.Polyline(pts) + + self.PopTransform(num=2) + + def MarkerArrow(self, x, y, direction=dirN, width=pcbnew.FromMM(1)): + """ + Draw a marker arrow facing in the given direction, with the + point at (x,y) + + Direction of 0 is north + """ + + self.TransformTranslate(x, y) + self.TransformRotationOrigin(direction) + + pts = [[0, 0], + [width / 2, width / 2], + [-width / 2, width / 2], + [0, 0]] + + self.Polyline(pts) + self.PopTransform(2) diff --git a/pcbnew/scripting/plugins/HelpfulFootprintWizardPlugin.py b/pcbnew/scripting/plugins/HelpfulFootprintWizardPlugin.py index de93cfda03..4b69ef0b10 100644 --- a/pcbnew/scripting/plugins/HelpfulFootprintWizardPlugin.py +++ b/pcbnew/scripting/plugins/HelpfulFootprintWizardPlugin.py @@ -15,8 +15,10 @@ # import pcbnew +import math import FootprintWizardDrawingAids + class FootprintWizardParameterManager: """ Functions for helpfully managing parameters to a KiCAD Footprint @@ -50,8 +52,9 @@ class FootprintWizardParameterManager: uMils = 2 uNatural = 3 uBool = 4 + uString = 5 - def AddParam(self, section, param, unit, default, hint = ''): + def AddParam(self, section, param, unit, default, hint=''): """ Add a parameter with some properties. @@ -66,14 +69,16 @@ class FootprintWizardParameterManager: val = pcbnew.FromMils(default) elif unit == self.uNatural: val = default + elif unit == self.uString: + val = str(default) elif unit == self.uBool: - val = "True" if default else "False" #ugly stringing + val = "True" if default else "False" # ugly stringing else: print "Warning: Unknown unit type: %s" % unit return - if unit in [self.uNatural, self.uBool]: - param = "*%s" % param #star prefix for natural + if unit in [self.uNatural, self.uBool, self.uString]: + param = "*%s" % param # star prefix for natural if section not in self.parameters: self.parameters[section] = {} @@ -89,7 +94,8 @@ class FootprintWizardParameterManager: for key, value in section.iteritems(): unit = "" - if (type(value) is int or type(value) is float) and not "*" in key: + if ((type(value) is int or type(value) is float) + and not "*" in key): unit = "mm" if "*" in key: @@ -101,7 +107,7 @@ class FootprintWizardParameterManager: def _ParametersHaveErrors(self): """ - Return true if we discovered errors suring parameter processing + Return true if we discovered errors during parameter processing """ for name, section in self.parameter_errors.iteritems(): @@ -124,8 +130,8 @@ class FootprintWizardParameterManager: if not printed_section: print " %s:" % name - print " %s: %s (have %s)" % (key, value, - self.parameters[name][key]) + print " %s: %s (have %s)" % ( + key, value, self.parameters[name][key]) def ProcessParameters(self): """ @@ -134,14 +140,15 @@ class FootprintWizardParameterManager: """ self.ClearErrors() - self.CheckParameters(); + self.CheckParameters() if self._ParametersHaveErrors(): print "Cannot build footprint: Parameters have errors:" self._PrintParameterErrors() return False - print "Building new %s footprint with the following parameters:" % self.name + print ("Building new %s footprint with the following parameters:" + % self.name) self._PrintParameterTable() return True @@ -150,29 +157,37 @@ class FootprintWizardParameterManager: # PARAMETER CHECKERS ################################################################# - def CheckParamPositiveInt(self, section, param, min_value = 1, - max_value = None, is_multiple_of = 1): + def CheckParamInt(self, section, param, min_value=1, + max_value=None, is_multiple_of=1): """ Make sure a parameter can be made into an int, and enforce limits if required """ try: - self.parameters[section][param] = int(self.parameters[section][param]) + self.parameters[section][param] = ( + int(self.parameters[section][param])) except ValueError: - self.parameter_errors[section][param] = "Must be a valid integer" + self.parameter_errors[section][param] = ( + "Must be a valid integer") return - if min_value is not None and (self.parameters[section][param] < min_value): - self.parameter_errors[section][param] = "Must be greater than or equal to %d" % (min_value) + if min_value is not None and ( + self.parameters[section][param] < min_value): + self.parameter_errors[section][param] = ( + "Must be greater than or equal to %d" % (min_value)) return - if max_value is not None and (self.parameters[section][param] > min_value): - self.parameter_errors[section][param] = "Must be less than or equal to %d" % (max_value) + if max_value is not None and ( + self.parameters[section][param] > min_value): + self.parameter_errors[section][param] = ( + "Must be less than or equal to %d" % (max_value)) return - if is_multiple_of > 1 and (self.parameters[section][param] % is_multiple_of) > 0: - self.parameter_errors[section][param] = "Must be a multiple of %d" % is_multiple_of + if is_multiple_of > 1 and ( + self.parameters[section][param] % is_multiple_of) > 0: + self.parameter_errors[section][param] = ( + "Must be a multiple of %d" % is_multiple_of) return return @@ -182,11 +197,13 @@ class FootprintWizardParameterManager: Make sure a parameter looks like a boolean, convert to native boolean type if so """ - if str(self.parameters[section][param]).lower() in ["true", "t", "y", "yes", "on", "1", "1.0"]: - self.parameters[section][param] = True; + if str(self.parameters[section][param]).lower() in [ + "true", "t", "y", "yes", "on", "1", "1.0"]: + self.parameters[section][param] = True return - elif str(self.parameters[section][param]).lower() in ["false", "f", "n", "no", "off", "0", "0.0"]: - self.parameters[section][param] = False; + elif str(self.parameters[section][param]).lower() in [ + "false", "f", "n", "no", "off", "0", "0.0"]: + self.parameters[section][param] = False return self.parameter_errors[section][param] = "Must be boolean (true/false)" @@ -194,7 +211,7 @@ class FootprintWizardParameterManager: class HelpfulFootprintWizardPlugin(pcbnew.FootprintWizardPlugin, - FootprintWizardParameterManager): + FootprintWizardParameterManager): """ A class to simplify many aspects of footprint creation, leaving only the foot-print specific routines to the wizards themselves @@ -216,16 +233,46 @@ class HelpfulFootprintWizardPlugin(pcbnew.FootprintWizardPlugin, self.decription = self.GetDescription() self.image = self.GetImage() - def GetReference(self): + def GetValue(self): raise NotImplementedError - def GetValuePrefix(self): - return "U" # footprints needing wizards of often ICs + def GetReferencePrefix(self): + return "U" # footprints needing wizards of often ICs def GetImage(self): return "" + def GetTextSize(self): + """ + IPC nominal + """ + return pcbnew.FromMM(1.2) + + def GetTextThickness(self): + """ + Thicker than IPC guidelines (10% of text height = 0.12mm) + as 5 wires/mm is a common silk screen limitation + """ + return pcbnew.FromMM(0.2) + + def SetModule3DModel(self): + """ + Set a 3D model for the module + + Default is to do nothing, you need to implement this if you have + a model to set + + FIXME: This doesn't seem to be enabled yet? + """ + pass + def BuildThisFootprint(self): + """ + Draw the footprint. + + This is specific to each footprint class, you need to implment + this to draw what you want + """ raise NotImplementedError def BuildFootprint(self): @@ -234,17 +281,26 @@ class HelpfulFootprintWizardPlugin(pcbnew.FootprintWizardPlugin, the implmenting class """ + self.module = pcbnew.MODULE(None) # create a new module + # do it first, so if we return early, we don't segfault KiCad + if not self.ProcessParameters(): return - self.module = pcbnew.MODULE(None) # create a new module + self.draw = FootprintWizardDrawingAids.FootprintWizardDrawingAids( + self.module) - self.draw = FootprintWizardDrawingAids.FootprintWizardDrawingAids(self.module) + self.module.SetValue(self.GetValue()) + self.module.SetReference("%s**" % self.GetReferencePrefix()) - self.module.SetReference(self.GetReference()) - self.module.SetValue("%s**" % self.GetValuePrefix()) + fpid = pcbnew.FPID(self.module.GetValue()) # the name in library + self.module.SetFPID(fpid) - fpid = pcbnew.FPID(self.module.GetReference()) #the name in library - self.module.SetFPID( fpid ) + self.BuildThisFootprint() # implementer's build function - self.BuildThisFootprint() # implementer's build function + self.SetModule3DModel() # add a 3d module if specified + + thick = self.GetTextThickness() + + self.module.Reference().SetThickness(thick) + self.module.Value().SetThickness(thick) diff --git a/pcbnew/scripting/plugins/PadArray.py b/pcbnew/scripting/plugins/PadArray.py index 9e4d9b3572..97b93c20af 100644 --- a/pcbnew/scripting/plugins/PadArray.py +++ b/pcbnew/scripting/plugins/PadArray.py @@ -1,4 +1,27 @@ +# PadArray.py +# +# Copyright 2014 john +# +# 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., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. +# +# +from __future__ import division + +import math import pcbnew class PadMaker: @@ -9,7 +32,7 @@ class PadMaker: def __init__(self, module): self.module = module - def THPad(self, w, l, drill, shape = pcbnew.PAD_OVAL): + def THPad(self, w, l, drill, shape=pcbnew.PAD_OVAL): pad = pcbnew.D_PAD(self.module) pad.SetSize(pcbnew.wxSize(l, w)) @@ -22,7 +45,23 @@ class PadMaker: return pad - def SMDPad(self, w, l, shape = pcbnew.PAD_RECT): + def THRoundPad(self, size, drill): + pad = self.THPad(size, size, drill, shape=pcbnew.PAD_CIRCLE) + return pad + + def NPTHRoundPad(self, drill): + pad = pcbnew.D_PAD(self.module) + + pad.SetSize(pcbnew.wxSize(drill, drill)) + + pad.SetShape(pcbnew.PAD_CIRCLE) + + pad.SetAttribute(pcbnew.PAD_HOLE_NOT_PLATED) + pad.SetLayerSet(pad.UnplatedHoleMask()) + pad.SetDrillSize(pcbnew.wxSize(drill, drill)) + return pad + + def SMDPad(self, w, l, shape=pcbnew.PAD_RECT): pad = pcbnew.D_PAD(self.module) pad.SetSize(pcbnew.wxSize(l, w)) @@ -34,23 +73,65 @@ class PadMaker: return pad def SMTRoundPad(self, size): - pad = self.SMDPad(size, size, shape = pcbnew.PAD_CIRCLE) + pad = self.SMDPad(size, size, shape=pcbnew.PAD_CIRCLE) return pad + class PadArray: def __init__(self): - self.firstPad = 1; + self.firstPadNum = 1 + self.pinNames = None + self.firstPad = None + + def SetPinNames(self, pinNames): + """ + Set a name for all the pins + """ + self.pinNames = pinNames + + def SetFirstPadType(self, firstPad): + self.firstPad = firstPad def SetFirstPadInArray(self, fpNum): - self.firstPad = fpNum + self.firstPadNum = fpNum def AddPad(self, pad): self.pad.GetParent().Add(pad) + def GetPad(self, is_first_pad, pos): + + if (self.firstPad and is_first_pad): + pad = self.firstPad + else: + pad = self.pad + + # create a new pad with same characteristics + pad = pad.Duplicate() + + pad.SetPos0(pos) + pad.SetPosition(pos) + + return pad + + def GetName(self, *args, **kwargs): + + if self.pinNames is None: + return self.NamingFunction(*args, **kwargs) + + return self.pinNames + + def NamingFunction(self, *args, **kwargs): + """ + Implement this as needed for each array type + """ + raise NotImplementedError; + + class PadGridArray(PadArray): - def __init__(self, pad, nx, ny, px, py, pin1Pos): + def __init__(self, pad, nx, ny, px, py, centre=pcbnew.wxPoint(0, 0)): + PadArray.__init__(self) # this pad is more of a "context", we will use it as a source of # pad data, but not actually add it self.pad = pad @@ -58,78 +139,121 @@ class PadGridArray(PadArray): self.ny = int(ny) self.px = px self.py = py - self.pin1Pos = pin1Pos + self.centre = centre # handy utility function 1 - A, 2 - B, 26 - AA, etc # aIndex = 0 for 0 - A - # alphabet = set of allowable chars if not A-Z, eg ABCDEFGHJKLMNPRTUVWY for BGA - def AlphaNameFromNumber(self, n, aIndex = 1, alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"): + # alphabet = set of allowable chars if not A-Z, + # eg ABCDEFGHJKLMNPRTUVWY for BGA + def AlphaNameFromNumber(self, n, aIndex=1, + alphabet="ABCDEFGHIJKLMNOPQRSTUVWXYZ"): div, mod = divmod(n - aIndex, len(alphabet)) alpha = alphabet[mod] if div > 0: - return self.AlphaNameFromNumber(div, aIndex, alphabet) + alpha; + return self.AlphaNameFromNumber(div, aIndex, alphabet) + alpha - return alpha; + return alpha # right to left, top to bottom def NamingFunction(self, x, y): - return self.firstPad + (self.nx * y + x) + return self.firstPadNum + (self.nx * y + x) #relocate the pad and add it as many times as we need - def AddPadsToModule(self): + def AddPadsToModule(self, dc): + + pin1posX = self.centre.x - self.px * (self.nx - 1) / 2 + pin1posY = self.centre.y - self.py * (self.ny - 1) / 2 for x in range(0, self.nx): + + posX = pin1posX + (x * self.px) + for y in range(self.ny): - posX = self.pin1Pos.x + (self.px * x) - posY = self.pin1Pos.y + (self.py * y) + posY = pin1posY + (self.py * y) - pos = pcbnew.wxPoint(posX, posY) + pos = dc.TransformPoint(posX, posY) - # create a new pad with same characteristics - pad = self.pad.Duplicate() + pad = self.GetPad(x == 0 and y == 0, pos) - pad.SetPos0(pos) - pad.SetPosition(pos) - - pad.SetPadName(str(self.NamingFunction(x,y))) + pad.SetPadName(self.GetName(x,y)) self.AddPad(pad) + class PadLineArray(PadGridArray): - def __init__(self, pad, n, pitch, isVertical, pin1Pos): + def __init__(self, pad, n, pitch, isVertical, + centre=pcbnew.wxPoint(0, 0)): if isVertical: - PadGridArray.__init__(self, pad, 1, n, 0, pitch, pin1Pos) + PadGridArray.__init__(self, pad, 1, n, 0, pitch, centre) else: - PadGridArray.__init__(self, pad, n, 1, pitch, 0, pin1Pos) + PadGridArray.__init__(self, pad, n, 1, pitch, 0, centre) -class RectPadArray(PadArray): +class PadCircleArray(PadArray): - def __init__(self, nx, ny, pitch, xpitch, ypitch, pin1Pos): + def __init__(self, pad, n, r, angle_offset=0, centre=pcbnew.wxPoint(0, 0), + clockwise=True): + PadArray.__init__(self) + # this pad is more of a "context", we will use it as a source of + # pad data, but not actually add it + self.pad = pad + self.n = int(n) + self.r = r + self.angle_offset = angle_offset + self.centre = centre + self.clockwise = clockwise - #left row - pin1Pos = pcbnew.wxPoint(-h_pitch / 2, -row_len / 2) - array = PadLineArray(h_pad, pads_per_row, pad_pitch, True, pin1Pos) - array.SetFirstPadInArray(1) - array.AddPadsToModule() + # around the circle, CW or CCW according to the flag + def NamingFunction(self, n): + return str(self.firstPadNum + n) - #bottom row - pin1Pos = pcbnew.wxPoint(-row_len / 2, v_pitch / 2) - array = PA.PadLineArray(v_pad, pads_per_row, pad_pitch, False, pin1Pos) - array.SetFirstPadInArray(pads_per_row + 1) - array.AddPadsToModule() + #relocate the pad and add it as many times as we need + def AddPadsToModule(self, dc): - #right row - pin1Pos = pcbnew.wxPoint(h_pitch / 2, row_len / 2) - array = PadLineArray(h_pad, pads_per_row, -pad_pitch, True, pin1Pos) - array.SetFirstPadInArray(2*pads_per_row + 1) - array.AddPadsToModule() + for pin in range(0, self.n): - #top row - pin1Pos = pcbnew.wxPoint(row_len / 2, -v_pitch / 2) - array = PadLineArray(v_pad, pads_per_row, -pad_pitch, False, pin1Pos) - array.SetFirstPadInArray(3*pads_per_row + 1) - array.AddPadsToModule() + angle = self.angle_offset + (360 / self.n) * pin + + if not self.clockwise: + angle = -angle + + pos_x = math.sin(angle * math.pi / 180) * self.r + pos_y = -math.cos(angle * math.pi / 180) * self.r + + pos = dc.TransformPoint(pos_x, pos_y) + + pad = self.GetPad(pin == 0, pos) + + pad.SetPadName(self.GetName(pin)) + + self.AddPad(pad) + +class PadCustomArray(PadArray): + """ + Layout pads according to a custom array of [x,y] data + """ + + def __init__(self, pad, array): + PadArray.__init__(self) + self.pad = pad + + self.array = array + + def NamingFunction(self, n): + return str(self.firstPadNum + n) + + #relocate the pad and add it as many times as we need + def AddPadsToModule(self, dc): + + for i in range(len(self.array)): + + pos = dc.TransformPoint(self.array[i][0], self.array[i][1]) + + pad = self.GetPad(i == 0, pos) + + pad.SetPadName(self.GetName(i)) + + self.AddPad(pad) diff --git a/pcbnew/scripting/plugins/__init__.py b/pcbnew/scripting/plugins/__init__.py new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/pcbnew/scripting/plugins/__init__.py @@ -0,0 +1 @@ + diff --git a/pcbnew/scripting/plugins/bga_wizard.py b/pcbnew/scripting/plugins/bga_wizard.py index 9b68b48ef6..2ca044a821 100644 --- a/pcbnew/scripting/plugins/bga_wizard.py +++ b/pcbnew/scripting/plugins/bga_wizard.py @@ -23,8 +23,10 @@ import PadArray as PA class BGAPadGridArray(PA.PadGridArray): - def NamingFunction(self, x, y): - return "%s%d" % (self.AlphaNameFromNumber(y + 1, alphabet="ABCDEFGHJKLMNPRTUVWY"), x + 1) + def NamingFunction(self, n_x, n_y): + return "%s%d" % ( + self.AlphaNameFromNumber(n_y + 1, alphabet="ABCDEFGHJKLMNPRTUVWY"), + n_x + 1) class BGAWizard(HFPW.HelpfulFootprintWizardPlugin): @@ -46,21 +48,19 @@ class BGAWizard(HFPW.HelpfulFootprintWizardPlugin): def CheckParameters(self): - self.CheckParamPositiveInt("Pads", "*row count") - self.CheckParamPositiveInt("Pads", "*column count") + self.CheckParamInt("Pads", "*row count") + self.CheckParamInt("Pads", "*column count") + def GetValue(self): - def GetReference(self): - - pins = self.parameters["Pads"]["*row count"] * self.parameters["Pads"]["*column count"] + pins = (self.parameters["Pads"]["*row count"] + * self.parameters["Pads"]["*column count"]) return "BGA %d" % pins - - def GetValuePrefix(self): + def GetReferencePrefix(self): return "U" - def BuildThisFootprint(self): pads = self.parameters["Pads"] @@ -76,23 +76,24 @@ class BGAWizard(HFPW.HelpfulFootprintWizardPlugin): # add in the pads pad = PA.PadMaker(self.module).SMTRoundPad(pads["pad size"]) - pin1Pos = pcbnew.wxPoint(-((cols - 1) * pad_pitch) / 2, - -((rows - 1) * pad_pitch) / 2) + pin1_pos = pcbnew.wxPoint(-((cols - 1) * pad_pitch) / 2, + -((rows - 1) * pad_pitch) / 2) - array = BGAPadGridArray(pad, cols, rows, pad_pitch, pad_pitch, pin1Pos) - array.AddPadsToModule() + array = BGAPadGridArray(pad, cols, rows, pad_pitch, pad_pitch) + array.AddPadsToModule(self.draw) #box - ssX = -pin1Pos.x + pads["outline x margin"] - ssY = -pin1Pos.y + pads["outline y margin"] + ssx = -pin1_pos.x + pads["outline x margin"] + ssy = -pin1_pos.y + pads["outline y margin"] - self.draw.BoxWithDiagonalAtCorner(0, 0, ssX*2, ssY*2, pads["outline x margin"]) + self.draw.BoxWithDiagonalAtCorner(0, 0, ssx*2, ssy*2, + pads["outline x margin"]) #reference and value - textSize = pcbnew.FromMM(0.8) + text_size = pcbnew.FromMM(1.2) # IPC nominal - self.draw.Value(0, - ssY - textSize, textSize) - self.draw.Reference(0, ssY + textSize, textSize) + self.draw.Value(0, - ssy - text_size, text_size) + self.draw.Reference(0, ssy + text_size, text_size) BGAWizard().register() diff --git a/pcbnew/scripting/plugins/pad_arrays.py b/pcbnew/scripting/plugins/pad_arrays.py new file mode 100644 index 0000000000..b498b3618b --- /dev/null +++ b/pcbnew/scripting/plugins/pad_arrays.py @@ -0,0 +1,77 @@ +# 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., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. +# +from __future__ import division + +import math + +import pcbnew +import HelpfulFootprintWizardPlugin as HFPW +import PadArray as PA + + +class circular_array_wizard(HFPW.HelpfulFootprintWizardPlugin): + + def GetName(self): + return "Circular Array" + + def GetDescription(self): + return "Circular array of pads" + + def GenerateParameterList(self): + + self.AddParam("Pads", "n", self.uNatural, 6) + self.AddParam("Pads", "pad width", self.uMM, 1.5) + self.AddParam("Pads", "drill", self.uMM, 1) + self.AddParam("Pads", "circle diameter", self.uMM, 5) + self.AddParam("Pads", "first pad angle", self.uNatural, 0) + self.AddParam("Pads", "number clockwise", self.uBool, True) + self.AddParam("Pads", "first pad number", self.uNatural, 1) + + def CheckParameters(self): + + self.CheckParamInt("Pads", "*n") + self.CheckParamInt("Pads", "*first pad number") + self.CheckParamBool("Pads", "*number clockwise") + + def GetValue(self): + return "A" + + def GetReference(self): + return "" + + def BuildThisFootprint(self): + + prm = self.parameters['Pads'] + + pad_size = prm['pad width'] + + pad = PA.PadMaker(self.module).THPad( + prm['pad width'], + prm['pad width'], + prm['drill']) + + array = PA.PadCircleArray( + pad, prm['*n'], prm['circle diameter'] / 2, + angle_offset=prm["*first pad angle"], + centre=pcbnew.wxPoint(0, 0), + clockwise=prm["*number clockwise"]) + + array.SetFirstPadInArray(prm["*first pad number"]) + + array.AddPadsToModule(self.draw) + + +circular_array_wizard().register() diff --git a/pcbnew/scripting/plugins/qfp_wizard.py b/pcbnew/scripting/plugins/qfp_wizard.py index 4964bcdfac..76fac3700a 100644 --- a/pcbnew/scripting/plugins/qfp_wizard.py +++ b/pcbnew/scripting/plugins/qfp_wizard.py @@ -1,9 +1,26 @@ +# 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., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. +# + from __future__ import division import pcbnew import HelpfulFootprintWizardPlugin import PadArray as PA + class QFPWizard(HelpfulFootprintWizardPlugin.HelpfulFootprintWizardPlugin): def GetName(self): @@ -26,10 +43,10 @@ class QFPWizard(HelpfulFootprintWizardPlugin.HelpfulFootprintWizardPlugin): def CheckParameters(self): - self.CheckParamPositiveInt("Pads", "*n", is_multiple_of = 4) + self.CheckParamInt("Pads", "*n", is_multiple_of=4) self.CheckParamBool("Pads", "*oval") - def GetReference(self): + def GetValue(self): return "QFP %d" % self.parameters["Pads"]["*n"] def BuildThisFootprint(self): @@ -49,44 +66,58 @@ class QFPWizard(HelpfulFootprintWizardPlugin.HelpfulFootprintWizardPlugin): pad_shape = pcbnew.PAD_OVAL if pads["*oval"] else pcbnew.PAD_RECT - h_pad = PA.PadMaker(self.module).SMDPad(pad_width, pad_length, shape = pad_shape) - v_pad = PA.PadMaker(self.module).SMDPad(pad_length, pad_width, shape = pad_shape) + h_pad = PA.PadMaker(self.module).SMDPad( + pad_width, pad_length, shape=pad_shape) + v_pad = PA.PadMaker(self.module).SMDPad( + pad_length, pad_width, shape=pad_shape) #left row - pin1Pos = pcbnew.wxPoint(-h_pitch / 2, -row_len / 2) - array = PA.PadLineArray(h_pad, pads_per_row, pad_pitch, True, pin1Pos) + pin1Pos = pcbnew.wxPoint(-h_pitch / 2, 0) + array = PA.PadLineArray(h_pad, pads_per_row, pad_pitch, True, + pin1Pos) array.SetFirstPadInArray(1) - array.AddPadsToModule() + array.AddPadsToModule(self.draw) #bottom row - pin1Pos = pcbnew.wxPoint(-row_len / 2, v_pitch / 2) - array = PA.PadLineArray(v_pad, pads_per_row, pad_pitch, False, pin1Pos) + pin1Pos = pcbnew.wxPoint(0, v_pitch / 2) + array = PA.PadLineArray(v_pad, pads_per_row, pad_pitch, False, + pin1Pos) array.SetFirstPadInArray(pads_per_row + 1) - array.AddPadsToModule() + array.AddPadsToModule(self.draw) #right row - pin1Pos = pcbnew.wxPoint(h_pitch / 2, row_len / 2) - array = PA.PadLineArray(h_pad, pads_per_row, -pad_pitch, True, pin1Pos) + pin1Pos = pcbnew.wxPoint(h_pitch / 2, 0) + array = PA.PadLineArray(h_pad, pads_per_row, -pad_pitch, True, + pin1Pos) array.SetFirstPadInArray(2*pads_per_row + 1) - array.AddPadsToModule() + array.AddPadsToModule(self.draw) #top row - pin1Pos = pcbnew.wxPoint(row_len / 2, -v_pitch / 2) - array = PA.PadLineArray(v_pad, pads_per_row, -pad_pitch, False, pin1Pos) + pin1Pos = pcbnew.wxPoint(0, -v_pitch / 2) + array = PA.PadLineArray(v_pad, pads_per_row, -pad_pitch, False, + pin1Pos) array.SetFirstPadInArray(3*pads_per_row + 1) - array.AddPadsToModule() + array.AddPadsToModule(self.draw) - limX = pads["package width"] / 2 - limY = pads["package height"] / 2 + lim_x = pads["package width"] / 2 + lim_y = pads["package height"] / 2 inner = (row_len / 2) + pad_pitch #top left - diagonal - self.draw.Line(-limX, -inner, -inner, -limY) + self.draw.Line(-lim_x, -inner, -inner, -lim_y) # top right - self.draw.Polyline([(inner, -limY), (limX, -limY), (limX, -inner)]) + self.draw.Polyline([(inner, -lim_y), (lim_x, -lim_y), (lim_x, -inner)]) # bottom left - self.draw.Polyline([(-inner, limY), (-limX, limY), (-limX, inner)]) + self.draw.Polyline([(-inner, lim_y), (-lim_x, lim_y), (-lim_x, inner)]) # bottom right - self.draw.Polyline([(inner, limY), (limX, limY), (limX, inner)]) + self.draw.Polyline([(inner, lim_y), (lim_x, lim_y), (lim_x, inner)]) + + #reference and value + text_size = pcbnew.FromMM(1.2) # IPC nominal + + text_offset = v_pitch / 2 + text_size + pad_length / 2 + + self.draw.Value(0, -text_offset, text_size) + self.draw.Reference(0, text_offset, text_size) QFPWizard().register() diff --git a/pcbnew/scripting/plugins/sdip_wizard.py b/pcbnew/scripting/plugins/sdip_wizard.py index c2a37653cb..876fa2f9ad 100644 --- a/pcbnew/scripting/plugins/sdip_wizard.py +++ b/pcbnew/scripting/plugins/sdip_wizard.py @@ -24,10 +24,11 @@ import PadArray as PA class RowedGridArray(PA.PadGridArray): def NamingFunction(self, x, y): - if (x % 2) == 0: # even row, count up - return (x * self.ny) + y + 1; - else: # odd row, count down - return (self.ny * (x + 1)) - y; + if (x % 2) == 0: # even row, count up + return (x * self.ny) + y + 1 + else: # odd row, count down + return (self.ny * (x + 1)) - y + class RowedFootprint(HFPW.HelpfulFootprintWizardPlugin): @@ -39,9 +40,13 @@ class RowedFootprint(HFPW.HelpfulFootprintWizardPlugin): self.AddParam("Pads", "row count", self.uNatural, 2) def CheckParameters(self): - self.CheckParamPositiveInt("Pads", "*row count") - self.CheckParamPositiveInt("Pads", "*n", is_multiple_of = self.parameters["Pads"]["*row count"]) - self.CheckParamBool("Pads", "*silk screen inside") #can do this internally to parameter manager? + self.CheckParamInt("Pads", "*row count") + self.CheckParamInt( + "Pads", "*n", + is_multiple_of=self.parameters["Pads"]["*row count"]) + + # can do this internally to parameter manager? + self.CheckParamBool("Pads", "*silk screen inside") def BuildThisFootprint(self): @@ -57,39 +62,40 @@ class RowedFootprint(HFPW.HelpfulFootprintWizardPlugin): pads_per_row = num_pads // num_rows - row_length = pad_pitch * (pads_per_row - 1) #fenceposts + row_length = pad_pitch * (pads_per_row - 1) # fenceposts # add in the pads pad = self.GetPad() - pin1Pos = pcbnew.wxPoint(-((num_rows - 1) * row_pitch) / 2, -row_length / 2) + pin1_pos = pcbnew.wxPoint( + -((num_rows - 1) * row_pitch) / 2, + -row_length / 2) - array = RowedGridArray(pad, num_rows, pads_per_row, row_pitch, pad_pitch, pin1Pos) - array.AddPadsToModule() + array = RowedGridArray(pad, num_rows, pads_per_row, row_pitch, + pad_pitch) + array.AddPadsToModule(self.draw) # draw the Silk Screen pad_length = pads["pad length"] pad_width = pads["pad width"] - ssXOffset = -pad_length / 2 - pads["outline x margin"] - ssYOffset = -pad_width / 2 - pads["outline y margin"] - + ssx_offset = -pad_length / 2 - pads["outline x margin"] + ssy_offset = -pad_width / 2 - pads["outline y margin"] if pads["*silk screen inside"]: - ssXOffset *= -1 + ssx_offset *= -1 - ssX = -pin1Pos.x - ssXOffset - ssY = -pin1Pos.y - ssYOffset + ssx = -pin1_pos.x - ssx_offset + ssy = -pin1_pos.y - ssy_offset - - self.DrawBox(ssX, ssY) + self.DrawBox(ssx, ssy) #reference and value - textSize = pcbnew.FromMM(0.8) + text_size = pcbnew.FromMM(1.2) # IPC nominal - self.draw.Value(0, - ssY - textSize, textSize) - self.draw.Reference(0, ssY + textSize, textSize) + self.draw.Value(0, - ssy - text_size, text_size) + self.draw.Reference(0, ssy + text_size, text_size) class SDIPWizard(RowedFootprint): @@ -111,15 +117,15 @@ class SDIPWizard(RowedFootprint): self.AddParam("Pads", "outline x margin", self.uMM, 0.5) self.AddParam("Pads", "outline y margin", self.uMM, 1) - def GetReference(self): + def GetValue(self): rows = self.parameters["Pads"]["*row count"] - if rows == 1: + if rows == 1: name = "SIP" elif rows == 2: name = "DIP" - else: # triple and up aren't really a thing, but call it something! + else: # triple and up aren't really a thing, but call it something! name = "xIP" return "%s %d" % (name, self.parameters["Pads"]["*n"]) @@ -128,9 +134,10 @@ class SDIPWizard(RowedFootprint): pad_length = self.parameters["Pads"]["pad length"] pad_width = self.parameters["Pads"]["pad width"] drill = self.parameters["Pads"]["drill size"] - return PA.PadMaker(self.module).THPad(pad_width, pad_length, drill, shape = pcbnew.PAD_OVAL) + return PA.PadMaker(self.module).THPad( + pad_width, pad_length, drill, shape=pcbnew.PAD_OVAL) - def DrawBox(self, ssX, ssY): + def DrawBox(self, ssx, ssy): if self.parameters["Pads"]["*row count"] == 2: @@ -144,18 +151,19 @@ class SDIPWizard(RowedFootprint): notchWidth = pcbnew.FromMM(3) notchHeight = pcbnew.FromMM(1) - self.draw.NotchedBox(0, 0, ssX*2, ssY*2, notchWidth, notchHeight) + self.draw.NotchedBox(0, 0, ssx*2, ssy*2, notchWidth, notchHeight) else: # ----------------- # |1|2 3 4 5 6 7 8| # ----------------- - self.draw.Box(ssX*2, ssY*2) + self.draw.Box(0, 0, ssx*2, ssy*2) #line between pin1 and pin2 - pad_pitch = self.parameters["Pads"]["pad pitch"]; - self.draw.HLine(-ssX, pin1Pos.y + pad_pitch/2, ssX * 2) + pad_pitch = self.parameters["Pads"]["pad pitch"] + line_y = - (self.parameters["Pads"]["*n"] - 2) * pad_pitch / 2 + self.draw.HLine(-ssx, line_y, ssx * 2) - return ssX, ssY + return ssx, ssy SDIPWizard().register() @@ -168,7 +176,7 @@ class SOICWizard(RowedFootprint): def GetDescription(self): return "SOIC, MSOP, SSOP, TSSOP, etc, footprint wizard" - def GetReference(self): + def GetValue(self): return "%s %d" % ("SOIC", self.parameters["Pads"]["*n"]) def GenerateParameterList(self): @@ -186,15 +194,16 @@ class SOICWizard(RowedFootprint): def GetPad(self): pad_length = self.parameters["Pads"]["pad length"] pad_width = self.parameters["Pads"]["pad width"] - return PA.PadMaker(self.module).SMDPad(pad_width, pad_length, shape = pcbnew.PAD_RECT) + return PA.PadMaker(self.module).SMDPad( + pad_width, pad_length, shape=pcbnew.PAD_RECT) - def DrawBox(self, ssX, ssY): + def DrawBox(self, ssx, ssy): # ---------- # |8 7 6 5 | # |1 2 3 4 | # \--------- - self.draw.BoxWithDiagonalAtCorner(0, 0, ssX*2, ssY*2, pcbnew.FromMM(1)) + self.draw.BoxWithDiagonalAtCorner(0, 0, ssx*2, ssy*2, pcbnew.FromMM(1)) SOICWizard().register()