WIP: Simplify machine creation

This commit is contained in:
Lipu Fei 2018-02-14 14:13:21 +01:00
parent b1e4cb91de
commit 730cbb25bf
6 changed files with 129 additions and 97 deletions

View file

@ -294,21 +294,25 @@ class CuraApplication(QtApplication):
# Since they are empty, they should never be serialized and instead just programmatically created. # Since they are empty, they should never be serialized and instead just programmatically created.
# We need them to simplify the switching between materials. # We need them to simplify the switching between materials.
empty_container = ContainerRegistry.getInstance().getEmptyInstanceContainer() empty_container = ContainerRegistry.getInstance().getEmptyInstanceContainer()
self.empty_container = empty_container
empty_definition_changes_container = copy.deepcopy(empty_container) empty_definition_changes_container = copy.deepcopy(empty_container)
empty_definition_changes_container.setMetaDataEntry("id", "empty_definition_changes") empty_definition_changes_container.setMetaDataEntry("id", "empty_definition_changes")
empty_definition_changes_container.addMetaDataEntry("type", "definition_changes") empty_definition_changes_container.addMetaDataEntry("type", "definition_changes")
ContainerRegistry.getInstance().addContainer(empty_definition_changes_container) ContainerRegistry.getInstance().addContainer(empty_definition_changes_container)
self.empty_definition_changes_container = empty_definition_changes_container
empty_variant_container = copy.deepcopy(empty_container) empty_variant_container = copy.deepcopy(empty_container)
empty_variant_container.setMetaDataEntry("id", "empty_variant") empty_variant_container.setMetaDataEntry("id", "empty_variant")
empty_variant_container.addMetaDataEntry("type", "variant") empty_variant_container.addMetaDataEntry("type", "variant")
ContainerRegistry.getInstance().addContainer(empty_variant_container) ContainerRegistry.getInstance().addContainer(empty_variant_container)
self.empty_variant_container = empty_variant_container
empty_material_container = copy.deepcopy(empty_container) empty_material_container = copy.deepcopy(empty_container)
empty_material_container.setMetaDataEntry("id", "empty_material") empty_material_container.setMetaDataEntry("id", "empty_material")
empty_material_container.addMetaDataEntry("type", "material") empty_material_container.addMetaDataEntry("type", "material")
ContainerRegistry.getInstance().addContainer(empty_material_container) ContainerRegistry.getInstance().addContainer(empty_material_container)
self.empty_material_container = empty_material_container
empty_quality_container = copy.deepcopy(empty_container) empty_quality_container = copy.deepcopy(empty_container)
empty_quality_container.setMetaDataEntry("id", "empty_quality") empty_quality_container.setMetaDataEntry("id", "empty_quality")
@ -317,12 +321,14 @@ class CuraApplication(QtApplication):
empty_quality_container.addMetaDataEntry("type", "quality") empty_quality_container.addMetaDataEntry("type", "quality")
empty_quality_container.addMetaDataEntry("supported", False) empty_quality_container.addMetaDataEntry("supported", False)
ContainerRegistry.getInstance().addContainer(empty_quality_container) ContainerRegistry.getInstance().addContainer(empty_quality_container)
self.empty_quality_container = empty_quality_container
empty_quality_changes_container = copy.deepcopy(empty_container) empty_quality_changes_container = copy.deepcopy(empty_container)
empty_quality_changes_container.setMetaDataEntry("id", "empty_quality_changes") empty_quality_changes_container.setMetaDataEntry("id", "empty_quality_changes")
empty_quality_changes_container.addMetaDataEntry("type", "quality_changes") empty_quality_changes_container.addMetaDataEntry("type", "quality_changes")
empty_quality_changes_container.addMetaDataEntry("quality_type", "not_supported") empty_quality_changes_container.addMetaDataEntry("quality_type", "not_supported")
ContainerRegistry.getInstance().addContainer(empty_quality_changes_container) ContainerRegistry.getInstance().addContainer(empty_quality_changes_container)
self.empty_quality_changes_container = empty_quality_changes_container
with ContainerRegistry.getInstance().lockFile(): with ContainerRegistry.getInstance().lockFile():
ContainerRegistry.getInstance().loadAllMetadata() ContainerRegistry.getInstance().loadAllMetadata()

