提取 TikZ 中任意点的 x,y 坐标

提取 TikZ 中任意点的 x,y 坐标

我需要一个宏来从任意点提取 x 和 y 坐标,如(3,4),或如(A),或如([xshift=-2pt] A.north west),其中A是节点的名称。

我已经看到了解决方案

 \newdimen\mydim
 \newcommand\getx[1]{
      \pgfextractx\mydim{\pgfpointanchor{#1}{center}}
 }

在 StackExchange 的其他地方,但这显然不适用于上述所有情况。我需要能够调用\getx{(3,4)}\getx{(A)}\getx{([xshift=-2pt] A.north west)},以及为了让它们都同样有效,在本例中将参数的 x 坐标放入变量中\mydim

我有点惊讶这看起来有多难!我肯定错过了什么……

答案1

您可以使用将最近使用的点的坐标提取到维度寄存器\pgfgetlastxy{\XCoord}{\YCoord}中并。xy\XCoord{\YCoord}

为了使该点成为最近使用的点,我\path在提取之前使用宏。下面是一个例子,我定义点,提取 x 和 y 坐标,然后通过提取的坐标标记它们。该点C位于X-codA-坐标B

在此处输入图片描述

笔记:

  • 这已更新,当将scale=因子应用于时可以正常工作tikzpicture。要查看输出结果而不调整比例因子,请取消注释该行

    %\let\ExtractCoordinate\ExtractCoordinateOld
    

代码:

\documentclass[border=2pt]{standalone}

\usepackage{tikz}
\usetikzlibrary{calc}

%% https://tex.stackexchange.com/questions/86897/recover-scaling-factor-in-tikz
\newcommand*\getscale[1]{%
  \begingroup
    \pgfgettransformentries{\scaleA}{\scaleB}{\scaleC}{\scaleD}{\whatevs}{\whatevs}%
    \pgfmathsetmacro{#1}{sqrt(abs(\scaleA*\scaleD-\scaleB*\scaleC))}%
    \expandafter
  \endgroup
  \expandafter\def\expandafter#1\expandafter{#1}%
}

\makeatletter
\newdimen\@XCoord
\newdimen\@YCoord
\newdimen\XCoord
\newdimen\YCoord
\newcommand*{\ExtractCoordinate}[1]{%
    \getscale{\@scalefactor}
    \path [transform canvas] (#1); \pgfgetlastxy{\@XCoord}{\@YCoord}
    \pgfmathsetlength{\XCoord}{\@XCoord/\@scalefactor}
    \pgfmathsetlength{\YCoord}{\@YCoord/\@scalefactor}
}
\newcommand*{\ExtractCoordinateOld}[1]{%
    \path [transform canvas] (#1); \pgfgetlastxy{\XCoord}{\YCoord}%
}%
%\let\ExtractCoordinate\ExtractCoordinateOld
\makeatother

\newcommand*{\LabelCurrentCoordinate}[2]{%
    \fill [#1] ($(\XCoord,\YCoord)$) circle (2pt) node [right] {#2}
}


\newdimen\XCoordA
\newdimen\YCoordA
\newdimen\XCoordB
\newdimen\YCoordB

\begin{document}
\begin{tikzpicture}[scale=1.5]
    \coordinate (A) at (3,2);
    \coordinate (B) at ([xshift=-2cm,yshift=-1cm] A.north west);

    \ExtractCoordinate{$(A)$};
    \LabelCurrentCoordinate{red}{A};
    \setlength\XCoordA{\XCoord}
    \setlength\YCoordA{\YCoord}

    \ExtractCoordinate{$(B)$};
    \LabelCurrentCoordinate{blue}{B};
    \setlength\XCoordB{\XCoord}
    \setlength\YCoordB{\YCoord}

    \ExtractCoordinate{$(\XCoordA,\YCoordB)$};
    \LabelCurrentCoordinate{magenta}{C};
\end{tikzpicture}
\end{document}

答案2

Peter、Jamie 和 wh1t3(评论中的最后一个)的答案都很好。我将其添加为“低级”版本,因为这通常是人们想要作为更大事情的一部分来做的事情,然后知道如何在这个较低的级别上做这件事会很有用。

扫描坐标并找出其实际对应位置的 TikZ 命令称为\tikz@scan@one@point。它有点需要两个参数。第一个是宏,第二个是要扫描的点。之所以说是“有点”,是因为第二个参数不是参数,而只是裸坐标。解析坐标,直到 TikZ 认为它已经足够理解它,可以在页面上生成真实的 xy 坐标,然后调用 宏,并以该 xy 坐标作为其参数(具体来说,它调用\themacro{\pgfpoint{x-coord}{y-coord}}。通过指定宏为\@firstofone(或者\pgfutil@firstofone如果我们想成为优秀的 PGFers),我们可以将\pgf@x\pgf@y设置为这些坐标。如果我们想保存它们,我们可以传递一个花哨的保存宏,或者只是保存\pgf@x和的值\pgf@y

这是一个简单的例子,我们定义一个接受三个参数的宏,即坐标和两个用于保存 x 和 y 坐标的宏。

\documentclass{article}
%\url{http://tex.stackexchange.com/q/33703/86}
\usepackage{tikz}
\makeatletter
\newcommand{\gettikzxy}[3]{%
  \tikz@scan@one@point\pgfutil@firstofone#1\relax
  \edef#2{\the\pgf@x}%
  \edef#3{\the\pgf@y}%
}
\makeatother
\begin{document}
\begin{tikzpicture}
\draw (0,0) .. controls +(1,0) and +(-1,0) .. node[auto] (A) {A} (3,3);
\gettikzxy{(A)}{\ax}{\ay}
\fill[red,fill opacity=.5] (\ax,\ay) circle[radius=12pt];
\begin{scope}[rotate=45,xshift=3cm]
\draw (0,0) -- node[auto] (B) {B} (3,2);
\end{scope}
\gettikzxy{(B)}{\bx}{\by}
\fill[blue,fill opacity=.5] (\bx,\by) circle[radius=12pt];
\gettikzxy{([xshift=-2cm] A.north west)}{\cx}{\cy}
\fill[green] (\cx,\cy) circle[radius=2pt];
\fill ([xshift=-2cm] A.north west) circle[radius=1pt];
\end{tikzpicture}
\end{document}

(最后一个是从你的问题中取出的,但我将转变改为,2cm以便它更加明显。)

结果是:

获取 TikZ 坐标

答案3

这感觉很不对,但我无论如何都会这么做……

\newdimen{\tempx}
\newdimen{\tempy}
\newcommand\getxy[1]{
    \coordinate (tmp) at #1;
    \pgfextractx\tempx{\pgfpointanchor{tmp}{center}}
    \pgfextracty\tempy{\pgfpointanchor{tmp}{center}}
}

答案4

e1, ..., e6我有一个点矩阵,分别在 y 坐标和S1, ..., S5x 坐标上命名。我的目标是在坐标(ei -| Sj)处为某些给定点绘制一个小正方形(就像邻接矩阵一样)。

我试图使用以前的解决方案从列表中提取点的 x 和 y 分量,例如

\foreach \pt in {(1 ,2), (1, 3), (2, 2), (2, 4)} {
    \parsept{\x}{\y}{\pt}
    \fill (S\x |- e\y) +(-1, -1) rectangle +(1, 1);
}

请注意,在这种情况下先前的解决方案不再有效,因为它们提取原始坐标由 TikZ 计算,因此 TeX 引擎会寻找名为S28.221344pt(失败) 的某个点。

所以我最终编写了一个用于解析( x , y )表达式的简单宏。该解决方案可能对其他读者有用要求按字面意思解析坐标

\makeatletter
\def\parsept#1#2#3{%
    \def\nospace##1{\zap@space##1 \@empty}%
    \def\rawparsept(##1,##2){%
        \edef#1{\nospace{##1}}%
        \edef#2{\nospace{##2}}%
    }%
    \expandafter\rawparsept#3%
}
\makeatother

宏会删除参数中的所有空格(因此\parsept{\x}{\y}{( a b, c)}会产生\x=ab\y=c),但我无法在此上下文中使\ignorespaces\unskip工作。删除空格的功劳归功于大卫·卡莱尔的回答

相关内容