Commit 0385eb03 authored by sumpfralle's avatar sumpfralle

added proof-of-concept for automatic support grid positioning


git-svn-id: https://pycam.svn.sourceforge.net/svnroot/pycam/trunk@622 bbaffbd6-741e-11dd-a85d-61de82d9cad9
parent 2a4bdb52
Version 0.3.1 - UNRELEASED
* added automatic support grid positioning for contour models
Version 0.3.0 - 2010-08-16
* added support for importing contour paths from SVG files (requires Inkscape and pstoedit)
* added basic support for importing simple DXF contour files
......
......@@ -203,6 +203,23 @@
</row>
</data>
</object>
<object class="GtkListStore" id="SupportGridTypesList">
<columns>
<!-- column-name name -->
<column type="gchararray"/>
</columns>
<data>
<row>
<col id="0" translatable="yes">none</col>
</row>
<row>
<col id="0" translatable="yes">grid pattern</col>
</row>
<row>
<col id="0" translatable="yes">automatic distribution</col>
</row>
</data>
</object>
<object class="GtkWindow" id="ProjectWindow">
<property name="title" translatable="yes">PyCAM</property>
<property name="destroy_with_parent">True</property>
......@@ -889,16 +906,31 @@
<property name="visible">True</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkCheckButton" id="SupportGridEnable">
<property name="label" translatable="yes">enable support grid</property>
<object class="GtkHBox" id="hbox26">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">A support grid (also called "live bridges") is additional material that is left behind around the model. This material is supposed to keep the object at its current position during the machining process. This is especially useful for very small objects or if you don't use a vacuum table.</property>
<property name="draw_indicator">True</property>
<child>
<object class="GtkComboBox" id="SupportGridTypesControl">
<property name="visible">True</property>
<property name="model">SupportGridTypesList</property>
<property name="active">0</property>
<child>
<object class="GtkCellRendererText" id="SupportGridTypesCell"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
......@@ -906,6 +938,100 @@
<object class="GtkVBox" id="SupportGridDetailsBox">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkExpander" id="GridProfileExpander">
<property name="visible">True</property>
<property name="can_focus">True</property>
<child>
<object class="GtkHBox" id="hbox1">
<property name="visible">True</property>
<property name="spacing">3</property>
<child>
<object class="GtkAlignment" id="alignment20">
<property name="width_request">40</property>
<property name="visible">True</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="SupportGridThicknessLabel">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">thickness:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="SupportGridThicknessControl">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
<property name="adjustment">SupportGridThickness</property>
<property name="digits">2</property>
<property name="numeric">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkVSeparator" id="vseparator10">
<property name="visible">True</property>
<property name="orientation">vertical</property>
</object>
<packing>
<property name="expand">False</property>
<property name="padding">3</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="SupportGridHeightLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">height:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="SupportGridHeightControl">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
<property name="adjustment">SupportGridHeight</property>
<property name="digits">2</property>
<property name="numeric">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">5</property>
</packing>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="GridProfileExpanderLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">Profile</property>
</object>
</child>
</object>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkExpander" id="GridPatternExpander">
<property name="visible">True</property>
......@@ -1035,100 +1161,6 @@
</object>
</child>
</object>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkExpander" id="GridProfileExpander">
<property name="visible">True</property>
<property name="can_focus">True</property>
<child>
<object class="GtkHBox" id="hbox1">
<property name="visible">True</property>
<property name="spacing">3</property>
<child>
<object class="GtkAlignment" id="alignment20">
<property name="width_request">40</property>
<property name="visible">True</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="SupportGridThicknessLabel">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">thickness:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="SupportGridThicknessControl">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
<property name="adjustment">SupportGridThickness</property>
<property name="digits">2</property>
<property name="numeric">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkVSeparator" id="vseparator10">
<property name="visible">True</property>
<property name="orientation">vertical</property>
</object>
<packing>
<property name="expand">False</property>
<property name="padding">3</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="SupportGridHeightLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">height:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="SupportGridHeightControl">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
<property name="adjustment">SupportGridHeight</property>
<property name="digits">2</property>
<property name="numeric">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">5</property>
</packing>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="GridProfileExpanderLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">Profile</property>
</object>
</child>
</object>
<packing>
<property name="position">1</property>
</packing>
......@@ -1410,6 +1442,117 @@
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkExpander" id="GridAverageDistanceExpander">
<property name="visible">True</property>
<property name="can_focus">True</property>
<child>
<object class="GtkTable" id="table12">
<property name="visible">True</property>
<property name="n_rows">2</property>
<property name="n_columns">3</property>
<property name="column_spacing">3</property>
<property name="row_spacing">2</property>
<child>
<object class="GtkSpinButton" id="GridMinBridgesPerPolygon">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
<property name="adjustment">SupportGridMinBridgesPerPolygon</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="GridMinBridgesPerPolygonLabel">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Minimum bridges per polygon:</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="GridAverageDistance">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
<property name="adjustment">SupportGridAverageDistance</property>
<property name="digits">2</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="GridAverageDistanceLabel">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Average distance between bridges:</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<object class="GtkAlignment" id="alignment39">
<property name="width_request">40</property>
<property name="visible">True</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<object class="GtkAlignment" id="alignment40">
<property name="width_request">40</property>
<property name="visible">True</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="GridAverageDistanceExpanderLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">Distribution</property>
</object>
</child>
</object>
<packing>
<property name="position">4</property>
</packing>
</child>
</object>
<packing>
<property name="position">1</property>
......@@ -6067,4 +6210,16 @@ Any selected group of dimensions will be scaled accordingly.</property>
<object class="GtkAction" id="HelpHotkeys">
<property name="label">_Keyboard Shortcuts</property>
</object>
<object class="GtkAdjustment" id="SupportGridAverageDistance">
<property name="value">30</property>
<property name="lower">0.01</property>
<property name="upper">500</property>
<property name="step_increment">1</property>
</object>
<object class="GtkAdjustment" id="SupportGridMinBridgesPerPolygon">
<property name="value">2</property>
<property name="lower">1</property>
<property name="upper">20</property>
<property name="step_increment">1</property>
</object>
</interface>
......@@ -94,6 +94,9 @@ class Point:
def dot(self, p):
return self.x * p.x + self.y * p.y + self.z * p.z
def size(self):
return sqrt(self.dot(self))
def cross(self, p):
return Point(self.y * p.z - p.y * self.z, p.x * self.z - self.x * p.z,
self.x * p.y - p.x * self.y)
......
......@@ -36,7 +36,7 @@ class Polygon(TransformableContainer):
# TODO: derive the plane from the appended points
if plane is None:
plane = Plane(Point(0, 0, 0), Point(0, 0, 1))
self._plane = plane
self.plane = plane
self._points = []
self._is_closed = False
self.maxx = None
......@@ -102,10 +102,10 @@ class Polygon(TransformableContainer):
def next(self):
for point in self._points:
yield point
yield self._plane
yield self.plane
def get_children_count(self):
return len(self._points) + self._plane.get_children_count()
return len(self._points) + self.plane.get_children_count()
def get_area(self):
""" calculate the area covered by a line group
......@@ -126,6 +126,27 @@ class Polygon(TransformableContainer):
value += p1.x * p2.y - p2.x * p1.y
return value / 2
def get_length(self):
""" add the length of all lines within the polygon
"""
return sum(self.get_lengths())
def get_middle_of_line(self, index):
if (index >= len(self._points)) \
or (not self._is_closed and index == len(self._points) - 1):
return None
else:
return self._points[index].add(self._points[(index + 1) % len(self._points)]).div(2)
def get_lengths(self):
result = []
for index in range(len(self._points) - 1):
result.append(self._points[index + 1].sub(
self._points[index]).size())
if self._is_closed:
result.append(self._points[0].sub(self._points[-1]).size())
return result
def get_max_inside_distance(self):
""" calculate the maximum distance between two points of the polygon
"""
......@@ -243,10 +264,10 @@ class Polygon(TransformableContainer):
skel_dir = d1.add(d2).normalized()
if skel_dir is None:
# the two vectors pointed to opposite directions
skel_dir = d1.cross(self._plane.n).normalized()
skel_dir = d1.cross(self.plane.n).normalized()
else:
skel_up_vector = skel_dir.cross(p2.sub(p1))
offset_up_vector = self._plane.n
offset_up_vector = self.plane.n
# TODO: check for other axis as well
if offset_up_vector.z * skel_up_vector.z < 0:
# reverse the skeleton vector to point outwards
......@@ -257,7 +278,7 @@ class Polygon(TransformableContainer):
def get_shifted_vertex(index, offset):
p1 = self._points[index]
p2 = self._points[(index + 1) % len(self._points)]
cross_offset = p2.sub(p1).cross(self._plane.n).normalized()
cross_offset = p2.sub(p1).cross(self.plane.n).normalized()
bisector_normalized = self.get_bisector(index)
factor = cross_offset.dot(bisector_normalized)
if factor != 0:
......@@ -375,7 +396,7 @@ class Polygon(TransformableContainer):
self_is_outer = self.is_outer()
groups = []
for lines in cleaned_line_groups:
group = Polygon(self._plane)
group = Polygon(self.plane)
for line in lines:
group.append(line)
if group.is_outer() != self_is_outer:
......@@ -408,7 +429,7 @@ class Polygon(TransformableContainer):
if offset == 0:
return Line(line.p1, line.p2)
else:
cross_offset = line.dir.cross(self._plane.n).normalized().mul(offset)
cross_offset = line.dir.cross(self.plane.n).normalized().mul(offset)
# Prolong the line at the beginning and at the end - to allow
# overlaps. Use factor "2" to take care for star-like structure
# where a complete convex triangle would get cropped (two lines
......@@ -581,7 +602,7 @@ class Polygon(TransformableContainer):
self_is_outer = self.is_outer()
groups = []
for lines in cleaned_line_groups:
group = Polygon(self._plane)
group = Polygon(self.plane)
for line in lines:
group.append(line)
if group.is_outer() == self_is_outer:
......@@ -619,7 +640,7 @@ class Polygon(TransformableContainer):
pass
else:
# no suitable group was found - we create a new one
new_group = Polygon(self._plane)
new_group = Polygon(self.plane)
new_group.append(new_line)
new_groups.append(new_group)
if len(new_groups) > 0:
......
......@@ -97,6 +97,8 @@ 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}
# floating point color values are only available since gtk 2.16
GTK_COLOR_MAX = 65535.0
......@@ -324,7 +326,7 @@ class ProjectGui:
scale_dimension_control.connect("focus-out-event",
lambda widget, data: self.window.set_default(None))
# support grid
self.gui.get_object("SupportGridEnable").connect("clicked",
self.gui.get_object("SupportGridTypesControl").connect("changed",
self.update_support_grid_controls)
grid_distance_x = self.gui.get_object("SupportGridDistanceX")
grid_distance_x.connect("value-changed",
......@@ -354,14 +356,25 @@ class ProjectGui:
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.update_support_grid_model)
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.update_support_grid_model)
self.settings.add_item("support_grid_offset_y",
grid_offset_y.get_value, grid_offset_y.set_value)
grid_average_distance = self.gui.get_object("GridAverageDistance")
grid_average_distance.connect("value-changed",
self.update_support_grid_model)
self.settings.add_item("support_grid_average_distance",
grid_average_distance.get_value,
grid_average_distance.set_value)
grid_minimum_bridges = self.gui.get_object("GridMinBridgesPerPolygon")
grid_minimum_bridges.connect("value-changed",
self.update_support_grid_model)
self.settings.add_item("support_grid_minimum_bridges",
grid_minimum_bridges.get_value, grid_minimum_bridges.set_value)
# manual grid adjustments
self.grid_adjustment_axis_x = self.gui.get_object("SupportGridPositionManualAxisX")
self.grid_adjustment_axis_x.connect("toggled",
......@@ -405,9 +418,11 @@ class ProjectGui:
get_set_grid_adjustment_value, get_set_grid_adjustment_value)
# support grid defaults
grid_distance_square.set_active(True)
self.settings.set("support_grid_distance_x", 5.0)
self.settings.set("support_grid_distance_x", 10.0)
self.settings.set("support_grid_thickness", 0.5)
self.settings.set("support_grid_height", 0.5)
self.settings.set("support_grid_average_distance", 30)
self.settings.set("support_grid_minimum_bridges", 2)
self.grid_adjustment_axis_x_last = True
# visual and general settings
for name, objname in (("show_model", "ShowModelCheckBox"),
......@@ -720,49 +735,77 @@ class ProjectGui:
@gui_activity_guard
def update_support_grid_controls(self, widget=None):
details_box = self.gui.get_object("SupportGridDetailsBox")
grid_square = self.gui.get_object("SupportGridDistanceSquare")
distance_y = self.gui.get_object("SupportGridDistanceYControl")
if self.gui.get_object("SupportGridEnable").get_active():
controls = {"GridProfileExpander": ("grid", "automatic"),
"GridPatternExpander": ("grid", ),
"GridPositionExpander": ("grid", ),
"GridManualShiftExpander": ("grid", ),
"GridAverageDistanceExpander": ("automatic", ),
}
grid_type = self.gui.get_object("SupportGridTypesControl").get_active()
if grid_type == GRID_TYPES["grid"]:
grid_square = self.gui.get_object("SupportGridDistanceSquare")
distance_y = self.gui.get_object("SupportGridDistanceYControl")
distance_y.set_sensitive(not grid_square.get_active())
details_box.show()
if grid_square.get_active():
# We let "distance_y" track the value of "distance_x".
self.settings.set("support_grid_distance_y",
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"]:
pass
else:
details_box.hide()
raise ValueError("Invalid grid type: %d" % grid_type)
# show and hide all controls according to the current type
for key, grid_types in controls.iteritems():
obj = self.gui.get_object(key)
if grid_type in [GRID_TYPES[allowed] for allowed in grid_types]:
obj.show()
else:
obj.hide()
self.update_support_grid_model()
self.update_view()
def update_support_grid_model(self):
is_enabled = self.gui.get_object("SupportGridEnable").get_active()
def update_support_grid_model(self, widget=None):
grid_type = self.gui.get_object("SupportGridTypesControl").get_active()
s = self.settings
if is_enabled \
and (s.get("support_grid_thickness") > 0) \
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):
support_grid = pycam.Toolpath.SupportGrid.get_support_grid(
s.get("minx"), s.get("maxx"), s.get("miny"), s.get("maxy"),
s.get("minz"), s.get("support_grid_distance_x"),
s.get("support_grid_distance_y"),
s.get("support_grid_thickness"),
s.get("support_grid_height"),
offset_x=s.get("support_grid_offset_x"),
offset_y=s.get("support_grid_offset_y"),
adjustments_x=self.grid_adjustments_x,
adjustments_y=self.grid_adjustments_y)
else:
support_grid = None
support_grid = None
if grid_type == GRID_TYPES["grid"]:
if (s.get("support_grid_thickness") > 0) \
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):
support_grid = pycam.Toolpath.SupportGrid.get_support_grid(
s.get("minx"), s.get("maxx"), s.get("miny"), s.get("maxy"),
s.get("minz"), s.get("support_grid_distance_x"),
s.get("support_grid_distance_y"),
s.get("support_grid_thickness"),
s.get("support_grid_height"),
offset_x=s.get("support_grid_offset_x"),
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"]:
if (s.get("support_grid_thickness") > 0) \
and (s.get("support_grid_height") > 0) \
and (s.get("support_grid_average_distance") > 0) \
and (s.get("support_grid_minimum_bridges") > 0):
support_grid = pycam.Toolpath.SupportGrid.get_distributed_support_bridges(
s.get("model"), s.get("minz"),
s.get("support_grid_average_distance"),
s.get("support_grid_minimum_bridges"),
s.get("support_grid_thickness"),
s.get("support_grid_height"))
elif grid_type == GRID_TYPES["none"]:
pass
s.set("support_grid", support_grid)
def switch_support_grid_manual_selector(self, widget=None):
......@@ -2528,7 +2571,8 @@ class ProjectGui:
tool_settings["speed"], tool_settings["feedrate"])
# get the support grid options
if self.gui.get_object("SupportGridEnable").get_active():
grid_type = self.gui.get_object("SupportGridTypesControl").get_active()
if grid_type == GRID_TYPES["grid"]:
toolpath_settings.set_support_grid(
self.settings.get("support_grid_distance_x"),
self.settings.get("support_grid_distance_y"),
......@@ -2538,6 +2582,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"]:
toolpath_settings.set_support_automatic(
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"))
elif grid_type == GRID_TYPES["none"]:
pass
else:
raise ValueError("Invalid support grid type: %d" % grid_type)
# calculation backend: ODE / None
if self.settings.get("enable_ode"):
......
......@@ -20,13 +20,23 @@ You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
from pycam.Geometry.Point import Point
from pycam.Geometry.Point import Point, Vector
from pycam.Geometry.Line import Line
from pycam.Geometry.Triangle import Triangle
from pycam.Geometry.Model import Model
from pycam.Geometry.utils import number
def _add_pyramid_to_model(model, start, direction, height, width):
up = Vector(0, 0, 1)
top = start.add(direction).add(up.mul(height))
middle_end = start.add(direction)
end_right = middle_end.add(direction.cross(up).normalized().mul(width / 2))
end_left = middle_end.add(direction.cross(up).normalized().mul(-width / 2))
for points in ((start, top, end_right), (start, end_right, top),
(start, end_right, end_left), (top, end_left, end_right)):
model.append(Triangle(points[0], points[1], points[2]))
def _add_cuboid_to_model(minx, maxx, miny, maxy, minz, maxz):
def get_triangles_for_face(pts):
t1 = Triangle(pts[0], pts[1], pts[2], Line(pts[0], pts[1]),
......@@ -131,3 +141,38 @@ def get_support_grid(minx, maxx, miny, maxy, z_plane, dist_x, dist_y, thickness,
line_y + thick_half, z_plane, z_plane + height)
return grid_model
def get_distributed_support_bridges(model, z_plane, average_distance,
min_bridges_per_polygon, thickness, height):
result = Model()
for polygon in model.get_polygons():
if not polygon.is_outer():
continue
lines = polygon.get_lines()
poly_lengths = polygon.get_lengths()
num_of_bridges = max(min_bridges_per_polygon,
int(round(sum(poly_lengths) / average_distance)))
real_average_distance = sum(poly_lengths) / num_of_bridges
max_line_index = poly_lengths.index(max(poly_lengths))
positions = []
current_line_index = max_line_index
distance_processed = poly_lengths[current_line_index] / 2
positions.append(current_line_index)
while len(positions) < num_of_bridges:
current_line_index += 1
current_line_index %= len(poly_lengths)
while distance_processed + poly_lengths[current_line_index] < real_average_distance:
distance_processed += poly_lengths[current_line_index]
current_line_index += 1
current_line_index %= len(poly_lengths)
positions.append(current_line_index)
distance_processed += poly_lengths[current_line_index]
distance_processed %= real_average_distance
for line_index in positions:
bridge_dir = lines[line_index].dir.cross(polygon.plane.n)
# TODO: should we ask for a length?
length = average_distance / 4
_add_pyramid_to_model(result,
polygon.get_middle_of_line(line_index), bridge_dir,
height, thickness)
return result
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