Merge branch 'master' into CURA-6854_align_layer_label_top_bottom

# Conflicts:
#	plugins/SimulationView/SimulationViewMainComponent.qml
This commit is contained in:
Nino van Hooff 2019-11-01 10:51:21 +01:00
commit 94d291a20c
54 changed files with 948 additions and 75 deletions

View file

@ -143,6 +143,52 @@ UM.Dialog
}
}
UM.TooltipArea {
Layout.fillWidth:true
height: childrenRect.height
text: catalog.i18nc("@info:tooltip","For lithophanes a simple logarithmic model for translucency is available. For height maps the pixel values correspond to heights linearly.")
Row {
width: parent.width
Label {
text: "Color Model"
width: 150 * screenScaleFactor
anchors.verticalCenter: parent.verticalCenter
}
ComboBox {
id: color_model
objectName: "ColorModel"
model: [ catalog.i18nc("@item:inlistbox","Linear"), catalog.i18nc("@item:inlistbox","Translucency") ]
width: 180 * screenScaleFactor
onCurrentIndexChanged: { manager.onColorModelChanged(currentIndex) }
}
}
}
UM.TooltipArea {
Layout.fillWidth:true
height: childrenRect.height
text: catalog.i18nc("@info:tooltip","The percentage of light penetrating a print with a thickness of 1 millimeter. Lowering this value increases the contrast in dark regions and decreases the contrast in light regions of the image.")
visible: color_model.currentText == catalog.i18nc("@item:inlistbox","Translucency")
Row {
width: parent.width
Label {
text: catalog.i18nc("@action:label", "1mm Transmittance (%)")
width: 150 * screenScaleFactor
anchors.verticalCenter: parent.verticalCenter
}
TextField {
id: transmittance
objectName: "Transmittance"
focus: true
validator: RegExpValidator {regExp: /^[1-9]\d{0,2}([\,|\.]\d*)?$/}
width: 180 * screenScaleFactor
onTextChanged: { manager.onTransmittanceChanged(text) }
}
}
}
UM.TooltipArea {
Layout.fillWidth:true
height: childrenRect.height

View file

@ -3,6 +3,8 @@
import numpy
import math
from PyQt5.QtGui import QImage, qRed, qGreen, qBlue
from PyQt5.QtCore import Qt
@ -46,9 +48,9 @@ class ImageReader(MeshReader):
def _read(self, file_name):
size = max(self._ui.getWidth(), self._ui.getDepth())
return self._generateSceneNode(file_name, size, self._ui.peak_height, self._ui.base_height, self._ui.smoothing, 512, self._ui.lighter_is_higher)
return self._generateSceneNode(file_name, size, self._ui.peak_height, self._ui.base_height, self._ui.smoothing, 512, self._ui.lighter_is_higher, self._ui.use_transparency_model, self._ui.transmittance_1mm)
def _generateSceneNode(self, file_name, xz_size, peak_height, base_height, blur_iterations, max_size, lighter_is_higher):
def _generateSceneNode(self, file_name, xz_size, peak_height, base_height, blur_iterations, max_size, lighter_is_higher, use_transparency_model, transmittance_1mm):
scene_node = SceneNode()
mesh = MeshBuilder()
@ -99,12 +101,14 @@ class ImageReader(MeshReader):
for x in range(0, width):
for y in range(0, height):
qrgb = img.pixel(x, y)
avg = float(qRed(qrgb) + qGreen(qrgb) + qBlue(qrgb)) / (3 * 255)
height_data[y, x] = avg
if use_transparency_model:
height_data[y, x] = (0.299 * math.pow(qRed(qrgb) / 255.0, 2.2) + 0.587 * math.pow(qGreen(qrgb) / 255.0, 2.2) + 0.114 * math.pow(qBlue(qrgb) / 255.0, 2.2))
else:
height_data[y, x] = (0.212655 * qRed(qrgb) + 0.715158 * qGreen(qrgb) + 0.072187 * qBlue(qrgb)) / 255 # fast computation ignoring gamma and degamma
Job.yieldThread()
if not lighter_is_higher:
if lighter_is_higher == use_transparency_model:
height_data = 1 - height_data
for _ in range(0, blur_iterations):
@ -124,8 +128,15 @@ class ImageReader(MeshReader):
Job.yieldThread()
height_data *= scale_vector.y
height_data += base_height
if use_transparency_model:
divisor = 1.0 / math.log(transmittance_1mm / 100.0) # log-base doesn't matter here. Precompute this value for faster computation of each pixel.
min_luminance = (transmittance_1mm / 100.0) ** (peak_height - base_height)
for (y, x) in numpy.ndindex(height_data.shape):
mapped_luminance = min_luminance + (1.0 - min_luminance) * height_data[y, x]
height_data[y, x] = base_height + divisor * math.log(mapped_luminance) # use same base as a couple lines above this
else:
height_data *= scale_vector.y
height_data += base_height
heightmap_face_count = 2 * height_minus_one * width_minus_one
total_face_count = heightmap_face_count + (width_minus_one * 2) * (height_minus_one * 2) + 2

View file

@ -34,6 +34,8 @@ class ImageReaderUI(QObject):
self.peak_height = 2.5
self.smoothing = 1
self.lighter_is_higher = False;
self.use_transparency_model = True;
self.transmittance_1mm = 50.0; # based on pearl PLA
self._ui_lock = threading.Lock()
self._cancelled = False
@ -75,6 +77,7 @@ class ImageReaderUI(QObject):
self._ui_view.findChild(QObject, "Base_Height").setProperty("text", str(self.base_height))
self._ui_view.findChild(QObject, "Peak_Height").setProperty("text", str(self.peak_height))
self._ui_view.findChild(QObject, "Transmittance").setProperty("text", str(self.transmittance_1mm))
self._ui_view.findChild(QObject, "Smoothing").setProperty("value", self.smoothing)
def _createConfigUI(self):
@ -144,3 +147,11 @@ class ImageReaderUI(QObject):
@pyqtSlot(int)
def onImageColorInvertChanged(self, value):
self.lighter_is_higher = (value == 1)
@pyqtSlot(int)
def onColorModelChanged(self, value):
self.use_transparency_model = (value == 0)
@pyqtSlot(int)
def onTransmittanceChanged(self, value):
self.transmittance_1mm = value

View file

@ -12,14 +12,18 @@ import Cura 1.0 as Cura
Item
{
// An Item whose bounds are guaranteed to be safe for overlays to be placed.
// Defaults to parent, ie. the entire available area
property var safeArea: parent
// Subtract the actionPanel from the safe area. This way the view won't draw interface elements under/over it
Item {
id: safeArea
visible: false
anchors.left: parent.left
anchors.right: actionPanelWidget.left
anchors.top: parent.top
anchors.bottom: actionPanelWidget.top
Item
{
id: childSafeArea
x: safeArea.x - parent.x
y: safeArea.y - parent.y
width: actionPanelWidget.x - x
height: actionPanelWidget.y - y
}
Loader
@ -29,9 +33,10 @@ Item
source: UM.Controller.activeView != null && UM.Controller.activeView.mainComponent != null ? UM.Controller.activeView.mainComponent : ""
onLoaded: {
onLoaded:
{
if (previewMain.item.safeArea !== undefined){
previewMain.item.safeArea = Qt.binding(function() { return safeArea });
previewMain.item.safeArea = Qt.binding(function() { return childSafeArea });
}
}
}

View file

@ -56,6 +56,11 @@ Item
return Math.min(Math.max(value, sliderRoot.minimumValue), sliderRoot.maximumValue)
}
onWidthChanged : {
// After a width change, the pixel-position of the handle is out of sync with the property value
setHandleValue(handleValue)
}
// slider track
Rectangle
{

View file

@ -18,7 +18,10 @@ Item
property bool isSimulationPlaying: false
readonly property var layerSliderSafeYMax: safeArea.y + safeArea.height
readonly property real layerSliderSafeYMin: safeArea.y
readonly property real layerSliderSafeYMax: safeArea.y + safeArea.height
readonly property real pathSliderSafeXMin: safeArea.x + playButton.width
readonly property real pathSliderSafeXMax: safeArea.x + safeArea.width
visible: UM.SimulationView.layerActivity && CuraApplication.platformActivity
@ -26,13 +29,21 @@ Item
PathSlider
{
id: pathSlider
readonly property real preferredWidth: UM.Theme.getSize("slider_layerview_size").height // not a typo, should be as long as layerview slider
readonly property real margin: UM.Theme.getSize("default_margin").width
readonly property real pathSliderSafeWidth: pathSliderSafeXMax - pathSliderSafeXMin
height: UM.Theme.getSize("slider_handle").width
width: UM.Theme.getSize("slider_layerview_size").height
width: preferredWidth + margin * 2 < pathSliderSafeWidth ? preferredWidth : pathSliderSafeWidth - margin * 2
anchors.bottom: parent.bottom
anchors.bottomMargin: UM.Theme.getSize("default_margin").height
anchors.bottomMargin: margin
anchors.horizontalCenter: parent.horizontalCenter
anchors.horizontalCenterOffset: -(parent.width - pathSliderSafeXMax - pathSliderSafeXMin) / 2 // center between parent top and layerSliderSafeYMax
visible: !UM.SimulationView.compatibilityMode
@ -184,16 +195,18 @@ Item
{
property var preferredHeight: UM.Theme.getSize("slider_layerview_size").height
property double heightMargin: UM.Theme.getSize("default_margin").height * 3 // extra margin to accomodate layer number tooltips
property double layerSliderSafeHeight: layerSliderSafeYMax - layerSliderSafeYMin
id: layerSlider
width: UM.Theme.getSize("slider_handle").width
height: preferredHeight + heightMargin * 2 < layerSliderSafeYMax ? preferredHeight : layerSliderSafeYMax - heightMargin * 2
height: preferredHeight + heightMargin * 2 < layerSliderSafeHeight ? preferredHeight : layerSliderSafeHeight - heightMargin * 2
anchors
{
right: parent.right
verticalCenter: parent.verticalCenter
verticalCenterOffset: -(parent.height - layerSliderSafeYMax) / 2 // center between parent top and layerSliderSafeYMax
verticalCenterOffset: -(parent.height - layerSliderSafeYMax - layerSliderSafeYMin) / 2 // center between parent top and layerSliderSafeYMax
rightMargin: UM.Theme.getSize("default_margin").width
bottomMargin: heightMargin
topMargin: heightMargin