Metapost:vardef - 画一幅画并返回对

Metapost:vardef - 画一幅画并返回对

在 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从第一级宏中移除。我发现编写只执行一项逻辑操作(即创建路径)的宏比创建路径并将其作为副作用绘制出来更容易。

我还使用了rightleftupdown宏,因为它们使代码更易于阅读(用英语!)。我本可以这样写,(wd,0)而不是wd * right、 等。

相关内容