;;;-*- Mode:Common-Lisp; Package:PICTURES; Base:10 -*-
;;;
;;;
;;;
;;;			 TEXAS INSTRUMENTS INCORPORATED
;;;				  P.O. BOX 149149
;;;			       AUSTIN, TEXAS 78714-9149
;;;
;;; Copyright (C)1987,1988,1989,1990 Texas Instruments Incorporated.
;;;
;;; Permission is granted to any individual or institution to use, copy, modify,
;;; and distribute this software, provided that this complete copyright and
;;; permission notice is maintained, intact, in all copies and supporting
;;; documentation.
;;;
;;; Texas Instruments Incorporated provides this software "as is" without
;;; express or implied warranty.
;;;
;;; Authors: Delmar Hager, James Dutton, Teri Crowe
;;; Contributors: Kerry Kimbrough, Patrick Hogan, Eric Mielke

(in-package "PICTURES")


(export '(
	  make-ellipse
	  make-filled-ellipse
	  make-filled-ellipse-edge
	  ellipse-origin-x
	  ellipse-origin-y
	  ellipse-width
	  ellipse-height
	  )
	'pictures)

;Method: rectangle-size
;Method: rectangle-width and (setf rectangle-width)
;Method: rectangle-height and (setf rectangle-height)
;Method: scale-transform

(defclass ellipse (rectangle)
  ()
  (:documentation "A  graphic that represents a ellipse in either object coordinates."))


;Filled-Ellipse Class Definition:

(defclass filled-ellipse (  ellipse filled-rectangle)
  ()
  (:documentation "Filled ellipse class in pictures"))


;Filled-Ellipse-Edge Class Definition:

(defclass filled-ellipse-edge (  ellipse filled-rectangle-edge)
  ()
  (:documentation "Filled ellipse edge class in pictures"))



(defun make-ellipse (x-min y-min width height  &rest options )
  "Make a ellipse with the with the given X-MIN, Y-MIN, WIDTH and HEIGHT.
The following keyword OPTIONS are allowed: GSTATE PARENT SENESITIVITY TRANSFORM PLIST"
  (DECLARE (VALUES ellipse))

  (APPLY #'MAKE-INSTANCE 'ellipse
	 :point-seq (complete-rectangle x-min y-min (+ x-min width) (+ y-min height))
	 options))

(defun make-filled-ellipse (x-min y-min width height  &rest options )
  "Make a filled-ellipse with the given X-MIN, Y-MIN, WIDTH and HEIGHT.
The following keyword OPTIONS are allowed: GSTATE PARENT SENESITIVITY TRANSFORM PLIST"
  (DECLARE (VALUES filled-ellipse))

  (APPLY #'MAKE-INSTANCE 'filled-ellipse
	 :point-seq (complete-rectangle x-min y-min (+ x-min width) (+ y-min height))
	 options))





(defun make-filled-ellipse-edge (x-min y-min width height  &rest options )
  "Make a filled-ellipse-edge with the given X-MIN, Y-MIN, WIDTH and HEIGHT.
The following keyword OPTIONS are allowed: GSTATE PARENT SENESITIVITY TRANSFORM PLIST"
  (DECLARE (VALUES filled-ellipse-edge))

  (APPLY #'MAKE-INSTANCE 'filled-ellipse-edge
	 :point-seq (complete-rectangle x-min y-min (+ x-min width) (+ y-min height))
	 options))

(DEFMETHOD ellipse-origin-x ((ellipse ellipse))
  (DECLARE (VALUES (type ocoord x)))
  (vertex-x ellipse 0)
  )

(DEFMETHOD (SETF ellipse-origin-x) (origin-x (ellipse ellipse) )
  (LET ((difference (- origin-x (vertex-x ellipse 0))))
    (extent-changed ellipse)
    (DOTIMES (pos 4 origin-x)
      (SETF (vertex-x ellipse pos) (+ difference (vertex-x ellipse pos)) ))))

(DEFMETHOD ellipse-origin-y ((ellipse ellipse))
  (DECLARE (VALUES (type ocoord y)))
  (vertex-y ellipse 0))

