mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-06 14:37:29 -06:00
Convert doxygen to rst for CuraEngineBackend
This commit is contained in:
parent
8f3827d5ae
commit
797d6ed438
3 changed files with 220 additions and 143 deletions
|
@ -42,12 +42,14 @@ catalog = i18nCatalog("cura")
|
|||
class CuraEngineBackend(QObject, Backend):
|
||||
backendError = Signal()
|
||||
|
||||
## Starts the back-end plug-in.
|
||||
#
|
||||
# This registers all the signal listeners and prepares for communication
|
||||
# with the back-end in general.
|
||||
# CuraEngineBackend is exposed to qml as well.
|
||||
def __init__(self) -> None:
|
||||
"""Starts the back-end plug-in.
|
||||
|
||||
This registers all the signal listeners and prepares for communication
|
||||
with the back-end in general.
|
||||
CuraEngineBackend is exposed to qml as well.
|
||||
"""
|
||||
|
||||
super().__init__()
|
||||
# Find out where the engine is located, and how it is called.
|
||||
# This depends on how Cura is packaged and which OS we are running on.
|
||||
|
@ -177,18 +179,22 @@ class CuraEngineBackend(QObject, Backend):
|
|||
self._machine_error_checker = self._application.getMachineErrorChecker()
|
||||
self._machine_error_checker.errorCheckFinished.connect(self._onStackErrorCheckFinished)
|
||||
|
||||
## Terminate the engine process.
|
||||
#
|
||||
# This function should terminate the engine process.
|
||||
# Called when closing the application.
|
||||
def close(self) -> None:
|
||||
"""Terminate the engine process.
|
||||
|
||||
This function should terminate the engine process.
|
||||
Called when closing the application.
|
||||
"""
|
||||
|
||||
# Terminate CuraEngine if it is still running at this point
|
||||
self._terminate()
|
||||
|
||||
## Get the command that is used to call the engine.
|
||||
# This is useful for debugging and used to actually start the engine.
|
||||
# \return list of commands and args / parameters.
|
||||
def getEngineCommand(self) -> List[str]:
|
||||
"""Get the command that is used to call the engine.
|
||||
|
||||
This is useful for debugging and used to actually start the engine.
|
||||
:return: list of commands and args / parameters.
|
||||
"""
|
||||
command = [self._application.getPreferences().getValue("backend/location"), "connect", "127.0.0.1:{0}".format(self._port), ""]
|
||||
|
||||
parser = argparse.ArgumentParser(prog = "cura", add_help = False)
|
||||
|
@ -199,17 +205,18 @@ class CuraEngineBackend(QObject, Backend):
|
|||
|
||||
return command
|
||||
|
||||
## Emitted when we get a message containing print duration and material amount.
|
||||
# This also implies the slicing has finished.
|
||||
# \param time The amount of time the print will take.
|
||||
# \param material_amount The amount of material the print will use.
|
||||
printDurationMessage = Signal()
|
||||
|
||||
## Emitted when the slicing process starts.
|
||||
"""Emitted when we get a message containing print duration and material amount.
|
||||
|
||||
This also implies the slicing has finished.
|
||||
:param time: The amount of time the print will take.
|
||||
:param material_amount: The amount of material the print will use.
|
||||
"""
|
||||
slicingStarted = Signal()
|
||||
"""Emitted when the slicing process starts."""
|
||||
|
||||
## Emitted when the slicing process is aborted forcefully.
|
||||
slicingCancelled = Signal()
|
||||
"""Emitted when the slicing process is aborted forcefully."""
|
||||
|
||||
@pyqtSlot()
|
||||
def stopSlicing(self) -> None:
|
||||
|
@ -226,14 +233,16 @@ class CuraEngineBackend(QObject, Backend):
|
|||
if self._error_message:
|
||||
self._error_message.hide()
|
||||
|
||||
## Manually triggers a reslice
|
||||
@pyqtSlot()
|
||||
def forceSlice(self) -> None:
|
||||
"""Manually triggers a reslice"""
|
||||
|
||||
self.markSliceAll()
|
||||
self.slice()
|
||||
|
||||
## Perform a slice of the scene.
|
||||
def slice(self) -> None:
|
||||
"""Perform a slice of the scene."""
|
||||
|
||||
Logger.log("i", "Starting to slice...")
|
||||
self._slice_start_time = time()
|
||||
if not self._build_plates_to_be_sliced:
|
||||
|
@ -289,9 +298,11 @@ class CuraEngineBackend(QObject, Backend):
|
|||
self._start_slice_job.start()
|
||||
self._start_slice_job.finished.connect(self._onStartSliceCompleted)
|
||||
|
||||
## Terminate the engine process.
|
||||
# Start the engine process by calling _createSocket()
|
||||
def _terminate(self) -> None:
|
||||
"""Terminate the engine process.
|
||||
|
||||
Start the engine process by calling _createSocket()
|
||||
"""
|
||||
self._slicing = False
|
||||
self._stored_layer_data = []
|
||||
if self._start_slice_job_build_plate in self._stored_optimized_layer_data:
|
||||
|
@ -316,15 +327,17 @@ class CuraEngineBackend(QObject, Backend):
|
|||
except Exception as e: # terminating a process that is already terminating causes an exception, silently ignore this.
|
||||
Logger.log("d", "Exception occurred while trying to kill the engine %s", str(e))
|
||||
|
||||
## Event handler to call when the job to initiate the slicing process is
|
||||
# completed.
|
||||
#
|
||||
# When the start slice job is successfully completed, it will be happily
|
||||
# slicing. This function handles any errors that may occur during the
|
||||
# bootstrapping of a slice job.
|
||||
#
|
||||
# \param job The start slice job that was just finished.
|
||||
def _onStartSliceCompleted(self, job: StartSliceJob) -> None:
|
||||
"""Event handler to call when the job to initiate the slicing process is
|
||||
|
||||
completed.
|
||||
|
||||
When the start slice job is successfully completed, it will be happily
|
||||
slicing. This function handles any errors that may occur during the
|
||||
bootstrapping of a slice job.
|
||||
|
||||
:param job: The start slice job that was just finished.
|
||||
"""
|
||||
if self._error_message:
|
||||
self._error_message.hide()
|
||||
|
||||
|
@ -443,11 +456,13 @@ class CuraEngineBackend(QObject, Backend):
|
|||
if self._slice_start_time:
|
||||
Logger.log("d", "Sending slice message took %s seconds", time() - self._slice_start_time )
|
||||
|
||||
## Determine enable or disable auto slicing. Return True for enable timer and False otherwise.
|
||||
# It disables when
|
||||
# - preference auto slice is off
|
||||
# - decorator isBlockSlicing is found (used in g-code reader)
|
||||
def determineAutoSlicing(self) -> bool:
|
||||
"""Determine enable or disable auto slicing. Return True for enable timer and False otherwise.
|
||||
|
||||
It disables when:
|
||||
- preference auto slice is off
|
||||
- decorator isBlockSlicing is found (used in g-code reader)
|
||||
"""
|
||||
enable_timer = True
|
||||
self._is_disabled = False
|
||||
|
||||
|
@ -472,8 +487,9 @@ class CuraEngineBackend(QObject, Backend):
|
|||
self.disableTimer()
|
||||
return False
|
||||
|
||||
## Return a dict with number of objects per build plate
|
||||
def _numObjectsPerBuildPlate(self) -> Dict[int, int]:
|
||||
"""Return a dict with number of objects per build plate"""
|
||||
|
||||
num_objects = defaultdict(int) #type: Dict[int, int]
|
||||
for node in DepthFirstIterator(self._scene.getRoot()):
|
||||
# Only count sliceable objects
|
||||
|
@ -483,12 +499,14 @@ class CuraEngineBackend(QObject, Backend):
|
|||
num_objects[build_plate_number] += 1
|
||||
return num_objects
|
||||
|
||||
## Listener for when the scene has changed.
|
||||
#
|
||||
# This should start a slice if the scene is now ready to slice.
|
||||
#
|
||||
# \param source The scene node that was changed.
|
||||
def _onSceneChanged(self, source: SceneNode) -> None:
|
||||
"""Listener for when the scene has changed.
|
||||
|
||||
This should start a slice if the scene is now ready to slice.
|
||||
|
||||
:param source: The scene node that was changed.
|
||||
"""
|
||||
|
||||
if not source.callDecoration("isSliceable"):
|
||||
return
|
||||
|
||||
|
@ -536,10 +554,12 @@ class CuraEngineBackend(QObject, Backend):
|
|||
|
||||
self._invokeSlice()
|
||||
|
||||
## Called when an error occurs in the socket connection towards the engine.
|
||||
#
|
||||
# \param error The exception that occurred.
|
||||
def _onSocketError(self, error: Arcus.Error) -> None:
|
||||
"""Called when an error occurs in the socket connection towards the engine.
|
||||
|
||||
:param error: The exception that occurred.
|
||||
"""
|
||||
|
||||
if self._application.isShuttingDown():
|
||||
return
|
||||
|
||||
|
@ -567,8 +587,9 @@ class CuraEngineBackend(QObject, Backend):
|
|||
break
|
||||
return has_slicable
|
||||
|
||||
## Remove old layer data (if any)
|
||||
def _clearLayerData(self, build_plate_numbers: Set = None) -> None:
|
||||
"""Remove old layer data (if any)"""
|
||||
|
||||
# Clear out any old gcode
|
||||
self._scene.gcode_dict = {} # type: ignore
|
||||
|
||||
|
@ -583,8 +604,9 @@ class CuraEngineBackend(QObject, Backend):
|
|||
if build_plate_number not in self._build_plates_to_be_sliced:
|
||||
self._build_plates_to_be_sliced.append(build_plate_number)
|
||||
|
||||
## Convenient function: mark everything to slice, emit state and clear layer data
|
||||
def needsSlicing(self) -> None:
|
||||
"""Convenient function: mark everything to slice, emit state and clear layer data"""
|
||||
|
||||
# CURA-6604: If there's no slicable object, do not (try to) trigger slice, which will clear all the current
|
||||
# gcode. This can break Gcode file loading if it tries to remove it afterwards.
|
||||
if not self.hasSlicableObject():
|
||||
|
@ -597,10 +619,12 @@ class CuraEngineBackend(QObject, Backend):
|
|||
# With manually having to slice, we want to clear the old invalid layer data.
|
||||
self._clearLayerData()
|
||||
|
||||
## A setting has changed, so check if we must reslice.
|
||||
# \param instance The setting instance that has changed.
|
||||
# \param property The property of the setting instance that has changed.
|
||||
def _onSettingChanged(self, instance: SettingInstance, property: str) -> None:
|
||||
"""A setting has changed, so check if we must reslice.
|
||||
|
||||
:param instance: The setting instance that has changed.
|
||||
:param property: The property of the setting instance that has changed.
|
||||
"""
|
||||
if property == "value": # Only reslice if the value has changed.
|
||||
self.needsSlicing()
|
||||
self._onChanged()
|
||||
|
@ -618,25 +642,31 @@ class CuraEngineBackend(QObject, Backend):
|
|||
self.needsSlicing()
|
||||
self._onChanged()
|
||||
|
||||
## Called when a sliced layer data message is received from the engine.
|
||||
#
|
||||
# \param message The protobuf message containing sliced layer data.
|
||||
def _onLayerMessage(self, message: Arcus.PythonMessage) -> None:
|
||||
"""Called when a sliced layer data message is received from the engine.
|
||||
|
||||
:param message: The protobuf message containing sliced layer data.
|
||||
"""
|
||||
|
||||
self._stored_layer_data.append(message)
|
||||
|
||||
## Called when an optimized sliced layer data message is received from the engine.
|
||||
#
|
||||
# \param message The protobuf message containing sliced layer data.
|
||||
def _onOptimizedLayerMessage(self, message: Arcus.PythonMessage) -> None:
|
||||
"""Called when an optimized sliced layer data message is received from the engine.
|
||||
|
||||
:param message: The protobuf message containing sliced layer data.
|
||||
"""
|
||||
|
||||
if self._start_slice_job_build_plate is not None:
|
||||
if self._start_slice_job_build_plate not in self._stored_optimized_layer_data:
|
||||
self._stored_optimized_layer_data[self._start_slice_job_build_plate] = []
|
||||
self._stored_optimized_layer_data[self._start_slice_job_build_plate].append(message)
|
||||
|
||||
## Called when a progress message is received from the engine.
|
||||
#
|
||||
# \param message The protobuf message containing the slicing progress.
|
||||
def _onProgressMessage(self, message: Arcus.PythonMessage) -> None:
|
||||
"""Called when a progress message is received from the engine.
|
||||
|
||||
:param message: The protobuf message containing the slicing progress.
|
||||
"""
|
||||
|
||||
self.processingProgress.emit(message.amount)
|
||||
self.setState(BackendState.Processing)
|
||||
|
||||
|
@ -653,10 +683,12 @@ class CuraEngineBackend(QObject, Backend):
|
|||
else:
|
||||
self._change_timer.start()
|
||||
|
||||
## Called when the engine sends a message that slicing is finished.
|
||||
#
|
||||
# \param message The protobuf message signalling that slicing is finished.
|
||||
def _onSlicingFinishedMessage(self, message: Arcus.PythonMessage) -> None:
|
||||
"""Called when the engine sends a message that slicing is finished.
|
||||
|
||||
:param message: The protobuf message signalling that slicing is finished.
|
||||
"""
|
||||
|
||||
self.setState(BackendState.Done)
|
||||
self.processingProgress.emit(1.0)
|
||||
|
||||
|
@ -698,27 +730,32 @@ class CuraEngineBackend(QObject, Backend):
|
|||
self.enableTimer() # manually enable timer to be able to invoke slice, also when in manual slice mode
|
||||
self._invokeSlice()
|
||||
|
||||
## Called when a g-code message is received from the engine.
|
||||
#
|
||||
# \param message The protobuf message containing g-code, encoded as UTF-8.
|
||||
def _onGCodeLayerMessage(self, message: Arcus.PythonMessage) -> None:
|
||||
"""Called when a g-code message is received from the engine.
|
||||
|
||||
:param message: The protobuf message containing g-code, encoded as UTF-8.
|
||||
"""
|
||||
|
||||
try:
|
||||
self._scene.gcode_dict[self._start_slice_job_build_plate].append(message.data.decode("utf-8", "replace")) #type: ignore #Because we generate this attribute dynamically.
|
||||
except KeyError: # Can occur if the g-code has been cleared while a slice message is still arriving from the other end.
|
||||
pass # Throw the message away.
|
||||
|
||||
## Called when a g-code prefix message is received from the engine.
|
||||
#
|
||||
# \param message The protobuf message containing the g-code prefix,
|
||||
# encoded as UTF-8.
|
||||
def _onGCodePrefixMessage(self, message: Arcus.PythonMessage) -> None:
|
||||
"""Called when a g-code prefix message is received from the engine.
|
||||
|
||||
:param message: The protobuf message containing the g-code prefix,
|
||||
encoded as UTF-8.
|
||||
"""
|
||||
|
||||
try:
|
||||
self._scene.gcode_dict[self._start_slice_job_build_plate].insert(0, message.data.decode("utf-8", "replace")) #type: ignore #Because we generate this attribute dynamically.
|
||||
except KeyError: # Can occur if the g-code has been cleared while a slice message is still arriving from the other end.
|
||||
pass # Throw the message away.
|
||||
|
||||
## Creates a new socket connection.
|
||||
def _createSocket(self, protocol_file: str = None) -> None:
|
||||
"""Creates a new socket connection."""
|
||||
|
||||
if not protocol_file:
|
||||
plugin_path = PluginRegistry.getInstance().getPluginPath(self.getPluginId())
|
||||
if not plugin_path:
|
||||
|
@ -728,10 +765,12 @@ class CuraEngineBackend(QObject, Backend):
|
|||
super()._createSocket(protocol_file)
|
||||
self._engine_is_fresh = True
|
||||
|
||||
## Called when anything has changed to the stuff that needs to be sliced.
|
||||
#
|
||||
# This indicates that we should probably re-slice soon.
|
||||
def _onChanged(self, *args: Any, **kwargs: Any) -> None:
|
||||
"""Called when anything has changed to the stuff that needs to be sliced.
|
||||
|
||||
This indicates that we should probably re-slice soon.
|
||||
"""
|
||||
|
||||
self.needsSlicing()
|
||||
if self._use_timer:
|
||||
# if the error check is scheduled, wait for the error check finish signal to trigger auto-slice,
|
||||
|
@ -745,11 +784,13 @@ class CuraEngineBackend(QObject, Backend):
|
|||
else:
|
||||
self._change_timer.start()
|
||||
|
||||
## Called when a print time message is received from the engine.
|
||||
#
|
||||
# \param message The protobuf message containing the print time per feature and
|
||||
# material amount per extruder
|
||||
def _onPrintTimeMaterialEstimates(self, message: Arcus.PythonMessage) -> None:
|
||||
"""Called when a print time message is received from the engine.
|
||||
|
||||
:param message: The protobuf message containing the print time per feature and
|
||||
material amount per extruder
|
||||
"""
|
||||
|
||||
material_amounts = []
|
||||
for index in range(message.repeatedMessageCount("materialEstimates")):
|
||||
material_amounts.append(message.getRepeatedMessage("materialEstimates", index).material_amount)
|
||||
|
@ -757,10 +798,12 @@ class CuraEngineBackend(QObject, Backend):
|
|||
times = self._parseMessagePrintTimes(message)
|
||||
self.printDurationMessage.emit(self._start_slice_job_build_plate, times, material_amounts)
|
||||
|
||||
## Called for parsing message to retrieve estimated time per feature
|
||||
#
|
||||
# \param message The protobuf message containing the print time per feature
|
||||
def _parseMessagePrintTimes(self, message: Arcus.PythonMessage) -> Dict[str, float]:
|
||||
"""Called for parsing message to retrieve estimated time per feature
|
||||
|
||||
:param message: The protobuf message containing the print time per feature
|
||||
"""
|
||||
|
||||
result = {
|
||||
"inset_0": message.time_inset_0,
|
||||
"inset_x": message.time_inset_x,
|
||||
|
@ -777,19 +820,22 @@ class CuraEngineBackend(QObject, Backend):
|
|||
}
|
||||
return result
|
||||
|
||||
## Called when the back-end connects to the front-end.
|
||||
def _onBackendConnected(self) -> None:
|
||||
"""Called when the back-end connects to the front-end."""
|
||||
|
||||
if self._restart:
|
||||
self._restart = False
|
||||
self._onChanged()
|
||||
|
||||
## Called when the user starts using some tool.
|
||||
#
|
||||
# When the user starts using a tool, we should pause slicing to prevent
|
||||
# continuously slicing while the user is dragging some tool handle.
|
||||
#
|
||||
# \param tool The tool that the user is using.
|
||||
def _onToolOperationStarted(self, tool: Tool) -> None:
|
||||
"""Called when the user starts using some tool.
|
||||
|
||||
When the user starts using a tool, we should pause slicing to prevent
|
||||
continuously slicing while the user is dragging some tool handle.
|
||||
|
||||
:param tool: The tool that the user is using.
|
||||
"""
|
||||
|
||||
self._tool_active = True # Do not react on scene change
|
||||
self.disableTimer()
|
||||
# Restart engine as soon as possible, we know we want to slice afterwards
|
||||
|
@ -797,12 +843,14 @@ class CuraEngineBackend(QObject, Backend):
|
|||
self._terminate()
|
||||
self._createSocket()
|
||||
|
||||
## Called when the user stops using some tool.
|
||||
#
|
||||
# This indicates that we can safely start slicing again.
|
||||
#
|
||||
# \param tool The tool that the user was using.
|
||||
def _onToolOperationStopped(self, tool: Tool) -> None:
|
||||
"""Called when the user stops using some tool.
|
||||
|
||||
This indicates that we can safely start slicing again.
|
||||
|
||||
:param tool: The tool that the user was using.
|
||||
"""
|
||||
|
||||
self._tool_active = False # React on scene change again
|
||||
self.determineAutoSlicing() # Switch timer on if appropriate
|
||||
# Process all the postponed scene changes
|
||||
|
@ -816,8 +864,9 @@ class CuraEngineBackend(QObject, Backend):
|
|||
self._process_layers_job.finished.connect(self._onProcessLayersFinished)
|
||||
self._process_layers_job.start()
|
||||
|
||||
## Called when the user changes the active view mode.
|
||||
def _onActiveViewChanged(self) -> None:
|
||||
"""Called when the user changes the active view mode."""
|
||||
|
||||
view = self._application.getController().getActiveView()
|
||||
if view:
|
||||
active_build_plate = self._application.getMultiBuildPlateModel().activeBuildPlate
|
||||
|
@ -835,17 +884,20 @@ class CuraEngineBackend(QObject, Backend):
|
|||
else:
|
||||
self._layer_view_active = False
|
||||
|
||||
## Called when the back-end self-terminates.
|
||||
#
|
||||
# We should reset our state and start listening for new connections.
|
||||
def _onBackendQuit(self) -> None:
|
||||
"""Called when the back-end self-terminates.
|
||||
|
||||
We should reset our state and start listening for new connections.
|
||||
"""
|
||||
|
||||
if not self._restart:
|
||||
if self._process: # type: ignore
|
||||
Logger.log("d", "Backend quit with return code %s. Resetting process and socket.", self._process.wait()) # type: ignore
|
||||
self._process = None # type: ignore
|
||||
|
||||
## Called when the global container stack changes
|
||||
def _onGlobalStackChanged(self) -> None:
|
||||
"""Called when the global container stack changes"""
|
||||
|
||||
if self._global_container_stack:
|
||||
self._global_container_stack.propertyChanged.disconnect(self._onSettingChanged)
|
||||
self._global_container_stack.containersChanged.disconnect(self._onChanged)
|
||||
|
@ -874,15 +926,18 @@ class CuraEngineBackend(QObject, Backend):
|
|||
Logger.log("d", "See if there is more to slice(2)...")
|
||||
self._invokeSlice()
|
||||
|
||||
## Connect slice function to timer.
|
||||
def enableTimer(self) -> None:
|
||||
"""Connect slice function to timer."""
|
||||
|
||||
if not self._use_timer:
|
||||
self._change_timer.timeout.connect(self.slice)
|
||||
self._use_timer = True
|
||||
|
||||
## Disconnect slice function from timer.
|
||||
# This means that slicing will not be triggered automatically
|
||||
def disableTimer(self) -> None:
|
||||
"""Disconnect slice function from timer.
|
||||
|
||||
This means that slicing will not be triggered automatically
|
||||
"""
|
||||
if self._use_timer:
|
||||
self._use_timer = False
|
||||
self._change_timer.timeout.disconnect(self.slice)
|
||||
|
@ -894,8 +949,9 @@ class CuraEngineBackend(QObject, Backend):
|
|||
if auto_slice:
|
||||
self._change_timer.start()
|
||||
|
||||
## Tickle the backend so in case of auto slicing, it starts the timer.
|
||||
def tickle(self) -> None:
|
||||
"""Tickle the backend so in case of auto slicing, it starts the timer."""
|
||||
|
||||
if self._use_timer:
|
||||
self._change_timer.start()
|
||||
|
||||
|
|
|
@ -28,10 +28,12 @@ from cura.Machines.Models.ExtrudersModel import ExtrudersModel
|
|||
catalog = i18nCatalog("cura")
|
||||
|
||||
|
||||
## Return a 4-tuple with floats 0-1 representing the html color code
|
||||
#
|
||||
# \param color_code html color code, i.e. "#FF0000" -> red
|
||||
def colorCodeToRGBA(color_code):
|
||||
"""Return a 4-tuple with floats 0-1 representing the html color code
|
||||
|
||||
:param color_code: html color code, i.e. "#FF0000" -> red
|
||||
"""
|
||||
|
||||
if color_code is None:
|
||||
Logger.log("w", "Unable to convert color code, returning default")
|
||||
return [0, 0, 0, 1]
|
||||
|
@ -51,13 +53,15 @@ class ProcessSlicedLayersJob(Job):
|
|||
self._abort_requested = False
|
||||
self._build_plate_number = None
|
||||
|
||||
## Aborts the processing of layers.
|
||||
#
|
||||
# This abort is made on a best-effort basis, meaning that the actual
|
||||
# job thread will check once in a while to see whether an abort is
|
||||
# requested and then stop processing by itself. There is no guarantee
|
||||
# that the abort will stop the job any time soon or even at all.
|
||||
def abort(self):
|
||||
"""Aborts the processing of layers.
|
||||
|
||||
This abort is made on a best-effort basis, meaning that the actual
|
||||
job thread will check once in a while to see whether an abort is
|
||||
requested and then stop processing by itself. There is no guarantee
|
||||
that the abort will stop the job any time soon or even at all.
|
||||
"""
|
||||
|
||||
self._abort_requested = True
|
||||
|
||||
def setBuildPlate(self, new_value):
|
||||
|
|
|
@ -40,8 +40,9 @@ class StartJobResult(IntEnum):
|
|||
ObjectsWithDisabledExtruder = 8
|
||||
|
||||
|
||||
## Formatter class that handles token expansion in start/end gcode
|
||||
class GcodeStartEndFormatter(Formatter):
|
||||
"""Formatter class that handles token expansion in start/end gcode"""
|
||||
|
||||
def __init__(self, default_extruder_nr: int = -1) -> None:
|
||||
super().__init__()
|
||||
self._default_extruder_nr = default_extruder_nr
|
||||
|
@ -82,8 +83,9 @@ class GcodeStartEndFormatter(Formatter):
|
|||
return value
|
||||
|
||||
|
||||
## Job class that builds up the message of scene data to send to CuraEngine.
|
||||
class StartSliceJob(Job):
|
||||
"""Job class that builds up the message of scene data to send to CuraEngine."""
|
||||
|
||||
def __init__(self, slice_message: Arcus.PythonMessage) -> None:
|
||||
super().__init__()
|
||||
|
||||
|
@ -100,9 +102,11 @@ class StartSliceJob(Job):
|
|||
def setBuildPlate(self, build_plate_number: int) -> None:
|
||||
self._build_plate_number = build_plate_number
|
||||
|
||||
## Check if a stack has any errors.
|
||||
## returns true if it has errors, false otherwise.
|
||||
def _checkStackForErrors(self, stack: ContainerStack) -> bool:
|
||||
"""Check if a stack has any errors."""
|
||||
|
||||
"""returns true if it has errors, false otherwise."""
|
||||
|
||||
if stack is None:
|
||||
return False
|
||||
|
||||
|
@ -119,8 +123,9 @@ class StartSliceJob(Job):
|
|||
Job.yieldThread()
|
||||
return False
|
||||
|
||||
## Runs the job that initiates the slicing.
|
||||
def run(self) -> None:
|
||||
"""Runs the job that initiates the slicing."""
|
||||
|
||||
if self._build_plate_number is None:
|
||||
self.setResult(StartJobResult.Error)
|
||||
return
|
||||
|
@ -323,14 +328,14 @@ class StartSliceJob(Job):
|
|||
def setIsCancelled(self, value: bool):
|
||||
self._is_cancelled = value
|
||||
|
||||
## Creates a dictionary of tokens to replace in g-code pieces.
|
||||
#
|
||||
# This indicates what should be replaced in the start and end g-codes.
|
||||
# \param stack The stack to get the settings from to replace the tokens
|
||||
# with.
|
||||
# \return A dictionary of replacement tokens to the values they should be
|
||||
# replaced with.
|
||||
def _buildReplacementTokens(self, stack: ContainerStack) -> Dict[str, Any]:
|
||||
"""Creates a dictionary of tokens to replace in g-code pieces.
|
||||
|
||||
This indicates what should be replaced in the start and end g-codes.
|
||||
:param stack: The stack to get the settings from to replace the tokens with.
|
||||
:return: A dictionary of replacement tokens to the values they should be replaced with.
|
||||
"""
|
||||
|
||||
result = {}
|
||||
for key in stack.getAllKeys():
|
||||
value = stack.getProperty(key, "value")
|
||||
|
@ -358,10 +363,12 @@ class StartSliceJob(Job):
|
|||
extruder_nr = extruder_stack.getProperty("extruder_nr", "value")
|
||||
self._all_extruders_settings[str(extruder_nr)] = self._buildReplacementTokens(extruder_stack)
|
||||
|
||||
## Replace setting tokens in a piece of g-code.
|
||||
# \param value A piece of g-code to replace tokens in.
|
||||
# \param default_extruder_nr Stack nr to use when no stack nr is specified, defaults to the global stack
|
||||
def _expandGcodeTokens(self, value: str, default_extruder_nr: int = -1) -> str:
|
||||
"""Replace setting tokens in a piece of g-code.
|
||||
|
||||
:param value: A piece of g-code to replace tokens in.
|
||||
:param default_extruder_nr: Stack nr to use when no stack nr is specified, defaults to the global stack
|
||||
"""
|
||||
if not self._all_extruders_settings:
|
||||
self._cacheAllExtruderSettings()
|
||||
|
||||
|
@ -377,8 +384,9 @@ class StartSliceJob(Job):
|
|||
Logger.logException("w", "Unable to do token replacement on start/end g-code")
|
||||
return str(value)
|
||||
|
||||
## Create extruder message from stack
|
||||
def _buildExtruderMessage(self, stack: ContainerStack) -> None:
|
||||
"""Create extruder message from stack"""
|
||||
|
||||
message = self._slice_message.addRepeatedMessage("extruders")
|
||||
message.id = int(stack.getMetaDataEntry("position"))
|
||||
if not self._all_extruders_settings:
|
||||
|
@ -407,11 +415,13 @@ class StartSliceJob(Job):
|
|||
setting.value = str(value).encode("utf-8")
|
||||
Job.yieldThread()
|
||||
|
||||
## Sends all global settings to the engine.
|
||||
#
|
||||
# The settings are taken from the global stack. This does not include any
|
||||
# per-extruder settings or per-object settings.
|
||||
def _buildGlobalSettingsMessage(self, stack: ContainerStack) -> None:
|
||||
"""Sends all global settings to the engine.
|
||||
|
||||
The settings are taken from the global stack. This does not include any
|
||||
per-extruder settings or per-object settings.
|
||||
"""
|
||||
|
||||
if not self._all_extruders_settings:
|
||||
self._cacheAllExtruderSettings()
|
||||
|
||||
|
@ -445,15 +455,16 @@ class StartSliceJob(Job):
|
|||
setting_message.value = str(value).encode("utf-8")
|
||||
Job.yieldThread()
|
||||
|
||||
## Sends for some settings which extruder they should fallback to if not
|
||||
# set.
|
||||
#
|
||||
# This is only set for settings that have the limit_to_extruder
|
||||
# property.
|
||||
#
|
||||
# \param stack The global stack with all settings, from which to read the
|
||||
# limit_to_extruder property.
|
||||
def _buildGlobalInheritsStackMessage(self, stack: ContainerStack) -> None:
|
||||
"""Sends for some settings which extruder they should fallback to if not set.
|
||||
|
||||
This is only set for settings that have the limit_to_extruder
|
||||
property.
|
||||
|
||||
:param stack: The global stack with all settings, from which to read the
|
||||
limit_to_extruder property.
|
||||
"""
|
||||
|
||||
for key in stack.getAllKeys():
|
||||
extruder_position = int(round(float(stack.getProperty(key, "limit_to_extruder"))))
|
||||
if extruder_position >= 0: # Set to a specific extruder.
|
||||
|
@ -462,10 +473,13 @@ class StartSliceJob(Job):
|
|||
setting_extruder.extruder = extruder_position
|
||||
Job.yieldThread()
|
||||
|
||||
## Check if a node has per object settings and ensure that they are set correctly in the message
|
||||
# \param node Node to check.
|
||||
# \param message object_lists message to put the per object settings in
|
||||
def _handlePerObjectSettings(self, node: CuraSceneNode, message: Arcus.PythonMessage):
|
||||
"""Check if a node has per object settings and ensure that they are set correctly in the message
|
||||
|
||||
:param node: Node to check.
|
||||
:param message: object_lists message to put the per object settings in
|
||||
"""
|
||||
|
||||
stack = node.callDecoration("getStack")
|
||||
|
||||
# Check if the node has a stack attached to it and the stack has any settings in the top container.
|
||||
|
@ -501,10 +515,13 @@ class StartSliceJob(Job):
|
|||
|
||||
Job.yieldThread()
|
||||
|
||||
## Recursive function to put all settings that require each other for value changes in a list
|
||||
# \param relations_set Set of keys of settings that are influenced
|
||||
# \param relations list of relation objects that need to be checked.
|
||||
def _addRelations(self, relations_set: Set[str], relations: List[SettingRelation]):
|
||||
"""Recursive function to put all settings that require each other for value changes in a list
|
||||
|
||||
:param relations_set: Set of keys of settings that are influenced
|
||||
:param relations: list of relation objects that need to be checked.
|
||||
"""
|
||||
|
||||
for relation in filter(lambda r: r.role == "value" or r.role == "limit_to_extruder", relations):
|
||||
if relation.type == RelationType.RequiresTarget:
|
||||
continue
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue