二維計算幾何
阿新 • • 發佈:2021-10-07
二維計算幾何模板(更新ing)
目錄 (只包含已寫部分)
比較實數大小/* 暫時跳過內容 複數部分 判斷兩線段是否相交 (包括是否判斷端點) 求兩線段最小距離的平方 */ #include <bits/stdc++.h> #define db double #define ll long long #define mp make_pair #define fi first #define se second #define pb push_back using namespace std; const db pi = acos(-1); const db eps = 1e-6;
//判斷一個實數的符號,在 [-eps,eps]內被認定為
int sign(db x)
{
if (x > eps) return 1;
else if (x < -eps) return -1;
return 0;
}
// 比較兩個實數的大小
int cmp(db x, db y) { return sign(x - y); }
封裝平面上的點及向量
平面向量和與點的拓展操作struct Point { db x, y; Point(db x = 0, db y = 0) : x(x), y(y) { } //平面點座標和向量的基本操作 //向量 + 向量 or 點 + 向量 Point operator+ (const Point& p) const { return Point(x + p.x, y + p.y); } //向量相減 or 點 - 點 = 向量 Point operator- (const Point& p) const { return Point(x - p.x, y - p.y); } //向量數乘/數除 Point operator* (db p) const { return Point(x * p, y * p); } Point operator/ (db p) const { return Point(x / p, y / p); } //判斷向量是否平行 or是否是一個點 bool operator== (const Point& p) const { return cmp(x, p.x) && cmp(y, p.y); } //求極角 : 在極座標系中,平面上任何一點到極點的連線和極軸的夾角叫做極角。 單位為弧度 rad db polar_angle() { return atan2(y, x); } //內積 db dot(const Point& p) { return x * p.x + y * p.y; } //外積 db cross(const Point& p) { return x * p.y - y * p.x; } //點到原點的距離 or 向量的模 db length() { return sqrt(x * x + y * y); } //向量逆時針旋轉 rad 度,rad:弧度 且為逆時針旋轉的角 Point turn(db p){ return Point(x * cos(p) - y * sin(p), x * sin(p) + y * cos(p)); } Point turn90(){ return Point(-y, x); } };
封裝平面上的直線typedef Point Vector; //判斷向量BC是否在向量AB的逆時針方向 (點C是否在向量AB左邊) bool ToLeftTest(Point a, Point b, Point c) { return (b - a).cross(c - b) > 0; } //兩個向量弧度制下的夾角 db angle (Vector a, Vector b) { return acos(a.dot(b) / a.length() / b.length()); } //兩向量構成的四邊形面積 db area(Point a, Point b, Point c) { return (b - a).cross(c - a); } //向量的單位化和法線 Vector format(Vector& a) { db l = a.length(); return Vector(a.x / l, a.y / l); } Vector normal(Vector a) { db l = a.length(); return Vector(-a.y / l, a.x / l); } // q點繞著p點逆時針旋轉 Point rotate(Point q, Point p, db angle) { Point v = q - p; db c = cos(angle), s = sin(angle); return Point(p.x + v.x * c - v.y * s, p.y + v.x * s + v.y * c); }
struct Line
{
Vector v;
Point p;
Line(Vector v, Point p):v(v), p(p) {}
Point get_point_in_line(db t) //返回直線上一點P = v + (p - v)*t
{
return v + (p - v)*t;
}
};
點與直線的相關操作
//點和直線關係 1 在左側 -1 在右側 0 在直線上 A, B:直線上一點,C:待判斷關係的點
int relation(Point a, Point b, Point c)
{
int tag = sign((b - a).cross(c - a));
if(tag < 0) return 1;
else if(tag > 0) return -1;
return 0;
}
//計算兩直線交點 直線p + tv 和 q + tw 要確保直線有交點
Point Get_line_intersection(Point p, Vector v, Point q, Vector w)
{
//if (v.cross(w) == 0) 無交點
Vector u = p - q;
db t = w.cross(u) / w.cross(v);
return p + v * t;
}
//點到直線的距離 點p到直線ab的距離
db Distance_point_to_line(Point p, Point a, Point b)
{
Vector v1 =b - a, v2 = p - a;
return fabs(v1.cross(v2) / v1.length());//如果不取絕對值,那麼得到的是有向距離
}
//點到線段的距離 點p到線段ab的距離
double Distance_point_to_segment(Point p, Point a, Point b)
{
if(a == b) return (p - a).length();//(如果重合那麼就是兩個點之間的距離,直接轉成向量求距離即可)
Vector v1 = b - a, v2 = p - a, v3 = p - b;
if(sign(v1.dot(v2)) < 0) return v2.length(); //A點左邊
if(sign(v1.dot(v3)) > 0) return v3.length(); //B點右邊
return fabs(v1.cross(v2) / v1.length()); //垂線的距離
}
//點到直線的上的投影點
Point Get_line_projection(Point a, Point b, Point p)
{
Vector v = b - a;
return a + v * (v.dot(p - a) / v.dot(v));
}
//點到直線上的垂足
Point Foot_point(Point p, Point a, Point b)
{
Vector x = p - a, y = p - b, z = b - a;
db len1 = x.dot(z) / z.length(), len2 = - 1.0 * y.dot(z) / z.length();
return a + z * (len1 / (len1 + len2));
}
//點關於一條直線的對稱點
Point Symmetry_PL(Point p, Point a, Point b)
{
return p + (Foot_point(p, a, b) - p) * 2;
}
//點是否線上段上
bool On_segment(Point p, Point a, Point b)
{
return sign((p - a).cross(p - b)) == 0 && sign((p - a).dot(p - b)) < 0;
}
//判斷兩條是直線是否平行
bool Parallel(Line a, Line b)
{
return sign(a.v.cross(b.v)) == 0;
}
//兩直線關係 0 平行 1 重合 2 相交
int linecrossline(Line a, Line b)
{
db t = a.v.cross(b.v);
if (sign(t) == 0)
{
db s = a.v.cross(a.p - b.p);
if (sign(s) == 0) return 0;
return 1;
}
return 2;
}
int main()
{
printf("無內容\n");
return 0;
}