John Alberto
John Alberto

Reputation: 437

Finding a "movement direction" (angle) of a point

I'm working on a pretty cool project where I'm collecting data about the movement of a cursor, but I've run into an issue where I think I could use some help. I am constantly reading in data about the x and y position of the cursor (along with other relevant data), and once the cursor exceeds a certain threshold in the y-dimension, I need to calculate the movement direction (angle). Let me illustrate with a figure I drew:

enter image description here

What tends to happen is that the cursor moves in a somewhat straight line, but then curves towards the end of the movement. I need to calculate theta, i.e., the angle of the blue vector with respect to the positive x-axis. The idea I came up with is to use the last 2 samples to largely determine what the movement direction is, otherwise if I use too many samples I would skew what the actual angle is. To give an extreme case let me follow up with another picture:

enter image description here

Here each dot represents a sample. Note that if I use BOTH dots, the real angle I want will be wrong (again, I need to find the direction the cursor was moving in last, which is the vector drawn at the end of the line). I dont expect this case to come up much, but was wondering if there would be a way to solve for it if it does.

Lastly, note that the these motions can occur in either the first or second quadrant, if that makes a difference.

I'd really appreciate any help here. I'm coding this in C++ but I think I could translate any answer. Thanks.

Upvotes: 8

Views: 3056

Answers (2)

Louis Ricci
Louis Ricci

Reputation: 21116

This should get you started http://jsfiddle.net/0ao9oa7a/

  • Get all of the recorded points
  • Filter out points that are close together (I use 5 pixels)
  • Find the angles of each consecutive pair of points (atan2)
  • Find the absolute differences between each consecutive pair of angles
    • Throw away all of the angles before the max difference
  • Average the remaining angles (average all point vectors then atan2 back into an angle)

Code

function process(points) {
    if(points.length === 0) { 
        txt = "Not enough points\n" + txt;
        return null; 
    }
    // compress points, removing those that are too close together
    var newPoints = [];
    newPoints.push(points[0]);
    for(var i = 1; i < points.length; i++) {
        if(Math.sqrt(Math.pow(points[i].x - newPoints[newPoints.length - 1].x, 2) + Math.pow(points[i].y - newPoints[newPoints.length - 1].y, 2)) > 5) {
            newPoints.push(points[i]);
        }
    }
    points = newPoints;
    if(points.length < 2) { 
        txt = "Not enough points\n" + txt;
        return null; 
    }
    // get all of the angles
    var angles = [];
    for(var i=0; i < points.length - 1; i++) {
        var rad = Math.atan2(points[i + 1].y - points[i].y, points[i + 1].x - points[i].x);
        angles[i] = rad;
        txt += "x: " + (points[i].x|0) + " y: " + (points[i].y|0) + " x: " + (points[i+1].x|0) + " y: " + (points[i+1].y|0) + " [" + ((rad * 180 / Math.PI)|0) + "]" + "\n";
    }
    txt += "\n";
    // get all of the diffs between angles
    // save the index of the max diff
    var absDiffs = [];
    var maxDiff = -1;
    var maxDiffAngleIndex = -1;
    for(var i=0; i < points.length - 1; i++) {
        var delta = Math.abs(angles[i] - angles[i + 1]);
        if(delta >= maxDiff) {
            maxDiff = delta;
            maxDiffAngleIndex = i + 1;
        }
    }
    if(maxDiffAngleIndex == -1) {
        txt = "Angle: " + angles[0] + " : " + (angles[0] * 180 / Math.PI) + "\n" + txt;
        return angles[0];
    } else if(maxDiffAngleIndex == angles.length - 1) {
        txt = "Angle: " + angles[angle.length - 1] + " : " + (angles[angles.length - 1] * 180 / Math.PI) + "\n" + txt;
        return angles[angles.length - 1];
    } else {
        // find the average angle from the index to the end
        var sumX = 0;
        var sumY = 0;
        for(var i = maxDiffAngleIndex; i < angles.length; i++) {
            sumX += Math.cos(angles[i]);
            sumY += Math.sin(angles[i]);
        }
        var avgX = sumX / (angles.length - maxDiffAngleIndex);
        var avgY = sumY / (angles.length - maxDiffAngleIndex);
        //
        var avgAngle = Math.atan2(avgY, avgX);
        txt = "Angle: " + avgAngle + " : " + (avgAngle * 180 / Math.PI) + "\n" + txt;
        return avgAngle;
    }
}

Upvotes: 3

Gabriel
Gabriel

Reputation: 763

As I can see, the “movement direction” (angle) of a point would be the angular coefficient of two dots, one dot at the end of the vector and the other one at the begnning.

Cause we can only find the angle with two dots, so we can make a line, since the direction vector would be (B-A), where A and B are the points I already told you about.

We can calcule this using the formula of the angular coefficient of a line:

m = Tan θ = Δy / Δx

And that is simply:

Tan θ = (yB – yA) / (xB – xA)

Where θ is the “movement direction” (angle) and (x,y) are the coordinates of the points A and B.

Talking about the quadrant, you will only need to use the trigonometric circle to know the sinal of the value of Tan θ, so take a look at this image:

enter image description here

And of course, after you find the value of Tan θ, you will need to use it to find the arctan θ, and that will be your final answer.

Upvotes: 0

Related Questions