home *** CD-ROM | disk | FTP | other *** search
/ vis-ftp.cs.umass.edu / vis-ftp.cs.umass.edu.tar / vis-ftp.cs.umass.edu / pub / Software / ASCENDER / ascendMar8.tar / UMass / Epipolar / vectors.lisp < prev   
Lisp/Scheme  |  1995-07-20  |  19KB  |  472 lines

  1. ;;; File VECTORS.LISP  - simple vector and matrix manipulation
  2. ;;; Bob Collins, University of Massachusetts
  3. ;;; general contents:
  4. ;;;   cross product,  dot product,  computing vector length,
  5. ;;;   scaling, adding, and subtracting vectors
  6. ;;;   normalizing vectors, plane and line normals
  7. ;;;   matrix multiplication
  8. ;;;   determinant and minors of 3x3 matrices
  9. ;;;
  10. ;;; converted from the lisp machine version -- Bob Collins, 8/11/94
  11. ;;;   added sequence-type function to replace type-of for the result type
  12. ;;;     of mapping over vectors (this was needed for clisp, lucid was OK).
  13. ;;;   wrote la::transpose to replace the nonexistant math::matrix-transpose
  14. ;;;   wrote la::listarray to replace the nonexistant listarray
  15.  
  16. (in-package 'linear-algebra :nicknames '("LA"))
  17.  
  18. (export '(cross-product dot-product vector-length 
  19.           normalize normalize2 normalize3 normalize-line normalize-plane
  20.       scale-vector vector-subtract vector-add
  21.       v+ v- vs vdot vcross vnorm vmag vmag2
  22.       matmult matplus matminus scale-matrix transpose
  23.       m* m+ m- ms mt
  24.       compute-minors3 compute-minor3 cofactors3
  25.       cofactors-mat3 adjoint3 inverse3
  26.       matrix-with-columns diag 
  27.       solve-2-by-2 
  28.       unit-normal unit-vector-angle))
  29.  
  30. (defmacro sequence-type (thing)
  31.   `(let ((evalthing ,thing))
  32.      (if (consp evalthing) 'list (type-of evalthing))))
  33.  
  34. (defun listarray (arr)
  35.   (ecase (length (array-dimensions arr))
  36.     (1 (map 'list #'identity arr))
  37.     (2 (let ((res nil))
  38.       (dotimes (i (array-dimension arr 0))
  39.         (dotimes (j (array-dimension arr 1))
  40.            (push (aref arr i j) res)))
  41.       (nreverse res)))))
  42.  
  43. (defun vectorize (thing)
  44.   "  if thing is a sequence, everything is OK.  It can also be an array, in
  45.   which case a listarray is done to it - which gives obvious results in the
  46.   case of a matrix consisting of a single row or column, less obvious in
  47.   other cases. If it is a number, then a list of one number is return."
  48.   (cond
  49.     ((or (vectorp thing) (listp thing)) thing)
  50.     ((arrayp thing) (listarray thing))
  51.     ((numberp thing) (list thing))
  52.     (t (error "argument ~s was not an array, vector, list or number" thing))))
  53.  
  54. (defun cross-product3 (x1 y1 z1 x2 y2 z2)
  55.   "Returns the cross product of two 3-dimensional vectors."
  56.   (list (- (* y1 z2) (* z1 y2))
  57.     (- (* x2 z1) (* x1 z2))
  58.     (- (* x1 y2) (* y1 x2))))
  59.  
  60. (defun cross-product (vector1 vector2)
  61.   "  Returns a new vector which is the cross product of 2 vectors. 
  62.   They should both have either 2 or 3 elements.  The new vector has
  63.   exactly 3 elements."
  64.   (setf vector1 (vectorize vector1) vector2 (vectorize vector2))
  65.   (multiple-value-bind (x1 y1 z1) (values-list vector1)
  66.     (multiple-value-bind (x2 y2 z2) (values-list vector2)
  67.       (cross-product3 x1 y1 (or z1 0) x2 y2 (or z2 0)))))
  68.  
  69. (defun abs-max (sequence)
  70.   "Returns the largest element magnitude."
  71.   (reduce #'(lambda (x y) (max x (abs y))) 
  72.       sequence 
  73.       :initial-value (abs (elt sequence 0)) 
  74.       :start 1))
  75.  
  76. (defun dot-product (vector1 vector2)
  77.   "  Returns the dot product of vector1 and vector2, both of which must be sequences.
  78.   If both vectors are not the same length, the shorter is treated as if it were padded
  79.   with zeros at the end."
  80.   ;;note: the following is more accurate in some cases than the obvious implementation
  81.   (setf vector1 (vectorize vector1) vector2 (vectorize vector2))
  82.   (let ((result 0)
  83.     (max1 (abs-max vector1))
  84.     (max2 (abs-max vector2)))
  85.     (if (or (zerop max1) (zerop max2))
  86.     0
  87.     (progn
  88.       (map nil #'(lambda (n1 n2) (incf result (* (/ n1 max1) (/ n2 max2)))) vector1 vector2)
  89.       (* result max1 max2)))))
  90.  
  91. (defun dot-product3 (x1 y1 z1 x2 y2 z2)
  92.   "Returns the dot product of two 3-dimensional vectors."
  93.   (dot-product (list x1 y1 z1) (list x2 y2 z2)))
  94.  
  95. (defun squared-vector-length (&rest vector)
  96.   "Returns the square of the vector length; basically dotproduct(vector,vector)."
  97.   (unless (numberp (elt vector 0)) (setf vector (vectorize (car vector))))
  98.   (dot-product vector vector))
  99.  
  100. (defun vector-length (&rest vector)
  101.   "Returns vector length of vector = sqrt(dotproduct(vector,vector))"
  102.   (unless (numberp (elt vector 0)) (setf vector (vectorize (car vector))))
  103.   (sqrt (dot-product vector vector)))
  104.  
  105. (defun scale-vector (k &rest vector)
  106.   "Returns a new vector scaled by k."
  107.   (unless (numberp (elt vector 0)) (setf vector (car vector)))
  108.   (setf vector (vectorize vector))
  109.   (map (sequence-type vector)
  110.        #'(lambda (n) (* k n))
  111.        vector))
  112.  
  113. (defun vector-subtract (vector1 vector2)
  114.   "subtracts vector2 from vector1 and returns the result"
  115.   (setf vector1 (vectorize vector1) vector2 (vectorize vector2))
  116.   (map (sequence-type vector1)
  117.        #'-
  118.        vector1
  119.        vector2))
  120.  
  121. (defun vector-add (vector1 vector2)
  122.   "adds two vectors and returns the result"
  123.   (setf vector1 (vectorize vector1) vector2 (vectorize vector2))
  124.   (map (sequence-type vector1)
  125.        #'+
  126.        vector1
  127.        vector2))
  128.  
  129. (defun normalize (&rest vector)
  130.   "Returns a new vector, scaled to have length 1."
  131.   (unless (numberp (elt vector 0)) (setf vector (vectorize (car vector))))
  132.   (let ((max (abs-max vector)))
  133.     (if (zerop max)
  134.     (progn (cerror "return ~s" "vector of length 0 cannot be normalized" vector)
  135.            vector)
  136.     (let* ((newvec (map 'list #'(lambda (x) (/ x max)) vector))
  137.            (len-squared (dot-product newvec newvec)))
  138.       (map (sequence-type vector) 
  139.            #'(lambda (n) (* (signum n) (sqrt (/ (* n n) len-squared))))
  140.            newvec)))))
  141.  
  142.  
  143. (defun v+ (&rest vectors)
  144.   "  Adds a list of vector together, if they have compatible dimensions."
  145.   (when vectors
  146.     (setf vectors (mapcar #'vectorize vectors))
  147.     (apply #'map (sequence-type (car vectors)) #'+ vectors)))
  148.  
  149.  
  150. (defun v- (&rest vectors)
  151.   "  Subtracts a list of vectors from the first, or unary minus if only one."
  152.   (when vectors
  153.     (if (= 1 (length vectors))
  154.     (scale-vector -1 (car vectors))
  155.     (let ((vectors (mapcar #'vectorize vectors)))
  156.       (apply #'map (sequence-type (car vectors)) #'- vectors)))))
  157.  
  158. (defun vs (k vec)
  159.   "  Return a new vector scaled by the given amount."
  160.   (scale-vector k vec))
  161.  
  162. (defun vdot (vec1 vec2)
  163.   "  Returns the dot product of vector1 and vector2, both of which must be sequences.
  164.   If both vectors are not the same length, the shorter is treated as if it were padded
  165.   with zeros at the end."
  166.   (dot-product vec1 vec2))
  167.  
  168. (defun vcross (vec1 vec2)
  169.   "  Returns a new vector which is the cross product of 2 vectors. 
  170.   They should both have either 2 or 3 elements.  The new vector has
  171.   exactly 3 elements."
  172.   (cross-product vec1 vec2))
  173.  
  174. (defun vnorm (vec)
  175.   "Returns a new vector, scaled to have length 1."
  176.   (normalize vec))
  177.  
  178. (defun vmag (vector)
  179.   "Returns vector magnitude = length of vector = sqrt(dotproduct(vector,vector))"
  180.   (vector-length vector))
  181.  
  182. (defun vmag2 (vector)
  183.   "Returns the square of the vector magnitude; basically dotproduct(vector,vector)."
  184.   (squared-vector-length vector))
  185.  
  186. (defun normalize2 (&rest vector)
  187.   "Returns a new vector, scaled so that the sum of the squares of the first two elements is 1."
  188.   (unless (numberp (elt vector 0)) (setf vector (vectorize (car vector))))
  189.   (let ((n1 (elt vector 0))
  190.     (n2 (elt vector 1)))
  191.     (unless (and n1 n2) (error "vector must have at least two elements"))
  192.     (let ((len-squared (+ (* n1 n1) (* n2 n2))))
  193.       (if (zerop len-squared)
  194.       (progn (cerror "return ~s" "vector cannot be normalized by 0" vector)
  195.            vector)
  196.       (map (sequence-type vector) 
  197.            #'(lambda (n) (* (signum n) (sqrt (/ (* n n) len-squared))))
  198.            vector)))))
  199.  
  200. (defun normalize3 (&rest vector)
  201.   "Returns a new vector, scaled so that the sum of the squares of the first three elements is 1."
  202.   (unless (numberp (elt vector 0)) (setf vector (vectorize (car vector))))
  203.   (let ((n1 (elt vector 0))
  204.     (n2 (elt vector 1))
  205.     (n3 (elt vector 2)))
  206.     (unless (and n1 n2 n3) (error "vector must have at least three elements"))
  207.     (let ((len-squared (+ (* n1 n1) (* n2 n2) (* n3 n3))))
  208.       (if (zerop len-squared)
  209.       (progn (cerror "return ~s" "vector cannot be normalized by 0" vector)
  210.          vector)
  211.       (map (sequence-type vector) 
  212.            #'(lambda (n) (* (signum n) (sqrt (/ (* n n) len-squared))))
  213.            vector)))))
  214.  
  215. (defun normalize-line (vec)
  216.   (unless (= (length vec) 3) (error "line must have 3 parameters"))
  217.   (normalize2 vec))
  218.  
  219. (defun normalize-plane (vec)
  220.   (unless (= (length vec) 4) (error "plane must have 4 parameters"))
  221.   (normalize3 vec))
  222.  
  223. (defun matricize (thing)
  224.   "  if thing is a matrix, everything is OK.  If it is a vector or list,
  225.   it is treated as a column vector and the appropriate Nx1 array is returned.
  226.   If it is a number, then a 1X1 matrix is returned."
  227.   (cond
  228.     ((and (arrayp thing) (not (vectorp thing))) thing)
  229.     ((or (vectorp thing) (listp thing))
  230.         (let ((arr (make-array (list (length thing) 1))))
  231.       (dotimes (i (length thing) arr)
  232.         (setf (aref arr i 0) (elt thing i)))))
  233.     ((numberp thing) (make-array '(1 1) :initial-element thing))
  234.     (t (error "argument ~s was not an array, vector, list or number" thing))))
  235.  
  236. (defun column-vector (vec)
  237.   (matricize vec))
  238.  
  239. (defun matmult (a b)
  240.   "  Multiplies two dimensional matrices a and b having size (lxm) and (mxn) 
  241.   respectively. The resulting matrix has size (lxn)."
  242.   (setf a (matricize a) b (matricize b))
  243.   (let ((l (array-dimension a 0))
  244.     (m (array-dimension a 1))
  245.     (m2 (array-dimension b 0))
  246.     (n (array-dimension b 1)))
  247.     (unless (= m m2) (error "matrices have incompatible dimensions"))
  248.     (let ((result (make-array (list l n) :element-type (array-element-type a))))
  249.       (dotimes (i l)
  250.     (dotimes (j n)
  251.       (let ((sum 0))
  252.         (dotimes (k m)
  253.           (incf sum (* (aref a i k) (aref b k j))))
  254.         (setf (aref result i j) sum))))
  255.       result)))
  256.  
  257. (defun matplus (a b)
  258.   "  Adds two matrices together."
  259.   (setf a (matricize a) b (matricize b))
  260.   (let ((l (array-dimension a 0))
  261.     (m (array-dimension a 1)))
  262.     (unless (and (= l (array-dimension b 0)) (= m (array-dimension b 1)))
  263.       (error "matrices have incompatible dimensions"))
  264.     (let ((result (make-array (list l m) :element-type (array-element-type a))))
  265.       (dotimes (i l)
  266.     (dotimes (j m)
  267.       (setf (aref result i j) (+ (aref a i j) (aref b i j)))))
  268.       result)))
  269.  
  270. (defun matminus (a b)
  271.   "  Subtracts second matrix from first."
  272.   (setf a (matricize a) b (matricize b))
  273.   (let ((l (array-dimension a 0))
  274.     (m (array-dimension a 1)))
  275.     (unless (and (= l (array-dimension b 0)) (= m (array-dimension b 1)))
  276.       (error "matrices have incompatible dimensions"))
  277.     (let ((result (make-array (list l m) :element-type (array-element-type a))))
  278.       (dotimes (i l)
  279.     (dotimes (j m)
  280.       (setf (aref result i j) (- (aref a i j) (aref b i j)))))
  281.       result)))
  282.  
  283. (defun scale-matrix (mat scale)
  284.   "  Return a new matrix scaled by the given amount."
  285.   (let ((l (array-dimension mat 0))
  286.     (m (array-dimension mat 1)))
  287.     (let ((result (make-array (list l m) :element-type (array-element-type mat))))
  288.       (dotimes (i l)
  289.     (dotimes (j m)
  290.       (setf (aref result i j) (* (aref mat i j) scale))))
  291.       result)))
  292.  
  293.  
  294. (defun transpose (mat)
  295.   "  Returns the transpose of the given matrix"
  296.   (multiple-value-bind (r c) (values-list (array-dimensions mat))
  297.     (let ((arr (make-array (list c r))))
  298.       (dotimes (i r arr)
  299.         (dotimes (j c)
  300.           (setf (aref arr j i) (aref mat i j)))))))
  301.  
  302.   
  303. (defun m* (&rest matrices)
  304.   "  Multiplies a list of matrices together, if they have compatible dimensions."
  305.   (reduce #'matmult (cdr matrices) :initial-value (car matrices)))
  306.  
  307. (defun m+ (&rest matrices)
  308.   "  Adds a list of matrices together, if they have compatible dimensions."
  309.   (reduce #'matplus (cdr matrices) :initial-value (car matrices)))
  310.  
  311. (defun m- (&rest matrices)
  312.   "  Subtracts a list of matrices from the first, or unary minus if only one given."
  313.   (if (= 1 (length matrices))
  314.       (scale-matrix (car matrices) -1)
  315.       (reduce #'matminus (cdr matrices) :initial-value (car matrices))))
  316.  
  317. (defun ms (k mat)
  318.   "  Return a new matrix scaled by the given amount."
  319.   (scale-matrix mat k))
  320.  
  321. (defun mt (mat)
  322.   "  Returns the transpose of the given matrix."
  323.   (transpose (matricize mat)))
  324.  
  325. (defun determinant3 (a11 a12 a13 a21 a22 a23 a31 a32 a33)
  326.   "Computes the determinant of the 3x3 matrix with elements aij, i=row, j=col."
  327.   (- (+ (* a11 a22 a33) (* a21 a32 a13) (* a31 a12 a23))
  328.      (+ (* a31 a22 a13) (* a21 a12 a33) (* a11 a32 a23))))
  329.  
  330. (defun determinant2 (a11 a12 a21 a22)
  331.   "Computes the determinant of the 2X2 matrix with elements aij, i=row, j=col."
  332.   (- (* a11 a22) (* a21 a12)))
  333.  
  334. (defun compute-minors3 (a11 a12 a13 a21 a22 a23 a31 a32 a33)
  335.   "Finds rank2 minors of 3X3 matrix aij.  Returns as a list of
  336.   9 minors (... mij ...)  where mij is minor without rowi, colj."
  337.   (list
  338.     (determinant2 a22 a23 a32 a33)
  339.     (determinant2 a21 a23 a31 a33)
  340.     (determinant2 a21 a22 a31 a32)
  341.     (determinant2 a12 a13 a32 a33)
  342.     (determinant2 a11 a13 a31 a33)
  343.     (determinant2 a11 a12 a31 a32)
  344.     (determinant2 a12 a13 a22 a23)
  345.     (determinant2 a11 a13 a21 a23)
  346.     (determinant2 a11 a12 a21 a22)))
  347.  
  348. (defun compute-minor3 (matrix row col)
  349.   "  Finds rank2 minor of 3X3 MATRIX (a list of nine elements in row-col order)
  350.   formed by leaving out row ROW and column COL."
  351.   (multiple-value-bind (a11 a12 a13 a21 a22 a23 a31 a32 a33)
  352.       (values-list matrix)
  353.     (ecase row
  354.       (1 (ecase col
  355.        (1 (determinant2 a22 a23 a32 a33))
  356.        (2 (determinant2 a21 a23 a31 a33))
  357.        (3 (determinant2 a21 a22 a31 a32))))
  358.       (2 (ecase col
  359.        (1 (determinant2 a12 a13 a32 a33))
  360.        (2 (determinant2 a11 a13 a31 a33))
  361.        (3 (determinant2 a11 a12 a31 a32))))
  362.       (3 (ecase col
  363.        (1 (determinant2 a12 a13 a22 a23))
  364.        (2 (determinant2 a11 a13 a21 a23))
  365.        (3 (determinant2 a11 a12 a21 a22)))))))
  366.  
  367. (defun cofactors3 (a11 a12 a13 a21 a22 a23 a31 a32 a33)
  368.   "Finds cofactors of 3X3 matrix aij.  Returns as a list of
  369.   9 cofactors (... cij ...)  where cij is cofactor of rowi, colj."
  370.   (list
  371.     (determinant2 a22 a23 a32 a33)
  372.     (- (determinant2 a21 a23 a31 a33))
  373.     (determinant2 a21 a22 a31 a32)
  374.     (- (determinant2 a12 a13 a32 a33))
  375.     (determinant2 a11 a13 a31 a33)
  376.     (- (determinant2 a11 a12 a31 a32))
  377.     (determinant2 a12 a13 a22 a23)
  378.     (- (determinant2 a11 a13 a21 a23))
  379.     (determinant2 a11 a12 a21 a22)))
  380.  
  381. (defun cofactors-mat3 (mat &optional (cofmat (make-array '(3 3) :element-type (array-element-type mat))))
  382.   "Finds cofactors of 3X3 matrix MAT, and returns a new matrix where element i,j is cofactor of rowi, colj."
  383.   (multiple-value-bind (a11 a12 a13 a21 a22 a23 a31 a32 a33) (values-list (listarray mat))
  384.     (setf (aref cofmat 0 0) (determinant2 a22 a23 a32 a33))
  385.     (setf (aref cofmat 0 1) (- (determinant2 a21 a23 a31 a33)))
  386.     (setf (aref cofmat 0 2) (determinant2 a21 a22 a31 a32))
  387.     (setf (aref cofmat 1 0) (- (determinant2 a12 a13 a32 a33)))
  388.     (setf (aref cofmat 1 1) (determinant2 a11 a13 a31 a33))
  389.     (setf (aref cofmat 1 2) (- (determinant2 a11 a12 a31 a32)))
  390.     (setf (aref cofmat 2 0) (determinant2 a12 a13 a22 a23))
  391.     (setf (aref cofmat 2 1) (- (determinant2 a11 a13 a21 a23)))
  392.     (setf (aref cofmat 2 2) (determinant2 a11 a12 a21 a22))
  393.     cofmat))
  394.  
  395. (defun adjoint3 (mat &optional (adj-mat (make-array '(3 3) :element-type (array-element-type mat))))
  396.   "Finds transpose of cofactor matrix of 3X3 matrix MAT, which is the inverse of MAT up to a scale factor"
  397.   (multiple-value-bind (a11 a12 a13 a21 a22 a23 a31 a32 a33) (values-list (listarray mat))
  398.     (setf (aref adj-mat 0 0) (determinant2 a22 a23 a32 a33))
  399.     (setf (aref adj-mat 1 0) (- (determinant2 a21 a23 a31 a33)))
  400.     (setf (aref adj-mat 2 0) (determinant2 a21 a22 a31 a32))
  401.     (setf (aref adj-mat 0 1) (- (determinant2 a12 a13 a32 a33)))
  402.     (setf (aref adj-mat 1 1) (determinant2 a11 a13 a31 a33))
  403.     (setf (aref adj-mat 2 1) (- (determinant2 a11 a12 a31 a32)))
  404.     (setf (aref adj-mat 0 2) (determinant2 a12 a13 a22 a23))
  405.     (setf (aref adj-mat 1 2) (- (determinant2 a11 a13 a21 a23)))
  406.     (setf (aref adj-mat 2 2) (determinant2 a11 a12 a21 a22))
  407.     adj-mat))
  408.  
  409. (defun inverse3 (mat &optional (inv-mat (make-array '(3 3) :element-type (array-element-type mat))))
  410.   "Returns inverse of the given 3x3 matrix (or nil if singular)."
  411.   (let ((adj (adjoint3 mat inv-mat)))
  412.     (let ((scale (+ (* (aref mat 0 0) (aref adj 0 0))
  413.             (* (aref mat 0 1) (aref adj 1 0))
  414.             (* (aref mat 0 2) (aref adj 2 0)))))
  415.       (if (zerop scale)
  416.       nil
  417.       (ms (/ scale) adj)))))
  418.  
  419. (defun matrix-with-columns (&rest column-list)
  420.   "Return a matrix having the given columns."
  421.   (let ((mat (make-array (list (length (car column-list)) (length column-list))))
  422.     (numrows (length (car column-list)))
  423.     (col 0))
  424.     (dolist (vec column-list mat)
  425.       (dotimes (row numrows)
  426.     (setf (aref mat row col) (elt vec row)))
  427.       (incf col))))
  428.  
  429. (defun diag (&rest element-list)
  430.   "Return a diagonal matrix containing the given elements"
  431.   (let ((num (length element-list))
  432.     (i 0))
  433.     (let ((mat (make-array (list num num) :element-type (type-of (car element-list)) 
  434.                :initial-element (coerce 0 (type-of (car element-list))))))
  435.       (dolist (element element-list mat)
  436.     (setf (aref mat i i) element)
  437.     (incf i)))))
  438.  
  439. (defun solve-2-by-2 (a11 a12 a21 a22 b1 b2)
  440.   "  Solves 2X2 system of equations
  441.     | a11 a12 |  | X |   | b1 |
  442.     | a21 a22 |  | Y | = | b2 |
  443.   for X and Y and returns them as the list (X Y)."
  444.   (let ((denom (- (* a11 a22) (* a12 a21))))
  445.     (list (/ (- (* b1 a22) (* b2 a12)) denom)
  446.       (/ (- (* b2 a11) (* b1 a21)) denom))))
  447.  
  448. (defun unit-normal (vector1 vector2)
  449.   "Returns a unit vector perpendicular to the two given vectors"
  450.   (normalize (cross-product vector1 vector2)))
  451.  
  452. (defun unit-vector-angle (x y z refx refy refz normx normy normz)
  453.   "Returns a angle in radians between [0 and 2pi) representing the angle
  454.   between the two unit vectors <x,y,z> and <refx,refy,refz>.  Norm is a
  455.   unit normal vector perpendicular to the plane containing the two other
  456.   vectors.  The angle returned is measured from the reference vector ref
  457.   to the given vector <x,y,z> counterclockwise around the axis norm. 
  458.   Thus an angle r means that to a viewer at the origin whose line of
  459.   sight lies along vector <normx,normy,normz>, the vector <refx,refy,refz>
  460.   would have to be rotated counterclockwise about the origin r radians
  461.   to bring it into correspondence with vector <x,y,z>."
  462.   (let ((dp (dot-product3 refx refy refz x y z))
  463.     (sp (determinant3 normx normy normz refx refy refz x y z)))
  464.     ;;note: dp = dot product of ref and xyz = cos angle between them
  465.     ;;      sp = scalar triple product = norm *dot* (ref *cross* xyz)
  466.     ;;         = sin of the angle between ref and xyz
  467.     (let ((theta (acos (max -1.0 (min 1.0 dp)))))  ;acos returns results in range [0,pi)
  468.       (when (and (plusp sp) (plusp theta)) (setf theta (- (* 2.0 pi) theta)))
  469.       theta)))
  470.  
  471.  
  472.