;;-*-mode:common-lisp ;  Package:DASH ; fonts: medfnt, medfnb ; base:10.-*-
;
;===============================================================================
;
;   Written by Nichael Lynn Cramer
;
;===============================================================================
;
;   This data and information is proprietary to, and a valuable trade secret of
;   Texas Instruments, Incorporated, a Delaware corporation.  It is given in
;   confidence by Texas Instruments, and may not be used as the basis of
;   manufacture, or be reproduced or copied, or be distributed to any other
;   party, in whole or in part, without the prior written consent of Texas
;   Instruments.
;
;===============================================================================
;
;   (c) Unpublished Copyright 1984 by Texas Instruments.  All rights reserved.
;
;===============================================================================
;
;1;*****************************************************************
;1; This file contains flavors and methods for the 'background' features*
;1; of the Dial.  These include tick-marks and labels and are features*
;1; of the Dial's face that do not change as the value of the Dial changes.*
;1;*
;1; This file also contains those features that has to do with information*
;1; concerning the basic shape of a Dial.*
;1;******************************************************NLC18SEP84*


;1;*****************************************************************
;1;*
;1; TICKS allow tick-marks to be drawn on the Dial face at specific*
;1; locations associated with values.  The user who designs a new*
;1; complete Dial flavor should that uses this mixin should build a*
;1; method *:draw-one-tick1 which is responsible for drawing a single tick*
;1; appropriate to the needs of that Dial.  As an example, see*
;1; *dash:basic-round-dial-mixin1.  The *:draw-one-tick1 method should accept*
;1; three arguements: the value at which the tick-mark should be drawn,*
;1; the length of the tick-mark and the width of the tick-mark.*
;1;*
;1; The user can specify a function*, TICKS-CALCULATION-FUNCTION,1 which can be*
;; 1invoked by calling the method :*calculate-ticks-spacing1.  This function*
;; 1should accept one argument (the current list *TICKS1) and return a new *
;; 1value for this list.*  1The function is funcall'ed inside the instance and*
;1; so has access to all the instance-variables.*
;1; *
;1;******************************************************NLC15APR84*
(defflavor ticks-mixin
	((TICKS t)     ;1;LIST OF TICK-MARKS*
	 (TICK-BASE-DISTANCE nil)
	 (DEFAULT-TICK-SPACING 1.)
	 (DEFAULT-TICK-WIDTH 2.)
	 (DEFAULT-TICK-LENGTH 5.)
	 (TICKS-CALCULATION-FUNCTION 'dash:default-ticks-calculation-function)
	                    ;1;USER-DEFINABLE FUNCTION WHICH CAN BE USED TO*
	                    ;1;CALULATE THE TICKS AND THEIR POSITIONS*

	 )
	   ()
  :initable-instance-variables
  :gettable-instance-variables
  :settable-instance-variables
  (:required-methods :draw-one-tick)
  (:documentation "Flavor to draw tick marks on a Dial.")
  )

(defmethod (ticks-mixin :AFTER :INIT) (&rest ignore)
 (send self ':re-start-ticks)
 )

(defmethod (ticks-mixin :re-start-ticks) ()
  "2Called by :init.  Default*-2initializes *TICKS2.*"
  (if (equal TICKS 't)
      (send self ':calculate-tick-spacing))
  )


(defmethod (ticks-mixin :draw-ticks)
	   (WINDOW LO-VALUE HI-VALUE &optional (AALU tv:alu-ior))
  "2If *TICKS2 is *nil2, no tick-marks.  If *t2, draw ticks with default value-spacing, width and length.  If *TICKS2 is a list, draw all the tick-marks in it.  The elements of the list can be just the values of the tick-marks, in which case they are 1drawn at that value** 2with default width and length.*"
  (when TICK-BASE-DISTANCE
    (cond ((listp TICKS)
	   (dolist (ONE-TICK TICKS)
	     (if (listp ONE-TICK)	       
		 (send self :draw-one-tick WINDOW (first ONE-TICK)
			       (or (second ONE-TICK)
				 DEFAULT-TICK-LENGTH)
			       (or (third ONE-TICK)
				   DEFAULT-TICK-WIDTH)
			       AALU)
	       (send self :draw-one-tick WINDOW ONE-TICK
			     DEFAULT-TICK-LENGTH
			     DEFAULT-TICK-WIDTH
			     AALU))))
	  (TICKS
	   (loop for ILOOP from LO-VALUE to HI-VALUE by DEFAULT-TICK-SPACING
		 do (send self :draw-one-tick WINDOW (floor ILOOP)
				  DEFAULT-TICK-LENGTH
				  DEFAULT-TICK-WIDTH
				  AALU))))
    )
  )

(defmethod (ticks-mixin :calculate-tick-spacing) ()
  "2Funcalls *TICKS-CALCULATION-FUNCTION 2in order to set *TICKS2.*"
    (setq TICKS
	  (send self ':funcall-inside-yourself
			TICKS-CALCULATION-FUNCTION TICKS))
    )

(defmethod (ticks-mixin :make-tick-list)
	   (NEWVALUE NEWLENGTH NEWWIDTH &optional OLDLIST)
  "2Can be used to add a new tick-mark or create a new *TICKS2 list.*"
  (let ((NEW-TICK (if (not (or NEWLENGTH NEWWIDTH))
		      NEWVALUE
		      (list NEWVALUE NEWLENGTH NEWWIDTH))))
    (setq TICKS (if OLDLIST
		    (replace OLDLIST NEW-TICK TICKS)
		    (if (listp TICKS)
			(cons NEW-TICK TICKS)
			(list NEW-TICK ))))
    )
  )

(defun dash:default-ticks-calculation-function (TICK-LIST)
  "2For use with round Dials.  If TICK-LIST is *nil2, return *nil2.  1If non-nil, return* a list of tick-marks with default value-spacing, width and length.*"
  (declare (special MIN-HAND-VALUE MAX-HAND-VALUE DEFAULT-TICK-SPACING
		    DEFAULT-TICK-WIDTH DEFAULT-TICK-LENGTH))
    (when TICK-LIST
      (setq  TICK-LIST
	     (loop for TICK-VALUE from MIN-HAND-VALUE to MAX-HAND-VALUE by DEFAULT-TICK-SPACING
		   collect (list TICK-VALUE
				    DEFAULT-TICK-LENGTH DEFAULT-TICK-WIDTH)))
      )
    )

;1;*****************************************************************
;1; *
;1; LABELS are similar to captions (see *basic-dial1 for more information)*
;1; except that labels are associated with a location on the DIAL which*
;1; corresponds to some value.*
;1;*
;1; The user can specify a function*, LABEL-CALCULATION-FUNCTION,1 which can be*
;; 1invoked by calling the method :*calculate-label-spacing1.  This function*
;; 1should accept one argument (the current list *LABELS1) and return a new *
;; 1value for this list.*  1The function is funcall'ed inside the instance and*
;1; so has access to all the instance-variables.*
;1;*
;1; The format of the list for a label is:*
;1;  ( <label-head>  <X-offset>  <Y-offset>  <font> )*
;1; where:*
;1;  label-head :either 1] a number, which is the value with which the*
;1;                        label is asscociated.  This value will printed*
;1;                        as the label.*
;1;              or     2] a list of the form:*
;1;                            ( <label-string>  <label-value> )*
;1;                        where label-string will be printed in a location*
;1;                        associated with label value.*
;1;  X-offset   The label is drawn at these offsets from the position *
;1;  Y-offset           associated with this label value.*
;1;  font       The font the label is printed with.*
;1;*
;1; The designer of a new flavor that uses LABELS is responsible for *
;1; creating a * :convert-dial-value-to-window-coordinates1 method.  This method*
;1; should accept a single arguement [some value on the Dial] and return*
;1; two values, the X and Y co-ordinates [relative to the Dial center]*
;1; of some point associated with that value.  For example, the method in*
;1; circular Dial flavor returns a point on the *MAJOR-RADIUS1 at an angle*
;1; corresponding to the value.*
;1; *
;1;******************************************************NLC10APR84*
(defflavor labels-mixin
	((LABELS  t)        ;1;IF *nil1, NO LABELS.*
	                    ;1;IF *t1, ALLOW CALCULATION OF LABELS.*
                            ;1;OTHERWISE A LIST OF LABEL SPECIFICATION.*
	 (LABELS-BASE-DISTANCE nil)
	 (LABELS-SPACING 1.);1;DEFAULT LABEL SPACING USED IN LABEL CALUCULATION*
	 (DEFAULT-LABELS-FONT fonts:cptfont) ;1;DEFAULT LABEL FONT.*
	 (LABEL-CALCULATION-FUNCTION 'dash:default-label-calculation-function)
	                    ;1;USER-DEFINABLE FUNCTION WHICH CAN BE USED TO*
	                    ;1;CALULATE THE LABELS AND THEIR POSITIONS*
	 )
	   ()
  (:documentation "Flavor for adding value located labels for the DIAL.")
  :initable-instance-variables
  :gettable-instance-variables
  :settable-instance-variables
  (:required-methods :convert-dial-value-to-window-coordinates)
  )

(defmethod (labels-mixin :AFTER :INIT) (&rest ignore)
 (send self ':re-start-labels)
 )

(defmethod (labels-mixin :re-start-labels) ()
  "2Called by :init.  If *LABELS2 is *t2, calculate the labels.*"
  (if (equal LABELS 't)
      (send self ':calculate-label-spacing))
  )
 
(defmethod (labels-mixin :calculate-label-spacing) ()
  "2Calls *LABEL-CALCULATION-FUNCTION2 inside DIAL instance to get the list *LABELS2.*"
  (setq LABELS
	(send self :funcall-inside-yourself LABEL-CALCULATION-FUNCTION LABELS))
  )

(defun dash:default-label-calculation-function (OLD-LABELS)
  "2Used to calculate label locations.  Intended for round dials.  Function tries to center label just outside the place on *LABELS-BASE-DISTANCE 2corresponding to that the label's value.  If *OLD-LABELS2 is *nil2, no labels.  If *non-nil2, make centered labels,  spaced according to *LABELS-SPACING2 from *MIN-HAND-VALUE2 to* MAX-HAND-VALUE2.*"
  (declare (special LABELS-BASE-DISTANCE MIN-HAND-VALUE SELF
		    MAX-HAND-VALUE LABELS-SPACING DEFAULT-LABELS-FONT
		    LABELS))
  (when OLD-LABELS
    (setq LABELS
	  (loop for LABEL-VALUE from MIN-HAND-VALUE to MAX-HAND-VALUE by LABELS-SPACING
		collect (multiple-value-bind (RIMX RIMY)
			    (send self :convert-dial-value-to-window-coordinates
					  LABEL-VALUE LABELS-BASE-DISTANCE)
			  (multiple-value-bind (STRX STRY)
			      (send self :convert-dial-value-to-window-coordinates
					    LABEL-VALUE (+ 15. LABELS-BASE-DISTANCE))
			    (list LABEL-VALUE
				  (- STRX RIMX
				     (* (string-length (format nil "~D" LABEL-VALUE))
					(round (/ (tv:font-char-width
						    DEFAULT-LABELS-FONT)
						  2.0))))
				  (- STRY RIMY (round (/ (tv:font-baseline
							   DEFAULT-LABELS-FONT)
							 2.0)))))))))
  )

(defmethod (labels-mixin :draw-labels)
	   (WINDOW LO-VALUE HI-VALUE &optional (AALU tv:alu-xor))
  "2Draws the labels in the list LABELS.*"
  (let (VALUE)
    (if (listp LABELS)
	(dolist (ONE-LABEL LABELS)
	  (setq VALUE (if (listp (first ONE-LABEL))
			  (second (first ONE-LABEL))
			(first ONE-LABEL)))
	  (if (and (>= VALUE LO-VALUE) (<= VALUE HI-VALUE))
	      (send self :draw-one-label-at-value WINDOW 
			    ONE-LABEL
			    VALUE
			    AALU))))
    )
  )

(defmethod (labels-mixin :draw-one-label-at-value)
	   (WINDOW LABEL VALUE &optional (AALU tv:alu-xor))
  "2Draws one *LABEL2 at *VALUE2.  LABEL is a list of the form ( *<2label-head*>2  *<2Xoff*>2 * <2Yoff*>  <2label-font*>2 ).  label-head is a number (the value of the label) or a list of the form ( label-string  label-value ) where the label is label-string drawn at label-value.  label-font defaults to *DEFAULT-LABELS-FONT2.  Xoff and Yoff, the X and Y offsets from the corresponding 'value points' both default to 0.1  Calls :convert-dial-value-to-window-coordinates to get the point on the Dial associated with the value.**"
  (multiple-value-bind (wx wy)
      (send self :convert-dial-value-to-window-coordinates
		    VALUE LABELS-BASE-DISTANCE)
    (send self :draw-string-in-window
		  WINDOW
		  (if (listp (first LABEL))
		      (first (first LABEL))
		      (format nil "~D" (first LABEL)))
		  (+ wx (if (second LABEL) (second LABEL) 0.))
		  (+ wy (if (third LABEL) (third LABEL) 0.))
		  (or (fourth LABEL) DEFAULT-LABELS-FONT)
		  AALU))
  )

(defmethod (labels-mixin :make-label-list)
	   (NEWSTRING NEWVALUE NEWX NEWY NEWFONT &optional OLDLIST)
  "2Used to add a new label descriptor to the list *LABELS2.*"
  (let* ((NEWHEAD (if NEWSTRING (list NEWSTRING NEWVALUE) NEWVALUE))
	 (NEW-LABEL (list NEWHEAD NEWX NEWY NEWFONT)))
    (setq LABELS (if OLDLIST
		     (replace OLDLIST NEW-LABEL LABELS)
		     (iF (listp LABELS)
			 (cons NEW-LABEL LABELS)
			 (list NEW-LABEL))))
    )
  )

;1;*****************************************************************
;1;*
;1; FLAVORS AND METHODS for the basic round types of DIALS.  These are*
;1; primarily envisioned as being* 1Circular and Sector types of DIALS.  It*
;1; contains a *MAJOR-RADIUS1 (used, for instance, as the location at which*
;1; the tick marks are drawn) and any number of *MINOR-RADII1 (mainly*
;1; decorative).  The arcs or circles drawn at these various radii can*
;1; have an arbitrary thickness.  A nil thickness means a thickness of 1.*
;1;*
;1; There are also functions (which can be user-defined) which*
;1; are used for converting between values and angles in a round DIAL.*
;1;*
;1; Examples of using *VALUE-TO-ANGLE-FUNCTION1 occur in DIALs whose*
;1; representation of values are non-linear (e.g. a logarithmic DIAL)*
;1; or circular DIALs where the range of values do not cover the entire*
;1; circumference of the DIAL.*
;1;*
;1; *ANGLE-TO-VALUE-FUNCTION1 is useful in converting mouse selected screen*
;1; locations to a DIAL value.*
;1;*
;1; The variable MINOR-RADII is a list containing the descriptors of the*
;1; minor radii.  Each descriptor is either a number [draw a circle or an*
;1; arc at this radius, with a thickness of one] or a list of the form:*
;1;      ( <radius>  <thickness-of-circle-or-arc> ).*
;1;*
;1;******************************************************NLC10APR84*
(defflavor round-dial-mixin	
	((MINOR-RADII '(100. 75.))    ;1;List of concentric cirles and arcs*
	 )
	()
  :initable-instance-variables
  :settable-instance-variables
  :gettable-instance-variables
  (:required-flavors dash:basic-dial)
  (:documentation "Flavor for basic information for round type of DIALS.")
  )

(defmethod (round-dial-mixin :make-minor-radii-list)
	   (NEW-RADIUS-VALUE NEWTHICKNESS &optional OLD-RADIUS-LIST)
  "2Used to add a new minor radius element to the l1ist MINOR-RADII.  Largest radius is kept at the front of the list.  Each elment can have to forms: [1] a number which is the radius, in which case the thickness is 1 or [2] a list of the form ( <radius>  <thickness-of-circle-or-arc> ).**"
  (let* ((NEW-RADIUS-LIST (if (null NEWTHICKNESS)
			      NEW-RADIUS-VALUE
			    (list NEW-RADIUS-VALUE NEWTHICKNESS)))
	 (TEMP-RADII-LIST (if OLD-RADIUS-LIST
			      (remove OLD-RADIUS-LIST MINOR-RADII)
			    MINOR-RADII))
	 (CURRENT-MAX (if (listp (first TEMP-RADII-LIST))
			  (first (first TEMP-RADII-LIST))
			(first TEMP-RADII-LIST))))
    (setq MINOR-RADII
	  (if TEMP-RADII-LIST
	      (if (> NEW-RADIUS-VALUE CURRENT-MAX)
		  (cons NEW-RADIUS-LIST TEMP-RADII-LIST)
		(append `(,(first TEMP-RADII-LIST) ,NEW-RADIUS-LIST)
			(cdr TEMP-RADII-LIST)))
	    (list NEW-RADIUS-LIST))))
  )

(defmethod (round-dial-mixin :inside-dial?) (XXX YYY)
  "2Returns *t2 if *XXX YYY2 (in window co-ordinates) are inside of the largest radius of the DIAL.*"
 (> (send self :largest-radius)
    (sqrt (+ (square (- XXX X-CENTER))
	     (square (- YYY Y-CENTER)))))
 )

(defmethod (round-dial-mixin :largest-radius) ()
  "2Returns the value of the largest minor radius of the dial.*"
  (if (listp (first MINOR-RADII))
      (first (first MINOR-RADII))
    (first MINOR-RADII))
  )

(defmethod (round-dial-mixin :draw-circles-at-radii) (WINDOW)
  "2Draws the circles at* 2all of the MINOR-RADII on the DIAL.*"
  (loop for ONE-RADIUS in MINOR-RADII
	doing (if (listp ONE-RADIUS)
		  (send WINDOW :draw-circle
			X-CENTER Y-CENTER (first ONE-RADIUS)
			(second ONE-RADIUS) gwin:black tv:alu-ior)
		(send WINDOW :draw-circle
			X-CENTER Y-CENTER ONE-RADIUS
			1. gwin:black tv:alu-ior)))
  )


;1;*****************************************************************
;1;*
;1; WEDGE DIALS are meant for wedge shaped round Dials.*
;1;*
;1; NOTE: Because of peculiarities in the SYMBOLICS software, you*
;1; should stick to wedges whose total angular size is less than*
;1; 180 dgs.  It draws filled sectors bigger than this weirdly.  It*
;1; shouldn't be to hard to have the Dials stuff compensate for this,*
;1; but that's just not been done [yet].*
;1;*
;1;******************************************************NLC15APR84*
(defflavor wedge-dial-mixin
	((WEDGE-START-ANGLE 30.)   ;1;'START' ANGLE FOR WEDGE*
	 (WEDGE-START-ANGLE-R nil) ;1;RADIAN EQUIVALENT OF THE ABOVE*
	 (WEDGE-END-ANGLE 150.)    ;1;'END' ANGLE OF THE WEDGE*
	 (WEDGE-END-ANGLE-R nil))  ;1;RADIAN EQUIVALENT OF THE ABOVE*
	()
  (:required-flavors dash:round-dial-mixin)
  (:documentation "Flavor for wedge shaped round Dials.")
  :initable-instance-variables
  :gettable-instance-variables
  :settable-instance-variables
  )

(defmethod (wedge-dial-mixin :AFTER :INIT) (&rest ignore)
 (send self :startup-wedge)
 )

(defmethod (wedge-dial-mixin :startup-wedge) ()
  "2Called by :init.  Initializes *START-ANGLE2,* WEDGE-START-ANGLE-R 2and *WEDGE-END-ANGLE-R2.*"
    (setq WEDGE-START-ANGLE-R (degrees-to-radians WEDGE-START-ANGLE)
	  WEDGE-END-ANGLE-R (degrees-to-radians WEDGE-END-ANGLE))
  )

(defmethod (wedge-dial-mixin :inside-dial?) (XXX YYY)
  "2Returns *t2, if inside the wedge defined by *WEDGE-START-ANGLE2, *WEDGE-END-ANGLE2 and the largest radius.*"
  (let ((XREL (- XXX X-CENTER))
	(YREL (- Y-CENTER YYY)))
    (and (> (send self :largest-radius)
	    (sqrt (+ (square XREL)
		     (square YREL))))
	 (>= (atan YREL XREL) WEDGE-START-ANGLE-R)
	 (<= (atan YREL XREL) WEDGE-END-ANGLE-R))
    )
  )

(defmethod (wedge-dial-mixin :draw-wedge-arcs-at-radii) (WINDOW)
  "2Draws arcs at *MAJOR-RADIUS2 and at all the *MINOR-RADII2.*"
  (loop for ONE-RADIUS in MINOR-RADII
	doing (if (listp ONE-RADIUS)
		  (send WINDOW :draw-arc X-CENTER Y-CENTER
			(+ X-CENTER
			   (* (cosd WEDGE-START-ANGLE) (first ONE-RADIUS)))
			(- Y-CENTER
			   (* (sind WEDGE-START-ANGLE) (first ONE-RADIUS)))
			(- WEDGE-END-ANGLE WEDGE-START-ANGLE)
			(second ONE-RADIUS) gwin:black tv:alu-ior)
		(send WINDOW :draw-arc X-CENTER Y-CENTER
		      (+ X-CENTER (* (cosd WEDGE-START-ANGLE) ONE-RADIUS))
		      (+ Y-CENTER (* (sind WEDGE-START-ANGLE) ONE-RADIUS))
		      (- WEDGE-END-ANGLE WEDGE-START-ANGLE)
		      1.  gwin:black tv:alu-ior))
	)
  )

(defmethod (wedge-dial-mixin :draw-wedge-edges)
	   (WINDOW &optional (AALU tv:alu-ior))
  "2Draws lines at the 'edges' of the wedge.*"
  (send WINDOW :draw-line X-CENTER Y-CENTER
	(+ x-center
	   (floor (* (send self :largest-radius) (cos wedge-start-angle-r))))
	(- y-center
	   (floor (* (send self :largest-radius) (sin wedge-start-angle-r))))
	1. gwin:black AALU)
  (send WINDOW :draw-line X-CENTER Y-CENTER
	(+ x-center
	      (floor (* (send self :largest-radius) (cos wedge-end-angle-r))))
	(- y-center
	      (floor (* (send self :largest-radius) (sin wedge-end-angle-r))))
	1. gwin:black AALU)
  )

;1;*****************************************************************
;1; RECTANGULAR PANEL MIXINS are intended to be used as a background*
;1; panel for rectangular shaped Dials.*
;1;*
;1; If Dial is drawn in reverse-video, a central rectangular region is*
;1; cleared out, and a rim THICKNESS pixels wide is left around the *
;1; edge.*
;1;******************************************************NLC15APR84*

(defflavor rectangular-panels-mixin (RECT-HEIGHT
				      RECT-WIDTH
				      THICKNESS)
	   ()
  (:documentation "Flavor for the shape of rectangular Dials.")
  (:required-flavors dash:basic-dial)
  :initable-instance-variables
  :gettable-instance-variables
  :settable-instance-variables
  )

(defmethod (rectangular-panels-mixin :draw-filled-rectangular-panel)
	   (WINDOW &optional (AALU tv:alu-ior))
  "2Draws basic background rectangular panel.*"
  (send WINDOW :draw-filled-rectangle
	(- X-CENTER (round (/ RECT-WIDTH 2.0)))
	(- Y-CENTER (round (/ RECT-HEIGHT 2.0)))
	RECT-WIDTH RECT-HEIGHT
	gwin:black AALU)
  )

(defmethod (rectangular-panels-mixin :draw-inner-rectangular-panel)
	   (WINDOW &optional (AALU tv:alu-xor))
  "2Clears the center area out of a rectangular panel.  The cleared area is THICKNESS pixels smaller in both dimensions than the main rectangular panel.*"
  (let ((TEMP-RECT-WIDTH (- RECT-WIDTH (* 2 THICKNESS)))
	(TEMP-RECT-HEIGHT (- RECT-HEIGHT (* 2 THICKNESS))))
    (send WINDOW :draw-filled-rectangle
	  (- X-CENTER (round (/ TEMP-RECT-WIDTH 2.0)))
	  (- Y-CENTER (round (/ TEMP-RECT-HEIGHT 2.0)))
	  TEMP-RECT-WIDTH TEMP-RECT-HEIGHT
	  gwin:black AALU)
    )
  )

(defmethod (rectangular-panels-mixin :draw-hollow-rectangular-panel)
	   (WINDOW &optional (AALU tv:alu-xor))
  "2Draws a hollow rectanglular panel.*"
  (send self :draw-filled-rectangle WINDOW AALU)
  (send self :draw-inner-rectangular-panel WINDOW tv:alu-xor)
  )

(defmethod (rectangular-panels-mixin :inside-dial?) (XXX YYY)
  "2Returns *t2 iff (*XXX,YYY2) is 'on' the rectangular panel.*"
  (let* ((HALF-HEIGHT (round (/ RECT-HEIGHT 2.0)))
	 (HALF-WIDTH (round (/ RECT-WIDTH 2.0))))
    (and (>= XXX (- X-CENTER HALF-WIDTH))
	 (>= YYY (- Y-CENTER HALF-HEIGHT))
	 (<= XXX (+ X-CENTER HALF-WIDTH))
	 (<= YYY (+ Y-CENTER HALF-HEIGHT)))
    )
  )
;1;*****************************************************************
;1;******************************************************NLC15APR84
