c
c    Fortran version of a set of C routines which handled the output for
c    Rex Saunders' Calcomp-like Postscript routines (written in Fortran)
c    Dan Severance, 5/89 Purdue University
c
c    The rest of the code is Rex Saunders' with some modifications
c
c    The original routines were very much UNIX bound, besides requiring
c    the user to have two compilers.
c
c    These routines should work on any computer including UNIX with a
c    fortran 77 compiler..
c
c    These routines do _not_ generate Encapsulated PostScript... just
c    the plain vanilla variety...
c
      subroutine plbegn
      character*7 fname
      character bigstr*256
      common /str/ bigstr,nstr
      data fname / 'psplot'/
      nstr = 1
      open (7,file=fname,status='unknown',iostat=l)
      if (l.ne.0) then
         write (*,*) 'plbegn: can''t open ',fname
         return
      endif
      write (7,'(A)') '%!'
      write (7,'(A)') '% postscript output from ccps library'
      return
      end
c
c
      subroutine pldone
c
      write (7,'(A)') '% end of ccps output'
      close (7)
      return
      end
c
c
      subroutine plcout (c)
      character c*1,bigstr*256
      common /str/ bigstr,nstr
      data islash / 92 /
c
c    send one char to plot file
c
      ic = mod(ichar(c),127)
      bigstr(nstr:nstr) = c
      nstr = nstr+1
      return
      end
c
c
      subroutine pliout (i)
      integer i
      character bigstr*256,temp*80
      common /str/ bigstr,nstr
c
c    send one integer value to plot string
c
      write (temp,'(i20)') i
      call strbnd (temp,ibgn,iend)
      iadd = iend-ibgn
      bigstr(nstr:nstr+iadd) = temp(ibgn:iend)
      nstr = nstr+iadd+1
      return
      end
c
c
      subroutine plfout (f)
      real f
      character bigstr*256,temp*80
      common /str/ bigstr,nstr
c
c    send one float value to plot string
c
      write (temp,'(f10.3)') f
      call strbnd (temp,ibgn,iend)
      iadd = iend-ibgn
      bigstr(nstr:nstr+iadd) = temp(ibgn:iend)
      nstr = nstr+iadd+1
      return
      end
c
c
      subroutine plsout (s)
      character*(*)s
      character bigstr*256,blnk*1,newl*1,slshn*2
      common /str/ bigstr,nstr
      data blnk / ' '/,islsh / 92 /,slshn / ' n'/
c
c    send a string to plot file
c
      newl = char(10)
      slshn(1:1) = char(islsh)
      call strbnd (s,ibgn,iend)
      i = index(s(1:iend),newl)
      j = index(s(1:iend),slshn)
      if (j.ne.0) i = j
c
c    if i is not 0, then there was a newline imbedded, decrement the end
c    pointer to be just before the newline and write the string, along
c    with whatever happens to be in bigstr.
c
      if (i.ne.0) then
         iend = i-1
         if (nstr.eq.1) then
            write (7,'(A)') s(1:iend)
         else
            nstr = nstr-1
            write (7,'(A)') bigstr(1:nstr),s(1:iend)
            nstr = 1
         endif
      else
c
c    there was no newline, so add the text to whats in bigstr
c
         iadd = iend
c
c    add one to end in case a space was included in the incoming string
c
         iend = iend+1
         bigstr(nstr:(nstr+iadd)) = s(1:iend)
         nstr = nstr+iend
      endif
      return
      end
c
c
      subroutine strbnd (strng,ibgn,iend)
c
c    routine to return the bounds of a string
c
      character*(*) strng
      integer ibgn,iend
c
      l = len(strng)
      do 10 i = 1, l
         if (strng(i:i).ne.' ') go to 20
   10 continue
   20 ibgn = i
      do 30 i = l, 1, -1
         if (strng(i:i).ne.' ') go to 40
   30 continue
   40 iend = i
      return
      end
c
c end of rewritten C routines - what follows is partially modified code
c from Rex Saunders
c
      subroutine plots (idum)
      integer idum