(DEFMETHOD (SETF ellipse-origin-y) (origin-y (ellipse ellipse) )
  (LET ((difference (- origin-y (vertex-y ellipse 0))))
    (extent-changed ellipse)
    (DOTIMES (pos 4 origin-y)
      (SETF (vertex-y ellipse pos) (+ difference (vertex-y ellipse pos)) ))))

(DEFMETHOD ellipse-width ((ellipse ellipse))
  (with-slots (vertices transform) ellipse
     (VALUES (distance
	      (vertex-x ellipse 0) (vertex-y ellipse 0) (vertex-x ellipse 1) (vertex-y ellipse 1)))))

(DEFMETHOD (SETF ellipse-width) (width (ellipse ellipse))
  (with-slots (vertices transform) ellipse
    (extent-changed ellipse)
    (MULTIPLE-VALUE-BIND (x y dx dy) (compute-point (VERTEX-X ELLIPSE 0)(VERTEX-Y ELLIPSE 0)
						    (vertex-x ellipse 1)(vertex-y ellipse 1) width)
      (SETF (vertex-x ellipse 1) x)
      (SETF (vertex-y ellipse 1) y)
      (SETF (vertex-x ellipse 2) (+ (vertex-x ellipse 2) dx))
      (SETF (vertex-y ellipse 2) (+ (vertex-y ellipse 2) dy))))
  ellipse)

(DEFMETHOD ellipse-height ((ellipse ellipse))
  (with-slots (vertices transform) ellipse
    (VALUES (distance
	      (vertex-x ellipse 0) (vertex-y ellipse 0) (vertex-x ellipse 3) (vertex-y ellipse 3)))))


(DEFMETHOD (SETF ellipse-height) (height (ellipse ellipse))
  (with-slots (vertices transform) ellipse
    (extent-changed ellipse)
    (MULTIPLE-VALUE-BIND (x y dx dy) (compute-point (VERTEX-X ELLIPSE 0)(VERTEX-Y ELLIPSE 0)
						    (vertex-x ellipse 3)(vertex-y ellipse 3) height)
      (SETF (vertex-x ellipse 3) x)
      (SETF (vertex-y ellipse 3) y)
      (SETF (vertex-x ellipse 2) (+ (vertex-x ellipse 2) dx))
      (SETF (vertex-y ellipse 2) (+ (vertex-y ellipse 2) dy)))
    ellipse))

(defmethod draw-graphic ((ellipse ellipse) (view view)
			 &optional min-x min-y width height) 
  (declare (type (or null wcoord) min-x min-y width height))
  (LET ((world-transform (graphic-world-transform ellipse)))
    (with-slots (vertices extent) ellipse    
      (WHEN (visible-p ellipse)
	(with-vector temp-vertices
	  (copy-to-vector vertices temp-vertices)

	    (if (AND world-transform (= (t12 world-transform)(t21 world-transform) 0))

		(PROGN
		  (transform-point-seq world-transform temp-vertices)
		  (view-draw-arc  view		; Yes, use draw-ellipse to draw it
				  (min-value-vector temp-vertices 0)
				  (min-value-vector temp-vertices 1)
				  (- (max-value-vector temp-vertices 0)(min-value-vector temp-vertices 0))
				  (- (max-value-vector temp-vertices 1)(min-value-vector temp-vertices 1))
				  0 (* 2.0 pi)
				  (graphic-gstate ellipse)))

		(with-vector scan-vector
		  (scan-ellipse (ellipse-origin-x ellipse)(ellipse-origin-y ellipse)
				(ellipse-width ellipse)(ellipse-height ellipse) scan-vector
				(view-pixel-size view))
		  (transform-point-seq world-transform scan-vector)
		  (view-draw-polygon view	; No, use draw-polygon to draw it
				     scan-vector
				     (graphic-gstate ellipse)))
		)
	    ))
	))
  ellipse)

