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.

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?

share|improve this question
    
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

6 Answers 6

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}

shifted triangle

share|improve this answer

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}

scaled and translated triangle

share|improve this answer

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}

node_coordinate_transforms

Not sure if it is 100% robust though.

share|improve this answer

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:

enter image description here

\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}
share|improve this answer
up vote 1 down vote accepted

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.

share|improve this answer
    
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

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}
share|improve this answer

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.