c************
c  Description:	This module contains the non-XWindows graphics support routines
c		for Points Mode FACILITIES related graphics operations
c
c  Author:	JGS   4//90
c		Split from glibf2.for 7/19/95
c
c  $Revision: 1.3 $
c  $Modtime:   01 May 1996 16:27:22  $
c  
c************

	subroutine MXU$POINTS (Mx, Xf, MQD, ROUTINE, modep)

	implicit none

	include 'primitive.inc'
	include 'xprim.inc'
	include 'xfacilities.inc'
	include 'qmessdef.inc'
c Arguments
	record /XFACILITIES/ Xf
	record /MQ_DATA/ MQD
	external ROUTINE
	integer*4 modep
c Locals
	integer*4 sym, rad, npoint, mpoint, iarg, BSORT
	integer*4 n, i, j, li, w, h, item
	logical*4 xy, found, exposure, set
	character titlebar*42, menu*128, filename*80, c
	record /STKSTRUCT/ stk4

	record /XFPOINT/ point(1), poi
	pointer (point_addr, point)

c Code
	if (modep.eq.L_Draw .and. Xf.npoint.eq.0) return

	if (Xf.point.p .eq. 0) then
	  if (Xf.mpoint.le.0 .or. modep.eq.L_CleanExit) return
	  call M$STMALLOC(Xf.mpoint * L_xfpoint, Xf.point)
	  call M$STMALLOC(Xf.mpoint * L_pixstruct, Xf.pwork)
	endif

	xy   = Xf.xy
	sym  = Xf.pdot
	rad  = Xf.prad
	point_addr = Xf.point.p

	call MX$ORIGIN (Mx.origin, 4, Mx.stk(Mx.level), stk4)

	if (modep.eq.L_draw) then
	  call PPLOT(Mx, Xf, Xf.npoint, 1, 1)
c
	elseif (modep.eq.L_CleanExit) then
	  call M$STMFREE(Xf.mpoint * L_xfpoint, Xf.point)
	  call M$STMFREE(Xf.mpoint * L_pixstruct, Xf.pwork)
	  Xf.point.p = 0
	  Xf.pwork.p = 0
	  Xf.mpoint = 0
	  Xf.npoint = 0
c
	elseif (modep.eq.2) then	! add/alter point from MQD.POINTINFO
	  if (Xf.iarg.gt.Xf.mpoint) Xf.iarg = -1
	  if (Xf.iarg.le.0) return
	  Xf.iarg = min (Xf.iarg, Xf.npoint + 1)
	  call PPLOT(Mx, Xf, Xf.npoint, 1, 1)
	  if (xy) then
	    point(Xf.iarg).xyX = MQD.POINTINFO.x
	    point(Xf.iarg).xyY = MQD.POINTINFO.y
	  else
	    point(Xf.iarg).yxX = MQD.POINTINFO.x
	    point(Xf.iarg).yxY = MQD.POINTINFO.y
	  endif
	  call POINT_MSG (Xf, point, Xf.iarg)
	  Xf.npoint = max (Xf.iarg, Xf.npoint)
	  if (Xf.psort .and. Xf.iarg.eq.Xf.npoint) then
	    Xf.iarg = BSORT (point, Xf.npoint)
	  elseif (Xf.psort) then
	    call PSORT (point, Xf.npoint)
	  endif
	  call PPLOT(Mx, Xf, Xf.npoint, 1, 1)
c
	elseif (modep.eq.3) then	! put point into MQD.POINTINFO
	  if (Xf.iarg.eq.0) Xf.iarg = Xf.npoint
	  if (Xf.iarg.lt.0) Xf.iarg = max (1, Xf.npoint+Xf.iarg+1)
	  if (Xf.iarg.ge.1 .and. Xf.iarg.le.Xf.npoint) then
	    if (xy) then
	      MQD.POINTINFO.x = point(Xf.iarg).xyX
	      MQD.POINTINFO.y = point(Xf.iarg).xyY
	    else
	      MQD.POINTINFO.x = point(Xf.iarg).yxX
	      MQD.POINTINFO.y = point(Xf.iarg).yxY
	    endif
	  else
	    Xf.iarg = -1
	  endif
c
	elseif (modep.eq.4) then	! erase point(s)
	  if (Xf.iarg.eq.0) then
	    call PPLOT(Mx, Xf, Xf.npoint, 1, 1)
	    Xf.iarg = Xf.npoint
	    Xf.npoint = 0
	    call POINT_MSG (Xf, point, 0)
	  elseif (Xf.iarg.le.Xf.npoint) then
	    if (Xf.iarg.lt.0) Xf.iarg = max (1, Xf.npoint+Xf.iarg+1)
	    call PPLOT(Mx, Xf, Xf.npoint, 1, 1)
	    call POINT_MSG (Xf, point, -Xf.iarg)
	    if (Xf.iarg.lt.Xf.npoint) call M$MOVE (point(Xf.iarg+1), 
     &		point(Xf.iarg), (Xf.npoint-Xf.iarg)*L_xfpoint)
	    Xf.npoint = Xf.npoint - 1
	    call PPLOT(Mx, Xf, Xf.npoint, 1, 1)
	  else
	    Xf.iarg = 0
	  endif

	elseif (modep.eq.5) then	! SET messages
	  set = (Xf.iarg.ne.0)
	  if (MQD.SET.object .eq. 'POINTSOR') then
	    if (Xf.iarg .eq. -1 .or. (Xf.psort .neqv. set)) then
	      call TOGGLE_POINTSORT (Mx, Xf, point)
	    endif
	  elseif (MQD.SET.object .eq. 'POINTLIN') then
	    if (Xf.iarg.ge.0 .and. Xf.iarg.le.3 .and.
     &			Xf.iarg.ne.Xf.pline) then
	      call PPLOT(Mx, Xf, Xf.npoint, 1, 0)
	      Xf.pline = Xf.iarg
	      call PPLOT(Mx, Xf, Xf.npoint, 1, 0)
	    endif
	  elseif (MQD.SET.object .eq. 'POINTSYM') then
	    if (Xf.iarg .ne. Xf.pdot) then
	      call PPLOT(Mx, Xf, Xf.npoint, 0, 1)
	      Xf.pdot = Xf.iarg
	      call PPLOT(Mx, Xf, Xf.npoint, 0, 1)
	    endif
	  elseif (MQD.SET.object .eq. 'POINTRAD') then
	    if (Xf.iarg .ne. Xf.prad) then
	      call PPLOT(Mx, Xf, Xf.npoint, 0, 1)
	      Xf.prad = Xf.iarg
	      call PPLOT(Mx, Xf, Xf.npoint, 0, 1)
	    endif
	  endif

	elseif (modep.eq.L_PreLoad) then		! preload file
	  call POINTS_FILE(Mx, Xf, MQD.NEWFILE.filename, 0)

	elseif (modep.eq.6) then			! load file from msg
	  if (MQD.NEWFILE.filename .eq. ' ') then
	    call PPLOT(Mx, Xf, Xf.npoint, 1, 1)
	    Xf.iarg = Xf.npoint
	    Xf.npoint = 0
	    call POINT_MSG (Xf, point, 0)
	  else
	    call POINTS_FILE(Mx, Xf, MQD.NEWFILE.filename, 1)
	  endif
	endif

	if (modep.ne.L_Interactive .and. modep.ne.L_OneShot)  return