c
c   plotter initialisation routine - must be called before any other plo
c     calls are made
c
c   where:
c     idum = dummy variable for compatibility
c

      common /cqpbnf/ xold,yold,fac,ires
      save /cqpbnf/
      real xold,yold,fac
      integer ires

      logical first
      save first
      data first / .true. /

c
c   initialise plot storage - if we haven't already
c
      if (idum.eq.1) then
         call pldone
         first = .true.
      endif
      if (first) then
         first = .false.
         call plbegn
c
c       scale, rotate and translate postscript output
c         units of pixels (300/inch for most laser printers)
c         origin in lower left corner, landscape mode
c
         call plsout ('72 300 div dup scale\n')
         call plsout ('90 rotate\n')
         call plsout ('75 -2460 translate\n')
         call plsout ('0 0 moveto\n')
c
c       set other line drawing parameters
c
         call plsout ('1 setlinewidth\n')
         call plsout ('1 setlinejoin\n')
         call plsout ('1 setlinecap\n')
c
c     speed up symbol font handling
c
         call plsout ('/sf /Times-Roman findfont def\n')
c
c       set up definitions for other routines:
c
c       move
c
         call plsout ('/m /moveto load def\n')
c
c       relative move
c
         call plsout ('/rm /rmoveto load def\n')
c
c       draw
c
         call plsout ('/d {lineto currentpoint stroke moveto} def\n')
c
         call plsout ('/l /lineto load def\n')
c
c       set new origin
c
         call plsout ('/o {currentpoint translate} def\n')
c
c       set new linewidth
c
         call plsout (
     *      '/w {currentpoint stroke moveto setlinewidth} def\n')
c
c       set character height
c
         call plsout ('/h {sf exch scalefont setfont} def\n')
c
c       show character string
c
         call plsout ('/s /show load def\n')
c
c       start and end rotated text
c
         call plsout ('/rs {currentpoint gsave translate rotate} def\n')
         call plsout ('/re /grestore load def\n')

c
c set a circle file macro.
c
         call plsout ('/cf {moveto setgray 0 360 arc fill} def\n')
         call plsout ('/ci {0 360 arc 0.0 setgray stroke} def\n')
         call plsout ('% \n')
      endif

c
c   initialise common variables
c
      fac = 1.0
      xold = 0.0
      yold = 0.0
      ires = 300
      return
      end
c
c
      subroutine plot (x,y,ipen)
      real x,y
      integer ipen
c
c  plotter driver conforming to:
c    'programming calcomp electromechanical plotters', calcomp, january
c    output for postscript printers like apple laserwriter plus
c
c  rex sanders, usgs, 2/87
c
c  where:
c    x,y = coordinates, in inches from the current origin, of the positi
c          to which the pen is to be moved
c
c    ipen = pen control, origin definition, and plot termiination such t
c      if ipen = 1, move with pen in present condition
c      if ipen = 2, move with pen down
c      if ipen = 3, move with pen up
c      if ipen = -1, move with no pen change, reset origin to terminal p
c      if ipen = -2, move with pen down, reset origin to terminal positi
c      if ipen = -3, move with pen up, reset origin to terminal position
c      if ipen = 666, see 999.
c      if ipen = 999, move with pen up, terminate plot, close plot file
c      if ipen = anything else, no action is taken
c

      common /cqpbnf/ xold,yold,fac,ires
      save /cqpbnf/
      real xold,yold,fac
      integer ires

      integer locpen
      logical penup
      save penup
      data penup / .true. /

      locpen = abs(ipen)

c
c   check pen for proper values
c
      if (locpen.ne.1.and.locpen.ne.2.and.locpen.ne.3.and.ipen.ne.
     *   666.and.ipen.ne.999) return

c
c   reset locpen to current pen status
c
      if (locpen.eq.1) then
         if (penup) then
            locpen = 3
         else
            locpen = 2
         endif
      elseif (ipen.eq.666) then
         locpen = 999
         ipen = 999
      endif

