蒟蒻表示计算几何一WA就手足无措啊。。还要care一下精度问题。
因为最多旋转十次,直接取一个向量模拟,最后算旋转夹角就行了。注意这里面角度结果的范围是[0,2*pi),而acos的范围是[0,pi),所以最后要根据叉积判断夹角有木有超Pi。
然后旋转中心通过轨迹中垂线求解,我之前把这个和两条直线的交点弄混了。==
#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<stdlib.h>
#include<vector>
#include<string>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<queue>
#include <ctype.h>
using namespace std;
//hdu 4998
int T;
int n;
double pi=acos(-1.0);
const double eps=1e-11;
struct Point
{
double x;
double y;
Point(double x=0,double y=0):x(x),y(y) { }
};
typedef Point Vector;
const double esp=1e-10;
Vector Rotate(Vector A,double rad)
{
return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad));
}
Vector operator + (Vector A,Vector B)
{
return Vector(A.x+B.x,A.y+B.y);
}
Vector operator - (Vector A,Vector B)
{
return Vector(A.x-B.x,A.y-B.y);
}
Vector operator * (Vector A,double p)
{
return Vector(A.x*p,A.y*p);
}
double Cross(Vector A,Vector B)
{
return A.x*B.y-A.y*B.x;
}
Point GetLineIntersection(Point P,Vector v,Point Q,Vector w)
{
Vector u=P-Q;
double t=Cross(w,u)/Cross(v,w);
return P+v*t;
}
double Dot(Vector A,Vector B)
{
return A.x*B.x+A.y*B.y;
}
double Length(Vector A)
{
return sqrt(Dot(A,A));
}
Vector Normal(Vector A)
{
double L=Length(A);
return Vector(-A.y/L,A.x/L);
}
double Angle(Vector A, Vector B)
{
return acos(Dot(A,B)/Length(A)/Length(B));//acos返回的是0-pi的弧度,而题目中是0 to 2pi
}
Point rotcen[15];
double p[15];
Point st0;//初始直线位置
Point ed0;
Point st;//旋转最后的直线位置
Point ed;
void input()
{
scanf("%d",&n);
memset(p,0,sizeof(p));
for(int i=0;i<n;i++)
{
scanf("%lf %lf %lf",&rotcen[i].x,&rotcen[i].y,&p[i]);
}
// st0=Point(rotcen[0].x-1,rotcen[0].y-1);
// ed0=Point(rotcen[0].x+1,rotcen[0].y);//不能随手设个初值,要防止旋转点和初值为同一点
st0=Point(-1,-1);
ed0=Point(1,0);//随手设个初值也行。。
}
void run()
{
Point sttmp=st0;
Point edtmp=ed0;
for(int i=0;i<n;i++)
{
Vector tmp=sttmp-rotcen[i];//要转化成在原点旋转的情况
sttmp=Rotate(tmp,p[i])+rotcen[i];
tmp=edtmp-rotcen[i];
edtmp=Rotate(tmp,p[i])+rotcen[i];
// cout<<sttmp.x<<" "<<sttmp.y<<" "<<edtmp.x<<" "<<edtmp.y<<endl;
}
st=sttmp;
ed=edtmp;
//st0,st ed0,ed的连线的垂直平分线交点才是旋转中心,不是两条直线旋转的交点
Point P=Point(0.5*(st0.x+st.x),0.5*(st0.y+st.y));
Point Q=Point(0.5*(ed0.x+ed.x),0.5*(ed0.y+ed.y));
Vector v=Normal(st-st0);
Vector w=Normal(ed-ed0);
Point center=GetLineIntersection(P,v,Q,w);
//double ang=Angle(st-st0,ed-ed0);//应该是绕旋转中心的旋转角,不是两条直线的夹角
double ang=Angle(st-center,st0-center);
// cout<<Cross(st-center,st0-center) <<endl;
if(Cross(st-center,st0-center)> 0)//叉乘默认逆时针为正,>0则旋转的角度>pi
ang = 2 * pi - ang;
// Vector t3=st0-center,t4=st-center;//直接用几何的方法算也行
// double ang=atan2(t4.y,t4.x)-atan2(t3.y,t3.x);//new-old
// if(ang<eps)//用atan2相减算ang时,没有这个特判会WA
// {
// ang+=2*pi;
// }
printf("%.10lf %.10lf %.10lf\n",center.x,center.y,ang);
}
int main()
{
freopen("input.txt","r",stdin);
// freopen("data.txt","r",stdin);
//freopen("out1.txt","w",stdout);
scanf("%d",&T);
for(int i=0;i<T;i++)
{
input();
run();
}
return 0;
}