[Geometry] 程序员的几何学 - 入门 - [1]

入门

1.1 编程的哪些部分需要几何?

我已经提到了一些需要几何游戏引擎、CAD 框架和 3D 打印工具包的领域,但列表还不止于此。 虚拟现实、增强现实、计算机视觉系统、计算机断层扫描、2D 图形和动画以及数据可视化都使用相同的数学(尽管数量不同)。 您对数学了解得越多,您为所有这些任务使用和编写代码的效率就越高。 一般来说,了解工具背后的数学原理可以让你在任何相关领域成为更好的程序员。

但这种说法只是老生常谈。 让我们通过几个领域来看看几何在哪里有用、在哪里没用:

  • 游戏引擎 —— 在游戏引擎中,几何体主要负责对象定位、创建平滑变换、渲染和物理交互建模。 了解几何可能并不能让你成为更好的游戏设计师,但以最有效的方式编程视觉效果将使你的游戏在更广泛的游戏硬件上流畅运行。

  • 虚拟/增强现实 —— 虚拟或增强现实中的情况更加复杂,因为现在您需要根据每个用户调整渲染并考虑与现实世界对象的交互。 当然,并非所有这些问题都是几何问题。 例如,虚拟现实集的渲染校准是一个跨学科问题,涉及光学、硬件设计、解剖学甚至神经学。 一些神经系统疾病只会阻止用户遵循校准指南,在这种情况下,了解几何形状可能无济于事。

  • CAD —— 在计算机辅助设计中,所应用的几何形状用于精确的表面建模、计算表面约束实体的交集,并将这些实体转化为小块集合以进行有限元分析。 有限元分析是一种以编程方式模拟模型物理特性的方法,从而节省实际碰撞测试的时间和金钱。 这个过程本身并不是几何问题,它更多地与微分分析和计算有关,但是将模型从一种表示形式转换为另一种表示形式并返回是一个纯粹的几何问题。

  • 3D 打印 - 在 3D 打印中,除了打印本身之外,几何体完成了所有事情:准备模型,将它们有效地放置在打印机平台上,构建支撑结构以确保构建成功,然后将所有数据转换为打印机指令列表。 在这个领域,材料科学(例如用于金属印刷的冶金学或塑料化学)与数学一样重要。

  • 图像处理 - 在图像处理中,应用的几何体负责将原始像素数据转换为平滑的曲线或曲面(称为分割),并将这些对象定位在图像空间中(称为配准)。 图像本身的变换和空间定位也是几何问题。 但其中涉及的许多离散数学与几何无关。

拓扑学家会说,因为每组对象以及它们之间的一组关系构成了一个拓扑空间,所以关系数据库甚至源代码都是几何对象。 然而,这种对几何的理解过于宽泛而不实用。 在本书中,我们将继续关注曲线、曲面及其变换。

几何支持并启用许多编程领域。 它可能并不总是管弦乐队中的第一小提琴,但它通常像低音提琴一样不可或缺且不可替代。

1.2 对于程序员来说几何是什么?

我们在学校都学过几何。 几何从直线和圆、尺子和圆规开始,然后转向公理和定理——很多定理。 这种称为公理几何的几何本质上是心理健美操,不幸的是与编程关系不大(除非您正在编写一个向儿童教授公理几何的应用程序)。

几何只有在变得解析时才符合编程——当点获得坐标、曲线和曲面获得它们的公式时。 即便如此,某些几何尝试知识仍然比其他知识更与编程相关。 例如,cochoid(回旋曲线)、cissoid(西索曲线)和trisectrix(三等分曲线)等特殊曲线在现代工程中意义不大,因为您可以使用非均匀有理基础样条(简称 NURBS)等通用事物对它们进行建模。

如果这些术语不熟悉,请不要担心。 本书旨在解释您不熟悉的术语(如果您需要),如果您不需要则忽略它们。 我们将在第 7 章中回到 NURBS,但从现在开始,您将永远不会在本书中或可能在您的职业生涯中看到这三种特殊曲线。

