!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
module cubetopology_range_types
  use cubetopology_messaging
  !
  public :: range_prog_t
  private
  !
  type range_prog_t
     real(kind=coor_k), public :: p(2) = 0d0  ! [pix|chan] First and last values
     real(kind=coor_k), public :: dp = 0d0    ! [pix|chan] Step size
     real(kind=coor_k), public :: n = 0d0     ! [--------] Number of steps
  contains
     procedure, public :: to_inte_k => cubetopology_range_prog_to_inte_k
  end type range_prog_t
  !
contains
  !
  subroutine cubetopology_range_prog_to_inte_k(range,first,last,stride,error)
    !----------------------------------------------------------------------
    ! First and last are expected to be inclusive, we expect them to
    ! include the whole pixels at the edges. However, they may be located
    ! outside the associated axis range.
    !
    ! Remembering pixel N runs from N-0.5 to N+0.5, we implement 3 main
    ! cases:
    !  1) values are randomly placed in the pixel (could be at the center):
    !     using nint() function will return the proper pixel to be taken,
    !     satisfying the inclusive rule. This rule also applies if the
    !     range is null size (2 identical values, 1 pixel to be extracted)
    !     but not on a boundary.
    !  2a) one value is at a pixel boundary: there is an ambiguity on the
    !     pixel to be selected which is solved by checking if we consider
    !     the left boundary or the right boundary of the range. For example
    !     extracting from 4.5 to 7.0 => extract 5 to 7, but
    !     extracting from 2.0 to 4.5 => extract 2 to 4
    !     which means 4.5 is rounded depending on the context.
    !  2b) same rule applies if both values are at a pixel boundary as
    !     long as they are not identical.
    !  3) if both values are identical AND at a pixel boundary, a single
    !     pixel has to be extracted; the right one is chosen arbitrarily.
    !----------------------------------------------------------------------
    class(range_prog_t),  intent(in)    :: range
    integer(kind=pixe_k), intent(out)   :: first
    integer(kind=pixe_k), intent(out)   :: last
    integer(kind=pixe_k), intent(out)   :: stride
    logical,              intent(inout) :: error
    !
    real(kind=coor_k) :: left,right
    real(kind=coor_k), parameter :: eps=1d-9  ! [pixel]
    logical :: same,lboundary,rboundary
    character(len=*), parameter :: rname='RANGE>PROG>TO>INTE_K'
    !
    call cubetopology_message(toposeve%trace,rname,'Welcome')
    !
    if (range%p(1).lt.range%p(2)) then
      left  = range%p(1)
      right = range%p(2)
    else
      left  = range%p(2)
      right = range%p(1)
    endif
    !
    ! Check if values are exactly on pixel boundary (down to eps pixel precision)
    same = abs(left-right).le.eps
    lboundary = nint(left -eps).ne.nint(left +eps)
    rboundary = nint(right-eps).ne.nint(right+eps)
    !
    ! Apply rules
    if (lboundary) then
      if (same) then
        first = ceiling(left)  ! Rule 3
      else
        first = ceiling(left)  ! Rule 2
      endif
    else
      first = nint(left)       ! Rule 1
    endif
    if (rboundary) then
      if (same) then
        last = first           ! Rule 3
      else
        last = floor(right)    ! Rule 2
      endif
    else
      last = nint(right)       ! Rule 1
    endif
    !
    stride = nint(abs(range%dp))  ! abs() because first/last were sorted
  end subroutine cubetopology_range_prog_to_inte_k
end module cubetopology_range_types
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
