POJ 2826 计算几何模板

An Easy Problem?!
Time Limit: 1000MS Memory Limit: 65536K
   

Description

It's raining outside. Farmer Johnson's bull Ben wants some rain to water his flowers. Ben nails two wooden boards on the wall of his barn. Shown in the pictures below, the two boards on the wall just look like two segments on the plane, as they have the same width. 

Your mission is to calculate how much rain these two boards can collect. 

Input

The first line contains the number of test cases. 
Each test case consists of 8 integers not exceeding 10,000 by absolute value,  x 1y 1x 2y 2x 3y 3x 4y 4. ( x 1y 1), ( x 2y 2) are the endpoints of one board, and ( x 3y 3), ( x 4y 4) are the endpoints of the other one. 

Output

For each test case output a single line containing a real number with precision up to two decimal places - the amount of rain collected. 

Sample Input

2
0 1 1 0
1 0 2 1

0 1 2 1
1 0 1 2

Sample Output

1.00
0.00
 
题意:给你两块挡板的坐标,求能收集多少水。

题解:超级烦琐的计算几何题,我写这篇日志主要目的是把模板放上来23333.
言归正传,这题有很多坑。
1.答案要加eps
2.共线答案为0
3.平行答案为0
4.能收集水的三角形被挡住答案为0,比如0 0 10 10   0 0 8 9
5.判断相等与否必须用fabs(x-y)<eps
 
 
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
using namespace std;
#define eps 1e-8
#define zero(x) (((x)>0?(x):-(x))<eps)
struct point
{
    double x;
    double y;
};
int direction (point p0, point p1, point p2) {  
    return ((p2.x - p0.x)*(p1.y - p0.y) - (p1.x - p0.x)*(p2.y - p0.y));  
}  
  
bool on_segment (point p0, point p1, point p2) { 
    int minx, maxx, miny, maxy;  
    minx = min(p0.x, p1.x);  
    maxx = max(p0.x, p1.x);  
    miny = min(p0.y, p1.y);  
    maxy = max(p0.y, p1.y);  
    if (p2.x >= minx && p2.x <= maxx && p2.y >= miny && p2.y <= maxy)  
        return true;  
    else  
        return false;  
}  
bool segments_intersect (point p1, point p2, point p3, point p4) {  //判两条线段是否相交

    int d1, d2, d3, d4;  
    d1 = direction(p3, p4, p1);  
    d2 = direction(p3, p4, p2);  
    d3 = direction(p1, p2, p3);  
    d4 = direction(p1, p2, p4);  
    if (((d1 < 0 && d2 > 0) || (d1 > 0 && d2 < 0)) && ((d3 < 0 && d4 > 0) || (d3 > 0 && 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;  
    else  
        return false;  
}  
point intersection(point u1,point u2,point v1,point v2){//两条直线的交点
    point ret=u1;
    double t=((u1.x-v1.x)*(v1.y-v2.y)-(u1.y-v1.y)*(v1.x-v2.x))
             /((u1.x-u2.x)*(v1.y-v2.y)-(u1.y-u2.y)*(v1.x-v2.x));
    ret.x+=(u2.x-u1.x)*t;
    ret.y+=(u2.y-u1.y)*t;
    return ret;
}
double xmult(point p1,point p2,point p0)//叉积
{
    return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}
int dot_online_in(point p,point l1,point l2)//判断点是否在线段上
{
    return zero(xmult(p,l1,l2))&&(l1.x-p.x)*(l2.x-p.x)<eps&&(l1.y-p.y)*(l2.y-p.y)<eps;
}
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		point a1,a2,a3,a4;
		scanf("%lf%lf%lf%lf%lf%lf%lf%lf",&a1.x,&a1.y,&a2.x,&a2.y,&a3.x,&a3.y,&a4.x,&a4.y);
		if(fabs(a1.x-a2.x)<eps&&fabs(a3.x-a4.x)<eps){//判两条线平行  斜率不存在
			printf("0.00\n");
			continue;
		}
		else if((fabs(a2.x-a1.x)>eps&&fabs(a3.x-a4.x)>eps)&&((fabs((a2.y-a1.y)/(a2.x-a1.x)-(a4.y-a3.y)/(a4.x-a3.x))<eps))){
			printf("0.00\n");//判两条线平行  斜率存在
			continue;
		}
		if(!segments_intersect(a1,a2,a3,a4)){//判是否有交点
			printf("0.00\n");
			continue;
		}
		point jiao=intersection(a1,a2,a3,a4);//两条直线的交点
		double y=max(a1.y,a2.y);
		double yy=max(a3.y,a4.y);
		y=min(y,yy);//两块挡板的最低点
		if(fabs(y-jiao.y)<eps){//判交点和最低点是否是同一点
			printf("0.00\n");
			continue;
		}
		point xx;
		xx.x=0;
		xx.y=y;
		point jiao1=intersection(xx,(point){xx.x+1,y},a1,a2);//封住三角形的上面的两个点的其中一个
		point jiao2=intersection(xx,(point){xx.x+1,y},a3,a4);//第二个交点
		point jiaoy2=intersection((point){jiao1.x,jiao1.y},(point){jiao1.x,jiao1.y+1},a3,a4);//做垂线  求出与另一条直线的交点
		point jiaoy3=intersection((point){jiao2.x,jiao2.y},(point){jiao2.x,jiao2.y+1},a1,a2);//同理
		if((jiao1.y<jiaoy2.y)&&(dot_online_in(jiaoy2,a3,a4))){/如果它上面有点且那个点在另一条线上  就代表挡住了
			printf("0.00\n");
			continue;
		}
		if((jiao2.y<jiaoy3.y)&&(dot_online_in(jiaoy3,a1,a2))){
			printf("0.00\n");
			continue;
		}
		printf("%.2f\n",fabs(jiao2.x-jiao1.x)*fabs(y-jiao.y)/2.0+eps);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值