Skip to content
This repository has been archived by the owner on Oct 23, 2022. It is now read-only.

Brian gun/issue310 lenslet analysis #312

Merged
merged 82 commits into from
Dec 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
f5dc258
Add lenslet analysis
BrianGun Nov 2, 2021
9c32351
Add lenslet analysis
BrianGun Nov 2, 2021
f25d84d
changed analysis code to use mtf @ frequency rather than impulse resp…
BrianGun Nov 2, 2021
7984599
added comments
BrianGun Nov 2, 2021
abd2c9a
fixed comment
BrianGun Nov 2, 2021
0cd161e
added function to compute pupil diameter as a function of scene lumin…
BrianGun Nov 3, 2021
e429aa3
Add lenslet analysis
BrianGun Nov 4, 2021
3d717d3
added license header
BrianGun Nov 4, 2021
beaca84
Add lenslet analysis
BrianGun Nov 5, 2021
b7a1e8b
Add lenslet analysis
BrianGun Nov 6, 2021
eea5063
Add lenslet analysis
BrianGun Nov 6, 2021
450a2fc
Add lenslet analysis
BrianGun Nov 7, 2021
8104dd4
improved comments
BrianGun Nov 7, 2021
b28827d
comment change
BrianGun Nov 7, 2021
faa2d5e
removed LinearAlgebra dependency for plotall
BrianGun Nov 7, 2021
55e1390
plotting of containing shape was messed up. fixed it.
BrianGun Nov 7, 2021
a292db4
comment change
BrianGun Nov 7, 2021
5e60cc7
minor change in plot code
BrianGun Nov 7, 2021
e78a8df
added code to compute color across a lattice for hex 3 color pattern,.
BrianGun Nov 8, 2021
abedf36
converting hex clusters to auto generate colors.
BrianGun Nov 10, 2021
7557907
adding code to automatically determine color of color lattice clusters.
BrianGun Nov 10, 2021
3d4f756
automatic coloring of RGB clusters appears to work now.
BrianGun Nov 10, 2021
a1bb6d3
added angle subdivisions info to systemproperties return value
BrianGun Nov 10, 2021
647edfa
added eyebox_angles to info returned by systemproperties
BrianGun Nov 10, 2021
593f524
fixed error in lenslet display size in systemproperties
BrianGun Nov 10, 2021
a61a92b
added focal length and fnumber to systemproperties computations
BrianGun Nov 10, 2021
2530903
updated testtilesinside
BrianGun Nov 11, 2021
0392c7e
removed lensletpixels function
BrianGun Nov 11, 2021
de9b740
Merge branch 'main' into BrianGun/issue310
BrianGun Nov 11, 2021
ffa6446
added print function for system properties
BrianGun Nov 11, 2021
3d8e936
Merge branch 'BrianGun/issue310' of https://github.com/microsoft/Opti…
BrianGun Nov 11, 2021
b32a437
removed unnecessary struct LensletClusterProperties
BrianGun Nov 12, 2021
6a3c9c6
changed drawglassmap to flip x axis (dispersion) in accordance with o…
BrianGun Nov 12, 2021
384a076
modified drawglassmap to print wavelength that dispersion is calculat…
BrianGun Nov 12, 2021
c1a49ef
added filter predicate to drawglassmap
BrianGun Nov 12, 2021
5d1bf56
writing code to distribute colors and fields of view among lenslets.
BrianGun Nov 13, 2021
3442d8b
Merge branch 'main' into BrianGun/issue310
BrianGun Nov 14, 2021
9e6c463
Changed PlanarShape to AbstractPlanarShape to be consistent with our …
BrianGun Nov 14, 2021
1608cc8
adding code to do vertex projection onto arbitrary shapes
BrianGun Nov 14, 2021
10275e8
more work on projecting vertices onto surface.
BrianGun Nov 14, 2021
98dd285
fixed but in projectonplane
BrianGun Nov 14, 2021
8dfbda7
added local and world coordinate frames to return values for projecto…
BrianGun Nov 14, 2021
4adfc8d
added convenience function for project so can use any matrix type, no…
BrianGun Nov 14, 2021
4b2fe8c
added code to create convexpolygon after projection
BrianGun Nov 14, 2021
96c0217
Merge branch 'main' into BrianGun/issue310
BrianGun Nov 14, 2021
9093ea8
adding code to project spherical display onto eyebox.
BrianGun Nov 15, 2021
d306556
Merge branch 'BrianGun/issue310' of https://github.com/microsoft/Opti…
BrianGun Nov 15, 2021
03c6b33
working on spherical display projection onto eyebox
BrianGun Nov 15, 2021
996037f
still working on display generation
BrianGun Nov 16, 2021
0b0182f
fixed bug in tilesinside. Was not adding center of bbox to vertices o…
BrianGun Nov 18, 2021
4b88c6e
fixed another bug in tilesinside. Wasn't offset the final positions b…
BrianGun Nov 18, 2021
88bc68f
changed printout of lenslet system properties to include cycles/degree
BrianGun Nov 21, 2021
1e520e4
comment change
BrianGun Nov 21, 2021
a47db42
added license to DisplayGeneration.jl
BrianGun Nov 21, 2021
3d3a9a2
begun working on projection code again.
BrianGun Nov 23, 2021
15844ae
comment change
BrianGun Nov 23, 2021
350f520
added basic optical properties of the eye to Eye.jl. Renamed Eye.jl t…
BrianGun Nov 24, 2021
a073dcb
moved pupil size function to HumanEye module and fixed up sys propert…
BrianGun Nov 25, 2021
534ef1c
undoing PlanarShape -> AbstractPlanarShape change. This should be a s…
BrianGun Nov 25, 2021
aa8e545
comment change
BrianGun Nov 25, 2021
6deeee5
added comment to HexClusters.jl
BrianGun Nov 25, 2021
8ef0d4d
comment change
BrianGun Nov 25, 2021
1d35e3a
working on display generation
BrianGun Nov 27, 2021
84bdc18
in the middle of the code to generate lenslet display arrays.
BrianGun Nov 27, 2021
0914e52
wrote function to compute cluster coords and element index in that cl…
BrianGun Nov 28, 2021
3774506
comment change
BrianGun Nov 28, 2021
c305779
exported cluster_coordinates_from_tile_coordinates
BrianGun Nov 28, 2021
9f9454f
tilecoordinates and cluster_coordinates_from_tile_coordinates both ap…
BrianGun Nov 28, 2021
062a598
comment
BrianGun Nov 28, 2021
a08d6ad
comment
BrianGun Nov 28, 2021
154a5d0
comment
BrianGun Nov 28, 2021
5a674f4
moved test programs for cluster into test directory.,
BrianGun Nov 28, 2021
8df563e
finally got projection of hex shapes onto spherical display working. …
BrianGun Nov 28, 2021
02a2a1e
working on lenslet generation
BrianGun Nov 28, 2021
72354e2
code to generate lenslets on spherical display is running but not wel…
BrianGun Nov 28, 2021
a84e395
using OpticSim instead of OpticSim:ParaxialLens because for unknown r…
BrianGun Nov 29, 2021
00f3ef7
changed Lenslet to Lenslets in Repeat.jl tests in test directory.
BrianGun Nov 29, 2021
2fc23b8
was using empty instead of empty! caused weird error.
BrianGun Nov 29, 2021
9ac5798
Merge branch 'main' into BrianGun/issue310
BrianGun Nov 30, 2021
8914d18
added better documentation to code in Analysis.jl
BrianGun Nov 30, 2021
f6a76f5
Merge branch 'BrianGun/issue310' of https://github.com/microsoft/Opti…
BrianGun Nov 30, 2021
aa8dc3e
added Length types to all functions in Analysis
BrianGun Nov 30, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267"
Revise = "295af30f-e4ad-537b-8983-00126c2a3abe"
Roots = "f2b01f46-fcfa-551c-844a-d8ac1e96c665"
SHA = "ea8e919c-243c-51af-8825-aaa63cd721ce"
SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
StringEncodings = "69024149-9ee7-55f6-a4c4-859efe599b68"
Expand Down Expand Up @@ -84,7 +86,6 @@ PlutoUI = "0.7"
Polynomials = "2.0"
PyCall = "1.92"
ReverseDiff = "1.7"
Revise = "3.1"
StaticArrays = "1.0"
StringEncodings = "0.3"
Unitful = "1.6"
Expand Down
2 changes: 2 additions & 0 deletions src/Geometry/Primitives/NonCSG/ConvexPolygon.jl
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ end
export ConvexPolygon

centroid(poly::ConvexPolygon) = poly.plane.pointonplane
normal(poly::ConvexPolygon) = normal(poly.plane)
localframe(poly::ConvexPolygon) = poly.local_frame

#function barrier to make vertices allocate less and be faster.
function to3d(pts::SMatrix{2,N,T,L}) where{N,L,T}
Expand Down
2 changes: 1 addition & 1 deletion src/Geometry/SphericalPolygon.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# See LICENSE in the project root for full license information.

#SphericalPolygon uses StaticArrays to represent vertices. Expect performance degradation for polygons with large numbers of vertices. Performance appears to be good up to perhaps 100 vertices, perhaps as much as 1000 vertices. By 10,000 vertices performance is terrible.
"""SphericalPolygon uses StaticArrays to represent vertices. Expect performance degradation for polygons with large numbers of vertices. Performance appears to be good up to perhaps 100 vertices, perhaps as much as 1000 vertices. By 10,000 vertices performance is terrible."""
struct SphericalPolygon{N,T<:Real}
ptvectors::SMatrix{3,N,T}
spherecenter::SVector{3,T}
Expand Down
11 changes: 10 additions & 1 deletion src/Geometry/Transform.jl
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,14 @@ Transform(rotation::AbstractArray{S,2}, translation::AbstractArray{S,1})
"""
Transform{T} = SMatrix{4,4,T,16}
export Transform
#TODO: This was a bad idea. Should make Transform a concrete type of its own containing an SMatrix because the * operator for SMatrix*SVector is specialized for static arrays and vectors of particular sizes. Will lead to subtle and hard to fix bugs. Maybe something like this:
# struct Transform{T} <: SMatrix{4,4,T,16}
# transform::SMatrix{4,4,T,16}
# end
# :*(a::Transform{T},b::SVector{3,T}) ...
# :*(a::Transform{T},b::SVector{4,T}) ...



# for compatability ith the "old" RigidBodyTransform
"""
Expand Down Expand Up @@ -433,6 +441,7 @@ function world2local(t::Transform{T}) where {T<:Real}
end
export world2local

