Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

anim_translate error, error in fourier example[BUG] #467

Closed
aburousan opened this issue Feb 26, 2022 · 13 comments
Closed

anim_translate error, error in fourier example[BUG] #467

aburousan opened this issue Feb 26, 2022 · 13 comments
Labels
bug Something isn't working

Comments

@aburousan
Copy link
Contributor

Describe the bug

A clear and concise description of what the bug is.

To Reproduce

  1. Julia Version (i.e. output of julia -v): 1.7.1

  2. Operating system (Mac, Linux, Windows): Windows 11

  3. Javis version (i.e output of ] status Javis in the REPL) 0.8.0

  4. Minimum working code example that led to bug: Running the example code of Fourier example.

Expected Behavior and Actual Behavior
Should create Julia logo as shown in fourier example.
But showing the error given below.

TSP cost: 1851.3679707085373
ERROR: LoadError: MethodError: no method matching anim_translate(::Object)
Closest candidates are:
  anim_translate(::Union{Point, Object}, ::Union{Point, Object}) at C:\Users\Syeda Spandita Zaman\.julia\packages\Javis\TCcr1\src\structs\Transitions.jl:32
  anim_translate(::Real, ::Real) at C:\Users\Syeda Spandita Zaman\.julia\packages\Javis\TCcr1\src\structs\Transitions.jl:30
  anim_translate(::Point) at C:\Users\Syeda Spandita Zaman\.julia\packages\Javis\TCcr1\src\structs\Transitions.jl:31
Stacktrace:
 [1] animate_fourier(options::NamedTuple{(:npoints, :nplay_frames, :nruns, :nend_frames, :width, :height, :shape_scale, :tsp_quality_factor, :filename), Tuple{Int64, Int64, Int64, Int64, Int64, Int64, Float64, Int64, String}})
   @ Main E:\\fourier.jl:137
 [2] main()
   @ Main E:\\fourier.jl:185
 [3] top-level scope
   @ E:\\fourier.jl:188