解析几何与线性代数紧密相连,以至于你可以利用几何直觉来学习线性系统(第 3 章)或向量代数(第 9 章)。 要理解曲线和曲面,您还需要一小部分微积分。 第 5 章涵盖了您需要了解的所有内容; 它将导数引入为实用的几何工具,而不是某种抽象的分析工具。 同样,第 6 章介绍了多项式,它代表了您稍后将用来雕刻曲线和曲面的数字粘土。

说到曲线和曲面,第 7 章介绍了 NURBS,它是目前最流行的曲线和曲面建模工具,并且还解释了样条线的一般方法,使您可以制作自己的样条线公式,以实现最佳性能。

第 8 章介绍了如何生成和变形曲面,第 4 章介绍了如何使用称为矩阵乘法的单一操作来平移、旋转和缩放几何模型。

最后三章专门讨论用几何模型对现实世界甚至想象的对象进行建模的三种方法:有符号距离函数、边界表示和 3D 图像。 不同的模型在不同的上下文中效果最好,因此为了最有效地使用算法,您必须了解所有三种表示形式,以及如何将模型从一种表示形式转换为另一种表示形式。

为了回答“几何学的哪一部分适用于编程?”这个问题,本书中的所有内容都适用:直线、平面、曲线、曲面、变换、变形和几何数据表示。

1.3 为什么不让我的工具处理几何图形呢?

现代引擎和框架常常试图将您与数学隔离开来。在这种环境中进行创作就像驾驶一辆引擎盖被焊接关闭的汽车。 如果出了问题,你无法修复它,如果你想调整你的车比竞争对手跑得更快,你就必须亲自动手。

2013 年,我正在开发一种图像处理工具,可以将弯曲的页面从图片中拉直,使它们看起来平坦。 我用 C# 创建了一个原型,但速度很慢。 我想过用 C++ 重写它,因为常识告诉我们 C++ 比 C# 更快。 但首先,我使用分析器完成了整个工作流程,发现瓶颈在于初始图像投影(图 1.2)。

在这里插入图片描述
图 1.2 在 2D 中,创建投影本质上与将四边形转换为其他四边形相同。

这一发现很奇怪,因为这个操作应该很快。 投影一个点所需要做的就是执行九次乘法和六次加法。 就是这样。 通常,您可以使用矩阵乘法通过单个函数调用来执行所有这些操作(您将在第 4 章中看到如何操作)。 本质上,几何变换是简单的数字运算; 它应该很快。

但我使用标准库中的一种方法来进行转换,并且在幕后,它从一个点的一种表示形式到另一种表示形式进行了不少于四次转换。 该进程还有一个空的构造函数调用和一个名为CreateInstanceSlow 的方法。 计算本身是如此之快,以至于它甚至没有显示在分析器中,但所有转换的开销导致了速度减慢。

因此,我在代码中重新实现了转换,这样速度似乎快了一百倍以上。 代码长了四行,但没有转换,没有构造函数,也不再有慢速实例。

这里的主要要点是,当您了解数学知识时,您可以选择绕过必须使用的低效例程。 这个选项本身就是一种竞争优势。 但您还可以学到另一个教训:不信任数学会使您的代码变慢。

有人曾经认为矩阵乘法太复杂而不能暴露出来,所以他们用某种变换函数包装它。 其他人认为齐次坐标不是一个容易理解的概念,他们决定将射影空间点包装在仿射空间点转换器中。 然后另一个人决定应该从系统中禁止使用“projecteclive”和“affme”这两个词,并为它们编写了另一个包装。 总而言之,包装纸的重量变成了被包裹物重量的一百倍。 在糖果行业,这个结果将是令人震惊的。

对于毫无准备的人来说,这些术语和概念可能看起来很可怕,但事实是。用其他术语和概念包裹它们并不能让它们消失。 事实上,它只是引入了更多术语和概念。 包装并不会让事情变得更容易;学习才可以! 此外,这些事情一开始并不太复杂。

