-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathPressureAdvanceSettingPlugin.py
141 lines (106 loc) · 5.88 KB
/
PressureAdvanceSettingPlugin.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# Copyright (c) 2020 ollyfg
# The PressureAdvanceSettingPlugin is released under the terms of the AGPLv3 or higher.
from UM.Extension import Extension
from cura.CuraApplication import CuraApplication
from UM.Logger import Logger
from UM.Settings.SettingDefinition import SettingDefinition
from UM.Settings.DefinitionContainer import DefinitionContainer
from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.i18n import i18nCatalog
i18n_catalog = i18nCatalog("PressureAdvanceSettingPlugin")
import collections
import json
import os.path
from typing import List, Optional, Any, Dict, TYPE_CHECKING
if TYPE_CHECKING:
from UM.OutputDevice.OutputDevice import OutputDevice
class PressureAdvanceSettingPlugin(Extension):
def __init__(self) -> None:
super().__init__()
self._application = CuraApplication.getInstance()
self._i18n_catalog = None # type: Optional[i18nCatalog]
self._settings_dict = {} # type: Dict[str, Any]
self._expanded_categories = [] # type: List[str] # temporary list used while creating nested settings
settings_definition_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "pressure_advance.def.json")
try:
with open(settings_definition_path, "r", encoding = "utf-8") as f:
self._settings_dict = json.load(f, object_pairs_hook = collections.OrderedDict)
except:
Logger.logException("e", "Could not load pressure advance settings definition")
return
ContainerRegistry.getInstance().containerLoadComplete.connect(self._onContainerLoadComplete)
self._application.getOutputDeviceManager().writeStarted.connect(self._filterGcode)
def _onContainerLoadComplete(self, container_id: str) -> None:
if not ContainerRegistry.getInstance().isLoaded(container_id):
# skip containers that could not be loaded, or subsequent findContainers() will cause an infinite loop
return
try:
container = ContainerRegistry.getInstance().findContainers(id = container_id)[0]
except IndexError:
# the container no longer exists
return
if not isinstance(container, DefinitionContainer):
# skip containers that are not definitions
return
if container.getMetaDataEntry("type") == "extruder":
# skip extruder definitions
return
try:
material_category = container.findDefinitions(key="material")[0]
except IndexError:
Logger.log("e", "Could not find parent category setting to add settings to")
return
setting_key = list(self._settings_dict.keys())[0]
setting_definition = SettingDefinition(setting_key, container, material_category, self._i18n_catalog)
setting_definition.deserialize(self._settings_dict[setting_key])
# add the setting to the already existing material settingdefinition
# private member access is naughty, but the alternative is to serialise, nix and deserialise the whole thing,
# which breaks stuff
material_category._children.append(setting_definition)
container._definition_cache[setting_key] = setting_definition
self._expanded_categories = self._application.expandedCategories.copy()
self._updateAddedChildren(container, setting_definition)
self._application.setExpandedCategories(self._expanded_categories)
self._expanded_categories = [] # type: List[str]
container._updateRelations(setting_definition)
def _updateAddedChildren(self, container: DefinitionContainer, setting_definition: SettingDefinition) -> None:
children = setting_definition.children
if not children or not setting_definition.parent:
return
# make sure this setting is expanded so its children show up in setting views
if setting_definition.parent.key in self._expanded_categories:
self._expanded_categories.append(setting_definition.key)
for child in children:
container._definition_cache[child.key] = child
self._updateAddedChildren(container, child)
def _filterGcode(self, output_device: "OutputDevice") -> None:
scene = self._application.getController().getScene()
global_container_stack = self._application.getGlobalContainerStack()
used_extruder_stacks = self._application.getExtruderManager().getUsedExtruderStacks()
if not global_container_stack or not used_extruder_stacks:
return
gcode_dict = getattr(scene, "gcode_dict", {})
if not gcode_dict: # this also checks for an empty dict
Logger.log("w", "Scene has no gcode to process")
return
gcode_command_pattern = "SET_PRESSURE_ADVANCE ADVANCE=%f" # TODO: Add smoothing as another setting
gcode_command_pattern += " ;added by PressureAdvanceSettingPlugin"
dict_changed = False
for plate_id in gcode_dict:
gcode_list = gcode_dict[plate_id]
if len(gcode_list) < 2:
Logger.log("w", "Plate %s does not contain any layers", plate_id)
continue
if ";PRESSUREDVANCEPROCESSED\n" in gcode_list[0]:
Logger.log("d", "Plate %s has already been processed", plate_id)
continue
setting_key = list(self._settings_dict.keys())[0]
apply_factor_per_feature = {} # type: Dict[int, bool]
for extruder_stack in used_extruder_stacks:
pressure_advance_factor = extruder_stack.getProperty(setting_key, "value")
gcode_list[1] = gcode_list[1] + gcode_command_pattern % (pressure_advance_factor) + "\n"
dict_changed = True
gcode_list[0] += ";PRESSUREADVANCEPROCESSED\n"
gcode_dict[plate_id] = gcode_list
if dict_changed:
setattr(scene, "gcode_dict", gcode_dict)