HDU1154求线段在多边形内长度

来源:互联网 发布:记忆力训练 知乎 编辑:程序博客网 时间:2024/06/01 07:23
/******************************************************************题意:多边形有n个顶点,输入m条直线,分别输出它们在多边形内的长度,边界也算算法:求出直线与多边形的所有交点,排序后,判断每一段线段是否在多边形内(判断中点是否在多边形内),求和。*******************************************************************/#include<iostream>#include<cstring>#include<cstdio>#include<cmath>#include<algorithm>using namespace std;struct Point{    double x;    double y;} p[1001], px[10001];int n;double eps=1e-8;int cmp(Point a, Point b){    if(abs(a.x-b.x)<eps)        return a.y<b.y;    return a.x<b.x;}double dist(Point a,Point b)//求距离{    return sqrt((a.x - b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}double direction(Point pi,Point pj,Point pk){    return (pk.x-pi.x)*(pj.y-pi.y)-(pj.x-pi.x)*(pk.y-pi.y);}bool on_segment(Point pi,Point pj,Point pk)//判断点pk时候在线段pi, pj上{    if(direction(pi, pj, pk)==0)    {        if(pk.x>=min(pi.x,pj.x)&&pk.x<=max(pi.x,pj.x)&&pk.y>=min(pi.y,pj.y)&&pk.y<=max(pi.y,pj.y))            return true;    }    return false;}bool segments_intersect(Point p1,Point p2,Point p3,Point p4)//判断线段是否相交{    double d1=direction(p3,p4,p1);    double d2=direction(p3,p4,p2);    double d3=direction(p1,p2,p3);    double d4=direction(p1,p2,p4);    if(d1*d2<0&&d3*d4<0)        return true;    else if(d1==0&&on_segment(p3,p4,p1))        return true;    else if(d2==0&&on_segment(p3,p4,p2))        return true;    else if(d3==0&&on_segment(p1,p2,p3))        return true;    else if(d4==0&&on_segment(p1,p2,p4))        return true;    return false;}Point intersection(Point a1, Point a2, Point b1, Point b2)//计算线段交点{    Point ret = a1;    double t = ((a1.x - b1.x) * (b1.y - b2.y) - (a1.y - b1.y) * (b1.x - b2.x))               / ((a1.x - a2.x) * (b1.y - b2.y) - (a1.y - a2.y) * (b1.x - b2.x));    ret.x += (a2.x - a1.x) * t;    ret.y += (a2.y - a1.y) * t;    return ret;}int InPolygon(Point a)//判断点是否在多边形的内部{    int i;    Point b,c,d;    b.y=a.y;    b.x=1e15;//定义射线    int flag=0;    int count=0;    for(i=0; i<n; i++)    {        c = p[i];        d = p[i + 1];        if(on_segment(c,d,a))//该点在多边形的一条边上            return 1;        if(abs(c.y-d.y)<eps)            continue;        if(on_segment(a,b,c))//和顶点相交的情况,如果y值较大则取        {            if(c.y>d.y)                count++;        }        else if(on_segment(a,b,d))//和顶点相交的情况,如果y值较大则取        {            if(d.y>c.y)                count++;        }        else if(segments_intersect(a,b,c,d))//和边相交            count++;    }    return count%2;//当L和多边形的交点数目C是奇数的时候,P在多边形内,是偶数的话P在多边形外。}bool Intersect(Point s,Point e,Point a,Point b){    return direction(e,a,s)*direction(e,b,s)<=0;}//所在直线相交double calculate(Point s,Point e){    int i,j,k=0;    double sum;    Point a,b,temp;    for(i=0; i<n; i++) //遍历所有点计算交点    {        a=p[i];        b=p[i+1];        if(abs(direction(e,a,s))<eps&&abs(direction(e,b,s))<eps)        {            px[k++]=a;            px[k++]=b;        }        else if(Intersect(s,e,a,b))//两直线相交        {            px[k++]=intersection(s,e,a,b);//两直线交点        }    }    if(k==0)        return 0.0;    sort(px,px+k,cmp); // 排序,由于割线是直线,所以交点必定线性分布    px[k]=px[0];    sum=0;    for(i=0; i<k-1; i++)    {        a=px[i];        b=px[i+1];        temp.x=(a.x+b.x)/2.0;        temp.y=(a.y+b.y)/2.0;        if(InPolygon(temp))//如果两点的中点在多边形外部,说明直线在外部            sum+=dist(a,b);    }    return sum;}int main(){    int q,i,j;    double sum;    Point s,e;    //freopen("C:\\Users\\Administrator\\Desktop\\kd.txt","r",stdin);    while(~scanf("%d%d",&n,&q))    {        if(q==0&&n==0)            break;        for(i=0; i<n; i++)            scanf("%lf%lf",&p[i].x,&p[i].y);        p[n]=p[0];        for(j=0; j<q; j++)        {            scanf("%lf%lf%lf%lf",&s.x,&s.y,&e.x,&e.y);            sum=calculate(s,e);            printf("%.3f\n",sum);        }    }    return 0;}


 

原创粉丝点击