From 1f9e0e2dee75bcbc12fbe1b54c61de10e5a5f65c Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Tue, 28 Nov 2023 15:15:39 +0100 Subject: [PATCH 01/73] Add url protocol support for msi, nsis, dmg and pkg installers CURA-11288 --- UltiMaker-Cura.spec.jinja | 4 +++ packaging/NSIS/Ultimaker-Cura.nsi.jinja | 15 +++++++++++ packaging/msi/UltiMaker-Cura.wxs.jinja | 36 +++++++++++++++++++++++++ 3 files changed, 55 insertions(+) diff --git a/UltiMaker-Cura.spec.jinja b/UltiMaker-Cura.spec.jinja index 3d540d3b8f..cd939cf736 100644 --- a/UltiMaker-Cura.spec.jinja +++ b/UltiMaker-Cura.spec.jinja @@ -266,6 +266,10 @@ app = UMBUNDLE( 'CFBundlePackageType': 'APPL', 'CFBundleVersionString': {{ version }}, 'CFBundleShortVersionString': {{ short_version }}, + 'CFBundleURLTypes': [{ + 'CFBundleURLName': '{{ display_name }}', + 'CFBundleURLSchemes': ['cura', 'slicer'], + }], 'CFBundleDocumentTypes': [{ 'CFBundleTypeRole': 'Viewer', 'CFBundleTypeExtensions': ['*'], diff --git a/packaging/NSIS/Ultimaker-Cura.nsi.jinja b/packaging/NSIS/Ultimaker-Cura.nsi.jinja index 9996b24773..228dba4fe4 100644 --- a/packaging/NSIS/Ultimaker-Cura.nsi.jinja +++ b/packaging/NSIS/Ultimaker-Cura.nsi.jinja @@ -192,3 +192,18 @@ DeleteRegKey ${REG_ROOT} "${UNINSTALL_PATH}" SectionEnd ###################################################################### + +Section UrlProtocol + WriteRegStr HKCR "cura" "" "URL:cura" + WriteRegStr HKCR "cura" "URL Protocol" "" + WriteRegStr HKCR "cura\DefaultIcon" "" "$INSTDIR\${MAIN_APP_EXE},1" + WriteRegStr HKCR "cura\shell" "" "open" + WriteRegStr HKCR "cura\shell\open\command" "" '"$INSTDIR\${MAIN_APP_EXE}" "%1"' + + WriteRegStr HKCR "slicer" "" "URL:slicer" + WriteRegStr HKCR "slicer" "URL Protocol" "" + WriteRegStr HKCR "slicer\DefaultIcon" "" "$INSTDIR\${MAIN_APP_EXE},1" + WriteRegStr HKCR "slicer\shell" "" "open" + WriteRegStr HKCR "slicer\shell\open\command" "" '"$INSTDIR\${MAIN_APP_EXE}" "%1"' + +SectionEnd \ No newline at end of file diff --git a/packaging/msi/UltiMaker-Cura.wxs.jinja b/packaging/msi/UltiMaker-Cura.wxs.jinja index a183a97d5f..5ce8cd0a08 100644 --- a/packaging/msi/UltiMaker-Cura.wxs.jinja +++ b/packaging/msi/UltiMaker-Cura.wxs.jinja @@ -33,6 +33,21 @@ /> + + + + + {% if "Enterprise" in app_name %} @@ -144,11 +159,32 @@ + + + + + + + + + + + + + + + + + + + + + From d53b2d94abc0219995757c4c2e922226cefd0054 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Thu, 30 Nov 2023 11:51:35 +0100 Subject: [PATCH 02/73] Add directory for wix components CURA-11288 --- packaging/msi/UltiMaker-Cura.wxs.jinja | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packaging/msi/UltiMaker-Cura.wxs.jinja b/packaging/msi/UltiMaker-Cura.wxs.jinja index 5ce8cd0a08..de441443f4 100644 --- a/packaging/msi/UltiMaker-Cura.wxs.jinja +++ b/packaging/msi/UltiMaker-Cura.wxs.jinja @@ -160,7 +160,7 @@ - + @@ -169,7 +169,7 @@ - + From d1f4aa6cd3f9e97d9b5f5eaf220162d610923cfb Mon Sep 17 00:00:00 2001 From: Paul Kuiper <46715907+pkuiper-ultimaker@users.noreply.github.com> Date: Thu, 30 Nov 2023 13:03:22 +0100 Subject: [PATCH 03/73] PP-397 Adjust z shrinkage factor for the PET-CF annealing intent from 2.0 to 0.9% --- .../ultimaker_s3/um_s3_cc0.4_petcf_0.15mm_annealing.inst.cfg | 2 +- .../ultimaker_s3/um_s3_cc0.4_petcf_0.2mm_annealing.inst.cfg | 2 +- .../ultimaker_s3/um_s3_cc0.6_petcf_0.15mm_annealing.inst.cfg | 2 +- .../ultimaker_s3/um_s3_cc0.6_petcf_0.2mm_annealing.inst.cfg | 2 +- .../ultimaker_s5/um_s5_cc0.4_petcf_0.15mm_annealing.inst.cfg | 2 +- .../ultimaker_s5/um_s5_cc0.4_petcf_0.2mm_annealing.inst.cfg | 2 +- .../ultimaker_s5/um_s5_cc0.6_petcf_0.15mm_annealing.inst.cfg | 2 +- .../ultimaker_s5/um_s5_cc0.6_petcf_0.2mm_annealing.inst.cfg | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/resources/intent/ultimaker_s3/um_s3_cc0.4_petcf_0.15mm_annealing.inst.cfg b/resources/intent/ultimaker_s3/um_s3_cc0.4_petcf_0.15mm_annealing.inst.cfg index e042d43090..0c1e598e6c 100644 --- a/resources/intent/ultimaker_s3/um_s3_cc0.4_petcf_0.15mm_annealing.inst.cfg +++ b/resources/intent/ultimaker_s3/um_s3_cc0.4_petcf_0.15mm_annealing.inst.cfg @@ -15,7 +15,7 @@ variant = CC 0.4 infill_sparse_density = 100 jerk_print = 30 material_shrinkage_percentage_xy = 100.3 -material_shrinkage_percentage_z = 102.0 +material_shrinkage_percentage_z = 100.9 speed_infill = =speed_print speed_layer_0 = 20 speed_print = 25 diff --git a/resources/intent/ultimaker_s3/um_s3_cc0.4_petcf_0.2mm_annealing.inst.cfg b/resources/intent/ultimaker_s3/um_s3_cc0.4_petcf_0.2mm_annealing.inst.cfg index 8d8ec0f3fd..7961bb5ca0 100644 --- a/resources/intent/ultimaker_s3/um_s3_cc0.4_petcf_0.2mm_annealing.inst.cfg +++ b/resources/intent/ultimaker_s3/um_s3_cc0.4_petcf_0.2mm_annealing.inst.cfg @@ -15,7 +15,7 @@ variant = CC 0.4 infill_sparse_density = 100 jerk_print = 30 material_shrinkage_percentage_xy = 100.3 -material_shrinkage_percentage_z = 102.0 +material_shrinkage_percentage_z = 100.9 speed_infill = =speed_print speed_layer_0 = 20 speed_print = 20 diff --git a/resources/intent/ultimaker_s3/um_s3_cc0.6_petcf_0.15mm_annealing.inst.cfg b/resources/intent/ultimaker_s3/um_s3_cc0.6_petcf_0.15mm_annealing.inst.cfg index 90f8fb6c16..90401c220c 100644 --- a/resources/intent/ultimaker_s3/um_s3_cc0.6_petcf_0.15mm_annealing.inst.cfg +++ b/resources/intent/ultimaker_s3/um_s3_cc0.6_petcf_0.15mm_annealing.inst.cfg @@ -15,7 +15,7 @@ variant = CC 0.6 infill_sparse_density = 100 jerk_print = 30 material_shrinkage_percentage_xy = 100.3 -material_shrinkage_percentage_z = 102.0 +material_shrinkage_percentage_z = 100.9 speed_infill = =speed_print speed_layer_0 = 20 speed_print = 25 diff --git a/resources/intent/ultimaker_s3/um_s3_cc0.6_petcf_0.2mm_annealing.inst.cfg b/resources/intent/ultimaker_s3/um_s3_cc0.6_petcf_0.2mm_annealing.inst.cfg index 392f21098a..3b05f8fd30 100644 --- a/resources/intent/ultimaker_s3/um_s3_cc0.6_petcf_0.2mm_annealing.inst.cfg +++ b/resources/intent/ultimaker_s3/um_s3_cc0.6_petcf_0.2mm_annealing.inst.cfg @@ -15,7 +15,7 @@ variant = CC 0.6 infill_sparse_density = 100 jerk_print = 30 material_shrinkage_percentage_xy = 100.3 -material_shrinkage_percentage_z = 102.0 +material_shrinkage_percentage_z = 100.9 speed_infill = =speed_print speed_layer_0 = 20 speed_print = 25 diff --git a/resources/intent/ultimaker_s5/um_s5_cc0.4_petcf_0.15mm_annealing.inst.cfg b/resources/intent/ultimaker_s5/um_s5_cc0.4_petcf_0.15mm_annealing.inst.cfg index 923467092e..e3da6ecedb 100644 --- a/resources/intent/ultimaker_s5/um_s5_cc0.4_petcf_0.15mm_annealing.inst.cfg +++ b/resources/intent/ultimaker_s5/um_s5_cc0.4_petcf_0.15mm_annealing.inst.cfg @@ -15,7 +15,7 @@ variant = CC 0.4 infill_sparse_density = 100 jerk_print = 30 material_shrinkage_percentage_xy = 100.3 -material_shrinkage_percentage_z = 102.0 +material_shrinkage_percentage_z = 100.9 speed_infill = =speed_print speed_layer_0 = 20 speed_print = 25 diff --git a/resources/intent/ultimaker_s5/um_s5_cc0.4_petcf_0.2mm_annealing.inst.cfg b/resources/intent/ultimaker_s5/um_s5_cc0.4_petcf_0.2mm_annealing.inst.cfg index 8a09c840a1..5141dba947 100644 --- a/resources/intent/ultimaker_s5/um_s5_cc0.4_petcf_0.2mm_annealing.inst.cfg +++ b/resources/intent/ultimaker_s5/um_s5_cc0.4_petcf_0.2mm_annealing.inst.cfg @@ -15,7 +15,7 @@ variant = CC 0.4 infill_sparse_density = 100 jerk_print = 30 material_shrinkage_percentage_xy = 100.3 -material_shrinkage_percentage_z = 102.0 +material_shrinkage_percentage_z = 100.9 speed_infill = =speed_print speed_layer_0 = 20 speed_print = 20 diff --git a/resources/intent/ultimaker_s5/um_s5_cc0.6_petcf_0.15mm_annealing.inst.cfg b/resources/intent/ultimaker_s5/um_s5_cc0.6_petcf_0.15mm_annealing.inst.cfg index 069c039879..6ce13e175f 100644 --- a/resources/intent/ultimaker_s5/um_s5_cc0.6_petcf_0.15mm_annealing.inst.cfg +++ b/resources/intent/ultimaker_s5/um_s5_cc0.6_petcf_0.15mm_annealing.inst.cfg @@ -15,7 +15,7 @@ variant = CC 0.6 infill_sparse_density = 100 jerk_print = 30 material_shrinkage_percentage_xy = 100.3 -material_shrinkage_percentage_z = 102.0 +material_shrinkage_percentage_z = 100.9 speed_infill = =speed_print speed_layer_0 = 20 speed_print = 25 diff --git a/resources/intent/ultimaker_s5/um_s5_cc0.6_petcf_0.2mm_annealing.inst.cfg b/resources/intent/ultimaker_s5/um_s5_cc0.6_petcf_0.2mm_annealing.inst.cfg index 55faf12587..ceea80d7fd 100644 --- a/resources/intent/ultimaker_s5/um_s5_cc0.6_petcf_0.2mm_annealing.inst.cfg +++ b/resources/intent/ultimaker_s5/um_s5_cc0.6_petcf_0.2mm_annealing.inst.cfg @@ -15,7 +15,7 @@ variant = CC 0.6 infill_sparse_density = 100 jerk_print = 30 material_shrinkage_percentage_xy = 100.3 -material_shrinkage_percentage_z = 102.0 +material_shrinkage_percentage_z = 100.9 speed_infill = =speed_print speed_layer_0 = 20 speed_print = 25 From 2b5f8b3a7c4a77e7eb99fc974996efcd4b77ace0 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Thu, 30 Nov 2023 13:23:37 +0100 Subject: [PATCH 04/73] Remove deprecated `createAndRemoveOnUninstall` action from wix installer CURA-11288 --- packaging/msi/UltiMaker-Cura.wxs.jinja | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packaging/msi/UltiMaker-Cura.wxs.jinja b/packaging/msi/UltiMaker-Cura.wxs.jinja index de441443f4..07a2c7d8c9 100644 --- a/packaging/msi/UltiMaker-Cura.wxs.jinja +++ b/packaging/msi/UltiMaker-Cura.wxs.jinja @@ -161,7 +161,7 @@ - + @@ -170,7 +170,7 @@ - + From 87caa0307a80040a74d68a2060b9f34853e09115 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Thu, 30 Nov 2023 13:28:33 +0100 Subject: [PATCH 05/73] Display message on open file event CURA-11288 --- cura/CuraApplication.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index c6c44cf8f5..0ac7118776 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -1154,6 +1154,15 @@ class CuraApplication(QtApplication): """Handle Qt events""" if event.type() == QEvent.Type.FileOpen: + + result_message = Message( + f"file: {str(event.file())}, url: {str(event.url())}", + lifetime=0, + title="OPENING FILE", + message_type=Message.MessageType.NEUTRAL, + ) + result_message.show() + if self._plugins_loaded: self._openFile(event.file()) else: From ad871c627ed5a4de7e93613f83e7439d8030818c Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Thu, 30 Nov 2023 13:42:48 +0100 Subject: [PATCH 06/73] Don't open file on open file event CURA-11288 --- cura/CuraApplication.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 0ac7118776..da1594c37b 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -1163,10 +1163,10 @@ class CuraApplication(QtApplication): ) result_message.show() - if self._plugins_loaded: - self._openFile(event.file()) - else: - self._open_file_queue.append(event.file()) + # if self._plugins_loaded: + # self._openFile(event.file()) + # else: + # self._open_file_queue.append(event.file()) if int(event.type()) == 20: # 'QEvent.Type.Quit' enum isn't there, even though it should be according to docs. # Once we're at this point, everything should have been flushed already (past OnExitCallbackManager). From 66ad006bc528392bd7246a29cfec4896fb31105d Mon Sep 17 00:00:00 2001 From: Paul Kuiper <46715907+pkuiper-ultimaker@users.noreply.github.com> Date: Thu, 30 Nov 2023 14:15:00 +0100 Subject: [PATCH 07/73] Reduced line width of the middle raft layer from 1.2 to 0.4 Increase speed from 27.5mm/s to 90mm/s. --- resources/definitions/ultimaker_method_base.def.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/definitions/ultimaker_method_base.def.json b/resources/definitions/ultimaker_method_base.def.json index 8e9034c954..6ac68ef2de 100644 --- a/resources/definitions/ultimaker_method_base.def.json +++ b/resources/definitions/ultimaker_method_base.def.json @@ -357,7 +357,8 @@ "raft_base_thickness": { "value": 0.8 }, "raft_interface_extruder_nr": { "value": "raft_surface_extruder_nr" }, "raft_interface_layers": { "value": 2 }, - "raft_interface_line_width": { "value": 1.2 }, + "raft_interface_line_width": { "value": "line_width" }, + "raft_interface_speed": { "value": 90 }, "raft_interface_thickness": { "value": 0.3 }, "raft_margin": { "value": 3 }, "raft_surface_extruder_nr": { "value": "int(anyExtruderWithMaterial('material_is_support_material')) if support_enable and extruderValue(support_extruder_nr,'material_is_support_material') else raft_base_extruder_nr" }, From a442228f38d758870f7753870f03438e9fd6986b Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Thu, 30 Nov 2023 22:45:18 +0100 Subject: [PATCH 08/73] Open file on url scheme CURA-11289 --- cura/CuraApplication.py | 73 ++++++++++++++++++++++++++++++++--------- 1 file changed, 57 insertions(+), 16 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index da1594c37b..e7289a225f 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -8,9 +8,11 @@ import time import platform from pathlib import Path from typing import cast, TYPE_CHECKING, Optional, Callable, List, Any, Dict +import re +import requests import numpy -from PyQt6.QtCore import QObject, QTimer, QUrl, pyqtSignal, pyqtProperty, QEvent, pyqtEnum, QCoreApplication +from PyQt6.QtCore import QObject, QTimer, QUrl, QUrlQuery, pyqtSignal, pyqtProperty, QEvent, pyqtEnum, QCoreApplication from PyQt6.QtGui import QColor, QIcon from PyQt6.QtQml import qmlRegisterUncreatableType, qmlRegisterUncreatableMetaObject, qmlRegisterSingletonType, qmlRegisterType from PyQt6.QtWidgets import QMessageBox @@ -249,7 +251,7 @@ class CuraApplication(QtApplication): self._additional_components = {} # Components to add to certain areas in the interface self._open_file_queue = [] # A list of files to open (after the application has started) - + self._open_url_queue = [] # A list of urls to open (after the application has started) self._update_platform_activity_timer = None self._sidebar_custom_menu_items = [] # type: list # Keeps list of custom menu items for the side bar @@ -946,6 +948,8 @@ class CuraApplication(QtApplication): self.callLater(self._openFile, file_name) for file_name in self._open_file_queue: # Open all the files that were queued up while plug-ins were loading. self.callLater(self._openFile, file_name) + for url in self._open_url_queue: + self.callLater(self._openUrl, url) initializationFinished = pyqtSignal() showAddPrintersUncancellableDialog = pyqtSignal() # Used to show the add printers dialog with a greyed background @@ -1154,19 +1158,16 @@ class CuraApplication(QtApplication): """Handle Qt events""" if event.type() == QEvent.Type.FileOpen: - - result_message = Message( - f"file: {str(event.file())}, url: {str(event.url())}", - lifetime=0, - title="OPENING FILE", - message_type=Message.MessageType.NEUTRAL, - ) - result_message.show() - - # if self._plugins_loaded: - # self._openFile(event.file()) - # else: - # self._open_file_queue.append(event.file()) + if self._plugins_loaded: + if event.file(): + self._openFile(event.file()) + if event.url(): + self._openUrl(event.url()) + else: + if event.file(): + self._open_file_queue.append(event.file()) + if event.url(): + self._open_url_queue.append(event.url()) if int(event.type()) == 20: # 'QEvent.Type.Quit' enum isn't there, even though it should be according to docs. # Once we're at this point, everything should have been flushed already (past OnExitCallbackManager). @@ -1550,7 +1551,7 @@ class CuraApplication(QtApplication): if not nodes: return - objects_in_filename = {} # type: Dict[str, List[CuraSceneNode]] + objects_in_filename: Dict[str, List[CuraSceneNode]] = {} for node in nodes: mesh_data = node.getMeshData() if mesh_data: @@ -1791,6 +1792,46 @@ class CuraApplication(QtApplication): def _openFile(self, filename): self.readLocalFile(QUrl.fromLocalFile(filename)) + def _openUrl(self, url: QUrl) -> None: + supported_schemes = ["cura", "slicer"] + if url.scheme() not in supported_schemes: + # only handle cura:// and slicer:// urls schemes + return + + match url.host() + url.path(): + case "open": + query = QUrlQuery(url.query()) + model_url = QUrl(query.queryItemValue("file", options=QUrl.ComponentFormattingOption.FullyDecoded)) + response = requests.get(model_url.url()) + if response.status_code is not 200: + Logger.log("e", "Could not download file from {0}".format(model_url.url())) + return + + content_disposition = response.headers.get('Content-Disposition') + if content_disposition is None: + Logger.log("w", + "Could not find Content-Disposition header in response from {0}".format(model_url.url())) + # Use the last part of the url as the filename, and assume it is an STL file + filename = model_url.path().split("/")[-1] + ".stl" + else: + # content_disposition is in the following format + # ``` + # content_disposition attachment; "filename=[FILENAME]" + # ``` + # Use a regex to extract the filename + # content_disposition = response.headers.get('Content-Disposition') + content_disposition_match = re.match(r'attachment; filename="(?P.*)"', + content_disposition) + assert content_disposition_match is not None + filename = content_disposition_match.group("filename") + + tmp = tempfile.NamedTemporaryFile(suffix=filename, delete=False) + with open(tmp.name, "wb") as f: + f.write(response.content) + self.readLocalFile(QUrl.fromLocalFile(tmp.name), add_to_recent_files=False) + case path: + Logger.log("w", "Unsupported url scheme path: {0}".format(path)) + def _addProfileReader(self, profile_reader): # TODO: Add the profile reader to the list of plug-ins that can be used when importing profiles. pass From cf6874c98481bd899a4a47c9af05af1570688a34 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Fri, 1 Dec 2023 10:53:30 +0100 Subject: [PATCH 09/73] Use the `HttpRequestManager` to avoid blocking the main thread CURA-11289 --- cura/CuraApplication.py | 65 ++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index e7289a225f..079a27b6ce 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -2,17 +2,18 @@ # Cura is released under the terms of the LGPLv3 or higher. import enum import os +import re import sys import tempfile import time import platform from pathlib import Path from typing import cast, TYPE_CHECKING, Optional, Callable, List, Any, Dict -import re import requests import numpy -from PyQt6.QtCore import QObject, QTimer, QUrl, QUrlQuery, pyqtSignal, pyqtProperty, QEvent, pyqtEnum, QCoreApplication +from PyQt6.QtCore import QObject, QTimer, QUrl, QUrlQuery, pyqtSignal, pyqtProperty, QEvent, pyqtEnum, QCoreApplication, \ + QByteArray from PyQt6.QtGui import QColor, QIcon from PyQt6.QtQml import qmlRegisterUncreatableType, qmlRegisterUncreatableMetaObject, qmlRegisterSingletonType, qmlRegisterType from PyQt6.QtWidgets import QMessageBox @@ -1802,33 +1803,43 @@ class CuraApplication(QtApplication): case "open": query = QUrlQuery(url.query()) model_url = QUrl(query.queryItemValue("file", options=QUrl.ComponentFormattingOption.FullyDecoded)) - response = requests.get(model_url.url()) - if response.status_code is not 200: - Logger.log("e", "Could not download file from {0}".format(model_url.url())) + + def on_finish(response): + content_disposition_header_key = QByteArray("content-disposition".encode()) + + if not response.hasRawHeader(content_disposition_header_key): + Logger.log("w", "Could not find Content-Disposition header in response from {0}".format( + model_url.url())) + # Use the last part of the url as the filename, and assume it is an STL file + filename = model_url.path().split("/")[-1] + ".stl" + else: + # content_disposition is in the format + # ``` + # content_disposition attachment; "filename=[FILENAME]" + # ``` + # Use a regex to extract the filename + content_disposition = str(response.rawHeader(content_disposition_header_key).data(), + encoding='utf-8') + content_disposition_match = re.match(r'attachment; filename="(?P.*)"', + content_disposition) + assert content_disposition_match is not None + filename = content_disposition_match.group("filename") + + tmp = tempfile.NamedTemporaryFile(suffix=filename, delete=False) + with open(tmp.name, "wb") as f: + f.write(response.readAll()) + + self.readLocalFile(QUrl.fromLocalFile(tmp.name), add_to_recent_files=False) + + def on_error(): + Logger.log("w", "Could not download file from {0}".format(model_url.url())) return - content_disposition = response.headers.get('Content-Disposition') - if content_disposition is None: - Logger.log("w", - "Could not find Content-Disposition header in response from {0}".format(model_url.url())) - # Use the last part of the url as the filename, and assume it is an STL file - filename = model_url.path().split("/")[-1] + ".stl" - else: - # content_disposition is in the following format - # ``` - # content_disposition attachment; "filename=[FILENAME]" - # ``` - # Use a regex to extract the filename - # content_disposition = response.headers.get('Content-Disposition') - content_disposition_match = re.match(r'attachment; filename="(?P.*)"', - content_disposition) - assert content_disposition_match is not None - filename = content_disposition_match.group("filename") - - tmp = tempfile.NamedTemporaryFile(suffix=filename, delete=False) - with open(tmp.name, "wb") as f: - f.write(response.content) - self.readLocalFile(QUrl.fromLocalFile(tmp.name), add_to_recent_files=False) + self.getHttpRequestManager().get( + model_url.url(), + callback=on_finish, + error_callback=on_error, + ) case path: Logger.log("w", "Unsupported url scheme path: {0}".format(path)) From 4b4b8b351462f7b788816c2ddbf2d75d38ee7de6 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Fri, 1 Dec 2023 13:03:40 +0100 Subject: [PATCH 10/73] Update nsi installer CURA-11288 --- packaging/NSIS/Ultimaker-Cura.nsi.jinja | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packaging/NSIS/Ultimaker-Cura.nsi.jinja b/packaging/NSIS/Ultimaker-Cura.nsi.jinja index 228dba4fe4..c562e5f654 100644 --- a/packaging/NSIS/Ultimaker-Cura.nsi.jinja +++ b/packaging/NSIS/Ultimaker-Cura.nsi.jinja @@ -197,13 +197,11 @@ Section UrlProtocol WriteRegStr HKCR "cura" "" "URL:cura" WriteRegStr HKCR "cura" "URL Protocol" "" WriteRegStr HKCR "cura\DefaultIcon" "" "$INSTDIR\${MAIN_APP_EXE},1" - WriteRegStr HKCR "cura\shell" "" "open" - WriteRegStr HKCR "cura\shell\open\command" "" '"$INSTDIR\${MAIN_APP_EXE}" "%1"' + WriteRegStr HKCR "cura\shell\open\command" "" '"$INSTDIR\${MAIN_APP_EXE}"' WriteRegStr HKCR "slicer" "" "URL:slicer" WriteRegStr HKCR "slicer" "URL Protocol" "" WriteRegStr HKCR "slicer\DefaultIcon" "" "$INSTDIR\${MAIN_APP_EXE},1" - WriteRegStr HKCR "slicer\shell" "" "open" - WriteRegStr HKCR "slicer\shell\open\command" "" '"$INSTDIR\${MAIN_APP_EXE}" "%1"' + WriteRegStr HKCR "slicer\shell\open\command" "" '"$INSTDIR\${MAIN_APP_EXE}"' SectionEnd \ No newline at end of file From 34aecf20fe4f8f5e1ff4e52e80969d2f4279cb15 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Fri, 1 Dec 2023 13:04:49 +0100 Subject: [PATCH 11/73] pin uranium CURA-11288 --- conanfile.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/conanfile.py b/conanfile.py index 48cba847be..2c756f20c8 100644 --- a/conanfile.py +++ b/conanfile.py @@ -327,7 +327,7 @@ class CuraConan(ConanFile): self.requires("pysavitar/5.3.0") self.requires("pynest2d/5.3.0") self.requires("curaengine_plugin_gradual_flow/0.1.0") - self.requires("uranium/(latest)@ultimaker/testing") + self.requires("uranium/latest@ultimaker/cura_11288") self.requires("cura_binary_data/(latest)@ultimaker/testing") self.requires("cpython/3.10.4") if self.options.internal: @@ -358,7 +358,7 @@ class CuraConan(ConanFile): vr = VirtualRunEnv(self) vr.generate() - self._generate_cura_version(os.path.join(self.source_folder, "cura")) + # self._generate_cura_version(os.path.join(self.source_folder, "cura")) if not self.in_local_cache: # Copy CuraEngine.exe to bindirs of Virtual Python Environment @@ -466,7 +466,7 @@ echo "CURA_APP_NAME={{ cura_app_name }}" >> ${{ env_prefix }}GITHUB_ENV ext = ".sh" if self.settings.os != "Windows" else ".ps1" save(self, os.path.join(self._script_dir, f"activate_github_actions_version_env{ext}"), activate_github_actions_version_env) - self._generate_cura_version(os.path.join(self._site_packages, "cura")) + # self._generate_cura_version(os.path.join(self._site_packages, "cura")) entitlements_file = "'{}'".format(Path(self.cpp_info.res_paths[2], "MacOS", "cura.entitlements")) self._generate_pyinstaller_spec(location = self._base_dir, From 19b75b96fb007973bb2fe3f3c0ef0e1e95567903 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Fri, 1 Dec 2023 16:13:19 +0100 Subject: [PATCH 12/73] unpin dulcificum CURA-11288 --- conanfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conanfile.py b/conanfile.py index 2c756f20c8..b58cbb4b7f 100644 --- a/conanfile.py +++ b/conanfile.py @@ -322,7 +322,7 @@ class CuraConan(ConanFile): self.requires("curaengine_grpc_definitions/0.1.0") self.requires("zlib/1.2.13") self.requires("pyarcus/5.3.0") - self.requires("dulcificum/0.1.0-beta.1") + self.requires("dulcificum/(latest)@ultimaker/testing") self.requires("curaengine/(latest)@ultimaker/testing") self.requires("pysavitar/5.3.0") self.requires("pynest2d/5.3.0") From a9c3c2b4b432d7224d97fa356e8d042f4848aeba Mon Sep 17 00:00:00 2001 From: Paul Kuiper <46715907+pkuiper-ultimaker@users.noreply.github.com> Date: Tue, 5 Dec 2023 15:25:52 +0100 Subject: [PATCH 13/73] Increased raft base layer speed from 5mm/s to 10mm/s and increased raft middle layer linewidth from 0.4 to 0.7mm to increase productivity. PP-408 --- resources/definitions/ultimaker_method_base.def.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/definitions/ultimaker_method_base.def.json b/resources/definitions/ultimaker_method_base.def.json index 6ac68ef2de..ea00c726c2 100644 --- a/resources/definitions/ultimaker_method_base.def.json +++ b/resources/definitions/ultimaker_method_base.def.json @@ -353,11 +353,11 @@ "print_sequence": { "enabled": false }, "raft_base_line_spacing": { "value": "2*raft_base_line_width" }, "raft_base_line_width": { "value": 1.4 }, - "raft_base_speed": { "value": 5 }, + "raft_base_speed": { "value": 10 }, "raft_base_thickness": { "value": 0.8 }, "raft_interface_extruder_nr": { "value": "raft_surface_extruder_nr" }, "raft_interface_layers": { "value": 2 }, - "raft_interface_line_width": { "value": "line_width" }, + "raft_interface_line_width": { "value": 0.7 }, "raft_interface_speed": { "value": 90 }, "raft_interface_thickness": { "value": 0.3 }, "raft_margin": { "value": 3 }, From b46f6e8e09582f49216e4f0af295a413b78c9e7e Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Tue, 5 Dec 2023 18:24:44 +0100 Subject: [PATCH 14/73] Add support for CLI file opening with 'cura' and 'slicer' schemes CURA-11288 --- cura/CuraApplication.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 079a27b6ce..a71b6d9915 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -276,6 +276,8 @@ class CuraApplication(QtApplication): self._conan_installs = ApplicationMetadata.CONAN_INSTALLS self._python_installs = ApplicationMetadata.PYTHON_INSTALLS + self._supported_url_schemes: List[str] = ["cura", "slicer"] + @pyqtProperty(str, constant=True) def ultimakerCloudApiRootUrl(self) -> str: return UltimakerCloudConstants.CuraCloudAPIRoot @@ -328,7 +330,11 @@ class CuraApplication(QtApplication): assert not "This crash is triggered by the trigger_early_crash command line argument." for filename in self._cli_args.file: - self._files_to_open.append(os.path.abspath(filename)) + url = QUrl(filename) + if url.scheme() in self._supported_url_schemes: + self._open_url_queue.append(url) + else: + self._files_to_open.append(os.path.abspath(filename)) def initialize(self) -> None: self.__addExpectedResourceDirsAndSearchPaths() # Must be added before init of super @@ -1794,8 +1800,7 @@ class CuraApplication(QtApplication): self.readLocalFile(QUrl.fromLocalFile(filename)) def _openUrl(self, url: QUrl) -> None: - supported_schemes = ["cura", "slicer"] - if url.scheme() not in supported_schemes: + if url.scheme() not in self._supported_url_schemes: # only handle cura:// and slicer:// urls schemes return From a7a4e4bd2911ae9a7a9095cb9d676b009233149a Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Wed, 6 Dec 2023 06:06:08 +0100 Subject: [PATCH 15/73] Revert "Update nsi installer" This reverts commit 4b4b8b351462f7b788816c2ddbf2d75d38ee7de6. --- packaging/NSIS/Ultimaker-Cura.nsi.jinja | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packaging/NSIS/Ultimaker-Cura.nsi.jinja b/packaging/NSIS/Ultimaker-Cura.nsi.jinja index c562e5f654..228dba4fe4 100644 --- a/packaging/NSIS/Ultimaker-Cura.nsi.jinja +++ b/packaging/NSIS/Ultimaker-Cura.nsi.jinja @@ -197,11 +197,13 @@ Section UrlProtocol WriteRegStr HKCR "cura" "" "URL:cura" WriteRegStr HKCR "cura" "URL Protocol" "" WriteRegStr HKCR "cura\DefaultIcon" "" "$INSTDIR\${MAIN_APP_EXE},1" - WriteRegStr HKCR "cura\shell\open\command" "" '"$INSTDIR\${MAIN_APP_EXE}"' + WriteRegStr HKCR "cura\shell" "" "open" + WriteRegStr HKCR "cura\shell\open\command" "" '"$INSTDIR\${MAIN_APP_EXE}" "%1"' WriteRegStr HKCR "slicer" "" "URL:slicer" WriteRegStr HKCR "slicer" "URL Protocol" "" WriteRegStr HKCR "slicer\DefaultIcon" "" "$INSTDIR\${MAIN_APP_EXE},1" - WriteRegStr HKCR "slicer\shell\open\command" "" '"$INSTDIR\${MAIN_APP_EXE}"' + WriteRegStr HKCR "slicer\shell" "" "open" + WriteRegStr HKCR "slicer\shell\open\command" "" '"$INSTDIR\${MAIN_APP_EXE}" "%1"' SectionEnd \ No newline at end of file From 351183f407360b89565084b0bdef72ff7e852570 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Wed, 6 Dec 2023 06:13:39 +0100 Subject: [PATCH 16/73] Temporarily pin spdlog CURA-11288 --- conanfile.py | 1 + 1 file changed, 1 insertion(+) diff --git a/conanfile.py b/conanfile.py index b58cbb4b7f..081db4d933 100644 --- a/conanfile.py +++ b/conanfile.py @@ -335,6 +335,7 @@ class CuraConan(ConanFile): self.requires("fdm_materials/(latest)@internal/testing") else: self.requires("fdm_materials/(latest)@ultimaker/testing") + self.requires("spdlog/1.12.0@_/_") def build_requirements(self): if self.options.get_safe("enable_i18n", False): From c4939701e1f3ee37314f8e71a27eb4196ab3f3e1 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Wed, 6 Dec 2023 06:37:36 +0100 Subject: [PATCH 17/73] Re-enable genrate cura version CURA-11288 --- conanfile.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conanfile.py b/conanfile.py index 081db4d933..ec5be608d6 100644 --- a/conanfile.py +++ b/conanfile.py @@ -359,7 +359,7 @@ class CuraConan(ConanFile): vr = VirtualRunEnv(self) vr.generate() - # self._generate_cura_version(os.path.join(self.source_folder, "cura")) + self._generate_cura_version(os.path.join(self.source_folder, "cura")) if not self.in_local_cache: # Copy CuraEngine.exe to bindirs of Virtual Python Environment @@ -467,7 +467,7 @@ echo "CURA_APP_NAME={{ cura_app_name }}" >> ${{ env_prefix }}GITHUB_ENV ext = ".sh" if self.settings.os != "Windows" else ".ps1" save(self, os.path.join(self._script_dir, f"activate_github_actions_version_env{ext}"), activate_github_actions_version_env) - # self._generate_cura_version(os.path.join(self._site_packages, "cura")) + self._generate_cura_version(os.path.join(self._site_packages, "cura")) entitlements_file = "'{}'".format(Path(self.cpp_info.res_paths[2], "MacOS", "cura.entitlements")) self._generate_pyinstaller_spec(location = self._base_dir, From 153e2e7bd073f4d7e367560345993525f7a5aebc Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Wed, 6 Dec 2023 07:14:36 +0100 Subject: [PATCH 18/73] Fix warning/Boyscouting CURA-11288 --- cura/PrinterOutput/Models/MaterialOutputModel.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cura/PrinterOutput/Models/MaterialOutputModel.py b/cura/PrinterOutput/Models/MaterialOutputModel.py index 6920cead1b..d60c34ed10 100644 --- a/cura/PrinterOutput/Models/MaterialOutputModel.py +++ b/cura/PrinterOutput/Models/MaterialOutputModel.py @@ -42,8 +42,7 @@ class MaterialOutputModel(QObject): "tpu" :{"name" :"tpu_175" ,"guid": "19baa6a9-94ff-478b-b4a1-8157b74358d2"} } - - if guid is None and brand is not "empty" and type in _MATERIAL_MAP: + if guid is None and brand != "empty" and type in _MATERIAL_MAP: name = _MATERIAL_MAP[type]["name"] guid = _MATERIAL_MAP[type]["guid"] return name, guid From d6a73a5976067078c7e7e63e2d6a12b89573d566 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Wed, 6 Dec 2023 07:57:45 +0100 Subject: [PATCH 19/73] Fix opening files on windows `_open_url_queue` is expecting a list of strings, not a `QUrl` instance CURA-11288 --- cura/CuraApplication.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index a71b6d9915..82313eece8 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -332,7 +332,7 @@ class CuraApplication(QtApplication): for filename in self._cli_args.file: url = QUrl(filename) if url.scheme() in self._supported_url_schemes: - self._open_url_queue.append(url) + self._open_url_queue.append(filename) else: self._files_to_open.append(os.path.abspath(filename)) From 568fc4ca766afa3ee14f1620d925b90363196b09 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Wed, 6 Dec 2023 08:49:37 +0100 Subject: [PATCH 20/73] Revert "Fix opening files on windows" This reverts commit d6a73a5976067078c7e7e63e2d6a12b89573d566. --- cura/CuraApplication.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 82313eece8..a71b6d9915 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -332,7 +332,7 @@ class CuraApplication(QtApplication): for filename in self._cli_args.file: url = QUrl(filename) if url.scheme() in self._supported_url_schemes: - self._open_url_queue.append(filename) + self._open_url_queue.append(url) else: self._files_to_open.append(os.path.abspath(filename)) From 84d56367f4f357caec408e14e4d396d96aa13aef Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Wed, 6 Dec 2023 13:33:57 +0100 Subject: [PATCH 21/73] Also listen to the "/" appended string for url schemes Windows adds a slash for some reason CURA-11288 --- cura/CuraApplication.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index a71b6d9915..1f60130787 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -1805,7 +1805,7 @@ class CuraApplication(QtApplication): return match url.host() + url.path(): - case "open": + case "open" | "open/": query = QUrlQuery(url.query()) model_url = QUrl(query.queryItemValue("file", options=QUrl.ComponentFormattingOption.FullyDecoded)) From 7574b56ebad4371efcbeb5bd42d0bbe864e317ec Mon Sep 17 00:00:00 2001 From: Casper Lamboo Date: Thu, 7 Dec 2023 10:32:01 +0100 Subject: [PATCH 22/73] Update conanfile.py --- conanfile.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/conanfile.py b/conanfile.py index 1ee2094490..678943759c 100644 --- a/conanfile.py +++ b/conanfile.py @@ -326,13 +326,12 @@ class CuraConan(ConanFile): self.requires("curaengine_grpc_definitions/0.1.0") self.requires("zlib/1.2.13") self.requires("pyarcus/5.3.0") - self.requires("dulcificum/(latest)@ultimaker/testing") self.requires("dulcificum/(latest)@ultimaker/stable") self.requires("curaengine/(latest)@ultimaker/testing") self.requires("pysavitar/5.3.0") self.requires("pynest2d/5.3.0") self.requires("curaengine_plugin_gradual_flow/0.1.0") - self.requires("uranium/latest@ultimaker/testing") + self.requires("uranium/(latest)@ultimaker/testing") self.requires("cura_binary_data/(latest)@ultimaker/testing") self.requires("cpython/3.10.4@ultimaker/stable") self.requires("openssl/3.2.0") @@ -341,7 +340,6 @@ class CuraConan(ConanFile): self.requires("fdm_materials/(latest)@internal/testing") else: self.requires("fdm_materials/(latest)@ultimaker/testing") - self.requires("spdlog/1.12.0@_/_") def build_requirements(self): if self.options.get_safe("enable_i18n", False): From cfec5e0cc112181d4db4af13ed6a0f8ec3047669 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Tue, 19 Dec 2023 10:12:56 +0100 Subject: [PATCH 23/73] Proof of concept for simulation Co-authored-by: Casper Lamboo CURA-7647 --- cura/LayerPolygon.py | 6 +- plugins/SimulationView/SimulationPass.py | 32 +++-- plugins/SimulationView/SimulationView.py | 124 +++++++++++++----- .../SimulationViewMainComponent.qml | 47 +------ plugins/SimulationView/SimulationViewProxy.py | 23 +--- 5 files changed, 128 insertions(+), 104 deletions(-) diff --git a/cura/LayerPolygon.py b/cura/LayerPolygon.py index e5fd307dc9..e772a8b78e 100644 --- a/cura/LayerPolygon.py +++ b/cura/LayerPolygon.py @@ -67,7 +67,7 @@ class LayerPolygon: # Buffering the colors shouldn't be necessary as it is not # re-used and can save a lot of memory usage. self._color_map = LayerPolygon.getColorMap() - self._colors = self._color_map[self._types] # type: numpy.ndarray + self._colors: numpy.ndarray = self._color_map[self._types] # When type is used as index returns true if type == LayerPolygon.InfillType # or type == LayerPolygon.SkinType @@ -75,8 +75,8 @@ class LayerPolygon: # Should be generated in better way, not hardcoded. self._is_infill_or_skin_type_map = numpy.array([0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0], dtype=bool) - self._build_cache_line_mesh_mask = None # type: Optional[numpy.ndarray] - self._build_cache_needed_points = None # type: Optional[numpy.ndarray] + self._build_cache_line_mesh_mask: Optional[numpy.ndarray] = None + self._build_cache_needed_points: Optional[numpy.ndarray] = None def buildCache(self) -> None: # For the line mesh we do not draw Infill or Jumps. Therefore those lines are filtered out. diff --git a/plugins/SimulationView/SimulationPass.py b/plugins/SimulationView/SimulationPass.py index 1294b37db4..3294f4b1e6 100644 --- a/plugins/SimulationView/SimulationPass.py +++ b/plugins/SimulationView/SimulationPass.py @@ -35,7 +35,7 @@ class SimulationPass(RenderPass): self._nozzle_shader = None self._disabled_shader = None self._old_current_layer = 0 - self._old_current_path = 0 + self._old_current_path: float = 0.0 self._switching_layers = True # Tracking whether the user is moving across layers (True) or across paths (False). If false, lower layers render as shadowy. self._gl = OpenGL.getInstance().getBindingsObject() self._scene = Application.getInstance().getController().getScene() @@ -139,7 +139,7 @@ class SimulationPass(RenderPass): continue # Render all layers below a certain number as line mesh instead of vertices. - if self._layer_view._current_layer_num > -1 and ((not self._layer_view._only_show_top_layers) or (not self._layer_view.getCompatibilityMode())): + if self._layer_view.getCurrentLayer() > -1 and ((not self._layer_view._only_show_top_layers) or (not self._layer_view.getCompatibilityMode())): start = 0 end = 0 element_counts = layer_data.getElementCounts() @@ -147,7 +147,7 @@ class SimulationPass(RenderPass): # In the current layer, we show just the indicated paths if layer == self._layer_view._current_layer_num: # We look for the position of the head, searching the point of the current path - index = self._layer_view._current_path_num + index = int(self._layer_view.getCurrentPath()) offset = 0 for polygon in layer_data.getLayer(layer).polygons: # The size indicates all values in the two-dimension array, and the second dimension is @@ -157,23 +157,33 @@ class SimulationPass(RenderPass): offset = 1 # This is to avoid the first point when there is more than one polygon, since has the same value as the last point in the previous polygon continue # The head position is calculated and translated - head_position = Vector(polygon.data[index+offset][0], polygon.data[index+offset][1], polygon.data[index+offset][2]) + node.getWorldPosition() + ratio = self._layer_view.getCurrentPath() - index + pos_a = Vector(polygon.data[index + offset][0], polygon.data[index + offset][1], + polygon.data[index + offset][2]) + if ratio > 0.0001: + pos_b = Vector(polygon.data[index + offset + 1][0], + polygon.data[index + offset + 1][1], + polygon.data[index + offset + 1][2]) + vec = pos_a * (1.0 - ratio) + pos_b * ratio + head_position = vec + node.getWorldPosition() + else: + head_position = pos_a + node.getWorldPosition() break break - if self._layer_view._minimum_layer_num > layer: + if self._layer_view.getMinimumLayer() > layer: start += element_counts[layer] end += element_counts[layer] # Calculate the range of paths in the last layer current_layer_start = end - current_layer_end = end + self._layer_view._current_path_num * 2 # Because each point is used twice + current_layer_end = end + int( self._layer_view.getCurrentPath()) * 2 # Because each point is used twice # This uses glDrawRangeElements internally to only draw a certain range of lines. # All the layers but the current selected layer are rendered first - if self._old_current_path != self._layer_view._current_path_num: + if self._old_current_path != self._layer_view.getCurrentPath(): self._current_shader = self._layer_shadow_shader self._switching_layers = False - if not self._layer_view.isSimulationRunning() and self._old_current_layer != self._layer_view._current_layer_num: + if not self._layer_view.isSimulationRunning() and self._old_current_layer != self._layer_view.getCurrentLayer(): self._current_shader = self._layer_shader self._switching_layers = True @@ -193,8 +203,8 @@ class SimulationPass(RenderPass): current_layer_batch.addItem(node.getWorldTransformation(), layer_data) current_layer_batch.render(self._scene.getActiveCamera()) - self._old_current_layer = self._layer_view._current_layer_num - self._old_current_path = self._layer_view._current_path_num + self._old_current_layer = self._layer_view.getCurrentLayer() + self._old_current_path = self._layer_view.getCurrentPath() # Create a new batch that is not range-limited batch = RenderBatch(self._layer_shader, type = RenderBatch.RenderType.Solid) @@ -230,4 +240,4 @@ class SimulationPass(RenderPass): if changed_object.callDecoration("getLayerData"): # Any layer data has changed. self._switching_layers = True self._old_current_layer = 0 - self._old_current_path = 0 + self._old_current_path = 0.0 diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index a659a6de97..64ec0dfc1b 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -40,7 +40,7 @@ from .SimulationViewProxy import SimulationViewProxy import numpy import os.path -from typing import Optional, TYPE_CHECKING, List, cast +from typing import Optional, TYPE_CHECKING, List, Tuple, cast if TYPE_CHECKING: from UM.Scene.SceneNode import SceneNode @@ -74,21 +74,20 @@ class SimulationView(CuraView): self._old_max_layers = 0 self._max_paths = 0 - self._current_path_num = 0 + self._current_path_num: float = 0.0 + self._current_time = 0.0 self._minimum_path_num = 0 self.currentLayerNumChanged.connect(self._onCurrentLayerNumChanged) - self._current_feedrates = {} - self._lengths_of_polyline ={} self._busy = False self._simulation_running = False - self._ghost_shader = None # type: Optional["ShaderProgram"] - self._layer_pass = None # type: Optional[SimulationPass] - self._composite_pass = None # type: Optional[CompositePass] - self._old_layer_bindings = None # type: Optional[List[str]] - self._simulationview_composite_shader = None # type: Optional["ShaderProgram"] - self._old_composite_shader = None # type: Optional["ShaderProgram"] + self._ghost_shader: Optional["ShaderProgram"] = None + self._layer_pass: Optional[SimulationPass] = None + self._composite_pass: Optional[CompositePass] = None + self._old_layer_bindings: Optional[List[str]] = None + self._simulationview_composite_shader: Optional["ShaderProgram"] = None + self._old_composite_shader: Optional["ShaderProgram"] = None self._max_feedrate = sys.float_info.min self._min_feedrate = sys.float_info.max @@ -99,13 +98,13 @@ class SimulationView(CuraView): self._min_flow_rate = sys.float_info.max self._max_flow_rate = sys.float_info.min - self._global_container_stack = None # type: Optional[ContainerStack] + self._global_container_stack: Optional[ContainerStack] = None self._proxy = None self._resetSettings() self._legend_items = None self._show_travel_moves = False - self._nozzle_node = None # type: Optional[NozzleNode] + self._nozzle_node: Optional[NozzleNode] = None Application.getInstance().getPreferences().addPreference("view/top_layer_count", 5) Application.getInstance().getPreferences().addPreference("view/only_show_top_layers", False) @@ -127,13 +126,12 @@ class SimulationView(CuraView): self._only_show_top_layers = bool(Application.getInstance().getPreferences().getValue("view/only_show_top_layers")) self._compatibility_mode = self._evaluateCompatibilityMode() - self._slice_first_warning_message = Message(catalog.i18nc("@info:status", - "Nothing is shown because you need to slice first."), - title = catalog.i18nc("@info:title", "No layers to show"), - option_text = catalog.i18nc("@info:option_text", - "Do not show this message again"), - option_state = False, - message_type = Message.MessageType.WARNING) + self._slice_first_warning_message = Message(catalog.i18nc("@info:status", "Nothing is shown because you need to slice first."), + title=catalog.i18nc("@info:title", "No layers to show"), + option_text=catalog.i18nc("@info:option_text", + "Do not show this message again"), + option_state=False, + message_type=Message.MessageType.WARNING) self._slice_first_warning_message.optionToggled.connect(self._onDontAskMeAgain) CuraApplication.getInstance().getPreferences().addPreference(self._no_layers_warning_preference, True) @@ -189,9 +187,82 @@ class SimulationView(CuraView): def getMaxLayers(self) -> int: return self._max_layers - def getCurrentPath(self) -> int: + def getCurrentPath(self) -> float: return self._current_path_num + def setTime(self, time: float) -> None: + self._current_time = time + + left_i = 0 + right_i = self._max_paths - 1 + + total_duration, cumulative_line_duration = self.cumulativeLineDuration() + + # make an educated guess about where to start + i = int(right_i * max(0.0, min(1.0, self._current_time / total_duration))) + + # binary search for the correct path + while left_i < right_i: + if cumulative_line_duration[i] <= self._current_time: + left_i = i + 1 + else: + right_i = i + i = int((left_i + right_i) / 2) + + left_value = cumulative_line_duration[i - 1] if i > 0 else 0.0 + right_value = cumulative_line_duration[i] + + assert (left_value <= self._current_time <= right_value) + + fractional_value = (self._current_time - left_value) / (right_value - left_value) + + self.setPath(i + fractional_value) + + def advanceTime(self, time_increase: float) -> bool: + """ + Advance the time by the given amount. + + :param time_increase: The amount of time to advance (in seconds). + :return: True if the time was advanced, False if the end of the simulation was reached. + """ + total_duration, cumulative_line_duration = self.cumulativeLineDuration() + + # time ratio + time_increase = time_increase + + if self._current_time + time_increase > total_duration: + # If we have reached the end of the simulation, go to the next layer. + if self.getCurrentLayer() == self.getMaxLayers(): + # If we are already at the last layer, go to the first layer. + self.setTime(total_duration) + return False + + # advance to the next layer, and reset the time + self.setLayer(self.getCurrentLayer() + 1) + self.setTime(0.0) + else: + self.setTime(self._current_time + time_increase) + return True + + def cumulativeLineDuration(self) -> Tuple[float, List[float]]: + # TODO: cache the total duration and cumulative line duration at each layer change event + cumulative_line_duration = [] + total_duration = 0.0 + for polyline in self.getLayerData().polygons: + for line_duration in list((polyline.lineLengths / polyline.lineFeedrates)[0]): + total_duration += line_duration + cumulative_line_duration.append(total_duration) + return total_duration, cumulative_line_duration + + def getLayerData(self) -> Optional["LayerData"]: + scene = self.getController().getScene() + for node in DepthFirstIterator(scene.getRoot()): # type: ignore + layer_data = node.callDecoration("getLayerData") + if not layer_data: + continue + return layer_data.getLayer(self.getCurrentLayer()) + return None + def getMinimumPath(self) -> int: return self._minimum_path_num @@ -279,7 +350,7 @@ class SimulationView(CuraView): self._startUpdateTopLayers() self.currentLayerNumChanged.emit() - def setPath(self, value: int) -> None: + def setPath(self, value: float) -> None: """ Set the upper end of the range of visible paths on the current layer. @@ -402,15 +473,6 @@ class SimulationView(CuraView): def getMaxFeedrate(self) -> float: return self._max_feedrate - def getSimulationTime(self, currentIndex) -> float: - try: - return (self._lengths_of_polyline[self._current_layer_num][currentIndex] / self._current_feedrates[self._current_layer_num][currentIndex])[0] - - except: - # In case of change in layers, currentIndex comes one more than the items in the lengths_of_polyline - # We give 1 second time for layer change - return 1.0 - def getMinThickness(self) -> float: if abs(self._min_thickness - sys.float_info.max) < 10: # Some lenience due to floating point rounding. return 0.0 # If it's still max-float, there are no measurements. Use 0 then. @@ -535,10 +597,8 @@ class SimulationView(CuraView): visible_indicies_with_extrusion = numpy.where(numpy.isin(polyline.types, visible_line_types_with_extrusion))[0] if visible_indices.size == 0: # No items to take maximum or minimum of. continue - self._lengths_of_polyline[layer_index] = polyline.lineLengths visible_feedrates = numpy.take(polyline.lineFeedrates, visible_indices) visible_feedrates_with_extrusion = numpy.take(polyline.lineFeedrates, visible_indicies_with_extrusion) - self._current_feedrates[layer_index] = polyline.lineFeedrates visible_linewidths = numpy.take(polyline.lineWidths, visible_indices) visible_linewidths_with_extrusion = numpy.take(polyline.lineWidths, visible_indicies_with_extrusion) visible_thicknesses = numpy.take(polyline.lineThicknesses, visible_indices) diff --git a/plugins/SimulationView/SimulationViewMainComponent.qml b/plugins/SimulationView/SimulationViewMainComponent.qml index 216095c15c..23cbf8c611 100644 --- a/plugins/SimulationView/SimulationViewMainComponent.qml +++ b/plugins/SimulationView/SimulationViewMainComponent.qml @@ -136,54 +136,19 @@ Item Timer { id: simulationTimer - interval: UM.SimulationView.simulationTime + interval: 1000 / 60 running: false repeat: true onTriggered: { - var currentPath = UM.SimulationView.currentPath - var numPaths = UM.SimulationView.numPaths - var currentLayer = UM.SimulationView.currentLayer - var numLayers = UM.SimulationView.numLayers - - // When the user plays the simulation, if the path slider is at the end of this layer, we start - // the simulation at the beginning of the current layer. - if (!isSimulationPlaying) - { - if (currentPath >= numPaths) - { - UM.SimulationView.setCurrentPath(0) - } - else - { - UM.SimulationView.setCurrentPath(currentPath + 1) - } - } - // If the simulation is already playing and we reach the end of a layer, then it automatically - // starts at the beginning of the next layer. - else - { - if (currentPath >= numPaths) - { - // At the end of the model, the simulation stops - if (currentLayer >= numLayers) - { - playButton.pauseSimulation() - } - else - { - UM.SimulationView.setCurrentLayer(currentLayer + 1) - UM.SimulationView.setCurrentPath(0) - } - } - else - { - UM.SimulationView.setCurrentPath(currentPath + 1) - } + // divide by 1000 to accont for ms to s conversion + const advance_time = simulationTimer.interval / 1000.0; + if (!UM.SimulationView.advanceTime(advance_time)) { + playButton.pauseSimulation(); } // The status must be set here instead of in the resumeSimulation function otherwise it won't work // correctly, because part of the logic is in this trigger function. - isSimulationPlaying = true + isSimulationPlaying = true; } } diff --git a/plugins/SimulationView/SimulationViewProxy.py b/plugins/SimulationView/SimulationViewProxy.py index 576281874c..bf449a99d1 100644 --- a/plugins/SimulationView/SimulationViewProxy.py +++ b/plugins/SimulationView/SimulationViewProxy.py @@ -2,7 +2,6 @@ # Cura is released under the terms of the LGPLv3 or higher. from typing import TYPE_CHECKING -import numpy from PyQt6.QtCore import QObject, pyqtSignal, pyqtProperty from UM.FlameProfiler import pyqtSlot from UM.Application import Application @@ -12,11 +11,6 @@ if TYPE_CHECKING: class SimulationViewProxy(QObject): - - S_TO_MS = 1000 - SPEED_OF_SIMULATION = 10 - FACTOR = S_TO_MS/SPEED_OF_SIMULATION - def __init__(self, simulation_view: "SimulationView", parent=None) -> None: super().__init__(parent) self._simulation_view = simulation_view @@ -56,17 +50,13 @@ class SimulationViewProxy(QObject): def numPaths(self): return self._simulation_view.getMaxPaths() - @pyqtProperty(int, notify=currentPathChanged) + @pyqtProperty(float, notify=currentPathChanged) def currentPath(self): return self._simulation_view.getCurrentPath() - @pyqtProperty(int, notify=currentPathChanged) - def simulationTime(self): - # Extracts the currents paths simulation time (in seconds) for the current path from the dict of simulation time of the current layer. - # We multiply the time with 100 to make it to ms from s.(Should be 1000 in real time). This scaling makes the simulation time 10x faster than the real time. - simulationTimeOfpath = self._simulation_view.getSimulationTime(self._simulation_view.getCurrentPath()) * SimulationViewProxy.FACTOR - # Since the timer cannot process time less than 1 ms, we put a lower limit here - return int(max(1, simulationTimeOfpath)) + @pyqtSlot(float, result=bool) + def advanceTime(self, duration: float) -> bool: + return self._simulation_view.advanceTime(duration) @pyqtProperty(int, notify=currentPathChanged) def minimumPath(self): @@ -92,8 +82,8 @@ class SimulationViewProxy(QObject): def setMinimumLayer(self, layer_num): self._simulation_view.setMinimumLayer(layer_num) - @pyqtSlot(int) - def setCurrentPath(self, path_num): + @pyqtSlot(float) + def setCurrentPath(self, path_num: float): self._simulation_view.setPath(path_num) @pyqtSlot(int) @@ -229,4 +219,3 @@ class SimulationViewProxy(QObject): self._simulation_view.activityChanged.disconnect(self._onActivityChanged) self._simulation_view.globalStackChanged.disconnect(self._onGlobalStackChanged) self._simulation_view.preferencesChanged.disconnect(self._onPreferencesChanged) - From ddfd7d6a06842b2350b259ad9c22d8fd8fadcf06 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Tue, 19 Dec 2023 10:50:56 +0100 Subject: [PATCH 24/73] Use of APP_ASSOCIATE in url_scheme CURA-11288 --- packaging/NSIS/Ultimaker-Cura.nsi.jinja | 67 +++++++++++++++++++------ 1 file changed, 51 insertions(+), 16 deletions(-) diff --git a/packaging/NSIS/Ultimaker-Cura.nsi.jinja b/packaging/NSIS/Ultimaker-Cura.nsi.jinja index 228dba4fe4..3bef698805 100644 --- a/packaging/NSIS/Ultimaker-Cura.nsi.jinja +++ b/packaging/NSIS/Ultimaker-Cura.nsi.jinja @@ -144,6 +144,49 @@ SectionEnd ###################################################################### +Section UrlProtocol + +!macro APP_ASSOCIATE extension progid description commandname command + WriteRegStr HKCR "${extension}" "" "${description}" + WriteRegStr HKCR "${extension}" "URL Protocol" "" + WriteRegStr HKCR "${extension}\DefaultIcon" "" "${commandname},1" + WriteRegStr HKCR "${extension}\shell" "" "open" + WriteRegStr HKCR "${extension}\shell\open\command" "" '"${command}" "%1"' + !insertmacro APP_ASSOCIATE_SHORTCUT "${extension}" "${progid}" "${description}" "${command}" +!macroend + +WriteRegStr HKCR "cura" "" "URL:cura" +WriteRegStr HKCR "cura" "URL Protocol" "" +WriteRegStr HKCR "cura\DefaultIcon" "" "$INSTDIR\${MAIN_APP_EXE},1" +WriteRegStr HKCR "cura\shell" "" "open" +WriteRegStr HKCR "cura\shell\open\command" "" '"$INSTDIR\${MAIN_APP_EXE}" "%1"' + +WriteRegStr HKCR "slicer" "" "URL:slicer" +WriteRegStr HKCR "slicer" "URL Protocol" "" +WriteRegStr HKCR "slicer\DefaultIcon" "" "$INSTDIR\${MAIN_APP_EXE},1" +WriteRegStr HKCR "slicer\shell" "" "open" +WriteRegStr HKCR "slicer\shell\open\command" "" '"$INSTDIR\${MAIN_APP_EXE}" "%1"' + +; Set the uninstall section flag for this section +SetSectionFlags ${SECTION_UNINSTALL} + +; Define file associations for 'cura' protocol +StrCpy $0 "cura" +StrCpy $1 "URL:cura" +StrCpy $2 "CURA Protocol" +StrCpy $3 "$INSTDIR\${MAIN_APP_EXE},1" +Call APP_ASSOCIATE + +; Define file associations for 'slicer' protocol +StrCpy $0 "slicer" +StrCpy $1 "URL:slicer" +StrCpy $2 "SLICER Protocol" +StrCpy $3 "$INSTDIR\${MAIN_APP_EXE},1" +Call APP_ASSOCIATE + +SectionEnd +###################################################################### + Section Uninstall ${INSTALL_TYPE}{% for files in mapped_out_paths.values() %}{% for file in files %} Delete "{{ file[1] }}"{% endfor %}{% endfor %}{% for rem_dir in rmdir_paths %} @@ -187,23 +230,15 @@ RmDir "$SMPROGRAMS\{{ app_name }}" !insertmacro APP_UNASSOCIATE "stl" "Cura.model" !insertmacro APP_UNASSOCIATE "3mf" "Cura.project" +; Unassociate file associations for 'cura' protocol +StrCpy $0 "cura" +Call APP_UNASSOCIATE + +; Unassociate file associations for 'slicer' protocol +StrCpy $0 "slicer" +Call APP_UNASSOCIATE + DeleteRegKey ${REG_ROOT} "${REG_APP_PATH}" DeleteRegKey ${REG_ROOT} "${UNINSTALL_PATH}" SectionEnd -###################################################################### - -Section UrlProtocol - WriteRegStr HKCR "cura" "" "URL:cura" - WriteRegStr HKCR "cura" "URL Protocol" "" - WriteRegStr HKCR "cura\DefaultIcon" "" "$INSTDIR\${MAIN_APP_EXE},1" - WriteRegStr HKCR "cura\shell" "" "open" - WriteRegStr HKCR "cura\shell\open\command" "" '"$INSTDIR\${MAIN_APP_EXE}" "%1"' - - WriteRegStr HKCR "slicer" "" "URL:slicer" - WriteRegStr HKCR "slicer" "URL Protocol" "" - WriteRegStr HKCR "slicer\DefaultIcon" "" "$INSTDIR\${MAIN_APP_EXE},1" - WriteRegStr HKCR "slicer\shell" "" "open" - WriteRegStr HKCR "slicer\shell\open\command" "" '"$INSTDIR\${MAIN_APP_EXE}" "%1"' - -SectionEnd \ No newline at end of file From 5769fcba50134c7975437452a4a17f68927a6446 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Tue, 19 Dec 2023 13:26:19 +0100 Subject: [PATCH 25/73] Deleting the register key for url scheme CURA-11288 --- packaging/NSIS/Ultimaker-Cura.nsi.jinja | 32 ++----------------------- 1 file changed, 2 insertions(+), 30 deletions(-) diff --git a/packaging/NSIS/Ultimaker-Cura.nsi.jinja b/packaging/NSIS/Ultimaker-Cura.nsi.jinja index 3bef698805..0a2ce0f517 100644 --- a/packaging/NSIS/Ultimaker-Cura.nsi.jinja +++ b/packaging/NSIS/Ultimaker-Cura.nsi.jinja @@ -146,15 +146,6 @@ SectionEnd Section UrlProtocol -!macro APP_ASSOCIATE extension progid description commandname command - WriteRegStr HKCR "${extension}" "" "${description}" - WriteRegStr HKCR "${extension}" "URL Protocol" "" - WriteRegStr HKCR "${extension}\DefaultIcon" "" "${commandname},1" - WriteRegStr HKCR "${extension}\shell" "" "open" - WriteRegStr HKCR "${extension}\shell\open\command" "" '"${command}" "%1"' - !insertmacro APP_ASSOCIATE_SHORTCUT "${extension}" "${progid}" "${description}" "${command}" -!macroend - WriteRegStr HKCR "cura" "" "URL:cura" WriteRegStr HKCR "cura" "URL Protocol" "" WriteRegStr HKCR "cura\DefaultIcon" "" "$INSTDIR\${MAIN_APP_EXE},1" @@ -167,23 +158,6 @@ WriteRegStr HKCR "slicer\DefaultIcon" "" "$INSTDIR\${MAIN_APP_EXE},1" WriteRegStr HKCR "slicer\shell" "" "open" WriteRegStr HKCR "slicer\shell\open\command" "" '"$INSTDIR\${MAIN_APP_EXE}" "%1"' -; Set the uninstall section flag for this section -SetSectionFlags ${SECTION_UNINSTALL} - -; Define file associations for 'cura' protocol -StrCpy $0 "cura" -StrCpy $1 "URL:cura" -StrCpy $2 "CURA Protocol" -StrCpy $3 "$INSTDIR\${MAIN_APP_EXE},1" -Call APP_ASSOCIATE - -; Define file associations for 'slicer' protocol -StrCpy $0 "slicer" -StrCpy $1 "URL:slicer" -StrCpy $2 "SLICER Protocol" -StrCpy $3 "$INSTDIR\${MAIN_APP_EXE},1" -Call APP_ASSOCIATE - SectionEnd ###################################################################### @@ -231,12 +205,10 @@ RmDir "$SMPROGRAMS\{{ app_name }}" !insertmacro APP_UNASSOCIATE "3mf" "Cura.project" ; Unassociate file associations for 'cura' protocol -StrCpy $0 "cura" -Call APP_UNASSOCIATE +DeleteRegKey HKCR "cura" ; Unassociate file associations for 'slicer' protocol -StrCpy $0 "slicer" -Call APP_UNASSOCIATE +DeleteRegKey HKCR "slicer" DeleteRegKey ${REG_ROOT} "${REG_APP_PATH}" DeleteRegKey ${REG_ROOT} "${UNINSTALL_PATH}" From 69f8227b412e2eefa8e53b4c2e28fca6f803490c Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Tue, 19 Dec 2023 14:33:21 +0100 Subject: [PATCH 26/73] Path correction for cura application for msi CURA-11288 --- packaging/msi/UltiMaker-Cura.wxs.jinja | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packaging/msi/UltiMaker-Cura.wxs.jinja b/packaging/msi/UltiMaker-Cura.wxs.jinja index 07a2c7d8c9..e9cb01a041 100644 --- a/packaging/msi/UltiMaker-Cura.wxs.jinja +++ b/packaging/msi/UltiMaker-Cura.wxs.jinja @@ -164,8 +164,8 @@ - - + + @@ -173,8 +173,8 @@ - - + + From cb01026aad29777fdd2aa3eb05a6fbd9fe1f43ac Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Tue, 19 Dec 2023 15:27:53 +0100 Subject: [PATCH 27/73] Path correction for cura application for msi CURA-11288 --- packaging/msi/UltiMaker-Cura.wxs.jinja | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packaging/msi/UltiMaker-Cura.wxs.jinja b/packaging/msi/UltiMaker-Cura.wxs.jinja index e9cb01a041..c6ec5dbd63 100644 --- a/packaging/msi/UltiMaker-Cura.wxs.jinja +++ b/packaging/msi/UltiMaker-Cura.wxs.jinja @@ -164,8 +164,8 @@ - - + + @@ -173,8 +173,8 @@ - - + + From f663c57a927ca7a637bd382cd7b0ab9bc19c76aa Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Wed, 20 Dec 2023 08:50:37 +0100 Subject: [PATCH 28/73] Remove msi installer code Should be done for CURA-11435 CURA-11288 --- packaging/msi/UltiMaker-Cura.wxs.jinja | 36 -------------------------- 1 file changed, 36 deletions(-) diff --git a/packaging/msi/UltiMaker-Cura.wxs.jinja b/packaging/msi/UltiMaker-Cura.wxs.jinja index c6ec5dbd63..a183a97d5f 100644 --- a/packaging/msi/UltiMaker-Cura.wxs.jinja +++ b/packaging/msi/UltiMaker-Cura.wxs.jinja @@ -33,21 +33,6 @@ /> - - - - - {% if "Enterprise" in app_name %} @@ -159,32 +144,11 @@ - - - - - - - - - - - - - - - - - - - - - From f8f497b5781da97567077bff81bd75123b5bc3f4 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Wed, 20 Dec 2023 10:05:01 +0100 Subject: [PATCH 29/73] url registry entry for msi CURA-11435 --- packaging/msi/UltiMaker-Cura.wxs.jinja | 36 ++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/packaging/msi/UltiMaker-Cura.wxs.jinja b/packaging/msi/UltiMaker-Cura.wxs.jinja index a183a97d5f..c6ec5dbd63 100644 --- a/packaging/msi/UltiMaker-Cura.wxs.jinja +++ b/packaging/msi/UltiMaker-Cura.wxs.jinja @@ -33,6 +33,21 @@ /> + + + + + {% if "Enterprise" in app_name %} @@ -144,11 +159,32 @@ + + + + + + + + + + + + + + + + + + + + + From 76f86081c63c48652949d11d5c6aea62c5a4fd8b Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Wed, 20 Dec 2023 10:50:57 +0100 Subject: [PATCH 30/73] fixing the register entry CURA-11435 --- packaging/msi/UltiMaker-Cura.wxs.jinja | 41 ++++++++++++++++++++------ 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/packaging/msi/UltiMaker-Cura.wxs.jinja b/packaging/msi/UltiMaker-Cura.wxs.jinja index c6ec5dbd63..3dcb9ef2ee 100644 --- a/packaging/msi/UltiMaker-Cura.wxs.jinja +++ b/packaging/msi/UltiMaker-Cura.wxs.jinja @@ -160,24 +160,47 @@ - + + + + + + + + + + + + + + + + + + + + + 127.0.0.1 + + + + - - + + - + - - - - + + + + - From e08d183b6c424d9ecc5c5e4668e7e379edf0cabf Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Wed, 20 Dec 2023 10:56:25 +0100 Subject: [PATCH 31/73] undo commit 76f8608 CURA-11435 --- packaging/msi/UltiMaker-Cura.wxs.jinja | 37 +++++--------------------- 1 file changed, 7 insertions(+), 30 deletions(-) diff --git a/packaging/msi/UltiMaker-Cura.wxs.jinja b/packaging/msi/UltiMaker-Cura.wxs.jinja index 3dcb9ef2ee..21f017c813 100644 --- a/packaging/msi/UltiMaker-Cura.wxs.jinja +++ b/packaging/msi/UltiMaker-Cura.wxs.jinja @@ -160,31 +160,7 @@ - - - - - - - - - - - - - - - - - - - - - 127.0.0.1 - - - - + @@ -193,14 +169,15 @@ - + - - - - + + + + + From 41efdbabe0faf7bd70fe2d759db19be3e6033414 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Wed, 20 Dec 2023 18:16:04 +0100 Subject: [PATCH 32/73] Path change possible by user - simulation speed increased - no buffering in between layers - fps made 30 CURA-7647 --- plugins/SimulationView/SimulationView.py | 43 +++++++++++-------- .../SimulationViewMainComponent.qml | 3 +- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index 64ec0dfc1b..2663993f55 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -1,6 +1,6 @@ # Copyright (c) 2021 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. - +import math import sys from PyQt6.QtCore import Qt @@ -58,6 +58,7 @@ class SimulationView(CuraView): LAYER_VIEW_TYPE_LINE_TYPE = 1 LAYER_VIEW_TYPE_FEEDRATE = 2 LAYER_VIEW_TYPE_THICKNESS = 3 + SIMULATION_FACTOR = 5 _no_layers_warning_preference = "view/no_layers_warning" @@ -97,6 +98,7 @@ class SimulationView(CuraView): self._min_line_width = sys.float_info.max self._min_flow_rate = sys.float_info.max self._max_flow_rate = sys.float_info.min + self._cumulative_line_duration ={} self._global_container_stack: Optional[ContainerStack] = None self._proxy = None @@ -196,21 +198,21 @@ class SimulationView(CuraView): left_i = 0 right_i = self._max_paths - 1 - total_duration, cumulative_line_duration = self.cumulativeLineDuration() + total_duration = self.cumulativeLineDuration() # make an educated guess about where to start i = int(right_i * max(0.0, min(1.0, self._current_time / total_duration))) # binary search for the correct path while left_i < right_i: - if cumulative_line_duration[i] <= self._current_time: + if self._cumulative_line_duration[self.getCurrentLayer()][i] <= self._current_time: left_i = i + 1 else: right_i = i i = int((left_i + right_i) / 2) - left_value = cumulative_line_duration[i - 1] if i > 0 else 0.0 - right_value = cumulative_line_duration[i] + left_value = self._cumulative_line_duration[self.getCurrentLayer()][i - 1] if i > 0 else 0.0 + right_value = self._cumulative_line_duration[self.getCurrentLayer()][i] assert (left_value <= self._current_time <= right_value) @@ -225,10 +227,7 @@ class SimulationView(CuraView): :param time_increase: The amount of time to advance (in seconds). :return: True if the time was advanced, False if the end of the simulation was reached. """ - total_duration, cumulative_line_duration = self.cumulativeLineDuration() - - # time ratio - time_increase = time_increase + total_duration = self.cumulativeLineDuration() if self._current_time + time_increase > total_duration: # If we have reached the end of the simulation, go to the next layer. @@ -244,15 +243,20 @@ class SimulationView(CuraView): self.setTime(self._current_time + time_increase) return True - def cumulativeLineDuration(self) -> Tuple[float, List[float]]: - # TODO: cache the total duration and cumulative line duration at each layer change event - cumulative_line_duration = [] - total_duration = 0.0 - for polyline in self.getLayerData().polygons: - for line_duration in list((polyline.lineLengths / polyline.lineFeedrates)[0]): - total_duration += line_duration - cumulative_line_duration.append(total_duration) - return total_duration, cumulative_line_duration + def cumulativeLineDuration(self) -> float: + # Make sure _cumulative_line_duration is initialized properly + if self.getCurrentLayer() not in self._cumulative_line_duration: + self._cumulative_line_duration[self.getCurrentLayer()] = [] + total_duration = 0.0 + for polyline in self.getLayerData().polygons: + for line_duration in list((polyline.lineLengths / polyline.lineFeedrates)[0]): + total_duration += line_duration / SimulationView.SIMULATION_FACTOR + self._cumulative_line_duration[self.getCurrentLayer()].append(total_duration) + + # Calculate the total duration using numpy.sum + total_duration = (self._cumulative_line_duration[self.getCurrentLayer()][-1]) + + return total_duration def getLayerData(self) -> Optional["LayerData"]: scene = self.getController().getScene() @@ -360,6 +364,9 @@ class SimulationView(CuraView): if self._current_path_num != value: self._current_path_num = min(max(value, 0), self._max_paths) self._minimum_path_num = min(self._minimum_path_num, self._current_path_num) + # update _current time when the path is changed by user + if self.getCurrentLayer() in self._cumulative_line_duration and self._current_path_num < self._max_paths and round(self._current_path_num)== self._current_path_num: + self._current_time = self._cumulative_line_duration[self.getCurrentLayer()][int(self._current_path_num)] self._startUpdateTopLayers() self.currentPathNumChanged.emit() diff --git a/plugins/SimulationView/SimulationViewMainComponent.qml b/plugins/SimulationView/SimulationViewMainComponent.qml index 23cbf8c611..0432cfc08d 100644 --- a/plugins/SimulationView/SimulationViewMainComponent.qml +++ b/plugins/SimulationView/SimulationViewMainComponent.qml @@ -127,6 +127,7 @@ Item function resumeSimulation() { UM.SimulationView.setSimulationRunning(true) + UM.SimulationView.setCurrentPath(UM.SimulationView.currentPath) simulationTimer.start() layerSlider.manuallyChanged = false pathSlider.manuallyChanged = false @@ -136,7 +137,7 @@ Item Timer { id: simulationTimer - interval: 1000 / 60 + interval: 1000 / 30 running: false repeat: true onTriggered: From e2e94b7f6b9252ad64641793ef9a4d283cff5bcb Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Thu, 21 Dec 2023 10:32:49 +0100 Subject: [PATCH 33/73] fps made 15 for lower GPU load - reinitialisation of cummulative_time for new model CURA-7647 --- plugins/SimulationView/SimulationView.py | 5 +++-- plugins/SimulationView/SimulationViewMainComponent.qml | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index 2663993f55..bce7062a36 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -98,7 +98,7 @@ class SimulationView(CuraView): self._min_line_width = sys.float_info.max self._min_flow_rate = sys.float_info.max self._max_flow_rate = sys.float_info.min - self._cumulative_line_duration ={} + self._cumulative_line_duration = {} self._global_container_stack: Optional[ContainerStack] = None self._proxy = None @@ -253,7 +253,7 @@ class SimulationView(CuraView): total_duration += line_duration / SimulationView.SIMULATION_FACTOR self._cumulative_line_duration[self.getCurrentLayer()].append(total_duration) - # Calculate the total duration using numpy.sum + # total duration for a layer to simulate is the last element of the list total_duration = (self._cumulative_line_duration[self.getCurrentLayer()][-1]) return total_duration @@ -572,6 +572,7 @@ class SimulationView(CuraView): self._max_thickness = sys.float_info.min self._min_flow_rate = sys.float_info.max self._max_flow_rate = sys.float_info.min + self._cumulative_line_duration = {} # The colour scheme is only influenced by the visible lines, so filter the lines by if they should be visible. visible_line_types = [] diff --git a/plugins/SimulationView/SimulationViewMainComponent.qml b/plugins/SimulationView/SimulationViewMainComponent.qml index 0432cfc08d..d9e7a95bc1 100644 --- a/plugins/SimulationView/SimulationViewMainComponent.qml +++ b/plugins/SimulationView/SimulationViewMainComponent.qml @@ -137,12 +137,12 @@ Item Timer { id: simulationTimer - interval: 1000 / 30 + interval: 1000 / 15 running: false repeat: true onTriggered: { - // divide by 1000 to accont for ms to s conversion + // divide by 1000 to account for ms to s conversion const advance_time = simulationTimer.interval / 1000.0; if (!UM.SimulationView.advanceTime(advance_time)) { playButton.pauseSimulation(); From 3f8908f53a8207d2d75cab89618d22436df31ccd Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Thu, 21 Dec 2023 10:42:52 +0100 Subject: [PATCH 34/73] cleanup CURA-7647 --- plugins/SimulationView/SimulationView.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index bce7062a36..070a5c0345 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -1,6 +1,5 @@ # Copyright (c) 2021 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -import math import sys from PyQt6.QtCore import Qt @@ -40,7 +39,7 @@ from .SimulationViewProxy import SimulationViewProxy import numpy import os.path -from typing import Optional, TYPE_CHECKING, List, Tuple, cast +from typing import Optional, TYPE_CHECKING, List, cast if TYPE_CHECKING: from UM.Scene.SceneNode import SceneNode From 0de4f612b399cfe8b7a6c8059e9579489bcd739c Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Thu, 21 Dec 2023 14:13:16 +0100 Subject: [PATCH 35/73] fixing review comments. Cache only for the current layer CURA-7647 --- plugins/SimulationView/SimulationView.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index 070a5c0345..1043c7659a 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -197,21 +197,22 @@ class SimulationView(CuraView): left_i = 0 right_i = self._max_paths - 1 - total_duration = self.cumulativeLineDuration() + cumulative_line_duration = self.cumulativeLineDuration() + total_duration = cumulative_line_duration[-1] # make an educated guess about where to start i = int(right_i * max(0.0, min(1.0, self._current_time / total_duration))) # binary search for the correct path while left_i < right_i: - if self._cumulative_line_duration[self.getCurrentLayer()][i] <= self._current_time: + if cumulative_line_duration[i] <= self._current_time: left_i = i + 1 else: right_i = i i = int((left_i + right_i) / 2) - left_value = self._cumulative_line_duration[self.getCurrentLayer()][i - 1] if i > 0 else 0.0 - right_value = self._cumulative_line_duration[self.getCurrentLayer()][i] + left_value = cumulative_line_duration[i - 1] if i > 0 else 0.0 + right_value = cumulative_line_duration[i] assert (left_value <= self._current_time <= right_value) @@ -226,7 +227,7 @@ class SimulationView(CuraView): :param time_increase: The amount of time to advance (in seconds). :return: True if the time was advanced, False if the end of the simulation was reached. """ - total_duration = self.cumulativeLineDuration() + total_duration = self.cumulativeLineDuration()[-1] if self._current_time + time_increase > total_duration: # If we have reached the end of the simulation, go to the next layer. @@ -242,9 +243,11 @@ class SimulationView(CuraView): self.setTime(self._current_time + time_increase) return True - def cumulativeLineDuration(self) -> float: + def cumulativeLineDuration(self) -> list: # Make sure _cumulative_line_duration is initialized properly if self.getCurrentLayer() not in self._cumulative_line_duration: + #clear cache + self._cumulative_line_duration = {} self._cumulative_line_duration[self.getCurrentLayer()] = [] total_duration = 0.0 for polyline in self.getLayerData().polygons: @@ -252,10 +255,7 @@ class SimulationView(CuraView): total_duration += line_duration / SimulationView.SIMULATION_FACTOR self._cumulative_line_duration[self.getCurrentLayer()].append(total_duration) - # total duration for a layer to simulate is the last element of the list - total_duration = (self._cumulative_line_duration[self.getCurrentLayer()][-1]) - - return total_duration + return self._cumulative_line_duration[self.getCurrentLayer()] def getLayerData(self) -> Optional["LayerData"]: scene = self.getController().getScene() @@ -364,8 +364,8 @@ class SimulationView(CuraView): self._current_path_num = min(max(value, 0), self._max_paths) self._minimum_path_num = min(self._minimum_path_num, self._current_path_num) # update _current time when the path is changed by user - if self.getCurrentLayer() in self._cumulative_line_duration and self._current_path_num < self._max_paths and round(self._current_path_num)== self._current_path_num: - self._current_time = self._cumulative_line_duration[self.getCurrentLayer()][int(self._current_path_num)] + if self._current_path_num < self._max_paths and round(self._current_path_num)== self._current_path_num: + self._current_time = self.cumulativeLineDuration()[int(self._current_path_num)] self._startUpdateTopLayers() self.currentPathNumChanged.emit() From 152cb27232310a35b3e71a70b438253a95c760f5 Mon Sep 17 00:00:00 2001 From: Saumya Jain <70144862+saumyaj3@users.noreply.github.com> Date: Thu, 21 Dec 2023 14:30:43 +0100 Subject: [PATCH 36/73] Update plugins/SimulationView/SimulationView.py review fix Co-authored-by: Casper Lamboo --- plugins/SimulationView/SimulationView.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index 1043c7659a..04fc383fbb 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -243,7 +243,7 @@ class SimulationView(CuraView): self.setTime(self._current_time + time_increase) return True - def cumulativeLineDuration(self) -> list: + def cumulativeLineDuration(self) -> List[float]: # Make sure _cumulative_line_duration is initialized properly if self.getCurrentLayer() not in self._cumulative_line_duration: #clear cache From 608c2344c5d8b44e318d14a1284eb6204b194154 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Thu, 21 Dec 2023 16:25:12 +0100 Subject: [PATCH 37/73] on_error takes multiple args CURA-11289 --- cura/CuraApplication.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 52f38d4685..fd4b0c858c 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -1837,7 +1837,7 @@ class CuraApplication(QtApplication): self.readLocalFile(QUrl.fromLocalFile(tmp.name), add_to_recent_files=False) - def on_error(): + def on_error(*args, **kwargs): Logger.log("w", "Could not download file from {0}".format(model_url.url())) return From a309c9efdb5e3520de880fec40a89835d87f14dd Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Thu, 21 Dec 2023 17:26:11 +0100 Subject: [PATCH 38/73] Error is displayed on Cura screen CURA-11289 --- cura/CuraApplication.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index fd4b0c858c..1ef2f63a9e 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -1839,6 +1839,9 @@ class CuraApplication(QtApplication): def on_error(*args, **kwargs): Logger.log("w", "Could not download file from {0}".format(model_url.url())) + Message("Could not download file: " + str(model_url.url()), + title= "Loading Model failed", + message_type=Message.MessageType.ERROR).show() return self.getHttpRequestManager().get( From 411b40d78c39923723ad31709d04f5558c7d1728 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Fri, 22 Dec 2023 10:37:51 +0100 Subject: [PATCH 39/73] Simulation speed made 3X case where no polygon in layer is also addressed CURA-11289 --- plugins/SimulationView/SimulationView.py | 57 ++++++++++++------------ 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index 04fc383fbb..337879475b 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -57,7 +57,7 @@ class SimulationView(CuraView): LAYER_VIEW_TYPE_LINE_TYPE = 1 LAYER_VIEW_TYPE_FEEDRATE = 2 LAYER_VIEW_TYPE_THICKNESS = 3 - SIMULATION_FACTOR = 5 + SIMULATION_FACTOR = 3 _no_layers_warning_preference = "view/no_layers_warning" @@ -192,33 +192,30 @@ class SimulationView(CuraView): return self._current_path_num def setTime(self, time: float) -> None: - self._current_time = time - - left_i = 0 - right_i = self._max_paths - 1 - cumulative_line_duration = self.cumulativeLineDuration() - total_duration = cumulative_line_duration[-1] + if len(cumulative_line_duration) > 0: + self._current_time = time + left_i = 0 + right_i = self._max_paths - 1 + total_duration = cumulative_line_duration[-1] + # make an educated guess about where to start + i = int(right_i * max(0.0, min(1.0, self._current_time / total_duration))) + # binary search for the correct path + while left_i < right_i: + if cumulative_line_duration[i] <= self._current_time: + left_i = i + 1 + else: + right_i = i + i = int((left_i + right_i) / 2) - # make an educated guess about where to start - i = int(right_i * max(0.0, min(1.0, self._current_time / total_duration))) + left_value = cumulative_line_duration[i - 1] if i > 0 else 0.0 + right_value = cumulative_line_duration[i] - # binary search for the correct path - while left_i < right_i: - if cumulative_line_duration[i] <= self._current_time: - left_i = i + 1 - else: - right_i = i - i = int((left_i + right_i) / 2) + assert (left_value <= self._current_time <= right_value) - left_value = cumulative_line_duration[i - 1] if i > 0 else 0.0 - right_value = cumulative_line_duration[i] + fractional_value = (self._current_time - left_value) / (right_value - left_value) - assert (left_value <= self._current_time <= right_value) - - fractional_value = (self._current_time - left_value) / (right_value - left_value) - - self.setPath(i + fractional_value) + self.setPath(i + fractional_value) def advanceTime(self, time_increase: float) -> bool: """ @@ -227,7 +224,9 @@ class SimulationView(CuraView): :param time_increase: The amount of time to advance (in seconds). :return: True if the time was advanced, False if the end of the simulation was reached. """ - total_duration = self.cumulativeLineDuration()[-1] + total_duration = 0.0 + if len(self.cumulativeLineDuration()) > 0: + total_duration = self.cumulativeLineDuration()[-1] if self._current_time + time_increase > total_duration: # If we have reached the end of the simulation, go to the next layer. @@ -250,10 +249,12 @@ class SimulationView(CuraView): self._cumulative_line_duration = {} self._cumulative_line_duration[self.getCurrentLayer()] = [] total_duration = 0.0 - for polyline in self.getLayerData().polygons: - for line_duration in list((polyline.lineLengths / polyline.lineFeedrates)[0]): - total_duration += line_duration / SimulationView.SIMULATION_FACTOR - self._cumulative_line_duration[self.getCurrentLayer()].append(total_duration) + polylines = self.getLayerData() + if polylines is not None: + for polyline in polylines.polygons: + for line_duration in list((polyline.lineLengths / polyline.lineFeedrates)[0]): + total_duration += line_duration / SimulationView.SIMULATION_FACTOR + self._cumulative_line_duration[self.getCurrentLayer()].append(total_duration) return self._cumulative_line_duration[self.getCurrentLayer()] From 224f6132286e0e2aec6386545cfb6921f58afcab Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Fri, 22 Dec 2023 11:36:51 +0100 Subject: [PATCH 40/73] Property of machinemanager redefined CURA-11459 --- resources/qml/PrinterSelector/MachineSelector.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/qml/PrinterSelector/MachineSelector.qml b/resources/qml/PrinterSelector/MachineSelector.qml index b8b27049f6..1bad1d70bc 100644 --- a/resources/qml/PrinterSelector/MachineSelector.qml +++ b/resources/qml/PrinterSelector/MachineSelector.qml @@ -11,7 +11,7 @@ Cura.ExpandablePopup { id: machineSelector - property Cura.MachineManager machineManager + property var machineManager: Cura.MachineManager property bool isNetworkPrinter: machineManager.activeMachineHasNetworkConnection property bool isConnectedCloudPrinter: machineManager.activeMachineHasCloudConnection property bool isCloudRegistered: machineManager.activeMachineHasCloudRegistration @@ -107,6 +107,7 @@ Cura.ExpandablePopup { return UM.Theme.getIcon("Printer", "medium") } + else { return "" From 7fab301866b63d90ffb72603fdd3aa30a505cdec Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Fri, 22 Dec 2023 18:02:23 +0100 Subject: [PATCH 41/73] Guard against index out of bound CURA-7647 --- plugins/SimulationView/SimulationPass.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/SimulationView/SimulationPass.py b/plugins/SimulationView/SimulationPass.py index 3294f4b1e6..e97a0cd32c 100644 --- a/plugins/SimulationView/SimulationPass.py +++ b/plugins/SimulationView/SimulationPass.py @@ -160,14 +160,14 @@ class SimulationPass(RenderPass): ratio = self._layer_view.getCurrentPath() - index pos_a = Vector(polygon.data[index + offset][0], polygon.data[index + offset][1], polygon.data[index + offset][2]) - if ratio > 0.0001: + if ratio <= 0.0001 or index + offset == len(polygon.data): + head_position = pos_a + node.getWorldPosition() + else: pos_b = Vector(polygon.data[index + offset + 1][0], polygon.data[index + offset + 1][1], polygon.data[index + offset + 1][2]) vec = pos_a * (1.0 - ratio) + pos_b * ratio head_position = vec + node.getWorldPosition() - else: - head_position = pos_a + node.getWorldPosition() break break if self._layer_view.getMinimumLayer() > layer: From 632c10db51908445c41a3cd12bd2532c0df0211e Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Wed, 27 Dec 2023 10:12:40 +0100 Subject: [PATCH 42/73] Guard against index for edge case CURA-7647 --- plugins/SimulationView/SimulationPass.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/SimulationView/SimulationPass.py b/plugins/SimulationView/SimulationPass.py index e97a0cd32c..dd94d678ae 100644 --- a/plugins/SimulationView/SimulationPass.py +++ b/plugins/SimulationView/SimulationPass.py @@ -160,7 +160,7 @@ class SimulationPass(RenderPass): ratio = self._layer_view.getCurrentPath() - index pos_a = Vector(polygon.data[index + offset][0], polygon.data[index + offset][1], polygon.data[index + offset][2]) - if ratio <= 0.0001 or index + offset == len(polygon.data): + if ratio <= 0.0001 or index + offset < len(polygon.data): head_position = pos_a + node.getWorldPosition() else: pos_b = Vector(polygon.data[index + offset + 1][0], From e66314b2dd35bb6f87f1f3804a38311e5fc535f4 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Tue, 2 Jan 2024 10:48:40 +0100 Subject: [PATCH 43/73] ppr setting was added when it should be excluded CURA-11480 --- resources/qml/Preferences/SettingVisibilityPage.qml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/qml/Preferences/SettingVisibilityPage.qml b/resources/qml/Preferences/SettingVisibilityPage.qml index 476ba999cf..8743999fe2 100644 --- a/resources/qml/Preferences/SettingVisibilityPage.qml +++ b/resources/qml/Preferences/SettingVisibilityPage.qml @@ -123,7 +123,7 @@ UM.PreferencesPage var idx = -1; for(var i = 0; i < settingVisibilityPresetsModel.items.length; ++i) { - if(settingVisibilityPresetsModel.items[i].presetId == settingVisibilityPresetsModel.activePreset) + if(settingVisibilityPresetsModel.items[i].presetId === settingVisibilityPresetsModel.activePreset) { idx = i; break; @@ -159,7 +159,7 @@ UM.PreferencesPage id: definitionsModel containerId: Cura.MachineManager.activeMachine != null ? Cura.MachineManager.activeMachine.definition.id: "" showAll: true - exclude: ["machine_settings", "command_line_settings"] + exclude: ["machine_settings", "command_line_settings", "ppr"] showAncestors: true expanded: ["*"] visibilityHandler: UM.SettingPreferenceVisibilityHandler {} @@ -173,13 +173,13 @@ UM.PreferencesPage id: loader width: settingsListView.width - scrollBar.width - height: model.type != undefined ? UM.Theme.getSize("section").height : 0 + height: model.type !== undefined ? UM.Theme.getSize("section").height : 0 property var definition: model property var settingDefinitionsModel: definitionsModel asynchronous: true - active: model.type != undefined + active: model.type !== undefined sourceComponent: { switch (model.type) From 0bb1f0b7c3ff87edbecca432e017c6423ad03eed Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Tue, 2 Jan 2024 12:05:55 +0100 Subject: [PATCH 44/73] Case of simulation with multiple extruders CURA-7647 --- plugins/SimulationView/SimulationPass.py | 22 +++++++++++----------- plugins/SimulationView/SimulationView.py | 7 +++++-- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/plugins/SimulationView/SimulationPass.py b/plugins/SimulationView/SimulationPass.py index dd94d678ae..cdeb9da29f 100644 --- a/plugins/SimulationView/SimulationPass.py +++ b/plugins/SimulationView/SimulationPass.py @@ -1,5 +1,6 @@ # Copyright (c) 2021 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +import math from UM.Math.Color import Color from UM.Math.Vector import Vector @@ -148,24 +149,23 @@ class SimulationPass(RenderPass): if layer == self._layer_view._current_layer_num: # We look for the position of the head, searching the point of the current path index = int(self._layer_view.getCurrentPath()) - offset = 0 for polygon in layer_data.getLayer(layer).polygons: # The size indicates all values in the two-dimension array, and the second dimension is # always size 3 because we have 3D points. - if index >= polygon.data.size // 3 - offset: - index -= polygon.data.size // 3 - offset - offset = 1 # This is to avoid the first point when there is more than one polygon, since has the same value as the last point in the previous polygon + if index >= polygon.data.size // 3 : + index -= polygon.data.size // 3 continue # The head position is calculated and translated - ratio = self._layer_view.getCurrentPath() - index - pos_a = Vector(polygon.data[index + offset][0], polygon.data[index + offset][1], - polygon.data[index + offset][2]) - if ratio <= 0.0001 or index + offset < len(polygon.data): + ratio = self._layer_view.getCurrentPath() - math.floor(self._layer_view.getCurrentPath()) + pos_a = Vector(polygon.data[index][0], polygon.data[index + offset][1], + polygon.data[index][2]) + if ratio <= 0.0001 or index + 1 == len(polygon.data): + # in case there multiple polygons and polygon changes, the first point has the same value as the last point in the previous polygon head_position = pos_a + node.getWorldPosition() else: - pos_b = Vector(polygon.data[index + offset + 1][0], - polygon.data[index + offset + 1][1], - polygon.data[index + offset + 1][2]) + pos_b = Vector(polygon.data[index + 1][0], + polygon.data[index + 1][1], + polygon.data[index + 1][2]) vec = pos_a * (1.0 - ratio) + pos_b * ratio head_position = vec + node.getWorldPosition() break diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index 337879475b..92a6a9e853 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -57,7 +57,7 @@ class SimulationView(CuraView): LAYER_VIEW_TYPE_LINE_TYPE = 1 LAYER_VIEW_TYPE_FEEDRATE = 2 LAYER_VIEW_TYPE_THICKNESS = 3 - SIMULATION_FACTOR = 3 + SIMULATION_FACTOR = 2 _no_layers_warning_preference = "view/no_layers_warning" @@ -211,7 +211,8 @@ class SimulationView(CuraView): left_value = cumulative_line_duration[i - 1] if i > 0 else 0.0 right_value = cumulative_line_duration[i] - assert (left_value <= self._current_time <= right_value) + if not (left_value <= self._current_time <= right_value): + Logger.debug(f"At index {i}: left value {left_value} right value {right_value} and current time is {self._current_time}") fractional_value = (self._current_time - left_value) / (right_value - left_value) @@ -255,6 +256,8 @@ class SimulationView(CuraView): for line_duration in list((polyline.lineLengths / polyline.lineFeedrates)[0]): total_duration += line_duration / SimulationView.SIMULATION_FACTOR self._cumulative_line_duration[self.getCurrentLayer()].append(total_duration) + # for tool change we add an extra tool path + self._cumulative_line_duration[self.getCurrentLayer()].append(total_duration) return self._cumulative_line_duration[self.getCurrentLayer()] From ee7ecc1acc76f8d5504251dba9b4627bbb3b5ca5 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Wed, 3 Jan 2024 09:16:04 +0100 Subject: [PATCH 45/73] offset removed CURA-7647 --- plugins/SimulationView/SimulationPass.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/SimulationView/SimulationPass.py b/plugins/SimulationView/SimulationPass.py index cdeb9da29f..2099f6c21d 100644 --- a/plugins/SimulationView/SimulationPass.py +++ b/plugins/SimulationView/SimulationPass.py @@ -157,7 +157,7 @@ class SimulationPass(RenderPass): continue # The head position is calculated and translated ratio = self._layer_view.getCurrentPath() - math.floor(self._layer_view.getCurrentPath()) - pos_a = Vector(polygon.data[index][0], polygon.data[index + offset][1], + pos_a = Vector(polygon.data[index][0], polygon.data[index][1], polygon.data[index][2]) if ratio <= 0.0001 or index + 1 == len(polygon.data): # in case there multiple polygons and polygon changes, the first point has the same value as the last point in the previous polygon From 1e230ffef1962faeae7068caf4ad3f91f6a35b06 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Wed, 3 Jan 2024 14:19:22 +0100 Subject: [PATCH 46/73] Printer name changed to printer type printer names can be different for same type of printer. Also, printer type is coming from cloud here so the type search is changed accordingly CURA-11432 --- plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDevice.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDevice.py b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDevice.py index 9a11bb886c..b2541f6f82 100644 --- a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDevice.py +++ b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDevice.py @@ -331,7 +331,7 @@ class CloudOutputDevice(UltimakerNetworkedPrinterOutputDevice): return False [printer, *_] = self._printers - return printer.name in ("ultimaker_methodx", "ultimaker_methodxl") + return printer.type in ("MakerBot Method X", "MakerBot Method XL") @pyqtProperty(bool, notify=_cloudClusterPrintersChanged) def supportsPrintJobActions(self) -> bool: From 2e197f72ee3b5abfd18941fa1969d31e5ae3dcc0 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Wed, 3 Jan 2024 17:37:54 +0100 Subject: [PATCH 47/73] Add missing `default_value` for `roofing_monotonic --- resources/definitions/fdmprinter.def.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 62143cf8f8..2a35a5faab 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -1478,6 +1478,7 @@ "description": "Print top surface lines in an ordering that causes them to always overlap with adjacent lines in a single direction. This takes slightly more time to print, but makes flat surfaces look more consistent.", "type": "bool", "value": true, + "default_value": true, "enabled": "roofing_layer_count > 0 and top_layers > 0 and roofing_pattern != 'concentric'", "limit_to_extruder": "roofing_extruder_nr", "settable_per_mesh": true @@ -8438,4 +8439,4 @@ } } } -} \ No newline at end of file +} From 4a8e00fcc6b43f04ca87a08abe8ce2a6e7739ed8 Mon Sep 17 00:00:00 2001 From: jellespijker Date: Wed, 3 Jan 2024 16:38:51 +0000 Subject: [PATCH 48/73] Applied printer-linter format --- resources/definitions/fdmprinter.def.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 2a35a5faab..7796b04751 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -8439,4 +8439,4 @@ } } } -} +} \ No newline at end of file From 7d040a0b026c2d77ea7e9733fef334c6eccef062 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Wed, 3 Jan 2024 18:03:37 +0100 Subject: [PATCH 49/73] Fixed multiple `default_value` definitions default_value should be an actual value --- resources/definitions/fdmprinter.def.json | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 7796b04751..cf2b7a57af 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -4579,6 +4579,7 @@ "unit": "\u00b0C", "type": "float", "value": "material_print_temperature", + "default_value": 0, "enabled": "cool_min_layer_time > 0", "minimum_value_warning": "max(material_final_print_temperature, material_initial_print_temperature)", "maximum_value_warning": "material_print_temperature", @@ -6690,7 +6691,7 @@ "type": "float", "unit": "mm", "enabled": "resolveOrValue('prime_tower_enable') and (resolveOrValue('prime_tower_brim_enable') or resolveOrValue('adhesion_type') == 'raft')", - "default_value": "resolveOrValue('brim_width')", + "default_value": 1.2, "minimum_value": "0", "maximum_value": "min(0.5 * machine_width, 0.5 * machine_depth)", "settable_per_mesh": false, @@ -8330,7 +8331,7 @@ { "label": "Flow Warning", "description": "Limit on the flow warning for detection.", - "default_value": "15.0", + "default_value": 15.0, "enabled": "ppr_enable", "unit": "%", "type": "float", @@ -8340,7 +8341,7 @@ { "label": "Flow Limit", "description": "Limit on flow anomaly for detection.", - "default_value": "25.0", + "default_value": 25.0, "enabled": "ppr_enable", "unit": "%", "type": "float", @@ -8352,7 +8353,7 @@ "description": "Limit on Print temperature warning for detection.", "unit": "\u00b0C", "type": "float", - "default_value": "3.0", + "default_value": 3.0, "enabled": "ppr_enable", "settable_per_extruder": true }, @@ -8362,7 +8363,7 @@ "description": "Limit on Print Temperature anomaly for detection.", "unit": "\u00b0C", "type": "float", - "default_value": "7.0", + "default_value": 7.0, "enabled": "ppr_enable", "settable_per_extruder": true }, @@ -8372,7 +8373,7 @@ "description": "Limit on Build Volume Temperature warning for detection.", "unit": "\u00b0C", "type": "float", - "default_value": "7.5", + "default_value": 7.5, "enabled": "ppr_enable", "settable_per_extruder": false }, @@ -8382,7 +8383,7 @@ "description": "Limit on Build Volume temperature Anomaly for detection.", "unit": "\u00b0C", "type": "float", - "default_value": "10.0", + "default_value": 10.0, "enabled": "ppr_enable", "settable_per_extruder": false } From da4f675008a61ff1602e74ed14838cc41ad5d9b3 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Sat, 6 Jan 2024 16:39:04 +0100 Subject: [PATCH 50/73] Optimize wall printing order CURA-11507 --- resources/definitions/fdmprinter.def.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index cf2b7a57af..2b37b3d7ac 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -1159,7 +1159,7 @@ "label": "Optimize Wall Printing Order", "description": "Optimize the order in which walls are printed so as to reduce the number of retractions and the distance travelled. Most parts will benefit from this being enabled but some may actually take longer so please compare the print time estimates with and without optimization. First layer is not optimized when choosing brim as build plate adhesion type.", "type": "bool", - "default_value": false, + "default_value": true, "settable_per_mesh": true }, "inset_direction": From 18302d6213788ad49438876833b650ad40546895 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Sun, 7 Jan 2024 11:10:22 +0100 Subject: [PATCH 51/73] attempt to fix binary search --- plugins/SimulationView/SimulationView.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index 92a6a9e853..c070c69939 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -97,7 +97,8 @@ class SimulationView(CuraView): self._min_line_width = sys.float_info.max self._min_flow_rate = sys.float_info.max self._max_flow_rate = sys.float_info.min - self._cumulative_line_duration = {} + self._cumulative_line_duration_layer: Optional[int] = None + self._cumulative_line_duration: List[float] = [] self._global_container_stack: Optional[ContainerStack] = None self._proxy = None @@ -196,7 +197,7 @@ class SimulationView(CuraView): if len(cumulative_line_duration) > 0: self._current_time = time left_i = 0 - right_i = self._max_paths - 1 + right_i = len(cumulative_line_duration) - 1 total_duration = cumulative_line_duration[-1] # make an educated guess about where to start i = int(right_i * max(0.0, min(1.0, self._current_time / total_duration))) @@ -212,7 +213,8 @@ class SimulationView(CuraView): right_value = cumulative_line_duration[i] if not (left_value <= self._current_time <= right_value): - Logger.debug(f"At index {i}: left value {left_value} right value {right_value} and current time is {self._current_time}") + Logger.warn( + f"Binary search error (out of bounds): index {i}: left value {left_value} right value {right_value} and current time is {self._current_time}") fractional_value = (self._current_time - left_value) / (right_value - left_value) @@ -245,21 +247,22 @@ class SimulationView(CuraView): def cumulativeLineDuration(self) -> List[float]: # Make sure _cumulative_line_duration is initialized properly - if self.getCurrentLayer() not in self._cumulative_line_duration: + if self.getCurrentLayer() != self._cumulative_line_duration_layer: #clear cache - self._cumulative_line_duration = {} - self._cumulative_line_duration[self.getCurrentLayer()] = [] + self._cumulative_line_duration = [] total_duration = 0.0 polylines = self.getLayerData() if polylines is not None: for polyline in polylines.polygons: for line_duration in list((polyline.lineLengths / polyline.lineFeedrates)[0]): total_duration += line_duration / SimulationView.SIMULATION_FACTOR - self._cumulative_line_duration[self.getCurrentLayer()].append(total_duration) + self._cumulative_line_duration.append(total_duration) # for tool change we add an extra tool path - self._cumulative_line_duration[self.getCurrentLayer()].append(total_duration) + self._cumulative_line_duration.append(total_duration) + # set current cached layer + self._cumulative_line_duration_layer = self.getCurrentLayer() - return self._cumulative_line_duration[self.getCurrentLayer()] + return self._cumulative_line_duration def getLayerData(self) -> Optional["LayerData"]: scene = self.getController().getScene() From 1a5370d2efd67ef7a5dc5eace7da94152f7946e9 Mon Sep 17 00:00:00 2001 From: GregValiant <64202104+GregValiant@users.noreply.github.com> Date: Sun, 7 Jan 2024 12:41:59 +0100 Subject: [PATCH 52/73] Add 'Advanced Cooling Fan Control' post-processing script. See discussions in #15853 (on github) and (internally) tracking-ticket CURA-11520 --- .../scripts/AddCoolingProfile.py | 879 ++++++++++++++++++ 1 file changed, 879 insertions(+) create mode 100644 plugins/PostProcessingPlugin/scripts/AddCoolingProfile.py diff --git a/plugins/PostProcessingPlugin/scripts/AddCoolingProfile.py b/plugins/PostProcessingPlugin/scripts/AddCoolingProfile.py new file mode 100644 index 0000000000..6f9ac2dc13 --- /dev/null +++ b/plugins/PostProcessingPlugin/scripts/AddCoolingProfile.py @@ -0,0 +1,879 @@ +# January 2023 by GregValiant (Greg Foresi). +# Functions: +# Remove all fan speed lines from the file (optional). +# Enter new M106 lines "By Layer" or "By Feature" (;TYPE:WALL-OUTER, etc.). +# A Starting layer and/or an Ending layer can be defined. +# Fan speeds are scaled PWM (0 - 255) or RepRap (0 - 1) depending on {machine_scale_fan_speed_zero_to_one}. +# A minimum fan speed of 12% is enforced. +# If multiple extruders have separate fan circuits the speeds are set at tool changes and conform to the layer or +# feature setting. There is support for up to 4 layer cooling fan circuits. +# The option for whether or not to remove the existing M106 lines is added to allow multiple instances of this post-processor to be installed without the followup instances wiping out the insertions of previous instances. 1/3 of a file can be 'By Layer' and the second third 'By Feature', and end up with 'By Layer' again. +# My design intent was to make it as full featured and "industrial strength" as I could. +# My thanks to @5axes, @fieldOfView(@AHoeben), @Ghostkeeper, and @Torgeir. +# 9/14/23 added support for One-at-a-Time and removed the kick out code +# 12/15/23 split off some functions. Revised the regex replacements. + +from ..Script import Script +from UM.Application import Application +import re + +class AddCoolingProfile(Script): + + def getSettingDataString(self): + return """{ + "name": "Advanced Cooling Fan Control", + "key": "AddCoolingProfile", + "metadata": {}, + "version": 2, + "settings": + { + "fan_layer_or_feature": + { + "label": "Cooling Control by:", + "description": "A fan percentage of ''0'' turns the fan off. Minimum Fan is 12% (when on). All layer entries are the Cura Preview number. ''By Layer'': Enter as ''Layer#/Fan%'' (foreslash is the delimiter). Your final layer speed will continue to the end of the Gcode. ''By Feature'': If you enable an 'End Layer' then the ''Final %'' is available and is the speed that will finish the file. 'By Feature' is better for large slow prints than it is for short fast prints.", + "type": "enum", + "options": { + "by_layer": "Layer Numbers", + "by_feature": "Feature Types"}, + "default_value": "by_layer" + }, + "delete_existing_m106": + { + "label": "Remove M106 lines prior to inserting new.", + "description": "If you have 2 or more instances of 'Advanced Cooling Fan Control' running (to cool a portion of a print differently), then uncheck this box or the followup instances will remove all the lines inserted by the first instance. Pay attention to the Start and Stop layers. If you want to keep the Cura inserted lines up to the point where this post-processor will start making insertions, then un-check the box.", + "type": "bool", + "enabled": true, + "value": true + }, + "feature_fan_start_layer": + { + "label": "Starting Layer", + "description": "Layer to start the insertion at. Use the Cura preview numbers. Changes will begin at the start of that layer.", + "type": "int", + "default_value": 5, + "minimum_value": 1, + "unit": "Lay# ", + "enabled": "fan_layer_or_feature == 'by_feature'" + }, + "feature_fan_end_layer": + { + "label": "Ending Layer", + "description": "Layer to complete the insertion at. Enter '-1' for the entire file or enter a layer number. Insertions will stop at the END of this layer. If you set an End Layer then you should set the Final % that will finish the file", + "type": "int", + "default_value": -1, + "minimum_value": -1, + "unit": "Lay# ", + "enabled": "fan_layer_or_feature == 'by_feature'" + }, + "layer_fan_1st": + { + "label": "Layer/Percent #1", + "description": "Enter as: 'LAYER / Percent' Ex: 57/100 with the layer first, then a '/' to delimit, and then the fan percentage.", + "type": "str", + "default_value": "5/30", + "unit": "L#/% ", + "enabled": "fan_layer_or_feature == 'by_layer'" + }, + "layer_fan_2nd": + { + "label": "Layer/Percent #2", + "description": "Enter as: 'LAYER / Percent' Ex: 57/100 with the layer first, then a '/' to delimit, and then the fan percentage.", + "type": "str", + "default_value": "", + "unit": "L#/% ", + "enabled": "fan_layer_or_feature == 'by_layer'" + }, + "layer_fan_3rd": + { + "label": "Layer/Percent #3", + "description": "Enter as: 'LAYER / Percent' Ex: 57/100 with the layer first, then a '/' to delimit, and then the fan percentage.", + "type": "str", + "default_value": "", + "unit": "L#/% ", + "enabled": "fan_layer_or_feature == 'by_layer'" + }, + "layer_fan_4th": + { + "label": "Layer/Percent #4", + "description": "Enter as: 'LAYER / Percent' Ex: 57/100 with the layer first, then a '/' to delimit, and then the fan percentage.", + "type": "str", + "default_value": "", + "unit": "L#/% ", + "enabled": "fan_layer_or_feature == 'by_layer'" + }, + "layer_fan_5th": + { + "label": "Layer/Percent #5", + "description": "Enter as: 'LAYER / Percent' Ex: 57/100 with the layer first, then a '/' to delimit, and then the fan percentage.", + "type": "str", + "default_value": "", + "unit": "L#/% ", + "enabled": "fan_layer_or_feature == 'by_layer'" + }, + "layer_fan_6th": + { + "label": "Layer/Percent #6", + "description": "Enter as: 'LAYER / Percent' Ex: 57/100 with the layer first, then a '/' to delimit, and then the fan percentage.", + "type": "str", + "default_value": "", + "unit": "L#/% ", + "enabled": "fan_layer_or_feature == 'by_layer'" + }, + "layer_fan_7th": + { + "label": "Layer/Percent #7", + "description": "Enter as: 'LAYER / Percent' Ex: 57/100 with the layer first, then a '/' to delimit, and then the fan percentage.", + "type": "str", + "default_value": "", + "unit": "L#/% ", + "enabled": "fan_layer_or_feature == 'by_layer'" + }, + "layer_fan_8th": + { + "label": "Layer/Percent #8", + "description": "Enter as: 'LAYER / Percent' Ex: 57/100 with the layer first, then a '/' to delimit, and then the fan percentage.", + "type": "str", + "default_value": "", + "unit": "L#/% ", + "enabled": "fan_layer_or_feature == 'by_layer'" + }, + "feature_fan_skirt": + { + "label": "Skirt/Brim/Ooze Shield %", + "description": "Enter the fan percentage for skirt/brim. If you are starting at a layer above 1 then this setting only affects Ooze Shields and from the Start layer up.", + "type": "int", + "default_value": 0, + "minimum_value": 0, + "maximum_value": 100, + "unit": "% ", + "enabled": "fan_layer_or_feature == 'by_feature'" + }, + "feature_fan_wall_inner": + { + "label": "Inner Walls %", + "description": "Enter the fan percentage for the Wall-Inner.", + "type": "int", + "default_value": 35, + "minimum_value": 0, + "maximum_value": 100, + "unit": "% ", + "enabled": "fan_layer_or_feature == 'by_feature'" + }, + "feature_fan_wall_outer": + { + "label": "Outer Walls %", + "description": "Enter the fan percentage for the Wall-Outer.", + "type": "int", + "default_value": 75, + "minimum_value": 0, + "maximum_value": 100, + "unit": "% ", + "enabled": "fan_layer_or_feature == 'by_feature'" + }, + "feature_fan_fill": + { + "label": "Infill %", + "description": "Enter the fan percentage for the Infill.", + "type": "int", + "default_value": 35, + "minimum_value": 0, + "maximum_value": 100, + "unit": "% ", + "enabled": "fan_layer_or_feature == 'by_feature'" + }, + "feature_fan_skin": + { + "label": "Top/Bottom (Skin) %", + "description": "Enter the fan percentage for the Skins.", + "type": "int", + "default_value": 100, + "minimum_value": 0, + "maximum_value": 100, + "unit": "% ", + "enabled": "fan_layer_or_feature == 'by_feature'" + }, + "feature_fan_support": + { + "label": "Support %", + "description": "Enter the fan percentage for the Supports.", + "type": "int", + "default_value": 35, + "minimum_value": 0, + "maximum_value": 100, + "unit": "% ", + "enabled": "fan_layer_or_feature == 'by_feature'" + }, + "feature_fan_support_interface": + { + "label": "Support Interface %", + "description": "Enter the fan percentage for the Support Interface.", + "type": "int", + "default_value": 100, + "minimum_value": 0, + "maximum_value": 100, + "unit": "% ", + "enabled": "fan_layer_or_feature == 'by_feature'" + }, + "feature_fan_prime_tower": + { + "label": "Prime Tower %", + "description": "Enter the fan percentage for the Prime Tower (whether it's used or not).", + "type": "int", + "default_value": 35, + "minimum_value": 0, + "maximum_value": 100, + "unit": "% ", + "enabled": "fan_layer_or_feature == 'by_feature'" + }, + "feature_fan_bridge": + { + "label": "Bridge %", + "description": "Enter the fan percentage for any Bridging (whether it's used on not).", + "type": "int", + "default_value": 100, + "minimum_value": 0, + "maximum_value": 100, + "unit": "% ", + "enabled": "fan_layer_or_feature == 'by_feature'" + }, + "feature_fan_combing": + { + "label": "Fan 'OFF' during Combing:", + "description": "When checked will set the fan to 0% for combing moves over 5 lines long in the gcode. When un-checked the fan speed during combing is whatever the previous speed is set to.", + "type": "bool", + "enabled": "fan_layer_or_feature == 'by_feature'", + "default_value": true + }, + "feature_fan_feature_final": + { + "label": "Final %", + "description": "If you choose an 'End Layer' then this is the fan speed that will carry through to the end of the gcode file. It will go into effect at the 'END' of your end layer.", + "type": "int", + "default_value": 35, + "minimum_value": 0, + "maximum_value": 100, + "unit": "% ", + "enabled": "(int(feature_fan_end_layer) != -1) and (fan_layer_or_feature == 'by_feature')" + }, + "fan_enable_raft": + { + "label": "Enable Raft Cooling", + "description": "Enable the fan for the raft layers. When enabled the Raft Fan Speed will continue until another Layer or Feature setting over-rides it.", + "type": "bool", + "default_value": false, + "enabled": true + }, + "fan_raft_percent": + { + "label": "Raft Fan %:", + "description": "Enter the percentage for the Raft.", + "type": "int", + "default_value": 35, + "minimum_value": 0, + "maximum_value": 100, + "unit": "% ", + "enabled": "fan_enable_raft" + } + } + }""" + + def initialize(self) -> None: + super().initialize() + scripts = Application.getInstance().getGlobalContainerStack().getMetaDataEntry("post_processing_scripts") + if scripts != None: + script_count = scripts.count("AddCoolingProfile") + if script_count > 0: + ## Set the default to "false" if there is more than one instance of this script running. + self._instance.setProperty("delete_existing_m106", "value", False) + + def execute(self, data): + #Initialize variables that are buried in if statements. + mycura = Application.getInstance().getGlobalContainerStack() + t0_fan = " P0"; t1_fan = " P0"; t2_fan = " P0"; t3_fan = " P0"; is_multi_extr_print = True + + #Get some information from Cura----------------------------------- + extruder = mycura.extruderList + + #This will be true when fan scale is 0-255pwm and false when it's RepRap 0-1 (Cura 5.x) + fan_mode = True + ##For 4.x versions that don't have the 0-1 option + try: + fan_mode = not bool(extruder[0].getProperty("machine_scale_fan_speed_zero_to_one", "value")) + except: + pass + bed_adhesion = (extruder[0].getProperty("adhesion_type", "value")) + extruder_count = mycura.getProperty("machine_extruder_count", "value") + print_sequence = str(mycura.getProperty("print_sequence", "value")) + + #Assign the fan numbers to the tools------------------------------ + if extruder_count == 1: + is_multi_fan = False + is_multi_extr_print = False + if int((extruder[0].getProperty("machine_extruder_cooling_fan_number", "value"))) > 0: + t0_fan = " P" + str((extruder[0].getProperty("machine_extruder_cooling_fan_number", "value"))) + else: + #No P parameter if there is a single fan circuit------------------ + t0_fan = "" + elif extruder_count > 1: + is_multi_fan = True + t0_fan = " P" + str((extruder[0].getProperty("machine_extruder_cooling_fan_number", "value"))) + if is_multi_fan: + if extruder_count > 1: t1_fan = " P" + str((extruder[1].getProperty("machine_extruder_cooling_fan_number", "value"))) + if extruder_count > 2: t2_fan = " P" + str((extruder[2].getProperty("machine_extruder_cooling_fan_number", "value"))) + if extruder_count > 3: t3_fan = " P" + str((extruder[3].getProperty("machine_extruder_cooling_fan_number", "value"))) + + #Initialize the fan_list with defaults---------------------------- + fan_list = ["z"] * 16 + for num in range(0,15,2): + fan_list[num + 1] = "M106 S0" + + #Assign the variable values if "By Layer"------------------------- + by_layer_or_feature = self.getSettingValueByKey("fan_layer_or_feature") + if by_layer_or_feature == "by_layer": + ## By layer doesn't do any feature search + feature_fan_combing = False + fan_list[0] = self.getSettingValueByKey("layer_fan_1st") + fan_list[2] = self.getSettingValueByKey("layer_fan_2nd") + fan_list[4] = self.getSettingValueByKey("layer_fan_3rd") + fan_list[6] = self.getSettingValueByKey("layer_fan_4th") + fan_list[8] = self.getSettingValueByKey("layer_fan_5th") + fan_list[10] = self.getSettingValueByKey("layer_fan_6th") + fan_list[12] = self.getSettingValueByKey("layer_fan_7th") + fan_list[14] = self.getSettingValueByKey("layer_fan_8th") + ## If there is no '/' delimiter then ignore the line else put the settings in a list + for num in range(0,15,2): + if "/" in fan_list[num]: + fan_list[num + 1] = self._layer_checker(fan_list[num], "p", fan_mode) + fan_list[num] = self._layer_checker(fan_list[num], "l", fan_mode) + + ## Assign the variable values if "By Feature" + elif by_layer_or_feature == "by_feature": + the_start_layer = self.getSettingValueByKey("feature_fan_start_layer") - 1 + the_end_layer = self.getSettingValueByKey("feature_fan_end_layer") + try: + if int(the_end_layer) != -1: + ## Catch a possible input error. + if the_end_layer < the_start_layer: + the_end_layer = the_start_layer + except: + the_end_layer = -1 ## If there is an input error default to the entire gcode file. + + ## Get the speed for each feature + # 0;TYPE:SKIRT, 1;TYPE:WALL-INNER, 2;TYPE:WALL-OUTER, 3;TYPE:FILL, 4;TYPE:SKIN, 5;TYPE:SUPPORT, 6;TYPE:SUPPORT-INTERFACE, 7;TYPE:PRIME-TOWER, 8;BRIDGE, 9;FEATURE_FINAL, 10;FAN_COMBING, + fan_sp_skirt = self._feature_checker(self.getSettingValueByKey("feature_fan_skirt"), fan_mode) + fan_sp_wall_inner = self._feature_checker(self.getSettingValueByKey("feature_fan_wall_inner"), fan_mode) + fan_sp_wall_outer = self._feature_checker(self.getSettingValueByKey("feature_fan_wall_outer"), fan_mode) + fan_sp_fill = self._feature_checker(self.getSettingValueByKey("feature_fan_fill"), fan_mode) + fan_sp_skin = self._feature_checker(self.getSettingValueByKey("feature_fan_skin"), fan_mode) + fan_sp_support = self._feature_checker(self.getSettingValueByKey("feature_fan_support"), fan_mode) + fan_sp_support_interface = self._feature_checker(self.getSettingValueByKey("feature_fan_support_interface"), fan_mode) + fan_sp_prime_tower = self._feature_checker(self.getSettingValueByKey("feature_fan_prime_tower"), fan_mode) + fan_sp_bridge = self._feature_checker(self.getSettingValueByKey("feature_fan_bridge"), fan_mode) + fan_sp_feature_final = self._feature_checker(self.getSettingValueByKey("feature_fan_feature_final"), fan_mode) + feature_fan_combing = self.getSettingValueByKey("feature_fan_combing") + if the_end_layer > -1 and by_layer_or_feature == "by_feature": + ## Required so the final speed input can be determined + the_end_is_enabled = True + else: + ## There is no ending layer so do the whole file + the_end_is_enabled = False + if the_end_layer == -1 or the_end_is_enabled == False: + the_end_layer = len(data) + 2 + + ## Find the Layer0Index and the RaftIndex + raft_start_index = 0 + number_of_raft_layers = 0 + layer_0_index = 0 + ## Catch the number of raft layers. + for l_num in range(1,10,1): + layer = data[l_num] + if ";LAYER:-" in layer: + number_of_raft_layers += 1 + if raft_start_index == 0: + raft_start_index = l_num + if ";LAYER:0" in layer: + layer_0_index = l_num + break + + ## Is this a single extruder print on a multi-extruder printer? - get the correct fan number for the extruder being used. + if is_multi_fan: + T0_used = False + T1_used = False + T2_used = False + T3_used = False + ## Bypass the file header and ending gcode. + for num in range(1,len(data)-1,1): + lines = data[num] + if "T0" in lines: + T0_used = True + if "T1" in lines: + T1_used = True + if "T2" in lines: + T2_used = True + if "T3" in lines: + T3_used = True + is_multi_extr_print = True if sum([T0_used, T1_used, T2_used, T3_used]) > 1 else False + + ## On a multi-extruder printer and single extruder print find out which extruder starts the file. + init_fan = t0_fan + if not is_multi_extr_print: + startup = data[1] + lines = startup.split("\n") + for line in lines: + if line == "T1": + t0_fan = t1_fan + elif line == "T2": + t0_fan = t2_fan + elif line == "T3": + t0_fan = t3_fan + elif is_multi_extr_print: + ## On a multi-extruder printer and multi extruder print find out which extruder starts the file. + startup = data[1] + lines = startup.split("\n") + for line in lines: + if line == "T0": + init_fan = t0_fan + elif line == "T1": + init_fan = t1_fan + elif line == "T2": + init_fan = t2_fan + elif line == "T3": + init_fan = t3_fan + else: + init_fan = "" + ## Assign the variable values if "Raft Enabled" + raft_enabled = self.getSettingValueByKey("fan_enable_raft") + if raft_enabled and bed_adhesion == "raft": + fan_sp_raft = self._feature_checker(self.getSettingValueByKey("fan_raft_percent"), fan_mode) + else: + fan_sp_raft = "M106 S0" + + # Start to alter the data----------------------------------------- + ## Strip the existing M106 lines from the file up to the end of the last layer. If a user wants to use more than one instance of this plugin then they won't want to erase the M106 lines that the preceding plugins inserted so 'delete_existing_m106' is an option. + delete_existing_m106 = self.getSettingValueByKey("delete_existing_m106") + if delete_existing_m106: + ## Start deleting from the beginning + start_from = int(raft_start_index) + else: + if by_layer_or_feature == "by_layer": + altered_start_layer = str(len(data)) + ## The fan list layers don't need to be in ascending order. Get the lowest. + for num in range(0,15,2): + if int(fan_list[num]) < int(altered_start_layer): + altered_start_layer = int(fan_list[num]) + elif by_layer_or_feature == "by_feature": + altered_start_layer = int(the_start_layer) - 1 + start_from = int(layer_0_index) + int(altered_start_layer) + + ## Strip the M106 and M107 lines from the file + for l_index in range(int(start_from), len(data) - 1, 1): + data[l_index] = re.sub(re.compile("M106(.*)\n"), "", data[l_index]) + data[l_index] = re.sub(re.compile("M107(.*)\n"), "", data[l_index]) + + ## Deal with a raft and with One-At-A-Time + if raft_enabled and bed_adhesion == "raft": + if print_sequence == "one_at_a_time": + for r_index in range(2,len(data)-2,1): + lines = data[r_index].split("\n") + if not raft_enabled or bed_adhesion != "raft": + if ";LAYER:0" in data[r_index] or ";LAYER:-" in data[r_index]: + lines.insert(1, "M106 S0" + str(t0_fan)) + if raft_enabled and bed_adhesion == "raft": + if ";LAYER:-" in data[r_index]: + ## Turn the raft fan on + lines.insert(1, fan_sp_raft + str(t0_fan)) + ## Shut the raft fan off + if ";LAYER:0" in data[r_index]: + lines.insert(1,"M106 S0" + str(t0_fan)) + data[r_index] = "\n".join(lines) + elif print_sequence == "all_at_once": + layer = data[raft_start_index] + lines = layer.split("\n") + if ";LAYER:-" in layer: + ## Turn the raft fan on + lines.insert(1, fan_sp_raft + str(init_fan)) + layer = "\n".join(lines) + data[raft_start_index] = layer + layer = data[layer_0_index] + lines = layer.split("\n") + ## Shut the raft fan off + lines.insert(1, "M106 S0" + str(init_fan)) + data[layer_0_index] = "\n".join(lines) + else: + for r_index in range(2,len(data)-2,1): + lines = data[r_index].split("\n") + if ";LAYER:0" in data[r_index] or ";LAYER:-" in data[r_index]: + if not "0" in fan_list: + lines.insert(1, "M106 S0" + str(t0_fan)) + data[r_index] = "\n".join(lines) + + ## Turn off all fans at the end of data[1] + temp_startup = data[1].split("\n") + temp_startup.insert(len(temp_startup)-2,"M106 S0" + str(t0_fan)) + ## If there are multiple cooling fans shut them all off + if is_multi_fan: + if extruder_count > 1 and t1_fan != t0_fan: temp_startup.insert(len(temp_startup)-2,"M106 S0" + str(t1_fan)) + if extruder_count > 2 and t2_fan != t1_fan and t2_fan != t0_fan: temp_startup.insert(len(temp_startup)-2,"M106 S0" + str(t2_fan)) + if extruder_count > 3 and t3_fan != t2_fan and t3_fan != t1_fan and t3_fan != t0_fan: temp_startup.insert(len(temp_startup)-2,"M106 S0" + str(t3_fan)) + data[1] = "\n".join(temp_startup) + + ## If 'feature_fan_combing' is True then add additional 'MESH:NONMESH' lines for travel moves over 5 lines long + ## For compatibility with 5.3.0 change any MESH:NOMESH to MESH:NONMESH. + if feature_fan_combing: + for layer_num in range(2,len(data)): + layer = data[layer_num] + data[layer_num] = re.sub(";MESH:NOMESH", ";MESH:NONMESH", layer) + data = self._add_travel_comment(data, layer_0_index) + + # Single Fan "By Layer"-------------------------------------------- + if by_layer_or_feature == "by_layer" and not is_multi_fan: + return self._single_fan_by_layer(data, layer_0_index, fan_list, t0_fan) + + # Multi-Fan "By Layer"--------------------------------------------- + if by_layer_or_feature == "by_layer" and is_multi_fan: + return self._multi_fan_by_layer(data, layer_0_index, fan_list, t0_fan, t1_fan, t2_fan, t3_fan) + + #Single Fan "By Feature"------------------------------------------ + if by_layer_or_feature == "by_feature" and (not is_multi_fan or not is_multi_extr_print): + return self._single_fan_by_feature(data, layer_0_index, the_start_layer, the_end_layer, the_end_is_enabled, fan_list, t0_fan, fan_sp_skirt, fan_sp_wall_inner, fan_sp_wall_outer, fan_sp_fill, fan_sp_skin, fan_sp_support, fan_sp_support_interface, feature_fan_combing, fan_sp_prime_tower, fan_sp_bridge, fan_sp_feature_final) + + #Multi Fan "By Feature"------------------------------------------- + if by_layer_or_feature == "by_feature" and is_multi_fan: + return self._multi_fan_by_feature(data, layer_0_index, the_start_layer, the_end_layer, the_end_is_enabled, fan_list, t0_fan, t1_fan, t2_fan, t3_fan, fan_sp_skirt, fan_sp_wall_inner, fan_sp_wall_outer, fan_sp_fill, fan_sp_skin, fan_sp_support, fan_sp_support_interface, feature_fan_combing, fan_sp_prime_tower, fan_sp_bridge, fan_sp_feature_final) + + # The Single Fan "By Layer"---------------------------------------- + def _single_fan_by_layer(self, data: str, layer_0_index: int, fan_list: str, t0_fan: str)->str: + layer_number = "0" + single_fan_layer = data + for l_index in range(layer_0_index,len(single_fan_layer)-1,1): + layer = single_fan_layer[l_index] + fan_lines = layer.split("\n") + for fan_line in fan_lines: + if ";LAYER:" in fan_line: + layer_number = int(fan_line.split(":")[1]) + ## If there is a match for the current layer number make the insertion. + try: + for num in range(0,15,2): + if int(layer_number) == int(fan_list[num]): + layer = layer.replace(fan_lines[0],fan_lines[0] + "\n" + fan_list[num + 1] + str(t0_fan)) + single_fan_layer[l_index] = layer + except: + continue + return single_fan_layer + + # Multi-Fan "By Layer"----------------------------------------- + def _multi_fan_by_layer(self, data: str, layer_0_index: int, fan_list: str, t0_fan: str, t1_fan: str, t2_fan: str, t3_fan: str)->str: + multi_fan_data = data + layer_number = "0" + current_fan_speed = "0" + prev_fan = str(t0_fan) + this_fan = str(t0_fan) + start_index = str(len(multi_fan_data)) + for num in range(0,15,2): + ## The fan_list may not be in ascending order. Get the lowest layer number + try: + if int(fan_list[num]) < int(start_index): + start_index = str(fan_list[num]) + except: + pass + ## Move the start point if delete_existing_m106 is false + start_index = int(start_index) + int(layer_0_index) + ## Track the tool number + for num in range(1,int(start_index),1): + layer = multi_fan_data[num] + lines = layer.split("\n") + for line in lines: + if line == "T0": + prev_fan = this_fan + this_fan = t0_fan + elif line == "T1": + prev_fan = this_fan + this_fan = t1_fan + elif line == "T2": + prev_fan = this_fan + this_fan = t2_fan + elif line == "T3": + prev_fan = this_fan + this_fan = t3_fan + for l_index in range(int(start_index),len(multi_fan_data)-1,1): + modified_data = "" + layer = multi_fan_data[l_index] + fan_lines = layer.split("\n") + for fan_line in fan_lines: + ## Prepare to shut down the previous fan and start the next one. + if fan_line.startswith("T"): + if fan_line == "T0": this_fan = str(t0_fan) + if fan_line == "T1": this_fan = str(t1_fan) + if fan_line == "T2": this_fan = str(t2_fan) + if fan_line == "T3": this_fan = str(t3_fan) + modified_data += "M106 S0" + prev_fan + "\n" + modified_data += fan_line + "\n" + modified_data += "M106 S" + str(current_fan_speed) + this_fan + "\n" + prev_fan = this_fan + elif ";LAYER:" in fan_line: + modified_data += fan_line + "\n" + layer_number = str(fan_line.split(":")[1]) + for num in range(0,15,2): + if layer_number == str(fan_list[num]): + modified_data += fan_list[num + 1] + this_fan + "\n" + current_fan_speed = str(fan_list[num + 1].split("S")[1]) + current_fan_speed = str(current_fan_speed.split(" ")[0]) ## Just in case + else: + modified_data += fan_line + "\n" + if modified_data.endswith("\n"): modified_data = modified_data[0:-1] + multi_fan_data[l_index] = modified_data + return multi_fan_data + + # Single fan by feature----------------------------------------------- + def _single_fan_by_feature(self, data: str, layer_0_index: int, the_start_layer: str, the_end_layer: str, the_end_is_enabled: str, fan_list: str, t0_fan: str, fan_sp_skirt: str, fan_sp_wall_inner: str, fan_sp_wall_outer: str, fan_sp_fill: str, fan_sp_skin: str, fan_sp_support: str, fan_sp_support_interface: str, feature_fan_combing: str, fan_sp_prime_tower: str, fan_sp_bridge: str, fan_sp_feature_final: str)->str: + single_fan_data = data + layer_number = "0" + index = 1 + ## Start with layer:0 + for l_index in range(layer_0_index,len(single_fan_data)-1,1): + modified_data = "" + layer = single_fan_data[l_index] + lines = layer.split("\n") + for line in lines: + if ";LAYER:" in line: + layer_number = str(line.split(":")[1]) + if int(layer_number) >= int(the_start_layer) and int(layer_number) < int(the_end_layer)-1: + if ";TYPE:SKIRT" in line: + modified_data += fan_sp_skirt + t0_fan + "\n" + elif ";TYPE:WALL-INNER" in line: + modified_data += fan_sp_wall_inner + t0_fan + "\n" + elif ";TYPE:WALL-OUTER" in line: + modified_data += fan_sp_wall_outer + t0_fan + "\n" + elif ";TYPE:FILL" in line: + modified_data += fan_sp_fill + t0_fan + "\n" + elif ";TYPE:SKIN" in line: + modified_data += fan_sp_skin + t0_fan + "\n" + elif line == ";TYPE:SUPPORT": + modified_data += fan_sp_support + t0_fan + "\n" + elif ";TYPE:SUPPORT-INTERFACE" in line: + modified_data += fan_sp_support_interface + t0_fan + "\n" + elif ";MESH:NONMESH" in line: + if feature_fan_combing == True: + modified_data += "M106 S0" + t0_fan + "\n" + elif ";TYPE:PRIME-TOWER" in line: + modified_data += fan_sp_prime_tower + t0_fan + "\n" + elif line == ";BRIDGE": + modified_data += fan_sp_bridge + t0_fan + "\n" + modified_data += line + "\n" + ## If an End Layer is defined and is less than the last layer then insert the Final Speed + if line == ";LAYER:" + str(the_end_layer) and the_end_is_enabled == True: + modified_data += fan_sp_feature_final + t0_fan + "\n" + if modified_data.endswith("\n"): modified_data = modified_data[0: - 1] + single_fan_data[l_index] = modified_data + return single_fan_data + + # Multi-fan by feature------------------------------------------------ + def _multi_fan_by_feature(self, data: str, layer_0_index: int, the_start_layer: str, the_end_layer: str, the_end_is_enabled: str, fan_list: str, t0_fan: str, t1_fan: str, t2_fan: str, t3_fan: str, fan_sp_skirt: str, fan_sp_wall_inner: str, fan_sp_wall_outer: str, fan_sp_fill: str, fan_sp_skin: str, fan_sp_support: str, fan_sp_support_interface: str, feature_fan_combing: str, fan_sp_prime_tower: str, fan_sp_bridge: str, fan_sp_feature_final: str)->str: + multi_fan_data = data + layer_number = "0" + start_index = 1 + prev_fan = t0_fan + this_fan = t0_fan + modified_data = "" + current_fan_speed = "0" + for my_index in range(1, len(multi_fan_data) - 1, 1): + layer = multi_fan_data[my_index] + if ";LAYER:" + str(the_start_layer) + "\n" in layer: + start_index = int(my_index) - 1 + break + ## Track the previous tool changes + for num in range(1,start_index,1): + layer = multi_fan_data[num] + lines = layer.split("\n") + for line in lines: + if line == "T0": + prev_fan = this_fan + this_fan = t0_fan + elif line == "T1": + prev_fan = this_fan + this_fan = t1_fan + elif line == "T2": + prev_fan = this_fan + this_fan = t2_fan + elif line == "T3": + prev_fan = this_fan + this_fan = t3_fan + ## Get the current tool. + for l_index in range(start_index,start_index + 1,1): + layer = multi_fan_data[l_index] + lines = layer.split("\n") + for line in lines: + if line.startswith("T"): + if line == "T0": this_fan = t0_fan + if line == "T1": this_fan = t1_fan + if line == "T2": this_fan = t2_fan + if line == "T3": this_fan = t3_fan + prev_fan = this_fan + + ## Start to make insertions------------------------------------- + for l_index in range(start_index+1,len(multi_fan_data)-1,1): + layer = multi_fan_data[l_index] + lines = layer.split("\n") + for line in lines: + if line.startswith("T"): + if line == "T0": this_fan = t0_fan + if line == "T1": this_fan = t1_fan + if line == "T2": this_fan = t2_fan + if line == "T3": this_fan = t3_fan + ## Turn off the prev fan + modified_data += "M106 S0" + prev_fan + "\n" + modified_data += line + "\n" + ## Turn on the current fan + modified_data += "M106 S" + str(current_fan_speed) + this_fan + "\n" + prev_fan = this_fan + if ";LAYER:" in line: + layer_number = str(line.split(":")[1]) + modified_data += line + "\n" + if int(layer_number) >= int(the_start_layer): # Problem with oneatatime < start + if ";TYPE:SKIRT" in line: + modified_data += line + "\n" + modified_data += fan_sp_skirt + this_fan + "\n" + current_fan_speed = str(fan_sp_skirt.split("S")[1]) + elif ";TYPE:WALL-INNER" in line: + modified_data += line + "\n" + modified_data += fan_sp_wall_inner + this_fan + "\n" + current_fan_speed = str(fan_sp_wall_inner.split("S")[1]) + elif ";TYPE:WALL-OUTER" in line: + modified_data += line + "\n" + modified_data += fan_sp_wall_outer + this_fan + "\n" + current_fan_speed = str(fan_sp_wall_outer.split("S")[1]) + elif ";TYPE:FILL" in line: + modified_data += line + "\n" + modified_data += fan_sp_fill + this_fan + "\n" + current_fan_speed = str(fan_sp_fill.split("S")[1]) + elif ";TYPE:SKIN" in line: + modified_data += line + "\n" + modified_data += fan_sp_skin + this_fan + "\n" + current_fan_speed = str(fan_sp_skin.split("S")[1]) + elif line == ";TYPE:SUPPORT": + modified_data += line + "\n" + modified_data += fan_sp_support + this_fan + "\n" + current_fan_speed = str(fan_sp_support.split("S")[1]) + elif ";TYPE:SUPPORT-INTERFACE" in line: + modified_data += line + "\n" + modified_data += fan_sp_support_interface + this_fan + "\n" + current_fan_speed = str(fan_sp_support_interface.split("S")[1]) + elif ";MESH:NONMESH" in line: + if feature_fan_combing == True: + modified_data += line + "\n" + modified_data += "M106 S0" + this_fan + "\n" + current_fan_speed = "0" + else: + modified_data += line + "\n" + elif ";TYPE:PRIME-TOWER" in line: + modified_data += line + "\n" + modified_data += fan_sp_prime_tower + this_fan + "\n" + current_fan_speed = str(fan_sp_prime_tower.split("S")[1]) + elif line == ";BRIDGE": + modified_data += line + "\n" + modified_data += fan_sp_bridge + this_fan + "\n" + current_fan_speed = str(fan_sp_bridge.split("S")[1]) + ## If an end layer is defined - Insert the final speed and set the other variables to Final Speed to finish the file + ## There cannot be a break here because if there are multiple fan numbers they still need to be shut off and turned on. + elif line == ";LAYER:" + str(the_end_layer): + modified_data += fan_sp_feature_final + this_fan + "\n" + fan_sp_skirt = fan_sp_feature_final + fan_sp_wall_inner = fan_sp_feature_final + fan_sp_wall_outer = fan_sp_feature_final + fan_sp_fill = fan_sp_feature_final + fan_sp_skin = fan_sp_feature_final + fan_sp_support = fan_sp_feature_final + fan_sp_support_interface = fan_sp_feature_final + fan_sp_prime_tower = fan_sp_feature_final + fan_sp_bridge = fan_sp_feature_final + else: + ## Layer and Tool get inserted into modified_data above. All other lines go into modified_data here + if not line.startswith("T") and not line.startswith(";LAYER:"): modified_data += line + "\n" + if modified_data.endswith("\n"): modified_data = modified_data[0: - 1] + multi_fan_data[l_index] = modified_data + modified_data = "" + return multi_fan_data + + #Try to catch layer input errors, set the minimum speed to 12%, and put the strings together + def _layer_checker(self, fan_string: str, ty_pe: str, fan_mode: bool) -> str: + fan_string_l = str(fan_string.split("/")[0]) + try: + if int(fan_string_l) <= 1: fan_string_l = "1" + if fan_string_l == "": fan_string_l = str(len(data)) + except ValueError: + fan_string_l = str(len(data)) + fan_string_l = str(int(fan_string_l) - 1) + fan_string_p = str(fan_string.split("/")[1]) + if fan_string_p == "": fan_string_p = "0" + try: + if int(fan_string_p) < 0: fan_string_p = "0" + if int(fan_string_p) > 100: fan_string_p = "100" + except ValueError: + fan_string_p = "0" + ## Set the minimum fan speed to 12% + if int(fan_string_p) < 12 and int(fan_string_p) != 0: + fan_string_p = "12" + fan_layer_line = str(fan_string_l) + if fan_mode: + fan_percent_line = "M106 S" + str(round(int(fan_string_p) * 2.55)) + else: + fan_percent_line = "M106 S" + str(round(int(fan_string_p) / 100, 1)) + if ty_pe == "l": + return str(fan_layer_line) + elif ty_pe == "p": + return fan_percent_line + + #Try to catch feature input errors, set the minimum speed to 12%, and put the strings together when 'By Feature' + def _feature_checker(self, fan_feat_string: int, fan_mode: bool) -> str: + if fan_feat_string < 0: fan_feat_string = 0 + ## Set the minimum fan speed to 12% + if fan_feat_string > 0 and fan_feat_string < 12: fan_feat_string = 12 + if fan_feat_string > 100: fan_feat_string = 100 + if fan_mode: + fan_sp_feat = "M106 S" + str(round(fan_feat_string * 2.55)) + else: + fan_sp_feat = "M106 S" + str(round(fan_feat_string / 100, 1)) + return fan_sp_feat + + # Add additional travel comments to turn the fan off during combing. + def _add_travel_comment(self, the_data: str, lay_0_index: str) -> str: + for lay_num in range(int(lay_0_index), len(the_data)-1,1): + layer = the_data[lay_num] + lines = layer.split("\n") + ## Copy the data to new_data and make the insertions there + new_data = lines + g0_count = 0 + g0_index = -1 + feature_type = ";TYPE:SUPPORT" + is_travel = False + for index, line in enumerate(lines): + insert_index = 0 + if ";TYPE:" in line: + feature_type = line + is_travel = False + g0_count = 0 + if ";MESH:NONMESH" in line: + is_travel = True + g0_count = 0 + if line.startswith("G0 ") and not is_travel: + g0_count += 1 + if g0_index == -1: + g0_index = lines.index(line) + elif not line.startswith("G0 ") and not is_travel: + ## Add additional 'NONMESH' lines to shut the fan off during long combing moves-------- + if g0_count > 5: + if not is_travel: + new_data.insert(g0_index + insert_index, ";MESH:NONMESH") + insert_index += 1 + ## Add the feature_type at the end of the combing move to turn the fan back on + new_data.insert(g0_index + g0_count + 1, feature_type) + insert_index += 1 + g0_count = 0 + g0_index = -1 + is_travel = False + elif g0_count <= 5: + g0_count = 0 + g0_index = -1 + is_travel = False + the_data[lay_num] = "\n".join(new_data) + return the_data \ No newline at end of file From 13deab505ea06e8a352bd93615bfabe67775b210 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 8 Jan 2024 11:32:25 +0100 Subject: [PATCH 53/73] Add/reorganize settings for raft walls CURA-11228 --- resources/definitions/fdmprinter.def.json | 59 ++++++++++++++++++----- resources/setting_visibility/expert.cfg | 1 + 2 files changed, 49 insertions(+), 11 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 2b37b3d7ac..32908b6f3e 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -6329,6 +6329,54 @@ "settable_per_extruder": true, "limit_to_extruder": "raft_base_extruder_nr" }, + "raft_wall_count": + { + "label": "Raft Wall Count", + "description": "The number of contours to print around the linear pattern of the raft.", + "type": "int", + "default_value": 1, + "minimum_value": "0", + "enabled": "resolveOrValue('adhesion_type') == 'raft'", + "settable_per_mesh": false, + "settable_per_extruder": false, + "children": + { + "raft_surface_wall_count": + { + "label": "Raft Top Wall Count", + "description": "The number of contours to print around the linear pattern in the top layers of the raft.", + "type": "int", + "default_value": 0, + "minimum_value": "0", + "enabled": "resolveOrValue('adhesion_type') == 'raft'", + "settable_per_mesh": false, + "settable_per_extruder": false + }, + "raft_interface_wall_count": + { + "label": "Raft Middle Wall Count", + "description": "The number of contours to print around the linear pattern in the middle layers of the raft.", + "type": "int", + "default_value": 0, + "minimum_value": "0", + "enabled": "resolveOrValue('adhesion_type') == 'raft'", + "settable_per_mesh": false, + "settable_per_extruder": false + }, + "raft_base_wall_count": + { + "label": "Raft Base Wall Count", + "description": "The number of contours to print around the linear pattern in the base layer of the raft.", + "type": "int", + "default_value": 1, + "value": "raft_wall_count", + "minimum_value": "0", + "enabled": "resolveOrValue('adhesion_type') == 'raft'", + "settable_per_mesh": false, + "settable_per_extruder": false + } + } + }, "raft_speed": { "label": "Raft Print Speed", @@ -8286,17 +8334,6 @@ "settable_per_mesh": false, "settable_per_extruder": false }, - "raft_base_wall_count": - { - "label": "Raft Base Wall Count", - "description": "The number of contours to print around the linear pattern in the base layer of the raft.", - "type": "int", - "default_value": 1, - "enabled": "resolveOrValue('adhesion_type') == 'raft'", - "resolve": "max(extruderValues('raft_base_wall_count'))", - "settable_per_mesh": false, - "settable_per_extruder": false - }, "group_outer_walls": { "label": "Group Outer Walls", diff --git a/resources/setting_visibility/expert.cfg b/resources/setting_visibility/expert.cfg index 2f2dd7671d..384f8d2528 100644 --- a/resources/setting_visibility/expert.cfg +++ b/resources/setting_visibility/expert.cfg @@ -344,6 +344,7 @@ raft_interface_line_spacing raft_base_thickness raft_base_line_width raft_base_line_spacing +raft_wall_count raft_speed raft_acceleration raft_jerk From 68460c55474ac92b6c781df29db6d5567bcd3323 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Mon, 8 Jan 2024 12:47:28 +0100 Subject: [PATCH 54/73] Also run on 5.6E branch Fixes CURA-11523 --- .github/workflows/conan-package.yml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.github/workflows/conan-package.yml b/.github/workflows/conan-package.yml index 7ca2b0c467..faa970270d 100644 --- a/.github/workflows/conan-package.yml +++ b/.github/workflows/conan-package.yml @@ -20,12 +20,8 @@ on: - 'main' - 'CURA-*' - 'PP-*' - - '[0-9].[0-9]' - - '[0-9].[0-9][0-9]' - tags: - - '[0-9].[0-9].[0-9]*' - - '[0-9].[0-9].[0-9]' - - '[0-9].[0-9][0-9].[0-9]*' + - '[0-9].[0-9]*' + - '[0-9].[0-9][0-9]*' env: CONAN_LOGIN_USERNAME_CURA: ${{ secrets.CONAN_USER }} From 677f35b5159e53fded2d4c31b2ca58ede6b28373 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Mon, 8 Jan 2024 11:06:20 +0100 Subject: [PATCH 55/73] use `input` instead of the `github.events` Fixes CURA-11523 --- .github/workflows/installers.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/installers.yml b/.github/workflows/installers.yml index 6e531ba833..9c51cfe820 100644 --- a/.github/workflows/installers.yml +++ b/.github/workflows/installers.yml @@ -54,9 +54,9 @@ jobs: needs: [ default_values ] with: cura_conan_version: ${{ needs.default_values.outputs.cura_conan_version }} - conan_args: ${{ github.event.inputs.conan_args }} - enterprise: ${{ github.event.inputs.enterprise == 'true' }} - staging: ${{ github.event.inputs.staging == 'true' }} + conan_args: ${{ inputs.conan_args }} + enterprise: ${{ inputs.enterprise }} + staging: ${{ inputs.staging }} architecture: X64 operating_system: windows-2022 secrets: inherit @@ -66,9 +66,9 @@ jobs: needs: [ default_values ] with: cura_conan_version: ${{ needs.default_values.outputs.cura_conan_version }} - conan_args: ${{ github.event.inputs.conan_args }} - enterprise: ${{ github.event.inputs.enterprise == 'true' }} - staging: ${{ github.event.inputs.staging == 'true' }} + conan_args: ${{ inputs.conan_args }} + enterprise: ${{ inputs.enterprise }} + staging: ${{ inputs.staging }} architecture: X64 operating_system: ubuntu-22.04 secrets: inherit @@ -78,9 +78,9 @@ jobs: needs: [ default_values ] with: cura_conan_version: ${{ needs.default_values.outputs.cura_conan_version }} - conan_args: ${{ github.event.inputs.conan_args }} - enterprise: ${{ github.event.inputs.enterprise == 'true' }} - staging: ${{ github.event.inputs.staging == 'true' }} + conan_args: ${{ inputs.conan_args }} + enterprise: ${{ inputs.enterprise }} + staging: ${{ inputs.staging }} architecture: X64 operating_system: self-hosted-X64 secrets: inherit @@ -90,9 +90,9 @@ jobs: needs: [ default_values ] with: cura_conan_version: ${{ needs.default_values.outputs.cura_conan_version }} - conan_args: ${{ github.event.inputs.conan_args }} - enterprise: ${{ github.event.inputs.enterprise == 'true' }} - staging: ${{ github.event.inputs.staging == 'true' }} + conan_args: ${{ inputs.conan_args }} + enterprise: ${{ inputs.enterprise }} + staging: ${{ inputs.staging }} architecture: ARM64 operating_system: self-hosted-ARM64 secrets: inherit From 85a762aec38e8fc99d39addc0b58279f8e45078a Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Mon, 8 Jan 2024 11:17:16 +0100 Subject: [PATCH 56/73] sync workflow with 5.6E branch Fixes CURA-11523 --- .github/workflows/linux.yml | 11 +++-------- .github/workflows/macos.yml | 11 +++-------- .github/workflows/windows.yml | 11 +++-------- 3 files changed, 9 insertions(+), 24 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index f88b77a022..08c59c9158 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -39,19 +39,14 @@ on: options: - ubuntu-22.04 -env: - CONAN_ARGS: ${{ inputs.conan_args || '' }} - ENTERPRISE: ${{ inputs.enterprise || false }} - STAGING: ${{ inputs.staging || false }} - jobs: - installer: + linux-installer: uses: ultimaker/cura-workflows/.github/workflows/cura-installer-linux.yml@main with: cura_conan_version: ${{ inputs.cura_conan_version }} conan_args: ${{ inputs.conan_args }} - enterprise: ${{ inputs.enterprise == 'true' }} - staging: ${{ inputs.staging == 'true' }} + enterprise: ${{ inputs.enterprise }} + staging: ${{ inputs.staging }} architecture: ${{ inputs.architecture }} operating_system: ${{ inputs.operating_system }} secrets: inherit \ No newline at end of file diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index e909b9f839..9c940330e1 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -43,19 +43,14 @@ on: - macos-11 - macos-12 -env: - CONAN_ARGS: ${{ inputs.conan_args || '' }} - ENTERPRISE: ${{ inputs.enterprise || false }} - STAGING: ${{ inputs.staging || false }} - jobs: - installer: + macos-installer: uses: ultimaker/cura-workflows/.github/workflows/cura-installer-macos.yml@main with: cura_conan_version: ${{ inputs.cura_conan_version }} conan_args: ${{ inputs.conan_args }} - enterprise: ${{ inputs.enterprise == 'true' }} - staging: ${{ inputs.staging == 'true' }} + enterprise: ${{ inputs.enterprise }} + staging: ${{ inputs.staging }} architecture: ${{ inputs.architecture }} operating_system: ${{ inputs.operating_system }} secrets: inherit \ No newline at end of file diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 151935c3f3..22a81e9b2a 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -39,19 +39,14 @@ on: options: - windows-2022 -env: - CONAN_ARGS: ${{ inputs.conan_args || '' }} - ENTERPRISE: ${{ inputs.enterprise || false }} - STAGING: ${{ inputs.staging || false }} - jobs: - installer: + windows-installer: uses: ultimaker/cura-workflows/.github/workflows/cura-installer-windows.yml@main with: cura_conan_version: ${{ inputs.cura_conan_version }} conan_args: ${{ inputs.conan_args }} - enterprise: ${{ inputs.enterprise == 'true' }} - staging: ${{ inputs.staging == 'true' }} + enterprise: ${{ inputs.enterprise }} + staging: ${{ inputs.staging }} architecture: ${{ inputs.architecture }} operating_system: ${{ inputs.operating_system }} secrets: inherit \ No newline at end of file From b60b07e2b26f4d676222d56d135a5dc274ffa41f Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Mon, 8 Jan 2024 13:13:53 +0100 Subject: [PATCH 57/73] build Conan packages This will compile the mo files. But be sure that `enable_i18n` option is still removed from the `package_id`. Such that the build conan package can also be used Fixes CURA-11497 --- .github/workflows/conan-package.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/conan-package.yml b/.github/workflows/conan-package.yml index faa970270d..8faf1e27e1 100644 --- a/.github/workflows/conan-package.yml +++ b/.github/workflows/conan-package.yml @@ -40,3 +40,11 @@ jobs: recipe_id_full: ${{ needs.conan-recipe-version.outputs.recipe_id_full }} recipe_id_latest: ${{ needs.conan-recipe-version.outputs.recipe_id_latest }} secrets: inherit + + conan-package-create: + needs: [ conan-recipe-version, conan-package-export ] + uses: ultimaker/cura-workflows/.github/workflows/conan-package-create-linux.yml@main + with: + recipe_id_full: ${{ needs.conan-recipe-version.outputs.recipe_id_full }} + conan_extra_args: "-o cura:enable_i18n=True" + secrets: inherit \ No newline at end of file From a7137c5e634264b036ca3b38c8084423fbd8c2f1 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Mon, 8 Jan 2024 14:44:17 +0100 Subject: [PATCH 58/73] Add raft settings to make margin and remove inside corners configurable per raft-type Added teh following settings - raft_base_margin - raft_interface_margin - raft_surface_margin - raft_base_smoothing - raft_interface_smoothing - raft_surface_smoothing - raft_base_remove_inside_corners - raft_interface_remove_inside_corners - raft_surface_remove_inside_corners --- resources/definitions/fdmprinter.def.json | 129 +++++++++++++++++++++- resources/setting_visibility/expert.cfg | 9 ++ 2 files changed, 135 insertions(+), 3 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 2b37b3d7ac..b40e074f1c 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -6114,7 +6114,51 @@ "enabled": "resolveOrValue('adhesion_type') == 'raft'", "limit_to_extruder": "adhesion_extruder_nr", "settable_per_mesh": false, - "settable_per_extruder": true + "settable_per_extruder": true, + "children": { + "raft_base_margin": { + "label": "Raft Base Extra Margin", + "description": "If the raft base is enabled, this is the extra raft area around the model which is also given a raft. Increasing this margin will create a stronger raft while using more material and leaving less area for your print.", + "unit": "mm", + "type": "float", + "value": "raft_margin", + "default_value": 15, + "minimum_value_warning": "raft_interface_line_width", + "maximum_value_warning": "20", + "enabled": "resolveOrValue('adhesion_type') == 'raft'", + "limit_to_extruder": "adhesion_extruder_nr", + "settable_per_mesh": false, + "settable_per_extruder": true + }, + "raft_interface_margin": { + "label": "Raft Middle Extra Margin", + "description": "If the raft middle is enabled, this is the extra raft area around the model which is also given a raft. Increasing this margin will create a stronger raft while using more material and leaving less area for your print.", + "unit": "mm", + "type": "float", + "value": "raft_margin", + "default_value": 15, + "minimum_value_warning": "raft_interface_line_width", + "maximum_value_warning": "20", + "enabled": "resolveOrValue('adhesion_type') == 'raft'", + "limit_to_extruder": "adhesion_extruder_nr", + "settable_per_mesh": false, + "settable_per_extruder": true + }, + "raft_surface_margin": { + "label": "Raft Top Extra Margin", + "description": "If the raft top is enabled, this is the extra raft area around the model which is also given a raft. Increasing this margin will create a stronger raft while using more material and leaving less area for your print.", + "unit": "mm", + "type": "float", + "value": "raft_margin", + "default_value": 15, + "minimum_value_warning": "raft_interface_line_width", + "maximum_value_warning": "20", + "enabled": "resolveOrValue('adhesion_type') == 'raft'", + "limit_to_extruder": "adhesion_extruder_nr", + "settable_per_mesh": false, + "settable_per_extruder": true + } + } }, "raft_smoothing": { @@ -6128,7 +6172,51 @@ "enabled": "resolveOrValue('adhesion_type') == 'raft' and not raft_remove_inside_corners", "limit_to_extruder": "adhesion_extruder_nr", "settable_per_mesh": false, - "settable_per_extruder": true + "settable_per_extruder": true, + "children": { + "raft_base_smoothing": { + "label": "Raft Base Smoothing", + "description": "This setting controls how much inner corners in the raft base outline are rounded. Inward corners are rounded to a semi circle with a radius equal to the value given here. This setting also removes holes in the raft outline which are smaller than such a circle.", + "unit": "mm", + "type": "float", + "value": "raft_smoothing", + "default_value": 5, + "minimum_value": "0", + "minimum_value_warning": "raft_interface_line_width", + "enabled": "resolveOrValue('adhesion_type') == 'raft' and not raft_base_remove_inside_corners", + "limit_to_extruder": "adhesion_extruder_nr", + "settable_per_mesh": false, + "settable_per_extruder": true + }, + "raft_interface_smoothing": { + "label": "Raft Middle Smoothing", + "description": "This setting controls how much inner corners in the raft middle outline are rounded. Inward corners are rounded to a semi circle with a radius equal to the value given here. This setting also removes holes in the raft outline which are smaller than such a circle.", + "unit": "mm", + "type": "float", + "value": "raft_smoothing", + "default_value": 5, + "minimum_value": "0", + "minimum_value_warning": "raft_interface_line_width", + "enabled": "resolveOrValue('adhesion_type') == 'raft' and not raft_interface_remove_inside_corners", + "limit_to_extruder": "adhesion_extruder_nr", + "settable_per_mesh": false, + "settable_per_extruder": true + }, + "raft_surface_smoothing": { + "label": "Raft Top Smoothing", + "description": "This setting controls how much inner corners in the raft top outline are rounded. Inward corners are rounded to a semi circle with a radius equal to the value given here. This setting also removes holes in the raft outline which are smaller than such a circle.", + "unit": "mm", + "type": "float", + "value": "raft_smoothing", + "default_value": 5, + "minimum_value": "0", + "minimum_value_warning": "raft_interface_line_width", + "enabled": "resolveOrValue('adhesion_type') == 'raft' and not raft_surface_remove_inside_corners", + "limit_to_extruder": "adhesion_extruder_nr", + "settable_per_mesh": false, + "settable_per_extruder": true + } + } }, "raft_airgap": { @@ -8284,7 +8372,42 @@ "resolve": "any(extruderValues('raft_remove_inside_corners'))", "enabled": "resolveOrValue('adhesion_type') == 'raft'", "settable_per_mesh": false, - "settable_per_extruder": false + "settable_per_extruder": false, + "children": { + "raft_base_remove_inside_corners": { + "label": "Remove Raft Base Inside Corners", + "description": "Remove inside corners from the raft base, causing the raft to become convex.", + "type": "bool", + "value": "raft_remove_inside_corners", + "default_value": false, + "resolve": "any(extruderValues('raft_remove_inside_corners'))", + "enabled": "resolveOrValue('adhesion_type') == 'raft'", + "settable_per_mesh": false, + "settable_per_extruder": false + }, + "raft_interface_remove_inside_corners": { + "label": "Remove Raft Middle Inside Corners", + "description": "Remove inside corners from the raft middle part, causing the raft to become convex.", + "type": "bool", + "value": "raft_remove_inside_corners", + "default_value": false, + "resolve": "any(extruderValues('raft_remove_inside_corners'))", + "enabled": "resolveOrValue('adhesion_type') == 'raft'", + "settable_per_mesh": false, + "settable_per_extruder": false + }, + "raft_surface_remove_inside_corners": { + "label": "Remove Raft Top Inside Corners", + "description": "Remove inside corners from the raft top part, causing the raft to become convex.", + "type": "bool", + "value": "raft_remove_inside_corners", + "default_value": false, + "resolve": "any(extruderValues('raft_remove_inside_corners'))", + "enabled": "resolveOrValue('adhesion_type') == 'raft'", + "settable_per_mesh": false, + "settable_per_extruder": false + } + } }, "raft_base_wall_count": { diff --git a/resources/setting_visibility/expert.cfg b/resources/setting_visibility/expert.cfg index 2f2dd7671d..ebab2357dd 100644 --- a/resources/setting_visibility/expert.cfg +++ b/resources/setting_visibility/expert.cfg @@ -331,7 +331,13 @@ brim_line_count brim_outside_only brim_smart_ordering raft_margin +raft_base_margin +raft_interface_margin +raft_surface_margin raft_smoothing +raft_base_smoothing +raft_interface_smoothing +raft_surface_smoothing raft_airgap raft_surface_layers raft_surface_thickness @@ -467,3 +473,6 @@ small_hole_max_size small_feature_max_length small_feature_speed_factor small_feature_speed_factor_0 +raft_base_remove_inside_corners +raft_interface_remove_inside_corners +raft_surface_remove_inside_corners \ No newline at end of file From ff45f566d6ee27779fe01b3347c7239865bf1719 Mon Sep 17 00:00:00 2001 From: casperlamboo Date: Mon, 8 Jan 2024 13:46:14 +0000 Subject: [PATCH 59/73] Applied printer-linter format --- resources/definitions/fdmprinter.def.json | 36 +++++++++++++++-------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index b40e074f1c..ff09a16228 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -6115,8 +6115,10 @@ "limit_to_extruder": "adhesion_extruder_nr", "settable_per_mesh": false, "settable_per_extruder": true, - "children": { - "raft_base_margin": { + "children": + { + "raft_base_margin": + { "label": "Raft Base Extra Margin", "description": "If the raft base is enabled, this is the extra raft area around the model which is also given a raft. Increasing this margin will create a stronger raft while using more material and leaving less area for your print.", "unit": "mm", @@ -6130,7 +6132,8 @@ "settable_per_mesh": false, "settable_per_extruder": true }, - "raft_interface_margin": { + "raft_interface_margin": + { "label": "Raft Middle Extra Margin", "description": "If the raft middle is enabled, this is the extra raft area around the model which is also given a raft. Increasing this margin will create a stronger raft while using more material and leaving less area for your print.", "unit": "mm", @@ -6144,7 +6147,8 @@ "settable_per_mesh": false, "settable_per_extruder": true }, - "raft_surface_margin": { + "raft_surface_margin": + { "label": "Raft Top Extra Margin", "description": "If the raft top is enabled, this is the extra raft area around the model which is also given a raft. Increasing this margin will create a stronger raft while using more material and leaving less area for your print.", "unit": "mm", @@ -6173,8 +6177,10 @@ "limit_to_extruder": "adhesion_extruder_nr", "settable_per_mesh": false, "settable_per_extruder": true, - "children": { - "raft_base_smoothing": { + "children": + { + "raft_base_smoothing": + { "label": "Raft Base Smoothing", "description": "This setting controls how much inner corners in the raft base outline are rounded. Inward corners are rounded to a semi circle with a radius equal to the value given here. This setting also removes holes in the raft outline which are smaller than such a circle.", "unit": "mm", @@ -6188,7 +6194,8 @@ "settable_per_mesh": false, "settable_per_extruder": true }, - "raft_interface_smoothing": { + "raft_interface_smoothing": + { "label": "Raft Middle Smoothing", "description": "This setting controls how much inner corners in the raft middle outline are rounded. Inward corners are rounded to a semi circle with a radius equal to the value given here. This setting also removes holes in the raft outline which are smaller than such a circle.", "unit": "mm", @@ -6202,7 +6209,8 @@ "settable_per_mesh": false, "settable_per_extruder": true }, - "raft_surface_smoothing": { + "raft_surface_smoothing": + { "label": "Raft Top Smoothing", "description": "This setting controls how much inner corners in the raft top outline are rounded. Inward corners are rounded to a semi circle with a radius equal to the value given here. This setting also removes holes in the raft outline which are smaller than such a circle.", "unit": "mm", @@ -8373,8 +8381,10 @@ "enabled": "resolveOrValue('adhesion_type') == 'raft'", "settable_per_mesh": false, "settable_per_extruder": false, - "children": { - "raft_base_remove_inside_corners": { + "children": + { + "raft_base_remove_inside_corners": + { "label": "Remove Raft Base Inside Corners", "description": "Remove inside corners from the raft base, causing the raft to become convex.", "type": "bool", @@ -8385,7 +8395,8 @@ "settable_per_mesh": false, "settable_per_extruder": false }, - "raft_interface_remove_inside_corners": { + "raft_interface_remove_inside_corners": + { "label": "Remove Raft Middle Inside Corners", "description": "Remove inside corners from the raft middle part, causing the raft to become convex.", "type": "bool", @@ -8396,7 +8407,8 @@ "settable_per_mesh": false, "settable_per_extruder": false }, - "raft_surface_remove_inside_corners": { + "raft_surface_remove_inside_corners": + { "label": "Remove Raft Top Inside Corners", "description": "Remove inside corners from the raft top part, causing the raft to become convex.", "type": "bool", From 35131d5d7ce03b3ec7c5af4260b2baef43183382 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Mon, 8 Jan 2024 15:54:32 +0100 Subject: [PATCH 60/73] Inherit secrets for UT Fixes CURA-11497 --- .github/workflows/unit-test-post.yml | 1 + .github/workflows/unit-test.yml | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/unit-test-post.yml b/.github/workflows/unit-test-post.yml index eaf69692a7..a8e9f26b8b 100644 --- a/.github/workflows/unit-test-post.yml +++ b/.github/workflows/unit-test-post.yml @@ -11,3 +11,4 @@ jobs: with: event: ${{ github.event.workflow_run.event }} conclusion: ${{ github.event.workflow_run.conclusion }} + secrets: inherit diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 7c6910b39f..9a42f4f85d 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -58,4 +58,5 @@ jobs: conan_extra_args: '-g VirtualPythonEnv -o cura:devtools=True -c tools.build:skip_test=False' unit_test_cmd: 'pytest --junitxml=junit_cura.xml' unit_test_dir: 'tests' - conan_generator_dir: './venv/bin' \ No newline at end of file + conan_generator_dir: './venv/bin' + secrets: inherit \ No newline at end of file From 90ce6d7f765358c38308b46b4bcbcee3df01b2d6 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 8 Jan 2024 16:53:10 +0100 Subject: [PATCH 61/73] Reorganize raft settings to a user-intuitive order CURA-11228 --- resources/definitions/fdmprinter.def.json | 250 +++++++++++----------- 1 file changed, 125 insertions(+), 125 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 32908b6f3e..a49d613ce1 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -6159,66 +6159,53 @@ "settable_per_extruder": true, "limit_to_extruder": "raft_surface_extruder_nr" }, - "raft_surface_layers": + "raft_base_thickness": { - "label": "Raft Top Layers", - "description": "The number of top layers on top of the 2nd raft layer. These are fully filled layers that the model sits on. 2 layers result in a smoother top surface than 1.", - "type": "int", - "default_value": 2, - "minimum_value": "0", - "maximum_value_warning": "20", + "label": "Raft Base Thickness", + "description": "Layer thickness of the base raft layer. This should be a thick layer which sticks firmly to the printer build plate.", + "unit": "mm", + "type": "float", + "default_value": 0.3, + "value": "resolveOrValue('layer_height_0') * 1.2", + "minimum_value": "0.001", + "minimum_value_warning": "0.04", + "maximum_value_warning": "0.75 * raft_base_line_width", "enabled": "resolveOrValue('adhesion_type') == 'raft'", "settable_per_mesh": false, "settable_per_extruder": true, - "limit_to_extruder": "raft_surface_extruder_nr" + "limit_to_extruder": "raft_base_extruder_nr" }, - "raft_surface_thickness": + "raft_base_line_width": { - "label": "Raft Top Layer Thickness", - "description": "Layer thickness of the top raft layers.", + "label": "Raft Base Line Width", + "description": "Width of the lines in the base raft layer. These should be thick lines to assist in build plate adhesion.", "unit": "mm", "type": "float", - "default_value": 0.1, - "value": "resolveOrValue('layer_height')", + "default_value": 0.8, "minimum_value": "0.001", - "minimum_value_warning": "0.04", - "maximum_value_warning": "0.75 * machine_nozzle_size", - "enabled": "resolveOrValue('adhesion_type') == 'raft' and raft_surface_layers > 0", + "value": "machine_nozzle_size * 2", + "minimum_value_warning": "machine_nozzle_size * 0.5", + "maximum_value_warning": "machine_nozzle_size * 3", + "enabled": "resolveOrValue('adhesion_type') == 'raft'", "settable_per_mesh": false, "settable_per_extruder": true, - "limit_to_extruder": "raft_surface_extruder_nr" + "limit_to_extruder": "raft_base_extruder_nr" }, - "raft_surface_line_width": + "raft_base_line_spacing": { - "label": "Raft Top Line Width", - "description": "Width of the lines in the top surface of the raft. These can be thin lines so that the top of the raft becomes smooth.", + "label": "Raft Base Line Spacing", + "description": "The distance between the raft lines for the base raft layer. Wide spacing makes for easy removal of the raft from the build plate.", "unit": "mm", "type": "float", - "default_value": 0.4, - "value": "line_width", - "minimum_value": "0.001", - "minimum_value_warning": "machine_nozzle_size * 0.1", - "maximum_value_warning": "machine_nozzle_size * 2", - "enabled": "resolveOrValue('adhesion_type') == 'raft' and raft_surface_layers > 0", - "settable_per_mesh": false, - "settable_per_extruder": true, - "limit_to_extruder": "raft_surface_extruder_nr" - }, - "raft_surface_line_spacing": - { - "label": "Raft Top Spacing", - "description": "The distance between the raft lines for the top raft layers. The spacing should be equal to the line width, so that the surface is solid.", - "unit": "mm", - "type": "float", - "default_value": 0.4, + "default_value": 1.6, + "value": "raft_base_line_width * 2", "minimum_value": "0", - "minimum_value_warning": "raft_surface_line_width", - "maximum_value_warning": "raft_surface_line_width * 3", - "enabled": "resolveOrValue('adhesion_type') == 'raft' and raft_surface_layers > 0", - "value": "raft_surface_line_width", + "minimum_value_warning": "raft_base_line_width", + "maximum_value_warning": "100", + "enabled": "resolveOrValue('adhesion_type') == 'raft'", "settable_per_mesh": false, "settable_per_extruder": true, - "limit_to_extruder": "raft_surface_extruder_nr" + "limit_to_extruder": "raft_base_extruder_nr" }, "raft_interface_layers": { @@ -6281,53 +6268,66 @@ "settable_per_extruder": true, "limit_to_extruder": "raft_interface_extruder_nr" }, - "raft_base_thickness": + "raft_surface_layers": { - "label": "Raft Base Thickness", - "description": "Layer thickness of the base raft layer. This should be a thick layer which sticks firmly to the printer build plate.", + "label": "Raft Top Layers", + "description": "The number of top layers on top of the 2nd raft layer. These are fully filled layers that the model sits on. 2 layers result in a smoother top surface than 1.", + "type": "int", + "default_value": 2, + "minimum_value": "0", + "maximum_value_warning": "20", + "enabled": "resolveOrValue('adhesion_type') == 'raft'", + "settable_per_mesh": false, + "settable_per_extruder": true, + "limit_to_extruder": "raft_surface_extruder_nr" + }, + "raft_surface_thickness": + { + "label": "Raft Top Layer Thickness", + "description": "Layer thickness of the top raft layers.", "unit": "mm", "type": "float", - "default_value": 0.3, - "value": "resolveOrValue('layer_height_0') * 1.2", + "default_value": 0.1, + "value": "resolveOrValue('layer_height')", "minimum_value": "0.001", "minimum_value_warning": "0.04", - "maximum_value_warning": "0.75 * raft_base_line_width", - "enabled": "resolveOrValue('adhesion_type') == 'raft'", + "maximum_value_warning": "0.75 * machine_nozzle_size", + "enabled": "resolveOrValue('adhesion_type') == 'raft' and raft_surface_layers > 0", "settable_per_mesh": false, "settable_per_extruder": true, - "limit_to_extruder": "raft_base_extruder_nr" + "limit_to_extruder": "raft_surface_extruder_nr" }, - "raft_base_line_width": + "raft_surface_line_width": { - "label": "Raft Base Line Width", - "description": "Width of the lines in the base raft layer. These should be thick lines to assist in build plate adhesion.", + "label": "Raft Top Line Width", + "description": "Width of the lines in the top surface of the raft. These can be thin lines so that the top of the raft becomes smooth.", "unit": "mm", "type": "float", - "default_value": 0.8, + "default_value": 0.4, + "value": "line_width", "minimum_value": "0.001", - "value": "machine_nozzle_size * 2", - "minimum_value_warning": "machine_nozzle_size * 0.5", - "maximum_value_warning": "machine_nozzle_size * 3", - "enabled": "resolveOrValue('adhesion_type') == 'raft'", + "minimum_value_warning": "machine_nozzle_size * 0.1", + "maximum_value_warning": "machine_nozzle_size * 2", + "enabled": "resolveOrValue('adhesion_type') == 'raft' and raft_surface_layers > 0", "settable_per_mesh": false, "settable_per_extruder": true, - "limit_to_extruder": "raft_base_extruder_nr" + "limit_to_extruder": "raft_surface_extruder_nr" }, - "raft_base_line_spacing": + "raft_surface_line_spacing": { - "label": "Raft Base Line Spacing", - "description": "The distance between the raft lines for the base raft layer. Wide spacing makes for easy removal of the raft from the build plate.", + "label": "Raft Top Spacing", + "description": "The distance between the raft lines for the top raft layers. The spacing should be equal to the line width, so that the surface is solid.", "unit": "mm", "type": "float", - "default_value": 1.6, - "value": "raft_base_line_width * 2", + "default_value": 0.4, "minimum_value": "0", - "minimum_value_warning": "raft_base_line_width", - "maximum_value_warning": "100", - "enabled": "resolveOrValue('adhesion_type') == 'raft'", + "minimum_value_warning": "raft_surface_line_width", + "maximum_value_warning": "raft_surface_line_width * 3", + "enabled": "resolveOrValue('adhesion_type') == 'raft' and raft_surface_layers > 0", + "value": "raft_surface_line_width", "settable_per_mesh": false, "settable_per_extruder": true, - "limit_to_extruder": "raft_base_extruder_nr" + "limit_to_extruder": "raft_surface_extruder_nr" }, "raft_wall_count": { @@ -6341,12 +6341,13 @@ "settable_per_extruder": false, "children": { - "raft_surface_wall_count": + "raft_base_wall_count": { - "label": "Raft Top Wall Count", - "description": "The number of contours to print around the linear pattern in the top layers of the raft.", + "label": "Raft Base Wall Count", + "description": "The number of contours to print around the linear pattern in the base layer of the raft.", "type": "int", - "default_value": 0, + "default_value": 1, + "value": "raft_wall_count", "minimum_value": "0", "enabled": "resolveOrValue('adhesion_type') == 'raft'", "settable_per_mesh": false, @@ -6363,13 +6364,12 @@ "settable_per_mesh": false, "settable_per_extruder": false }, - "raft_base_wall_count": + "raft_surface_wall_count": { - "label": "Raft Base Wall Count", - "description": "The number of contours to print around the linear pattern in the base layer of the raft.", + "label": "Raft Top Wall Count", + "description": "The number of contours to print around the linear pattern in the top layers of the raft.", "type": "int", - "default_value": 1, - "value": "raft_wall_count", + "default_value": 0, "minimum_value": "0", "enabled": "resolveOrValue('adhesion_type') == 'raft'", "settable_per_mesh": false, @@ -6394,21 +6394,21 @@ "limit_to_extruder": "adhesion_extruder_nr", "children": { - "raft_surface_speed": + "raft_base_speed": { - "label": "Raft Top Print Speed", - "description": "The speed at which the top raft layers are printed. These should be printed a bit slower, so that the nozzle can slowly smooth out adjacent surface lines.", + "label": "Raft Base Print Speed", + "description": "The speed at which the base raft layer is printed. This should be printed quite slowly, as the volume of material coming out of the nozzle is quite high.", "unit": "mm/s", "type": "float", - "default_value": 20, + "default_value": 15, "minimum_value": "0.1", "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)", - "maximum_value_warning": "100", - "enabled": "resolveOrValue('adhesion_type') == 'raft' and raft_surface_layers > 0", - "value": "raft_speed", + "maximum_value_warning": "200", + "enabled": "resolveOrValue('adhesion_type') == 'raft'", + "value": "0.75 * raft_speed", "settable_per_mesh": false, "settable_per_extruder": true, - "limit_to_extruder": "raft_surface_extruder_nr" + "limit_to_extruder": "raft_base_extruder_nr" }, "raft_interface_speed": { @@ -6426,21 +6426,21 @@ "settable_per_extruder": true, "limit_to_extruder": "raft_interface_extruder_nr" }, - "raft_base_speed": + "raft_surface_speed": { - "label": "Raft Base Print Speed", - "description": "The speed at which the base raft layer is printed. This should be printed quite slowly, as the volume of material coming out of the nozzle is quite high.", + "label": "Raft Top Print Speed", + "description": "The speed at which the top raft layers are printed. These should be printed a bit slower, so that the nozzle can slowly smooth out adjacent surface lines.", "unit": "mm/s", "type": "float", - "default_value": 15, + "default_value": 20, "minimum_value": "0.1", "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)", - "maximum_value_warning": "200", - "enabled": "resolveOrValue('adhesion_type') == 'raft'", - "value": "0.75 * raft_speed", + "maximum_value_warning": "100", + "enabled": "resolveOrValue('adhesion_type') == 'raft' and raft_surface_layers > 0", + "value": "raft_speed", "settable_per_mesh": false, "settable_per_extruder": true, - "limit_to_extruder": "raft_base_extruder_nr" + "limit_to_extruder": "raft_surface_extruder_nr" } } }, @@ -6460,10 +6460,10 @@ "limit_to_extruder": "adhesion_extruder_nr", "children": { - "raft_surface_acceleration": + "raft_base_acceleration": { - "label": "Raft Top Print Acceleration", - "description": "The acceleration with which the top raft layers are printed.", + "label": "Raft Base Print Acceleration", + "description": "The acceleration with which the base raft layer is printed.", "unit": "mm/s\u00b2", "type": "float", "default_value": 3000, @@ -6471,9 +6471,9 @@ "minimum_value": "0.1", "minimum_value_warning": "100", "maximum_value_warning": "10000", - "enabled": "resolveOrValue('adhesion_type') == 'raft' and resolveOrValue('acceleration_enabled') and raft_surface_layers > 0", + "enabled": "resolveOrValue('adhesion_type') == 'raft' and resolveOrValue('acceleration_enabled')", "settable_per_mesh": false, - "limit_to_extruder": "raft_surface_extruder_nr" + "limit_to_extruder": "raft_base_extruder_nr" }, "raft_interface_acceleration": { @@ -6490,10 +6490,10 @@ "settable_per_mesh": false, "limit_to_extruder": "raft_interface_extruder_nr" }, - "raft_base_acceleration": + "raft_surface_acceleration": { - "label": "Raft Base Print Acceleration", - "description": "The acceleration with which the base raft layer is printed.", + "label": "Raft Top Print Acceleration", + "description": "The acceleration with which the top raft layers are printed.", "unit": "mm/s\u00b2", "type": "float", "default_value": 3000, @@ -6501,9 +6501,9 @@ "minimum_value": "0.1", "minimum_value_warning": "100", "maximum_value_warning": "10000", - "enabled": "resolveOrValue('adhesion_type') == 'raft' and resolveOrValue('acceleration_enabled')", + "enabled": "resolveOrValue('adhesion_type') == 'raft' and resolveOrValue('acceleration_enabled') and raft_surface_layers > 0", "settable_per_mesh": false, - "limit_to_extruder": "raft_base_extruder_nr" + "limit_to_extruder": "raft_surface_extruder_nr" } } }, @@ -6523,20 +6523,20 @@ "limit_to_extruder": "adhesion_extruder_nr", "children": { - "raft_surface_jerk": + "raft_base_jerk": { - "label": "Raft Top Print Jerk", - "description": "The jerk with which the top raft layers are printed.", + "label": "Raft Base Print Jerk", + "description": "The jerk with which the base raft layer is printed.", "unit": "mm/s", "type": "float", "default_value": 20, "value": "raft_jerk", "minimum_value": "0", "minimum_value_warning": "5", - "maximum_value_warning": "100", - "enabled": "resolveOrValue('adhesion_type') == 'raft' and resolveOrValue('jerk_enabled') and raft_surface_layers > 0", + "maximum_value_warning": "50", + "enabled": "resolveOrValue('adhesion_type') == 'raft' and resolveOrValue('jerk_enabled')", "settable_per_mesh": false, - "limit_to_extruder": "raft_surface_extruder_nr" + "limit_to_extruder": "raft_base_extruder_nr" }, "raft_interface_jerk": { @@ -6553,20 +6553,20 @@ "settable_per_mesh": false, "limit_to_extruder": "raft_interface_extruder_nr" }, - "raft_base_jerk": + "raft_surface_jerk": { - "label": "Raft Base Print Jerk", - "description": "The jerk with which the base raft layer is printed.", + "label": "Raft Top Print Jerk", + "description": "The jerk with which the top raft layers are printed.", "unit": "mm/s", "type": "float", "default_value": 20, "value": "raft_jerk", "minimum_value": "0", "minimum_value_warning": "5", - "maximum_value_warning": "50", - "enabled": "resolveOrValue('adhesion_type') == 'raft' and resolveOrValue('jerk_enabled')", + "maximum_value_warning": "100", + "enabled": "resolveOrValue('adhesion_type') == 'raft' and resolveOrValue('jerk_enabled') and raft_surface_layers > 0", "settable_per_mesh": false, - "limit_to_extruder": "raft_base_extruder_nr" + "limit_to_extruder": "raft_surface_extruder_nr" } } }, @@ -6585,20 +6585,20 @@ "limit_to_extruder": "adhesion_extruder_nr", "children": { - "raft_surface_fan_speed": + "raft_base_fan_speed": { - "label": "Raft Top Fan Speed", - "description": "The fan speed for the top raft layers.", + "label": "Raft Base Fan Speed", + "description": "The fan speed for the base raft layer.", "unit": "%", "type": "float", "minimum_value": "0", "maximum_value": "100", "default_value": 0, "value": "raft_fan_speed", - "enabled": "resolveOrValue('adhesion_type') == 'raft' and raft_surface_layers > 0", + "enabled": "resolveOrValue('adhesion_type') == 'raft'", "settable_per_mesh": false, "settable_per_extruder": true, - "limit_to_extruder": "raft_surface_extruder_nr" + "limit_to_extruder": "raft_base_extruder_nr" }, "raft_interface_fan_speed": { @@ -6615,20 +6615,20 @@ "settable_per_extruder": true, "limit_to_extruder": "raft_interface_extruder_nr" }, - "raft_base_fan_speed": + "raft_surface_fan_speed": { - "label": "Raft Base Fan Speed", - "description": "The fan speed for the base raft layer.", + "label": "Raft Top Fan Speed", + "description": "The fan speed for the top raft layers.", "unit": "%", "type": "float", "minimum_value": "0", "maximum_value": "100", "default_value": 0, "value": "raft_fan_speed", - "enabled": "resolveOrValue('adhesion_type') == 'raft'", + "enabled": "resolveOrValue('adhesion_type') == 'raft' and raft_surface_layers > 0", "settable_per_mesh": false, "settable_per_extruder": true, - "limit_to_extruder": "raft_base_extruder_nr" + "limit_to_extruder": "raft_surface_extruder_nr" } } } From 023a8f232588ce6c5fd84adf57960caabc99a210 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Tue, 9 Jan 2024 08:32:33 +0100 Subject: [PATCH 62/73] Ensure that nightlies have default values Fixes CURA-11528 --- .github/workflows/installers.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/installers.yml b/.github/workflows/installers.yml index 9c51cfe820..29ff24c2b5 100644 --- a/.github/workflows/installers.yml +++ b/.github/workflows/installers.yml @@ -54,9 +54,9 @@ jobs: needs: [ default_values ] with: cura_conan_version: ${{ needs.default_values.outputs.cura_conan_version }} - conan_args: ${{ inputs.conan_args }} - enterprise: ${{ inputs.enterprise }} - staging: ${{ inputs.staging }} + conan_args: ${{ env.CONAN_ARGS }} + enterprise: ${{ env.ENTERPRISE }} + staging: ${{ env.STAGING }} architecture: X64 operating_system: windows-2022 secrets: inherit @@ -66,9 +66,9 @@ jobs: needs: [ default_values ] with: cura_conan_version: ${{ needs.default_values.outputs.cura_conan_version }} - conan_args: ${{ inputs.conan_args }} - enterprise: ${{ inputs.enterprise }} - staging: ${{ inputs.staging }} + conan_args: ${{ env.CONAN_ARGS }} + enterprise: ${{ env.ENTERPRISE }} + staging: ${{ env.STAGING }} architecture: X64 operating_system: ubuntu-22.04 secrets: inherit @@ -78,9 +78,9 @@ jobs: needs: [ default_values ] with: cura_conan_version: ${{ needs.default_values.outputs.cura_conan_version }} - conan_args: ${{ inputs.conan_args }} - enterprise: ${{ inputs.enterprise }} - staging: ${{ inputs.staging }} + conan_args: ${{ env.CONAN_ARGS }} + enterprise: ${{ env.ENTERPRISE }} + staging: ${{ env.STAGING }} architecture: X64 operating_system: self-hosted-X64 secrets: inherit @@ -90,9 +90,9 @@ jobs: needs: [ default_values ] with: cura_conan_version: ${{ needs.default_values.outputs.cura_conan_version }} - conan_args: ${{ inputs.conan_args }} - enterprise: ${{ inputs.enterprise }} - staging: ${{ inputs.staging }} + conan_args: ${{ env.CONAN_ARGS }} + enterprise: ${{ env.ENTERPRISE }} + staging: ${{ env.STAGING }} architecture: ARM64 operating_system: self-hosted-ARM64 secrets: inherit From 7244ba4e24d516a97ea04f558a239ef3d747179e Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Tue, 9 Jan 2024 08:38:17 +0100 Subject: [PATCH 63/73] Revert "Ensure that nightlies have default values" This reverts commit 023a8f232588ce6c5fd84adf57960caabc99a210. --- .github/workflows/installers.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/installers.yml b/.github/workflows/installers.yml index 29ff24c2b5..9c51cfe820 100644 --- a/.github/workflows/installers.yml +++ b/.github/workflows/installers.yml @@ -54,9 +54,9 @@ jobs: needs: [ default_values ] with: cura_conan_version: ${{ needs.default_values.outputs.cura_conan_version }} - conan_args: ${{ env.CONAN_ARGS }} - enterprise: ${{ env.ENTERPRISE }} - staging: ${{ env.STAGING }} + conan_args: ${{ inputs.conan_args }} + enterprise: ${{ inputs.enterprise }} + staging: ${{ inputs.staging }} architecture: X64 operating_system: windows-2022 secrets: inherit @@ -66,9 +66,9 @@ jobs: needs: [ default_values ] with: cura_conan_version: ${{ needs.default_values.outputs.cura_conan_version }} - conan_args: ${{ env.CONAN_ARGS }} - enterprise: ${{ env.ENTERPRISE }} - staging: ${{ env.STAGING }} + conan_args: ${{ inputs.conan_args }} + enterprise: ${{ inputs.enterprise }} + staging: ${{ inputs.staging }} architecture: X64 operating_system: ubuntu-22.04 secrets: inherit @@ -78,9 +78,9 @@ jobs: needs: [ default_values ] with: cura_conan_version: ${{ needs.default_values.outputs.cura_conan_version }} - conan_args: ${{ env.CONAN_ARGS }} - enterprise: ${{ env.ENTERPRISE }} - staging: ${{ env.STAGING }} + conan_args: ${{ inputs.conan_args }} + enterprise: ${{ inputs.enterprise }} + staging: ${{ inputs.staging }} architecture: X64 operating_system: self-hosted-X64 secrets: inherit @@ -90,9 +90,9 @@ jobs: needs: [ default_values ] with: cura_conan_version: ${{ needs.default_values.outputs.cura_conan_version }} - conan_args: ${{ env.CONAN_ARGS }} - enterprise: ${{ env.ENTERPRISE }} - staging: ${{ env.STAGING }} + conan_args: ${{ inputs.conan_args }} + enterprise: ${{ inputs.enterprise }} + staging: ${{ inputs.staging }} architecture: ARM64 operating_system: self-hosted-ARM64 secrets: inherit From 76b93c31719822916507560069e19f15fe6639ab Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Tue, 9 Jan 2024 08:40:30 +0100 Subject: [PATCH 64/73] Revert "use `input` instead of the `github.events`" This reverts commit 677f35b5159e53fded2d4c31b2ca58ede6b28373. --- .github/workflows/installers.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/installers.yml b/.github/workflows/installers.yml index 9c51cfe820..6e531ba833 100644 --- a/.github/workflows/installers.yml +++ b/.github/workflows/installers.yml @@ -54,9 +54,9 @@ jobs: needs: [ default_values ] with: cura_conan_version: ${{ needs.default_values.outputs.cura_conan_version }} - conan_args: ${{ inputs.conan_args }} - enterprise: ${{ inputs.enterprise }} - staging: ${{ inputs.staging }} + conan_args: ${{ github.event.inputs.conan_args }} + enterprise: ${{ github.event.inputs.enterprise == 'true' }} + staging: ${{ github.event.inputs.staging == 'true' }} architecture: X64 operating_system: windows-2022 secrets: inherit @@ -66,9 +66,9 @@ jobs: needs: [ default_values ] with: cura_conan_version: ${{ needs.default_values.outputs.cura_conan_version }} - conan_args: ${{ inputs.conan_args }} - enterprise: ${{ inputs.enterprise }} - staging: ${{ inputs.staging }} + conan_args: ${{ github.event.inputs.conan_args }} + enterprise: ${{ github.event.inputs.enterprise == 'true' }} + staging: ${{ github.event.inputs.staging == 'true' }} architecture: X64 operating_system: ubuntu-22.04 secrets: inherit @@ -78,9 +78,9 @@ jobs: needs: [ default_values ] with: cura_conan_version: ${{ needs.default_values.outputs.cura_conan_version }} - conan_args: ${{ inputs.conan_args }} - enterprise: ${{ inputs.enterprise }} - staging: ${{ inputs.staging }} + conan_args: ${{ github.event.inputs.conan_args }} + enterprise: ${{ github.event.inputs.enterprise == 'true' }} + staging: ${{ github.event.inputs.staging == 'true' }} architecture: X64 operating_system: self-hosted-X64 secrets: inherit @@ -90,9 +90,9 @@ jobs: needs: [ default_values ] with: cura_conan_version: ${{ needs.default_values.outputs.cura_conan_version }} - conan_args: ${{ inputs.conan_args }} - enterprise: ${{ inputs.enterprise }} - staging: ${{ inputs.staging }} + conan_args: ${{ github.event.inputs.conan_args }} + enterprise: ${{ github.event.inputs.enterprise == 'true' }} + staging: ${{ github.event.inputs.staging == 'true' }} architecture: ARM64 operating_system: self-hosted-ARM64 secrets: inherit From 37f350b134d69518ef6455f214f152e4e04737b6 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Tue, 9 Jan 2024 10:15:17 +0100 Subject: [PATCH 65/73] Limit settings to their correct extruders --- resources/definitions/fdmprinter.def.json | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 95588c2f24..3253e25cf3 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -6128,7 +6128,7 @@ "minimum_value_warning": "raft_interface_line_width", "maximum_value_warning": "20", "enabled": "resolveOrValue('adhesion_type') == 'raft'", - "limit_to_extruder": "adhesion_extruder_nr", + "limit_to_extruder": "raft_base_extruder_nr", "settable_per_mesh": false, "settable_per_extruder": true }, @@ -6143,7 +6143,7 @@ "minimum_value_warning": "raft_interface_line_width", "maximum_value_warning": "20", "enabled": "resolveOrValue('adhesion_type') == 'raft'", - "limit_to_extruder": "adhesion_extruder_nr", + "limit_to_extruder": "raft_interface_extruder_nr", "settable_per_mesh": false, "settable_per_extruder": true }, @@ -6158,7 +6158,7 @@ "minimum_value_warning": "raft_interface_line_width", "maximum_value_warning": "20", "enabled": "resolveOrValue('adhesion_type') == 'raft'", - "limit_to_extruder": "adhesion_extruder_nr", + "limit_to_extruder": "raft_surface_extruder_nr", "settable_per_mesh": false, "settable_per_extruder": true } @@ -6190,7 +6190,7 @@ "minimum_value": "0", "minimum_value_warning": "raft_interface_line_width", "enabled": "resolveOrValue('adhesion_type') == 'raft' and not raft_base_remove_inside_corners", - "limit_to_extruder": "adhesion_extruder_nr", + "limit_to_extruder": "raft_base_extruder_nr", "settable_per_mesh": false, "settable_per_extruder": true }, @@ -6205,7 +6205,7 @@ "minimum_value": "0", "minimum_value_warning": "raft_interface_line_width", "enabled": "resolveOrValue('adhesion_type') == 'raft' and not raft_interface_remove_inside_corners", - "limit_to_extruder": "adhesion_extruder_nr", + "limit_to_extruder": "raft_interface_extruder_nr", "settable_per_mesh": false, "settable_per_extruder": true }, @@ -6220,7 +6220,7 @@ "minimum_value": "0", "minimum_value_warning": "raft_interface_line_width", "enabled": "resolveOrValue('adhesion_type') == 'raft' and not raft_surface_remove_inside_corners", - "limit_to_extruder": "adhesion_extruder_nr", + "limit_to_extruder": "raft_surface_extruder_nr", "settable_per_mesh": false, "settable_per_extruder": true } @@ -8440,6 +8440,7 @@ "default_value": false, "resolve": "any(extruderValues('raft_remove_inside_corners'))", "enabled": "resolveOrValue('adhesion_type') == 'raft'", + "limit_to_extruder": "raft_base_extruder_nr", "settable_per_mesh": false, "settable_per_extruder": false }, @@ -8452,6 +8453,7 @@ "default_value": false, "resolve": "any(extruderValues('raft_remove_inside_corners'))", "enabled": "resolveOrValue('adhesion_type') == 'raft'", + "limit_to_extruder": "raft_interface_extruder_nr", "settable_per_mesh": false, "settable_per_extruder": false }, @@ -8464,6 +8466,7 @@ "default_value": false, "resolve": "any(extruderValues('raft_remove_inside_corners'))", "enabled": "resolveOrValue('adhesion_type') == 'raft'", + "limit_to_extruder": "raft_surface_extruder_nr", "settable_per_mesh": false, "settable_per_extruder": false } From af51ccf5f37c5fdaf93bf31de307c5d3678f3691 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Tue, 9 Jan 2024 10:17:10 +0100 Subject: [PATCH 66/73] Move "Remove Raft Inside Corners" outside experimental --- resources/definitions/fdmprinter.def.json | 101 ++++++++++------------ 1 file changed, 48 insertions(+), 53 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 3253e25cf3..ce165d1f3d 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -6164,6 +6164,54 @@ } } }, + "raft_remove_inside_corners": { + "label": "Remove Raft Inside Corners", + "description": "Remove inside corners from the raft, causing the raft to become convex.", + "type": "bool", + "default_value": false, + "resolve": "any(extruderValues('raft_remove_inside_corners'))", + "enabled": "resolveOrValue('adhesion_type') == 'raft'", + "settable_per_mesh": false, + "settable_per_extruder": false, + "children": { + "raft_base_remove_inside_corners": { + "label": "Remove Raft Base Inside Corners", + "description": "Remove inside corners from the raft base, causing the raft to become convex.", + "type": "bool", + "value": "raft_remove_inside_corners", + "default_value": false, + "resolve": "any(extruderValues('raft_remove_inside_corners'))", + "enabled": "resolveOrValue('adhesion_type') == 'raft'", + "limit_to_extruder": "raft_base_extruder_nr", + "settable_per_mesh": false, + "settable_per_extruder": false + }, + "raft_interface_remove_inside_corners": { + "label": "Remove Raft Middle Inside Corners", + "description": "Remove inside corners from the raft middle part, causing the raft to become convex.", + "type": "bool", + "value": "raft_remove_inside_corners", + "default_value": false, + "resolve": "any(extruderValues('raft_remove_inside_corners'))", + "enabled": "resolveOrValue('adhesion_type') == 'raft'", + "limit_to_extruder": "raft_interface_extruder_nr", + "settable_per_mesh": false, + "settable_per_extruder": false + }, + "raft_surface_remove_inside_corners": { + "label": "Remove Raft Top Inside Corners", + "description": "Remove inside corners from the raft top part, causing the raft to become convex.", + "type": "bool", + "value": "raft_remove_inside_corners", + "default_value": false, + "resolve": "any(extruderValues('raft_remove_inside_corners'))", + "enabled": "resolveOrValue('adhesion_type') == 'raft'", + "limit_to_extruder": "raft_surface_extruder_nr", + "settable_per_mesh": false, + "settable_per_extruder": false + } + } + }, "raft_smoothing": { "label": "Raft Smoothing", @@ -8419,59 +8467,6 @@ "settable_per_mesh": true, "settable_per_extruder": true }, - "raft_remove_inside_corners": - { - "label": "Remove Raft Inside Corners", - "description": "Remove inside corners from the raft, causing the raft to become convex.", - "type": "bool", - "default_value": false, - "resolve": "any(extruderValues('raft_remove_inside_corners'))", - "enabled": "resolveOrValue('adhesion_type') == 'raft'", - "settable_per_mesh": false, - "settable_per_extruder": false, - "children": - { - "raft_base_remove_inside_corners": - { - "label": "Remove Raft Base Inside Corners", - "description": "Remove inside corners from the raft base, causing the raft to become convex.", - "type": "bool", - "value": "raft_remove_inside_corners", - "default_value": false, - "resolve": "any(extruderValues('raft_remove_inside_corners'))", - "enabled": "resolveOrValue('adhesion_type') == 'raft'", - "limit_to_extruder": "raft_base_extruder_nr", - "settable_per_mesh": false, - "settable_per_extruder": false - }, - "raft_interface_remove_inside_corners": - { - "label": "Remove Raft Middle Inside Corners", - "description": "Remove inside corners from the raft middle part, causing the raft to become convex.", - "type": "bool", - "value": "raft_remove_inside_corners", - "default_value": false, - "resolve": "any(extruderValues('raft_remove_inside_corners'))", - "enabled": "resolveOrValue('adhesion_type') == 'raft'", - "limit_to_extruder": "raft_interface_extruder_nr", - "settable_per_mesh": false, - "settable_per_extruder": false - }, - "raft_surface_remove_inside_corners": - { - "label": "Remove Raft Top Inside Corners", - "description": "Remove inside corners from the raft top part, causing the raft to become convex.", - "type": "bool", - "value": "raft_remove_inside_corners", - "default_value": false, - "resolve": "any(extruderValues('raft_remove_inside_corners'))", - "enabled": "resolveOrValue('adhesion_type') == 'raft'", - "limit_to_extruder": "raft_surface_extruder_nr", - "settable_per_mesh": false, - "settable_per_extruder": false - } - } - }, "group_outer_walls": { "label": "Group Outer Walls", From 594e4a5ea67fc0266783dfe8052f2b3a8b0191cc Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Tue, 9 Jan 2024 10:18:22 +0100 Subject: [PATCH 67/73] Warn if raft extra margin exceeds raft margin of layer below --- resources/definitions/fdmprinter.def.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index ce165d1f3d..48321bae2f 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -6126,7 +6126,7 @@ "value": "raft_margin", "default_value": 15, "minimum_value_warning": "raft_interface_line_width", - "maximum_value_warning": "20", + "maximum_value_warning": "min(raft_interface_margin, 20)", "enabled": "resolveOrValue('adhesion_type') == 'raft'", "limit_to_extruder": "raft_base_extruder_nr", "settable_per_mesh": false, @@ -6141,7 +6141,7 @@ "value": "raft_margin", "default_value": 15, "minimum_value_warning": "raft_interface_line_width", - "maximum_value_warning": "20", + "maximum_value_warning": "min(raft_surface_margin, 20)", "enabled": "resolveOrValue('adhesion_type') == 'raft'", "limit_to_extruder": "raft_interface_extruder_nr", "settable_per_mesh": false, From 4489b8db462e28777e24947fbcc09517566ecfe2 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Tue, 9 Jan 2024 10:21:55 +0100 Subject: [PATCH 68/73] Make expert more consistent Only include parent settings --- resources/setting_visibility/expert.cfg | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/resources/setting_visibility/expert.cfg b/resources/setting_visibility/expert.cfg index 7f72dfe8ab..ab0d2aa920 100644 --- a/resources/setting_visibility/expert.cfg +++ b/resources/setting_visibility/expert.cfg @@ -331,10 +331,8 @@ brim_line_count brim_outside_only brim_smart_ordering raft_margin -raft_base_margin -raft_interface_margin -raft_surface_margin raft_smoothing +raft_remove_inside_corners raft_base_smoothing raft_interface_smoothing raft_surface_smoothing @@ -474,6 +472,3 @@ small_hole_max_size small_feature_max_length small_feature_speed_factor small_feature_speed_factor_0 -raft_base_remove_inside_corners -raft_interface_remove_inside_corners -raft_surface_remove_inside_corners \ No newline at end of file From d9feb88b24836d4015365f953b132fbc0528216d Mon Sep 17 00:00:00 2001 From: casperlamboo Date: Tue, 9 Jan 2024 09:22:53 +0000 Subject: [PATCH 69/73] Applied printer-linter format --- resources/definitions/fdmprinter.def.json | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 48321bae2f..af041bd803 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -6164,7 +6164,8 @@ } } }, - "raft_remove_inside_corners": { + "raft_remove_inside_corners": + { "label": "Remove Raft Inside Corners", "description": "Remove inside corners from the raft, causing the raft to become convex.", "type": "bool", @@ -6173,8 +6174,10 @@ "enabled": "resolveOrValue('adhesion_type') == 'raft'", "settable_per_mesh": false, "settable_per_extruder": false, - "children": { - "raft_base_remove_inside_corners": { + "children": + { + "raft_base_remove_inside_corners": + { "label": "Remove Raft Base Inside Corners", "description": "Remove inside corners from the raft base, causing the raft to become convex.", "type": "bool", @@ -6186,7 +6189,8 @@ "settable_per_mesh": false, "settable_per_extruder": false }, - "raft_interface_remove_inside_corners": { + "raft_interface_remove_inside_corners": + { "label": "Remove Raft Middle Inside Corners", "description": "Remove inside corners from the raft middle part, causing the raft to become convex.", "type": "bool", @@ -6198,7 +6202,8 @@ "settable_per_mesh": false, "settable_per_extruder": false }, - "raft_surface_remove_inside_corners": { + "raft_surface_remove_inside_corners": + { "label": "Remove Raft Top Inside Corners", "description": "Remove inside corners from the raft top part, causing the raft to become convex.", "type": "bool", From 1f7b8efff0d7369ae576410d86c0c1ff15e087e6 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Tue, 9 Jan 2024 16:26:14 +0100 Subject: [PATCH 70/73] Don't make `raft_smoothing` settable per extruder CURA-11395 --- resources/definitions/fdmprinter.def.json | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index af041bd803..0bdfa7c602 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -6196,7 +6196,6 @@ "type": "bool", "value": "raft_remove_inside_corners", "default_value": false, - "resolve": "any(extruderValues('raft_remove_inside_corners'))", "enabled": "resolveOrValue('adhesion_type') == 'raft'", "limit_to_extruder": "raft_interface_extruder_nr", "settable_per_mesh": false, @@ -6229,7 +6228,7 @@ "enabled": "resolveOrValue('adhesion_type') == 'raft' and not raft_remove_inside_corners", "limit_to_extruder": "adhesion_extruder_nr", "settable_per_mesh": false, - "settable_per_extruder": true, + "settable_per_extruder": false, "children": { "raft_base_smoothing": @@ -6245,7 +6244,7 @@ "enabled": "resolveOrValue('adhesion_type') == 'raft' and not raft_base_remove_inside_corners", "limit_to_extruder": "raft_base_extruder_nr", "settable_per_mesh": false, - "settable_per_extruder": true + "settable_per_extruder": false }, "raft_interface_smoothing": { @@ -6260,7 +6259,7 @@ "enabled": "resolveOrValue('adhesion_type') == 'raft' and not raft_interface_remove_inside_corners", "limit_to_extruder": "raft_interface_extruder_nr", "settable_per_mesh": false, - "settable_per_extruder": true + "settable_per_extruder": false }, "raft_surface_smoothing": { @@ -6275,7 +6274,7 @@ "enabled": "resolveOrValue('adhesion_type') == 'raft' and not raft_surface_remove_inside_corners", "limit_to_extruder": "raft_surface_extruder_nr", "settable_per_mesh": false, - "settable_per_extruder": true + "settable_per_extruder": false } } }, From 30b25975df64990c3ac063699f4b56587ebe7dc8 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Tue, 9 Jan 2024 16:38:57 +0100 Subject: [PATCH 71/73] Make settings not settable par extruder CURA-11395 --- resources/definitions/fdmprinter.def.json | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 0bdfa7c602..8531fdcbe3 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -6170,7 +6170,6 @@ "description": "Remove inside corners from the raft, causing the raft to become convex.", "type": "bool", "default_value": false, - "resolve": "any(extruderValues('raft_remove_inside_corners'))", "enabled": "resolveOrValue('adhesion_type') == 'raft'", "settable_per_mesh": false, "settable_per_extruder": false, @@ -6183,9 +6182,7 @@ "type": "bool", "value": "raft_remove_inside_corners", "default_value": false, - "resolve": "any(extruderValues('raft_remove_inside_corners'))", "enabled": "resolveOrValue('adhesion_type') == 'raft'", - "limit_to_extruder": "raft_base_extruder_nr", "settable_per_mesh": false, "settable_per_extruder": false }, @@ -6197,7 +6194,6 @@ "value": "raft_remove_inside_corners", "default_value": false, "enabled": "resolveOrValue('adhesion_type') == 'raft'", - "limit_to_extruder": "raft_interface_extruder_nr", "settable_per_mesh": false, "settable_per_extruder": false }, @@ -6208,9 +6204,7 @@ "type": "bool", "value": "raft_remove_inside_corners", "default_value": false, - "resolve": "any(extruderValues('raft_remove_inside_corners'))", "enabled": "resolveOrValue('adhesion_type') == 'raft'", - "limit_to_extruder": "raft_surface_extruder_nr", "settable_per_mesh": false, "settable_per_extruder": false } @@ -6226,7 +6220,6 @@ "minimum_value": "0", "minimum_value_warning": "raft_interface_line_width", "enabled": "resolveOrValue('adhesion_type') == 'raft' and not raft_remove_inside_corners", - "limit_to_extruder": "adhesion_extruder_nr", "settable_per_mesh": false, "settable_per_extruder": false, "children": @@ -6242,7 +6235,6 @@ "minimum_value": "0", "minimum_value_warning": "raft_interface_line_width", "enabled": "resolveOrValue('adhesion_type') == 'raft' and not raft_base_remove_inside_corners", - "limit_to_extruder": "raft_base_extruder_nr", "settable_per_mesh": false, "settable_per_extruder": false }, @@ -6257,7 +6249,6 @@ "minimum_value": "0", "minimum_value_warning": "raft_interface_line_width", "enabled": "resolveOrValue('adhesion_type') == 'raft' and not raft_interface_remove_inside_corners", - "limit_to_extruder": "raft_interface_extruder_nr", "settable_per_mesh": false, "settable_per_extruder": false }, @@ -6272,7 +6263,6 @@ "minimum_value": "0", "minimum_value_warning": "raft_interface_line_width", "enabled": "resolveOrValue('adhesion_type') == 'raft' and not raft_surface_remove_inside_corners", - "limit_to_extruder": "raft_surface_extruder_nr", "settable_per_mesh": false, "settable_per_extruder": false } From 2ad2afd1f41b70acffa0674cd53afa315d05cef2 Mon Sep 17 00:00:00 2001 From: GregValiant <64202104+GregValiant@users.noreply.github.com> Date: Tue, 9 Jan 2024 19:55:03 +0100 Subject: [PATCH 72/73] Update 'Advanced Cooling Fan Control' post-processing script. See discussions in #15853 (on github) and (internally) tracking-ticket CURA-11520 --- .../scripts/AddCoolingProfile.py | 258 ++++++++---------- 1 file changed, 108 insertions(+), 150 deletions(-) diff --git a/plugins/PostProcessingPlugin/scripts/AddCoolingProfile.py b/plugins/PostProcessingPlugin/scripts/AddCoolingProfile.py index 6f9ac2dc13..44709afd24 100644 --- a/plugins/PostProcessingPlugin/scripts/AddCoolingProfile.py +++ b/plugins/PostProcessingPlugin/scripts/AddCoolingProfile.py @@ -1,17 +1,16 @@ -# January 2023 by GregValiant (Greg Foresi). -# Functions: -# Remove all fan speed lines from the file (optional). -# Enter new M106 lines "By Layer" or "By Feature" (;TYPE:WALL-OUTER, etc.). -# A Starting layer and/or an Ending layer can be defined. -# Fan speeds are scaled PWM (0 - 255) or RepRap (0 - 1) depending on {machine_scale_fan_speed_zero_to_one}. -# A minimum fan speed of 12% is enforced. -# If multiple extruders have separate fan circuits the speeds are set at tool changes and conform to the layer or -# feature setting. There is support for up to 4 layer cooling fan circuits. -# The option for whether or not to remove the existing M106 lines is added to allow multiple instances of this post-processor to be installed without the followup instances wiping out the insertions of previous instances. 1/3 of a file can be 'By Layer' and the second third 'By Feature', and end up with 'By Layer' again. -# My design intent was to make it as full featured and "industrial strength" as I could. -# My thanks to @5axes, @fieldOfView(@AHoeben), @Ghostkeeper, and @Torgeir. -# 9/14/23 added support for One-at-a-Time and removed the kick out code -# 12/15/23 split off some functions. Revised the regex replacements. +# Designed in January 2023 by GregValiant (Greg Foresi) +## My design intent was to make this as full featured and "industrial strength" as I could. People printing exotic materials on large custom printers may want to turn the fans off for certain layers, and then back on again later in the print. This script allows that. +# Functions: +## Remove all fan speed lines from the file (optional). This should be enabled for the first instance of the script. It is disabled by default in any following instances. +## "By Layer" allows the user to adjust the fan speed up, or down, or off, within the print. "By Feature" allows different fan speeds for different features (;TYPE:WALL-OUTER, etc.). +## If 'By Feature' then a Start Layer and/or an End Layer can be defined. +## Fan speeds are scaled PWM (0 - 255) or RepRap (0.0 - 1.0) depending on {machine_scale_fan_speed_zero_to_one}. +## A minimum fan speed of 12% is enforced. It is the slowest speed that my cooling fan will turn on so that's what I used. 'M106 S14' (as Cura might insert) was pretty useless. +## If multiple extruders have separate fan circuits the speeds are set at tool changes and conform to the layer or feature setting. There is support for up to 4 layer cooling fan circuits. +## My thanks to @5axes(@CUQ), @fieldOfView(@AHoeben), @Ghostkeeper, and @Torgeir. A special thanks to @RBurema for his patience in reviewing my 'non-pythonic' script. +## 9/14/23 (Greg Foresi) Added support for One-at-a-Time print sequence. +## 12/15/23 (Greg Foresi) Split off 'Single Fan By Layer', 'Multi-fan By Layer', 'Single Fan By Feature', and 'Multi-fan By Feature' from the main 'execute' script. +## 1/5/24 (Greg Foresi) Revised the regex replacements. from ..Script import Script from UM.Application import Application @@ -40,10 +39,11 @@ class AddCoolingProfile(Script): "delete_existing_m106": { "label": "Remove M106 lines prior to inserting new.", - "description": "If you have 2 or more instances of 'Advanced Cooling Fan Control' running (to cool a portion of a print differently), then uncheck this box or the followup instances will remove all the lines inserted by the first instance. Pay attention to the Start and Stop layers. If you want to keep the Cura inserted lines up to the point where this post-processor will start making insertions, then un-check the box.", + "description": "If you have 2 or more instances of 'Advanced Cooling Fan Control' running (to cool a portion of a print differently), then you must uncheck this box or the followup instances will remove all the lines inserted by the first instance. Pay attention to the Start and Stop layers. Regardless of this setting: The script always removes M106 lines starting with the lowest layer number (when 'By Layer') or the starting layer number (when 'By Feature'). If you want to keep the M106 lines that Cura inserted up to the point where this post-processor will start making insertions, then un-check the box.", "type": "bool", "enabled": true, - "value": true + "value": true, + "default_value": true }, "feature_fan_start_layer": { @@ -65,73 +65,73 @@ class AddCoolingProfile(Script): "unit": "Lay# ", "enabled": "fan_layer_or_feature == 'by_feature'" }, - "layer_fan_1st": + "layer_fan_1": { "label": "Layer/Percent #1", - "description": "Enter as: 'LAYER / Percent' Ex: 57/100 with the layer first, then a '/' to delimit, and then the fan percentage.", + "description": "Enter as: 'LAYER / Percent' Ex: 55/100 with the layer first, then a '/' to delimit, and then the fan percentage. There are up to 8 changes. If you need more then add a second instance of this script and remember to turn off 'Remove M106 lines' in the second instance. The layer numbers in the second instance must start with a layer number higher than the last layer number in a previous script. You can't end the first script with a setting for layer 80 and then start the second script with a setting for layer 40 because 'Remove M106 lines' always starts with the lowest layer number when 'By Layer' is selected.", "type": "str", "default_value": "5/30", "unit": "L#/% ", "enabled": "fan_layer_or_feature == 'by_layer'" }, - "layer_fan_2nd": + "layer_fan_2": { "label": "Layer/Percent #2", - "description": "Enter as: 'LAYER / Percent' Ex: 57/100 with the layer first, then a '/' to delimit, and then the fan percentage.", + "description": "Enter as: 'LAYER / Percent' Ex: 55/100 with the layer first, then a '/' to delimit, and then the fan percentage.", "type": "str", "default_value": "", "unit": "L#/% ", "enabled": "fan_layer_or_feature == 'by_layer'" }, - "layer_fan_3rd": + "layer_fan_3": { "label": "Layer/Percent #3", - "description": "Enter as: 'LAYER / Percent' Ex: 57/100 with the layer first, then a '/' to delimit, and then the fan percentage.", + "description": "Enter as: 'LAYER / Percent' Ex: 55/100 with the layer first, then a '/' to delimit, and then the fan percentage.", "type": "str", "default_value": "", "unit": "L#/% ", "enabled": "fan_layer_or_feature == 'by_layer'" }, - "layer_fan_4th": + "layer_fan_4": { "label": "Layer/Percent #4", - "description": "Enter as: 'LAYER / Percent' Ex: 57/100 with the layer first, then a '/' to delimit, and then the fan percentage.", + "description": "Enter as: 'LAYER / Percent' Ex: 55/100 with the layer first, then a '/' to delimit, and then the fan percentage.", "type": "str", "default_value": "", "unit": "L#/% ", "enabled": "fan_layer_or_feature == 'by_layer'" }, - "layer_fan_5th": + "layer_fan_5": { "label": "Layer/Percent #5", - "description": "Enter as: 'LAYER / Percent' Ex: 57/100 with the layer first, then a '/' to delimit, and then the fan percentage.", + "description": "Enter as: 'LAYER / Percent' Ex: 55/100 with the layer first, then a '/' to delimit, and then the fan percentage.", "type": "str", "default_value": "", "unit": "L#/% ", "enabled": "fan_layer_or_feature == 'by_layer'" }, - "layer_fan_6th": + "layer_fan_6": { "label": "Layer/Percent #6", - "description": "Enter as: 'LAYER / Percent' Ex: 57/100 with the layer first, then a '/' to delimit, and then the fan percentage.", + "description": "Enter as: 'LAYER / Percent' Ex: 55/100 with the layer first, then a '/' to delimit, and then the fan percentage.", "type": "str", "default_value": "", "unit": "L#/% ", "enabled": "fan_layer_or_feature == 'by_layer'" }, - "layer_fan_7th": + "layer_fan_7": { "label": "Layer/Percent #7", - "description": "Enter as: 'LAYER / Percent' Ex: 57/100 with the layer first, then a '/' to delimit, and then the fan percentage.", + "description": "Enter as: 'LAYER / Percent' Ex: 55/100 with the layer first, then a '/' to delimit, and then the fan percentage.", "type": "str", "default_value": "", "unit": "L#/% ", "enabled": "fan_layer_or_feature == 'by_layer'" }, - "layer_fan_8th": + "layer_fan_8": { "label": "Layer/Percent #8", - "description": "Enter as: 'LAYER / Percent' Ex: 57/100 with the layer first, then a '/' to delimit, and then the fan percentage.", + "description": "Enter as: 'LAYER / Percent' Ex: 55/100 with the layer first, then a '/' to delimit, and then the fan percentage.", "type": "str", "default_value": "", "unit": "L#/% ", @@ -140,7 +140,7 @@ class AddCoolingProfile(Script): "feature_fan_skirt": { "label": "Skirt/Brim/Ooze Shield %", - "description": "Enter the fan percentage for skirt/brim. If you are starting at a layer above 1 then this setting only affects Ooze Shields and from the Start layer up.", + "description": "Enter the fan percentage for skirt/brim. If you are starting at a layer above 1 then this setting only affects Ooze Shields and from the Start Layer up.", "type": "int", "default_value": 0, "minimum_value": 0, @@ -247,7 +247,7 @@ class AddCoolingProfile(Script): "feature_fan_feature_final": { "label": "Final %", - "description": "If you choose an 'End Layer' then this is the fan speed that will carry through to the end of the gcode file. It will go into effect at the 'END' of your end layer.", + "description": "If you choose an 'End Layer' then this is the fan speed that will carry through to the end of the gcode file. It will go into effect at the 'END' of your End layer.", "type": "int", "default_value": 35, "minimum_value": 0, @@ -283,7 +283,7 @@ class AddCoolingProfile(Script): if scripts != None: script_count = scripts.count("AddCoolingProfile") if script_count > 0: - ## Set the default to "false" if there is more than one instance of this script running. + ## Set 'Remove M106 lines' to "false" if there is already an instance of this script running. self._instance.setProperty("delete_existing_m106", "value", False) def execute(self, data): @@ -314,6 +314,8 @@ class AddCoolingProfile(Script): else: #No P parameter if there is a single fan circuit------------------ t0_fan = "" + + #Get the cooling fan numbers for each extruder if the printer has multiple extruders elif extruder_count > 1: is_multi_fan = True t0_fan = " P" + str((extruder[0].getProperty("machine_extruder_cooling_fan_number", "value"))) @@ -325,21 +327,22 @@ class AddCoolingProfile(Script): #Initialize the fan_list with defaults---------------------------- fan_list = ["z"] * 16 for num in range(0,15,2): + fan_list[num] = len(data) fan_list[num + 1] = "M106 S0" #Assign the variable values if "By Layer"------------------------- by_layer_or_feature = self.getSettingValueByKey("fan_layer_or_feature") if by_layer_or_feature == "by_layer": - ## By layer doesn't do any feature search + ## By layer doesn't do any feature search so there is no need to look for combing moves feature_fan_combing = False - fan_list[0] = self.getSettingValueByKey("layer_fan_1st") - fan_list[2] = self.getSettingValueByKey("layer_fan_2nd") - fan_list[4] = self.getSettingValueByKey("layer_fan_3rd") - fan_list[6] = self.getSettingValueByKey("layer_fan_4th") - fan_list[8] = self.getSettingValueByKey("layer_fan_5th") - fan_list[10] = self.getSettingValueByKey("layer_fan_6th") - fan_list[12] = self.getSettingValueByKey("layer_fan_7th") - fan_list[14] = self.getSettingValueByKey("layer_fan_8th") + fan_list[0] = self.getSettingValueByKey("layer_fan_1") + fan_list[2] = self.getSettingValueByKey("layer_fan_2") + fan_list[4] = self.getSettingValueByKey("layer_fan_3") + fan_list[6] = self.getSettingValueByKey("layer_fan_4") + fan_list[8] = self.getSettingValueByKey("layer_fan_5") + fan_list[10] = self.getSettingValueByKey("layer_fan_6") + fan_list[12] = self.getSettingValueByKey("layer_fan_7") + fan_list[14] = self.getSettingValueByKey("layer_fan_8") ## If there is no '/' delimiter then ignore the line else put the settings in a list for num in range(0,15,2): if "/" in fan_list[num]: @@ -359,17 +362,18 @@ class AddCoolingProfile(Script): the_end_layer = -1 ## If there is an input error default to the entire gcode file. ## Get the speed for each feature - # 0;TYPE:SKIRT, 1;TYPE:WALL-INNER, 2;TYPE:WALL-OUTER, 3;TYPE:FILL, 4;TYPE:SKIN, 5;TYPE:SUPPORT, 6;TYPE:SUPPORT-INTERFACE, 7;TYPE:PRIME-TOWER, 8;BRIDGE, 9;FEATURE_FINAL, 10;FAN_COMBING, - fan_sp_skirt = self._feature_checker(self.getSettingValueByKey("feature_fan_skirt"), fan_mode) - fan_sp_wall_inner = self._feature_checker(self.getSettingValueByKey("feature_fan_wall_inner"), fan_mode) - fan_sp_wall_outer = self._feature_checker(self.getSettingValueByKey("feature_fan_wall_outer"), fan_mode) - fan_sp_fill = self._feature_checker(self.getSettingValueByKey("feature_fan_fill"), fan_mode) - fan_sp_skin = self._feature_checker(self.getSettingValueByKey("feature_fan_skin"), fan_mode) - fan_sp_support = self._feature_checker(self.getSettingValueByKey("feature_fan_support"), fan_mode) - fan_sp_support_interface = self._feature_checker(self.getSettingValueByKey("feature_fan_support_interface"), fan_mode) - fan_sp_prime_tower = self._feature_checker(self.getSettingValueByKey("feature_fan_prime_tower"), fan_mode) - fan_sp_bridge = self._feature_checker(self.getSettingValueByKey("feature_fan_bridge"), fan_mode) - fan_sp_feature_final = self._feature_checker(self.getSettingValueByKey("feature_fan_feature_final"), fan_mode) + feature_name_list = [] + feature_speed_list = [] + feature_speed_list.append(self._feature_checker(self.getSettingValueByKey("feature_fan_skirt"), fan_mode)); feature_name_list.append(";TYPE:SKIRT") + feature_speed_list.append(self._feature_checker(self.getSettingValueByKey("feature_fan_wall_inner"), fan_mode)); feature_name_list.append(";TYPE:WALL-INNER") + feature_speed_list.append(self._feature_checker(self.getSettingValueByKey("feature_fan_wall_outer"), fan_mode)); feature_name_list.append(";TYPE:WALL-OUTER") + feature_speed_list.append(self._feature_checker(self.getSettingValueByKey("feature_fan_fill"), fan_mode)); feature_name_list.append(";TYPE:FILL") + feature_speed_list.append(self._feature_checker(self.getSettingValueByKey("feature_fan_skin"), fan_mode)); feature_name_list.append(";TYPE:SKIN") + feature_speed_list.append(self._feature_checker(self.getSettingValueByKey("feature_fan_support"), fan_mode)); feature_name_list.append(";TYPE:SUPPORT") + feature_speed_list.append(self._feature_checker(self.getSettingValueByKey("feature_fan_support_interface"), fan_mode)); feature_name_list.append(";TYPE:SUPPORT-INTERFACE") + feature_speed_list.append(self._feature_checker(self.getSettingValueByKey("feature_fan_prime_tower"), fan_mode)); feature_name_list.append(";TYPE:PRIME-TOWER") + feature_speed_list.append(self._feature_checker(self.getSettingValueByKey("feature_fan_bridge"), fan_mode)); feature_name_list.append(";BRIDGE") + feature_speed_list.append(self._feature_checker(self.getSettingValueByKey("feature_fan_feature_final"), fan_mode)); feature_name_list.append("FINAL_FAN") feature_fan_combing = self.getSettingValueByKey("feature_fan_combing") if the_end_layer > -1 and by_layer_or_feature == "by_feature": ## Required so the final speed input can be determined @@ -459,18 +463,20 @@ class AddCoolingProfile(Script): altered_start_layer = str(len(data)) ## The fan list layers don't need to be in ascending order. Get the lowest. for num in range(0,15,2): - if int(fan_list[num]) < int(altered_start_layer): - altered_start_layer = int(fan_list[num]) + try: + if int(fan_list[num]) < int(altered_start_layer): + altered_start_layer = int(fan_list[num]) + except: + pass elif by_layer_or_feature == "by_feature": altered_start_layer = int(the_start_layer) - 1 start_from = int(layer_0_index) + int(altered_start_layer) - ## Strip the M106 and M107 lines from the file for l_index in range(int(start_from), len(data) - 1, 1): data[l_index] = re.sub(re.compile("M106(.*)\n"), "", data[l_index]) data[l_index] = re.sub(re.compile("M107(.*)\n"), "", data[l_index]) - ## Deal with a raft and with One-At-A-Time + ## Deal with a raft and with One-At-A-Time print sequence if raft_enabled and bed_adhesion == "raft": if print_sequence == "one_at_a_time": for r_index in range(2,len(data)-2,1): @@ -482,7 +488,7 @@ class AddCoolingProfile(Script): if ";LAYER:-" in data[r_index]: ## Turn the raft fan on lines.insert(1, fan_sp_raft + str(t0_fan)) - ## Shut the raft fan off + ## Shut the raft fan off at layer 0 if ";LAYER:0" in data[r_index]: lines.insert(1,"M106 S0" + str(t0_fan)) data[r_index] = "\n".join(lines) @@ -507,7 +513,7 @@ class AddCoolingProfile(Script): lines.insert(1, "M106 S0" + str(t0_fan)) data[r_index] = "\n".join(lines) - ## Turn off all fans at the end of data[1] + ## Turn off all fans at the end of data[1]. If more than one instance of this script is running then this will result in multiple M106 lines. temp_startup = data[1].split("\n") temp_startup.insert(len(temp_startup)-2,"M106 S0" + str(t0_fan)) ## If there are multiple cooling fans shut them all off @@ -535,31 +541,28 @@ class AddCoolingProfile(Script): #Single Fan "By Feature"------------------------------------------ if by_layer_or_feature == "by_feature" and (not is_multi_fan or not is_multi_extr_print): - return self._single_fan_by_feature(data, layer_0_index, the_start_layer, the_end_layer, the_end_is_enabled, fan_list, t0_fan, fan_sp_skirt, fan_sp_wall_inner, fan_sp_wall_outer, fan_sp_fill, fan_sp_skin, fan_sp_support, fan_sp_support_interface, feature_fan_combing, fan_sp_prime_tower, fan_sp_bridge, fan_sp_feature_final) + return self._single_fan_by_feature(data, layer_0_index, the_start_layer, the_end_layer, the_end_is_enabled, fan_list, t0_fan, feature_speed_list, feature_name_list, feature_fan_combing) #Multi Fan "By Feature"------------------------------------------- if by_layer_or_feature == "by_feature" and is_multi_fan: - return self._multi_fan_by_feature(data, layer_0_index, the_start_layer, the_end_layer, the_end_is_enabled, fan_list, t0_fan, t1_fan, t2_fan, t3_fan, fan_sp_skirt, fan_sp_wall_inner, fan_sp_wall_outer, fan_sp_fill, fan_sp_skin, fan_sp_support, fan_sp_support_interface, feature_fan_combing, fan_sp_prime_tower, fan_sp_bridge, fan_sp_feature_final) + return self._multi_fan_by_feature(data, layer_0_index, the_start_layer, the_end_layer, the_end_is_enabled, fan_list, t0_fan, t1_fan, t2_fan, t3_fan, feature_speed_list, feature_name_list, feature_fan_combing) # The Single Fan "By Layer"---------------------------------------- def _single_fan_by_layer(self, data: str, layer_0_index: int, fan_list: str, t0_fan: str)->str: layer_number = "0" - single_fan_layer = data - for l_index in range(layer_0_index,len(single_fan_layer)-1,1): - layer = single_fan_layer[l_index] + single_fan_data = data + for l_index in range(layer_0_index,len(single_fan_data)-1,1): + layer = single_fan_data[l_index] fan_lines = layer.split("\n") for fan_line in fan_lines: if ";LAYER:" in fan_line: - layer_number = int(fan_line.split(":")[1]) - ## If there is a match for the current layer number make the insertion. - try: - for num in range(0,15,2): - if int(layer_number) == int(fan_list[num]): - layer = layer.replace(fan_lines[0],fan_lines[0] + "\n" + fan_list[num + 1] + str(t0_fan)) - single_fan_layer[l_index] = layer - except: - continue - return single_fan_layer + layer_number = str(fan_line.split(":")[1]) + ## If there is a match for the current layer number make the insertion + for num in range(0,15,2): + if layer_number == str(fan_list[num]): + layer = layer.replace(fan_lines[0],fan_lines[0] + "\n" + fan_list[num + 1] + str(t0_fan)) + single_fan_data[l_index] = layer + return single_fan_data # Multi-Fan "By Layer"----------------------------------------- def _multi_fan_by_layer(self, data: str, layer_0_index: int, fan_list: str, t0_fan: str, t1_fan: str, t2_fan: str, t3_fan: str)->str: @@ -625,7 +628,7 @@ class AddCoolingProfile(Script): return multi_fan_data # Single fan by feature----------------------------------------------- - def _single_fan_by_feature(self, data: str, layer_0_index: int, the_start_layer: str, the_end_layer: str, the_end_is_enabled: str, fan_list: str, t0_fan: str, fan_sp_skirt: str, fan_sp_wall_inner: str, fan_sp_wall_outer: str, fan_sp_fill: str, fan_sp_skin: str, fan_sp_support: str, fan_sp_support_interface: str, feature_fan_combing: str, fan_sp_prime_tower: str, fan_sp_bridge: str, fan_sp_feature_final: str)->str: + def _single_fan_by_feature(self, data: str, layer_0_index: int, the_start_layer: str, the_end_layer: str, the_end_is_enabled: str, fan_list: str, t0_fan: str, feature_speed_list: str, feature_name_list: str, feature_fan_combing: bool)->str: single_fan_data = data layer_number = "0" index = 1 @@ -638,37 +641,26 @@ class AddCoolingProfile(Script): if ";LAYER:" in line: layer_number = str(line.split(":")[1]) if int(layer_number) >= int(the_start_layer) and int(layer_number) < int(the_end_layer)-1: - if ";TYPE:SKIRT" in line: - modified_data += fan_sp_skirt + t0_fan + "\n" - elif ";TYPE:WALL-INNER" in line: - modified_data += fan_sp_wall_inner + t0_fan + "\n" - elif ";TYPE:WALL-OUTER" in line: - modified_data += fan_sp_wall_outer + t0_fan + "\n" - elif ";TYPE:FILL" in line: - modified_data += fan_sp_fill + t0_fan + "\n" - elif ";TYPE:SKIN" in line: - modified_data += fan_sp_skin + t0_fan + "\n" - elif line == ";TYPE:SUPPORT": - modified_data += fan_sp_support + t0_fan + "\n" - elif ";TYPE:SUPPORT-INTERFACE" in line: - modified_data += fan_sp_support_interface + t0_fan + "\n" + temp = line.split(" ")[0] + try: + name_index = feature_name_list.index(temp) + except: + name_index = -1 + if name_index != -1: + modified_data += feature_speed_list[name_index] + t0_fan + "\n" elif ";MESH:NONMESH" in line: if feature_fan_combing == True: modified_data += "M106 S0" + t0_fan + "\n" - elif ";TYPE:PRIME-TOWER" in line: - modified_data += fan_sp_prime_tower + t0_fan + "\n" - elif line == ";BRIDGE": - modified_data += fan_sp_bridge + t0_fan + "\n" modified_data += line + "\n" ## If an End Layer is defined and is less than the last layer then insert the Final Speed - if line == ";LAYER:" + str(the_end_layer) and the_end_is_enabled == True: - modified_data += fan_sp_feature_final + t0_fan + "\n" + if line == ";LAYER:" + str(the_end_layer) and the_end_is_enabled == True: + modified_data += feature_speed_list[len(feature_speed_list) - 1] + t0_fan + "\n" if modified_data.endswith("\n"): modified_data = modified_data[0: - 1] single_fan_data[l_index] = modified_data return single_fan_data # Multi-fan by feature------------------------------------------------ - def _multi_fan_by_feature(self, data: str, layer_0_index: int, the_start_layer: str, the_end_layer: str, the_end_is_enabled: str, fan_list: str, t0_fan: str, t1_fan: str, t2_fan: str, t3_fan: str, fan_sp_skirt: str, fan_sp_wall_inner: str, fan_sp_wall_outer: str, fan_sp_fill: str, fan_sp_skin: str, fan_sp_support: str, fan_sp_support_interface: str, feature_fan_combing: str, fan_sp_prime_tower: str, fan_sp_bridge: str, fan_sp_feature_final: str)->str: + def _multi_fan_by_feature(self, data: str, layer_0_index: int, the_start_layer: str, the_end_layer: str, the_end_is_enabled: str, fan_list: str, t0_fan: str, t1_fan: str, t2_fan: str, t3_fan: str, feature_speed_list: str, feature_name_list: str, feature_fan_combing: bool)->str: multi_fan_data = data layer_number = "0" start_index = 1 @@ -729,35 +721,16 @@ class AddCoolingProfile(Script): if ";LAYER:" in line: layer_number = str(line.split(":")[1]) modified_data += line + "\n" - if int(layer_number) >= int(the_start_layer): # Problem with oneatatime < start - if ";TYPE:SKIRT" in line: - modified_data += line + "\n" - modified_data += fan_sp_skirt + this_fan + "\n" - current_fan_speed = str(fan_sp_skirt.split("S")[1]) - elif ";TYPE:WALL-INNER" in line: - modified_data += line + "\n" - modified_data += fan_sp_wall_inner + this_fan + "\n" - current_fan_speed = str(fan_sp_wall_inner.split("S")[1]) - elif ";TYPE:WALL-OUTER" in line: - modified_data += line + "\n" - modified_data += fan_sp_wall_outer + this_fan + "\n" - current_fan_speed = str(fan_sp_wall_outer.split("S")[1]) - elif ";TYPE:FILL" in line: - modified_data += line + "\n" - modified_data += fan_sp_fill + this_fan + "\n" - current_fan_speed = str(fan_sp_fill.split("S")[1]) - elif ";TYPE:SKIN" in line: - modified_data += line + "\n" - modified_data += fan_sp_skin + this_fan + "\n" - current_fan_speed = str(fan_sp_skin.split("S")[1]) - elif line == ";TYPE:SUPPORT": - modified_data += line + "\n" - modified_data += fan_sp_support + this_fan + "\n" - current_fan_speed = str(fan_sp_support.split("S")[1]) - elif ";TYPE:SUPPORT-INTERFACE" in line: - modified_data += line + "\n" - modified_data += fan_sp_support_interface + this_fan + "\n" - current_fan_speed = str(fan_sp_support_interface.split("S")[1]) + if int(layer_number) >= int(the_start_layer): + temp = line.split(" ")[0] + try: + name_index = feature_name_list.index(temp) + except: + name_index = -1 + if name_index != -1: + modified_data += line + "\n" + feature_speed_list[name_index] + this_fan + "\n" + #modified_data += feature_speed_list[name_index] + this_fan + "\n" + current_fan_speed = str(feature_speed_list[name_index].split("S")[1]) elif ";MESH:NONMESH" in line: if feature_fan_combing == True: modified_data += line + "\n" @@ -765,27 +738,12 @@ class AddCoolingProfile(Script): current_fan_speed = "0" else: modified_data += line + "\n" - elif ";TYPE:PRIME-TOWER" in line: - modified_data += line + "\n" - modified_data += fan_sp_prime_tower + this_fan + "\n" - current_fan_speed = str(fan_sp_prime_tower.split("S")[1]) - elif line == ";BRIDGE": - modified_data += line + "\n" - modified_data += fan_sp_bridge + this_fan + "\n" - current_fan_speed = str(fan_sp_bridge.split("S")[1]) ## If an end layer is defined - Insert the final speed and set the other variables to Final Speed to finish the file ## There cannot be a break here because if there are multiple fan numbers they still need to be shut off and turned on. elif line == ";LAYER:" + str(the_end_layer): - modified_data += fan_sp_feature_final + this_fan + "\n" - fan_sp_skirt = fan_sp_feature_final - fan_sp_wall_inner = fan_sp_feature_final - fan_sp_wall_outer = fan_sp_feature_final - fan_sp_fill = fan_sp_feature_final - fan_sp_skin = fan_sp_feature_final - fan_sp_support = fan_sp_feature_final - fan_sp_support_interface = fan_sp_feature_final - fan_sp_prime_tower = fan_sp_feature_final - fan_sp_bridge = fan_sp_feature_final + modified_data += feature_speed_list[len(feature_speed_list) - 1] + this_fan + "\n" + for set_speed in range(0, len(feature_speed_list) - 2): + feature_speed_list[set_speed] = feature_speed_list[len(feature_speed_list) - 1] else: ## Layer and Tool get inserted into modified_data above. All other lines go into modified_data here if not line.startswith("T") and not line.startswith(";LAYER:"): modified_data += line + "\n" @@ -836,9 +794,9 @@ class AddCoolingProfile(Script): return fan_sp_feat # Add additional travel comments to turn the fan off during combing. - def _add_travel_comment(self, the_data: str, lay_0_index: str) -> str: - for lay_num in range(int(lay_0_index), len(the_data)-1,1): - layer = the_data[lay_num] + def _add_travel_comment(self, comment_data: str, lay_0_index: str) -> str: + for lay_num in range(int(lay_0_index), len(comment_data)-1,1): + layer = comment_data[lay_num] lines = layer.split("\n") ## Copy the data to new_data and make the insertions there new_data = lines @@ -875,5 +833,5 @@ class AddCoolingProfile(Script): g0_count = 0 g0_index = -1 is_travel = False - the_data[lay_num] = "\n".join(new_data) - return the_data \ No newline at end of file + comment_data[lay_num] = "\n".join(new_data) + return comment_data \ No newline at end of file From b3825ee1c7f43a7e21784462433a921ea4a612a9 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Wed, 10 Jan 2024 05:39:59 +0100 Subject: [PATCH 73/73] actually use f string Contributes to CURA-11482 --- plugins/CuraEngineBackend/StartSliceJob.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index fe7137150b..935eb81afa 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -337,7 +337,7 @@ class StartSliceJob(Job): user_id = uuid.getnode() # On all of Cura's supported platforms, this returns the MAC address which is pseudonymical information (!= anonymous). user_id %= 2 ** 16 # So to make it anonymous, apply a bitmask selecting only the last 16 bits. This prevents it from being traceable to a specific user but still gives somewhat of an idea of whether it's just the same user hitting the same crash over and over again, or if it's widespread. - self._slice_message.sentry_id = "{user_id}" + self._slice_message.sentry_id = f"{user_id}" self._slice_message.cura_version = CuraVersion # Build messages for extruder stacks