% File: hawkdraw-softpath.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.3.0 2026-06-17

\tl_new:N \g_hawkdraw_softpath_original_tl

% #1 , #2: x and y coordinate of first point of path
\cs_new_protected:Npn \hawkdraw_softpath_close_op:nn #1#2 {
    \draw_path_close:
}

% #1 , #2: x and y coordinate of point
\cs_new_protected:Npn \hawkdraw_softpath_moveto_op:nn #1#2 {
    \draw_path_moveto:n { #1 , #2 }
}

% #1 , #2: x and y coordinate of end point
\cs_new_protected:Npn \hawkdraw_softpath_lineto_op:nn #1#2 {
    \draw_path_lineto:n { #1 , #2 }
}

% #1 , #2: x and y coordinate of control point
% #3     : \hawkdraw_softpath_curveto_opii:nn
% #4 , #5: x and y coordinate of end point (quadratic) or second control point (cubic)
% #6     : \hawkdraw_softpath_curveto_opiii:nn
% #7 , #8: empty (quadratic) or x and y coordinate of end point (cubic)
\cs_new_protected:Npn \hawkdraw_softpath_curveto_op:nnNnnNnn #1#2#3#4#5#6#7#8 {
    \tl_if_empty:nTF {#7} {
        \draw_path_curveto:nn { #1 , #2 } { #4 , #5 }
    } {
        \draw_path_curveto:nnn { #1 , #2 } { #4 , #5 } { #7 , #8 }
    }
}

\cs_new_protected:Npn \hawkdraw_softpath_curveto_opi:nn #1#2 {
    \hawkdraw_softpath_curveto_op:nnNnnNnn {#1} {#2}
}

\cs_new_protected:Npn \hawkdraw_softpath_curveto_opii:nn #1#2 {
    \hawkdraw_softpath_curveto_opii:nn
}

\cs_new_protected:Npn \hawkdraw_softpath_curveto_opiii:nn #1#2 {
    \hawkdraw_softpath_curveto_opiii:nn
}

% #1 , #2: lengths of x and y radius
% #3     : \hawkdraw_softpath_arc_opii:nn
% #4 , #5: start and end angle
\cs_new_protected:Npn \hawkdraw_softpath_arc_op:nnNnn #1#2#3#4#5 {
    \draw_path_arc:nnnn {#1} {#2} {#4} {#5}
}

\cs_new_protected:Npn \hawkdraw_softpath_arc_opi:nn #1#2 {
    \hawkdraw_softpath_arc_op:nnNnn {#1} {#2}
}

\cs_new_protected:Npn \hawkdraw_softpath_arc_opii:nn #1#2 {
    \hawkdraw_softpath_arc_opii:nn
}

% #1 , #2: x and y coordinate of vector a
% #3     : \hawkdraw_softpath_arc_axes_opii:nn
% #4 , #5: x and y coordinate of value b
% #6     : \hawkdraw_softpath_arc_axes_opiii:nn
% #7 , #8: start and end angle
\cs_new_protected:Npn \hawkdraw_softpath_arc_axes_op:nnNnnNnn #1#2#3#4#5#6#7#8 {
    \draw_path_arc_axes:nnnn { #1 , #2 } { #4 , #5 } {#7} {#8}
}

\cs_new_protected:Npn \hawkdraw_softpath_arc_axes_opi:nn #1#2 {
    \hawkdraw_softpath_arc_axes_op:nnNnnNnn {#1} {#2}
}

\cs_new_protected:Npn \hawkdraw_softpath_arc_axes_opii:nn #1#2 {
    \hawkdraw_softpath_arc_axes_opii:nn
}

\cs_new_protected:Npn \hawkdraw_softpath_arc_axes_opiii:nn #1#2 {
    \hawkdraw_softpath_arc_axes_opiii:nn
}

% #1 , #2: x and y coordinate of center
% #3     : \hawkdraw_softpath_circle_opii:nn
% #4     : length of radius
% #5     : empty
\cs_new_protected:Npn \hawkdraw_softpath_circle_op:nnNnn #1#2#3#4#5 {
    \draw_path_circle:nn { #1 , #2 } {#4}
}

\cs_new_protected:Npn \hawkdraw_softpath_circle_opi:nn #1#2 {
    \hawkdraw_softpath_circle_op:nnNnn {#1} {#2}
}

\cs_new_protected:Npn \hawkdraw_softpath_circle_opii:nn #1#2 {
    \hawkdraw_softpath_circle_opii:nn
}

% #1 , #2: x and y coordinate of center
% #3     : \hawkdraw_softpath_ellipse_opii:nn
% #4 , #5: x and y coordinate of vector a
% #6     : \hawkdraw_softpath_ellipse_opiii:nn
% #7 , #8: x and y coordinate of vector b
\cs_new_protected:Npn \hawkdraw_softpath_ellipse_op:nnNnnNnn #1#2#3#4#5#6#7#8 {
    \draw_path_ellipse:nnn { #1 , #2 } { #4 , #5 } { #7 , #8 }
}

\cs_new_protected:Npn \hawkdraw_softpath_ellipse_opi:nn #1#2 {
    \hawkdraw_softpath_ellipse_op:nnNnnNnn {#1} {#2}
}

\cs_new_protected:Npn \hawkdraw_softpath_ellipse_opii:nn #1#2 {
    \hawkdraw_softpath_ellipse_opii:nn
}

\cs_new_protected:Npn \hawkdraw_softpath_ellipse_opiii:nn #1#2 {
    \hawkdraw_softpath_ellipse_opiii:nn
}
% #1 , #2: x and y coordinate of corner a
% #3     : \hawkdraw_softpath_rectangle_opii:nn
% #4 , #5: x and y coordinate of corner b
\cs_new_protected:Npn \hawkdraw_softpath_rectangle_op:nnNnn #1#2#3#4#5 {
    \draw_path_rectangle:nn { #1 , #2 } { #4 , #5 }
}

\cs_new_protected:Npn \hawkdraw_softpath_rectangle_opi:nn #1#2 {
    \hawkdraw_softpath_rectangle_op:nnNnn {#1} {#2}
}

\cs_new_protected:Npn \hawkdraw_softpath_rectangle_opii:nn #1#2 {
    \hawkdraw_softpath_rectangle_opii:nn
}

% #1 , #2: lengths of x and y step
% #3     : \hawkdraw_softpath_grid_opii:nn
% #4 , #5: x and y coordinate of corner a
% #6     : \hawkdraw_softpath_grid_opiii:nn
% #7 , #8: x and y coordinate of corner b
\cs_new_protected:Npn \hawkdraw_softpath_grid_op:nnNnnNnn #1#2#3#4#5#6#7#8 {
    \draw_path_grid:nnnn {#1} {#2} { #4 , #5 } { #7 , #8 }
}

\cs_new_protected:Npn \hawkdraw_softpath_grid_opi:nn #1#2 {
    \hawkdraw_softpath_grid_op:nnNnnNnn {#1} {#2}
}

\cs_new_protected:Npn \hawkdraw_softpath_grid_opii:nn #1#2 {
    \hawkdraw_softpath_grid_opii:nn
}

\cs_new_protected:Npn \hawkdraw_softpath_grid_opiii:nn #1#2 {
    \hawkdraw_softpath_grid_opiii:nn
}

% =====

% Softpath manipulation helper functions

% ===

\msg_new:nnn { hawkdraw } { softpath-unknown } {
    Softpath ~ mechanism ~ `#1` ~ unknown.
}

\cs_new_protected:Npn \hawkdraw_softpath_add:NNnn #1#2#3#4 {
    \tl_build_put_right:Nn #1 { #2 }
    \tl_build_put_right:Ne #1 { {#3} }
    \tl_build_put_right:Ne #1 { {#4} }
}

\cs_new_protected:Npn \hawkdraw_softpath_add_split_tuple:NNn #1#2#3 {
    \tl_build_put_right:Nn #1 { #2 }
    \tl_build_put_right:Ne #1 {
        { \hawkdraw_tuple_use_i:n {#3} }
    }
    \tl_build_put_right:Ne #1 {
        { \hawkdraw_tuple_use_ii:n {#3} }
    }
}

\cs_new_protected:Npn \hawkdraw_softpath_gadd:NNnn #1#2#3#4 {
    \tl_build_gput_right:Nn #1 { #2 }
    \tl_build_gput_right:Ne #1 { {#3} }
    \tl_build_gput_right:Ne #1 { {#4} }
}

