CURA-4526 Add the SimulationView plugin to Cura and deleting LayerView

plugin
This commit is contained in:
Diego Prado Gesto 2017-11-17 14:27:46 +01:00
parent 0f6d65950a
commit 98d48978a8
24 changed files with 2162 additions and 821 deletions

View file

@ -217,7 +217,7 @@ class CuraApplication(QtApplication):
"CuraEngineBackend", "CuraEngineBackend",
"UserAgreement", "UserAgreement",
"SolidView", "SolidView",
"LayerView", "SimulationView",
"STLReader", "STLReader",
"SelectionTool", "SelectionTool",
"CameraTool", "CameraTool",
@ -1383,7 +1383,7 @@ class CuraApplication(QtApplication):
extension = os.path.splitext(filename)[1] extension = os.path.splitext(filename)[1]
if extension.lower() in self._non_sliceable_extensions: if extension.lower() in self._non_sliceable_extensions:
self.getController().setActiveView("LayerView") self.getController().setActiveView("SimulationView")
view = self.getController().getActiveView() view = self.getController().getActiveView()
view.resetLayerData() view.resetLayerData()
view.setLayer(9999999) view.setLayer(9999999)

View file

@ -588,7 +588,7 @@ class CuraEngineBackend(QObject, Backend):
def _onActiveViewChanged(self): def _onActiveViewChanged(self):
if Application.getInstance().getController().getActiveView(): if Application.getInstance().getController().getActiveView():
view = Application.getInstance().getController().getActiveView() view = Application.getInstance().getController().getActiveView()
if view.getPluginId() in ("LayerView", "SimulationView"): # If switching to layer view, we should process the layers if that hasn't been done yet. if view.getPluginId() == "SimulationView": # If switching to layer view, we should process the layers if that hasn't been done yet.
self._layer_view_active = True self._layer_view_active = True
# There is data and we're not slicing at the moment # There is data and we're not slicing at the moment
# if we are slicing, there is no need to re-calculate the data as it will be invalid in a moment. # if we are slicing, there is no need to re-calculate the data as it will be invalid in a moment.

View file

@ -61,7 +61,7 @@ class ProcessSlicedLayersJob(Job):
def run(self): def run(self):
start_time = time() start_time = time()
if Application.getInstance().getController().getActiveView().getPluginId() in ("LayerView", "SimulationView"): if Application.getInstance().getController().getActiveView().getPluginId() == "SimulationView":
self._progress_message.show() self._progress_message.show()
Job.yieldThread() Job.yieldThread()
if self._abort_requested: if self._abort_requested:
@ -221,7 +221,7 @@ class ProcessSlicedLayersJob(Job):
self._progress_message.setProgress(100) self._progress_message.setProgress(100)
view = Application.getInstance().getController().getActiveView() view = Application.getInstance().getController().getActiveView()
if view.getPluginId() in ("LayerView", "SimulationView"): if view.getPluginId() == "SimulationView":
view.resetLayerData() view.resetLayerData()
if self._progress_message: if self._progress_message:
@ -234,7 +234,7 @@ class ProcessSlicedLayersJob(Job):
def _onActiveViewChanged(self): def _onActiveViewChanged(self):
if self.isRunning(): if self.isRunning():
if Application.getInstance().getController().getActiveView().getPluginId() in ("LayerView", "SimulationView"): if Application.getInstance().getController().getActiveView().getPluginId() == "SimulationView":
if not self._progress_message: if not self._progress_message:
self._progress_message = Message(catalog.i18nc("@info:status", "Processing Layers"), 0, False, 0, catalog.i18nc("@info:title", "Information")) self._progress_message = Message(catalog.i18nc("@info:status", "Processing Layers"), 0, False, 0, catalog.i18nc("@info:title", "Information"))
if self._progress_message.getProgress() != 100: if self._progress_message.getProgress() != 100:

View file

@ -1,113 +0,0 @@
# Copyright (c) 2016 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
from UM.Resources import Resources
from UM.Scene.SceneNode import SceneNode
from UM.Scene.ToolHandle import ToolHandle
from UM.Application import Application
from UM.PluginRegistry import PluginRegistry
from UM.View.RenderPass import RenderPass
from UM.View.RenderBatch import RenderBatch
from UM.View.GL.OpenGL import OpenGL
from cura.Settings.ExtruderManager import ExtruderManager
import os.path
## RenderPass used to display g-code paths.
class LayerPass(RenderPass):
def __init__(self, width, height):
super().__init__("layerview", width, height)
self._layer_shader = None
self._tool_handle_shader = None
self._gl = OpenGL.getInstance().getBindingsObject()
self._scene = Application.getInstance().getController().getScene()
self._extruder_manager = ExtruderManager.getInstance()
self._layer_view = None
self._compatibility_mode = None
def setLayerView(self, layerview):
self._layer_view = layerview
self._compatibility_mode = layerview.getCompatibilityMode()
def render(self):
if not self._layer_shader:
if self._compatibility_mode:
shader_filename = "layers.shader"
else:
shader_filename = "layers3d.shader"
self._layer_shader = OpenGL.getInstance().createShaderProgram(os.path.join(PluginRegistry.getInstance().getPluginPath("LayerView"), shader_filename))
# Use extruder 0 if the extruder manager reports extruder index -1 (for single extrusion printers)
self._layer_shader.setUniformValue("u_active_extruder", float(max(0, self._extruder_manager.activeExtruderIndex)))
if self._layer_view:
self._layer_shader.setUniformValue("u_layer_view_type", self._layer_view.getLayerViewType())
self._layer_shader.setUniformValue("u_extruder_opacity", self._layer_view.getExtruderOpacities())
self._layer_shader.setUniformValue("u_show_travel_moves", self._layer_view.getShowTravelMoves())
self._layer_shader.setUniformValue("u_show_helpers", self._layer_view.getShowHelpers())
self._layer_shader.setUniformValue("u_show_skin", self._layer_view.getShowSkin())
self._layer_shader.setUniformValue("u_show_infill", self._layer_view.getShowInfill())
else:
#defaults
self._layer_shader.setUniformValue("u_layer_view_type", 1)
self._layer_shader.setUniformValue("u_extruder_opacity", [1, 1, 1, 1])
self._layer_shader.setUniformValue("u_show_travel_moves", 0)
self._layer_shader.setUniformValue("u_show_helpers", 1)
self._layer_shader.setUniformValue("u_show_skin", 1)
self._layer_shader.setUniformValue("u_show_infill", 1)
if not self._tool_handle_shader:
self._tool_handle_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "toolhandle.shader"))
self.bind()
tool_handle_batch = RenderBatch(self._tool_handle_shader, type = RenderBatch.RenderType.Overlay)
for node in DepthFirstIterator(self._scene.getRoot()):
if isinstance(node, ToolHandle):
tool_handle_batch.addItem(node.getWorldTransformation(), mesh = node.getSolidMesh())
elif isinstance(node, SceneNode) and (node.getMeshData() or node.callDecoration("isBlockSlicing")) and node.isVisible():
layer_data = node.callDecoration("getLayerData")
if not layer_data:
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())):
start = 0
end = 0
element_counts = layer_data.getElementCounts()
for layer in sorted(element_counts.keys()):
if layer > self._layer_view._current_layer_num:
break
if self._layer_view._minimum_layer_num > layer:
start += element_counts[layer]
end += element_counts[layer]
# This uses glDrawRangeElements internally to only draw a certain range of lines.
batch = RenderBatch(self._layer_shader, type = RenderBatch.RenderType.Solid, mode = RenderBatch.RenderMode.Lines, range = (start, end))
batch.addItem(node.getWorldTransformation(), layer_data)
batch.render(self._scene.getActiveCamera())
# Create a new batch that is not range-limited
batch = RenderBatch(self._layer_shader, type = RenderBatch.RenderType.Solid)
if self._layer_view.getCurrentLayerMesh():
batch.addItem(node.getWorldTransformation(), self._layer_view.getCurrentLayerMesh())
if self._layer_view.getCurrentLayerJumps():
batch.addItem(node.getWorldTransformation(), self._layer_view.getCurrentLayerJumps())
if len(batch.items) > 0:
batch.render(self._scene.getActiveCamera())
# Render toolhandles on top of the layerview
if len(tool_handle_batch.items) > 0:
tool_handle_batch.render(self._scene.getActiveCamera())
self.release()

View file

@ -1,154 +0,0 @@
from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty
from UM.FlameProfiler import pyqtSlot
from UM.Application import Application
import LayerView
class LayerViewProxy(QObject):
def __init__(self, parent=None):
super().__init__(parent)
self._current_layer = 0
self._controller = Application.getInstance().getController()
self._controller.activeViewChanged.connect(self._onActiveViewChanged)
self._onActiveViewChanged()
currentLayerChanged = pyqtSignal()
maxLayersChanged = pyqtSignal()
activityChanged = pyqtSignal()
globalStackChanged = pyqtSignal()
preferencesChanged = pyqtSignal()
busyChanged = pyqtSignal()
@pyqtProperty(bool, notify=activityChanged)
def layerActivity(self):
active_view = self._controller.getActiveView()
if isinstance(active_view, LayerView.LayerView.LayerView):
return active_view.getActivity()
return False
@pyqtProperty(int, notify=maxLayersChanged)
def numLayers(self):
active_view = self._controller.getActiveView()
if isinstance(active_view, LayerView.LayerView.LayerView):
return active_view.getMaxLayers()
return 0
@pyqtProperty(int, notify=currentLayerChanged)
def currentLayer(self):
active_view = self._controller.getActiveView()
if isinstance(active_view, LayerView.LayerView.LayerView):
return active_view.getCurrentLayer()
return 0
@pyqtProperty(int, notify=currentLayerChanged)
def minimumLayer(self):
active_view = self._controller.getActiveView()
if isinstance(active_view, LayerView.LayerView.LayerView):
return active_view.getMinimumLayer()
return 0
@pyqtProperty(bool, notify=busyChanged)
def busy(self):
active_view = self._controller.getActiveView()
if isinstance(active_view, LayerView.LayerView.LayerView):
return active_view.isBusy()
return False
@pyqtProperty(bool, notify=preferencesChanged)
def compatibilityMode(self):
active_view = self._controller.getActiveView()
if isinstance(active_view, LayerView.LayerView.LayerView):
return active_view.getCompatibilityMode()
return False
@pyqtSlot(int)
def setCurrentLayer(self, layer_num):
active_view = self._controller.getActiveView()
if isinstance(active_view, LayerView.LayerView.LayerView):
active_view.setLayer(layer_num)
@pyqtSlot(int)
def setMinimumLayer(self, layer_num):
active_view = self._controller.getActiveView()
if isinstance(active_view, LayerView.LayerView.LayerView):
active_view.setMinimumLayer(layer_num)
@pyqtSlot(int)
def setLayerViewType(self, layer_view_type):
active_view = self._controller.getActiveView()
if isinstance(active_view, LayerView.LayerView.LayerView):
active_view.setLayerViewType(layer_view_type)
@pyqtSlot(result=int)
def getLayerViewType(self):
active_view = self._controller.getActiveView()
if isinstance(active_view, LayerView.LayerView.LayerView):
return active_view.getLayerViewType()
return 0
# Opacity 0..1
@pyqtSlot(int, float)
def setExtruderOpacity(self, extruder_nr, opacity):
active_view = self._controller.getActiveView()
if isinstance(active_view, LayerView.LayerView.LayerView):
active_view.setExtruderOpacity(extruder_nr, opacity)
@pyqtSlot(int)
def setShowTravelMoves(self, show):
active_view = self._controller.getActiveView()
if isinstance(active_view, LayerView.LayerView.LayerView):
active_view.setShowTravelMoves(show)
@pyqtSlot(int)
def setShowHelpers(self, show):
active_view = self._controller.getActiveView()
if isinstance(active_view, LayerView.LayerView.LayerView):
active_view.setShowHelpers(show)
@pyqtSlot(int)
def setShowSkin(self, show):
active_view = self._controller.getActiveView()
if isinstance(active_view, LayerView.LayerView.LayerView):
active_view.setShowSkin(show)
@pyqtSlot(int)
def setShowInfill(self, show):
active_view = self._controller.getActiveView()
if isinstance(active_view, LayerView.LayerView.LayerView):
active_view.setShowInfill(show)
@pyqtProperty(int, notify=globalStackChanged)
def extruderCount(self):
active_view = self._controller.getActiveView()
if isinstance(active_view, LayerView.LayerView.LayerView):
return active_view.getExtruderCount()
return 0
def _layerActivityChanged(self):
self.activityChanged.emit()
def _onLayerChanged(self):
self.currentLayerChanged.emit()
self._layerActivityChanged()
def _onMaxLayersChanged(self):
self.maxLayersChanged.emit()
def _onBusyChanged(self):
self.busyChanged.emit()
def _onGlobalStackChanged(self):
self.globalStackChanged.emit()
def _onPreferencesChanged(self):
self.preferencesChanged.emit()
def _onActiveViewChanged(self):
active_view = self._controller.getActiveView()
if isinstance(active_view, LayerView.LayerView.LayerView):
active_view.currentLayerNumChanged.connect(self._onLayerChanged)
active_view.maxLayersChanged.connect(self._onMaxLayersChanged)
active_view.busyChanged.connect(self._onBusyChanged)
active_view.globalStackChanged.connect(self._onGlobalStackChanged)
active_view.preferencesChanged.connect(self._onPreferencesChanged)

View file

@ -1,25 +0,0 @@
# Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from . import LayerView, LayerViewProxy
from PyQt5.QtQml import qmlRegisterType, qmlRegisterSingletonType
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
def getMetaData():
return {
"view": {
"name": catalog.i18nc("@item:inlistbox", "Layer view"),
"view_panel": "LayerView.qml",
"weight": 2
}
}
def createLayerViewProxy(engine, script_engine):
return LayerViewProxy.LayerViewProxy()
def register(app):
layer_view = LayerView.LayerView()
qmlRegisterSingletonType(LayerViewProxy.LayerViewProxy, "UM", 1, 0, "LayerView", layer_view.getProxy)
return { "view": LayerView.LayerView() }

View file

