1111
1212#include < glm/gtc/epsilon.hpp>
1313
14+ #include < QNativeGestureEvent>
1415#include < QPointF>
16+ #include < QTouchEvent>
1517
1618const MMapper::Array<RoomTintEnum, NUM_ROOM_TINTS> &getAllRoomTints ()
1719{
@@ -57,6 +59,12 @@ std::optional<glm::vec3> MapCanvasViewport::project(const glm::vec3 &v) const
5759//
5860// output: world coordinates.
5961glm::vec3 MapCanvasViewport::unproject_raw (const glm::vec3 &mouse_depth) const
62+ {
63+ return unproject_raw (mouse_depth, m_viewProj);
64+ }
65+
66+ glm::vec3 MapCanvasViewport::unproject_raw (const glm::vec3 &mouse_depth,
67+ const glm::mat4 &viewProj) const
6068{
6169 const float depth = mouse_depth.z ;
6270 assert (::isClamped (depth, 0 .f , 1 .f ));
@@ -67,7 +75,7 @@ glm::vec3 MapCanvasViewport::unproject_raw(const glm::vec3 &mouse_depth) const
6775 const glm::vec3 screen{screen2d, depth};
6876 const auto ndc = screen * 2 .f - 1 .f ;
6977
70- const auto tmp = glm::inverse (m_viewProj ) * glm::vec4 (ndc, 1 .f );
78+ const auto tmp = glm::inverse (viewProj ) * glm::vec4 (ndc, 1 .f );
7179 // clamp to avoid division by zero
7280 constexpr float limit = 1e-6f ;
7381 const auto w = (std::abs (tmp.w ) < limit) ? std::copysign (limit, tmp.w ) : tmp.w ;
@@ -79,12 +87,18 @@ glm::vec3 MapCanvasViewport::unproject_raw(const glm::vec3 &mouse_depth) const
7987// note: the returned coordinate may not be visible,
8088// because it could be
8189glm::vec3 MapCanvasViewport::unproject_clamped (const glm::vec2 &mouse) const
90+ {
91+ return unproject_clamped (mouse, m_viewProj);
92+ }
93+
94+ glm::vec3 MapCanvasViewport::unproject_clamped (const glm::vec2 &mouse,
95+ const glm::mat4 &viewProj) const
8296{
8397 const auto flayer = static_cast <float >(m_currentLayer);
8498 const auto &x = mouse.x ;
8599 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
100+ const auto a = unproject_raw (glm::vec3{x, y, 0 .f }, viewProj ); // near
101+ const auto b = unproject_raw (glm::vec3{x, y, 1 .f }, viewProj ); // far
88102 const float t = (flayer - a.z ) / (b.z - a.z );
89103 const auto result = glm::mix (a, b, std::clamp (t, 0 .f , 1 .f ));
90104 return glm::vec3{glm::vec2{result}, flayer};
@@ -93,13 +107,30 @@ glm::vec3 MapCanvasViewport::unproject_clamped(const glm::vec2 &mouse) const
93107glm::vec2 MapCanvasViewport::getMouseCoords (const QInputEvent *const event) const
94108{
95109 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 ());
110+ const auto x = static_cast <float >(mouse->position ().x ());
111+ const auto y = static_cast <float >(height () - mouse->position ().y ());
98112 return glm::vec2{x, y};
99113 } else if (const auto *const wheel = dynamic_cast <const QWheelEvent *>(event)) {
100114 const auto x = static_cast <float >(wheel->position ().x ());
101115 const auto y = static_cast <float >(height () - wheel->position ().y ());
102116 return glm::vec2{x, y};
117+ } else if (const auto *const gesture = dynamic_cast <const QNativeGestureEvent *>(event)) {
118+ const auto x = static_cast <float >(gesture->position ().x ());
119+ const auto y = static_cast <float >(height () - gesture->position ().y ());
120+ return glm::vec2{x, y};
121+ } else if (const auto *const touch = dynamic_cast <const QTouchEvent *>(event)) {
122+ const auto &points = touch->points ();
123+ if (points.isEmpty ()) {
124+ throw std::invalid_argument (" no touch points" );
125+ }
126+ QPointF centroid (0 , 0 );
127+ for (const auto &p : points) {
128+ centroid += p.position ();
129+ }
130+ centroid /= static_cast <qreal>(points.size ());
131+ const auto x = static_cast <float >(centroid.x ());
132+ const auto y = static_cast <float >(height () - centroid.y ());
133+ return glm::vec2{x, y};
103134 } else {
104135 throw std::invalid_argument (" event" );
105136 }
@@ -109,7 +140,16 @@ glm::vec2 MapCanvasViewport::getMouseCoords(const QInputEvent *const event) cons
109140// output is the world space intersection with the current layer
110141std::optional<glm::vec3> MapCanvasViewport::unproject (const QInputEvent *const event) const
111142{
112- const auto xy = getMouseCoords (event);
143+ try {
144+ const auto xy = getMouseCoords (event);
145+ return unproject (xy);
146+ } catch (const std::invalid_argument &) {
147+ return std::nullopt ;
148+ }
149+ }
150+
151+ std::optional<glm::vec3> MapCanvasViewport::unproject (const glm::vec2 &xy) const
152+ {
113153 // We don't actually know the depth we're trying to unproject;
114154 // technically we're solving for a ray, so we should unproject
115155 // two different depths and find where the ray intersects the
@@ -130,7 +170,17 @@ std::optional<glm::vec3> MapCanvasViewport::unproject(const QInputEvent *const e
130170
131171std::optional<MouseSel> MapCanvasViewport::getUnprojectedMouseSel (const QInputEvent *const event) const
132172{
133- const auto opt_v = unproject (event);
173+ try {
174+ const auto xy = getMouseCoords (event);
175+ return getUnprojectedMouseSel (xy);
176+ } catch (const std::invalid_argument &) {
177+ return std::nullopt ;
178+ }
179+ }
180+
181+ std::optional<MouseSel> MapCanvasViewport::getUnprojectedMouseSel (const glm::vec2 &xy) const
182+ {
183+ const auto opt_v = unproject (xy);
134184 if (!opt_v.has_value ()) {
135185 return std::nullopt ;
136186 }
0 commit comments