From 8d13cfb5d626f5b31efd28bfb53a8bc0534ab062 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Sat, 3 Apr 2021 16:03:20 +0200 Subject: [PATCH 1/9] Make limits in colour scheme depend on the visible line types This way, if travel moves are not currently visible in the layer view, the travel moves don't get counted with the limits to determine the colour spectrum to grade each line with. Quite often, travel moves had a much greater speed than other moves, like 120mm/s instead of the fastest printed line 60mm/s. This caused all of the layer view to be pushed into the lower end of the spectrum. It makes it hard to distinguish the differences in speed and line width because travel moves influence the spectrum so much. This way, the travel moves only influence the spectrum if they are visible. If they are visible, it might be relevant to the user. Otherwise, the user gets the full spectrum to differentiate between all the line widths and speeds. This currently doesn't update correctly yet. That is something we'll need to fix. --- plugins/SimulationView/SimulationView.py | 43 +++++++++++++++++++----- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index 9494e42a5e..1cf7a26768 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -1,4 +1,4 @@ -# Copyright (c) 2020 Ultimaker B.V. +# Copyright (c) 2021 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. import sys @@ -30,6 +30,7 @@ from UM.View.GL.ShaderProgram import ShaderProgram from UM.i18n import i18nCatalog from cura.CuraView import CuraView +from cura.LayerPolygon import LayerPolygon # To distinguish line types. from cura.Scene.ConvexHullNode import ConvexHullNode from cura.CuraApplication import CuraApplication @@ -399,11 +400,32 @@ class SimulationView(CuraView): return self._min_line_width def calculateMaxLayers(self) -> None: + """ + Calculates number of layers, and the limits of each statistic for the colour schemes. + """ scene = self.getController().getScene() + visible_line_types = [] + if self.getShowSkin(): # Actually "shell". + visible_line_types.append(LayerPolygon.SkinType) + visible_line_types.append(LayerPolygon.Inset0Type) + visible_line_types.append(LayerPolygon.InsetXType) + if self.getShowStarts(): + visible_line_types.append(LayerPolygon.NoneType) + if self.getShowInfill(): + visible_line_types.append(LayerPolygon.InfillType) + if self.getShowHelpers(): + visible_line_types.append(LayerPolygon.PrimeTowerType) + visible_line_types.append(LayerPolygon.SkirtType) + visible_line_types.append(LayerPolygon.SupportType) + visible_line_types.append(LayerPolygon.SupportInfillType) + visible_line_types.append(LayerPolygon.SupportInterfaceType) + if self.getShowTravelMoves(): + visible_line_types.append(LayerPolygon.MoveCombingType) + visible_line_types.append(LayerPolygon.MoveRetractionType) + self._old_max_layers = self._max_layers new_max_layers = -1 - """Recalculate num max layers""" for node in DepthFirstIterator(scene.getRoot()): # type: ignore layer_data = node.callDecoration("getLayerData") if not layer_data: @@ -420,13 +442,18 @@ class SimulationView(CuraView): # Store the max and min feedrates and thicknesses for display purposes for p in layer_data.getLayer(layer_id).polygons: - self._max_feedrate = max(float(p.lineFeedrates.max()), self._max_feedrate) - self._min_feedrate = min(float(p.lineFeedrates.min()), self._min_feedrate) - self._max_line_width = max(float(p.lineWidths.max()), self._max_line_width) - self._min_line_width = min(float(p.lineWidths.min()), self._min_line_width) - self._max_thickness = max(float(p.lineThicknesses.max()), self._max_thickness) + is_visible = numpy.isin(p.types, visible_line_types) + visible_indices = numpy.where(is_visible) + visible_feedrates = numpy.take(p.lineFeedrates, visible_indices) + visible_linewidths = numpy.take(p.lineWidths, visible_indices) + visible_thicknesses = numpy.take(p.lineThicknesses, visible_indices) + self._max_feedrate = max(float(visible_feedrates.max()), self._max_feedrate) + self._min_feedrate = min(float(visible_feedrates.min()), self._min_feedrate) + self._max_line_width = max(float(visible_linewidths.max()), self._max_line_width) + self._min_line_width = min(float(visible_linewidths.min()), self._min_line_width) + self._max_thickness = max(float(visible_thicknesses.max()), self._max_thickness) try: - self._min_thickness = min(float(p.lineThicknesses[numpy.nonzero(p.lineThicknesses)].min()), self._min_thickness) + self._min_thickness = min(float(visible_thicknesses[numpy.nonzero(visible_thicknesses)].min()), self._min_thickness) except ValueError: # Sometimes, when importing a GCode the line thicknesses are zero and so the minimum (avoiding # the zero) can't be calculated From 28f8da8f7b44dc5de66e260e99af596bd50d1363 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Sat, 3 Apr 2021 16:16:02 +0200 Subject: [PATCH 2/9] Move calculation of simulation spectrum limits to separate function This is just a refactor that shouldn't have any influence on the behaviour. It is a necessary prerequisite to be able to trigger the updating of the layer view colour spectrum more frequently, i.e. if the visible line types change. --- plugins/SimulationView/SimulationView.py | 84 ++++++++++++++---------- 1 file changed, 48 insertions(+), 36 deletions(-) diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index 1cf7a26768..94a5fcd4e2 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -405,24 +405,7 @@ class SimulationView(CuraView): """ scene = self.getController().getScene() - visible_line_types = [] - if self.getShowSkin(): # Actually "shell". - visible_line_types.append(LayerPolygon.SkinType) - visible_line_types.append(LayerPolygon.Inset0Type) - visible_line_types.append(LayerPolygon.InsetXType) - if self.getShowStarts(): - visible_line_types.append(LayerPolygon.NoneType) - if self.getShowInfill(): - visible_line_types.append(LayerPolygon.InfillType) - if self.getShowHelpers(): - visible_line_types.append(LayerPolygon.PrimeTowerType) - visible_line_types.append(LayerPolygon.SkirtType) - visible_line_types.append(LayerPolygon.SupportType) - visible_line_types.append(LayerPolygon.SupportInfillType) - visible_line_types.append(LayerPolygon.SupportInterfaceType) - if self.getShowTravelMoves(): - visible_line_types.append(LayerPolygon.MoveCombingType) - visible_line_types.append(LayerPolygon.MoveRetractionType) + self.calculateColorSchemeLimits() self._old_max_layers = self._max_layers new_max_layers = -1 @@ -440,24 +423,6 @@ class SimulationView(CuraView): if len(layer_data.getLayer(layer_id).polygons) < 1: continue - # Store the max and min feedrates and thicknesses for display purposes - for p in layer_data.getLayer(layer_id).polygons: - is_visible = numpy.isin(p.types, visible_line_types) - visible_indices = numpy.where(is_visible) - visible_feedrates = numpy.take(p.lineFeedrates, visible_indices) - visible_linewidths = numpy.take(p.lineWidths, visible_indices) - visible_thicknesses = numpy.take(p.lineThicknesses, visible_indices) - self._max_feedrate = max(float(visible_feedrates.max()), self._max_feedrate) - self._min_feedrate = min(float(visible_feedrates.min()), self._min_feedrate) - self._max_line_width = max(float(visible_linewidths.max()), self._max_line_width) - self._min_line_width = min(float(visible_linewidths.min()), self._min_line_width) - self._max_thickness = max(float(visible_thicknesses.max()), self._max_thickness) - try: - self._min_thickness = min(float(visible_thicknesses[numpy.nonzero(visible_thicknesses)].min()), self._min_thickness) - except ValueError: - # Sometimes, when importing a GCode the line thicknesses are zero and so the minimum (avoiding - # the zero) can't be calculated - Logger.log("i", "Min thickness can't be calculated because all the values are zero") if max_layer_number < layer_id: max_layer_number = layer_id if min_layer_number > layer_id: @@ -481,6 +446,53 @@ class SimulationView(CuraView): self.maxLayersChanged.emit() self._startUpdateTopLayers() + def calculateColorSchemeLimits(self) -> None: + """ + Calculates the limits of the colour schemes, depending on the layer view data that is visible to the user. + """ + # The colour scheme is only influenced by the visible lines, so filter the lines by if they should be visible. + visible_line_types = [] + if self.getShowSkin(): # Actually "shell". + visible_line_types.append(LayerPolygon.SkinType) + visible_line_types.append(LayerPolygon.Inset0Type) + visible_line_types.append(LayerPolygon.InsetXType) + if self.getShowInfill(): + visible_line_types.append(LayerPolygon.InfillType) + if self.getShowHelpers(): + visible_line_types.append(LayerPolygon.PrimeTowerType) + visible_line_types.append(LayerPolygon.SkirtType) + visible_line_types.append(LayerPolygon.SupportType) + visible_line_types.append(LayerPolygon.SupportInfillType) + visible_line_types.append(LayerPolygon.SupportInterfaceType) + if self.getShowTravelMoves(): + visible_line_types.append(LayerPolygon.MoveCombingType) + visible_line_types.append(LayerPolygon.MoveRetractionType) + + for node in DepthFirstIterator(self.getController().getScene().getRoot()): + layer_data = node.callDecoration("getLayerData") + if not layer_data: + continue + + for layer_index in layer_data.getLayers(): + if len(layer_data.getLayer(layer_index).polygons) <= 0: # Empty layer. + continue # Skip for performance. + for polyline in layer_data.getLayer(layer_index).polygons: + is_visible = numpy.isin(polyline.types, visible_line_types) + visible_indices = numpy.where(is_visible) + visible_feedrates = numpy.take(polyline.lineFeedrates, visible_indices) + visible_linewidths = numpy.take(polyline.lineWidths, visible_indices) + visible_thicknesses = numpy.take(polyline.lineThicknesses, visible_indices) + self._max_feedrate = max(float(visible_feedrates.max()), self._max_feedrate) + self._min_feedrate = min(float(visible_feedrates.min()), self._min_feedrate) + self._max_line_width = max(float(visible_linewidths.max()), self._max_line_width) + self._min_line_width = min(float(visible_linewidths.min()), self._min_line_width) + self._max_thickness = max(float(visible_thicknesses.max()), self._max_thickness) + try: + self._min_thickness = min(float(visible_thicknesses[numpy.nonzero(visible_thicknesses)].min()), self._min_thickness) + except ValueError: + # Sometimes, when importing a GCode the line thicknesses are zero and so the minimum (avoiding the zero) can't be calculated. + Logger.log("i", "Min thickness can't be calculated because all the values are zero") + def calculateMaxPathsOnLayer(self, layer_num: int) -> None: # Update the currentPath scene = self.getController().getScene() From 424f037dcab4e446117d2b331840f46ee1de591e Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Sat, 3 Apr 2021 16:30:10 +0200 Subject: [PATCH 3/9] Trigger recalculation of colour scheme limits when visibility changes While it's now correctly triggered to recalculate, it doesn't correctly update yet in the interface. We'll need to resolve that next. --- plugins/SimulationView/SimulationView.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index 94a5fcd4e2..14e2fdb3fb 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -116,6 +116,7 @@ class SimulationView(CuraView): Application.getInstance().getPreferences().addPreference("layerview/show_infill", True) Application.getInstance().getPreferences().addPreference("layerview/show_starts", True) + self.visibleStructuresChanged.connect(self.calculateColorSchemeLimits) self._updateWithPreferences() self._solid_layers = int(Application.getInstance().getPreferences().getValue("view/top_layer_count")) @@ -199,6 +200,7 @@ class SimulationView(CuraView): if node.getMeshData() is None: return self.setActivity(False) + self.calculateColorSchemeLimits() self.calculateMaxLayers() self.calculateMaxPathsOnLayer(self._current_layer_num) @@ -335,36 +337,51 @@ class SimulationView(CuraView): return Matrix(self._extruder_opacity) def setShowTravelMoves(self, show): + if show == self._show_travel_moves: + return self._show_travel_moves = show self.currentLayerNumChanged.emit() + self.visibleStructuresChanged.emit() def getShowTravelMoves(self): return self._show_travel_moves def setShowHelpers(self, show: bool) -> None: + if show == self._show_helpers: + return self._show_helpers = show self.currentLayerNumChanged.emit() + self.visibleStructuresChanged.emit() def getShowHelpers(self) -> bool: return self._show_helpers def setShowSkin(self, show: bool) -> None: + if show == self._show_skin: + return self._show_skin = show self.currentLayerNumChanged.emit() + self.visibleStructuresChanged.emit() def getShowSkin(self) -> bool: return self._show_skin def setShowInfill(self, show: bool) -> None: + if show == self._show_infill: + return self._show_infill = show self.currentLayerNumChanged.emit() + self.visibleStructuresChanged.emit() def getShowInfill(self) -> bool: return self._show_infill def setShowStarts(self, show: bool) -> None: + if show == self._show_starts: + return self._show_starts = show self.currentLayerNumChanged.emit() + self.visibleStructuresChanged.emit() def getShowStarts(self) -> bool: return self._show_starts @@ -401,12 +418,11 @@ class SimulationView(CuraView): def calculateMaxLayers(self) -> None: """ - Calculates number of layers, and the limits of each statistic for the colour schemes. + Calculates number of layers, triggers signals if the number of layers changed and makes sure the top layers are + recalculated for legacy layer view. """ scene = self.getController().getScene() - self.calculateColorSchemeLimits() - self._old_max_layers = self._max_layers new_max_layers = -1 for node in DepthFirstIterator(scene.getRoot()): # type: ignore @@ -519,6 +535,7 @@ class SimulationView(CuraView): preferencesChanged = Signal() busyChanged = Signal() activityChanged = Signal() + visibleStructuresChanged = Signal() def getProxy(self, engine, script_engine): """Hackish way to ensure the proxy is already created @@ -550,6 +567,7 @@ class SimulationView(CuraView): Application.getInstance().getPreferences().preferenceChanged.connect(self._onPreferencesChanged) self._controller.getScene().getRoot().childrenChanged.connect(self._onSceneChanged) + self.calculateColorSchemeLimits() self.calculateMaxLayers() self.calculateMaxPathsOnLayer(self._current_layer_num) From 9f902f7a7a1c608a4adbba6e9fa1ae6ca724bc23 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Sat, 3 Apr 2021 16:49:04 +0200 Subject: [PATCH 4/9] Update colour scheme limits if visibility changed the limits If the user makes certain structures visible or invisible, and this then causes the limits of the colour scheme to change, this now triggers the layer view to be re-rendered and updates the legend in the simulation view menu component. --- plugins/SimulationView/SimulationView.py | 14 ++++++++ .../SimulationViewMenuComponent.qml | 12 +++---- plugins/SimulationView/SimulationViewProxy.py | 32 +++++++++++-------- 3 files changed, 39 insertions(+), 19 deletions(-) diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index 14e2fdb3fb..d116b10597 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -466,6 +466,14 @@ class SimulationView(CuraView): """ Calculates the limits of the colour schemes, depending on the layer view data that is visible to the user. """ + # Before we start, save the old values so that we can tell if any of the spectrums need to change. + old_min_feedrate = self._min_feedrate + old_max_feedrate = self._max_feedrate + old_min_linewidth = self._min_line_width + old_max_linewidth = self._max_line_width + old_min_thickness = self._min_thickness + old_max_thickness = self._max_thickness + # The colour scheme is only influenced by the visible lines, so filter the lines by if they should be visible. visible_line_types = [] if self.getShowSkin(): # Actually "shell". @@ -509,6 +517,11 @@ class SimulationView(CuraView): # Sometimes, when importing a GCode the line thicknesses are zero and so the minimum (avoiding the zero) can't be calculated. Logger.log("i", "Min thickness can't be calculated because all the values are zero") + if old_min_feedrate != self._min_feedrate or old_max_feedrate != self._max_feedrate \ + or old_min_linewidth != self._min_line_width or old_max_linewidth != self._max_line_width \ + or old_min_thickness != self._min_thickness or old_max_thickness != self._max_thickness: + self.colorSchemeLimitsChanged.emit() + def calculateMaxPathsOnLayer(self, layer_num: int) -> None: # Update the currentPath scene = self.getController().getScene() @@ -536,6 +549,7 @@ class SimulationView(CuraView): busyChanged = Signal() activityChanged = Signal() visibleStructuresChanged = Signal() + colorSchemeLimitsChanged = Signal() def getProxy(self, engine, script_engine): """Hackish way to ensure the proxy is already created diff --git a/plugins/SimulationView/SimulationViewMenuComponent.qml b/plugins/SimulationView/SimulationViewMenuComponent.qml index 708fc932c8..a1ffc22908 100644 --- a/plugins/SimulationView/SimulationViewMenuComponent.qml +++ b/plugins/SimulationView/SimulationViewMenuComponent.qml @@ -389,17 +389,17 @@ Cura.ExpandableComponent // Feedrate selected if (UM.Preferences.getValue("layerview/layer_view_type") == 2) { - return parseFloat(UM.SimulationView.getMinFeedrate()).toFixed(2) + return parseFloat(UM.SimulationView.minFeedrate).toFixed(2) } // Layer thickness selected if (UM.Preferences.getValue("layerview/layer_view_type") == 3) { - return parseFloat(UM.SimulationView.getMinThickness()).toFixed(2) + return parseFloat(UM.SimulationView.minThickness).toFixed(2) } //Line width selected if(UM.Preferences.getValue("layerview/layer_view_type") == 4) { - return parseFloat(UM.SimulationView.getMinLineWidth()).toFixed(2); + return parseFloat(UM.SimulationView.minLineWidth).toFixed(2); } } return catalog.i18nc("@label","min") @@ -448,17 +448,17 @@ Cura.ExpandableComponent // Feedrate selected if (UM.Preferences.getValue("layerview/layer_view_type") == 2) { - return parseFloat(UM.SimulationView.getMaxFeedrate()).toFixed(2) + return parseFloat(UM.SimulationView.maxFeedrate).toFixed(2) } // Layer thickness selected if (UM.Preferences.getValue("layerview/layer_view_type") == 3) { - return parseFloat(UM.SimulationView.getMaxThickness()).toFixed(2) + return parseFloat(UM.SimulationView.maxThickness).toFixed(2) } //Line width selected if(UM.Preferences.getValue("layerview/layer_view_type") == 4) { - return parseFloat(UM.SimulationView.getMaxLineWidth()).toFixed(2); + return parseFloat(UM.SimulationView.maxLineWidth).toFixed(2); } } return catalog.i18nc("@label","max") diff --git a/plugins/SimulationView/SimulationViewProxy.py b/plugins/SimulationView/SimulationViewProxy.py index 12947f6464..bdf787ab3a 100644 --- a/plugins/SimulationView/SimulationViewProxy.py +++ b/plugins/SimulationView/SimulationViewProxy.py @@ -1,4 +1,4 @@ -# Copyright (c) 2018 Ultimaker B.V. +# Copyright (c) 2021 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. from typing import TYPE_CHECKING @@ -28,6 +28,7 @@ class SimulationViewProxy(QObject): globalStackChanged = pyqtSignal() preferencesChanged = pyqtSignal() busyChanged = pyqtSignal() + colorSchemeLimitsChanged = pyqtSignal() @pyqtProperty(bool, notify=activityChanged) def layerActivity(self): @@ -101,28 +102,28 @@ class SimulationViewProxy(QObject): def getSimulationRunning(self): return self._simulation_view.isSimulationRunning() - @pyqtSlot(result=float) - def getMinFeedrate(self): + @pyqtProperty(float, notify = colorSchemeLimitsChanged) + def minFeedrate(self): return self._simulation_view.getMinFeedrate() - @pyqtSlot(result=float) - def getMaxFeedrate(self): + @pyqtProperty(float, notify = colorSchemeLimitsChanged) + def maxFeedrate(self): return self._simulation_view.getMaxFeedrate() - @pyqtSlot(result=float) - def getMinThickness(self): + @pyqtProperty(float, notify = colorSchemeLimitsChanged) + def minThickness(self): return self._simulation_view.getMinThickness() - @pyqtSlot(result=float) - def getMaxThickness(self): + @pyqtProperty(float, notify = colorSchemeLimitsChanged) + def maxThickness(self): return self._simulation_view.getMaxThickness() - @pyqtSlot(result=float) - def getMaxLineWidth(self): + @pyqtProperty(float, notify = colorSchemeLimitsChanged) + def maxLineWidth(self): return self._simulation_view.getMaxLineWidth() - @pyqtSlot(result=float) - def getMinLineWidth(self): + @pyqtProperty(float, notify = colorSchemeLimitsChanged) + def minLineWidth(self): return self._simulation_view.getMinLineWidth() # Opacity 0..1 @@ -153,6 +154,9 @@ class SimulationViewProxy(QObject): self.currentLayerChanged.emit() self._layerActivityChanged() + def _onColorSchemeLimitsChanged(self): + self.colorSchemeLimitsChanged.emit() + def _onPathChanged(self): self.currentPathChanged.emit() self._layerActivityChanged() @@ -182,6 +186,7 @@ class SimulationViewProxy(QObject): active_view = self._controller.getActiveView() if active_view == self._simulation_view: self._simulation_view.currentLayerNumChanged.connect(self._onLayerChanged) + self._simulation_view.colorSchemeLimitsChanged.connect(self._onColorSchemeLimitsChanged) self._simulation_view.currentPathNumChanged.connect(self._onPathChanged) self._simulation_view.maxLayersChanged.connect(self._onMaxLayersChanged) self._simulation_view.maxPathsChanged.connect(self._onMaxPathsChanged) @@ -194,6 +199,7 @@ class SimulationViewProxy(QObject): # Disconnect all of em again. self.is_simulationView_selected = False self._simulation_view.currentLayerNumChanged.disconnect(self._onLayerChanged) + self._simulation_view.colorSchemeLimitsChanged.connect(self._onColorSchemeLimitsChanged) self._simulation_view.currentPathNumChanged.disconnect(self._onPathChanged) self._simulation_view.maxLayersChanged.disconnect(self._onMaxLayersChanged) self._simulation_view.maxPathsChanged.disconnect(self._onMaxPathsChanged) From b5bc4aecd5b1beeeb50ac4aa973c846f97da743d Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Sat, 3 Apr 2021 16:56:36 +0200 Subject: [PATCH 5/9] Reset color scheme limits before every recalculation This prevents previous measurements from influencing the colour scheme. Essentially previously it was showing the colour scheme based on all lines you had ever seen, rather than just the line types you were currently seeing. --- plugins/SimulationView/SimulationView.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index d116b10597..824da0f60a 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -221,12 +221,6 @@ class SimulationView(CuraView): def resetLayerData(self) -> None: self._current_layer_mesh = None self._current_layer_jumps = None - self._max_feedrate = sys.float_info.min - self._min_feedrate = sys.float_info.max - self._max_thickness = sys.float_info.min - self._min_thickness = sys.float_info.max - self._max_line_width = sys.float_info.min - self._min_line_width = sys.float_info.max def beginRendering(self) -> None: scene = self.getController().getScene() @@ -474,6 +468,13 @@ class SimulationView(CuraView): old_min_thickness = self._min_thickness old_max_thickness = self._max_thickness + self._min_feedrate = sys.float_info.max + self._max_feedrate = sys.float_info.min + self._min_line_width = sys.float_info.max + self._max_line_width = sys.float_info.min + self._min_thickness = sys.float_info.max + self._max_thickness = sys.float_info.min + # The colour scheme is only influenced by the visible lines, so filter the lines by if they should be visible. visible_line_types = [] if self.getShowSkin(): # Actually "shell". From 9b1941a4a26d9c88ef0ab185955dfdd89afca369 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Sat, 3 Apr 2021 17:07:01 +0200 Subject: [PATCH 6/9] Don't crash if there are no visible lines in a polyline --- plugins/SimulationView/SimulationView.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index 824da0f60a..903c937d19 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -499,11 +499,11 @@ class SimulationView(CuraView): continue for layer_index in layer_data.getLayers(): - if len(layer_data.getLayer(layer_index).polygons) <= 0: # Empty layer. - continue # Skip for performance. for polyline in layer_data.getLayer(layer_index).polygons: is_visible = numpy.isin(polyline.types, visible_line_types) visible_indices = numpy.where(is_visible) + if visible_indices[0].size == 0: # No items to take maximum or minimum of. + continue visible_feedrates = numpy.take(polyline.lineFeedrates, visible_indices) visible_linewidths = numpy.take(polyline.lineWidths, visible_indices) visible_thicknesses = numpy.take(polyline.lineThicknesses, visible_indices) From 6209a08121265c874dabf8e8bcf23fbfa482a1d4 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Sat, 3 Apr 2021 17:19:24 +0200 Subject: [PATCH 7/9] Fix accidentally always taking 0th line along The input array here is 2D, but always 1 by N long. The output of where then gives a tuple of two arrays, one indicating the Y positions and the other the X positions. The X positions were therefore always 0. The amin and amax functions were then always taking this index 0 along in their results, regardless of whether the line at that index was visible at all or not. This will also improve performance since it's checking the limits now only for half as many indices. --- plugins/SimulationView/SimulationView.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index 903c937d19..9ae715beec 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -501,8 +501,8 @@ class SimulationView(CuraView): for layer_index in layer_data.getLayers(): for polyline in layer_data.getLayer(layer_index).polygons: is_visible = numpy.isin(polyline.types, visible_line_types) - visible_indices = numpy.where(is_visible) - if visible_indices[0].size == 0: # No items to take maximum or minimum of. + visible_indices = numpy.where(is_visible)[0] + if visible_indices.size == 0: # No items to take maximum or minimum of. continue visible_feedrates = numpy.take(polyline.lineFeedrates, visible_indices) visible_linewidths = numpy.take(polyline.lineWidths, visible_indices) From 71b217c624b09d68735f34c1b9f31b3f5b37e2e1 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Sat, 3 Apr 2021 17:29:33 +0200 Subject: [PATCH 8/9] Fix colour calculations if spectrum is entirely one value If the range of the colour spectrum is 0, i.e. there is only one value for the current colour spectrum, then this would previously give a division by 0 in the shader, causing the final colour to become black. This is unexpected and makes the layer view hard to read. Instead, we'll now use the middle of the range then. This was likely a problem for a long time but only really became visible due to the colour spectrum now showing only the range of values for the visible structures. Previously it was a problem e.g. for layer thickness if all layers had the same thickness (i.e. initial layer height == layer height). --- plugins/SimulationView/layers3d.shader | 30 +++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/plugins/SimulationView/layers3d.shader b/plugins/SimulationView/layers3d.shader index 6a2ff63b8e..1b4c3be4cf 100644 --- a/plugins/SimulationView/layers3d.shader +++ b/plugins/SimulationView/layers3d.shader @@ -44,7 +44,15 @@ vertex41core = vec4 feedrateGradientColor(float abs_value, float min_value, float max_value) { - float value = (abs_value - min_value)/(max_value - min_value); + float value; + if(abs(max_value - min_value) < 0.0001) //Max and min are equal (barring floating point rounding errors). + { + value = 0.5; //Pick a colour in exactly the middle of the range. + } + else + { + value = (abs_value - min_value) / (max_value - min_value); + } float red = value; float green = 1-abs(1-4*value); if (value > 0.375) @@ -57,7 +65,15 @@ vertex41core = vec4 layerThicknessGradientColor(float abs_value, float min_value, float max_value) { - float value = (abs_value - min_value)/(max_value - min_value); + float value; + if(abs(max_value - min_value) < 0.0001) //Max and min are equal (barring floating point rounding errors). + { + value = 0.5; //Pick a colour in exactly the middle of the range. + } + else + { + value = (abs_value - min_value) / (max_value - min_value); + } float red = min(max(4*value-2, 0), 1); float green = min(1.5*value, 0.75); if (value > 0.75) @@ -70,7 +86,15 @@ vertex41core = vec4 lineWidthGradientColor(float abs_value, float min_value, float max_value) { - float value = (abs_value - min_value) / (max_value - min_value); + float value; + if(abs(max_value - min_value) < 0.0001) //Max and min are equal (barring floating point rounding errors). + { + value = 0.5; //Pick a colour in exactly the middle of the range. + } + else + { + value = (abs_value - min_value) / (max_value - min_value); + } float red = value; float green = 1 - abs(1 - 4 * value); if(value > 0.375) From 972e024a43b338cc67edb5e21b4edec01a849910 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 15 Apr 2021 19:31:57 +0200 Subject: [PATCH 9/9] Add typing for get/setShowTravelMoves This one was missing. The rest already seems to have typing. --- plugins/SimulationView/SimulationView.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index 9ae715beec..cf555590e6 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -330,14 +330,14 @@ class SimulationView(CuraView): # If more than 16 extruders are called for, this should be converted to a sampler1d. return Matrix(self._extruder_opacity) - def setShowTravelMoves(self, show): + def setShowTravelMoves(self, show: bool) -> None: if show == self._show_travel_moves: return self._show_travel_moves = show self.currentLayerNumChanged.emit() self.visibleStructuresChanged.emit() - def getShowTravelMoves(self): + def getShowTravelMoves(self) -> bool: return self._show_travel_moves def setShowHelpers(self, show: bool) -> None: