Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to detect if a user has drawn a circle on a touch device using canvas and javascript?

I am creating a Tangram puzzle game using Javascript. And I need to detect when a user has drawn a circle (or circle like shape) with their finger. I have been able to gather hundreds (if not thousands) of x and y points with:

 var touchX = event.targetTouches[0].pageX - canvas.offsetLeft;
 var touchY = event.targetTouches[0].pageY - canvas.offsetTop;

I then push each x and y coordinate into an array:

    touchMoveX.push(touchX);   
    touchMoveY.push(touchY);

I then loop through each array and create two points:

    for(var i = 0; i < touchMoveX.length; i++)
      {
        for(var l=0; l < touchMoveY.length; l++)
        {
            var xPosition = touchMoveX[i];
            var yPosition = touchMoveY[l];

            var v1x = touchMoveX[i];
            var v2x = touchMoveX[i + 1];
            var v1y = touchMoveY[l];
            var v2y = touchMoveY[l + 1];

Then using those two points, I use the following formula to figure out the angle between these two points in degrees:

 var v1 = {x: v1x, y: v1y}, v2 = {x: v2x, y: v2y},
 angleRad = Math.acos( (v1.x * v2.x + v1.y * v2.y) / 
 (Math.sqrt(v1.x*v1.x + v1.y*v1.y) * Math.sqrt(v2.x*v2.x + v2.y*v2.y) ) ),
 angleDeg = angleRad * 180 / Math.PI;

I then sum up all of the angles and see if they are around 360 degrees.

But the above code I have described isn't working very well. Does someone out there have a better way to do this? Thank you very much.

like image 887
Ramona Soderlind Avatar asked Jan 24 '15 23:01

Ramona Soderlind


1 Answers

yeah compute the average of all points (giving you a cheaply approximated center) then check if more than a certain percent of points are within a certain threshold. You can tune those values to adjust the precision until it feels right.

edit: Didn't consider that the circle could have multiple sizes, but you could just add another step computing the average of all distances. Adjusted the example for that.

var totalAmount = touchMoveX.length;

// sum up all coordinates and divide them by total length 
// the average is a cheap approximation of the center.
var averageX = touchMoveX.reduce( function ( previous, current) {
    return previous + current;
} ) / totalAmount ;
var averageY = touchMoveY.reduce( function ( previous, current) {
    return previous + current;
} ) / totalAmount ;

// compute distance to approximated center from each point
var distances = touchMoveX.map ( function ( x, index ) {
    var y = touchMoveY[index];        
    return Math.sqrt( Math.pow(x - averageX, 2) + Math.pow(y - averageY, 2) );
} );
// average of those distance is 
var averageDistance = distances.reduce ( function ( previous, current ) {
    return previous + current;
} ) / distances.length;

var min = averageDistance * 0.8;
var max = averageDistance * 1.2;
// filter out the ones not inside the min and max boundaries 
var inRange = distances.filter ( function ( d ) {
   return d > min && d < max;
} ).length;

var minPercentInRange = 80;
var percentInRange = inRange.length / totalAmount * 100;
// by the % of points within those boundaries we can guess if it's circle
if( percentInRange > minPercentInRange ) { 
   //it's probably a circle
}
like image 50
Winchestro Avatar answered Oct 29 '22 17:10

Winchestro