scan of worm works now
[woropt.git] / lens / lens.lisp
bloba42a070008a2abf75de4181d2b838a44eaafd460
1 ;; for i in `cat lens.lisp|grep "^(defun"|cut -d " " -f2`;do echo \#:$i ;done
2 (in-package :lens)
4 (declaim (optimize (speed 2) (safety 3) (debug 3)))
6 (defgeneric intersect (ray object))
8 (defmethod intersect ((ray ray) (plane plane))
9 "Find the point where a ray intersects a plane."
10 (declare (values vec &optional))
11 (with-slots (center normal) plane
12 (with-slots ((start vector::start) (dir vector::direction)) ray
13 (let* ((hess-dist (v. center normal)) ;; distance of plane to origin
14 (div (v. normal dir)))
15 (when (< (abs div) 1d-12) ;; plane and ray are parallel
16 (error 'ray-lost))
17 (let ((eta (/ (- hess-dist (v. normal start))
18 ;; scaling along ray to hit exactly on plane
19 div)))
20 (v+ start (v* dir eta)))))))
22 #+nil
23 (intersect
24 (make-instance 'ray :start (v 0 1 -1) :direction (v 0 0 1))
25 (make-instance 'plane :normal (v 0 0 1) :center (v)))
27 (defgeneric refract (ray object))
30 ;; --\
31 ;; | -----\ intersection
32 ;; | --+
33 ;; | \ ---|--\
34 ;; | | -----/ | ----\
35 ;; | ----+/ r' | ----\
36 ;; f |--/ c | ----\ dir
37 ;; | r | ---\
38 ;; | |rho ----\
39 ;; | | ----\
40 ;; | | ----\
41 ;; | | phi ----\
42 ;; -------+----------<-------+-------------------------------------------
43 ;; | n | center
44 ;; | |
45 ;; | |
46 ;; | |
47 ;; |
48 ;; f |
50 (defmethod refract ((ray ray) (lens lens))
51 "Return new ray after refraction on thin lens. In general you will
52 have to normalize its direction. The refraction on an objective needs
53 the non-normalized result. When the ray doesn't hit the lens the
54 condition RAY-LOST is signalled."
55 (declare (values ray &optional))
56 (check-direction-norm ray)
57 (with-slots ((start vector::start)
58 (dir vector::direction)) ray
59 (with-slots ((c center)
60 (n normal)
61 (f focal-length)
62 (r radius)) lens
63 (check-unit-norm n)
64 (let* ((i (intersect ray lens))
65 (rho (v- i c)))
66 (when (< r (norm rho)) ;; ray doesn't hit free aperture of lens
67 (error 'ray-lost))
68 (let* ((cosphi (v. n dir)))
69 (make-instance 'ray
70 :start i
71 :direction (v- (v* dir (/ f cosphi))
72 rho)))))))
73 #+nil
74 (handler-case
75 (refract (make-instance 'ray
76 :start (v 0 .1 -10)
77 :direction (v 0 0 1))
78 (make-instance 'lens
79 :focal-length 10.0
80 :center (v)
81 :normal (v 0 0 1)
82 :radius 200d0))
83 (ray-lost () 3))
86 ;; |
87 ;; |
88 ;; --------------- s |
89 ;;-/ X---- |
90 ;; / \-- ---- |
91 ;; ro/ \-- \--+----
92 ;; | ----/ | \-------
93 ;; / -----/ \ | \------
94 ;; / ----/ ru \ | \-------
95 ;; /-/ \|rho \-------
96 ;; | \---
97 ;; |
98 ;; ------------------------------+-----------------------------------------
99 ;; |
100 ;; | nf /
101 ;; +--------------------
102 ;; | /
104 ;; 2008 Hwang Simulation of an oil immersion objective lens...
105 (defmethod refract ((ray ray) (objective objective))
106 "Returns the refracted ray with the starting point on the principle
107 sphere of the objective. If the cap of the principal sphere (given by
108 NA) is missed then the condition LOST-RAY is signalled."
109 (declare (values ray &optional))
110 (check-direction-norm ray)
111 (with-slots ((start vector::start)
112 (dir vector::direction)) ray
113 (with-slots ((c center)
114 (n normal)
115 (f focal-length)
116 (rad radius)
117 (bfprad bfp-radius)
118 (ri immersion-index)
119 (na numerical-aperture)) objective
120 (check-unit-norm n)
121 ;; call refract for lens and refine the result
122 (let* ((lens-ray (call-next-method ray objective))
123 (r (vector::direction lens-ray))
124 (i (vector::start lens-ray)) ;; intersection with lens plane
125 (a (v* n (* f (- ri 1))))
126 (ru (v+ r a))
127 (rho (v- i c))
128 (rho2 (v. rho rho))
129 (nf (* ri f))
130 (nf2 (* nf nf))
131 (rat (- nf2 rho2)))
132 (when (<= rat 0d0) ;; ray doesn't hit principal sphere
133 (error 'ray-lost))
134 (let* ((s (v* dir (- nf (sqrt rat))))
135 (ro (v- ru s))
136 (nro (normalize ro))
137 (cosu (v. nro n))
138 (sinu2 (- 1 (* cosu cosu)))
139 (sinu-max (/ na ri)))
140 (when (<= (* sinu-max sinu-max) sinu2) ;; angle to steep
141 (error 'ray-lost))
142 (make-instance 'ray
143 :direction ro
144 :start (v+ s i)))))))
145 #+nil
146 (handler-case
147 (refract (make-instance 'ray
148 :direction (normalize (v 0 .001 1))
149 :start (v 0 0 -10))
150 (make-objective :center (v)
151 :normal (v 0 0 1)))
152 (ray-lost () 'lost))
154 ;; +-------+--
155 ;; | | \-----
156 ;; h | | \-----
157 ;; | | \----
158 ;; | | phi \-----
159 ;; -----+-------+------------o------------\------------------------
160 ;; (n-1)f f f
162 ;; 2005wolf p. 180 formula (8) sine condition for one image in infinity
163 (defmethod find-inverse-ray-angle ((objective objective) point-x point-y)
164 "Find the angle in the back focal plane for a ray that originates
165 from a POINT (coordinates in mm) in the focal plane in the object. The
166 coordinates of the point are given relative to the center of the front
167 focal plane."
168 (declare (double-float point-x point-y)
169 (values double-float &optional))
170 (with-slots (focal-length)
171 objective
172 (let* ((h (sqrt (+ (* point-x point-x) (* point-y point-y))))
173 (phi (asin (/ h focal-length))))
174 phi)))
176 #+nil
177 (let* ((f (focal-length-from-magnification 63d0))
178 (ri 1.515d0)
179 (obj (make-objective :immersion-index ri
180 :normal (v 0d0 0d0 -1d0)
181 :center (make-vec 0d0 0d0 (- f))))
182 (bfp-radius (back-focal-plane-radius obj))
183 (field (make-vec .0d0 0d0 (- (+ f (* ri f)))))
184 (pupil (make-vec bfp-radius 0d0 0d0)))
185 (find-inverse-ray-angle obj 0d0 .07d0))