\cs_new_protected:Npn \hawkdraw_softpath_gadd_split_tuple:NNn #1#2#3 {
    \tl_build_gput_right:Nn #1 { #2 }
    \tl_build_gput_right:Ne #1 {
        { \hawkdraw_tuple_use_i:n {#3} }
    }
    \tl_build_gput_right:Ne #1 {
        { \hawkdraw_tuple_use_ii:n {#3} }
    }
}

\cs_new_protected:Npn \hawkdraw_softpath_build_close:n #1 {
    \hawkdraw_softpath_gadd_split_tuple:NNn
        \g_hawkdraw_softpath_original_tl
        \hawkdraw_softpath_close_op:nn {#1}
}

\cs_new_protected:Npn \hawkdraw_softpath_build_moveto:n #1 {
    \hawkdraw_softpath_gadd_split_tuple:NNn
        \g_hawkdraw_softpath_original_tl
        \hawkdraw_softpath_moveto_op:nn {#1}
}

\cs_new_protected:Npn \hawkdraw_softpath_build_lineto:n #1 {
    \hawkdraw_softpath_gadd_split_tuple:NNn
        \g_hawkdraw_softpath_original_tl
        \hawkdraw_softpath_lineto_op:nn {#1}
}

\cs_new_protected:Npn \hawkdraw_softpath_build_curveto:nn #1#2 {
    \hawkdraw_softpath_gadd_split_tuple:NNn
        \g_hawkdraw_softpath_original_tl
        \hawkdraw_softpath_curveto_opi:nn {#1}
    \hawkdraw_softpath_gadd_split_tuple:NNn
        \g_hawkdraw_softpath_original_tl
        \hawkdraw_softpath_curveto_opii:nn {#2}
    \hawkdraw_softpath_gadd:NNnn
        \g_hawkdraw_softpath_original_tl
        \hawkdraw_softpath_curveto_opiii:nn { } { }
}

\cs_new_protected:Npn \hawkdraw_softpath_build_curveto:nnn #1#2#3 {
    \hawkdraw_softpath_gadd_split_tuple:NNn
        \g_hawkdraw_softpath_original_tl
        \hawkdraw_softpath_curveto_opi:nn {#1}
    \hawkdraw_softpath_gadd_split_tuple:NNn
        \g_hawkdraw_softpath_original_tl
        \hawkdraw_softpath_curveto_opii:nn {#2}
    \hawkdraw_softpath_gadd_split_tuple:NNn
        \g_hawkdraw_softpath_original_tl
        \hawkdraw_softpath_curveto_opiii:nn {#3}
}

\cs_new_protected:Npn \hawkdraw_softpath_build_arc:nnnn #1#2#3#4 {
    \hawkdraw_softpath_gadd:NNnn
        \g_hawkdraw_softpath_original_tl
        \hawkdraw_softpath_arc_opi:nn {#1} {#2}
    \hawkdraw_softpath_gadd:NNnn
        \g_hawkdraw_softpath_original_tl
        \hawkdraw_softpath_arc_opii:nn {#3} {#4}
}
\cs_generate_variant:Nn \hawkdraw_softpath_build_arc:nnnn { VV }

\cs_new_protected:Npn \hawkdraw_softpath_build_arc_axes:nnnn #1#2#3#4 {
    \hawkdraw_softpath_gadd_split_tuple:NNn
        \g_hawkdraw_softpath_original_tl
        \hawkdraw_softpath_arc_axes_opi:nn {#1}
    \hawkdraw_softpath_gadd_split_tuple:NNn
        \g_hawkdraw_softpath_original_tl
        \hawkdraw_softpath_arc_axes_opii:nn {#2}
    \hawkdraw_softpath_gadd:NNnn
        \g_hawkdraw_softpath_original_tl
        \hawkdraw_softpath_arc_axes_opiii:nn {#3} {#4}
}

\cs_new_protected:Npn \hawkdraw_softpath_build_circle:nn #1#2 {
    \hawkdraw_softpath_gadd_split_tuple:NNn
        \g_hawkdraw_softpath_original_tl
        \hawkdraw_softpath_circle_opi:nn {#1}
    \hawkdraw_softpath_gadd:NNnn
        \g_hawkdraw_softpath_original_tl
        \hawkdraw_softpath_circle_opii:nn {#2} { }
}
\cs_generate_variant:Nn \hawkdraw_softpath_build_circle:nn { nV }

\cs_new_protected:Npn \hawkdraw_softpath_build_ellipse:nnn #1#2#3 {
    \hawkdraw_softpath_gadd_split_tuple:NNn
        \g_hawkdraw_softpath_original_tl
        \hawkdraw_softpath_ellipse_opi:nn {#1}
    \hawkdraw_softpath_gadd_split_tuple:NNn
        \g_hawkdraw_softpath_original_tl
        \hawkdraw_softpath_ellipse_opii:nn {#2}
    \hawkdraw_softpath_gadd_split_tuple:NNn
        \g_hawkdraw_softpath_original_tl
        \hawkdraw_softpath_ellipse_opiii:nn {#3}
}

\cs_new_protected:Npn \hawkdraw_softpath_build_rectangle:nn #1#2 {
    \hawkdraw_softpath_gadd_split_tuple:NNn
        \g_hawkdraw_softpath_original_tl
        \hawkdraw_softpath_rectangle_opi:nn {#1}
    \hawkdraw_softpath_gadd_split_tuple:NNn
        \g_hawkdraw_softpath_original_tl
        \hawkdraw_softpath_rectangle_opii:nn {#2}
}

\cs_new_protected:Npn \hawkdraw_softpath_build_grid:nnnn #1#2#3#4 {
    \hawkdraw_softpath_gadd:NNnn
        \g_hawkdraw_softpath_original_tl
        \hawkdraw_softpath_grid_opi:nn {#1} {#2}
    \hawkdraw_softpath_gadd_split_tuple:NNn
        \g_hawkdraw_softpath_original_tl
        \hawkdraw_softpath_grid_opii:nn {#3}
    \hawkdraw_softpath_gadd_split_tuple:NNn
        \g_hawkdraw_softpath_original_tl
        \hawkdraw_softpath_grid_opiii:nn {#4}
}
\cs_generate_variant:Nn \hawkdraw_softpath_build_grid:nnnn { VV }

% =====

\clist_new:N \l_hawkdraw_softpath_update_clist
\tl_new:N \l__hawkdraw_softpath_updated_tl

\cs_new_protected:Npn \hawkdraw_softpath_update:Nn #1#2 {
    \clist_map_inline:nn {#2} {
        \group_begin:
            \tl_build_begin:N \l__hawkdraw_softpath_updated_tl
            \cs_if_exist_use:cF { hawkdraw_softpath_ ##1 _update_fn: } {
                \msg_error:nnn { hawkdraw } { softpath-unknown } {##1}
            }
            \tl_build_end:N \l__hawkdraw_softpath_updated_tl
            \tl_gset_eq:NN #1 \l__hawkdraw_softpath_updated_tl
        \group_end:
    }
}
\cs_generate_variant:Nn \hawkdraw_softpath_update:Nn { NV }

\cs_new_protected:Npn \hawkdraw_softpath_update_close:n #1 {
    \hawkdraw_softpath_add_split_tuple:NNn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_close_op:nn {#1}
}

\cs_new_protected:Npn \hawkdraw_softpath_update_moveto:n #1 {
    \hawkdraw_softpath_add_split_tuple:NNn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_moveto_op:nn {#1}
}

\cs_new_protected:Npn \hawkdraw_softpath_update_lineto:n #1 {
    \hawkdraw_softpath_add_split_tuple:NNn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_lineto_op:nn {#1}
}

\cs_new_protected:Npn \hawkdraw_softpath_update_curveto:nn #1#2 {
    \hawkdraw_softpath_add_split_tuple:NNn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_curveto_opi:nn {#1}
    \hawkdraw_softpath_add_split_tuple:NNn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_curveto_opii:nn {#2}
    \hawkdraw_softpath_add:NNnn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_curveto_opiii:nn { } { }
}

\cs_new_protected:Npn \hawkdraw_softpath_update_curveto:nnn #1#2#3 {
    \hawkdraw_softpath_add_split_tuple:NNn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_curveto_opi:nn {#1}
    \hawkdraw_softpath_add_split_tuple:NNn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_curveto_opii:nn {#2}
    \hawkdraw_softpath_add_split_tuple:NNn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_curveto_opiii:nn {#3}
}

\cs_new_protected:Npn \hawkdraw_softpath_update_arc:nnnn #1#2#3#4 {
    \hawkdraw_softpath_add:NNnn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_arc_opi:nn {#1} {#2}
    \hawkdraw_softpath_add:NNnn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_arc_opii:nn {#3} {#4}
}

\cs_new_protected:Npn \hawkdraw_softpath_update_arc_axes:nnnn #1#2#3#4 {
    \hawkdraw_softpath_add_split_tuple:NNn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_arc_axes_opi:nn {#1}
    \hawkdraw_softpath_add_split_tuple:NNn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_arc_axes_opii:nn {#2}
    \hawkdraw_softpath_add:NNnn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_arc_axes_opiii:nn {#3} {#4}
}

\cs_new_protected:Npn \hawkdraw_softpath_update_circle:nn #1#2 {
    \hawkdraw_softpath_add_split_tuple:NNn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_circle_opi:nn {#1}
    \hawkdraw_softpath_add:NNnn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_circle_opii:nn {#2} { }
}

\cs_new_protected:Npn \hawkdraw_softpath_update_ellipse:nnn #1#2#3 {
    \hawkdraw_softpath_add_split_tuple:NNn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_ellipse_opi:nn {#1}
    \hawkdraw_softpath_add_split_tuple:NNn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_ellipse_opii:nn {#2}
    \hawkdraw_softpath_add_split_tuple:NNn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_ellipse_opiii:nn {#3}
}

\cs_new_protected:Npn \hawkdraw_softpath_update_rectangle:nn #1#2 {
    \hawkdraw_softpath_add_split_tuple:NNn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_rectangle_opi:nn {#1}
    \hawkdraw_softpath_add_split_tuple:NNn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_rectangle_opii:nn {#2}
}

\cs_new_protected:Npn \hawkdraw_softpath_update_grid:nnnn #1#2#3#4 {
    \hawkdraw_softpath_add:NNnn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_grid_opi:nn {#1} {#2}
    \hawkdraw_softpath_add_split_tuple:NNn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_grid_opii:nn {#3}
    \hawkdraw_softpath_add_split_tuple:NNn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_grid_opiii:nn {#4}
}

% =====

% Shorten paths

% ===

\dim_new:N \l_hawkdraw_softpath_shorten_start_dim
\dim_new:N \l_hawkdraw_softpath_shorten_end_dim
\bool_new:N \l__hawkdraw_softpath_shorten_start_bool
\bool_new:N \l__hawkdraw_softpath_shorten_end_bool
\fp_new:N \l_hawkdraw_softpath_shorten_point_previous_fp
\fp_new:N \l_hawkdraw_softpath_shorten_point_last_fp

\keys_define:nn { hawkdraw / path } {
    shorten ~ start         .code:n     = {
        \clist_put_right:Nn \l_hawkdraw_softpath_update_clist { shorten }
        \clist_remove_duplicates:N \l_hawkdraw_softpath_update_clist
        \dim_set:Nn \l_hawkdraw_softpath_shorten_start_dim {#1}
    } ,
    shorten ~ end           .code:n     = {
        \clist_put_right:Nn \l_hawkdraw_softpath_update_clist { shorten }
        \clist_remove_duplicates:N \l_hawkdraw_softpath_update_clist
        \dim_set:Nn \l_hawkdraw_softpath_shorten_end_dim {#1}
    } ,
}

\cs_new_protected:Npn \hawkdraw_softpath_shorten_update_fn: {
    \bool_set_true:N \l__hawkdraw_softpath_shorten_start_bool
    \fp_set:Nn \l_hawkdraw_softpath_shorten_point_last_fp { 0pt , 0pt }
    \clist_map_inline:nn {
        moveto_op:nn , lineto_op:nn ,
        curveto_op:nnNnnNnn , arc_op:nnNnn , arc_axes_op:nnNnnNnn ,
        close:op:nn , circle_op:nnNnnNnn , ellipse_op:nnNnnNnn ,
        rectangle_op:nnNnnNnn , grid_op:nnNnnNnn
    } {
        \cs_set_eq:cc {
            hawkdraw_softpath_ ##1
        } {
            hawkdraw_softpath_shorten_ ##1
        }
    }
    \tl_use:N \g_hawkdraw_softpath_original_tl
}

\cs_new_protected:Npn \__hawkdraaw_softpath_shorten_lookahead:nN #1#2 {
    \token_if_eq_meaning:NNTF #2 \s__hawkdraw_softpath_end {
        \bool_set_true:N \l__hawkdraw_softpath_shorten_end_bool
    } {
        \bool_set_false:N \l__hawkdraw_softpath_shorten_end_bool
    }
    #1#2
}

\cs_new_protected:Npn \hawkdraw_softpath_shorten_moveto_op:nn #1#2 {
    \fp_set_eq:NN \l_hawkdraw_softpath_shorten_point_previous_fp \l_hawkdraw_softpath_shorten_point_last_fp
    \fp_set:Nn \l_hawkdraw_softpath_shorten_point_last_fp { #1 , #2 }
    \bool_lazy_and:nnF {
        \dim_compare_p:nNn { \l_hawkdraw_softpath_shorten_start_dim } > { 0pt }
    } {
        \l__hawkdraw_softpath_shorten_start_bool
    } {
        \hawkdraw_softpath_update_moveto:n {
            \l_hawkdraw_softpath_shorten_point_previous_fp
        }
    }
}

\fp_new:N \l__hawkdraw_softpath_shorten_start_line_part_fp
\fp_new:N \l__hawkdraw_softpath_shorten_end_line_part_fp

\cs_new_protected:Npn \hawkdraw_softpath_shorten_lineto_op:nn #1#2 {
    \fp_set_eq:NN \l_hawkdraw_softpath_shorten_point_previous_fp \l_hawkdraw_softpath_shorten_point_last_fp
    \__hawkdraaw_softpath_shorten_lookahead:nN {
        \__hawkdraw_softpath_shorten_line:nn {
            \l_hawkdraw_softpath_shorten_point_previous_fp
        } { #1 , #2 }
    }
}

\cs_new_protected:Npn \__hawkdraw_softpath_shorten_line:nn #1#2 {
    \fp_set:Nn \l_hawkdraw_softpath_shorten_point_last_fp {#2}
    \bool_lazy_and:nnT {
        \dim_compare_p:nNn { \l_hawkdraw_softpath_shorten_start_dim } > { 0pt }
    } {
        \l__hawkdraw_softpath_shorten_start_bool
    } {
        \bool_set_false:N \l__hawkdraw_softpath_shorten_start_bool
        \fp_set:Nn \l__hawkdraw_softpath_shorten_start_line_part_fp {
            \l_hawkdraw_softpath_shorten_start_dim /
            \__hawkdraw_path_length_line:nn {#1} {#2}
        }
        \fp_gset:Nn \g_hawkdraw_path_point_first_fp {
            \__hawkdraw_point_part_line:nnn {
                \l__hawkdraw_softpath_shorten_start_line_part_fp
            } {#1} {#2}
        }
        % line: shorten start
        \hawkdraw_softpath_update_moveto:n {
            \g_hawkdraw_path_point_first_fp
        }
    }
    \bool_lazy_and:nnTF {
        \dim_compare_p:nNn { \l_hawkdraw_softpath_shorten_end_dim } > { 0pt }
    } {
        \l__hawkdraw_softpath_shorten_end_bool
    } {
        \fp_set:Nn \l__hawkdraw_softpath_shorten_end_line_part_fp {
            1 - (
                \l_hawkdraw_softpath_shorten_end_dim /
                \__hawkdraw_path_length_line:nn {#1} {#2}
            )
        }
        \fp_gset:Nn \g_hawkdraw_path_point_last_fp {
            \__hawkdraw_point_part_line:nnn {
                \l__hawkdraw_softpath_shorten_end_line_part_fp
            } {#1} {#2}
        }
        % line: shorten end
        \hawkdraw_softpath_update_lineto:n {
            \g_hawkdraw_path_point_last_fp
        }
    } {
        \hawkdraw_softpath_update_lineto:n {#2}
    }
}

\fp_new_function:n { hawkdrawlerp }
\fp_set_function:nnn { hawkdrawlerp } { p , q , t } {
    ( 1 - t ) * p + t * q
}

\fp_new_function:n { hawkdrawremapt }
\fp_set_function:nnn { hawkdrawremapt } { t , u } {
    ( u - t ) / ( 1 - t )
}

\fp_new:N \l__hawkdraw_softpath_shorten_start_curve_part_fp
\fp_new:N \l__hawkdraw_softpath_shorten_end_curve_part_fp
\fp_new:N \l__hawkdraw_softpath_shorten_start_end_curve_part_fp

\fp_new:N \l__hawkdraw_softpath_shorten_curve_point_tmpa_fp
\fp_new:N \l__hawkdraw_softpath_shorten_curve_point_tmpb_fp

\cs_new_protected:Npn \hawkdraw_softpath_shorten_curveto_op:nnNnnNnn #1#2#3#4#5#6#7#8 {
    \fp_set_eq:NN \l_hawkdraw_softpath_shorten_point_previous_fp \l_hawkdraw_softpath_shorten_point_last_fp
    \__hawkdraaw_softpath_shorten_lookahead:nN {
        \tl_if_empty:nTF {#7} {
            \__hawkdraw_softpath_shorten_curve_quadratic:nnn {
                \l_hawkdraw_softpath_shorten_point_previous_fp
             } { #1 , #2 } { #4 , #5 }
        } {
            \__hawkdraw_softpath_shorten_curve_cubic:nnnn {
                \l_hawkdraw_softpath_shorten_point_previous_fp
            } { #1 , #2 } { #4 , #5 } { #7 , #8 }
        }
    }
}

\cs_new_protected:Npn \__hawkdraw_softpath_shorten_curve_quadratic:nnn #1#2#3 {
    \fp_set:Nn \l_hawkdraw_softpath_shorten_point_last_fp {#3}
    % quadratic curve
    \bool_lazy_and:nnTF {
        \dim_compare_p:nNn { \l_hawkdraw_softpath_shorten_end_dim } > { 0pt }
    } {
        \l__hawkdraw_softpath_shorten_end_bool
    } {
        \fp_set:Nn \l__hawkdraw_softpath_shorten_end_curve_part_fp {
            1 - (
                \l_hawkdraw_softpath_shorten_end_dim /
                \__hawkdraw_path_length_curve_quadratic:nnn
                    {#1} {#2} {#3}
            )
        }
        \fp_gset:Nn \g_hawkdraw_path_point_last_fp {
            \__hawkdraw_point_part_curve_quadratic:nnnn {
                \l__hawkdraw_softpath_shorten_end_curve_part_fp
            } {#1} {#2} {#3}
        }
        \bool_lazy_and:nnTF {
            \dim_compare_p:nNn { \l_hawkdraw_softpath_shorten_start_dim } > { 0pt }
        } {
            \l__hawkdraw_softpath_shorten_start_bool
        } {
            \bool_set_false:N \l__hawkdraw_softpath_shorten_start_bool
            \fp_set:Nn \l__hawkdraw_softpath_shorten_start_curve_part_fp {
                \l_hawkdraw_softpath_shorten_start_dim /
                \__hawkdraw_path_length_curve_quadratic:nnn
                    {#1} {#2} {#3}
            }
            \fp_set:Nn \l__hawkdraw_softpath_shorten_start_end_curve_part_fp {
                hawkdrawremapt (
                    \l__hawkdraw_softpath_shorten_start_curve_part_fp ,
                    \l__hawkdraw_softpath_shorten_end_curve_part_fp
                )
            }
            \fp_gset:Nn \g_hawkdraw_path_point_first_fp {
                \__hawkdraw_point_part_curve_quadratic:nnnn {
                    \l__hawkdraw_softpath_shorten_start_curve_part_fp
                } {#1} {#2} {#3}
            }
            \fp_set:Nn \l__hawkdraw_softpath_shorten_curve_point_tmpa_fp {
                hawkdrawlerp (
                    \g_hawkdraw_path_point_first_fp ,
                    hawkdrawlerp (
                        ( #2 ) ,
                        ( #3 ) ,
                        \l__hawkdraw_softpath_shorten_start_curve_part_fp
                    ) ,
                    \l__hawkdraw_softpath_shorten_start_end_curve_part_fp
                )
            }
            % quadratic curve: shorten start, shorten end
            \hawkdraw_softpath_update_moveto:n {
                \g_hawkdraw_path_point_first_fp
            }
            \hawkdraw_softpath_update_curveto:nn {
                \l__hawkdraw_softpath_shorten_curve_point_tmpa_fp
            } {
                \g_hawkdraw_path_point_last_fp
            }
            \fp_gset:Nn \g_hawkdraw_path_slope_first_fp {
                \hawkdraw_calculate_slope:nn {
                    \g_hawkdraw_path_point_first_fp
                } {
                    \l__hawkdraw_softpath_shorten_curve_point_tmpa_fp
                }
            }
            \fp_gset:Nn \g_hawkdraw_path_slope_last_fp {
                \hawkdraw_calculate_slope:nn {
                    \l__hawkdraw_softpath_shorten_curve_point_tmpa_fp
                } {
                    \g_hawkdraw_path_point_last_fp
                }
            }
        } {
            \fp_set:Nn \l__hawkdraw_softpath_shorten_curve_point_tmpa_fp {
                hawkdrawlerp (
                    ( #1 ) ,
                    ( #2 ) ,
                    \l__hawkdraw_softpath_shorten_end_curve_part_fp
                )
            }
            % quadratic curve: shorten end
            \hawkdraw_softpath_update_curveto:nn {
                \l__hawkdraw_softpath_shorten_curve_point_tmpa_fp
            } {
                \g_hawkdraw_path_point_last_fp
            }
            \fp_gset:Nn \g_hawkdraw_path_slope_last_fp {
                \hawkdraw_calculate_slope:nn {
                    \l__hawkdraw_softpath_shorten_curve_point_tmpa_fp
                } { \g_hawkdraw_path_point_last_fp }
            }
        }
    } {
        \bool_lazy_and:nnTF {
            \dim_compare_p:nNn { \l_hawkdraw_softpath_shorten_start_dim } > { 0pt }
        } {
            \l__hawkdraw_softpath_shorten_start_bool
        } {
            \bool_set_false:N \l__hawkdraw_softpath_shorten_start_bool
            \fp_set:Nn \l__hawkdraw_softpath_shorten_start_curve_part_fp {
                \l_hawkdraw_softpath_shorten_start_dim /
                \__hawkdraw_path_length_curve_quadratic:nnn
                    {#1} {#2} {#3}
            }
            \fp_gset:Nn \g_hawkdraw_path_point_first_fp {
                \__hawkdraw_point_part_curve_quadratic:nnnn {
                    \l__hawkdraw_softpath_shorten_start_curve_part_fp
                } {#1} {#2} {#3}
            }
            \fp_set:Nn \l__hawkdraw_softpath_shorten_curve_point_tmpa_fp {
                hawkdrawlerp (
                    ( #2 ) ,
                    ( #3 ) ,
                    \l__hawkdraw_softpath_shorten_start_curve_part_fp
                )
            }
            % quadratic curve: shorten start
            \hawkdraw_softpath_update_moveto:n {
                \g_hawkdraw_path_point_first_fp
            }
            \hawkdraw_softpath_update_curveto:nn {
                \l__hawkdraw_softpath_shorten_curve_point_tmpa_fp
            } {#3}
            \fp_gset:Nn \g_hawkdraw_path_slope_first_fp {
                \hawkdraw_calculate_slope:nn {
                    \g_hawkdraw_path_point_first_fp
                } {
                    \l__hawkdraw_softpath_shorten_curve_point_tmpa_fp
                }
            }
        } {
            \hawkdraw_softpath_update_curveto:nn {#2} {#3}
        }
    }
}

\cs_new_protected:Npn \__hawkdraw_softpath_shorten_curve_cubic:nnnn #1#2#3#4 {
    \fp_set:Nn \l_hawkdraw_softpath_shorten_point_last_fp {#4}
    % cubic curve
    \bool_lazy_and:nnTF {
        \dim_compare_p:nNn { \l_hawkdraw_softpath_shorten_end_dim } > { 0pt }
    } {
        \l__hawkdraw_softpath_shorten_end_bool
    } {
        \fp_set:Nn \l__hawkdraw_softpath_shorten_end_curve_part_fp {
            1 - (
                \l_hawkdraw_softpath_shorten_end_dim /
                \__hawkdraw_path_length_curve_cubic:nnnn
                    {#1} {#2} {#3} {#4}
            )
        }
        \fp_gset:Nn \g_hawkdraw_path_point_last_fp {
            \__hawkdraw_point_part_curve_cubic:nnnnn {
                \l__hawkdraw_softpath_shorten_end_curve_part_fp
            } {#1} {#2} {#3} {#4}
        }
        \bool_lazy_and:nnTF {
            \dim_compare_p:nNn { \l_hawkdraw_softpath_shorten_start_dim } > { 0pt }
        } {
            \l__hawkdraw_softpath_shorten_start_bool
        } {
            \bool_set_false:N \l__hawkdraw_softpath_shorten_start_bool
            \fp_set:Nn \l__hawkdraw_softpath_shorten_start_curve_part_fp {
                \l_hawkdraw_softpath_shorten_start_dim /
                \__hawkdraw_path_length_curve_cubic:nnnn
                    {#1} {#2} {#3} {#4}
            }
            \fp_set:Nn \l__hawkdraw_softpath_shorten_start_end_curve_part_fp {
                hawkdrawremapt (
                    \l__hawkdraw_softpath_shorten_start_curve_part_fp ,
                    \l__hawkdraw_softpath_shorten_end_curve_part_fp
                )
            }
            \fp_gset:Nn \g_hawkdraw_path_point_first_fp {
                \__hawkdraw_point_part_curve_cubic:nnnnn {
                    \l__hawkdraw_softpath_shorten_start_curve_part_fp
                } {#1} {#2} {#3} {#4}
            }
            \fp_set:Nn \l__hawkdraw_softpath_shorten_curve_point_tmpa_fp {
                % A' = (1-u)F + uE
                hawkdrawlerp (
                    % F = (1-t)D + tE = R0
                    \g_hawkdraw_path_point_first_fp ,
                    % E = (1-t)B + tC
                    hawkdrawlerp (
                        % B = (1-t)P1 + tP2
                        hawkdrawlerp (
                            ( #2 ) ,
                            ( #3 ) ,
                            \l__hawkdraw_softpath_shorten_start_curve_part_fp
                        ) ,
                        % C = (1-t)P2 + tP3
                        hawkdrawlerp (
                            ( #3 ) ,
                            ( #4 ) ,
                            \l__hawkdraw_softpath_shorten_start_curve_part_fp
                        ) ,
                        \l__hawkdraw_softpath_shorten_start_curve_part_fp
                    ) ,
                    \l__hawkdraw_softpath_shorten_start_end_curve_part_fp
                )
            }
            \fp_set:Nn \l__hawkdraw_softpath_shorten_curve_point_tmpb_fp {
                % D' = (1-u)A' + uB'
                hawkdrawlerp (
                    hawkdrawlerp (
                        \g_hawkdraw_path_point_first_fp ,
                        hawkdrawlerp (
                            hawkdrawlerp (
                                ( #2 ) ,
                                ( #3 ) ,
                                \l__hawkdraw_softpath_shorten_start_curve_part_fp
                            ) ,
                            hawkdrawlerp (
                                ( #3 ) ,
                                ( #4 ) ,
                                \l__hawkdraw_softpath_shorten_start_curve_part_fp
                            ) ,
                            \l__hawkdraw_softpath_shorten_start_curve_part_fp
                        ) ,
                        \l__hawkdraw_softpath_shorten_start_end_curve_part_fp
                    ) ,
                    % B' = (1-u)E + uC
                    hawkdrawlerp (
                        hawkdrawlerp (
                            hawkdrawlerp (
                                ( #2 ) ,
                                ( #3 ) ,
                                \l__hawkdraw_softpath_shorten_start_curve_part_fp
                            ) ,
                            hawkdrawlerp (
                                ( #3 ) ,
                                ( #4 ) ,
                                \l__hawkdraw_softpath_shorten_start_curve_part_fp
                            ) ,
                            \l__hawkdraw_softpath_shorten_start_curve_part_fp
                        ) ,
                        hawkdrawlerp (
                            ( #3 ) ,
                            ( #4 ) ,
                            \l__hawkdraw_softpath_shorten_start_curve_part_fp
                        ) ,
                        \l__hawkdraw_softpath_shorten_start_end_curve_part_fp
                    ) ,
                    \l__hawkdraw_softpath_shorten_start_end_curve_part_fp
                )
            }
            % cubic curve: shorten start, shorten end
            \hawkdraw_softpath_update_moveto:n {
                \g_hawkdraw_path_point_first_fp
            }
            \hawkdraw_softpath_update_curveto:nnn {
                \l__hawkdraw_softpath_shorten_curve_point_tmpa_fp
            } {
                \l__hawkdraw_softpath_shorten_curve_point_tmpb_fp
            } {
                \g_hawkdraw_path_point_last_fp
            }
            \fp_gset:Nn \g_hawkdraw_path_slope_first_fp {
                \hawkdraw_calculate_slope:nn {
                    \g_hawkdraw_path_point_first_fp
                } {
                    \l__hawkdraw_softpath_shorten_curve_point_tmpa_fp
                }
            }
            \fp_gset:Nn \g_hawkdraw_path_slope_last_fp {
                \hawkdraw_calculate_slope:nn {
                    \l__hawkdraw_softpath_shorten_curve_point_tmpb_fp
                } {
                    \g_hawkdraw_path_point_last_fp
                }
            }
        } {
            \fp_set:Nn \l__hawkdraw_softpath_shorten_curve_point_tmpa_fp {
                hawkdrawlerp (
                    ( #1 ) ,
                    ( #2 ) ,
                    \l__hawkdraw_softpath_shorten_end_curve_part_fp
                )
            }
            \fp_set:Nn \l__hawkdraw_softpath_shorten_curve_point_tmpb_fp {
                hawkdrawlerp (
                    hawkdrawlerp (
                        ( #1 ) ,
                        ( #2 ) ,
                        \l__hawkdraw_softpath_shorten_end_curve_part_fp
                    ) ,
                    hawkdrawlerp (
                        ( #2 ) ,
                        ( #3 ) ,
                        \l__hawkdraw_softpath_shorten_end_curve_part_fp
                    ) ,
                    \l__hawkdraw_softpath_shorten_end_curve_part_fp
                )
            }
            % cubic curve: shorten end
            \hawkdraw_softpath_update_curveto:nnn {
                \l__hawkdraw_softpath_shorten_curve_point_tmpa_fp
            } {
                \l__hawkdraw_softpath_shorten_curve_point_tmpb_fp
            } {
                \g_hawkdraw_path_point_last_fp
            }
            \fp_gset:Nn \g_hawkdraw_path_slope_last_fp {
                \hawkdraw_calculate_slope:nn {
                    \l__hawkdraw_softpath_shorten_curve_point_tmpb_fp
                } {
                    \g_hawkdraw_path_point_last_fp
                }
            }
        }
    } {
        \bool_lazy_and:nnTF {
            \dim_compare_p:nNn { \l_hawkdraw_softpath_shorten_start_dim } > { 0pt }
        } {
            \l__hawkdraw_softpath_shorten_start_bool
        } {
            \bool_set_false:N \l__hawkdraw_softpath_shorten_start_bool
            \fp_set:Nn \l__hawkdraw_softpath_shorten_start_curve_part_fp {
                \l_hawkdraw_softpath_shorten_start_dim /
                \__hawkdraw_path_length_curve_cubic:nnnn
                    {#1} {#2} {#3} {#4}
            }
            \fp_gset:Nn \g_hawkdraw_path_point_first_fp {
                \__hawkdraw_point_part_curve_cubic:nnnnn {
                    \l__hawkdraw_softpath_shorten_start_curve_part_fp
                } {#1} {#2} {#3} {#4}
            }
            \fp_set:Nn \l__hawkdraw_softpath_shorten_curve_point_tmpa_fp {
                hawkdrawlerp (
                    hawkdrawlerp (
                        ( #2 ) ,
                        ( #3 ) ,
                        \l__hawkdraw_softpath_shorten_start_curve_part_fp
                    ) ,
                    hawkdrawlerp (
                        ( #3 ) ,
                        ( #4 ) ,
                        \l__hawkdraw_softpath_shorten_start_curve_part_fp
                    ) ,
                    \l__hawkdraw_softpath_shorten_start_curve_part_fp
                )
            }
            \fp_set:Nn \l__hawkdraw_softpath_shorten_curve_point_tmpb_fp {
                hawkdrawlerp (
                    ( #3 ) ,
                    ( #4 ) ,
                    \l__hawkdraw_softpath_shorten_start_curve_part_fp
                )
            }
            % cubic curve: shorten start
            \hawkdraw_softpath_update_moveto:n {
                \g_hawkdraw_path_point_first_fp
            }
            \hawkdraw_softpath_update_curveto:nnn {
                \l__hawkdraw_softpath_shorten_curve_point_tmpa_fp
            } {
                \l__hawkdraw_softpath_shorten_curve_point_tmpb_fp
            } {#4}
            \fp_gset:Nn \g_hawkdraw_path_slope_first_fp {
                \hawkdraw_calculate_slope:nn {
                    \g_hawkdraw_path_point_first_fp
                } {
                    \l__hawkdraw_softpath_shorten_curve_point_tmpa_fp
                }
            }
        } {
            \hawkdraw_softpath_update_curveto:nnn {#2} {#3} {#4}
        }
    }
}

\fp_new:N \l__hawkdraw_softpath_shorten_start_arc_part_fp
\fp_new:N \l__hawkdraw_softpath_shorten_end_arc_part_fp

\cs_new_protected:Npn \hawkdraw_softpath_shorten_arc_op:nnNnn #1#2#3#4#5 {
    \fp_set_eq:NN \l_hawkdraw_softpath_shorten_point_previous_fp \l_hawkdraw_softpath_shorten_point_last_fp
    \__hawkdraaw_softpath_shorten_lookahead:nN {
        \__hawkdraw_softpath_shorten_arc:nnnn
            {#1} {#2} {#4} {#5}
    }
}

\cs_new_protected:Npn \__hawkdraw_softpath_shorten_arc:nnnn #1#2#3#4 {
    \fp_set:Nn \l_hawkdraw_softpath_shorten_point_last_fp {
        \__hawkdraw_point_part_arc:nnnnnn
            { 1 } { \l_hawkdraw_softpath_shorten_point_previous_fp }
            {#1} {#2} {#3} {#4}
    }
    \bool_lazy_and:nnTF {
        \dim_compare_p:nNn { \l_hawkdraw_softpath_shorten_end_dim } > { 0pt }
    } {
        \l__hawkdraw_softpath_shorten_end_bool
    } {
        \fp_set:Nn \l__hawkdraw_softpath_shorten_end_arc_part_fp {
            \l_hawkdraw_softpath_shorten_end_dim /
            \__hawkdraw_path_length_arc:nnnn
                {#1} {#2} {#3} {#4}
        }
        \fp_gset:Nn \g_hawkdraw_path_point_last_fp {
            \__hawkdraw_point_part_arc:nnnnn {
                \l__hawkdraw_softpath_shorten_end_arc_part_fp
            } {
                \l_hawkdraw_softpath_shorten_point_previous_fp
            } {#1} {#2} {#3} {#4}
        }
        \bool_lazy_and:nnTF {
            \dim_compare_p:nNn { \l_hawkdraw_softpath_shorten_start_dim } > { 0pt }
        } {
            \l__hawkdraw_softpath_shorten_start_bool
        } {
            \bool_set_false:N \l__hawkdraw_softpath_shorten_start_bool
            \fp_set:Nn \l__hawkdraw_softpath_shorten_start_arc_part_fp {
                \l_hawkdraw_softpath_shorten_start_dim /
                \__hawkdraw_path_length_arc:nnnn
                    {#1} {#2} {#3} {#4}
            }
            \fp_gset:Nn \g_hawkdraw_path_point_first_fp {
                \__hawkdraw_point_part_arc:nnnnn {
                    \l__hawkdraw_softpath_shorten_start_arc_part_fp
                } {
                    \l_hawkdraw_softpath_shorten_point_previous_fp
                } {#1} {#2} {#3} {#4}
            }
            % arc: shorten start, shorten end
            \hawkdraw_softpath_update_moveto:n {
                \g_hawkdraw_path_point_first_fp
            }
            \hawkdraw_softpath_update_arc:nnnn {#1} {#2} {
                #3 + \l__hawkdraw_softpath_shorten_start_arc_part_fp * ( #4 - #3 )
            } {
                #4 - \l__hawkdraw_softpath_shorten_end_arc_part_fp * ( #4 - #3 )
            }
            \fp_gset:Nn \g_hawkdraw_path_slope_first_fp {
                \__hawkdraw_point_part_slope_arc:n {
                    \l__hawkdraw_softpath_shorten_start_arc_part_fp
                }
            }
            \fp_gset:Nn \g_hawkdraw_path_slope_last_fp {
                \__hawkdraw_point_part_slope_arc:n {
                    \l__hawkdraw_softpath_shorten_end_arc_part_fp
                }
            }
        } {
            % arc: shorten end
            \hawkdraw_softpath_update_arc:nnnn {#1} {#2} {#3} {
                #4 - \l__hawkdraw_softpath_shorten_end_arc_part_fp * ( #4 - #3 )
            }
            \fp_gset:Nn \g_hawkdraw_path_slope_last_fp {
                \__hawkdraw_point_part_slope_arc:n {
                    \l__hawkdraw_softpath_shorten_end_arc_part_fp
                }
            }
        }
    } {
        \bool_lazy_and:nnTF {
            \dim_compare_p:nNn { \l_hawkdraw_softpath_shorten_start_dim } > { 0pt }
        } {
            \l__hawkdraw_softpath_shorten_start_bool
        } {
            \fp_set:Nn \l__hawkdraw_softpath_shorten_start_arc_part_fp {
                \l_hawkdraw_softpath_shorten_start_dim /
                \__hawkdraw_path_length_arc:nnnn
                    {#1} {#2} {#3} {#4}
            }
            \fp_gset:Nn \g_hawkdraw_path_point_first_fp {
                \__hawkdraw_point_part_arc:nnnnn {
                    \l__hawkdraw_softpath_shorten_start_arc_part_fp
                } {
                    \l_hawkdraw_softpath_shorten_point_previous_fp
                } {#1} {#2} {#3} {#4}
            }
            \hawkdraw_softpath_update_moveto:n {
                \g_hawkdraw_path_point_first_fp
            }
            \hawkdraw_softpath_update_arc:nnnn {#1} {#2} {
                #3 + \l__hawkdraw_softpath_shorten_start_arc_part_fp * ( #4 - #3 )
            } {#4}
            \fp_gset:Nn \g_hawkdraw_path_slope_first_fp {
                \__hawkdraw_point_part_slope_arc:n {
                    \l__hawkdraw_softpath_shorten_start_arc_part_fp
                }
            }
        } {
            \hawkdraw_softpath_update_arc:nnnn {#1} {#2} {#3} {#4}
        }
    }
}

\fp_new:N \l__hawkdraw_softpath_shorten_start_arc_axes_part_fp
\fp_new:N \l__hawkdraw_softpath_shorten_end_arc_axes_part_fp

\cs_new_protected:Npn \hawkdraw_softpath_shorten_arc_axes_op:nnNnnNnn #1#2#3#4#5#6#7#8 {
    \fp_set_eq:NN \l_hawkdraw_softpath_shorten_point_previous_fp \l_hawkdraw_softpath_shorten_point_last_fp
    \__hawkdraaw_softpath_shorten_lookahead:nN {
        \__hawkdraw_softpath_shorten_arc_axes:nnnn
            { #1 , #2 } { #4 , #5 } {#7} {#8}
    }
}

\cs_new_protected:Npn \__hawkdraw_softpath_shorten_arc_axes:nnnn #1#2#3#4 {
    \fp_set:Nn \l_hawkdraw_softpath_shorten_point_last_fp {
        \__hawkdraw_point_part_arc:nnnnnn
            { 1 } { \l_hawkdraw_softpath_shorten_point_previous_fp }
            {#1} {#2} {#3} {#4}
    }
    \bool_lazy_and:nnTF {
        \dim_compare_p:nNn { \l_hawkdraw_softpath_shorten_end_dim } > { 0pt }
    } {
        \l__hawkdraw_softpath_shorten_end_bool
    } {
        \fp_set:Nn \l__hawkdraw_softpath_shorten_end_arc_axes_part_fp {
            \l_hawkdraw_softpath_shorten_end_dim /
            \__hawkdraw_path_length_arc_axes:nnnn
                {#1} {#2} {#3} {#4}
        }
        \fp_gset:Nn \g_hawkdraw_path_point_last_fp {
            \__hawkdraw_point_part_arc_axes:nnnnn {
                \l__hawkdraw_softpath_shorten_end_arc_axes_part_fp
            } {
                \l_hawkdraw_softpath_shorten_point_previous_fp
            } {#1} {#2} {#3} {#4}
        }
        \bool_lazy_and:nnTF {
            \dim_compare_p:nNn { \l_hawkdraw_softpath_shorten_start_dim } > { 0pt }
        } {
            \l__hawkdraw_softpath_shorten_start_bool
        } {
            \bool_set_false:N \l__hawkdraw_softpath_shorten_start_bool
            \fp_set:Nn \l__hawkdraw_softpath_shorten_start_arc_axes_part_fp {
                \l_hawkdraw_softpath_shorten_start_dim /
                \__hawkdraw_path_length_arc_axes:nnnn
                    {#1} {#2} {#3} {#4}
            }
            \fp_gset:Nn \g_hawkdraw_path_point_first_fp {
                \__hawkdraw_point_part_arc_axes:nnnnn {
                    \l__hawkdraw_softpath_shorten_start_arc_axes_part_fp
                } {
                    \l_hawkdraw_softpath_shorten_point_previous_fp
                } {#1} {#2} {#3} {#4}
            }
            % arc: shorten start, shorten end
            \hawkdraw_softpath_update_moveto:n {
                \g_hawkdraw_path_point_first_fp
            }
            \hawkdraw_softpath_update_arc_axes:nnnn {#1} {#2} {
                #3 + \l__hawkdraw_softpath_shorten_start_arc_axes_part_fp * ( #4 - #3 )
            } {
                #4 - \l__hawkdraw_softpath_shorten_end_arc_axes_part_fp * ( #4 - #3 )
            }
            \fp_gset:Nn \g_hawkdraw_path_slope_first_fp {
                \__hawkdraw_point_part_slope_arc:n {
                    \l__hawkdraw_softpath_shorten_start_arc_axes_part_fp
                }
            }
            \fp_gset:Nn \g_hawkdraw_path_slope_last_fp {
                \__hawkdraw_point_part_slope_arc:n {
                    \l__hawkdraw_softpath_shorten_end_arc_axes_part_fp
                }
            }
        } {
            % arc: shorten end
            \hawkdraw_softpath_update_arc_axes:nnnn {#1} {#2} {#3} {
                #4 - \l__hawkdraw_softpath_shorten_end_arc_axes_part_fp * ( #4 - #3 )
            }
            \fp_gset:Nn \g_hawkdraw_path_slope_last_fp {
                \__hawkdraw_point_part_slope_arc:n {
                    \l__hawkdraw_softpath_shorten_end_arc_axes_part_fp
                }
            }
        }
    } {
        \bool_lazy_and:nnTF {
            \dim_compare_p:nNn { \l_hawkdraw_softpath_shorten_start_dim } > { 0pt }
        } {
            \l__hawkdraw_softpath_shorten_start_bool
        } {
            \fp_set:Nn \l__hawkdraw_softpath_shorten_start_arc_axes_part_fp {
                \l_hawkdraw_softpath_shorten_start_dim /
                \__hawkdraw_path_length_arc_axes:nnnn
                    {#1} {#2} {#3} {#4}
            }
            \fp_gset:Nn \g_hawkdraw_path_point_first_fp {
                \__hawkdraw_point_part_arc_axes:nnnnn {
                    \l__hawkdraw_softpath_shorten_start_arc_axes_part_fp
                } {
                    \l_hawkdraw_softpath_shorten_point_previous_fp
                } {#1} {#2} {#3} {#4}
            }
            % arc: shorten start
            \hawkdraw_softpath_update_moveto:n {
                \g_hawkdraw_path_point_first_fp
            }
            \hawkdraw_softpath_update_arc_axes:nnnn {#1} {#2} {
                #3 + \l__hawkdraw_softpath_shorten_start_arc_axes_part_fp * ( #4 - #3 )
            } {#4}
            \fp_gset:Nn \g_hawkdraw_path_slope_first_fp {
                \__hawkdraw_point_part_slope_arc:n {
                    \l__hawkdraw_softpath_shorten_start_arc_axes_part_fp
                }
            }
        } {
            \hawkdraw_softpath_update_arc_axes:nnnn {#1} {#2} {#3} {#4}
        }
    }
}

\cs_new_protected:Npn \hawkdraw_softpath_shorten_close_op:nn #1#2 {
    \hawkdraw_softpath_add:NNnn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_close_op:nn {#1} {#2}
}

\cs_new_protected:Npn \hawkdraw_softpath_shorten_circle_op:nnNnn #1#2#3#4#5 {
    \hawkdraw_softpath_add:NNnn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_circle_opi:nn {#1} {#2}
    \hawkdraw_softpath_add:NNnn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_circle_opii:nn {#4} {#5}
}

\cs_new_protected:Npn \hawkdraw_softpath_shorten_ellipse_op:nnNnnNnn #1#2#3#4#5#6#7#8 {
    \hawkdraw_softpath_add:NNnn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_ellipse_opi:nn {#1} {#2}
    \hawkdraw_softpath_add:NNnn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_ellipse_opii:nn {#4} {#5}
    \hawkdraw_softpath_add:NNnn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_ellipse_opiii:nn {#7} {#8}
}

\cs_new_protected:Npn \hawkdraw_softpath_shorten_rectangle_op:nnNnn #1#2#3#4#5 {
    \hawkdraw_softpath_add:NNnn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_rectangle_opi:nn {#1} {#2}
    \hawkdraw_softpath_add:NNnn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_rectangle_opii:nn {#4} {#5}
}

\cs_new_protected:Npn \hawkdraw_softpath_shorten_grid_op:nnNnnNnn #1#2#3#4#5#6#7#8 {
    \hawkdraw_softpath_add:NNnn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_grid_opi:nn {#1} {#2}
    \hawkdraw_softpath_add:NNnn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_grid_opii:nn {#4} {#5}
    \hawkdraw_softpath_add:NNnn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_grid_opiii:nn {#7} {#8}
}

% =====

% Offset paths

% ===

\dim_new:N \l_hawkdraw_softpath_offset_dim
\bool_new:N \l__hawkdraw_softpath_offset_moveto_bool
\fp_new:N \l_hawkdraw_softpath_offset_point_first_fp
\fp_new:N \l_hawkdraw_softpath_offset_point_last_fp
\fp_new:N \l_hawkdraw_softpath_offset_slope_next_fp

\keys_define:nn { hawkdraw / path } {
    offset                 .code:n     = {
        \clist_put_right:Nn \l_hawkdraw_softpath_update_clist { offset }
        \clist_remove_duplicates:N \l_hawkdraw_softpath_update_clist
        \dim_set:Nn \l_hawkdraw_softpath_offset_dim {#1}
    } ,
}

\cs_new_protected:Npn \hawkdraw_softpath_offset_update_fn: {
    \clist_map_inline:nn {
        moveto_op:nn , lineto_op:nn ,
        curveto_op:nnNnnNnn , arc_op:nnNnn , arc_axes_op:nnNnnNnn ,
        close:op:nn , circle_op:nnNnn , ellipse_op:nnNnnNnn ,
        rectangle_op:nnNnn , grid_op:nnNnnNnn
    } {
        \cs_set_eq:cc {
            hawkdraw_softpath_ ##1
        } {
            hawkdraw_softpath_offset_ ##1
        }
    }
    \tl_use:N \g_hawkdraw_softpath_original_tl
}

\fp_new:N \l__hawkdraw_softpath_offset_corner_offset_fp
\fp_set:Nn \l__hawkdraw_softpath_offset_corner_offset_fp { 0pt , 0pt }

\cs_new_protected:Npn \__hawkdraw_softpath_offset_get_slope_next:nnN #1#2#3 {
    \token_if_eq_meaning:NNTF #3 \s__hawkdraw_softpath_end {
        \fp_set:Nn \l_hawkdraw_softpath_offset_slope_next_fp { nan }
        #2
    } {
        \__hawkdraw_softpath_offset_get_slope_next:nnNnn {#1} {#2}
    }
    #3
}

\cs_new_protected:Npn \__hawkdraw_softpath_offset_get_slope_next:nnNnn #1#2#3#4#5 {
    \token_if_eq_meaning:NNT #3 \hawkdraw_softpath_lineto_op:nn {
        \fp_set:Nn \l_hawkdraw_softpath_offset_slope_next_fp {
            \hawkdraw_calculate_slope:nn {#1} {
                #4 , #5
            }
        }
    }
    \token_if_eq_meaning:NNT #3 \hawkdraw_softpath_curveto_opi:nn {
        \fp_set:Nn \l_hawkdraw_softpath_offset_slope_next_fp {
            \hawkdraw_calculate_slope:nn {#1} {
                #4 , #5
            }
        }
    }
    \bool_lazy_or:nnTF {
        \token_if_eq_meaning_p:NN #3 \hawkdraw_softpath_arc_opi:nn
    } {
        \token_if_eq_meaning_p:NN #3 \hawkdraw_softpath_arc_axes_opi:nn
    } {
        \__hawkdraw_softpath_offset_get_slope_next_arc:nNnnNnn
            {#2} #3 {#4} {#5}
    } {
        #2#3 {#4} {#5}
    }
}

\cs_new_protected:Npn \__hawkdraw_softpath_offset_get_slope_next_arc:nNnnNnn #1#2#3#4#5#6#7 {
    \token_if_eq_meaning:NNTF #2 \hawkdraw_softpath_arc_opi:nn {
        \fp_set:Nn \l_hawkdraw_softpath_offset_slope_next_fp {
            \__hawkdraw_point_part_slope_arc:nnnnn
                { 0 } {#3} {#4} {#6} {#7}
        }
        #1#2 {#3} {#4} #5 {#6} {#7}
    } {
        \__hawkdraw_softpath_offset_get_slope_next_arc_axes:nnNnn
            {#1} { #2 {#3} {#4} #5 {#6} {#7} }
    }
}

\cs_new_protected:Npn \__hawkdraw_softpath_offset_get_slope_next_arc_axes:nnNnn #1#2#3#4#5 {
    \fp_set:Nn \l_hawkdraw_softpath_offset_slope_next_fp {
        \__hawkdraw_point_part_slope_arc_axes:nnnnn
            { 0 } {
                \tl_item:nn {#2} { 2 } , \tl_item:nn {#2} { 3 }
            } {
                \tl_item:nn {#2} { 5 } , \tl_item:nn {#2} { 6 }
            } {#4} {#5}
    }
    {#1}
    \tl_item:nn {#2} { 1 } { \tl_item:nn {#2} { 2 } } { \tl_item:nn {#2} { 3 } }
    \tl_item:nn {#2} { 4 } { \tl_item:nn {#2} { 5 } } { \tl_item:nn {#2} { 6 } }
    #3 {#4} {#5}
}

\cs_new_protected:Npn \hawkdraw_softpath_offset_calculate_corner_offset:Nnnn #1#2#3#4 {
    \fp_if_nan:nTF {#4} {
        \fp_set:Nn #1 {
            \draw_point_polar:nn {#2} { #3 + 90 }
        }
    } {
        \fp_compare:nNnF {#4} = {#3} {
            \fp_set:Nn #1 {
                \draw_point_polar:nn {
                    #2 /
                    cosd( ( #4 - #3 ) / 2 )
                } {
                    #4 - ( #4 - #3 ) / 2 + 90
                }
            }
        }
    }
}

\cs_new_protected:Npn \hawkdraw_softpath_offset_moveto_op:nn #1#2 {
    \fp_set:Nn \l_hawkdraw_softpath_offset_point_first_fp { #1 , #2 }
    \fp_set:Nn \l_hawkdraw_softpath_offset_point_last_fp { #1 , #2 }
    \fp_set:Nn \l_hawkdraw_softpath_offset_slope_next_fp { nan }
    \bool_set_true:N \l__hawkdraw_softpath_offset_moveto_bool
}

\cs_new_protected:Npn \hawkdraw_softpath_offset_lineto_op:nn #1#2 {
    \__hawkdraw_softpath_offset_get_slope_next:nnN {
        #1 , #2
    } {
        \hawkdraw_softpath_offset_lineto:n {
            #1 , #2
        }
    }
}

\cs_new_protected:Npn \hawkdraw_softpath_offset_lineto:n #1 {
    \bool_if:NT \l__hawkdraw_softpath_offset_moveto_bool {
        \bool_set_false:N \l__hawkdraw_softpath_offset_moveto_bool
        \fp_gset:Nn \g_hawkdraw_path_point_first_fp {
            \l_hawkdraw_softpath_offset_point_first_fp + (
                \draw_point_polar:nn {
                    \l_hawkdraw_softpath_offset_dim
                } {
                    \g_hawkdraw_path_slope_first_fp + 90
                }
            )
        }
        \hawkdraw_softpath_update_moveto:n {
            \g_hawkdraw_path_point_first_fp
        }
    }
    \hawkdraw_softpath_offset_calculate_corner_offset:Nnnn
        \l__hawkdraw_softpath_offset_corner_offset_fp {
            \l_hawkdraw_softpath_offset_dim
        } {
            \hawkdraw_calculate_slope:nn {
                \l_hawkdraw_softpath_offset_point_last_fp
            } {#1}
        } {
            \l_hawkdraw_softpath_offset_slope_next_fp
        }
    \fp_set:Nn \l_hawkdraw_softpath_offset_point_last_fp {#1}
    \fp_gset:Nn \g_hawkdraw_path_point_last_fp {
        \l_hawkdraw_softpath_offset_point_last_fp +
        \l__hawkdraw_softpath_offset_corner_offset_fp
    }
    \hawkdraw_softpath_update_lineto:n {
        \g_hawkdraw_path_point_last_fp
    }
}

% a to l
\int_step_inline:nn { 12 } {
    \fp_new:c {
        l__hawkdraw_softpath_offset_curve_point_tmp \int_to_alph:n {#1 } _fp
    }
}

\cs_new_protected:Npn \hawkdraw_softpath_offset_curveto_op:nnNnnNnn #1#2#3#4#5#6#7#8 {
    \__hawkdraw_softpath_offset_get_slope_next:nnN {
        \tl_if_empty:nTF {#7} {
            #4 , #5
        } {
            #7 , #8
        }
    } {
        \hawkdraw_softpath_offset_calculate_corner_offset:Nnnn
            \l__hawkdraw_softpath_offset_corner_offset_fp {
                \l_hawkdraw_softpath_offset_dim
            } {
                \tl_if_empty:nTF {#7} {
                    \hawkdraw_calculate_slope:nn { #1 , #2 } { #4 , #5 }
                } {
                    \hawkdraw_calculate_slope:nn { #4 , #5 } { #7 , #8 }
                }
            } {
                \l_hawkdraw_softpath_offset_slope_next_fp
            }
        \tl_if_empty:nTF {#7} {
            \__hawkdraw_softpath_offset_curve_quadratic:nnn {
                \l_hawkdraw_softpath_offset_point_last_fp
            } { #1 , #2 } { #4 , #5 }
            \fp_set:Nn \l_hawkdraw_softpath_offset_point_last_fp {
                #4 , #5
            }
        } {
            \__hawkdraw_softpath_offset_curve_cubic:nnnn {
                \l_hawkdraw_softpath_offset_point_last_fp
            } { #1 , #2 } { #4 , #5 } { #7 , #8 }
            \fp_set:Nn \l_hawkdraw_softpath_offset_point_last_fp {
                #7 , #8
            }
        }
    }
}

\cs_new_protected:Npn \__hawkdraw_softpath_offset_curve_quadratic:nnn #1#2#3 {
    \fp_set:Nn \l__hawkdraw_softpath_offset_curve_point_tmpa_fp {
        hawkdrawlerp ( ( #1 ) , ( #2 ) , 1/3 )
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_curve_point_tmpb_fp {
        hawkdrawlerp (
            hawkdrawlerp ( ( #1 ) , ( #2 ) , 1/3 ) ,
            hawkdrawlerp ( ( #2 ) , ( #3 ) , 1/3 ) ,
            1/3
        )
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_curve_point_tmpc_fp {
        hawkdrawlerp (
            hawkdrawlerp ( ( #1 ) , ( #2 ) , 1/3 ) ,
            hawkdrawlerp ( ( #2 ) , ( #3 ) , 1/3 ) ,
            2/3
        )
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_curve_point_tmpd_fp {
        hawkdrawlerp (
            hawkdrawlerp ( ( #1 ) , ( #2 ) , 2/3 ) ,
            hawkdrawlerp ( ( #2 ) , ( #3 ) , 2/3 ) ,
            2/3
        )
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_curve_point_tmpe_fp {
        hawkdrawlerp ( ( #2 ) , ( #3 ) , 2/3 )
    }

    \fp_set:Nn \l__hawkdraw_softpath_offset_curve_point_tmpf_fp {
        ( #1 ) + (
            \draw_point_polar:nn {
                \l_hawkdraw_softpath_offset_dim
            } {
                \hawkdraw_calculate_slope:nn {#1} {#2} + 90
            }
        )
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_curve_point_tmpg_fp {
        ( \l__hawkdraw_softpath_offset_curve_point_tmpa_fp ) + (
            \draw_point_polar:nn {
                \l_hawkdraw_softpath_offset_dim
            } {
                \hawkdraw_calculate_slope:nn {#1} {
                    \l__hawkdraw_softpath_offset_curve_point_tmpb_fp
                } + 90
            }
        )
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_curve_point_tmph_fp {
        ( \l__hawkdraw_softpath_offset_curve_point_tmpb_fp ) + (
            \draw_point_polar:nn {
                \l_hawkdraw_softpath_offset_dim
            } {
                \hawkdraw_calculate_slope:nn {
                    \l__hawkdraw_softpath_offset_curve_point_tmpa_fp
                } {
                    \l__hawkdraw_softpath_offset_curve_point_tmpc_fp
                } + 90
            }
        )
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_curve_point_tmpj_fp {
        ( \l__hawkdraw_softpath_offset_curve_point_tmpd_fp ) + (
            \draw_point_polar:nn {
                \l_hawkdraw_softpath_offset_dim
            } {
                \hawkdraw_calculate_slope:nn {
                    \l__hawkdraw_softpath_offset_curve_point_tmpc_fp
                } {
                    \l__hawkdraw_softpath_offset_curve_point_tmpe_fp
                } + 90
            }
        )
    }
   \fp_set:Nn \l__hawkdraw_softpath_offset_curve_point_tmpk_fp {
        ( \l__hawkdraw_softpath_offset_curve_point_tmpe_fp ) + (
            \draw_point_polar:nn {
                \l_hawkdraw_softpath_offset_dim
            } {
                \hawkdraw_calculate_slope:nn {
                    \l__hawkdraw_softpath_offset_curve_point_tmpd_fp
                } {
                    #3
                } + 90
            }
        )
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_curve_point_tmpl_fp {
        ( #3 ) + (
            \draw_point_polar:nn {
                \l_hawkdraw_softpath_offset_dim
            } {
                \hawkdraw_calculate_slope:nn {#2} {#3} + 90
            }
        )
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_curve_point_tmpi_fp {
        \draw_point_intersect_lines:nnnn {
            \l__hawkdraw_softpath_offset_curve_point_tmpg_fp
        } {
            \l__hawkdraw_softpath_offset_curve_point_tmph_fp
        } {
            \l__hawkdraw_softpath_offset_curve_point_tmpj_fp
        } {
            \l__hawkdraw_softpath_offset_curve_point_tmpk_fp
        }
    }

    \bool_if:NT \l__hawkdraw_softpath_offset_moveto_bool {
        \bool_set_false:N \l__hawkdraw_softpath_offset_moveto_bool
        \hawkdraw_softpath_update_moveto:n {
            \l__hawkdraw_softpath_offset_curve_point_tmpf_fp
        }
    }
    \fp_gset:Nn \g_hawkdraw_path_point_last_fp {
        ( #3 ) +
        \l__hawkdraw_softpath_offset_corner_offset_fp
    }
    \hawkdraw_softpath_update_curveto:nn {
        \l__hawkdraw_softpath_offset_curve_point_tmpg_fp
    } {
        \l__hawkdraw_softpath_offset_curve_point_tmph_fp
    }
    \hawkdraw_softpath_update_curveto:nn {
        \l__hawkdraw_softpath_offset_curve_point_tmpi_fp % <
    } {
        \l__hawkdraw_softpath_offset_curve_point_tmpj_fp
    }
    \hawkdraw_softpath_update_curveto:nn {
        \l__hawkdraw_softpath_offset_curve_point_tmpk_fp
    } {
        \g_hawkdraw_path_point_last_fp
    }
}

% a to j
\int_step_inline:nn { 10 } {
    \fp_new:c {
        l__hawkdraw_softpath_offset_arc_construct_point_ \int_to_alph:n {#1 } _fp
    }
}

% a to h
\int_step_inline:nn { 8 } {
    \fp_new:c {
        l__hawkdraw_softpath_offset_arc_construct_point_tmp \int_to_alph:n {#1 } _fp
    }
}

% we use the mechanism for cubic Béziers also for arcs and allipses
\cs_new_protected:Npn \__hawkdraw_softpath_offset_arc_construct_set_points:nnnn #1#2#3#4 {
    \fp_set:Nn \l__hawkdraw_softpath_offset_arc_construct_point_tmpa_fp {
        hawkdrawlerp ( ( #1 ) , ( #2 ) , 1/3 )
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_arc_construct_point_tmpb_fp {
        hawkdrawlerp (
            hawkdrawlerp ( ( #1 ) , ( #2 ) , 1/3 ) ,
            hawkdrawlerp ( ( #2 ) , ( #3 ) , 1/3 ) ,
            1/3
        )
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_arc_construct_point_tmpc_fp {
        hawkdrawlerp (
            hawkdrawlerp (
                hawkdrawlerp ( ( #1 ) , ( #2 ) , 1/3 ) ,
                hawkdrawlerp ( ( #2 ) , ( #3 ) , 1/3 ) ,
                1/3
            ) ,
            hawkdrawlerp (
                hawkdrawlerp ( ( #2 ) , ( #3 ) , 1/3 ) ,
                hawkdrawlerp ( ( #3 ) , ( #4 ) , 1/3 ) ,
                1/3
            ) ,
            1/3
        )
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_arc_construct_point_tmpd_fp {
        hawkdrawlerp (
            hawkdrawlerp (
                hawkdrawlerp ( ( #1 ) , ( #2 ) , 1/3 ) ,
                hawkdrawlerp ( ( #2 ) , ( #3 ) , 1/3 ) ,
                1/3
            ) ,
            hawkdrawlerp (
                hawkdrawlerp ( ( #2 ) , ( #3 ) , 1/3 ) ,
                hawkdrawlerp ( ( #3 ) , ( #4 ) , 1/3 ) ,
                1/3
            ) ,
            2/3
        )
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_arc_construct_point_tmpe_fp {
        hawkdrawlerp (
            hawkdrawlerp (
                hawkdrawlerp ( ( #1 ) , ( #2 ) , 1/3 ) ,
                hawkdrawlerp ( ( #2 ) , ( #3 ) , 1/3 ) ,
                2/3
            ) ,
            hawkdrawlerp (
                hawkdrawlerp ( ( #2 ) , ( #3 ) , 1/3 ) ,
                hawkdrawlerp ( ( #3 ) , ( #4 ) , 1/3 ) ,
                2/3
            ) ,
            2/3
        )
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_arc_construct_point_tmpf_fp {
        hawkdrawlerp (
            hawkdrawlerp (
                hawkdrawlerp ( ( #1 ) , ( #2 ) , 2/3 ) ,
                hawkdrawlerp ( ( #2 ) , ( #3 ) , 2/3 ) ,
                2/3
            ) ,
            hawkdrawlerp (
                hawkdrawlerp ( ( #2 ) , ( #3 ) , 2/3 ) ,
                hawkdrawlerp ( ( #3 ) , ( #4 ) , 2/3 ) ,
                2/3
            ) ,
            2/3
        )
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_arc_construct_point_tmpg_fp {
        hawkdrawlerp (
            hawkdrawlerp ( ( #2 ) , ( #3 ) , 2/3 ) ,
            hawkdrawlerp ( ( #3 ) , ( #4 ) , 2/3 ) ,
            2/3
        )
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_arc_construct_point_tmph_fp {
        hawkdrawlerp ( ( #3 ) , ( #4 ) , 2/3 )
    }

    \fp_set:Nn \l__hawkdraw_softpath_offset_arc_construct_point_a_fp {
        ( #1 ) + (
            \draw_point_polar:nn {
                \l_hawkdraw_softpath_offset_dim
            } {
                \hawkdraw_calculate_slope:nn {#1} {#2} + 90
            }
        )
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_arc_construct_point_b_fp {
        ( \l__hawkdraw_softpath_offset_arc_construct_point_tmpa_fp ) + (
            \draw_point_polar:nn {
                \l_hawkdraw_softpath_offset_dim
            } {
                \hawkdraw_calculate_slope:nn {#1} {
                    \l__hawkdraw_softpath_offset_arc_construct_point_tmpb_fp
                } + 90
            }
        )
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_arc_construct_point_c_fp {
        ( \l__hawkdraw_softpath_offset_arc_construct_point_tmpb_fp ) + (
            \draw_point_polar:nn {
                \l_hawkdraw_softpath_offset_dim
            } {
                \hawkdraw_calculate_slope:nn {
                    \l__hawkdraw_softpath_offset_arc_construct_point_tmpa_fp
                } {
                    \l__hawkdraw_softpath_offset_arc_construct_point_tmpc_fp
                } + 90
            }
        )
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_arc_construct_point_e_fp {
        ( \l__hawkdraw_softpath_offset_arc_construct_point_tmpd_fp ) + (
            \draw_point_polar:nn {
                \l_hawkdraw_softpath_offset_dim
            } {
                \hawkdraw_calculate_slope:nn {
                    \l__hawkdraw_softpath_offset_arc_construct_point_tmpc_fp
                } {
                    \l__hawkdraw_softpath_offset_arc_construct_point_tmpe_fp
                } + 90
            }
        )
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_arc_construct_point_f_fp {
        ( \l__hawkdraw_softpath_offset_arc_construct_point_tmpe_fp ) + (
            \draw_point_polar:nn {
                \l_hawkdraw_softpath_offset_dim
            } {
                \hawkdraw_calculate_slope:nn {
                    \l__hawkdraw_softpath_offset_arc_construct_point_tmpd_fp
                } {
                    \l__hawkdraw_softpath_offset_arc_construct_point_tmpf_fp
                } + 90
            }
        )
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_arc_construct_point_h_fp {
        ( \l__hawkdraw_softpath_offset_arc_construct_point_tmpg_fp ) + (
            \draw_point_polar:nn {
                \l_hawkdraw_softpath_offset_dim
            } {
                \hawkdraw_calculate_slope:nn {
                    \l__hawkdraw_softpath_offset_arc_construct_point_tmpf_fp
                } {
                    \l__hawkdraw_softpath_offset_arc_construct_point_tmph_fp
                } + 90
            }
        )
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_arc_construct_point_i_fp {
        ( \l__hawkdraw_softpath_offset_arc_construct_point_tmph_fp ) + (
            \draw_point_polar:nn {
                \l_hawkdraw_softpath_offset_dim
            } {
                \hawkdraw_calculate_slope:nn {
                    \l__hawkdraw_softpath_offset_arc_construct_point_tmpg_fp
                } {#4} + 90
            }
        )
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_arc_construct_point_j_fp {
        ( #4 ) + (
            \draw_point_polar:nn {
                \l_hawkdraw_softpath_offset_dim
            } {
                \hawkdraw_calculate_slope:nn {#3} {#4} + 90
            }
        )
    }

    \fp_set:Nn \l__hawkdraw_softpath_offset_arc_construct_point_d_fp {
        (
            ( \l__hawkdraw_softpath_offset_arc_construct_point_c_fp ) +
            ( \l__hawkdraw_softpath_offset_arc_construct_point_e_fp )
        ) / 2
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_arc_construct_point_g_fp {
        (
            ( \l__hawkdraw_softpath_offset_arc_construct_point_f_fp ) +
            ( \l__hawkdraw_softpath_offset_arc_construct_point_h_fp )
        ) / 2
    }
}

\cs_new_protected:Npn \__hawkdraw_softpath_offset_curve_cubic:nnnn #1#2#3#4 {
    \__hawkdraw_softpath_offset_arc_construct_set_points:nnnn {#1} {#2} {#3} {#4}

    \bool_if:NT \l__hawkdraw_softpath_offset_moveto_bool {
        \bool_set_false:N \l__hawkdraw_softpath_offset_moveto_bool
        \hawkdraw_softpath_update_moveto:n {
            \l__hawkdraw_softpath_offset_arc_construct_point_a_fp
        }
    }
    \fp_gset:Nn \g_hawkdraw_path_point_last_fp {
        ( #4 ) +
        \l__hawkdraw_softpath_offset_corner_offset_fp
    }
    \hawkdraw_softpath_update_curveto:nnn {
        \l__hawkdraw_softpath_offset_arc_construct_point_b_fp
    } {
        \l__hawkdraw_softpath_offset_arc_construct_point_c_fp
    } {
        \l__hawkdraw_softpath_offset_arc_construct_point_d_fp % <
    }
    \hawkdraw_softpath_update_curveto:nnn {
        \l__hawkdraw_softpath_offset_arc_construct_point_e_fp
    } {
        \l__hawkdraw_softpath_offset_arc_construct_point_f_fp
    } {
        \l__hawkdraw_softpath_offset_arc_construct_point_g_fp % <
    }
    \hawkdraw_softpath_update_curveto:nnn {
        \l__hawkdraw_softpath_offset_arc_construct_point_h_fp
    } {
        \l__hawkdraw_softpath_offset_arc_construct_point_i_fp
    } {
        \g_hawkdraw_path_point_last_fp
    }
}

\fp_new_function:n { hawkdrawbezierk }
\fp_set_function:nnn { hawkdrawbezierk } { a } {
    4 / 3 * tand( a / 4 )
}

\fp_new:N \l__hawkdraw_softpath_offset_arc_point_last_fp
\fp_new:N \l__hawkdraw_softpath_offset_arc_angle_tmpa_fp
\fp_new:N \l__hawkdraw_softpath_offset_arc_angle_tmpb_fp
\fp_new:N \l__hawkdraw_softpath_offset_arc_tveca_fp
\fp_new:N \l__hawkdraw_softpath_offset_arc_tvecb_fp

\cs_new_protected:Npn \__hawkdraw_softpath_offset_arc_construct: {
    \hawkdraw_softpath_update_curveto:nnn {
        \l__hawkdraw_softpath_offset_arc_construct_point_b_fp
    } {
        \l__hawkdraw_softpath_offset_arc_construct_point_c_fp
    } {
        \l__hawkdraw_softpath_offset_arc_construct_point_d_fp
    }
    \hawkdraw_softpath_update_curveto:nnn {
        \l__hawkdraw_softpath_offset_arc_construct_point_e_fp
    } {
        \l__hawkdraw_softpath_offset_arc_construct_point_f_fp
    } {
        \l__hawkdraw_softpath_offset_arc_construct_point_g_fp
    }
    \hawkdraw_softpath_update_curveto:nnn {
        \l__hawkdraw_softpath_offset_arc_construct_point_h_fp
    } {
        \l__hawkdraw_softpath_offset_arc_construct_point_i_fp
    } {
        \l__hawkdraw_softpath_offset_arc_construct_point_j_fp
    }
}

\cs_new_protected:Npn \hawkdraw_softpath_offset_arc_op:nnNnn #1#2#3#4#5 {
    \__hawkdraw_softpath_offset_get_slope_next:nnN {
        ( cosd(#5) ,  sind(#5) )
    } {
        \hawkdraw_softpath_offset_calculate_corner_offset:Nnnn
            \l__hawkdraw_softpath_offset_corner_offset_fp {
                \l_hawkdraw_softpath_offset_dim
            } {
                \__hawkdraw_point_part_slope_arc_axes:nnnnn
                    { 1 } { #1 , 0pt } { 0pt , #2 } {#4} {#5}
            } {
                \l_hawkdraw_softpath_offset_slope_next_fp
            }
        \__hawkdraw_softpath_offset_arc_axes:nnnn
            { #1 , 0pt } { 0pt , #2 } {#4} {#5}
    }
}

\cs_new_protected:Npn \hawkdraw_softpath_offset_arc_axes_op:nnNnnNnn #1#2#3#4#5#6#7#8 {
    \__hawkdraw_softpath_offset_get_slope_next:nnN {
        (
            \hawkdraw_tuple_use_i:n {#3} * cosd( #5 ) -
            \hawkdraw_tuple_use_i:n {#2} * sind( #5 )
        ,
            \hawkdraw_tuple_use_ii:n {#3} * cosd( #5 ) -
            \hawkdraw_tuple_use_ii:n {#2} * sind( #5 )
        )
    } {
        \hawkdraw_softpath_offset_calculate_corner_offset:Nnnn
            \l__hawkdraw_softpath_offset_corner_offset_fp {
                \l_hawkdraw_softpath_offset_dim
            } {
                \__hawkdraw_point_part_slope_arc_axes:nnnnn
                    { 1 } { #1 , #2 } { #4 , #5 } {#7} {#8}
            } {
                \l_hawkdraw_softpath_offset_slope_next_fp
            }
        \__hawkdraw_softpath_offset_arc_axes:nnnn
            { #1 , #2 } { #4 , #5 } {#7} {#8}
    }
}

\cs_new_protected:Npn \__hawkdraw_softpath_offset_arc_axes:nnnn #1#2#3#4 {
    \fp_set_eq:NN \l__hawkdraw_softpath_offset_arc_point_last_fp
        \l_hawkdraw_softpath_offset_point_last_fp
    % construct the path quarter-wise
    \fp_set:Nn \l__hawkdraw_softpath_offset_arc_angle_tmpa_fp {
        #3
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_arc_angle_tmpb_fp {
        min( #4 , #3 + 90 )
    }
    \__hawkdraw_softpath_offset_arc_axes_construct_quarter:nnnnn
        {#1} {#2} {
            \l_hawkdraw_softpath_offset_point_last_fp
        } {
            \l__hawkdraw_softpath_offset_arc_angle_tmpa_fp
        } {
            \l__hawkdraw_softpath_offset_arc_angle_tmpb_fp
        }
    \bool_if:NTF \l__hawkdraw_softpath_offset_moveto_bool {
        \bool_set_false:N \l__hawkdraw_softpath_offset_moveto_bool
        \hawkdraw_softpath_update_moveto:n {
            \l__hawkdraw_softpath_offset_arc_construct_point_a_fp
        }
    } {
        \fp_set_eq:NN \l__hawkdraw_softpath_offset_arc_construct_point_a_fp
            \g_hawkdraw_path_point_last_fp
        \hawkdraw_softpath_update_lineto:n {
            \l__hawkdraw_softpath_offset_arc_construct_point_a_fp
        }
    }
    \__hawkdraw_softpath_offset_arc_construct:
    \fp_compare:nNnT { #4 } > { #3 + 90 } {
        \fp_set:Nn \l__hawkdraw_softpath_offset_arc_angle_tmpa_fp {
            #3 + 90
        }
        \fp_set:Nn \l__hawkdraw_softpath_offset_arc_angle_tmpb_fp {
            min( #4 , #3 + 180 )
        }
        \__hawkdraw_softpath_offset_arc_axes_construct_quarter:nnnnn
            {#1} {#2} {
                \l__hawkdraw_softpath_offset_arc_point_last_fp
            } {
                \l__hawkdraw_softpath_offset_arc_angle_tmpa_fp
            } {
                \l__hawkdraw_softpath_offset_arc_angle_tmpb_fp
            }
        \__hawkdraw_softpath_offset_arc_construct:
    }
    \fp_compare:nNnT { #4 } > { #3 + 180 } {
        \fp_set:Nn \l__hawkdraw_softpath_offset_arc_angle_tmpa_fp {
            #3 + 180
        }
        \fp_set:Nn \l__hawkdraw_softpath_offset_arc_angle_tmpb_fp {
            min( #4 , #3 + 270 )
        }
        \__hawkdraw_softpath_offset_arc_axes_construct_quarter:nnnnn
            {#1} {#2} {
                \l__hawkdraw_softpath_offset_arc_point_last_fp
            } {
                \l__hawkdraw_softpath_offset_arc_angle_tmpa_fp
            } {
                \l__hawkdraw_softpath_offset_arc_angle_tmpb_fp
            }
        \__hawkdraw_softpath_offset_arc_construct:
    }
    \fp_compare:nNnT { #4 } > { #3 + 270 } {
        \fp_set:Nn \l__hawkdraw_softpath_offset_arc_angle_tmpa_fp {
            #3 + 270
        }
        \fp_set:Nn \l__hawkdraw_softpath_offset_arc_angle_tmpb_fp {
            #4
        }
        \__hawkdraw_softpath_offset_arc_axes_construct_quarter:nnnnn
            {#1} {#2} {
                \l__hawkdraw_softpath_offset_arc_point_last_fp
            } {
                \l__hawkdraw_softpath_offset_arc_angle_tmpa_fp
            } {
                \l__hawkdraw_softpath_offset_arc_angle_tmpb_fp
            }
        \__hawkdraw_softpath_offset_arc_construct:
    }
    \hawkdraw_softpath_update_lineto:n {
        \l__hawkdraw_softpath_offset_arc_point_last_fp +
        \l__hawkdraw_softpath_offset_corner_offset_fp
    }
    \fp_set:Nn \l_hawkdraw_softpath_offset_point_last_fp {
        \l__hawkdraw_softpath_offset_arc_point_last_fp +
        \l__hawkdraw_softpath_offset_corner_offset_fp
    }
}

\cs_new_protected:Npn \__hawkdraw_softpath_offset_arc_axes_construct_quarter:nnnnn #1#2#3#4#5 {
    % compute the endpoints
    \fp_set:Nn \l__hawkdraw_softpath_offset_arc_point_tmpa_fp {
        \__hawkdraw_point_part_arc_axes:nnnnnn
            { 0 } {#3} {#1} {#2} {#4} {#5}
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_arc_point_tmpd_fp {
        \__hawkdraw_point_part_arc_axes:nnnnnn
            { 1 } {#3} {#1} {#2} {#4} {#5}
    }
    % compute the tangent vectors
    \fp_set:Nn \l__hawkdraw_softpath_offset_arc_tveca_fp {
        ( #2 ) * cosd( #4 ) - ( #1 ) * sind( #4 )
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_arc_tvecb_fp {
        ( #2 ) * cosd( #5 ) - ( #1 ) * sind( #5 )
    }
    % compute the control points
    \fp_set:Nn \l__hawkdraw_softpath_offset_arc_point_tmpb_fp {
        \l__hawkdraw_softpath_offset_arc_point_tmpa_fp +
        hawkdrawbezierk( #5 - #4 ) *
        \l__hawkdraw_softpath_offset_arc_tveca_fp
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_arc_point_tmpc_fp {
        \l__hawkdraw_softpath_offset_arc_point_tmpd_fp -
        hawkdrawbezierk( #5 - #4 ) *
        \l__hawkdraw_softpath_offset_arc_tvecb_fp
    }

    \fp_set_eq:NN \l__hawkdraw_softpath_offset_arc_point_last_fp
        \l__hawkdraw_softpath_offset_arc_point_tmpd_fp

    \__hawkdraw_softpath_offset_arc_construct_set_points:nnnn {
        \l__hawkdraw_softpath_offset_arc_point_tmpa_fp
    } {
        \l__hawkdraw_softpath_offset_arc_point_tmpb_fp
    } {
        \l__hawkdraw_softpath_offset_arc_point_tmpc_fp
    } {
        \l__hawkdraw_softpath_offset_arc_point_tmpd_fp
    }
}

\cs_new_protected:Npn \hawkdraw_softpath_offset_circle_op:nnNnn #1#2#3#4#5 {
    \hawkdraw_softpath_update_circle:nn {
        #1 , #2
    } {
        #4 + \l_hawkdraw_softpath_offset_dim
    }
}

% a to l
\int_step_inline:nn { 12 } {
    \fp_new:c {
        l__hawkdraw_softpath_offset_ellipse_point_tmp \int_to_alph:n {#1 } _fp
    }
}

\cs_new_protected:Npn \hawkdraw_softpath_offset_ellipse_op:nnNnnNnn #1#2#3#4#5#6#7#8 {
    \hawkdraw_softpath_offset_ellipse:nnn { #1 , #2 } { #4 , #5 } { #7 , #8 }
}

\cs_new_protected:Npn \hawkdraw_softpath_offset_ellipse:nnn #1#2#3 {
    \fp_set:Nn \l__hawkdraw_softpath_offset_ellipse_point_tmpa_fp {
        ( #1 ) + ( #2 )
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_ellipse_point_tmpb_fp {
        ( #1 ) +
        ( #2 ) +
        hawkdrawbezierk(90) * ( #3 )
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_ellipse_point_tmpc_fp {
        ( #1 ) +
        hawkdrawbezierk(90) * ( #2 ) +
        ( #3 )
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_ellipse_point_tmpd_fp {
        ( #1 ) + ( #3 )
    }

    \fp_set:Nn \l__hawkdraw_softpath_offset_ellipse_point_tmpe_fp {
        ( #1 ) -
        hawkdrawbezierk(90) * ( #2 ) +
        ( #3 )
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_ellipse_point_tmpf_fp {
        ( #1 ) -
        ( #2 ) +
        hawkdrawbezierk(90) * ( #3 )
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_ellipse_point_tmpg_fp {
        ( #1 ) - ( #2 )
    }

    \fp_set:Nn \l__hawkdraw_softpath_offset_ellipse_point_tmph_fp {
        ( #1 ) -
        ( #2 ) -
        hawkdrawbezierk(90) * ( #3 )
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_ellipse_point_tmpi_fp {
        ( #1 ) -
        hawkdrawbezierk(90) * ( #2 ) -
        ( #3 )
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_ellipse_point_tmpj_fp {
        ( #1 ) - ( #3 )
    }

    \fp_set:Nn \l__hawkdraw_softpath_offset_ellipse_point_tmpk_fp {
        ( #1 ) +
        hawkdrawbezierk(90) * ( #2 ) -
        ( #3 )
    }
    \fp_set:Nn \l__hawkdraw_softpath_offset_ellipse_point_tmpl_fp {
        ( #1 ) +
        ( #2 ) -
        hawkdrawbezierk(90) * ( #3 )
    }

    \__hawkdraw_softpath_offset_arc_construct_set_points:nnnn {
        \l__hawkdraw_softpath_offset_ellipse_point_tmpa_fp
    } {
        \l__hawkdraw_softpath_offset_ellipse_point_tmpb_fp
    } {
        \l__hawkdraw_softpath_offset_ellipse_point_tmpc_fp
    } {
        \l__hawkdraw_softpath_offset_ellipse_point_tmpd_fp
    }
    \hawkdraw_softpath_update_moveto:n {
        \l__hawkdraw_softpath_offset_arc_construct_point_a_fp
    }
    \__hawkdraw_softpath_offset_arc_construct:

    \__hawkdraw_softpath_offset_arc_construct_set_points:nnnn {
        \l__hawkdraw_softpath_offset_ellipse_point_tmpd_fp
    } {
        \l__hawkdraw_softpath_offset_ellipse_point_tmpe_fp
    } {
        \l__hawkdraw_softpath_offset_ellipse_point_tmpf_fp
    } {
        \l__hawkdraw_softpath_offset_ellipse_point_tmpg_fp
    }
    \__hawkdraw_softpath_offset_arc_construct:

    \__hawkdraw_softpath_offset_arc_construct_set_points:nnnn {
        \l__hawkdraw_softpath_offset_ellipse_point_tmpg_fp
    } {
        \l__hawkdraw_softpath_offset_ellipse_point_tmph_fp
    } {
        \l__hawkdraw_softpath_offset_ellipse_point_tmpi_fp
    } {
        \l__hawkdraw_softpath_offset_ellipse_point_tmpj_fp
    }
    \__hawkdraw_softpath_offset_arc_construct:

    \__hawkdraw_softpath_offset_arc_construct_set_points:nnnn {
        \l__hawkdraw_softpath_offset_ellipse_point_tmpj_fp
    } {
        \l__hawkdraw_softpath_offset_ellipse_point_tmpk_fp
    } {
        \l__hawkdraw_softpath_offset_ellipse_point_tmpl_fp
    } {
        \l__hawkdraw_softpath_offset_ellipse_point_tmpa_fp
    }
    \__hawkdraw_softpath_offset_arc_construct:
    \hawkdraw_softpath_update_close:n {
        \l__hawkdraw_softpath_offset_arc_construct_point_a_fp
    }
}

\cs_new_protected:Npn \hawkdraw_softpath_offset_rectangle_op:nnNnn #1#2#3#4#5 {
    \hawkdraw_softpath_update_rectangle:nn {
        #1 - \l_hawkdraw_softpath_offset_dim ,
        #2 - \l_hawkdraw_softpath_offset_dim
    } {
        #4 + 2 * \l_hawkdraw_softpath_offset_dim ,
        #5 + 2 * \l_hawkdraw_softpath_offset_dim
    }
}

\cs_new_protected:Npn \hawkdraw_softpath_offset_grid_op:nnNnnNnn #1#2#3#4#5#6#7#8 {
    \hawkdraw_softpath_update_grid:nnnn {
        #1
    } {
        #2
    } {
        #4 - \l_hawkdraw_softpath_offset_dim ,
        #5 - \l_hawkdraw_softpath_offset_dim
    } {
        #7 + 2 * \l_hawkdraw_softpath_offset_dim ,
        #8 + 2 * \l_hawkdraw_softpath_offset_dim
    }
}

\cs_new_protected:Npn \hawkdraw_softpath_offset_close_op:nn #1#2 {
    \hawkdraw_softpath_add:NNnn
        \l__hawkdraw_softpath_updated_tl
        \hawkdraw_softpath_close_op:nn {#1} {#2}
}

% EOF