@ -1,312 +1,325 @@
// Copyright (c) 2017 Ultimaker B.V. // Copyright (c) 2017 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2 import QtQuick 2.2
import QtQuick.Controls 1.2 import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.1 import QtQuick.Controls.Styles 1.1
import UM 1.0 as UM import UM 1.0 as UM
import Cura 1.0 as Cura import Cura 1.0 as Cura
Item { Item {
id: sliderRoot id: sliderRoot
// handle properties // handle properties
property real handleSize: 10 property real handleSize: 10
property real handleRadius: handleSize / 2 property real handleRadius: handleSize / 2
property real minimumRangeHandleSize: handleSize / 2 property real minimumRangeHandleSize: handleSize / 2
property color upperHandleColor: "black" property color upperHandleColor: "black"
property color lowerHandleColor: "black" property color lowerHandleColor: "black"
property color rangeHandleColor: "black" property color rangeHandleColor: "black"
property real handleLabelWidth: width property color handleActiveColor: "white"
property var activeHandle: upperHandle property real handleLabelWidth: width
property var activeHandle: upperHandle
// track properties
property real trackThickness: 4 // width of the slider track // track properties
property real trackRadius: trackThickness / 2 property real trackThickness: 4 // width of the slider track
property color trackColor: "white" property real trackRadius: trackThickness / 2
property real trackBorderWidth: 1 // width of the slider track border property color trackColor: "white"
property color trackBorderColor: "black" property real trackBorderWidth: 1 // width of the slider track border
property color trackBorderColor: "black"
// value properties
property real maximumValue: 100 // value properties
property real minimumValue: 0 property real maximumValue: 100
property real minimumRange: 0 // minimum range allowed between min and max values property real minimumValue: 0
property bool roundValues: true property real minimumRange: 0 // minimum range allowed between min and max values
property real upperValue: maximumValue property bool roundValues: true
property real lowerValue: minimumValue property real upperValue: maximumValue
property real lowerValue: minimumValue
property bool layersVisible: true
property bool layersVisible: true
function getUpperValueFromSliderHandle () {
return upperHandle.getValue() function getUpperValueFromSliderHandle () {
} return upperHandle.getValue()
}
function setUpperValue (value) {
upperHandle.setValue(value) function setUpperValue (value) {
updateRangeHandle() upperHandle.setValue(value)
} updateRangeHandle()
}
function getLowerValueFromSliderHandle () {
return lowerHandle.getValue() function getLowerValueFromSliderHandle () {
} return lowerHandle.getValue()
}
function setLowerValue (value) {
lowerHandle.setValue(value) function setLowerValue (value) {
updateRangeHandle() lowerHandle.setValue(value)
} updateRangeHandle()
}
function updateRangeHandle () {
rangeHandle.height = lowerHandle.y - (upperHandle.y + upperHandle.height) function updateRangeHandle () {
} rangeHandle.height = lowerHandle.y - (upperHandle.y + upperHandle.height)
}
// set the active handle to show only one label at a time
function setActiveHandle (handle) { // set the active handle to show only one label at a time
activeHandle = handle function setActiveHandle (handle) {
} activeHandle = handle
}
// slider track
Rectangle { // slider track
id: track Rectangle {
id: track
width: sliderRoot.trackThickness
height: sliderRoot.height - sliderRoot.handleSize width: sliderRoot.trackThickness
radius: sliderRoot.trackRadius height: sliderRoot.height - sliderRoot.handleSize
anchors.centerIn: sliderRoot radius: sliderRoot.trackRadius
color: sliderRoot.trackColor anchors.centerIn: sliderRoot
border.width: sliderRoot.trackBorderWidth color: sliderRoot.trackColor
border.color: sliderRoot.trackBorderColor border.width: sliderRoot.trackBorderWidth
visible: sliderRoot.layersVisible border.color: sliderRoot.trackBorderColor
} visible: sliderRoot.layersVisible
}
// Range handle
Item { // Range handle
id: rangeHandle Item {
id: rangeHandle
y: upperHandle.y + upperHandle.height
width: sliderRoot.handleSize y: upperHandle.y + upperHandle.height
height: sliderRoot.minimumRangeHandleSize width: sliderRoot.handleSize
anchors.horizontalCenter: sliderRoot.horizontalCenter height: sliderRoot.minimumRangeHandleSize
visible: sliderRoot.layersVisible anchors.horizontalCenter: sliderRoot.horizontalCenter
visible: sliderRoot.layersVisible
// set the new value when dragging
function onHandleDragged () { // set the new value when dragging
function onHandleDragged () {
upperHandle.y = y - upperHandle.height
lowerHandle.y = y + height upperHandle.y = y - upperHandle.height
lowerHandle.y = y + height
var upperValue = sliderRoot.getUpperValueFromSliderHandle()
var lowerValue = sliderRoot.getLowerValueFromSliderHandle() var upperValue = sliderRoot.getUpperValueFromSliderHandle()
var lowerValue = sliderRoot.getLowerValueFromSliderHandle()
// set both values after moving the handle position
UM.LayerView.setCurrentLayer(upperValue) // set both values after moving the handle position
UM.LayerView.setMinimumLayer(lowerValue) UM.SimulationView.setCurrentLayer(upperValue)
} UM.SimulationView.setMinimumLayer(lowerValue)
}
function setValue (value) {
var range = sliderRoot.upperValue - sliderRoot.lowerValue function setValue (value) {
value = Math.min(value, sliderRoot.maximumValue) var range = sliderRoot.upperValue - sliderRoot.lowerValue
value = Math.max(value, sliderRoot.minimumValue + range) value = Math.min(value, sliderRoot.maximumValue)
value = Math.max(value, sliderRoot.minimumValue + range)
UM.LayerView.setCurrentLayer(value)
UM.LayerView.setMinimumLayer(value - range) UM.SimulationView.setCurrentLayer(value)
} UM.SimulationView.setMinimumLayer(value - range)
}
Rectangle {
width: sliderRoot.trackThickness - 2 * sliderRoot.trackBorderWidth Rectangle {
height: parent.height + sliderRoot.handleSize width: sliderRoot.trackThickness - 2 * sliderRoot.trackBorderWidth
anchors.centerIn: parent height: parent.height + sliderRoot.handleSize
color: sliderRoot.rangeHandleColor anchors.centerIn: parent
} color: sliderRoot.rangeHandleColor
}
MouseArea {
anchors.fill: parent MouseArea {
anchors.fill: parent
drag {
target: parent drag {
axis: Drag.YAxis target: parent
minimumY: upperHandle.height axis: Drag.YAxis
maximumY: sliderRoot.height - (rangeHandle.height + lowerHandle.height) minimumY: upperHandle.height
} maximumY: sliderRoot.height - (rangeHandle.height + lowerHandle.height)
}
onPositionChanged: parent.onHandleDragged()
onPressed: sliderRoot.setActiveHandle(rangeHandle) onPositionChanged: parent.onHandleDragged()
} onPressed: sliderRoot.setActiveHandle(rangeHandle)
}
LayerSliderLabel {
id: rangleHandleLabel SimulationSliderLabel {
id: rangleHandleLabel
height: sliderRoot.handleSize + UM.Theme.getSize("default_margin").height
x: parent.x - width - UM.Theme.getSize("default_margin").width height: sliderRoot.handleSize + UM.Theme.getSize("default_margin").height
anchors.verticalCenter: parent.verticalCenter x: parent.x - width - UM.Theme.getSize("default_margin").width
target: Qt.point(sliderRoot.width, y + height / 2) anchors.verticalCenter: parent.verticalCenter
visible: sliderRoot.activeHandle == parent target: Qt.point(sliderRoot.width, y + height / 2)
visible: sliderRoot.activeHandle == parent
// custom properties
maximumValue: sliderRoot.maximumValue // custom properties
value: sliderRoot.upperValue maximumValue: sliderRoot.maximumValue
busy: UM.LayerView.busy value: sliderRoot.upperValue
setValue: rangeHandle.setValue // connect callback functions busy: UM.SimulationView.busy
} setValue: rangeHandle.setValue // connect callback functions
} }
}
// Upper handle
Rectangle { // Upper handle
id: upperHandle Rectangle {
id: upperHandle
y: sliderRoot.height - (sliderRoot.minimumRangeHandleSize + 2 * sliderRoot.handleSize)
width: sliderRoot.handleSize y: sliderRoot.height - (sliderRoot.minimumRangeHandleSize + 2 * sliderRoot.handleSize)
height: sliderRoot.handleSize width: sliderRoot.handleSize
anchors.horizontalCenter: sliderRoot.horizontalCenter height: sliderRoot.handleSize
radius: sliderRoot.handleRadius anchors.horizontalCenter: sliderRoot.horizontalCenter
color: sliderRoot.upperHandleColor radius: sliderRoot.handleRadius
visible: sliderRoot.layersVisible color: upperHandleLabel.activeFocus ? sliderRoot.handleActiveColor : sliderRoot.upperHandleColor
visible: sliderRoot.layersVisible
function onHandleDragged () {
function onHandleDragged () {
// don't allow the lower handle to be heigher than the upper handle
if (lowerHandle.y - (y + height) < sliderRoot.minimumRangeHandleSize) { // don't allow the lower handle to be heigher than the upper handle
lowerHandle.y = y + height + sliderRoot.minimumRangeHandleSize if (lowerHandle.y - (y + height) < sliderRoot.minimumRangeHandleSize) {
} lowerHandle.y = y + height + sliderRoot.minimumRangeHandleSize
}
// update the range handle
sliderRoot.updateRangeHandle() // update the range handle
sliderRoot.updateRangeHandle()
// set the new value after moving the handle position
UM.LayerView.setCurrentLayer(getValue()) // set the new value after moving the handle position
} UM.SimulationView.setCurrentLayer(getValue())
}
// get the upper value based on the slider position
function getValue () { // get the upper value based on the slider position
var result = y / (sliderRoot.height - (2 * sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize)) function getValue () {
result = sliderRoot.maximumValue + result * (sliderRoot.minimumValue - (sliderRoot.maximumValue - sliderRoot.minimumValue)) var result = y / (sliderRoot.height - (2 * sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize))
result = sliderRoot.roundValues ? Math.round(result) : result result = sliderRoot.maximumValue + result * (sliderRoot.minimumValue - (sliderRoot.maximumValue - sliderRoot.minimumValue))
return result result = sliderRoot.roundValues ? Math.round(result) : result
} return result
}
// set the slider position based on the upper value
function setValue (value) { // set the slider position based on the upper value
function setValue (value) {
UM.LayerView.setCurrentLayer(value)
UM.SimulationView.setCurrentLayer(value)
var diff = (value - sliderRoot.maximumValue) / (sliderRoot.minimumValue - sliderRoot.maximumValue)
var newUpperYPosition = Math.round(diff * (sliderRoot.height - (2 * sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize))) var diff = (value - sliderRoot.maximumValue) / (sliderRoot.minimumValue - sliderRoot.maximumValue)
y = newUpperYPosition var newUpperYPosition = Math.round(diff * (sliderRoot.height - (2 * sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize)))
y = newUpperYPosition
// update the range handle
sliderRoot.updateRangeHandle() // update the range handle
} sliderRoot.updateRangeHandle()
}
// dragging
MouseArea { Keys.onUpPressed: upperHandleLabel.setValue(upperHandleLabel.value + ((event.modifiers & Qt.ShiftModifier) ? 10 : 1))
anchors.fill: parent Keys.onDownPressed: upperHandleLabel.setValue(upperHandleLabel.value - ((event.modifiers & Qt.ShiftModifier) ? 10 : 1))
drag { // dragging
target: parent MouseArea {
axis: Drag.YAxis anchors.fill: parent
minimumY: 0
maximumY: sliderRoot.height - (2 * sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize) drag {
} target: parent
axis: Drag.YAxis
onPositionChanged: parent.onHandleDragged() minimumY: 0
onPressed: sliderRoot.setActiveHandle(upperHandle) maximumY: sliderRoot.height - (2 * sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize)
} }
LayerSliderLabel { onPositionChanged: parent.onHandleDragged()
id: upperHandleLabel onPressed: {
sliderRoot.setActiveHandle(upperHandle)
height: sliderRoot.handleSize + UM.Theme.getSize("default_margin").height upperHandleLabel.forceActiveFocus()
x: parent.x - width - UM.Theme.getSize("default_margin").width }
anchors.verticalCenter: parent.verticalCenter }
target: Qt.point(sliderRoot.width, y + height / 2)
visible: sliderRoot.activeHandle == parent SimulationSliderLabel {
id: upperHandleLabel
// custom properties
maximumValue: sliderRoot.maximumValue height: sliderRoot.handleSize + UM.Theme.getSize("default_margin").height
value: sliderRoot.upperValue x: parent.x - width - UM.Theme.getSize("default_margin").width
busy: UM.LayerView.busy anchors.verticalCenter: parent.verticalCenter
setValue: upperHandle.setValue // connect callback functions target: Qt.point(sliderRoot.width, y + height / 2)
} visible: sliderRoot.activeHandle == parent
}
// custom properties
// Lower handle maximumValue: sliderRoot.maximumValue
Rectangle { value: sliderRoot.upperValue
id: lowerHandle busy: UM.SimulationView.busy
setValue: upperHandle.setValue // connect callback functions
y: sliderRoot.height - sliderRoot.handleSize }
width: parent.handleSize }
height: parent.handleSize
anchors.horizontalCenter: parent.horizontalCenter // Lower handle
radius: sliderRoot.handleRadius Rectangle {
color: sliderRoot.lowerHandleColor id: lowerHandle
visible: slider.layersVisible y: sliderRoot.height - sliderRoot.handleSize
width: parent.handleSize
function onHandleDragged () { height: parent.handleSize
anchors.horizontalCenter: parent.horizontalCenter
// don't allow the upper handle to be lower than the lower handle radius: sliderRoot.handleRadius
if (y - (upperHandle.y + upperHandle.height) < sliderRoot.minimumRangeHandleSize) { color: lowerHandleLabel.activeFocus ? sliderRoot.handleActiveColor : sliderRoot.lowerHandleColor
upperHandle.y = y - (upperHandle.heigth + sliderRoot.minimumRangeHandleSize)
} visible: sliderRoot.layersVisible
// update the range handle function onHandleDragged () {
sliderRoot.updateRangeHandle()
// don't allow the upper handle to be lower than the lower handle
// set the new value after moving the handle position if (y - (upperHandle.y + upperHandle.height) < sliderRoot.minimumRangeHandleSize) {
UM.LayerView.setMinimumLayer(getValue()) upperHandle.y = y - (upperHandle.heigth + sliderRoot.minimumRangeHandleSize)
} }
// get the lower value from the current slider position // update the range handle
function getValue () { sliderRoot.updateRangeHandle()
var result = (y - (sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize)) / (sliderRoot.height - (2 * sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize));
result = sliderRoot.maximumValue - sliderRoot.minimumRange + result * (sliderRoot.minimumValue - (sliderRoot.maximumValue - sliderRoot.minimumRange)) // set the new value after moving the handle position
result = sliderRoot.roundValues ? Math.round(result) : result UM.SimulationView.setMinimumLayer(getValue())
return result }
}
// get the lower value from the current slider position
// set the slider position based on the lower value function getValue () {
function setValue (value) { var result = (y - (sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize)) / (sliderRoot.height - (2 * sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize));
result = sliderRoot.maximumValue - sliderRoot.minimumRange + result * (sliderRoot.minimumValue - (sliderRoot.maximumValue - sliderRoot.minimumRange))
UM.LayerView.setMinimumLayer(value) result = sliderRoot.roundValues ? Math.round(result) : result
return result
var diff = (value - sliderRoot.maximumValue) / (sliderRoot.minimumValue - sliderRoot.maximumValue) }
var newLowerYPosition = Math.round((sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize) + diff * (sliderRoot.height - (2 * sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize)))
y = newLowerYPosition // set the slider position based on the lower value
function setValue (value) {
// update the range handle
sliderRoot.updateRangeHandle() UM.SimulationView.setMinimumLayer(value)
}
var diff = (value - sliderRoot.maximumValue) / (sliderRoot.minimumValue - sliderRoot.maximumValue)
// dragging var newLowerYPosition = Math.round((sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize) + diff * (sliderRoot.height - (2 * sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize)))
MouseArea { y = newLowerYPosition
anchors.fill: parent
// update the range handle
drag { sliderRoot.updateRangeHandle()
target: parent }
axis: Drag.YAxis
minimumY: upperHandle.height + sliderRoot.minimumRangeHandleSize Keys.onUpPressed: lowerHandleLabel.setValue(lowerHandleLabel.value + ((event.modifiers & Qt.ShiftModifier) ? 10 : 1))
maximumY: sliderRoot.height - parent.height Keys.onDownPressed: lowerHandleLabel.setValue(lowerHandleLabel.value - ((event.modifiers & Qt.ShiftModifier) ? 10 : 1))
}
// dragging
onPositionChanged: parent.onHandleDragged() MouseArea {
onPressed: sliderRoot.setActiveHandle(lowerHandle) anchors.fill: parent
}
drag {
LayerSliderLabel { target: parent
id: lowerHandleLabel axis: Drag.YAxis
minimumY: upperHandle.height + sliderRoot.minimumRangeHandleSize
height: sliderRoot.handleSize + UM.Theme.getSize("default_margin").height maximumY: sliderRoot.height - parent.height
x: parent.x - width - UM.Theme.getSize("default_margin").width }
anchors.verticalCenter: parent.verticalCenter
target: Qt.point(sliderRoot.width, y + height / 2) onPositionChanged: parent.onHandleDragged()
visible: sliderRoot.activeHandle == parent onPressed: {
sliderRoot.setActiveHandle(lowerHandle)
// custom properties lowerHandleLabel.forceActiveFocus()
maximumValue: sliderRoot.maximumValue }
value: sliderRoot.lowerValue }
busy: UM.LayerView.busy
setValue: lowerHandle.setValue // connect callback functions SimulationSliderLabel {
} id: lowerHandleLabel
}
} height: sliderRoot.handleSize + UM.Theme.getSize("default_margin").height
x: parent.x - width - UM.Theme.getSize("default_margin").width
anchors.verticalCenter: parent.verticalCenter
target: Qt.point(sliderRoot.width, y + height / 2)
visible: sliderRoot.activeHandle == parent
// custom properties
maximumValue: sliderRoot.maximumValue
value: sliderRoot.lowerValue
busy: UM.SimulationView.busy
setValue: lowerHandle.setValue // connect callback functions
}
}
}

View file

@ -0,0 +1,49 @@
# Copyright (c) 2017 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from UM.Application import Application
from UM.Math.Color import Color
from UM.Math.Vector import Vector
from UM.PluginRegistry import PluginRegistry
from UM.Scene.SceneNode import SceneNode
from UM.View.GL.OpenGL import OpenGL
from UM.Resources import Resources
import os
class NozzleNode(SceneNode):
def __init__(self, parent = None):
super().__init__(parent)
self._shader = None
self.setCalculateBoundingBox(False)
self._createNozzleMesh()
def _createNozzleMesh(self):
mesh_file = "resources/nozzle.stl"
try:
path = os.path.join(PluginRegistry.getInstance().getPluginPath("SimulationView"), mesh_file)
except FileNotFoundError:
path = ""
reader = Application.getInstance().getMeshFileHandler().getReaderForFile(path)
node = reader.read(path)
if node.getMeshData():
self.setMeshData(node.getMeshData())
def render(self, renderer):
# Avoid to render if it is not visible
if not self.isVisible():
return False
if not self._shader:
# We now misuse the platform shader, as it actually supports textures
self._shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "color.shader"))
self._shader.setUniformValue("u_color", Color(*Application.getInstance().getTheme().getColor("layerview_nozzle").getRgb()))
# Set the opacity to 0, so that the template is in full control.
self._shader.setUniformValue("u_opacity", 0)
if self.getMeshData():
renderer.queueNode(self, shader = self._shader, transparent = True)
return True

View file

@ -0,0 +1,161 @@
// Copyright (c) 2017 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.1
import UM 1.0 as UM
import Cura 1.0 as Cura
Item {
id: sliderRoot
// handle properties
property real handleSize: 10
property real handleRadius: handleSize / 2
property color handleColor: "black"
property color handleActiveColor: "white"
property color rangeColor: "black"
property real handleLabelWidth: width
// track properties
property real trackThickness: 4 // width of the slider track
property real trackRadius: trackThickness / 2
property color trackColor: "white"
property real trackBorderWidth: 1 // width of the slider track border
property color trackBorderColor: "black"
// value properties
property real maximumValue: 100
property bool roundValues: true
property real handleValue: maximumValue
property bool pathsVisible: true
function getHandleValueFromSliderHandle () {
return handle.getValue()
}
function setHandleValue (value) {
handle.setValue(value)
updateRangeHandle()
}
function updateRangeHandle () {
rangeHandle.width = handle.x - sliderRoot.handleSize
}
// slider track
Rectangle {
id: track
width: sliderRoot.width - sliderRoot.handleSize
height: sliderRoot.trackThickness
radius: sliderRoot.trackRadius
anchors.centerIn: sliderRoot
color: sliderRoot.trackColor
border.width: sliderRoot.trackBorderWidth
border.color: sliderRoot.trackBorderColor
visible: sliderRoot.pathsVisible
}
// Progress indicator
Item {
id: rangeHandle
x: handle.width
height: sliderRoot.handleSize
width: handle.x - sliderRoot.handleSize
anchors.verticalCenter: sliderRoot.verticalCenter
visible: sliderRoot.pathsVisible
Rectangle {
height: sliderRoot.trackThickness - 2 * sliderRoot.trackBorderWidth
width: parent.width + sliderRoot.handleSize
anchors.centerIn: parent
color: sliderRoot.rangeColor
}
}
// Handle
Rectangle {
id: handle
x: sliderRoot.handleSize
width: sliderRoot.handleSize
height: sliderRoot.handleSize
anchors.verticalCenter: sliderRoot.verticalCenter
radius: sliderRoot.handleRadius
color: handleLabel.activeFocus ? sliderRoot.handleActiveColor : sliderRoot.handleColor
visible: sliderRoot.pathsVisible
function onHandleDragged () {
// update the range handle
sliderRoot.updateRangeHandle()
// set the new value after moving the handle position
UM.SimulationView.setCurrentPath(getValue())
}
// get the value based on the slider position
function getValue () {
var result = x / (sliderRoot.width - sliderRoot.handleSize)
result = result * sliderRoot.maximumValue
result = sliderRoot.roundValues ? Math.round(result) : result
return result
}
// set the slider position based on the value
function setValue (value) {
UM.SimulationView.setCurrentPath(value)
var diff = value / sliderRoot.maximumValue
var newXPosition = Math.round(diff * (sliderRoot.width - sliderRoot.handleSize))
x = newXPosition
// update the range handle
sliderRoot.updateRangeHandle()
}
Keys.onRightPressed: handleLabel.setValue(handleLabel.value + ((event.modifiers & Qt.ShiftModifier) ? 10 : 1))
Keys.onLeftPressed: handleLabel.setValue(handleLabel.value - ((event.modifiers & Qt.ShiftModifier) ? 10 : 1))
// dragging
MouseArea {
anchors.fill: parent
drag {
target: parent
axis: Drag.XAxis
minimumX: 0
maximumX: sliderRoot.width - sliderRoot.handleSize
}
onPressed: {
handleLabel.forceActiveFocus()
}
onPositionChanged: parent.onHandleDragged()
}
SimulationSliderLabel {
id: handleLabel
height: sliderRoot.handleSize + UM.Theme.getSize("default_margin").height
y: parent.y + sliderRoot.handleSize + UM.Theme.getSize("default_margin").height
anchors.horizontalCenter: parent.horizontalCenter
target: Qt.point(x + width / 2, sliderRoot.height)
visible: false
startFrom: 0
// custom properties
maximumValue: sliderRoot.maximumValue
value: sliderRoot.handleValue
busy: UM.SimulationView.busy
setValue: handle.setValue // connect callback functions
}
}
}

View file

@ -0,0 +1,187 @@
# Copyright (c) 2017 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from UM.Math.Color import Color
from UM.Math.Vector import Vector
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
from UM.Resources import Resources
from UM.Scene.SceneNode import SceneNode
from UM.Scene.ToolHandle import ToolHandle
from UM.Application import Application
from UM.PluginRegistry import PluginRegistry
from UM.View.RenderPass import RenderPass
from UM.View.RenderBatch import RenderBatch
from UM.View.GL.OpenGL import OpenGL
from cura.Settings.ExtruderManager import ExtruderManager
import os.path
## RenderPass used to display g-code paths.
from plugins.SimulationView.NozzleNode import NozzleNode
class SimulationPass(RenderPass):
def __init__(self, width, height):
super().__init__("simulationview", width, height)
self._layer_shader = None
self._layer_shadow_shader = None
self._current_shader = None # This shader will be the shadow or the normal depending if the user wants to see the paths or the layers
self._tool_handle_shader = None
self._nozzle_shader = None
self._old_current_layer = 0
self._old_current_path = 0
self._gl = OpenGL.getInstance().getBindingsObject()
self._scene = Application.getInstance().getController().getScene()
self._extruder_manager = ExtruderManager.getInstance()
self._layer_view = None
self._compatibility_mode = None
def setSimulationView(self, layerview):
self._layer_view = layerview
self._compatibility_mode = layerview.getCompatibilityMode()
def render(self):
if not self._layer_shader:
if self._compatibility_mode:
shader_filename = "layers.shader"
shadow_shader_filename = "layers_shadow.shader"
else:
shader_filename = "layers3d.shader"
shadow_shader_filename = "layers3d_shadow.shader"
self._layer_shader = OpenGL.getInstance().createShaderProgram(os.path.join(PluginRegistry.getInstance().getPluginPath("SimulationView"), shader_filename))
self._layer_shadow_shader = OpenGL.getInstance().createShaderProgram(os.path.join(PluginRegistry.getInstance().getPluginPath("SimulationView"), shadow_shader_filename))
self._current_shader = self._layer_shader
# Use extruder 0 if the extruder manager reports extruder index -1 (for single extrusion printers)
self._layer_shader.setUniformValue("u_active_extruder", float(max(0, self._extruder_manager.activeExtruderIndex)))
if self._layer_view:
self._layer_shader.setUniformValue("u_max_feedrate", self._layer_view.getMaxFeedrate())
self._layer_shader.setUniformValue("u_min_feedrate", self._layer_view.getMinFeedrate())
self._layer_shader.setUniformValue("u_max_thickness", self._layer_view.getMaxThickness())
self._layer_shader.setUniformValue("u_min_thickness", self._layer_view.getMinThickness())
self._layer_shader.setUniformValue("u_layer_view_type", self._layer_view.getSimulationViewType())
self._layer_shader.setUniformValue("u_extruder_opacity", self._layer_view.getExtruderOpacities())
self._layer_shader.setUniformValue("u_show_travel_moves", self._layer_view.getShowTravelMoves())
self._layer_shader.setUniformValue("u_show_helpers", self._layer_view.getShowHelpers())
self._layer_shader.setUniformValue("u_show_skin", self._layer_view.getShowSkin())
self._layer_shader.setUniformValue("u_show_infill", self._layer_view.getShowInfill())
else:
#defaults
self._layer_shader.setUniformValue("u_max_feedrate", 1)
self._layer_shader.setUniformValue("u_min_feedrate", 0)
self._layer_shader.setUniformValue("u_max_thickness", 1)
self._layer_shader.setUniformValue("u_min_thickness", 0)
self._layer_shader.setUniformValue("u_layer_view_type", 1)
self._layer_shader.setUniformValue("u_extruder_opacity", [1, 1, 1, 1])
self._layer_shader.setUniformValue("u_show_travel_moves", 0)
self._layer_shader.setUniformValue("u_show_helpers", 1)
self._layer_shader.setUniformValue("u_show_skin", 1)
self._layer_shader.setUniformValue("u_show_infill", 1)
if not self._tool_handle_shader:
self._tool_handle_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "toolhandle.shader"))
if not self._nozzle_shader:
self._nozzle_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "color.shader"))
self._nozzle_shader.setUniformValue("u_color", Color(*Application.getInstance().getTheme().getColor("layerview_nozzle").getRgb()))
self.bind()
tool_handle_batch = RenderBatch(self._tool_handle_shader, type = RenderBatch.RenderType.Solid)
head_position = None # Indicates the current position of the print head
nozzle_node = None
for node in DepthFirstIterator(self._scene.getRoot()):
if isinstance(node, ToolHandle):
tool_handle_batch.addItem(node.getWorldTransformation(), mesh = node.getSolidMesh())
elif isinstance(node, NozzleNode):
nozzle_node = node
nozzle_node.setVisible(False)
elif isinstance(node, SceneNode) and (node.getMeshData() or node.callDecoration("isBlockSlicing")) and node.isVisible():
layer_data = node.callDecoration("getLayerData")
if not layer_data:
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())):
start = 0
end = 0
element_counts = layer_data.getElementCounts()
for layer in sorted(element_counts.keys()):
# 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
offset = 0
for polygon in layer_data.getLayer(layer).polygons:
# The size indicates all values in the two-dimension array, and the second dimension is
# always size 3 because we have 3D points.
if index >= polygon.data.size // 3 - offset:
index -= polygon.data.size // 3 - offset
offset = 1 # This is to avoid the first point when there is more than one polygon, since has the same value as the last point in the previous polygon
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()
break
break
if self._layer_view._minimum_layer_num > 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
# 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:
self._current_shader = self._layer_shadow_shader
if not self._layer_view.isSimulationRunning() and self._old_current_layer != self._layer_view._current_layer_num:
self._current_shader = self._layer_shader
layers_batch = RenderBatch(self._current_shader, type = RenderBatch.RenderType.Solid, mode = RenderBatch.RenderMode.Lines, range = (start, end))
layers_batch.addItem(node.getWorldTransformation(), layer_data)
layers_batch.render(self._scene.getActiveCamera())
# Current selected layer is rendered
current_layer_batch = RenderBatch(self._layer_shader, type = RenderBatch.RenderType.Solid, mode = RenderBatch.RenderMode.Lines, range = (current_layer_start, current_layer_end))
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
# Create a new batch that is not range-limited
batch = RenderBatch(self._layer_shader, type = RenderBatch.RenderType.Solid)
if self._layer_view.getCurrentLayerMesh():
batch.addItem(node.getWorldTransformation(), self._layer_view.getCurrentLayerMesh())
if self._layer_view.getCurrentLayerJumps():
batch.addItem(node.getWorldTransformation(), self._layer_view.getCurrentLayerJumps())
if len(batch.items) > 0:
batch.render(self._scene.getActiveCamera())
# The nozzle is drawn once we know the correct position
if self._layer_view.getActivity() and nozzle_node is not None:
if head_position is not None:
nozzle_node.setVisible(True)
nozzle_node.setPosition(head_position)
nozzle_batch = RenderBatch(self._nozzle_shader, type = RenderBatch.RenderType.Solid)
nozzle_batch.addItem(nozzle_node.getWorldTransformation(), mesh = nozzle_node.getMeshData())
nozzle_batch.render(self._scene.getActiveCamera())
# Render toolhandles on top of the layerview
if len(tool_handle_batch.items) > 0:
tool_handle_batch.render(self._scene.getActiveCamera())
self.release()

