下午在vj的训练赛考到了又裸又板的三维向量旋转,赛时为了方便直接封了一个板子出来,现进行一个板子的贴:

题目链接:Gym-103145J Transform

题目翻译

  给定三维空间中的两点 ((A, B, C)) 和 ((x, y, z))。设 (L) 为通过点 ((A, B, C)) 和原点 ((0, 0, 0)) 的直线。将点 ((x, y, z)) 绕着直线 (L) 旋转 (r) 度和 (-r) 度,会得到两个点 (P) 和 (Q)。如果点 (P) 的 (z) 坐标大于 (Q) 的 (z) 坐标,则输出点 (P);否则,输出点 (Q)。保证解是唯一的。


罗德里格公式简介

罗德里格旋转公式(Rodrigues' rotation formula)是一种用于描述一个向量绕着固定轴旋转的方法。在三维空间中,它可以用来计算一个向量绕某个轴旋转一定角度后的新坐标。该公式在计算机图形学、物理学和工程学中有广泛应用。GPT

假设有一个向量 (\mathbf{v}),它绕一个单位向量 (\mathbf{k}) 旋转一个角度 (\theta) 后得到的新向量 (\mathbf{v}')。罗德里格旋转公式如下:

公式描述

罗德里格旋转公式用于计算一个向量绕固定轴旋转后的新向量。假设有一个向量 (\mathbf{v}),它绕一个单位向量 (\mathbf{k}) 旋转一个角度 (\theta) 后得到的新向量 (\mathbf{v}')。罗德里格旋转公式如下:

$$\mathbf{v}' = \mathbf{v} \cos \theta + (\mathbf{k} \times \mathbf{v}) \sin \theta + \mathbf{k} (\mathbf{k} \cdot \mathbf{v}) (1 - \cos \theta)$$

其中:

  • (\mathbf{v}) 是要旋转的向量。
  • (\mathbf{k}) 是旋转轴的单位向量。
  • (\theta) 是旋转角度。
  • (\mathbf{k} \times \mathbf{v}) 表示 (\mathbf{k}) 和 (\mathbf{v}) 的叉积。
  • (\mathbf{k} \cdot \mathbf{v}) 表示 (\mathbf{k}) 和 (\mathbf{v}) 的点积。

代码

模板部分

class Vector
{

public:
    double x, y, z;
    const double pi = acos(-1.0);

    double dot(const Vector& A, const Vector& B)
    {
        return A.x * B.x + A.y * B.y + A.z * B.z;
    }

    Vector cross(const Vector& A, const Vector& B)
    {
        return Vector(A.y * B.z - A.z * B.y, A.z * B.x - A.x * B.z, A.x * B.y - A.y * B.x);
    }

    Vector to_unit(const Vector& A)
    {
        double len = sqrt(dot(A, A));
        return Vector(A / len);
    }

    Vector rotate(const Vector& Uni, const Vector& A, double rad)
    {
        return A * cos(rad) + Uni * dot(Uni, A) * (1 - cos(rad)) + cross(Uni, A) * sin(rad);
    }

    double rad_to_deg(double rad)
    {
        return rad * 180 / pi;
    }

    double deg_to_rad(double deg)
    {
        return deg * pi / 180;
    }

    Vector(double x = 0, double y = 0, double z = 0) : x(x), y(y), z(z) {}

    Vector operator+(const Vector& B) const
    {
        return Vector(x + B.x, y + B.y, z + B.z);
    }

    Vector operator-(const Vector& B) const
    {
        return Vector(x - B.x, y - B.y, z - B.z);
    }

    Vector operator*(double p) const
    {
        return Vector(x * p, y * p, z * p);
    }

    Vector operator/(double p) const
    {
        return Vector(x / p, y / p, z / p);
    }

    bool operator<(const Vector& B) const
    {
        if (x == B.x)
        {
            if (y == B.y)
                return z < B.z;
            return y < B.y;
        }
        return x < B.x;
    }

};  

完整代码

#include<bits/stdc++.h>
#include<unordered_map>

using namespace std;

#define int long long
#define endl '\n'
#define ULL unsigned long long
#define xx first
#define yy second
#define PII pair

const int MAXN = 1e6 + 10;
const int MOD = 998244353;
const int mod = 1e9 + 7;
const double eps = 1e-8;
int _x[] = { 1,-1,0,0 };
int _y[] = { 0,0,1,-1 };
int arr[MAXN];

class Vector
{

public:
    double x, y, z;
    const double pi = acos(-1.0);

    double dot(const Vector& A, const Vector& B)
    {
        return A.x * B.x + A.y * B.y + A.z * B.z;
    }

    Vector cross(const Vector& A, const Vector& B)
    {
        return Vector(A.y * B.z - A.z * B.y, A.z * B.x - A.x * B.z, A.x * B.y - A.y * B.x);
    }

    Vector to_unit(const Vector& A)
    {
        double len = sqrt(dot(A, A));
        return Vector(A / len);
    }

    Vector rotate(const Vector& Uni, const Vector& A, double rad)
    {
        return A * cos(rad) + Uni * dot(Uni, A) * (1 - cos(rad)) + cross(Uni, A) * sin(rad);
    }

    double rad_to_deg(double rad)
    {
        return rad * 180 / pi;
    }

    double deg_to_rad(double deg)
    {
        return deg * pi / 180;
    }

    Vector(double x = 0, double y = 0, double z = 0) : x(x), y(y), z(z) {}

    Vector operator+(const Vector& B) const
    {
        return Vector(x + B.x, y + B.y, z + B.z);
    }

    Vector operator-(const Vector& B) const
    {
        return Vector(x - B.x, y - B.y, z - B.z);
    }

    Vector operator*(double p) const
    {
        return Vector(x * p, y * p, z * p);
    }

    Vector operator/(double p) const
    {
        return Vector(x / p, y / p, z / p);
    }

    bool operator<(const Vector& B) const
    {
        if (x == B.x)
        {
            if (y == B.y)
                return z < B.z;
            return y < B.y;
        }
        return x < B.x;
    }

};


signed main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin >> t;
    while (t--)
    {
        double a, b, c, x, y, z, r;
        cin >> a >> b >> c >> x >> y >> z >> r;
        Vector A(a, b, c), B(x, y, z);
        Vector Uni = Vector().to_unit(A);
        Vector End1 = Vector().rotate(Uni, B, Vector().deg_to_rad(r));
        Vector End2 = Vector().rotate(Uni, B, -Vector().deg_to_rad(r));
        Vector Ans = End1.z > End2.z ? End1 : End2;
        cout << fixed << setprecision(9) << Ans.x << " " << Ans.y << " " << Ans.z << endl;

    }


    return 0;
}  
···