Commit 84ab9bff authored by sumpfralle's avatar sumpfralle

added support for automatically distributed support bridges at corners or at edges


git-svn-id: https://pycam.svn.sourceforge.net/svnroot/pycam/trunk@959 bbaffbd6-741e-11dd-a85d-61de82d9cad9
parent f7b6f7ee
...@@ -21,6 +21,7 @@ Version 0.4.1 - UNRELEASED ...@@ -21,6 +21,7 @@ Version 0.4.1 - UNRELEASED
* visibility of 3D view items is now configurable in the 3D window * visibility of 3D view items is now configurable in the 3D window
* via a button and via the context menu * via a button and via the context menu
* improved stability of remote processing: disconnected nodes should not cause problems anymore * improved stability of remote processing: disconnected nodes should not cause problems anymore
* automatically distributed support bridges can now be placed at corners or edges
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
......
...@@ -216,7 +216,10 @@ ...@@ -216,7 +216,10 @@
<col id="0" translatable="yes">grid pattern</col> <col id="0" translatable="yes">grid pattern</col>
</row> </row>
<row> <row>
<col id="0" translatable="yes">automatic distribution</col> <col id="0" translatable="yes">automatic distribution (edges)</col>
</row>
<row>
<col id="0" translatable="yes">automatic distribution (corners)</col>
</row> </row>
</data> </data>
</object> </object>
......
...@@ -142,6 +142,7 @@ class Polygon(TransformableContainer): ...@@ -142,6 +142,7 @@ class Polygon(TransformableContainer):
Currently this works only for line groups in an xy-plane. Currently this works only for line groups in an xy-plane.
Returns zero for empty line groups or for open line groups. Returns zero for empty line groups or for open line groups.
Returns negative values for inner hole. Returns negative values for inner hole.
TODO: "get_area" is wrong by some factor - check the result!
""" """
if not self._points: if not self._points:
return 0 return 0
...@@ -163,6 +164,55 @@ class Polygon(TransformableContainer): ...@@ -163,6 +164,55 @@ class Polygon(TransformableContainer):
self._area_cache = result / 2 self._area_cache = result / 2
return self._area_cache return self._area_cache
def get_barycenter(self):
area = self.get_area()
if not area:
return None
# TODO: for now we just calculate the "middle of the outline" - the "barycenter" code below needs to be fixed
return Point((self.maxx + self.minx) / 2, (self.maxy + self.miny) / 2,
(self.maxz + self.minz) / 2)
# see: http://stackoverflow.com/questions/2355931/compute-the-centroid-of-a-3d-planar-polygon/2360507
# first: calculate cx and y
cxy, cxz, cyx, cyz, czx, czy = (0, 0, 0, 0, 0, 0)
for index in range(len(self._points)):
p1 = self._points[index]
p2 = self._points[(index + 1) % len(self._points)]
cxy += (p1.x + p2.x) * (p1.x * p2.y - p1.y * p2.x)
cxz += (p1.x + p2.x) * (p1.x * p2.z - p1.z * p2.x)
cyx += (p1.y + p2.y) * (p1.y * p2.x - p1.x * p2.y)
cyz += (p1.y + p2.y) * (p1.y * p2.z - p1.z * p2.y)
czx += (p1.z + p2.z) * (p1.z * p2.x - p1.x * p2.z)
czy += (p1.z + p2.z) * (p1.z * p2.y - p1.y * p2.z)
if self.minz == self.maxz:
return Point(cxy / (6 * area), cyx / (6 * area), self.minz)
elif self.miny == self.maxy:
return Point(cxz / (6 * area), self.miny, czx / (6 * area))
elif self.minz == self.maxz:
return Point(self.minx, cyz / (6 * area), czy / (6 * area))
else:
# calculate area of xy projection
area_xy = self.get_plane_projection(Plane(Point(0, 0, 0),
Point(0, 0, 1))).get_area()
area_xz = self.get_plane_projection(Plane(Point(0, 0, 0),
Point(0, 1, 0))).get_area()
area_yz = self.get_plane_projection(Plane(Point(0, 0, 0),
Point(1, 0, 0))).get_area()
if 0 in (area_xy, area_xz, area_yz):
log.info("Failed assumtion: zero-sized projected area - " + \
"%s / %s / %s" % (area_xy, area_xz, area_yz))
return Point(0, 0, 0)
if abs(cxy / area_xy - cxz / area_xz) > epsilon:
log.info("Failed assumption: barycenter xy/xz - %s / %s" % \
(cxy / area_xy, cxz / area_xz))
if abs(cyx / area_xy - cyz / area_yz) > epsilon:
log.info("Failed assumption: barycenter yx/yz - %s / %s" % \
(cyx / area_xy, cyz / area_yz))
if abs(czx / area_xz - czy / area_yz) > epsilon:
log.info("Failed assumption: barycenter zx/zy - %s / %s" % \
(czx / area_xz, cyz / area_yz))
return Point(cxy / (6 * area_xy), cyx / (6 * area_xy),
czx / (6 * area_xz))
def get_length(self): def get_length(self):
""" add the length of all lines within the polygon """ add the length of all lines within the polygon
""" """
...@@ -306,6 +356,7 @@ class Polygon(TransformableContainer): ...@@ -306,6 +356,7 @@ class Polygon(TransformableContainer):
self.minz = min(self.minz, point.z) self.minz = min(self.minz, point.z)
self.maxz = max(self.maxz, point.z) self.maxz = max(self.maxz, point.z)
self._lines_cache = None self._lines_cache = None
self._area_cache = None
def reset_cache(self): def reset_cache(self):
self._cached_offset_polygons = {} self._cached_offset_polygons = {}
......
...@@ -145,7 +145,7 @@ PREFERENCES_DEFAULTS = { ...@@ -145,7 +145,7 @@ PREFERENCES_DEFAULTS = {
""" the listed items will be loaded/saved via the preferences file in the """ the listed items will be loaded/saved via the preferences file in the
user's home directory on startup/shutdown""" user's home directory on startup/shutdown"""
GRID_TYPES = {"none": 0, "grid": 1, "automatic": 2} GRID_TYPES = {"none": 0, "grid": 1, "automatic_edge": 2, "automatic_corner": 3}
POCKETING_TYPES = ["none", "holes", "enclosed"] POCKETING_TYPES = ["none", "holes", "enclosed"]
MAX_UNDO_STATES = 10 MAX_UNDO_STATES = 10
...@@ -1185,11 +1185,13 @@ class ProjectGui: ...@@ -1185,11 +1185,13 @@ class ProjectGui:
@gui_activity_guard @gui_activity_guard
def update_support_grid_controls(self, widget=None): def update_support_grid_controls(self, widget=None):
controls = {"GridProfileExpander": ("grid", "automatic"), controls = {"GridProfileExpander": ("grid", "automatic_edge",
"automatic_corner"),
"GridPatternExpander": ("grid", ), "GridPatternExpander": ("grid", ),
"GridPositionExpander": ("grid", ), "GridPositionExpander": ("grid", ),
"GridManualShiftExpander": ("grid", ), "GridManualShiftExpander": ("grid", ),
"GridAverageDistanceExpander": ("automatic", ), "GridAverageDistanceExpander": ("automatic_edge",
"automatic_corner"),
} }
grid_type = self.settings.get("support_grid_type") grid_type = self.settings.get("support_grid_type")
if grid_type == GRID_TYPES["grid"]: if grid_type == GRID_TYPES["grid"]:
...@@ -1202,9 +1204,8 @@ class ProjectGui: ...@@ -1202,9 +1204,8 @@ class ProjectGui:
self.settings.get("support_grid_distance_x")) self.settings.get("support_grid_distance_x"))
self.update_support_grid_manual_model() self.update_support_grid_manual_model()
self.switch_support_grid_manual_selector() self.switch_support_grid_manual_selector()
elif grid_type == GRID_TYPES["automatic"]: elif grid_type in (GRID_TYPES["automatic_edge"],
pass GRID_TYPES["automatic_corner"], GRID_TYPES["none"]):
elif grid_type == GRID_TYPES["none"]:
pass pass
elif grid_type < 0: elif grid_type < 0:
# not initialized # not initialized
...@@ -1246,7 +1247,8 @@ class ProjectGui: ...@@ -1246,7 +1247,8 @@ class ProjectGui:
offset_y=s.get("support_grid_offset_y"), offset_y=s.get("support_grid_offset_y"),
adjustments_x=self.grid_adjustments_x, adjustments_x=self.grid_adjustments_x,
adjustments_y=self.grid_adjustments_y) adjustments_y=self.grid_adjustments_y)
elif grid_type == GRID_TYPES["automatic"]: elif grid_type in (GRID_TYPES["automatic_edge"],
GRID_TYPES["automatic_corner"]):
if (s.get("support_grid_thickness") > 0) \ if (s.get("support_grid_thickness") > 0) \
and (s.get("support_grid_height") > 0) \ and (s.get("support_grid_height") > 0) \
and (s.get("support_grid_average_distance") > 0) \ and (s.get("support_grid_average_distance") > 0) \
...@@ -1258,13 +1260,15 @@ class ProjectGui: ...@@ -1258,13 +1260,15 @@ class ProjectGui:
if not bounds is None: if not bounds is None:
minz = bounds.get_absolute_limits( minz = bounds.get_absolute_limits(
reference=self.model.get_bounds())[0][2] reference=self.model.get_bounds())[0][2]
corner_start = (grid_type == GRID_TYPES["automatic_corner"])
support_grid = pycam.Toolpath.SupportGrid.get_support_distributed( support_grid = pycam.Toolpath.SupportGrid.get_support_distributed(
s.get("model"), minz, s.get("model"), minz,
s.get("support_grid_average_distance"), s.get("support_grid_average_distance"),
s.get("support_grid_minimum_bridges"), s.get("support_grid_minimum_bridges"),
s.get("support_grid_thickness"), s.get("support_grid_thickness"),
s.get("support_grid_height"), s.get("support_grid_height"),
s.get("support_grid_length")) s.get("support_grid_length"),
start_at_corners=corner_start)
elif grid_type == GRID_TYPES["none"]: elif grid_type == GRID_TYPES["none"]:
pass pass
s.set("support_grid", support_grid) s.set("support_grid", support_grid)
...@@ -3605,13 +3609,16 @@ class ProjectGui: ...@@ -3605,13 +3609,16 @@ class ProjectGui:
offset_y=self.settings.get("support_grid_offset_y"), offset_y=self.settings.get("support_grid_offset_y"),
adjustments_x=self.grid_adjustments_x, adjustments_x=self.grid_adjustments_x,
adjustments_y=self.grid_adjustments_y) adjustments_y=self.grid_adjustments_y)
elif grid_type == GRID_TYPES["automatic"]: elif grid_type in (GRID_TYPES["automatic_edge"],
GRID_TYPES["automatic_corner"]):
corner_start = (grid_type == GRID_TYPES["automatic_corner"])
toolpath_settings.set_support_distributed( toolpath_settings.set_support_distributed(
self.settings.get("support_grid_average_distance"), self.settings.get("support_grid_average_distance"),
self.settings.get("support_grid_minimum_bridges"), self.settings.get("support_grid_minimum_bridges"),
self.settings.get("support_grid_thickness"), self.settings.get("support_grid_thickness"),
self.settings.get("support_grid_height"), self.settings.get("support_grid_height"),
self.settings.get("support_grid_length")) self.settings.get("support_grid_length"),
start_at_corner=corner_start)
elif grid_type == GRID_TYPES["none"]: elif grid_type == GRID_TYPES["none"]:
pass pass
else: else:
......
...@@ -582,6 +582,7 @@ class ToolpathSettings: ...@@ -582,6 +582,7 @@ class ToolpathSettings:
"average_distance": float, "average_distance": float,
"minimum_bridges": int, "minimum_bridges": int,
"length": float, "length": float,
"start_at_corner": bool,
}, },
"Program": { "Program": {
"unit": str, "unit": str,
...@@ -660,13 +661,14 @@ class ToolpathSettings: ...@@ -660,13 +661,14 @@ class ToolpathSettings:
self.support_grid["adjustments_y"] = adjustments_y self.support_grid["adjustments_y"] = adjustments_y
def set_support_distributed(self, average_distance, minimum_bridges, def set_support_distributed(self, average_distance, minimum_bridges,
thickness, height, length): thickness, height, length, start_at_corner=False):
self.support_grid["type"] = "distributed" self.support_grid["type"] = "distributed"
self.support_grid["average_distance"] = average_distance self.support_grid["average_distance"] = average_distance
self.support_grid["minimum_bridges"] = minimum_bridges self.support_grid["minimum_bridges"] = minimum_bridges
self.support_grid["thickness"] = thickness self.support_grid["thickness"] = thickness
self.support_grid["height"] = height self.support_grid["height"] = height
self.support_grid["length"] = length self.support_grid["length"] = length
self.support_grid["start_at_corner"] = start_at_corner
def get_support_grid(self): def get_support_grid(self):
result = {} result = {}
......
This diff is collapsed.
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