Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

The "shorten >=" option in TikZ causes a change in the shape of the Bezier curve. With a looping edge for example, it makes the loop asymmetrical (node A in the picture).

I could make it symmetrical using curveto,post=moveto and mark decorations but:

  1. The arrow head doesn't show up at the right place.
  2. It doesn't point towards the node.

See node B in the picture.

These can be fixed using custom arrow code and hand-tuning in the decoration (node C):

A: asymmetrical loop. B: wrong arrow head position and orientation. C: Correct.

Here is the code:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc,arrows,decorations.pathmorphing,decorations.markings}
\begin{document}
\begin{tikzpicture}

  \node [circle,draw] (A) at (0, 0) {A};
  \path (A) edge [out=240,in=300,min distance=8mm,-angle 90 reversed,shorten >=6pt] (A);

  \node [circle,draw] (B) at (2, 0) {B};
  \path (B) edge [out=240,in=300,min distance=8mm,
                  decoration={curveto,post=moveto,post length=8pt},
                  postaction={decoration={post length=0,markings,mark=at position 1
                                          with {\arrow{angle 90 reversed}}},decorate},
                  decorate] (B);

  \node [circle,draw] (C) at (4, 0) {C};
  \path (C) edge [out=240,in=300,min distance=8mm,
                  decoration={curveto,post=moveto,post length=8pt},
                  postaction={decoration={post length=0,markings,mark=at position 1
                  with {\draw [-angle 90 reversed] (0, 0) -- 
                        ($(0, 0)!2.5pt!(\tikztotarget.center)$);}},decorate},
                  decorate] (C);

\end{tikzpicture}
\end{document}

However it is a bit complex and requires hand-tuning. Does anyone see a better approach?

share|improve this question
    
Please post a compilable example. With this I get Argument of \tikz@cc@scan@one@rot has an extra }. <inserted text> \par l.23 decorate] (C) ; –  Peter Grill Mar 12 '12 at 15:17
    
I believe this is the same problem as report in Smooth option sometimes produces incorrect arrow tips in PGFplots, but can't see if that fixes it for you as the code does not compile. –  Peter Grill Mar 12 '12 at 15:20
    
@PeterGrill It should be working now. –  percusse Mar 13 '12 at 0:43
    
Not sure if this is what you are looking for, but if you remove the reversed option the arrows point towards the node? Also, you can increase min distance=12mm to get the arrow curve more towards the node center. –  Peter Grill Mar 13 '12 at 0:50
    
@PeterGrill The reversed was on purpose, it's the arrow head I needed for a drawing. A normal arrow still doesn't point towards the node center (cf. Andrew's answer). However a normal arrow does show up at the right position, unlike the reversed arrow in case (B). I wonder if the bad reversed arrow position is a bug in TiKZ... @percusse Thanks for fixing my typo. –  Jeremie Mar 13 '12 at 13:19
show 1 more comment

1 Answer

up vote 3 down vote accepted

I'm going to stick my neck out here a little bit - maybe by saying what I'm going to say then someone will be inspired to prove me wrong.

Does anyone see a better approach?

No.

Of course, you could wrap up your complicated code into a single decoration, but under the bonnet it would still be doing the same thing.

My reasoning is based on what information is available to PGF at the time that it decorates the path. This is just the raw path. PGF does not know how the path was actually specified. TikZ knew that, but it doesn't pass on that information to PGF. So even though you've written \draw (C) DoSomethingComplicated (C);[^1], TikZ adjusts the (C) to a point on the boundary of the node, and then forgets that it was (C) that you care about and only passes on the actual coordinate to PGF.

So PGF just gets the path between two points which happen to be on the boundary of the node (C), but PGF doesn't know about (C). You want to terminate this path early and then draw an arrowhead. This seems within PGF's provenance: for the termination, you can either use the decorations as you have or you could use the lower level \pgfpathcurvebetweentime macro which truncates a bezier curve. The advantage of the former method is that you can specify the truncation distance precisely, the advantage of the latter is that it is faster and produces an actual bezier curve for the output (instead of loads of short lines). That's easy enough for PGF as that only involves the path and the termination criterion.

However, you then want to place an arrow on the path. This is where the fact that PGF doesn't know as much as you do becomes important. All PGF knows is about the curve. So it can work out the direction of the curve at various points, including the termination point and the actual final point. However, neither of these is what you want. What you want is the direction from the termination point to whatever-the-final-point-was-looking-at. But the direction from the final point only gives you the line that that point lies on, not how far along it is. Since the termination point is displaced from the final point (that was rather the ... point ... of the whole process), you cannot figure out from the direction at the final point where you should be looking at the termination point, and therefore PGF cannot figure out what direction to put the arrow in. You therefore need to specify it, which is - in effect - what you do. There may well be slightly easier ways of specifying the direction, but probably not all that much.

(Actually, as I write this, I figured out one way that PGF could use the information given to work out the direction for the arrow, but the computations are definitely more complicated than what you already have so I'll leave it as an exercise for a passing TikZ enthusiast with more time on their hands than I have.)

[^1]: The DoSomethingComplicated path specification is currently under development in the TeX-SX laboratories.

share|improve this answer
    
Thanks, that makes a lot of sense. I will probably go for \pgfmathcurvebetweentime to keep the curve symmetrical. I wonder if someone wrote PGF code to approximate t(l) and l(t) (time as a function of the arc length and vice versa). Regarding how PGF could find the correct direction for the arrow head: do you have in mind calculating the intersection of the initial and final directions? That should work for loops at least (not for paths between two nodes). –  Jeremie Mar 13 '12 at 14:10
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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