3 (declaim (optimize (speed 2) (safety 3) (debug 3)))
5 (define-condition one-solution
() ())
6 (define-condition no-solution
() ())
8 (defun quadratic-roots (a b c
)
9 (declare (double-float a b c
)
10 (values double-float double-float
&optional
))
11 "Find the two roots of ax^2+bx+c=0 and return them as multiple
13 ;; see numerical recipes sec 5.6, p. 251 on how to avoid roundoff
15 (let ((det2 (- (* b b
) (* 4 a c
))))
19 (q (* .5d0
(+ b
(* (signum b
) (sqrt pdet2
)))))
22 (declare ((double-float 0d0
) pdet2
))
23 (cond ((and (< aq
1d-12
) (< aa
1d-12
)) (error 'no-solution
))
24 ((or (< aq
1d-12
) (< aa
1d-12
)) (error 'one-solution
))
25 (t (values (/ q a
) (/ c q
)))))))
28 (quadratic-roots 1d0
2d0 -
3d0
)
30 (quadratic-roots 0d0
1d0
0d0
)
32 (quadratic-roots 0d0 -
0d0
1d0
)
35 ((center :accessor center
:initarg
:center
:initform
(v) :type vec
)
36 (radius :accessor radius
:initarg
:radius
:initform
1d0
:type double-float
)))
39 (defmethod print-object ((sphere sphere
) stream
)
40 (with-slots (center radius
) sphere
41 (format stream
"#<sphere radius: ~4f center: <~4f ~4f ~4f>>"
42 radius
(vec-x center
) (vec-y center
) (vec-z center
))))
44 (defmethod ray-sphere-intersection-length ((ray ray
) center radius
)
47 (values double-float
&optional
))
48 ;; (c-x)^2=r^2 defines the sphere, substitute x with the rays p+alpha a,
49 ;; the raydirection should have length 1, solve the quadratic equation,
50 ;; the distance between the two solutions is the distance that the ray
51 ;; travelled through the sphere
52 (check-direction-norm ray
)
53 (with-slots ((start vector
::start
) (direction vector
::direction
)) ray
54 (let* ((l (v- center start
))
55 (c (- (v. l l
) (* radius radius
)))
56 (b (* -
2d0
(v. l direction
))))
58 (multiple-value-bind (x1 x2
)
59 (quadratic-roots 1d0 b c
)
62 (no-solution () 0d0
)))))
65 (ray-sphere-intersection-length (v 0d0
.1d0 -
12d0
) (v 0d0
0d0
1d0
) (v) 3d0
)
67 (defmethod ray-spheres-intersection ((ray ray
) (model sphere-algebraic-model
)
68 illuminated-sphere-index
)
69 (declare (fixnum illuminated-sphere-index
)
70 (values double-float
&optional
))
71 (with-slots (centers-mm radii-mm
) model
73 (loop for c in centers-mm and r in radii-mm and i from
0 do
74 (unless (eq i illuminated-sphere-index
)
75 (incf sum
(ray-sphere-intersection-length ray c r
))))