fortplot_polar_rendering_helpers.f90 Source File


Source Code

module fortplot_polar_rendering_helpers
    !! Polar rendering helper procedures
    !!
    !! Extracted from fortplot_figure_rendering_pipeline to reduce module size
    !! Single Responsibility: Polar axes and plot rendering helpers

    use, intrinsic :: iso_fortran_env, only: wp => real64
    use fortplot_context, only: plot_context
    use fortplot_figure_initialization, only: figure_state_t
    use fortplot_plot_data, only: plot_data_t
    use fortplot_polar_rendering, only: render_polar_data, render_polar_boundary, &
                                        render_polar_radial_gridlines, &
                                        render_polar_angular_gridlines, &
                                        render_polar_angular_ticks
    implicit none

    private
    public :: render_polar_axes, render_polar_plot_internal

contains

    subroutine render_polar_axes(backend, x_min, x_max, y_min, y_max, state)
        !! Render polar axes: circular boundary, radial spokes, angular circles, tick labels
        class(plot_context), intent(inout) :: backend
        real(wp), intent(in) :: x_min, x_max, y_min, y_max
        type(figure_state_t), intent(in) :: state

        real(wp) :: center_x, center_y, radius
        real(wp) :: theta_offset
        logical :: clockwise
        integer :: n_spokes, n_circles

        if (.not. state%polar_projection) return

        center_x = (x_min + x_max)*0.5_wp
        center_y = (y_min + y_max)*0.5_wp
        radius = min(x_max - x_min, y_max - y_min)*0.45_wp

        theta_offset = state%polar_theta_offset
        clockwise = state%polar_theta_direction_cw
        n_spokes = state%polar_theta_gridlines
        n_circles = state%polar_r_gridlines

        ! Render concentric circles (angular gridlines)
        call render_polar_angular_gridlines(backend, center_x, center_y, radius, &
                                            n_circles)

        ! Render radial spokes
        call render_polar_radial_gridlines(backend, center_x, center_y, radius, &
                                           n_spokes, theta_offset, clockwise)

        ! Render circular boundary
        call render_polar_boundary(backend, center_x, center_y, radius)

        ! Render angular tick labels
        call render_polar_angular_ticks(backend, center_x, center_y, radius, &
                                        n_spokes, theta_offset, clockwise)
    end subroutine render_polar_axes

    subroutine render_polar_plot_internal(backend, plot, x_min, x_max, y_min, y_max, &
                                          state)
        !! Render polar plot data within the coordinate system
        !! The plot stores pre-converted Cartesian coordinates in x/y arrays
        !! but we use polar_theta/polar_r for proper polar rendering
        class(plot_context), intent(inout) :: backend
        type(plot_data_t), intent(in) :: plot
        real(wp), intent(in) :: x_min, x_max, y_min, y_max
        type(figure_state_t), intent(in), optional :: state

        real(wp) :: center_x, center_y, radius, r_scale
        real(wp) :: theta_offset
        logical :: clockwise
        integer :: n

        ! Compute center and radius in data coordinates
        center_x = (x_min + x_max)*0.5_wp
        center_y = (y_min + y_max)*0.5_wp
        radius = min(x_max - x_min, y_max - y_min)*0.45_wp

        ! Get polar configuration from state
        theta_offset = 0.0_wp  ! 0 deg at east (matplotlib)
        clockwise = .false.
        if (present(state)) then
            theta_offset = state%polar_theta_offset
            clockwise = state%polar_theta_direction_cw
        end if

        ! Compute r_scale based on polar data range
        r_scale = 1.0_wp
        if (allocated(plot%polar_r)) then
            if (size(plot%polar_r) > 0) then
                r_scale = radius/maxval(abs(plot%polar_r))
            end if
        end if

        ! Render polar data if available
        if (allocated(plot%polar_theta) .and. allocated(plot%polar_r)) then
            n = min(size(plot%polar_theta), size(plot%polar_r))
            if (n > 0) then
                call render_polar_data(backend, plot%polar_theta, plot%polar_r, n, &
                                       center_x, center_y, r_scale, &
                                       theta_offset, clockwise, plot%color)
            end if
        end if
    end subroutine render_polar_plot_internal

end module fortplot_polar_rendering_helpers