![如何在宏中获取 TikZ 中某个片段的长度](https://linux22.com/image/479371/%E5%A6%82%E4%BD%95%E5%9C%A8%E5%AE%8F%E4%B8%AD%E8%8E%B7%E5%8F%96%20TikZ%20%E4%B8%AD%E6%9F%90%E4%B8%AA%E7%89%87%E6%AE%B5%E7%9A%84%E9%95%BF%E5%BA%A6.png)
我的问题正是这个问题let
声明。但是,由于某些原因,我无法使用该运算符。
那么我该如何定义一个命令\getlength
以便\getlength{a}{b}
返回的长度(a) -- (b)
?
当前不工作的示例 – 我认为这是因为两个 Ti钾Z 张图片是嵌套的,这绝对不是好事:
\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
如此。可以使用fpu
pgfplots
这在“普通钛钾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
提取x
和y
坐标作为维度,因此您需要首先定义这些维度。我认为为实际结果定义另一个维度也是不错的选择。如果您定义这些新维度,那么您的代码几乎可以正常工作。
没有什么好的理由,我更喜欢将节点定义为路径,因此我重写了你的代码,以便\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}