与圆和切线的一些基础处理.
#include <algorithm>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
using namespace std;
#define eps 1e-10
#define MAXN 1001000
const double pi = acos(-1.0);
template <class T> inline T sqr(T a) { return a * a; }
inline int abs(const int x) { return x > 0 ? x : -x; };
inline double sig(const double x) { return (x > eps) - (x < -eps); };
inline double fabs(const double x) { return sig(x) > 0 ? x : -x; };
struct Point
{
double x, y;
Point() {}
Point(double _x, double _y): x(_x), y(_y) {}
void in();
Point v() const;
void out() const;
double len() const;
double len2() const;
Point rotate(double f) const;
Point operator *(double k) const;
Point operator /(double k) const;
double dis(const Point &argu) const;
double dis2(const Point &argu) const;
bool operator <(const Point &argu) const;
Point operator -(const Point &argu) const;
Point operator +(const Point &argu) const;
double operator ^(const Point &argu) const;
double operator *(const Point &argu) const;
};
struct Segment
{
Point a, b;
Segment() {}
Segment(Point _a, Point _b): a(_a), b(_b) {}
void in();
Point d() const;
void out() const;
double len() const;
double len2() const;
int sgn(const Segment &argu) const;
bool qrt(const Segment &argu) const;
double dis(const Point &argu) const;
double dis2(const Point &argu) const;
double dis(const Segment &argu) const;
double dis2(const Segment &argu) const;
double operator ^(const Segment &argu) const;
};
struct Line
{
Segment l;
Line() {}
Line(Segment _l): l(_l) {}
Line(Point _a, Point _b): l(Segment(_a, _b)) {}
double dis(const Line &argu) const;
double dis2(const Line &argu) const;
double dis(const Point &argu) const;
double dis2(const Point &argu) const;
double dis(const Segment &argu) const;
double dis2(const Segment &argu) const;
};
inline double Cross(const Point &o, const Point &a, const Point &b) { return (a - o) ^ (b - o); }
void Point::in() { scanf("%lf%lf", &x, &y); }
Point Point::v() const { return Point(-y, x); }
double Point::len() const { return sqrt(len2()); }
double Point::len2() const { return x * x + y * y; }
void Point::out() const{ printf("%.4lf %.4lf\n", x, y); }
double Point::dis(const Point &argu) const { return sqrt(dis2(argu)); }
Point Point::operator *(double k) const { return Point(x * k, y * k); }
Point Point::operator /(double k) const { return Point(x / k, y / k); }
double Point::operator ^(const Point &argu) const { return x * argu.y - y * argu.x; }
double Point::operator *(const Point &argu) const { return x * argu.x + y * argu.y; }
Point Point::operator -(const Point &argu) const { return Point(x - argu.x, y - argu.y); }
Point Point::operator +(const Point &argu) const { return Point(x + argu.x, y + argu.y); }
Point Point::rotate(double f) const { return Point(x * cos(f) - y * sin(f), y * cos(f) + x * sin(f)); }
bool Point::operator <(const Point &argu) const { return sig(x - argu.x) == 0 ? y < argu.y : x < argu.x; }
double Point::dis2(const Point &argu) const { return (x - argu.x) * (x - argu.x) + (y - argu.y) * (y - argu.y); }
void Segment::in() { a.in(), b.in(); }
Point Segment::d() const { return b - a; }
double Segment::len2() const { return d().len2(); }
double Segment::len() const { return sqrt(len2()); }
void Segment::out() const { a.out(), b.out(); }
double Segment::dis2(const Segment &argu) const
{
if(~sgn(argu)) return 0;
return min(min(dis2(argu.a), dis2(argu.b)), min(argu.dis2(a), argu.dis2(b)));
}
double Segment::dis2(const Point &argu) const
{
Point pa = argu - a, pb = argu - b;
if(sig(d() * pa) <= 0) return pa.len2(); if(sig(d() * pb) >= 0) return pb.len2();
Line l = Line((*this)); return l.dis2(argu);
}
int Segment::sgn(const Segment &argu) const
{
if(!qrt(argu)) return -1;
return sig(Cross(a, b, argu.a)) * sig(Cross(a, b, argu.b)) <= 0 &&
sig(Cross(argu.a, argu.b, a)) * sig(Cross(argu.a, argu.b, b)) <= 0 ? 1 : -1;
}
//快速排斥实验
bool Segment::qrt(const Segment &argu) const
{
return min(a.x, b.x) <= max(argu.a.x, argu.b.x) && min(a.y, b.y) <= max(argu.a.y, argu.b.y) &&
min(argu.a.x, argu.b.x) <= max(a.x, b.x) && min(argu.a.y, argu.b.y) <= max(a.y, b.y);
}
double Segment::dis(const Point &argu) const { return sqrt(dis2(argu)); }
double Segment::dis(const Segment &argu) const { return sqrt(dis2(argu)); }
double Line::dis(const Point &argu) const { return sqrt(dis2(argu)); }
double Line::dis2(const Point &argu) const { return sqr(fabs(l.d() ^ (argu - l.a))) / l.len2(); }
double Line::dis(const Segment &argu) const { return sqrt(dis2(argu)); }
double Line::dis2(const Segment &argu) const
{
Point v1 = argu.a - l.a, v2 = argu.b - l.b; double d1 = l.d() ^ v1, d2 = l.d() ^ v2;
return sig(d1) != sig(d2) ? 0 : sqr(min(fabs(d1), fabs(d2))) / l.len2();
}
struct Circle
{
Point o;
double r;
Circle() {}
Circle(Point _o, double _r): o(_o), r(_r) {}
Circle(double ox, double oy, double _r): o(Point(ox, oy)), r(_r) {}
void in();
Point getP(double x) const;
bool operator <(const Circle &argu) const;
};
void Circle::in() { scanf("%lf%lf%lf", &o.x, &o.y, &r); }
bool Circle::operator <(const Circle &argu) const { return sig(r - argu.r) < 0; }
Point Circle::getP(double f) const { return Point(o.x + r * cos(f), o.y + r * sin(f)); }
Point get_Intersection(const Point &u1, const Point &u2, const Point &v1, const Point &v2)
{
Point ret = u1;
double t = ((u1.x - v1.x) * (v1.y - v2.y) - (u1.y-v1.y) * (v1.x - v2.x))
/ ((u1.x - u2.x) * (v1.y - v2.y) - (u1.y - u2.y) * (v1.x - v2.x));
ret.x += (u2.x - u1.x) * t;
ret.y += (u2.y - u1.y) * t;
return ret;
}
Point FootPoint(const Point &p, const Line &ll)
{
Point tmp = p;
tmp = tmp + ll.l.d().v();
// if (((ll.l.a - p) ^ (tmp - p)) * ((ll.l.b - p) ^ (tmp - p)) > eps)
// return p.dis2(ll.l.a) < p.dis2(ll.l.b) ? ll.l.a : ll.l.b;
return get_Intersection(p, tmp, ll.l.a, ll.l.b);
}
Point Insp[2];
int Line_Intersect_Circle(const Circle &c, const Line &ll, Point p[])
{
double d2 = ll.dis2(c.o);
int sgn = sig(d2 - c.r * c.r);
if(sgn > 0) return 0;
if(sgn == 0) return -1;
int cnt = 0;
Point tmp = c.o;
tmp = tmp + ll.l.d().v();
tmp = get_Intersection(tmp, c.o, ll.l.a, ll.l.b);
double t = sqrt(c.r * c.r - tmp.dis2(c.o)) / ll.l.len();
p[cnt++] = Point(tmp.x + (ll.l.b.x - ll.l.a.x) * t, tmp.y + (ll.l.b.y - ll.l.a.y) * t);
p[cnt++] = Point(tmp.x - (ll.l.b.x - ll.l.a.x) * t, tmp.y - (ll.l.b.y - ll.l.a.y) * t);
return cnt;
}
int Circle_Intersect_Circle(const Circle &a, const Circle &b, Point p[])
{
double d2 = a.o.dis2(b.o);
double rdif = fabs(a.r - b.r);
if(sig(d2 - rdif * rdif) < 0 || sig(d2) == 0) return 0;
double u = (a.r * a.r - b.r * b.r) / (d2 + d2) + 0.5;
Point pa = a.o + (b.o - a.o) * u;
Point pb = pa + (b.o - a.o).v();
return Line_Intersect_Circle(a, Line(pa, pb), p);
}
Point Tanp[2];
//过园外一点作圆切线
int get_Tangents(const Circle &c, const Point &p, Point *Tan)
{
int sgn = sig(c.o.dis2(p) - c.r * c.r);
if(sgn < 0) return 0;
if(sgn == 0) return -1;
Circle c2 = Circle((c.o + p) / 2.0, c.o.dis(p) / 2.0);
return Circle_Intersect_Circle(c, c2, Tan);
}
Line Tanl[4];
//两圆公切线,a点在圆A上,b点在圆B上
int get_Tangents(const Circle &A, const Circle &B, Line *Tan)
{
if(sig(A.r - B.r) < 0) return get_Tangents(B, A, Tan);
int cnt = 0;
double d2 = A.o.dis2(B.o);
if(sig(d2) == 0 && sig(A.r - B.r) == 0) return -1; //1.重合
double rdif = A.r - B.r; //两园半径差
double rsum = A.r + B.r; //两园半径和
if(sig(d2) == 0 || sig(d2 - rdif * rdif) < 0) return 0; //2.内含
double base = atan2(B.o.y - A.o.y, B.o.x - A.o.x);
if(sig(d2 - rdif * rdif) == 0) //3.内切
{
Tan[cnt++] = Line(A.getP(base), B.getP(base));
return cnt;
}
double ang = acos(rdif / sqrt(d2));
Tan[cnt++] = Line(A.getP(base + ang), B.getP(base + ang));
Tan[cnt++] = Line(A.getP(base - ang), B.getP(base - ang));
if(sig(d2 - rsum * rsum) == 0) //4.外切
{
Tan[cnt++] = Line(A.getP(base), B.getP(base + pi));
}
else if(sig(d2 - rsum * rsum) > 0) //5.外离
{
ang = acos(rsum / sqrt(d2));
Tan[cnt++] = Line(A.getP(base + ang), B.getP(base + ang + pi));
Tan[cnt++] = Line(A.getP(base - ang), B.getP(base - ang + pi));
}
return cnt;
}
//角a的角平分线
Line get_Angle_Bisector(const Point &a, const Point &b, const Point &c)
{
Point s1 = b - a, s2 = c - a;
double m1 = s1.len(), m2 = s2.len();
Point t1 = Point(a.x + 100 * s1.x / m1, a.y + 100 * s1.y / s1.len());
Point t2 = Point(a.x + 100 * s2.x / m2, a.y + 100 * s2.y / s2.len());
Point a2 = (t1 + t2) / 2.0;
return Line(a, a2);
}
//内心
Point get_Inc(double &r, const Point &a, const Point &b, const Point &c)
{
double ea = c.dis(b), eb = a.dis(c), ec = b.dis(a);
r = fabs((b - a) ^ (c - a) / (ea + eb + ec));
return (a * ea + b * eb + c *ec) / (ea + eb + ec);
}
char op[50];
char se[6][50] = {
"CircumscribedCircle",
"InscribedCircle",
"TangentLineThroughPoint",
"CircleThroughAPointAndTangentToALineWithRadius",
"CircleTangentToTwoLinesWithRadius",
"CircleTangentToTwoDisjointCirclesWithRadius"
};
void func0();
void func1();
void func2();
void func3();
void func4();
void func5();
int main()
{
// freopen("12304.in", "r", stdin);
while(~scanf("%s", op))
{
if(strcmp(op, se[0]) == 0) func0();
else if(strcmp(op, se[1]) == 0) func1();
else if(strcmp(op, se[2]) == 0) func2();
else if(strcmp(op, se[3]) == 0) func3();
else if(strcmp(op, se[4]) == 0) func4();
else if(strcmp(op, se[5]) == 0) func5();
}
return 0;
}
//外接圆
void func0()
{
Point pp[3];
for(int i = 0; i < 3; i++) pp[i].in();
Point s1 = pp[0] - pp[1], s2 = pp[0] - pp[2];
Point u1 = (pp[0] + pp[1]) / 2.0;
Point u2 = Point(u1.x + s1.y, u1.y - s1.x);
Point v1 = (pp[0] + pp[2]) / 2.0;
Point v2 = Point(v1.x + s2.y, v1.y - s2.x);
Point c = get_Intersection(u1, u2, v1, v2);
printf("(%.6f,%.6f,%.6f)\n", c.x, c.y, c.dis(pp[0]));
}
//内切圆
void func1()
{
Point pp[3];
Circle c;
for(int i = 0; i < 3; i++) pp[i].in();
c.o = get_Inc(c.r, pp[0], pp[1], pp[2]);
printf("(%.6f,%.6f,%.6f)\n", c.o.x, c.o.y, c.r);
}
void func2()
{
Circle c; c.in();
Point p; p.in();
int tot = get_Tangents(c, p, Tanp);
printf("[");
if(tot == -1) printf("0.000000");
if(tot > 0)
{
double r[2];
for(int i = 0; i < 2; i++)
{
r[i] = 180.0 * atan2(Tanp[i].y - p.y, Tanp[i].x - p.x) / pi;
if(sig(r[i]) < 0) r[i] += 180.0;
}
if(sig(r[0] - r[1]) > 0) swap(r[0], r[1]);
printf("%.6lf,%.6lf", r[0], r[1]);
}
printf("]\n");
}
void func3()
{
Line ll;
Point p;
double r;
p.in();
ll.l.a.in(), ll.l.b.in();
scanf("%lf", &r);
double d2 = ll.dis2(p);
int sgn1 = sig(d2), sgn2 = sig(d2 - 4.0 * r * r);
printf("[");
if(sgn1 == 0)
{
Point v = ll.l.d().v();
double k = r / v.len();
Point c1 = Point(p.x + k * v.x, p.y + k * v.y);
Point c2 = Point(p.x - k * v.x, p.y - k * v.y);
if(c2 < c1) swap(c1, c2);
printf("(%.6lf,%.6lf),(%.6lf,%.6lf)", c1.x, c1.y, c2.x, c2.y);
}
else if(sgn2 == 0)
{
Point fp = FootPoint(p, ll);
fp = (fp + p) / 2.0;
printf("(%.6lf,%.6lf)", fp.x, fp.y);
}
else if(sgn1 > 0 && sgn2 < 0)
{
double df = fabs(sqrt(d2) - r);
double h2 = r * r - df * df;
double pr = sqrt(d2 + h2);
Circle pc = Circle(p, pr);
int tot = Line_Intersect_Circle(pc, ll, Insp);
Point v = ll.l.d().v();
double k = r / v.len();
Point c1 = Point(Insp[0].x + k * v.x, Insp[0].y + k * v.y);
if(sig(Cross(ll.l.a, p, ll.l.b) * Cross(ll.l.a, c1, ll.l.b)) < 0)
c1 = Point(Insp[0].x - k * v.x, Insp[0].y - k * v.y);
Point c2 = Point(Insp[1].x + k * v.x, Insp[1].y + k * v.y);
if(sig(Cross(ll.l.a, p, ll.l.b) * Cross(ll.l.a, c2, ll.l.b)) < 0)
c2 = Point(Insp[1].x - k * v.x, Insp[1].y - k * v.y);
if(c2 < c1) swap(c1, c2);
printf("(%.6lf,%.6lf),(%.6lf,%.6lf)", c1.x, c1.y, c2.x, c2.y);
}
printf("]\n");
}
void func4()
{
Point s[2], t[2], c[4];
s[0].in(), t[0].in();
s[1].in(), t[1].in();
double r; scanf("%lf", &r);
printf("[");
Point v0 = (s[0] - t[0]), v1 = (s[1] - t[1]);
v0 = v0 / v0.len() * r; v0 = v0.rotate(pi / 2.0);
v1 = v1 / v1.len() * r; v1 = v1.rotate(pi / 2.0);
c[0] = get_Intersection(s[0] + v0, t[0] + v0, s[1] + v1, t[1] + v1);
c[1] = get_Intersection(s[0] + v0, t[0] + v0, s[1] - v1, t[1] - v1);
c[2] = get_Intersection(s[0] - v0, t[0] - v0, s[1] - v1, t[1] - v1);
c[3] = get_Intersection(s[0] - v0, t[0] - v0, s[1] + v1, t[1] + v1);
sort(c, c + 4);
for(int i = 0; i < 4; i++)
{
if(i) printf(",");
printf("(%.6lf,%.6lf)", c[i].x, c[i].y);
}
printf("]\n");
}
void func5()
{
Circle c[2];
c[0].in(), c[1].in();
double r; scanf("%lf", &r);
double d = c[0].o.dis(c[1].o);
c[0].r += r, c[1].r += r;
printf("[");
if(sig(d - c[0].r - c[1].r) == 0)
{
Point m = ((c[1].o - c[0].o) / d) * c[0].r + c[0].o;
printf("(%.6lf,%.6lf)", m.x, m.y);
}
else if(sig(d - c[0].r - c[1].r) < 0)
{
Circle_Intersect_Circle(c[0], c[1], Insp);
if(Insp[1] < Insp[0]) swap(Insp[0], Insp[1]);
printf("(%.6lf,%.6lf),(%.6lf,%.6lf)", Insp[0].x, Insp[0].y, Insp[1].x, Insp[1].y);
}
printf("]\n");
}