TikZ/PGF:创建保存的长度作为形状定义的一部分

TikZ/PGF:创建保存的长度作为形状定义的一部分

当我使用 pgfdeclareshape 创建新形状时,我希望能够存储长度以供以后参考。我可能想稍后对此长度进行简单的算术运算。这是一个基本的尝试:

 \pgfdeclareshape{MyShape}
 {
    \saveddimen\mydimen
    {
        \pgf@x = 10pt
    }
    \backgroundpath
    {
        \pgfpathmoveto
            {\pgfpoint{0pt}{0pt}}
        \pgfpathlineto
            {\pgfpoint{2\mydimen}{0pt}}
        \pgfusepath{stroke}
    }
 }

其目的是生成一条 20pt 长的线 - 但实际上它画了一条 210pt 长的线,大概是因为 \mydimen 将值 10pt 存储为计划文本,而不是尺寸。

如何在创建形状时保存尺寸数量?

答案1

您说得对,\pgfdeclareshape将其保存为宏而不是长度。我不知道为什么会这样(但我猜是因为创建大量新宏比创建大量新长度更容易)。只要您意识到这一点,这不是问题。您只需要记住在而不是长度。幸运的是,\pgfpoint它通过 PGFMath 传递其参数,因此您在此示例中实际需要做的就是添加乘法:

\documentclass{article}

\usepackage{tikz}
\makeatletter
\pgfdeclareshape{MyShape}
 {
    \saveddimen\mydimen
    {
        \pgf@x = 10pt
    }
    \backgroundpath
    {
        \pgfpathmoveto
            {\pgfpoint{0pt}{0pt}}
        \pgfpathlineto
            {\pgfpoint{2*\mydimen}{0pt}}
        \pgfpathmoveto
            {\pgfpoint{0pt}{-5pt}}
        \pgfpathlineto
            {\pgfpoint{2\mydimen}{-5pt}}
        \pgfpathmoveto
            {\pgfpoint{0pt}{-10pt}}
        \pgfpathlineto
            {\pgfpoint{\mydimen}{-10pt}}
        \pgfusepath{stroke}
    }
 }
\makeatother

\begin{document}
\begin{tikzpicture}
\node[MyShape,draw] {};
\end{tikzpicture}
\end{document}

(忽略有关缺少锚点的错误!)这会产生三条线,最上面的一条是您想要的线,中间的是您的原始线,最下面的一条是“参考”线,以显示最上面的一条确实是最下面的一条的两倍。

如果您使用的是\pgfqpoint-,它比\pgfpoint- 更快,那么您就必须担心从宏转换为长度,因为它不使用 PGFMath。在这种情况下,您可以执行以下操作:

\pgf@xa=\mydimen\relax
\pgf@xa=2\pgf@xa
\pgfpathmoveto{\pgfqpoint{\pgf@xa}{0pt}}

以达到同样的效果。

答案2

正如您所指出的, s\saveddimen不是实际维度。为每个形状甚至每个节点分配一个维度寄存器会耗费太多精力和开销。您可以使用\dimexpr\yoursaveddimen\relax它来生成一个实际维度表达式,该表达式接受乘法的主导因子:

 \pgfdeclareshape{MyShape}{%
    \saveddimen\mydimen{%
        \pgf@x = 10pt%
    }%
    \backgroundpath{%
        \pgfpathmoveto
            {\pgfpoint{0pt}{0pt}}%
        \pgfpathlineto
            {\pgfpoint{2\dimexpr\mydimen\relax}{0pt}}%
        \pgfusepath{stroke}%
    }%
 }%

PS:这里用到的相关内部宏是:(换行和缩进是我加的)

\saveddimen:
macro:#1#2->\expandafter \pgfutil@g@addto@macro \csname pgf@sh@s@\shape@name \endcsname
    {\pgf@sh@resaveddimen {#1}{#2}}


\pgf@sh@resaveddimen:
macro:#1#2->{#2\global \pgf@x =\pgf@x }\edef \pgf@sh@marshal
    {\noexpand \pgfutil@g@addto@macro \noexpand \pgf@sh@savedpoints
    {\noexpand \def \noexpand #1{\the \pgf@x }}}\pgf@sh@marshal 

\the\pgf@x您会看到,给定的宏被定义为中的的扩展值\pgf@sh@resaveddimen。如果您经常需要它,您可以重新定义这个宏来\dimexpr\the\pgf@x\relax代替它。\dimexpr那么 就不会被扩展,并且保存的维度将是一个宏,其内容为您的情况下的宏\dimexpr 10pt\relax,它的作用就像一个普通的维度寄存器(我的意思是在赋值的右侧)。

相关内容