Stroke 是圆吗?

Is the Stroke a circle?

是否可以检测用户在canvas上画的笔画是不是圆形?

我有两个数组 x[]y[],它们具有笔画的所有坐标。我如何使用此信息来检查笔画是否为圆形?

我想这取决于您对 "circle" 的定义。用户不太可能画出真正的圆圈,尽管它们可能很接近。所以首先,您需要为 "circle".

定义一个规范

这是一个可能有用的方法:

  1. 绘制的形状是闭合曲线。 IE。最终点离初始点比较近
  2. 每个点到"center"的距离,其中"center"定义为所有点的平均值,比较接近所有点的平均距离。

请注意,该规范仍然相当模糊。我使用短语 "relatively close" 而不是精确的术语,因为我真的不知道您对 "circle" 的标准是什么。但我希望以上内容是一个很好的起点。


编辑:

如评论中所述,上面的内容仍然允许一些相当草率的绘图有资格作为圆形,例如提到的 "D" 形状。如果希望将绘图限制为合理的圆形,但仍允许相当 "squashed" 的形状(例如更椭圆、蛋形等),可以通过添加基于角度的试探法来改进上述内容通过点的三元组。

要正确地做到这一点有点复杂。您可以使用点积轻松确定两个向量之间的角度。但不幸的是,该计算与哪个向量无关"first"。也就是说,如果您关心凹曲线与凸曲线,则点积不会区分。另一种方法是使用 Math.Atan2() 函数。比如我们先看前三点的夹角:

// Note: normally one would make both vectors have the same start
// point, i.e. using pointList[1], for the subtraction of the
// Atan2 value to give the correct result. But here, what we really
// want to know is how different in direction the second vector is
// from the first, so calculating both line segment angles in the
// same direction of drawing gives a more useful result.

double vx1 = pointList[1].X - pointList[0].X, vy1 = pointList[1].Y - pointList[0].Y,
    vx2 = pointList[2].X - pointList[1].X, vy2 = pointList[2].Y - pointList[1].Y;
double angleDifference = Math.Atan2(vx2, vy2) - Math.Atan2(vx1, vy1);

(您当然会在循环中进行这些计算,以获得每个三元组点的差异;以上内容仅用于说明目的)。

假设用户在逆时针方向画了一个圆,那么上面应该return接近0的正角差。如果它们接近0,那么你会想要拒绝绘图,因为这表明用户正在绘制直线(例如 "D" 的竖线)。但是如果某些差异与 0 相差太远,您还需要拒绝绘图,因为这表明用户可能正在绘制尖角(例如 "D" 的左上角或左下角)。

注意:较小的圆需要更锐利的角度。您可能希望根据圆的标称直径(即每个点距中心的平均距离)动态调整用于此的限制,将最小和最大角度差设置为较小的圆圈,较大的圆圈较小圈子。

注意:此处的角度值以弧度为单位。因此,在设置角度差的下限和上限时,您需要确保使用正确的单位进行比较。

注:用户当然可以顺时针方向画圆。如果你把所有的差异加起来,你会得到一个正数或负数;该标志将告诉您是否应该将您的差异与您想要的限制进行比较,或者与这些限制的负数进行比较。要解决此问题,您可以执行以下任一操作:

  • 对数据进行两次遍历,首先找出您想要的限值是正值还是负值,然后将实际值与限值进行比较。
  • 在第一次通过时保存角度计算,然后在第二次通过时使用这些保存的值。
  • 只需跟踪您的比较是否始终在正限、负限或两者内(即两个标志,根据与正限和负限的比较将适当的设置为 true ).数据过一遍就知道应该用正极限还是负极限,然后只要最后只设置一个flag,圆就有效(假设没有角度超过绝对极限) , 当然).