bringing run to life again
[woropt.git] / bresenham.lisp
blob0db9cf1eec019a7a10176170bc5c53a5b499c021
1 #.(require :vector)
2 (defpackage :bresenham
3 (:use :cl :vector)
4 (:export #:scan-convert-line3))
6 (in-package :bresenham)
8 ;; 1986 kaufman
9 (defun scan-convert-line3x (x1 y1 z1 x2 y2 z2 vol)
10 (declare (fixnum x1 y1 z1 x2 y2 z2)
11 ((simple-array (unsigned-byte 8) 3) vol)
12 (values (simple-array (unsigned-byte 8) 3) &optional))
13 ;; x2 - x1 has to be the biggest difference between endpoint
14 ;; coordinates
15 (let* ((x x1)
16 (delx (- x2 x1))
17 ;; initialization for y
18 (y y1)
19 (ddy (- y2 y1))
20 (dely (abs ddy))
21 (ysign (signum ddy))
22 (dy (- (* 2 dely) delx)) ;; decision variable along y
23 (yinc1 (* 2 dely)) ;; increment along y for dy<0
24 (yinc2 (* 2 (- dely delx))) ;; inc along y for dy>=0
25 ;; same initialization for z
26 (z z1)
27 (ddz (- z2 z1))
28 (delz (abs ddz))
29 (zsign (signum ddz))
30 (dz (- (* 2 delz) delx))
31 (zinc1 (* 2 delz))
32 (zinc2 (* 2 (- delz delx))))
33 (when (<= delx 0)
34 (error "x2 is <= x1."))
35 (setf (aref vol z y x) 255)
36 (loop while (< x x2) do
37 (incf x) ;; step in x
38 (if (< dy 0) ;; then no change in y
39 (incf dy yinc1) ;; update dy
40 (progn
41 (incf dy yinc2) ;; update dy, and
42 (incf y ysign)));; increment/decrement y
44 (if (< dz 0)
45 (incf dz zinc1)
46 (progn
47 (incf dz zinc2)
48 (incf z zsign)))
49 (setf (aref vol z y x) 255)))
50 vol)
51 ;; start from scan-convert-line3x and replace x->$, y->x, $->y
52 (defun scan-convert-line3y (x1 y1 z1 x2 y2 z2 vol)
53 (declare (fixnum x1 y1 z1 x2 y2 z2)
54 ((simple-array (unsigned-byte 8) 3) vol)
55 (values (simple-array (unsigned-byte 8) 3) &optional))
56 (let* ((y y1)
57 (dely (- y2 y1))
58 (x x1)
59 (ddx (- x2 x1))
60 (delx (abs ddx))
61 (xsign (signum ddx))
62 (dx (- (* 2 delx) dely))
63 (xinc1 (* 2 delx))
64 (xinc2 (* 2 (- delx dely)))
65 (z z1)
66 (ddz (- z2 z1))
67 (delz (abs ddz))
68 (zsign (signum ddz))
69 (dz (- (* 2 delz) dely))
70 (zinc1 (* 2 delz))
71 (zinc2 (* 2 (- delz dely))))
72 (when (<= dely 0)
73 (error "y2 is <= y1."))
74 (setf (aref vol z y x) 255)
75 (loop while (< y y2) do
76 (incf y)
77 (if (< dx 0)
78 (incf dx xinc1)
79 (progn
80 (incf dx xinc2)
81 (incf x xsign)))
82 (if (< dz 0)
83 (incf dz zinc1)
84 (progn
85 (incf dz zinc2)
86 (incf z zsign)))
87 (setf (aref vol z y x) 255)))
88 vol)
89 ;; replace x->$, z->x, $->z
90 (defun scan-convert-line3z (x1 y1 z1 x2 y2 z2 vol)
91 (declare (fixnum x1 y1 z1 x2 y2 z2)
92 ((simple-array (unsigned-byte 8) 3) vol)
93 (values (simple-array (unsigned-byte 8) 3) &optional))
94 (let* ((z z1)
95 (delz (- z2 z1))
96 (y y1)
97 (ddy (- y2 y1))
98 (dely (abs ddy))
99 (ysign (signum ddy))
100 (dy (- (* 2 dely) delz))
101 (yinc1 (* 2 dely))
102 (yinc2 (* 2 (- dely delz)))
103 (x x1)
104 (ddx (- x2 x1))
105 (delx (abs ddx))
106 (xsign (signum ddx))
107 (dx (- (* 2 delx) delz))
108 (xinc1 (* 2 delx))
109 (xinc2 (* 2 (- delx delz))))
110 (when (<= delz 0)
111 (error "z2 is <= z1."))
112 (setf (aref vol z y x) 255)
113 (loop while (< z z2) do
114 (incf z)
115 (if (< dy 0)
116 (incf dy yinc1)
117 (progn
118 (incf dy yinc2)
119 (incf y ysign)))
121 (if (< dx 0)
122 (incf dx xinc1)
123 (progn
124 (incf dx xinc2)
125 (incf x xsign)))
126 (setf (aref vol z y x) 255)))
127 vol)
129 (defun scan-convert-line3 (start end vol)
130 (declare (vec-i start end)
131 ((simple-array (unsigned-byte 8) 3) vol)
132 (values (simple-array (unsigned-byte 8) 3) &optional))
133 (let* ((diff (v--i end start))
134 (ls (list (list (vec-i-x diff) 2)
135 (list (vec-i-y diff) 1)
136 (list (vec-i-z diff) 0)))
137 (diffa (mapcar #'(lambda (e) (list (abs (first e))
138 (second e))) ls))
139 ;; find the direction with the biggest difference
140 (sorted-diff-a (sort diffa #'> :key #'car))
141 (main-direction (second (first sorted-diff-a))) ;; 2 corresponds to x, 1->y, 0->z
142 ;; find the order in which to deliver the points
143 (main-diff (aref diff main-direction))
144 ;; we have to swap the points when main-diff is negative
145 (swap-points? (< main-diff 0))
146 ;; create the function name to dispatch to
147 (function (ecase main-direction
148 (2 #'scan-convert-line3x)
149 (1 #'scan-convert-line3y)
150 (0 #'scan-convert-line3z))))
151 (when (eq 0 main-diff)
152 (error "start and end point are the same."))
153 (if swap-points?
154 (funcall function
155 (vec-i-x end)
156 (vec-i-y end)
157 (vec-i-z end)
158 (vec-i-x start)
159 (vec-i-y start)
160 (vec-i-z start)
161 vol)
162 (funcall function
163 (vec-i-x start)
164 (vec-i-y start)
165 (vec-i-z start)
166 (vec-i-x end)
167 (vec-i-y end)
168 (vec-i-z end)
169 vol))))
172 #+nil
173 (time
174 (let ((vol (make-array (list 128 128 128) :element-type '(unsigned-byte 8))))
175 (save-stack-ub8 "/home/martin/tmp/line"
176 (scan-convert-line3 (make-vec-i :x 0 :y 0 :z 0)
177 (make-vec-i :x 120 :y 127 :z 127)
178 vol))))