c
c mode for interactive create/delete points
	if (stk4.xscl .eq. 0.d0 .or. stk4.yscl .eq. 0.d0) then
	  call M$WARNING ('Illegal scaling values detected in Points Mode.')
	  return
	endif

	exposure = .false.
	titlebar = 'Points Mode: LM-Add/moVe MM-Menu RM-Delete'
	call MX$SETBAR (titlebar)

	do while (.true.)

	  Mx.button_press = 0
	  do while (Mx.button_press.eq.0) 
	    call MX$EVENT ()
	    if (Mc.break) goto 999
	    if (Mc.sysunlock .or. Mx.breakflag) then	! system unlock (exit)
	      if (Mc.sysunlock) exposure = .true.
	      goto 999
	    elseif (Mx.key_upchar.eq.'A') then		! Add point
	      Mx.button_press = 1		
	    elseif (Mx.key_upchar.eq.'V') then		! Move point
	      Mx.button_press = 1		
	    elseif (Mx.key_upchar.eq.'M') then		! Menu
	      Mx.button_press = 2		
	    elseif (Mx.key_upchar.eq.'D') then		! Delete point
	      Mx.button_press = 3		
	    elseif (Mx.key_upchar.eq.'?') then		! Help
	      call MX$MHELP ('~POINTS OPTIONS', 'Points Mode')
	    elseif (Mx.key_upchar.eq.'Q') then		! Quit
	      goto 999
	    endif
	    if (Mx.exposure) exposure = .true.
	    if (Mx.resize) goto 999	! Resize (may be caught in mhelp)
	    if (Xf.ROUTINE.p .ne. 0) call ROUTINE
	  enddo

c
c delete point
	  if ((Mx.button_press.eq.3 .or. Mx.button_press.eq.1) .and.
     &		Mx.xpos.gt.stk4.x1 .and. Mx.xpos.lt.stk4.x2 .and.
     &		Mx.ypos.gt.stk4.y1 .and. Mx.ypos.lt.stk4.y2) then
c
	    n = 0					! delete point
	    found = .false.
	    if (Mx.key_upchar .eq. 'A') n = Xf.npoint
	    do while (n.lt.Xf.npoint .and. .not.found)
	      n = n + 1
	      if (xy) then	! translate virtual point to pixel
		i = NINT((point(n).xyX - stk4.xmin)/stk4.xscl) + stk4.x1 
		j = NINT((point(n).xyY - stk4.ymin)/stk4.yscl) + stk4.y1 
	      else
		i = NINT((point(n).yxX - stk4.xmin)/stk4.xscl) + stk4.x1 
		j = NINT((point(n).yxY - stk4.ymin)/stk4.yscl) + stk4.y1 
	      endif
	      found = (Xf.pline.eq.2 .or. iabs(Mx.xpos-i).lt.10) .and. 
     &		      (Xf.pline.eq.1 .or. iabs(Mx.ypos-j).lt.10)
	    enddo
	    if (found) then
	      if (Mx.button_press.eq.3) then		! Delete Point
		if (sym.ne.0) call MX$DRAW_SYMBOL(L_XORColor, i, j, sym, rad)
		call PPLOT(Mx, Xf, Xf.npoint, 1, 0)
	        call POINT_MSG (Xf, point, -n)
		call M$MOVE (point(n+1), point(n), 16*(Xf.npoint-n))
		Xf.npoint = Xf.npoint-1
		call PPLOT(Mx, Xf, Xf.npoint, 1, 0)
	      elseif (Xf.pline.gt.0 .or. sym.ne.0) then	! Move Point
		if (Xf.pline.eq.1) then
		  w = 0
		  h = Mx.height
		elseif (Xf.pline.eq.2) then
		  w = Mx.width
		  h = 0
		else
		  w = abs(rad)
		  h = w
		endif
		i = Mx.xpos - w
		j = Mx.ypos - h
		call MX$DRAGBOX (i, j, 2*w, 2*h, 
     &			stk4.x1-w, stk4.x2+w, stk4.y1-h, stk4.y2+h, ROUTINE)
		i = i + w
		j = j + h
		if (Mx.button_release.eq.1) then
		  call PPLOT(Mx, Xf, Xf.npoint, 1, 1)
		  if (xy) then	! translate pixel to virtual point 
		    point(n).xyX = stk4.xmin + (i-stk4.x1) * stk4.xscl
		    point(n).xyY = stk4.ymin + (j-stk4.y1) * stk4.yscl
		  else
		    point(n).yxX = stk4.xmin + (i-stk4.x1) * stk4.xscl
		    point(n).yxY = stk4.ymin + (j-stk4.y1) * stk4.yscl
		  endif
		  call POINT_MSG (Xf, point, n)
		  if (Xf.psort) call PSORT (point, Xf.npoint)
		  call PPLOT(Mx, Xf, Xf.npoint, 1, 1)
		endif
	      endif