(defmethod draw-graphic ((ellipse filled-ellipse) (view view)
			 &optional min-x min-y width height) 
  (declare (type (or null wcoord) min-x min-y width height))
  (LET ((world-transform (graphic-world-transform ellipse)))
    (with-slots (vertices extent) ellipse    
      (WHEN (visible-p ellipse)
	(with-vector temp-vertices
	  (copy-to-vector vertices temp-vertices)

	    (if (AND world-transform (= (t12 world-transform)(t21 world-transform) 0))

		(PROGN
		  (transform-point-seq world-transform temp-vertices)
		  (view-draw-filled-arc  view		; Yes, use draw-ellipse to draw it
				  (min-value-vector temp-vertices 0)
				  (min-value-vector temp-vertices 1)
				  (- (max-value-vector temp-vertices 0)(min-value-vector temp-vertices 0))
				  (- (max-value-vector temp-vertices 1)(min-value-vector temp-vertices 1))
				  0 (* 2.0 pi)
				  (graphic-gstate ellipse)))

		(with-vector scan-vector
		  (scan-ellipse (ellipse-origin-x ellipse)(ellipse-origin-y ellipse)
				(ellipse-width ellipse)(ellipse-height ellipse) scan-vector
				(view-pixel-size view))
		  (transform-point-seq world-transform scan-vector)
		  (view-draw-filled-polygon view	; No, use draw-polygon to draw it
				     scan-vector
				     (graphic-gstate ellipse)))
		)
	    ))
	))
  ellipse)

(defmethod draw-graphic ((ellipse filled-ellipse-edge) (view view)
			 &optional min-x min-y width height) 
  (declare (type (or null wcoord) min-x min-y width height))
  (LET ((world-transform (graphic-world-transform ellipse)))
    (with-slots (vertices edge-gstate extent) ellipse    
      (WHEN (visible-p ellipse)
	(with-vector temp-vertices
	  (copy-to-vector vertices temp-vertices)
	  	  
	  (if (AND world-transform (= (t12 world-transform)(t21 world-transform) 0))
	      
	      (PROGN
		(transform-point-seq world-transform temp-vertices)
		(view-draw-filled-arc  view	; Yes, use draw-ellipse to draw it
				       (min-value-vector temp-vertices 0)
				       (min-value-vector temp-vertices 1)
				       (- (max-value-vector temp-vertices 0)(min-value-vector temp-vertices 0))
				       (- (max-value-vector temp-vertices 1)(min-value-vector temp-vertices 1))
				       0 (* 2.0 pi)
				       (graphic-gstate ellipse))
		(view-draw-arc  view		; Yes, use draw-ellipse to draw it
				(min-value-vector temp-vertices 0)
				(min-value-vector temp-vertices 1)
				(- (max-value-vector temp-vertices 0)(min-value-vector temp-vertices 0))
				(- (max-value-vector temp-vertices 1)(min-value-vector temp-vertices 1))
				0 (* 2.0 pi)
				(edge-gstate ellipse)))
	      
	      (with-vector scan-vector
		(scan-ellipse (ellipse-origin-x ellipse)(ellipse-origin-y ellipse)
			      (ellipse-width ellipse)(ellipse-height ellipse) scan-vector
			      (view-pixel-size view))
		(transform-point-seq world-transform scan-vector)
		
		(view-draw-filled-polygon view	; No, use draw-polygon to draw it
					  scan-vector
					  (graphic-gstate ellipse))
		(view-draw-polygon view	
				   scan-vector
				   (edge-gstate ellipse)))
	      )
	  ))
      ))
  ellipse)

(DEFMETHOD graphic-contains-p ((ellipse ellipse)  x y &optional (pixel 1))
  (DECLARE (type wcoord x y) )
  (when (point-in-extents-p ellipse x y pixel)
    (LET ((world-transform (graphic-world-transform ellipse))
	  (line-width (OR (AND
			    (graphic-gstate ellipse)
			    (gstate-line-width ellipse) (+ (/ (gstate-line-width ellipse) 2) pixel)) pixel)))
      (with-slots (vertices) ellipse    
	(with-vector temp-vertices
	  (copy-to-vector vertices temp-vertices)
	  (with-vector scan-vector
	    (scan-ellipse (ellipse-origin-x ellipse)(ellipse-origin-y ellipse)
			  (ellipse-width ellipse)(ellipse-height ellipse) scan-vector
			  pixel)
	    (transform-point-seq world-transform scan-vector)
	    (point-near-line scan-vector line-width x y)))))))

