感谢@TorbjørnT,我知道不建议弄乱节点和节点矩阵,因为您将无法再使用(m-1-1)
矩阵单元的坐标m
。(参见tikz 图表的编译问题)
现在我的问题是:我定义一个像这样的节点形状
\newcommand{\bSum}[4]{
\node [draw=\linecolor, circle,minimum size=1.5em, \linetype, fill=\backgroundcolor, drop shadow={opacity=\dark}] (sum) at (0,0) {};
\node [draw, cross out, minimum size=1.0em, thin, draw=gray!50] {};
\node [above of= sum, node distance = 0.45em] () { \color{\colortext}\tiny{$#1$}};
\node [left of= sum, node distance = 0.45em] () { \color{\colortext}\tiny{$#2$}};
\node [below of= sum, node distance = 0.45em] () { \color{\colortext}\tiny{$#3$}};
\node [right of= sum, node distance = 0.45em] () { \color{\colortext}\tiny{$#4$}};
}
\draw
由于它的参数,我无法仅使用命令来设计这样的形状。
如果我尝试使用这个(现在可编译的)代码,如果我取消注释它将\draw ...
不起作用:
\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{matrix}
\usepgflibrary{shapes.misc}
\usetikzlibrary{arrows,shadows}
\newcommand{\bSum}[4]{
\node [draw, circle,minimum size=1.5em, fill=white, thick, drop shadow={opacity=1}] (sum) at (0,0) {};
\node [draw, cross out, minimum size=1.0em, thin, draw=gray!50] {};
\node [above of= sum, node distance = 0.45em] () {\tiny{$#1$}};
\node [left of= sum, node distance = 0.45em] () {\tiny{$#2$}};
\node [below of= sum, node distance = 0.45em] () {\tiny{$#3$}};
\node [right of= sum, node distance = 0.45em] () {\tiny{$#4$}};
}
\begin{document}
\begin{tikzpicture}
\matrix (m) [matrix of nodes, ampersand replacement=\&, column sep = 1.5cm, row sep = 1.2cm]{
\bSum{+}{+}{-}{}\\
};
%\draw (m-1-1) -- (0,0); % <- where it fails
\end{tikzpicture}
\end{document}
是否存在一个技巧可以让我获得相同的结果,并且能够访问(m-1-1)
?
答案1
我宁愿写另一个答案而不是编辑我之前的答案,因为这个答案解决了一些新问题并提供了不同的解决方案。
笔记matrix of nodes
:这是一个非常长的答案,其中包含有关、等内部运作的详细信息pic
。如果您只对最终解决方案感兴趣,请跳至“最终解决方案”部分。
理想(但几乎不可能)的方式:
我喜欢这种pic
方法。但是,正如我在另一个回答中所述,一旦你将\draw
命令放入单元格中matrix of nodes
,就会破坏自动命名系统。
要理解原因(以及可能的解决方案),我们必须首先了解 tikz 在 中的作用matrix of nodes
。基本上,如果你在单元格中放入文本:
\matrix (m) [matrix of nodes, ... other options... ] {
|whatever| foo \& ... \\
...
};
Tikz 为该单元格生成命令:
\node (m-1-1) whatever {foo};
即它会自动放置一个\node
突击队员,为节点分配一个自动名称,传递您在垂直条内写的任何选项,最后将单元格的内容传递给节点的参数(内容)。
但是,如果单元格的内容是\path
、\draw
、\fill
或\node
,则上述操作均不会执行,而是该单元格的内容是您指定的任何绘图命令。因此,如果您有:
\matrix (m) [matrix of nodes, ... other options... ] {
\draw pic {bSum}; \& ... \\
...
};
那么该单元格仅包含\draw pic {bSum};
,因此没有分配自动节点名称。
这解释了为什么它不起作用。但它也为如何让它发挥作用提供了一些启示。
pic
我们知道,元素可以是\draw
或命令的一部分,但我发现,如果使用它们,它们也可以是命令的一部分\path
\node
后节点内容。即:以下不起作用(一般来说,对于任何pic
形状):
\node pic {bSum} {node contents};
但以下确实有效:
\node {node contents} pic {bSum};
并将节点内容和图片放在同一坐标处。
所以这应该工作,即使这是一个可怕的黑客行为:
\matrix (m) [matrix of nodes, ... other options... ] {
|{} pic{bSum};| IGNORED TEXT \& ... \\
...
};
因为该单元格将扩展为:
\node {} pic{bSum}; {IGNORED TEXT};
请注意,IGNORED TEXT
不是任何 tikz 命令的一部分,因此它将被 tikz 忽略(事实上,它将使用空字体进行排版)。
以下代码是一个概念证明(请注意,pic
与我的其他答案相比,我简化了代码,但这与我们在此研究的特征无关):
\documentclass{article}
\usepackage{tikz}
\begin{document}
\usetikzlibrary{calc,shadows,matrix}
\usepgflibrary{shapes.misc}
\tikzset{
myShape/.style = {
circle, minimum size=1.5em, fill, drop shadow={opacity=1},
draw, thick
},
myCross/.style = {
draw, cross out, minimum size=1.0em, thin, draw=gray!50,
},
bSum/.pic = {
\node [myShape] at (0,0) {};
\node [myCross] at (0,0) {};
\foreach \t [count=\i] in {#1}{
\pgfmathsetmacro{\angle}{\i*90}
\node[anchor=center] at (\angle:0.45em) {\tiny$\t$};
}
},
}
\begin{tikzpicture}
\matrix (m) [matrix of nodes, ampersand replacement=\&,
column sep = 1.5cm, row sep = 1.2cm]{
|{} pic[fill=yellow!20] {bSum={+,+, ,-}};| IGNORED TEXT \\
A \\
};
\draw (m-1-1) -- (m-2-1); % <-- IT WORKS!! :D
\end{tikzpicture}
\end{document}
虽然这个语法是有效的,但是这是一个糟糕的黑客行为,而且结果是:
您可以看到,该线的终点既不是圆的边缘,也不是圆的中心,而是稍微“靠内”一点。这是因为(m-1-1)
我们将空节点的名称放在矩阵的该位置,该矩阵具有默认的最小大小。
一个可能的解决方案是为这个空节点指定附加选项,以便它具有与相同半径的圆形pic
:
\begin{tikzpicture}
\matrix (m) [matrix of nodes, ampersand replacement=\&,
column sep = 1.5cm, row sep = 1.2cm]{
|[circle, minimum size=1.5em] {} pic[fill=yellow!20] {bSum={+,+, ,-}};| IGNORED TEXT \\
A \\
};
\draw (m-1-1) -- (m-2-1);
\end{tikzpicture}
它可以工作,但是语法越来越丑陋......
不同的方法
另一种方法是为 指定一个名称pic
,然后使用该名称来引用该节点,而不是标准的(m-1-1)
。 思路如下:
\matrix (m) [matrix of nodes, ... other options... ] {
\draw pic[options] (myName) {bSum} \& ... \\
...
};
如果你以这种方式给 命名pic
,那么这个名称并不指向任何特定的节点,而是一个名称前缀对于在 内定义的任何节点名称pic
。因此,我们可以为构成形状的圆形节点命名,例如,这样,我们就可以从此 tikzpicture 的任何其他部分-edge
引用。(myName-edge)
这看起来是个好主意。然而,在这种特殊情况下,由于使用了 ,出现了更多问题drop shadow
。显然,此选项使用名为 的节点(current bounding box)
进行计算。但由于它出现在pic
命名空间为的 中,tikz 会感到困惑,并尝试使用不存在的myName
名为 的节点。(myNamecurrent bounding box)
为了避免这个问题,我们必须在绘制阴影时通过name prefix ..
选项“重置”命名空间。因此,我们必须分两个阶段绘制形状bSum
:一个阶段不使用命名空间前缀来绘制阴影,另一个阶段使用命名空间前缀来绘制圆形轮廓并为其赋予一个外部可用的名称。所以...
最终的解决方案
\documentclass{article}
\usepackage{tikz}
\begin{document}
\usetikzlibrary{calc,shadows,matrix}
\usepgflibrary{shapes.misc}
\tikzset{
myShape background/.style = { % For the first phase
circle, minimum size=1.5em, fill, drop shadow={opacity=1},
name prefix ..
},
myShape edge/.style = { % For the second phase
draw, circle, minimum size=1.5em, thick,
},
myCross/.style = {
draw, cross out, minimum size=1.0em, thin, draw=gray!50,
},
bSum/.pic = {
\node [myShape background] at (0,0) {}; % First phase
\node [myCross] at (0,0) {};
\foreach \t [count=\i] in {#1}{
\pgfmathsetmacro{\angle}{\i*90}
\node[anchor=center] at (\angle:0.45em) {\tiny$\t$};
}
\node [myShape edge] (-edge) at (0,0) {}; % Second phase, give it a name
},
}
\begin{tikzpicture}
\matrix (m) [matrix of nodes, ampersand replacement=\&,
column sep = 1.5cm, row sep = 1.2cm]{
\draw pic[fill=white] (S) {bSum={+,+, ,-}}; \\
A \\
};
\draw[latex-] (S-edge) -- (m-2-1);
\end{tikzpicture}
\end{document}
注意(S)
我们传递给 的选项pic
。这会导致S
成为命名空间前缀,因此(-edge)
pic 内部的命名节点可以在名称 下从外部访问(S-edge)
。此代码产生所需的结果:
当然,没有什么可以阻止你给出(m-1-1)
作为命名空间前缀而不是(S)
。但是,请记住,这并不定义名为的节点(m-1-1)
,而是命名空间前缀。你仍然必须使用(m-1-1-edge)
来引用实际的 pic 形状。
更新:最终破解
我意识到,如果你(m)
为元素指定命名空间,并在其中为最后一个圆形节点pic
指定名称,那么你就可以从 tikzpicture 中的任何位置访问 来引用该单元格中的圆形节点。事实上,你可以在 中使用计数器和作为 中的节点名称的一部分,从而最终实现预期目标。(-1-1)
(m-1-1)
\pgfmatrixcurrentrow
\pgfmatrixcurrentcolumn
pic
下面的代码展示了一个完整的示例:
\documentclass{article}
\usepackage{tikz}
\begin{document}
\thispagestyle{empty}
\usetikzlibrary{calc,shadows,matrix}
\usepgflibrary{shapes.misc}
\tikzset{
myShape background/.style = { % For the first phase
circle, minimum size=1.5em, fill, drop shadow={opacity=1},
name prefix ..
},
myShape edge/.style = { % For the second phase
draw, circle, minimum size=1.5em, thick,
},
myCross/.style = {
draw, cross out, minimum size=1.0em, thin, draw=gray!50,
},
bSum/.pic = {
\node [myShape background] at (0,0) {}; % First phase
\node [myCross] at (0,0) {};
\foreach \t [count=\i] in {#1}{
\pgfmathsetmacro{\angle}{\i*90}
\node[anchor=center] at (\angle:0.45em) {\tiny$\t$};
}
\node [myShape edge] % Second phase, give it a name
(-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn)
at (0,0) {};
},
}
\begin{tikzpicture}
\matrix (m) [matrix of nodes, ampersand replacement=\&,
column sep = 1.5cm, row sep = 1.2cm, nodes={anchor=center}]{
\draw pic[fill=white] (m) {bSum={+,+,-,}}; \& B \\
A \& \draw pic[fill=green!10] (m) {bSum={,\odot,\smile,\prec}}; \\
};
\draw[-latex] (m-2-1) -- (m-2-2); % <-- It works!
\draw[-latex] (m-1-1) -- (m-2-2); % <-- It works!
\end{tikzpicture}
\end{document}
结果:
答案2
请参阅更新以了解使用的解决方案pic
原始答案
显然,代码的行为会根据所使用的 PGF 版本而有所不同。
使用 PGF 2.10,以下代码(基本上是 OP 的代码,矩阵中有第二行,以使后来绘制的线更加清晰可见)可以毫无问题地进行编译:
\documentclass{article}
\usepackage{tikz}
\begin{document}
\thispagestyle{empty}
\usetikzlibrary{matrix}
\usepgflibrary{shapes.misc}
\usetikzlibrary{arrows,shadows}
\newcommand{\bSum}[4]{
\node [draw, circle,minimum size=1.5em, thick, fill = white, drop shadow={opacity=1}] (sum) at (0,0) {};
\node [draw, cross out, minimum size=1.0em, thin, draw=gray!50] (sum) {};
\node [above of= sum, node distance = 0.45em] () {\tiny{$#1$}};
\node [left of= sum, node distance = 0.45em] () {\tiny{$#2$}};
\node [below of= sum, node distance = 0.45em] () {\tiny{$#3$}};
\node [right of= sum, node distance = 0.45em] () {\tiny{$#4$}};
\node [draw, circle,minimum size=1.5em, thick] at (0,0) {};
}
\begin{tikzpicture}
\matrix (m) [matrix of nodes, ampersand replacement=\&, column sep = 1.5cm, row sep = 1.2cm]{
\bSum{+}{+}{-}{}\\
A \\
};
\draw (m-1-1) -- (m-2-1); % <- where it fails
\end{tikzpicture}
\end{document}
并产生:
但是,使用 PGF 3.0.0 的相同代码会产生错误:
! Package pgf Error: No shape named m-1-1 is known.
可以通过创建\bSum
宏来创建新的 tikz 图片来解决此问题,即:
\newcommand{\bSum}[4]{
\tikz{
\node [draw, circle,minimum size=1.5em, thick, fill = white, drop shadow={opacity=1}] (sum) at (0,0) {};
\node [draw, cross out, minimum size=1.0em, thin, draw=gray!50] (sum) {};
\node [above of= sum, node distance = 0.45em] () {\tiny{$#1$}};
\node [left of= sum, node distance = 0.45em] () {\tiny{$#2$}};
\node [below of= sum, node distance = 0.45em] () {\tiny{$#3$}};
\node [right of= sum, node distance = 0.45em] () {\tiny{$#4$}};
\node [draw, circle,minimum size=1.5em, thick] at (0,0) {};
}
}
但结果略有不同:
奇怪的是,这个“修复”不适用于 PGF 2.10。
更新:使用 PGF 3.0.0 图片
PGF 3.0.0 引入了一项新功能,pic
允许您定义可放置在路径上任何位置的任意形状。
1. 定义图片
使用此功能(并定义一些样式来简化代码),您可以获得:
\tikzset{
myShape/.style = {
draw, circle, minimum size=1.5em, thick,
fill, drop shadow={opacity=1}
},
myCross/.style = {
draw, cross out, minimum size=1.0em, thin, draw=gray!50,
},
myLabel1/.style = {
above of=sum, node distance=0.45em,
},
myLabel2/.style = {
left of=sum, node distance=0.45em,
},
myLabel3/.style = {
below of=sum, node distance=0.45em,
},
myLabel4/.style = {
right of=sum, node distance=0.45em,
},
pics/bSum/.style = {
code = {
\node [myShape] (sum) at (0,0) {};
\node [myCross] at (sum) {};
\foreach \t [count=\i] in {#1}
\node[myLabel\i] {\tiny$\t$};
}
},
}
有趣的部分是 which 的定义pics/bSum/.style
有一个名为 which 的键code
,用于绘制形状。请注意,#1
在代码中使用,期望每个象限都有一个以逗号分隔的标签列表。您可以将其用作任何的一部分\draw
,如下所示:
\begin{tikzpicture}
\draw[fill=white] (0,0) pic {bSum={+,+,-, }};
\end{tikzpicture}
要得到:
请注意,您必须在 中指定填充颜色\draw
,因为我没有在 样式 中指定它myShape
。我更喜欢这样做,这样您就可以灵活地使用不同的背景颜色绘制相同的图片(如果需要)。
2. 在节点矩阵中使用它。
不幸的是,如果您尝试直接使用它来代替节点矩阵内的节点,如下所示:
\matrix (m) [matrix of nodes, ampersand replacement=\&,
column sep = 1.5cm, row sep = 1.2cm]{
\draw[fill=white] pic {bSum={+,+,-, };
};
您将遇到与第一种方法相同的问题。使用绘图命令代替节点矩阵中的节点会干扰节点自动命名机制,然后您将无法访问(m-1-1)
节点名称。
黑客式的解决方法
我能想到的唯一解决方案是不绘制这些形状来代替节点。相反,将这些节点保留为一些“虚拟”占位符。然后,在矩阵完成后,您可以转到(m-1-1)
那里绘制所需的形状。
以下代码展示了这种方法。在此代码中,我使用了一些数字作为占位符,因为图片具有不透明背景,会隐藏它们。您可以改用空格( )。我还展示了如何以不同的背景颜色和不同的符号(作为参数传递)显示\
相同的内容。pic
\begin{tikzpicture}
\matrix (m) [matrix of nodes, ampersand replacement=\&,
column sep = 1.5cm, row sep = 1.2cm]{
1 \& 2 \& 3 \\
4 \& 5 \& 6 \\
};
\draw (m-1-1) -- (m-2-1);
\draw (m-2-2) -- (m-1-3);
\draw[fill=yellow] (m-1-1) pic{bSum={+,+,-, }};
\draw[fill=white] (m-2-2) pic{bSum={+, ,-,+}};
\end{tikzpicture}
得出的结果为:
答案3
这是基于pic
@JLDiaz 的代码的另一个建议。
首先请注意,节点内容设置在矩形框中,即使它本身是一个圆形。因此我使用选项来隐藏矩阵节点中overlay
的尺寸。pic
\documentclass[tikz,margin=5mm,convert=false]{standalone}
\usepackage{tikz}
\begin{document}
\usetikzlibrary{matrix}
\usepgflibrary{shapes.misc}
\usetikzlibrary{arrows,shadows}
\tikzset{
myShape/.style = {
circle, minimum size=1.5em, thick,
},
mybSum/.style = {
myShape,
draw,fill, drop shadow={opacity=1},
},
myCross/.style = {
draw, cross out, minimum size=1.0em, thin, draw=gray!50,
},
myLabel1/.style = {above of=#1}, myLabel2/.style = {left of=#1},
myLabel3/.style = {below of=#1}, myLabel4/.style = {right of=#1},
myLabelDist/.style = {node distance=0.45em},
pics/bSum/.style = {
code = {
\node [mybSum](sum){};
\node [myCross]{};
\foreach \t [count=\i] in {#1}
\node[myLabelDist, myLabel\i=sum] {\tiny$\t$};
\node [myShape,draw]{};
}
},
}
\newcommand\bSum[2]{|[myShape]|\tikz\pic[overlay,fill=white,#1]{bSum={#2}};}
\begin{tikzpicture}
\matrix (m) [matrix of nodes, ampersand replacement=\&, column sep = 1.5cm, row sep = 1.2cm]{
\bSum{}{+,+,-,}\&\bSum{fill=yellow,draw=red,text=green}{-,,,+}\\
A \& B\\
};
\path[<->] (m-2-1) edge (m-1-1)
edge (m-1-2);
\end{tikzpicture}
\end{document}
该命令\bSum
有两个强制参数:#1 影响布局pic
并且可以为空,#2 包含每个象限的逗号分隔的标签列表。