subroutine eq1950_gal(a,d,lii,bii,n)
  use phys_const
  use gwcs_interfaces, except_this=>eq1950_gal
  !---------------------------------------------------------------------
  ! @ public
  !  Converts (A,D) (1950.0) in LII,BII
  !  Units are radians
  !---------------------------------------------------------------------
  real(kind=8),    intent(in)  :: a(*)    !
  real(kind=8),    intent(in)  :: d(*)    !
  real(kind=8),    intent(out) :: lii(*)  !
  real(kind=8),    intent(out) :: bii(*)  !
  integer(kind=4), intent(in)  :: n       !
  ! Local
  real(kind=8) :: aa,cosa,sina,cosdec,sindec,expr
  real(kind=8), parameter :: c626=0.4601997847838517d0, s626=0.8878153851364013d0
  integer(kind=4) :: i
  !
  ! Formulaes are in degrees (LANG K.R. page 504)
  !
  !       SIN(Bii)             = SIN(D)COS(62.6) - COS(D)SIN(A-282.25)SIN(62.6)
  !       COS(Bii)*COS(Lii-33) = COS(D)COS(A-282.25)
  !       COS(Bii)*SIN(Lii-33) = COS(D)SIN(A-282.25)COS(62.6) + SIN(D)SIN(62.6)
  !
  do i=1,n
    aa = a(i)-282.25d0*pi/180.d0
    cosa = cos(aa)
    sina = sin(aa)
    cosdec = cos(d(i))
    sindec = sin(d(i))
    expr = cosdec*sina
    bii(i) = asin (sindec*c626 - expr*s626)
    lii(i) = atan2( (expr*c626+sindec*s626) , cosdec*cosa ) + 33.d0*pi/180.d0
  enddo
end subroutine eq1950_gal
!
subroutine gal_eq1950(lii,bii,a,d,n)
  use phys_const
  use gwcs_interfaces, except_this=>gal_eq1950
  !---------------------------------------------------------------------
  ! @ public
  !   Converts Lii,Bii to (A,D) (1950.0)
  !   Units are radians
  !---------------------------------------------------------------------
  real(kind=8),    intent(in)  :: lii(*)  !
  real(kind=8),    intent(in)  :: bii(*)  !
  real(kind=8),    intent(out) :: a(*)    !
  real(kind=8),    intent(out) :: d(*)    !
  integer(kind=4), intent(in)  :: n       !
  ! Local
  real(kind=8) :: ll,sinb,cosb,sinl,cosl,expr
  real(kind=8), parameter :: c626=0.4601997847838517d0, s626=0.8878153851364013d0
  integer(kind=4) :: i
  !
  ! The conversion formulae are
  !       COS(D)SIN(A-282.25) = COS(Bii)SIN(Lii-33)COS(62.6) - SIN(Bii)SIN(62.6)
  !       COS(D)COS(A-282.25) = COS(Bii)COS(Lii-33)
  !       SIN(D)              = COS(Bii)SIN(Lii-33)SIN(62.6) + SIN(Bii)COS(62.6)
  !
  do i = 1,n
    ll   = lii(i) - 33.d0*pi/180.d0
    sinb = sin(bii(i))
    cosb = cos(bii(i))
    sinl = sin(ll)
    cosl = cos(ll)
    expr = cosb*sinl
    d(i) = asin ( expr*s626 + sinb*c626 )
    a(i) = atan2 ( expr*c626 - sinb*s626 , cosb*cosl ) + 282.25d0*pi/180.d0
  enddo
end subroutine gal_eq1950
!
subroutine rel_to_abs_0d(proj,x,y,a,d,n)
  use gwcs_interfaces, except_this=>rel_to_abs_0d
  use gwcs_types
  !---------------------------------------------------------------------
  ! @ public-generic rel_to_abs
  !  Convert a set of plane position to spherical coordinates according
  ! to the current projection formulae
  ! ---
  ! This version for scalar values
  !---------------------------------------------------------------------
  type(projection_t), intent(in)  :: proj  ! Description of projection
  real(kind=8),       intent(in)  :: x     ! Offset in X
  real(kind=8),       intent(in)  :: y     ! Offset in Y
  real(kind=8),       intent(out) :: a     ! R.A. (radians)
  real(kind=8),       intent(out) :: d     ! Declinations
  integer(kind=4),    intent(in)  :: n     ! Useless, assumed 1
  ! Local
  real(kind=8) :: x1(1),y1(1),a1(1),d1(1)
  !
  x1(1) = x
  y1(1) = y
  call rel_to_abs_1dn8(proj,x1,y1,a1,d1,1_8)
  a = a1(1)
  d = d1(1)
  !
end subroutine rel_to_abs_0d
!
subroutine rel_to_abs_1dn4(proj,x,y,a,d,n)
  use gwcs_interfaces, except_this=>rel_to_abs_1dn4
  use gwcs_types
  !---------------------------------------------------------------------
  ! @ public-generic rel_to_abs
  !  Convert a set of plane position to spherical coordinates according
  ! to the current projection formulae
  ! ---
  ! This version for 1D arrays, size as I*4
  !---------------------------------------------------------------------
  type(projection_t), intent(in)  :: proj  ! Description of projection
  real(kind=8),       intent(in)  :: x(*)  ! Array of offsets in X
  real(kind=8),       intent(in)  :: y(*)  ! Array of offsets in Y
  real(kind=8),       intent(out) :: a(*)  ! Array of R.A. (radians)
  real(kind=8),       intent(out) :: d(*)  ! Array of declinations
  integer(kind=4),    intent(in)  :: n     ! Size of arrays
  !
  call rel_to_abs_1dn8(proj,x,y,a,d,int(n,kind=8))
  !
end subroutine rel_to_abs_1dn4
!
subroutine rel_to_abs_1dn8(proj,x,y,a,d,n)
  use phys_const
  use gbl_constant
  use gbl_message
  use gwcs_interfaces, except_this=>rel_to_abs_1dn8
  use gwcs_types
  !---------------------------------------------------------------------
  ! @ public-generic rel_to_abs
  !  Convert a set of plane position to spherical coordinates according
  ! to the current projection formulae
  ! ---
  ! This version for 1D arrays, size as I*8
  !---------------------------------------------------------------------
  type(projection_t), intent(in)  :: proj  ! Description of projection
  real(kind=8),       intent(in)  :: x(*)  ! Array of offsets in X
  real(kind=8),       intent(in)  :: y(*)  ! Array of offsets in Y
  real(kind=8),       intent(out) :: a(*)  ! Array of R.A. (radians)
  real(kind=8),       intent(out) :: d(*)  ! Array of declinations
  integer(kind=8),    intent(in)  :: n     ! Size of arrays
  ! Local
  real(kind=8), parameter :: precision=1.0d-10
  real(kind=8) :: r,p,sinr,cosr,sinp,cosp,sindec,da,cosda,cpang,spang,ma0,theta
  integer(kind=8) :: i
  logical :: changesign
  !
  select case(proj%type)
  case(p_cartesian)  ! Cartesian projection
    if (abs(proj%angle).le.precision) then
      do i = 1,n
        a(i) = proj%a0+x(i)
        d(i) = proj%d0+y(i)
      enddo
    else
      cpang = cos(-proj%angle)
      spang = sin(-proj%angle)
      do i = 1,n
        a(i) = proj%a0+x(i)*cpang+y(i)*spang
        d(i) = proj%d0-x(i)*spang+y(i)*cpang
      enddo
    endif
    !
  case(p_gnomonic)  ! Gnomonic projection
    if (proj%sind0.gt.precision) then
      do i = 1,n
        r = atan ( sqrt(x(i)**2+y(i)**2) )
        if (r.gt.precision) then
          p = atan2 ( x(i),y(i) ) - proj%angle
          sinr = sin(r)
          cosr = cos(r)
          sinp = sin(p)
          cosp = cos(p)
          sindec = (proj%sind0*cosr + proj%cosd0*sinr*cosp)
          if (y(i) .lt. proj%npole) then
            d(i) = arcsin (sindec)
            a(i) = proj%a0 + arcsin ( sinr*sinp/cos(d(i)) )
          else
            d(i) = arcsin (sindec)
            a(i) = proj%a0 - arcsin ( sinr*sinp/cos(d(i)) ) + pi
          endif
        else
          a(i) = proj%a0
          d(i) = proj%d0
        endif
      enddo
    elseif (proj%sind0.lt.-precision) then
      do i = 1,n
        r = atan ( sqrt(x(i)**2+y(i)**2) )
        if (r.gt.precision) then
          p = atan2 ( x(i),y(i) ) - proj%angle
          sinr = sin(r)
          cosr = cos(r)
          sinp = sin(p)
          cosp = cos(p)
          sindec = (proj%sind0*cosr + proj%cosd0*sinr*cosp)
          if (y(i) .gt. proj%spole) then
            d(i) = arcsin (sindec)
            a(i) = proj%a0 + arcsin ( sinr*sinp/cos(d(i)) )
          else
            d(i) = arcsin (sindec)
            a(i) = proj%a0 - arcsin ( sinr*sinp/cos(d(i)) ) + pi
          endif
        else
          a(i) = proj%a0
          d(i) = proj%d0
        endif
      enddo
    else
      do i=1,n
        r = atan ( sqrt(x(i)**2+y(i)**2) )
        if (r.gt.precision) then
          p = atan2 ( x(i),y(i) ) - proj%angle
          sinr = sin(r)
          cosr = cos(r)
          sinp = sin(p)
          cosp = cos(p)
          sindec = (proj%sind0*cosr + proj%cosd0*sinr*cosp)
          d(i) = arcsin (sindec)
          a(i) = proj%a0 + arcsin ( sinr*sinp/cos(d(i)) )
        else
          a(i) = proj%a0
          d(i) = proj%d0
        endif
      enddo
    endif
    !
  case(p_ortho)  ! Orthographic (Dixon)
    if (proj%sind0.gt.precision) then
      do i = 1,n
        r = x(i)**2+y(i)**2
        if (r.le.1.d0) then
          sinr = sqrt(r)
          r = arcsin ( sinr )
          if (sinr.gt.precision) then
            p = atan2 ( x(i),y(i) ) - proj%angle
            cosr = cos(r)
            sinp = sin(p)
            cosp = cos(p)
            sindec = (proj%sind0*cosr + proj%cosd0*sinr*cosp)
            d(i) = arcsin (sindec)
            a(i) = proj%a0 + atan2( sinr*sinp*proj%sind0, sindec*proj%cosd0-sinr*cosp )
          else
            a(i) = proj%a0
            d(i) = proj%d0
          endif
        else
          a(i) = 0.d0
          d(i) = 0.d0
        endif
      enddo
    elseif (proj%sind0.lt.-precision) then
      do i = 1,n
        r = x(i)**2+y(i)**2
        if (r.le.1.d0) then
          sinr = sqrt(r)
          r = arcsin ( sinr )
          if (sinr.gt.precision) then
            p = atan2 ( x(i),y(i) ) - proj%angle
            cosr = cos(r)
            sinp = sin(p)
            cosp = cos(p)
            sindec = (proj%sind0*cosr + proj%cosd0*sinr*cosp)
            d(i) = arcsin (sindec)
            a(i) = proj%a0 + atan2( sinr*sinp*proj%sind0, sindec*proj%cosd0-sinr*cosp ) + pi
          else
            a(i) = proj%a0
            d(i) = proj%d0
          endif
        else
          a(i) = 0.d0
          d(i) = 0.d0
        endif
      enddo
    else
      do i=1,n
        r = x(i)**2+y(i)**2
        if (r.le.1.d0) then
          sinr = sqrt(r)
          r = arcsin ( sinr )
          if (sinr.gt.precision) then
            p = atan2 ( x(i),y(i) ) - proj%angle
            cosr = cos(r)
            sinp = sin(p)
            cosp = cos(p)
            sindec = (proj%sind0*cosr + proj%cosd0*sinr*cosp)
            d(i) = arcsin (sindec)
            a(i) = proj%a0 + atan2( sinr*sinp, cosr + proj%sind0*sinr*cosp)
          else
            a(i) = proj%a0
            d(i) = proj%d0
          endif
        else
          a(i) = 0.d0
          d(i) = 0.d0
        endif
      enddo
    endif
    !
  case(p_azimuthal)  ! Azimuthal or Schmidt
    if (proj%sind0.gt.precision) then
      do i = 1,n
        r = sqrt(x(i)**2+y(i)**2)
        if (r.le.precision) then
          a(i) = proj%a0
          d(i) = proj%d0
        elseif (r.le.pi-precision) then
          p = atan2 ( x(i),y(i) ) - proj%angle
          sinr = sin(r)
          cosr = cos(r)
          sinp = sin(p)
          cosp = cos(p)
          sindec = (proj%sind0*cosr + proj%cosd0*sinr*cosp)
          d(i) = arcsin (sindec)
          a(i) = proj%a0 + atan2( sinr*sinp*proj%sind0, sindec*proj%cosd0-sinr*cosp )
        elseif (r.lt.pi+precision) then
          a(i) = proj%a0
          d(i) = -proj%d0
        else
          a(i) = 0.d0
          d(i) = 0.d0
        endif
      enddo
    elseif (proj%sind0.lt.-precision) then
      do i = 1,n
        r = sqrt(x(i)**2+y(i)**2)
        if (r.le.precision) then
          a(i) = proj%a0
          d(i) = proj%d0
        elseif (r.le.pi-precision) then
          p = atan2 ( x(i),y(i) ) - proj%angle
          sinr = sin(r)
          cosr = cos(r)
          sinp = sin(p)
          cosp = cos(p)
          sindec = (proj%sind0*cosr + proj%cosd0*sinr*cosp)
          d(i) = arcsin (sindec)
          a(i) = proj%a0 + atan2( sinr*sinp*proj%sind0, sindec*proj%cosd0-sinr*cosp ) + pi
        elseif (r.lt.pi+precision) then
          a(i) = proj%a0
          d(i) = -proj%d0
        else
          a(i) = 0.d0
          d(i) = 0.d0
        endif
      enddo
    else
      do i = 1,n
        r = sqrt(x(i)**2+y(i)**2)
        if (r.le.precision) then
          a(i) = proj%a0
          d(i) = proj%d0
        elseif (r.le.pi-precision) then
          p = atan2 ( x(i),y(i) ) - proj%angle
          sinr = sin(r)
          cosr = cos(r)
          sinp = sin(p)
          cosp = cos(p)
          sindec = (proj%sind0*cosr + proj%cosd0*sinr*cosp)
          d(i) = arcsin (sindec)
          a(i) = proj%a0 + atan2( sinr*sinp, cosr + proj%sind0*sinr*cosp)
        elseif (r.lt.pi+precision) then
          a(i) = proj%a0
          d(i) = -proj%d0
        else
          a(i) = 0.d0
          d(i) = 0.d0
        endif
      enddo
    endif
    !
  case(p_stereo)  ! Stereographic
    if (proj%sind0.gt.precision) then
      do i = 1,n
        r = sqrt(x(i)**2+y(i)**2)
        if (r.le.precision) then
          a(i) = proj%a0
          d(i) = proj%d0
        else
          r = 2.d0 * atan (r/2.d0)
          p = atan2 ( x(i),y(i) ) - proj%angle
          sinr = sin(r)
          cosr = cos(r)
          sinp = sin(p)
          cosp = cos(p)
          sindec = (proj%sind0*cosr + proj%cosd0*sinr*cosp)
          d(i) = arcsin (sindec)
          a(i) = proj%a0 + atan2( sinr*sinp*proj%sind0, sindec*proj%cosd0-sinr*cosp )
        endif
      enddo
    elseif (proj%sind0.lt.-precision) then
      do i = 1,n
        r = sqrt(x(i)**2+y(i)**2)
        if (r.le.precision) then
          a(i) = proj%a0
          d(i) = proj%d0
        else
          r = 2.d0 * atan (r)
          p = atan2 ( x(i),y(i) ) - proj%angle
          sinr = sin(r)
          cosr = cos(r)
          sinp = sin(p)
          cosp = cos(p)
          sindec = (proj%sind0*cosr + proj%cosd0*sinr*cosp)
          d(i) = arcsin (sindec)
          a(i) = proj%a0 + atan2( sinr*sinp*proj%sind0, sindec*proj%cosd0-sinr*cosp ) + pi
        endif
      enddo
    else
      do i=1,n
        r = sqrt(x(i)**2+y(i)**2)
        if (r.le.precision) then
          a(i) = proj%a0
          d(i) = proj%d0
        else
          r = 2.d0 * atan (r)
          p = atan2 ( x(i),y(i) ) - proj%angle
          sinr = sin(r)
          cosr = cos(r)
          sinp = sin(p)
          cosp = cos(p)
          sindec = (proj%sind0*cosr + proj%cosd0*sinr*cosp)
          d(i) = arcsin (sindec)
          if (0.5d0*pi-abs(d(i)).gt.precision) then
            a(i) = proj%a0 + atan2( sinr*sinp, cosr + proj%sind0*sinr*cosp)
          else
            a(i) = proj%a0
          endif
        endif
      enddo
    endif
    !
  case(p_lambert)  ! Lambert equal area
    !  u = 2*sin(r)/sqrt(2*(1+cos(r))
    !  r = acos (1-0.5*u**2)
    if (proj%sind0.gt.precision) then
      do i = 1,n
        r = x(i)**2+y(i)**2
        if (r.le.precision) then
          a(i) = proj%a0
          d(i) = proj%d0
        elseif (r.le.4d0) then
          r = acos (1d0-0.5d0*r)
          p = atan2 ( x(i),y(i) ) - proj%angle
          sinr = sin(r)
          cosr = cos(r)
          sinp = sin(p)
          cosp = cos(p)
          sindec = (proj%sind0*cosr + proj%cosd0*sinr*cosp)
          d(i) = arcsin (sindec)
          a(i) = proj%a0 + atan2( sinr*sinp*proj%sind0, sindec*proj%cosd0-sinr*cosp )
        else
          a(i) = 0.0
          d(i) = 0.0
        endif
      enddo
    elseif (proj%sind0.lt.-precision) then
      do i = 1,n
        r = x(i)**2+y(i)**2
        if (r.le.precision) then
          a(i) = proj%a0
          d(i) = proj%d0
        elseif (r.le.4d0) then
          r = acos (1d0-0.5d0*r)
          p = atan2 ( x(i),y(i) ) - proj%angle
          sinr = sin(r)
          cosr = cos(r)
          sinp = sin(p)
          cosp = cos(p)
          sindec = (proj%sind0*cosr + proj%cosd0*sinr*cosp)
          d(i) = arcsin (sindec)
          a(i) = proj%a0 + atan2( sinr*sinp*proj%sind0, sindec*proj%cosd0-sinr*cosp ) + pi
        else
          a(i) = 0.0
          d(i) = 0.0
        endif
      enddo
    else
      do i=1,n
        r = x(i)**2+y(i)**2
        if (r.le.precision) then
          a(i) = proj%a0
          d(i) = proj%d0
        elseif (r.le.4d0) then
          r = acos (1.d0-0.5d0*r)
          p = atan2 ( x(i),y(i) ) - proj%angle
          sinr = sin(r)
          cosr = cos(r)
          sinp = sin(p)
          cosp = cos(p)
          sindec = (proj%sind0*cosr + proj%cosd0*sinr*cosp)
          d(i) = arcsin (sindec)
          if (0.5d0*pi-abs(d(i)).gt.precision) then
            a(i) = proj%a0 + atan2( sinr*sinp, cosr + proj%sind0*sinr*cosp)
          else
            a(i) = proj%a0
          endif
        else
          a(i) = 0.0
          d(i) = 0.0
        endif
      enddo
    endif
    !
  case(p_aitoff)  ! Aitoff
    do i = 1,n
      changesign = y(i).lt.0.d0
      sinr = 0.5d0*sqrt(0.25d0*x(i)**2+y(i)**2)
      if (sinr.gt.1.d0) then
        a(i) = proj%a0
        d(i) = 0.5d0*pi
      elseif (sinr.gt.precision) then
        r = 2.d0 * arcsin(sinr)
        p = atan2 ( x(i),2.d0*y(i) )
        cosr = cos(r)
        da = atan2 (sin(p)*sin(r),cosr)
        d(i) = arccos ( cosr/cos(da) )
        a(i) = proj%a0 + 2.d0*da
      else
        a(i) = proj%a0                !      + 2.D0*ARCSIN(SINR)
        d(i) = 0.d0
      endif
      if (changesign) d(i) = -d(i)
    enddo
    !
  case(p_radio)  ! GLS:  Classical Single-Dish mapping
    do i=1,n
      if (y(i).le.proj%spole) then
        a(i) = proj%a0
        d(i) = -pi*0.5d0
      elseif (y(i).ge.proj%npole) then
        a(i) = proj%a0
        d(i) = pi*0.5d0
      else
        p = proj%d0 + y(i)
        d(i) = p
        r = x(i)/cos(p)
        if (r.le.-pi) then
          a(i) = proj%a0-pi
        elseif (r.ge.pi) then
          a(i) = proj%a0+pi
        else
          a(i) = proj%a0 + r
        endif
      endif
    enddo
    !
  case(p_sfl)
    call rel_to_abs_sfl(proj,x,y,a,d,n)
    !
  case(p_mollweide)  ! Mollweide
    do i=1,n
      theta = asin(y(i)/sqrt(2.d0))
      a(i) = proj%a0 + pi*x(i) / ( 2.d0*sqrt(2.d0)*cos(theta) )
      d(i) = asin( (2.d0*theta+sin(2.d0*theta)) / pi )
    enddo
    !
  case(p_ncp)  ! North Celestial Pole projection (used by the WSRT)
    do i=1,n
      da = atan2( x(i), proj%cosd0-y(i)*proj%sind0 )
      cosda = cos(da)
      if (abs(cosda).lt.precision) then
        if (x(i).ge.0.d0) then
          a(i) = proj%a0 + pi/2.d0
          d(i) = acos(x(i))
        else
          a(i) = proj%a0 - pi/2.d0
          d(i) = acos(-x(i))
        endif
      else
        a(i) = proj%a0 + da
        d(i) = sign(1d0,proj%d0) * acos( (proj%cosd0-y(i)*proj%sind0) / cosda )
      endif
    enddo
    !
  case(p_none)
    a(1:n) = x(1:n)
    d(1:n) = y(1:n)
    call gwcs_message(seve%w,'PROJECTION','No coordinate conversion for projection NONE (2)')
  case default
    call gwcs_message(seve%e,'PROJECTION','Unsupported projection (2)')
    return
  end select
  !
  ! Modulo the a(:) values. We want
  ! 1)   0   < a0 < 2*pi    to be consistent with e.g. V\HEADER which prints
  !                         it in this range
  ! 2) a0-pi < a  < a0+pi   to ensure that there is no discontinuity when a0
  !                         neighbours 0 or 2*pi. This means that 'a' can be
  !                         slightly under 0 or beyond 2*pi (24h).
  ma0 = modulo(proj%a0,2d0*pi)
  do i=1,n
    if (a(i).lt.ma0-pi) then
      a(i) = a(i) + 2d0*pi
    elseif (a(i).gt.ma0+pi) then
      a(i) = a(i) - 2d0*pi
    endif
  enddo
  !
end subroutine rel_to_abs_1dn8
!
subroutine rel_to_abs_sfl(proj,x,y,a,d,n)
  use phys_const
  use gwcs_types
  !---------------------------------------------------------------------
  ! @ private
  ! SFL: see Calabretta and Greisen 2002
  !
  ! Their general idea, as described in section 2, is that
  ! 1) you convert from (x,y) projected coordinates to the "native"
  !    absolute spherical coordinate: (x,y) are converted to
  !    (phi,theta).
  ! 2) you rotate the absolute native coordinates (phi,theta) to
  !    absolute celestial coordinates (alpha,delta) (Euler rotation of
  !    the native sphere).
  ! => those 2 steps are grouped in Eq. 2, 8, 9, 10.
  !
  ! In the context of SFL, these equations can be simplified. As per
  ! section 5.3, SFL projection is a pseudo-spherical projection with
  ! coordinates of the reference point (phi_0,theta_0) = (0,0). Also,
  ! (phi,theta) are defined in Eq. 92, 93 for SFL projection.
  !---------------------------------------------------------------------
  type(projection_t), intent(in)  :: proj  ! Description of projection
  real(kind=8),       intent(in)  :: x(*)  ! Array of offsets in X
  real(kind=8),       intent(in)  :: y(*)  ! Array of offsets in Y
  real(kind=8),       intent(out) :: a(*)  ! Array of R.A. (radians)
  real(kind=8),       intent(out) :: d(*)  ! Array of declinations
  integer(kind=8),    intent(in)  :: n     ! Size of arrays
  ! Local
  real(kind=8) :: phi,theta,cost,sint
  real(kind=8) :: cosppp,sinppp
  integer(kind=8) :: i
  !
  do i=1,n
    theta = y(i)       ! Eq. 92
    cost = cos(theta)
    sint = sin(theta)
    phi  = x(i)/cost   ! Eq. 93
    cosppp = cos(phi-proj%sfl%phi_p)
    sinppp = sin(phi-proj%sfl%phi_p)
    ! Eq. 2:
    a(i) = proj%sfl%alpha_p +  &
              atan2(-cost*sinppp,  &
                     sint*proj%sfl%cosdp - cost*proj%sfl%sindp*cosppp)
    d(i) = asin( sint*proj%sfl%sindp + cost*proj%sfl%cosdp*cosppp )
  enddo
  !
end subroutine rel_to_abs_sfl
!
subroutine abs_to_rel_0d(proj,a,d,x,y,n)
  use gwcs_interfaces, except_this=>abs_to_rel_0d
  use gwcs_types
  !---------------------------------------------------------------------
  ! @ public-generic abs_to_rel
  !  Convert a set of plane position to spherical coordinates according
  ! to the current projection formulae
  ! ---
  ! This version for scalar values
  !---------------------------------------------------------------------
  type(projection_t), intent(in)  :: proj  ! Description of projection
  real(kind=8),       intent(in)  :: a     ! R.A. (radians)
  real(kind=8),       intent(in)  :: d     ! Declinations
  real(kind=8),       intent(out) :: x     ! Offset in X
  real(kind=8),       intent(out) :: y     ! Offset in Y
  integer(kind=4),    intent(in)  :: n     ! Useless, assumed 1
  ! Local
  real(kind=8) :: a1(1),d1(1),x1(1),y1(1)
  !
  a1(1) = a
  d1(1) = d
  call abs_to_rel_1dn8(proj,a1,d1,x1,y1,1_8)
  x = x1(1)
  y = y1(1)
  !
end subroutine abs_to_rel_0d
!
subroutine abs_to_rel_1dn4(proj,a,d,x,y,n)
  use phys_const
  use gbl_constant
  use gbl_message
  use gwcs_interfaces, except_this=>abs_to_rel_1dn4
  use gwcs_types
  !---------------------------------------------------------------------
  ! @ public-generic abs_to_rel
  !  Convert a set of plane position to spherical coordinates according
  ! to the current projection formulae
  ! ---
  ! This version for 1D arrays, size as I*4
  !---------------------------------------------------------------------
  type(projection_t), intent(in)  :: proj  ! Description of projection
  real(kind=8),       intent(in)  :: a(*)  ! Array of R.A. (radians)
  real(kind=8),       intent(in)  :: d(*)  ! Array of declinations
  real(kind=8),       intent(out) :: x(*)  ! Array of offsets in X
  real(kind=8),       intent(out) :: y(*)  ! Array of offsets in Y
  integer(kind=4),    intent(in)  :: n     ! Size of arrays
  !
  call abs_to_rel_1dn8(proj,a,d,x,y,int(n,kind=8))
  !
end subroutine abs_to_rel_1dn4
!
subroutine abs_to_rel_1dn8(proj,a,d,x,y,n)
  use phys_const
  use gbl_constant
  use gbl_message
  use gwcs_interfaces, except_this=>abs_to_rel_1dn8
  use gwcs_types
  !---------------------------------------------------------------------
  ! @ public-generic abs_to_rel
  !  Convert a set of plane position to spherical coordinates according
  ! to the current projection formulae
  ! ---
  ! This version for 1D arrays, size as I*8
  !---------------------------------------------------------------------
  type(projection_t), intent(in)  :: proj  ! Description of projection
  real(kind=8),       intent(in)  :: a(*)  ! Array of R.A. (radians)
  real(kind=8),       intent(in)  :: d(*)  ! Array of declinations
  real(kind=8),       intent(out) :: x(*)  ! Array of offsets in X
  real(kind=8),       intent(out) :: y(*)  ! Array of offsets in Y
  integer(kind=8),    intent(in)  :: n     ! Size of arrays
  ! Local
  real(kind=8), parameter :: precision=1.0d-10
  real(kind=8) :: r,p,cosdec,sindec,cosa,sina,expr,da,cosda,theta,dtheta,cpang,spang
  integer(kind=8) :: i
  logical :: changesign
  !
  select case(proj%type)
  case(p_cartesian)  ! Cartesian projection
    if (abs(proj%angle).le.precision) then
      do i = 1, n
        x(i) = a(i)-proj%a0
        y(i) = d(i)-proj%d0
      enddo
    else
      cpang = cos(proj%angle)
      spang = sin(proj%angle)
      do i = 1, n
        r = a(i)-proj%a0
        p = d(i)-proj%d0
        x(i) =  r*cpang+p*spang
        y(i) = -r*spang+p*cpang
      enddo
    endif
    !
  case(p_gnomonic)  ! Gnomonic
    if (abs(proj%sind0).ge.precision) then
      do i = 1,n
        sindec = sin(d(i))
        cosdec = cos(d(i))
        sina = sin(a(i)-proj%a0)
        cosa = cos(a(i)-proj%a0)
        expr = sindec*proj%cosd0-cosdec*proj%sind0*cosa
        r = arccos ( (sindec - proj%cosd0*expr)/proj%sind0 )
        if (r.gt.precision) then
          p = atan2 ( cosdec*sina , expr ) + proj%angle
          expr = tan(r)
          x(i) =  expr*sin(p)
          y(i) =  expr*cos(p)
        else
          x(i) = 0.d0
          y(i) = 0.d0
        endif
      enddo
    else
      do i=1,n
        sina = sin(a(i)-proj%a0)
        cosa = cos(a(i)-proj%a0)
        cosdec = cos(d(i))
        sindec = sin(d(i))
        r = arccos ( cosdec*cosa )
        if (r.ge.precision) then
          p = atan2 ( cosdec*sina,sindec ) + proj%angle
          expr = tan(r)
          x(i) =  expr*sin(p)
          y(i) =  expr*cos(p)
        else
          x(i) = 0.d0
          y(i) = 0.d0
        endif
      enddo
    endif
    !
  case(p_ortho)  ! Dixon or Orthographic
    if (abs(proj%sind0).ge.precision) then
      do i = 1,n
        sindec = sin(d(i))
        cosdec = cos(d(i))
        sina = sin(a(i)-proj%a0)
        cosa = cos(a(i)-proj%a0)
        expr = sindec*proj%cosd0-cosdec*proj%sind0*cosa
        r = arccos ( (sindec - proj%cosd0*expr)/proj%sind0 )
        if (r.gt.precision) then
          p = atan2 ( cosdec*sina , expr ) + proj%angle
          expr = sin(r)
          !!!                 if (r.ge.pi/2) r=pi/2
          x(i) = expr*sin(p)
          y(i) = expr*cos(p)
        else
          x(i) = 0.d0
          y(i) = 0.d0
        endif
      enddo
    else
      do i=1,n
        sina = sin(a(i)-proj%a0)
        cosa = cos(a(i)-proj%a0)
        cosdec = cos(d(i))
        sindec = sin(d(i))
        r = arccos ( cosdec*cosa )
        if (r.ge.precision) then
          p = atan2 ( cosdec*sina,sindec ) + proj%angle
          expr = sin(r)
          !!!                 if (r.ge.pi/2) r=pi/2
          x(i) = expr*sin(p)
          y(i) = expr*cos(p)
        else
          x(i) = 0.d0
          y(i) = 0.d0
        endif
      enddo
    endif
    !
  case(p_azimuthal)  ! Azimuthal or Schmidt
    if (abs(proj%sind0).ge.precision) then
      do i = 1,n
        sindec = sin(d(i))
        cosdec = cos(d(i))
        sina = sin(a(i)-proj%a0)
        cosa = cos(a(i)-proj%a0)
        expr = sindec*proj%cosd0-cosdec*proj%sind0*cosa
        r = arccos ( (sindec - proj%cosd0*expr)/proj%sind0 )
        if (r.gt.precision) then
          p = atan2 ( cosdec*sina , expr ) + proj%angle
          x(i) = r*sin(p)
          y(i) = r*cos(p)
        else
          x(i) = 0.d0
          y(i) = 0.d0
        endif
      enddo
    else
      do i=1,n
        sina = sin(a(i)-proj%a0)
        cosa = cos(a(i)-proj%a0)
        cosdec = cos(d(i))
        sindec = sin(d(i))
        r = arccos ( cosdec*cosa )
        if (r.ge.precision) then
          p = atan2 ( cosdec*sina,sindec ) + proj%angle
          x(i) = r*sin(p)
          y(i) = r*cos(p)
        else
          x(i) = 0.d0
          y(i) = 0.d0
        endif
      enddo
    endif
    !
  case(p_stereo)  ! Stereographic
    if (abs(proj%sind0).ge.precision) then
      do i = 1,n
        sindec = sin(d(i))
        cosdec = cos(d(i))
        sina = sin(a(i)-proj%a0)
        cosa = cos(a(i)-proj%a0)
        expr = sindec*proj%cosd0-cosdec*proj%sind0*cosa
        r = arccos ( (sindec - proj%cosd0*expr)/proj%sind0 )
        if (r.gt.precision) then
          p = atan2 ( cosdec*sina , expr ) + proj%angle
          expr = 2.d0*tan(r*0.5d0)
          x(i) =  expr*sin(p)
          y(i) =  expr*cos(p)
        else
          x(i) = 0.d0
          y(i) = 0.d0
        endif
      enddo
    else
      do i=1,n
        sina = sin(a(i)-proj%a0)
        cosa = cos(a(i)-proj%a0)
        cosdec = cos(d(i))
        sindec = sin(d(i))
        r = arccos ( cosdec*cosa )
        if (r.ge.precision) then
          p = atan2 ( cosdec*sina,sindec ) + proj%angle
          expr = tan(r*0.5d0)
          x(i) =  expr*sin(p)
          y(i) =  expr*cos(p)
        else
          x(i) = 0.d0
          y(i) = 0.d0
        endif
      enddo
    endif
    !
  case(p_lambert)  ! Lambert equal area
    if (abs(proj%sind0).ge.precision) then
      do i = 1,n
        sindec = sin(d(i))
        cosdec = cos(d(i))
        sina = sin(a(i)-proj%a0)
        cosa = cos(a(i)-proj%a0)
        expr = sindec*proj%cosd0-cosdec*proj%sind0*cosa
        r = arccos ( (sindec - proj%cosd0*expr)/proj%sind0 )
        if (r.gt.precision) then
          p = atan2 ( cosdec*sina , expr ) + proj%angle
          if (r.ge.pi-precision) then
            expr = 2.0
          else
            expr = 2.d0*sin(r)/sqrt(2.d0*(1.d0+cos(r)))
          endif
          x(i) =  expr*sin(p)
          y(i) =  expr*cos(p)
        else
          x(i) = 0.d0
          y(i) = 0.d0
        endif
      enddo
    else
      do i=1,n
        sina = sin(a(i)-proj%a0)
        cosa = cos(a(i)-proj%a0)
        cosdec = cos(d(i))
        sindec = sin(d(i))
        r = arccos ( cosdec*cosa )
        if (r.ge.precision) then
          p = atan2 ( cosdec*sina,sindec ) + proj%angle
          if (r.ge.pi-precision) then
            expr = 2.0
          else
            expr = 2.d0*sin(r)/sqrt(2.d0*(1.d0+cos(r)))
          endif
          x(i) =  expr*sin(p)
          y(i) =  expr*cos(p)
        else
          x(i) = 0.d0
          y(i) = 0.d0
        endif
      enddo
    endif
    !
  case(p_aitoff)  ! Aitoff
    do i=1,n
      changesign = d(i).lt.0.d0
      da = a(i) - proj%a0
      do while (da.lt.-pi)
        da = da + 2.d0*pi
      enddo
      do while (da.gt.pi)
        da = da - 2.d0*pi
      enddo
      da = da*0.5d0
      if (da.eq.0.d0 .and. d(i).eq.0.d0) then
        x(i)=0.d0
        y(i)=0.d0
      else
        cosdec = cos(d(i))
        r = arccos( cosdec*cos(da) )
        expr = min ( max(cosdec*sin(da)/sin(r),-1.d0), 1.d0)
        r = 2.d0*sin(r*0.5d0)
        x(i) = 2.d0*r*expr
        y(i) = r*cos(arcsin(expr))
        if (changesign) y(i)=-y(i)
      endif
    enddo
    !
  case(p_radio)  ! Classical Single-Dish mapping
    do i=1,n
      p = d(i)
      da = a(i)-proj%a0
      do while (da.lt.-pi)
        da = da+2.d0*pi
      enddo
      do while (da.gt.pi)
        da = da-2.d0*pi
      enddo
      x(i) = da*cos(p)
      y(i) = p-proj%d0
    enddo
    !
  case(p_sfl)  ! SFL Calabretta & Greisen
    call abs_to_rel_sfl(proj,a,d,x,y,n)
    !
  case(p_mollweide)  ! Mollweide
    ! References:
    !  - "Map projections - A working manual" by John P. Snyder (U.S. Geological
    !    Survey Professional Paper 1395)
    !  - https://en.wikipedia.org/wiki/Mollweide_projection
    !  - https://fr.wikipedia.org/wiki/Projection_de_Mollweide
    do i=1,n
      !
      if (d(i).ge.pi/2.d0) then
        x(i) = 0.d0
        y(i) = proj%npole
      elseif (d(i).le.-pi/2.d0) then
        x(i) = 0.d0
        y(i) = proj%spole
      else
        ! Determine auxiliary angle theta such as:
        ! 2 theta + sin(2 theta) = pi sin(d)
        ! Use Newton-Raphson iterative method (rapid convergence, slower near
        ! the poles)
        theta = 2.d0*d(i)  ! Start point
        dtheta = pi        ! Precision reached
        ! The minimal precision to be reached has been chosen by checking
        ! that the conversion loop absolute -> relative -> absolute
        ! coordinates is accurate down to the milliarcsec, for a set of
        ! coordinates sampling the whole sphere (especially near the pole).
        do while (abs(dtheta).gt.pi/5.d4)
          dtheta = (theta + sin(theta) - pi*sin(d(i))) /  &
                  (1.d0 + cos(theta))
          theta = theta - dtheta
        enddo
        ! We have resolved theta' = 2 theta. Find theta:
        theta = theta/2.d0
        !
        x(i) = 2.d0*sqrt(2.d0)*(a(i)-proj%a0)*cos(theta)/pi
        y(i) = sqrt(2.d0) * sin(theta)
      endif
      !
    enddo
      !
  case(p_ncp)  ! North Celestial Pole projection (used by the WSRT)
    do i=1,n
      da = a(i)-proj%a0
      x(i) = cos(d(i)) * sin(da)
      cosda = cos(da)
      if (abs(cosda).lt.precision) then
        y(i) = proj%cosd0 / proj%sind0
      else
        y(i) = (proj%cosd0 - cos(d(i))*cos(da)) / proj%sind0
      endif
    enddo
    !
  case(p_none)
    x(1:n) = a(1:n)
    y(1:n) = d(1:n)
    call gwcs_message(seve%w,'PROJECTION','No coordinate conversion for projection NONE (3)')
  case default
    call gwcs_message(seve%e,'PROJECTION','Unsupported projection (3)')
  end select
  !
end subroutine abs_to_rel_1dn8
!
subroutine abs_to_rel_sfl(proj,a,d,x,y,n)
  use gwcs_types
  !---------------------------------------------------------------------
  ! @ private
  ! SFL: see Calabretta and Greisen 2002
  !
  ! See comments in rel_to_abs_sfl
  !---------------------------------------------------------------------
  type(projection_t), intent(in)  :: proj  ! Description of projection
  real(kind=8),       intent(in)  :: a(*)  ! Array of R.A. (radians)
  real(kind=8),       intent(in)  :: d(*)  ! Array of declinations
  real(kind=8),       intent(out) :: x(*)  ! Array of offsets in X
  real(kind=8),       intent(out) :: y(*)  ! Array of offsets in Y
  integer(kind=8),    intent(in)  :: n     ! Size of arrays
  ! Local
  real(kind=8) :: cosd,sind,cosaap,sinaap,phi,theta
  integer(kind=8) :: i
  !
  do i=1,n
    cosd   = cos(d(i))
    sind   = sin(d(i))
    cosaap = cos(a(i)-proj%sfl%alpha_p)
    sinaap = sin(a(i)-proj%sfl%alpha_p)
    ! Eq. 5:
    phi = proj%sfl%phi_p +  &
          atan2( -cosd*sinaap,  &
            sind*proj%sfl%cosdp - cosd*proj%sfl%sindp*cosaap)
    theta = asin(sind*proj%sfl%sindp + cosd*proj%sfl%cosdp*cosaap)
    ! Eq. 90, 91:
    x(i) = phi * cos(theta)
    y(i) = theta
  enddo
  !
