Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CairoMakie/src/primitives.jl
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ function draw_glyph_collection(scene, ctx, position, glyph_collection, rotation,

glyph_pos = let
transform_func = scene.transformation.transform_func[]
p = Makie.apply_transform(transform_func, position)
p = Makie.apply_transform(transform_func, position, space)

Makie.clip_to_space(scene.camera, markerspace) *
Makie.space_to_clip(scene.camera, space) *
Expand Down Expand Up @@ -797,7 +797,7 @@ function draw_mesh3D(
# and have `func` be fully typed inside closure
vs = broadcast(meshpoints, (func,)) do v, f
# Should v get a nan2zero?
v = Makie.apply_transform(f, v)
v = Makie.apply_transform(f, v, space)
p4d = to_ndim(Vec4f, scale .* to_ndim(Vec3f, v, 0f0), 1f0)
view * (model * p4d .+ to_ndim(Vec4f, pos, 0f0))
end
Expand Down
2 changes: 1 addition & 1 deletion CairoMakie/src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

function project_position(scene, transform_func::T, space, point, model, yflip::Bool = true) where T
# use transform func
point = Makie.apply_transform(transform_func, point)
point = Makie.apply_transform(transform_func, point, space)
_project_position(scene, space, point, model, yflip)
end

Expand Down
43 changes: 25 additions & 18 deletions GLMakie/src/drawing_primitives.jl
Original file line number Diff line number Diff line change
Expand Up @@ -200,11 +200,11 @@ function draw_atomic(screen::Screen, scene::Scene, @nospecialize(x::Union{Scatte
gl_attributes[:shading] = to_value(get(gl_attributes, :shading, true))
marker = lift_convert(:marker, pop!(gl_attributes, :marker), x)

space = get(gl_attributes, :space, :data) # needs to happen before connect_camera! call
positions = handle_view(x[1], gl_attributes)
positions = apply_transform(transform_func_obs(x), positions)
positions = apply_transform(transform_func_obs(x), positions, space)

if isa(x, Scatter)
space = get(gl_attributes, :space, :data)
mspace = get(gl_attributes, :markerspace, :pixel)
cam = scene.camera
gl_attributes[:preprojection] = map(space, mspace, cam.projectionview, cam.resolution) do space, mspace, _, _
Expand Down Expand Up @@ -260,8 +260,9 @@ function draw_atomic(screen::Screen, scene::Scene, @nospecialize(x::Lines))
linewidth = gl_attributes[:thickness]
data[:pattern] = ls .* (to_value(linewidth) * 0.25)
end
space = get(gl_attributes, :space, :data) # needs to happen before connect_camera! call
positions = handle_view(x[1], data)
positions = apply_transform(transform_func_obs(x), positions)
positions = apply_transform(transform_func_obs(x), positions, space)
handle_intensities!(data)
connect_camera!(data, scene.camera)
return draw_lines(screen, positions, data)
Expand All @@ -279,8 +280,9 @@ function draw_atomic(screen::Screen, scene::Scene, @nospecialize(x::LineSegments
linewidth = gl_attributes[:thickness]
data[:pattern] = ls .* (to_value(linewidth) * 0.25)
end
space = get(gl_attributes, :space, :data) # needs to happen before connect_camera! call
positions = handle_view(x.converted[1], data)
positions = apply_transform(transform_func_obs(x), positions)
positions = apply_transform(transform_func_obs(x), positions, space)
if haskey(data, :color) && data[:color][] isa AbstractVector{<: Number}
c = pop!(data, :color)
data[:color] = el32convert(c)
Expand All @@ -302,13 +304,13 @@ function draw_atomic(screen::Screen, scene::Scene,

transfunc = Makie.transform_func_obs(scene)
pos = gl_attributes[:position]
space = get(gl_attributes, :space, Observable(:data))
space = get(gl_attributes, :space, Observable(:data)) # needs to happen before connect_camera! call
markerspace = gl_attributes[:markerspace]
offset = pop!(gl_attributes, :offset, Vec2f(0))

# calculate quad metrics
glyph_data = map(pos, glyphcollection, offset, transfunc) do pos, gc, offset, transfunc
Makie.text_quads(pos, to_value(gc), offset, transfunc)
glyph_data = map(pos, glyphcollection, offset, transfunc, space) do pos, gc, offset, transfunc, space
Makie.text_quads(pos, to_value(gc), offset, transfunc, space)
end

# unpack values from the one signal:
Expand Down Expand Up @@ -379,7 +381,8 @@ function draw_atomic(screen::Screen, scene::Scene, x::Heatmap)
return cached_robj!(screen, scene, x) do gl_attributes
t = Makie.transform_func_obs(scene)
mat = x[3]
xypos = map(t, x[1], x[2]) do t, x, y
space = get(gl_attributes, :space, :data) # needs to happen before connect_camera! call
xypos = map(t, x[1], x[2], space) do t, x, y, space
x1d = xy_convert(x, size(mat[], 1))
y1d = xy_convert(y, size(mat[], 2))
# Only if transform doesn't do anything, we can stay linear in 1/2D
Expand All @@ -389,10 +392,10 @@ function draw_atomic(screen::Screen, scene::Scene, x::Heatmap)
# If we do any transformation, we have to assume things aren't on the grid anymore
# so x + y need to become matrices.
map!(x1d, x1d) do x
return apply_transform(t, Point(x, 0))[1]
return apply_transform(t, Point(x, 0), space)[1]
end
map!(y1d, y1d) do y
return apply_transform(t, Point(0, y))[2]
return apply_transform(t, Point(0, y), space)[2]
end
return (x1d, y1d)
end
Expand Down Expand Up @@ -436,8 +439,9 @@ function draw_atomic(screen::Screen, scene::Scene, x::Image)
end
gl_attributes[:color] = x[3]
gl_attributes[:shading] = false
space = get(gl_attributes, :space, :data) # needs to happen before connect_camera! call
connect_camera!(gl_attributes, scene.camera)
return mesh_inner(screen, mesh, transform_func_obs(x), gl_attributes)
return mesh_inner(screen, mesh, transform_func_obs(x), gl_attributes, space)
end
end

Expand All @@ -448,7 +452,7 @@ function update_positions(mesh::GeometryBasics.Mesh, positions)
return GeometryBasics.Mesh(meta(positions; attr...), faces(mesh))
end

function mesh_inner(screen::Screen, mesh, transfunc, gl_attributes)
function mesh_inner(screen::Screen, mesh, transfunc, gl_attributes, space=:data)
# signals not supported for shading yet
gl_attributes[:shading] = to_value(pop!(gl_attributes, :shading))
color = pop!(gl_attributes, :color)
Expand All @@ -474,9 +478,9 @@ function mesh_inner(screen::Screen, mesh, transfunc, gl_attributes)
else
error("Unsupported color type: $(typeof(to_value(color)))")
end
mesh = map(mesh, transfunc) do mesh, func
mesh = map(mesh, transfunc, space) do mesh, func, space
if !Makie.is_identity_transform(func)
return update_positions(mesh, apply_transform.(Ref(func), mesh.position))
return update_positions(mesh, apply_transform.(Ref(func), mesh.position, space))
end
return mesh
end
Expand All @@ -486,8 +490,9 @@ end
function draw_atomic(screen::Screen, scene::Scene, meshplot::Mesh)
return cached_robj!(screen, scene, meshplot) do gl_attributes
t = transform_func_obs(meshplot)
space = get(gl_attributes, :space, :data) # needs to happen before connect_camera! call
connect_camera!(gl_attributes, scene.camera)
return mesh_inner(screen, meshplot[1], t, gl_attributes)
return mesh_inner(screen, meshplot[1], t, gl_attributes, space)
end
end

Expand All @@ -513,6 +518,8 @@ function draw_atomic(screen::Screen, scene::Scene, x::Surface)
gl_attributes[:color_norm] = nothing
end

space = get(gl_attributes, :space, :data) # needs to happen before connect_camera! call

gl_attributes[:image] = img
gl_attributes[:shading] = to_value(get(gl_attributes, :shading, true))
connect_camera!(gl_attributes, scene.camera)
Expand All @@ -523,17 +530,17 @@ function draw_atomic(screen::Screen, scene::Scene, x::Surface)
if all(T -> T <: Union{AbstractMatrix, AbstractVector}, types)
t = Makie.transform_func_obs(scene)
mat = x[3]
xypos = map(t, x[1], x[2]) do t, x, y
xypos = map(t, x[1], x[2], space) do t, x, y, space
# Only if transform doesn't do anything, we can stay linear in 1/2D
if Makie.is_identity_transform(t)
return (x, y)
else
matrix = if x isa AbstractMatrix && y isa AbstractMatrix
apply_transform.((t,), Point.(x, y))
apply_transform.((t,), Point.(x, y), space)
else
# If we do any transformation, we have to assume things aren't on the grid anymore
# so x + y need to become matrices.
[apply_transform(t, Point(x, y)) for x in x, y in y]
[apply_transform(t, Point(x, y), space) for x in x, y in y]
end
return (first.(matrix), last.(matrix))
end
Expand Down
3 changes: 2 additions & 1 deletion RPRMakie/src/meshes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,9 @@ function to_rpr_object(context, matsys, scene, plot::Makie.Surface)

function grid(x, y, z, trans)
g = map(CartesianIndices(z)) do i
space = to_value(get(plot, :space, :data))
p = Point3f(Makie.get_dim(x, i, 1, size(z)), Makie.get_dim(y, i, 2, size(z)), z[i])
return Makie.apply_transform(trans, p)
return Makie.apply_transform(trans, p, space)
end
return vec(g)
end
Expand Down
13 changes: 13 additions & 0 deletions ReferenceTests/src/tests/short_tests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,19 @@ end
f
end

@reference_test "space test in transformed axis" begin
f = lines(exp.(0.1*(1.0:100)); axis=(yscale=log10,))
poly!(Rect(1, 1, 100, 100), color=:red, space=:pixel)
scatter!(2*mod.(1:100:10000, 97), 2*mod.(1:101:10000, 97), color=:blue, space=:pixel)
scatter!(Point2f(0, 0.25), space=:clip)
lines!([0.5,0.5], [0, 1]; space=:relative)
lines!([50,50], [0, 100]; space=:pixel)
lines!([0,1], [0.25, 0.25]; space=:clip)
scatter!(Point2f(0.5, 0), space=:relative)
f
end


# Needs a way to disable autolimits on show
# @reference_test "interactions after close" begin
# # After saving, interactions may be cleaned up:
Expand Down
10 changes: 5 additions & 5 deletions WGLMakie/src/imagelike.jl
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,10 @@ function limits_to_uvmesh(plot)
positions = Buffer(lift(rect-> decompose(Point2f, rect), rect))
faces = Buffer(lift(rect -> decompose(GLTriangleFace, rect), rect))
uv = Buffer(lift(decompose_uv, rect))
else
grid(x, y, trans) = Makie.matrix_grid(p-> apply_transform(trans, p), x, y, zeros(length(x), length(y)))
else
grid(x, y, trans, space) = Makie.matrix_grid(p-> apply_transform(trans, p, space), x, y, zeros(length(x), length(y)))
rect = lift((x, y) -> Tesselation(Rect2(0f0, 0f0, 1f0, 1f0), (length(x), length(y))), px, py)
positions = Buffer(lift(grid, px, py, t))
positions = Buffer(lift(grid, px, py, t, get(plot, :space, :data)))
faces = Buffer(lift(r -> decompose(GLTriangleFace, r), rect))
uv = Buffer(lift(decompose_uv, rect))
end
Expand All @@ -80,8 +80,8 @@ end
function create_shader(mscene::Scene, plot::Surface)
# TODO OWN OPTIMIZED SHADER ... Or at least optimize this a bit more ...
px, py, pz = plot[1], plot[2], plot[3]
grid(x, y, z, trans) = Makie.matrix_grid(p-> apply_transform(trans, p), x, y, z)
positions = Buffer(lift(grid, px, py, pz, transform_func_obs(plot)))
grid(x, y, z, trans, space) = Makie.matrix_grid(p-> apply_transform(trans, p, space), x, y, z)
positions = Buffer(lift(grid, px, py, pz, transform_func_obs(plot), get(plot, :space, :data)))
rect = lift(z -> Tesselation(Rect2(0f0, 0f0, 1f0, 1f0), size(z)), pz)
faces = Buffer(lift(r -> decompose(GLTriangleFace, r), rect))
uv = Buffer(lift(decompose_uv, rect))
Expand Down
4 changes: 2 additions & 2 deletions WGLMakie/src/lines.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ end

function create_shader(scene::Scene, plot::Union{Lines,LineSegments})
# Potentially per instance attributes
positions = lift(plot[1], transform_func_obs(plot)) do points, trans
points = apply_transform(trans, topoint(points))
positions = lift(plot[1], transform_func_obs(plot), get(plot, :space, :data)) do points, trans, space
points = apply_transform(trans, topoint(points), space)
if plot isa LineSegments
return points
else
Expand Down
6 changes: 3 additions & 3 deletions WGLMakie/src/meshes.jl
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
function vertexbuffer(x, trans)
function vertexbuffer(x, trans, space)
pos = decompose(Point, x)
return apply_transform(trans, pos)
return apply_transform(trans, pos, space)
end

function vertexbuffer(x::Observable, p)
return Buffer(lift(vertexbuffer, x, transform_func_obs(p)))
return Buffer(lift(vertexbuffer, x, transform_func_obs(p), get(p, :space, :data)))
end

facebuffer(x) = facebuffer(GeometryBasics.faces(x))
Expand Down
9 changes: 5 additions & 4 deletions WGLMakie/src/particles.jl
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ function create_shader(scene::Scene, plot::MeshScatter)
per_instance = filter(plot.attributes.attributes) do (k, v)
return k in per_instance_keys && !(isscalar(v[]))
end
per_instance[:offset] = apply_transform(transform_func_obs(plot), plot[1])
space = get(plot, :space, :data)
per_instance[:offset] = apply_transform(transform_func_obs(plot), plot[1], space)

for (k, v) in per_instance
per_instance[k] = Buffer(lift_convert(k, v, plot))
Expand Down Expand Up @@ -174,7 +175,7 @@ function create_shader(scene::Scene, plot::Scatter)
attributes[:preprojection] = map(space, mspace, cam.projectionview, cam.resolution) do space, mspace, _, _
Makie.clip_to_space(cam, mspace) * Makie.space_to_clip(cam, space)
end
attributes[:pos] = apply_transform(transform_func_obs(plot), plot[1])
attributes[:pos] = apply_transform(transform_func_obs(plot), plot[1], space)
quad_offset = get(attributes, :marker_offset, Observable(Vec2f(0)))
attributes[:marker_offset] = Vec3f(0)
attributes[:quad_offset] = quad_offset
Expand Down Expand Up @@ -219,8 +220,8 @@ function create_shader(scene::Scene, plot::Makie.Text{<:Tuple{<:Union{<:Makie.Gl
gcollection = Observable(glyphcollection)
end

glyph_data = map(pos, gcollection, offset, transfunc) do pos, gc, offset, transfunc
Makie.text_quads(pos, to_value(gc), offset, transfunc)
glyph_data = map(pos, gcollection, offset, transfunc, space) do pos, gc, offset, transfunc, space
Makie.text_quads(pos, to_value(gc), offset, transfunc, space)
end

# unpack values from the one signal:
Expand Down
5 changes: 3 additions & 2 deletions src/basic_recipes/text.jl
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,9 @@ function plot!(plot::Text)

sc = parent_scene(plot)

onany(linesegs, positions, sc.camera.projectionview, sc.px_area, transform_func_obs(sc)) do segs, pos, _, _, transf
pos_transf = scene_to_screen(apply_transform(transf, pos), sc)
onany(linesegs, positions, sc.camera.projectionview, sc.px_area,
transform_func_obs(sc), get(plot, :space, :data)) do segs, pos, _, _, transf, space
pos_transf = scene_to_screen(apply_transform(transf, pos, space), sc)
linesegs_shifted[] = map(segs, lineindices[]) do seg, index
seg + attr_broadcast_getindex(pos_transf, index)
end
Expand Down
2 changes: 1 addition & 1 deletion src/interaction/inspector.jl
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ function shift_project(scene, plot, pos)
project(
camera(scene).projectionview[],
Vec2f(widths(pixelarea(scene)[])),
apply_transform(transform_func_obs(plot)[], pos)
apply_transform(transform_func(plot), pos, to_value(get(plot, :space, :data)))
) .+ Vec2f(origin(pixelarea(scene)[]))
end

Expand Down
8 changes: 4 additions & 4 deletions src/layouting/layouting.jl
Original file line number Diff line number Diff line change
Expand Up @@ -302,8 +302,8 @@ _offset_at(o::Vector, i) = o[i]
Base.getindex(x::ScalarOrVector, i) = x.sv isa Vector ? x.sv[i] : x.sv
Base.lastindex(x::ScalarOrVector) = x.sv isa Vector ? length(x.sv) : 1

function text_quads(position::VecTypes, gc::GlyphCollection, offset, transfunc)
p = apply_transform(transfunc, position)
function text_quads(position::VecTypes, gc::GlyphCollection, offset, transfunc, space)
p = apply_transform(transfunc, position, space)
pos = [to_ndim(Point3f, p, 0) for _ in gc.origins]

atlas = get_texture_atlas()
Expand Down Expand Up @@ -336,8 +336,8 @@ function text_quads(position::VecTypes, gc::GlyphCollection, offset, transfunc)
return pos, char_offsets, quad_offsets, uvs, scales
end

function text_quads(position::Vector, gcs::Vector{<: GlyphCollection}, offset, transfunc)
ps = apply_transform(transfunc, position)
function text_quads(position::Vector, gcs::Vector{<: GlyphCollection}, offset, transfunc, space)
ps = apply_transform(transfunc, position, space)
pos = [to_ndim(Point3f, p, 0) for (p, gc) in zip(ps, gcs) for _ in gc.origins]

atlas = get_texture_atlas()
Expand Down
12 changes: 12 additions & 0 deletions src/layouting/transformation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,16 @@ transformationmatrix(x) = transformation(x).model
transform_func(x) = transform_func_obs(x)[]
transform_func_obs(x) = transformation(x).transform_func

"""
apply_transform(f, data, space)
Apply the data transform func to the data if the space matches one
of the the transformation spaces (currently only :data is transformed)
"""
apply_transform(f, data, space) = space == :data ? apply_transform(f, data) : data
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to point it out - this might need to be copy(data) if there are any mutating operations done on the output. I don't think there are, since we generally go through observables which create copies, but I thought I'd mention it anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The identity transforms make a point of returning data (or x) directly (and verifies that by checking === in one of the test cases), so that behavior was mirrored here. I would think any issues with mutating the data would quickly show up in that regard. Let me know if you think this needs any changes.

Copy link
Member

@jkrumbiegel jkrumbiegel Nov 23, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I did that at the time because I thought the overhead of copying was unnecessary. And because I didn't see the need for mutation afterwards, but still one should be careful

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a change (documentation note maybe?) or test you would like to insert here to make sure this stays consistent in the future?

function apply_transform(f::Observable, data::Observable, space::Observable)
return lift((f, d, s)-> apply_transform(f, d, s), f, data, space)
end

"""
apply_transform(f, data)
Apply the data transform func to the data
Expand Down Expand Up @@ -373,3 +383,5 @@ end
# by heatmaps or images
zvalue2d(x)::Float32 = Makie.translation(x)[][3] + zvalue2d(x.parent)
zvalue2d(::Nothing)::Float32 = 0f0


3 changes: 2 additions & 1 deletion src/makielayout/blocks/axis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ function update_axis_camera(camera::Camera, t, lims, xrev::Bool, yrev::Bool)
nearclip = -10_000f0
farclip = 10_000f0

tlims = Makie.apply_transform(t, lims)
# we are computing transformed camera position, so this isn't space dependent
tlims = Makie.apply_transform(t, lims)

left, bottom = minimum(tlims)
right, top = maximum(tlims)
Expand Down
2 changes: 1 addition & 1 deletion test/text.jl
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
# Test quad data
positions, char_offsets, quad_offsets, uvs, scales = Makie.text_quads(
to_ndim(Point3f, p.position[], 0), glyph_collection,
Vec2f(0), Makie.transform_func_obs(scene)[]
Vec2f(0), Makie.transform_func_obs(scene)[], :data
)

# Also doesn't work
Expand Down
Loading