HDU 4998 Rotate(绕一点旋转坐标轴)

Rotate
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1402 Accepted Submission(s): 630
Special Judge

Problem Description
Noting is more interesting than rotation!

Your little sister likes to rotate things. To put it easier to analyze, your sister makes n rotations. In the i-th time, she makes everything in the plane rotate counter-clockwisely around a point ai by a radian of pi.

Now she promises that the total effect of her rotations is a single rotation around a point A by radian P (this means the sum of pi is not a multiplier of 2π).

Of course, you should be able to figure out what is A and P 😃.

Input
The first line contains an integer T, denoting the number of the test cases.

For each test case, the first line contains an integer n denoting the number of the rotations. Then n lines follows, each containing 3 real numbers x, y and p, which means rotating around point (x, y) counter-clockwisely by a radian of p.

We promise that the sum of all p’s is differed at least 0.1 from the nearest multiplier of 2π.

T<=100. 1<=n<=10. 0<=x, y<=100. 0<=p<=2π.

Output
For each test case, print 3 real numbers x, y, p, indicating that the overall rotation is around (x, y) counter-clockwisely by a radian of p. Note that you should print p where 0<=p<2π.

Your answer will be considered correct if and only if for x, y and p, the absolute error is no larger than 1e-5.

Sample Input
1
3
0 0 1
1 1 1
2 2 1

Sample Output
1.8088715944 0.1911284056 3.0000000000

题意

给你n个点的坐标和旋转角度,对坐标轴进行这n次操作,求某一点的坐标和旋转角度,让坐标轴等价为绕这一点旋转

思路

由于旋转的是坐标轴用一点来代替肯定不行,至少是两点组成的线段才行,所以我们取 ( 0 , 0 ) (0,0) (0,0) ( 1 , 1 ) (1,1) (1,1)所构成的线段来按照题目所给的n次进行旋转,旋转公式为
x ′ = ( x − x 0 ) ∗ c o s ( p ) − ( y − y 0 ) ∗ s i n ( p ) + x 0 x'=(x-x_0)*cos(p)-(y-y_0)*sin(p)+x_0 x=(xx0)cos(p)(yy0)sin(p)+x0
y ′ = ( x − x 0 ) ∗ s i n ( p ) + ( y − y 0 ) ∗ c o s ( p ) + y 0 y'=(x-x_0)*sin(p)+(y-y_0)*cos(p)+y_0 y=(xx0)sin(p)+(yy0)cos(p)+y0
( x , y ) (x,y) (x,y) ( x 0 , y 0 ) (x_0,y_0) (x0,y0)逆时针旋转 p p p度后的坐标 ( x ′ , y ′ ) (x',y') (x,y)
那么我们通过n次操作得到的两个点设为 ( x 0 , y 0 ) (x_0,y_0) (x0,y0) ( x 1 , y 1 ) (x_1,y_1) (x1,y1),原坐标为 ( 0 , 0 ) (0,0) (0,0) ( 1 , 1 ) (1,1) (1,1).
我们连接 ( x 0 , y 0 ) (x_0,y_0) (x0,y0) ( 0 , 0 ) (0,0) (0,0)做中垂线, ( x 1 , y 1 ) (x_1,y_1) (x1,y1) ( 1 , 1 ) (1,1) (1,1)做中垂线,这两条线的交点就是我们要找的旋转点,所以的到下列方程
{ y = − x 0 y 0 ( x − x 0 2 ) + y 0 2 y = − x 1 − 1 y 1 − 1 ( x − x 1 − 1 2 ) + y 1 − 1 2 \left\{\begin{matrix} y=-\frac{x_{0}}{y_{0}}(x-\frac{x_0}{2})+\frac{y_0}{2}\\ y=-\frac{x_{1}-1}{y_{1}-1}(x-\frac{x_1-1}{2})+\frac{y_1-1}{2} \end{matrix}\right. {y=y0x0(x2x0)+2y0y=y11x11(x2x11)+2y11
再联立方程即可得到坐标,下一个问题就是角度,我们怎么求得角度呢
我们可以这样想,每次旋转都可以看作由两个操作构成,一个绕原点旋转p度然后再平移到 ( x , y ) (x,y) (x,y)点,由于每次都可以看作绕原点旋转所以,总的旋转角度肯定是固定的(n个点的旋转角度之和),实际上我们要求解的也就只是最后我们所处的位置(在上面解决了)

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <math.h>
using namespace std;
const double PI=acos(-1);
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        double x0=0,y0=0;
        double x1=1,y1=1;
        double angle=0;
        for(int i=0;i<n;i++)
        {
            double x,y,p;
            scanf("%lf%lf%lf",&x,&y,&p);
            double x2=(x0-x)*cos(p)-(y0-y)*sin(p)+x;
            double y2=(x0-x)*sin(p)+(y0-y)*cos(p)+y;
            double x3=(x1-x)*cos(p)-(y1-y)*sin(p)+x;
            double y3=(x1-x)*sin(p)+(y1-y)*cos(p)+y;
            x0=x2;
            y0=y2;
            x1=x3;
            y1=y3;
            angle+=p;
        }
        angle=fmod(angle,2*PI);
        double k0=y0/x0;
        k0=-1/k0;
        double k1=(y1-1)/(x1-1);
        k1=-1/k1;
        x0/=2;
        y0/=2;
        x1=(x1+1)/2;
        y1=(y1+1)/2;
        double x=(k0*x0-k1*x1+y1-y0)/(k0-k1);
        double y=k0*(x-x0)+y0;
        printf("%.10lf %.10lf %.10lf\n",x,y,angle);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值