Added Measuring tool.

This commit is contained in:
Juan Pablo Caram 2014-03-07 15:43:54 -05:00
parent 8c3a8d694a
commit e8728ed15c
3 changed files with 986 additions and 1061 deletions

2
.gitignore vendored
View File

@ -1,2 +0,0 @@
flatcam.sublime*
.nfs*

View File

@ -641,6 +641,7 @@ class App:
self.progress_bar = self.builder.get_object("progressbar") self.progress_bar = self.builder.get_object("progressbar")
self.progress_bar.set_show_text(True) self.progress_bar.set_show_text(True)
self.units_label = self.builder.get_object("label_units") self.units_label = self.builder.get_object("label_units")
self.toolbar = self.builder.get_object("toolbar_main")
# White (transparent) background on the "Options" tab. # White (transparent) background on the "Options" tab.
self.builder.get_object("vp_options").override_background_color(Gtk.StateType.NORMAL, self.builder.get_object("vp_options").override_background_color(Gtk.StateType.NORMAL,
@ -658,19 +659,11 @@ class App:
self.builder.connect_signals(self) self.builder.connect_signals(self)
#### Make plot area #### #### Make plot area ####
# self.figure = None
# self.axes = None
# self.canvas = None
# self.setup_plot()
self.plotcanvas = PlotCanvas(self.grid) self.plotcanvas = PlotCanvas(self.grid)
self.plotcanvas.mpl_connect('button_press_event', self.on_click_over_plot) self.plotcanvas.mpl_connect('button_press_event', self.on_click_over_plot)
self.plotcanvas.mpl_connect('motion_notify_event', self.on_mouse_move_over_plot) self.plotcanvas.mpl_connect('motion_notify_event', self.on_mouse_move_over_plot)
self.plotcanvas.mpl_connect('key_press_event', self.on_key_over_plot) self.plotcanvas.mpl_connect('key_press_event', self.on_key_over_plot)
# self.axes = self.plotcanvas.axes # TODO: Just for testing
# self.figure = self.plotcanvas.figure # TODO: Just for testing
# self.canvas = self.plotcanvas.canvas # TODO: Just for testing
self.setup_tooltips() self.setup_tooltips()
#### DATA #### #### DATA ####
@ -721,9 +714,17 @@ class App:
self.plot_mousemove_subscribers = {} self.plot_mousemove_subscribers = {}
## Tools ## ## Tools ##
# self.measure = Measurement(self.axes, self.plot_click_subscribers, self.measure = Measurement(self.builder.get_object("box39"), self.plotcanvas.axes,
# self.plot_mousemove_subscribers, self.plot_click_subscribers, self.plot_mousemove_subscribers)
# lambda: self.canvas.queue_draw()) # Toolbar icon
# TODO: Where should I put this? Tool should have a method to add to toolbar?
meas_ico = Gtk.Image.new_from_file('share/measure32.png')
measure = Gtk.ToolButton.new(meas_ico, "")
measure.connect("clicked", self.measure.toggle_active)
measure.set_tooltip_markup("<b>Measure Tool:</b> Enable/disable tool.\n" +
"Click on point to set reference.\n" +
"(Click on plot and hit <b>m</b>)")
self.toolbar.insert(measure, -1)
#### Initialization #### #### Initialization ####
self.load_defaults() self.load_defaults()
@ -757,49 +758,48 @@ class App:
self.window.show_all() self.window.show_all()
def setup_toolbar(self): def setup_toolbar(self):
toolbar = self.builder.get_object("toolbar_main")
# Zoom fit # Zoom fit
zf_ico = Gtk.Image.new_from_file('share/zoom_fit32.png') zf_ico = Gtk.Image.new_from_file('share/zoom_fit32.png')
zoom_fit = Gtk.ToolButton.new(zf_ico, "") zoom_fit = Gtk.ToolButton.new(zf_ico, "")
zoom_fit.connect("clicked", self.on_zoom_fit) zoom_fit.connect("clicked", self.on_zoom_fit)
zoom_fit.set_tooltip_markup("Zoom Fit.\n(Click on plot and hit <b>1</b>)") zoom_fit.set_tooltip_markup("Zoom Fit.\n(Click on plot and hit <b>1</b>)")
toolbar.insert(zoom_fit, -1) self.toolbar.insert(zoom_fit, -1)
# Zoom out # Zoom out
zo_ico = Gtk.Image.new_from_file('share/zoom_out32.png') zo_ico = Gtk.Image.new_from_file('share/zoom_out32.png')
zoom_out = Gtk.ToolButton.new(zo_ico, "") zoom_out = Gtk.ToolButton.new(zo_ico, "")
zoom_out.connect("clicked", self.on_zoom_out) zoom_out.connect("clicked", self.on_zoom_out)
zoom_out.set_tooltip_markup("Zoom Out.\n(Click on plot and hit <b>2</b>)") zoom_out.set_tooltip_markup("Zoom Out.\n(Click on plot and hit <b>2</b>)")
toolbar.insert(zoom_out, -1) self.toolbar.insert(zoom_out, -1)
# Zoom in # Zoom in
zi_ico = Gtk.Image.new_from_file('share/zoom_in32.png') zi_ico = Gtk.Image.new_from_file('share/zoom_in32.png')
zoom_in = Gtk.ToolButton.new(zi_ico, "") zoom_in = Gtk.ToolButton.new(zi_ico, "")
zoom_in.connect("clicked", self.on_zoom_in) zoom_in.connect("clicked", self.on_zoom_in)
zoom_in.set_tooltip_markup("Zoom In.\n(Click on plot and hit <b>3</b>)") zoom_in.set_tooltip_markup("Zoom In.\n(Click on plot and hit <b>3</b>)")
toolbar.insert(zoom_in, -1) self.toolbar.insert(zoom_in, -1)
# Clear plot # Clear plot
cp_ico = Gtk.Image.new_from_file('share/clear_plot32.png') cp_ico = Gtk.Image.new_from_file('share/clear_plot32.png')
clear_plot = Gtk.ToolButton.new(cp_ico, "") clear_plot = Gtk.ToolButton.new(cp_ico, "")
clear_plot.connect("clicked", self.on_clear_plots) clear_plot.connect("clicked", self.on_clear_plots)
clear_plot.set_tooltip_markup("Clear Plot") clear_plot.set_tooltip_markup("Clear Plot")
toolbar.insert(clear_plot, -1) self.toolbar.insert(clear_plot, -1)
# Replot # Replot
rp_ico = Gtk.Image.new_from_file('share/replot32.png') rp_ico = Gtk.Image.new_from_file('share/replot32.png')
replot = Gtk.ToolButton.new(rp_ico, "") replot = Gtk.ToolButton.new(rp_ico, "")
replot.connect("clicked", self.on_toolbar_replot) replot.connect("clicked", self.on_toolbar_replot)
replot.set_tooltip_markup("Re-plot all") replot.set_tooltip_markup("Re-plot all")
toolbar.insert(replot, -1) self.toolbar.insert(replot, -1)
# Delete item # Delete item
del_ico = Gtk.Image.new_from_file('share/delete32.png') del_ico = Gtk.Image.new_from_file('share/delete32.png')
delete = Gtk.ToolButton.new(del_ico, "") delete = Gtk.ToolButton.new(del_ico, "")
delete.connect("clicked", self.on_delete) delete.connect("clicked", self.on_delete)
delete.set_tooltip_markup("Delete selected\nobject.") delete.set_tooltip_markup("Delete selected\nobject.")
toolbar.insert(delete, -1) self.toolbar.insert(delete, -1)
def setup_obj_classes(self): def setup_obj_classes(self):
""" """
@ -824,7 +824,7 @@ class App:
self.tree_select = self.tree.get_selection() self.tree_select = self.tree.get_selection()
self.signal_id = self.tree_select.connect("changed", self.on_tree_selection_changed) self.signal_id = self.tree_select.connect("changed", self.on_tree_selection_changed)
renderer = Gtk.CellRendererText() renderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn("Title", renderer, text=0) column = Gtk.TreeViewColumn("Objects", renderer, text=0)
self.tree.append_column(column) self.tree.append_column(column)
self.builder.get_object("box_project").pack_start(self.tree, False, False, 1) self.builder.get_object("box_project").pack_start(self.tree, False, False, 1)
@ -862,45 +862,6 @@ class App:
""" """
self.info_label.set_text(text) self.info_label.set_text(text)
# def zoom(self, factor, center=None):
# """
# Zooms the plot by factor around a given
# center point. Takes care of re-drawing.
#
# :param factor: Number by which to scale the plot.
# :type factor: float
# :param center: Coordinates [x, y] of the point around which to scale the plot.
# :type center: list
# :return: None
# """
# xmin, xmax = self.axes.get_xlim()
# ymin, ymax = self.axes.get_ylim()
# width = xmax - xmin
# height = ymax - ymin
#
# if center is None:
# center = [(xmin + xmax) / 2.0, (ymin + ymax) / 2.0]
#
# # For keeping the point at the pointer location
# relx = (xmax - center[0]) / width
# rely = (ymax - center[1]) / height
#
# new_width = width / factor
# new_height = height / factor
#
# xmin = center[0] - new_width * (1 - relx)
# xmax = center[0] + new_width * relx
# ymin = center[1] - new_height * (1 - rely)
# ymax = center[1] + new_height * rely
#
# for name in self.stuff:
# self.stuff[name].axes.set_xlim((xmin, xmax))
# self.stuff[name].axes.set_ylim((ymin, ymax))
# self.axes.set_xlim((xmin, xmax))
# self.axes.set_ylim((ymin, ymax))
#
# self.canvas.queue_draw()
def build_list(self): def build_list(self):
""" """
Clears and re-populates the list of objects in currently Clears and re-populates the list of objects in currently
@ -998,7 +959,7 @@ class App:
self.tree_select.select_iter(iter) self.tree_select.select_iter(iter)
# Need to return False such that GLib.idle_add # Need to return False such that GLib.idle_add
# or .timeout_add do not repear. # or .timeout_add do not repeat.
return False return False
def new_object(self, kind, name, initialize): def new_object(self, kind, name, initialize):
@ -1106,61 +1067,6 @@ class App:
except: except:
return None return None
# def adjust_axes(self, xmin, ymin, xmax, ymax):
# """
# Adjusts axes of all plots while maintaining the use of the whole canvas
# and an aspect ratio to 1:1 between x and y axes. The parameters are an original
# request that will be modified to fit these restrictions.
#
# :param xmin: Requested minimum value for the X axis.
# :type xmin: float
# :param ymin: Requested minimum value for the Y axis.
# :type ymin: float
# :param xmax: Requested maximum value for the X axis.
# :type xmax: float
# :param ymax: Requested maximum value for the Y axis.
# :type ymax: float
# :return: None
# """
# m_x = 15 # pixels
# m_y = 25 # pixels
# width = xmax - xmin
# height = ymax - ymin
# try:
# r = width / height
# except:
# print "ERROR: Height is", height
# return
# Fw, Fh = self.canvas.get_width_height()
# Fr = float(Fw) / Fh
# x_ratio = float(m_x) / Fw
# y_ratio = float(m_y) / Fh
#
# if r > Fr:
# ycenter = (ymin + ymax) / 2.0
# newheight = height * r / Fr
# ymin = ycenter - newheight / 2.0
# ymax = ycenter + newheight / 2.0
# else:
# xcenter = (xmax + ymin) / 2.0
# newwidth = width * Fr / r
# xmin = xcenter - newwidth / 2.0
# xmax = xcenter + newwidth / 2.0
#
# for name in self.stuff:
# if self.stuff[name].axes is None:
# continue
# self.stuff[name].axes.set_xlim((xmin, xmax))
# self.stuff[name].axes.set_ylim((ymin, ymax))
# self.stuff[name].axes.set_position([x_ratio, y_ratio,
# 1 - 2 * x_ratio, 1 - 2 * y_ratio])
# self.axes.set_xlim((xmin, xmax))
# self.axes.set_ylim((ymin, ymax))
# self.axes.set_position([x_ratio, y_ratio,
# 1 - 2 * x_ratio, 1 - 2 * y_ratio])
#
# self.canvas.queue_draw()
def load_defaults(self): def load_defaults(self):
""" """
Loads the aplication's default settings from defaults.json into Loads the aplication's default settings from defaults.json into
@ -1372,7 +1278,7 @@ class App:
for obj in self.stuff: for obj in self.stuff:
combo.append_text(obj) combo.append_text(obj)
def versionCheck(self): def versionCheck(self, *args):
""" """
Checks for the latest version of the program. Alerts the Checks for the latest version of the program. Alerts the
user if theirs is outdated. This method is meant to be run user if theirs is outdated. This method is meant to be run
@ -1989,9 +1895,6 @@ class App:
:return: None :return: None
""" """
# xmin, xmax = self.axes.get_xlim()
# ymin, ymax = self.axes.get_ylim()
# self.adjust_axes(xmin, ymin, xmax, ymax)
self.plotcanvas.auto_adjust_axes() self.plotcanvas.auto_adjust_axes()
def on_row_activated(self, widget, path, col): def on_row_activated(self, widget, path, col):
@ -2788,45 +2691,69 @@ class App:
class Measurement: class Measurement:
def __init__(self, axes, click_subscibers, move_subscribers, update=None): def __init__(self, container, axes, click_subscibers, move_subscribers, update=None):
self.update = update self.update = update
self.container = container
self.frame = None
self.label = None
self.axes = axes self.axes = axes
self.click_subscribers = click_subscibers self.click_subscribers = click_subscibers
self.move_subscribers = move_subscribers self.move_subscribers = move_subscribers
self.point1 = None self.point1 = None
self.point2 = None self.point2 = None
self.active = False self.active = False
self.at = None # AnchoredText object on plot # self.at = None # AnchoredText object on plot
def toggle_active(self): def toggle_active(self, *args):
if self.active: if self.active: # Deactivate
self.active = False self.active = False
self.move_subscribers.pop("meas") self.move_subscribers.pop("meas")
self.click_subscribers.pop("meas") self.click_subscribers.pop("meas")
self.at.remove() # self.at.remove()
self.container.remove(self.frame)
if self.update is not None: if self.update is not None:
self.update() self.update()
return False return False
else: else: # Activate
print "DEBUG: Activating Measurement Tool..."
self.active = True self.active = True
self.click_subscribers["meas"] = self.on_click self.click_subscribers["meas"] = self.on_click
self.move_subscribers["meas"] = self.on_move self.move_subscribers["meas"] = self.on_move
self.frame = Gtk.Frame()
self.frame.set_margin_right(5)
self.frame.set_margin_top(3)
align = Gtk.Alignment()
align.set(0, 0.5, 0, 0)
align.set_padding(4, 4, 4, 4)
self.label = Gtk.Label()
self.label.set_label("Measuring tool...")
align.add(self.label)
self.frame.add(align)
self.frame.set_size_request(200, 30)
self.frame.set_hexpand(True)
self.container.pack_end(self.frame, False, True, 1)
self.frame.show_all()
align.show_all()
self.label.show_all()
self.container.queue_draw()
return True return True
def on_move(self, event): def on_move(self, event):
try: # try:
self.at.remove() # self.at.remove()
except: # except:
pass # pass
if self.point1 is None: if self.point1 is None:
self.at = AnchoredText("Click on a reference point...") # self.at = AnchoredText("Click on a reference point...")
self.label.set_label("Click on a reference point...")
else: else:
dx = event.xdata - self.point1[0] dx = event.xdata - self.point1[0]
dy = event.ydata - self.point1[1] dy = event.ydata - self.point1[1]
d = sqrt(dx**2 + dy**2) d = sqrt(dx**2 + dy**2)
self.at = AnchoredText("D = %.4f\nD(x) = %.4f\nD(y) = %.4f" % (d, dx, dy), # self.at = AnchoredText("D = %.4f\nD(x) = %.4f\nD(y) = %.4f" % (d, dx, dy),
loc=2, prop={'size': 14}, frameon=False) # loc=2, prop={'size': 14}, frameon=False)
self.axes.add_artist(self.at) self.label.set_label("D = %.4f D(x) = %.4f D(y) = %.4f" % (d, dx, dy))
# self.axes.add_artist(self.at)
if self.update is not None: if self.update is not None:
self.update() self.update()
@ -2837,6 +2764,7 @@ class Measurement:
else: else:
self.point2 = copy.copy(self.point1) self.point2 = copy.copy(self.point1)
self.point1 = (event.xdata, event.ydata) self.point1 = (event.xdata, event.ydata)
self.on_move(event)
class PlotCanvas: class PlotCanvas:
@ -2877,7 +2805,7 @@ class PlotCanvas:
self.canvas.set_can_focus(True) # For key press self.canvas.set_can_focus(True) # For key press
# Attach to parent # Attach to parent
self.container.attach(self.canvas, 0, 0, 600, 400) self.container.attach(self.canvas, 0, 0, 600, 400) # TODO: Height and width are num. columns??
# Events # Events
self.canvas.mpl_connect('motion_notify_event', self.on_mouse_move) self.canvas.mpl_connect('motion_notify_event', self.on_mouse_move)

1851
FlatCAM.ui

File diff suppressed because it is too large Load Diff