Merge branch 'feature_intent_container_tree' of https://github.com/Ultimaker/Cura into feature_intent_container_tree

This commit is contained in:
Remco Burema 2019-08-15 16:47:29 +02:00
commit 9374934d72
4 changed files with 21 additions and 103 deletions

View file

@ -8,7 +8,7 @@ from UM.Settings.Interfaces import ContainerInterface
from cura.Machines.MachineNode import MachineNode from cura.Machines.MachineNode import MachineNode
from typing import Dict from typing import Dict
import time
## This class contains a look-up tree for which containers are available at ## This class contains a look-up tree for which containers are available at
# which stages of configuration. # which stages of configuration.
# #
@ -32,12 +32,15 @@ class ContainerTree:
## Builds the initial container tree. ## Builds the initial container tree.
def _loadAll(self): def _loadAll(self):
Logger.log("i", "Building container tree.") Logger.log("i", "Building container tree.")
start_time = time.time()
all_stacks = ContainerRegistry.getInstance().findContainerStacks() all_stacks = ContainerRegistry.getInstance().findContainerStacks()
for stack in all_stacks: for stack in all_stacks:
definition_id = stack.definition.getId() definition_id = stack.definition.getId()
if definition_id not in self.machines: if definition_id not in self.machines:
self.machines[definition_id] = MachineNode(definition_id) self.machines[definition_id] = MachineNode(definition_id)
Logger.log("d", "Building the container tree took %s seconds", time.time() - start_time)
## When a printer gets added, we need to build up the tree for that container. ## When a printer gets added, we need to build up the tree for that container.
def _machineAdded(self, definition_container: ContainerInterface): def _machineAdded(self, definition_container: ContainerInterface):
if not isinstance(definition_container, DefinitionContainer): if not isinstance(definition_container, DefinitionContainer):

View file

@ -83,71 +83,6 @@ class MaterialManager(QObject):
self._favorites = set(cura.CuraApplication.CuraApplication.getInstance().getPreferences().getValue("cura/favorite_materials").split(";")) self._favorites = set(cura.CuraApplication.CuraApplication.getInstance().getPreferences().getValue("cura/favorite_materials").split(";"))
self.materialsUpdated.emit() self.materialsUpdated.emit()
def __addMaterialMetadataIntoLookupTree(self, material_metadata: Dict[str, Any]) -> None:
material_id = material_metadata["id"]
# We don't store empty material in the lookup tables
if material_id == "empty_material":
return
root_material_id = material_metadata["base_file"]
definition = material_metadata["definition"]
approximate_diameter = str(material_metadata["approximate_diameter"])
if approximate_diameter not in self._diameter_machine_nozzle_buildplate_material_map:
self._diameter_machine_nozzle_buildplate_material_map[approximate_diameter] = {}
machine_nozzle_buildplate_material_map = self._diameter_machine_nozzle_buildplate_material_map[
approximate_diameter]
if definition not in machine_nozzle_buildplate_material_map:
machine_nozzle_buildplate_material_map[definition] = MaterialNode()
# This is a list of information regarding the intermediate nodes:
# nozzle -> buildplate
nozzle_name = material_metadata.get("variant_name")
buildplate_name = material_metadata.get("buildplate_name")
intermediate_node_info_list = [(nozzle_name, VariantType.NOZZLE),
(buildplate_name, VariantType.BUILD_PLATE),
]
variant_manager = cura.CuraApplication.CuraApplication.getInstance().getVariantManager()
machine_node = machine_nozzle_buildplate_material_map[definition]
current_node = machine_node
current_intermediate_node_info_idx = 0
error_message = None # type: Optional[str]
while current_intermediate_node_info_idx < len(intermediate_node_info_list):
variant_name, variant_type = intermediate_node_info_list[current_intermediate_node_info_idx]
if variant_name is not None:
# The new material has a specific variant, so it needs to be added to that specific branch in the tree.
variant = variant_manager.getVariantNode(definition, variant_name, variant_type)
if variant is None:
error_message = "Material {id} contains a variant {name} that does not exist.".format(
id = material_metadata["id"], name = variant_name)
break
# Update the current node to advance to a more specific branch
if variant_name not in current_node.children_map:
current_node.children_map[variant_name] = MaterialNode()
current_node = current_node.children_map[variant_name]
current_intermediate_node_info_idx += 1
if error_message is not None:
Logger.log("e", "%s It will not be added into the material lookup tree.", error_message)
CuraContainerRegistry.getInstance().addWrongContainerId(material_metadata["id"])
return
# Add the material to the current tree node, which is the deepest (the most specific) branch we can find.
# Sanity check: Make sure that there is no duplicated materials.
if root_material_id in current_node.material_map:
Logger.log("e", "Duplicated material [%s] with root ID [%s]. It has already been added.",
material_id, root_material_id)
ConfigurationErrorMessage.getInstance().addFaultyContainers(root_material_id)
return
current_node.material_map[root_material_id] = MaterialNode(material_metadata)
def getMaterialGroup(self, root_material_id: str) -> Optional[MaterialGroup]: def getMaterialGroup(self, root_material_id: str) -> Optional[MaterialGroup]:
return self._material_group_map.get(root_material_id) return self._material_group_map.get(root_material_id)
@ -190,41 +125,22 @@ class MaterialManager(QObject):
# #
def getMaterialNode(self, machine_definition_id: str, nozzle_name: Optional[str], def getMaterialNode(self, machine_definition_id: str, nozzle_name: Optional[str],
buildplate_name: Optional[str], diameter: float, root_material_id: str) -> Optional["MaterialNode"]: buildplate_name: Optional[str], diameter: float, root_material_id: str) -> Optional["MaterialNode"]:
# round the diameter to get the approximate diameter container_tree = ContainerTree.getInstance()
rounded_diameter = str(round(diameter)) machine_node = container_tree.machines.get(machine_definition_id)
if rounded_diameter not in self._diameter_machine_nozzle_buildplate_material_map: if machine_node is None:
Logger.log("i", "Cannot find materials with diameter [%s] (rounded to [%s]) for root material id [%s]", Logger.log("w", "Could not find machine with definition %s in the container tree", machine_definition_id)
diameter, rounded_diameter, root_material_id)
return None return None
# If there are nozzle materials, get the nozzle-specific material variant_node = machine_node.variants.get(nozzle_name)
machine_nozzle_buildplate_material_map = self._diameter_machine_nozzle_buildplate_material_map[rounded_diameter] # type: Dict[str, MaterialNode] if variant_node is None:
machine_node = machine_nozzle_buildplate_material_map.get(machine_definition_id) Logger.log("w", "Could not find variant %s for machine with definition %s in the container tree", nozzle_name, machine_definition_id )
nozzle_node = None return None
buildplate_node = None
# Fallback for "fdmprinter" if the machine-specific materials cannot be found material_node = variant_node.materials.get(root_material_id)
if machine_node is None:
machine_node = machine_nozzle_buildplate_material_map.get(self._default_machine_definition_id)
if machine_node is not None and nozzle_name is not None and nozzle_name in machine_node.children_map:
nozzle_node = machine_node.children_map[nozzle_name]
if nozzle_node is not None and buildplate_name is not None and buildplate_name in nozzle_node.children_map:
buildplate_node = nozzle_node.children_map[buildplate_name]
# Fallback mechanism of finding materials: if material_node is None:
# 1. buildplate-specific material Logger.log("w", "Could not find material %s for machine with definition %s and variant %s in the container tree", root_material_id, machine_definition_id, nozzle_name)
# 2. nozzle-specific material return None
# 3. machine-specific material
# 4. generic material (for fdmprinter)
nodes_to_check = [buildplate_node, nozzle_node, machine_node,
machine_nozzle_buildplate_material_map.get(self._default_machine_definition_id)]
material_node = None
for node in nodes_to_check:
if node is not None:
material_node = node.material_map.get(root_material_id)
if material_node:
break
return material_node return material_node

