3

I want to draw so-called bond graphs with TikZ, where elements (nodes) are connected through half-arrows. I can use a "left/right to" arrow head, use the 3.0 \draw[-{Straight Barb[left]}] (a) -- (b), or create my own arrow head that has a larger stroke with \pgfarrowsdeclare, using the arrows, arrows.meta packages.

However, formatting rules dictate that the stroke of the half-arrow must always point downwards (on horizontal arrows) or to the left (on vertical arrows); diagonal arrows are treated as horizontal or vertical depending on their angle (45° is the cross-over point, of course: slightly more vertical than 45° is vertical).

Is it possible to define a pgf arrow head, a tikzstyle or some other macro to automatically make the stroke point either down or left, instead of left/right w.r.t. the path?

MWE:

\documentclass[a4paper,12pt]{article} 

\usepackage{tikz}
\usetikzlibrary{arrows,arrows.meta}

% Half-arrow with a large stroke
\pgfarrowsdeclare{ha}{ha} 
{ 
  \arrowsize=2pt 
  \advance\arrowsize by .5\pgflinewidth 
  \pgfarrowsleftextend{-4\arrowsize-.5\pgflinewidth} 
  \pgfarrowsrightextend{.5\pgflinewidth} 
} 
{ 
  \arrowsize=0.2pt 
  \advance\arrowsize by .5\pgflinewidth 
  \pgfsetdash{}{0pt} % do not dash 
  \pgfsetroundjoin   % fix join 
  \pgfsetroundcap    % fix cap 
  \pgfpathmoveto{\pgfpoint{-8\arrowsize}{-8\arrowsize}}
    \pgfpathlineto{\pgfpoint{0}{0}}
  \pgfusepathqstroke
} 

\begin{document}

    \pgfversion %3.0.0

  \begin{tikzpicture}
    \node (a) at (0,0) {a};
    \node (b) at (1,0) {b};
    \node (c) at (1,1) {c};
    \node (d) at (2,0) {d};
    \node (e) at (1,-1) {e};

    \draw[-{Straight Barb[right]}] (a) -- (b);
    \draw[-ha] (b) -- (c);
    \draw[-ha] (d) -- (b);
    \draw[-ha] (b) -- (e);

  \end{tikzpicture}

\end{document}

Result of MWE

In this MWE, a-b and b-e are correct, while b-c and d-b point in the wrong direction. I can fix this manually, by changing a left into right or v.v., but is there any way to do this automatically?

  • 1
    You would need to convey the direction information to the arrow selection, not possible using current syntax. You would need something like \arrow{from-coord}{to-coord} which would then select the appropriate \draw command. – John Kormylo Oct 22 '14 at 4:12
5

You could try a decoration which provides \pgfdecoratedangle (for straight lines this gives angle of the line) and use this to apply the appropriate arrow:

\documentclass[tikz,border=5]{standalone}
\usetikzlibrary{decorations.pathreplacing,arrows.meta}
\tikzset{barbs/.style={
  decoration={show path construction,
    lineto code={
    \draw 
      \pgfextra{%      
        \pgfmathparse{int(\pgfdecoratedangle/90)}% Possibly check for -ve values.
        \ifcase\pgfmathresult
          \tikzset{-{Straight Barb[right]}}
        \or
          \tikzset{-{Straight Barb[left]}}
        \or
          \tikzset{-{Straight Barb[left]}}
        \else
          \tikzset{-{Straight Barb[right]}}
        \fi
      }  (\tikzinputsegmentfirst) -- (\tikzinputsegmentlast);
    }
  },
  decorate
}}
\begin{document}
\begin{tikzpicture}
\node (o) {o};
\foreach \l [count=\i from 0] in {a,...,d}
   \node (\l) at (\i*90:1) {\l};

\foreach \l in {a,...,d}
  \draw [barbs] (\l) -- (o);
\end{tikzpicture}
\end{document}

enter image description here

  • I changed the ,decorate to postaction=decorate to allow extra style options like \draw[barbs,red,line width=1pt] (a) -- (b); to get through. Very nice solution! – Geert F Oct 22 '14 at 13:30
  • Ah, and a final modification to get the "cross-over point" at 45°: change int(\pgfdecoratedangle/90) to int((\pgfdecoratedangle+45)/90). Thanks again. :) – Geert F Oct 22 '14 at 13:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.