!-----------------------------------------------------------------------
! This file provides routines which return useful values of Any Working
! (GTV) Directory or Device.
!-----------------------------------------------------------------------
subroutine get_free_slot_output(output,error)
  use gtv_interfaces, except_this=>get_free_slot_output
  use gtv_types
  use gtv_protocol
  use gbl_message
  !---------------------------------------------------------------------
  ! @ private
  ! RenameMe!
  !  Get a free slot for a 'output' instance.
  ! ---
  !  Thread status: not thread safe. Should the 'all_outputs' structure
  ! be protected?
  !---------------------------------------------------------------------
  type(gt_display), pointer :: output  ! The 'gt_display' instance found
  logical,    intent(inout) :: error   ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='GET_FREE_SLOT_OUTPUT'
  integer :: iout
  !
  do iout=1,moutputs
    if (.not.all_outputs(iout)%used) then
      ! Found an available slot at iout position
      all_outputs(iout)%used = .true.
      output => all_outputs(iout)
      return
    endif
  enddo
  !
  ! No free instance available
  ! call gtv_message(seve%e,rname,'Internal error: no free output instance')
  ! The following message is currently biased to X windows as it is the
  ! only device which uses the 'all_outputs' array.
  call gtv_message(seve%e,'DEVICE','Can not create more than 20 windows')
  output => null()
  error = .true.
  !
end subroutine get_free_slot_output
!
subroutine get_slot_output_by_num(dir,win_num,output,error)
  use gbl_message
  use gildas_def
  use gtv_buffers
  use gtv_interfaces, except_this=>get_slot_output_by_num
  use gtv_types
  !---------------------------------------------------------------------
  ! @ private
  ! RenameMe!
  !  Return the index of the output instance which is identified by
  ! the input directory and window number.
  ! ---
  !  Thread status: not thread safe. Calling routine must be thread
  ! safe
  !---------------------------------------------------------------------
  type(gt_directory)              :: dir      ! Input directory
  integer(kind=4),  intent(in)    :: win_num  ! Window number
  type(gt_display), pointer       :: output   ! The 'gt_display' instance found
  logical,          intent(inout) :: error    ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='GET_SLOT_OUTPUT_BY_NUM'
  integer(kind=address_length) :: graph_env
  character(len=message_length) :: mess
  logical :: found
  !
  graph_env = c_get_win_genv(dir%x%genv_array,win_num)
  !
  call get_slot_output_by_genv(graph_env,output,.true.,found,error)
  if (error) then
    write(mess,*) 'Internal error: output instance not found (num = ',  &
      win_num,')'
    call gtv_message(seve%e,rname,mess)
    return
  endif
  !
end subroutine get_slot_output_by_num
!
subroutine get_slot_output_by_genv(graph_env,output,present,found,error)
  use gtv_interfaces, except_this=>get_slot_output_by_genv
  use gildas_def
  use gtv_protocol
  use gbl_message
  !---------------------------------------------------------------------
  ! @ private
  ! RenameMe!
  !  Return the index of the output instance which is identified by
  ! the input graph_env.
  ! ---
  !  Thread status: not thread safe. Should the 'all_outputs' structure
  ! be protected?
  !---------------------------------------------------------------------
  integer(kind=address_length), intent(in)    :: graph_env  ! Identifier
  type(gt_display),             pointer       :: output     ! The 'gt_display' instance found
  logical,                      intent(in)    :: present    ! Must the graph_env exist?
  logical,                      intent(out)   :: found      ! .true. if found
  logical,                      intent(inout) :: error      ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='GET_SLOT_OUTPUT_BY_GENV'
  integer :: iout
  character(len=message_length) :: mess
  !
  do iout=1,moutputs
    if (all_outputs(iout)%used) then
      if (all_outputs(iout)%x%graph_env.eq.graph_env) then
        found = .true.
        output => all_outputs(iout)
        return
      endif
    endif
  enddo
  !
  ! Not found...
  found = .false.
  output => null()
  if (present) then
    write(mess,*) 'Internal error: output instance not found (genv = ',  &
      graph_env,')'
    call gtv_message(seve%e,rname,mess)
    error = .true.
  endif
  !
