%% %% This is file `hobby.code.tex', %% generated with the docstrip utility. %% %% The original source files were: %% %% hobby_code.dtx (with options: `hobby') %% ---------------------------------------------------------------- %% hobby --- a TikZ/PGF library for drawing smooth(ish) curves using %% Hobby's algorithm (implemented in LaTeX3) %% E-mail: loopspace@mathforge.org %% Released under the LaTeX Project Public License v1.3c or later %% See http://www.latex-project.org/lppl.txt %% ---------------------------------------------------------------- %% \RequirePackage{pml3array} \ExplSyntaxOn \cs_generate_variant:Nn \fp_set:Nn {Nx} \cs_generate_variant:Nn \tl_if_eq:nnTF {VnTF} \cs_generate_variant:Nn \tl_if_eq:nnTF {xnTF} \tl_clear:N \l_tmpa_tl \tl_if_exist:NT \g__hobby_version { \tl_set:Nn \l_tmpa_tl { \ExplSyntaxOff \tl_clear:N \l_tmpa_tl \endinput } } \tl_use:N \l_tmpa_tl \tl_new:N \g__hobby_version \tl_new:N \g__hobby_date \tl_gset:Nn \g__hobby_version {1.12} \tl_gset:Nn \g__hobby_date {2023-09-01} \DeclareDocumentCommand \hobbyVersion {} { \tl_use:N \g__hobby_version } \DeclareDocumentCommand \hobbyDate {} { \tl_use:N \g__hobby_date } \fp_new:N \g_hobby_parama_fp \fp_new:N \g_hobby_paramb_fp \fp_new:N \g_hobby_paramc_fp \fp_gset:Nn \g_hobby_parama_fp {2^.5} \fp_gset:Nn \g_hobby_paramb_fp {1/16} \fp_gset:Nn \g_hobby_paramc_fp {(3-5^.5)/2} \bool_new:N \l_hobby_closed_bool \bool_new:N \l_hobby_disjoint_bool \bool_new:N \l_hobby_save_aux_bool \bool_set_true:N \l_hobby_save_aux_bool \DeclareDocumentCommand \HobbyDisableAux {} { \bool_set_false:N \l_hobby_save_aux_bool } \array_new:N \g__hobby_points_array \array_new:N \g__hobby_points_x_array \array_new:N \g__hobby_points_y_array \array_new:N \g__hobby_actions_array \array_new:N \g__hobby_angles_array \array_new:N \g__hobby_distances_array \array_new:N \g__hobby_tension_out_array \array_new:N \g__hobby_tension_in_array \array_new:N \g__hobby_matrix_a_array \array_new:N \g__hobby_matrix_b_array \array_new:N \g__hobby_matrix_c_array \array_new:N \g__hobby_matrix_d_array \array_new:N \g__hobby_vector_u_array \array_new:N \g__hobby_excess_angle_array \array_new:N \g__hobby_psi_array \array_new:N \g__hobby_theta_array \array_new:N \g__hobby_phi_array \array_new:N \g__hobby_sigma_array \array_new:N \g__hobby_rho_array \array_new:N \g__hobby_controla_array \array_new:N \g__hobby_controlb_array \fp_new:N \l_hobby_matrix_v_fp \fp_new:N \l_hobby_tempa_tl \fp_new:N \l_hobby_tempb_tl \fp_new:N \l_hobby_tempa_fp \fp_new:N \l_hobby_tempb_fp \fp_new:N \l_hobby_tempc_fp \fp_new:N \l_hobby_tempd_fp \fp_new:N \l_hobby_temps_fp \fp_new:N \g__hobby_in_curl_fp \fp_gset:Nn \g__hobby_in_curl_fp {1} \fp_new:N \g__hobby_out_curl_fp \fp_gset:Nn \g__hobby_out_curl_fp {1} \fp_new:N \g__hobby_in_angle_fp \fp_gset_eq:NN \g__hobby_in_angle_fp \c_inf_fp \fp_new:N \g__hobby_out_angle_fp \fp_gset_eq:NN \g__hobby_out_angle_fp \c_inf_fp \int_new:N \g__hobby_npoints_int \int_new:N \g__hobby_draw_int \keys_define:nn {hobby / read in all} { point .code:n = { \fp_set:Nn \l_hobby_tempa_fp {\clist_item:nn {#1} {1}} \fp_set:Nn \l_hobby_tempb_fp {\clist_item:nn {#1} {2}} }, tension~out .fp_set:N = \l_hobby_tempc_fp, tension~in .fp_set:N = \l_hobby_tempd_fp, excess~angle .fp_set:N = \l_hobby_temps_fp, break .tl_set:N = \l_tmpb_tl, blank .tl_set:N = \l_tmpa_tl, tension .meta:n = { tension~out=#1, tension~in=#1 }, break .default:n = false, blank .default:n = false, invert~soft~blanks .choice:, invert~soft~blanks / true .code:n = { \int_gset:Nn \g__hobby_draw_int {0} }, invert~soft~blanks / false .code:n = { \int_gset:Nn \g__hobby_draw_int {1} }, invert~soft~blanks .default:n = true, tension~out .default:n = 1, tension~in .default:n = 1, excess~angle .default:n = 0, in~angle .fp_gset:N = \g__hobby_in_angle_fp, out~angle .fp_gset:N = \g__hobby_out_angle_fp, in~curl .fp_gset:N = \g__hobby_in_curl_fp, out~curl .fp_gset:N = \g__hobby_out_curl_fp, closed .bool_gset:N = \g__hobby_closed_bool, closed .default:n = true, disjoint .bool_gset:N = \g__hobby_disjoint_bool, disjoint .default:n = true, break~default .code:n = { \keys_define:nn { hobby / read in all } { break .default:n = #1 } }, blank~default .code:n = { \keys_define:nn { hobby / read in all } { blank .default:n = #1 } }, } \keys_define:nn { hobby / read in params} { in~angle .fp_gset:N = \g__hobby_in_angle_fp, out~angle .fp_gset:N = \g__hobby_out_angle_fp, in~curl .fp_gset:N = \g__hobby_in_curl_fp, out~curl .fp_gset:N = \g__hobby_out_curl_fp, closed .bool_gset:N = \g__hobby_closed_bool, closed .default:n = true, disjoint .bool_gset:N = \g__hobby_disjoint_bool, disjoint .default:n = true, break~default .code:n = { \keys_define:nn { hobby / read in all } { break .default:n = #1 } }, blank~default .code:n = { \keys_define:nn { hobby / read in all } { blank .default:n = #1 } }, invert~soft~blanks .choice:, invert~soft~blanks / true .code:n = { \int_gset:Nn \g__hobby_draw_int {0} }, invert~soft~blanks / false .code:n = { \int_gset:Nn \g__hobby_draw_int {1} }, invert~soft~blanks .default:n = true, } \cs_set:Nn \hobby_distangle:n { \fp_set:Nn \l_hobby_tempa_fp { (\array_get:Nn \g__hobby_points_x_array {#1 + 1}) - (\array_get:Nn \g__hobby_points_x_array {#1})} \fp_set:Nn \l_hobby_tempb_fp { (\array_get:Nn \g__hobby_points_y_array {#1 + 1}) - (\array_get:Nn \g__hobby_points_y_array {#1})} \fp_set:Nn \l_hobby_tempc_fp { atan ( \l_hobby_tempb_fp, \l_hobby_tempa_fp ) } \fp_veclen:NVV \l_hobby_tempd_fp \l_hobby_tempa_fp \l_hobby_tempb_fp \array_gpush:Nx \g__hobby_angles_array {\fp_to_tl:N \l_hobby_tempc_fp} \array_gpush:Nx \g__hobby_distances_array {\fp_to_tl:N \l_hobby_tempd_fp} } \cs_new:Nn \fp_veclen:Nnn { \fp_set:Nn #1 {((#2)^2 + (#3)^2)^.5} } \cs_generate_variant:Nn \fp_veclen:Nnn {NVV} \cs_new:Nn \hobby_ctrllen:Nnn { \fp_set:Nn #1 {(2 - \g_hobby_parama_fp * ( sin(#2) - \g_hobby_paramb_fp * sin(#3) ) * ( sin(#3) - \g_hobby_paramb_fp * sin(#2) ) * ( cos(#2) - cos(#3) ) ) / ( 1 + (1 - \g_hobby_paramc_fp) * cos(#3) + \g_hobby_paramc_fp * cos(#2))} } \cs_generate_variant:Nn \hobby_ctrllen:Nnn {NVV} \cs_new_protected:Npn \hobby_append_point_copy:n #1 { \hobby_append_point_copy_aux:Nn \g__hobby_points_array {#1} \hobby_append_point_copy_aux:Nn \g__hobby_points_x_array {#1} \hobby_append_point_copy_aux:Nn \g__hobby_points_y_array {#1} \hobby_append_point_copy_aux:Nn \g__hobby_tension_in_array {#1} \hobby_append_point_copy_aux:Nn \g__hobby_tension_out_array {#1} \hobby_append_point_copy_aux:Nn \g__hobby_excess_angle_array {#1} \hobby_append_point_copy_aux:Nn \g__hobby_actions_array {#1} } \cs_new_protected:Npn \hobby_append_point_copy_aux:Nn #1#2 { \array_gpush:Nx #1 { \array_get:Nn #1 {#2} } } \cs_new:Nn \hobby_gen_path: { \bool_if:NT \g__hobby_closed_bool { \fp_compare:nTF {(\array_get:Nn \g__hobby_points_x_array {0}) = (\array_top:N \g__hobby_points_x_array)} { \fp_compare:nF { \array_get:Nn \g__hobby_points_y_array {0} = \array_top:N \g__hobby_points_y_array } { \hobby_append_point_copy:n {0} } } { \hobby_append_point_copy:n {0} } \hobby_append_point_copy:n {1} } \int_gset:Nn \g__hobby_npoints_int {\array_length:N \g__hobby_points_y_array} \int_compare:nNnTF {\g__hobby_npoints_int} = {0} { } { \int_compare:nNnTF {\g__hobby_npoints_int} = {1} { \hobby_distangle:n {0} \fp_compare:nF { \g__hobby_out_angle_fp == \c_inf_fp } { \fp_set:Nn \l_hobby_tempa_fp { \g__hobby_out_angle_fp - \array_get:Nn \g__hobby_angles_array {0}} \fp_compare:nT {\l_hobby_tempa_fp > \c_pi_fp } { \fp_sub:Nn \l_hobby_tempa_fp {2 * \c_pi_fp} } \fp_compare:nT {\l_hobby_tempa_fp < -\c_pi_fp } { \fp_add:Nn \l_hobby_tempa_fp {2 * \c_pi_fp} } \array_gput:Nnx \g__hobby_theta_array {0} {\fp_to_tl:N \l_hobby_tempa_fp} \fp_compare:nT { \g__hobby_in_angle_fp == \c_inf_fp } { \array_gput:Nnx \g__hobby_phi_array {1}{ \fp_to_tl:N \l_hobby_tempa_fp} } } \fp_compare:nTF { \g__hobby_in_angle_fp == \c_inf_fp } { \fp_compare:nT { \g__hobby_out_angle_fp == \c_inf_fp } { \array_gput:Nnx \g__hobby_phi_array {1} {0} \array_gput:Nnx \g__hobby_theta_array {0} {0} } } { \fp_set:Nn \l_hobby_tempa_fp { - \g__hobby_in_angle_fp + \c_pi_fp + (\array_get:Nn \g__hobby_angles_array {0})} \fp_compare:nT {\l_hobby_tempa_fp > \c_pi_fp } { \fp_sub:Nn \l_hobby_tempa_fp {2 * \c_pi_fp} } \fp_compare:nT {\l_hobby_tempa_fp < -\c_pi_fp } { \fp_add:Nn \l_hobby_tempa_fp {2 * \c_pi_fp} } \array_gput:Nnx \g__hobby_phi_array {1} {\fp_to_tl:N \l_hobby_tempa_fp} \fp_compare:nT { \g__hobby_out_angle_fp == \c_inf_fp } { \array_gput:Nnx \g__hobby_theta_array {0}{ \fp_to_tl:N \l_hobby_tempa_fp} } } } { \hobby_compute_path: } \hobby_build_path: } } \cs_new:Nn \hobby_compute_path: { \int_step_function:nnnN {0} {1} {\g__hobby_npoints_int - 1} \hobby_distangle:n \int_step_inline:nnnn {1} {1} {\g__hobby_npoints_int - 1} { \fp_set:Nx \l_hobby_tempa_fp { \array_get:Nn \g__hobby_angles_array {##1} - \array_get:Nn \g__hobby_angles_array {##1 - 1}} \fp_compare:nTF {\l_hobby_tempa_fp > \c_pi_fp } { \fp_sub:Nn \l_hobby_tempa_fp {2 * \c_pi_fp} } {} \fp_compare:nTF {\l_hobby_tempa_fp <= -\c_pi_fp } { \fp_add:Nn \l_hobby_tempa_fp {2 * \c_pi_fp} } {} \array_get:NnNTF \g__hobby_excess_angle_array {##1} \l_tmpa_tl { \fp_add:Nn \l_hobby_tempa_fp {2 * \c_pi_fp * \l_tmpa_tl} }{} \array_gput:Nnx \g__hobby_psi_array {##1}{\fp_to_tl:N \l_hobby_tempa_fp} } \int_step_inline:nnnn {1} {1} {\g__hobby_npoints_int - 1} { \array_gput:Nnx \g__hobby_matrix_a_array {##1} {\fp_to_tl:n { \array_get:Nn \g__hobby_tension_in_array {##1}^2 * \array_get:Nn \g__hobby_distances_array {##1} * \array_get:Nn \g__hobby_tension_in_array {##1 + 1} }} } \int_step_inline:nnnn {1} {1} {\g__hobby_npoints_int - 1} { \array_gput:Nnx \g__hobby_matrix_b_array {##1} {\fp_to_tl:n {(3 * (\array_get:Nn \g__hobby_tension_in_array {##1 + 1}) - 1) * (\array_get:Nn \g__hobby_tension_out_array {##1})^2 * (\array_get:Nn \g__hobby_tension_out_array {##1 - 1}) * ( \array_get:Nn \g__hobby_distances_array {##1 - 1}) + (3 * (\array_get:Nn \g__hobby_tension_out_array {##1 - 1}) - 1) * (\array_get:Nn \g__hobby_tension_in_array {##1})^2 * (\array_get:Nn \g__hobby_tension_in_array {##1 + 1}) * (\array_get:Nn \g__hobby_distances_array {##1})} } } \int_step_inline:nnnn {1} {1} {\g__hobby_npoints_int - 2} { \array_gput:Nnx \g__hobby_matrix_c_array {##1} {\fp_to_tl:n {(\array_get:Nn \g__hobby_tension_in_array {##1})^2 * (\array_get:Nn \g__hobby_tension_in_array {##1 - 1}) * (\array_get:Nn \g__hobby_distances_array {##1 - 1}) }} } \int_step_inline:nnnn {1} {1} {\g__hobby_npoints_int - 2} { \array_gput:Nnx \g__hobby_matrix_d_array {##1} {\fp_to_tl:n { - (\array_get:Nn \g__hobby_psi_array {##1 + 1}) * (\array_get:Nn \g__hobby_tension_out_array {##1})^2 * (\array_get:Nn \g__hobby_tension_out_array {##1 - 1}) * (\array_get:Nn \g__hobby_distances_array {##1 - 1}) - (3 * (\array_get:Nn \g__hobby_tension_out_array {##1 - 1}) - 1) * (\array_get:Nn \g__hobby_psi_array {##1}) * (\array_get:Nn \g__hobby_tension_in_array {##1})^2 * (\array_get:Nn \g__hobby_tension_in_array {##1 + 1}) * (\array_get:Nn \g__hobby_distances_array {##1}) } } } \bool_if:NTF \g__hobby_closed_bool { \array_gput:Nnx \g__hobby_matrix_c_array {0} {\fp_to_tl:n { - (\array_get:Nn \g__hobby_distances_array {\g__hobby_npoints_int - 2}) * (\array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int - 2}) * (\array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int - 1})^2 }} \array_gput:Nnn \g__hobby_matrix_b_array {0} {1} \array_gput:Nnn \g__hobby_matrix_d_array {0} {0} \array_gput:Nnx \g__hobby_matrix_b_array {\g__hobby_npoints_int - 1} {\fp_to_tl:n { (\array_get:Nn \g__hobby_matrix_b_array {\g__hobby_npoints_int - 1}) + 1 }} \array_gput:Nnx \g__hobby_matrix_d_array {\g__hobby_npoints_int - 1} {\fp_to_tl:n { - (\array_get:Nn \g__hobby_psi_array {1}) * (\array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int -1})^2 * (\array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int -2}) * (\array_get:Nn \g__hobby_distances_array {\g__hobby_npoints_int - 2}) - (3 * (\array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int - 2}) - 1) * (\array_get:Nn \g__hobby_psi_array {\g__hobby_npoints_int - 1}) * (\array_get:Nn \g__hobby_tension_in_array {\g__hobby_npoints_int - 1})^2 * (\array_get:Nn \g__hobby_tension_in_array {\g__hobby_npoints_int}) * (\array_get:Nn \g__hobby_distances_array {\g__hobby_npoints_int -1}) } } \array_gput:Nnn \g__hobby_vector_u_array {0} {1} \array_gput:Nnn \g__hobby_vector_u_array {\g__hobby_npoints_int - 1} {1} \int_step_inline:nnnn {1} {1} {\g__hobby_npoints_int - 2} { \array_gput:Nnn \g__hobby_vector_u_array {##1} {0} } \fp_set:Nn \l_hobby_matrix_v_fp { (\array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int -1})^2 * (\array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int -2}) * (\array_get:Nn \g__hobby_distances_array {\g__hobby_npoints_int -2}) } } { \fp_compare:nTF { \g__hobby_out_angle_fp == \c_inf_fp } { \array_gput:Nnx \g__hobby_matrix_b_array {0} {\fp_to_tl:n { (\array_get:Nn \g__hobby_tension_in_array {1})^3 * \g__hobby_in_curl_fp + (3 * (\array_get:Nn \g__hobby_tension_in_array {1}) - 1) * (\array_get:Nn \g__hobby_tension_out_array {0})^3 }} \array_gput:Nnx \g__hobby_matrix_c_array {0} {\fp_to_tl:n { (\array_get:Nn \g__hobby_tension_out_array {0})^3 + (3 * (\array_get:Nn \g__hobby_tension_out_array {0}) - 1) * (\array_get:Nn \g__hobby_tension_in_array {1})^3 * \g__hobby_in_curl_fp }} \array_gput:Nnx \g__hobby_matrix_d_array {0} {\fp_to_tl:n { -( (\array_get:Nn \g__hobby_tension_out_array {0})^3 + (3 * (\array_get:Nn \g__hobby_tension_out_array {0}) - 1) * (\array_get:Nn \g__hobby_tension_in_array {1})^3 * \g__hobby_in_curl_fp) * (\array_get:Nn \g__hobby_psi_array {1}) }} } { \array_gput:Nnn \g__hobby_matrix_b_array {0} {1} \array_gput:Nnn \g__hobby_matrix_c_array {0} {0} \fp_set:Nn \l_hobby_tempa_fp { \g__hobby_out_angle_fp - \array_get:Nn \g__hobby_angles_array {0}} \fp_compare:nT {\l_hobby_tempa_fp > \c_pi_fp } { \fp_sub:Nn \l_hobby_tempa_fp {2 * \c_pi_fp} } \fp_compare:nT {\l_hobby_tempa_fp < -\c_pi_fp } { \fp_add:Nn \l_hobby_tempa_fp {2 * \c_pi_fp} } \array_gput:Nnx \g__hobby_matrix_d_array {0} {\fp_to_tl:N \l_hobby_tempa_fp} } \fp_compare:nTF { \g__hobby_in_angle_fp == \c_inf_fp } { \array_gput:Nnx \g__hobby_matrix_b_array {\g__hobby_npoints_int - 1} {\fp_to_tl:n { \array_get:Nn \g__hobby_matrix_b_array {\g__hobby_npoints_int - 1} - (\array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int - 1})^2 * (\array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int - 2}) * (\array_get:Nn \g__hobby_distances_array {\g__hobby_npoints_int - 2}) * ((3 * (\array_get:Nn \g__hobby_tension_in_array {\g__hobby_npoints_int} ) - 1) * (\array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int - 1})^3 \l_tmpa_tl * \g__hobby_out_curl_fp + (\array_get:Nn \g__hobby_tension_in_array {\g__hobby_npoints_int })^3) / ((3 * (\array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int -2}) - 1) * (\array_get:Nn \g__hobby_tension_in_array {\g__hobby_npoints_int})^3 + ( \array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int - 1})^3 * \g__hobby_out_curl_fp) }} \array_gput:Nnx \g__hobby_matrix_d_array {\g__hobby_npoints_int - 1} {\fp_to_tl:n { - (3 * (\array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int - 2}) - 1) * (\array_get:Nn \g__hobby_psi_array {\g__hobby_npoints_int - 1}) * (\array_get:Nn \g__hobby_tension_in_array {\g__hobby_npoints_int - 1})^2 * (\array_get:Nn \g__hobby_tension_in_array {\g__hobby_npoints_int}) * (\array_get:Nn \g__hobby_distances_array {\g__hobby_npoints_int - 1}) }} } { \fp_set:Nn \l_hobby_tempa_fp { - \g__hobby_in_angle_fp + \c_pi_fp + (\array_get:Nn \g__hobby_angles_array {\g__hobby_npoints_int - 1})} \fp_compare:nT {\l_hobby_tempa_fp > \c_pi_fp } { \fp_sub:Nn \l_hobby_tempa_fp {2 * \c_pi_fp} } \fp_compare:nT {\l_hobby_tempa_fp < -\c_pi_fp } { \fp_add:Nn \l_hobby_tempa_fp {2 * \c_pi_fp} } \array_gput:Nnx \g__hobby_phi_array {\g__hobby_npoints_int} {\fp_to_tl:N \l_hobby_tempa_fp} \array_gput:Nnx \g__hobby_matrix_d_array {\g__hobby_npoints_int - 1} {\fp_to_tl:n { \l_hobby_tempa_fp * (\array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int - 1})^2 * (\array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int - 2}) * (\array_get:Nn \g__hobby_distances_array {\g__hobby_npoints_int - 2}) - (3 * ( \array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int - 2}) - 1) * (\array_get:Nn \g__hobby_psi_array {\g__hobby_npoints_int - 1}) * (\array_get:Nn \g__hobby_tension_in_array {\g__hobby_npoints_int - 1})^2 * (\array_get:Nn \g__hobby_tension_in_array {\g__hobby_npoints_int}) * (\array_get:Nn \g__hobby_distances_array {\g__hobby_npoints_int - 1}) }} } } \int_step_inline:nnnn {1} {1} {\g__hobby_npoints_int - 1} { \array_gput:Nnx \g__hobby_matrix_b_array {##1} {\fp_to_tl:n { (\array_get:Nn \g__hobby_matrix_b_array {##1 - 1}) * (\array_get:Nn \g__hobby_matrix_b_array {##1}) - (\array_get:Nn \g__hobby_matrix_c_array {##1 - 1}) * (\array_get:Nn \g__hobby_matrix_a_array {##1}) }} \int_compare:nT {##1 < \g__hobby_npoints_int - 1} { \array_gput:Nnx \g__hobby_matrix_c_array {##1} {\fp_to_tl:n { (\array_get:Nn \g__hobby_matrix_b_array {##1 - 1}) * (\array_get:Nn \g__hobby_matrix_c_array {##1}) }} } \array_gput:Nnx \g__hobby_matrix_d_array {##1} {\fp_to_tl:n { (\array_get:Nn \g__hobby_matrix_b_array {##1 - 1}) * (\array_get:Nn \g__hobby_matrix_d_array {##1}) - (\array_get:Nn \g__hobby_matrix_d_array {##1 - 1}) * (\array_get:Nn \g__hobby_matrix_a_array {##1}) }} \bool_if:NT \g__hobby_closed_bool { \array_gput:Nnx \g__hobby_vector_u_array {##1} {\fp_to_tl:n { (\array_get:Nn \g__hobby_matrix_b_array {##1 - 1}) * (\array_get:Nn \g__hobby_vector_u_array {##1}) - (\array_get:Nn \g__hobby_vector_u_array {##1 - 1}) * (\array_get:Nn \g__hobby_matrix_a_array {##1}) }} } } \array_gput:Nnx \g__hobby_theta_array {\g__hobby_npoints_int - 1} {\fp_to_tl:n { (\array_get:Nn \g__hobby_matrix_d_array {\g__hobby_npoints_int - 1}) / (\array_get:Nn \g__hobby_matrix_b_array {\g__hobby_npoints_int - 1}) }} \bool_if:NT \g__hobby_closed_bool { \array_gput:Nnx \g__hobby_vector_u_array {\g__hobby_npoints_int - 1} {\fp_to_tl:n { (\array_get:Nn \g__hobby_vector_u_array {\g__hobby_npoints_int - 1}) / (\array_get:Nn \g__hobby_matrix_b_array {\g__hobby_npoints_int - 1}) }} } \int_step_inline:nnnn {\g__hobby_npoints_int - 2} {-1} {0} { \array_gput:Nnx \g__hobby_theta_array {##1} {\fp_to_tl:n { ( (\array_get:Nn \g__hobby_matrix_d_array {##1}) - (\array_get:Nn \g__hobby_theta_array {##1 + 1}) * (\array_get:Nn \g__hobby_matrix_c_array {##1}) ) / (\array_get:Nn \g__hobby_matrix_b_array {##1}) }} } \bool_if:NT \g__hobby_closed_bool { \int_step_inline:nnnn {\g__hobby_npoints_int - 2} {-1} {0} { \array_gput:Nnx \g__hobby_vector_u_array {##1} {\fp_to_tl:n { ((\array_get:Nn \g__hobby_vector_u_array {##1}) - (\array_get:Nn \g__hobby_vector_u_array {##1 + 1}) * (\array_get:Nn \g__hobby_matrix_c_array {##1}) ) / (\array_get:Nn \g__hobby_matrix_b_array {##1}) }} } \fp_set:Nn \l_hobby_tempb_fp { ((\array_get:Nn \g__hobby_theta_array {1}) * \l_hobby_matrix_v_fp - (\array_get:Nn \g__hobby_theta_array {\g__hobby_npoints_int - 1}) ) / ( (\array_get:Nn \g__hobby_vector_u_array {1}) * \l_hobby_matrix_v_fp - (\array_get:Nn \g__hobby_vector_u_array {\g__hobby_npoints_int - 1}) + 1 )} \int_step_inline:nnnn {0} {1} {\g__hobby_npoints_int - 1} { \array_gput:Nnx \g__hobby_theta_array {##1} {\fp_to_tl:n { (\array_get:Nn \g__hobby_theta_array {##1}) - (\array_get:Nn \g__hobby_vector_u_array {##1}) * \l_hobby_tempb_fp }} } } \int_step_inline:nnnn {1} {1} {\g__hobby_npoints_int - 1} { \array_gput:Nnx \g__hobby_phi_array {##1} {\fp_to_tl:n { - (\array_get:Nn \g__hobby_psi_array {##1}) - (\array_get:Nn \g__hobby_theta_array {##1}) }} } \bool_if:NTF \g__hobby_closed_bool { \int_gdecr:N \g__hobby_npoints_int }{ \fp_compare:nT { \g__hobby_in_angle_fp == \c_inf_fp } { \array_gput:Nnx \g__hobby_phi_array {\g__hobby_npoints_int} {\fp_to_tl:n { ((3 * (\array_get:Nn \g__hobby_tension_in_array {\g__hobby_npoints_int}) - 1) * (\array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int - 1})^3 * \g__hobby_out_curl_fp + (\array_get:Nn \g__hobby_tension_in_array {\g__hobby_npoints_int })^3) / ((3 * (\array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int -2}) - 1) * (\array_get:Nn \g__hobby_tension_in_array {\g__hobby_npoints_int})^3 \l_tmpa_tl + (\array_get:Nn \g__hobby_tension_out_array {\g__hobby_npoints_int - 1})^3 * \g__hobby_out_curl_fp) * (\array_get:Nn \g__hobby_theta_array {\g__hobby_npoints_int -1}) }} } } } \cs_new:Nn \hobby_build_path: { \int_step_inline:nnnn {0} {1} {\g__hobby_npoints_int - 1} { \fp_set:Nn \l_hobby_tempa_fp {\array_get:Nn \g__hobby_theta_array {##1}} \fp_set:Nn \l_hobby_tempb_fp {\array_get:Nn \g__hobby_phi_array {##1 + 1}} \hobby_ctrllen:NVV \l_hobby_temps_fp \l_hobby_tempa_fp \l_hobby_tempb_fp \array_gput:Nnx \g__hobby_sigma_array {##1 + 1} {\fp_to_tl:N \l_hobby_temps_fp} \hobby_ctrllen:NVV \l_hobby_temps_fp \l_hobby_tempb_fp \l_hobby_tempa_fp \array_gput:Nnx \g__hobby_rho_array {##1} {\fp_to_tl:N \l_hobby_temps_fp} } \int_step_inline:nnnn {0} {1} {\g__hobby_npoints_int - 1} { \array_gput:Nnx \g__hobby_controla_array {##1 + 1} {\fp_eval:n { (\array_get:Nn \g__hobby_points_x_array {##1}) + (\array_get:Nn \g__hobby_distances_array {##1}) * (\array_get:Nn \g__hobby_rho_array {##1}) * cos ( (\array_get:Nn \g__hobby_angles_array {##1}) + (\array_get:Nn \g__hobby_theta_array {##1})) /3 }, \fp_eval:n { ( \array_get:Nn \g__hobby_points_y_array {##1}) + (\array_get:Nn \g__hobby_distances_array {##1}) * (\array_get:Nn \g__hobby_rho_array {##1}) * sin ( (\array_get:Nn \g__hobby_angles_array {##1}) + (\array_get:Nn \g__hobby_theta_array {##1})) /3 } } } \int_step_inline:nnnn {1} {1} {\g__hobby_npoints_int} { \array_gput:Nnx \g__hobby_controlb_array {##1} { \fp_eval:n {\array_get:Nn \g__hobby_points_x_array {##1} - (\array_get:Nn \g__hobby_distances_array {##1 - 1}) * (\array_get:Nn \g__hobby_sigma_array {##1}) * cos((\array_get:Nn \g__hobby_angles_array {##1 - 1}) - (\array_get:Nn \g__hobby_phi_array {##1}))/3 }, \fp_eval:n { (\array_get:Nn \g__hobby_points_y_array {##1}) - (\array_get:Nn \g__hobby_distances_array {##1 - 1}) * (\array_get:Nn \g__hobby_sigma_array {##1}) * sin((\array_get:Nn \g__hobby_angles_array {##1 - 1}) - (\array_get:Nn \g__hobby_phi_array {##1}))/3 } } } } \NewDocumentCommand \hobbyinit {m m m} { \hobby_set_cmds:NNN #1#2#3 \hobby_clear_path: } \NewDocumentCommand \hobbyaddpoint { m } { \keys_set:nn { hobby/read in all } { tension~out, tension~in, excess~angle, blank, break, #1 } \tl_if_eq:VnTF \l_tmpa_tl {true} {\tl_set:Nn \l_tmpa_tl {2}} { \tl_if_eq:VnTF \l_tmpa_tl {soft} {\tl_set:Nn \l_tmpa_tl {0}} {\tl_set:Nn \l_tmpa_tl {1}} } \tl_if_eq:VnTF \l_tmpb_tl {true} {\tl_put_right:Nn \l_tmpa_tl {1}} {\tl_put_right:Nn \l_tmpa_tl {0}} \tl_set:Nx \l_hobby_tempa_tl {\fp_use:N \l_hobby_tempa_fp} \tl_set:Nx \l_hobby_tempb_tl {\fp_use:N \l_hobby_tempb_fp} \hobby_add_point:VVVVVV \l_hobby_tempa_tl \l_hobby_tempb_tl \l_hobby_tempc_fp \l_hobby_tempd_fp \l_hobby_temps_fp \l_tmpa_tl } \cs_new_nopar:Npn \hobby_add_point:nnnnnn #1#2#3#4#5#6 { \array_gpush:Nn \g__hobby_actions_array { #6 } \array_gpush:Nn \g__hobby_tension_out_array { #3 } \array_gpush:Nn \g__hobby_tension_in_array { #4 } \array_gpush:Nn \g__hobby_excess_angle_array { #5 } \array_gpush:Nn \g__hobby_points_array { #1, #2 } \array_gpush:Nn \g__hobby_points_x_array { #1 } \array_gpush:Nn \g__hobby_points_y_array { #2 } } \cs_generate_variant:Nn \hobby_add_point:nnnnnn {VVVVVV} \NewDocumentCommand \hobbysetparams { m } { \keys_set:nn { hobby / read in params } { #1 } } \cs_new:Npn \hobby_moveto:nnn #1#2#3 {} \cs_new:Npn \hobby_curveto:nnn #1#2#3 {} \cs_new:Npn \hobby_close:n #1 {} \cs_generate_variant:Nn \hobby_moveto:nnn {VVV,nnV} \cs_generate_variant:Nn \hobby_curveto:nnn {VVV} \cs_generate_variant:Nn \hobby_close:n {V} \cs_new:Nn \hobby_set_cmds:NNN { \cs_gset_eq:NN \hobby_moveto:nnn #1 \cs_gset_eq:NN \hobby_curveto:nnn #2 \cs_gset_eq:NN \hobby_close:n #3 } \NewDocumentCommand \hobbygenpath { } { \array_if_empty:NF \g__hobby_points_array { \hobby_gen_path: } } \NewDocumentCommand \hobbygenifnecpath { m } { \tl_if_exist:cTF {g_hobby_#1_path} { \tl_use:c {g_hobby_#1_path} } { \hobby_gen_path: } \hobby_save_path:n {#1} \hobby_save_path_to_aux:x {#1} } \NewDocumentCommand \hobbygenuseifnecpath { m } { \tl_if_exist:cTF {g_hobby_#1_path} { \tl_use:c {g_hobby_#1_path} } { \hobby_gen_path: } \hobby_save_path:n {#1} \hobby_save_path_to_aux:x {#1} \hobby_use_path: } \NewDocumentCommand \hobbyusepath { m } { \hobbysetparams{#1} \hobby_use_path: } \NewDocumentCommand \hobbysavepath { m } { \hobby_save_path:n {#1} } \NewDocumentCommand \hobbyrestorepath { m } { \tl_if_exist:cT {g_hobby_#1_path} { \tl_use:c {g_hobby_#1_path} } } \NewDocumentCommand \hobbyshowpath { m } { \tl_if_exist:cT {g_hobby_#1_path} { \tl_show:c {g_hobby_#1_path} } } \NewDocumentCommand \hobbygenusepath { } { \array_if_empty:NF \g__hobby_points_array { \hobby_gen_path: \hobby_use_path: } } \NewDocumentCommand \hobbyclearpath { } { \hobby_clear_path: } \tl_new:N \l_tmpc_tl \tl_new:N \l_tmpd_tl \cs_new:Nn \hobby_use_path: { \bool_if:NT \g__hobby_disjoint_bool { \array_get:NnN \g__hobby_points_array {0} \l_tmpa_tl \hobby_moveto:nnV {} {} \l_tmpa_tl } \int_step_inline:nnnn {1} {1} {\g__hobby_npoints_int} { \array_get:NnN \g__hobby_controla_array {##1} \l_tmpa_tl \array_get:NnN \g__hobby_controlb_array {##1} \l_tmpb_tl \array_get:NnN \g__hobby_points_array {##1} \l_tmpc_tl \array_get:NnN \g__hobby_actions_array {##1} \l_tmpd_tl \int_compare:nNnTF {\tl_item:Nn \l_tmpd_tl {1}} = {\g__hobby_draw_int} { \hobby_curveto:VVV \l_tmpa_tl \l_tmpb_tl \l_tmpc_tl }{ \bool_gset_false:N \g__hobby_closed_bool \hobby_moveto:VVV \l_tmpa_tl \l_tmpb_tl \l_tmpc_tl } \tl_if_eq:xnTF {\tl_item:Nn \l_tmpd_tl {2}} {1} { \bool_gset_false:N \g__hobby_closed_bool \hobby_moveto:VVV \l_tmpa_tl \l_tmpb_tl \l_tmpc_tl }{} } \bool_if:NT \g__hobby_closed_bool { \array_get:NnN \g__hobby_points_array {0} \l_tmpa_tl \hobby_close:V \l_tmpa_tl } } \cs_new:Nn \hobby_save_path:n { \tl_clear:N \l_tmpa_tl \tl_put_right:Nn \l_tmpa_tl {\int_gset:Nn \g__hobby_npoints_int} \tl_put_right:Nx \l_tmpa_tl {{\int_use:N \g__hobby_npoints_int}} \bool_if:NTF \g__hobby_disjoint_bool { \tl_put_right:Nn \l_tmpa_tl {\bool_gset_true:N} }{ \tl_put_right:Nn \l_tmpa_tl {\bool_gset_false:N} } \tl_put_right:Nn \l_tmpa_tl {\g__hobby_disjoint_bool} \bool_if:NTF \g__hobby_closed_bool { \tl_put_right:Nn \l_tmpa_tl {\bool_gset_true:N} }{ \tl_put_right:Nn \l_tmpa_tl {\bool_gset_false:N} } \tl_put_right:Nn \l_tmpa_tl {\g__hobby_closed_bool} \tl_put_right:Nn \l_tmpa_tl {\array_gclear:N \g__hobby_points_array} \array_map_inline:Nn \g__hobby_points_array { \tl_put_right:Nn \l_tmpa_tl { \array_gput:Nnn \g__hobby_points_array {##1} {##2} } } \tl_put_right:Nn \l_tmpa_tl {\array_gclear:N \g__hobby_actions_array} \array_map_inline:Nn \g__hobby_actions_array { \tl_put_right:Nn \l_tmpa_tl { \array_gput:Nnn \g__hobby_actions_array {##1} {##2} } } \tl_put_right:Nn \l_tmpa_tl {\array_gclear:N \g__hobby_controla_array} \array_map_inline:Nn \g__hobby_controla_array { \tl_put_right:Nn \l_tmpa_tl { \array_gput:Nnn \g__hobby_controla_array {##1} {##2} } } \tl_put_right:Nn \l_tmpa_tl {\array_gclear:N \g__hobby_controlb_array} \array_map_inline:Nn \g__hobby_controlb_array { \tl_put_right:Nn \l_tmpa_tl { \array_gput:Nnn \g__hobby_controlb_array {##1} {##2} } } \tl_gclear_new:c {g_hobby_#1_path} \tl_gset_eq:cN {g_hobby_#1_path} \l_tmpa_tl } \int_set:Nn \l_tmpa_int {\char_value_catcode:n {`@}} \char_set_catcode_letter:N @ \cs_new:Npn \hobby_save_path_to_aux:n #1 { \bool_if:nT { \tl_if_exist_p:c {g_hobby_#1_path} && ! \tl_if_exist_p:c {g_hobby_#1_path_saved} && \l_hobby_save_aux_bool } { \tl_clear:N \l_tmpa_tl \tl_put_right:Nn \l_tmpa_tl { \ExplSyntaxOn \tl_gclear_new:c {g_hobby_#1_path} \tl_gput_right:cn {g_hobby_#1_path} } \tl_put_right:Nx \l_tmpa_tl { {\tl_to_str:c {g_hobby_#1_path}} } \tl_put_right:Nn \l_tmpa_tl { \ExplSyntaxOff } \protected@write\@auxout{}{ \tl_to_str:N \l_tmpa_tl } \tl_new:c {g_hobby_#1_path_saved} } } \char_set_catcode:nn {`@} {\l_tmpa_int} \cs_generate_variant:Nn \hobby_save_path_to_aux:n {x} \cs_new:Nn \hobby_clear_path: { \array_gclear:N \g__hobby_points_array \array_gclear:N \g__hobby_points_x_array \array_gclear:N \g__hobby_points_y_array \array_gclear:N \g__hobby_angles_array \array_gclear:N \g__hobby_actions_array \array_gclear:N \g__hobby_distances_array \array_gclear:N \g__hobby_tension_out_array \array_gclear:N \g__hobby_tension_in_array \array_gclear:N \g__hobby_excess_angle_array \array_gclear:N \g__hobby_matrix_a_array \array_gclear:N \g__hobby_matrix_b_array \array_gclear:N \g__hobby_matrix_c_array \array_gclear:N \g__hobby_matrix_d_array \array_gclear:N \g__hobby_vector_u_array \array_gclear:N \g__hobby_psi_array \array_gclear:N \g__hobby_theta_array \array_gclear:N \g__hobby_phi_array \array_gclear:N \g__hobby_sigma_array \array_gclear:N \g__hobby_rho_array \array_gclear:N \g__hobby_controla_array \array_gclear:N \g__hobby_controlb_array \bool_gset_false:N \g__hobby_closed_bool \bool_gset_false:N \g__hobby_disjoint_bool \int_gset:Nn \g__hobby_npoints_int {-1} \int_gset:Nn \g__hobby_draw_int {1} \fp_gset_eq:NN \g__hobby_in_angle_fp \c_inf_fp \fp_gset_eq:NN \g__hobby_out_angle_fp \c_inf_fp \fp_gset_eq:NN \g__hobby_in_curl_fp \c_one_fp \fp_gset_eq:NN \g__hobby_out_curl_fp \c_one_fp } \ExplSyntaxOff %% %% Copyright (C) 2012-2021 by Andrew Stacey %% %% This file may be distributed and/or modified under the conditions %% of the LaTeX Project Public License, either version 1.3 of this %% license or (at your option) any later version. %% The latest version of this license is in: %% %% http://www.latex-project.org/lppl.txt %% %% and version 1.3 or later is part of all distributions of LaTeX %% version 2005/12/01 or later. %% %% This work is "maintained" (as per LPPL maintenance status) by %% Andrew Stacey. %% %% This work consists of the files hobby_code.dtx %% hobby.tex %% and the derived files hobby.code.tex %% pgflibraryhobby.code.tex %% tikzlibraryhobby.code.tex %% pml3array.sty %% hobby-l3draw.sty %% hobby.ins %% hobby.pdf %% hobby_code.pdf %% README.txt %% %% %% End of file `hobby.code.tex'.