为了寻找等效旋转操作,我们任选两个点P0和Q0,分别绕这n个点旋转一定的角度后最终得到Pn和Qn
然后已知:P0和Pn共圆,Q0和Qn共圆。所以要找的等效旋转点就是这两个线段的垂直平分线交点O。
等效的角度的计算,可以利用已知的等腰三角形(这里有两个)△P0PnR,做一条垂线(三线合一的性质),再利用反三角函数计算半角,再乘二
还有一种特殊情况就是,如果答案比平角要大,我们计算的角度就不对了。
此时可以让P0逆时针旋转90°得到一个P1,然后将P1和Pn的坐标分别代入直线P0R的方程,如果异号,说明P1和Pn在直线两侧;同号说明同侧。
也就是异侧的话,就要将所求角度用2π减去它。
1 //#define LOCAL 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 #include <cmath> 6 using namespace std; 7 8 void Rote(double& a1, double& b1, double a2, double b2, double p) 9 { 10 double tempx = a1, tempy = b1; 11 tempx = cos(p)*(a1 - a2) + sin(p)*(b2 - b1) + a2; 12 tempy = sin(p)*(a1 - a2) + cos(p)*(b1 - b2) + b2; 13 a1 = tempx; 14 b1 = tempy; 15 } 16 17 double dis(double a1, double b1, double a2, double b2) 18 { 19 return sqrt((a1-a2)*(a1-a2) + (b1-b2)*(b1-b2)); 20 } 21 22 int main(void) 23 { 24 #ifdef LOCAL 25 freopen("Bin.txt", "r", stdin); 26 #endif 27 28 int T; 29 scanf("%d", &T); 30 while(T--) 31 { 32 int n; 33 scanf("%d", &n); 34 double P0x = 0.123, P0y = 0.312, Q0x = 1.589, Q0y = 1.455; 35 double Pnx = P0x, Pny = P0y, Qnx = Q0x, Qny = Q0y; 36 for(int i = 0; i < n; ++i) 37 { 38 double P1x, P1y, alpha; 39 scanf("%lf%lf%lf", &P1x, &P1y, &alpha); 40 Rote(Pnx, Pny, P1x, P1y, alpha); 41 Rote(Qnx, Qny, P1x, P1y, alpha); 42 } 43 double A1 = P0x - Pnx, B1 = P0y - Pny, C1 = (P0x*P0x + P0y*P0y - Pnx*Pnx - Pny*Pny) / 2; 44 double A2 = Q0x - Qnx, B2 = Q0y - Qny, C2 = (Q0x*Q0x + Q0y*Q0y - Qnx*Qnx - Qny*Qny) / 2; 45 double ansx = (C1*B2 - C2*B1) / (A1*B2 - A2*B1); 46 double ansy = (C1*A2 - C2*A1) / (B1*A2 - B2*A1); 47 48 double zx = (P0x + Pnx) / 2, zy = (P0y + Pny) / 2; 49 double ansa = acos(dis(zx,zy, ansx, ansy) / dis(P0x, P0y, ansx, ansy)) * 2; 50 51 double P1x = ansx - (P0y - ansy), P1y = ansy + (P0x - ansx); 52 if(((P0y-ansy)*(P1x-ansx)-(P0x-ansx)*(P1y-ansy)) * ((P0y-ansy)*(Pnx-ansx)-(P0x-ansx)*(Pny-ansy)) < 0) 53 ansa = 3.1415926536 * 2 - ansa; 54 55 printf("%.10lf %.10lf %.10lf\n", ansx, ansy, ansa); 56 } 57 return 0; 58 }