您的位置:首页 > 其它

Inheritance - SGU 129(线段与多边形相交的长度)

2015-09-25 18:56 483 查看
题目大意:给一个凸多边形(点不是按顺序给的),然后计算给出的线段在这个凸多边形里面的长度,如果在边界不计算。

分析:WA2..WA3...WA4..WA11...WA的无话可说,总之细节一定考虑清楚,重合的时候一定是0

代码如下:

=========================================================================================================

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<iostream>
using namespace std;

const int MAXN = 1007;
const double EPS = 1e-14;
const double FarX = 4e4+7;

int Sign(double x)
{
if(x > EPS)return 1;
if(fabs(x) < EPS)return 0;
return -1;
}
struct point
{
double x, y;
point(double x=0, double y=0):x(x),y(y){}
point operator - (const point &t)const{
return point(x-t.x, y-t.y);
}
bool operator == (const point &t)const{
return Sign(x-t.x) ==0 && Sign(y-t.y) == 0;
}
double operator ^(const point &t)const{
return x*t.y - y*t.x;
}
double operator *(const point &t)const{
return x*t.x + y*t.y;
}
};
double Dist(point t1, point t2)
{
return sqrt((t1-t2)*(t1-t2));
}
struct segment
{
point S, E;
double a, b, c;///ax + by = c;

segment(point S=0, point E=0):S(S), E(E){
a = S.y - E.y;
b = E.x - S.x;
c = E.x*S.y - S.x*E.y;
}
int  Inter(const segment &tmp)const{
int t1 = Sign((S-E)^(tmp.S-E));
int t2 = Sign((S-E)^(tmp.E-E));

if(t1 == 0 && t2 == 0)
return -1;

if(t1*t2 == -1)
return 1;
if(abs(t1+t2) == 1)///如果完全相交或者有一点相交,不考虑重合
return 2;
return false;
}
point crossNode(const segment &tmp)const
{///两条线段的交点
point result;
result.x = (c*tmp.b-tmp.c*b) / (a*tmp.b-tmp.a*b);
result.y = (c*tmp.a-tmp.c*a) / (b*tmp.a-tmp.b*a);

return result;
}
bool OnSeg(const point &p)
{///判断点是否在线段上
if(Sign((S-E)^(p-E)) == 0)
if(Sign((p.x-S.x)*(p.x-E.x)) <= 0)
if(Sign((p.y-S.y)*(p.y-E.y)) <= 0)
return true;
return false;
}
};
struct Polygon
{
int N;///有N个点
point vertex[MAXN];

int Point_In_Poly(const point &p)
{///点在多边形里面1,还是外面-1,还是边上 0
segment ray(p, point(FarX, p.y));
int cnt = 0;

for(int i=0; i<N; i++)
{
segment L(vertex[i], vertex[i+1]);

if(L.OnSeg(p))
return 0;

if(ray.OnSeg(L.S))
{
if(L.E.y-L.S.y > EPS)
cnt ++;
}
else if(ray.OnSeg(L.E))
{
if(L.S.y-L.E.y > EPS)
cnt ++;
}
else if(L.Inter(ray)==1 && ray.Inter(L)==1)
cnt++;
}

if(cnt % 2)
return 1;
return -1;
}
double Seg_In_Poly(const segment &L1)
{///线段与多边形相交的长度,先求出线段与多边形有几个交点
point p[10];
int k=0;

for(int i=0; i<N; i++)
{
segment L2(vertex[i], vertex[i+1]);

if(L1.Inter(L2) == -1 && L2.Inter(L1) == -1)
return 0;

if(k<2 && L1.Inter(L2) && L2.Inter(L1))
{
point t = L1.crossNode(L2);
if(!k || !(p[0] == t) )
p[k++] = t;
}
}

double len=0;

if(k == 2)
{///有两个不同的交点
len = Dist(p[0], p[1]);
}
else if(k == 1)
{///有一个交点,判断哪个端点在多边形内
if(Point_In_Poly(L1.S) == 1)
len = Dist(p[0], L1.S);
else if(Point_In_Poly(L1.E) == 1)
len = Dist(p[0], L1.E);
}
else if(Point_In_Poly(L1.S) == 1)
{///没有交点的时候,判断线段是否在多边形内
len = Dist(L1.S, L1.E);
}

return len;
}
};
Polygon poly;

bool cmp(point t1, point t2)
{
return Sign((t2-poly.vertex[0])^(t1-poly.vertex[0])) < 0;
}

int main()
{
int i, M, ki=0;

scanf("%d", &poly.N);

for(i=0; i<poly.N; i++)
{
scanf("%lf%lf", &poly.vertex[i].x, &poly.vertex[i].y);
if(poly.vertex[ki].y > poly.vertex[i].y ||
(poly.vertex[ki].y == poly.vertex[i].y && poly.vertex[ki].x > poly.vertex[i].x) )
ki = i;
}

swap(poly.vertex[0], poly.vertex[ki]);
sort(poly.vertex+1, poly.vertex+poly.N, cmp);
poly.vertex[poly.N] = poly.vertex[0];

scanf("%d", &M);

while(M--)
{
point A, B;

scanf("%lf%lf%lf%lf", &A.x, &A.y, &B.x, &B.y);
segment L(A, B);
printf("%.6f\n",poly.Seg_In_Poly(L));
}

return 0;
}
/**
6
1 2
2 1
2 3
3 1
3 3
4 2
200
1 1 4 10
**/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: