简单的圆形手势检测

发布于 2024-08-24 06:55:10 字数 374 浏览 7 评论 0原文

我正在寻找一种简单的编程方法来检测用户是否绘制了圆形形状。我正在使用 C 语言工作,但很高兴使用伪代码工作。谷歌搜索一下就会发现一些(希望如此)过于复杂的方法。

我将鼠标坐标作为浮点数进行跟踪,并创建了一个向量数组来跟踪鼠标随时间的移动。本质上,我希望检测何时绘制了一个圆,然后丢弃与该圆无关的所有运动数据。

我对如何实现这一点有一个基本想法:

使用轮询功能跟踪所有运动。每次轮询该函数时,都会存储当前鼠标位置。在这里,我们循环遍历历史位置数据并进行粗略的“捕捉位置”以比较两个位置。如果新位置距离旧位置足够近,我们将删除旧位置之前的所有历史数据。

虽然这在理论上可行,但在实践中却很混乱。有人有什么建议吗?如果建议的方法可以检测它是顺时针还是逆时针绘制的,那就加分了。

I'm looking at a simple, programmatic way of detecting whether or not the user has drawn a circular shape. I'm working in C, but am happy to work from pseudo-code. A bit of Googling brings up a number of (hopefully) overly-complex methods.

I'm tracking the mouse coordinates as floats, and have created an array of vectors to track the mouse movement over time. Essentially I'm looking to detect when a circle has been drawn and then disgard all movement data not associated with that circle.

I have a basic idea of how this might be accomplished:

Track all movements using a polling function. Each time the function is polled the current mouse position is stored. Here, we loop through the historic position data and do a rough 'snap to position' to compare the two locations. If the new location is within a close enough distance to an old position, we remove all historic data before the old location.

While this works in theory, it's a mess in practice. Does anyone have any suggestions? Bonus points if the method suggested can detect whether it's been drawn clockwise or counter-clockwise.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

半步萧音过轻尘 2024-08-31 06:55:10

恕我直言,你绝对走在正确的道路上。基本上,您需要将每个鼠标点与前一个鼠标点进行比较,并计算它们之间的角度(如单位圆上的设想,其中第一个点位于原点)。为此,您可以使用以下公式:

double angle = atan2(y2 - y1, x2 - x1) * 180 / PI;

if (angle < 0)
    angle += 360;

您最终得到的是,对于顺时针运动,角度将以正方向循环,而对于逆时针运动,角度将以负方向循环。您可以使用以下逻辑计算出当前角度是大于还是小于前一个角度:

if (angle2 > 270 && angle1 < 90)
{
    angle1 += 360
}
else if (angle1 > 270 && angle2 < 90)
{
    angle2 += 360
}

bool isPositive = (angle2-angle1 > 0);

如果您获得一定数量的向量,所有角度都在增加(isPositive 为 true,比方说,10 倍),您可以假设正在绘制顺时针圆;如果趋势为负(isPositive 为 false 10 次),则为逆时针圆圈。 :)

You are definitely on the right track IMHO. Basically you need to compare each mouse point with the previous mouse point and calculate the angle between them (as envisioned on a unit circle where the first point is at the origin). For this you can use the formula:

double angle = atan2(y2 - y1, x2 - x1) * 180 / PI;

if (angle < 0)
    angle += 360;

What you end up with is that for clockwise movement, the angle will cycle in a positive direction, whereas for counterclockwise movement the angle will cycle in a negative direction. You can figure out if the current angle is greater or less than the previous one with the following logic:

if (angle2 > 270 && angle1 < 90)
{
    angle1 += 360
}
else if (angle1 > 270 && angle2 < 90)
{
    angle2 += 360
}

bool isPositive = (angle2-angle1 > 0);

If you get a certain number of vectors all with angles that are increasing (isPositive is true, let's say, 10 times), you can assume a clockwise circle is being drawn; if the tendency is negative (isPositive is false 10 times) it's a counterclockwise circle. :)

迷荒 2024-08-31 06:55:10

基于您的跟踪/轮询功能,它将浮点数对推送到堆栈上。这必须定期进行。

  1. 对列表中的两个相等条目进行基于阈值的搜索。现在你的堆栈中有两个索引;第一个和第二个条目相等。将其视为一条线。
  2. 获取指数的绝对差。然后除以二,得到该点的坐标。 (线的中心。)
  3. 您有两个点:因此您可以通过将两点之间的距离除以二来获得圆的半径。
  4. 将步骤 2 的数字除以 2,现在就得到了四分之一。

    如果第 1 步中的线是垂直的,并且线的第一个点位于顶部:如果第一个四分之一位于中心点的左侧,则按逆时针方向绘制圆。如果第一个四分之一位于中心点的右侧,则按顺时针方向绘制圆。如果线的第一个点位于底部,则反转(即 ccw => CW 且 CW => ccw)

    如果第 1 步中的线是水平的,并且列表的第一个点位于左侧:如果第一个四分之一位于中心点上方,则按逆时针方向绘制圆。如果第一个四分之一位于中心点下方,则按顺时针方向绘制圆。如果直线的第一个点位于右侧,则反转。

  5. 检查它是否是一个圆:迭代所有坐标对并计算到中心点的距离。根据计算距离和到中心点的实际距离调整允许距离的阈值。

在步骤 2 和 4 中,如果时间间隔非常短(快速轮询),您可以通过取多个索引的平均值来进一步调整此算法。例如:数组中有 30 对,然后对 0、1 和 28、29 处的对进行平均以获得最高点。对所有其他点执行相同的操作。

我希望这很容易。

Based on your tracking/polling function, which pushes float pairs on a stack. This must be done on a regular timing interval.

  1. Do a threshold-based search for two equal entries in the list. Now you have two indexes in your stack; the first and the second equal entries. Consider this as a line.
  2. Get the absolute difference in indices. Then divide by two and get the coordinates of this point. (Center of the line.)
  3. You've got two points: thus you can get the radius of the circle, by getting the distance between the two points divided by two.
  4. Divide the number of step 2 by 2, now you've got the quarters.

    If the line at step 1 is vertical and the first point of the line is at the top: If the first quarter is left of the center-point, the circle was drawn counter-clockwise. If the first quarter is right of the center-point, the circle was drawn clockwise. If the first point of the line is at the bottom, reverse (i.e. ccw => cw and cw => ccw)

    If the line at step 1 is horizontal and the first point of the list is at the left: If the first quarter is above the center-point, the circle was drawn counter-clockwise. If the first quarter is below of the center-point, the circle was drawn clockwise. If the first point of the line is at the right, reverse.

  5. Check if it was a circle: iterate over all pairs of coordinates and calculate the distance to the center-point. Tweak the threshold of allowed distances from the calculated distance and the actual distance to the center-point.

In step 2 and 4 you can tweak this algorithm further by taking the average of several indices if the timing interval is very low (fast polling). For instance: there are 30 pairs in the array, then you average pairs at 0, 1 and 28, 29 to get the upper point. Do the same for all other points.

I hope this is easy enough.

忆梦 2024-08-31 06:55:10

下面是一个查看点数组是否适合圆的算法:

  1. 计算点的质心(所有 x 和 y 坐标的平均值)

  2. 计算所有点到质心的距离

  3. 求最大和最小距离

  4. 如果最大值 - 最小值 <公差,检测到圆形截面

注意:这也会检测圆的一部分,因此您需要确定扫过足够的角度以使其成为一个完整的圆。

要做到这一点:

  1. 如上所述计算质心
  2. 计算质心和每个点之间的角度(使用atan2函数)
  3. 将角度映射到线段(我发现12个30度线段对我有用;只需将角度除以30并向下舍入为整数 - 假设您正在工作此处以度为单位)
  4. 如果所有线段至少包含 1 个点,则它是一个圆(即映射的线段数组包含 0 到 11 之间的所有值)

  5. 奖励:角度增加是逆时针的;顺时针方向减小

Here's an algorithm to see if an array of points fits a circle:

  1. calculate the centroid of the points (average of all the x and y coordinates)

  2. calculate the distance of all points to the centroid

  3. find the maximum and minimum distances

  4. if maximum - minimum < tolerance, circular section detected

NB This will detect a section of a circle as well so you will need to determine that enough of an angle is swept through for it to be a full circle.

To do this:

  1. calculate centroid as above
  2. calculate angle between centroid and each point (use atan2 function)
  3. map angles to segments (I find 12 30 degree segments works for me; just divide angle by 30 and round down to integer - assuming you are working in degrees here)
  4. if all segments contain at least 1 point, then it is a circle (i.e. your mapped segments array contains all values between 0 and 11)

  5. bonus: increasing angle is anti-clockwise; decreasing is clockwise

绳情 2024-08-31 06:55:10

还没有尝试过这个,但在阅读你的问题时想到了这个想法,所以不妨与你分享:

我假设在给定稳定的“采样率”的情况下,必须在合理的时间内绘制圆圈鼠标的形状将留下已知大小的二维向量(点)数组。将它们全部相加,然后除以 2D 向量的数量,以获得数组中“中心”点的估计值。然后形成从该中心点到数组中的点的向量,并进行点积(按向量长度归一化),确保点积的符号对于一系列点保持相同意味着这些点都以相同的方式移动方向,正号表示逆时针方向运动,负号则相反。如果累积的角度超过 2 PI,则会绘制圆周运动。

祝你好运。

Haven't tried this, but the idea came to mind reading your question, so might as well share it with you:

I'm assuming the circle has to be drawn within a reasonable amount of time, given a steady "sample-rate" of the mouse that would leave a known-size array of 2D vectors (points). Add them all and divide by the count of 2D vectors to get an estimate of the "center" point in the array. Then form vectors from this center-point to the points in the array and do dot-products (normalizing by vector length), making sure the sign of the dot-products remain identical for a range of points means those points all move in the same direction, a positive sign will indicate counter-clockwise movement, negative is just the opposite. If the accumulated angle exceeds 2 PI, a circular movement was drawn..

Good luck.

比忠 2024-08-31 06:55:10

1 - 选取任意 3 个点

2 - 如果这些点共线 +/-“某个缓冲区”,则它不是圆。

3 - 使用维基百科上描述的求三角形外接圆的方法来找到候选圆的中点和半径

画任意两条三角形的外心即可
的三个垂直平分线。对于三个不共线的点,
这两条线不能平行,外心就是点
他们交叉的地方。平分线上的任意一点到
它平分两点,由此得出这一点,在
两条平分线与所有三个三角形顶点的距离相等。这
外接圆半径是从它到三个顶点中任意一个的距离。

4 - 检查到其余点的距离。如果这些点位于“候选圆半径”+/-“一些缓冲区余量”内,那么它就是一个圆。

5 - 要确定方向,只需计算第一个点和第二个点与中点之间的角度。负角是正确的。留下一个正角。 (根据您使用的坐标系可能会相反)

1 - Pick any 3 of the points

2 - If the points are collinear +/- 'some buffer' then it isn't a circle.

3 - Use the method described on Wikipedia for finding the circumscribed circle for a triangle to find the midpoint and radius of your candidate circle

The circumcenter of a triangle can be constructed by drawing any two
of the three perpendicular bisectors. For three non-collinear points,
these two lines cannot be parallel, and the circumcenter is the point
where they cross. Any point on the bisector is equidistant from the
two points that it bisects, from which it follows that this point, on
both bisectors, is equidistant from all three triangle vertices. The
circumradius is the distance from it to any of the three vertices.

4 - Check the distance to the remaining points. If those points are within the 'candidate circle radius' +/- 'some buffer allowance' then it is a circle.

5 - To determine direction, simply calculate the angle between the first and 2nd points from the midpoint. A negative angle is right. A positive angle is left. (Could be reversed depending on the coordinate system you are using)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文