Skip to content

Commit

Permalink
Merge pull request #1707 from alicevision/dev/manipulatorPanorama
Browse files Browse the repository at this point in the history
Manipulator for panorama viewer
  • Loading branch information
fabiencastan authored Nov 3, 2022
2 parents 4911ec9 + 603b9df commit 78e2570
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 13 deletions.
97 changes: 96 additions & 1 deletion meshroom/ui/components/scene3D.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from math import acos, pi, sqrt
from math import acos, pi, sqrt, atan2, cos, sin, asin

from PySide2.QtCore import QObject, Slot, QSize, Signal, QPointF
from PySide2.Qt3DCore import Qt3DCore
Expand Down Expand Up @@ -109,6 +109,101 @@ class Transformations3DHelper(QObject):

# ---------- Exposed to QML ---------- #

@Slot(QVector3D, QVector3D, result=QQuaternion)
def rotationBetweenAandB(self, A, B):

A = A/A.length()
B = B/B.length()

# Get rotation matrix between 2 vectors
v = QVector3D.crossProduct(A, B)
s = v.length()
c = QVector3D.dotProduct(A, B)
return QQuaternion.fromAxisAndAngle(v / s, atan2(s, c) * 180 / pi)

@Slot(QVector3D, result=QVector3D)
def fromEquirectangular(self, vector):
return QVector3D(cos(vector.x()) * sin(vector.y()), sin(vector.x()), cos(vector.x()) * cos(vector.y()))

@Slot(QVector3D, result=QVector3D)
def toEquirectangular(self, vector):
return QVector3D(asin(vector.y()), atan2(vector.x(), vector.z()), 0)

@Slot(QVector3D, QVector2D, QVector2D, result=QVector3D)
def updatePanorama(self, euler, ptStart, ptEnd):

delta = 1e-3

#Get initial rotation
qStart = QQuaternion.fromEulerAngles(euler.y(), euler.x(), euler.z())

#Convert input to points on unit sphere
vStart = self.fromEquirectangular(QVector3D(ptStart))
vStartdY = self.fromEquirectangular(QVector3D(ptStart.x(), ptStart.y() + delta, 0))
vEnd = self.fromEquirectangular(QVector3D(ptEnd))

qAdd = QQuaternion.rotationTo(vStart, vEnd)


#Get the 3D point on unit sphere which would correspond to the no rotation +X
vCurrent = qAdd.rotatedVector(vStartdY)
vIdeal = self.fromEquirectangular(QVector3D(ptEnd.x(), ptEnd.y() + delta, 0))

#project on rotation plane
lambdaEnd = 1 / QVector3D.dotProduct(vEnd, vCurrent)
lambdaIdeal = 1 / QVector3D.dotProduct(vEnd, vIdeal)
vPlaneCurrent = lambdaEnd * vCurrent
vPlaneIdeal = lambdaIdeal * vIdeal

#Get the directions
rotStart = (vPlaneCurrent - vEnd).normalized()
rotEnd = (vPlaneIdeal - vEnd).normalized()

# Get rotation matrix between 2 vectors
v = QVector3D.crossProduct(rotEnd, rotStart)
s = QVector3D.dotProduct(v, vEnd)
c = QVector3D.dotProduct(rotStart, rotEnd)
angle = atan2(s, c) * 180 / pi

qImage = QQuaternion.fromAxisAndAngle(vEnd, -angle)

return (qImage * qAdd * qStart).toEulerAngles()

@Slot(QVector3D, QVector2D, QVector2D, result=QVector3D)
def updatePanoramaInPlane(self, euler, ptStart, ptEnd):

delta = 1e-3

#Get initial rotation
qStart = QQuaternion.fromEulerAngles(euler.y(), euler.x(), euler.z())

#Convert input to points on unit sphere
vStart = self.fromEquirectangular(QVector3D(ptStart))
vEnd = self.fromEquirectangular(QVector3D(ptEnd))

#Get the 3D point on unit sphere which would correspond to the no rotation +X
vIdeal = self.fromEquirectangular(QVector3D(ptStart.x(), ptStart.y() + delta, 0))

