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

Fix merging of AnimationTracks. #124

Merged
merged 1 commit into from
Aug 5, 2019
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
17 changes: 7 additions & 10 deletions src/animations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ end

AnimationTrack{T}(name::String, jstype::String) where {T} = AnimationTrack(name, jstype, Pair{Int, T}[])

wider_js_type(::Type{<:Integer}) = Float64 # Javascript thinks everything is a `double`
wider_js_type(::Type{Float64}) = Float64
wider_js_type(x) = x

function Base.insert!(track::AnimationTrack, frame::Integer, value)
i = searchsortedfirst(track.events, frame; by=first)
if i <= length(track.events) && first(track.events[i]) == frame
Expand All @@ -22,16 +18,17 @@ function Base.insert!(track::AnimationTrack, frame::Integer, value)
end

function Base.merge!(a::AnimationTrack{T}, others::AnimationTrack{T}...) where T
l = length(a)
events = copy(a.events)
l = length(a.events)
for other in others
@assert other.name == a.name
@assert other.jstype == a.jstype
events_temp = similar(events, length(events) + length(other.events))
mergesorted!(events_temp, events, other.events; by=first)
events = events_temp
l += length(other.events)
end
a.events = unique(first, a.events) # TODO: use unique! in ≥ 1.1
events = similar(a.events, l)
mergesorted!(events, a.events, Iterators.flatten((other.events for other in others)))
combine!(events, by=first, combine=(a, b) -> b)
resize!(a.events, length(events))
copyto!(a.events, events)
return a
end

Expand Down
4 changes: 4 additions & 0 deletions src/atframe.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
wider_js_type(::Type{<:Integer}) = Float64 # Javascript thinks everything is a `double`
wider_js_type(::Type{Float64}) = Float64
wider_js_type(x) = x

function _setprop!(clip::AnimationClip, frame::Integer, prop::AbstractString, jstype::AbstractString, value)
T = wider_js_type(typeof(value))
track = get!(clip.tracks, prop) do
Expand Down
45 changes: 45 additions & 0 deletions src/util.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,25 @@
# Port of possible implementation of std::merge (second version),
# https://en.cppreference.com/w/cpp/algorithm/merge
# TODO: contribute to base.

"""
mergesorted!(dest::AbstractVector, a, b; by=identity, lt=isless)

Merge sorted iterators `a` and `b`, storing the result in `dest`.
`dest` should be of the appropriate length to store all elements of `a` and `b`;
it is not resized.

For equivalent elements in `a` and `b`, the elements from `a`
(preserving their original order) precede the elements from `b`
(preserving their original order).

Elements are compared by `(x, y) -> lt(by(x), by(y))`

The behavior is undefined if `dest` overlaps `a` or `b` (though the `a` and `b`
may overlap each other) or if `a` or `b` are not sorted.

Adapted from https://en.cppreference.com/w/cpp/algorithm/merge.
"""
@inline function mergesorted!(dest::AbstractVector, a, b; by=identity, lt=isless)
i = 1
it_a = iterate(a)
Expand Down Expand Up @@ -31,3 +50,29 @@
end
return dest
end

# from https://github.com/JuliaOpt/MathOptInterface.jl/blob/d3106f434293a2aae7c664a22a30a7bd4069111a/src/Utilities/functions.jl#L390.
# TODO: contribute to Base
function combine!(x::AbstractVector; by=identity, keep=x->true, combine)
@boundscheck issorted(x; by=by) || throw(ArgumentError("Input is not sorted."))
if length(x) > 0
i1 = firstindex(x)
for i2 in eachindex(x)[2:end]
if by(x[i1]) == by(x[i2])
x[i1] = combine(x[i1], x[i2])
else
if !keep(x[i1])
x[i1] = x[i2]
else
x[i1 + 1] = x[i2]
i1 += 1
end
end
end
if !keep(x[i1])
i1 -= 1
end
resize!(x, i1)
end
return x
end
20 changes: 20 additions & 0 deletions test/visualizer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,26 @@ end
end
end

@testset "AnimationTrack" begin
track1 = MeshCat.AnimationTrack{Float64}("foo", "bar")
@test track1.name == "foo"
@test track1.jstype == "bar"
insert!(track1, 0, 32.0)
@test track1.events == [0 => 32.0]
insert!(track1, 2, 64.0)
@test track1.events == [0 => 32.0, 2 => 64.0]
insert!(track1, 2, 65.0)
@test track1.events == [0 => 32.0, 2 => 65.0]

track2 = MeshCat.AnimationTrack{Float64}("foo", "bar")
insert!(track2, 1, 17.0)
insert!(track2, 2, 66.0)
insert!(track2, 5, 1.0)

merge!(track1, track2)
@test track1.events == [0 => 32.0, 1 => 17.0, 2 => 66.0, 5 => 1.0]
end

@testset "setvisible!" begin
v = vis[:box_to_hide]
setobject!(v, HyperRectangle(Vec(0., 0, 0), Vec(0.1, 0.2, 0.3)))
Expand Down