3 (defmethod draw-hidden-spheres ((model sphere-model
))
4 (with-slots (centers-mm radii-mm
) model
8 (loop for c in centers-mm and r in radii-mm do
13 (glut:solid-sphere r
(* 2 n
) n
)
16 (glut:wire-sphere
(* 1.06 r
) (* 2 n
) n
)
19 (glut:wire-sphere
(* 1.12 r
) (* 2 n
) n
)))))))
21 ;; sketch of the coordinate system:
23 ;; the objective sits below the sample. its (thin) lens has a distance
24 ;; nf to the in-focus plane. z is directed from the objective towards
25 ;; the sample. the first slice of the stack is nearest to the
26 ;; objective. in the test sample the single sphere is centered on
27 ;; slice 10, the plane of spheres is in slice 20.
33 ;; --------+-----/------+--------- z-plane-mm = z_slice * n * dz * 1d-3
34 ;; +---/-+------+ -- 0
41 ;; | -----+----------------- - nf + z-plane-mm
46 ;; ----+---------+----------------- - f - nf + z-plane-mm
47 ;; | | back focal plane
50 (defmacro pop-until-end
(l)
52 (pop ,l
) ;; needs to be a macro so that pop has an effect
59 (view-center (list (v))))
60 (defun update-tex (data)
61 "Supply either an image or a volume of unsigned-byte. It will be
62 displayed as a texture."
64 (defun ensure-uptodate-tex ()
65 "Call this function within an OpenGL context to check for new
71 (setf tex
(make-instance 'texture-luminance-ub8
:data new-tex
))
73 (defun update-scale (target-value &optional
(steps 10))
74 "Smooth zooming. Meant to enable viewing of the microscopic sample
75 as well as the macroscopic objective with its back focal plane."
76 (let* ((current (car scale
)))
78 (loop for i from
1 upto steps collect
79 (let* ((x (/ (* 1d0 i
) steps
)))
80 (+ (* (- 1 x
) current
) (* x target-value
)))))))
81 (defun update-view-center (target-value &optional
(steps 10))
82 "Create smooth transition to different view center. This is meant
83 to shift the current nucleus into view."
84 (let ((current (car view-center
)))
86 (loop for i from
1 upto steps collect
87 (let* ((x (/ (* 1d0 i
) steps
)))
88 (v+ (v* current
(- 1 x
)) (v* target-value x
)))))))
89 (defun rotate-translate-sample-space ()
90 "Wiggle sample around a point that has been set via
92 (when (< 360 (incf rot
10))
94 (let ((center (pop-until-end view-center
))
95 (angle (+ 120 (* 15 (expt (* .5
100 (gl:rotate angle
0 0 1)
101 (translate-v (v* center -
1d0
))))
102 (defmethod draw ((model sphere-model
) &key
(nucleus 0)
103 (objective (lens:make-objective
:normal
(v 0 0 1)
105 (win-x/r
0d0
) (win-y/r
0d0
)
107 (z-plane-mm (vec-z (elt
108 (raytrace::centers-mm model
) nucleus
)))
112 (declare (fixnum nucleus
)
113 (lens:objective objective
)
114 (double-float win-x
/r win-y
/r win-r
/r
))
115 (gl:clear-color
1 1 1 1)
116 (with-slots (dimensions spheres centers-mm centers dx dy dz
) model
117 (with-slots ((f lens
::focal-length
)
118 (bfp-radius lens
::bfp-radius
)
119 (center lens
::center
)
120 (na lens
::numerical-aperture
)
121 (ri lens
::immersion-index
)) objective
122 (setf center
(make-vec 0d0
0d0
(+ (- (* ri f
)) z-plane-mm
)))
123 (destructuring-bind (z y x
)
125 (let* ((cent (elt centers-mm nucleus
))
129 (gl:enable
:depth-test
)
130 (let ((s (pop-until-end scale
)))
132 #+nil
(gl:translate
0 0 (- nf
))
133 (rotate-translate-sample-space)
134 (draw-axes) ;; move axes into focal plane
135 (draw-hidden-spheres model
)
136 (let ((lens (make-instance 'lens
:disk
:center center
138 (bfp (make-instance 'lens
:disk
:center
139 (v- center
(make-vec 0d0
0d0 f
))
140 :radius bfp-radius
)))
141 (gl:color
.4 .4 .4) ;; draw planes defining the objective
144 (labels ((plane (direction position
)
145 "Define a plane that is perpendicular to
146 an axis and crosses it at POSITION."
147 (declare ((member :x
:y
:z
) direction
)
148 (double-float position
))
149 (let* ((normal (ecase direction
153 (let* ((center (v* normal position
))
154 (outer-normal (normalize center
)))
155 (make-instance 'lens
:disk
160 (z- (* 1d-3 ri dz z
))
161 (p-z (plane :z z-
)) ;; slice that's furthest from objective
162 (x+ (* 1d-3 ri dx x
))
163 (y+ (* 1d-3 ri dy x
)))
164 (let* ((start (make-vec 0d0
0d0 z
+)) ;; draw bounding box
165 (dim (make-vec x
+ y
+ z-
)))
167 (draw-wire-box start
(v+ start dim
)))
168 ;; rays from back focal plane through sample
169 (loop for
(exit enter
) in
170 (make-rays objective model nucleus
171 (sample-circles nr-ffp nr-bfp nr-theta
)
172 win-x
/r win-y
/r win-r
/r
) do
173 (let ((h-z (lens:intersect exit p-z
)))
176 (gl:with-primitive
:line-strip
177 (vertex-v (vector::start enter
))
178 (vertex-v (vector::start exit
))
180 (let* ((ty (/ (* 1d0
(vec-i-y (elt centers
0)))
182 (gl:color
1 1 1 1) ;; load and display the 3d texture
183 (ensure-uptodate-tex)
185 (draw-xz tex x
+ 0d0 z
+ z-
:ty ty
:y y-mm
))))))))))))
188 (loop for
(exit enter
) in
189 (make-rays (lens:make-objective
) *model
* 0 (sample-circles 2 2 1)
192 (vector::start enter
)))
196 (list (lens:make-objective
) (sample-circles 2 2 2)))