Вычисление угла между линией, определяемой двумя точками
В настоящее время я разрабатываю простую 2D-игру для Android. У меня есть неподвижный объект, расположенный в центре экрана, и я пытаюсь заставить этот объект вращаться и указывать на область на экране, к которой прикасается пользователь. У меня есть постоянные координаты, которые представляют центр экрана, и я могу получить координаты точки, которую пользователь нажимает. Я использую формулу, изложенную в этом форуме: Как получить угол между двумя точками?
-
Он гласит: "Если вы хотите, чтобы угол между линией, определяемой этими двумя точками, и горизонтальной осью:
double angle = atan2(y2 - y1, x2 - x1) * 180 / PI;".
-
Я реализовал это, но я думаю, что факт, что я работаю в координатах экрана, вызывает просчет, поскольку Y-координата обращена. Я не уверен, что это правильный путь для этого, любые другие мысли или предложения оценены.
Ответы
Ответ 1
Предположения: x
- горизонтальная ось и увеличивается при движении слева направо.
y
- вертикальная ось и увеличивается снизу вверх. (touch_x, touch_y)
- это
выбранного пользователем. (center_x, center_y)
- точка в центре
экран. theta
измеряется против часовой стрелки от оси +x
. Тогда:
delta_x = touch_x - center_x
delta_y = touch_y - center_y
theta_radians = atan2(delta_y, delta_x)
Изменить: вы упомянули в комментарии, что y увеличивается сверху вниз. В этом
case,
delta_y = center_y - touch_y
Но было бы правильнее описать это как выражение (touch_x, touch_y)
в полярных координатах относительно (center_x, center_y)
. Как сказал ChrisF,
идея определения "угла между двумя точками" не определена.
Ответ 2
Мне нужна была аналогичная функциональность, поэтому после многократного вытягивания волос я придумал функцию ниже
/**
* 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);
}
Ответ 3
Несколько ответов здесь попытались объяснить проблему "экрана", где top left
- 0,0
, а bottom right
- (положительный) screen width, screen height
. Большинство сеток имеют ось Y
как положительную выше X
не ниже.
Следующий метод будет работать со значениями экрана вместо значений "сетки". Единственное отличие от полученного ответа - инвертировать значения Y
.
/**
* 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;
}
Ответ 4
Если вы считаете, что координата y обращена, просто отрицайте значение (значения). Имеет ли смысл смысл?
Ответ 5
"начало находится в верхнем левом углу экрана, а Y-координата увеличивается вниз, а X-координата увеличивается вправо, как обычно. Думаю, мой вопрос становится, мне нужно преобразовать координаты экрана перед декартовыми координатами, прежде чем применять приведенную выше формулу?"
Если вы вычисляли угол, используя декартовы координаты, и обе точки были в квадранте 1 (где x > 0 и y > 0), ситуация была бы идентична координатам пиксельных пикселей (кроме перевернутого-Y Если вы отрицаете Y, чтобы получить его правую сторону, он становится квадрантом 4...). Преобразование координат пиксельных пикселей в декартово не меняет угол.
Ответ 6
с pygame:
dy = p1.y - p2.y
dX = p2.x - p1.x
rads = atan2(dy,dx)
degs = degrees(rads)
if degs < 0 :
degs +=90
это работает для меня
Ответ 7
В Android я сделал это с помощью Kotlin:
private fun angleBetweenPoints(a: PointF, b: PointF): Double {
val deltaY = abs(b.y - a.y)
val deltaX = abs(b.x - a.x)
return Math.toDegrees(atan2(deltaY.toDouble(), deltaX.toDouble()))
}