Primitives
All geometry is built up from a small(ish) number of primitives and a number of constructive solid geometry (CSG) operations (see CSG). Primitives are split into two types, Surface
s and ParametricSurface
s, the latter being a subset of the former. Surface
s are standalone surfaces which cannot be used in CSG operations, e.g. an aperture or rectangle. ParametricSurface
s are valid csg objects and can be composed into very complex structures.
Surfaces
A surface can be any surface in 3D space, it can be bounded and not create a half-space (i.e. not partition space into inside and outside).
OpticSim.Surface
— TypeSurface{T<:Real}
T
is the number type used to represent the surface, e.g., Float64
. Basic Surface
s are not valid CSG objects, they function only in a stand-alone capacity.
Must implement the following:
surfaceintersection(surface::Surface{T}, ray::AbstractRay{T,3}) -> Union{EmptyInterval{T},Interval{T}}
normal(surface::Surface{T}) -> SVector{3,T}
interface(surface::Surface{T}) -> OpticalInterface{T}
makemesh(surface::Surface{T}) -> TriangleMesh{T}
In a conventional ray tracer the surface intersection function would only return the first surface the ray intersects. Because our ray tracer does CSG operations the surface intersection function intersects the ray with all leaf surfaces which are part of the CSG tree.
Each leaf surface returns one or more 1D intervals along the ray. These intervals contain the part of the ray which is inside the surface. The intervals computed at the leaves are propagated upward through the CSG tree and the CSG operations of union, intersection, and difference are applied to generate new intervals which are themselves propagated upward.
The result is a union of 1D intervals, which may be disjoint, a single interval, or empty. The union of intervals represents the parts of the ray which are inside the CSG object.
Inside is well defined for halfspaces such as cylinders and spheres which divide space into two parts, but not for Bezier or NURBS patches which generally do not enclose a volume. For surfaces which are not halfspaces the notion of inside is defined locally by computing the angle between the incoming ray and the normal of the surface at the point of intersection. All surfaces must be defined so that the normal points to the outside of the surface.
A negative dot product between the incoming ray and the normal indicates the ray is coming from the outside of the surface and heading toward the inside. A positive dot product indicates the ray is coming from the inside of the surface and heading toward the outside.
Intervals are defined along the ray which is being intersected with the surface, so they are one dimensional. For example, assume we have a ray with origin o on the outside of a plane and an intersection with the plane at point int = o + td where t is a scalar and d is the unit direction of the ray. The inside interval will be (Intersection(t),Infinity). This interval begins at the intersection point on the plane and continues to positive infinity. The Intersection struct stores both the parametric value t and the 3D point of intersection to make various operations more efficient. But the interval operations only depend on the parametric value t.
If the origin o is on the inside of the plane then the inside interval will be (RayOrigin,Intersection(t)). Only the part of the ray from the ray origin to the intersection point is inside the plane.
It is the programmer's responsibility to return Interval results from surfaceintersection that maintain these properties.
The following must be impemented only if the surface is being used as a detector
uv(surface::Surface{T}, p::SVector{3,T}) -> SVector{2,T}
uvtopix(surface::Surface{T}, uv::SVector{2,T}, imsize::Tuple{Int,Int}) -> Tuple{Int,Int}
onsurface(surface::Surface{T}, p::SVector{3,T}) -> Bool
Basic Shapes
These are the simple shapes with are provided already, they act only as standalone objects and cannot be used in CSG objects. Adding a new Surface
is easy, the new structure must simply follow the interface defined above.
OpticSim.Ellipse
— TypeEllipse{T} <: Surface{T}
Elliptical surface, not a valid CSG object. The rotation of the rectangle around its normal is defined by rotationvec
. rotationvec×surfacenormal
is taken as the vector along the u axis.
Can be used as a detector in AbstractOpticalSystem
s.
Ellipse(halfsizeu::T, halfsizev::T, [surfacenormal::SVector{3,T}, centrepoint::SVector{3,T}]; interface::NullOrFresnel{T} = nullinterface(T))
The minimal case returns an ellipse centered at the origin with surfacenormal = [0, 0, 1]
.
OpticSim.Circle
— FunctionCircle(radius, [surfacenormal, centrepoint]; interface = nullinterface(T))
Shortcut method to create a circle. The minimal case returns a circle centred at the origin with normal = [0, 0, 1]
.
OpticSim.Rectangle
— TypeRectangle{T} <: Surface{T}
Rectangular surface, not a valid CSG object. The rotation of the rectangle around its normal is defined by rotationvec
. rotationvec×surfacenormal
is taken as the vector along the u axis.
Can be used as a detector in AbstractOpticalSystem
s.
Rectangle(halfsizeu::T, halfsizev::T, [surfacenormal::SVector{3,T}, centrepoint::SVector{3,T}]; rotationvec::SVector{3,T} = [0.0, 1.0, 0.0], interface::NullOrFresnel{T} = nullinterface(T))
The minimal case returns a rectangle centered at the origin with surfacenormal = [0, 0, 1]
.
OpticSim.Hexagon
— TypeHexagon{T} <: Surface{T}
Hexagonal surface, not a valid CSG object. The rotation of the hexagon around its normal is defined by rotationvec
. rotationvec×surfacenormal
is taken as the vector along the u axis.
Hexagon(side_length::T, [surfacenormal::SVector{3,T}, centrepoint::SVector{3,T}]; rotationvec::SVector{3,T} = [0.0, 1.0, 0.0], interface::NullOrFresnel{T} = nullinterface(T))
The minimal case returns a rectangle centered at the origin with surfacenormal = [0, 0, 1]
.
OpticSim.Triangle
— TypeTriangle{T} <: Surface{T}
Triangular surface, not a valid CSG object. Primarily used as a component part of TriangleMesh
or to enable intersection of AcceleratedParametricSurface
s. Can never be used directly as an optical surface as it doesn't have an OpticalInterface
.
Triangle(v1::SVector{3,T}, v2::SVector{3,T}, v3::SVector{3,T}, [uv1::SVector{2,T}, uv2::SVector{2,T}, uv3::SVector{2,T}])
OpticSim.TriangleMesh
— TypeTriangleMesh{T} <: Surface{T}
An array of Triangle
s forming a mesh. Used for visualization purposes only.
TriangleMesh(tris::Vector{Triangle{T}})
Stops
A number of simple occlusive apertures are provided as constructing such objects using CSG can be inefficient and error-prone.
OpticSim.InfiniteStop
— TypeInfiniteStop{T,P<:StopShape} <: Surface{T}
Stop surface with infinite extent (outside of the aperture). P
refers to the shape of the aperture.
OpticSim.FiniteStop
— TypeFiniteStop{T,P<:StopShape,Q<:StopShape} <: Surface{T}
Stop surface with finite extent. P
refers to the shape of the aperture and Q
represents the shape of the bounds of the stop surface.
OpticSim.RectangularAperture
— FunctionRectangularAperture(aphalfsizeu::T, aphalfsizev::T, surfacenormal::SVector{3,T}, centrepoint::SVector{3,T}; rotationvec::SVector{3,T} = [0.0, 1.0, 0.0])
Creates a rectangular aperture in a plane i.e. InfiniteStop{T,RectangularStopShape}
. The rotation of the rectangle around its normal is defined by rotationvec
. rotationvec×surfacenormal
is taken as the vector along the u axis.
RectangularAperture(innerhalfsizeu::T, innerhalfsizev::T, outerhalfsizeu::T, outerhalfsizev::T, surfacenormal::SVector{3,T}, centrepoint::SVector{3,T}; rotationvec::SVector{3,T} = [0.0, 1.0, 0.0])
Creates a rectangular aperture in a rectangle i.e. FiniteStop{T,RectangularStopShape,RectangularStopShape}
. The rotation of the rectangle around its normal is defined by rotationvec
. rotationvec×surfacenormal
is taken as the vector along the u axis.
OpticSim.CircularAperture
— FunctionCircularAperture(radius::T, surfacenormal::SVector{3,T}, centrepoint::SVector{3,T})
Creates a circular aperture in a plane i.e. InfiniteStop{T,CircularStopShape}
.
CircularAperture(radius::T, outerhalfsizeu::T, outerhalfsizev::T, surfacenormal::SVector{3,T}, centrepoint::SVector{3,T}; rotationvec::SVector{3,T} = [0.0, 1.0, 0.0])
Creates a circular aperture in a rectangle i.e. FiniteStop{T,CircularStopShape,RectangularStopShape}
. The rotation of the rectangle around its normal is defined by rotationvec
. rotationvec×surfacenormal
is taken as the vector along the u axis.
OpticSim.Annulus
— FunctionAnnulus(innerradius::T, outerradius::T, surfacenormal::SVector{3,T}, centrepoint::SVector{3,T})
Creates a circular aperture in a circle i.e. FiniteStop{T,CircularStopShape,CircularStopShape}
.
Parametric Surfaces
A parametric surface must partition space into two valid half-spaces, i.e. inside and outside. The surface must also be parameterized by two variables, nominally u
and v
. Typically these surfaces cannot be intersected with a ray analytically and so must be triangulated and an iterative solution found.
OpticSim.ParametricSurface
— TypeParametricSurface{T,N} <: Surface{T}
T
is the number type used to represent the surface, e.g., Float64
. N
is the dimension of the space the surface is embedded in. ParametricSurface
s are valid CSG objects, in some cases (where analytic intersection isn't possible) they must be wrapped in an AcceleratedParametricSurface
for use.
Must implement the following:
uv(surface::ParametricSurface{T,N}, p::SVector{N,T}) -> SVector{2,T}
uvrange(surface::ParametricSurface{T,N}) -> Tuple{Tuple{T,T},Tuple{T,T}}
point(surface::ParametricSurface{T,N}, u::T, v::T) -> SVector{N,T}
partials(surface::ParametricSurface{T,N}, u::T, v::T) -> Tuple{SVector{N,T}, SVector{N,T}}
normal(surface::ParametricSurface{T,N}, u::T, v::T) -> SVector{N,T}
inside(surface::ParametricSurface{T,N}, p: :SVector{N,T}) -> Bool
onsurface(surface::ParametricSurface{T,N}, p::SVector{N,T}) -> Bool
surfaceintersection(surface::ParametricSurface{T,N}, AbstractRay::Ray{T,N}) -> Union{EmptyInterval{T},Interval{T},DisjointUnion{T}}
interface(surface::ParametricSurface{T,N}) -> OpticalInterface{T}
OpticSim.AcceleratedParametricSurface
— TypeAcceleratedParametricSurface{T,N,S} <: ParametricSurface{T,N}
Wrapper class for ParametricSurface
s where analytical intersection isn't feasible (e.g. ZernikeSurface
, ChebyshevSurface
). The surface is instead triangulated and an iterative (newton raphson) process carried out to determine precise ray intersection points. S
is the type of the ParametricSurface being wrapped.
AcceleratedParametricSurface(surf::ParametricSurface{T,N}, numsamples::Int = 17; interface::NullOrFresnel{T} = nullinterface(T))
Parametric Surface Types
These are the available types of parametric surfaces which are already implemented, all of which can be used in the creation of CSG objects. New ParametricSurface
s can be added with relative ease providing they follow the interface defined above.
OpticSim.Cylinder
— TypeCylinder{T,N} <: ParametricSurface{T,N}
Cylinder of infinite height centered at the origin, oriented along the z-axis. visheight
is used for visualization purposes only, note that this does not fully represent the surface.
Cylinder(radius::T, visheight::T = 2.0; interface::NullOrFresnel{T} = nullinterface(T))
OpticSim.Plane
— TypePlane{T,N} <: ParametricSurface{T,N}
Infinite planar surface where the positive normal side is outside the surface.
By default this will not create any geometry for visualization, the optional vishalfsizeu
and vishalfsizev
arguments can be used to draw the plane as a rectangle for visualization note that this does not fully represent the surface. In this case, the rotation of the rectangle around the normal to the plane is defined by visvec
- surfacenormal×visvec
is taken as the vector along the u axis.
Plane(surfacenormal::SVector{N,T}, pointonplane::SVector{N,T}; interface::NullOrFresnel{T} = nullinterface(T), vishalfsizeu::T = 0.0, vishalfsizev::T = 0.0, visvec::SVector{N,T} = [0.0, 1.0, 0.0])
Plane(nx::T, ny::T, nz::T, x::T, y::T, z::T; interface::NullOrFresnel{T} = nullinterface(T), vishalfsizeu::T = 0.0, vishalfsizev::T = 0.0, visvec::SVector{N,T} = [0.0, 1.0, 0.0])
OpticSim.Sphere
— TypeSphere{T,N} <: ParametricSurface{T,N}
Spherical surface centered at the origin.
Sphere(radius::T = 1.0; interface::NullOrFresnel{T} = nullinterface(T))
OpticSim.SphericalCap
— TypeSphericalCap{T} <: ParametricSurface{T}
Spherical cap surface, creates a half-space which is essentially the subtraction of a sphere from an infinite plane. Only the spherical cap itself is visualized, not the plane. The positive normal side is outside the surface.
Can be used as a detector in AbstractOpticalSystem
s.
SphericalCap(radius::T, ϕmax::T, [surfacenormal::SVector{3,T}, centrepoint::SVector{3,T}]; interface::NullOrFresnel{T} = nullinterface(T))
The minimal case returns a spherical cap centered at the origin with surfacenormal = [0, 0, 1]
.
OpticSim.AsphericSurface
— TypeAsphericSurface{T,N,Q,M} <: ParametricSurface{T,N}
Surface incorporating an aspheric polynomial - radius, conic and aspherics are defined relative to absolute semi-diameter,. T
is the datatype, N
is the dimensionality, Q
is the number of aspheric terms, and M
is the type of aspheric polynomial.
AsphericSurface(semidiameter; radius, conic, aspherics=nothing, normradius = semidiameter)
The surface is centered at the origin and treated as being the cap of an infinite cylinder, thus creating a true half-space. Outside of 0 <= ρ <= 1
the height of the surface is not necessarily well defined, so NaN may be returned.
aspherics
aspherics should be vectors containing tuples of the form (i, v) where i is the polynomial power of the aspheric term. An empty vector is not permitted. Use nothing
instead.
The sag is defined by the equation
\[z(r,\phi) = \frac{cr^2}{1 + \sqrt{1 - (1+k)c^2r^2}} + \sum_{i}^{Q}\alpha_ir^{i}\]
where $\rho = \frac{r}{\texttt{normradius}}$, $c = \frac{1}{\texttt{radius}}$, and $k = \texttt{conic}$ .
The function checks if the aspheric terms are missing, even, odd or both and uses an efficient polynomial evaluation strategy.
OpticSim.ZernikeSurface
— TypeZernikeSurface{T,N,P,Q,M} <: ParametricSurface{T,N}
Surface incorporating the Zernike polynomials - radius, conic and aspherics are defined relative to absolute semi-diameter, Zernike terms are normalized according to the normradius
parameter. T
is the datatype, N
is the dimensionality, P
is the number of Zernike terms, Q
is the number of aspheric terms and M
is the Aspheric Type.
The surface is centered at the origin and treated as being the cap of an infinite cylinder, thus creating a true half-space. Outside of 0 <= ρ <= 1
the height of the surface is not necessarily well defined, so NaN may be returned.
For convenience the input zcoeff
can be indexed using either OSA or Noll convention, indicated using the indexing
argument as either ZernikeIndexingOSA
or ZernikeIndexingNoll
.
ZernikeSurface(semidiameter, radius = Inf, conic = 0, zcoeff = nothing, aspherics = nothing, normradius = semidiameter, indexing = ZernikeIndexingOSA)
zcoeff
and aspherics
should be vectors containing tuples of the form (i, v)
where i
is either the index of the Zernike term for the corresponding indexing
, or the polynomial power of the aspheric term (may be even or odd) and v
is the corresponding coefficient $A_i$ or $\alpha_i$ respectively.. M
will be determined from the terms entered to optimize the evaluation of the aspheric polynomial.
The sag is defined by the equation
\[z(r,\phi) = \frac{cr^2}{1 + \sqrt{1 - (1+k)c^2r^2}} + \sum_{i}^{Q}\alpha_ir^{2i} + \sum_{i}^PA_iZ_i(\rho, \phi)\]
where $\rho = \frac{r}{\texttt{normradius}}$, $c = \frac{1}{\texttt{radius}}$, $k = \texttt{conic}$ and $Z_n$ is the nᵗʰ Zernike polynomial.
OpticSim.BezierSurface
— TypeBezierSurface{P,S,N,M} <: SplineSurface{P,S,N,M}
Bezier surface defined by grid of control points.
This surface does not create a valid half-space, requires updates to function correctly.
BezierSurface{P,S,N,M}(controlpoints::AbstractArray{<:AbstractArray{S,1},2})
OpticSim.BSplineSurface
— TypeBSplineSurface{P,S,N,M} <: SplineSurface{P,S,N,M}
Curve order is the same in the u and v direction and fixed over all spans. u and v knot vectors are allowed to be different - may change this to make them both the same.
Control points in the u direction correspond to columns, with the lowest value of u corresponding to row 1. Control points in the v direction correspond to rows, with the lowest value of v corresponding to col 1.
This surface does not create a valid half-space, requires updates to function correctly.
BSplineSurface{P,S,N,M}(knots::KnotVector{S}, controlpoints::AbstractArray{<:AbstractArray{S,1},2})
BSplineSurface{P,S,N,M}(uknots::KnotVector{S}, vknots::KnotVector{S}, controlpoints::AbstractArray{<:AbstractArray{S,1},2})
OpticSim.QTypeSurface
— TypeQTypeSurface{T,D,M,N} <: ParametricSurface{T,D}
Surface incorporating the QType polynomials - radius and conic are defined relative to absolute semi-diameter, QType terms are normalized according to the normradius
parameter. T
is the datatype, D
is the dimensionality, M
and N
are the maximum QType terms used.
The surface is centered at the origin and treated as being the cap of an infinite cylinder, thus creating a true half-space. Outside of 0 <= ρ <= 1 the height of the surface is not necessarily well defined, so NaN may be returned.
QTypeSurface(semidiameter; radius = Inf, conic = 0.0, αcoeffs = nothing, βcoeffs = nothing, normradius = semidiameter)
αcoeffs
and βcoeffs
should be a vector of tuples of the form (m, n, v)
where v
is the value of the coefficient $α_n^m$ or $β_n^m$ respectively.
The sag is defined by the equation
\[\begin{aligned} z(r,\phi) = & \frac{cr^2}{1 + \sqrt{1 - (1+k)c^2r^2}} + \frac{\sqrt{1 + kc^2r^2}}{\sqrt{1-(1+k)c^2r^2}} \cdot \\ & \left\{ \rho^2(1-\rho^2)\sum_{n=0}^{N}\alpha_n^0 Q_n^0 (\rho^2) + \sum_{m=1}^{M}\rho^m\sum_{n=0}^N \left[ \alpha_n^m\cos{m\phi} +\beta_n^m\sin{m\phi}\right]Q_n^m(\rho^2) \right\} \end{aligned}\]
where $\rho = \frac{r}{\texttt{normradius}}$, $c = \frac{1}{\texttt{radius}}$, $k = \texttt{conic}$ and $Q_n^m$ is the QType polynomial index $m$, $n$.
OpticSim.ChebyshevSurface
— TypeChebyshevSurface{T,N,P,Q} <: ParametricSurface{T,N}
Rectangular surface incorporating Chebyshev polynomials as well as radius and conic terms. T
is the datatype, N
is the dimensionality, P
is the number of Chebyshev terms in u and Q
is the number of Chebyshev terms in v.
The surface is centered at the origin and treated as being the cap of an infinite rectangular prism, thus creating a true half-space. Note that the surface is vertically offset so that the center (i.e., (u,v) == (0,0)
) lies at 0 on the z-axis.
ChebyshevSurface(halfsizeu, halfsizev, chebycoeff; radius = Inf, conic = 0)
chebycoeff
is a vector containing tuples of the form (i, j, v)
where v
is the value of the coefficient $c_{ij}$.
The sag is defined by the equation
\[z(u,v) = \frac{c(u^2 + v^2)^2}{1 + \sqrt{1 - (1+k)c^2(u^2 + v^2)}} + \sum_{i}^{P}\sum_{j}^{Q}c_{ij}T_i(u)T_j(v)\]
where $c = \frac{1}{\texttt{radius}}$, $k = \texttt{conic}$ and $T_n$ is the nᵗʰ Chebyshev polynomial of the first kind.
OpticSim.GridSagSurface
— TypeGridSagSurface{T,N,S<:Union{ZernikeSurface{T,N},ChebyshevSurface{T,N}},Nu,Nv} <: ParametricSurface{T,N}
Either a Zernike (circular) or Chebyshev (rectangular) surface with grid sag height added to the base sag. The surface shape is determined by either a linear or a bicubic spline interpolation of the Nu×Nv
grid of sag values, set by the interpolation
argument taking either GridSagLinear
or GridSagBicubic
.
Each entry in the grid is a vector of the form $[z, \frac{\partial z}{\partial x}, \frac{\partial z}{\partial y}, \frac{\partial^2 z}{\partial x \partial y}]$. The first data item corresponds to the lower left corner of the surface, that is, the corner defined by the -u and -v limit. Each point that follows is read across the face of the surface from left to right moving upwards. If zero is given for the partials (and using bicubic interpolation) then the partials will be approximated using finite differences.
The sag grid can be decentered from the surface in uv space, if so the surface may become wild outside of the area over which the grid is defined. It is advised to clip the surface to the valid area using CSG operations in this case.
A surface can also be generated from a .GRD
file by passing in the filename as the first and only positional argument. In this case the surface will be rectangular with optional radius and conic.
See docs for ZernikeSurface
and ChebyshevSurface
for details of the base surface.
GridSagSurface(basesurface::Union{ZernikeSurface{T,N},ChebyshevSurface{T,N}}, sag_grid::AbstractArray{T,3}; interpolation = GridSagBicubic, decenteruv = (0, 0))
GridSagSurface{T}(filename::String; radius = Inf, conic = 0, interpolation = GridSagBicubic)
Functions
These are some useful functions related to Surface
objects.
OpticSim.point
— Methodpoint(surf::ParametricSurface{T}, u::T, v::T) -> SVector{3,T}
point(surf::ParametricSurface{T}, uv::SVector{2,T}) -> SVector{3,T}
Returns the 3D point on surf
at the given uv coordinate.
OpticSim.normal
— Functionnormal(surf::ParametricSurface{T}, u::T, v::T) -> SVector{3,T}
normal(surf::ParametricSurface{T}, uv::SVector{2,T}) -> SVector{3,T}
Returns the normal to surf
at the given uv coordinate.
OpticSim.partials
— Methodpartials(surf::ParametricSurface{T}, u::T, v::T) -> (SVector{3,T}, SVector{3,T})
partials(surf::ParametricSurface{T}, uv::SVector{2,T}) -> (SVector{3,T}, SVector{3,T})
Returns a tuple of the 3D partial derivatives of surf
with respect to u and v at the given uv coordinate.
OpticSim.uvrange
— Functionuvrange(s::ParametricSurface)
uvrange(::Type{S}) where {S<:ParametricSurface}
Returns a tuple of the form: ((umin, umax), (vmin, vmax))
specifying the limits of the parameterisation for this surface type. Also implemented for some Surface
s which are not ParametricSurface
s (e.g. Rectangle
).
OpticSim.uv
— Functionuv(surf::ParametricSurface{T}, p::SVector{3,T}) -> SVector{2,T}
uv(surf::ParametricSurface{T}, x::T, y::T, z::T) -> SVector{2,T}
Returns the uv coordinate on surf
of a point, p
, in 3D space. If onsurface(surf, p)
is false then the behavior is undefined, it may return an inorrect uv, an invalid uv, NaN or crash.
OpticSim.uvtopix
— Functionuvtopix(surf::Surface{T}, uv::SVector{2,T}, imsize::Tuple{Int,Int}) -> Tuple{Int,Int}
Converts a uvcoordinate on surf
to an integer index to a pixel in an image of size imsize
. Not implemented on all Surface
objects. Used to determine where in the detector image a ray has hit when in intersects the detector surface of an AbstractOpticalSystem
.
OpticSim.inside
— Methodinside(surf::ParametricSurface{T}, p::SVector{3,T}) -> Bool
inside(surf::ParametricSurface{T}, x::T, y::T, z::T) -> Bool
Tests whether a 3D point in world space is inside surf
.
OpticSim.onsurface
— Methodonsurface(surf::ParametricSurface{T}, p::SVector{3,T}) -> Bool
onsurface(surf::ParametricSurface{T}, x::T, y::T, z::T) -> Bool
Tests whether a 3D point in world space is on surf
.
OpticSim.interface
— Functioninterface(surf::Surface{T}) -> OpticalInterface{T}
Return the OpticalInterface
associated with surf
.
OpticSim.surfaceintersection
— Methodsurfaceintersection(surf::Surface{T}, r::AbstractRay{T}) where {T}
Calculates the intersection of r
with a surface of any type, surf
. Note that some surfaces cannot be intersected analytically so must be wrapped in an AcceleratedParametricSurface
in order to be intersected.
Returns an EmptyInterval
if there is no Intersection
, an Interval
if there is one or two intersections and a DisjointUnion
if there are more than two intersections.
OpticSim.samplesurface
— Functionsamplesurface(surf::ParametricSurface{T,N}, samplefunction::Function, numsamples::Int = 30)
Sample a parametric surface on an even numsamples
×numsamples
grid in UV space with provided function
OpticSim.triangulate
— Functiontriangulate(surf::ParametricSurface{S,N}, quads_per_row::Int, extensionu::Bool = false, extensionv::Bool = false, radialu::Bool = false, radialv::Bool = false)
Create an array of triangles representing the parametric surface where vertices are sampled on an even grid in UV space. The surface can be extended by 1% in u and v separately, and specifying either u or v as being radial - i.e. detemining the radius on the surface e.g. rho for zernike - will result in that dimension being sampled using sqwrt so that area of triangles is uniform. The extension will also only apply to the maximum in this case.
OpticSim.makemesh
— Functionmakemesh(object, subdivisions::Int = 30) -> TriangleMesh
Creates a TriangleMesh
from an object, either a ParametricSurface
, CSGTree
or certain surfaces (e.g. Circle
, Rectangle
). This is used for visualization purposes only.
makemesh(poly::ConvexPolygon{N, T}, ::Int = 0) where {N, T<:Real} -> TriangleMesh
Create a triangle mesh that can be rendered by iterating on the polygon's edges and for each edge use the centroid as the third vertex of the triangle.
Bounding Boxes
Bounding boxes are mostly used internally for efficiency, but are also exposed to the user for visualization (and any other) purposes. All bounding boxes are axis aligned.
OpticSim.BoundingBox
— TypeBoundingBox{T<:Real}
Axis-aligned three-dimensional bounding box.
BoundingBox(xmin::T, xmax::T, ymin::T, ymax::T, zmin::T, zmax::T)
BoundingBox(s::Surface{T})
BoundingBox(s::ParametricSurface{T,3}, transform::Transform{T} = identitytransform(T))
BoundingBox(c::CSGTree{T})
BoundingBox(tri::Triangle{T})
BoundingBox(triangles::AbstractVector{Triangle{T}})
BoundingBox(points::AbstractArray{SVector{3,T}})
BoundingBox(la::LensAssembly{T})
OpticSim.doesintersect
— Functiondoesintersect(bbox::BoundingBox{T}, r::AbstractRay{T,3}) -> Bool
Tests whether r
intersects an axis-aligned BoundingBox
, bbox
.
OpticSim.surfaceintersection
— Methodsurfaceintersection(bbox::BoundingBox{T}, r::AbstractRay{T,3}) -> Union{EmptyInterval{T},Interval{T}}
Calculates the intersection of r
with an axis-aligned BoundingBox
, bbox
.
Returns an EmptyInterval
if there is no intersection or an Interval
if there is one or two intersections. Note that the uv of the returned intersection is always 0.