我正在尝试了解如何定义具有可变数量参数的 PGF 函数。以下是我正在尝试执行的操作的一个最小工作示例:
\documentclass{minimal}
\usepackage{pgfmath}
\pgfmathdeclarefunction{theFnIDef}{...}{%
\begingroup
\pgfmatharray{#1}{0}%
% \pgfmatharray{#1}{1}% <--- This line always fails
\pgfmathsmuggle\pgfmathresult
\endgroup
}
\begin{document}
theFnIDef(2,3): \pgfmathparse{theFnIDef(2,3)}\pgfmathresult
theFnIDef(2,3,5,8): \pgfmathparse{theFnIDef(2,3,5,8)}\pgfmathresult
\end{document}
这总是输出:
FnIDef(2,3): 3
FnIDef(2,3,5,8):8
这基本上是最后一个元素。我尝试了其他语法(\pgfmathparse{array(#1,1)}
)并使用附加花括号(\pgfmathparse{theFnIDef({2,3})}
)调用该函数,但没有任何效果。
在 3.1.9a 版的文档第 1050 页中,有如下内容:
...尽管这是一个相当简单的任务...
正如我从文档中截取的屏幕截图所示:
但我似乎不知道该怎么做。如果有人能帮忙,那就太好了。
答案1
您需要使用该array
函数的内部定义做期望其第一个参数是括号元素的列表,即
{2}{3}
和
{2}{3}{5}{8}
在您的情况下,这正是您的theFnIDef
函数的内部定义必须处理的问题(因为这是您一直所做的事情\pgfmathdeclarefunction{<name>}
,您实际上定义了\pgfmath<name>@
)。
所以
\pgfmatharray@{#1}{<num>}%
<num>
将通过将参数的第个元素存储在 中来为您提供它\pgfmathresult
。
该函数本身只是循环遍历所有给定的内容,直到到达您所要求的内容。array@
{…}
在下面的代码中,我#1
使用函数获取数组的大小(应用相同的规则→使用内部函数),该函数也循环遍历所有元素,每次完成时都会增加一个计数器dim@
柜台是一个元素。
这是一种访问所有参数的非常低效(O(n²)?)的方法,因为它涉及多个对实际元素不执行任何操作的循环。
但是为了更有效(或更容易?)地使用所有元素,需要对函数进行实际定义。
这段代码什么也不做,只是返回参数的数量(基本上只是第一次调用dim@
)并将元素写入日志。
无论如何,在迭代参数时,最好也做一些处理。在我的另一个答案十个参数中的最后八个参数被简单地转发给其他函数(需要八个参数)。这是通过函数\pgfmath@util@…
(和位扩展控制)完成的。
还有一个\pgfmathloop
…\repeatpgfmathloop
有自己的自增计数器\pgfmathcounter
(不是 TeX 计数!)但它从 1 开始,而不是从 0 开始,所以我们需要
\pgfmatharray@{#1}{\numexpr\pgfmathcounter-1\relax}%
在循环中(和\the\numexpr\pgfmathcounter-1\relax
中\typeout
)获取数组索引的 PGFmath 编号。
我选择了\pgfutil@loop
(它应该等于 LaTeX,\@loop
但在所有可以运行 PGFmath 的平台上定义。
代码
\documentclass{article}
\usepackage{pgfmath}
\makeatletter
\pgfmathdeclarefunction{theFnIDef}{...}{%
\begingroup
\pgfmathdim@{#1}%
\let\pgfmatharraysize\pgfmathresult
\typeout{Array #1 has \pgfmatharraysize\space elements.}%
\c@pgf@countb=0
\pgfutil@loop
\pgfmatharray@{#1}{\c@pgf@countb}%
\typeout{Argument No \the\c@pgf@countb\space is \pgfmathresult.}%
\advance\c@pgf@countb by 1
\ifnum\c@pgf@countb<\pgfmatharraysize\relax
\pgfutil@repeat
\let\pgfmathresult\pgfmatharraysize
\pgfmathsmuggle\pgfmathresult % will just return the number of elements
\endgroup
}
\makeatother
\begin{document}
theFnIDef(2,3): \pgfmathprint{theFnIDef(2,3)}
theFnIDef(2,3,5,8): \pgfmathprint{theFnIDef(2,3,5,8)}
\end{document}
输出(日志)
Array {2}{3} has 2 elements.
Argument No 0 is 2.
Argument No 1 is 3.
Array {2}{3}{5}{8} has 4 elements.
Argument No 0 is 2.
Argument No 1 is 3.
Argument No 2 is 5.
Argument No 3 is 8.