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
  • 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. Oct 22, 2014 at 4:12

1 Answer 1

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

2
  • 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, 2014 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, 2014 at 13:37

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .