!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
module cubefield_incline_tool
  use cubetools_parameters
  !
  public :: incline_tool_t
  private
  !
  type incline_tool_t
     real(kind=coor_k) :: angle
     real(kind=coor_k) :: cosa
     real(kind=coor_k) :: sina
   contains
     procedure, public  :: init     => cubefield_incline_tool_initrot
     procedure, public  :: sou2sky  => cubefield_incline_tool_sou2sky
     procedure, public  :: sky2sou  => cubefield_incline_tool_sky2sou
     procedure, private :: rotate   => cubefield_incline_tool_rotate
     procedure, private :: unrotate => cubefield_incline_tool_unrotate
  end type incline_tool_t
  !
contains
  !
  subroutine cubefield_incline_tool_sou2sky(incline,xsou,ysou,zsou,xsky,ysky,zsky)
    !----------------------------------------------------------------------
    ! Projection onto plane of sky:
    !
    !                   zsou                  ysky   zsky
    !                   |                        |    /
    !                   |                        |  /
    ! From     xsou ____|       to      xsky ____|/
    !                  /                        
    !                /                         /
    !            ysou                   Observer         
    !
    ! The observer direction is in the (ysou,zsou) plane and the (ysky,zsky)
    ! plane and the x axis is common in both referentials. So a rotation around
    ! the x-axis will do the job.
    !----------------------------------------------------------------------
    class(incline_tool_t), intent(in)  :: incline
    real(kind=coor_k),     intent(in)  :: xsou
    real(kind=coor_k),     intent(in)  :: ysou
    real(kind=coor_k),     intent(in)  :: zsou
    real(kind=coor_k),     intent(out) :: xsky
    real(kind=coor_k),     intent(out) :: ysky
    real(kind=coor_k),     intent(out) :: zsky
    !
    xsky = xsou
    call incline%rotate(ysou,zsou,ysky,zsky)
  end subroutine cubefield_incline_tool_sou2sky
  !
  subroutine cubefield_incline_tool_sky2sou(incline,xsky,ysky,zsky,xsou,ysou,zsou)
    !----------------------------------------------------------------------
    ! Projection onto plane of sky:
    !
    !                ysky   zsky                     zsou
    !                   |    /                       |   
    !                   |  /                         |   
    ! From     xsky ____|/          to      xsou ____|   
    !                  /                            /    
    !                /                            /      
    !          Observer                       ysou        
    !
    ! The observer direction is in the (ysou,zsou) plane and the (ysky,zsky)
    ! plane and the x axis is common in both referentials. So a rotation around
    ! the x-axis will do the job.
    !----------------------------------------------------------------------
    class(incline_tool_t), intent(in)  :: incline
    real(kind=coor_k),     intent(in)  :: xsky
    real(kind=coor_k),     intent(in)  :: ysky
    real(kind=coor_k),     intent(in)  :: zsky
    real(kind=coor_k),     intent(out) :: xsou
    real(kind=coor_k),     intent(out) :: ysou
    real(kind=coor_k),     intent(out) :: zsou
    !
    xsou = xsky
    call incline%unrotate(ysky,zsky,ysou,zsou)
  end subroutine cubefield_incline_tool_sky2sou
  !
  subroutine cubefield_incline_tool_initrot(rot2d,inclination)
    !----------------------------------------------------------------------
    ! Definition of the cosinus and sinus for a rotation around the x-axis
    ! by a given incline angle:
    !
    !        (zsou = sou axis)   (ysky = plane of sky)
    !                        \    |                    
    !                          \  |                   
    !                   zsky ____\|    ----> Observer          
    !                 
    ! incline is defined as the angle between ysky and zsou.
    ! incline is positive from ysky to zsou.
    !----------------------------------------------------------------------
    class(incline_tool_t), intent(inout) :: rot2d
    real(kind=coor_k),     intent(in)    :: inclination
    !
    rot2d%angle = inclination
    rot2d%cosa = cos(rot2d%angle)
    rot2d%sina = sin(rot2d%angle)
  end subroutine cubefield_incline_tool_initrot
  !
  subroutine cubefield_incline_tool_rotate(rot2d,x,y,xrot,yrot)
    !----------------------------------------------------------------------
    ! 2D rotation from (x,y) to (xrot,yrot) by an angle = angle from x to
    ! xrot or from y to yrot.
    !----------------------------------------------------------------------
    class(incline_tool_t), intent(in)  :: rot2d
    real(kind=coor_k),     intent(in)  :: x
    real(kind=coor_k),     intent(in)  :: y
    real(kind=coor_k),     intent(out) :: xrot
    real(kind=coor_k),     intent(out) :: yrot
    !
    xrot = x*rot2d%cosa-y*rot2d%sina
    yrot = x*rot2d%sina+y*rot2d%cosa
  end subroutine cubefield_incline_tool_rotate
  !
  subroutine cubefield_incline_tool_unrotate(rot2d,xrot,yrot,x,y)
    !----------------------------------------------------------------------
    ! 2D unrotation from (xrot,yrot) to (x,y) by an angle = angle from x to
    ! xrot or from y to yrot.
    !----------------------------------------------------------------------
    class(incline_tool_t), intent(in)  :: rot2d
    real(kind=coor_k),     intent(in)  :: xrot
    real(kind=coor_k),     intent(in)  :: yrot
    real(kind=coor_k),     intent(out) :: x
    real(kind=coor_k),     intent(out) :: y
    !
    x =  xrot*rot2d%cosa+yrot*rot2d%sina
    y = -xrot*rot2d%sina+yrot*rot2d%cosa
  end subroutine cubefield_incline_tool_unrotate
end module cubefield_incline_tool
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
