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?

2
  • If they were 'real' arrows, bending would work. But these are not...
    – cfr
    Commented Feb 3, 2015 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
    Commented Feb 4, 2015 at 6:03

2 Answers 2

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;
3
  • 2
    Pfff... very nice again. Now I have to make the TikZ equivalent. Why do you do this to me? ;)
    – percusse
    Commented Feb 4, 2015 at 13:58
  • 1
    @percusse it's not personal!
    – Thruston
    Commented Feb 4, 2015 at 15:23
  • Very nice thank you. Still hope that someone is going to post a TikZ solution though.
    – user26756
    Commented Feb 5, 2015 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

You must log in to answer this question.

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