Skip to content

Commit

Permalink
Merge branch 'main' into CURA-12081_scarf-seam
Browse files Browse the repository at this point in the history
  • Loading branch information
wawanbreton authored Oct 4, 2024
2 parents 1d28f7d + 383c102 commit fe5c81a
Show file tree
Hide file tree
Showing 7,491 changed files with 52,371 additions and 7,586 deletions.
The diff you're trying to view is too large. We only load the first 3000 changed files.
2 changes: 1 addition & 1 deletion cura/CuraApplication.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ class CuraApplication(QtApplication):
# SettingVersion represents the set of settings available in the machine/extruder definitions.
# You need to make sure that this version number needs to be increased if there is any non-backwards-compatible
# changes of the settings.
SettingVersion = 23
SettingVersion = 24

Created = False

Expand Down
1 change: 1 addition & 0 deletions cura/Machines/MachineNode.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ def __init__(self, container_id: str) -> None:
self.preferred_variant_name = my_metadata.get("preferred_variant_name", "")
self.preferred_material = my_metadata.get("preferred_material", "")
self.preferred_quality_type = my_metadata.get("preferred_quality_type", "")
self.supports_abstract_color = parseBool(my_metadata.get("supports_abstract_color", "false"))

self._loadAll()

Expand Down
7 changes: 3 additions & 4 deletions cura/Machines/Models/QualityManagementModel.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,13 +127,12 @@ def renameQualityChangesGroup(self, quality_changes_group: "QualityChangesGroup"
# have no container for the global stack, because "my_profile" just got renamed to "my_new_profile". This results
# in crashes because the rest of the system assumes that all data in a QualityChangesGroup will be correct.
#
# Renaming the container for the global stack in the end seems to be ok, because the assumption is mostly based
# on the quality changes container for the global stack.
# This is why we use the "supress_signals" flag for the set name. This basically makes the change silent.
for metadata in quality_changes_group.metadata_per_extruder.values():
extruder_container = cast(InstanceContainer, container_registry.findContainers(id = metadata["id"])[0])
extruder_container.setName(new_name)
extruder_container.setName(new_name, supress_signals=True)
global_container = cast(InstanceContainer, container_registry.findContainers(id = quality_changes_group.metadata_for_global["id"])[0])
global_container.setName(new_name)
global_container.setName(new_name, supress_signals=True)

quality_changes_group.name = new_name

Expand Down
4 changes: 4 additions & 0 deletions cura/Machines/VariantNode.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ def _loadAll(self) -> None:
filtered_materials = [material for material in materials if not self.machine.isExcludedMaterialBaseFile(material["id"])]

for material in filtered_materials:
if material.get("abstract_color", False) and not self.machine.supports_abstract_color:
continue # do not show abstract color profiles if the machine does not support them
base_file = material["base_file"]
if base_file not in self.materials:
self.materials[base_file] = MaterialNode(material["id"], variant = self)
Expand Down Expand Up @@ -126,6 +128,8 @@ def _materialAdded(self, container: ContainerInterface) -> None:
return # We won't add any materials.
material_definition = container.getMetaDataEntry("definition")

if (not self.machine.supports_abstract_color) and container.getMetaDataEntry("abstract_color", False):
return
base_file = container.getMetaDataEntry("base_file")
if self.machine.isExcludedMaterialBaseFile(base_file):
return # Material is forbidden for this printer.
Expand Down
19 changes: 17 additions & 2 deletions plugins/CuraEngineBackend/CuraEngineBackend.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,8 @@ def __init__(self) -> None:
self._slicing_error_message.actionTriggered.connect(self._reportBackendError)

self._resetLastSliceTimeStats()
self._snapshot: Optional[QImage] = None
self._snapshot: Optional[QImage] = None
self._last_socket_error: Optional[Arcus.Error] = None

application.initializationFinished.connect(self.initialize)

Expand Down Expand Up @@ -569,7 +570,20 @@ def _onStartSliceCompleted(self, job: StartSliceJob) -> None:
return

# Preparation completed, send it to the backend.
self._socket.sendMessage(job.getSliceMessage())
immediate_success = self._socket.sendMessage(job.getSliceMessage())
if (not CuraApplication.getInstance().getUseExternalBackend()) and (not immediate_success):
if self._last_socket_error is not None and self._last_socket_error.getErrorCode() == Arcus.ErrorCode.MessageTooBigError:
error_txt = catalog.i18nc("@info:status", "Unable to send the model data to the engine. Please try to use a less detailed model, or reduce the number of instances.")
else:
error_txt = catalog.i18nc("@info:status", "Unable to send the model data to the engine. Please try again, or contact support.")

self._error_message = Message(error_txt,
title=catalog.i18nc("@info:title", "Unable to slice"),
message_type=Message.MessageType.WARNING)
self._error_message.show()
self.setState(BackendState.Error)
self.backendError.emit(job)
return

# Notify the user that it's now up to the backend to do its job
self.setState(BackendState.Processing)
Expand Down Expand Up @@ -691,6 +705,7 @@ def _onSocketError(self, error: Arcus.Error) -> None:
if error.getErrorCode() == Arcus.ErrorCode.Debug:
return

self._last_socket_error = error
self._terminate()
self._createSocket()

Expand Down
230 changes: 191 additions & 39 deletions plugins/PostProcessingPlugin/scripts/InsertAtLayerChange.py
Original file line number Diff line number Diff line change
@@ -1,65 +1,217 @@
# Copyright (c) 2020 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
# Created by Wayne Porter
# Re-write in April of 2024 by GregValiant (Greg Foresi)
# Changes:
# Added an 'Enable' setting
# Added support for multi-line insertions (comma delimited)
# Added insertions in a range of layers or a single insertion at a layer. Numbers are consistent with the Cura Preview (base1)
# Added frequency of Insertion (once only, every layer, every 2nd, 3rd, 5th, 10th, 25th, 50th, 100th)
# Added support for 'One at a Time' print sequence
# Rafts are allowed and accounted for but no insertions are made in raft layers

from ..Script import Script
import re
from UM.Application import Application

class InsertAtLayerChange(Script):
def __init__(self):
super().__init__()

def getSettingDataString(self):
return """{
"name": "Insert at layer change",
"name": "Insert at Layer Change",
"key": "InsertAtLayerChange",
"metadata": {},
"version": 2,
"settings":
{
"insert_location":
"enabled":
{
"label": "When to insert",
"description": "Whether to insert code before or after layer change.",
"label": "Enable this script",
"description": "You must enable the script for it to run.",
"type": "bool",
"default_value": true,
"enabled": true
},
"insert_frequency":
{
"label": "How often to insert",
"description": "Every so many layers starting with the Start Layer OR as single insertion at a specific layer. If the print sequence is 'one_at_a_time' then the insertions will be made for every model. Insertions are made at the beginning of a layer.",
"type": "enum",
"options": {"before": "Before", "after": "After"},
"default_value": "before"
"options": {
"once_only": "One insertion only",
"every_layer": "Every Layer",
"every_2nd": "Every 2nd",
"every_3rd": "Every 3rd",
"every_5th": "Every 5th",
"every_10th": "Every 10th",
"every_25th": "Every 25th",
"every_50th": "Every 50th",
"every_100th": "Every 100th"},
"default_value": "every_layer",
"enabled": "enabled"
},
"gcode_to_add":
"start_layer":
{
"label": "G-code to insert",
"description": "G-code to add before or after layer change.",
"type": "str",
"default_value": ""
"label": "Starting Layer",
"description": "The layer before which the first insertion will take place. If the Print_Sequence is 'All at Once' then use the layer numbers from the Cura Preview. Enter '1' to start at gcode LAYER:0. In 'One at a Time' mode use the layer numbers from the first model that prints AND all models will receive the same insertions. NOTE: There is never an insertion for raft layers.",
"type": "int",
"default_value": 1,
"minimum_value": 1,
"enabled": "insert_frequency != 'once_only' and enabled"
},
"skip_layers":
"end_layer":
{
"label": "Skip layers",
"description": "Number of layers to skip between insertions (0 for every layer).",
"label": "Ending Layer",
"description": "The layer before which the last insertion will take place. Enter '-1' to indicate the entire file. Use layer numbers from the Cura Preview.",
"type": "int",
"default_value": 0,
"minimum_value": 0
"default_value": -1,
"minimum_value": -1,
"enabled": "insert_frequency != 'once_only' and enabled"
},
"single_end_layer":
{
"label": "Layer # for Single Insertion.",
"description": "The layer before which the Gcode insertion will take place. Use the layer numbers from the Cura Preview.",
"type": "str",
"default_value": "",
"enabled": "insert_frequency == 'once_only' and enabled"
},
"gcode_to_add":
{
"label": "G-code to insert.",
"description": "G-code to add at start of the layer. Use a comma to delimit multi-line commands. EX: G28 X Y,M220 S100,M117 HELL0. NOTE: All inserted text will be converted to upper-case as some firmwares don't understand lower-case.",
"type": "str",
"default_value": "",
"enabled": "enabled"
}
}
}"""

def execute(self, data):
gcode_to_add = self.getSettingValueByKey("gcode_to_add") + "\n"
skip_layers = self.getSettingValueByKey("skip_layers")
count = 0
for layer in data:
# Check that a layer is being printed
lines = layer.split("\n")
for line in lines:
if ";LAYER:" in line:
index = data.index(layer)
if count == 0:
if self.getSettingValueByKey("insert_location") == "before":
layer = gcode_to_add + layer
else:
layer = layer + gcode_to_add

data[index] = layer

count = (count + 1) % (skip_layers + 1)
break
return data
# Exit if the script is not enabled
if not bool(self.getSettingValueByKey("enabled")):
return data
#Initialize variables
mycode = self.getSettingValueByKey("gcode_to_add").upper()
start_layer = int(self.getSettingValueByKey("start_layer"))
end_layer = int(self.getSettingValueByKey("end_layer"))
when_to_insert = self.getSettingValueByKey("insert_frequency")
end_list = [0]
print_sequence = Application.getInstance().getGlobalContainerStack().getProperty("print_sequence", "value")
# Get the topmost layer number and adjust the end_list
if end_layer == -1:
if print_sequence == "all_at_once":
for lnum in range(0, len(data) - 1):
if ";LAYER:" in data[lnum]:
the_top = int(data[lnum].split(";LAYER:")[1].split("\n")[0])
end_list[0] = the_top
# Get the topmost layer number for each model and append it to the end_list
if print_sequence == "one_at_a_time":
for lnum in range(0, 10):
if ";LAYER:0" in data[lnum]:
start_at = lnum + 1
break
for lnum in range(start_at, len(data)-1, 1):
if ";LAYER:" in data[lnum] and not ";LAYER:0" in data[lnum] and not ";LAYER:-" in data[lnum]:
end_list[len(end_list) - 1] = int(data[lnum].split(";LAYER:")[1].split("\n")[0])
continue
if ";LAYER:0" in data[lnum]:
end_list.append(0)
elif end_layer != -1:
if print_sequence == "all_at_once":
# Catch an error if the entered End_Layer > the top layer in the gcode
for e_num, layer in enumerate(data):
if ";LAYER:" in layer:
top_layer = int(data[e_num].split(";LAYER:")[1].split("\n")[0])
end_list[0] = end_layer - 1
if top_layer < end_layer - 1:
end_list[0] = top_layer
elif print_sequence == "one_at_a_time":
# Find the index of the first Layer:0
for lnum in range(0, 10):
if ";LAYER:0" in data[lnum]:
start_at = lnum + 1
break
# Get the top layer number for each model
for lnum in range(start_at, len(data)-1):
if ";LAYER:" in data[lnum] and not ";LAYER:0" in data[lnum] and not ";LAYER:-" in data[lnum]:
end_list[len(end_list) - 1] = int(data[lnum].split(";LAYER:")[1].split("\n")[0])
if ";LAYER:0" in data[lnum]:
end_list.append(0)
# Adjust the end list if an end layer was named
for index, num in enumerate(end_list):
if num > end_layer - 1:
end_list[index] = end_layer - 1
#If the gcode_to_enter is multi-line then replace the commas with newline characters
if mycode != "":
if "," in mycode:
mycode = re.sub(",", "\n",mycode)
gcode_to_add = mycode
#Get the insertion frequency
match when_to_insert:
case "every_layer":
freq = 1
case "every_2nd":
freq = 2
case "every_3rd":
freq = 3
case "every_5th":
freq = 5
case "every_10th":
freq = 10
case "every_25th":
freq = 25
case "every_50th":
freq = 50
case "every_100th":
freq = 100
case "once_only":
the_insert_layer = int(self.getSettingValueByKey("single_end_layer"))-1
case _:
raise ValueError(f"Unexpected insertion frequency {when_to_insert}")
#Single insertion
if when_to_insert == "once_only":
# For print sequence 'All at once'
if print_sequence == "all_at_once":
for index, layer in enumerate(data):
if ";LAYER:" + str(the_insert_layer) + "\n" in layer:
lines = layer.split("\n")
lines.insert(1,gcode_to_add)
data[index] = "\n".join(lines)
return data
# For print sequence 'One at a time'
else:
for index, layer in enumerate(data):
if ";LAYER:" + str(the_insert_layer) + "\n" in layer:
lines = layer.split("\n")
lines.insert(1,gcode_to_add)
data[index] = "\n".join(lines)
return data
# For multiple insertions
if when_to_insert != "once_only":
# Search from the line after the first Layer:0 so we know when a model ends if in One at a Time mode.
first_0 = True
next_layer = start_layer - 1
end_layer = end_list.pop(0)
for index, layer in enumerate(data):
lines = layer.split("\n")
for l_index, line in enumerate(lines):
if ";LAYER:" in line:
layer_number = int(line.split(":")[1])
if layer_number == next_layer and layer_number <= end_layer:
lines.insert(l_index + 1,gcode_to_add)
data[index] = "\n".join(lines)
next_layer += freq
# Reset the next_layer for one-at-a-time
if next_layer > int(end_layer):
next_layer = start_layer - 1
# Index to the next end_layer when a Layer:0 is encountered
try:
if not first_0 and layer_number == 0:
end_layer = end_list.pop(0)
except:
pass
# Beyond the initial Layer:0 futher Layer:0's indicate the top layer of a model.
if layer_number == 0:
first_0 = False
break
return data
Loading

0 comments on commit fe5c81a

Please sign in to comment.