c
	    elseif (Mx.button_press.eq.1 .and. Mx.key_upchar.ne.'V') then
								! Add Point
	      if (Xf.npoint.ge.Xf.mpoint) then
		call MX$MESSAGE ('No more points available', -2.0)
	      else
		Xf.npoint = Xf.npoint + 1
		if (xy) then	! translate pixel to virtual point 
		  point(Xf.npoint).xyX = stk4.xmin+(Mx.xpos-stk4.x1)*stk4.xscl
		  point(Xf.npoint).xyY = stk4.ymin+(Mx.ypos-stk4.y1)*stk4.yscl
		else
		  point(Xf.npoint).yxX = stk4.xmin+(Mx.xpos-stk4.x1)*stk4.xscl
		  point(Xf.npoint).yxY = stk4.ymin+(Mx.ypos-stk4.y1)*stk4.yscl
		endif
		if (sym.ne.0)
     &		  call MX$DRAW_SYMBOL(L_XORColor, Mx.xpos, Mx.ypos, sym, rad)
		call PPLOT(Mx, Xf, Xf.npoint-1, 1, 0)
		call POINT_MSG (Xf, point, Xf.npoint)
		if (Xf.psort) n = BSORT (point,Xf.npoint)
		call PPLOT(Mx, Xf, Xf.npoint, 1, 0)
	      endif
	    endif
c
c menu options
 	  elseif (Mx.button_press.eq.2) then
	    menu = '~POINTS OPTIONS;Save to File...,Load File...,Clear'//
     &		   ' All,Symbols...,Lines...,- Sort,Exit Points'
	    if (Xf.psort) menu(76:76) = '+'
	    item = MX$MENU (0, menu)
c
	    if (item.eq.1) then				! save to file
	      filename = ' '
	      call MX$PROMPT('~Points Filename: ', filename)
	      if (filename.ne.' ') call POINTS_FILE(Mx, Xf, filename, -1)
c
	    elseif (item.eq.2) then				! load from file
	      if (Xf.npoint.ge.Xf.mpoint) then
		call MX$MESSAGE('No more point slots available.', 1.0)
	      else
		filename = ' '
		n = MX$FILES (filename)
		call MX$SETBAR (titlebar)
		if (n.gt.0) call POINTS_FILE(Mx, Xf, filename, 2)
	      endif
c
	    elseif (item.eq.3) then				! clear all
	      call PPLOT(Mx, Xf, Xf.npoint, 1, 1)
	      Xf.npoint = 0
	      call POINT_MSG (Xf, point, Xf.npoint)
c
	    elseif (item.eq.4) then				! symbols
	      sym = MX$MENU((min(sym,8))+1, '~SYMBOLS;None,'//
     &		'Pixels,Circles,Squares,Plusses,X''s,'//
     &		'Triangles,Down Triangles,ASCII...') - 1
	      if (sym .eq. 8) then
		c = ' '
		if (Xf.pdot .gt. 7) c = CHAR(Xf.pdot)
		call MX$PROMPT ('ASCII Character: ', c)
		if (c .eq. ' ') then
		  sym = Xf.pdot
		else
		  sym = ICHAR(c)
		  rad = - (Mx.text_w/2)
		endif
	      elseif (sym .gt. L_PixelSymbol) then
		call MX$LVAL('~Symbol Radius:', rad, -20, 20, 1, 0)
		call MX$SETBAR(titlebar)
	      endif
	      if (sym.ne.Xf.pdot .or. rad.ne.Xf.prad) then
	      	call PPLOT(Mx, Xf, Xf.npoint, 0, 1)
		Xf.prad = rad
		Xf.pdot = sym
	      	call PPLOT(Mx, Xf, Xf.npoint, 0, 1)
	      endif
