Added OS-X installation instructions to manual.

This commit is contained in:
jpcaram
2014-12-27 15:12:49 -05:00
parent 6fae5258db
commit a0d6d1a6a9
5 changed files with 141 additions and 61 deletions

View File

@@ -2419,16 +2419,18 @@ class App(QtCore.QObject):
try: try:
f = open(filename, 'w') f = open(filename, 'w')
except IOError: except IOError:
App.log.error("[error] Failed to open file for saving:", filename) App.log.error("[error] Failed to open file for saving: %s", filename)
return return
# Write # Write
try: json.dump(d, f, default=to_dict)
json.dump(d, f, default=to_dict) # try:
except: # json.dump(d, f, default=to_dict)
App.log.error("[error] File open but failed to write:", filename) # except Exception, e:
f.close() # print str(e)
return # App.log.error("[error] File open but failed to write: %s", filename)
# f.close()
# return
f.close() f.close()

View File

@@ -800,7 +800,6 @@ class FlatCAMDraw(QtCore.QObject):
self.shape_buffer.remove(shape) self.shape_buffer.remove(shape)
# Add the new utility shape # Add the new utility shape
#self.shape_buffer.append(geo)
self.add_shape(geo) self.add_shape(geo)
# Efficient plotting for fast animation # Efficient plotting for fast animation
@@ -811,13 +810,12 @@ class FlatCAMDraw(QtCore.QObject):
self.axes.draw_artist(el) self.axes.draw_artist(el)
#self.canvas.canvas.blit(self.axes.bbox) #self.canvas.canvas.blit(self.axes.bbox)
#self.replot() # Pointer (snapped)
elements = self.axes.plot(x, y, 'bo', animated=True)
for el in elements:
self.axes.draw_artist(el)
elements = self.axes.plot(x, y, 'bo', animated=True) self.canvas.canvas.blit(self.axes.bbox)
for el in elements:
self.axes.draw_artist(el)
self.canvas.canvas.blit(self.axes.bbox)
def on_canvas_key(self, event): def on_canvas_key(self, event):
""" """
@@ -905,7 +903,7 @@ class FlatCAMDraw(QtCore.QObject):
def plot_shape(self, geometry=None, linespec='b-', linewidth=1, animated=False): def plot_shape(self, geometry=None, linespec='b-', linewidth=1, animated=False):
""" """
Plots a geometric object or list of objects without rendeting. Plotted objects Plots a geometric object or list of objects without rendering. Plotted objects
are returned as a list. This allows for efficient/animated rendering. are returned as a list. This allows for efficient/animated rendering.
:param geometry: Geometry to be plotted (Any Shapely.geom kind or list of such) :param geometry: Geometry to be plotted (Any Shapely.geom kind or list of such)
@@ -971,7 +969,6 @@ class FlatCAMDraw(QtCore.QObject):
:type shape: DrawToolShape :type shape: DrawToolShape
:return: None :return: None
""" """
print "add_shape()"
# List of DrawToolShape? # List of DrawToolShape?
if isinstance(shape, list): if isinstance(shape, list):

108
camlib.py
View File

@@ -154,26 +154,31 @@ class Geometry(object):
if reset: if reset:
self.flat_geometry = [] self.flat_geometry = []
## If iterable, expand recursively.
try: try:
for geo in geometry: for geo in geometry:
self.flatten_to_paths(geometry=geo, reset=False) self.flatten_to_paths(geometry=geo, reset=False)
## Not iterable, do the actual indexing and add.
except TypeError: except TypeError:
if type(geometry) == Polygon: if type(geometry) == Polygon:
g = geometry.exterior g = geometry.exterior
self.flat_geometry.append(g) self.flat_geometry.append(g)
self.flat_geometry_rtree.insert(len(self.flat_geometry)-1, g.coords[0])
self.flat_geometry_rtree.insert(len(self.flat_geometry)-1, g.coords[-1]) ## Add first and last points of the path to the index.
self.flat_geometry_rtree.insert(len(self.flat_geometry) - 1, g.coords[0])
self.flat_geometry_rtree.insert(len(self.flat_geometry) - 1, g.coords[-1])
for interior in geometry.interiors: for interior in geometry.interiors:
g = interior g = interior
self.flat_geometry.append(g) self.flat_geometry.append(g)
self.flat_geometry_rtree.insert(len(self.flat_geometry)-1, g.coords[0]) self.flat_geometry_rtree.insert(len(self.flat_geometry) - 1, g.coords[0])
self.flat_geometry_rtree.insert(len(self.flat_geometry)-1, g.coords[-1]) self.flat_geometry_rtree.insert(len(self.flat_geometry) - 1, g.coords[-1])
else: else:
g = geometry g = geometry
self.flat_geometry.append(g) self.flat_geometry.append(g)
self.flat_geometry_rtree.insert(len(self.flat_geometry)-1, g.coords[0]) self.flat_geometry_rtree.insert(len(self.flat_geometry) - 1, g.coords[0])
self.flat_geometry_rtree.insert(len(self.flat_geometry)-1, g.coords[-1]) self.flat_geometry_rtree.insert(len(self.flat_geometry) - 1, g.coords[-1])
return self.flat_geometry, self.flat_geometry_rtree return self.flat_geometry, self.flat_geometry_rtree
@@ -258,17 +263,18 @@ class Geometry(object):
:return: :return:
""" """
# Estimate good seedpoint if not provided.
if seedpoint is None: if seedpoint is None:
seedpoint = polygon.representative_point() seedpoint = polygon.representative_point()
# Current buffer radius # Current buffer radius
radius = tooldia/2*(1-overlap) radius = tooldia / 2 * (1 - overlap)
# The toolpaths # The toolpaths
geoms = [Point(seedpoint).buffer(radius).exterior] geoms = []
# Path margin # Path margin
path_margin = polygon.buffer(-tooldia/2) path_margin = polygon.buffer(-tooldia / 2)
# Grow from seed until outside the box. # Grow from seed until outside the box.
while 1: while 1:
@@ -281,12 +287,12 @@ class Geometry(object):
else: else:
geoms.append(path) geoms.append(path)
radius += tooldia*(1-overlap) radius += tooldia * (1 - overlap)
# Clean edges # Clean edges
outer_edges = [x.exterior for x in autolist(polygon.buffer(-tooldia/2))] outer_edges = [x.exterior for x in autolist(polygon.buffer(-tooldia / 2))]
inner_edges = [] inner_edges = []
for x in autolist(polygon.buffer(-tooldia/2)): # Over resulting polygons for x in autolist(polygon.buffer(-tooldia / 2)): # Over resulting polygons
for y in x.interiors: # Over interiors of each polygon for y in x.interiors: # Over interiors of each polygon
inner_edges.append(y) inner_edges.append(y)
geoms += outer_edges + inner_edges geoms += outer_edges + inner_edges
@@ -2198,6 +2204,11 @@ class CNCjob(Geometry):
""" """
Generates G-Code from a Geometry object. Stores in ``self.gcode``. Generates G-Code from a Geometry object. Stores in ``self.gcode``.
Algorithm description:
----------------------
Follow geometry paths in the order they are being read. No attempt
to optimize.
:param geometry: Geometry defining the toolpath :param geometry: Geometry defining the toolpath
:type geometry: Geometry :type geometry: Geometry
:param append: Wether to append to self.gcode or re-write it. :param append: Wether to append to self.gcode or re-write it.
@@ -2259,14 +2270,21 @@ class CNCjob(Geometry):
""" """
Second algorithm to generate from Geometry. Second algorithm to generate from Geometry.
ALgorithm description:
----------------------
Uses RTree to find the nearest path to follow.
:param geometry: :param geometry:
:param append: :param append:
:param tooldia: :param tooldia:
:param tolerance: :param tolerance:
:return: :return: None
""" """
assert isinstance(geometry, Geometry) assert isinstance(geometry, Geometry)
flat_geometry, rtindex = geometry.flatten_to_paths()
## Flatten the geometry and get rtree index
flat_geometry, rti = geometry.flatten_to_paths()
log.debug("%d paths" % len(flat_geometry))
if tooldia is not None: if tooldia is not None:
self.tooldia = tooldia self.tooldia = tooldia
@@ -2285,24 +2303,28 @@ class CNCjob(Geometry):
self.gcode += "M03\n" # Spindle start self.gcode += "M03\n" # Spindle start
self.gcode += self.pausecode + "\n" self.gcode += self.pausecode + "\n"
# Iterate over geometry and run individual methods ## Iterate over geometry paths getting the nearest each time.
# depending on type path_count = 0
# for geo in flat_geometry: current_pt = (0, 0)
# hits = list(rti.nearest(current_pt, 1))
# if type(geo) == LineString or type(geo) == LinearRing:
# self.gcode += self.linear2gcode(geo, tolerance=tolerance)
# continue
#
# if type(geo) == Point:
# self.gcode += self.point2gcode(geo)
# continue
#
# log.warning("G-code generation not implemented for %s" % (str(type(geo))))
hits = list(rtindex.nearest((0, 0), 1))
while len(hits) > 0: while len(hits) > 0:
path_count += 1
print "Current: ", "(%.3f, %.3f)" % current_pt
geo = flat_geometry[hits[0]] geo = flat_geometry[hits[0]]
# Determine which end of the path is closest.
distance2start = distance(current_pt, geo.coords[0])
distance2stop = distance(current_pt, geo.coords[-1])
print " Path index =", hits[0]
print " Start: ", "(%.3f, %.3f)" % geo.coords[0], " D(Start): %.3f" % distance2start
print " Stop : ", "(%.3f, %.3f)" % geo.coords[-1], " D(Stop): %.3f" % distance2stop
# Reverse if end is closest.
if distance2start > distance2stop:
print " Reversing!"
geo.coords = list(geo.coords)[::-1]
# G-code
if type(geo) == LineString or type(geo) == LinearRing: if type(geo) == LineString or type(geo) == LinearRing:
self.gcode += self.linear2gcode(geo, tolerance=tolerance) self.gcode += self.linear2gcode(geo, tolerance=tolerance)
elif type(geo) == Point: elif type(geo) == Point:
@@ -2310,12 +2332,13 @@ class CNCjob(Geometry):
else: else:
log.warning("G-code generation not implemented for %s" % (str(type(geo)))) log.warning("G-code generation not implemented for %s" % (str(type(geo))))
start_pt = geo.coords[0] # Delete from index, update current location and continue.
stop_pt = geo.coords[-1] rti.delete(hits[0], geo.coords[0])
rtindex.delete(hits[0], start_pt) rti.delete(hits[0], geo.coords[-1])
rtindex.delete(hits[0], stop_pt) current_pt = geo.coords[-1]
hits = list(rtindex.nearest(stop_pt, 1)) hits = list(rti.nearest(current_pt, 1))
log.debug("%s paths traced." % path_count)
# Finish # Finish
self.gcode += "G00 Z%.4f\n" % self.z_move # Stop cutting self.gcode += "G00 Z%.4f\n" % self.z_move # Stop cutting
@@ -2518,6 +2541,8 @@ class CNCjob(Geometry):
:param tool_tolerance: Tolerance when drawing the toolshape. :param tool_tolerance: Tolerance when drawing the toolshape.
:return: None :return: None
""" """
path_num = 0
if tooldia is None: if tooldia is None:
tooldia = self.tooldia tooldia = self.tooldia
@@ -2531,7 +2556,11 @@ class CNCjob(Geometry):
axes.plot(x, y, linespec, color=linecolor) axes.plot(x, y, linespec, color=linecolor)
else: else:
for geo in self.gcode_parsed: for geo in self.gcode_parsed:
poly = geo['geom'].buffer(tooldia/2.0).simplify(tool_tolerance) path_num += 1
axes.annotate(str(path_num), xy=geo['geom'].coords[0],
xycoords='data')
poly = geo['geom'].buffer(tooldia / 2.0).simplify(tool_tolerance)
patch = PolygonPatch(poly, facecolor=color[geo['kind'][0]][0], patch = PolygonPatch(poly, facecolor=color[geo['kind'][0]][0],
edgecolor=color[geo['kind'][0]][1], edgecolor=color[geo['kind'][0]][1],
alpha=alpha[geo['kind'][0]], zorder=2) alpha=alpha[geo['kind'][0]], zorder=2)
@@ -2812,7 +2841,10 @@ def find_polygon(poly_set, point):
def to_dict(obj): def to_dict(obj):
""" """
Makes a Shapely geometry object into serializeable form. Makes the following types into serializable form:
* ApertureMacro
* BaseGeometry
:param obj: Shapely geometry. :param obj: Shapely geometry.
:type obj: BaseGeometry :type obj: BaseGeometry
@@ -3149,3 +3181,7 @@ def three_point_circle(p1, p2, p3):
radius = norm(center - p1) radius = norm(center - p1)
return center, radius, T[0] return center, radius, T[0]
def distance(pt1, pt2):
return sqrt((pt1[0] - pt2[0]) ** 2 + (pt1[1] - pt2[1]) ** 2)

View File

@@ -7,7 +7,8 @@ Drawing
* [DONE] Arcs * [DONE] Arcs
* [DONE] Subtract Shapes * [DONE] Subtract Shapes
* [DONE] Selected objects must be kept onlist to preserve order. * [DONE] Selected objects must be kept onlist to preserve order.
* Polygon to outline * [DONE] Cut Path
* Polygon to outline
* Force perpendicular * Force perpendicular
* Un-group (Union creates group) * Un-group (Union creates group)
* Group (But not union) * Group (But not union)

View File

@@ -4,16 +4,27 @@ Installation
Windows Installer Windows Installer
----------------- -----------------
Download the installer from the repository_ and run it in your machine. It includes everything you need. Download the installer from the repository_ and run it in your machine.
It includes everything you need.
.. _repository: https://bitbucket.org/jpcgt/flatcam/downloads .. _repository: https://bitbucket.org/jpcgt/flatcam/downloads
Ubuntu Ubuntu
------ ------
FlatCAM should work on most Linux distributions but Ubuntu has been chosen as the test platform. FlatCAM should work on most Linux distributions but Ubuntu has been
chosen as the test platform.
There are several dependencies required to run FlatCAM. These are
listed in the following section. Before attempting a manual installation,
try running the provided setup script ``setup_ubuntu.sh`` that will
download and install required packages.
OS-X
----
See manual instructions below.
There are several dependencies required to run FlatCAM. These are listed in the following section. Before attempting a manual installation, try running the provided setup script ``setup_ubuntu.sh`` that will download and install required packages.
Manual Installation Manual Installation
------------------- -------------------
@@ -26,6 +37,9 @@ Requirements
* Matplotlib 1.3.1 * Matplotlib 1.3.1
* Numpy 1.8 * Numpy 1.8
* `Shapely 1.3`_ * `Shapely 1.3`_
* GEOS
* RTree
* SpatialIndex
.. _Shapely 1.3: https://pypi.python.org/pypi/Shapely .. _Shapely 1.3: https://pypi.python.org/pypi/Shapely
@@ -34,9 +48,14 @@ These packages might have their own dependencies.
Linux Linux
~~~~~ ~~~~~
Under Linux, most modern package installers like **yum** or **apt-get** will attempt to locate and install the whole tree of dependencies for a specified package automatically. Refer to the provided setup script ``setup_ubuntu.sh`` for the names and installation order. Under Linux, most modern package installers like **yum** or **apt-get**
will attempt to locate and install the whole tree of dependencies for a
specified package automatically. Refer to the provided setup script
``setup_ubuntu.sh`` for the names and installation order.
Once the dependencies are installed, download the latest .zip release (or the latest source, although it is not garanteed to work), unpack it, change into the created folder and run:: Once the dependencies are installed, download the latest .zip release
(or the latest source, although it is not garanteed to work), unpack it,
change into the created folder and run::
Python FlatCAM.py Python FlatCAM.py
@@ -44,11 +63,36 @@ Once the dependencies are installed, download the latest .zip release (or the la
Windows Windows
~~~~~~~ ~~~~~~~
An easy way to get the requirements in your system is to install WinPython_. This is a standalone distribution of Python which includes all of FlatCAM's dependencies, except for Shapely. An easy way to get the requirements in your system is to install WinPython_.
This is a standalone distribution of Python which includes all of FlatCAM's
dependencies, except for Shapely.
.. _WinPython: http://winpython.sourceforge.net/ .. _WinPython: http://winpython.sourceforge.net/
Once the dependencies are installed, download the latest .zip release (or the latest source, although it is not garanteed to work), unpack it, change into the created folder and run:: Once the dependencies are installed, download the latest .zip
release (or the latest source, although it is not garanteed to work),
unpack it, change into the created folder and run::
Python FlatCAM.py python FlatCAM.py
OS-X
~~~~
Start by installing binary packages: pyqt, geos, spatialindex.
One way to do this is using Homebrew_::
brew install name_of_package
.. _Homebrew: http://brew.sh
Now you can install all Python packages (numpy, matplotlib, rtree, scipy,
shapely, simplejson) using pip::
pip install name_of_package
Finally, download the latest FlatCAM .zip package or source code. Change into
its directory and launch it by running::
python FlatCAM.py