Calculating the angle between the line defined by two points
Assumptions: x
is the horizontal axis, and increases when moving from left to right.y
is the vertical axis, and increases from bottom to top. (touch_x, touch_y)
is thepoint selected by the user. (center_x, center_y)
is the point at the center of thescreen. theta
is measured counter-clockwise from the +x
axis. Then:
delta_x = touch_x - center_xdelta_y = touch_y - center_ytheta_radians = atan2(delta_y, delta_x)
Edit: you mentioned in a comment that y increases from top to bottom. In thatcase,
delta_y = center_y - touch_y
But it would be more correct to describe this as expressing (touch_x, touch_y)
in polar coordinates relative to (center_x, center_y)
. As ChrisF mentioned,the idea of taking an "angle between two points" is not well defined.
Had a need for similar functionality myself, so after much hair pulling I came up with the function below
/** * Fetches angle relative to screen centre point * where 3 O'Clock is 0 and 12 O'Clock is 270 degrees * * @param screenPoint * @return angle in degress from 0-360. */public double getAngle(Point screenPoint) { double dx = screenPoint.getX() - mCentreX; // Minus to correct for coord re-mapping double dy = -(screenPoint.getY() - mCentreY); double inRads = Math.atan2(dy, dx); // We need to map to coord system when 0 degree is at 3 O'clock, 270 at 12 O'clock if (inRads < 0) inRads = Math.abs(inRads); else inRads = 2 * Math.PI - inRads; return Math.toDegrees(inRads);}
A few answers here have tried to explain the "screen" issue where top left
is 0,0
and bottom right
is (positive) screen width, screen height
. Most grids have the Y
axis as positive above X
not below.
The following method will work with screen values instead of "grid" values. The only difference to the excepted answer is the Y
values are inverted.
/** * Work out the angle from the x horizontal winding anti-clockwise * in screen space. * * The value returned from the following should be 315. * <pre> * x,y ------------- * | 1,1 * | \ * | \ * | 2,2 * </pre> * @param p1 * @param p2 * @return - a double from 0 to 360 */public static double angleOf(PointF p1, PointF p2) { // NOTE: Remember that most math has the Y axis as positive above the X. // However, for screens we have Y as positive below. For this reason, // the Y values are inverted to get the expected results. final double deltaY = (p1.y - p2.y); final double deltaX = (p2.x - p1.x); final double result = Math.toDegrees(Math.atan2(deltaY, deltaX)); return (result < 0) ? (360d + result) : result;}