def _fixMaterialDiameterAndNozzleSize(self, global_stack, extruder_stack_list): keys_to_copy = ["material_diameter", "machine_nozzle_size"] # these will be copied over to all extruders extruder_positions_to_update = set() for extruder_stack in extruder_stack_list: for key in keys_to_copy: # Only copy the value when this extruder doesn't have the value. if extruder_stack.definitionChanges.hasProperty(key, "value"): continue setting_value_in_global_def_changes = global_stack.definitionChanges.getProperty(key, "value") setting_value_in_global_def = global_stack.definition.getProperty(key, "value") setting_value = setting_value_in_global_def if setting_value_in_global_def_changes is not None: setting_value = setting_value_in_global_def_changes if setting_value == extruder_stack.definition.getProperty(key, "value"): continue setting_definition = global_stack.getSettingDefinition(key) new_instance = SettingInstance(setting_definition, extruder_stack.definitionChanges) new_instance.setProperty("value", setting_value) new_instance.resetState() # Ensure that the state is not seen as a user state. extruder_stack.definitionChanges.addInstance(new_instance) extruder_stack.definitionChanges.setDirty(True) # Make sure the material diameter is up to date for the extruder stack. if key == "material_diameter": position = int(extruder_stack.getMetaDataEntry("position")) extruder_positions_to_update.add(position) # We have to remove those settings here because we know that those values have been copied to all # the extruders at this point. for key in keys_to_copy: if global_stack.definitionChanges.hasProperty(key, "value"): global_stack.definitionChanges.removeInstance(key, postpone_emit = True)
def setVisible(self, visible): if not self._node: return if not self._stack: self._node.addDecorator(SettingOverrideDecorator()) self._stack = self._node.callDecoration("getStack") settings = self._stack.getTop() all_instances = settings.findInstances() visibility_changed = False # Flag to check if at the end the signal needs to be emitted # Remove all instances that are not in visibility list for instance in all_instances: if instance.definition.key not in visible: settings.removeInstance(instance.definition.key) visibility_changed = True # Add all instances that are not added, but are in visibility list for item in visible: if not settings.getInstance(item): definition = self._stack.getSettingDefinition(item) if definition: new_instance = SettingInstance(definition, settings) stack_nr = -1 if definition.limit_to_extruder and self._stack.getProperty("machine_extruder_count", "value") > 1: # Obtain the value from the correct container stack. Only once, upon adding the setting. stack_nr = str( int(round(float(self._stack.getProperty(item, "limit_to_extruder")))) ) # Stack to get the setting from. Round it and remove the fractional part. if stack_nr not in ExtruderManager.getInstance().extruderIds and self._stack.getProperty( "extruder_nr", "value" ): # Property not defined, but we have an extruder number. stack_nr = str(int(round(float(self._stack.getProperty("extruder_nr", "value"))))) if ( stack_nr in ExtruderManager.getInstance().extruderIds ): # We have either a limit_to_extruder or an extruder_nr. stack = UM.Settings.ContainerRegistry.getInstance().findContainerStacks( id=ExtruderManager.getInstance().extruderIds[stack_nr] )[0] else: stack = UM.Application.getInstance().getGlobalContainerStack() new_instance.setProperty("value", stack.getRawProperty(item, "value")) new_instance.resetState() # Ensure that the state is not seen as a user state. settings.addInstance(new_instance) visibility_changed = True else: Logger.log( "w", "Unable to add instance (%s) to per-object visibility because we couldn't find the matching definition", item, ) if visibility_changed: self.visibilityChanged.emit()
def setVisible(self, visible): if not self._node: return if not self._stack: self._node.addDecorator(SettingOverrideDecorator()) self._stack = self._node.callDecoration("getStack") settings = self._stack.getTop() all_instances = settings.findInstances() visibility_changed = False # Flag to check if at the end the signal needs to be emitted # Remove all instances that are not in visibility list for instance in all_instances: # exceptionally skip setting if instance.definition.key in self._skip_reset_setting_set: continue if instance.definition.key not in visible: settings.removeInstance(instance.definition.key) visibility_changed = True # Add all instances that are not added, but are in visibility list for item in visible: if not settings.getInstance(item): # Setting was not added already. definition = self._stack.getSettingDefinition(item) if definition: new_instance = SettingInstance(definition, settings) stack_nr = -1 stack = None # Check from what stack we should copy the raw property of the setting from. if self._stack.getProperty("machine_extruder_count", "value") > 1: if definition.limit_to_extruder != "-1": # A limit to extruder function was set and it's a multi extrusion machine. Check what stack we do need to use. stack_nr = str(int(round(float(self._stack.getProperty(item, "limit_to_extruder"))))) # Check if the found stack_number is in the extruder list of extruders. if stack_nr not in ExtruderManager.getInstance().extruderIds and self._stack.getProperty("extruder_nr", "value") is not None: stack_nr = -1 # Use the found stack number to get the right stack to copy the value from. if stack_nr in ExtruderManager.getInstance().extruderIds: stack = ContainerRegistry.getInstance().findContainerStacks(id = ExtruderManager.getInstance().extruderIds[stack_nr])[0] else: stack = self._stack # Use the raw property to set the value (so the inheritance doesn't break) if stack is not None: new_instance.setProperty("value", stack.getRawProperty(item, "value")) else: new_instance.setProperty("value", None) new_instance.resetState() # Ensure that the state is not seen as a user state. settings.addInstance(new_instance) visibility_changed = True else: Logger.log("w", "Unable to add instance (%s) to per-object visibility because we couldn't find the matching definition", item) if visibility_changed: self.visibilityChanged.emit()
def setVisible(self, visible): if not self._node: return if not self._stack: self._node.addDecorator(SettingOverrideDecorator()) self._stack = self._node.callDecoration("getStack") settings = self._stack.getTop() all_instances = settings.findInstances() visibility_changed = False # Flag to check if at the end the signal needs to be emitted # Remove all instances that are not in visibility list for instance in all_instances: if instance.definition.key not in visible: settings.removeInstance(instance.definition.key) visibility_changed = True # Add all instances that are not added, but are in visibility list for item in visible: if not settings.getInstance(item): definition = self._stack.getSettingDefinition(item) if definition: settings.addInstance(SettingInstance(definition, settings)) visibility_changed = True else: Logger.log( "w", "Unable to add instance (%s) to perobject visibility because we couldn't find the matching definition", item) if visibility_changed: self.visibilityChanged.emit()
def _instantiateMissingSettingInstancesInCache(self) -> None: """Creates SettingInstances that are missing in this InstanceContainer from the cache if any. This function will **ONLY instantiate SettingInstances. The cached values will not be applied.** """ if not self._cached_values: return for key, value in self._cached_values.items(): if key not in self._instances: if not self.getDefinition(): Logger.log( "w", "Tried to set value of setting %s that has no instance in container %s and the container has no definition", key, self.getName()) return setting_definition = self.getDefinition().findDefinitions( key=key) if not setting_definition: Logger.log( "w", "Tried to set value of setting %s that has no instance in container %s or its definition %s", key, self.getName(), self.getDefinition().getName()) return instance = SettingInstance(setting_definition[0], self) instance.propertyChanged.connect(self.propertyChanged) self._instances[instance.definition.key] = instance
def _instantiateMissingSettingInstancesInCache(self) -> None: if not self._cached_values: return for key, value in self._cached_values.items(): if key not in self._instances: if not self.getDefinition(): Logger.log( "w", "Tried to set value of setting %s that has no instance in container %s and the container has no definition", key, self.getName()) return setting_definition = self.getDefinition().findDefinitions( key=key) if not setting_definition: Logger.log( "w", "Tried to set value of setting %s that has no instance in container %s or its definition %s", key, self.getName(), self.getDefinition().getName()) return instance = SettingInstance(setting_definition[0], self) instance.propertyChanged.connect(self.propertyChanged) self._instances[instance.definition.key] = instance
def setProperty(self, key, property_name, property_value, container = None, set_from_cache = False): if self._read_only and not set_from_cache: Logger.log( "w", "Tried to setProperty [%s] with value [%s] with key [%s] on read-only object [%s]" % ( property_name, property_value, key, self.id)) return if key not in self._instances: if not self._definition: Logger.log("w", "Tried to set value of setting %s that has no instance in container %s and the container has no definition", key, self._name) return setting_definition = self._definition.findDefinitions(key = key) if not setting_definition: Logger.log("w", "Tried to set value of setting %s that has no instance in container %s or its definition %s", key, self._name, self._definition.getName()) return instance = SettingInstance(setting_definition[0], self) instance.propertyChanged.connect(self.propertyChanged) self._instances[instance.definition.key] = instance self._instances[key].setProperty(property_name, property_value, container) if not set_from_cache: self.setDirty(True)
def setProperty(self, key: str, property_name: str, property_value: Any, container: ContainerInterface = None, set_from_cache: bool = False) -> None: if self._read_only and not set_from_cache: Logger.log( "w", "Tried to setProperty [%s] with value [%s] with key [%s] on read-only object [%s]" % ( property_name, property_value, key, self.id)) return if key not in self._instances: if not self.getDefinition(): Logger.log("w", "Tried to set value of setting %s that has no instance in container %s and the container has no definition", key, self.getName()) return setting_definition = self.getDefinition().findDefinitions(key = key) if not setting_definition: Logger.log("w", "Tried to set value of setting %s that has no instance in container %s or its definition %s", key, self.getName(), self.getDefinition().getName()) return instance = SettingInstance(setting_definition[0], self) instance.propertyChanged.connect(self.propertyChanged) self._instances[instance.definition.key] = instance # Do not emit any signal if the value is set from cache self._instances[key].setProperty(property_name, property_value, container, emit_signals = not set_from_cache) if not set_from_cache: self.setDirty(True)
def setMeshType(self, mesh_type): selected_object = Selection.getSelectedObject(0) stack = selected_object.callDecoration("getStack") #Don't try to get the active extruder since it may be None anyway. if not stack: selected_object.addDecorator(SettingOverrideDecorator()) stack = selected_object.callDecoration("getStack") settings = stack.getTop() for property_key in ["infill_mesh", "cutting_mesh", "support_mesh", "anti_overhang_mesh"]: if property_key != mesh_type: if settings.getInstance(property_key): settings.removeInstance(property_key) else: if not (settings.getInstance(property_key) and settings.getProperty(property_key, "value")): definition = stack.getSettingDefinition(property_key) new_instance = SettingInstance(definition, settings) new_instance.setProperty("value", True) new_instance.resetState() # Ensure that the state is not seen as a user state. settings.addInstance(new_instance)
def setMeshType(self, mesh_type): selected_object = Selection.getSelectedObject(0) stack = selected_object.callDecoration( "getStack" ) #Don't try to get the active extruder since it may be None anyway. if not stack: selected_object.addDecorator(SettingOverrideDecorator()) stack = selected_object.callDecoration("getStack") settings = stack.getTop() for property_key in [ "infill_mesh", "cutting_mesh", "support_mesh", "anti_overhang_mesh" ]: if property_key != mesh_type: if settings.getInstance(property_key): settings.removeInstance(property_key) else: if not (settings.getInstance(property_key) and settings.getProperty(property_key, "value")): definition = stack.getSettingDefinition(property_key) new_instance = SettingInstance(definition, settings) new_instance.setProperty("value", True) new_instance.resetState( ) # Ensure that the state is not seen as a user state. settings.addInstance(new_instance)
def setVisible(self, visible): if not self._node: return if not self._stack: self._node.addDecorator(SettingOverrideDecorator()) self._stack = self._node.callDecoration("getStack") settings = self._stack.getTop() all_instances = settings.findInstances() visibility_changed = False # Flag to check if at the end the signal needs to be emitted # Remove all instances that are not in visibility list for instance in all_instances: if instance.definition.key not in visible: settings.removeInstance(instance.definition.key) visibility_changed = True # Add all instances that are not added, but are in visibility list for item in visible: if not settings.getInstance(item): # Setting was not added already. definition = self._stack.getSettingDefinition(item) if definition: new_instance = SettingInstance(definition, settings) stack_nr = -1 stack = None # Check from what stack we should copy the raw property of the setting from. if self._stack.getProperty("machine_extruder_count", "value") > 1: if definition.limit_to_extruder != "-1": # A limit to extruder function was set and it's a multi extrusion machine. Check what stack we do need to use. stack_nr = str(int(round(float(self._stack.getProperty(item, "limit_to_extruder"))))) # Check if the found stack_number is in the extruder list of extruders. if stack_nr not in ExtruderManager.getInstance().extruderIds and self._stack.getProperty("extruder_nr", "value") is not None: stack_nr = -1 # Use the found stack number to get the right stack to copy the value from. if stack_nr in ExtruderManager.getInstance().extruderIds: stack = ContainerRegistry.getInstance().findContainerStacks(id = ExtruderManager.getInstance().extruderIds[stack_nr])[0] else: stack = self._stack # Use the raw property to set the value (so the inheritance doesn't break) if stack is not None: new_instance.setProperty("value", stack.getRawProperty(item, "value")) else: new_instance.setProperty("value", None) new_instance.resetState() # Ensure that the state is not seen as a user state. settings.addInstance(new_instance) visibility_changed = True else: Logger.log("w", "Unable to add instance (%s) to per-object visibility because we couldn't find the matching definition", item) if visibility_changed: self.visibilityChanged.emit()
def setNextStack(self, stack: ContainerStack) -> None: super().setNextStack(stack) stack.addExtruder(self) self.addMetaDataEntry("machine", stack.id) # For backward compatibility: Register the extruder with the Extruder Manager ExtruderManager.getInstance().registerExtruder(self, stack.id) # Now each machine will have at least one extruder stack. If this is the first extruder, the extruder-specific # settings such as nozzle size and material diameter should be moved from the machine's definition_changes to # the this extruder's definition_changes. # # We do this here because it is tooooo expansive to do it in the version upgrade: During the version upgrade, # when we are upgrading a definition_changes container file, there is NO guarantee that other files such as # machine an extruder stack files are upgraded before this, so we cannot read those files assuming they are in # the latest format. if self.getMetaDataEntry("position") == "0": for key in _EXTRUDER_SPECIFIC_DEFINITION_CHANGES_SETTINGS: setting_value = stack.definitionChanges.getProperty( key, "value") if setting_value is None: continue setting_definition = stack.getSettingDefinition(key) new_instance = SettingInstance(setting_definition, self.definitionChanges) new_instance.setProperty("value", setting_value) new_instance.resetState( ) # Ensure that the state is not seen as a user state. self.definitionChanges.addInstance(new_instance) self.definitionChanges.setDirty(True) stack.definitionChanges.removeInstance(key, postpone_emit=True)
def _createEraserMesh(self, parent: CuraSceneNode, position: Vector): node = CuraSceneNode() node.setName("Eraser") node.setSelectable(True) node.setCalculateBoundingBox(True) mesh = self._createCube(10) node.setMeshData(mesh.build()) node.calculateBoundingBoxMesh() active_build_plate = CuraApplication.getInstance().getMultiBuildPlateModel().activeBuildPlate node.addDecorator(BuildPlateDecorator(active_build_plate)) node.addDecorator(SliceableObjectDecorator()) stack = node.callDecoration("getStack") # created by SettingOverrideDecorator that is automatically added to CuraSceneNode settings = stack.getTop() definition = stack.getSettingDefinition("anti_overhang_mesh") new_instance = SettingInstance(definition, settings) new_instance.setProperty("value", True) new_instance.resetState() # Ensure that the state is not seen as a user state. settings.addInstance(new_instance) op = GroupedOperation() # First add node to the scene at the correct position/scale, before parenting, so the eraser mesh does not get scaled with the parent op.addOperation(AddSceneNodeOperation(node, self._controller.getScene().getRoot())) op.addOperation(SetParentOperation(node, parent)) op.push() node.setPosition(position, CuraSceneNode.TransformSpace.World) CuraApplication.getInstance().getController().getScene().sceneChanged.emit(node)
def _createEraserMesh(self, parent: CuraSceneNode, position: Vector): node = CuraSceneNode() node.setName("Eraser") node.setSelectable(True) mesh = MeshBuilder() mesh.addCube(10,10,10) node.setMeshData(mesh.build()) active_build_plate = Application.getInstance().getMultiBuildPlateModel().activeBuildPlate node.addDecorator(BuildPlateDecorator(active_build_plate)) node.addDecorator(SliceableObjectDecorator()) stack = node.callDecoration("getStack") # created by SettingOverrideDecorator that is automatically added to CuraSceneNode settings = stack.getTop() definition = stack.getSettingDefinition("anti_overhang_mesh") new_instance = SettingInstance(definition, settings) new_instance.setProperty("value", True) new_instance.resetState() # Ensure that the state is not seen as a user state. settings.addInstance(new_instance) op = AddSceneNodeOperation(node, parent) op.push() node.setPosition(position, CuraSceneNode.TransformSpace.World) Application.getInstance().getController().getScene().sceneChanged.emit(node)
def setVisible(self, visible): if not self._node: return if not self._stack: self._node.addDecorator(SettingOverrideDecorator()) self._stack = self._node.callDecoration("getStack") settings = self._stack.getTop() all_instances = settings.findInstances() visibility_changed = False # Flag to check if at the end the signal needs to be emitted # Remove all instances that are not in visibility list for instance in all_instances: if instance.definition.key not in visible: settings.removeInstance(instance.definition.key) visibility_changed = True # Add all instances that are not added, but are in visibility list for item in visible: if not settings.getInstance(item): definition = self._stack.getSettingDefinition(item) if definition: new_instance = SettingInstance(definition, settings) if definition.global_inherits_stack and self._stack.getProperty("machine_extruder_count", "value") > 1: #Obtain the value from the correct container stack. Only once, upon adding the setting. stack_nr = self._stack.getProperty(item, "global_inherits_stack") #Stack to get the setting from. if float(stack_nr) >= 0: #Only if it defines an extruder stack. extruder_stack = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = ExtruderManager.getInstance().extruderIds[stack_nr])[0] new_instance.setProperty("value", extruder_stack.getProperty(item, "value")) settings.addInstance(new_instance) visibility_changed = True else: Logger.log("w", "Unable to add instance (%s) to per-object visibility because we couldn't find the matching definition", item) if visibility_changed: self.visibilityChanged.emit()
def setNextStack(self, stack: ContainerStack) -> None: super().setNextStack(stack) stack.addExtruder(self) self.addMetaDataEntry("machine", stack.id) # For backward compatibility: Register the extruder with the Extruder Manager ExtruderManager.getInstance().registerExtruder(self, stack.id) # Now each machine will have at least one extruder stack. If this is the first extruder, the extruder-specific # settings such as nozzle size and material diameter should be moved from the machine's definition_changes to # the this extruder's definition_changes. # # We do this here because it is tooooo expansive to do it in the version upgrade: During the version upgrade, # when we are upgrading a definition_changes container file, there is NO guarantee that other files such as # machine an extruder stack files are upgraded before this, so we cannot read those files assuming they are in # the latest format. # # MORE: # For single-extrusion machines, nozzle size is saved in the global stack, so the nozzle size value should be # carried to the first extruder. # For material diameter, it was supposed to be applied to all extruders, so its value should be copied to all # extruders. keys_to_copy = ["material_diameter", "machine_nozzle_size" ] # these will be copied over to all extruders for key in keys_to_copy: # Since material_diameter is not on the extruder definition, we need to add it here # WARNING: this might be very dangerous and should be refactored ASAP! definition = stack.getSettingDefinition(key) if definition: self.definition.addDefinition(definition) # Only copy the value when this extruder doesn't have the value. if self.definitionChanges.hasProperty(key, "value"): continue setting_value = stack.definitionChanges.getProperty(key, "value") if setting_value is None: continue setting_definition = stack.getSettingDefinition(key) new_instance = SettingInstance(setting_definition, self.definitionChanges) new_instance.setProperty("value", setting_value) new_instance.resetState( ) # Ensure that the state is not seen as a user state. self.definitionChanges.addInstance(new_instance) self.definitionChanges.setDirty(True) # Make sure the material diameter is up to date for the extruder stack. if key == "material_diameter": position = self.getMetaDataEntry("position", "0") Application.getInstance().getExtruderManager( ).updateMaterialForDiameter(position)
def setProperty(self, key: str, property_name: str, property_value: Any, container: ContainerInterface = None, set_from_cache: bool = False) -> None: """Set the value of a property of a SettingInstance. This will set the value of the specified property on the SettingInstance corresponding to key. If no instance has been created for the specified key, a new one will be created and inserted into this instance. :param key: The key of the setting to set a property of. :param property_name: The name of the property to set. :param property_value: The new value of the property. :param container: The container to use for retrieving values when changing the property triggers property updates. Defaults to None, which means use the current container. :param set_from_cache: Flag to indicate that the property was set from cache. This triggers the behavior that the read_only and setDirty are ignored. :note If no definition container is set for this container, new instances cannot be created and this method will do nothing. """ if self._read_only and not set_from_cache: Logger.log( "w", "Tried to setProperty [%s] with value [%s] with key [%s] on read-only object [%s]" % ( property_name, property_value, key, self.id)) return if key not in self._instances: try: definition = self.getDefinition() except DefinitionNotFoundError: Logger.log("w", "Tried to set value of setting when the container has no definition") return setting_definition = definition.findDefinitions(key = key) if not setting_definition: Logger.log("w", "Tried to set value of setting %s that has no instance in container %s or its definition %s", key, self.getName(), self.getDefinition().getName()) return instance = SettingInstance(setting_definition[0], self) instance.propertyChanged.connect(self.propertyChanged) self._instances[instance.definition.key] = instance # Do not emit any signal if the value is set from cache self._instances[key].setProperty(property_name, property_value, container, emit_signals = not set_from_cache) if not set_from_cache: self.setDirty(True)
def _fixMaterialDiameterAndNozzleSize(self, global_stack, extruder_stack_list): keys_to_copy = ["material_diameter", "machine_nozzle_size" ] # these will be copied over to all extruders extruder_positions_to_update = set() for extruder_stack in extruder_stack_list: for key in keys_to_copy: # Only copy the value when this extruder doesn't have the value. if extruder_stack.definitionChanges.hasProperty(key, "value"): continue setting_value_in_global_def_changes = global_stack.definitionChanges.getProperty( key, "value") setting_value_in_global_def = global_stack.definition.getProperty( key, "value") setting_value = setting_value_in_global_def if setting_value_in_global_def_changes is not None: setting_value = setting_value_in_global_def_changes if setting_value == extruder_stack.definition.getProperty( key, "value"): continue setting_definition = global_stack.getSettingDefinition(key) new_instance = SettingInstance( setting_definition, extruder_stack.definitionChanges) new_instance.setProperty("value", setting_value) new_instance.resetState( ) # Ensure that the state is not seen as a user state. extruder_stack.definitionChanges.addInstance(new_instance) extruder_stack.definitionChanges.setDirty(True) # Make sure the material diameter is up to date for the extruder stack. if key == "material_diameter": position = int(extruder_stack.getMetaDataEntry("position")) extruder_positions_to_update.add(position) # We have to remove those settings here because we know that those values have been copied to all # the extruders at this point. for key in keys_to_copy: if global_stack.definitionChanges.hasProperty(key, "value"): global_stack.definitionChanges.removeInstance( key, postpone_emit=True) # Update material diameter for extruders for position in extruder_positions_to_update: self.updateMaterialForDiameter(position, global_stack=global_stack)
def setVisible(self, visible): node = Application.getInstance().getController().getScene().findObject( self._selected_object_id) if not node: return stack = node.callDecoration("getStack") if not stack: node.addDecorator(SettingOverrideDecorator()) stack = node.callDecoration("getStack") settings = stack.getTop() all_instances = settings.findInstances(**{}) visibility_changed = False # Flag to check if at the end the signal needs to be emitted # Remove all instances that are not in visibility list for instance in all_instances: if instance.definition.key not in visible: settings.removeInstance(instance.definition.key) visibility_changed = True # Add all instances that are not added, but are in visiblity list for item in visible: if not settings.getInstance(item): definition_container = Application.getInstance( ).getGlobalContainerStack().getBottom() definitions = definition_container.findDefinitions(key=item) if definitions: settings.addInstance( SettingInstance(definitions[0], settings)) visibility_changed = True else: Logger.log( "w", "Unable to add instance (%s) to perobject visibility because we couldn't find the matching definition", item) if visibility_changed: self.visibilityChanged.emit()
def setVisible(self, visible): if not self._node: return if not self._stack: self._node.addDecorator(SettingOverrideDecorator()) self._stack = self._node.callDecoration("getStack") settings = self._stack.getTop() all_instances = settings.findInstances() visibility_changed = False # Flag to check if at the end the signal needs to be emitted # Remove all instances that are not in visibility list for instance in all_instances: if instance.definition.key not in visible: settings.removeInstance(instance.definition.key) visibility_changed = True # Add all instances that are not added, but are in visibility list for item in visible: if not settings.getInstance(item): definition = self._stack.getSettingDefinition(item) if definition: new_instance = SettingInstance(definition, settings) stack_nr = -1 if definition.global_inherits_stack and self._stack.getProperty("machine_extruder_count", "value") > 1: #Obtain the value from the correct container stack. Only once, upon adding the setting. stack_nr = str(int(round(float(self._stack.getProperty(item, "global_inherits_stack"))))) #Stack to get the setting from. Round it and remove the fractional part. if stack_nr not in ExtruderManager.getInstance().extruderIds and self._stack.getProperty("extruder_nr", "value"): #Property not defined, but we have an extruder number. stack_nr = str(int(round(float(self._stack.getProperty("extruder_nr", "value"))))) if stack_nr in ExtruderManager.getInstance().extruderIds: #We have either a global_inherits_stack or an extruder_nr. stack = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = ExtruderManager.getInstance().extruderIds[stack_nr])[0] else: stack = UM.Application.getInstance().getGlobalContainerStack() new_instance.setProperty("value", stack.getProperty(item, "value")) new_instance.resetState() # Ensure that the state is not seen as a user state. settings.addInstance(new_instance) visibility_changed = True else: Logger.log("w", "Unable to add instance (%s) to per-object visibility because we couldn't find the matching definition", item) if visibility_changed: self.visibilityChanged.emit()
def _createEraserMesh(self): node = CuraSceneNode() node.setName("Eraser") node.setSelectable(True) mesh = MeshBuilder() mesh.addCube(10, 10, 10) node.setMeshData(mesh.build()) # Place the cube in the platform. Do it manually so it works if the "automatic drop models" is OFF move_vector = Vector(0, 5, 0) node.setPosition(move_vector) active_build_plate = Application.getInstance().getMultiBuildPlateModel( ).activeBuildPlate node.addDecorator(SettingOverrideDecorator()) node.addDecorator(BuildPlateDecorator(active_build_plate)) node.addDecorator(SliceableObjectDecorator()) stack = node.callDecoration( "getStack" ) #Don't try to get the active extruder since it may be None anyway. if not stack: node.addDecorator(SettingOverrideDecorator()) stack = node.callDecoration("getStack") settings = stack.getTop() if not (settings.getInstance("anti_overhang_mesh") and settings.getProperty("anti_overhang_mesh", "value")): definition = stack.getSettingDefinition("anti_overhang_mesh") new_instance = SettingInstance(definition, settings) new_instance.setProperty("value", True) new_instance.resetState( ) # Ensure that the state is not seen as a user state. settings.addInstance(new_instance) scene = self._controller.getScene() op = AddSceneNodeOperation(node, scene.getRoot()) op.push() Application.getInstance().getController().getScene().sceneChanged.emit( node)
def setMeshType(self, mesh_type: str) -> bool: if self.getMeshType() == mesh_type: return False selected_object = Selection.getSelectedObject(0) if selected_object is None: Logger.log( "w", "Tried setting the mesh type of the selected object, but no object was selected" ) return False stack = selected_object.callDecoration( "getStack" ) #Don't try to get the active extruder since it may be None anyway. if not stack: selected_object.addDecorator(SettingOverrideDecorator()) stack = selected_object.callDecoration("getStack") settings = stack.getTop() for property_key in [ "infill_mesh", "cutting_mesh", "support_mesh", "anti_overhang_mesh" ]: if property_key != mesh_type: if settings.getInstance(property_key): settings.removeInstance(property_key) else: if not (settings.getInstance(property_key) and settings.getProperty(property_key, "value")): definition = stack.getSettingDefinition(property_key) new_instance = SettingInstance(definition, settings) new_instance.setProperty("value", True) new_instance.resetState( ) # Ensure that the state is not seen as a user state. settings.addInstance(new_instance) self.propertyChanged.emit() return True
def _createEraserMesh(self, parent: CuraSceneNode, position: Vector): node = CuraSceneNode() node.setName("Eraser") node.setSelectable(True) mesh = MeshBuilder() mesh.addCube(10, 10, 10) node.setMeshData(mesh.build()) node.setPosition(position) active_build_plate = Application.getInstance().getMultiBuildPlateModel( ).activeBuildPlate node.addDecorator(SettingOverrideDecorator()) node.addDecorator(BuildPlateDecorator(active_build_plate)) node.addDecorator(SliceableObjectDecorator()) stack = node.callDecoration( "getStack") # created by SettingOverrideDecorator settings = stack.getTop() definition = stack.getSettingDefinition("anti_overhang_mesh") new_instance = SettingInstance(definition, settings) new_instance.setProperty("value", True) new_instance.resetState( ) # Ensure that the state is not seen as a user state. settings.addInstance(new_instance) root = self._controller.getScene().getRoot() op = GroupedOperation() # First add the node to the scene, so it gets the expected transform op.addOperation(AddSceneNodeOperation(node, root)) op.addOperation(SetParentOperation(node, parent)) op.push() Application.getInstance().getController().getScene().sceneChanged.emit( node)
def _createSupportMesh(self, parent: CuraSceneNode, position: Vector): node = CuraSceneNode() node.setSelectable(True) if self._SupportType == 'cylinder': height = position.y node.setName("CustomSupportCylinder") mesh = self._createCylinder(self._SupportSize,22.5,height) node_position = Vector(position.x,position.y,position.z) else: node.setName("CustomSupportCube") height = position.y-self._SupportSize/2+self._SupportSize*0.1 mesh = self._createCube(self._SupportSize,height) node_position = Vector(position.x,position.y-self._SupportSize/2+self._SupportSize*0.1,position.z) node.setMeshData(mesh.build()) active_build_plate = CuraApplication.getInstance().getMultiBuildPlateModel().activeBuildPlate node.addDecorator(BuildPlateDecorator(active_build_plate)) node.addDecorator(SliceableObjectDecorator()) stack = node.callDecoration("getStack") # created by SettingOverrideDecorator that is automatically added to CuraSceneNode settings = stack.getTop() for key in ["support_mesh", "support_mesh_drop_down"]: definition = stack.getSettingDefinition(key) new_instance = SettingInstance(definition, settings) new_instance.setProperty("value", True) new_instance.resetState() # Ensure that the state is not seen as a user state. settings.addInstance(new_instance) op = GroupedOperation() # First add node to the scene at the correct position/scale, before parenting, so the support mesh does not get scaled with the parent op.addOperation(AddSceneNodeOperation(node, self._controller.getScene().getRoot())) op.addOperation(SetParentOperation(node, parent)) op.push() node.setPosition(node_position, CuraSceneNode.TransformSpace.World) CuraApplication.getInstance().getController().getScene().sceneChanged.emit(node)
def _node(self, mesh, settings): node = CuraSceneNode() node.setMeshData(mesh) node.setSelectable(True) node.addDecorator(SliceableObjectDecorator()) if len(settings) > 0: node.addDecorator(SettingOverrideDecorator()) stack = node.callDecoration('getStack') top = stack.getTop() for k, v in settings.items(): if k == 'extruder': node.callDecoration('setActiveExtruder', v) else: definition = stack.getSettingDefinition(k) instance = SettingInstance(definition, top) instance.setProperty("value", v) instance.resetState() top.addInstance(instance) Logger.log('d', 'node: {0}'.format(node)) return node
def _createSupportMesh(self, parent: CuraSceneNode, position: Vector): node = CuraSceneNode() node.setName("RoundTab") node.setSelectable(True) # long=Support Height _long=position.y # get layer_height_0 used to define pastille height _id_ex=0 # This function can be triggered in the middle of a machine change, so do not proceed if the machine change # has not done yet. global_container_stack = CuraApplication.getInstance().getGlobalContainerStack() #extruder = global_container_stack.extruderList[int(_id_ex)] extruder_stack = CuraApplication.getInstance().getExtruderManager().getActiveExtruderStacks()[0] _layer_h_i = extruder_stack.getProperty("layer_height_0", "value") _layer_height = extruder_stack.getProperty("layer_height", "value") _line_w = extruder_stack.getProperty("line_width", "value") # Logger.log('d', 'layer_height_0 : ' + str(_layer_h_i)) _layer_h = (_layer_h_i * 1.2) + (_layer_height * (self._Nb_Layer -1) ) _line_w = _line_w * 1.2 if self._AsCapsule: # Capsule creation Diameter , Increment angle 4°, length, layer_height_0*1.2 , line_width mesh = self._createCapsule(self._UseSize,4,_long,_layer_h,_line_w) else: # Cylinder creation Diameter , Increment angle 4°, length, layer_height_0*1.2 mesh = self._createPastille(self._UseSize,4,_long,_layer_h) node.setMeshData(mesh.build()) active_build_plate = CuraApplication.getInstance().getMultiBuildPlateModel().activeBuildPlate node.addDecorator(BuildPlateDecorator(active_build_plate)) node.addDecorator(SliceableObjectDecorator()) stack = node.callDecoration("getStack") # created by SettingOverrideDecorator that is automatically added to CuraSceneNode settings = stack.getTop() # support_mesh type definition = stack.getSettingDefinition("support_mesh") new_instance = SettingInstance(definition, settings) new_instance.setProperty("value", True) new_instance.resetState() # Ensure that the state is not seen as a user state. settings.addInstance(new_instance) definition = stack.getSettingDefinition("support_mesh_drop_down") new_instance = SettingInstance(definition, settings) new_instance.setProperty("value", False) new_instance.resetState() # Ensure that the state is not seen as a user state. settings.addInstance(new_instance) if self._AsCapsule: s_p = global_container_stack.getProperty("support_type", "value") if s_p == 'buildplate' : Message(text = "Info modification current profile support_type parameter\nNew value : everywhere", title = catalog.i18nc("@info:title", "Warning ! Tab Anti Warping")).show() Logger.log('d', 'support_type different : ' + str(s_p)) # Define support_type=everywhere global_container_stack.setProperty("support_type", "value", 'everywhere') # Define support_xy_distance definition = stack.getSettingDefinition("support_xy_distance") new_instance = SettingInstance(definition, settings) new_instance.setProperty("value", self._UseOffset) # new_instance.resetState() # Ensure that the state is not seen as a user state. settings.addInstance(new_instance) # Fix some settings in Cura to get a better result id_ex=0 global_container_stack = CuraApplication.getInstance().getGlobalContainerStack() extruder_stack = CuraApplication.getInstance().getExtruderManager().getActiveExtruderStacks()[0] #extruder = global_container_stack.extruderList[int(id_ex)] # hop to fix it in a futur release # https://github.com/Ultimaker/Cura/issues/9882 # if self.Major < 5 or ( self.Major == 5 and self.Minor < 1 ) : _xy_distance = extruder_stack.getProperty("support_xy_distance", "value") if self._UseOffset != _xy_distance : _msg = "New value : %8.3f" % (self._UseOffset) Message(text = "Info modification current profile support_xy_distance parameter\nNew value : %8.3f" % (self._UseOffset), title = catalog.i18nc("@info:title", "Warning ! Tab Anti Warping")).show() Logger.log('d', 'support_xy_distance different : ' + str(_xy_distance)) # Define support_xy_distance extruder_stack.setProperty("support_xy_distance", "value", self._UseOffset) if self._Nb_Layer >1 : s_p = int(extruder_stack.getProperty("support_infill_rate", "value")) Logger.log('d', 'support_infill_rate actual : ' + str(s_p)) if s_p < 99 : Message(text = "Info modification current profile support_infill_rate parameter\nNew value : 100%", title = catalog.i18nc("@info:title", "Warning ! Tab Anti Warping")).show() Logger.log('d', 'support_infill_rate different : ' + str(s_p)) # Define support_infill_rate=100% extruder_stack.setProperty("support_infill_rate", "value", 100) op = GroupedOperation() # First add node to the scene at the correct position/scale, before parenting, so the support mesh does not get scaled with the parent op.addOperation(AddSceneNodeOperation(node, self._controller.getScene().getRoot())) op.addOperation(SetParentOperation(node, parent)) op.push() node.setPosition(position, CuraSceneNode.TransformSpace.World) CuraApplication.getInstance().getController().getScene().sceneChanged.emit(node)
def test_valueChanges(container_registry): setting_property_provider = SettingPropertyProvider() # First create the basics; A container stack that will hold 2 instance containers and a single definition container container_stack = ContainerStack("test!") instance_container = InstanceContainer("data") second_instance_container = InstanceContainer("data2") definition_container = DefinitionContainer("foo") # Create a setting definition for our one and only setting! setting_definition = SettingDefinition("test_setting") setting_definition._deserialize_dict({"value": 10, "label": "blorp", "type": "float", "description": "nah", "maximum_value": 23, "maximum_value_warning": 21, "enabled": "test_setting != 20"}) definition_container.addDefinition(setting_definition) # Make a single setting instance for our one and only setting. setting_instance = SettingInstance(setting_definition, instance_container) setting_instance.setProperty("value", 20) setting_instance.setProperty("enabled", False) instance_container.addInstance(setting_instance) # Make a setting instance that lives in our second instance_container setting_instance2 = SettingInstance(setting_definition, second_instance_container) second_instance_container.addInstance(setting_instance2) # Now that both containers are done, actually add them. container_stack.addContainer(definition_container) container_stack.addContainer(second_instance_container) container_stack.addContainer(instance_container) setting_property_provider.setContainerStack(container_stack) setting_property_provider.setKey("test_setting") assert setting_property_provider.key == "test_setting" assert setting_property_provider.getPropertyValue("value", 0) == 20 setting_property_provider.setWatchedProperties(["enabled", "value", "validationState"]) setting_property_provider._update() assert setting_property_provider.watchedProperties == ["enabled", "value", "validationState"] assert setting_property_provider.properties.value("enabled") == "False" assert setting_property_provider.properties.value("value") == "20" # Validator state is a special property that gets added based on the type and the value assert setting_property_provider.properties.value("validationState") == str(ValidatorState.Valid) # Set the property value to something that will trigger a warning setting_property_provider.setPropertyValue("value", 22) assert setting_property_provider.properties.value("validationState") == str(ValidatorState.MaximumWarning) assert setting_property_provider.getPropertyValue("value", 0) == 22 # The setting doesn't exist in our second instance container, so this should be None assert setting_property_provider.getPropertyValue("value", 1) is None # Set the property value to something that will trigger an error setting_property_provider.setPropertyValue("value", 25) # The Qtimer that we use to prevent flooding doesn't work in tests, so tickle the change manually. setting_property_provider._update() assert setting_property_provider.properties.value("validationState") == str(ValidatorState.MaximumError) # We now ask for the second instance container to be targeted setting_property_provider.setStoreIndex(1) assert setting_property_provider.storeIndex == 1 setting_property_provider.setPropertyValue("value", 2) setting_property_provider._update() # So now we should see a change in that instance container assert setting_property_provider.getPropertyValue("value", 1) == 2 # But not if we ask the provider, because the container above it still has a 25 as value! assert setting_property_provider.getPropertyValue("value", 0) == 25 assert setting_property_provider.stackLevels == [0, 1, 2] # We're asking for an index that doesn't exist. assert setting_property_provider.getPropertyValue("value", 2000) is None # The value is used, so the property must be true assert setting_property_provider.isValueUsed # Try to remove the setting from the container setting_property_provider.removeFromContainer(0) assert setting_property_provider.getPropertyValue("value", 0) is None # Ensure that a weird index doesn't break setting_property_provider.removeFromContainer(90001)
def setMeshType(self, mesh_type: str) -> bool: """Returns True when the mesh_type was changed, False when current mesh_type == mesh_type""" old_mesh_type = self.getMeshType() if old_mesh_type == mesh_type: return False selected_object = Selection.getSelectedObject(0) if selected_object is None: Logger.log( "w", "Tried setting the mesh type of the selected object, but no object was selected" ) return False stack = selected_object.callDecoration( "getStack" ) #Don't try to get the active extruder since it may be None anyway. if not stack: selected_object.addDecorator(SettingOverrideDecorator()) stack = selected_object.callDecoration("getStack") settings_visibility_changed = False settings = stack.getTop() for property_key in [ "infill_mesh", "cutting_mesh", "support_mesh", "anti_overhang_mesh" ]: if property_key != mesh_type: if settings.getInstance(property_key): settings.removeInstance(property_key) else: if not (settings.getInstance(property_key) and settings.getProperty(property_key, "value")): definition = stack.getSettingDefinition(property_key) new_instance = SettingInstance(definition, settings) new_instance.setProperty("value", True) new_instance.resetState( ) # Ensure that the state is not seen as a user state. settings.addInstance(new_instance) for property_key in ["top_bottom_thickness", "wall_thickness"]: if mesh_type == "infill_mesh": if settings.getInstance(property_key) is None: definition = stack.getSettingDefinition(property_key) new_instance = SettingInstance(definition, settings) new_instance.setProperty("value", 0) new_instance.resetState( ) # Ensure that the state is not seen as a user state. settings.addInstance(new_instance) settings_visibility_changed = True elif old_mesh_type == "infill_mesh" and settings.getInstance( property_key) and settings.getProperty( property_key, "value") == 0: settings.removeInstance(property_key) settings_visibility_changed = True if settings_visibility_changed: self.visibility_handler.forceVisibilityChanged() self.propertyChanged.emit() return True
def addExtruderStackForSingleExtrusionMachine( self, machine, extruder_id, new_global_quality_changes=None, create_new_ids=True): new_extruder_id = extruder_id application = cura.CuraApplication.CuraApplication.getInstance() extruder_definitions = self.findDefinitionContainers( id=new_extruder_id) if not extruder_definitions: Logger.log("w", "Could not find definition containers for extruder %s", new_extruder_id) return extruder_definition = extruder_definitions[0] unique_name = self.uniqueName( machine.getName() + " " + new_extruder_id ) if create_new_ids else machine.getName() + " " + new_extruder_id extruder_stack = ExtruderStack.ExtruderStack(unique_name) extruder_stack.setName(extruder_definition.getName()) extruder_stack.setDefinition(extruder_definition) extruder_stack.setMetaDataEntry( "position", extruder_definition.getMetaDataEntry("position")) # create a new definition_changes container for the extruder stack definition_changes_id = self.uniqueName( extruder_stack.getId() + "_settings" ) if create_new_ids else extruder_stack.getId() + "_settings" definition_changes_name = definition_changes_id definition_changes = InstanceContainer(definition_changes_id, parent=application) definition_changes.setName(definition_changes_name) definition_changes.setMetaDataEntry("setting_version", application.SettingVersion) definition_changes.setMetaDataEntry("type", "definition_changes") definition_changes.setMetaDataEntry("definition", extruder_definition.getId()) # move definition_changes settings if exist for setting_key in definition_changes.getAllKeys(): if machine.definition.getProperty(setting_key, "settable_per_extruder"): setting_value = machine.definitionChanges.getProperty( setting_key, "value") if setting_value is not None: # move it to the extruder stack's definition_changes setting_definition = machine.getSettingDefinition( setting_key) new_instance = SettingInstance(setting_definition, definition_changes) new_instance.setProperty("value", setting_value) new_instance.resetState( ) # Ensure that the state is not seen as a user state. definition_changes.addInstance(new_instance) definition_changes.setDirty(True) machine.definitionChanges.removeInstance( setting_key, postpone_emit=True) self.addContainer(definition_changes) extruder_stack.setDefinitionChanges(definition_changes) # create empty user changes container otherwise user_container_id = self.uniqueName( extruder_stack.getId() + "_user") if create_new_ids else extruder_stack.getId() + "_user" user_container_name = user_container_id user_container = InstanceContainer(user_container_id, parent=application) user_container.setName(user_container_name) user_container.setMetaDataEntry("type", "user") user_container.setMetaDataEntry("machine", machine.getId()) user_container.setMetaDataEntry("setting_version", application.SettingVersion) user_container.setDefinition(machine.definition.getId()) user_container.setMetaDataEntry( "position", extruder_stack.getMetaDataEntry("position")) if machine.userChanges: # For the newly created extruder stack, we need to move all "per-extruder" settings to the user changes # container to the extruder stack. for user_setting_key in machine.userChanges.getAllKeys(): settable_per_extruder = machine.getProperty( user_setting_key, "settable_per_extruder") if settable_per_extruder: setting_value = machine.getProperty( user_setting_key, "value") setting_definition = machine.getSettingDefinition( user_setting_key) new_instance = SettingInstance(setting_definition, definition_changes) new_instance.setProperty("value", setting_value) new_instance.resetState( ) # Ensure that the state is not seen as a user state. user_container.addInstance(new_instance) user_container.setDirty(True) machine.userChanges.removeInstance(user_setting_key, postpone_emit=True) self.addContainer(user_container) extruder_stack.setUserChanges(user_container) empty_variant = application.empty_variant_container empty_material = application.empty_material_container empty_quality = application.empty_quality_container if machine.variant.getId() not in ("empty", "empty_variant"): variant = machine.variant else: variant = empty_variant extruder_stack.variant = variant if machine.material.getId() not in ("empty", "empty_material"): material = machine.material else: material = empty_material extruder_stack.material = material if machine.quality.getId() not in ("empty", "empty_quality"): quality = machine.quality else: quality = empty_quality extruder_stack.quality = quality machine_quality_changes = machine.qualityChanges if new_global_quality_changes is not None: machine_quality_changes = new_global_quality_changes if machine_quality_changes.getId() not in ("empty", "empty_quality_changes"): extruder_quality_changes_container = self.findInstanceContainers( name=machine_quality_changes.getName(), extruder=extruder_id) if extruder_quality_changes_container: extruder_quality_changes_container = extruder_quality_changes_container[ 0] quality_changes_id = extruder_quality_changes_container.getId() extruder_stack.qualityChanges = self.findInstanceContainers( id=quality_changes_id)[0] else: # Some extruder quality_changes containers can be created at runtime as files in the qualities # folder. Those files won't be loaded in the registry immediately. So we also need to search # the folder to see if the quality_changes exists. extruder_quality_changes_container = self._findQualityChangesContainerInCuraFolder( machine_quality_changes.getName()) if extruder_quality_changes_container: quality_changes_id = extruder_quality_changes_container.getId( ) extruder_quality_changes_container.setMetaDataEntry( "position", extruder_definition.getMetaDataEntry("position")) extruder_stack.qualityChanges = self.findInstanceContainers( id=quality_changes_id)[0] else: # If we still cannot find a quality changes container for the extruder, create a new one container_name = machine_quality_changes.getName() container_id = self.uniqueName(extruder_stack.getId() + "_qc_" + container_name) extruder_quality_changes_container = InstanceContainer( container_id, parent=application) extruder_quality_changes_container.setName(container_name) extruder_quality_changes_container.setMetaDataEntry( "type", "quality_changes") extruder_quality_changes_container.setMetaDataEntry( "setting_version", application.SettingVersion) extruder_quality_changes_container.setMetaDataEntry( "position", extruder_definition.getMetaDataEntry("position")) extruder_quality_changes_container.setMetaDataEntry( "quality_type", machine_quality_changes.getMetaDataEntry( "quality_type")) extruder_quality_changes_container.setDefinition( machine_quality_changes.getDefinition().getId()) self.addContainer(extruder_quality_changes_container) extruder_stack.qualityChanges = extruder_quality_changes_container if not extruder_quality_changes_container: Logger.log( "w", "Could not find quality_changes named [%s] for extruder [%s]", machine_quality_changes.getName(), extruder_stack.getId()) else: # Move all per-extruder settings to the extruder's quality changes for qc_setting_key in machine_quality_changes.getAllKeys(): settable_per_extruder = machine.getProperty( qc_setting_key, "settable_per_extruder") if settable_per_extruder: setting_value = machine_quality_changes.getProperty( qc_setting_key, "value") setting_definition = machine.getSettingDefinition( qc_setting_key) new_instance = SettingInstance(setting_definition, definition_changes) new_instance.setProperty("value", setting_value) new_instance.resetState( ) # Ensure that the state is not seen as a user state. extruder_quality_changes_container.addInstance( new_instance) extruder_quality_changes_container.setDirty(True) machine_quality_changes.removeInstance( qc_setting_key, postpone_emit=True) else: extruder_stack.qualityChanges = self.findInstanceContainers( id="empty_quality_changes")[0] self.addContainer(extruder_stack) # Also need to fix the other qualities that are suitable for this machine. Those quality changes may still have # per-extruder settings in the container for the machine instead of the extruder. if machine_quality_changes.getId() not in ("empty", "empty_quality_changes"): quality_changes_machine_definition_id = machine_quality_changes.getDefinition( ).getId() else: whole_machine_definition = machine.definition machine_entry = machine.definition.getMetaDataEntry("machine") if machine_entry is not None: container_registry = ContainerRegistry.getInstance() whole_machine_definition = container_registry.findDefinitionContainers( id=machine_entry)[0] quality_changes_machine_definition_id = "fdmprinter" if whole_machine_definition.getMetaDataEntry( "has_machine_quality"): quality_changes_machine_definition_id = machine.definition.getMetaDataEntry( "quality_definition", whole_machine_definition.getId()) qcs = self.findInstanceContainers( type="quality_changes", definition=quality_changes_machine_definition_id) qc_groups = {} # map of qc names -> qc containers for qc in qcs: qc_name = qc.getName() if qc_name not in qc_groups: qc_groups[qc_name] = [] qc_groups[qc_name].append(qc) # Try to find from the quality changes cura directory too quality_changes_container = self._findQualityChangesContainerInCuraFolder( machine_quality_changes.getName()) if quality_changes_container: qc_groups[qc_name].append(quality_changes_container) for qc_name, qc_list in qc_groups.items(): qc_dict = {"global": None, "extruders": []} for qc in qc_list: extruder_position = qc.getMetaDataEntry("position") if extruder_position is not None: qc_dict["extruders"].append(qc) else: qc_dict["global"] = qc if qc_dict["global"] is not None and len( qc_dict["extruders"]) == 1: # Move per-extruder settings for qc_setting_key in qc_dict["global"].getAllKeys(): settable_per_extruder = machine.getProperty( qc_setting_key, "settable_per_extruder") if settable_per_extruder: setting_value = qc_dict["global"].getProperty( qc_setting_key, "value") setting_definition = machine.getSettingDefinition( qc_setting_key) new_instance = SettingInstance(setting_definition, definition_changes) new_instance.setProperty("value", setting_value) new_instance.resetState( ) # Ensure that the state is not seen as a user state. qc_dict["extruders"][0].addInstance(new_instance) qc_dict["extruders"][0].setDirty(True) qc_dict["global"].removeInstance(qc_setting_key, postpone_emit=True) # Set next stack at the end extruder_stack.setNextStack(machine) return extruder_stack
def importProfile(self, file_name: str) -> Dict[str, str]: Logger.log("d", "Attempting to import profile %s", file_name) if not file_name: return { "status": "error", "message": catalog.i18nc( "@info:status Don't translate the XML tags <filename>!", "Failed to import profile from <filename>{0}</filename>: {1}", file_name, "Invalid path") } global_stack = Application.getInstance().getGlobalContainerStack() if not global_stack: return { "status": "error", "message": catalog.i18nc( "@info:status Don't translate the XML tags <filename>!", "Can't import profile from <filename>{0}</filename> before a printer is added.", file_name) } machine_extruders = [] for position in sorted(global_stack.extruders): machine_extruders.append(global_stack.extruders[position]) plugin_registry = PluginRegistry.getInstance() extension = file_name.split(".")[-1] for plugin_id, meta_data in self._getIOPlugins("profile_reader"): if meta_data["profile_reader"][0]["extension"] != extension: continue profile_reader = cast(ProfileReader, plugin_registry.getPluginObject(plugin_id)) try: profile_or_list = profile_reader.read( file_name) # Try to open the file with the profile reader. except NoProfileException: return { "status": "ok", "message": catalog.i18nc( "@info:status Don't translate the XML tags <filename>!", "No custom profile to import in file <filename>{0}</filename>", file_name) } except Exception as e: # Note that this will fail quickly. That is, if any profile reader throws an exception, it will stop reading. It will only continue reading if the reader returned None. Logger.log( "e", "Failed to import profile from %s: %s while using profile reader. Got exception %s", file_name, profile_reader.getPluginId(), str(e)) return { "status": "error", "message": catalog.i18nc( "@info:status Don't translate the XML tags <filename>!", "Failed to import profile from <filename>{0}</filename>:", file_name) + "\n<message>" + str(e) + "</message>" } if profile_or_list: # Ensure it is always a list of profiles if not isinstance(profile_or_list, list): profile_or_list = [profile_or_list] # First check if this profile is suitable for this machine global_profile = None extruder_profiles = [] if len(profile_or_list) == 1: global_profile = profile_or_list[0] else: for profile in profile_or_list: if not profile.getMetaDataEntry("position"): global_profile = profile else: extruder_profiles.append(profile) extruder_profiles = sorted( extruder_profiles, key=lambda x: int(x.getMetaDataEntry("position"))) profile_or_list = [global_profile] + extruder_profiles if not global_profile: Logger.log( "e", "Incorrect profile [%s]. Could not find global profile", file_name) return { "status": "error", "message": catalog.i18nc( "@info:status Don't translate the XML tags <filename>!", "This profile <filename>{0}</filename> contains incorrect data, could not import it.", file_name) } profile_definition = global_profile.getMetaDataEntry( "definition") # Make sure we have a profile_definition in the file: if profile_definition is None: break machine_definitions = self.findDefinitionContainers( id=profile_definition) if not machine_definitions: Logger.log( "e", "Incorrect profile [%s]. Unknown machine type [%s]", file_name, profile_definition) return { "status": "error", "message": catalog.i18nc( "@info:status Don't translate the XML tags <filename>!", "This profile <filename>{0}</filename> contains incorrect data, could not import it.", file_name) } machine_definition = machine_definitions[0] # Get the expected machine definition. # i.e.: We expect gcode for a UM2 Extended to be defined as normal UM2 gcode... profile_definition = getMachineDefinitionIDForQualitySearch( machine_definition) expected_machine_definition = getMachineDefinitionIDForQualitySearch( global_stack.definition) # And check if the profile_definition matches either one (showing error if not): if profile_definition != expected_machine_definition: Logger.log( "e", "Profile [%s] is for machine [%s] but the current active machine is [%s]. Will not import the profile", file_name, profile_definition, expected_machine_definition) return { "status": "error", "message": catalog.i18nc( "@info:status Don't translate the XML tags <filename>!", "The machine defined in profile <filename>{0}</filename> ({1}) doesn't match with your current machine ({2}), could not import it.", file_name, profile_definition, expected_machine_definition) } # Fix the global quality profile's definition field in case it's not correct global_profile.setMetaDataEntry("definition", expected_machine_definition) quality_name = global_profile.getName() quality_type = global_profile.getMetaDataEntry("quality_type") name_seed = os.path.splitext(os.path.basename(file_name))[0] new_name = self.uniqueName(name_seed) # Ensure it is always a list of profiles if type(profile_or_list) is not list: profile_or_list = [profile_or_list] # Make sure that there are also extruder stacks' quality_changes, not just one for the global stack if len(profile_or_list) == 1: global_profile = profile_or_list[0] extruder_profiles = [] for idx, extruder in enumerate( global_stack.extruders.values()): profile_id = ContainerRegistry.getInstance( ).uniqueName(global_stack.getId() + "_extruder_" + str(idx + 1)) profile = InstanceContainer(profile_id) profile.setName(quality_name) profile.setMetaDataEntry( "setting_version", cura.CuraApplication. CuraApplication.SettingVersion) profile.setMetaDataEntry("type", "quality_changes") profile.setMetaDataEntry("definition", expected_machine_definition) profile.setMetaDataEntry("quality_type", quality_type) profile.setMetaDataEntry("position", "0") profile.setDirty(True) if idx == 0: # Move all per-extruder settings to the first extruder's quality_changes for qc_setting_key in global_profile.getAllKeys(): settable_per_extruder = global_stack.getProperty( qc_setting_key, "settable_per_extruder") if settable_per_extruder: setting_value = global_profile.getProperty( qc_setting_key, "value") setting_definition = global_stack.getSettingDefinition( qc_setting_key) if setting_definition is not None: new_instance = SettingInstance( setting_definition, profile) new_instance.setProperty( "value", setting_value) new_instance.resetState( ) # Ensure that the state is not seen as a user state. profile.addInstance(new_instance) profile.setDirty(True) global_profile.removeInstance( qc_setting_key, postpone_emit=True) extruder_profiles.append(profile) for profile in extruder_profiles: profile_or_list.append(profile) # Import all profiles for profile_index, profile in enumerate(profile_or_list): if profile_index == 0: # This is assumed to be the global profile profile_id = (cast(ContainerInterface, global_stack.getBottom()).getId() + "_" + name_seed).lower().replace( " ", "_") elif profile_index < len(machine_extruders) + 1: # This is assumed to be an extruder profile extruder_id = machine_extruders[profile_index - 1].definition.getId() extruder_position = str(profile_index - 1) if not profile.getMetaDataEntry("position"): profile.setMetaDataEntry("position", extruder_position) else: profile.setMetaDataEntry("position", extruder_position) profile_id = (extruder_id + "_" + name_seed).lower().replace(" ", "_") else: # More extruders in the imported file than in the machine. continue # Delete the additional profiles. result = self._configureProfile( profile, profile_id, new_name, expected_machine_definition) if result is not None: return { "status": "error", "message": catalog.i18nc( "@info:status Don't translate the XML tags <filename> or <message>!", "Failed to import profile from <filename>{0}</filename>:", file_name) + " <message>" + result + "</message>" } return { "status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile_or_list[0].getName()) } # This message is throw when the profile reader doesn't find any profile in the file return { "status": "error", "message": catalog.i18nc("@info:status", "File {0} does not contain any valid profile.", file_name) } # If it hasn't returned by now, none of the plugins loaded the profile successfully. return { "status": "error", "message": catalog.i18nc( "@info:status", "Profile {0} has an unknown file type or is corrupted.", file_name) }
def test_valueChanges(container_registry): setting_property_provider = SettingPropertyProvider() # First create the basics; A container stack that will hold 2 instance containers and a single definition container container_stack = ContainerStack("test!") instance_container = InstanceContainer("data") second_instance_container = InstanceContainer("data2") definition_container = DefinitionContainer("foo") # Create a setting definition for our one and only setting! setting_definition = SettingDefinition("test_setting") setting_definition._deserialize_dict({"value": 10, "label": "blorp", "type": "float", "description": "nah", "maximum_value": 23, "maximum_value_warning": 21}) definition_container.addDefinition(setting_definition) # Make a single setting instance for our one and only setting. setting_instance = SettingInstance(setting_definition, instance_container) setting_instance.setProperty("value", 20) setting_instance.setProperty("enabled", False) instance_container.addInstance(setting_instance) # Make a setting instance that lives in our second instance_container setting_instance2 = SettingInstance(setting_definition, second_instance_container) second_instance_container.addInstance(setting_instance2) # Now that both containers are done, actually add them. container_stack.addContainer(definition_container) container_stack.addContainer(second_instance_container) container_stack.addContainer(instance_container) setting_property_provider.setContainerStack(container_stack) setting_property_provider.setKey("test_setting") assert setting_property_provider.getPropertyValue("value", 0) == 20 setting_property_provider.setWatchedProperties(["enabled", "value", "validationState"]) assert setting_property_provider.properties.value("enabled") == "False" assert setting_property_provider.properties.value("value") == "20" # Validator state is a special property that gets added based on the type and the value assert setting_property_provider.properties.value("validationState") == str(ValidatorState.Valid) # Set the property value to something that will trigger a warning setting_property_provider.setPropertyValue("value", 22) assert setting_property_provider.properties.value("validationState") == str(ValidatorState.MaximumWarning) assert setting_property_provider.getPropertyValue("value", 0) == 22 # The setting doesn't exist in our second instance container, so this should be None assert setting_property_provider.getPropertyValue("value", 1) is None # Set the property value to something that will trigger an error setting_property_provider.setPropertyValue("value", 25) # The Qtimer that we use to prevent flooding doesn't work in tests, so tickle the change manually. setting_property_provider._update() assert setting_property_provider.properties.value("validationState") == str(ValidatorState.MaximumError) # We now ask for the second instance container to be targeted setting_property_provider.setStoreIndex(1) assert setting_property_provider.storeIndex == 1 setting_property_provider.setPropertyValue("value", 2) setting_property_provider._update() # So now we should see a change in that instance container assert setting_property_provider.getPropertyValue("value", 1) == 2 # But not if we ask the provider, because the container above it still has a 25 as value! assert setting_property_provider.getPropertyValue("value", 0) == 25 assert setting_property_provider.stackLevels == [0, 1, 2] # We're asking for an index that doesn't exist. assert setting_property_provider.getPropertyValue("value", 2000) is None # The value is used, so the property must be true assert setting_property_provider.isValueUsed # Try to remove the setting from the container setting_property_provider.removeFromContainer(0) assert setting_property_provider.getPropertyValue("value", 0) is None # Ensure that a weird index doesn't break setting_property_provider.removeFromContainer(90001)
def updateSceneFromOptimizationResult( self, analysis: pywim.smartslice.result.Analysis): type_map = { 'int': int, 'float': float, 'str': str, 'enum': str, 'bool': bool } our_only_node = getPrintableNodes()[0] active_extruder = getNodeActiveExtruder(our_only_node) # TODO - Move this into a common class or function to apply an am.Config to GlobalStack/ExtruderStack if analysis.print_config.infill: infill_density = analysis.print_config.infill.density infill_pattern = analysis.print_config.infill.pattern if infill_pattern is None or infill_pattern == pywim.am.InfillType.unknown: infill_pattern = pywim.am.InfillType.grid infill_pattern_name = SmartSliceJobHandler.INFILL_SMARTSLICE_CURA[ infill_pattern] extruder_dict = { "wall_line_count": analysis.print_config.walls, "top_layers": analysis.print_config.top_layers, "bottom_layers": analysis.print_config.bottom_layers, "infill_sparse_density": analysis.print_config.infill.density, "infill_pattern": infill_pattern_name } Logger.log("d", "Optimized extruder settings: {}".format(extruder_dict)) for key, value in extruder_dict.items(): if value is not None: property_type = type_map.get( active_extruder.getProperty(key, "type")) if property_type: active_extruder.setProperty(key, "value", property_type(value), set_from_cache=True) active_extruder.setProperty(key, "state", InstanceState.User, set_from_cache=True) Application.getInstance().getMachineManager( ).forceUpdateAllSettings() self.optimizationResultAppliedToScene.emit() # Remove any modifier meshes which are present from a previous result mod_meshes = getModifierMeshes() if len(mod_meshes) > 0: for node in mod_meshes: node.addDecorator(SmartSliceRemovedDecorator()) our_only_node.removeChild(node) Application.getInstance().getController().getScene( ).sceneChanged.emit(node) # Add in the new modifier meshes for modifier_mesh in analysis.modifier_meshes: # Building the scene node modifier_mesh_node = CuraSceneNode() modifier_mesh_node.setName("SmartSliceMeshModifier") modifier_mesh_node.setSelectable(True) modifier_mesh_node.setCalculateBoundingBox(True) # Use the data from the SmartSlice engine to translate / rotate / scale the mod mesh modifier_mesh_node.setTransformation( Matrix(modifier_mesh.transform)) # Building the mesh # # Preparing the data from pywim for MeshBuilder modifier_mesh_vertices = [[v.x, v.y, v.z] for v in modifier_mesh.vertices] modifier_mesh_indices = [[triangle.v1, triangle.v2, triangle.v3] for triangle in modifier_mesh.triangles] # Doing the actual build modifier_mesh_data = MeshBuilder() modifier_mesh_data.setVertices( numpy.asarray(modifier_mesh_vertices, dtype=numpy.float32)) modifier_mesh_data.setIndices( numpy.asarray(modifier_mesh_indices, dtype=numpy.int32)) modifier_mesh_data.calculateNormals() modifier_mesh_node.setMeshData(modifier_mesh_data.build()) modifier_mesh_node.calculateBoundingBoxMesh() active_build_plate = Application.getInstance( ).getMultiBuildPlateModel().activeBuildPlate modifier_mesh_node.addDecorator( BuildPlateDecorator(active_build_plate)) modifier_mesh_node.addDecorator(SliceableObjectDecorator()) modifier_mesh_node.addDecorator(SmartSliceAddedDecorator()) bottom = modifier_mesh_node.getBoundingBox().bottom z_offset_decorator = ZOffsetDecorator() z_offset_decorator.setZOffset(bottom) modifier_mesh_node.addDecorator(z_offset_decorator) stack = modifier_mesh_node.callDecoration("getStack") settings = stack.getTop() modifier_mesh_node_infill_pattern = SmartSliceJobHandler.INFILL_SMARTSLICE_CURA[ modifier_mesh.print_config.infill.pattern] definition_dict = { "infill_mesh": True, "infill_pattern": modifier_mesh_node_infill_pattern, "infill_sparse_density": modifier_mesh.print_config.infill.density, "wall_line_count": modifier_mesh.print_config.walls, "top_layers": modifier_mesh.print_config.top_layers, "bottom_layers": modifier_mesh.print_config.bottom_layers, } Logger.log( "d", "Optimized modifier mesh settings: {}".format(definition_dict)) for key, value in definition_dict.items(): if value is not None: definition = stack.getSettingDefinition(key) property_type = type_map.get(stack.getProperty( key, "type")) if property_type: new_instance = SettingInstance(definition, settings) new_instance.setProperty("value", property_type(value)) new_instance.resetState( ) # Ensure that the state is not seen as a user state. settings.addInstance(new_instance) our_only_node.addChild(modifier_mesh_node) # emit changes and connect error tracker Application.getInstance().getController().getScene( ).sceneChanged.emit(modifier_mesh_node)
def importProfile(self, file_name): Logger.log("d", "Attempting to import profile %s", file_name) if not file_name: return { "status": "error", "message": catalog.i18nc( "@info:status Don't translate the XML tags <filename> or <message>!", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, "Invalid path") } plugin_registry = PluginRegistry.getInstance() extension = file_name.split(".")[-1] global_container_stack = Application.getInstance( ).getGlobalContainerStack() if not global_container_stack: return machine_extruders = list( ExtruderManager.getInstance().getMachineExtruders( global_container_stack.getId())) machine_extruders.sort(key=lambda k: k.getMetaDataEntry("position")) for plugin_id, meta_data in self._getIOPlugins("profile_reader"): if meta_data["profile_reader"][0]["extension"] != extension: continue profile_reader = plugin_registry.getPluginObject(plugin_id) try: profile_or_list = profile_reader.read( file_name) # Try to open the file with the profile reader. except Exception as e: # Note that this will fail quickly. That is, if any profile reader throws an exception, it will stop reading. It will only continue reading if the reader returned None. Logger.log( "e", "Failed to import profile from %s: %s while using profile reader. Got exception %s", file_name, profile_reader.getPluginId(), str(e)) return { "status": "error", "message": catalog.i18nc( "@info:status Don't translate the XML tags <filename> or <message>!", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, "\n" + str(e)) } if profile_or_list: # Ensure it is always a list of profiles if not isinstance(profile_or_list, list): profile_or_list = [profile_or_list] # First check if this profile is suitable for this machine global_profile = None if len(profile_or_list) == 1: global_profile = profile_or_list[0] else: for profile in profile_or_list: if not profile.getMetaDataEntry("extruder"): global_profile = profile break if not global_profile: Logger.log( "e", "Incorrect profile [%s]. Could not find global profile", file_name) return { "status": "error", "message": catalog.i18nc( "@info:status Don't translate the XML tags <filename> or <message>!", "This profile <filename>{0}</filename> contains incorrect data, could not import it.", file_name) } profile_definition = global_profile.getMetaDataEntry( "definition") expected_machine_definition = "fdmprinter" if parseBool( global_container_stack.getMetaDataEntry( "has_machine_quality", "False")): expected_machine_definition = global_container_stack.getMetaDataEntry( "quality_definition") if not expected_machine_definition: expected_machine_definition = global_container_stack.definition.getId( ) if expected_machine_definition is not None and profile_definition is not None and profile_definition != expected_machine_definition: Logger.log( "e", "Profile [%s] is for machine [%s] but the current active machine is [%s]. Will not import the profile", file_name, profile_definition, expected_machine_definition) return { "status": "error", "message": catalog.i18nc( "@info:status Don't translate the XML tags <filename> or <message>!", "The machine defined in profile <filename>{0}</filename> ({1}) doesn't match with your current machine ({2}), could not import it.", file_name, profile_definition, expected_machine_definition) } name_seed = os.path.splitext(os.path.basename(file_name))[0] new_name = self.uniqueName(name_seed) # Ensure it is always a list of profiles if type(profile_or_list) is not list: profile_or_list = [profile_or_list] # Make sure that there are also extruder stacks' quality_changes, not just one for the global stack if len(profile_or_list) == 1: global_profile = profile_or_list[0] extruder_profiles = [] for idx, extruder in enumerate( global_container_stack.extruders.values()): profile_id = ContainerRegistry.getInstance( ).uniqueName(global_container_stack.getId() + "_extruder_" + str(idx + 1)) profile = InstanceContainer(profile_id) profile.setName(global_profile.getName()) profile.addMetaDataEntry( "setting_version", CuraApplication.SettingVersion) profile.addMetaDataEntry("type", "quality_changes") profile.addMetaDataEntry( "definition", global_profile.getMetaDataEntry("definition")) profile.addMetaDataEntry( "quality_type", global_profile.getMetaDataEntry("quality_type")) profile.addMetaDataEntry("extruder", extruder.getId()) profile.setDirty(True) if idx == 0: # move all per-extruder settings to the first extruder's quality_changes for qc_setting_key in global_profile.getAllKeys(): settable_per_extruder = global_container_stack.getProperty( qc_setting_key, "settable_per_extruder") if settable_per_extruder: setting_value = global_profile.getProperty( qc_setting_key, "value") setting_definition = global_container_stack.getSettingDefinition( qc_setting_key) new_instance = SettingInstance( setting_definition, profile) new_instance.setProperty( "value", setting_value) new_instance.resetState( ) # Ensure that the state is not seen as a user state. profile.addInstance(new_instance) profile.setDirty(True) global_profile.removeInstance( qc_setting_key, postpone_emit=True) extruder_profiles.append(profile) for profile in extruder_profiles: profile_or_list.append(profile) # Import all profiles for profile_index, profile in enumerate(profile_or_list): if profile_index == 0: # This is assumed to be the global profile profile_id = ( global_container_stack.getBottom().getId() + "_" + name_seed).lower().replace(" ", "_") elif profile_index < len(machine_extruders) + 1: # This is assumed to be an extruder profile extruder_id = Application.getInstance( ).getMachineManager().getQualityDefinitionId( machine_extruders[profile_index - 1].getBottom()) if not profile.getMetaDataEntry("extruder"): profile.addMetaDataEntry("extruder", extruder_id) else: profile.setMetaDataEntry("extruder", extruder_id) profile_id = (extruder_id + "_" + name_seed).lower().replace(" ", "_") else: #More extruders in the imported file than in the machine. continue #Delete the additional profiles. result = self._configureProfile(profile, profile_id, new_name) if result is not None: return { "status": "error", "message": catalog.i18nc( "@info:status Don't translate the XML tags <filename> or <message>!", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, result) } return { "status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile_or_list[0].getName()) } # This message is throw when the profile reader doesn't find any profile in the file return { "status": "error", "message": catalog.i18nc("@info:status", "File {0} does not contain any valid profile.", file_name) } # If it hasn't returned by now, none of the plugins loaded the profile successfully. return { "status": "error", "message": catalog.i18nc( "@info:status", "Profile {0} has an unknown file type or is corrupted.", file_name) }
def addExtruderStackForSingleExtrusionMachine(self, machine, extruder_id, new_global_quality_changes = None, create_new_ids = True): new_extruder_id = extruder_id application = CuraApplication.getInstance() extruder_definitions = self.findDefinitionContainers(id = new_extruder_id) if not extruder_definitions: Logger.log("w", "Could not find definition containers for extruder %s", new_extruder_id) return extruder_definition = extruder_definitions[0] unique_name = self.uniqueName(machine.getName() + " " + new_extruder_id) if create_new_ids else machine.getName() + " " + new_extruder_id extruder_stack = ExtruderStack.ExtruderStack(unique_name) extruder_stack.setName(extruder_definition.getName()) extruder_stack.setDefinition(extruder_definition) extruder_stack.addMetaDataEntry("position", extruder_definition.getMetaDataEntry("position")) # create a new definition_changes container for the extruder stack definition_changes_id = self.uniqueName(extruder_stack.getId() + "_settings") if create_new_ids else extruder_stack.getId() + "_settings" definition_changes_name = definition_changes_id definition_changes = InstanceContainer(definition_changes_id, parent = application) definition_changes.setName(definition_changes_name) definition_changes.addMetaDataEntry("setting_version", CuraApplication.SettingVersion) definition_changes.addMetaDataEntry("type", "definition_changes") definition_changes.addMetaDataEntry("definition", extruder_definition.getId()) # move definition_changes settings if exist for setting_key in definition_changes.getAllKeys(): if machine.definition.getProperty(setting_key, "settable_per_extruder"): setting_value = machine.definitionChanges.getProperty(setting_key, "value") if setting_value is not None: # move it to the extruder stack's definition_changes setting_definition = machine.getSettingDefinition(setting_key) new_instance = SettingInstance(setting_definition, definition_changes) new_instance.setProperty("value", setting_value) new_instance.resetState() # Ensure that the state is not seen as a user state. definition_changes.addInstance(new_instance) definition_changes.setDirty(True) machine.definitionChanges.removeInstance(setting_key, postpone_emit = True) self.addContainer(definition_changes) extruder_stack.setDefinitionChanges(definition_changes) # create empty user changes container otherwise user_container_id = self.uniqueName(extruder_stack.getId() + "_user") if create_new_ids else extruder_stack.getId() + "_user" user_container_name = user_container_id user_container = InstanceContainer(user_container_id, parent = application) user_container.setName(user_container_name) user_container.addMetaDataEntry("type", "user") user_container.addMetaDataEntry("machine", machine.getId()) user_container.addMetaDataEntry("setting_version", CuraApplication.SettingVersion) user_container.setDefinition(machine.definition.getId()) user_container.setMetaDataEntry("position", extruder_stack.getMetaDataEntry("position")) if machine.userChanges: # for the newly created extruder stack, we need to move all "per-extruder" settings to the user changes # container to the extruder stack. for user_setting_key in machine.userChanges.getAllKeys(): settable_per_extruder = machine.getProperty(user_setting_key, "settable_per_extruder") if settable_per_extruder: setting_value = machine.getProperty(user_setting_key, "value") setting_definition = machine.getSettingDefinition(user_setting_key) new_instance = SettingInstance(setting_definition, definition_changes) new_instance.setProperty("value", setting_value) new_instance.resetState() # Ensure that the state is not seen as a user state. user_container.addInstance(new_instance) user_container.setDirty(True) machine.userChanges.removeInstance(user_setting_key, postpone_emit = True) self.addContainer(user_container) extruder_stack.setUserChanges(user_container) empty_variant = application.empty_variant_container empty_material = application.empty_material_container empty_quality = application.empty_quality_container if machine.variant.getId() not in ("empty", "empty_variant"): variant = machine.variant else: variant = empty_variant extruder_stack.variant = variant if machine.material.getId() not in ("empty", "empty_material"): material = machine.material else: material = empty_material extruder_stack.material = material if machine.quality.getId() not in ("empty", "empty_quality"): quality = machine.quality else: quality = empty_quality extruder_stack.quality = quality machine_quality_changes = machine.qualityChanges if new_global_quality_changes is not None: machine_quality_changes = new_global_quality_changes if machine_quality_changes.getId() not in ("empty", "empty_quality_changes"): extruder_quality_changes_container = self.findInstanceContainers(name = machine_quality_changes.getName(), extruder = extruder_id) if extruder_quality_changes_container: extruder_quality_changes_container = extruder_quality_changes_container[0] quality_changes_id = extruder_quality_changes_container.getId() extruder_stack.qualityChanges = self.findInstanceContainers(id = quality_changes_id)[0] else: # Some extruder quality_changes containers can be created at runtime as files in the qualities # folder. Those files won't be loaded in the registry immediately. So we also need to search # the folder to see if the quality_changes exists. extruder_quality_changes_container = self._findQualityChangesContainerInCuraFolder(machine_quality_changes.getName()) if extruder_quality_changes_container: quality_changes_id = extruder_quality_changes_container.getId() extruder_quality_changes_container.addMetaDataEntry("position", extruder_definition.getMetaDataEntry("position")) extruder_stack.qualityChanges = self.findInstanceContainers(id = quality_changes_id)[0] else: # if we still cannot find a quality changes container for the extruder, create a new one container_name = machine_quality_changes.getName() container_id = self.uniqueName(extruder_stack.getId() + "_qc_" + container_name) extruder_quality_changes_container = InstanceContainer(container_id, parent = application) extruder_quality_changes_container.setName(container_name) extruder_quality_changes_container.addMetaDataEntry("type", "quality_changes") extruder_quality_changes_container.addMetaDataEntry("setting_version", CuraApplication.SettingVersion) extruder_quality_changes_container.addMetaDataEntry("position", extruder_definition.getMetaDataEntry("position")) extruder_quality_changes_container.addMetaDataEntry("quality_type", machine_quality_changes.getMetaDataEntry("quality_type")) extruder_quality_changes_container.setDefinition(machine_quality_changes.getDefinition().getId()) self.addContainer(extruder_quality_changes_container) extruder_stack.qualityChanges = extruder_quality_changes_container if not extruder_quality_changes_container: Logger.log("w", "Could not find quality_changes named [%s] for extruder [%s]", machine_quality_changes.getName(), extruder_stack.getId()) else: # move all per-extruder settings to the extruder's quality changes for qc_setting_key in machine_quality_changes.getAllKeys(): settable_per_extruder = machine.getProperty(qc_setting_key, "settable_per_extruder") if settable_per_extruder: setting_value = machine_quality_changes.getProperty(qc_setting_key, "value") setting_definition = machine.getSettingDefinition(qc_setting_key) new_instance = SettingInstance(setting_definition, definition_changes) new_instance.setProperty("value", setting_value) new_instance.resetState() # Ensure that the state is not seen as a user state. extruder_quality_changes_container.addInstance(new_instance) extruder_quality_changes_container.setDirty(True) machine_quality_changes.removeInstance(qc_setting_key, postpone_emit=True) else: extruder_stack.qualityChanges = self.findInstanceContainers(id = "empty_quality_changes")[0] self.addContainer(extruder_stack) # Also need to fix the other qualities that are suitable for this machine. Those quality changes may still have # per-extruder settings in the container for the machine instead of the extruder. if machine_quality_changes.getId() not in ("empty", "empty_quality_changes"): quality_changes_machine_definition_id = machine_quality_changes.getDefinition().getId() else: whole_machine_definition = machine.definition machine_entry = machine.definition.getMetaDataEntry("machine") if machine_entry is not None: container_registry = ContainerRegistry.getInstance() whole_machine_definition = container_registry.findDefinitionContainers(id = machine_entry)[0] quality_changes_machine_definition_id = "fdmprinter" if whole_machine_definition.getMetaDataEntry("has_machine_quality"): quality_changes_machine_definition_id = machine.definition.getMetaDataEntry("quality_definition", whole_machine_definition.getId()) qcs = self.findInstanceContainers(type = "quality_changes", definition = quality_changes_machine_definition_id) qc_groups = {} # map of qc names -> qc containers for qc in qcs: qc_name = qc.getName() if qc_name not in qc_groups: qc_groups[qc_name] = [] qc_groups[qc_name].append(qc) # try to find from the quality changes cura directory too quality_changes_container = self._findQualityChangesContainerInCuraFolder(machine_quality_changes.getName()) if quality_changes_container: qc_groups[qc_name].append(quality_changes_container) for qc_name, qc_list in qc_groups.items(): qc_dict = {"global": None, "extruders": []} for qc in qc_list: extruder_position = qc.getMetaDataEntry("position") if extruder_position is not None: qc_dict["extruders"].append(qc) else: qc_dict["global"] = qc if qc_dict["global"] is not None and len(qc_dict["extruders"]) == 1: # move per-extruder settings for qc_setting_key in qc_dict["global"].getAllKeys(): settable_per_extruder = machine.getProperty(qc_setting_key, "settable_per_extruder") if settable_per_extruder: setting_value = qc_dict["global"].getProperty(qc_setting_key, "value") setting_definition = machine.getSettingDefinition(qc_setting_key) new_instance = SettingInstance(setting_definition, definition_changes) new_instance.setProperty("value", setting_value) new_instance.resetState() # Ensure that the state is not seen as a user state. qc_dict["extruders"][0].addInstance(new_instance) qc_dict["extruders"][0].setDirty(True) qc_dict["global"].removeInstance(qc_setting_key, postpone_emit=True) # Set next stack at the end extruder_stack.setNextStack(machine) return extruder_stack
def importProfile(self, file_name): Logger.log("d", "Attempting to import profile %s", file_name) if not file_name: return { "status": "error", "message": catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, "Invalid path")} plugin_registry = PluginRegistry.getInstance() extension = file_name.split(".")[-1] global_stack = Application.getInstance().getGlobalContainerStack() if not global_stack: return machine_extruders = [] for position in sorted(global_stack.extruders): machine_extruders.append(global_stack.extruders[position]) for plugin_id, meta_data in self._getIOPlugins("profile_reader"): if meta_data["profile_reader"][0]["extension"] != extension: continue profile_reader = plugin_registry.getPluginObject(plugin_id) try: profile_or_list = profile_reader.read(file_name) # Try to open the file with the profile reader. except NoProfileException: return { "status": "ok", "message": catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "No custom profile to import in file <filename>{0}</filename>", file_name)} except Exception as e: # Note that this will fail quickly. That is, if any profile reader throws an exception, it will stop reading. It will only continue reading if the reader returned None. Logger.log("e", "Failed to import profile from %s: %s while using profile reader. Got exception %s", file_name, profile_reader.getPluginId(), str(e)) return { "status": "error", "message": catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, "\n" + str(e))} if profile_or_list: # Ensure it is always a list of profiles if not isinstance(profile_or_list, list): profile_or_list = [profile_or_list] # First check if this profile is suitable for this machine global_profile = None extruder_profiles = [] if len(profile_or_list) == 1: global_profile = profile_or_list[0] else: for profile in profile_or_list: if not profile.getMetaDataEntry("position"): global_profile = profile else: extruder_profiles.append(profile) extruder_profiles = sorted(extruder_profiles, key = lambda x: int(x.getMetaDataEntry("position"))) profile_or_list = [global_profile] + extruder_profiles if not global_profile: Logger.log("e", "Incorrect profile [%s]. Could not find global profile", file_name) return { "status": "error", "message": catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "This profile <filename>{0}</filename> contains incorrect data, could not import it.", file_name)} profile_definition = global_profile.getMetaDataEntry("definition") # Make sure we have a profile_definition in the file: if profile_definition is None: break machine_definition = self.findDefinitionContainers(id = profile_definition) if not machine_definition: Logger.log("e", "Incorrect profile [%s]. Unknown machine type [%s]", file_name, profile_definition) return {"status": "error", "message": catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "This profile <filename>{0}</filename> contains incorrect data, could not import it.", file_name) } machine_definition = machine_definition[0] # Get the expected machine definition. # i.e.: We expect gcode for a UM2 Extended to be defined as normal UM2 gcode... profile_definition = getMachineDefinitionIDForQualitySearch(machine_definition) expected_machine_definition = getMachineDefinitionIDForQualitySearch(global_stack.definition) # And check if the profile_definition matches either one (showing error if not): if profile_definition != expected_machine_definition: Logger.log("e", "Profile [%s] is for machine [%s] but the current active machine is [%s]. Will not import the profile", file_name, profile_definition, expected_machine_definition) return { "status": "error", "message": catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "The machine defined in profile <filename>{0}</filename> ({1}) doesn't match with your current machine ({2}), could not import it.", file_name, profile_definition, expected_machine_definition)} # Fix the global quality profile's definition field in case it's not correct global_profile.setMetaDataEntry("definition", expected_machine_definition) quality_name = global_profile.getName() quality_type = global_profile.getMetaDataEntry("quality_type") name_seed = os.path.splitext(os.path.basename(file_name))[0] new_name = self.uniqueName(name_seed) # Ensure it is always a list of profiles if type(profile_or_list) is not list: profile_or_list = [profile_or_list] # Make sure that there are also extruder stacks' quality_changes, not just one for the global stack if len(profile_or_list) == 1: global_profile = profile_or_list[0] extruder_profiles = [] for idx, extruder in enumerate(global_stack.extruders.values()): profile_id = ContainerRegistry.getInstance().uniqueName(global_stack.getId() + "_extruder_" + str(idx + 1)) profile = InstanceContainer(profile_id) profile.setName(quality_name) profile.addMetaDataEntry("setting_version", CuraApplication.SettingVersion) profile.addMetaDataEntry("type", "quality_changes") profile.addMetaDataEntry("definition", expected_machine_definition) profile.addMetaDataEntry("quality_type", quality_type) profile.addMetaDataEntry("position", "0") profile.setDirty(True) if idx == 0: # move all per-extruder settings to the first extruder's quality_changes for qc_setting_key in global_profile.getAllKeys(): settable_per_extruder = global_stack.getProperty(qc_setting_key, "settable_per_extruder") if settable_per_extruder: setting_value = global_profile.getProperty(qc_setting_key, "value") setting_definition = global_stack.getSettingDefinition(qc_setting_key) new_instance = SettingInstance(setting_definition, profile) new_instance.setProperty("value", setting_value) new_instance.resetState() # Ensure that the state is not seen as a user state. profile.addInstance(new_instance) profile.setDirty(True) global_profile.removeInstance(qc_setting_key, postpone_emit=True) extruder_profiles.append(profile) for profile in extruder_profiles: profile_or_list.append(profile) # Import all profiles for profile_index, profile in enumerate(profile_or_list): if profile_index == 0: # This is assumed to be the global profile profile_id = (global_stack.getBottom().getId() + "_" + name_seed).lower().replace(" ", "_") elif profile_index < len(machine_extruders) + 1: # This is assumed to be an extruder profile extruder_id = machine_extruders[profile_index - 1].definition.getId() extruder_position = str(profile_index - 1) if not profile.getMetaDataEntry("position"): profile.addMetaDataEntry("position", extruder_position) else: profile.setMetaDataEntry("position", extruder_position) profile_id = (extruder_id + "_" + name_seed).lower().replace(" ", "_") else: #More extruders in the imported file than in the machine. continue #Delete the additional profiles. result = self._configureProfile(profile, profile_id, new_name, expected_machine_definition) if result is not None: return {"status": "error", "message": catalog.i18nc( "@info:status Don't translate the XML tags <filename> or <message>!", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, result)} return {"status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile_or_list[0].getName())} # This message is throw when the profile reader doesn't find any profile in the file return {"status": "error", "message": catalog.i18nc("@info:status", "File {0} does not contain any valid profile.", file_name)} # If it hasn't returned by now, none of the plugins loaded the profile successfully. return {"status": "error", "message": catalog.i18nc("@info:status", "Profile {0} has an unknown file type or is corrupted.", file_name)}
def _constructSupport(self, buffer: QImage) -> None: depth_pass = PickingPass( buffer.width(), buffer.height() ) #Instead of using the picking pass to pick for us, we need to bulk-pick digits so do this in Numpy. depth_pass.render() depth_image = depth_pass.getOutput() camera = CuraApplication.getInstance().getController().getScene( ).getActiveCamera() #to_support = qimage2ndarray.raw_view(buffer) #to_support= _qimageview(_qt.QImage(buffer)) to_support = self._raw_view(buffer) #depth = qimage2ndarray.recarray_view(depth_image) depth = self._recarray_view(depth_image) depth.a = 0 #Discard alpha channel. depth = depth.view(dtype=_np.int32).astype( _np.float32 ) / 1000 #Conflate the R, G and B channels to one 24-bit (cast to 32) float. Divide by 1000 to get mm. support_positions_2d = _np.array( _np.where(_np.bitwise_and(to_support == 255, depth < 16777)) ) #All the 2D coordinates on the screen where we want support. The 16777 is for points that don't land on a model. support_depths = _np.take( depth, support_positions_2d[0, :] * depth.shape[1] + support_positions_2d[1, :]) #The depth at those pixels. support_positions_2d = support_positions_2d.transpose( ) #We want rows with pixels, not columns with pixels. if len(support_positions_2d) == 0: Logger.log( "i", "Support was not drawn on the surface of any objects. Not creating support." ) return support_positions_2d[:, [0, 1]] = support_positions_2d[:, [ 1, 0 ]] #Swap columns to get OpenGL's coordinate system. camera_viewport = _np.array( [camera.getViewportWidth(), camera.getViewportHeight()]) support_positions_2d = support_positions_2d * 2.0 / camera_viewport - 1.0 #Scale to view coordinates (range -1 to 1). inverted_projection = _np.linalg.inv( camera.getProjectionMatrix().getData()) transformation = camera.getWorldTransformation().getData() transformation[:, 1] = -transformation[:, 1] #Invert Z to get OpenGL's coordinate system. #For each pixel, get the near and far plane. near = _np.ndarray((support_positions_2d.shape[0], 4)) near.fill(1) near[0:support_positions_2d.shape[0], 0:support_positions_2d.shape[1]] = support_positions_2d near[:, 2].fill(-1) near = _np.dot(inverted_projection, near.transpose()) near = _np.dot(transformation, near) near = near[0:3] / near[3] far = _np.ndarray((support_positions_2d.shape[0], 4)) far.fill(1) far[0:support_positions_2d.shape[0], 0:support_positions_2d.shape[1]] = support_positions_2d far = _np.dot(inverted_projection, far.transpose()) far = _np.dot(transformation, far) far = far[0:3] / far[3] #Direction is from near plane pixel to far plane pixel, normalised. direction = near - far direction /= _np.linalg.norm(direction, axis=0) #Final position is in the direction of the pixel, moving with <depth> mm away from the camera position. support_positions_3d = ( support_depths - 1 ) * direction #We want the support to appear just before the surface, not behind the surface, so - 1. support_positions_3d = support_positions_3d.transpose() camera_position_data = camera.getPosition().getData() support_positions_3d = support_positions_3d + camera_position_data #Create the vertices for the 3D mesh. #This mesh consists of a diamond-shape for each position that we traced. n = support_positions_3d.shape[0] Logger.log( "i", "Adding support in {num_pixels} locations.".format(num_pixels=n)) vertices = support_positions_3d.copy().astype(_np.float32) vertices = _np.resize(vertices, (n * 6, support_positions_3d.shape[1] )) #Resize will repeat all coordinates 6 times. #For each position, create a diamond shape around the position with 6 vertices. vertices[ n * 0:n * 1, 0] -= support_depths * 0.001 * self.globule_size #First corner (-x, +y). vertices[n * 0:n * 1, 2] += support_depths * 0.001 * self.globule_size vertices[ n * 1:n * 2, 0] += support_depths * 0.001 * self.globule_size #Second corner (+x, +y). vertices[n * 1:n * 2, 2] += support_depths * 0.001 * self.globule_size vertices[ n * 2:n * 3, 0] -= support_depths * 0.001 * self.globule_size #Third corner (-x, -y). vertices[n * 2:n * 3, 2] -= support_depths * 0.001 * self.globule_size vertices[ n * 3:n * 4, 0] += support_depths * 0.001 * self.globule_size #Fourth corner (+x, -y) vertices[n * 3:n * 4, 2] -= support_depths * 0.001 * self.globule_size vertices[n * 4:n * 5, 1] += support_depths * 0.001 * self.globule_size #Top side. vertices[ n * 5:n * 6, 1] -= support_depths * 0.001 * self.globule_size #Bottom side. #Create the faces of the diamond. indices = _np.arange(n, dtype=_np.int32) indices = _np.kron(indices, _np.ones( (3, 1))).astype(_np.int32).transpose() indices = _np.resize( indices, (n * 8, 3) ) #Creates 8 triangles using 3 times the same vertex, for each position: [[0, 0, 0], [1, 1, 1], ... , [0, 0, 0], [1, 1, 1], ... ] #indices[n * 0: n * 1, 0] += n * 0 #First corner. indices[n * 0:n * 1, 1] += n * 1 #Second corner. indices[n * 0:n * 1, 2] += n * 4 #Top side. indices[n * 1:n * 2, 0] += n * 1 #Second corner. indices[n * 1:n * 2, 1] += n * 3 #Fourth corner. indices[n * 1:n * 2, 2] += n * 4 #Top side. indices[n * 2:n * 3, 0] += n * 3 #Fourth corner. indices[n * 2:n * 3, 1] += n * 2 #Third corner. indices[n * 2:n * 3, 2] += n * 4 #Top side. indices[n * 3:n * 4, 0] += n * 2 #Third corner. #indices[n * 3: n * 4, 1] += n * 0 #First corner. indices[n * 3:n * 4, 2] += n * 4 #Top side. indices[n * 4:n * 5, 0] += n * 1 #Second corner. #indices[n * 4: n * 5, 1] += n * 0 #First corner. indices[n * 4:n * 5, 2] += n * 5 #Bottom side. indices[n * 5:n * 6, 0] += n * 3 #Fourth corner. indices[n * 5:n * 6, 1] += n * 1 #Second corner. indices[n * 5:n * 6, 2] += n * 5 #Bottom side. indices[n * 6:n * 7, 0] += n * 2 #Third corner. indices[n * 6:n * 7, 1] += n * 3 #Fourth corner. indices[n * 6:n * 7, 2] += n * 5 #Bottom side. #indices[n * 7: n * 8, 0] += n * 0 #First corner. indices[n * 7:n * 8, 1] += n * 2 #Third corner. indices[n * 7:n * 8, 2] += n * 5 #Bottom side. builder = MeshBuilder() builder.addVertices(vertices) builder.addIndices(indices) #Create the scene node. scene = CuraApplication.getInstance().getController().getScene() new_node = CuraSceneNode(parent=scene.getRoot(), name="BrushSupport") new_node.setSelectable(False) new_node.setMeshData(builder.build()) new_node.addDecorator( BuildPlateDecorator(CuraApplication.getInstance(). getMultiBuildPlateModel().activeBuildPlate)) new_node.addDecorator(SliceableObjectDecorator()) operation = GroupedOperation() #Figure out which mesh this piece of support belongs to. #TODO: You can draw support in one stroke over multiple meshes. The support would belong to an arbitrary one of these. selection_pass = CuraApplication.getInstance().getRenderer( ).getRenderPass("selection") parent_id = selection_pass.getIdAtPosition( support_positions_2d[0][0], support_positions_2d[0] [1]) #Find the selection under the first support pixel. parent_node = scene.getRoot() if not parent_id: Logger.log("d", "Can't link custom support to any scene node.") else: for node in BreadthFirstIterator(scene.getRoot()): if id(node) == parent_id: parent_node = node break #Add the appropriate per-object settings. stack = new_node.callDecoration( "getStack" ) #Created by SettingOverrideDecorator that is automatically added to CuraSceneNode. settings = stack.getTop() support_mesh_instance = SettingInstance( stack.getSettingDefinition("support_mesh"), settings) support_mesh_instance.setProperty("value", True) support_mesh_instance.resetState() settings.addInstance(support_mesh_instance) drop_down_instance = SettingInstance( stack.getSettingDefinition("support_mesh_drop_down"), settings) drop_down_instance.setProperty("value", True) drop_down_instance.resetState() settings.addInstance(drop_down_instance) #Add the scene node to the scene (and allow for undo). operation.addOperation( AddSceneNodeOperation(new_node, scene.getRoot()) ) #Set the parent to root initially, then change the parent, so that we don't have to alter the transformation. operation.addOperation(SetParentOperation(new_node, parent_node)) operation.push() scene.sceneChanged.emit(new_node)
def setMeshType(self, mesh_type: str) -> bool: """Returns True when the mesh_type was changed, False when current mesh_type == mesh_type""" old_mesh_type = self.getMeshType() if old_mesh_type == mesh_type: return False selected_object = Selection.getSelectedObject(0) if selected_object is None: Logger.log( "w", "Tried setting the mesh type of the selected object, but no object was selected" ) return False stack = selected_object.callDecoration( "getStack" ) #Don't try to get the active extruder since it may be None anyway. if not stack: selected_object.addDecorator(SettingOverrideDecorator()) stack = selected_object.callDecoration("getStack") settings_visibility_changed = False settings = stack.getTop() for property_key in [ "infill_mesh", "cutting_mesh", "support_mesh", "anti_overhang_mesh" ]: if property_key != mesh_type: if settings.getInstance(property_key): settings.removeInstance(property_key) else: if not (settings.getInstance(property_key) and settings.getProperty(property_key, "value")): definition = stack.getSettingDefinition(property_key) new_instance = SettingInstance(definition, settings) new_instance.setProperty("value", True) new_instance.resetState( ) # Ensure that the state is not seen as a user state. settings.addInstance(new_instance) # Override some settings to ensure that the infill mesh by default adds no skin or walls. Or remove them if not an infill mesh. specialized_settings = { "top_bottom_thickness": 0, "top_thickness": "=top_bottom_thickness", "bottom_thickness": "=top_bottom_thickness", "top_layers": "=0 if infill_sparse_density == 100 else math.ceil(round(top_thickness / resolveOrValue('layer_height'), 4))", "bottom_layers": "=0 if infill_sparse_density == 100 else math.ceil(round(bottom_thickness / resolveOrValue('layer_height'), 4))", "wall_thickness": 0, "wall_line_count": "=max(1, round((wall_thickness - wall_line_width_0) / wall_line_width_x) + 1) if wall_thickness != 0 else 0" } for property_key in specialized_settings: if mesh_type == "infill_mesh": if settings.getInstance(property_key) is None: definition = stack.getSettingDefinition(property_key) new_instance = SettingInstance(definition, settings) new_instance.setProperty( "value", specialized_settings[property_key]) new_instance.resetState( ) # Ensure that the state is not seen as a user state. settings.addInstance(new_instance) settings_visibility_changed = True elif old_mesh_type == "infill_mesh" and settings.getInstance( property_key) and property_key in specialized_settings: settings.removeInstance(property_key) settings_visibility_changed = True if settings_visibility_changed: self.visibility_handler.forceVisibilityChanged() self.propertyChanged.emit() return True