end subroutine get_slot_output_by_genv
!
function get_window_cnum_byname(dir,rname,line,iopt,iarg,error)
  use gbl_message
  use gtv_dependencies_interfaces
  use gtv_interfaces, except_this=>get_window_cnum_byname
  use gtv_types
  use gtv_tree
  !---------------------------------------------------------------------
  ! @ private
  !  Return the window instance in the input directory which is
  ! identified by its name (can be "ZOOM") or window number (as seen
  ! by user).
  ! ---
  !  Thread status: not thread safe. Calling routine must be thread
  ! safe
  !---------------------------------------------------------------------
  integer(kind=4) :: get_window_cnum_byname  ! Function value on return
  type(gt_directory), intent(in)    :: dir    ! Directory to search in
  character(len=*),   intent(in)    :: rname  ! Calling routine name
  character(len=*),   intent(in)    :: line   ! Command line
  integer(kind=4),    intent(in)    :: iopt   ! Option number in command line
  integer(kind=4),    intent(in)    :: iarg   ! Argument number in option
  logical,            intent(inout) :: error  ! Logical error flag
  ! Local
  character(len=*), parameter :: zoom='ZOOM'
  character(len=gtvpath_length) :: wname
  logical :: found
  integer(kind=4) :: nc,win_num
  !
  call sic_ke(line,iopt,iarg,wname,nc,.true.,error)
  if (error) return
  !
  if (wname(1:nc).eq.zoom(1:min(nc,4))) then
    call get_zoom_win(dir,get_window_cnum_byname,found)
    if (.not.found) then
      call gtv_message(seve%e,rname,  &
        'No zoom window attached to current directory')
      error = .true.
      return
    endif
  else
    call sic_math_inte(wname,nc,win_num,error)
    ! Translate the user number into internal number
    get_window_cnum_byname = get_window_cnum(dir,win_num,error)
  endif
  !
end function get_window_cnum_byname
!
function get_window_cnum(dir,usernum,error)
  use gbl_message
  use gildas_def
  use gtv_buffers
  use gtv_interfaces, except_this=>get_window_cnum
  use gtv_types
  !---------------------------------------------------------------------
  ! @ private
  ! RenameMe!
  !  Return the window instance which is identified by its parent
  ! directory and window number (as seen by user).
  ! ---
  !  Thread status: not thread safe. Calling routine must be thread
  ! safe
  !---------------------------------------------------------------------
  integer(kind=4) :: get_window_cnum  ! Function value on return
  type(gt_directory), intent(in)    :: dir      ! Input directory
  integer(kind=4),    intent(in)    :: usernum  ! Window number (as seen by user)
  logical,            intent(inout) :: error    ! Logical error flag
  ! Local
  integer :: iwin
  type(gt_display), pointer :: output
  !
  if (error)  return
  !
  if (dir%x%nbwin.eq.0) then
    get_window_cnum = 0
    return
  else
    get_window_cnum = -1
  endif
  !
  do iwin=0,dir%x%nbwin-1
    call get_slot_output_by_num(dir,iwin,output,error)
    if (error)  return
    if (output%x%number.eq.usernum) then
      get_window_cnum = iwin
      return
    endif
  enddo
  !
  ! Not found... Error will be detected later.
  !
end function get_window_cnum
!
function get_window_usernum(dir,cnum,error)
  use gtv_types
  use gtv_interfaces, except_this=>get_window_usernum
  !---------------------------------------------------------------------
  ! @ private
  !  Return the window number in the user system of numbering, given
  ! the internal number in the C-and-continuous internal system of
  ! numbering.
  !---------------------------------------------------------------------
  integer(kind=4) :: get_window_usernum  ! Function value on return
  type(gt_directory), intent(in)    :: dir    ! The directory the window is attached on
  integer(kind=4),    intent(in)    :: cnum   ! The C number of the window we look for
  logical,            intent(inout) :: error  ! Logical error flag
  ! Local
  type(gt_display), pointer :: output
  !
  get_window_usernum = 0
  !
  call get_slot_output_by_num(dir,cnum,output,error)
  if (error)  return
  !
  get_window_usernum = output%x%number
  !
end function get_window_usernum
!
subroutine free_slot_output_by_genv(graph_env,error)
  use gtv_interfaces, except_this=>free_slot_output_by_genv
  use gildas_def
  use gtv_protocol
  use gbl_message
  !---------------------------------------------------------------------
  ! @ private
  ! RenameMe!
  !  Free the output instance which is identified by the input
  ! graph_env.
  !---------------------------------------------------------------------
  integer(kind=address_length), intent(in)  :: graph_env  ! Identifier
  logical, intent(inout) :: error  ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='FREE_SLOT_OUTPUT_BY_GENV'
  integer :: iout
  !
  do iout=1,moutputs
    if (all_outputs(iout)%used) then
      if (all_outputs(iout)%x%graph_env.eq.graph_env) then
        call gt_output_reset(all_outputs(iout))
        return
      endif
    endif
  enddo
  !
  ! Not found...
  call gtv_message(seve%e,rname,'Internal error: output instance not found')
  error = .true.
  !
end subroutine free_slot_output_by_genv
!
subroutine gt_output_reset(output)
  use gtv_interfaces, except_this=>gt_output_reset
  use gtv_types
  use gtv_bitmap
  !---------------------------------------------------------------------
  ! @ private
  !   Reset the instance parameters, set it unused, and free the
  ! allocated memory it was using for images.
  !---------------------------------------------------------------------
  type(gt_display) :: output  ! Output instance
  !
  output%used = .false.
  output%autorotate = .false.
  output%autoscale = .true.
  !
  output%px1 = 0  ! Reset actual size ensures that device defaults will
  output%px2 = 0  ! be used instead.
  output%py1 = 0
  output%py2 = 0
  !
  output%idashe = 1
  output%iweigh = graisse(1)
  output%icolou = 1
  !
  call x_display_reset(output%x)
  !
end subroutine gt_output_reset
!
subroutine x_display_reset(xdisplay)
  use gtv_interfaces, except_this=>x_display_reset
  use gtv_types
  !---------------------------------------------------------------------
  ! @ private
  !
  !---------------------------------------------------------------------
  type(x_output), intent(inout) :: xdisplay  ! Instance to be reset
  ! Local
  type(gt_bitmap), pointer :: xbitmap,next
  !
  xdisplay%name = ' '
  xdisplay%graph_env = 0
  xdisplay%is_zoom = .false.
  !
  ! 0 values (invalid for size) mean unset
  xdisplay%geometry%x = 0.
  xdisplay%geometry%unitx = ' '
  xdisplay%geometry%y = 0.
  xdisplay%geometry%unity = ' '
  !
  ! -1 values (invalid for position) mean unset
  xdisplay%position%x = -1.
  xdisplay%position%unitx = ' '
  xdisplay%position%y = -1.
  xdisplay%position%unity = ' '
  !
  ! Clean the X bitmaps
  xbitmap => xdisplay%bitmap_first
  do while (associated(xbitmap))
    ! Keep track of next before deletion
    next => xbitmap%next
    !
    call gt_bitmap_deallocate(xbitmap)
    xbitmap => next
  enddo
  xdisplay%bitmap_first => null()
  xdisplay%bitmap_last => null()
  !
end subroutine x_display_reset
!
subroutine gt_bitmap_deallocate(bitmap)
  use gtv_interfaces, except_this=>gt_bitmap_deallocate
  use gtv_types
  !---------------------------------------------------------------------
  ! @ private
  !   Elemental routine which deallocates the input 'gt_bitmap' and
  ! frees the data associated. This routine does NOT take care of the
  ! pointers to this instance: it is up to the calling routine to
  ! remake the chain, if required.
  !---------------------------------------------------------------------
  type(gt_bitmap), pointer :: bitmap  !
  !
  if (associated(bitmap%irvalues))  deallocate(bitmap%irvalues)
  if (associated(bitmap%igvalues))  deallocate(bitmap%igvalues)
  if (associated(bitmap%ibvalues))  deallocate(bitmap%ibvalues)
  !
  ! No need: we destroy the instance right after
  ! bitmap%irvalues => null()
  ! bitmap%igvalues => null()
  ! bitmap%ibvalues => null()
  ! bitmap%image => null()
  ! bitmap%next => null()
  !
  deallocate(bitmap)
  !
