subroutine greg_axis(line,error)
  use gbl_message
  use greg_dependencies_interfaces
  use greg_interfaces, except_this=>greg_axis
  use greg_axes
  use greg_kernel
  use greg_pen
  use greg_types
  use greg_wcs
  !---------------------------------------------------------------------
  ! @ private
  ! GREG Support routines for commands
  !   AXIS  XLow|XUp|YLeft|YRight [A1 A2]
  ! 1       /TICK ICLOCK SMALL BIG
  ! 2       /LABEL POSITION [FORMAT]
  ! 3       /LOCATION   X Y LENGTH
  ! 4-5     /[NO]LOGARITHM
  ! 6       /ABSOLUTE
  ! 7       /UNIT Angle
  ! 8-9     /[NO]BRIEF
  ! --- to be implemented ---
  !                       /WINDOW AMIN AMAX
  !   TICKSPACE  [X SMALL BIG]  [Y SMALL BIG]
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: line   ! Command line
  logical,          intent(inout) :: error  ! Logical error flag
  ! Global
  include 'gbl_pi.inc'
  ! Local
  character(len=*), parameter :: rname='AXIS'
  logical :: notick
  real(kind=8) :: a1,a2,a,small,big
  type(axis_t) :: axis
  real(kind=4) :: ax,ay,alen
  integer(kind=4) :: inum
  character(len=1) :: clock,clabel
  character(len=80) :: chain
  character(len=2) :: arg1
  character(len=12) :: argum,name,angu(4)
  integer(kind=4) :: c_angle,n,nc
  ! Data
  data angu/'SECOND','MINUTE','DEGREE','RADIAN'/
  !
  call sic_ke (line,0,1,arg1,nc,.true.,error)
  if (error) return
  !
  ! Default is: decimal notation
  axis%label%format = format_decimal
  !
  if (arg1.eq.'XL') then
    !
    ! No projection, No System : Nothing
    if (gproj%type.eq.p_none .and. i_system.eq.type_un .and. sic_present(6,0)) then
      call greg_message(seve%w,rname,'/ABSOLUTE coordinates ignored when '//  &
      'no projection')
      a1 = gux1
      a2 = gux2
      !
    elseif (sic_present(6,0)) then
      ! Absolute labelling
      if (abs(gux2-gux1).gt.0.2 .and. gproj%type.ne.p_none) then
        ! See remark in subroutine greg_box
        call greg_message(seve%e,rname,'Field of view is too large for '//  &
        'absolute labelling')
        goto 10
      endif
      if (i_system.eq.type_eq .or. i_system.eq.type_ic) then
        a1 = (axrem1+axrem2)*0.5d0/pi*3.6d3*1.2d1
        a2 = (axrem5+axrem6)*0.5d0/pi*3.6d3*1.2d1
        axis%label%format = format_sexage_hour
        axis%label%format_nd = ndecimx
      else
        if (xsixty.eq.format_decimal) then
          a1 = (axrem1+axrem2)*0.5d0/pi*1.8d2
          a2 = (axrem5+axrem6)*0.5d0/pi*1.8d2
          axis%label%format = format_decimal
        else
          a1 = (axrem1+axrem2)*0.5d0/pi*1.8d2*3.6d3
          a2 = (axrem5+axrem6)*0.5d0/pi*1.8d2*3.6d3
          axis%label%format = format_sexage_none
          if (i_system.eq.type_ga) axis%label%format = format_sexage_degree
          ! The %format_nd field was not defined before...
          axis%label%format_nd = ndecimx
        endif
      endif
      if (gux1.lt.gux2) then
        a = a1
        a1 = a2
        a2 = a
      endif
    else
      !
      ! Relative labelling in current angle unit
      c_angle = u_angle
      if (sic_present(7,0)) then
        call sic_ke (line,7,1,name,nc,.true.,error)
        if (error) goto 10
        call sic_ambigs(rname,name,argum,n,angu,4,error)
        if (error) goto 10
        c_angle = n
      endif
      if (c_angle.eq.u_second) then
        a1 = gux1/pi*3.6d3*1.8d2
        a2 = gux2/pi*3.6d3*1.8d2
      elseif (c_angle.eq.u_minute) then
        a1 = gux1/pi*6.0d1*1.8d2
        a2 = gux2/pi*6.0d1*1.8d2
      elseif (c_angle.eq.u_degree) then
        a1 = gux1/pi*1.8d2
        a2 = gux2/pi*1.8d2
      else
        a1 = gux1
        a2 = gux2
      endif
    endif
    axis%angle = tangle*pi/180.d0
    small  = smallx
    big    = bigx
    axis%loga = axis_xlog
    ax     = gx1
    ay     = gy1
    alen   = gx2-gx1
    inum   = 1
    axis%doline  = .true.
    axis%dolabel = .true.
    axis%label%justif = 1
    if (axis%label%format.eq.format_decimal) then
      axis%label%brief = axis_xdecim_brief
    else
      axis%label%brief = axis_xsexag_brief
    endif
    axis%label%expo = axis_xexpo
    !
  elseif (arg1.eq.'XU') then
    !
    ! No projection
    if (gproj%type.eq.p_none .and. i_system.eq.type_un .and. sic_present(6,0)) then
      call greg_message(seve%w,rname,'/ABSOLUTE coordinates ignored when '//  &
      'no projection')
      a1 = gux1
      a2 = gux2
      !
      ! Absolute labelling
    elseif (sic_present(6,0)) then
      if (abs(gux2-gux1).gt.0.2 .and. gproj%type.ne.p_none) then
        ! See remark in subroutine greg_box
        call greg_message(seve%e,rname,'Field of view is too large for '//  &
        'absolute labelling')
        goto 10
      endif
      if (i_system.eq.type_eq .or. i_system.eq.type_ic) then
        a1 = (axrem1+axrem2)*0.5d0/pi*3.6d3*1.2d1
        a2 = (axrem5+axrem6)*0.5d0/pi*3.6d3*1.2d1
        axis%label%format = format_sexage_hour
        axis%label%format_nd = ndecimx
      else
        if (xsixty.eq.format_decimal) then
          a1 = (axrem1+axrem2)*0.5d0/pi*1.8d2
          a2 = (axrem5+axrem6)*0.5d0/pi*1.8d2
          axis%label%format = format_decimal
        else
          a1 = (axrem1+axrem2)*0.5d0/pi*1.8d2*3.6d3
          a2 = (axrem5+axrem6)*0.5d0/pi*1.8d2*3.6d3
          axis%label%format = format_sexage_none
          if (i_system.eq.type_ga) axis%label%format = format_sexage_degree
          ! The %format_nd field was not defined before...
          axis%label%format_nd = ndecimx
        endif
      endif
      if (gux1.lt.gux2) then
        a = a1
        a1 = a2
        a2 = a
      endif
    else
      !
      ! Relative labelling in current angle unit
      c_angle = u_angle
      if (sic_present(7,0)) then
        call sic_ke (line,7,1,name,nc,.true.,error)
        if (error) goto 10
        call sic_ambigs(rname,name,argum,n,angu,4,error)
        if (error) goto 10
        c_angle = n
      endif
      if (c_angle.eq.u_second) then
        a1 = gux1/pi*3.6d3*1.8d2
        a2 = gux2/pi*3.6d3*1.8d2
      elseif (c_angle.eq.u_minute) then
        a1 = gux1/pi*6.0d1*1.8d2
        a2 = gux2/pi*6.0d1*1.8d2
      elseif (c_angle.eq.u_degree) then
        a1 = gux1/pi*1.8d2
        a2 = gux2/pi*1.8d2
      else
        a1 = gux1
        a2 = gux2
      endif
    endif
    axis%angle = tangle*pi/180.d0
    small  = smallx
    big    = bigx
    axis%loga = axis_xlog
    ax     = gx1
    ay     = gy2
    alen   = gx2-gx1
    inum   = 3
    axis%doline  = .true.
    axis%dolabel = .false.
    axis%label%justif = 1
    if (axis%label%format.eq.format_decimal) then
      axis%label%brief = axis_xdecim_brief
    else
      axis%label%brief = axis_xsexag_brief
    endif
    axis%label%expo = axis_xexpo
    !
  elseif (arg1.eq.'YL') then
    !
    ! No projection
    if (gproj%type.eq.p_none .and. i_system.eq.type_un .and. sic_present(6,0)) then
      call greg_message(seve%w,rname,'/ABSOLUTE coordinates ignored when '//  &
      'no projection')
      a1 = guy1
      a2 = guy2
      !
      ! Absolute labelling
    elseif (sic_present(6,0)) then
      if (abs(guy2-guy1).gt.0.2 .and. gproj%type.ne.p_none) then
        ! See remark in subroutine greg_box
        call greg_message(seve%e,rname,'Field of view is too large for '//  &
        'absolute labelling')
        goto 10
      endif
      if (i_system.eq.type_eq .or. i_system.eq.type_ic) then
        a1 = (ayrem1+ayrem5)*0.5d0/pi*3.6d3*1.8d2
        a2 = (ayrem2+ayrem6)*0.5d0/pi*3.6d3*1.8d2
        axis%label%format = format_sexage_degree
        axis%label%format_nd = ndecimy
      else
        if (ysixty.eq.format_decimal) then
          a1 = (ayrem1+ayrem5)*0.5d0/pi*1.8d2
          a2 = (ayrem2+ayrem6)*0.5d0/pi*1.8d2
          axis%label%format = format_decimal
        else
          a1 = (ayrem1+ayrem5)*0.5d0/pi*1.8d2*3.6d3
          a2 = (ayrem2+ayrem6)*0.5d0/pi*1.8d2*3.6d3
          axis%label%format = format_sexage_none
          if (i_system.eq.type_ga) axis%label%format = format_sexage_degree
          ! The %format_nd field was not defined before...
          axis%label%format_nd = ndecimy
        endif
      endif
      if (guy1.gt.guy2) then
        a = a1
        a1 = a2
        a2 = a
      endif
    else
      !
      ! Relative labelling in current angle unit
      c_angle = u_angle
      if (sic_present(7,0)) then
        call sic_ke (line,7,1,name,nc,.true.,error)
        if (error) goto 10
        call sic_ambigs(rname,name,argum,n,angu,4,error)
        if (error) goto 10
        c_angle = n
      endif
      if (c_angle.eq.u_second) then
        a1 = guy1/pi*3.6d3*1.8d2
        a2 = guy2/pi*3.6d3*1.8d2
      elseif (c_angle.eq.u_minute) then
        a1 = guy1/pi*6.0d1*1.8d2
        a2 = guy2/pi*6.0d1*1.8d2
      elseif (c_angle.eq.u_degree) then
        a1 = guy1/pi*1.8d2
        a2 = guy2/pi*1.8d2
      else
        a1 = guy1
        a2 = guy2
      endif
    endif
    axis%angle = (tangle+90.d0)*pi/180.d0
    small  = smally
    big    = bigy
    axis%loga = axis_ylog
    ax     = gx1
    ay     = gy1
    alen   = gy2-gy1
    inum   = 5
    axis%doline  = .true.
    axis%dolabel = .true.
    axis%label%justif = just(5)
    if (axis%label%format.eq.format_decimal) then
      axis%label%brief = axis_ydecim_brief
    else
      axis%label%brief = axis_ysexag_brief
    endif
    axis%label%expo = axis_yexpo
    !
  elseif (arg1.eq.'YR') then
    !
    ! No projection
    if (gproj%type.eq.p_none .and. i_system.eq.type_un .and. sic_present(6,0)) then
      call greg_message(seve%w,rname,'/ABSOLUTE coordinates ignored when '//  &
      'no projection')
      a1 = guy1
      a2 = guy2
      !
      ! Absolute labelling
    elseif (sic_present(6,0)) then
      if (abs(guy2-guy1).gt.0.2 .and. gproj%type.ne.p_none) then
        ! See remark in subroutine greg_box
        call greg_message(seve%e,rname,'Field of view is too large for '//  &
        'absolute labelling')
        goto 10
      endif
      if (i_system.eq.type_eq .or. i_system.eq.type_ic) then
        a1 = (ayrem1+ayrem5)*0.5d0/pi*3.6d3*1.8d2
        a2 = (ayrem2+ayrem6)*0.5d0/pi*3.6d3*1.8d2
        axis%label%format = format_sexage_degree
        axis%label%format_nd = ndecimy
      else
        if (ysixty.eq.format_decimal) then
          a1 = (ayrem1+ayrem5)*0.5d0/pi*1.8d2
          a2 = (ayrem2+ayrem6)*0.5d0/pi*1.8d2
          axis%label%format = format_decimal
        else
          a1 = (ayrem1+ayrem5)*0.5d0/pi*1.8d2*3.6d3
          a2 = (ayrem2+ayrem6)*0.5d0/pi*1.8d2*3.6d3
          axis%label%format = format_sexage_none
          if (i_system.eq.type_ga) axis%label%format = format_sexage_degree
          ! The %format_nd field was not defined before...
          axis%label%format_nd = ndecimy
        endif
      endif
      if (guy1.gt.guy2) then
        a = a1
        a1 = a2
        a2 = a
      endif
    else
      !
      ! Relative labelling in current angle unit
      c_angle = u_angle
      if (sic_present(7,0)) then
        call sic_ke (line,7,1,name,nc,.true.,error)
        if (error) goto 10
        call sic_ambigs(rname,name,argum,n,angu,4,error)
        if (error) goto 10
        c_angle = n
      endif
      if (c_angle.eq.u_second) then
        a1 = guy1/pi*3.6d3*1.8d2
        a2 = guy2/pi*3.6d3*1.8d2
      elseif (c_angle.eq.u_minute) then
        a1 = guy1/pi*6.0d1*1.8d2
        a2 = guy2/pi*6.0d1*1.8d2
      elseif (c_angle.eq.u_degree) then
        a1 = guy1/pi*1.8d2
        a2 = guy2/pi*1.8d2
      else
        a1 = guy1
        a2 = guy2
      endif
    endif
    axis%angle = (tangle+90.d0)*pi/180.d0
    small  = smally
    big    = bigy
    ax     = gx2
    ay     = gy1
    alen   = gy2-gy1
    axis%loga = axis_ylog
    inum   = 7
    axis%doline  = .true.
    axis%dolabel = .false.
    axis%label%justif = just(7)
    if (axis%label%format.eq.format_decimal) then
      axis%label%brief = axis_ydecim_brief
    else
      axis%label%brief = axis_ysexag_brief
    endif
    axis%label%expo = axis_yexpo
    !
  else
    chain = 'Invalid argument '//arg1
    call greg_message(seve%e,rname,chain)
    goto 10
  endif
  axis%label%offset = 1.
  call sic_r8 (line,0,2,a1,.false.,error)
  if (error) goto 10
  call sic_r8 (line,0,3,a2,.false.,error)
  if (error) goto 10
  !
  ! /TICK [In/Out/None] [SMALL] [BIG]
  notick = .false.
  if (sic_present(1,0)) then
    call sic_ke (line,1,1,clock,nc,.false.,error)
    if (error) goto 10
    if (clock.eq.'O') then
      inum = inum+1
      axis%label%offset = -2.
    elseif (clock.eq.'N') then
      notick = .true.
    elseif (clock.ne.'I') then
      call greg_message(seve%e,rname,'Invalid parameter for /TICK option')
      goto 10
    endif
    call sic_r8 (line,1,2,small,.false.,error)
    if (error) goto 10
    call sic_r8 (line,1,3,big,.false.,error)
    if (error) goto 10
  endif
  !
  ! /LABEL
  if (sic_present(2,0)) then
    call sic_ke (line,2,1,clabel,nc,.false.,error)
    if (error) goto 10
    if (clabel.eq.'N') then      ! No labels
      axis%dolabel = .false.
    elseif (clabel.eq.'P') then  ! Parallel
      axis%dolabel = .true.
      axis%label%justif = 1
    elseif (clabel.eq.'O') then  ! Orthogonal
      axis%dolabel = .true.
      axis%label%justif = just(inum)
    else
      chain = 'Invalid argument '//clabel
      call greg_message(seve%e,rname,chain)
      goto 10
    endif
    if (notick .and. clabel.ne.'N') then
      call greg_message(seve%e,rname,  &
        'Conflicting options : /TICKS None and /LABEL')
    endif
    !
    clabel = ' '
    call sic_ke (line,2,2,clabel,nc,.false.,error)
    if (error) goto 10
    if (clabel.eq.'O')  axis%doline = .false.
  endif
  !
  ! /LOCATION
  if (sic_present(3,0)) then
    call sic_r4 (line,3,1,ax,.false.,error)
    if (error) goto 10
    call sic_r4 (line,3,2,ay,.false.,error)
    if (error) goto 10
    call sic_r4 (line,3,3,alen,.false.,error)
    if (error) goto 10
  endif
  !
  ! /LOGARITHM
  if (sic_present(4,0)) axis%loga = .true.
  !
  ! /NOLOG
  if (sic_present(5,0)) then
    if (sic_present(4,0)) then
      call greg_message(seve%e,rname,'Conflicting options /LOG and /NOLOG')
      goto 10
    endif
    axis%loga = .false.
  endif
  !
  ! /[NO]BRIEF
  if (sic_present(8,0)) then
    if (sic_present(9,0)) then
      call greg_message(seve%e,rname,'Conflicting options /BRIEF and /NOBRIEF')
      goto 10
    endif
    axis%label%brief = .true.
  elseif (sic_present(9,0)) then
    axis%label%brief = .false.
  endif
  !
  axis%tdirect = jclock(inum)
  call setdas(1)
  if (notick) then
    call grelocate(ax,ay)
    ax = ax+alen*cos(axis%angle)
    ay = ay+alen*sin(axis%angle)
    call gdraw(ax,ay)
  else
    call plot_axis(a1,a2,small,big,ax,ay,alen,axis,error)
  endif
  return
  !
