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
* added support for EPS/PS contour files
* 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
* 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
<property name="position">6</property>
</packing>
</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>
</child>
</object>
......
......@@ -118,36 +118,39 @@ class Line(TransformableContainer):
# point is self.p1 or self.p2.
return (dir1 == dir2 == self.dir) or (dir1 is None) or (dir2 is None)
def to_OpenGL(self):
if GL_enabled:
GL.glBegin(GL.GL_LINES)
GL.glVertex3f(self.p1.x, self.p1.y, self.p1.z)
def to_OpenGL(self, color=None, show_directions=False):
if not GL_enabled:
return
if not color is None:
GL.glColor4f(*color)
GL.glBegin(GL.GL_LINES)
GL.glVertex3f(self.p1.x, self.p1.y, self.p1.z)
GL.glVertex3f(self.p2.x, self.p2.y, self.p2.z)
# (optional) draw arrows for visualizing the direction of each line
if show_directions and (self.p1 != self.p2):
line = (self.p2.x - self.p1.x, self.p2.y - self.p1.y)
if line[0] == 0:
ortho = (1.0, 0.0)
elif line[1] == 0:
ortho = (0.0, 1.0)
else:
ortho = (1.0 / line[0], -1.0 / line[1])
line_size = sqrt((line[0] ** 2) + (line[1] ** 2))
ortho_size = sqrt((ortho[0] ** 2) + (ortho[1] ** 2))
ortho_dest_size = line_size / 10.0
ortho = (ortho[0] * ortho_dest_size / ortho_size,
ortho[1] * ortho_dest_size / ortho_size)
line_back = (-line[0] * ortho_dest_size / line_size,
-line[1] * ortho_dest_size / line_size)
p3 = (self.p2.x + ortho[0] + line_back[0],
self.p2.y + ortho[1] + line_back[1], self.p2.z)
p4 = (self.p2.x - ortho[0] + line_back[0],
self.p2.y - ortho[1] + line_back[1], self.p2.z)
GL.glVertex3f(p3[0], p3[1], p3[2])
GL.glVertex3f(self.p2.x, self.p2.y, self.p2.z)
GL.glVertex3f(p4[0], p4[1], p4[2])
GL.glVertex3f(self.p2.x, self.p2.y, self.p2.z)
# (optional) draw arrows for visualizing the direction of each line
if False:
line = (self.p2.x - self.p1.x, self.p2.y - self.p1.y)
if line[0] == 0:
ortho = (1.0, 0.0)
elif line[1] == 0:
ortho = (0.0, 1.0)
else:
ortho = (1.0 / line[0], -1.0 / line[1])
line_size = sqrt((line[0] ** 2) + (line[1] ** 2))
ortho_size = sqrt((ortho[0] ** 2) + (ortho[1] ** 2))
ortho_dest_size = line_size / 10.0
ortho = (ortho[0] * ortho_dest_size / ortho_size,
ortho[1] * ortho_dest_size / ortho_size)
line_back = (-line[0] * ortho_dest_size / line_size,
-line[1] * ortho_dest_size / line_size)
p3 = (self.p2.x + ortho[0] + line_back[0],
self.p2.y + ortho[1] + line_back[1], self.p2.z)
p4 = (self.p2.x - ortho[0] + line_back[0],
self.p2.y - ortho[1] + line_back[1], self.p2.z)
GL.glVertex3f(p3[0], p3[1], p3[2])
GL.glVertex3f(self.p2.x, self.p2.y, self.p2.z)
GL.glVertex3f(p4[0], p4[1], p4[2])
GL.glVertex3f(self.p2.x, self.p2.y, self.p2.z)
GL.glEnd()
GL.glEnd()
def get_intersection(self, line, infinite_lines=False):
""" Get the point of intersection between two lines. Intersections
......
......@@ -83,13 +83,14 @@ class BaseModel(TransformableContainer):
result += item.get_children_count()
return result
def to_OpenGL(self, visible_filter=None):
def to_OpenGL(self, visible_filter=None, show_directions=False):
def paint_item_filtered(item):
do_paint, color = visible_filter(item)
if do_paint:
item.to_OpenGL(color)
item.to_OpenGL(color, show_directions=show_directions)
if visible_filter is None:
paint_item = lambda item: item.to_OpenGL()
paint_item = lambda item: item.to_OpenGL(
show_directions=show_directions)
else:
paint_item = paint_item_filtered
for item in self.next():
......
......@@ -101,7 +101,7 @@ class Triangle(TransformableContainer):
# tree points per triangle
return 7
def to_OpenGL(self, color=None):
def to_OpenGL(self, color=None, show_directions=False):
if not GL_enabled:
return
if not color is None:
......@@ -116,7 +116,7 @@ class Triangle(TransformableContainer):
GL.glVertex3f(self.p3.x, self.p3.y, self.p3.z)
GL.glVertex3f(self.p2.x, self.p2.y, self.p2.z)
GL.glEnd()
if False: # display surface normals
if show_directions: # display surface normals
n = self.normal
c = self.center
d = 0.5
......
......@@ -31,6 +31,7 @@ except (ImportError, RuntimeError):
GL_ENABLED = False
from pycam.Geometry.Point import Point
from pycam.Geometry.Line import Line
import pycam.Geometry.Matrix as Matrix
from pycam.Geometry.utils import sqrt, number
import pycam.Utils.log
......@@ -758,7 +759,7 @@ def draw_complete_model_view(settings):
return True, normal_color
model.to_OpenGL(visible_filter=check_triangle_draw)
"""
model.to_OpenGL()
model.to_OpenGL(show_directions=settings.get("show_directions"))
# draw the support grid
if settings.get("show_support_grid") and settings.get("support_grid"):
GL.glColor4f(*settings.get("color_support_grid"))
......@@ -772,7 +773,8 @@ def draw_complete_model_view(settings):
if toolpath_obj.visible:
draw_toolpath(toolpath_obj.get_path(),
settings.get("color_toolpath_cut"),
settings.get("color_toolpath_return"))
settings.get("color_toolpath_return"),
settings.get("show_directions"))
# draw the drill
if settings.get("show_drill_progress"):
cutter = settings.get("cutter")
......@@ -784,11 +786,13 @@ def draw_complete_model_view(settings):
if not toolpath_in_progress is None:
draw_toolpath(toolpath_in_progress,
settings.get("color_toolpath_cut"),
settings.get("color_toolpath_return"))
settings.get("color_toolpath_return"),
settings.get("show_directions"))
@keep_gl_mode
@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.glLoadIdentity()
if toolpath:
......@@ -796,15 +800,11 @@ def draw_toolpath(toolpath, color_forward, color_backward):
for path in toolpath:
if last:
GL.glColor4f(*color_backward)
GL.glBegin(GL.GL_LINES)
GL.glVertex3f(last.x, last.y, last.z)
last = path.points[0]
GL.glVertex3f(last.x, last.y, last.z)
GL.glEnd()
Line(last, path.points[0]).to_OpenGL(
show_directions=show_directions)
GL.glColor4f(*color_forward)
GL.glBegin(GL.GL_LINE_STRIP)
for point in path.points:
GL.glVertex3f(point.x, point.y, point.z)
GL.glEnd()
for index in range(len(path.points) - 1):
Line(path.points[index], path.points[index + 1]).to_OpenGL(
show_directions=show_directions)
last = path.points[-1]
......@@ -87,6 +87,7 @@ PREFERENCES_DEFAULTS = {
"show_bounding_box": True,
"show_toolpath": True,
"show_drill_progress": False,
"show_directions": False,
"color_background": (0.0, 0.0, 0.0, 1.0),
"color_model": (0.5, 0.5, 1.0, 1.0),
"color_support_grid": (0.8, 0.8, 0.3, 1.0),
......@@ -495,7 +496,8 @@ class ProjectGui:
("show_dimensions", "ShowDimensionsCheckBox"),
("show_bounding_box", "ShowBoundingCheckBox"),
("show_toolpath", "ShowToolPathCheckBox"),
("show_drill_progress", "ShowDrillProgressCheckBox")):
("show_drill_progress", "ShowDrillProgressCheckBox"),
("show_directions", "ShowDirectionsCheckBox")):
obj = self.gui.get_object(objname)
self.settings.add_item(name, obj.get_active, obj.set_active)
# all of the objects above should trigger redraw
......@@ -1349,13 +1351,13 @@ class ProjectGui:
"MillingStyleIgnore", "MaxStepDownControl",
"MaterialAllowanceControl", "OverlapPercentControl"),
"ContourFollowStrategy": ("MillingStyleConventional",
"MillingStyleClimb", "MillingStyleIgnore",
"MaxStepDownControl"),
"MillingStyleClimb", "MaxStepDownControl"),
"SurfaceStrategy": ("GridDirectionX", "GridDirectionY",
"MillingStyleConventional", "MillingStyleClimb",
"MillingStyleIgnore", "MaterialAllowanceControl",
"OverlapPercentControl"),
"EngraveStrategy": ("MaxStepDownControl", "EngraveOffsetControl"),
"EngraveStrategy": ("MaxStepDownControl", "EngraveOffsetControl",
"MillingStyleConventional", "MillingStyleClimb"),
}
for one_control in all_controls:
get_obj(one_control).set_sensitive(one_control in active_controls[cutter_name])
......
......@@ -199,6 +199,7 @@ path_strategy: ContourFollowStrategy
material_allowance: 0.2
step_down: 1.5
overlap_percent: 40
milling_style: conventional
[Process2]
name: Cleanup
......@@ -211,6 +212,7 @@ name: Gravure
path_strategy: EngraveStrategy
step_down: 1.0
overlap_percent: 50
milling_style: conventional
[BoundsDefault]
type: relative_margin
......@@ -703,7 +705,6 @@ class ToolpathSettings:
# TODO: this hack should be somewhere else, I guess
if generator in ("ContourFollow", "EngraveCutter"):
material_allowance = 0.0
milling_style = "ignore"
self.process_settings = {
"generator": generator,
"postprocessor": postprocessor,
......
......@@ -41,6 +41,7 @@ class SimpleCutter:
if self.curr_path == None:
simplify_toolpath(curr_path)
if self.reverse:
curr_path.reverse()
self.paths.insert(0, curr_path)
else:
self.paths.append(curr_path)
......
......@@ -254,7 +254,8 @@ def generate_toolpath(model, tool_settings=None,
if isinstance(physics, basestring):
return physics
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):
return generator
if (overlap < 0) or (overlap >= 1):
......@@ -278,14 +279,16 @@ def generate_toolpath(model, tool_settings=None,
"ignore": pycam.Toolpath.MotionGrid.MILLING_STYLE_IGNORE,
"conventional": pycam.Toolpath.MotionGrid.MILLING_STYLE_CONVENTIONAL,
"climb": pycam.Toolpath.MotionGrid.MILLING_STYLE_CLIMB}
motion_grid = pycam.Toolpath.MotionGrid.get_fixed_grid(bounds,
layer_distance, line_stepping, step_width=step_width,
grid_direction=direction_dict[direction],
milling_style=milling_style_grid[milling_style])
if path_generator == "DropCutter":
toolpath = generator.GenerateToolPath(motion_grid, minz, maxz, callback)
elif path_generator == "PushCutter":
toolpath = generator.GenerateToolPath(motion_grid, callback)
if path_generator in ("DropCutter", "PushCutter"):
motion_grid = pycam.Toolpath.MotionGrid.get_fixed_grid(bounds,
layer_distance, line_stepping, step_width=step_width,
grid_direction=direction_dict[direction],
milling_style=milling_style_grid[milling_style])
if path_generator == "DropCutter":
toolpath = generator.GenerateToolPath(motion_grid, minz, maxz,
callback)
else:
toolpath = generator.GenerateToolPath(motion_grid, callback)
elif path_generator == "EngraveCutter":
if step_down > 0:
dz = step_down
......@@ -308,7 +311,7 @@ def generate_toolpath(model, tool_settings=None,
return toolpath
def _get_pathgenerator_instance(trimesh_models, contour_model, cutter,
pathgenerator, pathprocessor, physics):
pathgenerator, pathprocessor, physics, milling_style):
if pathgenerator != "EngraveCutter" and contour_model:
return ("The only available toolpath strategy for 2D contour models " \
+ "is 'Engraving'.")
......@@ -340,8 +343,9 @@ def _get_pathgenerator_instance(trimesh_models, contour_model, cutter,
return PushCutter.PushCutter(cutter, trimesh_models, processor,
physics=physics)
elif pathgenerator == "EngraveCutter":
reverse = (milling_style == "conventional")
if pathprocessor == "SimpleCutter":
processor = pycam.PathProcessors.SimpleCutter()
processor = pycam.PathProcessors.SimpleCutter(reverse=reverse)
else:
return ("Invalid postprocessor (%s) for 'EngraveCutter' - it " \
+ "should be: SimpleCutter") % str(pathprocessor)
......@@ -351,8 +355,9 @@ def _get_pathgenerator_instance(trimesh_models, contour_model, cutter,
return EngraveCutter.EngraveCutter(cutter, trimesh_models,
contour_model, processor, physics=physics)
elif pathgenerator == "ContourFollow":
reverse = (milling_style == "conventional")
if pathprocessor == "SimpleCutter":
processor = pycam.PathProcessors.SimpleCutter()
processor = pycam.PathProcessors.SimpleCutter(reverse=reverse)
else:
return ("Invalid postprocessor (%s) for 'ContourFollow' - it " \
+ "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