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: b4c79387a8f7c704b6028612c70c15c331ff4b0f (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
# Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.

from PyQt5.QtCore import QTimer
from cura.Scene.CuraSceneNode import CuraSceneNode

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

catalog = i18nCatalog("cura")


SHRINKAGE_THRESHOLD = 0.5
WARNING_SIZE_XY = 150
WARNING_SIZE_Z = 100

MESSAGE_LIFETIME = 10


class ModelChecker(Extension):
    def __init__(self):
        super().__init__()

        self._update_timer = QTimer()
        self._update_timer.setInterval(2000)
        self._update_timer.setSingleShot(True)
        self._update_timer.timeout.connect(self.checkObjects)

        self._nodes_to_check = set()

        self._warning_model_names = set()  # Collect the names of models so we show the next warning with timeout

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

    def bindSignals(self):
        Application.getInstance().getController().getScene().sceneChanged.connect(self._onSceneChanged)
        Application.getInstance().getMachineManager().rootMaterialChanged.connect(self._checkAllSliceableNodes)

    def checkObjects(self):
        warning_nodes = []
        global_container_stack = Application.getInstance().getGlobalContainerStack()
        material_shrinkage = {}
        need_check = False

        # Get all shrinkage values of materials used
        for extruder_position, extruder in global_container_stack.extruders.items():
            shrinkage = extruder.material.getProperty("material_shrinkage_ratio_percentage", "value")
            if shrinkage is None:
                shrinkage = 0
            if shrinkage > SHRINKAGE_THRESHOLD:
                need_check = True
            material_shrinkage[extruder_position] = shrinkage

        # Check if we can bail out fast
        if not need_check:
            return

        # Check node material shrinkage and bounding box size
        for node in self._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)
        self._nodes_to_check = set()

        # Display warning message
        if warning_nodes:
            message_lifetime = MESSAGE_LIFETIME
            for node in warning_nodes:
                if node.getName() not in self._warning_model_names:
                    message_lifetime = 0  # infinite
                    self._warning_model_names.add(node.getName())
            caution_message = Message(catalog.i18nc(
                "@info:warning",
                "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 = message_lifetime,
                title = catalog.i18nc("@info:title", "Model Warning"))
            caution_message.show()

    def _onSceneChanged(self, source):
        if isinstance(source, CuraSceneNode) and source.callDecoration("isSliceable"):
            self._nodes_to_check.add(source)
            self._update_timer.start()

    def _checkAllSliceableNodes(self, *args):
        # Add all scene nodes
        scene = Application.getInstance().getController().getScene()
        for node in DepthFirstIterator(scene.getRoot()):
            if node.callDecoration("isSliceable"):
                self._nodes_to_check.add(node)
        if self._nodes_to_check:
            self._update_timer.start()