c
c   set up for move or draw
c     output 'x y'
c
      call pliout (nint(x*fac*ires))
      call plcout (char(32))
      call pliout (nint(y*fac*ires))

c
c   pen down - draw
c
      if (locpen.eq.2) then
         call plsout (' d\n')
         penup = .false.

c
c   pen up - move
c
      elseif (locpen.eq.3.or.locpen.eq.999) then
         call plsout (' m\n')
         penup = .true.
      endif

      if (ipen.ge.0) then
         xold = x
         yold = y
      else
c
c     set new origin
c
         call plsout ('o\n')
         xold = 0.0
         yold = 0.0
      endif

c
c   close and clean up plot file
c
      if (ipen.eq.999) then
         call plsout ('showpage\n')
         call pldone
      endif

      return
      end
c
c
      subroutine line (x,y,n,k,j,ocsym)
      character strocs
      integer ocsym
      dimension x(1),y(1)
c
c   plot pairs x,y scaled to minimum of
c   x(n*k+1),y(n*k+1), and increment per inch
c   of x(n*(k+1)),y(n*(k+1)).
c
c   x = horizontal array of points
c   y = vertical array of points
c   n = # of pairs of points to ploit in x and y
c   k = plot n points from the 1st, k+1st, 2,k+1st, etc..
c       positions of arrays x and y.
c   j = >0: plot symbol ocsym (hollerith) each jth point
c            with connected line
c   j =  0: plot only the line.
c   j = <0: plot only the symbols each jth point.
c
      n1 = n*k
      im = n1+1
      id = im+k
      if (x(id).eq.0.or.y(id).eq.0) return
      ipen = 2
      m = j
      if (j.lt.0) then
         m = -m
         ipen = 3
      endif
      x1 = (x(1)-x(im))/x(id)
      y1 = (y(1)-y(im))/y(id)
      call plot (x1,y1,3)
      jcnt = 0
      do 10 i = 1, n1, k
         jcnt = jcnt+1
         xp = (x(i)-x(im))/x(id)
         yp = (y(i)-y(im))/y(id)
         if (j.ne.0) then
            if (m.ne.jcnt) go to 10
            jcnt = 0
         endif
         call plot (xp,yp,ipen)
         if (j.ne.0) then
            strocs = char(ocsym)
            call symbol (xp,yp,.14,strocs,0.,-1)
            call plot (xp,yp,3)
         endif
   10 continue
      return
      end
c
c
      subroutine dshlin (x,y,n,dsh,gap,nsec)
      integer pen
      dimension x(1),y(1),dsh(1),gap(1)
c
      if (nsec.ne.0) then
c
c     initialize
c
         k = 1
         pen = 2
         s = 0.0
         t = dsh(1)
         xmin = x(n+1)
         xinc = x(n+2)
         ymin = y(n+1)
         yinc = y(n+2)
c
c     move to first point
c
         x2 = (x(1)-xmin)/xinc
         y2 = (y(1)-ymin)/yinc
         call plot (x2,y2,3)
c
c     plot dashed line curve
c
         do 20 i = 2, n
   10       x1 = x2
            y1 = y2
            x2 = (x(i)-xmin)/xinc
            y2 = (y(i)-ymin)/yinc
            d = sqrt((x2-x1)**2+(y2-y1)**2)
            s = s+d
            if (s.ge.t) then
               x2 = x2+(x1-x2)*(s-t)/d
               y2 = y2+(y1-y2)*(s-t)/d
               call plot (x2,y2,pen)
               pen = 5-pen
               s = 0.0
               t = gap(k)
               if (pen.eq.3) go to 10
               k = mod(k,nsec)+1
               t = dsh(k)
               go to 10
            endif
            call plot (x2,y2,pen)
   20    continue
         return
      endif
      call line (x,y,n,1,0,0)
      return
      end
c
c
      subroutine symbol (xin,yin,ht,cstr,ang,nchin)
      real xin,yin,ht,ang
      integer nchin
