计算几何板子

才知道为啥我们ACM教练说计算几何是一个性价比很高的东西,因为ACM让带纸质材料啊!所以只要板子我有,那计算几何确实就变得可做了。

const db PI = acos(-1);
In int dcmp(db x)							       //比较两个实数大小 
{
	if(fabs(x) < eps) return 0;
	return x < 0 ? -1 : 1;
}
struct Vec								       //向量类 
{
	db x, y;
	In Vec operator - (const Vec& oth)const {return (Vec){x - oth.x, y - oth.y};}
	In Vec operator + (const Vec& oth)const {return (Vec){x + oth.x, y + oth.y};}	
	In db operator ^ (const Vec& oth)const	{return x * oth.x + y * oth.y;}	//点积 
	In db operator * (const Vec& oth)const {return x * oth.y - y * oth.x;}	//差积 
	In Vec operator * (const db& a)const {return (Vec){x * a, y * a};}
	In int operator == (const Vec& oth)const {return !dcmp(x - oth.x) && !dcmp(y - oth.y);}
	friend In db dis(const Vec& A) {return sqrt(A.x * A.x + A.y * A.y);}	//模长 
	friend In Vec rot(const Vec& A, const db& a) {return (Vec){A.x * cos(a) - A.y * sin(a), A.x * sin(a) + A.y * cos(a)};}	//旋转(逆时针) 
	In bool operator < (const Vec& oth)const {return x < oth.x || (!dcmp(x - oth.x) && y < oth.y);}
};
struct Lin								      //直线类 
{
	Vec A, v;
	friend In Lin mov(const Lin& l, const db& d)		//将直线沿垂直于该直线的左侧平移d个单位 
	{
		db dv = dis(l.v);
		Vec tp = (Vec){-l.v.y, l.v.x} * (1.0 / dv);
		return (Lin){l.A + tp * d, l.v};
	}
	In Vec Point(const db& t) {return A + v * t;}		//求直线上的点 
};
struct Cir								      //圆类 
{
	Vec C; db r;
	In Vec Point(const db& a) {return C + (Vec){cos(a) * r, sin(a) * r};}
};

In db Ang(Vec A) {return atan2(A.y, A.x);}				      //求向量角度 
In db changeAng(db a)							      //将一个角转换到[0,2PI) 
{
	a -= PI * 2 * floor(a / (2 * PI));
	return a < 0 ? a + PI * 2 : a;
}

In bool onSeg(Vec A, Vec p1, Vec p2)					      //A在线段p1p2上,dcmp小于等于/小于0表示含/不含端点 
{
	return dcmp((p1 - A) * (p2 - A)) == 0 && dcmp((p1 - A) ^ (p2 - A)) < 0;
}
In bool Cross(Vec A, Vec B, Vec C, Vec D)				      //判断两条线段是否相交 
{
	if(onSeg(A, C, D) || onSeg(B, C, D) || onSeg(C, A, B) || onSeg(D, A, B)) return 1;	//加上这一句表示算端点 
	return dcmp((B - A) * (C - A)) * dcmp((B - A) * (D - A)) < 0 && dcmp((D - C) * (A - C)) * dcmp((D - C) * (B - C)) < 0;
}
In Vec getCross(Vec A, Vec B, Vec C, Vec D)				      //计算两条直线的交点 
{
	Vec v = B - A, w = D - C, u = A - C;
	db tp = (w * u) / (v * w);
	return A + v * tp;
}
In db getDisPtL(Vec P, Vec A, Vec B)					      //计算点P到直线AB的距离 
{
	db S = (B - A) * (P - A);
	return fabs(S) / dis(B - A);
}
In db getLAD(Vec V)							      //计算直线的倾斜角(角度制) 
{
	db ang = atan(V.y / V.x) / PI * 180;
	while(ang < 0) ang += 360;
	while(dcmp(ang - 180) >= 0) ang -= 180;
	return ang; 
}

In bool disCC(Cir C1, Cir C2)						      //判断两圆是否相离(包含外切) 
{      
	return dcmp(dis(C1.C - C2.C) - (C1.r + C2.r)) >= 0;
}
In int getCrossCL(Lin l, Cir C, vector<Vec>& ans)		              //求直线和圆的交点,结果储存在ans中,返回交点个数 
{
	db a = l.v.x, b = l.A.x - C.C.x, c = l.v.y, d = l.A.y - C.C.y;
	db e = a * a + c * c, f = (a * b + c * d) * 2, g = b * b + d * d - C.r * C.r;
	db del = f * f - e * g * 4;
	if(dcmp(del) < 0) return 0;
	if(dcmp(del) == 0) {ans.push_back(l.Point(-f / (e * 2))); return 1;}
	ans.push_back(l.Point((-f - sqrt(del)) / (e * 2)));
	ans.push_back(l.Point((-f + sqrt(del)) / (e * 2)));
	return 2;
}
In int getCrossCC(Cir C1, Cir C2, vector<Vec>& ans)		              //计算两个圆的交点 
{      
	db d = dis(C1.C - C2.C);
	if(dcmp(d) == 0) return dcmp(C1.r - C2.r) ? 0 : -1;
	if(dcmp(d - C1.r - C2.r) > 0 || dcmp(fabs(C1.r - C2.r) - d) > 0) return 0;
	db a = Ang(C2.C - C1.C), d1 = acos((C1.r * C1.r + d * d - C2.r * C2.r) / (C1.r * d * 2));//acos(d / 2 / C1.r);
	Vec p1 = C1.Point(a + d1), p2 = C1.Point(a - d1);
	ans.push_back(p1); if(p1 == p2) return 1;
	ans.push_back(p2); return 2;
}

In db calcS(Vec* p, int n)						     //计算一个多边形的面积 
{
	db ret = 0;
	for(int i = 2; i < n; ++i)
		ret += (p[i] - p[1]) * (p[i + 1] - p[1]);
	return fabs(ret / 2); 
}

In int PiP(Vec A, Vec* p, int n)					     //判定点是否在多边形内 
{
	int wn = 0;
	p[0] = p[n]; 
	for(int i = 1; i <= n; ++i)
	{
		Vec p1 = p[i - 1], p2 = p[i]; 
		if(onSeg(A, p1, p2)) return -1;
		int k = dcmp((p2 - p1) * (A - p1));
		int d1 = dcmp(p1.y - A.y), d2 = dcmp(p2.y - A.y);
		if(k > 0 && d1 <= 0 && d2 > 0) wn++;
		if(k < 0 && d2 <= 0 && d1 > 0) wn--;
	}
	p[0] = (Vec){0, 0};
	return wn != 0;
}

Vec S;									    //求凸包,返回凸包数组st和大小top. 
In bool cmpP(Vec A, Vec B)
{
	db s = (A - S) * (B - S);
	return dcmp(s) ? s > 0 : dis(A - S) < dis(B - S);
}
In db calcP(Vec A, Vec B, Vec C) {return (B - A) * (C - A);}
In void getPol(Vec* p, int n, Vec* st, int& top)
{
	int id = 1;
	for(int i = 2; i <= n; ++i)
		if(p[i].x < p[id].x || (!dcmp(p[i].x - p[id].x) && p[i].y < p[id].y)) id = i;
	if(id ^ 1) swap(p[1], p[id]);
	S = p[1];
	sort(p + 2, p + n + 1, cmpP);
	st[top = 1] = p[1];
	for(int i = 2; i <= n; ++i)
	{
		while(top > 1 && calcP(st[top - 1], st[top], p[i]) < 0) top--;
		st[++top] = p[i];
	}	
}
posted @ 2020-12-01 21:07  mrclr  阅读(181)  评论(0编辑  收藏  举报