mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-06 14:37:29 -06:00
Merge branch 'layer_view_statistic_limits_only_visible' of github.com:Ultimaker/Cura
This commit is contained in:
commit
eb3bdfc18a
4 changed files with 146 additions and 44 deletions
|
@ -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
|
||||
|
||||
|
@ -115,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"))
|
||||
|
@ -198,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)
|
||||
|
||||
|
@ -218,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()
|
||||
|
@ -334,37 +331,52 @@ 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:
|
||||
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
|
||||
|
@ -400,11 +412,14 @@ class SimulationView(CuraView):
|
|||
return self._min_line_width
|
||||
|
||||
def calculateMaxLayers(self) -> None:
|
||||
"""
|
||||
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._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:
|
||||
|
@ -419,19 +434,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:
|
||||
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)
|
||||
try:
|
||||
self._min_thickness = min(float(p.lineThicknesses[numpy.nonzero(p.lineThicknesses)].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:
|
||||
|
@ -455,6 +457,73 @@ 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.
|
||||
"""
|
||||
# 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
|
||||
|
||||
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".
|
||||
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():
|
||||
for polyline in layer_data.getLayer(layer_index).polygons:
|
||||
is_visible = numpy.isin(polyline.types, visible_line_types)
|
||||
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)
|
||||
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")
|
||||
|
||||
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()
|
||||
|
@ -481,6 +550,8 @@ class SimulationView(CuraView):
|
|||
preferencesChanged = Signal()
|
||||
busyChanged = Signal()
|
||||
activityChanged = Signal()
|
||||
visibleStructuresChanged = Signal()
|
||||
colorSchemeLimitsChanged = Signal()
|
||||
|
||||
def getProxy(self, engine, script_engine):
|
||||
"""Hackish way to ensure the proxy is already created
|
||||
|
@ -512,6 +583,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)
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue