ArcballController.qml 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. // Copyright (C) 2025 The Qt Company Ltd.
  2. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
  3. import QtQuick
  4. import QtQuick3D
  5. // The rotation math is based on the paper
  6. // ARCBALL:
  7. // A User Interface for Specifying Three-Dimensional Orientation Using a Mouse
  8. // by Ken Shoemake, 1992
  9. Item {
  10. id: root
  11. visible: false
  12. required property Node controlledObject
  13. property vector3d lastPos: Qt.vector3d(0, 0, 0)
  14. property bool moving: false
  15. // From Shoemake 1992:
  16. // pt.x <- (screen.x - center.x)/radius;
  17. // pt.y <- (screen.y - center.y)/radius;
  18. // r <- pt.x*pt.x + pt.y*pt.y;
  19. // IF r > 1.0
  20. // THEN s <- 1.0/Sqrt[r];
  21. // pt.x <- s*pt.x;
  22. // pt.y <- s*pt.y;
  23. // pt.z <- 0.0;
  24. // ELSE pt.z <- Sqrt[1.0 - r] ;
  25. function pos2DToPos3D(posNDC) {
  26. var pt = Qt.vector3d(posNDC.x, posNDC.y, 0)
  27. let r = posNDC.x * posNDC.x + posNDC.y * posNDC.y
  28. if (r > 1.0) {
  29. let s = 1.0 / Math.sqrt(r)
  30. pt.x = s * pt.x
  31. pt.y = s * pt.y
  32. pt.z = 0.0
  33. } else {
  34. pt.z = Math.sqrt(1.0 - r)
  35. }
  36. return pt
  37. }
  38. function mousePressed(posNDC) {
  39. lastPos = pos2DToPos3D(posNDC)
  40. moving = true
  41. }
  42. function mouseReleased(posNDC) {
  43. moving = false
  44. }
  45. function mouseMoved(posNDC) {
  46. if (!moving)
  47. return
  48. let currentPos = pos2DToPos3D(posNDC)
  49. // From Shoemake 1992:
  50. // [q.x, q.y, q.z] <- V3_Cross[pO, p1];
  51. // q.w <- V3_Dot[pO, p1];
  52. // qnow <- QuatMul[q, qstart];
  53. let p0 = lastPos
  54. let p1 = currentPos
  55. let p0p1 = p0.crossProduct(p1)
  56. let q = Qt.quaternion(p0.dotProduct(p1), p0p1.x, p0p1.y, p0p1.z)
  57. let qnow = q.times(controlledObject.rotation)
  58. controlledObject.rotation = qnow
  59. lastPos = currentPos
  60. }
  61. }