计算几何小记

Preface

做了几道题之后才知道为什么计算几何真的是毒瘤(手动捂脸)

为了方便接下来的向量不带箭头。

点积

表示: U V U·V

几何定义: V V U U 上投影长度 * U U 的模长

代数定义: a . x b . x + a . y b . y a.x*b.x +a.y*b.y

连接两个向量,组成三角形,然后用余弦定理去证明。

叉积

表示: U × V U×V

几何定义: U U V V 的围成的平行四边形的有向面积。(如果 U × V 0 U×V\ge 0 )则 V V U U 左手向。

代数定义: a . x b . y b . x a . y a.xb.y-b.xa.y

这个随便证明。

精度误差

e e 是个小量,double下多取 1 0 8 10^{-8}

a = b a b < e a=b \Rightarrow |a-b|<e
a < b a < b e a\lt b \Rightarrow a\lt b-e
a b a < b + e a\le b \Rightarrow a\lt b+e

半平面交

注意一下几个步骤

  1. 极角排序:

    这个主要用 a t a n 2 ( y , x ) atan2(y,x) 这个函数。

    貌似这样常数很大,samjia说用叉积。

    但叉积麻烦,其实可以加入直线的时候先算出来,排序的时候再直接调用。

  2. 确定直线方向

    这点最重要了。

    一般来说,如果是围绕原点或者某个定点,我们需要规定一个方向,可以在加入直线的时候用函数判一判。

    但还是那句话,具体情况具体分析,有时候并不总围绕某个顶点时,而是只确定一个方向,这时候就要好好注意。

  3. 排序条件

    排序条件中有一栏是当两个向量极角相同时,我们必须只能保留到原点较短的那个。

    所以用atan2可以显得方便很多。

  4. 最后要用队尾更新队头

    这个也很重要。

代码

struct Dot {
	db x, y;
	Dot (db _x = 0, db _y = 0) { x = _x, y = _y; }

	friend Dot operator + (Dot a, Dot b) { return Dot(a.x + b.x, a.y + b.y); }
	friend Dot operator - (Dot a, Dot b) { return Dot(a.x - b.x, a.y - b.y); }
	friend db operator ^ (Dot a, Dot b) { return (a.x * b.y - b.x * a.y); }
	friend db operator * (Dot a, Dot b) { return (a.x * b.x + a.y * b.y); }
	friend Dot operator * (Dot a, db b) { return Dot(a.x * b, a.y * b); }
}

struct Line {
	Dot p, v; db px; // px是极角
	Line () {}
	Line (Dot _p, Dot _v) { p = _p, v = _v; }
	friend bool operator < (Line a, Line b) { return a.px - b.px < -e; }
}

db len(Dot a) { return sqrt(a ^ a); } // 模长
bool in(Line a, Dot b) { return a.v * (b - a.p) <= 0; } // 判断点b在直线a的左手向则返回1
db distl(Line a, Dot b) { return fabs(a.v * (b - a.p) / len(a.v))} // 点b到直线a的距离,运用叉积除以底得到高
Dot Ict(Line a, Line b) { return Dot(b.p + b.v * (a.v * (a.p - b.p) / (a.v * b.v))); } // 比例法,记住那副图,还有中间的a.p - b.p

上面几个操作就可以做半平面交了:

sort(d + 1, d + L + 1);
int h = 1, t = 1;
que[1] = d[1];
F(i, 2, L) {
	if (fabs(d[i].px - d[i - 1].px) <= e) continue;
	while (h < t && in(d[i], Ict(que[t - 1], que[t]))) t --;
	while (h < t && in(d[i], Ict(que[h], que[h + 1]))) h ++;
	que[++ t] = d[i];
}
while (h < t && in(que[h], Ict(que[t], que[t - 1]))) t --;

以上.

猜你喜欢

转载自blog.csdn.net/Algor_pro_king_John/article/details/94655841