100 如何使用l3coffin找到合适的锚点拼接以实现嵌套积分号排版

发布于 2024-09-19 21:39:43

先前遇到过一个如下的嵌套积分号排版效果图

image.png

在尝试学习了l3coffin后实现已经实现了从对于coffin中的积分号,先后在其右上和右下位置处添加新的coffin连接的"轮子",如下面的代码:

\documentclass{article}
\usepackage[margin=2cm,a2paper]{geometry}
\usepackage{amsmath}
\usepackage{xcolor}
\usepackage{xcoffins}
\usepackage{graphicx}
\newcommand{\diffx}{$\mathrm{d}x$}
\newcommand{\myint}[1][8]{\scalebox{#1}{$\int$}}
\newcommand{\numzero}[1][8]{\scalebox{#1}{$0$}}
\newcommand{\numone}[1][8]{\scalebox{#1}{$1$}}
\begin{document}
\ExplSyntaxOn
%改进\coffin_reset_poles:N的c功能并将其封装为\my_coffin_reset:n
\cs_generate_variant:Nn \coffin_reset_poles:N {c}
\cs_new:Nn \my_coffin_reset:n % <coffin>
{
    \coffin_reset_poles:c {l_tmp#1_coffin}
}
\cs_set_nopar:Nn \newSetCof:nn {
    %重新封装coffins命令,若不存在,则新建名为l_tmp#1_coffin的新coffin
    %之后设置hcoffin的matrial内容为#2
    \coffin_if_exist:cF {l_tmp#1_coffin}
    {\coffin_new:c {l_tmp#1_coffin}}
    \hcoffin_set:cn {l_tmp#1_coffin}{#2}
}
\cs_set_nopar:Nn \useCof:n {
    %控制输出coffin,默认按照手柄位置handles{l,b}进行对齐
    %\coffin_typeset:cnnnn {l_tmp#1_coffin} {l} {b} {0pt} {0pt}
    \coffin_display_handles:cn {l_tmp#1_coffin} {magenta}
}
\cs_set_nopar:Nn \setIntPolesUpper:n {%设置上半对齐点位
    \my_coffin_reset:n {#1}
    \coffin_set_horizontal_pole:cnn {l_tmp#1_coffin}{upperh}{0.95 \coffin_ht:c {l_tmp#1_coffin}}% 0.8 height pole set
    \coffin_set_vertical_pole:cnn {l_tmp#1_coffin}{upperv}{0.88 \coffin_wd:c {l_tmp#1_coffin}}
    % then we can use the handle (upperv,upperh) for the upper one
}
\cs_set_nopar:Nn \setIntPolesLower:n {
    \my_coffin_reset:n {#1}%设置下半对齐点位
    \coffin_set_horizontal_pole:cnn {l_tmp#1_coffin}{lowerh}{-0.3 \coffin_ht:c {l_tmp#1_coffin}}% -0.25 height pole set
    % \coffin_set_vertical_pole:Nnn {\l_tmpI_coffin}{baselow}{0pt}
    \coffin_set_vertical_pole:cnn {l_tmp#1_coffin}{lowerv}{0.85 \coffin_wd:c {l_tmp#1_coffin}}
    % then we can use the handle (lowerv,lowerh) for the upper one
}
%关键的核心封装命令\intgral_coffin_join:nnn <intgral-within-coffin> <content1> <content2> 
\cs_new:Nn \intgral_coffin_join:nnn {
    % #1=base #2 = \myint[4] #3 = \numone[4]
    %处理流程:
    %(1) reset coffin poles with base
    \my_coffin_reset:n {#1}
    %(2) new_coffin_with_tmpA with matrial #2
    \newSetCof:nn {A} {#2}
    %(3) join base with upper_part tmpA with handles (upperv,upperh) (l,vc)
    \setIntPolesUpper:n {#1}

    \coffin_join:cnncnnnn {l_tmp#1_coffin} {upperv} {upperh} {l_tmpA_coffin} {l} {vc} {0pt} {0pt}
    %(4) reset coffin poles with base
    \my_coffin_reset:n {#1}
    % %(5) new_coffin_with_tmpB with matrial #3
    \newSetCof:nn {B} {#3}
    % %(6) join base with lower_part tmpB with handles (lowerv,lowerh) (l,vc)
    \setIntPolesLower:n {#1}
    \coffin_join:cnncnnnn {l_tmp#1_coffin} {lowerv} {lowerh} {l_tmpB_coffin} {l} {vc} {0pt} {0pt}
    %(7) reset coffin poles with base
    \my_coffin_reset:n {#1}
    % return => joined and poles-reset coffin "base"
}

\newSetCof:nn {base}{\myint}
\my_coffin_reset:n {base}
\useCof:n {base}

% test for command \intgral_coffin_join
% \intgral_coffin_join:nnn {base}{\myint[4]}{\numone[4]}
% \useCof:n {base}

\int_step_inline:nn {6}{
    \intgral_coffin_join:nnn {base}{\myint[5]}{\myint[5]}
    \useCof:n {base} \par
}
\ExplSyntaxOff
\end{document}

其中关键代码已做注释,\intgral_coffin_join:nnn用于实现一次coffin的拼接,实现的效果如下:
image.png

现阶段存在的问题是:

  • 在默认的积分号的倾斜角度下,是否容易找到合适的定位superscript和subscript的pattern(例如使用的水平或者垂直pole进行定位的距离符合某一等比数列),或者改用垂直积分号(?)
  • 使用递归(?)等方式找到原图的重复规律(这种规律不一定是确实存在的,原图的转发者透露该图是使用类似photoshop等软件制作的)只要能实现这种类似"分形"的效果就可以

由于本人实在是穷,只能小小献上50积分...

有关可汇总和参考的代码如下压缩包文件nested-integral.zip

(Un)Happy TeXing!

查看更多

关注者
0
被浏览
386
1 个回答
Eureka
Eureka 2024-09-20
这家伙很懒,什么也没写!

目前给一个比较粗糙的答案, 使用的是递归生成的, 生成的效果大概如下:

  • 支持分支,不可以指定上下限

image.png

这种情况下可以用上一些 PS 的手段,然后就可以得到像下面这样的结果:
image.png

  • 不支持分支,可以指定上下限

image.png

完整的可编译代码如下:

\documentclass{article}
\usepackage{amsmath}
\usepackage[a3paper, margin=1in]{geometry}



\ExplSyntaxOn
\int_new:N \g_recursion_depth_int
\int_gset:Nn \g_recursion_depth_int {0}
\seq_new:N \g_data_collect_I_seq
\seq_new:N \g_data_collect_II_seq

% ==> fractuation integral
% ARGUMENTS SPECIFICATION
% #1 -> subscript
% #2 -> superscript
% #3 -> total depth
\NewDocumentCommand\NEWINT{mmm}{
  \int_compare:nTF {\g_recursion_depth_int <= #3}{
    \int_gadd:Nn \g_recursion_depth_int {1}
    \_split_int_fractal_tree:ennn 
      {\_split_list}{#1}{#2}{#3}
  }{
    \int
      \c_math_subscript_token{#1}
      \c_math_superscript_token{#2}
  }
}
\NewDocumentCommand\_split_list{}{}
\DeclareDocumentCommand\SplitList{m}{
  \renewcommand\_split_list{#1}
}
% ==> split tree using a int array
% ARGUMENTS SPECIFICATION
% #1 -> places to split the tree
% #2 -> subscript
% #3 -> superscript
% #4 -> total depth
\cs_new_protected:Npn \_split_int_fractal_tree:nnnn #1#2#3#4 {
  \clist_if_in:nVTF {#1}\g_recursion_depth_int {
    \NEWINT
        {\int\c_math_subscript_token {
            #2 \c_math_superscript_token{#3}
          }
        }
        {\int\c_math_superscript_token {#3 \c_math_subscript_token {#2}}}
        {#4}
  }{
    \int_compare:nTF {\g_recursion_depth_int = 1}{
      \NEWINT
        {\int\c_math_subscript_token {#2}\c_math_superscript_token{1}\!x\mathrm{d}x}
        {\int\c_math_superscript_token {#3}\c_math_subscript_token{0}\!x\mathrm{d}x}
        {#4}
    }{
      \NEWINT
        {\int\c_math_subscript_token   {#2}\c_math_superscript_token{\scriptscriptstyle 1}}
        {\int\c_math_superscript_token {#3}\c_math_subscript_token{\scriptscriptstyle 0}}
        {#4}
    }
  }
}
\cs_generate_variant:Nn \_split_int_fractuation_tree:nnnn {ennn}
\makeatletter
\newcommand{\raisemath}[1]{\mathpalette{\raisem@th{#1}}}
\newcommand{\raisem@th}[3]{\raisebox{#1}{$#2#3$}}
\makeatother
\ExplSyntaxOff


\begin{document}
% \SplitList{5, 10, 25, 50}
\[
  \NEWINT{\beta}{\alpha}{20}
\]


\begin{align}
  & \int_a^b x \\
  & \int_a^{\raisemath{-10pt}{b}} x
\end{align}
\end{document}
  • l3coffin 的思路我还没有去尝试,后续我也许会换到这个方向上来试一试.
  • 关于积分上下限的位置,目前可以使用 \raisemath{}{} 这个函数

撰写答案

请登录后再发布答案,点击登录

发布
问题

分享
好友

手机
浏览

扫码手机浏览