【UVa 12304】2D Geometry 110 in 1! (计算几何、圆)

Description

https://vjudge.net/problem/UVA-12304

Solution

都是一些最基本的操作,没什么技术含量,只是代码量有点大,,码了一天,摆上代码吧。

Source

/************************************************
 * Happy Spring Festival!
 * Au: Hany01
 * Date: Feb 11th, 2018
 * Prob: UVa12304 2D Geometry 110 in 1!
 * Email: hany01@foxmail.com
************************************************/

#include<bits/stdc++.h>

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

#define rep(i, j) for (register int i = 0, i##_end_ = (j); i < i##_end_; ++ i)
#define For(i, j, k) for (register int i = (j), i##_end_ = (k); i <= i##_end_; ++ i)
#define Fordown(i, j, k) for (register int i = (j), i##_end_ = (k); i >= i##_end_; -- i)
#define Set(a, b) memset(a, b, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define fir first
#define sec second
#define pb(a) push_back(a)
#define mp(a, b) make_pair(a, b)
#define ALL(a) (a).begin(), (a).end()
#define SZ(a) ((int)(a).size())
#define INF (0x3f3f3f3f)
#define INF1 (2139062143)
#define Mod (1000000007)
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define y1 wozenmezhemecaia

template <typename T> inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }
template <typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }

inline int read()
{
    register int _, __; register char c_;
    for (_ = 0, __ = 1, c_ = getchar(); c_ < '0' || c_ > '9'; c_ = getchar()) if (c_ == '-') __ = -1;
    for ( ; c_ >= '0' && c_ <= '9'; c_ = getchar()) _ = (_ << 1) + (_ << 3) + (c_ ^ 48);
    return _ * __;
}

inline void File()
{
#ifdef hany01
    freopen("uva12304.in", "r", stdin);
    freopen("uva12304.out", "w", stdout);
#endif
}

const double eps = 1e-7, Pi = acos(-1.0);

inline int dcmp(double x) { if (fabs(x) < eps) return 0; return x < 0 ? -1 : 1; }

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

bool operator == (const Vector& A, const Vector& B) {
    return !dcmp(A.x - B.x) && !dcmp(A.y - B.y);
}

bool operator < (const Vector& A, const Vector& B) {
    return A.x < B.x || (A.x == B.x && A.y < B.y);
}

struct Circle
{
    Point O; double r;
    Circle(Point O = Point(0, 0), double r = 0): O(O), r(r) {}
    Point point(double rad) {
        return Point(O.x + cos(rad) * r, O.y + sin(rad) * r);
    }
};

Point Mid(Point A, Point B) {
    return Point((A.x + B.x) / 2, (A.y + B.y) / 2);
}

double Cross(Point A, Point B) {
    return A.x * B.y - A.y * B.x;
}

