ZOJ-1018-Deformed wheel

实际做题中我们可能会遇到很多有关及计算几何的问题,其中有一类问题就是向量的旋转问题,下面我们来具体探讨一下有关旋转的问题。

首先我们先把问题简化一下,我们先研究一个点绕另一个点旋转一定角度的问题。已知A点坐标(x1,y1),B点坐标(x2,y2),我们需要求得A点绕着B点旋转θ度后的位置。

A点绕B点旋转θ角度后得到的点,问题是我们要如何才能得到A’ 点的坐标。(向逆时针方向旋转角度正,反之为负)研究一个点绕另一个点旋转的问题,我们可以先简化为一个点绕原点旋转的问题,这样比较方便我们的研究。之后我们可以将结论推广到一般的形式上。

令B是原点,我们先以A点向逆时针旋转为例,我们过A’ 做AB的垂线,交AB于C,过C做x轴的平行线交过A’ 做x轴的垂线于D。过点C做x轴的垂线交x轴于点E。

令A的坐标(x,y),A’ 坐标(x1,y1),B的坐标(0,0)。我们可以轻松的获取AB的长度,而且显而易见A’ B长度等于AB。假设我们已知θ角的大小那么我们可以很快求出BC和A’ C的长度。BC=A’ B x cosθ,A’ C=A’ B x sinθ。

因为∠A’ CB和∠DCE为直角(显然的结论),则∠A’ CD +∠DCB =∠ECD +∠DCB=90度。

则∠A’ CD=∠ECD,∠A’ DC=∠CEB=90度,因此可以推断⊿CA’ D ∽⊿CBE。由此可以退出的结论有:

BC/BE=A’ C/A’ D和BC/CE=A’ C/CD

当然了DC和A’ D都是未知量,需要我们求解,但是我们却可以通过求出C点坐标和E点坐标间接获得A’ C和CD的长度。我们应该利用相似的知识求解C点坐标。

C点横坐标等于:((|AB| x cosθ) / |AB|) * x = x*cosθ

C点纵坐标等于:((|AB| x cosθ) / |AB|) * y = y*cosθ

则CE和BE的的长度都可以确定。

我们可以通过相⊿CA’ D ∽⊿CBE得出:

AD = x * sinθ DC = y * sinθ

那么接下来很容易就可以得出:

x1 = xcosθ- y * sinθ y1 = ycosθ + x * sinθ

则A’ 的坐标为(xcosθ- y * sinθ, ycosθ + x * sinθ)

我们可以这样认为:对于任意点A(x,y),A非原点,绕原点旋转θ角后点的坐标为:(xcosθ- y * sinθ, ycosθ + x * sinθ)

接下来我们对这个结论进行一下简单的推广,对于任意两个不同的点A和B(对于求点绕另一个点旋转后的坐标时,A B重合显然没有太大意义),求A点绕B点旋转θ角度后的坐标,我们都可以将B点看做原点,对A和B进行平移变换,计算出的点坐标后,在其横纵坐标上分别加上原B点的横纵坐标,这个坐标就是A’ 的坐标。

推广结论:对于任意两个不同点A和B,A绕B旋转θ角度后的坐标为:

(Δxcosθ- Δy * sinθ+ xB, Δycosθ + Δx * sinθ+ yB )

注:xB、yB为B点坐标。

结论的进一步推广:对于任意非零向量AB(零向量研究意义不大),对于点C进行旋转,我们只需求出点A和B对于点C旋转一定角度的坐标即可求出旋转后的向量A’ B’ ,因为向量旋转后仍然是一条有向线段。同理,对于任意二维平面上的多边形旋转也是如此。

网上抄的代码,我也不懂,求解释

#include<cstdio>
#include<cmath>
#include<vector>
using namespace std;
typedef struct{
	double x,y;
}POINT;
int n;
const double pi=3.1415926;
//当前点的位置
POINT p[10],g;
//存储长度和斜率
vector<double> vl,vs;
//存储每条直线的起点和斜率.
vector<POINT> vp;

inline double dis(POINT p1,POINT p2)
{
	return sqrt( (p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y) );
}

inline double dot(POINT p1,POINT p2,POINT p3)
{
	return (p3.x-p2.x)*(p1.x-p2.x)+(p3.y-p2.y)*(p1.y-p2.y);
}