end subroutine gt_bitmap_deallocate
!
subroutine print_gt_device(dev)
  use gtv_interfaces, except_this=>print_gt_device
  use gtv_types
  !---------------------------------------------------------------------
  ! @ private
  ! Print the content various variables attached to the input gt_device
  ! structure. For debugging purpose.
  !---------------------------------------------------------------------
  type(gt_device), intent(in) :: dev  ! Input gt_device
  !
  write(*,101) 'Protocol:',dev%protocol
  write(*,101) 'Linit1:',  dev%linit1
  write(*,100) 'Init1:',   trim(dev%init1)
  write(*,101) 'Linit2:',  dev%linit2
  write(*,100) 'Init2:',   trim(dev%init2)
  !
  write(*,101) 'Px1 (default):',dev%px1
  write(*,101) 'Px2 (default):',dev%px2
  write(*,101) 'Py1 (default):',dev%py1
  write(*,101) 'Py2 (default):',dev%py2
  write(*,102) 'Rxy:',          dev%rxy
  !
  ! To be continued
  !
100 format(2X,A,T25,A)     ! Character string
101 format(2X,A,T25,I8)    ! Integer value
102 format(2X,A,T25,F8.3)  ! Float value
end subroutine print_gt_device
!
subroutine print_gt_output(output)
  use gtv_interfaces, except_this=>print_gt_output
  use gtv_types
  !---------------------------------------------------------------------
  ! @ private
  ! Print the content of various variables attached to the input
  ! gt_device structure. For debugging purpose.
  !---------------------------------------------------------------------
  type(gt_display), intent(in) :: output  ! Input gt_display instance
  !
  write(*,111) 'Px1, Px2 (actual):',output%px1,output%px2
  write(*,111) 'Py1, Py2 (actual):',output%py1,output%py2
  !
  write(*,112) 'Gx1, Gx2:',         output%gx1,output%gx2
  write(*,112) 'Gy1, Gy2:',         output%gy1,output%gy2
  !
  ! To be continued
  !
! 103 format(2X,A,T25,L1,  T35,L1)    ! 1 Logical value
! 110 format(2X,A,T25,A,   T35,A)     ! 2 Character strings
111 format(2X,A,T25,I8,  T35,I8)    ! 2 Integer values
112 format(2X,A,T25,F8.3,T35,F8.3)  ! 2 Float values
end subroutine print_gt_output
!
subroutine get_scale_awd(out,scalex,scaley)
  use gtv_interfaces, except_this=>get_scale_awd
  use gtv_types
  !---------------------------------------------------------------------
  ! @ private
  ! Compute the X and Y scaling relation between physical and pixel
  ! units, for Input Working Device.
  !  Note that the range of pixels [out%px1:out%px2] is fully mapped
  ! on the physical range [out%gx1:out%gx2]. Pixels have a finite size:
  ! the left border of the first pixel is aligned on the left border of
  ! the physical range, and the right border of the last pixel is
  ! aligned on the right border of the physical range.
  !  This is very useful for images: when you ask a 100 pixels image to
  ! be displayed on a 100 pixels device, you except a 1 to 1 pixel
  ! alignment (not 100 image pixels on 99 device pixels). Note also that
  ! you want to align the boundaries of the side pixels, NOT the center
  ! of the side pixels. Example:
  ! 1) Same number of pixels
  !  Image:  |--.--|--.--|--.--|--.--|--.--|--.--|--.--|--.--|  8 pixels
  !  Device: |--.--|--.--|--.--|--.--|--.--|--.--|--.--|--.--|  8 pixels
  ! 2a) Twice more, we want boundaries aligned:
  !  Image:  |-----.-----|-----.-----|-----.-----|-----.-----|  4 pixels
  !  Device: |--.--|--.--|--.--|--.--|--.--|--.--|--.--|--.--|  8 pixels
  ! 2b) Twice more, we DO NOT want centers aligned because this truncate
  !     the original pixels:
  !  Image:  |-----.-----|-----.-----|-----.-----|-----.-----|  4 pixels
  !  Device:     |-.--|--.-|--.-|--.-|--.-|--.-|--.-|--.-|      8 pixels
  !---------------------------------------------------------------------
  type(gt_display), intent(in)  :: out     ! Input gt_display
  real(kind=4),     intent(out) :: scalex  ! Number of pixels per world unit in X
  real(kind=4),     intent(out) :: scaley  ! Number of pixels per world unit in Y
  ! Local
  real(kind=4) :: gx,gy,kxy
  !
  if (out%py1.lt.out%py2) then
    ! out%py2-out%py1+1 > 0 = +(number of pixels)
    gy = (out%gy2-out%gy1)/float(out%py2-out%py1+1)
  else
    ! out%py2-out%py1-1 < 0 = -(number of pixels)
    gy = (out%gy2-out%gy1)/float(out%py2-out%py1-1)
  endif
  if (out%px1.lt.out%px2) then
    gx = (out%gx2-out%gx1)/float(out%px2-out%px1+1)
  else
    gx = (out%gx2-out%gx1)/float(out%px2-out%px1-1)
  endif
  kxy = gx/gy
  if (abs(gy*out%dev%rxy) .ge. abs(gx)) then
    scaley = 1./gy
    if (kxy.gt.0.) then
      scalex = scaley / out%dev%rxy
    else
      scalex = - scaley / out%dev%rxy
    endif
  else
    scalex = 1./gx
    if (kxy.gt.0.) then
      scaley = scalex * out%dev%rxy
    else
      scaley = - scalex * out%dev%rxy
    endif
  endif
  !
