Подтвердить что ты не робот

Вычисление угла между линией, определяемой двумя точками

В настоящее время я разрабатываю простую 2D-игру для Android. У меня есть неподвижный объект, расположенный в центре экрана, и я пытаюсь заставить этот объект вращаться и указывать на область на экране, к которой прикасается пользователь. У меня есть постоянные координаты, которые представляют центр экрана, и я могу получить координаты точки, которую пользователь нажимает. Я использую формулу, изложенную в этом форуме: Как получить угол между двумя точками?

  • Он гласит: "Если вы хотите, чтобы угол между линией, определяемой этими двумя точками, и горизонтальной осью:

    double angle = atan2(y2 - y1, x2 - x1) * 180 / PI;".
    
  • Я реализовал это, но я думаю, что факт, что я работаю в координатах экрана, вызывает просчет, поскольку Y-координата обращена. Я не уверен, что это правильный путь для этого, любые другие мысли или предложения оценены.

4b9b3361

Ответ 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()))
    }