1. 程式人生 > 其它 >二維計算幾何

二維計算幾何

二維計算幾何模板(更新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;	
}