in expression starting at E:\fourier.jl:188```
@aburousan aburousan added the bug Something isn't working label Feb 26, 2022
@aburousan aburousan changed the title anim_translate error, error in fourier[BUG] anim_translate error, error in fourier example[BUG] Feb 26, 2022
@gpucce
Copy link
Member

gpucce commented Feb 26, 2022

Hi @aburousan changing

act!(circles[i], Action(1:1, anim_translate(circles[i-1])))

with

act!(circles[i], Action(1:1, anim_translate(O, circles[i-1])))

Should fix the error, could you check if it does?

@aburousan
Copy link
Contributor Author

It's rendering but now it's showing new error

E:\>julia fourier.jl
#points: 643
TSP cost: 1851.3679707085373
Rendering frames...100%|████████████████████████████████████████████████████████████████████████| Time: 0:00:28
ERROR: LoadError: failed process: Process(`'C:\Users\Syeda Spandita Zaman\.julia\artifacts\ecb81e6429c089c1da802644fae337754832d534\bin\ffmpeg.exe' -loglevel panic -framerate 30 -i 'C:\Users\SYEDAS~1\AppData\Local\Temp\jl_t5RcVi/%10d.png' -i 'C:\Users\SYEDAS~1\AppData\Local\Temp\jl_t5RcVi/palette.png' -lavfi paletteuse -y 'E:\gifs/julia_logo_dft.gif'`, ProcessExited(1)) [1]

Stacktrace:
  [1] pipeline_error
    @ .\process.jl:531 [inlined]
  [2] run(::Cmd; wait::Bool)
    @ Base .\process.jl:446
  [3] run
    @ .\process.jl:444 [inlined]
  [4] (::FFMPEG.var"#4#6"{Cmd})(command_path::String)
    @ FFMPEG C:\Users\Syeda Spandita Zaman\.julia\packages\FFMPEG\OUpap\src\FFMPEG.jl:112
  [5] (::JLLWrappers.var"#2#3"{FFMPEG.var"#4#6"{Cmd}, String})()
    @ JLLWrappers C:\Users\Syeda Spandita Zaman\.julia\packages\JLLWrappers\QpMQW\src\runtime.jl:49
  [6] withenv(f::JLLWrappers.var"#2#3"{FFMPEG.var"#4#6"{Cmd}, String}, keyvals::Pair{String, String})
    @ Base .\env.jl:172
  [7] withenv_executable_wrapper(f::Function, executable_path::String, PATH::String, LIBPATH::String, adjust_PATH::Bool, adjust_LIBPATH::Bool)
    @ JLLWrappers C:\Users\Syeda Spandita Zaman\.julia\packages\JLLWrappers\QpMQW\src\runtime.jl:48
  [8] #invokelatest#2
    @ .\essentials.jl:716 [inlined]
  [9] invokelatest
    @ .\essentials.jl:714 [inlined]
 [10] #ffmpeg#3
    @ C:\Users\Syeda Spandita Zaman\.julia\packages\JLLWrappers\QpMQW\src\products\executable_generators.jl:21 [inlined]
 [11] ffmpeg
    @ C:\Users\Syeda Spandita Zaman\.julia\packages\JLLWrappers\QpMQW\src\products\executable_generators.jl:21 [inlined]
 [12] #exe#2
    @ C:\Users\Syeda Spandita Zaman\.julia\packages\FFMPEG\OUpap\src\FFMPEG.jl:111 [inlined]
 [13] ffmpeg_exe
    @ C:\Users\Syeda Spandita Zaman\.julia\packages\FFMPEG\OUpap\src\FFMPEG.jl:123 [inlined]
 [14] render(video::Video; framerate::Int64, pathname::String, liveview::Bool, streamconfig::Nothing, tempdirectory::String, ffmpeg_loglevel::String, rescale_factor::Float64, postprocess_frames_flow::typeof(identity), postprocess_frame::typeof(Javis.default_postprocess))
    @ Javis C:\Users\Syeda Spandita Zaman\.julia\packages\Javis\TCcr1\src\Javis.jl:350
 [15] animate_fourier(options::NamedTuple{(:npoints, :nplay_frames, :nruns, :nend_frames, :width, :height, :shape_scale, :tsp_quality_factor, :filename), Tuple{Int64, Int64, Int64, Int64, Int64, Int64, Float64, Int64, String}})
    @ Main E:\\fourier.jl:146
 [16] main()
    @ Main E:\\fourier.jl:185
 [17] top-level scope
    @ E:\\fourier.jl:188
in expression starting at E:\fourier.jl:188

@gpucce
Copy link
Member

gpucce commented Feb 27, 2022

Hi, this I believe might depend on the pathname you used but I can't find this out without seeing your code.

Could you share the exact code you use?

@Wikunia
Copy link
Member

Wikunia commented Feb 27, 2022

Basically the last line with render as I assume everything else is from our Fourier example.

@aburousan
Copy link
Contributor Author

This is the code

using Javis, FFTW, FFTViews
using TravelingSalesmanHeuristics

function ground(args...)
    background("black")
    sethue("white")
end

function circ(; r = 10, vec = O, action = :stroke, color = "white")
    sethue(color)
    circle(O, r, action)
    my_arrow(O, vec)
    return vec
end

function my_arrow(start_pos, end_pos)
    arrow(
        start_pos,
        end_pos;
        linewidth = distance(start_pos, end_pos) / 100,
        arrowheadlength = 7,
    )
    return end_pos
end

function draw_line(
    p1 = O,
    p2 = O;
    color = "white",
    action = :stroke,
    edge = "solid",
    linewidth = 3,
)
    sethue(color)
    setdash(edge)
    setline(linewidth)
    line(p1, p2, action)
end

function draw_path!(path, pos, color)
    sethue(color)

    push!(path, pos)
    return draw_line.(path[2:end], path[1:(end - 1)]; color = color)
end

function get_points(npoints, options)
    Drawing() # julialogo needs a drawing
    julialogo(; action = :path, centered = true)
    shapes = pathtopoly()
    new_shapes = shapes[1:6]
    last_i = 1
    # the circles in the JuliaLogo are part of a single shape
    # this loop creates new shapes for each circle
    for shape in shapes[7:7]
        max_dist = 0.0
        for i in 2:length(shape)
            d = distance(shape[i - 1], shape[i])
            if d > 3
                push!(new_shapes, shape[last_i:(i - 1)])
                last_i = i
            end
        end
    end
    push!(new_shapes, shapes[7][last_i:end])
    shapes = new_shapes
    for i in 1:length(shapes)
        shapes[i] .*= options.shape_scale
    end

    total_distance = 0.0
    for shape in shapes
        total_distance += polyperimeter(shape)
    end
    parts = []
    points = Point[]
    start_i = 1
    for shape in shapes
        len = polyperimeter(shape)
        portion = len / total_distance
        nlocalpoints = floor(Int, portion * npoints)
        new_points = [
            Javis.get_polypoint_at(shape, i / (nlocalpoints - 1)) for
            i in 0:(nlocalpoints - 1)
        ]
        append!(points, new_points)
        new_i = start_i + length(new_points) - 1
        push!(parts, start_i:new_i)
        start_i = new_i
    end
    return points, parts
end

c2p(c::Complex) = Point(real(c), imag(c))

remap_idx(i::Int) = (-1)^i * floor(Int, i / 2)
remap_inv(n::Int) = 2n * sign(n) - 1 * (n > 0)

function animate_fourier(options)
    npoints = options.npoints
    nplay_frames = options.nplay_frames
    nruns = options.nruns
    nframes = nplay_frames + options.nend_frames

    # obtain points from julialogo
    points, parts = get_points(npoints, options)
    npoints = length(points)
    println("#points: $npoints")
    # solve tsp to reduce length of extra edges
    distmat = [distance(points[i], points[j]) for i in 1:npoints, j in 1:npoints]

    path, cost = solve_tsp(distmat; quality_factor = options.tsp_quality_factor)
    println("TSP cost: $cost")
    points = points[path] # tsp saves the last point again

    # optain the fft result and scale
    x = [p.x for p in points]
    y = [p.y for p in points]

    fs = FFTView(fft(complex.(x, y)))
    # normalize the points as fs isn't normalized
    fs ./= npoints
    npoints = length(fs)

    video = Video(options.width, options.height)
    Background(1:nframes, ground)

    circles = Object[]

    for i in 1:npoints
        ridx = remap_idx(i)

        push!(circles, Object((args...) -> circ(; r = abs(fs[ridx]), vec = c2p(fs[ridx]))))

        if i > 1
            # translate to the tip of the vector of the previous circle
            act!(circles[i], Action(1:1, anim_translate(O, circles[i-1])))
        end
        ridx = remap_idx(i)
        act!(circles[i], Action(1:nplay_frames, anim_rotate(0.0, ridx * 2π * nruns)))
    end

    trace_points = Point[]
    Object(1:nframes, (args...) -> draw_path!(trace_points, pos(circles[end]), "red"))

    return render(video; pathname = joinpath(@__DIR__, options.filename))
end

function main()
    hd_options = (
        npoints = 3001, # rough number of points for the shape => number of circles
        nplay_frames = 1200, # number of frames for the animation of fourier
        nruns = 2, # how often it's drawn
        nend_frames = 200,  # number of frames in the end
        width = 1920,
        height = 1080,
        shape_scale = 2.5, # scale factor for the logo
        tsp_quality_factor = 50,
        filename = "julia_hd.mp4",
    )

    fast_options = (
        npoints = 1001, # rough number of points for the shape => number of circles
        nplay_frames = 600, # number of frames for the animation of fourier
        nruns = 1, # how often it's drawn
        nend_frames = 200,  # number of frames in the end
        width = 1000,
        height = 768,
        shape_scale = 1.5, # scale factor for the logo
        tsp_quality_factor = 40,
        filename = "julia_fast.mp4",
    )

    gif_options = (
        npoints = 651, # rough number of points for the shape => number of circles
        nplay_frames = 600, # number of frames for the animation of fourier
        nruns = 2, # how often it's drawn
        nend_frames = 0,  # number of frames in the end
        width = 350,
        height = 219,
        shape_scale = 0.8, # scale factor for the logo
        tsp_quality_factor = 80,
        filename = "gifs/julia_logo_dft.gif",
    )
    return animate_fourier(gif_options)
end

main()

@gpucce
Copy link
Member

gpucce commented Feb 27, 2022

Hi, you need to change this line:

return render(video; pathname = joinpath(@__DIR__, options.filename))

with something like

return render(video; pathname = "path2gif.gif")

Can you tell if this does it?

@aburousan
Copy link
Contributor Author

Thanks ... Now it's working like a charm...
If you don't mind, I have another question.
How can we save a particular frame of the animation as svg? And how can we make a Fourier plot for any random word(text)?

@ArbitRandomUser
Copy link
Contributor

ArbitRandomUser commented Feb 27, 2022

running `render(video,tempdirecory='moviedir',pathname="") will save each frame as .png in moviedir

