66
77#include " ../opengl/LineRendering.h"
88
9+ #include < cassert>
910#include < cmath>
1011#include < optional>
1112
1213#include < glm/gtc/epsilon.hpp>
1314
15+ #include < QDebug>
16+ #include < QNativeGestureEvent>
1417#include < QPointF>
18+ #include < QTouchEvent>
1519
1620const MMapper::Array<RoomTintEnum, NUM_ROOM_TINTS> &getAllRoomTints ()
1721{
@@ -57,6 +61,12 @@ std::optional<glm::vec3> MapCanvasViewport::project(const glm::vec3 &v) const
5761//
5862// output: world coordinates.
5963glm::vec3 MapCanvasViewport::unproject_raw (const glm::vec3 &mouse_depth) const
64+ {
65+ return unproject_raw (mouse_depth, m_viewProj);
66+ }
67+
68+ glm::vec3 MapCanvasViewport::unproject_raw (const glm::vec3 &mouse_depth,
69+ const glm::mat4 &viewProj) const
6070{
6171 const float depth = mouse_depth.z ;
6272 assert (::isClamped (depth, 0 .f , 1 .f ));
@@ -67,7 +77,7 @@ glm::vec3 MapCanvasViewport::unproject_raw(const glm::vec3 &mouse_depth) const
6777 const glm::vec3 screen{screen2d, depth};
6878 const auto ndc = screen * 2 .f - 1 .f ;
6979
70- const auto tmp = glm::inverse (m_viewProj ) * glm::vec4 (ndc, 1 .f );
80+ const auto tmp = glm::inverse (viewProj ) * glm::vec4 (ndc, 1 .f );
7181 // clamp to avoid division by zero
7282 constexpr float limit = 1e-6f ;
7383 const auto w = (std::abs (tmp.w ) < limit) ? std::copysign (limit, tmp.w ) : tmp.w ;
@@ -79,29 +89,54 @@ glm::vec3 MapCanvasViewport::unproject_raw(const glm::vec3 &mouse_depth) const
7989// note: the returned coordinate may not be visible,
8090// because it could be
8191glm::vec3 MapCanvasViewport::unproject_clamped (const glm::vec2 &mouse) const
92+ {
93+ return unproject_clamped (mouse, m_viewProj);
94+ }
95+
96+ glm::vec3 MapCanvasViewport::unproject_clamped (const glm::vec2 &mouse,
97+ const glm::mat4 &viewProj) const
8298{
8399 const auto flayer = static_cast <float >(m_currentLayer);
84100 const auto &x = mouse.x ;
85101 const auto &y = mouse.y ;
86- const auto a = unproject_raw (glm::vec3{x, y, 0 .f }); // near
87- const auto b = unproject_raw (glm::vec3{x, y, 1 .f }); // far
102+ const auto a = unproject_raw (glm::vec3{x, y, 0 .f }, viewProj ); // near
103+ const auto b = unproject_raw (glm::vec3{x, y, 1 .f }, viewProj ); // far
88104 const float t = (flayer - a.z ) / (b.z - a.z );
89105 const auto result = glm::mix (a, b, std::clamp (t, 0 .f , 1 .f ));
90106 return glm::vec3{glm::vec2{result}, flayer};
91107}
92108
93- glm::vec2 MapCanvasViewport::getMouseCoords (const QInputEvent *const event) const
109+ std::optional< glm::vec2> MapCanvasViewport::getMouseCoords (const QInputEvent *const event) const
94110{
95111 if (const auto *const mouse = dynamic_cast <const QMouseEvent *>(event)) {
96- const auto x = static_cast <float >(mouse->pos ().x ());
97- const auto y = static_cast <float >(height () - mouse->pos ().y ());
112+ const auto x = static_cast <float >(mouse->position ().x ());
113+ const auto y = static_cast <float >(height () - mouse->position ().y ());
98114 return glm::vec2{x, y};
99115 } else if (const auto *const wheel = dynamic_cast <const QWheelEvent *>(event)) {
100116 const auto x = static_cast <float >(wheel->position ().x ());
101117 const auto y = static_cast <float >(height () - wheel->position ().y ());
102118 return glm::vec2{x, y};
119+ } else if (const auto *const gesture = dynamic_cast <const QNativeGestureEvent *>(event)) {
120+ const auto x = static_cast <float >(gesture->position ().x ());
121+ const auto y = static_cast <float >(height () - gesture->position ().y ());
122+ return glm::vec2{x, y};
123+ } else if (const auto *const touch = dynamic_cast <const QTouchEvent *>(event)) {
124+ const auto &points = touch->points ();
125+ if (points.isEmpty ()) {
126+ return std::nullopt ;
127+ }
128+ QPointF centroid (0 , 0 );
129+ for (const auto &p : points) {
130+ centroid += p.position ();
131+ }
132+ centroid /= static_cast <qreal>(points.size ());
133+ const auto x = static_cast <float >(centroid.x ());
134+ const auto y = static_cast <float >(height () - centroid.y ());
135+ return glm::vec2{x, y};
103136 } else {
104- throw std::invalid_argument (" event" );
137+ qWarning () << " MapCanvasViewport::getMouseCoords: unhandled event type" << event->type ();
138+ assert (false );
139+ return std::nullopt ;
105140 }
106141}
107142
@@ -110,6 +145,14 @@ glm::vec2 MapCanvasViewport::getMouseCoords(const QInputEvent *const event) cons
110145std::optional<glm::vec3> MapCanvasViewport::unproject (const QInputEvent *const event) const
111146{
112147 const auto xy = getMouseCoords (event);
148+ if (!xy) {
149+ return std::nullopt ;
150+ }
151+ return unproject (*xy);
152+ }
153+
154+ std::optional<glm::vec3> MapCanvasViewport::unproject (const glm::vec2 &xy) const
155+ {
113156 // We don't actually know the depth we're trying to unproject;
114157 // technically we're solving for a ray, so we should unproject
115158 // two different depths and find where the ray intersects the
@@ -130,7 +173,16 @@ std::optional<glm::vec3> MapCanvasViewport::unproject(const QInputEvent *const e
130173
131174std::optional<MouseSel> MapCanvasViewport::getUnprojectedMouseSel (const QInputEvent *const event) const
132175{
133- const auto opt_v = unproject (event);
176+ const auto xy = getMouseCoords (event);
177+ if (!xy) {
178+ return std::nullopt ;
179+ }
180+ return getUnprojectedMouseSel (*xy);
181+ }
182+
183+ std::optional<MouseSel> MapCanvasViewport::getUnprojectedMouseSel (const glm::vec2 &xy) const
184+ {
185+ const auto opt_v = unproject (xy);
134186 if (!opt_v.has_value ()) {
135187 return std::nullopt ;
136188 }
0 commit comments