end subroutine get_scale_awd
!
subroutine get_central_pixel_awd(out,xpix_center,ypix_center)
  use gtv_interfaces, except_this=>get_central_pixel_awd
  use gtv_types
  !---------------------------------------------------------------------
  ! @ private
  ! Return the center pixel of Input Working Device. Should be dynamic
  ! at some point i.e. will dynamically get the device size (and NOT
  ! from some global variable), and then compute this center.
  !---------------------------------------------------------------------
  type(gt_display), intent(in)  :: out          ! Input gt_display
  real(kind=4),     intent(out) :: xpix_center  ! Central pixel X coordinate
  real(kind=4),     intent(out) :: ypix_center  ! Central pixel X coordinate
  !
  xpix_center = float(out%px1+out%px2)/2. + (0.5-out%dev%poff)
  ypix_center = float(out%py1+out%py2)/2. + (0.5-out%dev%poff)
  !
end subroutine get_central_pixel_awd
!
subroutine get_central_clipping_awd(out,x_center,y_center)
  use gtv_interfaces, except_this=>get_central_clipping_awd
  use gtv_types
  !---------------------------------------------------------------------
  ! @ private
  ! Return the center of the clipping window of the Input Working
  ! Device. Should be dynamic at some point i.e. will dynamically get
  ! the current device clipping window (and NOT from some global
  ! variable), and then compute this center.
  !---------------------------------------------------------------------
  type(gt_display), intent(in)  :: out       ! Input gt_display
  real(kind=4),     intent(out) :: x_center  ! Center X point of plot space
  real(kind=4),     intent(out) :: y_center  ! Center Y point of plot space
  !
  x_center = (out%gx1+out%gx2)/2.
  y_center = (out%gy1+out%gy2)/2.
  !
end subroutine get_central_clipping_awd
!
subroutine world_to_pixel_size_i4(out,wx,wy,px,py)
  use gtv_interfaces, except_this=>world_to_pixel_size_i4
  use gtv_types
  !---------------------------------------------------------------------
  ! @ private-generic world_to_pixel_size
  ! Convert world SIZE into pixel size for the input working device.
  ! ---
  !  Integer(kind=4) version: do not call directly. Use generic
  ! interface 'world_to_pixel_size' instead.
  !---------------------------------------------------------------------
  type(gt_display), intent(in)  :: out    ! Input gt_display
  real(kind=4),     intent(in)  :: wx,wy  ! Input size in world coordinates
  integer(kind=4),  intent(out) :: px,py  ! Output size in pixels
  ! Local
  real(kind=4) :: rpx,rpy
  !
  call world_to_pixel_size_r4(out,wx,wy,rpx,rpy)
  !
  px = nint(rpx)
  py = nint(rpy)
  !
