first commit
[woropt.git] / run.lisp
blob9f4180a759f72afd7cb8175d5d4c1729142a3f17
1 #.(progn (require :asdf)
2 (require :vol)
3 (require :psf)
4 (require :simplex-anneal)
5 (require :raytrace)
6 (require :lens))
8 (defpackage :run
9 (:use :cl :vol :raytrace))
10 (in-package :run)
11 #||
12 mkdir ~/tmp
13 cp /home/martin/0519/MedianofCelegans-10-02-09-LSM700-t58.tif ~/tmp/med.tif
14 cd ~/tmp/
15 tiffsplit med.tif
16 for i in *.tif ; do tifftopnm $i > `basename $i .tif`.pgm;done
17 ||#
19 (deftype vec-i ()
20 `(simple-array fixnum (3)))
22 (defstruct (vec-i (:type (vector fixnum)))
23 (z 0) (y 0) (x 0))
25 (declaim (ftype (function (vec-i vec-i)
26 (values fixnum &optional))
27 v.-i))
28 (defun v.-i (a b)
29 (+ (* (vec-i-x a) (vec-i-x b))
30 (* (vec-i-y a) (vec-i-y b))
31 (* (vec-i-z a) (vec-i-z b))))
33 (declaim (ftype (function (vec-i vec-i)
34 (values vec-i &optional))
35 v--i v+-i))
36 (defun v--i (a b)
37 (make-vec-i :x (- (vec-i-x a) (vec-i-x b))
38 :y (- (vec-i-y a) (vec-i-y b))
39 :z (- (vec-i-z a) (vec-i-z b))))
40 (defun v+-i (a b)
41 (make-vec-i :x (+ (vec-i-x a) (vec-i-x b))
42 :y (+ (vec-i-y a) (vec-i-y b))
43 :z (+ (vec-i-z a) (vec-i-z b))))
45 (declaim (ftype (function (vec-i)
46 (values double-float &optional))
47 norm-i))
48 (defun norm-i (a)
49 (sqrt (* 1d0 (v.-i a a))))
51 (declaim (ftype (function (string (simple-array (complex double-float) 3)
52 &key (:function function))
53 (values null &optional))
54 save-stack))
55 (defun save-stack (fn vol &key (function #'realpart))
56 (ensure-directories-exist fn)
57 (destructuring-bind (z y x)
58 (array-dimensions vol)
59 (let ((b (make-array (list y x)
60 :element-type '(unsigned-byte 8))))
61 (dotimes (k z)
62 (do-rectangle (j i 0 y 0 x)
63 (setf (aref b j i)
64 (clamp (floor (* 255 (funcall function (aref vol k j i)))))))
65 (write-pgm b (format nil "~a/~3,'0d.pgm" fn k)))))
66 nil)
68 (declaim (ftype (function (string (simple-array (unsigned-byte 8) 3))
69 (values null &optional))
70 save-stack-ub8))
71 (defun save-stack-ub8 (fn vol)
72 (ensure-directories-exist fn)
73 (destructuring-bind (z y x)
74 (array-dimensions vol)
75 (let ((b (make-array (list y x)
76 :element-type '(unsigned-byte 8))))
77 (dotimes (k z)
78 (do-rectangle (j i 0 y 0 x)
79 (setf (aref b j i)
80 (aref vol k j i)))
81 (write-pgm b (format nil "~a/~3,'0d.pgm" fn k)))))
82 nil)
85 (declaim (ftype (function (fixnum fixnum string
86 (simple-array (complex double-float) 3))
87 (values null &optional))
88 save-scaled-stack))
89 (defun save-scaled-stack (h w fn vol)
90 (destructuring-bind (z y x)
91 (array-dimensions vol)
92 (let* ((b (make-array (list y x)
93 :element-type '(unsigned-byte 8)))
94 (bb (make-array (list h w)
95 :element-type '(unsigned-byte 8))))
96 (dotimes (k z)
97 (do-rectangle (j i 0 y 0 x)
98 (setf (aref b j i)
99 (clamp (floor (* 255 (realpart (aref vol k j i)))))))
100 (do-rectangle (j i 0 h 0 w)
101 (setf (aref bb j i)
102 (floor (interpolate2 b (* (/ 1d0 h) j y) (* (/ 1d0 w) i x)))))
103 (write-pgm bb (format nil "~a~3,'0d.pgm" fn k)))))
104 nil)
106 (declaim (ftype (function ((simple-array (complex double-float) 3)
107 (simple-array (complex double-float) 3))
108 (values (simple-array (complex double-float) 3) &optional))
109 .*))
110 (defun .* (vola volb)
111 (let ((result (make-array (array-dimensions vola)
112 :element-type (array-element-type vola))))
113 (destructuring-bind (z y x)
114 (array-dimensions vola)
115 (do-box (k j i 0 z 0 y 0 x)
116 (setf (aref result k j i)
117 (* (aref vola k j i)
118 (aref volb k j i)))))
119 result))
121 (declaim (ftype (function (double-float (simple-array (complex double-float) 3))
122 (values (simple-array (complex double-float) 3) &optional))
123 s*))
125 (defun s* (s vol)
126 (let* ((a (sb-ext:array-storage-vector vol))
127 (n (length a)))
128 (dotimes (i n)
129 (setf (aref a i) (* s (aref a i)))))
130 vol)
133 (declaim (ftype (function ((simple-array (complex double-float) 3)
134 (simple-array (complex double-float) 3))
135 (values (simple-array (complex double-float) 3) &optional))
136 convolve3-circ convolve3))
137 (defun convolve3-circ (vola volb)
138 (let* ((da (array-dimensions vola))
139 (db (array-dimensions volb))
140 (compare-ab (map 'list #'(lambda (x y) (eq x y)) da db)))
141 (when (some #'null compare-ab)
142 (error "convolve3-circ expects both input arrays to have the same dimensions.")))
143 (ift3 (.* (ft3 vola) (ft3 volb))))
145 ;; volb is the kernel
146 (defun convolve3 (vola volb)
147 (destructuring-bind (za ya xa)
148 (array-dimensions vola)
149 (destructuring-bind (zb yb xb)
150 (array-dimensions volb)
151 (let* ((biga (make-array (list (+ za zb)
152 (+ ya yb)
153 (+ xa xb))
154 :element-type '(complex double-float)))
155 (bigb (make-array (array-dimensions biga)
156 :element-type '(complex double-float)))
157 (fzb (floor zb 2))
158 (fyb (floor yb 2))
159 (fxb (floor xb 2))
160 (fza (floor za 2))
161 (fya (floor ya 2))
162 (fxa (floor xa 2)))
163 (do-box (k j i 0 za 0 ya 0 xa)
164 (setf (aref biga (+ k fzb) (+ j fyb) (+ i fxb))
165 (aref vola k j i)))
166 (do-box (k j i 0 zb 0 yb 0 xb)
167 (setf (aref bigb (+ k fza) (+ j fya) (+ i fxa))
168 (aref volb k j i)))
169 (let* ((conv (convolve3-circ biga (fftshift3 bigb)))
170 (result (make-array (array-dimensions vola)
171 :element-type '(complex double-float))))
172 (do-box (k j i 0 za 0 ya 0 xa)
173 (setf (aref result k j i)
174 (aref conv (+ k fzb) (+ j fyb) (+ i fxb))))
175 result)))))
177 #+nil
178 (let ((a (make-array (list 100 200 300)
179 :element-type '(complex double-float)))
180 (b (make-array (list 10 200 30)
181 :element-type '(complex double-float))))
182 (convolve3 a b)
183 nil)
185 (declaim (ftype (function (double-float fixnum fixnum fixnum &key (:scale-z double-float))
186 (values (simple-array (complex double-float) 3) &optional))
187 draw-sphere))
188 (defun draw-sphere (radius z y x &key (scale-z 1d0))
189 (let ((sphere (make-array (list z y x)
190 :element-type '(complex double-float))))
191 (do-box (k j i 0 z 0 y 0 x)
192 (let ((r (sqrt (+ (square (- i (* .5d0 x)))
193 (square (- j (* .5d0 y)))
194 (square (* scale-z (- k (* .5d0 z))))))))
195 (setf (aref sphere k j i)
196 (if (< r radius)
197 (complex 1d0)
198 (complex 0d0)))))
199 sphere))
201 (declaim (ftype (function ()
202 (values (simple-array vec-i 1)
203 (simple-array double-float 1)
204 cons
205 &optional))
206 find-centers))
207 (defvar *stack* ())
208 ;; to find centers of cells do a convolution with a sphere
209 (defun find-centers ()
210 (let* ((stack-byte (read-stack "/home/martin/tmp/xa*.pgm"))
211 (stack (make-array (array-dimensions stack-byte)
212 :element-type '(complex double-float))))
213 (destructuring-bind (z y x)
214 (array-dimensions stack)
215 (dotimes (k z)
216 (dotimes (j y)
217 (dotimes (i x)
218 (let ((v (+ (* .43745d0 k)
219 (aref stack-byte k j i))))
220 (setf
221 (aref stack-byte k j i) (clamp (floor v))
222 (aref stack k j i) (complex v))))))
223 #+nil(setf *stack* stack)
224 ;; find centers of cells by convolving with sphere
225 (let* ((sphere (draw-sphere 11d0 z y x :scale-z 5d0))
226 (conv (convolve3-circ stack (fftshift3 sphere)))
227 (conv-byte (make-array (list y x)
228 :element-type '(unsigned-byte 8)))
229 (centers (make-array 0 :element-type 'vec-i
230 :initial-element (make-vec-i)
231 :adjustable t
232 :fill-pointer t))
233 (center-heights (make-array 0 :element-type 'double-float
234 :adjustable t
235 :fill-pointer t)))
236 (loop for k from 6 below (- z 3) do
237 (loop for j from 1 below (1- y) do
238 (loop for i from 1 below (1- x) do
239 (let ((v (abs (aref conv k j i))))
240 (setf (aref conv-byte j i)
241 (if (and (< (abs (aref conv k j (1- i))) v)
242 (< (abs (aref conv k j (1+ i))) v)
243 (< (abs (aref conv k (1- j) i)) v)
244 (< (abs (aref conv k (1+ j) i)) v)
245 (< (abs (aref conv (1- k) j i)) v)
246 (< (abs (aref conv (1+ k) j i)) v))
247 (progn
248 (vector-push-extend
249 (make-vec-i :z k :y j :x i)
250 centers)
251 (vector-push-extend v center-heights)
253 (clamp (floor (/ v (* 4e2 x y z)))))))))
254 #+nil(write-pgm conv-byte
255 (format nil "/home/martin/tmp/conv~3,'0d.pgm" k)))
256 (let ((c (make-array (length centers)
257 :element-type 'vec-i
258 :initial-contents centers))
259 (ch (make-array (length center-heights)
260 :element-type 'double-float
261 :initial-contents center-heights)))
262 (values c ch (array-dimensions stack)))))))
265 (declaim (ftype (function (fixnum)
266 (values fixnum &optional))
267 ensure-even))
268 (defun ensure-even (x)
269 (if (eq 1 (mod x 2))
270 (1+ x)
273 (declaim (ftype (function (double-float (simple-array vec-i 1)
274 &key (:div-x double-float)
275 (:div-y double-float)
276 (:div-z double-float))
277 (values (simple-array (complex double-float) 3)
278 &optional))
279 draw-scaled-spheres))
280 ;; put points into the centers of nuclei and convolve a sphere around each
281 (defun draw-scaled-spheres (radius centers &key (div-x 5d0)
282 (div-y 5d0)
283 (div-z 1d0))
284 (let* ((max-x (floor (reduce #'max
285 (map '(simple-array fixnum 1) #'vec-i-x
286 centers)) div-x))
287 (max-y (floor (reduce #'max
288 (map '(simple-array fixnum 1) #'vec-i-y
289 centers)) div-y))
290 (max-z (floor (reduce #'max
291 (map '(simple-array fixnum 1) #'vec-i-z
292 centers)) div-z))
293 (cr (ceiling radius))
294 (rh (floor radius 2))
295 (x (ensure-even (+ max-x cr)))
296 (y (ensure-even (+ max-y cr)))
297 (z (ensure-even (+ max-z cr)))
298 (dims (list z y x))
299 (points (make-array dims
300 :element-type '(complex double-float))))
301 (loop for c across centers do
302 (setf (aref points
303 (- (floor (vec-i-z c) div-z) rh)
304 (- (floor (vec-i-y c) div-y) rh)
305 (- (floor (vec-i-x c) div-x) rh))
306 (complex 1d0 0d0)))
307 (convolve3-circ points (draw-sphere radius z y x))))
309 (declaim (ftype (function ((simple-array (complex double-float) 3))
310 (values (simple-array (unsigned-byte 8) 3)
311 &optional))
312 convert-vol))
313 (defun convert-vol (vol)
314 (destructuring-bind (z y x)
315 (array-dimensions vol)
316 (let ((result (make-array (array-dimensions vol)
317 :element-type '(unsigned-byte 8))))
318 (do-box (k j i 0 z 0 y 0 x)
319 (setf (aref result k j i)
320 (clamp (floor (* 255 (abs (aref vol k j i)))))))
321 result)))
323 (declaim (ftype (function ((simple-array (complex double-float) 2)
324 &optional function)
325 (values (simple-array (unsigned-byte 8) 2)
326 &optional))
327 convert-img))
328 (defun convert-img (img &optional (function #'abs))
329 (destructuring-bind (y x)
330 (array-dimensions img)
331 (let ((result (make-array (array-dimensions img)
332 :element-type '(unsigned-byte 8))))
333 (do-rectangle (j i 0 y 0 x)
334 (setf (aref result j i)
335 (clamp (floor (funcall function (aref img j i))))))
336 result)))
338 (declaim (ftype (function (double-float (simple-array vec-i 1)
339 fixnum fixnum
340 fixnum)
341 (values (simple-array (complex double-float) 3)
342 &optional))
343 draw-spheres))
344 ;; put points into the centers of nuclei and convolve a sphere around each
345 (defun draw-spheres (radius centers z y x)
346 (let* ((dims (list z y x))
347 (points (make-array dims
348 :element-type '(complex double-float)))
349 (n (length centers)))
350 (dotimes (i n)
351 (let ((c (aref centers i)))
352 (setf (aref points
353 (* 5 (vec-i-z c))
354 (vec-i-y c)
355 (vec-i-x c))
356 (complex 1d0 0d0))))
357 (convolve3-circ points (fftshift3 (draw-sphere radius z y x)))))
361 #+nil
362 (progn
363 (defparameter *merge*
364 (let ((a (make-array (array-dimensions *stack*)
365 :element-type '(unsigned-byte 8))))
366 (destructuring-bind (z y x)
367 (array-dimensions *stack*)
368 (do-box (k j i 0 z 0 y 0 x)
369 (setf (aref a k j i)
370 (clamp (if (eq 0 (aref *blobs*
371 k j i))
372 (* (aref *stack* k j i) 2)
373 0))))
374 a)))
375 (save-stack-ub "/home/martin/tmp/merge" *merge*))
377 ;; (- z k 1) (- y j 1) (- x i 1)
381 #+nil ;; model with isotropic pixels
382 (save-stack-ub "/home/martin/tmp/iso/iso"
383 (convert-vol (draw-scaled-spheres 2d0 *centers*)))
385 #+nil
386 (save-stack-ub "/home/martin/tmp/blobs" *blobs*)
388 #+nil
389 (save-scaled-stack 100 100 "/home/martin/tmp/sca" *blobs*)
391 #+nil ;; find maximum
392 (reduce #'max (map 'vector #'abs (sb-ext:array-storage-vector *stack*)))
394 #+nil ;; scale to 1
395 (destructuring-bind (z y x)
396 (array-dimensions *stack*)
397 (do-box (k j i 0 z 0 y 0 x)
398 (setf (aref *stack* k j i)
399 (/ (aref *stack* k j i) 257d0))))
401 #+nil
402 (save-stack "/home/martin/tmp/stack" *stack*)
405 #+nil ;; make a text image of the psf
406 (let ((numerical-aperture 1.38d0))
407 (psf:init :numerical-aperture numerical-aperture)
408 (multiple-value-bind (u v)
409 (psf:get-uv 0 1.5 3 :numerical-aperture numerical-aperture)
410 (let* ((nu 31)
411 (nv 61)
412 (a (psf:integ-all nu nv (/ u nu) (/ v nv)))
413 (max (aref a 0 0))
414 (scale (/ 99 max)))
415 (destructuring-bind (uu vv)
416 (array-dimensions a)
417 (format t "~%")
418 (dotimes (u uu)
419 (dotimes (v vv)
420 (format t "~2d" (truncate (* scale (aref a u v)))))
421 (format t "~%"))))))
424 #+nil
425 (time
426 (let ((z 18d0))
427 (save-stack "/home/martin/tmp/psf"
428 (fftshift3 (ft3 (sim-psf 128 128 128 z (* .5d0 z))))
429 :function #'(lambda (x) (* .01d0 (abs x))))))
431 ;; worm stack 0.198 um in X and Y and 1 um in Z
433 #+nil
434 (array-dimensions *blobs*)
436 #+nil ;; write ft of object
437 (time
438 (save-stack "/home/martin/tmp/kblobs" (fftshift3 (ft3 *blobs*))
439 :function #'(lambda (x) (* 1d-4 (abs x)))))
441 #+nil ;; write ft of psf
442 (time
443 (destructuring-bind (z y x)
444 (array-dimensions *blobs*)
445 (save-stack "/home/martin/tmp/otf"
446 (fftshift3 (ft3 (sim-psf z y x
447 (* .198d0 z) (* .198d0 (ceiling (* (sqrt 2d0) (max y x)))))))
448 :function #'(lambda (x) (* 1d-1 (abs x))))))
450 (declaim (ftype (function ((simple-array (complex double-float) (* * *)))
451 (values (simple-array (complex double-float) (* * *))
452 &optional))
453 zshift3))
454 (defun zshift3 (in)
455 (let ((out (make-array (array-dimensions in)
456 :element-type '(complex double-float))))
457 (destructuring-bind (w2 w1 w0)
458 (array-dimensions in)
459 (dotimes (k w2)
460 (dotimes (j w1)
461 (dotimes (i w0)
462 (let* ((kk (if (> k (/ w2 2))
463 (+ w2 (/ w2 2) (- k))
464 (- (/ w2 2) k))))
465 (setf (aref out k j i)
466 (aref in kk j i))
467 nil)))))
468 out))
472 #+nil
473 (time
474 (destructuring-bind (z y x)
475 (array-dimensions *blobs*)
476 (let ((psf (sim-psf z y x
477 (* .198d0 z) (* .198d0 (ceiling (* (sqrt 2d0) (max y x)))))))
478 (save-stack "/home/martin/tmp/impsf"
479 (convolve3 *blobs* psf)
480 :function #'(lambda (x) (* 1d-8 (realpart x)))))))
483 (declaim (ftype (function ((simple-array (complex double-float) 3)
484 &optional fixnum)
485 (values (simple-array (complex double-float) 2)
486 &optional))
487 cross-section-xz))
488 (defun cross-section-xz (a &optional (y (floor (array-dimension a 1) 2)))
489 (destructuring-bind (z y-size x)
490 (array-dimensions a)
491 (unless (<= 0 y (1- y-size))
492 (error "Y is out of bounds."))
493 (let ((b (make-array (list z x)
494 :element-type `(complex double-float))))
495 (do-rectangle (j i 0 z 0 x)
496 (setf (aref b j i)
497 (aref a j y i)))
498 b)))
500 (declaim (ftype (function ((simple-array (complex double-float) 2)
501 &key (:function function))
502 (values (simple-array (unsigned-byte 8) 2)
503 &optional))
504 normalize-img))
505 (defun normalize-img (a &key (function #'abs))
506 (destructuring-bind (y x)
507 (array-dimensions a)
508 (let ((b (make-array (list y x)
509 :element-type 'double-float)))
510 (do-rectangle (j i 0 y 0 x)
511 (setf (aref b j i)
512 (funcall function (aref a j i))))
513 (let* ((b1 (sb-ext:array-storage-vector b))
514 (ma (reduce #'max b1))
515 (mi (reduce #'min b1))
516 (result (make-array (list y x)
517 :element-type '(unsigned-byte 8)))
518 (s (/ 255d0 (- ma mi))))
519 (do-rectangle (j i 0 y 0 x)
520 (setf (aref result j i)
521 (floor (* s (- (aref b j i) mi)))))
522 result))))
524 (declaim (ftype (function ((simple-array (complex double-float) 3)
525 &key (:function function))
526 (values (simple-array (unsigned-byte 8) 3)
527 &optional))
528 normalize-vol))
529 (defun normalize-vol (a &key (function #'abs))
530 (destructuring-bind (z y x)
531 (array-dimensions a)
532 (let ((b (make-array (list z y x)
533 :element-type 'double-float)))
534 (do-box (k j i 0 z 0 y 0 x)
535 (setf (aref b k j i)
536 (funcall function (aref a k j i))))
537 (let* ((b1 (sb-ext:array-storage-vector b))
538 (ma (reduce #'max b1))
539 (mi (reduce #'min b1))
540 (result (make-array (list z y x)
541 :element-type '(unsigned-byte 8)))
542 (s (/ 255d0 (- ma mi))))
543 (do-box (k j i 0 z 0 y 0 x)
544 (setf (aref result k j i)
545 (floor (* s (- (aref b k j i) mi)))))
546 result))))
548 #+nil ;; compare intensity and |e-field|^2
549 (time
550 (let ((z 128)
551 (y 128)
552 (x 128))
553 (multiple-value-bind (e0 e1 e2)
554 (psf:electric-field-psf z x y 10d0 5d0)
555 (let ((intens (make-array (array-dimensions e0)
556 :element-type '(complex double-float))))
557 (do-box (k j i 0 z 0 y 0 x)
558 (setf (aref intens k j i) (complex (+ (psf::abs2 (aref e0 k j i))
559 (psf::abs2 (aref e1 k j i))
560 (psf::abs2 (aref e2 k j i))))))
561 (let* ((k0 (fftshift3 (ft3 intens)))
562 (k1 (fftshift3 (ft3 (psf:intensity-psf z y x 10d0 5d0))))
563 (k- (make-array (array-dimensions k0)
564 :element-type '(complex double-float))))
565 (do-box (k j i 0 z 0 y 0 x)
566 (setf (aref k- k j i) (- (aref k0 k j i)
567 (aref k1 k j i))))
568 (save-stack "/home/martin/tmp/intens0"
570 :function #'(lambda (x) (* 1d-1 (abs x))))
571 (write-pgm (convert-img (cross-section-xz k-)
572 #'(lambda (z) (* 1e-1 (abs z))))
573 "/home/martin/tmp/intens0xz.pgm"))))))
575 ;; create psf by blocking light in the back-focal plane. only a disk
576 ;; centered on point p=(CENTER-X, CENTER-Y) with r=RADIUS is left
577 ;; transparent. p=(0,0) and r=1 will unblock the full
578 ;; bfp. p=(.9,0). r=.1 will illuminate with a high angle from positive
579 ;; x.
581 ;; SIZE-X and SIZE-Z give the extend in um. the extend in the y
582 ;; direction is set to SIZE-X.
583 (declaim (ftype (function (double-float double-float double-float
584 &key (:x fixnum) (:y fixnum) (:z fixnum)
585 (:size-x double-float)
586 (:size-z double-float)
587 (:wavelength double-float)
588 (:numerical-aperture double-float)
589 (:immersion-index double-float)
590 (:integrand-evaluations fixnum))
591 (values (simple-array (complex double-float) 3)))
592 angular-psf))
593 (defun angular-psf (center-x center-y radius &key
594 (x 64) (y 64) (z 64) (size-x 12d0)
595 (size-z 12d0)
596 (wavelength .480d0)
597 (numerical-aperture 1.38d0)
598 (immersion-index 1.515d0)
599 (integrand-evaluations 31))
600 (let* ((dx (/ x size-x)) ;; pixels/um
602 ;; calculate the electric field in focus
603 (multiple-value-bind (e0 e1 e2)
604 (psf:electric-field-psf z y x size-z size-x
605 :numerical-aperture numerical-aperture
606 :immersion-index immersion-index
607 :wavelength wavelength
608 :integrand-evaluations integrand-evaluations)
609 (write-pgm (normalize-img (cross-section-xz e0))
610 "/home/martin/tmp/cut-asf-e0-no.pgm")
611 ;; k0, k1 and k2 contain sections of the k-sphere
612 (let* ((k0 (fftshift3 (ft3 e0)))
613 (k1 (fftshift3 (ft3 e1)))
614 (k2 (fftshift3 (ft3 e2)))
615 ;; radius of the circular border of the cut k-sphere
616 ;; sin(phi)=r/k, k=2pi/lambda, sin(phi)=NA/n -> r=k*sin(phi)
617 (sinphi (/ numerical-aperture immersion-index))
618 (klen (/ (* 2d0 pi) wavelength))
619 (bfp-radius (* klen sinphi))
620 (bfp-radius-pixels (* bfp-radius (/ dx (* 2d0 (sqrt 2d0)))))
621 ;; wiil contain distance to center-x,center-y
622 (rad-a (make-array (list y x)
623 :element-type 'double-float)))
624 (defparameter *efield-k* (list k0 k1 k2))
625 (write-pgm (normalize-img (cross-section-xz k0))
626 "/home/martin/tmp/cut-e0-no.pgm")
627 ;; calculate distances to center point for all points in one slice
628 (do-rectangle (j i 0 y 0 x)
629 (let* ((ii (- i (floor x 2) (* center-x bfp-radius-pixels)))
630 (jj (- j (floor y 2) (* center-y bfp-radius-pixels)))
631 (radius (sqrt (+ (* 1d0 ii ii) (* jj jj)))))
632 (setf (aref rad-a j i) radius)))
634 ;; set fourier field to zero if outside of transparent circle
635 (do-box (k j i 0 z 0 y 0 x)
636 (when (< (* radius bfp-radius-pixels) (aref rad-a j i))
637 (setf (aref k0 k j i) (complex 0d0)
638 (aref k1 k j i) (complex 0d0)
639 (aref k2 k j i) (complex 0d0))))
640 (write-pgm (normalize-img (cross-section-xz k0))
641 "/home/martin/tmp/cut-e0.pgm")
643 ;; deteriorated electric fields
644 (setf e0 (ift3 (fftshift3 k0))
645 e1 (ift3 (fftshift3 k1))
646 e2 (ift3 (fftshift3 k2)))
648 ;; calculate energy density of electric field
649 (let ((density (make-array (array-dimensions e0)
650 :element-type '(complex double-float))))
651 (do-box (k j i 0 z 0 y 0 x)
652 (setf (aref density k j i)
653 (complex (+ (psf:abs2 (aref e0 k j i))
654 (psf:abs2 (aref e1 k j i))
655 (psf:abs2 (aref e2 k j i))))))
656 (write-pgm (normalize-img (cross-section-xz density))
657 "/home/martin/tmp/cut-intens.pgm")
658 density)))))
660 #+nil ;; find centers of nuclei
661 (time
662 (multiple-value-bind (c ch dims)
663 (find-centers)
664 (defparameter *centers* c)
665 (defparameter *center-heights* ch)
666 (defparameter *dims* dims)
667 (sb-ext:gc :full t)))
669 #+nil ;; draw the spheres
670 (let ((spheres
671 (destructuring-bind (z y x)
672 *dims*
673 (draw-spheres 7d0 *centers* (* 5 z) y x))))
674 (setf *spheres* spheres)
675 (save-stack-ub8 "/home/martin/tmp/spheres" (normalize-vol *spheres*)))
678 #+nil ;; construct LCOS image
679 (let ((coord (aref *centers* 0))
680 (radius 7d0)
681 (slice (make-array (array-dimensions *spheres*)
682 :element-type '(complex double-float))))
683 (destructuring-bind (z y x)
684 (array-dimensions *spheres*)
685 ;; draw only the center sphere
686 (let* ((xc (vec-i-x coord))
687 (yc (vec-i-y coord))
688 (zc (* 5 (vec-i-z coord)))
689 (k zc))
690 (do-rectangle (j i 0 y 0 x)
691 (let ((r (sqrt (+ (square (* 1d0 (- i xc)))
692 (square (* 1d0 (- j yc)))
693 (square (* 1d0 (- k zc)))))))
694 (setf (aref slice k j i)
695 (if (< r radius)
696 (complex 255d0)
697 (complex 0d0)))))))
698 (defparameter *slice* slice)
699 (save-stack-ub8 "/home/martin/tmp/slice" (convert-vol slice))
700 #+nil (write-pgm (normalize-img (cross-section-xz slice (* 5 (vec-i-z coord))))
701 "/home/martin/tmp/cut-intens2.pgm"))
703 (defparameter *bfp-circ-radius* .5d0)
704 (defparameter *bfp-circ-center-x* (- .999d0 *bfp-circ-radius*))
706 #+nil
707 (time
708 (progn
709 (angular-psf *bfp-circ-center-x* 0d0 *bfp-circ-radius* :x 200 :y 200 :z 200
710 :size-x (* 200 .2d0) :size-z (* 200 .2d0)
711 :integrand-evaluations 160)
712 nil))
714 #+nil ;; light distribution in the specimen
715 ;; default resolution is isotropic 12 um /64 = 187.5 nm/pixel
716 (time
717 (let* ((radius *bfp-circ-radius*)
718 (x *bfp-circ-center-x*)
719 (xx 300)
720 (yy xx)
721 (zz 300)
722 (dx .2d0)
723 (psf (angular-psf x 0d0 radius :x xx :y yy :z zz
724 :size-x (* xx dx) :size-z (* zz dx)
725 :integrand-evaluations 190))
726 (dims (destructuring-bind (z y x)
727 *dims*
728 (list (* z 5) y x)))
729 #+nil (psf-big (make-array dims
730 :element-type '(complex double-float))))
731 #+nil (destructuring-bind (z y x)
732 dims
733 (let ((ox (- (floor x 2) (floor xx 2)))
734 (oy (- (floor y 2) (floor yy 2)))
735 (oz (- (floor z 2) (floor zz 2))))
736 (do-box (k j i 0 zz 0 yy 0 xx)
737 (setf (aref psf-big (+ oz k) (+ oy j) (+ ox i))
738 (aref psf k j i)))))
739 #+nil (defparameter *psf-big* psf-big)
740 #+nil (save-stack-ub8 "/home/martin/tmp/psf-big" (normalize-vol psf-big))
741 (defparameter *psf* psf)
742 (sb-ext:gc :full t)
743 (defparameter *slice-x-psf* (convolve3 *slice* psf))
744 (sb-ext:gc :full t)))
746 #+nil
747 (save-stack-ub8 "/home/martin/tmp/psf" (normalize-vol *psf*))
750 ;; /-
751 ;; --- /---
752 ;; \----- /---
753 ;; \----- /---
754 ;; \---- /---
755 ;; /--------
756 ;; /--- \----
757 ;; /--- \-----
758 ;; /--- \-----
759 ;; -- \--
764 #+nil ;; draw lines into the light distribution in the specimen
765 (destructuring-bind (z y x)
766 (array-dimensions *slice-x-psf*)
767 (let ((coord (elt *centers* 0))
768 (vol (normalize-vol *slice-x-psf*))
769 (dx 2.d-4))
770 (loop for pos in (list (list (* (- (floor x 2) (- (vec-i-x coord) 7)) dx)
771 (* (- (floor y 2) (vec-i-y coord)) dx))
772 (list (* (- (floor x 2) (+ (vec-i-x coord) 7)) dx)
773 (* (- (floor y 2) (vec-i-y coord)) dx))) do
774 (loop for angle in (list 0d0
775 -.4d0
776 (- (- *bfp-circ-center-x* *bfp-circ-radius*))
777 (- (+ *bfp-circ-center-x* *bfp-circ-radius*))) do
778 (draw-ray-into-vol (first pos) (second pos)
779 angle 0d0
781 :shift-z (- (* 5d0 (vec-i-z coord))
782 (floor z 2)))))
783 (save-stack-ub8 "/home/martin/tmp/slice-x-psf" vol)))
786 #+nil ;; draw lines into the volume of the psf
787 (destructuring-bind (z y x)
788 (array-dimensions *psf-big*)
789 (let ((vol (normalize-vol *psf-big*))
790 (dx 2.d-4))
791 (draw-ray-into-vol 0d0 0d0
792 (- (- 1d0 1d-4)) 0d0
794 :center-z (floor z 2))
795 (draw-ray-into-vol 0d0 0d0
796 -.7d0 0d0 vol
797 :center-z (floor z 2))
798 (draw-ray-into-vol 0d0 0d0
799 -.4d0 0d0 vol
800 :center-z (floor z 2))
801 (draw-ray-into-vol 0d0 0d0
802 0d0 0d0 vol
803 :center-z (floor z 2))
804 (save-stack-ub8 "/home/martin/tmp/psf-big" vol)))
807 #+nil ;; excited fluorophores
808 (progn
809 (setf *slice-x-psf-times-spheres* (.* *spheres* *slice-x-psf*))
810 (save-stack-ub8 "/home/martin/tmp/slice-x-psf-times-spheres"
811 (normalize-vol *slice-x-psf-times-spheres*)))
814 #+nil ;; blur with detection psf
815 (time
816 (let* ((radius .5d0)
817 (x (- 1d0 radius))
818 (xx 80)
819 (yy xx)
820 (zz 128)
821 (dx .2d0)
822 (psf (psf:intensity-psf zz yy xx (* zz dx) (* xx dx)
823 :integrand-evaluations 100))
824 (dims (destructuring-bind (z y x)
825 *dims*
826 (list (* z 5) y x)))
827 (psf-big (make-array dims
828 :element-type '(complex double-float))))
829 (setf *psf-big* psf-big)
830 (destructuring-bind (z y x)
831 dims
832 (let ((ox (- (floor x 2) (floor xx 2)))
833 (oy (- (floor y 2) (floor yy 2)))
834 (oz (- (floor z 2) (floor zz 2))))
835 (do-box (k j i 0 zz 0 yy 0 xx)
836 (setf (aref psf-big (+ oz k) (+ oy j) (+ ox i))
837 (aref psf k j i)))))
838 (save-stack-ub8 "/home/martin/tmp/psf-detect-big" (normalize-vol psf-big))
839 (sb-ext:gc :full t)
840 (defparameter *camera-volume* (convolve3-circ *slice-x-psf-times-spheres*
841 (fftshift3 psf-big)))
842 (save-stack-ub8 "/home/martin/tmp/camera-volume"
843 (normalize-vol *camera-volume*))
844 (sb-ext:gc :full t)))
848 #+nil ;; check convolution
849 (time
850 (let ((a (make-array (list 64 64 64)
851 :element-type '(complex double-float)))
852 (b (psf:intensity-psf 64 64 64 20d0 20d0) #+nil (make-array (list 64 64 64)
853 :element-type '(complex double-float))))
854 (setf (aref a 12 12 12) (complex 255d0))
855 #+nil (setf (aref b 0 0 0) (complex 255d0))
856 (save-stack-ub8 "/home/martin/tmp/conv-test" (normalize-vol (convolve3-circ a (fftshift3 b))))))
859 #+nil ;; output the xz cross section centered on a sphere in the middle
860 (let ((coord (aref *centers* 30)))
861 (write-pgm (normalize-img (cross-section-xz *spheres* (* 5 (vec-i-z coord))))
862 "/home/martin/tmp/cut-spheres.pgm")
863 (write-pgm (normalize-img (cross-section-xz *psf-big*))
864 "/home/martin/tmp/cut-psf-big.pgm")
865 (write-pgm (normalize-img (cross-section-xz *slice-x-psf* (* 5 (vec-i-z coord))))
866 "/home/martin/tmp/cut-slice-x-psf.pgm")
867 (write-pgm (normalize-img (cross-section-xz (.* *spheres* *slice-x-psf*) (* 5 (vec-i-z coord))))
868 "/home/martin/tmp/cut-exfluo.pgm"))
870 #+nil
871 (save-stack-ub8 "/home/martin/tmp/spheres" (normalize-vol *spheres*))
873 #+nil
874 (let ((sli (make-array (array-dimensions *spheres*)
875 :element-type '(complex double-float))))
876 (destructuring-bind (z y x)
877 (array-dimensions *spheres*)
878 (do-box (k j i 0 z 0 y 0 x)
879 (setf (aref sli k j i)
880 (aref *spheres* k j i)))
881 (let ((k (* 5 (vec-i-z (aref *centers* 30)))))
882 (do-rectangle (j i 0 y 0 x)
883 (setf (aref sli k j i)
884 (* 10 (aref sli k j i)))))
885 (defparameter *sli* sli))
886 (save-stack-ub8 "/home/martin/tmp/spheres" (normalize-vol *sli*)))
890 #+nil
891 (let ((a (sb-ext:array-storage-vector *slice*)))
892 (reduce #'max (map 'vector #'abs a)))
894 #+nil
895 (sb-ext:gc :full t)
897 #+nil ;; model with unscaled spheres
898 (defparameter *blobs*
899 (destructuring-bind (z y x)
900 *dims*
901 (draw-spheres 7d0 *centers* (* 5 z) y x)))
904 #+nil ;; print ft of angular psf
905 (time (let* ((radius .5d0)
906 (x (- 1d0 radius))
907 (psf (angular-psf x 0d0 radius)))
908 (write-pgm (normalize-img (cross-section-xz (fftshift3 (ft3 psf))))
909 "/home/martin/tmp/cut-intens.pgm")))
910 #+nil
911 (let* ((intens (psf:intensity-psf 64 64 64 10d0 5d0))
912 (k0 intens #+nil(fftshift3 (ft3 intens))))
913 (save-stack "/home/martin/tmp/intens1" k0
914 :function #'(lambda (x) (* 1d-5 (abs x))))
915 (write-pgm (convert-img
916 (cross-section-xz k0)
917 #'(lambda (z) (* 1d-4 (abs z))))
918 "/home/martin/tmp/intens1xz.pgm"))
920 #+nil
921 (time
922 (destructuring-bind (z y x)
923 (array-dimensions *blobs*)
924 (save-stack "/home/martin/tmp/blobs"
925 *blobs*
929 #+nil ;; clean up the garbage
930 (sb-ext:gc :full t)
933 #+nil
934 (sb-vm:memory-usage :print-spaces t :count-spaces t)
935 #+nil
936 (sb-vm:memory-usage)
938 #+nil
939 (sb-vm:instance-usage :dynamic)
941 #+nil
942 (sb-vm:list-allocated-objects :dynamic)
944 #+nil
945 (sb-vm:print-allocated-objects :dynamic)
947 #+nil
948 (format t "~a~%" (sb-vm::type-breakdown :dynamic))
951 (declaim (ftype (function (double-float)
952 (values double-float &optional))
953 sq))
954 (defun sq (x)
955 (* x x))
958 (declaim (ftype (function ((array double-float *))
959 (values double-float &optional))
960 rosenbrock))
961 (defun rosenbrock (p)
962 (let* ((x (aref p 0))
963 (y (aref p 1))
964 (result (+ (sq (- 1 x))
965 (* 100 (sq (- y (sq x)))))))
966 (format t "~a~%" (list 'rosenbrock p result))
967 result))
968 #+nil
969 (rosenbrock (make-array 2 :element-type 'double-float
970 :initial-contents (list 1.5d0 1.5d0)))
971 ;; run the following code to test the downhill simplex optimizer on a
972 ;; 2d function:
974 ;; +----- | |
975 ;; | \-- | |
976 ;; | \- | |
977 ;; | \- | |
978 ;; | \| |
979 ;; | || |
980 ;; | | |
981 ;; |-------------+-------+------- <- z
982 ;; -nf /0 f
983 ;; object lens bfp
985 #+nil
986 (time (let ((start (make-array 2 :element-type 'double-float
987 :initial-contents (list 1.5d0 1.5d0))))
988 (simplex-anneal:anneal (simplex-anneal:make-simplex start 1d0)
989 #'rosenbrock
990 :ftol 1d-5)))
992 (defun draw-ray-into-vol (x-mm y-mm bfp-ratio-x bfp-ratio-y vol
993 &key (dx-mm .2d-3)
994 (shift-z 0d0))
995 (destructuring-bind (z y x)
996 (array-dimensions vol)
997 (let* ((f (lens:focal-length-from-magnification 63d0))
998 (na 1.38d0)
999 (ri 1.515d0)
1000 (bfp-radius (lens:back-focal-plane-radius f na))
1001 (obj (lens:make-thin-objective :normal (v 0d0 0d0 -1d0)
1002 :center (v)
1003 :focal-length f
1004 :radius bfp-radius
1005 :numerical-aperture na
1006 :immersion-index ri))
1007 (theta (lens:find-inverse-ray-angle x-mm y-mm obj))
1008 (phi (atan y-mm x-mm))
1009 (start (lens:v (* bfp-ratio-x bfp-radius)
1010 (* bfp-ratio-y bfp-radius)
1012 (dx dx-mm)
1013 (cz (* .5d0 z)) ;; position that is in the center of front focal plane
1014 (cy (* .5d0 y))
1015 (cx (* .5d0 x))
1016 (nf (* ri f)))
1017 (macrolet ((plane (direction position)
1018 ;; for defining a plane that is perpendicular to an
1019 ;; axis and crosses it at POSITION
1020 (declare (type (member :x :y :z) direction))
1021 (let* ((normal (ecase direction
1022 (:x (lens:v 1d0))
1023 (:y (lens:v 0d0 1d0))
1024 (:z (lens:v 0d0 0d0 1d0)))))
1025 `(let* ((pos ,position)
1026 (center (lens::v* ,normal pos))
1027 (outer-normal (lens::normalize center)))
1028 (declare (type double-float pos))
1029 (lens::make-disk :normal outer-normal :center center)))))
1030 ;; define the borders of the viewing volume, distances in mm
1031 (let ((p+z (plane :z (- (* dx (- z cz))
1032 nf)))
1033 (p-z (plane :z (- (* dx (- (- z cz)))
1034 nf)))
1035 (p+y (plane :y (* dx (- y cy))))
1036 (p-y (plane :y (* dx (- (- y cy)))))
1037 (p+x (plane :x (* dx (- x cx))))
1038 (p-x (plane :x (* dx (- (- x cx))))))
1039 (multiple-value-bind (ro s)
1040 (lens:thin-objective-ray obj
1041 start
1042 (lens::v* (lens:v (* (cos phi) (sin theta))
1043 (* (sin phi) (sin theta))
1044 (cos theta))
1045 -1d0))
1046 (setf s (lens::v+ s (lens:v 0d0 0d0 (* dx shift-z))))
1047 (let* ((nro (lens::normalize ro)))
1048 (macrolet ((hit (plane)
1049 ;; (declare (type lens::disk plane))
1050 ;; find intersection between plane and the ray
1051 `(multiple-value-bind (dir hit-point)
1052 (lens::plane-ray ,plane
1053 ;; shift start of vector a bit
1055 nro)
1056 (declare (ignore dir))
1057 hit-point))
1058 (pixel (hit-expr)
1059 ;; convert coordinates from mm into integer pixel positions
1060 `(let ((h ,hit-expr))
1061 (declare (type (or null lens::vec) h))
1062 (when h
1063 (make-vec-i
1064 :z (floor (+ cz (/ (+ (aref h 2) nf) dx)))
1065 :y (floor (+ cy (/ (aref h 1) dx)))
1066 :x (floor (+ cx (/ (aref h 0) dx))))))))
1067 (let* ((h+z (pixel (hit p+z)))
1068 (h-z (pixel (hit p-z)))
1069 (h+y (pixel (hit p+y)))
1070 (h-y (pixel (hit p-y)))
1071 (h+x (pixel (hit p+x)))
1072 (h-x (pixel (hit p-x)))
1073 ;; make a list of all the points
1074 (hlist (list h+z h-z h+y h-y h+x h-x))
1075 ;; throw away points that are nil or that contain
1076 ;; coordinates outside of the array dimensions
1077 (filtered-hlist (remove-if-not #'(lambda (v)
1078 (if v
1079 (and (< -1 (vec-i-x v) x)
1080 (< -1 (vec-i-y v) y)
1081 (< -1 (vec-i-z v) z))
1082 nil)) hlist))
1083 ;; sort best points by x
1084 (choice (sort filtered-hlist #'< :key (lambda (v) (vec-i-x v)))))
1085 (format t "~a~%" (list 'choice choice))
1086 (scan-convert-line3
1087 (first choice)
1088 (second choice)
1089 vol))))))))))
1091 #+nil
1092 (let ((vol (make-array (list 128 128 128) :element-type '(unsigned-byte 8))))
1093 (loop for i in '(4.0d-3 -.2d-3) do
1094 (draw-ray-into-vol i 0d0 .99d0 .0d0 vol)
1095 (draw-ray-into-vol i 0d0 -.99d0 .0d0 vol)
1096 (draw-ray-into-vol i 0d0 0d0 .99d0 vol)
1097 (draw-ray-into-vol i 0d0 0d0 -.99d0 vol))
1099 (save-stack-ub8 "/home/martin/tmp/line"
1100 vol))
1103 #+nil
1104 (let ((vol (make-array (list 128 128 128) :element-type '(unsigned-byte 8))))
1105 (draw-line3 (make-vec-i :x 108 :y 112 :z 103)
1106 (make-vec-i :x 82 :y 102 :z 10)
1107 vol))
1109 (declaim (ftype (function (fixnum fixnum fixnum
1110 fixnum fixnum fixnum
1111 (simple-array (unsigned-byte 8) 3))
1112 (values (simple-array (unsigned-byte 8) 3) &optional))
1113 scan-convert-line3x scan-convert-line3y scan-convert-line3z))
1114 ;; 1986 kaufman
1115 (defun scan-convert-line3x (x1 y1 z1 x2 y2 z2 vol)
1116 ;; x2 - x1 has to be the biggest difference between endpoint
1117 ;; coordinates
1118 (let* ((x x1)
1119 (delx (- x2 x1))
1120 ;; initialization for y
1121 (y y1)
1122 (ddy (- y2 y1))
1123 (dely (abs ddy))
1124 (ysign (signum ddy))
1125 (dy (- (* 2 dely) delx)) ;; decision variable along y
1126 (yinc1 (* 2 dely)) ;; increment along y for dy<0
1127 (yinc2 (* 2 (- dely delx))) ;; inc along y for dy>=0
1128 ;; same initialization for z
1129 (z z1)
1130 (ddz (- z2 z1))
1131 (delz (abs ddz))
1132 (zsign (signum ddz))
1133 (dz (- (* 2 delz) delx))
1134 (zinc1 (* 2 delz))
1135 (zinc2 (* 2 (- delz delx))))
1136 (when (<= delx 0)
1137 (error "x2 is <= x1."))
1138 (setf (aref vol z y x) 255)
1139 (loop while (< x x2) do
1140 (incf x) ;; step in x
1141 (if (< dy 0) ;; then no change in y
1142 (incf dy yinc1) ;; update dy
1143 (progn
1144 (incf dy yinc2) ;; update dy, and
1145 (incf y ysign)));; increment/decrement y
1147 (if (< dz 0)
1148 (incf dz zinc1)
1149 (progn
1150 (incf dz zinc2)
1151 (incf z zsign)))
1152 (setf (aref vol z y x) 255)))
1153 vol)
1154 ;; start from scan-convert-line3x and replace x->$, y->x, $->y
1155 (defun scan-convert-line3y (x1 y1 z1 x2 y2 z2 vol)
1156 (let* ((y y1)
1157 (dely (- y2 y1))
1158 (x x1)
1159 (ddx (- x2 x1))
1160 (delx (abs ddx))
1161 (xsign (signum ddx))
1162 (dx (- (* 2 delx) dely))
1163 (xinc1 (* 2 delx))
1164 (xinc2 (* 2 (- delx dely)))
1165 (z z1)
1166 (ddz (- z2 z1))
1167 (delz (abs ddz))
1168 (zsign (signum ddz))
1169 (dz (- (* 2 delz) dely))
1170 (zinc1 (* 2 delz))
1171 (zinc2 (* 2 (- delz dely))))
1172 (when (<= dely 0)
1173 (error "y2 is <= y1."))
1174 (setf (aref vol z y x) 255)
1175 (loop while (< y y2) do
1176 (incf y)
1177 (if (< dx 0)
1178 (incf dx xinc1)
1179 (progn
1180 (incf dx xinc2)
1181 (incf x xsign)))
1182 (if (< dz 0)
1183 (incf dz zinc1)
1184 (progn
1185 (incf dz zinc2)
1186 (incf z zsign)))
1187 (setf (aref vol z y x) 255)))
1188 vol)
1189 ;; replace x->$, z->x, $->z
1190 (defun scan-convert-line3z (x1 y1 z1 x2 y2 z2 vol)
1191 (let* ((z z1)
1192 (delz (- z2 z1))
1193 (y y1)
1194 (ddy (- y2 y1))
1195 (dely (abs ddy))
1196 (ysign (signum ddy))
1197 (dy (- (* 2 dely) delz))
1198 (yinc1 (* 2 dely))
1199 (yinc2 (* 2 (- dely delz)))
1200 (x x1)
1201 (ddx (- x2 x1))
1202 (delx (abs ddx))
1203 (xsign (signum ddx))
1204 (dx (- (* 2 delx) delz))
1205 (xinc1 (* 2 delx))
1206 (xinc2 (* 2 (- delx delz))))
1207 (when (<= delz 0)
1208 (error "z2 is <= z1."))
1209 (setf (aref vol z y x) 255)
1210 (loop while (< z z2) do
1211 (incf z)
1212 (if (< dy 0)
1213 (incf dy yinc1)
1214 (progn
1215 (incf dy yinc2)
1216 (incf y ysign)))
1218 (if (< dx 0)
1219 (incf dx xinc1)
1220 (progn
1221 (incf dx xinc2)
1222 (incf x xsign)))
1223 (setf (aref vol z y x) 255)))
1224 vol)
1226 (declaim (ftype (function (vec-i vec-i (simple-array (unsigned-byte 8) 3))
1227 (values (simple-array (unsigned-byte 8) 3) &optional))
1228 scan-convert-line3))
1229 (defun scan-convert-line3 (start end vol)
1230 (let* ((diff (v--i end start))
1231 (ls (list (list (vec-i-x diff) 2)
1232 (list (vec-i-y diff) 1)
1233 (list (vec-i-z diff) 0)))
1234 (diffa (mapcar #'(lambda (e) (list (abs (first e))
1235 (second e))) ls))
1236 ;; find the direction with the biggest difference
1237 (sorted-diff-a (sort diffa #'> :key #'car))
1238 (main-direction (second (first sorted-diff-a))) ;; 2 corresponds to x, 1->y, 0->z
1239 ;; find the order in which to deliver the points
1240 (main-diff (aref diff main-direction))
1241 ;; we have to swap the points when main-diff is negative
1242 (swap-points? (< main-diff 0))
1243 ;; create the function name to dispatch to
1244 (function (intern (format nil "SCAN-CONVERT-LINE3~a" (ecase main-direction
1245 (2 'X)
1246 (1 'Y)
1247 (0 'Z))))))
1248 (when (eq 0 main-diff)
1249 (error "start and end point are the same."))
1250 (if swap-points?
1251 (funcall function
1252 (vec-i-x end)
1253 (vec-i-y end)
1254 (vec-i-z end)
1255 (vec-i-x start)
1256 (vec-i-y start)
1257 (vec-i-z start)
1258 vol)
1259 (funcall function
1260 (vec-i-x start)
1261 (vec-i-y start)
1262 (vec-i-z start)
1263 (vec-i-x end)
1264 (vec-i-y end)
1265 (vec-i-z end)
1266 vol))))
1269 #+nil
1270 (time
1271 (let ((vol (make-array (list 128 128 128) :element-type '(unsigned-byte 8))))
1272 (save-stack-ub8 "/home/martin/tmp/line"
1273 (scan-convert-line3 (make-vec-i :x 0 :y 0 :z 0)
1274 (make-vec-i :x 120 :y 127 :z 127)
1275 vol))))