View file

@ -1,103 +1,104 @@
// Copyright (c) 2017 Ultimaker B.V. // Copyright (c) 2017 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2 import QtQuick 2.2
import QtQuick.Controls 1.2 import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.1 import QtQuick.Controls.Styles 1.1
import UM 1.0 as UM import UM 1.0 as UM
import Cura 1.0 as Cura import Cura 1.0 as Cura
UM.PointingRectangle { UM.PointingRectangle {
id: sliderLabelRoot id: sliderLabelRoot
// custom properties // custom properties
property real maximumValue: 100 property real maximumValue: 100
property real value: 0 property real value: 0
property var setValue // Function property var setValue // Function
property bool busy: false property bool busy: false
property int startFrom: 1
target: Qt.point(parent.width, y + height / 2)
arrowSize: UM.Theme.getSize("default_arrow").width target: Qt.point(parent.width, y + height / 2)
height: parent.height arrowSize: UM.Theme.getSize("default_arrow").width
width: valueLabel.width + UM.Theme.getSize("default_margin").width height: parent.height
visible: false width: valueLabel.width + UM.Theme.getSize("default_margin").width
visible: false
// make sure the text field is focussed when pressing the parent handle
// needed to connect the key bindings when switching active handle // make sure the text field is focussed when pressing the parent handle
onVisibleChanged: if (visible) valueLabel.forceActiveFocus() // needed to connect the key bindings when switching active handle
onVisibleChanged: if (visible) valueLabel.forceActiveFocus()
color: UM.Theme.getColor("tool_panel_background")
borderColor: UM.Theme.getColor("lining") color: UM.Theme.getColor("tool_panel_background")
borderWidth: UM.Theme.getSize("default_lining").width borderColor: UM.Theme.getColor("lining")
borderWidth: UM.Theme.getSize("default_lining").width
Behavior on height {
NumberAnimation { Behavior on height {
duration: 50 NumberAnimation {
} duration: 50
} }
}
// catch all mouse events so they're not handled by underlying 3D scene
MouseArea { // catch all mouse events so they're not handled by underlying 3D scene
anchors.fill: parent MouseArea {
} anchors.fill: parent
}
TextField {
id: valueLabel TextField {
id: valueLabel
anchors {
left: parent.left anchors {
leftMargin: Math.floor(UM.Theme.getSize("default_margin").width / 2) left: parent.left
verticalCenter: parent.verticalCenter leftMargin: Math.floor(UM.Theme.getSize("default_margin").width / 2)
} verticalCenter: parent.verticalCenter
}
width: 40 * screenScaleFactor
text: sliderLabelRoot.value + 1 // the current handle value, add 1 because layers is an array width: 40 * screenScaleFactor
horizontalAlignment: TextInput.AlignRight text: sliderLabelRoot.value + startFrom // the current handle value, add 1 because layers is an array
horizontalAlignment: TextInput.AlignRight
// key bindings, work when label is currenctly focused (active handle in LayerSlider)
Keys.onUpPressed: sliderLabelRoot.setValue(sliderLabelRoot.value + ((event.modifiers & Qt.ShiftModifier) ? 10 : 1)) // key bindings, work when label is currenctly focused (active handle in LayerSlider)
Keys.onDownPressed: sliderLabelRoot.setValue(sliderLabelRoot.value - ((event.modifiers & Qt.ShiftModifier) ? 10 : 1)) Keys.onUpPressed: sliderLabelRoot.setValue(sliderLabelRoot.value + ((event.modifiers & Qt.ShiftModifier) ? 10 : 1))
Keys.onDownPressed: sliderLabelRoot.setValue(sliderLabelRoot.value - ((event.modifiers & Qt.ShiftModifier) ? 10 : 1))
style: TextFieldStyle {
textColor: UM.Theme.getColor("setting_control_text") style: TextFieldStyle {
font: UM.Theme.getFont("default") textColor: UM.Theme.getColor("setting_control_text")
background: Item { } font: UM.Theme.getFont("default")
} background: Item { }
}
onEditingFinished: {
onEditingFinished: {
// Ensure that the cursor is at the first position. On some systems the text isn't fully visible
// Seems to have to do something with different dpi densities that QML doesn't quite handle. // Ensure that the cursor is at the first position. On some systems the text isn't fully visible
// Another option would be to increase the size even further, but that gives pretty ugly results. // Seems to have to do something with different dpi densities that QML doesn't quite handle.
cursorPosition = 0 // Another option would be to increase the size even further, but that gives pretty ugly results.
cursorPosition = 0
if (valueLabel.text != "") {
// -1 because we need to convert back to an array structure if (valueLabel.text != "") {
sliderLabelRoot.setValue(parseInt(valueLabel.text) - 1) // -startFrom because we need to convert back to an array structure
} sliderLabelRoot.setValue(parseInt(valueLabel.text) - startFrom)
} }
}
validator: IntValidator {
bottom: 1 validator: IntValidator {
top: sliderLabelRoot.maximumValue + 1 // +1 because actual layers is an array bottom:startFrom
} top: sliderLabelRoot.maximumValue + startFrom // +startFrom because maybe we want to start in a different value rather than 0
} }
}
BusyIndicator {
id: busyIndicator BusyIndicator {
id: busyIndicator
anchors {
left: parent.right anchors {
leftMargin: Math.floor(UM.Theme.getSize("default_margin").width / 2) left: parent.right
verticalCenter: parent.verticalCenter leftMargin: Math.floor(UM.Theme.getSize("default_margin").width / 2)
} verticalCenter: parent.verticalCenter
}
width: sliderLabelRoot.height
height: width width: sliderLabelRoot.height
height: width
visible: sliderLabelRoot.busy
running: sliderLabelRoot.busy visible: sliderLabelRoot.busy
} running: sliderLabelRoot.busy
} }
}

View file

