class PrintInformation(QObject): class SlicePass: CurrentSettings = 1 LowQualitySettings = 2 HighQualitySettings = 3 class SliceReason: SceneChanged = 1 SettingChanged = 2 ActiveMachineChanged = 3 Other = 4 def __init__(self, parent=None): super().__init__(parent) self._current_print_time = Duration(None, self) self._material_amount = -1 self._backend = Application.getInstance().getBackend() if self._backend: self._backend.printDurationMessage.connect( self._onPrintDurationMessage) currentPrintTimeChanged = pyqtSignal() @pyqtProperty(Duration, notify=currentPrintTimeChanged) def currentPrintTime(self): return self._current_print_time materialAmountChanged = pyqtSignal() @pyqtProperty(float, notify=materialAmountChanged) def materialAmount(self): return self._material_amount def _onPrintDurationMessage(self, time, amount): #if self._slice_pass == self.SlicePass.CurrentSettings: self._current_print_time.setDuration(time) self.currentPrintTimeChanged.emit() # Material amount is sent as an amount of mm^3, so calculate length from that r = Application.getInstance().getGlobalContainerStack().getProperty( "material_diameter", "value") / 2 self._material_amount = round((amount / (math.pi * r**2)) / 1000, 2) self.materialAmountChanged.emit()
class PrintInformation(QObject): class SlicePass: CurrentSettings = 1 LowQualitySettings = 2 HighQualitySettings = 3 class SliceReason: SceneChanged = 1 SettingChanged = 2 ActiveMachineChanged = 3 Other = 4 def __init__(self, parent = None): super().__init__(parent) self._current_print_time = Duration(None, self) self._material_amount = -1 self._backend = Application.getInstance().getBackend() if self._backend: self._backend.printDurationMessage.connect(self._onPrintDurationMessage) currentPrintTimeChanged = pyqtSignal() @pyqtProperty(Duration, notify = currentPrintTimeChanged) def currentPrintTime(self): return self._current_print_time materialAmountChanged = pyqtSignal() @pyqtProperty(float, notify = materialAmountChanged) def materialAmount(self): return self._material_amount def _onPrintDurationMessage(self, time, amount): #if self._slice_pass == self.SlicePass.CurrentSettings: self._current_print_time.setDuration(time) self.currentPrintTimeChanged.emit() # Material amount is sent as an amount of mm^3, so calculate length from that r = Application.getInstance().getGlobalContainerStack().getProperty("material_diameter", "value") / 2 self._material_amount = round((amount / (math.pi * r ** 2)) / 1000, 2) self.materialAmountChanged.emit()
class PrintInformation(QObject): class SlicePass: CurrentSettings = 1 LowQualitySettings = 2 HighQualitySettings = 3 class SliceReason: SceneChanged = 1 SettingChanged = 2 ActiveMachineChanged = 3 Other = 4 def __init__(self, parent=None): super().__init__(parent) self._current_print_time = Duration(None, self) self._material_lengths = [] self._material_weights = [] self._backend = Application.getInstance().getBackend() if self._backend: self._backend.printDurationMessage.connect( self._onPrintDurationMessage) self._job_name = "" self._abbr_machine = "" Application.getInstance().globalContainerStackChanged.connect( self._setAbbreviatedMachineName) Application.getInstance().fileLoaded.connect(self.setJobName) currentPrintTimeChanged = pyqtSignal() @pyqtProperty(Duration, notify=currentPrintTimeChanged) def currentPrintTime(self): return self._current_print_time materialLengthsChanged = pyqtSignal() @pyqtProperty("QVariantList", notify=materialLengthsChanged) def materialLengths(self): return self._material_lengths materialWeightsChanged = pyqtSignal() @pyqtProperty("QVariantList", notify=materialWeightsChanged) def materialWeights(self): return self._material_weights def _onPrintDurationMessage(self, total_time, material_amounts): self._current_print_time.setDuration(total_time) self.currentPrintTimeChanged.emit() # Material amount is sent as an amount of mm^3, so calculate length from that r = Application.getInstance().getGlobalContainerStack().getProperty( "material_diameter", "value") / 2 self._material_lengths = [] self._material_weights = [] extruder_stacks = list( cura.Settings.ExtruderManager.getInstance().getMachineExtruders( Application.getInstance().getGlobalContainerStack().getId())) for index, amount in enumerate(material_amounts): ## Find the right extruder stack. As the list isn't sorted because it's a annoying generator, we do some # list comprehension filtering to solve this for us. if extruder_stacks: # Multi extrusion machine extruder_stack = [ extruder for extruder in extruder_stacks if extruder.getMetaDataEntry("position") == str(index) ][0] density = extruder_stack.getMetaDataEntry("properties", {}).get( "density", 0) else: # Machine with no extruder stacks density = Application.getInstance().getGlobalContainerStack( ).getMetaDataEntry("properties", {}).get("density", 0) self._material_weights.append( float(amount) * float(density) / 1000) self._material_lengths.append( round((amount / (math.pi * r**2)) / 1000, 2)) self.materialLengthsChanged.emit() self.materialWeightsChanged.emit() @pyqtSlot(str) def setJobName(self, name): # Ensure that we don't use entire path but only filename name = os.path.basename(name) # when a file is opened using the terminal; the filename comes from _onFileLoaded and still contains its # extension. This cuts the extension off if necessary. name = os.path.splitext(name)[0] if self._job_name != name: self._job_name = name self.jobNameChanged.emit() jobNameChanged = pyqtSignal() @pyqtProperty(str, notify=jobNameChanged) def jobName(self): return self._job_name @pyqtSlot(str, result=str) def createJobName(self, base_name): base_name = self._stripAccents(base_name) if Preferences.getInstance().getValue("cura/jobname_prefix"): return self._abbr_machine + "_" + base_name else: return base_name ## Created an acronymn-like abbreviated machine name from the currently active machine name # Called each time the global stack is switched def _setAbbreviatedMachineName(self): global_stack_name = Application.getInstance().getGlobalContainerStack( ).getName() split_name = global_stack_name.split(" ") abbr_machine = "" for word in split_name: if word.lower() == "ultimaker": abbr_machine += "UM" elif word.isdigit(): abbr_machine += word else: abbr_machine += self._stripAccents( word.strip("()[]{}#").upper())[0] self._abbr_machine = abbr_machine ## Utility method that strips accents from characters (eg: â -> a) def _stripAccents(self, str): return ''.join(char for char in unicodedata.normalize('NFD', str) if unicodedata.category(char) != 'Mn')
class PrintInformation(QObject): class SlicePass: CurrentSettings = 1 LowQualitySettings = 2 HighQualitySettings = 3 class SliceReason: SceneChanged = 1 SettingChanged = 2 ActiveMachineChanged = 3 Other = 4 def __init__(self, parent=None): super().__init__(parent) self.initializeCuraMessagePrintTimeProperties() self._material_lengths = [] self._material_weights = [] self._material_costs = [] self._pre_sliced = False self._backend = Application.getInstance().getBackend() if self._backend: self._backend.printDurationMessage.connect( self._onPrintDurationMessage) self._base_name = "" self._abbr_machine = "" self._job_name = "" Application.getInstance().globalContainerStackChanged.connect( self._updateJobName) Application.getInstance().fileLoaded.connect(self.setBaseName) Preferences.getInstance().preferenceChanged.connect( self._onPreferencesChanged) self._active_material_container = None Application.getInstance().getMachineManager( ).activeMaterialChanged.connect(self._onActiveMaterialChanged) self._onActiveMaterialChanged() self._material_amounts = [] # Crate cura message translations and using translation keys initialize empty time Duration object for total time # and time for each feature def initializeCuraMessagePrintTimeProperties(self): self._current_print_time = Duration(None, self) self._print_time_message_translations = { "inset_0": catalog.i18nc("@tooltip", "Outer Wall"), "inset_x": catalog.i18nc("@tooltip", "Inner Walls"), "skin": catalog.i18nc("@tooltip", "Skin"), "infill": catalog.i18nc("@tooltip", "Infill"), "support_infill": catalog.i18nc("@tooltip", "Support Infill"), "support_interface": catalog.i18nc("@tooltip", "Support Interface"), "support": catalog.i18nc("@tooltip", "Support"), "skirt": catalog.i18nc("@tooltip", "Skirt"), "travel": catalog.i18nc("@tooltip", "Travel"), "retract": catalog.i18nc("@tooltip", "Retractions"), "none": catalog.i18nc("@tooltip", "Other") } self._print_time_message_values = {} # Full fill message values using keys from _print_time_message_translations for key in self._print_time_message_translations.keys(): self._print_time_message_values[key] = Duration(None, self) currentPrintTimeChanged = pyqtSignal() preSlicedChanged = pyqtSignal() @pyqtProperty(bool, notify=preSlicedChanged) def preSliced(self): return self._pre_sliced def setPreSliced(self, pre_sliced): self._pre_sliced = pre_sliced self.preSlicedChanged.emit() @pyqtProperty(Duration, notify=currentPrintTimeChanged) def currentPrintTime(self): return self._current_print_time materialLengthsChanged = pyqtSignal() @pyqtProperty("QVariantList", notify=materialLengthsChanged) def materialLengths(self): return self._material_lengths materialWeightsChanged = pyqtSignal() @pyqtProperty("QVariantList", notify=materialWeightsChanged) def materialWeights(self): return self._material_weights materialCostsChanged = pyqtSignal() @pyqtProperty("QVariantList", notify=materialCostsChanged) def materialCosts(self): return self._material_costs def _onPrintDurationMessage(self, print_time, material_amounts): self._updateTotalPrintTimePerFeature(print_time) self.currentPrintTimeChanged.emit() self._material_amounts = material_amounts self._calculateInformation() def _updateTotalPrintTimePerFeature(self, print_time): total_estimated_time = 0 for feature, time in print_time.items(): if time != time: # Check for NaN. Engine can sometimes give us weird values. self._print_time_message_values.get(feature).setDuration(0) Logger.log("w", "Received NaN for print duration message") continue total_estimated_time += time self._print_time_message_values.get(feature).setDuration(time) self._current_print_time.setDuration(total_estimated_time) def _calculateInformation(self): if Application.getInstance().getGlobalContainerStack() is None: return # Material amount is sent as an amount of mm^3, so calculate length from that radius = Application.getInstance().getGlobalContainerStack( ).getProperty("material_diameter", "value") / 2 self._material_lengths = [] self._material_weights = [] self._material_costs = [] material_preference_values = json.loads( Preferences.getInstance().getValue("cura/material_settings")) extruder_stacks = list( ExtruderManager.getInstance().getMachineExtruders( Application.getInstance().getGlobalContainerStack().getId())) for index, amount in enumerate(self._material_amounts): ## Find the right extruder stack. As the list isn't sorted because it's a annoying generator, we do some # list comprehension filtering to solve this for us. material = None if extruder_stacks: # Multi extrusion machine extruder_stack = [ extruder for extruder in extruder_stacks if extruder.getMetaDataEntry("position") == str(index) ][0] density = extruder_stack.getMetaDataEntry("properties", {}).get( "density", 0) material = extruder_stack.findContainer({"type": "material"}) else: # Machine with no extruder stacks density = Application.getInstance().getGlobalContainerStack( ).getMetaDataEntry("properties", {}).get("density", 0) material = Application.getInstance().getGlobalContainerStack( ).findContainer({"type": "material"}) weight = float(amount) * float(density) / 1000 cost = 0 if material: material_guid = material.getMetaDataEntry("GUID") if material_guid in material_preference_values: material_values = material_preference_values[material_guid] weight_per_spool = float( material_values["spool_weight"] if material_values and "spool_weight" in material_values else 0) cost_per_spool = float( material_values["spool_cost"] if material_values and "spool_cost" in material_values else 0) if weight_per_spool != 0: cost = cost_per_spool * weight / weight_per_spool else: cost = 0 if radius != 0: length = round((amount / (math.pi * radius**2)) / 1000, 2) else: length = 0 self._material_weights.append(weight) self._material_lengths.append(length) self._material_costs.append(cost) self.materialLengthsChanged.emit() self.materialWeightsChanged.emit() self.materialCostsChanged.emit() def _onPreferencesChanged(self, preference): if preference != "cura/material_settings": return self._calculateInformation() def _onActiveMaterialChanged(self): if self._active_material_container: try: self._active_material_container.metaDataChanged.disconnect( self._onMaterialMetaDataChanged) except TypeError: #pyQtSignal gives a TypeError when disconnecting from something that is already disconnected. pass active_material_id = Application.getInstance().getMachineManager( ).activeMaterialId active_material_containers = ContainerRegistry.getInstance( ).findInstanceContainers(id=active_material_id) if active_material_containers: self._active_material_container = active_material_containers[0] self._active_material_container.metaDataChanged.connect( self._onMaterialMetaDataChanged) def _onMaterialMetaDataChanged(self, *args, **kwargs): self._calculateInformation() @pyqtSlot(str) def setJobName(self, name): self._job_name = name self.jobNameChanged.emit() jobNameChanged = pyqtSignal() @pyqtProperty(str, notify=jobNameChanged) def jobName(self): return self._job_name def _updateJobName(self): if self._base_name == "": self._job_name = "" self.jobNameChanged.emit() return base_name = self._stripAccents(self._base_name) self._setAbbreviatedMachineName() if self._pre_sliced: self._job_name = catalog.i18nc("@label", "Pre-sliced file {0}", base_name) elif Preferences.getInstance().getValue("cura/jobname_prefix"): # Don't add abbreviation if it already has the exact same abbreviation. if base_name.startswith(self._abbr_machine + "_"): self._job_name = base_name else: self._job_name = self._abbr_machine + "_" + base_name else: self._job_name = base_name self.jobNameChanged.emit() @pyqtProperty(str) def baseName(self): return self._base_name @pyqtSlot(str) def setBaseName(self, base_name): # Ensure that we don't use entire path but only filename name = os.path.basename(base_name) # when a file is opened using the terminal; the filename comes from _onFileLoaded and still contains its # extension. This cuts the extension off if necessary. name = os.path.splitext(name)[0] # name is "" when I first had some meshes and afterwards I deleted them so the naming should start again if name == "" or (self._base_name == "" and self._base_name != name): self._base_name = name self._updateJobName() ## Created an acronymn-like abbreviated machine name from the currently active machine name # Called each time the global stack is switched def _setAbbreviatedMachineName(self): global_container_stack = Application.getInstance( ).getGlobalContainerStack() if not global_container_stack: self._abbr_machine = "" return global_stack_name = global_container_stack.getName() split_name = global_stack_name.split(" ") abbr_machine = "" for word in split_name: if word.lower() == "ultimaker": abbr_machine += "UM" elif word.isdigit(): abbr_machine += word else: abbr_machine += self._stripAccents( word.strip("()[]{}#").upper())[0] self._abbr_machine = abbr_machine ## Utility method that strips accents from characters (eg: â -> a) def _stripAccents(self, str): return ''.join(char for char in unicodedata.normalize('NFD', str) if unicodedata.category(char) != 'Mn') @pyqtSlot(result="QVariantMap") def getFeaturePrintTimes(self): result = {} for feature, time in self._print_time_message_values.items(): if feature in self._print_time_message_translations: result[self._print_time_message_translations[feature]] = time else: result[feature] = time return result # Simulate message with zero time duration def setToZeroPrintInformation(self): temp_message = {} for key in self._print_time_message_values.keys(): temp_message[key] = 0 temp_material_amounts = [0] self._onPrintDurationMessage(temp_message, temp_material_amounts)
class PrintInformation(QObject): class SlicePass: CurrentSettings = 1 LowQualitySettings = 2 HighQualitySettings = 3 class SliceReason: SceneChanged = 1 SettingChanged = 2 ActiveMachineChanged = 3 Other = 4 def __init__(self, parent = None): super().__init__(parent) self._current_print_time = Duration(None, self) self._material_amounts = [] self._backend = Application.getInstance().getBackend() if self._backend: self._backend.printDurationMessage.connect(self._onPrintDurationMessage) self._job_name = "" self._abbr_machine = "" Application.getInstance().globalContainerStackChanged.connect(self._setAbbreviatedMachineName) Application.getInstance().fileLoaded.connect(self.setJobName) currentPrintTimeChanged = pyqtSignal() @pyqtProperty(Duration, notify = currentPrintTimeChanged) def currentPrintTime(self): return self._current_print_time materialAmountsChanged = pyqtSignal() @pyqtProperty("QVariantList", notify = materialAmountsChanged) def materialAmounts(self): return self._material_amounts def _onPrintDurationMessage(self, total_time, material_amounts): self._current_print_time.setDuration(total_time) self.currentPrintTimeChanged.emit() # Material amount is sent as an amount of mm^3, so calculate length from that r = Application.getInstance().getGlobalContainerStack().getProperty("material_diameter", "value") / 2 self._material_amounts = [] for amount in material_amounts: self._material_amounts.append(round((amount / (math.pi * r ** 2)) / 1000, 2)) self.materialAmountsChanged.emit() @pyqtSlot(str) def setJobName(self, name): # when a file is opened using the terminal; the filename comes from _onFileLoaded and still contains its # extension. This cuts the extension off if necessary. name = os.path.splitext(name)[0] if self._job_name != name: self._job_name = name self.jobNameChanged.emit() jobNameChanged = pyqtSignal() @pyqtProperty(str, notify = jobNameChanged) def jobName(self): return self._job_name @pyqtSlot(str, result = str) def createJobName(self, base_name): base_name = self._stripAccents(base_name) if Preferences.getInstance().getValue("cura/jobname_prefix"): return self._abbr_machine + "_" + base_name else: return base_name ## Created an acronymn-like abbreviated machine name from the currently active machine name # Called each time the global stack is switched def _setAbbreviatedMachineName(self): global_stack_name = Application.getInstance().getGlobalContainerStack().getName() split_name = global_stack_name.split(" ") abbr_machine = "" for word in split_name: if word.lower() == "ultimaker": abbr_machine += "UM" elif word.isdigit(): abbr_machine += word else: abbr_machine += self._stripAccents(word.strip("()[]{}#").upper())[0] self._abbr_machine = abbr_machine ## Utility method that strips accents from characters (eg: â -> a) def _stripAccents(self, str): return ''.join(char for char in unicodedata.normalize('NFD', str) if unicodedata.category(char) != 'Mn')
class PrintInformation(QObject): class SlicePass: CurrentSettings = 1 LowQualitySettings = 2 HighQualitySettings = 3 class SliceReason: SceneChanged = 1 SettingChanged = 2 ActiveMachineChanged = 3 Other = 4 def __init__(self, parent=None): super().__init__(parent) self._current_print_time = Duration(None, self) self._material_lengths = [] self._material_weights = [] self._material_costs = [] self._pre_sliced = False self._backend = Application.getInstance().getBackend() if self._backend: self._backend.printDurationMessage.connect( self._onPrintDurationMessage) self._job_name = "" self._abbr_machine = "" Application.getInstance().globalContainerStackChanged.connect( self._setAbbreviatedMachineName) Application.getInstance().fileLoaded.connect(self.setJobName) Preferences.getInstance().preferenceChanged.connect( self._onPreferencesChanged) self._active_material_container = None Application.getInstance().getMachineManager( ).activeMaterialChanged.connect(self._onActiveMaterialChanged) self._onActiveMaterialChanged() currentPrintTimeChanged = pyqtSignal() preSlicedChanged = pyqtSignal() @pyqtProperty(bool, notify=preSlicedChanged) def preSliced(self): return self._pre_sliced def setPreSliced(self, pre_sliced): self._pre_sliced = pre_sliced self.preSlicedChanged.emit() @pyqtProperty(Duration, notify=currentPrintTimeChanged) def currentPrintTime(self): return self._current_print_time materialLengthsChanged = pyqtSignal() @pyqtProperty("QVariantList", notify=materialLengthsChanged) def materialLengths(self): return self._material_lengths materialWeightsChanged = pyqtSignal() @pyqtProperty("QVariantList", notify=materialWeightsChanged) def materialWeights(self): return self._material_weights materialCostsChanged = pyqtSignal() @pyqtProperty("QVariantList", notify=materialCostsChanged) def materialCosts(self): return self._material_costs def _onPrintDurationMessage(self, total_time, material_amounts): if total_time != total_time: # Check for NaN. Engine can sometimes give us weird values. Logger.log("w", "Received NaN for print duration message") self._current_print_time.setDuration(0) else: self._current_print_time.setDuration(total_time) self.currentPrintTimeChanged.emit() self._material_amounts = material_amounts self._calculateInformation() def _calculateInformation(self): # Material amount is sent as an amount of mm^3, so calculate length from that r = Application.getInstance().getGlobalContainerStack().getProperty( "material_diameter", "value") / 2 self._material_lengths = [] self._material_weights = [] self._material_costs = [] material_preference_values = json.loads( Preferences.getInstance().getValue("cura/material_settings")) extruder_stacks = list( ExtruderManager.getInstance().getMachineExtruders( Application.getInstance().getGlobalContainerStack().getId())) for index, amount in enumerate(self._material_amounts): ## Find the right extruder stack. As the list isn't sorted because it's a annoying generator, we do some # list comprehension filtering to solve this for us. material = None if extruder_stacks: # Multi extrusion machine extruder_stack = [ extruder for extruder in extruder_stacks if extruder.getMetaDataEntry("position") == str(index) ][0] density = extruder_stack.getMetaDataEntry("properties", {}).get( "density", 0) material = extruder_stack.findContainer({"type": "material"}) else: # Machine with no extruder stacks density = Application.getInstance().getGlobalContainerStack( ).getMetaDataEntry("properties", {}).get("density", 0) material = Application.getInstance().getGlobalContainerStack( ).findContainer({"type": "material"}) weight = float(amount) * float(density) / 1000 cost = 0 if material: material_guid = material.getMetaDataEntry("GUID") if material_guid in material_preference_values: material_values = material_preference_values[material_guid] weight_per_spool = float( material_values["spool_weight"] if material_values and "spool_weight" in material_values else 0) cost_per_spool = float( material_values["spool_cost"] if material_values and "spool_cost" in material_values else 0) if weight_per_spool != 0: cost = cost_per_spool * weight / weight_per_spool else: cost = 0 self._material_weights.append(weight) self._material_lengths.append( round((amount / (math.pi * r**2)) / 1000, 2)) self._material_costs.append(cost) self.materialLengthsChanged.emit() self.materialWeightsChanged.emit() self.materialCostsChanged.emit() def _onPreferencesChanged(self, preference): if preference != "cura/material_settings": return self._calculateInformation() def _onActiveMaterialChanged(self): if self._active_material_container: self._active_material_container.metaDataChanged.disconnect( self._onMaterialMetaDataChanged) active_material_id = Application.getInstance().getMachineManager( ).activeMaterialId active_material_containers = ContainerRegistry.getInstance( ).findInstanceContainers(id=active_material_id) if active_material_containers: self._active_material_container = active_material_containers[0] self._active_material_container.metaDataChanged.connect( self._onMaterialMetaDataChanged) def _onMaterialMetaDataChanged(self, *args, **kwargs): self._calculateInformation() @pyqtSlot(str) def setJobName(self, name): # Ensure that we don't use entire path but only filename name = os.path.basename(name) # when a file is opened using the terminal; the filename comes from _onFileLoaded and still contains its # extension. This cuts the extension off if necessary. name = os.path.splitext(name)[0] if self._job_name != name: self._job_name = name self.jobNameChanged.emit() jobNameChanged = pyqtSignal() @pyqtProperty(str, notify=jobNameChanged) def jobName(self): return self._job_name @pyqtSlot(str, result=str) def createJobName(self, base_name): if base_name == "": return "" base_name = self._stripAccents(base_name) self._setAbbreviatedMachineName() if self._pre_sliced: return catalog.i18nc("@label", "Pre-sliced file {0}", base_name) elif Preferences.getInstance().getValue("cura/jobname_prefix"): # Don't add abbreviation if it already has the exact same abbreviation. if base_name.startswith(self._abbr_machine + "_"): return base_name return self._abbr_machine + "_" + base_name else: return base_name ## Created an acronymn-like abbreviated machine name from the currently active machine name # Called each time the global stack is switched def _setAbbreviatedMachineName(self): global_container_stack = Application.getInstance( ).getGlobalContainerStack() if not global_container_stack: self._abbr_machine = "" return global_stack_name = global_container_stack.getName() split_name = global_stack_name.split(" ") abbr_machine = "" for word in split_name: if word.lower() == "ultimaker": abbr_machine += "UM" elif word.isdigit(): abbr_machine += word else: abbr_machine += self._stripAccents( word.strip("()[]{}#").upper())[0] self._abbr_machine = abbr_machine ## Utility method that strips accents from characters (eg: â -> a) def _stripAccents(self, str): return ''.join(char for char in unicodedata.normalize('NFD', str) if unicodedata.category(char) != 'Mn')
class PrintInformation(QObject): class SlicePass: CurrentSettings = 1 LowQualitySettings = 2 HighQualitySettings = 3 class SliceReason: SceneChanged = 1 SettingChanged = 2 ActiveMachineChanged = 3 Other = 4 def __init__(self, parent=None): super().__init__(parent) self._current_print_time = Duration(None, self) self._material_lengths = [] self._material_weights = [] self._backend = Application.getInstance().getBackend() if self._backend: self._backend.printDurationMessage.connect(self._onPrintDurationMessage) self._job_name = "" self._abbr_machine = "" Application.getInstance().globalContainerStackChanged.connect(self._setAbbreviatedMachineName) Application.getInstance().fileLoaded.connect(self.setJobName) currentPrintTimeChanged = pyqtSignal() @pyqtProperty(Duration, notify=currentPrintTimeChanged) def currentPrintTime(self): return self._current_print_time materialLengthsChanged = pyqtSignal() @pyqtProperty("QVariantList", notify=materialLengthsChanged) def materialLengths(self): return self._material_lengths materialWeightsChanged = pyqtSignal() @pyqtProperty("QVariantList", notify=materialWeightsChanged) def materialWeights(self): return self._material_weights def _onPrintDurationMessage(self, total_time, material_amounts): self._current_print_time.setDuration(total_time) self.currentPrintTimeChanged.emit() # Material amount is sent as an amount of mm^3, so calculate length from that r = Application.getInstance().getGlobalContainerStack().getProperty("material_diameter", "value") / 2 self._material_lengths = [] self._material_weights = [] extruder_stacks = list( cura.Settings.ExtruderManager.getInstance().getMachineExtruders( Application.getInstance().getGlobalContainerStack().getId() ) ) for index, amount in enumerate(material_amounts): ## Find the right extruder stack. As the list isn't sorted because it's a annoying generator, we do some # list comprehension filtering to solve this for us. if extruder_stacks: # Multi extrusion machine extruder_stack = [ extruder for extruder in extruder_stacks if extruder.getMetaDataEntry("position") == str(index) ][0] density = extruder_stack.getMetaDataEntry("properties", {}).get("density", 0) else: # Machine with no extruder stacks density = ( Application.getInstance() .getGlobalContainerStack() .getMetaDataEntry("properties", {}) .get("density", 0) ) self._material_weights.append(float(amount) * float(density) / 1000) self._material_lengths.append(round((amount / (math.pi * r ** 2)) / 1000, 2)) self.materialLengthsChanged.emit() self.materialWeightsChanged.emit() @pyqtSlot(str) def setJobName(self, name): # Ensure that we don't use entire path but only filename name = os.path.basename(name) # when a file is opened using the terminal; the filename comes from _onFileLoaded and still contains its # extension. This cuts the extension off if necessary. name = os.path.splitext(name)[0] if self._job_name != name: self._job_name = name self.jobNameChanged.emit() jobNameChanged = pyqtSignal() @pyqtProperty(str, notify=jobNameChanged) def jobName(self): return self._job_name @pyqtSlot(str, result=str) def createJobName(self, base_name): base_name = self._stripAccents(base_name) if Preferences.getInstance().getValue("cura/jobname_prefix"): return self._abbr_machine + "_" + base_name else: return base_name ## Created an acronymn-like abbreviated machine name from the currently active machine name # Called each time the global stack is switched def _setAbbreviatedMachineName(self): global_stack_name = Application.getInstance().getGlobalContainerStack().getName() split_name = global_stack_name.split(" ") abbr_machine = "" for word in split_name: if word.lower() == "ultimaker": abbr_machine += "UM" elif word.isdigit(): abbr_machine += word else: abbr_machine += self._stripAccents(word.strip("()[]{}#").upper())[0] self._abbr_machine = abbr_machine ## Utility method that strips accents from characters (eg: â -> a) def _stripAccents(self, str): return "".join(char for char in unicodedata.normalize("NFD", str) if unicodedata.category(char) != "Mn")
class PrintInformation(QObject): class SlicePass: CurrentSettings = 1 LowQualitySettings = 2 HighQualitySettings = 3 class SliceReason: SceneChanged = 1 SettingChanged = 2 ActiveMachineChanged = 3 Other = 4 def __init__(self, parent = None): super().__init__(parent) self._enabled = False self._minimum_print_time = Duration(None, self) self._current_print_time = Duration(None, self) self._maximum_print_time = Duration(None, self) self._material_amount = -1 self._time_quality_value = 50 self._time_quality_changed_timer = QTimer() self._time_quality_changed_timer.setInterval(500) self._time_quality_changed_timer.setSingleShot(True) self._time_quality_changed_timer.timeout.connect(self._updateTimeQualitySettings) self._interpolation_settings = { "layer_height": { "minimum": "low", "maximum": "high", "curve": "linear", "precision": 2 }, "fill_sparse_density": { "minimum": "low", "maximum": "high", "curve": "linear", "precision": 0 } } self._low_quality_settings = None self._current_settings = None self._high_quality_settings = None self._slice_pass = None self._slice_reason = None Application.getInstance().activeMachineChanged.connect(self._onActiveMachineChanged) self._onActiveMachineChanged() Application.getInstance().getController().getScene().sceneChanged.connect(self._onSceneChanged) self._backend = Application.getInstance().getBackend() if self._backend: self._backend.printDurationMessage.connect(self._onPrintDurationMessage) self._backend.slicingStarted.connect(self._onSlicingStarted) self._backend.slicingCancelled.connect(self._onSlicingCancelled) minimumPrintTimeChanged = pyqtSignal() @pyqtProperty(Duration, notify = minimumPrintTimeChanged) def minimumPrintTime(self): return self._minimum_print_time currentPrintTimeChanged = pyqtSignal() @pyqtProperty(Duration, notify = currentPrintTimeChanged) def currentPrintTime(self): return self._current_print_time maximumPrintTimeChanged = pyqtSignal() @pyqtProperty(Duration, notify = maximumPrintTimeChanged) def maximumPrintTime(self): return self._maximum_print_time materialAmountChanged = pyqtSignal() @pyqtProperty(float, notify = materialAmountChanged) def materialAmount(self): return self._material_amount timeQualityValueChanged = pyqtSignal() @pyqtProperty(int, notify = timeQualityValueChanged) def timeQualityValue(self): return self._time_quality_value def setEnabled(self, enabled): if enabled != self._enabled: self._enabled = enabled if self._enabled: self._updateTimeQualitySettings() self._onSlicingStarted() self.enabledChanged.emit() enabledChanged = pyqtSignal() @pyqtProperty(bool, fset = setEnabled, notify = enabledChanged) def enabled(self): return self._enabled @pyqtSlot(int) def setTimeQualityValue(self, value): if value != self._time_quality_value: self._time_quality_value = value self.timeQualityValueChanged.emit() self._time_quality_changed_timer.start() def _onSlicingStarted(self): if self._slice_pass is None: self._slice_pass = self.SlicePass.CurrentSettings if self._slice_reason is None: self._slice_reason = self.SliceReason.Other if self._slice_pass == self.SlicePass.CurrentSettings and self._slice_reason != self.SliceReason.SettingChanged: self._minimum_print_time.setDuration(-1) self.minimumPrintTimeChanged.emit() self._maximum_print_time.setDuration(-1) self.maximumPrintTimeChanged.emit() def _onPrintDurationMessage(self, time, amount): if self._slice_pass == self.SlicePass.CurrentSettings: self._current_print_time.setDuration(time) self.currentPrintTimeChanged.emit() self._material_amount = round(amount / 10) / 100 self.materialAmountChanged.emit() if not self._enabled: return if self._slice_reason != self.SliceReason.SettingChanged or not self._minimum_print_time.valid or not self._maximum_print_time.valid: self._slice_pass = self.SlicePass.LowQualitySettings self._backend.slice(settings = self._low_quality_settings, save_gcode = False, save_polygons = False, force_restart = False, report_progress = False) else: self._slice_pass = None self._slice_reason = None elif self._slice_pass == self.SlicePass.LowQualitySettings: self._minimum_print_time.setDuration(time) self.minimumPrintTimeChanged.emit() self._slice_pass = self.SlicePass.HighQualitySettings self._backend.slice(settings = self._high_quality_settings, save_gcode = False, save_polygons = False, force_restart = False, report_progress = False) elif self._slice_pass == self.SlicePass.HighQualitySettings: self._maximum_print_time.setDuration(time) self.maximumPrintTimeChanged.emit() self._slice_pass = None self._slice_reason = None def _onActiveMachineChanged(self): if self._current_settings: self._current_settings.settingChanged.disconnect(self._onSettingChanged) self._current_settings = Application.getInstance().getActiveMachine() if self._current_settings: self._current_settings.settingChanged.connect(self._onSettingChanged) self._low_quality_settings = None self._high_quality_settings = None self._updateTimeQualitySettings() self._slice_reason = self.SliceReason.ActiveMachineChanged def _updateTimeQualitySettings(self): if not self._current_settings or not self._enabled: return if not self._low_quality_settings: self._low_quality_settings = MachineSettings() self._low_quality_settings.loadSettingsFromFile(Resources.getPath(Resources.SettingsLocation, self._current_settings.getTypeID() + ".json")) self._low_quality_settings.loadValuesFromFile(Resources.getPath(Resources.SettingsLocation, "profiles", "low_quality.conf")) if not self._high_quality_settings: self._high_quality_settings = MachineSettings() self._high_quality_settings.loadSettingsFromFile(Resources.getPath(Resources.SettingsLocation, self._current_settings.getTypeID() + ".json")) self._high_quality_settings.loadValuesFromFile(Resources.getPath(Resources.SettingsLocation, "profiles", "high_quality.conf")) for key, options in self._interpolation_settings.items(): minimum_value = None if options["minimum"] == "low": minimum_value = self._low_quality_settings.getSettingValueByKey(key) elif options["minimum"] == "high": minimum_value = self._high_quality_settings.getSettingValueByKey(key) else: continue maximum_value = None if options["maximum"] == "low": maximum_value = self._low_quality_settings.getSettingValueByKey(key) elif options["maximum"] == "high": maximum_value = self._high_quality_settings.getSettingValueByKey(key) else: continue setting_value = round(minimum_value + (maximum_value - minimum_value) * (self._time_quality_value / 100), options["precision"]) self._current_settings.setSettingValueByKey(key, setting_value) def _onSceneChanged(self, source): self._slice_reason = self.SliceReason.SceneChanged def _onSettingChanged(self, source): self._slice_reason = self.SliceReason.SettingChanged def _onSlicingCancelled(self): self._slice_pass = None
class PrintInformation(QObject): class SlicePass: CurrentSettings = 1 LowQualitySettings = 2 HighQualitySettings = 3 class SliceReason: SceneChanged = 1 SettingChanged = 2 ActiveMachineChanged = 3 Other = 4 def __init__(self, parent = None): super().__init__(parent) self._current_print_time = Duration(None, self) self._material_lengths = [] self._material_weights = [] self._material_costs = [] self._pre_sliced = False self._backend = Application.getInstance().getBackend() if self._backend: self._backend.printDurationMessage.connect(self._onPrintDurationMessage) self._job_name = "" self._abbr_machine = "" Application.getInstance().globalContainerStackChanged.connect(self._setAbbreviatedMachineName) Application.getInstance().fileLoaded.connect(self.setJobName) Preferences.getInstance().preferenceChanged.connect(self._onPreferencesChanged) self._active_material_container = None Application.getInstance().getMachineManager().activeMaterialChanged.connect(self._onActiveMaterialChanged) self._onActiveMaterialChanged() self._material_amounts = [] currentPrintTimeChanged = pyqtSignal() preSlicedChanged = pyqtSignal() @pyqtProperty(bool, notify=preSlicedChanged) def preSliced(self): return self._pre_sliced def setPreSliced(self, pre_sliced): self._pre_sliced = pre_sliced self.preSlicedChanged.emit() @pyqtProperty(Duration, notify = currentPrintTimeChanged) def currentPrintTime(self): return self._current_print_time materialLengthsChanged = pyqtSignal() @pyqtProperty("QVariantList", notify = materialLengthsChanged) def materialLengths(self): return self._material_lengths materialWeightsChanged = pyqtSignal() @pyqtProperty("QVariantList", notify = materialWeightsChanged) def materialWeights(self): return self._material_weights materialCostsChanged = pyqtSignal() @pyqtProperty("QVariantList", notify = materialCostsChanged) def materialCosts(self): return self._material_costs def _onPrintDurationMessage(self, total_time, material_amounts): if total_time != total_time: # Check for NaN. Engine can sometimes give us weird values. Logger.log("w", "Received NaN for print duration message") self._current_print_time.setDuration(0) else: self._current_print_time.setDuration(total_time) self.currentPrintTimeChanged.emit() self._material_amounts = material_amounts self._calculateInformation() def _calculateInformation(self): if Application.getInstance().getGlobalContainerStack() is None: return # Material amount is sent as an amount of mm^3, so calculate length from that radius = Application.getInstance().getGlobalContainerStack().getProperty("material_diameter", "value") / 2 self._material_lengths = [] self._material_weights = [] self._material_costs = [] material_preference_values = json.loads(Preferences.getInstance().getValue("cura/material_settings")) extruder_stacks = list(ExtruderManager.getInstance().getMachineExtruders(Application.getInstance().getGlobalContainerStack().getId())) for index, amount in enumerate(self._material_amounts): ## Find the right extruder stack. As the list isn't sorted because it's a annoying generator, we do some # list comprehension filtering to solve this for us. material = None if extruder_stacks: # Multi extrusion machine extruder_stack = [extruder for extruder in extruder_stacks if extruder.getMetaDataEntry("position") == str(index)][0] density = extruder_stack.getMetaDataEntry("properties", {}).get("density", 0) material = extruder_stack.findContainer({"type": "material"}) else: # Machine with no extruder stacks density = Application.getInstance().getGlobalContainerStack().getMetaDataEntry("properties", {}).get("density", 0) material = Application.getInstance().getGlobalContainerStack().findContainer({"type": "material"}) weight = float(amount) * float(density) / 1000 cost = 0 if material: material_guid = material.getMetaDataEntry("GUID") if material_guid in material_preference_values: material_values = material_preference_values[material_guid] weight_per_spool = float(material_values["spool_weight"] if material_values and "spool_weight" in material_values else 0) cost_per_spool = float(material_values["spool_cost"] if material_values and "spool_cost" in material_values else 0) if weight_per_spool != 0: cost = cost_per_spool * weight / weight_per_spool else: cost = 0 if radius != 0: length = round((amount / (math.pi * radius ** 2)) / 1000, 2) else: length = 0 self._material_weights.append(weight) self._material_lengths.append(length) self._material_costs.append(cost) self.materialLengthsChanged.emit() self.materialWeightsChanged.emit() self.materialCostsChanged.emit() def _onPreferencesChanged(self, preference): if preference != "cura/material_settings": return self._calculateInformation() def _onActiveMaterialChanged(self): if self._active_material_container: self._active_material_container.metaDataChanged.disconnect(self._onMaterialMetaDataChanged) active_material_id = Application.getInstance().getMachineManager().activeMaterialId active_material_containers = ContainerRegistry.getInstance().findInstanceContainers(id=active_material_id) if active_material_containers: self._active_material_container = active_material_containers[0] self._active_material_container.metaDataChanged.connect(self._onMaterialMetaDataChanged) def _onMaterialMetaDataChanged(self, *args, **kwargs): self._calculateInformation() @pyqtSlot(str) def setJobName(self, name): # Ensure that we don't use entire path but only filename name = os.path.basename(name) # when a file is opened using the terminal; the filename comes from _onFileLoaded and still contains its # extension. This cuts the extension off if necessary. name = os.path.splitext(name)[0] if self._job_name != name: self._job_name = name self.jobNameChanged.emit() jobNameChanged = pyqtSignal() @pyqtProperty(str, notify = jobNameChanged) def jobName(self): return self._job_name @pyqtSlot(str, result = str) def createJobName(self, base_name): if base_name == "": return "" base_name = self._stripAccents(base_name) self._setAbbreviatedMachineName() if self._pre_sliced: return catalog.i18nc("@label", "Pre-sliced file {0}", base_name) elif Preferences.getInstance().getValue("cura/jobname_prefix"): # Don't add abbreviation if it already has the exact same abbreviation. if base_name.startswith(self._abbr_machine + "_"): return base_name return self._abbr_machine + "_" + base_name else: return base_name ## Created an acronymn-like abbreviated machine name from the currently active machine name # Called each time the global stack is switched def _setAbbreviatedMachineName(self): global_container_stack = Application.getInstance().getGlobalContainerStack() if not global_container_stack: self._abbr_machine = "" return global_stack_name = global_container_stack.getName() split_name = global_stack_name.split(" ") abbr_machine = "" for word in split_name: if word.lower() == "ultimaker": abbr_machine += "UM" elif word.isdigit(): abbr_machine += word else: abbr_machine += self._stripAccents(word.strip("()[]{}#").upper())[0] self._abbr_machine = abbr_machine ## Utility method that strips accents from characters (eg: â -> a) def _stripAccents(self, str): return ''.join(char for char in unicodedata.normalize('NFD', str) if unicodedata.category(char) != 'Mn')
class PrintInformation(QObject): class SlicePass: CurrentSettings = 1 LowQualitySettings = 2 HighQualitySettings = 3 class SliceReason: SceneChanged = 1 SettingChanged = 2 ActiveMachineChanged = 3 Other = 4 def __init__(self, parent=None): super().__init__(parent) self._enabled = False self._minimum_print_time = Duration(None, self) self._current_print_time = Duration(None, self) self._maximum_print_time = Duration(None, self) self._material_amount = -1 self._time_quality_value = 50 self._time_quality_changed_timer = QTimer() self._time_quality_changed_timer.setInterval(500) self._time_quality_changed_timer.setSingleShot(True) self._time_quality_changed_timer.timeout.connect( self._updateTimeQualitySettings) self._interpolation_settings = { "layer_height": { "minimum": "low", "maximum": "high", "curve": "linear", "precision": 2 }, "fill_sparse_density": { "minimum": "low", "maximum": "high", "curve": "linear", "precision": 0 } } self._low_quality_settings = None self._current_settings = None self._high_quality_settings = None self._slice_pass = None self._slice_reason = None Application.getInstance().activeMachineChanged.connect( self._onActiveMachineChanged) self._onActiveMachineChanged() Application.getInstance().getController().getScene( ).sceneChanged.connect(self._onSceneChanged) self._backend = Application.getInstance().getBackend() if self._backend: self._backend.printDurationMessage.connect( self._onPrintDurationMessage) self._backend.slicingStarted.connect(self._onSlicingStarted) self._backend.slicingCancelled.connect(self._onSlicingCancelled) minimumPrintTimeChanged = pyqtSignal() @pyqtProperty(Duration, notify=minimumPrintTimeChanged) def minimumPrintTime(self): return self._minimum_print_time currentPrintTimeChanged = pyqtSignal() @pyqtProperty(Duration, notify=currentPrintTimeChanged) def currentPrintTime(self): return self._current_print_time maximumPrintTimeChanged = pyqtSignal() @pyqtProperty(Duration, notify=maximumPrintTimeChanged) def maximumPrintTime(self): return self._maximum_print_time materialAmountChanged = pyqtSignal() @pyqtProperty(float, notify=materialAmountChanged) def materialAmount(self): return self._material_amount timeQualityValueChanged = pyqtSignal() @pyqtProperty(int, notify=timeQualityValueChanged) def timeQualityValue(self): return self._time_quality_value def setEnabled(self, enabled): if enabled != self._enabled: self._enabled = enabled if self._enabled: self._updateTimeQualitySettings() self._onSlicingStarted() self.enabledChanged.emit() enabledChanged = pyqtSignal() @pyqtProperty(bool, fset=setEnabled, notify=enabledChanged) def enabled(self): return self._enabled @pyqtSlot(int) def setTimeQualityValue(self, value): if value != self._time_quality_value: self._time_quality_value = value self.timeQualityValueChanged.emit() self._time_quality_changed_timer.start() def _onSlicingStarted(self): if self._slice_pass is None: self._slice_pass = self.SlicePass.CurrentSettings if self._slice_reason is None: self._slice_reason = self.SliceReason.Other if self._slice_pass == self.SlicePass.CurrentSettings and self._slice_reason != self.SliceReason.SettingChanged: self._minimum_print_time.setDuration(-1) self.minimumPrintTimeChanged.emit() self._maximum_print_time.setDuration(-1) self.maximumPrintTimeChanged.emit() def _onPrintDurationMessage(self, time, amount): if self._slice_pass == self.SlicePass.CurrentSettings: self._current_print_time.setDuration(time) self.currentPrintTimeChanged.emit() self._material_amount = round(amount / 10) / 100 self.materialAmountChanged.emit() if not self._enabled: return if self._slice_reason != self.SliceReason.SettingChanged or not self._minimum_print_time.valid or not self._maximum_print_time.valid: self._slice_pass = self.SlicePass.LowQualitySettings self._backend.slice(settings=self._low_quality_settings, save_gcode=False, save_polygons=False, force_restart=False, report_progress=False) else: self._slice_pass = None self._slice_reason = None elif self._slice_pass == self.SlicePass.LowQualitySettings: self._minimum_print_time.setDuration(time) self.minimumPrintTimeChanged.emit() self._slice_pass = self.SlicePass.HighQualitySettings self._backend.slice(settings=self._high_quality_settings, save_gcode=False, save_polygons=False, force_restart=False, report_progress=False) elif self._slice_pass == self.SlicePass.HighQualitySettings: self._maximum_print_time.setDuration(time) self.maximumPrintTimeChanged.emit() self._slice_pass = None self._slice_reason = None def _onActiveMachineChanged(self): if self._current_settings: self._current_settings.settingChanged.disconnect( self._onSettingChanged) self._current_settings = Application.getInstance().getActiveMachine() if self._current_settings: self._current_settings.settingChanged.connect( self._onSettingChanged) self._low_quality_settings = None self._high_quality_settings = None self._updateTimeQualitySettings() self._slice_reason = self.SliceReason.ActiveMachineChanged def _updateTimeQualitySettings(self): if not self._current_settings or not self._enabled: return if not self._low_quality_settings: self._low_quality_settings = MachineSettings() self._low_quality_settings.loadSettingsFromFile( Resources.getPath(Resources.SettingsLocation, self._current_settings.getTypeID() + ".json")) self._low_quality_settings.loadValuesFromFile( Resources.getPath(Resources.SettingsLocation, "profiles", "low_quality.conf")) if not self._high_quality_settings: self._high_quality_settings = MachineSettings() self._high_quality_settings.loadSettingsFromFile( Resources.getPath(Resources.SettingsLocation, self._current_settings.getTypeID() + ".json")) self._high_quality_settings.loadValuesFromFile( Resources.getPath(Resources.SettingsLocation, "profiles", "high_quality.conf")) for key, options in self._interpolation_settings.items(): minimum_value = None if options["minimum"] == "low": minimum_value = self._low_quality_settings.getSettingValueByKey( key) elif options["minimum"] == "high": minimum_value = self._high_quality_settings.getSettingValueByKey( key) else: continue maximum_value = None if options["maximum"] == "low": maximum_value = self._low_quality_settings.getSettingValueByKey( key) elif options["maximum"] == "high": maximum_value = self._high_quality_settings.getSettingValueByKey( key) else: continue setting_value = round( minimum_value + (maximum_value - minimum_value) * (self._time_quality_value / 100), options["precision"]) self._current_settings.setSettingValueByKey(key, setting_value) def _onSceneChanged(self, source): self._slice_reason = self.SliceReason.SceneChanged def _onSettingChanged(self, source): self._slice_reason = self.SliceReason.SettingChanged def _onSlicingCancelled(self): self._slice_pass = None
class PrintInformation(QObject): class SlicePass: CurrentSettings = 1 LowQualitySettings = 2 HighQualitySettings = 3 class SliceReason: SceneChanged = 1 SettingChanged = 2 ActiveMachineChanged = 3 Other = 4 def __init__(self, parent=None): super().__init__(parent) self._current_print_time = Duration(None, self) self._material_amount = -1 self._backend = Application.getInstance().getBackend() if self._backend: self._backend.printDurationMessage.connect( self._onPrintDurationMessage) self._job_name = "" self._abbr_machine = "" Application.getInstance().globalContainerStackChanged.connect( self._setAbbreviatedMachineName) Application.getInstance().fileLoaded.connect(self.setJobName) currentPrintTimeChanged = pyqtSignal() @pyqtProperty(Duration, notify=currentPrintTimeChanged) def currentPrintTime(self): return self._current_print_time materialAmountChanged = pyqtSignal() @pyqtProperty(float, notify=materialAmountChanged) def materialAmount(self): return self._material_amount def _onPrintDurationMessage(self, time, amount): #if self._slice_pass == self.SlicePass.CurrentSettings: self._current_print_time.setDuration(time) self.currentPrintTimeChanged.emit() # Material amount is sent as an amount of mm^3, so calculate length from that r = Application.getInstance().getGlobalContainerStack().getProperty( "material_diameter", "value") / 2 self._material_amount = round((amount / (math.pi * r**2)) / 1000, 2) self.materialAmountChanged.emit() @pyqtSlot(str) def setJobName(self, name): # when a file is opened using the terminal; the filename comes from _onFileLoaded and still contains its # extension. This cuts the extension off if necessary. name = os.path.splitext(name)[0] if self._job_name != name: self._job_name = name self.jobNameChanged.emit() jobNameChanged = pyqtSignal() @pyqtProperty(str, notify=jobNameChanged) def jobName(self): return self._job_name @pyqtSlot(str, result=str) def createJobName(self, base_name): base_name = self._stripAccents(base_name) if Preferences.getInstance().getValue("cura/jobname_prefix"): return self._abbr_machine + "_" + base_name else: return base_name ## Created an acronymn-like abbreviated machine name from the currently active machine name # Called each time the global stack is switched def _setAbbreviatedMachineName(self): global_stack_name = Application.getInstance().getGlobalContainerStack( ).getName() split_name = global_stack_name.split(" ") abbr_machine = "" for word in split_name: if word.lower() == "ultimaker": abbr_machine += "UM" elif word.isdigit(): abbr_machine += word else: abbr_machine += self._stripAccents( word.strip("()[]{}#").upper())[0] self._abbr_machine = abbr_machine ## Utility method that strips accents from characters (eg: â -> a) def _stripAccents(self, str): return ''.join(char for char in unicodedata.normalize('NFD', str) if unicodedata.category(char) != 'Mn')