7

This is a follow-up to my recent question Half arrows in graph using TikZ.

\documentclass[tikz]{standalone}
\usetikzlibrary{matrix,arrows,arrows.meta,bending,decorations.pathreplacing,
                decorations.pathmorphing,decorations.markings,fit,patterns,
                shapes,intersections,calc}

\begin{document}

\tikzset
   {
    down oriented arrow/.style 2 args = {
      thick,
      decoration={
        markings,
        mark=at position 0.01 with
         {
          \coordinate (A) at (0,0);
          \coordinate (B) at (.125,.125);
         },
        mark=at position 0.99 with
         {
          \coordinate (C) at (-.25,.125);
          \coordinate (D) at (-.25,.25);
          \coordinate (E) at (0,0);
          \filldraw[#1,#2]
            (A) -- (B) -- (C) -- (D) -- (E) -- cycle;
         }
       },
      preaction = {decorate},
     },
    down oriented arrow/.default={draw=black}{fill=black!30}
   }
\tikzset
   {
    up oriented arrow/.style 2 args = {
      thick,
      decoration={
        markings,
        mark=at position 0.01 with
         {
          \coordinate (A) at (0,0);
          \coordinate (B) at (.125,-.125);
         },
        mark=at position 0.99 with
         {
          \coordinate (C) at (-.25,-.125);
          \coordinate (D) at (-.25,-.25);
          \coordinate (E) at (0,0);
          \filldraw[#1,#2]
            (A) -- (B) -- (C) -- (D) -- (E) -- cycle;
         }
       },
      preaction = {decorate},
     },
    up oriented arrow/.default={draw=black}{fill=black!30}
   }

\begin{tikzpicture}[align=center,node distance=3cm]
  \node[draw,circle] (a) {};
  \node[draw,circle,right of=a] (b) {};

  \node[draw,circle,below of=a] (c) {};
  \node[draw,circle,right of=c] (d) {};

  \draw[down oriented arrow={draw=green!90}{fill=green!30}] (a) to node [midway,sloped,above = 2pt] {$\vec{e}$} (b);
  \draw[down oriented arrow={draw=blue!90}{fill=blue!30}] (b) to (a);
  \draw[up oriented arrow={draw=orange!90}{fill=orange!30}] (b) to node [midway,sloped,above = 2pt] {$\vec{e}$} (c);
  \draw[up oriented arrow={draw=red!90}{fill=red!30}] (c) to (b);
  \draw[down oriented arrow] (d) to[bend right] (b);
\end{tikzpicture}

\end{document}

enter image description here

What I would like to achieve is that the decorations created by the up oriented arrow and down oriented arrow styles bend with the edge. Is it possible to achieve this?

  • If they were 'real' arrows, bending would work. But these are not... – cfr Feb 3 '15 at 23:25
  • @cfr I think there is no existing arrow style that does what I want. If you include custom arrows, then I disagree. They would not bend automatically right if you somehow connect the arrow head and tail as above. But I am not sure about how to do that anyway, so I am thankful for help. – user26756 Feb 4 '15 at 6:03
6

Here's a Metapost approach, using a macro to do the half-arrow. The arguments to the macro are a path and a colour. The arrow is made by moving segments of the path and then joining them up.

enter image description here

prologues := 3;
outputtemplate := "%j%c.eps";

vardef do_half_arrow(expr p, shade) = 
   save base, shaft, outline, barb; path base, shaft, outline; pair barb;
   base  = subpath(1/10 length p, 9/10 length p) of p;
   shaft = subpath(3/20 length p, 8/10 length p) of p 
           shifted (unitvector(direction 1/2 length p of p rotated 90) scaled 4);
   barb  = unitvector(direction 8/10 length p of p rotated 90) scaled 6 shifted point 8/10 length p of p;
   outline = base -- barb -- reverse shaft -- cycle;
   fill outline withcolor .8[shade, background];
   draw outline withcolor .4[shade, background];

enddef;

beginfig(1);

u = 3cm;

z0 = origin;
z1 = (u,0);
z2 = (u,u);
z3 = (0,u);

do_half_arrow(z3 -- z2, 1/2 green);
do_half_arrow(z2 -- z3, blue);
do_half_arrow(z0 -- z2, red + 1/2 green);
do_half_arrow(z2 -- z0, red);

draw z0--z2;
draw z2--z3;

path arc; arc = z1 {dir 60} .. z2;

do_half_arrow(arc,black);

draw arc;

forsuffixes $ = range 0 thru 3: 
  fill fullcircle scaled .12u shifted z$ withcolor background;
  draw fullcircle scaled .12u shifted z$;
  endfor

picture e;
e = thelabel(btex $\vec{e}$ etex, origin);
draw e shifted 10 up            shifted .5[z3,z2];
draw e shifted 10 up rotated 45 shifted .5[z0,z2];

endfig;
end.

The path can be any arbitrary curve, but it will probably work best with straight or gently curved lines, like this for example:

enter image description here

beginfig(2);
path p; 
p = origin .. (50,15) .. (100,-5) .. (140,10);

do_half_arrow(p, .67 blue);
do_half_arrow(reverse p, .53 red);
drawarrow p;

endfig;
| improve this answer | |
  • 2
    Pfff... very nice again. Now I have to make the TikZ equivalent. Why do you do this to me? ;) – percusse Feb 4 '15 at 13:58
  • 1
    @percusse it's not personal! – Thruston Feb 4 '15 at 15:23
  • Very nice thank you. Still hope that someone is going to post a TikZ solution though. – user26756 Feb 5 '15 at 18:23
6

I managed to finaly come up with a TikZ solution. It uses markings to define coordinates along the arrow and connects them afterwards.

\documentclass[tikz]{standalone}
\usetikzlibrary{matrix,arrows,arrows.meta,bending,decorations.pathreplacing,
                decorations.pathmorphing,decorations.markings,fit,patterns,
                shapes,intersections,calc}

\begin{document}
\tikzset
   {
    down oriented arrow/.style 2 args = {
      thick,
      shorten >= 0.2ex,
      shorten <= 0.2ex,
      line cap=round,
      decoration={
        markings,
        mark=at position 1ex with
         {
          \coordinate (T) at (0,0);
         },
        mark=between positions 2ex and -2ex step 1ex with
         {
          \pgfkeysgetvalue{/pgf/decoration/mark info/sequence number}{\j}
          \pgfmathtruncatemacro{\i}{\j-1}
          \coordinate (A\i) at (0,0);
          \coordinate (B\i) at (0,.1);
          \coordinate (C\i) at (0,.15);
         },
        mark=at position -1ex with
         {
          \pgfkeysgetvalue{/pgf/decoration/mark info/sequence number}{\j}
          \pgfmathtruncatemacro{\marks}{\j-2}
          \coordinate (H) at (0,0);
          \filldraw[#1,#2] (H) -- (C\marks)
            foreach \i in {\marks,...,1}
             { -- (B\i) }
            -- (T)
            foreach \i in {1,...,\marks}
             { -- (A\i)}
            -- cycle;
         }
        },
      preaction = {decorate},
     },
    down oriented arrow/.default={draw=black}{fill=black!30}
   }
\tikzset
   {
    up oriented arrow/.style 2 args = {
      thick,
      shorten >= 0.2ex,
      shorten <= 0.2ex,
      line cap=round,
      decoration={
        markings,
        mark=at position 1ex with
         {
          \coordinate (T) at (0,0);
         },
        mark=between positions 2ex and -2ex step 1ex with
         {
          \pgfkeysgetvalue{/pgf/decoration/mark info/sequence number}{\j}
          \pgfmathtruncatemacro{\i}{\j-1}
          \coordinate (A\i) at (0,0);
          \coordinate (B\i) at (0,-.1);
          \coordinate (C\i) at (0,-.15);
         },
        mark=at position -1ex with
         {
          \pgfkeysgetvalue{/pgf/decoration/mark info/sequence number}{\j}
          \pgfmathtruncatemacro{\marks}{\j-2}
          \coordinate (H) at (0,0);
          \filldraw[#1,#2] (H) -- (C\marks)
            foreach \i in {\marks,...,1}
             { -- (B\i) }
            -- (T)
            foreach \i in {1,...,\marks}
             { -- (A\i)}
            -- cycle;
         }
        },
      preaction = {decorate},
     },
    up oriented arrow/.default={draw=black}{fill=black!30}
   }

\begin{tikzpicture}[align=center,node distance=3cm]
  \node[draw,circle] (a) {};
  \node[draw,circle,right of=a] (b) {};

  \node[draw,circle,below of=a] (c) {};
  \node[draw,circle,right of=c] (d) {};

  \draw[down oriented arrow={draw=green!90}{fill=green!30}] (a) to node [midway, sloped, above = 2pt] {\color{green} $\vec{e}$} (b);
  \draw[down oriented arrow={draw=blue!90}{fill=blue!30}] (b) to node [midway, sloped, below = 1pt] {\color{blue} $\vec{f}$} (a);
  \draw[up oriented arrow={draw=orange!90}{fill=orange!30}] (b) to node [midway, sloped, above = 2pt] {\color{orange} $\vec{g}$} (c);
  \draw[up oriented arrow={draw=red!90}{fill=red!30}] (c) to node [midway, sloped, below = 1pt] {\color{red} $\vec{h}$} (b);
  \draw[down oriented arrow] (d) to[bend right] (b);
\end{tikzpicture}

\end{document}

Result: enter image description here

| improve this answer | |

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.