#TODO: should make Transform a concrete type of its own containing an SMatrix. This is hijackijng the * operator for SMatrix*SVector for arrays and vectors of particular sizes. Will lead to subtle and hard to fix bugs.
function Base.:*(t::Transform{T}, v::SVector{3,T}) where {T<:Real}
res = t * Vec4(v)
if (t[4,4] == one(T))
Expand All @@ -442,7 +451,7 @@ function Base.:*(t::Transform{T}, v::SVector{3,T}) where {T<:Real}
end
end


#TODO: should make Transform a concrete type of its own containing an SMatrix. This is hijackijng the * operator for SMatrix*SVector for arrays and vectors of particular sizes. Will lead to subtle and hard to fix bugs.
function Base.:*(t::Transform{T}, m::SMatrix{3,N,T}) where{N,T<:Real}
res = MMatrix{3,N,T}(undef)

Expand Down
15 changes: 11 additions & 4 deletions src/GlassCat/utilities.jl
Original file line number Diff line number Diff line change
Expand Up @@ -326,14 +326,20 @@ end
Draw a scatter plot of index vs dispersion (the derivative of index with respect to wavelength). Both index and
dispersion are computed at wavelength λ.

Choose glasses to graph using the glassfilterprediate argument. This is a function that receives a Glass object and returns true if the glass should be graphed.

If showprefixglasses is true then glasses with names like `F_BAK7` will be displayed. Otherwise glasses that have a
leading letter prefix followed by an underscore, such as `F_`, will not be displayed.

The index formulas for some glasses may give incorrect results if λ is outside the valid range for that glass. This can
give anomalous results, such as indices less than zero or greater than 6. To filter out these glasses set maximumindex
to a reasonable value such as 3.0.

example: plot only glasses that do not contain the strings "E_" and "J_"

drawglassmap(NIKON,showprefixglasses = true,glassfilterpredicate = (x) -> !occursin("J_",string(x)) && !occursin("E_",string(x)))
"""
function drawglassmap(glasscatalog::Module; λ::Length = 550nm, glassfontsize::Integer = 3, showprefixglasses::Bool = false, minindex = 1.0, maxindex = 3.0, mindispersion = -.3, maxdispersion = 0.0)
function drawglassmap(glasscatalog::Module; λ::Length = 550nm, glassfontsize::Integer = 3, showprefixglasses::Bool = false, minindex = 1.0, maxindex = 3.0, mindispersion = -.3, maxdispersion = 0.0, glassfilterpredicate = (x)->true)
wavelength = Float64(ustrip(uconvert(μm, λ)))
indices = Vector{Float64}(undef,0)
dispersions = Vector{Float64}(undef,0)
Expand All @@ -351,7 +357,7 @@ function drawglassmap(glasscatalog::Module; λ::Length = 550nm, glassfontsize::I

# don't show glasses that have an _ in the name. This prevents cluttering the map with many glasses of
# similar (index, dispersion).
if (mindispersion <= dispersion <= maxdispersion) && (showprefixglasses || !hasprefix)
if glassfilterpredicate(glass) && (mindispersion <= dispersion <= maxdispersion) && (showprefixglasses || !hasprefix)
push!(indices, index(glass, wavelength))
push!(dispersions, dispersion)
push!(glassnames, String(name))
Expand All @@ -367,7 +373,8 @@ function drawglassmap(glasscatalog::Module; λ::Length = 550nm, glassfontsize::I
series_annotations,
markeralpha = 0.0,
legends = :none,
xaxis = "dispersion",
xaxis = "dispersion @$λ",
yaxis = "index",
title = "Glass Catalog: $glasscatalog") #should use markershape = :none to prevent markers from being drawn but this option doesn't work. Used markeralpha = 0 so the markers are invisible. A hack which works.
title = "Glass Catalog: $glasscatalog",
xflip = true) #should use markershape = :none to prevent markers from being drawn but this option doesn't work. Used markeralpha = 0 so the markers are invisible. A hack which works.
end
57 changes: 55 additions & 2 deletions src/Optical/Eye.jl → src/Optical/HumanEye.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,62 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# See LICENSE in the project root for full license information.

using .GlassCat
module HumanEye

using OpticSim
using OpticSim.GlassCat
using OpticSim.Geometry
import Unitful
using Unitful.DefaultSymbols:mm,°

# Approximate average properties of the human eye


"""
# Pupil diameter as a function of scene luminance
https://jov.arvojournals.org/article.aspx?articleid=2279420
https://en.wikipedia.org/wiki/Orders_of_magnitude_(luminance)

Pupil diameter is approximately 2.8mm at 100cd/m^2. A typical overcast day is 700cd/m^2
"""

"""computes pupil diameter as a function of scene luminance `L`, in cd/m², and the angular area, `a`, over which this luminance is presented to the eye."""
𝐃sd(L,a) = 7.75 - 5.75 * ((L * a / 846)^.41) / ((L * a / 846)^.41 + 2) # the first letter of this function name is \bfD not D.

eyeradius() = 12mm
export eyeradius

"""Posterior focal length, i.e., optical distance from entrance pupil to the retina. Focal length will change depending on accomodation. This value is for focus at ∞. When the eye is focused at 25cm focal length will be ≈ 22mm. Because the index of refraction of the vitreous humor is approximately 1.33 the physical distance from the entrance pupil to the retina will be 24mm/1.33 = 18mm."""
eyefocallength() = 24mm
export eyefocallength


vc_epupil() = 3mm #distance from vertex of cornea to entrance pupil

""" distance from vertex of cornea to center of rotation"""
cornea_to_eyecenter() = 13.5mm
export cornea_to_eyecenter

entrancepupil_to_retina() = 22.9mm

"""distance from entrance pupil to center of rotation."""
entrancepupil_to_eyecenter() = entrancepupil_to_retina() - eyeradius()
export entrancepupil_to_eyecenter

"""average angle, in degrees, the eye will rotate before users will turn their head"""
comfortable_eye_rotation_angle() = 20°

"""average translation of the entrance pupil associated with comfortable eye rotation"""
comfortable_entrance_pupil_translation() = sin(comfortable_eye_rotation_angle())*entrancepupil_to_eyecenter()
export comfortable_entrance_pupil_translation


#Model eyes of varying degrees of verisimilitude

"""
ModelEye(assembly::LensAssembly{T}, nsamples::Int = 17; pupil_radius::T = 3.0, detpixels::Int = 1000, transform::Transform{T} = identitytransform(T))

Geometrically accurate model of the human eye focussed at infinity with variable `pupil_radius`.
Geometrically accurate model of the human eye focused at infinity with variable `pupil_radius`.
The eye is added to the provided `assembly` to create a [`CSGOpticalSystem`](@ref) with the retina of the eye as the detector.

The eye can be positioned in the scene using the `transform` argument and the resolution of the detector specified with `detpixels`.
Expand Down Expand Up @@ -76,4 +126,7 @@ function ArizonaEye(::Type{T} = Float64; accommodation::T = 0.0) where {T<:Real}
)
end
export ArizonaEye

