fplot_arrow.f90 Source File


Contents

Source Code


Source Code

module fplot_arrow
    use iso_fortran_env
    use fplot_plot_object
    use fplot_colors
    use fplot_constants
    use strings
    implicit none
    private
    public :: plot_arrow

    type, extends(plot_object) :: plot_arrow
        !! Defines an arrow that can be drawn on a plot.
        logical, private :: m_visible = .true.
            !! Visible?
        real(real32), private, dimension(3) :: m_tail = [0.0, 0.0, 0.0]
            !! The x, y, z coordinates of the tail.
        real(real32), private, dimension(3) :: m_head = [0.0, 0.0, 0.0]
            !! The x, y, z coordinates of the head.
        type(color), private :: m_color = CLR_BLACK
            !! The arrow color.
        integer(int32), private :: m_linestyle = LINE_SOLID
            !! The line style.
        real(real32), private :: m_linewidth = 1.0
            !! The line width.
        integer(int32), private :: m_head_type = ARROW_HEAD
            !! The head configuration.
        integer(int32), private :: m_filling = ARROW_FILLED
            !! Arrow filling.
        logical, private :: m_front = .true.
            !! Move to front?
        real(real32), private :: m_size = 0.375
            !! Arrow head size.
        real(real32), private :: m_angle = 10.0
            !! Arrow head angle.
        real(real32), private :: m_backangle = 90.0
            !! Arrow head back angle.
        logical, private :: m_use_default_size = .true.
            !! Use default head size.
    contains
        procedure, public :: get_is_visible => par_get_is_visible
        procedure, public :: set_is_visible => par_set_is_visible
        procedure, public :: get_tail_location => par_get_tail
        generic, public :: set_tail_location => par_set_tail_1, &
            par_set_tail_2, par_set_tail_3
        procedure, private :: par_set_tail_1
        procedure, private :: par_set_tail_2
        procedure, private :: par_set_tail_3
        procedure, public :: get_head_location => par_get_head
        generic, public :: set_head_location => par_set_head_1, &
            par_set_head_2, par_set_head_3
        procedure, private :: par_set_head_1
        procedure, private :: par_set_head_2
        procedure, private :: par_set_head_3
        procedure, public :: get_color => par_get_color
        procedure, public :: set_color => par_set_color
        procedure, public :: get_line_style => par_get_line_style
        procedure, public :: set_line_style => par_set_line_style
        procedure, public :: get_line_width => par_get_line_width
        procedure, public :: set_line_width => par_set_line_width
        procedure, public :: get_head_type => par_get_head_type
        procedure, public :: set_head_type => par_set_head_type
        procedure, public :: get_head_fill => par_get_fill
        procedure, public :: set_head_fill => par_set_fill
        procedure, public :: get_move_to_front => par_get_move_to_front
        procedure, public :: set_move_to_front => par_set_move_to_front
        procedure, public :: get_head_size => par_get_head_size
        procedure, public :: set_head_size => par_set_head_size
        procedure, public :: get_head_angle => par_get_head_angle
        procedure, public :: set_head_angle => par_set_head_angle
        procedure, public :: get_head_back_angle => par_get_head_back_angle
        procedure, public :: set_head_back_angle => par_set_head_back_angle
        procedure, public :: get_use_default_size => par_get_use_default_size
        procedure, public :: set_use_default_size => par_set_use_default_size
        procedure, public :: get_command_string => par_get_cmd
    end type

contains
! ------------------------------------------------------------------------------
pure function par_get_is_visible(this) result(rst)
    !! Gets a value determining if the arrow is visible.
    class(plot_arrow), intent(in) :: this
        !! The plot_arrow object.
    logical :: rst
        !! True if the arrow is visible; else, false.
    rst = this%m_visible
end function

! --------------------
subroutine par_set_is_visible(this, x)
    !! Sets a value determining if the arrow is visible.
    class(plot_arrow), intent(inout) :: this
        !! The plot_arrow object.
    logical, intent(in) :: x
        !! True if the arrow is visible; else, false.
    this%m_visible = x
end subroutine

! ------------------------------------------------------------------------------
pure function par_get_tail(this) result(rst)
    !! Gets the coordinates of the arrow's tail.
    class(plot_arrow), intent(in) :: this
        !! The plot_arrow object.
    real(real32), dimension(3) :: rst
        !! A 3-element array containing the x, y, and z coordinates of the 
        !! arrow's tail.
    rst = this%m_tail
end function

! --------------------
subroutine par_set_tail_1(this, x)
    !! Sets the coordinates of the arrow's tail.
    class(plot_arrow), intent(inout) :: this
        !! The plot_arrow object.
    real(real32), intent(in) :: x(3)
        !! A 3-element array containing the x, y, and z coordinates of the 
        !! arrow's tail.
    this%m_tail = x
end subroutine

! --------------------
subroutine par_set_tail_2(this, x, y)
    !! Sets the coordinates of the arrow's tail.
    class(plot_arrow), intent(inout) :: this
        !! The plot_arrow object.
    real(real32), intent(in) :: x
        !! The x-coordinate of the arrow's tail.
    real(real32), intent(in) :: y
        !! !! The y-coordinate of the arrow's tail.
    this%m_tail = [x, y, 0.0]
end subroutine

! --------------------
subroutine par_set_tail_3(this, x, y, z)
    !! Sets the coordinates of the arrow's tail.
    class(plot_arrow), intent(inout) :: this
        !! The plot_arrow object.
    real(real32), intent(in) :: x
        !! The x-coordinate of the arrow's tail.
    real(real32), intent(in) :: y
        !! The y-coordinate of the arrow's tail.
    real(real32), intent(in) :: z
        !! The z-coordinate of the arrow's tail.
    this%m_tail = [x, y, z]
end subroutine

! ------------------------------------------------------------------------------
pure function par_get_head(this) result(rst)
    !! Gets the coordinates of the arrow's head.
    class(plot_arrow), intent(in) :: this
        !! The plot_arrow object.
    real(real32), dimension(3) :: rst
        !! A 3-element array containing the x, y, and z coordinates of the
        !! arrow's head.
    rst = this%m_head
end function

! --------------------
subroutine par_set_head_1(this, x)
    !! Sets the location of the arrow's head.
    class(plot_arrow), intent(inout) :: this
        !! The plot_arrow object.
    real(real32), intent(in) :: x(3)
        !! A 3-element array containing the x, y, and z coordinates of the
        !! arrow's head.
    this%m_head = x
end subroutine

! --------------------
subroutine par_set_head_2(this, x, y)
    !! Sets the location of the arrow's head.
    class(plot_arrow), intent(inout) :: this
        !! The plot_arrow object.
    real(real32), intent(in) :: x
        !! The x-coordinate of the arrow's head.
    real(real32), intent(in) :: y
        !! The y-coordinate of the arrow's head.
    this%m_head = [x, y, 0.0]
end subroutine

! --------------------
subroutine par_set_head_3(this, x, y, z)
    !! Sets the location of the arrow's head.
    class(plot_arrow), intent(inout) :: this
        !! The plot_arrow object.
    real(real32), intent(in) :: x
        !! The x-coordinate of the arrow's head.
    real(real32), intent(in) :: y
        !! The y-coordinate of the arrow's head.
    real(real32), intent(in) :: z
        !! The z-coordinate of the arrow's head.
    this%m_head = [x, y, z]
end subroutine

! ------------------------------------------------------------------------------
pure function par_get_color(this) result(rst)
    !! Gets the color of the arrow.
    class(plot_arrow), intent(in) :: this
        !! The plot_arrow object.
    type(color) :: rst
        !! The color.
    rst = this%m_color
end function

! --------------------
subroutine par_set_color(this, x)
    !! Sets the color of the arrow.
    class(plot_arrow), intent(inout) :: this
        !! The plot_arrow object.
    type(color), intent(in) :: x
        !! The color.
    this%m_color = x
end subroutine

! ------------------------------------------------------------------------------
pure function par_get_line_style(this) result(rst)
    !! Gets the line style used to draw the arrow.
    class(plot_arrow), intent(in) :: this
        !! The plot_arrow object.
    integer(int32) :: rst
        !! The line style.
    rst = this%m_linestyle
end function

! --------------------
subroutine par_set_line_style(this, x)
    !! Sets the line style used to draw the arrow.
    class(plot_arrow), intent(inout) :: this
        !! The plot_arrow object.
    integer(int32), intent(in) :: x
        !! The line style.  The value must be one of the following.
        !!
        !!  - LINE_SOLID
        !!
        !!  - LINE_DASHED
        !!
        !!  - LINE_DASH_DOTTED
        !!
        !!  - LINE_DASH_DOT_DOT
        !!
        !!  - LINE_DOTTED
        !!
        !! If the value is not one of the above, the command is ignored.
    if (x == LINE_DASHED .or. &
        x == LINE_DASH_DOTTED .or. &
        x == LINE_DASH_DOT_DOT .or. &
        x == LINE_DOTTED .or. &
        x == LINE_SOLID) then
        ! Only reset the line style if it is a valid type.
        this%m_linestyle = x
    end if
end subroutine

! ------------------------------------------------------------------------------
pure function par_get_line_width(this) result(rst)
    !! Gets the width of the lines used to draw the arrow.
    class(plot_arrow), intent(in) :: this
        !! The plot_arrow object.
    real(real32) :: rst
        !! The width of the line.
    rst = this%m_linewidth
end function

! --------------------
subroutine par_set_line_width(this, x)
    !! Sets the width of the lines used to draw the arrow.
    class(plot_arrow), intent(inout) :: this
        !! The plot_arrow object.
    real(real32), intent(in) :: x
        !! The width of the line.
    this%m_linewidth = x
end subroutine

! ------------------------------------------------------------------------------
pure function par_get_head_type(this) result(rst)
    !! Gets the type of arrow head.
    class(plot_arrow), intent(in) :: this
        !! The plot_arrow object.
    integer(int32) :: rst
        !! The arrow head type.
    rst = this%m_head_type
end function

! --------------------
subroutine par_set_head_type(this, x)
    !! Sets the type of arrow head.
    class(plot_arrow), intent(inout) :: this
        !! The plot_arrow object.
    integer(int32), intent(in) :: x
        !! The arrow head type.  It must be one of the following constants.
        !!
        !! - ARROW_HEAD
        !!
        !! - ARROW_BACKHEAD
        !!
        !! - ARROW_HEADS
        !!
        !! - ARROW_NO_HEAD
        !!
        !! If the value is not one of the above, the command is ignored.
    if (x == ARROW_BACKHEAD .or. &
        x == ARROW_HEAD .or. &
        x == ARROW_HEADS .or. &
        x == ARROW_NO_HEAD &
    ) then
        this%m_head_type = x
    end if
end subroutine

! ------------------------------------------------------------------------------
pure function par_get_fill(this) result(rst)
    !! Gets a flag denoting the head fill type.
    class(plot_arrow), intent(in) :: this
        !! The plot_arrow object.
    integer(int32) :: rst
        !! The flag denoting head fill.
    rst = this%m_filling
end function

! --------------------
subroutine par_set_fill(this, x)
    !! Sets a flag denoting the head fill type.
    class(plot_arrow), intent(inout) :: this
        !! The plot_arrow object.
    integer(int32), intent(in) :: x
        !! The flag denoting head fill.  It must be one of the following 
        !! constants.
        !!
        !! - ARROW_FILLED
        !!
        !! - ARROW_EMPTY
        !!
        !! - ARROW_NO_BORDER
        !!
        !! - ARROW_NO_FILL
        !!
        !! If the value is not one of the above, the command is ignored.
    if (x == ARROW_FILLED .or. &
        x == ARROW_EMPTY .or. &
        x == ARROW_NO_BORDER .or. &
        x == ARROW_NO_FILL &
    ) then
        this%m_filling = x
    end if
end subroutine

! ------------------------------------------------------------------------------
pure function par_get_move_to_front(this) result(rst)
    !! Gets a value determining if the arrow should be moved to the front.
    class(plot_arrow), intent(in) :: this
        !! The plot_arrow object.
    logical :: rst
        !! True if the arrow should be moved to the front; else, false.
    rst = this%m_front
end function

! --------------------
subroutine par_set_move_to_front(this, x)
    !! Sets a value determining if the arrow should be moved to the front.
    class(plot_arrow), intent(inout) :: this
        !! The plot_arrow object.
    logical, intent(in) :: x
        !! True if the arrow should be moved to the front; else, false.
    this%m_front = x
end subroutine

! ------------------------------------------------------------------------------
pure function par_get_head_size(this) result(rst)
    !! Gets the size of the arrow head.
    class(plot_arrow), intent(in) :: this
        !! The plot_arrow object.
    real(real32) :: rst
        !! The head size.
    rst = this%m_size
end function

! --------------------
subroutine par_set_head_size(this, x)
    !! Sets the size of the arrow head.
    class(plot_arrow), intent(inout) :: this
        !! The plot_arrow object.
    real(real32), intent(in) :: x
        !! The head size.
    this%m_size = x
end subroutine

! ------------------------------------------------------------------------------
pure function par_get_head_angle(this) result(rst)
    !! Gets the angle of the arrow head.
    class(plot_arrow), intent(in) :: this
        !! The plot_arrow object.
    real(real32) :: rst
        !! The angle, in degrees.
    rst = this%m_angle
end function

! --------------------
subroutine par_set_head_angle(this, x)
    !! Sets the angle of the arrow head.
    class(plot_arrow), intent(inout) :: this
        !! The plot_arrow object.
    real(real32), intent(in) :: x
        !! The angle, in degrees.
    this%m_angle = x
end subroutine

! ------------------------------------------------------------------------------
pure function par_get_head_back_angle(this) result(rst)
    !! Gets the angle of the back of the arrow head.
    class(plot_arrow), intent(in) :: this
        !! The plot_arrow object.
    real(real32) :: rst
        !! The angle, in degrees.
    rst = this%m_backangle
