Skip to content

Commit

Permalink
Fix merging of AnimationTracks.
Browse files Browse the repository at this point in the history
  • Loading branch information
tkoolen committed Aug 5, 2019
1 parent ca6e588 commit 9d01060
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 10 deletions.
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

0 comments on commit 9d01060

Please sign in to comment.