end #module
export HumanEye
#! format: on
2 changes: 1 addition & 1 deletion src/Optical/Optical.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ include("LensAssembly.jl")
include("HierarchicalImage.jl")
include("OpticalSystem.jl")
include("Lenses.jl")
include("Eye.jl")
include("HumanEye.jl")
include("Fields.jl")
6 changes: 6 additions & 0 deletions src/Optical/Paraxial.jl
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,12 @@ function ParaxialLensHex(focaldistance::T, side_length::T, surfacenormal::SVecto
return ParaxialLens(h, ParaxialInterface(focaldistance, centrepoint, outsidematerial))
end

function ParaxialLensConvexPoly(focallength::T,convpoly::ConvexPolygon{N,T},local_center_point::SVector{2,T}; outsidematerial::OpticSim.GlassCat.AbstractGlass = OpticSim.GlassCat.Air) where {N, T<:Real}
centrepoint = SVector{3, T}(local2world(localframe(convpoly)) * Vec3(local_center_point[1], local_center_point[2], zero(T)))
return ParaxialLens(convpoly, ParaxialInterface(focallength, centrepoint, outsidematerial))
end


function ParaxialLensConvexPoly(focaldistance::T, local_frame::Transform{T}, local_polygon_points::Vector{SVector{2, T}}, local_center_point::SVector{2, T}; outsidematerial::OpticSim.GlassCat.AbstractGlass = OpticSim.GlassCat.Air) where {N, T<:Real}
poly = ConvexPolygon(local_frame, local_polygon_points)
centrepoint = SVector{3, T}(local2world(local_frame) * Vec3(local_center_point[1], local_center_point[2], zero(T)))
Expand Down
34 changes: 33 additions & 1 deletion src/RepeatingStructures/Cluster.jl
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ function Base.size(::LatticeCluster{N1,N}) where{N1,N}
return ntuple((i)->Base.IsInfinite(),N)
end

"""returns the integer coordinates of the tile at tileindex in the cluster at for a cluster with location cᵢ,cⱼ"""
function tilecoordinates(cluster::LatticeCluster{N1,N},cᵢ,cⱼ,tileindex) where{N1,N}
@assert tileindex <= N1
clustercenter = basismatrix(clusterbasis(cluster))*SVector(cᵢ,cⱼ)
tileoffset = cluster.clusterelements[tileindex]
return clustercenter .+ tileoffset
end
export tilecoordinates

Base.setindex!(A::AbstractBasis{N}, v, I::Vararg{Int, N}) where{N} = nothing #can't set lattice points. Might want to throw an exception instead.

""" returns the lattice indices of the elements in the cluster. These are generally not the positions of the elements"""
Expand All @@ -77,10 +86,33 @@ function clustercoordinates(a::LatticeCluster{N1,N},indices::Vararg{Int,N}) wher
for i in 1:N1
temp[:,i] = SVector{N,Int}(a.clusterelements[i]) + clusteroffset
end
return SMatrix{N,N1,Int}(temp) #positions of the cluster elements, not the lattice coordinates.
return SMatrix{N,N1,Int}(temp) #the lattice coordinates in the underlying element basis of the cluster elements
end
export clustercoordinates

"""Given the (i,j) coordinates of a tile defined in the the underlying lattice basis of elements of the cluster compute the coordinates (cᵢ,cⱼ) of the cluster containing the tile, and the tile number of the tile in that cluster"""
function cluster_coordinates_from_tile_coordinates(cluster::LatticeCluster{N1,N},i::Int,j::Int) where{N1,N}
found = false
bmatrix = Rational.(basismatrix(clusterbasis(cluster)))

local clustercoords::SVector{}
tileindex = 0 #initialize to illegal value
for coords in eachcol(clustercoordinates(cluster, 0,0)) #don't know which tile in the cluster the i,j coords come from so try all of them until find one that yields an integer value for the cluster coordinate.
tileindex += 1
possiblecenter = SVector{N,Rational}((i,j)) .- Rational.(coords)
clustercoords = bmatrix \ possiblecenter
if all(1 .== denominator.(clustercoords)) #If coordinates are integer this is the correct cluster value. If coordinates are not integer keep trying.
found = true #every tile position i,j corresponds to some cluster (cᵢ,cⱼ) so will always find an answer
break
end
end
@assert found == true #should always find a cluster corresponding to any i,j. If not then something is seriously wrong.

return Int64.(clustercoords),tileindex #return coordinates of the cluster and the index of the tile within that cluster
end
export cluster_coordinates_from_tile_coordinates



"""
May want to have many properties associated with the elements in a cluster, which is why properties is represented as a DataFrame. The DataFrame in the properties field should have as many rows as there are elements in a cluster. At a minimum it must have a :Color and a :Name column.
Expand Down
Loading