Skip to content

Commit

Permalink
Change camera variables to Float64 (#3984)
Browse files Browse the repository at this point in the history
* change cameras to Float64

* add test

* update changelog

* generalize angle

* fix test

* fix RPRMakie

* increase tolerance

---------

Co-authored-by: Simon <sdanisch@protonmail.com>
  • Loading branch information
ffreyer and SimonDanisch authored Jun 28, 2024
1 parent 299caba commit 90d88e5
Show file tree
Hide file tree
Showing 15 changed files with 227 additions and 208 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## [Unreleased]

- Changed camera variables to Float64 for increased accuracy [#3984](https://github.com/MakieOrg/Makie.jl/pull/3984)
- Allow CairoMakie to render `poly` overloads that internally don't use two child plots [#3986](https://github.com/MakieOrg/Makie.jl/pull/3986).
- Fixes for Menu and DataInspector [#3975](https://github.com/MakieOrg/Makie.jl/pull/3975).
- Add line-loop detection and rendering to GLMakie and WGLMakie [#3907](https://github.com/MakieOrg/Makie.jl/pull/3907).
Expand Down
18 changes: 9 additions & 9 deletions GLMakie/src/drawing_primitives.jl
Original file line number Diff line number Diff line change
Expand Up @@ -139,14 +139,14 @@ function to_glvisualize_key(k)
end

function connect_camera!(plot, gl_attributes, cam, space = gl_attributes[:space])
for key in (:pixel_space, :eyeposition)
# Overwrite these, user defined attributes shouldn't use those!
gl_attributes[key] = lift(identity, plot, getfield(cam, key))
end
# Overwrite these, user defined attributes shouldn't use those!
gl_attributes[:pixel_space] = lift(Mat4f, plot, cam.pixel_space)
gl_attributes[:eyeposition] = lift(identity, plot, cam.eyeposition)

get!(gl_attributes, :view) do
# get!(cam.calculated_values, Symbol("view_$(space[])")) do
return lift(plot, cam.view, space) do view, space
return is_data_space(space) ? view : Mat4f(I)
return is_data_space(space) ? Mat4f(view) : Mat4f(I)
end
# end
end
Expand All @@ -169,14 +169,14 @@ function connect_camera!(plot, gl_attributes, cam, space = gl_attributes[:space]
get!(gl_attributes, :projection) do
# return get!(cam.calculated_values, Symbol("projection_$(space[])")) do
return lift(plot, cam.projection, cam.pixel_space, space) do _, _, space
return Makie.space_to_clip(cam, space, false)
return Mat4f(Makie.space_to_clip(cam, space, false))
end
# end
end
get!(gl_attributes, :projectionview) do
# get!(cam.calculated_values, Symbol("projectionview_$(space[])")) do
return lift(plot, cam.projectionview, cam.pixel_space, space) do _, _, space
Makie.space_to_clip(cam, space, true)
return Mat4f(Makie.space_to_clip(cam, space, true))
end
# end
end
Expand Down Expand Up @@ -391,7 +391,7 @@ function draw_atomic(screen::Screen, scene::Scene, @nospecialize(plot::Union{Sca
cam = scene.camera
gl_attributes[:preprojection] = lift(plot, space, mspace, cam.projectionview,
cam.resolution) do space, mspace, _, _
return Makie.clip_to_space(cam, mspace) * Makie.space_to_clip(cam, space)
return Mat4f(Makie.clip_to_space(cam, mspace) * Makie.space_to_clip(cam, space))
end
# fast pixel does its own setup
if !(marker[] isa FastPixel)
Expand Down Expand Up @@ -574,7 +574,7 @@ function draw_atomic(screen::Screen, scene::Scene,
cam = scene.camera
# gl_attributes[:preprojection] = Observable(Mat4f(I))
gl_attributes[:preprojection] = lift(plot, space, markerspace, cam.projectionview, cam.resolution) do s, ms, pv, res
Makie.clip_to_space(cam, ms) * Makie.space_to_clip(cam, s)
Mat4f(Makie.clip_to_space(cam, ms) * Makie.space_to_clip(cam, s))
end

return draw_scatter(screen, (DISTANCEFIELD, positions), gl_attributes)
Expand Down
2 changes: 1 addition & 1 deletion RPRMakie/src/scene.jl
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ function to_rpr_light(context::RPR.Context, rpr_scene, light::Makie.DirectionalL
else
dir = normalize(dir)
end
quart = Makie.rotation_between(dir, Vec3f(0,0,-1))
quart = Makie.rotation_between(Vec3f(dir), Vec3f(0,0,-1))
transform!(directionallight, Makie.rotationmatrix4(quart))
end
map(light.color) do c
Expand Down
2 changes: 1 addition & 1 deletion ReferenceTests/src/tests/short_tests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -300,4 +300,4 @@ end
# f.scene.events.scroll[] = (0, -10)
# # reference test the zoomed out plot
# f
# end
# end
4 changes: 2 additions & 2 deletions WGLMakie/src/serialization.jl
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ function serialize_scene(scene::Scene)

cam3d_state = if cam_controls isa Camera3D
fields = (:lookat, :upvector, :eyeposition, :fov, :near, :far)
dict = Dict((f => lift(serialize_three, scene, getfield(cam_controls, f)) for f in fields))
dict = Dict((f => lift(x -> serialize_three(Float32.(x)), scene, getfield(cam_controls, f)) for f in fields))
dict[:resolution] = lift(res -> Int32[res...], scene, scene.camera.resolution)
dict
else
Expand Down Expand Up @@ -377,6 +377,6 @@ function serialize_camera(scene::Scene)
# eyeposition updates with viewmatrix, since an eyepos change will trigger
# a view matrix change!
ep = cam.eyeposition[]
return [vec(collect(view)), vec(collect(proj)), Int32[res...], Float32[ep...]]
return [vec(collect(Mat4f(view))), vec(collect(Mat4f(proj))), Int32[res...], Float32[ep...]]
end
end
4 changes: 2 additions & 2 deletions src/basic_recipes/contours.jl
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ with z-elevation for each level.
MakieCore.documented_attributes(Contour)...
end

angle(p1::Union{Vec2f,Point2f}, p2::Union{Vec2f,Point2f})::Float32 =
atan(p2[2] - p1[2], p2[1] - p1[1]) # result in [-π, π]
# result in [-π, π]
angle(p1::VecTypes{2}, p2::VecTypes{2}) = Float32(atan(p2[2] - p1[2], p2[1] - p1[1]))

function label_info(lev, vertices, col)
mid = ceil(Int, 0.5f0 * length(vertices))
Expand Down
12 changes: 6 additions & 6 deletions src/camera/camera.jl
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,13 @@ end

function Camera(viewport)
pixel_space = lift(viewport) do window_size
nearclip = -10_000f0
farclip = 10_000f0
w, h = Float32.(widths(window_size))
return orthographicprojection(0f0, w, 0f0, h, nearclip, farclip)
nearclip = -10_000.0
farclip = 10_000.0
w, h = Float64.(widths(window_size))
return orthographicprojection(0.0, w, 0.0, h, nearclip, farclip)
end
view = Observable(Mat4f(I))
proj = Observable(Mat4f(I))
view = Observable(Mat4d(I))
proj = Observable(Mat4d(I))
proj_view = map(*, proj, view)
return Camera(
pixel_space,
Expand Down
76 changes: 38 additions & 38 deletions src/camera/camera2d.jl
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
struct Camera2D <: AbstractCamera
area::Observable{Rect2f}
zoomspeed::Observable{Float32}
area::Observable{Rect2d}
zoomspeed::Observable{Float64}
zoombutton::Observable{IsPressedInputType}
panbutton::Observable{IsPressedInputType}
padding::Observable{Float32}
padding::Observable{Float64}
last_area::Observable{Vec{2, Int}}
update_limits::Observable{Bool}
end
Expand All @@ -17,16 +17,16 @@ selections.
## Keyword Arguments
- `zoomspeed = 0.1f0` sets the zoom speed.
- `zoomspeed = 0.1` sets the zoom speed.
- `zoombutton = true` sets a button (combination) which needs to be pressed to enable zooming. By default no button needs to be pressed.
- `panbutton = Mouse.right` sets the button used to translate the camera. This must include a mouse button.
- `selectionbutton = (Keyboard.space, Mouse.left)` sets the button used for rectangle selection. This must include a mouse button.
"""
function cam2d!(scene::SceneLike; kw_args...)
cam_attributes = merged_get!(:cam2d, scene, Attributes(kw_args)) do
Attributes(
area = Observable(Rectf(0, 0, 1, 1)),
zoomspeed = 0.10f0,
area = Observable(Rectd(0, 0, 1, 1)),
zoomspeed = 0.1,
zoombutton = true,
panbutton = Mouse.right,
selectionbutton = (Keyboard.space, Mouse.left),
Expand Down Expand Up @@ -73,7 +73,7 @@ Useful when using the `Observable` pipeline.
update_cam!(scene::SceneLike) = update_cam!(scene, cameracontrols(scene), data_limits(scene))

function update_cam!(scene::Scene, cam::Camera2D, area3d::Rect)
area = Rect2f(area3d)
area = Rect2d(area3d)
area = positive_widths(area)
# ignore rects with width almost 0
any(x-> x 0.0, widths(area)) && return
Expand All @@ -89,18 +89,18 @@ function update_cam!(scene::Scene, cam::Camera2D, area3d::Rect)
# so we make the minimum 1.0, and grow in the other dimension
s = ratio ./ minimum(ratio)
newwh = s .* widths(area)
cam.area[] = Rectf(minimum(area), newwh)
cam.area[] = Rect2d(minimum(area), newwh)
end
update_cam!(scene, cam)
end

function update_cam!(scene::SceneLike, cam::Camera2D)
x, y = minimum(cam.area[])
w, h = widths(cam.area[]) ./ 2f0
x, y = Float64.(minimum(cam.area[]))
w, h = Float64.(0.5 .* widths(cam.area[]))
# These observables should be final, no one should do map(cam.projection),
# so we don't push! and just update the value in place
view = translationmatrix(Vec3f(-x - w, -y - h, 0))
projection = orthographicprojection(-w, w, -h, h, -10_000f0, 10_000f0)
view = translationmatrix(Vec3d(-x - w, -y - h, 0))
projection = orthographicprojection(-w, w, -h, h, -10_000.0, 10_000.0)
set_proj_view!(camera(scene), projection, view)
cam.last_area[] = Vec(size(scene))
return
Expand All @@ -112,7 +112,7 @@ function correct_ratio!(scene, cam)
change = neww .- cam.last_area[]
if !(change Vec(0.0, 0.0))
s = 1.0 .+ (change ./ cam.last_area[])
camrect = Rectf(minimum(cam.area[]), widths(cam.area[]) .* s)
camrect = Rect2d(minimum(cam.area[]), widths(cam.area[]) .* s)
cam.area[] = camrect
update_cam!(scene, cam)
end
Expand Down Expand Up @@ -142,7 +142,7 @@ function add_pan!(scene::SceneLike, cam::Camera2D)
startpos[] = mp
area = cam.area[]
diff = Vec(diff) .* wscale(viewport(scene)[], area)
cam.area[] = Rectf(minimum(area) .+ diff, widths(area))
cam.area[] = Rect2d(minimum(area) .+ diff, widths(area))
update_cam!(scene, cam)
active[] = false
return Consume(true)
Expand All @@ -160,7 +160,7 @@ function add_pan!(scene::SceneLike, cam::Camera2D)
startpos[] = pos
area = cam.area[]
diff = Vec(diff) .* wscale(viewport(scene)[], area)
cam.area[] = Rectf(minimum(area) .+ diff, widths(area))
cam.area[] = Rect2d(minimum(area) .+ diff, widths(area))
update_cam!(scene, cam)
return Consume(true)
end
Expand All @@ -172,17 +172,17 @@ function add_zoom!(scene::SceneLike, cam::Camera2D)
e = events(scene)
on(camera(scene), e.scroll) do x
@extractvalue cam (zoomspeed, zoombutton, area)
zoom = Float32(x[2])
zoom = Float64(x[2])
if zoom != 0 && ispressed(scene, zoombutton) && is_mouseinside(scene)
pa = viewport(scene)[]
z = (1f0 - zoomspeed)^zoom
mp = Vec2f(e.mouseposition[]) - minimum(pa)
z = (1.0 - zoomspeed)^zoom
mp = Vec2d(e.mouseposition[]) - minimum(pa)
mp = (mp .* wscale(pa, area)) + minimum(area)
p1, p2 = minimum(area), maximum(area)
p1, p2 = p1 - mp, p2 - mp # translate to mouse position
p1, p2 = z * p1, z * p2
p1, p2 = p1 + mp, p2 + mp
cam.area[] = Rectf(p1, p2 - p1)
cam.area[] = Rect2d(p1, p2 - p1)
update_cam!(scene, cam)
return Consume(true)
end
Expand All @@ -200,13 +200,13 @@ function absrect(rect)
xy = ntuple(Val(2)) do i
wh[i] < 0 ? xy[i] + wh[i] : xy[i]
end
return Rectf(Vec2f(xy), Vec2f(abs.(wh)))
return Rect2(Vec2(xy), Vec2(abs.(wh)))
end


function selection_rect!(scene, cam, key)
rect = RefValue(Rectf(NaN, NaN, NaN, NaN))
lw = 2f0
lw = 2.0
scene_unscaled = Scene(
scene, transformation = Transformation(),
cam = copy(camera(scene)), clear = false
Expand Down Expand Up @@ -274,14 +274,14 @@ function reset!(cam, boundingbox, preserveratio = true)
ratio = w2 ./ w1
w1 = if ratio[1] > ratio[2]
s = w2[1] ./ w2[2]
Vec2f(s * w1[2], w1[2])
Vec2(s * w1[2], w1[2])
else
s = w2[2] ./ w2[1]
Vec2f(w1[1], s * w1[1])
Vec2(w1[1], s * w1[1])
end
end
p = minimum(w1) .* 0.001 # 2mm padding
update_cam!(cam, Rectf(-p, -p, w1 .+ 2p))
update_cam!(cam, Rect(-p, -p, w1 .+ 2p))
return
end

Expand All @@ -290,7 +290,7 @@ function add_restriction!(cam, window, rarea::Rect2, minwidths::Vec)
restrict_action = paused_action(1.0) do t
o = lerp(origin(area_ref[]), origin(cam[Area]), t)
wh = lerp(widths(area_ref[]), widths(cam[Area]), t)
update_cam!(cam, Rectf(o, wh))
update_cam!(cam, Rect2d(o, wh))
end
on(window, Mouse.Drag) do drag
if drag == Mouse.up && !isplaying(restrict_action)
Expand All @@ -302,13 +302,13 @@ function add_restriction!(cam, window, rarea::Rect2, minwidths::Vec)
maxi = maxi - newmax
newo = newo - maxi
newwh = newmax - newo
scale = 1f0
scale = 1.0
for (w1, w2) in zip(minwidths, newwh)
stmp = w1 > w2 ? w1 / w2 : 1f0
stmp = w1 > w2 ? w1 / w2 : 1.0
scale = max(scale, stmp)
end
newwh = newwh * scale
area_ref[] = Rectf(newo, newwh)
area_ref[] = Rect2d(newo, newwh)
if area_ref[] != cam[Area]
play!(restrict_action)
end
Expand All @@ -324,25 +324,25 @@ get_space(::PixelCamera) = :pixel

struct UpdatePixelCam
camera::Camera
near::Float32
far::Float32
near::Float64
far::Float64
end
get_space(::UpdatePixelCam) = :pixel

function (cam::UpdatePixelCam)(window_size)
w, h = Float32.(widths(window_size))
projection = orthographicprojection(0f0, w, 0f0, h, cam.near, cam.far)
set_proj_view!(cam.camera, projection, Mat4f(I))
w, h = Float64.(widths(window_size))
projection = orthographicprojection(0.0, w, 0.0, h, cam.near, cam.far)
set_proj_view!(cam.camera, projection, Mat4d(I))
end

"""
campixel!(scene; nearclip=-1000f0, farclip=1000f0)
campixel!(scene; nearclip=-1000.0, farclip=1000.0)
Creates a pixel camera for the given `scene`. This means that the positional
data of a plot will be interpreted in pixel units. This camera does not feature
controls.
"""
function campixel!(scene::Scene; nearclip=-10_000f0, farclip=10_000f0)
function campixel!(scene::Scene; nearclip=-10_000.0, farclip=10_000.0)
disconnect!(camera(scene))
camera(scene).view_direction[] = Vec3f(0, 0, -1)
update_once = Observable(false)
Expand All @@ -365,11 +365,11 @@ get_space(::RelativeCamera) = :relative
Creates a camera for the given `scene` which maps the scene area to a 0..1 by
0..1 range. This camera does not feature controls.
"""
function cam_relative!(scene::Scene; nearclip=-10_000f0, farclip=10_000f0)
function cam_relative!(scene::Scene; nearclip=-10_000.0, farclip=10_000.0)
disconnect!(camera(scene))
camera(scene).view_direction[] = Vec3f(0, 0, -1)
projection = orthographicprojection(0f0, 1f0, 0f0, 1f0, nearclip, farclip)
set_proj_view!(camera(scene), projection, Mat4f(I))
projection = orthographicprojection(0.0, 1.0, 0.0, 1.0, nearclip, farclip)
set_proj_view!(camera(scene), projection, Mat4d(I))
cam = RelativeCamera()
cameracontrols!(scene, cam)
cam
Expand Down
Loading

0 comments on commit 90d88e5

Please sign in to comment.