@ -1,46 +1,46 @@
# Copyright (c) 2015 Ultimaker B.V. # Copyright (c) 2017 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
import sys import sys
from UM.PluginRegistry import PluginRegistry
from UM.View.View import View
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
from UM.Resources import Resources
from UM.Event import Event, KeyEvent
from UM.Signal import Signal
from UM.Scene.Selection import Selection
from UM.Math.Color import Color
from UM.Mesh.MeshBuilder import MeshBuilder
from UM.Job import Job
from UM.Preferences import Preferences
from UM.Logger import Logger
from UM.View.GL.OpenGL import OpenGL
from UM.Message import Message
from UM.Application import Application
from UM.View.GL.OpenGLContext import OpenGLContext
from cura.ConvexHullNode import ConvexHullNode
from cura.Settings.ExtruderManager import ExtruderManager
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication from PyQt5.QtWidgets import QApplication
from . import LayerViewProxy from UM.Application import Application
from UM.Event import Event, KeyEvent
from UM.Job import Job
from UM.Logger import Logger
from UM.Math.Color import Color
from UM.Math.Vector import Vector
from UM.Mesh.MeshBuilder import MeshBuilder
from UM.Message import Message
from UM.PluginRegistry import PluginRegistry
from UM.Preferences import Preferences
from UM.Resources import Resources
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
from UM.Scene.SceneNode import SceneNode
from UM.Scene.Selection import Selection
from UM.Signal import Signal
from UM.View.GL.OpenGL import OpenGL
from UM.View.GL.OpenGLContext import OpenGLContext
from UM.View.View import View
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura") from cura.ConvexHullNode import ConvexHullNode
from plugins.SimulationView.NozzleNode import NozzleNode
from . import SimulationPass, SimulationViewProxy
from . import LayerPass catalog = i18nCatalog("cura")
import numpy import numpy
import os.path import os.path
## View used to display g-code paths. ## View used to display g-code paths.
class LayerView(View): class SimulationView(View):
# Must match LayerView.qml # Must match SimulationView.qml
LAYER_VIEW_TYPE_MATERIAL_TYPE = 0 LAYER_VIEW_TYPE_MATERIAL_TYPE = 0
LAYER_VIEW_TYPE_LINE_TYPE = 1 LAYER_VIEW_TYPE_LINE_TYPE = 1
LAYER_VIEW_TYPE_FEEDRATE = 2
LAYER_VIEW_TYPE_THICKNESS = 3
def __init__(self): def __init__(self):
super().__init__() super().__init__()
@ -54,22 +54,29 @@ class LayerView(View):
self._activity = False self._activity = False
self._old_max_layers = 0 self._old_max_layers = 0
self._max_paths = 0
self._current_path_num = 0
self._minimum_path_num = 0
self.currentLayerNumChanged.connect(self._onCurrentLayerNumChanged)
self._busy = False self._busy = False
self._simulation_running = False
self._ghost_shader = None self._ghost_shader = None
self._layer_pass = None self._layer_pass = None
self._composite_pass = None self._composite_pass = None
self._old_layer_bindings = None self._old_layer_bindings = None
self._layerview_composite_shader = None self._simulationview_composite_shader = None
self._old_composite_shader = None self._old_composite_shader = None
self._global_container_stack = None self._global_container_stack = None
self._proxy = LayerViewProxy.LayerViewProxy() self._proxy = SimulationViewProxy.SimulationViewProxy()
self._controller.getScene().getRoot().childrenChanged.connect(self._onSceneChanged) self._controller.getScene().getRoot().childrenChanged.connect(self._onSceneChanged)
self._resetSettings() self._resetSettings()
self._legend_items = None self._legend_items = None
self._show_travel_moves = False self._show_travel_moves = False
self._nozzle_node = None
Preferences.getInstance().addPreference("view/top_layer_count", 5) Preferences.getInstance().addPreference("view/top_layer_count", 5)
Preferences.getInstance().addPreference("view/only_show_top_layers", False) Preferences.getInstance().addPreference("view/only_show_top_layers", False)
@ -91,7 +98,7 @@ class LayerView(View):
self._compatibility_mode = True # for safety self._compatibility_mode = True # for safety
self._wireprint_warning_message = Message(catalog.i18nc("@info:status", "Cura does not accurately display layers when Wire Printing is enabled"), self._wireprint_warning_message = Message(catalog.i18nc("@info:status", "Cura does not accurately display layers when Wire Printing is enabled"),
title = catalog.i18nc("@info:title", "Layer View")) title = catalog.i18nc("@info:title", "Simulation View"))
def _resetSettings(self): def _resetSettings(self):
self._layer_view_type = 0 # 0 is material color, 1 is color by linetype, 2 is speed self._layer_view_type = 0 # 0 is material color, 1 is color by linetype, 2 is speed
@ -101,17 +108,24 @@ class LayerView(View):
self._show_helpers = 1 self._show_helpers = 1
self._show_skin = 1 self._show_skin = 1
self._show_infill = 1 self._show_infill = 1
self.resetLayerData()
def getActivity(self): def getActivity(self):
return self._activity return self._activity
def getLayerPass(self): def setActivity(self, activity):
if self._activity == activity:
return
self._activity = activity
self.activityChanged.emit()
def getSimulationPass(self):
if not self._layer_pass: if not self._layer_pass:
# Currently the RenderPass constructor requires a size > 0 # Currently the RenderPass constructor requires a size > 0
# This should be fixed in RenderPass's constructor. # This should be fixed in RenderPass's constructor.
self._layer_pass = LayerPass.LayerPass(1, 1) self._layer_pass = SimulationPass.SimulationPass(1, 1)
self._compatibility_mode = OpenGLContext.isLegacyOpenGL() or bool(Preferences.getInstance().getValue("view/force_layer_view_compatibility_mode")) self._compatibility_mode = OpenGLContext.isLegacyOpenGL() or bool(Preferences.getInstance().getValue("view/force_layer_view_compatibility_mode"))
self._layer_pass.setLayerView(self) self._layer_pass.setSimulationView(self)
return self._layer_pass return self._layer_pass
def getCurrentLayer(self): def getCurrentLayer(self):
@ -120,13 +134,26 @@ class LayerView(View):
def getMinimumLayer(self): def getMinimumLayer(self):
return self._minimum_layer_num return self._minimum_layer_num
def _onSceneChanged(self, node):
self.calculateMaxLayers()
def getMaxLayers(self): def getMaxLayers(self):
return self._max_layers return self._max_layers
busyChanged = Signal() def getCurrentPath(self):
return self._current_path_num
def getMinimumPath(self):
return self._minimum_path_num
def getMaxPaths(self):
return self._max_paths
def getNozzleNode(self):
if not self._nozzle_node:
self._nozzle_node = NozzleNode()
return self._nozzle_node
def _onSceneChanged(self, node):
self.setActivity(False)
self.calculateMaxLayers()
def isBusy(self): def isBusy(self):
return self._busy return self._busy
@ -136,9 +163,19 @@ class LayerView(View):
self._busy = busy self._busy = busy
self.busyChanged.emit() self.busyChanged.emit()
def isSimulationRunning(self):
return self._simulation_running
def setSimulationRunning(self, running):
self._simulation_running = running
def resetLayerData(self): def resetLayerData(self):
self._current_layer_mesh = None self._current_layer_mesh = None
self._current_layer_jumps = 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
def beginRendering(self): def beginRendering(self):
scene = self.getController().getScene() scene = self.getController().getScene()
@ -186,15 +223,43 @@ class LayerView(View):
self.currentLayerNumChanged.emit() self.currentLayerNumChanged.emit()
def setPath(self, value):
if self._current_path_num != value:
self._current_path_num = value
if self._current_path_num < 0:
self._current_path_num = 0
if self._current_path_num > self._max_paths:
self._current_path_num = self._max_paths
if self._current_path_num < self._minimum_path_num:
self._minimum_path_num = self._current_path_num
self._startUpdateTopLayers()
self.currentPathNumChanged.emit()
def setMinimumPath(self, value):
if self._minimum_path_num != value:
self._minimum_path_num = value
if self._minimum_path_num < 0:
self._minimum_path_num = 0
if self._minimum_path_num > self._max_layers:
self._minimum_path_num = self._max_layers
if self._minimum_path_num > self._current_path_num:
self._current_path_num = self._minimum_path_num
self._startUpdateTopLayers()
self.currentPathNumChanged.emit()
## Set the layer view type ## Set the layer view type
# #
# \param layer_view_type integer as in LayerView.qml and this class # \param layer_view_type integer as in SimulationView.qml and this class
def setLayerViewType(self, layer_view_type): def setSimulationViewType(self, layer_view_type):
self._layer_view_type = layer_view_type self._layer_view_type = layer_view_type
self.currentLayerNumChanged.emit() self.currentLayerNumChanged.emit()
## Return the layer view type, integer as in LayerView.qml and this class ## Return the layer view type, integer as in SimulationView.qml and this class
def getLayerViewType(self): def getSimulationViewType(self):
return self._layer_view_type return self._layer_view_type
## Set the extruder opacity ## Set the extruder opacity
@ -243,9 +308,20 @@ class LayerView(View):
def getExtruderCount(self): def getExtruderCount(self):
return self._extruder_count return self._extruder_count
def getMinFeedrate(self):
return self._min_feedrate
def getMaxFeedrate(self):
return self._max_feedrate
def getMinThickness(self):
return self._min_thickness
def getMaxThickness(self):
return self._max_thickness
def calculateMaxLayers(self): def calculateMaxLayers(self):
scene = self.getController().getScene() scene = self.getController().getScene()
self._activity = True
self._old_max_layers = self._max_layers self._old_max_layers = self._max_layers
## Recalculate num max layers ## Recalculate num max layers
@ -255,9 +331,16 @@ class LayerView(View):
if not layer_data: if not layer_data:
continue continue
self.setActivity(True)
min_layer_number = sys.maxsize min_layer_number = sys.maxsize
max_layer_number = -sys.maxsize max_layer_number = -sys.maxsize
for layer_id in layer_data.getLayers(): for layer_id in layer_data.getLayers():
# 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_thickness = max(float(p.lineThicknesses.max()), self._max_thickness)
self._min_thickness = min(float(p.lineThicknesses.min()), self._min_thickness)
if max_layer_number < layer_id: if max_layer_number < layer_id:
max_layer_number = layer_id max_layer_number = layer_id
if min_layer_number > layer_id: if min_layer_number > layer_id:
@ -281,10 +364,32 @@ class LayerView(View):
self.maxLayersChanged.emit() self.maxLayersChanged.emit()
self._startUpdateTopLayers() self._startUpdateTopLayers()
def calculateMaxPathsOnLayer(self, layer_num):
# Update the currentPath
scene = self.getController().getScene()
for node in DepthFirstIterator(scene.getRoot()):
layer_data = node.callDecoration("getLayerData")
if not layer_data:
continue
layer = layer_data.getLayer(layer_num)
if layer is None:
return
new_max_paths = layer.lineMeshElementCount()
if new_max_paths > 0 and new_max_paths != self._max_paths:
self._max_paths = new_max_paths
self.maxPathsChanged.emit()
self.setPath(int(new_max_paths))
maxLayersChanged = Signal() maxLayersChanged = Signal()
maxPathsChanged = Signal()
currentLayerNumChanged = Signal() currentLayerNumChanged = Signal()
currentPathNumChanged = Signal()
globalStackChanged = Signal() globalStackChanged = Signal()
preferencesChanged = Signal() preferencesChanged = Signal()
busyChanged = Signal()
activityChanged = Signal()
## Hackish way to ensure the proxy is already created, which ensures that the layerview.qml is already created ## Hackish way to ensure the proxy is already created, which ensures that the layerview.qml is already created
# as this caused some issues. # as this caused some issues.
@ -308,26 +413,31 @@ class LayerView(View):
return True return True
if event.type == Event.ViewActivateEvent: if event.type == Event.ViewActivateEvent:
# Make sure the LayerPass is created # Make sure the SimulationPass is created
layer_pass = self.getLayerPass() layer_pass = self.getSimulationPass()
self.getRenderer().addRenderPass(layer_pass) self.getRenderer().addRenderPass(layer_pass)
# Make sure the NozzleNode is add to the root
nozzle = self.getNozzleNode()
nozzle.setParent(self.getController().getScene().getRoot())
nozzle.setVisible(False)
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged) Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged)
self._onGlobalStackChanged() self._onGlobalStackChanged()
if not self._layerview_composite_shader: if not self._simulationview_composite_shader:
self._layerview_composite_shader = OpenGL.getInstance().createShaderProgram(os.path.join(PluginRegistry.getInstance().getPluginPath("LayerView"), "layerview_composite.shader")) self._simulationview_composite_shader = OpenGL.getInstance().createShaderProgram(os.path.join(PluginRegistry.getInstance().getPluginPath("SimulationView"), "simulationview_composite.shader"))
theme = Application.getInstance().getTheme() theme = Application.getInstance().getTheme()
self._layerview_composite_shader.setUniformValue("u_background_color", Color(*theme.getColor("viewport_background").getRgb())) self._simulationview_composite_shader.setUniformValue("u_background_color", Color(*theme.getColor("viewport_background").getRgb()))
self._layerview_composite_shader.setUniformValue("u_outline_color", Color(*theme.getColor("model_selection_outline").getRgb())) self._simulationview_composite_shader.setUniformValue("u_outline_color", Color(*theme.getColor("model_selection_outline").getRgb()))
if not self._composite_pass: if not self._composite_pass:
self._composite_pass = self.getRenderer().getRenderPass("composite") self._composite_pass = self.getRenderer().getRenderPass("composite")
self._old_layer_bindings = self._composite_pass.getLayerBindings()[:] # make a copy so we can restore to it later self._old_layer_bindings = self._composite_pass.getLayerBindings()[:] # make a copy so we can restore to it later
self._composite_pass.getLayerBindings().append("layerview") self._composite_pass.getLayerBindings().append("simulationview")
self._old_composite_shader = self._composite_pass.getCompositeShader() self._old_composite_shader = self._composite_pass.getCompositeShader()
self._composite_pass.setCompositeShader(self._layerview_composite_shader) self._composite_pass.setCompositeShader(self._simulationview_composite_shader)
elif event.type == Event.ViewDeactivateEvent: elif event.type == Event.ViewDeactivateEvent:
self._wireprint_warning_message.hide() self._wireprint_warning_message.hide()
@ -335,6 +445,7 @@ class LayerView(View):
if self._global_container_stack: if self._global_container_stack:
self._global_container_stack.propertyChanged.disconnect(self._onPropertyChanged) self._global_container_stack.propertyChanged.disconnect(self._onPropertyChanged)
self._nozzle_node.setParent(None)
self.getRenderer().removeRenderPass(self._layer_pass) self.getRenderer().removeRenderPass(self._layer_pass)
self._composite_pass.setLayerBindings(self._old_layer_bindings) self._composite_pass.setLayerBindings(self._old_layer_bindings)
self._composite_pass.setCompositeShader(self._old_composite_shader) self._composite_pass.setCompositeShader(self._old_composite_shader)
@ -364,6 +475,9 @@ class LayerView(View):
else: else:
self._wireprint_warning_message.hide() self._wireprint_warning_message.hide()
def _onCurrentLayerNumChanged(self):
self.calculateMaxPathsOnLayer(self._current_layer_num)
def _startUpdateTopLayers(self): def _startUpdateTopLayers(self):
if not self._compatibility_mode: if not self._compatibility_mode:
return return
@ -397,7 +511,7 @@ class LayerView(View):
self._compatibility_mode = OpenGLContext.isLegacyOpenGL() or bool( self._compatibility_mode = OpenGLContext.isLegacyOpenGL() or bool(
Preferences.getInstance().getValue("view/force_layer_view_compatibility_mode")) Preferences.getInstance().getValue("view/force_layer_view_compatibility_mode"))
self.setLayerViewType(int(float(Preferences.getInstance().getValue("layerview/layer_view_type")))); self.setSimulationViewType(int(float(Preferences.getInstance().getValue("layerview/layer_view_type"))));
for extruder_nr, extruder_opacity in enumerate(Preferences.getInstance().getValue("layerview/extruder_opacities").split("|")): for extruder_nr, extruder_opacity in enumerate(Preferences.getInstance().getValue("layerview/extruder_opacities").split("|")):
try: try:

View file