10 continue
  error = .true.
end subroutine greg_axis
!
subroutine greg_rule(line,error)
  use greg_dependencies_interfaces
  use greg_interfaces, except_this=>greg_rule
  use gbl_message
  !---------------------------------------------------------------------
  ! @ private
  ! GREG Support for command RULE
  !  RULE [X] [Y] [/MAJOR] [/MINOR]
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: line   !
  logical,          intent(inout) :: error  !
  ! Local
  character(len=*), parameter :: rname='RULE'
  character(len=4) :: chain
  integer(kind=4) :: ixy,nc
  logical :: lx,ly,lmajor,lminor
  !
  ! Rule X and/or Y ticks. Default is ticking both X and Y ticks.
  lx = .false.
  ly = .false.
  if (sic_present(0,1)) then
    call sic_ke (line,0,1,chain,nc,.false.,error)
    if (error) goto 10
    if (chain.eq.'X') then
      lx = .true.
    elseif (chain.eq.'Y') then
      ly = .true.
    else
      goto 10
    endif
  endif
  if (sic_present(0,2)) then
    call sic_ke (line,0,2,chain,nc,.false.,error)
    if (error) goto 10
    if (chain.eq.'X') then
      lx = .true.
    elseif (chain.eq.'Y') then
      ly = .true.
    else
      goto 10
    endif
  endif
  if (lx.and.ly) then
    ixy = 3
  elseif (lx) then
    ixy = 1
  elseif (ly) then
    ixy = 2
  else
    ixy = 3
  endif
  !
  ! Rule Major or Minor ticks ? Default is Major only.
  lmajor = sic_present(1,0)
  lminor = sic_present(2,0)
  if (.not.lmajor .and. .not.lminor) lmajor = .true.
  !
  if (lmajor) call rulexy (.true.,ixy,error)
  if (lminor) call rulexy (.false.,ixy,error)
  return
  !