end subroutine world_to_pixel_size_i4
!
subroutine world_to_pixel_size_r4(out,wx,wy,px,py)
  use gtv_interfaces, except_this=>world_to_pixel_size_r4
  use gtv_types
  !---------------------------------------------------------------------
  ! @ private-generic world_to_pixel_size
  ! Convert world SIZE into pixel size for the input working device.
  ! ---
  !  Real(kind=4) version: do not call directly. Use generic
  ! interface 'world_to_pixel_size' instead.
  !---------------------------------------------------------------------
  type(gt_display), intent(in)  :: out    ! Input gt_display
  real(kind=4),     intent(in)  :: wx,wy  ! Input size in world coordinates
  real(kind=4),     intent(out) :: px,py  ! Output size in pixels
  ! Local
  real(kind=4) :: gsclx,gscly
  !
  ! Get the Current Working Device parameters:
  call get_scale_awd(out,gsclx,gscly)
  !
  px = wx*abs(gsclx)
  py = wy*abs(gscly)
  !
end subroutine world_to_pixel_size_r4
!
subroutine pixel_to_world_size_i4(out,px,py,wx,wy)
  use gtv_interfaces, except_this=>pixel_to_world_size_i4
  use gtv_types
  !---------------------------------------------------------------------
  ! @ private-generic pixel_to_world_size
  !  Convert pixel SIZE into world size for the input working device.
  ! ---
  !  Integer(kind=4) version: do not call directly. Use generic
  ! interface 'pixel_to_world_size' instead.
  !---------------------------------------------------------------------
  type(gt_display), intent(in)  :: out    ! Input gt_display
  integer(kind=4),  intent(in)  :: px,py  ! Input pixel size
  real(kind=4),     intent(out) :: wx,wy  ! Output world size
  !
  call pixel_to_world_size_r4(out,real(px,kind=4),real(py,kind=4),wx,wy)
  !
end subroutine pixel_to_world_size_i4
!
subroutine pixel_to_world_size_r4(out,px,py,wx,wy)
  use gtv_interfaces, except_this=>pixel_to_world_size_r4
  use gtv_types
  !---------------------------------------------------------------------
  ! @ private-generic pixel_to_world_size
  !  Convert pixel SIZE into world size for the input working device.
  ! ---
  !  Real(kind=4) version: do not call directly. Use generic
  ! interface 'pixel_to_world_size' instead.
  !---------------------------------------------------------------------
  type(gt_display), intent(in)  :: out    ! Input gt_display
  real(kind=4),     intent(in)  :: px,py  ! Input pixel size
  real(kind=4),     intent(out) :: wx,wy  ! Output world size
  ! Local
  real(kind=4) :: gsclx,gscly
  !
  ! Get the Current Working Device parameters:
  call get_scale_awd(out,gsclx,gscly)
  !
  wx = px/gsclx
  wy = py/gscly
  !
end subroutine pixel_to_world_size_r4
!
subroutine world_to_pixel_i4(out,wx,wy,px,py)
  use gtv_interfaces, except_this=>world_to_pixel_i4
  use gtv_types
  !---------------------------------------------------------------------
  ! @ private-generic world_to_pixel
  ! Convert world COORDINATES into pixel coordinates for the input
  ! working device.
  ! ---
  !  Integer(kind=4) version: do not call directly. Use generic
  ! interface 'world_to_pixel' instead.
  !---------------------------------------------------------------------
  type(gt_display), intent(in)  :: out    ! Input gt_display
  real(kind=4),     intent(in)  :: wx,wy  ! Input world coordinates
  integer(kind=4),  intent(out) :: px,py  ! Output pixel coordinates
  ! Local
  real(kind=4) :: rpx,rpy
  !
  call world_to_pixel_r4(out,wx,wy,rpx,rpy)
  !
  px = nint(rpx)
  py = nint(rpy)
  !
