我有
\node (A) at (0,2) {$A$};
\node (B) at (0,0) {$B$}
edge [<-] (A)
edge [<-, bend right=90] (A);
我该如何填充这个 D 形?显然,我必须使用\filldraw
,但我不知道如何进行弯曲。
答案1
很难给出答案,因为你没有准确解释什么是 D 形。如果你想从 A.center 和 B.center 填充,答案是不一样的。现在重要的是要了解你为什么会遇到问题。
所有的解释都在 pgfmanual 中,但我会添加一些完整的示例。
边缘操作的效果是在主路径之后在图片中添加以下路径:
\path[every edge,⟨options⟩] (\tikztostart) ⟨path⟩;
这里,⟨path⟩ 是 to 路径。请注意,与 to 操作添加的路径不同,(\tikztostart) 被添加到 ⟨path⟩ 之前(对于 to 操作来说,这是不必要的,因为这个坐标已经是主路径的一部分)。\tikztostart 是路径上紧接在边缘操作之前的最后一个坐标,就像节点或 to 操作一样。但是,这条规则有一个例外:如果边缘操作直接位于节点操作之前,那么这个刚刚声明的节点就是起始坐标(而不是像通常那样,放置这个刚刚声明的节点的坐标 - 这是一个很小但微妙的区别)。在这方面,edge 与 node 和 to 都不同。如果连续有多个边缘操作,那么它们的起始坐标对于所有操作都是相同的,因为它们的目标坐标毕竟不是主路径的一部分。因此,起始坐标是第一个边缘操作之前的坐标。这与节点类似,因为边缘操作根本不会修改当前路径。具体来说,它不会改变最后访问的坐标,请参见以下示例:
\tikzstyle{every edge}= [draw]
边操作的工作方式类似于在绘制主路径后添加的 to 操作,就像在绘制主路径后添加节点一样。这允许每条边具有不同的外观。作为节点操作,边会暂时中止当前路径的构建,并构建一条新路径 p。这条新路径 p 将在绘制主路径后绘制。请注意,p 的选项可能与主路径完全不同。还请注意,如果主路径中有多个 to 和/或节点操作,则每个操作都会创建自己的路径,并按照在路径上遇到的顺序绘制它们。
\path ... edge[⟨options⟩] ⟨nodes⟩ (⟨coordinate⟩) ...;
您的代码
\node (A) at (0,2) {$A$};
\node (B) at (0,0) {$B$}
edge [<-] (A)
edge [<-, bend right=90] (A);
首先,我认为将节点的创建、边的创建和区域的填充混合在一起并不是一个好主意。我建议
\begin{tikzpicture}
\node (A) at (0,2) {$A$};
\node (B) at (0,0) {$B$};
\path[<-] (B) edge (A)
edge [bend right=90] (A);
\end{tikzpicture}
但更自然的是
\begin{tikzpicture}
\node (A) at (0,2) {$A$};
\node (B) at (0,0) {$B$};
\path[->] (A) edge (B)
edge [bend left=90] (B);
\end{tikzpicture}
但我们可以注意到尽管使用了\path
曲线,但每条曲线都有一个箭头。
边缘操作的效果是在主路径之后在图片中添加以下路径:
\path[every edge,⟨options⟩] (\tikztostart) ⟨path⟩;
和
\tikzstyle{every edge}= [draw]
边缘操作会创建新路径。这就是绘制曲线的原因。绘制选项是继承的,如 ->、thick 等。使用 \tikzstyle{every edge}= [draw,fill=red]`,您可以填充边缘操作定义的所有区域。
一个示例来了解边缘如何工作
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{backgrounds}
\begin{document}
\tikzstyle{every edge}= [draw=red]
\begin{tikzpicture}[out=90,in=90,relative]
\node [circle,draw] (a) at (0,0) {a};
\node [circle,draw] (b) at (1,1) {b};
\node [circle,draw] (c) at (2,2) {c};
\draw[->] (a) -- (b)
(a) edge (b)
edge (c)
(b) -- (c);
\end{tikzpicture}
\end{document}
另一处充满
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{backgrounds}
\begin{document}
\tikzstyle{every edge}= [draw=red,fill=blue!20,opacity=.5]
\begin{tikzpicture}[out=90,in=90,relative]
\node [circle,draw] (a) at (0,0) {a};
\node [circle,draw] (b) at (1,1) {b};
\node [circle,draw] (c) at (2,2) {c};
\draw[->] (a) -- (b)
(a) edge (b)
edge (c)
(b) -- (c);
\end{tikzpicture}
\end{document}
现在我将填充命令放在路径的开头。此命令仅用于主路径,但在您的情况下,主路径不是您想要的。我认为它是一个单点。您需要在边缘操作中添加一个选项,或者every edge
如果您想填充使用边缘获得的额外路径,则需要进行修改。
现在有三个例子:第一个看看主路径的选项如何工作,第二个看看它是否可以用to
,第三个填充整个图片。
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{backgrounds}
\begin{document}
\begin{tikzpicture}
\node (A) at (0,2) {$A$};
\node (B) at (0,0) {$B$};
\draw[->,ultra thick] (A) edge (B)
edge[ bend left=90,fill=red] (B);
\end{tikzpicture}
\begin{tikzpicture}
\node (C) at (0,2) {$A$};
\node (D) at (0,0) {$B$};
\draw[->] (C) to (D);
\draw[->,fill=red] (C) to [ bend left=90] (D);
\end{tikzpicture}
\begin{tikzpicture}
\node (C) at (0,2) {$A$};
\node (D) at (0,0) {$B$};
\draw[->] (C) to (D);
\draw[->] (C) to [ bend left=90] (D);
\begin{scope}[on background layer]
\path [fill=red!30] (A) to [ bend left=90] (B) -- (B.center)--(A.center)--(A.east);
\end{scope}
\end{tikzpicture}
\end{document}
答案2
您所要求的内容实际上相当复杂。以下是使其变得复杂的原因:
- 每个
edge
命令都定义一条全新的路径。因此,您要填充的区域不仅由物理上不相交的路径描述,还由编程上不相交的路径描述。 - 箭头只放在路径的末端,所以你确实希望这些路径在画。
- 您想要填充的区域没有精确定义。
- 填充路径时,将路径的每一段都通过直线连接起点和终点来独立填充。
- 至少有一条路径是这样的,用户不知道它到底在哪里。(在给定的代码中,可以看到弯曲的箭头最终到达了哪个锚点,但这可能并不总是正确的。)
所以你要做的是:指定一些路径,然后在两个不同的且不兼容方法。解决这个问题的一个复杂方法是存储这两条路径,然后通过“焊接”它们来生成一条新路径。然后,原来的两条路径可以用于箭头,焊接的路径用于填充。这样做完全可行(使用我的spath
库),但是对于这种情况来说,这有点太复杂了(而且spath
代码显然不稳定)。如果您准备再次指定这两条路径,那么有一个快速的破解方法可以得到您想要的。
指定路径时填充,我们使用to
s 而不是edge
s。就创建的路径而言,它们是相同的(由于to
更新当前位置但edge
不更新,因此路径的指定方式有所不同)。不同之处在于生成的对象是单个路径,而不是多个路径。然后我们要做的是插入一个低级黑客,它会更改所有内部的movetos 到 linetos。这将创建一个封闭的填充路径。然后我们必须使用绘图命令重新指定它。
这样做的一个缺点是节点被绘制前路径已填充(好吧,在示例中,A
节点始终在路径填充之前绘制,但现在B
也是如此),这意味着填充区域可能与节点文本重叠。在这种情况下,情况并非如此,但如果确实如此,则可以使用图层将填充区域放在节点下方(参见TikZ 中的“Z 级别”有一些偷偷摸摸的方法可以做到这一点)。
代码如下:
\documentclass{article}
%\url{https://tex.stackexchange.com/q/55739/86}
\usepackage{tikz}
\makeatletter
\let\orig@pgfsyssoftpath@movetotoken=\pgfsyssoftpath@movetotoken
\def\new@pgfsyssoftpath@movetotoken{%
\let\pgfsyssoftpath@movetotoken=\pgfsyssoftpath@linetotoken
\orig@pgfsyssoftpath@movetotoken}
\tikzset{
join with lines/.code={
\let\pgfsyssoftpath@movetotoken=\new@pgfsyssoftpath@movetotoken
}
}
\makeatother
\begin{document}
\begin{tikzpicture}
\node (A) at (0,2) {$A$};
\node (B) at (0,0) {$B$};
\fill[red,join with lines] (A) to (B) to[<-,bend right=90] (A);
\draw[black] (B) edge[<-] (A) edge[<-,bend right=90] (A);
\end{tikzpicture}
\end{document}
结果:
答案3
只需使用fill
\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\node (A) at (0,2) {$A$};
\node (B) at (0,0) {$B$}
edge [<-] (A)
edge [<-, bend right=90,fill=red] (A);
\end{tikzpicture}
\end{document}
编辑一个小的修改(来自 Altermundus 答案的想法)
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{backgrounds}
\begin{document}
\begin{tikzpicture}
\node[fill=white,inner sep=.5pt] (A) at (0,2) {$A$};
\node [fill=white,inner sep=.5pt] (B) at (0,0) {$B$};
\draw[->] (A) to (B);
\draw[->] (A) to [ bend left=90] (B);
\begin{scope}[on background layer]
\path [fill=red!30] (A) to [ bend left=90] (B) -- (B.center)--(A.center)--(A.east);
\end{scope}
\end{tikzpicture}
\end{document}