10 continue
  call greg_message(seve%e,rname,  &
    'Invalid Arguments. Valid arguments are X or Y.')
  error = .true.
end subroutine greg_rule
!
subroutine rulexy(major,ixy,error)
  use phys_const
  use greg_interfaces, except_this=>rulexy
  use greg_axes
  use greg_kernel
  use greg_types
  use greg_wcs
  !---------------------------------------------------------------------
  ! @ private
  ! GREG Support routine for command
  !  RULE [X] [Y] [/MAJOR] [/MINOR]
  ! Arguments :
  !  IXY    For ruling X or Y ticks
  !    1 Rule X ticks
  !    2 Rule Y ticks
  !    3 Rule both X and Y ticks
  !---------------------------------------------------------------------
  logical,         intent(in)    :: major  ! T for lines at labelled ticks, F for all ticks
  integer(kind=4), intent(in)    :: ixy    ! For ruling X or Y ticks (1:X, 2:Y, 3:both)
  logical,         intent(inout) :: error  ! Logical flag
  ! Local
  type(axis_t) :: axis  ! Axis description
  !
  if (ixy.eq.1 .or. ixy.eq.3) then
    axis%angle = 0.d0
    axis%loga = axis_xlog
    axis%glength = gy2 - gy1
    axis%gmajor = major
    axis%ghoriz = .false.
    ! Label format has influence on major tick position. Duplicate.
    if (i_system.eq.type_eq .or. i_system.eq.type_ic) then
      axis%label%format = format_sexage_hour
    else
      if (xsixty.eq.format_decimal) then
        axis%label%format = format_decimal
      else
        axis%label%format = format_sexage_none
        if (i_system.eq.type_ga) axis%label%format = format_sexage_degree
      endif
    endif
    axis%label%justif = 1
    axis%label%brief = .false.
    !
    call plot_at_tick(gux1,gux2,smallx,bigx,gx1,gy1,gx2-gx1,axis,plot_rulexy,error)
    if (error)  return
  endif
  !
  if (ixy.eq.2 .or. ixy.eq.3) then
    axis%angle = pi/2.d0
    axis%loga = axis_ylog
    axis%glength = gx2 - gx1
    axis%gmajor = major
    axis%ghoriz = .true.
    ! Label format has influence on major tick position. Duplicate.
    if (i_system.eq.type_eq .or. i_system.eq.type_ic) then
      axis%label%format = format_sexage_hour
    else
      if (ysixty.eq.format_decimal) then
        axis%label%format = format_decimal
      else
        axis%label%format = format_sexage_none
        if (i_system.eq.type_ga) axis%label%format = format_sexage_degree
      endif
    endif
    axis%label%justif = just(5)
    axis%label%brief = .false.
    !
    call plot_at_tick(guy1,guy2,smally,bigy,gx1,gy1,gy2-gy1,axis,plot_rulexy,error)
    if (error)  return
  endif
  !
end subroutine rulexy
!
subroutine plot_axis(a1,a2,small,big,ax,ay,alen,axis,error)
  use greg_interfaces, except_this=>plot_axis
  use greg_kernel
  use greg_types
  !---------------------------------------------------------------------
  ! @ private
  !  Plot an axis: line+ticks and/or tick labels
  !---------------------------------------------------------------------
  real(kind=8), intent(in)    :: a1     ! User coordinate value at start point of axis
  real(kind=8), intent(in)    :: a2     ! User coordinate value at end point of axis
  real(kind=8), intent(in)    :: small  ! Minor tick space
  real(kind=8), intent(in)    :: big    ! Major (labelled) tick space
  real(kind=4), intent(in)    :: ax     ! Page coordinates of start point of axis
  real(kind=4), intent(in)    :: ay     ! Page coordinates of start point of axis
  real(kind=4), intent(in)    :: alen   ! Length of axis
  type(axis_t), intent(inout) :: axis   ! Parameters for labels and ticks
  logical,      intent(inout) :: error  ! Error flag
  ! Global
  include 'gbl_pi.inc'
  ! Local
  real(kind=4) :: ax2,ay2
  !
  ax2 = alen*cos(axis%angle) + ax
  ay2 = alen*sin(axis%angle) + ay
  !
  if (axis%doline) then
    !
    ! Plot axis
    call grline(ax2,ay2,ax,ay)
    !
    ! Plot ticks
    call plot_at_tick(a1,a2,small,big,ax,ay,alen,axis,plot_tickmark,error)
    if (error) return
  endif
  !
  if (axis%dolabel) then
    ! Write labels
    call plot_at_tick(a1,a2,small,big,ax,ay,alen,axis,plot_ticklabel,error)
  endif
  !
end subroutine plot_axis
!
subroutine plot_at_tick(a1,a2,small,big,ax,ay,alen,axis,func,error)
  use gbl_message
  use greg_interfaces, except_this=>plot_at_tick
  use greg_kernel
  use greg_types
  !---------------------------------------------------------------------
  ! @ private
  !  Execute the input function at each tick position
  !---------------------------------------------------------------------
  real(kind=8), intent(in)    :: a1     ! User coordinate value at start point of axis
  real(kind=8), intent(in)    :: a2     ! User coordinate value at end point of axis
  real(kind=8), intent(in)    :: small  ! Minor tick space
  real(kind=8), intent(in)    :: big    ! Major (labelled) tick space
  real(kind=4), intent(in)    :: ax     ! Page X coordinates of start point of axis
  real(kind=4), intent(in)    :: ay     ! Page Y coordinates of start point of axis
  real(kind=4), intent(in)    :: alen   ! Length of axis
  type(axis_t), intent(inout) :: axis   ! Parameters for labels and ticks
  external                    :: func   ! Tick drawing function
  logical,      intent(inout) :: error  ! Logical flag
  ! Global
  include 'gbl_pi.inc'
  ! Local
  character(len=*), parameter :: rname='AXIS'
  real(kind=4) :: rsmall
  real(kind=8) :: val(6),ax1,ax2,tickpos,off,step,adiff,diff,dx
  real(kind=4) :: sine,cosine,amant
  real(kind=4) :: xlen
  logical :: first,lbrief
  integer(kind=4) :: nch,nlabel,nsmall
  integer(kind=4) :: iexp,num,i,j,n1,n2,smstep
  logical :: dolog
  type(tick_t) :: tick
  ! Data
  ! Tick locations for a logarithmic axis with two decades between major ticks.
  data val /1.d0,2.d0,5.d0,1.d1,2.d1,5.d1/
  !
  ! Logarithmic axis
  if (axis%loga) then
    if (a1.le.0.d0 .or. a2.le.0.d0) then
      call greg_message(seve%e,rname,'Negative limit on logarithmic axis')
      error = .true.
      return
    endif
    ax1 = dlog10(a1)
    ax2 = dlog10(a2)
    nch = 5  ! Was 9 before, but this is more appropriate
    ! Evaluate number of label intervals that can fit on the axis.
    if (axis%label%justif.eq.1) then
      nlabel = int(alen/(nch*cwidth*cdef*expand))
    else
      nlabel = int(alen/(5.*cheight*cdef*expand))
    endif
    ! Compute distance between major ticks in (user) decades
    if (nlabel.gt.0) then
      ! step = 1.d0 * int((ax2-ax1)/nlabel)
      n1 = int(ax1)
      if (ax1.lt.0) n1 = n1-1
      n2 = int(ax2)
      if (ax2.lt.0) n2 = n2-1
      step = 1.d0 * int(abs(n2-n1)/(nlabel+1))
    else
      call greg_message(seve%e,rname,'Character size too big')
      error = .true.
      return
    endif
    ! Number of small ticks depends on (user) distance between big ticks
    ! One decade: minor ticks at every integer
    dolog = .true.  ! Do effective log spacing for ticks
    if (step.le.1.d0) then
      ! Beware that AX2 can be smaller than AX1
      if (int(abs(ax2-ax1)).lt.1d0) then   !
        ! Less than 1 Decade, we have an issue: fall back on "standard" label
        step = 0d0
        dolog = .false.
      else
        step = 1.d0
        nsmall = 10
      endif
      ! Two decades: minor ticks at 2 5 10 20 50 100
    elseif (step.eq.2.d0) then
      nsmall = 6
      ! More than two decades: minor ticks every decade up to 10 decades,
      ! every second up to 20 and so
    else
      smstep = int((step-1)/10)+1
      step = smstep*int(step/smstep)
      nsmall = int(step/smstep)
    endif
  else
    dolog = .false.  ! Don't forget to initialize it...
  endif
  !
  if (dolog) then
    continue                   ! Log axis done...
    ! Linear axis
  elseif (big.gt.0.and.small.gt.0) then
    ax1 = a1
    ax2 = a2
    step = big
    rsmall = abs(step/small)
    if (rsmall.lt.2e2) then
      nsmall = int(rsmall)
    else
      call greg_message(seve%e,rname,'Too many small ticks')
      error = .true.
      return
    endif
    !
    ! Linear axis
  elseif (big.eq.0) then
    ax1 = a1
    ax2 = a2
    nsmall = 5
    nch = 9
    if (axis%label%justif.eq.1) then
      nlabel = int(alen/(nch*cwidth*cdef*expand))
    else
      nlabel = int(alen/(5.*cheight*cdef*expand))
    endif
    !
    ! Sexagesimal label
    if (axis%label%format.ne.format_decimal) then
      if (nlabel.lt.3) nlabel = 3
      adiff = abs(a2-a1)
      if (adiff.lt.10*nlabel) then
        diff  = log10(adiff/nlabel)
        iexp  = diff
        if (diff.lt.0.) iexp = iexp-1
        amant = diff - iexp
        if (amant.eq.0.) then
          num = 1
        elseif (amant.lt..302) then
          num = 2
          nsmall = 4
        elseif (amant.lt..700) then
          num = 5
        else
          num = 1
          iexp = iexp+1
        endif
        axis%label%format_nd = -iexp
        step = num * 1.d1**iexp
      else
        !
        ! IEXP nombre de multiple de 60 -1,0 Secondes 1 Minutes 2 Degres
        ! AMANT mantisse
        diff  = log10(adiff/nlabel)/log10(60.0)
        iexp  = diff
        if (diff.lt.0.) iexp = iexp-1
        amant = diff - iexp
        if (amant.eq.0.) then
          num = 1
          nsmall = 6
        elseif (amant.le.0.171) then   ! log10(2)/log10(60)
          num = 2
          nsmall = 4
        elseif (amant.le.0.395) then   ! log10(5)/log10(60)
          num = 5
          nsmall = 5
        elseif (amant.le.0.564) then   ! log10(10)/log10(60)
          num = 10
          nsmall = 5
        elseif (amant.le.0.832) then   ! log10(30)/log10(60)
          num = 30
          nsmall = 3
        else
          num = 60
          nsmall = 6
        endif
        step = num * 6.d1**iexp
        axis%label%format_nd = 0
      endif
    else
      ! Normal decimal label
      if (nlabel.le.4) nlabel = 5
      adiff = abs(a2-a1)
      diff  = log10(adiff/nlabel)
      iexp  = diff
      if (diff.lt.0.) iexp = iexp-1
      amant = diff - iexp
      if (amant.eq.0.) then
        num = 1
      elseif (amant.lt..302) then
        num = 2
        nsmall = 4
      elseif (amant.lt..700) then
        num = 5
      else
        num = 10
      endif
      step = num * 1.d1**iexp
    endif
    if (small.gt.0) then
      rsmall = abs(step/small)
      if (rsmall.lt.2e2) then
        nsmall = int(rsmall)
      else
        call greg_message(seve%e,rname,'Too many small ticks')
        error = .true.
        return
      endif
    endif
  else
    call greg_message(seve%e,rname,'Invalid tick space')
    error = .true.
    return
  endif
  !
  if (ax2.lt.ax1) step = -step
  off = dint(ax1/step)
  if (ax1/step.lt.0.d0) off = off-1.d0
  tickpos = step*off
  dx = ax2-ax1
  cosine = cos(axis%angle)
  sine = sin(axis%angle)
  !
  first = .true.
  if (axis%loga .or. .not.axis%label%brief) then
    lbrief = .false.
    tick%loffval = 0.d0
  else
    call tick_offset(axis%label%format.ne.format_decimal,a1,a2,lbrief,tick%loffval)
  endif
  tick%lbrief = .false.  ! First major tick is not abbreviated
  !
  ! Place Major Tick every "Step" value, starting from "Tick" value
  do j=1,100
    do i=1,nsmall
      !
      if (dolog) then
        if (abs(step).eq.1.d0) then
          tick%value = i*1.d1**tickpos
        elseif (abs(step).eq.2.d0) then
          tick%value = val(i)*1.d1**tickpos
        else
          ! tick%value = 1.d1**(tickpos+(i-1))
          tick%value = 1.d1**(tickpos+dble(i-1)*smstep)
        endif
        xlen  = alen*(dlog10(tick%value)-ax1)/dx
      else
        tick%value = tickpos + step*dble(i-1)/dble(nsmall)
        if (axis%loga) then
          xlen = alen * (log10(tick%value)-log10(ax1)) / (log10(ax2)-log10(ax1))
        else
          if (abs(tick%value).lt.abs(step*1.d-12)) tick%value = 0.d0
          xlen  = alen*(tick%value-ax1)/dx
        endif
      endif
      !
      ! Allow for roundoff errors
      if (xlen.gt.alen*(1d0+1.d-5)) return
      if (xlen.le.-1.d-5)  cycle
      !
      tick%x = xlen*cosine + ax
      tick%y = xlen*sine + ay
      if (i.eq.1) then
        ! A major tick
        tick%major = .true.
        call func(tick,axis)
        !
        if (first) then
          ! Next major ticks abbreviated or not?
          tick%lbrief = lbrief
          first = .false.
        endif
      else
        ! A minor tick
        tick%major = .false.
        call func(tick,axis)
      endif
      !
    enddo
    tickpos = tickpos+step
  enddo