end subroutine world_to_pixel_i4
!
subroutine world_to_pixel_r4(out,wx,wy,px,py)
  use gtv_interfaces, except_this=>world_to_pixel_r4
  use gtv_types
  !---------------------------------------------------------------------
  ! @ private-generic world_to_pixel
  ! Convert world COORDINATES into pixel coordinates for the input
  ! working device.
  ! ---
  !  Real(kind=4) version: do not call directly. Use generic
  ! interface 'world_to_pixel' instead.
  !---------------------------------------------------------------------
  type(gt_display), intent(in)  :: out    ! Input gt_display
  real(kind=4),     intent(in)  :: wx,wy  ! Input world coordinates
  real(kind=4),     intent(out) :: px,py  ! Output pixel coordinates
  ! Local
  real(kind=4) :: gsclx,gscly,pox,poy,gox,goy
  !
  ! Get the Current Working Device parameters:
  call get_scale_awd(out,gsclx,gscly)
  call get_central_pixel_awd(out,pox,poy)
  call get_central_clipping_awd(out,gox,goy)
  !
  px = (wx-gox)*gsclx + pox
  py = (wy-goy)*gscly + poy
  !
  ! Description of the above formula:
  ! - we want to align out%gx1 to the left border  of the letf  pixel, and
  !                    out%gx2 to the right border of the right pixel
  !   (i.e. the physical range covers all the pixels).
  ! - This writes as:
  !    out%gx1 <=> out%px1-1/2
  !    out%gx2 <=> out%px2+1/2  if  out%px1<out%px2, OR
  !    out%gx1 <=> out%px2-1/2
  !    out%gx2 <=> out%px1+1/2  if  out%px1>out%px2
  ! - in get_scale_awd, we get easily the slope of the relationship
  !   formula (something like px = wx*m+p)
  ! - Now we have m but we need p. Instead of choosing p aligned on gx1
  !   or gx2, we choose p at the center of them. This makes our life
  !   easier, because it nullifies the +-1/2 problem depending on the
  !   pixel axis sign.
  !
end subroutine world_to_pixel_r4
!
subroutine pixel_to_world_i4(out,px,py,wx,wy)
  use gtv_interfaces, except_this=>pixel_to_world_i4
  use gtv_types
  !---------------------------------------------------------------------
  ! @ private-generic pixel_to_world
  !  Convert pixel coordinates into world coordinates for the input
  ! working device.
  ! ---
  !  Integer(kind=4) version: do not call directly. Use generic
  ! interface 'pixel_to_world' instead.
  !---------------------------------------------------------------------
  type(gt_display), intent(in)  :: out    ! Input gt_display
  integer(kind=4),  intent(in)  :: px,py  ! Input pixel coordinates
  real(kind=4),     intent(out) :: wx,wy  ! Output world coordinates
  !
  call pixel_to_world_r4(out,real(px,kind=4),real(py,kind=4),wx,wy)
  !
end subroutine pixel_to_world_i4
!
subroutine pixel_to_world_r4(out,px,py,wx,wy)
  use gtv_interfaces, except_this=>pixel_to_world_r4
  use gtv_types
  !---------------------------------------------------------------------
  ! @ private-generic pixel_to_world
  !  Convert pixel coordinates into world coordinates for the input
  ! working device.
  ! ---
  !  Real(kind=4) version: do not call directly. Use generic
  ! interface 'pixel_to_world' instead.
  !---------------------------------------------------------------------
  type(gt_display), intent(in)  :: out    ! Input gt_display
  real(kind=4),     intent(in)  :: px,py  ! Input pixel coordinates
  real(kind=4),     intent(out) :: wx,wy  ! Output world coordinates
  ! Local
  real(kind=4) :: gsclx,gscly,pox,poy,gox,goy
  !
  ! Get the Current Working Device parameters:
  call get_scale_awd(out,gsclx,gscly)
  call get_central_pixel_awd(out,pox,poy)
  call get_central_clipping_awd(out,gox,goy)
  !
  wx = (px-pox)/gsclx + gox
  wy = (py-poy)/gscly + goy
  !
end subroutine pixel_to_world_r4