在本书中,您将学习有关projective spaces(射影空间)、homogeneous coordinates(齐次坐标)以及其他通常被认为晦涩难懂的概念所需的所有知识。 您将逐渐理解并信任游戏引擎和 CAD 框架代码背后的数学原理。 作为几何相关代码的用户,您将变得更加熟练,并且您还将获得自行重新实现部分代码的知识。

1.4 应用几何学一直存在。为什么现在才学呢?

两个实证观察解释了我们今天生活的技术格局。 首先是摩尔定律,该定律规定芯片上的晶体管数量大约每两年翻一番。 实际上,这一观察意味着计算机年复一年地变得更快、更小、更便宜。 当然,这种效果是有时间限制的; 理论上,晶体管的尺寸存在物理限制,因为亚原子晶体管并不存在。 不过,我们仍然观察到这种效果,即使它不是太明显。 摩尔定律不再适用于 PC 中央处理单元 (CPU),但移动设备的速度仍然越来越快,图形处理单元 (GPU) 也进展顺利。

第二个观察点是马丁的Lawn。 2014 年,罗伯特·C·马丁 (Robert C. Martin) 估计,在过去的 40 年里,世界上程序员的总数每五年就会翻一番。 当然,这种效果也是有时间限制的; 按照这个速度,到本世纪中叶我们就会耗尽非编程人员。

注意 Lawn 中的 n 不是拼写错误。 该观察结果发表在题为“My Lawn”的博文中,网址为:http://blog.cleancoder.com/uncle-bob/2014/06/20Mylawn.html。

摩尔定律的衰落意味着人们现在寻求其他方法来提高性能,而不是等到硬件变得更快。 新的架构、设备和商业模式随时可用。 例如,NVIDIA 的服务器端 GPU 根本就不是为了渲染画面; 他们不生成图形,而是以惊人的速度处理数字。 自2016年以来,谷歌已经生产了自己的计算机,但不是通用计算机; 它是一个专门用于人工智能工作的张量处理单元。 在低延迟为王的金融行业,大多数超快速计算已经在裸机中完成。

当然,云技术是一个巨大的游戏规则改变者——不是因为技术本身,而是因为它的商业模式。 在PC世界中,用户支付一台机器的费用,然后购买适合这台机器的软件。 因此,软件制造商应该优先考虑兼容性而不是性能。 消费者为运行时间付费,但如果产品不适合用户的机器,它就不会销售。

有了云,情况就有点不同了。 现在我们软件行业卖的是服务,而不是软件。 我们出售我们的软件的访问权限,该软件在别人的机器上运行。 云中的机器是我们自己花钱买的,所以性能很重要; 运行时间就是我们的成本。 但我们也可以决定这些机器是什么。 我们不再过多依赖用户的选择。 因此,我们可以自由地针对高度专业化的设备优化我们的代码,而且这样做是值得的。 当然,要优化执行您销售的服务的算法,您必须知道它们是如何工作的,这就是为什么了解数学很重要。 你还必须擅长编程,并且还必须了解机器。 但软件框架会来来去去,硬件架构也会不断发展; 唯一经得起时间考验的就是数学。

回到马丁的Lawn,大约半个世纪以来,对有能力的程序员的需求一直高于供给。 这种情况应该会在某个时候结束。市场会自行饱和,竞争会变得更加激烈。 为了在未来的竞争中获得优势,你应该从现在开始学习。

你无法学习不存在的硬件架构,你无法擅长尚未发明的编程语言。 但你可以学习几何。 它已经存在了几千年,而且还将继续存在几千年。 与未来的软件或硬件不同,您可以随时开始学习几何,而且越早越好。 那么为什么不今天呢?

1.5 您无需了解太多即可开始

这本书的名字是《Geomelry for Programmers》,而不是《Programming for Geomelers》,因此它不需要任何特定的高等数学知识。 这本书也不教你如何编程。 本书中的所有代码示例均采用 Python 编写,但我们非常欢迎您使用您选择的语言来进行练习或亲自尝试。 那么,您应该从哪些方面感到舒服才能继续阅读这本书呢? 你应该具备以下技能:

  • 阅读和理解 Python 代码片段——您不必特别擅长 Python 编程。 在本书的前半部分,您将遇到的 Python 代码片段本质上是伪装的公式。 我们将使用一个名为 SymPy 的 Python 库来为我们进行数学计算。 SymPy 是一种计算机代数系统,如果使用正确,可以替代多年的符号计算培训。 随着我们向实际应用迈进,我们将使用 Matplotlib 来绘制图片,并使用 NumPy 来进行数值计算。 您不必熟悉这些库中的任何一个; 我将在本书后面简要介绍它们。

  • 在头脑中想象事物 这本书有图片,但它们只是图片。为了正确地发展你的几何直觉,你需要了解对象如何相互作用以及它们如何响应参数变化。 这本书可以给你提示和方向,但要看到最终的“视频”,你必须发挥你的想象力。
    此外,书中的大部分材料都附有交互式演示和教程的链接。 你不必仅仅依靠阅读和编程; 您可以使用现成环境中呈现的概念。

  • 用您喜欢的任何语言进行编码——大多数章节都有练习,可以促使您用您选择的语言编写代码。 使用哪种语言并不重要; Python、JavaScript 和 Rust 中的几何形状是相同的。

  • 理解初等数学——本书中我会根据需要教你一些常见的数学概念,但你仍然需要理解基础知识,比如什么是方程和坐标平面,以及数学中函数的构成是什么感觉。
    这本书不需要接触高等数学。 如果您已经熟悉线性代数或微积分,这些知识将对您相关章节有所帮助,但这不是强制性的。 然而,对几何实体进行编程的本质意味着进行大量的符号计算——将您知道的公式转换为您想要的公式。 通常,这项任务需要大量的代数训练,但我们会通过使用计算机代数系统来作弊。 如今,让计算机为你做代数比听起来简单得多。 我们将在下一节中完成该任务。

1.6 SymPy 会为你做数学计算

我必须承认一件事:我的数学真的很糟糕。 我喜欢数学,但这种感觉不是相互的。

我喜欢数学的语言; 我喜欢它的解释力; 当我学习新概念并在实践中尝试时,我喜欢重新发明的感觉。 但是当涉及到进行符号计算时,我不能连续进行十几个而不弄乱加号和减号至少四次。

我一直都是这样。 当我向编辑展示我的第一篇学术论文时,他简单地看了一眼,指着第一个公式说:“你应该在这里说减号,而不是加号。”事实证明,我不止一次弄乱了符号 ; 我做了好几次了。

这种情况也使我作为工程师的职业生涯变得复杂。 幸运的是,一位擅长数学的朋友看到我在方程式上苦苦挣扎,就问我:“如果你这么讨厌这样做,那你为什么还要这样做呢?” “嗯,我会为此得到报酬,”我说。“当然,他回答道,“但是你为什么要手工做呢?"

在我朋友的世界里,只有当你喜欢这样做时,手工做数学才可以。在专业上,他使用 SymPy 做数学,这是一个符号数学库,旨在成为一个全功能的计算机代数系统。

符号数学和计算机代数可能看起来都太科学了,所以让我按照我朋友向我解释的方式来解释这个过程:“你导入 SymPy;然后你给它输入你的方程并说‘求解’。”就是这样。

让我们尝试一个简单的数学问题。 火车从阿姆斯特丹出发前往巴黎。 另一列火车从巴黎出发前往阿姆斯特丹,速度是原来的两倍。 巴黎和阿姆斯特丹之间的距离为 450 公里,火车在一小时内抵达。 火车的速度是多少?

当你用数学符号重写这个问题时,你会得到一对方程。 我们将从阿姆斯特丹出发的火车的速度称为 V a V_{a} Va,将巴黎火车的速度称为 V p V_{p} Vp。另外,我们将速度以公里每小时为单位存储。 现在,这两列火车每小时行驶 450 公里的事实就变成了这样,

