我需要一个宏来从任意点提取 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}
中并。x
y
\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
以便它更加明显。)
结果是:
答案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, ..., S5
x 坐标上命名。我的目标是在坐标(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
工作。删除空格的功劳归功于大卫·卡莱尔的回答。