Commit 0cc5946a authored by sumpfralle's avatar sumpfralle

added toolpath grid pattern operation: clone a single toolpath into rows and columns


git-svn-id: https://pycam.svn.sourceforge.net/svnroot/pycam/trunk@993 bbaffbd6-741e-11dd-a85d-61de82d9cad9
parent b8aab86d
...@@ -9,6 +9,7 @@ Version 0.4.1 - UNRELEASED ...@@ -9,6 +9,7 @@ Version 0.4.1 - UNRELEASED
* added a very simple "pocketing" mode for 2D models * added a very simple "pocketing" mode for 2D models
* added 2D projection of 3D models * added 2D projection of 3D models
* added toolpath cropping * added toolpath cropping
* added toolpath grid pattern: clone a single toolpath in rows and columns
* added support for DXF features "LWPOLYLINE" and "ARC" * added support for DXF features "LWPOLYLINE" and "ARC"
* added a configuration setting for automatically loading a custom task settings file on startup * added a configuration setting for automatically loading a custom task settings file on startup
* added a simple "undo" feature for reversing model manipulations * added a simple "undo" feature for reversing model manipulations
......
...@@ -4247,6 +4247,19 @@ Usually you will want to use the cutter radius here to cut around the outline.</ ...@@ -4247,6 +4247,19 @@ Usually you will want to use the cutter radius here to cut around the outline.</
<property name="position">0</property> <property name="position">0</property>
</packing> </packing>
</child> </child>
<child>
<object class="GtkButton" id="ToolpathGrid">
<property name="label">gtk-page-setup</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
<child> <child>
<object class="GtkButton" id="toolpath_crop"> <object class="GtkButton" id="toolpath_crop">
<property name="label" translatable="yes">Crop</property> <property name="label" translatable="yes">Crop</property>
...@@ -4259,7 +4272,7 @@ Usually you will want to use the cutter radius here to cut around the outline.</ ...@@ -4259,7 +4272,7 @@ Usually you will want to use the cutter radius here to cut around the outline.</
</object> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="position">1</property> <property name="position">2</property>
</packing> </packing>
</child> </child>
<child> <child>
...@@ -4273,7 +4286,7 @@ Usually you will want to use the cutter radius here to cut around the outline.</ ...@@ -4273,7 +4286,7 @@ Usually you will want to use the cutter radius here to cut around the outline.</
</object> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="position">2</property> <property name="position">3</property>
</packing> </packing>
</child> </child>
<child> <child>
...@@ -4287,7 +4300,7 @@ Usually you will want to use the cutter radius here to cut around the outline.</ ...@@ -4287,7 +4300,7 @@ Usually you will want to use the cutter radius here to cut around the outline.</
</object> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="position">3</property> <property name="position">4</property>
</packing> </packing>
</child> </child>
<child> <child>
...@@ -4301,7 +4314,7 @@ Usually you will want to use the cutter radius here to cut around the outline.</ ...@@ -4301,7 +4314,7 @@ Usually you will want to use the cutter radius here to cut around the outline.</
</object> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="position">4</property> <property name="position">5</property>
</packing> </packing>
</child> </child>
</object> </object>
...@@ -4851,6 +4864,7 @@ Usually you will want to use the cutter radius here to cut around the outline.</ ...@@ -4851,6 +4864,7 @@ Usually you will want to use the cutter radius here to cut around the outline.</
<property name="border_width">5</property> <property name="border_width">5</property>
<property name="title" translatable="yes">PyCAM Preferences</property> <property name="title" translatable="yes">PyCAM Preferences</property>
<property name="destroy_with_parent">True</property> <property name="destroy_with_parent">True</property>
<property name="icon_name">preferences-desktop</property>
<property name="type_hint">normal</property> <property name="type_hint">normal</property>
<child internal-child="vbox"> <child internal-child="vbox">
<object class="GtkVBox" id="dialog-vbox1"> <object class="GtkVBox" id="dialog-vbox1">
...@@ -6753,6 +6767,7 @@ You should have received a copy of the GNU General Public License along with thi ...@@ -6753,6 +6767,7 @@ You should have received a copy of the GNU General Public License along with thi
<property name="border_width">5</property> <property name="border_width">5</property>
<property name="title" translatable="yes">Unit change compensation</property> <property name="title" translatable="yes">Unit change compensation</property>
<property name="modal">True</property> <property name="modal">True</property>
<property name="icon_name">accessories-calculator</property>
<property name="type_hint">normal</property> <property name="type_hint">normal</property>
<child internal-child="vbox"> <child internal-child="vbox">
<object class="GtkVBox" id="dialog-vbox7"> <object class="GtkVBox" id="dialog-vbox7">
...@@ -7516,6 +7531,7 @@ Please read the description of the Server Mode (linked below) to understand the ...@@ -7516,6 +7531,7 @@ Please read the description of the Server Mode (linked below) to understand the
<property name="title" translatable="yes">Engrave text</property> <property name="title" translatable="yes">Engrave text</property>
<property name="window_position">center</property> <property name="window_position">center</property>
<property name="destroy_with_parent">True</property> <property name="destroy_with_parent">True</property>
<property name="icon_name">accessories-character-map</property>
<property name="type_hint">dialog</property> <property name="type_hint">dialog</property>
<property name="transient_for">ProjectWindow</property> <property name="transient_for">ProjectWindow</property>
<child internal-child="vbox"> <child internal-child="vbox">
...@@ -8174,4 +8190,260 @@ upon interesting bugs and weird results.</property> ...@@ -8174,4 +8190,260 @@ upon interesting bugs and weird results.</property>
<property name="upper">100</property> <property name="upper">100</property>
<property name="step_increment">5.0000000000000002e-05</property> <property name="step_increment">5.0000000000000002e-05</property>
</object> </object>
<object class="GtkDialog" id="ToolpathGridDialog">
<property name="border_width">5</property>
<property name="title" translatable="yes">Toolpath Grid</property>
<property name="destroy_with_parent">True</property>
<property name="icon_name">document-page-setup</property>
<property name="type_hint">normal</property>
<property name="has_separator">False</property>
<child internal-child="vbox">
<object class="GtkVBox" id="dialog-vbox10">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child>
<object class="GtkTable" id="table16">
<property name="visible">True</property>
<property name="n_rows">4</property>
<property name="n_columns">3</property>
<property name="column_spacing">3</property>
<property name="row_spacing">3</property>
<property name="homogeneous">True</property>
<child>
<object class="GtkLabel" id="LabelGridRows">
<property name="visible">True</property>
<property name="label" translatable="yes">Rows</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="GtkLabel" id="LabelGridColumns">
<property name="visible">True</property>
<property name="label" translatable="yes">Columns</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="LabelGridCount">
<property name="visible">True</property>
<property name="label" translatable="yes">Count:</property>
</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="GtkLabel" id="LabelGridDistance">
<property name="visible">True</property>
<property name="label" translatable="yes">Distance:</property>
</object>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="GridYCount">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
<property name="adjustment">GridYCountValue</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="GridXCount">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
<property name="adjustment">GridXCountValue</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="GtkSpinButton" id="GridYDistance">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
<property name="adjustment">GridYDistanceValue</property>
<property name="digits">3</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="GridXDistance">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
<property name="adjustment">GridXDistanceValue</property>
<property name="digits">3</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<object class="GtkAlignment" id="alignment47">
<property name="visible">True</property>
<child>
<placeholder/>
</child>
</object>
</child>
<child>
<object class="GtkLabel" id="LabelWidth">
<property name="visible">True</property>
<property name="label" translatable="yes">Width:</property>
</object>
<packing>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="LabelGridYWidth">
<property name="visible">True</property>
<property name="label" translatable="yes">?</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="LabelGridXWidth">
<property name="visible">True</property>
<property name="label" translatable="yes">?</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
<child internal-child="action_area">
<object class="GtkHButtonBox" id="dialog-action_area9">
<property name="visible">True</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="ToolpathGridClose">
<property name="label">gtk-cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="ToolpathGridOK">
<property name="label">gtk-ok</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="0">ToolpathGridClose</action-widget>
<action-widget response="1">ToolpathGridOK</action-widget>
</action-widgets>
</object>
<object class="GtkAdjustment" id="GridYCountValue">
<property name="value">1</property>
<property name="lower">1</property>
<property name="upper">1000</property>
<property name="step_increment">1</property>
</object>
<object class="GtkAdjustment" id="GridXCountValue">
<property name="value">1</property>
<property name="lower">1</property>
<property name="upper">1000</property>
<property name="step_increment">1</property>
</object>
<object class="GtkAdjustment" id="GridYDistanceValue">
<property name="lower">-1000</property>
<property name="upper">1000</property>
<property name="step_increment">1</property>
</object>
<object class="GtkAdjustment" id="GridXDistanceValue">
<property name="lower">-1000</property>
<property name="upper">1000</property>
<property name="step_increment">1</property>
</object>
</interface> </interface>
...@@ -32,6 +32,7 @@ import pycam.Importers.CXFImporter ...@@ -32,6 +32,7 @@ import pycam.Importers.CXFImporter
import pycam.Importers import pycam.Importers
from pycam.Geometry.Point import Point, Vector from pycam.Geometry.Point import Point, Vector
from pycam.Geometry.Plane import Plane from pycam.Geometry.Plane import Plane
import pycam.Geometry.Path
import pycam.Utils.log import pycam.Utils.log
import pycam.Utils import pycam.Utils
from pycam.Geometry.utils import sqrt from pycam.Geometry.utils import sqrt
...@@ -43,7 +44,6 @@ from pycam.Utils import ProgressCounter, check_uri_exists ...@@ -43,7 +44,6 @@ from pycam.Utils import ProgressCounter, check_uri_exists
from pycam.Toolpath import Bounds from pycam.Toolpath import Bounds
from pycam import VERSION from pycam import VERSION
import pycam.Physics.ode_physics import pycam.Physics.ode_physics
import pycam.Toolpath.MotionGrid
# this requires ODE - we import it later, if necessary # this requires ODE - we import it later, if necessary
#import pycam.Simulation.ODEBlocks #import pycam.Simulation.ODEBlocks
import gtk import gtk
...@@ -448,6 +448,7 @@ class ProjectGui: ...@@ -448,6 +448,7 @@ class ProjectGui:
self.grid_adjustments_x = [] self.grid_adjustments_x = []
self.grid_adjustments_y = [] self.grid_adjustments_y = []
self._last_unit = None self._last_unit = None
self._toolpath_for_grid_data = {}
# add some dummies - to be implemented later ... # add some dummies - to be implemented later ...
self.settings.add_item("model", lambda: self.model) self.settings.add_item("model", lambda: self.model)
self.settings.add_item("toolpath", lambda: self.toolpath) self.settings.add_item("toolpath", lambda: self.toolpath)
...@@ -672,6 +673,11 @@ class ProjectGui: ...@@ -672,6 +673,11 @@ class ProjectGui:
self.settings.set("support_grid_minimum_bridges", 2) self.settings.set("support_grid_minimum_bridges", 2)
self.settings.set("support_grid_length", 5) self.settings.set("support_grid_length", 5)
self.grid_adjustment_axis_x_last = True self.grid_adjustment_axis_x_last = True
# toolpath grid pattern
for objname in ("GridYCount", "GridXCount", "GridYDistance",
"GridXDistance"):
self.gui.get_object(objname).connect("value-changed",
self.update_toolpath_grid_window)
# visual and general settings # visual and general settings
for name, objname in (("show_model", "ShowModelCheckBox"), for name, objname in (("show_model", "ShowModelCheckBox"),
("show_support_grid", "ShowSupportGridCheckBox"), ("show_support_grid", "ShowSupportGridCheckBox"),
...@@ -843,6 +849,7 @@ class ProjectGui: ...@@ -843,6 +849,7 @@ class ProjectGui:
self.gui.get_object("toolpath_delete").connect("clicked", self.toolpath_table_event, "delete") self.gui.get_object("toolpath_delete").connect("clicked", self.toolpath_table_event, "delete")
self.gui.get_object("toolpath_simulate").connect("clicked", self.toolpath_table_event, "simulate") self.gui.get_object("toolpath_simulate").connect("clicked", self.toolpath_table_event, "simulate")
self.gui.get_object("toolpath_crop").connect("clicked", self.toolpath_table_event, "crop") self.gui.get_object("toolpath_crop").connect("clicked", self.toolpath_table_event, "crop")
self.gui.get_object("ToolpathGrid").connect("clicked", self.toolpath_table_event, "grid")
self.gui.get_object("ExitSimulationButton").connect("clicked", self.finish_toolpath_simulation) self.gui.get_object("ExitSimulationButton").connect("clicked", self.finish_toolpath_simulation)
speed_factor_widget = self.gui.get_object("SimulationSpeedFactor") speed_factor_widget = self.gui.get_object("SimulationSpeedFactor")
self.settings.add_item("simulation_speed_factor", self.settings.add_item("simulation_speed_factor",
...@@ -3223,14 +3230,67 @@ class ProjectGui: ...@@ -3223,14 +3230,67 @@ class ProjectGui:
index = self._treeview_get_active_index(self.toolpath_table, self.toolpath) index = self._treeview_get_active_index(self.toolpath_table, self.toolpath)
if not index is None: if not index is None:
self.crop_toolpath(self.toolpath[index]) self.crop_toolpath(self.toolpath[index])
elif action == "grid":
index = self._treeview_get_active_index(self.toolpath_table, self.toolpath)
if not index is None:
self.create_toolpath_grid(self.toolpath[index])
# process the default operations (move, delete) # process the default operations (move, delete)
self._treeview_button_event(self.toolpath_table, self.toolpath, action, self._treeview_button_event(self.toolpath_table, self.toolpath, action,
self.update_toolpath_table) self.update_toolpath_table)
# do some post-processing ... # do some post-processing ...
if action in ("delete", "crop"): if action in ("delete", "crop", "grid"):
# hide the deleted toolpath immediately
self.update_view() self.update_view()
def update_toolpath_grid_window(self, widget=None):
data = self._toolpath_for_grid_data
x_dim = data["maxx"] - data["minx"]
y_dim = data["maxy"] - data["miny"]
x_count = self.gui.get_object("GridXCount").get_value()
x_space = self.gui.get_object("GridXDistance").get_value()
y_count = self.gui.get_object("GridYCount").get_value()
y_space = self.gui.get_object("GridYDistance").get_value()
x_width = x_dim * x_count + x_space * (x_count - 1)
y_width = y_dim * y_count + y_space * (y_count - 1)
self.gui.get_object("LabelGridXWidth").set_label("%g%s" % \
(x_width, self.settings.get("unit")))
self.gui.get_object("LabelGridYWidth").set_label("%g%s" % \
(y_width, self.settings.get("unit")))
def create_toolpath_grid(self, toolpath):
dialog = self.gui.get_object("ToolpathGridDialog")
data = self._toolpath_for_grid_data
data["minx"] = toolpath.minx()
data["maxx"] = toolpath.maxx()
data["miny"] = toolpath.miny()
data["maxy"] = toolpath.maxy()
self.gui.get_object("GridXCount").set_value(1)
self.gui.get_object("GridYCount").set_value(1)
self.update_toolpath_grid_window()
result = dialog.run()
if result == 1:
# "OK" was pressed
new_tp = []
x_count = int(self.gui.get_object("GridXCount").get_value())
y_count = int(self.gui.get_object("GridYCount").get_value())
x_space = self.gui.get_object("GridXDistance").get_value()
y_space = self.gui.get_object("GridYDistance").get_value()
x_dim = data["maxx"] - data["minx"]
y_dim = data["maxy"] - data["miny"]
for x in range(x_count):
for y in range(y_count):
shift = Point(x * (x_space + x_dim),
y * (y_space + y_dim), 0)
for path in toolpath.get_paths():
new_path = pycam.Geometry.Path.Path()
new_path.points = [shift.add(p) for p in path.points]
new_tp.append(new_path)
new_toolpath = pycam.Toolpath.Toolpath(new_tp, toolpath.name,
toolpath.toolpath_settings)
toolpath.visible = False
new_toolpath.visible = True
self.toolpath.append(new_toolpath)
dialog.hide()
@progress_activity_guard @progress_activity_guard
def crop_toolpath(self, toolpath): def crop_toolpath(self, toolpath):
if hasattr(self.model, "get_polygons"): if hasattr(self.model, "get_polygons"):
...@@ -3297,6 +3357,7 @@ class ProjectGui: ...@@ -3297,6 +3357,7 @@ class ProjectGui:
self.gui.get_object("toolpath_down").set_sensitive((not new_index is None) and (new_index + 1 < len(self.toolpath))) self.gui.get_object("toolpath_down").set_sensitive((not new_index is None) and (new_index + 1 < len(self.toolpath)))
self.gui.get_object("toolpath_simulate").set_sensitive(not new_index is None) self.gui.get_object("toolpath_simulate").set_sensitive(not new_index is None)
self.gui.get_object("toolpath_crop").set_sensitive(not new_index is None) self.gui.get_object("toolpath_crop").set_sensitive(not new_index is None)
self.gui.get_object("ToolpathGrid").set_sensitive(not new_index is None)
@gui_activity_guard @gui_activity_guard
def save_task_settings_file(self, widget=None, filename=None): def save_task_settings_file(self, widget=None, filename=None):
......
...@@ -77,6 +77,31 @@ class Toolpath(object): ...@@ -77,6 +77,31 @@ class Toolpath(object):
# generate random color # generate random color
self.set_color() self.set_color()
def _get_limit_generic(self, attr, func):
path_min = []
for path in self.get_paths():
if path.points:
path_min.append(func([getattr(p, attr) for p in path.points]))
return func(path_min)
def minx(self):
return self._get_limit_generic("x", min)
def maxx(self):
return self._get_limit_generic("x", max)
def miny(self):
return self._get_limit_generic("y", min)
def maxy(self):
return self._get_limit_generic("y", max)
def minz(self):
return self._get_limit_generic("z", min)
def maxz(self):
return self._get_limit_generic("z", max)
def get_paths(self): def get_paths(self):
return self.toolpath return self.toolpath
......
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