7 #:back-focal-plane-radius
8 #:focal-length-from-magnification
10 #:oil-objective-etendue
11 #:magnification-from-angles
20 #:find-inverse-ray-angle
))
22 ;; for i in `cat lens.lisp|grep "^(defun"|cut -d " " -f2`;do echo \#:$i ;done
25 (declaim (optimize (speed 2) (safety 3) (debug 3)))
28 `(simple-array double-float
(3)))
31 `(simple-array double-float
(3 3)))
33 (declaim (ftype (function (&optional double-float double-float
35 (values vec
&optional
))
37 (defun v (&optional
(x 0d0
) (y 0d0
) (z 0d0
))
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
))
46 "Dot product between two vectors."
48 (declare (double-float sum
))
50 (incf sum
(* (aref a i
)
54 (declaim (ftype (function (vec vec
)
55 (values vec
&optional
))
57 (defmacro v-op
(op a b
)
58 "Subtracting and adding vectors."
61 (setf (aref result i
) (,op
(aref ,a i
)
70 "Subtract two vectors."
73 (declaim (ftype (function (vec double-float
)
74 (values vec
&optional
))
76 (defmethod v* (a scalar
)
77 "Multiply vector with scalar."
78 (declare (double-float scalar
)
82 (setf (aref result i
) (* scalar
(aref a i
))))
85 (declaim (ftype (function (vec)
86 (values double-float
&optional
))
91 (declare (type (double-float 0d0
) l2
)) ;; Otherwise warning with complex-double
94 (declaim (ftype (function (vec)
95 (values vec
&optional
))
97 (defmethod normalize (a)
98 "Rescale vector to unit length."
101 (declaim (ftype (function (disk vec vec
)
102 (values vec
(or null vec
) &optional
))
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
)
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
120 (values ray-direction
121 (v+ ray-start
(v* ray-direction eta
))))))))
123 (plane-ray (make-disk) (v 0d0
.1d0 -
1d0
) (v 0d0
0d0
1d0
))
127 ;; | -----\ intersection
130 ;; | | -----/ | ----\
131 ;; | ----+/ r' | ----\
132 ;; f |--/ c | ----\ dir
138 ;; -------+----------<-------+-------------------------------------------
147 (declaim (ftype (function (lens vec vec
148 &key
(:normalize boolean
))
149 (values (or null vec
) vec
&optional
))
151 (defun lens-ray (lens
152 ray-start ray-direction
154 "Return new ray-direction and intersection after thin lens."
155 (with-slots (center normal focal-length radius
)
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
)
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
))
173 (values (if normalize
175 r
) intersection
))))))
177 (lens-ray (make-lens)
184 ;; --------------- s |
188 ;; | ----/ | \-------
189 ;; / -----/ \ | \------
190 ;; / ----/ ru \ | \-------
191 ;; /-/ \|rho \-------
194 ;; ------------------------------+-----------------------------------------
197 ;; +--------------------
200 (declaim (ftype (function (thin-objective
202 (values (or null vec
) vec
&optional
))
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
213 immersion-index numerical-aperture
)
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
)
222 ray-start ray-direction
:normalize nil
)
224 (return-from thin-objective-ray
(values nil intersection
)))
225 (let* ((a (v* normal
(* focal-length
(- immersion-index
1))))
227 (rho (v- intersection center
))
229 (nf (* immersion-index focal-length
))
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
))))
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
)))))))
245 (thin-objective-ray (v 0d0
0d0
0d0
)
249 (normalize (v 0d0
0d0 -
1d0
)))
256 ;; X-----+-------------------------------
263 ;; ---------------------+----------------------------------------
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
))
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)
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
))
290 (defun etendue (chief-height marginal-angle
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
))))
298 (etendue .07d0
(* 67d0
(/ pi
180)) 1.515d0
)
301 (declaim (ftype (function (double-float &optional 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
))))
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."
324 (declaim (ftype (function (mirror vec vec
)
325 (values (or null vec
) vec
&optional
))
327 ;; sketch of the mirror for incoming parallel light
328 ;; --------------------+-----------------------
331 ;; / n| \ N=n*(- (p.n))
335 ;; / | \ q=p-2(p.n)*n
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
)
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
)
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
))
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))
400 (rotation-matrix (/ pi
2) (v 0d0
0d0
1d0
))
402 (declaim (ftype (function (mat vec
)
403 (values vec
&optional
))
405 (defun m* (matrix vect
)
406 "Multiply MATRIX with VECT. Copies 4th component w from VECT into
412 (* (aref matrix i j
) (aref vect j
)))))
415 (m* (rotation-matrix (/ pi
2) (v 0d0
0d0
1d0
)) (v 1d0
))
417 (declaim (ftype (function (vec vec
)
418 (values vec
&optional
))
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)))))
431 (deftype optical-component
()
432 `(or disk mirror lens thin-objective
))
436 (start (v) :type vec
)
437 (direction (v) :type vec
))
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
))
456 (defun rotate-vector (angle axis vector
)
457 (let ((m (rotation-matrix angle axis
)))
465 ;; -----+-------+------------o------------\------------------------
467 (declaim (ftype (function (double-float double-float thin-objective
)
468 (values double-float
&optional
))
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)
477 (let* ((h (sqrt (+ (* point-x point-x
) (* point-y point-y
))))
478 (phi (asin (/ h focal-length
))))
482 (let* ((f (focal-length-from-magnification 63d0
))
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
))
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
)))