From a0bd34de451826ba0648a35eeb505fa55bf9c50c Mon Sep 17 00:00:00 2001 From: Juan Pablo Caram Date: Sun, 10 Apr 2016 15:44:17 -0400 Subject: [PATCH 1/5] Fixes #198 --- descartes/patch.py | 66 ---------------------------------------------- 1 file changed, 66 deletions(-) delete mode 100644 descartes/patch.py diff --git a/descartes/patch.py b/descartes/patch.py deleted file mode 100644 index 34686f78..00000000 --- a/descartes/patch.py +++ /dev/null @@ -1,66 +0,0 @@ -"""Paths and patches""" - -from matplotlib.patches import PathPatch -from matplotlib.path import Path -from numpy import asarray, concatenate, ones - - -class Polygon(object): - # Adapt Shapely or GeoJSON/geo_interface polygons to a common interface - def __init__(self, context): - if hasattr(context, 'interiors'): - self.context = context - else: - self.context = getattr(context, '__geo_interface__', context) - @property - def geom_type(self): - return (getattr(self.context, 'geom_type', None) - or self.context['type']) - @property - def exterior(self): - return (getattr(self.context, 'exterior', None) - or self.context['coordinates'][0]) - @property - def interiors(self): - value = getattr(self.context, 'interiors', None) - if value is None: - value = self.context['coordinates'][1:] - return value - - -def PolygonPath(polygon): - """Constructs a compound matplotlib path from a Shapely or GeoJSON-like - geometric object""" - this = Polygon(polygon) - assert this.geom_type == 'Polygon' - def coding(ob): - # The codes will be all "LINETO" commands, except for "MOVETO"s at the - # beginning of each subpath - n = len(getattr(ob, 'coords', None) or ob) - vals = ones(n, dtype=Path.code_type) * Path.LINETO - vals[0] = Path.MOVETO - return vals - vertices = concatenate( - [asarray(this.exterior)] - + [asarray(r) for r in this.interiors]) - codes = concatenate( - [coding(this.exterior)] - + [coding(r) for r in this.interiors]) - return Path(vertices, codes) - - -def PolygonPatch(polygon, **kwargs): - """Constructs a matplotlib patch from a geometric object - - The `polygon` may be a Shapely or GeoJSON-like object with or without holes. - The `kwargs` are those supported by the matplotlib.patches.Polygon class - constructor. Returns an instance of matplotlib.patches.PathPatch. - - Example (using Shapely Point and a matplotlib axes): - - >>> b = Point(0, 0).buffer(1.0) - >>> patch = PolygonPatch(b, fc='blue', ec='blue', alpha=0.5) - >>> axis.add_patch(patch) - - """ - return PathPatch(PolygonPath(polygon), **kwargs) From bac9f29d0889a0154f0cc08093e96687eec7f34f Mon Sep 17 00:00:00 2001 From: Juan Pablo Caram Date: Sun, 10 Apr 2016 15:48:25 -0400 Subject: [PATCH 2/5] Recovered patch.py --- descartes/patch.py | 66 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 descartes/patch.py diff --git a/descartes/patch.py b/descartes/patch.py new file mode 100644 index 00000000..34686f78 --- /dev/null +++ b/descartes/patch.py @@ -0,0 +1,66 @@ +"""Paths and patches""" + +from matplotlib.patches import PathPatch +from matplotlib.path import Path +from numpy import asarray, concatenate, ones + + +class Polygon(object): + # Adapt Shapely or GeoJSON/geo_interface polygons to a common interface + def __init__(self, context): + if hasattr(context, 'interiors'): + self.context = context + else: + self.context = getattr(context, '__geo_interface__', context) + @property + def geom_type(self): + return (getattr(self.context, 'geom_type', None) + or self.context['type']) + @property + def exterior(self): + return (getattr(self.context, 'exterior', None) + or self.context['coordinates'][0]) + @property + def interiors(self): + value = getattr(self.context, 'interiors', None) + if value is None: + value = self.context['coordinates'][1:] + return value + + +def PolygonPath(polygon): + """Constructs a compound matplotlib path from a Shapely or GeoJSON-like + geometric object""" + this = Polygon(polygon) + assert this.geom_type == 'Polygon' + def coding(ob): + # The codes will be all "LINETO" commands, except for "MOVETO"s at the + # beginning of each subpath + n = len(getattr(ob, 'coords', None) or ob) + vals = ones(n, dtype=Path.code_type) * Path.LINETO + vals[0] = Path.MOVETO + return vals + vertices = concatenate( + [asarray(this.exterior)] + + [asarray(r) for r in this.interiors]) + codes = concatenate( + [coding(this.exterior)] + + [coding(r) for r in this.interiors]) + return Path(vertices, codes) + + +def PolygonPatch(polygon, **kwargs): + """Constructs a matplotlib patch from a geometric object + + The `polygon` may be a Shapely or GeoJSON-like object with or without holes. + The `kwargs` are those supported by the matplotlib.patches.Polygon class + constructor. Returns an instance of matplotlib.patches.PathPatch. + + Example (using Shapely Point and a matplotlib axes): + + >>> b = Point(0, 0).buffer(1.0) + >>> patch = PolygonPatch(b, fc='blue', ec='blue', alpha=0.5) + >>> axis.add_patch(patch) + + """ + return PathPatch(PolygonPath(polygon), **kwargs) From 7112ac5caf115abc4961a2eeafb129cfb5d7280b Mon Sep 17 00:00:00 2001 From: Juan Pablo Caram Date: Sun, 10 Apr 2016 16:02:38 -0400 Subject: [PATCH 3/5] Recovered patch.py --- FlatCAM.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/FlatCAM.py b/FlatCAM.py index 1cb60c9f..46cfc307 100644 --- a/FlatCAM.py +++ b/FlatCAM.py @@ -1,10 +1,13 @@ import sys from PyQt4 import QtGui -from PyQt4 import QtCore from FlatCAMApp import App + def debug_trace(): - '''Set a tracepoint in the Python debugger that works with Qt''' + """ + Set a tracepoint in the Python debugger that works with Qt + :return: None + """ from PyQt4.QtCore import pyqtRemoveInputHook #from pdb import set_trace pyqtRemoveInputHook() @@ -12,9 +15,10 @@ def debug_trace(): debug_trace() -# all X11 calling should be thread safe otherwise we have strange issues -QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_X11InitThreads) +# All X11 calling should be thread safe otherwise we have strange issues +# QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_X11InitThreads) +# NOTE: Never talk to the GUI from threads! This is why I commented the above. app = QtGui.QApplication(sys.argv) fc = App() -sys.exit(app.exec_()) \ No newline at end of file +sys.exit(app.exec_()) From 3717169105a89eb9bd481367cc942d09e553efcb Mon Sep 17 00:00:00 2001 From: Juan Pablo Caram Date: Sun, 10 Apr 2016 16:23:04 -0400 Subject: [PATCH 4/5] Default excellon milling tool dia. Fixes #160. --- FlatCAMApp.py | 2 ++ FlatCAMGUI.py | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/FlatCAMApp.py b/FlatCAMApp.py index 872a6e4f..6c0701b0 100644 --- a/FlatCAMApp.py +++ b/FlatCAMApp.py @@ -231,6 +231,7 @@ class App(QtCore.QObject): "excellon_feedrate": self.defaults_form.excellon_group.feedrate_entry, "excellon_spindlespeed": self.defaults_form.excellon_group.spindlespeed_entry, "excellon_toolchangez": self.defaults_form.excellon_group.toolchangez_entry, + "excellon_tooldia": self.defaults_form.excellon_group.tooldia_entry, "geometry_plot": self.defaults_form.geometry_group.plot_cb, "geometry_cutz": self.defaults_form.geometry_group.cutz_entry, "geometry_travelz": self.defaults_form.geometry_group.travelz_entry, @@ -360,6 +361,7 @@ class App(QtCore.QObject): "excellon_feedrate": self.options_form.excellon_group.feedrate_entry, "excellon_spindlespeed": self.options_form.excellon_group.spindlespeed_entry, "excellon_toolchangez": self.options_form.excellon_group.toolchangez_entry, + "excellon_tooldia": self.options_form.excellon_group.tooldia_entry, "geometry_plot": self.options_form.geometry_group.plot_cb, "geometry_cutz": self.options_form.geometry_group.cutz_entry, "geometry_travelz": self.options_form.geometry_group.travelz_entry, diff --git a/FlatCAMGUI.py b/FlatCAMGUI.py index 3c01d124..2ec95ac3 100644 --- a/FlatCAMGUI.py +++ b/FlatCAMGUI.py @@ -607,6 +607,23 @@ class ExcellonOptionsGroupUI(OptionsGroupUI): self.spindlespeed_entry = IntEntry(allow_empty=True) grid1.addWidget(self.spindlespeed_entry, 4, 1) + #### Milling Holes #### + self.mill_hole_label = QtGui.QLabel('Mill Holes') + self.mill_hole_label.setToolTip( + "Create Geometry for milling holes." + ) + self.layout.addWidget(self.mill_hole_label) + + grid1 = QtGui.QGridLayout() + self.layout.addLayout(grid1) + tdlabel = QtGui.QLabel('Tool dia:') + tdlabel.setToolTip( + "Diameter of the cutting tool." + ) + grid1.addWidget(tdlabel, 0, 0) + self.tooldia_entry = LengthEntry() + grid1.addWidget(self.tooldia_entry, 0, 1) + class GeometryOptionsGroupUI(OptionsGroupUI): def __init__(self, parent=None): From d28858ff38f419a6c9a173a8a9b398928beb4e58 Mon Sep 17 00:00:00 2001 From: Juan Pablo Caram Date: Sun, 10 Apr 2016 16:43:03 -0400 Subject: [PATCH 5/5] Fast vertical movement above board. Fixes #141. --- camlib.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/camlib.py b/camlib.py index 7c0cd11a..d66a71fd 100644 --- a/camlib.py +++ b/camlib.py @@ -2782,7 +2782,9 @@ class CNCjob(Geometry): else: selected_tools = [x.strip() for x in tools.split(",")] # we strip spaces and also separate the tools by ',' selected_tools = filter(lambda i: i in selected_tools, selected_tools) - tools = [i for i,j in sorted_tools for k in selected_tools if i == k] # create a sorted list of selected tools from the sorted_tools list + + # Create a sorted list of selected tools from the sorted_tools list + tools = [i for i, j in sorted_tools for k in selected_tools if i == k] log.debug("Tools selected and sorted are: %s" % str(tools)) # Points (Group by tool) @@ -2800,7 +2802,8 @@ class CNCjob(Geometry): # Basic G-Code macros t = "G00 " + CNCjob.defaults["coordinate_format"] + "\n" down = "G01 Z%.4f\n" % self.z_cut - up = "G01 Z%.4f\n" % self.z_move + up = "G00 Z%.4f\n" % self.z_move + up_to_zero = "G01 Z0\n" # Initialization gcode = self.unitcode[self.units.upper()] + "\n" @@ -2810,7 +2813,8 @@ class CNCjob(Geometry): gcode += "G00 Z%.4f\n" % self.z_move # Move to travel height if self.spindlespeed is not None: - gcode += "M03 S%d\n" % int(self.spindlespeed) # Spindle start with configured speed + # Spindle start with configured speed + gcode += "M03 S%d\n" % int(self.spindlespeed) else: gcode += "M03\n" # Spindle start @@ -2818,7 +2822,7 @@ class CNCjob(Geometry): for tool in tools: - # only if tool have some points, otherwise thre may be error and this part is useless + # Only if tool has points. if tool in points: # Tool change sequence (optional) if toolchange: @@ -2829,7 +2833,8 @@ class CNCjob(Geometry): gcode += "(MSG, Change to tool dia=%.4f)\n" % exobj.tools[tool]["C"] gcode += "M0\n" # Temporary machine stop if self.spindlespeed is not None: - gcode += "M03 S%d\n" % int(self.spindlespeed) # Spindle start with configured speed + # Spindle start with configured speed + gcode += "M03 S%d\n" % int(self.spindlespeed) else: gcode += "M03\n" # Spindle start @@ -2837,7 +2842,7 @@ class CNCjob(Geometry): for point in points[tool]: x, y = point.coords.xy gcode += t % (x[0], y[0]) - gcode += down + up + gcode += down + up_to_zero + up gcode += t % (0, 0) gcode += "M05\n" # Spindle stop