[Tex/LaTex] Why does coordinate (X) [midway] doesn’t work, while coordinate [midway] (X) is fine


Why doesn’t the coordinate see the options if they are behind the name? With nodes it makes no difference wether the options follow or precede the name.


    \draw (0,3) -- ++(5,0) node (A) [midway] (A) {};
    \draw (0,2) -- ++(5,0) node (B) [midway] {};
    \draw (0,1) -- ++(5,0) coordinate [midway] (C);
    \draw (0,0) -- ++(5,0) coordinate (D) [midway];
    \foreach \C in {A,B,C}
        \fill (\C) [green!70!black] circle [radius=1pt] node [above] {\C\ is ok};
    \fill (D) [red!70!black] circle [radius=1pt] node [above] {D is not};
    \fill (2.5,0) [green!70!black] circle [radius=1pt] node [above] {D};

coordinate options

The point D should be in the middle of the line as the others but it seems like the coordinate can’t see the midway option. I guess the reason is the way how TikZ parses a coordinate (starting with coor… ending with …)?) but I wonder if this is a bug and should be reported …

Best Answer

I guess the reason is the way how TikZ parses a coordinate (starting with coor… ending with …)?) […]

What is a coordinate?
A coordinate is nothing but a node shape that doesn’t have anything except one coordinate (the .center anchor is the same as every other anchor).

How does TikZ work?
It scans its way through the whole \path and looks out for key words or sequences of characters in a combination of \futurelets and ifnextchars.

If it encounters a c it tests for a following i (→ circle) or a following h (→ child), otherwise it must (should) be an o that follows. It tests than whether another o follows, otherwise it must be cos.

If everything works (i.e. co without a following o) \tikz@coordinate will be called.

% Syntax for coordinates:
% coordinate[options] (coordinate name) at (point)
% where ``at (point)'' is optional
\def\tikz@coordinate ordinate{%
  {\tikz@fig ode[shape=coordinate,#1]{}}}%}
  \pgfutil@ifnextchar a{\tikz@@coordinate@at[#1](#2)}
  {\tikz@fig ode[shape=coordinate,#1](#2){}}}
  \pgfutil@ifnextchar t{\tikz@@coordinate@@at[#1](#2)a}%
  {\tikz@fig ode[shape=coordinate,#1](#2){}a}%

The macro \tikz@coordinate (that gobbles ordinate) then checks for an [ (or assumes an option-less coordinate, ergo an empty []). TikZ allows at this point only coordinate [optional arguments] (optional name) (and the at part at the end that I will leave out now). If this sequence is found (with or without at) an actual node is made with he absolute final (empty) node text (which is ignored in the case of a coordinate anyway).

The node text {} is absolutely final on the node path operator in a path. After that, every option used is applied to the path (like [draw]). In your example the [midway] is set for the path (which is the default anyway) and does only apply to nodes/coordinates between a path operator (like --) and the target coordinate.

The \tikz@fig ode macro works a little bit different because it always tests for options [, a name ( and a position at. Those can be mixed freely as it works similar to the whole path which is ended with ;.

Another way to look at it is to use:

\draw (0,1) -- ++(5,0) coordinate [midway, red] (C);
\draw (0,0) -- ++(5,0) coordinate (D) [midway, red];

In the first line the coordinate (which doesn’t have a path) would be red, in the second case, the path is red as if you would have written \draw[red].

[…] but I wonder if this is a bug and should be reported …

Well, how would you signalize the end of a coordinate path operation? TikZ defines

…             coordinate          [<options>]   (<name>)    at (<position>)  …

^                 ^                   ^            ^         ^        ^      ^
rest of path  specifies a coord.   optional    optional       optional    rest of path

in exactly this order with one of the optional sequences being the final part of the coordinate. It doesn’t even allow

coordinate at (<somewhere>) [<options>] (<name>)

but it does

node[shape=coordinate] at (<somewhere) [<options>]
               (<name>) [<other options>] (<overwriting the previous set name>) {}