%%% ---------------------------------------------------------------------------- %%% suanpan: draw suanpan(abacus) with LaTeX3 %%% Author : Nan Geng %%% Repository: https://gitee.com/nwafu_nan/suan-span %%% License : The LaTeX Project Public License 1.3c %%% ---------------------------------------------------------------------------- \NeedsTeXFormat{LaTeX2e}[2020/10/01] \RequirePackage{expl3} % \ProvidesExplPackage{suanpan}{2024-08-20}{v1.0.0} % 初稿 % \ProvidesExplPackage{suanpan}{2024-08-28}{v1.1.0} % 优化(统一尺寸计算,添加空白占位) % \ProvidesExplPackage{suanpan-l3}{2024-08-30}{v1.1.1} % 更名为suanpan-l3 % \ProvidesExplPackage{suanpan-l3}{2024-08-31}{v1.1.2} % 添加empty不绘制空档选项 % \ProvidesExplPackage{suanpan-l3}{2024-09-01}{v1.1.3} % 添加bid批处理及绘制颜色选项 % % 将算珠与档杆绘制改为TikZ % \ProvidesExplPackage{suanpan-l3}{2024-09-04}{v1.2.0} % 添加\lab横梁文字标记命令 % \ProvidesExplPackage{suanpan-l3}{2024-09-05}{v1.2.1} % 将草稿模式所有算珠改为圆冒 % % 直线并取消所有高光特效 \ProvidesExplPackage{suanpan-l3}{2024-09-07}{v1.2.2} % 为珠高、珠宽、档杆宽度和 % 边框宽度添加设置选项 {draw suanpan(abacus) with LaTeX3} \RequirePackage{l3keys2e} \RequirePackage{xparse} \RequirePackage{l3draw} \RequirePackage {tikz} \cs_new:Npn \__suanpan_error:n { \msg_error:nn { suanpan(abacus) } } % 盒子容器总高度计算函数 \cs_new_nopar:Npn \__suanpan_coffin_ht_plus_dp:N #1 { \coffin_ht:N #1 + \coffin_dp:N #1 } % =============颜色处理函数============= % 填充色辅助函数 \cs_new_nopar:Nn \__suanpan_aux_color_boxfill: { } % 颜色命名函数 % #1 颜色名称 % #2 颜色表达式 \cs_set_nopar:Npn \__suanpan_color_select:nn #1#2 { \colorlet { #1 } { #2 } } \cs_generate_variant:Nn \__suanpan_color_select:nn {nx} % 颜色命名函数 % #1 颜色名称 % #2 颜色空间 % #3 颜色分量值 \cs_set_nopar:Npn \__suanpan_color_select:nnn #1#2#3 { \definecolor { #1 } { #2 } { #3 } } \cs_generate_variant:Nn \__suanpan_color_select:nnn {nnx} % 定义变量 % 算盘基础尺寸 \dim_new:N \l__suanpan_bid_h_dim \dim_new:N \l__suanpan_bid_d_dim \dim_new:N \l__suanpan_rod_d_dim \dim_new:N \l__suanpan_frame_b_dim \dim_new:N \l__suanpan_bid_sep_dim \dim_new:N \l__suanpan_rod_sep_dim % 算盘基础尺寸初值(参考 QBT1747-1993 算盘标准) \dim_set:Nn \l__suanpan_bid_h_dim { 12mm } \dim_set:Nn \l__suanpan_bid_d_dim { 23mm } \dim_set:Nn \l__suanpan_rod_d_dim { 7mm } \dim_set:Nn \l__suanpan_frame_b_dim { 13mm } \dim_set:Nn \l__suanpan_bid_sep_dim { 1.8pt } \dim_set:Nn \l__suanpan_rod_sep_dim { 3.0pt } % 半长度 \dim_new:N \l__suanpan_bid_h_half_dim \dim_new:N \l__suanpan_bid_d_half_dim \dim_new:N \l__suanpan_rod_d_half_dim \dim_new:N \l__suanpan_frame_b_half_dim % 上珠偏移 \dim_new:N \l__suanpan_bid_upper_offset_dim % 下珠偏移 \dim_new:N \l__suanpan_bid_lower_offset_dim % 上档杆长度 \dim_new:N \l__suanpan_rod_upper_h_dim % 下档杆长度 \dim_new:N \l__suanpan_rod_lower_h_dim % 上档杆偏移 \dim_new:N \l__suanpan_rod_upper_offset_dim % 下档杆偏移 \dim_new:N \l__suanpan_rod_lower_offset_dim % 上档杆位置 \dim_new:N \l__suanpan_rod_upper_dim % 下档杆位置 \dim_new:N \l__suanpan_rod_lower_dim % 上边框内线偏移 \dim_new:N \l__suanpan_frame_upper_inner_offset_dim % 下边框内线偏移 \dim_new:N \l__suanpan_frame_lower_inner_offset_dim % 上边框外线偏移 \dim_new:N \l__suanpan_frame_upper_outer_offset_dim % 下边框外线偏移 \dim_new:N \l__suanpan_frame_lower_outer_offset_dim % 算珠上边缘 \dim_new:N \l__suanpan_bid_upper_dim % 算珠下边缘 \dim_new:N \l__suanpan_bid_lower_dim % 算珠绘制高度 \dim_new:N \l__suanpan_bid_draw_h_dim % 算珠绘制半高度 \dim_new:N \l__suanpan_bid_draw_h_half_dim % 算珠圆角半径 \dim_new:N \l__suanpan_bid_arc_dim % 横梁计位点半径 \dim_new:N \l__suanpan_frame_unit_r_dim % 边框外线半宽度 \dim_new:N \l__suanpan_frame_outer_half_dim % 档杆总成宽度 \dim_new:N \l__suanpan_support_d_dim % 档杆总成半宽度 \dim_new:N \l__suanpan_support_d_half_dim % 档杆总成组装垂直偏移 \dim_new:N \l__suanpan_support_y_offset_dim % 上边框内线位置 \dim_new:N \l__suanpan_frame_inner_upper_dim % 下边框内线位置 \dim_new:N \l__suanpan_frame_inner_lower_dim % 边框内线高度 \dim_new:N \l__suanpan_frame_inner_h_dim % 边框外线高度 \dim_new:N \l__suanpan_frame_outer_h_dim \dim_new:N \l__suanpan_frame_inner_linewidth_dim \dim_new:N \l__suanpan_frame_outer_linewidth_dim \dim_new:N \l__suanpan_rod_linewidth_dim \dim_new:N \l__suanpan_bid_linewidth_dim % 状态变量 \bool_new:N \l__suanpan_support_frame_bool \bool_set_true:N \l__suanpan_support_frame_bool \bool_new:N \l__suanpan_support_unit_bool \bool_set_false:N \l__suanpan_support_unit_bool \bool_new:N \l__suanpan_draft_bool \bool_new:N \l__suanpan_empty_rod_bool % 容器(盒子) \coffin_new:N \l__suanpan_inner_bid_coffin \coffin_new:N \l__suanpan_outer_bid_coffin \coffin_new:N \l__suanpan_float_bid_coffin \coffin_new:N \l__suanpan_support_coffin \coffin_new:N \l_tmpc_coffin \coffin_new:N \l_tmpd_coffin % 凭据表(Token) \tl_new:N \l__suanpan_bid_draw_color_tl \tl_new:N \l__suanpan_bid_fill_color_tl \tl_new:N \l__suanpan_scale_tl \tl_new:N \l__suanpan_mark_font_tl % 档位最大值 \int_new:N \l__suanpan_rod_max_int \int_zero:N \l__suanpan_rod_max_int % 档位算珠位置列表 \clist_new:N \l__suanpan_bids_pos_clist % 档位数字与算珠位置对照属性表常量(内珠和外珠) % {x, y}==>x: 算珠位置(1-11, 1-7---下珠,8-10---上珠,11---悬珠) % y: 算珠类型(0---外珠,1---内珠) \prop_const_from_keyval:Nn \l__suanpan_rods_val_prop { 0 = {{1, 0}, {2, 0}, {3, 0}, {4, 0}, {5, 0}, {9, 0}, {10, 0}}, 1 = {{1, 0}, {2, 0}, {3, 0}, {4, 0}, {7, 1}, {9, 0}, {10, 0}}, 2 = {{1, 0}, {2, 0}, {3, 0}, {6, 1}, {7, 1}, {9, 0}, {10, 0}}, 3 = {{1, 0}, {2, 0}, {5, 1}, {6, 1}, {7, 1}, {9, 0}, {10, 0}}, 4 = {{1, 0}, {4, 1}, {5, 1}, {6, 1}, {7, 1}, {9, 0}, {10, 0}}, 5 = {{1, 0}, {2, 0}, {3, 0}, {4, 0}, {5, 0}, {8, 1}, {10, 0}}, 6 = {{1, 0}, {2, 0}, {3, 0}, {4, 0}, {7, 1}, {8, 1}, {10, 0}}, 7 = {{1, 0}, {2, 0}, {3, 0}, {6, 1}, {7, 1}, {8, 1}, {10, 0}}, 8 = {{1, 0}, {2, 0}, {5, 1}, {6, 1}, {7, 1}, {8, 1}, {10, 0}}, 9 = {{1, 0}, {4, 1}, {5, 1}, {6, 1}, {7, 1}, {8, 1}, {10, 0}}, 10 = {{3, 1}, {4, 1}, {5, 1}, {6, 1}, {7, 1}, {8, 1}, {10, 0}}, 11 = {{1, 0}, {2, 0}, {3, 0}, {4, 0}, {7, 1}, {8, 1}, {9 , 1}}, 12 = {{1, 0}, {2, 0}, {3, 0}, {6, 1}, {7, 1}, {8, 1}, {9 , 1}}, 13 = {{1, 0}, {2, 0}, {5, 1}, {6, 1}, {7, 1}, {8, 1}, {9 , 1}}, 14 = {{1, 0}, {4, 1}, {5, 1}, {6, 1}, {7, 1}, {8, 1}, {9 , 1}}, 15 = {{3, 1}, {4, 1}, {5, 1}, {6, 1}, {7, 1}, {8, 1}, {9 , 1}}, 16 = {{1, 0}, {2, 0}, {3, 0}, {4, 0}, {7, 1}, {8, 1}, {11, 1}}, 17 = {{1, 0}, {2, 0}, {3, 0}, {6, 1}, {7, 1}, {8, 1}, {11, 1}}, 18 = {{1, 0}, {2, 0}, {5, 1}, {6, 1}, {7, 1}, {8, 1}, {11, 1}}, 19 = {{1, 0}, {4, 1}, {5, 1}, {6, 1}, {7, 1}, {8, 1}, {11, 1}}, 20 = {{3, 1}, {4, 1}, {5, 1}, {6, 1}, {7, 1}, {8, 1}, {11, 1}} } % 尺寸计算函数 \cs_new:Nn \__suanpan_dim_calc: { % 基础尺寸半长度 \dim_set:Nn \l__suanpan_bid_h_half_dim { \l__suanpan_bid_h_dim / 2 } \dim_set:Nn \l__suanpan_bid_d_half_dim { \l__suanpan_bid_d_dim / 2 } \dim_set:Nn \l__suanpan_rod_d_half_dim { \l__suanpan_rod_d_dim / 2 } \dim_set:Nn \l__suanpan_frame_b_half_dim { \l__suanpan_frame_b_dim / 2 } % 上珠偏移(8号算珠) \dim_set:Nn \l__suanpan_bid_upper_offset_dim { \l__suanpan_frame_b_half_dim + \l__suanpan_bid_h_half_dim } % 下珠偏移(1号算珠) \dim_set:Nn \l__suanpan_bid_lower_offset_dim { -\l__suanpan_frame_b_half_dim - \l__suanpan_bid_h_dim * 7 + \l__suanpan_bid_h_half_dim } % 上档杆长度 \dim_set:Nn \l__suanpan_rod_upper_h_dim { \l__suanpan_bid_h_dim * 3 } % 下档杆长度 \dim_set:Nn \l__suanpan_rod_lower_h_dim { \l__suanpan_bid_h_dim * 7 } % 上档杆偏移 \dim_set:Nn \l__suanpan_rod_upper_offset_dim { \l__suanpan_frame_b_half_dim } % 下档杆偏移 \dim_set:Nn \l__suanpan_rod_lower_offset_dim { -\l__suanpan_frame_b_half_dim - \l__suanpan_rod_lower_h_dim } % 上档杆位置 \dim_set:Nn \l__suanpan_rod_upper_dim { \l__suanpan_rod_upper_offset_dim + \l__suanpan_rod_upper_h_dim } % 下档杆位置 \dim_set:Nn \l__suanpan_rod_lower_dim { -\l__suanpan_frame_b_half_dim } % 上边框内线偏移 \dim_set:Nn \l__suanpan_frame_upper_inner_offset_dim { \l__suanpan_frame_b_half_dim + \l__suanpan_rod_upper_h_dim } % 下边框内线偏移 \dim_set:Nn \l__suanpan_frame_lower_inner_offset_dim { -\l__suanpan_frame_b_half_dim - \l__suanpan_rod_lower_h_dim } % 上边框外线偏移 \dim_set:Nn \l__suanpan_frame_upper_outer_offset_dim { \l__suanpan_frame_b_dim + \l__suanpan_frame_b_half_dim + \l__suanpan_rod_upper_h_dim } % 下边框外线偏移 \dim_set:Nn \l__suanpan_frame_lower_outer_offset_dim { -\l__suanpan_frame_b_dim - \l__suanpan_frame_b_half_dim - \l__suanpan_rod_lower_h_dim } % 算珠上边缘 \dim_set:Nn \l__suanpan_bid_upper_dim { \l__suanpan_bid_h_half_dim - \l__suanpan_bid_sep_dim / 2 } % 算珠上边缘 \dim_set:Nn \l__suanpan_bid_lower_dim { -\l__suanpan_bid_h_half_dim + \l__suanpan_bid_sep_dim / 2 } % 算珠绘制高度 \dim_set:Nn \l__suanpan_bid_draw_h_dim { \l__suanpan_bid_upper_dim - \l__suanpan_bid_lower_dim } % 算珠绘制半高度 \dim_set:Nn \l__suanpan_bid_draw_h_half_dim { \l__suanpan_bid_draw_h_dim / 2 } % 算珠圆角半径 \dim_set:Nn \l__suanpan_bid_arc_dim { \l__suanpan_bid_draw_h_half_dim - 1pt} % 横梁计位点半径 \dim_set:Nn \l__suanpan_frame_unit_r_dim { \l__suanpan_frame_b_dim / 4 } % 边框外线半宽度 \dim_set:Nn \l__suanpan_frame_outer_half_dim { \l__suanpan_frame_outer_linewidth_dim / 2 } % 档杆总成宽度 \dim_set:Nn \l__suanpan_support_d_dim { \l__suanpan_bid_d_dim + \l__suanpan_rod_sep_dim } % 档杆总成半宽度 \dim_set:Nn \l__suanpan_support_d_half_dim { \l__suanpan_bid_d_half_dim + \l__suanpan_rod_sep_dim / 2 } % 档杆总成组装垂直偏移 \dim_set:Nn \l__suanpan_support_y_offset_dim { ( \l__suanpan_frame_upper_outer_offset_dim - \l__suanpan_frame_lower_outer_offset_dim + \l__suanpan_frame_outer_linewidth_dim ) / 2 - \l__suanpan_frame_upper_outer_offset_dim - \l__suanpan_frame_outer_half_dim } % 上边框内线位置 \dim_set:Nn \l__suanpan_frame_inner_upper_dim { \l__suanpan_frame_upper_inner_offset_dim + \l__suanpan_frame_inner_linewidth_dim / 2 } % 下边框内线位置 \dim_set:Nn \l__suanpan_frame_inner_lower_dim { \l__suanpan_frame_lower_inner_offset_dim - \l__suanpan_frame_inner_linewidth_dim / 2 } % 边框内线高度 \dim_set:Nn \l__suanpan_frame_inner_h_dim { \l__suanpan_rod_upper_h_dim + \l__suanpan_rod_lower_h_dim + \l__suanpan_frame_b_dim } % 边框外线高度 \dim_set:Nn \l__suanpan_frame_outer_h_dim { \l__suanpan_rod_upper_h_dim + \l__suanpan_rod_lower_h_dim + \l__suanpan_frame_b_dim * 3 } } % 选项处理 % ============宏包选项================= \keys_define:nn { suanpan } { % 草稿模式 draft .choice:, draft / true .code:n = {% \bool_set_true:N \l__suanpan_draft_bool \bool_set_false:N \l__suanpan_empty_rod_bool }, draft / false .code:n = {% \bool_set_false:N \l__suanpan_draft_bool \bool_set_true:N \l__suanpan_empty_rod_bool }, draft .default:n = true, draft .initial:n = false, % 是否绘制档的数值为0的空档算珠 empty .choice:, empty / true .code:n = { \bool_set_true:N \l__suanpan_empty_rod_bool }, empty / false .code:n = { \bool_set_false:N \l__suanpan_empty_rod_bool }, empty .default:n = true, empty .initial:n = true, unknown .code:n = { \msg_error:nn { suanpan } { unknown-option } } } % key_value选项设计 \keys_define:nn { suanpan } { % 绘图线宽 linewd .code:n = { % 算盘边框内线线宽 \dim_set:Nn \l__suanpan_frame_inner_linewidth_dim {#1} % 算盘边框外线线宽 \dim_set:Nn \l__suanpan_frame_outer_linewidth_dim { \fp_to_dim:n { \fp_eval:n {% \l__suanpan_frame_inner_linewidth_dim * 7.0 } } } % 档杆线宽 \dim_set:Nn \l__suanpan_rod_linewidth_dim { \fp_to_dim:n { \fp_eval:n {% \l__suanpan_frame_inner_linewidth_dim * 0.2 } } } % 算珠线宽 \dim_set:Nn \l__suanpan_bid_linewidth_dim { \fp_to_dim:n { \fp_eval:n {% \l__suanpan_frame_inner_linewidth_dim * 0.2 } } } % 计算其它尺寸 \__suanpan_dim_calc: }, linewd .initial:n = 2.0pt, % 算珠高度 bidh .code:n = {% \dim_set:Nn \l__suanpan_bid_h_dim { #1 } % 计算其它尺寸 \__suanpan_dim_calc: }, bidh .initial:n = 12mm, % 算珠直径 bidd .code:n = {% \dim_set:Nn \l__suanpan_bid_d_dim { #1 } % 计算其它尺寸 \__suanpan_dim_calc: }, bidd .initial:n = 23mm, % 档杆直径(应小于算珠直径bidd) rodd .code:n = {% \dim_set:Nn \l__suanpan_rod_d_dim { #1 } % 计算其它尺寸 \__suanpan_dim_calc: }, rodd .initial:n = 7mm, % 边框宽度 framew .code:n = {% \dim_set:Nn \l__suanpan_frame_b_dim { #1 } % 计算其它尺寸 \__suanpan_dim_calc: }, framew .initial:n = 13mm, % 档间间距 rodsep .code:n = {% \dim_set:Nn \l__suanpan_rod_sep_dim { #1 } % 计算其它尺寸 \__suanpan_dim_calc: }, rodsep .initial:n = 3.0pt, % 算珠间距 bidsep .code:n = {% \dim_set:Nn \l__suanpan_bid_sep_dim { #1 } % 计算其它尺寸 \__suanpan_dim_calc: }, bidsep .initial:n = 0.0pt, % 缩放参数 scale .tl_set:N = \l__suanpan_scale_tl, scale .initial:n = 1.0, % 边框绘图颜色 framedraw .code:n = { \__suanpan_color_select:nn { framecolor } {#1} }, framedraw .initial:n = black, framedraw* .code:n = { \__suanpan_color_select:nnn { framecolor } #1 }, % 档杆绘图颜色 roddraw .code:n = { \__suanpan_color_select:nn { roddrawcolor } {#1} }, roddraw .initial:n = black, roddraw* .code:n = { \__suanpan_color_select:nnn { roddrawcolor } #1 }, % 档杆填充颜色 rodfill .code:n = { \__suanpan_color_select:nn { rodfillcolor } {#1} }, rodfill .initial:n = black!20, rodfill* .code:n = { \__suanpan_color_select:nnn { rodfillcolor } #1 }, % 外珠绘图颜色 outerdraw .code:n = { \__suanpan_color_select:nn { outerdrawcolor } {#1} }, outerdraw .initial:n = black, outerdraw* .code:n = { \__suanpan_color_select:nnn { outerdrawcolor } #1 }, % 外珠填充颜色 outerfill .code:n = { \__suanpan_color_select:nn { outerfillcolor } {#1} }, outerfill .initial:n = black!40, outerfill* .code:n = { \__suanpan_color_select:nnn { outerfillcolor } #1 }, % 内珠绘图颜色 innerdraw .code:n = { \__suanpan_color_select:nn { innerdrawcolor } {#1} }, innerdraw .initial:n = black, innerdraw* .code:n = { \__suanpan_color_select:nnn { innerdrawcolor } #1 }, % 内珠填充颜色 innerfill .code:n = { \__suanpan_color_select:nn { innerfillcolor } {#1} }, innerfill .initial:n = black, innerfill* .code:n = { \__suanpan_color_select:nnn { innerfillcolor } #1 }, innerfill .initial:n = black, % 横梁标记字符格式 font .code:n = {% \tl_gset:Nn \l__suanpan_mark_font_tl {#1} }, font .initial:n = \bfseries\Large, unknown .code:n = { \msg_error:nn { suanpan } { unknown-option } } } % 出错输出信息 \msg_new:nnn { suanpan } { unknown-option } { package~ option~ "\l_keys_key_tl"~ is~ unknown. } % 选项默认值 \keys_set:nn { suanpan } { linewd = 2.0pt, rodsep = 3.0pt, bidsep = 1.8pt, scale = 1.0, empty = true, } % 将文档类选项传给suanpan \ProcessKeysOptions { suanpan } % 构建内珠(靠近横梁,参与计数)容器(盒子) \cs_new:Nn \__suanpan_inner_bid_construct: { \dim_set:Nn \l_tmpa_dim { \l__suanpan_bid_d_half_dim - \l__suanpan_bid_draw_h_half_dim } \tikzset{bid/.style = {% 内珠高光填充样式 inner~color = innerfillcolor!30, outer~color = innerfillcolor, draw = innerdrawcolor, line~width = \l__suanpan_bid_linewidth_dim, rounded~corners = \l__suanpan_bid_arc_dim, }, draftline/.style = {% 内珠草稿模式绘制样式 draw = innerfillcolor, line~cap = round,% 圆角线冒 line~width = \l__suanpan_bid_draw_h_dim, } } \group_begin: \hcoffin_gset:Nn \l__suanpan_inner_bid_coffin { % 判断是否为草稿模式 \bool_if:NTF \l__suanpan_draft_bool { \begin{tikzpicture} \draw[draftline] ( -\l_tmpa_dim, 0) -- ( \l_tmpa_dim, 0); \end{tikzpicture} }{ \begin{tikzpicture} \shadedraw[bid] ( -\l__suanpan_bid_d_half_dim, \l__suanpan_bid_lower_dim) rectangle ( \l__suanpan_bid_d_half_dim, \l__suanpan_bid_upper_dim); \end{tikzpicture} } } \group_end: } % 构建外珠(远离横梁,不参与计数)容器(盒子) \cs_new:Nn \__suanpan_outer_bid_construct: { \dim_set:Nn \l_tmpa_dim { \l__suanpan_bid_d_half_dim - \l__suanpan_bid_draw_h_half_dim } \tikzset{bid/.style ={ inner~color = outerfillcolor!30, outer~color = outerfillcolor, draw = outerdrawcolor, line~width = \l__suanpan_bid_linewidth_dim, rounded~corners = \l__suanpan_bid_arc_dim, }, draftline/.style = { draw = outerfillcolor, line~cap = round, line~width = \l__suanpan_bid_draw_h_dim, } } \group_begin: \hcoffin_gset:Nn \l__suanpan_outer_bid_coffin { % 判断是否为草稿模式 \bool_if:NTF \l__suanpan_draft_bool { \begin{tikzpicture} \draw[draftline] ( -\l_tmpa_dim, 0) -- ( \l_tmpa_dim, 0 ); \end{tikzpicture} }{ \begin{tikzpicture} \shadedraw[bid]% ( -\l__suanpan_bid_d_half_dim, \l__suanpan_bid_lower_dim) rectangle ( \l__suanpan_bid_d_half_dim, \l__suanpan_bid_upper_dim); \end{tikzpicture} } } \group_end: } % 构建浮珠容器(盒子) % 浮珠指可以在算盘中任意布置的算珠 % #1 绘制颜色 % #2 填充颜色 \cs_new:Npn \__suanpan_float_bid_construct:nn #1#2 { \dim_set:Nn \l_tmpa_dim { \l__suanpan_bid_d_half_dim - \l__suanpan_bid_draw_h_half_dim } \tikzset{bid/.style ={ line~width = \l__suanpan_bid_linewidth_dim, rounded~corners = \l__suanpan_bid_arc_dim, }, draftline/.style = { line~cap = round, line~width = \l__suanpan_bid_draw_h_dim, } } \group_begin: \hcoffin_gset:Nn \l__suanpan_float_bid_coffin { % 判断是否为草稿模式 \bool_if:NTF \l__suanpan_draft_bool { \begin{tikzpicture} \draw[draw=#2, draftline] ( -\l_tmpa_dim, 0) -- ( \l_tmpa_dim, 0 ); \end{tikzpicture} }{ \begin{tikzpicture} \shadedraw[draw = #1, inner~color=#2!30, outer~color=#2, bid]% ( -\l__suanpan_bid_d_half_dim, \l__suanpan_bid_lower_dim) rectangle ( \l__suanpan_bid_d_half_dim, \l__suanpan_bid_upper_dim); \end{tikzpicture} } } \group_end: } % 构建档杆容器(盒子) \cs_new:Nn \__suanpan_support_construct: { % TikZ绘图样式 \tikzset{% rod/.style = {% 档杆 inner~color = rodfillcolor!30, outer~color = rodfillcolor, draw = roddrawcolor, line~width = \l__suanpan_rod_linewidth_dim, }, beam/.style = {% 横梁 bottom~color = framecolor!60, top~color = framecolor!60, middle~color = framecolor!5, }, frame/.style = {% 上下梁 bottom~color = framecolor!95, top~color = framecolor!95, middle~color = framecolor!15, }, rodline/.style = {% 档杆边线 draw = roddrawcolor, line~width = \l__suanpan_rod_linewidth_dim, }, frameinner/.style = {% 内边框线 draw = framecolor, line~width = \l__suanpan_frame_inner_linewidth_dim, }, frameouter/.style = {% 外边框线 draw = framecolor, line~width = \l__suanpan_frame_outer_linewidth_dim, }, } \group_begin: \hcoffin_gset:Nn \l__suanpan_support_coffin { % 判断是否为草稿模式 \bool_if:NTF \l__suanpan_draft_bool { \begin{tikzpicture} % 绘制下杆 \draw[rodline] ( -\l__suanpan_rod_d_half_dim, \l__suanpan_rod_lower_offset_dim ) rectangle ( \l__suanpan_rod_d_half_dim, \l__suanpan_rod_lower_dim ); % 绘制上杆 \draw[rodline] ( -\l__suanpan_rod_d_half_dim, \l__suanpan_rod_upper_offset_dim ) rectangle ( \l__suanpan_rod_d_half_dim, \l__suanpan_rod_upper_dim ); % 绘制横梁 \draw[frameinner] ( -\l__suanpan_support_d_half_dim, \l__suanpan_frame_b_half_dim ) -- ( \l__suanpan_support_d_half_dim, \l__suanpan_frame_b_half_dim ); \draw[frameinner] ( -\l__suanpan_support_d_half_dim, -\l__suanpan_frame_b_half_dim ) -- ( \l__suanpan_support_d_half_dim, -\l__suanpan_frame_b_half_dim ); % 绘制上梁下边线 \draw[frameinner] ( -\l__suanpan_support_d_half_dim, \l__suanpan_frame_upper_inner_offset_dim ) -- ( \l__suanpan_support_d_half_dim, \l__suanpan_frame_upper_inner_offset_dim ); % 绘制上梁上边线 \draw[frameouter] ( -\l__suanpan_support_d_half_dim, \l__suanpan_frame_upper_outer_offset_dim - \l__suanpan_frame_outer_linewidth_dim / 2) -- ( \l__suanpan_support_d_half_dim, \l__suanpan_frame_upper_outer_offset_dim - \l__suanpan_frame_outer_linewidth_dim / 2); % 绘制下梁上边线 \draw[frameinner] ( -\l__suanpan_support_d_half_dim, \l__suanpan_frame_lower_inner_offset_dim ) -- ( \l__suanpan_support_d_half_dim, \l__suanpan_frame_lower_inner_offset_dim ); % 绘制下梁下边线 \draw[frameouter] ( -\l__suanpan_support_d_half_dim, \l__suanpan_frame_lower_outer_offset_dim + \l__suanpan_frame_outer_linewidth_dim / 2 ) -- ( \l__suanpan_support_d_half_dim, \l__suanpan_frame_lower_outer_offset_dim + \l__suanpan_frame_outer_linewidth_dim / 2 ); % 绘制计位点(黑色圆点) \bool_if:NT \l__suanpan_support_unit_bool { \fill[% fill=black, ] (0pt, 0pt) circle [radius = \l__suanpan_frame_unit_r_dim]; } \end{tikzpicture} }{ \begin{tikzpicture} % 绘制下杆 \shadedraw[rod] ( -\l__suanpan_rod_d_half_dim, \l__suanpan_rod_lower_offset_dim ) rectangle ( \l__suanpan_rod_d_half_dim, \l__suanpan_rod_lower_dim ); % 绘制上杆 \shadedraw[rod] ( -\l__suanpan_rod_d_half_dim, \l__suanpan_rod_upper_offset_dim ) rectangle ( \l__suanpan_rod_d_half_dim, \l__suanpan_rod_upper_dim ); % 绘制横梁 \shade[beam] ( -\l__suanpan_support_d_half_dim, -\l__suanpan_frame_b_half_dim ) rectangle ( \l__suanpan_support_d_half_dim, \l__suanpan_frame_b_half_dim ); \draw[frameinner] ( -\l__suanpan_support_d_half_dim, \l__suanpan_frame_b_half_dim ) -- ( \l__suanpan_support_d_half_dim, \l__suanpan_frame_b_half_dim ); \draw[frameinner] ( -\l__suanpan_support_d_half_dim, -\l__suanpan_frame_b_half_dim ) -- ( \l__suanpan_support_d_half_dim, -\l__suanpan_frame_b_half_dim ); % 绘制上梁下边线 \draw[frameinner] ( -\l__suanpan_support_d_half_dim, \l__suanpan_frame_upper_inner_offset_dim ) -- ( \l__suanpan_support_d_half_dim, \l__suanpan_frame_upper_inner_offset_dim ); % 绘制上梁上边线 \draw[frameouter] ( -\l__suanpan_support_d_half_dim, \l__suanpan_frame_upper_outer_offset_dim - \l__suanpan_frame_outer_linewidth_dim / 2) -- ( \l__suanpan_support_d_half_dim, \l__suanpan_frame_upper_outer_offset_dim - \l__suanpan_frame_outer_linewidth_dim / 2); % 绘制下梁上边线 \draw[frameinner] ( -\l__suanpan_support_d_half_dim, \l__suanpan_frame_lower_inner_offset_dim ) -- ( \l__suanpan_support_d_half_dim, \l__suanpan_frame_lower_inner_offset_dim ); % 绘制下梁下边线 \draw[frameouter] ( -\l__suanpan_support_d_half_dim, \l__suanpan_frame_lower_outer_offset_dim + \l__suanpan_frame_outer_linewidth_dim / 2 ) -- ( \l__suanpan_support_d_half_dim, \l__suanpan_frame_lower_outer_offset_dim + \l__suanpan_frame_outer_linewidth_dim / 2 ); % 绘制计位点(黑色圆点) \bool_if:NT \l__suanpan_support_unit_bool { \shade[% inner~color=black!40, outer~color=black!80, ] (0pt, 0pt) circle [radius = \l__suanpan_frame_unit_r_dim]; } \end{tikzpicture} } } \group_end: } % 绘制算珠 % #1: 算珠位置编号 % o o o o o o o | o o o % 1 2 3 4 5 6 7 8 9 10 % | o % 11 % 其中,11是悬珠位置 % #2: 算珠类型 % 0——外珠,1——内珠,2——浮珠 \cs_new:Npn \__suanpan_bid_layout:nn #1#2 { % 算珠垂直偏移 \int_compare:nNnTF { #1 } > { 7 } { \int_compare:nNnTF { #1 } < { 11 } { % 上珠 \dim_set:Nn \l_tmpb_dim{ \l__suanpan_bid_upper_offset_dim + \l__suanpan_bid_h_dim * (#1 - 8) } }{ % 悬珠 \dim_set:Nn \l_tmpb_dim{ \l__suanpan_frame_b_half_dim + \l__suanpan_bid_h_dim * 2 } } }{ % 下珠 \dim_set:Nn \l_tmpb_dim{ \l__suanpan_bid_lower_offset_dim + \l__suanpan_bid_h_dim * (#1 - 1) } } % 绘图算珠 \draw_scope_begin: \draw_transform_yshift:n { \l_tmpb_dim } \int_case:nnF { #2 } { { 0 } { \draw_coffin_use:Nnn \l__suanpan_outer_bid_coffin { hc } { vc } } { 1 } { \draw_coffin_use:Nnn \l__suanpan_inner_bid_coffin { hc } { vc } } { 2 } { \draw_coffin_use:Nnn \l__suanpan_float_bid_coffin { hc } { vc } } }{ \msg_error:nnn { suanpan } { bid-type-error } {#2} } \draw_scope_end: } \msg_new:nnn { suanpan } { bid-type-error } { #1~ bid~ type~ is~ unknown. } % 函数变体 \cs_generate_variant:Nn \__suanpan_bid_layout:nn {xx} % 组装一个档位 % #1: 档位编号(基于1,从左向右计数) % #2: 档位数字 \cs_new:Npn \__suanpan_assemble_rod:nn #1#2 { \tl_set:Nn \l_tmpb_tl { #2 } % 绘制 \draw_scope_begin: % 水平方向偏移 \draw_transform_xshift:n { \l__suanpan_support_d_dim * (#1 - 1) } % 档杆 \draw_coffin_use:Nnnn \l__suanpan_support_coffin { hc } { vc } { 0pt, -\l__suanpan_support_y_offset_dim } % 算珠 \int_compare:nNnTF { #2 } = { 0 } { % 判断0值空档算珠是否需要绘制 \bool_if:NT \l__suanpan_empty_rod_bool { % 取得档位数字对应算珠位置及内珠/外珠编号 \prop_get:NnN \l__suanpan_rods_val_prop { #2 } \l_tmpa_tl \clist_clear:N \l__suanpan_bids_pos_clist \clist_set:NV \l__suanpan_bids_pos_clist \l_tmpa_tl \clist_map_inline:Nn \l__suanpan_bids_pos_clist { \clist_set:Nn \l_tmpa_clist { ##1 } \__suanpan_bid_layout:xx { \clist_item:Nn \l_tmpa_clist { 1 } } { \clist_item:Nn \l_tmpa_clist { 2 } } } } }{ % 不是0值空档算珠,需要绘制 % 取得档位数字对应算珠位置及内珠/外珠编号 \prop_get:NnN \l__suanpan_rods_val_prop { #2 } \l_tmpa_tl \clist_clear:N \l__suanpan_bids_pos_clist \clist_set:NV \l__suanpan_bids_pos_clist \l_tmpa_tl \clist_map_inline:Nn \l__suanpan_bids_pos_clist { \clist_set:Nn \l_tmpa_clist { ##1 } \__suanpan_bid_layout:xx { \clist_item:Nn \l_tmpa_clist { 1 } } { \clist_item:Nn \l_tmpa_clist { 2 } } } } \draw_scope_end: } % 指定一个档位上浮珠的颜色 % #1: 档位编号(从左向右) % #2: 算珠位置([1, 11]) \cs_new:Npn \__suanpan_float_bid:nn #1#2 { \draw_scope_begin: % 水平偏移 \draw_transform_xshift:n { \l__suanpan_support_d_dim * ( #1 - 1 ) } % 覆盖绘制 \__suanpan_bid_layout:xx { #2 }{ 2 } \draw_scope_end: } % 为一个档位添加计数标记 % #1: 档位编号(基于1,从左向右) % #2: 标记内容 \cs_new:Npn \__suanpan_rod_mark:nn #1#2 { \hcoffin_set:Nn \l_tmpa_coffin { \begin{tikzpicture} \node at ( 0, 0 ) [font=\l__suanpan_mark_font_tl] { #2 }; \end{tikzpicture} } \draw_scope_begin: % 水平偏移 \draw_transform_xshift:n { \l__suanpan_support_d_dim * ( #1 - 1 ) } \draw_coffin_use:Nnn \l_tmpa_coffin { hc } { vc } \draw_scope_end: } % 绘制边框 % #1 第一档编号(左) % #2 最后一档编号(右) \cs_new:Npn \__suanpan_frame_layout:nn #1#2 { % TikZ绘制样式 \tikzset{% hframe/.style = {% 上下梁 bottom~color = framecolor!95, top~color = framecolor!95, middle~color = framecolor!15, draw = framecolor, line~width = \l__suanpan_frame_inner_linewidth_dim, }, vframe/.style = {% 左右梁 left~color = framecolor!95, right~color = framecolor!95, middle~color = framecolor!15, draw = framecolor, line~width = \l__suanpan_frame_inner_linewidth_dim, }, mframe/.style = {% 横梁 top~color = framecolor!60, bottom~color = framecolor!60, middle~color = framecolor!5, line~width = \l__suanpan_frame_inner_linewidth_dim, }, frameline/.style = {% 梁连线 draw = framecolor, line~width = \l__suanpan_frame_inner_linewidth_dim, }, framefill/.style = {% 外框填充 draw = framecolor, fill = framecolor, line~width = \l__suanpan_frame_inner_linewidth_dim, }, arcline/.style = {% 转角线 draw = framecolor, line~width = \l__suanpan_frame_inner_linewidth_dim, rounded~corners = \l__suanpan_frame_inner_linewidth_dim / 2, }, } % 总宽度 \dim_set:Nn \l_tmpa_dim { \fp_to_dim:n { \fp_eval:n { \l__suanpan_support_d_dim * ( #2 - #1 + 1.0) } } } % 减半档宽度 \dim_set:Nn \l_tmpb_dim { \fp_to_dim:n { \fp_eval:n { \l__suanpan_support_d_dim * ( #2 - #1 ) + \l__suanpan_support_d_half_dim} } } \group_begin: % 上下边框基础容器(盒子) \hcoffin_set:Nn \l_tmpa_coffin { % 判断是否为草稿模式 \bool_if:NTF \l__suanpan_draft_bool { \begin{tikzpicture} \draw[framefill] ( 0pt, 0pt ) -- ++( \l_tmpa_dim, 0) -- ++( \l__suanpan_frame_b_dim, \l__suanpan_frame_b_dim ) -- ++( -\l__suanpan_frame_b_dim, 0 ) -- ++( -\l_tmpa_dim, 0 ) -- ++( -\l__suanpan_frame_b_dim, 0 ) -- cycle; \end{tikzpicture} }{ \begin{tikzpicture} \shadedraw[hframe] ( 0pt, 0pt ) -- ++( \l_tmpa_dim, 0) -- ++( \l__suanpan_frame_b_dim, \l__suanpan_frame_b_dim ) -- ++( -\l__suanpan_frame_b_dim, 0 ) -- ++( -\l_tmpa_dim, 0 ) -- ++( -\l__suanpan_frame_b_dim, 0 ) -- cycle; \end{tikzpicture} } } % 左右边框基础容器(盒子) \hcoffin_set:Nn \l_tmpb_coffin { % 判断是否为草稿模式 \bool_if:NTF \l__suanpan_draft_bool { \begin{tikzpicture} \draw[framefill] ( 0, 0 ) -- ++( 0, \l__suanpan_frame_inner_h_dim) -- ++( -\l__suanpan_frame_b_dim, \l__suanpan_frame_b_dim ) -- ++( 0, -\l__suanpan_frame_outer_h_dim ) -- cycle; \draw[arcline] ( 0, 0 ) ++( 0, \l__suanpan_frame_inner_h_dim ) ++( 0, \l__suanpan_frame_b_dim ) ++( 0, \l__suanpan_frame_inner_linewidth_dim * 0.9 ) ++( -\l__suanpan_frame_b_half_dim, 0 ) -- ++( -\l__suanpan_frame_b_half_dim, 0 ) -- ++( -\l__suanpan_frame_inner_linewidth_dim * 0.9, 0 ) -- ++( 0, -\l__suanpan_frame_b_half_dim ); \draw[arcline] ( 0, 0 ) ++( 0, -\l__suanpan_frame_b_dim ) ++( 0, -\l__suanpan_frame_inner_linewidth_dim * 0.9 ) ++( -\l__suanpan_frame_b_half_dim, 0 ) -- ++( -\l__suanpan_frame_b_half_dim, 0 ) -- ++( -\l__suanpan_frame_inner_linewidth_dim * 0.9, 0 ) -- ++( 0, \l__suanpan_frame_b_half_dim ); \end{tikzpicture} }{ \begin{tikzpicture} \shadedraw[vframe] ( 0, 0 ) -- ++( 0, \l__suanpan_frame_inner_h_dim) -- ++( -\l__suanpan_frame_b_dim, \l__suanpan_frame_b_dim ) -- ++( 0, -\l__suanpan_frame_outer_h_dim ) -- cycle; \draw[arcline] ( 0, 0 ) ++( 0, \l__suanpan_frame_inner_h_dim ) ++( 0, \l__suanpan_frame_b_dim ) ++( 0, \l__suanpan_frame_inner_linewidth_dim * 0.9 ) ++( -\l__suanpan_frame_b_half_dim, 0 ) -- ++( -\l__suanpan_frame_b_half_dim, 0 ) -- ++( -\l__suanpan_frame_inner_linewidth_dim * 0.9, 0 ) -- ++( 0, -\l__suanpan_frame_b_half_dim ); \draw[arcline] ( 0, 0 ) ++( 0, -\l__suanpan_frame_b_dim ) ++( 0, -\l__suanpan_frame_inner_linewidth_dim * 0.9 ) ++( -\l__suanpan_frame_b_half_dim, 0 ) -- ++( -\l__suanpan_frame_b_half_dim, 0 ) -- ++( -\l__suanpan_frame_inner_linewidth_dim * 0.9, 0 ) -- ++( 0, \l__suanpan_frame_b_half_dim ); \end{tikzpicture} } } % 横梁接头基础容器(盒子) \hcoffin_set:Nn \l_tmpc_coffin { % 判断是否为草稿模式 \bool_if:NTF \l__suanpan_draft_bool { \begin{tikzpicture} \fill[fill=white, line~width=\l__suanpan_frame_inner_linewidth_dim] ( 0pt, 0pt ) --++( 0, \l__suanpan_frame_b_dim) -- ++(-\l__suanpan_frame_inner_linewidth_dim, 0) -- ++(-\l__suanpan_frame_b_dim / 3, -\l__suanpan_frame_b_dim / 2) -- ++( \l__suanpan_frame_b_dim / 3, -\l__suanpan_frame_b_dim / 2) -- cycle; \draw[frameline]% ( 0, \l__suanpan_frame_b_dim) -- ++(-\l__suanpan_frame_inner_linewidth_dim, 0) -- ++(-\l__suanpan_frame_b_dim / 3, -\l__suanpan_frame_b_dim / 2) -- ++( \l__suanpan_frame_b_dim / 3, -\l__suanpan_frame_b_dim / 2) -- ++( \l__suanpan_frame_inner_linewidth_dim, 0); \end{tikzpicture} }{ \begin{tikzpicture} \shade[mframe] ( 0pt, 0pt ) --++( 0, \l__suanpan_frame_b_dim) -- ++(-\l__suanpan_frame_inner_linewidth_dim, 0) -- ++(-\l__suanpan_frame_b_dim / 3, -\l__suanpan_frame_b_dim / 2) -- ++( \l__suanpan_frame_b_dim / 3, -\l__suanpan_frame_b_dim / 2) -- cycle; \draw[frameline]% ( 0, \l__suanpan_frame_b_dim) -- ++(-\l__suanpan_frame_inner_linewidth_dim, 0) -- ++(-\l__suanpan_frame_b_dim / 3, -\l__suanpan_frame_b_dim / 2) -- ++( \l__suanpan_frame_b_dim / 3, -\l__suanpan_frame_b_dim / 2) -- ++( \l__suanpan_frame_inner_linewidth_dim, 0); \end{tikzpicture} } } % 布置上边框 \draw_scope_begin: \draw_transform_xshift:n { -\l__suanpan_support_d_half_dim - \l__suanpan_frame_inner_linewidth_dim / 2 } \draw_transform_yshift:n { \l__suanpan_frame_inner_upper_dim - \l__suanpan_frame_inner_linewidth_dim } \draw_coffin_use:Nnnn \l_tmpa_coffin { l } { b } { -\l__suanpan_frame_b_dim, 0pt } \draw_scope_end: % 布置下边框 \draw_scope_begin: \coffin_rotate:Nn \l_tmpa_coffin { 180 } \draw_transform_xshift:n { \l_tmpa_dim - \l__suanpan_support_d_half_dim + \l__suanpan_frame_inner_linewidth_dim / 2 } \draw_transform_yshift:n { \l__suanpan_frame_inner_lower_dim + \l__suanpan_frame_inner_linewidth_dim } \draw_coffin_use:Nnnn \l_tmpa_coffin { l } { b } { \l__suanpan_frame_b_dim, 0pt } \draw_scope_end: % 布置左边框 \draw_scope_begin: \draw_transform_xshift:n { -\l__suanpan_support_d_half_dim - \l__suanpan_frame_b_dim - \l__suanpan_frame_inner_linewidth_dim * 1.5 } \draw_transform_yshift:n { \l__suanpan_frame_inner_lower_dim - \l__suanpan_frame_inner_linewidth_dim } \draw_coffin_use:Nnnn \l_tmpb_coffin { l } { b } { 0pt, -\l__suanpan_frame_b_dim } \draw_scope_end: % 布置右边框 \draw_scope_begin: \coffin_rotate:Nn \l_tmpb_coffin { 180 } \draw_transform_xshift:n { \l_tmpb_dim + \l__suanpan_frame_b_dim + \l__suanpan_frame_inner_linewidth_dim * 1.5}% - \draw_transform_yshift:n { \l__suanpan_frame_inner_upper_dim + \l__suanpan_frame_inner_linewidth_dim } \draw_coffin_use:Nnnn \l_tmpb_coffin { l } { b } { 0pt, \l__suanpan_frame_b_dim } \draw_scope_end: % 布置左横梁接头 \draw_scope_begin: \draw_transform_xshift:n { -\l__suanpan_support_d_half_dim - \l__suanpan_frame_b_dim / 3 - \l__suanpan_frame_inner_linewidth_dim / 2 } \draw_transform_yshift:n { -\l__suanpan_frame_b_dim / 2 - \l__suanpan_frame_inner_linewidth_dim / 2 } \draw_coffin_use:Nnnn \l_tmpc_coffin { l } { b } { 0pt, 0pt } \draw_scope_end: % 布置右横梁接头 \draw_scope_begin: \coffin_rotate:Nn \l_tmpc_coffin { 180 } \draw_transform_xshift:n { \l_tmpb_dim + \l__suanpan_frame_b_dim / 3 + \l__suanpan_frame_inner_linewidth_dim / 2 } \draw_transform_yshift:n { \l__suanpan_frame_b_dim / 2 + \l__suanpan_frame_inner_linewidth_dim / 2 } \draw_coffin_use:Nnnn \l_tmpc_coffin { l } { b } { 0pt, 0pt } \draw_scope_end: \group_end: } % 算盘排版用户接口 % 算盘排版环境 % #1 suanpan环境选项 % #2 suanpan环境内容(!b参数) \NewDocumentEnvironment{ suanpan }{ o !b } { \group_begin: % 设置选项 \IfNoValueF{ #1 } { \keys_set:nn { suanpan }{ #1 } } % 构造基础容器(盒子) \__suanpan_inner_bid_construct: \__suanpan_outer_bid_construct: \__suanpan_support_construct: % 删除#2(!b)参数取得的环境内容中的空白 \str_set:Nn \l_tmpa_str { #2 } \str_remove_all:Nn \l_tmpa_str {~} % 将str还原为tl \tl_set_rescan:Nno \l_tmpa_tl {}{ \l_tmpa_str } % 在容器(盒子)中用#2(!b)参数取得的按环境内容实现绘制 \hcoffin_set:Nn \l_tmpa_coffin { \draw_begin: \l_tmpa_tl \draw_end: } \hcoffin_set:Nn \l_tmpb_coffin { % 将原图缩小50% \coffin_scale:Nnn \l_tmpa_coffin { 0.50 } { 0.50 } \coffin_typeset:Nnnnn \l_tmpa_coffin{ l }{ b }{ 0pt }{ 0pt } } }{ % 按用户指定比例缩放 \coffin_scale:Nnn \l_tmpb_coffin { \l__suanpan_scale_tl } { \l__suanpan_scale_tl } % 设置基字符盒子(排版深度) \hbox_set:Nn \l_tmpa_box { x } % 盒子深度 \dim_set:Nn \l_tmpa_dim { \box_dp:N \l_tmpa_box} % 输出算盘容器(盒子) \coffin_typeset:Nnnnn \l_tmpb_coffin{ l }{ b }{ 0pt }{ -\l_tmpa_dim } \int_zero:N \l__suanpan_rod_max_int \group_end: } % 排版算盘一个档位,包括档杆和算珠 % #1 星号命令,绘制计位点(黑色圆点) % #2 档位编号(基于1,从左向右计数) % #3 本档数字(0-20,10-15需用到顶珠和底珠,16-20需要用到悬珠) \NewDocumentCommand{ \rod }{ s m m } { % 记录原状态变量 \bool_set_eq:NN \l_tmpa_bool \l__suanpan_support_unit_bool % 星号命令,用于在横梁绘制计位点 \IfBooleanTF{#1} { \bool_set_true:N \l__suanpan_support_unit_bool }{ \bool_set_false:N \l__suanpan_support_unit_bool } % 如状态发生改变,则重新绘制档杆单元 \bool_if:NTF \l_tmpa_bool { \bool_if:NF \l__suanpan_support_unit_bool { \__suanpan_support_construct: } }{ \bool_if:NT \l__suanpan_support_unit_bool { \__suanpan_support_construct: } } % 组装一个档位 \__suanpan_assemble_rod:nn { #2 }{ #3 } % 统计档位总数 \int_set:Nn \l__suanpan_rod_max_int { \int_max:nn { \l__suanpan_rod_max_int }{ #2 } } } % 排版算盘多个档位,包括档杆和算珠 % #1 本档数字(0-20,10-15需用到顶珠和底珠,16-20需要用到悬珠) % 各数字之间需要用逗号分隔。 \NewDocumentCommand{ \rods }{ m } { % 构造档位数字列表 \clist_set:Nn \l_tmpa_clist { #1 } % 初始化档位计数器 \int_set:Nn \l_tmpa_int { 0 } \clist_map_inline:Nn \l_tmpa_clist { % 档位计数器自增1 \int_incr:N \l_tmpa_int % 组装当前档位 \__suanpan_assemble_rod:nn {\l_tmpa_int }{ ##1 } } % 记录档位总数 \int_set:Nn \l__suanpan_rod_max_int { \int_max:nn { \l__suanpan_rod_max_int }{ \l_tmpa_int } } } % 指定某档上某个算珠的颜色 % #1 档位(基于1,从左向右计数) % #2 算珠位置列表(1--11,11为悬珠位置) % #3 算珠填充颜色 % #4 算珠绘制颜色(默认为内珠绘制颜色) \NewDocumentCommand{ \bid }{ m m m O{innerdrawcolor} } { % 构造浮珠 \__suanpan_float_bid_construct:nn { #4 }{ #3 } % 构造算珠位置列表 \clist_set:Nn \l_tmpa_clist { #2 } \clist_map_inline:Nn \l_tmpa_clist { % 绘制浮珠 \__suanpan_float_bid:nn { #1 }{ ##1 } } } % 指定某档上所有内珠或外珠的颜色 % #1 星号命令,选择内珠或外珠 % #2 档位(基于1,从左向右计数) % #3 该档数字 % #4 算珠填充颜色(绘图颜色采用原内/外珠绘制颜色) \NewDocumentCommand{ \bids }{ s m m m } { % 取得档位数字对应算珠位置及内珠/外珠编号 \prop_get:NnN \l__suanpan_rods_val_prop { #3 } \l_tmpa_tl \clist_clear:N \l__suanpan_bids_pos_clist \clist_set:NV \l__suanpan_bids_pos_clist \l_tmpa_tl % 星号命令,用于选择外珠着色 \IfBooleanTF{#1} { % 构造浮珠 \__suanpan_float_bid_construct:nn { outerdrawcolor }{ #4 } \clist_map_inline:Nn \l__suanpan_bids_pos_clist { \clist_set:Nn \l_tmpa_clist { ##1 } % 选择外珠 \int_compare:nNnT { \clist_item:Nn \l_tmpa_clist { 2 } } = { 0 } { \__suanpan_float_bid:nn { #2 }{ \clist_item:Nn \l_tmpa_clist { 1 } } } } }{ % 构造浮珠 \__suanpan_float_bid_construct:nn { innerdrawcolor }{ #4 } \clist_map_inline:Nn \l__suanpan_bids_pos_clist { \clist_set:Nn \l_tmpa_clist { ##1 } % 选择内珠 \int_compare:nNnT { \clist_item:Nn \l_tmpa_clist { 2 } } = { 1 } { \__suanpan_float_bid:nn { #2 }{ \clist_item:Nn \l_tmpa_clist { 1 } } } } } } % 左右边框 \NewDocumentCommand{ \mkframe }{ } { \__suanpan_frame_layout:nn { 1 }{ \l__suanpan_rod_max_int } } % 为各档添加计位标记 % #1 起始档位(基于1,从左向右计数) % #2 标记列表 \NewDocumentCommand{ \rodmark }{ O{1} m } { % 标记列表 \clist_set:Nn \l_tmpa_clist { #2 } % 计数器 \int_set:Nn \l_tmpa_int { #1 } % 遍历列表 \clist_map_inline:Nn \l_tmpa_clist { % 输出标记 \__suanpan_rod_mark:nn { \l_tmpa_int }{ ##1 } % 调整计数器 \int_incr:N \l_tmpa_int % 超出最大档位 \int_compare:nNnT { \l_tmpa_int } > { \l__suanpan_rod_max_int } { \clist_map_break: } } } % 选项设置用户接口 \NewDocumentCommand{ \suanpanset } { m } { \IfNoValueF { #1} { \keys_set:nn { suanpan } { #1 } } } \endinput