[POJ 3596] Illuminated Planet [计算几何]

已知行星球心,恒星球心,摄像机这3个点的坐标,和行星,恒星的半径。问摄像机能够拍到的行星的范围内有没有一个面积为正的区域被恒星照亮。

首先把这三者做一下坐标转换。以行星球心为原点,行星球心向恒星球心为x轴正方向,摄像机所在位置为y轴正方向所在区域。把这个图转化到一个二维平面中。

记行星半径为r,恒星半径为R,行星和恒星的球心距为a,恒星与摄像机距离为b,行星与摄像机距离为c。行星坐标为原点(0,0),恒星坐标为(a,0),可以求出摄像机坐标为(x,y)。

可以求出恒星能照亮的角度范围为[-alpha,+alpha],以及摄像机能够看到的范围[atan2-acos(r/c),atan2+acos(r/c)]。

所以可以得出,如果belta=atan2-acos(r/c)<alpha,则有面积为正的区域。如果belta==alpha,则有面积为0的区域(一个交点...)。如果belta>alpha,则没有交叉区域。

#include <cstdio>
#include <cmath>
#include <iostream>

using std::cin;
using std::cout;
using std::endl;

const long double PI2=asin((long double)1);
const long double eps=1e-11;

long double xx1,yy1,zz1,r;
long double xx2,yy2,zz2,R;
long double xx3,yy3,zz3;
long double a,b,c;
long double xx,yy,alpha,beta;

long double len(long double xx,long double yy,long double zz=0) {
	return sqrt(xx*xx+yy*yy+zz*zz);
}
long double calAlpha() {
	if (R>r) return PI2+asin((R-r)/a);
	else acos((r-R)/a);
}
void calPos() {
	long double p=(a+b+c)/2;
	long double s=sqrt(p*(p-a)*(p-b)*(p-c));
	long double h=s*2/a;
	long double l=sqrt(c*c-h*h);
	yy=h;
	//printf("a=%Lf b=%Lf c=%Lf\n",a/1e7,b/1e7,c/1e7);
	//printf("p=%Lf s=%Lf\n",p/1e7,s/1e7);
	//printf("h=%Lf l=%Lf cos=%Lf\n",h/1e7,l/1e7,(a*a+c*c-b*b)/1e7);
	if (a*a+c*c-b*b>0) {
		xx=l;
	} else {
		xx=-l;
	}
}
long double calBeta() {
	return atan2(yy,xx)-acos(r/c);
}

int main() {
	cin >> xx1 >> yy1 >> zz1 >> r;
	cin >> xx2 >> yy2 >> zz2 >> R;
	cin >> xx3 >> yy3 >> zz3;
	a=len(xx1-xx2,yy1-yy2,zz1-zz2);
	b=len(xx3-xx2,yy3-yy2,zz3-zz2);
	c=len(xx1-xx3,yy1-yy3,zz1-zz3);
	alpha=calAlpha();
	calPos();
	beta=calBeta();
	//printf("a=%Lf b=%Lf c=%Lf\n",a/1e7,b/1e7,c/1e7);
	//printf("r=%Lf R=%Lf\n",r/1e7,R/1e7);
	//printf("x=%Lf y=%Lf\n",xx/1e7,yy/1e7);
	//printf("alpha=%Lf beta=%Lf\n",alpha,beta);
	//printf("PI/2=%Lf PI=%Lf\n",PI2,PI2*2);
	if (c<=r+eps) cout << "No" << endl;
	else if (alpha>beta+eps) cout << "Yes" << endl;
	else cout << "No" << endl;
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值