def insert_keepout_polygon(wx_points, layers=None): layers_LSET = pcbnew.LSET() if layers is None: layers_LSET.AddLayer(pcbnew.F_Cu) layers_LSET.AddLayer(pcbnew.B_Cu) layers = [pcbnew.F_Cu] else: for layer in layers: layers_LSET.AddLayer(layer) board = pcbnew.GetBoard() area = board.InsertArea(-1, 0xffff, layers[0], 0, 0, pcbnew.ZONE_CONTAINER.DIAGONAL_FULL) area.SetLayerSet(layers_LSET) area.SetIsKeepout(True) area.SetDoNotAllowTracks(True) area.SetDoNotAllowVias(True) area.SetDoNotAllowCopperPour(True) outline = area.Outline() outline.RemoveAllContours() for p in wx_points: area.AppendCorner(p, -1) #print(p) if hasattr(area, "BuildFilledSolidAreasPolygons"): area.BuildFilledSolidAreasPolygons(board) if hasattr(area, "Hatch"): area.Hatch()
def build(self): board = pcbnew.BOARD() # outline PcbPolygon(self.outline).build(board) # Add holes for h in self.holes: h.build(board) # Add ground plane signals = {} if self.fill_name: fill_net = pcbnew.NETINFO_ITEM(board, self.fill_name) board.Add(fill_net) signals[self.fill_name] = fill_net item = pcbnew.ZONE(board, False) poly = pcbnew.wxPoint_Vector() for x, y in self.outline.exterior.coords: poly.append(pcbnew.wxPointMM(x, y)) item.AddPolygon(poly) item.SetNet(fill_net) lset = pcbnew.LSET() lset.AddLayer(pcbnew.F_Cu) lset.AddLayer(pcbnew.B_Cu) item.SetLayerSet(lset) board.Add(item) for component in self.components: component.build(board, signals) return board
def DrawThermalPadSolderPaste(self, x, y, rows, cols, percent): # Calculate the paste area given percentage x_total_size = x / (math.sqrt(1 / (percent / 100))) y_total_size = y / (math.sqrt(1 / (percent / 100))) x_box = x_total_size / cols y_box = y_total_size / cols x_spacer = (x - cols * x_box) / (cols - 1) y_spacer = (y - rows * y_box) / (rows - 1) x_step = x_spacer + x_box y_step = y_spacer + y_box # Use PAD as Paste only but Kicad complains # Is it a valid use ? pastepad = PA.PadMaker(self.module).SMDPad(x_box, y_box, pcbnew.PAD_RECT) only_paste = pcbnew.LSET(pcbnew.F_Paste) pastepad.SetLayerSet(only_paste) array = ThermalViasArray(pastepad, cols, rows, x_step, y_step) #array.SetFirstPadInArray(self.parameters["Pads"]["*nbpads"]+1) array.SetFirstPadInArray('~') array.AddPadsToModule(self.draw)
def _to_LayerSet(layers): """Create LayerSet used for defining pad layers""" bitset = 0 for l in layers: bitset |= 1 << _get_layer(l) hexset = '{0:013x}'.format(bitset) lset = pcbnew.LSET() lset.ParseHex(hexset, len(hexset)) return lset
def smdRectPad(self, module, size, pos, name): pad = D_PAD(module) pad.SetSize(size) pad.SetShape(PAD_SHAPE_RECT) pad.SetAttribute(PAD_ATTRIB_SMD) layerset = pcbnew.LSET() layerset.AddLayer(pcbnew.F_Cu) pad.SetLayerSet(layerset) pad.SetPos0(pos) pad.SetPosition(pos) pad.SetName(name) return pad
def _drawSolderMaskOpening(self, sizex, sizey, radius): # Draw the solder mask opening pad = pcbnew.D_PAD(self.module) pad.SetSize(pcbnew.wxSize(sizex, sizey)) #TODO: Add fancy radius, once I figure out where to set the radius... # pad.SetShape(pcbnew.PAD_SHAPE_ROUNDRECT) pad.SetShape(pcbnew.PAD_SHAPE_RECT) pad.SetAttribute(pcbnew.PAD_ATTRIB_SMD) layerset = pcbnew.LSET() layerset.AddLayer(pcbnew.F_Mask) pad.SetLayerSet( layerset ) pad.SetLocalSolderMaskMargin( -1 ) pad.SetPosition(pcbnew.wxPoint(0, 0)) pad.SetPadName("") self.module.Add(pad)
def smdTrianglePad(self, module, size, pos, name, up_down=1, left_right=0): pad = D_PAD(module) pad.SetSize(wxSize(size[0], size[1])) pad.SetShape(PAD_SHAPE_TRAPEZOID) pad.SetAttribute(PAD_ATTRIB_SMD) layerset = pcbnew.LSET() layerset.AddLayer(currentLayer) pad.SetLayerSet(layerset) pad.SetPos0(pos) pad.SetPosition(pos) pad.SetName(name) pad.SetDelta(wxSize(left_right * size[1], up_down * size[0])) return pad
def _drawPixel(self, xposition, yposition): # build a rectangular pad: as a dot pad = pcbnew.D_PAD(self.module) pad.SetSize(pcbnew.wxSize(self.X, self.X)) pad.SetShape(pcbnew.PAD_SHAPE_RECT) pad.SetAttribute(pcbnew.PAD_ATTRIB_SMD) layerset = pcbnew.LSET() if self.UseCu: layerset.AddLayer(pcbnew.F_Cu) if self.UseSilkS: layerset.AddLayer(pcbnew.F_SilkS) pad.SetLayerSet( layerset ) pad.SetLocalSolderMaskMargin( -1 ) pad.SetPosition(pcbnew.wxPoint(xposition,yposition)) pad.SetPadName("") self.module.Add(pad)
def _drawPixel(self, xposition, yposition): # build a rectangular pad as a dot on copper layer, # and a polygon (a square) on silkscreen if self.UseCu: pad = pcbnew.D_PAD(self.module) pad.SetSize(pcbnew.wxSize(self.X, self.X)) pad.SetPosition(pcbnew.wxPoint(xposition,yposition)) pad.SetShape(pcbnew.PAD_SHAPE_RECT) pad.SetAttribute(pcbnew.PAD_ATTRIB_SMD) pad.SetName("") layerset = pcbnew.LSET() layerset.AddLayer(pcbnew.F_Cu) layerset.AddLayer(pcbnew.F_Mask) pad.SetLayerSet( layerset ) self.module.Add(pad) if self.UseSilkS: polygon=self.drawSquareArea(pcbnew.F_SilkS, self.X, xposition, yposition) self.module.Add(polygon)
def TaperFootprint(self, center=pcbnew.wxPoint(0,0), angle_deg=0): self.module = pcbnew.MODULE(None) # 6 # 5 +------------+ # | |\ # | | \ 7 # | | +---+ 0 # | | | | # | | +---+ 1 # | | / 2 # | |/ # 4 +------------+ # 3 points = [(self.w2/2, -self.w2/2), (self.w2/2, self.w2/2), (-self.w2/2, self.w2/2), \ (-self.w2/2 - self.tlen, self.w1/2), (-(self.w1/2 + self.tlen + self.w2/2), self.w1/2), \ (-(self.w1/2 + self.tlen + self.w2/2), -self.w1/2), (-self.w2/2 - self.tlen, -self.w1/2), \ (-self.w2/2, -self.w2/2)] points = [pcbnew.wxPoint(*point) for point in points] # Custom pad for smaller W2 x W2 pad cs_pad = pcbnew.D_PAD(self.module) cs_pad.SetSize(pcbnew.wxSize(self.w2, self.w2)) cs_pad.SetShape(pcbnew.PAD_SHAPE_CUSTOM) cs_pad.SetAnchorPadShape(pcbnew.PAD_SHAPE_RECT) cs_pad.SetAttribute(pcbnew.PAD_ATTRIB_SMD) cs_pad.SetLayerSet(pcbnew.LSET(pcbnew.F_Cu)) cs_pad.AddPrimitive(points, 0) cs_pad.SetLocalClearance(1) cs_pad.SetNet(self.net) cs_pad.SetPadName("1") self.module.Add(cs_pad) self.module.Add(Layout.smdRectPad(self.module, pcbnew.wxSize(self.w1, self.w1), pcbnew.wxPoint(-(self.w1/2 + self.tlen + self.w2/2), 0), "1", angle_deg, self.net)) # TODO: Address other layers... self.module.SetPosition(center) # Add to pcbnew pcbnew.GetBoard().Add(self.module) pcbnew.Refresh()
def loadsetsfromfolder(self): board = pcbnew.GetBoard() f = [] for (dirpath, dirnames, filenames) in os.walk(savepath): f.extend(filenames) break for filename in f: layerarray = [] rendervalue = None with open(os.path.join(dirpath,filename),'r') as f: for line in f: line=line.strip() if line.startswith('#'): continue # line here is 3 values separated by commas (type,name,visible) = map(str.strip,line.split(',')) if type=='layer': id = board.GetLayerID(name) layerarray.append((id,visible)) elif type=='render': rendervalue = int(name, 2) else: pass # type is unrecognized # Generate the lset and the render values, and assign them to an element # element is (layerset,rendervalue,widget,name,file) if layerarray: layerset = pcbnew.LSET() for layer,visible in layerarray: layerset.addLayer(layer) else: layerset = None widget = self.get_viewset_widget( self._nameparent, filename, self.get_tool_tip(layerset,rendervalue)) #Element = collections.namedtuple('Element','layers items widget name filepath') element = Element(layerset,rendervalue,widget,filename,os.path.join(dirpath,filename)) self._layersetsaved.append(element)
def createPad(self, number, name): top = number % 2 == 1 if self.omitPin(number): return None padTotalHeight = topPadHeight if top else bottomPadHeight padHeight = padTotalHeight - padVerticalOffset padSize = pcbnew.wxSize(padWidth, padHeight) padOneCenterX = pcbnew.FromMM(18 * 0.5 + 0.25) padTwoCenterX = padOneCenterX + pcbnew.FromMM(0.25) pad = pcbnew.D_PAD(self.module) layerSet = pcbnew.LSET() if top: # On the top, 0.0 is centered between pads 35 and 37. padOffset = (number - 1) / 2 padCenterX = padOneCenterX - pcbnew.FromMM(padOffset * 0.5) layerSet.AddLayer(pcbnew.F_Cu) else: # On the bottom, 0.0 is the center of pad 36. padOffset = (number) / 2 padCenterX = padTwoCenterX - pcbnew.FromMM(padOffset * 0.5) layerSet.AddLayer(pcbnew.B_Cu) padCenterY = -(padVerticalOffset + padHeight / 2.0) padCenter = pcbnew.wxPoint(padCenterX, padCenterY) pad.SetSize(padSize) pad.SetPos0(padCenter) pad.SetPosition(padCenter) pad.SetShape(pcbnew.PAD_SHAPE_RECT) pad.SetAttribute(pcbnew.PAD_ATTRIB_SMD) pad.SetLayerSet(layerSet) pad.SetPadName(name) return pad
def smdRectPad(module, size, pos, name, angle, net): '''Build a rectangular pad.''' pad = pcbnew.D_PAD(module) pad.SetSize(size) pad.SetShape(pcbnew.PAD_SHAPE_RECT) pad.SetAttribute(pcbnew.PAD_ATTRIB_SMD) # Set only the copper layer without mask # since nothing is mounted on these pads pad.SetLayerSet(pcbnew.LSET(pcbnew.F_Cu)) # Get active layer pad.SetPos0(pos) pad.SetPosition(pos) pad.SetPadName(name) pad.Rotate(pos, angle) # Set clearance to small value, because # pads can be very close together. # If distance is smaller than clearance # DRC doesn't allow routing the pads pad.SetLocalClearance(1) pad.SetNet(net) return pad
def BuildThisFootprint(self): pad_pitch = self.pads["pitch"] pad_length = self.pads["length"] # offset allows to define how much of the pad is outside of the package pad_offset = self.pads["offset"] pad_width = self.pads["width"] v_pitch = self.package["height"] h_pitch = self.package["width"] pads_per_row = int(self.pads["n"] // 4) row_len = (pads_per_row - 1) * pad_pitch pad_shape = pcbnew.PAD_SHAPE_OVAL if self.pads[ "oval"] else pcbnew.PAD_SHAPE_RECT h_pad = PA.PadMaker(self.module).SMDPad(pad_length, pad_width, shape=pad_shape, rot_degree=90.0) v_pad = PA.PadMaker(self.module).SMDPad(pad_length, pad_width, shape=pad_shape) h_pitch = h_pitch / 2 - pad_length + pad_offset + pad_length / 2 v_pitch = v_pitch / 2 - pad_length + pad_offset + pad_length / 2 #left row pin1Pos = pcbnew.wxPoint(-h_pitch, 0) array = PA.PadLineArray(h_pad, pads_per_row, pad_pitch, True, pin1Pos) array.SetFirstPadInArray(1) array.AddPadsToModule(self.draw) #bottom row pin1Pos = pcbnew.wxPoint(0, v_pitch) array = PA.PadLineArray(v_pad, pads_per_row, pad_pitch, False, pin1Pos) array.SetFirstPadInArray(pads_per_row + 1) array.AddPadsToModule(self.draw) #right row pin1Pos = pcbnew.wxPoint(h_pitch, 0) array = PA.PadLineArray(h_pad, pads_per_row, -pad_pitch, True, pin1Pos) array.SetFirstPadInArray(2 * pads_per_row + 1) array.AddPadsToModule(self.draw) #top row pin1Pos = pcbnew.wxPoint(0, -v_pitch) array = PA.PadLineArray(v_pad, pads_per_row, -pad_pitch, False, pin1Pos) array.SetFirstPadInArray(3 * pads_per_row + 1) array.AddPadsToModule(self.draw) lim_x = self.package["width"] / 2 lim_y = self.package["height"] / 2 inner = (row_len / 2) + pad_pitch # epad epad_width = self.epad["width"] epad_length = self.epad["length"] epad_ny = self.epad["x divisions"] epad_nx = self.epad["y divisions"] epad_via_drill = self.epad["thermal vias drill"] # Create a central exposed pad? if self.epad['epad'] == True: epad_num = self.pads['n'] + 1 epad_w = epad_length / epad_nx epad_l = epad_width / epad_ny # Create the epad epad = PA.PadMaker(self.module).SMDPad(epad_w, epad_l, shape=pcbnew.PAD_SHAPE_RECT) epad.SetLocalSolderPasteMargin(-1 * self.epad['paste margin']) # set pad layers layers = pcbnew.LSET(pcbnew.F_Mask) layers.AddLayer(pcbnew.F_Cu) layers.AddLayer(pcbnew.F_Paste) epad.SetName(epad_num) array = PA.EPADGridArray(epad, epad_ny, epad_nx, epad_l, epad_w, pcbnew.wxPoint(0, 0)) array.SetFirstPadInArray(epad_num) array.AddPadsToModule(self.draw) if self.epad['thermal vias']: # create the thermal via via_diam = min(epad_w, epad_l) / 2 via_drill = min(via_diam / 2, epad_via_drill) via = PA.PadMaker(self.module).THRoundPad(via_diam, via_drill) layers = pcbnew.LSET.AllCuMask() layers.AddLayer(pcbnew.B_Mask) layers.AddLayer(pcbnew.F_Mask) via.SetLayerSet(layers) via_array = PA.EPADGridArray(via, epad_ny, epad_nx, epad_l, epad_w, pcbnew.wxPoint(0, 0)) via_array.SetFirstPadInArray(epad_num) via_array.AddPadsToModule(self.draw) # Draw the package outline on the F.Fab layer bevel = min(pcbnew.FromMM(1.0), self.package['width'] / 2, self.package['height'] / 2) self.draw.SetLayer(pcbnew.F_Fab) w = self.package['width'] h = self.package['height'] self.draw.BoxWithDiagonalAtCorner(0, 0, w, h, bevel) # Silkscreen self.draw.SetLayer(pcbnew.F_SilkS) offset = self.draw.GetLineThickness() clip = row_len / 2 + self.pads['pitch'] self.draw.SetLineThickness( pcbnew.FromMM(0.12)) #Default per KLC F5.1 as of 12/2018 self.draw.Polyline([[clip, -h / 2 - offset], [w / 2 + offset, -h / 2 - offset], [w / 2 + offset, -clip]]) # top right self.draw.Polyline([[clip, h / 2 + offset], [w / 2 + offset, h / 2 + offset], [w / 2 + offset, clip]]) # bottom right self.draw.Polyline([[-clip, h / 2 + offset], [-w / 2 - offset, h / 2 + offset], [-w / 2 - offset, clip]]) # bottom left # Add pin-1 indication as per IPC-7351C self.draw.Line(-clip, -h / 2 - offset, -w / 2 - pad_length / 2, -h / 2 - offset) self.draw.SetLineThickness(offset) #Restore default # Courtyard cmargin = self.package["margin"] self.draw.SetLayer(pcbnew.F_CrtYd) sizex = (lim_x + cmargin) * 2 + pad_length sizey = (lim_y + cmargin) * 2 + pad_length # round size to nearest 0.1mm, rectangle will thus land on a 0.05mm grid sizex = pcbnew.PutOnGridMM(sizex, 0.1) sizey = pcbnew.PutOnGridMM(sizey, 0.1) # set courtyard line thickness to the one defined in KLC thick = self.draw.GetLineThickness() self.draw.SetLineThickness(pcbnew.FromMM(0.05)) self.draw.Box(0, 0, sizex, sizey) # restore line thickness to previous value self.draw.SetLineThickness(pcbnew.FromMM(thick)) #reference and value text_size = self.GetTextSize() # IPC nominal text_offset = sizey / 2 + text_size self.draw.Value(0, text_offset, text_size) self.draw.Reference(0, -text_offset, text_size) # set SMD attribute self.module.SetAttributes(pcbnew.MOD_SMD)
def BuildThisFootprint(self): pads = self.parameters["Pads"] pad_pitch = pads["pad pitch"] pad_length = pads["pad length"] pad_width = pads["pad width"] v_pitch = self.parameters["Package"]["package height"] h_pitch = self.parameters["Package"]["package width"] pads_per_row = pads["*n"] // 4 row_len = (pads_per_row - 1) * pad_pitch pad_shape = pcbnew.PAD_SHAPE_OVAL if pads[ "*oval"] else pcbnew.PAD_SHAPE_RECT h_pad = PA.PadMaker(self.module).SMDPad(pad_length, pad_width, shape=pad_shape, rot_degree=90.0) v_pad = PA.PadMaker(self.module).SMDPad(pad_length, pad_width, shape=pad_shape) #left row pin1Pos = pcbnew.wxPoint(-h_pitch / 2, 0) array = PA.PadLineArray(h_pad, pads_per_row, pad_pitch, True, pin1Pos) array.SetFirstPadInArray(1) array.AddPadsToModule(self.draw) #bottom row 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(self.draw) #right row 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(self.draw) #top row 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(self.draw) lim_x = self.parameters["Package"]["package width"] / 2 lim_y = self.parameters["Package"]["package height"] / 2 inner = (row_len / 2) + pad_pitch # epad epad_width = self.parameters["Package"]["package height"] - ( 2 * pad_length) epad_length = self.parameters["Package"]["package width"] - ( 2 * pad_length) epad_subdv_x = pads["*epad subdiv x"] epad_subdv_y = pads["*epad subdiv y"] epad_via_drill = pads["thermal vias drill"] if (epad_subdv_y != 0 and epad_subdv_x != 0) and (epad_subdv_y != 1 or epad_subdv_x != 1): # Create the master pad (one area) on front solder mask, and perhaps of front copper layer # at location 0,0 emasterpad = PA.PadMaker(self.module).SMDPad( epad_length, epad_width, shape=pcbnew.PAD_SHAPE_RECT, rot_degree=0.0) emasterpad.SetLayerSet(pcbnew.LSET( pcbnew.F_Mask)) # currently, only on solder mask emasterpad.SetPadName(pads["*n"] + 1) self.module.Add(emasterpad) px = pcbnew.FromMM(0.1) py = pcbnew.FromMM(0.1) esubpad_size_x = epad_length / epad_subdv_x - px esubpad_size_y = epad_width / epad_subdv_y - py epad1_pos = pcbnew.wxPoint( -(esubpad_size_x * (epad_subdv_x - 1) / 2), -esubpad_size_y * (epad_subdv_y - 1) / 2) epad = PA.PadMaker(self.module).SMDPad(esubpad_size_y, esubpad_size_x, shape=pcbnew.PAD_SHAPE_RECT, rot_degree=0.0) array = PA.EPADGridArray(epad, epad_subdv_x, epad_subdv_y, esubpad_size_x + px, esubpad_size_y + py, pcbnew.wxPoint(0, 0)) array.SetFirstPadInArray(pads["*n"] + 1) array.AddPadsToModule(self.draw) if pads["*thermal vias"]: via_diam = min(esubpad_size_y, esubpad_size_x) / 3. thpad = PA.PadMaker(self.module).THRoundPad( via_diam, min(via_diam / 2, epad_via_drill)) layerset = pcbnew.LSET.AllCuMask() layerset.AddLayer(pcbnew.B_Mask) layerset.AddLayer(pcbnew.F_Mask) thpad.SetLayerSet(layerset) array2 = PA.EPADGridArray(thpad, epad_subdv_x, epad_subdv_y, esubpad_size_x + px, esubpad_size_y + py, pcbnew.wxPoint(0, 0)) array2.SetFirstPadInArray(pads["*n"] + 1) array2.AddPadsToModule(self.draw) else: epad = PA.PadMaker(self.module).SMDPad(epad_length, epad_width) epad_pos = pcbnew.wxPoint(0, 0) array = PA.PadLineArray(epad, 1, 1, False, epad_pos) array.SetFirstPadInArray(pads["*n"] + 1) array.AddPadsToModule(self.draw) if pads["*thermal vias"]: via_diam = min(epad_length, epad_width) / 3. thpad = PA.PadMaker(self.module).THRoundPad( via_diam, min(via_diam / 2, epad_via_drill)) layerset = pcbnew.LSET.AllCuMask() layerset.AddLayer(pcbnew.B_Mask) layerset.AddLayer(pcbnew.F_Mask) thpad.SetLayerSet(layerset) array2 = PA.PadLineArray(thpad, 1, 1, False, epad_pos) array2.SetFirstPadInArray(pads["*n"] + 1) array2.AddPadsToModule(self.draw) #top left - diagonal self.draw.Line(-lim_x, -inner, -inner, -lim_y) # top right self.draw.Polyline([(inner, -lim_y), (lim_x, -lim_y), (lim_x, -inner)]) # bottom left self.draw.Polyline([(-inner, lim_y), (-lim_x, lim_y), (-lim_x, inner)]) # bottom right self.draw.Polyline([(inner, lim_y), (lim_x, lim_y), (lim_x, inner)]) # Courtyard cmargin = self.parameters["Package"]["courtyard margin"] self.draw.SetLayer(pcbnew.F_CrtYd) sizex = (lim_x + cmargin) * 2 + pad_length / 2. sizey = (lim_y + cmargin) * 2 + pad_length / 2. # round size to nearest 0.1mm, rectangle will thus land on a 0.05mm grid sizex = self.PutOnGridMM(sizex, 0.1) sizey = self.PutOnGridMM(sizey, 0.1) # set courtyard line thickness to the one defined in KLC thick = self.draw.GetLineThickness() self.draw.SetLineThickness(pcbnew.FromMM(0.05)) self.draw.Box(0, 0, sizex, sizey) # restore line thickness to previous value self.draw.SetLineThickness(pcbnew.FromMM(thick)) #reference and value text_size = self.GetTextSize() # 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) # set SMD attribute self.module.SetAttributes(pcbnew.MOD_CMS)
def ChamferFootprint(self, center=pcbnew.wxPoint(0, 0)): self.module = pcbnew.MODULE(None) # Create new module self.angle = m.radians(self.angle_deg) # Calculate the miter w = self.width # Width of the corner from edge of the corner to inside corner corner_width = pcbnew.ToMM(w) / m.cos(self.angle / 2) # Get proportion of width to cut cut = self.OptimalMiter() print("Cut: {0:.2f}%".format(cut * 100)) # Distance from uncut outside corner point to point 7 cut = pcbnew.FromMM(cut * corner_width / m.cos( (m.pi - self.angle) / 2)) # Distance between points 2 and 3 and points 3 and 4 # Minimum of w/2 to satisfy DRC, otherwise pads are too close # and track connected to other pad overlaps the other one. # Rounded trace end can also stick out of the cut area # if a is too small. a = max(cut - self.width * m.tan(self.angle / 2), w / 2) # Distance between points 3 and 4 x34 = a * m.sin(self.angle) y34 = a * m.cos(self.angle) # Distance between points 4 and 5 x45 = self.width * m.cos(self.angle) y45 = self.width * m.sin(self.angle) # Distance from point 7 to 1 (no x-component) d71 = a + self.width * m.tan(self.angle / 2) - cut # 1 2 # +--+ # | |3 # 7 \ --+ 4 # \ | # \--+ 5 # 6 dW = w / 55 # To prevent tracks from over-extending points = [ (-w / 2, -d71 / 2), (w / 2, -d71 / 2), (w / 2, a - d71 / 2 + dW), (w / 2 + x34 - (d71 / 2 - d71 / 1e5 - dW) * m.sin(self.angle), a + y34 - d71 / 2 - (d71 / 2 - d71 / 1e5 - dW) * m.cos(self.angle) + dW), (w / 2 + x34 - x45 - (d71 / 2 - d71 / 1e5 - dW) * m.sin(self.angle), a + y34 + y45 - d71 / 2 - (d71 / 2 - d71 / 1e5 - dW) * m.cos(self.angle) + dW), (cut * m.sin(self.angle) - w / 2, a + self.width * m.tan(self.angle / 2) + cut * m.cos(self.angle) - d71 / 2 + dW), (-w / 2, a + self.width * m.tan(self.angle / 2) - cut - d71 / 2 + dW) ] # Last two points can be equal if points[-2] == points[-1]: points = points[:-1] points = [pcbnew.wxPoint(*point) for point in points] # Custom pad cs_pad = pcbnew.D_PAD(self.module) cs_pad.SetSize(pcbnew.wxSize(w, d71)) cs_pad.SetShape(pcbnew.PAD_SHAPE_CUSTOM) cs_pad.SetAnchorPadShape(pcbnew.PAD_SHAPE_RECT) cs_pad.SetAttribute(pcbnew.PAD_ATTRIB_SMD) cs_pad.SetLayerSet(pcbnew.LSET(pcbnew.F_Cu)) cs_pad.AddPrimitive(points, 0) cs_pad.SetLocalClearance(1) cs_pad.SetNet(self.net) cs_pad.SetPadName("1") self.module.Add(cs_pad) # Halfway between points 4 and 5 posx = ((w / 2 + x34) + (w / 2 + x34 - x45)) / 2 posy = ((a + y34 - d71 / 2) + (a + y34 + y45 - d71 / 2)) / 2 # Position pad so that pad edge touches polygon edge posx -= (d71 / 2 - dW) * m.sin(self.angle) posy -= (d71 / 2 - dW) * m.cos(self.angle) - dW size_pad = pcbnew.wxSize(d71, w) self.module.Add( Layout.smdRectPad(self.module, pcbnew.wxSize(w, d71), pcbnew.wxPoint(0, 0), "1", 0, self.net)) # Alignment pad self.module.Add( Layout.smdRectPad(self.module, size_pad, pcbnew.wxPoint(posx, posy), "1", (self.angle_deg - 90) * 10, self.net)) self.module.Rotate(self.module.GetPosition(), (90 + self.angle_deg) * 100) # self.module.MoveAnchorPosition(pcbnew.wxPoint((d71/2 - a - w/2)*m.sin(self.angle), \ # (d71/2 - a - w/2)*m.cos(self.angle))) self.module.SetPosition(center) if self.layer == pcbnew.B_Cu: self.module.Flip(self.module.GetCenter()) elif self.layer == pcbnew.F_Cu: self.module.Rotate(self.module.GetPosition(), (90 + self.angle_deg) * 100) # Find center of bounding box for placement # Add to Pcbnew pcbnew.GetBoard().Add(self.module) pcbnew.Refresh()