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
This commit is contained in:
parent
1edd8c8ac8
commit
c1e0a8d067
|
@ -30,7 +30,7 @@ class FPCFootprintWizard(FootprintWizardPlugin):
|
||||||
pad.SetSize(size)
|
pad.SetSize(size)
|
||||||
pad.SetShape(PAD_RECT)
|
pad.SetShape(PAD_RECT)
|
||||||
pad.SetAttribute(PAD_SMD)
|
pad.SetAttribute(PAD_SMD)
|
||||||
pad.SetLayerSet( pad.StandardMask() )
|
pad.SetLayerSet( pad.SMDMask() )
|
||||||
pad.SetPos0(pos)
|
pad.SetPos0(pos)
|
||||||
pad.SetPosition(pos)
|
pad.SetPosition(pos)
|
||||||
pad.SetPadName(name)
|
pad.SetPadName(name)
|
||||||
|
|
|
@ -14,7 +14,11 @@
|
||||||
# MA 02110-1301, USA.
|
# MA 02110-1301, USA.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
from __future__ import division
|
||||||
|
|
||||||
import pcbnew
|
import pcbnew
|
||||||
|
import math
|
||||||
|
|
||||||
|
|
||||||
class FootprintWizardDrawingAids:
|
class FootprintWizardDrawingAids:
|
||||||
"""
|
"""
|
||||||
|
@ -24,31 +28,291 @@ class FootprintWizardDrawingAids:
|
||||||
A "drawing context" is provided which can be used to set and retain
|
A "drawing context" is provided which can be used to set and retain
|
||||||
settings such as line width and layer
|
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):
|
def __init__(self, module):
|
||||||
self.module = module
|
self.module = module
|
||||||
#drawing context defaults
|
# drawing context defaults
|
||||||
self.dc = {
|
self.dc = {
|
||||||
'layer': pcbnew.SILKSCREEN_N_FRONT,
|
'layer': pcbnew.F_SilkS,
|
||||||
'width': pcbnew.FromMM(0.2)
|
'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):
|
def SetWidth(self, width):
|
||||||
|
"""
|
||||||
|
Set the current pen width used for subsequent drawing
|
||||||
|
operations
|
||||||
|
"""
|
||||||
self.dc['width'] = width
|
self.dc['width'] = width
|
||||||
|
|
||||||
|
def GetWidth(self):
|
||||||
|
"""
|
||||||
|
Get the current drawing context width
|
||||||
|
"""
|
||||||
|
return self.dc['width']
|
||||||
|
|
||||||
def SetLayer(self, layer):
|
def SetLayer(self, layer):
|
||||||
|
"""
|
||||||
|
Set the current drawing layer, used for subsequent drawing
|
||||||
|
operations
|
||||||
|
"""
|
||||||
self.dc['layer'] = layer
|
self.dc['layer'] = layer
|
||||||
|
|
||||||
def Line(self, x1, y1, x2, y2):
|
def Line(self, x1, y1, x2, y2):
|
||||||
|
"""
|
||||||
|
Draw a line from (x1, y1) to (x2, y2)
|
||||||
|
"""
|
||||||
|
|
||||||
outline = pcbnew.EDGE_MODULE(self.module)
|
outline = pcbnew.EDGE_MODULE(self.module)
|
||||||
outline.SetWidth(self.dc['width'])
|
outline.SetWidth(self.dc['width'])
|
||||||
outline.SetLayer(self.dc['layer'])
|
outline.SetLayer(self.dc['layer'])
|
||||||
outline.SetShape(pcbnew.S_SEGMENT)
|
outline.SetShape(pcbnew.S_SEGMENT)
|
||||||
start = pcbnew.wxPoint(x1, y1)
|
start = self.TransformPoint(x1, y1)
|
||||||
end = pcbnew.wxPoint(x2, y2)
|
end = self.TransformPoint(x2, y2)
|
||||||
outline.SetStartEnd(start, end)
|
outline.SetStartEnd(start, end)
|
||||||
self.module.Add(outline)
|
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
|
# extends from (x1,y1) right
|
||||||
def HLine(self, x, y, l):
|
def HLine(self, x, y, l):
|
||||||
"""
|
"""
|
||||||
|
@ -62,14 +326,35 @@ class FootprintWizardDrawingAids:
|
||||||
"""
|
"""
|
||||||
self.Line(x, y, x, y + l)
|
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
|
||||||
|
"""
|
||||||
|
|
||||||
|
def _PolyLineInternal(pts):
|
||||||
if len(pts) < 2:
|
if len(pts) < 2:
|
||||||
return
|
return
|
||||||
|
|
||||||
for i in range(0, len(pts) - 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])
|
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):
|
def Reference(self, x, y, size):
|
||||||
"""
|
"""
|
||||||
Draw the module's reference as the given point.
|
Draw the module's reference as the given point.
|
||||||
|
@ -80,8 +365,9 @@ class FootprintWizardDrawingAids:
|
||||||
|
|
||||||
text_size = pcbnew.wxSize(size, size)
|
text_size = pcbnew.wxSize(size, size)
|
||||||
|
|
||||||
self.module.Reference().SetPos0(pcbnew.wxPoint(x, y))
|
self.module.Reference().SetPos0(self.TransformPoint(x, y))
|
||||||
self.module.Reference().SetTextPosition(self.module.Reference().GetPos0())
|
self.module.Reference().SetTextPosition(
|
||||||
|
self.module.Reference().GetPos0())
|
||||||
self.module.Reference().SetSize(text_size)
|
self.module.Reference().SetSize(text_size)
|
||||||
|
|
||||||
def Value(self, x, y, size):
|
def Value(self, x, y, size):
|
||||||
|
@ -90,7 +376,7 @@ class FootprintWizardDrawingAids:
|
||||||
"""
|
"""
|
||||||
text_size = pcbnew.wxSize(size, size)
|
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().SetTextPosition(self.module.Value().GetPos0())
|
||||||
self.module.Value().SetSize(text_size)
|
self.module.Value().SetSize(text_size)
|
||||||
|
|
||||||
|
@ -99,25 +385,55 @@ class FootprintWizardDrawingAids:
|
||||||
Draw a rectangular box, centred at (x,y), with given width and
|
Draw a rectangular box, centred at (x,y), with given width and
|
||||||
height
|
height
|
||||||
"""
|
"""
|
||||||
self.VLine(x - w/2, y - h/2, h) # left
|
|
||||||
self.VLine(x + w/2, y - h/2, h) # right
|
pts = [[x - w/2, y - h/2], # left
|
||||||
self.HLine(x - w/2, y + h/2, w) # bottom
|
[x + w/2, y - h/2], # right
|
||||||
self.HLine(x - w/2, y - h/2, w) # top
|
[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):
|
def NotchedBox(self, x, y, w, h, notchW, notchH):
|
||||||
"""
|
"""
|
||||||
Draw a box with a notch in the top edge
|
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)
|
notchW = min(x + w/2, notchW)
|
||||||
|
|
||||||
# draw notch
|
# draw notch
|
||||||
self.Polyline([ #three sides of box
|
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),
|
||||||
(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
|
# the notch
|
||||||
(notchW/2, y - h/2),
|
(notchW/2, y - h/2),
|
||||||
(notchW/2, y - h/2 + notchH),
|
(notchW/2, y - h/2 + notchH),
|
||||||
(-notchW/2, y - h/2 + notchH),
|
(-notchW/2, y - h/2 + notchH),
|
||||||
|
@ -125,10 +441,59 @@ class FootprintWizardDrawingAids:
|
||||||
(x - w/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
|
pts = [[x - w/2 + setback, y - h/2],
|
||||||
self.Line(x - w/2 + diagSetback, x - h/2, x - w/2,
|
[x - w/2, y - h/2 + setback],
|
||||||
x - h/2 + diagSetback)
|
[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)
|
||||||
|
|
|
@ -15,8 +15,10 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
import pcbnew
|
import pcbnew
|
||||||
|
import math
|
||||||
import FootprintWizardDrawingAids
|
import FootprintWizardDrawingAids
|
||||||
|
|
||||||
|
|
||||||
class FootprintWizardParameterManager:
|
class FootprintWizardParameterManager:
|
||||||
"""
|
"""
|
||||||
Functions for helpfully managing parameters to a KiCAD Footprint
|
Functions for helpfully managing parameters to a KiCAD Footprint
|
||||||
|
@ -50,8 +52,9 @@ class FootprintWizardParameterManager:
|
||||||
uMils = 2
|
uMils = 2
|
||||||
uNatural = 3
|
uNatural = 3
|
||||||
uBool = 4
|
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.
|
Add a parameter with some properties.
|
||||||
|
|
||||||
|
@ -66,14 +69,16 @@ class FootprintWizardParameterManager:
|
||||||
val = pcbnew.FromMils(default)
|
val = pcbnew.FromMils(default)
|
||||||
elif unit == self.uNatural:
|
elif unit == self.uNatural:
|
||||||
val = default
|
val = default
|
||||||
|
elif unit == self.uString:
|
||||||
|
val = str(default)
|
||||||
elif unit == self.uBool:
|
elif unit == self.uBool:
|
||||||
val = "True" if default else "False" #ugly stringing
|
val = "True" if default else "False" # ugly stringing
|
||||||
else:
|
else:
|
||||||
print "Warning: Unknown unit type: %s" % unit
|
print "Warning: Unknown unit type: %s" % unit
|
||||||
return
|
return
|
||||||
|
|
||||||
if unit in [self.uNatural, self.uBool]:
|
if unit in [self.uNatural, self.uBool, self.uString]:
|
||||||
param = "*%s" % param #star prefix for natural
|
param = "*%s" % param # star prefix for natural
|
||||||
|
|
||||||
if section not in self.parameters:
|
if section not in self.parameters:
|
||||||
self.parameters[section] = {}
|
self.parameters[section] = {}
|
||||||
|
@ -89,7 +94,8 @@ class FootprintWizardParameterManager:
|
||||||
|
|
||||||
for key, value in section.iteritems():
|
for key, value in section.iteritems():
|
||||||
unit = ""
|
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"
|
unit = "mm"
|
||||||
|
|
||||||
if "*" in key:
|
if "*" in key:
|
||||||
|
@ -101,7 +107,7 @@ class FootprintWizardParameterManager:
|
||||||
|
|
||||||
def _ParametersHaveErrors(self):
|
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():
|
for name, section in self.parameter_errors.iteritems():
|
||||||
|
@ -124,8 +130,8 @@ class FootprintWizardParameterManager:
|
||||||
if not printed_section:
|
if not printed_section:
|
||||||
print " %s:" % name
|
print " %s:" % name
|
||||||
|
|
||||||
print " %s: %s (have %s)" % (key, value,
|
print " %s: %s (have %s)" % (
|
||||||
self.parameters[name][key])
|
key, value, self.parameters[name][key])
|
||||||
|
|
||||||
def ProcessParameters(self):
|
def ProcessParameters(self):
|
||||||
"""
|
"""
|
||||||
|
@ -134,14 +140,15 @@ class FootprintWizardParameterManager:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.ClearErrors()
|
self.ClearErrors()
|
||||||
self.CheckParameters();
|
self.CheckParameters()
|
||||||
|
|
||||||
if self._ParametersHaveErrors():
|
if self._ParametersHaveErrors():
|
||||||
print "Cannot build footprint: Parameters have errors:"
|
print "Cannot build footprint: Parameters have errors:"
|
||||||
self._PrintParameterErrors()
|
self._PrintParameterErrors()
|
||||||
return False
|
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()
|
self._PrintParameterTable()
|
||||||
return True
|
return True
|
||||||
|
@ -150,29 +157,37 @@ class FootprintWizardParameterManager:
|
||||||
# PARAMETER CHECKERS
|
# PARAMETER CHECKERS
|
||||||
#################################################################
|
#################################################################
|
||||||
|
|
||||||
def CheckParamPositiveInt(self, section, param, min_value = 1,
|
def CheckParamInt(self, section, param, min_value=1,
|
||||||
max_value = None, is_multiple_of = 1):
|
max_value=None, is_multiple_of=1):
|
||||||
"""
|
"""
|
||||||
Make sure a parameter can be made into an int, and enforce
|
Make sure a parameter can be made into an int, and enforce
|
||||||
limits if required
|
limits if required
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.parameters[section][param] = int(self.parameters[section][param])
|
self.parameters[section][param] = (
|
||||||
|
int(self.parameters[section][param]))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
self.parameter_errors[section][param] = "Must be a valid integer"
|
self.parameter_errors[section][param] = (
|
||||||
|
"Must be a valid integer")
|
||||||
return
|
return
|
||||||
|
|
||||||
if min_value is not None and (self.parameters[section][param] < min_value):
|
if min_value is not None and (
|
||||||
self.parameter_errors[section][param] = "Must be greater than or equal to %d" % (min_value)
|
self.parameters[section][param] < min_value):
|
||||||
|
self.parameter_errors[section][param] = (
|
||||||
|
"Must be greater than or equal to %d" % (min_value))
|
||||||
return
|
return
|
||||||
|
|
||||||
if max_value is not None and (self.parameters[section][param] > min_value):
|
if max_value is not None and (
|
||||||
self.parameter_errors[section][param] = "Must be less than or equal to %d" % (max_value)
|
self.parameters[section][param] > min_value):
|
||||||
|
self.parameter_errors[section][param] = (
|
||||||
|
"Must be less than or equal to %d" % (max_value))
|
||||||
return
|
return
|
||||||
|
|
||||||
if is_multiple_of > 1 and (self.parameters[section][param] % is_multiple_of) > 0:
|
if is_multiple_of > 1 and (
|
||||||
self.parameter_errors[section][param] = "Must be a multiple of %d" % is_multiple_of
|
self.parameters[section][param] % is_multiple_of) > 0:
|
||||||
|
self.parameter_errors[section][param] = (
|
||||||
|
"Must be a multiple of %d" % is_multiple_of)
|
||||||
return
|
return
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -182,11 +197,13 @@ class FootprintWizardParameterManager:
|
||||||
Make sure a parameter looks like a boolean, convert to native
|
Make sure a parameter looks like a boolean, convert to native
|
||||||
boolean type if so
|
boolean type if so
|
||||||
"""
|
"""
|
||||||
if str(self.parameters[section][param]).lower() in ["true", "t", "y", "yes", "on", "1", "1.0"]:
|
if str(self.parameters[section][param]).lower() in [
|
||||||
self.parameters[section][param] = True;
|
"true", "t", "y", "yes", "on", "1", "1.0"]:
|
||||||
|
self.parameters[section][param] = True
|
||||||
return
|
return
|
||||||
elif str(self.parameters[section][param]).lower() in ["false", "f", "n", "no", "off", "0", "0.0"]:
|
elif str(self.parameters[section][param]).lower() in [
|
||||||
self.parameters[section][param] = False;
|
"false", "f", "n", "no", "off", "0", "0.0"]:
|
||||||
|
self.parameters[section][param] = False
|
||||||
return
|
return
|
||||||
|
|
||||||
self.parameter_errors[section][param] = "Must be boolean (true/false)"
|
self.parameter_errors[section][param] = "Must be boolean (true/false)"
|
||||||
|
@ -216,16 +233,46 @@ class HelpfulFootprintWizardPlugin(pcbnew.FootprintWizardPlugin,
|
||||||
self.decription = self.GetDescription()
|
self.decription = self.GetDescription()
|
||||||
self.image = self.GetImage()
|
self.image = self.GetImage()
|
||||||
|
|
||||||
def GetReference(self):
|
def GetValue(self):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def GetValuePrefix(self):
|
def GetReferencePrefix(self):
|
||||||
return "U" # footprints needing wizards of often ICs
|
return "U" # footprints needing wizards of often ICs
|
||||||
|
|
||||||
def GetImage(self):
|
def GetImage(self):
|
||||||
return ""
|
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):
|
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
|
raise NotImplementedError
|
||||||
|
|
||||||
def BuildFootprint(self):
|
def BuildFootprint(self):
|
||||||
|
@ -234,17 +281,26 @@ class HelpfulFootprintWizardPlugin(pcbnew.FootprintWizardPlugin,
|
||||||
the implmenting class
|
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():
|
if not self.ProcessParameters():
|
||||||
return
|
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())
|
fpid = pcbnew.FPID(self.module.GetValue()) # the name in library
|
||||||
self.module.SetValue("%s**" % self.GetValuePrefix())
|
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)
|
||||||
|
|
|
@ -1,4 +1,27 @@
|
||||||
|
# PadArray.py
|
||||||
|
#
|
||||||
|
# Copyright 2014 john <john@johndev>
|
||||||
|
#
|
||||||
|
# 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 pcbnew
|
||||||
|
|
||||||
class PadMaker:
|
class PadMaker:
|
||||||
|
@ -9,7 +32,7 @@ class PadMaker:
|
||||||
def __init__(self, module):
|
def __init__(self, module):
|
||||||
self.module = 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 = pcbnew.D_PAD(self.module)
|
||||||
|
|
||||||
pad.SetSize(pcbnew.wxSize(l, w))
|
pad.SetSize(pcbnew.wxSize(l, w))
|
||||||
|
@ -22,7 +45,23 @@ class PadMaker:
|
||||||
|
|
||||||
return pad
|
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 = pcbnew.D_PAD(self.module)
|
||||||
pad.SetSize(pcbnew.wxSize(l, w))
|
pad.SetSize(pcbnew.wxSize(l, w))
|
||||||
|
|
||||||
|
@ -34,23 +73,65 @@ class PadMaker:
|
||||||
return pad
|
return pad
|
||||||
|
|
||||||
def SMTRoundPad(self, size):
|
def SMTRoundPad(self, size):
|
||||||
pad = self.SMDPad(size, size, shape = pcbnew.PAD_CIRCLE)
|
pad = self.SMDPad(size, size, shape=pcbnew.PAD_CIRCLE)
|
||||||
return pad
|
return pad
|
||||||
|
|
||||||
|
|
||||||
class PadArray:
|
class PadArray:
|
||||||
|
|
||||||
def __init__(self):
|
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):
|
def SetFirstPadInArray(self, fpNum):
|
||||||
self.firstPad = fpNum
|
self.firstPadNum = fpNum
|
||||||
|
|
||||||
def AddPad(self, pad):
|
def AddPad(self, pad):
|
||||||
self.pad.GetParent().Add(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):
|
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
|
# this pad is more of a "context", we will use it as a source of
|
||||||
# pad data, but not actually add it
|
# pad data, but not actually add it
|
||||||
self.pad = pad
|
self.pad = pad
|
||||||
|
@ -58,78 +139,121 @@ class PadGridArray(PadArray):
|
||||||
self.ny = int(ny)
|
self.ny = int(ny)
|
||||||
self.px = px
|
self.px = px
|
||||||
self.py = py
|
self.py = py
|
||||||
self.pin1Pos = pin1Pos
|
self.centre = centre
|
||||||
|
|
||||||
# handy utility function 1 - A, 2 - B, 26 - AA, etc
|
# handy utility function 1 - A, 2 - B, 26 - AA, etc
|
||||||
# aIndex = 0 for 0 - A
|
# aIndex = 0 for 0 - A
|
||||||
# alphabet = set of allowable chars if not A-Z, eg ABCDEFGHJKLMNPRTUVWY for BGA
|
# alphabet = set of allowable chars if not A-Z,
|
||||||
def AlphaNameFromNumber(self, n, aIndex = 1, alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"):
|
# eg ABCDEFGHJKLMNPRTUVWY for BGA
|
||||||
|
def AlphaNameFromNumber(self, n, aIndex=1,
|
||||||
|
alphabet="ABCDEFGHIJKLMNOPQRSTUVWXYZ"):
|
||||||
|
|
||||||
div, mod = divmod(n - aIndex, len(alphabet))
|
div, mod = divmod(n - aIndex, len(alphabet))
|
||||||
alpha = alphabet[mod]
|
alpha = alphabet[mod]
|
||||||
|
|
||||||
if div > 0:
|
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
|
# right to left, top to bottom
|
||||||
def NamingFunction(self, x, y):
|
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
|
#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):
|
for x in range(0, self.nx):
|
||||||
|
|
||||||
|
posX = pin1posX + (x * self.px)
|
||||||
|
|
||||||
for y in range(self.ny):
|
for y in range(self.ny):
|
||||||
posX = self.pin1Pos.x + (self.px * x)
|
posY = pin1posY + (self.py * y)
|
||||||
posY = self.pin1Pos.y + (self.py * y)
|
|
||||||
|
|
||||||
pos = pcbnew.wxPoint(posX, posY)
|
pos = dc.TransformPoint(posX, posY)
|
||||||
|
|
||||||
# create a new pad with same characteristics
|
pad = self.GetPad(x == 0 and y == 0, pos)
|
||||||
pad = self.pad.Duplicate()
|
|
||||||
|
|
||||||
pad.SetPos0(pos)
|
pad.SetPadName(self.GetName(x,y))
|
||||||
pad.SetPosition(pos)
|
|
||||||
|
|
||||||
pad.SetPadName(str(self.NamingFunction(x,y)))
|
|
||||||
|
|
||||||
self.AddPad(pad)
|
self.AddPad(pad)
|
||||||
|
|
||||||
|
|
||||||
class PadLineArray(PadGridArray):
|
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:
|
if isVertical:
|
||||||
PadGridArray.__init__(self, pad, 1, n, 0, pitch, pin1Pos)
|
PadGridArray.__init__(self, pad, 1, n, 0, pitch, centre)
|
||||||
else:
|
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
|
# around the circle, CW or CCW according to the flag
|
||||||
pin1Pos = pcbnew.wxPoint(-h_pitch / 2, -row_len / 2)
|
def NamingFunction(self, n):
|
||||||
array = PadLineArray(h_pad, pads_per_row, pad_pitch, True, pin1Pos)
|
return str(self.firstPadNum + n)
|
||||||
array.SetFirstPadInArray(1)
|
|
||||||
array.AddPadsToModule()
|
|
||||||
|
|
||||||
#bottom row
|
#relocate the pad and add it as many times as we need
|
||||||
pin1Pos = pcbnew.wxPoint(-row_len / 2, v_pitch / 2)
|
def AddPadsToModule(self, dc):
|
||||||
array = PA.PadLineArray(v_pad, pads_per_row, pad_pitch, False, pin1Pos)
|
|
||||||
array.SetFirstPadInArray(pads_per_row + 1)
|
|
||||||
array.AddPadsToModule()
|
|
||||||
|
|
||||||
#right row
|
for pin in range(0, self.n):
|
||||||
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()
|
|
||||||
|
|
||||||
#top row
|
angle = self.angle_offset + (360 / self.n) * pin
|
||||||
pin1Pos = pcbnew.wxPoint(row_len / 2, -v_pitch / 2)
|
|
||||||
array = PadLineArray(v_pad, pads_per_row, -pad_pitch, False, pin1Pos)
|
if not self.clockwise:
|
||||||
array.SetFirstPadInArray(3*pads_per_row + 1)
|
angle = -angle
|
||||||
array.AddPadsToModule()
|
|
||||||
|
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)
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -23,8 +23,10 @@ import PadArray as PA
|
||||||
|
|
||||||
class BGAPadGridArray(PA.PadGridArray):
|
class BGAPadGridArray(PA.PadGridArray):
|
||||||
|
|
||||||
def NamingFunction(self, x, y):
|
def NamingFunction(self, n_x, n_y):
|
||||||
return "%s%d" % (self.AlphaNameFromNumber(y + 1, alphabet="ABCDEFGHJKLMNPRTUVWY"), x + 1)
|
return "%s%d" % (
|
||||||
|
self.AlphaNameFromNumber(n_y + 1, alphabet="ABCDEFGHJKLMNPRTUVWY"),
|
||||||
|
n_x + 1)
|
||||||
|
|
||||||
|
|
||||||
class BGAWizard(HFPW.HelpfulFootprintWizardPlugin):
|
class BGAWizard(HFPW.HelpfulFootprintWizardPlugin):
|
||||||
|
@ -46,21 +48,19 @@ class BGAWizard(HFPW.HelpfulFootprintWizardPlugin):
|
||||||
|
|
||||||
def CheckParameters(self):
|
def CheckParameters(self):
|
||||||
|
|
||||||
self.CheckParamPositiveInt("Pads", "*row count")
|
self.CheckParamInt("Pads", "*row count")
|
||||||
self.CheckParamPositiveInt("Pads", "*column 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
|
return "BGA %d" % pins
|
||||||
|
|
||||||
|
def GetReferencePrefix(self):
|
||||||
def GetValuePrefix(self):
|
|
||||||
return "U"
|
return "U"
|
||||||
|
|
||||||
|
|
||||||
def BuildThisFootprint(self):
|
def BuildThisFootprint(self):
|
||||||
|
|
||||||
pads = self.parameters["Pads"]
|
pads = self.parameters["Pads"]
|
||||||
|
@ -76,23 +76,24 @@ class BGAWizard(HFPW.HelpfulFootprintWizardPlugin):
|
||||||
# add in the pads
|
# add in the pads
|
||||||
pad = PA.PadMaker(self.module).SMTRoundPad(pads["pad size"])
|
pad = PA.PadMaker(self.module).SMTRoundPad(pads["pad size"])
|
||||||
|
|
||||||
pin1Pos = pcbnew.wxPoint(-((cols - 1) * pad_pitch) / 2,
|
pin1_pos = pcbnew.wxPoint(-((cols - 1) * pad_pitch) / 2,
|
||||||
-((rows - 1) * pad_pitch) / 2)
|
-((rows - 1) * pad_pitch) / 2)
|
||||||
|
|
||||||
array = BGAPadGridArray(pad, cols, rows, pad_pitch, pad_pitch, pin1Pos)
|
array = BGAPadGridArray(pad, cols, rows, pad_pitch, pad_pitch)
|
||||||
array.AddPadsToModule()
|
array.AddPadsToModule(self.draw)
|
||||||
|
|
||||||
#box
|
#box
|
||||||
ssX = -pin1Pos.x + pads["outline x margin"]
|
ssx = -pin1_pos.x + pads["outline x margin"]
|
||||||
ssY = -pin1Pos.y + pads["outline y 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
|
#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.Value(0, - ssy - text_size, text_size)
|
||||||
self.draw.Reference(0, ssY + textSize, textSize)
|
self.draw.Reference(0, ssy + text_size, text_size)
|
||||||
|
|
||||||
|
|
||||||
BGAWizard().register()
|
BGAWizard().register()
|
||||||
|
|
|
@ -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()
|
|
@ -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
|
from __future__ import division
|
||||||
import pcbnew
|
import pcbnew
|
||||||
|
|
||||||
import HelpfulFootprintWizardPlugin
|
import HelpfulFootprintWizardPlugin
|
||||||
import PadArray as PA
|
import PadArray as PA
|
||||||
|
|
||||||
|
|
||||||
class QFPWizard(HelpfulFootprintWizardPlugin.HelpfulFootprintWizardPlugin):
|
class QFPWizard(HelpfulFootprintWizardPlugin.HelpfulFootprintWizardPlugin):
|
||||||
|
|
||||||
def GetName(self):
|
def GetName(self):
|
||||||
|
@ -26,10 +43,10 @@ class QFPWizard(HelpfulFootprintWizardPlugin.HelpfulFootprintWizardPlugin):
|
||||||
|
|
||||||
def CheckParameters(self):
|
def CheckParameters(self):
|
||||||
|
|
||||||
self.CheckParamPositiveInt("Pads", "*n", is_multiple_of = 4)
|
self.CheckParamInt("Pads", "*n", is_multiple_of=4)
|
||||||
self.CheckParamBool("Pads", "*oval")
|
self.CheckParamBool("Pads", "*oval")
|
||||||
|
|
||||||
def GetReference(self):
|
def GetValue(self):
|
||||||
return "QFP %d" % self.parameters["Pads"]["*n"]
|
return "QFP %d" % self.parameters["Pads"]["*n"]
|
||||||
|
|
||||||
def BuildThisFootprint(self):
|
def BuildThisFootprint(self):
|
||||||
|
@ -49,44 +66,58 @@ class QFPWizard(HelpfulFootprintWizardPlugin.HelpfulFootprintWizardPlugin):
|
||||||
|
|
||||||
pad_shape = pcbnew.PAD_OVAL if pads["*oval"] else pcbnew.PAD_RECT
|
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)
|
h_pad = PA.PadMaker(self.module).SMDPad(
|
||||||
v_pad = PA.PadMaker(self.module).SMDPad(pad_length, pad_width, shape = pad_shape)
|
pad_width, pad_length, shape=pad_shape)
|
||||||
|
v_pad = PA.PadMaker(self.module).SMDPad(
|
||||||
|
pad_length, pad_width, shape=pad_shape)
|
||||||
|
|
||||||
#left row
|
#left row
|
||||||
pin1Pos = pcbnew.wxPoint(-h_pitch / 2, -row_len / 2)
|
pin1Pos = pcbnew.wxPoint(-h_pitch / 2, 0)
|
||||||
array = PA.PadLineArray(h_pad, pads_per_row, pad_pitch, True, pin1Pos)
|
array = PA.PadLineArray(h_pad, pads_per_row, pad_pitch, True,
|
||||||
|
pin1Pos)
|
||||||
array.SetFirstPadInArray(1)
|
array.SetFirstPadInArray(1)
|
||||||
array.AddPadsToModule()
|
array.AddPadsToModule(self.draw)
|
||||||
|
|
||||||
#bottom row
|
#bottom row
|
||||||
pin1Pos = pcbnew.wxPoint(-row_len / 2, v_pitch / 2)
|
pin1Pos = pcbnew.wxPoint(0, v_pitch / 2)
|
||||||
array = PA.PadLineArray(v_pad, pads_per_row, pad_pitch, False, pin1Pos)
|
array = PA.PadLineArray(v_pad, pads_per_row, pad_pitch, False,
|
||||||
|
pin1Pos)
|
||||||
array.SetFirstPadInArray(pads_per_row + 1)
|
array.SetFirstPadInArray(pads_per_row + 1)
|
||||||
array.AddPadsToModule()
|
array.AddPadsToModule(self.draw)
|
||||||
|
|
||||||
#right row
|
#right row
|
||||||
pin1Pos = pcbnew.wxPoint(h_pitch / 2, row_len / 2)
|
pin1Pos = pcbnew.wxPoint(h_pitch / 2, 0)
|
||||||
array = PA.PadLineArray(h_pad, pads_per_row, -pad_pitch, True, pin1Pos)
|
array = PA.PadLineArray(h_pad, pads_per_row, -pad_pitch, True,
|
||||||
|
pin1Pos)
|
||||||
array.SetFirstPadInArray(2*pads_per_row + 1)
|
array.SetFirstPadInArray(2*pads_per_row + 1)
|
||||||
array.AddPadsToModule()
|
array.AddPadsToModule(self.draw)
|
||||||
|
|
||||||
#top row
|
#top row
|
||||||
pin1Pos = pcbnew.wxPoint(row_len / 2, -v_pitch / 2)
|
pin1Pos = pcbnew.wxPoint(0, -v_pitch / 2)
|
||||||
array = PA.PadLineArray(v_pad, pads_per_row, -pad_pitch, False, pin1Pos)
|
array = PA.PadLineArray(v_pad, pads_per_row, -pad_pitch, False,
|
||||||
|
pin1Pos)
|
||||||
array.SetFirstPadInArray(3*pads_per_row + 1)
|
array.SetFirstPadInArray(3*pads_per_row + 1)
|
||||||
array.AddPadsToModule()
|
array.AddPadsToModule(self.draw)
|
||||||
|
|
||||||
limX = pads["package width"] / 2
|
lim_x = pads["package width"] / 2
|
||||||
limY = pads["package height"] / 2
|
lim_y = pads["package height"] / 2
|
||||||
inner = (row_len / 2) + pad_pitch
|
inner = (row_len / 2) + pad_pitch
|
||||||
|
|
||||||
#top left - diagonal
|
#top left - diagonal
|
||||||
self.draw.Line(-limX, -inner, -inner, -limY)
|
self.draw.Line(-lim_x, -inner, -inner, -lim_y)
|
||||||
# top right
|
# 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
|
# 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
|
# 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()
|
QFPWizard().register()
|
||||||
|
|
|
@ -25,9 +25,10 @@ class RowedGridArray(PA.PadGridArray):
|
||||||
|
|
||||||
def NamingFunction(self, x, y):
|
def NamingFunction(self, x, y):
|
||||||
if (x % 2) == 0: # even row, count up
|
if (x % 2) == 0: # even row, count up
|
||||||
return (x * self.ny) + y + 1;
|
return (x * self.ny) + y + 1
|
||||||
else: # odd row, count down
|
else: # odd row, count down
|
||||||
return (self.ny * (x + 1)) - y;
|
return (self.ny * (x + 1)) - y
|
||||||
|
|
||||||
|
|
||||||
class RowedFootprint(HFPW.HelpfulFootprintWizardPlugin):
|
class RowedFootprint(HFPW.HelpfulFootprintWizardPlugin):
|
||||||
|
|
||||||
|
@ -39,9 +40,13 @@ class RowedFootprint(HFPW.HelpfulFootprintWizardPlugin):
|
||||||
self.AddParam("Pads", "row count", self.uNatural, 2)
|
self.AddParam("Pads", "row count", self.uNatural, 2)
|
||||||
|
|
||||||
def CheckParameters(self):
|
def CheckParameters(self):
|
||||||
self.CheckParamPositiveInt("Pads", "*row count")
|
self.CheckParamInt("Pads", "*row count")
|
||||||
self.CheckParamPositiveInt("Pads", "*n", is_multiple_of = self.parameters["Pads"]["*row count"])
|
self.CheckParamInt(
|
||||||
self.CheckParamBool("Pads", "*silk screen inside") #can do this internally to parameter manager?
|
"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):
|
def BuildThisFootprint(self):
|
||||||
|
|
||||||
|
@ -57,39 +62,40 @@ class RowedFootprint(HFPW.HelpfulFootprintWizardPlugin):
|
||||||
|
|
||||||
pads_per_row = num_pads // num_rows
|
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
|
# add in the pads
|
||||||
pad = self.GetPad()
|
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 = RowedGridArray(pad, num_rows, pads_per_row, row_pitch,
|
||||||
array.AddPadsToModule()
|
pad_pitch)
|
||||||
|
array.AddPadsToModule(self.draw)
|
||||||
|
|
||||||
# draw the Silk Screen
|
# draw the Silk Screen
|
||||||
|
|
||||||
pad_length = pads["pad length"]
|
pad_length = pads["pad length"]
|
||||||
pad_width = pads["pad width"]
|
pad_width = pads["pad width"]
|
||||||
|
|
||||||
ssXOffset = -pad_length / 2 - pads["outline x margin"]
|
ssx_offset = -pad_length / 2 - pads["outline x margin"]
|
||||||
ssYOffset = -pad_width / 2 - pads["outline y margin"]
|
ssy_offset = -pad_width / 2 - pads["outline y margin"]
|
||||||
|
|
||||||
|
|
||||||
if pads["*silk screen inside"]:
|
if pads["*silk screen inside"]:
|
||||||
ssXOffset *= -1
|
ssx_offset *= -1
|
||||||
|
|
||||||
ssX = -pin1Pos.x - ssXOffset
|
ssx = -pin1_pos.x - ssx_offset
|
||||||
ssY = -pin1Pos.y - ssYOffset
|
ssy = -pin1_pos.y - ssy_offset
|
||||||
|
|
||||||
|
self.DrawBox(ssx, ssy)
|
||||||
self.DrawBox(ssX, ssY)
|
|
||||||
|
|
||||||
#reference and value
|
#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.Value(0, - ssy - text_size, text_size)
|
||||||
self.draw.Reference(0, ssY + textSize, textSize)
|
self.draw.Reference(0, ssy + text_size, text_size)
|
||||||
|
|
||||||
|
|
||||||
class SDIPWizard(RowedFootprint):
|
class SDIPWizard(RowedFootprint):
|
||||||
|
@ -111,7 +117,7 @@ class SDIPWizard(RowedFootprint):
|
||||||
self.AddParam("Pads", "outline x margin", self.uMM, 0.5)
|
self.AddParam("Pads", "outline x margin", self.uMM, 0.5)
|
||||||
self.AddParam("Pads", "outline y margin", self.uMM, 1)
|
self.AddParam("Pads", "outline y margin", self.uMM, 1)
|
||||||
|
|
||||||
def GetReference(self):
|
def GetValue(self):
|
||||||
|
|
||||||
rows = self.parameters["Pads"]["*row count"]
|
rows = self.parameters["Pads"]["*row count"]
|
||||||
|
|
||||||
|
@ -128,9 +134,10 @@ class SDIPWizard(RowedFootprint):
|
||||||
pad_length = self.parameters["Pads"]["pad length"]
|
pad_length = self.parameters["Pads"]["pad length"]
|
||||||
pad_width = self.parameters["Pads"]["pad width"]
|
pad_width = self.parameters["Pads"]["pad width"]
|
||||||
drill = self.parameters["Pads"]["drill size"]
|
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:
|
if self.parameters["Pads"]["*row count"] == 2:
|
||||||
|
|
||||||
|
@ -144,18 +151,19 @@ class SDIPWizard(RowedFootprint):
|
||||||
notchWidth = pcbnew.FromMM(3)
|
notchWidth = pcbnew.FromMM(3)
|
||||||
notchHeight = pcbnew.FromMM(1)
|
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:
|
else:
|
||||||
# -----------------
|
# -----------------
|
||||||
# |1|2 3 4 5 6 7 8|
|
# |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
|
#line between pin1 and pin2
|
||||||
pad_pitch = self.parameters["Pads"]["pad pitch"];
|
pad_pitch = self.parameters["Pads"]["pad pitch"]
|
||||||
self.draw.HLine(-ssX, pin1Pos.y + pad_pitch/2, ssX * 2)
|
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()
|
SDIPWizard().register()
|
||||||
|
|
||||||
|
@ -168,7 +176,7 @@ class SOICWizard(RowedFootprint):
|
||||||
def GetDescription(self):
|
def GetDescription(self):
|
||||||
return "SOIC, MSOP, SSOP, TSSOP, etc, footprint wizard"
|
return "SOIC, MSOP, SSOP, TSSOP, etc, footprint wizard"
|
||||||
|
|
||||||
def GetReference(self):
|
def GetValue(self):
|
||||||
return "%s %d" % ("SOIC", self.parameters["Pads"]["*n"])
|
return "%s %d" % ("SOIC", self.parameters["Pads"]["*n"])
|
||||||
|
|
||||||
def GenerateParameterList(self):
|
def GenerateParameterList(self):
|
||||||
|
@ -186,15 +194,16 @@ class SOICWizard(RowedFootprint):
|
||||||
def GetPad(self):
|
def GetPad(self):
|
||||||
pad_length = self.parameters["Pads"]["pad length"]
|
pad_length = self.parameters["Pads"]["pad length"]
|
||||||
pad_width = self.parameters["Pads"]["pad width"]
|
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 |
|
# |8 7 6 5 |
|
||||||
# |1 2 3 4 |
|
# |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()
|
SOICWizard().register()
|
||||||
|
|
Loading…
Reference in New Issue