View file

@ -257,7 +257,7 @@ class QualityManager(QObject):
return quality_changes_group_dict return quality_changes_group_dict
def getQualityGroups(self, machine: "GlobalStack") -> dict: def getQualityGroups(self, machine: "GlobalStack") -> dict:
# TODO: How to make this simpler, including the fallbacks. # TODO: How to make this simpler, including the fall backs.
# Get machine definition ID # Get machine definition ID
machine_definition_id = self._default_machine_definition_id machine_definition_id = self._default_machine_definition_id
if parseBool(machine.getMetaDataEntry("has_machine_quality", False)): if parseBool(machine.getMetaDataEntry("has_machine_quality", False)):
@ -270,8 +270,13 @@ class QualityManager(QObject):
raise RuntimeError("Cannot find node for machine def [%s] in Quality lookup table" % machine_definition_id) raise RuntimeError("Cannot find node for machine def [%s] in Quality lookup table" % machine_definition_id)
# iterate over all quality_types in the machine node # iterate over all quality_types in the machine node
node_to_fetch_global = machine_node
quality_group_dict = {} quality_group_dict = {}
for quality_type, quality_node in machine_node.quality_type_map.items(): if not node_to_fetch_global.quality_type_map:
# Fallback mechanism:
# If there is no machine-specific quality, fallback to use the default fdmprinter's.
node_to_fetch_global = self._machine_variant_material_quality_type_to_quality_dict.get(self._default_machine_definition_id)
for quality_type, quality_node in node_to_fetch_global.quality_type_map.items():
quality_group = QualityGroup(quality_node.metadata["name"], quality_type) quality_group = QualityGroup(quality_node.metadata["name"], quality_type)
quality_group.node_for_global = quality_node quality_group.node_for_global = quality_node

View file

