Animation with Meshes.jl

How can I animate the Box defined by Meshes.jl?

I thought the following code might work.


using GLMakie, Meshes, Rotations

b = Meshes.Box((-1, -1, -1), (1, 1, 1))

obs_b =  Observable(b)

fig = Figure(size = (800, 500))
ax = Axis3(
    fig[1, 1],
)

hidespines!(ax)
hidedecorations!(ax)

Meshes.viz(obs_b)

record(fig, "animation.gif", framerate = 20) do idx

    # update observables
    obs_b[] = b |> Rotate(AngleAxis(0.2, 1.0, 0.0, 0.0))
end

However, this gives an error:

ERROR: MethodError: Cannot `convert` an object of type TransformedGeometry{𝔼{3}, CoordRefSystems.Cart
esian3D{CoordRefSystems.NoDatum, Unitful.Quantity{Float64, Unitful.Dimensions{(Unitful.Dimension{:Length}(1//1),)}(), Unitful.FreeUnits{(Unitful.Unit{:Meter, Unitful.Dimensions{(Unitful.Dimension{:Length}(1//1),)}()}(0, 1//1),), Unitful.Dimensions{(Unitful.Dimension{:Length}(1//1),)}(), nothing}}}, Meshes.Box{𝔼{3}, CoordRefSystems.Cartesian3D{CoordRefSystems.NoDatum, Unitful.Quantity{Float64, Unitful.Dim
ensions{(Unitful.Dimension{:Length}(1//1),)}(), Unitful.FreeUnits{(Unitful.Unit{:Meter, Unitful.Dimensions{(Unitful.Dimension{:Length}(1//1),)}()}(0, 1//1),), Unitful.Dimensions{(Unitful.Dimension{:Length}(1//1),)}(), nothing}}}}, Rotate{AngleAxis{Float64}}} to an object of type Meshes.Box{𝔼{3}, CoordRef
Systems.Cartesian3D{CoordRefSystems.NoDatum, Unitful.Quantity{Float64, Unitful.Dimensions{(Unitful.Dimension{:Length}(1//1),)}(), Unitful.FreeUnits{(Unitful.Unit{:Meter, Unitful.Dimensions{(Unitful.Dimension{:Length}(1//1),)}()}(0, 1//1),), Unitful.Dimensions{(Unitful.Dimension{:Length}(1//1),)}(), nothing}}}}
The function `convert` exists, but no method is defined for this combination of argument types.

Hi @Mizu49 , please tag the question with meshes or post it in the Geo category of this forum, otherwise we don’t get a notification.

To answer your question, notice that the rotation of an axis-aligned Box is no longer an axis-aligned box, but a TransformedBox:

julia> b |> Rotate(AngleAxis(0.2, 1.0, 0.0, 0.0))
TransformedBox
β”œβ”€ geometry: Box(min: (x: -1.0 m, y: -1.0 m, z: -1.0 m), max: (x: 1.0 m, y: 1.0 m, z: 1.0 m))
└─ transform: Rotate(rot: [1.0 0.0 0.0; 0.0 0.980067 -0.198669; 0.0 0.198669 0.980067])

This means that your Observable must hold any type of Geometry, not just Box. You can solve the issue by defining:

obs_b = Observable{Any}(b)

There is another issue in your code where you update the observable with a constant, instead of with the current value of the observable.

1 Like

This error message is telling you that the Observable of Box cannot hold a TransformedGeometry. The error message could have been clearer though given that this is a common pattern with Observable.

2 Likes

@juliohm
Thank you for your comments!

I still have trouble with the following updated code…

using GLMakie, Meshes, Rotations

b = Meshes.Box((-1, -1, -1), (1, 1, 1))

obs_b = Observable{Any}(b)

fig = Figure(size = (800, 500))
ax = Axis3(
    fig[1, 1],
)

hidespines!(ax)
hidedecorations!(ax)

Meshes.viz(obs_b)

framerate = 30
timestamps = range(0, 2, step=1/framerate)

record(fig, "animation.gif", timestamps, framerate = framerate) do idx

    # update observables
    obs_b[] = obs_b[] |> Rotate(AngleAxis(0.2, 1.0, 0.0, 0.0))
end

obs_b[] = obs_b[] |> Rotate(AngleAxis(0.2, 1.0, 0.0, 0.0)) gives an error.

ERROR: MethodError: Cannot `convert` an object of type 
  GeometrySet{𝔼 {3},CoordRefSystems.Cartesian{CoordRefSystems.NoDatum,3,Unitful.Quantity{Float64,𝐋 ,Unitful.FreeUnits{(m,),𝐋 ,nothing}}},TransformedGeometry{𝔼{3}, CoordRefSystems.Cartesian3D{CoordRefSyst
ems.NoDatum, Unitful.Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}}, Meshes.Box{𝔼{3}, C
oordRefSystems.Cartesian3D{CoordRefSystems.NoDatum, Unitful.Quantity{Float64, 𝐋, Unitful.FreeUnits{(m
,), 𝐋, nothing}}}}, Rotate{AngleAxis{Float64}}} } to an object of type 
  GeometrySet{𝔼 {3},CoordRefSystems.Cartesian{CoordRefSystems.NoDatum,3,Unitful.Quantity{Float64,𝐋 ,Unitful.FreeUnits{(m,),𝐋 ,nothing}}},Meshes.Box{𝔼{3}, CoordRefSystems.Cartesian3D{CoordRefSystems.NoDat
um, Unitful.Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}}}  }
The function `convert` exists, but no method is defined for this combination of argument types.

I believe the type convertion still not working with the Geometry and Observables.

Hi @Mizu49, the code looks fine to me. Could you try with a Triangle geometry instead to see if this issue is specific to Box?

Hi @juliohm ,

I tried with the Triangle geometry, and it looks file to me.


using GLMakie, Meshes, Rotations

geometry = Triangle((0, 0), (1, 0), (0, 1))

obs = Observable{Any}(geometry)

fig = Figure()
ax = Axis(
    fig[1, 1],
    limits = tuple(-1, 1, -1, 1)
)

Meshes.viz!(obs)

iter = 1:100

record(fig, "animation.gif", iter, framerate = 30) do idx

    # update observables
    obs[] = obs[] |> Rotate(0.2)
end

Result:
animation

I’m not sure why this code doesn’t work for Box geometry…

1 Like

Box is a primitive geometry for which we have various optimizations. These optimizations may be interfering with viz dispatch methods. Could you please file an issue on GitHub so that we can take a look at it?

@Mizu49 in the meantime, you can use quad = convert(Quadrangle, box) to produce the animation. The Quadrangle can be rotated without issues.

If your box is 3D, then you can use hexa = convert(Hexahedron, box).

The error message above indicates that somewhere in the code the TransformedBox is saved in a variable that holds a Box.