Commit bad6bc59 authored by sumpfralle's avatar sumpfralle

added climb and conventional milling style to ContourFollow and Engrave strategy

optional visualization of directions (for contour models, toolpaths and triangle's normals)


git-svn-id: https://pycam.svn.sourceforge.net/svnroot/pycam/trunk@816 bbaffbd6-741e-11dd-a85d-61de82d9cad9
parent 3fd4780d
Version 0.4.1 - UNRELEASED Version 0.4.1 - UNRELEASED
* added support for EPS/PS contour files * added support for EPS/PS contour files
* added adaptive positioning for DropCutter strategy (improves precision) * added adaptive positioning for DropCutter strategy (improves precision)
* allow conventional/climb milling style for ContourFollow and Engrave strategies
* optional visualization of toolpath direction
Version 0.4.0.1 - 2010-10-24 Version 0.4.0.1 - 2010-10-24
* disabled parallel processing for Windows standalone executable * disabled parallel processing for Windows standalone executable
......
...@@ -5462,6 +5462,21 @@ It is significantly faster, but the current release of ODE contains a nasty bug ...@@ -5462,6 +5462,21 @@ It is significantly faster, but the current release of ODE contains a nasty bug
<property name="position">6</property> <property name="position">6</property>
</packing> </packing>
</child> </child>
<child>
<object class="GtkCheckButton" id="ShowDirectionsCheckBox">
<property name="label" translatable="yes">Show Directions</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Show the directions of some visual features (e.g. arrows
for contour lines and toolpaths, triangle's normals, et cetera).</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">7</property>
</packing>
</child>
</object> </object>
</child> </child>
</object> </object>
......
...@@ -118,13 +118,16 @@ class Line(TransformableContainer): ...@@ -118,13 +118,16 @@ class Line(TransformableContainer):
# point is self.p1 or self.p2. # point is self.p1 or self.p2.
return (dir1 == dir2 == self.dir) or (dir1 is None) or (dir2 is None) return (dir1 == dir2 == self.dir) or (dir1 is None) or (dir2 is None)
def to_OpenGL(self): def to_OpenGL(self, color=None, show_directions=False):
if GL_enabled: if not GL_enabled:
return
if not color is None:
GL.glColor4f(*color)
GL.glBegin(GL.GL_LINES) GL.glBegin(GL.GL_LINES)
GL.glVertex3f(self.p1.x, self.p1.y, self.p1.z) GL.glVertex3f(self.p1.x, self.p1.y, self.p1.z)
GL.glVertex3f(self.p2.x, self.p2.y, self.p2.z) GL.glVertex3f(self.p2.x, self.p2.y, self.p2.z)
# (optional) draw arrows for visualizing the direction of each line # (optional) draw arrows for visualizing the direction of each line
if False: if show_directions and (self.p1 != self.p2):
line = (self.p2.x - self.p1.x, self.p2.y - self.p1.y) line = (self.p2.x - self.p1.x, self.p2.y - self.p1.y)
if line[0] == 0: if line[0] == 0:
ortho = (1.0, 0.0) ortho = (1.0, 0.0)
......
...@@ -83,13 +83,14 @@ class BaseModel(TransformableContainer): ...@@ -83,13 +83,14 @@ class BaseModel(TransformableContainer):
result += item.get_children_count() result += item.get_children_count()
return result return result
def to_OpenGL(self, visible_filter=None): def to_OpenGL(self, visible_filter=None, show_directions=False):
def paint_item_filtered(item): def paint_item_filtered(item):
do_paint, color = visible_filter(item) do_paint, color = visible_filter(item)
if do_paint: if do_paint:
item.to_OpenGL(color) item.to_OpenGL(color, show_directions=show_directions)
if visible_filter is None: if visible_filter is None:
paint_item = lambda item: item.to_OpenGL() paint_item = lambda item: item.to_OpenGL(
show_directions=show_directions)
else: else:
paint_item = paint_item_filtered paint_item = paint_item_filtered
for item in self.next(): for item in self.next():
......
...@@ -101,7 +101,7 @@ class Triangle(TransformableContainer): ...@@ -101,7 +101,7 @@ class Triangle(TransformableContainer):
# tree points per triangle # tree points per triangle
return 7 return 7
def to_OpenGL(self, color=None): def to_OpenGL(self, color=None, show_directions=False):
if not GL_enabled: if not GL_enabled:
return return
if not color is None: if not color is None:
...@@ -116,7 +116,7 @@ class Triangle(TransformableContainer): ...@@ -116,7 +116,7 @@ class Triangle(TransformableContainer):
GL.glVertex3f(self.p3.x, self.p3.y, self.p3.z) GL.glVertex3f(self.p3.x, self.p3.y, self.p3.z)
GL.glVertex3f(self.p2.x, self.p2.y, self.p2.z) GL.glVertex3f(self.p2.x, self.p2.y, self.p2.z)
GL.glEnd() GL.glEnd()
if False: # display surface normals if show_directions: # display surface normals
n = self.normal n = self.normal
c = self.center c = self.center
d = 0.5 d = 0.5
......
...@@ -31,6 +31,7 @@ except (ImportError, RuntimeError): ...@@ -31,6 +31,7 @@ except (ImportError, RuntimeError):
GL_ENABLED = False GL_ENABLED = False
from pycam.Geometry.Point import Point from pycam.Geometry.Point import Point
from pycam.Geometry.Line import Line
import pycam.Geometry.Matrix as Matrix import pycam.Geometry.Matrix as Matrix
from pycam.Geometry.utils import sqrt, number from pycam.Geometry.utils import sqrt, number
import pycam.Utils.log import pycam.Utils.log
...@@ -758,7 +759,7 @@ def draw_complete_model_view(settings): ...@@ -758,7 +759,7 @@ def draw_complete_model_view(settings):
return True, normal_color return True, normal_color
model.to_OpenGL(visible_filter=check_triangle_draw) model.to_OpenGL(visible_filter=check_triangle_draw)
""" """
model.to_OpenGL() model.to_OpenGL(show_directions=settings.get("show_directions"))
# draw the support grid # draw the support grid
if settings.get("show_support_grid") and settings.get("support_grid"): if settings.get("show_support_grid") and settings.get("support_grid"):
GL.glColor4f(*settings.get("color_support_grid")) GL.glColor4f(*settings.get("color_support_grid"))
...@@ -772,7 +773,8 @@ def draw_complete_model_view(settings): ...@@ -772,7 +773,8 @@ def draw_complete_model_view(settings):
if toolpath_obj.visible: if toolpath_obj.visible:
draw_toolpath(toolpath_obj.get_path(), draw_toolpath(toolpath_obj.get_path(),
settings.get("color_toolpath_cut"), settings.get("color_toolpath_cut"),
settings.get("color_toolpath_return")) settings.get("color_toolpath_return"),
settings.get("show_directions"))
# draw the drill # draw the drill
if settings.get("show_drill_progress"): if settings.get("show_drill_progress"):
cutter = settings.get("cutter") cutter = settings.get("cutter")
...@@ -784,11 +786,13 @@ def draw_complete_model_view(settings): ...@@ -784,11 +786,13 @@ def draw_complete_model_view(settings):
if not toolpath_in_progress is None: if not toolpath_in_progress is None:
draw_toolpath(toolpath_in_progress, draw_toolpath(toolpath_in_progress,
settings.get("color_toolpath_cut"), settings.get("color_toolpath_cut"),
settings.get("color_toolpath_return")) settings.get("color_toolpath_return"),
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(toolpath, color_forward, color_backward,
show_directions=False):
GL.glMatrixMode(GL.GL_MODELVIEW) GL.glMatrixMode(GL.GL_MODELVIEW)
GL.glLoadIdentity() GL.glLoadIdentity()
if toolpath: if toolpath:
...@@ -796,15 +800,11 @@ def draw_toolpath(toolpath, color_forward, color_backward): ...@@ -796,15 +800,11 @@ def draw_toolpath(toolpath, color_forward, color_backward):
for path in toolpath: for path in toolpath:
if last: if last:
GL.glColor4f(*color_backward) GL.glColor4f(*color_backward)
GL.glBegin(GL.GL_LINES) Line(last, path.points[0]).to_OpenGL(
GL.glVertex3f(last.x, last.y, last.z) show_directions=show_directions)
last = path.points[0]
GL.glVertex3f(last.x, last.y, last.z)
GL.glEnd()
GL.glColor4f(*color_forward) GL.glColor4f(*color_forward)
GL.glBegin(GL.GL_LINE_STRIP) for index in range(len(path.points) - 1):
for point in path.points: Line(path.points[index], path.points[index + 1]).to_OpenGL(
GL.glVertex3f(point.x, point.y, point.z) show_directions=show_directions)
GL.glEnd()
last = path.points[-1] last = path.points[-1]
...@@ -87,6 +87,7 @@ PREFERENCES_DEFAULTS = { ...@@ -87,6 +87,7 @@ PREFERENCES_DEFAULTS = {
"show_bounding_box": True, "show_bounding_box": True,
"show_toolpath": True, "show_toolpath": True,
"show_drill_progress": False, "show_drill_progress": False,
"show_directions": False,
"color_background": (0.0, 0.0, 0.0, 1.0), "color_background": (0.0, 0.0, 0.0, 1.0),
"color_model": (0.5, 0.5, 1.0, 1.0), "color_model": (0.5, 0.5, 1.0, 1.0),
"color_support_grid": (0.8, 0.8, 0.3, 1.0), "color_support_grid": (0.8, 0.8, 0.3, 1.0),
...@@ -495,7 +496,8 @@ class ProjectGui: ...@@ -495,7 +496,8 @@ class ProjectGui:
("show_dimensions", "ShowDimensionsCheckBox"), ("show_dimensions", "ShowDimensionsCheckBox"),
("show_bounding_box", "ShowBoundingCheckBox"), ("show_bounding_box", "ShowBoundingCheckBox"),
("show_toolpath", "ShowToolPathCheckBox"), ("show_toolpath", "ShowToolPathCheckBox"),
("show_drill_progress", "ShowDrillProgressCheckBox")): ("show_drill_progress", "ShowDrillProgressCheckBox"),
("show_directions", "ShowDirectionsCheckBox")):
obj = self.gui.get_object(objname) obj = self.gui.get_object(objname)
self.settings.add_item(name, obj.get_active, obj.set_active) self.settings.add_item(name, obj.get_active, obj.set_active)
# all of the objects above should trigger redraw # all of the objects above should trigger redraw
...@@ -1349,13 +1351,13 @@ class ProjectGui: ...@@ -1349,13 +1351,13 @@ class ProjectGui:
"MillingStyleIgnore", "MaxStepDownControl", "MillingStyleIgnore", "MaxStepDownControl",
"MaterialAllowanceControl", "OverlapPercentControl"), "MaterialAllowanceControl", "OverlapPercentControl"),
"ContourFollowStrategy": ("MillingStyleConventional", "ContourFollowStrategy": ("MillingStyleConventional",
"MillingStyleClimb", "MillingStyleIgnore", "MillingStyleClimb", "MaxStepDownControl"),
"MaxStepDownControl"),
"SurfaceStrategy": ("GridDirectionX", "GridDirectionY", "SurfaceStrategy": ("GridDirectionX", "GridDirectionY",
"MillingStyleConventional", "MillingStyleClimb", "MillingStyleConventional", "MillingStyleClimb",
"MillingStyleIgnore", "MaterialAllowanceControl", "MillingStyleIgnore", "MaterialAllowanceControl",
"OverlapPercentControl"), "OverlapPercentControl"),
"EngraveStrategy": ("MaxStepDownControl", "EngraveOffsetControl"), "EngraveStrategy": ("MaxStepDownControl", "EngraveOffsetControl",
"MillingStyleConventional", "MillingStyleClimb"),
} }
for one_control in all_controls: for one_control in all_controls:
get_obj(one_control).set_sensitive(one_control in active_controls[cutter_name]) get_obj(one_control).set_sensitive(one_control in active_controls[cutter_name])
......
...@@ -199,6 +199,7 @@ path_strategy: ContourFollowStrategy ...@@ -199,6 +199,7 @@ path_strategy: ContourFollowStrategy
material_allowance: 0.2 material_allowance: 0.2
step_down: 1.5 step_down: 1.5
overlap_percent: 40 overlap_percent: 40
milling_style: conventional
[Process2] [Process2]
name: Cleanup name: Cleanup
...@@ -211,6 +212,7 @@ name: Gravure ...@@ -211,6 +212,7 @@ name: Gravure
path_strategy: EngraveStrategy path_strategy: EngraveStrategy
step_down: 1.0 step_down: 1.0
overlap_percent: 50 overlap_percent: 50
milling_style: conventional
[BoundsDefault] [BoundsDefault]
type: relative_margin type: relative_margin
...@@ -703,7 +705,6 @@ class ToolpathSettings: ...@@ -703,7 +705,6 @@ class ToolpathSettings:
# TODO: this hack should be somewhere else, I guess # TODO: this hack should be somewhere else, I guess
if generator in ("ContourFollow", "EngraveCutter"): if generator in ("ContourFollow", "EngraveCutter"):
material_allowance = 0.0 material_allowance = 0.0
milling_style = "ignore"
self.process_settings = { self.process_settings = {
"generator": generator, "generator": generator,
"postprocessor": postprocessor, "postprocessor": postprocessor,
......
...@@ -41,6 +41,7 @@ class SimpleCutter: ...@@ -41,6 +41,7 @@ class SimpleCutter:
if self.curr_path == None: if self.curr_path == None:
simplify_toolpath(curr_path) simplify_toolpath(curr_path)
if self.reverse: if self.reverse:
curr_path.reverse()
self.paths.insert(0, curr_path) self.paths.insert(0, curr_path)
else: else:
self.paths.append(curr_path) self.paths.append(curr_path)
......
...@@ -254,7 +254,8 @@ def generate_toolpath(model, tool_settings=None, ...@@ -254,7 +254,8 @@ def generate_toolpath(model, tool_settings=None,
if isinstance(physics, basestring): if isinstance(physics, basestring):
return physics return physics
generator = _get_pathgenerator_instance(trimesh_models, contour_model, generator = _get_pathgenerator_instance(trimesh_models, contour_model,
cutter, path_generator, path_postprocessor, physics) cutter, path_generator, path_postprocessor, physics,
milling_style=milling_style)
if isinstance(generator, basestring): if isinstance(generator, basestring):
return generator return generator
if (overlap < 0) or (overlap >= 1): if (overlap < 0) or (overlap >= 1):
...@@ -278,13 +279,15 @@ def generate_toolpath(model, tool_settings=None, ...@@ -278,13 +279,15 @@ def generate_toolpath(model, tool_settings=None,
"ignore": pycam.Toolpath.MotionGrid.MILLING_STYLE_IGNORE, "ignore": pycam.Toolpath.MotionGrid.MILLING_STYLE_IGNORE,
"conventional": pycam.Toolpath.MotionGrid.MILLING_STYLE_CONVENTIONAL, "conventional": pycam.Toolpath.MotionGrid.MILLING_STYLE_CONVENTIONAL,
"climb": pycam.Toolpath.MotionGrid.MILLING_STYLE_CLIMB} "climb": pycam.Toolpath.MotionGrid.MILLING_STYLE_CLIMB}
if path_generator in ("DropCutter", "PushCutter"):
motion_grid = pycam.Toolpath.MotionGrid.get_fixed_grid(bounds, motion_grid = pycam.Toolpath.MotionGrid.get_fixed_grid(bounds,
layer_distance, line_stepping, step_width=step_width, layer_distance, line_stepping, step_width=step_width,
grid_direction=direction_dict[direction], grid_direction=direction_dict[direction],
milling_style=milling_style_grid[milling_style]) milling_style=milling_style_grid[milling_style])
if path_generator == "DropCutter": if path_generator == "DropCutter":
toolpath = generator.GenerateToolPath(motion_grid, minz, maxz, callback) toolpath = generator.GenerateToolPath(motion_grid, minz, maxz,
elif path_generator == "PushCutter": callback)
else:
toolpath = generator.GenerateToolPath(motion_grid, callback) toolpath = generator.GenerateToolPath(motion_grid, callback)
elif path_generator == "EngraveCutter": elif path_generator == "EngraveCutter":
if step_down > 0: if step_down > 0:
...@@ -308,7 +311,7 @@ def generate_toolpath(model, tool_settings=None, ...@@ -308,7 +311,7 @@ def generate_toolpath(model, tool_settings=None,
return toolpath return toolpath
def _get_pathgenerator_instance(trimesh_models, contour_model, cutter, def _get_pathgenerator_instance(trimesh_models, contour_model, cutter,
pathgenerator, pathprocessor, physics): pathgenerator, pathprocessor, physics, milling_style):
if pathgenerator != "EngraveCutter" and contour_model: if pathgenerator != "EngraveCutter" and contour_model:
return ("The only available toolpath strategy for 2D contour models " \ return ("The only available toolpath strategy for 2D contour models " \
+ "is 'Engraving'.") + "is 'Engraving'.")
...@@ -340,8 +343,9 @@ def _get_pathgenerator_instance(trimesh_models, contour_model, cutter, ...@@ -340,8 +343,9 @@ def _get_pathgenerator_instance(trimesh_models, contour_model, cutter,
return PushCutter.PushCutter(cutter, trimesh_models, processor, return PushCutter.PushCutter(cutter, trimesh_models, processor,
physics=physics) physics=physics)
elif pathgenerator == "EngraveCutter": elif pathgenerator == "EngraveCutter":
reverse = (milling_style == "conventional")
if pathprocessor == "SimpleCutter": if pathprocessor == "SimpleCutter":
processor = pycam.PathProcessors.SimpleCutter() processor = pycam.PathProcessors.SimpleCutter(reverse=reverse)
else: else:
return ("Invalid postprocessor (%s) for 'EngraveCutter' - it " \ return ("Invalid postprocessor (%s) for 'EngraveCutter' - it " \
+ "should be: SimpleCutter") % str(pathprocessor) + "should be: SimpleCutter") % str(pathprocessor)
...@@ -351,8 +355,9 @@ def _get_pathgenerator_instance(trimesh_models, contour_model, cutter, ...@@ -351,8 +355,9 @@ def _get_pathgenerator_instance(trimesh_models, contour_model, cutter,
return EngraveCutter.EngraveCutter(cutter, trimesh_models, return EngraveCutter.EngraveCutter(cutter, trimesh_models,
contour_model, processor, physics=physics) contour_model, processor, physics=physics)
elif pathgenerator == "ContourFollow": elif pathgenerator == "ContourFollow":
reverse = (milling_style == "conventional")
if pathprocessor == "SimpleCutter": if pathprocessor == "SimpleCutter":
processor = pycam.PathProcessors.SimpleCutter() processor = pycam.PathProcessors.SimpleCutter(reverse=reverse)
else: else:
return ("Invalid postprocessor (%s) for 'ContourFollow' - it " \ return ("Invalid postprocessor (%s) for 'ContourFollow' - it " \
+ "should be: SimpleCutter") % str(pathprocessor) + "should be: SimpleCutter") % str(pathprocessor)
......
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