@ -13,19 +13,19 @@ Item
{ {
id: base id: base
width: { width: {
if (UM.LayerView.compatibilityMode) { if (UM.SimulationView.compatibilityMode) {
return UM.Theme.getSize("layerview_menu_size_compatibility").width; return UM.Theme.getSize("layerview_menu_size_compatibility").width;
} else { } else {
return UM.Theme.getSize("layerview_menu_size").width; return UM.Theme.getSize("layerview_menu_size").width;
} }
} }
height: { height: {
if (UM.LayerView.compatibilityMode) { if (UM.SimulationView.compatibilityMode) {
return UM.Theme.getSize("layerview_menu_size_compatibility").height; return UM.Theme.getSize("layerview_menu_size_compatibility").height;
} else if (UM.Preferences.getValue("layerview/layer_view_type") == 0) { } else if (UM.Preferences.getValue("layerview/layer_view_type") == 0) {
return UM.Theme.getSize("layerview_menu_size_material_color_mode").height + UM.LayerView.extruderCount * (UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("layerview_row_spacing").height) return UM.Theme.getSize("layerview_menu_size_material_color_mode").height + UM.SimulationView.extruderCount * (UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("layerview_row_spacing").height)
} else { } else {
return UM.Theme.getSize("layerview_menu_size").height + UM.LayerView.extruderCount * (UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("layerview_row_spacing").height) return UM.Theme.getSize("layerview_menu_size").height + UM.SimulationView.extruderCount * (UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("layerview_row_spacing").height)
} }
} }
@ -46,7 +46,7 @@ Item
anchors.top: parent.top anchors.top: parent.top
width: parent.width width: parent.width
height: parent.height height: parent.height
z: slider.z - 1 z: layerSlider.z - 1
color: UM.Theme.getColor("tool_panel_background") color: UM.Theme.getColor("tool_panel_background")
borderWidth: UM.Theme.getSize("default_lining").width borderWidth: UM.Theme.getSize("default_lining").width
borderColor: UM.Theme.getColor("lining") borderColor: UM.Theme.getColor("lining")
@ -61,7 +61,8 @@ Item
property bool show_skin: UM.Preferences.getValue("layerview/show_skin") property bool show_skin: UM.Preferences.getValue("layerview/show_skin")
property bool show_infill: UM.Preferences.getValue("layerview/show_infill") property bool show_infill: UM.Preferences.getValue("layerview/show_infill")
// if we are in compatibility mode, we only show the "line type" // if we are in compatibility mode, we only show the "line type"
property bool show_legend: UM.LayerView.compatibilityMode ? 1 : UM.Preferences.getValue("layerview/layer_view_type") == 1 property bool show_legend: UM.SimulationView.compatibilityMode ? true : UM.Preferences.getValue("layerview/layer_view_type") == 1
property bool show_gradient: UM.SimulationView.compatibilityMode ? false : UM.Preferences.getValue("layerview/layer_view_type") == 2 || UM.Preferences.getValue("layerview/layer_view_type") == 3
property bool only_show_top_layers: UM.Preferences.getValue("view/only_show_top_layers") property bool only_show_top_layers: UM.Preferences.getValue("view/only_show_top_layers")
property int top_layer_count: UM.Preferences.getValue("view/top_layer_count") property int top_layer_count: UM.Preferences.getValue("view/top_layer_count")
@ -79,12 +80,12 @@ Item
anchors.left: parent.left anchors.left: parent.left
text: catalog.i18nc("@label","Color scheme") text: catalog.i18nc("@label","Color scheme")
font: UM.Theme.getFont("default"); font: UM.Theme.getFont("default");
visible: !UM.LayerView.compatibilityMode visible: !UM.SimulationView.compatibilityMode
Layout.fillWidth: true Layout.fillWidth: true
color: UM.Theme.getColor("setting_control_text") color: UM.Theme.getColor("setting_control_text")
} }
ListModel // matches LayerView.py ListModel // matches SimulationView.py
{ {
id: layerViewTypes id: layerViewTypes
} }
@ -97,7 +98,15 @@ Item
}) })
layerViewTypes.append({ layerViewTypes.append({
text: catalog.i18nc("@label:listbox", "Line Type"), text: catalog.i18nc("@label:listbox", "Line Type"),
type_id: 1 // these ids match the switching in the shader type_id: 1
})
layerViewTypes.append({
text: catalog.i18nc("@label:listbox", "Feedrate"),
type_id: 2
})
layerViewTypes.append({
text: catalog.i18nc("@label:listbox", "Layer thickness"),
type_id: 3 // these ids match the switching in the shader
}) })
} }
@ -108,7 +117,7 @@ Item
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredWidth: UM.Theme.getSize("layerview_row").width Layout.preferredWidth: UM.Theme.getSize("layerview_row").width
model: layerViewTypes model: layerViewTypes
visible: !UM.LayerView.compatibilityMode visible: !UM.SimulationView.compatibilityMode
style: UM.Theme.styles.combobox style: UM.Theme.styles.combobox
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 10 * screenScaleFactor anchors.rightMargin: 10 * screenScaleFactor
@ -120,14 +129,14 @@ Item
Component.onCompleted: Component.onCompleted:
{ {
currentIndex = UM.LayerView.compatibilityMode ? 1 : UM.Preferences.getValue("layerview/layer_view_type"); currentIndex = UM.SimulationView.compatibilityMode ? 1 : UM.Preferences.getValue("layerview/layer_view_type");
updateLegends(currentIndex); updateLegends(currentIndex);
} }
function updateLegends(type_id) function updateLegends(type_id)
{ {
// update visibility of legends // update visibility of legends
view_settings.show_legend = UM.LayerView.compatibilityMode || (type_id == 1); view_settings.show_legend = UM.SimulationView.compatibilityMode || (type_id == 1);
} }
} }
@ -139,7 +148,7 @@ Item
text: catalog.i18nc("@label","Compatibility Mode") text: catalog.i18nc("@label","Compatibility Mode")
font: UM.Theme.getFont("default") font: UM.Theme.getFont("default")
color: UM.Theme.getColor("text") color: UM.Theme.getColor("text")
visible: UM.LayerView.compatibilityMode visible: UM.SimulationView.compatibilityMode
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: UM.Theme.getSize("layerview_row").height Layout.preferredHeight: UM.Theme.getSize("layerview_row").height
Layout.preferredWidth: UM.Theme.getSize("layerview_row").width Layout.preferredWidth: UM.Theme.getSize("layerview_row").width
@ -157,7 +166,7 @@ Item
target: UM.Preferences target: UM.Preferences
onPreferenceChanged: onPreferenceChanged:
{ {
layerTypeCombobox.currentIndex = UM.LayerView.compatibilityMode ? 1 : UM.Preferences.getValue("layerview/layer_view_type"); layerTypeCombobox.currentIndex = UM.SimulationView.compatibilityMode ? 1 : UM.Preferences.getValue("layerview/layer_view_type");
layerTypeCombobox.updateLegends(layerTypeCombobox.currentIndex); layerTypeCombobox.updateLegends(layerTypeCombobox.currentIndex);
view_settings.extruder_opacities = UM.Preferences.getValue("layerview/extruder_opacities").split("|"); view_settings.extruder_opacities = UM.Preferences.getValue("layerview/extruder_opacities").split("|");
view_settings.show_travel_moves = UM.Preferences.getValue("layerview/show_travel_moves"); view_settings.show_travel_moves = UM.Preferences.getValue("layerview/show_travel_moves");
@ -178,7 +187,7 @@ Item
view_settings.extruder_opacities[index] = checked ? 1.0 : 0.0 view_settings.extruder_opacities[index] = checked ? 1.0 : 0.0
UM.Preferences.setValue("layerview/extruder_opacities", view_settings.extruder_opacities.join("|")); UM.Preferences.setValue("layerview/extruder_opacities", view_settings.extruder_opacities.join("|"));
} }
visible: !UM.LayerView.compatibilityMode visible: !UM.SimulationView.compatibilityMode
enabled: index + 1 <= 4 enabled: index + 1 <= 4
Rectangle { Rectangle {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
@ -190,7 +199,7 @@ Item
radius: width / 2 radius: width / 2
border.width: UM.Theme.getSize("default_lining").width border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("lining") border.color: UM.Theme.getColor("lining")
visible: !view_settings.show_legend visible: !view_settings.show_legend & !view_settings.show_gradient
} }
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("default_lining").height Layout.preferredHeight: UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("default_lining").height
@ -213,28 +222,28 @@ Item
Repeater { Repeater {
model: ListModel { model: ListModel {
id: typesLegenModel id: typesLegendModel
Component.onCompleted: Component.onCompleted:
{ {
typesLegenModel.append({ typesLegendModel.append({
label: catalog.i18nc("@label", "Show Travels"), label: catalog.i18nc("@label", "Show Travels"),
initialValue: view_settings.show_travel_moves, initialValue: view_settings.show_travel_moves,
preference: "layerview/show_travel_moves", preference: "layerview/show_travel_moves",
colorId: "layerview_move_combing" colorId: "layerview_move_combing"
}); });
typesLegenModel.append({ typesLegendModel.append({
label: catalog.i18nc("@label", "Show Helpers"), label: catalog.i18nc("@label", "Show Helpers"),
initialValue: view_settings.show_helpers, initialValue: view_settings.show_helpers,
preference: "layerview/show_helpers", preference: "layerview/show_helpers",
colorId: "layerview_support" colorId: "layerview_support"
}); });
typesLegenModel.append({ typesLegendModel.append({
label: catalog.i18nc("@label", "Show Shell"), label: catalog.i18nc("@label", "Show Shell"),
initialValue: view_settings.show_skin, initialValue: view_settings.show_skin,
preference: "layerview/show_skin", preference: "layerview/show_skin",
colorId: "layerview_inset_0" colorId: "layerview_inset_0"
}); });
typesLegenModel.append({ typesLegendModel.append({
label: catalog.i18nc("@label", "Show Infill"), label: catalog.i18nc("@label", "Show Infill"),
initialValue: view_settings.show_infill, initialValue: view_settings.show_infill,
preference: "layerview/show_infill", preference: "layerview/show_infill",
@ -285,7 +294,7 @@ Item
UM.Preferences.setValue("view/only_show_top_layers", checked ? 1.0 : 0.0); UM.Preferences.setValue("view/only_show_top_layers", checked ? 1.0 : 0.0);
} }
text: catalog.i18nc("@label", "Only Show Top Layers") text: catalog.i18nc("@label", "Only Show Top Layers")
visible: UM.LayerView.compatibilityMode visible: UM.SimulationView.compatibilityMode
style: UM.Theme.styles.checkbox style: UM.Theme.styles.checkbox
} }
CheckBox { CheckBox {
@ -294,20 +303,20 @@ Item
UM.Preferences.setValue("view/top_layer_count", checked ? 5 : 1); UM.Preferences.setValue("view/top_layer_count", checked ? 5 : 1);
} }
text: catalog.i18nc("@label", "Show 5 Detailed Layers On Top") text: catalog.i18nc("@label", "Show 5 Detailed Layers On Top")
visible: UM.LayerView.compatibilityMode visible: UM.SimulationView.compatibilityMode
style: UM.Theme.styles.checkbox style: UM.Theme.styles.checkbox
} }
Repeater { Repeater {
model: ListModel { model: ListModel {
id: typesLegenModelNoCheck id: typesLegendModelNoCheck
Component.onCompleted: Component.onCompleted:
{ {
typesLegenModelNoCheck.append({ typesLegendModelNoCheck.append({
label: catalog.i18nc("@label", "Top / Bottom"), label: catalog.i18nc("@label", "Top / Bottom"),
colorId: "layerview_skin", colorId: "layerview_skin",
}); });
typesLegenModelNoCheck.append({ typesLegendModelNoCheck.append({
label: catalog.i18nc("@label", "Inner Wall"), label: catalog.i18nc("@label", "Inner Wall"),
colorId: "layerview_inset_x", colorId: "layerview_inset_x",
}); });
@ -336,47 +345,272 @@ Item
font: UM.Theme.getFont("default") font: UM.Theme.getFont("default")
} }
} }
// Text for the minimum, maximum and units for the feedrates and layer thickness
Rectangle {
id: gradientLegend
visible: view_settings.show_gradient
width: parent.width
height: UM.Theme.getSize("layerview_row").height
anchors {
topMargin: UM.Theme.getSize("slider_layerview_margin").height
horizontalCenter: parent.horizontalCenter
}
Label {
text: minText()
anchors.left: parent.left
color: UM.Theme.getColor("setting_control_text")
font: UM.Theme.getFont("default")
function minText() {
if (UM.SimulationView.layerActivity && CuraApplication.platformActivity) {
// Feedrate selected
if (UM.Preferences.getValue("layerview/layer_view_type") == 2) {
return parseFloat(UM.SimulationView.getMinFeedrate()).toFixed(2)
}
// Layer thickness selected
if (UM.Preferences.getValue("layerview/layer_view_type") == 3) {
return parseFloat(UM.SimulationView.getMinThickness()).toFixed(2)
}
}
return catalog.i18nc("@label","min")
}
}
Label {
text: unitsText()
anchors.horizontalCenter: parent.horizontalCenter
color: UM.Theme.getColor("setting_control_text")
font: UM.Theme.getFont("default")
function unitsText() {
if (UM.SimulationView.layerActivity && CuraApplication.platformActivity) {
// Feedrate selected
if (UM.Preferences.getValue("layerview/layer_view_type") == 2) {
return "mm/s"
}
// Layer thickness selected
if (UM.Preferences.getValue("layerview/layer_view_type") == 3) {
return "mm"
}
}
return ""
}
}
Label {
text: maxText()
anchors.right: parent.right
color: UM.Theme.getColor("setting_control_text")
font: UM.Theme.getFont("default")
function maxText() {
if (UM.SimulationView.layerActivity && CuraApplication.platformActivity) {
// Feedrate selected
if (UM.Preferences.getValue("layerview/layer_view_type") == 2) {
return parseFloat(UM.SimulationView.getMaxFeedrate()).toFixed(2)
}
// Layer thickness selected
if (UM.Preferences.getValue("layerview/layer_view_type") == 3) {
return parseFloat(UM.SimulationView.getMaxThickness()).toFixed(2)
}
}
return catalog.i18nc("@label","max")
}
}
}
// Gradient colors for feedrate and thickness
Rectangle { // In QML 5.9 can be changed by LinearGradient
// Invert values because then the bar is rotated 90 degrees
id: gradient
visible: view_settings.show_gradient
anchors.left: parent.right
height: parent.width
width: UM.Theme.getSize("layerview_row").height * 1.5
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("lining")
transform: Rotation {origin.x: 0; origin.y: 0; angle: 90}
gradient: Gradient {
GradientStop {
position: 0.000
color: Qt.rgba(1, 0, 0, 1)
}
GradientStop {
position: 0.25
color: Qt.rgba(0.75, 0.5, 0.25, 1)
}
GradientStop {
position: 0.5
color: Qt.rgba(0.5, 1, 0.5, 1)
}
GradientStop {
position: 0.75
color: Qt.rgba(0.25, 0.5, 0.75, 1)
}
GradientStop {
position: 1.0
color: Qt.rgba(0, 0, 1, 1)
}
}
}
} }
LayerSlider { Item {
id: slider id: slidersBox
width: UM.Theme.getSize("slider_handle").width width: parent.width
height: UM.Theme.getSize("layerview_menu_size").height visible: UM.SimulationView.layerActivity && CuraApplication.platformActivity
anchors { anchors {
top: parent.bottom top: parent.bottom
topMargin: UM.Theme.getSize("slider_layerview_margin").height topMargin: UM.Theme.getSize("slider_layerview_margin").height
right: layerViewMenu.right left: parent.left
rightMargin: UM.Theme.getSize("slider_layerview_margin").width
} }
// custom properties PathSlider {
upperValue: UM.LayerView.currentLayer id: pathSlider
lowerValue: UM.LayerView.minimumLayer
maximumValue: UM.LayerView.numLayers
handleSize: UM.Theme.getSize("slider_handle").width
trackThickness: UM.Theme.getSize("slider_groove").width
trackColor: UM.Theme.getColor("slider_groove")
trackBorderColor: UM.Theme.getColor("slider_groove_border")
upperHandleColor: UM.Theme.getColor("slider_handle")
lowerHandleColor: UM.Theme.getColor("slider_handle")
rangeHandleColor: UM.Theme.getColor("slider_groove_fill")
handleLabelWidth: UM.Theme.getSize("slider_layerview_background").width
layersVisible: UM.LayerView.layerActivity && CuraApplication.platformActivity ? true : false
// update values when layer data changes width: parent.width
Connections { height: UM.Theme.getSize("slider_handle").width
target: UM.LayerView anchors.left: parent.left
onMaxLayersChanged: slider.setUpperValue(UM.LayerView.currentLayer) visible: !UM.SimulationView.compatibilityMode
onMinimumLayerChanged: slider.setLowerValue(UM.LayerView.minimumLayer)
onCurrentLayerChanged: slider.setUpperValue(UM.LayerView.currentLayer) // custom properties
handleValue: UM.SimulationView.currentPath
maximumValue: UM.SimulationView.numPaths
handleSize: UM.Theme.getSize("slider_handle").width
trackThickness: UM.Theme.getSize("slider_groove").width
trackColor: UM.Theme.getColor("slider_groove")
trackBorderColor: UM.Theme.getColor("slider_groove_border")
handleColor: UM.Theme.getColor("slider_handle")
handleActiveColor: UM.Theme.getColor("slider_handle_active")
rangeColor: UM.Theme.getColor("slider_groove_fill")
// update values when layer data changes
Connections {
target: UM.SimulationView
onMaxPathsChanged: pathSlider.setHandleValue(UM.SimulationView.currentPath)
onCurrentPathChanged: pathSlider.setHandleValue(UM.SimulationView.currentPath)
}
// make sure the slider handlers show the correct value after switching views
Component.onCompleted: {
pathSlider.setHandleValue(UM.SimulationView.currentPath)
}
} }
// make sure the slider handlers show the correct value after switching views LayerSlider {
Component.onCompleted: { id: layerSlider
slider.setLowerValue(UM.LayerView.minimumLayer)
slider.setUpperValue(UM.LayerView.currentLayer) width: UM.Theme.getSize("slider_handle").width
height: UM.Theme.getSize("layerview_menu_size").height
anchors {
top: pathSlider.bottom
topMargin: UM.Theme.getSize("slider_layerview_margin").height
right: parent.right
rightMargin: UM.Theme.getSize("slider_layerview_margin").width
}
// custom properties
upperValue: UM.SimulationView.currentLayer
lowerValue: UM.SimulationView.minimumLayer
maximumValue: UM.SimulationView.numLayers
handleSize: UM.Theme.getSize("slider_handle").width
trackThickness: UM.Theme.getSize("slider_groove").width
trackColor: UM.Theme.getColor("slider_groove")
trackBorderColor: UM.Theme.getColor("slider_groove_border")
upperHandleColor: UM.Theme.getColor("slider_handle")
lowerHandleColor: UM.Theme.getColor("slider_handle")
rangeHandleColor: UM.Theme.getColor("slider_groove_fill")
handleActiveColor: UM.Theme.getColor("slider_handle_active")
handleLabelWidth: UM.Theme.getSize("slider_layerview_background").width
// update values when layer data changes
Connections {
target: UM.SimulationView
onMaxLayersChanged: layerSlider.setUpperValue(UM.SimulationView.currentLayer)
onMinimumLayerChanged: layerSlider.setLowerValue(UM.SimulationView.minimumLayer)
onCurrentLayerChanged: layerSlider.setUpperValue(UM.SimulationView.currentLayer)
}
// make sure the slider handlers show the correct value after switching views
Component.onCompleted: {
layerSlider.setLowerValue(UM.SimulationView.minimumLayer)
layerSlider.setUpperValue(UM.SimulationView.currentLayer)
}
}
// Play simulation button
Button {
id: playButton
implicitWidth: UM.Theme.getSize("button").width * 0.75;
implicitHeight: UM.Theme.getSize("button").height * 0.75;
iconSource: "./resources/simulation_resume.svg"
style: UM.Theme.styles.tool_button
visible: !UM.SimulationView.compatibilityMode
anchors {
horizontalCenter: layerSlider.horizontalCenter
top: layerSlider.bottom
topMargin: UM.Theme.getSize("slider_layerview_margin").width
}
property var status: 0 // indicates if it's stopped (0) or playing (1)
onClicked: {
switch(status) {
case 0: {
resumeSimulation()
break
}
case 1: {
pauseSimulation()
break
}
}
}
function pauseSimulation() {
UM.SimulationView.setSimulationRunning(false)
iconSource = "./resources/simulation_resume.svg"
simulationTimer.stop()
status = 0
}
function resumeSimulation() {
UM.SimulationView.setSimulationRunning(true)
iconSource = "./resources/simulation_pause.svg"
simulationTimer.start()
status = 1
}
}
}
Timer
{
id: simulationTimer
interval: 250
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
if (currentPath >= numPaths) {
if (currentLayer >= numLayers) {
playButton.pauseSimulation()
}
else {
UM.SimulationView.setCurrentLayer(currentLayer+1)
UM.SimulationView.setCurrentPath(0)
}
}
else {
UM.SimulationView.setCurrentPath(currentPath+1)
}
} }
} }
} }

