Commit 61893a20 authored by sumpfralle's avatar sumpfralle

moved all of the toolpath visualization and export code to ToolpathSettings


git-svn-id: https://pycam.svn.sourceforge.net/svnroot/pycam/trunk@844 bbaffbd6-741e-11dd-a85d-61de82d9cad9
parent b7acd0b6
...@@ -37,8 +37,7 @@ PATH_MODES = {"exact_path": 0, "exact_stop": 1, "continuous": 2} ...@@ -37,8 +37,7 @@ PATH_MODES = {"exact_path": 0, "exact_stop": 1, "continuous": 2}
class GCodeGenerator: class GCodeGenerator:
def __init__(self, destination, metric_units=True, safety_height=0.0, def __init__(self, destination, metric_units=True, safety_height=0.0,
toggle_spindle_status=False, max_skip_safety_distance=None, toggle_spindle_status=False, header=None, comment=None):
header=None, comment=None):
if isinstance(destination, basestring): if isinstance(destination, basestring):
# open the file # open the file
self.destination = file(destination,"w") self.destination = file(destination,"w")
...@@ -51,10 +50,8 @@ class GCodeGenerator: ...@@ -51,10 +50,8 @@ class GCodeGenerator:
self._close_stream_on_exit = False self._close_stream_on_exit = False
self.safety_height = safety_height self.safety_height = safety_height
self.gcode = gcode(safetyheight=self.safety_height) self.gcode = gcode(safetyheight=self.safety_height)
self.max_skip_safety_distance = max_skip_safety_distance
self.toggle_spindle_status = toggle_spindle_status self.toggle_spindle_status = toggle_spindle_status
self.comment = comment self.comment = comment
self._last_path_point = None
self._finished = False self._finished = False
if comment: if comment:
self.add_comment(comment) self.add_comment(comment)
...@@ -94,55 +91,26 @@ class GCodeGenerator: ...@@ -94,55 +91,26 @@ class GCodeGenerator:
% str(mode)) % str(mode))
self.append(result) self.append(result)
def add_path_list(self, paths, tool_id=None, max_skip_safety_distance=None, def add_moves(self, moves, tool_id=None, comment=None):
comment=None):
if max_skip_safety_distance is None:
max_skip_safety_distance = self.max_skip_safety_distance
if not comment is None: if not comment is None:
self.add_comment(comment) self.add_comment(comment)
if not tool_id is None: # move straight up to safety height
# Move straight up to safety height (avoiding any collisions on the
# way to the tool changer).
self.append(self.gcode.safety()) self.append(self.gcode.safety())
if not tool_id is None:
self.append("T%d M6" % tool_id) self.append("T%d M6" % tool_id)
if self.toggle_spindle_status: if self.toggle_spindle_status:
self.append("M3 (start spindle)") self.append("M3 (start spindle)")
self.append(self.gcode.delay(2)) self.append(self.gcode.delay(2))
# move straight up to safety height for pos, rapid in moves:
self.append(self.gcode.safety()) if rapid:
for path in paths: self.append(self.gcode.rapid(pos.x, pos.y, pos.z))
self.add_path(path, max_skip_safety_distance=max_skip_safety_distance) else:
self.append(self.gcode.cut(pos.x, pos.y, pos.z))
# go back to safety height # go back to safety height
self.append(self.gcode.safety()) self.append(self.gcode.safety())
if self.toggle_spindle_status: if self.toggle_spindle_status:
self.append("M5 (stop spindle)") self.append("M5 (stop spindle)")
def _check_distance_for_skipping_safety_height(self, new_point,
max_skip_safety_distance):
if (self._last_path_point is None) \
or (max_skip_safety_distance is None):
return False
distance = new_point.sub(self._last_path_point).norm
return distance <= max_skip_safety_distance
def add_path(self, path, max_skip_safety_distance=None):
if not path:
return
point = path.points[0]
# first move to the safety height if the distance to the last point
# does not exceed the given maximum
if not self._check_distance_for_skipping_safety_height(point,
max_skip_safety_distance):
# move to safety height at the end of the previous path
if not self._last_path_point is None:
self.append(self.gcode.safety())
# move to safety height for the start of the current path
self.append(self.gcode.rapid(point.x, point.y,
self.safety_height))
for point in path.points:
self.append(self.gcode.cut(point.x, point.y, point.z))
self._last_path_point = point
def finish(self): def finish(self):
self.append(self.gcode.safety()) self.append(self.gcode.safety())
self.append("M2 (end program)") self.append("M2 (end program)")
......
...@@ -766,71 +766,55 @@ def draw_complete_model_view(settings): ...@@ -766,71 +766,55 @@ def draw_complete_model_view(settings):
settings.get("support_grid").to_OpenGL() settings.get("support_grid").to_OpenGL()
# draw the toolpath # draw the toolpath
# don't do it, if a new toolpath is just being calculated # don't do it, if a new toolpath is just being calculated
safety_height = settings.get("gcode_safety_height")
if settings.get("show_toolpath") \ if settings.get("show_toolpath") \
and not (settings.get("show_drill_progress") \ and not (settings.get("show_drill_progress") \
and (not settings.get("toolpath_in_progress") is None)): and (not settings.get("toolpath_in_progress") is None)):
for toolpath_obj in settings.get("toolpath"): for toolpath_obj in settings.get("toolpath"):
if toolpath_obj.visible: if toolpath_obj.visible:
draw_toolpath(toolpath_obj.get_path(), draw_toolpath(toolpath_obj.get_moves(safety_height),
settings.get("color_toolpath_cut"), settings.get("color_toolpath_cut"),
settings.get("color_toolpath_return"), settings.get("color_toolpath_return"),
safety_height=settings.get("gcode_safety_height"),
show_directions=settings.get("show_directions")) show_directions=settings.get("show_directions"))
# draw the drill # draw the drill
if settings.get("show_drill_progress"): if settings.get("show_drill_progress") \
and settings.get("toolpath_in_progress"):
cutter = settings.get("cutter") cutter = settings.get("cutter")
if not cutter is None: if not cutter is None:
GL.glColor4f(*settings.get("color_cutter")) GL.glColor4f(*settings.get("color_cutter"))
cutter.to_OpenGL() cutter.to_OpenGL()
# also show the toolpath that is currently being calculated # also show the toolpath that is currently being calculated
toolpath_in_progress = settings.get("toolpath_in_progress") toolpath_in_progress = settings.get("toolpath_in_progress")
# do a quick conversion from a list of Paths to a list of points
moves = []
for path in toolpath_in_progress:
for point in path.points:
moves.append((point, False))
if not toolpath_in_progress is None: if not toolpath_in_progress is None:
draw_toolpath(toolpath_in_progress, draw_toolpath(moves, settings.get("color_toolpath_cut"),
settings.get("color_toolpath_cut"),
settings.get("color_toolpath_return"), settings.get("color_toolpath_return"),
safety_height=settings.get("gcode_safety_height"),
show_directions=settings.get("show_directions")) show_directions=settings.get("show_directions"))
@keep_gl_mode @keep_gl_mode
@keep_matrix @keep_matrix
def draw_toolpath(toolpath, color_forward, color_backward, def draw_toolpath(moves, color_cut, color_rapid, show_directions=False):
safety_height=None, show_directions=False):
draw_line = lambda p1, p2: Line(p1, p2).to_OpenGL(
show_directions=show_directions)
GL.glMatrixMode(GL.GL_MODELVIEW) GL.glMatrixMode(GL.GL_MODELVIEW)
GL.glLoadIdentity() GL.glLoadIdentity()
p_last = None last_position = None
if toolpath: last_rapid = None
for path in toolpath: GL.glBegin(GL.GL_LINE_STRIP)
if not path: for position, rapid in moves:
# ignore empty paths if last_rapid != rapid:
continue GL.glEnd()
if (p_last is None) and (not safety_height is None): if rapid:
current = path.points[0] GL.glColor4f(*color_rapid)
p_last = Point(current.x, current.y, safety_height)
if p_last:
p_next = path.points[0]
GL.glColor4f(*color_backward)
# Draw the connection between the last and the next path.
# Respect the safety height.
if (not safety_height is None) and \
((abs(p_last.x - p_next.x) > epsilon) \
or (abs(p_last.y - p_next.y) > epsilon)):
# first move up
safety_last = Point(p_last.x, p_last.y, safety_height)
safety_next = Point(p_next.x, p_next.y, safety_height)
connect_points = (p_last, safety_last, safety_next, p_next)
else: else:
# ignore safety height GL.glColor4f(*color_cut)
connect_points = (p_last, p_next) GL.glBegin(GL.GL_LINE_STRIP)
for i in range(len(connect_points) - 1): if not last_position is None:
draw_line(connect_points[i], connect_points[i + 1]) GL.glVertex3f(last_position.x, last_position.y, last_position.z)
GL.glColor4f(*color_forward) last_rapid = rapid
for index in range(len(path.points) - 1): GL.glVertex3f(position.x, position.y, position.z)
draw_line(path.points[index], path.points[index + 1]) last_position = position
p_last = path.points[-1] GL.glEnd()
if (not p_last is None) and (not safety_height is None):
GL.glColor4f(*color_backward)
p_last_safety = Point(p_last.x, p_last.y, safety_height)
draw_line(p_last, p_last_safety)
...@@ -100,7 +100,7 @@ PREFERENCES_DEFAULTS = { ...@@ -100,7 +100,7 @@ PREFERENCES_DEFAULTS = {
"color_bounding_box": (0.3, 0.3, 0.3, 1.0), "color_bounding_box": (0.3, 0.3, 0.3, 1.0),
"color_cutter": (1.0, 0.2, 0.2, 1.0), "color_cutter": (1.0, 0.2, 0.2, 1.0),
"color_toolpath_cut": (1.0, 0.5, 0.5, 1.0), "color_toolpath_cut": (1.0, 0.5, 0.5, 1.0),
"color_toolpath_return": (0.5, 1.0, 0.5, 1.0), "color_toolpath_return": (0.9, 1.0, 0.1, 0.4),
"color_material": (1.0, 0.5, 0.0, 1.0), "color_material": (1.0, 0.5, 0.0, 1.0),
"view_light": True, "view_light": True,
"view_shadow": True, "view_shadow": True,
...@@ -2874,7 +2874,7 @@ class ProjectGui: ...@@ -2874,7 +2874,7 @@ class ProjectGui:
tool["id"], process["material_allowance"], tool["id"], process["material_allowance"],
tool["speed"], tool["feedrate"], tool["speed"], tool["feedrate"],
get_time_string(tp.get_machine_time( get_time_string(tp.get_machine_time(
safety_height=self.settings.get("gcode_safety_height")))) self.settings.get("gcode_safety_height"))))
model.append(items) model.append(items)
if not new_index is None: if not new_index is None:
self._treeview_set_active_index(self.toolpath_table, new_index) self._treeview_set_active_index(self.toolpath_table, new_index)
...@@ -3002,7 +3002,7 @@ class ProjectGui: ...@@ -3002,7 +3002,7 @@ class ProjectGui:
return return
else: else:
toolpath = self.toolpath[toolpath_index] toolpath = self.toolpath[toolpath_index]
paths = toolpath.get_path() paths = toolpath.get_paths()
# set the current cutter # set the current cutter
self.cutter = pycam.Cutters.get_tool_from_settings( self.cutter = pycam.Cutters.get_tool_from_settings(
toolpath.get_tool_settings()) toolpath.get_tool_settings())
...@@ -3358,10 +3358,11 @@ class ProjectGui: ...@@ -3358,10 +3358,11 @@ class ProjectGui:
"gcode_safety_height"), self.settings.get("maxz"))) "gcode_safety_height"), self.settings.get("maxz")))
try: try:
destination = open(filename, "w") destination = open(filename, "w")
safety_height=self.settings.get("gcode_safety_height")
generator = pycam.Exporters.GCodeExporter.GCodeGenerator( generator = pycam.Exporters.GCodeExporter.GCodeGenerator(
destination, destination,
metric_units=(self.settings.get("unit") == "mm"), metric_units=(self.settings.get("unit") == "mm"),
safety_height=self.settings.get("gcode_safety_height"), safety_height=safety_height,
toggle_spindle_status=self.settings.get("gcode_start_stop_spindle"), toggle_spindle_status=self.settings.get("gcode_start_stop_spindle"),
comment=self.get_meta_data()) comment=self.get_meta_data())
path_mode = self.settings.get("gcode_path_mode") path_mode = self.settings.get("gcode_path_mode")
...@@ -3384,9 +3385,8 @@ class ProjectGui: ...@@ -3384,9 +3385,8 @@ class ProjectGui:
process = settings.get_process_settings() process = settings.get_process_settings()
tool = settings.get_tool_settings() tool = settings.get_tool_settings()
generator.set_speed(tool["feedrate"], tool["speed"]) generator.set_speed(tool["feedrate"], tool["speed"])
generator.add_path_list(tp.get_path(), tool_id=tool["id"], generator.add_moves(tp.get_moves(safety_height),
max_skip_safety_distance=2*tool["tool_radius"], tool_id=tool["id"], comment=tp.get_meta_data())
comment=tp.get_meta_data())
generator.finish() generator.finish()
destination.close() destination.close()
log.info("GCode file successfully written: %s" % str(filename)) log.info("GCode file successfully written: %s" % str(filename))
......
...@@ -23,7 +23,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>. ...@@ -23,7 +23,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
__all__ = ["simplify_toolpath", "ToolpathList", "Toolpath", "Generator"] __all__ = ["simplify_toolpath", "ToolpathList", "Toolpath", "Generator"]
from pycam.Geometry.Point import Point from pycam.Geometry.Point import Point
from pycam.Geometry.utils import number from pycam.Geometry.utils import number, epsilon
import pycam.Utils.log import pycam.Utils.log
import random import random
import os import os
...@@ -75,7 +75,7 @@ class Toolpath(object): ...@@ -75,7 +75,7 @@ class Toolpath(object):
# generate random color # generate random color
self.set_color() self.set_color()
def get_path(self): def get_paths(self):
return self.toolpath return self.toolpath
def get_bounding_box(self): def get_bounding_box(self):
...@@ -101,40 +101,61 @@ class Toolpath(object): ...@@ -101,40 +101,61 @@ class Toolpath(object):
else: else:
self.color = color self.color = color
def get_machine_time(self, start_position=None, safety_height=0.0): def get_moves(self, safety_height):
result = []
paths = self.get_paths()
p_last = None
max_safe_distance = 2 * self.toolpath_settings.get_tool().radius \
+ epsilon
for path in paths:
if not path:
# ignore empty paths
continue
p_next = path.points[0]
if p_last is None:
p_last = Point(p_next.x, p_next.y, safety_height)
result.append((p_last, True))
if ((abs(p_last.x - p_next.x) > epsilon) \
or (abs(p_last.y - p_next.y) > epsilon)):
# Draw the connection between the last and the next path.
# Respect the safety height.
if (abs(p_last.z - p_next.z) > epsilon) \
or (p_last.sub(p_next).norm > max_safe_distance):
# The distance between these two points is too far.
# This condition helps to prevent moves up/down for
# adjacent lines.
safety_last = Point(p_last.x, p_last.y, safety_height)
safety_next = Point(p_next.x, p_next.y, safety_height)
result.append((safety_last, True))
result.append((safety_next, True))
for p in path.points:
result.append((p, False))
p_last = path.points[-1]
if not p_last is None:
p_last_safety = Point(p_last.x, p_last.y, safety_height)
result.append((p_last_safety, True))
return result
def get_machine_time(self, safety_height=0.0):
""" calculate an estimation of the time required for processing the """ calculate an estimation of the time required for processing the
toolpath with the machine toolpath with the machine
@value start_position: (optional) the position of the tool before the @value safety_height: the safety height configured for this toolpath
start @type safety_height: float
@type start_position: pycam.Geometry.Point.Point
@rtype: float @rtype: float
@returns: the machine time used for processing the toolpath in minutes @returns: the machine time used for processing the toolpath in minutes
""" """
settings = self.toolpath_settings result = 0
if start_position is None: feedrate = self.toolpath_settings.get_tool_settings()["feedrate"]
start_position = Point(0, 0, 0) feedrate = number(feedrate)
feedrate = number(settings.get_tool_settings()["feedrate"])
result = {}
result["time"] = 0
result["position"] = start_position
def move(new_pos):
result["time"] += new_pos.sub(result["position"]).norm / feedrate
result["position"] = new_pos
# move to safey height at the starting position
safety_height = number(safety_height) safety_height = number(safety_height)
move(Point(start_position.x, start_position.y, safety_height)) current_position = None
for path in self.get_path():
# go to safety height (horizontally from the previous x/y location)
if len(path.points) > 0:
move(Point(path.points[0].x, path.points[0].y, safety_height))
# go through all points of the path # go through all points of the path
for point in path.points: for new_pos, rapid in self.get_moves(safety_height):
move(point) if not current_position is None:
# go to safety height (vertically up from the current x/y location) result += new_pos.sub(current_position).norm / feedrate
if len(path.points) > 0: current_position = new_pos
move(Point(path.points[-1].x, path.points[-1].y, safety_height)) return result
return result["time"]
class Bounds: class Bounds:
......
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