From 158df26735b5819d724e928c85e094c2efb98e1d Mon Sep 17 00:00:00 2001 From: Fredrik Bagge Carlson Date: Thu, 26 Oct 2023 12:36:27 +0200 Subject: [PATCH] add recursive subsystem rendering --- docs/src/examples/pendulum.md | 1 + docs/src/examples/spherical_pendulum.md | 1 + docs/src/examples/spring_damper_system.md | 1 + docs/src/examples/spring_mass_system.md | 1 + docs/src/examples/three_springs.md | 1 + ext/Render.jl | 40 ++++++++++++++++------- 6 files changed, 34 insertions(+), 11 deletions(-) diff --git a/docs/src/examples/pendulum.md b/docs/src/examples/pendulum.md index 00a3ea1e..5a566113 100644 --- a/docs/src/examples/pendulum.md +++ b/docs/src/examples/pendulum.md @@ -71,6 +71,7 @@ Multibody.jl supports automatic 3D rendering of mechanisms, we use this feature ```@example spring_mass_system import WGLMakie Multibody.render(model, sol; z = -5, filename = "pendulum.gif") # Use "pendulum.mp4" for a video file +nothing # hide ``` ![animation](spherical.gif) diff --git a/docs/src/examples/spherical_pendulum.md b/docs/src/examples/spherical_pendulum.md index 36da05b5..50e50bf0 100644 --- a/docs/src/examples/spherical_pendulum.md +++ b/docs/src/examples/spherical_pendulum.md @@ -40,6 +40,7 @@ Multibody.jl supports automatic 3D rendering of mechanisms, we use this feature ```@example spring_mass_system import WGLMakie Multibody.render(model, sol; z = -5, filename = "spherical.gif") # Use "spherical.mp4" for a video file +nothing # hide ``` ![animation](spherical.gif) \ No newline at end of file diff --git a/docs/src/examples/spring_damper_system.md b/docs/src/examples/spring_damper_system.md index cafb4aaa..2cf9cb4c 100644 --- a/docs/src/examples/spring_damper_system.md +++ b/docs/src/examples/spring_damper_system.md @@ -82,6 +82,7 @@ Multibody.jl supports automatic 3D rendering of mechanisms, we use this feature ```@example spring_mass_system import WGLMakie Multibody.render(model, sol; z = -5, filename = "springdamper.gif") # Use "springdamper.mp4" for a video file +nothing # hide ``` ![animation](springdamper.gif) \ No newline at end of file diff --git a/docs/src/examples/spring_mass_system.md b/docs/src/examples/spring_mass_system.md index 5c8ee19d..3dcbe02b 100644 --- a/docs/src/examples/spring_mass_system.md +++ b/docs/src/examples/spring_mass_system.md @@ -64,6 +64,7 @@ Multibody.jl supports automatic 3D rendering of mechanisms, we use this feature ```@example spring_mass_system import WGLMakie Multibody.render(model, sol; z = -5, filename = "springmass.gif") # Use "springmass.mp4" for a video file +nothing # hide ``` ![animation](springmass.gif) \ No newline at end of file diff --git a/docs/src/examples/three_springs.md b/docs/src/examples/three_springs.md index 72221979..cd261ea0 100644 --- a/docs/src/examples/three_springs.md +++ b/docs/src/examples/three_springs.md @@ -51,6 +51,7 @@ Multibody.jl supports automatic 3D rendering of mechanisms, we use this feature ```@example spring_mass_system import WGLMakie Multibody.render(model, sol; z = -5, filename = "three_springs.gif") # Use "three_springs.mp4" for a video file +nothing # hide ``` ![animation](three_springs.gif) \ No newline at end of file diff --git a/ext/Render.jl b/ext/Render.jl index f6a57f3a..a38a492b 100644 --- a/ext/Render.jl +++ b/ext/Render.jl @@ -64,10 +64,7 @@ function render(model, sol, t = 0.0 t = Observable(timevec[1]) - for subsys in model.systems - system_type = get_systemtype(subsys) - render!(scene, system_type, subsys, sol, t) - end + recursive_render!(scene, model, sol, t) record(scene, filename, timevec; framerate) do time t[] = time @@ -95,16 +92,28 @@ function render(model, sol, time::Real; ] # t = Observable(time) + recursive_render!(scene, model, sol, t) + fig, t +end + +""" +Internal function: Recursively render all subsystem components of a multibody system. If a particular component returns `true` from its `render!` method, indicating that the component performaed rendering, the recursion stops. +""" +function recursive_render!(scene, model, sol, t) for subsys in model.systems system_type = get_systemtype(subsys) - render!(scene, system_type, subsys, sol, t) + did_render = render!(scene, system_type, subsys, sol, t) + if !did_render + recursive_render!(scene, subsys, sol, t) + end end - fig, t end +render!(scene, ::Any, args...) = false # Fallback for systems that have no rendering + """ - render!(scene, ::typeof(ComponentConstructor), sys, sol, t) + did_render::Bool = render!(scene, ::typeof(ComponentConstructor), sys, sol, t) Each component that can be rendered must have a `render!` method. This method is called by `render` for each component in the system. @@ -117,6 +126,9 @@ thing = @lift begin end mesh!(scene, thing; style...) ``` + +# Returns +A boolean indicating whether or not the component performed any rendering. Typically, all custom methods of this function should return `true`, while the default fallback method is the only one returning false. """ function render!(scene, ::typeof(Body), sys, sol, t) thing = @lift begin # Sphere @@ -150,6 +162,7 @@ function render!(scene, ::typeof(Body), sys, sol, t) # Makie.GeometryBasics.Cylinder(origin, extremity, radius) # end # mesh!(scene, thing, color=:purple) + true end function render!(scene, ::typeof(World), sys, sol, t) @@ -174,6 +187,7 @@ function render!(scene, ::typeof(World), sys, sol, t) Makie.GeometryBasics.Cylinder(O, z, radius) end mesh!(scene, thing, color=:blue) + true end function render!(scene, ::typeof(Revolute), sys, sol, t) @@ -185,6 +199,7 @@ function render!(scene, ::typeof(Revolute), sys, sol, t) Sphere(point, 0.1) end mesh!(scene, thing, color=:red) + true end function render!(scene, ::typeof(Spherical), sys, sol, t) @@ -195,9 +210,10 @@ function render!(scene, ::typeof(Spherical), sys, sol, t) Sphere(point, 0.1) end mesh!(scene, thing, color=:yellow) + true end -render!(scene, ::typeof(FreeMotion), sys, sol, t) = () +render!(scene, ::typeof(FreeMotion), sys, sol, t) = true function render!(scene, ::typeof(FixedTranslation), sys, sol, t) @@ -210,6 +226,7 @@ function render!(scene, ::typeof(FixedTranslation), sys, sol, t) Makie.GeometryBasics.Cylinder(origin, extremity, radius) end mesh!(scene, thing, color=:purple) + true end function render!(scene, ::typeof(BodyShape), sys, sol, t) @@ -231,6 +248,7 @@ function render!(scene, ::typeof(BodyShape), sys, sol, t) # Makie.GeometryBasics.Sphere((r1+r2) ./ 2, 0.1f0) # end # mesh!(scene, thing, color=:purple) + true end @@ -245,6 +263,7 @@ function render!(scene, ::typeof(Damper), sys, sol, t) Makie.GeometryBasics.Cylinder(origin, extremity, radius) end mesh!(scene, thing, color=:gray) + true end @@ -255,12 +274,10 @@ function render!(scene, ::typeof(Spring), sys, sol, t) spring_mesh(r1,r2) end plot!(scene, thing, color=:blue) + true end - -render!(scene, ::Any, args...) = () # Fallback for systems that have no rendering - function render!(scene, ::Function, sys, sol, t, args...) # Fallback for systems that have at least two frames count(ModelingToolkit.isframe, sys.systems) == 2 || return try @@ -275,6 +292,7 @@ function render!(scene, ::Function, sys, sol, t, args...) # Fallback for systems mesh!(scene, thing, color=:green, alpha=0.5) catch end + true end function spring_mesh(p1, p2; n_wind=6, radius=0.1f0, N=200)