double Dot(Point A, Point 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 Angle(Vector A) {
    return atan2(A.y, A.x);
}

Point GetLineIntersection(Point P, Vector v, Point Q, Vector w) {
    register Vector u = P - Q;
    return P + v * (Cross(w, u) / Cross(v, w));
}

Point GetLineProjection(Point P, Point A, Point B) {
    Vector v = B - A;
    return A + v * (Dot(v, P - A) / Dot(v, v));
}

Vector Rotate(Vector A, double rad) {
    return Vector(A.x * cos(rad) - A.y * sin(rad), A.x * sin(rad) + A.y * cos(rad));
}

double DistanceToLine(Point P, Point A, Point B) {
    return fabs(Cross(P - A, B - A)) / Length(B - A);
}

inline void Correct(double& x) {
    while (dcmp(x) < 0) x += Pi;
    while (dcmp(x - Pi) >= 0) x -= Pi;
}

int GetTangents(Circle C, Point P, double* Ans) {
    double d = Length(C.O - P);
    if (dcmp(d - C.r) < 0) return 0;
    double aPC = Angle(P - C.O), theta = acos(C.r / d);
    Ans[1] = aPC + theta + Pi / 2, Ans[2] = aPC - theta + Pi / 2;
    Correct(Ans[1]), Correct(Ans[2]);
    if (!dcmp(Ans[1] - Ans[2])) return 1;
    return 2;
}

int GetLineCircleIntersection(Point A, Point B, Circle C, Point& S1, Point& S2) {
    double d = DistanceToLine(C.O, A, B);
    register int tmp = dcmp(d - C.r);
    if (tmp > 0) return 0;
    Point P = GetLineProjection(C.O, A, B);
    if (!tmp) { S1 = S2 = P; return 1; }
    double L = sqrt(C.r * C.r - d * d);
    Vector v = (B - A) / Length(B - A);
    S1 = P - v * L, S2 = P + v * L;
    return 2;
}

int GetCircleIntersection(Circle C1, Circle C2, Point& P1, Point& P2) {
    double d = Length(C1.O - C2.O);
    if (!dcmp(d)) { if (!dcmp(C1.r - C2.r)) return -1; return 0; }
    if (dcmp(C1.r + C2.r - d) < 0 || dcmp(fabs(C1.r - C2.r) - d) > 0) return 0;
    double a = Angle(C2.O - C1.O), da = acos((C1.r * C1.r + d * d - C2.r * C2.r) / (2 * C1.r * d));
    P1 = C1.point(a - da), P2 = C1.point(a + da);
    if (P1 == P2) return 1;
    return 2;
}

Point move(Point A, double a, double r) { return Point(A.x, A.y + r / cos(a)); }

char Q[40];

int main()
{
    File();
    while (scanf("%s", Q) != EOF)
    {
        if (Q[4] == 'u')
        {
            register Point A, B, C, D, E, vDO, vEO, O;
            register double r;
            scanf("%lf%lf%lf%lf%lf%lf", &A.x, &A.y, &B.x, &B.y, &C.x, &C.y);
            D = Mid(B, C);
            vDO = Vector(B.y - C.y, C.x - B.x),
            E = Mid(A, C);
            vEO = Vector(A.y - C.y, C.x - A.x);
            O = GetLineIntersection(D, vDO, E, vEO), r = Length(O - A);
            printf("(%.6lf,%.6lf,%.6lf)\n", O.x, O.y, r);
        }
        else if (Q[0] == 'I')
        {
            register Point A, B, C, D, E, vBD, vCE, O;
            register double r, ABD, ACE;
            scanf("%lf%lf%lf%lf%lf%lf", &A.x, &A.y, &B.x, &B.y, &C.x, &C.y);
            if (dcmp(Cross(B - A, C - A)) < 0) swap(B, C);
            ABD = Angle(A - B, C - B) / 2;
            ACE = Angle(A - C, B - C) / 2;
            vBD = Rotate(C - B, ABD);
            vCE = Rotate(B - C, 2 * Pi - ACE);
            O = GetLineIntersection(B, vBD, C, vCE);
            r = DistanceToLine(O, A, B);
            printf("(%.6lf,%.6lf,%.6lf)\n", O.x, O.y, r);
        }
        else if (Q[0] == 'T')
        {
            register Circle C;
            register Point P;
            register double Ans[6];
            register int cnt;
            scanf("%lf%lf%lf%lf%lf", &C.O.x, &C.O.y, &C.r, &P.x, &P.y);
            cnt = GetTangents(C, P, Ans);
            if (!cnt) { puts("[]"); continue; }
            sort(Ans + 1, Ans + 1 + cnt);
            putchar('[');
            For(i, 1, cnt - 1) printf("%.6lf,", Ans[i] / Pi * 180);
            printf("%.6lf]\n", Ans[cnt] / Pi * 180);
        }
        else if (Q[13] == 'A')
        {
            register Point P, A, B, A1, A2, A3;
            register double r, d, a;
            register Circle C;
            register int cntt;
            scanf("%lf%lf%lf%lf%lf%lf%lf", &P.x, &P.y, &A.x, &A.y, &B.x, &B.y, &r);
            if (!dcmp((d = DistanceToLine(P, A, B)) - r * 2))
            {
                A1 = GetLineProjection(P, A, B);
                printf("[(%lf,%lf)]\n", (A1.x + P.x) / 2, (A1.y + P.y) / 2);
                continue;
            }
            if (dcmp(d - r * 2) > 0) { puts("[]"); continue; }
            C = Circle(P, r);
            a = Angle(B - A);
            if (!(cntt = GetLineCircleIntersection(move(A, a, r), move(B, a, r), C, A1, A2))) {
                cntt = GetLineCircleIntersection(move(A, a, -r), move(B, a, -r), C, A1, A2);
            }
            else if (cntt == 1) GetLineCircleIntersection(move(A, a, -r), move(B, a, -r), C, A2, A3);
            if (A2 < A1) swap(A1, A2);
            printf("[(%.6lf,%.6lf),(%.6lf,%.6lf)]\n", A1.x, A1.y, A2.x, A2.y);
        }
        else if (Q[18] == 'L')
        {
            register Point Ans[6], A1, A2, B1, B2, A1_, VA, B1_, VB;
            register double a1, a2, r;
            register int cnt = 0;
            scanf("%lf%lf%lf%lf%lf%lf%lf%lf%lf", &A1.x, &A1.y, &A2.x, &A2.y, &B1.x, &B1.y, &B2.x, &B2.y, &r);
            a1 = Angle(A2 - A1);
            a2 = Angle(B2 - B1);
            For(i, -1, 1) if (i) For(j, -1, 1) if (j) {
                A1_ = move(A1, a1, r * i);
                VA = A2 - A1;
                B1_ = move(B1, a2, r * j);
                VB = B2 - B1;
                Ans[++ cnt] = GetLineIntersection(A1_, VA, B1_, VB);
            }
            sort(Ans + 1, Ans + 5);
            putchar('[');
            For(i, 1, 4) printf("(%.6lf,%.6lf)%c", Ans[i].x, Ans[i].y, i == 4 ? ']' : ',');
            putchar('\n');
        } else if (Q[18] == 'D') {
            register Circle C1, C2;
            register Point Ans1, Ans2;
            register double r;
            register int cnt;
            scanf("%lf%lf%lf", &C1.O.x, &C1.O.y, &C1.r),
            scanf("%lf%lf%lf", &C2.O.x, &C2.O.y, &C2.r);
            scanf("%lf", &r), C1.r += r, C2.r += r;
            cnt = GetCircleIntersection(C1, C2, Ans1, Ans2);
            if (!cnt) puts("[]");
            else if (cnt == 1)
                printf("[(%lf,%lf)]\n", Ans1.x, Ans1.y);
            else
            {
                if (Ans2 < Ans1) swap(Ans1, Ans2);
                printf("[(%lf,%lf),(%lf,%lf)]\n", Ans1.x, Ans1.y, Ans2.x, Ans2.y);
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值