汇总篇:计算几何汇总
题目描述
649.计算几何-空袭计算 (10分)
C时间限制:3000 毫秒 | C内存限制:3000 Kb
题目内容:
轰炸机轰炸的目标区域是地面上一个n个顶点的多边形,现在三维坐标(x,y,h)处投一颗炸弹,飞行速度是(vx,vy,0),
重力加速度是10。炸弹的爆炸半径是r, 现需要了解被炸的区域面积.输入描述
第一行是x y h
第二行是vx vy
第三行是炸弹的爆炸半径r
第四行是n,代表目标区域的顶点数
下面是n行是目标多变形的顶点坐标,按顺时针给出
输出描述
被炸的区域面积(两位小数)
输入样例
0 0 2000
100 0
100
4
1900 100
2000 100
2000 -100
1900 -100
输出样例
15707.96
解题思路
先根据物理学知识计算出落地圆心,然后就是多边形与圆相交面积的计算了
计算圆心
vxy=sqrt(vx*vx+vy*vy);
h = g*t*t/2;-> t = sqrt(2*h/g);
L = vxy*t;
S = (x,y)
e = (vx,vy)/dis((0,0),(vx,vy));
E = S + e*L;
多边形与圆相交面积请查看我另一篇博客,有详细介绍
ac代码
//c++ 提供默认的 = 赋值函数 和拷贝构造函数
#include<iostream>
#include<cmath>
#include<cstdio>
#include<vector>
using namespace std;
const int eps = 1e-2;
double myRound(double a){//因为小数有误差,所以判断相切时要精确到固定位数
return floor(a * 100 + 0.5) / 100; /*保留小数点后2位*/
}
class point{
public:
double x;
double y;
point(double x_=0,double y_=0):x(x_),y(y_){}
friend const point operator+(const point& p1,const point& p2){
return point(p1.x+p2.x,p1.y+p2.y);
};
friend const point operator-(const point& p1,const point& p2){
return point(p1.x-p2.x,p1.y-p2.y);
};
friend const point operator*(const point& p,const double& m){
return point(p.x*m,p.y*m);
};
friend const point operator*(const double& m,const point& p){
return point(p.x*m,p.y*m);
};
friend const point operator/(const point& p,const double& m){
return point(p.x/m,p.y/m);
};
friend ostream& operator <<(ostream& out,point& a){
printf("(%lf,%lf)",a.x,a.y);
return out;
};
};
typedef point vect2;//重命名,向量也是用坐标表示
class line{
public:
point start;
point end;
line(point s=point(0,0),point e=point(0,0)):start(s),end(e){}
};
class circle{
public:
double r;
point O;
circle(point O_=point(0,0),double r_=0):O(O_),r(r_){}
};
class polygon{//这里使用浅拷贝,更快
public:
vector<point> p;
int n;
polygon(vector<point> q= vector<point>(),int n_=0){p=q;n=n_;}
};
//函数声明------------------------------------------------------------------
double dot(point O,point A,point B);
double cross(point O,point A,point B);
double dis(const point &p1,const point &p2);
double angle(point O,point A,point B);
double sectorArea(point O,point A,point B,double r);
double disOfPointToLine(point O,line l);
point shadowPointOfPointToLine(point O,line l);
bool pointIsOnLine(point O,line L);
bool interPointOfLineAndCircle(line l,point O,double r,vector<point> &ans);
double InterAreaOfCircleAndPolygon(polygon poly,circle c);
//--------------------------------------------------------------------------
double dot(point O,point A,point B){//点乘
double oa_x=A.x-O.x;
double oa_y=A.y-O.y;
double ob_x=B.x-O.x;
double ob_y=B.y-O.y;
return oa_x*ob_x+oa_y*ob_y;
}
double cross(point O,point A,point B){//叉乘
double oa_x=A.x-O.x;
double oa_y=A.y-O.y;
double ob_x=B.x-O.x;
double ob_y=B.y-O.y;
return oa_x*ob_y-oa_y*ob_x;
}
double dis(const point &p1,const point &p2){//求两点之间距离
double ans=(p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y);
return sqrt(ans);
}
double dis2(const point &p1,const point &p2){//求两点之间距离
return(p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y);
}
//两直线夹角
double angle(point O,point A,point B){
return acos(dot(O,A,B)/(dis(O,A)*dis(O,B)));
}
//扇形面积alpha*pi*r*r/2*pi
double sectorArea(point O,point A,point B,double r){
double alpha=angle(O,A,B);
return alpha*r*r/2;
}
//点到直线的距离
double disOfPointToLine(point O,line l){
double cos0=dot(l.start,O,l.end)/(dis(O,l.start)*dis(l.start,l.end));
return dis(O,l.start)*sin(acos(cos0));
}
//点在直线上的投影
point shadowPointOfPointToLine(point A,line l){//投影点出了问题
point B = l.start;
point C = l.end;
point D;
vect2 BC = C - B;
vect2 BA = B - A;
vect2 BD = dot(B,A,C)/dis2(B,C)*BC;
D = B + BD;
return D;
}
//点是否在线段上
bool pointIsOnLine(point O,line L){
point S=L.start;
point E=L.end;
if(cross(O,S,E)==0//在直线L上
and min(S.x,E.x)<=O.x&&O.x<=max(S.x,E.x)
and min(S.y,E.y)<=O.y&&O.y<=max(S.y,E.y))
return true;
else return false;
}
//线段到圆的交点,所需函数:点到直线的距离,点在直线上的投影,两点之间的距离,判断点是否在线段上
bool interPointOfLineAndCircle(line l,point O,double r,vector<point> &ans){
ans.clear();
point C,D,E;
double d= disOfPointToLine(O,l);
E = shadowPointOfPointToLine(O,l);
vect2 AB = l.end-l.start;
vect2 e=AB/dis(l.start,l.end);
double base2 =myRound(r*r-d*d);//取约数,不然本来是0的会得不到0
//相切base^2 =0 两个点相等,相离 base^2<0
if(base2<0)return false;
double base = sqrt(base2);
C = E - e*base;
D = E + e*base;
//判断C,D时候在线段AB上即可
if(pointIsOnLine(C,l))ans.push_back(C);
if(pointIsOnLine(D,l)&&!(D.x==C.x&&D.y==C.y))//避免点重复
ans.push_back(D);
if(ans.size()>0)return true;
else return false;
}
//多边形和圆相交的面积,所需函数:点到直线的距离,线段和圆的交点,扇形面积,两点之间的距离
double InterAreaOfCircleAndPolygon(polygon poly,circle c){
double sums=0;//有向面积
vector<point> pointsInCircle;
vector<point> pointsOutCircle;
vector<point> interPoints;
for(int i=0;i<poly.n;i++){
double s=0;
pointsInCircle.clear();
pointsOutCircle.clear();
line l(poly.p[i],poly.p[(i+1)%poly.n]);//取多边形的一条边
double d = disOfPointToLine(c.O,l);//圆心到这条边的距离
//判断边的两个端点是在圆内还是圆外
if(dis(l.start,c.O)<=d){
pointsInCircle.push_back(l.start);
}else pointsOutCircle.push_back(l.start);//靠l的start方向的点先入vector
if(dis(l.end,c.O)<=d){
pointsInCircle.push_back(l.end);
}else pointsOutCircle.push_back(l.end);
//分四种情况
if(pointsInCircle.size()==2){//1:两个点都在圆内
//cout<<"三角形:"<<s<<endl;
s = cross(c.O,l.start,l.end)/2;
}else if(pointsInCircle.size()==1){//2:一个点在圆内,一个点在圆外
interPoints.clear();
//这里出错了没有求得交点
interPointOfLineAndCircle(l,c.O,c.r,interPoints);//只有一个交点
//定比分点求另一个交点,即圆外的顶点与圆心相连的线与圆的交点
vect2 e = (pointsOutCircle[0] - c.O)/dis(pointsOutCircle[0],c.O);
point interPoint2 = c.O + e*c.r;
double s1 = cross(c.O,pointsInCircle[0],interPoints[0]);
double s2 = sectorArea(c.O,interPoints[0],interPoint2,c.r);
//cout<<"三角形:"<<s1<<"扇形:"<<s2<<endl;
s = s1 + s2;
}else if(pointsInCircle.size()==0){//两个顶点都在圆外
if(d<=c.r){//3:两顶点所在边与圆相交
interPoints.clear();
interPointOfLineAndCircle(l,c.O,c.r,interPoints);//这里有两个交点,在l的靠start方向的点先进入vector
//定比分点求另外两个交点,即圆外的顶点与圆心相连的线与圆的交点
vect2 e1 = (pointsOutCircle[0] - c.O)/dis(pointsOutCircle[0],c.O);
vect2 e2 = (pointsOutCircle[1] - c.O)/dis(pointsOutCircle[1],c.O);
interPoints.push_back(point(c.O + e1*c.r));
interPoints.push_back(point(c.O + e2*c.r));
double s1 = cross(c.O,interPoints[0],interPoints[1]);
double s2 = sectorArea(c.O,interPoints[0],interPoints[2],c.r);
double s3 = sectorArea(c.O,interPoints[1],interPoints[3],c.r);
//printf("三角形:%lf 扇形:%lf %lf\n",s1,s2,s3);
s = s1 + s2 +s3;
}else{//4:两顶点所在边与圆不相交
interPoints.clear();
vect2 e1 = (pointsOutCircle[0] - c.O)/dis(pointsOutCircle[0],c.O);
vect2 e2 = (pointsOutCircle[1] - c.O)/dis(pointsOutCircle[1],c.O);
interPoints.push_back(point(c.O + e1*c.r));
interPoints.push_back(point(c.O + e2*c.r));
s = sectorArea(c.O,interPoints[0],interPoints[1],c.r);
//cout<<"扇形:"<<s<<endl;
}
}
sums+=s;
//cout<<"s="<<s<<endl;
}
return fabs(sums);
}
/*
第一行是x y h
第二行是vx vy
第三行是炸弹的爆炸半径r
第四行是n,代表目标区域的顶点数
下面是n行是目标多变形的顶点坐标,按顺时针给出
vxy=sqrt(vx*vx+vy*vy);
h = g*t*t/2;-> t = sqrt(2*h/g);
L = vxy*t;
S = (x,y)
e = (vx,vy)/dis((0,0),(vx,vy));
E = S + e*L;
*/
double x,y,h,vx,vy,r,n;
const int N = 10005;
vector<point> P;
double px,py;
circle c;
polygon poly;
circle getCircle(){
double vxy;
double t;
double L;
double g=10.0;
point S;
vect2 e;
vect2 Vxy;
point E;
vxy=sqrt(vx*vx+vy*vy);
t = sqrt(2*h/g);
L = vxy*t;
S=point(x,y);
Vxy = point(vx,vy);
e = Vxy/dis(point(0,0),Vxy);
E = S + e*L;
//cout<<"circle:"<<E.x<<" "<<E.y<<" r="<<r<<endl;
return circle(E,r);
}
void solve(){
c = getCircle();
printf("%.2lf\n",InterAreaOfCircleAndPolygon(poly,c)+eps);
}
int main(){
while(~scanf("%lf%lf%lf",&x,&y,&h)){
scanf("%lf%lf",&vx,&vy);
scanf("%lf",&r);
scanf("%lf",&n);
P.clear();
for(int i=0;i<n;i++){
scanf("%lf%lf",&px,&py);
P.push_back(point(px,py));
}
poly=polygon(P,n);
solve();
}
return 0;
}