Commit dfbffd2b authored by sumpfralle's avatar sumpfralle

more style fixes

disabled "namedtuple" for now (it was never in effect)


git-svn-id: https://pycam.svn.sourceforge.net/svnroot/pycam/trunk@975 bbaffbd6-741e-11dd-a85d-61de82d9cad9
parent f84adff7
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
$Id$ $Id$
Copyright 2008-2010 Lode Leroy Copyright 2008-2010 Lode Leroy
Copyright 2010 Lars Kruse <devel@sumpfralle.de> Copyright 2010-2011 Lars Kruse <devel@sumpfralle.de>
This file is part of PyCAM. This file is part of PyCAM.
...@@ -22,11 +22,10 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>. ...@@ -22,11 +22,10 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
""" """
import pycam.Utils.threading
from pycam.Geometry.Point import Point from pycam.Geometry.Point import Point
from pycam.Geometry.utils import number, INFINITE, epsilon from pycam.Geometry.utils import number, INFINITE, epsilon
from pycam.Geometry.intersection import intersect_circle_point, \ from pycam.Geometry.intersection import intersect_cylinder_point, \
intersect_cylinder_point, intersect_cylinder_line intersect_cylinder_line
import uuid import uuid
...@@ -49,7 +48,8 @@ class BaseCutter(object): ...@@ -49,7 +48,8 @@ class BaseCutter(object):
self.distance_radius = self.radius self.distance_radius = self.radius
self.distance_radiussq = self.distance_radius ** 2 self.distance_radiussq = self.distance_radius ** 2
self.shape = {} self.shape = {}
self.moveto(location) self.location = location
self.moveto(self.location)
self.uuid = None self.uuid = None
self.update_uuid() self.update_uuid()
...@@ -131,8 +131,7 @@ class BaseCutter(object): ...@@ -131,8 +131,7 @@ class BaseCutter(object):
* triangle.radius + triangle.radiussq) + epsilon: * triangle.radius + triangle.radiussq) + epsilon:
return None return None
(cl, d, cp) = self.intersect(BaseCutter.vertical, triangle, start=start) return self.intersect(BaseCutter.vertical, triangle, start=start)[0]
return cl
def intersect_circle_triangle(self, direction, triangle, start=None): def intersect_circle_triangle(self, direction, triangle, start=None):
(cl, ccp, cp, d) = self.intersect_circle_plane(direction, triangle, (cl, ccp, cp, d) = self.intersect_circle_plane(direction, triangle,
......
...@@ -131,7 +131,8 @@ class CylindricalCutter(BaseCutter): ...@@ -131,7 +131,8 @@ class CylindricalCutter(BaseCutter):
def moveto(self, location, **kwargs): def moveto(self, location, **kwargs):
BaseCutter.moveto(self, location, **kwargs) BaseCutter.moveto(self, location, **kwargs)
self.center = Point(location.x, location.y, location.z - self.get_required_distance()) self.center = Point(location.x, location.y,
location.z - self.get_required_distance())
def intersect_circle_plane(self, direction, triangle, start=None): def intersect_circle_plane(self, direction, triangle, start=None):
if start is None: if start is None:
...@@ -166,10 +167,6 @@ class CylindricalCutter(BaseCutter): ...@@ -166,10 +167,6 @@ class CylindricalCutter(BaseCutter):
return (cl, ccp, cp, l) return (cl, ccp, cp, l)
return (None, None, None, INFINITE) return (None, None, None, INFINITE)
def intersect_plane(self, direction, triangle, start=None):
# TODO: are "intersect_plane" and "self.intersect_circle_plane" obsolete?
return self.intersect_circle_plane(direction, triangle, start=start)
def intersect(self, direction, triangle, start=None): def intersect(self, direction, triangle, start=None):
(cl_t, d_t, cp_t) = self.intersect_circle_triangle(direction, triangle, (cl_t, d_t, cp_t) = self.intersect_circle_triangle(direction, triangle,
start=start) start=start)
......
...@@ -128,7 +128,8 @@ class ToroidalCutter(BaseCutter): ...@@ -128,7 +128,8 @@ class ToroidalCutter(BaseCutter):
return (None, None, None, INFINITE) return (None, None, None, INFINITE)
def intersect_torus_triangle(self, direction, triangle, start=None): def intersect_torus_triangle(self, direction, triangle, start=None):
(cl, ccp, cp, d) = self.intersect_torus_plane(direction, triangle, start=start) (cl, ccp, cp, d) = self.intersect_torus_plane(direction, triangle,
start=start)
if cp and triangle.is_point_inside(cp): if cp and triangle.is_point_inside(cp):
return (cl, d, cp) return (cl, d, cp)
return (None, INFINITE, None) return (None, INFINITE, None)
......
...@@ -27,11 +27,12 @@ import os ...@@ -27,11 +27,12 @@ import os
class STLExporter: class STLExporter:
def __init__(self, model, name="model", created_by="pycam", linesep=None, comment=None): def __init__(self, model, name="model", created_by="pycam", linesep=None,
comment=None):
# sadly STL does not seem to support comments
self.model = model self.model = model
self.name = name self.name = name
self.created_by = created_by self.created_by = created_by
self.comment = comment
if linesep is None: if linesep is None:
self.linesep = os.linesep self.linesep = os.linesep
else: else:
...@@ -49,20 +50,14 @@ class STLExporter: ...@@ -49,20 +50,14 @@ class STLExporter:
date = datetime.date.today().isoformat() date = datetime.date.today().isoformat()
yield """solid "%s"; Produced by %s (v%s), %s""" \ yield """solid "%s"; Produced by %s (v%s), %s""" \
% (self.name, self.created_by, VERSION, date) % (self.name, self.created_by, VERSION, date)
# sadly STL does not seem to support comments for triangle in self.model.triangles():
""" norm = triangle.normal.normalized()
if self.comment:
for line in self.comment.split(self.linesep):
yield(";%s" % line)
"""
for tr in self.model.triangles():
norm = tr.normal.normalized()
yield "facet normal %f %f %f" % (norm.x, norm.y, norm.z) yield "facet normal %f %f %f" % (norm.x, norm.y, norm.z)
yield " outer loop" yield " outer loop"
# Triangle vertices are stored in clockwise order - thus we need # Triangle vertices are stored in clockwise order - thus we need
# to reverse the order (STL expects counter-clockwise orientation). # to reverse the order (STL expects counter-clockwise orientation).
for p in (tr.p3, tr.p2, tr.p1): for point in (triangle.p3, triangle.p2, triangle.p1):
yield " vertex %f %f %f" % (p.x, p.y, p.z) yield " vertex %f %f %f" % (point.x, point.y, point.z)
yield " endloop" yield " endloop"
yield "endfacet" yield "endfacet"
yield "endsolid" yield "endsolid"
......
...@@ -29,7 +29,7 @@ class SVGExporter: ...@@ -29,7 +29,7 @@ class SVGExporter:
def __init__(self, output, unit="mm"): def __init__(self, output, unit="mm"):
if isinstance(output, basestring): if isinstance(output, basestring):
# a filename was given # a filename was given
self.output = file(filename,"w") self.output = file(output,"w")
else: else:
# a stream was given # a stream was given
self.output = output self.output = output
......
...@@ -44,15 +44,22 @@ class gcode: ...@@ -44,15 +44,22 @@ class gcode:
"G04 P3 T%d M6" % self.tool_id, "G04 P3 T%d M6" % self.tool_id,
"G00 Z%.4f" % self.safetyheight) "G00 Z%.4f" % self.safetyheight)
def end(self):
return "M2"
def exactpath(self): def exactpath(self):
return "G61" return "G61"
def continuous(self): def continuous(self):
return "G64" return "G64"
def rapid(self, x = None, y = None, z = None, a = None, gcode = "G00", def rapid(self, x=None, y=None, z=None, a=None, code="G00", feed=None):
feed=None): gcodestring = ""
gcodestring = feedstring = xstring = ystring = zstring = astring = "" feedstring = ""
xstring = ""
ystring = ""
zstring = ""
astring = ""
if x == None: if x == None:
x = self.lastx x = self.lastx
if y == None: if y == None:
...@@ -61,9 +68,9 @@ class gcode: ...@@ -61,9 +68,9 @@ class gcode:
z = self.lastz z = self.lastz
if a == None: if a == None:
a = self.lasta a = self.lasta
if gcode != self.lastgcode: if code != self.lastgcode:
gcodestring = gcode gcodestring = code
self.lastgcode = gcode self.lastgcode = code
if x != self.lastx: if x != self.lastx:
xstring = " X%.4f" % (x) xstring = " X%.4f" % (x)
self.lastx = x self.lastx = x
...@@ -76,7 +83,7 @@ class gcode: ...@@ -76,7 +83,7 @@ class gcode:
if a != self.lasta: if a != self.lasta:
astring = " A%.4f" % (a) astring = " A%.4f" % (a)
self.lasta = a self.lasta = a
if (gcode == "G01") and feed and (feed != self.lastfeed): if (code == "G01") and feed and (feed != self.lastfeed):
feedstring = " F%.4f" % (feed) feedstring = " F%.4f" % (feed)
self.lastfeed = feed self.lastfeed = feed
positionstring = xstring + ystring + zstring + astring positionstring = xstring + ystring + zstring + astring
...@@ -90,7 +97,7 @@ class gcode: ...@@ -90,7 +97,7 @@ class gcode:
if y == None: y = self.lasty if y == None: y = self.lasty
if z == None: z = self.lastz if z == None: z = self.lastz
if a == None: a = self.lasta if a == None: a = self.lasta
return self.rapid(x, y, z, a, gcode="G01", feed=feed) return self.rapid(x, y, z, a, code="G01", feed=feed)
def safety(self): def safety(self):
return self.rapid(z=self.safetyheight) return self.rapid(z=self.safetyheight)
......
...@@ -27,12 +27,10 @@ from pycam.Geometry.Plane import Plane ...@@ -27,12 +27,10 @@ from pycam.Geometry.Plane import Plane
from pycam.Geometry.utils import epsilon, sqrt from pycam.Geometry.utils import epsilon, sqrt
# OpenGLTools will be imported later, if necessary # OpenGLTools will be imported later, if necessary
#import pycam.Gui.OpenGLTools #import pycam.Gui.OpenGLTools
import math
try: try:
import OpenGL.GL as GL import OpenGL.GL as GL
import OpenGL.GLUT as GLUT
GL_enabled = True GL_enabled = True
except ImportError: except ImportError:
GL_enabled = False GL_enabled = False
...@@ -42,6 +40,7 @@ class Line(TransformableContainer): ...@@ -42,6 +40,7 @@ class Line(TransformableContainer):
id = 0 id = 0
def __init__(self, p1, p2): def __init__(self, p1, p2):
super(Line, self).__init__()
self.id = Line.id self.id = Line.id
Line.id += 1 Line.id += 1
self.p1 = p1 self.p1 = p1
......
...@@ -27,7 +27,7 @@ from pycam.Geometry.Triangle import Triangle ...@@ -27,7 +27,7 @@ from pycam.Geometry.Triangle import Triangle
from pycam.Geometry.Line import Line from pycam.Geometry.Line import Line
from pycam.Geometry.Plane import Plane from pycam.Geometry.Plane import Plane
from pycam.Geometry.Polygon import Polygon from pycam.Geometry.Polygon import Polygon
from pycam.Geometry.Point import Point, Vector from pycam.Geometry.Point import Point
from pycam.Geometry.TriangleKdtree import TriangleKdtree from pycam.Geometry.TriangleKdtree import TriangleKdtree
from pycam.Geometry.Matrix import TRANSFORMATIONS from pycam.Geometry.Matrix import TRANSFORMATIONS
from pycam.Toolpath import Bounds from pycam.Toolpath import Bounds
...@@ -110,7 +110,8 @@ class BaseModel(TransformableContainer): ...@@ -110,7 +110,8 @@ class BaseModel(TransformableContainer):
+ "support the 'export' function.") % str(type(self))) + "support the 'export' function.") % str(type(self)))
def _update_limits(self, item): def _update_limits(self, item):
# ignore items without limit attributes (e.g. the normal of a ContourModel) # Ignore items without limit attributes (e.g. the normal of a
# ContourModel).
if hasattr(item, "minx"): if hasattr(item, "minx"):
if self.minx is None: if self.minx is None:
self.minx = item.minx self.minx = item.minx
...@@ -313,7 +314,8 @@ class ContourModel(BaseModel): ...@@ -313,7 +314,8 @@ class ContourModel(BaseModel):
self._plane_groups = [self._plane] self._plane_groups = [self._plane]
self._item_groups.append(self._plane_groups) self._item_groups.append(self._plane_groups)
self._cached_offset_models = {} self._cached_offset_models = {}
self._export_function = pycam.Exporters.SVGExporter.SVGExporterContourModel self._export_function = \
pycam.Exporters.SVGExporter.SVGExporterContourModel
def reset_cache(self): def reset_cache(self):
super(ContourModel, self).reset_cache() super(ContourModel, self).reset_cache()
...@@ -409,8 +411,10 @@ class ContourModel(BaseModel): ...@@ -409,8 +411,10 @@ class ContourModel(BaseModel):
new_queue = processed new_queue = processed
while len(self._line_groups) > 0: while len(self._line_groups) > 0:
self._line_groups.pop() self._line_groups.pop()
print "Processed polygons: %s" % str([len(p.get_lines()) for p in processed_polygons]) print "Processed polygons: %s" % str([len(p.get_lines())
print "New queue: %s" % str([len(p.get_lines()) for p in new_queue]) for p in processed_polygons])
print "New queue: %s" % str([len(p.get_lines())
for p in new_queue])
for processed_polygon in processed_polygons + new_queue: for processed_polygon in processed_polygons + new_queue:
self._line_groups.append(processed_polygon) self._line_groups.append(processed_polygon)
# TODO: this is quite expensive - can we do it differently? # TODO: this is quite expensive - can we do it differently?
......
...@@ -29,8 +29,10 @@ This reduces the memory consumption of a toolpath down to 1/3. ...@@ -29,8 +29,10 @@ This reduces the memory consumption of a toolpath down to 1/3.
try: try:
# this works for python 2.6 or above (saves memory) # this works for python 2.6 or above (saves memory)
import collections.namedtuple # TODO: disabled for now - check if we could enable it later ...
tuple_point = collections.namedtuple("TuplePoint", "x y z") import INVALID_IMPORT
from collections import namedtuple
tuple_point = namedtuple("TuplePoint", "x y z")
get_point_object = lambda point: tuple_point(point.x, point.y, point.z) get_point_object = lambda point: tuple_point(point.x, point.y, point.z)
except ImportError: except ImportError:
# dummy for python < v2.6 (consumes more memory) # dummy for python < v2.6 (consumes more memory)
...@@ -48,22 +50,22 @@ class Path: ...@@ -48,22 +50,22 @@ class Path:
self.points = [] self.points = []
def __repr__(self): def __repr__(self):
s = "" text = ""
s += "path %d: " % self.id text += "path %d: " % self.id
first = True first = True
for p in self.points: for point in self.points:
if first: if first:
first = False first = False
else: else:
s += "-" text += "-"
s += "%d(%g,%g,%g)" % (p.id, p.x, p.y, p.z) text += "%d(%g,%g,%g)" % (point.id, point.x, point.y, point.z)
return s return text
def insert(self, index, p): def insert(self, index, point):
self.points.insert(index, get_point_object(p)) self.points.insert(index, get_point_object(point))
def append(self, p): def append(self, point):
self.points.append(get_point_object(p)) self.points.append(get_point_object(point))
def reverse(self): def reverse(self):
self.points.reverse() self.points.reverse()
...@@ -22,18 +22,19 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>. ...@@ -22,18 +22,19 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
from pycam.Geometry import TransformableContainer from pycam.Geometry import TransformableContainer
from pycam.Geometry.utils import INFINITE, epsilon from pycam.Geometry.utils import INFINITE, epsilon
from pycam.Geometry.Point import Point, Vector from pycam.Geometry.Point import Vector
# "Line" is imported later to avoid circular imports # "Line" is imported later to avoid circular imports
#from pycam.Geometry.Line import Line #from pycam.Geometry.Line import Line
class Plane(TransformableContainer): class Plane(TransformableContainer):
id = 0 id = 0
def __init__(self, p, n): def __init__(self, point, normal):
super(Plane, self).__init__()
self.id = Plane.id self.id = Plane.id
Plane.id += 1 Plane.id += 1
self.p = p self.p = point
self.n = n self.n = normal
if not isinstance(self.n, Vector): if not isinstance(self.n, Vector):
self.n = self.n.get_vector() self.n = self.n.get_vector()
...@@ -123,8 +124,7 @@ class Plane(TransformableContainer): ...@@ -123,8 +124,7 @@ class Plane(TransformableContainer):
return None return None
def get_point_projection(self, point): def get_point_projection(self, point):
p, dist = self.intersect_point(self.n, point) return self.intersect_point(self.n, point)[0]
return p
def get_line_projection(self, line): def get_line_projection(self, line):
# don't import Line in the header -> circular import # don't import Line in the header -> circular import
......
...@@ -25,9 +25,7 @@ from pycam.Geometry.Point import Point, Vector ...@@ -25,9 +25,7 @@ from pycam.Geometry.Point import Point, Vector
from pycam.Geometry.Plane import Plane from pycam.Geometry.Plane import Plane
from pycam.Geometry import TransformableContainer, get_bisector from pycam.Geometry import TransformableContainer, get_bisector
from pycam.Geometry.utils import number, epsilon from pycam.Geometry.utils import number, epsilon
import pycam.Geometry.Matrix as Matrix
import pycam.Utils.log import pycam.Utils.log
import math
# import later to avoid circular imports # import later to avoid circular imports
#from pycam.Geometry.Model import ContourModel #from pycam.Geometry.Model import ContourModel
...@@ -69,7 +67,8 @@ class Polygon(TransformableContainer): ...@@ -69,7 +67,8 @@ class Polygon(TransformableContainer):
self._update_limits(line.p2) self._update_limits(line.p2)
elif self._points[-1] == line.p1: elif self._points[-1] == line.p1:
# the new Line can be added to the end of the polygon # the new Line can be added to the end of the polygon
if line.dir == self._points[-1].sub(self._points[-2]).normalized(): if line.dir == self._points[-1].sub(
self._points[-2]).normalized():
# Remove the last point, if the previous point combination # Remove the last point, if the previous point combination
# is in line with the new Line. This avoids unnecessary # is in line with the new Line. This avoids unnecessary
# points on straight lines. # points on straight lines.
...@@ -84,7 +83,8 @@ class Polygon(TransformableContainer): ...@@ -84,7 +83,8 @@ class Polygon(TransformableContainer):
else: else:
# the new Line can be added to the beginning of the polygon # the new Line can be added to the beginning of the polygon
if (len(self._points) > 1) \ if (len(self._points) > 1) \
and (line.dir == self._points[1].sub(self._points[0]).normalized()): and (line.dir == self._points[1].sub(
self._points[0]).normalized()):
# Avoid points on straight lines - see above. # Avoid points on straight lines - see above.
self._points.pop(0) self._points.pop(0)
if line.p1 != self._points[-1]: if line.p1 != self._points[-1]:
...@@ -142,7 +142,6 @@ class Polygon(TransformableContainer): ...@@ -142,7 +142,6 @@ class Polygon(TransformableContainer):
Currently this works only for line groups in an xy-plane. Currently this works only for line groups in an xy-plane.
Returns zero for empty line groups or for open line groups. Returns zero for empty line groups or for open line groups.
Returns negative values for inner hole. Returns negative values for inner hole.
TODO: "get_area" is wrong by some factor - check the result!
""" """
if not self._points: if not self._points:
return 0 return 0
...@@ -227,7 +226,8 @@ class Polygon(TransformableContainer): ...@@ -227,7 +226,8 @@ class Polygon(TransformableContainer):
or (not self.is_closed and index == len(self._points) - 1): or (not self.is_closed and index == len(self._points) - 1):
return None return None
else: else:
return self._points[index].add(self._points[(index + 1) % len(self._points)]).div(2) return self._points[index].add(self._points[(index + 1) % \
len(self._points)]).div(2)
def get_lengths(self): def get_lengths(self):
result = [] result = []
...@@ -324,7 +324,8 @@ class Polygon(TransformableContainer): ...@@ -324,7 +324,8 @@ class Polygon(TransformableContainer):
lines = [] lines = []
for index in range(len(self._points) - 1): for index in range(len(self._points) - 1):
lines.append(Line(self._points[index], self._points[index + 1])) lines.append(Line(self._points[index], self._points[index + 1]))
# connect the last point with the first only if the polygon is closed # Connect the last point with the first only if the polygon is
# closed.
if self.is_closed: if self.is_closed:
lines.append(Line(self._points[-1], self._points[0])) lines.append(Line(self._points[-1], self._points[0]))
self._lines_cache = lines self._lines_cache = lines
...@@ -333,16 +334,6 @@ class Polygon(TransformableContainer): ...@@ -333,16 +334,6 @@ class Polygon(TransformableContainer):
def to_OpenGL(self, **kwords): def to_OpenGL(self, **kwords):
for line in self.get_lines(): for line in self.get_lines():
line.to_OpenGL(**kwords) line.to_OpenGL(**kwords)
return
offset_polygons = self.get_offset_polygons(0.2)
for polygon in offset_polygons:
for line in polygon.get_lines():
line.to_OpenGL(**kwords)
"""
for index, point in enumerate(self._points):
line = Line(point, point.add(self.get_bisector(index)))
line.get_length_line(1).to_OpenGL()
"""
def _update_limits(self, point): def _update_limits(self, point):
if self.minx is None: if self.minx is None:
...@@ -452,9 +443,12 @@ class Polygon(TransformableContainer): ...@@ -452,9 +443,12 @@ class Polygon(TransformableContainer):
shifted_lines[prev_index] = (False, Line(prev_line.p1, cp)) shifted_lines[prev_index] = (False, Line(prev_line.p1, cp))
shifted_lines[next_index] = (False, Line(cp, next_line.p2)) shifted_lines[next_index] = (False, Line(cp, next_line.p2))
else: else:
cp, dist = prev_line.get_intersection(next_line, infinite_lines=True) cp, dist = prev_line.get_intersection(next_line,
raise BaseException("Expected intersection not found: " \ infinite_lines=True)
+ "%s - %s - %s(%d) / %s(%d)" % (cp, shifted_lines[prev_index+1:next_index], prev_line, prev_index, next_line, next_index)) raise BaseException("Expected intersection not found: " + \
"%s - %s - %s(%d) / %s(%d)" % \
(cp, shifted_lines[prev_index+1:next_index],
prev_line, prev_index, next_line, next_index))
if index > next_index: if index > next_index:
# we wrapped around the end of the list # we wrapped around the end of the list
break break
...@@ -603,7 +597,8 @@ class Polygon(TransformableContainer): ...@@ -603,7 +597,8 @@ class Polygon(TransformableContainer):
for cached_offset in self._cached_offset_polygons: for cached_offset in self._cached_offset_polygons:
if is_better_offset(best_offset, cached_offset): if is_better_offset(best_offset, cached_offset):
best_offset = cached_offset best_offset = cached_offset
best_offset_polygons = self._cached_offset_polygons[cached_offset] best_offset_polygons = \
self._cached_offset_polygons[cached_offset]
remaining_offset = offset - best_offset remaining_offset = offset - best_offset
result_polygons = [] result_polygons = []
for poly in best_offset_polygons: for poly in best_offset_polygons:
...@@ -780,14 +775,16 @@ class Polygon(TransformableContainer): ...@@ -780,14 +775,16 @@ class Polygon(TransformableContainer):
# We ignore groups that changed the direction. These # We ignore groups that changed the direction. These
# parts of the original group are flipped due to the # parts of the original group are flipped due to the
# offset. # offset.
log.debug("Ignoring reversed polygon: %s / %s" % (self.get_area(), group.get_area())) log.debug("Ignoring reversed polygon: %s / %s" % \
(self.get_area(), group.get_area()))
continue continue
# Remove polygons that should be inside the original, # Remove polygons that should be inside the original,
# but due to float inaccuracies they are not. # but due to float inaccuracies they are not.
if ((self.is_outer() and (offset < 0)) \ if ((self.is_outer() and (offset < 0)) \
or (not self.is_outer() and (offset > 0))) \ or (not self.is_outer() and (offset > 0))) \
and (not self.is_polygon_inside(group)): and (not self.is_polygon_inside(group)):
log.debug("Ignoring inaccurate polygon: %s / %s" % (self.get_area(), group.get_area())) log.debug("Ignoring inaccurate polygon: %s / %s" \
% (self.get_area(), group.get_area()))
continue continue
groups.append(group) groups.append(group)
if not groups: if not groups:
......
...@@ -39,11 +39,14 @@ else: ...@@ -39,11 +39,14 @@ else:
ceil = lambda value: int(math.ceil(value)) ceil = lambda value: int(math.ceil(value))
# return "0" for "-epsilon < value < 0" (to work around floating inaccuracies) # return "0" for "-epsilon < value < 0" (to work around floating inaccuracies)
# otherwise: return the sqrt function of the current type (could even raise exceptions) # otherwise: return the sqrt function of the current type (could even raise
# exceptions)
if _use_precision: if _use_precision:
sqrt = lambda value: (((value < -epsilon) or (value > 0)) and value.sqrt()) or 0 sqrt = lambda value: (((value < -epsilon) or (value > 0)) and \
value.sqrt()) or 0
else: else:
sqrt = lambda value: (((value < -epsilon) or (value > 0)) and math.sqrt(value)) or 0 sqrt = lambda value: (((value < -epsilon) or (value > 0)) and \
math.sqrt(value)) or 0
if _use_precision: if _use_precision:
number = lambda value: decimal.Decimal(str(value)) number = lambda value: decimal.Decimal(str(value))
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
""" """
$Id$ $Id$
Copyright 2010 Lars Kruse <devel@sumpfralle.de> Copyright 2010-2011 Lars Kruse <devel@sumpfralle.de>
This file is part of PyCAM. This file is part of PyCAM.
...@@ -32,13 +32,11 @@ except (ImportError, RuntimeError): ...@@ -32,13 +32,11 @@ except (ImportError, RuntimeError):
from pycam.Geometry.Point import Point from pycam.Geometry.Point import Point
import pycam.Geometry.Matrix as Matrix import pycam.Geometry.Matrix as Matrix
from pycam.Geometry.utils import sqrt, number, epsilon from pycam.Geometry.utils import sqrt, number
import pycam.Utils.log import pycam.Utils.log
import gtk import gtk
import gobject
import pango import pango
import math import math
import time
# buttons for rotating, moving and zooming the model view window # buttons for rotating, moving and zooming the model view window
BUTTON_ROTATE = gtk.gdk.BUTTON1_MASK BUTTON_ROTATE = gtk.gdk.BUTTON1_MASK
...@@ -237,12 +235,13 @@ class Camera: ...@@ -237,12 +235,13 @@ class Camera:
# This distance calculation is completely based on trial-and-error. # This distance calculation is completely based on trial-and-error.
distance = math.sqrt(sum([d ** 2 for d in v["distance"]])) distance = math.sqrt(sum([d ** 2 for d in v["distance"]]))
distance *= math.log(math.sqrt(width * height)) / math.log(10) distance *= math.log(math.sqrt(width * height)) / math.log(10)
left = v["center"][0] - math.sin(v["fovy"] / 360.0 * math.pi) * distance sin_factor = math.sin(v["fovy"] / 360.0 * math.pi) * distance
right = v["center"][0] + math.sin(v["fovy"] / 360.0 * math.pi) * distance left = v["center"][0] - sin_factor
top = v["center"][1] + math.sin(v["fovy"] / 360.0 * math.pi) * distance right = v["center"][0] + sin_factor
bottom = v["center"][1] - math.sin(v["fovy"] / 360.0 * math.pi) * distance top = v["center"][1] + sin_factor
near = v["center"][2] - 2 * math.sin(v["fovy"] / 360.0 * math.pi) * distance bottom = v["center"][1] - sin_factor
far = v["center"][2] + 2 * math.sin(v["fovy"] / 360.0 * math.pi) * distance near = v["center"][2] - 2 * sin_factor
far = v["center"][2] + 2 * sin_factor
GL.glOrtho(left, right, bottom, top, near, far) GL.glOrtho(left, right, bottom, top, near, far)
GLU.gluLookAt(camera_position[0], camera_position[1], GLU.gluLookAt(camera_position[0], camera_position[1],
camera_position[2], v["center"][0], v["center"][1], camera_position[2], v["center"][0], v["center"][1],
...@@ -383,9 +382,10 @@ class ModelViewWindowGL: ...@@ -383,9 +382,10 @@ class ModelViewWindowGL:
for action in context_menu_actions: for action in context_menu_actions:
action_group.add_action(action) action_group.add_action(action)
uimanager = gtk.UIManager() uimanager = gtk.UIManager()
# the "pos" parameter is optional since 2.12 - we can remove it later # The "pos" parameter is optional since gtk 2.12 - we can
# remove it later.
uimanager.insert_action_group(action_group, pos=-1) uimanager.insert_action_group(action_group, pos=-1)
uimanager_template = """<ui><popup name="context">%s</popup></ui>""" uimanager_template = '<ui><popup name="context">%s</popup></ui>'
uimanager_item_template = """<menuitem action="%s" />""" uimanager_item_template = """<menuitem action="%s" />"""
uimanager_text = uimanager_template % "".join( uimanager_text = uimanager_template % "".join(
[uimanager_item_template % action.get_name() [uimanager_item_template % action.get_name()
...@@ -442,12 +442,6 @@ class ModelViewWindowGL: ...@@ -442,12 +442,6 @@ class ModelViewWindowGL:
ord("K"): (0, 1), ord("K"): (0, 1),
ord("L"): (-1, 0), ord("L"): (-1, 0),
} }
def get_char(value):
# avoid exceptions
if 0 <= value <= 255:
return chr(value)
else:
return None
if key_string and (key_string in '1234567'): if key_string and (key_string in '1234567'):
names = ["reset", "front", "back", "left", "right", "top", "bottom"] names = ["reset", "front", "back", "left", "right", "top", "bottom"]
index = '1234567'.index(key_string) index = '1234567'.index(key_string)
...@@ -603,7 +597,8 @@ class ModelViewWindowGL: ...@@ -603,7 +597,8 @@ class ModelViewWindowGL:
and (abs(event.y - self.mouse["pressed_pos"][1]) < 3): and (abs(event.y - self.mouse["pressed_pos"][1]) < 3):
# A quick press/release cycle with the right mouse button # A quick press/release cycle with the right mouse button
# -> open the context menu. # -> open the context menu.
self.context_menu.popup(None, None, None, event.button, int(event.get_time())) self.context_menu.popup(None, None, None, event.button,
int(event.get_time()))
@check_busy @check_busy
@gtkgl_functionwrapper @gtkgl_functionwrapper
...@@ -910,8 +905,8 @@ def draw_complete_model_view(settings): ...@@ -910,8 +905,8 @@ def draw_complete_model_view(settings):
and settings.get("simulation_toolpath_moves")): and settings.get("simulation_toolpath_moves")):
GL.glColor4f(*settings.get("color_model")) GL.glColor4f(*settings.get("color_model"))
model = settings.get("model") model = settings.get("model")
min_area = abs(model.maxx - model.minx) * abs(model.maxy - model.miny) / 100
""" """
min_area = abs(model.maxx - model.minx) * abs(model.maxy - model.miny) / 100
# example for coloring specific triangles # example for coloring specific triangles
groups = model.get_flat_areas(min_area) groups = model.get_flat_areas(min_area)
all_flat_ids = [] all_flat_ids = []
......
This diff is collapsed.
...@@ -359,9 +359,9 @@ process: 3 ...@@ -359,9 +359,9 @@ process: 3
tasks=None): tasks=None):
text = self.get_config_text(tools, processes, bounds, tasks) text = self.get_config_text(tools, processes, bounds, tasks)
try: try:
fi = open(filename, "w") handle = open(filename, "w")
fi.write(text) handle.write(text)
fi.close() handle.close()
except IOError, err_msg: except IOError, err_msg:
log.error("Settings: Failed to write configuration to file " \ log.error("Settings: Failed to write configuration to file " \
+ "(%s): %s" % (filename, err_msg)) + "(%s): %s" % (filename, err_msg))
...@@ -417,7 +417,8 @@ process: 3 ...@@ -417,7 +417,8 @@ process: 3
try: try:
try: try:
value_raw = self.config.get( value_raw = self.config.get(
prefix + self.DEFAULT_SUFFIX, key, raw=raw) prefix + self.DEFAULT_SUFFIX, key,
raw=raw)
except (ConfigParser.NoSectionError, except (ConfigParser.NoSectionError,
ConfigParser.NoOptionError): ConfigParser.NoOptionError):
value_raw = None value_raw = None
...@@ -474,13 +475,13 @@ process: 3 ...@@ -474,13 +475,13 @@ process: 3
def get_config_text(self, tools=None, processes=None, bounds=None, def get_config_text(self, tools=None, processes=None, bounds=None,
tasks=None): tasks=None):
def get_dictionary_of_bounds(b): def get_dictionary_of_bounds(boundary):
""" this function should be the inverse operation of """ this function should be the inverse operation of
'_get_bounds_instance_from_dict' '_get_bounds_instance_from_dict'
""" """
result = {} result = {}
result["name"] = b.get_name() result["name"] = boundary.get_name()
bounds_type_num = b.get_type() bounds_type_num = boundary.get_type()
if bounds_type_num == Bounds.TYPE_RELATIVE_MARGIN: if bounds_type_num == Bounds.TYPE_RELATIVE_MARGIN:
bounds_type_name = "relative_margin" bounds_type_name = "relative_margin"
elif bounds_type_num == Bounds.TYPE_FIXED_MARGIN: elif bounds_type_num == Bounds.TYPE_FIXED_MARGIN:
...@@ -488,12 +489,12 @@ process: 3 ...@@ -488,12 +489,12 @@ process: 3
else: else:
bounds_type_name = "custom" bounds_type_name = "custom"
result["type"] = bounds_type_name result["type"] = bounds_type_name
low, high = b.get_bounds() low, high = boundary.get_bounds()
for index, axis in enumerate("xyz"): for index, axis in enumerate("xyz"):
result["%s_low" % axis] = low[index] result["%s_low" % axis] = low[index]
result["%s_high" % axis] = high[index] result["%s_high" % axis] = high[index]
# special handler to allow tasks to track this new object # special handler to allow tasks to track this new object
result[self.REFERENCE_TAG] = b result[self.REFERENCE_TAG] = boundary
return result return result
result = [] result = []
if tools is None: if tools is None:
......
...@@ -44,7 +44,7 @@ DEPENDENCY_DESCRIPTION = { ...@@ -44,7 +44,7 @@ DEPENDENCY_DESCRIPTION = {
+ "'glxgears' to locate this problem."), + "'glxgears' to locate this problem."),
} }
REQUIREMENTS_LINK = "http://sourceforge.net/apps/mediawiki/pycam/index.php?title=Requirements" REQUIREMENTS_LINK = "http://sf.net/apps/mediawiki/pycam/?title=Requirements"
# Usually the windows registry "HKEY_LOCAL_MACHINE/SOFTWARE/Gtk+/Path" contains # Usually the windows registry "HKEY_LOCAL_MACHINE/SOFTWARE/Gtk+/Path" contains
# something like: C:\Programs\Common files\GTK # something like: C:\Programs\Common files\GTK
...@@ -80,8 +80,8 @@ def import_gtk_carefully(): ...@@ -80,8 +80,8 @@ def import_gtk_carefully():
except NameError: except NameError:
# GTK is probably not installed - the next import will fail # GTK is probably not installed - the next import will fail
pass pass
except WindowsError: except OSError:
# this happens with pyinstaller binaries - just ignore it # "WindowsError" - this happens with pyinstaller binaries
pass pass
else: else:
# add the new path to the PATH environment variable # add the new path to the PATH environment variable
......
...@@ -183,8 +183,9 @@ class DXFParser(object): ...@@ -183,8 +183,9 @@ class DXFParser(object):
for index in range(len(p_array)): for index in range(len(p_array)):
if p_array[index] is None: if p_array[index] is None:
if (index == 0) or (index == 1): if (index == 0) or (index == 1):
log.debug("DXFImporter: weird LWPOLYLINE input data " \ log.debug("DXFImporter: weird LWPOLYLINE input " + \
+ "in line %d: %s" % (self.line_number, p_array)) "date in line %d: %s" % \
(self.line_number, p_array))
p_array[index] = 0 p_array[index] = 0
points.append(Point(p_array[0], p_array[1], p_array[2])) points.append(Point(p_array[0], p_array[1], p_array[2]))
start_line = self.line_number start_line = self.line_number
...@@ -323,8 +324,8 @@ class DXFParser(object): ...@@ -323,8 +324,8 @@ class DXFParser(object):
center = Point(center[0], center[1], center[2]) center = Point(center[0], center[1], center[2])
xy_point_coords = pycam.Geometry.get_points_of_arc(center, radius, xy_point_coords = pycam.Geometry.get_points_of_arc(center, radius,
angle_start, angle_end) angle_start, angle_end)
# Somehow the order of points seems to be the opposite of the what # Somehow the order of points seems to be the opposite of what is
# is expected. # expected.
xy_point_coords.reverse() xy_point_coords.reverse()
if len(xy_point_coords) > 1: if len(xy_point_coords) > 1:
for index in range(len(xy_point_coords) - 1): for index in range(len(xy_point_coords) - 1):
...@@ -334,9 +335,9 @@ class DXFParser(object): ...@@ -334,9 +335,9 @@ class DXFParser(object):
p2 = Point(p2[0], p2[1], center.z) p2 = Point(p2[0], p2[1], center.z)
self.lines.append(Line(p1, p2)) self.lines.append(Line(p1, p2))
else: else:
log.warn("DXFImporter: Ignoring zero-length LINE (between " \ log.warn("DXFImporter: Ignoring tiny ARC (between input " + \
+ "input line %d and %d): %s" % (start_line, end_line, "line %d and %d): %s / %s (%s - %s)" % (start_line,
line)) end_line, center, radius, angle_start, angle_end))
def check_header(self): def check_header(self):
# TODO: this function is not used? # TODO: this function is not used?
...@@ -367,8 +368,8 @@ def import_model(filename, program_locations=None, unit=None, ...@@ -367,8 +368,8 @@ def import_model(filename, program_locations=None, unit=None,
if lines: if lines:
model = pycam.Geometry.Model.ContourModel() model = pycam.Geometry.Model.ContourModel()
for index, l in enumerate(lines): for index, line in enumerate(lines):
model.append(l) model.append(line)
# keep the GUI smooth # keep the GUI smooth
if callback and (index % 50 == 0): if callback and (index % 50 == 0):
callback() callback()
...@@ -390,7 +391,7 @@ def import_model(filename, program_locations=None, unit=None, ...@@ -390,7 +391,7 @@ def import_model(filename, program_locations=None, unit=None,
% (len(lines), len(model.get_polygons()))) % (len(lines), len(model.get_polygons())))
return model return model
else: else:
link = "http://sourceforge.net/apps/mediawiki/pycam/index.php?title=SupportedFormats" link = "http://sf.net/apps/mediawiki/pycam/?title=SupportedFormats"
log.error('DXFImporter: No supported elements found in DXF file!\n' \ log.error('DXFImporter: No supported elements found in DXF file!\n' \
+ '<a href="%s">Read PyCAM\'s modelling hints.</a>' % link) + '<a href="%s">Read PyCAM\'s modelling hints.</a>' % link)
return None return None
......
...@@ -23,7 +23,6 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>. ...@@ -23,7 +23,6 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
from pycam.Importers.SVGImporter import convert_eps2dxf from pycam.Importers.SVGImporter import convert_eps2dxf
import pycam.Importers.DXFImporter import pycam.Importers.DXFImporter
import tempfile import tempfile
import subprocess
import os import os
log = pycam.Utils.log.get_logger() log = pycam.Utils.log.get_logger()
......
...@@ -145,9 +145,9 @@ def ImportModel(filename, use_kdtree=True, program_locations=None, unit=None, ...@@ -145,9 +145,9 @@ def ImportModel(filename, use_kdtree=True, program_locations=None, unit=None,
t = Triangle(p1, p3, p2) t = Triangle(p1, p3, p2)
elif dotcross < 0: elif dotcross < 0:
if not normal_conflict_warning_seen: if not normal_conflict_warning_seen:
log.warn(("Inconsistent normal/vertices found in facet " \ log.warn(("Inconsistent normal/vertices found in facet " + \
+ "definition %d of '%s'. Please validate the STL " \ "definition %d of '%s'. Please validate the " + \
+ "file!") % (i, filename)) "STL file!") % (i, filename))
normal_conflict_warning_seen = True normal_conflict_warning_seen = True
t = Triangle(p1, p2, p3) t = Triangle(p1, p2, p3)
else: else:
...@@ -245,9 +245,9 @@ def ImportModel(filename, use_kdtree=True, program_locations=None, unit=None, ...@@ -245,9 +245,9 @@ def ImportModel(filename, use_kdtree=True, program_locations=None, unit=None,
t = Triangle(p1, p3, p2, n) t = Triangle(p1, p3, p2, n)
elif dotcross < 0: elif dotcross < 0:
if not normal_conflict_warning_seen: if not normal_conflict_warning_seen:
log.warn(("Inconsistent normal/vertices found in line " \ log.warn(("Inconsistent normal/vertices found in " + \
+ "%d of '%s'. Please validate the STL file!") \ "line %d of '%s'. Please validate the STL " + \
% (current_line, filename)) "file!") % (current_line, filename))
normal_conflict_warning_seen = True normal_conflict_warning_seen = True
t = Triangle(p1, p2, p3, n) t = Triangle(p1, p2, p3, n)
else: else:
......
...@@ -68,10 +68,11 @@ def convert_eps2dxf(eps_filename, dxf_filename, location=None, unit="mm"): ...@@ -68,10 +68,11 @@ def convert_eps2dxf(eps_filename, dxf_filename, location=None, unit="mm"):
if returncode == 0: if returncode == 0:
return True return True
elif returncode == -11: elif returncode == -11:
log.warn(("SVGImporter: maybe there was a problem with the " \ log.warn(("SVGImporter: maybe there was a problem with the " + \
+ "conversion from EPS (%s) to DXF\n Users of Ubuntu 'lucid' should install " \ "conversion from EPS (%s) to DXF\n Users of Ubuntu 'lucid' " + \
+ "the package 'libpstoedit0c2a' from the 'maverick' " \ "should install the package 'libpstoedit0c2a' from the " + \
+ "repository to avoid this warning.") % str(eps_filename)) "'maverick' repository to avoid this warning.") % \
str(eps_filename))
return True return True
else: else:
log.warn(("SVGImporter: failed to convert EPS file (%s) to DXF file " \ log.warn(("SVGImporter: failed to convert EPS file (%s) to DXF file " \
...@@ -96,7 +97,8 @@ def import_model(filename, program_locations=None, unit="mm", callback=None): ...@@ -96,7 +97,8 @@ def import_model(filename, program_locations=None, unit="mm", callback=None):
# the "right" way would be: # the "right" way would be:
# inkscape --print='| pstoedit -dt -f dxf:-polyaslines - -' input.svg # inkscape --print='| pstoedit -dt -f dxf:-polyaslines - -' input.svg
# Sadly a bug in v0.47 breaks this: https://bugs.launchpad.net/inkscape/+bug/511361 # Sadly a bug in v0.47 breaks this:
# https://bugs.launchpad.net/inkscape/+bug/511361
# convert svg to eps via inkscape # convert svg to eps via inkscape
eps_file_handle, eps_file_name = tempfile.mkstemp(suffix=".eps") eps_file_handle, eps_file_name = tempfile.mkstemp(suffix=".eps")
......
This diff is collapsed.
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
""" """
$Id$ $Id$
Copyright 2010 Lars Kruse <devel@sumpfralle.de> Copyright 2010-2011 Lars Kruse <devel@sumpfralle.de>
Copyright 2008-2009 Lode Leroy Copyright 2008-2009 Lode Leroy
This file is part of PyCAM. This file is part of PyCAM.
...@@ -21,8 +21,6 @@ You should have received a copy of the GNU General Public License ...@@ -21,8 +21,6 @@ You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>. along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
""" """
from pycam.Geometry.Point import Point
from pycam.Geometry.utils import INFINITE, ceil
from pycam.PathGenerators import get_max_height_dynamic from pycam.PathGenerators import get_max_height_dynamic
from pycam.Utils import ProgressCounter from pycam.Utils import ProgressCounter
from pycam.Utils.threading import run_in_parallel from pycam.Utils.threading import run_in_parallel
...@@ -117,17 +115,17 @@ class DropCutter: ...@@ -117,17 +115,17 @@ class DropCutter:
# cancel requested # cancel requested
quit_requested = True quit_requested = True
break break
for p in points: for point in points:
if p is None: if point is None:
# exceeded maxz - the cutter has to skip this point # exceeded maxz - the cutter has to skip this point
self.pa.end_scanline() self.pa.end_scanline()
self.pa.new_scanline() self.pa.new_scanline()
continue continue
self.pa.append(p) self.pa.append(point)
# "draw_callback" returns true, if the user requested to quit # "draw_callback" returns true, if the user requested to quit
# via the GUI. # via the GUI.
# The progress counter may return True, if cancel was requested. # The progress counter may return True, if cancel was requested.
if draw_callback and draw_callback(tool_position=p, if draw_callback and draw_callback(tool_position=point,
toolpath=self.pa.paths): toolpath=self.pa.paths):
quit_requested = True quit_requested = True
break break
......
...@@ -22,9 +22,10 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>. ...@@ -22,9 +22,10 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
""" """
import pycam.PathProcessors.PathAccumulator import pycam.PathProcessors.PathAccumulator
from pycam.Geometry.Point import Point from pycam.Geometry.Point import Point, Vector
from pycam.Geometry.Line import Line
from pycam.Geometry.Plane import Plane
from pycam.Geometry.utils import ceil from pycam.Geometry.utils import ceil
from pycam.PathGenerators import get_max_height_dynamic
from pycam.PathGenerators import get_max_height_dynamic, get_free_paths_ode, \ from pycam.PathGenerators import get_max_height_dynamic, get_free_paths_ode, \
get_free_paths_triangles get_free_paths_triangles
from pycam.Utils import ProgressCounter from pycam.Utils import ProgressCounter
...@@ -178,19 +179,19 @@ class EngraveCutter: ...@@ -178,19 +179,19 @@ class EngraveCutter:
# for both point pairs. # for both point pairs.
factor = (z - line.p1.z) / (line.p2.z - line.p1.z) factor = (z - line.p1.z) / (line.p2.z - line.p1.z)
plane_point = line.p1.add(line.vector.mul(factor)) plane_point = line.p1.add(line.vector.mul(factor))
GenerateToolPathLinePush(pa, Line(line.p1, plane_point), z, self.GenerateToolPathLinePush(pa, Line(line.p1, plane_point), z,
previous_z, draw_callback=draw_callback) previous_z, draw_callback=draw_callback)
GenerateToolPathLinePush(pa, Line(plane_point, line.p2), z, self.GenerateToolPathLinePush(pa, Line(plane_point, line.p2), z,
previous_z, draw_callback=draw_callback) previous_z, draw_callback=draw_callback)
elif line.minz < previous_z < line.maxz: elif line.minz < previous_z < line.maxz:
plane = Plane(Point(0, 0, previous_z), Vector(0, 0, 1)) plane = Plane(Point(0, 0, previous_z), Vector(0, 0, 1))
cp, d = plane.intersect_point(line.dir, line.p1) cp = plane.intersect_point(line.dir, line.p1)[0]
# we can be sure that there is an intersection # we can be sure that there is an intersection
if line.p1.z > previous_z: if line.p1.z > previous_z:
p1, p2 = cp, line.p2 p1, p2 = cp, line.p2
else: else:
p1, p2 = line.p1, cp p1, p2 = line.p1, cp
GenerateToolPathLinePush(pa, Line(p1, p2), z, previous_z, self.GenerateToolPathLinePush(pa, Line(p1, p2), z, previous_z,
draw_callback=draw_callback) draw_callback=draw_callback)
else: else:
if line.maxz <= z: if line.maxz <= z:
...@@ -212,12 +213,13 @@ class EngraveCutter: ...@@ -212,12 +213,13 @@ class EngraveCutter:
elif self.physics: elif self.physics:
points = get_free_paths_ode(self.physics, p1, p2) points = get_free_paths_ode(self.physics, p1, p2)
else: else:
points = get_free_paths_triangles(relevant_models, self.cutter, p1, p2) points = get_free_paths_triangles(relevant_models, self.cutter,
p1, p2)
if points: if points:
for p in points: for point in points:
pa.append(p) pa.append(point)
if draw_callback: if draw_callback:
draw_callback(tool_position=p, toolpath=pa.paths) draw_callback(tool_position=points[-1], toolpath=pa.paths)
def GenerateToolPathLineDrop(self, pa, line, minz, maxz, horiz_step, def GenerateToolPathLineDrop(self, pa, line, minz, maxz, horiz_step,
...@@ -245,16 +247,17 @@ class EngraveCutter: ...@@ -245,16 +247,17 @@ class EngraveCutter:
x_steps = [(p1.x + i * x_step) for i in range(num_of_steps)] x_steps = [(p1.x + i * x_step) for i in range(num_of_steps)]
y_steps = [(p1.y + i * y_step) for i in range(num_of_steps)] y_steps = [(p1.y + i * y_step) for i in range(num_of_steps)]
step_coords = zip(x_steps, y_steps) step_coords = zip(x_steps, y_steps)
# TODO: this "min(..)" is not correct for inclided lines. This should be fixed in "get_max_height". # TODO: this "min(..)" is not correct for inclided lines. This
# should be fixed in "get_max_height".
points = get_max_height_dynamic(self.combined_model, self.cutter, points = get_max_height_dynamic(self.combined_model, self.cutter,
step_coords, min(p1.z, p2.z), maxz, self.physics) step_coords, min(p1.z, p2.z), maxz, self.physics)
for p in points: for point in points:
if p is None: if point is None:
# exceeded maxz - the cutter has to skip this point # exceeded maxz - the cutter has to skip this point
pa.end_scanline() pa.end_scanline()
pa.new_scanline() pa.new_scanline()
continue continue
pa.append(p) pa.append(point)
if draw_callback and points: if draw_callback and points:
draw_callback(tool_position=points[-1], toolpath=pa.paths) draw_callback(tool_position=points[-1], toolpath=pa.paths)
pa.end_scanline() pa.end_scanline()
......
...@@ -21,10 +21,9 @@ You should have received a copy of the GNU General Public License ...@@ -21,10 +21,9 @@ You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>. along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
""" """
from pycam.Geometry.Point import Point
from pycam.PathGenerators import get_free_paths_ode, get_free_paths_triangles from pycam.PathGenerators import get_free_paths_ode, get_free_paths_triangles
import pycam.PathProcessors import pycam.PathProcessors
from pycam.Geometry.utils import epsilon, ceil from pycam.Geometry.utils import ceil
from pycam.Utils.threading import run_in_parallel from pycam.Utils.threading import run_in_parallel
from pycam.Utils import ProgressCounter from pycam.Utils import ProgressCounter
import pycam.Utils.log import pycam.Utils.log
...@@ -86,7 +85,8 @@ class PushCutter: ...@@ -86,7 +85,8 @@ class PushCutter:
break break
self.pa.new_direction(0) self.pa.new_direction(0)
self.GenerateToolPathSlice(layer_grid, draw_callback, progress_counter) self.GenerateToolPathSlice(layer_grid, draw_callback,
progress_counter)
self.pa.end_direction() self.pa.end_direction()
self.pa.finish() self.pa.finish()
...@@ -106,8 +106,8 @@ class PushCutter: ...@@ -106,8 +106,8 @@ class PushCutter:
for p1, p2 in pairs: for p1, p2 in pairs:
free_points = get_free_paths_triangles(other_models, free_points = get_free_paths_triangles(other_models,
self.cutter, p1, p2) self.cutter, p1, p2)
for p in free_points: for point in free_points:
final_pa.append(p) final_pa.append(point)
final_pa.end_scanline() final_pa.end_scanline()
final_pa.finish() final_pa.finish()
return final_pa.paths return final_pa.paths
...@@ -144,10 +144,10 @@ class PushCutter: ...@@ -144,10 +144,10 @@ class PushCutter:
callback=progress_counter.update): callback=progress_counter.update):
if points: if points:
self.pa.new_scanline() self.pa.new_scanline()
for p in points: for point in points:
self.pa.append(p) self.pa.append(point)
if draw_callback: if draw_callback:
draw_callback(tool_position=p, toolpath=self.pa.paths) draw_callback(tool_position=points[-1], toolpath=self.pa.paths)
self.pa.end_scanline() self.pa.end_scanline()
# update the progress counter # update the progress counter
if progress_counter and progress_counter.increment(): if progress_counter and progress_counter.increment():
......
...@@ -129,7 +129,7 @@ def get_free_paths_triangles(models, cutter, p1, p2, return_triangles=False): ...@@ -129,7 +129,7 @@ def get_free_paths_triangles(models, cutter, p1, p2, return_triangles=False):
return points return points
else: else:
# return only the cutter locations (without triangles) # return only the cutter locations (without triangles)
return [cl for (cl, t, cp) in points] return [cut_info[0] for cut_info in points]
def get_free_paths_ode(physics, p1, p2, depth=8): def get_free_paths_ode(physics, p1, p2, depth=8):
...@@ -281,9 +281,10 @@ def get_max_height_dynamic(model, cutter, positions, minz, maxz, physics=None): ...@@ -281,9 +281,10 @@ def get_max_height_dynamic(model, cutter, positions, minz, maxz, physics=None):
p1 = result[index] p1 = result[index]
p2 = result[index + 1] p2 = result[index + 1]
p3 = result[index + 2] p3 = result[index + 2]
if (not p1 is None) and (not p2 is None) and (not p3 is None) \ if (not p1 is None) and (not p2 is None) and (not p3 is None) and \
and not _check_deviance_of_adjacent_points(p1, p2, p3, min_distance) \ not _check_deviance_of_adjacent_points(p1, p2, p3,
and (depth_count < max_depth): min_distance) and \
(depth_count < max_depth):
# distribute the new point two before the middle and one after # distribute the new point two before the middle and one after
if depth_count % 3 != 2: if depth_count % 3 != 2:
# insert between the 1st and 2nd point # insert between the 1st and 2nd point
......
...@@ -23,6 +23,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>. ...@@ -23,6 +23,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
from pycam.Geometry.utils import sqrt from pycam.Geometry.utils import sqrt
from pycam.Geometry.Point import Point from pycam.Geometry.Point import Point
import ctypes import ctypes
import math
try: try:
......
...@@ -251,7 +251,6 @@ def generate_toolpath(model, tool_settings=None, ...@@ -251,7 +251,6 @@ def generate_toolpath(model, tool_settings=None,
if (not contour_model is None) and (pocketing_type != "none"): if (not contour_model is None) and (pocketing_type != "none"):
if not callback is None: if not callback is None:
callback(text="Generating pocketing polygons ...") callback(text="Generating pocketing polygons ...")
new_polygons = []
pocketing_offset = cutter.radius * 1.8 pocketing_offset = cutter.radius * 1.8
# TODO: this is an arbitrary limit to avoid infinite loops # TODO: this is an arbitrary limit to avoid infinite loops
pocketing_limit = 1000 pocketing_limit = 1000
...@@ -273,8 +272,8 @@ def generate_toolpath(model, tool_settings=None, ...@@ -273,8 +272,8 @@ def generate_toolpath(model, tool_settings=None,
else: else:
other_polygons.append(poly) other_polygons.append(poly)
else: else:
return "Unknown pocketing type given (not one of 'none', 'holes', " \ return "Unknown pocketing type given (not one of 'none', " + \
+ "'enclosed'): %s" % str(pocketing_type) "'holes', 'enclosed'): %s" % str(pocketing_type)
# For now we use only the polygons that do not surround eny other # For now we use only the polygons that do not surround eny other
# polygons. Sorry - the pocketing is currently very simple ... # polygons. Sorry - the pocketing is currently very simple ...
base_filtered_polygons = [] base_filtered_polygons = []
...@@ -402,8 +401,9 @@ def _get_pathgenerator_instance(trimesh_models, contour_model, cutter, ...@@ -402,8 +401,9 @@ def _get_pathgenerator_instance(trimesh_models, contour_model, cutter,
elif pathprocessor == "ContourCutter": elif pathprocessor == "ContourCutter":
processor = ContourCutter.ContourCutter() processor = ContourCutter.ContourCutter()
else: else:
return ("Invalid postprocessor (%s) for 'PushCutter' - it should " \ return ("Invalid postprocessor (%s) for 'PushCutter' - it " + \
+ "be one of these: %s") % (pathprocessor, PATH_POSTPROCESSORS) "should be one of these: %s") % \
(pathprocessor, PATH_POSTPROCESSORS)
return PushCutter.PushCutter(cutter, trimesh_models, processor, return PushCutter.PushCutter(cutter, trimesh_models, processor,
physics=physics) physics=physics)
elif pathgenerator == "EngraveCutter": elif pathgenerator == "EngraveCutter":
......
...@@ -110,11 +110,13 @@ def get_fixed_grid_layer(minx, maxx, miny, maxy, z, line_distance, ...@@ -110,11 +110,13 @@ def get_fixed_grid_layer(minx, maxx, miny, maxy, z, line_distance,
if milling_style == MILLING_STYLE_IGNORE: if milling_style == MILLING_STYLE_IGNORE:
# just move forward - milling style is not important # just move forward - milling style is not important
pass pass
elif (milling_style == MILLING_STYLE_CLIMB) == (grid_direction == GRID_DIRECTION_X): elif (milling_style == MILLING_STYLE_CLIMB) == \
(grid_direction == GRID_DIRECTION_X):
if bool(start_position & START_X) == bool(start_position & START_Y): if bool(start_position & START_X) == bool(start_position & START_Y):
# we can't start from here - choose an alternative # we can't start from here - choose an alternative
start_position = get_alternative_start_position(start_position) start_position = get_alternative_start_position(start_position)
elif (milling_style == MILLING_STYLE_CONVENTIONAL) == (grid_direction == GRID_DIRECTION_X): elif (milling_style == MILLING_STYLE_CONVENTIONAL) == \
(grid_direction == GRID_DIRECTION_X):
if bool(start_position & START_X) != bool(start_position & START_Y): if bool(start_position & START_X) != bool(start_position & START_Y):
# we can't start from here - choose an alternative # we can't start from here - choose an alternative
start_position = get_alternative_start_position(start_position) start_position = get_alternative_start_position(start_position)
......
...@@ -21,7 +21,6 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>. ...@@ -21,7 +21,6 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
""" """
from pycam.Geometry.Point import Point, Vector from pycam.Geometry.Point import Point, Vector
from pycam.Geometry.Line import Line
from pycam.Geometry.Triangle import Triangle from pycam.Geometry.Triangle import Triangle
from pycam.Geometry.Plane import Plane from pycam.Geometry.Plane import Plane
from pycam.Geometry.Model import Model from pycam.Geometry.Model import Model
...@@ -129,8 +128,8 @@ def get_support_grid_locations(minx, maxx, miny, maxy, dist_x, dist_y, ...@@ -129,8 +128,8 @@ def get_support_grid_locations(minx, maxx, miny, maxy, dist_x, dist_y,
def get_support_grid(minx, maxx, miny, maxy, z_plane, dist_x, dist_y, thickness, def get_support_grid(minx, maxx, miny, maxy, z_plane, dist_x, dist_y, thickness,
height, offset_x=0.0, offset_y=0.0, adjustments_x=None, height, offset_x=0.0, offset_y=0.0, adjustments_x=None,
adjustments_y=None): adjustments_y=None):
lines_x, lines_y = get_support_grid_locations(minx, maxx, miny, maxy, dist_x, lines_x, lines_y = get_support_grid_locations(minx, maxx, miny, maxy,
dist_y, offset_x, offset_y, adjustments_x, adjustments_y) dist_x, dist_y, offset_x, offset_y, adjustments_x, adjustments_y)
# create all x grid lines # create all x grid lines
grid_model = Model() grid_model = Model()
# convert all inputs to "number" # convert all inputs to "number"
...@@ -214,7 +213,8 @@ class _BridgeCorner(object): ...@@ -214,7 +213,8 @@ class _BridgeCorner(object):
return "%s (%s) - %s" % (self.position, self.location, self.priority) return "%s (%s) - %s" % (self.position, self.location, self.priority)
def _get_corner_bridges(polygon, z_plane, min_bridges, average_distance, avoid_distance): def _get_corner_bridges(polygon, z_plane, min_bridges, average_distance,
avoid_distance):
""" try to place support bridges at corners of a polygon """ try to place support bridges at corners of a polygon
Priorities: Priorities:
- bigger corner angles are preferred - bigger corner angles are preferred
...@@ -264,7 +264,8 @@ def _get_corner_bridges(polygon, z_plane, min_bridges, average_distance, avoid_d ...@@ -264,7 +264,8 @@ def _get_corner_bridges(polygon, z_plane, min_bridges, average_distance, avoid_d
corners.remove(suitable_corners[0]) corners.remove(suitable_corners[0])
return [(c.position, c.direction) for c in bridge_corners] return [(c.position, c.direction) for c in bridge_corners]
def _get_edge_bridges(polygon, z_plane, min_bridges, average_distance, avoid_distance): def _get_edge_bridges(polygon, z_plane, min_bridges, average_distance,
avoid_distance):
def is_near_list(point_list, point, distance): def is_near_list(point_list, point, distance):
for p in point_list: for p in point_list:
if p.sub(point).norm <= distance: if p.sub(point).norm <= distance:
......
...@@ -116,14 +116,15 @@ class Toolpath(object): ...@@ -116,14 +116,15 @@ class Toolpath(object):
self.append = self.append_with_movement_limit self.append = self.append_with_movement_limit
def append_with_movement_limit(self, new_position, rapid): def append_with_movement_limit(self, new_position, rapid):
if self.last_pos is None: if self.last_pos is None:
# first movement with unknown start position - thus we ignore it # first move with unknown start position - ignore it
self.moves.append((new_position, rapid)) self.moves.append((new_position, rapid))
self.last_pos = new_position self.last_pos = new_position
return True return True
else: else:
distance = new_position.sub(self.last_pos).norm distance = new_position.sub(self.last_pos).norm
if self.moved_distance + distance > self.max_movement: if self.moved_distance + distance > self.max_movement:
partial = (self.max_movement - self.moved_distance) / distance partial = (self.max_movement - self.moved_distance) / \
distance
partial_dest = self.last_pos.add(new_position.sub( partial_dest = self.last_pos.add(new_position.sub(
self.last_pos).mul(partial)) self.last_pos).mul(partial))
self.moves.append((partial_dest, rapid)) self.moves.append((partial_dest, rapid))
...@@ -213,7 +214,8 @@ class Toolpath(object): ...@@ -213,7 +214,8 @@ class Toolpath(object):
for path in self.toolpath: for path in self.toolpath:
if path: if path:
for index in range(len(path.points) - 1): for index in range(len(path.points) - 1):
open_lines.append(Line(path.points[index], path.points[index + 1])) open_lines.append(Line(path.points[index],
path.points[index + 1]))
# go through all polygons and add "inner" lines (or parts thereof) to # go through all polygons and add "inner" lines (or parts thereof) to
# the final list of remaining lines # the final list of remaining lines
inner_lines = [] inner_lines = []
......
...@@ -99,9 +99,9 @@ def get_external_program_location(key): ...@@ -99,9 +99,9 @@ def get_external_program_location(key):
location = win32api.FindExecutable(key)[1] location = win32api.FindExecutable(key)[1]
if location: if location:
return location return location
except: except Exception:
# Wildcard exeception to match "ImportError" and "pywintypes.error" # Wildcard (non-system exiting) exeception to match "ImportError" and
# (for "not found"). # "pywintypes.error" (for "not found").
pass pass
# go through the PATH environment variable # go through the PATH environment variable
if "PATH" in os.environ: if "PATH" in os.environ:
......
...@@ -45,7 +45,7 @@ try: ...@@ -45,7 +45,7 @@ try:
# prevent connection errors to trigger exceptions # prevent connection errors to trigger exceptions
try: try:
SyncManager._run_server(*args) SyncManager._run_server(*args)
except socket.error, err_msg: except socket.error:
pass pass
except ImportError: except ImportError:
pass pass
...@@ -151,7 +151,7 @@ class ManagerInfo(object): ...@@ -151,7 +151,7 @@ class ManagerInfo(object):
def init_threading(number_of_processes=None, enable_server=False, remote=None, def init_threading(number_of_processes=None, enable_server=False, remote=None,
run_server=False, server_credentials="", local_port=DEFAULT_PORT): run_server=False, server_credentials="", local_port=DEFAULT_PORT):
global __multiprocessing, __num_of_processes, __manager, __closing, global __multiprocessing, __num_of_processes, __manager, __closing, \
__task_source_uuid __task_source_uuid
if __multiprocessing: if __multiprocessing:
# kill the manager and clean everything up for a re-initialization # kill the manager and clean everything up for a re-initialization
...@@ -465,8 +465,8 @@ def _handle_tasks(tasks, results, stats, cache, pending_tasks, closing): ...@@ -465,8 +465,8 @@ def _handle_tasks(tasks, results, stats, cache, pending_tasks, closing):
def run_in_parallel_remote(func, args_list, unordered=False, def run_in_parallel_remote(func, args_list, unordered=False,
disable_multiprocessing=False, callback=None): disable_multiprocessing=False, callback=None):
global __multiprocessing, __num_of_processes, __manager, __task_source_uuid, global __multiprocessing, __num_of_processes, __manager, \
__finished_jobs __task_source_uuid, __finished_jobs
if __multiprocessing is None: if __multiprocessing is None:
# threading was not configured before # threading was not configured before
init_threading() init_threading()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment