mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-05-01 00:04:27 +08:00

We wanted to select an extruder based on wether or not it has support-material, so that the user doesn't have to think about selecting a support extruder any more and in most cases, can't forget anymore either. The formula present in fdmprinter to do that was not only an unreadable nightmare, but also very slow. We decided to pull most of that functionality into the settings-function machinery instead (but just a bit more generic so other properties can be selected, not just 'material_is_support_material'). done as part of finishing off CURA-10643
196 lines
9.3 KiB
Python
196 lines
9.3 KiB
Python
# Copyright (c) 2018 Ultimaker B.V.
|
|
# Cura is released under the terms of the LGPLv3 or higher.
|
|
|
|
from typing import Any, List, Optional, TYPE_CHECKING
|
|
|
|
from UM.Settings.PropertyEvaluationContext import PropertyEvaluationContext
|
|
from UM.Settings.SettingFunction import SettingFunction
|
|
from UM.Logger import Logger
|
|
|
|
if TYPE_CHECKING:
|
|
from cura.CuraApplication import CuraApplication
|
|
from cura.Settings.CuraContainerStack import CuraContainerStack
|
|
|
|
|
|
#
|
|
# This class contains all Cura-related custom functions that can be used in formulas. Some functions requires
|
|
# information such as the currently active machine, so this is made into a class instead of standalone functions.
|
|
#
|
|
class CuraFormulaFunctions:
|
|
|
|
def __init__(self, application: "CuraApplication") -> None:
|
|
self._application = application
|
|
|
|
# ================
|
|
# Custom Functions
|
|
# ================
|
|
|
|
# Gets the default extruder position of the currently active machine.
|
|
def getDefaultExtruderPosition(self) -> str:
|
|
machine_manager = self._application.getMachineManager()
|
|
return machine_manager.defaultExtruderPosition
|
|
|
|
# Gets the given setting key from the given extruder position.
|
|
def getValueInExtruder(self, extruder_position: int, property_key: str,
|
|
context: Optional["PropertyEvaluationContext"] = None) -> Any:
|
|
machine_manager = self._application.getMachineManager()
|
|
|
|
if extruder_position == -1:
|
|
extruder_position = int(machine_manager.defaultExtruderPosition)
|
|
|
|
global_stack = machine_manager.activeMachine
|
|
try:
|
|
extruder_stack = global_stack.extruderList[int(extruder_position)]
|
|
except IndexError:
|
|
if extruder_position != 0:
|
|
Logger.log("w", "Value for %s of extruder %s was requested, but that extruder is not available. Returning the result from extruder 0 instead" % (property_key, extruder_position))
|
|
# This fixes a very specific fringe case; If a profile was created for a custom printer and one of the
|
|
# extruder settings has been set to non zero and the profile is loaded for a machine that has only a single extruder
|
|
# it would cause all kinds of issues (and eventually a crash).
|
|
# See https://github.com/Ultimaker/Cura/issues/5535
|
|
return self.getValueInExtruder(0, property_key, context)
|
|
Logger.log("w", "Value for %s of extruder %s was requested, but that extruder is not available. " % (property_key, extruder_position))
|
|
return None
|
|
|
|
value = extruder_stack.getRawProperty(property_key, "value", context = context)
|
|
if isinstance(value, SettingFunction):
|
|
value = value(extruder_stack, context = context)
|
|
|
|
return value
|
|
|
|
def _getActiveExtruders(self, context: Optional["PropertyEvaluationContext"] = None) -> List[str]:
|
|
machine_manager = self._application.getMachineManager()
|
|
extruder_manager = self._application.getExtruderManager()
|
|
|
|
global_stack = machine_manager.activeMachine
|
|
|
|
result = []
|
|
for extruder in extruder_manager.getActiveExtruderStacks():
|
|
if not extruder.isEnabled:
|
|
continue
|
|
# only include values from extruders that are "active" for the current machine instance
|
|
if int(extruder.getMetaDataEntry("position")) >= global_stack.getProperty("machine_extruder_count", "value", context = context):
|
|
continue
|
|
result.append(extruder)
|
|
|
|
return result
|
|
|
|
# Gets all extruder values as a list for the given property.
|
|
def getValuesInAllExtruders(self, property_key: str,
|
|
context: Optional["PropertyEvaluationContext"] = None) -> List[Any]:
|
|
global_stack = self._application.getMachineManager().activeMachine
|
|
|
|
result = []
|
|
for extruder in self._getActiveExtruders(context):
|
|
value = extruder.getRawProperty(property_key, "value", context = context)
|
|
|
|
if value is None:
|
|
continue
|
|
|
|
if isinstance(value, SettingFunction):
|
|
value = value(extruder, context = context)
|
|
|
|
result.append(value)
|
|
|
|
if not result:
|
|
result.append(global_stack.getProperty(property_key, "value", context = context))
|
|
|
|
return result
|
|
|
|
# Get the first extruder that adheres to a specific (boolean) property, like 'material_is_support_material'.
|
|
def getAnyExtruderPositionWithOrDefault(self, filter_key: str,
|
|
context: Optional["PropertyEvaluationContext"] = None) -> str:
|
|
for extruder in self._getActiveExtruders(context):
|
|
value = extruder.getRawProperty(filter_key, "value", context=context)
|
|
if value is None or not value:
|
|
continue
|
|
return str(extruder.position)
|
|
return self.getDefaultExtruderPosition()
|
|
|
|
# Get the resolve value or value for a given key.
|
|
def getResolveOrValue(self, property_key: str, context: Optional["PropertyEvaluationContext"] = None) -> Any:
|
|
machine_manager = self._application.getMachineManager()
|
|
|
|
global_stack = machine_manager.activeMachine
|
|
resolved_value = global_stack.getProperty(property_key, "value", context = context)
|
|
|
|
return resolved_value
|
|
|
|
# Gets the default setting value from given extruder position. The default value is what excludes the values in
|
|
# the user_changes container.
|
|
def getDefaultValueInExtruder(self, extruder_position: int, property_key: str) -> Any:
|
|
machine_manager = self._application.getMachineManager()
|
|
|
|
global_stack = machine_manager.activeMachine
|
|
try:
|
|
extruder_stack = global_stack.extruderList[extruder_position]
|
|
except IndexError:
|
|
Logger.log("w", "Unable to find extruder on in index %s", extruder_position)
|
|
else:
|
|
context = self.createContextForDefaultValueEvaluation(extruder_stack)
|
|
|
|
return self.getValueInExtruder(extruder_position, property_key, context = context)
|
|
|
|
# Gets all default setting values as a list from all extruders of the currently active machine.
|
|
# The default values are those excluding the values in the user_changes container.
|
|
def getDefaultValuesInAllExtruders(self, property_key: str) -> List[Any]:
|
|
machine_manager = self._application.getMachineManager()
|
|
|
|
global_stack = machine_manager.activeMachine
|
|
|
|
context = self.createContextForDefaultValueEvaluation(global_stack)
|
|
|
|
return self.getValuesInAllExtruders(property_key, context = context)
|
|
|
|
# Gets the resolve value or value for a given key without looking the first container (user container).
|
|
def getDefaultResolveOrValue(self, property_key: str) -> Any:
|
|
machine_manager = self._application.getMachineManager()
|
|
|
|
global_stack = machine_manager.activeMachine
|
|
|
|
context = self.createContextForDefaultValueEvaluation(global_stack)
|
|
return self.getResolveOrValue(property_key, context = context)
|
|
|
|
# Gets the value for the given setting key starting from the given container index.
|
|
def getValueFromContainerAtIndex(self, property_key: str, container_index: int,
|
|
context: Optional["PropertyEvaluationContext"] = None) -> Any:
|
|
machine_manager = self._application.getMachineManager()
|
|
global_stack = machine_manager.activeMachine
|
|
|
|
context = self.createContextForDefaultValueEvaluation(global_stack)
|
|
context.context["evaluate_from_container_index"] = container_index
|
|
|
|
return global_stack.getProperty(property_key, "value", context = context)
|
|
|
|
# Gets the extruder value for the given setting key starting from the given container index.
|
|
def getValueFromContainerAtIndexInExtruder(self, extruder_position: int, property_key: str, container_index: int,
|
|
context: Optional["PropertyEvaluationContext"] = None) -> Any:
|
|
machine_manager = self._application.getMachineManager()
|
|
global_stack = machine_manager.activeMachine
|
|
|
|
if extruder_position == -1:
|
|
extruder_position = int(machine_manager.defaultExtruderPosition)
|
|
|
|
global_stack = machine_manager.activeMachine
|
|
try:
|
|
extruder_stack = global_stack.extruderList[int(extruder_position)]
|
|
except IndexError:
|
|
Logger.log("w", "Value for %s of extruder %s was requested, but that extruder is not available. " % (property_key, extruder_position))
|
|
return None
|
|
|
|
context = self.createContextForDefaultValueEvaluation(extruder_stack)
|
|
context.context["evaluate_from_container_index"] = container_index
|
|
|
|
return self.getValueInExtruder(extruder_position, property_key, context)
|
|
|
|
# Creates a context for evaluating default values (skip the user_changes container).
|
|
def createContextForDefaultValueEvaluation(self, source_stack: "CuraContainerStack") -> "PropertyEvaluationContext":
|
|
context = PropertyEvaluationContext(source_stack)
|
|
context.context["evaluate_from_container_index"] = 1 # skip the user settings container
|
|
context.context["override_operators"] = {
|
|
"extruderValue": self.getDefaultValueInExtruder,
|
|
"extruderValues": self.getDefaultValuesInAllExtruders,
|
|
"resolveOrValue": self.getDefaultResolveOrValue,
|
|
}
|
|
return context
|