bupt244

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;
}
 

你可能感兴趣的:(UP)