我知道如何将库let
中的命令用于命令中并修复该路径上特定节点的某些参数。但我想在节点的样式定义中使用。TikZ calc
path
作为示例,考虑如何自动修复single arrow
节点之间的高度和边框旋转:
\documentclass[tikz,border=2mm]{standalone}
\usetikzlibrary{positioning, shapes.arrows, calc}
\begin{document}
\begin{tikzpicture}
\node[draw] (a) {A};
\node[draw, above right=2cm and 1cm of a] (b) {B};
\path (a.north east) let \p1=($(b.south west)-(a.north east)$) in
node[single arrow, draw,
minimum height={veclen(\x1,\y1)},
shape border uses incircle,
shape border rotate={atan2(\y1,\x1)},
anchor=tail] at (a.north east) {};
\end{tikzpicture}
\end{document}
我想用类似的样式定义这个箭头节点arrow between a and b
并能够使用
\node[arrow between a and b] {};
问题是我从未见过let
a 内部有.\style
for a node
。可以做到吗?
答案1
是的,
math
图书馆及其/tikz/evaluate
钥匙(不要混淆/pgf/foreach/evaluate
):\tikzset{ arrow between/.style args={#1 and #2}{ evaluate={ coordinate \diffPoint; \diffPoint=(#2.south west)-(#1.north east);}, shape=single arrow, draw, at={(#1.north east)}, anchor=tail, shape border uses incircle, minimum height=veclen(\diffPoint)*1pt, shape border rotate={atan2(\diffPointy,\diffPointx)}}}
是的,通过使用
let … in
解析器,但停用切换回\path
解析的功能。\makeatletter \tikzset{parse let/.code={\def\tikz@cc@stop@let in{}\tikz@let@command et #1in}} \makeatother \tikzset{ arrow between'/.style args={#1 and #2}{ parse let={\p{diffPoint}=($(#2.south west)-(#1.north east)$)}, shape=single arrow, draw, at={(#1.north east)}, anchor=tail, shape border uses incircle, minimum height=veclen(\p{diffPoint})*1pt, shape border rotate={atan2(\y{diffPoint},\x{diffPoint})}}}
或者直接使用 PGF 级别的计算
\pgfkeyssetevalue{<key>}{<value>}
的更快版本在哪里\pgfkeys{<key>/.expanded=<value>}
?\pgfmathveclen@
更快的版本在哪里\pgfmathveclen
,\pgfmathparse{veclen(…)
因为参数不需要再次解析,并且- 我们重新使用全球化维度
\pgf@x
和\pgf@y
来自\pgfmathanglebetweenpoints
'\pgfpointdiff
的功能veclen
:
\tikzset{ arrow between''/.style args={#1 and #2}{% shape=single arrow, draw, at={(#1.north east)}, anchor=tail, shape border uses incircle, /utils/exec=% \pgfmathanglebetweenpoints {\pgfpointanchor{#1}{north east}}{\pgfpointanchor{#2}{south west}}% \pgfkeyssetevalue{/pgf/shape border rotate}{\pgfmathresult}% \pgfmathveclen@{\pgf@x}{\pgf@y}% \pgfkeyssetevalue{/pgf/minimum height}{\pgfmathresult pt}}}
当然,所有解决方案都需要做一些工作来检测所需的锚点。(是#2
低于还是高于#1
?在右边还是左边?当它们(几乎)垂直或水平对齐时应该使用什么锚点?)
代码
\documentclass[tikz,border=2mm]{standalone}
\usetikzlibrary{positioning, shapes.arrows, calc, math}
% 1. math library that allows 'calc'ulations:
\tikzset{
arrow between/.style args={#1 and #2}{
evaluate={
coordinate \diffPoint;
\diffPoint=(#2.south west)-(#1.north east);},
shape=single arrow, draw,
at={(#1.north east)}, anchor=tail,
shape border uses incircle,
minimum height=veclen(\diffPoint)*1pt,
shape border rotate={atan2(\diffPointy,\diffPointx)}}}
% 2. using the original let syntax
\makeatletter
\tikzset{parse let/.code={\def\tikz@cc@stop@let in{}\tikz@let@command et #1in}}
\makeatother
\tikzset{
arrow between'/.style args={#1 and #2}{
parse let={\p{diffPoint}=($(#2.south west)-(#1.north east)$)},
shape=single arrow, draw,
at={(#1.north east)}, anchor=tail,
shape border uses incircle,
minimum height=veclen(\p{diffPoint})*1pt,
shape border rotate={atan2(\y{diffPoint},\x{diffPoint})}}}
% 3. using lower level PGF commands
\makeatletter
\tikzset{
arrow between''/.style args={#1 and #2}{%
shape=single arrow, draw,
at={(#1.north east)}, anchor=tail,
shape border uses incircle,
/utils/exec=%
\pgfmathanglebetweenpoints
{\pgfpointanchor{#1}{north east}}{\pgfpointanchor{#2}{south west}}%
\pgfkeyssetevalue{/pgf/shape border rotate}{\pgfmathresult}%
\pgfmathveclen@{\pgf@x}{\pgf@y}%
\pgfkeyssetevalue{/pgf/minimum height}{\pgfmathresult pt}}}
\makeatother
\begin{document}
\begin{tikzpicture}
\node[draw] (a) {A};
\node[draw, above right=2cm and 1cm of a] (b) {B};
\node[arrow between=a and b] {};
\end{tikzpicture}
\begin{tikzpicture}
\node[draw] (a) {A};
\node[draw, above right=2cm and 1cm of a] (b) {B};
\node[arrow between'=a and b] {};
\end{tikzpicture}
\begin{tikzpicture}
\node[draw] (a) {A};
\node[draw, above right=2cm and 1cm of a] (b) {B};
\node[arrow between''=a and b] {};
\end{tikzpicture}
\end{document}
答案2
这就是您所寻找的吗?
\documentclass[tikz,border=2mm]{standalone}
\usetikzlibrary{positioning, shapes.arrows, calc}
\begin{document}
\tikzset{/tikz/.cd,
my arrow/.code args={#1 and #2}{%
\path (#1.north east) let \p1=($(#2.south west)-(#1.north east)$) in
node[single arrow, draw,
minimum height={veclen(\x1,\y1)},
% shape border uses incircle,
% shape border
rotate={atan2(\y1,\x1)},
anchor=tail] at (#1.north east) {\MyAwTxt};
},
my arrow text/.store in=\MyAwTxt,
my arrow text=,
}
\begin{tikzpicture}
\node[draw] (a) {A};
\node[draw, above right=2cm and 1cm of a] (b) {B};
\node[my arrow text=bob,my arrow={a and b}]{x};
\end{tikzpicture}
\end{document}
是第一次尝试
\documentclass[tikz,border=2mm]{standalone}
\usetikzlibrary{positioning, shapes.arrows, calc}
\begin{document}
\tikzset{/tikz/.cd,
my arrow/.code args={#1 and #2}{%
\path (#1.north east) let \p1=($(#2.south west)-(#1.north east)$) in
node[single arrow, draw,
minimum height={veclen(\x1,\y1)},
shape border uses incircle,
shape border rotate={atan2(\y1,\x1)},
anchor=tail] at (#1.north east) {};
},
}
\begin{tikzpicture}
\node[draw] (a) {A};
\node[draw, above right=2cm and 1cm of a] (b) {B};
%\node[my arrow={a and b}] {}; % <- OP's request
\path[my arrow={a and b}] ; % <- My first idea
\end{tikzpicture}
\end{document}
答案3
我可能遗漏了一些东西,但你可以做一些类似的事情这个答案。更新@Tarass 告诉我,文本应该位于箭头内,这很容易实现。如果我知道所有要求,我会很乐意实现它们。
\documentclass[tikz,border=2mm]{standalone}
\usetikzlibrary{positioning, shapes.arrows, calc}
\usetikzlibrary{calc}
\tikzset{
my arrow/.style n args={2}{at={($(#1)!0.5!(#2)$)},
append after command={
\pgfextra{\path (#1.north east) let \p1=($(#2.south west)-(#1.north east)$) in
node[single arrow, draw,
minimum height={veclen(\x1,\y1)},
shape border uses incircle,
shape border rotate={atan2(\y1,\x1)},
anchor=tail] at (a.north east) {};
}}
}
}
\begin{document}
\begin{tikzpicture}
\node[draw] (a) {A};
\node[draw, above right=2cm and 1cm of a] (b) {B};
\node[my arrow={a}{b}]{C};
\end{tikzpicture}
\end{document}