end subroutine plot_at_tick
!
subroutine plot_tickmark(tick,axis)
  use greg_interfaces, except_this=>plot_tickmark
  use greg_kernel
  use greg_types
  !---------------------------------------------------------------------
  ! @ private-mandatory (because symbol is used elsewhere)
  !  Plot one tick mark
  !---------------------------------------------------------------------
  type(tick_t), intent(in) :: tick    ! Tick description
  type(axis_t), intent(in) :: axis     ! Axis description
  ! Local
  real(kind=4) :: big,xtick,ytick
  real(kind=4) :: small,orient
  real(kind=8) :: sine,cosine
  !
  if (axis%tdirect) then
    orient = 1.
  else
    orient = -1.
  endif
  big = ctick*expand*orient
  small = cmtick*expand*orient
  cosine = cos(axis%angle)
  sine = sin(axis%angle)
  if (tick%major) then
    xtick = -big*sine+tick%x
    ytick =  big*cosine+tick%y
  else
    xtick = -small*sine+tick%x
    ytick =  small*cosine+tick%y
  endif
  call grline(tick%x,tick%y,xtick,ytick)
end subroutine plot_tickmark
!
subroutine plot_ticklabel(tick,axis)
  use phys_const
  use greg_dependencies_interfaces
  use greg_interfaces, except_this=>plot_ticklabel
  use greg_kernel
  use greg_types
  !---------------------------------------------------------------------
  ! @ private-mandatory (because symbol is used elsewhere)
  !  Plot one tick label
  !---------------------------------------------------------------------
  type(tick_t), intent(in) :: tick  ! Tick description
  type(axis_t), intent(in) :: axis  ! Axis description
  ! Local
  real(kind=8) :: value,range,angle,sine,cosine
  real(kind=4) :: big,tiny,dx,slength,t,xs,ys,xlabl,ylabl
  integer(kind=4) :: iform,oform,nchar
  character(len=30) :: string
  ! Data
  data range/0.d0/
  !
  if (.not.tick%major) return
  !
  if (axis%tdirect) then
    big = cheight*cdef*expand
  else
    big = -cheight*cdef*expand
  endif
  tiny = big*0.5
  !
  if (tick%lbrief .and. tick%loffval.ne.0.d0) then
    ! Remove offset value from value
    value = tick%value-tick%loffval
    !   At this stage there may be roundoff problems in 'value', because we
    ! may have substracted two huge values (remember this is the exact purpose
    ! of the 'brief' flag!). As a solution, we round the value to 6
    ! significant digits (not decimal but significant). 6 should be fine
    ! because, again, this is the purpose of the 'brief' flag: keeping only a
    ! few significant digits!
    !   Note that rounding is not done with integer rounding because
    ! nint(kind=8) is limited to ~9.E18:
    !     fact = 10.d0**(floor(log10(value))-6)
    !     value = dble(nint(value/fact,kind=8)*fact)
    ! Rely on compiler instead
    write(string,'(E20.6)') value
    read(string,*) value
  else
    value = tick%value
  endif
  !
  if (axis%label%format.ne.format_decimal) then
    call gag_cflabh (string,value,nchar,  &
      axis%label%format_nd,axis%label%format,tick%lbrief)
  else
    if (axis%label%expo) then
      iform = -1  ! Request floating point format
    else
      iform = 0  ! Request integer format
    endif
    call sic_spanum(string,value,iform,oform,nchar,range,15,5) ! was 3) before, and too long
    ! print *,'iform, oform = ',iform,oform,nchar,string(1:nchar)
    if (oform.eq.-1) then
      ! String has been returned with floating point format. Need to convert
      ! it to something Greg can understand
      call spanum_to_greg(string,nchar,axis%label%expo)
    endif
  endif
  call gstrlen (nchar,string,slength)
  dx = - axis%label%justif*0.5*slength
  cosine = cos(axis%angle)
  sine = sin(axis%angle)
  if (axis%label%justif.eq.1) then
    t = axis%label%offset*big
    xlabl = t*sine+tick%x
    ylabl =-t*cosine+tick%y
    xs = dx*cosine + xlabl
    ys = dx*sine + ylabl
    call grelocate (xs,ys)
    call gstring(nchar,string,axis%angle,.false.)
  else
    t = (4*axis%label%offset-1)/3.*tiny
    xlabl =  t*sine+tick%x
    ylabl = -t*cosine+tick%y
    xs = dx*sine + xlabl
    ys = -dx*cosine + ylabl
    call grelocate (xs,ys)
    angle = axis%angle-pi/2.d0
    call gstring(nchar,string,angle,.false.)
  endif
end subroutine plot_ticklabel
!
subroutine plot_rulexy(tick,axis)
  use greg_interfaces, except_this=>plot_rulexy
  use greg_types
  !---------------------------------------------------------------------
  ! @ private-mandatory (because symbol is used elsewhere)
  !  Used by command RULE for gridding the plot page
  !---------------------------------------------------------------------
  type(tick_t), intent(in) :: tick  ! Tick description
  type(axis_t), intent(in) :: axis  ! Axis description
  ! Local
  real(kind=4) :: xb,yb
  !
  if (tick%major.neqv.axis%gmajor) return
  !
  if (axis%ghoriz) then
    xb = tick%x + axis%glength
    yb = tick%y
  else
    xb = tick%x
    yb = tick%y + axis%glength
  endif
  call grline(tick%x,tick%y,xb,yb)
end subroutine plot_rulexy
!
subroutine greg_tickspace(line,error)
  use greg_dependencies_interfaces
  use greg_interfaces, except_this=>greg_tickspace
  use greg_axes
  use gbl_message
  !---------------------------------------------------------------------
  ! @ private
  ! GREG  Support routine for command
  !  TICKSPACE SMALLX BIGX SMALLY BIGY
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: line   ! Command line
  logical,          intent(inout) :: error  ! Logical error flag
  !
  if (sic_narg(0).ne.4) then
    call greg_message(seve%e,'TICKSPACE','4 arguments required')
    error = .true.
    return
  endif
  !
  call sic_r8 (line,0,1,smallx,.false.,error)
  if (error) return
  call sic_r8 (line,0,2,bigx,.false.,error)
  if (error) return
  call sic_r8 (line,0,3,smally,.false.,error)
  if (error) return
  call sic_r8 (line,0,4,bigy,.false.,error)