View file

@ -1,11 +1,10 @@
# Copyright (c) 2019 Ultimaker B.V. # Copyright (c) 2019 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
from typing import TYPE_CHECKING, Optional, cast, Dict, List, Set from typing import TYPE_CHECKING, Optional, Dict
from PyQt5.QtCore import QObject, QTimer, pyqtSignal, pyqtSlot from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot
from UM.ConfigurationErrorMessage import ConfigurationErrorMessage
from UM.Logger import Logger from UM.Logger import Logger
from UM.Util import parseBool from UM.Util import parseBool
from UM.Settings.InstanceContainer import InstanceContainer from UM.Settings.InstanceContainer import InstanceContainer
@ -117,7 +116,7 @@ class QualityManager(QObject):
nozzle_name = extruder.variant.getName() nozzle_name = extruder.variant.getName()
material_base = extruder.material.getMetaDataEntry("base_file") material_base = extruder.material.getMetaDataEntry("base_file")
if nozzle_name not in machine_node.variants or material_base not in machine_node.variants[nozzle_name].materials: if nozzle_name not in machine_node.variants or material_base not in machine_node.variants[nozzle_name].materials:
# The printer has no variant/material-specific quality profiles. Return the global quality profiles. # The printer has no variant/material-specific quality profiles. Use the global quality profiles.
qualities_per_type_per_extruder[extruder_nr] = machine_node.global_qualities qualities_per_type_per_extruder[extruder_nr] = machine_node.global_qualities
else: else:
# Use the actually specialised quality profiles. # Use the actually specialised quality profiles.
@ -126,8 +125,8 @@ class QualityManager(QObject):
# Create the quality group for each available type. # Create the quality group for each available type.
quality_groups = {} quality_groups = {}
for quality_type, global_quality_node in machine_node.global_qualities.items(): for quality_type, global_quality_node in machine_node.global_qualities.items():
quality_groups[quality_type].node_for_global = global_quality_node
quality_groups[quality_type] = QualityGroup(name = global_quality_node.getMetaDataEntry("name", "Unnamed profile"), quality_type = quality_type) quality_groups[quality_type] = QualityGroup(name = global_quality_node.getMetaDataEntry("name", "Unnamed profile"), quality_type = quality_type)
quality_groups[quality_type].node_for_global = global_quality_node
for extruder, qualities_per_type in qualities_per_type_per_extruder: for extruder, qualities_per_type in qualities_per_type_per_extruder:
quality_groups[quality_type].nodes_for_extruders[extruder] = qualities_per_type[quality_type] quality_groups[quality_type].nodes_for_extruders[extruder] = qualities_per_type[quality_type]

View file

@ -1253,7 +1253,7 @@ class MachineManager(QObject):
if self._global_container_stack is None: if self._global_container_stack is None:
return return
if material_node: if material_node:
self._global_container_stack.extruders[position].material = CuraContainerRegistry.getInstance().findContainers(id = material_node.container_id) self._global_container_stack.extruders[position].material = CuraContainerRegistry.getInstance().findContainers(id = material_node.container_id)[0]
root_material_id = material_node.getMetaDataEntry("base_file", None) root_material_id = material_node.getMetaDataEntry("base_file", None)
else: else:
self._global_container_stack.extruders[position].material = empty_material_container self._global_container_stack.extruders[position].material = empty_material_container