POJ 2986 A Triangle and a Circle(计算几何)
来源:互联网 发布:软件项目风险管理方案 编辑:程序博客网 时间:2024/05/02 19:11
Description
给出一个三角形各点坐标以及一个圆的圆心坐标和其半径,求三角形与该圆的相交面积
Input
输入包含多组样例,以文件尾结束,每组用例包括9个浮点数x1,y1,x2,y2,x3,y3,x0,y0,r分别表示三角形三点坐标,圆心坐标以及圆的半径
Output
对于每组用例,输出一行,为多边形与圆相交部分的面积。所有输出中浮点数保留小数点后两位
Sample Input
0 20 10 0 -10 0 0 0 10
Sample Output
144.35
Solution
只要求出以圆心和三角形边形上任一条边组成的三角形与圆的相交面积再模仿叉乘求多边形面积通过有向面积累加即可求出三角形与圆的相交面积,对于三角形与圆的相交面积分为以下六种情况
1.两点都在圆内
2.两点都在圆外且圆心到直线ab距离大于半径
3.两点都在圆外且圆心到直线距离小于半径但三角形oab有一底角是钝角即直线ab与圆没有交点
4.两点都在圆外且原点到直线ab距离小于半径且三角形oab底角均为锐角即直线ab与圆有两个交点
5.a点在圆外,b点在圆内
6.b点在圆外,a点在圆内
之后就根据每个三角形的特点从上述六种情况中找到分类即可求出相交面积
注意,因为圆心坐标不是原点时会增加难度,所以每次都将圆心平移到原点
Code
#include<cstdio>#include<iostream>#include<cmath>using namespace std;struct node{ double x,y;};double r;double multi(node a,node b)//向量叉乘 { return a.x*b.y-a.y*b.x;}int get_sign(node a,node b)//判断向量叉乘符号 { if(multi(a,b)>0) return 1; return -1;}double dis(node a,node b)//两点间距离 { return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}double dis_line(node a,node b)//求原点到直线ab的距离 { return fabs(multi(a,b))/dis(a,b);}double get_angle(double a,double b,double c)//求边c对角的值 { return (a*a+b*b-c*c)/(2.0*a*b);}node get_point(node a)//求a点与原点连线与圆的交点坐标 { node ans; double k; if(a.x!=0)//斜率存在 { k=a.y/a.x; ans.x=fabs(r)/sqrt(1.0+k*k); if(a.x<0) ans.x=-ans.x;//判断ans.x的符号 ans.y=k*ans.x; } else//斜率不存在 { ans.x=0; if(a.y>0) ans.y=r;//判断ans.y的符号 else ans.y=-r; } return ans;}double get_area(node a,node b,node o)//求a,b,o三点所形成的三角形与圆相交的有向面积 { int sign=get_sign(a,b);//判断有向面积的符号 double ans=0; double oa=dis(o,a),ob=dis(o,b),ab=dis(a,b); double l=dis_line(a,b); if(oa==0||ob==0)//有一边边长为0则面积为0 return 0; //第一种情况,两点都在圆内 if(oa<=r&&ob<=r) { ans=fabs(multi(a,b))/2.0;//相交面积即为三角形oab的面积 return sign*ans; } //第二种情况,两点都在圆外且圆心到直线ab距离大于半径 else if(oa>=r&&ob>=r&&l>=r) { node t1=get_point(a);//oa与圆的交点 node t2=get_point(b);//ob与圆的交点 double d=dis(t1,t2); double ang=acos(get_angle(r,r,d));//角t1ot2 ans=fabs(ang*r*r/2.0);//相交面积即为扇形ot1t2的面积 return sign*ans; } //第三种情况,两点都在圆外且圆心到直线距离小于半径但三角形oab有一底角是钝角即直线ab与圆没有交点 else if(oa>=r&&ob>=r&&l<=r&&(get_angle(ab,oa,ob)<=0||get_angle(ab,ob,oa)<=0)) { node t1=get_point(a);//oa与圆的交点 node t2=get_point(b);//ob与圆的交点 double dist=dis(t1,t2);//线段t1t2长度 double ang=acos(get_angle(r,r,dist));//角t1ot2 ans=fabs(ang*r*r/2.0);//相交面积即为扇形ot1t2的面积 return sign*ans; } //第四种情况,两点都在圆外且原点到直线ab距离小于半径且三角形oab底角均为锐角即直线ab与圆有两个交点 else if(oa>=r&&ob>=r&&l<=r&&get_angle(ab,oa,ob)>0&&get_angle(ab,ob,oa)>0) { node c,d;//c,d为直线ab与圆的两个交点 if(a.x!=b.x)//直线ab斜率存在 { double k=(a.y-b.y)/(a.x-b.x);//直线ab斜率 double h=a.y-k*a.x;//直线ab截距 //解一元二次方程求圆与直线ab的交点 double a0=1.0+k*k; double b0=2.0*k*h; double c0=h*h-r*r; c.x=(-b0+sqrt(b0*b0-4.0*a0*c0))/(2.0*a0); c.y=k*c.x+h; d.x=(-b0-sqrt(b0*b0-4.0*a0*c0))/(2.0*a0); d.y=k*d.x+h; } else//直线ab斜率不存在 { c.x=a.x; d.x=a.x; c.y=sqrt(r*r-a.x*a.x); d.y=-sqrt(r*r-a.x*a.x); } node t1=get_point(a);//oa与圆的交点 node t2=get_point(b);//ob与圆的交点 double d1=dis(c,d);//线段cd长度 double d2=dis(t1,t2);//线段t1t2长度 double ang1=acos(get_angle(r,r,d1));//角cod double ang2=acos(get_angle(r,r,d2));//角t1ot2 double s1=fabs(ang1*r*r/2.0);//小扇形ocd面积 double s2=fabs(ang2*r*r/2.0);//小大扇形ot1t2面积 double s3=fabs(multi(c,d))/2.0;//三角形ocd面积 ans=s2+s3-s1;//相交面积即为三角形ocd面积加上两个扇形面积之差 return sign*ans; } //第五种情况,a点在圆外,b点在圆内 else if(oa>=r&&ob<=r) { node c,d,e;//c,d两点为直线ab与圆的两个交点,e点为介于ab两点之间的那个交点 if(a.x!=b.x)//直线ab斜率存在 { double k=(a.y-b.y)/(a.x-b.x);//直线ab斜率 double h=a.y-k*a.x;//直线ab截距 //解一元二次方程求圆与直线ab的交点 double a0=1.0+k*k; double b0=2.0*k*h; double c0=h*h-r*r; c.x=(-b0+sqrt(b0*b0-4.0*a0*c0))/(2.0*a0); c.y=k*c.x+h; d.x=(-b0-sqrt(b0*b0-4.0*a0*c0))/(2.0*a0); d.y=k*d.x+h; //交点应为c,d两点中横坐标介于(a.x,b.x)两点之间的那一个 if(a.x<=c.x&&c.x<=b.x||a.x>=c.x&&c.x>=b.x) e=c; else e=d; } else//直线ab斜率不存在 { c.x=d.x=a.x; c.y=-sqrt(r*r-a.x*a.x); d.y=sqrt(r*r-a.x*a.x); //交点应为c,d两点中纵坐标介于(a.y,b.y)两点之间的那一个 if(a.y<=c.y&&c.y<=b.y||a.y>=c.y&&c.y>=b.y) e=c; else e=d; } node t1=get_point(a);//oa与圆的交点 double dist=dis(t1,e);//线段t1e长度 double ang=acos(get_angle(r,r,dist));//角eot1 double s1=fabs(ang*r*r/2.0);//扇形oet1面积 double s2=fabs(multi(b,e))/2.0;//三角形obe面积 ans=s1+s2;//相交面积即三角形obe面积加上扇形oet1面积 return sign*ans; } //第五种情况,b点在圆外,a点在圆内 else if(ob>=r&&oa<=r) { node c,d,e;//c,d两点为直线ab与圆的两个交点,e点为介于ab两点之间的那个交点 if(a.x!=b.x)//直线ab斜率存在 { double k=(a.y-b.y)/(a.x-b.x);//直线ab斜率 double h=a.y-k*a.x;//直线ab截距 //解一元二次方程求圆与直线ab的交点 double a0=1.0+k*k; double b0=2.0*k*h; double c0=h*h-r*r; c.x=(-b0+sqrt(b0*b0-4.0*a0*c0))/(2.0*a0); c.y=k*c.x+h; d.x=(-b0-sqrt(b0*b0-4.0*a0*c0))/(2.0*a0); d.y=k*d.x+h; //交点应为c,d两点中横坐标介于(a.x,b.x)两点之间的那一个 if(a.x<=c.x&&c.x<=b.x||a.x>=c.x&&c.x>=b.x) e=c; else e=d; } else//直线ab斜率不存在 { c.x=d.x=a.x; c.y=-sqrt(r*r-a.x*c.x); d.y=sqrt(r*r-a.x*a.x); //交点应为c,d两点中纵坐标介于(a.y,b.y)两点之间的那一个 if(a.y<=c.y&&c.y<=b.y||a.y>=c.y&&c.y>=b.y) e=c; else e=d; } node t1=get_point(b);//oa与圆的交点 double dist=dis(t1,e);//线段t1e长度 double ang=acos(get_angle(r,r,dist));//角eot1 double s1=fabs(ang*r*r/2.0);//扇形oet1面积 double s2=fabs(multi(a,e))/2.0;//三角形oae面积 ans=s1+s2;//相交面积即三角形oae面积加上扇形oet1面积 return sign*ans; }}int main(){ node a,b,c,o; while(scanf("%lf%lf%lf%lf%lf%lf%lf%lf%lf",&a.x,&a.y,&b.x,&b.y,&c.x,&c.y,&o.x,&o.y,&r)!=EOF) { double ans=0.0; //将圆心移动到原点 a.x-=o.x;a.y-=o.y; b.x-=o.x;b.y-=o.y; c.x-=o.x;c.y-=o.y; o.x=o.y=0; ans=get_area(a,b,o)+get_area(b,c,o)+get_area(c,a,o); printf("%.2lf\n",fabs(ans)); } return 0;}
0 0
- POJ 2986 A Triangle and a Circle(计算几何)
- POJ 2986 A Triangle and a Circle(计算几何)
- POJ 2986 A Triangle and a Circle
- poj 2986 A Triangle and a Circle 圆与三角形的公共面积
- POJ 3675/2986(Telescope/A Triangle and a Circle-三角形与圆的面积并)
- 【计算几何】 POJ 1981 Circle and Points
- POJ 1981 Circle and Points 计算几何
- A Circle and a Square----计算几何,判断点是否在图形内
- POJ1981 Circle and Points(计算几何)
- poj2986A Triangle and a Circle (圆与三角形求交)
- hdu-1221--Rectangle and Circle(计算几何)
- CodeForces 613 A. Peter and Snow Blower(计算几何)
- 计算几何-hdoj-1221-Rectangle and Circle
- poj1981 Circle and Points 计算几何
- 【暴力几何】#6 A. Triangle
- CodeForces 18A Triangle (几何)
- JOJ 2109 && POJ 1981 Circle and Points 计算几何 单位圆覆盖问题
- Mahmoud and a Triangle
- 南邮 OJ 1198 A_Mispelling4
- 程序员一生必读的书籍
- uva 10020 Minimal coverage(贪心,区间覆盖)
- Android launcher3布局和结构
- 社説 20150805 辺野古作業中断 事態打開へ知事も頭冷やそう
- POJ 2986 A Triangle and a Circle(计算几何)
- Construct Binary Tree from Inorder and Postorder Traversal
- CircleImageView圆形图控件+MPAndroidChart图表控件
- Android java 中如何优雅的结束线程
- LeetCode237——Delete Node in a Linked List
- Android基础之横竖屏切换时Activity的生命周期
- poj 3620 Avoid The Lakes
- Heap Spray原理浅析
- 给定入栈顺序,求解出栈顺序