View file

@ -0,0 +1,246 @@
# Copyright (c) 2017 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty
from UM.FlameProfiler import pyqtSlot
from UM.Application import Application
import SimulationView
class SimulationViewProxy(QObject):
def __init__(self, parent=None):
super().__init__(parent)
self._current_layer = 0
self._controller = Application.getInstance().getController()
self._controller.activeViewChanged.connect(self._onActiveViewChanged)
self._onActiveViewChanged()
currentLayerChanged = pyqtSignal()
currentPathChanged = pyqtSignal()
maxLayersChanged = pyqtSignal()
maxPathsChanged = pyqtSignal()
activityChanged = pyqtSignal()
globalStackChanged = pyqtSignal()
preferencesChanged = pyqtSignal()
busyChanged = pyqtSignal()
@pyqtProperty(bool, notify=activityChanged)
def layerActivity(self):
active_view = self._controller.getActiveView()
if isinstance(active_view, SimulationView.SimulationView.SimulationView):
return active_view.getActivity()
return False
@pyqtProperty(int, notify=maxLayersChanged)
def numLayers(self):
active_view = self._controller.getActiveView()
if isinstance(active_view, SimulationView.SimulationView.SimulationView):
return active_view.getMaxLayers()
return 0
@pyqtProperty(int, notify=currentLayerChanged)
def currentLayer(self):
active_view = self._controller.getActiveView()
if isinstance(active_view, SimulationView.SimulationView.SimulationView):
return active_view.getCurrentLayer()
return 0
@pyqtProperty(int, notify=currentLayerChanged)
def minimumLayer(self):
active_view = self._controller.getActiveView()
if isinstance(active_view, SimulationView.SimulationView.SimulationView):
return active_view.getMinimumLayer()
return 0
@pyqtProperty(int, notify=maxPathsChanged)
def numPaths(self):
active_view = self._controller.getActiveView()
if isinstance(active_view, SimulationView.SimulationView.SimulationView):
return active_view.getMaxPaths()
return 0
@pyqtProperty(int, notify=currentPathChanged)
def currentPath(self):
active_view = self._controller.getActiveView()
if isinstance(active_view, SimulationView.SimulationView.SimulationView):
return active_view.getCurrentPath()
return 0
@pyqtProperty(int, notify=currentPathChanged)
def minimumPath(self):
active_view = self._controller.getActiveView()
if isinstance(active_view, SimulationView.SimulationView.SimulationView):
return active_view.getMinimumPath()
return 0
@pyqtProperty(bool, notify=busyChanged)
def busy(self):
active_view = self._controller.getActiveView()
if isinstance(active_view, SimulationView.SimulationView.SimulationView):
return active_view.isBusy()
return False
@pyqtProperty(bool, notify=preferencesChanged)
def compatibilityMode(self):
active_view = self._controller.getActiveView()
if isinstance(active_view, SimulationView.SimulationView.SimulationView):
return active_view.getCompatibilityMode()
return False
@pyqtSlot(int)
def setCurrentLayer(self, layer_num):
active_view = self._controller.getActiveView()
if isinstance(active_view, SimulationView.SimulationView.SimulationView):
active_view.setLayer(layer_num)
@pyqtSlot(int)
def setMinimumLayer(self, layer_num):
active_view = self._controller.getActiveView()
if isinstance(active_view, SimulationView.SimulationView.SimulationView):
active_view.setMinimumLayer(layer_num)
@pyqtSlot(int)
def setCurrentPath(self, path_num):
active_view = self._controller.getActiveView()
if isinstance(active_view, SimulationView.SimulationView.SimulationView):
active_view.setPath(path_num)
@pyqtSlot(int)
def setMinimumPath(self, path_num):
active_view = self._controller.getActiveView()
if isinstance(active_view, SimulationView.SimulationView.SimulationView):
active_view.setMinimumPath(path_num)
@pyqtSlot(int)
def setSimulationViewType(self, layer_view_type):
active_view = self._controller.getActiveView()
if isinstance(active_view, SimulationView.SimulationView.SimulationView):
active_view.setSimulationViewisinstance(layer_view_type)
@pyqtSlot(result=int)
def getSimulationViewType(self):
active_view = self._controller.getActiveView()
if isinstance(active_view, SimulationView.SimulationView.SimulationView):
return active_view.getSimulationViewType()
return 0
@pyqtSlot(bool)
def setSimulationRunning(self, running):
active_view = self._controller.getActiveView()
if isinstance(active_view, SimulationView.SimulationView.SimulationView):
active_view.setSimulationRunning(running)
@pyqtSlot(result=bool)
def getSimulationRunning(self):
active_view = self._controller.getActiveView()
if isinstance(active_view, SimulationView.SimulationView.SimulationView):
return active_view.isSimulationRunning()
return False
@pyqtSlot(result=float)
def getMinFeedrate(self):
active_view = self._controller.getActiveView()
if isinstance(active_view, SimulationView.SimulationView.SimulationView):
return active_view.getMinFeedrate()
return 0
@pyqtSlot(result=float)
def getMaxFeedrate(self):
active_view = self._controller.getActiveView()
if isinstance(active_view, SimulationView.SimulationView.SimulationView):
return active_view.getMaxFeedrate()
return 0
@pyqtSlot(result=float)
def getMinThickness(self):
active_view = self._controller.getActiveView()
if isinstance(active_view, SimulationView.SimulationView.SimulationView):
return active_view.getMinThickness()
return 0
@pyqtSlot(result=float)
def getMaxThickness(self):
active_view = self._controller.getActiveView()
if isinstance(active_view, SimulationView.SimulationView.SimulationView):
return active_view.getMaxThickness()
return 0
# Opacity 0..1
@pyqtSlot(int, float)
def setExtruderOpacity(self, extruder_nr, opacity):
active_view = self._controller.getActiveView()
if isinstance(active_view, SimulationView.SimulationView.SimulationView):
active_view.setExtruderOpacity(extruder_nr, opacity)
@pyqtSlot(int)
def setShowTravelMoves(self, show):
active_view = self._controller.getActiveView()
if isinstance(active_view, SimulationView.SimulationView.SimulationView):
active_view.setShowTravelMoves(show)
@pyqtSlot(int)
def setShowHelpers(self, show):
active_view = self._controller.getActiveView()
if isinstance(active_view, SimulationView.SimulationView.SimulationView):
active_view.setShowHelpers(show)
@pyqtSlot(int)
def setShowSkin(self, show):
active_view = self._controller.getActiveView()
if isinstance(active_view, SimulationView.SimulationView.SimulationView):
active_view.setShowSkin(show)
@pyqtSlot(int)
def setShowInfill(self, show):
active_view = self._controller.getActiveView()
if isinstance(active_view, SimulationView.SimulationView.SimulationView):
active_view.setShowInfill(show)
@pyqtProperty(int, notify=globalStackChanged)
def extruderCount(self):
active_view = self._controller.getActiveView()
if isinstance(active_view, SimulationView.SimulationView.SimulationView):
return active_view.getExtruderCount()
return 0
def _layerActivityChanged(self):
self.activityChanged.emit()
def _onLayerChanged(self):
self.currentLayerChanged.emit()
self._layerActivityChanged()
def _onPathChanged(self):
self.currentPathChanged.emit()
self._layerActivityChanged()
def _onMaxLayersChanged(self):
self.maxLayersChanged.emit()
def _onMaxPathsChanged(self):
self.maxPathsChanged.emit()
def _onBusyChanged(self):
self.busyChanged.emit()
def _onActivityChanged(self):
self.activityChanged.emit()
def _onGlobalStackChanged(self):
self.globalStackChanged.emit()
def _onPreferencesChanged(self):
self.preferencesChanged.emit()
def _onActiveViewChanged(self):
active_view = self._controller.getActiveView()
if isinstance(active_view, SimulationView.SimulationView.SimulationView):
active_view.currentLayerNumChanged.connect(self._onLayerChanged)
active_view.currentPathNumChanged.connect(self._onPathChanged)
active_view.maxLayersChanged.connect(self._onMaxLayersChanged)
active_view.maxPathsChanged.connect(self._onMaxPathsChanged)
active_view.busyChanged.connect(self._onBusyChanged)
active_view.activityChanged.connect(self._onActivityChanged)
active_view.globalStackChanged.connect(self._onGlobalStackChanged)
active_view.preferencesChanged.connect(self._onPreferencesChanged)

View file

@ -0,0 +1,26 @@
# Copyright (c) 2017 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from PyQt5.QtQml import qmlRegisterSingletonType
from UM.i18n import i18nCatalog
from . import SimulationViewProxy, SimulationView
catalog = i18nCatalog("cura")
def getMetaData():
return {
"view": {
"name": catalog.i18nc("@item:inlistbox", "Simulation view"),
"view_panel": "SimulationView.qml",
"weight": 2
}
}
def createSimulationViewProxy(engine, script_engine):
return SimulationViewProxy.SimulatorViewProxy()
def register(app):
simulation_view = SimulationView.SimulationView()
qmlRegisterSingletonType(SimulationViewProxy.SimulationViewProxy, "UM", 1, 0, "SimulationView", simulation_view.getProxy)
return { "view": SimulationView.SimulationView()}

View file

@ -6,6 +6,10 @@ vertex41core =
uniform highp mat4 u_modelMatrix; uniform highp mat4 u_modelMatrix;
uniform highp mat4 u_viewProjectionMatrix; uniform highp mat4 u_viewProjectionMatrix;
uniform lowp float u_active_extruder; uniform lowp float u_active_extruder;
uniform lowp float u_max_feedrate;
uniform lowp float u_min_feedrate;
uniform lowp float u_max_thickness;
uniform lowp float u_min_thickness;
uniform lowp int u_layer_view_type; uniform lowp int u_layer_view_type;
uniform lowp vec4 u_extruder_opacity; // currently only for max 4 extruders, others always visible uniform lowp vec4 u_extruder_opacity; // currently only for max 4 extruders, others always visible
@ -18,6 +22,8 @@ vertex41core =
in highp vec2 a_line_dim; // line width and thickness in highp vec2 a_line_dim; // line width and thickness
in highp float a_extruder; in highp float a_extruder;
in highp float a_line_type; in highp float a_line_type;
in highp float a_feedrate;
in highp float a_thickness;
out lowp vec4 v_color; out lowp vec4 v_color;
@ -32,6 +38,15 @@ vertex41core =
out highp vec3 f_vertex; out highp vec3 f_vertex;
out highp vec3 f_normal; out highp vec3 f_normal;
vec4 gradientColor(float abs_value, float min_value, float max_value)
{
float value = (abs_value - min_value)/(max_value - min_value);
float red = value;
float green = 1-abs(1-2*value);
float blue = 1-value;
return vec4(red, green, blue, 1.0);
}
void main() void main()
{ {
vec4 v1_vertex = a_vertex; vec4 v1_vertex = a_vertex;
@ -48,6 +63,12 @@ vertex41core =
case 1: // "Line type" case 1: // "Line type"
v_color = a_color; v_color = a_color;
break; break;
case 2: // "Feedrate"
v_color = gradientColor(a_feedrate, u_min_feedrate, u_max_feedrate);
break;
case 3: // "Layer thickness"
v_color = gradientColor(a_line_dim.y, u_min_thickness, u_max_thickness);
break;
} }
v_vertex = world_space_vert.xyz; v_vertex = world_space_vert.xyz;
@ -247,6 +268,12 @@ u_show_helpers = 1
u_show_skin = 1 u_show_skin = 1
u_show_infill = 1 u_show_infill = 1
u_min_feedrate = 0
u_max_feedrate = 1
u_min_thickness = 0
u_max_thickness = 1
[bindings] [bindings]
u_modelViewProjectionMatrix = model_view_projection_matrix u_modelViewProjectionMatrix = model_view_projection_matrix
u_modelMatrix = model_matrix u_modelMatrix = model_matrix
@ -262,3 +289,5 @@ a_line_dim = line_dim
a_extruder = extruder a_extruder = extruder
a_material_color = material_color a_material_color = material_color
a_line_type = line_type a_line_type = line_type
a_feedrate = feedrate
a_thickness = thickness

View file

