diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 6c5bc61cbe..0000000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,16 +0,0 @@ -image: registry.gitlab.com/ultimaker/cura/cura-build-environment:centos7 - -stages: - - build - -build and test linux: - stage: build - tags: - - cura - - docker - - linux - script: - - docker/build.sh - artifacts: - paths: - - build diff --git a/cura/Machines/MachineNode.py b/cura/Machines/MachineNode.py index 92f71b409b..cee71160d2 100644 --- a/cura/Machines/MachineNode.py +++ b/cura/Machines/MachineNode.py @@ -162,6 +162,7 @@ class MachineNode(ContainerNode): container_registry = ContainerRegistry.getInstance() if not self.has_variants: self.variants["empty"] = VariantNode("empty_variant", machine = self) + self.variants["empty"].materialsChanged.connect(self.materialsChanged) else: # Find all the variants for this definition ID. variants = container_registry.findInstanceContainersMetadata(type = "variant", definition = self.container_id, hardware_type = "nozzle") diff --git a/cura/Machines/VariantNode.py b/cura/Machines/VariantNode.py index c9e3ec4913..550b5881a3 100644 --- a/cura/Machines/VariantNode.py +++ b/cura/Machines/VariantNode.py @@ -167,15 +167,21 @@ class VariantNode(ContainerNode): # Search for any submaterials from that base file that are still left. materials_same_base_file = ContainerRegistry.getInstance().findContainersMetadata(base_file = base_file) if materials_same_base_file: - most_specific_submaterial = materials_same_base_file[0] + most_specific_submaterial = None for submaterial in materials_same_base_file: if submaterial["definition"] == self.machine.container_id: - if most_specific_submaterial["definition"] == "fdmprinter": + if submaterial.get("variant_name", "empty") == self.variant_name: most_specific_submaterial = submaterial - if most_specific_submaterial.get("variant_name", "empty") == "empty" and submaterial.get("variant_name", "empty") == self.variant_name: + break # most specific match possible + if submaterial.get("variant_name", "empty") == "empty": most_specific_submaterial = submaterial - self.materials[base_file] = MaterialNode(most_specific_submaterial["id"], variant = self) - self.materialsChanged.emit(self.materials[base_file]) + + if most_specific_submaterial is None: + Logger.log("w", "Material %s removed, but no suitable replacement found", base_file) + else: + Logger.log("i", "Material %s (%s) overridden by %s", base_file, self.variant_name, most_specific_submaterial.get("id")) + self.materials[base_file] = MaterialNode(most_specific_submaterial["id"], variant = self) + self.materialsChanged.emit(self.materials[base_file]) if not self.materials: # The last available material just got deleted and there is nothing with the same base file to replace it. self.materials["empty_material"] = MaterialNode("empty_material", variant = self) diff --git a/cura/UI/PrintInformation.py b/cura/UI/PrintInformation.py index abf1083836..e33ab13b69 100644 --- a/cura/UI/PrintInformation.py +++ b/cura/UI/PrintInformation.py @@ -298,9 +298,7 @@ class PrintInformation(QObject): # Only update the job name when it's not user-specified. if not self._is_user_specified_job_name: - if self._pre_sliced: - self._job_name = catalog.i18nc("@label", "Pre-sliced file {0}", base_name) - elif self._application.getInstance().getPreferences().getValue("cura/jobname_prefix"): + if self._application.getInstance().getPreferences().getValue("cura/jobname_prefix") and not self._pre_sliced: # Don't add abbreviation if it already has the exact same abbreviation. if base_name.startswith(self._abbr_machine + "_"): self._job_name = base_name diff --git a/plugins/PostProcessingPlugin/scripts/ColorMix.py b/plugins/PostProcessingPlugin/scripts/ColorMix.py new file mode 100644 index 0000000000..1152ba70da --- /dev/null +++ b/plugins/PostProcessingPlugin/scripts/ColorMix.py @@ -0,0 +1,190 @@ +# ColorMix script - 2-1 extruder color mix and blending +# This script is specific for the Geeetech A10M dual extruder but should work with other Marlin printers. +# It runs with the PostProcessingPlugin which is released under the terms of the AGPLv3 or higher. +# This script is licensed under the Creative Commons - Attribution - Share Alike (CC BY-SA) terms + +#Authors of the 2-1 ColorMix plug-in / script: +# Written by John Hryb - john.hryb.4@gmail.com + +##history / change-log: +##V1.0.0 + +## Uses - +## M163 - Set Mix Factor +## M164 - Save Mix - saves to T3 as a unique mix + +import re #To perform the search and replace. +from ..Script import Script + +class ColorMix(Script): + def __init__(self): + super().__init__() + + def getSettingDataString(self): + return """{ + "name":"ColorMix 2-1", + "key":"ColorMix 2-1", + "metadata": {}, + "version": 2, + "settings": + { + "measurement_units": + { + "label": "Units of measurement", + "description": "Input value as mm or layer number.", + "type": "enum", + "options": {"mm":"mm","layer":"Layer"}, + "default_value": "layer" + }, + "start_height": + { + "label": "Start Height", + "description": "Value to start at (mm or layer)", + "type": "float", + "default_value": 0, + "minimum_value": "0" + }, + "behavior": + { + "label": "Fixed or blend", + "description": "Select Fixed (set new mixture) or Blend mode (dynamic mix)", + "type": "enum", + "options": {"fixed_value":"Fixed","blend_value":"Blend"}, + "default_value": "fixed_value" + }, + "finish_height": + { + "label": "Finish Height", + "description": "Value to stop at (mm or layer)", + "type": "float", + "default_value": 0, + "minimum_value": "0", + "minimum_value_warning": "0.1", + "enabled": "c_behavior == 'blend_value'" + }, + "mix_start_ratio": + { + "label": "Start mix ratio", + "description": "First extruder percentage 0-100", + "type": "float", + "default_value": 100, + "minimum_value": "0", + "minimum_value_warning": "0", + "maximum_value_warning": "100" + }, + "mix_finish_ratio": + { + "label": "End mix ratio", + "description": "First extruder percentage 0-100 to finish blend", + "type": "float", + "default_value": 0, + "minimum_value": "0", + "minimum_value_warning": "0", + "maximum_value_warning": "100", + "enabled": "c_behavior == 'blend_value'" + }, + "notes": + { + "label": "Notes", + "description": "A spot to put a note", + "type": "str", + "default_value": "" + } + } + }""" + def getValue(self, line, key, default = None): #replace default getvalue due to comment-reading feature + if not key in line or (";" in line and line.find(key) > line.find(";") and + not ";ChangeAtZ" in key and not ";LAYER:" in key): + return default + subPart = line[line.find(key) + len(key):] #allows for string lengths larger than 1 + if ";ChangeAtZ" in key: + m = re.search("^[0-4]", subPart) + elif ";LAYER:" in key: + m = re.search("^[+-]?[0-9]*", subPart) + else: + #the minus at the beginning allows for negative values, e.g. for delta printers + m = re.search("^[-]?[0-9]*\.?[0-9]*", subPart) + if m == None: + return default + try: + return float(m.group(0)) + except: + return default + + def execute(self, data): + #get user variables + firstHeight = 0.0 + secondHeight = 0.0 + firstMix = 0.0 + SecondMix = 0.0 + + firstHeight = self.getSettingValueByKey("start_height") + secondHeight = self.getSettingValueByKey("finish_height") + firstMix = self.getSettingValueByKey("mix_start_ratio") + SecondMix = self.getSettingValueByKey("mix_finish_ratio") + + #locals + layer = 0 + + #get layer height + layerHeight = .2 + for active_layer in data: + lines = active_layer.split("\n") + for line in lines: + if ";Layer height: " in line: + layerHeight = self.getValue(line, ";Layer height: ", layerHeight) + break + #get layers to use + startLayer = 0 + endLayer = 0 + if self.getSettingValueByKey("measurement_units") == "mm": + if firstHeight == 0: + startLayer = 0 + else: + startLayer = firstHeight / layerHeight + if secondHeight == 0: + endLayer = 0 + else: + endLayer = secondHeight / layerHeight + else: #layer height + startLayer = firstHeight + endLayer = secondHeight + #see if one-shot + if self.getSettingValueByKey("behavior") == "fixed_value": + endLayer = startLayer + firstExtruderIncrements = 0 + else: #blend + firstExtruderIncrements = (SecondMix - firstMix) / (endLayer - startLayer) + firstExtruderValue = 0 + index = 0 + #start scanning + for active_layer in data: + modified_gcode = "" + lineIndex = 0; + lines = active_layer.split("\n") + for line in lines: + #dont leave blanks + if line != "": + modified_gcode += line + "\n" + # find current layer + if ";LAYER:" in line: + layer = self.getValue(line, ";LAYER:", layer) + if (layer >= startLayer) and (layer <= endLayer): #find layers of interest + if lines[lineIndex + 4] == "T2": #check if needing to delete old data + del lines[(lineIndex + 1):(lineIndex + 5)] + firstExtruderValue = int(((layer - startLayer) * firstExtruderIncrements) + firstMix) + if firstExtruderValue == 100: + modified_gcode += "M163 S0 P1\n" + modified_gcode += "M163 S1 P0\n" + elif firstExtruderValue == 0: + modified_gcode += "M163 S0 P0\n" + modified_gcode += "M163 S1 P1\n" + else: + modified_gcode += "M163 S0 P0.{:02d}\n".format(firstExtruderValue) + modified_gcode += "M163 S1 P0.{:02d}\n".format(100 - firstExtruderValue) + modified_gcode += "M164 S2\n" + modified_gcode += "T2\n" + lineIndex += 1 #for deleting index + data[index] = modified_gcode + index += 1 + return data diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 1c84e99d24..394342a316 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -2073,6 +2073,36 @@ "settable_per_mesh": true } } + }, + "skin_edge_support_thickness": + { + "label": "Skin Edge Support Thickness", + "description": "The thickness of the extra infill that supports skin edges.", + "unit": "mm", + "default_value": 0.8, + "minimum_value": "0", + "maximum_value": "machine_height", + "type": "float", + "value": "0", + "comment": "This was put at 0 to keep the default behaviour the same, but in the original PR the 'value' was: resolveOrValue('infill_sparse_thickness') * (4 if infill_sparse_density < 12.5 else (3 if infill_sparse_density < 25 else (2 if infill_sparse_density < 50 else 1)))", + "limit_to_extruder": "infill_extruder_nr", + "enabled": "infill_sparse_density > 0", + "settable_per_mesh": true, + "children": + { + "skin_edge_support_layers": + { + "label": "Skin Edge Support Layers", + "description": "The number of infill layers that supports skin edges.", + "default_value": 4, + "minimum_value": "0", + "type": "int", + "value": "math.ceil(round(skin_edge_support_thickness / resolveOrValue('infill_sparse_thickness'), 4))", + "limit_to_extruder": "infill_extruder_nr", + "enabled": "infill_sparse_density > 0", + "settable_per_mesh": true + } + } } } }, diff --git a/resources/setting_visibility/expert.cfg b/resources/setting_visibility/expert.cfg index 2b9ad362fc..7b24934b0d 100644 --- a/resources/setting_visibility/expert.cfg +++ b/resources/setting_visibility/expert.cfg @@ -101,6 +101,8 @@ bottom_skin_expand_distance max_skin_angle_for_expansion min_skin_width_for_expansion infill_randomize_start_location +skin_edge_support_thickness +skin_edge_support_layers [material] default_material_print_temperature