as of now there is seems to be no way to get svg of a frame from render , the frame is returned rasterized for render to stitch it.
(someone who knows the innards of Javis better than me plis confirm)

@gpucce
Copy link
Member

gpucce commented Feb 27, 2022

Hi, I also don't think it is possible right away, perhaps playing a bit with Javis code.

@aburousan would like to try and open a PR to fix the example? If you don't no worries I will do it! :)

@aburousan
Copy link
Contributor Author

Sure

@Wikunia
Copy link
Member

Wikunia commented Feb 27, 2022

Currently svg isn't directly supported but simply because we didn't find a good way to make use of it in animations. It would be fairly simple though to render the single images as svgs as it's supported by Luxor. You can search for PNG inside Javis and replace it with SVG. That should be all there is to it if you are only interested in the single frames in the temporary directory

@ArbitRandomUser
Copy link
Contributor

Currently svg isn't directly supported but simply because we didn't find a good way to make use of it in animations. It would be fairly simple though to render the single images as svgs as it's supported by Luxor. You can search for PNG inside Javis and replace it with SVG. That should be all there is to it if you are only interested in the single frames in the temporary directory

Simply changing to .png might not quite work like how they want exactly ...right ? , by the time we call Image.save to save it to tempdir we have already rasterized the image into frame_image, i dont know if Image.save will convert it back to svg , but even if it does you wont get the original vector image as you would have got if Luxor wrote the svg.

@Wikunia
Copy link
Member

Wikunia commented Feb 27, 2022

Ah you're right I think before we added layer functionality this was actually as simple as I described but now it would be a bit more involved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants