知识点 - 计算几何基础

知识点 - 计算几何基础

讲义

我们把点 \(\mathbf r\) 看成从 \(\mathbf 0\) 到 \(\mathbf r\)的向量 \(\vec{\mathbf r}\)

#define ftype long double
struct point2d {
    ftype x, y;
    point2d() {}
    point2d(ftype x, ftype y): x(x), y(y) {}
    point2d& operator+=(const point2d &t) {
        x += t.x;
        y += t.y;
        return *this;
    }
    point2d& operator-=(const point2d &t) {
        x -= t.x;
        y -= t.y;
        return *this;
    }
    point2d& operator*=(ftype t) {
        x *= t;
        y *= t;
        return *this;
    }
    point2d& operator/=(ftype t) {
        x /= t;
        y /= t;
        return *this;
    }
    point2d operator+(const point2d &t) const {
        return point2d(*this) += t;
    }
    point2d operator-(const point2d &t) const {
        return point2d(*this) -= t;
    }
    point2d operator*(ftype t) const {
        return point2d(*this) *= t;
    }
    point2d operator/(ftype t) const {
        return point2d(*this) /= t;
    }
};
point2d operator*(ftype a, point2d b) {
    return b * a;
}

点乘

  1. \(\mathbf a \cdot \mathbf b = \mathbf b \cdot \mathbf a\)
  2. \((\alpha \cdot \mathbf a)\cdot \mathbf b = \alpha \cdot (\mathbf a \cdot \mathbf b)\)
  3. \((\mathbf a + \mathbf b)\cdot \mathbf c = \mathbf a \cdot \mathbf c + \mathbf b \cdot \mathbf c\)

若有单位向量:

\[\mathbf e_x = \begin{pmatrix} 1 \\\ 0 \\\ 0 \end{pmatrix}, \mathbf e_y = \begin{pmatrix} 0 \\\ 1 \\\ 0 \end{pmatrix}, \mathbf e_z = \begin{pmatrix} 0 \\\ 0 \\\ 1 \end{pmatrix}.\]
我们定义 \(\mathbf r = (x;y;z)\) 表示 \(r = x \cdot \mathbf e_x + y \cdot \mathbf e_y + z \cdot \mathbf e_z\).
因为
\[\mathbf e_x\cdot \mathbf e_x = \mathbf e_y\cdot \mathbf e_y = \mathbf e_z\cdot \mathbf e_z = 1,\\\mathbf e_x\cdot \mathbf e_y = \mathbf e_y\cdot \mathbf e_z = \mathbf e_z\cdot \mathbf e_x = 0\]
所以对 \(\mathbf a = (x_1;y_1;z_1)\) 和 \(\mathbf b = (x_2;y_2;z_2)\) 有
\[\mathbf a\cdot \mathbf b = (x_1 \cdot \mathbf e_x + y_1 \cdot\mathbf e_y + z_1 \cdot\mathbf e_z)\cdot( x_2 \cdot\mathbf e_x + y_2 \cdot\mathbf e_y + z_2 \cdot\mathbf e_z) = x_1 x_2 + y_1 y_2 + z_1 z_2\]

ftype dot(point2d a, point2d b) {
    return a.x * b.x + a.y * b.y;
}
ftype dot(point3d a, point3d b) {
    return a.x * b.x + a.y * b.y + a.z * b.z;
}

? 一些定义:

  1. Norm of \(\mathbf a\) (长度的平方): \(|\mathbf a|^2 = \mathbf a\cdot \mathbf a\)
  2. Length of \(\mathbf a\): \(|\mathbf a| = \sqrt{\mathbf a\cdot \mathbf a}\)
  3. Projection of \(\mathbf a\) onto \(\mathbf b\)(投影): \(\dfrac{\mathbf a\cdot\mathbf b}{|\mathbf b|}\)
  4. Angle between vectors(夹角): \(\arccos \left(\dfrac{\mathbf a\cdot \mathbf b}{|\mathbf a| \cdot |\mathbf b|}\right)\)
  5. 从上一点说明点乘的正负可以用来判断锐角(acute)钝角(obtuse)直角(orthogonal).
ftype norm(point2d a) {
    return dot(a, a);
}
double abs(point2d a) {
    return sqrt(norm(a));
}
double proj(point2d a, point2d b) {
    return dot(a, b) / abs(b);
}
double angle(point2d a, point2d b) {
    return acos(dot(a, b) / abs(a) / abs(b));
}

叉乘

定义:

先定义三重积triple product \(\mathbf a\cdot(\mathbf b\times \mathbf c)\) 为上面这个平行六面体的体积,于是我们可以得到\(\mathbf b\times \mathbf c\)的大小和方向。

性质:
  1. \(\mathbf a\times \mathbf b = -\mathbf b\times \mathbf a\)
  2. \((\alpha \cdot \mathbf a)\times \mathbf b = \alpha \cdot (\mathbf a\times \mathbf b)\)
  3. \(\mathbf a\cdot (\mathbf b\times \mathbf c) = \mathbf b\cdot (\mathbf c\times \mathbf a) = -\mathbf a\cdot( \mathbf c\times \mathbf b)\)
  4. \((\mathbf a + \mathbf b)\times \mathbf c = \mathbf a\times \mathbf c + \mathbf b\times \mathbf c\).
    对任意的 \(\mathbf r\) 有:
    \[\mathbf r\cdot( (\mathbf a + \mathbf b)\times \mathbf c) = (\mathbf a + \mathbf b) \cdot (\mathbf c\times \mathbf r) = \mathbf a \cdot(\mathbf c\times \mathbf r) + \mathbf b\cdot(\mathbf c\times \mathbf r) = \mathbf r\cdot (\mathbf a\times \mathbf c) + \mathbf r\cdot(\mathbf b\times \mathbf c) = \mathbf r\cdot(\mathbf a\times \mathbf c + \mathbf b\times \mathbf c)\]
    这证明了第三点 \((\mathbf a + \mathbf b)\times \mathbf c = \mathbf a\times \mathbf c + \mathbf b\times \mathbf c\)
  5. \(|\mathbf a\times \mathbf b|=|\mathbf a| \cdot |\mathbf b| \sin \theta\)

因为

\[\mathbf e_x\times \mathbf e_x = \mathbf e_y\times \mathbf e_y = \mathbf e_z\times \mathbf e_z = \mathbf 0,\\\mathbf e_x\times \mathbf e_y = \mathbf e_z,~\mathbf e_y\times \mathbf e_z = \mathbf e_x,~\mathbf e_z\times \mathbf e_x = \mathbf e_y\]
于是我们可以算出 \(\mathbf a = (x_1;y_1;z_1)\) 和 \(\mathbf b = (x_2;y_2;z_2)\) 的叉乘结果:

\[\mathbf a\times \mathbf b = (x_1 \cdot \mathbf e_x + y_1 \cdot \mathbf e_y + z_1 \cdot \mathbf e_z)\times (x_2 \cdot \mathbf e_x + y_2 \cdot \mathbf e_y + z_2 \cdot \mathbf e_z) =\]
\[(y_1 z_2 - z_1 y_2)\mathbf e_x + (z_1 x_2 - x_1 z_2)\mathbf e_y + (x_1 y_2 - y_1 x_2)\]

用行列式表达的话:

\[\mathbf a\times \mathbf b = \begin{vmatrix}\mathbf e_x & \mathbf e_y & \mathbf e_z \\\ x_1 & y_1 & z_1 \\\ x_2 & y_2 & z_2 \end{vmatrix},~a\cdot(b\times c) = \begin{vmatrix} x_1 & y_1 & z_1 \\\ x_2 & y_2 & z_2 \\\ x_3 & y_3 & z_3 \end{vmatrix}\]

二维的叉乘 (namely the pseudo-scalar product)可以被定义为
\[
|\mathbf e_z\cdot(\mathbf a\times \mathbf b)| = |x_1 y_2 - y_1 x_2|
\]
一个直观理解方式是为了计算\(|\mathbf a| \cdot |\mathbf b| \sin \theta\) 将 \(\mathbf a\)转 \(90^\circ\)得到\(\widehat{\mathbf a}=(-y_1;x_1)\).于是\(|\widehat{\mathbf a}\cdot\mathbf b|=|x_1y_2 - y_1 x_2|\).

