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 byy). 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): Twhen 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;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章