This repository has been archived by the owner on May 9, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 9
/
PadArray.py
459 lines (374 loc) · 13.8 KB
/
PadArray.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
# 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(object):
"""!
Useful construction functions for common types of pads, providing
sensible defaults for common pads.
"""
def __init__(self, module):
"""!
@param module: the module the pads will be part of
"""
self.module = module
def THPad(self, Vsize, Hsize, drill, shape=pcbnew.PAD_SHAPE_OVAL,
rot_degree = 0):
"""!
A basic through-hole pad of the given size and shape
@param Vsize: the vertical size of the pad
@param Hsize: the horizontal size of the pad
@param drill: the drill diameter
@param shape: the shape of the pad
@param rot_degree: the pad rotation, in degrees
"""
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):
"""!
A round though-hole pad. A shortcut for THPad()
@param size: pad diameter
@param drill: drill diameter
"""
pad = self.THPad(size, size, drill, shape=pcbnew.PAD_SHAPE_CIRCLE)
return pad
def NPTHRoundPad(self, drill):
"""!
A round non-plated though hole (NPTH)
@param drill: the drill diameter (equals the NPTH diameter)
"""
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):
"""
Create a surface-mount pad of the given size and shape
@param Vsize: the vertical size of the pad
@param Hsize: the horizontal size of the pad
@param drill: the drill diameter
@param shape: the shape of the pad
@param rot_degree: the pad rotation, in degrees
"""
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):
"""!
A round surface-mount pad. A shortcut for SMDPad()
@param size: pad diameter
"""
pad = self.SMDPad(size, size, shape=pcbnew.PAD_SHAPE_CIRCLE)
return pad
class PadArray(object):
"""!
A class to assist in creating repetitive grids of pads
Generally, PadArrays have an internal prototypical pad, and copy this
for each pad in the array. They can also have a special pad for the
first pad, and a custom function to name the pad.
Generally, PadArray is used as a base class for more specific array
types.
"""
def __init__(self, pad):
"""!
@param pad: the prototypical pad
"""
self.firstPadNum = 1
self.pinNames = None
# 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.firstPad = None
def SetPinNames(self, pinNames):
"""!
Set a name for all the pins. If given, this overrides the
naming function.
@param pinNames: the name to use for all pins
"""
self.pinNames = pinNames
def SetFirstPadType(self, firstPad):
"""!
If the array has a different first pad, this is the pad that
is used
@param firstPad: the prototypical first pad
"""
self.firstPad = firstPad
def SetFirstPadInArray(self, fpNum):
"""!
Set the numbering for the first pad in the array
@param fpNum: the number for the first pad
"""
self.firstPadNum = fpNum
def AddPad(self, pad):
"""!
Add a pad to the array, under the same moodule as the main
prototype pad
@param pad: pad to add
"""
self.pad.GetParent().Add(pad)
def GetPad(self, is_first_pad, pos):
"""!
Get a pad in the array with the given position
@param is_first_pad: use the special first pad if there is one
@param pos: the pad position
"""
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):
"""!
Get the pad name from the naming function, or the pre-set
pinNames parameter (set with SetPinNames)
"""
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):
"""!
A basic grid of pads
"""
def __init__(self, pad, nx, ny, px, py, centre=pcbnew.wxPoint(0, 0)):
"""!
@param pad: the prototypical pad of the array
@param nx: number of pads in x-direction
@param ny: number of pads in y-direction
@param px: pitch in x-direction
@param py: pitch in y-direction
@param centre: array centre point
"""
super().__init__(pad)
self.nx = int(nx)
self.ny = int(ny)
self.px = px
self.py = py
self.centre = centre
def AlphaNameFromNumber(self, n, aIndex=1,
alphabet="ABCDEFGHIJKLMNOPQRSTUVWXYZ"):
"""!
Utility function to generate an alphabetical name:
eg. 1 - A, 2 - B, 26 - AA, etc
@param aIndex: index of 'A': 0 for 0 - A
@param n: the pad index
@param alphabet: set of allowable chars if not A-Z,
e.g. ABCDEFGHJKLMNPRTUVWY for BGA
"""
div, mod = divmod(n - aIndex, len(alphabet))
alpha = alphabet[mod]
if div > 0:
return self.AlphaNameFromNumber(div, aIndex, alphabet) + alpha
return alpha
def NamingFunction(self, x, y):
"""!
Implementation of the naming function: right to left, top-to-bottom
@param x: the pad x index
@param y: the pad y index
"""
return self.firstPadNum + (self.nx * y + x)
#relocate the pad and add it as many times as we need
def AddPadsToModule(self, dc):
"""!
Create the pads and add them to the module in the correct positions
@param dc: the drawing context
"""
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.SetName(self.GetName(x,y))
self.AddPad(pad)
class EPADGridArray(PadGridArray):
"""!
A pad grid array with a fixed name, used for things like thermal
pads and via grids.
"""
def NamingFunction(self, nx, ny):
"""!
Simply return the firstPadNum
@param nx: not used
@param ny: not used
"""
return self.firstPadNum
class PadZGridArray(PadArray):
"""!
A staggered pin array
"""
def __init__(self, pad, pad_count, line_count, line_pitch,
pad_pitch, centre=pcbnew.wxPoint(0, 0)):
"""!
@param pad: the prototypical pad
@param pad_count: total pad count
@param line_count: number of staggered lines
@param line_pitch: distance between lines
@param pad_pitch: distance between pads in a line
@param centre: array centre point
"""
super(PadZGridArray, self).__init__(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
def NamingFunction(self, pad_pos):
"""!
Naming just increased with pad index in array
"""
return self.firstPadNum + pad_pos
def AddPadsToModule(self, dc):
"""!
Create the pads and add them to the module in the correct positions
@param dc: the drawing context
"""
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.SetName(self.GetName(padnum))
self.AddPad(pad)
line += 1
if line >= self.line_count:
line = 0
class PadLineArray(PadGridArray):
"""!
Shortcut cases for a single-row grid array. Can be used for
constructing sections of larger footprints.
"""
def __init__(self, pad, n, pitch, isVertical,
centre=pcbnew.wxPoint(0, 0)):
"""!
@param pad: the prototypical pad
@param n: number of pads in array
@param pitch: distance between pad centres
@param isVertical: horizontal or vertical array (can also use the
drawing contexts transforms for more control)
@param centre: array centre
"""
if isVertical:
super(PadLineArray, self).__init__(pad, 1, n, 0, pitch, centre)
else:
super(PadLineArray, self).__init__(pad, n, 1, pitch, 0, centre)
class PadCircleArray(PadArray):
"""!
Circular pad array
"""
def __init__(self, pad, n, r, angle_offset=0, centre=pcbnew.wxPoint(0, 0),
clockwise=True, padRotationEnable=False, padRotationOffset=0):
"""!
@param pad: the prototypical pad
@param n: number of pads in array
@param r: the circle radius
@param angle_offset: angle of the first pad
@param centre: array centre point
@param clockwise: array increases in a clockwise direction
@param padRotationEnable: also rotate pads when placing
@param padRotationOffset: rotation of first pad
"""
super(PadCircleArray, self).__init__(pad)
self.n = int(n)
self.r = r
self.angle_offset = angle_offset
self.centre = centre
self.clockwise = clockwise
self.padRotationEnable = padRotationEnable
self.padRotationOffset = padRotationOffset
def NamingFunction(self, n):
"""!
Naming around the circle, CW or CCW according to the clockwise flag
"""
return str(self.firstPadNum + n)
def AddPadsToModule(self, dc):
"""!
Create the pads and add them to the module in the correct positions
@param dc: the drawing context
"""
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)
padAngle = self.padRotationOffset
if self.padRotationEnable:
padAngle -=angle
pad.SetOrientation(padAngle*10)
pad.SetName(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):
"""!
@param pad: the prototypical pad
@param array: the position data array
"""
super(PadCustomArray, self).__init__(pad)
self.array = array
def NamingFunction(self, n):
"""!
Simple increment along the given array
@param n: the pad index in the array
"""
return str(self.firstPadNum + n)
def AddPadsToModule(self, dc):
"""!
Create the pads and add them to the module in the correct positions
@param dc: the drawing context
"""
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.SetName(self.GetName(i))
self.AddPad(pad)