前两行正是我想要的:
\node (F) at (1,1) {$F$};
\draw (0,2) to [out=-90] (F);
也就是说,它从点向下绘制一条边(0,0)
,并将其弯曲以击中(F)
,以大约 135 度进入节点。我不必指定in=135
。
但是下一行使用相同的~135 度值in
,而我希望它的值在 45 度左右并且不指定它!
\draw (2,2) to [out=-90] (F);
我如何告诉再次tikz
计算该in
值而不是使用前一个值?
这是一个最小工作示例,现在已进行了修改,因为很明显我是“马戏团的受害者”:
\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\node [circle, draw=black] (F) at (1,1) {$F$};
\draw (0,2) to [out=-90] (F);
\draw (0.7,2) to [out=-90, in=110] (F);
\draw (2,2) to [out=-90, in=45] (F);
\draw (F) to [out=-135, in=90] (0,0);
\draw (F) to [out=-45, in=90] (2,0);
\end{tikzpicture}
\end{document}
答案1
你是马戏团的受害者。
“不必指定in=135
”这一事实纯属巧合。而第二种情况下 TikZ “使用前一个”的结论是错误的。观察到的行为完全归因于文件中的两行小代码tikzlibrarytopaths.code.tex
:
\def\tikz@to@out{45}
\def\tikz@to@in{135}
这意味着,如果您不指定,out
则会自动设置为45
,同样,如果您不指定,in
则会自动设置为135
。(这些仅在以下情况下有效:某物选择curve
的变体to path
,而不是默认的变体。指定一或in
就out
足够了。
有一个relative
选项可以设置相对于起始和结束坐标之间的线的角度。因此,如果您使用relative,in=180
(因为线的方向从来源到目标),然后为in
线选择了正确的角度。然而,这使得out
角度还相对的,这似乎不是你想要的。
这是我编写的一段代码,如果您没有自行设置,它会自动设置in
和。必须提供密钥out
auto ends
前任何覆盖out
或in
因为它无法区分用户所说的out=45
和默认值。然而,这似乎并不是什么困难。
它的作用是在调用时将in
和设置out
为空。然后在处理路径时,将任何仍为空的设置为起始和终止坐标之间的角度。
\documentclass{article}
%\url{http://tex.stackexchange.com/q/39903/86}
\usepackage{tikz}
\makeatletter
\tikzset{
auto ends/.code={%
\def\tikz@to@switch@on{\let\tikz@to@path=\tikz@to@curve@path@rel}%
\tikz@to@switch@on
\let\tikz@to@in=\pgfutil@empty
\let\tikz@to@out=\pgfutil@empty
}
}
\def\tikz@to@curve@path@rel{%
[every curve to]
\pgfextra{%
\ifx\tikz@to@out\pgfutil@empty
\let\relin@toto=\tikztotarget
\ifx\tikz@to@in\pgfutil@empty
\else
\tikz@to@modify\relin@toto\tikz@to@in
\fi
\tikz@scan@one@point\pgfutil@firstofone(\relin@toto)\relax
\pgf@xa=\pgf@x
\pgf@ya=\pgf@y
\tikz@scan@one@point\pgfutil@firstofone(\tikztostart)\relax
\advance\pgf@xa by -\pgf@x
\advance\pgf@ya by -\pgf@y
\pgfmathtruncatemacro\tikz@to@out{int(atan2(\pgf@xa,\pgf@ya))}%
\fi
\ifx\tikz@to@in\pgfutil@empty
\let\relin@tofrom=\tikztostart
\ifx\tikz@to@out\pgfutil@empty
\else
\tikz@to@modify\relin@tofrom\tikz@to@out
\fi
\tikz@scan@one@point\pgfutil@firstofone(\relin@tofrom)\relax
\pgf@xa=\pgf@x
\pgf@ya=\pgf@y
\tikz@scan@one@point\pgfutil@firstofone(\tikztotarget)\relax
\advance\pgf@xa by -\pgf@x
\advance\pgf@ya by -\pgf@y
\pgfmathtruncatemacro\tikz@to@in{int(atan2(\pgf@xa,\pgf@ya))}%
\fi
\iftikz@to@relative
\tikz@to@compute@relative
\else
\tikz@to@compute
\fi
}
\tikz@computed@path \tikztonodes
}
\makeatother
\begin{document}
\begin{tikzpicture}
\node [circle, draw=black] (F) at (1,1) {$F$};
\draw (0,2) to [auto ends,out=-90] (F);
\draw (2,2) to [auto ends,out=-90] (F);
\draw (2,-2) to [auto ends,out=90] (F);
\draw (-2,-2) to [auto ends] (F);
\end{tikzpicture}
\end{document}
结果如下:
Marc van Dongen 和我对该请求的解释略有不同。以下是上述代码的改编版,允许使用以下形式的语法:
\draw[every to/.style={auto ends}] (0,2) to [out=-90] (F) to[intermediate,in=-90] (2,2);
需要代码的原因是如果有人写了类似这样的代码:
\draw (0,0) to[out=90,in=45] (F) to[out=90,in=45] (0,2);
那么结果与写作不同
\draw (0,0) to[out=90,in=45] (F) (F) to[out=90,in=45] (0,2);
证人:
重点在于to path
构建了一条新的路径,该路径附加到当前路径。因此,在上面的构造结果类似于.. controls (some point) and (some other point) .. (the target)
。现在(the target)
可能已经从路径上最初指定的内容进行了修改。但附加部分中未提及来源(这对于连接路径段很有意义)。因此,两个连续to
路径的结果类似于:
.. controls (1st cntrl) and (2nd cntrl) .. (1st modified target) .. controls (3rd cntrl) and (4th cntrl) .. (2nd modified target);
尤其是来源第二个to path
是不是原始\draw
命令中指定的内容但是第一个命令to path
所说的内容。 大多数时候这正是我们想要的。然而,要按照原帖者的路径一气呵成,这不是我们想要的。我们想要的是第二种行为,其结果将是:
.. controls (1st cntrl) and (2nd cntrl) .. (1st modified target) (1st original target) .. controls (3rd cntrl) and (4th cntrl) .. (2nd modified target);
为了自动实现这一点,我们需要将原始目标重新插入到流中。但是,我们无法在第一个路径的末尾自动执行此操作,因为我们不知道在路径中是否有第二个路径。我们在第一个路径的末尾所能做的就是保存原始目标,以防再次需要它。然后在第二个路径的开头,我们可以重用它(如果我们愿意的话)以在正确的位置重新启动路径。
以下是修改后的代码,并附有示例。如所写,它与密钥绑定auto ends
,但可以很容易地提取到一组单独的密钥中。困难在于标准to path
s 需要修补才能插入正确的移动。
\documentclass{standalone}
%\url{http://tex.stackexchange.com/q/39903/86}
\usepackage{tikz}
\makeatletter
\tikzset{
auto ends/.code={%
\def\tikz@to@switch@on{\let\tikz@to@path=\tikz@to@curve@path@rel}%
\tikz@to@switch@on
\let\tikz@to@in=\pgfutil@empty
\let\tikz@to@out=\pgfutil@empty
\let\relin@start=\pgfutil@empty
},
intermediate/.code={
\let\relin@start=\relin@target
},
}
\newif\ifrelin@restartnext
\newif\ifrelin@restart
\def\tikz@to@curve@path@rel{%
[every curve to]
\pgfextra{%
\global\let\relin@target=\tikztotarget
\ifx\relin@start\pgfutil@empty
\else
\let\tikztostart=\relin@start
\fi
\ifx\tikz@to@out\pgfutil@empty
\let\relin@toto=\tikztotarget
\ifx\tikz@to@in\pgfutil@empty
\else
\tikz@to@modify\relin@toto\tikz@to@in
\fi
\tikz@scan@one@point\pgfutil@firstofone(\relin@toto)\relax
\pgf@xa=\pgf@x
\pgf@ya=\pgf@y
\tikz@scan@one@point\pgfutil@firstofone(\tikztostart)\relax
\advance\pgf@xa by -\pgf@x
\advance\pgf@ya by -\pgf@y
\pgfmathtruncatemacro\tikz@to@out{int(atan2(\pgf@xa,\pgf@ya))}%
\fi
\ifx\tikz@to@in\pgfutil@empty
\let\relin@tofrom=\tikztostart
\ifx\tikz@to@out\pgfutil@empty
\else
\tikz@to@modify\relin@tofrom\tikz@to@out
\fi
\tikz@scan@one@point\pgfutil@firstofone(\relin@tofrom)\relax
\pgf@xa=\pgf@x
\pgf@ya=\pgf@y
\tikz@scan@one@point\pgfutil@firstofone(\tikztotarget)\relax
\advance\pgf@xa by -\pgf@x
\advance\pgf@ya by -\pgf@y
\pgfmathtruncatemacro\tikz@to@in{int(atan2(\pgf@xa,\pgf@ya))}%
\fi
\iftikz@to@relative
\tikz@to@compute@relative
\else
\tikz@to@compute
\fi
\ifx\relin@start\pgfutil@empty
\else
\let\relin@computed@path=\tikz@computed@path
\edef\tikz@computed@path{(\relin@start)\tikz@computed@path}
\fi
}
\tikz@computed@path \tikztonodes
}
\makeatother
\begin{document}
\begin{tikzpicture}
\node [circle, draw=black] (F) at (1,1) {$F$};
\draw[every to/.style={auto ends}] (0,2) to[out=-90] (F) to[intermediate,in=-90] (2,2);
\end{tikzpicture}
\end{document}
结果:
答案2
您有一个简单的解决方案:
\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\node [circle, draw=black] (F) at (1,1) {$F$};
\draw (0,2) to [out=-90] (F);
\draw (F) to [in=-90] (2,2) ;
\end{tikzpicture}
\end{document}