Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ui] Viewer2D: various orientation fixes #2212

Merged
merged 4 commits into from
Oct 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 73 additions & 77 deletions meshroom/ui/qml/Viewer/CircleGizmo.qml
Original file line number Diff line number Diff line change
@@ -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
}
*/
}
3 changes: 1 addition & 2 deletions meshroom/ui/qml/Viewer/ColorCheckerEntity.qml
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand Down
11 changes: 3 additions & 8 deletions meshroom/ui/qml/Viewer/ColorCheckerViewer.qml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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

Expand All @@ -27,7 +22,6 @@ Item {
onViewpointChanged: { loadCCheckers(); }
property var updatePane: null


function getColors() {
if (ccheckers[selectedCChecker] === undefined)
return null;
Expand Down Expand Up @@ -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;
Expand All @@ -98,5 +94,4 @@ Item {
ccheckers = [];
selectedCChecker = -1;
}

}
54 changes: 29 additions & 25 deletions meshroom/ui/qml/Viewer/Viewer2D.qml
Original file line number Diff line number Diff line change
Expand Up @@ -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])
);
}
}
Expand All @@ -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: {
Expand All @@ -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

Expand Down