1.判断多边形是否合法
任两条边都不相交即合法,注意这里的相交是严格相交,顶点相交不算相交。
2.能看到哪些边
扫描线处理
#include<fstream>
#include<string.h>
#include<cmath>
using namespace std;
ifstream fin("fence4.in");
ofstream fout("fence4.out");
const int MAX = 202;
struct point
{
double x,y;
};
struct edge
{
point* v[2];
};
point watcher,*vert[MAX];
int n;
edge* fence[MAX];
bool isSight[MAX];
double times(double x1,double y1,double x2,double y2)
{//求叉积
return x1*y2-x2*y1;
}
void creatEdge()
{
for(int i=0; i<n-1; i++)
{
fence[i] = new edge();
fence[i]->v[0] = vert[i];
fence[i]->v[1] = vert[i+1];
}
fence[n-1] = new edge();
fence[n-1]->v[0] = vert[0];
fence[n-1]->v[1] = vert[n-1];
}
bool isCross(edge*a ,edge*b)
{
point*s = a->v[0];
if(times(a->v[1]->x - s->x,a->v[1]->y - s->y,b->v[0]->x - s->x,b->v[0]->y - s->y)
*times(a->v[1]->x - s->x,a->v[1]->y - s->y,b->v[1]->x - s->x,b->v[1]->y - s->y)>=0)
return false;
s = b->v[0];
if(times(b->v[1]->x - s->x,b->v[1]->y - s->y,a->v[0]->x - s->x,a->v[0]->y - s->y)
*times(b->v[1]->x - s->x,b->v[1]->y - s->y,a->v[1]->x - s->x,a->v[1]->y - s->y))
return false;
}
void checkCross()
{
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
if(i==j)continue;
if(!isCross(fence[i],fence[j]))continue;
fout<<"NOFENCE"<<endl;
exit(0);
}
}
/*
给定一个射线OA(向量OA与x轴正方向的夹角),算法将记录下边集中与射线OA有交点且交点离O点最近的线段。
*/
void checkLine(double angle)
{
double min_k = 1E16;
long firstCrah = -1;
double lx = cos(angle);
double ly = sin(angle);
double k1,t;
for(int i=0;i<n;i++)
{
double& x = watcher.x;
double& y = watcher.y;
double& x1 = fence[i]->v[0]->x;
double& y1 = fence[i]->v[0]->y;
double& x2 = fence[i]->v[1]->x;
double& y2 = fence[i]->v[1]->y;
if(times(x1-x,y1-y,lx,ly)*times(x2-x,y2-y,lx,ly)>=0)//不相交,继续
continue;
lx = cos(angle);
ly = sin(angle);
if(x2-x1==0)
{
k1 = (x1-x)/lx;
}
else
{
t=(y2-y1)/(x2-x1);
k1 = (t*(x1-x)+y-y1)/(t*lx-ly);
}
if(k1>0 && k1<min_k)
{
min_k = k1;
firstCrah = i;
}
}
if(firstCrah != -1)
{
isSight[firstCrah] = true;
}
}
/*
枚举观察点到每个顶点的向量,然后把其与x轴的夹角(+-)1E-8 rad 后检查沿该方向能看到的fence
*/
void canSight()
{
memset(isSight,0,sizeof(isSight));
double angle;
for(int i=0;i<n;i++)
{
angle = atan2(vert[i]->y - watcher.y,vert[i]->x - watcher.x);
checkLine(angle+1E-8);
checkLine(angle-1E-8);
}
}
int main()
{
fin>>n;
fin>>watcher.x>>watcher.y;
for(int i=0;i<n;i++)
{
vert[i] = new point();
fin>>vert[i]->x;
fin>>vert[i]->y;
}
creatEdge();
checkCross();
canSight();
int conter = 0;
for(int i=0;i<n;i++)
conter+=isSight[i];
fout<<conter<<endl;
for(int i=0;i<n-2;i++)
if(isSight[i])
fout<<fence[i]->v[0]->x<<" "
<<fence[i]->v[0]->y<<" "
<<fence[i]->v[1]->x<<" "
<<fence[i]->v[1]->y<<endl;
if(isSight[n-1])
fout<<fence[n-1]->v[0]->x<<" "
<<fence[n-1]->v[0]->y<<" "
<<fence[n-1]->v[1]->x<<" "
<<fence[n-1]->v[1]->y<<endl;
if(isSight[n-2])
fout<<fence[n-2]->v[0]->x<<" "
<<fence[n-2]->v[0]->y<<" "
<<fence[n-2]->v[1]->x<<" "
<<fence[n-2]->v[1]->y<<endl;
return 0;
}