def BuildFootprint(self): """ Actually make the footprint. We defer all but the setup to the implmenting class """ self.module = pcbnew.MODULE(None) # create a new module # do it first, so if we return early, we don't segfault KiCad if not self.ProcessParameters(): return self.draw = FootprintWizardDrawingAids.FootprintWizardDrawingAids( self.module) self.module.SetValue(self.GetValue()) self.module.SetReference("%s**" % self.GetReferencePrefix()) fpid = pcbnew.FPID(self.module.GetValue()) # the name in library self.module.SetFPID(fpid) self.SetModule3DModel() # add a 3d module if specified thick = self.GetTextThickness() self.module.Reference().SetThickness(thick) self.module.Value().SetThickness(thick) self.BuildThisFootprint() # implementer's build function
def new_module(self, reference, position=(0, 0)): """Create new module on the board""" module = pcbnew.MODULE(self._board) module.SetReference(reference) module.SetPosition(_to_wxpoint(position[0], position[1])) self._board.Add(module) return Module(module)
def copy_module(self, original, reference, position=(0, 0)): """Create a copy of an existing module on the board""" module = pcbnew.MODULE(self._board) module.Copy(original._module) module.SetReference(reference) module.SetPosition(_to_wxpoint(position[0], position[1])) self._board.Add(module) return Module(module)
def __call__(self, entity): """ :param entity: :type entity: DXFEntity :return: """ if isinstance(entity, Circle) and entity.dxftype == "CIRCLE": # Create a new module from the footprint fp = pcbnew.MODULE(self.footprint) fp.SetPosition(pcbpoint(entity.center).wxpoint()) self.board.Add(fp) elif isinstance(entity, LWPolyline) and entity.dxftype == "LWPOLYLINE": angle = -longest_angle_for_polygon(entity.points) fp = pcbnew.MODULE(self.footprint) fp.SetPosition(pcbpoint(centeroidnp(entity.points)).wxpoint()) fp.SetOrientation(angle * 10) self.board.Add(fp)
def hole_module(board, size, drill_size, pos, net, pad_type="round"): pos = pcbnew.wxPoint(pos[0], pos[1]) main_hole_size_wx = pcbnew.wxSize(size, size) main_hole_drill_size_wx = pcbnew.wxSize(drill_size, drill_size) module = pcbnew.MODULE(board) module.SetPosition(pos) hole_pad(board, module, main_hole_size_wx, main_hole_drill_size_wx, pos, net, pad_type) board.Add(module)
def BuildFootprint(self): """! Actually make the footprint. We defer all but the set-up to the implementing class """ self.buildmessages = "" self.module = pcbnew.MODULE(None) # create a new module # Perform default checks on all parameters for p in self.params: p.ClearErrors() p.Check() # use defaults self.CheckParameters() # User error checks if self.AnyErrors(): # Errors were detected! self.buildmessages = ("Cannot build footprint: " "Parameters have errors:\n") for p in self.params: if len(p.error_list) > 0: self.buildmessages += "['{page}']['{name}']:\n".format( page=p.page, name=p.name) for error in p.error_list: self.buildmessages += "\t" + error + "\n" return self.buildmessages = ( "Building new {name} footprint with the following parameters:\n". format(name=self.name)) self.buildmessages += self.Show() self.draw = FootprintWizardDrawingAids(self.module) self.module.SetValue(self.GetValue()) self.module.SetReference("%s**" % self.GetReferencePrefix()) fpid = pcbnew.LIB_ID("", self.module.GetValue() ) # the lib name (empty) and the name in library self.module.SetFPID(fpid) self.SetModule3DModel() # add a 3D module if specified thick = self.GetTextThickness() self.module.Reference().SetThickness(thick) self.module.Value().SetThickness(thick) self.BuildThisFootprint() # implementer's build function return
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 get_via_module(board, drill, diameter, net): n = 'VIA-{}-{}'.format(fmt(drill), fmt(diameter)) # instantiate new module m = pcbnew.MODULE(board) m.SetReference('REF**') m.SetValue(n) m.SetLastEditTime(pcbnew.GetNewTimeStamp()) # adjust reference and value display settings r = m.Reference() r.SetVisible(False) r.SetTextSize(pcbnew.wxSize(mm2kicad(0.3), mm2kicad(0.3))) r.SetThickness(mm2kicad(0.075)) v = m.Value() v.SetVisible(False) v.SetTextSize(pcbnew.wxSize(mm2kicad(0.3), mm2kicad(0.3))) v.SetThickness(mm2kicad(0.075)) #v.SetLayer() # TODO: Move value to F.Fab layer (F.SilkS is default) lib_id = pcbnew.LIB_ID(n) m.SetFPID(lib_id) # create through-hole pad pad = pcbnew.D_PAD(m) pad.SetPadName('1') pad.SetNet(net) pad.SetPosition(pcbnew.wxPoint(0, 0)) pad.SetShape(pcbnew.PAD_SHAPE_CIRCLE) pad.SetSize(pcbnew.wxSize(diameter, diameter)) pad.SetDrillShape(pcbnew.PAD_DRILL_SHAPE_CIRCLE) pad.SetDrillSize(pcbnew.wxSize(drill, drill)) pad.SetLayerSet(pcbnew.LSET.AllCuMask()) pad.SetZoneConnection(pcbnew.PAD_ZONE_CONN_FULL) # add pad to module m.Add(pad) return m
def BuildFootprint(self): """ Actually make the footprint. We defer all but the setup to the implementing class """ self.buildmessages = "" 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(): self.buildmessages = "Cannot build footprint: Parameters have errors:\n" self.buildmessages += self._PrintParameterErrors() return self.buildmessages = ( "Building new %s footprint with the following parameters:\n" % self.name) self.buildmessages += self._PrintParameterTable() self.draw = FootprintWizardDrawingAids.FootprintWizardDrawingAids( self.module) self.module.SetValue(self.GetValue()) self.module.SetReference("%s**" % self.GetReferencePrefix()) fpid = pcbnew.LIB_ID(self.module.GetValue()) # the name in library self.module.SetFPID(fpid) self.SetModule3DModel() # add a 3d module if specified thick = self.GetTextThickness() self.module.Reference().SetThickness(thick) self.module.Value().SetThickness(thick) self.BuildThisFootprint() # implementer's build function return
def parse_footprints(self): # type: (list) -> list footprints = [] for f in self.footprints: ref = f.GetReference() # bounding box if hasattr(pcbnew, 'MODULE'): f_copy = pcbnew.MODULE(f) else: f_copy = pcbnew.FOOTPRINT(f) f_copy.SetOrientation(0) f_copy.SetPosition(pcbnew.wxPoint(0, 0)) mrect = f_copy.GetFootprintRect() bbox = { "pos": self.normalize(f.GetPosition()), "relpos": self.normalize(mrect.GetPosition()), "size": self.normalize(mrect.GetSize()), "angle": f.GetOrientation() * 0.1, } # graphical drawings drawings = [] for d in f.GraphicalItems(): # we only care about copper ones, silkscreen is taken care of if d.GetLayer() not in [pcbnew.F_Cu, pcbnew.B_Cu]: continue drawing = self.parse_drawing(d) if not drawing: continue drawings.append({ "layer": "F" if d.GetLayer() == pcbnew.F_Cu else "B", "drawing": drawing, }) # footprint pads pads = [] for p in f.Pads(): pad_dict = self.parse_pad(p) if pad_dict is not None: pads.append((p.GetPadName(), pad_dict)) if pads: # Try to guess first pin name. pads = sorted(pads, key=lambda el: el[0]) pin1_pads = [p for p in pads if p[0] in ['1', 'A', 'A1', 'P1', 'PAD1']] if pin1_pads: pin1_pad_name = pin1_pads[0][0] else: # No pads have common first pin name, pick lexicographically smallest. pin1_pad_name = pads[0][0] for pad_name, pad_dict in pads: if pad_name == pin1_pad_name: pad_dict['pin1'] = 1 pads = [p[1] for p in pads] # add footprint footprints.append({ "ref": ref, "bbox": bbox, "pads": pads, "drawings": drawings, "layer": { pcbnew.F_Cu: "F", pcbnew.B_Cu: "B" }.get(f.GetLayer()) }) return footprints
def parse_modules(self, pcb_modules): # type: (list) -> list modules = [] for m in pcb_modules: # type: pcbnew.MODULE ref = m.GetReference() # bounding box m_copy = pcbnew.MODULE(m) m_copy.SetOrientation(0) m_copy.SetPosition(pcbnew.wxPoint(0, 0)) mrect = m_copy.GetFootprintRect() bbox = { "pos": self.normalize(m.GetPosition()), "relpos": self.normalize(mrect.GetPosition()), "size": self.normalize(mrect.GetSize()), "angle": m.GetOrientation() * 0.1, } # graphical drawings drawings = [] for d in m.GraphicalItems(): # we only care about copper ones, silkscreen is taken care of if d.GetLayer() not in [pcbnew.F_Cu, pcbnew.B_Cu]: continue drawing = self.parse_drawing(d) if not drawing: continue drawings.append({ "layer": "F" if d.GetLayer() == pcbnew.F_Cu else "B", "drawing": drawing, }) # footprint pads pads = [] for p in m.Pads(): pad_dict = self.parse_pad(p) if pad_dict is not None: pads.append((p.GetPadName(), pad_dict)) # If no pads have common 'first' pad name pick lexicographically. pin1_pads = [p for p in pads if 'pin1' in p[1]] if pads and not pin1_pads: pads = sorted(pads, key=lambda el: el[0]) for pad_name, pad_dict in pads: if pad_name: pad_dict['pin1'] = 1 break pads = [p[1] for p in pads] # add module modules.append({ "ref": ref, "bbox": bbox, "pads": pads, "drawings": drawings, "layer": { pcbnew.F_Cu: "F", pcbnew.B_Cu: "B" }.get(m.GetLayer()) }) return modules
def BuildFootprint(self): if self.has_errors(): print "Cannot build footprint: Parameters have errors:" print self.parameter_errors return print "Building new QFP footprint with the following parameters:" self.print_parameter_table() self.module = pcbnew.MODULE(None) # create a new module pads = self.parameters num_pads = int(pads["Pads"]["*n"]) pad_width = pads["Pads"]["width"] pad_length = pads["Pads"]["length"] pad_pitch = pads["Pads"]["pitch"] pad_horizontal_pitch = pads["Pads"]["horizontal pitch"] pad_vertical_pitch = pads["Pads"]["vertical pitch"] package_width = pads["Package"]["width"] package_height = pads["Package"]["height"] side_length = pad_pitch * ((num_pads / 4) - 1) offsetX = pad_pitch * ((num_pads / 4) - 1) / 2 text_size = pcbnew.wxSize(pcbnew.FromMM(0.8), pcbnew.FromMM(0.8)) self.module.SetReference("QFP %d" % int(num_pads)) self.module.Reference().SetPos0(pcbnew.wxPoint(0, pcbnew.FromMM(-0.8))) self.module.Reference().SetTextPosition( self.module.Reference().GetPos0()) self.module.Reference().SetSize(text_size) self.module.SetValue("U**") self.module.Value().SetPos0(pcbnew.wxPoint(0, pcbnew.FromMM(+0.8))) self.module.Value().SetTextPosition(self.module.Value().GetPos0()) self.module.Value().SetSize(text_size) fpid = pcbnew.FPID(self.module.GetReference()) #the name in library self.module.SetFPID(fpid) pad_size_left_right = pcbnew.wxSize(pad_length, pad_width) pad_size_bottom_top = pcbnew.wxSize(pad_width, pad_length) for cur_pad in range(0, num_pads): side = int( cur_pad / (num_pads / 4)) # 0 -> left, 1 -> bottom, 2 -> right, 3 -> top if side == 0 or side == 2: pad_size = pad_size_left_right pad_pos_x = -(pad_horizontal_pitch / 2) pad_pos_y = (cur_pad % (num_pads / 4)) * pad_pitch - (side_length / 2) if side == 2: pad_pos_x = -pad_pos_x pad_pos_y = -pad_pos_y else: pad_size = pad_size_bottom_top pad_pos_x = (cur_pad % (num_pads / 4)) * pad_pitch - (side_length / 2) pad_pos_y = -(pad_vertical_pitch / 2) if side == 1: pad_pos_y = -pad_pos_y else: pad_pos_x = -pad_pos_x pad_pos = pcbnew.wxPoint(pad_pos_x, pad_pos_y) pad = self.smd_rect_pad(self.module, pad_size, pad_pos, str(cur_pad + 1)) self.module.Add(pad) half_package_width = package_width / 2 half_package_height = package_height / 2 package_pad_height_offset = abs(package_height - side_length) / 2 - pad_pitch package_pad_width_offset = abs(package_width - side_length) / 2 - pad_pitch # Bottom Left Edge, vertical line outline = pcbnew.EDGE_MODULE(self.module) outline.SetWidth(pcbnew.FromMM(0.2)) outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT) outline.SetShape(pcbnew.S_SEGMENT) start = pcbnew.wxPoint(-half_package_width, half_package_height - package_pad_height_offset) end = pcbnew.wxPoint(-half_package_width, half_package_height) outline.SetStartEnd(start, end) self.module.Add(outline) # Bottom Left Edge, horizontal line outline = pcbnew.EDGE_MODULE(self.module) outline.SetWidth(pcbnew.FromMM(0.2)) outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT) outline.SetShape(pcbnew.S_SEGMENT) start = pcbnew.wxPoint(-half_package_width, half_package_height) end = pcbnew.wxPoint(-half_package_width + package_pad_width_offset, half_package_height) outline.SetStartEnd(start, end) self.module.Add(outline) # Bottom Right Edge, vertical line outline = pcbnew.EDGE_MODULE(self.module) outline.SetWidth(pcbnew.FromMM(0.2)) outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT) outline.SetShape(pcbnew.S_SEGMENT) start = pcbnew.wxPoint(half_package_width, half_package_height - package_pad_height_offset) end = pcbnew.wxPoint(half_package_width, half_package_height) outline.SetStartEnd(start, end) self.module.Add(outline) # Bottom Right Edge, horizontal line outline = pcbnew.EDGE_MODULE(self.module) outline.SetWidth(pcbnew.FromMM(0.2)) outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT) outline.SetShape(pcbnew.S_SEGMENT) start = pcbnew.wxPoint(half_package_width, half_package_height) end = pcbnew.wxPoint(half_package_width - package_pad_width_offset, half_package_height) outline.SetStartEnd(start, end) self.module.Add(outline) # Top Right Edge, vertical line outline = pcbnew.EDGE_MODULE(self.module) outline.SetWidth(pcbnew.FromMM(0.2)) outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT) outline.SetShape(pcbnew.S_SEGMENT) start = pcbnew.wxPoint( half_package_width, -half_package_height + package_pad_height_offset) end = pcbnew.wxPoint(half_package_width, -half_package_height) outline.SetStartEnd(start, end) self.module.Add(outline) # Top Right Edge, horizontal line outline = pcbnew.EDGE_MODULE(self.module) outline.SetWidth(pcbnew.FromMM(0.2)) outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT) outline.SetShape(pcbnew.S_SEGMENT) start = pcbnew.wxPoint(half_package_width, -half_package_height) end = pcbnew.wxPoint(half_package_width - package_pad_width_offset, -half_package_height) outline.SetStartEnd(start, end) self.module.Add(outline) # Top Left Edge, straight line outline = pcbnew.EDGE_MODULE(self.module) outline.SetWidth(pcbnew.FromMM(0.2)) outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT) outline.SetShape(pcbnew.S_SEGMENT) start = pcbnew.wxPoint( -half_package_width, -half_package_height + package_pad_height_offset) end = pcbnew.wxPoint(-half_package_width + package_pad_width_offset, -half_package_height) outline.SetStartEnd(start, end) self.module.Add(outline)
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()
def Run(self): """ The entry function of the plugin that is executed on user action """ board = pcbnew.GetBoard() # TODO also aggregate and bin by optional attributes, like tolerances radii = set() circles = [] # TODO don't add an extra hole in same place -> overwrite # get circles drawn on board # TODO maybe include some means of filtering out possible circular board outline drawing_list = board.DrawingsList() for d in drawing_list: if d.GetLayerName() == 'Edge.Cuts': # to gaurd against random stuff being on edge cuts for some reason # causing weird errors assert type( d) == pcbnew.DRAWSEGMENT, 'non-DRAWSEGMENT on Edge.Cuts' if d.GetShapeStr() == 'Circle': # TODO check these are what i want, and don't need modification # w/ thickness or whatever (check using dxf import) r = d.GetRadius() radii.add(r) c = d.GetCenter() circles.append((c.x, c.y, r)) # TODO make optional # how to do? board.RemoveNative(d) # TODO option to use nearest hole in existing library option / next largest # (report error) # TODO easiest way to get available footprints (and their radii?) # TODO option to take a set of target hole sizes (for DFM purposes) # TODO include either global use next largest / next smallest # (maybe ignore locked, and say that, to complement this?) # or let people check for each hole whether they want to use next up or down # TODO option to make new hole components and put in project specific library # TODO include field for library to be saved to (maybe mandatory if this option?) # TODO fail gracefully if board filename is empty (board not saved yet) target_footprint_lib = '.'.join(str(board.GetFileName()).split('.')[:-1]) \ + '.pretty' if not os.path.exists(target_footprint_lib): print('creating project specific footprint library' + \ ' {}'.format(target_footprint_lib)) pcbnew.PCB_IO().FootprintLibCreate(target_footprint_lib) else: print('using footprint library {}'.format(target_footprint_lib)) # make a new footprint for each distinct hole radius we need # save to project specific library by default for r in radii: r_mm = nm_to_mm(r) print('generating footprint for hole of radius {}mm'.format(r_mm)) footprint = pcbnew.MODULE(None) # for non-electronic parts like these footprint.SetAttributes(pcbnew.MOD_VIRTUAL) footprint.SetLastEditTime() footprint.SetKeywords('non-plated through hole NPTH') # TODO it looks like the module itself needs to be specified to be on F.Cu? # how? (see github for example output) # TODO set tags to include non-plated through hole, npth? #footprint.SetDescription('{}mm diameter non-plated through hole') pad = pcbnew.D_PAD(footprint) # other library mounting hole pads seem to have this pad number pad.SetName('1') # TODO does this change the layers and stuff automatically? pad shape? pad.SetAttribute(pcbnew.PAD_ATTRIB_HOLE_NOT_PLATED) pad.SetShape(pcbnew.PAD_SHAPE_CIRCLE) # TODO do i need setsize / setstartend? # size seems to equal (r, r) for existing npth library parts # all holes in KiCad currently have to reside on one of the (external?) # copper layers (F.Cu should be one of these layers. mask the other?) pad.SetLayerSet(pcbnew.D_PAD_UnplatedHoleMask()) # TODO are holes alone actually rendered, or do you need the other stuff? # there seems to be a PAD_DRILL_SHAPE_CIRCLE and PAD_DRILL_SHAPE_OBLONG # but when are they ever not circular? oblong = limited routing? # would advanced circuits do oblong, for instance? #pad.SetDrillShape() # huh??? # TODO why isn't this a single number? what gens (drill X)? # TODO why is x in (size x x) slightly larger than 1.5? pad.SetDrillSize(pcbnew.wxSize(r, r)) footprint.Add(pad) footprint_id = 'R{}mm_NPTH'.format(r_mm) footprint.SetReference(footprint_id) ''' footprint.Reference().SetPosition(pcbnew.wxPoint()1) footprint.Value().SetPosition(pcbnew.wxPoint()1) ''' # aiming for a visible layer that does not translate into manufacture comment_layer_id = get_layer_id_by_name('Cmts.User') footprint.Reference().SetLayer(comment_layer_id) footprint.Value().SetLayer(comment_layer_id) # this is the filename, preceeding .kicad_mod fpid = pcbnew.LIB_ID(footprint_id) footprint.SetFPID(fpid) # seems to work to lock all imports by default footprint.SetLocked(True) print('saving footprint to {}'.format(os.path.join(\ target_footprint_lib, footprint_id + '.kicad_mod'))) pcbnew.PCB_IO().FootprintSave(target_footprint_lib, footprint) for x, y, r_curr in circles: if r == r_curr: f_new = pcbnew.PCB_IO().FootprintLoad( target_footprint_lib, footprint_id) f_new.SetPosition(pcbnew.wxPoint(x, y)) board.Add(f_new)
n = 0 for module in modules: n += 1 newModules = [] i = 0 for sourceModule in modules: # Iterate through each object to be copied for x in range(0, NUM_X): # Iterate through x direction for y in range(0, NUM_Y): # Iterate through y direction i += 1 if ((x != 0) or (y != 0)): # Don't duplicate source object to location newModule = pcbnew.MODULE(sourceModule) newModule.SetPosition( wxPoint(x * boardWidth + sourceModule.GetPosition().x, y * boardHeight + sourceModule.GetPosition().y) ) # Move to correct location newModules.append( newModule) # Add to temporary list of objects if args.verbose: progress(i, n * NUM_X * NUM_Y, 'Positioning modules') # Progress bar if args.verbose: print("\n") i = 0 for module in newModules: # add new objects to board board.Add(module)