@ -6,6 +6,7 @@ from UM.Logger import Logger
from UM.Settings.Interfaces import DefinitionContainerInterface from UM.Settings.Interfaces import DefinitionContainerInterface
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.Util import parseBool
from .GlobalStack import GlobalStack from .GlobalStack import GlobalStack
from .ExtruderStack import ExtruderStack from .ExtruderStack import ExtruderStack
@ -22,7 +23,13 @@ class CuraStackBuilder:
# \return The new global stack or None if an error occurred. # \return The new global stack or None if an error occurred.
@classmethod @classmethod
def createMachine(cls, name: str, definition_id: str) -> Optional[GlobalStack]: def createMachine(cls, name: str, definition_id: str) -> Optional[GlobalStack]:
from cura.CuraApplication import CuraApplication
application = CuraApplication.getInstance()
variant_manager = CuraApplication.getInstance()._variant_manager
material_manager = CuraApplication.getInstance()._material_manager
quality_manager = CuraApplication.getInstance()._quality_manager
registry = ContainerRegistry.getInstance() registry = ContainerRegistry.getInstance()
definitions = registry.findDefinitionContainers(id = definition_id) definitions = registry.findDefinitionContainers(id = definition_id)
if not definitions: if not definitions:
Logger.log("w", "Definition {definition} was not found!", definition = definition_id) Logger.log("w", "Definition {definition} was not found!", definition = definition_id)
@ -30,7 +37,33 @@ class CuraStackBuilder:
machine_definition = definitions[0] machine_definition = definitions[0]
generated_name = registry.createUniqueName("machine", "", name, machine_definition.name) # get variant container for extruders
variant_container = application.empty_variant_container
# Only look for the preferred variant if this machine has variants
variant_name = None
if parseBool(machine_definition.getMetaDataEntry("has_variants", False)):
variant_name = machine_definition.getMetaDataEntry("preferred_variant_name")
if variant_name:
variant_node = variant_manager.getVariant(definition_id, variant_name)
# Sanity check. If you see this error, the related definition files should be fixed.
if variant_node is None:
raise RuntimeError("Cannot find variant with definition [%s] and variant name [%s]" % (definition_id, variant_name))
variant_container = variant_node.getContainer()
# get material container for extruders
material_container = application.empty_material_container
# Only look for the preferred material if this machine has materials
if parseBool(machine_definition.getMetaDataEntry("has_materials", False)):
material_diameter = machine_definition.getProperty("material_diameter", "value")
root_material_id = machine_definition.getMetaDataEntry("preferred_material")
material_node = material_manager.getMaterialNode(definition_id, variant_name, material_diameter, root_material_id)
# Sanity check. If you see this error, the related definition files should be fixed.
if not material_node:
raise RuntimeError("Cannot find material with definition [%s], variant_name [%s], and root_material_id [%s]" %
(definition_id, variant_name, root_material_id))
material_container = material_node.getContainer()
generated_name = registry.createUniqueName("machine", "", name, machine_definition.getName())
# Make sure the new name does not collide with any definition or (quality) profile # Make sure the new name does not collide with any definition or (quality) profile
# createUniqueName() only looks at other stacks, but not at definitions or quality profiles # createUniqueName() only looks at other stacks, but not at definitions or quality profiles
# Note that we don't go for uniqueName() immediately because that function matches with ignore_case set to true # Note that we don't go for uniqueName() immediately because that function matches with ignore_case set to true
@ -40,49 +73,45 @@ class CuraStackBuilder:
new_global_stack = cls.createGlobalStack( new_global_stack = cls.createGlobalStack(
new_stack_id = generated_name, new_stack_id = generated_name,
definition = machine_definition, definition = machine_definition,
quality = "default", variant_container = application.empty_variant_container, # TODO: fix for build plate
material = "default", material_container = application.empty_material_container,
variant = "default", quality_container = application.empty_quality_container,
) )
new_global_stack.setName(generated_name) new_global_stack.setName(generated_name)
extruder_definition = registry.findDefinitionContainers(machine = machine_definition.getId()) # Create ExtruderStacks
extruder_dict = machine_definition.getMetaDataEntry("machine_extruder_trains")
if not extruder_definition: for position, extruder_definition_id in extruder_dict.items():
# create extruder stack for single extrusion machines that have no separate extruder definition files # Sanity check: make sure that the positions in the extruder definitions are same as in the machine
extruder_definition = registry.findDefinitionContainers(id = "fdmextruder")[0] # definition
new_extruder_id = registry.uniqueName(machine_definition.getName() + " " + extruder_definition.id) extruder_definition = registry.findDefinitionContainers(id = extruder_definition_id)[0]
position_in_extruder_def = extruder_definition.getMetaDataEntry("position")
if position_in_extruder_def != position:
raise RuntimeError("Extruder position [%s] defined in extruder definition [%s] is not the same as in machine definition [%s] position [%s]" %
(position_in_extruder_def, extruder_definition_id, definition_id, position))
new_extruder_id = registry.uniqueName(extruder_definition_id)
new_extruder = cls.createExtruderStack( new_extruder = cls.createExtruderStack(
new_extruder_id, new_extruder_id,
definition = extruder_definition, extruder_definition = extruder_definition,
machine_definition_id = machine_definition.getId(), machine_definition_id = definition_id,
quality = "default", position = position,
material = "default", variant_container = variant_container,
variant = "default", material_container = material_container,
next_stack = new_global_stack quality_container = application.empty_quality_container,
) )
new_extruder.setNextStack(new_global_stack)
new_global_stack.addExtruder(new_extruder) new_global_stack.addExtruder(new_extruder)
registry.addContainer(new_extruder) registry.addContainer(new_extruder)
else:
# create extruder stack for each found extruder definition
for extruder_definition in registry.findDefinitionContainers(machine = machine_definition.id):
position = extruder_definition.getMetaDataEntry("position", None)
if not position:
Logger.log("w", "Extruder definition %s specifies no position metadata entry.", extruder_definition.id)
new_extruder_id = registry.uniqueName(extruder_definition.id) preferred_quality_type = machine_definition.getMetaDataEntry("preferred_quality_type")
new_extruder = cls.createExtruderStack( quality_group_dict = quality_manager.getQualityGroups(new_global_stack)
new_extruder_id, quality_group = quality_group_dict.get(preferred_quality_type)
definition = extruder_definition,
machine_definition_id = machine_definition.getId(), new_global_stack.quality = quality_group.node_for_global.getContainer()
quality = "default", for position, extruder_stack in new_global_stack.extruders.items():
material = "default", extruder_stack.quality = quality_group.nodes_for_extruders[position].getContainer()
variant = "default",
next_stack = new_global_stack
)
new_global_stack.addExtruder(new_extruder)
registry.addContainer(new_extruder)
# Register the global stack after the extruder stacks are created. This prevents the registry from adding another # Register the global stack after the extruder stacks are created. This prevents the registry from adding another
# extruder stack because the global stack didn't have one yet (which is enforced since Cura 3.1). # extruder stack because the global stack didn't have one yet (which is enforced since Cura 3.1).
@ -100,43 +129,27 @@ class CuraStackBuilder:
# #
# \return A new Global stack instance with the specified parameters. # \return A new Global stack instance with the specified parameters.
@classmethod @classmethod
def createExtruderStack(cls, new_stack_id: str, definition: DefinitionContainerInterface, machine_definition_id: str, **kwargs) -> ExtruderStack: def createExtruderStack(cls, new_stack_id: str, extruder_definition: DefinitionContainerInterface, machine_definition_id: str,
stack = ExtruderStack(new_stack_id) position: int,
stack.setName(definition.getName()) variant_container, material_container, quality_container) -> ExtruderStack:
stack.setDefinition(definition)
stack.addMetaDataEntry("position", definition.getMetaDataEntry("position"))
if "next_stack" in kwargs:
# Add stacks before containers are added, since they may trigger a setting update.
stack.setNextStack(kwargs["next_stack"])
user_container = InstanceContainer(new_stack_id + "_user")
user_container.addMetaDataEntry("type", "user")
user_container.addMetaDataEntry("extruder", new_stack_id)
from cura.CuraApplication import CuraApplication from cura.CuraApplication import CuraApplication
user_container.addMetaDataEntry("setting_version", CuraApplication.SettingVersion) application = CuraApplication.getInstance()
user_container.setDefinition(machine_definition_id)
stack.setUserChanges(user_container) stack = ExtruderStack(new_stack_id)
stack.setName(extruder_definition.getName())
stack.setDefinition(extruder_definition)
# Important! The order here matters, because that allows the stack to stack.addMetaDataEntry("position", position)
# assume the material and variant have already been set.
if "definition_changes" in kwargs:
stack.setDefinitionChangesById(kwargs["definition_changes"])
else:
stack.setDefinitionChanges(cls.createDefinitionChangesContainer(stack, new_stack_id + "_settings"))
if "variant" in kwargs: user_container = cls.createUserChangesContainer(new_stack_id + "_user", machine_definition_id, new_stack_id,
stack.setVariantById(kwargs["variant"]) is_global_stack = False)
if "material" in kwargs: stack.definitionChanges = cls.createDefinitionChangesContainer(stack, new_stack_id + "_settings")
stack.setMaterialById(kwargs["material"]) stack.variant = variant_container
stack.material = material_container
if "quality" in kwargs: stack.quality = quality_container
stack.setQualityById(kwargs["quality"]) stack.qualityChanges = application.empty_quality_changes_container
stack.userChanges = user_container
if "quality_changes" in kwargs:
stack.setQualityChangesById(kwargs["quality_changes"])
# Only add the created containers to the registry after we have set all the other # Only add the created containers to the registry after we have set all the other
# properties. This makes the create operation more transactional, since any problems # properties. This makes the create operation more transactional, since any problems
@ -153,42 +166,47 @@ class CuraStackBuilder:
# #
# \return A new Global stack instance with the specified parameters. # \return A new Global stack instance with the specified parameters.
@classmethod @classmethod
def createGlobalStack(cls, new_stack_id: str, definition: DefinitionContainerInterface, **kwargs) -> GlobalStack: def createGlobalStack(cls, new_stack_id: str, definition: DefinitionContainerInterface,
variant_container, material_container, quality_container) -> GlobalStack:
from cura.CuraApplication import CuraApplication
application = CuraApplication.getInstance()
stack = GlobalStack(new_stack_id) stack = GlobalStack(new_stack_id)
stack.setDefinition(definition) stack.setDefinition(definition)
user_container = InstanceContainer(new_stack_id + "_user") # Create user container
user_container.addMetaDataEntry("type", "user") user_container = cls.createUserChangesContainer(new_stack_id + "_user", definition.getId(), new_stack_id,
user_container.addMetaDataEntry("machine", new_stack_id) is_global_stack = True)
from cura.CuraApplication import CuraApplication
user_container.addMetaDataEntry("setting_version", CuraApplication.SettingVersion)
user_container.setDefinition(definition.getId())
stack.setUserChanges(user_container) stack.definitionChanges = cls.createDefinitionChangesContainer(stack, new_stack_id + "_settings")
stack.variant = variant_container
# Important! The order here matters, because that allows the stack to stack.material = material_container
# assume the material and variant have already been set. stack.quality = quality_container
if "definition_changes" in kwargs: stack.qualityChanges = application.empty_quality_changes_container
stack.setDefinitionChangesById(kwargs["definition_changes"]) stack.userChanges = user_container
else:
stack.setDefinitionChanges(cls.createDefinitionChangesContainer(stack, new_stack_id + "_settings"))
if "variant" in kwargs:
stack.setVariantById(kwargs["variant"])
if "material" in kwargs:
stack.setMaterialById(kwargs["material"])
if "quality" in kwargs:
stack.setQualityById(kwargs["quality"])
if "quality_changes" in kwargs:
stack.setQualityChangesById(kwargs["quality_changes"])
ContainerRegistry.getInstance().addContainer(user_container) ContainerRegistry.getInstance().addContainer(user_container)
return stack return stack
@classmethod
def createUserChangesContainer(cls, container_name: str, definition_id: str, stack_id: str,
is_global_stack: bool) -> "InstanceContainer":
from cura.CuraApplication import CuraApplication
unique_container_name = ContainerRegistry.getInstance().uniqueName(container_name)
container = InstanceContainer(unique_container_name)
container.setDefinition(definition_id)
container.addMetaDataEntry("type", "user")
container.addMetaDataEntry("setting_version", CuraApplication.SettingVersion)
metadata_key_to_add = "machine" if is_global_stack else "extruder"
container.addMetaDataEntry(metadata_key_to_add, stack_id)
return container
@classmethod @classmethod
def createDefinitionChangesContainer(cls, container_stack, container_name, container_index = None): def createDefinitionChangesContainer(cls, container_stack, container_name, container_index = None):
from cura.CuraApplication import CuraApplication from cura.CuraApplication import CuraApplication

