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

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

from typing import Any, Optional, TYPE_CHECKING

from UM.Logger import Logger
from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.Settings.Interfaces import ContainerInterface
from UM.Signal import Signal
from cura.Machines.ContainerNode import ContainerNode
from cura.Machines.QualityNode import QualityNode
import UM.FlameProfiler
if TYPE_CHECKING:
    from typing import Dict
    from cura.Machines.VariantNode import VariantNode


##  Represents a material in the container tree.
#
#   Its subcontainers are quality profiles.
class MaterialNode(ContainerNode):
    def __init__(self, container_id: str, variant: "VariantNode") -> None:
        super().__init__(container_id)
        self.variant = variant
        self.qualities = {}  # type: Dict[str, QualityNode] # Mapping container IDs to quality profiles.
        self.materialChanged = Signal()  # Triggered when the material is removed or its metadata is updated.

        container_registry = ContainerRegistry.getInstance()
        my_metadata = container_registry.findContainersMetadata(id = container_id)[0]
        self.base_file = my_metadata["base_file"]
        self.material_type = my_metadata["material"]
        self.guid = my_metadata["GUID"]
        self._loadAll()
        container_registry.containerRemoved.connect(self._onRemoved)
        container_registry.containerMetaDataChanged.connect(self._onMetadataChanged)

    ##  Finds the preferred quality for this printer with this material and this
    #   variant loaded.
    #
    #   If the preferred quality is not available, an arbitrary quality is
    #   returned. If there is a configuration mistake (like a typo in the
    #   preferred quality) this returns a random available quality. If there are
    #   no available qualities, this will return the empty quality node.
    #   \return The node for the preferred quality, or any arbitrary quality if
    #   there is no match.
    def preferredQuality(self) -> QualityNode:
        for quality_id, quality_node in self.qualities.items():
            if self.variant.machine.preferred_quality_type == quality_node.quality_type:
                return quality_node
        fallback = next(iter(self.qualities.values()))  # Should only happen with empty quality node.
        Logger.log("w", "Could not find preferred quality type {preferred_quality_type} for material {material_id} and variant {variant_id}, falling back to {fallback}.".format(
            preferred_quality_type = self.variant.machine.preferred_quality_type,
            material_id = self.container_id,
            variant_id = self.variant.container_id,
            fallback = fallback.container_id
        ))
        return fallback

    @UM.FlameProfiler.profile
    def _loadAll(self) -> None:
        container_registry = ContainerRegistry.getInstance()
        # Find all quality profiles that fit on this material.
        if not self.variant.machine.has_machine_quality:  # Need to find the global qualities.
            qualities = container_registry.findInstanceContainersMetadata(type = "quality",
                                                                          definition = "fdmprinter")
        elif not self.variant.machine.has_materials:
            qualities = container_registry.findInstanceContainersMetadata(type = "quality",
                                                                          definition = self.variant.machine.quality_definition)
        else:
            if self.variant.machine.has_variants:
                # Need to find the qualities that specify a material profile with the same material type.
                qualities = container_registry.findInstanceContainersMetadata(type = "quality",
                                                                              definition = self.variant.machine.quality_definition,
                                                                              variant = self.variant.variant_name,
                                                                              material = self.base_file)  # First try by exact material ID.
                # CURA-7070
                # The quality profiles only reference a material with the material_root_id. They will never state something
                # such as "generic_pla_ultimaker_s5_AA_0.4". So we search with the "base_file" which is the material_root_id.
            else:
                qualities = container_registry.findInstanceContainersMetadata(type = "quality", definition = self.variant.machine.quality_definition, material = self.base_file)
            if not qualities:
                my_material_type = self.material_type
                if self.variant.machine.has_variants:
                    qualities_any_material = container_registry.findInstanceContainersMetadata(type = "quality",
                                                                                               definition = self.variant.machine.quality_definition,
                                                                                               variant = self.variant.variant_name)
                else:
                    qualities_any_material = container_registry.findInstanceContainersMetadata(type = "quality", definition = self.variant.machine.quality_definition)
                for material_metadata in container_registry.findInstanceContainersMetadata(type = "material", material = my_material_type):
                    qualities.extend((quality for quality in qualities_any_material if quality.get("material") == material_metadata["base_file"]))

                if not qualities:  # No quality profiles found. Go by GUID then.
                    my_guid = self.guid
                    for material_metadata in container_registry.findInstanceContainersMetadata(type = "material", guid = my_guid):
                        qualities.extend((quality for quality in qualities_any_material if quality["material"] == material_metadata["base_file"]))

                if not qualities:
                    # There are still some machines that should use global profiles in the extruder, so do that now.
                    # These are mostly older machines that haven't received updates (so single extruder machines without specific qualities
                    # but that do have materials and profiles specific to that machine)
                    qualities.extend([quality for quality in qualities_any_material if quality.get("global_quality", "False") != "False"])

        for quality in qualities:
            quality_id = quality["id"]
            if quality_id not in self.qualities:
                self.qualities[quality_id] = QualityNode(quality_id, parent = self)
        if not self.qualities:
            self.qualities["empty_quality"] = QualityNode("empty_quality", parent = self)

    ##  Triggered when any container is removed, but only handles it when the
    #   container is removed that this node represents.
    #   \param container The container that was allegedly removed.
    def _onRemoved(self, container: ContainerInterface) -> None:
        if container.getId() == self.container_id:
            # Remove myself from my parent.
            if self.base_file in self.variant.materials:
                del self.variant.materials[self.base_file]
                if not self.variant.materials:
                    self.variant.materials["empty_material"] = MaterialNode("empty_material", variant = self.variant)
            self.materialChanged.emit(self)

    ##  Triggered when any metadata changed in any container, but only handles
    #   it when the metadata of this node is changed.
    #   \param container The container whose metadata changed.
    #   \param kwargs Key-word arguments provided when changing the metadata.
    #   These are ignored. As far as I know they are never provided to this
    #   call.
    def _onMetadataChanged(self, container: ContainerInterface, **kwargs: Any) -> None:
        if container.getId() != self.container_id:
            return

        new_metadata = container.getMetaData()
        old_base_file = self.base_file
        if new_metadata["base_file"] != old_base_file:
            self.base_file = new_metadata["base_file"]
            if old_base_file in self.variant.materials:  # Move in parent node.
                del self.variant.materials[old_base_file]
            self.variant.materials[self.base_file] = self

        old_material_type = self.material_type
        self.material_type = new_metadata["material"]
        old_guid = self.guid
        self.guid = new_metadata["GUID"]
        if self.base_file != old_base_file or self.material_type != old_material_type or self.guid != old_guid:  # List of quality profiles could've changed.
            self.qualities = {}
            self._loadAll()  # Re-load the quality profiles for this node.
        self.materialChanged.emit(self)