2D单位向量的角度是多少?

48

给定单位向量 (0.5, 0.5),如何找到它的角度(方向)?

cos(x) + sin(y) 吗?


从斜率转换为角度,可以使用atan函数,因此您可以在向量中使用atan2。 - Dair
25
顺便提一下,那不是一个单位向量。一个单位向量的长度为1,而那个向量的长度为sqrt(2)/2。 - Benjamin Lindley
@BenjaminLindley 这完全正确,这使得所有答案都有点奇怪。永远不会有一个单位向量是 (0.5,0.5) - 最接近的大约是从 pi/2 弧度的 (0.707,0.707)。 - Benjamin R
3个回答

111

已知 y 和 x,与 x 轴的夹角可以表示为:

atan2(y, x) // note that Y is first

在 (0.5, 0.5) 坐标下的角度为:

弧度制:

In [2]: math.atan2(0.5, 0.5)
Out[2]: 0.7853981633974483

度数:

In [3]: math.atan2(0.5, 0.5)*180/math.pi
Out[3]: 45.0

17
#include <cmath>

double x = 0.5;
double y = 0.5;
double angleInRadians = std::atan2(y, x);
double angleInDegrees = (angleInRadians / M_PI) * 180.0;

11

已经有很好的答案了,不幸的是没有人解决OP想要计算方向的代码问题,因为这是一个全局角度。 让我来解决一下。

atan (在其他答案中提到)将给出±0..90°的角度。然后,您需要找出向量位于哪个象限,并相应地修改角度;并且不要忘记x或y等于零的特殊情况! 这是我使用的稍微修改过的代码:

#include <cmath>
#include <iostream>

using namespace std;

constexpr int radToDeg(float rad) { return rad*(180/M_PI); }

int vectorAngle(int x, int y) {
    if (x == 0) // special cases
        return (y > 0)? 90
            : (y == 0)? 0
            : 270;
    else if (y == 0) // special cases
        return (x >= 0)? 0
            : 180;
    int ret = radToDeg(atanf((float)y/x));
    if (x < 0 && y < 0) // quadrant Ⅲ
        ret = 180 + ret;
    else if (x < 0) // quadrant Ⅱ
        ret = 180 + ret; // it actually substracts
    else if (y < 0) // quadrant Ⅳ
        ret = 270 + (90 + ret); // it actually substracts
    return ret;
}

int main() {
    cout << vectorAngle(1,0) << endl
         << vectorAngle(1,1) << endl
         << vectorAngle(0,1) << endl
         << vectorAngle(-1,1) << endl
         << vectorAngle(-1,0) << endl
         << vectorAngle(-1,-1) << endl
         << vectorAngle(0,-1) << endl
         << vectorAngle(1,-1) << endl
         << endl;
}

$ g++ test2.cpp -o a -g3 -O0 && ./a
0
45
90
135
180
225
270
315

然而,在实际的代码中,如果你经常同时使用角度和弧度 (例如因为你正在获取一个带有角度的输入,然后C++函数使用弧度),我建议使用包装器来避免偶尔交换它们 (这在我的代码中确实发生过)。为了完整起见,以下是我为赛车游戏编写的相关代码片段,请随意使用 :)

#include <cmath>
#include <iostream>

using namespace std;

struct Point {
    int x, y;
    bool operator==(const Point& p) const {
        return p.x == x && p.y == y;
    }
    bool operator!=(const Point& p) const {
        return !(p == *this);
    }
    Point operator+(const Point& rhs) const {
        return {x + rhs.x, y + rhs.y};
    }
    Point operator-(const Point& rhs) const {
        return {x - rhs.x, y - rhs.y};
    }
    void operator+=(const Point& rhs) {
        x += rhs.x;
        y += rhs.y;
    }
    friend ostream& operator<<(ostream& os, const Point& p) {
        os << "x = " << p.x << ", y = " << p.y;
        return os;
    }
};

template<typename T>
struct NumWrapper {
    T val;
    friend ostream& operator<<(ostream& os, const NumWrapper& w) {
        os << w.val;
        return os;
    }
    friend istream& operator>>(istream& is, NumWrapper& w) {
        is >> w.val;
        return is;
    }
    NumWrapper operator-(const T rhs) const {
        return {val - rhs};
    }
    NumWrapper operator-(const NumWrapper rhs) const {
        return {val - rhs.val};
    }
    NumWrapper operator-() const {
        return {-val};
    }
    NumWrapper operator+(const T rhs) const {
        return {val + rhs};
    }
    NumWrapper operator+(const NumWrapper rhs) const {
        return {val + rhs.val};
    }
};
using Degree = NumWrapper<int>;
using Radian = NumWrapper<float>;

constexpr Radian degToRad(Degree degree) { return {degree.val*(M_PI/180)}; }
constexpr Radian degToRad(int degree)    { return {degree*(M_PI/180)}; }
constexpr Degree radToDeg(Radian rad)    { return {rad.val*(180/M_PI)}; }
constexpr Degree radToDeg(float rad)     { return {rad*(180/M_PI)}; }

Degree vectorAngle(const Point& vec) {
    if (vec.x == 0) // special cases
        return (vec.y > 0)? Degree{90}
            : (vec.y == 0)? Degree{0}
            : Degree{270};
    else if (vec.y == 0) // special cases
        return (vec.x >= 0)? Degree{0}
            : Degree{180};
    Degree ret = radToDeg(atanf((float)vec.y/vec.x));
    if (vec.x < 0 && vec.y < 0) // quadrant Ⅲ
        ret.val = 180 + ret.val;
    else if (vec.x < 0) // quadrant Ⅱ
        ret.val = 180 + ret.val; // it actually substracts
    else if (vec.y < 0) // quadrant Ⅳ
        ret.val = 270 + (90 + ret.val); // it actually substracts
    return ret;
}

int main() {
    cout << vectorAngle({1,0}) << endl
         << vectorAngle({1,1}) << endl
         << vectorAngle({0,1}) << endl
         << vectorAngle({-1,1}) << endl
         << vectorAngle({-1,0}) << endl
         << vectorAngle({-1,-1}) << endl
         << vectorAngle({0,-1}) << endl
         << vectorAngle({1,-1}) << endl
         << endl;
}

5
其他答案提到了atan2函数,它可以根据给定的x和y分量返回一个合适象限内的角度。 - Teivaz
@teivaz 哈哈,没错。嗯,至少我锻炼了我的三角函数技能,并发布了㎭和度数包装器 - 我想它们对于寻找这种答案的人仍然有用。 - Hi-Angel
对于第二象限和第三象限,它们是否相同?如果是这种情况,您可以通过 if(vec.x < 0) ret.val = 180 + ret.val 将两个条件合并为一个。 - NoxFly

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接