V a + V p = 450 V_{a} + V_{p} = 450 Va+Vp=450

事实上,巴黎火车的速度是从阿姆斯特丹出发的火车的两倍,变成了这样:

V p = 2 V a V_{p} = 2V_{a} Vp=2Va

这些给了我们一个两部分方程组。 我相信你可以轻松解决你头脑中的问题,但请不要这样做。 让 SymPy 为您做这件事。 您甚至不必在计算机上安装 SymPy; 请访问 SymPy Live(网址为 https://live.sympy.org),并在那里尝试所有内容。

SymPy 是一个代数系统,可以为您计算代数,但它也是一个 Python 模块。 作为一个 Python 模块,它遵循 Python 规则,其中涉及一些含义。 首先,显然,您必须导入它才能使用它:

from sympy import *

接下来,您必须定义符号。 如果 SymPy 有自己的语言,则不需要执行此任务,但它重用了 Python 语法,并且在 Python 中,您必须在使用符号之前定义它们。 所以我们必须遵守这些规则。 让我们将阿姆斯特丹火车的速度定义为 Va,将巴黎火车的速度定义为 Vp:

Va, Vp = symbols('Va Vp')

接下来,让我们从速度差的方程开始,一一写出方程。 同样,SymPy 是一个 Python 模块,在 Python 中,= 是赋值运算符,所以我们不能写 Vp = 2Va。 相反,我们将所有方程都写成右侧为 0 的形式。 我们将所有东西从右侧移动到左侧,同时改变其符号。 所以 Vp = 2Va 变为

Vp - Va * 2,

现在“火车一小时后相遇”的等式如下所示:

Va * 1 + Vp * 1450

(您不必写 * 1,但让它保留一段时间。我们稍后会用其他内容替换它。)

接下来,要求 SymPy 求解这些方程:

solution = solve([
	 Vp - Va * 2,
	 Va * 1 + Vp * 1 - 450
	], (Va, Vp))

我们想知道 Va 和 Vp,因此在方程之后,我们将这些符号写在单独的元组中。 这个元组可能看起来像是不必要的重复,但是当我们引入更多符号时,我们就会明白为什么它是必要的。

最后,我们希望 SymPy 能给我们答案。 因为它使用Python,所以我们可以使用一个简单的打印命令:

print(solution)

就是这样。整个程序如下所示(本书源代码中的 ch_01/meet_sympy-numeric.py)。

清单 1.1 SymPy 中的数值解

from sympy import *
Va, Vp = symbols('Va Vp') //Va 是阿姆斯特丹火车的速度,Vp 是巴黎火车的速度,均以公里每小时为单位。
solution = solve([
	Vp - Va * 2,
	Va * 1 + Vp * 1 - 450
], (Va, Vp))
print(solution)

运行时,程序会打印以下内容:

{Va: 150, Vp: 300}

不错。 但这个结果并不是我们应该感到兴奋的数学结果。 这些是数字。我们可以用计算器得到数字。 那么字母和公式呢? SymPy 能否生成适用于任何距离、时间和速度比的广义方程?

是的,它可以。 SymPy 可以用字母进行数学运算。 我们将给它更多的符号和更少的数字。 让我们将代码中的所有常量(包括 1)更改为符号并重新运行程序,如清单 1.2 所示(本书源代码中的 ch_01/meet_sympy_symbolic.py)。

清单 1.2 SymPy 中的符号解

from sympy import *
Va, Vp, Vpx, D, t = symbols('Va Vp Vpx D t') 
//现在Vpx是一个比率,Vpa(以前是2); D 是巴黎和阿姆斯特丹之间的距离,单位为公里(450); 现在是火车集合前的时间(之前为 1 小时)。
solution = solve([
	Vp - Va * Vpx,
	Va * t + Vp * t - D
], (Va, Vp))
print(solution)

请注意,现在在方程后面写上 (Va, Vp) 更有意义。 我们希望通过时间象征性地计算速度,但我们也可以根据速度计算时间。 我们必须明确我们正在计算的内容。 元组中的符号是我们想要根据其他符号求解的符号。 在我们的例子中,这个解决方案是

{Va: D/(Vpx*t + t), Vp: D*Vpx/(Vpx*t + t)}

是的! 我们对两列火车问题有一个通用的解决方案。 他们现在可以从纽约飞往香港; 我们不在乎。 通过符号公式,我们可以解决每个距离、每个时间和每个速度比例的问题!

现在,因为我们是程序员,所以让我们将计算出的公式转化为代码。 我确信您可以轻松地手动完成此操作,但再次让 SymPy 为您完成此操作。 SymPhas 涵盖的工作。 如果您希望 SymPy 为您编写代码,您所需要做的就是提出要求!如果您需要一些 Python 代码,请使用 pycode 函数

print(pycode(solution))

SymPy 将打印以下内容:

{Va: D/(Vpx*t + t), Vp: D*Vpx/(Vpx*t + t)}

嗯,是的,这个结果与之前完全相同,但这只是因为我们的公式已经是有效的 Python 代码。 如果它们包含任何特定于语言的运算符和函数,那么此翻译功能会显得更加令人印象深刻。

我们可以要求 SymPy 使用 JavaScript(jscode)、Julia(julia_code)、FORTRAN(fcode)、C(ccode)、Octave 和 Matlab(octave_code),甚至 Rust(rust_code)生成代码。

另请参见 SymPy 的在线文档很棒。 如果您想了解有关代码生成的更多信息,请访问http://mng.bz/ElmO。

但是等等——还有更多! 假设您想发布您的方程。 数学家喜欢用 LaTeX 发布东西,那么我们为什么不也尝试一下呢? 使用 SymPy,您不必手动将解决方案转换为 LaTeX。 使用 Latex 函数代替 pycode:

print(latex(solution))

结果将是完美可打印的 LaTeX:

\left\{ Va : \frac{D}{Vpx t + t}, \ Vp : \frac{D Vpx}{Vpx t + t}\right\}

在打印中,公式将如下所示:

{ V a : D V p x t + t ,   V p : D V p x V p x t + t } \left\{ Va : \frac{D}{Vpx t + t}, \ Vp : \frac{D Vpx}{Vpx t + t}\right\} {Va:Vpxt+tD, Vp:Vpxt+tDVpx}

好的! 然而,在本书中,我们将谨慎使用数学符号。 请记住,这是程序员的几何,而不是几何的编程。

简单回顾一下:SymPy 是一个可以为您进行数学计算的 Python 库。 为了做到这一点,您必须导入它,声明方程的符号,将方程组合到一个系统中,然后运行求解。 如果可能,SymPy 将以数值方式求解方程。如果有必要,它将以符号方式求解方程,并用符号编写广义解。 然后,您可以将此解决方案转换为您选择的语言的代码,甚至转换为可发布的 LaTeX 公式。

现在您已经了解了使用 SymPy 实现高效工作所需的大部分内容。 您将在旅途中获得其余的内容。 恭喜! 您可能花了 15 分钟阅读这篇简介,并且您已经可以将计算机代数系统添加到您的简历中。 这不是一个好的开始吗?

总结

  • 应用几何学是在计算机图形学、动画、CAD、3D 和 2D 打印、增强和虚拟现实、计算机视觉和一般图像处理中应用的几何学。

  • 您可以随时开始学习几何,但现在可能是最好的时机。如果您已经作为 CAD 应用程序或游戏的程序员,或者在未来作为您的长期、不易腐烂的投资,那么您的学习将立即得到回报。

  • SymPy 是一个可以为您进行数学计算的 Python 库。 它可以进行一些数字运算,但它真正的用途是符号计算。 它将您拥有的公式转换为您想要的公式。此外,它还可以将公式转换为您选择的编程语言的源代码,并准备将其发布作为奖励。

  • 学习应用几何不需要稀有的技能或知识。 我们将使用 SymPy 为我们做数学计算,作为捷径。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值