您的位置:首页 > 其它

hdu 1154

2015-09-19 21:47 323 查看
给出两个点所在直线 然后求出直线和多边形的交线长度

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <algorithm>
using namespace std;
const double eps=1e-8;
const int maxn=1e3+5;

struct Point
{
    double x,y;
    Point(double x=0,double y=0):x(x),y(y) {}
};

typedef Point VC;
VC operator +(VC A,VC B){return VC(A.x+B.x,A.y+B.y);}
VC operator -(VC A,VC B) {return VC(A.x-B.x,A.y-B.y);}
bool operator < (const Point& a,const Point& b) {return a.x<b.x||(a.x==b.x&&a.x<b.y);}
int dcmp(double x){return (fabs(x)<eps)?0:(x<0?-1:1);}
bool operator == (const Point& a,const Point& b){return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;}
double Dot(VC A,VC B) {return A.x*B.x+A.y*B.y;}
double Length(VC A) {return sqrt(Dot(A,A));}
double Cross(VC A,VC B){return A.x*B.y-A.y*B.x;}
int cmp(Point a, Point b)///毁一生啊
{
    if(dcmp(a.x - b.x)==0)
        return a.y < b.y;
    return a.x < b.x;
}
double cross(Point o,Point  a,Point b) { return (a.x-o.x)*(b.y-o.y) - (b.x-o.x)*(a.y-o.y);}
/*
    前提假设a、b、x共线
    返回:
        x在seg(a,b)内:-1
        x在seg(a,b)上:0
        x在seg(a,b)外:1
*/
int btw(Point x, Point a, Point b) {
    return dcmp(Dot(a-x, b-x));
}
///判断点p在线段a1a2上,共线+逆向 有错 好像是直线
bool OnSegment(Point p,Point a1,Point a2)///含端点 矢量夹角差距<=90 为正
{
    if(p==a1||p==a2) return 1;
    return dcmp(Cross(a1-p,a2-p))==0&&dcmp(Dot(a1-p,a2-p))<0;///重合点也算
}
/**
    和segCross(...)类似
    只是ab为直线,cd为线段
*/
int segLineCross(Point a, Point b, Point c, Point d, Point &p) {
    double s1, s2;
    int d1, d2;
    d1 = dcmp(s1=Cross(c-a,b-a));
    d2 = dcmp(s2=Cross(d-a,b-a));
    if((d1^d2)==-2) {
        p.x = (c.x*s2-d.x*s1)/(s2-s1);
        p.y = (c.y*s2-d.y*s1)/(s2-s1);
        return 1;
    }
    if(d1==0 || d2==0)    return 2;
    return 0;
}
/**
 * 判断点p是否在任意多边形p[]  其中点按找顺时针 输入中
 * 0外,1内,2边上
 */
int PointInPolygon(Point cp,Point p[],int n)
{
    int k,d1,d2,wn=0;
    p
=p[0];
    for(int i=0;i<n;i++)
    {
        if(OnSegment(cp,p[i],p[i+1])) return 2;
        k=dcmp(Cross(p[i+1]-p[i],cp-p[i]));
        d1=dcmp(p[i+0].y-cp.y);
        d2=dcmp(p[i+1].y-cp.y);
        if(k>0&&d1<=0&&d2>0)wn++;
        if(k<0&&d2<=0&&d1>0)wn--;
    }
    return wn!=0;
}
void pri(Point p[],int n)
{
    printf("-->%d\n",n);
    for(int i=0;i<n;i++)
        printf("%f %f\n",p[i].x,p[i].y);
}
double cal(Point p1,Point p2,Point p[],int n)
{
    Point pointset[10*maxn];
    int len=0;
    p
=p[0];
    for(int i=0;i<n;i++)
    {
        Point ans;
        int k=segLineCross(p1,p2,p[i],p[i+1],ans);
        if(k==1) pointset[len++]=ans;
        if(k==2) {
                //printf("=====\n");
            if(dcmp(cross(p[i],p1,p2))==0)
            pointset[len++]=p[i];
        }
    }
    len=unique(pointset,pointset+len)-pointset;
    sort(pointset,len+pointset,cmp);///少了
    //pri(pointset,len);
    double sum=0;
    for(int i=0;i<len-1;i++)
    {
        Point mid=Point((pointset[i].x+pointset[i+1].x)/2,(pointset[i].y+pointset[i+1].y)/2);
        if(PointInPolygon(mid,p,n)) sum+=Length(pointset[i]-pointset[i+1]);
    }
    return sum;
}
int main()
{
    int n,m;
    Point p[maxn];
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(n==0&&m==0) break;
        for(int i=0;i<n;i++)
        {
            scanf("%lf%lf",&p[i].x,&p[i].y);
        }
        for(int i=0;i<m;i++)
        {
            Point a,b;
            scanf("%lf%lf%lf%lf",&a.x,&a.y,&b.x,&b.y);
            printf("%.3f\n",cal(a,b,p,n));
        }
    }
    return 0;
}


先求出直线和多边形的交点,然后对线段进行排序,肯定是直线上的点。

然后求出相邻两点间的中间点 ,假如中间点在多边形内,那么这个线段就在多边形内。

然后计算这个长度即可
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: