diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.cc index e63a75969..ba690ee99 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.cc @@ -164,60 +164,60 @@ camera_normal (const QMatrix4x4 &camera_trans, double x, double y) void normalize_scene_trans (const QMatrix4x4 &cam_trans, QVector3D &displacement, double &scale, double ztarget) { - QMatrix4x4 m; - // Here is the theory: // Let: // cam = ( M t ) M = 3x3 matrix, t = 3x1 translation vector, z = scalar, p = 1x3 perspective // ( p z ) // and: - // scene = ( S d ) S = s*U1 (s = scale factor, U1 = 3x3 unit matrix), d = 3x1 displacement vector - // ( 0 1 ) + // scene = ( S d*s ) S = s*U1 (s = scale factor, U1 = 3x3 unit matrix), d = 3x1 displacement vector + // ( 0 1 ) // then: - // cam * scene = ( M*s M*d+t ) - // ( p*s p*d+z ) (p*d = dot product) + // cam * scene = ( M*s M*d*s+t ) + // ( p*s p*d*s+z ) (p*d = dot product) // // this is image invariant (only x,y results are considered) against changes of s (s->s') if // - // 1.) (p*d+z)/s = (p*d'+z)/s' - // 2.) (M*d+t)/s = (M*d'+t)/s' for [x] and [y] + // 1.) (p*d*s+z)/s = (p*d'*s'+z)/s' (because x and y will be devided by this value) + // 2.) (M*d*s+t)/s = (M*d'*s'+t)/s' for [x] and [y] // - // Ff we seek a solution with d'[z] == b (b = ztarget), we get these equations (f:=s'/s) + // or // - // 2.) M[xx] * d'[x] + M[xy] * d'[y] - ((M*d)[x] + t[x]) * f = -t[x] - M[xz] * b - // M[yx] * d'[x] + M[yy] * d'[y] - ((M*d)[y] + t[y]) * f = -t[y] - M[yz] * b - // 1.) p[x] * d'[x] + p[y] * d'[y] - (p*d+z) * f = -z - p[z] * b + // 1.) p*d+z/s = p*d'+z/s' + // 2.) M*d+t/s = M*d'+t/s' + // + // If we seek a solution with d'[z] == b (b = ztarget), we get these equations (f:=1/s') + // + // 2.) M[xx] * d'[x] + M[xy] * d'[y] + t[x] * f = (M*d)[x] + t[x]/s - M[xz]*b + // M[yx] * d'[x] + M[yy] * d'[y] + t[y] * f = (M*d)[y] + t[y]/s - M[yz]*b + // 1.) p[x] * d'[x] + p[y] * d'[y] + z * f = p*d + z/s - p[z]*b // // we can solve these equations for d'[x], d'[y] and f. // With p[x]=M[wx], p[y]=M[wy] and z=t[w], the above equation system can be written as // - // M[ix] * d'[x] + M[iy] * d'[y] - ((M*d)[i] + t[i]) * f = -t[i] - M[iz]*b i = x,y,w - // - // and with M,t->M (4x4 matrix) and d->(d,1) (4d vector) - // - // M[ix] * d'[x] + M[iy] * d'[y] - (M*d)[i] * f = -t[i] - M[iz]*b i = x,y,w + // M[ix] * d'[x] + M[iy] * d'[y] + t[i] * f = (M*d)[i] - M[iz]*b + t[i]/s i = x,y,w // - QVector4D d4 (displacement); - d4.setW (1.0); + QMatrix4x4 m; for (int i = 0; i < 4; ++i) { if (i != 2) { m (i, 0) = cam_trans (i, 0); m (i, 1) = cam_trans (i, 1); - m (i, 3) = -QVector4D::dotProduct (cam_trans.row (i), d4); + m (i, 3) = cam_trans (i, 3); } } bool invertable = false; - m = m.inverted (&invertable); + QMatrix4x4 minv = m.inverted (&invertable); if (! invertable) { return; } - QVector4D sol = m.map (-cam_trans.column (3) - cam_trans.column (2) * ztarget); - if (sol.w () > 0.01 /*skip weird solutions*/) { - scale *= sol.w (); + QVector4D rhs = cam_trans.map (QVector4D (displacement.x (), displacement.y (), displacement.z () - ztarget, 1.0 / scale)); + QVector4D sol = minv.map (rhs); + double f = sol.w (); + if (f > 1e-6 /*skip weird solutions*/) { + scale = 1.0 / f; displacement = QVector3D (sol.x (), sol.y (), ztarget); } } diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc index ee173e776..5892e329a 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc @@ -201,7 +201,7 @@ D25ViewWidget::wheelEvent (QWheelEvent *event) // "Shift" is closeup double f = event->angleDelta ().y () * (1.0 / (90 * 8)); - m_displacement += -f * cam_position ().length () * ray.second; + m_displacement += -(f / m_scale_factor) * cam_position ().length () * ray.second; } else { @@ -212,7 +212,7 @@ D25ViewWidget::wheelEvent (QWheelEvent *event) QVector3D initial_displacement = m_displacement; QVector3D displacement = m_displacement; - displacement = hp * (1.0 - f) + displacement * f; + displacement += hp * (1.0 - f) / (f * m_scale_factor); m_scale_factor *= f; // normalize the scene translation so the scene does not "flee" @@ -251,7 +251,7 @@ D25ViewWidget::keyReleaseEvent (QKeyEvent *event) QVector3D D25ViewWidget::hit_point_with_scene (const QVector3D &line, const QVector3D &line_dir) { - QVector3D corner = QVector3D (m_bbox.left (), m_zmin, -(m_bbox.bottom () + m_bbox.height ())) * m_scale_factor + m_displacement; + QVector3D corner = (QVector3D (m_bbox.left (), m_zmin, -(m_bbox.bottom () + m_bbox.height ())) + m_displacement) * m_scale_factor; QVector3D dim = QVector3D (m_bbox.width (), m_zmax - m_zmin, m_bbox.height ()) * m_scale_factor; std::pair hp = lay::hit_point_with_cuboid (line, line_dir, corner, dim); @@ -314,7 +314,7 @@ D25ViewWidget::mouseMoveEvent (QMouseEvent *event) QVector3D yv (-re * xv.z (), cos (cam_elevation () * M_PI / 180.0), re * xv.x ()); QVector3D drag = xv * dx + yv * dy; - m_displacement = m_start_displacement + drag; + m_displacement = m_start_displacement + drag / m_scale_factor; update_cam_trans (); @@ -355,7 +355,7 @@ D25ViewWidget::cam_direction () const QVector3D D25ViewWidget::cam_position () const { - double focus_dist = 4.0; + double focus_dist = 4.0; // @@@ return cam_direction () * -focus_dist; } @@ -374,8 +374,10 @@ D25ViewWidget::cam_elevation () const QMatrix4x4 D25ViewWidget::cam_perspective () const { + double focus_dist = 4.0; // @@@ QMatrix4x4 t; t.perspective (60.0f, float (width ()) / float (height ()), 0.1f, 100.0f); + t.translate (QVector3D (0.0, 0.0, -focus_dist)); return t; } @@ -385,7 +387,6 @@ D25ViewWidget::cam_trans () const QMatrix4x4 t; t.rotate (-cam_elevation (), 1.0, 0.0, 0.0); t.rotate (cam_azimuth (), 0.0, 1.0, 0.0); - t.translate (-cam_position ()); return t; } @@ -649,9 +650,9 @@ D25ViewWidget::paintGL () QMatrix4x4 scene_trans; - // provide the displacement and scaling - scene_trans.translate (m_displacement); + // provide the displacement and scaling (in this order!) scene_trans.scale (m_scale_factor); + scene_trans.translate (m_displacement); // this way we can use y as z coordinate when drawing scene_trans.scale (1.0, 1.0, -1.0); diff --git a/src/plugins/tools/view_25d/unit_tests/layD25ViewUtilsTests.cc b/src/plugins/tools/view_25d/unit_tests/layD25ViewUtilsTests.cc index 4d9daa5b6..b24265b22 100644 --- a/src/plugins/tools/view_25d/unit_tests/layD25ViewUtilsTests.cc +++ b/src/plugins/tools/view_25d/unit_tests/layD25ViewUtilsTests.cc @@ -176,11 +176,11 @@ TEST(6_NormalizeSceneTrans) cam.translate (QVector3D (0.0, 0.0, 4.0)); double scale = 0.1; - QVector3D displacement (-0.5, 0.2, 2.0); + QVector3D displacement (-5.0, 2.0, 20.0); QMatrix4x4 scene1; - scene1.translate (displacement); scene1.scale (scale); + scene1.translate (displacement); QVector3D v1 = (cam * scene1).map (QVector3D (1.0, -1.0, 2.0)); v1.setZ (0); @@ -192,8 +192,8 @@ TEST(6_NormalizeSceneTrans) lay::normalize_scene_trans (cam, displacement, scale); QMatrix4x4 scene2; - scene2.translate (displacement); scene2.scale (scale); + scene2.translate (displacement); EXPECT_EQ (tl::sprintf ("%.4f", scale), "0.0667"); @@ -208,14 +208,14 @@ TEST(6_NormalizeSceneTrans) EXPECT_EQ ((u2 - v2).length () < 1e-4, true); EXPECT_EQ ((u3 - v3).length () < 1e-4, true); - lay::normalize_scene_trans (cam, displacement, scale, 1.0); + lay::normalize_scene_trans (cam, displacement, scale, 10.0); QMatrix4x4 scene3; - scene3.translate (displacement); scene3.scale (scale); + scene3.translate (displacement); - EXPECT_EQ (tl::sprintf ("%.4f", scale), "0.0833"); - EXPECT_EQ (tl::to_string (displacement.z ()), "1"); + EXPECT_EQ (tl::sprintf ("%.4f", scale), "0.0800"); + EXPECT_EQ (tl::to_string (displacement.z ()), "10"); QVector3D uu1 = (cam * scene2).map (QVector3D (1.0, -1.0, 2.0)); uu1.setZ (0);