point3d cross(point3d a, point3d b) {
    return point3d(a.y * b.z - a.z * b.y,
                   a.z * b.x - a.x * b.z,
                   a.x * b.y - a.y * b.x);
}
ftype triple(point3d a, point3d b, point3d c) {
    return dot(a, cross(b, c));
}
ftype cross(point2d a, point2d b) {
    return a.x * b.y - a.y * b.x;
}

直线与平面

? 一个直线可以被表示为一个起始点\(\mathbf r_0\) 和一个方向向量\(\mathbf d\) ,或者两个点\(\mathbf a\) , \(\mathbf b\).对应的方程为
\[
(\mathbf r - \mathbf r_0)\times\mathbf d=0 \\ (\mathbf r - \mathbf a)\times (\mathbf b - \mathbf a) = 0.
\]
? 一个平面可以被三个点确定: \(\mathbf a\), \(\mathbf b\) , \(\mathbf c\)。或者一个初始点\(\mathbf r_0\)和一组在这个平面里的向量\(\mathbf d_1\) , \(\mathbf d_2\)确定:
\[
(\mathbf r - \mathbf a)\cdot((\mathbf b - \mathbf a)\times (\mathbf c - \mathbf a))=0\(\mathbf r - \mathbf r_0)\cdot(\mathbf d_1\times \mathbf d_2)=0
\]

直线交点

\(l_1:\mathbf r = \mathbf a_1 + t \cdot \mathbf d_1\) 带入 \(l_2:(\mathbf r - \mathbf a_2)\times \mathbf d_2=0\)
\[
(\mathbf a_1 + t \cdot \mathbf d_1 - \mathbf a_2)\times \mathbf d_2=0 \quad\Rightarrow\quad t = \dfrac{(\mathbf a_2 - \mathbf a_1)\times\mathbf d_2}{\mathbf d_1\times \mathbf d_2}
\]

point2d intersect(point2d a1, point2d d1, point2d a2, point2d d2) {
    return a1 + cross(a2 - a1, d2) / cross(d1, d2) * d1;
}

三个平面交点

给你三个平面的初始点 \(\mathbf a_i\) 和法向量 \(\mathbf n_i\) 于是得到方程:
\[
\begin{cases}\mathbf r\cdot \mathbf n_1 = \mathbf a_1\cdot \mathbf n_1, \\\ \mathbf r\cdot \mathbf n_2 = \mathbf a_2\cdot \mathbf n_2, \\\ \mathbf r\cdot \mathbf n_3 = \mathbf a_3\cdot \mathbf n_3\end{cases}
\]
用克拉默法则解:

point3d intersect(point3d a1, point3d n1, point3d a2, point3d n2, point3d a3, point3d n3) {
    point3d x(n1.x, n2.x, n3.x);
    point3d y(n1.y, n2.y, n3.y);
    point3d z(n1.z, n2.z, n3.z);
    point3d d(dot(a1, n1), dot(a2, n2), dot(a3, n3));
    return point3d(triple(d, y, z),
                   triple(x, d, z),
                   triple(x, y, d)) / triple(n1, n2, n3);
}

模板

两个流派,一个是向量表示直线即两个点\(\mathbf a\) , \(\mathbf b\),另一个是直线方程即\(a_1 x + b_1 y + c_1 = 0\)

原文地址:https://www.cnblogs.com/SuuT/p/11370374.html

时间: 2024-08-27 02:56:56

知识点 - 计算几何基础的相关文章

nyis oj 68 三点顺序 (计算几何基础)

三点顺序 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描写叙述 如今给你不共线的三个点A,B,C的坐标,它们一定能组成一个三角形,如今让你推断A,B,C是顺时针给出的还是逆时针给出的? 如: 图1:顺时针给出 图2:逆时针给出 <图1>                   <图2> 输入 每行是一组測试数据,有6个整数x1,y1,x2,y2,x3,y3分别表示A,B,C三个点的横纵坐标.(坐标值都在0到10000之间) 输入0 0 0 0 0 0表示输入

计算几何基础——【点积和叉积的用处】

