% File: hawkdraw-plots.code.tex
% Copyright 2026 Jasper Habicht (mail(at)jasperhabicht.de).
%
% This work may be distributed and/or modified under the
% conditions of the LaTeX Project Public License version 1.3c,
% available at http://www.latex-project.org/lppl/.
%
% This file is part of the `hawkdraw' package (The Work in LPPL)
% and all files in that bundle must be distributed together.
%
% This work has the LPPL maintenance status `maintained'.
%
% BOF

% v0.1.0 2026-06-03

\msg_new:nnn { hawkdraw } { plot-unknown } {
    Plot ~ function ~ `#1` ~ unknown.
}

\scan_new:N \s__hawkdraw_plot_mark

\seq_new:N \g__hawkdraw_path_plot_points_seq
\tl_new:N \l_hawkdraw_path_plot_tl

\keys_define:nn { hawkdraw / path / plot } {
    function                .tl_set:N         = \l_hawkdraw_path_plot_tl ,
    function                .initial:n        = { debug } ,
}

% ===

\cs_new_protected:cpn { __hawkdraw_path_process_p_ l :w } plot #1#2 \s__hawkdraw_stop {
    \__hawkdraw_cs_if_exist_use_secure:nnTF {#1} {
        __hawkdraw_path_process_plot_ \tl_head:n {#1} :w
    } {
        #1#2 \s__hawkdraw_stop
    } {
        \__hawkdraw_path_plot:nn { } {#1}
        \tl_trim_spaces_apply:nN {#2} \__hawkdraw_path_process_continue:n
    }
}

\cs_new_protected:cpn { __hawkdraw_path_process_plot_ [ :w } [ #1 ] #2#3 \s__hawkdraw_stop {
    \__hawkdraw_path_plot:nn {#1} {#2}
    \tl_trim_spaces_apply:nN {#3} \__hawkdraw_path_process_continue:n
}

\cs_new_protected:Npn \__hawkdraw_path_plot:nn #1#2 {
    \str_set:Nn \l__hawkdraw_path_type_tl { plot }
    \fp_set_eq:NN \l__hawkdraw_point_o_fp \g_hawkdraw_path_last_point_fp
    \keys_set:nn { hawkdraw / path / plot } {#1}
    \seq_gclear:N \g__hawkdraw_path_plot_points_seq
    \seq_gput_right:Ne \g__hawkdraw_path_plot_points_seq {
        \fp_to_decimal:N \l__hawkdraw_point_o_fp
    }
    \tl_trim_spaces_apply:nN {#2} \__hawkdraw_path_process_plot:n
    \cs_if_exist_use:cF { __hawkdraw_plot_ \l_hawkdraw_path_plot_tl : } {
        \msg_error:nnV { hawkdraw } { plot-unknown } \l_hawkdraw_path_plot_tl
    }
}

\cs_new_protected:Npn \__hawkdraw_path_process_plot:n #1 {
    \__hawkdraw_cs_if_exist_use_secure:nnT {#1} {
        __hawkdraw_path_process_plot_i_ \tl_head:n {#1} :w
    } {
        #1 \s__hawkdraw_stop
    }
}

\cs_new_protected:cpn { __hawkdraw_path_process_plot_i_ ( :w } ( #1 ) #2 \s__hawkdraw_stop {
    \hawkdraw_point_parse_set:Nn \l__hawkdraw_point_a_fp {#1}
    \seq_gput_right:Ne \g__hawkdraw_path_plot_points_seq {
        \fp_to_decimal:N \l__hawkdraw_point_a_fp
    }
    \fp_gset_eq:NN \g_hawkdraw_path_last_point_fp \l__hawkdraw_point_a_fp
    \tl_trim_spaces_apply:nN {#2} \__hawkdraw_path_process_plot:n
}

\cs_new_protected:cpn { __hawkdraw_path_process_plot_i_ m :w } map #1 [ #2 ] #3#4 \s__hawkdraw_stop {
    \hawkdraw_map:nn {#2} {
        \tl_trim_spaces_apply:nN {#3} \__hawkdraw_path_process_plot:n
    }
    \tl_trim_spaces_apply:nN {#4} \__hawkdraw_path_process_plot:n
}

% ===

\prop_new:N \l__hawkdraw_plot_keys_prop
\seq_new:N \l__hawkdraw_plot_key_value_seq

\cs_new:Npn \__hawkdraw_plot_keys_process:nnn #1#2#3 {
    #2                      .fp_set:c         = { l_hawkdraw_plot_ #1 _ #2 _fp } ,
    #2                      .initial:n        = {#3} ,
}

\cs_new_protected:Npn \hawkdraw_plot_create:nn #1#2#3 {
    \prop_clear:N \l__hawkdraw_plot_keys_prop
    \seq_clear:N \l__hawkdraw_plot_key_value_seq
    \clist_map_inline:nn {#2} {
        \seq_set_split:Nnn \l__hawkdraw_plot_key_value_seq { = } {##1}
        \prop_put:Nee \l__hawkdraw_plot_keys_prop
            { \seq_item:Nn \l__hawkdraw_plot_key_value_seq { 1 } }
            { \seq_item:Nn \l__hawkdraw_plot_key_value_seq { 2 } }
        \tl_if_exist:cF { l_hawkdraw_plot_ #1 _ ##1 _fp } {
            \tl_new:c { l_hawkdraw_plot_ #1 _ ##1 _fp }
        }
    }
    \exp_args:Nne
    \keys_define:nn { hawkdraw / path / plot / #1 } {
        \prop_map_tokens:Nn \l__hawkdraw_plot_keys_prop {
            \__hawkdraw_plot_keys_process:nnn {#1}
        }
    }
    \cs_new_protected:cpn { __hawkdraw_plot_ #1 : } {
        \seq_if_empty:NF \g__hawkdraw_path_plot_points_seq {
            #3
        }
    }
}

% ===

\hawkdraw_plot_create:nn { debug } { } {
    \tl_analysis_log:N \g__hawkdraw_path_plot_points_seq
}

\hawkdraw_plot_create:nn { sharp } { } {
    \int_compare:nNnT { \seq_count:N \g__hawkdraw_path_plot_points_seq } > { 0 } {
        \draw_path_moveto:n { \seq_item:Nn \g__hawkdraw_path_plot_points_seq { 1 } }
        \int_compare:nNnT { \seq_count:N \g__hawkdraw_path_plot_points_seq } > { 1 } {
            \int_step_inline:nnn { 2 } { \seq_count:N \g__hawkdraw_path_plot_points_seq } {
                \draw_path_lineto:n { \seq_item:Nn \g__hawkdraw_path_plot_points_seq {##1} }
            }
        }
    }
}

\hawkdraw_plot_create:nn { smooth } {
    % can be set via plot/smooth/tension
    tension = 0.15
} {
    \int_compare:nNnT { \seq_count:N \g__hawkdraw_path_plot_points_seq } > { 0 } {
        \draw_path_moveto:n { \seq_item:Nn \g__hawkdraw_path_plot_points_seq { 1 } }
        \int_compare:nNnT { \seq_count:N \g__hawkdraw_path_plot_points_seq } > { 1 } {
            \int_compare:nNnTF { \seq_count:N \g__hawkdraw_path_plot_points_seq } < { 3 } {
                \draw_path_lineto:n { \seq_item:Nn \g__hawkdraw_path_plot_points_seq { 2 } }
            } {
                % more than 2 points: calculate slope between P0 and P2 and use it to calculate control points
                % first segment
                \draw_path_curveto:nn {
                    \seq_item:Nn \g__hawkdraw_path_plot_points_seq { 2 } -
                    (
                        \seq_item:Nn \g__hawkdraw_path_plot_points_seq { 3 } -
                        \seq_item:Nn \g__hawkdraw_path_plot_points_seq { 1 }
                    ) * \l_hawkdraw_plot_smooth_tension_fp
                } {
                    \seq_item:Nn \g__hawkdraw_path_plot_points_seq { 2 }
                }
                \int_step_inline:nnn { 3 } { \seq_count:N \g__hawkdraw_path_plot_points_seq - 1 } {
                    \draw_path_curveto:nnn {
                        \seq_item:Nn \g__hawkdraw_path_plot_points_seq { ##1 - 1 } +
                        (
                            \seq_item:Nn \g__hawkdraw_path_plot_points_seq {##1} -
                            \seq_item:Nn \g__hawkdraw_path_plot_points_seq { ##1 - 2 }
                        ) * \l_hawkdraw_plot_smooth_tension_fp
                    } {
                        \seq_item:Nn \g__hawkdraw_path_plot_points_seq {##1} -
                        (
                            \seq_item:Nn \g__hawkdraw_path_plot_points_seq { ##1 + 1 } -
                            \seq_item:Nn \g__hawkdraw_path_plot_points_seq { ##1 - 1 }
                        ) * \l_hawkdraw_plot_smooth_tension_fp
                    } {
                        \seq_item:Nn \g__hawkdraw_path_plot_points_seq {##1}
                    }
                }
                % last segment
                \draw_path_curveto:nn {
                    \seq_item:Nn \g__hawkdraw_path_plot_points_seq { -2 } +
                    (
                        \seq_item:Nn \g__hawkdraw_path_plot_points_seq { -1 } -
                        \seq_item:Nn \g__hawkdraw_path_plot_points_seq { -3 }
                    ) * \l_hawkdraw_plot_smooth_tension_fp
                } {
                    \seq_item:Nn \g__hawkdraw_path_plot_points_seq { -1 }
                }
            }
        }
    }
}

% EOF