Welcome to mirror list, hosted at ThFree Co, Russian Federation.

ModelChecker.py « ModelChecker « plugins - github.com/Ultimaker/Cura.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 285002deda87d94cb0705f4d33eed98bfa1889ee (plain)
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
# Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.

import os

from PyQt5.QtCore import QObject, pyqtSlot, pyqtSignal, pyqtProperty

from UM.Application import Application
from UM.Extension import Extension
from UM.Logger import Logger
from UM.Message import Message
from UM.i18n import i18nCatalog
from UM.PluginRegistry import PluginRegistry
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator

catalog = i18nCatalog("cura")


SHRINKAGE_THRESHOLD = 0.5
WARNING_SIZE_XY = 150
WARNING_SIZE_Z = 100

# Use this when actual shrinkage data is not in fdm_materials yet
MATERIALS_LOOKUP = {
    "generic_abs": 1,
    "generic_pc": 1,
    "generic_pp": 1,
    "generic_cpe_plus": 1
}


class ModelChecker(QObject, Extension):

    needCheckChanged = pyqtSignal()

    def __init__(self):
        super().__init__()

        self._button_view = None
        self._need_checks = False

        Application.getInstance().initializationFinished.connect(self.bindSignals)

    def bindSignals(self):
        Application.getInstance().getMachineManager().rootMaterialChanged.connect(self._onChanged)

    def checkObjectsForShrinkage(self, nodes_to_check):
        material_shrinkage = self.getMaterialShrinkage()

        warning_nodes = []

        # Check node material shrinkage and bounding box size
        for node in nodes_to_check:
            node_extruder_position = node.callDecoration("getActiveExtruderPosition")
            if material_shrinkage[node_extruder_position] > SHRINKAGE_THRESHOLD:
                bbox = node.getBoundingBox()
                if bbox.width >= WARNING_SIZE_XY or bbox.depth >= WARNING_SIZE_XY or bbox.height >= WARNING_SIZE_Z:
                    warning_nodes.append(node)

        return warning_nodes

    def checkAllSliceableNodes(self):
        # Add all sliceable scene nodes to check
        scene = Application.getInstance().getController().getScene()
        nodes_to_check = []
        for node in DepthFirstIterator(scene.getRoot()):
            if node.callDecoration("isSliceable"):
                nodes_to_check.append(node)
        return self.checkObjectsForShrinkage(nodes_to_check)

    ##  Display warning message
    def showWarningMessage(self, warning_nodes):
        caution_message = Message(catalog.i18nc(
            "@info:status",
            "Some models may not be printed optimal due to object size and material chosen [%s].\n"
            "Tips that may be useful to improve the print quality:\n"
            "1) Use rounded corners\n"
            "2) Turn the fan off (only if the are no tiny details on the model)\n"
            "3) Use a different material") % ", ".join([n.getName() for n in warning_nodes]),
            lifetime = 0,
            title = catalog.i18nc("@info:title", "Model Checker Warning"))
        caution_message.show()

    def showHappyMessage(self):
        happy_message = Message(catalog.i18nc(
            "@info:status",
            "The Model Checker did not detect any problems with your model / chosen materials combination."),
            lifetime = 5,
            title = catalog.i18nc("@info:title", "Model Checker"))
        happy_message.show()

    ##  Creates the view used by show popup. The view is saved because of the fairly aggressive garbage collection.
    def _createView(self):
        Logger.log("d", "Creating model checker view.")

        # Create the plugin dialog component
        path = os.path.join(PluginRegistry.getInstance().getPluginPath("ModelChecker"), "ModelChecker.qml")
        self._button_view = Application.getInstance().createQmlComponent(path, {"manager": self})

        # The qml is only the button
        Application.getInstance().addAdditionalComponent("jobSpecsButton", self._button_view)

        Logger.log("d", "Model checker view created.")

    def _onChanged(self, *args):
        if self._button_view is None:
            self._createView()
        old_need_checks = self._need_checks
        self._need_checks = self.calculateNeedCheck()
        if old_need_checks != self._need_checks:
            self.needCheckChanged.emit()

    @pyqtSlot()
    def runChecks(self):
        warning_nodes = self.checkAllSliceableNodes()
        if warning_nodes:
            self.showWarningMessage(warning_nodes)
        else:
            self.showHappyMessage()

    # TODO: use this if branch feature_model_check is merged in fdm_materials to master
    # def getMaterialShrinkage(self):
    #     global_container_stack = Application.getInstance().getGlobalContainerStack()
    #     if global_container_stack is None:
    #         return {}
    #
    #     material_shrinkage = {}
    #     # Get all shrinkage values of materials used
    #     for extruder_position, extruder in global_container_stack.extruders.items():
    #         shrinkage = extruder.material.getProperty("material_shrinkage_percentage", "value")
    #         if shrinkage is None:
    #             shrinkage = 0
    #         material_shrinkage[extruder_position] = shrinkage
    #     return material_shrinkage

    def getMaterialShrinkage(self):
        global_container_stack = Application.getInstance().getGlobalContainerStack()
        if global_container_stack is None:
            return {}

        material_shrinkage = {}
        # Get all shrinkage values of materials used
        for extruder_position, extruder in global_container_stack.extruders.items():
            base_file = extruder.material.getMetaDataEntry("base_file")
            shrinkage = MATERIALS_LOOKUP.get(base_file, 0)
            material_shrinkage[extruder_position] = shrinkage
        return material_shrinkage

    @pyqtProperty(bool, notify = needCheckChanged)
    def needCheck(self):
        return self._need_checks

    def calculateNeedCheck(self):
        need_check = False

        for shrinkage in self.getMaterialShrinkage().values():
            if shrinkage > SHRINKAGE_THRESHOLD:
                need_check = True

        return need_check