% 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.1 2026-06-24 \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:Ne #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:Ne #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:Ne #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:Ne #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 \bool_new:N \l_hawkdraw_softpath_keep_original_path_info_bool \fp_new:N \l__hawkdraw_softpath_point_first_original_fp \fp_new:N \l__hawkdraw_softpath_point_last_original_fp \fp_new:N \l__hawkdraw_softpath_slope_first_original_fp \fp_new:N \l__hawkdraw_softpath_slope_last_original_fp \scan_new:N \s__hawkdraw_softpath_end \keys_define:nn { hawkdraw / path } { keep ~ original ~ path ~ info .bool_set:N = \l_hawkdraw_softpath_keep_original_path_info_bool , keep ~ original ~ path ~ info .default:n = { true } , keep ~ original ~ path ~ info .initial:n = { false } , } \cs_new_protected:Npn \hawkdraw_softpath_update:Nn #1#2 { \fp_set_eq:NN \l__hawkdraw_softpath_point_first_original_fp \g_hawkdraw_path_point_first_fp \fp_set_eq:NN \l__hawkdraw_softpath_point_last_original_fp \g_hawkdraw_path_point_last_fp \fp_set_eq:NN \l__hawkdraw_softpath_slope_first_original_fp \g_hawkdraw_path_slope_first_fp \fp_set_eq:NN \l__hawkdraw_softpath_slope_last_original_fp \g_hawkdraw_path_slope_last_fp \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_put_right:Nn \l__hawkdraw_softpath_updated_tl { \s__hawkdraw_softpath_end } \tl_build_end:N \l__hawkdraw_softpath_updated_tl \tl_gset_eq:NN #1 \l__hawkdraw_softpath_updated_tl \group_end: } \bool_if:NT \l_hawkdraw_softpath_keep_original_path_info_bool { \fp_gset_eq:NN \g_hawkdraw_path_point_first_fp \l__hawkdraw_softpath_point_first_original_fp \fp_gset_eq:NN \g_hawkdraw_path_point_last_fp \l__hawkdraw_softpath_point_last_original_fp \fp_gset_eq:NN \g_hawkdraw_path_slope_first_fp \l__hawkdraw_softpath_slope_first_original_fp \fp_gset_eq:NN \g_hawkdraw_path_slope_last_fp \l__hawkdraw_softpath_slope_last_original_fp } } \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 % === \clist_new:N \l_hawkdraw_softpath_offset_clist \dim_new:N \l_hawkdraw_softpath_offset_dim \tl_new:N \l_hawkdraw_softpath_offset_updated_tl \tl_new:N \l_hawkdraw_softpath_offset_collect_tl \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_point_previous_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 \clist_set:Nn \l_hawkdraw_softpath_offset_clist {#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 } } \clist_map_inline:Nn \l_hawkdraw_softpath_offset_clist { \dim_set:Nn \l_hawkdraw_softpath_offset_dim {##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#2#3 {#4} {#5} } \cs_new:Npn \hawkdraw_softpath_offset_calculate_corner_offset:nnn #1#2#3 { \fp_if_nan:nTF {#3} { ( \draw_point_polar:nn {#1} { #2 + 90 } ) } { \fp_compare:nNnTF {#3} = {#2} { ( \draw_point_polar:nn {#1} { #2 + 90 } ) } { ( \draw_point_polar:nn { #1 / cosd( ( #3 - #2 ) / 2 ) } { #3 - ( #3 - #2 ) / 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_point_previous_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 { \fp_set:Nn \l__hawkdraw_softpath_offset_corner_offset_fp { \hawkdraw_softpath_offset_calculate_corner_offset:nnn { \l_hawkdraw_softpath_offset_dim } { \hawkdraw_calculate_slope:nn { \l_hawkdraw_softpath_offset_point_previous_fp } {#1} } { \l_hawkdraw_softpath_offset_slope_next_fp } } \fp_set:Nn \l_hawkdraw_softpath_offset_point_previous_fp {#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 } } \fp_set:Nn \l_hawkdraw_softpath_offset_point_last_fp { \l_hawkdraw_softpath_offset_point_previous_fp + \l__hawkdraw_softpath_offset_corner_offset_fp } \hawkdraw_softpath_update_lineto:n { \l_hawkdraw_softpath_offset_point_last_fp } \fp_gset_eq:NN \g_hawkdraw_path_point_last_fp \l_hawkdraw_softpath_offset_point_last_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 } } { \tl_if_empty:nTF {#7} { \hawkdraw_softpath_offset_curveto:nnn { #1 , #2 } { #4 , #5 } { } } { \hawkdraw_softpath_offset_curveto:nnn { #1 , #2 } { #4 , #5 } { #7 , #8 } } } } \cs_new_protected:Npn \hawkdraw_softpath_offset_curveto:nnn #1#2#3 { \fp_set:Nn \l__hawkdraw_softpath_offset_corner_offset_fp { \hawkdraw_softpath_offset_calculate_corner_offset:nnn { \l_hawkdraw_softpath_offset_dim } { \tl_if_empty:nTF {#3} { \hawkdraw_calculate_slope:nn {#1} {#2} } { \hawkdraw_calculate_slope:nn {#2} {#3} } } { \l_hawkdraw_softpath_offset_slope_next_fp } } \tl_if_empty:nTF {#3} { \__hawkdraw_softpath_offset_curve_quadratic:nnn { \l_hawkdraw_softpath_offset_point_previous_fp } {#1} {#2} \fp_set:Nn \l_hawkdraw_softpath_offset_point_previous_fp {#2} } { \__hawkdraw_softpath_offset_curve_cubic:nnnn { \l_hawkdraw_softpath_offset_point_previous_fp } {#1} {#2} {#3} \fp_set:Nn \l_hawkdraw_softpath_offset_point_previous_fp {#3} } \fp_set:Nn \l_hawkdraw_softpath_offset_point_last_fp { \l_hawkdraw_softpath_offset_point_previous_fp + \l__hawkdraw_softpath_offset_corner_offset_fp } \fp_gset_eq:NN \g_hawkdraw_path_point_last_fp \l_hawkdraw_softpath_offset_point_last_fp } % we use the same split mechanism for cubic and quadratic Béziers, as well as for arcs and allipses \seq_new:N \l_hawkdraw_softpath_offset_construct_cubic_segments_seq \tl_new:N \l__hawkdraw_softpath_offset_construct_cubic_previous_tl \fp_new:N \l__hawkdraw_softpath_offset_construct_cubic_ta_fp \fp_new:N \l__hawkdraw_softpath_offset_construct_cubic_tb_fp \fp_new:N \l__hawkdraw_softpath_offset_construct_cubic_tc_fp % tmpa to tmpg \int_step_inline:nn { 7 } { \fp_new:c { l__hawkdraw_softpath_offset_construct_cubic_point_tmp \int_to_alph:n {#1 } _fp } } \cs_new_protected:Npn \__hawkdraw_softpath_offset_construct_cubic_split:nnnnn #1#2#3#4#5 { \fp_set:Nn \l__hawkdraw_softpath_offset_construct_cubic_point_tmpa_fp { ( #2 ) } \fp_set:Nn \l__hawkdraw_softpath_offset_construct_cubic_point_tmpb_fp { % lerp(p0, p1, t); hawkdrawlerp ( ( #2 ) , ( #3 ) , ( #1 ) ) } \fp_set:Nn \l__hawkdraw_softpath_offset_construct_cubic_point_tmpc_fp { % lerp( lerp(p0, p1, t) , lerp(p1, p2, t) , t); hawkdrawlerp ( hawkdrawlerp ( ( #2 ) , ( #3 ) , ( #1 ) ) , hawkdrawlerp ( ( #3 ) , ( #4 ) , ( #1 ) ) , ( #1 ) ) } \fp_set:Nn \l__hawkdraw_softpath_offset_construct_cubic_point_tmpd_fp { % lerp( % lerp( lerp(p0, p1, t) , lerp(p1, p2, t) , t) , % lerp( lerp(p1, p2, t) , lerp(p2, p3, t) , t) % t); hawkdrawlerp ( hawkdrawlerp ( hawkdrawlerp ( ( #2 ) , ( #3 ) , ( #1 ) ) , hawkdrawlerp ( ( #3 ) , ( #4 ) , ( #1 ) ) , ( #1 ) ) , hawkdrawlerp ( hawkdrawlerp ( ( #3 ) , ( #4 ) , ( #1 ) ) , hawkdrawlerp ( ( #4 ) , ( #5 ) , ( #1 ) ) , ( #1 ) ) , ( #1 ) ) } \fp_set:Nn \l__hawkdraw_softpath_offset_construct_cubic_point_tmpe_fp { % lerp( lerp(p1, p2, t) , lerp(p2, p3, t) , t); hawkdrawlerp ( hawkdrawlerp ( ( #3 ) , ( #4 ) , ( #1 ) ) , hawkdrawlerp ( ( #4 ) , ( #5 ) , ( #1 ) ) , ( #1 ) ) } \fp_set:Nn \l__hawkdraw_softpath_offset_construct_cubic_point_tmpf_fp { % lerp(p2, p3, t); hawkdrawlerp ( ( #4 ) , ( #5 ) , ( #1 ) ) } \fp_set:Nn \l__hawkdraw_softpath_offset_construct_cubic_point_tmpg_fp { ( #5 ) } \tl_set:Nn \l__hawkdraw_softpath_offset_construct_cubic_curve_i_tl { { \l__hawkdraw_softpath_offset_construct_cubic_point_tmpa_fp } { \l__hawkdraw_softpath_offset_construct_cubic_point_tmpb_fp } { \l__hawkdraw_softpath_offset_construct_cubic_point_tmpc_fp } { \l__hawkdraw_softpath_offset_construct_cubic_point_tmpd_fp } } \tl_set:Nn \l__hawkdraw_softpath_offset_construct_cubic_curve_ii_tl { { \l__hawkdraw_softpath_offset_construct_cubic_point_tmpd_fp } { \l__hawkdraw_softpath_offset_construct_cubic_point_tmpe_fp } { \l__hawkdraw_softpath_offset_construct_cubic_point_tmpf_fp } { \l__hawkdraw_softpath_offset_construct_cubic_point_tmpg_fp } } } \cs_new:Npn \__hawkdraw_softpath_offset_construct_cubic_offset:N #1 { { \fp_eval:n { ( \tl_item:Nn #1 { 1 } ) + ( \draw_point_polar:nn { \l_hawkdraw_softpath_offset_dim } { \hawkdraw_calculate_slope:nn { \tl_item:Nn #1 { 1 } } { \tl_item:Nn #1 { 2 } } + 90 } ) } } { \fp_eval:n { ( \tl_item:Nn #1 { 2 } ) + ( \draw_point_polar:nn { \l_hawkdraw_softpath_offset_dim } { \hawkdraw_calculate_slope:nn { \tl_item:Nn #1 { 2 } } { \tl_item:Nn #1 { 3 } } + 90 } ) } } { \fp_eval:n { ( \tl_item:Nn #1 { 3 } ) + ( \draw_point_polar:nn { \l_hawkdraw_softpath_offset_dim } { \hawkdraw_calculate_slope:nn { \tl_item:Nn #1 { 2 } } { \tl_item:Nn #1 { 3 } } + 90 } ) } } { \fp_eval:n { ( \tl_item:Nn #1 { 4 } ) + ( \draw_point_polar:nn { \l_hawkdraw_softpath_offset_dim } { \hawkdraw_calculate_slope:nn { \tl_item:Nn #1 { 3 } } { \tl_item:Nn #1 { 4 } } + 90 } ) } } } \tl_new:N \l__hawkdraw_softpath_offset_construct_cubic_curve_i_tl \tl_new:N \l__hawkdraw_softpath_offset_construct_cubic_curve_ii_tl \cs_generate_variant:Nn \seq_set_item:Nnn { Nne } \cs_new_protected:Npn \hawkdraw_softpath_offset_construct_cubic_set_split:Nnnnnn #1#2#3#4#5#6 { \seq_clear:N #1 \tl_set:Nn \l__hawkdraw_softpath_offset_construct_cubic_previous_tl { {#3} {#4} {#5} {#6} } \fp_set:Nn \l__hawkdraw_softpath_offset_construct_cubic_ta_fp { 0 } \int_step_inline:nn {#2} { \fp_set:Nn \l__hawkdraw_softpath_offset_construct_cubic_tb_fp { ##1 / #2 } \fp_set:Nn \l__hawkdraw_softpath_offset_construct_cubic_tc_fp { hawkdrawremapt ( \l__hawkdraw_softpath_offset_construct_cubic_ta_fp , \l__hawkdraw_softpath_offset_construct_cubic_tb_fp ) } \exp_last_unbraced:Nno \__hawkdraw_softpath_offset_construct_cubic_split:nnnnn { \l__hawkdraw_softpath_offset_construct_cubic_tc_fp } { \l__hawkdraw_softpath_offset_construct_cubic_previous_tl } \seq_put_right:Ne #1 { \__hawkdraw_softpath_offset_construct_cubic_offset:N \l__hawkdraw_softpath_offset_construct_cubic_curve_i_tl } \tl_set_eq:NN \l__hawkdraw_softpath_offset_construct_cubic_previous_tl \l__hawkdraw_softpath_offset_construct_cubic_curve_ii_tl \fp_set_eq:NN \l__hawkdraw_softpath_offset_construct_cubic_ta_fp \l__hawkdraw_softpath_offset_construct_cubic_tb_fp } % smoothen segment convergence \int_compare:nNnT { \seq_count:N #1 } > { 1 } { \int_step_inline:nnn { 2 } { \seq_count:N #1 } { \tl_set:Ne \l__hawkdraw_softpath_offset_construct_cubic_curve_i_tl { \seq_item:Nn #1 { ##1 - 1 } } \tl_set:Ne \l__hawkdraw_softpath_offset_construct_cubic_curve_ii_tl { \seq_item:Nn #1 {##1} } \seq_set_item:Nne #1 { ##1 - 1 } { { \tl_item:Nn \l__hawkdraw_softpath_offset_construct_cubic_curve_i_tl { 1 } } { \tl_item:Nn \l__hawkdraw_softpath_offset_construct_cubic_curve_i_tl { 2 } } { \tl_item:Nn \l__hawkdraw_softpath_offset_construct_cubic_curve_i_tl { 3 } } { \fp_eval:n { ( \tl_item:Nn \l__hawkdraw_softpath_offset_construct_cubic_curve_i_tl { 3 } + \tl_item:Nn \l__hawkdraw_softpath_offset_construct_cubic_curve_ii_tl { 2 } ) / 2 } } } \seq_set_item:Nne #1 {##1} { { \fp_eval:n { ( \tl_item:Nn \l__hawkdraw_softpath_offset_construct_cubic_curve_i_tl { 3 } + \tl_item:Nn \l__hawkdraw_softpath_offset_construct_cubic_curve_ii_tl { 2 } ) / 2 } } { \tl_item:Nn \l__hawkdraw_softpath_offset_construct_cubic_curve_ii_tl { 2 } } { \tl_item:Nn \l__hawkdraw_softpath_offset_construct_cubic_curve_ii_tl { 3 } } { \tl_item:Nn \l__hawkdraw_softpath_offset_construct_cubic_curve_ii_tl { 4 } } } } } } \int_new:N \l_hawkdraw_softpath_bisection_count_int \keys_define:nn { hawkdraw / settings } { bisection ~ count .int_set:N = \l_hawkdraw_softpath_bisection_count_int , bisection ~ count .initial:n = { 3 } , } \cs_new_protected:Npn \__hawkdraw_softpath_offset_curve_quadratic:nnn #1#2#3 { \hawkdraw_softpath_offset_construct_cubic_set_split:Nnnnnn \l_hawkdraw_softpath_offset_construct_cubic_segments_seq { \l_hawkdraw_softpath_bisection_count_int } { #1 } { ( #1 ) + 2/3 * ( ( #2 ) - ( #1 ) ) } { ( #3 ) + 2/3 * ( ( #2 ) - ( #3 ) ) } { #3 } \seq_map_indexed_inline:Nn \l_hawkdraw_softpath_offset_construct_cubic_segments_seq { \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 { \tl_item:nn {##2} { 1 } } \hawkdraw_softpath_update_moveto:n { \g_hawkdraw_path_point_first_fp } } \hawkdraw_softpath_update_curveto:nnn { \tl_item:nn {##2} { 2 } } { \tl_item:nn {##2} { 3 } } { \int_compare:nNnTF {##1} = { \l_hawkdraw_softpath_bisection_count_int } { ( #3 ) + \l__hawkdraw_softpath_offset_corner_offset_fp } { \tl_item:nn {##2} { 4 } } } } } \cs_new_protected:Npn \__hawkdraw_softpath_offset_curve_cubic:nnnn #1#2#3#4 { \hawkdraw_softpath_offset_construct_cubic_set_split:Nnnnnn \l_hawkdraw_softpath_offset_construct_cubic_segments_seq { \l_hawkdraw_softpath_bisection_count_int } { #1 } { #2 } { #3 } { #4 } \seq_map_indexed_inline:Nn \l_hawkdraw_softpath_offset_construct_cubic_segments_seq { \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 { \tl_item:nn {##2} { 1 } } \hawkdraw_softpath_update_moveto:n { \g_hawkdraw_path_point_first_fp } } \hawkdraw_softpath_update_curveto:nnn { \tl_item:nn {##2} { 2 } } { \tl_item:nn {##2} { 3 } } { \int_compare:nNnTF {##1} = { \l_hawkdraw_softpath_bisection_count_int } { ( #4 ) + \l__hawkdraw_softpath_offset_corner_offset_fp } { \tl_item:nn {##2} { 4 } } } } } \cs_new_protected:Npn \hawkdraw_softpath_offset_arc_op:nnNnn #1#2#3#4#5 { \__hawkdraw_softpath_offset_get_slope_next:nnN { \__hawkdraw_point_part_arc:nnnnnn { 1 } { \l_hawkdraw_softpath_offset_point_previous_fp } {#1} {#2} {#4} {#5} } { \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_point_part_arc_axes:nnnnnn { 1 } { \l_hawkdraw_softpath_offset_point_previous_fp } { #1 , #2 } { #4 , #5 } {#7} {#8} } { \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:Nn \l__hawkdraw_softpath_offset_corner_offset_fp { \hawkdraw_softpath_offset_calculate_corner_offset:nnn { \l_hawkdraw_softpath_offset_dim } { \__hawkdraw_point_part_slope_arc_axes:nnnnn { 1 } {#1} {#2} {#3} {#4} } { \l_hawkdraw_softpath_offset_slope_next_fp } } \__hawkdraw_softpath_offset_arc_axes:nnnn {#1} {#2} {#3} {#4} } \fp_new_function:n { hawkdrawbezierk } \fp_set_function:nnn { hawkdrawbezierk } { a } { 4 / 3 * tand( a / 4 ) } \bool_new:N \l__hawkdraw_softpath_offset_arc_start_bool \fp_new:N \l__hawkdraw_softpath_offset_arc_point_last_fp \cs_new_protected:Npn \__hawkdraw_softpath_offset_construct_cubic_from_arc:nnnnn #1#2#3#4#5 { \hawkdraw_softpath_offset_construct_cubic_set_split:Nnnnnn \l_hawkdraw_softpath_offset_construct_cubic_segments_seq { \l_hawkdraw_softpath_bisection_count_int } { \__hawkdraw_point_part_arc_axes:nnnnnn { 0 } {#3} {#1} {#2} {#4} {#5} } { ( \__hawkdraw_point_part_arc_axes:nnnnnn { 0 } {#3} {#1} {#2} {#4} {#5} ) + hawkdrawbezierk( #5 - #4 ) * ( ( #2 ) * cosd( #4 ) - ( #1 ) * sind( #4 ) ) } { ( \__hawkdraw_point_part_arc_axes:nnnnnn { 1 } {#3} {#1} {#2} {#4} {#5} ) - hawkdrawbezierk( #5 - #4 ) * ( ( #2 ) * cosd( #5 ) - ( #1 ) * sind( #5 ) ) } { \__hawkdraw_point_part_arc_axes:nnnnnn { 1 } {#3} {#1} {#2} {#4} {#5} } \seq_map_indexed_inline:Nn \l_hawkdraw_softpath_offset_construct_cubic_segments_seq { \int_compare:nNnT {##1} = { 1 } { \bool_if:NTF \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 { \tl_item:nn {##2} { 1 } } \hawkdraw_softpath_update_moveto:n { \g_hawkdraw_path_point_first_fp } } { \bool_if:NT \l__hawkdraw_softpath_offset_arc_start_bool { \bool_set_false:N \l__hawkdraw_softpath_offset_arc_start_bool \hawkdraw_softpath_update_lineto:n { \tl_item:nn {##2} { 1 } } } } } \hawkdraw_softpath_update_curveto:nnn { \tl_item:nn {##2} { 2 } } { \tl_item:nn {##2} { 3 } } { \tl_item:nn {##2} { 4 } } } \fp_set:Nn \l__hawkdraw_softpath_offset_arc_point_last_fp { \__hawkdraw_point_part_arc_axes:nnnnnn { 1 } {#3} {#1} {#2} {#4} {#5} } } \cs_new_protected:Npn \__hawkdraw_softpath_offset_arc_axes:nnnn #1#2#3#4 { \fp_set:Nn \l__hawkdraw_softpath_offset_arc_point_last_fp { \__hawkdraw_point_part_arc_axes:nnnnnn { 0 } { \l_hawkdraw_softpath_offset_point_previous_fp } {#1} {#2} {#3} {#4} } \bool_set_true:N \l__hawkdraw_softpath_offset_arc_start_bool \__hawkdraw_softpath_offset_construct_cubic_from_arc:nnnnn { #1 } { #2 } { \l__hawkdraw_softpath_offset_arc_point_last_fp } { \fp_eval:n { #3 } } { \fp_eval:n { min( #4 , #3 + 90 ) } } \fp_compare:nNnT { #4 } > { #3 + 90 } { \__hawkdraw_softpath_offset_construct_cubic_from_arc:nnnnn { #1 } { #2 } { \l__hawkdraw_softpath_offset_arc_point_last_fp } { \fp_eval:n { #3 + 90 } } { \fp_eval:n { min( #4 , #3 + 180 ) } } } \fp_compare:nNnT { #4 } > { #3 + 180 } { \__hawkdraw_softpath_offset_construct_cubic_from_arc:nnnnn { #1 } { #2 } { \l__hawkdraw_softpath_offset_arc_point_last_fp } { \fp_eval:n { #3 + 180 } } { \fp_eval:n { min( #4 , #3 + 270 ) } } } \bool_set_true:N \l__hawkdraw_softpath_offset_arc_end_bool \fp_compare:nNnT { #4 } > { #3 + 270 } { \__hawkdraw_softpath_offset_construct_cubic_from_arc:nnnnn { #1 } { #2 } { \l__hawkdraw_softpath_offset_arc_point_last_fp } { \fp_eval:n { #3 + 270 } } { \fp_eval:n { #4 } } } \fp_set:Nn \l_hawkdraw_softpath_offset_point_previous_fp { \l__hawkdraw_softpath_offset_arc_point_last_fp } \fp_set:Nn \l_hawkdraw_softpath_offset_point_last_fp { \l_hawkdraw_softpath_offset_point_previous_fp + \l__hawkdraw_softpath_offset_corner_offset_fp } \hawkdraw_softpath_update_lineto:n { \l_hawkdraw_softpath_offset_point_last_fp } \fp_gset_eq:NN \g_hawkdraw_path_point_last_fp \l_hawkdraw_softpath_offset_point_last_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 } } \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_arc_point_last_fp { \__hawkdraw_point_part_ellipse:nnnn { 0 } {#1} {#2} {#3} } \int_step_inline:nn { 4 } { \__hawkdraw_softpath_offset_construct_cubic_from_arc:nnnnn { #2 } { #3 } { \l__hawkdraw_softpath_offset_arc_point_last_fp } { \fp_eval:n { ( ##1 - 1 ) * 90 } } { \fp_eval:n { ##1 * 90 } } } \hawkdraw_softpath_update_close:n { \l__hawkdraw_softpath_offset_arc_point_last_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