end subroutine abs_to_rel_sfl
!
function arcsin (x)
  use phys_const
  !---------------------------------------------------------------------
  ! @ private
  !---------------------------------------------------------------------
  real(kind=8) :: arcsin         !
  real(kind=8), intent(in) :: x  !
  !
  if (x.le.-1.d0) then
    arcsin = -pi*0.5d0
  elseif (x.ge.1.d0) then
    arcsin = pi*0.5d0
  else
    arcsin = asin(x)
  endif
end function arcsin
!
function arccos (x)
  use phys_const
  !---------------------------------------------------------------------
  ! @ private
  !---------------------------------------------------------------------
  real(kind=8) :: arccos         !
  real(kind=8), intent(in) :: x  !
  !
  if (x.le.-1.d0) then
    arccos = pi
  elseif (x.ge.1.d0) then
    arccos = 0.0d0
  else
    arccos = acos(x)
  endif
end function arccos
!
subroutine gwcs_projec(a0,d0,pangle,ptype,proj,error)
  use phys_const
  use gbl_constant
  use gbl_message
  use gwcs_interfaces, except_this=>gwcs_projec
  use gwcs_types
  !---------------------------------------------------------------------
  ! @ public
  !       Define a projection
  !---------------------------------------------------------------------
  real(kind=8),       intent(in)    :: a0      !
  real(kind=8),       intent(in)    :: d0      !
  real(kind=8),       intent(in)    :: pangle  !
  integer(kind=4),    intent(in)    :: ptype   !
  type(projection_t), intent(out)   :: proj    !
  logical,            intent(inout) :: error   !
  ! Local
  character(len=*), parameter :: rname='PROJECTION'
  real(kind=8), parameter :: halfpi=pi/2.d0
  real(kind=8) :: x,delta_p_1,delta_p_2,cospp
  !
  ! Setup necessary constants
  proj%type  = ptype
  proj%a0    = a0
  proj%d0    = d0
  proj%angle = pangle
  if (proj%type.eq.p_none) return
  !
  proj%sind0 = sin(d0)
  proj%cosd0 = cos(d0)
  proj%sina0 = sin(a0)
  proj%cosa0 = cos(a0)
  !
  ! Compute POLE position and values of remarkable points
  select case(proj%type)
  case(p_cartesian)
    proj%npole =  pi*0.5d0 - proj%d0
    proj%spole = -pi*0.5d0 - proj%d0
    !
  case(p_gnomonic)
    if (proj%d0.lt.-1.d-30) then
      proj%spole = 1.d0/tan(proj%d0)
      proj%npole = 1.d38
    elseif (proj%d0.gt.1.d-30) then
      proj%npole = 1.d0/tan(proj%d0)
      proj%spole = 1.d38
    else
      proj%npole = 1.d38
      proj%spole = 1.d38
    endif
    !
  case(p_ortho)
    if (proj%d0.lt.-1.d-30) then    ! North pole invisible
      proj%spole = -proj%cosd0
      proj%npole = 1.d38
    elseif(proj%d0.gt.1.d-30) then  ! South pole invisible
      proj%npole = proj%cosd0
      proj%spole = 1.d38
    else                            ! Both poles visibles
      proj%npole = 1.d0
      proj%spole = -1.d0
    endif
    !
  case(p_azimuthal)
    if (proj%d0.lt.0.d0) then
      proj%spole = -proj%d0-pi*0.5d0
      proj%npole = pi*0.5d0+proj%d0
    else
      proj%spole = proj%d0-pi*0.5d0
      proj%npole = pi*0.5d0-proj%d0
    endif
    !
  case(p_stereo)
    if (abs(proj%d0).gt.1.d-30) then
      call abs_to_rel(proj,0.d0,pi*0.5d0,x,proj%npole,1)
      call abs_to_rel(proj,0.d0,-pi*0.5d0,x,proj%spole,1)
    else
      proj%npole = 1.d0
      proj%spole = -1.d0
    endif
    !
  case(p_lambert)
    ! if (abs(proj%d0).gt.1.d-30) then
    call abs_to_rel(proj,0.d0,pi*0.5d0,x,proj%npole,1)
    call abs_to_rel(proj,0.d0,-pi*0.5d0,x,proj%spole,1)
    ! else
    !   proj%npole = 2.d0
    !   proj%spole = -2.d0
    ! endif
    !
  case(p_aitoff)
    if (proj%angle.ne.0.d0) then
      call gwcs_message(seve%w,rname,'AITOFF does not support a projection angle')
      proj%angle = 0.d0
    endif
    proj%npole = sqrt(2.0d0)
    proj%spole = -proj%npole
    proj%d0 = 0.d0
    proj%cosd0 = 1.d0
    proj%sind0 = 0.d0
    !
  case(p_radio)
    if (proj%angle.ne.0.d0) then
      call gwcs_message(seve%w,rname,'RADIO does not support a projection angle')
      proj%angle = 0.d0
    endif
    proj%npole = pi*0.5d0 - proj%d0
    proj%spole = -proj%d0 - pi*0.5d0
    !
  case(p_sfl)
    if (proj%angle.ne.0.d0) then
      call gwcs_message(seve%w,rname,'SFL does not support a projection angle')
      proj%angle = 0.d0
    endif
    proj%npole = halfpi - proj%d0
    proj%spole = -proj%d0 - halfpi
    ! See Calabretta & Greisen 2002 for references.
    ! Section 2.2 last paragraph: phi_p (LONPOLEa)
    if (proj%d0.ge.0.d0) then
      proj%sfl%phi_p = 0.d0
      cospp = 1.d0
    ! sinpp = 0.d0
    else
      proj%sfl%phi_p = pi
      cospp = -1.d0
    ! sinpp = 0.d0
    endif
    ! Eq 8:
    delta_p_1 = atan2(0.d0,cospp) + acos(proj%sind0)
    delta_p_2 = atan2(0.d0,cospp) - acos(proj%sind0)
    ! Section 2.4 gives a lot of rules to chose between the 2:
    if (delta_p_1.gt.0.d0 .and. delta_p_1.le.halfpi) then
      ! No LATPOLE, northen is the default (rule #4)
      proj%sfl%delta_p = delta_p_1
    else
      proj%sfl%delta_p = delta_p_2
    endif
    if (abs(proj%sfl%delta_p-halfpi).le.1d-10)  then
      ! delta_p = +pi/2 => rule #2
      proj%sfl%sindp = 1.d0
      proj%sfl%cosdp = 0.d0
      proj%sfl%alpha_p = proj%a0 + proj%sfl%phi_p - pi
    elseif (abs(proj%sfl%delta_p+halfpi).le.1d-10)  then
      ! delta_p = -pi/2 => rule #2
      proj%sfl%sindp = -1.d0
      proj%sfl%cosdp =  0.d0
      proj%sfl%alpha_p = proj%a0 - proj%sfl%phi_p
    else
      proj%sfl%sindp = sin(proj%sfl%delta_p)
      proj%sfl%cosdp = cos(proj%sfl%delta_p)
      ! Eq 9+10 combined as atan2(sin,cos)
      proj%sfl%alpha_p = proj%a0 -  &
                        atan2(0.d0,-proj%sfl%sindp*proj%sind0/(proj%sfl%cosdp*proj%cosd0))
    endif
    !
  case(p_mollweide)
    if (proj%angle.ne.0.d0) then
      call gwcs_message(seve%w,rname,'Mollweide does not support a projection angle')
      proj%angle = 0.d0
    endif
    if (proj%d0.ne.0.d0) then
      call gwcs_message(seve%w,rname,'Mollweide projection center must be on equator')
      proj%d0 = 0.d0
      proj%cosd0 = 1.d0
      proj%sind0 = 0.d0
      ! Note that we could tolerate a non-zero declination. However, the tangent
      ! plane would remain on the equator, but the overall projected map would
      ! be Y-shifted (same behaviour as radio projection).
    endif
    proj%npole = sqrt(2.d0)
    proj%spole = -sqrt(2.d0)
    !
  case(p_ncp)
    if (proj%d0.le.0.d0) then
      call gwcs_message(seve%w,rname,  &
        'North Celestial Pole projection center must be in North hemisphere')
      proj%d0 = pi/2.d0
      proj%cosd0 = 0.d0
      proj%sind0 = 1.d0
    endif
    proj%npole = proj%cosd0/proj%sind0
    proj%spole = 1.d38  ! Invisible
    !
  case default
    call gwcs_message(seve%e,rname,'Unsupported projection (1)')
    error = .true.
    return
  end select
  !
end subroutine gwcs_projec
!
subroutine abs_add_distance(lon1,lat1,off,angl,lon2,lat2)
  !---------------------------------------------------------------------
  ! @ public
  !   Add a distance to absolute spherical coordinates and return the
  ! resulting absolute spherical coordinates.
  !  This is basically an inverse Haversine formula.
  !  Angle:
  !    North   0
  !    East   90 (with longitude increasing towards East)
  !    South 180
  !    West  270
  !---------------------------------------------------------------------
  real(kind=8), intent(in)  ::  lon1  ! [rad] Longitude of input coordinates
  real(kind=8), intent(in)  ::  lat1  ! [rad] Latitude of input coordinates
  real(kind=8), intent(in)  ::  off   ! [rad] Offset/distance to be added
  real(kind=8), intent(in)  ::  angl  ! [rad] Angle of offset
  real(kind=8), intent(out) ::  lon2  ! [rad] Longitude of output coordinates
  real(kind=8), intent(out) ::  lat2  ! [rad] Latitude of output coordinates
  ! Local
  real(kind=8) :: slat1,clat1,coff,soff,slat2
  !
  slat1 = sin(lat1)
  clat1 = cos(lat1)
  soff = sin(off)
  coff = cos(off)
  !
  slat2 = slat1*coff + clat1*soff*cos(angl)
  lat2 = asin(slat2)
  !
  lon2 = lon1 + atan2( sin(angl)*soff*clat1 , coff-slat1*slat2 )
  !
end subroutine abs_add_distance