View file

@ -11,8 +11,9 @@
"file_formats": "text/x-gcode;application/x-stl-ascii;application/x-stl-binary;application/x-wavefront-obj;application/x3g", "file_formats": "text/x-gcode;application/x-stl-ascii;application/x-stl-binary;application/x-wavefront-obj;application/x3g",
"visible": false, "visible": false,
"has_materials": true, "has_materials": true,
"preferred_material": "*generic_pla*", "preferred_material": "generic_pla",
"preferred_quality": "*normal*", "preferred_quality": "*normal*",
"preferred_quality_type": "normal",
"machine_extruder_trains": "machine_extruder_trains":
{ {
"0": "fdmextruder" "0": "fdmextruder"

View file

@ -10,6 +10,7 @@
"platform": "ultimaker2_platform.obj", "platform": "ultimaker2_platform.obj",
"platform_texture": "Ultimaker2Plusbackplate.png", "platform_texture": "Ultimaker2Plusbackplate.png",
"preferred_variant": "*0.4*", "preferred_variant": "*0.4*",
"preferred_variant_name": "0.4 mm",
"has_variants": true, "has_variants": true,
"has_materials": true, "has_materials": true,
"has_machine_materials": true, "has_machine_materials": true,

View file

@ -16,8 +16,9 @@
"has_variant_materials": true, "has_variant_materials": true,
"has_variants": true, "has_variants": true,
"preferred_variant": "*aa04*", "preferred_variant": "*aa04*",
"preferred_variant_name": "AA 0.4",
"preferred_quality": "*Normal*", "preferred_quality": "*Normal*",
"preferred_quality_type": "fine", "preferred_quality_type": "normal",
"variants_name": "Print core", "variants_name": "Print core",
"machine_extruder_trains": "machine_extruder_trains":
{ {