我尝试回答一个有趣但被低估的问题老问题。
为了使我的答案也适用于倾斜路径,我需要箭头的可视后端点的坐标。
我想([xshift=-#1]\tikzinputsegmentlast)
在下面的代码中更改箭头的视觉后端的坐标。
是否可以?
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{arrows.meta}
\usetikzlibrary{decorations.pathreplacing}
\tikzset{
mystyle/.style={
-{Triangle[open, length=#1]},
decoration={
show path construction,
lineto code={
\coordinate (n0) at (\tikzinputsegmentfirst);
\coordinate (n3) at ([xshift=-#1]\tikzinputsegmentlast);
\coordinate (n4) at (\tikzinputsegmentlast);
\coordinate (n1) at (barycentric cs:n0=2,n3=1);
\coordinate (n2) at (barycentric cs:n0=1,n3=2);
\draw [-, color=red] (n0) -- (n1);
\draw [-, color=green] (n1) -- (n2);
\draw [-, color=blue] (n2) -- (n3);
\draw (n3) -- (n4);
}
},
decorate
},
mystyle/.default=5pt,
every node/.style={circle, draw}
}
\begin{document}
\begin{tikzpicture}
\node (A) at (0,0) {A};
\node (B) at (5,0) {B};
\draw[mystyle] (A) -- (B);
\end{tikzpicture}
\begin{tikzpicture}
\node (A) at (0,0) {A};
\node (B) at (5,0) {B};
\draw[mystyle={35pt}] (A) -- (B);
\end{tikzpicture}
\begin{tikzpicture}
\node (A) at (0,0) {A};
\node (B) at (5,1) {B};
\draw[mystyle={20}] (A) -- (B);
\end{tikzpicture}
\end{document}
正如你所看到的,现在第三张图是错误的。
答案1
视觉后端的位置存储在
\csname pgf@ar@visual@\pgf@arrow@id\endcsname
带格式
{visual tip end}{visual back end}{}
因此,倾斜减去向后就是您要从线上减去的距离。
要了解\pgf@arrow@id
,你需要将箭头规范传递给\pgfsetarrowsend
。例如\pgfsetarrowsend{Triangle[length=1cm]}
。后一个命令的功能有两方面:
- 如果箭头规范以前没有使用过,它会计算所需的一切并缓存。
- 如果箭头规范之前已经使用过,则将其设置
\pgf@arrow@id
为旧的 id。
不管怎样,您知道\pgf@arrow@id
并且现在
\csname pgf@ar@visual@\pgf@arrow@id\endcsname
有意义了。剩下的就是 expandafter-exercise。
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{arrows.meta}
\usetikzlibrary{decorations.pathreplacing}
\usetikzlibrary{calc}
\makeatletter
\def\computevisuallength#1#2#3{% visual end, visual tip, dummy
\pgf@x#1
\pgf@y#2
\advance\pgf@x-\pgf@y
\xdef\visuallength{\the\pgf@x}
}
\tikzset{
mystyle/.style={
decoration={
show path construction,
lineto code={
\coordinate (n0) at (\tikzinputsegmentfirst);
\coordinate (n4) at (\tikzinputsegmentlast);
\draw[dash pattern=on0off9999,-{Triangle[open, length=#1]}] (n0) -- (n4);
{
\pgfsetarrowsend{Triangle[open, length=#1]}% force pgf recall this arrow
\def\pgf@arrow@hull@point{hull}%%
\message{^^J }
\message{^^J arrow id: pgf@arrow@id\pgf@arrow@id}
\message{^^J hull: \csname pgf@ar@hull@\pgf@arrow@id\endcsname}
\message{^^J tip back: \csname pgf@ar@ends@\pgf@arrow@id\endcsname}
\message{^^J vis tip back: \csname pgf@ar@visual@\pgf@arrow@id\endcsname}
\message{^^J etc etc}
\message{^^J }
\expandafter\expandafter\expandafter\computevisuallength
\csname pgf@ar@visual@\pgf@arrow@id\endcsname
}
\coordinate (n3) at ($(n4)!\visuallength!(n0)$);
\coordinate (n1) at (barycentric cs:n0=2,n3=1);
\coordinate (n2) at (barycentric cs:n0=1,n3=2);
\draw [color=red] (n0) -- (n1);
\draw [color=green] (n1) -- (n2);
\draw [color=blue] (n2) -- (n3);
}
},
decorate
},
mystyle/.default=5pt,
every node/.style={circle, draw}
}
\begin{document}
\begin{tikzpicture}
\node (A) at (0,0) {A};
\node (B) at (5,0) {B};
\draw[mystyle] (A) -- (B);
\end{tikzpicture}
\begin{tikzpicture}
\node (A) at (0,0) {A};
\node (B) at (5,0) {B};
\draw[mystyle={35pt}] (A) -- (B);
\end{tikzpicture}
\begin{tikzpicture}
\node (A) at (0,0) {A};
\node (B) at (5,1) {B};
\draw[mystyle={20}] (A) -- (B);
\end{tikzpicture}
% Repeat the second arrow, can pgf recall the parameter?
\begin{tikzpicture}
\node (A) at (0,0) {A};
\node (B) at (5,0) {B};
\draw[mystyle={35pt}] (A) -- (B);
\end{tikzpicture}
\end{document}
答案2
\coordinate (n3) at
($(\tikzinputsegmentlast)!#1!(\tikzinputsegmentfirst)$);
有效。这定义n3
为从最后一个线段到第一个线段的沿线的坐标,并且距离最后一个线段#1
(必须是长度)。#1
奖金:下面的代码片段添加了对 的支持shorten >=<length>
,以及 为#1
无单位“长度”的用例(通过利用 的“特征” pgfmath
)。
\coordinate (n3) at
($(\tikzinputsegmentlast)!#1+\pgf@shorten@end@additional!(\tikzinputsegmentfirst)$);
完整示例
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{arrows.meta, calc}
\usetikzlibrary{decorations.pathreplacing}
\makeatletter
\tikzset{
mystyle/.style={
-{Triangle[open, length=#1]},
decoration={
show path construction,
lineto code={
\coordinate (n0) at (\tikzinputsegmentfirst);
\coordinate (n3) at
($(\tikzinputsegmentlast)!#1+\pgf@shorten@end@additional!(\tikzinputsegmentfirst)$);
\coordinate (n4) at (\tikzinputsegmentlast);
\coordinate (n1) at (barycentric cs:n0=2,n3=1);
\coordinate (n2) at (barycentric cs:n0=1,n3=2);
\begin{scope}[shorten >=0pt, arrows={-}]
\draw[red] (n0) -- (n1);
\draw[green] (n1) -- (n2);
\draw[blue] (n2) -- (n3);
\end{scope}
% this `\draw` will add the end-of-path arrow
\draw (n3) -- (n4);
% control group
\draw[help lines]
($ (\tikzinputsegmentfirst) + (0,.2) $) --
($ (\tikzinputsegmentlast) + (0,.2) $);
}
},
decorate
},
mystyle/.default=5pt,
every node/.style={circle, draw}
}
\makeatother
\begin{document}
\begin{tikzpicture}
\node (A) at (0,0) {A};
\node (B) at (5,0) {B};
\draw[mystyle] (A) -- (B);
\end{tikzpicture}
\begin{tikzpicture}
\node (A) at (0,0) {A};
\node (B) at (5,0) {B};
\draw[mystyle={35pt}] (A) -- (B);
\end{tikzpicture}
\begin{tikzpicture}
\node (A) at (0,0) {A};
\node (B) at (5,1) {B};
\draw[mystyle={20}] (A) -- (B);
\end{tikzpicture}
\begin{tikzpicture}
\node (A) at (0,0) {A};
\node (B) at (5,1) {B};
\draw[mystyle={20}, shorten >=10pt] (A) -- (B);
\end{tikzpicture}
\end{document}
备注:为了支持,我猜需要curve to
类似的东西。\pgf@prep@curved(start|end)