;;;-*- 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-polygon make-filled-polygon make-filled-polygon-edge 
	  )
	'pictures)

;Polygon Class Definition:

(defclass polygon (polypoint)
  ()
  (:documentation "the graphic class for drawing a polygon on the screen"))

;Function: make-polygon
; Return a new polygon object.

(defun make-polygon (point-seq  &rest options )
  "Make a polygon with the coordinates contained in POINT-SEQ.
The following keyword OPTIONS are allowed: GSTATE PARENT SENESITIVITY TRANSFORM PLIST"
  (DECLARE (VALUES polygon))

  (APPLY #'MAKE-INSTANCE 'polygon
	 :point-seq point-seq
	 options))


(defmethod draw-graphic ((polygon polygon) (view view)
			   &optional min-x min-y width height) 
  (declare (type (or null wcoord) min-x min-y width height))
  (with-slots (vertices gstate sensitivity extent) polygon
    (WHEN (visible-p polygon)
    (WHEN (AND ( > (LENGTH vertices) 0) (viewable-p polygon))
      (with-vector temp-vertices
		     (copy-to-vector vertices temp-vertices)
		     (transform-point-seq (graphic-world-transform polygon) temp-vertices)
		     (view-draw-polygon view temp-vertices 
				 (graphic-gstate polygon)))))
    ))



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

;define the filled-polygon class

(defclass filled-polygon (polygon)
  ()
  (:documentation "the graphic class for drawing a filled polygon on the screen"))

;Function: make-filled-polygon
;  Return a new filled polygon object.

(defun make-filled-polygon (point-seq  &rest options )
  "Make a filled-polygon with the coordinates contained in POINT-SEQ.
The following keyword OPTIONS are allowed: GSTATE PARENT SENESITIVITY TRANSFORM PLIST"
  (DECLARE (VALUES filled-polygon))

  (APPLY #'MAKE-INSTANCE 'filled-polygon
	 :point-seq point-seq
	 options))



;(DEFMETHOD graphic-contains-p ((filled-polygon filled-polygon) x y &optional pixel)
;  (DECLARE (type wcoord x y))
;  (WHEN (point-in-extents-p filled-polygon x y pixel)
;      (with-slots (vertices) filled-polygon
;	(with-vector temp-vertices
;		     (copy-to-vector vertices temp-vertices)
;		     (transform-point-seq (graphic-world-transform filled-polygon) temp-vertices)
;		     (WHEN 
;		       (inside-p temp-vertices (make-point :x x :y y)) t )))
;       ))

(defmethod graphic-contains-p ((filled-polygon filled-polygon) x y &optional pixel)
  
  ;; A variation of the "area fill" algorithm (see Lane J.  M. et al., ACM TOGS,
  ;; July, 1983, pp.  192-196). A series of triangles are formed connecting the
  ;; first vertex to the i'th and (1+ i)'th vertices. X/Y is inside the polygon
  ;; iff it is inside an odd number of these triangles.
  (when (point-in-extents-p filled-polygon x y pixel)
    (with-slots ( vertices) filled-polygon
      (with-vector points
	(copy-to-vector vertices points)
	(transform-point-seq (graphic-world-transform filled-polygon) points)
  
	(let*
	  ( ;;(points (polygon-points polygon))
	   
	   (p1x    (elt points 0))
	   (p1y    (elt points 1))
	   
	   (p2x    (elt points 2))
	   (p2y    (elt points 3))
	   
	   p3x p3y in-p)
	  
	  (do ((i 4 (+ i 2)))
	      
	      ((>= i (length points))
	       in-p)
	    
	    (setf p3x (elt points i)
		  p3y (elt points (1+ i)))
	    
	    ;; Point inside next triangle?
	    (when
	      
	      ;; Use cross product to test if point is on same side of all triangle
	      ;; edges or if point lies on an edge.
	      (let ((sign1 (signum (- (* (- p1x x) (- p2y y)) (* (- p2x x) (- p1y y))))))
		(or (zerop sign1)
		    (let ((sign2 (signum (- (* (- p2x x) (- p3y y)) (* (- p3x x) (- p2y y))))))
		      (or (zerop sign2)
			  (when (= sign1 sign2)
			    (let ((sign3 (signum (- (* (- p3x x) (- p1y y)) (* (- p1x x) (- p3y y))))))
			      (or (zerop sign3)
				  (= sign1 sign3))))))))
	      
	      ;; Yes, complement inside-ness
	      (setf in-p (not in-p)))
	    
	    ;; Prepare next triangle.
	    (setf p2x p3x p2y p3y)))))))

; Method for drawing a filled-polygon

(defmethod draw-graphic ((filled-polygon filled-polygon) (view view)
                           &optional min-x min-y width height) 
  (declare (type (or null wcoord) min-x min-y width height))
  (with-slots (vertices gstate extent) filled-polygon
    (WHEN (visible-p filled-polygon)
      (WHEN (AND ( > (LENGTH vertices) 0) (viewable-p filled-polygon))
	(with-vector temp-vertices
		     (copy-to-vector vertices temp-vertices)
		     (transform-point-seq (graphic-world-transform filled-polygon) temp-vertices)
	(view-draw-filled-polygon view temp-vertices 
				 (graphic-gstate filled-polygon)))))))



;;define the filled-polygon-edge class

(defclass filled-polygon-edge ( filled-polygon edge) ;mixin the edge class
  ()
  (:documentation "the graphic class for drawing a filled polygon with edge on the screen"))

;Function: make-filled-polygon-edge
;return a filled-polygon-edge

(defun make-filled-polygon-edge (point-seq  &rest options )
  "Make a filled-polygon-edge with the coordinates contained in POINT-SEQ.
The following keyword OPTIONS are allowed: GSTATE PARENT SENESITIVITY TRANSFORM PLIST"
  (DECLARE (VALUES filled-polygon-edge))

  (APPLY #'MAKE-INSTANCE 'filled-polygon-edge
	 :point-seq point-seq
	 options))





;  Return a new filled-polygon-edge object.

(defmethod draw-graphic ((filled-polygon-edge filled-polygon-edge) (view view)
                           &optional min-x min-y width height) 
  (declare (type (or null wcoord) min-x min-y width height))
  (with-slots (vertices gstate edge-gstate extent) filled-polygon-edge
    (when   (visible-p filled-polygon-edge)
      (WHEN (AND ( > (LENGTH vertices) 0) (viewable-p filled-polygon-edge))
	(with-vector temp-vertices
		     (copy-to-vector vertices temp-vertices)
		     (transform-point-seq (graphic-world-transform filled-polygon-edge) temp-vertices)
		     (view-draw-filled-polygon view temp-vertices 
					       (graphic-gstate filled-polygon-edge))
		     (view-draw-polygon view temp-vertices
					      (edge-gstate filled-polygon-edge)))
	))))
  
















