确定 Metapost/Metafont 中的路径是否是一条线

确定 Metapost/Metafont 中的路径是否是一条线

给定 Metapost/Metafont 中已定义的路径p:我如何确定像这样的线段是否subpath (0,1) of p是一条线?我知道我可以简单地检查控制点是否位于线上(例如,使用从控制点到端点的向量的叉积)。但有没有更直接的方法来做到这一点(比如命令straight(p))?

答案1

这是我之前做的,基于面积测试

vardef twice_area(expr a, b, c) = 
    (xpart b-xpart a)*(ypart c-ypart a) - (ypart b-ypart a)*(xpart c-xpart a)
enddef;

vardef collinear(expr a, b, c) = if abs(twice_area(a,b,c)) < 1.6 eps: true else: false fi enddef;

vardef straight(expr p) = (collinear(point 0 of p, postcontrol 0 of p, precontrol 1 of p)
                       and collinear(postcontrol 0 of p, precontrol 1 of p, point 1 of p)) enddef;

但这种方法不太可靠,因为行列式计算有点病态,使用默认缩放数字系统通常会给出略大于零的数字,尤其是对于非水平或垂直的直线。如果值超过 64bp,它还很容易溢出。

在 Metafont 中,这可能不是什么大问题,因为字符尺寸通常比较小,但在 Metapost 中,这却是一个麻烦,因为 Metapost 的字符尺寸通常较大。因此,这里有一个更简单、更好的straightMetapost 宏。

vardef straight(expr p) = arclength p - length (point length p of p - point 0 of p) < eps enddef;

这将给定路径的长度与路径第一点和最后一点之间的直线长度进行比较。在我的(诚然有限的)测试中,这似乎相当通用且可靠。但我欢迎反馈或改进。

笔记

  • arclength p返回给定路径的长度(以 PostScript 点为单位)p。这是 Metapost 独有的命令。

  • length p以 MP 的时间概念返回给定路径的长度p,例如fullcircle长度为 8 并且unitsquare长度为 4。

  • point 0 of p给出路径的第一个点p

  • point length p of p给出路径的最后一点(即使该路径是一个循环)。

  • (point length p of p - point 0 of p)返回pair表示路径起点和终点之间的向量。

  • length <pair>返回由以下表示的向量的长度(以 Postscript 点为单位)<pair>

因此length (point length p of p - point 0 of p)必须始终小于或等于arclength p。考虑到一点四舍五入,我们可以说p如果

arclength p - length (point length p of p - point 0 of p) < eps

该数量eps定义为plain.mp0.00049。

这两种不同的含义length也许令人遗憾,但在实践中并不难处理。

  • length <path>返回“时间”的长度
  • arclength <path>返回 Postscript 点的长度
  • length <pair>返回表示向量的 Postscript 点的长度<pair>

最后注意,由于<path>MP 中的 a 可以由单个点组成,您会发现如上定义的宏认为单个点是一条直线路径。因此(例如):

show straight(origin);

将会放

>> true

在您的日志文件中。

相关内容