forked from fieldOfView/Cura-LinearAdvanceSettingPlugin
/
LinearAdvanceSettingPlugin.py
166 lines (134 loc) · 7.34 KB
/
LinearAdvanceSettingPlugin.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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# Copyright (c) 2018 fieldOfView
# The LinearAdvanceSettingPlugin is released under the terms of the AGPLv3 or higher.
from UM.Extension import Extension
from UM.Application import Application
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("LinearAdvanceSettingPlugin")
import collections
import json
import os.path
class LinearAdvanceSettingPlugin(Extension):
def __init__(self) -> None:
super().__init__()
self._application = Application.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__)), "linear_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 linear advance settings definition")
return
ContainerRegistry.getInstance().containerLoadComplete.connect(self._onContainerLoadComplete)
self._application.getOutputDeviceManager().writeStarted.connect(self._filterGcode)
def _onContainerLoadComplete(self, container_id: str) -> None:
container = ContainerRegistry.getInstance().findContainers(id = container_id)[0]
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
container._updateRelations(setting_definition)
self._expanded_categories = self._application.expandedCategories.copy()
self._updateAddedChildren(container, setting_definition)
self._application.setExpandedCategories(self._expanded_categories)
self._expanded_categories = []
def _updateAddedChildren(self, container: DefinitionContainer, setting_definition: SettingDefinition) -> None:
children = setting_definition.children
if not children:
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
# check if any LA factor is specified at all
some_factors_set = False
for extruder_stack in used_extruder_stacks:
for setting_key in self.__gcode_type_to_setting_key.values():
linear_advance_factor = extruder_stack.getProperty(setting_key, "value")
if linear_advance_factor != 0:
some_factors_set = True
break
if some_factors_set:
break
if not some_factors_set:
Logger.log("d", "No used extruders specify a linear advance factor")
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
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 ";LINEARADVANCEPROCESSED\n" in gcode_list[0]:
Logger.log("d", "Plate %s has already been processed", plate_id)
continue
for layer_nr, layer in enumerate(gcode_list):
lines = layer.split("\n")
lines_changed = False
for line_nr, line in enumerate(lines):
if line.startswith(";TYPE:"):
# Changed line type
feature_type = line[6:] # remove ";TYPE:"
try:
setting_key = self.__gcode_type_to_setting_key[feature_type]
except KeyError:
Logger.log("w", "Unknown feature type in gcode: ", feature_type)
setting_key = ""
for extruder_stack in used_extruder_stacks:
if setting_key:
linear_advance_factor = extruder_stack.getProperty(setting_key, "value")
else: # unknown feature type
linear_advance_factor = 0 # no linear advance compensation for this feature
extruder_nr = extruder_stack.getProperty("extruder_nr", "value")
lines.insert(line_nr + 1, "M900 K%f T%d ;added by LinearAdvanceSettingPlugin" % (linear_advance_factor, extruder_nr))
lines_changed = True
if lines_changed:
gcode_list[layer_nr] = "\n".join(lines)
dict_changed = True
gcode_list[0] += ";LINEARADVANCEPROCESSED\n"
gcode_dict[plate_id] = gcode_list
if dict_changed:
setattr(scene, "gcode_dict", gcode_dict)
__gcode_type_to_setting_key = {
"WALL-OUTER": "material_linear_advance_factor_wall_0",
"WALL-INNER": "material_linear_advance_factor_wall_x",
"SKIN": "material_linear_advance_factor_topbottom",
"SUPPORT": "material_linear_advance_factor_support",
"SUPPORT-INTERFACE": "material_linear_advance_factor_support_interface",
"SKIRT": "material_linear_advance_factor_skirt_brim",
"FILL": "material_linear_advance_factor_infill",
"PRIME-TOWER": "material_linear_advance_factor_prime_tower"
}