diff --git a/CHANGELOG.md b/CHANGELOG.md index efc2b8418..0c4dbcfb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,15 @@ # Javis.jl - Changelog +## Unreleased +- Add new morhping mode + ## v0.6.2 (12th of August 2021) - added `@Frames` macro for full power mode of defining frames - bugfix in `@JLayer` when dimensions are not defined explicitly - allow color interpolation in `change` - bugfix `color` can be a non string value in `JBox` + ## v0.6.1 (7th of August 2021) - Add shorthands for basic shapes - New functions `JBox, JCircle, JEllipse, JLine, JPoly, JRect, JStar, @JShape` @@ -119,4 +123,4 @@ Initial implementation with - frames for `Action` can be defined using a `UnitRange`, `Symbol` or `Rel` - `Translation`, `Rotation` - `appear`/`disappear` using opacity and linewidth in `SubAction` -- render `latex` using a basic svg parser +- render `latex` using a basic svg parser \ No newline at end of file diff --git a/src/Shape.jl b/src/Shape.jl index 85fd22624..5c4410e08 100644 --- a/src/Shape.jl +++ b/src/Shape.jl @@ -220,8 +220,13 @@ function print_basic(s::Shape) println("#Holes: $(length(s.subpaths))") end +""" + prepare_to_interpolate(from_shape, to_shape, style) -function prepare_to_interpolate(from_shape, to_shape) +Determines the way in which shapes are morphed to one another by manipulating the mapping of respective points +of each shape. +""" +function prepare_to_interpolate(from_shape, to_shape, style) # match number of points for outer polygon from_outer, to_outer = match_num_points(from_shape.points, to_shape.points) @@ -239,6 +244,11 @@ function prepare_to_interpolate(from_shape, to_shape) rotate_i, _ = compute_shortest_morphing_dist(from_outer, to_outer) new_from_outer = circshift(from_outer, -rotate_i + 1) + if style == :mode1 + new_from_outer = + circshift(reverse!(new_from_outer), floor(Int, -length(new_from_outer) / 2.6)) # found this to work best + end + new_from_holes = Vector{Vector{Point}}() # rotate holes diff --git a/src/morphs.jl b/src/morphs.jl index 26b6305e0..3c04eebe7 100644 --- a/src/morphs.jl +++ b/src/morphs.jl @@ -1,7 +1,7 @@ include("Shape.jl") """ - morph_to(to_func::Function; object=:stroke) + morph_to(to_func::Function; style=:default, object=:stroke) A closure for the [`_morph_to`](@ref) function. This makes it easier to write the function inside an `Object`. @@ -11,6 +11,7 @@ It especially does not work with functions which produce more than one polygon or which produce filled polygons. Blending between fills of polygons is definitely coming at a later stage. +To get a more visually appealing morphing one can try setting `style = :long`. **Important:** The functions itself should not draw the polygon i.e. use `circle(Point(100,100), 50)` instead of `circle(Point(100,100), 50, :stroke)` @@ -19,6 +20,7 @@ i.e. use `circle(Point(100,100), 50)` instead of `circle(Point(100,100), 50, :st which will be displayed at the end of the Object # Keywords +- `style::Symbol` Sets the style of morphing - `do_action::Symbol` defines whether the object has a fill or just a stroke. Defaults to `:stroke`. # Example @@ -37,14 +39,21 @@ circle_obj = Object(11:20, acirc) act!(circle_obj, Action(:same, morph_to(astar))) ``` """ -function morph_to(to_func::Function; do_action = :stroke) - return (video, object, action, frame) -> - _morph_to(video, object, action, frame, to_func; do_action = do_action) +function morph_to(to_func::Function; style = :default, do_action = :stroke) + return (video, object, action, frame) -> _morph_to( + video, + object, + action, + frame, + to_func; + style = style, + do_action = do_action, + ) end """ - _morph_to(video::Video, object::Object, action::Action, frame, to_func::Function; do_action=:stroke) + _morph_to(video::Video, object::Object, action::Action, frame, to_func::Function; style=:default, do_action=:stroke) Internal version of [`morph_to`](@ref) but described there. """ @@ -54,6 +63,7 @@ function _morph_to( action::Action, frame, to_func::Function; + style = :default, do_action = :stroke, ) if frame == last(get_frames(action)) @@ -79,6 +89,7 @@ function _morph_to( frame, from_polys, to_polys; + style = style, do_action = do_action, ) end @@ -87,7 +98,7 @@ end """ morph_between(video::Video, action::Action, frame, from_polys::Vector{Vector{Point}}, to_polys::Vector{Vector{Point}}; - do_action=:stroke) + style=:default, do_action=:stroke) Internal version of [`morph_to`](@ref) after the from poly is defined. """ @@ -97,6 +108,7 @@ function morph_between( frame, from_polys::Vector{Vector{Point}}, to_polys::Vector{Vector{Point}}; + style = :default, do_action = :stroke, ) cs = get_current_setting() @@ -104,7 +116,7 @@ function morph_between( # computation of the polygons and the best way to morph in the first frame if frame == first(get_frames(action)) - save_morph_polygons!(action, from_polys, to_polys) + save_morph_polygons!(action, from_polys, to_polys, style) end # obtain the computed polygons. These polygons have the same number of points. @@ -228,7 +240,7 @@ end """ save_morph_polygons!(action::Action, from_func::Vector{Vector{Point}}, - to_func::Vector{Vector{Point}}) + to_func::Vector{Vector{Point}}, style::Symbol) Calls the functions to polygons and calls [`match_num_points`](@ref) such that both polygons have the same number of points. @@ -241,6 +253,7 @@ function save_morph_polygons!( action::Action, from_polys::Vector{Vector{Point}}, to_polys::Vector{Vector{Point}}, + style::Symbol, ) # delete polygons with less than 2 points for i in length(from_polys):-1:1 @@ -292,7 +305,7 @@ function save_morph_polygons!( ) end else - from_shape, to_shape = prepare_to_interpolate(from_shape, to_shape) + from_shape, to_shape = prepare_to_interpolate(from_shape, to_shape, style) push!(action.defs[:from_shape], from_shape) push!(action.defs[:to_shape], to_shape) diff --git a/test/morphing.jl b/test/morphing.jl index 3f56ccd69..abf805562 100644 --- a/test/morphing.jl +++ b/test/morphing.jl @@ -157,6 +157,7 @@ end end end + @testset "Morphing mutates the object" begin function ground(args...) background("black") @@ -215,3 +216,30 @@ end rm("images/$(lpad(i, 10, "0")).png") end end + +@testset "Morphing modes" begin + function ground(args...) + background("black") + sethue("white") + end + + astar(args...; do_action = :stroke) = star(O, 50, 5, 0.5, 0, do_action) + abox(args...; do_action = :stroke) = rect(-150, -150, 100, 100, do_action) + acirc(args...; do_action = :stroke) = circle(Point(0, 0), 50, do_action) + + video = Video(500, 500) + back = Background(1:50, ground) + star_obj = Object(1:50, astar) + box_obj = Object(1:50, abox) + act!(star_obj, Action(5:20, morph_to(acirc, style = :mode1))) + act!(box_obj, Action(30:50, morph_to(astar, style = :mode1))) + render(video; tempdirectory = "images", pathname = "") + + for i in [5, 10, 15, 19, 20, 21, 30, 35, 40, 45, 49, 50] + @test_reference "refs/morph_modes$i.png" load("images/$(lpad(i, 10, "0")).png") + end + + for i in 1:50 + rm("images/$(lpad(i, 10, "0")).png") + end +end diff --git a/test/refs/morph_modes10.png b/test/refs/morph_modes10.png new file mode 100644 index 000000000..b4e08842e Binary files /dev/null and b/test/refs/morph_modes10.png differ diff --git a/test/refs/morph_modes15.png b/test/refs/morph_modes15.png new file mode 100644 index 000000000..c1a60ad8e Binary files /dev/null and b/test/refs/morph_modes15.png differ diff --git a/test/refs/morph_modes19.png b/test/refs/morph_modes19.png new file mode 100644 index 000000000..9f3f6b0b5 Binary files /dev/null and b/test/refs/morph_modes19.png differ diff --git a/test/refs/morph_modes20.png b/test/refs/morph_modes20.png new file mode 100644 index 000000000..185ca7dfc Binary files /dev/null and b/test/refs/morph_modes20.png differ diff --git a/test/refs/morph_modes21.png b/test/refs/morph_modes21.png new file mode 100644 index 000000000..185ca7dfc Binary files /dev/null and b/test/refs/morph_modes21.png differ diff --git a/test/refs/morph_modes30.png b/test/refs/morph_modes30.png new file mode 100644 index 000000000..185ca7dfc Binary files /dev/null and b/test/refs/morph_modes30.png differ diff --git a/test/refs/morph_modes35.png b/test/refs/morph_modes35.png new file mode 100644 index 000000000..88dc6a962 Binary files /dev/null and b/test/refs/morph_modes35.png differ diff --git a/test/refs/morph_modes40.png b/test/refs/morph_modes40.png new file mode 100644 index 000000000..890a6c1f4 Binary files /dev/null and b/test/refs/morph_modes40.png differ diff --git a/test/refs/morph_modes45.png b/test/refs/morph_modes45.png new file mode 100644 index 000000000..e024491de Binary files /dev/null and b/test/refs/morph_modes45.png differ diff --git a/test/refs/morph_modes49.png b/test/refs/morph_modes49.png new file mode 100644 index 000000000..428140d3c Binary files /dev/null and b/test/refs/morph_modes49.png differ diff --git a/test/refs/morph_modes5.png b/test/refs/morph_modes5.png new file mode 100644 index 000000000..c8c5796ac Binary files /dev/null and b/test/refs/morph_modes5.png differ diff --git a/test/refs/morph_modes50.png b/test/refs/morph_modes50.png new file mode 100644 index 000000000..a75fa5369 Binary files /dev/null and b/test/refs/morph_modes50.png differ