在 let-Block 中定义函数

在 let-Block 中定义函数

有没有办法在 let-Block 中定义一个函数?我有一些代码可以创建一个框架并将两个节点放入其中:

\documentclass[tikz]{standalone}
\usetikzlibrary{calc}

\begin{document}
\begin{tikzpicture}
    \node (frame) [minimum width=4.5cm, minimum height=.5cm, draw=black, rounded corners=.1cm, anchor=east] at (0,0) {};
    \draw[-, dashed] let \p1=(frame.north west), \p2=(frame.south east), \n1={.5*(\x2-\x1)} in (\x1+\n1, \y1) -- (\x1+\n1, \y2);

    \path let \p1=(frame.north west), \p2=(frame.south east), \n1={.25*(\x2-\x1)}, \n2={.5*(\y1-\y2)} in node [align=center] at (\x1+\n1, \y1-\n2) { Left };
    \path let \p1=(frame.north west), \p2=(frame.south east), \n1={.75*(\x2-\x1)}, \n2={.5*(\y1-\y2)} in node [align=center] at (\x1+\n1, \y1-\n2) { Right };
\end{tikzpicture}
\end{document}

创建两个节点(左和右)的代码非常相似,我经常需要这样的代码。我想写的代码不是这两\path let ..行,而是这样的代码:

    \path let \p1=(frame.north west), \p2=(frame.south east), \f{v}={v*(\x2-\x1)}, \n2={.5*(\y1-\y2)} in
        node [align=center] at (\x1+\f{.25}, \y1-\n2) { Left }
        node [align=center] at (\x1+\f{.75}, \y1-\n2) { Right };

因此,我不再编写两行单独的代码,而是定义一个函数f(v)={v*(\x2-\x1)},可以调用两次来定义绘制这两个节点的位置。完整的代码如下所示:

\documentclass[tikz]{standalone}
\usetikzlibrary{calc}

\begin{document}
\begin{tikzpicture}
    \node (frame) [minimum width=4.5cm, minimum height=.5cm, draw=black, rounded corners=.1cm, anchor=east] at (0,0) {};
    \draw[-, dashed] let \p1=(frame.north west), \p2=(frame.south east), \n1={.5*(\x2-\x1)} in (\x1+\n1, \y1) -- (\x1+\n1, \y2);

    \path let \p1=(frame.north west), \p2=(frame.south east), \f{v}={v*(\x2-\x1)}, \n2={.5*(\y1-\y2)} in
        node [align=center] at (\x1+\f{.25}, \y1-\n2) { Left }
        node [align=center] at (\x1+\f{.75}, \y1-\n2) { Right };
\end{tikzpicture}
\end{document}

有什么想法可以做到这一点吗?提前感谢大家的帮助!

你好,塞巴斯蒂安

答案1

至少有两种可能的解决方案。请注意,在这两种情况下,如果您想在表达式中使用括号,则必须用括号括住 x 坐标。请参阅tikz 坐标中的算术(括号)由于这个原因。

然而,有人可能会争论,为这么简单的事情定义一个函数是否有点过头了。你应该权衡一下总是考虑的是它是否会使您的代码更可读或更难读。

示例输出


解决方案 1:您可以使用键/pgf/declare function来声明 pgfmath 函数,该函数由 pgfmath 引擎识别。这样做的好处是函数的作用域是路径本地的。您不会意外地在其他地方使用它。它看起来像这样:

\path[declare function={ f(\v)=\v * (\x2-\x1); }]
    let \p1=(frame.north west), \p2=(frame.south east), \n2={.5*(\y1-\y2)} in
        node [align=center] at ({\x1+f(0.25)}, \y1-\n2) { Left }
        node [align=center] at ({\x1+f(0.75)}, \y1-\n2) { Right };

请注意,函数定义使用未定义的符号\x1\x2,它们在函数执行时进行求值用过的,而不是当定义。根据某些定义,这可能被称为“非纯函数”。如果你在其他地方调用它,\x1而这些地方\x2没有定义,它可能会严重崩溃。

另外,您可以像您要​​求的那样将其放入 let 内的作用域中。作用域之后,定义消失:

\path let \p1=(frame.north west), \p2=(frame.south east), \n2={.5*(\y1-\y2)} in
    {[declare function={ f(\v)=\v * (\x2-\x1); }]
        node [align=center] at ({\x1+f(0.25)}, \y1-\n2) { Left }
        node [align=center] at ({\x1+f(0.75)}, \y1-\n2) { Right }
    }
    % node at ({\x1+f(0.25)}, \y1-\n2) { Left } % Fails because f is undefined
    ;

解决方案 2:您可以使用\def(或\newcommand*) 来定义一个宏\f。此宏将一直保留到组结束。

注意 整个 主体周围的括号\f。这可以防止 的情况0.5 ^ \f{0.25}分开,因为如果没有括号,这将被评估为(0.5 ^ 0.25) * (\x2 - \x1)因为^的优先级高于*

