forked from iot-salzburg/STL-tweaker
-
Notifications
You must be signed in to change notification settings - Fork 7
/
OrientationPlugin.py
140 lines (109 loc) · 5.86 KB
/
OrientationPlugin.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
from typing import List, cast
from UM.Extension import Extension
from UM.PluginRegistry import PluginRegistry
from UM.Scene.SceneNode import SceneNode
from UM.Scene.Selection import Selection
from UM.Message import Message
from cura.CuraApplication import CuraApplication
from cura.CuraVersion import CuraVersion # type: ignore
from UM.Version import Version
from .CalculateOrientationJob import CalculateOrientationJob
from UM.i18n import i18nCatalog
import os
i18n_catalog = i18nCatalog("OrientationPlugin")
class OrientationPlugin(Extension):
def __init__(self):
super().__init__()
self.addMenuItem(i18n_catalog.i18n("Calculate fast optimal printing orientation"), self.doFastAutoOrientation)
self.addMenuItem(i18n_catalog.i18n("Calculate extended optimal printing orientation"), self.doExtendedAutoOrientiation)
self.addMenuItem("", lambda: None)
self.addMenuItem(i18n_catalog.i18n("Modify Settings"), self.showPopup)
self._message = None
self._currently_loading_files = [] # type: List[str]
self._check_node_queue = [] # type: List[SceneNode]
CuraApplication.getInstance().getPreferences().addPreference("OrientationPlugin/do_auto_orientation", False)
self._do_auto_orientation = CuraApplication.getInstance().getPreferences().getValue("OrientationPlugin/do_auto_orientation")
# Should the volume beneath the overhangs be penalized?
CuraApplication.getInstance().getPreferences().addPreference("OrientationPlugin/min_volume", True)
self._popup = None
CuraApplication.getInstance().fileLoaded.connect(self._onFileLoaded)
CuraApplication.getInstance().fileCompleted.connect(self._onFileCompleted)
CuraApplication.getInstance().getController().getScene().sceneChanged.connect(self._onSceneChanged)
CuraApplication.getInstance().getPreferences().preferenceChanged.connect(self._onPreferencesChanged)
# Use the qml_qt6 stuff for 5.0.0 and up
if Version(CuraVersion).getMajor() >= 5:
self._qml_folder = "qml_qt6"
else:
self._qml_folder = "qml_qt5"
def _onPreferencesChanged(self, name: str) -> None:
if name != "OrientationPlugin/do_auto_orientation":
return
self._do_auto_orientation = CuraApplication.getInstance().getPreferences().getValue("OrientationPlugin/do_auto_orientation")
def _createPopup(self) -> None:
# Create the plugin dialog component
path = os.path.join(cast(str, PluginRegistry.getInstance().getPluginPath(self.getPluginId())), self._qml_folder,
"SettingsPopup.qml")
self._popup = CuraApplication.getInstance().createQmlComponent(path)
if self._popup is None:
return
def showPopup(self) -> None:
if self._popup is None:
self._createPopup()
if self._popup is None:
return
self._popup.show()
def _onFileLoaded(self, file_name):
self._currently_loading_files.append(file_name)
def _onFileCompleted(self, file_name):
if file_name in self._currently_loading_files:
self._currently_loading_files.remove(file_name)
def _onSceneChanged(self, node):
if not self._do_auto_orientation:
return # Nothing to do!
if not node or not node.getMeshData():
return
# only check meshes that have just been loaded
if node.getMeshData().getFileName() not in self._currently_loading_files:
return
# the scene may change multiple times while loading a mesh,
# but we want to check the mesh only once
if node not in self._check_node_queue:
self._check_node_queue.append(node)
CuraApplication.getInstance().callLater(self.checkQueuedNodes)
def checkQueuedNodes(self):
for node in self._check_node_queue:
if self._message:
self._message.hide()
auto_orient_message = Message(i18n_catalog.i18nc("@info:status", "Auto-Calculating the optimal orientation because auto orientation is enabled"), 0,
False, -1, title=i18n_catalog.i18nc("@title", "Auto-Orientation"))
auto_orient_message.show()
job = CalculateOrientationJob([node], extended_mode=True, message=auto_orient_message)
job.finished.connect(self._onFinished)
job.start()
self._check_node_queue = []
def doFastAutoOrientation(self):
self.doAutoOrientation(False)
def doExtendedAutoOrientiation(self):
self.doAutoOrientation(True)
def doAutoOrientation(self, extended_mode):
# If we still had a message open from last time, hide it.
if self._message:
self._message.hide()
selected_nodes = Selection.getAllSelectedObjects()
if len(selected_nodes) == 0:
self._message = Message(i18n_catalog.i18nc("@info:status", "No objects selected to orient. Please select one or more objects and try again."), title = i18n_catalog.i18nc("@title", "Auto-Orientation"))
self._message.show()
return
message = Message(i18n_catalog.i18nc("@info:status", "Calculating the optimal orientation..."), 0, False, -1, title = i18n_catalog.i18nc("@title", "Auto-Orientation"))
message.show()
job = CalculateOrientationJob(selected_nodes, extended_mode = extended_mode, message = message)
job.finished.connect(self._onFinished)
job.start()
def _onFinished(self, job):
if self._message:
self._message.hide()
if job.getMessage() is not None:
job.getMessage().hide()
self._message = Message(i18n_catalog.i18nc("@info:status", "All selected objects have been oriented."),
title=i18n_catalog.i18nc("@title", "Auto-Orientation"))
self._message.show()