#project on rotation plane
lambdaEnd = 1 / QVector3D.dotProduct(vStart, vEnd)
lambdaIdeal = 1 / QVector3D.dotProduct(vStart, vIdeal)
vPlaneEnd = lambdaEnd * vEnd
vPlaneIdeal = lambdaIdeal * vIdeal

#Get the directions
rotStart = (vPlaneEnd - vStart).normalized()
rotEnd = (vPlaneIdeal - vStart).normalized()

# Get rotation matrix between 2 vectors
v = QVector3D.crossProduct(rotEnd, rotStart)
s = QVector3D.dotProduct(v, vStart)
c = QVector3D.dotProduct(rotStart, rotEnd)
angle = atan2(s, c) * 180 / pi

qAdd = QQuaternion.fromAxisAndAngle(vStart, angle)

return (qAdd * qStart).toEulerAngles()

@Slot(QVector4D, Qt3DRender.QCamera, QSize, result=QVector2D)
def pointFromWorldToScreen(self, point, camera, windowSize):
""" Compute the Screen point corresponding to a World Point.
Expand Down
57 changes: 45 additions & 12 deletions meshroom/ui/qml/Viewer/PanoramaViewer.qml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ AliceVision.PanoramaViewer {
property var xStart : 0
property var yStart : 0

property var previous_yaw: 0;
property var previous_pitch: 0;
property var previous_roll: 0;

property double yaw: 0;
property double pitch: 0;
property double roll: 0;
Expand Down Expand Up @@ -132,18 +136,43 @@ AliceVision.PanoramaViewer {

// Rotate Panorama
if (isRotating && isEditable) {
var xoffset = mouse.x - lastX;
var yoffset = mouse.y - lastY;
lastX = mouse.x;
lastY = mouse.y;

// Update Euler Angles
if (mouse.modifiers & Qt.AltModifier) {
root.roll = limitAngle(root.roll + toDegrees((xoffset / width) * mouseMultiplier))
}
else {
root.yaw = limitAngle(root.yaw + toDegrees((xoffset / width) * mouseMultiplier))
root.pitch = limitPitch(root.pitch + toDegrees(-(yoffset / height) * mouseMultiplier))

var nx = Math.max(0, mouse.x)
var nx = Math.min(width - 1, mouse.x)
var ny = Math.max(0, mouse.y)
var ny = Math.min(height - 1, mouse.y)

var xoffset = nx - lastX;
var yoffset = ny - lastY;

if (xoffset != 0 || yoffset !=0)
{
var latitude_start = (yStart / height) * Math.PI - (Math.PI / 2);
var longitude_start = ((xStart / width) * 2 * Math.PI) - Math.PI;
var latitude_end = (ny / height) * Math.PI - ( Math.PI / 2);
var longitude_end = ((nx / width) * 2 * Math.PI) - Math.PI;

var start_pt = Qt.vector2d(latitude_start, longitude_start)
var end_pt = Qt.vector2d(latitude_end, longitude_end)

var previous_euler = Qt.vector3d(previous_yaw, previous_pitch, previous_roll)

if (mouse.modifiers & Qt.ControlModifier)
{
var result = Transformations3DHelper.updatePanoramaInPlane(previous_euler, start_pt, end_pt)
root.pitch = result.x
root.yaw = result.y
root.roll = result.z
}
else
{
var result = Transformations3DHelper.updatePanorama(previous_euler, start_pt, end_pt)
root.pitch = result.x
root.yaw = result.y
root.roll = result.z
}


}

_reconstruction.setAttribute(activeNode.attribute("manualTransform.manualRotation.x"), Math.round(root.pitch));
Expand All @@ -160,6 +189,10 @@ AliceVision.PanoramaViewer {

xStart = mouse.x;
yStart = mouse.y;

previous_yaw = yaw;
previous_pitch = pitch;
previous_roll = roll;
}

onReleased: {
Expand Down

0 comments on commit 78e2570

Please sign in to comment.