views:

274

answers:

2

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.

+1  A: 

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.

Pindatjuh
A: 

Hi,

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.

S.C. Madsen