解决方案 1

解决方案 1

在以下 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风格的方法来有效地连接节点,就像它们是coordinates 一样。

进一步更新

我尝试过与 @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}

Result

答案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

这个答案提供了三种解决方案:

  1. 第一个解决方案使用您的确切语法(即没有指定锚点或指示的节点名称.)。不幸的是,这需要修复用于解析隐式版本的现有宏node cs

    此宏检查.指定坐标中的:如果找到,则用于拆分节点名称和引用的锚点。如果没有,.<anchor>则会自动添加.center,这仅在tikz@shapeborder忽略 if 的情况下才会执行。这部分就是为什么当您未指定锚点时节点会如此智能地连接的原因。

    如果我们拦截了这个,我们就可以使你的语法成为可能。

  2. 解决方案二只是允许在本地定义一个通用锚点。

    该宏\pgfdeclaregenericanchor{<name>}{<code>}创建一个宏\pgf@anchor@generic@<name>,它接受一个参数,我们可以将其引用为<code>##1这仅用于引用另一个锚点。

    如果省略该通用锚点的名称,则可以用来(A.)引用快捷方式。

  3. 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}

Outputs

enter image description here

相关内容