end function

! --------------------
subroutine par_set_head_back_angle(this, x)
    !! Sets the angle of the back of the arrow head.
    class(plot_arrow), intent(inout) :: this
        !! The plot_arrow object.
    real(real32), intent(in) :: x
        !! The angle, in degrees.
    this%m_backangle = x
end subroutine

! ------------------------------------------------------------------------------
pure function par_get_use_default_size(this) result(rst)
    !! Gets a value determining if arrow head sizing defaults should be used.
    class(plot_arrow), intent(in) :: this
        !! The plot_arrow object.
    logical :: rst
        !! True if the defaults should be used; else, false.
    rst = this%m_use_default_size
end function

! --------------------
subroutine par_set_use_default_size(this, x)
    !! Sets a value determining if arrow head sizing defaults should be used.
    class(plot_arrow), intent(inout) :: this
        !! The plot_arrow object.
    logical, intent(in) :: x
        !! True if the defaults should be used; else, false.
    this%m_use_default_size = x
end subroutine

! ------------------------------------------------------------------------------
function par_get_cmd(this) result(rst)
    !! Returns the appropriate GNUPLOT command string to establish appropriate 
    !! parameters.
    class(plot_arrow), intent(in) :: this
        !! The plot_arrow object.
    character(len = :), allocatable :: rst
        !! The GNUPLOT command string.

    ! Local Variables
    type(string_builder) :: str
    type(color) :: clr
    real(real32) :: tail(3), head(3)

    ! Quick Return
    if (.not.this%get_is_visible()) then
        rst = ""
        return
    end if

    ! Command
    call str%append("set arrow")

    ! Position Info
    tail = this%get_tail_location()
    head = this%get_head_location()
    call str%append(" from ")
    call str%append(to_string(tail(1)))
    call str%append(",")
    call str%append(to_string(tail(2)))
    call str%append(",")
    call str%append(to_string(tail(3)))

    call str%append(" to ")
    call str%append(to_string(head(1)))
    call str%append(",")
    call str%append(to_string(head(2)))
    call str%append(",")
    call str%append(to_string(head(3)))

    ! Head Type
    select case (this%get_head_type())
    case (ARROW_BACKHEAD)
        call str%append(" backhead")
    case (ARROW_HEAD)
        call str%append(" head")
    case (ARROW_HEADS)
        call str%append(" heads")
    case (ARROW_NO_HEAD)
        call str%append(" nohead")
    end select

    if (this%get_head_type() /= ARROW_NO_HEAD) then
        ! Fill Info
        select case (this%get_head_fill())
        case (ARROW_FILLED)
            call str%append(" filled")
        case (ARROW_EMPTY)
            call str%append(" empty")
        case (ARROW_NO_BORDER)
            call str%append(" noborder")
        case (ARROW_NO_FILL)
            call str%append(" nofilled")
        end select

        ! Size
        if (.not.this%get_use_default_size()) then
            call str%append(" size ")
            call str%append(to_string(this%get_head_size()))
            call str%append(",")
            call str%append(to_string(this%get_head_angle()))
            call str%append(",")
            call str%append(to_string(this%get_head_back_angle()))
        end if
    end if

    ! Front/Back
    if (this%get_move_to_front()) then
        call str%append(" front")
    else
        call str%append(" back")
    end if

    ! Line Color
    clr = this%get_color()
    call str%append(' lc rgb "#')
    call str%append(clr%to_hex_string())
    call str%append('"')

    ! Line Width
    call str%append(" lw ")
    call str%append(to_string(this%get_line_width()))

    ! Line Style
    call str%append(" lt ")
    call str%append(to_string(this%get_line_style()))
    if (this%get_line_style() /= LINE_SOLID) then
        call str%append(" dashtype ")
        call str%append(to_string(this%get_line_style()))
    end if

    ! End
    rst = char(str%to_string())
end function

! ------------------------------------------------------------------------------
! pure subroutine par_assign(x, y)
!     type(plot_arrow), intent(out) :: x
!     class(plot_arrow), intent(in) :: y
!     x%m_visible = y%m_visible
!     x%m_tail = y%m_tail
!     x%m_head = y%m_head
!     x%m_color = y%m_color
!     x%m_linestyle = y%m_linestyle
!     x%m_linewidth = y%m_linewidth
!     x%m_head_type = y%m_head_type
!     x%m_filling = y%m_filling
!     x%m_front = y%m_front
!     x%m_size = y%m_size
!     x%m_angle = y%m_angle
!     x%m_backangle = y%m_backangle
!     x%m_use_default_size = y%m_use_default_size
! end subroutine

! ------------------------------------------------------------------------------
end module