UVa 12304 2D Geometry 110 in 1!(圆的处理)

与圆和切线的一些基础处理.

#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");
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值