(DEFMETHOD graphic-contains-p ((ellipse filled-ellipse)  x y &optional (pixel 1))
  (DECLARE (type wcoord x y) )
  (when (point-in-extents-p ellipse x y pixel)
    (LET ((world-transform (graphic-world-transform ellipse)))
      (with-slots (vertices) ellipse    
	(with-vector temp-vertices
	  (copy-to-vector vertices temp-vertices)
	  (with-vector scan-vector
	    (scan-ellipse (ellipse-origin-x ellipse)(ellipse-origin-y ellipse)
			  (ellipse-width ellipse)(ellipse-height ellipse) scan-vector
			  pixel)
	    (transform-point-seq world-transform scan-vector)
	    (WHEN 
	      (inside-p scan-vector (make-point :x x :y y)) t )
	    ))))))

(DEFMETHOD graphic-contains-p ((ellipse filled-ellipse-edge)  x y &optional (pixel 1))
  (DECLARE (type wcoord x y) )
  (when (point-in-extents-p ellipse x y pixel)
    (LET ((world-transform (graphic-world-transform ellipse))
	  (line-width (OR (AND
			    (graphic-gstate ellipse)
			    (gstate-line-width ellipse) (+ (/ (gstate-line-width ellipse) 2) pixel)) pixel)))
      (with-slots (vertices) ellipse    
	(with-vector temp-vertices
	  (copy-to-vector vertices temp-vertices)
	  (with-vector scan-vector
	    (scan-ellipse (ellipse-origin-x ellipse)(ellipse-origin-y ellipse)
			  (ellipse-width ellipse)(ellipse-height ellipse) scan-vector
			  pixel)
	    (transform-point-seq world-transform scan-vector)
	    (WHEN (OR  
		    (inside-p scan-vector (make-point :x x :y y))
		    (point-near-line scan-vector line-width x y) ) t )
	    ))))))



(DEFMACRO ellipse-y-coordinate (x  a2 b2)
  "Determine a given Y value in an ellispe for X and the aspects A and B.   A2 and B2 are A and B squared"
  `(SQRT (- ,b2 (/ (* ,x ,x ,b2) (* ,a2)))))

 

(DEFUN scan-ellipse ( origin-x origin-y width height vector pixel)
  "Contruct an ellipse from the ORIGIN-X, ORIGIN-Y, WIDTH, HEIGHT and store the new vertices in VECTOR"
  (SETF (FILL-POINTER vector) 0)
  (LET* ((a  (- (/  width  2) ))
	(a2 (* a a))
	(b  (/  height 2))
	(b2 (* b b))
	(smoothness (* pixel 1)))

    (VECTOR-PUSH-EXTEND a vector 100)
    (VECTOR-PUSH-EXTEND (ellipse-y-coordinate  a  a2 b2) vector 100)
    
    (DO ((x  (+ a (* pixel smoothness)) (+ x (* pixel (LET ((difference
								 (ABS (/ (- (ELT vector (- (FILL-POINTER vector) 1))
								    (ELT vector (- (FILL-POINTER vector) 3))) pixel))))
							   (COND
							     ((< difference 1) 8)
							     ((< difference 2) 6)
							     ((< difference 3) 4)
							     ((< difference 4) 2)
							     (t 1))))
							   )))
	((> x 0))
      (VECTOR-PUSH-EXTEND x vector  100)
      (VECTOR-PUSH-EXTEND (ellipse-y-coordinate x  a2 b2) vector 100)
      ))

  (DO ((y (- (FILL-POINTER vector) 1) (- y 2)))
	((< y 0))
      (VECTOR-PUSH-EXTEND (- (ELT vector (- y 1)))  vector 100)
      (VECTOR-PUSH-EXTEND  (ELT vector y) vector 100))

  (DO ((y (- (FILL-POINTER vector) 1) (- y 2)))
	((< y 0))
      (VECTOR-PUSH-EXTEND (ELT vector (- y 1))  vector 100)
      (VECTOR-PUSH-EXTEND  (- (ELT vector y)) vector 100))

  (DO ((y (- (FILL-POINTER vector) 1) (- y 2)))
	((< y 0))
      (SETF  (ELT vector (- y 1)) (+ (ELT vector (- y 1)) origin-x  (/ width 2)))
      (SETF  (ELT vector y) (+ (ELT vector y)  origin-y (/ height 2))))
  )
