计算几何是算法竞赛的一大块,而叉积是计算机和的基础. 首先叉积是计算说向量之间的叉积,那么我们可以这样定义向量,以及向量的运算符重载. struct Point { double x,y; Point(double x=0,double y=0):x(x),y(y) {} }; typedef Point Vector; Vector operator + (Vector A,Vector B) { return Vector(A.x+B.x,A.y+B.y); } Vector operato

【kuangbin专题】计算几何基础(极角相关)

[POJ 1696] Space Ants [题目大意] 给定多个点,对他们按照下面的规则排序,每个都在前一个点组成的左边,并且连线不相交(典型如图) [题目分析] 不断进行极角排序,不断选取一定区域内最符合要求的解 [代码] 1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #define ll double 5 using namespace std; 6 const double eps

BZOJ_1610_[Usaco2008_Feb]_Line连线游戏_(计算几何基础+暴力)

描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1610 给出n个点,问两两确定的直线中,斜率不同的共有多少条. 分析 暴力枚举直线,算出来斜率放在k数组里面(斜率不存在记为INF),然后去个重统计个数就行了. 其实特水... 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn=200+5; 5 const double eps=1e-8,INF=0x7f

计算几何及其应用——计算几何基础

写在前面:当时开计算几何这个专题神奇的从解析几何开始了,然后最近发现<计算几何及应用(金博)>这本书前面那章忽略掉了一些重要的东西比如说点定位.半平面相交之类的东西,恰好还有一些和计算几何扯上边但是不需要算法的简单题目没有整理,故在此开辟一块小空间. 我们再来看一道有关几何的问题.(Problem source:hdu2073)    数理分析:虽然这道题异常的简单,基本算不上计算几何这个专题当中的题目,但是把它拿到这里来,是源于这道简单几何题的思路其实体现了计算几何整个体系中比较重要的思维.

【习题整理】计算几何基础

bzoj1074[Scoi2007]折纸 思路:考虑倒着做,每次将在折叠的直线右边的扔掉,左边的点再对称一次加入: 算几知识:求向量关于法向量的对称向量 点$A$关于点$B$对称的点$C = 2B - A$ 如果要求$\vec{A}$关于法向量$\vec{l}$的对称向量$\vec{A'}$: 可以考虑都平移到原点 利用点积求出$\vec{A}$在$\vec{l}$上的投影点$D$, 再将点$A$关于$D$对称到$A'$: $A'$的坐标就是向量$\vec{A'}$ 1 #include<bit

计算几何基础

记录点滴. 1 /* 2 2015.6 HT 3 ACM Work_8 4 5 */ 6 7 #include <iostream> 8 #include <cstdio> 9 using namespace std; 10 11 /* 12 线段判交--ACM 13 14 1.快速排斥实验 15 设以线段P1P2和线段Q1Q2为对角线的矩形为M,N;若M,N 不相交,则两个线段显然不相交: 16 2.跨立实验 17 如果两线段相交,则两线段必然相互跨立对方.若P1P2跨立Q1Q2

POJ_1269_Intersecting_Lines_(计算几何基础)

描述 http://poj.org/problem?id=1269 给出两条直线,判断它们是平行,重合,还是相交,如果相交,求出交点. 分析 比较裸的一道题.学习了直线的写法(参数方程) 1 #include <cstdio> 2 #include <cmath> 3 using namespace std; 4 5 const double eps=1e-8; 6 7 struct pt{ double x,y; pt(double x=0,double y=0):x(x),y(

[学习笔记]计算几何基础

三角函数 向量 线性空间中有大小和方向的量. 坐标表示:$P(x_1,y_1),Q(x_2,y_2)$. $\overrightarrow{PQ}=(x_2-x_1,y_2-y_1)$. $|PQ|=\sqrt{(x_2-x_1)^2+(y_2-y_1)^2}$. 向量运算 $a=(x_1,y_1),b=(x_2,y_2)$. 加法 $a+b=(x_1+x_2,y_1+y_2)$. 减法 $a-b=(x_1-x_2,y_1-y_2)$. 点乘 $a\;\cdot\;b=x_1x_2+y_1y_2