anchor.diff:                                         (pdf:stroke)))))
                                position-seq))))
   
  +;;; Ellipses
  +
  +;;;
  +;;; PDF doesn't provide shape drawing functions per se, but rather
  +;;; primitives for working with paths such as lines and bezier
  +;;; curves. cl-pdf, which we use here in the PDF backend, defines some
  +;;; geometric drawing functions such as arc, pie, circle, rectangle,
  +;;; etc... and ellipse. Unfortunately the cl-pdf ellipse routine only
  +;;; handles axis-aligned ellipses. The CLIM specification describes
  +;;; arbitrary ellipses that have two (non-colinear) 2-d vectors as
  +;;; radii. So we have to add support for these kind of ellipses. There
  +;;; are multiple approaches to rendering ellipses but it turns out
  +;;; that one can closely approximate arbitrary ellipse path with
  +;;; appropriate bezier curves. A good primer on drawing ellipses with
  +;;; lines, or quadratic or cubic bezier curves can be found here:
  +;;; <https://www.spaceroots.org/documents/ellipse/index.html>.
  +;;;
  +;;; We use the algorithm described in the above reference to construct
  +;;; cubic bezier curves, which are in turn handled by cl-pdf.
  +
  +;;;
  +;;; this probably exists elsewhere in McCLIM and, either way, could be
  +;;; replaced with in-line expansion, or a simple macro. But efficiency
  +;;; isn't a key concern here so we'll leave this here for readability.
   (defun square (x)
  +  "Returns the number X squared."
     (* x x))
   
  -(defun vec-len (x1 y1)
  -  (sqrt (+ (square x1)
  -           (square y1))))
  -
  -(defun find-angle (x1 y1)
  -  (let ((angle (acos (/ x1 (vec-len x1 y1)))))
  -    (if (minusp y1)
  -        (- (* 2 pi) angle)
  -        angle)))
  -
  +(defun vec-len (x y)
  +  "Returns the length of the vector described by x and y"
  +  (sqrt (+ (square x)
  +           (square y))))
  +
  +(defun find-angle (x y)
  +  "Returns the angle (in radians) between the vector (x, y) and the
  +postiive x-axis. The angle is measured as running counter-clockwise,
  +in cartesian coordinates, in other words find-angle returns pi/4 for a
  +the vector (1, 1)."
  +  (acos (/ x (vec-len x y))))
  +
  +(defun normalize-angle (angle)
  +  "Takes an angle ANGLE and returns the corresponding non-negative angle
  +less than or equal to 2pi. Note that 4pi would be normalized to 0, not
  +2pi, but 2pi is normalized to 2pi."
  +  (if (or (< angle 0)
  +          (> angle (* pi 2)))
  +      (mod angle (* pi 2))
  +      angle))
  +
  +(defun find-angle* (x1 y1 x2 y2)
  +  "Returns the angle between two vectors described by x1, y1 and x2,
  +y2."
  +  (let ((theta (- (phase (complex y2 x2))
  +                  (phase (complex y1 x1)))))
  +    (normalize-angle theta)))
  +
  +
  +;;
  +;; CLIM describes general (not neccessarily axis-aligned) ellipses by
  +;; their center and two vectors describing the radii. The formulation
  +;; for general ellipses described by Luc Maisonobe, referenced above,
  +;; computes the ellipse paths based on the center, the length of each
  +;; radius vectors, and the angle between the two radii. Just as a
  +;; circle could be (over-)described by its center and a specific 2-d
  +;; radius, but only the length of the radius is needed to definitively
  +;; describe the circle, any two (non-colinear) radius vectors could
  +;; describe a general ellipse, but only the length of the vectors and
  +;; the angle between them are needed. So, given two radii, we'll
  +;; compute their lengths and the angle between them and use these for
  +;; describing the cubiz bezier curves that will represent the ellipse.
   (defun reparameterize-ellipse (radius1-dx radius1-dy radius2-dx radius2-dy)
  +  "Returns three values, the length of radius 1, the length of radius
  +2, and the angle (CCW in cartesian coordinates) between the two
  +vectors."
     (let ((a (vec-len radius1-dx radius1-dy))
           (b (vec-len radius2-dx radius2-dy)))
       (let ((theta
  
positive.code:                (* a (sin theta) (cos eta))
                 (* b (cos theta) (sin eta))))))
  
  (defun ell* (lam
               center-x center-y
               radius1-dx radius1-dy radius2-dx radius2-dy)
    (multiple-value-bind (a b theta)
        (reparameterize-ellipse radius1-dx
                                radius1-dy
                                radius2-dx
                                radius2-dy)
      (ell (- lam theta) center-x center-y a b theta)))
  
  (defun ell-prime (eta a b theta)
    (values (+ (- (* a (cos theta) (sin eta)))
               (- (* b (sin theta) (cos eta))))
            (+ (- (* a (sin theta) (sin eta)))
               (* b (cos theta) (cos eta)))))
  
  (defun ell-prime* (lam1 lam2
                     center-x center-y
                     radius1-dx radius1-dy radius2-dx radius2-dy)
    (declare (ignore center-x center-y))
    (multiple-value-bind (a b theta)
        (reparameterize-ellipse radius1-dx radius1-dy radius2-dx radius2-dy)
      (let ((lam1 (- lam1 theta))
            (lam2 (- lam2 theta)))
        (let ((eta1 (atan (/ (sin lam1) b)
                          (/ (cos lam1) a)))
              (eta2 (atan (/ (sin lam2) b)
                          (/ (cos lam2) a))))
          (let ((alpha (* (sin (- eta2 eta1))
                          (/ (- (sqrt (+ 4 (* 3 (square (tan (/ (- eta2 eta1) 2)))))) 1)
                             3))))
            (multiple-value-bind (e1x e1y)
                (ell-prime eta1 a b theta)
              (multiple-value-bind (e2x e2y)
                  (ell-prime eta2 a b theta)
                (values (* alpha e1x)
                        (* alpha e1y)
                        (* alpha e2x)
                        (* alpha e2y)))))))))
  
  (defun normalize-angle (angle)
    (if (or (< angle 0)
            (> angle (* pi 2)))
        (mod angle (* pi 2))
        angle))
  
  (defun find-angle* (x1 y1 x2 y2)
    (let ((theta (- (phase (complex y2 x2))
                    (phase (complex y1 x1)))))
      (normalize-angle theta)))
  
  (defun transformation-angle (tr)
    (let ((x1 0) (y1 1)
          (x2 1) (y2 0))
      (multiple-value-bind (tx1 ty1)
  
negative.code:                (find-angle radius1-dx radius1-dy))))
        (values a b theta))))
  
  (defun ellipse-point (lambda0 center-x center-y a b theta)
    "Given an ellipse having center CENTER-X, CENTER-Y, and two radii of
  length A and B, with angle THETA between the radii from the center of
  the ellipse, returns two values, the x and y coordinates of a point on
  the ellipse having angle LAMBDA0 (CCW) relative to the major axis of the
  ellipse."
    (let ((eta (atan (/ (sin lambda0) b)
                     (/ (cos lambda0) a))))
      (values (+ center-x
                 (* a (cos theta) (cos eta))
                 (- (* b (sin theta) (sin eta))))
  