source: http://acm.bupt.edu.cn/onlinejudge/newoj/showProblem/show_problem.php?problem_id=244
title: A Letter to Programmers
/*
坐标变换的公式+矩阵快速幂
*/
#include <iostream>
#include <cmath>
using namespace std;
const int N = 105;
const double pi = acos(-1.0);
const double eps = 1e-4;
struct point{
double x, y, z;
point(double _x=0, double _y=0, double _z=0):x(_x), y(_y), z(_z){};
void read(){
scanf("%lf%lf%lf", &x, &y, &z);
}
};
//三维点的变换矩阵,点做变换的时候是乘在矩阵的右边的,所以,后来的变换矩阵应该乘在
//原有矩阵的左边。
struct mat{
static const int N = 4;
double v[N][N];
int n;
mat(){ n = N; }
void setv(double _v[N][N]){
int i, j;
for(i = 0; i < N; i++){
for(j = 0; j < N; j++){
v[i][j] = _v[i][j];
}
}
}
//点绕轴(0,0,0)->(x,y,z)旋转(旋转方向为从 点(x,y,z)往(0,0,0))
//看是逆时针方向.如果所绕的轴的一个端点不在原点,则可以移到端
//点再移回来
void rotate(double x, double y, double z, double ang){
double cosa = cos(ang), sina = sin(ang), len;
len = sqrt(x*x+y*y+z*z);
x/=len; y/=len; z/=len;
double a[N][N] = {
cosa+(1-cosa)*x*x, (1-cosa)*x*y-z*sina, (1-cosa)*x*z+y*sina, 0,
(1-cosa)*x*y+z*sina, cosa+(1-cosa)*y*y, (1-cosa)*y*z-x*sina, 0,
(1-cosa)*x*z-y*sina, (1-cosa)*y*z+x*sina, cosa+(1-cosa)*z*z, 0,
0, 0, 0, 1
};
setv(a);
}
//移动矩阵,点(x0,y0,z0)变为(x0+x,y0+y,z0+z)
void translate(double x, double y, double z){
double a[N][N] = {
1, 0, 0, x,
0, 1, 0, y,
0, 0, 1, z,
0, 0, 0, 1
};
setv(a);
}
//伸缩矩阵,点(x0,y0,z0)变为(x0*x,y0*y,z0*y)
void scale(double x, double y, double z){
double a[N][N] = {
x, 0, 0, 0,
0, y, 0, 0,
0, 0, z, 0,
0, 0, 0, 1
};
setv(a);
}
//对点st应用该矩阵
point change(point st){
double ds[N] = {st.x, st.y, st.z, 1}, ans[N-1];
int i, j;
//点做矩阵变换的时候是点是乘在矩阵的右边的
for(i = 0; i < N-1; i++){
ans[i] = 0;
for(j = 0; j < N; j++){
ans[i] += v[i][j] * ds[j];
}
}
return point(ans[0], ans[1], ans[2]);
}
//矩阵乘法
mat operator*(mat tm){
mat ans;
int i, j, k;
for(i = 0; i < n; i++){
for(j = 0; j < n; j++){
ans.v[i][j] = 0;
for(k = 0; k < n; k++){
ans.v[i][j] += v[i][k] * tm.v[k][j];
}
}
}
return ans;
}
//矩阵幂
mat operator^(int k){
mat ans, org = *this;
ans.scale(1., 1., 1.); //初始化为单位矩阵
for(; k; k >>= 1, org = org * org){
if(k&1){
ans = ans * org;
// ans = org * ans;
}
}
return ans;
}
};
char ts[N]; //ts[i]为'm'表示矩阵,为'r'表示重复
mat ms[N];
int ks[N];
int main() {
// freopen("in.txt", "r", stdin);
int n, top, i, k;
char op[20];
double tx, ty, tz, d;
mat m;
point tp;
while(~scanf("%d", &n) && n > 0){
top=-1;
while(true){
scanf("%s", op);
if(strcmp(op, "translate") == 0){
scanf("%lf%lf%lf", &tx, &ty, &tz);
ms[++top].translate(tx, ty, tz);
ts[top] = 'm';
}else if(strcmp(op, "scale") == 0){
scanf("%lf%lf%lf", &tx, &ty, &tz);
ms[++top].scale(tx, ty, tz);
ts[top] = 'm';
}else if(strcmp(op, "rotate") == 0){
scanf("%lf%lf%lf%lf", &tx, &ty, &tz, &d);
d = (d * pi) / 180.0;
ms[++top].rotate(tx, ty, tz, d);
ts[top] = 'm';
}else if(strcmp(op, "repeat") == 0){
scanf("%d", &k);
ks[++top] = k;
ts[top] = 'r';
}else if(strcmp(op, "end") == 0){
m.scale(1, 1, 1);
while(top >= 0 && ts[top] != 'r'){
m = m * ms[top];
top--;
}
if(top < 0) break;
m = m ^ ks[top];
ms[top] = m;
ts[top] = 'm';
}
}
for(i = 0; i < n; i++){
tp.read();
tp = m.change(tp);
printf("%.2f %.2f %.2f\n", tp.x + eps, tp.y + eps, tp.z + eps);
}
printf("\n");
}
return 0;
}