def separate(input, output, source, debug): """ Separate a single board out of a multi-board design. The separated board is placed in the middle of the sheet. You can specify the board via bounding box or annotation. See documentation for further details on usage. """ try: from kikit import panelize_ui_impl as ki from kikit.panelize import Panel from pcbnew import LoadBoard, wxPointMM preset = ki.obtainPreset([], validate=False, source=source, debug=debug) board = LoadBoard(input) sourceArea = ki.readSourceArea(preset["source"], board) panel = Panel() panel.inheritDesignSettings(input) panel.inheritProperties(input) destination = wxPointMM(150, 100) panel.appendBoard(input, destination, sourceArea) panel.save(output) except Exception as e: sys.stderr.write("An error occurred: " + str(e) + "\n") sys.stderr.write("No output files produced\n") if isinstance(preset, dict) and preset["debug"]["trace"]: traceback.print_exc(file=sys.stderr) sys.exit(1)
def separate(input, output, source, page, debug, keepannotations): """ Separate a single board out of a multi-board design. The separated board is placed in the middle of the sheet. You can specify the board via bounding box or annotation. See documentation for further details on usage. """ try: from kikit import panelize_ui_impl as ki from kikit.panelize import Panel from pcbnewTransition.transition import isV6, pcbnew from pcbnew import LoadBoard, wxPointMM from kikit.common import fakeKiCADGui app = fakeKiCADGui() preset = ki.obtainPreset([], validate=False, source=source, page=page, debug=debug) if preset["debug"]["deterministic"] and isV6(): pcbnew.KIID.SeedGenerator(42) board = LoadBoard(input) sourceArea = ki.readSourceArea(preset["source"], board) panel = Panel(output) panel.inheritDesignSettings(board) panel.inheritProperties(board) panel.inheritTitleBlock(board) destination = wxPointMM(150, 100) panel.appendBoard(input, destination, sourceArea, interpretAnnotations=(not keepannotations)) ki.setStackup(preset["source"], panel) ki.positionPanel(preset["page"], panel) ki.setPageSize(preset["page"], panel, board) panel.save(reconstructArcs=True) except Exception as e: import sys sys.stderr.write("An error occurred: " + str(e) + "\n") sys.stderr.write("No output files produced\n") if isinstance(preset, dict) and preset["debug"]["trace"]: traceback.print_exc(file=sys.stderr) sys.exit(1)
def place_switches(c): OFFSET = wxPoint(FromMM(100), FromMM(50)) KEY_DISTANCE = 19.05 b = LoadBoard(KICAD_PCB) for row in range(5): for col in range(6): i = col + 6 * row + 1 m = b.FindModuleByReference(f"SW{i}") x = FromMM(KEY_DISTANCE * col) y = FromMM(KEY_DISTANCE) * row m.SetPosition(wxPoint(x, y) + OFFSET) m = b.FindModuleByReference(f"D{i}") x = FromMM(KEY_DISTANCE) * col + FromMM(KEY_DISTANCE) / 2 y = FromMM(KEY_DISTANCE) * row m.SetPosition(wxPoint(x, y) + OFFSET) m.SetOrientation(270 * 10) b.Save(b.GetFileName())
def appendBoard(self, filename, destination, sourceArea=None, origin=Origin.Center, rotationAngle=0, shrink=False, tolerance=0, bufferOutline=fromMm(0.001), netRenamer=None, refRenamer=None): """ Appends a board to the panel. The sourceArea (wxRect) of the board specified by filename is extracted and placed at destination (wxPoint). The source area (wxRect) can be auto detected if it is not provided. Only board items which fit entirely into the source area are selected. You can also specify rotation. Both translation and rotation origin are specified by origin. Origin specifies which point of the sourceArea is used for translation and rotation (origin it is placed to destination). It is possible to specify coarse source area and automatically shrink it if shrink is True. Tolerance enlarges (even shrinked) source area - useful for inclusion of filled zones which can reach out of the board edges. You can also specify functions which will rename the net and ref names. By default, nets are renamed to "Board_{n}-{orig}", refs are unchanged. The renamers are given board seq number and original name Returns bounding box (wxRect) of the extracted area placed at the destination and the extracted substrate of the board. """ board = LoadBoard(filename) thickness = board.GetDesignSettings().GetBoardThickness() if self.boardCounter == 0: self.board.GetDesignSettings().SetBoardThickness(thickness) else: panelThickness = self.board.GetDesignSettings().GetBoardThickness() if panelThickness != thickness: raise PanelError(f"Cannot append board {filename} as its " \ f"thickness ({toMm(thickness)} mm) differs from " \ f"thickness of the panel ({toMm(panelThickness)}) mm") self.boardCounter += 1 self.inheritCopperLayers(board) if not sourceArea: sourceArea = findBoardBoundingBox(board) elif shrink: sourceArea = findBoardBoundingBox(board, sourceArea) enlargedSourceArea = expandRect(sourceArea, tolerance) originPoint = getOriginCoord(origin, sourceArea) translation = wxPoint(destination[0] - originPoint[0], destination[1] - originPoint[1]) if netRenamer is None: netRenamer = lambda x, y: self._uniquePrefix() + y renameNets(board, lambda x: netRenamer(self.boardCounter, x)) if refRenamer is not None: renameRefs(board, lambda x: refRenamer(self.boardCounter, x)) drawings = collectItems(board.GetDrawings(), enlargedSourceArea) footprints = collectFootprints(board.GetFootprints(), enlargedSourceArea) tracks = collectItems(board.GetTracks(), enlargedSourceArea) zones = collectItems(board.Zones(), enlargedSourceArea) edges = [] for footprint in footprints: footprint.Rotate(originPoint, rotationAngle) footprint.Move(translation) edges += removeCutsFromFootprint(footprint) appendItem(self.board, footprint) for track in tracks: track.Rotate(originPoint, rotationAngle) track.Move(translation) appendItem(self.board, track) for zone in zones: zone.Rotate(originPoint, rotationAngle) zone.Move(translation) appendItem(self.board, zone) for netId in board.GetNetInfo().NetsByNetcode(): self.board.Add(board.GetNetInfo().GetNetItem(netId)) # Treat drawings differently since they contains board edges for drawing in drawings: drawing.Rotate(originPoint, rotationAngle) drawing.Move(translation) edges += [edge for edge in drawings if isBoardEdge(edge)] otherDrawings = [edge for edge in drawings if not isBoardEdge(edge)] try: s = Substrate(edges, bufferOutline) self.boardSubstrate.union(s) self.substrates.append(s) except substrate.PositionError as e: point = undoTransformation(e.point, rotationAngle, originPoint, translation) raise substrate.PositionError(filename + ": " + e.origMessage, point) for drawing in otherDrawings: appendItem(self.board, drawing) return findBoundingBox(edges)
def appendBoard(self, filename, destination, sourceArea=None, origin=Origin.Center, rotationAngle=0, shrink=False, tolerance=0): """ Appends a board to the panel. The sourceArea (wxRect) of the board specified by filename is extracted and placed at destination (wxPoint). The source area (wxRect) can be auto detected if it is not provided. Only board items which fit entirely into the source area are selected. You can also specify rotation. Both translation and rotation origin are specified by origin. Origin specifies which point of the sourceArea is used for translation and rotation (origin it is placed to destination). It is possible to specify coarse source area and automatically shrink it if shrink is True. Tolerance enlarges (even shrinked) source area - useful for inclusion of filled zones which can reach out of the board edges. Returns bounding box (wxRect) of the extracted area placed at the destination. """ board = LoadBoard(filename) self.boardCounter += 1 if not sourceArea: sourceArea = findBoardBoundingBox(board) elif shrink: sourceArea = findBoardBoundingBox(board, sourceArea) tightSourceArea = findBoardBoundingBox( board, expandRect(sourceArea, fromMm(1))) enlargedSourceArea = expandRect(sourceArea, tolerance) originPoint = getOriginCoord(origin, sourceArea) translation = wxPoint(destination[0] - originPoint[0], destination[1] - originPoint[1]) tightSourceArea = translateRect(tightSourceArea, translation) self._makeNetNamesUnique(board) drawings = collectItems(board.GetDrawings(), enlargedSourceArea) modules = collectItems(board.GetModules(), enlargedSourceArea) tracks = collectItems(board.GetTracks(), enlargedSourceArea) zones = collectItems(board.Zones(), enlargedSourceArea) for module in modules: module.Rotate(originPoint, rotationAngle) module.Move(translation) appendItem(self.board, module) for track in tracks: track.Rotate(originPoint, rotationAngle) track.Move(translation) appendItem(self.board, track) for zone in zones: zone.Rotate(originPoint, rotationAngle) zone.Move(translation) appendItem(self.board, zone) for netId in board.GetNetInfo().NetsByNetcode(): self.board.Add(board.GetNetInfo().GetNetItem(netId)) # Treat drawings differently since they contains board edges for drawing in drawings: drawing.Rotate(originPoint, rotationAngle) drawing.Move(translation) edges = [ edge for edge in drawings if edge.GetLayerName() == "Edge.Cuts" ] otherDrawings = [ edge for edge in drawings if edge.GetLayerName() != "Edge.Cuts" ] self.boardSubstrate.union(Substrate(edges)) for drawing in otherDrawings: appendItem(self.board, drawing) return tightSourceArea
Edge_Cuts as Cutout, wxPoint as wxPt, FromMils, FromMM from os import path as pt import re # generate vectors from dimensions step_vector = wxPt(Units(step_x), Units(step_y)) offset_vector = wxPt(Units(offset_x), Units(offset_y)) center = wxPt(Units(center_x), Units(center_y)) # derived file names fileNameSave = "%s-panelized.%s" % tuple(fileNamePCB.rsplit('.', 1)) fileNameCommonParts = "%s-panel-common.%s" % tuple(fileNamePCB.rsplit('.', 1)) # load PCB print("Reading file: '%s'\n" % fileNamePCB) pcb = LoadBoard(fileNamePCB) print("\n") # get all items lsItems = brdItemize(pcb) # delete original items for Item in lsItems: pcb.Remove(Item) boardcount = 0 # global variable is fine here for counting boards # instantiate boards @ different rotations for angle in angles: pcb_instanciate_multiple_boards(pcb, lsItems, nx, ny, step_vector,
def panelize(input, output, preset, layout, source, tabs, cuts, framing, tooling, fiducials, text, post, debug, dump): """ Panelize boards """ try: # Hide the import in the function to make KiKit start faster from kikit import panelize_ui_impl as ki from kikit.panelize import Panel from pcbnew import LoadBoard, wxPointMM import json import commentjson import sys from itertools import chain preset = ki.obtainPreset(preset, layout=layout, source=source, tabs=tabs, cuts=cuts, framing=framing, tooling=tooling, fiducials=fiducials, text=text, post=post, debug=debug) board = LoadBoard(input) panel = Panel() panel.inheritDesignSettings(input) panel.inheritProperties(input) sourceArea = ki.readSourceArea(preset["source"], board) substrates = ki.buildLayout(preset["layout"], panel, input, sourceArea) framingSubstrates = ki.dummyFramingSubstrate( substrates, ki.frameOffset(preset["framing"])) panel.buildPartitionLineFromBB(framingSubstrates) tabCuts = ki.buildTabs(preset["tabs"], panel, substrates, framingSubstrates) backboneCuts = ki.buildBackBone(preset["layout"], panel, substrates, ki.frameOffset(preset["framing"])) frameCuts = ki.buildFraming(preset["framing"], panel) ki.buildTooling(preset["tooling"], panel) ki.buildFiducials(preset["fiducials"], panel) ki.buildText(preset["text"], panel) ki.buildPostprocessing(preset["post"], panel) ki.makeTabCuts(preset["cuts"], panel, tabCuts) ki.makeOtherCuts(preset["cuts"], panel, chain(backboneCuts, frameCuts)) ki.runUserScript(preset["post"], panel) ki.buildDebugAnnotation(preset["debug"], panel) panel.save(output) if (dump): with open(dump, "w") as f: f.write(ki.dumpPreset(preset)) except Exception as e: import sys sys.stderr.write("An error occurred: " + str(e) + "\n") sys.stderr.write("No output files produced\n") if isinstance(preset, dict) and preset["debug"]["trace"]: traceback.print_exc(file=sys.stderr) sys.exit(1)
def processBoard(boardName, plotDir, quiet): '''Load board and initialize plot controller''' board = LoadBoard(boardName) boardbox = board.ComputeBoundingBox() boardxl = boardbox.GetX() boardyl = boardbox.GetY() boardwidth = boardbox.GetWidth() boardheight = boardbox.GetHeight() if not quiet: print(boardxl, boardyl, boardwidth, boardheight) pctl = PLOT_CONTROLLER(board) pctl.SetColorMode(True) popt = pctl.GetPlotOptions() popt.SetOutputDirectory(plotDir) popt.SetPlotFrameRef(False) popt.SetLineWidth(FromMM(0.15)) popt.SetAutoScale(False) popt.SetScale(2) popt.SetMirror(False) popt.SetUseGerberAttributes(True) popt.SetExcludeEdgeLayer(False) popt.SetUseAuxOrigin(True) layers = [ ("F_Cu", F_Cu, "Top copper"), ("In1_Cu", In1_Cu, "Inner1 copper"), ("In2_Cu", In2_Cu, "Inner2 copper"), ("In3_Cu", In3_Cu, "Inner3 copper"), ("In4_Cu", In4_Cu, "Inner4 copper"), ("B_Cu", B_Cu, "Bottom copper"), ("F_Adhes", F_Adhes, "Adhesive top"), ("B_Adhes", B_Adhes, "Adhesive bottom"), ("F_Paste", F_Paste, "Paste top"), ("B_Paste", B_Paste, "Paste bottom"), ("F_SilkS", F_SilkS, "Silk top"), ("B_SilkS", B_SilkS, "Silk top"), ("F_Mask", F_Mask, "Mask top"), ("B_Mask", B_Mask, "Mask bottom"), ("Dwgs_User", Dwgs_User, "User drawings"), ("Cmts_User", Cmts_User, "User comments"), ("Eco1_User", Eco1_User, "Eng change order 1"), ("Eco2_User", Eco2_User, "Eng change order 1"), ("Edge_Cuts", Edge_Cuts, "Edges"), ("Margin", Margin, "Margin"), ("F_CrtYd", F_CrtYd, "Courtyard top"), ("B_CrtYd", B_CrtYd, "Courtyard bottom"), ("F_Fab", F_Fab, "Fab top"), ("B_Fab", B_Fab, "Fab bottom") ] for layer_info in layers: pctl.SetLayer(layer_info[1]) pctl.OpenPlotfile(layer_info[0], PLOT_FORMAT_SVG, layer_info[2]) layer_name = board.GetLayerName(layer_info[1]).replace(".", "_") if layer_info[0] != layer_name: pctl.OpenPlotfile(layer_name, PLOT_FORMAT_SVG, layer_info[2]) pctl.PlotLayer() return (boardxl, boardyl, boardwidth, boardheight)
def doPanelization(input, output, preset, plugins=[]): """ The panelization logic is separated into a separate function so we can handle errors based on the context; e.g., CLI vs GUI """ from kikit import panelize_ui_impl as ki from kikit.panelize import Panel from pcbnewTransition.transition import isV6, pcbnew from pcbnew import LoadBoard from itertools import chain if preset["debug"]["deterministic"] and isV6(): pcbnew.KIID.SeedGenerator(42) if preset["debug"]["drawtabfail"]: import kikit.substrate kikit.substrate.TABFAIL_VISUAL = True board = LoadBoard(input) panel = Panel(output) useHookPlugins = ki.loadHookPlugins(plugins, board, preset) useHookPlugins(lambda x: x.prePanelSetup(panel)) # Register extra footprints for annotations for tabFootprint in preset["tabs"]["tabfootprints"]: panel.annotationReader.registerTab(tabFootprint.lib, tabFootprint.footprint) panel.inheritDesignSettings(board) panel.inheritProperties(board) panel.inheritTitleBlock(board) useHookPlugins(lambda x: x.afterPanelSetup(panel)) sourceArea = ki.readSourceArea(preset["source"], board) substrates, framingSubstrates, backboneCuts = \ ki.buildLayout(preset, panel, input, sourceArea) useHookPlugins(lambda x: x.afterLayout(panel, substrates)) tabCuts = ki.buildTabs(preset, panel, substrates, framingSubstrates, ki.frameOffset(preset["framing"])) useHookPlugins(lambda x: x.afterTabs(panel, tabCuts, backboneCuts)) frameCuts = ki.buildFraming(preset, panel) useHookPlugins(lambda x: x.afterFraming(panel, frameCuts)) ki.buildTooling(preset, panel) ki.buildFiducials(preset, panel) ki.buildText(preset["text"], panel) ki.buildPostprocessing(preset["post"], panel) ki.makeTabCuts(preset, panel, tabCuts) ki.makeOtherCuts(preset, panel, chain(backboneCuts, frameCuts)) useHookPlugins(lambda x: x.afterCuts(panel)) ki.buildCopperfill(preset["copperfill"], panel) ki.setStackup(preset["source"], panel) ki.positionPanel(preset["page"], panel) ki.setPageSize(preset["page"], panel, board) ki.runUserScript(preset["post"], panel) useHookPlugins(lambda x: x.finish(panel)) ki.buildDebugAnnotation(preset["debug"], panel) panel.save(reconstructArcs=preset["post"]["reconstructarcs"], refillAllZones=preset["post"]["refillzones"])
#!/usr/bin/env python import sys import transparency import drill import gerbers import images from common import maybe_create_dir from pcbnew import LoadBoard try: filename = sys.argv[1] except IndexError: print 'kicad_pcb source is required' sys.exit(1) maybe_create_dir('outputs') transparency.generate(LoadBoard(filename), 'outputs/pdf/') drill.generate(LoadBoard(filename), 'outputs/drill/') gerbers.generate(LoadBoard(filename), 'outputs/gerbers/') images.generate('outputs/gerbers/', 'outputs/images/')