(define (make-ray origin direction)
  (let*
    ((dir-x ((direction 'get-x)))
     (dir-y ((direction 'get-y)))
     (dir-z ((direction 'get-z)))
     (inverse-direction
       (make-point
         (/ 1.0 dir-x)
         (/ 1.0 dir-y)
         (/ 1.0 dir-z)))
     (ibyj (* dir-x ((inverse-direction 'get-y))))
     (jbyi (* dir-y ((inverse-direction 'get-x))))
     (jbyk (* dir-y ((inverse-direction 'get-z))))
     (kbyj (* dir-z ((inverse-direction 'get-y))))
     (ibyk (* dir-x ((inverse-direction 'get-z))))
     (kbyi (* dir-z ((inverse-direction 'get-x))))
     (xy (- ((origin 'get-y)) (* jbyi ((origin 'get-x)))))
     (xz (- ((origin 'get-z)) (* kbyi ((origin 'get-x)))))
     (yx (- ((origin 'get-x)) (* ibyj ((origin 'get-y)))))
     (yz (- ((origin 'get-z)) (* kbyj ((origin 'get-y)))))
     (zx (- ((origin 'get-x)) (* ibyk ((origin 'get-z)))))
     (zy (- ((origin 'get-y)) (* jbyk ((origin 'get-z)))))
     (classification
       (if (< dir-x 0.0)
         (if (< dir-y 0.0)
           (if (< dir-z 0.0)
             0 ; MMM
             (if (> dir-z 0.0)
               1 ; MMP
               2)) ; MMO dir-z >= 0.0
           (if (< dir-z 0.0) ; dir-y >= 0.0
             (if (= dir-y 0.0)
               6 ; MOM
               3) ; MPM
             (if (and (= dir-y 0.0) (= dir-z 0.0)) ; dir-z >= 0.0
               8 ; MOO
               (if (= dir-z 0.0)
                 5 ; MPO
                 (if (= dir-y 0.0)
                   7 ; MOP
                   4))))) ; MPP
         (if (< dir-y 0.0) ; dir-x >= 0.0
           (if (< dir-z 0.0)
             (if (= dir-x 0.0)
               18 ; OMM
               9) ; PMM
             (if (and (= dir-x 0.0) (= dir-z 0.0)) ; dir-z >= 0.0
               20 ; OMO
               (if (= dir-z 0.0)
                 11 ; PMO
                 (if (= dir-x 0.0)
                   19 ; OMP
                   10)))) ; PMP
           (if (< dir-z 0.0) ; dir-y >= 0.0
             (if (and (= dir-x 0.0) (= dir-y 0.0))
               24 ; OOM
               (if (= dir-x 0.0)
                 21 ; OPM
                 (if (= dir-y 0.0)
                   15 ; POM
                   12))) ; PPM
             (if (= dir-x 0.0) ; dir-z > 0.0
               (if (= dir-y 0.0)
                 25 ; OOP
                 (if (= dir-z 0.0)
                   23 ; OPO
                   22)) ; OPP
               (if (and (= dir-y 0.0) (= dir-z 0.0))
                 17 ; POO
                 (if (= dir-y 0.0)
                   16 ; POP
                   (if (= dir-z 0.0)
                     14 ; PPO
                     13)))))))) ; PPP
    )

    (lambda (selector)
      (case selector
        ((get-origin)
         (lambda () origin))
        ((get-dir-x)
         (lambda () dir-x))
        ((get-dir-y)
         (lambda () dir-y))
        ((get-dir-z)
         (lambda () dir-z))
        ((get-classification)
         (lambda () classification))
        ((get-direction)
         (lambda () direction))
        ((get-inverse-direction)
         (lambda () inverse-direction))
        ((get-ibyj)
         (lambda () ibyj))
        ((get-jbyi)
         (lambda () jbyi))
        ((get-jbyk)
         (lambda () jbyk))
        ((get-kbyj)
         (lambda () kbyj))
        ((get-ibyk)
         (lambda () ibyk))
        ((get-kbyi)
         (lambda () kbyi))
        ((get-xy)
         (lambda () xy))
        ((get-xz)
         (lambda () xz))
        ((get-yx)
         (lambda () yx))
        ((get-yz)
         (lambda () yz))
        ((get-zx)
         (lambda () zx))
        ((get-zy)
         (lambda () zy))
        (else
         (render-error "make-ray" "Invalid selector: " selector))))))
