mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-07 06:57:28 -06:00
Add one more layer to the decision tree
This commit is contained in:
parent
a303f394c8
commit
066a00653a
6 changed files with 368 additions and 185 deletions
|
@ -4,8 +4,7 @@
|
||||||
from collections import defaultdict, OrderedDict
|
from collections import defaultdict, OrderedDict
|
||||||
import copy
|
import copy
|
||||||
import uuid
|
import uuid
|
||||||
from typing import Dict, cast
|
from typing import Dict, Optional, TYPE_CHECKING
|
||||||
from typing import Optional, TYPE_CHECKING
|
|
||||||
|
|
||||||
from PyQt5.Qt import QTimer, QObject, pyqtSignal, pyqtSlot
|
from PyQt5.Qt import QTimer, QObject, pyqtSignal, pyqtSlot
|
||||||
|
|
||||||
|
@ -18,6 +17,7 @@ from UM.Util import parseBool
|
||||||
|
|
||||||
from .MaterialNode import MaterialNode
|
from .MaterialNode import MaterialNode
|
||||||
from .MaterialGroup import MaterialGroup
|
from .MaterialGroup import MaterialGroup
|
||||||
|
from .VariantType import VariantType
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from UM.Settings.DefinitionContainer import DefinitionContainer
|
from UM.Settings.DefinitionContainer import DefinitionContainer
|
||||||
|
@ -47,7 +47,7 @@ class MaterialManager(QObject):
|
||||||
|
|
||||||
self._fallback_materials_map = dict() # material_type -> generic material metadata
|
self._fallback_materials_map = dict() # material_type -> generic material metadata
|
||||||
self._material_group_map = dict() # root_material_id -> MaterialGroup
|
self._material_group_map = dict() # root_material_id -> MaterialGroup
|
||||||
self._diameter_machine_variant_material_map = dict() # approximate diameter str -> dict(machine_definition_id -> MaterialNode)
|
self._diameter_machine_nozzle_buildplate_material_map = dict() # approximate diameter str -> dict(machine_definition_id -> MaterialNode)
|
||||||
|
|
||||||
# We're using these two maps to convert between the specific diameter material id and the generic material id
|
# We're using these two maps to convert between the specific diameter material id and the generic material id
|
||||||
# because the generic material ids are used in qualities and definitions, while the specific diameter material is meant
|
# because the generic material ids are used in qualities and definitions, while the specific diameter material is meant
|
||||||
|
@ -186,10 +186,11 @@ class MaterialManager(QObject):
|
||||||
for root_material_id in data_dict.values():
|
for root_material_id in data_dict.values():
|
||||||
self._diameter_material_map[root_material_id] = default_root_material_id
|
self._diameter_material_map[root_material_id] = default_root_material_id
|
||||||
|
|
||||||
|
variant_manager = self._application.getVariantManager()
|
||||||
|
|
||||||
# Map #4
|
# Map #4
|
||||||
# "machine" -> "variant_name" -> "root material ID" -> specific material InstanceContainer
|
# "machine" -> "nozzle name" -> "buildplate name" -> "root material ID" -> specific material InstanceContainer
|
||||||
# Construct the "machine" -> "variant" -> "root material ID" -> specific material InstanceContainer
|
self._diameter_machine_nozzle_buildplate_material_map = dict()
|
||||||
self._diameter_machine_variant_material_map = dict()
|
|
||||||
for material_metadata in material_metadatas.values():
|
for material_metadata in material_metadatas.values():
|
||||||
# We don't store empty material in the lookup tables
|
# We don't store empty material in the lookup tables
|
||||||
if material_metadata["id"] == "empty_material":
|
if material_metadata["id"] == "empty_material":
|
||||||
|
@ -199,36 +200,62 @@ class MaterialManager(QObject):
|
||||||
definition = material_metadata["definition"]
|
definition = material_metadata["definition"]
|
||||||
approximate_diameter = material_metadata["approximate_diameter"]
|
approximate_diameter = material_metadata["approximate_diameter"]
|
||||||
|
|
||||||
if approximate_diameter not in self._diameter_machine_variant_material_map:
|
if approximate_diameter not in self._diameter_machine_nozzle_buildplate_material_map:
|
||||||
self._diameter_machine_variant_material_map[approximate_diameter] = {}
|
self._diameter_machine_nozzle_buildplate_material_map[approximate_diameter] = {}
|
||||||
|
|
||||||
machine_variant_material_map = self._diameter_machine_variant_material_map[approximate_diameter]
|
machine_nozzle_buildplate_material_map = self._diameter_machine_nozzle_buildplate_material_map[approximate_diameter]
|
||||||
if definition not in machine_variant_material_map:
|
if definition not in machine_nozzle_buildplate_material_map:
|
||||||
machine_variant_material_map[definition] = MaterialNode()
|
machine_nozzle_buildplate_material_map[definition] = MaterialNode()
|
||||||
|
|
||||||
machine_node = machine_variant_material_map[definition]
|
machine_node = machine_nozzle_buildplate_material_map[definition]
|
||||||
variant_name = material_metadata.get("variant_name")
|
nozzle_name = material_metadata.get("variant_name")
|
||||||
if not variant_name:
|
buildplate_name = material_metadata.get("buildplate_name")
|
||||||
# if there is no variant, this material is for the machine, so put its metadata in the machine node.
|
if not nozzle_name:
|
||||||
|
# if there is no nozzle, this material is for the machine, so put its metadata in the machine node.
|
||||||
machine_node.material_map[root_material_id] = MaterialNode(material_metadata)
|
machine_node.material_map[root_material_id] = MaterialNode(material_metadata)
|
||||||
else:
|
else:
|
||||||
# this material is variant-specific, so we save it in a variant-specific node under the
|
# this material is nozzle-specific, so we save it in a nozzle-specific node under the
|
||||||
# machine-specific node
|
# machine-specific node
|
||||||
|
|
||||||
# Check first if the variant exist in the manager
|
# Check first if the nozzle exists in the manager
|
||||||
existing_variant = self._application.getVariantManager().getVariantNode(definition, variant_name)
|
existing_nozzle = variant_manager.getVariantNode(definition, nozzle_name, VariantType.NOZZLE)
|
||||||
if existing_variant is not None:
|
if existing_nozzle is not None:
|
||||||
if variant_name not in machine_node.children_map:
|
if nozzle_name not in machine_node.children_map:
|
||||||
machine_node.children_map[variant_name] = MaterialNode()
|
machine_node.children_map[nozzle_name] = MaterialNode()
|
||||||
|
|
||||||
|
nozzle_node = machine_node.children_map[nozzle_name]
|
||||||
|
|
||||||
|
# Check build plate node
|
||||||
|
if not buildplate_name:
|
||||||
|
# if there is no buildplate, this material is for the machine, so put its metadata in the machine node.
|
||||||
|
if root_material_id in nozzle_node.material_map: # We shouldn't have duplicated nozzle-specific materials for the same machine.
|
||||||
|
ConfigurationErrorMessage.getInstance().addFaultyContainers(root_material_id)
|
||||||
|
continue
|
||||||
|
nozzle_node.material_map[root_material_id] = MaterialNode(material_metadata)
|
||||||
|
else:
|
||||||
|
# this material is nozzle-and-buildplate-specific, so we save it in a buildplate-specific node
|
||||||
|
# under the machine-specific node
|
||||||
|
|
||||||
|
# Check first if the buildplate exists in the manager
|
||||||
|
existing_buildplate = variant_manager.getVariantNode(definition, buildplate_name, VariantType.BUILD_PLATE)
|
||||||
|
if existing_buildplate is not None:
|
||||||
|
if buildplate_name not in nozzle_node.children_map:
|
||||||
|
nozzle_node.children_map[buildplate_name] = MaterialNode()
|
||||||
|
|
||||||
|
buildplate_node = nozzle_node.children_map[buildplate_name]
|
||||||
|
if root_material_id in buildplate_node.material_map: # We shouldn't have duplicated nozzle-and-buildplate-specific materials for the same machine.
|
||||||
|
ConfigurationErrorMessage.getInstance().addFaultyContainers(root_material_id)
|
||||||
|
continue
|
||||||
|
buildplate_node.material_map[root_material_id] = MaterialNode(material_metadata)
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Add this container id to the wrong containers list in the registry
|
||||||
|
Logger.log("w", "Not adding {id} to the material manager because the buildplate does not exist.".format(id = material_metadata["id"]))
|
||||||
|
self._container_registry.addWrongContainerId(material_metadata["id"])
|
||||||
|
|
||||||
variant_node = machine_node.children_map[variant_name]
|
|
||||||
if root_material_id in variant_node.material_map: # We shouldn't have duplicated variant-specific materials for the same machine.
|
|
||||||
ConfigurationErrorMessage.getInstance().addFaultyContainers(root_material_id)
|
|
||||||
continue
|
|
||||||
variant_node.material_map[root_material_id] = MaterialNode(material_metadata)
|
|
||||||
else:
|
else:
|
||||||
# Add this container id to the wrong containers list in the registry
|
# Add this container id to the wrong containers list in the registry
|
||||||
Logger.log("w", "Not adding {id} to the material manager because the variant does not exist.".format(id = material_metadata["id"]))
|
Logger.log("w", "Not adding {id} to the material manager because the nozzle does not exist.".format(id = material_metadata["id"]))
|
||||||
self._container_registry.addWrongContainerId(material_metadata["id"])
|
self._container_registry.addWrongContainerId(material_metadata["id"])
|
||||||
|
|
||||||
self.materialsUpdated.emit()
|
self.materialsUpdated.emit()
|
||||||
|
@ -263,45 +290,52 @@ class MaterialManager(QObject):
|
||||||
#
|
#
|
||||||
# Return a dict with all root material IDs (k) and ContainerNodes (v) that's suitable for the given setup.
|
# Return a dict with all root material IDs (k) and ContainerNodes (v) that's suitable for the given setup.
|
||||||
#
|
#
|
||||||
def getAvailableMaterials(self, machine_definition: "DefinitionContainer", extruder_variant_name: Optional[str],
|
def getAvailableMaterials(self, machine_definition: "DefinitionContainer", extruder_nozzle_name: Optional[str],
|
||||||
diameter: float) -> Dict[str, MaterialNode]:
|
buildplate_name: Optional[str], diameter: float) -> Dict[str, MaterialNode]:
|
||||||
# round the diameter to get the approximate diameter
|
# round the diameter to get the approximate diameter
|
||||||
rounded_diameter = str(round(diameter))
|
rounded_diameter = str(round(diameter))
|
||||||
if rounded_diameter not in self._diameter_machine_variant_material_map:
|
if rounded_diameter not in self._diameter_machine_nozzle_buildplate_material_map:
|
||||||
Logger.log("i", "Cannot find materials with diameter [%s] (rounded to [%s])", diameter, rounded_diameter)
|
Logger.log("i", "Cannot find materials with diameter [%s] (rounded to [%s])", diameter, rounded_diameter)
|
||||||
return dict()
|
return dict()
|
||||||
|
|
||||||
machine_definition_id = machine_definition.getId()
|
machine_definition_id = machine_definition.getId()
|
||||||
|
|
||||||
# If there are variant materials, get the variant material
|
# If there are nozzle-and-or-buildplate materials, get the nozzle-and-or-buildplate material
|
||||||
machine_variant_material_map = self._diameter_machine_variant_material_map[rounded_diameter]
|
machine_nozzle_buildplate_material_map = self._diameter_machine_nozzle_buildplate_material_map[rounded_diameter]
|
||||||
machine_node = machine_variant_material_map.get(machine_definition_id)
|
machine_node = machine_nozzle_buildplate_material_map.get(machine_definition_id)
|
||||||
default_machine_node = machine_variant_material_map.get(self._default_machine_definition_id)
|
default_machine_node = machine_nozzle_buildplate_material_map.get(self._default_machine_definition_id)
|
||||||
variant_node = None
|
nozzle_node = None
|
||||||
if extruder_variant_name is not None and machine_node is not None:
|
buildplate_node = None
|
||||||
variant_node = machine_node.getChildNode(extruder_variant_name)
|
if extruder_nozzle_name is not None and machine_node is not None:
|
||||||
|
nozzle_node = machine_node.getChildNode(extruder_nozzle_name)
|
||||||
|
# Get buildplate node if possible
|
||||||
|
if nozzle_node is not None and buildplate_name is not None:
|
||||||
|
buildplate_node = nozzle_node.getChildNode(buildplate_name)
|
||||||
|
|
||||||
nodes_to_check = [variant_node, machine_node, default_machine_node]
|
nodes_to_check = [buildplate_node, nozzle_node, machine_node, default_machine_node]
|
||||||
|
|
||||||
# Fallback mechanism of finding materials:
|
# Fallback mechanism of finding materials:
|
||||||
# 1. variant-specific material
|
# 1. buildplate-specific material
|
||||||
# 2. machine-specific material
|
# 2. nozzle-specific material
|
||||||
# 3. generic material (for fdmprinter)
|
# 3. machine-specific material
|
||||||
|
# 4. generic material (for fdmprinter)
|
||||||
machine_exclude_materials = machine_definition.getMetaDataEntry("exclude_materials", [])
|
machine_exclude_materials = machine_definition.getMetaDataEntry("exclude_materials", [])
|
||||||
|
|
||||||
material_id_metadata_dict = dict() # type: Dict[str, MaterialNode]
|
material_id_metadata_dict = dict() # type: Dict[str, MaterialNode]
|
||||||
for node in nodes_to_check:
|
for current_node in nodes_to_check:
|
||||||
if node is not None:
|
if current_node is None:
|
||||||
# Only exclude the materials that are explicitly specified in the "exclude_materials" field.
|
continue
|
||||||
# Do not exclude other materials that are of the same type.
|
|
||||||
for material_id, node in node.material_map.items():
|
|
||||||
if material_id in machine_exclude_materials:
|
|
||||||
Logger.log("d", "Exclude material [%s] for machine [%s]",
|
|
||||||
material_id, machine_definition.getId())
|
|
||||||
continue
|
|
||||||
|
|
||||||
if material_id not in material_id_metadata_dict:
|
# Only exclude the materials that are explicitly specified in the "exclude_materials" field.
|
||||||
material_id_metadata_dict[material_id] = node
|
# Do not exclude other materials that are of the same type.
|
||||||
|
for material_id, node in current_node.material_map.items():
|
||||||
|
if material_id in machine_exclude_materials:
|
||||||
|
Logger.log("d", "Exclude material [%s] for machine [%s]",
|
||||||
|
material_id, machine_definition.getId())
|
||||||
|
continue
|
||||||
|
|
||||||
|
if material_id not in material_id_metadata_dict:
|
||||||
|
material_id_metadata_dict[material_id] = node
|
||||||
|
|
||||||
return material_id_metadata_dict
|
return material_id_metadata_dict
|
||||||
|
|
||||||
|
@ -310,13 +344,14 @@ class MaterialManager(QObject):
|
||||||
#
|
#
|
||||||
def getAvailableMaterialsForMachineExtruder(self, machine: "GlobalStack",
|
def getAvailableMaterialsForMachineExtruder(self, machine: "GlobalStack",
|
||||||
extruder_stack: "ExtruderStack") -> Optional[dict]:
|
extruder_stack: "ExtruderStack") -> Optional[dict]:
|
||||||
variant_name = None
|
buildplate_name = machine.getBuildplateName()
|
||||||
|
nozzle_name = None
|
||||||
if extruder_stack.variant.getId() != "empty_variant":
|
if extruder_stack.variant.getId() != "empty_variant":
|
||||||
variant_name = extruder_stack.variant.getName()
|
nozzle_name = extruder_stack.variant.getName()
|
||||||
diameter = extruder_stack.approximateMaterialDiameter
|
diameter = extruder_stack.approximateMaterialDiameter
|
||||||
|
|
||||||
# Fetch the available materials (ContainerNode) for the current active machine and extruder setup.
|
# Fetch the available materials (ContainerNode) for the current active machine and extruder setup.
|
||||||
return self.getAvailableMaterials(machine.definition, variant_name, diameter)
|
return self.getAvailableMaterials(machine.definition, nozzle_name, buildplate_name, diameter)
|
||||||
|
|
||||||
#
|
#
|
||||||
# Gets MaterialNode for the given extruder and machine with the given material name.
|
# Gets MaterialNode for the given extruder and machine with the given material name.
|
||||||
|
@ -324,32 +359,36 @@ class MaterialManager(QObject):
|
||||||
# 1. the given machine doesn't have materials;
|
# 1. the given machine doesn't have materials;
|
||||||
# 2. cannot find any material InstanceContainers with the given settings.
|
# 2. cannot find any material InstanceContainers with the given settings.
|
||||||
#
|
#
|
||||||
def getMaterialNode(self, machine_definition_id: str, extruder_variant_name: Optional[str],
|
def getMaterialNode(self, machine_definition_id: str, nozzle_name: Optional[str],
|
||||||
diameter: float, root_material_id: str) -> Optional["InstanceContainer"]:
|
buildplate_name: Optional[str], diameter: float, root_material_id: str) -> Optional["InstanceContainer"]:
|
||||||
# round the diameter to get the approximate diameter
|
# round the diameter to get the approximate diameter
|
||||||
rounded_diameter = str(round(diameter))
|
rounded_diameter = str(round(diameter))
|
||||||
if rounded_diameter not in self._diameter_machine_variant_material_map:
|
if rounded_diameter not in self._diameter_machine_nozzle_buildplate_material_map:
|
||||||
Logger.log("i", "Cannot find materials with diameter [%s] (rounded to [%s]) for root material id [%s]",
|
Logger.log("i", "Cannot find materials with diameter [%s] (rounded to [%s]) for root material id [%s]",
|
||||||
diameter, rounded_diameter, root_material_id)
|
diameter, rounded_diameter, root_material_id)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# If there are variant materials, get the variant material
|
# If there are nozzle materials, get the nozzle-specific material
|
||||||
machine_variant_material_map = self._diameter_machine_variant_material_map[rounded_diameter]
|
machine_nozzle_buildplate_material_map = self._diameter_machine_nozzle_buildplate_material_map[rounded_diameter]
|
||||||
machine_node = machine_variant_material_map.get(machine_definition_id)
|
machine_node = machine_nozzle_buildplate_material_map.get(machine_definition_id)
|
||||||
variant_node = None
|
nozzle_node = None
|
||||||
|
buildplate_node = None
|
||||||
|
|
||||||
# Fallback for "fdmprinter" if the machine-specific materials cannot be found
|
# Fallback for "fdmprinter" if the machine-specific materials cannot be found
|
||||||
if machine_node is None:
|
if machine_node is None:
|
||||||
machine_node = machine_variant_material_map.get(self._default_machine_definition_id)
|
machine_node = machine_nozzle_buildplate_material_map.get(self._default_machine_definition_id)
|
||||||
if machine_node is not None and extruder_variant_name is not None:
|
if machine_node is not None and nozzle_name is not None:
|
||||||
variant_node = machine_node.getChildNode(extruder_variant_name)
|
nozzle_node = machine_node.getChildNode(nozzle_name)
|
||||||
|
if nozzle_node is not None and buildplate_name is not None:
|
||||||
|
buildplate_node = nozzle_node.getChildNode(buildplate_name)
|
||||||
|
|
||||||
# Fallback mechanism of finding materials:
|
# Fallback mechanism of finding materials:
|
||||||
# 1. variant-specific material
|
# 1. buildplate-specific material
|
||||||
# 2. machine-specific material
|
# 2. nozzle-specific material
|
||||||
# 3. generic material (for fdmprinter)
|
# 3. machine-specific material
|
||||||
nodes_to_check = [variant_node, machine_node,
|
# 4. generic material (for fdmprinter)
|
||||||
machine_variant_material_map.get(self._default_machine_definition_id)]
|
nodes_to_check = [buildplate_node, nozzle_node, machine_node,
|
||||||
|
machine_nozzle_buildplate_material_map.get(self._default_machine_definition_id)]
|
||||||
|
|
||||||
material_node = None
|
material_node = None
|
||||||
for node in nodes_to_check:
|
for node in nodes_to_check:
|
||||||
|
@ -366,7 +405,8 @@ class MaterialManager(QObject):
|
||||||
# 1. the given machine doesn't have materials;
|
# 1. the given machine doesn't have materials;
|
||||||
# 2. cannot find any material InstanceContainers with the given settings.
|
# 2. cannot find any material InstanceContainers with the given settings.
|
||||||
#
|
#
|
||||||
def getMaterialNodeByType(self, global_stack: "GlobalStack", position: str, extruder_variant_name: str, material_guid: str) -> Optional["MaterialNode"]:
|
def getMaterialNodeByType(self, global_stack: "GlobalStack", position: str, nozzle_name: str,
|
||||||
|
buildplate_name: Optional[str], material_guid: str) -> Optional["MaterialNode"]:
|
||||||
node = None
|
node = None
|
||||||
machine_definition = global_stack.definition
|
machine_definition = global_stack.definition
|
||||||
extruder_definition = global_stack.extruders[position].definition
|
extruder_definition = global_stack.extruders[position].definition
|
||||||
|
@ -385,7 +425,7 @@ class MaterialManager(QObject):
|
||||||
Logger.log("i", "Cannot find materials with guid [%s] ", material_guid)
|
Logger.log("i", "Cannot find materials with guid [%s] ", material_guid)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
node = self.getMaterialNode(machine_definition.getId(), extruder_variant_name,
|
node = self.getMaterialNode(machine_definition.getId(), nozzle_name, buildplate_name,
|
||||||
material_diameter, root_material_id)
|
material_diameter, root_material_id)
|
||||||
return node
|
return node
|
||||||
|
|
||||||
|
@ -413,13 +453,17 @@ class MaterialManager(QObject):
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
## Get default material for given global stack, extruder position and extruder variant name
|
## Get default material for given global stack, extruder position and extruder nozzle name
|
||||||
# you can provide the extruder_definition and then the position is ignored (useful when building up global stack in CuraStackBuilder)
|
# you can provide the extruder_definition and then the position is ignored (useful when building up global stack in CuraStackBuilder)
|
||||||
def getDefaultMaterial(self, global_stack: "GlobalStack", position: str, extruder_variant_name: Optional[str], extruder_definition: Optional["DefinitionContainer"] = None) -> Optional["MaterialNode"]:
|
def getDefaultMaterial(self, global_stack: "GlobalStack", position: str, nozzle_name: Optional[str],
|
||||||
|
extruder_definition: Optional["DefinitionContainer"] = None) -> Optional["MaterialNode"]:
|
||||||
node = None
|
node = None
|
||||||
|
|
||||||
|
buildplate_name = global_stack.getBuildplateName()
|
||||||
machine_definition = global_stack.definition
|
machine_definition = global_stack.definition
|
||||||
if extruder_definition is None:
|
if extruder_definition is None:
|
||||||
extruder_definition = global_stack.extruders[position].definition
|
extruder_definition = global_stack.extruders[position].definition
|
||||||
|
|
||||||
if extruder_definition and parseBool(global_stack.getMetaDataEntry("has_materials", False)):
|
if extruder_definition and parseBool(global_stack.getMetaDataEntry("has_materials", False)):
|
||||||
# At this point the extruder_definition is not None
|
# At this point the extruder_definition is not None
|
||||||
material_diameter = extruder_definition.getProperty("material_diameter", "value")
|
material_diameter = extruder_definition.getProperty("material_diameter", "value")
|
||||||
|
@ -428,7 +472,7 @@ class MaterialManager(QObject):
|
||||||
approximate_material_diameter = str(round(material_diameter))
|
approximate_material_diameter = str(round(material_diameter))
|
||||||
root_material_id = machine_definition.getMetaDataEntry("preferred_material")
|
root_material_id = machine_definition.getMetaDataEntry("preferred_material")
|
||||||
root_material_id = self.getRootMaterialIDForDiameter(root_material_id, approximate_material_diameter)
|
root_material_id = self.getRootMaterialIDForDiameter(root_material_id, approximate_material_diameter)
|
||||||
node = self.getMaterialNode(machine_definition.getId(), extruder_variant_name,
|
node = self.getMaterialNode(machine_definition.getId(), nozzle_name, buildplate_name,
|
||||||
material_diameter, root_material_id)
|
material_diameter, root_material_id)
|
||||||
return node
|
return node
|
||||||
|
|
||||||
|
@ -515,8 +559,8 @@ class MaterialManager(QObject):
|
||||||
if container_to_copy.getMetaDataEntry("definition") != "fdmprinter":
|
if container_to_copy.getMetaDataEntry("definition") != "fdmprinter":
|
||||||
new_id += "_" + container_to_copy.getMetaDataEntry("definition")
|
new_id += "_" + container_to_copy.getMetaDataEntry("definition")
|
||||||
if container_to_copy.getMetaDataEntry("variant_name"):
|
if container_to_copy.getMetaDataEntry("variant_name"):
|
||||||
variant_name = container_to_copy.getMetaDataEntry("variant_name")
|
nozzle_name = container_to_copy.getMetaDataEntry("variant_name")
|
||||||
new_id += "_" + variant_name.replace(" ", "_")
|
new_id += "_" + nozzle_name.replace(" ", "_")
|
||||||
|
|
||||||
new_container = copy.deepcopy(container_to_copy)
|
new_container = copy.deepcopy(container_to_copy)
|
||||||
new_container.getMetaData()["id"] = new_id
|
new_container.getMetaData()["id"] = new_id
|
||||||
|
|
|
@ -45,7 +45,7 @@ class QualityManager(QObject):
|
||||||
self._empty_quality_container = self._application.empty_quality_container
|
self._empty_quality_container = self._application.empty_quality_container
|
||||||
self._empty_quality_changes_container = self._application.empty_quality_changes_container
|
self._empty_quality_changes_container = self._application.empty_quality_changes_container
|
||||||
|
|
||||||
self._machine_variant_material_quality_type_to_quality_dict = {} # for quality lookup
|
self._machine_nozzle_buildplate_material_quality_type_to_quality_dict = {} # for quality lookup
|
||||||
self._machine_quality_type_to_quality_changes_dict = {} # for quality_changes lookup
|
self._machine_quality_type_to_quality_changes_dict = {} # for quality_changes lookup
|
||||||
|
|
||||||
self._default_machine_definition_id = "fdmprinter"
|
self._default_machine_definition_id = "fdmprinter"
|
||||||
|
@ -64,10 +64,10 @@ class QualityManager(QObject):
|
||||||
|
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
# Initialize the lookup tree for quality profiles with following structure:
|
# Initialize the lookup tree for quality profiles with following structure:
|
||||||
# <machine> -> <variant> -> <material>
|
# <machine> -> <nozzle> -> <buildplate> -> <material>
|
||||||
# -> <material>
|
# <machine> -> <material>
|
||||||
|
|
||||||
self._machine_variant_material_quality_type_to_quality_dict = {} # for quality lookup
|
self._machine_nozzle_buildplate_material_quality_type_to_quality_dict = {} # for quality lookup
|
||||||
self._machine_quality_type_to_quality_changes_dict = {} # for quality_changes lookup
|
self._machine_quality_type_to_quality_changes_dict = {} # for quality_changes lookup
|
||||||
|
|
||||||
quality_metadata_list = self._container_registry.findContainersMetadata(type = "quality")
|
quality_metadata_list = self._container_registry.findContainersMetadata(type = "quality")
|
||||||
|
@ -79,47 +79,58 @@ class QualityManager(QObject):
|
||||||
quality_type = metadata["quality_type"]
|
quality_type = metadata["quality_type"]
|
||||||
|
|
||||||
root_material_id = metadata.get("material")
|
root_material_id = metadata.get("material")
|
||||||
variant_name = metadata.get("variant")
|
nozzle_name = metadata.get("variant")
|
||||||
|
buildplate_name = metadata.get("buildplate")
|
||||||
is_global_quality = metadata.get("global_quality", False)
|
is_global_quality = metadata.get("global_quality", False)
|
||||||
is_global_quality = is_global_quality or (root_material_id is None and variant_name is None)
|
is_global_quality = is_global_quality or (root_material_id is None and nozzle_name is None and buildplate_name is None)
|
||||||
|
|
||||||
# Sanity check: material+variant and is_global_quality cannot be present at the same time
|
# Sanity check: material+variant and is_global_quality cannot be present at the same time
|
||||||
if is_global_quality and (root_material_id or variant_name):
|
if is_global_quality and (root_material_id or nozzle_name):
|
||||||
ConfigurationErrorMessage.getInstance().addFaultyContainers(metadata["id"])
|
ConfigurationErrorMessage.getInstance().addFaultyContainers(metadata["id"])
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if definition_id not in self._machine_variant_material_quality_type_to_quality_dict:
|
if definition_id not in self._machine_nozzle_buildplate_material_quality_type_to_quality_dict:
|
||||||
self._machine_variant_material_quality_type_to_quality_dict[definition_id] = QualityNode()
|
self._machine_nozzle_buildplate_material_quality_type_to_quality_dict[definition_id] = QualityNode()
|
||||||
machine_node = cast(QualityNode, self._machine_variant_material_quality_type_to_quality_dict[definition_id])
|
machine_node = cast(QualityNode, self._machine_nozzle_buildplate_material_quality_type_to_quality_dict[definition_id])
|
||||||
|
|
||||||
if is_global_quality:
|
if is_global_quality:
|
||||||
# For global qualities, save data in the machine node
|
# For global qualities, save data in the machine node
|
||||||
machine_node.addQualityMetadata(quality_type, metadata)
|
machine_node.addQualityMetadata(quality_type, metadata)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if variant_name is not None:
|
# Check if nozzle si specified
|
||||||
# If variant_name is specified in the quality/quality_changes profile, check if material is specified,
|
if nozzle_name is not None:
|
||||||
# too.
|
if nozzle_name not in machine_node.children_map:
|
||||||
if variant_name not in machine_node.children_map:
|
machine_node.children_map[nozzle_name] = QualityNode()
|
||||||
machine_node.children_map[variant_name] = QualityNode()
|
nozzle_node = cast(QualityNode, machine_node.children_map[nozzle_name])
|
||||||
variant_node = cast(QualityNode, machine_node.children_map[variant_name])
|
|
||||||
|
# Check if buildplate is specified
|
||||||
|
if buildplate_name is not None:
|
||||||
|
if buildplate_name not in nozzle_node.children_map:
|
||||||
|
nozzle_node.children_map[buildplate_name] = QualityNode()
|
||||||
|
buildplate_node = cast(QualityNode, nozzle_node.children_map[buildplate_name])
|
||||||
|
|
||||||
|
if root_material_id is None:
|
||||||
|
buildplate_node.addQualityMetadata(quality_type, metadata)
|
||||||
|
else:
|
||||||
|
if root_material_id not in buildplate_node.children_map:
|
||||||
|
buildplate_node.children_map[root_material_id] = QualityNode()
|
||||||
|
material_node = cast(QualityNode, buildplate_node.children_map[root_material_id])
|
||||||
|
|
||||||
|
material_node.addQualityMetadata(quality_type, metadata)
|
||||||
|
|
||||||
if root_material_id is None:
|
|
||||||
# If only variant_name is specified but material is not, add the quality/quality_changes metadata
|
|
||||||
# into the current variant node.
|
|
||||||
variant_node.addQualityMetadata(quality_type, metadata)
|
|
||||||
else:
|
else:
|
||||||
# If only variant_name and material are both specified, go one level deeper: create a material node
|
if root_material_id is None:
|
||||||
# under the current variant node, and then add the quality/quality_changes metadata into the
|
nozzle_node.addQualityMetadata(quality_type, metadata)
|
||||||
# material node.
|
else:
|
||||||
if root_material_id not in variant_node.children_map:
|
if root_material_id not in nozzle_node.children_map:
|
||||||
variant_node.children_map[root_material_id] = QualityNode()
|
nozzle_node.children_map[root_material_id] = QualityNode()
|
||||||
material_node = cast(QualityNode, variant_node.children_map[root_material_id])
|
material_node = cast(QualityNode, nozzle_node.children_map[root_material_id])
|
||||||
|
|
||||||
material_node.addQualityMetadata(quality_type, metadata)
|
material_node.addQualityMetadata(quality_type, metadata)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# If variant_name is not specified, check if material is specified.
|
# If nozzle is not specified, check if material is specified.
|
||||||
if root_material_id is not None:
|
if root_material_id is not None:
|
||||||
if root_material_id not in machine_node.children_map:
|
if root_material_id not in machine_node.children_map:
|
||||||
machine_node.children_map[root_material_id] = QualityNode()
|
machine_node.children_map[root_material_id] = QualityNode()
|
||||||
|
@ -217,8 +228,8 @@ class QualityManager(QObject):
|
||||||
# To find the quality container for the GlobalStack, check in the following fall-back manner:
|
# To find the quality container for the GlobalStack, check in the following fall-back manner:
|
||||||
# (1) the machine-specific node
|
# (1) the machine-specific node
|
||||||
# (2) the generic node
|
# (2) the generic node
|
||||||
machine_node = self._machine_variant_material_quality_type_to_quality_dict.get(machine_definition_id)
|
machine_node = self._machine_nozzle_buildplate_material_quality_type_to_quality_dict.get(machine_definition_id)
|
||||||
default_machine_node = self._machine_variant_material_quality_type_to_quality_dict.get(self._default_machine_definition_id)
|
default_machine_node = self._machine_nozzle_buildplate_material_quality_type_to_quality_dict.get(self._default_machine_definition_id)
|
||||||
nodes_to_check = [machine_node, default_machine_node]
|
nodes_to_check = [machine_node, default_machine_node]
|
||||||
|
|
||||||
# Iterate over all quality_types in the machine node
|
# Iterate over all quality_types in the machine node
|
||||||
|
@ -238,11 +249,13 @@ class QualityManager(QObject):
|
||||||
quality_group_dict[quality_type] = quality_group
|
quality_group_dict[quality_type] = quality_group
|
||||||
break
|
break
|
||||||
|
|
||||||
|
buildplate_name = machine.getBuildplateName()
|
||||||
|
|
||||||
# Iterate over all extruders to find quality containers for each extruder
|
# Iterate over all extruders to find quality containers for each extruder
|
||||||
for position, extruder in machine.extruders.items():
|
for position, extruder in machine.extruders.items():
|
||||||
variant_name = None
|
nozzle_name = None
|
||||||
if extruder.variant.getId() != "empty_variant":
|
if extruder.variant.getId() != "empty_variant":
|
||||||
variant_name = extruder.variant.getName()
|
nozzle_name = extruder.variant.getName()
|
||||||
|
|
||||||
# This is a list of root material IDs to use for searching for suitable quality profiles.
|
# This is a list of root material IDs to use for searching for suitable quality profiles.
|
||||||
# The root material IDs in this list are in prioritized order.
|
# The root material IDs in this list are in prioritized order.
|
||||||
|
@ -258,34 +271,47 @@ class QualityManager(QObject):
|
||||||
# Also try to get the fallback material
|
# Also try to get the fallback material
|
||||||
material_type = extruder.material.getMetaDataEntry("material")
|
material_type = extruder.material.getMetaDataEntry("material")
|
||||||
fallback_root_material_id = self._material_manager.getFallbackMaterialIdByMaterialType(material_type)
|
fallback_root_material_id = self._material_manager.getFallbackMaterialIdByMaterialType(material_type)
|
||||||
if fallback_root_material_id:
|
if fallback_root_material_id and root_material_id not in root_material_id_list:
|
||||||
root_material_id_list.append(fallback_root_material_id)
|
root_material_id_list.append(fallback_root_material_id)
|
||||||
|
|
||||||
# Here we construct a list of nodes we want to look for qualities with the highest priority first.
|
# Here we construct a list of nodes we want to look for qualities with the highest priority first.
|
||||||
# The use case is that, when we look for qualities for a machine, we first want to search in the following
|
# The use case is that, when we look for qualities for a machine, we first want to search in the following
|
||||||
# order:
|
# order:
|
||||||
# 1. machine-variant-and-material-specific qualities if exist
|
# 1. machine-nozzle-buildplate-and-material-specific qualities if exist
|
||||||
# 2. machine-variant-specific qualities if exist
|
# 2. machine-nozzle-and-material-specific qualities if exist
|
||||||
# 3. machine-material-specific qualities if exist
|
# 3. machine-nozzle-specific qualities if exist
|
||||||
# 4. machine-specific qualities if exist
|
# 4. machine-material-specific qualities if exist
|
||||||
# 5. generic qualities if exist
|
# 5. machine-specific qualities if exist
|
||||||
|
# 6. generic qualities if exist
|
||||||
# Each points above can be represented as a node in the lookup tree, so here we simply put those nodes into
|
# Each points above can be represented as a node in the lookup tree, so here we simply put those nodes into
|
||||||
# the list with priorities as the order. Later, we just need to loop over each node in this list and fetch
|
# the list with priorities as the order. Later, we just need to loop over each node in this list and fetch
|
||||||
# qualities from there.
|
# qualities from there.
|
||||||
nodes_to_check = []
|
nodes_to_check = []
|
||||||
|
|
||||||
if variant_name:
|
if nozzle_name:
|
||||||
# In this case, we have both a specific variant and a specific material
|
# In this case, we have both a specific nozzle and a specific material
|
||||||
variant_node = machine_node.getChildNode(variant_name)
|
nozzle_node = machine_node.getChildNode(nozzle_name)
|
||||||
if variant_node and has_material:
|
if nozzle_node and has_material:
|
||||||
|
# Check build plate if exists
|
||||||
|
if buildplate_name:
|
||||||
|
buildplate_node = nozzle_node.getChildNode(buildplate_name)
|
||||||
|
if buildplate_node and has_material:
|
||||||
|
for root_material_id in root_material_id_list:
|
||||||
|
material_node = buildplate_node.getChildNode(root_material_id)
|
||||||
|
if material_node:
|
||||||
|
nodes_to_check.append(material_node)
|
||||||
|
break
|
||||||
|
nodes_to_check.append(buildplate_node)
|
||||||
|
|
||||||
|
# Then add nozzle specific materials
|
||||||
for root_material_id in root_material_id_list:
|
for root_material_id in root_material_id_list:
|
||||||
material_node = variant_node.getChildNode(root_material_id)
|
material_node = nozzle_node.getChildNode(root_material_id)
|
||||||
if material_node:
|
if material_node:
|
||||||
nodes_to_check.append(material_node)
|
nodes_to_check.append(material_node)
|
||||||
break
|
break
|
||||||
nodes_to_check.append(variant_node)
|
nodes_to_check.append(nozzle_node)
|
||||||
|
|
||||||
# In this case, we only have a specific material but NOT a variant
|
# In this case, we only have a specific material but NOT a nozzle
|
||||||
if has_material:
|
if has_material:
|
||||||
for root_material_id in root_material_id_list:
|
for root_material_id in root_material_id_list:
|
||||||
material_node = machine_node.getChildNode(root_material_id)
|
material_node = machine_node.getChildNode(root_material_id)
|
||||||
|
@ -309,8 +335,9 @@ class QualityManager(QObject):
|
||||||
quality_group_dict[quality_type] = quality_group
|
quality_group_dict[quality_type] = quality_group
|
||||||
|
|
||||||
quality_group = quality_group_dict[quality_type]
|
quality_group = quality_group_dict[quality_type]
|
||||||
quality_group.nodes_for_extruders[position] = quality_node
|
if position not in quality_group.nodes_for_extruders:
|
||||||
break
|
quality_group.nodes_for_extruders[position] = quality_node
|
||||||
|
#break
|
||||||
|
|
||||||
# Update availabilities for each quality group
|
# Update availabilities for each quality group
|
||||||
self._updateQualityGroupsAvailability(machine, quality_group_dict.values())
|
self._updateQualityGroupsAvailability(machine, quality_group_dict.values())
|
||||||
|
@ -323,8 +350,8 @@ class QualityManager(QObject):
|
||||||
# To find the quality container for the GlobalStack, check in the following fall-back manner:
|
# To find the quality container for the GlobalStack, check in the following fall-back manner:
|
||||||
# (1) the machine-specific node
|
# (1) the machine-specific node
|
||||||
# (2) the generic node
|
# (2) the generic node
|
||||||
machine_node = self._machine_variant_material_quality_type_to_quality_dict.get(machine_definition_id)
|
machine_node = self._machine_nozzle_buildplate_material_quality_type_to_quality_dict.get(machine_definition_id)
|
||||||
default_machine_node = self._machine_variant_material_quality_type_to_quality_dict.get(
|
default_machine_node = self._machine_nozzle_buildplate_material_quality_type_to_quality_dict.get(
|
||||||
self._default_machine_definition_id)
|
self._default_machine_definition_id)
|
||||||
nodes_to_check = [machine_node, default_machine_node]
|
nodes_to_check = [machine_node, default_machine_node]
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,12 @@ class GlobalStack(CuraContainerStack):
|
||||||
return "machine_stack"
|
return "machine_stack"
|
||||||
return configuration_type
|
return configuration_type
|
||||||
|
|
||||||
|
def getBuildplateName(self) -> Optional[str]:
|
||||||
|
name = None
|
||||||
|
if self.variant.getId() != "empty_variant":
|
||||||
|
name = self.variant.getName()
|
||||||
|
return name
|
||||||
|
|
||||||
## Add an extruder to the list of extruders of this stack.
|
## Add an extruder to the list of extruders of this stack.
|
||||||
#
|
#
|
||||||
# \param extruder The extruder to add.
|
# \param extruder The extruder to add.
|
||||||
|
|
|
@ -1256,13 +1256,17 @@ class MachineManager(QObject):
|
||||||
else:
|
else:
|
||||||
position_list = [position]
|
position_list = [position]
|
||||||
|
|
||||||
|
buildplate_name = None
|
||||||
|
if self._global_container_stack.variant.getId() != "empty_variant":
|
||||||
|
buildplate_name = self._global_container_stack.variant.getName()
|
||||||
|
|
||||||
for position_item in position_list:
|
for position_item in position_list:
|
||||||
extruder = self._global_container_stack.extruders[position_item]
|
extruder = self._global_container_stack.extruders[position_item]
|
||||||
|
|
||||||
current_material_base_name = extruder.material.getMetaDataEntry("base_file")
|
current_material_base_name = extruder.material.getMetaDataEntry("base_file")
|
||||||
current_variant_name = None
|
current_nozzle_name = None
|
||||||
if extruder.variant.getId() != self._empty_variant_container.getId():
|
if extruder.variant.getId() != self._empty_variant_container.getId():
|
||||||
current_variant_name = extruder.variant.getMetaDataEntry("name")
|
current_nozzle_name = extruder.variant.getMetaDataEntry("name")
|
||||||
|
|
||||||
from UM.Settings.Interfaces import PropertyEvaluationContext
|
from UM.Settings.Interfaces import PropertyEvaluationContext
|
||||||
from cura.Settings.CuraContainerStack import _ContainerIndexes
|
from cura.Settings.CuraContainerStack import _ContainerIndexes
|
||||||
|
@ -1271,7 +1275,8 @@ class MachineManager(QObject):
|
||||||
material_diameter = extruder.getProperty("material_diameter", "value", context)
|
material_diameter = extruder.getProperty("material_diameter", "value", context)
|
||||||
candidate_materials = self._material_manager.getAvailableMaterials(
|
candidate_materials = self._material_manager.getAvailableMaterials(
|
||||||
self._global_container_stack.definition,
|
self._global_container_stack.definition,
|
||||||
current_variant_name,
|
current_nozzle_name,
|
||||||
|
buildplate_name,
|
||||||
material_diameter)
|
material_diameter)
|
||||||
|
|
||||||
if not candidate_materials:
|
if not candidate_materials:
|
||||||
|
@ -1284,7 +1289,7 @@ class MachineManager(QObject):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# The current material is not available, find the preferred one
|
# The current material is not available, find the preferred one
|
||||||
material_node = self._material_manager.getDefaultMaterial(self._global_container_stack, position_item, current_variant_name)
|
material_node = self._material_manager.getDefaultMaterial(self._global_container_stack, position_item, current_nozzle_name)
|
||||||
if material_node is not None:
|
if material_node is not None:
|
||||||
self._setMaterial(position_item, material_node)
|
self._setMaterial(position_item, material_node)
|
||||||
|
|
||||||
|
@ -1389,12 +1394,17 @@ class MachineManager(QObject):
|
||||||
def setMaterialById(self, position: str, root_material_id: str) -> None:
|
def setMaterialById(self, position: str, root_material_id: str) -> None:
|
||||||
if self._global_container_stack is None:
|
if self._global_container_stack is None:
|
||||||
return
|
return
|
||||||
|
buildplate_name = None
|
||||||
|
if self._global_container_stack.variant.getId() != "empty_variant":
|
||||||
|
buildplate_name = self._global_container_stack.variant.getName()
|
||||||
|
|
||||||
machine_definition_id = self._global_container_stack.definition.id
|
machine_definition_id = self._global_container_stack.definition.id
|
||||||
position = str(position)
|
position = str(position)
|
||||||
extruder_stack = self._global_container_stack.extruders[position]
|
extruder_stack = self._global_container_stack.extruders[position]
|
||||||
variant_name = extruder_stack.variant.getName()
|
nozzle_name = extruder_stack.variant.getName()
|
||||||
material_diameter = extruder_stack.approximateMaterialDiameter
|
material_diameter = extruder_stack.approximateMaterialDiameter
|
||||||
material_node = self._material_manager.getMaterialNode(machine_definition_id, variant_name, material_diameter, root_material_id)
|
material_node = self._material_manager.getMaterialNode(machine_definition_id, nozzle_name, buildplate_name,
|
||||||
|
material_diameter, root_material_id)
|
||||||
self.setMaterial(position, material_node)
|
self.setMaterial(position, material_node)
|
||||||
|
|
||||||
## global_stack: if you want to provide your own global_stack instead of the current active one
|
## global_stack: if you want to provide your own global_stack instead of the current active one
|
||||||
|
|
|
@ -6,19 +6,17 @@ import io
|
||||||
import json #To parse the product-to-id mapping file.
|
import json #To parse the product-to-id mapping file.
|
||||||
import os.path #To find the product-to-id mapping.
|
import os.path #To find the product-to-id mapping.
|
||||||
import sys
|
import sys
|
||||||
from typing import Any, Dict, List, Optional, cast
|
from typing import Any, Dict, List, Optional, Tuple, cast
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
from typing import Dict
|
|
||||||
from typing import Iterator
|
|
||||||
|
|
||||||
from UM.Resources import Resources
|
from UM.Resources import Resources
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
from cura.CuraApplication import CuraApplication
|
|
||||||
import UM.Dictionary
|
import UM.Dictionary
|
||||||
from UM.Settings.InstanceContainer import InstanceContainer
|
from UM.Settings.InstanceContainer import InstanceContainer
|
||||||
from UM.Settings.ContainerRegistry import ContainerRegistry
|
from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||||
from UM.ConfigurationErrorMessage import ConfigurationErrorMessage
|
from UM.ConfigurationErrorMessage import ConfigurationErrorMessage
|
||||||
|
|
||||||
|
from cura.CuraApplication import CuraApplication
|
||||||
from cura.Machines.VariantType import VariantType
|
from cura.Machines.VariantType import VariantType
|
||||||
|
|
||||||
from .XmlMaterialValidator import XmlMaterialValidator
|
from .XmlMaterialValidator import XmlMaterialValidator
|
||||||
|
@ -695,74 +693,38 @@ class XmlMaterialProfile(InstanceContainer):
|
||||||
if buildplate_id is None:
|
if buildplate_id is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
from cura.Machines.VariantManager import VariantType
|
|
||||||
variant_manager = CuraApplication.getInstance().getVariantManager()
|
variant_manager = CuraApplication.getInstance().getVariantManager()
|
||||||
variant_node = variant_manager.getVariantNode(machine_id, buildplate_id,
|
variant_node = variant_manager.getVariantNode(machine_id, buildplate_id,
|
||||||
variant_type = VariantType.BUILD_PLATE)
|
variant_type = VariantType.BUILD_PLATE)
|
||||||
if not variant_node:
|
if not variant_node:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
buildplate_compatibility = machine_compatibility
|
_, buildplate_unmapped_settings_dict = self._getSettingsDictForNode(buildplate)
|
||||||
buildplate_recommended = machine_compatibility
|
|
||||||
settings = buildplate.iterfind("./um:setting", self.__namespaces)
|
buildplate_compatibility = buildplate_unmapped_settings_dict.get("hardware compatible",
|
||||||
for entry in settings:
|
machine_compatibility)
|
||||||
key = entry.get("key")
|
buildplate_recommended = buildplate_unmapped_settings_dict.get("hardware recommended",
|
||||||
if key in self.__unmapped_settings:
|
machine_compatibility)
|
||||||
if key == "hardware compatible":
|
|
||||||
buildplate_compatibility = self._parseCompatibleValue(entry.text)
|
|
||||||
elif key == "hardware recommended":
|
|
||||||
buildplate_recommended = self._parseCompatibleValue(entry.text)
|
|
||||||
else:
|
|
||||||
Logger.log("d", "Unsupported material setting %s", key)
|
|
||||||
|
|
||||||
buildplate_map["buildplate_compatible"][buildplate_id] = buildplate_compatibility
|
buildplate_map["buildplate_compatible"][buildplate_id] = buildplate_compatibility
|
||||||
buildplate_map["buildplate_recommended"][buildplate_id] = buildplate_recommended
|
buildplate_map["buildplate_recommended"][buildplate_id] = buildplate_recommended
|
||||||
|
|
||||||
hotends = machine.iterfind("./um:hotend", self.__namespaces)
|
hotends = machine.iterfind("./um:hotend", self.__namespaces)
|
||||||
for hotend in hotends:
|
for hotend in hotends:
|
||||||
# The "id" field for hotends in material profiles are actually
|
# The "id" field for hotends in material profiles is actually name
|
||||||
hotend_name = hotend.get("id")
|
hotend_name = hotend.get("id")
|
||||||
if hotend_name is None:
|
if hotend_name is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
variant_manager = CuraApplication.getInstance().getVariantManager()
|
variant_manager = CuraApplication.getInstance().getVariantManager()
|
||||||
variant_node = variant_manager.getVariantNode(machine_id, hotend_name)
|
variant_node = variant_manager.getVariantNode(machine_id, hotend_name, VariantType.NOZZLE)
|
||||||
if not variant_node:
|
if not variant_node:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
hotend_compatibility = machine_compatibility
|
hotend_mapped_settings, hotend_unmapped_settings = self._getSettingsDictForNode(hotend)
|
||||||
hotend_setting_values = {}
|
hotend_compatibility = hotend_unmapped_settings.get("hardware compatible", machine_compatibility)
|
||||||
settings = hotend.iterfind("./um:setting", self.__namespaces)
|
|
||||||
for entry in settings:
|
|
||||||
key = entry.get("key")
|
|
||||||
if key in self.__material_settings_setting_map:
|
|
||||||
if key == "processing temperature graph": #This setting has no setting text but subtags.
|
|
||||||
graph_nodes = entry.iterfind("./um:point", self.__namespaces)
|
|
||||||
graph_points = []
|
|
||||||
for graph_node in graph_nodes:
|
|
||||||
flow = float(graph_node.get("flow"))
|
|
||||||
temperature = float(graph_node.get("temperature"))
|
|
||||||
graph_points.append([flow, temperature])
|
|
||||||
hotend_setting_values[self.__material_settings_setting_map[key]] = str(graph_points)
|
|
||||||
else:
|
|
||||||
hotend_setting_values[self.__material_settings_setting_map[key]] = entry.text
|
|
||||||
elif key in self.__unmapped_settings:
|
|
||||||
if key == "hardware compatible":
|
|
||||||
hotend_compatibility = self._parseCompatibleValue(entry.text)
|
|
||||||
else:
|
|
||||||
Logger.log("d", "Unsupported material setting %s", key)
|
|
||||||
|
|
||||||
# Add namespaced Cura-specific settings
|
|
||||||
settings = hotend.iterfind("./cura:setting", self.__namespaces)
|
|
||||||
for entry in settings:
|
|
||||||
value = entry.text
|
|
||||||
if value.lower() == "yes":
|
|
||||||
value = True
|
|
||||||
elif value.lower() == "no":
|
|
||||||
value = False
|
|
||||||
key = entry.get("key")
|
|
||||||
hotend_setting_values[key] = value
|
|
||||||
|
|
||||||
|
# Generate container ID for the hotend-specific material container
|
||||||
new_hotend_specific_material_id = self.getId() + "_" + machine_id + "_" + hotend_name.replace(" ", "_")
|
new_hotend_specific_material_id = self.getId() + "_" + machine_id + "_" + hotend_name.replace(" ", "_")
|
||||||
|
|
||||||
# Same as machine compatibility, keep the derived material containers consistent with the parent material
|
# Same as machine compatibility, keep the derived material containers consistent with the parent material
|
||||||
|
@ -787,7 +749,7 @@ class XmlMaterialProfile(InstanceContainer):
|
||||||
new_hotend_material.getMetaData()["buildplate_recommended"] = buildplate_map["buildplate_recommended"]
|
new_hotend_material.getMetaData()["buildplate_recommended"] = buildplate_map["buildplate_recommended"]
|
||||||
|
|
||||||
cached_hotend_setting_properties = cached_machine_setting_properties.copy()
|
cached_hotend_setting_properties = cached_machine_setting_properties.copy()
|
||||||
cached_hotend_setting_properties.update(hotend_setting_values)
|
cached_hotend_setting_properties.update(hotend_mapped_settings)
|
||||||
|
|
||||||
new_hotend_material.setCachedValues(cached_hotend_setting_properties)
|
new_hotend_material.setCachedValues(cached_hotend_setting_properties)
|
||||||
|
|
||||||
|
@ -796,6 +758,61 @@ class XmlMaterialProfile(InstanceContainer):
|
||||||
if is_new_material:
|
if is_new_material:
|
||||||
containers_to_add.append(new_hotend_material)
|
containers_to_add.append(new_hotend_material)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Build plates in hotend
|
||||||
|
#
|
||||||
|
buildplates = hotend.iterfind("./um:buildplate", self.__namespaces)
|
||||||
|
for buildplate in buildplates:
|
||||||
|
# The "id" field for buildplate in material profiles is actually name
|
||||||
|
buildplate_name = buildplate.get("id")
|
||||||
|
if buildplate_name is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
variant_manager = CuraApplication.getInstance().getVariantManager()
|
||||||
|
variant_node = variant_manager.getVariantNode(machine_id, buildplate_name, VariantType.BUILD_PLATE)
|
||||||
|
if not variant_node:
|
||||||
|
continue
|
||||||
|
|
||||||
|
buildplate_mapped_settings, buildplate_unmapped_settings = self._getSettingsDictForNode(buildplate)
|
||||||
|
buildplate_compatibility = buildplate_unmapped_settings.get("hardware compatible",
|
||||||
|
buildplate_map["buildplate_compatible"])
|
||||||
|
buildplate_recommended = buildplate_unmapped_settings.get("hardware recommended",
|
||||||
|
buildplate_map["buildplate_recommended"])
|
||||||
|
|
||||||
|
# Generate container ID for the hotend-and-buildplate-specific material container
|
||||||
|
new_hotend_and_buildplate_specific_material_id = new_hotend_specific_material_id + "_" + buildplate_name.replace(" ", "_")
|
||||||
|
|
||||||
|
# Same as machine compatibility, keep the derived material containers consistent with the parent material
|
||||||
|
if ContainerRegistry.getInstance().isLoaded(new_hotend_and_buildplate_specific_material_id):
|
||||||
|
new_hotend_and_buildplate_material = ContainerRegistry.getInstance().findContainers(id = new_hotend_and_buildplate_specific_material_id)[0]
|
||||||
|
is_new_material = False
|
||||||
|
else:
|
||||||
|
new_hotend_and_buildplate_material = XmlMaterialProfile(new_hotend_and_buildplate_specific_material_id)
|
||||||
|
is_new_material = True
|
||||||
|
|
||||||
|
new_hotend_and_buildplate_material.setMetaData(copy.deepcopy(new_hotend_material.getMetaData()))
|
||||||
|
new_hotend_and_buildplate_material.getMetaData()["id"] = new_hotend_and_buildplate_specific_material_id
|
||||||
|
new_hotend_and_buildplate_material.getMetaData()["name"] = self.getName()
|
||||||
|
new_hotend_and_buildplate_material.getMetaData()["variant_name"] = hotend_name
|
||||||
|
new_hotend_and_buildplate_material.getMetaData()["buildplate_name"] = buildplate_name
|
||||||
|
new_hotend_and_buildplate_material.setDefinition(machine_id)
|
||||||
|
# Don't use setMetadata, as that overrides it for all materials with same base file
|
||||||
|
new_hotend_and_buildplate_material.getMetaData()["compatible"] = buildplate_compatibility
|
||||||
|
new_hotend_and_buildplate_material.getMetaData()["machine_manufacturer"] = machine_manufacturer
|
||||||
|
new_hotend_and_buildplate_material.getMetaData()["definition"] = machine_id
|
||||||
|
new_hotend_and_buildplate_material.getMetaData()["buildplate_compatible"] = buildplate_compatibility
|
||||||
|
new_hotend_and_buildplate_material.getMetaData()["buildplate_recommended"] = buildplate_recommended
|
||||||
|
|
||||||
|
cached_hotend_and_buildplate_setting_properties = cached_hotend_setting_properties.copy()
|
||||||
|
cached_hotend_and_buildplate_setting_properties.update(buildplate_mapped_settings)
|
||||||
|
|
||||||
|
new_hotend_and_buildplate_material.setCachedValues(cached_hotend_and_buildplate_setting_properties)
|
||||||
|
|
||||||
|
new_hotend_and_buildplate_material._dirty = False
|
||||||
|
|
||||||
|
if is_new_material:
|
||||||
|
containers_to_add.append(new_hotend_and_buildplate_material)
|
||||||
|
|
||||||
# there is only one ID for a machine. Once we have reached here, it means we have already found
|
# there is only one ID for a machine. Once we have reached here, it means we have already found
|
||||||
# a workable ID for that machine, so there is no need to continue
|
# a workable ID for that machine, so there is no need to continue
|
||||||
break
|
break
|
||||||
|
@ -803,6 +820,54 @@ class XmlMaterialProfile(InstanceContainer):
|
||||||
for container_to_add in containers_to_add:
|
for container_to_add in containers_to_add:
|
||||||
ContainerRegistry.getInstance().addContainer(container_to_add)
|
ContainerRegistry.getInstance().addContainer(container_to_add)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _getSettingsDictForNode(cls, node) -> Tuple[dict, dict]:
|
||||||
|
node_mapped_settings_dict = dict()
|
||||||
|
node_unmapped_settings_dict = dict()
|
||||||
|
|
||||||
|
# Fetch settings in the "um" namespace
|
||||||
|
um_settings = node.iterfind("./um:setting", cls.__namespaces)
|
||||||
|
for um_setting_entry in um_settings:
|
||||||
|
setting_key = um_setting_entry.get("key")
|
||||||
|
|
||||||
|
# Mapped settings
|
||||||
|
if setting_key in cls.__material_settings_setting_map:
|
||||||
|
if setting_key == "processing temperature graph": # This setting has no setting text but subtags.
|
||||||
|
graph_nodes = um_setting_entry.iterfind("./um:point", cls.__namespaces)
|
||||||
|
graph_points = []
|
||||||
|
for graph_node in graph_nodes:
|
||||||
|
flow = float(graph_node.get("flow"))
|
||||||
|
temperature = float(graph_node.get("temperature"))
|
||||||
|
graph_points.append([flow, temperature])
|
||||||
|
node_mapped_settings_dict[cls.__material_settings_setting_map[setting_key]] = str(
|
||||||
|
graph_points)
|
||||||
|
else:
|
||||||
|
node_mapped_settings_dict[cls.__material_settings_setting_map[setting_key]] = um_setting_entry.text
|
||||||
|
|
||||||
|
# Unmapped settings
|
||||||
|
elif setting_key in cls.__unmapped_settings:
|
||||||
|
if setting_key in ("hardware compatible", "hardware recommended"):
|
||||||
|
node_unmapped_settings_dict[setting_key] = cls._parseCompatibleValue(um_setting_entry.text)
|
||||||
|
|
||||||
|
# Unknown settings
|
||||||
|
else:
|
||||||
|
Logger.log("w", "Unsupported material setting %s", setting_key)
|
||||||
|
|
||||||
|
# Fetch settings in the "cura" namespace
|
||||||
|
cura_settings = node.iterfind("./cura:setting", cls.__namespaces)
|
||||||
|
for cura_setting_entry in cura_settings:
|
||||||
|
value = cura_setting_entry.text
|
||||||
|
if value.lower() == "yes":
|
||||||
|
value = True
|
||||||
|
elif value.lower() == "no":
|
||||||
|
value = False
|
||||||
|
key = cura_setting_entry.get("key")
|
||||||
|
|
||||||
|
# Cura settings are all mapped
|
||||||
|
node_mapped_settings_dict[key] = value
|
||||||
|
|
||||||
|
return node_mapped_settings_dict, node_unmapped_settings_dict
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def deserializeMetadata(cls, serialized: str, container_id: str) -> List[Dict[str, Any]]:
|
def deserializeMetadata(cls, serialized: str, container_id: str) -> List[Dict[str, Any]]:
|
||||||
result_metadata = [] #All the metadata that we found except the base (because the base is returned).
|
result_metadata = [] #All the metadata that we found except the base (because the base is returned).
|
||||||
|
@ -985,6 +1050,36 @@ class XmlMaterialProfile(InstanceContainer):
|
||||||
|
|
||||||
result_metadata.append(new_hotend_material_metadata)
|
result_metadata.append(new_hotend_material_metadata)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Buildplates in Hotends
|
||||||
|
#
|
||||||
|
buildplates = hotend.iterfind("./um:buildplate", cls.__namespaces)
|
||||||
|
for buildplate in buildplates:
|
||||||
|
# The "id" field for buildplate in material profiles is actually name
|
||||||
|
buildplate_name = buildplate.get("id")
|
||||||
|
if buildplate_name is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
buildplate_mapped_settings, buildplate_unmapped_settings = cls._getSettingsDictForNode(buildplate)
|
||||||
|
buildplate_compatibility = buildplate_unmapped_settings.get("hardware compatible",
|
||||||
|
buildplate_map["buildplate_compatible"])
|
||||||
|
buildplate_recommended = buildplate_unmapped_settings.get("hardware recommended",
|
||||||
|
buildplate_map["buildplate_recommended"])
|
||||||
|
|
||||||
|
# Generate container ID for the hotend-and-buildplate-specific material container
|
||||||
|
new_hotend_and_buildplate_specific_material_id = new_hotend_specific_material_id + "_" + buildplate_name.replace(
|
||||||
|
" ", "_")
|
||||||
|
|
||||||
|
new_hotend_and_buildplate_material_metadata = {}
|
||||||
|
new_hotend_and_buildplate_material_metadata.update(new_hotend_material_metadata)
|
||||||
|
new_hotend_and_buildplate_material_metadata["id"] = new_hotend_and_buildplate_specific_material_id
|
||||||
|
new_hotend_and_buildplate_material_metadata["buildplate_name"] = buildplate_name
|
||||||
|
new_hotend_and_buildplate_material_metadata["compatible"] = buildplate_compatibility
|
||||||
|
new_hotend_and_buildplate_material_metadata["buildplate_compatible"] = buildplate_compatibility
|
||||||
|
new_hotend_and_buildplate_material_metadata["buildplate_recommended"] = buildplate_recommended
|
||||||
|
|
||||||
|
result_metadata.append(new_hotend_and_buildplate_material_metadata)
|
||||||
|
|
||||||
# there is only one ID for a machine. Once we have reached here, it means we have already found
|
# there is only one ID for a machine. Once we have reached here, it means we have already found
|
||||||
# a workable ID for that machine, so there is no need to continue
|
# a workable ID for that machine, so there is no need to continue
|
||||||
break
|
break
|
||||||
|
|
|
@ -2127,6 +2127,7 @@
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"default_value": 60,
|
"default_value": 60,
|
||||||
"value": "default_material_bed_temperature",
|
"value": "default_material_bed_temperature",
|
||||||
|
"resolve": "max(extruderValues('material_bed_temperature'))",
|
||||||
"minimum_value": "-273.15",
|
"minimum_value": "-273.15",
|
||||||
"minimum_value_warning": "0",
|
"minimum_value_warning": "0",
|
||||||
"maximum_value_warning": "130",
|
"maximum_value_warning": "130",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue