ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

AcWing 3034. 望远镜 POJ3675 三角剖分求圆与多边形的面积交并

2021-02-10 17:31:46  阅读:218  来源: 互联网

标签:return Vector Point 3034 double 剖分求 pb POJ3675 dcmp


题意

https://www.acwing.com/problem/content/description/3037/

求以原点为圆心的圆与一个简单多边形的面积交

思路

将多边形每条边与圆心相连求出其围成的有向三角形面积(三角剖分思想) 相加即为答案

求次面积交要考虑的状态如下:(设多边形某条边上的两端点为Point a,b,如果线段ab与圆有交点 设交点为pa pb)

1.a b均在圆内 S = Cross(a,b)/2;

2.a b均在圆外 

①ab与圆心O的距离 >= R, S = aOb的扇形面积

②距离 < R,S = paOPb的扇形面积 + aOpa的有向S△ + pbOb的有向S△

3.a在圆内 b在圆外 S = bOpb的扇形 + aOpb的有向S△

4.b在圆内 a在圆外 S = paOa的扇形 + paOb的有向S△

以上,在通过扇形面积公式 线段与圆心间的关系处理细节即可

求出交就能就并~

代码

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

using namespace std;
const double eps = 1e-8;
const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;

int n;
double R;
struct Point{
	double x,y;
	Point(double x = 0,double y = 0) : x(x),y(y) {}
}p[55],O;
typedef Point Vector;

int dcmp(double x){//equal ?= 0
	if(fabs(x) < eps) return 0;
	else return x < 0 ? -1:1;
}

//运算符重载
Vector operator + (Vector A, Vector B){ return Vector(A.x+B.x, A.y+B.y); }
Vector operator - (Vector A, Vector B){ return Vector(A.x-B.x, A.y-B.y); }
Vector operator * (Vector A, double p){ return Vector(A.x*p, A.y*p); }
Vector operator / (Vector A, double p){ return Vector(A.x/p, A.y/p); }
bool operator == (const Point &a, const Point &b){
	return dcmp(a.x-b.x) == 0 && dcmp(a.y-b.y) == 0;
}

double Dot(Vector A, Vector B){ return A.x*B.x + A.y*B.y; }
double Cross(Vector A, Vector B){ return A.x*B.y - A.y*B.x; }

double dis(Point A,Point B){
	return sqrt((A.x-B.x)*(A.x-B.x) + (A.y-B.y)*(A.y-B.y));
}

double Length(Vector A){return sqrt(Dot(A,A));}//计算向量的长度

Point rotate(Point a, double b){
    return {a.x * cos(b) + a.y * sin(b), -a.x * sin(b) + a.y * cos(b)};
}

Vector norm(Vector a){//将向量a标准化
	return a / Length(a);
}

//P点再P1P2上 叉积==0
bool OnSeg(Point P,Point P1,Point P2){
	return dcmp(Cross(P1 - P,P2 - P)) == 0 && dcmp(Dot(P1 - P,P2 - P)) <= 0;
}

//判断共线
bool Collinear(Point P1,Point P2,Point P3,Point P4){
	double A = Cross(P1 - P2,P3 - P2);
	double B = Cross(P1 - P2,P4 - P2);
	if(!dcmp(A) && !dcmp(B)) return 1;
	return 0;
}

//两参数方程求交点,(点,向量,点,向量)
Point Getlinenode(Point P,Point v,Point Q,Point w){
	//线1(P1,P2) 线2(P3,P4) (P1,P1-P2,P3,P3-P4)
    Point u = P - Q;
    double t = Cross(w,u) / Cross(v,w);
    return P + v * t;
}

double get_sector(Point a,Point b){//Oa Ob扇形面积
	double angle = acos(Dot(a,b) / Length(a) / Length(b));//aOb夹角
	if(dcmp(Cross(a,b)) < 0) angle *= -1.0;//面积是有向的
	return R * R * angle / 2.0;//面积
}

//求圆与直线的交点
double get_C_L_Ist(Point a,Point b,Point &pa,Point &pb){//ab 与 O 相交于 papb
	Point e = Getlinenode(a,b - a,O,rotate(b - a,pi / 2.0));//e是O垂直于ab的垂足
	double mind = dis(O,e);//垂线的距离
	if(!OnSeg(e,a,b)){
		mind = min(dis(O,a),dis(O,b));//O到线段ab的最短距离
	}
	if(dcmp(R - mind) <= 0) return mind;//ab均在圆外 返回最短距离 不比再求交点
	double len = sqrt(R * R - dis(O,e)*dis(O,e));//欲加在e上的向量长度 勾股
	pa = e + norm(a - b) * len;
	pb = e + norm(b - a) * len;
	return mind;
}

double get_circle_triangle_area(Point a,Point b){
	double disa = dis(a,O),disb = dis(b,O);
	if(dcmp(R - disa) >= 0 && dcmp(R - disb) >= 0) return Cross(a,b)/2.0;//a b在圆内 等于S△
	if(Collinear(a,O,b,O)) return 0.0;//O a b三点共线
	Point pa,pb;//ab与圆的两个交点
	double mind = get_C_L_Ist(a,b,pa,pb);//线段ab与O的最近距离
	if(dcmp(R - mind) <= 0) return get_sector(a,b);//扇形aOb
	if(dcmp(R - disa) >= 0) return get_sector(pb,b)+Cross(a,pb)/2.0;
	if(dcmp(R - disb) >= 0) return get_sector(a,pa)+Cross(pa,b)/2.0;
	//扇形+△ 注意有向!
	return get_sector(a,pa)+get_sector(pb,b)+Cross(pa,pb)/2.0;//俩扇形+△
}

double work(){
	double ans = 0.0;
	for(int i = 0;i < n; i++){
		ans += get_circle_triangle_area(p[i],p[(i + 1) % n]);
	}
	return fabs(ans);
}

int main()
{
	O.x = 0,O.y = 0;
	while(~scanf("%lf %d",&R,&n)){
		for(int i = 0;i < n; i++) scanf("%lf %lf",&p[i].x,&p[i].y);
		printf("%.2f\n",work());
	}
}

 

标签:return,Vector,Point,3034,double,剖分求,pb,POJ3675,dcmp
来源: https://blog.csdn.net/qq_43685900/article/details/113783988

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有