From 0b16365ba2ff7343d5b207989e9d62eb911e7aed Mon Sep 17 00:00:00 2001 From: Juan Pablo Caram Date: Thu, 9 Jan 2014 22:14:46 -0500 Subject: [PATCH] View, delete, re-plot items --- camlib.py | 63 ++--- camlib.pyc | Bin 18281 -> 18468 bytes cirkuix.py | 295 +++++++++++++++++++++--- cirkuix.pyc | Bin 0 -> 9442 bytes cirkuix.ui | 643 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 938 insertions(+), 63 deletions(-) create mode 100644 cirkuix.pyc diff --git a/camlib.py b/camlib.py index 442c9d6..f6f8e3c 100644 --- a/camlib.py +++ b/camlib.py @@ -1,4 +1,4 @@ -import cairo +#import cairo #from string import * #from math import * @@ -11,7 +11,7 @@ from numpy import arctan2, Inf, array, sqrt, pi, ceil, sin, cos from matplotlib.figure import Figure # See: http://toblerity.org/shapely/manual.html -from shapely.geometry import Polygon, LineString, Point +from shapely.geometry import Polygon, LineString, Point, LinearRing from shapely.geometry import MultiPoint, MultiPolygon from shapely.geometry import box as shply_box from shapely.ops import cascaded_union @@ -41,7 +41,11 @@ class Geometry: if self.solid_geometry == None: print "Warning: solid_geometry not computed yet." return (0,0,0,0) - return self.solid_geometry.bounds + + if type(self.solid_geometry) == list: + return cascaded_union(self.solid_geometry).bounds + else: + return self.solid_geometry.bounds def size(self): ''' @@ -62,7 +66,7 @@ class Geometry: ''' if boundary == None: boundary = self.solid_geometry.envelope - return boundary.difference(g.solid_geometry) + return boundary.difference(self.solid_geometry) def clear_polygon(self, polygon, tooldia, overlap = 0.15): ''' @@ -340,9 +344,10 @@ class Excellon(Geometry): self.solid_geometry.append(poly) self.solid_geometry = cascaded_union(self.solid_geometry) -class CNCjob: +class CNCjob(Geometry): def __init__(self, units="in", kind="generic", z_move = 0.1, feedrate = 3.0, z_cut = -0.002): + # Options self.kind = kind self.units = units @@ -366,7 +371,8 @@ class CNCjob: self.tooldia = 0 # Output generated by CNCjob.create_gcode_geometry() - self.G_geometry = None + #self.G_geometry = None + self.gcode_parsed = None def generate_from_excellon(self, exobj): ''' @@ -447,7 +453,7 @@ class CNCjob: self.gcode += "G00 Z%.4f\n"%self.z_move # Stop cutting continue - if type(geo) == LineString or type(geo) == LineRing: + if type(geo) == LineString or type(geo) == LinearRing: path = list(geo.coords) self.gcode += t%(0, path[0][0], path[0][1]) # Move to first point self.gcode += "G01 Z%.4f\n"%self.z_cut # Start cutting @@ -469,7 +475,7 @@ class CNCjob: self.gcode += "G00 X0Y0\n" self.gcode += "M05\n" # Spindle stop - def create_gcode_geometry(self): + def gcode_parse(self): steps_per_circ = 20 ''' G-Code parser (from self.gcode). Generates dictionary with @@ -534,7 +540,8 @@ class CNCjob: for code in gobj: current[code] = gobj[code] - self.G_geometry = geometry + #self.G_geometry = geometry + self.gcode_parsed = geometry return geometry def plot(self, tooldia=None, dpi=75, margin=0.1, @@ -555,7 +562,7 @@ class CNCjob: ax.set_ylim(ymin-margin, ymax+margin) if tooldia == 0: - for geo in self.G_geometry: + for geo in self.gcode_parsed: linespec = '--' linecolor = color[geo['kind'][0]][1] if geo['kind'][0] == 'C': @@ -563,7 +570,7 @@ class CNCjob: x, y = geo['geom'].coords.xy ax.plot(x, y, linespec, color=linecolor) else: - for geo in self.G_geometry: + for geo in self.gcode_parsed: poly = geo['geom'].buffer(tooldia/2.0) patch = PolygonPatch(poly, facecolor=color[geo['kind'][0]][0], edgecolor=color[geo['kind'][0]][1], @@ -576,20 +583,13 @@ class CNCjob: color={"T":["#F0E24D", "#B5AB3A"], "C":["#5E6CFF", "#4650BD"]}, alpha={"T":0.3, "C":1.0}): ''' - Plots the G-code job onto the given axes + Plots the G-code job onto the given axes. ''' if tooldia == None: tooldia = self.tooldia - - #fig = Figure(dpi=dpi) - #ax = fig.add_subplot(111) - #ax.set_aspect(1) - #xmin, ymin, xmax, ymax = self.input_geometry_bounds - #ax.set_xlim(xmin-margin, xmax+margin) - #ax.set_ylim(ymin-margin, ymax+margin) if tooldia == 0: - for geo in self.G_geometry: + for geo in self.gcode_parsed: linespec = '--' linecolor = color[geo['kind'][0]][1] if geo['kind'][0] == 'C': @@ -597,13 +597,17 @@ class CNCjob: x, y = geo['geom'].coords.xy axes.plot(x, y, linespec, color=linecolor) else: - for geo in self.G_geometry: + for geo in self.gcode_parsed: poly = geo['geom'].buffer(tooldia/2.0) patch = PolygonPatch(poly, facecolor=color[geo['kind'][0]][0], edgecolor=color[geo['kind'][0]][1], alpha=alpha[geo['kind'][0]], zorder=2) axes.add_patch(patch) + def create_geometry(self): + self.solid_geometry = cascaded_union([geo['geom'] for geo in self.gcode_parsed]) + + def gparse1b(gtext): ''' @@ -650,21 +654,18 @@ def gparse1b(gtext): gcmds.append(cmds) return gcmds -def get_bounds(geometry_sets): +def get_bounds(geometry_set): xmin = Inf ymin = Inf xmax = -Inf ymax = -Inf - #geometry_sets = [self.gerbers, self.excellons] - - for gs in geometry_sets: - for g in gs: - gxmin, gymin, gxmax, gymax = g.solid_geometry.bounds - xmin = min([xmin, gxmin]) - ymin = min([ymin, gymin]) - xmax = max([xmax, gxmax]) - ymax = max([ymax, gymax]) + for gs in geometry_set: + gxmin, gymin, gxmax, gymax = geometry_set[gs].bounds() + xmin = min([xmin, gxmin]) + ymin = min([ymin, gymin]) + xmax = max([xmax, gxmax]) + ymax = max([ymax, gymax]) return [xmin, ymin, xmax, ymax] diff --git a/camlib.pyc b/camlib.pyc index c02cf4a10594e9822e9172ab4b6ba72d46621534..c70f7cecf06992d449f50536e38929b6cfeef6b6 100644 GIT binary patch delta 3771 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 delta 3629 zcmZ`+du*Fm6~EVx?bwN9=Vd3(dr4cTZPKhs+N4?Ys++KtrrRx$)$5eG`5gC4{Yd>e zTgsAkWkb-x)@@fjiVAGfCfI;MG37D3O`U*g4@!juV%o$XmH1<5(ir;_L^!|mCFwxm zFaG76bMHO(yzaT5pLtxq_n5rd`H|mu^@F$6tXTUv>HjEwt({T`gZ`vQ3lXk^+ZZ4URI*3#u{V!)+-lUI|G*m7NF;9OE(&C~qYhIu9)aX}B zzSD|mE38*F1h$ggV%D&t6n!YU(%4wrKx7Aftx^Kv3P_hMk;Ol_oHDYpRAJKE&P1sO zTG^oe9-&)$@FJPP0y2ZKDAvsw5UTLM2b^0Z5lMLy1 zyfbp29`X&ggt0Wjx&e&<7_Hg>QGIQ)HKZzuhD}yEfm?b#^!W7azEw9yR9IgvyN|Sz zS1#x~tW)Lx*bU!I`iiM&38A`~pa5S@Yv$fW+B6CVt7D58#)l+>_FwFu~jN7-qs8c4Rh}%NuGtWL=QKx^yyYTkeB+Cje1UUcf;Do@HhWQI>=tLB*xgW;SW5 zJ^Es}Cp-bEhrrAl$)#AYnj~5s;Akr%pD)(et;)^;NJjv}fN21-X@_DA>=0mFk445K zy&%~j4on$X1XZ=`Z$`pf*%G8@E}gKBE9hp!X3hL;I%z9k)Ar}cQTd)8YPhl&;j$gM z3z|4@w}9FWKq;sIfJ49rpr+Q-KG-;Lz(I9uRgh4~TIrWQdYq098RhVGV(nG{*DNb# z^$4W;3;^M6*V_JWEE2_2Qbgc0Y8NrLi5q+Jb|1?mP2_-ccT#YH z3)M0|OSQ#2BEv@BOsCa6m(vO259;Ce=E#2q8&2ENT?;H-9->@dXz!9&^c(Hnp&DU$ z#KR5|cMGGG`>TfthPtMuZg?)sCY1Z5$j$T|Cef&!wd z_2o@DTDN_3bMGdMApesysbnsbEaXo`aYWc3RSoJa;7fon10I1ZTTml+qMXp%gwre6 z9%tC5oL+v4uWs&i$TRx==$0~=!*NlIy1DcAN!I%WgpUAt2afg`u$JDz5>*f zp!xy4^8fD3Mq+cj6?lo_xTa03pfB&J?|>@>h{=p(-pu7Kh3Il){v>rBWoA?Q!yVOj z3qY@254-I#oAec|K!c+(>Qdc36Y?9y#h!Vmdz6H#p#Rc)sEpf?1wOAw`nJfkI@Nbu zkj>}Q!5+5jD}4>^nr210H*l4r8mvNc!J1h}=4a4z)Khx3uf6O6Xgdu!tGoJ-@I5)3 zPbLbym^~ilx`D%rgZd(7phPl>e9FwKUt;8C{ovqk`LzBy-PAX{ zpT|@e0Tk(r74>fQYvLM<{yk@;+@sG8^_}*$u6;}zv5oKQ;2$MvOD~Z^4#!S{R$Id2Rxn@3NEYP5b*J~8xVS2Vu||ChRfhy(Ka@^*`^6^E8KZ@~Qk{(tgEx zhD7QY0Ji$~xHCG`=SVP3A+nGfdfAbIh<8h1*c1$*4aTl4RxEA;#X&{ylb%t644tFN86ou&pKf(IRnz549zTO~-dK2&# z;I{-^_9;uX5UmHs54Apu)Zm>$NH;wm=_&EkrCuki_=yys9X}`o-=*=js{7lBdQQvO zro>-KX5XM};@e<3&N#;kk>s9bU#LF;dkOGUz|RQyoEc_5Ia@GuS@lDRu+&J*SY|4# zzOKIzi^}WzN3qSW7fAl?;yW=V?-(Ug6##b<@Q(sMDkd7F{T_gnbD~qp{IMmraf3Z& zU&^0`g6)7V{lG+r+b&?fUg_tS__2O{q9YJ(C6ZUpCd_8C>lz<5FwvHzjlIc_3 zxdlrF^ts8pPCiMMG-SWfq(Pxf6>3a<2!J0dP8HnMiIno0DEID>L1&{3$)F56f{yCF Sp%+63s#k^2+vTnDR{t9`@12wY diff --git a/cirkuix.py b/cirkuix.py index b2f4d85..236eeeb 100644 --- a/cirkuix.py +++ b/cirkuix.py @@ -13,18 +13,92 @@ from matplotlib.backends.backend_gtk3agg import FigureCanvasGTK3Agg as FigureCan from camlib import * +class CirkuixObj: + def __init__(self, name, kind): + self.name = name + self.kind = kind + +class CirkuixGerber(CirkuixObj, Gerber): + def __init__(self, name): + Gerber.__init__(self) + CirkuixObj.__init__(self, name, "gerber") + self.fields = [{"name":"plot", + "type":bool, + "value":True, + "get":None, + "set":None, + "onchange":None}, + {}] + +class CirkuixExcellon(CirkuixObj, Excellon): + def __init__(self, name): + Excellon.__init__(self) + CirkuixObj.__init__(self, name, "excellon") + self.options = {"plot": True, + "solid": False, + "multicolored": False} + +class CirkuixCNCjob(CirkuixObj, CNCjob): + def __init__(self, name): + CNCjob.__init__(self) + CirkuixObj.__init__(self, name, "cncjob") + self.options = {"plot": True} + +class CirkuixGeometry(CirkuixObj, Geometry): + def __init__(self, name): + CirkuixObj.__init__(self, name, "geometry") + self.options = {"plot": True, + "solid": False, + "multicolored": False} + +class CirkuixObjForm: + def __init__(self, container, Cobj): + self.Cobj = Cobj + self.container = container + self.fields = {} + + def populate(self): + return + + def save(self): + return + +#class CirkuixGerberForm(CirkuixObjForm) + + +def get_entry_text(entry): + return entry.get_text() + +def get_entry_int(entry): + return int(entry.get_text()) + +def get_entry_float(entry): + return float(entry.get_text()) + +def get_entry_eval(entry): + return eval(entry.get_text) + +getters = {"entry_text":get_entry_text, + "entry_int":get_entry_int, + "entry_float":get_entry_float, + "entry_eval":get_entry_eval} + +setters = {"entry"} + class App: def __init__(self): ######################################## ## GUI ## - ######################################## + ######################################## self.gladefile = "cirkuix.ui" self.builder = Gtk.Builder() self.builder.add_from_file(self.gladefile) self.window = self.builder.get_object("window1") + self.window.set_title("Cirkuix") self.positionLabel = self.builder.get_object("label3") self.grid = self.builder.get_object("grid1") + self.notebook = self.builder.get_object("notebook1") ## Event handling ## self.builder.connect_signals(self) @@ -33,34 +107,36 @@ class App: self.figure = None self.axes = None self.canvas = None - self.mplpaint() + self.plot_setup() + self.setup_component_viewer() + self.setup_component_editor() ######################################## ## DATA ## ######################################## - self.gerbers = [] - self.excellons = [] - self.cncjobs = [] + self.stuff = {} # CirkuixObj's by name self.mouse = None + # What is selected by the user. It is + # a key if self.stuff + self.selected_item_name = None + ######################################## ## START ## ######################################## self.window.show_all() Gtk.main() - def mplpaint(self): + def plot_setup(self): self.figure = Figure(dpi=50) - #self.axes = self.figure.add_subplot(111) self.axes = self.figure.add_axes([0.05,0.05,0.9,0.9]) self.axes.set_aspect(1) #t = arange(0.0,5.0,0.01) #s = sin(2*pi*t) #self.axes.plot(t,s) self.axes.grid() - #a.patch.set_visible(False) Background of the axes self.figure.patch.set_visible(False) self.canvas = FigureCanvas(self.figure) # a Gtk.DrawingArea @@ -76,11 +152,13 @@ class App: self.canvas.mpl_connect('key_press_event', self.on_key_over_plot) self.canvas.mpl_connect('scroll_event', self.on_scroll_over_plot) - #self.builder.get_object("viewport2").add(self.canvas) self.grid.attach(self.canvas,0,0,600,400) - #self.builder.get_object("scrolledwindow1").add(self.canvas) def zoom(self, factor, center=None): + ''' + Zooms the plot by factor around a given + center point. Takes care of re-drawing. + ''' xmin, xmax = self.axes.get_xlim() ymin, ymax = self.axes.get_ylim() width = xmax-xmin @@ -129,6 +207,8 @@ class App: for ints in poly.interiors: x, y = ints.coords.xy self.axes.plot(x, y, linespec) + + self.canvas.queue_draw() def plot_excellon(self, excellon): excellon.create_geometry() @@ -140,31 +220,152 @@ class App: for ints in geo.interiors: x, y = ints.coords.xy self.axes.plot(x, y, 'g-') + + self.canvas.queue_draw() def plot_cncjob(self, job): - job.create_gcode_geometry() + #job.gcode_parse() tooldia_text = self.builder.get_object("entry_tooldia").get_text() tooldia_val = eval(tooldia_text) job.plot2(self.axes, tooldia=tooldia_val) - return - - def file_chooser_action(self, on_success): - dialog = Gtk.FileChooserDialog("Please choose a file", self.window, - Gtk.FileChooserAction.OPEN, - (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, - Gtk.STOCK_OPEN, Gtk.ResponseType.OK)) - response = dialog.run() - if response == Gtk.ResponseType.OK: - on_success(self, dialog.get_filename()) - elif response == Gtk.ResponseType.CANCEL: - print("Cancel clicked") - dialog.destroy() + self.canvas.queue_draw() + def setup_component_viewer(self): + ''' + List or Tree where whatever has been loaded or created is + displayed. + ''' + self.store = Gtk.ListStore(str) + self.tree = Gtk.TreeView(self.store) + select = self.tree.get_selection() + self.signal_id = select.connect("changed", self.on_tree_selection_changed) + renderer = Gtk.CellRendererText() + column = Gtk.TreeViewColumn("Title", renderer, text=0) + self.tree.append_column(column) + self.builder.get_object("notebook1").append_page(self.tree, Gtk.Label("Project")) + + def setup_component_editor(self): + box1 = Gtk.Box(Gtk.Orientation.VERTICAL) + label1 = Gtk.Label("Choose an item from Project") + box1.pack_start(label1, False, False, 1) + self.builder.get_object("notebook1").append_page(box1, Gtk.Label("Selection")) + + def build_list(self): + self.store.clear() + for key in self.stuff: + self.store.append([key]) + + def build_gerber_ui(self): + print "build_gerber_ui()" + osw = self.builder.get_object("offscrwindow_gerber") + box1 = self.builder.get_object("box_gerber") + osw.remove(box1) + self.notebook.append_page(box1, Gtk.Label("Selection")) + gerber = self.stuff[self.selected_item_name] + entry_name = self.builder.get_object("entry_gerbername") + entry_name.set_text(self.selected_item_name) + entry_name.connect("activate", self.on_activate_name) + box1.show() + + def build_excellon_ui(self): + print "build_excellon_ui()" + osw = self.builder.get_object("offscrwindow_excellon") + box1 = self.builder.get_object("box_excellon") + osw.remove(box1) + self.notebook.append_page(box1, Gtk.Label("Selection")) + entry_name = self.builder.get_object("entry_excellonname") + entry_name.set_text(self.selected_item_name) + entry_name.connect("activate", self.on_activate_name) + box1.show() + + def build_cncjob_ui(self): + print "build_cncjob_ui()" + osw = self.builder.get_object("offscrwindow_cncjob") + box1 = self.builder.get_object("box_cncjob") + osw.remove(box1) + self.notebook.append_page(box1, Gtk.Label("Selection")) + entry_name = self.builder.get_object("entry_cncjobname") + entry_name.set_text(self.selected_item_name) + entry_name.connect("activate", self.on_activate_name) + box1.show() + + def plot_all(self): + self.clear_plots() + plotter = {"gerber":self.plot_gerber, + "excellon":self.plot_excellon, + "cncjob":self.plot_cncjob} + + for i in self.stuff: + kind = self.stuff[i].kind + plotter[kind](self.stuff[i]) + + self.on_zoom_fit(None) + self.axes.grid() + self.canvas.queue_draw() + + def clear_plots(self): + self.axes.cla() + self.canvas.queue_draw() + ######################################## ## EVENT HANDLERS ## ######################################## - + def on_delete(self, widget): + self.stuff.pop(self.selected_item_name) + + #self.tree.get_selection().disconnect(self.signal_id) + self.build_list() # Update the items list + #self.signal_id = self.tree.get_selection().connect( + # "changed", self.on_tree_selection_changed) + + self.plot_all() + #self.notebook.set_current_page(1) + + def on_replot(self, widget): + self.plot_all() + + def on_clear_plots(self, widget): + self.clear_plots() + + def on_activate_name(self, entry): + ''' + Hitting 'Enter' after changing the name of an item + updates the item dictionary and re-builds the item list. + ''' + print "Changing name" + self.tree.get_selection().disconnect(self.signal_id) + new_name = entry.get_text() # Get from form + self.stuff[new_name] = self.stuff.pop(self.selected_item_name) # Update dictionary + self.selected_item_name = new_name # Update selection name + self.build_list() # Update the items list + self.signal_id = self.tree.get_selection().connect( + "changed", self.on_tree_selection_changed) + + def on_tree_selection_changed(self, selection): + model, treeiter = selection.get_selected() + + + if treeiter != None: + print "You selected", model[treeiter][0] + else: + return # TODO: Clear "Selected" page + + self.selected_item_name = model[treeiter][0] + # Remove the current selection page + # from the notebook + # TODO: Assuming it was last page or #2. Find the right page + self.builder.get_object("notebook1").remove_page(2) + + # Determine the kind of item selected + kind = self.stuff[model[treeiter][0]].kind + + # Build the UI + builder = {"gerber": self.build_gerber_ui, + "excellon": self.build_excellon_ui, + "cncjob": self.build_cncjob_ui} + builder[kind]() + def on_filequit(self, param): print "quit from menu" self.window.destroy() @@ -175,31 +376,61 @@ class App: self.window.destroy() Gtk.main_quit() + def file_chooser_action(self, on_success): + ''' + Opens the file chooser and runs on_success + upon completion of valid file choice. + ''' + dialog = Gtk.FileChooserDialog("Please choose a file", self.window, + Gtk.FileChooserAction.OPEN, + (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, + Gtk.STOCK_OPEN, Gtk.ResponseType.OK)) + response = dialog.run() + if response == Gtk.ResponseType.OK: + on_success(self, dialog.get_filename()) + elif response == Gtk.ResponseType.CANCEL: + print("Cancel clicked") + dialog.destroy() + def on_fileopengerber(self, param): def on_success(self, filename): - gerber = Gerber() + name = filename.split('/')[-1].split('\\')[-1] + gerber = CirkuixGerber(name) gerber.parse_file(filename) - self.gerbers.append(gerber) + self.store.append([name]) + #self.gerbers.append(gerber) + self.stuff[name] = gerber self.plot_gerber(gerber) + self.on_zoom_fit(None) self.file_chooser_action(on_success) def on_fileopenexcellon(self, param): def on_success(self, filename): - excellon = Excellon() + name = filename.split('/')[-1].split('\\')[-1] + excellon = CirkuixExcellon(name) excellon.parse_file(filename) - self.excellons.append(excellon) + self.store.append([name]) + #self.excellons.append(excellon) + self.stuff[name] = excellon self.plot_excellon(excellon) + self.on_zoom_fit(None) self.file_chooser_action(on_success) def on_fileopengcode(self, param): def on_success(self, filename): + name = filename.split('/')[-1].split('\\')[-1] f = open(filename) gcode = f.read() f.close() - job = CNCjob() + job = CirkuixCNCjob(name) job.gcode = gcode - self.cncjobs.append(job) + job.gcode_parse() + job.create_geometry() + self.store.append([name]) + #self.cncjobs.append(job) + self.stuff[name] = job self.plot_cncjob(job) + self.on_zoom_fit(None) self.file_chooser_action(on_success) def on_mouse_move_over_plot(self, event): @@ -226,7 +457,7 @@ class App: self.zoom(1/1.5) def on_zoom_fit(self, event): - xmin, ymin, xmax, ymax = get_bounds([self.gerbers, self.excellons]) + xmin, ymin, xmax, ymax = get_bounds(self.stuff) width = xmax-xmin height = ymax-ymin self.axes.set_xlim((xmin-0.05*width, xmax+0.05*width)) diff --git a/cirkuix.pyc b/cirkuix.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3732da81826408c773fe186eeac5fdb771a77407 GIT binary patch literal 9442 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 literal 0 HcmV?d00001 diff --git a/cirkuix.ui b/cirkuix.ui index 7554388..6ed2297 100644 --- a/cirkuix.ui +++ b/cirkuix.ui @@ -16,6 +16,607 @@ False gtk-open + + False + + + True + False + 5 + 5 + 5 + 5 + vertical + + + True + False + 3 + CNC Job Object + + + + + + False + True + 0 + + + + + True + False + + + True + False + 3 + Name: + + + False + True + 0 + + + + + True + True + + True + + + False + True + 1 + + + + + False + True + 1 + + + + + True + False + 0 + 3 + Plot Options: + + + + + + False + True + 2 + + + + + Plot + True + True + False + 0 + True + True + + + False + True + 3 + + + + + Solid + True + True + False + 0 + True + + + False + True + 4 + + + + + Multi-colored + True + True + False + 0 + True + + + False + True + 5 + + + + + Refresh Plot + True + True + True + + + False + True + 6 + + + + + + + + + + + + + + + + False + + + True + False + 5 + 5 + 5 + 5 + vertical + + + True + False + 3 + Excellon Object + + + + + + False + True + 0 + + + + + True + False + + + True + False + 3 + Name: + + + False + True + 0 + + + + + True + True + + True + + + False + True + 1 + + + + + False + True + 1 + + + + + True + False + 0 + 3 + Plot Options: + + + + + + False + True + 2 + + + + + Plot + True + True + False + 0 + True + True + + + False + True + 3 + + + + + Solid + True + True + False + 0 + True + + + False + True + 4 + + + + + Multi-colored + True + True + False + 0 + True + + + False + True + 5 + + + + + Refresh Plot + True + True + True + + + False + True + 6 + + + + + + + + + + + + + + + + False + + + True + False + 5 + 5 + 5 + 5 + vertical + + + True + False + 3 + Gerber Object + + + + + + False + True + 0 + + + + + True + False + + + True + False + 3 + Name: + + + False + True + 0 + + + + + True + True + + + + False + True + 1 + + + + + False + True + 1 + + + + + True + False + 0 + 3 + Plot Options: + + + + + + False + True + 2 + + + + + Plot + True + True + False + 0 + True + True + + + False + True + 3 + + + + + Merge Polygons + True + True + False + 0 + True + True + + + False + True + 4 + + + + + Solid + True + True + False + 0 + True + + + False + True + 5 + + + + + Multi-colored + True + True + False + 0 + True + + + False + True + 6 + + + + + Refresh Plot + True + True + True + + + False + True + 7 + + + + + True + False + 0 + 3 + Isolation Routing: + + + + + + False + True + 8 + + + + + True + False + 2 + 2 + + + True + False + 1 + 3 + Tool diam: + + + 0 + 0 + 1 + 1 + + + + + True + True + + True + + + 1 + 0 + 1 + 1 + + + + + True + False + 1 + 3 + Cut X: + + + 0 + 1 + 1 + 1 + + + + + True + True + + True + + + 1 + 1 + 1 + 1 + + + + + True + False + 1 + 3 + Travel X: + + + 0 + 2 + 1 + 1 + + + + + True + True + + True + + + 1 + 2 + 1 + 1 + + + + + False + True + 9 + + + + + Generate Geometry + True + True + True + + + False + True + 10 + + + + + + + + + + + + + + 600 400 @@ -237,6 +838,48 @@ True + + + True + False + Clear Plots + True + gtk-stop + + + + False + True + + + + + True + False + Re-plot + True + gtk-redo + + + + False + True + + + + + True + False + Delete Object + True + gtk-delete + + + + False + True + + False