diff --git a/src/scales.jl b/src/scales.jl index 34d5eff5c..a11938861 100644 --- a/src/scales.jl +++ b/src/scales.jl @@ -29,7 +29,8 @@ end function (ls::LinearScale)(x) if ls.clamp - x = clamp(x, ls.fmin, ls.fmax) + # clamp needs the values in low high order + x = clamp(x, min(ls.fmin, ls.fmax), max(ls.fmin, ls.fmax)) end return (x - ls.fmin) / (ls.fmax - ls.fmin) * (ls.tmax - ls.tmin) + ls.tmin end @@ -38,8 +39,9 @@ function (ls::LinearScale{T})(p::Point) where {T<:Point} px = p.x py = p.y if ls.clamp - px = clamp(px, ls.fmin.x, ls.fmax.x) - py = clamp(py, ls.fmin.y, ls.fmax.y) + # clamp needs the values in low high order + px = clamp(px, min(ls.fmin.x, ls.fmax.x), max(ls.fmin.x, ls.fmax.x)) + py = clamp(py, min(ls.fmin.y, ls.fmax.y), max(ls.fmin.y, ls.fmax.y)) end nx = (px - ls.fmin.x) / (ls.fmax.x - ls.fmin.x) * (ls.tmax.x - ls.tmin.x) + ls.tmin.x ny = (py - ls.fmin.y) / (ls.fmax.y - ls.fmin.y) * (ls.tmax.y - ls.tmin.y) + ls.tmin.y @@ -50,7 +52,14 @@ macro scale_layer(scale_mapping, body) return esc( quote @layer begin - Luxor.translate(-$scale_mapping.fmin.x, -$scale_mapping.fmin.y) + # compute the center of both rectangles + fcenterx = ($scale_mapping.fmax.x + $scale_mapping.fmin.x) / 2 + fcentery = ($scale_mapping.fmax.y + $scale_mapping.fmin.y) / 2 + + tcenterx = ($scale_mapping.tmax.x + $scale_mapping.tmin.x) / 2 + tcentery = ($scale_mapping.tmax.y + $scale_mapping.tmin.y) / 2 + + # scale in x and y sx = ($scale_mapping.tmax.x - $scale_mapping.tmin.x) / ($scale_mapping.fmax.x - $scale_mapping.fmin.x) @@ -58,7 +67,12 @@ macro scale_layer(scale_mapping, body) ($scale_mapping.tmax.y - $scale_mapping.tmin.y) / ($scale_mapping.fmax.y - $scale_mapping.fmin.y) Luxor.scale(sx, sy) - Luxor.translate($scale_mapping.tmin.x / sx, $scale_mapping.tmin.y / sy) + + # translate such that inputting the center from the "from mapping" is at 0,0 + Luxor.translate(-fcenterx, -fcentery) + + # shift center of canvas to center of new region + Luxor.translate(tcenterx / sx, tcentery / sy) $body end end, diff --git a/test/animations.jl b/test/animations.jl index f91800c70..f520d342d 100644 --- a/test/animations.jl +++ b/test/animations.jl @@ -719,7 +719,69 @@ end @test_logs (:error,) render(video; pathname = "test.mp3") end -@testset "@scale_layer" begin +@testset "@scale_layer vs mapping" begin + function dots_mapping(mapping, pts) + @JShape begin + @scale_layer mapping begin + circle.(pts, 0.1, :fill) + end + end + end + + function dots(pts) + @JShape begin + circle.(pts, 3, :fill) + end + end + + from_bls = [O, Point(1, 1), Point(-1, -1), Point(-1, 1)] + from_trs = [Point(10, 10), O, Point(10, 5)] + to_bls = [Point(10, 10), O] + + + for (from_bl, from_tr) in zip(from_bls, from_trs) + for to_bl in to_bls + diam = from_tr - from_bl + factor = 30 + to_tr = to_bl + factor * diam + vid = Video(500, 500) + + mapping = scale_linear(from_bl, from_tr, to_bl, to_tr) + + nframes = 1 + Background(1:nframes, ground) + dot_pos = [O] + Object(1:nframes, dots_mapping(mapping, dot_pos)) + + render(vid, tempdirectory = "images/with_mapping", pathname = "") + + vid = Video(500, 500) + + nframes = 1 + Background(1:nframes, ground) + dot_pos = mapping.(dot_pos) + Object(1:nframes, dots(dot_pos)) + + render(vid, tempdirectory = "images/without_mapping", pathname = "") + + for frame in [1] + png_name = lpad(string(frame), 10, "0") + @test_reference "images/with_mapping/$png_name.png" load( + "images/without_mapping/$png_name.png", + ) + end + + for i in 1:1 + rm("images/with_mapping/$(lpad(i, 10, "0")).png") + rm("images/without_mapping/$(lpad(i, 10, "0")).png") + end + rm("images/with_mapping/", recursive = true) + rm("images/without_mapping/", recursive = true) + end + end +end + +@testset "@scale_layer center origin" begin function dots_mapping(pts) @JShape begin mapping = scale_linear(O, Point(5, 5), Point(50, -50), Point(200, -200))