Meshroom/meshroom/ui/qml/Viewer/PanoramaViewer.qml

266 lines
8.1 KiB
QML

import QtQuick 2.11
import Utils 1.0
import AliceVision 1.0 as AliceVision
/**
* FloatImage displays an Image with gamma / offset / channel controls
* Requires QtAliceVision plugin.
*/
AliceVision.PanoramaViewer {
id: root
width: 3000
height: 1500
visible: (status === Image.Ready)
// paintedWidth / paintedHeight / status for compatibility with standard Image
property int paintedWidth: textureSize.width
property int paintedHeight: textureSize.height
property var status: Image.Null
property int downscaleValue: 2
property int subdivisionsPano: 12
property bool isEditable: true
property bool isHighlightable: true
property bool displayGridPano: true
property int mouseMultiplier: 1
onIsHighlightableChanged:{
for (var i = 0; i < repeater.model; i++) {
repeater.itemAt(i).item.onChangedHighlightState(isHighlightable);
}
}
onSubdivisionsPanoChanged:{
for (var i = 0; i < repeater.model; i++) {
repeater.itemAt(i).item.updateSubdivisions(subdivisionsPano);
}
}
onDownscaleValueChanged: {
for (var i = 0; i < repeater.model; i++) {
repeater.itemAt(i).item.setDownscale(downscaleValue);
}
}
clearBeforeLoad: true
property alias containsMouse: mouseAreaPano.containsMouse
property bool isRotating: false
property var lastX : 0
property var lastY: 0
property int yaw: 0;
property int pitch: 0;
// Yaw and Pitch in Degrees from SfMTransform sliders
property int yawNode: _reconstruction.activeNodes.get('SfMTransform').node.attribute("manualTransform.manualRotation.y").value;
property int pitchNode: _reconstruction.activeNodes.get('SfMTransform').node.attribute("manualTransform.manualRotation.x").value;
onYawNodeChanged: {
if (!isRotating) {
for (var i = 0; i < repeater.model; i++) {
repeater.itemAt(i).item.rotatePanoramaDegrees(yawNode, pitchNode);
}
}
}
onPitchNodeChanged: {
if (!isRotating) {
for (var i = 0; i < repeater.model; i++) {
repeater.itemAt(i).item.rotatePanoDegrees(yawNode, pitchNode);
}
}
}
Item {
id: containerPanorama
z: 10
Rectangle {
width: 3000
height: 1500
//color: mouseAreaPano.containsMouse? "red" : "green"
color: "transparent"
MouseArea {
id: mouseAreaPano
anchors.fill: parent
hoverEnabled: true
cursorShape: {
if (isEditable)
isRotating ? Qt.ClosedHandCursor : Qt.OpenHandCursor
}
onPositionChanged: {
// Send Mouse Coordinates to Float Images Viewers
for (var i = 0; i < repeater.model && isHighlightable; i++) {
var highlight = repeater.itemAt(i).item.getMouseCoordinates(mouse.x, mouse.y);
repeater.itemAt(i).z = highlight ? 2 : 0
}
// Rotate Panorama
if (isRotating && isEditable) {
var xoffset = mouse.x - lastX;
var yoffset = mouse.y - lastY;
lastX = mouse.x;
lastY = mouse.y;
for (var i = 0; i < repeater.model; i++) {
repeater.itemAt(i).item.rotatePanoRadians((xoffset / width) * mouseMultiplier, -(yoffset / height) * mouseMultiplier);
}
}
}
onPressed:{
isRotating = true;
lastX = mouse.x;
lastY = mouse.y;
}
onReleased: {
if (isRotating)
{
// Update Euler angles
var activeNode = _reconstruction.activeNodes.get('SfMTransform').node;
root.yaw = repeater.itemAt(0).item.getYaw();
root.pitch = repeater.itemAt(0).item.getPitch();
activeNode.attribute("manualTransform.manualRotation.y").value = root.yaw;
activeNode.attribute("manualTransform.manualRotation.x").value = root.pitch;
}
isRotating = false;
lastX = 0
lastY = 0
}
}
// Grid Panorama Viewer
Canvas {
id: gridPano
visible: displayGridPano
anchors.fill : parent
property int wgrid: 40
onPaint: {
var ctx = getContext("2d")
ctx.lineWidth = 1.0
ctx.shadowBlur = 0
ctx.strokeStyle = "grey"
var nrows = height/wgrid;
for(var i=0; i < nrows+1; i++){
ctx.moveTo(0, wgrid*i);
ctx.lineTo(width, wgrid*i);
}
var ncols = width/wgrid
for(var j=0; j < ncols+1; j++){
ctx.moveTo(wgrid*j, 0);
ctx.lineTo(wgrid*j, height);
}
ctx.closePath()
ctx.stroke()
}
}
}
}
property string sfmPath: ""
function updateSfmPath() {
console.warn("SFM UPDATE - PANO")
var activeNode = _reconstruction.activeNodes.get('SfMTransform').node;
if(!activeNode)
{
root.sfmPath = "";
}
else
{
root.sfmPath = activeNode.attribute("input").value;
}
root.setSfmPath(sfmPath);
}
property var pathList : []
property var idList : []
Item {
id: panoImages
width: root.width
height: root.height
Component {
id: imgPano
Loader {
id: floatOneLoader
active: root.status
visible: (floatOneLoader.status === Loader.Ready)
z:0
//anchors.centerIn: parent
property string cSource: Filepath.stringToUrl(root.pathList[index].toString())
property int cId: root.idList[index]
onActiveChanged: {
if(active) {
setSource("FloatImage.qml", {
'isPanoViewer' : true,
'source': Qt.binding(function() { return cSource; }),
'index' : index,
'idView': Qt.binding(function() { return cId; }),
})
} else {
// Force the unload (instead of using Component.onCompleted to load it once and for all) is necessary since Qt 5.14
setSource("", {})
}
}
}
}
Repeater {
id: repeater
model: 0
delegate: imgPano
}
Connections {
target: root
onImagesDataChanged: {
//We receive the map<ImgPath, idView> from C++
//Resetting arrays to avoid problem with push
pathList = []
idList = []
//Iterating through the map
for (var path in imagesData) {
console.warn("Object item:", path, "=", imagesData[path])
root.pathList.push(path)
root.idList.push(imagesData[path])
}
console.warn(root.pathList.length)
//Changing the repeater model (number of elements)
panoImages.updateRepeater()
root.status = Image.Ready;
}
}
function updateRepeater() {
if(repeater.model !== root.pathList.length){
repeater.model = 0;
}
repeater.model = root.pathList.length;
}
}
}