diff --git a/meshroom/ui/qml/Viewer/CircleGizmo.qml b/meshroom/ui/qml/Viewer/CircleGizmo.qml index 644efb279e..ff072f728b 100644 --- a/meshroom/ui/qml/Viewer/CircleGizmo.qml +++ b/meshroom/ui/qml/Viewer/CircleGizmo.qml @@ -1,100 +1,96 @@ import QtQuick 2.15 -Rectangle { +Item { id: root property bool readOnly: false - signal moved() + signal moved(real xoffset, real yoffset) signal incrementRadius(real radiusOffset) - width: radius * 2 - height: width - color: "transparent" - border.width: 5 - border.color: readOnly ? "green" : "yellow" - - /* - // visualize top-left corner for debugging purpose - Rectangle { - color: "red" - width: 500 - height: 50 - } + // Circle + property real circleX: 0. + property real circleY: 0. Rectangle { - color: "red" - width: 50 - height: 500 - } - */ - // Cross to visualize the circle center - Rectangle { - color: parent.border.color - anchors.centerIn: parent - width: parent.width * 0.2 - height: parent.border.width * 0.5 - } - Rectangle { - color: parent.border.color - anchors.centerIn: parent - width: parent.border.width * 0.5 - height: parent.height * 0.2 - } + id: circle - Behavior on x { - NumberAnimation { - duration: 100 - } - } + width: radius * 2 + height: width - Behavior on y { - NumberAnimation { - duration: 100 - } - } + x: circleX + (root.width - width) / 2 + y: circleY + (root.height - height) / 2 - Behavior on radius { - NumberAnimation { - duration: 100 - } - } + color: "transparent" + border.width: 5 + border.color: readOnly ? "green" : "yellow" - Loader { - anchors.fill: parent - active: !root.readOnly + // Cross to visualize the circle center + Rectangle { + color: parent.border.color + anchors.centerIn: parent + width: parent.width * 0.2 + height: parent.border.width * 0.5 + } + Rectangle { + color: parent.border.color + anchors.centerIn: parent + width: parent.border.width * 0.5 + height: parent.height * 0.2 + } - sourceComponent: MouseArea { - id: mArea + Loader { anchors.fill: parent - cursorShape: root.readOnly ? Qt.ArrowCursor : (controlModifierEnabled ? Qt.SizeBDiagCursor : (pressed ? Qt.ClosedHandCursor : Qt.OpenHandCursor)) - propagateComposedEvents: true + active: !root.readOnly - property bool controlModifierEnabled: false - onPositionChanged: { - mArea.controlModifierEnabled = (mouse.modifiers & Qt.ControlModifier) - mouse.accepted = false; - } - acceptedButtons: Qt.LeftButton - hoverEnabled: true - drag.target: root + sourceComponent: MouseArea { + id: mArea + anchors.fill: parent + cursorShape: root.readOnly ? Qt.ArrowCursor : (controlModifierEnabled ? Qt.SizeBDiagCursor : (pressed ? Qt.ClosedHandCursor : Qt.OpenHandCursor)) + propagateComposedEvents: true - drag.onActiveChanged: { - if(!drag.active) { - moved(); + property bool controlModifierEnabled: false + onPositionChanged: { + mArea.controlModifierEnabled = (mouse.modifiers & Qt.ControlModifier) + mouse.accepted = false; } - } - onPressed: { - forceActiveFocus(); - } - onWheel: { - mArea.controlModifierEnabled = (wheel.modifiers & Qt.ControlModifier) - if (wheel.modifiers & Qt.ControlModifier) { - incrementRadius(wheel.angleDelta.y / 120.0); - wheel.accepted = true; - } else { - wheel.accepted = false; + acceptedButtons: Qt.LeftButton + hoverEnabled: true + drag.target: circle + + drag.onActiveChanged: { + if(!drag.active) { + root.moved(circle.x - (root.width - circle.width) / 2, circle.y - (root.height - circle.height) / 2); + } + } + onPressed: { + forceActiveFocus(); + } + onWheel: { + mArea.controlModifierEnabled = (wheel.modifiers & Qt.ControlModifier) + if (wheel.modifiers & Qt.ControlModifier) { + root.incrementRadius(wheel.angleDelta.y / 120.0); + wheel.accepted = true; + } else { + wheel.accepted = false; + } } } } } + property alias circleRadius: circle.radius + property alias circleBorder: circle.border + + /* + // visualize top-left corner for debugging purpose + Rectangle { + color: "red" + width: 500 + height: 50 + } + Rectangle { + color: "red" + width: 50 + height: 500 + } + */ } diff --git a/meshroom/ui/qml/Viewer/ColorCheckerEntity.qml b/meshroom/ui/qml/Viewer/ColorCheckerEntity.qml index fb57de0e8d..a9811dff09 100644 --- a/meshroom/ui/qml/Viewer/ColorCheckerEntity.qml +++ b/meshroom/ui/qml/Viewer/ColorCheckerEntity.qml @@ -31,8 +31,7 @@ Item { } - function transform(matrix) { - var m = matrix + function applyTransform(m) { transformation.matrix = Qt.matrix4x4( m[0][0], m[0][1], 0, m[0][2], m[1][0], m[1][1], 0, m[1][2], diff --git a/meshroom/ui/qml/Viewer/ColorCheckerViewer.qml b/meshroom/ui/qml/Viewer/ColorCheckerViewer.qml index c173b0da6c..8b51aa5bdc 100644 --- a/meshroom/ui/qml/Viewer/ColorCheckerViewer.qml +++ b/meshroom/ui/qml/Viewer/ColorCheckerViewer.qml @@ -5,7 +5,6 @@ Item { property url source: undefined property var json: null - property var image: null property var viewpoint: null property real zoom: 1.0 @@ -15,10 +14,6 @@ Item { readonly property real ccheckerSizeX: 1675.0 readonly property real ccheckerSizeY: 1125.0 - // offset the cchecker top left corner to match the image top left corner - x: -image.width / 2 + ccheckerSizeX / 2 - y: -image.height / 2 + ccheckerSizeY / 2 - property var ccheckers: [] property int selectedCChecker: -1 @@ -27,7 +22,6 @@ Item { onViewpointChanged: { loadCCheckers(); } property var updatePane: null - function getColors() { if (ccheckers[selectedCChecker] === undefined) return null; @@ -79,11 +73,13 @@ Item { var cpt = Qt.createComponent("ColorCheckerEntity.qml"); var obj = cpt.createObject(root, { + x: ccheckerSizeX / 2, + y: ccheckerSizeY / 2, sizeX: root.ccheckerSizeX, sizeY: root.ccheckerSizeY, colors: root.json.checkers[i].colors }); - obj.transform(root.json.checkers[i].transform); + obj.applyTransform(root.json.checkers[i].transform); ccheckers.push(obj); selectedCChecker = ccheckers.length-1; break; @@ -98,5 +94,4 @@ Item { ccheckers = []; selectedCChecker = -1; } - } diff --git a/meshroom/ui/qml/Viewer/Viewer2D.qml b/meshroom/ui/qml/Viewer/Viewer2D.qml index 9dfc0ad6bc..958a134a39 100644 --- a/meshroom/ui/qml/Viewer/Viewer2D.qml +++ b/meshroom/ui/qml/Viewer/Viewer2D.qml @@ -611,23 +611,27 @@ FocusScope { active: (displayFisheyeCircleLoader.checked && activeNode) sourceComponent: CircleGizmo { + width: imgContainer.width + height: imgContainer.height + property bool useAuto: activeNode.attribute("estimateFisheyeCircle").value readOnly: useAuto visible: (!useAuto) || activeNode.isComputed property real userFisheyeRadius: activeNode.attribute("fisheyeRadius").value property variant fisheyeAutoParams: _reconstruction.getAutoFisheyeCircle(activeNode) - x: useAuto ? fisheyeAutoParams.x : activeNode.attribute("fisheyeCenterOffset.fisheyeCenterOffset_x").value - y: useAuto ? fisheyeAutoParams.y : activeNode.attribute("fisheyeCenterOffset.fisheyeCenterOffset_y").value - radius: useAuto ? fisheyeAutoParams.z : ((imgContainer.image ? Math.min(imgContainer.image.width, imgContainer.image.height) : 1.0) * 0.5 * (userFisheyeRadius * 0.01)) + circleX: useAuto ? fisheyeAutoParams.x : activeNode.attribute("fisheyeCenterOffset.fisheyeCenterOffset_x").value + circleY: useAuto ? fisheyeAutoParams.y : activeNode.attribute("fisheyeCenterOffset.fisheyeCenterOffset_y").value + + circleRadius: useAuto ? fisheyeAutoParams.z : ((imgContainer.image ? Math.min(imgContainer.image.width, imgContainer.image.height) : 1.0) * 0.5 * (userFisheyeRadius * 0.01)) - border.width: Math.max(1, (3.0 / imgContainer.scale)) + circleBorder.width: Math.max(1, (3.0 / imgContainer.scale)) onMoved: { if(!useAuto) { _reconstruction.setAttribute( activeNode.attribute("fisheyeCenterOffset"), - JSON.stringify([x, y]) + JSON.stringify([xoffset, yoffset]) ); } } @@ -641,33 +645,29 @@ FocusScope { } // LightingCalibration: display circle - // note: use a Loader to evaluate if a PanoramaInit node exist and displayFisheyeCircle checked at runtime - Loader { + ExifOrientedViewer { anchors.centerIn: parent + orientationTag: imgContainer.orientationTag + xOrigin: imgContainer.width / 2 + yOrigin: imgContainer.height / 2 property var activeNode: _reconstruction.activeNodes.get("SphereDetection").node active: (displayLightingCircleLoader.checked && activeNode) - // handle rotation/position based on available metadata - rotation: { - var orientation = m.imgMetadata ? m.imgMetadata["Orientation"] : 0 - switch(orientation) { - case "6": return 90; - case "8": return -90; - default: return 0; - } - } - sourceComponent: CircleGizmo { + width: imgContainer.width + height: imgContainer.height + readOnly: false - x: activeNode.attribute("sphereCenter.x").value - y: activeNode.attribute("sphereCenter.y").value - radius: activeNode.attribute("sphereRadius").value - border.width: Math.max(1, (3.0 / imgContainer.scale)) + circleX: activeNode.attribute("sphereCenter.x").value + circleY: activeNode.attribute("sphereCenter.y").value + circleRadius: activeNode.attribute("sphereRadius").value + + circleBorder.width: Math.max(1, (3.0 / imgContainer.scale)) onMoved: { _reconstruction.setAttribute( activeNode.attribute("sphereCenter"), - JSON.stringify([x, y]) + JSON.stringify([xoffset, yoffset]) ); } onIncrementRadius: { @@ -678,17 +678,21 @@ FocusScope { // ColorCheckerViewer: display color checker detection results // note: use a Loader to evaluate if a ColorCheckerDetection node exist and displayColorChecker checked at runtime - Loader { + ExifOrientedViewer { id: colorCheckerViewerLoader anchors.centerIn: parent + orientationTag: imgContainer.orientationTag + xOrigin: imgContainer.width / 2 + yOrigin: imgContainer.height / 2 property var activeNode: _reconstruction ? _reconstruction.activeNodes.get("ColorCheckerDetection").node : null active: (displayColorCheckerViewerLoader.checked && activeNode) - sourceComponent: ColorCheckerViewer { + width: imgContainer.width + height: imgContainer.height + visible: activeNode.isComputed && json !== undefined && imgContainer.image.status === Image.Ready source: Filepath.stringToUrl(activeNode.attribute("outputData").value) - image: imgContainer.image viewpoint: _reconstruction.selectedViewpoint zoom: imgContainer.scale