UVa 634 - Polygon:判断点在任意多边形内

Modern graphic computer programs can, among other, even more stunning capabilities, fill a closed region. Though not all of them can protect the user from accidentally choosing to fill the background rather than the inner part. Besides being a channel hopper at home your boss' favourite hobby is colouring the pictures, you cannot protest long about adding this magnificent protection feature to his graphic program.


This means that your job is to write a program, which determines whether a point belong to a polygon, given the array of its vertices.


To make life a bit simpler you may assume that:

  • all edges of the polygon are vertical or horizontal segments
  • lengths of all the edges of the polygon are even integer numbers
  • co-ordinates of at least one vertex are odd integer numbers
  • both co-ordinates of any vortex cannot be divisible by 7 at the same time
  • the investigated point P has both co-ordinates being even integer numbers
  • the polygon has at most 1000 vertices
  • co-ordinates of the vertices lay in the range: -10000..10000.

Input 

Input data may consist of several data sets, each beginning with a number of polygon's vertices ( n ). Consecutive  n  lines contain co-ordinates of the vertices ( x  followed by y ). Then go the co-ordinates of investigated point P. Input data end when you find 0 the number of polygon's vertices.

Output 

For each polygon and each point P you should print one character (in separate lines):  T when P belongs to the polygon or  F  otherwise.

Sample Input 

4
1 1
1 3
3 3
3 1
2 2
12
1 1
1 9
3 9
3 5
5 5
5 9
7 9
7 1
5 1
5 3
3 3
3 1
4 2
0

Sample Output 

T
F


Miguel A. Revilla 
2000-01-10


//用之前分析写的射线法 、角度和法和 改进弧长法 判断点是否在任意多边形内的程序都AC了此题,对自己写的射线法精确度有了更大的信心!

//射线法

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<algorithm>
using namespace std;
#define maxn 10005
#define eps 1e-8
#define max(x,y) (x>y?x:y)
#define min(x,y) (x<y?x:y)

struct point 
{
	double x,y;
};
int n;
point p0,p[maxn]; 

int Fabs(double d)
{
	if(fabs(d)<eps)	return 0;
	else return d>0?1:-1;
}

double x_multi(point p1,point p2,point p3)  
{
	return (p2.x-p1.x)*(p3.y-p1.y)-(p3.x-p1.x)*(p2.y-p1.y);
}

bool Onsegment(point p1,point p2,point p3)  	
{
	double min_x=min(p1.x,p2.x);
	double min_y=min(p1.y,p2.y);
	double max_x=max(p1.x,p2.x);
	double max_y=max(p1.y,p2.y);
	if(p3.x>=min_x&&p3.x<=max_x&&p3.y>=min_y&&p3.y<=max_y)
		return true;
	return false;
}

bool Is_intersected(point p1,point p2,point p3,point p4)  
{
	double d1=x_multi(p1,p2,p3);
	double d2=x_multi(p1,p2,p4);
	double d3=x_multi(p3,p4,p1);
	double d4=x_multi(p3,p4,p2);
	if(d1*d2<0.0&&d3*d4<0.0)
		return true;
//	if(d1==0.0&&Onsegment(p1,p2,p3))  
	//	return true;
	if(d2==0.0&&Onsegment(p1,p2,p4))
		return true;
	if(d3==0.0&&Onsegment(p3,p4,p1))
		return true;
	if(d4==0.0&&Onsegment(p3,p4,p2))
		return true;
	return false;
}

double Dot(point p1,point p2,point p3)
{
	return (p2.x-p1.x)*(p3.x-p1.x)+(p2.y-p1.y)*(p3.y-p1.y);
}

int pointonsegment(point p1,point p2,point p3)
{
	return Fabs(x_multi(p1,p2,p3))==0&&Fabs(Dot(p1,p2,p3))<=0;
}

bool point_is_inside()  //射线法判读点是否在多边形内
{
	int i,num=0;
	point p1,p2,p3;
	p1.x=999999999.0,p1.y=p0.y;
	for(i=0;i<n;i++)
	{
 		if(p[i].y==p[(i+1)%n].y)	
		{
			if(pointonsegment(p0,p[i],p[(i+1)%n]))
		 		return true;
		}
		else 
		{
			p2=p[i],p3=p[(i+1)%n];
			if(p2.y>p3.y)
				swap(p2,p3);
			if(Is_intersected(p0,p1,p2,p3))
				num++;
		}
	} 
	return num%2==1;
}

int main()
{
	int i,j;
	while(scanf("%d",&n),n)
	{
		for(i=0;i<n;i++)
			scanf("%lf%lf",&p[i].x,&p[i].y);
		scanf("%lf%lf",&p0.x,&p0.y); 
		if(point_is_inside()) 
			puts("T");
		else
			puts("F"); 
	}
	return 0;
}

//角度和法

double x_multi(point p1,point p2,point p3)  
{
	return (p2.x-p1.x)*(p3.y-p1.y)-(p3.x-p1.x)*(p2.y-p1.y);
}

double Len_ab(point p1,point p2)
{
	return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
}

double Dot(point p1,point p2,point p3)
{
	return (p2.x-p1.x)*(p3.x-p1.x)+(p2.y-p1.y)*(p3.y-p1.y);
}

int pointonsegment(point p1,point p2,point p3)
{
	return Fabs(x_multi(p1,p2,p3))==0&&Fabs(Dot(p1,p2,p3))<=0;
}

bool point_is_inside()
{
	int i;
	double sum=0.0;
	for(i=0;i<n;i++)
	{
		if(p0==p[i]) //点在多边形端点上
			return true;
		if(p[i]==p[(i+1)%n]) //去重点
			continue;
		if(pointonsegment(p0,p[i],p[(i+1)%n]))  //点在多边形边上
			return true;
		double a=Len_ab(p0,p[i]);
		double b=Len_ab(p0,p[(i+1)%n]);
		double c=Len_ab(p[i],p[(i+1)%n]);
		sum+=Fabs(x_multi(p0,p[i],p[(i+1)%n]))*acos((a*a+b*b-c*c)/(2.0*a*b)); //计算角度和,叉积大于0则加上,小于0则减去
	}
	sum=fabs(sum);
	if(Fabs(sum-2.0*pi)==0)
		return true;
	return false;
}

//改进弧长法:

int get_tmp(point p1)
{
	return p1.x>=0?(p1.y>=0?0:3):(p1.y>=0?1:2);
}

bool point_is_inside()
{
	int tmp1,tmp2,sum=0,i;
	point p1;
	p1.x=p[0].x-p0.x,p1.y=p[0].y-p0.y;
	tmp1=get_tmp(p1);
	
	for(i=0;i<n;i++)
	{
		if(p[i]==p0)
			break;
		int t0=Fabs(x_multi(p0,p[i],p[(i+1)%n]));
		int t1=Fabs((p[i].x-p0.x)*(p[(i+1)%n].x-p0.x));
		int t2=Fabs((p[i].y-p0.y)*(p[(i+1)%n].y-p0.y));
		
		if(!t0&&t1<=0&&t2<=0)
			break;
		p1.x=p[(i+1)%n].x-p0.x,p1.y=p[(i+1)%n].y-p0.y;
		tmp2=get_tmp(p1);
		switch((tmp2-tmp1+4)%4)
		{
			case 1:{ sum++; break; }
			case 2:
			{
				if(t0>0) sum+=2;
				else sum-=2;
				break;
			}
			case 3: { sum--; break; }
		}
		tmp1=tmp2;
	}
	if(i<n||sum)
		return true;
	return false;
}



你可能感兴趣的:(struct,Integer,ini,input,character,each)