CuraStackBuilder.py 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. # Copyright (c) 2017 Ultimaker B.V.
  2. # Cura is released under the terms of the LGPLv3 or higher.
  3. from UM.Logger import Logger
  4. from UM.Settings.Interfaces import DefinitionContainerInterface
  5. from UM.Settings.InstanceContainer import InstanceContainer
  6. from UM.Settings.ContainerRegistry import ContainerRegistry
  7. from .GlobalStack import GlobalStack
  8. from .ExtruderStack import ExtruderStack
  9. from typing import Optional
  10. ## Contains helper functions to create new machines.
  11. class CuraStackBuilder:
  12. ## Create a new instance of a machine.
  13. #
  14. # \param name The name of the new machine.
  15. # \param definition_id The ID of the machine definition to use.
  16. #
  17. # \return The new global stack or None if an error occurred.
  18. @classmethod
  19. def createMachine(cls, name: str, definition_id: str) -> Optional[GlobalStack]:
  20. registry = ContainerRegistry.getInstance()
  21. definitions = registry.findDefinitionContainers(id = definition_id)
  22. if not definitions:
  23. Logger.log("w", "Definition {definition} was not found!", definition = definition_id)
  24. return None
  25. machine_definition = definitions[0]
  26. generated_name = registry.createUniqueName("machine", "", name, machine_definition.name)
  27. # Make sure the new name does not collide with any definition or (quality) profile
  28. # createUniqueName() only looks at other stacks, but not at definitions or quality profiles
  29. # Note that we don't go for uniqueName() immediately because that function matches with ignore_case set to true
  30. if registry.findContainersMetadata(id = generated_name):
  31. generated_name = registry.uniqueName(generated_name)
  32. new_global_stack = cls.createGlobalStack(
  33. new_stack_id = generated_name,
  34. definition = machine_definition,
  35. quality = "default",
  36. material = "default",
  37. variant = "default",
  38. )
  39. new_global_stack.setName(generated_name)
  40. extruder_definition = registry.findDefinitionContainers(machine = machine_definition.getId())
  41. if not extruder_definition:
  42. # create extruder stack for single extrusion machines that have no separate extruder definition files
  43. extruder_definition = registry.findDefinitionContainers(id = "fdmextruder")[0]
  44. new_extruder_id = registry.uniqueName(machine_definition.getName() + " " + extruder_definition.id)
  45. new_extruder = cls.createExtruderStack(
  46. new_extruder_id,
  47. definition = extruder_definition,
  48. machine_definition_id = machine_definition.getId(),
  49. quality = "default",
  50. material = "default",
  51. variant = "default",
  52. next_stack = new_global_stack
  53. )
  54. new_global_stack.addExtruder(new_extruder)
  55. registry.addContainer(new_extruder)
  56. else:
  57. # create extruder stack for each found extruder definition
  58. for extruder_definition in registry.findDefinitionContainers(machine = machine_definition.id):
  59. position = extruder_definition.getMetaDataEntry("position", None)
  60. if not position:
  61. Logger.log("w", "Extruder definition %s specifies no position metadata entry.", extruder_definition.id)
  62. new_extruder_id = registry.uniqueName(extruder_definition.id)
  63. new_extruder = cls.createExtruderStack(
  64. new_extruder_id,
  65. definition = extruder_definition,
  66. machine_definition_id = machine_definition.getId(),
  67. quality = "default",
  68. material = "default",
  69. variant = "default",
  70. next_stack = new_global_stack
  71. )
  72. new_global_stack.addExtruder(new_extruder)
  73. registry.addContainer(new_extruder)
  74. # Register the global stack after the extruder stacks are created. This prevents the registry from adding another
  75. # extruder stack because the global stack didn't have one yet (which is enforced since Cura 3.1).
  76. registry.addContainer(new_global_stack)
  77. return new_global_stack
  78. ## Create a new Extruder stack
  79. #
  80. # \param new_stack_id The ID of the new stack.
  81. # \param definition The definition to base the new stack on.
  82. # \param machine_definition_id The ID of the machine definition to use for
  83. # the user container.
  84. # \param kwargs You can add keyword arguments to specify IDs of containers to use for a specific type, for example "variant": "0.4mm"
  85. #
  86. # \return A new Global stack instance with the specified parameters.
  87. @classmethod
  88. def createExtruderStack(cls, new_stack_id: str, definition: DefinitionContainerInterface, machine_definition_id: str, **kwargs) -> ExtruderStack:
  89. stack = ExtruderStack(new_stack_id)
  90. stack.setName(definition.getName())
  91. stack.setDefinition(definition)
  92. stack.addMetaDataEntry("position", definition.getMetaDataEntry("position"))
  93. if "next_stack" in kwargs:
  94. # Add stacks before containers are added, since they may trigger a setting update.
  95. stack.setNextStack(kwargs["next_stack"])
  96. user_container = InstanceContainer(new_stack_id + "_user")
  97. user_container.addMetaDataEntry("type", "user")
  98. user_container.addMetaDataEntry("extruder", new_stack_id)
  99. from cura.CuraApplication import CuraApplication
  100. user_container.addMetaDataEntry("setting_version", CuraApplication.SettingVersion)
  101. user_container.setDefinition(machine_definition_id)
  102. stack.setUserChanges(user_container)
  103. # Important! The order here matters, because that allows the stack to
  104. # assume the material and variant have already been set.
  105. if "definition_changes" in kwargs:
  106. stack.setDefinitionChangesById(kwargs["definition_changes"])
  107. else:
  108. stack.setDefinitionChanges(cls.createDefinitionChangesContainer(stack, new_stack_id + "_settings"))
  109. if "variant" in kwargs:
  110. stack.setVariantById(kwargs["variant"])
  111. if "material" in kwargs:
  112. stack.setMaterialById(kwargs["material"])
  113. if "quality" in kwargs:
  114. stack.setQualityById(kwargs["quality"])
  115. if "quality_changes" in kwargs:
  116. stack.setQualityChangesById(kwargs["quality_changes"])
  117. # Only add the created containers to the registry after we have set all the other
  118. # properties. This makes the create operation more transactional, since any problems
  119. # setting properties will not result in incomplete containers being added.
  120. ContainerRegistry.getInstance().addContainer(user_container)
  121. return stack
  122. ## Create a new Global stack
  123. #
  124. # \param new_stack_id The ID of the new stack.
  125. # \param definition The definition to base the new stack on.
  126. # \param kwargs You can add keyword arguments to specify IDs of containers to use for a specific type, for example "variant": "0.4mm"
  127. #
  128. # \return A new Global stack instance with the specified parameters.
  129. @classmethod
  130. def createGlobalStack(cls, new_stack_id: str, definition: DefinitionContainerInterface, **kwargs) -> GlobalStack:
  131. stack = GlobalStack(new_stack_id)
  132. stack.setDefinition(definition)
  133. user_container = InstanceContainer(new_stack_id + "_user")
  134. user_container.addMetaDataEntry("type", "user")
  135. user_container.addMetaDataEntry("machine", new_stack_id)
  136. from cura.CuraApplication import CuraApplication
  137. user_container.addMetaDataEntry("setting_version", CuraApplication.SettingVersion)
  138. user_container.setDefinition(definition.getId())
  139. stack.setUserChanges(user_container)
  140. # Important! The order here matters, because that allows the stack to
  141. # assume the material and variant have already been set.
  142. if "definition_changes" in kwargs:
  143. stack.setDefinitionChangesById(kwargs["definition_changes"])
  144. else:
  145. stack.setDefinitionChanges(cls.createDefinitionChangesContainer(stack, new_stack_id + "_settings"))
  146. if "variant" in kwargs:
  147. stack.setVariantById(kwargs["variant"])
  148. if "material" in kwargs:
  149. stack.setMaterialById(kwargs["material"])
  150. if "quality" in kwargs:
  151. stack.setQualityById(kwargs["quality"])
  152. if "quality_changes" in kwargs:
  153. stack.setQualityChangesById(kwargs["quality_changes"])
  154. ContainerRegistry.getInstance().addContainer(user_container)
  155. return stack
  156. @classmethod
  157. def createDefinitionChangesContainer(cls, container_stack, container_name, container_index = None):
  158. from cura.CuraApplication import CuraApplication
  159. unique_container_name = ContainerRegistry.getInstance().uniqueName(container_name)
  160. definition_changes_container = InstanceContainer(unique_container_name)
  161. definition_changes_container.setDefinition(container_stack.getBottom().getId())
  162. definition_changes_container.addMetaDataEntry("type", "definition_changes")
  163. definition_changes_container.addMetaDataEntry("setting_version", CuraApplication.SettingVersion)
  164. ContainerRegistry.getInstance().addContainer(definition_changes_container)
  165. container_stack.definitionChanges = definition_changes_container
  166. return definition_changes_container