这个部分模板是来自kuagnbin模板,我为了能够好理解加了些解释和说明
但是由于下面代码全部是我自己纯手抄的,所以只能保证编译通过,不能保证100%正确,如有错误希望大家指正,所以如果比赛使用模板仍然以kuangbin模板为准,我的这篇仅供理解
首先在开始前需要定义一些变量,和几个必要的方法
#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-8;
const double inf = 1e20;
const double pi = acos( 1.0);//圆周率
const int maxp = 1010;
//和0比较大小的函数
int sgn(double x){
if(fabs(x) < eps)return 0;//等于0
if(x < 0)return -1;//小于0
else return 1; //大于0
}
//浮点数平方
inline double sqr(double x){return x*x;}
一、与点相关的公式
首先定义点的结构体,并对必要运算符进行重载得到点坐标的基本运算
struct Point{
double x,y;
Point(){}
Point(double _x,double _y){
x = _x;
y = _y;
}//构造函数
void input(){//输入
scanf("%lf%lf",&x,&y);
}
void output(){//输出
printf("%.2f %.2f\n",x,y);//保留位数可自己控制
}
bool operator == (Point b)const{//横纵坐标均相等
return sgn(x - b.x) == 0 && sgn(y - b.y) == 0;
}
bool operator < (Point b)const{//先比横坐标,相同在比较纵坐标
return sgn(x - b.x) == 0 ? sgn(y - b.y) < 0 : x < b.x;
}
Point operator - (const Point &b)const{
return Point(x - b.x, y - b.y);
}
Point operator + (const Point &b)const{
return Point(x + b.x, y + b.y);
}
//叉积
double operator ^ (const Point &b)const{
return x * b.y - y * b.x;
}
//点积
double operator * (const Point &b)const{
return x * b.x + y * b.y;
}
//数乘
Point operator * (const double &k)const{
return Point(x * k, y * k);
}
Point operator / (const double &k)const{
return Point(x / k, y / k);
}
//返回长度
double len(){
return hypot(x,y);//<math.h>中函数,给定直角三角形两直角边求出斜边长度
}
//返回长度平方
double len2(){
return x * x + y * y;
}
//返回两点距离
double dis(Point p){
return hypot(x - p.x, y - p.y);
}
};
1.计算向量 的夹角
我们知道在直角坐标系中,知道一个点坐标我们可以计算其角度如下图所示
利用 反正切函数可以求出角度
但是我们使用一个更好的函数 这个函数同样是反正切函数,但是要比 更稳定
所以
对于一般情况只要求出一个投影和投影高度就可以利用函数求啦
我们可以这样求
所以函数中只需传入叉积和点积的绝对值即可
模板:
//计算pa和pb的夹角
double rad(Point a,Point b){
Point p = *this;
return fabs(atan2(fabs((a - p) ^ (b - p)),(a - p) * (b - p)));
}
2.转化成长度为r的向量
模板:
//化为长度为r的向量
Point turn(double r){
double l = len();
if(!sgn(l)) return *this;//如果原来长度为0,直接返回这个点
r /= l;
return Point(x * r,y * r);
}
假设原向量 ,改变后为
其长度为
3.点的旋转
逆时针旋转90°和顺时针旋转90°
模板:
//逆时针旋转90
Point rotleft(){
return Point(-y,x);
}
//顺时针旋转90
Point rotright(){
return Point(y,-x);
}
点 绕点 逆时针旋转任意角度 有公式:
证明先不证明了,不会。。。网上应该有看着很麻烦就不写了
模板
//绕p点逆时针旋转angle
Point rot(Point p,double angle){
Point v = (*this) - p;
double c = cos(angle), s = sin(angle);
return Point(p.x + v.x * c - v.y * s, p.y + v.x * s + v.y * c);
}
以上就是关于点的一些操作的模板,下面是代码汇总(全都在一个结构体中)
struct Point{
double x,y;
Point(){}
Point(double _x,double _y){
x = _x;
y = _y;
}//构造函数
void input(){//输入
scanf("%lf%lf",&x,&y);
}
void output(){//输出
printf("%.2f %.2f\n",x,y);//保留位数可自己控制
}
bool operator == (Point b)const{//横纵坐标均相等
return sgn(x - b.x) == 0 && sgn(y - b.y) == 0;
}
bool operator < (Point b)const{//先比横坐标,相同在比较纵坐标
return sgn(x - b.x) == 0 ? sgn(y - b.y) < 0 : x < b.x;
}
Point operator - (const Point &b)const{
return Point(x - b.x, y - b.y);
}
Point operator + (const Point &b)const{
return Point(x + b.x, y + b.y);
}
//叉积
double operator ^ (const Point &b)const{
return x * b.y - y * b.x;
}
//点积
double operator * (const Point &b)const{
return x * b.x + y * b.y;
}
//数乘
Point operator * (const double &k)const{
return Point(x * k, y * k);
}
Point operator / (const double &k)const{
return Point(x / k, y / k);
}
//返回长度
double len(){
return hypot(x,y);//<math.h>中函数,给定直角三角形两直角边求出斜边长度
}
//返回长度平方
double len2(){
return x * x + y * y;
}
//返回两点距离
double dis(Point p){
return hypot(x - p.x, y - p.y);
}
//计算pa和pb的夹角
double rad(Point a,Point b){
Point p = *this;
return fabs(atan2(fabs((a - p) ^ (b - p)),(a - p) * (b - p)));
}
//化为长度为r的向量
Point turn(double r){
double l = len();
if(!sgn(l)) return *this;//如果原来长度为0,直接返回这个点
r /= l;
return Point(x * r,y * r);
}
//逆时针旋转90
Point rotleft(){
return Point(-y,x);
}
//顺时针旋转90
Point rotright(){
return Point(y,-x);
}
//绕p点逆时针旋转angle
Point rot(Point p,double angle){
Point v = (*this) - p;
double c = cos(angle), s = sin(angle);
return Point(p.x + v.x * c - v.y * s, p.y + v.x * s + v.y * c);
}
};
关于直线的公式
仍然是定义直线的结构体,两个点来存直线,因此直线中的计算依附于上面我们已经写了的点的运算
//用两点来存
struct Line{
Point s,e;
Line(){}
Line(Point _s,Point _e){
s = _s;
e = _e;
}
//根据一个点和倾斜角angle确定直线
Line(Point p,double angle){
s = p;
if(sgn(angle - pi / 2) == 0){
e = (s + Point(0,1));
}//斜率不存在,就是一条竖线
else{
e = (s + Point(1,tan(angle)));//x增加1,y增加tan,由tan=y/x,当x=1,y=tan
}
}
//ax+by+c=0
Line(double a,double b,double c){
if(sgn(a) == 0){//斜率为0,一条横线
s = Point(0,-c / b);
e = Point(1,-c / b);
}
else if(sgn(b) == 0){//斜率不存在,一条横线
s = Point(-c / a,0);
e = Point(-c / a,1);
}
else{//令x=0算一个点,令x=1算一个点
s = Point(0,-c / b);
e = Point(1,(-c - a) / b);
}
}
bool operator == (Line v){
return (s == v.s) && (e == v.e);
}
void input(){
s.input();
e.input();
}
void adjust(){//以后让e作为较大的点
if(e < s) swap(s,e);
}
//求线段长度
double length(){
return s.dis(e);
}
//返回直线倾斜角
double angle(){
double k = atan2(e.y - s.y, e.x - s.x);
if(sgn(k) < 0) k += pi;//如果是负的,加上180度,得到补角因为直线倾斜角在0-180度
if(sgn(k-pi) == 0) k -= pi;//如果是180度就变成0度
return k;
}
};
1.点和直线的位置关系
利用叉积巧妙解决
在左侧
在右侧
其他说明在线上
模板:
//点和直线关系
//1 在左侧
//2 在右侧
//3 在直线上
int relation(Point p){
int c = sgn((p - s) ^ (e - s));
if(c < 0) return 1;
else if(c > 0) return 2;
else return 3;
}
2.点和线段的位置关系
叉积和点积的结合判断
先用叉积判断是否在直线上,如上面所说
再用点积判断是否在e,s两点之间
计算点积 的正负
如果在线段上一定为负否则一定为正
模板:
//点在线段上的判断
bool pointonseg(Point p){
return sgn((p - s) ^ (e - s)) == 0 && sgn((p - s) * (p - e)) <= 0;//前面判断在直线上,后面判断在两点间
}
3.点在射线上
同理先判断在直线上然后用点积
大于等于0说明在射线上
模板:
//点在射线上的判断
bool pointonray(Point p){
return sgn((p - s) ^ (e - s)) == 0 && sgn((p - s) * (e - s)) >= 0;
}
4.两线段的相交判断
首先需要了解几个概念
线段的规范相交: 交点在线段内部(不在任何一条线段的端点上).
线段的非规范相交: 交点在某条线段的端点.
其他情况就是不相交了
首先对于两条线段,先利用叉积判断是否相交
先按照图1,利用叉积看另一条线段点是否在这条线段的两侧
和
如果线段 两端点在线段 则两个叉积的符号相反
同理在按照图2,看是否线段端点都相互在另外一条线段两侧,如果成立就是规范相交
之后判断是否非规范相交,即有一个端点是交点
我们只拿一个例子来说明如图
这种情况是叉积
此时这种情况说明点v.s在在se所在直线上,我们只需要判断点v.s在线段se上就行,判断点在线段上的模板上面说了,其他四个点同理
模板:
//两线段相交判断
//2 规范相交
//1 非规范相交
//0 不相交
int segcrossseg(Line v){
int d1 = sgn((e - s) ^ (v.s - s));
int d2 = sgn((e - s) ^ (v.e - s));
int d3 = sgn((v.e - v.s) ^ (s - v.s));
int d4 = sgn((v.e - v.s) ^ (e - v.s));
if((d1 ^ d2) == -2 && (d3 ^ d4) == -2) return 2;//1^-1 = -2
return (d1 == 0 && sgn((v.s - s) * (v.s - e)) <= 0) ||
(d2 == 0 && sgn((v.e - s) * (v.e - e)) <= 0) ||
(d3 == 0 && sgn((s - v.s) * (s - v.e)) <= 0) ||
(d4 == 0 && sgn((e - v.s) * (e - v.e)) <= 0);
}
5.直线和线段的相交判断
这个更加容易,判断条件减少,只需要判断线段两端点在直线两侧就行了,以为直线无限延伸一定可以相交
模板:
//直线和线段相交判断
//-*this line -v seg
//2 规范相交
//1 非规范相交
//0 不相交
int linecrossseg(Line v){
int d1 = sgn((e - s) * (v.s - s));
int d2 = sgn((e - s) * (v.e - s));
if((d1 ^ d2) == -2) return 2;
return (d1 == 0 || d2 == 0);
}
7.两向量平行
直接判断叉积为0
模板:
//两向量平行
bool parallel(Line v){
return sgn((e - s) ^ (v.e - v.s)) == 0
}
8.两直线关系
模板:
//两直线关系
//0 平行
//1 重合
//2 相交
int linecrossline(Line v){
if((*this).parallel(v))
return v.relation(s) == 3;
return 2;
}
9.求两直线交点
一般来求两个支线的交点我们可以通过直线方程联立,但是那样写起来很麻烦,代码冗长,我们希望有一个通用的公式可以直接求解
下面介绍一种利用叉积计算交点的方法
首先先发出一个公式叫定比分点公式,这是高中的公式,可能给名字不太熟悉,但是下面给出公式一定是见过的,下面只给出坐标公式:
在平面直角坐标系内,已知两点 在两点连线上有一点P,设它的坐标为 且 那么我们说P分有向线段 的比为 我们将
当P为内分点时, ;当P为外分点时, ;当P与A重合时, ;当P与B重合时, 不存在
注意上面的公式说的是求有向线段的,而我们求得是直线的那么一定是内分点,所以 一定是正的
根据上面的图我们发现AP和BP的比值实际上就是绿色高的比值,其实是就是黄色三角形和蓝色三角形的面积比值,而面积比值等同于叉积的比值,所以我们有:
设
比值
注意因为我们求叉积的顺序,使得当前比值为负数即( )
所以将原来的加号变成减号就好了
模板:
//求两直线的交点
//要保证两直线不平行不重合
Point crosspoint(Line v){
double a1 = (v.e - v.s) ^ (s - v.s);
double a2 = (v.e - v.s) ^ (e - v.s);
return Point((s.x * a2 - e.x * a1) / (a2 - a1),(s.y * a2 - e.y * a1) / (a2 - a1));
}
10.求点到直线的距离
根据图片很容易看出,只需要求出叉积
然后除去se的长度就行了
模板:
//点到直线的距离
double dispointtoline(Point p){
return fabs((p - s) ^ (e - s)) / length();
}
11.点到线段的距离
先看能否向线段作垂线,能就和上面方法,一样,不能就是点到线段端点的距离
判断能否作垂线就是用点积看点p是否在两点之间
模板:
//点到线段的距离
double dispointtoseg(Point p){
if(sgn((p - s) * (e - s)) < 0 || sgn((p - e) * (s - e)) < 0)
return min(p.dis(s),p.dis(e));
return dispointtoline(p);
}
12.线段到线段的距离
//返回线段到线段的距离
//前提是两线段不相交,相交距离就是0了
double dissegtoseg(Line v){
return min(min(dispointtoseg(v.s),dispointtoseg(v.e)),min(v.dispointtoseg(s),v.dispointtoseg(e)));
}
13.点到直线上的投影
给点s的坐标加上长度为
的向量
即可
因此目标求长度为|sp’|的向量
这就是比值,即点s的坐标应该加的长度
模板:
//返回点在直线上的投影
Point lineprog(Point p){
return s + (((e - s) * ((e - s) * (p - s))) / ((e - s).len2()));
}
14.点p关于直线的对称点
首先根据上面的式子得到投影,然后用中点坐标公式求出对称点
中点坐标公式:
已知两点 ,设两点的中点为 中点公式为:
所以知道中点和一个点可以求另一个点
模板:
//返回点p关于直线的对称点
Point symmetrypoint(Point p){
Point q = lineprog(p);
return Point(2 * q.x - p.x, 2 * q.y - p.y);
}
以上便是关于直线的所有公式,下面是关于直线代码汇总(注意只是直线的汇总,里面用到点的一些方法,因此代码想跑需要和上面点的代码放一起才行,最后我会放上所有代码汇总可以运行的)
模板:
//用两点来存
struct Line{
Point s,e;
Line(){}
Line(Point _s,Point _e){
s = _s;
e = _e;
}
//根据一个点和倾斜角angle确定直线
Line(Point p,double angle){
s = p;
if(sgn(angle - pi / 2) == 0){
e = (s + Point(0,1));
}//斜率不存在,就是一条竖线
else{
e = (s + Point(1,tan(angle)));//x增加1,y增加tan,由tan=y/x,当x=1,y=tan
}
}
//ax+by+c=0
Line(double a,double b,double c){
if(sgn(a) == 0){//斜率为0,一条横线
s = Point(0,-c / b);
e = Point(1,-c / b);
}
else if(sgn(b) == 0){//斜率不存在,一条横线
s = Point(-c / a,0);
e = Point(-c / a,1);
}
else{//令x=0算一个点,令x=1算一个点
s = Point(0,-c / b);
e = Point(1,(-c - a) / b);
}
}
bool operator == (Line v){
return (s == v.s) && (e == v.e);
}
void input(){
s.input();
e.input();
}
void adjust(){
if(e < s) swap(s,e);
}
//求线段长度
double length(){
return s.dis(e);
}
//返回直线倾斜角
double angle(){
double k = atan2(e.y - s.y, e.x - s.x);
if(sgn(k) < 0) k += pi;
if(sgn(k-pi) == 0) k -= pi;
return k;
}
//点和直线关系
//1 在左侧
//2 在右侧
//3 在直线上
int relation(Point p){
int c = sgn((p - s) ^ (e - s));
if(c < 0) return 1;
else if(c > 0) return 2;
else return 3;
}
//点在线段上的判断
bool pointonseg(Point p){
return sgn((p - s) ^ (e - s)) == 0 && sgn((p - s) * (p - e)) <= 0;//前面判断在直线上,后面判断在两点间
}
//点在射线上的判断
bool pointonray(Point p){
return sgn((p - s) ^ (e - s)) == 0 && sgn((p - s) * (e - s)) >= 0;
}
//两向量平行
bool parallel(Line v){
return sgn((e - s) ^ (v.e - v.s)) == 0;
}
//两线段相交判断
//2 规范相交
//1 非规范相交
//0 不相交
int segcrossseg(Line v){
int d1 = sgn((e - s) ^ (v.s - s));
int d2 = sgn((e - s) ^ (v.e - s));
int d3 = sgn((v.e - v.s) ^ (s - v.s));
int d4 = sgn((v.e - v.s) ^ (e - v.s));
if((d1 ^ d2) == -2 && (d3 ^ d4) == -2) return 2;//1^-1 = -2
return (d1 == 0 && sgn((v.s - s) * (v.s - e)) <= 0) ||
(d2 == 0 && sgn((v.e - s) * (v.e - e)) <= 0) ||
(d3 == 0 && sgn((s - v.s) * (s - v.e)) <= 0) ||
(d4 == 0 && sgn((e - v.s) * (e - v.e)) <= 0);
}
//直线和线段相交判断
//-*this line -v seg
//2 规范相交
//1 非规范相交
//0 不相交
int linecrossseg(Line v){
int d1 = sgn((e - s) * (v.s - s));
int d2 = sgn((e - s) * (v.e - s));
if((d1 ^ d2) == -2) return 2;
return (d1 == 0 || d2 == 0);
}
//两直线关系
//0 平行
//1 重合
//2 相交
int linecrossline(Line v){
if((*this).parallel(v))
return v.relation(s) == 3;
return 2;
}
//求两直线的交点
//要保证两直线不平行不重合
Point crosspoint(Line v){
double a1 = (v.e - v.s) ^ (s - v.s);
double a2 = (v.e - v.s) ^ (e - v.s);
return Point((s.x * a2 - e.x * a1) / (a2 - a1),(s.y * a2 - e.y * a1) / (a2 - a1));
}
//点到直线的距离
double dispointtoline(Point p){
return fabs((p - s) ^ (e - s)) / length();
}
//点到线段的距离
double dispointtoseg(Point p){
if(sgn((p - s) * (e - s)) < 0 || sgn((p - e) * (s - e)) < 0)
return min(p.dis(s),p.dis(e));
return dispointtoline(p);
}
//返回线段到线段的距离
//前提是两线段不相交,相交距离就是0了
double dissegtoseg(Line v){
return min(min(dispointtoseg(v.s),dispointtoseg(v.e)),min(v.dispointtoseg(s),v.dispointtoseg(e)));
}
//返回点p在直线上的投影
Point lineprog(Point p){
return s + (((e - s) * ((e - s) * (p - s))) / ((e - s).len2()));
}
//返回点p关于直线的对称点
Point symmetrypoint(Point p){
Point q = lineprog(p);
return Point(2 * q.x - p.x, 2 * q.y - p.y);
}
};
三、关于圆的公式
首先还是圆结构体的基本定义和基本操作
struct circle{
Point p;//圆心
double r;//半径
circle(){}
circle(Point _p,double _r){
p = _p;
r = _r;
}
circle(double x,double y,double _r){
p = Point(x,y);
r = _r;
}
void input(){
p.input();
scanf("%lf",&r);
}
void output(){
printf("%.2f %.2f %.2f\n",p.x,p.y,r);
}
bool operator == (circle v){
return (p == v.p) && sgn(r - v.r) == 0;
}
bool operator < (circle v)const{
return ((p < v.p) || (p == v.p && sgn(r-v.r) < 0));
}
double area(){
return pi * r * r;
}
double circumference(){
return 2.0 * pi * r;
}
};
1.求三角形的外接圆和内切圆
由于这两个都是求圆,因此我们都把它们写成构造函数,为了进行区分,我们给求内切圆的构造函数多加一个缺省参数来进行区别
求三角形外接圆的方式是通过求出两条三角形的中垂线,然后求出交点p为圆心,半径为pa的长度
中垂线可以通过中点坐标求中点,然后对这条边左旋90度得到垂直的向量,然后以中点为起点即可
这些方法上面已经说过了,如果你前面已经认真看了,那么这里画画图应该很好理解
模板:
//三角形的外接圆,利用两条边的中垂线得到圆心
circle(Point a,Point b,Point c){
Line u = Line((a + b) / 2,((a + b) / 2) + ((b - a).rotleft()));
Line v = Line((b + c) / 2,((b + c) / 2) + ((c - b).rotleft()));
p = u.crosspoint(v);
r = p.dis(a);
}
对于内切圆来说方法和上面类似,只不过上面求两条中垂线变成了求两条角平分线,然后求交点就是圆心,圆心到三角形边的距离就是半径,利用点到直线的距离来求。不过我确实没有看懂,kuangbin模板上求角平分线的过程的原理,十分抱歉
模板:
//三角形的内切圆,利用两条角平分线得到圆心
circle(Point a,Point b,Point c,bool t){
Line u,v;
double m = atan2(b.y - a.y, b.x - a.x), n = atan2(c.y - a.y, c.x - a.x);
u.s = a;
u.e = u.s + Point(cos((n + m) / 2), sin(n + m) / 2);
v.s = b;
m = atan2(a.y - b.y, a.x - b.x), n = atan2(c.y - b.y, c.x - b.x);
v.e = v.s + Point(cos((n + m) / 2),sin((n + m) / 2));
p = u.crosspoint(v);
r = Line(a,b).dispointtoseg(p);
}
2.点和圆的关系
通过点到圆心的距离判断
//点和圆的关系
//0圆外 1圆上 2园内
int relation(Point b){
double dst = b.dis(p);
if(sgn(dst - r) < 0) return 2;
else if(sgn(dst - r) == 0) return 1;
return 0;
}
3.线段和圆的关系
比较的是圆心到线段的距离和半径的关系
//线段和圆的关系
//0 相离 1 相切 2 相交或圆内
int relationseg(Line v){
double dst = v.dispointtoseg(p);
if(sgn(dst - r) < 0) return 2;
else if(sgn(dst - r) == 0) return 1;
return 0;
}
4.直线和圆的关系
比较圆心到直线的距离和半径的关系
//直线和圆的关系
int relationline(Line v){
double dst = v.dispointtoline(p);
if(sgn(dst - r) < 0) return 2;
else if(sgn(dst - r) == 0) return 1;
return 0;
}
5.两圆关系
判断圆心距和半径和差的关系
//两圆关系
//5 相离
//4 外切
//3 相交
//2 内切
//1 内含
int relationcircle(circle v){
double d = p.dis(v.p);
if(sgn(d - r - v.r) > 0) return 5;
if(sgn(d - r - v.r) == 0) return 4;
double l = fabs(r - v.r);
if(sgn(d - r - v.r) < 0 && sgn(d - l) > 0) return 3;
if(sgn(d - l) == 0) return 2;
if(sgn(d - l) < 0) return 1;
}
6.求两圆的交点
首先根据上面判断两圆关系,如果没有交点直接返回
下面是对一般情况的讨论
如果使用方程求解将会十分麻烦,这里仍然是使用向量的办法
首先我们知道相交圆的一个性质,就是两个相交点的连线被圆心的连线垂直平分即
我们想要知道 的长度,这对我们相当重要,为什么重要呢?
只要我们知道了k点向量坐标,通过左旋90°和右旋90°,然后加上 长度就行了
首先根据余弦定理得到
所以
根据勾股定理可得 假设记为h
怎么得到k坐标呢
首先把向量 化成长度为 长度的向量,然后在p点基础上加上这个向量就行了,然后得到了k点,只需要左右旋转90°,但是现在长度仍然是 ,再化成h的长度就好了,这些函数前面都写过了
模板:
//求两个圆的交点,返回0表示没有交点,1是一个交点,2是两个交点
int pointcrosscircle(circle v,Point &p1,Point &p2){
int rel = relationcircle(v);
if(rel == 1 || rel == 5) return 0;
double d = p.dis(v.p);//圆心距
double l = (d * d + r * r - v.r * v.r) / (2 * d);
double h = sqrt(r * r - l * l);
Point tmp = p + (v.p - p).turn(l);
p1 = tmp + ((v.p - p).rotleft().turn(h));
p2 = tmp + ((v.p - p).rotright().turn(h));
if(rel == 2 || rel == 4)
return 1;
return 2;
}
7.求直线和圆的交点,返回交点个数
做法和上面做法类似
同样是得到a点,用特定长度的向量相加减得到点坐标
模板:
//求直线和圆的交点,返回交点个数
int pointcrossline(Line v,Point &p1,Point &p2){
if(!(*this).relationline(v)) return 0;
Point a = v.lineprog(p);
double d = v.dispointtoline(p);
d = sqrt(r * r - d * d);
if(sgn(d) == 0){
p1 = a;
p2 = a;
return 1;
}
p1 = a + (v.e - v.s).turn(d);
p2 = a - (v.e - v.s).turn(d);
return 2;
}
8.得到过a,b两点,半径为r1的两个圆
emmmmmm。。。。这个没看懂求得啥
模板:
//得到过a,b两点,半径r1的两个圆
int getcircel(Point a,Point b,double r1,circle &c1,circle &c2){
circle x(a,r1),y(b,r1);
int t = x.pointcrosscircle(y,c1.p,c2.p);
if(!t) return 0;
c1.r = c2.r = r;
return t;
}
9.得到与直线u相切,过点q,半径为r1的圆
//得到与直线u相切,过点q,半径为r1的圆
int getcircle(Line u,Point q,double r1,circle &c1,circle &c2){
double dis = u.dispointtoline(q);
if(sgn(dis - r1 * 2) > 0) return 0;
if(sgn(dis) == 0){
c1.p = q + ((u.e - u.s).rotleft().turn(r1));
c2.p = q + ((u.e - u.s).rotright().turn(r1));
c1.r = c2.r = r1;
return 2;
}
Line u1 = Line((u.s + (u.e - u.s).rotleft().turn(r1)),(u.e + (u.e - u.s).rotleft().turn(r1)));
Line u2 = Line((u.s + (u.e - u.s).rotright().turn(r1)),(u.e + (u.e - u.s).rotright().turn(r1)));
circle cc = circle(q,r1);
Point p1,p2;
if(!cc.pointcrossline(u1,p1,p2))
cc.pointcrossline(u2,p1,p2);
c1 = circle(p1,r1);
if(p1 == p2){
c2 = c1;
return 1;
}
c2 = circle(p2,r1);
return 2;
}
10.11.同时与直线 u,v 相切,半径为 r1 的圆,同时与不相交圆 cx,cy 相切,半径为 r1 的圆
//同时与直线 u,v 相切,半径为 r1 的圆
//测试:UVA12304
int getcircle(Line u,Line v,double r1,circle &c1,circle &c2, circle &c3,circle &c4){
if(u.parallel(v))return 0;//两直线平行
Line u1 = Line(u.s + (u.e - u.s).rotleft().turn(r1),u.e + (u.e - u.s).rotleft().turn(r1));
Line u2 = Line(u.s + (u.e - u.s).rotright().turn(r1),u.e + (u.e - u.s).rotright().turn(r1));
Line v1 = Line(v.s + (v.e - v.s).rotleft().turn(r1),v.e + (v.e - v.s).rotleft().turn(r1));
Line v2 = Line(v.s + (v.e - v.s).rotright().turn(r1),v.e + (v.e - v.s).rotright().turn(r1));
c1.r = c2.r = c3.r = c4.r = r1;
c1.p = u1.crosspoint(v1);
c2.p = u1.crosspoint(v2);
c3.p = u2.crosspoint(v1);
c4.p = u2.crosspoint(v2);
return 4;
}
//同时与不相交圆 cx,cy 相切,半径为 r1 的圆
//测试:UVA12304
int getcircle(circle cx,circle cy,double r1,circle &c1,circle & c2){
circle x(cx.p,r1+cx.r),y(cy.p,r1+cy.r);
int t = x.pointcrosscircle(y,c1.p,c2.p);
if(!t)return 0;
c1.r = c2.r = r1;
return t;
}
12.过一点作圆的切线
通过求出红色线长度和绿色线长度,利用向量旋转得到
的坐标这样
两条线就得到了
先看点的位置
模板:
//过一点作圆的切线(先判断点和圆的关系)
int tangentline(Point q,Line &u,Line &v){
int x = relation(q);
if(x == 2) return 0;
if(x == 1){
u = Line(q, q + (q - p).rotleft());
v = u;
return 1;
}
double d = p.dis(q);
double l = r * r / d;
double h = sqrt(r * r - l * l);
u = Line(q, p + ((q - p).turn(l) + (q - p).rotleft().turn(h)));
v = Line(q, p + ((q - p).turn(l) + (q - p).rotright().turn(h)));
return 2;
}
13.求相交圆的面积
一般情况
通过求出扇形面积和,在减去三角形面积,最后乘2,因为上下对称
其中三角形面积可利用海伦公式求
abc分别是三角形三条边长
相内切,面积为较小圆的面积,否则为0
//求两圆相交的面积
double areacircle(circle v){
int rel = relationcircle(v);
if(rel >= 4) return 0.0;
if(rel <= 2) return min(area(),v.area());
double d = p.dis(v.p);
double hf = (r + v.r + d) / 2.0;
double ss = 2 * sqrt(hf * (hf - r) * (hf - v.r) * (hf - d));//海伦公式求三角形面积
double a1 = acos((r * r + d * d - v.r * v.r) / (2.0 * r * d));
a1 = a1 * r * r;
double a2 = acos((v.r * v.r + d * d - r * r) / (2.0 * v.r * d));
a2 = a2 * v.r * v.r;
return a1 + a2 - ss;
}
14.求圆和三角形pab的相交面积
//求圆和三角形 pab 的相交面积
//测试:POJ3675 HDU3982 HDU2892
double areatriangle(Point a,Point b){
if(sgn((p - a)^(p - b)) == 0)return 0.0;
Point q[5];
int len = 0;
q[len++] = a;
Line l(a,b);
Point p1,p2;
if(pointcrossline(l,q[1],q[2])==2){
if(sgn((a - q[1])*(b - q[1]))<0)q[len++] = q[1];
if(sgn((a - q[2])*(b - q[2]))<0)q[len++] = q[2];
}
q[len++] = b;
if(len == 4 && sgn((q[0] - q[1])*(q[2] - q[1]))>0) swap(q[1],q [2]);
double res = 0;
for(int i = 0;i < len - 1;i++){
if(relation(q[i])==0||relation(q[i+1])==0){
double arg = p.rad(q[i],q[i+1]);
res += r*r*arg/2.0;
}
else{
res += fabs((q[i]-p)^(q[i+1]-p))/2.0;
}
}
return res;
}
与圆相关代码汇总
struct circle{
Point p;//圆心
double r;//半径
circle(){}
circle(Point _p,double _r){
p = _p;
r = _r;
}
circle(double x,double y,double _r){
p = Point(x,y);
r = _r;
}
//三角形的外接圆,利用两条边的中垂线得到圆心
circle(Point a,Point b,Point c){
Line u = Line((a + b) / 2,((a + b) / 2) + ((b - a).rotleft()));
Line v = Line((b + c) / 2,((b + c) / 2) + ((c - b).rotleft()));
p = u.crosspoint(v);
r = p.dis(a);
}
//三角形的内切圆,利用两条角平分线得到圆心
circle(Point a,Point b,Point c,bool t){
Line u,v;
double m = atan2(b.y - a.y, b.x - a.x), n = atan2(c.y - a.y, c.x - a.x);
u.s = a;
u.e = u.s + Point(cos((n + m) / 2), sin(n + m) / 2);
v.s = b;
m = atan2(a.y - b.y, a.x - b.x), n = atan2(c.y - b.y, c.x - b.x);
v.e = v.s + Point(cos((n + m) / 2),sin((n + m) / 2));
p = u.crosspoint(v);
r = Line(a,b).dispointtoseg(p);
}
void input(){
p.input();
scanf("%lf",&r);
}
void output(){
printf("%.2f %.2f %.2f\n",p.x,p.y,r);
}
bool operator == (circle v){
return (p == v.p) && sgn(r - v.r) == 0;
}
bool operator < (circle v)const{
return ((p < v.p) || (p == v.p && sgn(r-v.r) < 0));
}
double area(){
return pi * r * r;
}
double circumference(){
return 2.0 * pi * r;
}
//点和圆的关系
//0圆外 1圆上 2园内
int relation(Point b){
double dst = b.dis(p);
if(sgn(dst - r) < 0) return 2;
else if(sgn(dst - r) == 0) return 1;
return 0;
}
//线段和圆的关系
//0 相离 1 相切 2 相交或圆内
int relationseg(Line v){
double dst = v.dispointtoseg(p);
if(sgn(dst - r) < 0) return 2;
else if(sgn(dst - r) == 0) return 1;
return 0;
}
//直线和圆的关系
int relationline(Line v){
double dst = v.dispointtoline(p);
if(sgn(dst - r) < 0) return 2;
else if(sgn(dst - r) == 0) return 1;
return 0;
}
//两圆关系
//5 相离
//4 外切
//3 相交
//2 内切
//1 内含
int relationcircle(circle v){
double d = p.dis(v.p);
if(sgn(d - r - v.r) > 0) return 5;
if(sgn(d - r - v.r) == 0) return 4;
double l = fabs(r - v.r);
if(sgn(d - r - v.r) < 0 && sgn(d - l) > 0) return 3;
if(sgn(d - l) == 0) return 2;
if(sgn(d - l) < 0) return 1;
}
//求两个圆的交点,返回0表示没有交点,1是一个交点,2是两个交点
int pointcrosscircle(circle v,Point &p1,Point &p2){
int rel = relationcircle(v);
if(rel == 1 || rel == 5) return 0;
double d = p.dis(v.p);//圆心距
double l = (d * d + r * r - v.r * v.r) / (2 * d);
double h = sqrt(r * r - l * l);
Point tmp = p + (v.p - p).turn(l);
p1 = tmp + ((v.p - p).rotleft().turn(h));
p2 = tmp + ((v.p - p).rotright().turn(h));
if(rel == 2 || rel == 4)
return 1;
return 2;
}
//求直线和圆的交点,返回交点个数
int pointcrossline(Line v,Point &p1,Point &p2){
if(!(*this).relationline(v)) return 0;
Point a = v.lineprog(p);
double d = v.dispointtoline(p);
d = sqrt(r * r - d * d);
if(sgn(d) == 0){
p1 = a;
p2 = a;
return 1;
}
p1 = a + (v.e - v.s).turn(d);
p2 = a - (v.e - v.s).turn(d);
return 2;
}
//得到过a,b两点,半径r1的两个圆
int getcircle(Point a,Point b,double r1,circle &c1,circle &c2){
circle x(a,r1),y(b,r1);
int t = x.pointcrosscircle(y,c1.p,c2.p);
if(!t) return 0;
c1.r = c2.r = r;
return t;
}
//得到与直线u相切,过点q,半径为r1的圆
int getcircle(Line u,Point q,double r1,circle &c1,circle &c2){
double dis = u.dispointtoline(q);
if(sgn(dis - r1 * 2) > 0) return 0;
if(sgn(dis) == 0){
c1.p = q + ((u.e - u.s).rotleft().turn(r1));
c2.p = q + ((u.e - u.s).rotright().turn(r1));
c1.r = c2.r = r1;
return 2;
}
Line u1 = Line((u.s + (u.e - u.s).rotleft().turn(r1)),(u.e + (u.e - u.s).rotleft().turn(r1)));
Line u2 = Line((u.s + (u.e - u.s).rotright().turn(r1)),(u.e + (u.e - u.s).rotright().turn(r1)));
circle cc = circle(q,r1);
Point p1,p2;
if(!cc.pointcrossline(u1,p1,p2))
cc.pointcrossline(u2,p1,p2);
c1 = circle(p1,r1);
if(p1 == p2){
c2 = c1;
return 1;
}
c2 = circle(p2,r1);
return 2;
}
//同时与直线 u,v 相切,半径为 r1 的圆
//测试:UVA12304
int getcircle(Line u,Line v,double r1,circle &c1,circle &c2, circle &c3,circle &c4){
if(u.parallel(v))return 0;//两直线平行
Line u1 = Line(u.s + (u.e - u.s).rotleft().turn(r1),u.e + (u.e - u.s).rotleft().turn(r1));
Line u2 = Line(u.s + (u.e - u.s).rotright().turn(r1),u.e + (u.e - u.s).rotright().turn(r1));
Line v1 = Line(v.s + (v.e - v.s).rotleft().turn(r1),v.e + (v.e - v.s).rotleft().turn(r1));
Line v2 = Line(v.s + (v.e - v.s).rotright().turn(r1),v.e + (v.e - v.s).rotright().turn(r1));
c1.r = c2.r = c3.r = c4.r = r1;
c1.p = u1.crosspoint(v1);
c2.p = u1.crosspoint(v2);
c3.p = u2.crosspoint(v1);
c4.p = u2.crosspoint(v2);
return 4;
}
//同时与不相交圆 cx,cy 相切,半径为 r1 的圆
//测试:UVA12304
int getcircle(circle cx,circle cy,double r1,circle &c1,circle & c2){
circle x(cx.p,r1+cx.r),y(cy.p,r1+cy.r);
int t = x.pointcrosscircle(y,c1.p,c2.p);
if(!t)return 0;
c1.r = c2.r = r1;
return t;
}
//过一点作圆的切线(先判断点和圆的关系)
int tangentline(Point q,Line &u,Line &v){
int x = relation(q);
if(x == 2) return 0;
if(x == 1){
u = Line(q, q + (q - p).rotleft());
v = u;
return 1;
}
double d = p.dis(q);
double l = r * r / d;
double h = sqrt(r * r - l * l);
u = Line(q, p + ((q - p).turn(l) + (q - p).rotleft().turn(h)));
v = Line(q, p + ((q - p).turn(l) + (q - p).rotright().turn(h)));
return 2;
}
//求两圆相交的面积
double areacircle(circle v){
int rel = relationcircle(v);
if(rel >= 4) return 0.0;
if(rel <= 2) return min(area(),v.area());
double d = p.dis(v.p);
double hf = (r + v.r + d) / 2.0;
double ss = 2 * sqrt(hf * (hf - r) * (hf - v.r) * (hf - d));//海伦公式求三角形面积
double a1 = acos((r * r + d * d - v.r * v.r) / (2.0 * r * d));
a1 = a1 * r * r;
double a2 = acos((v.r * v.r + d * d - r * r) / (2.0 * v.r * d));
a2 = a2 * v.r * v.r;
return a1 + a2 - ss;
}
//求圆和三角形 pab 的相交面积
//测试:POJ3675 HDU3982 HDU2892
double areatriangle(Point a,Point b){
if(sgn((p - a)^(p - b)) == 0)return 0.0;
Point q[5];
int len = 0;
q[len++] = a;
Line l(a,b);
Point p1,p2;
if(pointcrossline(l,q[1],q[2])==2){
if(sgn((a - q[1])*(b - q[1]))<0)q[len++] = q[1];
if(sgn((a - q[2])*(b - q[2]))<0)q[len++] = q[2];
}
q[len++] = b;
if(len == 4 && sgn((q[0] - q[1])*(q[2] - q[1]))>0) swap(q[1],q [2]);
double res = 0;
for(int i = 0;i < len - 1;i++){
if(relation(q[i])==0||relation(q[i+1])==0){
double arg = p.rad(q[i],q[i+1]);
res += r*r*arg/2.0;
}
else{
res += fabs((q[i]-p)^(q[i+1]-p))/2.0;
}
}
return res;
}
};
所有模板代码:
#include <bits/stdc++.h>
using namespace std;
const double eps = 1e8;
const double inf = 1e20;
const double pi = acos( 1.0);//圆周率
const int maxp = 1010;
//和0比较大小的函数
int sgn(double x){
if(fabs(x) < eps)return 0;//等于0
if(x < 0)return -1;//小于0
else return 1; //大于0
}
//浮点数平方
inline double sqr(double x){return x*x;}
struct Point{
double x,y;
Point(){}
Point(double _x,double _y){
x = _x;
y = _y;
}//构造函数
void input(){//输入
scanf("%lf%lf",&x,&y);
}
void output(){//输出
printf("%.2f %.2f\n",x,y);//保留位数可自己控制
}
bool operator == (Point b)const{//横纵坐标均相等
return sgn(x - b.x) == 0 && sgn(y - b.y) == 0;
}
bool operator < (Point b)const{//先比横坐标,相同在比较纵坐标
return sgn(x - b.x) == 0 ? sgn(y - b.y) < 0 : x < b.x;
}
Point operator - (const Point &b)const{
return Point(x - b.x, y - b.y);
}
Point operator + (const Point &b)const{
return Point(x + b.x, y + b.y);
}
//叉积
double operator ^ (const Point &b)const{
return x * b.y - y * b.x;
}
//点积
double operator * (const Point &b)const{
return x * b.x + y * b.y;
}
//数乘
Point operator * (const double &k)const{
return Point(x * k, y * k);
}
Point operator / (const double &k)const{
return Point(x / k, y / k);
}
//返回长度
double len(){
return hypot(x,y);//<math.h>中函数,给定直角三角形两直角边求出斜边长度
}
//返回长度平方
double len2(){
return x * x + y * y;
}
//返回两点距离
double dis(Point p){
return hypot(x - p.x, y - p.y);
}
//计算pa和pb的夹角
double rad(Point a,Point b){
Point p = *this;
return fabs(atan2(fabs((a - p) ^ (b - p)),(a - p) * (b - p)));
}
//化为长度为r的向量
Point turn(double r){
double l = len();
if(!sgn(l)) return *this;//如果原来长度为0,直接返回这个点
r /= l;
return Point(x * r,y * r);
}
//逆时针旋转90
Point rotleft(){
return Point(-y,x);
}
//顺时针旋转90
Point rotright(){
return Point(y,-x);
}
//绕p点逆时针旋转angle
Point rot(Point p,double angle){
Point v = (*this) - p;
double c = cos(angle), s = sin(angle);
return Point(p.x + v.x * c - v.y * s, p.y + v.x * s + v.y * c);
}
};
//用两点来存
struct Line{
Point s,e;
Line(){}
Line(Point _s,Point _e){
s = _s;
e = _e;
}
//根据一个点和倾斜角angle确定直线
Line(Point p,double angle){
s = p;
if(sgn(angle - pi / 2) == 0){
e = (s + Point(0,1));
}//斜率不存在,就是一条竖线
else{
e = (s + Point(1,tan(angle)));//x增加1,y增加tan,由tan=y/x,当x=1,y=tan
}
}
//ax+by+c=0
Line(double a,double b,double c){
if(sgn(a) == 0){//斜率为0,一条横线
s = Point(0,-c / b);
e = Point(1,-c / b);
}
else if(sgn(b) == 0){//斜率不存在,一条横线
s = Point(-c / a,0);
e = Point(-c / a,1);
}
else{//令x=0算一个点,令x=1算一个点
s = Point(0,-c / b);
e = Point(1,(-c - a) / b);
}
}
bool operator == (Line v){
return (s == v.s) && (e == v.e);
}
void input(){
s.input();
e.input();
}
void adjust(){
if(e < s) swap(s,e);
}
//求线段长度
double length(){
return s.dis(e);
}
//返回直线倾斜角
double angle(){
double k = atan2(e.y - s.y, e.x - s.x);
if(sgn(k) < 0) k += pi;
if(sgn(k-pi) == 0) k -= pi;
return k;
}
//点和直线关系
//1 在左侧
//2 在右侧
//3 在直线上
int relation(Point p){
int c = sgn((p - s) ^ (e - s));
if(c < 0) return 1;
else if(c > 0) return 2;
else return 3;
}
//点在线段上的判断
bool pointonseg(Point p){
return sgn((p - s) ^ (e - s)) == 0 && sgn((p - s) * (p - e)) <= 0;//前面判断在直线上,后面判断在两点间
}
//点在射线上的判断
bool pointonray(Point p){
return sgn((p - s) ^ (e - s)) == 0 && sgn((p - s) * (e - s)) >= 0;
}
//两向量平行
bool parallel(Line v){
return sgn((e - s) ^ (v.e - v.s)) == 0;
}
//两线段相交判断
//2 规范相交
//1 非规范相交
//0 不相交
int segcrossseg(Line v){
int d1 = sgn((e - s) ^ (v.s - s));
int d2 = sgn((e - s) ^ (v.e - s));
int d3 = sgn((v.e - v.s) ^ (s - v.s));
int d4 = sgn((v.e - v.s) ^ (e - v.s));
if((d1 ^ d2) == -2 && (d3 ^ d4) == -2) return 2;//1^-1 = -2
return (d1 == 0 && sgn((v.s - s) * (v.s - e)) <= 0) ||
(d2 == 0 && sgn((v.e - s) * (v.e - e)) <= 0) ||
(d3 == 0 && sgn((s - v.s) * (s - v.e)) <= 0) ||
(d4 == 0 && sgn((e - v.s) * (e - v.e)) <= 0);
}
//直线和线段相交判断
//-*this line -v seg
//2 规范相交
//1 非规范相交
//0 不相交
int linecrossseg(Line v){
int d1 = sgn((e - s) * (v.s - s));
int d2 = sgn((e - s) * (v.e - s));
if((d1 ^ d2) == -2) return 2;
return (d1 == 0 || d2 == 0);
}
//两直线关系
//0 平行
//1 重合
//2 相交
int linecrossline(Line v){
if((*this).parallel(v))
return v.relation(s) == 3;
return 2;
}
//求两直线的交点
//要保证两直线不平行不重合
Point crosspoint(Line v){
double a1 = (v.e - v.s) ^ (s - v.s);
double a2 = (v.e - v.s) ^ (e - v.s);
return Point((s.x * a2 - e.x * a1) / (a2 - a1),(s.y * a2 - e.y * a1) / (a2 - a1));
}
//点到直线的距离
double dispointtoline(Point p){
return fabs((p - s) ^ (e - s)) / length();
}
//点到线段的距离
double dispointtoseg(Point p){
if(sgn((p - s) * (e - s)) < 0 || sgn((p - e) * (s - e)) < 0)
return min(p.dis(s),p.dis(e));
return dispointtoline(p);
}
//返回线段到线段的距离
//前提是两线段不相交,相交距离就是0了
double dissegtoseg(Line v){
return min(min(dispointtoseg(v.s),dispointtoseg(v.e)),min(v.dispointtoseg(s),v.dispointtoseg(e)));
}
//返回点p在直线上的投影
Point lineprog(Point p){
return s + (((e - s) * ((e - s) * (p - s))) / ((e - s).len2()));
}
//返回点p关于直线的对称点
Point symmetrypoint(Point p){
Point q = lineprog(p);
return Point(2 * q.x - p.x, 2 * q.y - p.y);
}
};
struct circle{
Point p;//圆心
double r;//半径
circle(){}
circle(Point _p,double _r){
p = _p;
r = _r;
}
circle(double x,double y,double _r){
p = Point(x,y);
r = _r;
}
//三角形的外接圆,利用两条边的中垂线得到圆心
circle(Point a,Point b,Point c){
Line u = Line((a + b) / 2,((a + b) / 2) + ((b - a).rotleft()));
Line v = Line((b + c) / 2,((b + c) / 2) + ((c - b).rotleft()));
p = u.crosspoint(v);
r = p.dis(a);
}
//三角形的内切圆,利用两条角平分线得到圆心
circle(Point a,Point b,Point c,bool t){
Line u,v;
double m = atan2(b.y - a.y, b.x - a.x), n = atan2(c.y - a.y, c.x - a.x);
u.s = a;
u.e = u.s + Point(cos((n + m) / 2), sin(n + m) / 2);
v.s = b;
m = atan2(a.y - b.y, a.x - b.x), n = atan2(c.y - b.y, c.x - b.x);
v.e = v.s + Point(cos((n + m) / 2),sin((n + m) / 2));
p = u.crosspoint(v);
r = Line(a,b).dispointtoseg(p);
}
void input(){
p.input();
scanf("%lf",&r);
}
void output(){
printf("%.2f %.2f %.2f\n",p.x,p.y,r);
}
bool operator == (circle v){
return (p == v.p) && sgn(r - v.r) == 0;
}
bool operator < (circle v)const{
return ((p < v.p) || (p == v.p && sgn(r-v.r) < 0));
}
double area(){
return pi * r * r;
}
double circumference(){
return 2.0 * pi * r;
}
//点和圆的关系
//0圆外 1圆上 2园内
int relation(Point b){
double dst = b.dis(p);
if(sgn(dst - r) < 0) return 2;
else if(sgn(dst - r) == 0) return 1;
return 0;
}
//线段和圆的关系
//0 相离 1 相切 2 相交或圆内
int relationseg(Line v){
double dst = v.dispointtoseg(p);
if(sgn(dst - r) < 0) return 2;
else if(sgn(dst - r) == 0) return 1;
return 0;
}
//直线和圆的关系
int relationline(Line v){
double dst = v.dispointtoline(p);
if(sgn(dst - r) < 0) return 2;
else if(sgn(dst - r) == 0) return 1;
return 0;
}
//两圆关系
//5 相离
//4 外切
//3 相交
//2 内切
//1 内含
int relationcircle(circle v){
double d = p.dis(v.p);
if(sgn(d - r - v.r) > 0) return 5;
if(sgn(d - r - v.r) == 0) return 4;
double l = fabs(r - v.r);
if(sgn(d - r - v.r) < 0 && sgn(d - l) > 0) return 3;
if(sgn(d - l) == 0) return 2;
if(sgn(d - l) < 0) return 1;
}
//求两个圆的交点,返回0表示没有交点,1是一个交点,2是两个交点
int pointcrosscircle(circle v,Point &p1,Point &p2){
int rel = relationcircle(v);
if(rel == 1 || rel == 5) return 0;
double d = p.dis(v.p);//圆心距
double l = (d * d + r * r - v.r * v.r) / (2 * d);
double h = sqrt(r * r - l * l);
Point tmp = p + (v.p - p).turn(l);
p1 = tmp + ((v.p - p).rotleft().turn(h));
p2 = tmp + ((v.p - p).rotright().turn(h));
if(rel == 2 || rel == 4)
return 1;
return 2;
}
//求直线和圆的交点,返回交点个数
int pointcrossline(Line v,Point &p1,Point &p2){
if(!(*this).relationline(v)) return 0;
Point a = v.lineprog(p);
double d = v.dispointtoline(p);
d = sqrt(r * r - d * d);
if(sgn(d) == 0){
p1 = a;
p2 = a;
return 1;
}
p1 = a + (v.e - v.s).turn(d);
p2 = a - (v.e - v.s).turn(d);
return 2;
}
//得到过a,b两点,半径r1的两个圆
int getcircle(Point a,Point b,double r1,circle &c1,circle &c2){
circle x(a,r1),y(b,r1);
int t = x.pointcrosscircle(y,c1.p,c2.p);
if(!t) return 0;
c1.r = c2.r = r;
return t;
}
//得到与直线u相切,过点q,半径为r1的圆
int getcircle(Line u,Point q,double r1,circle &c1,circle &c2){
double dis = u.dispointtoline(q);
if(sgn(dis - r1 * 2) > 0) return 0;
if(sgn(dis) == 0){
c1.p = q + ((u.e - u.s).rotleft().turn(r1));
c2.p = q + ((u.e - u.s).rotright().turn(r1));
c1.r = c2.r = r1;
return 2;
}
Line u1 = Line((u.s + (u.e - u.s).rotleft().turn(r1)),(u.e + (u.e - u.s).rotleft().turn(r1)));
Line u2 = Line((u.s + (u.e - u.s).rotright().turn(r1)),(u.e + (u.e - u.s).rotright().turn(r1)));
circle cc = circle(q,r1);
Point p1,p2;
if(!cc.pointcrossline(u1,p1,p2))
cc.pointcrossline(u2,p1,p2);
c1 = circle(p1,r1);
if(p1 == p2){
c2 = c1;
return 1;
}
c2 = circle(p2,r1);
return 2;
}
//同时与直线 u,v 相切,半径为 r1 的圆
//测试:UVA12304
int getcircle(Line u,Line v,double r1,circle &c1,circle &c2, circle &c3,circle &c4){
if(u.parallel(v))return 0;//两直线平行
Line u1 = Line(u.s + (u.e - u.s).rotleft().turn(r1),u.e + (u.e - u.s).rotleft().turn(r1));
Line u2 = Line(u.s + (u.e - u.s).rotright().turn(r1),u.e + (u.e - u.s).rotright().turn(r1));
Line v1 = Line(v.s + (v.e - v.s).rotleft().turn(r1),v.e + (v.e - v.s).rotleft().turn(r1));
Line v2 = Line(v.s + (v.e - v.s).rotright().turn(r1),v.e + (v.e - v.s).rotright().turn(r1));
c1.r = c2.r = c3.r = c4.r = r1;
c1.p = u1.crosspoint(v1);
c2.p = u1.crosspoint(v2);
c3.p = u2.crosspoint(v1);
c4.p = u2.crosspoint(v2);
return 4;
}
//同时与不相交圆 cx,cy 相切,半径为 r1 的圆
//测试:UVA12304
int getcircle(circle cx,circle cy,double r1,circle &c1,circle & c2){
circle x(cx.p,r1+cx.r),y(cy.p,r1+cy.r);
int t = x.pointcrosscircle(y,c1.p,c2.p);
if(!t)return 0;
c1.r = c2.r = r1;
return t;
}
//过一点作圆的切线(先判断点和圆的关系)
int tangentline(Point q,Line &u,Line &v){
int x = relation(q);
if(x == 2) return 0;
if(x == 1){
u = Line(q, q + (q - p).rotleft());
v = u;
return 1;
}
double d = p.dis(q);
double l = r * r / d;
double h = sqrt(r * r - l * l);
u = Line(q, p + ((q - p).turn(l) + (q - p).rotleft().turn(h)));
v = Line(q, p + ((q - p).turn(l) + (q - p).rotright().turn(h)));
return 2;
}
//求两圆相交的面积
double areacircle(circle v){
int rel = relationcircle(v);
if(rel >= 4) return 0.0;
if(rel <= 2) return min(area(),v.area());
double d = p.dis(v.p);
double hf = (r + v.r + d) / 2.0;
double ss = 2 * sqrt(hf * (hf - r) * (hf - v.r) * (hf - d));//海伦公式求三角形面积
double a1 = acos((r * r + d * d - v.r * v.r) / (2.0 * r * d));
a1 = a1 * r * r;
double a2 = acos((v.r * v.r + d * d - r * r) / (2.0 * v.r * d));
a2 = a2 * v.r * v.r;
return a1 + a2 - ss;
}
//求圆和三角形 pab 的相交面积
//测试:POJ3675 HDU3982 HDU2892
double areatriangle(Point a,Point b){
if(sgn((p - a)^(p - b)) == 0)return 0.0;
Point q[5];
int len = 0;
q[len++] = a;
Line l(a,b);
Point p1,p2;
if(pointcrossline(l,q[1],q[2])==2){
if(sgn((a - q[1])*(b - q[1]))<0)q[len++] = q[1];
if(sgn((a - q[2])*(b - q[2]))<0)q[len++] = q[2];
}
q[len++] = b;
if(len == 4 && sgn((q[0] - q[1])*(q[2] - q[1]))>0) swap(q[1],q [2]);
double res = 0;
for(int i = 0;i < len - 1;i++){
if(relation(q[i])==0||relation(q[i+1])==0){
double arg = p.rad(q[i],q[i+1]);
res += r*r*arg/2.0;
}
else{
res += fabs((q[i]-p)^(q[i+1]-p))/2.0;
}
}
return res;
}
};
int main(){
return 0;
}