From 24a0ba3974933ab15d55c0e5a262aa22b9c19856 Mon Sep 17 00:00:00 2001 From: jellespijker Date: Tue, 10 Oct 2023 05:20:19 +0200 Subject: [PATCH 01/70] Update PyQt6 dependencies to latest versions PyQt6 and PyQt6-sip along with their dependencies are updated to newer versions (6.5.2 and 13.5.2) in both requirements.txt and Uranium/requirements.txt. This is to ensure the application uses the latest and most secure versions of the libraries, potentially improving application performance and security. These updates also ensure compatibility with current and upcoming features and bug fixes. Contributes to CURA-11137 --- requirements.txt | 75 ++++++++++++++++++++++++------------------------ 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/requirements.txt b/requirements.txt index dfa974ef7d..48ee3abcdc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,41 +1,42 @@ ### Direct requirements for Uranium and libCharon ### -PyQt6-sip==13.4.1 \ - --hash=sha256:0df998f2b6ceeacfd10de773441572e215be0c9cae566cc7dd36e231bf714a12 \ - --hash=sha256:224575e84805c4317bacd5d1b8e93e0ad5c48685dadbbe1e902d4ebe16f22828 \ - --hash=sha256:36ae29cdc223cacc1257d0f5075cf81474550c6d26b728f922487a2aa935f130 \ - --hash=sha256:3a674c591d4274d4ea8127205290e927a7dab0eb87a0038d4f4ea1d430782649 \ - --hash=sha256:3ef9392e4ae29d393b79237d85840cdc6b8831f36eed5d56c7d9b329b380cc8d \ - --hash=sha256:43935873d60f57719632840d517afee04ef8f30e92cfe0dadc7e6326691920fc \ - --hash=sha256:5731f22618435654352ef07684549a17be82b75254227fc80b4b5b0b59fc6656 \ - --hash=sha256:5bc4beb6fb1de4c9ba8beee7b1a4a813fa888c3b095206dafcd25d7e6e4ed2a7 \ - --hash=sha256:5c36ab984402e96792eebf4b031abfaa589aa20af3190a79c54502c16964d97e \ - --hash=sha256:a2a0461992c6657f343308b150c4d6b57e9e7a0e5c2f79538434e7fb869ea827 \ - --hash=sha256:a81490ee84d7a41a126b116081bd97d758f41bf706aee0a8cec24d6e4c660184 \ - --hash=sha256:e00e287ea05bbc293fc6e2198301962af9b7b622bd2daf4288f925a88ae35dc9 \ - --hash=sha256:e670a7b2fb7e32204ce67d274017bfff3e21139d217d60cebbfcb75b019c91ee \ - --hash=sha256:ee06f255787a0b4957f357f93b78d2a11ca3761916833e3afa83f1381d4d1a46 \ - --hash=sha256:fbee0d554e0e98f56dbf6d94b00a28cc32425938ad7ae98fd91f8822c5b24d45 \ - --hash=sha256:fcc6d78314783f4a193f02353f431b7ea4d357f47c3c7a7d0740e723f69c64dc -PyQt6==6.4.2 \ - --hash=sha256:18d1daf98d9236d55102cdadafd1056f5802f3c9288fcf7238569937b71a89f0 \ - --hash=sha256:25bd399b4a95dce65d5f937c1aa85d3c7e14a21745ae2a4ca14c0116cd104290 \ - --hash=sha256:740244f608fe15ee1d89695c43f31a14caeca41c4f02ac36c86dfba4a5d5813d \ - --hash=sha256:c128bc0f17833e324593e3db83e99470d451a197dd17ff0333927b946c935bd9 -PyQt6-Qt6==6.4.2 \ - --hash=sha256:9f07c3c100cb46cca4074965e7494d4df4f0fc016497d5303c1fe135822876e1 \ - --hash=sha256:a29b8c858babd523e80c8db5f8fd19792641588ec04eab49af18b7a4423eb99f \ - --hash=sha256:c0e91d0275d428496cacff717a9b719c52bfa52b21f124d638b79cc2217bc81e \ - --hash=sha256:d19c4e72615762cd6f0b043f23fa5f0b02656091427ce6de1efccd58e10e6a53 -PyQt6-NetworkAuth==6.4.0 \ - --hash=sha256:ab6178b3b2902ae9939a148555cfcee8c7803d6b0d5924cd1bd8f3407b8b9210 \ - --hash=sha256:c16ec80232d88024b60d04386a23cc93067e5644a65f47f26ffb13d84dcd4a6d \ - --hash=sha256:c302cd0d838c7229eda5e26e0b1b3d3ec4f8720f8d9379472bce5a89ff0735c2 \ - --hash=sha256:d948fc0cf43b64afbda2acb5bf2392f785a1e7a2950d79ea850c1a3f4ae12f1a -PyQt6-NetworkAuth-Qt6==6.4.2 \ - --hash=sha256:179094bcb4d4d056316c22d3d067cd94d4591da23f804461bfb025ccfa29b2b4 \ - --hash=sha256:1de6abbb5fa6585b97ae49d3f64b0dfad40bd56b1a31744d9775ff26247241c8 \ - --hash=sha256:79ec4b0fc9450bbedbff03541b93b10d1c7e761cd2cc16ce70d2b09dcdf8c720 \ - --hash=sha256:d96d557fe61edb9b68d189f270f0393d6579c8d308e6b0d41bc0699371d7cb4e +PyQt6-sip==13.5.2 \ + --hash=sha256:1bdb1f7b5b2f6ac31d517a6f3a13c38055640ac0014f67a2e5422d2083ce69ec \ + --hash=sha256:318d4d1c7ef60f69c68227cef78fc439accc9028ec6149200eea3d34c433d373 \ + --hash=sha256:4b5b0c4b557e0293eba008021342459a0f91c69a7a2eb5231276d495d1d2960a \ + --hash=sha256:5b499eff7150d9f31fe835a73cc41f076bba2fcde0f5b0325b1284797f17c0ac \ + --hash=sha256:5d0fd42da765198b51d7fe12c29721cbe3e14b77ca4f68aa43618149ee7dbeff \ + --hash=sha256:831f5d606fc5296a80303ab30892c3308954c5766039bf7a96267488bb2524a5 \ + --hash=sha256:87d758ba999baa16459f0a3c7f7ed47a5b45e8991ad691f17345bf3c493a4281 \ + --hash=sha256:91812f0094443b816a74a89954d60bb50060807f54d7c016a4de7bd29454091e \ + --hash=sha256:94afb031db89159aa330891eba2c937b0378b4b264570998848c7a78eddf7c94 \ + --hash=sha256:9ad5b8c4c92d62e00ebf254a4c9656668b130f2a1d2792034e0d82b2d6571509 \ + --hash=sha256:9c9dac067710015895f523f5a2a4d59cbef8624a152b6f9a426e5b848d8c6d29 \ + --hash=sha256:ace942b78378bff8ae2d6bafccc84465f1ff0cf30720b8321e0bd6c95c36ede6 \ + --hash=sha256:b54b0d8d21c5835af8f6d6d8a323a23106e67b7cd4c31e23c35bb4c321000de8 \ + --hash=sha256:c0b4e55c4d0dc44728da90eb1451dfff0d05260b4a3496ff0014494e6c1865a6 \ + --hash=sha256:dcf602c233ee7600e810927adcb9e518d61bc796a6b2013c17feedd24c4e5413 \ + --hash=sha256:ebf6264b6feda01ba37d3b60a4bb87493bdb87be70f7b2a5384a7acd4902d88d +PyQt6==6.5.2 \ + --hash=sha256:1487ee7350f9ffb66d60ab4176519252c2b371762cbe8f8340fd951f63801280 \ + --hash=sha256:5bad1437eb0c1ae801103b32ef04ef62ef1cce505b448525f60089ce36329b89 \ + --hash=sha256:70468cca4537756c714a57fa1baa5beabb9b38775f52f9611f49870705672c55 \ + --hash=sha256:ff1d12767b578f0f0e87cdb12198e7dcad9a176c40d1d1d799984181b0af93cb +PyQt6-Qt6==6.5.2 \ + --hash=sha256:4b37f6f93c0980469ccc570998d3e3de243028bae7389fb6330443ab215ce2f6 \ + --hash=sha256:5a3c7bb899678bf801136b31cd589ed4d0d54ab32be5fb76c2bdeb161a9662ad \ + --hash=sha256:8dad61b4666d91882d7e1c4d619c71e7429c13e19182f8b3bebf3ecf95107d4c \ + --hash=sha256:953f3c0e99e486081a6d438b32fbc240da97457226562eb68cf1b11c516386fd +PyQt6-NetworkAuth==6.5.0 \ + --hash=sha256:6dc9e44a978698b673926e34da486f946ccbbeeac02078517c4d1ee23d0546a4 \ + --hash=sha256:7170db3f99e13aef855d9d52a00a8baa2dea92d12f9b441fed9c6dec57f83e09 \ + --hash=sha256:a8c8cb00a615dde1efaf1d7926e8532df77d6d08798d33b6325fb8f2ff0f220d \ + --hash=sha256:ac56d362c9efcfc194e358cc2bba362535b0775dc2bd8257f964e0bcfe7d421a +PyQt6-NetworkAuth-Qt6==6.5.2 \ + --hash=sha256:0588b93ec5a6f2c492a42dc56967f06d33306169e716c5636448816a65956278 \ + --hash=sha256:29396a63b68e8fa26587c35e8befad0a84e3a05e03551d1329ffd527684edc68 \ + --hash=sha256:2ec8ca45764d2f122912ad6c754b5ffe65f143b5a52f99649cc7931b475e064b \ + --hash=sha256:76e0877ed86247784740a0eb928f3c77da7466f08d96d17306efda6060df2c44 + certifi==2023.5.7; \ --hash=sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716 cryptography==41.0.1 \ From 6301926885f170f79189b0cf6fdc2d3594d1ba2e Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Tue, 7 Nov 2023 18:08:08 +0530 Subject: [PATCH 02/70] Calculating time of travel for each line segment CURA-7647 --- cura/LayerPolygon.py | 6 ++++++ plugins/SimulationView/SimulationView.py | 5 +++++ plugins/SimulationView/SimulationViewMainComponent.qml | 6 +++++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/cura/LayerPolygon.py b/cura/LayerPolygon.py index 103703e594..4eb21dd45f 100644 --- a/cura/LayerPolygon.py +++ b/cura/LayerPolygon.py @@ -1,5 +1,6 @@ # Copyright (c) 2019 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +import math import numpy from typing import Optional, cast @@ -186,6 +187,11 @@ class LayerPolygon: def types(self): return self._types + @property + def lineLengths(self): + return [math.sqrt(sum((b - a) ** 2 for a, b in zip(self._data[i], self._data[i + 1]))) + for i in range(len(self._data) - 1)] + @property def data(self): return self._data diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index 473948bc46..88fc44df98 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -400,6 +400,9 @@ class SimulationView(CuraView): def getMaxFeedrate(self) -> float: return self._max_feedrate + def getSimulationTime(self) -> list: + return [length / feedrate for length, feedrate in zip(self._visible_lengths, self._current_feedrates)] + 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. @@ -524,8 +527,10 @@ 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._visible_lengths = numpy.take(polyline.lineLengths, visible_indices) visible_feedrates = numpy.take(polyline.lineFeedrates, visible_indices) visible_feedrates_with_extrusion = numpy.take(polyline.lineFeedrates, visible_indicies_with_extrusion) + self._current_feedrates = visible_feedrates 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 a82d1e3db9..b2ef7b8356 100644 --- a/plugins/SimulationView/SimulationViewMainComponent.qml +++ b/plugins/SimulationView/SimulationViewMainComponent.qml @@ -136,9 +136,10 @@ Item Timer { id: simulationTimer - interval: 100 + interval: parseFloat(UM.SimulationView.getSimulationTime[pathNumber]).toFixed(2) //10 //dont change running: false repeat: true + property int pathNumber : 0 onTriggered: { var currentPath = UM.SimulationView.currentPath @@ -153,10 +154,12 @@ Item if (currentPath >= numPaths) { UM.SimulationView.setCurrentPath(0) + pathNumber =0 } else { UM.SimulationView.setCurrentPath(currentPath + 1) + pathNumber = 0 } } // If the simulation is already playing and we reach the end of a layer, then it automatically @@ -184,6 +187,7 @@ Item // 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 + pathNumber += 1 } } From efda0aaba4329948485021bbbc4d2e365a5b63c4 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Tue, 7 Nov 2023 18:42:41 +0530 Subject: [PATCH 03/70] updated for every layer CURA-7647 --- plugins/SimulationView/SimulationView.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index 88fc44df98..2f09c8018b 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -78,6 +78,8 @@ class SimulationView(CuraView): self._minimum_path_num = 0 self.currentLayerNumChanged.connect(self._onCurrentLayerNumChanged) + self._current_feedrates = {} + self._visible_lengths ={} self._busy = False self._simulation_running = False @@ -401,7 +403,7 @@ class SimulationView(CuraView): return self._max_feedrate def getSimulationTime(self) -> list: - return [length / feedrate for length, feedrate in zip(self._visible_lengths, self._current_feedrates)] + return [length / feedrate for length, feedrate in zip(self._visible_lengths[self._current_layer_num], self._current_feedrates[self._current_layer_num])] def getMinThickness(self) -> float: if abs(self._min_thickness - sys.float_info.max) < 10: # Some lenience due to floating point rounding. @@ -527,10 +529,10 @@ 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._visible_lengths = numpy.take(polyline.lineLengths, visible_indices) + self._visible_lengths[layer_index] = numpy.take(polyline.lineLengths, visible_indices) visible_feedrates = numpy.take(polyline.lineFeedrates, visible_indices) visible_feedrates_with_extrusion = numpy.take(polyline.lineFeedrates, visible_indicies_with_extrusion) - self._current_feedrates = visible_feedrates + self._current_feedrates[layer_index] = visible_feedrates 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) From 457cecba5943c09b1b3b5b2a573a18c0915e0bc0 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Wed, 8 Nov 2023 13:29:47 +0530 Subject: [PATCH 04/70] using numpy for array calculation CURA-7647 --- cura/LayerPolygon.py | 4 ++-- plugins/SimulationView/SimulationView.py | 2 +- plugins/SimulationView/SimulationViewMainComponent.qml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cura/LayerPolygon.py b/cura/LayerPolygon.py index 4eb21dd45f..e5fd307dc9 100644 --- a/cura/LayerPolygon.py +++ b/cura/LayerPolygon.py @@ -189,8 +189,8 @@ class LayerPolygon: @property def lineLengths(self): - return [math.sqrt(sum((b - a) ** 2 for a, b in zip(self._data[i], self._data[i + 1]))) - for i in range(len(self._data) - 1)] + data_array = numpy.array(self._data) + return numpy.linalg.norm(data_array[1:] - data_array[:-1], axis=1) @property def data(self): diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index 2f09c8018b..18d1f981c7 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -403,7 +403,7 @@ class SimulationView(CuraView): return self._max_feedrate def getSimulationTime(self) -> list: - return [length / feedrate for length, feedrate in zip(self._visible_lengths[self._current_layer_num], self._current_feedrates[self._current_layer_num])] + return self._visible_lengths[self._current_layer_num] / self._current_feedrates[self._current_layer_num] def getMinThickness(self) -> float: if abs(self._min_thickness - sys.float_info.max) < 10: # Some lenience due to floating point rounding. diff --git a/plugins/SimulationView/SimulationViewMainComponent.qml b/plugins/SimulationView/SimulationViewMainComponent.qml index b2ef7b8356..66acff656a 100644 --- a/plugins/SimulationView/SimulationViewMainComponent.qml +++ b/plugins/SimulationView/SimulationViewMainComponent.qml @@ -136,7 +136,7 @@ Item Timer { id: simulationTimer - interval: parseFloat(UM.SimulationView.getSimulationTime[pathNumber]).toFixed(2) //10 //dont change + interval: parseFloat(UM.SimulationView.getSimulationTime[pathNumber]).toFixed(2) running: false repeat: true property int pathNumber : 0 From 1f9e0e2dee75bcbc12fbe1b54c61de10e5a5f65c Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Tue, 28 Nov 2023 15:15:39 +0100 Subject: [PATCH 05/70] 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 06/70] 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 2b5f8b3a7c4a77e7eb99fc974996efcd4b77ace0 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Thu, 30 Nov 2023 13:23:37 +0100 Subject: [PATCH 07/70] 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 08/70] 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 09/70] 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 10/70] 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 11/70] 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 79c7db3e6f621ad444be94d98a2c27da6d2c9c04 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Fri, 1 Dec 2023 08:13:30 +0100 Subject: [PATCH 12/70] Use Uranium workign branch CURA-11137 Contributes to CURA-10831 and CURA-11137 --- conanfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conanfile.py b/conanfile.py index d52d62e5cc..1244661849 100644 --- a/conanfile.py +++ b/conanfile.py @@ -328,7 +328,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_11137") # FIXME: Use `testing` once the branch is merged self.requires("cura_binary_data/(latest)@ultimaker/testing") self.requires("cpython/3.10.4@ultimaker/stable") self.requires("openssl/3.2.0") From 31d48aabe7ca0b2eca3033b94f2eed7d9b3e20f5 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Fri, 1 Dec 2023 09:15:21 +0100 Subject: [PATCH 13/70] Use Qt6.6 and PyQt6.6 Contributes to CURA-11137 --- requirements.txt | 79 +++++++++++++++++++++++++----------------------- 1 file changed, 42 insertions(+), 37 deletions(-) diff --git a/requirements.txt b/requirements.txt index 48ee3abcdc..76339c884f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,41 +1,46 @@ ### Direct requirements for Uranium and libCharon ### -PyQt6-sip==13.5.2 \ - --hash=sha256:1bdb1f7b5b2f6ac31d517a6f3a13c38055640ac0014f67a2e5422d2083ce69ec \ - --hash=sha256:318d4d1c7ef60f69c68227cef78fc439accc9028ec6149200eea3d34c433d373 \ - --hash=sha256:4b5b0c4b557e0293eba008021342459a0f91c69a7a2eb5231276d495d1d2960a \ - --hash=sha256:5b499eff7150d9f31fe835a73cc41f076bba2fcde0f5b0325b1284797f17c0ac \ - --hash=sha256:5d0fd42da765198b51d7fe12c29721cbe3e14b77ca4f68aa43618149ee7dbeff \ - --hash=sha256:831f5d606fc5296a80303ab30892c3308954c5766039bf7a96267488bb2524a5 \ - --hash=sha256:87d758ba999baa16459f0a3c7f7ed47a5b45e8991ad691f17345bf3c493a4281 \ - --hash=sha256:91812f0094443b816a74a89954d60bb50060807f54d7c016a4de7bd29454091e \ - --hash=sha256:94afb031db89159aa330891eba2c937b0378b4b264570998848c7a78eddf7c94 \ - --hash=sha256:9ad5b8c4c92d62e00ebf254a4c9656668b130f2a1d2792034e0d82b2d6571509 \ - --hash=sha256:9c9dac067710015895f523f5a2a4d59cbef8624a152b6f9a426e5b848d8c6d29 \ - --hash=sha256:ace942b78378bff8ae2d6bafccc84465f1ff0cf30720b8321e0bd6c95c36ede6 \ - --hash=sha256:b54b0d8d21c5835af8f6d6d8a323a23106e67b7cd4c31e23c35bb4c321000de8 \ - --hash=sha256:c0b4e55c4d0dc44728da90eb1451dfff0d05260b4a3496ff0014494e6c1865a6 \ - --hash=sha256:dcf602c233ee7600e810927adcb9e518d61bc796a6b2013c17feedd24c4e5413 \ - --hash=sha256:ebf6264b6feda01ba37d3b60a4bb87493bdb87be70f7b2a5384a7acd4902d88d -PyQt6==6.5.2 \ - --hash=sha256:1487ee7350f9ffb66d60ab4176519252c2b371762cbe8f8340fd951f63801280 \ - --hash=sha256:5bad1437eb0c1ae801103b32ef04ef62ef1cce505b448525f60089ce36329b89 \ - --hash=sha256:70468cca4537756c714a57fa1baa5beabb9b38775f52f9611f49870705672c55 \ - --hash=sha256:ff1d12767b578f0f0e87cdb12198e7dcad9a176c40d1d1d799984181b0af93cb -PyQt6-Qt6==6.5.2 \ - --hash=sha256:4b37f6f93c0980469ccc570998d3e3de243028bae7389fb6330443ab215ce2f6 \ - --hash=sha256:5a3c7bb899678bf801136b31cd589ed4d0d54ab32be5fb76c2bdeb161a9662ad \ - --hash=sha256:8dad61b4666d91882d7e1c4d619c71e7429c13e19182f8b3bebf3ecf95107d4c \ - --hash=sha256:953f3c0e99e486081a6d438b32fbc240da97457226562eb68cf1b11c516386fd -PyQt6-NetworkAuth==6.5.0 \ - --hash=sha256:6dc9e44a978698b673926e34da486f946ccbbeeac02078517c4d1ee23d0546a4 \ - --hash=sha256:7170db3f99e13aef855d9d52a00a8baa2dea92d12f9b441fed9c6dec57f83e09 \ - --hash=sha256:a8c8cb00a615dde1efaf1d7926e8532df77d6d08798d33b6325fb8f2ff0f220d \ - --hash=sha256:ac56d362c9efcfc194e358cc2bba362535b0775dc2bd8257f964e0bcfe7d421a -PyQt6-NetworkAuth-Qt6==6.5.2 \ - --hash=sha256:0588b93ec5a6f2c492a42dc56967f06d33306169e716c5636448816a65956278 \ - --hash=sha256:29396a63b68e8fa26587c35e8befad0a84e3a05e03551d1329ffd527684edc68 \ - --hash=sha256:2ec8ca45764d2f122912ad6c754b5ffe65f143b5a52f99649cc7931b475e064b \ - --hash=sha256:76e0877ed86247784740a0eb928f3c77da7466f08d96d17306efda6060df2c44 +PyQt6-sip==13.6.0 \ + --hash=sha256:0dfd22cfedd87e96f9d51e0778ca2ba3dc0be83e424e9e0f98f6994d8d9c90f0 \ + --hash=sha256:13885361ca2cb2f5085d50359ba61b3fabd41b139fb58f37332acbe631ef2357 \ + --hash=sha256:24441032a29791e82beb7dfd76878339058def0e97fdb7c1cea517f3a0e6e96b \ + --hash=sha256:2486e1588071943d4f6657ba09096dc9fffd2322ad2c30041e78ea3f037b5778 \ + --hash=sha256:3075d8b325382750829e6cde6971c943352309d35768a4d4da0587459606d562 \ + --hash=sha256:33ea771fe777eb0d1a2c3ef35bcc3f7a286eb3ff09cd5b2fdd3d87d1f392d7e8 \ + --hash=sha256:39854dba35f8e5a4288da26ecb5f40b4c5ec1932efffb3f49d5ea435a7f37fb3 \ + --hash=sha256:3bf03e130fbfd75c9c06e687b86ba375410c7a9e835e4e03285889e61dd4b0c4 \ + --hash=sha256:43fb8551796030aae3d66d6e35e277494071ec6172cd182c9569ab7db268a2f5 \ + --hash=sha256:58f68a48400e0b3d1ccb18090090299bad26e3aed7ccb7057c65887b79b8aeea \ + --hash=sha256:5b9c6b6f9cfccb48cbb78a59603145a698fb4ffd176764d7083e5bf47631d8df \ + --hash=sha256:747f6ca44af81777a2c696bd501bc4815a53ec6fc94d4e25830e10bc1391f8ab \ + --hash=sha256:86a7b67c64436e32bffa9c28c9f21bf14a9faa54991520b12c3f6f435f24df7f \ + --hash=sha256:8c282062125eea5baf830c6998587d98c50be7c3a817a057fb95fef647184012 \ + --hash=sha256:8f9df9f7ccd8a9f0f1d36948c686f03ce1a1281543a3e636b7b7d5e086e1a436 \ + --hash=sha256:98bf954103b087162fa63b3a78f30b0b63da22fd6450b610ec1b851dbb798228 \ + --hash=sha256:9adf672f9114687533a74d5c2d4c03a9a929ad5ad9c3e88098a7da1a440ab916 \ + --hash=sha256:a6ce80bc24618d8a41be8ca51ad9f10e8bc4296dd90ab2809573df30a23ae0e5 \ + --hash=sha256:d6b5f699aaed0ac1fcd23e8fbca70d8a77965831b7c1ce474b81b1678817a49d \ + --hash=sha256:fa759b6339ff7e25f9afe2a6b651b775f0a36bcb3f5fa85e81a90d3b033c83f4 \ + --hash=sha256:fa7b10af7488efc5e53b41dd42c0f421bde6c2865a107af7ae259aff9d841da9 +PyQt6==6.6.0 \ + --hash=sha256:33655db05ac2de699320f035250c21434c77144a6a2943aca3f4c579dabc3f7b \ + --hash=sha256:3ef68830a9b32050c30f7962c56a5927802c9193b68eaf405faecb8ce9ae10a8 \ + --hash=sha256:d41512d66044c2df9c5f515a56a922170d68a37b3406ffddc8b4adc57181b576 \ + --hash=sha256:fc7185d65755f26d7a6842492ec5398c92544dc4eafbbcbef1b1922aca585c96 +PyQt6-Qt6==6.6.0 \ + --hash=sha256:1b079a33088d32ff47872cdb37fd15aa42101f0be46c3340244483849b781438 \ + --hash=sha256:8cb30d64a4d32465ea1686bc827cbe452225fb387c4873356b0fa7b9ae63534f \ + --hash=sha256:a151f34712cd645111e89cb30b02e5fb69c9dcc3603ab3c03a561e874bd7cbcf \ + --hash=sha256:e5483ae04bf107411c7469f1be9f9e2eb9840303e788b3ac524fe30af90d45f4 +PyQt6-NetworkAuth==6.6.0 \ + --hash=sha256:7b90b81792fe53105287c8cbb5e4b22bc44a482268ffb7d3e33f852807f86182 \ + --hash=sha256:c7e2335159aa795e2fe6fb069ccce6308672ab80f26c50fab57caf957371cbb5 \ + --hash=sha256:cdfc0bfaea16a9e09f075bdafefb996aa9fdec392052ba4fb3cbac233c1958fb \ + --hash=sha256:f60ff9a62f5129dc2a9d4c495fb47f9a03e4dfb666b50fb7d61f46e89bf7b6a2 +PyQt6-NetworkAuth-Qt6==6.6.0 \ + --hash=sha256:481d9093e1fb1ac6843d8beabcd359cc34b74b9a2cbb3e2b68d96bd3f178d4e0 \ + --hash=sha256:4cc48fd375730a0ba5fbed9d64abb2914f587377560a78a63aff893f9e276a45 \ + --hash=sha256:5006deabf55304d4a3e0b3c954f93e5835546b11e789d14653a2493d12d3a063 \ + --hash=sha256:bcd56bfc892fec961c51eba3c0bf32ba8317a762d9e254d3830569611ed569d6 certifi==2023.5.7; \ --hash=sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716 From cf6874c98481bd899a4a47c9af05af1570688a34 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Fri, 1 Dec 2023 10:53:30 +0100 Subject: [PATCH 14/70] 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 15/70] 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 16/70] 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 17/70] 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 e904123b8095376d31138b0c095909773a4e7d43 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Mon, 4 Dec 2023 14:41:46 +0100 Subject: [PATCH 18/70] Use Uranium CURA-11137 Contribute to CURA-11137 --- .github/workflows/conan-recipe-export.yml | 110 ---------------------- conandata.yml | 2 +- 2 files changed, 1 insertion(+), 111 deletions(-) delete mode 100644 .github/workflows/conan-recipe-export.yml diff --git a/.github/workflows/conan-recipe-export.yml b/.github/workflows/conan-recipe-export.yml deleted file mode 100644 index 69c4e4d34a..0000000000 --- a/.github/workflows/conan-recipe-export.yml +++ /dev/null @@ -1,110 +0,0 @@ -name: Export Conan Recipe to server - -on: - workflow_call: - inputs: - recipe_id_full: - required: true - type: string - - recipe_id_latest: - required: false - type: string - - runs_on: - required: true - type: string - - python_version: - required: true - type: string - - conan_config_branch: - required: false - type: string - - conan_logging_level: - required: false - type: string - - conan_export_binaries: - required: false - type: boolean - - conan_upload_community: - required: false - default: true - type: boolean - -env: - CONAN_LOGIN_USERNAME: ${{ secrets.CONAN_USER }} - CONAN_PASSWORD: ${{ secrets.CONAN_PASS }} - CONAN_LOG_RUN_TO_OUTPUT: 1 - CONAN_LOGGING_LEVEL: ${{ inputs.conan_logging_level }} - CONAN_NON_INTERACTIVE: 1 - -jobs: - package-export: - runs-on: ${{ inputs.runs_on }} - - steps: - - name: Checkout project - uses: actions/checkout@v3 - - - name: Setup Python and pip - uses: actions/setup-python@v4 - with: - python-version: ${{ inputs.python_version }} - cache: 'pip' - cache-dependency-path: .github/workflows/requirements-conan-package.txt - - - name: Install Python requirements and Create default Conan profile - run: | - pip install -r https://raw.githubusercontent.com/Ultimaker/Cura/main/.github/workflows/requirements-conan-package.txt - conan profile new default --detect - # Note the runner requirements are always installed from the main branch in the Ultimaker/Cura repo - - - name: Cache Conan local repository packages - uses: actions/cache@v3 - with: - path: $HOME/.conan/data - key: ${{ runner.os }}-conan-export-cache - - - name: Get Conan configuration from branch - if: ${{ inputs.conan_config_branch != '' }} - run: conan config install https://github.com/Ultimaker/conan-config.git -a "-b ${{ inputs.conan_config_branch }}" - - - name: Get Conan configuration - run: | - conan config install https://github.com/Ultimaker/conan-config.git - conan config install https://github.com/Ultimaker/conan-config.git -a "-b runner/${{ runner.os }}/${{ runner.arch }}" - - - name: Add Cura private Artifactory remote - run: conan remote add cura-private-conan-dev https://cura.jfrog.io/artifactory/api/conan/cura-private-conan-dev True - - - name: Set GH service account for remote cura-conan-dev - run: conan user -p ${{ secrets.CONAN_GH_RUNNER_PASS }} -r cura-private-conan-dev "${{ secrets.CONAN_GH_RUNNER_USER }}" - - - name: Export the Package (binaries) - if: ${{ inputs.conan_export_binaries }} - run: conan create . ${{ inputs.recipe_id_full }} --build=missing --update -c tools.build:skip_test=True - - - name: Export the Package - if: ${{ !inputs.conan_export_binaries }} - run: conan export . ${{ inputs.recipe_id_full }} - - - name: Create the latest alias - if: always() - run: conan alias ${{ inputs.recipe_id_latest }} ${{ inputs.recipe_id_full }} - - - name: Upload the Package(s) - if: ${{ always() && inputs.conan_upload_community }} - run: | - conan upload ${{ inputs.recipe_id_full }} -r cura --all -c - conan upload ${{ inputs.recipe_id_latest }} -r cura -c - - - name: Upload the Package(s) to the private Artifactory - if: ${{ always() && ! inputs.conan_upload_community }} - run: | - conan upload ${{ inputs.recipe_id_full }} -r cura-private-conan-dev --all -c - conan upload ${{ inputs.recipe_id_latest }} -r cura-private-conan-dev -c diff --git a/conandata.yml b/conandata.yml index 52f15cb3f3..347602a02e 100644 --- a/conandata.yml +++ b/conandata.yml @@ -1,6 +1,6 @@ version: "5.7.0-alpha.0" requirements: - - "uranium/(latest)@ultimaker/cura_10831" + - "uranium/(latest)@ultimaker/cura_11137" - "curaengine/(latest)@ultimaker/cura_10831" - "cura_binary_data/(latest)@ultimaker/cura_10831" - "fdm_materials/(latest)@ultimaker/cura_10831" From ce0cdd0b91f8df5a28e9bdf0bebd13c8f850bdb2 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Mon, 4 Dec 2023 17:07:43 +0100 Subject: [PATCH 19/70] =?UTF-8?q?Model=20translations=20while=20changing?= =?UTF-8?q?=20build=20plates=20while=20importing=20models,=20coordinate=20?= =?UTF-8?q?translations=20shouldn=E2=80=99t=20matter=20and=20the=20object?= =?UTF-8?q?=20should=20be=20organized=20on=20the=20plate=20where=20it=20fi?= =?UTF-8?q?nds=20space.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CURA-11166 --- cura/CuraApplication.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index c6c44cf8f5..7e2f0fb1ca 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -179,6 +179,7 @@ class CuraApplication(QtApplication): self._use_single_instance = False self._single_instance = None + self._project_mode = None self._cura_formula_functions = None # type: Optional[CuraFormulaFunctions] @@ -1845,7 +1846,7 @@ class CuraApplication(QtApplication): Logger.log("i", "Attempting to read file %s", file.toString()) if not file.isValid(): return - + self._project_mode = project_mode scene = self.getController().getScene() for node in DepthFirstIterator(scene.getRoot()): @@ -1855,16 +1856,16 @@ class CuraApplication(QtApplication): is_project_file = self.checkIsValidProjectFile(file) - if project_mode is None: - project_mode = self.getPreferences().getValue("cura/choice_on_open_project") + if self._project_mode is None: + self._project_mode = self.getPreferences().getValue("cura/choice_on_open_project") - if is_project_file and project_mode == "open_as_project": + if is_project_file and self._project_mode == "open_as_project": # open as project immediately without presenting a dialog workspace_handler = self.getWorkspaceFileHandler() workspace_handler.readLocalFile(file, add_to_recent_files_hint = add_to_recent_files) return - if is_project_file and project_mode == "always_ask": + if is_project_file and self._project_mode == "always_ask": # present a dialog asking to open as project or import models self.callLater(self.openProjectFile.emit, file, add_to_recent_files) return @@ -1999,8 +2000,11 @@ class CuraApplication(QtApplication): center_y = 0 node.translate(Vector(0, center_y, 0)) - nodes_to_arrange.append(node) + # If file extention is 3mf and models are to be loaded from a cura project, + # models are to be arranged in buildplate. + elif self._project_mode == "open_as_model": + nodes_to_arrange.append(node) # This node is deep copied from some other node which already has a BuildPlateDecorator, but the deepcopy # of BuildPlateDecorator produces one that's associated with build plate -1. So, here we need to check if 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 20/70] 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 21/70] 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 22/70] 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 23/70] 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 24/70] 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 25/70] 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 26/70] 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 27/70] 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 30e4c61620fc31703cf0b4227f419beea882db30 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Wed, 6 Dec 2023 12:39:10 +0100 Subject: [PATCH 28/70] review comments fix CURA-11166 --- cura/CuraApplication.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 7e2f0fb1ca..28dfd5e1c9 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -179,7 +179,7 @@ class CuraApplication(QtApplication): self._use_single_instance = False self._single_instance = None - self._project_mode = None + self._open_project_mode: Optional[str] = None self._cura_formula_functions = None # type: Optional[CuraFormulaFunctions] @@ -1846,7 +1846,7 @@ class CuraApplication(QtApplication): Logger.log("i", "Attempting to read file %s", file.toString()) if not file.isValid(): return - self._project_mode = project_mode + self._open_project_mode = project_mode scene = self.getController().getScene() for node in DepthFirstIterator(scene.getRoot()): @@ -1856,16 +1856,16 @@ class CuraApplication(QtApplication): is_project_file = self.checkIsValidProjectFile(file) - if self._project_mode is None: - self._project_mode = self.getPreferences().getValue("cura/choice_on_open_project") + if self._open_project_mode is None: + self._open_project_mode = self.getPreferences().getValue("cura/choice_on_open_project") - if is_project_file and self._project_mode == "open_as_project": + if is_project_file and self._open_project_mode == "open_as_project": # open as project immediately without presenting a dialog workspace_handler = self.getWorkspaceFileHandler() workspace_handler.readLocalFile(file, add_to_recent_files_hint = add_to_recent_files) return - if is_project_file and self._project_mode == "always_ask": + if is_project_file and self._open_project_mode == "always_ask": # present a dialog asking to open as project or import models self.callLater(self.openProjectFile.emit, file, add_to_recent_files) return @@ -2001,9 +2001,9 @@ class CuraApplication(QtApplication): node.translate(Vector(0, center_y, 0)) nodes_to_arrange.append(node) - # If file extention is 3mf and models are to be loaded from a cura project, - # models are to be arranged in buildplate. - elif self._project_mode == "open_as_model": + # If the file is a project,and models are to be loaded from a that project, + # models inside file should be arranged in buildplate. + elif self._open_project_mode == "open_as_model": nodes_to_arrange.append(node) # This node is deep copied from some other node which already has a BuildPlateDecorator, but the deepcopy From 84d56367f4f357caec408e14e4d396d96aa13aef Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Wed, 6 Dec 2023 13:33:57 +0100 Subject: [PATCH 29/70] 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 30/70] 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 bf2c8b5a08e0fbf442edfa70ae4f11f04d3c32f2 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Fri, 8 Dec 2023 11:41:16 +0100 Subject: [PATCH 31/70] Simulation time fed to the timer controlling speed simulation time is made 10x faster than the actual time, for better visualisation CURA-7647 --- plugins/SimulationView/SimulationView.py | 10 ++++++---- .../SimulationViewMainComponent.qml | 6 +----- plugins/SimulationView/SimulationViewProxy.py | 15 +++++++++++++++ 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index 18d1f981c7..6874b27625 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -79,7 +79,7 @@ class SimulationView(CuraView): self.currentLayerNumChanged.connect(self._onCurrentLayerNumChanged) self._current_feedrates = {} - self._visible_lengths ={} + self._lengths_of_polyline ={} self._busy = False self._simulation_running = False @@ -403,7 +403,9 @@ class SimulationView(CuraView): return self._max_feedrate def getSimulationTime(self) -> list: - return self._visible_lengths[self._current_layer_num] / self._current_feedrates[self._current_layer_num] + if len(self._lengths_of_polyline) > 0 and len(self._lengths_of_polyline) == len(self._current_feedrates): + return self._lengths_of_polyline[self._current_layer_num] / self._current_feedrates[self._current_layer_num] + return numpy.zeros(0) def getMinThickness(self) -> float: if abs(self._min_thickness - sys.float_info.max) < 10: # Some lenience due to floating point rounding. @@ -529,10 +531,10 @@ 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._visible_lengths[layer_index] = numpy.take(polyline.lineLengths, visible_indices) + 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] = visible_feedrates + 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 66acff656a..216095c15c 100644 --- a/plugins/SimulationView/SimulationViewMainComponent.qml +++ b/plugins/SimulationView/SimulationViewMainComponent.qml @@ -136,10 +136,9 @@ Item Timer { id: simulationTimer - interval: parseFloat(UM.SimulationView.getSimulationTime[pathNumber]).toFixed(2) + interval: UM.SimulationView.simulationTime running: false repeat: true - property int pathNumber : 0 onTriggered: { var currentPath = UM.SimulationView.currentPath @@ -154,12 +153,10 @@ Item if (currentPath >= numPaths) { UM.SimulationView.setCurrentPath(0) - pathNumber =0 } else { UM.SimulationView.setCurrentPath(currentPath + 1) - pathNumber = 0 } } // If the simulation is already playing and we reach the end of a layer, then it automatically @@ -187,7 +184,6 @@ Item // 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 - pathNumber += 1 } } diff --git a/plugins/SimulationView/SimulationViewProxy.py b/plugins/SimulationView/SimulationViewProxy.py index 669f7fdbcc..e80005fc36 100644 --- a/plugins/SimulationView/SimulationViewProxy.py +++ b/plugins/SimulationView/SimulationViewProxy.py @@ -2,9 +2,11 @@ # 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 +from UM.Logger import Logger if TYPE_CHECKING: from .SimulationView import SimulationView @@ -54,6 +56,19 @@ class SimulationViewProxy(QObject): def currentPath(self): return self._simulation_view.getCurrentPath() + @pyqtProperty(int, notify=currentPathChanged) + def simulationTime(self): + # This if is activated when there is a layer change + if numpy.all(self._simulation_view.getSimulationTime()==0) or len(self._simulation_view.getSimulationTime()) <= self._simulation_view.getCurrentPath(): + return 100 + # Extracts the currents paths simulation time (in seconds) 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()[0][self._simulation_view.getCurrentPath()] * 100 + # Since the timer cannot process time less than 1 ms, we put a lower limit here + if simulationTimeOfpath < 1: + return 1 + return int(simulationTimeOfpath) + @pyqtProperty(int, notify=currentPathChanged) def minimumPath(self): return self._simulation_view.getMinimumPath() From 7711c15ddedcce78e735d0a016f36e0134d3814d Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Fri, 8 Dec 2023 11:43:38 +0100 Subject: [PATCH 32/70] removed unnecessary import CURA-7647 --- plugins/SimulationView/SimulationViewProxy.py | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/SimulationView/SimulationViewProxy.py b/plugins/SimulationView/SimulationViewProxy.py index e80005fc36..8f83e9b403 100644 --- a/plugins/SimulationView/SimulationViewProxy.py +++ b/plugins/SimulationView/SimulationViewProxy.py @@ -6,7 +6,6 @@ import numpy from PyQt6.QtCore import QObject, pyqtSignal, pyqtProperty from UM.FlameProfiler import pyqtSlot from UM.Application import Application -from UM.Logger import Logger if TYPE_CHECKING: from .SimulationView import SimulationView From 3da4fb2d263012612becba3b32289ef12141abb6 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Mon, 11 Dec 2023 09:13:36 +0100 Subject: [PATCH 33/70] Install pdb files Contribute to CURA-11443 --- conanfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conanfile.py b/conanfile.py index e9d06452f3..a3ca8f1c89 100644 --- a/conanfile.py +++ b/conanfile.py @@ -242,7 +242,7 @@ class CuraConan(ConanFile): self.output.warning(f"Source path for binary {binary['binary']} does not exist") continue - for bin in Path(src_path).glob(binary["binary"] + "*[.exe|.dll|.so|.dylib|.so.]*"): + for bin in Path(src_path).glob(binary["binary"] + "*[.exe|.dll|.so|.dylib|.so.|.pdb]*"): binaries.append((str(bin), binary["dst"])) for bin in Path(src_path).glob(binary["binary"]): binaries.append((str(bin), binary["dst"])) From ab480a29ce42d1d8481a5108f169a191b0707d52 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Mon, 11 Dec 2023 09:16:59 +0100 Subject: [PATCH 34/70] Use CuraEngine CURA-11443 Contribute to CURA-11443 --- conandata.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conandata.yml b/conandata.yml index c4dd1ce6de..7f542add2a 100644 --- a/conandata.yml +++ b/conandata.yml @@ -1,7 +1,7 @@ version: "5.7.0-alpha.0" requirements: - "uranium/(latest)@ultimaker/testing" - - "curaengine/(latest)@ultimaker/testing" + - "curaengine/(latest)@ultimaker/cura_11443" - "cura_binary_data/(latest)@ultimaker/testing" - "fdm_materials/(latest)@ultimaker/testing" - "curaengine_plugin_gradual_flow/(latest)@ultimaker/stable" From a19c667106fce8ab4e6f7c7f50bd16c709d2aa51 Mon Sep 17 00:00:00 2001 From: Saumya Jain <70144862+saumyaj3@users.noreply.github.com> Date: Mon, 11 Dec 2023 14:29:33 +0100 Subject: [PATCH 35/70] Update plugins/SimulationView/SimulationViewProxy.py simplified code Co-authored-by: Casper Lamboo --- plugins/SimulationView/SimulationViewProxy.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/SimulationView/SimulationViewProxy.py b/plugins/SimulationView/SimulationViewProxy.py index 8f83e9b403..e3d5ca13a7 100644 --- a/plugins/SimulationView/SimulationViewProxy.py +++ b/plugins/SimulationView/SimulationViewProxy.py @@ -64,9 +64,7 @@ class SimulationViewProxy(QObject): # 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()[0][self._simulation_view.getCurrentPath()] * 100 # Since the timer cannot process time less than 1 ms, we put a lower limit here - if simulationTimeOfpath < 1: - return 1 - return int(simulationTimeOfpath) + return int(max(1, simulationTimeOfpath)) @pyqtProperty(int, notify=currentPathChanged) def minimumPath(self): From ba0fb97d6373bd51c143a4ad7169885bf354c236 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Tue, 12 Dec 2023 10:01:59 +0100 Subject: [PATCH 36/70] Include threshold settings Contributes to CURA-11391 --- resources/definitions/fdmprinter.def.json | 82 +++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index b640fb5746..85785981d6 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -8305,6 +8305,88 @@ } } }, + "ppr": + { + "label": "Print Process Reporting", + "type": "category", + "icon": "DocumentFilled", + "description": "Reporting events that go out of set thresholds", + "enabled": false, + "children": + { + "ppr_enable": + { + "label": "Enable Print Process Reporting", + "description": "Enable print process reporting for setting threshold values for possible fault detection.", + "type": "bool", + "enabled": false, + "default_value": false, + "value": false, + "settable_per_mesh": false, + "settable_per_extruder": false + }, + "flow_warn_limit": + { + "label": "Flow Warning Detection Limit", + "description": "Limit on the flow warning for detection.", + "default_value": "15.0", + "enabled": "ppr_enable", + "unit": "%", + "type": "float", + "settable_per_extruder": true + }, + "flow_anomaly_limit": + { + "label": "Flow Anomaly Detection Limit", + "description": "Limit on flow anomaly for detection.", + "default_value": "25.0", + "enabled": "ppr_enable", + "unit": "%", + "type": "float", + "settable_per_extruder": true + }, + "print_temp_warn_limit": + { + "label": "Print temperature Warning Detection Limit", + "description": "Limit on Print temperature warning for detection.", + "unit": "\u00b0C", + "type": "float", + "default_value": "3.0", + "enabled": "ppr_enable", + "settable_per_extruder": true + }, + "print_temp_anomaly_limit": + { + "label": "Print temperature Anomaly Detection Limit", + "description": "Limit on Print Temperature anomaly for detection.", + "unit": "\u00b0C", + "type": "float", + "default_value": "7.0", + "enabled": "ppr_enable", + "settable_per_extruder": true + }, + "bv_temp_warn_limit": + { + "label": "Build Volume temperature Warning Detection Limit", + "description": "Limit on Build Volume Temperature warning for detection.", + "unit": "\u00b0C", + "type": "float", + "default_value": "7.5", + "enabled": "ppr_enable", + "settable_per_extruder": false + }, + "bv_temp_anomaly_limit": + { + "label": "Build Volume temperature Anomaly Detection Limit", + "description": "Limit on Build Volume temperature Anomaly for detection.", + "unit": "\u00b0C", + "type": "float", + "default_value": "10.0", + "enabled": "ppr_enable", + "settable_per_extruder": false + } + } + }, "command_line_settings": { "label": "Command Line Settings", From cc4627886b85f2e1ef94f3190350e812d591a303 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Tue, 12 Dec 2023 13:01:37 +0100 Subject: [PATCH 37/70] Name shortned for Cura settings CURA-11392 --- resources/definitions/fdmprinter.def.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 85785981d6..62143cf8f8 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -8327,7 +8327,7 @@ }, "flow_warn_limit": { - "label": "Flow Warning Detection Limit", + "label": "Flow Warning", "description": "Limit on the flow warning for detection.", "default_value": "15.0", "enabled": "ppr_enable", @@ -8337,7 +8337,7 @@ }, "flow_anomaly_limit": { - "label": "Flow Anomaly Detection Limit", + "label": "Flow Limit", "description": "Limit on flow anomaly for detection.", "default_value": "25.0", "enabled": "ppr_enable", @@ -8347,7 +8347,7 @@ }, "print_temp_warn_limit": { - "label": "Print temperature Warning Detection Limit", + "label": "Print temperature Warning", "description": "Limit on Print temperature warning for detection.", "unit": "\u00b0C", "type": "float", @@ -8357,7 +8357,7 @@ }, "print_temp_anomaly_limit": { - "label": "Print temperature Anomaly Detection Limit", + "label": "Print temperature Limit", "description": "Limit on Print Temperature anomaly for detection.", "unit": "\u00b0C", "type": "float", @@ -8367,7 +8367,7 @@ }, "bv_temp_warn_limit": { - "label": "Build Volume temperature Warning Detection Limit", + "label": "Build Volume temperature Warning", "description": "Limit on Build Volume Temperature warning for detection.", "unit": "\u00b0C", "type": "float", @@ -8377,7 +8377,7 @@ }, "bv_temp_anomaly_limit": { - "label": "Build Volume temperature Anomaly Detection Limit", + "label": "Build Volume temperature Limit", "description": "Limit on Build Volume temperature Anomaly for detection.", "unit": "\u00b0C", "type": "float", From 189a22aa4fc9a5414424760ccab87a0418cf99d7 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Tue, 12 Dec 2023 14:56:06 +0100 Subject: [PATCH 38/70] refactoring of code for easier access and avoid hanging issues CURA-7647 --- plugins/SimulationView/SimulationView.py | 13 +++++++++---- plugins/SimulationView/SimulationViewProxy.py | 7 ++----- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index 6874b27625..186036a581 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -402,10 +402,13 @@ class SimulationView(CuraView): def getMaxFeedrate(self) -> float: return self._max_feedrate - def getSimulationTime(self) -> list: - if len(self._lengths_of_polyline) > 0 and len(self._lengths_of_polyline) == len(self._current_feedrates): - return self._lengths_of_polyline[self._current_layer_num] / self._current_feedrates[self._current_layer_num] - return numpy.zeros(0) + def getSimulationTime(self, currentIndex) -> list: + try: + return self._lengths_of_polyline[self._current_layer_num][currentIndex] / self._current_feedrates[self._current_layer_num][currentIndex] + 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 def getMinThickness(self) -> float: if abs(self._min_thickness - sys.float_info.max) < 10: # Some lenience due to floating point rounding. @@ -535,6 +538,8 @@ class SimulationView(CuraView): 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 + # if len(polyline.lineLengths) > 0 and len(polyline.lineLengths) == len(polyline.lineFeedrates): + # self._simulation_time[layer_index] = polyline.lineLengths / 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/SimulationViewProxy.py b/plugins/SimulationView/SimulationViewProxy.py index e3d5ca13a7..61366fccbb 100644 --- a/plugins/SimulationView/SimulationViewProxy.py +++ b/plugins/SimulationView/SimulationViewProxy.py @@ -57,12 +57,9 @@ class SimulationViewProxy(QObject): @pyqtProperty(int, notify=currentPathChanged) def simulationTime(self): - # This if is activated when there is a layer change - if numpy.all(self._simulation_view.getSimulationTime()==0) or len(self._simulation_view.getSimulationTime()) <= self._simulation_view.getCurrentPath(): - return 100 - # Extracts the currents paths simulation time (in seconds) from the dict of simulation time of the current layer. + # 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()[0][self._simulation_view.getCurrentPath()] * 100 + simulationTimeOfpath = self._simulation_view.getSimulationTime(self._simulation_view.getCurrentPath()) * 100 # Since the timer cannot process time less than 1 ms, we put a lower limit here return int(max(1, simulationTimeOfpath)) From 3c0b9a65db5e204cecc0dcdb43d8dd59d3b1d4f0 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Tue, 12 Dec 2023 14:59:41 +0100 Subject: [PATCH 39/70] removing commented code CURA-7647 --- plugins/SimulationView/SimulationView.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index 186036a581..cbf5e571fc 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -538,8 +538,6 @@ class SimulationView(CuraView): 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 - # if len(polyline.lineLengths) > 0 and len(polyline.lineLengths) == len(polyline.lineFeedrates): - # self._simulation_time[layer_index] = polyline.lineLengths / 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) From a9aba2df748977554a454ce3e7d7b1667d152e8d Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Tue, 12 Dec 2023 16:06:22 +0100 Subject: [PATCH 40/70] maintenence. CURA-7647 --- plugins/SimulationView/SimulationView.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index cbf5e571fc..a659a6de97 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -402,13 +402,14 @@ class SimulationView(CuraView): def getMaxFeedrate(self) -> float: return self._max_feedrate - def getSimulationTime(self, currentIndex) -> list: + def getSimulationTime(self, currentIndex) -> float: try: - return self._lengths_of_polyline[self._current_layer_num][currentIndex] / self._current_feedrates[self._current_layer_num][currentIndex] + 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 + return 1.0 def getMinThickness(self) -> float: if abs(self._min_thickness - sys.float_info.max) < 10: # Some lenience due to floating point rounding. From 84565b7daa03613087b2544b78fc944e249eae3d Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Tue, 12 Dec 2023 16:53:34 +0100 Subject: [PATCH 41/70] removal of magic number CURA-7647 --- plugins/SimulationView/SimulationViewProxy.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/SimulationView/SimulationViewProxy.py b/plugins/SimulationView/SimulationViewProxy.py index 61366fccbb..576281874c 100644 --- a/plugins/SimulationView/SimulationViewProxy.py +++ b/plugins/SimulationView/SimulationViewProxy.py @@ -12,6 +12,11 @@ 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 @@ -59,7 +64,7 @@ class SimulationViewProxy(QObject): 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()) * 100 + 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)) From 3472ec26a10c330cd6aea040ef70e0d6db94434d Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Tue, 12 Dec 2023 17:19:28 +0100 Subject: [PATCH 42/70] Fix snapshot for makerbot CURA-11442 --- cura/Snapshot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/Snapshot.py b/cura/Snapshot.py index 40c74c9693..f94b3ff42e 100644 --- a/cura/Snapshot.py +++ b/cura/Snapshot.py @@ -49,7 +49,7 @@ class Snapshot: """ if node is None: - root = Application.getInstance().getController().getScene().getRoot() + node = Application.getInstance().getController().getScene().getRoot() # the direction the camera is looking at to create the isometric view iso_view_dir = Vector(-1, -1, -1).normalized() From 5125c7d33a6dd1f36374d084d8100e22c9c3f99c Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Wed, 13 Dec 2023 17:00:02 +0100 Subject: [PATCH 43/70] Don't package system managed openssl This should fall back on the Conan package ssl version which is in the root of the AppDir Contributes to CURA-11080 --- packaging/AppImage-builder/AppImageBuilder.yml.jinja | 1 + 1 file changed, 1 insertion(+) diff --git a/packaging/AppImage-builder/AppImageBuilder.yml.jinja b/packaging/AppImage-builder/AppImageBuilder.yml.jinja index 446c0dacc0..9090a5f209 100644 --- a/packaging/AppImage-builder/AppImageBuilder.yml.jinja +++ b/packaging/AppImage-builder/AppImageBuilder.yml.jinja @@ -38,6 +38,7 @@ AppDir: - usr/share/doc/*/changelog.* - usr/share/doc/*/NEWS.* - usr/share/doc/*/TODO.* + - usr/lib/x86_64-linux-gnu/libssl.so* runtime: env: APPDIR_LIBRARY_PATH: "$APPDIR:$APPDIR/runtime/compat/:$APPDIR/usr/lib/x86_64-linux-gnu:$APPDIR/lib/x86_64-linux-gnu:$APPDIR/usr/lib:$APPDIR/usr/lib/x86_64-linux-gnu/gdk-pixbuf-2.0/2.10.0/loaders" From aebd5f32c5bb82a39d9d2f7a6ab070761e8e7e28 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Fri, 15 Dec 2023 10:08:16 +0100 Subject: [PATCH 44/70] Update Sentry to `1.39.1` Contributes to CURA-11464 --- requirements.txt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/requirements.txt b/requirements.txt index 76339c884f..916886e369 100644 --- a/requirements.txt +++ b/requirements.txt @@ -171,9 +171,9 @@ scipy==1.9.1 \ trimesh==3.9.36 \ --hash=sha256:f01e8edab14d1999700c980c21a1546f37417216ad915a53be649d263130181e \ --hash=sha256:8ac8bea693b3ee119f11b022fc9b9481c9f1af06cb38bc859bf5d16bbbe49b23 -sentry-sdk==0.13.5 \ - --hash=sha256:05285942901d38c7ce2498aba50d8e87b361fc603281a5902dda98f3f8c5e145 \ - --hash=sha256:c6b919623e488134a728f16326c6f0bcdab7e3f59e7f4c472a90eea4d6d8fe82 +sentry-sdk==1.39.1 \ + --hash=sha256:320a55cdf9da9097a0bead239c35b7e61f53660ef9878861824fd6d9b2eaf3b5 \ + --hash=sha256:81b5b9ffdd1a374e9eb0c053b5d2012155db9cbe76393a8585677b753bd5fdc1 mypy==0.931 \ --hash=sha256:0038b21890867793581e4cb0d810829f5fd4441aa75796b53033af3aa30430ce \ --hash=sha256:1171f2e0859cfff2d366da2c7092b06130f232c636a3f7301e3feb8b41f6377d \ @@ -209,9 +209,9 @@ idna==2.8 \ attrs==21.2.0 \ --hash=sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1 \ --hash=sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb -requests==2.22.0 \ - --hash=sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4 \ - --hash=sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31 +requests==2.31.0 \ + --hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1 \ + --hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f # twisted Twisted==21.2.0 \ --hash=sha256:77544a8945cf69b98d2946689bbe0c75de7d145cdf11f391dd487eae8fc95a12 \ @@ -372,9 +372,9 @@ cffi==1.15.0 \ --hash=sha256:f6f824dc3bce0edab5f427efcfb1d63ee75b6fcb7282900ccaf925be84efb0fc \ --hash=sha256:fd8a250edc26254fe5b33be00402e6d287f562b6a5b2152dec302fa15bb3e997 \ --hash=sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796 -urllib3==1.25.9 \ - --hash=sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527 \ - --hash=sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115 +urllib3==2.1.0 \ + --hash=sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54 \ + --hash=sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3 mypy-extensions==0.4.3 \ --hash=sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d \ --hash=sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8 From 139c46fc9dbbb19f7128783369abd0f68e0b36ef Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Fri, 15 Dec 2023 10:23:42 +0100 Subject: [PATCH 45/70] Use generic job name --- .github/workflows/linux.yml | 2 +- .github/workflows/macos.yml | 2 +- .github/workflows/windows.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 2ad8f90bfe..f88b77a022 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -45,7 +45,7 @@ env: STAGING: ${{ inputs.staging || false }} jobs: - windows-installer: + installer: uses: ultimaker/cura-workflows/.github/workflows/cura-installer-linux.yml@main with: cura_conan_version: ${{ inputs.cura_conan_version }} diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index d080fcc710..e909b9f839 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -49,7 +49,7 @@ env: STAGING: ${{ inputs.staging || false }} jobs: - windows-installer: + installer: uses: ultimaker/cura-workflows/.github/workflows/cura-installer-macos.yml@main with: cura_conan_version: ${{ inputs.cura_conan_version }} diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 0007936969..151935c3f3 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -45,7 +45,7 @@ env: STAGING: ${{ inputs.staging || false }} jobs: - windows-installer: + installer: uses: ultimaker/cura-workflows/.github/workflows/cura-installer-windows.yml@main with: cura_conan_version: ${{ inputs.cura_conan_version }} From 64cb060bd1c2ec23d498c81ea50a55957dfad3e6 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Fri, 15 Dec 2023 10:38:33 +0100 Subject: [PATCH 46/70] Revert "Update Sentry to `1.39.1`" This reverts commit aebd5f32c5bb82a39d9d2f7a6ab070761e8e7e28. --- requirements.txt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/requirements.txt b/requirements.txt index 916886e369..76339c884f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -171,9 +171,9 @@ scipy==1.9.1 \ trimesh==3.9.36 \ --hash=sha256:f01e8edab14d1999700c980c21a1546f37417216ad915a53be649d263130181e \ --hash=sha256:8ac8bea693b3ee119f11b022fc9b9481c9f1af06cb38bc859bf5d16bbbe49b23 -sentry-sdk==1.39.1 \ - --hash=sha256:320a55cdf9da9097a0bead239c35b7e61f53660ef9878861824fd6d9b2eaf3b5 \ - --hash=sha256:81b5b9ffdd1a374e9eb0c053b5d2012155db9cbe76393a8585677b753bd5fdc1 +sentry-sdk==0.13.5 \ + --hash=sha256:05285942901d38c7ce2498aba50d8e87b361fc603281a5902dda98f3f8c5e145 \ + --hash=sha256:c6b919623e488134a728f16326c6f0bcdab7e3f59e7f4c472a90eea4d6d8fe82 mypy==0.931 \ --hash=sha256:0038b21890867793581e4cb0d810829f5fd4441aa75796b53033af3aa30430ce \ --hash=sha256:1171f2e0859cfff2d366da2c7092b06130f232c636a3f7301e3feb8b41f6377d \ @@ -209,9 +209,9 @@ idna==2.8 \ attrs==21.2.0 \ --hash=sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1 \ --hash=sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb -requests==2.31.0 \ - --hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1 \ - --hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f +requests==2.22.0 \ + --hash=sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4 \ + --hash=sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31 # twisted Twisted==21.2.0 \ --hash=sha256:77544a8945cf69b98d2946689bbe0c75de7d145cdf11f391dd487eae8fc95a12 \ @@ -372,9 +372,9 @@ cffi==1.15.0 \ --hash=sha256:f6f824dc3bce0edab5f427efcfb1d63ee75b6fcb7282900ccaf925be84efb0fc \ --hash=sha256:fd8a250edc26254fe5b33be00402e6d287f562b6a5b2152dec302fa15bb3e997 \ --hash=sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796 -urllib3==2.1.0 \ - --hash=sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54 \ - --hash=sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3 +urllib3==1.25.9 \ + --hash=sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527 \ + --hash=sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115 mypy-extensions==0.4.3 \ --hash=sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d \ --hash=sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8 From a071795f9e5415f575cd7e8e86e3347faf8e6a1a Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Fri, 15 Dec 2023 12:43:54 +0100 Subject: [PATCH 47/70] Fix monitor page CURA-11426 --- 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 aed38a3949..9a11bb886c 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.pinterType in ("ultimaker_methodx", "ultimaker_methodxl") + return printer.name in ("ultimaker_methodx", "ultimaker_methodxl") @pyqtProperty(bool, notify=_cloudClusterPrintersChanged) def supportsPrintJobActions(self) -> bool: From a6218c3f5432a6d08d0ff852f67892119b317a7d Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Fri, 15 Dec 2023 18:08:46 +0100 Subject: [PATCH 48/70] Use cura sentry id and version Contribute to CURA-11482 --- conandata.yml | 2 +- plugins/CuraEngineBackend/Cura.proto | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/conandata.yml b/conandata.yml index a0a5a204ca..dcf883c630 100644 --- a/conandata.yml +++ b/conandata.yml @@ -1,7 +1,7 @@ version: "5.7.0-alpha.0" requirements: - "uranium/(latest)@ultimaker/testing" - - "curaengine/(latest)@ultimaker/testing" + - "curaengine/(latest)@ultimaker/cura_11482" - "cura_binary_data/(latest)@ultimaker/testing" - "fdm_materials/(latest)@ultimaker/testing" - "curaengine_plugin_gradual_flow/(latest)@ultimaker/stable" diff --git a/plugins/CuraEngineBackend/Cura.proto b/plugins/CuraEngineBackend/Cura.proto index 54c322fa0a..9593b83528 100644 --- a/plugins/CuraEngineBackend/Cura.proto +++ b/plugins/CuraEngineBackend/Cura.proto @@ -33,6 +33,8 @@ message Slice repeated Extruder extruders = 3; // The settings sent to each extruder object repeated SettingExtruder limit_to_extruder = 4; // From which stack the setting would inherit if not defined per object repeated EnginePlugin engine_plugins = 5; + string sentry_id = 6; // The anonymized Sentry user id that requested the slice + string cura_version = 7; // The version of Cura that requested the slice } message Extruder From 5744371f380e8c7baa47c2ab05bea9157c5d7e58 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Sun, 17 Dec 2023 17:44:30 +0100 Subject: [PATCH 49/70] Add anonymous user tracking to slice message User tracking has been added to the 'slice_message' method in the 'StartSliceJob.py' file. A unique, anonymous UUID is generated for each user, stripping away identifiable data with a bitmask operation. The user's Cura version is also included in the message. This facilitates more robust analysis of crash reports and user behaviors. Contributes to CURA-11482 --- plugins/CuraEngineBackend/StartSliceJob.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index a12e9e655d..fe7137150b 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -1,5 +1,7 @@ # Copyright (c) 2023 UltiMaker # Cura is released under the terms of the LGPLv3 or higher. +import uuid + import os import numpy @@ -30,6 +32,7 @@ from cura.CuraApplication import CuraApplication from cura.Scene.CuraSceneNode import CuraSceneNode from cura.OneAtATimeIterator import OneAtATimeIterator from cura.Settings.ExtruderManager import ExtruderManager +from cura.CuraVersion import CuraVersion NON_PRINTING_MESH_SETTINGS = ["anti_overhang_mesh", "infill_mesh", "cutting_mesh"] @@ -332,6 +335,11 @@ class StartSliceJob(Job): self._buildGlobalSettingsMessage(stack) self._buildGlobalInheritsStackMessage(stack) + 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.cura_version = CuraVersion + # Build messages for extruder stacks for extruder_stack in global_stack.extruderList: self._buildExtruderMessage(extruder_stack) From 82a3308d26a94ed834b5247dc2bfe945f68dee06 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Mon, 18 Dec 2023 17:03:52 +0100 Subject: [PATCH 50/70] for merging to main CURA-11482 --- conandata.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conandata.yml b/conandata.yml index dcf883c630..a0a5a204ca 100644 --- a/conandata.yml +++ b/conandata.yml @@ -1,7 +1,7 @@ version: "5.7.0-alpha.0" requirements: - "uranium/(latest)@ultimaker/testing" - - "curaengine/(latest)@ultimaker/cura_11482" + - "curaengine/(latest)@ultimaker/testing" - "cura_binary_data/(latest)@ultimaker/testing" - "fdm_materials/(latest)@ultimaker/testing" - "curaengine_plugin_gradual_flow/(latest)@ultimaker/stable" From cfec5e0cc112181d4db4af13ed6a0f8ec3047669 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Tue, 19 Dec 2023 10:12:56 +0100 Subject: [PATCH 51/70] 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 52/70] 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 53/70] 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 54/70] 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 55/70] 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 56/70] 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 57/70] 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 58/70] 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 59/70] 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 60/70] 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 61/70] 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 62/70] 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 63/70] 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 64/70] 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 65/70] 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 66/70] 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 67/70] 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 68/70] 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 69/70] 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 70/70] 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],