tkz-elements 宏包介绍
1. tkz-euclide 宏包的优缺点
之前在绘制平面几何图形的时候,一直使用 tkz-euclide 宏包。其优点如下:
- 方便调整图像大小和形状;
- 常见的需求都能够直接画出来(如三角形的各种心);
- 函数的命名规则比较规矩;
- 整个绘制图形的代码分为三部分,可读性很好:
- 定义(如
\tkzDef...
和\tkzInter...
); - 绘制(如
\tkzDraw...
和\tkzFill...
); - 标记(如
\tkzLabel...
和\tkzMark...
)。
- 定义(如
但是缺点也很明显:
- 命名比较繁琐;
- 各种括号容易写混了;
- 各个参数的顺序很不自然。
例如「直线 与 异于 的交点为 」,用 tkz-euclide 命令来写是
1 | \tkzInterLC[common=A](A,I)(O,A) \tkzGetFirstPoint{P} |
这里面主要有两个问题,一是可选参数 [common=A]
在中间,而正常的思路是先写出直线和圆,再写可选参数,这样会比较顺;二则是后面的获取交点 ,需要一个单独的命令,而且还要根据前面可选参数的不同,来决定是使用 \tkzGetFirstPoint
还是 \tkzGetPoints
。
另外,一个命令里同时用到了小括号、中括号、大括号,虽然是有规律的,但是还是容易打错了,导致编译失败。
当然解决方法也是有的,那就是利用 VSCode 的代码片段(snippet)功能,这样可以自定义参数的输入顺序,也可以保证不会打错括号。例如上面的命令,实际上用到了下面的代码片段:
1 | "tkzInterLC1": { |
我把常用的 50 多个命令都写成了类似上面的代码片段,这样在使用的时候就能够自动补全,只需要输入对应的参数即可。
2. tkz-elements 宏包简介
今年在写几何题解析的时候,发现了 tkz-euclide 宏包作者写的新宏包:tkz-elements,把比较繁琐的「定义」的部分改为使用 lua 语言进行编程。这样写出的代码可读性更强,写起来也更自然。
主要改进的点有:
- 计算更加精确(不过这点对我实际使用影响不大);
- 使用面向对象编程的范式,这对于写惯了编程代码的我来说就很顺了。
以 2024 年 IMO 第 4 题为例,定义部分新旧代码的对比如下:
1 | %% 定义三角形 ABC |
1 | -- 定义三角形 ABC |
使用 tkz-elements 绘制整个图形的代码结构如下:
1 | \directlua{ |
首先使用 \directlua
导入 lua 代码。
这也决定了该文档必须使用 LuaLaTeX 编译,而不能使用 pdfLaTeX 或 XeLaTeX 编译。
如果使用 latexmk 控制编译过程,加上 -pdflua
参数即可。
然后在 tikzpicture
环境中使用 \tkzGetNodes
获取上面定义的几何对象。
tkz-elements 宏包使用 lua 语言的 table(表)来保存几何对象,常用的有:
z
:点(复数 )L
:直线(line)C
:圆(circle)T
:三角形(triangle)
其它还包括:
Q
:四边形(quadrilateral)P
:平行四边形(parallelogram)R
:矩形(rectangle)S
:正方形(square)RP
:正多边形(regular polygon)O
:直角坐标系(orthonormal Cartesian coordinate system)V
:向量(vector)M
:矩阵(matrix)PA
:路径(path)
上面代码中的 init_elements()
,其实就是初始化(或者重置)上面这些储存几何对象的表。
lua 使用 table.name
来访问表中的元素(当然也可以使用 table["name"]
,不过显然前者更简洁)。
例如,z.A
表示点 ,z.T_A
表示点 ,z.Bp
表示点 (撇号的英文是 prime),T.ABC
表示三角形 。
lua 可以通过 table(以及内部的 metatable)实现面向对象编程。我们知道,对象由属性(attribute)和方法(method)组成。
lua 使用点号 .
来访问属性,使用冒号 :
来访问方法。
值得说明的是,有两个方法是所有几何对象都有的:new(...)
方法用来构造新的对象,get()
方法用来获取构造对象的点。
以三角形为例,我们首先使用 new
方法来创建对象:
1 | T.ABC = triangle:new(z.A, z.B, z.C) |
三角形包含一些常见的属性,比如顶点、边、面积、半周长、内心、外心、内径、外径等等。包含的方法也很多,包括中线、高、角平分线、内切圆、外接圆等等,基本上经常用到的都有定义。例如
1 | -- 点 O 是三角形 ABC 的外心 |
这些属性和方法基本上就是对应的英文名称,因此很好记。如果不确定的话,文档查起来也很方便。在文档中,每种几何对象都有一个列表,列出所有的属性;然后所有方法按照返回值的类型分别举例说明。
3. tkz-elements 宏包的一些内部实现
由于 tkz-elements 宏包是使用 lua 语言实现的,因此我能够看懂它的源代码,可以了解它的具体实现方法。
3.1. tkz-elements.sty
加载 tkz_elements_main
模块,定义了 tkzelements
环境、\tkzGetNodes
命令,还有一些不太常用的命令。
3.2. tkz_elements_main.lua
加载各个几何对象对应的定义和函数模块,定义了 init_elements
初始化函数。
3.3. tkz_elements_point.lua
首先定义了一个工厂函数 class
,用来实现面向对象的类,然后使用复数类来定义点。
3.4. tkz_elements_triangle.lua
可以看到,三角形的各个心都是通过重心坐标或者三线坐标计算得到。