在 a 中vardef
,我画了一个picture
,我想返回pairs
图片的。后面是小代码。它可以画出“I”形的图片,但我不知道如何返回对 - p[]
。
如果我取消注释最后一个draw origin -- p12;
,它会显示“xpart p12 undefined”。
另一方面,如果我picture
从 vardef 返回并在主函数中调用它,我如何获得pairs
与图片的关联?
outputtemplate := "%j-%c.eps";
prologues := 1 ;
beginfig(1)
vardef draw_I_shape (expr base, depth, width, tf ,tw) =
save p;
pair p[];
p1 := base;
p2 := p1 + (width, 0);
p3 := p2 + (0, tf);
p4 := p3 - ((width - tw) / 2, 0);
p5 := p4 + (0, depth - 2 * tf);
p6 := p5 + ((width - tw) / 2, 0);
p7 := p6 + (0, tf);
p8 := p7 - (width, 0);
p9 := p8 - (0, tf);
p10 := p9 + ((width - tw) / 2, 0);
p11 := p10 - (0, depth - 2 * tf);
p12 := p11 - ((width - tw) / 2, 0);
picture shape;
shape = image(
draw p1--p2--p3--p4--p5--p6--p7--p8--p9--p10--p11--p12--cycle;
);
draw shape;
p
enddef;
u = 0.1mm;
pair p[];
p = draw_I_shape (origin, 248u, 124u, 8u, 5u);
% draw origin -- p12;
endfig;
答案1
我会用不同的方法。我会构建一条路径来保存点,而不是尝试创建一个数组。我会编写一个turtle
宏,就像我在之前的一个问题的评论中所建议的那样,如下所示:
outputtemplate := "%j-%c.eps";
prologues := 3;
vardef turtle@# expr pr =
if known @#:
@# := @# -- point infinity of @# shifted pr
else:
@# := pr
fi
enddef;
beginfig(1)
vardef draw_I_shape (expr base, depth, width, tf ,tw) =
save p;
path p;
turtle.p base ;
turtle.p (width, 0);
turtle.p (0, tf);
turtle.p -(1/2(width-tw), 0);
turtle.p (0, depth - 2 * tf);
turtle.p ((width - tw) / 2, 0);
turtle.p (0, tf);
turtle.p -(width, 0);
turtle.p -(0, tf);
turtle.p ((width - tw) / 2, 0);
turtle.p -(0, depth - 2 * tf);
turtle.p -((width - tw) / 2, 0);
p := p--cycle;
draw p;
p
enddef;
u = 0.1mm;
path P;
P = draw_I_shape (origin, 248u, 124u, 8u, 5u);
draw origin -- point 6 of P withcolor red;
draw P scaled 1/2 rotated -20 shifted (42, 32) withcolor blue;
endfig;
end
生成结果:
笔记:
@#
上的后缀符号vardef
允许您传递后缀。这就是boxit
中的所有 etc 宏的工作方式boxes.mp
。因此如定义的那样,您需要
turtle
以变量名称path
作为后缀、以pair
表达式作为参数进行调用。在定义中,
@#
它像任何其他变量一样工作,因此您可以在普通表达式中使用它。if known @#
true
如果路径已经定义则返回,否则返回 false因此,如果你
turtle
使用新的(空)路径调用,if known @#
则将为 false,并且宏将简单地将该对分配给路径当您再次调用它时,路径不为空,因此
if known @#
将为真,现在宏将扩展为@# := @# -- point infinity of @# shifted pr
将路径重新定义@#
为其本身加上一条直线,该直线到由参数移动的终点。我想这是表达方式略微倒退了一点,但最终效果是添加相对于路径终点的参数。point infinity of p
是一种引用路径末尾点的便捷方法p
。您可以增强
turtle
宏来检查后缀是否是路径以及参数是否是pair
。
一次迈出多个步骤
你可以将这个想法更进一步,将“乌龟”部分包装在一个循环中,这样你就可以一次性指定所有的点:
prologues := 3;
outputtemplate := "%j%c.eps";
vardef creep@#(text t) =
for $=t:
@# := if known @#: @# -- point infinity of @# shifted fi $;
endfor
enddef;
vardef get_I_path(expr dp, wd, tf, tw) =
save p, h, v;
numeric h, v; h = 1/2(wd-tw); v = dp-2tf;
path p;
creep.p(
wd * right, tf * up, h * left, v * up, h * right, tf * up,
wd * left, tf * down, h * right, v * down, h * left, tf * down,
);
p := p--cycle;
p
enddef;
beginfig(1);
numeric u;
u = 0.1mm;
path S;
S = get_I_path(248u, 124u, 8u, 5u);
draw S;
draw point 0 of S -- point 6 of S withcolor red;
draw S scaled 1/2 rotated -20 shifted (42, 42) withcolor blue;
endfig;
end.
我在这里使用的 MP 语法功能是宏的类型参数。这允许您给出以逗号分隔的任意表达式或后缀列表。同样, MP 提供的源文件 text
中也有一些很好的例子。boxes.mp
vardef creep@#(text t) =
for $=t:
@# := if known @#: @# -- point infinity of @# shifted fi $;
endfor
enddef;
这里当creep
展开时,整个用逗号分隔的参数被读入t
,然后循环for $=t
用逗号将其拆分,并将参数中的每个项放入循环变量中$
。
然后,循环主体像以前一样添加$
到路径中@#
(除了我使用了更压缩的构造版本if
)。
此版本产生如下结果:
您会注意到,我已成功将路径的 0 点移至一个位置。如果这是个问题,您可以用 开始路径origin
。
出于风格考虑,我将命令draw
从第一级宏中移除。我发现编写只执行一项逻辑操作(即创建路径)的宏比创建路径并将其作为副作用绘制出来更容易。
我还使用了right
、left
、up
、down
宏,因为它们使代码更易于阅读(用英语!)。我本可以这样写,(wd,0)
而不是wd * right
、 等。