(FILECREATED "30-Oct-84 10:55:42" {ERIS}<LISPNEW>SOURCES>DRAWPATCH.;2 35312  

      changes to:  (FNS \DRAWCIRCLE.DISPLAY \DRAWELLIPSE.DISPLAY \LINEWITHBRUSH \CURVE2)
		   (VARS DRAWPATCHCOMS)

      previous date: "29-Oct-84 14:48:48" {ERIS}<LISPNEW>SOURCES>DRAWPATCH.;1)


(* Copyright (c) 1984 by Xerox Corporation. All rights reserved.)

(PRETTYCOMPRINT DRAWPATCHCOMS)

(RPAQQ DRAWPATCHCOMS ((FNS \DRAWCIRCLE.DISPLAY \DRAWELLIPSE.DISPLAY \LINEWITHBRUSH \CURVE2 
			   \BBTCURVEPT)))
(DEFINEQ

(\DRAWCIRCLE.DISPLAY
  [LAMBDA (DISPLAYSTREAM CENTERX CENTERY RADIUS BRUSH DASHING)
                                                             (* JonL " 7-May-84 02:46")
                                                             (* \DRAWCIRCLE.DISPLAY extended for color.
							     Color is specified by either BRUSH or the DSPCOLOR of 
							     DS.)
    (DECLARE (LOCALVARS . T))
    (COND
      ((OR (NOT (NUMBERP RADIUS))
	   (ILESSP (SETQ RADIUS (FIXR RADIUS))
		   0))
	(\ILLEGAL.ARG RADIUS))
      ((EQ RADIUS 0)                                         (* don't draw anything.)
	NIL)
      (T (GLOBALRESOURCE \BRUSHBBT
			 (PROG ((X 0)
				(Y RADIUS)
				(D (ITIMES 2 (IDIFFERENCE 1 RADIUS)))
				DestinationBitMap LEFT RIGHTPLUS1 TOP BOTTOM BRUSHWIDTH BRUSHHEIGHT 
				LEFTMINUSBRUSH BOTTOMMINUSBRUSH TOPMINUSBRUSH BRUSHBM DESTINATIONBASE 
				BRUSHBASE RASTERWIDTH BRUSHRASTERWIDTH NBITSRIGHTPLUS1 OPERATION 
				HEIGHTMINUS1 CX CY (BBT \BRUSHBBT)
				COLOR COLORBRUSHBASE NBITS (DISPLAYDATA (fetch IMAGEDATA
									   of DISPLAYSTREAM))
				(USERFN (AND (LITATOM BRUSH)
					     BRUSH)))        (* many of these variables are used by the macro for 
							     \CURVEPT that passes them to \BBTCURVEPT and 
							     .SETUP.FOR.\BBTCURVEPT. sets them up.)
			       (COND
				 (USERFN                     (* if calling user fn, don't bother with set up and 
							     leave points in stream coordinates.)
					 (SETQ CX CENTERX)
					 (SETQ CY CENTERY))
				 (T (.SETUP.FOR.\BBTCURVEPT.)
				    (SELECTQ NBITS
					     (1 (SETQ CX (\DSPTRANSFORMX (IDIFFERENCE CENTERX
										      (FOLDLO 
										       BRUSHWIDTH 2))
									 DISPLAYDATA)))
					     (4 (SETQ CX (\DSPTRANSFORMX (IDIFFERENCE
									   CENTERX
									   (FOLDLO (LRSH BRUSHWIDTH 2)
										   2))
									 DISPLAYDATA)))
					     (8 (SETQ CX (\DSPTRANSFORMX (IDIFFERENCE
									   CENTERX
									   (FOLDLO (LRSH BRUSHWIDTH 3)
										   2))
									 DISPLAYDATA)))
					     (SHOULDNT))     (* take into account the brush thickness.)
				    (SETQ CY (\DSPTRANSFORMY (IDIFFERENCE CENTERY (FOLDLO BRUSHHEIGHT 
											  2))
							     DISPLAYDATA))
                                                             (* Move the window to top while interruptable, but 
							     verify that it is still there uninterruptably with 
							     drawing points)
				    (\INSURETOPWDS DISPLAYSTREAM)))
			       [COND
				 ((EQ RADIUS 1)              (* put a single brush down.)
                                                             (* draw the top and bottom most points.)
				   [COND
				     (USERFN (APPLY* USERFN CX CY DISPLAYSTREAM))
				     (T (.WHILE.TOP.DS. DISPLAYSTREAM (\CURVEPT CX CY]
				   (RETURN))
				 (T                          (* draw the top and bottom most points.)
				    (COND
				      (USERFN (APPLY* USERFN CX (IPLUS CY RADIUS)
						      DISPLAYSTREAM)
					      (APPLY* USERFN CX (IDIFFERENCE CY RADIUS)
						      DISPLAYSTREAM))
				      (T (.WHILE.TOP.DS. DISPLAYSTREAM (\CURVEPT CX (IPLUS CY RADIUS))
							 (\CURVEPT CX (IDIFFERENCE CY RADIUS]
			   LP                                (* (UNFOLD x 2) is used instead of 
							     (ITIMES x 2))
			       [COND
				 [(IGREATERP 0 D)
				   (SETQ X (ADD1 X))
				   (COND
				     ((IGREATERP (UNFOLD (IPLUS D Y)
							 2)
						 1)
				       (SETQ D (IPLUS D (UNFOLD (IDIFFERENCE X Y)
								2)
						      4))
				       (SETQ Y (SUB1 Y)))
				     (T (SETQ D (IPLUS D (UNFOLD X 2)
						       1]
				 ((OR (EQ 0 D)
				      (IGREATERP X D))
				   (SETQ X (ADD1 X))
				   (SETQ D (IPLUS D (UNFOLD (IDIFFERENCE X Y)
							    2)
						  4))
				   (SETQ Y (SUB1 Y)))
				 (T (SETQ D (IPLUS (IDIFFERENCE D (UNFOLD Y 2))
						   3))
				    (SETQ Y (SUB1 Y]
			       (COND
				 [(EQ Y 0)                   (* left most and right most points are drawn specially 
							     so that they are not duplicated which leaves a hole in 
							     XOR mode.)
				   (COND
				     (USERFN (APPLY* USERFN (IPLUS CX X)
						     CY DISPLAYSTREAM)
					     (APPLY* USERFN (IDIFFERENCE CX X)
						     CY DISPLAYSTREAM))
				     (T (.WHILE.TOP.DS. DISPLAYSTREAM (\CURVEPT (IPLUS CX X)
										CY)
							(\CURVEPT (IDIFFERENCE CX X)
								  CY]
				 (T [COND
				      (USERFN (APPLY* USERFN (IPLUS CX X)
						      (IPLUS CY Y)
						      DISPLAYSTREAM)
					      (APPLY* USERFN (IDIFFERENCE CX X)
						      (IPLUS CY Y)
						      DISPLAYSTREAM)
					      (APPLY* USERFN (IPLUS CX X)
						      (IDIFFERENCE CY Y)
						      DISPLAYSTREAM)
					      (APPLY* USERFN (IDIFFERENCE CX X)
						      (IDIFFERENCE CY Y)
						      DISPLAYSTREAM))
				      (T (.WHILE.TOP.DS. DISPLAYSTREAM (\CIRCLEPTS CX CY X Y]
				    (GO LP)))
			       (MOVETO CENTERX CENTERY DISPLAYSTREAM)
			       (RETURN NIL])

(\DRAWELLIPSE.DISPLAY
  [LAMBDA (DISPLAYSTREAM CENTERX CENTERY SEMIMINORRADIUS SEMIMAJORRADIUS ORIENTATION BRUSH DASHING)
                                                             (* JonL " 7-May-84 02:45")
    (DECLARE (LOCALVARS . T))

          (* Draws an ellipse. At ORIENTATION 0, the semimajor axis is horizontal, the semiminor axis vertical.
	  Orientation is positive in the counterclockwise direction. The current location in the stream is left at the center 
	  of the ellipse.)


    (PROG ((CENTERX (FIXR CENTERX))
	   (CENTERY (FIXR CENTERY))
	   (SEMIMINORRADIUS (FIXR SEMIMINORRADIUS))
	   (SEMIMAJORRADIUS (FIXR SEMIMAJORRADIUS)))
          (COND
	    ((OR (EQ 0 SEMIMINORRADIUS)
		 (EQ 0 SEMIMAJORRADIUS))
	      (MOVETO CENTERX CENTERY DISPLAYSTREAM)
	      (RETURN)))
          (COND
	    ((ILESSP SEMIMINORRADIUS 1)
	      (\ILLEGAL.ARG SEMIMINORRADIUS))
	    ((ILESSP SEMIMAJORRADIUS 1)
	      (\ILLEGAL.ARG SEMIMAJORRADIUS))
	    ((OR (NULL ORIENTATION)
		 (EQ SEMIMINORRADIUS SEMIMAJORRADIUS))
	      (SETQ ORIENTATION 0))
	    ((NULL (NUMBERP ORIENTATION))
	      (\ILLEGAL.ARG ORIENTATION)))

          (* This function is the implementation of the algorithm given in 
	  "Algorithm for drawing ellipses or hyperbolae with a digital plotter" by Pitteway appearing in Computer Journal 10: 
	  (3) Nov 1967.0 The input parameters are used to determine the ellipse equation (1/8) Ayy+ (1/8) Bxx+ 
	  (1/4) Gxy+ (1/4) Ux+ (1/4) Vy= (1/4) K which specifies a translated version of the desired ellipse.
	  This ellipse passes through the mesh point (0,0), the initial point of the algorithm. The power of 2 factors reflect
	  an implementation convenience.)


          (GLOBALRESOURCE \BRUSHBBT
			  (PROG (DestinationBitMap LEFT RIGHTPLUS1 BOTTOM TOP BOTTOMMINUSBRUSH 
						   TOPMINUSBRUSH LEFTMINUSBRUSH DESTINATIONBASE 
						   BRUSHBASE BRUSHHEIGHT BRUSHWIDTH RASTERWIDTH 
						   BRUSHRASTERWIDTH BRUSHBM OPERATION HEIGHTMINUS1
						   (BBT \BRUSHBBT)
						   (cosOrientation (COS ORIENTATION))
						   (sinOrientation (SIN ORIENTATION))
						   (SEMIMINORRADIUSSQUARED (ITIMES SEMIMINORRADIUS 
										  SEMIMINORRADIUS))
						   (SEMIMAJORRADIUSSQUARED (ITIMES SEMIMAJORRADIUS 
										  SEMIMAJORRADIUS))
						   (x 0)
						   (y 0)
						   (x2 1)
						   x1 y1 y2 k1 k2 k3 a b d w A B G U V K CX CY 
						   yOffset CYPlusOffset CYMinusOffset NBITSRIGHTPLUS1 
						   COLORBRUSHBASE COLOR NBITS
						   (DISPLAYDATA (fetch IMAGEDATA of DISPLAYSTREAM))
						   (USERFN (AND (LITATOM BRUSH)
								BRUSH)))
                                                             (* many of these variables are used by the macro for 
							     \CURVEPT that passes them to \BBTCURVEPT and 
							     .SETUP.FOR.\BBTCURVEPT. sets them up.)
			        (COND
				  (USERFN                    (* if calling user fn, don't bother with set up and 
							     leave points in window coordinates.)
					  (SETQ CX CENTERX)
					  (SETQ CY CENTERY))
				  (T (.SETUP.FOR.\BBTCURVEPT.)
                                                             (* take into account the brush thickness.)
				     (SELECTQ NBITS
					      (1 (SETQ CX (\DSPTRANSFORMX (IDIFFERENCE CENTERX
										       (FOLDLO 
										       BRUSHWIDTH 2))
									  DISPLAYDATA)))
					      (4 (SETQ CX (\DSPTRANSFORMX (IDIFFERENCE
									    CENTERX
									    (FOLDLO (LRSH BRUSHWIDTH 
											  2)
										    2))
									  DISPLAYDATA)))
					      (8 (SETQ CX (\DSPTRANSFORMX (IDIFFERENCE
									    CENTERX
									    (FOLDLO (LRSH BRUSHWIDTH 
											  3)
										    2))
									  DISPLAYDATA)))
					      (SHOULDNT))
				     (SETQ CY (\DSPTRANSFORMY (IDIFFERENCE CENTERY (FOLDLO 
										      BRUSHHEIGHT 2))
							      DISPLAYDATA))
                                                             (* Move the window to top while interruptable, but 
							     verify that it is still there uninterruptably with 
							     drawing points)
				     (\INSURETOPWDS DISPLAYSTREAM)))
			        (SETQ A (FPLUS (FTIMES SEMIMAJORRADIUSSQUARED cosOrientation 
						       cosOrientation)
					       (FTIMES SEMIMINORRADIUSSQUARED sinOrientation 
						       sinOrientation)))
			        (SETQ B (LSH (FIXR (FPLUS (FTIMES SEMIMINORRADIUSSQUARED 
								  cosOrientation cosOrientation)
							  (FTIMES SEMIMAJORRADIUSSQUARED 
								  sinOrientation sinOrientation)))
					     3))
			        (SETQ G (FTIMES cosOrientation sinOrientation
						(LSH (IDIFFERENCE SEMIMINORRADIUSSQUARED 
								  SEMIMAJORRADIUSSQUARED)
						     1)))
			        [SETQ yOffset (FIXR (FQUOTIENT (ITIMES SEMIMINORRADIUS 
								       SEMIMAJORRADIUS)
							       (SQRT A]
			        (SETQ CYPlusOffset (IPLUS CY yOffset))
			        (SETQ CYMinusOffset (IDIFFERENCE CY yOffset))
			        (SETQ U (LSH (FIXR (FTIMES A (LSH yOffset 1)))
					     2))
			        (SETQ V (LSH (FIXR (FTIMES G yOffset))
					     2))
			        (SETQ K (LSH [FIXR (FDIFFERENCE (ITIMES SEMIMINORRADIUSSQUARED 
									SEMIMAJORRADIUSSQUARED)
								(FTIMES A (ITIMES yOffset yOffset]
					     2))
			        (SETQ A (LSH (FIXR A)
					     3))
			        (SETQ G (LSH (FIXR G)
					     2))

          (* The algorithm is incremental and iterates through the octants of a cartesian plane. The octants are labeled from 
	  1 through 8 beginning above the positive X axis and proceeding counterclockwise. Decisions in making the incremental
	  steps are determined according to the error term d which is updated according to the curvature terms a and b.
	  k1, k2, and k3 are used to correct the error and curvature terms at octant boundaries. The initial values of these 
	  terms depends on the octant in which drawing begins. The initial move steps (x1,y1) and (x2,y2) also depend on the 
	  starting octant.)


			        [COND
				  [(ILESSP (ABS U)
					   (ABS V))
				    (SETQ x1 0)
				    (COND
				      [(MINUSP V)            (* start in octant 2)
					(SETQ y1 1)
					(SETQ y2 1)
					(SETQ k1 (IMINUS A))
					(SETQ k2 (IDIFFERENCE k1 G))
					(SETQ k3 (IDIFFERENCE k2 (IPLUS B G)))
					(SETQ b (IPLUS U (RSH (IPLUS A G)
							      1)))
					(SETQ a (IMINUS (IPLUS b V)))
					(SETQ d (IPLUS b (RSH B 3)
						       (RSH V 1)
						       (IMINUS K]
				      (T                     (* start in octant 7)
					 (SETQ y1 -1)
					 (SETQ y2 -1)
					 (SETQ k1 A)
					 (SETQ k2 (IDIFFERENCE k1 G))
					 (SETQ k3 (IPLUS k2 B (IMINUS G)))
					 (SETQ b (IPLUS U (RSH (IDIFFERENCE G A)
							       1)))
					 (SETQ a (IDIFFERENCE V b))
					 (SETQ d (IPLUS b K (IMINUS (IPLUS (RSH V 1)
									   (RSH B 3]
				  (T (SETQ x1 1)
				     (SETQ y1 0)
				     (COND
				       [(MINUSP V)           (* start in octant 1)
					 (SETQ y2 1)
					 (SETQ k1 B)
					 (SETQ k2 (IPLUS k1 G))
					 (SETQ k3 (IPLUS k2 A G))
					 [SETQ b (IMINUS (IPLUS V (RSH (IPLUS B G)
								       1]
					 (SETQ a (IDIFFERENCE U b))
					 (SETQ d (IPLUS b K (IMINUS (IPLUS (RSH A 3)
									   (RSH U 1]
				       (T                    (* start in octant 8)
					  (SETQ y2 -1)
					  (SETQ k1 (IMINUS B))
					  (SETQ k2 (IPLUS k1 G))
					  (SETQ k3 (IPLUS k2 G (IMINUS A)))
					  (SETQ b (IPLUS V (RSH (IDIFFERENCE B G)
								1)))
					  (SETQ a (IDIFFERENCE U b))
					  (SETQ d (IPLUS b (RSH A 3)
							 (IMINUS (IPLUS K (RSH U 1]

          (* The ellipse equation describes an ellipse of the desired size and ORIENTATION centered at 
	  (0,0) and then dropped yOffset mesh points so that it will pass through (0,0). Thus, the intended starting point is 
	  (CX, CY+yOffset) where (CX, CY) is the center of the desired ellipse. Drawing is accomplished with point relative 
	  steps. In each octant, the error term d is used to choose between move 1 (an axis move) and move 2 
	  (a diagonal move).)


			    MOVE[COND
				  ((MINUSP d)                (* move 1)
				    (SETQ x (IPLUS x x1))
				    (SETQ y (IPLUS y y1))
				    (SETQ b (IDIFFERENCE b k1))
				    (SETQ a (IPLUS a k2))
				    (SETQ d (IPLUS b d)))
				  (T                         (* move 2)
				     (SETQ x (IPLUS x x2))
				     (SETQ y (IPLUS y y2))
				     (SETQ b (IDIFFERENCE b k2))
				     (SETQ a (IPLUS a k3))
				     (SETQ d (IDIFFERENCE d a]
			        (COND
				  ((MINUSP x)
				    (MOVETO CENTERX CENTERY DISPLAYSTREAM)
				    (RETURN NIL)))
			        [COND
				  (USERFN (APPLY* USERFN (IPLUS CX x)
						  (IPLUS CYPlusOffset y)
						  DISPLAYSTREAM)
					  (APPLY* USERFN (IDIFFERENCE CX x)
						  (IDIFFERENCE CYMinusOffset y)
						  DISPLAYSTREAM))
				  (T (.WHILE.TOP.DS. DISPLAYSTREAM (\CURVEPT (IPLUS CX x)
									     (IPLUS CYPlusOffset y))
						     (\CURVEPT (IDIFFERENCE CX x)
							       (IDIFFERENCE CYMinusOffset y]
			        (AND (MINUSP b)
				     (GO SQUARE))
			    DIAGONAL
			        (OR (MINUSP a)
				    (GO MOVE))               (* diagonal octant change)
			        (SETQ x1 (IDIFFERENCE x2 x1))
			        (SETQ y1 (IDIFFERENCE y2 y1))
			        (SETQ w (IDIFFERENCE (LSH k2 1)
						     k3))
			        (SETQ k1 (IDIFFERENCE w k1))
			        (SETQ k2 (IDIFFERENCE k2 k3))
			        (SETQ k3 (IMINUS k3))
			        [SETQ b (IPLUS b a (IMINUS (RSH (ADD1 k2)
								1]
			        [SETQ d (IPLUS b (RSH (IPLUS k3 4)
						      3)
					       (IMINUS d)
					       (IMINUS (RSH (ADD1 a)
							    1]
			        (SETQ a (IDIFFERENCE (RSH (ADD1 w)
							  1)
						     a))
			        (OR (MINUSP b)
				    (GO MOVE))
			    SQUARE                           (* square octant change)
			        [COND
				  ((EQ 0 x1)
				    (SETQ x2 (IMINUS x2)))
				  (T (SETQ y2 (IMINUS y2]
			        (SETQ w (IDIFFERENCE k2 k1))
			        (SETQ k1 (IMINUS k1))
			        (SETQ k2 (IPLUS w k1))
			        (SETQ k3 (IDIFFERENCE (LSH w 2)
						      k3))
			        (SETQ b (IDIFFERENCE (IMINUS b)
						     w))
			        (SETQ d (IDIFFERENCE (IDIFFERENCE b a)
						     d))
			        (SETQ a (IDIFFERENCE (IDIFFERENCE a w)
						     (LSH b 1)))
			        (GO DIAGONAL])

(\LINEWITHBRUSH
  [LAMBDA (X1 Y1 X2 Y2 BRUSH DASHLST DISPLAYSTREAM BBT)      (* JonL " 7-May-84 02:55")
                                                             (* draws a line with a brush on a guaranteed 
							     display-stream DISPLAYSTREAM)
    (DECLARE (LOCALVARS . T))
    (PROG (DestinationBitMap LEFT RIGHTPLUS1 TOP BOTTOM BRUSHWIDTH BRUSHHEIGHT LEFTMINUSBRUSH 
			     BOTTOMMINUSBRUSH TOPMINUSBRUSH BRUSHBM DESTINATIONBASE BRUSHBASE 
			     RASTERWIDTH BRUSHRASTERWIDTH NBITSRIGHTPLUS1 OPERATION HEIGHTMINUS1 
			     COLOR COLORBRUSHBASE NBITS HALFBRUSHWIDTH HALFBRUSHHEIGHT DX DY YINC CDL
			     (DASHON T)
			     (DASHTAIL DASHLST)
			     (DASHCNT (CAR DASHLST))
			     (DISPLAYDATA (fetch IMAGEDATA of DISPLAYSTREAM))
			     (USERFN (AND (LITATOM BRUSH)
					  BRUSH))
			     (DISPLAYDATA (fetch IMAGEDATA of DISPLAYSTREAM)))
                                                             (* many of these variables are used by the macro for 
							     \CURVEPT that passes them to \BBTCURVEPT and 
							     .SETUP.FOR.\BBTCURVEPT. sets them up.)
                                                             (* move the display stream position before the 
							     coordinates are clobbered.)
          (COND
	    ((NOT USERFN)
	      (.SETUP.FOR.\BBTCURVEPT.)
	      (SELECTQ NBITS
		       (1 (SETQ X1 (\DSPTRANSFORMX (IDIFFERENCE X1 (SETQ HALFBRUSHWIDTH
								  (FOLDLO BRUSHWIDTH 2)))
						   DISPLAYDATA)))
		       (4 (SETQ X1 (\DSPTRANSFORMX (IDIFFERENCE X1 (SETQ HALFBRUSHWIDTH
								  (FOLDLO (LRSH BRUSHWIDTH 2)
									  2)))
						   DISPLAYDATA)))
		       (8 (SETQ X1 (\DSPTRANSFORMX (IDIFFERENCE X1 (SETQ HALFBRUSHWIDTH
								  (FOLDLO (LRSH BRUSHWIDTH 3)
									  2)))
						   DISPLAYDATA)))
		       (SHOULDNT))
	      (SETQ X2 (\DSPTRANSFORMX (IDIFFERENCE X2 HALFBRUSHWIDTH)
				       DISPLAYDATA))
	      (SETQ Y1 (\DSPTRANSFORMY (IDIFFERENCE Y1 (SETQ HALFBRUSHHEIGHT (FOLDLO BRUSHHEIGHT 2)))
				       DISPLAYDATA))         (* take into account the brush thickness.)
	      (SETQ Y2 (\DSPTRANSFORMY (IDIFFERENCE Y2 HALFBRUSHHEIGHT)
				       DISPLAYDATA))         (* Move the window to top while interruptable, but 
							     verify that it is still there uninterruptably with 
							     drawing points)
	      (\INSURETOPWDS DISPLAYSTREAM)))                (* arrange things so that dx is positive.)
          (COND
	    ((IGREATERP X1 X2)                               (* switch points)
	      (swap X1 X2)
	      (swap Y1 Y2)))
          (SETQ DX (ADD1 (IDIFFERENCE X2 X1)))
          [SETQ DY (ADD1 (COND
			   ((IGREATERP Y2 Y1)
			     (SETQ YINC 1)
			     (IDIFFERENCE Y2 Y1))
			   (T (SETQ YINC -1)
			      (IDIFFERENCE Y1 Y2]
          [SETQ CDL (HALF (COND
			    ((IGREATERP DX DY)               (* set up the bucket so that the ends will be the 
							     same.)
			      (IREMAINDER DX DY))
			    (T (IREMAINDER DY DX]
          [COND
	    [USERFN                                          (* if user function is being called, don't bother 
							     bringing window to top uninterruptably.)
		    (COND
		      ((IGEQ DX DY)                          (* X is the fastest mover.)
			(until (IGREATERP X1 X2)
			   do                                (* main loop)
			      (COND
				(DASHON (APPLY* USERFN X1 Y1 DISPLAYSTREAM)))
			      [COND
				(DASHTAIL                    (* do dashing.)
					  (COND
					    ((EQ 0 (SETQ DASHCNT (SUB1 DASHCNT)))
					      (SETQ DASHON (NOT DASHON))
					      (SETQ DASHTAIL (OR (LISTP (CDR DASHTAIL))
								 DASHLST))
					      (SETQ DASHCNT (CAR DASHTAIL]
			      [COND
				((NOT (IGREATERP DX (add CDL DY)))
				  (add Y1 YINC)
				  (COND
				    ((COND
					((EQ YINC -1)
					  (ILESSP Y1 Y2))
					((IGREATERP Y1 Y2)))
				      (RETURN)))
				  (SETQ CDL (IDIFFERENCE CDL DX]
			      (add X1 1)))
		      (T                                     (* Y is the fastest mover.)
			 (until (COND
				  ((EQ YINC -1)
				    (ILESSP Y1 Y2))
				  ((IGREATERP Y1 Y2)))
			    do                               (* main loop)
			       (COND
				 (DASHON (APPLY* USERFN X1 Y1 DISPLAYSTREAM)))
			       [COND
				 (DASHTAIL                   (* do dashing.)
					   (COND
					     ((EQ 0 (SETQ DASHCNT (SUB1 DASHCNT)))
					       (SETQ DASHON (NOT DASHON))
					       (SETQ DASHTAIL (OR (LISTP (CDR DASHTAIL))
								  DASHLST))
					       (SETQ DASHCNT (CAR DASHTAIL]
			       [COND
				 ([NOT (IGREATERP DY (SETQ CDL (IPLUS CDL DX]
				   (COND
				     ((IGREATERP (SETQ X1 (ADD1 X1))
						 X2)
				       (RETURN)))
				   (SETQ CDL (IDIFFERENCE CDL DY]
			       (add Y1 YINC]
	    (T                                               (* when we put the points down make it uninterruptable)
	       (.WHILE.TOP.DS. DISPLAYSTREAM
			       (COND
				 [(IGEQ DX DY)               (* X is the fastest mover.)
				   (until (IGREATERP X1 X2)
				      do                     (* main loop)
					 (COND
					   (DASHON (\CURVEPT X1 Y1)))
					 [COND
					   (DASHTAIL         (* do dashing.)
						     (COND
						       ((EQ 0 (SETQ DASHCNT (SUB1 DASHCNT)))
							 (SETQ DASHON (NOT DASHON))
							 (SETQ DASHTAIL (OR (LISTP (CDR DASHTAIL))
									    DASHLST))
							 (SETQ DASHCNT (CAR DASHTAIL]
					 [COND
					   ([NOT (IGREATERP DX (SETQ CDL (IPLUS CDL DY]
					     (SETQ Y1 (IPLUS Y1 YINC))
					     (COND
					       ((COND
						   ((EQ YINC -1)
						     (ILESSP Y1 Y2))
						   ((IGREATERP Y1 Y2)))
						 (RETURN)))
					     (SETQ CDL (IDIFFERENCE CDL DX]
					 (SETQ X1 (ADD1 X1]
				 (T                          (* Y is the fastest mover.)
				    (until (COND
					     ((EQ YINC -1)
					       (ILESSP Y1 Y2))
					     ((IGREATERP Y1 Y2)))
				       do                    (* main loop)
					  (COND
					    (DASHON (\CURVEPT X1 Y1)))
					  [COND
					    (DASHTAIL        (* do dashing.)
						      (COND
							((EQ 0 (SETQ DASHCNT (SUB1 DASHCNT)))
							  (SETQ DASHON (NOT DASHON))
							  (SETQ DASHTAIL (OR (LISTP (CDR DASHTAIL))
									     DASHLST))
							  (SETQ DASHCNT (CAR DASHTAIL]
					  [COND
					    ([NOT (IGREATERP DY (SETQ CDL (IPLUS CDL DX]
					      (COND
						((IGREATERP (SETQ X1 (ADD1 X1))
							    X2)
						  (RETURN)))
					      (SETQ CDL (IDIFFERENCE CDL DY]
					  (SETQ Y1 (IPLUS Y1 YINC]
          (RETURN NIL])

(\CURVE2
  [LAMBDA (SPLINE BRUSH DASHLST BBT DISPLAYSTREAM)           (* jds "18-Aug-84 14:32")
    (DECLARE (SPECVARS . T))

          (* DISPLAYSTREAM is guaranteed to be a display-stream. Should declare most of these variables local but currently 
	  have the \CURVE function between here and \CURVEBBT so can't)


    (PROG (BRUSHBM DestinationBitMap OPERATION BRUSHWIDTH BRUSHHEIGHT BRUSHBASE BRUSHRASTERWIDTH LEFT 
		   RIGHTPLUS1 TOP BOTTOM DESTINATIONBASE LEFTMINUSBRUSH BOTTOMMINUSBRUSH 
		   TOPMINUSBRUSH RASTERWIDTH NBITSRIGHTPLUS1 HEIGHTMINUS1 COLOR COLORBRUSHBASE NBITS 
		   \CURX \CURY \OLDX \OLDY \OLDERX \OLDERY LKNOT (DASHON T)
		   (DASHTAIL DASHLST)
		   (DASHCNT (CAR DASHLST))
		   NPOINTS NSEGS POINTSPERSEG DX D2X D3X DY D2Y D3Y D1 D2 D3 X0 Y0 X1 Y1 DX DDX DDDX 
		   DY DDY DDDY (XPOLY (create POLYNOMIAL))
		   (X/PRIME/POLY (create POLYNOMIAL))
		   (YPOLY (create POLYNOMIAL))
		   (Y/PRIME/POLY (create POLYNOMIAL))
		   (DISPLAYDATA (fetch IMAGEDATA of DISPLAYSTREAM))
		   (USERFN (AND (LITATOM BRUSH)
				BRUSH)))                     (* many of these variables are used by the macro for 
							     \CURVEPT that passes them to \BBTCURVEPT and 
							     .SETUP.FOR.\BBTCURVEPT. sets them up.)
          (COND
	    ((NOT USERFN)                                    (* if calling user fn, don't bother with set up and 
							     leave points in window coordinates.)
	      (.SETUP.FOR.\BBTCURVEPT.)                      (* Do it interruptably here to get set up, then 
							     uninterruptably when drawing points)
	      (\INSURETOPWDS DISPLAYSTREAM)))
          (\CURVESTART (ELT (fetch (SPLINE SPLINEX) of SPLINE)
			    1)
		       (ELT (fetch (SPLINE SPLINEY) of SPLINE)
			    1))
          [bind PERSEG for KNOT from 1 to (SUB1 (fetch #KNOTS of SPLINE))
	     do (SETQ X0 (ELT (fetch (SPLINE SPLINEX) of SPLINE)
			      KNOT))
		(SETQ Y0 (ELT (fetch (SPLINE SPLINEY) of SPLINE)
			      KNOT))
		(SETQ X1 (ELT (fetch (SPLINE SPLINEX) of SPLINE)
			      (ADD1 KNOT)))
		(SETQ Y1 (ELT (fetch (SPLINE SPLINEY) of SPLINE)
			      (ADD1 KNOT)))
		(SETQ DX (ELT (fetch (SPLINE SPLINEDX) of SPLINE)
			      KNOT))
		(SETQ DY (ELT (fetch (SPLINE SPLINEDY) of SPLINE)
			      KNOT))
		(SETQ DDX (ELT (fetch SPLINEDDX of SPLINE)
			       KNOT))
		(SETQ DDY (ELT (fetch SPLINEDDY of SPLINE)
			       KNOT))
		(SETQ DDDX (ELT (fetch SPLINEDDDX of SPLINE)
				KNOT))
		(SETQ DDDY (ELT (fetch SPLINEDDDY of SPLINE)
				KNOT))
		(SETQ NPOINTS (FOLDLO (ITIMES (IMAX (IABS (IDIFFERENCE X1 X0))
						    (IABS (IDIFFERENCE Y1 Y0)))
					      3)
				      2))
		[COND
		  ((ILEQ NPOINTS 64)
		    (SETQ NSEGS 1)
		    (SETQ POINTSPERSEG NPOINTS))
		  (T (SETQ NSEGS (FOLDLO NPOINTS 64))
		     (SETQ POINTSPERSEG 64)
		     (SETQ NPOINTS (UNFOLD NSEGS 64]
		(SETQ D1 (FQUOTIENT 1.0 NPOINTS))
		(SETQ D2 (FTIMES D1 D1))
		(SETQ D3 (FTIMES D2 D1))
		(SETQ D3X (FTIMES D3 DDDX))
		(SETQ D3Y (FTIMES D3 DDDY))
		(COND
		  [(EQ NSEGS 1)
		    [SETQ DX (FPLUS (FTIMES D1 DX)
				    (FTIMES DDX D2 .5)
				    (FTIMES DDDX D3 (CONSTANT (FQUOTIENT 1.0 6.0]
		    (SETQ D2X (FPLUS (FTIMES D2 DDX)
				     (FTIMES D3 DDDX)))
		    [SETQ DY (FPLUS (FTIMES D1 DY)
				    (FTIMES D2 DDY .5)
				    (FTIMES D3 DDDY (CONSTANT (FQUOTIENT 1.0 6.0]
		    (SETQ D2Y (FPLUS (FTIMES D2 DDY)
				     (FTIMES D3 DDDY)))
		    (COND
		      (USERFN (\CURVE X0 Y0 X1 Y1 DX DY D2X D2Y D3X D3Y NPOINTS BRUSHBM DISPLAYDATA 
				      BBT NIL USERFN DISPLAYSTREAM))
		      (T (.WHILE.TOP.DS. DISPLAYSTREAM
					 (\CURVE X0 Y0 X1 Y1 DX DY D2X D2Y D3X D3Y NPOINTS BRUSHBM 
						 DISPLAYDATA BBT NIL NIL DISPLAYSTREAM]
		  (T (SETQ PERSEG (FQUOTIENT 1.0 NSEGS))
		     (LOADPOLY XPOLY X/PRIME/POLY DDDX DDX DX X0)
		     (LOADPOLY YPOLY Y/PRIME/POLY DDDY DDY DY Y0)
		     (bind (TT ← 0.0)
			   (DDDX/PER/SEG ←(FTIMES DDDX PERSEG))
			   (DDDY/PER/SEG ←(FTIMES DDDY PERSEG))
			   [D3XFACTOR ←(FTIMES D3 DDDX (CONSTANT (FQUOTIENT 1.0 6.0]
			   [D3YFACTOR ←(FTIMES D3 DDDY (CONSTANT (FQUOTIENT 1.0 6.0] for I
			from 0 to (SUB1 NSEGS)
			do (SETQ TT (FPLUS TT PERSEG))
			   (SETQ X1 (EVALPOLY XPOLY TT 3))
			   (SETQ Y1 (EVALPOLY YPOLY TT 3))
			   (SETQ DX (FPLUS (FTIMES D1 DX)
					   (FTIMES D2 DDX .5)
					   D3XFACTOR))
			   (SETQ D2X (FPLUS (FTIMES D2 DDX)
					    (FTIMES D3 DDDX)))
			   (SETQ DY (FPLUS (FTIMES D1 DY)
					   (FTIMES D2 DDY .5)
					   D3YFACTOR))
			   (SETQ D2Y (FPLUS (FTIMES D2 DDY)
					    (FTIMES D3 DDDY)))
			   [COND
			     (USERFN (\CURVE X0 Y0 X1 Y1 DX DY D2X D2Y D3X D3Y 64 BRUSHBM DISPLAYDATA 
					     BBT NIL USERFN DISPLAYSTREAM))
			     (T (.WHILE.TOP.DS. DISPLAYSTREAM
						(\CURVE X0 Y0 X1 Y1 DX DY D2X D2Y D3X D3Y 64 BRUSHBM 
							DISPLAYDATA BBT NIL NIL DISPLAYSTREAM]
			   (SETQ X0 X1)
			   (SETQ Y0 Y1)
			   (SETQ DDX (FPLUS DDX DDDX/PER/SEG))
			   (SETQ DDY (FPLUS DDY DDDY/PER/SEG))
			   (SETQ DX (EVALPOLY X/PRIME/POLY TT 2))
			   (SETQ DY (EVALPOLY Y/PRIME/POLY TT 2]
          (COND
	    (USERFN (\CURVE 0 0 0 0 0 0 0 0 0 0 0 BRUSHBM DISPLAYDATA BBT T USERFN DISPLAYSTREAM))
	    (T (.WHILE.TOP.DS. DISPLAYSTREAM
			       (\CURVE 0 0 0 0 0 0 0 0 0 0 0 BRUSHBM DISPLAYDATA BBT T NIL 
				       DISPLAYSTREAM])

(\BBTCURVEPT
  [LAMBDA (X Y BBT LEFT BRUSHWIDTH LEFTMINUSBRUSH RIGHTPLUS1 NBITSRIGHTPLUS1 TOPMINUSBRUSH 
	     DestinationBitMap BRUSHHEIGHT BOTTOMMINUSBRUSH TOP BRUSHBASE DESTINATIONBASE RASTERWIDTH 
	     BRUSHRASTERWIDTH COLORBRUSHBASE NBITS DISPLAYDATA)
                                                             (* rrb "30-Oct-84 10:37")

          (* Called by \CURVEPT macro. Draws a brush point by bitblting BRUSHBM to point X,Y in DestinationBitMap.
	  BBT is a BitBlt table where everything is already set except the source and destination addresses, width and height.
	  In other words, only the easy stuff)

                                                             (* set the width fields of the bbt)
    [PROG (CLIPPEDTOP STY)
          [COND
	    [(ILEQ Y TOPMINUSBRUSH)                          (* the top part of the brush is visible)
	      (SETQ CLIPPEDTOP (IPLUS Y BRUSHHEIGHT))
	      (replace PBTSOURCE of BBT with BRUSHBASE)
	      (replace PBTHEIGHT of BBT with (IMIN BRUSHHEIGHT (IDIFFERENCE Y BOTTOMMINUSBRUSH]
	    (T                                               (* only the bottom is visible)
	       (SETQ CLIPPEDTOP TOP)
	       [replace PBTSOURCE of BBT with (\ADDBASE BRUSHBASE (ITIMES BRUSHRASTERWIDTH
									  (SETQ STY (IDIFFERENCE
									      Y TOPMINUSBRUSH]
	       (replace PBTHEIGHT of BBT with (IDIFFERENCE (IMIN BRUSHHEIGHT (IDIFFERENCE Y 
										 BOTTOMMINUSBRUSH))
							   STY]
          (replace PBTDEST of BBT with (\ADDBASE DESTINATIONBASE (ITIMES RASTERWIDTH
									 (\SFInvert DestinationBitMap 
										    CLIPPEDTOP]
    [COND
      (COLORBRUSHBASE [COND
			[(ILESSP X LEFT)                     (* only the right part of the brush is visible)
                                                             (* FOR NOW BRUTE FORCE WITH NBITS CHECK)
			  [replace PBTDESTBIT of BBT with (COND
							    ((EQ NBITS 4)
							      (LLSH LEFT 2))
							    (T (LLSH LEFT 3]
			  (replace PBTSOURCEBIT of BBT
			     with (PROG ((COLORLEFT
					   (LLSH [IDIFFERENCE BRUSHWIDTH
							      (replace PBTWIDTH of BBT
								 with (COND
									((EQ NBITS 4)
									  (LLSH (IDIFFERENCE X 
										   LEFTMINUSBRUSH)
										2))
									(T (LLSH (IDIFFERENCE X 
										   LEFTMINUSBRUSH)
										 3]
						 2)))
				        (RETURN (COND
						  ((EQ NBITS 4)
						    COLORLEFT)
						  (T (LLSH COLORLEFT 1]
			(T                                   (* left edge is visible)
			   [replace PBTDESTBIT of BBT with (SETQ X (COND
							       ((EQ NBITS 4)
								 (LLSH X 2))
							       (T (LLSH X 3]
			   (replace PBTSOURCEBIT of BBT with 0)
                                                             (* set width to the amount that is visible)
			   (replace PBTWIDTH of BBT with (IMIN BRUSHWIDTH (IDIFFERENCE 
										  NBITSRIGHTPLUS1 X]
                                                             (* if color brush is used, the ground must be cleared 
							     before the brush is put in.)
		      (\SETPBTFUNCTION BBT (ffetch DDSOURCETYPE of (fetch IMAGEDATA of DISPLAYDATA))
				       (QUOTE ERASE))
		      (\PILOTBITBLT BBT 0)                   (* reset the source to point to the color bitmap.)
		      [COND
			((ILEQ Y TOPMINUSBRUSH)              (* the top part of the brush is visible)
			  (replace PBTSOURCE of BBT with COLORBRUSHBASE))
			(T                                   (* only the bottom is visible)
			   (replace PBTSOURCE of BBT with (\ADDBASE COLORBRUSHBASE
								    (ITIMES BRUSHRASTERWIDTH
									    (IDIFFERENCE Y 
										    TOPMINUSBRUSH]
		      (\SETPBTFUNCTION BBT (ffetch DDSOURCETYPE of (fetch IMAGEDATA of DISPLAYDATA))
				       (QUOTE PAINT)))
      (T (COND
	   [(ILESSP X LEFT)                                  (* only the right part of the brush is visible)
	     (replace PBTDESTBIT of BBT with LEFT)
	     (replace PBTSOURCEBIT of BBT with (IDIFFERENCE BRUSHWIDTH (replace PBTWIDTH
									  of BBT
									  with (IDIFFERENCE X 
										   LEFTMINUSBRUSH]
	   (T                                                (* left edge is visible)
	      (replace PBTDESTBIT of BBT with X)
	      (replace PBTSOURCEBIT of BBT with 0)           (* set width to the amount that is visible)
	      (replace PBTWIDTH of BBT with (IMIN BRUSHWIDTH (IDIFFERENCE RIGHTPLUS1 X]
    (\PILOTBITBLT BBT 0])
)
(PUTPROPS DRAWPATCH COPYRIGHT ("Xerox Corporation" 1984))
(DECLARE: DONTCOPY
  (FILEMAP (NIL (498 35232 (\DRAWCIRCLE.DISPLAY 508 . 5828) (\DRAWELLIPSE.DISPLAY 5830 . 17162) (
\LINEWITHBRUSH 17164 . 24381) (\CURVE2 24383 . 30326) (\BBTCURVEPT 30328 . 35230)))))
STOP