diff --git a/camlib.py b/camlib.py
index 83e3e70b..442c9d60 100644
--- a/camlib.py
+++ b/camlib.py
@@ -7,7 +7,7 @@ import cairo
#import os
#import sys
-from numpy import arctan2, Inf, array
+from numpy import arctan2, Inf, array, sqrt, pi, ceil, sin, cos
from matplotlib.figure import Figure
# See: http://toblerity.org/shapely/manual.html
@@ -16,6 +16,7 @@ from shapely.geometry import MultiPoint, MultiPolygon
from shapely.geometry import box as shply_box
from shapely.ops import cascaded_union
+from descartes.patch import PolygonPatch
class Geometry:
def __init__(self):
@@ -117,8 +118,6 @@ class Gerber (Geometry):
'''
for region in self.regions:
if region['polygon'].is_valid == False:
- #polylist = fix_poly(region['polygon'])
- #region['polygon'] = fix_poly3(polylist)
region['polygon'] = region['polygon'].buffer(0)
def buffer_paths(self):
@@ -232,6 +231,9 @@ class Gerber (Geometry):
"aperture":last_path_aperture})
def do_flashes(self):
+ '''
+ Creates geometry for Gerber flashes (aperture on a single point).
+ '''
self.flash_geometry = []
for flash in self.flashes:
aperture = self.apertures[flash['aperture']]
@@ -263,6 +265,81 @@ class Gerber (Geometry):
[poly['polygon'] for poly in self.regions] +
self.flash_geometry)
+class Excellon(Geometry):
+ def __init__(self):
+ Geometry.__init__(self)
+
+ self.tools = {}
+
+ self.drills = []
+
+ def parse_file(self, filename):
+ efile = open(filename, 'r')
+ estr = efile.readlines()
+ efile.close()
+ self.parse_lines(estr)
+
+ def parse_lines(self, elines):
+ '''
+ Main Excellon parser.
+ '''
+ current_tool = ""
+
+ for eline in elines:
+
+ ## Tool definitions ##
+ # TODO: Verify all this
+ indexT = eline.find("T")
+ indexC = eline.find("C")
+ indexF = eline.find("F")
+ # Type 1
+ if indexT != -1 and indexC > indexT and indexF > indexF:
+ tool = eline[1:indexC]
+ spec = eline[indexC+1:indexF]
+ self.tools[tool] = spec
+ continue
+ # Type 2
+ # TODO: Is this inches?
+ #indexsp = eline.find(" ")
+ #indexin = eline.find("in")
+ #if indexT != -1 and indexsp > indexT and indexin > indexsp:
+ # tool = eline[1:indexsp]
+ # spec = eline[indexsp+1:indexin]
+ # self.tools[tool] = spec
+ # continue
+ # Type 3
+ if indexT != -1 and indexC > indexT:
+ tool = eline[1:indexC]
+ spec = eline[indexC+1:-1]
+ self.tools[tool] = spec
+ continue
+
+ ## Tool change
+ if indexT == 0:
+ current_tool = eline[1:-1]
+ continue
+
+ ## Drill
+ indexX = eline.find("X")
+ indexY = eline.find("Y")
+ if indexX != -1 and indexY != -1:
+ x = float(int(eline[indexX+1:indexY])/10000.0)
+ y = float(int(eline[indexY+1:-1])/10000.0)
+ self.drills.append({'point':Point((x,y)), 'tool':current_tool})
+ continue
+
+ print "WARNING: Line ignored:", eline
+
+ def create_geometry(self):
+ self.solid_geometry = []
+ sizes = {}
+ for tool in self.tools:
+ sizes[tool] = float(self.tools[tool])
+ for drill in self.drills:
+ poly = Point(drill['point']).buffer(sizes[drill['tool']]/2.0)
+ self.solid_geometry.append(poly)
+ self.solid_geometry = cascaded_union(self.solid_geometry)
+
class CNCjob:
def __init__(self, units="in", kind="generic", z_move = 0.1,
feedrate = 3.0, z_cut = -0.002):
@@ -279,7 +356,7 @@ class CNCjob:
self.feedminutecode = "G94"
self.absolutecode = "G90"
- # Output G-Code
+ # Input/Output G-Code
self.gcode = ""
# Bounds of geometry given to CNCjob.generate_from_geometry()
@@ -393,6 +470,7 @@ class CNCjob:
self.gcode += "M05\n" # Spindle stop
def create_gcode_geometry(self):
+ steps_per_circ = 20
'''
G-Code parser (from self.gcode). Generates dictionary with
single-segment LineString's and "kind" indicating cut or travel,
@@ -415,26 +493,42 @@ class CNCjob:
current['Z'] = gobj['Z']
if 'G' in gobj:
- current['G'] = gobj['G']
+ current['G'] = int(gobj['G'])
if 'X' in gobj or 'Y' in gobj:
x = 0
y = 0
kind = ["C","F"] # T=travel, C=cut, F=fast, S=slow
+
if 'X' in gobj:
x = gobj['X']
else:
x = current['X']
+
if 'Y' in gobj:
y = gobj['Y']
else:
y = current['Y']
+
if current['Z'] > 0:
kind[0] = 'T'
- if current['G'] == 1:
+ if current['G'] > 0:
kind[1] = 'S'
- geometry.append({'geom':LineString([(current['X'],current['Y']),
- (x,y)]), 'kind':kind})
+
+ arcdir = [None, None, "cw", "ccw"]
+ if current['G'] in [0,1]: # line
+ geometry.append({'geom':LineString([(current['X'],current['Y']),
+ (x,y)]), 'kind':kind})
+ if current['G'] in [2,3]: # arc
+ center = [gobj['I'] + current['X'], gobj['J'] + current['Y']]
+ radius = sqrt(gobj['I']**2 + gobj['J']**2)
+ start = arctan2( -gobj['J'], -gobj['I'])
+ stop = arctan2(-center[1]+y, -center[0]+x)
+ geometry.append({'geom':arc(center, radius, start, stop,
+ arcdir[current['G']],
+ steps_per_circ),
+ 'kind':kind})
+
# Update current instruction
for code in gobj:
@@ -477,153 +571,46 @@ class CNCjob:
ax.add_patch(patch)
return fig
-
-
-class Excellon(Geometry):
- def __init__(self):
- Geometry.__init__(self)
- self.tools = {}
-
- self.drills = []
-
- def parse_file(self, filename):
- efile = open(filename, 'r')
- estr = efile.readlines()
- efile.close()
- self.parse_lines(estr)
-
- def parse_lines(self, elines):
+ def plot2(self, axes, tooldia=None, dpi=75, margin=0.1,
+ color={"T":["#F0E24D", "#B5AB3A"], "C":["#5E6CFF", "#4650BD"]},
+ alpha={"T":0.3, "C":1.0}):
'''
- Main Excellon parser.
+ Plots the G-code job onto the given axes
'''
- current_tool = ""
-
- for eline in elines:
+ if tooldia == None:
+ tooldia = self.tooldia
- ## Tool definitions ##
- # TODO: Verify all this
- indexT = eline.find("T")
- indexC = eline.find("C")
- indexF = eline.find("F")
- # Type 1
- if indexT != -1 and indexC > indexT and indexF > indexF:
- tool = eline[1:indexC]
- spec = eline[indexC+1:indexF]
- self.tools[tool] = spec
- continue
- # Type 2
- # TODO: Is this inches?
- #indexsp = eline.find(" ")
- #indexin = eline.find("in")
- #if indexT != -1 and indexsp > indexT and indexin > indexsp:
- # tool = eline[1:indexsp]
- # spec = eline[indexsp+1:indexin]
- # self.tools[tool] = spec
- # continue
- # Type 3
- if indexT != -1 and indexC > indexT:
- tool = eline[1:indexC]
- spec = eline[indexC+1:-1]
- self.tools[tool] = spec
- continue
-
- ## Tool change
- if indexT == 0:
- current_tool = eline[1:-1]
- continue
-
- ## Drill
- indexX = eline.find("X")
- indexY = eline.find("Y")
- if indexX != -1 and indexY != -1:
- x = float(int(eline[indexX+1:indexY])/10000.0)
- y = float(int(eline[indexY+1:-1])/10000.0)
- self.drills.append({'point':Point((x,y)), 'tool':current_tool})
- continue
-
- print "WARNING: Line ignored:", eline
+ #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)
- def create_geometry(self):
- self.solid_geometry = []
- sizes = {}
- for tool in self.tools:
- sizes[tool] = float(self.tools[tool])
- for drill in self.drills:
- poly = Point(drill['point']).buffer(sizes[drill['tool']]/2.0)
- self.solid_geometry.append(poly)
- self.solid_geometry = cascaded_union(self.solid_geometry)
-
-
-
-class motion:
- '''
- Represents a machine motion, which can be cutting or just travelling.
- '''
- def __init__(self, start, end, depth, typ='line', offset=None, center=None,
- radius=None, tooldia=0.5):
- self.typ = typ
- self.start = start
- self.end = end
- self.depth = depth
- self.center = center
- self.radius = radius
- self.tooldia = tooldia
- self.offset = offset # (I, J)
+ if tooldia == 0:
+ for geo in self.G_geometry:
+ linespec = '--'
+ linecolor = color[geo['kind'][0]][1]
+ if geo['kind'][0] == 'C':
+ linespec = 'k-'
+ x, y = geo['geom'].coords.xy
+ axes.plot(x, y, linespec, color=linecolor)
+ else:
+ for geo in self.G_geometry:
+ 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 gparse1(filename):
- '''
- Parses G-code file into list of dictionaries like
- Examples: {'G': 1.0, 'X': 0.085, 'Y': -0.125},
- {'G': 3.0, 'I': -0.01, 'J': 0.0, 'X': 0.0821, 'Y': -0.1179}
- '''
- f = open(filename)
- gcmds = []
- for line in f:
- line = line.strip()
-
- # Remove comments
- # NOTE: Limited to 1 bracket pair
- op = line.find("(")
- cl = line.find(")")
- if op > -1 and cl > op:
- #comment = line[op+1:cl]
- line = line[:op] + line[(cl+1):]
-
- # Parse GCode
- # 0 4 12
- # G01 X-0.007 Y-0.057
- # --> codes_idx = [0, 4, 12]
- codes = "NMGXYZIJFP"
- codes_idx = []
- i = 0
- for ch in line:
- if ch in codes:
- codes_idx.append(i)
- i += 1
- n_codes = len(codes_idx)
- if n_codes == 0:
- continue
-
- # Separate codes in line
- parts = []
- for p in range(n_codes-1):
- parts.append( line[ codes_idx[p]:codes_idx[p+1] ].strip() )
- parts.append( line[codes_idx[-1]:].strip() )
-
- # Separate codes from values
- cmds = {}
- for part in parts:
- cmds[part[0]] = float(part[1:])
- gcmds.append(cmds)
-
- f.close()
- return gcmds
def gparse1b(gtext):
+ '''
+ gtext is a single string with g-code
+ '''
gcmds = []
- lines = gtext.split("\n")
+ lines = gtext.split("\n") # TODO: This is probably a lot of work!
for line in lines:
line = line.strip()
@@ -662,98 +649,43 @@ def gparse1b(gtext):
cmds[part[0]] = float(part[1:])
gcmds.append(cmds)
return gcmds
-
-
-def gparse2(gcmds):
-
- x = []
- y = []
- z = []
- xypoints = []
- motions = []
- current_g = None
-
- for cmds in gcmds:
-
- # Destination point
- x_ = None
- y_ = None
- z_ = None
-
- if 'X' in cmds:
- x_ = cmds['X']
- x.append(x_)
- if 'Y' in cmds:
- y_ = cmds['Y']
- y.append(y_)
- if 'Z' in cmds:
- z_ = cmds['Z']
- z.append(z_)
-
- # Ingnore anything but XY movements from here on
- if x_ is None and y_ is None:
- #print "-> no x,y"
- continue
-
- if x_ is None:
- x_ = xypoints[-1][0]
-
- if y_ is None:
- y_ = xypoints[-1][1]
-
- if z_ is None:
- z_ = z[-1]
-
-
- mot = None
-
- if 'G' in cmds:
- current_g = cmds['G']
-
- if current_g == 0: # Fast linear
- if len(xypoints) > 0:
- #print "motion(", xypoints[-1], ", (", x_, ",", y_, "),", z_, ")"
- mot = motion(xypoints[-1], (x_, y_), z_)
-
- if current_g == 1: # Feed-rate linear
- if len(xypoints) > 0:
- #print "motion(", xypoints[-1], ", (", x_, ",", y_, "),", z_, ")"
- mot = motion(xypoints[-1], (x_, y_), z_)
-
- if current_g == 2: # Clockwise arc
- if len(xypoints) > 0:
- if 'I' in cmds and 'J' in cmds:
- mot = motion(xypoints[-1], (x_, y_), z_, offset=(cmds['I'],
- cmds['J']), typ='arccw')
-
- if current_g == 3: # Counter-clockwise arc
- if len(xypoints) > 0:
- if 'I' in cmds and 'J' in cmds:
- mot = motion(xypoints[-1], (x_, y_), z_, offset=(cmds['I'],
- cmds['J']), typ='arcacw')
-
- if mot is not None:
- motions.append(mot)
-
- xypoints.append((x_, y_))
-
- x = array(x)
- y = array(y)
- z = array(z)
- xmin = min(x)
- xmax = max(x)
- ymin = min(y)
- ymax = max(y)
-
- print "x:", min(x), max(x)
- print "y:", min(y), max(y)
- print "z:", min(z), max(z)
-
- print xypoints[-1]
+def get_bounds(geometry_sets):
+ xmin = Inf
+ ymin = Inf
+ xmax = -Inf
+ ymax = -Inf
- return xmin, xmax, ymin, ymax, motions
+ #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])
+
+ return [xmin, ymin, xmax, ymax]
+def arc(center, radius, start, stop, direction, steps_per_circ):
+ da_sign = {"cw":-1.0, "ccw":1.0}
+ points = []
+ if direction=="ccw" and stop <= start:
+ stop += 2*pi
+ if direction=="cw" and stop >= start:
+ stop -= 2*pi
+
+ angle = abs(stop - start)
+
+ #angle = stop-start
+ steps = max([int(ceil(angle/(2*pi)*steps_per_circ)), 2])
+ delta_angle = da_sign[direction]*angle*1.0/steps
+ for i in range(steps+1):
+ theta = start + delta_angle*i
+ points.append([center[0]+radius*cos(theta), center[1]+radius*sin(theta)])
+ return LineString(points)
+
############### cam.py ####################
def coord(gstr,digits,fraction):
'''
diff --git a/camlib.pyc b/camlib.pyc
index 04f9034e..c02cf4a1 100644
Binary files a/camlib.pyc and b/camlib.pyc differ
diff --git a/cirkuix.py b/cirkuix.py
index 1ddd289e..b2f4d855 100644
--- a/cirkuix.py
+++ b/cirkuix.py
@@ -29,22 +29,26 @@ class App:
## Event handling ##
self.builder.connect_signals(self)
+ ## Make plot area ##
self.figure = None
self.axes = None
self.canvas = None
-
- ## Make plot area ##
self.mplpaint()
- self.window.show_all()
+
########################################
## DATA ##
########################################
self.gerbers = []
self.excellons = []
+ self.cncjobs = []
self.mouse = None
+ ########################################
+ ## START ##
+ ########################################
+ self.window.show_all()
Gtk.main()
def mplpaint(self):
@@ -58,169 +62,24 @@ class App:
self.axes.grid()
#a.patch.set_visible(False) Background of the axes
self.figure.patch.set_visible(False)
- #self.figure.tight_layout()
self.canvas = FigureCanvas(self.figure) # a Gtk.DrawingArea
- #self.canvas.set_size_request(600,400)
+ self.canvas.set_hexpand(1)
+ self.canvas.set_vexpand(1)
+
+ ########################################
+ ## EVENTS ##
+ ########################################
self.canvas.mpl_connect('button_press_event', self.on_click_over_plot)
self.canvas.mpl_connect('motion_notify_event', self.on_mouse_move_over_plot)
- ##self.canvas.mpl_connect('scroll_event', self.on_scroll_over_plot)
- ##self.canvas.mpl_connect('key_press_event', self.on_key_over_plot)
-
-
- self.canvas.set_hexpand(1)
- self.canvas.set_vexpand(1)
+ self.canvas.set_can_focus(True) # For key press
+ 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 on_filequit(self, param):
- print "quit from menu"
- self.window.destroy()
- Gtk.main_quit()
-
- def on_closewindow(self, param):
- print "quit from X"
- self.window.destroy()
- Gtk.main_quit()
-
- def on_fileopengerber(self, param):
- print "File->Open Gerber"
- 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:
- ## Load the file ##
- print("Open clicked")
- print("File selected: " + dialog.get_filename())
- gerber = Gerber()
- gerber.parse_file(dialog.get_filename())
- self.gerbers.append(gerber)
- self.plot_gerber(gerber)
- ## End ##
- elif response == Gtk.ResponseType.CANCEL:
- print("Cancel clicked")
- dialog.destroy()
-
- def on_fileopenexcellon(self, param):
- print "File->Open Excellon"
- 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:
- ## Load the file ##
- print("Open clicked")
- print("File selected: " + dialog.get_filename())
- excellon = Excellon()
- excellon.parse_file(dialog.get_filename())
- self.excellons.append(excellon)
- self.plot_excellon(excellon)
- ## End ##
- elif response == Gtk.ResponseType.CANCEL:
- print("Cancel clicked")
- dialog.destroy()
-
- def plot_gerber(self, gerber):
- gerber.create_geometry()
-
- # Options
- mergepolys = self.builder.get_object("cb_mergepolys").get_active()
- multicolored = self.builder.get_object("cb_multicolored").get_active()
-
- geometry = None
- if mergepolys:
- geometry = gerber.solid_geometry
- else:
- geometry = gerber.buffered_paths + \
- [poly['polygon'] for poly in gerber.regions] + \
- gerber.flash_geometry
-
- linespec = None
- if multicolored:
- linespec = '-'
- else:
- linespec = 'k-'
- #f = Figure(dpi=75)
- #a = f.add_subplot(111)
- #a.set_aspect(1)
- for poly in geometry:
- x, y = poly.exterior.xy
- #a.plot(x, y)
- self.axes.plot(x, y, linespec)
- for ints in poly.interiors:
- x, y = ints.coords.xy
- self.axes.plot(x, y, linespec)
-
- #f.tight_layout()
- #canvas = FigureCanvas(f) # a Gtk.DrawingArea
- #canvas.set_size_request(600,400)
- #self.grid.attach(canvas,1,1,600,400)
- #self.window.show_all()
-
- def plot_excellon(self, excellon):
- excellon.create_geometry()
-
- # Plot excellon
- for geo in excellon.solid_geometry:
- x, y = geo.exterior.coords.xy
- self.axes.plot(x, y, 'r-')
- for ints in geo.interiors:
- x, y = ints.coords.xy
- self.axes.plot(x, y, 'g-')
-
- def on_mouse_move_over_plot(self, event):
- try: # May fail in case mouse not within axes
- self.positionLabel.set_label("X: %.4f Y: %.4f"%(
- event.xdata, event.ydata))
- self.mouse = [event.xdata, event.ydata]
- except:
- self.positionLabel.set_label("X: --- Y: ---")
- self.mouse = None
-
- def on_click_over_plot(self, event):
- print 'button=%d, x=%d, y=%d, xdata=%f, ydata=%f'%(
- event.button, event.x, event.y, event.xdata, event.ydata)
-
- def get_bounds(self):
- 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])
-
- return [xmin, ymin, xmax, ymax]
-
- def on_zoom_in(self, event):
- self.zoom(1.5)
- return
-
- def on_zoom_out(self, event):
- self.zoom(1/1.5)
-
- def on_zoom_fit(self, event):
- xmin, ymin, xmax, ymax = self.get_bounds()
- width = xmax-xmin
- height = ymax-ymin
- self.axes.set_xlim((xmin-0.05*width, xmax+0.05*width))
- self.axes.set_ylim((ymin-0.05*height, ymax+0.05*height))
- self.canvas.queue_draw()
- return
-
def zoom(self, factor, center=None):
xmin, xmax = self.axes.get_xlim()
ymin, ymax = self.axes.get_ylim()
@@ -241,34 +100,163 @@ class App:
self.axes.set_ylim((center[1]-new_height*(1-rely), center[1]+new_height*rely))
self.canvas.queue_draw()
+
+ def plot_gerber(self, gerber):
+ gerber.create_geometry()
-# def on_scroll_over_plot(self, event):
-# print "Scroll"
-# center = [event.xdata, event.ydata]
-# if sign(event.step):
-# self.zoom(1.5, center=center)
-# else:
-# self.zoom(1/1.5, center=center)
-#
-# def on_window_scroll(self, event):
-# print "Scroll"
-#
-# def on_key_over_plot(self, event):
-# print 'you pressed', event.key, event.xdata, event.ydata
+ # Options
+ mergepolys = self.builder.get_object("cb_mergepolys").get_active()
+ multicolored = self.builder.get_object("cb_multicolored").get_active()
- def on_window_key_press(self, widget, event):
- print event.get_keycode(), event.get_keyval()
- val = int(event.get_keyval()[1])
+ geometry = None
+ if mergepolys:
+ geometry = gerber.solid_geometry
+ else:
+ geometry = gerber.buffered_paths + \
+ [poly['polygon'] for poly in gerber.regions] + \
+ gerber.flash_geometry
- if val == 49: # 1
+ linespec = None
+ if multicolored:
+ linespec = '-'
+ else:
+ linespec = 'k-'
+
+ for poly in geometry:
+ x, y = poly.exterior.xy
+ #a.plot(x, y)
+ self.axes.plot(x, y, linespec)
+ for ints in poly.interiors:
+ x, y = ints.coords.xy
+ self.axes.plot(x, y, linespec)
+
+ def plot_excellon(self, excellon):
+ excellon.create_geometry()
+
+ # Plot excellon
+ for geo in excellon.solid_geometry:
+ x, y = geo.exterior.coords.xy
+ self.axes.plot(x, y, 'r-')
+ for ints in geo.interiors:
+ x, y = ints.coords.xy
+ self.axes.plot(x, y, 'g-')
+
+ def plot_cncjob(self, job):
+ job.create_gcode_geometry()
+ 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()
+
+
+ ########################################
+ ## EVENT HANDLERS ##
+ ########################################
+
+ def on_filequit(self, param):
+ print "quit from menu"
+ self.window.destroy()
+ Gtk.main_quit()
+
+ def on_closewindow(self, param):
+ print "quit from X"
+ self.window.destroy()
+ Gtk.main_quit()
+
+ def on_fileopengerber(self, param):
+ def on_success(self, filename):
+ gerber = Gerber()
+ gerber.parse_file(filename)
+ self.gerbers.append(gerber)
+ self.plot_gerber(gerber)
+ self.file_chooser_action(on_success)
+
+ def on_fileopenexcellon(self, param):
+ def on_success(self, filename):
+ excellon = Excellon()
+ excellon.parse_file(filename)
+ self.excellons.append(excellon)
+ self.plot_excellon(excellon)
+ self.file_chooser_action(on_success)
+
+ def on_fileopengcode(self, param):
+ def on_success(self, filename):
+ f = open(filename)
+ gcode = f.read()
+ f.close()
+ job = CNCjob()
+ job.gcode = gcode
+ self.cncjobs.append(job)
+ self.plot_cncjob(job)
+ self.file_chooser_action(on_success)
+
+ def on_mouse_move_over_plot(self, event):
+ try: # May fail in case mouse not within axes
+ self.positionLabel.set_label("X: %.4f Y: %.4f"%(
+ event.xdata, event.ydata))
+ self.mouse = [event.xdata, event.ydata]
+ except:
+ self.positionLabel.set_label("")
+ self.mouse = None
+
+ def on_click_over_plot(self, event):
+ # For key presses
+ self.canvas.grab_focus()
+
+ print 'button=%d, x=%d, y=%d, xdata=%f, ydata=%f'%(
+ event.button, event.x, event.y, event.xdata, event.ydata)
+
+ def on_zoom_in(self, event):
+ self.zoom(1.5)
+ return
+
+ def on_zoom_out(self, event):
+ self.zoom(1/1.5)
+
+ def on_zoom_fit(self, event):
+ xmin, ymin, xmax, ymax = get_bounds([self.gerbers, self.excellons])
+ width = xmax-xmin
+ height = ymax-ymin
+ self.axes.set_xlim((xmin-0.05*width, xmax+0.05*width))
+ self.axes.set_ylim((ymin-0.05*height, ymax+0.05*height))
+ self.canvas.queue_draw()
+ return
+
+ def on_scroll_over_plot(self, event):
+ print "Scroll"
+ center = [event.xdata, event.ydata]
+ if sign(event.step):
+ self.zoom(1.5, center=center)
+ else:
+ self.zoom(1/1.5, center=center)
+
+ def on_window_scroll(self, event):
+ print "Scroll"
+
+ def on_key_over_plot(self, event):
+ print 'you pressed', event.key, event.xdata, event.ydata
+
+ if event.key == '1': # 1
self.on_zoom_fit(None)
return
- if val == 50: # 2
+ if event.key == '2': # 2
self.zoom(1/1.5, self.mouse)
return
- if val == 51: # 3
+ if event.key == '3': # 3
self.zoom(1.5, self.mouse)
return
diff --git a/cirkuix.ui b/cirkuix.ui
index 2bc82838..7554388e 100644
--- a/cirkuix.ui
+++ b/cirkuix.ui
@@ -11,12 +11,16 @@
False
gtk-open
+