sgu-265. Wizards

题目大意:

空间直角坐标系中有 M(M<=100000) 个点,然后有一个操作集合,集合大小为 N(N<=1000) ,操作包括平移,关于原点放缩,还有绕向量旋转。要你求出所有点操作完后的坐标。
 
 
 

解题思路:

显然这需要把N个操作都变为一个矩阵或者什么别的东西,使得最后计算答案的时候只需要进行一次操作就行了。
具体的操作方法再次不赘述了,主要是点绕向量旋转是一个问题。
这里写图片描述
我们令向量为 t ,点为 p ,因为题目保证t是以原点为起点,然后我们只要求出 p 对于t的垂直向量 P 然后叉乘得出垂直向量 g ,然后将 g 调整成和 t 长度相同,然后最后的到得点 p gsin(α)+Pcos(α)+tmp

AC代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>


using namespace std;

const double PI=acos(-1);

struct Point
{
    double x,y,z;
    Point(){x=y=z=0;};

    Point(double x_,double y_,double z_)
    {x=x_,y=y_,z=z_;}

    double operator^(Point a1)
    {return x*a1.x+y*a1.y+z*a1.z;}

    Point operator-(Point a1)
    {return Point(x-a1.x,y-a1.y,z-a1.z);}

    Point operator+(Point a1)
    {return Point(x+a1.x,y+a1.y,z+a1.z);}

    Point operator*(Point a1)
    {return Point(y*a1.z-a1.y*z,z*a1.x-a1.z*x,x*a1.y-a1.x*y);}

    Point operator*(double a1)
    {return Point(x*a1,y*a1,z*a1);}

    void scanling(double a,double b,double c)
    {x*=a,y*=b,z*=c;}

    double Lenth()
    {return sqrt(x*x+y*y+z*z);}

    void rotate(Point a1,double X)
    {
        Point cnt=Point(x,y,z);
        Point tmp=a1*((cnt^a1)/(a1^a1));
        cnt=cnt-tmp;
        Point M=a1*cnt;
        if(M.Lenth()<=1e-10) return;
        M=M*(cnt.Lenth()/M.Lenth());
        x=cnt.x*cos(X)+M.x*sin(X)+tmp.x;
        y=cnt.y*cos(X)+M.y*sin(X)+tmp.y;
        z=cnt.z*cos(X)+M.z*sin(X)+tmp.z;
    }
};

void Readch(char &ch)
{
    for(ch=getchar();ch=='\n' || ch=='\r' || ch==' ';ch=getchar());
    return;
}

int main()
{
    char ch='\0';
    int N;
    scanf("%d",&N);
    struct Point P[4];
    P[1]=Point(1,0,0);P[2]=Point(0,1,0),P[3]=Point(0,0,1);
    for(int i=1;i<=N;i++)
    {
        Readch(ch);
        if(ch=='T')
        {
            double a,b,c;
            scanf("%lf%lf%lf",&a,&b,&c);
            P[0]=P[0]+Point(a,b,c);
        }
        else if(ch=='S')
        {
            double a,b,c;
            scanf("%lf%lf%lf",&a,&b,&c);
            for(int i=0;i<=3;i++) P[i].scanling(a,b,c);
        }
        else if(ch=='R')
        {
            double a,b,c,d;
            scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
            d=d/180*PI;
            for(int j=0;j<=3;j++)
                P[j].rotate(Point(a,b,c),d);
        }
    }
    int M;
    scanf("%d",&M);
    for(int i=1;i<=M;i++)
    {
        double a,b,c;
        scanf("%lf%lf%lf",&a,&b,&c);
        Point prt=Point(a,b,c);
        prt=P[1]*prt.x+P[2]*prt.y+P[3]*prt.z+P[0];
        printf("%lf %lf %lf\n",prt.x,prt.y,prt.z);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值