6

If I extract coordinates with \pgfgetlastxy{}{}, I get changing results depending on the transformations I've applied to my draw (rotation, scale):

\documentclass[margin=0.5cm]{standalone}
\usepackage{tikz}

\newcommand{\myDraw}[2]{%
\begin{minipage}[t]{6cm}
  \centering #1,#2\\
  \begin{tikzpicture}[#1,#2]
    \draw[->] (0,0) -- (3,0);
    \draw[->] (0,0) -- (0,3);
    \coordinate (A) at (1,3);
    \draw[blue] (A) node {$+$} node[above right] {\footnotesize A(2,3)};
    \path (A); \pgfgetlastxy{\xA}{\yA}; % Extract the coordinates of A
    \draw[red] (canvas cs:x=\xA,y=\yA)
      node {$+$} node[red,below right] {\parbox{2.5cm}{\footnotesize \textbackslash xA = \xA\\\textbackslash yA = \yA}};
  \end{tikzpicture}
\end{minipage}}

\begin{document}
  \myDraw{scale=1}{rotate=0}
  \myDraw{scale=0.5}{rotate=0}
  \myDraw{scale=1}{rotate=-20}
\end{document}

Output

And yet, I want to get the coordinates of A in the current scope (i.e \xA = 1 and \yA = 3 in the example above) because I need to apply later some conditionals (like "if \xA < \xb then...").

I was thinking maybe of using a command like \pgftransformreset inside a group and then "smuggle" the non transformed coordinates out of the group. But I'm mostly an LaTeX/TikZ end user and I don't know how to achieve that.

Moriambar
  • 11,466
remjg
  • 2,486

2 Answers2

7

Numbers get slightly distorted due to internal transformation inersion.

\documentclass[margin=0.5cm]{standalone}
\usepackage{tikz}
\makeatletter
\newcommand{\myDraw}[2]{%
\begin{minipage}[t]{6cm}
  \centering #1,#2\\
  \begin{tikzpicture}[#1,#2]
    \draw[->] (0,0) -- (3,0);
    \draw[->] (0,0) -- (0,3);
    \coordinate (A) at (1,3);
    \draw[blue] (A) node {$+$} node[above right] {\footnotesize A(2,3)};
    \pgfpointanchor{A}{center} %<----
    \edef\xa{\the\pgf@x}
    \edef\ya{\the\pgf@y}       %<----
    \draw[red] (canvas cs:x=\xa,y=\ya)
               node {$+$} node[red,below right] {\parbox{2.5cm}{\footnotesize%
               \textbackslash xA = \xa\\\textbackslash yA = \ya}};

  \end{tikzpicture}
\end{minipage}}
\makeatother
\begin{document}
  \myDraw{scale=1}{rotate=0}
  \myDraw{scale=0.5}{rotate=0}
  \myDraw{scale=1}{rotate=-20}
\end{document}

enter image description here

The marked code can be replaced with a higher level TikZ syntax

\path (A); \pgfgetlastxy{\xA}{\yA}; % Extract the coordinates of A
\begin{scope}
\pgftransforminvert
\coordinate (B) at (\xA,\yA);\path (B); \pgfgetlastxy{\xB}{\yB};    
\xdef\xorigA{\xB}
\xdef\yorigA{\yB}
\end{scope}

which does more or less the same thing.

percusse
  • 157,807
  • Note that there is a low level smuggle mechanism for PGF but let me know if you need it. – percusse Aug 29 '13 at 22:06
  • Nice! Since I need to do that many times, I have included your code in a separate macro which can be called like this: \extractCoordinates{A}{\xA}{\yA}. I've pasted the definition of the macro below: \newcommand{\extractCoordinates}[3]{% \begin{scope} \path (#1); \pgfgetlastxy{\xTEMP}{\yTEMP}; % Extract the coordinates of A \pgftransforminvert \coordinate (TEMP) at (\xTEMP,\yTEMP);\path (TEMP); \pgfgetlastxy{\xTEMP}{\yTEMP}; \xdef#2{\xTEMP} \xdef#3{\yTEMP} \end{scope}} I run quickly into some troubles so I had to change the names of the variables. Any advice on how to improve it? – remjg Aug 29 '13 at 22:41
  • @remjg I've simplified a little – percusse Aug 29 '13 at 23:47
  • Indeed, it's way simpler, I like it! I'm going to chose this answer but I have two requests if you don't mind. Could you post your previous answer in an other answer? I think it's a valuable answer, at least for learning. Also, do you mind if I add a macro version at the end of your answer? – remjg Aug 30 '13 at 08:16
  • @remjg Sure be my guest. I've put the old version. – percusse Aug 30 '13 at 15:28
5

Here a solution, without the low level macro \pgfgetlastxy, via a let operation:

enter image description here

\documentclass[margin=0.5cm]{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}

\newcommand{\myDraw}[2]{%
\begin{minipage}[t]{6cm}
  \centering #1,#2\\
  \begin{tikzpicture}[#1,#2]
    \draw[->] (0,0) -- (3,0);
    \draw[->] (0,0) -- (0,3);
    \coordinate (A) at (1,3);
    \draw[blue] (A) node {$+$} node[above right] {\footnotesize A(2,3)};

    \path [green!50!black]
    let \p1=(A) in
    (\x1,\y1)  node {$+$}
    node[below right,align=left,font=\footnotesize]{
      \textbackslash xA = \x1\\
      \textbackslash yA = \y1
    };

  \end{tikzpicture}
\end{minipage}}

\begin{document}
  \myDraw{scale=1}{rotate=0}
  \myDraw{scale=0.5}{rotate=0}
  \myDraw{scale=1}{rotate=-20}
\end{document}

If you need these macro definitions after the path and its let operation, you may:

  • use \xdef:

\path let \p1=(A) in
  \pgfextra{
    \xdef\xA{\x1}
    \xdef\yA{\y1}
  };
  • use \AfterGroup (from etextools package):

\usepackage{etextools}
...
\path let \p1=(A) in
  \pgfextra{
    \AfterGroup*{
      \noexpand\def\noexpand\xA{\x1}
      \noexpand\def\noexpand\yA{\y1}
    }
  };
Paul Gaborit
  • 70,770
  • 10
  • 176
  • 283
  • Thank you! The issue with the let operation is that it can only be used inside a path. I need to access to the coordinates inside conditionals later on. – remjg Aug 29 '13 at 22:20
  • After a few tries, I can use the let operation and an empty node to define \xA and \yB so I can use them later: \draw let \p1=(A) in (A) node {\xdef\xA{\x1}\xdef\yA{\y1}}; But I don't know really what \xdef is (a king of global variable I imagine) and I gess it's quite a bad pratice... – remjg Aug 30 '13 at 10:08
  • 2
    @remjg You don't need the node to \xdef (yes it globally defines \xA while expanding its content (\x1 and \y1 here), you can do \path let \p1=(A) in \pgfextra{\xdef…};. – Qrrbrbirlbel Aug 30 '13 at 16:02