Commit 5c4bd378 authored by sumpfralle's avatar sumpfralle

added support for non-square support grids

added x/y offsets to support grid options


git-svn-id: https://pycam.svn.sourceforge.net/svnroot/pycam/trunk@487 bbaffbd6-741e-11dd-a85d-61de82d9cad9
parent 40a89f9e
...@@ -3,8 +3,10 @@ Version 0.3.0 - UNRELEASED ...@@ -3,8 +3,10 @@ Version 0.3.0 - UNRELEASED
* added basic support for importing simple DXF contour files * added basic support for importing simple DXF contour files
* added support for engravings * added support for engravings
* integrated "help" links pointing to the wiki * integrated "help" links pointing to the wiki
* allow non-square profiles for the support grid
* improved OpenGL lightning (contributed by imyrek) * improved OpenGL lightning (contributed by imyrek)
* allow non-square profiles for the support grid
* added ability to create support grids with different x/y grid distance
* added x/y offsets to support grid options
* switched default tool size from radius to diameter * switched default tool size from radius to diameter
* fixed performance issue when using a support grid * fixed performance issue when using a support grid
* fixed empty toolpath after transforming the model * fixed empty toolpath after transforming the model
......
...@@ -281,25 +281,44 @@ class ProjectGui: ...@@ -281,25 +281,44 @@ class ProjectGui:
self.gui.get_object("ScaleDimensionButton").connect("clicked", self.scale_model_axis_fit) self.gui.get_object("ScaleDimensionButton").connect("clicked", self.scale_model_axis_fit)
# support grid # support grid
self.gui.get_object("SupportGridEnable").connect("clicked", self.update_support_grid_controls) self.gui.get_object("SupportGridEnable").connect("clicked", self.update_support_grid_controls)
grid_distance = self.gui.get_object("SupportGridDistance") grid_distance_x = self.gui.get_object("SupportGridDistanceX")
grid_distance.connect("value-changed", self.update_support_grid_controls) grid_distance_x.connect("value-changed",
self.settings.add_item("support_grid_distance", self.update_support_grid_controls)
grid_distance.get_value, grid_distance.set_value) self.settings.add_item("support_grid_distance_x",
grid_square_profile = self.gui.get_object("SupportGridSquare") grid_distance_x.get_value, grid_distance_x.set_value)
grid_square_profile.connect("toggled", self.update_support_grid_controls) grid_distance_square = self.gui.get_object("SupportGridDistanceSquare")
grid_distance_square.connect("clicked",
self.update_support_grid_controls)
grid_distance_y = self.gui.get_object("SupportGridDistanceY")
grid_distance_y.connect("value-changed",
self.update_support_grid_controls)
def get_support_grid_distance_y():
if grid_distance_square.get_active():
return self.settings.get("support_grid_distance_x")
else:
return grid_distance_y.get_value()
self.settings.add_item("support_grid_distance_y",
get_support_grid_distance_y, grid_distance_y.set_value)
grid_thickness = self.gui.get_object("SupportGridThickness") grid_thickness = self.gui.get_object("SupportGridThickness")
grid_thickness.connect("value-changed", self.update_support_grid_controls) grid_thickness.connect("value-changed", self.update_support_grid_controls)
self.settings.add_item("support_grid_thickness", self.settings.add_item("support_grid_thickness",
grid_thickness.get_value, grid_thickness.set_value) grid_thickness.get_value, grid_thickness.set_value)
grid_height = self.gui.get_object("SupportGridHeight") grid_height = self.gui.get_object("SupportGridHeight")
def get_support_grid_height():
if grid_square_profile.get_active():
return self.settings.get("support_grid_thickness")
else:
return grid_height.get_value()
self.settings.add_item("support_grid_height", get_support_grid_height, grid_height.set_value)
grid_height.connect("value-changed", self.update_support_grid_controls) grid_height.connect("value-changed", self.update_support_grid_controls)
self.settings.set("support_grid_distance", 5.0) self.settings.add_item("support_grid_height",
grid_height.get_value, grid_height.set_value)
grid_offset_x = self.gui.get_object("SupportGridOffsetX")
grid_offset_x.connect("value-changed",
self.update_support_grid_controls)
self.settings.add_item("support_grid_offset_x",
grid_offset_x.get_value, grid_offset_x.set_value)
grid_offset_y = self.gui.get_object("SupportGridOffsetY")
grid_offset_y.connect("value-changed",
self.update_support_grid_controls)
self.settings.add_item("support_grid_offset_y",
grid_offset_y.get_value, grid_offset_y.set_value)
grid_distance_square.set_active(True)
self.settings.set("support_grid_distance_x", 5.0)
self.settings.set("support_grid_thickness", 0.5) self.settings.set("support_grid_thickness", 0.5)
self.settings.set("support_grid_height", 0.5) self.settings.set("support_grid_height", 0.5)
# visual and general settings # visual and general settings
...@@ -579,20 +598,16 @@ class ProjectGui: ...@@ -579,20 +598,16 @@ class ProjectGui:
@gui_activity_guard @gui_activity_guard
def update_support_grid_controls(self, widget=None): def update_support_grid_controls(self, widget=None):
is_enabled = self.gui.get_object("SupportGridEnable").get_active()
grid_square = self.gui.get_object("SupportGridSquare")
details_box = self.gui.get_object("SupportGridDetailsBox") details_box = self.gui.get_object("SupportGridDetailsBox")
grid_height_box = self.gui.get_object("SupportGridHeightBox") grid_square = self.gui.get_object("SupportGridDistanceSquare")
if is_enabled: distance_y = self.gui.get_object("SupportGridDistanceYControl")
if self.gui.get_object("SupportGridEnable").get_active():
distance_y.set_sensitive(not grid_square.get_active())
details_box.show() details_box.show()
if grid_square.get_active(): if grid_square.get_active():
grid_height_box.hide() # We let "distance_y" track the value of "distance_x".
else: self.settings.set("support_grid_distance_y",
if widget == grid_square: self.settings.get("support_grid_distance_x"))
# reset the current height to the thickness, if the
# "square" checkbox was just de-activated
self.settings.set("support_grid_height", self.settings.get("support_grid_thickness"))
grid_height_box.show()
else: else:
details_box.hide() details_box.hide()
self.update_support_grid_model() self.update_support_grid_model()
...@@ -603,17 +618,26 @@ class ProjectGui: ...@@ -603,17 +618,26 @@ class ProjectGui:
s = self.settings s = self.settings
if is_enabled \ if is_enabled \
and (s.get("support_grid_thickness") > 0) \ and (s.get("support_grid_thickness") > 0) \
and (s.get("support_grid_distance") > s.get("support_grid_thickness")) \ and ((s.get("support_grid_distance_x") > 0) \
or (s.get("support_grid_distance_y") > 0)) \
and ((s.get("support_grid_distance_x") == 0) \
or (s.get("support_grid_distance_x") \
> s.get("support_grid_thickness"))) \
and ((s.get("support_grid_distance_y") == 0) \
or (s.get("support_grid_distance_y") \
> s.get("support_grid_thickness"))) \
and (s.get("support_grid_height") > 0): and (s.get("support_grid_height") > 0):
s.set("support_grid", support_grid = pycam.Toolpath.SupportGrid.get_support_grid(
pycam.Toolpath.SupportGrid.get_support_grid(s.get("minx"), s.get("minx"), s.get("maxx"), s.get("miny"), s.get("maxy"),
s.get("maxx"), s.get("miny"), s.get("maxy"), s.get("minz"), s.get("support_grid_distance_x"),
s.get("minz"), s.get("support_grid_distance"), s.get("support_grid_distance_y"),
s.get("support_grid_distance"), s.get("support_grid_thickness"),
s.get("support_grid_thickness"), s.get("support_grid_height"),
s.get("support_grid_height"))) offset_x=s.get("support_grid_offset_x"),
offset_y=s.get("support_grid_offset_y"))
else: else:
self.settings.set("support_grid", None) support_grid = None
s.set("support_grid", support_grid)
@gui_activity_guard @gui_activity_guard
def adjust_bounds(self, widget, axis, change): def adjust_bounds(self, widget, axis, change):
......
...@@ -499,9 +499,12 @@ class ToolpathSettings: ...@@ -499,9 +499,12 @@ class ToolpathSettings:
"feedrate": float, "feedrate": float,
}, },
"SupportGrid": { "SupportGrid": {
"distance": float, "distance_x": float,
"distance_y": float,
"thickness": float, "thickness": float,
"height": float, "height": float,
"offset_x": float,
"offset_y": float,
}, },
"Program": { "Program": {
"unit": str, "unit": str,
...@@ -560,8 +563,12 @@ class ToolpathSettings: ...@@ -560,8 +563,12 @@ class ToolpathSettings:
def get_tool_settings(self): def get_tool_settings(self):
return self.tool_settings return self.tool_settings
def set_support_grid(self, distance, thickness, height): def set_support_grid(self, distance_x, distance_y, thickness, height,
self.support_grid["distance"] = distance offset_x=0.0, offset_y=0.0):
self.support_grid["distance_x"] = distance_x
self.support_grid["distance_y"] = distance_y
self.support_grid["offset_x"] = offset_x
self.support_grid["offset_y"] = offset_y
self.support_grid["thickness"] = thickness self.support_grid["thickness"] = thickness
self.support_grid["height"] = height self.support_grid["height"] = height
...@@ -569,7 +576,8 @@ class ToolpathSettings: ...@@ -569,7 +576,8 @@ class ToolpathSettings:
if self.support_grid: if self.support_grid:
return self.support_grid return self.support_grid
else: else:
return {"distance": None, "thickness": None, "height": None} return {"distance_x": None, "distance_y": None, "thickness": None,
"height": None, "offset_x": None, "offset_y": None}
def set_calculation_backend(self, backend=None): def set_calculation_backend(self, backend=None):
self.program["enable_ode"] = (backend.upper() == "ODE") self.program["enable_ode"] = (backend.upper() == "ODE")
......
...@@ -51,9 +51,10 @@ def generate_toolpath(model, tool_settings=None, ...@@ -51,9 +51,10 @@ def generate_toolpath(model, tool_settings=None,
bounds_low=None, bounds_high=None, direction="x", bounds_low=None, bounds_high=None, direction="x",
path_generator="DropCutter", path_postprocessor="ZigZagCutter", path_generator="DropCutter", path_postprocessor="ZigZagCutter",
material_allowance=0.0, safety_height=None, overlap=0.0, step_down=0.0, material_allowance=0.0, safety_height=None, overlap=0.0, step_down=0.0,
engrave_offset=0.0, support_grid_distance=None, engrave_offset=0.0, support_grid_distance_x=None,
support_grid_thickness=None, support_grid_height=None, support_grid_distance_y=None, support_grid_thickness=None,
calculation_backend=None, callback=None): support_grid_height=None, support_grid_offset_x=None,
support_grid_offset_y=None, calculation_backend=None, callback=None):
""" abstract interface for generating a toolpath """ abstract interface for generating a toolpath
@type model: pycam.Geometry.Model.Model @type model: pycam.Geometry.Model.Model
...@@ -84,12 +85,18 @@ def generate_toolpath(model, tool_settings=None, ...@@ -84,12 +85,18 @@ def generate_toolpath(model, tool_settings=None,
@value step_down: maximum height of each layer (for PushCutter) @value step_down: maximum height of each layer (for PushCutter)
@type engrave_offset: float @type engrave_offset: float
@value engrave_offset: toolpath distance to the contour model @value engrave_offset: toolpath distance to the contour model
@type support_grid_distance: float @type support_grid_distance_x: float
@value support_grid_distance: grid size of remaining support material @value support_grid_distance_x: distance between support grid lines along x
@type support_grid_distance_y: float
@value support_grid_distance_y: distance between support grid lines along y
@type support_grid_thickness: float @type support_grid_thickness: float
@value support_grid_thickness: thickness of the support grid @value support_grid_thickness: thickness of the support grid
@type support_grid_height: float @type support_grid_height: float
@value support_grid_height: height of the support grid @value support_grid_height: height of the support grid
@type support_grid_offset_x: float
@value support_grid_offset_x: shift the support grid by this value along x
@type support_grid_offset_y: float
@value support_grid_offset_y: shift the support grid by this value along y
@type calculation_backend: str | None @type calculation_backend: str | None
@value calculation_backend: any member of the CALCULATION_BACKENDS set @value calculation_backend: any member of the CALCULATION_BACKENDS set
The default is the triangular collision detection. The default is the triangular collision detection.
...@@ -119,13 +126,17 @@ def generate_toolpath(model, tool_settings=None, ...@@ -119,13 +126,17 @@ def generate_toolpath(model, tool_settings=None,
# material allowance is ignored for engraving # material allowance is ignored for engraving
material_allowance = 0.0 material_allowance = 0.0
# create the grid model if requested # create the grid model if requested
if (not support_grid_distance is None) \ if (((not support_grid_distance_x is None) \
and (not support_grid_thickness is None): or (not support_grid_distance_y is None)) \
and (support_grid_thickness is None)):
# grid height defaults to the thickness # grid height defaults to the thickness
if support_grid_height is None: if support_grid_height is None:
support_grid_height = support_grid_thickness support_grid_height = support_grid_thickness
if support_grid_distance <= 0: if (support_grid_distance_x < 0) or (support_grid_distance_y < 0):
return "The distance of the support grid must be a positive value" return "The distance of the support grid must be a positive value"
if not ((support_grid_distance_x > 0) or (support_grid_distance_y > 0)):
return "Both distance values for the support grid may not be " \
+ "zero at the same time"
if support_grid_thickness <= 0: if support_grid_thickness <= 0:
return "The thickness of the support grid must be a positive value" return "The thickness of the support grid must be a positive value"
if support_grid_height <= 0: if support_grid_height <= 0:
...@@ -133,9 +144,10 @@ def generate_toolpath(model, tool_settings=None, ...@@ -133,9 +144,10 @@ def generate_toolpath(model, tool_settings=None,
if not callback is None: if not callback is None:
callback(text="Preparing support grid model ...") callback(text="Preparing support grid model ...")
support_grid_model = pycam.Toolpath.SupportGrid.get_support_grid( support_grid_model = pycam.Toolpath.SupportGrid.get_support_grid(
minx, maxx, miny, maxy, minz, support_grid_distance, minx, maxx, miny, maxy, minz, support_grid_distance_x,
support_grid_distance, support_grid_thickness, support_grid_distance_y, support_grid_thickness,
support_grid_height) support_grid_height, offset_x=support_grid_offset_x,
offset_y=support_grid_offset_y)
trimesh_model += support_grid_model trimesh_model += support_grid_model
# Adapt the contour_model to the engraving offset. This offset is # Adapt the contour_model to the engraving offset. This offset is
# considered to be part of the material_allowance. # considered to be part of the material_allowance.
......
...@@ -59,28 +59,45 @@ def _add_cuboid_to_model(minx, maxx, miny, maxy, minz, maxz): ...@@ -59,28 +59,45 @@ def _add_cuboid_to_model(minx, maxx, miny, maxy, minz, maxz):
model.append(t) model.append(t)
return model return model
def get_support_grid(minx, maxx, miny, maxy, z_plane, dist_x, dist_y, thickness, height): def get_support_grid(minx, maxx, miny, maxy, z_plane, dist_x, dist_y, thickness,
lines_x = int(math.ceil((maxx - minx) / dist_x)) height, offset_x=0.0, offset_y=0.0):
lines_y = int(math.ceil((maxy - miny) / dist_y)) def get_lines(center, dist, min_value, max_value):
# we center the grid """ generate a list of positions starting from the middle going up and
start_x = ((maxx - minx) - (lines_x - 1) * dist_x) / 2.0 + minx and down
start_y = ((maxy - miny) - (lines_y - 1) * dist_y) / 2.0 + miny """
if dist > 0:
lines = [center]
current = center
while current - dist > min_value:
current -= dist
lines.insert(0, current)
current = center
while current + dist < max_value:
current += dist
lines.append(current)
else:
lines = []
# remove lines that are out of range (e.g. due to a huge offset)
lines = [line for line in lines if min_value < line < max_value]
return lines
center_x = (maxx + minx) / 2.0 + offset_x
center_y = (maxy + miny) / 2.0 + offset_y
lines_x = get_lines(center_x, dist_x, minx, maxx)
lines_y = get_lines(center_y, dist_y, miny, maxy)
# create all x grid lines # create all x grid lines
grid_model = Model.Model() grid_model = Model.Model()
# helper variables # helper variables
thick_half = thickness / 2.0 thick_half = thickness / 2.0
length_extension = max(thickness, height) length_extension = max(thickness, height)
for i in range(lines_x): for line_x in lines_x:
x = start_x + i * dist_x
# we make the grid slightly longer (by thickness) than necessary # we make the grid slightly longer (by thickness) than necessary
grid_model += _add_cuboid_to_model(x - thick_half, x + thick_half, grid_model += _add_cuboid_to_model(line_x - thick_half,
miny - length_extension, maxy + length_extension, z_plane, line_x + thick_half, miny - length_extension,
z_plane + height) maxy + length_extension, z_plane, z_plane + height)
for i in range(lines_y): for line_y in lines_y:
y = start_y + i * dist_y
# we make the grid slightly longer (by thickness) than necessary # we make the grid slightly longer (by thickness) than necessary
grid_model += _add_cuboid_to_model(minx - length_extension, grid_model += _add_cuboid_to_model(minx - length_extension,
maxx + length_extension, y - thick_half, y + thick_half, maxx + length_extension, line_y - thick_half,
z_plane, z_plane + height) line_y + thick_half, z_plane, z_plane + height)
return grid_model return grid_model
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