La_Pluma 的 数学

一百行的几何板子?

#include <cmath>
#include <cstdio>
#include <algorithm>
namespace La_Pluma_math{
    const double eps = 1e-10;
    typedef double Point_type;
    struct Point; struct Vec; struct Line; struct Segment;
    double check_0(double);                                      // 判丢精的 0
    double dis(const Point, const Point);                        // 点到点的距离
    double dis(const Point, const Line);                         // 点到直线距离
    double dis(const Line, const Point);                         // 直线到点距离
    double dis(const Point, const Segment);                      // 点到线段距离
    double dis(const Segment, const Point);                      // 线段到点距离
    struct Point{                                                // 点
        Point_type x, y;
        Point():x(), y(){}                                       // 默认构造函数
        Point(const Vec);                                        // 用向量初始化 (感觉非常SB)
        Point(Point_type, Point_type);                           // 用坐标初始化
        bool operator == (const Point);                          // 判断是否为同一个点
        bool operator != (const Point);                          // 判断是否不为同一个点
    };
    struct Vec{                                                  // 向量
        double x, y;
        Vec():x(), y(){}                                         // 默认构造函数
        Vec(const Point);                                        // 用点初始化
        Vec(const Segment);                                      // 用线段初始化
        Vec(double, double);                                     // 用坐标初始化
        Vec(const Point, const Point);                           // 用两个点初始化 (起点和终点)
        Vec(double, double, double, double);                     // 用两个坐标初始化 (起点和终点)
        Vec    operator +  (const Vec);                          // 向量加
        Vec    operator -  (const Vec);                          // 向量减
        double operator ^  (const Vec);                          // 向量叉积的模
        double operator *  (const Vec);                          // 向量点积
        double operator ~  ();                                   // 向量的模
        Vec    operator += (const Vec);                          // 以下处理一些奇怪的运算符
        Vec    operator -= (const Vec);                          // 结果发现也就这些
        Vec    operator -  ();                                   // 又有谁能想到减号也可以是单目运算符呢
        bool   operator == (const Vec);                          // 判断是否为共线向量
        bool   operator != (const Vec);                          // 判断是否不为共线向量
    };
    struct Line{                                                 // 直线
        double A, B, C;
        Line():A(), B(), C(){}                                   // 默认构造函数
        Line(const Segment);                                     // 用线段初始化
        Line(double, double);                                    // 用斜截式初始化
        Line(const Point, const Point);                          // 用两个点初始化
        Line(double, double, double, double);                    // 用两个坐标初始化
        Point   operator ^  (const Line);                        // 求直线的交点
        bool    operator == (const Line);                        // 判断是否为同一条直线
        bool    operator != (const Line);                        // 判断是否不为同一条直线
        double  operator [] (const double);                      // 求 x 对应的 y 值
    };
    struct Segment{                                              // 线段
        Point a, b;
        Segment():a(),b(){}                                      // 默认构造函数
        Segment(const Point, const Point);                       // 用两个端点初始化
        Segment(Point_type, Point_type, Point_type, Point_type); // 用两个坐标初始化
        double operator ~ ();                                    // 线段的长度
        bool operator <  (Segment);                              // 万能的小于号
        bool operator >  (Segment);                              // 进行
        bool operator <= (Segment);                              // 一个
        bool operator >= (Segment);                              // 重的载
        bool operator == (Segment);                              // 判断线段的长度是否相等
        bool operator != (Segment);                              // 判断线段的长度是否不相等
    };

         Point::Point(const Vec a)                { x = a.x, y = a.y; }
         Point::Point(Point_type x, Point_type y) { this->x = x, this->y = y; }
    bool Point::operator == (const Point a)       { return x == a.x && y == a.y; }
    bool Point::operator != (const Point a)       { return !(*this == a); }

           Vec::Vec(const Point a)                { x = a.x, y = a.y; }
           Vec::Vec(const Segment a)              { *this = Vec(a.a, a.b); }
           Vec::Vec(const Point a, const Point b) { *this = Vec(b) - Vec(a); }
           Vec::Vec(double x, double y)           { this->x = x, this->y = y; }
    Vec    Vec::operator +  (const Vec b)         { return Vec(x + b.x, y + b.y); }
    Vec    Vec::operator -  (const Vec b)         { return Vec(x - b.x, y - b.y); }
    Vec    Vec::operator -  ()                    { return Vec(-x     , -y     ); }
    double Vec::operator ^  (const Vec b)         { return x * b.y - b.x * y; }
    double Vec::operator *  (const Vec b)         { return x * b.x + y * b.y; }
    double Vec::operator ~  ()                    { return sqrt(x * x + y * y); }
    Vec    Vec::operator += (const Vec b)         { return *this = *this + b; }
    Vec    Vec::operator -= (const Vec b)         { return *this = *this - b; }
    bool   Vec::operator == (const Vec b)         { if(!check_0(b.x)) return !check_0(x); if(!check_0(b.y)) return !check_0(y); return check_0(y / b.y - x / b.x) == 0; }
    bool   Vec::operator != (const Vec b)         { return !(*this == b); }

    Line::Line(const Segment a)                        { *this = Line(a.a, a.b); }
    Line::Line(double k, double b)                     { A = k, B = 0, C = b; }
    Line::Line(double a, double b, double c, double d) { *this = Line(Point(a, b), Point(c, d)); }
    Line::Line(const Point a, const Point b){
        if(a.x == b.x) A = 1, B = 0, C = -a.x;
        else if(a.y == b.y) A = 0, B = 1, C = -a.y;
        else A = (double)(a.y - b.y) / (a.x - b.x), B = -1, C = (double)(a.x * b.y - b.x * a.y) / (a.x - b.x);
    }
    Point  Line::operator ^  (const Line a)   { return Point((B * a.C - a.B * C) / (A * a.B - a.A * B), -(A * a.C - a.A * C) / (A * a.B - a.A * B)); }
    bool   Line::operator == (const Line a)   { return check_0(A * a.B - B * a.A) == 0 && check_0(A * a.C - C * a.A) == 0 && check_0(B * a.C - C * a.B) == 0; }
    bool   Line::operator != (const Line a)   { return !(*this == a); }
    double Line::operator [] (const double a) { return -(C + A * a) / B; }

           Segment::Segment(const Point a, const Point b) { this->a = a, this->b = b; }
           Segment::Segment(Point_type a, Point_type b, Point_type c, Point_type d) { *this = Segment(Point(a, b), Point(c, d)); }// 因为一些显然的问题, 这里就不对齐了
    double Segment::operator ~  ()                        { return dis(a, b); }
    bool   Segment::operator <  (Segment a)               { return (~(*this)) < (~a); }
    bool   Segment::operator >  (Segment a)               { return a < *this; }
    bool   Segment::operator <= (Segment a)               { return !(*this > a); }
    bool   Segment::operator >= (Segment a)               { return !(*this < a); }
    bool   Segment::operator == (Segment a)               { return !(*this < a) && !(*this > a); }
    bool   Segment::operator != (Segment a)               { return  (*this < a) ||  (*this > a); }

    double check_0(double a) { return fabs(a) < eps ? 0 : a; }
    double dis(const Point pos1, const Point pos2) { return check_0(sqrt((pos1.x - pos2.x) * (pos1.x - pos2.x) + (pos1.y - pos2.y) * (pos1.y - pos2.y))); }
    double dis(const Line link, const Point pos)   { return check_0(fabs(link.A * pos.x + link.B * pos.y + link.C) / sqrt(link.A * link.A + link.B * link.B)); }
    double dis(const Point pos, const Line link)   { return dis(link, pos); }
    double dis(const Point pos, const Segment Seg) { return dis(Seg,  pos); }
    double dis(const Segment Seg, const Point pos) {
        Vec vector1(Seg.a, pos);
        Vec vector2(Seg.b, pos);
        Vec vector3 = Seg;
        if(check_0(vector1 * vector3) < 0) return ~vector1;
        if(check_0(vector2 * vector3) > 0) return ~vector2;
        return check_0(fabs((vector1 ^ vector3) / (~vector3)));
    }
}
using namespace La_Pluma_math;
int main(){
    int T; scanf("%d", &T);
    while(T--){
        int a, b, c, d, e, f, g, h;
        scanf("%d%d%d%d%d%d%d%d", &a, &b, &c, &d, &e, &f, &g, &h);
        Segment n(a, b, c, d), m(e, f, g, h);
        if(b > d) std::swap(n.a, n.b); if(f > h) std::swap(m.a, m.b);
        if(Vec(n) == Vec(m) || Vec(n) == Vec(1, 0) || Vec(m) == Vec(1, 0)) {puts("0.00"); continue;}
        Point pos = Line(n) ^ Line(m);
        if(dis(pos, n) || dis(pos, m)) {puts("0.00"); continue;}
        if(Line(n).B * Line(n).A * Line(m).B * Line(m).A > 0){
            if(n.b.y >= m.b.y && !dis(Point(m.b.x, Line(n)[m.b.x]), n) && check_0(Line(n)[m.b.x] - m.b.y) >= 0) {puts("0.00"); continue;}
            if(n.b.y <= m.b.y && !dis(Point(n.b.x, Line(m)[n.b.x]), m) && check_0(Line(m)[n.b.x] - n.b.y) >= 0) {puts("0.00"); continue;}
        }
        if(n.b.y < m.b.y) m.b = Point(-(Line(m).C + Line(m).B * n.b.y) / Line(m).A, n.b.y);
        else              n.b = Point(-(Line(n).C + Line(n).B * m.b.y) / Line(n).A, m.b.y);
        printf("%.2f\n", fabs(Vec(pos, n.b) ^ Vec(pos, m.b)) * 0.5 + eps);
    }
}


有些事情必须声明一下, 可以保证过编译, 不保证不出错

posted @ 2022-10-09 14:55  La_pluma  阅读(45)  评论(3编辑  收藏  举报