如何在宏中获取 TikZ 中某个片段的长度

如何在宏中获取 TikZ 中某个片段的长度

我的问题正是这个问题let声明。但是,由于某些原因,我无法使用该运算符。

那么我该如何定义一个命令\getlength以便\getlength{a}{b}返回的长度(a) -- (b)

当前不工作的示例 – 我认为这是因为两个 TiZ 张图片是嵌套的,这绝对不是好事:

\documentclass[tikz,margin=3]{standalone}
\usetikzlibrary{calc}
\def\getlength#1#2{
  \path[overlay] ($(#1)-(#2)$);
  \pgfgetlastxy{\myx}{\myy}
  \pgfmathparse{veclen(\myx, \myy)}\pgfmathresult
}
\begin{document}
\begin{tikzpicture}
  \draw (0,0) coordinate (b) -- (5,0) coordinate (c) -- (1,4) coordinate (a) -- cycle;
  % It should work in both, but sadly it is not working in any of these
  \path node {\getlength{a}{b}};
  \draw (0,0) circle (\getlength{a}{b});
\end{tikzpicture}
\end{document}

任何帮助都将非常感激。

答案1

您正在加载calc,因此

\documentclass[tikz,margin=3]{standalone}
\usetikzlibrary{calc}
\begin{document}
\begin{tikzpicture}
  \draw (0,0) coordinate (b) -- (5,0) coordinate (c) -- (1,4) coordinate (a) -- cycle;
  \draw let \p1=($(b)-(a)$),\n1={veclen(\x1,\y1)} in
  (0,0) node {\n1}  circle [radius=\n1];
\end{tikzpicture}
\end{document}

在此处输入图片描述

但是,可以创建一个函数distance来返回两个命名坐标之间的距离。它可以像任何其他函数一样使用和解析。它不会创建路径。然而,我之前在路径中使用它的例子是危险的,而且总体来说是错误的。我感谢 JouleV 向我报告了这个问题!它甚至可以在 s 之外工作tikzpicture。(此处的函数经过定制以类似于您的原始函数。)

\documentclass[tikz,margin=3]{standalone}
\makeatletter
\pgfmathdeclarefunction{distance}{2}{%
\begingroup%
\pgfextractx{\pgf@xa}{\pgfpointanchor{#1}{center}}%
\pgfextracty{\pgf@ya}{\pgfpointanchor{#1}{center}}%
\pgfextractx{\pgf@xb}{\pgfpointanchor{#2}{center}}%
\pgfextracty{\pgf@yb}{\pgfpointanchor{#2}{center}}%
\pgfmathparse{veclen(\pgf@xa-\pgf@xb,\pgf@ya-\pgf@yb)}%
\pgfmathsmuggle\pgfmathresult\endgroup%
}%
\makeatother
\begin{document}
\begin{tikzpicture}
  \draw (0,0) coordinate (b) -- (5,0) coordinate (c) -- (1,4) coordinate (a) -- cycle;
  \pgfmathsetmacro{\mydist}{distance("a","b")}
  \path node {\mydist};
  \draw (0,0) circle [radius=\mydist pt];
\end{tikzpicture}
\end{document}

在此处输入图片描述

附录:我同意 Alain Matthes 的观点,这种说法veclen并不准确。这只是说你不需要xfp解决这个问题,计算欧几里得距离就足够了。我也认为这tkz-euclide很好,但人们不需要它来将结果转换为厘米,简单的\pgfmathparse{<whatever>/1cm}就足够了。

\documentclass[tikz,margin=3]{standalone}
\makeatletter
\pgfmathdeclarefunction{distance}{2}{%
\begingroup%
\pgfextractx{\pgf@xa}{\pgfpointanchor{#1}{center}}%
\pgfextracty{\pgf@ya}{\pgfpointanchor{#1}{center}}%
\pgfextractx{\pgf@xb}{\pgfpointanchor{#2}{center}}%
\pgfextracty{\pgf@yb}{\pgfpointanchor{#2}{center}}%
\pgfmathparse{sqrt((\pgf@xa-\pgf@xb)*(\pgf@xa-\pgf@xb)+(\pgf@ya-\pgf@yb)*(\pgf@ya-\pgf@yb))}%
\pgfmathsmuggle\pgfmathresult\endgroup%
}%
\makeatother
\begin{document}
\begin{tikzpicture}
  \draw (0,0) coordinate (b) -- (40pt,0)
              coordinate (c) -- (40pt,30pt)
              coordinate (a) -- cycle;
  \pgfmathsetmacro{\mydistance}{distance("a","b")}            
  \path node 
  {$\pgfmathprintnumber{\mydistance}\,\mathrm{pt}=
  \pgfmathparse{\mydistance/1cm}\pgfmathprintnumber{\pgfmathresult}\,\mathrm{cm}$};
  \draw (0,0) circle [radius={\mydistance pt}];
\end{tikzpicture}
\end{document}

在此处输入图片描述

不过,有一个优点:当距离很大时,它不会崩溃。为此而制作并在中使用的库也是xfp如此。可以使用fpupgfplots这在“普通钛Z 也一样。这产生了一个不受大值影响的版本,并且(相当)精确。

\documentclass[tikz,margin=3]{standalone}
\usetikzlibrary{fpu}
\newcommand{\pgfmathparseFPU}[1]{\begingroup%
\pgfkeys{/pgf/fpu,/pgf/fpu/output format=fixed}%
\pgfmathparse{#1}%
\pgfmathsmuggle\pgfmathresult\endgroup}
\makeatletter
\pgfmathdeclarefunction{distance}{2}{%
\begingroup%
\pgfextractx{\pgf@xa}{\pgfpointanchor{#1}{center}}%
\pgfextracty{\pgf@ya}{\pgfpointanchor{#1}{center}}%
\pgfextractx{\pgf@xb}{\pgfpointanchor{#2}{center}}%
\pgfextracty{\pgf@yb}{\pgfpointanchor{#2}{center}}%
\pgfmathparseFPU{sqrt((\pgf@xa-\pgf@xb)*(\pgf@xa-\pgf@xb)+(\pgf@ya-\pgf@yb)*(\pgf@ya-\pgf@yb))}%
\pgfmathsmuggle\pgfmathresult\endgroup%
}%
\makeatother
\begin{document}
\begin{tikzpicture}
  \draw (0,0) coordinate (b) -- (40pt,0)
              coordinate (c) -- (40pt,30pt)
              coordinate (a) -- cycle;
  \pgfmathsetmacro{\mydistance}{distance("a","b")}            
  \path node 
  {$\pgfmathprintnumber{\mydistance}\,\mathrm{pt}=
  \pgfmathparse{\mydistance/1cm}\pgfmathprintnumber{\pgfmathresult}\,\mathrm{cm}$};
  \draw (0,0) circle [radius={distance("a","b")}];
\end{tikzpicture}
\end{document}

答案2

问题是\pgfgetlastxy提取xy坐标作为维度,因此您需要首先定义这些维度。我认为为实际结果定义另一个维度也是不错的选择。如果您定义这些新维度,那么您的代码几乎可以正常工作。

没有什么好的理由,我更喜欢将节点定义为路径,因此我重写了你的代码,以便\getlength{a}{b}设置长度\mylength,你可以在需要的地方使用它:

\documentclass[tikz,border=3]{standalone}
\usetikzlibrary{calc}
\newdimen\mypointx
\newdimen\mypointy
\newdimen\mylength
\def\getlength#1#2{
  \node (#1#2) at ($ (#1)-(#2) $){};% define a point at (#1)-(#2_
  \pgfgetlastxy{\mypointx}{\mypointy}% extract the coordinates
  \pgfmathsetlength\mylength{veclen(\mypointx, \mypointy)}% compute the length
}
\begin{document}
\begin{tikzpicture}
  \draw (0,0) coordinate (b) -- (5,0) coordinate (c) -- (1,4) coordinate (a) -- cycle;
  % It should work in both, but sadly it is not working in any of these
  \getlength{a}{b};
  \draw (0,0) circle (\mylength);
\end{tikzpicture}
\end{document}

这将产生预期的结果:

在此处输入图片描述

我不确定\path node {\getlength{a}{b}};要做什么,因为例如,\path node 1;语法无效。你的意思是这样的吗\path node (\getlength{a}{b},0){};

最后,并不一定要使用上述其他长度\mylength。你可以使用标准宏

\pgfmathsetmacro\mymacro{veclen(\mypointx, \mypointy)}

甚至

\pgfmathparse{veclen(\mypointx, \mypointy)}

您可以在类似命令中使用

\draw (0,0) circle (\mymacro);

and

\draw (0,0) circle (\pgfmathresult);

分别。但是,据我所知,您不能将其放在\pgfmathresult末尾\getlength,然后在命令中使用它,例如

\draw (0,0) circle (\getlength{a}{b});

因为这总是返回错误。我怀疑是扩展问题。

答案3

veclen唯一的问题是来自的结果pgfmath

\documentclass[tikz,margin=3]{standalone}
\usetikzlibrary{calc}
\usepackage{xfp} 
\makeatletter
\pgfmathdeclarefunction*{veclen}{2}{%
\begingroup%
  \pgfmath@x#1pt\relax%
  \pgfmath@y#2pt\relax%
  \pgf@xa=\pgf@x%
  \pgf@ya=\pgf@y%
  \edef\tkz@temp@a{\fpeval{\pgfmath@tonumber{\pgf@xa}}}
  \edef\tkz@temp@b{\fpeval{\pgfmath@tonumber{\pgf@ya}}}
  \edef\tkz@temp@sum{\fpeval{%
    (\tkz@temp@a*\tkz@temp@a+\tkz@temp@b*\tkz@temp@b)}}
  \edef\tkzFPMathLen{\fpeval{sqrt(\tkz@temp@sum)}}
  \pgfmath@returnone\tkzFPMathLen pt%
\endgroup%
}
\makeatother
\begin{document}
\begin{tikzpicture}
  \draw (0,0) coordinate (b) -- (40pt,0)
              coordinate (c) -- (40pt,30pt)
              coordinate (a) -- cycle;
  \draw let \p1=($(b)-(a)$),\n1={veclen(\x1,\y1)} in
  (0,0) node {\n1}  circle [radius=\n1];
\end{tikzpicture}
\end{document}

在此处输入图片描述

tkz-euclide你有宏\tkzCalcLength

\documentclass[border=.25cm]{standalone}
\usepackage{tkz-euclide}

\begin{document}
\begin{tikzpicture}
    \tkzDefPoint(0,0){B}
    \tkzDefPoint(1,4){A}
    \tkzCalcLength(A,B)\tkzGetLength{dAB}
    \node {\dAB pt};
    \tkzCalcLength[cm](A,B)\tkzGetLength{dAB}
    \node at (2,0) {\dAB cm};
\end{tikzpicture}
\end{document}

在此处输入图片描述

相关内容