Commit f43f2b5f authored by sumpfralle's avatar sumpfralle

splitted all process parameters into seperate plugins

created a framework for processing strategies


git-svn-id: https://pycam.svn.sourceforge.net/svnroot/pycam/trunk@1139 bbaffbd6-741e-11dd-a85d-61de82d9cad9
parent 1c7dbc76
This diff is collapsed.
# -*- coding: utf-8 -*-
"""
$Id$
Copyright 2011 Lars Kruse <devel@sumpfralle.de>
This file is part of PyCAM.
PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
# gtk and gobject are imported later (to avoid plugin load failures)
import pycam.Utils.log
_log = pycam.Utils.log.get_logger()
class InputBaseClass(object):
def get_widget(self):
return self.control
def set_visible(self, state):
if state:
self.control.show()
else:
self.control.hide()
class InputNumber(InputBaseClass):
def __init__(self, digits=0, start=0, lower=0, upper=100,
increment=1, change_handler=None):
import gtk
adjustment = gtk.Adjustment(value=start, lower=lower, upper=upper,
step_incr=increment)
self.control = gtk.SpinButton(adjustment, digits=digits)
self.control.set_value(start)
if change_handler:
self.control.connect("changed", change_handler)
def get_value(self):
return self.control.get_value()
def set_value(self, value):
self.control.set_value(value)
class InputChoice(InputBaseClass):
def __init__(self, choices, force_type=None, change_handler=None):
import gtk
import gobject
type_mapper = {int: gobject.TYPE_INT,
long: gobject.TYPE_LONG,
basestring: gobject.TYPE_STRING,
bool: gobject.TYPE_BOOLEAN
}
if force_type is None:
value_sample = choices[0][1]
for key, g_type in type_mapper.iteritems():
if isinstance(value_sample, key):
break
else:
raise TypeError("Invalid sample type give: %s - %s" % \
(sample_value, type(sample_value)))
elif force_type in type_mapper:
g_type = type_mapper[force_type]
else:
raise TypeError("Invalid type forced: %s" % str(force_type))
self.model = gtk.ListStore(gobject.TYPE_STRING, g_type)
self.control = gtk.ComboBox(self.model)
renderer = gtk.CellRendererText()
self.control.pack_start(renderer)
self.control.set_attributes(renderer, text=0)
for label, value in choices:
self.model.append((label, value))
self.control.set_active(0)
if change_handler:
self.control.connect("changed", change_handler)
def get_value(self):
index = self.control.get_active()
if index < 0:
return None
else:
return self.model[index][1]
def set_value(self, value):
if value is None:
self.control.set_active(-1)
else:
for index, row in enumerate(self.model):
if row[1] == value:
self.control.set_active(index)
break
else:
_log.debug("Tried to set an invalid value: %s" % str(value))
def update_choices(self, choices):
# TODO: selection restore does not work currently; there seems to be a glitch during "delete model"
old_selection_index = self.control.get_active()
if old_selection_index < 0:
old_selection = None
else:
old_selection = self.model[old_selection_index][1]
for choice_index, (label, value) in enumerate(choices):
for index, row in enumerate(self.model):
if row[1] == value:
break
else:
# this choice is new
self.model.insert(choice_index, (label, value))
continue
# the current choice is preceded by some obsolete items
while index > choice_index:
m_iter = self.model.get_iter((index,))
self.model.remove(m_iter)
index -= 1
# update the label column
row[0] = label
# check if there are obsolete items after the last one
while len(self.model) > len(choices):
m_iter = self.model.get_iter((len(choices),))
self.model.remove(m_iter)
# restore the previous selection
for index, row in enumerate(self.model):
if row[1] == old_selection:
self.control.set_active(index)
print "Restored: %d" % index
break
else:
self.control.set_active(-1)
class InputCheckBox(InputBaseClass):
def __init__(self, start=False, change_handler=None):
import gtk
self.control = gtk.CheckButton()
self.control.set_active(start)
if change_handler:
self.control.connect("toggled", change_handler)
def get_value(self):
return self.control.get_active()
def set_value(self, value):
self.control.set_active(value)
# -*- coding: utf-8 -*-
"""
$Id$
Copyright 2011 Lars Kruse <devel@sumpfralle.de>
This file is part of PyCAM.
PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
import pycam.Plugins
import pycam.Gui.ControlsGTK
class PathParamOverlap(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager"]
def setup(self):
# TODO: check if gtk is in use
self.core.get("register_pathgenerator_parameter")("overlap",
"Overlap [%]", pycam.Gui.ControlsGTK.InputNumber(
lower=0, upper=99, digits=0,
change_handler=lambda widget=None: self.core.emit_event(
"pathgenerator-parameter-changed")),
weight=10)
return True
def teardown(self):
self.core.get("unregister_pathgenerator_parameter")("overlap")
class PathParamStepDown(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager"]
def setup(self):
# TODO: check if gtk is in use
self.core.get("register_pathgenerator_parameter")("step_down",
"Step down", pycam.Gui.ControlsGTK.InputNumber(lower=0.01,
upper=1000, digits=2, start=1,
change_handler=lambda widget=None: \
self.core.emit_event("pathgenerator-parameter-changed")),
weight=20)
return True
def teardown(self):
self.core.get("unregister_pathgenerator_parameter")("step_down")
class PathParamMaterialAllowance(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager"]
def setup(self):
# TODO: check if gtk is in use
self.core.get("register_pathgenerator_parameter")("material_allowance",
"Material allowance", pycam.Gui.ControlsGTK.InputNumber(
start=0, lower=0, upper=100, digits=2,
change_handler=lambda widget=None: self.core.emit_event(
"pathgenerator-parameter-changed")),
weight=30)
return True
def teardown(self):
self.core.get("unregister_pathgenerator_parameter")("overlap")
class PathParamMillingStyle(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager"]
def setup(self):
# TODO: check if gtk is in use
input_control = pycam.Gui.ControlsGTK.InputChoice(
(("ignore", "ignore"),
("climb / down", "climb"),
("conventional / up", "conventional")),
change_handler=lambda widget=None: self.core.emit_event(
"pathgenerator-parameter-changed"))
self.core.get("register_pathgenerator_parameter")("milling_style",
"Milling style", input_control, weight=50)
return True
def teardown(self):
self.core.get("unregister_pathgenerator_parameter")("milling_style")
class PathParamGridDirection(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager"]
def setup(self):
# TODO: check if gtk is in use
input_control = pycam.Gui.ControlsGTK.InputChoice(
(("x", "x"), ("y", "y"), ("xy", "xy")),
change_handler=lambda widget=None: self.core.emit_event(
"pathgenerator-parameter-changed"))
self.core.get("register_pathgenerator_parameter")("grid_direction",
"Direction", input_control, weight=40)
return True
def teardown(self):
self.core.get("unregister_pathgenerator_parameter")("grid_direction")
class PathParamRadiusCompensation(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager"]
def setup(self):
# TODO: check if gtk is in use
self.core.get("register_pathgenerator_parameter")("radius_compensation",
"Radius compensation",
pycam.Gui.ControlsGTK.InputCheckBox(
change_handler=lambda widget=None: self.core.emit_event(
"pathgenerator-parameter-changed")),
weight=80)
return True
def teardown(self):
self.core.get("unregister_pathgenerator_parameter")("radius_compensation")
class PathParamTraceModel(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager", "Models"]
def setup(self):
class InputModelSelection(pycam.Gui.ControlsGTK.InputChoice):
def get_value(inner_self):
ref = super(InputModelSelection, inner_self).get_value()
for model in self.core.get("models"):
if id(model) == ref:
return model
return None
# TODO: check if gtk is in use
self.input_control = InputModelSelection([], force_type=long,
change_handler=lambda widget=None: self.core.emit_event(
"pathgenerator-parameter-changed"))
self.input_control
self.core.get("register_pathgenerator_parameter")("trace_model",
"Trace model", self.input_control, weight=5)
self.core.register_event("model-list-changed", self._update_models)
return True
def _update_models(self):
choices = []
models = self.core.get("models")
for model in models:
if hasattr(model, "get_polygons"):
choices.append((models.get_attr(model, "name"), id(model)))
self.input_control.update_choices(choices)
def teardown(self):
self.core.get("unregister_pathgenerator_parameter")("trace_model")
# -*- coding: utf-8 -*-
"""
$Id$
Copyright 2011 Lars Kruse <devel@sumpfralle.de>
This file is part of PyCAM.
PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
import pycam.Plugins
class ProcessStrategyContour(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager", "PathParamStepDown",
"PathParamMaterialAllowance", "PathParamMillingStyle"]
def setup(self):
parameters = {"step_down": 1.0,
"material_allowance": 0,
"milling_style": "ignore",
}
self.core.get("register_strategy")("contour", "Waterline",
self.run_strategy, parameters=parameters, weight=20)
return True
def teardown(self):
self.core.get("unregister_strategy")("contour")
def run_strategy(self):
pass
# -*- coding: utf-8 -*-
"""
$Id$
Copyright 2011 Lars Kruse <devel@sumpfralle.de>
This file is part of PyCAM.
PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
import pycam.Plugins
class ProcessStrategyEngraving(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager", "PathParamStepDown",
"PathParamMillingStyle", "PathParamRadiusCompensation",
"PathParamTraceModel"]
def setup(self):
parameters = {"step_down": 1.0,
"milling_style": "ignore",
"radius_compensation": False,
"trace_model": None
}
self.core.get("register_strategy")("engraving", "Engraving",
self.run_strategy, parameters=parameters, weight=80)
return True
def teardown(self):
self.core.get("unregister_strategy")("engraving")
def run_strategy(self):
pass
# -*- coding: utf-8 -*-
"""
$Id$
Copyright 2011 Lars Kruse <devel@sumpfralle.de>
This file is part of PyCAM.
PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
import pycam.Plugins
class ProcessStrategyManager(pycam.Plugins.PluginBase):
def setup(self):
self.strategies = []
self.parameters = []
self.core.set("process-strategies", self.strategies)
self.core.set("pathgenerator_parameters", self.parameters)
self.core.set("register_strategy", self.register_strategy)
self.core.set("unregister_strategy", self.unregister_strategy)
self.core.set("register_pathgenerator_parameter",
self.register_generator_parameter)
self.core.set("unregister_pathgenerator_parameter",
self.unregister_generator_parameter)
self.core.set("get_pathgenerator_parameter_value",
self.get_parameter_value)
self.core.set("set_pathgenerator_parameter_value",
self.set_parameter_value)
return True
def teardown(self):
for name in ("strategies", "pathgenerator_parameters",
"register_strategy", "register_pathgenerator_parameter",
"unregister_strategy", "unregister_pathgenerator_parameter",
"get_pathgenerator_parameter_value",
"set_pathgenerator_parameter_value"):
self.core.set(name, None)
def register_strategy(self, name, label, func, parameters=None,
model_filter=None, weight=100):
if self.get_by_name(name):
self.log.debug("Registering an existing path generator again: " + \
name)
generator = {}
generator["name"] = name
generator["label"] = label
generator["func"] = func
generator["parameters"] = parameters or []
generator["model_filter"] = model_filter
generator["weight"] = weight
self.strategies.append(generator)
self.strategies.sort(key=lambda item: item["weight"])
self.core.emit_event("process-strategy-list-changed")
def unregister_strategy(self, name):
index = self.get_by_name(name, force_index=True)
if index < 0:
self.log.debug("Tried to unregister a non-existing path " + \
"generator: %s" % name)
else:
self.strategies.pop(index)
self.core.emit_event("process-strategy-list-changed")
def register_generator_parameter(self, name, label, control, weight=100):
if self.get_parameter_by_name(name):
self.log.debug("Registering an existing path generator parameter " + \
"again: %s" % name)
parameter = {}
parameter["name"] = name
parameter["label"] = label
parameter["control"] = control
parameter["weight"] = weight
self.parameters.append(parameter)
self.parameters.sort(key=lambda param: param["weight"])
self.core.emit_event("pathgenerator-parameter-list-changed")
def unregister_generator_parameter(self, name):
index = self.get_parameter_by_name(name, force_index=True)
if index < 0:
self.log.debug("Tried to unregister a non-existing path " + \
"generator parameter: %s" % name)
else:
self.parameters.pop(index)
self.core.emit_event("pathgenerator-parameter-list-changed")
def _get_by_name(self, name, force_index=False, data_list=None):
for index, generator in enumerate(data_list):
if generator["name"] == name:
if force_index:
return index
else:
return generator
else:
if force_index:
return -1
else:
return None
def get_by_name(self, *args, **kwargs):
merged_kw = kwargs.copy()
merged_kw.update({"data_list": self.strategies})
return self._get_by_name(*args, **merged_kw)
def get_parameter_by_name(self, *args, **kwargs):
merged_kw = kwargs.copy()
merged_kw.update({"data_list": self.parameters})
return self._get_by_name(*args, **merged_kw)
def get_parameter_value(self, name):
parameter = self.get_parameter_by_name(name)
if parameter:
return parameter["control"].get_value()
else:
self.log.debug("Unknown path parameter requested: %s" % name)
return None
def set_parameter_value(self, name, value):
parameter = self.get_parameter_by_name(name)
if parameter:
parameter["control"].set_value(value)
else:
self.log.debug("Unknown path parameter requested: %s" % name)
def run_path_generator(self, name, parameters):
generator = self.get_by_name(name)
if generator:
args = {}
for key in parameters:
if not key in generator["parameters"]:
continue
args[key] = parameters[key]
generator["func"](**parameters)
else:
self.log.debug("Tried to run a non-existing path generator:" + \
name)
#TODO: merge with ProcessStrategyManager
class PathParameterGTK(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager", "Processes"]
def setup(self):
# TODO: check for gtk
if True:
import gtk
self._gtk = gtk
self._table = gtk.Table(rows=1, columns=2)
self._table.set_col_spacings(3)
self._table.set_row_spacings(3)
self.core.register_ui("process_parameters", "Path parameters", self._table, 30)
self.core.register_event("pathgenerator-parameter-changed",
lambda: self.core.emit_event("process-changed"))
self.core.register_event("process-changed",
self._update_parameter_widgets)
self.core.register_event("process-strategy-changed",
self._update_parameter_widgets)
self.core.register_event("pathgenerator-parameter-list-changed",
self._update_parameter_widgets_table)
self._update_parameter_widgets_table()
self._table.show()
return True
def teardown(self):
if self.gui:
self.core.unregister_ui("process_parameters", self._table)
def _update_parameter_widgets_table(self):
# TODO: check for gtk
if True:
gtk = self._gtk
params = self.core.get("pathgenerator_parameters")
# remove all widgets from the table
for child in self._table.get_children():
self._table.remove(child)
# add the current controls
for index, param in enumerate(params):
widget = param["control"].get_widget()
if hasattr(widget, "get_label"):
# checkbox
widget.set_label(param["label"])
self._table.attach(widget, 0, 2, index, index + 1,
xoptions=gtk.FILL, yoptions=gtk.FILL)
else:
# spinbutton, combobox, ...
label = gtk.Label("%s:" % param["label"])
label.set_alignment(0.0, 0.5)
self._table.attach(label, 0, 1, index, index + 1,
xoptions=gtk.FILL, yoptions=gtk.FILL)
self._table.attach(widget, 1, 2, index, index + 1,
xoptions=gtk.FILL, yoptions=gtk.FILL)
self._update_parameter_widgets()
def _get_table_row_of_widget(self, widget):
for child in self._table.get_children():
if child is widget:
return self._get_child_row(child)
else:
return -1
def _get_child_row(self, widget):
return self._gtk.Container.child_get_property(self._table, widget,
"top-attach")
def _update_parameter_widgets(self):
params = self.core.get("pathgenerator_parameters")
generator = self.core.get("current-strategy")
if not generator:
return
for param in params:
table_row = self._get_table_row_of_widget(
param["control"].get_widget())
for child in self._table.get_children():
if self._get_child_row(child) == table_row:
if param["name"] in generator["parameters"]:
child.show()
else:
child.hide()
# -*- coding: utf-8 -*-
"""
$Id$
Copyright 2011 Lars Kruse <devel@sumpfralle.de>
This file is part of PyCAM.
PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
import pycam.Plugins
class ProcessStrategySlicing(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager", "PathParamOverlap",
"PathParamStepDown", "PathParamMaterialAllowance",
"PathParamMillingStyle", "PathParamGridDirection"]
def setup(self):
parameters = {"overlap": 10,
"step_down": 1.0,
"material_allowance": 0,
"milling_style": "ignore",
"grid_direction": "x",
}
self.core.get("register_strategy")("slicing", "Slice removal",
self.run_strategy, parameters=parameters, weight=10)
return True
def teardown(self):
self.core.get("unregister_strategy")("slicing")
def run_strategy(self):
pass
# -*- coding: utf-8 -*-
"""
$Id$
Copyright 2011 Lars Kruse <devel@sumpfralle.de>
This file is part of PyCAM.
PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
import pycam.Plugins
class ProcessStrategySurfacing(pycam.Plugins.PluginBase):
DEPENDS = ["ProcessStrategyManager", "PathParamOverlap",
"PathParamMaterialAllowance", "PathParamMillingStyle",
"PathParamGridDirection"]
def setup(self):
parameters = {"overlap": 60,
"material_allowance": 0,
"milling_style": "ignore",
"grid_direction": "x",
}
self.core.get("register_strategy")("surfacing", "Surfacing",
self.run_strategy, parameters=parameters, weight=50)
return True
def teardown(self):
self.core.get("unregister_strategy")("surfacing")
def run_strategy(self):
pass
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