const double PI = acos(-1);
int dcmp(double x) {
if(fabs(x) < eps) return 0;
else return x < 0 ? -1 : 1;
}
struct Point {
double x, y;
Point(double x = 0, double y = 0) : x(x), y(y) {}
};
double dist(const Point& a, const Point& b) {
return sqrt((a.x-b.x) * (a.x-b.x) + (a.y-b.y) * (a.y-b.y));
}
typedef Point Vector;
struct Circle {
Point c;
double r;
Circle(Point c = Point(0, 0), double r = 0):c(c),r(r){}
Point getPoint(double rad) {
return Point(cos(rad) * r + c.x, sin(rad) * r + c.y);
}
};
Point operator + (Vector A, Vector B) {return Point(A.x + B.x, A.y + B.y);}
Point operator - (Vector A, Vector B) {return Point(A.x - B.x, A.y - B.y);}
Point operator * (Vector A, double p) {return Point(A.x * p, A.y * p);}
Point operator / (Vector A, double p) {return Point(A.x / p, A.y / p);}
bool operator < (const Vector &A, const Vector &B) {return A.x < B.x || (A.x == B.x && A.y < B.y);}
bool operator == (const Vector &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;}
double Area2(Point A, Point B, Point C) {return Cross(B-A, C-A);}
Vector Normal(Vector A) {
double L = Length(A);
return Vector(-A.y/L, A.x/L);
}
Vector Rotate(Vector A, double rad) {
return Vector(A.x * cos(rad) - A.y * sin(rad), A.x * sin(rad) + A.y * cos(rad));
}
//凸包
int ConvexHull(Point *p, int n, Point *ch) {
sort(p, p + n);
int m = 0;
for(int i = 0; i < n; i++) {
while(m > 1 && dcmp(Cross(ch[m - 1] - ch[m - 2], p[i] - ch[m - 2])) <= 0) m--;
ch[m++] = p[i];
}
int k = m;
for(int i = n - 2; i >= 0; i--) {
while(m > k && dcmp(Cross(ch[m - 1] - ch[m - 2], p[i] - ch[m - 2])) <= 0) m--;
ch[m++] = p[i];
}
return m;
}
//两圆共切线
int getTangents(Circle A, Circle B, vector<Point>& a, vector<Point>& b) {
if(A.r < B.r) swap(A, B), swap(a, b);
double d2 = (A.c.x-B.c.x)*(A.c.x-B.c.x)+(A.c.y-B.c.y)*(A.c.y-B.c.y);
double rdiff = A.r - B.r;
double rsum = A.r + B.r;
if(dcmp(d2 - rdiff * rdiff) < 0) return 0;
double base = atan2(B.c.y-A.c.y,B.c.x-A.c.x);
if(d2 == 0 && dcmp(A.r - B.r) == 0) return -1;
if(dcmp(d2 - rdiff * rdiff) == 0) {
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(dcmp(d2 - rsum * rsum) == 0) {
a.push_back(A.getPoint(base)); b.push_back(B.getPoint(PI+base));
} else if(dcmp(d2 - rsum * rsum) > 0) {
double ang = acos((A.r + B.r) / sqrt(d2));
a.push_back(A.getPoint(base+ang)); b.push_back(B.getPoint(PI+base+ang));
a.push_back(A.getPoint(base-ang)); b.push_back(B.getPoint(PI+base-ang));
}
return (int)a.size();
}