;;;-*- 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-bspline make-closed-bspline make-filled-bspline make-filled-bspline-edge ) 'pictures) (defclass bspline (polypoint) () (:documentation "the graphic class for drawing a bspline on the screen")) (defun make-bspline (point-seq &rest options ) "Make a bspline with the coordinates contained in POINT-SEQ. The following keyword OPTIONS are allowed: GSTATE PARENT SENESITIVITY TRANSFORM PLIST" (DECLARE (VALUES polygon)) (APPLY #'MAKE-INSTANCE 'bspline :point-seq point-seq options)) (defclass closed-bspline (bspline) () (:documentation "the graphic class for drawing a closed bspline on the screen")) (defun make-closed-bspline (point-seq &rest options ) "Make a bspline with the coordinates contained in POINT-SEQ. The following keyword OPTIONS are allowed: GSTATE PARENT SENESITIVITY TRANSFORM PLIST" (DECLARE (VALUES polygon)) (APPLY #'MAKE-INSTANCE 'closed-bspline :point-seq point-seq options)) (defclass filled-bspline (bspline) () (:documentation "the graphic class for drawing a filled bspline on the screen")) (defun make-filled-bspline (point-seq &rest options ) "Make a bspline with the coordinates contained in POINT-SEQ. The following keyword OPTIONS are allowed: GSTATE PARENT SENESITIVITY TRANSFORM PLIST" (DECLARE (VALUES polygon)) (APPLY #'MAKE-INSTANCE 'filled-bspline :point-seq point-seq options)) (defclass filled-bspline-edge (filled-bspline edge) () (:documentation "the graphic class for drawing a filled bspline edge on the screen")) (defun make-filled-bspline-edge (point-seq &rest options ) "Make a bspline-edge with the coordinates contained in POINT-SEQ. The following keyword OPTIONS are allowed: GSTATE PARENT SENESITIVITY TRANSFORM PLIST" (DECLARE (VALUES polygon)) (APPLY #'MAKE-INSTANCE 'filled-bspline-edge :point-seq point-seq options)) (PROCLAIM '(inline bspline-fwd-diff)) (DEFUN bspline-fwd-diff (c position dt dt2 dt3) "Return the forward differences for a B-spline cubic polynomial. (SUBSEQ C 0 4) is the B-spline geometry vector. DT is the increment to the curve parameter for each iteration of the polynomial evaluation. DT2 and DT3 are DT squared and cubed, respectively." (LET* ((c0 (ELT c position)) (c1 (ELT c (+ position 2))) (c2 (ELT c (+ position 4))) (c3 (ELT c (+ position 6))) ;; Compute coefficent of curve polynomial at3 + bt2 + ct +d (a (* (/ 1 6) (+ (- c0) (* 3.0 c1) (* -3.0 c2) c3))) (b (* (/ 1 6) (+ (* 3.0 c0) (* -6.0 c1) (* 3.0 c2)))) (c (* (/ 1 6) (+ (* -3.0 c0) (* 3.0 c2)))) (d (* (/ 1 6) (+ c0 (* 4.0 c1) c2))) (adt3 (* a dt3)) (6adt3 (* 6.0 adt3)) (bdt2 (* b dt2))) (VALUES d (+ adt3 bdt2 (* c dt)) (+ 6adt3 (+ bdt2 bdt2)) 6adt3))) (DEFMACRO compose-spline (b-spline vertices) "Triple the end points so that B-spline will intersect first/last control points and place them in VERTICES" `(PROGN (DOTIMES (pos 2) (SETF (vertex-x ,b-spline pos) first-x)) (DOTIMES (pos 2) (SETF (vertex-y ,b-spline pos) first-y)) (SETF (vertex-i ,b-spline 2) ,vertices) (DOTIMES (pos 2) (SETF (vertex-x ,b-spline (+ *large-number* pos)) last-x)) (LET ((length-spline (length-point-seq ,b-spline))) (DOTIMES (pos 2) (SETF (vertex-y ,b-spline (- length-spline pos 1)) last-y))))) (DEFMACRO calculate-spline (vector) `(PROGN (DO ((i 0 (1+ i))) ((EQ i ncurves)) ;; Draw i'th curve (MULTIPLE-VALUE-BIND (x dx dx2 dx3) (bspline-fwd-diff spline (* i 2) dt dt2 dt3) (MULTIPLE-VALUE-BIND (y dy dy2 dy3) (bspline-fwd-diff spline (1+ (* i 2)) dt dt2 dt3) (DO ((n 0)) (()) (LET ((next-x x) (next-y y)) ;; Draw n'th curve segment (WHEN (AND prev-x (NOT (AND (= prev-x next-x) (= prev-y next-y)))) (MULTIPLE-VALUE-BIND (nx ny) (transform-point (graphic-world-transform bspline) next-x next-y) (LET ((length (length-point-seq ,vector))) (SETF (vertex-x ,vector length) nx) (SETF (vertex-y ,vector length) ny)))) (SETF prev-x x prev-y y) (WHEN (EQ number-deltas (INCF n)) (RETURN)) (INCF x dx) (INCF y dy) (INCF dx dx2) (INCF dx2 dx3) (INCF dy dy2) (INCF dy2 dy3)))))) ;; Draw final curve segment (MULTIPLE-VALUE-BIND (nx ny) (transform-point (graphic-world-transform bspline) last-x last-y) (LET ((length (length-point-seq ,vector))) (SETF (vertex-x ,vector length) nx) (SETF (vertex-y ,vector length) ny)) ))) (defmethod draw-graphic ((bspline bspline) (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) bspline (WHEN (visible-p bspline) (with-vector spline (WHEN (> (LENGTH vertices) 0) (LET ((last-x (vertex-x vertices *large-number* )) (last-y (vertex-y vertices *large-number* )) (first-x (vertex-x vertices 0)) (first-y (vertex-y vertices 0))) (compose-spline spline vertices) (LET* (prev-x prev-y (number-deltas 4) (dt (/ 1.0 number-deltas)) (dt2 (* dt dt)) (dt3 (* dt2 dt)) (ncurves (+ 1 (length-point-seq vertices)))) (with-vector spline-points (calculate-spline spline-points) (view-draw-polyline view spline-points (graphic-gstate bspline)) )))))))) (defmethod draw-graphic ((bspline closed-bspline) (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) bspline (WHEN (visible-p bspline) (with-vector spline (WHEN (> (LENGTH vertices) 0) (LET ((last-x (vertex-x vertices *large-number* )) (last-y (vertex-y vertices *large-number* )) (first-x (vertex-x vertices 0)) (first-y (vertex-y vertices 0))) (compose-spline spline vertices) (LET* (prev-x prev-y (number-deltas 4) (dt (/ 1.0 number-deltas)) (dt2 (* dt dt)) (dt3 (* dt2 dt)) (ncurves (+ 1 (length-point-seq vertices)))) (with-vector spline-points (calculate-spline spline-points) (view-draw-polygon view spline-points (graphic-gstate bspline)) ) ))))))) (defmethod draw-graphic ((bspline filled-bspline) (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) bspline (WHEN (visible-p bspline) (with-vector spline (WHEN (> (LENGTH vertices) 0) (LET ((last-x (vertex-x vertices *large-number* )) (last-y (vertex-y vertices *large-number* )) (first-x (vertex-x vertices 0)) (first-y (vertex-y vertices 0))) (compose-spline spline vertices) (LET* (prev-x prev-y (number-deltas 4) (dt (/ 1.0 number-deltas)) (dt2 (* dt dt)) (dt3 (* dt2 dt)) (ncurves (+ 1 (length-point-seq vertices)))) (with-vector spline-points (calculate-spline spline-points) (view-draw-filled-polygon view spline-points (graphic-gstate bspline)) ) ))))))) (defmethod draw-graphic ((bspline filled-bspline-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) bspline (WHEN (visible-p bspline) (with-vector spline (WHEN (> (LENGTH vertices) 0) (LET ((last-x (vertex-x vertices *large-number* )) (last-y (vertex-y vertices *large-number* )) (first-x (vertex-x vertices 0)) (first-y (vertex-y vertices 0))) (compose-spline spline vertices) (LET* (prev-x prev-y (number-deltas 4) (dt (/ 1.0 number-deltas)) (dt2 (* dt dt)) (dt3 (* dt2 dt)) (ncurves (+ 1 (length-point-seq vertices)))) (with-vector spline-points (calculate-spline spline-points) (view-draw-filled-polygon view spline-points (graphic-gstate bspline)) (view-draw-polygon view spline-points (edge-gstate bspline)) )))))))) (DEFMETHOD graphic-contains-p ((bspline bspline) x y &optional (pixel 1)) (DECLARE (type wcoord x y) ) (when (point-in-extents-p bspline x y pixel) (with-vector spline (with-slots (vertices gstate) bspline (WHEN (> (LENGTH vertices) 0) (LET ((last-x (vertex-x vertices *large-number* )) (last-y (vertex-y vertices *large-number* )) (first-x (vertex-x vertices 0)) (first-y (vertex-y vertices 0))) (compose-spline spline vertices) (LET* (prev-x prev-y (line-width (OR (AND (graphic-gstate bspline) (gstate-line-width bspline) (+ (/ (gstate-line-width bspline) 2) pixel)) pixel)) (number-deltas 4) (dt (/ 1.0 number-deltas)) (dt2 (* dt dt)) (dt3 (* dt2 dt)) (ncurves (+ 1 (length-point-seq vertices)))) (with-vector spline-points (calculate-spline spline-points) (point-near-line spline-points line-width x y) )))))))) (DEFMETHOD graphic-contains-p ((bspline closed-bspline) x y &optional (pixel 1)) (DECLARE (type wcoord x y) ) (when (point-in-extents-p bspline x y pixel) (with-vector spline (with-slots (vertices gstate) bspline (WHEN (> (LENGTH vertices) 0) (LET ((last-x (vertex-x vertices *large-number* )) (last-y (vertex-y vertices *large-number* )) (first-x (vertex-x vertices 0)) (first-y (vertex-y vertices 0))) (compose-spline spline vertices) (LET* (prev-x prev-y (line-width (OR (AND (graphic-gstate bspline) (gstate-line-width bspline) (+ (/ (gstate-line-width bspline) 2) pixel)) pixel)) (number-deltas 4) (dt (/ 1.0 number-deltas)) (dt2 (* dt dt)) (dt3 (* dt2 dt)) (ncurves (+ 1 (length-point-seq vertices)))) (with-vector spline-points (calculate-spline spline-points) (with-vector temp-vector (VECTOR-PUSH-EXTEND first-x temp-vector) (VECTOR-PUSH-EXTEND first-y temp-vector) (SETF (vertex-i spline-points *large-number*) temp-vector)) (point-near-line spline-points line-width x y) )))))))) (defmacro inside-spline-p (points x y) `(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)))) (DEFMETHOD graphic-contains-p ((bspline filled-bspline) x y &optional (pixel 1)) (DECLARE (type wcoord x y) ) (when (point-in-extents-p bspline x y pixel) (with-vector spline (with-slots (vertices gstate) bspline (WHEN (> (LENGTH vertices) 0) (LET ((last-x (vertex-x vertices *large-number* )) (last-y (vertex-y vertices *large-number* )) (first-x (vertex-x vertices 0)) (first-y (vertex-y vertices 0))) (compose-spline spline vertices) (LET* (prev-x prev-y (number-deltas 4) (dt (/ 1.0 number-deltas)) (dt2 (* dt dt)) (dt3 (* dt2 dt)) (ncurves (+ 1 (length-point-seq vertices)))) (with-vector spline-points (calculate-spline spline-points) (inside-spline-p spline-points x y ) )))))))) (DEFMETHOD graphic-contains-p ((bspline filled-bspline-edge) x y &optional (pixel 1)) (DECLARE (type wcoord x y) ) (when (point-in-extents-p bspline x y pixel) (with-vector spline (with-slots (vertices gstate) bspline (WHEN (> (LENGTH vertices) 0) (LET ((last-x (vertex-x vertices *large-number* )) (last-y (vertex-y vertices *large-number* )) (first-x (vertex-x vertices 0)) (first-y (vertex-y vertices 0)) (line-width (OR (AND (graphic-gstate bspline) (gstate-line-width bspline) (+ (/ (gstate-line-width bspline) 2) pixel)) pixel))) (compose-spline spline vertices) (LET* (prev-x prev-y (number-deltas 4) (dt (/ 1.0 number-deltas)) (dt2 (* dt dt)) (dt3 (* dt2 dt)) (ncurves (+ 1 (length-point-seq vertices)))) (with-vector spline-points (calculate-spline spline-points) (OR (inside-spline-p spline-points x y) (point-near-line spline-points line-width x y)) )))))))) (DEFMETHOD graphic-damage ((graphic bspline)) "Records graphic as a damaged region in each view to which it is attached." (with-slots (extent gstate) graphic (WHEN (valid-extent-p extent) (do ((g graphic (graphic-parent g))) ((null g)) (dolist (view (graphic-views g)) (UNLESS (extent-valid-p graphic) (graphic-extent graphic)) (WHEN (AND (NOT (AND gstate (gstate-line-width graphic))) (< (ABS (- (extent-rect-xmax extent) (extent-rect-xmin extent))) (view-pixel-size view))) (SETF (extent-rect-xmax extent) (+ (extent-rect-xmin extent) (view-pixel-size view)))) (view-damage view graphic))))))