hdu-1154 Cutting a Polygon(计算几何综合应用,多模板)

题目链接:点击打开链接

Cutting a Polygon

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 663    Accepted Submission(s): 175


Problem Description
Given is a simple but not necessarily convex polygon. Given is also a line in the plane. If the polygon is cut along the line then we may get several smaller polygons. Your task is to find the length of the cut, that is the total length of the segments in the intersection of the line and the polygon. 
 

Input
Input consists of a number of cases. The data of each case appears on a number of input lines, the first of which contains two non negative integers n and m giving the number of the vertices of the polygon and the number of cutting lines to consider, 3 ≤ n ≤ 1000. The following n lines contain coordinates of the vertices of the polygon; each line contains the x and y coordinates of a vertex. The vertices are given either in clockwise or counterclockwise order. Each of the following m lines of input contains four numbers; these are x and y coordinates of the two points defining the cutting line. If a vertex of the polygon is closer than 10e-8 to the cutting line then we consider that the vertex lies on the cutting line. 
Input is terminated by a line with n and m equal to 0. 

 

Output
For each cutting line, print the total length of the segments in the intersection of the line and the polygon defined for this test case, with 3 digits after the decimal point. Note: the perimiter of a polygon belongs the polygon. 
The picture above illustrates the first cutting line for the polygon from the sample. 
 

Sample Input
  
  
9 5 0 0 0 2 1 1 2 2 3 1 4 2 5 1 6 2 6 0 -1 2 7.5 1 0 1 6 1 0 1.5 6 1.5 0 2 6 1 0 0 0 2 0 0
 

Sample Output
  
  
2.798 6.000 3.000 2.954 2.000
题意:求直线与多边形的公共长度。

思路:详细请看代码注释

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define N 1010
#define eps 1e-8
struct Node
{
    double x,y;
} p[N],q[N*10];
int n;
bool cmp(Node a,Node b)//排序,从左到右,从下到上
{
    if(abs(a.x-b.x)<eps)
        return a.y<b.y;
    return a.x<b.x;
}
double dist(Node a,Node b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double mulit(Node a,Node c,Node b)//向量ac与向量ab叉乘
{
    return (c.x-a.x)*(b.y-a.y)-(c.y-a.y)*(b.x-a.x);
}
int check(Node a,Node b,Node c,Node d)//判断直线ab与线段cd是否相交
{
    if(mulit(a,c,b)*mulit(a,d,b)<=0)
        return 1;
    return 0;
}
Node get_point(Node a,Node b,Node c,Node d)//求直线ab与线段cd的交点(已证明直线与线段相交,则可以当做两直线)
{
    Node ret=a;
    double t=((a.x-c.x)*(c.y-d.y)-(a.y-c.y)*(c.x-d.x))
             /((a.x-b.x)*(c.y-d.y)-(a.y-b.y)*(c.x-d.x));
    ret.x+=(b.x-a.x)*t;
    ret.y+=(b.y-a.y)*t;
    return ret;
}
int checkss(Node a,Node c,Node d)//判断点a是否在线段cd上
{
    if(mulit(a,c,d)!=0)
        return 0;
    if((a.x<c.x&&a.x<d.x)||(a.x>c.x&&a.x>d.x))
        return 0;
    if((a.y<c.y&&a.y<d.y)||(a.y>c.y&&a.y>d.y))
        return 0;
        return 1;
}
int isI(Node a,Node b,Node c,Node d)//判断线段ab和线段cd是否相交(互跨)
{
    if(mulit(a,c,b)*mulit(a,d,b)<=0&&mulit(c,a,d)*mulit(c,b,d)<=0)
        return 1;
    return 0;
}
int checks(Node a)//判断点a是否在多边形内
{
    Node b=a,c,d;
    b.x=1e15;
    int num=0;
    for(int i=0;i<n;i++)
    {
        c=p[i];
        d=p[i+1];
        if(checkss(a,c,d))
            return 1;
        if(abs(c.y-d.y)<eps)
            continue;
        if(checkss(c,a,b))
        {
            if(c.y>d.y)
                num++;
        }
        else if(checkss(d,a,b))
        {
            if(d.y>c.y)
                num++;
        }
        else if(isI(a,b,c,d))
        {
            num++;
        }
    }
    return num%2;
}
double get_len(Node a,Node b)//求直线与多边形的公共面积
{
    Node c,d;
    int cnt=0;
    for(int i=0; i<n; i++) //求出直线与多边形各边的交点
    {
        c=p[i];
        d=p[i+1];
        if(abs(mulit(a,b,c))<eps&&abs(mulit(a,b,d))<eps)
        {
            q[cnt++]=c;
            q[cnt++]=d;
        }
        else if(check(a,b,c,d))
            q[cnt++]=get_point(a,b,c,d);
    }
    if(cnt==0)
        return 0.0;
    sort(q,q+cnt,cmp);
    int t=1;
    for(int i=1; i<cnt; i++)
    {
        c=q[i];
        d=q[i-1];
        if(!(abs(c.x-d.x)<eps&&abs(c.y-d.y)<eps))
            q[t++]=q[i];
    }//去重
    double sum=0.0;
    for(int i=1; i<t; i++)
    {
        c.x=(q[i].x+q[i-1].x)*0.5;
        c.y=(q[i].y+q[i-1].y)*0.5;
        if(checks(c))
                sum+=dist(q[i],q[i-1]);
    }
    return sum;
}
int main()
{
    int m;
    Node a,b;
    while(~scanf("%d %d",&n,&m)&&n&&m)
    {
        for(int i=0; i<n; i++)
            scanf("%lf %lf",&p[i].x,&p[i].y);
        p[n]=p[0];
        for(int i=0; i<m; i++)
        {
            scanf("%lf %lf %lf %lf",&a.x,&a.y,&b.x,&b.y);
            printf("%.3lf\n",get_len(a,b));
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值