bringing run to life again
[woropt.git] / lens.lisp
blob9896466b13337a1b29176a6dfe3ce244ae2c2302
1 #.(require :vector)
2 (defpackage :lens
3 (:use :cl :vector)
4 (:export #:plane-ray
5 #:lens-ray
6 #:thin-objective-ray
7 #:back-focal-plane-radius
8 #:focal-length-from-magnification
9 #:etendue
10 #:oil-objective-etendue
11 #:magnification-from-angles
12 #:mirror-ray
13 #:make-thin-objective
14 #:rotate-vector
15 #:find-inverse-ray-angle))
17 ;; for i in `cat lens.lisp|grep "^(defun"|cut -d " " -f2`;do echo \#:$i ;done
18 (in-package :lens)
20 (declaim (optimize (speed 2) (safety 3) (debug 3)))
22 (declaim (ftype (function (disk vec vec)
23 (values vec (or null vec) &optional))
24 plane-ray))
25 (defun plane-ray (disk ray-start ray-direction)
26 "Find the point where a ray intersects a plane. It returns two
27 vectors first the unchanged direction of the beam and then the
28 intersection point. The ray is defined by one position RAY-START and a
29 direction RAY-DIRECTION. The plane is defined by a point PLANE-CENTER
30 and its normal PLANE-NORMAL."
31 (with-slots (center normal)
32 disk
33 (let* ((hess-dist (v. center normal)) ;; distance of plane to origin
34 (div (v. normal ray-direction)))
35 (if (< (abs div) 1d-13)
36 ;; plane and ray are parallel and don't intersect
37 (values ray-direction nil)
38 (let ((eta (/ (- hess-dist (v. normal ray-start))
39 ;; scaling along ray to hit exactly on plane
40 div)))
41 (values ray-direction
42 (v+ ray-start (v* ray-direction eta))))))))
43 #+nil
44 (plane-ray (make-disk) (v 0d0 .1d0 -1d0) (v 0d0 0d0 1d0))
47 ;; --\
48 ;; | -----\ intersection
49 ;; | --+
50 ;; | \ ---|--\
51 ;; | | -----/ | ----\
52 ;; | ----+/ r' | ----\
53 ;; f |--/ c | ----\ dir
54 ;; | r | ---\
55 ;; | |rho ----\
56 ;; | | ----\
57 ;; | | ----\
58 ;; | | phi ----\
59 ;; -------+----------<-------+-------------------------------------------
60 ;; | n | center
61 ;; | |
62 ;; | |
63 ;; | |
64 ;; |
65 ;; f |
68 (declaim (ftype (function (lens vec vec
69 &key (:normalize boolean))
70 (values (or null vec) vec &optional))
71 lens-ray))
72 (defun lens-ray (lens
73 ray-start ray-direction
74 &key (normalize t))
75 "Return new ray-direction and intersection after thin lens."
76 (with-slots (center normal focal-length radius)
77 lens
78 (unless (< (abs (- 1 (norm ray-direction))) 1d-12)
79 (error "ray-direction doesn't have unit length"))
80 (unless (< (abs (- 1 (norm normal))) 1e-12)
81 (error "lens-normal doesn't have unit length"))
82 (multiple-value-bind (dir intersection)
83 (plane-ray lens
84 ray-start ray-direction)
85 (declare (ignore dir))
86 (let* ((rho (v- intersection center)))
87 #+nil (format t "~a~%" (list 'intersection intersection 'center center
88 'rho rho 'norm (norm rho)))
89 (unless (< (norm rho) radius)
90 (return-from lens-ray (values nil intersection)))
91 (let* ((cosphi (v. normal ray-direction))
92 (r (v- (v* ray-direction (/ focal-length cosphi))
93 rho)))
94 (values (if normalize
95 (normalize r)
96 r) intersection))))))
97 #+nil
98 (lens-ray (make-lens)
99 (v 0d0 .1d0 -2d0)
100 (v 0d0 0d0 1d0))
103 ;; |
104 ;; |
105 ;; --------------- s |
106 ;;-/ X---- |
107 ;; / \-- ---- |
108 ;; ro/ \-- \--+----
109 ;; | ----/ | \-------
110 ;; / -----/ \ | \------
111 ;; / ----/ ru \ | \-------
112 ;; /-/ \|rho \-------
113 ;; | \---
114 ;; |
115 ;; ------------------------------+-----------------------------------------
116 ;; |
117 ;; | nf /
118 ;; +--------------------
119 ;; | /
121 (declaim (ftype (function (thin-objective
122 vec vec)
123 (values (or null vec) vec &optional))
124 thin-objective-ray))
125 ;; 2008 Hwang Simulation of an oil immersion objective lens...
126 (defun thin-objective-ray (objective
127 ray-start ray-direction)
128 "Returns direction of outgoing ray and intersection with principal
129 sphere. If this sphere isn't hit inside the maximum angle (given by
130 NA), then nil as a direction and the intersection with the
131 lens-surface is returned instead."
132 (with-slots (center normal focal-length
133 radius ;; bfp-radius
134 immersion-index numerical-aperture)
135 objective
136 (unless (< (abs (- 1 (norm normal))) 1d-12)
137 (error "lens normal doesn't have unit length"))
138 (unless (< (abs (- 1 (norm ray-direction))) 1d-12)
139 (error "ray-direction doesn't have unit length"))
141 (multiple-value-bind (r intersection)
142 (lens-ray objective
143 ray-start ray-direction :normalize nil)
144 (unless r
145 (return-from thin-objective-ray (values nil intersection)))
146 (let* ((a (v* normal (* focal-length (- immersion-index 1))))
147 (ru (v+ r a))
148 (rho (v- intersection center))
149 (rho2 (v. rho rho))
150 (nf (* immersion-index focal-length))
151 (nf2 (* nf nf))
152 (rat (- nf2 rho2)))
153 (unless (<= 0d0 rat)
154 (return-from thin-objective-ray (values nil intersection))
155 #+nil (error "ray can't pass through objective"))
156 (let* ((s (v* ray-direction (- nf (sqrt rat))))
157 (ro (v- ru s))
158 (cosu (v. ro normal))
159 (sinu2 (- 1 (* cosu cosu)))
160 (sinu-max (/ numerical-aperture immersion-index)))
161 (unless (<= sinu2 (* sinu-max sinu-max))
162 (return-from thin-objective-ray (values nil intersection)))
163 (values ro (v+ s intersection)))))))
165 #+nil
166 (thin-objective-ray (v 0d0 0d0 0d0)
167 (v 0d0 0d0 -1d0)
168 2.3d0 1.515d0
169 (v 0d0 1d0 10d0)
170 (normalize (v 0d0 0d0 -1d0)))
173 ;; |
174 ;; -------- |
175 ;; SS \--- |
176 ;; \-- |
177 ;; X-----+-------------------------------
178 ;; /- \ |
179 ;; /- \ |
180 ;; nf=h /- \ | D/2=R
181 ;; /- \|
182 ;; /- |
183 ;; /- alpha |
184 ;; ---------------------+----------------------------------------
185 ;; nf |
187 ;; sin(alpha) = R/nf
190 (declaim (ftype (function (double-float double-float)
191 (values double-float &optional))
192 back-focal-plane-radius))
193 (defun back-focal-plane-radius (focal-length numerical-aperture)
194 (* focal-length numerical-aperture))
195 #+nil
196 (back-focal-plane-radius 2.61d0 1.4d0)
198 (declaim (ftype (function (double-float)
199 (values double-float &optional))
200 focal-length-from-magnification))
201 (defun focal-length-from-magnification (mag)
202 (/ 164.5 mag))
203 #+nil
204 (focal-length-from-magnification 63d0)
206 (declaim (ftype (function (double-float double-float
207 &optional double-float
208 double-float double-float)
209 (values double-float &optional))
210 etendue))
211 (defun etendue (chief-height marginal-angle
212 &optional
213 (refractive-index 1d0)
214 (marginal-height 0d0) (chief-angle 0d0))
215 (let ((q (- (* chief-height refractive-index marginal-angle)
216 (* marginal-height refractive-index chief-angle))))
217 (* q q)))
218 #+nil
219 (etendue .07d0 (* 67d0 (/ pi 180)) 1.515d0)
222 (declaim (ftype (function (double-float &optional double-float
223 double-float)
224 (values double-float &optional))
225 oil-objective-etendue))
226 (defun oil-objective-etendue (field-radius &optional (numerical-aperture 1.4d0)
227 (refractive-index 1.515d0))
228 (let ((rat (/ numerical-aperture refractive-index)))
229 (unless (<= (abs rat) 1)
230 (error "impossible angle, check numerical aperture and refractive index."))
231 (let* ((marginal-angle (asin rat)))
232 (etendue field-radius marginal-angle refractive-index))))
233 #+nil
234 (oil-objective-etendue .07d0)
236 (declaim (ftype (function (double-float double-float
237 &optional double-float double-float)
238 (values double-float &optional))
239 magnification-from-angles))
240 (defun magnification-from-angles (u uu &optional (n 1d0) (nn 1d0))
241 "u is the objects marginal ray angle and uu for the image."
242 (/ (* n (sin u))
243 (* nn (sin uu))))
245 (declaim (ftype (function (mirror vec vec)
246 (values (or null vec) vec &optional))
247 mirror-ray))
248 ;; sketch of the mirror for incoming parallel light
249 ;; --------------------+-----------------------
250 ;; /|\
251 ;; / | \
252 ;; / n| \ N=n*(- (p.n))
253 ;; q / | \ p p+N=r
254 ;; / v \ q=N+r
255 ;; / \
256 ;; / | \ q=p-2(p.n)*n
257 ;; / | \
258 ;; / N| \
259 ;; / | \
260 ;; / | r \
261 ;; / v<----------\
262 ;; p .. ray-direction
263 ;; N .. mirror-normal
265 (defun mirror-ray (mirror ray-start ray-direction)
266 "Mirror center C, mirror normal N.
267 Return reflected direction and intersection. If the ray isn't inside
268 of the radius return nil and the intersection."
269 (with-slots (center normal radius)
270 mirror
271 (unless (< (abs (- 1 (norm normal))) 1d-12)
272 (error "mirror normal doesn't have unit length"))
273 (unless (< (abs (- 1 (norm ray-direction))) 1d-12)
274 (error "ray-direction doesn't have unit length"))
275 (multiple-value-bind (dir intersection)
276 (plane-ray mirror ray-start ray-direction)
277 (declare (ignore dir))
278 (unless (< (norm (v- intersection center)) radius)
279 (return-from mirror-ray (values nil intersection)))
280 (let ((dir (v+ ray-direction (v* normal
281 (* -2d0 (v. ray-direction normal))))))
282 (values dir intersection)))))
284 (deftype optical-component ()
285 `(or disk mirror lens thin-objective))
288 (defstruct ray
289 (start (v) :type vec)
290 (direction (v) :type vec))
292 (defstruct disk
293 (normal (v 0d0 0d0 1d0) :type vec)
294 (center (v) :type vec)
295 (radius 1d0 :type double-float))
297 (defstruct (mirror (:include disk)))
299 (defstruct (lens (:include disk))
300 (focal-length 1d0 :type double-float))
302 (defstruct (thin-objective (:include lens))
303 (immersion-index 1.515d0 :type double-float)
304 (numerical-aperture 1.38d0 :type double-float))
306 (declaim (ftype (function (double-float vec vec)
307 (values vec &optional))
308 rotate-vector))
309 (defun rotate-vector (angle axis vector)
310 (let ((m (rotation-matrix angle axis)))
311 (m* m vector)))
313 ;; +-------+--
314 ;; | | \-----
315 ;; h | | \-----
316 ;; | | \----
317 ;; | | phi \-----
318 ;; -----+-------+------------o------------\------------------------
319 ;; (n-1)f f f
320 (declaim (ftype (function (double-float double-float thin-objective)
321 (values double-float &optional))
322 find-inverse-ray))
323 ;; 2005wolf p. 180 formula (8) sine condition for one image in infinity
324 (defun find-inverse-ray-angle (point-x point-y objective)
325 "Find the angle in the back focal plane for a ray that originates
326 from a POINT in the object. The coordinates of the point are given
327 relative to the center of the front focal plane."
328 (with-slots (focal-length)
329 objective
330 (let* ((h (sqrt (+ (* point-x point-x) (* point-y point-y))))
331 (phi (asin (/ h focal-length))))
332 phi)))
334 #+nil
335 (let* ((f (focal-length-from-magnification 63d0))
336 (na 1.38d0)
337 (ri 1.515d0)
338 (bfp-radius (back-focal-plane-radius f na))
339 (obj (make-thin-objective :normal (v 0d0 0d0 -1d0)
340 :center (v 0d0 0d0 (- f))
341 :focal-length f
342 :numerical-aperture na
343 :immersion-index ri))
344 (field (v .0d0 0d0 (- (+ f (* ri f)))))
345 (pupil (v bfp-radius 0d0 0d0)))
346 (list bfp-radius f (find-inverse-ray-angle 0 .07 obj)))