@ -0,0 +1,256 @@
[shaders]
vertex41core =
#version 410
uniform highp mat4 u_modelViewProjectionMatrix;
uniform highp mat4 u_modelMatrix;
uniform highp mat4 u_viewProjectionMatrix;
uniform lowp float u_active_extruder;
uniform lowp vec4 u_extruder_opacity; // currently only for max 4 extruders, others always visible
uniform highp mat4 u_normalMatrix;
in highp vec4 a_vertex;
in lowp vec4 a_color;
in lowp vec4 a_grayColor;
in lowp vec4 a_material_color;
in highp vec4 a_normal;
in highp vec2 a_line_dim; // line width and thickness
in highp float a_extruder;
in highp float a_line_type;
out lowp vec4 v_color;
out highp vec3 v_vertex;
out highp vec3 v_normal;
out lowp vec2 v_line_dim;
out highp int v_extruder;
out highp vec4 v_extruder_opacity;
out float v_line_type;
out lowp vec4 f_color;
out highp vec3 f_vertex;
out highp vec3 f_normal;
void main()
{
vec4 v1_vertex = a_vertex;
v1_vertex.y -= a_line_dim.y / 2; // half layer down
vec4 world_space_vert = u_modelMatrix * v1_vertex;
gl_Position = world_space_vert;
// shade the color depending on the extruder index stored in the alpha component of the color
v_color = vec4(0.4, 0.4, 0.4, 0.9); // default color for not current layer
v_vertex = world_space_vert.xyz;
v_normal = (u_normalMatrix * normalize(a_normal)).xyz;
v_line_dim = a_line_dim;
v_extruder = int(a_extruder);
v_line_type = a_line_type;
v_extruder_opacity = u_extruder_opacity;
// for testing without geometry shader
f_color = v_color;
f_vertex = v_vertex;
f_normal = v_normal;
}
geometry41core =
#version 410
uniform highp mat4 u_viewProjectionMatrix;
uniform int u_show_travel_moves;
uniform int u_show_helpers;
uniform int u_show_skin;
uniform int u_show_infill;
layout(lines) in;
layout(triangle_strip, max_vertices = 26) out;
in vec4 v_color[];
in vec3 v_vertex[];
in vec3 v_normal[];
in vec2 v_line_dim[];
in int v_extruder[];
in vec4 v_extruder_opacity[];
in float v_line_type[];
out vec4 f_color;
out vec3 f_normal;
out vec3 f_vertex;
// Set the set of variables and EmitVertex
void myEmitVertex(vec3 vertex, vec4 color, vec3 normal, vec4 pos) {
f_vertex = vertex;
f_color = color;
f_normal = normal;
gl_Position = pos;
EmitVertex();
}
void main()
{
vec4 g_vertex_delta;
vec3 g_vertex_normal_horz; // horizontal and vertical in respect to layers
vec4 g_vertex_offset_horz; // vec4 to match gl_in[x].gl_Position
vec3 g_vertex_normal_vert;
vec4 g_vertex_offset_vert;
vec3 g_vertex_normal_horz_head;
vec4 g_vertex_offset_horz_head;
float size_x;
float size_y;
if ((v_extruder_opacity[0][v_extruder[0]] == 0.0) && (v_line_type[0] != 8) && (v_line_type[0] != 9)) {
return;
}
// See LayerPolygon; 8 is MoveCombingType, 9 is RetractionType
if ((u_show_travel_moves == 0) && ((v_line_type[0] == 8) || (v_line_type[0] == 9))) {
return;
}
if ((u_show_helpers == 0) && ((v_line_type[0] == 4) || (v_line_type[0] == 5) || (v_line_type[0] == 7) || (v_line_type[0] == 10))) {
return;
}
if ((u_show_skin == 0) && ((v_line_type[0] == 1) || (v_line_type[0] == 2) || (v_line_type[0] == 3))) {
return;
}
if ((u_show_infill == 0) && (v_line_type[0] == 6)) {
return;
}
if ((v_line_type[0] == 8) || (v_line_type[0] == 9)) {
// fixed size for movements
size_x = 0.05;
} else {
size_x = v_line_dim[1].x / 2 + 0.01; // radius, and make it nicely overlapping
}
size_y = v_line_dim[1].y / 2 + 0.01;
g_vertex_delta = gl_in[1].gl_Position - gl_in[0].gl_Position;
g_vertex_normal_horz_head = normalize(vec3(-g_vertex_delta.x, -g_vertex_delta.y, -g_vertex_delta.z));
g_vertex_offset_horz_head = vec4(g_vertex_normal_horz_head * size_x, 0.0);
g_vertex_normal_horz = normalize(vec3(g_vertex_delta.z, g_vertex_delta.y, -g_vertex_delta.x));
g_vertex_offset_horz = vec4(g_vertex_normal_horz * size_x, 0.0); //size * g_vertex_normal_horz;
g_vertex_normal_vert = vec3(0.0, 1.0, 0.0);
g_vertex_offset_vert = vec4(g_vertex_normal_vert * size_y, 0.0);
if ((v_line_type[0] == 8) || (v_line_type[0] == 9)) {
// Travels: flat plane with pointy ends
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz + g_vertex_offset_vert));
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz_head + g_vertex_offset_vert));
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position - g_vertex_offset_horz + g_vertex_offset_vert));
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz + g_vertex_offset_vert));
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz + g_vertex_offset_vert));
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_horz + g_vertex_offset_vert));
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz_head + g_vertex_offset_vert));
EndPrimitive();
} else {
// All normal lines are rendered as 3d tubes.
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz));
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_horz));
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_vert));
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_vert));
myEmitVertex(v_vertex[0], v_color[0], -g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position - g_vertex_offset_horz));
myEmitVertex(v_vertex[1], v_color[1], -g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz));
myEmitVertex(v_vertex[0], v_color[0], -g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position - g_vertex_offset_vert));
myEmitVertex(v_vertex[1], v_color[1], -g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_vert));
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz));
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_horz));
EndPrimitive();
// left side
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz));
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_vert));
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_horz_head, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz_head));
myEmitVertex(v_vertex[0], v_color[0], -g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position - g_vertex_offset_horz));
EndPrimitive();
myEmitVertex(v_vertex[0], v_color[0], -g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position - g_vertex_offset_horz));
myEmitVertex(v_vertex[0], v_color[0], -g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position - g_vertex_offset_vert));
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_horz_head, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz_head));
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz));
EndPrimitive();
// right side
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_horz));
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_vert));
myEmitVertex(v_vertex[1], v_color[1], -g_vertex_normal_horz_head, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz_head));
myEmitVertex(v_vertex[1], v_color[1], -g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz));
EndPrimitive();
myEmitVertex(v_vertex[1], v_color[1], -g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz));
myEmitVertex(v_vertex[1], v_color[1], -g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_vert));
myEmitVertex(v_vertex[1], v_color[1], -g_vertex_normal_horz_head, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz_head));
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_horz));
EndPrimitive();
}
}
fragment41core =
#version 410
in lowp vec4 f_color;
in lowp vec3 f_normal;
in lowp vec3 f_vertex;
out vec4 frag_color;
uniform mediump vec4 u_ambientColor;
uniform highp vec3 u_lightPosition;
void main()
{
mediump vec4 finalColor = vec4(0.0);
float alpha = f_color.a;
finalColor.rgb += f_color.rgb * 0.3;
highp vec3 normal = normalize(f_normal);
highp vec3 light_dir = normalize(u_lightPosition - f_vertex);
// Diffuse Component
highp float NdotL = clamp(dot(normal, light_dir), 0.0, 1.0);
finalColor += (NdotL * f_color);
finalColor.a = alpha; // Do not change alpha in any way
frag_color = finalColor;
}
[defaults]
u_active_extruder = 0.0
u_extruder_opacity = [1.0, 1.0, 1.0, 1.0]
u_specularColor = [0.4, 0.4, 0.4, 1.0]
u_ambientColor = [0.3, 0.3, 0.3, 0.0]
u_diffuseColor = [1.0, 0.79, 0.14, 1.0]
u_shininess = 20.0
u_show_travel_moves = 0
u_show_helpers = 1
u_show_skin = 1
u_show_infill = 1
[bindings]
u_modelViewProjectionMatrix = model_view_projection_matrix
u_modelMatrix = model_matrix
u_viewProjectionMatrix = view_projection_matrix
u_normalMatrix = normal_matrix
u_lightPosition = light_0_position
[attributes]
a_vertex = vertex
a_color = color
a_grayColor = vec4(0.87, 0.12, 0.45, 1.0)
a_normal = normal
a_line_dim = line_dim
a_extruder = extruder
a_material_color = material_color
a_line_type = line_type

View file

@ -0,0 +1,156 @@
[shaders]
vertex =
uniform highp mat4 u_modelViewProjectionMatrix;
uniform lowp float u_active_extruder;
uniform lowp float u_shade_factor;
uniform highp int u_layer_view_type;
attribute highp float a_extruder;
attribute highp float a_line_type;
attribute highp vec4 a_vertex;
attribute lowp vec4 a_color;
attribute lowp vec4 a_material_color;
varying lowp vec4 v_color;
varying float v_line_type;
void main()
{
gl_Position = u_modelViewProjectionMatrix * a_vertex;
// shade the color depending on the extruder index
v_color = vec4(0.4, 0.4, 0.4, 0.9); // default color for not current layer;
// 8 and 9 are travel moves
// if ((a_line_type != 8.0) && (a_line_type != 9.0)) {
// v_color = (a_extruder == u_active_extruder) ? v_color : vec4(u_shade_factor * v_color.rgb, v_color.a);
// }
v_line_type = a_line_type;
}
fragment =
varying lowp vec4 v_color;
varying float v_line_type;
uniform int u_show_travel_moves;
uniform int u_show_helpers;
uniform int u_show_skin;
uniform int u_show_infill;
void main()
{
if ((u_show_travel_moves == 0) && (v_line_type >= 7.5) && (v_line_type <= 9.5)) { // actually, 8 and 9
// discard movements
discard;
}
// support: 4, 5, 7, 10
if ((u_show_helpers == 0) && (
((v_line_type >= 3.5) && (v_line_type <= 4.5)) ||
((v_line_type >= 6.5) && (v_line_type <= 7.5)) ||
((v_line_type >= 9.5) && (v_line_type <= 10.5)) ||
((v_line_type >= 4.5) && (v_line_type <= 5.5))
)) {
discard;
}
// skin: 1, 2, 3
if ((u_show_skin == 0) && (
(v_line_type >= 0.5) && (v_line_type <= 3.5)
)) {
discard;
}
// infill:
if ((u_show_infill == 0) && (v_line_type >= 5.5) && (v_line_type <= 6.5)) {
// discard movements
discard;
}
gl_FragColor = v_color;
}
vertex41core =
#version 410
uniform highp mat4 u_modelViewProjectionMatrix;
uniform lowp float u_active_extruder;
uniform lowp float u_shade_factor;
uniform highp int u_layer_view_type;
in highp float a_extruder;
in highp float a_line_type;
in highp vec4 a_vertex;
in lowp vec4 a_color;
in lowp vec4 a_material_color;
out lowp vec4 v_color;
out float v_line_type;
void main()
{
gl_Position = u_modelViewProjectionMatrix * a_vertex;
v_color = vec4(0.4, 0.4, 0.4, 0.9); // default color for not current layer
// if ((a_line_type != 8) && (a_line_type != 9)) {
// v_color = (a_extruder == u_active_extruder) ? v_color : vec4(u_shade_factor * v_color.rgb, v_color.a);
// }
v_line_type = a_line_type;
}
fragment41core =
#version 410
in lowp vec4 v_color;
in float v_line_type;
out vec4 frag_color;
uniform int u_show_travel_moves;
uniform int u_show_helpers;
uniform int u_show_skin;
uniform int u_show_infill;
void main()
{
if ((u_show_travel_moves == 0) && (v_line_type >= 7.5) && (v_line_type <= 9.5)) { // actually, 8 and 9
// discard movements
discard;
}
// helpers: 4, 5, 7, 10
if ((u_show_helpers == 0) && (
((v_line_type >= 3.5) && (v_line_type <= 4.5)) ||
((v_line_type >= 6.5) && (v_line_type <= 7.5)) ||
((v_line_type >= 9.5) && (v_line_type <= 10.5)) ||
((v_line_type >= 4.5) && (v_line_type <= 5.5))
)) {
discard;
}
// skin: 1, 2, 3
if ((u_show_skin == 0) && (
(v_line_type >= 0.5) && (v_line_type <= 3.5)
)) {
discard;
}
// infill:
if ((u_show_infill == 0) && (v_line_type >= 5.5) && (v_line_type <= 6.5)) {
// discard movements
discard;
}
frag_color = v_color;
}
[defaults]
u_active_extruder = 0.0
u_shade_factor = 0.60
u_layer_view_type = 0
u_extruder_opacity = [1.0, 1.0, 1.0, 1.0]
u_show_travel_moves = 0
u_show_helpers = 1
u_show_skin = 1
u_show_infill = 1
[bindings]
u_modelViewProjectionMatrix = model_view_projection_matrix
[attributes]
a_vertex = vertex
a_color = color
a_extruder = extruder
a_line_type = line_type
a_material_color = material_color

View file

@ -1,8 +1,8 @@
{ {
"name": "Layer View", "name": "Simulation View",
"author": "Ultimaker B.V.", "author": "Ultimaker B.V.",
"version": "1.0.0", "version": "1.0.0",
"description": "Provides the Layer view.", "description": "Provides the Simulation view.",
"api": 4, "api": 4,
"i18n-catalog": "cura" "i18n-catalog": "cura"
} }

Binary file not shown.

View file

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
viewBox="0 0 30 30"
version="1.1"
id="svg4620"
sodipodi:docname="simulation_pause.svg"
inkscape:version="0.92.2 (5c3e80d, 2017-08-06)">
<metadata
id="metadata4626">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs4624" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1137"
id="namedview4622"
showgrid="false"
showguides="true"
inkscape:guide-bbox="true"
inkscape:zoom="22.250293"
inkscape:cx="8.1879003"
inkscape:cy="12.643765"
inkscape:window-x="2872"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg4620">
<sodipodi:guide
position="15,15"
orientation="1,0"
id="guide4628"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,0,255)" />
<sodipodi:guide
position="15,15"
orientation="0,1"
id="guide4630"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,0,255)" />
</sodipodi:namedview>
<rect
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect5192"
width="2"
height="20"
x="19"
y="5" />
<rect
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect5192-5"
width="2"
height="20"
x="9"
y="5" />
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View file

@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
viewBox="0 0 30 30"
version="1.1"
id="svg3765"
sodipodi:docname="simulation_resume.svg"
inkscape:version="0.92.2 (5c3e80d, 2017-08-06)">
<metadata
id="metadata3771">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs3769" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1137"
id="namedview3767"
showgrid="false"
showguides="true"
inkscape:guide-bbox="true"
inkscape:zoom="23.327047"
inkscape:cx="10.788646"
inkscape:cy="14.67951"
inkscape:window-x="2872"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg3765">
<sodipodi:guide
position="15,15"
orientation="0,1"
id="guide4592"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,0,255)" />
<sodipodi:guide
position="15,15"
orientation="1,0"
id="guide4594"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,0,255)" />
</sodipodi:namedview>
<path
sodipodi:type="star"
id="path3783"
sodipodi:sides="3"
sodipodi:cx="12.732001"
sodipodi:cy="14.695877"
sodipodi:r1="13.891838"
sodipodi:r2="6.945919"
sodipodi:arg1="0"
sodipodi:arg2="1.0471976"
inkscape:flatsided="true"
inkscape:rounded="0"
inkscape:randomized="0"
d="m 26.623839,14.695877 -20.8377567,12.030685 0,-24.0613696 z"
inkscape:transform-center-x="-2.9211205"
style="fill:none;stroke:#000000;stroke-width:2.32790732;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
transform="matrix(0.84110413,0,0,0.87756418,1.775541,2.1034247)" />
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB