在以下 MWE 中,我知道注释行有效。我想知道的是为什么该every node/.style
方法不起作用。
\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}[x=2in,y=2in]
\node (A) at (1,0) {};
\node (B) at (0,1) {};
\node (C) at (-1,0) {};
\node (D) at (1,1) {};
% \draw (A.center) -- (B.center) -- (D.center) -- (C.center) -- cycle;
\draw[every node/.style={anchor=center}] (A) -- (B) -- (D) -- (C) -- cycle;
\end{tikzpicture}
\end{document}
有什么方法可以做到这一点而不必(<node_name>.center)
为我想连接的每个节点都写一条线?
更新
我可以写类似下面的内容:
\def\concatenatedpoints{}
\foreach \x in {A,B,C,D}
{\xdef\concatenatedpoints{\concatenatedpoints (\x.center) -- } }
\draw \concatenatedpoints cycle;
这产生了预期的效果。当然,我可以编写一个宏来实现这一点,以便每当我想以这种方式连接节点时都可以使用。
但似乎他们必须采用一种更具tikz
风格的方法来有效地连接节点,就像它们是coordinate
s 一样。
进一步更新
我尝试过与 @percusse 在评论中和 @jldiaz 在他的回答中提出的建议非常相似的方法。我尝试的是
\draw \foreach \x in {A,B,D,C}{(\x.center) -- } cycle;
我非常好奇为什么我的方法会失败,但他们的方法却可以。
答案1
这是一个愚蠢的想法,语法也很丑陋,但也许你确实喜欢它。
\documentclass{article}
\usepackage{tikz}
\def\drawPathThrough#1#2{
\def\firstnode{#1}
\draw \foreach \n in {#1,#2} {\ifx\n\firstnode\else -- \fi (\n.center) } --cycle;
}
\begin{document}
\begin{tikzpicture}[x=2in,y=2in]
\node (A) at (1,0) {A};
\node (B) at (0,1) {B};
\node (C) at (-1,0) {C};
\node (D) at (1,1) {D};
\drawPathThrough{A}{B,D,C};
\end{tikzpicture}
\end{document}
答案2
对于这\foreach
部分,需要稍微澄清一下。
在路径中使用时\foreach
,它不仅仅是连接字符串,还解析循环的每次旋转并连接路径(!)
因此,您所拥有的是不完整的路径片段,需要最终坐标,换句话说,您告诉 TikZ
\draw (A.center) --
\draw (A.center) -- (B.center) --
\draw (A.center) -- (B.center) -- (C.center) --
\draw (A.center) -- (B.center) -- (C.center) -- (D.center) --
\draw (A.center) -- (B.center) -- (C.center) -- (D.center) -- cycle;
这只在最后一次旋转中是正确的,但由于错误,它永远不会到达那一点。相反,如果你使用
\draw (A.center) \foreach \x in {B,D,C}{-- (\x.center)}-- cycle;
那么你有
\draw (A.center)
\draw (A.center) -- (B.center)
\draw (A.center) -- (B.center) -- (C.center)
\draw (A.center) -- (B.center) -- (C.center) -- (D.center)
\draw (A.center) -- (B.center) -- (C.center) -- (D.center) -- cycle;
并且每次旋转都是一个有效语句。好吧,万事通先生,您如何解释这一点?
\draw \foreach \x in {A,B,D,C}{-- (\x.center)}-- cycle;
没有错误,也没有路径!其实不是。这是因为缺少将\pgfpathmoveto{}
笔放在画布上的内部函数。例如,一个不错的谜语是
\pgfpathmoveto{}
\draw -- (A.center)-- (B.center)--(C.center)--(D.center);
:) 这句台词(a)
出自(d)
哪里?
答案3
这个答案提供了三种解决方案:
第一个解决方案使用您的确切语法(即没有指定锚点或指示的节点名称
.
)。不幸的是,这需要修复用于解析隐式版本的现有宏node cs
。此宏检查
.
指定坐标中的:如果找到,则用于拆分节点名称和引用的锚点。如果没有,.<anchor>
则会自动添加.center
,这仅在tikz@shapeborder
忽略 if 的情况下才会执行。这部分就是为什么当您未指定锚点时节点会如此智能地连接的原因。如果我们拦截了这个,我们就可以使你的语法成为可能。
解决方案二只是允许在本地定义一个通用锚点。
该宏
\pgfdeclaregenericanchor{<name>}{<code>}
创建一个宏\pgf@anchor@generic@<name>
,它接受一个参数,我们可以将其引用为<code>
。##1
这仅用于引用另一个锚点。如果省略该通用锚点的名称,则可以用来
(A.)
引用快捷方式。insert path
查看避免锚点问题的其他解决方案,我会定义一些通过样式和处理程序构建路径.list
以连接坐标/节点的样式:open polygon={<first coordinate>, <list of other coordinates>}
和closed polygon
使用相同的语法,但包含一个额外的-- cycle
。
使用
insert path
而不是相当固定的宏使得可以将该路径用作另一条路径的一部分(对于封闭多边形来说可能性不是那么大,但仍然如此)。
解决方案 1
修补程序构建了一个\tikz@parse@node
宏,定义为(来自原始来源的注释):
\def\tikz@parse@node#1(#2){%
\pgfutil@in@.{#2}% Ok, flag this
\ifpgfutil@in@
\tikz@calc@anchor#2\tikz@stop%
\else%
\pgfkeysgetvalue{/tikz/use anchor}\tikz@temp
\ifx\tikz@temp\pgfutil@empty
\tikz@calc@anchor#2.center\tikz@stop% to be on the save side, in
% case iftikz@shapeborder is ignored...
\expandafter\ifx\csname pgf@sh@ns@#2\endcsname\tikz@coordinate@text%
\else
\tikz@shapebordertrue%
\def\tikz@shapeborder@name{#2}%
\fi%
\else
\expandafter\tikz@calc@anchor#2\tikz@temp\tikz@stop
\fi
\fi%
\edef\tikz@marshal{\noexpand#1{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}}%
\tikz@marshal}
和\pgfkeysgetvalue
以及\ifx
它的\else
部件都是新的。
这里发生了什么?首先,我们的代码仅在没有时才使用,.
这#2
意味着,如果指定了锚点,则使用它。但如果没有.
,#2
它将检查的值是否/tikz/use anchor
为空,如果是,则应用通常的行为:.center
使用锚点并tikz@shapeborder
打开布尔值。这个布尔值以及名称\tikz@shapeborder@name
后来在许多路径运算符中用于实际查找行的开头。如果你通常说
\draw (<node1>) -- (<some other coordinate>);
该线实际上从<some other coordinate>
方向的角度锚点开始。这些路径运算符检查\iftikz@shapeborder
是否已指定节点而没有明确的锚点,并且是否包含额外的移动到。
在我们的例子中,我们禁用这种智能(只要/tikz/use anchor
不为空)并且只需添加锚点而不设置tikz@shapeborder
。
代码 1
\documentclass[tikz]{standalone}
\tikzset{use anchor/.initial=}
\usepackage{etoolbox}
\makeatletter
\patchcmd\tikz@parse@node{\else\tikz@calc@anchor}{%
\else\pgfkeysgetvalue{/tikz/use anchor}\tikz@temp
\ifx\tikz@temp\pgfutil@empty\tikz@calc@anchor}{}{}
\patchcmd\tikz@parse@node{\fi\fi}{\fi\else\tikz@calc@anchor#2.\tikz@temp\tikz@stop\fi}{}{}
\makeatother
\begin{document}
\begin{tikzpicture}[x=2in,y=2in, nodes={draw, help lines}]
\node (A) at (1,0) {A}; \node (B) at (0,1) {B};
\node (C) at (-1,0) {C}; \node (D) at (1,1) {D};
\draw[use anchor=center] (A) -- (B) -- (D) -- (C) -- cycle;
\draw[use anchor=south west, blue] (A) -- (B) -- (D) -- (C) -- cycle;
\end{tikzpicture}
\end{document}
解决方案 2
对该解决方案的初始说明无需添加太多内容。
This may be the most flexible solution as you actually can (globally) define a few short-cuts like
\tikzset{
anchor shortcut/.list={
{nw}{north west},
{n}{north},
{ne}{north east}}}
Code 2
\documentclass[tikz]{standalone}
\makeatletter
\tikzset{
use anchor/.style={anchor shortcut={}{#1}},
anchor shortcut/.code 2 args=\pgfdeclaregenericanchor{#1}{\pgf@sh@reanchor{##1}{#2}}}
\makeatother
\begin{document}
\begin{tikzpicture}[x=2in, y=2in, nodes={draw, help lines}]
\node (A) at (1,0) {A}; \node (B) at (0,1) {B};
\node (C) at (-1,0) {C}; \node (D) at (1,1) {D};
\draw[use anchor=center] (A.) -- (B.) -- (D.) -- (C.) -- cycle;
\draw[anchor shortcut={sw}{south west},blue](A.sw) -- (B.sw) -- (D.sw) -- (C.sw) -- cycle;
\end{tikzpicture}
\end{document}
Solution 3
I also can’t say much additional to this solution.
It may be noted that due to the fact how the argument to open polygon
(and thus closed polygon
) is parsed one cannot write
open polygon={A , …}
but only
open polygon={A, …}
Otherwise, spaces do no harm as all other coordinates are parsed by the \foreach
parser.
Please note that the .
has to be given in the argument of open polygon anchor
. (This can be changed with another text and an \edef
without a problem though.)
If you only draw tetragons, you could actually just define
\tikzset{
tetragon/.style args={#1:#2,#3,#4,#5}{
insert path={(#2.#1) -- (#3.#1) -- (#4.#1) -- (#5.#1) -- cycle}}
}
which you can use as
\draw[red, thick, tetragon={east:A,B,C,D}];
and be done with it.
Code 3
\documentclass[tikz]{standalone}
\makeatletter
\tikzset{
open polygon anchor/.initial=,
open polygon/.code args={#1,#2}{%
\edef\tikz@temp{\pgfkeysvalueof{/tikz/open polygon anchor}}%
\tikzset{@open polygon/.expanded={\tikz@temp}{#1}{#2}}},
@open polygon/.style n args={3}{%
insert path={(#2#1)},
@@open polygon/.style={insert path={-- (##1#1)}},
@@open polygon/.list={#3}},
closed polygon/.style={open polygon={#1},insert path={-- cycle}}}
\makeatother
\begin{document}
\begin{tikzpicture}[x=2in,y=2in, nodes={draw, help lines}]
\node (A) at (1,0) {A}; \node (B) at (0,1) {B};
\node (C) at (-1,0) {C}; \node (D) at (1,1) {D};
\draw[open polygon anchor=.center, closed polygon={A,B,D,C}] ;
\draw[open polygon anchor=.south west, closed polygon={A,B,D,C}, blue];
\end{tikzpicture}
\end{document}