Kinematic system
This page explains how the kinematic API described in the Kinematics section is implemented, and what a developer has to provide so that a new optical element, ray or beam type can be moved with it.
Kinematic traits
Analogous to the BeamletOptics.AbstractShapeTrait of the Geometry representation, the kinematic API is built on a trait that is dispatched on via multiple dispatch. Every public kinematic function, e.g. translate3d!(x, offset), forwards to a trait-specific method translate3d!(kinematic_trait_of(x), x, offset). As on the Geometry representation page, solid arrows are labeled with the field that leads from one type to the next, dotted arrows point to subtypes.
BeamletOptics.AbstractKinematicTrait Type
The kinematic trait defines whether an entity can be moved by the kinematic API (translate3d!, rotate3d!, ...). It is returned by kinematic_trait_of and follows the same dispatch pattern as AbstractShapeTrait: every public function e.g. translate3d!(x, args...) forwards to translate3d!(kinematic_trait_of(x), x, args...).
Two traits are defined:
Static:xcannot be moved, every kin. function throws anArgumentErrorMovable:xcan be moved; its frame (OrientedorDirected) selects orientation- or direction-based behaviour
A subtype of a movable abstract type can opt out of the kinematic API by declaring its own kinematic_trait_of method, e.g.
struct FixedMirror{T, S <: AbstractShape{T}} <: AbstractObject{T}
shape::S
end
kinematic_trait_of(::FixedMirror) = Static()Every kinematic function on a FixedMirror now throws an ArgumentError; its getters (position, orientation, ...) stay available.
Containers
All members of a container (ObjectGroup, UnionSDF/DifferenceSDF, AbstractBeamGroup) must be either all Static or all Movable. Frames can still be mixed. This must be checked in the respective constructors; nesting is then covered because a nested container already has a uniform class from its own constructor. The container then takes that class: Static if all members are Static, else Movable(Oriented()). All shapes returned by shape(object) of a MultiShape object must be movable, since MultiShape objects (e.g. a CubeBeamsplitter) have no shared constructor to enforce this.
BeamletOptics.kinematic_trait_of Function
kinematic_trait_of(x) -> AbstractKinematicTraitReturns the AbstractKinematicTrait of x. Defaults to Static(). Movable types declare Movable(Oriented()) or Movable(Directed()).
kinematic_trait_of(c::AbstractCompositeSDF)A composite takes the kinematic class of its operands, which the constructor ensures to be either all static or all movable, see BeamletOptics.AbstractKinematicTrait.
Static and movable entities
Whether an entity can be moved at all is defined by its trait. The fallback of BeamletOptics.kinematic_trait_of is BeamletOptics.Static, so types that do not opt in cannot be moved. The abstract types BeamletOptics.AbstractObject, BeamletOptics.AbstractRay, BeamletOptics.AbstractBeam and BeamletOptics.AbstractBeamGroup declare themselves BeamletOptics.Movable, so a new subtype of them only has to implement the kinematic primitives listed below.
BeamletOptics.Static Type
Static <: AbstractKinematicTraitRepresents a value that cannot be moved. Every kinematic function throws an ArgumentError; the getters (e.g. position, orientation) stay available. This is the fallback of kinematic_trait_of.
BeamletOptics.Movable Type
Movable{F <: AbstractKinematicFrame} <: AbstractKinematicTraitRepresents a value that can be moved by the kinematic API. The frame field (Oriented or Directed) selects orientation- or direction-based behaviour of the derived functions.
Rotations are applied about the own position of the value unless a pivot is passed explicitly. A rotation axis can have any non-zero length (it is normalized internally).
Kinematic functions
translate3d!: movesxby anoffsetvector (primitive, implemented per type)rotate3d!: rotatesxby a rotation matrixRaboutposition(x), or about a givenpivotif one is passed (theR-only form is the primitive, implemented per type; the axis/angle and pivot forms are derived from it)translate_to3d!: movesxso thatposition(x)coincides with a target pointxrotate3d!/yrotate3d!/zrotate3d!: rotatexby an angleθ[rad] about the global x-, y- or z-axis throughposition(x)align3d!: rotatesxaboutposition(x)so thatdirection(x)is aligned with a target vectorreset_translation3d!: movesxso thatposition(x)is the global origin; available for everyMovable, including rays, beams and beam groupsreset_rotation3d!: only available forOrientedvalues, where it rotatesxback to identityorientation; forDirectedvalues (rays, beams) it throws anArgumentError, usealign3d!insteaddirection: forOrientedvalues this is the local y-axis,orientation(x)[:, 2];Directedvalues provide their own getter
Sources (rays, beams and beam groups) are additionally reset to their untraced start state by every one of the functions above: a moved but already-traced source would otherwise keep rays or child beams belonging to the old, now geometrically wrong, light path. Moving a beam that is not the root of its beam tree (e.g. one created by a beamsplitter interaction) throws an ArgumentError; move its root beam instead.
Implementation reqs.
If kinematic_trait_of(::Foo) = Movable(...) is declared, Foo must implement the following:
positiontranslate3d!(::Movable, x::Foo, offset): movesxbyoffsetrotate3d!(::Movable, x::Foo, R::AbstractMatrix): rotatesxbyRaboutposition(x)
All other kin. functions listed above are derived from these two primitives.
sourceOriented and directed frames
The frame of a BeamletOptics.Movable entity selects whether the derived functions work on a full local coordinate system or only on a direction vector. Shapes, objects and beam groups are BeamletOptics.Oriented, whereas rays and beams are BeamletOptics.Directed.
BeamletOptics.AbstractKinematicFrame Type
Reference frame of a Movable value, either Oriented or Directed.
BeamletOptics.Oriented Type
Oriented <: AbstractKinematicFrameReference frame of a movable value with a full local coordinate system, e.g. shapes, objects and beam groups.
Implementation reqs.
position/position!orientation/orientation!: a right-handed orthonormal 3x3 matrix
direction returns the local y-axis, i.e. orientation(x)[:, 2]. reset_rotation3d! rotates x by transpose(orientation(x)) about its position and then sets the orientation to the identity.
BeamletOptics.Directed Type
Directed <: AbstractKinematicFrameReference frame of a movable value that only has a direction but no orientation, e.g. rays and beams.
Implementation reqs.
positiondirection: the direction getter of the type
reset_rotation3d! throws an ArgumentError, use align3d! instead.
Type-specific implementation requirements
The primitives translate3d!(::Movable, x, offset) and rotate3d!(::Movable, x, R) are implemented differently for the individual abstract types. The requirements for subtypes are listed in the Kinematic section of the respective docstrings:
BeamletOptics.AbstractObject: the primitives forward to theBeamletOptics.AbstractShapeTraitof the object, seeBeamletOptics.SingleShapeandBeamletOptics.MultiShapeBeamletOptics.AbstractRay: only subtypes carrying direction-dependent data (e.g. the field vector of aPolarizedRay) need their ownrotate3d!BeamletOptics.AbstractBeam: either implement_component_beamsor the two primitives; every move resets the beam viaempty!BeamletOptics.AbstractBeamGroup: moves itsbeamsrigidly about the groupcenter