Что не так с этой функцией XNA RotateVector2? - PullRequest
0 голосов
/ 21 сентября 2010

Я знаю, что это, вероятно, очень простой вопрос, но я не могу понять это. Прежде всего, я хочу указать, что я просматривал Google и SO в течение получаса или около того, не найдя ответа на свой вопрос (да, я серьезно).

По сути, я хочу повернуть Vector2 вокруг точки (которая, в моем случае, всегда является вектором (0, 0)). Итак, я попытался сделать функцию, чтобы сделать это с параметрами, являющимися точкой поворота и углом (в градусах), на который можно повернуть.

Вот быстрый рисунок, показывающий, чего я пытаюсь достичь:

alt text

Я хочу взять V1 (красный вектор), повернуть его на угол A (синий), чтобы получить новый вектор (V2, зеленый). В этом примере я использовал один из самых простых случаев: V1 на оси и угол 90 градусов, но я хочу, чтобы функция обрабатывала также больше случаев " сложных ".

Итак, вот моя функция:

public static Vector2 RotateVector2(Vector2 point, float degrees)
{
    return Vector2.Transform(point, 
    Matrix.CreateRotationZ(MathHelper.ToRadians(degrees)));
}

Итак, что я делаю не так? Когда я запускаю код и вызываю эту функцию с вектором (0, -1) и углом 90 градусов, я получаю вектор (1, 4.371139E-08) ...

Кроме того, что, если я хочу принять точку для поворота в качестве параметра тоже? Так что вращение не всегда происходит вокруг (0, 0) ...

Ответы [ 2 ]

6 голосов
/ 21 сентября 2010

Ответ Криса Шмича относительно точности с плавающей запятой и использования радиан является правильным. Я предлагаю альтернативную реализацию для RotateVector2 и отвечу на вторую часть вашего вопроса.

Построение матрицы вращения 4x4 для поворота вектора вызовет много ненужных операций. Матричное преобразование фактически выполняет следующее, но использует много избыточной математики:

    public static Vector2 RotateVector2(Vector2 point, float radians)
    {
        float cosRadians = (float)Math.Cos(radians);
        float sinRadians = (float)Math.Sin(radians);

        return new Vector2(
            point.X * cosRadians - point.Y * sinRadians,
            point.X * sinRadians + point.Y * cosRadians);
    }

Если вы хотите повернуть вокруг произвольной точки, вам сначала нужно перевести свое пространство так, чтобы точка, вокруг которой вращается, была началом координат, выполните вращение, а затем переверните перевод.

    public static Vector2 RotateVector2(Vector2 point, float radians, Vector2 pivot)
    {
        float cosRadians = (float)Math.Cos(radians);
        float sinRadians = (float)Math.Sin(radians);

        Vector2 translatedPoint = new Vector2();
        translatedPoint.X = point.X - pivot.X;
        translatedPoint.Y = point.Y - pivot.Y;

        Vector2 rotatedPoint = new Vector2();
        rotatedPoint.X = translatedPoint.X * cosRadians - translatedPoint.Y * sinRadians + pivot.X;
        rotatedPoint.Y = translatedPoint.X * sinRadians + translatedPoint.Y * cosRadians + pivot.Y;

        return rotatedPoint;
    }

Обратите внимание, что векторная арифметика была встроена для максимальной скорости.

3 голосов
/ 21 сентября 2010

Итак, что я делаю не так?Когда я запускаю код и вызываю эту функцию с вектором (0, -1) и углом 90 градусов, я получаю вектор (1, 4.371139E-08) ...

Ваш кодправильно, это просто проблема представления с плавающей запятой.4.371139E-08 по существу равен нулю (это 0,0000000431139), но преобразование не дало значения, которое было точно нулевым.Это распространенная проблема с плавающей запятой, о которой вы должны знать. Этот ответ SO имеет несколько дополнительных полезных моментов относительно числа с плавающей запятой.

Также, если возможно, вы должны придерживаться радиан, а не использовать градусы.Это, вероятно, вносит больше ошибок в ваши вычисления.

...