(define (make-point x y z)
  (lambda (selector)
    (case selector
      ((get-x)
       (lambda () x))
      ((get-y)
       (lambda () y))
      ((get-z)
       (lambda () z))
      ((set-x)
       (lambda (a) (set! x a)))
      ((set-y)
       (lambda (a) (set! y a)))
      ((set-z)
       (lambda (a) (set! z a)))
      ((set)
       (lambda (a b c)
         (set! x a)
         (set! y b)
         (set! z c)))
      ((distance)
       (lambda (p2)
         (let*
           ((x2 ((p2 'get-x)))
            (y2 ((p2 'get-y)))
            (z2 ((p2 'get-z)))
            (x2-x1 (- x2 x))
            (y2-y1 (- y2 y))
            (z2-z1 (- z2 z)))
           (sqrt (+ (* x2-x1 x2-x1)
                    (* y2-y1 y2-y1)
                    (* z2-z1 z2-z1))))))
      ((direction-vector)
       (lambda (p2)
         (let*
           ((delta-x (- ((p2 'get-x)) x))
            (delta-y (- ((p2 'get-y)) y))
            (delta-z (- ((p2 'get-z)) z))
            (max-delta (max (abs delta-x) (abs delta-y) (abs delta-z))))
           (make-point (/ delta-x max-delta)
                     (/ delta-y max-delta)
                     (/ delta-z max-delta)))))
      ((zero-adjust)
       (lambda ()
         (let
           ((x x)
            (y y)
            (z z))
           (if (= x 0.0)
             (set! x (+ x EPSILON)))
           (if (= y 0.0)
             (set! y (+ y EPSILON)))
           (if (= z 0.0)
             (set! z (+ z EPSILON)))
           (make-point x y z))))
      ((display)
       (lambda ()
         (display #\()
         (display x) (display ", ")
         (display y) (display ", ")
         (display z) (display #\))))
      (else
       (render-error "make-point" "Invalid selector: " selector)))))
