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}
class GCodeGenerator:
def __init__(self, destination, metric_units=True, safety_height=0.0,
toggle_spindle_status=False, max_skip_safety_distance=None,
header=None, comment=None):
toggle_spindle_status=False, header=None, comment=None):
if isinstance(destination, basestring):
# open the file
self.destination = file(destination,"w")
......@@ -51,10 +50,8 @@ class GCodeGenerator:
self._close_stream_on_exit = False
self.safety_height = 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.comment = comment
self._last_path_point = None
self._finished = False
if comment:
self.add_comment(comment)
......@@ -94,55 +91,26 @@ class GCodeGenerator:
% str(mode))
self.append(result)
def add_path_list(self, paths, tool_id=None, max_skip_safety_distance=None,
comment=None):
if max_skip_safety_distance is None:
max_skip_safety_distance = self.max_skip_safety_distance
def add_moves(self, moves, tool_id=None, comment=None):
if not comment is None:
self.add_comment(comment)
if not tool_id is None:
# Move straight up to safety height (avoiding any collisions on the
# way to the tool changer).
# move straight up to safety height
self.append(self.gcode.safety())
if not tool_id is None:
self.append("T%d M6" % tool_id)
if self.toggle_spindle_status:
self.append("M3 (start spindle)")
self.append(self.gcode.delay(2))
# move straight up to safety height
self.append(self.gcode.safety())
for path in paths:
self.add_path(path, max_skip_safety_distance=max_skip_safety_distance)
for pos, rapid in moves:
if rapid:
self.append(self.gcode.rapid(pos.x, pos.y, pos.z))
else:
self.append(self.gcode.cut(pos.x, pos.y, pos.z))
# go back to safety height
self.append(self.gcode.safety())
if self.toggle_spindle_status:
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):
self.append(self.gcode.safety())
self.append("M2 (end program)")
......
......@@ -766,71 +766,55 @@ def draw_complete_model_view(settings):
settings.get("support_grid").to_OpenGL()
# draw the toolpath
# don't do it, if a new toolpath is just being calculated
safety_height = settings.get("gcode_safety_height")
if settings.get("show_toolpath") \
and not (settings.get("show_drill_progress") \
and (not settings.get("toolpath_in_progress") is None)):
for toolpath_obj in settings.get("toolpath"):
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_return"),
safety_height=settings.get("gcode_safety_height"),
show_directions=settings.get("show_directions"))
# 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")
if not cutter is None:
GL.glColor4f(*settings.get("color_cutter"))
cutter.to_OpenGL()
# also show the toolpath that is currently being calculated
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:
draw_toolpath(toolpath_in_progress,
settings.get("color_toolpath_cut"),
draw_toolpath(moves, settings.get("color_toolpath_cut"),
settings.get("color_toolpath_return"),
safety_height=settings.get("gcode_safety_height"),
show_directions=settings.get("show_directions"))
@keep_gl_mode
@keep_matrix
def draw_toolpath(toolpath, color_forward, color_backward,
safety_height=None, show_directions=False):
draw_line = lambda p1, p2: Line(p1, p2).to_OpenGL(
show_directions=show_directions)
def draw_toolpath(moves, color_cut, color_rapid, show_directions=False):
GL.glMatrixMode(GL.GL_MODELVIEW)
GL.glLoadIdentity()
p_last = None
if toolpath:
for path in toolpath:
if not path:
# ignore empty paths
continue
if (p_last is None) and (not safety_height is None):
current = path.points[0]
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)
last_position = None
last_rapid = None
GL.glBegin(GL.GL_LINE_STRIP)
for position, rapid in moves:
if last_rapid != rapid:
GL.glEnd()
if rapid:
GL.glColor4f(*color_rapid)
else:
# ignore safety height
connect_points = (p_last, p_next)
for i in range(len(connect_points) - 1):
draw_line(connect_points[i], connect_points[i + 1])
GL.glColor4f(*color_forward)
for index in range(len(path.points) - 1):
draw_line(path.points[index], path.points[index + 1])
p_last = path.points[-1]
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)
GL.glColor4f(*color_cut)
GL.glBegin(GL.GL_LINE_STRIP)
if not last_position is None:
GL.glVertex3f(last_position.x, last_position.y, last_position.z)
last_rapid = rapid
GL.glVertex3f(position.x, position.y, position.z)
last_position = position
GL.glEnd()
......@@ -100,7 +100,7 @@ PREFERENCES_DEFAULTS = {
"color_bounding_box": (0.3, 0.3, 0.3, 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_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),
"view_light": True,
"view_shadow": True,
......@@ -2874,7 +2874,7 @@ class ProjectGui:
tool["id"], process["material_allowance"],
tool["speed"], tool["feedrate"],
get_time_string(tp.get_machine_time(
safety_height=self.settings.get("gcode_safety_height"))))
self.settings.get("gcode_safety_height"))))
model.append(items)
if not new_index is None:
self._treeview_set_active_index(self.toolpath_table, new_index)
......@@ -3002,7 +3002,7 @@ class ProjectGui:
return
else:
toolpath = self.toolpath[toolpath_index]
paths = toolpath.get_path()
paths = toolpath.get_paths()
# set the current cutter
self.cutter = pycam.Cutters.get_tool_from_settings(
toolpath.get_tool_settings())
......@@ -3358,10 +3358,11 @@ class ProjectGui:
"gcode_safety_height"), self.settings.get("maxz")))
try:
destination = open(filename, "w")
safety_height=self.settings.get("gcode_safety_height")
generator = pycam.Exporters.GCodeExporter.GCodeGenerator(
destination,
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"),
comment=self.get_meta_data())
path_mode = self.settings.get("gcode_path_mode")
......@@ -3384,9 +3385,8 @@ class ProjectGui:
process = settings.get_process_settings()
tool = settings.get_tool_settings()
generator.set_speed(tool["feedrate"], tool["speed"])
generator.add_path_list(tp.get_path(), tool_id=tool["id"],
max_skip_safety_distance=2*tool["tool_radius"],
comment=tp.get_meta_data())
generator.add_moves(tp.get_moves(safety_height),
tool_id=tool["id"], comment=tp.get_meta_data())
generator.finish()
destination.close()
log.info("GCode file successfully written: %s" % str(filename))
......
......@@ -23,7 +23,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
__all__ = ["simplify_toolpath", "ToolpathList", "Toolpath", "Generator"]
from pycam.Geometry.Point import Point
from pycam.Geometry.utils import number
from pycam.Geometry.utils import number, epsilon
import pycam.Utils.log
import random
import os
......@@ -75,7 +75,7 @@ class Toolpath(object):
# generate random color
self.set_color()
def get_path(self):
def get_paths(self):
return self.toolpath
def get_bounding_box(self):
......@@ -101,40 +101,61 @@ class Toolpath(object):
else:
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
toolpath with the machine
@value start_position: (optional) the position of the tool before the
start
@type start_position: pycam.Geometry.Point.Point
@value safety_height: the safety height configured for this toolpath
@type safety_height: float
@rtype: float
@returns: the machine time used for processing the toolpath in minutes
"""
settings = self.toolpath_settings
if start_position is None:
start_position = Point(0, 0, 0)
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
result = 0
feedrate = self.toolpath_settings.get_tool_settings()["feedrate"]
feedrate = number(feedrate)
safety_height = number(safety_height)
move(Point(start_position.x, start_position.y, safety_height))
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))
current_position = None
# go through all points of the path
for point in path.points:
move(point)
# go to safety height (vertically up from the current x/y location)
if len(path.points) > 0:
move(Point(path.points[-1].x, path.points[-1].y, safety_height))
return result["time"]
for new_pos, rapid in self.get_moves(safety_height):
if not current_position is None:
result += new_pos.sub(current_position).norm / feedrate
current_position = new_pos
return result
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