kicad/pcbnew/scripting/plugins/PadArray.py

276 lines
8.4 KiB
Python

# 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
class PadMaker:
"""
Useful construction functions for common types of pads
"""
def __init__(self, module):
self.module = module
def THPad(self, Vsize, Hsize, drill, shape=pcbnew.PAD_SHAPE_OVAL, rot_degree = 0):
pad = pcbnew.D_PAD(self.module)
pad.SetSize(pcbnew.wxSize(Hsize, Vsize))
pad.SetShape(shape)
pad.SetAttribute(pcbnew.PAD_ATTRIB_STANDARD)
pad.SetLayerSet(pad.StandardMask())
pad.SetDrillSize(pcbnew.wxSize(drill, drill))
pad.SetOrientation(rot_degree*10) # rotation is in 0.1 degrees
return pad
def THRoundPad(self, size, drill):
pad = self.THPad(size, size, drill, shape=pcbnew.PAD_SHAPE_CIRCLE)
return pad
def NPTHRoundPad(self, drill):
pad = pcbnew.D_PAD(self.module)
pad.SetSize(pcbnew.wxSize(drill, drill))
pad.SetShape(pcbnew.PAD_SHAPE_CIRCLE)
pad.SetAttribute(pcbnew.PAD_ATTRIB_HOLE_NOT_PLATED)
pad.SetLayerSet(pad.UnplatedHoleMask())
pad.SetDrillSize(pcbnew.wxSize(drill, drill))
return pad
def SMDPad(self, Vsize, Hsize, shape=pcbnew.PAD_SHAPE_RECT, rot_degree=0):
pad = pcbnew.D_PAD(self.module)
pad.SetSize(pcbnew.wxSize(Hsize, Vsize))
pad.SetShape(shape)
pad.SetAttribute(pcbnew.PAD_ATTRIB_SMD)
pad.SetLayerSet(pad.SMDMask())
pad.SetOrientation(rot_degree*10) # rotation is in 0.1 degrees
return pad
def SMTRoundPad(self, size):
pad = self.SMDPad(size, size, shape=pcbnew.PAD_SHAPE_CIRCLE)
return pad
class PadArray:
def __init__(self):
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.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, 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
self.nx = int(nx)
self.ny = int(ny)
self.px = px
self.py = py
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"):
div, mod = divmod(n - aIndex, len(alphabet))
alpha = alphabet[mod]
if div > 0:
return self.AlphaNameFromNumber(div, aIndex, alphabet) + alpha
return alpha
# right to left, top to bottom
def NamingFunction(self, x, y):
return self.firstPadNum + (self.nx * y + x)
#relocate the pad and add it as many times as we need
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):
posY = pin1posY + (self.py * y)
pos = dc.TransformPoint(posX, posY)
pad = self.GetPad(x == 0 and y == 0, pos)
pad.SetPadName(self.GetName(x,y))
self.AddPad(pad)
class PadZGridArray(PadArray):
def __init__(self, pad, pad_count, line_count, line_pitch,
pad_pitch, 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
self.pad_count = int(pad_count)
self.line_count = int(line_count)
self.line_pitch = line_pitch
self.pad_pitch = pad_pitch
self.centre = centre
# right to left, top to bottom
def NamingFunction(self, pad_pos):
return self.firstPadNum + pad_pos
#relocate the pad and add it as many times as we need
def AddPadsToModule(self, dc):
pin1posX = self.centre.x - self.pad_pitch * (self.pad_count - 1) / 2
pin1posY = self.centre.y + self.line_pitch * (self.line_count - 1) / 2
line = 0
for padnum in range(0, self.pad_count):
posX = pin1posX + (padnum * self.pad_pitch)
posY = pin1posY - (self.line_pitch * line)
pos = dc.TransformPoint(posX, posY)
pad = self.GetPad(padnum == 0, pos)
pad.SetPadName(self.GetName(padnum))
self.AddPad(pad)
line += 1
if line >= self.line_count:
line = 0
class PadLineArray(PadGridArray):
def __init__(self, pad, n, pitch, isVertical,
centre=pcbnew.wxPoint(0, 0)):
if isVertical:
PadGridArray.__init__(self, pad, 1, n, 0, pitch, centre)
else:
PadGridArray.__init__(self, pad, n, 1, pitch, 0, centre)
class PadCircleArray(PadArray):
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
# around the circle, CW or CCW according to the flag
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 pin in range(0, self.n):
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)