double theta(POINT p2,POINT p1)
{
	double dx=p2.x-p1.x,dy=p2.y-p1.y,ret;
	if(dx==0)
	{
	
		if(dy>0)
			return	pi/2;
		else
		    return 1.5*pi;
	}
	else
	{
		ret=atan(dy/dx);
		if(dx>0)
		{
			if(dy>=0)
				return ret;
			else
				return 2*pi+ret;
		}
		else
			return pi+ret;	
	}
}
int main()
{
	int T;
	//cur_v,cur_l:当前旋转点所在的顶点和线段
	int i,j,cur_v,cur_l,flag;
	//dthe:旋转角度;tthe:角度变量
	double length,slope,dx,A,B,C,b,dthe,tthe,len;
	POINT tp;

	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		//input:输入多边形的顶点
		for(i=0;i<n;i++)
			scanf("%lf%lf",&p[i].x,&p[i].y);
	    scanf("%lf%lf",&g.x,&g.y);

		vl.clear();
		vs.clear();
        while(1)
		{
			scanf("%lf%lf",&length,&slope);
			vl.push_back(length);
			vs.push_back(slope);
			if(slope==0)
				break;
		}
		//第一条线段的右端点
		scanf("%lf%lf",&tp.x,&tp.y);
		vp.clear();
		vp.push_back(tp);
		for(i=1;i<vs.size();i++)
		{
			dx=vl[i-1]/sqrt(1+vs[i-1]*vs[i-1]);
			tp.x=vp[i-1].x-dx;
			tp.y=vp[i-1].y-dx*vs[i-1];
			vp.push_back(tp);

		}
		for(i=0;i<vl.size();i++)
		{
			for(j=0;j<n;j++)
				if( fabs( vs[i] * ( p[j].x - vp[i].x ) + vp[i].y - p[j].y ) <= 1e-6 )
				{
					cur_l=i;
					cur_v=j;
					break;
				}
			if(j<n)
				break;
		}
    	//上面得到的信息是旋转点在第i坡上,是多边形的第j个顶点
		if(vl.size()==1)
		{
			if( g.x > p[cur_v].x )
				flag = 1;
			else if(g.x < p[cur_v].x)
				flag = -1;
			else
				break;
			while(1)
			{
		
				//找出以p[cur_v]为原点的偏移角度最大的点
				tthe=100;
				for(i=0;i<n;i++)
					if( i!=cur_v && tthe - flag*theta(p[i],p[cur_v]) > 1e-9)
					{
						tthe = flag*theta(p[i],p[cur_v]);
						j = i;
					}
				len = dis(p[j],p[cur_v]);
				tp.x = p[cur_v].x + flag*len;
				tp.y = p[cur_v].y;
				dthe = theta(tp,p[cur_v]) - theta(p[j],p[cur_v]);
			
				for(i=0;i<n;i++)
				{
					len=dis(p[cur_v],p[i]);
					tthe=dthe+theta(p[i],p[cur_v]);
					p[i].x=p[cur_v].x+len*cos(tthe);
					p[i].y=p[cur_v].y+len*sin(tthe);
				}
				
				len=dis(g,p[cur_v]);
				tthe=dthe+theta(g,p[cur_v]);
				g.x=p[cur_v].x+len*cos(tthe);
				g.y=p[cur_v].y+len*sin(tthe);
				
				cur_v = j;
				if(flag==1 && g.x <= p[cur_v].x)
					break;
                if(flag==-1 && g.x >= p[cur_v].x)
					break;
			}
		}
		else
		{
			while(1)
			{
					
				//找到下一个旋转点
				//找出以p[cur_v]为原点的偏移角度最大的点
				tthe=-100;
				for(i=0;i<n;i++)
					if(i!=cur_v && tthe - theta(p[i],p[cur_v]) < 1e-9)
					{
						tthe = theta(p[i],p[cur_v]);
						j = i;
					}
			
				len=dis(p[j],p[cur_v]);
				for( ; cur_l+1<vl.size() && dis(p[cur_v],vp[cur_l+1])<len ; )
					cur_l++;
				//A*x^2+B*x+C=0;
				b=vp[cur_l].y-vs[cur_l]*vp[cur_l].x;
				A=1+vs[cur_l]*vs[cur_l];
				B=vs[cur_l]*(b-p[cur_v].y)-p[cur_v].x;
				B*=2;
				C=p[cur_v].x*p[cur_v].x;
				C+=(b-p[cur_v].y)*(b-p[cur_v].y)-len*len;
				//取值小的那个,并把(-B-sqrt(B^2-4*A*C))/2/A=>2*C/(-B+sqrt(B^2-4*A*C))
				tp.x=2*C/(-B+sqrt(B*B-4*A*C));
				tp.y=vs[cur_l]*tp.x+b;
			
				//将每个点都按一定角度旋转
				dthe = theta(tp,p[cur_v]) - theta(p[j],p[cur_v]);
				for(i=0;i<n;i++)
				{
					len=dis(p[cur_v],p[i]);
					tthe=dthe+theta(p[i],p[cur_v]);
					p[i].x=p[cur_v].x+len*cos(tthe);
					p[i].y=p[cur_v].y+len*sin(tthe);
				}
				//
				//len=dg[cur_v];
				len=dis(g,p[cur_v]);
				tthe=dthe+theta(g,p[cur_v]);
				g.x=p[cur_v].x+len*cos(tthe);
				g.y=p[cur_v].y+len*sin(tthe);
				//判断是否还会旋转
               	if( g.x >= p[j].x )
					break;
				cur_v = j;
			}
		}
		printf("%.3lf %.3lf\n",g.x,g.y);
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值