*------------- Telecommunications & Signal Processing Lab --------------
*                          McGill University
*
*
* Module:
*     SUBROUTINE LOGTIC (XMIN, XMAX, ATICK, ALABEL, NTICK)
*
*
* Purpose:
*     Generate axis ticks and labels for a log plot
*
*
* Description:
*     This subroutine finds an appropriate scale for plotting data
*     on a logarithmic scale.  The output is an array of values
*     corresponding to tick values and the labels corresponding to the
*     tick values.
*
*     Consider a data with a range from Xmin to Xmax.  For example with
*     Xmin=1 and Xmax=1000, the data extends over 3 decades.   The
*     problem is to determine appropriate positions for the axis ticks.
*     Ticks at 1, 10, 100 and 1000 correspond to the decade points.
*     The corresponding labels are "1", "10", "100", and "1000".
*     Intermediate ticks are be placed between decades.  For the
*     decade between 10 and 1000, ticks are placed at the values of 20,
*     30, ..., 90.  The convention is to label only the 2*10**n and the
*     5*10**n points (here 20 and 50), since these are approximately
*     equally spaced between decades.
*
*     The algorithm used to generate tick values and labels is as
*     follows.  The data range is extended to be an integral number
*     of decades that includes Xmin and Xmax.  The range is set to be
*     at least one decade.  The decade points are always labelled.
*     Depending on the number of decades, intermediate values may get
*     labelled.

*     The following table shows which ticks get labelled in each decade
*     (the I symbol indicates a longer tick than a | symbol).
*
*       No. Decades       Ticks and Labels in each Decade
*
*          1              I       I  I  I  I  I I I I I
*                        10^n     2  3  4  5  6 7 8 9 10^(n+1)
*
*         2-4             I       I  |  |  I  | | | | I
*                        10^n     2        5         10^(n+1)
*
*         5-7             I       I  |  |  I  | | | | I
*                        10^n                        10^(n+1)
*
*         8-10            I       |        |          I
*                        10^n                        10^(n+1)
*
*         11-20           I                           I
*                        10^n                        10^(n+1)
*
*     In the general case, the decades are marked with a power of 10
*     notation and the intermediate values are given as integers.
*     If the intermediate points are given, these are printed in a
*     character size that is slightly smaller than the decade points.
*     A special case occurs if there are 1-4 decades.  Then if
*     Xmin>=0.1 and Xmax<=1000, the labels give the numbers directly.
*
*
* Parameters:
* R ->  XMIN   - Minimum value
* R ->  XMAX   - Maximum value
* R <-  ATICK  - Array of values corresponding to the ticks
* C <-  ALABEL - Character array of labels corresponding to the ticks.
*                These are in one-to-one correspondence with the array
*                of tick values.  Each element of the array ALABEL
*                should allow for least 10 characters (includes space
*                for control characters).  Each of the generated labels
*                is terminated with a null character if it is shorter
*                than the length of the array elements.
* I <-  NTICK  - Number of elements in each of the arrays ATICK and
*                ALABEL. NTICK may be as large as 64. In case of error,
*                NTICK=0.
*
*
* Author / revision:
*     P. Kabal
*     $Revision: 1.7 $  $Date: 1995/03/08 15:28:03 $
*
*
*-----------------------------------------------------------------------

      SUBROUTINE LOGTIC (XMIN, XMAX, ATICK, ALABEL, NTICK)


      INTEGER NULL,TICK,BTICK,VALUE,P10
      PARAMETER (NULL=0,TICK=1,BTICK=2,VALUE=3,P10=4)
      INTEGER ICSML,ICSUP,ICNOR
      PARAMETER (ICSML=11,ICSUP=15,ICNOR=14)
      INTEGER NPL
      PARAMETER (NPL=6)

      CHARACTER*1 VT,SI,SO,NUL
      CHARACTER*(NPL) CSTR
      CHARACTER*(*) ALABEL(*)

      INTEGER NTICK
      INTEGER ILMAX,ILMIN,NDEC,MODE,NTD,K,I,IL,NC
      INTEGER ICEILX,IFLORX

      LOGICAL TV

      REAL XMIN,XMAX
      REAL ATICK(*)
      REAL XLMIN,XLMAX,P

