A first step to better arrow placement would be to be able to move arrows along the path by some given distance, e.g. to say something like place the arrow 3pt left of the middle of the path.
So I started to look at the code in pgflibrarydecorations.markings
. The posititon calculation is done by \pgf@lib@dec@parsenum
.
At first I thought I could simply put a wrapper around that macro that splits any input with +
into the summands, calculates the lengths of each separately and then adds them together.
Unfortunately this doesn't work: the macro subtracts negative values form the total length, so that 0.5-3pt
would become 0.5*(total length) + (total length) - 3pt. So I rewrote the whole macro.
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{decorations.markings}
\makeatletter
% overwrite the number parsing macro from pgflibrarydecorations.markings
\def\pgf@lib@dec@parsenum#1{%
\gdef\pgf@lib@dec@computed@width{0 pt}%
\tsx@pgf@lib@dec@parsenum#1+endmarker+%
\ifdim\pgf@lib@dec@computed@width<0pt\relax%
\pgfmathparse{\pgfdecoratedpathlength\pgf@lib@dec@computed@width}
\edef\pgf@lib@dec@computed@width{\pgfmathresult pt}%
\fi%
}
\def\tsx@pgf@lib@dec@parsenum@endmarker{endmarker}
% this is iterated over all numbers that are summed
\def\tsx@pgf@lib@dec@parsenum#1+{
\def\temp{#1}%
\ifx\temp\tsx@pgf@lib@dec@parsenum@endmarker%
\else%
\tsx@pgf@lib@dec@parsenum@one{#1}%
\expandafter\tsx@pgf@lib@dec@parsenum%
\fi%
}
% calculate the length for each number
\def\tsx@pgf@lib@dec@parsenum@one#1{%
\pgfmathparse{#1}%
\ifpgfmathunitsdeclared%
\pgfmathparse{\pgf@lib@dec@computed@width + \pgfmathresult pt}%
\else%
\pgfmathparse{\pgf@lib@dec@computed@width + \pgfmathresult*\pgfdecoratedpathlength*1pt}%
\fi%
\edef\pgf@lib@dec@computed@width{\pgfmathresult pt}%
}
\makeatother
\begin{document}
\begin{tikzpicture}
\draw[decoration={
markings,
mark={at position 0.5 + -1cm with {\arrow{>}}},
},
postaction={decorate}
]
(0,0) to [out=30, in=150] (4,0);
\end{tikzpicture}
\end{document}
This is my first time writing this type of iterative macro. So maybe someone could tell me if this is the 'right' way to do this. Also, is there an easy way to allow both plus and minus in the input, e.g. 0.5-1cm
instead of 0.5+-1cm
? (I know, I shouldn't put a question into an answer...)