在我的一门课程中,我得到了一项家庭作业,要求我们用谷歌搜索 Metapost 语言并找到该语言中方程求解功能的用途。在浏览了 Metapost 用户手册的前十几页之后,我发现它之所以有用只有一个原因,那就是“允许许多程序以主要的声明式风格编写”。除了说明它使编程更加“声明性”(据我理解,这意味着我们告诉语言该做什么而不是如何去做)我想不出任何其他原因说明方程求解是有用的。谁能帮我吗?
1 回答
这是一个说明如何在 MetaPost 中求解方程——以及就此而言的声明式编程——可能是有用的。
假设我们要画一个骰子:
为此,让我们首先定义一个宏,它将绘制骰子的一个面:一个s
上面有数字的正方形。
def face (expr s) = image (begingroup
pickup pencircle scaled 1pt;
draw (0.5, 0.5) -- (0.5, 9.5) -- (9.5, 9.5) -- (9.5, 0.5) -- cycle;
label (s, (5, 5));
endgroup) scaled 10 enddef;
现在我们可以绘制它并得到图片:
draw face ("1");
接下来,我们需要一个上脸和一个右脸。要绘制它们,我们将必须编写仿射变换来倾斜它们。这可能很棘手,因为唯一现成的用于倾斜的原始转换是slanted a
将点(x, y)
转换为(x + ay, y)
. 这是我们的图片倾斜1:
draw face ("2") slanted 1;
然后(或者更确切地说,在此之前)我们必须按以下坐标之一进行缩放:
draw face ("2") yscaled 0.35 slanted 1;
同样的方法不适用于第三张脸:
draw face ("3") xscaled 0.35 slanted 1;
经过一番试验,我们找到了正确的代码:
draw face ("3") rotated 90 yscaled 0.35 slanted -1 rotated -90;
但为什么所有的乏味?我们确切地知道我们需要什么样的转变。一种自然的表达方式是使用原语。但是,如果这被证明是不直观的,就像我们最后一行一样,那么只指定平面的哪些点转换到哪些点可能会更舒服。
transform t;
(0, 0) transformed t = (0, 0);
(0, 1) transformed t = (0.35, 0.35);
(1, 0) transformed t = (1, 0);
draw face ("3") transformed t;
这基本上告诉 MetaPost:有一个 transform t
,我们指定的三个点在它下面移动到我们指定的其他三个点。事实证明,这唯一地确定了平面变换,我们得到了相同的图片:
将所有这些放在一起(代码beginfig (7)
在帖子末尾)让我们最终看到我们的死:
在这个简单的例子中,“坐标和方程”方法的难度与“原始变换”方法相当。现在,想象一下我们想要我们的立方体稍微倾斜。使用相同的声明性方法,仍然可以不调用 3D 几何(代码beginfig (8)
在帖子末尾):
完整的程序如下。
prologues := 3;
def face (expr s) = image (begingroup
pickup pencircle scaled 1pt;
draw (0.5, 0.5) -- (0.5, 9.5) -- (9.5, 9.5) -- (9.5, 0.5) -- cycle;
label (s, (5, 5));
endgroup) scaled 10 enddef;
beginfig (1)
draw face ("1");
endfig;
beginfig (2)
draw face ("2") slanted 1;
endfig;
beginfig (3)
draw face ("2") yscaled 0.35 slanted 1;
endfig;
beginfig (4)
draw face ("3") xscaled 0.35 slanted 1;
endfig;
beginfig (5)
draw face ("3") rotated 90 yscaled 0.35 slanted -1 rotated -90;
endfig;
beginfig (6)
transform t;
(0, 0) transformed t = (0, 0);
(0, 1) transformed t = (0, 1);
(1, 0) transformed t = (0.35, 0.35);
draw face ("3") transformed t;
endfig;
beginfig (7)
transform t [];
draw face ("1");
(0, 0) transformed t[1] = (0, 0);
(0, 1) transformed t[1] = (0.35, 0.35);
(1, 0) transformed t[1] = (1, 0);
draw face ("2") transformed t[1] shifted (0, 100);
(0, 0) transformed t[2] = (0, 0);
(0, 1) transformed t[2] = (0, 1);
(1, 0) transformed t[2] = (0.35, 0.35);
draw face ("3") transformed t[2] shifted (100, 0);
endfig;
beginfig (8)
transform t [];
pair Ox, Oy, Oz;
Ox = (0.86, -0.21);
Oy = (0.21, 0.86);
Oz = (0.29, 0.44);
(0, 0) transformed t[1] = (0, 0);
(1, 0) transformed t[1] = Ox;
(0, 1) transformed t[1] = Oy;
draw face ("4") transformed t[1];
(0, 0) transformed t[2] = (0, 0);
(1, 0) transformed t[2] = Ox;
(0, 1) transformed t[2] = Oz;
draw face ("5") transformed t[2] shifted (Oy scaled 100);
(0, 0) transformed t[3] = (0, 0);
(1, 0) transformed t[3] = Oz;
(0, 1) transformed t[3] = Oy;
draw face ("6") transformed t[3] shifted (Ox scaled 100);
endfig;
end