Skip to content

Commit

Permalink
[panoramaViewer] working manipulator for panoram
Browse files Browse the repository at this point in the history
  • Loading branch information
servantftechnicolor authored and fabiencastan committed Nov 3, 2022
1 parent a156b85 commit e754390
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 49 deletions.
97 changes: 81 additions & 16 deletions 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, atan2
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 @@ -114,31 +114,96 @@ 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)
M = QQuaternion.fromAxisAndAngle(v / s, atan2(s, c) * 180 / pi).toRotationMatrix()
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

x = QVector3D(M(0, 0), M(0, 1), M(0, 2))
y = QVector3D(M(1, 0), M(1, 1), M(1, 2))
z = QVector3D(M(2, 0), M(2, 1), M(2, 2))
#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))

fx = QVector3D(1, 0, 0)
y = QVector3D.crossProduct(z, x).normalized()
x = QVector3D.crossProduct(y, z).normalized()
z = QVector3D.crossProduct(x, y).normalized()
qAdd = QQuaternion.rotationTo(vStart, vEnd)

M = QMatrix3x3([x.x(), x.y(), x.z(), y.x(), y.y(), y.z(), z.x(), z.y(), z.z()])

return QQuaternion.fromRotationMatrix(M)
#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

@Slot(QQuaternion, float, float, float, result = QVector3D)
def updateEulers(self, quat, previous_pitch, previous_yaw, previous_roll):
qAdd = QQuaternion.fromAxisAndAngle(vStart, angle)

init = QQuaternion.fromEulerAngles(previous_pitch, previous_yaw, previous_roll)
return (quat * init).toEulerAngles()
return (qAdd * qStart).toEulerAngles()

@Slot(QVector4D, Qt3DRender.QCamera, QSize, result=QVector2D)
def pointFromWorldToScreen(self, point, camera, windowSize):
Expand Down
69 changes: 36 additions & 33 deletions meshroom/ui/qml/Viewer/PanoramaViewer.qml
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ AliceVision.PanoramaViewer {
property var xStart : 0
property var yStart : 0

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

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

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

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 Px_start = Math.cos(latitude_start) * Math.sin(longitude_start);
var Py_start = Math.sin(latitude_start);
var Pz_start = Math.cos(latitude_start) * Math.cos(longitude_start);

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 latitude_end = (ny / height) * Math.PI - ( Math.PI / 2);
var longitude_end = ((nx / width) * 2 * Math.PI) - Math.PI;
var Px_end = Math.cos(latitude_end) * Math.sin(longitude_end);
var Py_end = Math.sin(latitude_end);
var Pz_end = Math.cos(latitude_end) * Math.cos(longitude_end);

var A = Qt.vector3d(Px_start, Py_start, Pz_start)
var B = Qt.vector3d(Px_end, Py_end, Pz_end)

var quat = Transformations3DHelper.rotationBetweenAandB(A, B)

var result = Transformations3DHelper.updateEulers(quat, previous_pitch, previous_yaw, previous_roll)

root.pitch = result.x
root.yaw = result.y
root.roll = result.z

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 @@ -187,9 +190,9 @@ AliceVision.PanoramaViewer {
xStart = mouse.x;
yStart = mouse.y;

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

onReleased: {
Expand Down

0 comments on commit e754390

Please sign in to comment.