c
c   symbol subroutine conforming to
c     'programming calcomp electromechanical plotters', 1976
c   for postscript printers, using adobe courier font and font metrics
c
c   rex sanders, usgs, 3/87  jim blake 06/88
c

      common /cqpbnf/ xold,yold,fac,ires
      save /cqpbnf/
      real xold,yold,fac
      integer ires

      real x,y
      real cosang,sinang
      integer nch,i,ic,intang

c           cfudge - courier font fudge factor to get proper height
c
      real cfudge
      save cfudge

      character*(*) cstr


c     data cfudge / 1.66666666 / <-- Too big
      data cfudge / 1.20000000 /
c
c   bad input check
c
      if (nchin.lt.-2.or.ht.le.0.0) return
c
c check for calcomp on-center symbols.
c
      if (ichar(cstr(1:1)).ge.0.and.ichar(cstr(1:1)).le.25) then
         return
      endif
c
c   initialize lots of stuff
c
      x = xin-ht/4.0
      y = yin-ht/4.0
      nch = nchin
      call plot (x,y,3)
c
c   round angle to integer - good to 1 degree
c
      intang = nint(ang)
      cosang = cos(float(intang)*0.017453292519)
      sinang = sin(float(intang)*0.017453292519)
c
c   set char height
c
      call pliout (nint(ht*cfudge*fac*ires))
      call plsout (' h ')
c
c   plot a string of characters
c
      if (nch.gt.0) then
c
c     set char angle
c
         if (intang.ne.0) then
            call pliout (intang)
            call plsout (' rs ')
         endif

c
c     output '(string) s ', escape ( ) \
c
         call plcout (char(40))

         do 10 i = 1, nch
            ic = mod(ichar(cstr(i:i)),127)
            if (ic.eq.40.or.ic.eq.41.or.ic.eq.92) then
               call plcout (char(92))
            endif
            call plcout (cstr(i:i))
   10    continue

         call plsout (') s ')

c
c       update our idea of where the pen is.
c
         xold = x+(nch*ht*fac*cosang)
         yold = y+(nch*ht*fac*sinang)
c
c     undo character angle
c
         if (intang.ne.0) then
            call plsout ('re\n')
         else
            call plsout ('\n')
         endif

c
c   plot one char in strin
c
      elseif (nch.eq.0) then
c
c     set char angle
c
         if (intang.ne.0) then
            call pliout (intang)
            call plsout (' rs ')
         endif

c
c     output '(c) s ', escape '(' and ')' and '\'
c
         call plcout (char(40))
         ic = mod(ichar(cstr(1:1)),127)
         if (ic.eq.40.or.ic.eq.41.or.ic.eq.92) then
            call plcout (char(92))
         endif
         call plcout (cstr(1:1))
         call plsout (') s ')

c
c   update our idea of where the pen is.
c
         xold = x+(ht*fac*cosang)
         yold = y+(ht*fac*sinang)
c
c     undo character angle
c
         if (intang.ne.0) then
            call plsout ('re\n')
         else
            call plsout ('\n')
         endif
      endif

      return
      end
c
c
      subroutine factor (f)
      real f
c
c  sets plot sizing factor -
c    if f = 2.0 then all subsequent pen movements will be twice normal s
c    if f is reset to 1.0, all plotting returns to normal size
c

      common /cqpbnf/ xold,yold,fac,ires
      save /cqpbnf/
      real xold,yold,fac
      integer ires

      fac = f
      return
      end
c
c
      subroutine newpen (ipen)
      integer ipen
c
c  selects new pen as indicated by ipen
c  where:
c     ipen = 1..n indicating pen 1 - n
c  simulated by changing line width for postscript printers
c

      integer npen
      integer usepen
      integer savpen
      save savpen
      data savpen / 1 /

      npen = max(ipen,1)
      if (npen.ne.savpen) then
c
c     want pen width to be odd number of pixels wide
c
         usepen = ((npen-1)*2)+1
         call pliout (usepen)
         call plsout (' w\n')

         savpen = npen
      endif

      return
      end
