def flatten(self, color=None, alpha=None): if self.isOutline == True and self._render_count == 1: # outline layer # reconstruct the contour (the original lines go in no particular order) curPoint = self.lineList[0] countourPoints = [] for i in range(1000): countourPoints.append([curPoint[0][0], curPoint[0][1], curPoint[2]]) dist = sys.float_info.max # find the closest point among the for ll in self.lineList: llinv = [ll[1], ll[0], ll[2]] if ll == curPoint or llinv == curPoint: continue d = (ll[0][0] - curPoint[1][0])**2 + (ll[0][1] - curPoint[1][1])**2 if d < dist: dist = d nextCurPoint = ll d = (ll[1][0] - curPoint[1][0])**2 + (ll[1][1] - curPoint[1][1])**2 if d < dist: dist = d nextCurPoint = llinv if dist < 1.e-4: break if nextCurPoint[0] in countourPoints: break curPoint = nextCurPoint # draw the filled contour with self._new_mask() as mask: mask.ctx.move_to(countourPoints[0][0], countourPoints[0][1]) wasArc = False for ll in countourPoints: if ll[2]: arc = ll[2] center = self.scale_point(arc.center) radius = self.scale[0] * arc.radius two_pi = 2 * math.pi angle1 = (arc.start_angle + two_pi) % two_pi angle2 = (arc.end_angle + two_pi) % two_pi if arc.direction == 'counterclockwise': mask.ctx.arc(center[0], center[1], radius, angle1, angle2) else: mask.ctx.arc_negative(center[0], center[1], radius, angle1, angle2) else: mask.ctx.line_to(ll[0], ll[1]) mask.ctx.set_source_rgba(1.0, 1.0, 1.0, 1.0) mask.ctx.fill() self.ctx.mask_surface(mask.surface, 0.0, 0.0) GerberCairoContext.flatten(self, color, alpha)
class PcbGui(tk.Frame): def __init__(self, master=None): super().__init__(master) self.master = master self.pack() self.ctx = GerberCairoContext(8) self.ctx.units = 'metric' self.layers = {} self.components = [] # self.components = self.load_pickplace() self.layer = "TopLayer" # self.geometry("{}x{}".format(self._image_ref.width(), self._image_ref.height())) self.clist = ComponentListGui(self) # self.clist.add_components(self.components, self.layer) self.clist.pack(expand=True, side="right") self.label = tk.Label(self) self.label.pack(expand=True, side="left") # self.draw_component() self.bind('<ButtonRelease-1>', self.draw_component) def select_gerber_folder(self): dir = tk.filedialog.askdirectory(title="Select folder with Gerbers") self.layers = {} for infile in listdir(dir): path = os.path.join(dir, infile) if infile.lower().endswith('gbl'): self.layers['gbl'] = gerber.load_layer(path) if infile.lower().endswith('gtl'): self.layers['gtl'] = gerber.load_layer(path) if infile.lower().endswith('gtp'): self.layers['gtp'] = gerber.load_layer(path) self.draw_component() def set_layer(self, layer): self.layer = layer self.draw_component() self.clist.add_components(self.components, self.layer) def menubar(self, root): menubar = tk.Menu(root) pageMenu = tk.Menu(menubar) pageMenu.add_command(label="Open Gerber folder", command=self.select_gerber_folder) pageMenu.add_command(label="Open pick and place file", command=self.load_pickplace) menubar.add_cascade(label="File", menu=pageMenu) layerMenu = tk.Menu(menubar) layerMenu.add_radiobutton(label="Top Layer", command=lambda: self.set_layer("TopLayer")) layerMenu.add_radiobutton( label="Bottom Layer", command=lambda: self.set_layer("BottomLayer")) menubar.add_cascade(label="Layer", menu=layerMenu) helpMenu = tk.Menu(menubar, name="help") helpMenu.add_command(label="About") menubar.add_cascade(label="Help", menu=helpMenu) return menubar # def load_gerber(self): # self.layers = {} # self.layers.append(gerber.load_layer('example.GTL')) # self.ctx.render_layers(layers, buffer, max_width=self.w, max_height=self.h, verbose=True) def draw_component(self, event=None): self.ctx.clear() if len(self.layers) > 0: if self.layer == "TopLayer": copper_settings = RenderSettings(color=theme.COLORS['black'], alpha=0.8, mirror=False) self.ctx.render_layer(self.layers["gtl"], settings=copper_settings, verbose=True) self.ctx.new_render_layer(mirror=False) if self.layer == "BottomLayer": copper_settings = RenderSettings(color=theme.COLORS['black'], alpha=0.8, mirror=True) self.ctx.render_layer(self.layers["gbl"], settings=copper_settings) self.ctx.new_render_layer(mirror=True) self.ctx._color = (1.0, 0.0, 1.0) layer = self.layer if self.clist.tb.selected_row != None: part_number = self.clist.tb.selected_row['PN'] else: part_number = None for c in self.components: if (c['layer'] == layer) and (c['part_number'] == part_number): print("{} {}".format(c['x_mm'], c['y_mm'])) self.ctx.render( gerber.primitives.Circle((c['x_mm'], c['y_mm']), 1)) self.ctx.flatten() buffer = BytesIO() self.ctx.dump(buffer) img = ImageTk.PhotoImage(Image.open(buffer)) self.label.configure(image=img) self.label.image = img def load_pickplace(self): filename = tk.filedialog.askopenfilename( title="Select pick and place file") components = [] filetype = "Kicad" with open(filename, "r") as ppfile: header_read = False for line in ppfile: line = shlex.split(line) if len(line) > 0: if header_read == False: # Try to determine the file type based on the contents if line[0] == "Altium": filetype = "Altium" if line[0] == "Designator" or line[0] == "#": header_read = True else: if filetype == "Altium": component = {} component['designator'] = line[0] component['part_number'] = line[1] component['x_mm'] = float(line[4][:-2]) component['y_mm'] = float(line[5][:-2]) component['layer'] = line[2] component['description'] = line[7] components.append(component) elif filetype == "Kicad": if len(line) > 6: print(line) component = {} component['designator'] = line[0] component['part_number'] = line[1] component['x_mm'] = float(line[3]) component['y_mm'] = float(line[4]) component['layer'] = "TopLayer" if line[ 6] == "top" else "BottomLayer" if component['layer'] == "BottomLayer": component['x_mm'] *= -1 component['description'] = line[2] components.append(component) self.components = components self.clist.add_components(self.components, self.layer)