c
	    elseif (item.eq.5) then				! lines
	      li = MX$MENU(Xf.pline+1,
     &		'~LINES;None,Verticals,Horizontals,Connecting') - 1
	      if (li.ne.Xf.pline) then
		call PPLOT(Mx, Xf, Xf.npoint, 1, 0)
		Xf.pline = li
		call PPLOT(Mx, Xf, Xf.npoint, 1, 0)
	      endif

	    elseif (item.eq.6) then				! sort
	      call TOGGLE_POINTSORT (Mx, Xf, point)
c
	    elseif (item.eq.7) then				! exit
	      goto 999
	    endif
c
	  endif

	  if (Mx.button_press.ne.0 .and. modep.eq.L_OneShot) goto 999

	enddo

 999	call MX$UNSETBAR ()
	Mx.exposure = exposure
	return 
	end

	subroutine POINTS_FILE (Mx, Xf, filename, mode)
	implicit none
	include 'types.inc'
	include 'xprim.inc'
	include 'xfacilities.inc'
	include 'headers.inc'
c Arguments
	record /XFACILITIES/ Xf
	character*(*) filename
	integer*4 mode		! -1=save, 0=preload, 1=newfile msg, 2=load
c Locals
	record /header/ hcb
	integer*4 i, nget, junk, BSORT
	record /XFPOINT/ point(*)
	pointer (point_addr, point)

	call M$INITIALIZE(hcb)
	hcb.file_name = filename(1:M$LENGTH(filename))
	point_addr = Xf.point.p

	if (mode.lt.0) then
	  hcb.type = 3010
	  hcb.format = 'SD'
	  hcb.switch = 'NOABORT'
	  call M$ADDSREC(hcb, 'ABSC', 'SD')
	  call M$ADDSREC(hcb, 'ORD ', 'SD')
	  hcb.size = Xf.npoint
	  call M$ALLOCATE (hcb)
	  if (hcb.open) then
	    call M$FILAD(hcb, point, Xf.npoint)
	    call M$CLOSE(hcb)
	    call MX$MESSAGE('File saved', 1.0)
	  else
	    call MX$MESSAGE('Aborted save', 1.0)
	  endif
	else
	  hcb.type_allow = '3000'
	  hcb.format_allow = 'SD'
	  hcb.switch = 'NOABORT'
	  call M$INOK(hcb)
	  if (hcb.open) then
	    if (mode.eq.1 .and. Xf.iarg.eq.-1) then
	      call PPLOT(Mx, Xf, Xf.npoint, 1, 1)
	      Xf.npoint = 0
	      call POINT_MSG (Xf, point, 0)
	    endif
	    nget = min(INT(hcb.size), Xf.mpoint-Xf.npoint)
	    call M$GRAB(hcb, point(Xf.npoint+1), 1.d0, nget, -1)
	    call M$CLOSE(hcb)
	    call PPLOT(Mx, Xf, Xf.npoint, 1, 1)
	    if (Xf.msgid.gt.0) then
	      do i = Xf.npoint+1, Xf.npoint+nget
		Xf.npoint = Xf.npoint + 1
		call POINT_MSG (Xf, point, Xf.npoint)
		if (Xf.psort) junk = BSORT(point, Xf.npoint)
	      enddo
	    else
	      Xf.npoint = Xf.npoint + nget
	      if (Xf.psort) call PSORT(point, Xf.npoint)
	    endif
	    if (mode.ne.0) call PPLOT(Mx, Xf, Xf.npoint, 1, 1)
	    if (nget.lt.INT(hcb.size)) then
	      if (mode .eq. 0) then
		call M$WARNING('Points file truncated')
	      else
		call MX$MESSAGE('Points file truncated',2.0)
	      endif
	    endif
	  elseif (mode.eq.2) then
	    call MX$MESSAGE('Error opening points file '//hcb.file_name, 
     &                                                    1.0)
	  else
	    call M$WARNING('Error opening points file '//hcb.file_name)
	  endif
	endif

	return
	end

	subroutine TOGGLE_POINTSORT (Mx, Xf, point)
	include 'types.inc'
	include 'xprim.inc'
	include 'xfacilities.inc'
	record /XFACILITIES/ Xf
	record /XFPOINT/ point(*)
	integer*4 n
	Xf.psort = .not. Xf.psort
	if (Xf.psort) then
	  if (Xf.pline.eq.3) then
	    call PPLOT(Mx, Xf, Xf.npoint, 1, 0)
	    call PSORT (point, Xf.npoint)
	    call PPLOT(Mx, Xf, Xf.npoint, 1, 0)
	  else
	    call PSORT (point, Xf.npoint)
	  endif
	  if (Xf.msgid) then
	    do n = 1, Xf.npoint
	      call POINT_MSG (Xf, point, n)
	    enddo
	  endif
	endif
	return
	end

c**************************************************************************
c
c  ~Subroutine PSORT (point,n)
c
c  complex*16	point(*)  An array of points (same size as an /XFPOINT/)
c  integer*4	n	  Number of points in array
c
c  Bubble sort optimized for having last point out of place.
c
c**************************************************************************

	subroutine PSORT (point, n)

	implicit none

	complex*16 point(*),ip
	integer*4 i, n
	logical*4 moved

	moved = .false.
	do i = 1,n-1
	  if (DREAL(point(i)) .gt. DREAL(point(i+1))) then
	    moved = .true.
	    ip = point(i)
	    point(i) = point(i+1)
	    point(i+1) = ip
	  endif
	enddo
	do while (moved)	
	  moved = .false.
	  do i = n-1,1,-1
	    if (DREAL(point(i)) .gt. DREAL(point(i+1))) then
	      moved = .true.
	      ip = point(i)
	      point(i) = point(i+1)
	      point(i+1) = ip
	    endif
	  enddo
	enddo

	return
	end

c**************************************************************************
c
c  ~Function BSORT (point,n)
c
c  complex*16	point(*)  An array of points (same size as an /XFPOINT/)
c  integer*4	n	  Number of points in array
c  integer*4	BSORT	  Returns new location of sorted last point
c
c  Binary sort for having ONLY the last point out of place.  Returns the
c  new location of the last point after sorting.
c
c**************************************************************************

	integer*4 function BSORT (point,n)

	implicit none

	complex*16 point(*),ip
	integer*4 n, il, ir, im, found

	BSORT = 1
	if (n.eq.1) return
	il = 1
	ir = n - 1
	found = 0
	do while (found.eq.0)
	  im = (il + ir)/2
	  if (DREAL(point(n)) .lt. DREAL(point(im))) then
	    if (im.eq.il) found = il
	    ir = im
	  else
	    if (im.eq.ir) found = ir + 1
	    il = im + 1
	  endif
	enddo
	if (found.lt.n) then
	  ip = point(n)
	  call M$MOVE (point(found), point(found+1), 16*(n-found))
	  point(found) = ip
	endif
	BSORT = found
c
	return
	end

c*************************************************************************
c
c  ~Subroutine PPLOT(Mx, Xf, npt, line, symbol)
c  
c  /MX/		Mx	The MX graphics structure
c  /XFACILITIES/ Xf	The XFacilities structure with points info
c  integer*4	npt	The number of points in the array
c  integer*4	line	Line type (1=Draw lines, 0=Do not)
c  integer*4	symbol	Point type (1=Draw symbols, 0=Do not)
c  
c  This routine is called by MXU$POINTS to draw its array of points in the
c  reversible rubber band graphics context (double thick if indicated by
c  Mx.rmode).  It is simply a dummy wrapper that calls MXF$TRACE but is
c  necessary to convert the line specification to the proper <ic> flag
c  for MXF$TRACE.
c
c  PPLOT also splits apart the array of points into the separate X and
c  Y point arrays depending on <xy>.  The skip parameter of MXF$TRACE is
c  set to 2 since the x and y coordinates are interwoven, much like complex
c  data that is sometimes plotted through MXF$TRACE.
c
c*************************************************************************

	subroutine PPLOT (Mx, Xf, npt, line, symbol)

	implicit none

	include 'types.inc'
	include 'xprim.inc'
	include 'xfacilities.inc'
	record /XFACILITIES/ Xf
	record /XFPOINT/ pt
	record /M_PTR/ x, y
	integer*4 npt, line, symbol, mode, li, sy

c
c Set the bit flags for verticals/horizontals/connecting flags and the bit
c flag for clipping, if Xf.clip is false then we'll let MXF$TRACE do the
c clipping for us, clipping to the Mx.stk(Mx.level) field
c
	mode = 0
	sy = 0
	if (line.gt.0 .and. Xf.pline.gt.0) then
	  li = 1
	  if (Xf.pline.eq.1) then
	    mode = 2
	  elseif (Xf.pline.eq.2) then
	    mode = 4
	  endif
	elseif (symbol.gt.0 .and. Xf.pdot.ne.0) then
	  li = 0
	else
	  return
	endif
	if (symbol.gt.0) sy = Xf.pdot

	if (Xf.clip) then
	  mode = mode + 1
	  call MX$RCLIP(Xf.x1, Xf.y1, Xf.x2-Xf.x1+1, Xf.y2-Xf.y1+1)
	endif

c
c Figure out the correct pointer offsets for the point buffers
c if Xf.xy = TRUE they are ordered (x,y) otherwise they are ordered (y,x)
c
	if (Xf.xy) then
	  x.p = Xf.point.p + %loc(pt.xyX) - %loc(pt)
	  y.p = Xf.point.p + %loc(pt.xyY) - %loc(pt)
	else
	  x.p = Xf.point.p + %loc(pt.yxX) - %loc(pt)
	  y.p = Xf.point.p + %loc(pt.yxY) - %loc(pt)
	endif

	call MXF$TRACE (Mx, L_XORColor, %val(x.p), %val(y.p), 
     &	    npt, 2, li, sy, Xf.prad, %val(Xf.pwork.p), mode)

	if (Xf.clip) call MX$RCLIP(0, 0, 0, 0)

	return
	end

c*************************************************************************
c
c Actual routine called by MX$POINTS passing the Mx structure.  MX$POINTS is 
c a C jacket in gjackets.c that passes its global pointer to the Mx structure 
c along with the other arguments.  See HELP MX$POINTS for more info.
c
c This is actually another wrapper that calls MXU$POINTS so the user does not 
c have to keep track of the points array.  Provides access to the point 
c coords through modes 5,6 and allows points to be added non-interactively 
c through modes 3 and 4.
c
c    0: cleaned exit
c    1,2: plot points			-1,-2: interactive mode
c    3,4: add specific points    	-3,-4: oneshot mode
c    4,5: return points coordinates
c
c Odd mode means (time,value) points are to be plotted with time on the X 
c axis and value on the Y axis (X-PLOT).  Even mode means (time,value) are
c plotted with time on the Y axis and value on the X axis (X-RASTER).  Simply
c stated, if mode is odd, each point is stored and interpreted as (x,y); if
c even (y,x). 
c
c In MXU$POINTS, all information stored here statically is located in a
c structure.  Also, the difference the (x,y) or (y,x) mode of plotting
c is stored as a field in this structure so the odd and even mode format
c is unnecessary.  MXF$POINTS simply initializes a statuc XFACILITIES
c structure and then calculates the (x,y) mode by reading the modeb
c argument and converting.  The flags to MXU$POINTS are the same as those
c to MXF$POINTS but divided in half.
c
c*************************************************************************

	subroutine MXF$POINTS (Mx, modep, ROUTINE, iarg, dpoint, pix)

	implicit none

	integer*4 mpoint
	parameter (mpoint=1024)
	include 'types.inc'
	include 'xprim.inc'
	include 'xfacilities.inc'

	external ROUTINE
	integer*4 modep, iarg, mode
	logical*4 xy
	real*8 dpoint(*)
	record /PIXSTRUCT/ pix(mpoint)

	SAVE
	logical*4 uninitialized  /.true./
	record /XFPOINT/ point(mpoint)
	record /XFACILITIES/ Xf

	if (modep .eq. 0) then
	  uninitialized = .true.
	  return
	elseif (uninitialized) then
	  Xf.point.p = %loc(point)
	  Xf.pwork.p = %loc(pix) 
	  Xf.psort = .true.
	  Xf.pline = 0
	  Xf.pdot = L_CircleSymbol
	  Xf.prad = -3
	  Xf.npoint = 0
	  Xf.xy = MOD(iabs(modep),2).eq.1
	  uninitialized = .false.
	endif

	mode = modep / 2
	if (Xf.xy .and. modep.gt.0) mode = mode + 1
	if (Xf.xy .and. modep.lt.0) mode = mode - 1
	call MXU$POINTS (Mx, Xf, dpoint, ROUTINE, modep)

	return
	end

c*************************************************************************
c
c  ~Subroutine POINT_MSG (Xf, point, pointid)
c  
c  /XFACILITIES/ Xf	 An XFACILITIES structure (SEE XFACILITIES.INC)
c  /XFPOINT/	point(*) The array of points used by MXU$POINTS
c  integer*4	pointid	 The index into point(*) of the point that changed
c
c  This routine is called each time a point is added, changed or removed
c  from the point array.  If the Xf.msgid field is non-negative and the
c  MSK_POINTS bit is set in the Xf.mask field then a POINTINFO message is
c  sent out to the primitive whose Mu.id field is Xf.msgid.
c
c  If <pointid> is less than 0, then it indicates that the point located in
c  the <point(*)> array at slot abs(<pointid>) was deleted.  The pointinfo
c  message will also send out a negative pointid value.
c
c  Before sending out the coordinates in the BOXINFO message they must
c  be converted to <x,y>.  This is done by checking the Xf.xy.
c
c*************************************************************************

	subroutine POINT_MSG (Xf, point, pointid)

	implicit none

	include 'types.inc'
	include 'xfacilities.inc'
	include 'msgmask.inc'
	include 'qmessdef.inc'
	record /XFACILITIES/ Xf
	record /XFPOINT/ point(*)
	integer*4 pointid, id
	record /MQH_POINTINFO/ MQH
	record /MQD_POINTINFO/ dpoint

	if (Xf.msgid.le.0 .or. .not.BTEST(Xf.msgmask,MSK_POINTS)) return
	MQH.pointid = pointid
	id = abs(MQH.pointid)
	if (id.ne.0) then
	  if (Xf.xy) then
	    dpoint.x = point(id).xyX
	    dpoint.y = point(id).xyY
	  else
	    dpoint.x = point(id).yxX
	    dpoint.y = point(id).yxY
	  endif
	endif
	call M$SEND_MSG (MQH, dpoint, Xf.msgid, 0)
	return
	end