* Coding tables
      INTEGER NTDEC(5)
      REAL VAL(9,5)
      INTEGER ICODE(9,5)

      DATA NTDEC/9,9,9,3,1/
      DATA VAL/
     -  1.,2.,3.,4.,5.,6.,7.,8.,9.,
     -  1.,2.,3.,4.,5.,6.,7.,8.,9.,
     -  1.,2.,3.,4.,5.,6.,7.,8.,9.,
     -  1.,2.,      5.,             0.,0.,0.,0.,0.,0.,
     -  1.,                         0.,0.,0.,0.,0.,0.,0.,0./
      DATA ICODE/
     -    P10, VALUE,VALUE,VALUE,VALUE,VALUE,VALUE,VALUE,VALUE,
     -    P10, VALUE, TICK, TICK,VALUE, TICK, TICK, TICK, TICK,
     -    P10, BTICK, TICK, TICK,BTICK, TICK, TICK, TICK, TICK,
     -    P10,  TICK, TICK, NULL, NULL, NULL, NULL, NULL, NULL,
     -    P10,  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL/


* Find the number of decades needed to span the data
      IF (XMIN.LE.0.0 .OR. XMAX.LE.0.0) THEN
        CALL WARN('LOGTIC - Error, negative values for log scale')
        NTICK=0
        GO TO 900
      END IF
      XLMIN=LOG10(XMIN)
      XLMAX=LOG10(XMAX)
      ILMAX=ICEILX( MAX(XLMIN,XLMAX) )
      ILMIN=IFLORX( MIN(XLMIN,XLMAX) )
      IF (ILMIN.EQ.ILMAX) ILMAX=ILMIN+1
      NDEC=ILMAX-ILMIN

* Find the mode in which to print the labels
      IF (NDEC.EQ.1) THEN
        MODE=1
      ELSE IF (NDEC.LE.4) THEN
        MODE=2
      ELSE IF (NDEC.LE.7) THEN
        MODE=3
      ELSE IF (NDEC.LE.10) THEN
        MODE=4
      ELSE IF (NDEC.LE.20) THEN
        MODE=5
      ELSE
        CALL WARN('LOGTIC - Too many decades')
        NTICK=0
        GO TO 900
      END IF

      TV=ILMIN.GE.-1 .AND. ILMAX.LE.3
      VT=CHAR(ICSML)
      SI=CHAR(ICSUP)
      SO=CHAR(ICNOR)
      NUL=CHAR(0)

      NTD=NTDEC(MODE)
      NTICK=NTD*NDEC+1
      DO 100 K=1,NTICK
        I=MOD(K-1,NTD)+1
        IL=(K-1)/NTD+ILMIN
        P=10.**IL

* Fill in the tick array
        ATICK(K)=P*VAL(I,MODE)

* Generate the character string for each label
        IF (ICODE(I,MODE).EQ.TICK) THEN
          ALABEL(K)=NUL

        ELSE IF (ICODE(I,MODE).EQ.BTICK) THEN
          ALABEL(K)=' '//NUL

        ELSE IF (ICODE(I,MODE).EQ.VALUE) THEN
          IF (TV) THEN
            CALL LABEL(P*VAL(I,MODE),NPL,CSTR,NC)
          ELSE
            CALL LABEL(VAL(I,MODE),NPL,CSTR,NC)
          END IF
          ALABEL(K)=VT//CSTR(1:NC)//NUL

        ELSE IF (ICODE(I,MODE).EQ.P10) THEN
          IF (TV) THEN
            CALL LABEL(P*VAL(I,MODE),NPL,CSTR,NC)
            ALABEL(K)=CSTR(1:NC)//NUL
          ELSE IF (IL.EQ.0) THEN
            ALABEL(K)=SI//' '//SO//'1'//SI//' '//NUL
          ELSE IF (IL.EQ.1) THEN
            ALABEL(K)=SI//' '//SO//'10'//SI//' '//NUL
          ELSE
            CALL LABEL(REAL(IL),NPL,CSTR,NC)
            ALABEL(K)='10'//SI//CSTR(1:NC)//NUL
          END IF
        END IF
 100  CONTINUE


 900  RETURN

      END
