changed the prototype stuff from the bottom into a new angular-psf function
[woropt.git] / lens.lisp
blob844a8e55620a61a958855dc974230558e65bf5b4
1 (defpackage :lens
2 (:use :cl)
3 (:export #:norm
4 #: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 #:m
14 #:v
15 #:rotation-matrix
16 #:m*
17 #:cross
18 #:make-thin-objective
19 #:rotate-vector
20 #:find-inverse-ray-angle))
22 ;; for i in `cat lens.lisp|grep "^(defun"|cut -d " " -f2`;do echo \#:$i ;done
23 (in-package :lens)
25 (declaim (optimize (speed 2) (safety 3) (debug 3)))
27 (deftype vec ()
28 `(simple-array double-float (3)))
30 (deftype mat ()
31 `(simple-array double-float (3 3)))
33 (declaim (ftype (function (&optional double-float double-float
34 double-float)
35 (values vec &optional))
36 v))
37 (defun v (&optional (x 0d0) (y 0d0) (z 0d0))
38 "Create a vector."
39 (make-array 3 :element-type 'double-float
40 :initial-contents (list x y z)))
42 (declaim (ftype (function (vec vec)
43 (values double-float &optional))
44 v.))
45 (defun v. (a b)
46 "Dot product between two vectors."
47 (let ((sum 0d0))
48 (declare (double-float sum))
49 (dotimes (i 3)
50 (incf sum (* (aref a i)
51 (aref b i))))
52 sum))
54 (declaim (ftype (function (vec vec)
55 (values vec &optional))
56 v- v+))
57 (defmacro v-op (op a b)
58 "Subtracting and adding vectors."
59 `(let ((result (v)))
60 (dotimes (i 3)
61 (setf (aref result i) (,op (aref ,a i)
62 (aref ,b i))))
63 result))
65 (defun v+ (a b)
66 "Add two vectors."
67 (v-op + a b))
69 (defun v- (a b)
70 "Subtract two vectors."
71 (v-op - a b))
73 (declaim (ftype (function (vec double-float)
74 (values vec &optional))
75 v*))
76 (defmethod v* (a scalar)
77 "Multiply vector with scalar."
78 (declare (double-float scalar)
79 (vec a))
80 (let* ((result (v)))
81 (dotimes (i 3)
82 (setf (aref result i) (* scalar (aref a i))))
83 result))
85 (declaim (ftype (function (vec)
86 (values double-float &optional))
87 norm))
88 (defun norm (a)
89 "Length of a vector."
90 (let ((l2 (v. a a)))
91 (declare (type (double-float 0d0) l2)) ;; Otherwise warning with complex-double
92 (sqrt l2)))
94 (declaim (ftype (function (vec)
95 (values vec &optional))
96 normalize))
97 (defmethod normalize (a)
98 "Rescale vector to unit length."
99 (v* a (/ (norm a))))
101 (declaim (ftype (function (disk vec vec)
102 (values vec (or null vec) &optional))
103 plane-ray))
104 (defun plane-ray (disk ray-start ray-direction)
105 "Find the point where a ray intersects a plane. It returns two
106 vectors first the unchanged direction of the beam and then the
107 intersection point. The ray is defined by one position RAY-START and a
108 direction RAY-DIRECTION. The plane is defined by a point PLANE-CENTER
109 and its normal PLANE-NORMAL."
110 (with-slots (center normal)
111 disk
112 (let* ((hess-dist (v. center normal)) ;; distance of plane to origin
113 (div (v. normal ray-direction)))
114 (if (< (abs div) 1d-13)
115 ;; plane and ray are parallel and don't intersect
116 (values ray-direction nil)
117 (let ((eta (/ (- hess-dist (v. normal ray-start))
118 ;; scaling along ray to hit exactly on plane
119 div)))
120 (values ray-direction
121 (v+ ray-start (v* ray-direction eta))))))))
122 #+nil
123 (plane-ray (make-disk) (v 0d0 .1d0 -1d0) (v 0d0 0d0 1d0))
126 ;; --\
127 ;; | -----\ intersection
128 ;; | --+
129 ;; | \ ---|--\
130 ;; | | -----/ | ----\
131 ;; | ----+/ r' | ----\
132 ;; f |--/ c | ----\ dir
133 ;; | r | ---\
134 ;; | |rho ----\
135 ;; | | ----\
136 ;; | | ----\
137 ;; | | phi ----\
138 ;; -------+----------<-------+-------------------------------------------
139 ;; | n | center
140 ;; | |
141 ;; | |
142 ;; | |
143 ;; |
144 ;; f |
147 (declaim (ftype (function (lens vec vec
148 &key (:normalize boolean))
149 (values (or null vec) vec &optional))
150 lens-ray))
151 (defun lens-ray (lens
152 ray-start ray-direction
153 &key (normalize t))
154 "Return new ray-direction and intersection after thin lens."
155 (with-slots (center normal focal-length radius)
156 lens
157 (unless (< (abs (- 1 (norm ray-direction))) 1d-12)
158 (error "ray-direction doesn't have unit length"))
159 (unless (< (abs (- 1 (norm normal))) 1e-12)
160 (error "lens-normal doesn't have unit length"))
161 (multiple-value-bind (dir intersection)
162 (plane-ray lens
163 ray-start ray-direction)
164 (declare (ignore dir))
165 (let* ((rho (v- intersection center)))
166 (format t "~a~%" (list 'intersection intersection 'center center
167 'rho rho 'norm (norm rho)))
168 (unless (< (norm rho) radius)
169 (return-from lens-ray (values nil intersection)))
170 (let* ((cosphi (v. normal ray-direction))
171 (r (v- (v* ray-direction (/ focal-length cosphi))
172 rho)))
173 (values (if normalize
174 (normalize r)
175 r) intersection))))))
176 #+nil
177 (lens-ray (make-lens)
178 (v 0d0 .1d0 -2d0)
179 (v 0d0 0d0 1d0))
182 ;; |
183 ;; |
184 ;; --------------- s |
185 ;;-/ X---- |
186 ;; / \-- ---- |
187 ;; ro/ \-- \--+----
188 ;; | ----/ | \-------
189 ;; / -----/ \ | \------
190 ;; / ----/ ru \ | \-------
191 ;; /-/ \|rho \-------
192 ;; | \---
193 ;; |
194 ;; ------------------------------+-----------------------------------------
195 ;; |
196 ;; | nf /
197 ;; +--------------------
198 ;; | /
200 (declaim (ftype (function (thin-objective
201 vec vec)
202 (values (or null vec) vec &optional))
203 thin-objective-ray))
204 ;; 2008 Hwang Simulation of an oil immersion objective lens...
205 (defun thin-objective-ray (objective
206 ray-start ray-direction)
207 "Returns direction of outgoing ray and intersection with principal
208 sphere. If this sphere isn't hit inside the maximum angle (given by
209 NA), then nil as a direction and the intersection with the
210 lens-surface is returned instead."
211 (with-slots (center normal focal-length
212 radius ;; bfp-radius
213 immersion-index numerical-aperture)
214 objective
215 (unless (< (abs (- 1 (norm normal))) 1d-12)
216 (error "lens normal doesn't have unit length"))
217 (unless (< (abs (- 1 (norm ray-direction))) 1d-12)
218 (error "ray-direction doesn't have unit length"))
220 (multiple-value-bind (r intersection)
221 (lens-ray objective
222 ray-start ray-direction :normalize nil)
223 (unless r
224 (return-from thin-objective-ray (values nil intersection)))
225 (let* ((a (v* normal (* focal-length (- immersion-index 1))))
226 (ru (v+ r a))
227 (rho (v- intersection center))
228 (rho2 (v. rho rho))
229 (nf (* immersion-index focal-length))
230 (nf2 (* nf nf))
231 (rat (- nf2 rho2)))
232 (unless (<= 0d0 rat)
233 (return-from thin-objective-ray (values nil intersection))
234 #+nil (error "ray can't pass through objective"))
235 (let* ((s (v* ray-direction (- nf (sqrt rat))))
236 (ro (v- ru s))
237 (cosu (v. ro normal))
238 (sinu2 (- 1 (* cosu cosu)))
239 (sinu-max (/ numerical-aperture immersion-index)))
240 (unless (<= sinu2 (* sinu-max sinu-max))
241 (return-from thin-objective-ray (values nil intersection)))
242 (values ro (v+ s intersection)))))))
244 #+nil
245 (thin-objective-ray (v 0d0 0d0 0d0)
246 (v 0d0 0d0 -1d0)
247 2.3d0 1.515d0
248 (v 0d0 1d0 10d0)
249 (normalize (v 0d0 0d0 -1d0)))
252 ;; |
253 ;; -------- |
254 ;; SS \--- |
255 ;; \-- |
256 ;; X-----+-------------------------------
257 ;; /- \ |
258 ;; /- \ |
259 ;; nf=h /- \ | D/2=R
260 ;; /- \|
261 ;; /- |
262 ;; /- alpha |
263 ;; ---------------------+----------------------------------------
264 ;; nf |
266 ;; sin(alpha) = R/nf
269 (declaim (ftype (function (double-float double-float)
270 (values double-float &optional))
271 back-focal-plane-radius))
272 (defun back-focal-plane-radius (focal-length numerical-aperture)
273 (* focal-length numerical-aperture))
274 #+nil
275 (back-focal-plane-radius 2.61d0 1.4d0)
277 (declaim (ftype (function (double-float)
278 (values double-float &optional))
279 focal-length-from-magnification))
280 (defun focal-length-from-magnification (mag)
281 (/ 164.5 mag))
282 #+nil
283 (focal-length-from-magnification 63d0)
285 (declaim (ftype (function (double-float double-float
286 &optional double-float
287 double-float double-float)
288 (values double-float &optional))
289 etendue))
290 (defun etendue (chief-height marginal-angle
291 &optional
292 (refractive-index 1d0)
293 (marginal-height 0d0) (chief-angle 0d0))
294 (let ((q (- (* chief-height refractive-index marginal-angle)
295 (* marginal-height refractive-index chief-angle))))
296 (* q q)))
297 #+nil
298 (etendue .07d0 (* 67d0 (/ pi 180)) 1.515d0)
301 (declaim (ftype (function (double-float &optional double-float
302 double-float)
303 (values double-float &optional))
304 oil-objective-etendue))
305 (defun oil-objective-etendue (field-radius &optional (numerical-aperture 1.4d0)
306 (refractive-index 1.515d0))
307 (let ((rat (/ numerical-aperture refractive-index)))
308 (unless (<= (abs rat) 1)
309 (error "impossible angle, check numerical aperture and refractive index."))
310 (let* ((marginal-angle (asin rat)))
311 (etendue field-radius marginal-angle refractive-index))))
312 #+nil
313 (oil-objective-etendue .07d0)
315 (declaim (ftype (function (double-float double-float
316 &optional double-float double-float)
317 (values double-float &optional))
318 magnification-from-angles))
319 (defun magnification-from-angles (u uu &optional (n 1d0) (nn 1d0))
320 "u is the objects marginal ray angle and uu for the image."
321 (/ (* n (sin u))
322 (* nn (sin uu))))
324 (declaim (ftype (function (mirror vec vec)
325 (values (or null vec) vec &optional))
326 mirror-ray))
327 ;; sketch of the mirror for incoming parallel light
328 ;; --------------------+-----------------------
329 ;; /|\
330 ;; / | \
331 ;; / n| \ N=n*(- (p.n))
332 ;; q / | \ p p+N=r
333 ;; / v \ q=N+r
334 ;; / \
335 ;; / | \ q=p-2(p.n)*n
336 ;; / | \
337 ;; / N| \
338 ;; / | \
339 ;; / | r \
340 ;; / v<----------\
341 ;; p .. ray-direction
342 ;; N .. mirror-normal
344 (defun mirror-ray (mirror ray-start ray-direction)
345 "Mirror center C, mirror normal N.
346 Return reflected direction and intersection. If the ray isn't inside
347 of the radius return nil and the intersection."
348 (with-slots (center normal radius)
349 mirror
350 (unless (< (abs (- 1 (norm normal))) 1d-12)
351 (error "mirror normal doesn't have unit length"))
352 (unless (< (abs (- 1 (norm ray-direction))) 1d-12)
353 (error "ray-direction doesn't have unit length"))
354 (multiple-value-bind (dir intersection)
355 (plane-ray mirror ray-start ray-direction)
356 (declare (ignore dir))
357 (unless (< (norm (v- intersection center)) radius)
358 (return-from mirror-ray (values nil intersection)))
359 (let ((dir (v+ ray-direction (v* normal
360 (* -2d0 (v. ray-direction normal))))))
361 (values dir intersection)))))
363 (declaim (ftype (function (double-float double-float double-float
364 double-float double-float double-float
365 double-float double-float double-float)
366 (values mat &optional))
368 (defun m (a b c d e f g h i)
369 (make-array '(3 3)
370 :element-type 'double-float
371 :initial-contents (list (list a b c) (list d e f) (list g h i))))
373 (declaim (ftype (function (double-float vec)
374 (values mat &optional))
375 rotation-matrix))
376 (defun rotation-matrix (angle vect)
377 "Create matrix that rotates by ANGLE radians around the direction
378 VECT. VECT must be normalized."
379 (let* ((u (aref vect 0))
380 (v (aref vect 1))
381 (w (aref vect 2))
382 (c (cos angle))
383 (s (sin angle))
384 (1-c (- 1 c))
385 (su (* s u))
386 (sv (* s v))
387 (sw (* s w)))
388 (m (+ c (* 1-c u u))
389 (+ (* 1-c u v) sw)
390 (- (* 1-c u w) sv)
392 (- (* 1-c u v) sw)
393 (+ c (* 1-c v v))
394 (+ (* 1-c v w) su)
396 (+ (* 1-c u w) sv)
397 (- (* 1-c v w) su)
398 (+ c (* 1-c w w)))))
399 #+nil
400 (rotation-matrix (/ pi 2) (v 0d0 0d0 1d0))
402 (declaim (ftype (function (mat vec)
403 (values vec &optional))
404 m*))
405 (defun m* (matrix vect)
406 "Multiply MATRIX with VECT. Copies 4th component w from VECT into
407 result."
408 (let ((res (v)))
409 (dotimes (i 3)
410 (dotimes (j 3)
411 (incf (aref res i)
412 (* (aref matrix i j) (aref vect j)))))
413 res))
414 #+nil
415 (m* (rotation-matrix (/ pi 2) (v 0d0 0d0 1d0)) (v 1d0))
417 (declaim (ftype (function (vec vec)
418 (values vec &optional))
419 cross))
420 (defun cross (a b)
421 (v (- (* (aref a 1) (aref b 2))
422 (* (aref a 2) (aref b 1)))
423 (- (* (aref a 2) (aref b 0))
424 (* (aref a 0) (aref b 2)))
425 (- (* (aref a 0) (aref b 1))
426 (* (aref a 1) (aref b 0)))))
427 #+nil
428 (cross (v 1d0)
429 (v 0d0 1d0))
431 (deftype optical-component ()
432 `(or disk mirror lens thin-objective))
435 (defstruct ray
436 (start (v) :type vec)
437 (direction (v) :type vec))
439 (defstruct disk
440 (normal (v 0d0 0d0 1d0) :type vec)
441 (center (v) :type vec)
442 (radius 1d0 :type double-float))
444 (defstruct (mirror (:include disk)))
446 (defstruct (lens (:include disk))
447 (focal-length 1d0 :type double-float))
449 (defstruct (thin-objective (:include lens))
450 (immersion-index 1.515d0 :type double-float)
451 (numerical-aperture 1.38d0 :type double-float))
453 (declaim (ftype (function (double-float vec vec)
454 (values vec &optional))
455 rotate-vector))
456 (defun rotate-vector (angle axis vector)
457 (let ((m (rotation-matrix angle axis)))
458 (m* m vector)))
460 ;; +-------+--
461 ;; | | \-----
462 ;; h | | \-----
463 ;; | | \----
464 ;; | | phi \-----
465 ;; -----+-------+------------o------------\------------------------
466 ;; (n-1)f f f
467 (declaim (ftype (function (double-float double-float thin-objective)
468 (values double-float &optional))
469 find-inverse-ray))
470 ;; 2005wolf p. 180 formula (8) sine condition for one image in infinity
471 (defun find-inverse-ray-angle (point-x point-y objective)
472 "Find the angle in the back focal plane for a ray that originates
473 from a POINT in the object. The coordinates of the point are given
474 relative to the center of the front focal plane."
475 (with-slots (focal-length)
476 objective
477 (let* ((h (sqrt (+ (* point-x point-x) (* point-y point-y))))
478 (phi (asin (/ h focal-length))))
479 phi)))
481 #+nil
482 (let* ((f (focal-length-from-magnification 63d0))
483 (na 1.38d0)
484 (ri 1.515d0)
485 (bfp-radius (back-focal-plane-radius f na))
486 (obj (make-thin-objective :normal (v 0d0 0d0 -1d0)
487 :center (v 0d0 0d0 (- f))
488 :focal-length f
489 :numerical-aperture na
490 :immersion-index ri))
491 (field (v .0d0 0d0 (- (+ f (* ri f)))))
492 (pupil (v bfp-radius 0d0 0d0)))
493 (list bfp-radius f (find-inverse-ray-angle 0 .07 obj)))