\def\f#1{(#1 * (\x2 - \x1))}
\path let \p1=(frame.north west), \p2=(frame.south east), \n2={.5*(\y1-\y2)} in
    node [align=center] at ({\x1+\f{0.25}}, \y1-\n2) { Left }
    node [align=center] at ({\x1+\f{0.75}}, \y1-\n2) { Right };

完整示例:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{math}

\begin{document}
Using \verb|\def|:

\begin{tikzpicture}
    \node (frame) [minimum width=4.5cm, minimum height=.5cm, draw=black, rounded corners=.1cm, anchor=east] at (0,0) {};
    \draw[-, dashed] let \p1=(frame.north west), \p2=(frame.south east), \n1={.5*(\x2-\x1)} in (\x1+\n1, \y1) -- (\x1+\n1, \y2);

    \def\f#1{(#1 * (\x2 - \x1))}
    \path let \p1=(frame.north west), \p2=(frame.south east), \n2={.5*(\y1-\y2)} in
    node [align=center] at ({\x1+\f{0.25}}, \y1-\n2) { Left }
    node [align=center] at ({\x1+\f{0.75}}, \y1-\n2) { Right };
\end{tikzpicture}

Using \verb|declare function|:

\begin{tikzpicture}
    \node (frame) [minimum width=4.5cm, minimum height=.5cm, draw=black, rounded corners=.1cm, anchor=east] at (0,0) {};
    \draw[-, dashed] let \p1=(frame.north west), \p2=(frame.south east), \n1={.5*(\x2-\x1)} in (\x1+\n1, \y1) -- (\x1+\n1, \y2);
    \path[declare function={
        f(\v)=\v * (\x2-\x1);
    }] let \p1=(frame.north west), \p2=(frame.south east), \n2={.5*(\y1-\y2)} in
    node [align=center] at ({\x1+f(0.25)}, \y1-\n2) { Left }
    %node [align=center] at (\x1+\f{0.25}, \y1-\n2) { Left }
    node [align=center] at ({\x1+f(0.75)}, \y1-\n2) { Right };
\end{tikzpicture}
\end{document}

答案2

您始终可以使用\newcommand以避免在文档中重新输入重复的文本:

\documentclass[tikz]{standalone}
\usetikzlibrary{calc}

\newcommand{\myletcode}[2]{
    let \p1=(frame.north west), \p2=(frame.south east), \n1={#1*(\x2-\x1)}, \n2={.5*(\y1-\y2)} in node [align=center] at (\x1+\n1, \y1-\n2) { #2 }
}

\begin{document}
\begin{tikzpicture}
    \node (frame) [minimum width=4.5cm, minimum height=.5cm, draw=black, rounded corners=.1cm, anchor=east] at (0,0) {};
    \draw[-, dashed] let \p1=(frame.north west), \p2=(frame.south east), \n1={.5*(\x2-\x1)} in (\x1+\n1, \y1) -- (\x1+\n1, \y2);

    \path \myletcode{.25}{Left};
    \path \myletcode{.75}{Right};
\end{tikzpicture}
\end{document}

在此处输入图片描述

尽管如果问题是这样的节点,您可以使用rectangle splitfrom shapes.multipart

在这种情况下,你应该使用text width而不是minimum width(见“最小宽度”对水平多部分节点没有影响),并且虚线分隔线是使用path picture命令绘制的,因为我不知道如何为分割线固定特定的样式。

\documentclass[tikz]{standalone}
\usetikzlibrary{shapes.multipart}


\begin{document}
\begin{tikzpicture}[
    mynode/.style={
        rectangle split, 
        rectangle split parts=2, 
        rectangle split horizontal, 
        rectangle split draw splits=false, 
        path picture={%
            \draw[dashed] (path picture bounding box.north)--
            (path picture bounding box.south);},
        align=center,
    }]

    \node (frame) [mynode, text width=2.25cm, minimum height=.5cm, draw=black, rounded corners=.1cm, anchor=east] {Left\nodepart{two}Right};

\end{tikzpicture}
\end{document}

答案3

使用该fit包的另一个(简单)解决方案:

\documentclass[tikz]{standalone}
\usetikzlibrary{fit,
                positioning}

\begin{document}
    \begin{tikzpicture}[
node distance = 0pt,
box/.style = {text width=22.5mm, minimum height=5mm, 
              align=center, outer sep=0pt},
FIT/.style = {draw, rounded corners=1mm, inner sep=0pt, fit=#1}
                        ]
\node (n1) [box] {left};
\node (n2) [box,right=of n1] {right};
\node (n3) [FIT=(n1) (n2)] {};
\draw[dashed]   (n3.north) -- (n3.south);                  
    \end{tikzpicture}
\end{document}

在此处输入图片描述

相关内容