我正在考虑开始使用 TIKZ,并试图弄清楚它是否能满足我的要求以及如何实现。
我有一份包含许多贝塞尔曲线图片的大型文档。对于每张图,我想绘制曲线本身、其控制点处的四个点以及连接这四个点的三条线。我目前正在使用 Powerpoint 宏绘制这些图。它们看起来像这样:
我想将这个东西“封装”在一个函数或宏中,以便于实例化,并确保不同图片之间的一致性。我设想函数的输入将是四个点的坐标和三种颜色(一个用于曲线,一个用于点,一个用于线)。
我读过关于“tikzstyle”功能的文章。听起来不错,因为我可以将“style”定义放在外部,并在我的所有图片中重复使用它,这为我提供了一致性和轻松的全局更改。但我不确定“输入参数”(坐标)如何工作。
tikzstyle 是正确的方法吗,或者有没有更好的方法(使用 TIKZ 或其他类似工具)?
答案1
这是一个可能的解决方案。这里,一个宏定义mybezier
在tikzpicture
如下所示的环境中,该宏带有 4 个参数:P_0、P_a、P_b、P_1。然后调用\mybezier{p0}{pa}{pb}{p1}
以绘制。
\newcommand\mybezier[4]{
\begin{tikzpicture}
\draw [green] (#1)--(#2)-- (#3)--(#4);
\draw[very thick,blue] (#1).. controls (#2) and (#3) .. (#4);
\draw [fill=red,draw=black] (#1)node[left] {$P_0$} circle (2pt);
\draw [fill=red,draw=black] (#2)node[left] {$P_a$} circle (2pt);
\draw [fill=red,draw=black] (#3)node[right]{$P_b$} circle (2pt);
\draw [fill=red,draw=black] (#4)node[right]{$P_1$} circle (2pt);
\end{tikzpicture}
}
代码
\documentclass[]{article}
\usepackage{tikz}
\usetikzlibrary{positioning}
\newcommand\mybezier[4]{
\begin{tikzpicture}
\draw [green] (#1)--(#2)-- (#3)--(#4);
\draw[very thick,blue] (#1).. controls (#2) and (#3) .. (#4);
\draw [fill=red,draw=black] (#1)node[left] {$P_0$} circle (2pt);
\draw [fill=red,draw=black] (#2)node[left] {$P_a$} circle (2pt);
\draw [fill=red,draw=black] (#3)node[right]{$P_b$} circle (2pt);
\draw [fill=red,draw=black] (#4)node[right]{$P_1$} circle (2pt);
\end{tikzpicture}
}
\begin{document}
\mybezier{1,0}{2,3}{5,4}{6,1}
\end{document}
答案2
另一种方法是尝试show path construction
装饰。设置需要一点时间(例如,自动“很好地”放置控件标签,同时还允许自定义放置),但之后使用它就相当容易了,而且可以使用 TikZ 样式进行控制:
\documentclass[tikz,border=5]{standalone}
\usetikzlibrary{decorations.pathreplacing,shapes.misc,calc}
\tikzset{show bezier controls/.style={decoration={show path construction,
curveto code={
\tikzset{#1}
\path [hull/.try]
(\tikzinputsegmentfirst) -- (\tikzinputsegmentsupporta) --
(\tikzinputsegmentsupportb) -- (\tikzinputsegmentlast);
\path [curve/.try] (\tikzinputsegmentfirst) .. controls
(\tikzinputsegmentsupporta) and (\tikzinputsegmentsupportb)
.. (\tikzinputsegmentlast);
\path let \p1=(\tikzinputsegmentfirst), \p2=(\tikzinputsegmentsupporta),
\p3=(\tikzinputsegmentsupportb), \p4=(\tikzinputsegmentlast),
% Ugh. All this just to get the mid-angles of the relevant lines
\n1={atan2(\y2-\y1,\x2-\x1)}, \n2={atan2(\y2-\y3,\x2-\x3)},
\n2={abs(\n2-\n1)<180 ? (\n2 + \n1)/2+180 : (\n2 + \n1)/2},
\n3={atan2(\y3-\y2,\x3-\x2)}, \n4={atan2(\y3-\y4,\x3-\x4)},
\n3={abs(\n4-\n3)<180 ? (\n4 + \n3)/2+180 : (\n4 + \n3)/2}
in
\foreach \l [count=\i] in \tikzbezierlabels{ (\p\i)
node [inner sep=0pt, marking/.try, marking=\i/.try] {}
node [anchor=\n\i, marking label/.try, marking label \i/.try] {$\l$}
};
}}, decorate},
bezier labels/.store in=\tikzbezierlabels, bezier labels={,,,}
}
\begin{document}
\begin{tikzpicture}[
hull/.style={draw=green},
curve/.style={thick, draw=blue},
marking/.style={circle, draw=black, fill=red, minimum size=2.5pt},
marking label/.style={shape=circle},
bezier labels={P_0, P_a, P_b, P_1}
]
\path [show bezier controls] (1,0) .. controls (2,3) and (5,4) .. (6,1);
\path [show bezier controls, bezier labels={P_0, P_1, P_2, P_3}]
(0,4) .. controls (1,8) and (4,5) .. (6,10);
\path [show bezier controls={hull/.style={fill=gray!20, draw=black, dotted},
curve/.style={draw=black},
marking/.style={solid,shape=cross out, draw=black!50, thick, minimum size=3pt},
marking label/.append style={outer sep=.25cm, fill=blue!20},
marking label 2/.style={text=red}, bezier labels={P,Q,R,S}}, shift=(90:10)]
(0,0) .. controls ++(4,4) and ++(-4,3) .. (2,0);
\end{tikzpicture}
\end{document}
答案3
这是一个pic
版本。
\documentclass[]{article}
\usepackage{tikz}
\usetikzlibrary{positioning}
\tikzset{
pics/.cd,
mybezier/.style args={#1#2#3#4#5}{
code={
\draw[very thick,#5] (#1).. controls (#2) and (#3) .. (#4);
\draw [gray] (#1)--(#2)-- (#3)--(#4);
\draw [fill=green,draw=black] (#1)node[above] {$P₀$} circle (2pt);
\draw [fill=green,draw=black] (#2)node[above] {$P_a$} circle (2pt);
\draw [fill=green,draw=black] (#3)node[right] {$P_b$} circle (2pt);
\draw [fill=green,draw=black] (#4)node[right] {$P₁$} circle (2pt);
}},
}
\begin{document}
\begin{tikzpicture}
\pic (first) {mybezier={1,4}{4,4}{7,2}{8,0}{blue}};
\pic (second) {mybezier={0,3}{3,3}{5,2}{6,0}{red}};
\end{tikzpicture}
\end{document}
答案4
为了方便参考(我自己参考,也许其他人也参考),下面是最终代码,包括评论中提到的改进,还有一些其他内容。感谢 Jesse 完成了大部分工作。
\documentclass[12pt]{article}
\usepackage{tikz}
\usetikzlibrary{positioning}
\newcommand\poleDiam{1.8pt}
\newcommand\mybezier[5]{
\draw[very thick,#5] (#1).. controls (#2) and (#3) .. (#4);
\draw [gray] (#1)--(#2)-- (#3)--(#4);
\draw [fill=green,draw=black] (#1)node[above] {$P_0$} circle (\poleDiam);
\draw [fill=green,draw=black] (#2)node[above] {$P_a$} circle (\poleDiam);
\draw [fill=green,draw=black] (#3)node[right] {$P_b$} circle (\poleDiam);
\draw [fill=green,draw=black] (#4)node[right] {$P_1$} circle (\poleDiam);
}
\begin{document}
Here is some text before the picture.
\begin{center}
\begin{tikzpicture}
\mybezier{1,4}{4,4}{7,2}{8,0}{blue}
\mybezier{0,3}{3,3}{5,2}{6,0}{red}
\end{tikzpicture}
\end{center}
And here is some text after the picture.
\end{document}
输出结果如下:
除了图形一致性和易于修改之外,标签还有另一个好处。在 Powerpoint 中制作计算机现代标签很繁琐。