Use of logging instead of print statements.

This commit is contained in:
Juan Pablo Caram
2014-05-02 22:10:04 -04:00
parent 0bdc3b19f0
commit 582e472e12
10 changed files with 746 additions and 939 deletions

View File

@@ -6,7 +6,7 @@
<property name="border_width">5</property>
<property name="type_hint">dialog</property>
<property name="program_name">FlatCAM</property>
<property name="version">Version Alpha 3 (2014/03) - UNSTABLE</property>
<property name="version">Version Alpha 5 (2014/05)</property>
<property name="copyright" translatable="yes">(c) 2014 Juan Pablo Caram</property>
<property name="comments" translatable="yes">2D Post-processing for Manufacturing specialized in
Printed Circuit Boards</property>

File diff suppressed because it is too large Load Diff

View File

@@ -13,7 +13,7 @@ from gi.repository import GObject
import inspect # TODO: Remove
from FlatCAMApp import *
import FlatCAMApp
from camlib import *
from ObjectUI import *
@@ -123,15 +123,15 @@ class FlatCAMObj(GObject.GObject, object):
"""
if self.axes is None:
print "New axes"
FlatCAMApp.App.log.debug("setup_axes(): New axes")
self.axes = figure.add_axes([0.05, 0.05, 0.9, 0.9],
label=self.options["name"])
elif self.axes not in figure.axes:
print "Clearing and attaching axes"
FlatCAMApp.App.log.debug("setup_axes(): Clearing and attaching axes")
self.axes.cla()
figure.add_axes(self.axes)
else:
print "Clearing Axes"
FlatCAMApp.App.log.debug("setup_axes(): Clearing Axes")
self.axes.cla()
# Remove all decoration. The app's axes will have
@@ -158,7 +158,7 @@ class FlatCAMObj(GObject.GObject, object):
:return: None
:rtype: None
"""
print inspect.stack()[1][3], "--> FlatCAMObj.read_form()"
FlatCAMApp.App.log.debug(str(inspect.stack()[1][3]) + "--> FlatCAMObj.read_form()")
for option in self.options:
self.read_form_item(option)
@@ -171,7 +171,7 @@ class FlatCAMObj(GObject.GObject, object):
"""
self.muted_ui = True
print inspect.stack()[1][3], "--> FlatCAMObj.build_ui()"
FlatCAMApp.App.log.debug(str(inspect.stack()[1][3]) + "--> FlatCAMObj.build_ui()")
# Where the UI for this object is drawn
# box_selected = self.app.builder.get_object("box_selected")
@@ -186,8 +186,8 @@ class FlatCAMObj(GObject.GObject, object):
# box_selected.pack_start(sw, True, True, 0)
box_selected.add(self.ui)
self.to_form()
box_selected.show_all()
self.ui.show()
GLib.idle_add(box_selected.show_all)
GLib.idle_add(self.ui.show_all)
self.muted_ui = False
def set_form_item(self, option):
@@ -202,7 +202,7 @@ class FlatCAMObj(GObject.GObject, object):
try:
self.form_fields[option].set_value(self.options[option])
except KeyError:
App.log.warn("Tried to set an option or field that does not exist: %s" % option)
self.app.log.warn("Tried to set an option or field that does not exist: %s" % option)
def read_form_item(self, option):
"""
@@ -216,7 +216,7 @@ class FlatCAMObj(GObject.GObject, object):
try:
self.options[option] = self.form_fields[option].get_value()
except KeyError:
App.log.warning("Failed to read option from field: %s" % option)
self.app.log.warning("Failed to read option from field: %s" % option)
def plot(self):
"""
@@ -497,8 +497,8 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
zorder=2)
self.axes.add_patch(patch)
except AssertionError:
print "WARNING: A geometry component was not a polygon:"
print poly
FlatCAMApp.App.log.warning("A geometry component was not a polygon:")
FlatCAMApp.App.log.warning(str(poly))
else:
for poly in geometry:
x, y = poly.exterior.xy
@@ -547,15 +547,6 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
"toolselection": ""
})
# self.form_kinds.update({
# "plot": "cb",
# "solid": "cb",
# "drillz": "entry_eval",
# "travelz": "entry_eval",
# "feedrate": "entry_eval",
# "toolselection": "entry_text"
# })
# TODO: Document this.
self.tool_cbs = {}
@@ -564,10 +555,49 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
# from predecessors.
self.ser_attrs += ['options', 'kind']
assert isinstance(self.ui, ExcellonObjectUI)
self.ui.plot_cb.connect('clicked', self.on_plot_cb_click)
self.ui.plot_cb.connect('activate', self.on_plot_cb_click)
self.ui.solid_cb.connect('clicked', self.on_solid_cb_click)
self.ui.solid_cb.connect('activate', self.on_solid_cb_click)
self.ui.choose_tools_button.connect('clicked', lambda args: self.show_tool_chooser())
self.ui.choose_tools_button.connect('activate', lambda args: self.show_tool_chooser())
self.ui.generate_cnc_button.connect('clicked', self.on_create_cncjob_button_click)
self.ui.generate_cnc_button.connect('activate', self.on_create_cncjob_button_click)
def on_create_cncjob_button_click(self, *args):
self.read_form()
job_name = self.options["name"] + "_cnc"
# Object initialization function for app.new_object()
def job_init(job_obj, app_obj):
assert isinstance(job_obj, FlatCAMCNCjob)
GLib.idle_add(lambda: app_obj.set_progress_bar(0.2, "Creating CNC Job..."))
job_obj.z_cut = self.options["drillz"]
job_obj.z_move = self.options["travelz"]
job_obj.feedrate = self.options["feedrate"]
# There could be more than one drill size...
# job_obj.tooldia = # TODO: duplicate variable!
# job_obj.options["tooldia"] =
job_obj.generate_from_excellon_by_tool(self, self.options["toolselection"])
GLib.idle_add(lambda: app_obj.set_progress_bar(0.5, "Parsing G-Code..."))
job_obj.gcode_parse()
GLib.idle_add(lambda: app_obj.set_progress_bar(0.6, "Creating New Geometry..."))
job_obj.create_geometry()
GLib.idle_add(lambda: app_obj.set_progress_bar(0.8, "Plotting..."))
# To be run in separate thread
def job_thread(app_obj):
app_obj.new_object("cncjob", job_name, job_init)
GLib.idle_add(lambda: app_obj.set_progress_bar(1.0, "Done!"))
GLib.timeout_add_seconds(1, lambda: app_obj.set_progress_bar(0.0, ""))
# Send to worker
self.app.worker.add_task(job_thread, [self.app])
def on_plot_cb_click(self, *args):
if self.muted_ui:
@@ -669,11 +699,6 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
"tooldia": self.ui.tooldia_entry
})
# self.form_kinds.update({
# "plot": "cb",
# "tooldia": "entry_eval"
# })
# Attributes to be included in serialization
# Always append to it because it carries contents
# from predecessors.
@@ -682,6 +707,18 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
self.ui.plot_cb.connect('clicked', self.on_plot_cb_click)
self.ui.plot_cb.connect('activate', self.on_plot_cb_click)
self.ui.export_gcode_button.connect('clicked', self.on_exportgcode_button_click)
self.ui.export_gcode_button.connect('activate', self.on_exportgcode_button_click)
def on_exportgcode_button_click(self, *args):
def on_success(app_obj, filename):
f = open(filename, 'w')
f.write(self.gcode)
f.close()
app_obj.info("Saved to: " + filename)
self.app.file_chooser_save_action(on_success)
def on_plot_cb_click(self, *args):
if self.muted_ui:
return
@@ -702,7 +739,7 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
def convert_units(self, units):
factor = CNCjob.convert_units(self, units)
print "FlatCAMCNCjob.convert_units()"
FlatCAMApp.App.log.debug("FlatCAMCNCjob.convert_units()")
self.options["tooldia"] *= factor
@@ -795,7 +832,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
geo_obj.options["cnctooldia"] = tooldia
name = self.options["name"] + "_paint"
self.new_object("geometry", name, gen_paintarea)
self.app.new_object("geometry", name, gen_paintarea)
subscription = self.app.plotcanvas.mpl_connect('button_press_event', doit)
@@ -934,7 +971,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.axes.plot(x, y, 'r-')
continue
print "WARNING: Did not plot:", str(type(geo))
FlatCAMApp.App.log.warning("Did not plot:", str(type(geo)))
#self.app.plotcanvas.auto_adjust_axes()
GLib.idle_add(self.app.plotcanvas.auto_adjust_axes)

View File

@@ -1,6 +1,15 @@
############################################################
# FlatCAM: 2D Post-processing for Manufacturing #
# http://caram.cl/software/flatcam #
# Author: Juan Pablo Caram (c) #
# Date: 2/5/2014 #
# MIT Licence #
############################################################
from gi.repository import Gtk
import re
from copy import copy
import FlatCAMApp
class RadioSet(Gtk.Box):
@@ -24,16 +33,20 @@ class RadioSet(Gtk.Box):
else:
choice['radio'] = Gtk.RadioButton.new_with_label_from_widget(self.group, choice['label'])
self.pack_start(choice['radio'], expand=True, fill=False, padding=2)
# choice['radio'].connect('toggled', self.on_toggle)
choice['radio'].connect('toggled', self.on_toggle)
# def on_toggle(self, *args):
# return
self.group_toggle_fn = lambda x, y: None
def on_toggle(self, btn):
if btn.get_active():
self.group_toggle_fn(btn, self.get_value)
return
def get_value(self):
for choice in self.choices:
if choice['radio'].get_active():
return choice['value']
print "ERROR: No button was toggled in RadioSet."
FlatCAMApp.App.log.error("No button was toggled in RadioSet.")
return None
def set_value(self, val):
@@ -41,7 +54,7 @@ class RadioSet(Gtk.Box):
if choice['value'] == val:
choice['radio'].set_active(True)
return
print "ERROR: Value given is not part of this RadioSet:", val
FlatCAMApp.App.log.error("Value given is not part of this RadioSet: %s" % str(val))
class LengthEntry(Gtk.Entry):
@@ -63,7 +76,7 @@ class LengthEntry(Gtk.Entry):
if val is not None:
self.set_text(str(val))
else:
print "WARNING: Could not interpret entry:", self.get_text()
FlatCAMApp.App.log.warning("Could not interpret entry: %s" % self.get_text())
def get_value(self):
raw = self.get_text().strip(' ')
@@ -76,7 +89,7 @@ class LengthEntry(Gtk.Entry):
else:
return float(match.group(1))
except:
print "ERROR: Could not parse value in entry:", raw
FlatCAMApp.App.log.error("Could not parse value in entry: %s" % str(raw))
return None
def set_value(self, val):
@@ -94,14 +107,14 @@ class FloatEntry(Gtk.Entry):
if val is not None:
self.set_text(str(val))
else:
print "WARNING: Could not interpret entry:", self.get_text()
FlatCAMApp.App.log.warning("Could not interpret entry: %s" % self.get_text())
def get_value(self):
raw = self.get_text().strip(' ')
try:
evaled = eval(raw)
except:
print "ERROR: Could not evaluate:", raw
FlatCAMApp.App.log.error("Could not evaluate: %s" % str(raw))
return None
return float(evaled)
@@ -132,6 +145,29 @@ class FCEntry(Gtk.Entry):
self.set_text(str(val))
class EvalEntry(Gtk.Entry):
def __init__(self):
Gtk.Entry.__init__(self)
def on_activate(self, *args):
val = self.get_value()
if val is not None:
self.set_text(str(val))
else:
FlatCAMApp.App.log.warning("Could not interpret entry: %s" % self.get_text())
def get_value(self):
raw = self.get_text().strip(' ')
try:
return eval(raw)
except:
FlatCAMApp.App.log.error("Could not evaluate: %s" % str(raw))
return None
def set_value(self, val):
self.set_text(str(val))
class FCCheckBox(Gtk.CheckButton):
def __init__(self, label=''):
Gtk.CheckButton.__init__(self, label=label)

View File

@@ -9,6 +9,7 @@
from FlatCAMObj import *
from gi.repository import Gtk, GdkPixbuf
import inspect # TODO: Remove
import FlatCAMApp
class ObjectCollection:
@@ -75,11 +76,11 @@ class ObjectCollection:
iterat = self.store.iter_next(iterat)
def delete_all(self):
print "OC.delete_all()"
FlatCAMApp.App.log.debug(str(inspect.stack()[1][3]) + "--> OC.delete_all()")
self.store.clear()
def delete_active(self):
print "OC.delete_active()"
FlatCAMApp.App.log.debug(str(inspect.stack()[1][3]) + "--> OC.delete_active()")
try:
model, treeiter = self.tree_selection.get_selected()
self.store.remove(treeiter)
@@ -94,7 +95,7 @@ class ObjectCollection:
:param selection: Ignored.
:return: None
"""
print inspect.stack()[1][3], "--> OC.on_list_selection_change()"
FlatCAMApp.App.log.debug(str(inspect.stack()[1][3]) + "--> OC.on_list_selection_change()")
try:
self.get_active().build_ui()
except AttributeError: # For None being active
@@ -109,11 +110,11 @@ class ObjectCollection:
:type name: str
:return: None
"""
print "OC.set_active()"
FlatCAMApp.App.log.debug(str(inspect.stack()[1][3]) + "--> OC.set_active()")
self.set_list_selection(name)
def get_active(self):
print inspect.stack()[1][3], "--> OC.get_active()"
FlatCAMApp.App.log.debug(str(inspect.stack()[1][3]) + "--> OC.get_active()")
try:
model, treeiter = self.tree_selection.get_selected()
return model[treeiter][0]
@@ -128,7 +129,7 @@ class ObjectCollection:
:rtype name: str
:return: None
"""
print inspect.stack()[1][3], "--> OC.set_list_selection()"
FlatCAMApp.App.log.debug(str(inspect.stack()[1][3]) + "--> OC.set_list_selection()")
iterat = self.store.get_iter_first()
while iterat is not None and self.store[iterat][0].options["name"] != name:
iterat = self.store.iter_next(iterat)
@@ -144,7 +145,7 @@ class ObjectCollection:
:type active: bool
:return: None
"""
print inspect.stack()[1][3], "--> OC.append()"
FlatCAMApp.App.log.debug(str(inspect.stack()[1][3]) + "--> OC.append()")
def guitask():
self.store.append([obj])
@@ -159,7 +160,7 @@ class ObjectCollection:
:return: List of names.
:rtype: list
"""
print "OC.get_names()"
FlatCAMApp.App.log.debug(str(inspect.stack()[1][3]) + "--> OC.get_names()")
names = []
iterat = self.store.get_iter_first()
while iterat is not None:
@@ -175,7 +176,7 @@ class ObjectCollection:
:return: [xmin, ymin, xmax, ymax]
:rtype: list
"""
print "OC.get_bounds()"
FlatCAMApp.App.log.debug(str(inspect.stack()[1][3]) + "--> OC.get_bounds()")
# TODO: Move the operation out of here.
@@ -194,7 +195,7 @@ class ObjectCollection:
xmax = max([xmax, gxmax])
ymax = max([ymax, gymax])
except:
print "DEV WARNING: Tried to get bounds of empty geometry."
FlatCAMApp.App.log.waring("DEV WARNING: Tried to get bounds of empty geometry.")
iterat = self.store.iter_next(iterat)
return [xmin, ymin, xmax, ymax]
@@ -205,6 +206,7 @@ class ObjectCollection:
:return: List with all FlatCAMObj.
:rtype: list
"""
FlatCAMApp.App.log.debug(str(inspect.stack()[1][3]) + "--> OC.get_list()")
collection_list = []
iterat = self.store.get_iter_first()
while iterat is not None:
@@ -222,6 +224,8 @@ class ObjectCollection:
:return: The requested object or None if no such object.
:rtype: FlatCAMObj or None
"""
FlatCAMApp.App.log.debug(str(inspect.stack()[1][3]) + "--> OC.get_by_name()")
iterat = self.store.get_iter_first()
while iterat is not None:
obj = self.store[iterat][0]

View File

@@ -1,12 +1,20 @@
############################################################
# FlatCAM: 2D Post-processing for Manufacturing #
# http://caram.cl/software/flatcam #
# Author: Juan Pablo Caram (c) #
# Date: 2/5/2014 #
# MIT Licence #
############################################################
from gi.repository import Gtk
import re
from copy import copy
from GUIElements import *
class ObjectUI(Gtk.VBox):
"""
Base class for the UI of FlatCAM objects.
"""
def __init__(self, icon_file='share/flatcam_icon32.png', title='FlatCAM Object'):
Gtk.VBox.__init__(self, spacing=3, margin=5, vexpand=False)
@@ -26,7 +34,7 @@ class ObjectUI(Gtk.VBox):
## Object name
self.name_box = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 2)
self.pack_start(self.name_box, expand=True, fill=False, padding=2)
self.pack_start(self.name_box, expand=False, fill=False, padding=2)
name_label = Gtk.Label('Name:')
name_label.set_justify(Gtk.Justification.RIGHT)
self.name_box.pack_start(name_label,
@@ -42,10 +50,10 @@ class ObjectUI(Gtk.VBox):
## Scale
self.scale_label = Gtk.Label(justify=Gtk.Justification.LEFT, xalign=0, margin_top=5)
self.scale_label.set_markup('<b>Scale:</b>')
self.pack_start(self.scale_label, expand=True, fill=False, padding=2)
self.pack_start(self.scale_label, expand=False, fill=False, padding=2)
grid5 = Gtk.Grid(column_spacing=3, row_spacing=2)
self.pack_start(grid5, expand=True, fill=False, padding=2)
self.pack_start(grid5, expand=False, fill=False, padding=2)
# Factor
l10 = Gtk.Label('Factor:', xalign=1)
@@ -56,25 +64,25 @@ class ObjectUI(Gtk.VBox):
# GO Button
self.scale_button = Gtk.Button(label='Scale')
self.pack_start(self.scale_button, expand=True, fill=False, padding=2)
self.pack_start(self.scale_button, expand=False, fill=False, padding=2)
## Offset
self.offset_label = Gtk.Label(justify=Gtk.Justification.LEFT, xalign=0, margin_top=5)
self.offset_label.set_markup('<b>Offset:</b>')
self.pack_start(self.offset_label, expand=True, fill=False, padding=2)
self.pack_start(self.offset_label, expand=False, fill=False, padding=2)
grid6 = Gtk.Grid(column_spacing=3, row_spacing=2)
self.pack_start(grid6, expand=True, fill=False, padding=2)
self.pack_start(grid6, expand=False, fill=False, padding=2)
# Vector
l11 = Gtk.Label('Offset Vector:', xalign=1)
grid6.attach(l11, 0, 0, 1, 1)
self.offsetvector_entry = FCEntry()
self.offsetvector_entry = EvalEntry()
self.offsetvector_entry.set_text("(0.0, 0.0)")
grid6.attach(self.offsetvector_entry, 1, 0, 1, 1)
self.offset_button = Gtk.Button(label='Scale')
self.pack_start(self.offset_button, expand=True, fill=False, padding=2)
self.pack_start(self.offset_button, expand=False, fill=False, padding=2)
def set_field(self, name, value):
getattr(self, name).set_value(value)
@@ -84,16 +92,20 @@ class ObjectUI(Gtk.VBox):
class CNCObjectUI(ObjectUI):
"""
User interface for CNCJob objects.
"""
def __init__(self):
ObjectUI.__init__(self, title='CNC Job Object', icon_file='share/cnc32.png')
## Plot options
self.plot_options_label = Gtk.Label(justify=Gtk.Justification.LEFT, xalign=0, margin_top=5)
self.plot_options_label.set_markup("<b>Plot Options:</b>")
self.pack_start(self.plot_options_label, expand=False, fill=True, padding=2)
self.custom_box.pack_start(self.plot_options_label, expand=False, fill=True, padding=2)
grid0 = Gtk.Grid(column_spacing=3, row_spacing=2)
self.pack_start(grid0, expand=True, fill=False, padding=2)
self.custom_box.pack_start(grid0, expand=False, fill=False, padding=2)
# Plot CB
self.plot_cb = FCCheckBox(label='Plot')
@@ -107,19 +119,23 @@ class CNCObjectUI(ObjectUI):
# Update plot button
self.updateplot_button = Gtk.Button(label='Update Plot')
self.pack_start(self.updateplot_button, expand=True, fill=False, padding=2)
self.custom_box.pack_start(self.updateplot_button, expand=False, fill=False, padding=2)
## Export G-Code
self.export_gcode_label = Gtk.Label(justify=Gtk.Justification.LEFT, xalign=0, margin_top=5)
self.export_gcode_label.set_markup("<b>Export G-Code:</b>")
self.pack_start(self.export_gcode_label, expand=True, fill=False, padding=2)
self.custom_box.pack_start(self.export_gcode_label, expand=False, fill=False, padding=2)
# GO Button
self.export_gcode_button = Gtk.Button(label='Export G-Code')
self.pack_start(self.export_gcode_button, expand=True, fill=False, padding=2)
self.custom_box.pack_start(self.export_gcode_button, expand=False, fill=False, padding=2)
class GeometryObjectUI(ObjectUI):
"""
User interface for Geometry objects.
"""
def __init__(self):
ObjectUI.__init__(self, title='Geometry Object', icon_file='share/geometry32.png')
@@ -200,6 +216,10 @@ class GeometryObjectUI(ObjectUI):
class ExcellonObjectUI(ObjectUI):
"""
User interface for Excellon objects.
"""
def __init__(self):
ObjectUI.__init__(self, title='Excellon Object', icon_file='share/drill32.png')
@@ -254,6 +274,9 @@ class ExcellonObjectUI(ObjectUI):
class GerberObjectUI(ObjectUI):
"""
User interface for Gerber objects.
"""
def __init__(self):
ObjectUI.__init__(self, title='Gerber Object')

310
PlotCanvas.py Normal file
View File

@@ -0,0 +1,310 @@
from gi.repository import Gdk
from matplotlib.figure import Figure
from matplotlib.backends.backend_gtk3agg import FigureCanvasGTK3Agg as FigureCanvas
#from FlatCAMApp import *
import FlatCAMApp
class PlotCanvas:
"""
Class handling the plotting area in the application.
"""
def __init__(self, container):
"""
The constructor configures the Matplotlib figure that
will contain all plots, creates the base axes and connects
events to the plotting area.
:param container: The parent container in which to draw plots.
:rtype: PlotCanvas
"""
# Options
self.x_margin = 15 # pixels
self.y_margin = 25 # Pixels
# Parent container
self.container = container
# Plots go onto a single matplotlib.figure
self.figure = Figure(dpi=50) # TODO: dpi needed?
self.figure.patch.set_visible(False)
# These axes show the ticks and grid. No plotting done here.
# New axes must have a label, otherwise mpl returns an existing one.
self.axes = self.figure.add_axes([0.05, 0.05, 0.9, 0.9], label="base", alpha=0.0)
self.axes.set_aspect(1)
self.axes.grid(True)
# The canvas is the top level container (Gtk.DrawingArea)
self.canvas = FigureCanvas(self.figure)
self.canvas.set_hexpand(1)
self.canvas.set_vexpand(1)
self.canvas.set_can_focus(True) # For key press
# Attach to parent
self.container.attach(self.canvas, 0, 0, 600, 400) # TODO: Height and width are num. columns??
# Events
self.canvas.mpl_connect('motion_notify_event', self.on_mouse_move)
self.canvas.connect('configure-event', self.auto_adjust_axes)
self.canvas.add_events(Gdk.EventMask.SMOOTH_SCROLL_MASK)
self.canvas.connect("scroll-event", self.on_scroll)
self.canvas.mpl_connect('key_press_event', self.on_key_down)
self.canvas.mpl_connect('key_release_event', self.on_key_up)
self.mouse = [0, 0]
self.key = None
def on_key_down(self, event):
"""
:param event:
:return:
"""
self.key = event.key
def on_key_up(self, event):
"""
:param event:
:return:
"""
self.key = None
def mpl_connect(self, event_name, callback):
"""
Attach an event handler to the canvas through the Matplotlib interface.
:param event_name: Name of the event
:type event_name: str
:param callback: Function to call
:type callback: func
:return: Connection id
:rtype: int
"""
return self.canvas.mpl_connect(event_name, callback)
def mpl_disconnect(self, cid):
"""
Disconnect callback with the give id.
:param cid: Callback id.
:return: None
"""
self.canvas.mpl_disconnect(cid)
def connect(self, event_name, callback):
"""
Attach an event handler to the canvas through the native GTK interface.
:param event_name: Name of the event
:type event_name: str
:param callback: Function to call
:type callback: function
:return: Nothing
"""
self.canvas.connect(event_name, callback)
def clear(self):
"""
Clears axes and figure.
:return: None
"""
# Clear
self.axes.cla()
try:
self.figure.clf()
except KeyError:
FlatCAMApp.App.log.warning("KeyError in MPL figure.clf()")
# Re-build
self.figure.add_axes(self.axes)
self.axes.set_aspect(1)
self.axes.grid(True)
# Re-draw
self.canvas.queue_draw()
def adjust_axes(self, xmin, ymin, xmax, ymax):
"""
Adjusts all axes 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
"""
FlatCAMApp.App.log.debug("PC.adjust_axes()")
width = xmax - xmin
height = ymax - ymin
try:
r = width / height
except ZeroDivisionError:
FlatCAMApp.App.log.error("Height is %f" % height)
return
canvas_w, canvas_h = self.canvas.get_width_height()
canvas_r = float(canvas_w) / canvas_h
x_ratio = float(self.x_margin) / canvas_w
y_ratio = float(self.y_margin) / canvas_h
if r > canvas_r:
ycenter = (ymin + ymax) / 2.0
newheight = height * r / canvas_r
ymin = ycenter - newheight / 2.0
ymax = ycenter + newheight / 2.0
else:
xcenter = (xmax + xmin) / 2.0
newwidth = width * canvas_r / r
xmin = xcenter - newwidth / 2.0
xmax = xcenter + newwidth / 2.0
# Adjust axes
for ax in self.figure.get_axes():
if ax._label != 'base':
ax.set_frame_on(False) # No frame
ax.set_xticks([]) # No tick
ax.set_yticks([]) # No ticks
ax.patch.set_visible(False) # No background
ax.set_aspect(1)
ax.set_xlim((xmin, xmax))
ax.set_ylim((ymin, ymax))
ax.set_position([x_ratio, y_ratio, 1 - 2 * x_ratio, 1 - 2 * y_ratio])
# Re-draw
self.canvas.queue_draw()
def auto_adjust_axes(self, *args):
"""
Calls ``adjust_axes()`` using the extents of the base axes.
:rtype : None
:return: None
"""
xmin, xmax = self.axes.get_xlim()
ymin, ymax = self.axes.get_ylim()
self.adjust_axes(xmin, ymin, xmax, ymax)
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 or center == [None, 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
# Adjust axes
for ax in self.figure.get_axes():
ax.set_xlim((xmin, xmax))
ax.set_ylim((ymin, ymax))
# Re-draw
self.canvas.queue_draw()
def pan(self, x, y):
xmin, xmax = self.axes.get_xlim()
ymin, ymax = self.axes.get_ylim()
width = xmax - xmin
height = ymax - ymin
# Adjust axes
for ax in self.figure.get_axes():
ax.set_xlim((xmin + x*width, xmax + x*width))
ax.set_ylim((ymin + y*height, ymax + y*height))
# Re-draw
self.canvas.queue_draw()
def new_axes(self, name):
"""
Creates and returns an Axes object attached to this object's Figure.
:param name: Unique label for the axes.
:return: Axes attached to the figure.
:rtype: Axes
"""
return self.figure.add_axes([0.05, 0.05, 0.9, 0.9], label=name)
def on_scroll(self, canvas, event):
"""
Scroll event handler.
:param canvas: The widget generating the event. Ignored.
:param event: Event object containing the event information.
:return: None
"""
# So it can receive key presses
self.canvas.grab_focus()
# Event info
z, direction = event.get_scroll_direction()
if self.key is None:
if direction is Gdk.ScrollDirection.UP:
self.zoom(1.5, self.mouse)
else:
self.zoom(1/1.5, self.mouse)
return
if self.key == 'shift':
if direction is Gdk.ScrollDirection.UP:
self.pan(0.3, 0)
else:
self.pan(-0.3, 0)
return
if self.key == 'ctrl+control':
if direction is Gdk.ScrollDirection.UP:
self.pan(0, 0.3)
else:
self.pan(0, -0.3)
return
def on_mouse_move(self, event):
"""
Mouse movement event hadler. Stores the coordinates.
:param event: Contains information about the event.
:return: None
"""
self.mouse = [event.xdata, event.ydata]

View File

@@ -27,6 +27,15 @@ import simplejson as json
# TODO: Commented for FlatCAM packaging with cx_freeze
#from matplotlib.pyplot import plot
import logging
log = logging.getLogger('base2')
log.setLevel(logging.DEBUG)
formatter = logging.Formatter('[%(levelname)s] %(message)s')
handler = logging.StreamHandler()
handler.setFormatter(formatter)
log.addHandler(handler)
class Geometry(object):
def __init__(self):
@@ -57,7 +66,7 @@ class Geometry(object):
of geometry: (xmin, ymin, xmax, ymax).
"""
if self.solid_geometry is None:
print "Warning: solid_geometry not computed yet."
log.warning("solid_geometry not computed yet.")
return (0, 0, 0, 0)
if type(self.solid_geometry) == list:
@@ -72,7 +81,7 @@ class Geometry(object):
bounds of geometry.
"""
if self.solid_geometry is None:
print "Warning: solid_geometry not computed yet."
log.warning("Solid_geometry not computed yet.")
return 0
bounds = self.bounds()
return (bounds[2]-bounds[0], bounds[3]-bounds[1])
@@ -133,7 +142,7 @@ class Geometry(object):
:return: Scaling factor resulting from unit change.
:rtype: float
"""
print "Geometry.convert_units()"
log.debug("Geometry.convert_units()")
if units.upper() == self.units.upper():
return 1.0
@@ -143,7 +152,7 @@ class Geometry(object):
elif units.upper() == "IN":
factor = 1/25.4
else:
print "Unsupported units:", units
log.error("Unsupported units: %s" % str(units))
return 1.0
self.units = units
@@ -293,7 +302,7 @@ class ApertureMacro:
self.primitives.append([eval(x) for x in elements])
continue
print "WARNING: Unknown syntax of aperture macro part:", part
log.warning("Unknown syntax of aperture macro part: %s" % str(part))
def append(self, data):
"""
@@ -834,7 +843,7 @@ class Gerber (Geometry):
"modifiers": paramList}
return apid
print "WARNING: Aperture not implemented:", apertureType
log.warning("Aperture not implemented: %s" % str(apertureType))
return None
def parse_file(self, filename):
@@ -975,7 +984,7 @@ class Gerber (Geometry):
geo = Polygon(path)
else:
if last_path_aperture is None:
print "Warning: No aperture defined for curent path. (%d)" % line_num
log.warning("No aperture defined for curent path. (%d)" % line_num)
width = self.apertures[last_path_aperture]["size"]
geo = LineString(path).buffer(width/2)
poly_buffer.append(geo)
@@ -1016,13 +1025,13 @@ class Gerber (Geometry):
j = 0
if quadrant_mode is None:
print "ERROR: Found arc without preceding quadrant specification G74 or G75. (%d)" % line_num
print gline
log.error("Found arc without preceding quadrant specification G74 or G75. (%d)" % line_num)
log.error(gline)
continue
if mode is None and current_interpolation_mode not in [2, 3]:
print "ERROR: Found arc without circular interpolation mode defined. (%d)" % line_num
print gline
log.error("Found arc without circular interpolation mode defined. (%d)" % line_num)
log.error(gline)
continue
elif mode is not None:
current_interpolation_mode = int(mode)
@@ -1033,10 +1042,10 @@ class Gerber (Geometry):
# Nothing created! Pen Up.
if current_operation_code == 2:
print "Warning: Arc with D2. (%d)" % line_num
log.warning("Arc with D2. (%d)" % line_num)
if len(path) > 1:
if last_path_aperture is None:
print "Warning: No aperture defined for curent path. (%d)" % line_num
log.warning("No aperture defined for curent path. (%d)" % line_num)
# --- BUFFERED ---
width = self.apertures[last_path_aperture]["size"]
@@ -1050,7 +1059,7 @@ class Gerber (Geometry):
# Flash should not happen here
if current_operation_code == 3:
print "ERROR: Trying to flash within arc. (%d)" % line_num
log.error("Trying to flash within arc. (%d)" % line_num)
continue
if quadrant_mode == 'MULTI':
@@ -1075,7 +1084,7 @@ class Gerber (Geometry):
continue
if quadrant_mode == 'SINGLE':
print "Warning: Single quadrant arc are not implemented yet. (%d)" % line_num
log.warning("Single quadrant arc are not implemented yet. (%d)" % line_num)
### Operation code alone
match = self.opcode_re.search(gline)
@@ -1228,7 +1237,7 @@ class Gerber (Geometry):
continue
### Line did not match any pattern. Warn user.
print "WARNING: Line ignored (%d):" % line_num, gline
log.warning("Line ignored (%d): %s" % (line_num, gline))
if len(path) > 1:
# EOF, create shapely LineString if something still in path
@@ -1528,7 +1537,7 @@ class Excellon(Geometry):
y = current_y
if x is None or y is None:
print "ERROR: Missing coordinates"
log.error("Missing coordinates")
continue
self.drills.append({'point': Point((x, y)), 'tool': current_tool})
@@ -1550,7 +1559,7 @@ class Excellon(Geometry):
y = current_y
if x is None or y is None:
print "ERROR: Missing coordinates"
log.error("Missing coordinates")
continue
self.drills.append({'point': Point((x, y)), 'tool': current_tool})
@@ -1581,7 +1590,7 @@ class Excellon(Geometry):
self.units = {"INCH": "IN", "METRIC": "MM"}[match.group(1)]
continue
print "WARNING: Line ignored:", eline
log.warning("Line ignored: %s" % eline)
def parse_number(self, number_str):
"""
@@ -1724,7 +1733,7 @@ class CNCjob(Geometry):
def convert_units(self, units):
factor = Geometry.convert_units(self, units)
print "CNCjob.convert_units()"
log.debug("CNCjob.convert_units()")
self.z_cut *= factor
self.z_move *= factor
@@ -1783,20 +1792,20 @@ class CNCjob(Geometry):
:return: None
:rtype: None
"""
print "Creating CNC Job from Excellon..."
log.debug("Creating CNC Job from Excellon...")
if tools == "all":
tools = [tool for tool in exobj.tools]
else:
tools = [x.strip() for x in tools.split(",")]
tools = filter(lambda i: i in exobj.tools, tools)
print "Tools are:", tools
log.debug("Tools are: %s" % str(tools))
points = []
for drill in exobj.drills:
if drill['tool'] in tools:
points.append(drill['point'])
print "Found %d drills." % len(points)
log.debug("Found %d drills." % len(points))
#self.kind = "drill"
self.gcode = []
@@ -1873,8 +1882,8 @@ class CNCjob(Geometry):
self.gcode += self.polygon2gcode(poly, tolerance=tolerance)
continue
print "WARNING: G-code generation not implemented for %s" % (str(type(geo)))
log.warning("G-code generation not implemented for %s" % (str(type(geo))))
self.gcode += "G00 Z%.4f\n" % self.z_move # Stop cutting
self.gcode += "G00 X0Y0\n"
self.gcode += "M05\n" # Spindle stop
@@ -1967,8 +1976,8 @@ class CNCjob(Geometry):
## Changing height
if 'Z' in gobj:
if ('X' in gobj or 'Y' in gobj) and gobj['Z'] != current['Z']:
print "WARNING: Non-orthogonal motion: From", current
print " To:", gobj
log.warning("Non-orthogonal motion: From %s" % str(current))
log.warning(" To: %s" % str(gobj))
current['Z'] = gobj['Z']
# Store the path into geometry and reset path
if len(path) > 1:
@@ -2239,7 +2248,7 @@ def get_bounds(geometry_list):
xmax = max([xmax, gxmax])
ymax = max([ymax, gymax])
except:
print "DEV WARNING: Tried to get bounds of empty geometry."
log.warning("DEVELOPMENT: Tried to get bounds of empty geometry.")
return [xmin, ymin, xmax, ymax]
@@ -2392,7 +2401,7 @@ def plotg(geo):
_ = iter(g)
plotg(g)
except:
print "Cannot plot:", str(type(g))
log.error("Cannot plot: " + str(type(g)))
continue

View File

@@ -1 +1 @@
{"gerber_noncopperrounded": false, "geometry_paintoverlap": 0.15, "geometry_plot": true, "excellon_feedrate": 5.0, "gerber_plot": true, "excellon_drillz": -0.1, "geometry_feedrate": 3.0, "units": "IN", "excellon_travelz": 0.1, "gerber_multicolored": false, "gerber_solid": true, "gerber_isopasses": 1, "excellon_plot": true, "gerber_isotooldia": 0.016, "cncjob_tooldia": 0.016, "geometry_travelz": 0.1, "gerber_cutoutmargin": 0.2, "excellon_solid": false, "geometry_paintmargin": 0.01, "geometry_cutz": -0.002, "geometry_cnctooldia": 0.016, "gerber_cutouttooldia": 0.07, "geometry_painttooldia": 0.0625, "gerber_gaps": "4", "gerber_bboxmargin": 0.0, "cncjob_plot": true, "gerber_cutoutgapsize": 0.15, "gerber_isooverlap": 0.15, "gerber_bboxrounded": false, "geometry_multicolored": false, "gerber_noncoppermargin": 0.0, "geometry_solid": false}
{"gerber_noncopperrounded": false, "geometry_paintoverlap": 0.15, "geometry_plot": true, "excellon_feedrate": 5.0, "gerber_plot": true, "excellon_drillz": -0.1, "geometry_feedrate": 3.0, "units": "IN", "excellon_travelz": 0.1, "gerber_multicolored": false, "gerber_solid": true, "gerber_isopasses": 1, "excellon_plot": true, "gerber_isotooldia": 0.016, "gerber_bboxmargin": 0.0, "cncjob_tooldia": 0.016, "geometry_travelz": 0.1, "gerber_cutoutmargin": 0.2, "excellon_solid": false, "geometry_paintmargin": 0.01, "geometry_cutz": -0.002, "geometry_cnctooldia": 0.016, "gerber_cutouttooldia": 0.07, "gerber_gaps": "4", "geometry_painttooldia": 0.0625, "cncjob_plot": true, "gerber_cutoutgapsize": 0.15, "gerber_isooverlap": 0.15, "gerber_bboxrounded": false, "gerber_noncoppermargin": 0.0}

View File

@@ -1 +1 @@
[{"kind": "project", "filename": "C:\\Users\\jpcaram\\Dropbox\\VNA\\KiCad_Bridge2\\Bridge2.fcproj"}, {"kind": "excellon", "filename": "C:\\Users\\jpcaram\\Dropbox\\PhD\\Kenney\\Project Outputs for AnalogPredistortion1\\apd.TXT"}, {"kind": "gerber", "filename": "C:\\Users\\jpcaram\\Dropbox\\PhD\\Kenney\\Project Outputs for AnalogPredistortion1\\apd.GTL"}, {"kind": "excellon", "filename": "C:\\Users\\jpcaram\\Dropbox\\VNA\\KiCad_Bridge2\\KiCad_Bridge2.drl"}, {"kind": "excellon", "filename": "C:\\Users\\jpcaram\\Dropbox\\CNC\\pcbcam\\test_files\\LockController_v1.0_pcb-RoundHoles.TXT\\LockController_v1.0_pcb-RoundHoles.TXT"}, {"kind": "gerber", "filename": "C:\\Users\\jpcaram\\Dropbox\\VNA\\KiCad_Bridge2\\KiCad_Bridge2-F_Cu.gtl"}, {"kind": "gerber", "filename": "C:\\Users\\jpcaram\\Dropbox\\CNC\\pcbcam\\test_files\\WindMills - Bottom Copper 2.gbr"}, {"kind": "gerber", "filename": "C:\\Users\\jpcaram\\Dropbox\\CNC\\pcbcam\\test_files\\Example1_copper_bottom_Gndplane_modified.gbr"}, {"kind": "gerber", "filename": "C:\\Users\\jpcaram\\Dropbox\\CNC\\pcbcam\\test_files\\Example1_copper_bottom_Gndplane.gbr"}, {"kind": "gerber", "filename": "C:\\Users\\jpcaram\\Dropbox\\CNC\\pcbcam\\test_files\\CC_LOAD_7000164-00_REV_A_copper_top.gbr"}]
[{"kind": "gerber", "filename": "C:\\Users\\jpcaram\\Dropbox\\CNC\\pcbcam\\test_files\\bedini 7 coils capacitor discharge.gbr"}, {"kind": "cncjob", "filename": "C:\\Users\\jpcaram\\Dropbox\\CNC\\test.cnc"}, {"kind": "project", "filename": "C:\\Users\\jpcaram\\Dropbox\\VNA\\KiCad_Bridge2\\Bridge2_test.fcproj"}, {"kind": "gerber", "filename": "C:\\Users\\jpcaram\\Dropbox\\CNC\\Controller_Board_Shield\\CBS-B_Cu.gbl"}, {"kind": "cncjob", "filename": "C:\\Users\\jpcaram\\Dropbox\\CNC\\squarerpcb\\KiCad_Squarer.gcode"}, {"kind": "excellon", "filename": "C:\\Users\\jpcaram\\Dropbox\\VNA\\KiCad_Squarer\\KiCad_Squarer.drl"}, {"kind": "gerber", "filename": "C:\\Users\\jpcaram\\Dropbox\\VNA\\KiCad_Squarer\\KiCad_Squarer-F_Cu.gtl"}, {"kind": "project", "filename": "C:\\Users\\jpcaram\\Dropbox\\VNA\\KiCad_Bridge2\\Bridge2.fcproj"}, {"kind": "excellon", "filename": "C:\\Users\\jpcaram\\Dropbox\\PhD\\Kenney\\Project Outputs for AnalogPredistortion1\\apd.TXT"}, {"kind": "gerber", "filename": "C:\\Users\\jpcaram\\Dropbox\\PhD\\Kenney\\Project Outputs for AnalogPredistortion1\\apd.GTL"}]