TikZ从零开始(三):Euclid‘s Amber Version of the Elements (Ⅰ)

0、前言

本教程译、改编自TikZ官方文档。
在这里插入图片描述

1、建立环境

\documentclass[tikz,margin=10pt]{standalone}
\usetikzlibrary{calc}
\usetikzlibrary{backgrounds}
\usetikzlibrary{through} % 为了更方便地画圆(已知圆心和圆上一点)
\usetikzlibrary{intersections}
\begin{document}
	\begin{tikzpicture}
		...
	\end{tikzpicture}
\end{document}

2、直线AB

当然我们可以用\draw (0,0)--(2,0);这样的代码,但是这里A、B其实可以是任意某两个点,我只想表达连接A、B,为此我们可以先用\coordinate命令定义出两个点。

\coordinate命令是\path coordinate命令的缩略版本。如果你不想命名,那么就不要写at。

\coordinate (A)  at (0,0);
\coordinate (B) at (1.25,0.25);
\draw[blue] (A) -- (B);

在这里插入图片描述
现在我们添加标注,这需要在用coordinate命令时随之设置,并且,它不需要画出连线就能显示,请看下例。

\coordinate[label=left:\textcolor{blue}{$ A $}] (A)  at (0,0);
\coordinate[label=right:\textcolor{blue}{$ B $}] (B) at (1.25,0.25);

在这里插入图片描述
现在画出连线。

\coordinate[label=left:\textcolor{blue}{$ A $}] (A)  at (0,0);
\coordinate[label=right:\textcolor{blue}{$ B $}] (B) at (1.25,0.25);
\draw[blue] (A) -- (B);

在这里插入图片描述
现在我们想让A、B真正任意起来,而TikZ恰好为我们提供了rand函数,它可以产生一个-1到1之间的均匀分布随机数(而rnd产生0到1之间的均匀分布随机数)。

\coordinate[label=left:\textcolor{blue}{$ A $}] (A)  at (0+0.1*rand,0.1*rand);
\coordinate[label=right:\textcolor{blue}{$ B $}] (B) at (1.25+0.1*rand,0.25+0.1*rand);
\draw[blue] (A) -- (B);

这看起来还不错,不过我们想成向量加法的形式: ( 0 , 0 ) + 0.1 ( r a n d , r a n d ) (0,0)+0.1(\mathrm{rand},\mathrm{rand}) (0,0)+0.1(rand,rand),这就需要用到calc库了。

\coordinate[label=left:\textcolor{blue}{$ A $}] (A)  at ($ (0,0) + 0.1*(rand,rand) $);
\coordinate[label=right:\textcolor{blue}{$ B $}] (B) at ($ (1.25,0.25) + 0.1*(rand,rand) $);
\draw[blue] (A) -- (B);

这种语法要求以($起始,以$)结束,注意,这儿的美元符号($ $)并不代表行内数学公式排版,而是表示要进行运算。
在这里插入图片描述

3、以A为圆心的圆

画圆就有些棘手了,因为我们不想手工计算AB的长度,为此,我们可以使用TikZ中的let操作。

let操作,syntax:\path … let <assignment> ,<assignment>,<assignment> … in …;
遇到这样的语句,<assignment>们会被依次计算,计算结果被暂存在寄存器中。随后我们就可以通过\p \n \x \y这些命令来调用结果。
1)第一种赋值(assignment)语句具有该形式:\n<number register>={<formula>}<number register>可以随便取什么名字,比如英文单词词组\n{hello world}或者数字\n3,如果是字母要加花括号。计算结果暂存于<number register>中,有单位(如 p t 、 c m \mathrm{pt、cm} ptcm)会保留单位。
例如,如果let \n1={1pt+2pt} \n2=<1+2> in ...那么在省略号...的部分\n1 \n2就会分别扩展为 3 p t 、 3 \mathrm{3pt、3} 3pt3
2)第二种<assignment>具有该形式:\p<point register>={<formula>}。点位置寄存器存储单个点的位置,包括用 p t \mathrm{pt} pt计量的 x x x坐标和 y y y坐标。
在这里插入图片描述\p{<point register>}写在=左侧,它只是被赋值了;而当它写在了右侧或者写在in后面,它就会进行扩展。
\x{<point regitster>}表示点的 x x x坐标,\y{<point regitster>}表示点的 y y y坐标。
上述的宏(macro)只适用于let操作。在这里插入图片描述
在上例中,也可以使用|-记号:
\fill[red] let \p1 = (first point), \p2 = (second point) in (\p1|-\p2) circle [radius=2pt];
注意,计算结果只在let-in语句有效,如果想要在语句之外也能使用计算结果,就要用coordinate进行保留。在这里插入图片描述
这边用到了感叹号表示法来表示中点,我试了试相加除以2,报错了。
在这里插入图片描述
这个做切线圆的我就看不懂感叹号表示法了。

在这里插入图片描述
circle后面的第一层圆括号是circle命令需要的:(<圆心>) circle (<半径>),第二层花括号是为了保证veclen函数在计算环境中(还记得第一节的{tan(30)}吗),而如果是做calc允许的向量加减或者带感叹号的,就要放在($ $)中。

现在我们想一次性画两个圆,所以我们可以先计算出半径,之后就不用再算了。

\coordinate[label=left:\textcolor{blue}{$ A $}] (A)  at ($ (0,0) + 0.1*(rnd,rand) $);
\coordinate[label=right:\textcolor{blue}{$ B $}] (B) at ($ (1.25,0.25) + 0.1*(rand,rand) $);
\draw[blue] (A) -- (B);
\draw let
	\p1 = ($ (B)-(A) $),
	\n2 = {veclen(\x1,\y1)}
	in (A) circle (\n2)
	   (B) circle (\n2);

在这段代码中,如果我们调用\n1,它不仅不会扩展成任何数,而且会报错,这是因为\p \x \y在同一个名字空间,而\n在自己独立的名字空间里。

用TikZ的through库可以更方便地画圆,我们的想法很简单,已知圆心A,且圆经过B,要作圆,而through刚好实现了我们的想法。

\coordinate[label=left:\textcolor{blue}{$ A $}] (A)  at ($ (0,0) + 0.1*(rnd,rand) $);
\coordinate[label=right:\textcolor{blue}{$ B $}] (B) at ($ (1.25,0.25) + 0.1*(rand,rand) $);
\draw[blue] (A) -- (B);
\node[draw,circle through=(B),label=left:$ D $] at (A) {};
\node[draw,circle through=(A),label=right:$ E $] at (B) {};

倒数第二行代码是这样运作的:首先创建一内外都没有空白(separation)的节点,然后设置节点形状为以A为圆心的圆,最后设定半径使得圆恰经过点B。
在这里插入图片描述

4、圆的交点

现在我们要找到交点。手工计算可就复杂了,好在TikZ给我们提供了intersections库,使得我们可以计算出任意路径的交点。

\coordinate[label=left:\textcolor{blue}{$ A $}] (A)  at ($ (0,0) + 0.1*(rnd,rand) $);
\coordinate[label=right:\textcolor{blue}{$ B $}] (B) at ($ (1.25,0.25) + 0.1*(rand,rand) $);
\draw[blue] (A) -- (B);
\node (D) [name path=D,draw,circle through=(B),label=left:$ D $] at (A) {};
\node (E) [name path=E,draw,circle through=(A),label=right:$ E $] at (B) {};
\path[name intersections={of=D and E,by={i1,i2}}];
\coordinate [label=above:$ C $] (C) at (i1);
\draw[red] (A)--(C);\draw[red] (B)--(C);

先指定两个路径名分别为D和E(虽然和节点名相同,但互不影响,因为他们在不同的名字空间),然后作交点,因为有两个交点,我用{i1,i2}表示它们(如果不用by指定交点名,则默认为intersection-1 intersection-2 ...),我想交在上方的点,所以最后一行at (i1)
在这里插入图片描述
我们甚至可以在作交点时顺便标注。
在这里插入图片描述
在这里插入图片描述

5、完整代码

\def\A{\textcolor{input}{$A$}} \def\B{\textcolor{input}{$B$}}
\def\C{\textcolor{output}{$C$}} \def\D{$D$}
\def\E{$E$}
\colorlet{input}{blue!80!black} \colorlet{output}{red!70!black}
\colorlet{triangle}{orange}
\coordinate [label=left:\A] (A) at ($ (0,0) + .1*(rand,rand) $);
\coordinate [label=right:\B] (B) at ($ (1.25,0.25) + .1*(rand,rand) $);
\draw [input] (A) -- (B);
\node [name path=D,help lines,draw,label=left:\D] (D) at (A) [circle through=(B)] {};
\node [name path=E,help lines,draw,label=right:\E] (E) at (B) [circle through=(A)] {};
\path [name intersections={of=D and E,by={[label=above:\C]C}}];
\draw [output] (A) -- (C) -- (B);
\foreach \point in {A,B,C}
\fill [black,opacity=.5] (\point) circle (2pt);
\begin{pgfonlayer}{background}
	\fill[triangle!80] (A) -- (C) -- (B) -- cycle;
\end{pgfonlayer}
\node [below right, text width=10cm,align=justify] at (4,3) {
	\small\textbf{Proposition I}\par
	\emph{To construct an \textcolor{triangle}{equilateral triangle}
		on a given \textcolor{input}{finite straight line}.}
	\par\vskip1em
	Let \A\B\ be the given \textcolor{input}{finite straight line}. \dots
};

注:设置背景也可以用上节的\begin{scope}[on background layer] \end{scope}代码,这里用了pgfonlayer环境,后面的background放在花括号而不是中括号中。
在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值