TikZ:以编程方式将宽度应用于节点,以及“未定义的控制序列 pgf”

TikZ:以编程方式将宽度应用于节点,以及“未定义的控制序列 pgf”

这是我想要做的:给定两个(水平)节点,计算它们之间的 x 距离,并生成一个宽度与节点之间的 x 距离相同的矩形节点,放置在它们下方。

我已经尝试了以下代码,重复使用在路径/计算中使用 \pgfmathparse - 为什么这个 let 表达式在 TikZ 中不起作用(计算中点)? - TeX - LaTeX - Stack Exchange

\usetikzlibrary{shapes.arrows,chains,positioning,matrix,calc}

\begin{tikzpicture}[font=\tt]
    \node (A1) [shape=circle,draw]              {A1};
    \node (A2) [shape=circle,draw,right=of A1]  {A2};

    % draw a rectangular node
    \draw let \p1 = (A1.west), \p2 = (A2.east) 
      in \pgfextra{
        \pgfmathparse{\x2 - \x1}
      }
        node[draw,right,below=of A1,text width=\pgfmathresult pt]{test};
\end{tikzpicture}

结果如下图所示:

显然 - 该框的宽度不如 A1 和 A2 节点之间的距离(并且其右边缘均未与 A1.west 对齐)。

然后我想尝试一些类似于给出的代码回复:tikz:以编程方式获取节点的宽度,它也使用\pgfextra,所以我尝试了类似如下的方法:

\usetikzlibrary{shapes.arrows,chains,positioning,matrix,calc}
\newdimen{\mydim}

\begin{tikzpicture}[font=\tt]
    \node (A1) [shape=circle,draw]              {A1};
    \node (A2) [shape=circle,draw,right=of A1]  {A2};

    % draw a rectangular node
    \draw let \p1 = (A1.west), \p2 = (A2.east) 
      in \pgfextra{
        \pgf@x=\n1
        \pgf@y=1cm
        \divide\pgf@x by \pgf@y
        \setlength{\mydim}{\pgf@x}      
      }
        node[draw,right,below=of A1,text width=\mydim pt]{test};
\end{tikzpicture}

...但是,对于该代码,LaTeX 在遇到时似乎会崩溃\pgf@x,因为错误消息是:

! Undefined control sequence.
<argument>  \pgf 
                 @x=\n 1 \pgf @y=1cm \divide \pgf @x by \pgf @y \setlength {...
l.40      }

!  ==> Fatal error occurred, no output PDF file produced!

我发现的唯一与此相关的错误是pgfdeclareshape 示例不可编译 - pgf-users,其中建议为:

如果将 \makeatletter 放在 \pgfdeclareshape{...} 之前并将 \makeatother 放在之后,是否可以编译?(手册中的示例中缺少它,但我认为它是必要的)。

... 但是,我不知道它在这里如何应用 - 因为这里使用所有这些 pgf 的目的只是计算(而不是实际的绘图/渲染)。

好吧,提前感谢任何指点,
干杯!

 

编辑:好吧,通过上述方法的组合,我开始取得一些进展:

\usetikzlibrary{shapes.arrows,chains,positioning,matrix,calc}
\newdimen{\mydim}

\begin{tikzpicture}[font=\tt]
    \node (A1) [shape=circle,draw]              {A1};
    \node (A2) [shape=circle,draw,right=of A1]  {A2};

    % draw a rectangular node
    \draw let \p1 = (A1.west), \p2 = (A2.east) 
      in \pgfextra{%
        \pgfmathparse{\x2 - \x1}
        \setlength{\mydim}{\pgfmathresult pt}       
      }
        node[draw,right,below=of A1.west,anchor=west,text width=\mydim]{test};
\end{tikzpicture} 

...但还是不太好。通过使用anchor=west,现在可以正确对齐;通过删除\pgf@x,并使用\pgfmathresult设置\mydim长度 - 宽度看起来会好一些,但比预期的要长,见图:

所以现在剩下的问题是:

  • 我如何获得框的正确宽度——以便它的左边缘与 A2 的左边缘对齐?
  • 为什么会发生这种‘碰撞\pgf@x\pgfextra

再次感谢,
干杯!

答案1

我猜想您的第一个示例没有给出正确的长度的原因是,\pgfmathresult在应用于选项之前,某个地方覆盖了 (您还忘记减去inner sep,这就是您编辑的长度不正确的原因)。但是,节点被正确地放置在 (A1) 下方,因为默认节点对齐是居中。

