From cdb57cc17c516127b0342d363b1e510d453c3d1b Mon Sep 17 00:00:00 2001 From: Ran Gal Date: Sat, 3 Apr 2021 20:55:19 -0700 Subject: [PATCH] added some docstrings to the emitters components, exported the Source and CompositeSource data types and added a docmentation page for the new emitters. also added the using of the OpticSim.Emitters to the documentation script. --- docs/make.jl | 2 +- docs/src/emitters_new.md | 303 +++++++++++++++++++++++++++++++++++++++ src/Optical/Emitters.jl | 144 ++++++++++++++++++- 3 files changed, 443 insertions(+), 6 deletions(-) create mode 100644 docs/src/emitters_new.md diff --git a/docs/make.jl b/docs/make.jl index 3819485eb..7bf3b15f0 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -21,7 +21,7 @@ # SOFTWARE using Documenter -using OpticSim, OpticSim.Geometry +using OpticSim, OpticSim.Geometry, OpticSim.Emitters makedocs( sitename = "OpticSim.jl", diff --git a/docs/src/emitters_new.md b/docs/src/emitters_new.md new file mode 100644 index 000000000..ff43fc982 --- /dev/null +++ b/docs/src/emitters_new.md @@ -0,0 +1,303 @@ +# Emitters (NEW) + +Emitters create rays in a certain pattern, usually controlled by some parameters. Emitters are defined by Pixels and Spatial Layouts, and have a spectrum and an optical power distribution over the hemisphere. These are intrinsic physical properties of the emitter. + +The **basic emitter** ([`Source`](@ref sources)) is constructed as a combination of 4 basic elements and a 3D [`Transform`](@ref). The basic elements include: +- [`Spectrum`](@ref spectrum) +- [`Angular Power Distribution`](@ref angular_power_distribution) +- [`Rays Origins Distribution`](@ref rays_origins_distribution) +- [`Rays Directions Distribution`](@ref rays_directions_distribution) + +The [`OpticSim`](index.html) package comes with various implementations of each of these basic elements: +- Spectrum - the **generate** interface returns a tuple (power, wavelength) + * [`Emitters.Spectrum.Uniform`](@ref) - A flat spectrum bounded (default: from 450nm to 680nm). the range is sampled uniformly. + * [`Emitters.Spectrum.DeltaFunction`](@ref) - Constant wave length. + * [`Emitters.Spectrum.Measured`](@ref) - measured spectrum to compute emitter power and wavelength (created by reading CSV files – more details will follow). +- Angular Power Distribution - the interface **apply** returns an OpticalRay with modified power + * [`Emitters.AngularPower.Lambertian`](@ref) + * [`Emitters.AngularPower.Cosine`](@ref) + * [`Emitters.AngularPower.Gaussian`](@ref) +- Rays Origins Distribution - the interface **length** returns the number of samples, and **generate** returns the n'th sample. + * [`Emitters.Origins.Point`](@ref) - a single point + * [`Emitters.Origins.RectUniform`](@ref) - a uniformly sampled rectangle with user defined number of samples + * [`Emitters.Origins.RectGrid`](@ref) - a rectangle sampled in a grid fashion + * [`Emitters.Origins.Hexapolar`](@ref) - a circle (or an ellipse) sampled in an hexapolar fasion (rings) +- Rays Directions Distribution - the interface **length** returns the number of samples, and **generate** returns the n'th sample. + * [`Emitters.Directions.Constant`](@ref) + * [`Emitters.Directions.RectGrid`](@ref) + * [`Emitters.Directions.UniformCone`](@ref) + * [`Emitters.Directions.HexapolarCone`](@ref) + +## [Examples of Basic Emitters](@id basic_emitters) + +**Note**: All the examples on this page assumes the followin statement was executed: + +```@example +using OpticSim, OpticSim.Geometry, OpticSim.Emitters +``` + +### Point origin with various Direction distributions +```@example +using OpticSim, OpticSim.Geometry, OpticSim.Emitters # hide +src = Sources.Source(origins=Origins.Point(), directions=Directions.RectGrid(π/4, π/4, 15, 15)) +Vis.draw(src, debug=true) +Vis.save("assets/emitters_example_rect_grid.png") # hide +nothing #hide +``` + +```@raw html + + + +
+ + + + +An example of RectGrid Direction Distribution +
+``` + +```@example +using OpticSim, OpticSim.Geometry, OpticSim.Emitters # hide +src = Sources.Source(origins=Origins.Point(), directions=Directions.UniformCone(π/6, 1000)) +Vis.draw(src, debug=true) +Vis.save("assets/emitters_example_uniform_cone.png") # hide +nothing #hide +``` + +```@raw html + + + +
+ + + + +An example of UniformCone Direction Distribution with 1000 sampled directions +
+``` + +```@example +using OpticSim, OpticSim.Geometry, OpticSim.Emitters # hide +src = Sources.Source(origins=Origins.Point(), directions=Directions.HexapolarCone(π/6, 10)) +Vis.draw(src, debug=true) +Vis.save("assets/emitters_example_hexapolar_cone.png") # hide +nothing #hide +``` + +```@raw html + + + +
+ + + + +An example of HexapolarCone Direction Distribution +
+``` + +### Various origins distributions + +```@example +using OpticSim, OpticSim.Geometry, OpticSim.Emitters # hide +src = Sources.Source(origins=Origins.RectGrid(1.0, 1.0, 10, 10), directions=Directions.Constant()) +Vis.draw(src, debug=true) +Vis.save("assets/emitters_example_origin_rectgrid.png") # hide +nothing #hide +``` + +```@raw html + + + +
+ + + + +An example of RectGrid origin distribution +
+``` + +```@example +using OpticSim, OpticSim.Geometry, OpticSim.Emitters # hide +src = Sources.Source(origins=Origins.Hexapolar(5, 1.0, 2.0), directions=Directions.Constant()) +Vis.draw(src, debug=true) +Vis.save("assets/emitters_example_origin_hexapolar.png") # hide +nothing #hide +``` + +```@raw html + + + +
+ + + + +An example of Hexapolar origin distribution +
+``` + +### Examples of Angular Power Distribution + +In these example, the arrow width is proportional to the ray power. + +```@example +using OpticSim, OpticSim.Geometry, OpticSim.Emitters # hide +src = Sources.Source( + origins=Origins.Hexapolar(1, 8.0, 8.0), # Hexapolar Origins + directions=Directions.RectGrid(π/6, π/6, 15, 15), # RectGrid Directions + power=AngularPower.Cosine(10.0) # Cosine Angular Power +) +Vis.draw(src, debug=true) +Vis.save("assets/emitters_example_angular1.png") # hide +nothing #hide +``` + +```@raw html + + + +
+ + + + +An example of Cosine angular power distribution +
+``` + +```@example +using OpticSim, OpticSim.Geometry, OpticSim.Emitters # hide +src = Sources.Source( + origins=Origins.RectGrid(1.0, 1.0, 3, 3), # RectGrid Origins + directions=Directions.HexapolarCone(π/6, 10), # HexapolarCone Directions + power=AngularPower.Gaussian(2.0, 2.0) # Gaussian Angular Power +) +Vis.draw(src, debug=true) +Vis.save("assets/emitters_example_angular2.png") # hide +nothing #hide +``` + +```@raw html + + + +
+ + + + +An example of Gaussian angular power distribution +
+``` + +### Composite Sources - Display Example + +```@example +using OpticSim, OpticSim.Geometry, OpticSim.Emitters # hide + +# construct the emitter's basic components +S = Spectrum.Uniform() +P = AngularPower.Lambertian() +O = Origins.RectGrid(1.0, 1.0, 3, 3) +D = Directions.HexapolarCone(deg2rad(5.0), 3) + +# construct the srouce. in this example a "pixel" source will contain only one source as we are simulating a "b/w" display. +# for RGB displays we can combine 3 sources to simulate "a pixel". +Tr = Transform(Vec3(0.5, 0.5, 0.0)) +source1 = Sources.Source(Tr, S, O, D, P) + +# create a list of pixels - each one is a composite source +pixels = Vector{Sources.CompositeSource{Float64}}(undef, 0) +for y in 1:5 # image_height + for x in 1:10 # image_width + # pixel position relative to the display's origin + local pixel_position = Vec3((x-1) * 1.1, (y-1) * 1.5, 0.0) + local Tr = Transform(pixel_position) + + # constructing the "pixel" + pixel = Sources.CompositeSource(Tr, [source1]) + + push!(pixels, pixel) + end +end + +Tr = Transform(Vec3(0.0, 0.0, 0.0)) +my_display = Sources.CompositeSource(Tr, pixels) + +Vis.draw(my_display) # render the display - nothing bu the origins primities +rays = AbstractArray{OpticalRay{Float64, 3}}(collect(my_display)) # collect the rays generated by the display +Vis.draw!(rays) # render the rays + +Vis.save("assets/emitters_example_composite_display.png") # hide +nothing #hide +``` + +```@raw html + + + +
+ + + + +A display example using composite sources. +
+``` + + + +## [Spectrum](@id spectrum) + +```@docs +Emitters.Spectrum.Uniform +Emitters.Spectrum.DeltaFunction +Emitters.Spectrum.Measured +``` + +## [Angular Power Distribution](@id angular_power_distribution) + +```@docs +Emitters.AngularPower.Lambertian +Emitters.AngularPower.Cosine +Emitters.AngularPower.Gaussian +``` + +## [Rays Origins Distribution](@id rays_origins_distribution) + +```@docs +Emitters.Origins.Point +Emitters.Origins.RectUniform +Emitters.Origins.RectGrid +Emitters.Origins.Hexapolar +``` + +## [Rays Directions Distribution](@id rays_directions_distribution) + +```@docs +Emitters.Directions.Constant +Emitters.Directions.RectGrid +Emitters.Directions.UniformCone +Emitters.Directions.HexapolarCone +``` + +## [Sources](@id sources) + +```@docs +Emitters.Sources.Source +Emitters.Sources.CompositeSource +``` + + + + + + diff --git a/src/Optical/Emitters.jl b/src/Optical/Emitters.jl index 5b918975e..a4a9d5fe6 100644 --- a/src/Optical/Emitters.jl +++ b/src/Optical/Emitters.jl @@ -47,9 +47,17 @@ const UNIFORMLONG = 0.680 #um #--------------------------------------- # Uniform Spectrum #--------------------------------------- +""" +Encapsulates a flat spectrum range which is sampled uniformly. Unless stated diferrently, the range used will be 450nm to 680nm. + +```julia +Uniform(low::T, high::T) where {T<:Real} +Uniform(::Type{T} = Float64) where {T<:Real} +``` +""" struct Uniform{T} <: AbstractSpectrum{T} low_end::T - high_end::T + high_end::T # user defined range of spectrum function Uniform(low::T, high::T) where {T<:Real} @@ -68,6 +76,13 @@ Emitters.generate(s::Uniform{T}) where {T} = (T(1), rand(Distributions.Uniform(s #--------------------------------------- # Delta Function Spectrum #--------------------------------------- +""" +Encapsulates a constant spectrum. + +```julia +DeltaFunction{T<:Real} +``` +""" struct DeltaFunction{T<:Real} <: AbstractSpectrum{T} λ::T end @@ -79,6 +94,14 @@ Emitters.generate(s::DeltaFunction{T}) where {T} = (T(1), s.λ) # Measured Spectrum #--------------------------------------- +""" +Encapsulates a measured spectrum to compute emitter power. Create spectrum by reading CSV files. +Evaluate spectrum at arbitrary wavelength with [`spectrumpower`](@ref) (**more technical details coming soon**) + +```julia +Measured(samples::DataFrame) +``` +""" struct Measured{T<:Real} <: AbstractSpectrum{T} low_wave_length::Int high_wave_length::Int @@ -174,6 +197,14 @@ Base.copy(a::AbstractDirectionDistribution) = a # most don't have any heap alloc #--------------------------------------- # Constant Ray Direction #--------------------------------------- +""" +Encapsulates a single ray direction, where the default direction is unitZ3 [0, 0, 1]. + +```julia +Constant(direction::Vec3{T}) where {T<:Real} +Constant(::Type{T} = Float64) where {T<:Real} +``` +""" struct Constant{T} <: AbstractDirectionDistribution{T} direction::Vec3{T} @@ -196,6 +227,14 @@ end #--------------------------------------- # Grid Ray Distribution #--------------------------------------- +""" +Encapsulates a single ray direction, where the default direction is unitZ3 [0, 0, 1]. + +```julia +Constant(direction::Vec3{T}) where {T<:Real} +Constant(::Type{T} = Float64) where {T<:Real} +``` +""" struct RectGrid{T} <: AbstractDirectionDistribution{T} direction::Vec3{T} halfangleu::T @@ -237,6 +276,14 @@ end #--------------------------------------- # Cone Ray Distribution #--------------------------------------- +""" +Encapsulates a numsamples rays sampled uniformlly from a cone with max angle θmax. + +```julia +UniformCone(direction::Vec3{T}, θmax::T, numsamples::Int) where {T<:Real} +UniformCone(θmax::T, numsamples::Int) where {T<:Real} +``` +""" struct UniformCone{T} <: AbstractDirectionDistribution{T} direction::Vec3{T} θmax::T @@ -271,6 +318,15 @@ end #---------------------------------------------------------------------------- # Cone Ray Hexapolar Distribution #----------------------------------------------------------------------------- +""" +Rays are generated by sampling a cone with θmax angle in an hexapolar fasion. The number of rays depends on the requested rings and is computed using the following formula: +`1 + round(Int, (nrings * (nrings + 1) / 2) * 6)` + +```julia +HexapolarCone(direction::Vec3{T}, θmax::T, nrings::Int) where {T<:Real} +HexapolarCone(θmax::T, nrings::Int = 3) where {T<:Real} +``` +""" struct HexapolarCone{T} <: AbstractDirectionDistribution{T} direction::Vec3{T} θmax::T @@ -354,6 +410,15 @@ export generate #-------------------------------------- # Point Origin #-------------------------------------- +""" +Encapsulates a single point origin. + +```julia +Point(position::Vec3{T}) where {T<:Real} +Point(x::T, y::T, z::T) where {T<:Real} +Point(::Type{T} = Float64) where {T<:Real} +``` +""" struct Point{T} <: AbstractOriginDistribution{T} origin::Vec3{T} @@ -382,6 +447,13 @@ end #------------------------------------- # Random Rectangle Origin #------------------------------------- +""" +Encapsulates a uniformly sampled rectangle with user defined number of samples. + +```julia +RectUniform(width::T, height::T, count::Int) where {T<:Real} +``` +""" struct RectUniform{T} <: AbstractOriginDistribution{T} width::T height::T @@ -409,6 +481,13 @@ end #------------------------------------- # Grid Rectangle Origin #------------------------------------- +""" +Encapsulates a rectangle sampled in a grid fashion. + +```julia +RectGrid(width::T, height::T, usamples::Int, vsamples::Int) where {T<:Real} +``` +""" struct RectGrid{T} <: AbstractOriginDistribution{T} width::T height::T @@ -438,8 +517,13 @@ end #------------------------------------- # Hexapolar Origin #------------------------------------- +""" +Encapsulates an ellipse (or a circle where halfsizeu=halfsizev) sampled in an hexapolar fasion (rings) -# TODO: Finish this one +```julia +Hexapolar(nrings::Int, halfsizeu::T, halfsizev::T) where {T<:Real} +``` +""" struct Hexapolar{T} <: AbstractOriginDistribution{T} halfsizeu::T halfsizev::T @@ -498,7 +582,9 @@ abstract type AbstractAngularPowerDistribution{T<:Real} end #--------------------------------------- # Lambertian #--------------------------------------- - +""" +Ray power is unaffected by angle. +""" struct Lambertian{T} <: AbstractAngularPowerDistribution{T} Lambertian(::Type{T} = Float64) where {T<:Real} = new{T}() end @@ -511,7 +597,13 @@ export Lambertian #--------------------------------------- # Cosine Power Distribution #--------------------------------------- +""" + Cosine(cosine_exp::T = one(T)) where {T<:Real} + +Cosine power distribution. Ray power is calculated by: +`power = power * (cosine_angle ^ cosine_exp)` +""" struct Cosine{T} <: AbstractAngularPowerDistribution{T} cosine_exp::T @@ -531,7 +623,14 @@ end #--------------------------------------- # Gaussian Power Distribution #--------------------------------------- +""" + Gaussian(gaussianu::T, gaussianv::T) where {T<:Real} +GGaussian power distribution. Ray power is calculated by: + +`power = power * exp(-(gaussianu * l^2 + gaussianv * m^2))` +where l and m are the cos_angles between the two axes respectivly. +""" struct Gaussian{T} <: AbstractAngularPowerDistribution{T} gaussianu::T gaussianv::T @@ -582,6 +681,33 @@ Base.copy(a::AbstractSource) = a # most don't have any heap allocated stuff so d #--------------------------------------- # Source #--------------------------------------- +""" +This data-type represents the basic emitter (Source), which is a combination of a Spectrum, Angular Power Distribution, Origins and Directions distibution and a 3D Transform. + +```julia +Source(::Type{T} = Float64; + transform::Tr = Transform(), + spectrum::S = Spectrum.Uniform(), + origins::O = Origins.Point(), + directions::D = Directions.Constant(), + power::P = AngularPower.Lambertian(), + sourcenum::Int = 0) where { + Tr<:Transform, + S<:Spectrum.AbstractSpectrum, + O<:Origins.AbstractOriginDistribution, + D<:Directions.AbstractDirectionDistribution, + P<:AngularPower.AbstractAngularPowerDistribution, + T<:Real} +Source(transform::Tr, spectrum::S, origins::O, directions::D, power::P, ::Type{T} = Float64; sourcenum::Int = 0) where { + Tr<:Transform, + S<:Spectrum.AbstractSpectrum, + O<:Origins.AbstractOriginDistribution, + D<:Directions.AbstractDirectionDistribution, + P<:AngularPower.AbstractAngularPowerDistribution, + T<:Real} + +``` +""" struct Source{ T<:Real, Tr<:Transform{T}, S<:Spectrum.AbstractSpectrum{T}, @@ -621,6 +747,7 @@ struct Source{ T<:Real, new{T, Tr, S, O, D, P}(transform, spectrum, origins, directions, power, sourcenum) end end +export Source # used to not generate new origin points if we can use last points - mainly to keep consistency of origin generation when randomness is involved struct SourceGenerationState{T<:Real} @@ -680,6 +807,13 @@ end #--------------------------------------- # Composite Source #--------------------------------------- +""" +This data-type represents the composit emitter (Source) which is constructed with a list of basic or composite emitters and a 3D Transform. + +```julia +CompositeSource(transform::Transform{T}, sources::Array, ::Type{T} = Float64) where {T<:Real} +``` +""" struct CompositeSource{T} <: AbstractSource{T} transform::Transform{T} sources::Array @@ -715,7 +849,7 @@ struct CompositeSource{T} <: AbstractSource{T} new{T}(transform, sources, uniform_length, total_length, start_indexes) end end - +export CompositeSource Base.length(s::CompositeSource{T}) where {T} = s.total_length @@ -949,4 +1083,4 @@ export Geometry, Spectrum, Directions, Origins, AngularPower, Sources end # module Emitters - +export Emitters