/*
白书几何模板
*/
const double eps = 1e-10;
struct Point{
double x,y;//点的坐标类型自己定
Point(double x = 0,double y = 0):x(x),y(y){}
};
typedef Point Vector;//向量就是点的表示
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);
}
//以上重载操作符
int dcmp(double x){
if(fabs(x) < eps)return 0;//两数的减差小于eps就返回0
else return x < 0 ? -1 : 1;// < 输出-1 > 输出1
}
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 Length(Vector A){//向量的长度
return sqrt(Dot(A,A));
}
double Angle(Vector A,Vector B){//返回亮相两夹角的角度
return acos(Dot(A,B) / Length(A) / Length(B));
}
double Cross(Vector A,Vector B){//两向量叉乘
return A.x * B.y - A.y * B.x;
}
Vector Rotate(Vector A,double rad){//rad是弧度
return Vector(A.x * cos(rad) - A.y * sin(rad),A.x * sin(rad) + A.y * cos(rad));
}
Vector Normal(Vector A){//计算向量的单位法线,保证该向量为非0向量
double L = Length(A);
return Vector(-A.y / L,A.x / L);
}
Point GetLineIntersection(Point P,Vector v,Point Q,Vector w){//计算两直线的交点,确保两直线只有一个交点,且Cross(v,w)非零
Vector u = P - Q;
double t = Cross(w,u) / Cross(v,w);
return P + v * t;
}
double DistanceToLine(Point P,Point A,Point B){//直线为AB,计算点P到AB的距离
Vector v1 = B - A,v2 = P - A;
return fabs(Cross(v1,v2)) / Length(v1);//如果不取绝对值,得到的是有向距离
}
Point GetlLineProjection(Point P,Point A,Point B){
Vector v = B - A;
return A + v * (Dot(v,P - A) / Dot(v,v));
}
bool SegmentProperIntersection(Point a1,Point a2,Point b1,Point b2){//判断两线段是否相交,其中交点一定要恰好有一个,一个线段的某一点不在另一个线段的端点上
double c1 = Cross(a2 - a1,b1 - a1),c2 = Cross(a2 - a1,b2 - a1),
c3 = Cross(b2 - b1,a1 - b1),c4 = Cross(b2 - b1,a2 - b1);
return dcmp(c1) * dcmp(c2) < 0 && dcmp(c3) * dcmp(c4) < 0;
}//如果c1,c2同时为0,则说明两线段有部分重叠,如果不全为0,其中一个为0,则说明一个线段的端点在另一个线段上
bool OnSegment(Point p,Point a1,Point a2){//判断线段的端点是否在另一个线段上
return dcmp(Cross(a1 - p,a2 - p)) == 0 && dcmp(Dot(a1 - p,a2 - p)) < 0;
}
/*
以下为和圆有关的函数
*/
struct Circle{
Point c;
double r;
Circle(Point c,double r):c(c),r(r){}
Circle(){}
Point point(double a){//给出角度,求圆上的点
return Point(c.x + cos(a) * r,c.y + sin(a) * r);
}
};
//求圆和直线的交点,假设直线为AB,圆为c,得到修改的t1,t2,若存在的话,则交点P是A + ti * (B - A)
int getLineCircleIntersection(Point A,Point B,Circle c,double &t1,double &t2){
Vector v = B - A;//求出直线的向量
double a = v.x,b = A.x - c.c.x,c = v.y,d = A.y - c.c.y;
double e = a * a + c * c,f = 2 * (a * b + c * d),g = b * b + d * d - c.r * c.r;
double delta = f * f - 4 * e * g;
if(dcmp(delta) < 0)return 0;//相离
if(dcmp(delta) == 0){//相切
t1 = t2 = -f / (2 * e);
return 1;
}
//接下来是相交
t1 = (-f - sqrt(delta)) / (2 * e);
t2 = (-f + sqrt(delta)) / (2 * e);
}
//以下为求两圆的交点
double angle(Vector v){return atan2(v.y,v.x);}//其中atan2(y,x)表示出发点是原点,目标点是(x,y)的射线与x正半轴的夹角的角度
//如果有交点,设交点为P1,P2
int getCircleCircleIntersection(Circle C1,Circle C2,vector<Point> & sol){//其中sol存交点
double d = Length(C1.c - C2.c);
if(dcmp(d) == 0){//圆心重合
if(dcmp(C1.r - C2.r) == 0){
if(dcmp(C1.r - C2.r) == 0)return -1;//两圆重合
return 0;//大圆包含小圆,无交点
}
}
if(dcmp(C1.r + C2.r - d) < 0)return 0;//两圆半径相加小于距离,外离
if(dcmp(fabs(C1.r - C2.r) - d) > 0)return 0;//大圆包含小圆
double a = angle(C2.c - C1.c);//向量C1C2的极角
double da = acos((C1.r * C1.r + d * d - C2.r * C2.r) / (2 * C1.r * d));//C1C2到C1P1的角
Point p1 = C1.point(a - da),p2 = C1.point(a + da);
sol.push_back(p1);
if(p1 == p2)return 1;//相切
sol.push_back(p2);
return 2;
}
//以下为从一个点出发,求已知圆的切线
//过点p到圆c的切线,v[i]是第i条切线,返回切线数
int getTangents(Point p,Circle c,vector<Vector> &v){
Vector u = C.c - p;
double dist = Length(u);
if(dist < C.r)return 0;//点在圆内,无切线
else if(dcmp(dist - C.r) == 0){//p在圆上,只有一条切线
v.push_back(Rotate(u,PI / 2));//其中PI为常数3.1415926.....
return 1;
}else {
double ang = asin(C.r / dist);
v.push_back(Rotate(u,-ang));
v.push_back(Rotate(u,+ang));
return 2;
}
}
//以下为知道两个圆,求两个圆的公切线
int getTangents(Circle A,Circle B,vector<Point> &a,vector<Point> &b){
int cnt = 0;
if(A.r < B.r){swap(A,B);swap(a,b);}
int d2 = (A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y);
int rdiff = A.r - B.r;
int rsum = A.r + B.r;
if(d2 < rdiff * rdiff)return 0;//内含无切线
double base = atan2(B.y - A.y,B.x - A.x);
if(d2 == 0 && A.r == B.r)return -1;//两圆重合,无限多条切线
if(d2 == rdiff * rdiff){
a.push_back(A.getPoint(base));b.push_back(B.getPoint(base));
return 1;//内切,一条切线
}
//以上为一个圆在另一个园内,以下为有外公切线
double ang = acos((A.r - B.r) / sqrt(d2));
a.push_back(A.getPoint(base + ang));b.push_back(B.getPoint(base + ang));
a.push_back(A.getPoint(base - ang));b.push_back(B.getPoint(base - ang));
if(d2 == rsum * rsum){//一条内公切线,即两圆外切
a.push_back(A.getPoint(base));b.push_back(B.getPoint(base));
}else if(d2 > rsum * rsum){//两圆外离
double ang = acos((A.r + B.r) / sqrt(d2));
a.push_back(A.getPoint(base + ang));b.push_back(B.getPoint(PI + base + ang));//其中PI为圆周率常数
a.push_back(A.getPoint(base - ang));b.push_back(B.getPoint(PI + base - ang));
}
return cnt;//返回切线条数
}
白书几何模板
最新推荐文章于 2018-07-31 19:53:51 发布