PrintInformation.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. # Copyright (c) 2015 Ultimaker B.V.
  2. # Cura is released under the terms of the AGPLv3 or higher.
  3. from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty, pyqtSlot
  4. from UM.Application import Application
  5. from UM.Qt.Duration import Duration
  6. from UM.Preferences import Preferences
  7. import math
  8. import os.path
  9. import unicodedata
  10. ## A class for processing and calculating minimum, current and maximum print time as well as managing the job name
  11. #
  12. # This class contains all the logic relating to calculation and slicing for the
  13. # time/quality slider concept. It is a rather tricky combination of event handling
  14. # and state management. The logic behind this is as follows:
  15. #
  16. # - A scene change or setting change event happens.
  17. # We track what the source was of the change, either a scene change, a setting change, an active machine change or something else.
  18. # - This triggers a new slice with the current settings - this is the "current settings pass".
  19. # - When the slice is done, we update the current print time and material amount.
  20. # - If the source of the slice was not a Setting change, we start the second slice pass, the "low quality settings pass". Otherwise we stop here.
  21. # - When that is done, we update the minimum print time and start the final slice pass, the "high quality settings pass".
  22. # - When the high quality pass is done, we update the maximum print time.
  23. #
  24. # This class also mangles the current machine name and the filename of the first loaded mesh into a job name.
  25. # This job name is requested by the JobSpecs qml file.
  26. class PrintInformation(QObject):
  27. class SlicePass:
  28. CurrentSettings = 1
  29. LowQualitySettings = 2
  30. HighQualitySettings = 3
  31. class SliceReason:
  32. SceneChanged = 1
  33. SettingChanged = 2
  34. ActiveMachineChanged = 3
  35. Other = 4
  36. def __init__(self, parent = None):
  37. super().__init__(parent)
  38. self._current_print_time = Duration(None, self)
  39. self._material_amounts = []
  40. self._backend = Application.getInstance().getBackend()
  41. if self._backend:
  42. self._backend.printDurationMessage.connect(self._onPrintDurationMessage)
  43. self._job_name = ""
  44. self._abbr_machine = ""
  45. Application.getInstance().globalContainerStackChanged.connect(self._setAbbreviatedMachineName)
  46. Application.getInstance().fileLoaded.connect(self.setJobName)
  47. currentPrintTimeChanged = pyqtSignal()
  48. @pyqtProperty(Duration, notify = currentPrintTimeChanged)
  49. def currentPrintTime(self):
  50. return self._current_print_time
  51. materialAmountsChanged = pyqtSignal()
  52. @pyqtProperty("QVariantList", notify = materialAmountsChanged)
  53. def materialAmounts(self):
  54. return self._material_amounts
  55. def _onPrintDurationMessage(self, total_time, material_amounts):
  56. self._current_print_time.setDuration(total_time)
  57. self.currentPrintTimeChanged.emit()
  58. # Material amount is sent as an amount of mm^3, so calculate length from that
  59. r = Application.getInstance().getGlobalContainerStack().getProperty("material_diameter", "value") / 2
  60. self._material_amounts = []
  61. for amount in material_amounts:
  62. self._material_amounts.append(round((amount / (math.pi * r ** 2)) / 1000, 2))
  63. self.materialAmountsChanged.emit()
  64. @pyqtSlot(str)
  65. def setJobName(self, name):
  66. # when a file is opened using the terminal; the filename comes from _onFileLoaded and still contains its
  67. # extension. This cuts the extension off if necessary.
  68. name = os.path.splitext(name)[0]
  69. if self._job_name != name:
  70. self._job_name = name
  71. self.jobNameChanged.emit()
  72. jobNameChanged = pyqtSignal()
  73. @pyqtProperty(str, notify = jobNameChanged)
  74. def jobName(self):
  75. return self._job_name
  76. @pyqtSlot(str, result = str)
  77. def createJobName(self, base_name):
  78. base_name = self._stripAccents(base_name)
  79. if Preferences.getInstance().getValue("cura/jobname_prefix"):
  80. return self._abbr_machine + "_" + base_name
  81. else:
  82. return base_name
  83. ## Created an acronymn-like abbreviated machine name from the currently active machine name
  84. # Called each time the global stack is switched
  85. def _setAbbreviatedMachineName(self):
  86. global_stack_name = Application.getInstance().getGlobalContainerStack().getName()
  87. split_name = global_stack_name.split(" ")
  88. abbr_machine = ""
  89. for word in split_name:
  90. if word.lower() == "ultimaker":
  91. abbr_machine += "UM"
  92. elif word.isdigit():
  93. abbr_machine += word
  94. else:
  95. abbr_machine += self._stripAccents(word.strip("()[]{}#").upper())[0]
  96. self._abbr_machine = abbr_machine
  97. ## Utility method that strips accents from characters (eg: â -> a)
  98. def _stripAccents(self, str):
  99. return ''.join(char for char in unicodedata.normalize('NFD', str) if unicodedata.category(char) != 'Mn')