第一步:修复\pgfmathresult\pgfmathparse这里其实不需要 ,我们可以简单地执行以下操作(inner sep文本和边框之间的默认值为 0.3333em,因此我们需要减去 的两倍text width):

\begin{tikzpicture}[font=\tt]
    \node (A1) [shape=circle,draw]              {A1};
    \node (A2) [shape=circle,draw,right=of A1]  {A2};

    % draw a rectangular node
    \draw let \p1 = (A1.west), \p2 = (A2.east) in 
          node[draw,right,below=of A1,text width={\x2-\x1-0.6666em}]{test};
\end{tikzpicture}

第一步的结果

第二步:修复对齐。该right选项不执行任何操作,因此我们可以直接删除它。默认情况下,节点锚定在其中心。实际上,对于below=of ..,它们锚定在北(中心)。所以我们必须设置anchor=north west让节点位于右侧。但它位于 A1.center 的右侧(具体来说,node distance在 A1.south 下方)。所以我们需要指定below=of A1.south west。不幸的是,这不太管用,因为 A1 以圆圈为界(因此south west在圆圈上,而不是我们希望的那么西和南)。A1.west 是第一个近似值:

\begin{tikzpicture}[font=\tt]
    \node (A1) [shape=circle,draw]              {A1};
    \node (A2) [shape=circle,draw,right=of A1]  {A2};

    % draw a rectangular node
    \draw let \p1 = (A1.west), \p2 = (A2.east) in 
          node[draw,below={of A1.west},anchor=north west,text width={\x2-\x1-0.6666em}]{test};
\end{tikzpicture}

步骤 2.1 的结果

这还不够完美,因为第三个节点现在有点太高了。形状circle没有提供正确的锚点,所以我们必须计算它的位置(这很容易:A1.west 给出正确的 x 坐标,A1.south 给出正确的 y 坐标)。另外,让我们将align=center文本添加到节点的中心:

\begin{tikzpicture}[font=\tt]
    \node (A1) [shape=circle,draw]              {A1};
    \node (A2) [shape=circle,draw,right=of A1]  {A2};

    % draw a rectangular node
    \draw let 
            \p1 = (A1.west),
            \p2 = (A2.east),
            \p3 = (A1.south)
          in node [
            draw,
            below={of (\x1,\y3)},
            anchor=north west,
            text width={\x2-\x1-0.6666em},
            align=center
          ] {test};
\end{tikzpicture}

完成的图像


要使第二个示例编译,您需要在适当的位置添加\makeatletter\makeatother。默认情况下,@ 属于“其他”类,不能用于命令名称。但是,它通常用于用户不应访问的内部命令。\makeatletter使 @ 成为“字母”,以便它可以用于命令名称。另请参阅为什么 LaTeX 内部命令中带有 @?。但是代码似乎还有其他问题,添加\makeatletter只会改变错误。我还不太熟悉 TeX 和 LaTeX 处理尺寸和长度的方式,无法为您提供如何更正该代码的建议。

答案2

感谢@Caramdir,这里也是一个使用 的版本\pgf@x;虽然\makeatletter/\makeatother是摆脱 所必需的! Undefined control sequence,但 OP 代码还需要使用“计数器”而不是“维度”,以便完全发生一些宽度缩放。

下面的代码应该构建并生成一个图像 - 但这次它的宽度将稍微更短比 A1 和 A2 之间的“总”距离更大:

\usetikzlibrary{shapes.arrows,chains,positioning,matrix,calc}
\newdimen{\mydim}
\newcounter{counterOne}

\begin{tikzpicture}[font=\tt]

    \node (A1) [shape=circle,draw]              {A1};
    \node (A2) [shape=circle,draw,right=of A1]  {A2};

    % draw a rectangular node
    \makeatletter
    \draw let \p1 = (A1.west), \p2 = (A2.east) 
      in let \n{width} = {\x2 - \x1}
        in \pgfextra{
        % \pgf@x=\n1 % ! Missing number, treated as zero. \tikz@cc@n@1
        % manual: "the \p, \x, and \y macros refer to the same logical point, while the \n macro has “its own namespace.”"
        \pgf@x=\n{width}
        \pgf@y=1cm
        \divide\pgf@x by \pgf@y
        \setcounter{counterOne}{\pgf@x}  % NOWORK: \setlength{\mydim}{\pgf@x}
      }
        node[draw,right,below=of A1.west,anchor=west,text width=\thecounterOne cm]{test};
    \makeatother

\end{tikzpicture} 

... 结果图像:

使用 \pgf@x 和计数器代码缩短宽度

好吧,无论如何,我很高兴这个问题得到了解决:)
干杯!

相关内容