# Transform defined coordinates in TikZ

Say I have a triangle with vertices defined using

\coordinate (a) at (0,0);
\coordinate (b) at (1,0);
\coordinate (c) at (0,1);


Let us denote by T(x,y) the triangle defined by (a),(b) and (c) which is translated by a vector (x,y). I can now easily draw T(0,0) as follows:

\draw (a) -- (b) -- (c) -- cycle;


So far so good. Now, lets say that I want to plot the triangle T(2,3). Ideally, I would like to do something like:

\begin{scope}[shift={(2,3)}]
\draw (a) -- (b) -- (c) -- cycle;
\end{scope}


However, as the coordinates were defined outside of the scope the transformation (translation in this case) won't effect them. See this answer. What would be the smart way to do it? Or more generally:

What is the best way to reuse coordinates that are defined once under varying transformations?

Possible solution: Basing on the comment of @Qrrbrbirlbel I posted an answer. This answer however, is very limited and local - is the something more general?

-
Depending on your use-case, shifting every coordinate (\draw ([shift={(2,3)}] a) -- ([shift={(2,3)}] b) -- ([shift={(2,3)}] c) -- cycle;) or using a canvas transformation can be the solution. See the top part of another answer. – Qrrbrbirlbel Feb 19 '13 at 13:18

## 7 Answers

As the other questions linked have explained the issue, I'll not go over old ground. Looking at the code there does not seem to be an easy way to say "Apply the following style (say, shift={(2,3)}) to all of the following points.". There is no every point style (contrast the many every path or every node or ...). Moreover, adding one in would not be simple as the coordinate parser needs to see the [ to invoke the bit that does the transformation (the code here has the illuminating comment uhoh... options! at this point).

So there's not a really, really simple solution. But there is a way to make the proper way to do this a little simpler using styles.

\documentclass{article}
%\url{http://tex.stackexchange.com/q/98924/86}
\usepackage{tikz}

\tikzset{
c/.style={every coordinate/.try}
}

\begin{document}
\begin{tikzpicture}
\coordinate (a) at (0,0);
\coordinate (b) at (1,0);
\coordinate (c) at (0,1);
\draw (a) -- (b) -- (c) -- cycle;
\begin{scope}[every coordinate/.style={shift={(2,3)}}]
\draw ([c]a) -- ([c]b) -- ([c]c) -- cycle;
\end{scope}
\end{tikzpicture}
\end{document}


-

It isn't straightforward at all to add a general every coordinate style. But, a \iftikztransformnodecoordinates is fairly simply to hack.

\documentclass{standalone}
\usepackage{tikz}

\makeatletter
\newif\iftikztransformnodecoordinates
\tikzset{transform node coordinates/.is if=tikztransformnodecoordinates}

\def\tikz@parse@node#1(#2){%
\pgfutil@in@.{#2}%
\ifpgfutil@in@
\tikz@calc@anchor#2\tikz@stop%
\else%
\tikz@calc@anchor#2.center\tikz@stop%
\expandafter\ifx\csname pgf@sh@ns@#2\endcsname\tikz@coordinate@text%
\else
\tikz@shapebordertrue%
\def\tikz@shapeborder@name{#2}%
\fi%
\fi%
\iftikztransformnodecoordinates%
\pgf@pos@transform{\pgf@x}{\pgf@y}%
\fi
\edef\tikz@marshal{\noexpand#1{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}}%
\tikz@marshal%
}

\begin{document}

\begin{tikzpicture}

\coordinate (a) at (0,0);
\coordinate (b) at (1,0);
\coordinate (c) at (0,1);

\draw (a) -- (b) -- (c) -- cycle;

\draw [red, transform node coordinates, rotate=10]
(a) -- (b) -- (c) -- cycle;

\draw [green, transform node coordinates, shift={(1,1)}]
(a) -- (b) -- (c) -- cycle;

\draw [blue, transform node coordinates, rotate=10, shift={(1,1)}]
(a) -- (b) -- (c) -- cycle;

\end{tikzpicture}

\end{document}


Not sure if it is 100% robust though.

-

In TikZ/pgf, transformations are applied only to numeric coordinates. To retrieve original numeric coordinates from nodes or coordinates, you may use a let operation:

\documentclass[tikz]{standalone}
\usetikzlibrary{calc,scopes}
\begin{document}
\begin{tikzpicture}
\coordinate (a) at (0,0);
\coordinate (b) at (1,0);
\coordinate (c) at (0,1);
\draw (a) -- (b) -- (c) -- cycle;

\draw[blue] let \p{a}=(a),\p{b}=(b),\p{c}=(c) in
{[rotate=30] (\p{a}) -- (\p{b}) -- (\p{c}) -- cycle}
{[shift={(2,3)}] (\p{a}) -- (\p{b}) -- (\p{c}) -- cycle};
\end{tikzpicture}
\end{document}

-

What about defining a generic anchor (r for relative) which applies the transformation? EDIT: Now a version that really works!

Two problems:

• the code that calls the generic anchor expects the coordinates in the node's cs.
• that same code applies the inverse of the outer transformation --- this is what makes the named coordinates absolute!

Out job is to do the inverses of all these operations (in the reverse order).

\documentclass{article}
\usepackage{tikz}

\makeatletter
\pgfdeclaregenericanchor{r}{%
% 1. get (x,y) in the node's cs
\pgf@sh@reanchor{\csname pgf@sh@ns@\pgfreferencednodename\endcsname}{center}%
{% 2. apply the node transformation
\pgfsettransform{\csname pgf@sh@nt@\pgfreferencednodename\endcsname}%
\pgf@pos@transform{\pgf@x}{\pgf@y}%
\global\pgf@x=\pgf@x%
\global\pgf@y=\pgf@y%
}%
% 3. *don't* apply the inverse of the outer transformation! We want
%    relative coordinates!
{% 4. apply the inverse of the inverse of the outer transform
%    (cancels the inverse of the outer transformation done by \pgfpointanchor)
\pgf@pos@transform{\pgf@x}{\pgf@y}%
\global\pgf@x=\pgf@x%
\global\pgf@y=\pgf@y%
}%
{% 5. apply the inverse of the nodes transformation (cancels the node
%    transformation done by \pgfpointanchor)
\pgfsettransform{\csname pgf@sh@nt@\pgfreferencednodename\endcsname}%
\pgftransforminvert
\pgf@pos@transform{\pgf@x}{\pgf@y}%
\global\pgf@x=\pgf@x%
\global\pgf@y=\pgf@y%
}%
}
\makeatother

\begin{document}

\begin{tikzpicture}
\coordinate (a) at (0,0);
\coordinate (b) at (1,0);
\coordinate (c) at (0,1);
\draw[blue,ultra thick] (a) -- (b) -- (c) -- cycle;
\begin{scope}[shift={(2,0)},scale=2]
\draw[red] (a.r) -- (b.r) -- (c.r) -- cycle;
\end{scope}
\end{tikzpicture}

\end{document}


-

Not as pgf-hacky as the other answers, but how about the following. Very straight forward, simple and easy to understand workaround.

\documentclass{article}
\usepackage{tikz}

\begin{document}
\begin{tikzpicture}
\newcommand*{\defcoords}{%
\coordinate (a) at (0,0);
\coordinate (b) at (1,0);
\coordinate (c) at (0,1);
}
\begin{scope}[shift={(0,0)}]
\defcoords
\draw (a) -- (b) -- (c) -- cycle;
\end{scope}
\begin{scope}[shift={(2,3)}]
\defcoords
\draw (a) -- (b) -- (c) -- cycle;
\end{scope}
\end{tikzpicture}
\end{document}

-

Based on the comment of @Qrrbrbirlbel: One can define the coordinates globally as in the OP. Then, the following function can be defined:

\newcommand*{\drawT}[1]{%
\draw ([shift={#1}] a) -- ([shift={#1}] b) -- ([shift={#1}] c) -- cycle;%
}


Now, calling \drawT{(2,3)} will draw T(2,3) as per the OP definitions.

-
I accepted my own answer because this is the one I actually used once I posted it and it solved my problem. I did not tested the other solutions. – Dror Feb 24 '13 at 16:09

Here is a solution that is mixture of a macro seen in another answer and the pic command from TiKz 3.0.

% macro taken from http://tex.stackexchange.com/a/33765
% -----------------------------------------------------
\makeatletter
\newcommand{\gettikzxy}[3]{%
\tikz@scan@one@point\pgfutil@firstofone#1\relax
\edef#2{\the\pgf@x}%
\edef#3{\the\pgf@y}%
}
\makeatother
% -----------------------------------------------------

\begin{tikzpicture}

\coordinate (a) at (0,0);
\coordinate (b) at (1,0);
\coordinate (c) at (0,1);

\gettikzxy{(a)}{\ax}{\ay}
\gettikzxy{(b)}{\bx}{\by}
\gettikzxy{(c)}{\cx}{\cy}
\tikzset{
triangle/.pic={
\path[pic actions] (\ax,\ay) -- (\bx,\by) -- (\cx,\cy) -- cycle;
}
}

\path (1,1) pic[draw]{triangle};
\path (0,0) pic[fill=red]{triangle};
\end{tikzpicture}


EDIT : Here is another solution that produce the same image using 'let/shift' trick (adapted from Paul Gaborit's answer).

\begin{tikzpicture}

\coordinate (a) at (0,0);
\coordinate (b) at (1,0);
\coordinate (c) at (0,1);

\coordinate (origin) at (0,0);
\tikzset{
triangle/.pic={
\path let \p{a}=(a), \p{b}=(b), \p{c}=(c) in
[pic actions, shift={([scale=-1]origin)}]
(\p{a}) -- (\p{b}) -- (\p{c}) -- cycle;
}
}

\path (1,1) pic[draw]{triangle};
\path (0,0) pic[fill=red]{triangle};
\end{tikzpicture}


NOTE: But with this second method rotate and scale don't work. For example

\path (0,0) pic[fill=red, rotate=30]{triangle};


do not rotate the triangle (with the first method it is ok). Like if rotate=30 is not passed to pic actions but directly transforming the coordinates (as directly passed to path command).

-