Repository: JuliaPlots/Makie.jl (julia)

Issue:
New cam3d! and scale! issue
Since `Makie@0.15.0` the example at https://github.com/JuliaPlots/Makie.jl/issues/1115#issuecomment-879070279 stopped working:

1. `scale!` doesn't scale the axis labels and ticks anymore:
![bug](https://user-images.githubusercontent.com/13423344/126064293-acf0956d-771d-471d-8c5e-f8ba0d4239ad.png)

2. new `cam3d!` with `projectiontype=Makie.Orthographic` behaves badly (without the `scale!` in the previous example): I'm trying to un-zoom and drag the scene but it obviously fails (whereas using `old_cam3d!` or `projectiontype=Makie.Perspective` is OK):
![bug](https://user-images.githubusercontent.com/13423344/126064805-a916f321-86dd-46b2-b291-47339fc71715.gif)

Pull request:
This should make `Camera3D(scene, projectiontype=Orthographic)` pixel perfect in terms of translations. Also fixes the initial zoom level.

Fix https://github.com/JuliaPlots/Makie.jl/issues/1142.

Patch:
diff --git a/src/camera/camera3d.jl b/src/camera/camera3d.jl
index 6bc5db478ff..b7ba59ca0b1 100644
--- a/src/camera/camera3d.jl
+++ b/src/camera/camera3d.jl
@@ -119,7 +119,7 @@ function Camera3D(scene; kwargs...)
             keyboard_translationspeed = 0.5f0,
             keyboard_zoomspeed = 1f0,
             mouse_rotationspeed = 1f0,
-            mouse_translationspeed = 0.2f0,
+            mouse_translationspeed = 1f0,
             mouse_zoomspeed = 1f0,
             circular_rotation = (true, true, true),
             fov = 45f0, # base fov
@@ -239,6 +239,17 @@ function add_translation!(scene, cam::Camera3D)
     last_mousepos = RefValue(Vec2f0(0, 0))
     dragging = RefValue(false)
 
+    function compute_diff(delta)
+        if cam.attributes[:projectiontype][] == Orthographic
+            aspect = Float32((/)(widths(scene.px_area[])...))
+            aspect_scale = Vec2f0(1f0 + aspect, 1f0 + 1f0 / aspect)
+            return cam.zoom_mult[] * delta .* aspect_scale ./ widths(scene.px_area[])
+        else
+            viewdir = cam.lookat[] - cam.eyeposition[]
+            return 0.002f0 * cam.zoom_mult[] * norm(viewdir) * delta
+        end
+    end
+
     # drag start/stop
     on(camera(scene), scene.events.mousebutton) do event
         if event.button == button[]
@@ -248,11 +259,10 @@ function add_translation!(scene, cam::Camera3D)
                 return Consume(true)
             elseif event.action == Mouse.release && dragging[]
                 mousepos = mouseposition_px(scene)
-                dragging[] = false
-                diff = (last_mousepos[] - mousepos) * 0.01f0 * translationspeed[]
+                diff = compute_diff(last_mousepos[] - mousepos)
                 last_mousepos[] = mousepos
-                viewdir = cam.lookat[] - cam.eyeposition[]
-                translate_cam!(scene, cam, cam.zoom_mult[] * norm(viewdir) * Vec3f0(diff[1], diff[2], 0f0))
+                dragging[] = false
+                translate_cam!(scene, cam, translationspeed[] * Vec3f0(diff[1], diff[2], 0f0))
                 update_cam!(scene, cam)
                 return Consume(true)
             end
@@ -264,10 +274,9 @@ function add_translation!(scene, cam::Camera3D)
     on(camera(scene), scene.events.mouseposition) do mp
         if dragging[] && ispressed(scene, button[]) && ispressed(scene, mod[])
             mousepos = screen_relative(scene, mp)
-            diff = (last_mousepos[] .- mousepos) * 0.01f0 * translationspeed[]
+            diff = compute_diff(last_mousepos[] - mousepos)
             last_mousepos[] = mousepos
-            viewdir = cam.lookat[] - cam.eyeposition[]
-            translate_cam!(scene, cam, cam.zoom_mult[] * norm(viewdir) * Vec3f0(diff[1], diff[2], 0f0))
+            translate_cam!(scene, cam, translationspeed[] * Vec3f0(diff[1], diff[2], 0f0))
             update_cam!(scene, cam)
             return Consume(true)
         end
@@ -276,7 +285,6 @@ function add_translation!(scene, cam::Camera3D)
 
     on(camera(scene), scene.events.scroll) do scroll
         if is_mouseinside(scene) && ispressed(scene, mod[])
-            cam_res = Vec2f0(widths(scene.px_area[]))
             zoom_step = (1f0 + 0.1f0 * zoomspeed[]) ^ -scroll[2]
             zoom!(scene, cam, zoom_step, shift_lookat[], cad[])
             update_cam!(scene, cam)
@@ -402,11 +410,12 @@ function translate_cam!(scene, cam, t)
     # x expands right, y expands up and z expands towards the screen
     lookat = cam.lookat[]
     eyepos = cam.eyeposition[]
-    up = cam.upvector[]         # +y
-    viewdir = lookat - eyepos   # -z
-    right = cross(viewdir, up)  # +x
+    up = normalize(cam.upvector[])
+    u_z = normalize(eyepos - lookat)
+    u_x = normalize(cross(up, u_z))
+    u_y = normalize(cross(u_z, u_x))
 
-    trans = normalize(right) * t[1] + normalize(up) * t[2] - normalize(viewdir) * t[3]
+    trans = u_x * t[1] + u_y * t[2] + u_z * t[3]
 
     # apply world space restrictions
     fix_x = ispressed(scene, cam.attributes[:fix_x_key][])
@@ -498,22 +507,32 @@ function zoom!(scene::Scene, cam::Camera3D, zoom_step, shift_lookat = false, cad
         shifted = eyepos + 0.1f0 * sign(1f0 - zoom_step) * norm(viewdir) * shift
         cam.eyeposition[] = lookat + norm(viewdir) * normalize(shifted - lookat)
     elseif shift_lookat
-        # translate both eyeposition and lookat to more or less keep data under
-        # the mouse in view
         lookat = cam.lookat[]
         eyepos = cam.eyeposition[]
-        up = cam.upvector[]         # +y
-        viewdir = lookat - eyepos   # -z
-        right = cross(viewdir, up)  # +x
-
-        fov = cam.attributes[:fov][]
-        before = tan(clamp(cam.zoom_mult[] * fov, 0.01f0, 175f0) / 360f0 * Float32(pi))
-        after  = tan(clamp(cam.zoom_mult[] * zoom_step * fov, 0.01f0, 175f0) / 360f0 * Float32(pi))
-
-        aspect = Float32((/)(widths(scene.px_area[])...))
-        rel_pos = 2f0 * mouseposition_px(scene) ./ widths(scene.px_area[]) .- 1f0
-        shift = rel_pos[1] * normalize(right) + rel_pos[2] * normalize(up)
-        shift = -(after - before) * norm(viewdir) * normalize(aspect .* shift)
+        up = normalize(cam.upvector[])
+        viewdir = lookat - eyepos
+        u_z = normalize(-viewdir)
+        u_x = normalize(cross(up, u_z))
+        u_y = normalize(cross(u_z, u_x))
+
+        if cam.attributes[:projectiontype][] == Perspective
+            # translate both eyeposition and lookat to more or less keep data 
+            # under the mouse in view
+            fov = cam.attributes[:fov][]
+            before = tan(clamp(cam.zoom_mult[] * fov, 0.01f0, 175f0) / 360f0 * Float32(pi))
+            after  = tan(clamp(cam.zoom_mult[] * zoom_step * fov, 0.01f0, 175f0) / 360f0 * Float32(pi))
+
+            aspect = Float32((/)(widths(scene.px_area[])...))
+            rel_pos = 2f0 * mouseposition_px(scene) ./ widths(scene.px_area[]) .- 1f0
+            shift = rel_pos[1] * u_x + rel_pos[2] * u_y
+            shift = -(after - before) * norm(viewdir) * normalize(aspect .* shift)
+        else
+            mx, my = 2f0 * mouseposition_px(scene) ./ widths(scene.px_area[]) .- 1f0
+            aspect = Float32((/)(widths(scene.px_area[])...))
+            w = 0.5f0 * (1f0 + aspect) * cam.zoom_mult[]
+            h = 0.5f0 * (1f0 + 1f0 / aspect) * cam.zoom_mult[]
+            shift = (1f0 - zoom_step) * (mx * w * u_x + my * h * u_y)
+        end
 
         cam.lookat[]      = lookat + shift
         cam.eyeposition[] = eyepos + shift
@@ -555,7 +574,6 @@ function update_cam!(scene::Scene, camera::Camera3D, area3d::Rect)
     bb = FRect3D(area3d)
     width = widths(bb)
     half_width = width/2f0
-    lower_corner = minimum(bb)
     middle = maximum(bb) - half_width
     old_dir = normalize(eyeposition .- lookat)
     camera.lookat[] = middle
@@ -568,7 +586,11 @@ function update_cam!(scene::Scene, camera::Camera3D, area3d::Rect)
     if camera.attributes[:far][] === automatic
         camera.far[]  = 3f0 * norm(widths(bb))
     end
-    camera.zoom_mult[] = 1f0
+    if camera.attributes[:projectiontype][] == Orthographic
+        camera.zoom_mult[] = 0.6 * norm(width)
+    else 
+        camera.zoom_mult[] = 1f0
+    end
     update_cam!(scene, camera)
     return
 end
diff --git a/src/camera/old_camera3d.jl b/src/camera/old_camera3d.jl
index 306c43c1694..76413c2376a 100644
--- a/src/camera/old_camera3d.jl
+++ b/src/camera/old_camera3d.jl
@@ -337,7 +337,6 @@ function update_cam!(scene::Scene, camera::OldCamera3D, area3d::Rect)
     bb = FRect3D(area3d)
     width = widths(bb)
     half_width = width/2f0
-    lower_corner = minimum(bb)
     middle = maximum(bb) - half_width
     old_dir = normalize(eyeposition .- lookat)
     camera.lookat[] = middle


Test patch:
diff --git a/test/events.jl b/test/events.jl
index 5705e928b9e..e9ce0bc1bd2 100644
--- a/test/events.jl
+++ b/test/events.jl
@@ -112,21 +112,21 @@ end
         # 1) In scene, in drag
         e.mousebutton[] = MouseButtonEvent(Mouse.right, Mouse.press)
         e.mouseposition[] = (600, 250)
-        @test cc.lookat[]       ≈ Vec3f0(4.409082, -4.409082, -2.598076)
-        @test cc.eyeposition[]  ≈ Vec3f0(7.409082, -1.4090819, 0.4019239)
+        @test cc.lookat[]       ≈ Vec3f0(5.4697413, -3.3484206, -2.1213205)
+        @test cc.eyeposition[]  ≈ Vec3f0(8.469742, -0.34842062, 0.8786795)
         @test cc.upvector[]     ≈ Vec3f0(0.0, 0.0, 1.0)
 
         # 2) Outside scene, in drag
         e.mouseposition[] = (1000, 450)
-        @test cc.lookat[]       ≈ Vec3f0(7.3484697, -7.3484697, -4.676537)
-        @test cc.eyeposition[]  ≈ Vec3f0(10.34847, -4.3484697, -1.676537)
+        @test cc.lookat[]       ≈ Vec3f0(9.257657, -5.4392805, -3.818377)
+        @test cc.eyeposition[]  ≈ Vec3f0(12.257658, -2.4392805, -0.81837714)
         @test cc.upvector[]     ≈ Vec3f0(0.0, 0.0, 1.0)
 
         # 3) not in drag
         e.mousebutton[] = MouseButtonEvent(Mouse.right, Mouse.release)
         e.mouseposition[] = (400, 250)
-        @test cc.lookat[]       ≈ Vec3f0(7.3484697, -7.3484697, -4.676537)
-        @test cc.eyeposition[]  ≈ Vec3f0(10.34847, -4.3484697, -1.676537)
+        @test cc.lookat[]       ≈ Vec3f0(9.257657, -5.4392805, -3.818377)
+        @test cc.eyeposition[]  ≈ Vec3f0(12.257658, -2.4392805, -0.81837714)
         @test cc.upvector[]     ≈ Vec3f0(0.0, 0.0, 1.0)