Live rendering
render! generates new plots on every call. For animations and interactive applications, where components are moved and the system is re-solved many times per second, use live_render! instead. It returns a handle that re-synchronizes the existing plots with the current simulation state via update_render!:
using GLMakie, BeamletOptics
fig = Figure()
ax = LScene(fig[1, 1])
hsys = live_render!(ax, system) # geometry is generated once
hbeam = live_render!(ax, beam) # all ray segments bundled into a single plot
zrotate3d!(mirror, 1e-3)
solve_system!(system, beam)
update_render!(hsys) # moved components: only their model transformation changes
update_render!(hbeam) # beam path: point buffer is replaced in placeObjects and systems: the geometry is rendered once with
render!. Kinematic changes (translate3d!,rotate3d!, ...) are then applied as a rigid model transformation of the existing plots, which costs microseconds regardless of the mesh resolution.Rays, beams and beam groups: all segments are drawn by a single
linesegmentsplot, so the number of plots does not grow with the number of rays. The number of segments may change between updates, e.g. when a component is moved out of the beam path.Gaussian beamlets: the 1/e² envelope of all segments is merged into a single mesh. This applies to
GaussianBeamlets,AstigmaticGaussianBeamlets and groups of astigmatic beamlets, of which everyrender_every-th beamlet is rendered.
live_render! draws the same plots as render!, see Rays and beams and Gaussian beamlets; it only keeps the data they are drawn from. Use remove_render! to delete the plots of a handle.
Render handle protocol
Every handle returned by live_render! is a BeamletOptics.AbstractRenderHandle. Packages built on BeamletOptics, e.g. BeamletOpticsGUI, use the handles through a protocol instead of the concrete handle types of the Makie extension. There are three abstract handle types: BeamletOptics.AbstractObjectRenderHandle for a component, BeamletOptics.AbstractSystemRenderHandle for a system and BeamletOptics.AbstractBeamRenderHandle for a ray, beam or beam group. They share the accessors below.
BeamletOptics.rendered Function
rendered(h::AbstractRenderHandle)The object, system or beam that the render handle h shows, see AbstractRenderHandle.
BeamletOptics.render_plots Function
render_plots(h::AbstractRenderHandle) -> AbstractVectorThe plots of the render handle h; of a system handle, the plots of all its object handles. The plots of an object handle may be replaced by update_render!, hence do not keep them.
A system handle groups the handles of its objects. It can be searched and changed at runtime:
BeamletOptics.render_children Function
render_children(h::AbstractSystemRenderHandle) -> AbstractVector{<:AbstractObjectRenderHandle}The object handles of the system handle h, one per rendered object (the objects of groups, not the groups). Change them via push! and delete! of h, not via the returned vector.
BeamletOptics.render_parent Function
render_parent(h::AbstractSystemRenderHandle, obj)The object group of the system of h that holds obj (an object or a group), or nothing if obj is at the top level or not in h.
Base.push! Method
push!(h::AbstractSystemRenderHandle, oh::AbstractObjectRenderHandle) -> hAdds the object handle oh at the top level of the system handle h, e.g. of an object added to the scene after live_render!, such that update_render! and pick_object of h include it.
Base.delete! Method
delete!(h::AbstractSystemRenderHandle, oh::AbstractObjectRenderHandle) -> hRemoves the object handle oh from the system handle h. Its plots stay in the axis, delete them via remove_render!(oh).
push! adds an object handle at the top level, delete! removes it from the system handle without deleting its plots (use remove_render! for that). update_render!, remove_render! and pick_object work on any system handle through these accessors, so a handle type of your own only needs to implement them.
An object that is added to a system at runtime, see Changing a system, is rendered into the handle of the system, and removed from it again, by:
BeamletOptics.live_render! Method
live_render!(h::AbstractSystemRenderHandle, obj::AbstractObject; kwargs...) -> Vector{<:AbstractObjectRenderHandle}Live-renders obj into the axis of the system handle h and adds it to h, e.g. an object that was added to the system via push!(system, obj) after h was created. An object group is rendered per object, with its hierarchy known to render_parent, like the groups of live_render!(ax, system). Returns the new object handles, one per rendered object. The system of h is not changed. An obj that h already renders throws an ArgumentError.
Keyword arguments are passed on as for render!. Implemented by the handle returned by live_render!(ax, system). A system handle that does not implement it throws an ArgumentError: render obj via live_render!(ax, obj) and add its handle via push!(h, oh) instead.
BeamletOptics.remove_render! Method
remove_render!(h::AbstractSystemRenderHandle, obj::AbstractObject)Removes obj from the system handle h: deletes the plots of obj (of all objects of an object group) from the axis and removes their object handles from h, e.g. after delete!(system, obj). The system of h is not changed. Nothing happens for an obj that h does not render. An object within a group can not be removed on its own and throws an ArgumentError: remove the group instead.
push!(system, lens)
live_render!(hsys, lens) # draws the lens, hsys now updates and picks it
delete!(system, lens)
remove_render!(hsys, lens) # deletes its plots and its handleBeam handles report how they were drawn:
BeamletOptics.render_settings Function
render_settings(h::AbstractBeamRenderHandle) -> NamedTupleThe settings with which the beam handle h draws its beam, at least flen (length of a final ray without intersection [m]) and render_every (every how many beams of a beam group are drawn, 1 for other beams), e.g. to find the drawn segments of a beam.
Overlays that are not part of a component, e.g. markers, are drawn with the function form of live_render!, which returns a handle for the plots draw creates and moves them together with x:
BeamletOptics.live_render! Method
live_render!(draw, axis, x) -> AbstractObjectRenderHandleLive-renders x via the function draw: draw() plots x in its current pose into the axis, and the returned handle moves these plots with x like those of an object, see live_render!, e.g. a marker of a thing that render! does not draw. x has a position and an orientation (or a direction), e.g. a source or an own movable type (see kinematic_trait_of):
h = live_render!(ax, src) do
scatter!(ax, [Point3f(position(src))]; color = :orange)
endIf no suitable backend is loaded, a MissingBackendError will be thrown.
pick_object finds the object that owns a picked plot. By default all plots of an object select it; a method of pickable_plots restricts this, e.g. to exclude an outline. The colors of the material classes of the active look are available via look_colors:
BeamletOptics.pickable_plots Function
pickable_plots(x, plots) -> AbstractVectorThe plots among the plots of x that select x in pick_object, by default all. Add a method for the type of x to exclude plots, e.g. the outline of a marker, whose clicks should reach what lies behind it.
BeamletOptics.look_colors Function
look_colors() -> Dict{Symbol, RGBf}The colors of the material classes (:refractive, :reflective, :coating, :polarizer, :detector, :mechanics, :interface) of the active look, see set_render_look, e.g. to recolor the rendered objects of a class for a dark background.
Needs the Makie extension, i.e. a loaded Makie backend.