POJ 2074 计算几何 障碍物与视线的问题

15 篇文章 0 订阅
4 篇文章 0 订阅

将house的右端点跟所有障碍物的左端点连接起来,之后延长交与property_line点x_left。

将将house的左端点跟所有障碍物的右端点连接起来,之后延长交与property_line点x_right。

这样得到bleacher线上的left跟right点,从左到右扫描一次。 就可以算出答案了。

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;

const double eps = 1e-8;
const int MAXN = 1111;
double hx1,hx2,hy;  // house
double fx1,fx2,hf;  // property line
int n;
bool isZero(double a){
	if(fabs(a) < eps)
		return true;
	else return false;
} 
struct point  
{  
    double x,y;  
	point(){}
	point(double _x,double _y){ x=_x,y=_y;}
};  
struct line  
{  
    point a,b;  
	line(){}
	line(point _a,point _b){a = _a,b=_b;}
}L[MAXN];
//通过一条直线的两个点,计算在某一个y坐标时的坐标
point pointGetFromLine(line &l,double y){
	if( isZero(l.a.y - l.b.y) ){
		if(isZero(l.a.y - y))
			return point(0.0,y);
		return point(0.0,0.0);
	}else if(isZero(l.a.x - l.b.x)){
		return point(l.a.x,y);
	}else{
		double ret = l.a.x - (l.a.y - y)*(l.b.x-l.a.x)/(l.b.y - l.a.y);
		return point(ret,y);
	}
}
struct inFireLine{
	point p1;
	point p2;
	inFireLine(){}
	inFireLine(point _p1,point _p2){
		p1=_p1;  p2=_p2;
	}
}inFire[MAXN<<1];
//bool cmp(int i,int j){
//	return inFire[i].p.x < inFire[j].p.x || ( inFire[i].p.x == inFire[j].p.x && !is_right);
//}
bool cmp(const inFireLine &f1, const inFireLine &f2){
	return f1.p1.x < f2.p1.x || ( f1.p1.x == f2.p1.x && f1.p2.x < f2.p2.x);
}
int firCur;
void solve(){
	point p_house_left = point(hx1,hy),p_house_right = point(hx2,hy);
	firCur = 0;
	for(int i = 0;i < n;i++){
		if(L[i].a.y + eps > hy || L[i].a.y + eps < hf || isZero(hy - L[i].a.y) || isZero(hf - L[i].a.y) ) //不在中间的障碍物直接抛弃
			continue;
		//房子的右点 跟遮挡物的左点 ,y
		line l1 = line(p_house_right,L[i].a);
		point t1 = pointGetFromLine( l1, hf);
		t1.x = max(1.0*fx1,t1.x);
		line l2 = line(p_house_left,L[i].b);
		//房子的左点 跟遮挡物的左点 ,y
		point t2 = pointGetFromLine( l2, hf);
		t2.x = min(1.0*fx2,t2.x);
		if(t1.x > fx2 + eps || t2.x +eps < fx1)
			continue;
		inFire[firCur++] = inFireLine(t1,t2);
	}
	sort(inFire,inFire+firCur,cmp);
	double ans = 0;
	double lastX = fx1,left_tot = 0; //left_tot是计算左节点的数目
	
	if(firCur){
		for(int i = 0;i < firCur;i++){
			if(inFire[i].p1.x > lastX + eps){
				ans = max(ans, inFire[i].p1.x - lastX);
				lastX = inFire[i].p2.x;
			}else if(inFire[i].p2.x > lastX + eps){
				lastX = inFire[i].p2.x;
			}
		}
		if(lastX + eps < fx2)
			ans = max(ans,fx2 - lastX);
	}else{
		ans = fx2-fx1;
	}
	if(isZero(ans)){
		printf("0.00\n");
	}else{
		printf("%.2lf\n",ans);
	}
}
int main(){
	while(cin >> hx1 >> hx2 >> hy){
		if(isZero(hx1+hx2+hy))
			break;
		cin >> fx1 >> fx2 >> hf;
		cin >> n;
		double a,b,c;
		for(int i = 0;i < n;i++){
			cin >> a >> b >> c;
			L[i].a = point(a,c); L[i].b = point(b,c);
		}
		
		solve();
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值