# How to get the coordinates of the visual back end point of an arrow?

I tried to answer an interesting but underrated old question.

To make my answer work also for sloped paths, I need the coordinates of the visual back end point of an arrow.

From the TikZ manual:

I would like to change ([xshift=-#1]\tikzinputsegmentlast) in the following code with the coordinates of the visual back end of the arrow.

Is it possible?

\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}


As you can see, now the third picture is wrong.

The positions of the visual back end is stored in

\csname pgf@ar@visual@\pgf@arrow@id\endcsname


with format

{visual tip end}{visual back end}{}


So tip minus back is the distance you want to subtract from the line.

To learn \pgf@arrow@id, you pass the arrow specification to \pgfsetarrowsend. For instance \pgfsetarrowsend{Triangle[length=1cm]}. The function of the later command is two-fold:

• If the arrow spec has not been used before, it computes everything needed and caches.
• If the arrow spec has been used before, it sets \pgf@arrow@id to the old id.

Either way, you know \pgf@arrow@id and now \csname pgf@ar@visual@\pgf@arrow@id\endcsname makes sense. The rest is 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
\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}


• +1 You're the arrow master. Nov 25 at 10:04
• This is perfect, it works also with other arrow types. I can award the bounty in 7 hours. Nov 25 at 11:43
\coordinate (n3) at
($(\tikzinputsegmentlast)!#1!(\tikzinputsegmentfirst)$);


works. This defines n3 to be a coordinate along the line from segment last and segment first, and #1 (#1 must be a length) away from last.

Bonus: The code snippet below adds support for shorten >=<length>, as well as the use case when #1 is a unit-less "length" (by making use of a "feature" of pgfmath).

\coordinate (n3) at
($(\tikzinputsegmentlast)!#1+\pgf@shorten@end@additional!(\tikzinputsegmentfirst)$);


Full example

\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}


Remark: To support curve to, I guess something similar to \pgf@prep@curved(start|end) is required.

• +1 In the old question, the arrow head was given separate from the tricolor style. I made some experiments with applying three actions in the line of decoration={lineto, pre=moveto, pre length=0.66*\pgfmetadecoratedpathlength}, decorate, blue but I can not make it work with an arrow head. Nov 20 at 10:35
• @hpekristiansen I think the decoration never takes the path shortening into account, as shown in pgfmanual sec. 3.12 "Adding the Snaked Line and Multi-Line Text". Hence a complete answer to the old question really requires retrieving or re-calculating the shorten length. Nov 20 at 12:01
• Thank you @muzimuzhiZ. Actually, this solves the original problem but doesn't give exactly the answer to this question (the coordinates of the visual back end). I think you should answer the original question. I'll wait a bit before accepting your answer to see if someone else gives another solution. Nov 20 at 15:58
• Coordinate n3 is the one you need. If you prefer a standalone solution that works outside the decoration,\pgf@prepare@end@of@path can be a starter. I will try this way, maybe tomorrow. Nov 20 at 16:26
• @muzimuzhiZ Yes, but coordinate n3 is calculated using the length passed as an argument, it is not general. For example, if I change the arrow shape, the default doesn't work anymore. Thank you if you have time to dedicate to this tomorrow. Nov 20 at 16:38