Reputation: 437
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:
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:
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
Reputation: 21116
This should get you started http://jsfiddle.net/0ao9oa7a/
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
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:
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