简单的圆形手势检测
我正在寻找一种简单的编程方法来检测用户是否绘制了圆形形状。我正在使用 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
恕我直言,你绝对走在正确的道路上。基本上,您需要将每个鼠标点与前一个鼠标点进行比较,并计算它们之间的角度(如单位圆上的设想,其中第一个点位于原点)。为此,您可以使用以下公式:
您最终得到的是,对于顺时针运动,角度将以正方向循环,而对于逆时针运动,角度将以负方向循环。您可以使用以下逻辑计算出当前角度是大于还是小于前一个角度:
如果您获得一定数量的向量,所有角度都在增加(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:
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 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. :)
基于您的跟踪/轮询功能,它将浮点数对推送到堆栈上。这必须定期进行。
将步骤 2 的数字除以 2,现在就得到了四分之一。
如果第 1 步中的线是垂直的,并且线的第一个点位于顶部:如果第一个四分之一位于中心点的左侧,则按逆时针方向绘制圆。如果第一个四分之一位于中心点的右侧,则按顺时针方向绘制圆。如果线的第一个点位于底部,则反转(即 ccw => CW 且 CW => ccw)
如果第 1 步中的线是水平的,并且列表的第一个点位于左侧:如果第一个四分之一位于中心点上方,则按逆时针方向绘制圆。如果第一个四分之一位于中心点下方,则按顺时针方向绘制圆。如果直线的第一个点位于右侧,则反转。
在步骤 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.
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.
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.
下面是一个查看点数组是否适合圆的算法:
计算点的质心(所有 x 和 y 坐标的平均值)
计算所有点到质心的距离
求最大和最小距离
如果最大值 - 最小值 <公差,检测到圆形截面
注意:这也会检测圆的一部分,因此您需要确定扫过足够的角度以使其成为一个完整的圆。
要做到这一点:
如果所有线段至少包含 1 个点,则它是一个圆(即映射的线段数组包含 0 到 11 之间的所有值)
奖励:角度增加是逆时针的;顺时针方向减小
Here's an algorithm to see if an array of points fits a circle:
calculate the centroid of the points (average of all the x and y coordinates)
calculate the distance of all points to the centroid
find the maximum and minimum distances
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:
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)
bonus: increasing angle is anti-clockwise; decreasing is clockwise
还没有尝试过这个,但在阅读你的问题时想到了这个想法,所以不妨与你分享:
我假设在给定稳定的“采样率”的情况下,必须在合理的时间内绘制圆圈鼠标的形状将留下已知大小的二维向量(点)数组。将它们全部相加,然后除以 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.
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
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)