• 向量旋转专题


    二维向量旋转

    知识点参考:  http://www.cnblogs.com/woodfish1988/archive/2007/09/10/888439.html

    x1= x * cos(θ) - y * sin(θ)

    y1= x * sin(θ) + y *cos(θ)

     求平面上任意点 绕任意点p(x,y)旋转 角度 sita 后的坐标矩阵

    hdu 1700  Points on Cycle

     题意:已知圆上一点, 求另外两点, 使得三角形周长最大, 则该三角形为等边三角形, 直接将 一点 顺时和 逆时针 旋转120  得到另外两点, 即可。

    代码如下:

    using namespace std ;
    const double pi= acos(-1);
    #define arc(x) (x / 180 * pi)
    typedef long long LL ;
    const double EPS = 0.0005;
    struct Point {
        double x,y;
        Point(){}
        Point(double x, double y):x(x),y(y){}
        Point rot( double sita){
            return Point( x * cos(sita) - y*sin(sita) , x* sin(sita) + y * cos(sita)  );
        }
    };
    int main(){
        int t;
        scanf("%d",&t);
        Point p0, p1, p2;
        while(t--){
            scanf("%lf%lf",&p0.x,&p0.y);
            p1=p0.rot( arc(120.0) );
            p2=p0.rot( arc(-120.0) );
            if( p1.y - p2.y > EPS )
                swap(p1,p2);
            else if( (fabs(p1.y - p2.y) < EPS)  &&  (p1.x - p2.x > EPS) )
                swap(p1,p2);
            printf("%.3lf %.3lf %.3lf %.3lf
    ",p1.x, p1.y, p2.x, p2.y);
        }
        return 0;
    }
    View Code

     

    hdu 1033  Edge

    题目来源:  http://acm.hdu.edu.cn/showproblem.php?pid=1033

    分析:求点绕任意点(x,y)旋转角度90(-90)后的坐标。

    模板题

    double mat[3][3];
    // 绕任一点(x,y)旋转角度sita 其中 c = cos(sita)  s = sin(sita)
    void Get_mat(double c, double s, double x, double y){
        mat[0][0] = c; mat[0][1] = -s ; mat[0][2] = (1 - c) * x + s * y ;
        mat[1][0] = s; mat[1][1] = c ; mat[1][2] = (1 - c) * y - s * x;
        mat[2][0] = mat[2][1] = 0; mat[2][2] = 1;
    }

    代码如下:

    using namespace std ;
    const double pi= acos(-1.0);
    #define arc(x) (x / 180 * pi)
    const double EPS = 1e-8;
    const int Max_N = 35;
    double mat[3][3];
    // 绕过原点和(x,y,z)的轴,转 a 角度的 旋转矩阵,注意传的点向量为单位向量,a为弧度
    void Get_mat(double c, double s, double x, double y){
        mat[0][0] = c; mat[0][1] = -s ; mat[0][2] = (1 - c) * x + s * y ;
        mat[1][0] = s; mat[1][1] = c ; mat[1][2] = (1 - c) * y - s * x;
        mat[2][0] = mat[2][1] = 0; mat[2][2] = 1;
    }
    int main(){
       string s;
       int st[3],ed[3],tmp[3];
       while(cin>>s){
            st[0] = 300, st[1] = 420, st[2] = 1 ;
            ed[0] = 310, ed[1] = 420, ed[2] = 1 ;
            int len=s.length();
            printf("300 420 moveto
    310 420 lineto
    ");
            for(int i=0; i<len ;i++){
                if(s[i] == 'A') // 顺时针,其实代入的是逆时针
                    Get_mat(0, 1, ed[0],ed[1]);
                else // 逆时针,其实代入的是 顺时针
                    Get_mat(0, -1, ed[0],ed[1]);
                tmp[0] = mat[0][0]*st[0] + mat[0][1] * st[1] + mat[0][2] * st[2];
                tmp[1] = mat[1][0]*st[0] + mat[1][1] * st[1] + mat[1][2] * st[2];
                tmp[2] =1;
                for(int i=0; i<3; i++){
                    swap(st[i],ed[i]);
                    swap(tmp[i],ed[i]);
                }
                printf("%d %d lineto
    ",ed[0],ed[1]);
            }
            printf("stroke
    showpage
    ");
       }
        return 0;
    }
    View Code

    三维向量旋转。

    左手坐标系下,一点绕任意轴旋转θ角的右乘矩阵:

    其中C为cosθ,S为sinθ,A为单位化的旋转轴。

    推导过程 请 参照    http://blog.csdn.net/tan625747/article/details/5523728

    hdu 2898   旋转

    题目来源:     http://acm.hdu.edu.cn/showproblem.php?pid=2898

    求空间中一个点绕一穿过原点的轴线旋转一定角度后的坐标,沿着旋转轴往原点看旋转的角度为顺时针。

     沿着旋转轴往原点看旋转的角度为顺时针,模板

    double mat[3][3];
    // 绕过原点和(x,y,z)的轴,转 a 角度的 旋转矩阵,注意传的点向量为单位向量,a为弧度
    void Get_mat(double x,double y,double z, double a){
        double c=cos(a);
        double s=sin(a);
        double xy = x*y, xz = x*z, yz = y*z, xx = x*x, yy = y*y , zz = z*z ;
        mat[0][0] = xx + (1 - xx) * c; mat[0][1] = xy * (1-c) - z * s; mat[0][2] = xz * (1-c) + y * s;
        mat[1][0] = xy * (1 - c) + z * s; mat[1][1] = yy + (1 - yy) * c; mat[1][2] = yz * (1-c) -x * s ;
        mat[2][0] = xz * (1 - c) - y * s; mat[2][1] = yz * (1-c) + x * s; mat[2][2] = zz + (1 - zz) * c;
    }

     代码如下:

    using namespace std ;
    const double pi= acos(-1);
    #define arc(x) (x / 180 * pi)
    const double EPS = 1e-8;
    const int Max_N = 35;
    double mat[3][3];
    // 绕过原点和(x,y,z)的轴,转 a 角度的 旋转矩阵,注意传的点向量为单位向量,a为弧度
    void Get_mat(double x,double y,double z, double a){
        double c=cos(a);
        double s=sin(a);
        double xy = x*y, xz = x*z, yz = y*z, xx = x*x, yy = y*y , zz = z*z ;
        mat[0][0] = xx + (1 - xx) * c; mat[0][1] = xy * (1-c) - z * s; mat[0][2] = xz * (1-c) + y * s;
        mat[1][0] = xy * (1 - c) + z * s; mat[1][1] = yy + (1 - yy) * c; mat[1][2] = yz * (1-c) -x * s ;
        mat[2][0] = xz * (1 - c) - y * s; mat[2][1] = yz * (1-c) + x * s; mat[2][2] = zz + (1 - zz) * c;
    }
    int main(){
        double px[3];
        double py[3];
        double x,y,z;
        double a;
        while(scanf("%lf%lf%lf", &px[0], &px[1], &px[2]  ) != EOF){
            memset(py,0,sizeof(py));
            scanf("%lf%lf%lf%lf",&x,&y, &z, &a);
            double len = sqrt(x * x + y * y +z *z) ;
            Get_mat(x / len, y / len, z / len, a);
            for(int i=0; i<3; i++){
                for(int j=0; j<3; j++){
                    py[i] += mat[i][j]*px[j];
                }
            }
            printf("%.3lf %.3lf %.3lf
    ",py[0],py[1],py[2]);
    
        }
        return 0;
    }
    View Code

    hit   Cubic Rotation

    题目来源:     http://acm.hrbeu.edu.cn/index.php?act=problem&id=1006&cid=16

    The ACM/ICPC Asia Harbin Online First Round Contest 2010

    分析: 求 正方体 绕 任意轴 p1p2 向量, 旋转 sita 角度后 , 在 平面 xoy 平面上的 投影面积。 (旋转 + 凸包面积)。

    由于是 任意轴 ,故在 代入 旋转公式前, 先平移(-p1)向量, 再 代入旋转公式, 再 逆平移(p1);

    注意, 题中 案例 2 ,中的 275 应改成 270, 这题 做了 ,显然 却不能提交。

    代码如下:

    using namespace std ;
    const double pi= acos(-1.0);
    #define arc(x) (x / 180 * pi)
    const double EPS = 1e-8;
    double mat[3][3];
    // 绕过原点和(x,y,z )的轴,转a 角度的旋转矩阵,注意传入的点向量为单位向量, a 为弧度
    void Get_mat(double x, double y, double z, double a){
        double c = cos(a);
        double s = sin(a);
        double xy = x*y, xz = x*z, yz = y*z, xx = x*x, yy = y*y, zz = z*z;
        mat[0][0] = xx + (1-xx)* c; mat[0][1] = xy * (1 - c) - z* s; mat[0][2] = xz * (1 - c) + y * s;
        mat[1][0] = xy * (1 - c) + z * s; mat[1][1] = yy + (1 - yy) *c; mat[1][2] = yz * (1- c) - x * s;
        mat[2][0] = xz * (1 - c) - y * s; mat[2][1] = yz * (1 - c) + x * s; mat[2][2] = zz + (1 - zz) * c;
    }
    int len ;
    double dir[8][3] = { {0, 0 ,0}, {1, 0, 0}, {1, 0, 1}, {0, 0, 1},
                         {0, 1, 0}, {1, 1, 0}, {1, 1, 1}, {0, 1, 1}};
    struct Point{
        double x,y,z;
        Point(){}
        Point(double x, double y, double z):x(x),y(y),z(z){}
        Point operator + (Point p){
            return Point( x + p.x , y + p.y, z + p.z);
        }
        Point operator - (Point p){
            return Point( x - p.x , y - p.y, z - p.z);
        }
    };
    Point cub[10],p1,p2,tmp[10];
    // 求凸包以及凸包形成的面积
    double add(double a, double b){
        if(fabs(a+b) < EPS * (fabs(a) + fabs(b)) ) return 0;
        return a+b;
    }
    struct tubao{
        double x,y;
        tubao(){}
        tubao(double x, double y):x(x),y(y){}
        double operator ^(tubao p){
            return add(x*p.y ,-y*p.x );
        }
    };
    //p0p1 * p0p2 > 0 左转
    double xmult(tubao p1, tubao p2, tubao p0){
        return add( (p1.x-p0.x)*(p2.y-p0.y), -(p1.y-p0.y)*(p2.x-p0.x) );
    }
    tubao List[10];
    int top;
    tubao qs[10];
    bool operator < (tubao a, tubao b){
        if(a.y != b.y) return a.y < b.y;
        else return a.x < b.x;
    }
    double graham(int n){
        sort(List, List + n);
        double sum=0;
        if(n == 0 || n == 1) return 0;
        qs[0] = List[0];
        qs[1] = List[1];
        top =1;
        for(int i=2; i<n; i++){
            while(top>= 1 && xmult(qs[top], List[i] , qs[top - 1]) <= 0)
                top --;
            qs[++top] = List[i];
        }
        qs[++top] = List[n-2];
        int le = top;
        for(int i=n-3; i>= 0; i--){
            while(top >= le && xmult(qs[top], List[i], qs[top - 1]) <= 0)
                top--;
            qs[++top] = List[i];
        }
        for(int i=0; i<top ; i++)
            sum += qs[i] ^ qs[i+1];
        sum /= 2;
        return sum;
    }
    int main(){
        int t;
        scanf("%d",&t);
        while(t--){
            int i;
            double sita;
            double p[3];
            scanf("%d%lf%lf%lf",&len,&p[0],&p[1],&p[2]);
            scanf("%lf%lf%lf%lf%lf%lf%lf",&p1.x, &p1.y, &p1.z,&p2.x, &p2.y, &p2.z,&sita);
            for(i=0; i<8; i++){
                cub[i].x = p[0] + len*dir[i][0];
                cub[i].y = p[1] + len*dir[i][1];
                cub[i].z = p[2] + len*dir[i][2];
            }
            //先平移 ( -p1)
            p2 = p2 - p1;
            for(i = 0; i<8; i++)
                cub[i] = cub[i] - p1;
            // 处理后准备旋转
            double unit = sqrt(p2.x * p2.x + p2.y * p2.y + p2.z * p2.z);
            Get_mat(p2.x / unit, p2.y / unit , p2.z / unit, arc(sita));
            for(i=0; i<8 ;i++){
                tmp[i].x = mat[0][0]*cub[i].x + mat[0][1]*cub[i].y + mat[0][2] * cub[i].z;
                tmp[i].y = mat[1][0]*cub[i].x + mat[1][1]*cub[i].y + mat[1][2] * cub[i].z;
                tmp[i].z = mat[2][0]*cub[i].x + mat[2][1]*cub[i].y + mat[2][2] * cub[i].z;
            }
            // 反平移(p1)
            for(i = 0; i<8; i++)
                cub[i] = tmp[i] + p1;
            for(i=0; i<8 ; i++){
                List[i].x = cub[i].x;
                List[i].y = cub[i].y;
            }
            printf("%.2lf
    ", graham(8));
        }
        return 0;
    }

    2014年携程决赛   飞机的碎片

    题目来源:  http://acm.hdu.edu.cn/diy/contest_showproblem.php?cid=23086&pid=1002

    Problem Description

    一架飞机不幸在某海洋上失事,海面上漂浮着一架飞机的一些碎片……
    幸好有卫星把这些碎片拍下来了,可以大致让我们确定一块搜索的区域来确定失事飞机的位置。
    为了更好地进行搜救,节约成本,需要在海上划出一块周长尽可能小的区域进行巡逻式的搜救。但是由于技术问题,巡逻的区域只能是矩形。现给出这些碎片的相对位置,请告知这块巡逻区域的周长(请务必保留小数点后6位数字)
    由于雷达扫描到的碎片相对于广阔的海洋实在太小,可以用极小的点来代替它。

    Input

    输入包含多组测试用例,每组测试用例的第一行包含一个整数N(3≤N≤10 000),表示碎片在海洋里的数量,接下去N行中的每行都有两个整数Xi和Yi(0 ≤ Xi, Yi ≤ 10 000),表示碎片的坐标。每个碎片的坐标都不同,并且所有的碎片都不在同一直线上。

    Output

    每一个测试用例,输出一行包含一个实数,一个矩形区域的最小周长。注意矩形的边缘不需要与坐标轴平行。

    Sample Input

    3
    0 0
    1 0
    0 1
    

    Sample Output

    4.000000
    

    Source

    CodingTrip - 携程编程大赛 (决赛)

    分析:

    1: 最小包围盒。 题意是求把所有点包含在内的最小矩阵的周长。

    2:我们先求所有点构成的凸包, 最小矩阵一定过凸包的某一条边。 如果边 平行于 x轴, 取 最左边点和最右边点 和 y轴方向最远的点, 如果 边 平行于 y 轴, 取 最上和最下的点 和 x轴最远的点,  如果 边 不平行于 轴, 则 对 凸包进行旋转,(平面上绕任意点 进行的旋转矩阵) 使边 平行于 x 轴, 进行同样的处理。求最小值。

    代码如下:

    const double pi= acos(-1.0);
    #define arc(x) (x / 180 * pi)
    const double EPS = 1e-8;
    const int Max_N  = 10005;
    const double inf = 0xfffffff;
    // 求凸包以及凸包形成的面积
    double add(double a, double b){
        if(fabs(a+b) < EPS * (fabs(a) + fabs(b)) ) return 0;
        return a+b;
    }
    struct Point{
        double x,y;
        Point(){}
        Point(double x, double y):x(x),y(y){}
        double operator ^(Point p){
            return add(x*p.y ,-y*p.x );
        }
        double dist(Point p){
            return sqrt( add( (x- p.x)*(x - p.x) ,(y - p.y)*(y - p.y) ) ) ;
        }
    };
    //p0p1 * p0p2 > 0 左转
    double xmult(Point p1, Point p2, Point p0){
        return add( (p1.x-p0.x)*(p2.y-p0.y), -(p1.y-p0.y)*(p2.x-p0.x) );
    }
    Point List[Max_N];
    int top,n;
    Point qs[Max_N];
    Point tmp[Max_N];
    bool operator < (Point a, Point b){
        if(a.y != b.y) return a.y < b.y;
        else return a.x < b.x;
    }
    double graham(){ // qs[0] = qs[top] = 原点。
        sort(List, List + n);
        if(n == 0 || n == 1) return 0;
        qs[0] = List[0];
        qs[1] = List[1];
        top =1;
        for(int i=2; i<n; i++){
            while(top>= 1 && xmult(qs[top], List[i] , qs[top - 1]) <= 0)
                top --;
            qs[++top] = List[i];
        }
        qs[++top] = List[n-2];
        int le = top;
        for(int i=n-3; i>= 0; i--){
            while(top >= le && xmult(qs[top], List[i], qs[top - 1]) <= 0)
                top--;
            qs[++top] = List[i];
        }
    }
    // 平面上 绕 任意点 逆时针旋转 角度 sita(弧度) 矩阵
    double mat[3][3];
    void Get_mat(double x, double y , double sita){
        double c = cos(sita);
        double s = sin(sita);
        mat[0][0] = c; mat[0][1] = -s; mat[0][2] = (1 - c) * x + s * y ;
        mat[1][0] = s; mat[1][1] = c; mat[1][2] = (1 - c) * y - s * x;
        mat[2][0] =mat[2][1] = 0; mat[2][2] = 1;
     }
    int main(){
        while(scanf("%d",&n) != EOF){
            int i,k,j,h;
            double changy,kuanx;
            double Min = inf;
            for(i=0; i<n; i++)
                scanf("%lf%lf",&List[i].x, &List[i].y);
            graham();
            for(i=0; i<top; i++) // 遍历每一条边
            {
                if(qs[i].x == qs[i+1].x){
                    for(k=j=0; j<top; j++) // 最大的y
                        k = qs[k].y > qs[j].y ? k : j;
                    changy = qs[k].y - qs[0].y;
                    k=i;
                    for( j = 0; j<top ; j++ ) // 距离最大的x横距
                        k = fabs(qs[j].x-qs[i].x) > fabs(qs[k].x - qs[i].x) ? j : k;
                    kuanx = fabs( qs[k].x - qs[i].x ) ;
                    Min = min(2*(changy + kuanx), Min );
                    continue;
                }
                else if(qs[i].y == qs[i+1].y){
                    // 最小的x, 最大的x
                    for(h=k=j=0; j<top ; j++){
                        k = qs[k].x > qs[j].x ? k : j ;
                        h = qs[h].x < qs[j].x ? h : j ;
                    }
                    kuanx = qs[k].x - qs[h].x ;
                    //距离最大的y 纵距
                    for(k=j =0 ; j<top; j++)
                        k = fabs(qs[j].y-qs[i].y) > fabs(qs[k].y - qs[i].y) ? j : k;
                    changy = fabs( qs[k].y - qs[i].y ) ;
                    Min = min(2*(changy + kuanx), Min );
                    continue;
                }
                else {
                    double sita = -atan2 ( (qs[i+1].y - qs[i].y) , (qs[i+1].x -qs[i].x ) );
                   double sss=sita / pi * 180;
                    Get_mat(qs[i].x , qs[i].y , sita);
                    for(j=0; j<top; j++){
                        if(j != i){
                        tmp[j].x = mat[0][0] * qs[j].x + mat[0][1] * qs[j].y + mat[0][2];
                        tmp[j].y = mat[1][0] * qs[j].x + mat[1][1] * qs[j].y + mat[1][2];}
                        else {
                            tmp[j].x = qs[i].x;
                            tmp[j].y = qs[i].y;
                        }
                    }
                     // 最小的x, 最大的x
                    for(h=k=j=0; j<top ; j++){
                        k = tmp[k].x > tmp[j].x ? k : j ;
                        h = tmp[h].x < tmp[j].x ? h : j ;
                    }
                    kuanx = tmp[k].x - tmp[h].x ;
                    //距离最大的y 纵距
                    for(k=j =0 ; j<top; j++)
                        k = fabs(tmp[j].y-tmp[i].y) > fabs(tmp[k].y - tmp[i].y) ? j : k;
                    changy = fabs( tmp[k].y - tmp[i].y ) ;
                    Min = min(2*(changy + kuanx), Min );
                    continue;
                }
            }
            printf("%.6lf
    ", Min);
        }
        return 0;
    }
  • 相关阅读:
    java实现冒泡排序
    使用telnet测试指定端口的连通性
    聊聊Java中的异常及处理
    Java工具类——数学相关的类
    谈谈javaSE中的==和equals的联系与区别
    如何在Vim中更改颜色和主题
    配置类为什么要添加@Configuration注解呢?
    你知道Spring是怎么解析配置类的吗?
    读源码,我们可以从第一行读起
    Spring杂谈 | Spring中的AutowireCandidateResolver
  • 原文地址:https://www.cnblogs.com/zn505119020/p/3682458.html
Copyright © 2020-2023  润新知