end subroutine greg_tickspace
!
subroutine tick_offset(sexage,v1,v2,brief,o)
  use greg_interfaces, except_this=>tick_offset
  use gbl_message
  use greg_kernel
  use greg_types
  !---------------------------------------------------------------------
  ! @ private
  ! Custom rounding function. Takes 2 floats as input and return
  ! the most common value.
  ! - Example 1: d1=111259. and d2=111335.
  !    We want to return 111000. There is trap here: dx<100 but we have
  !    to round to the 1000s.
  ! - Example 2: d1=123456. and d2=3.
  !    We want to return 0.
  ! - Example 3: d1=123456. and d2=-120000.
  !    We want to return 0.
  ! - Example 4: d1=123456.789 and d2=d1
  !    We want to return d1
  !---------------------------------------------------------------------
  logical,      intent(in)  :: sexage  ! Sexagesimal notation?
  real(kind=8), intent(in)  :: v1,v2   !
  logical,      intent(out) :: brief   !
  real(kind=8), intent(out) :: o       !
  ! Local
  character(len=*), parameter :: rname='AXIS'
  integer(kind=4), parameter :: strlen=24
  character(len=strlen) :: c1,c2,c3
  integer(kind=4) :: e,d,d1,d2,m1,m2,ier
  real(kind=8) :: s
  !
  brief = .false.
  o = 0.d0
  !
  ! No common digits if numbers do not have the same sign
  if (v1*v2.lt.0.)  return
  !
  if (sexage) then
    d1 = floor(abs(v1)/3.6d3)
    d2 = floor(abs(v2)/3.6d3)
    if (d1.ne.d2)  return
    !
    s = sign(1.d0,v1)
    m1 = floor(abs(v1)/60.d0)-d1*60
    m2 = floor(abs(v2)/60.d0)-d2*60
    if (m1.ne.m2) then
      o = s*real(d1,kind=8)*3.6d3
    else
      o = s*(real(d1,kind=8)*3.6d3+real(m1,kind=8)*60d0)
    endif
    !
  else
    ! For double precision floats, use 15 significant digits
    write(c1,'(D24.15)')  v1
    write(c2,'(D24.15)')  v2
    !
    ! No common digits if numbers do not share the same highest power of 10
    ! NB: this test is also valid for numbers lower than 1.
    e = index(c1,'D')  ! Exponent position
    if (c1(e:).ne.c2(e:))  return
    !
    d = index(c1,'0')+2  ! First significant digit position
    do while (c1(1:d).eq.c2(1:d))
      d = d+1
    enddo
    c3 = c1(1:d-1)//c1(e:)
    read(c3,*,iostat=ier) o
    if (ier.ne.0) then
      call greg_message(seve%e,rname,'Error while reading '//c3)
      o = 0.d0
      return
    endif
  endif
  !
  brief = .true.
  !
end subroutine tick_offset
