Shortening and decorating a path
Well, if the shorten routine provided by TikZ does not do what you want, you may build your own. Here is a proposal inspired by this answer. The idea is to measure the length of the path and then switch the drawing off and on. (UPDATE: Add dash phase=0.0001pt
, a trick discovered by the OP, that avoids a very tiny point at the beginning of the path, which I failed to spot when I posted the earlier versions of this answer.)
\documentclass[border =3mm]{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations.markings}
\newlength\mylen
\newlength\vislen
\newlength\hidlen
\tikzset{
mid arrow/.style={postaction={decorate,decoration={markings,mark=at position .35 with {\arrow[#1]{stealth}}}}},
connect/.style={
decoration={
markings,
mark=at position 0.5 with {
\node[draw=none,inner sep=0pt,fill=none,text width=0pt,minimum size=0pt]
{\global\setlength\mylen{\pgfdecoratedpathlength}
\pgfmathsetmacro{\hiddenlength}{#1 mm}
\global\setlength\hidlen{\hiddenlength pt}
\pgfmathsetmacro{\visiblelength}{\pgfdecoratedpathlength-2*\hidlen}
\global\setlength\vislen{\visiblelength pt}
};
},
},
preaction={decorate},
dash pattern=on 0pt off \hidlen on \vislen off \hidlen,
dash phase=0.0001pt,
out=0, in=180, looseness=2},
}
\begin{document}
\begin{tikzpicture}
\coordinate (A) at (0,0); \coordinate (B) at (2,1);
\path[draw=blue] (A) edge[mid arrow=red, connect=1] (B);
\path[draw=orange] (B) edge[mid arrow=black, connect=0] (A);
\end{tikzpicture}
\end{document}
Let me stress that this is not a real alternative of TikZ' shorten (yet). For instance, if you were to add arrow heads by simply saying \draw[->]
, this won't work, i.e. the arrow heads would just sit at the position of the target, but a bit of the curve would be missing. (However, you could of course easily add arrow heads wherever you want them.)
ADDENDUM: Just for fun, added a more flexible style myconnect
which allows one to skip different amounts at the beginning and at the end of the path, and also double-checked that for curves with controls everything works fine.
\documentclass[border =3mm]{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations.markings}
\newlength\mylen
\newlength\vislen
\newlength\hidlen
\newlength\firstlen
\newlength\secondlen
\tikzset{
mid arrow/.style={postaction={decorate,decoration={markings,mark=at position .35 with {\arrow[#1]{stealth}}}}},
connect/.style={
decoration={
markings,
mark=at position 0.5 with {
\node[draw=none,inner sep=0pt,fill=none,text width=0pt,minimum size=0pt]
{\global\setlength\mylen{\pgfdecoratedpathlength}
\pgfmathsetmacro{\hiddenlength}{#1 mm}
\global\setlength\hidlen{\hiddenlength pt}
\pgfmathsetmacro{\visiblelength}{\pgfdecoratedpathlength-2*\hidlen}
\global\setlength\vislen{\visiblelength pt}
};
},
},
preaction={decorate},
dash pattern=on 0pt off \hidlen on \vislen off \hidlen,
dash phase=0.0001pt,
out=0, in=180, looseness=2},
}
\tikzset{myshorten/.style n args={3}{#1,
decoration={
markings,
mark=at position 0.5 with {
\node[draw=none,inner sep=0pt,fill=none,text width=0pt,minimum size=0pt]
{\global\setlength\mylen{\pgfdecoratedpathlength}
\pgfmathsetmacro{\hiddenlength}{#2}
\global\setlength\firstlen{\hiddenlength pt}
\pgfmathsetmacro{\hiddenlength}{#3}
\global\setlength\secondlen{\hiddenlength pt}
\pgfmathsetmacro{\visiblelength}{\pgfdecoratedpathlength-\the\firstlen-\the\secondlen}
\global\setlength\vislen{\visiblelength pt}
};
},
},
preaction={decorate},
dash pattern=on 0\mylen off \firstlen on \vislen off \secondlen,
dash phase=0.0001pt
}
}
\begin{document}
\begin{tikzpicture}
\coordinate (B) at (2,1); \coordinate (C) at (5,5);
\path[draw=red] (B) edge[mid arrow=blue,myshorten={out=0, in=180, looseness=2}{5mm}{7mm}]
(C);
\end{tikzpicture}
\begin{tikzpicture}
\coordinate (B) at (2,1); \coordinate (C) at (3,5);
\draw[gray,connect=0] (B) .. controls ++(0:1.75) and ++(180:1.75) .. (C);
\draw[mid arrow=red,connect=10] (B) .. controls ++(0:1.75) and ++(180:1.75) .. (C);
\end{tikzpicture}
\end{document}
The gray curve in the right picture is just to verify that the curve does not get deformed.
Just a little better ... And the problem is the same with controls
or arc
, see below.
\documentclass[border=3mm]{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations.markings}
\tikzset{
mid arrow/.style args={#1 at #2}{% #2 not 0 or 1 exactly
decoration={%
markings,
mark = at position #2 with {%
% what ever you want, as if you were in a scope
% the coordinate system tangential
\draw[#1,-stealth] (0,0)--(1pt,0pt);
}
},
postaction={decorate}
},
connect/.style={out=0, in=180, looseness=2, shorten >= #1, shorten <= #1},
}
\begin{document}
\begin{tikzpicture}
\coordinate (A) at (0,0);
\coordinate (B) at (2,1);
\path[draw=blue] (A) edge[mid arrow=red at .35, connect=1mm] (B);
\path[draw=orange] (B) edge[mid arrow=black at .35, connect=1mm] (A);
\end{tikzpicture}
\end{document}
To discuss the first remark in the comment (and to add more arrows in the race).
The problem is more complicated than just switching the decoration step (placing the arrow on the path) and the shorten step, because the black arrow follows the orange line but with gray tangential coordinate.
Switching the two steps is not enough: the shorten
action introduces a twist in the new path (the two paths are no more on the same drawn line) and, furthermore, a shift in pos
ition. Therefore, the tangential coordinates are calculated on the original path and are no more tangential to the new twisted drawn line.
pos
offset = 0.025 :
No pos
offset :
The twist: starting and ending points are shifted and leave the initial line and the in and out angles stays the same. shorten
does not make the line shorter, it rather creates a new one! Here, with a shorten of 10
, the red arrow should be on the dark blue line while it stays on the pale one, which is the original without shortening.
The problem is the same with controls
or arc
\documentclass[border=3mm]{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations.markings}
\tikzset{
mid arrow/.style={postaction={decorate,decoration={markings,mark=at position .35 with {\arrow[#1]{stealth}}}}},
connect/.style={shorten >= #1 mm, shorten <= #1 mm, looseness=2},
}
\begin{document}
\begin{tikzpicture}
\coordinate (A) at (0,0); \coordinate (B) at (2,1);
\draw[mid arrow=red,connect=10] (A) .. controls ++(0:1.75) and ++(180:1.75) .. (B) ;
\draw[mid arrow=black,orange] (B) .. controls ++(0:1.75) and ++(180:1.75) .. (A) ;
\draw[blue] (2,0) arc (0:45:2) ;
\draw[blue,mid arrow=red,connect=10] (2,0) arc (0:45:2) ;
\end{tikzpicture}
\end{document}