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
* visibility of 3D view items is now configurable in the 3D window
* via a button and via the context menu
* 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
* disabled parallel processing for Windows standalone executable
......
......@@ -216,7 +216,10 @@
<col id="0" translatable="yes">grid pattern</col>
</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>
</data>
</object>
......
......@@ -142,6 +142,7 @@ class Polygon(TransformableContainer):
Currently this works only for line groups in an xy-plane.
Returns zero for empty line groups or for open line groups.
Returns negative values for inner hole.
TODO: "get_area" is wrong by some factor - check the result!
"""
if not self._points:
return 0
......@@ -163,6 +164,55 @@ class Polygon(TransformableContainer):
self._area_cache = result / 2
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):
""" add the length of all lines within the polygon
"""
......@@ -306,6 +356,7 @@ class Polygon(TransformableContainer):
self.minz = min(self.minz, point.z)
self.maxz = max(self.maxz, point.z)
self._lines_cache = None
self._area_cache = None
def reset_cache(self):
self._cached_offset_polygons = {}
......
......@@ -145,7 +145,7 @@ PREFERENCES_DEFAULTS = {
""" the listed items will be loaded/saved via the preferences file in the
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"]
MAX_UNDO_STATES = 10
......@@ -1185,11 +1185,13 @@ class ProjectGui:
@gui_activity_guard
def update_support_grid_controls(self, widget=None):
controls = {"GridProfileExpander": ("grid", "automatic"),
controls = {"GridProfileExpander": ("grid", "automatic_edge",
"automatic_corner"),
"GridPatternExpander": ("grid", ),
"GridPositionExpander": ("grid", ),
"GridManualShiftExpander": ("grid", ),
"GridAverageDistanceExpander": ("automatic", ),
"GridAverageDistanceExpander": ("automatic_edge",
"automatic_corner"),
}
grid_type = self.settings.get("support_grid_type")
if grid_type == GRID_TYPES["grid"]:
......@@ -1202,9 +1204,8 @@ class ProjectGui:
self.settings.get("support_grid_distance_x"))
self.update_support_grid_manual_model()
self.switch_support_grid_manual_selector()
elif grid_type == GRID_TYPES["automatic"]:
pass
elif grid_type == GRID_TYPES["none"]:
elif grid_type in (GRID_TYPES["automatic_edge"],
GRID_TYPES["automatic_corner"], GRID_TYPES["none"]):
pass
elif grid_type < 0:
# not initialized
......@@ -1246,7 +1247,8 @@ class ProjectGui:
offset_y=s.get("support_grid_offset_y"),
adjustments_x=self.grid_adjustments_x,
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) \
and (s.get("support_grid_height") > 0) \
and (s.get("support_grid_average_distance") > 0) \
......@@ -1258,13 +1260,15 @@ class ProjectGui:
if not bounds is None:
minz = bounds.get_absolute_limits(
reference=self.model.get_bounds())[0][2]
corner_start = (grid_type == GRID_TYPES["automatic_corner"])
support_grid = pycam.Toolpath.SupportGrid.get_support_distributed(
s.get("model"), minz,
s.get("support_grid_average_distance"),
s.get("support_grid_minimum_bridges"),
s.get("support_grid_thickness"),
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"]:
pass
s.set("support_grid", support_grid)
......@@ -3605,13 +3609,16 @@ class ProjectGui:
offset_y=self.settings.get("support_grid_offset_y"),
adjustments_x=self.grid_adjustments_x,
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(
self.settings.get("support_grid_average_distance"),
self.settings.get("support_grid_minimum_bridges"),
self.settings.get("support_grid_thickness"),
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"]:
pass
else:
......
......@@ -582,6 +582,7 @@ class ToolpathSettings:
"average_distance": float,
"minimum_bridges": int,
"length": float,
"start_at_corner": bool,
},
"Program": {
"unit": str,
......@@ -660,13 +661,14 @@ class ToolpathSettings:
self.support_grid["adjustments_y"] = adjustments_y
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["average_distance"] = average_distance
self.support_grid["minimum_bridges"] = minimum_bridges
self.support_grid["thickness"] = thickness
self.support_grid["height"] = height
self.support_grid["length"] = length
self.support_grid["start_at_corner"] = start_at_corner
def get_support_grid(self):
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