<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Goldydocs on MU</title><link>https://choy-mutao.github.io/</link><description>Recent content in Goldydocs on MU</description><generator>Hugo</generator><language>zh-cn</language><atom:link href="https://choy-mutao.github.io/index.xml" rel="self" type="application/rss+xml"/><item><title>迭代器相关</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/stl/%E8%BF%AD%E4%BB%A3%E5%99%A8%E7%9B%B8%E5%85%B3/</link><pubDate>Mon, 01 Nov 2021 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/stl/%E8%BF%AD%E4%BB%A3%E5%99%A8%E7%9B%B8%E5%85%B3/</guid><description>描述</description></item><item><title>点</title><link>https://choy-mutao.github.io/geometry_10/%E5%9F%BA%E7%A1%80%E5%87%A0%E4%BD%95/math/point/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/geometry_10/%E5%9F%BA%E7%A1%80%E5%87%A0%E4%BD%95/math/point/</guid><description/></item><item><title>图的表示方法</title><link>https://choy-mutao.github.io/dsa_1/graph/%E5%9B%BE%E7%9A%84%E8%A1%A8%E7%A4%BA/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/dsa_1/graph/%E5%9B%BE%E7%9A%84%E8%A1%A8%E7%A4%BA/</guid><description>描述 邻接矩阵 用一个二维矩阵来存储两个节点之间的状态
缺点: 面对稀疏图时，有很多空间没有储存有效信息
确定邻接至或邻接于一个给定节点的集合需要用时 \(\Theta{(n)}\), 增加或删除一条 边仅需要 \(\Theta{(1)}\) 邻接链表 只考虑那些有连边的点对
对一个有 n 个点的图, 可以用 n 个链表, 第 i 个链表中存着从 i 直接连接的点
链式前向星表示的图 链式前向星（也称为邻接表的一种变种）是一种用于存储图的数据结构，它结合了数组和链表的优点，既节省空间又方便使用。在链式前向星中，每个节点的边不是直接存储在一个链表中，而是通过一个数组来存储所有边的信息，同时使用两个辅助数组来记录每条边的起点以及下一条边的位置。</description></item><item><title>新建一个窗口</title><link>https://choy-mutao.github.io/graphics_11/opengl/tut01/zh/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/graphics_11/opengl/tut01/zh/</guid><description>简介 欢迎来到第一课！
在学习 OpenGL 之前，我们将先学习如何生成，运行，和玩转（最重要的一点）课程中的代 码。
预备知识 不需要特别的预备知识。如果你有 C、Java、Lisp、Javascript 等编程语言的经验，那么 理解课程代码会更快；但这不是必需的；如果没有，那么也仅仅是同时学两样东西（编程语 言+OpenGL）会稍微复杂点而已。
课程全部用“傻瓜式 C++”编写：我费了很大劲尽量让代码简单些。代码里没有模板 （template）、类或指针。就是说，即使只懂 Java，也能理解所有内容。
忘记一切 如前面所说，我们不需要预备知识；但请暂时把『老式 OpenGL』先忘了吧（例如 glBegin()这类东西）。在这里，你将学习新式 OpenGL（OpenGL 3 和 4），而多数网上教 程还在讲『老式 OpenGL』（OpenGL 1 和 2）。所以，在你的脑袋乱成一锅粥之前，把它们 都搁在一边吧。
生成课程中的代码 所有课程代码都能在 Windows、Linux、和 Mac 上生成，而且过程大体相同：
更新驱动 下载 C++编译器。 安装 CMake 下载全部课程代码 用 CMake 创建工程 编译工程 试试这些例子！ 各平台的详细代码生成过程将会在后面一一给出，不过具体每个平台可能会有差异。如果你 不确定，可以去看看 Windows 平台的生成说明，然后按照需改动一下来适应你自己的 平台。
在 Windows 平台上生成代码 更新驱动应该很轻松。直接去 NVIDIA 或者 AMD 的官网下载。若不清楚 GPU 的型号:控 制面板-&amp;gt;系统和安全-&amp;gt;系统-&amp;gt;设备管理器-&amp;gt;显示适配器。如果是 Intel 集成显卡，一般 由电脑厂商（Dell、HP 等）提供驱动。
建议用 Visual Studio Express 来编译。 这里可以免费下载。 若喜欢用 MinGW，推 荐Qt Creator。安装哪个都行。下列步骤是用 Visual Studio 讲解的，其他 IDE 也差不多。</description></item><item><title>PSO gbest and lbest</title><link>https://choy-mutao.github.io/pso_30/original/gbestlbest/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/pso_30/original/gbestlbest/</guid><description>gbest 模型(全局最优模型) 全局最优模型的PSO中,一般定义为:
$$\hat{y}_t \in \left\{ \vec{p}_t^1, \vec{p}_t^2, \ldots, \vec{p}_t^s \right\} \mid f(\hat{y}_t) = \min \left( \left\{ f(\vec{p}_t^1), f(\vec{p}_t^2), \ldots, f(\vec{p}_t^s) \right\} \right)$$y作为目标粒子, 表示d维搜索空间中整个群或其邻域中最佳粒子的位置;
在 gbest 模型中，所有粒子都参考全局最优位置（全局最佳解）来更新自己的位置和速度。 全局最优位置是整个粒子群中所找到的最好的位置。 这种模型通常收敛速度较快，但容易陷入局部最优，因为所有粒子都朝向相同的目标移动。 lbest 模型(局部最优模型) 在 局部最优模型中, 如下定义一个粒子的符合线性排序邻居粒子:
$$N_i = \left\{ \vec{p}_t^{i-l}, \vec{p}_t^{i-l+1}, \ldots, \vec{p}_t^{i-1}, \vec{p}_t^i, \vec{p}_t^{i+1}, \ldots, \vec{p}_t^{i+l-1}, \vec{p}_t^{i+l} \right\}$$则 lbest模型公式如下
$$\hat{y}_t \in N_i \mid f(\hat{y}_t) = \min \left( \left\{ f(\vec{a}) \right\} \right), \forall \vec{a} \in N_i$$ 在 lbest 模型中，每个粒子仅参考其邻域内的最优位置来更新自己的位置和速度。 邻域的定义可以是粒子群中的一小部分粒子，通常是该粒子周围的某个固定数量的邻居粒子。 这种模型能够更好地保持多样性，减少陷入局部最优的风险，但收敛速度可能较慢</description></item><item><title>画第一个三角形</title><link>https://choy-mutao.github.io/graphics_11/opengl/tut02/zh/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/graphics_11/opengl/tut02/zh/</guid><description>描述 这将又是一篇长教程。
用 OpenGL 3 实现复杂的东西很方便；为此付出的代价是，画一个简单的三角形变得比较麻 烦。
不要忘了，定期复制粘贴，跑一下代码。
如果程序启动时崩溃了，很可能是你从错误的目录下运行了它。请仔细地阅读第一课中讲到的如何配置Visual Studio！
顶点数组对象(VAO) 你需要创建一个顶点数组对象，并将它设为当前对象（细节暂不深入）：
GLuint VertexArrayID; glGenVertexArrays(1, &amp;amp;VertexArrayID); glBindVertexArray(VertexArrayID); 当窗口创建成功后（即 [OpenGL 上下文] 创建后），马上做这一步工作；必须在任何其他 OpenGL 调用前完成。
若想进一步了解顶点数组对象（VAO），可以参考其他教程；但这不是很重要。
屏幕坐标系 三点定义一个三角形。当我们在三维图形学中谈论“点（point）”时，我们经常说“顶点 （Vertex）”。一个顶点有三个坐标：X，Y 和 Z。你可以用以下方式来想象这三个坐标：
X 在你的右方 Y 在你的上方 Z 是你背后的方向（是的，背后，而不是你的前方）这里有一 个更形象的方法：使用 [右手定则]
X 是你的拇指 Y 是你的食指 Z 是你的中指。如果你把你的拇指指向右边，食指指向天空， 那么中指将指向你的背后。让 Z 指往这个方向很奇怪，为什么要这样呢？简单的说：因为 基于右手定则的坐标系被广泛使用了 100 多年，它会给你很多有用的数学工具；而唯一的 缺点只是 Z 方向不直观。
补充：注意，你可以自由地移动你的手：你的 X，Y 和 Z 轴也将跟着移动（详见后文） 。
我们需要三个三维点来组成一个三角形；现在开始：
// An array of 3 vectors which represents 3 vertices static const GLfloat g_vertex_buffer_data[] = { -1.</description></item><item><title>图的深度优先搜索算法</title><link>https://choy-mutao.github.io/dsa_1/graph/%E5%9B%BE%E7%9A%84%E6%B7%B1%E5%BA%A6%E4%BC%98%E5%85%88%E6%90%9C%E7%B4%A2/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/dsa_1/graph/%E5%9B%BE%E7%9A%84%E6%B7%B1%E5%BA%A6%E4%BC%98%E5%85%88%E6%90%9C%E7%B4%A2/</guid><description>描述 深度优先搜索（Depth-First Search，DFS）是一种用于遍历或搜索树或图的算法。
DFS 的基本思想是从一个初始节点开始，尽可能[深入地探索]其子节点，直到无法继续深入 为止，然后回溯到上一个节点，继续探索其他未访问过的分支。这种策略类似 于[树的先序遍历] 。
DFS 的基本步骤 选择一个其实节点: 选择图中的任意一个节点作为起始节点 标记节点为已访问: 将当前节点标记为已访问，避免重复访问 递归访问相邻节点: 对于当前节点的每一个未访问过的相邻节点，递归地执行 DFS 回溯: 当当前节点的所有相邻节点都被访问过之后，回溯到上一个节点，继续访问 其他未访问过的分支</description></item><item><title>向量</title><link>https://choy-mutao.github.io/geometry_10/%E5%9F%BA%E7%A1%80%E5%87%A0%E4%BD%95/math/vector/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/geometry_10/%E5%9F%BA%E7%A1%80%E5%87%A0%E4%BD%95/math/vector/</guid><description/></item><item><title>Convergence Improvements</title><link>https://choy-mutao.github.io/pso_30/enhanced/convergence_improvements/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/pso_30/enhanced/convergence_improvements/</guid><description>Summary of the most important convergence improvements developed for PSO # Convergence Improvements ## New parameters ### Inertia weight ($\omega$) ### Constriction factor($K$) ### Guaranteed Convergence PSO (GCPSO) ### Near Neighbour Ineractions ## Cooperative PSO (CPSO) ## Stretched PSO (STPSO) ## Fully Informed Particle Swarm (FIPS) ## Hybrid approaches ### Evolutionary operators #### Selection #### Mutation #### Evolutionary PSO (EPSO) ### Other algorithms #### Genetic Algorithms(GA) #### Differential Evolutionary PSO (DEEPSO) #### Simulated Annealing(SA) #### Ant Colony Optimisation(ACO)</description></item><item><title>矩阵</title><link>https://choy-mutao.github.io/geometry_10/%E5%9F%BA%E7%A1%80%E5%87%A0%E4%BD%95/math/matrix/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/geometry_10/%E5%9F%BA%E7%A1%80%E5%87%A0%E4%BD%95/math/matrix/</guid><description/></item><item><title>矩阵</title><link>https://choy-mutao.github.io/graphics_11/opengl/tut03/zh/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/graphics_11/opengl/tut03/zh/</guid><description>描述 引擎完全没有推动飞船。飞船静止在原处，而引擎推动了环绕着飞船的宇宙。
《飞出个未来》(一部美国科幻动画片)
这一课是所有课程中最重要的。请至少看八遍。
齐次坐标（Homogeneous coordinates） 目前为止，我们仍然把三维顶点视为三元组(x, y, z)。现在引入一个新的分量 w，得到向 量(x, y, z, w)。
请先记住以下两点（稍后我们会给出解释）：
若 w==1，则向量(x, y, z, 1)为空间中的点。
若 w==0，则向量(x, y, z, 0)为方向。
（事实上，要永远记着。）
这有什么不同呢？对于旋转，二者没什么不同。当你旋转点和方向时，结果是一样的。但对 于平移（将点沿着某个方向移动），情况就不同了。『平移一个方向』是毫无意义的。
齐次坐标使我们能用同一个公式对点和方向作运算。
变换矩阵（Transformation matrices） 矩阵简介 简而言之，矩阵就是一个行、列数固定的，纵横排列的数表。比如，一个 2×3 矩阵看起来 像这样：
三维图形学中我们只用到 4×4 矩阵，它能对顶点(x, y, z, w)作变换。这一变换是用矩阵 左乘顶点来实现的：
矩阵 x 顶点（记住顺序！！矩阵左乘顶点，顶点用列向量表示）= 变换后的顶点
这看上去复杂，实则不然。左手指着 a，右手指着 x，得到 ax。 左手移向右边一个数 b， 右手移向下一个数 y，得到 by。依次类推，得到 cz、dw。最后求和 ax + by + cz + dw， 就得到了新的 x！每一行都这么算下去，就得到了新的(x, y, z, w)向量。
这种重复无聊的计算就让计算机代劳吧。</description></item><item><title>图的广度优先搜索算法</title><link>https://choy-mutao.github.io/dsa_1/graph/%E5%9B%BE%E7%9A%84%E5%B9%BF%E5%BA%A6%E4%BC%98%E5%85%88%E6%90%9C%E7%B4%A2/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/dsa_1/graph/%E5%9B%BE%E7%9A%84%E5%B9%BF%E5%BA%A6%E4%BC%98%E5%85%88%E6%90%9C%E7%B4%A2/</guid><description>描述 广度优先搜索（Breadth-First Search，简称 BFS）是一种用于遍历或搜索树或图的算法。 这种算法从根节点开始，然后遍历所有[相邻的]节点，之后对于每一个相邻的节点，再遍历 它们未访问过的相邻节点，依次类推，直到所有的节点都被访问过为止。BFS 是一种逐层扩 展节点的搜索策略，即先搜索离起始节点最近的所有节点，然后再搜索下一层的节点。
BFS 的基本步骤 初始化：选择一个起始节点，将其标记为已访问，并放入队列中。 处理队列中的节点： 从队列中移除第一个节点。 对于这个节点，访问它所有的邻接点。如果某个邻接点没有被访问过，则标记这个邻 接点为已访问，并将其添加到队列的末尾。 loop[2]，直到队列为空。 在实际操作中，为了防止重复访问同一个节点，通常需要使用一个数据结构来记录已经访 问过的节点。此外，队列是实现 BFS 的关键数据结构，因为它是先进先出（FIFO）的数 据结构，能够确保节点按照其被发现的顺序被处理。</description></item><item><title>彩色立方体</title><link>https://choy-mutao.github.io/graphics_11/opengl/tut04/zh/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/graphics_11/opengl/tut04/zh/</guid><description>彩色立方体 欢迎来到第四课！你将学到：
画立方体，代替单调的三角形 加上绚丽的色彩 学习深度缓存（Z-Buffer） 画立方体 立方体有六个方形表面，而OpenGL只支持画三角形，因此需要画12个三角形，每面两个。我们用定义三角形顶点的方式来定义这些顶点。
// Our vertices. Tree consecutive floats give a 3D vertex; Three consecutive vertices give a triangle. // A cube has 6 faces with 2 triangles each, so this makes 6*2=12 triangles, and 12*3 vertices static const GLfloat g_vertex_buffer_data[] = { -1.0f,-1.0f,-1.0f, // triangle 1 : begin -1.0f,-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, // triangle 1 : end 1.0f, 1.0f,-1.0f, // triangle 2 : begin -1.</description></item><item><title>欧拉</title><link>https://choy-mutao.github.io/geometry_10/%E5%9F%BA%E7%A1%80%E5%87%A0%E4%BD%95/math/euler/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/geometry_10/%E5%9F%BA%E7%A1%80%E5%87%A0%E4%BD%95/math/euler/</guid><description/></item><item><title>最小生成树</title><link>https://choy-mutao.github.io/dsa_1/graph/%E6%9C%80%E5%B0%8F%E7%94%9F%E6%88%90%E6%A0%91/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/dsa_1/graph/%E6%9C%80%E5%B0%8F%E7%94%9F%E6%88%90%E6%A0%91/</guid><description>描述 生成树（Spanning Tree）是[图论]中的一个重要概念，尤其在处理连通图时非常有用。生 成树是指一个[无向图]的一个子图，它是一个包含图中所有顶点的树。也就是说，生成树是 一棵包含了原图中所有节点的[无环连通子图]
最小生成树 最小生成树（Minimum Spanning Tree, MST）是图论中的一个基本概念，特别是在处理加权 无向图时非常重要。给定一个加权无向图，最小生成树是指该图的一个生成树，其中所有边 的权重之和是最小的。这意味着，在保证所有节点连通的情况下，最小生成树选取的边的总 成本最低</description></item><item><title>单源最短路径算法</title><link>https://choy-mutao.github.io/dsa_1/graph/%E5%8D%95%E6%BA%90%E6%9C%80%E7%9F%AD%E8%B7%AF%E5%BE%84%E7%AE%97%E6%B3%95/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/dsa_1/graph/%E5%8D%95%E6%BA%90%E6%9C%80%E7%9F%AD%E8%B7%AF%E5%BE%84%E7%AE%97%E6%B3%95/</guid><description/></item><item><title>四元数</title><link>https://choy-mutao.github.io/geometry_10/%E5%9F%BA%E7%A1%80%E5%87%A0%E4%BD%95/math/quaternion/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/geometry_10/%E5%9F%BA%E7%A1%80%E5%87%A0%E4%BD%95/math/quaternion/</guid><description/></item><item><title>纹理立方体</title><link>https://choy-mutao.github.io/graphics_11/opengl/tut05/zh/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/graphics_11/opengl/tut05/zh/</guid><description>第五课：纹理立方体 本课学习如下几点：
什么是UV坐标 怎样自行加载纹理 怎样在OpenGL中使用纹理 什么是滤波？什么是mipmap？怎样使用？ 怎样利用GLFW更加有效地加载纹理？ 什么是alpha通道？ 关于UV坐标 给一个模型贴纹理时，需要通过某种方式告诉OpenGL用哪一块图像来填充三角形。这是借助UV坐标来实现的。
每个顶点除了位置坐标外还有两个浮点数坐标：U和V。这两个坐标用于获取纹理，如下图所示：
注意纹理是怎样在三角形上扭曲的。
自行加载.BMP图片 了解BMP文件格式并不重要：很多库可以帮你做这个。但BMP格式极为简单，可以帮助你理解那些库的工作原理。所以，我们从头开始写一个BMP文件加载器，以便你理解其工作原理，不过（在实际工程中）千万别再用这个实验品。
如下是加载函数的声明：
GLuint loadBMP_custom(const char * imagepath); 使用方式如下：
GLuint image = loadBMP_custom(&amp;#34;./my_texture.bmp&amp;#34;); 接下来看看如何读取BMP文件。
首先需要一些数据。读取文件时将设置这些变量。
// Data read from the header of the BMP file unsigned char header[54]; // Each BMP file begins by a 54-bytes header unsigned int dataPos; // Position in the file where the actual data begins unsigned int width, height; unsigned int imageSize; // = width*height*3 // Actual RGB data unsigned char * data; 现在正式开始打开文件。</description></item><item><title>键盘和鼠标</title><link>https://choy-mutao.github.io/graphics_11/opengl/tut06/zh/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/graphics_11/opengl/tut06/zh/</guid><description>键盘和鼠标 欢迎来到第六课！
我们将学习如何通过鼠标和键盘来移动相机，就像在第一人称射击游戏中一样。
接口 这段代码在整个课程中多次被使用，因此把它单独放在一个文件中 ：common/controls.cpp，然后在 common/controls.hpp 中声明函数接口，这样 tutorial06.cpp 就能使用它们了。
和前节课比，tutorial06.cpp 里的代码变动很小。主要的变化是：每一帧都计算 MVP（投 影视图矩阵）矩阵，而不像之前那样只算一次。现在把这段代码加到主循环中：
do{ // ... // Compute the MVP matrix from keyboard and mouse input computeMatricesFromInputs(); glm::mat4 ProjectionMatrix = getProjectionMatrix(); glm::mat4 ViewMatrix = getViewMatrix(); glm::mat4 ModelMatrix = glm::mat4(1.0); glm::mat4 MVP = ProjectionMatrix * ViewMatrix * ModelMatrix; // ... } 这段代码需要 3 个新函数：
computeMatricesFromInputs()读键盘和鼠标操作，然后计算投影视图矩阵。这就是奇妙 所在。 getProjectionMatrix()返回计算好的投影矩阵。 getViewMatrix()返回计算好的视图矩阵。 这只是一种实现方式，当然，如果你不喜欢这些函数，勇敢地去改写它们。
来看看 controls.cpp 在做什么。
实际代码 我们需要几个变量。
// position glm::vec3 position = glm::vec3( 0, 0, 5 ); // horizontal angle : toward -Z float horizontalAngle = 3.</description></item><item><title>模型加载</title><link>https://choy-mutao.github.io/graphics_11/opengl/tut07/zh/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/graphics_11/opengl/tut07/zh/</guid><description>第七课：模型加载 目前为止，我们一直在硬编码描述立方体。你一定觉得这样做很笨拙、不方便。
本课将学习从文件中加载3D模型。和加载纹理类似，我们先写一个小的、功能有限的加载器，接着再为大家介绍几个比我们写的更好的、实用的库。
为了让课程尽可能简单，我们将采用简单、常用的OBJ格式。同样也是出于简单原则，我们只处理每个顶点有一个UV坐标和一个法向量的OBJ文件（目前你不需要知道什么是法向量）。
加载OBJ模型 加载函数在common/objloader.hpp中声明，在common/objloader.cpp中实现。函数原型如下：
bool loadOBJ( const char * path, std::vector &amp;amp; out_vertices, std::vector &amp;amp; out_uvs, std::vector &amp;amp; out_normals ) 我们让loadOBJ读取文件路径，把数据写入out_vertices/out_uvs/out_normals。如果出错则返回false。std::vector是C++中的数组，可存放glm::vec3类型的数据，数组大小可任意修改，不过std::vector和数学中的向量（vector）是两码事。其实它只是个数组。最后提一点，符号&amp;amp;意思是这个函数将会直接修改这些数组。
OBJ文件示例 OBJ文件看起来大概像这样：
# Blender3D v249 OBJ File: untitled.blend # www.blender3d.org mtllib cube.mtl v 1.000000 -1.000000 -1.000000 v 1.000000 -1.000000 1.000000 v -1.000000 -1.000000 1.000000 v -1.000000 -1.000000 -1.000000 v 1.000000 1.000000 -1.000000 v 0.999999 1.000000 1.000001 v -1.000000 1.000000 1.000000 v -1.000000 1.000000 -1.000000 vt 0.748573 0.750412 vt 0.</description></item><item><title>基础光照模型</title><link>https://choy-mutao.github.io/graphics_11/opengl/tut08/zh/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/graphics_11/opengl/tut08/zh/</guid><description>基础光照模型 在第八课中，我们将学习光照模型的基础知识。包括：
物体离光源越近会越亮 直视反射光时会有高亮（镜面反射） 当光没有直接照射物体时，物体会更暗（漫反射） 用环境光简化计算 不包括：
阴影。这是个宽阔的主题，大到需要专题教程了。 类镜面反射（包括水） 任何复杂的光与物质的相互作用，像次表面散射（比如蜡） 各向异性材料（比如拉丝的金属） 追求真实感的，基于物理的光照模型 环境光遮蔽（在洞穴里会更黑） 颜色溢出（一块红色的地毯会映得白色天花板带红色） 透明度 任何种类的全局光照（它包括了上面的所有） 总而言之：只讲基础。
法向 过去的几个教程中我们一直在处理法向，但是并不知道法向到底是什么。
三角形法向 一个平面的法向是一个长度为 1 并且垂直于这个平面的向量。
一个三角形的法向是一个长度为 1 并且垂直于这个三角形的向量。通过简单地将三角形两 条边进行叉乘计算（向量 a 和 b 的叉乘结果是一个同时垂直于 a 和 b 的向量，记得？） ，然后归一化：使长度为 1。伪代码如下：
triangle ( v1, v2, v3 ) edge1 = v2-v1 edge2 = v3-v1 triangle.normal = cross(edge1, edge2).normalize() 不要将法向(normal)和 normalize()函数混淆。Normalize()函数是让一个向量（任意向量 ，不一定必须是 normal）除以其长度，从而使新长度为 1。法向(normal)则是某一类向量 的名字。
顶点法向 引申开来：顶点的法向，是包含该顶点的所有三角形的法向的均值。这很方便——因为在顶点 着色器中，我们处理顶点，而不是三角形；所以在顶点处有信息是很好的。并且在 OpenGL 中，我们没有任何办法获得三角形信息。伪代码如下：
vertex v1, v2, v3, .... triangle tr1, tr2, tr3 // all share vertex v1 v1.</description></item><item><title>VBO索引</title><link>https://choy-mutao.github.io/graphics_11/opengl/tut09/zh/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/graphics_11/opengl/tut09/zh/</guid><description>第九课：VBO索引 索引的原理 目前为止，建立VBO时我们总是重复存储一些共享的顶点和边。
本课将介绍索引技术。借助索引，我们可以重复使用一个顶点。这是用*索引缓冲区（index buffer）*来实现的。
索引缓冲区存储的是整数；每个三角形有三个整数索引，用索引就可以在各种属性缓冲区（顶点坐标、颜色、UV坐标、其他UV坐标、法向缓冲区等）中找到顶点的信息。这有点像OBJ文件格式，但有一点相差甚远：索引缓冲区只有一个。这意味着若两个三角形共用一个顶点，那这个顶点的所有属性对两个三角形来说都是一样的。
共享vs分开 来看看法向的例子。下图中，艺术家创建了两个三角形，试图模拟一个平滑曲面。可以把两个三角形的法向融合成一个顶点的法向。为方便观看，我画了一条红线表示平滑曲面。
然而在第二幅图中，美工想画的是“缝隙”或“边缘”。若融合了法向，就意味着色器会像前例一样进行平滑插值，生成一个平滑的表面：
因此在这种情况下，把顶点的法向分开存储反而更好；在OpenGL中，唯一实现方法是：把顶点连同其属性完整复制一份。
OpenGL中的索引VBO 索引的用法很简单。首先，需要创建一个额外的缓冲区存放索引。代码与之前一样，不过参数是ELEMENT_ARRAY_BUFFER，而非ARRAY_BUFFER。
std::vector&amp;lt;unsigned int&amp;gt; indices; // fill &amp;#34;indices&amp;#34; as needed // Generate a buffer for the indices GLuint elementbuffer; glGenBuffers(1, &amp;amp;elementbuffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &amp;amp;indices[0], GL_STATIC_DRAW); 只需把glDrawArrays替换为如下语句，即可绘制模型：
// Index buffer glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer); // Draw the triangles ! glDrawElements( GL_TRIANGLES, // mode indices.size(), // count GL_UNSIGNED_INT, // type (void*)0 // element array buffer offset ); （小提示：最好使用unsigned short，不要用unsigned int。这样更节省空间，速度也更快。）</description></item><item><title>透明</title><link>https://choy-mutao.github.io/graphics_11/opengl/tut10/zh/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/graphics_11/opengl/tut10/zh/</guid><description>第十课：透明 alpha通道 alpha通道的概念很简单。之前是写RGB结果，现在改为写RGBA：
// Ouput data : it&amp;#39;s now a vec4 out vec4 color; 前三个分量仍可以通过混合操作符（swizzle operator）.xyz访问，最后一个分量通过.a访问：
color.a = 0.3; 不太直观，但alpha = 不透明度；因此alpha = 1代表完全不透明，alpha = 0为完全透明。
这里我们简单地将alpha硬编码为0.3；但更常见的做法是用一个uniform变量表示它，或从RGBA纹理中读取（TGA格式支持alpha通道，而GLFW支持TGA）。
结果如下。既然我们能“看透”模型表面，请确保关闭隐面消除（glDisable(GL_CULL_FACE) ）。否则就发现模型没有了“背”面。 顺序很重要！ 上一个截图看上去还行，但这仅仅是运气好罢了。
###问题所在### 这里我画了一红一绿两个alpha值为50%的正方形。从中可以看出顺序的重要性，最终的颜色显著影响了眼睛对深度的感知。
我们的场景中也出现了同样的现象。试着稍稍改变一下视角：
事实证明这个问题十分棘手。游戏中透明的东西不多，对吧？
###常见解决方案###
常见解决方案即对所有的透明三角形排序。是的，所有的透明三角形。
绘制场景的不透明部分，让深度缓冲区能丢弃被遮挡的透明三角形。 对透明三角形按深度从近到远排序。 绘制透明三角形。 可以用C语言的qsort函数或者C++的std::sort函数来排序。细节就不多说了，因为……
###警告###
这么做可以解决问题（下一节还会介绍它），但：
填充速率会被限制，即，每个片断会写10、20次，也许更多。这对力不从心的内存总线来说太沉重了。通常，深度缓冲区可以自动丢弃“远”片断；但这时，我们显式地对片断进行排序，故深度缓冲区实际上没发挥作用。 这些操作，每个像素上都会做4遍（我们用了4倍多重采样抗锯齿（MSAA）），除非用了什么高明的优化。 透明三角形排序很耗时 若要逐个三角形地切换纹理，或者更糟糕地，要切换着色器——性能会大打折扣。别这么干。 一个足够好的解决方案是：
限制透明多边形的数量 对所有透明多边形使用同一个着色器和纹理 若这些透明多边形必须看起来很不同，请用纹理区分！ 若不排序，效果也还行，那最好别排序。 ###顺序无关透明 如果你的引擎确实需要顶尖的透明效果，这有一些技术值得研究一番：
2001年Depth Peeling论文：像素级精细度，但速度不快 Dual Depth Peeling：小幅改进 桶排序相关的几篇论文。把fragment存到数组，在shader中进行深度排序。 ATI Mecha Demo：又好又快，但实现起来有难度，需要最新的硬件。用链表存储fragment。 Cyril Crassin实现的ATI Mecha：实现难度更大 注意，即便是《小小大星球》（Little Big Planet）这种最新的端游，也只用了一层透明。
混合函数 要让之前的代码运行，得设置好混合函数。In order for the previous code to work, you need to setup your blend function.</description></item><item><title>2D文本</title><link>https://choy-mutao.github.io/graphics_11/opengl/tut11/zh/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/graphics_11/opengl/tut11/zh/</guid><description>第十一课：2D文本
本课将学习如何在三维场景之上绘制二维文本。本例是一个简单的计时器：
API 我们将实现这些简单的接口（位于common/text2D.h）：
void initText2D(const char * texturePath); void printText2D(const char * text, int x, int y, int size); void cleanupText2D(); 为了让代码在640*480和1080p分辨率下都能正常工作，x和y的范围分别设为[0-800]和[0-600]。顶点着色器将根据实际屏幕大小做对它做调整。
完整的实现代码请参阅common/text2D.cpp。
纹理 initText2D简单地读取一个纹理和一些着色器，很好理解。来看看纹理：
该纹理由CBFG生成。CBFG是诸多从字体生成纹理的工具之一。把纹理加载到Paint.NET，加上红色背景（仅为了观察方便；本教程中的红色背景，都代表透明）。
printText2D()在屏幕的适当位置，生成一个纹理坐标正确的四边形。
绘制 首先，填充这些缓冲区：
std::vector&amp;lt;glm::vec2&amp;gt; vertices; std::vector&amp;lt;glm::vec2&amp;gt; UVs; 文本中的每个字母，都要计算其四边形包围盒的顶点坐标，然后添加两个三角形（组成一个四边形）：
for ( unsigned int i=0 ; i&amp;lt;length ; i++ ){ glm::vec2 vertex_up_left??? = glm::vec2( x+i*size???? , y+size ); glm::vec2 vertex_up_right?? = glm::vec2( x+i*size+size, y+size ); glm::vec2 vertex_down_right = glm::vec2( x+i*size+size, y????? ); glm::vec2 vertex_down_left? = glm::vec2( x+i*size?</description></item><item><title>OpenGL扩展</title><link>https://choy-mutao.github.io/graphics_11/opengl/tut12/zh/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/graphics_11/opengl/tut12/zh/</guid><description>第十二课：OpenGL扩展 扩展 GPU的性能随着更新换代一直在提高，支持渲染更多的三角形和像素点。然而，原始性能不是我们唯一关心的。NVIDIA, AMD和Intel也通过增加功能来改善他们的显卡。来看一些例子。
ARB_fragment_program 回溯到2002年，GPU都没有顶点着色器或片断着色器：所有的一切都硬编码在芯片中。这被称为固定功能流水线（Fixed-Function Pipeline (FFP)）。同样地，当时最新的OpenGL 1.3中也没有接口可以创建、操作和使用所谓的“着色器”，因为它根本不存在。接着NVIDIA决定用实际代码描述渲染过程，来取代数以百计的标记和状态量。这就是ARB_fragment_program的由来。当时还没有GLSL，但你可以写这样的程序：
!!ARBfp1.0 MOV result.color, fragment.color; END 但若要显式地令OpenGL使用这些代码，你需要一些还不在OpenGL里的特殊函数。在进行解释前，再举个例子。
ARB_debug_output 好，你说『ARB_fragment_program太老了，所以我不需要扩展这东西』？其实有不少新的扩展非常方便。其中一个便是ARB_debug_output，它提供了一个不存在于OpenGL 3.3中的，但你可以/应该用到的功能。它定义了像GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB或GL_DEBUG_SEVERITY_MEDIUM_ARB之类的字符串，和DebugMessageCallbackARB这样的函数。这个扩展的伟大之处在于，当你写了一些不正确的代码，例如：
glEnable(GL_TEXTURE); // Incorrect ! You probably meant GL_TEXTURE_2D ! 你能得到错误消息和错误的精确位置。总结：
即便在现在的OpenGL 3.3中，扩展仍旧十分有用。 请使用ARB_debug_output ！下文有链接。 获取扩展 – 复杂的方式 『手动』查找一个扩展的方法是使用以下代码片断 (转自OpenGL.org wiki)：
int NumberOfExtensions; glGetIntegerv(GL_NUM_EXTENSIONS, &amp;amp;NumberOfExtensions); for(i=0; i&amp;lt;NumberOfExtensions; i++) { const GLubyte *ccc=glGetStringi(GL_EXTENSIONS, i); if ( strcmp(ccc, (const GLubyte *)&amp;#34;GL_ARB_debug_output&amp;#34;) == 0 ){ // The extension is supported by our hardware and driver // Try to get the &amp;#34;glDebugMessageCallbackARB&amp;#34; function : glDebugMessageCallbackARB = (PFNGLDEBUGMESSAGECALLBACKARBPROC) wglGetProcAddress(&amp;#34;glDebugMessageCallbackARB&amp;#34;); } } 获得所有的扩展 – 简单的方式 上面的方式太复杂。若用GLEW, GLee, gl3w这些库，就简单多了。例如，有了GLEW，你只需要在创建窗口后调用glewInit()，不少方便的变量就创建好了：</description></item><item><title>法线贴图</title><link>https://choy-mutao.github.io/graphics_11/opengl/tut13/zh/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/graphics_11/opengl/tut13/zh/</guid><description>第十三课：法线贴图 欢迎来到第十三课！今天讲法线贴图（normal mapping）。
学完第八课：基本光照模型后，我们知道了如何用三角形法线得到不错的光照效果。需要注意的是，截至目前，每个顶点仅有一个法线：在三角形三个顶点间，法线是平滑过渡的；而颜色（纹理的采样）恰与此相反。
法线纹理 法线纹理看起来像这样：
每个纹素的RGB值实际上表示的是XYZ向量：颜色的分量取值范围为0到1，而向量的分量取值范围是-1到1；可以建立从纹素到法线的简单映射：
normal = (2*color)-1 // on each component 法线纹理整体呈蓝色，因为法线基本是朝上的（上方即Z轴正向。OpenGL中Y轴=上，有所不同。这种不兼容很蠢，但没人想为此重写现有的工具，我们将就用吧。后面介绍详情。）
法线纹理的映射方式和颜色纹理相似。麻烦的是如何将法线从各三角形局部坐标系（切线坐标系tangent space，亦称图像坐标系image space）变换到模型坐标系（计算光照采用的坐标系）。
切线和双切线（Tangent and Bitangent） 想必大家对矩阵已经十分熟悉了；大家知道，定义一个坐标系（本例是切线坐标系）需要三个向量。现在Up向量已经有了，即法线：可用Blender计算，或做一个简单的叉乘。下图中蓝色箭头代表法线（法线贴图整体颜色也恰好是蓝色）。
然后是切线T：垂直于平面的向量。切线有很多个：
这么多切线中该选哪一个呢？理论上，任何一个都可以。不过我们得和相邻顶点保持一致，以免导致边缘出现瑕疵。一个通行的办法是将切线方向和纹理坐标系对齐：
定义一组基需要三个向量，因此我们还得计算双切线B（本来可以随便选一条切线，但选定垂直于其他两条轴的切线，计算会方便些）。
算法如下：若把三角形的两条边记为deltaPos1和deltaPos2，deltaUV1和deltaUV2是对应的UV坐标下的差值；此问题可用如下方程表示：
deltaPos1 = deltaUV1.x * T + deltaUV1.y * B deltaPos2 = deltaUV2.x * T + deltaUV2.y * B 求解T和B就得到了切线和双切线！（代码见下文）
已知T、B、N向量之后，即可得下面这个漂亮的矩阵，完成从模型坐标系到切线坐标系的变换：
有了TBN矩阵，我们就能把法线（从法线纹理中提取而来）变换到模型坐标系。
可我们需要的却是与之相反的变换：从切线坐标系到模型坐标系，法线保持不变。所有计算均在切线坐标系中进行，不会对其他计算产生影响。
既然要进行逆向的变换，那只需对以上矩阵求逆即可。这个矩阵（正交阵，即各向量相互正交，请看后面“延伸阅读”小节）的逆矩阵恰好也就是其转置矩阵，计算十分简单：
invTBN = transpose(TBN) 亦即：
准备VBO ###计算切线和双切线### 我们需要为整个模型计算切线、双切线和法线。用一个单独的函数完成这项工作：
void computeTangentBasis( // inputs std::vector&amp;lt;glm::vec3&amp;gt; &amp;amp; vertices, std::vector&amp;lt;glm::vec2&amp;gt; &amp;amp; uvs, std::vector&amp;lt;glm::vec3&amp;gt; &amp;amp; normals, // outputs std::vector&amp;lt;glm::vec3&amp;gt; &amp;amp; tangents, std::vector&amp;lt;glm::vec3&amp;gt; &amp;amp; bitangents ){ 为每个三角形计算边（deltaPos）和deltaUV</description></item><item><title>渲染到纹理</title><link>https://choy-mutao.github.io/graphics_11/opengl/tut14/zh/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/graphics_11/opengl/tut14/zh/</guid><description>第十四课：渲染到纹理 “渲染到纹理”是一系列特效方法之一。基本思想是：像通常那样渲染一个场景——只是这次是渲染到可以重用的纹理中。
应用包括：游戏（in-game）相机、后期处理（post-processing）以及你能想象到一切.
渲染到纹理 我们有三个任务：创建要渲染的纹理对象；将纹理渲染到对象上；使用生成的纹理。
###创建渲染目标（Render Target）###
我们要渲染的对象叫做帧缓存。它像一个容器，用来存纹理和一个可选的深度缓冲区(depth buffer)。在OpenGL中我们可以像创建其他对象一样创建它:
// The framebuffer, which regroups 0, 1, or more textures, and 0 or 1 depth buffer. GLuint FramebufferName = 0; glGenFramebuffers(1, &amp;amp;amp;FramebufferName); glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName); 现在需要创建纹理，纹理中包含着色器的RGB输出。这段代码非常的经典：
// The texture we&amp;#39;re going to render to GLuint renderedTexture; glGenTextures(1, &amp;amp;amp;renderedTexture); // &amp;#34;Bind&amp;#34; the newly created texture : all future texture functions will modify this texture glBindTexture(GL_TEXTURE_2D, renderedTexture); // Give an empty image to OpenGL ( the last &amp;amp;quot;0&amp;amp;quot; ) glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, 1024, 768, 0,GL_RGB, GL_UNSIGNED_BYTE, 0); // Poor filtering.</description></item><item><title>光照贴图（Lightmap）</title><link>https://choy-mutao.github.io/graphics_11/opengl/tut15/zh/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/graphics_11/opengl/tut15/zh/</guid><description>第十五课：光照贴图（Lightmap） 简介 这堂课是视频课程，没有介绍新的OpenGL相关技术/语法。不过，大家会学习如何利用现有知识，生成高质量的阴影。
本课介绍了用Blender创建简单场景的方法；还介绍了如何烘培（bake）光照贴图（lightmap），以便在你的项目中使用。
无需Blender预备知识，我会讲解包括快捷键的所有内容
关于光照贴图 光照图是永久、一次性地烘焙好的。也就是说光照图是完全静态的，你不能在运行时移动光源，连删除都不行。
但对于阳光这种光源来说，光照图还是大有用武之地的；在不会打碎灯泡的室内场景中，也是可以的。2009年发布的《镜之边缘》（Mirror Edge）室内、室外场景中大量采用了光照图。
更重要的是，光照图很容易配置，速度无可匹敌。
视频 这是个1024x768 高清视频。
Youku 标清含中文字幕 Vimeo 高清原版视频
附录 用OpenGL渲染时，你大概会注意到一些瑕疵（这里故意把瑕疵放大了）：
这是由mipmap造成的。从远处观察时，mipmap对纹素做了混合。纹理背景中的黑色像素点和光照图中的像素点混合在了一起。为了避免这一点，可以采取如下措施：
让Blender在UV图的limits上生成一个margin。这个margin参数位于bake面板。要想效果更好，可以把margin值设为20个纹素。 获取纹理时，加上一个偏离（bias）： color = texture2D( myTextureSampler, UV, -2.0 ).rgb; -2是偏离量。这个值是通过不断尝试得出的。上面的截图中bias值为+2，也就是说OpenGL将在原本的mipmap层次上再加两层（因此，纹素大小变为原来的1/16，瑕疵也随之变小了）。-
后期处理中可将背景填充为黑色，这一点我后面还会再讲。</description></item><item><title>阴影贴图（Shadow mapping）</title><link>https://choy-mutao.github.io/graphics_11/opengl/tut16/zh/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/graphics_11/opengl/tut16/zh/</guid><description>第十六课：阴影贴图（Shadow mapping） 第十五课中已经学习了如何创建光照贴图。光照贴图可用于静态对象的光照，其阴影效果也很不错，但无法处理运动的对象。
阴影贴图是目前（截止2012年）最好的生成动态阴影的方法。此法最大的优点是易于实现，缺点是想完全正确地实现不大容易。
本课首先介绍基本算法，探究其缺陷，然后实现一些优化。由于撰写本文时（2012），阴影贴图技术还在被广泛地研究；我们将提供一些指导，以便你根据自身需要，进一步改善你的阴影贴图。
基本的阴影贴图 基本的阴影贴图算法包含两个步骤。首先，从光源的视角将场景渲染一次，只计算每个片断的深度。接着从正常的视角把场景再渲染一次，渲染时要测试当前片断是否位于阴影中。
“是否在阴影中”的测试实际上非常简单。如果当前采样点比阴影贴图中的同一点离光源更远，那说明场景中有一个物体比当前采样点离光源更近；即当前片断位于阴影中。
下图可以帮你理解上述原理：
###渲染阴影贴图### 本课只考虑平行光——一种位于无限远处，其光线可视为相互平行的光源。故可用正交投影矩阵来渲染阴影贴图。正交投影矩阵和一般的透视投影矩阵差不多，只不过未考虑透视——因此无论距离相机多远，物体的大小看起来都是一样的。
###设置渲染目标和MVP矩阵### 十四课中，大家学习了把场景渲染到纹理，以便稍后从shader中访问的方法。
这里采用了一幅1024x1024、16位深度的纹理来存储阴影贴图。对于阴影贴图来说，通常16位绰绰有余;你可以自由地试试别的数值。注意，这里采用的是深度纹理，而非深度渲染缓冲区（这个要留到后面进行采样）。
// The framebuffer, which regroups 0, 1, or more textures, and 0 or 1 depth buffer. GLuint FramebufferName = 0; glGenFramebuffers(1, &amp;amp;FramebufferName); glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName); // Depth texture. Slower than a depth buffer, but you can sample it later in your shader GLuint depthTexture; glGenTextures(1, &amp;amp;depthTexture); glBindTexture(GL_TEXTURE_2D, depthTexture); glTexImage2D(GL_TEXTURE_2D, 0,GL_DEPTH_COMPONENT16, 1024, 1024, 0,GL_DEPTH_COMPONENT, GL_FLOAT, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexture, 0); glDrawBuffer(GL_NONE); // No color buffer is drawn to.</description></item><item><title>旋转</title><link>https://choy-mutao.github.io/graphics_11/opengl/tut17/zh/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/graphics_11/opengl/tut17/zh/</guid><description>##第十七课：旋转
虽然本课有些超出OpenGL的范围，但是解决了一个常见问题：怎样表示旋转？
《第三课：矩阵》中，我们了解到矩阵可以让点绕某个轴旋转。矩阵可以简洁地表示顶点的变换，但使用难度较大：例如，从最终结果中获取旋转轴就很麻烦。
本课将展示两种最常见的表示旋转的方法：欧拉角（Euler angles）和四元数（Quaternion）。最重要的是，本课将详细解释为何要尽量使用四元数。
旋转与朝向（orientation） 阅读有关旋转的文献时，你可能会为其中的术语感到困惑。本课中：
“朝向”是状态：该物体的朝向为……
“旋转”是操作：旋转该物体
也就是说，当实施旋转操作时，就改变了物体的朝向。 两者形式相同，因此容易混淆。闲话少叙，开始进入正题……
欧拉角 欧拉角是表示朝向的最简方法，只需存储绕X、Y、Z轴旋转的角度，非常容易理解。你可以用vec3来存储一个欧拉角：
vec3 EulerAngles( RotationAroundXInRadians, RotationAroundYInRadians, RotationAroundZInRadians); 这三个旋转是依次施加的，通常的顺序是：Y-Z-X（但并非一定要按照这种顺序）。顺序不同，产生的结果也不同。
一个欧拉角的简单应用就是用于设置角色的朝向。通常，游戏角色不会绕X和Z轴旋转，仅仅绕竖直的Y轴旋转。因此，无需处理三个朝向，只需用一个float型变量表示方向即可。
另外一个使用欧拉角的例子是FPS相机：用一个角度表示头部朝向（绕Y轴），一个角度表示俯仰（绕X轴）。参见common/controls.cpp的示例。
不过，面对更加复杂的情况时，欧拉角就显得力不从心了。例如：
对两个朝向进行插值比较困难。简单地对X、Y、Z角度进行插值得到的结果不太理想。 实施多次旋转很复杂且不精确：必须计算出最终的旋转矩阵，然后据此推测书欧拉角。 “臭名昭著”的“万向节死锁”(Gimbal Lock)问题有时会让旋转“卡死”。其他一些奇异状态还会导致模型方向翻转。 不同的角度可产生同样的旋转（例如-180°和180°） 容易出错——如上所述，一般的旋转顺序是YZX，如果用了非YZX顺序的库，就有麻烦了。 某些操作很复杂：如绕指定的轴旋转N角度。 四元数是表示旋转的好工具，可解决上述问题。
四元数 四元数由4个数[x y z w]构成，表示了如下的旋转：
// RotationAngle is in radians x = RotationAxis.x * sin(RotationAngle / 2) y = RotationAxis.y * sin(RotationAngle / 2) z = RotationAxis.z * sin(RotationAngle / 2) w = cos(RotationAngle / 2) RotationAxis，顾名思义即旋转轴。RotationAngle是旋转的角度。
因此，四元数实际上存储了一个旋转轴和一个旋转角度。这让旋转的组合变简单了。
###解读四元数###
四元数的形式当然不如欧拉角直观，不过还是能看懂的：xyz分量大致代表了各个轴上的旋转分量，而w=acos(旋转角度/2)。举个例子，假设你在调试器中看到了这样的值[ 0.</description></item><item><title>Billbard和粒子</title><link>https://choy-mutao.github.io/graphics_11/opengl/tut18/zh/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/graphics_11/opengl/tut18/zh/</guid><description>Billbard 和粒子 公告板是 3D 世界中的 2D 元素。它既不是最顶层的 2D 菜单，也不是可以随意转动的 3D 平面，而是介于两者之间的一种元素，比如游戏中的血条。
公告板的独特之处在于：它位于某个特定位置，朝向是自动计算的，这样它就能始终面向相 机（观察者）。
方案 1:2D 法 2D 法十分简单。只需计算出点在屏幕空间的坐标，然后在该处显示 2D 文本（参见第十一 课）即可。
// Everything here is explained in Tutorial 3 ! There&amp;#39;s nothing new. glm::vec4 BillboardPos_worldspace(x,y,z, 1.0f); glm::vec4 BillboardPos_screenspace = ProjectionMatrix * ViewMatrix * BillboardPos_worldspace; BillboardPos_screenspace /= BillboardPos_screenspace.w; if (BillboardPos_screenspace.z &amp;lt; 0.0f){ // Object is behind the camera, don&amp;#39;t display it. } 就这么搞定了！
2D 法优点是简单易行，无论点与相机距离远近，公告板始终保持大小不变。但此法总是把 文本显示在最顶层，有可能会遮挡其他物体，影响渲染效果。
方案 2:3D 法 与 2D 法相比，3D 法常常效果更好，也没复杂多少。我们的目的就是无论相机如何移动， 都要让公告板网格正对着相机：</description></item><item><title>半平面</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/mathmatic/half_plane/</link><pubDate>Wed, 18 Sep 2024 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/mathmatic/half_plane/</guid><description/></item><item><title>include 的细节</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/include/</link><pubDate>Tue, 17 Sep 2024 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/include/</guid><description>#include &amp;ldquo;headername&amp;rdquo; 和 #include &amp;lt;headername&amp;gt; 的区别 #include &amp;quot;headername&amp;quot; 和 #include &amp;lt;headername&amp;gt; 的主要区别在于头文件的搜索路 径。虽然在包含标准库文件（如 iostream）时，两者的行为通常没有区别，但在实际开发 中，两者有不同的语义，尤其是在包含自定义头文件时。
1.#include &amp;ldquo;headername&amp;rdquo; 含义：首先在当前目录（即源文件所在的目录）中搜索头文件。如果没有找到该头文件， 编译器会在标准的系统路径中继续查找。
用法：这种方式常用于包含用户自定义的头文件（非标准库头文件）。
搜索路径：
当前源文件所在目录。 如果在当前目录找不到头文件，编译器会在标准的包含路径（如 /usr/include/ 或 C:\Program Files...）中继续查找 2.#include &amp;lt;headername&amp;gt; 含义：编译器会直接在系统的标准路径中搜索头文件，而不检查当前目录。
用法：这种方式通常用于包含标准库头文件，例如 iostream、vector 等。
搜索路径：直接在系统的标准头文件路径中查找，不查找当前目录。
区别 主要区别是搜索路径： #include &amp;quot;headername&amp;quot;：先查找当前目录，然后再查找系统标准目录。 #include &amp;lt;headername&amp;gt;：只查找系统标准目录，不查找当前目录。 使用场景： #include &amp;quot;headername&amp;quot;：主要用于用户自定义的头文件，开发者可以将头文件放在 当前项目目录中。 #include &amp;lt;headername&amp;gt;：主要用于标准库头文件或系统级头文件，编译器会从系统 的标准路径中查找。 对于标准库头文件（如 #include &amp;lt;iostream&amp;gt;），两者的区别在很多编译器中不大，因 为即使你使用 #include &amp;quot;iostream&amp;quot;，编译器也会在标准路径中找到标准库头文件。但 是，规范上推荐使用 #include &amp;lt;iostream&amp;gt; 来包含标准库头文件，因为它更明确且可 以避免潜在的冲突。</description></item><item><title>pragma 指令</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/pragma/</link><pubDate>Tue, 17 Sep 2024 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/pragma/</guid><description>描述 在 C++ 中，#pragma 是一种编译器指令，用于向编译器提供特定的编译指示。它并不是 C++ 标准的一部分，而是由不同编译器实现的，因此它的作用和支持的指令可能会因编译器 的不同而有所差异。
#pragma 是一种编译器指令，用于执行特定的编译器行为，常用于内存对齐、警告控制、优 化等任务。由于它不是 C++ 标准的一部分，因此其使用和功能通常依赖于具体的编译器。 在跨平台开发时需要特别注意，尽量避免编译器特定的 #pragma 指令，以提高代码的可移 植性
1. #pragma once 用于防止头文件被多次包含。 它告诉编译器，在编译过程中只包含一次该文件的内容。相比传统的 include guard (#ifndef、#define、#endif)，它更简洁。 示例 #pragma once // 头文件内容 等同于 #ifndef HEADER_FILE_NAME #define HEADER_FILE_NAME // 头文件内容 #endif 2. #pragma pack 用于修改结构体或类的字节对齐方式。通常编译器会根据平台的要求为结构体字段进行内 存对齐，但通过 #pragma pack，你可以改变默认的对齐方式 下面的示例会让 MyStruct 使用 1 字节对齐，避免结构体字段之间的填充字节。
示例 #pragma pack(1) // 设置为1字节对齐 struct MyStruct { char a; int b; }; #pragma pack() // 恢复默认对齐 3. #pragma warning 用于控制编译过程中是否显示某些警告，通常是在禁用特定警告或启用更多警告信息时使 用。 示例 #pragma warning(push) // 保存当前警告状态 #pragma warning(disable:4996) // 禁用某个警告（如过时的函数使用） // 这里可以包含会触发该警告的代码，但警告会被忽略 #pragma warning(pop) // 恢复之前的警告状态 4.</description></item><item><title>迭代和递归</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/code/iterate_and_recursion/</link><pubDate>Tue, 17 Sep 2024 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/code/iterate_and_recursion/</guid><description>正文 迭代和递归, 一直是编程中的核心概念, 他们涉及到算法中的查询, 插入, 删除等各种操作, 也预示着编程的重要思想, &amp;ldquo;可重复性&amp;rdquo; 和 &amp;ldquo;分步性&amp;rdquo;</description></item><item><title>划分树</title><link>https://choy-mutao.github.io/geometry_10/%E5%87%A0%E4%BD%95%E7%AE%97%E6%B3%95/query_region/partition_tree/</link><pubDate>Fri, 13 Sep 2024 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/geometry_10/%E5%87%A0%E4%BD%95%E7%AE%97%E6%B3%95/query_region/partition_tree/</guid><description/></item><item><title>Task 的使用技巧</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/csharp/taskthread/task_skill/</link><pubDate>Fri, 30 Aug 2024 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/csharp/taskthread/task_skill/</guid><description>描述 使用 Task 时，有几个技巧可以帮助你更高效地进行并行编程：
使用 Task.Run 来简化任务创建：对于简单的后台工作，Task.Run 是最便捷的方式，它自动使用线程池，并简化了任务创建。
利用 async 和 await：结合 async 和 await 关键字来处理异步操作，使代码更易于阅读和维护，同时避免了回调地狱。
处理异常：使用 try-catch 块来捕获 await 异步操作中的异常，或者在 Task.ContinueWith 中处理任务的异常，以避免未处理的异常导致程序崩溃。
任务取消：使用 CancellationToken 来支持任务的取消操作。创建任务时，传递一个 CancellationToken，并在任务内部检查该 token，以便在需要时中断任务。
任务组合：使用 Task.WhenAll 和 Task.WhenAny 来等待多个任务的完成或处理第一个完成的任务。这对并发操作非常有用。
避免长时间运行的任务：尽量将长时间运行的任务拆分为多个较短的任务，以避免阻塞线程池中的线程，影响其他任务的执行。
使用 Task.Run 和 ConfigureAwait(false)：在不需要恢复到原始上下文的情况下，使用 ConfigureAwait(false) 来提高性能，特别是在库或服务中，避免不必要的上下文切换。
通过这些技巧，你可以更高效地使用 Task 来编写异步、并行的代码，并提升程序的性能和响应性</description></item><item><title>Task 和 Thread 的关系</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/csharp/taskthread/task_diff_thread/</link><pubDate>Fri, 30 Aug 2024 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/csharp/taskthread/task_diff_thread/</guid><description>描述 Task 和 Thread 都用于并行编程，但它们有不同的特性和用途：
抽象层次：Thread 是底层的线程管理类，直接操作线程。Task 是更高级的抽象，提供了对线程的封装，并支持异步编程模型。
资源管理：Task 通常使用线程池来管理和复用线程资源，减少了线程创建和销毁的开销。Thread 是直接创建和管理的，每个线程都需要独立的资源，可能会导致性能问题。
编程模型：Task 提供了更简洁的编程模型，支持任务链、异常处理、取消等功能。Thread 需要手动管理这些方面，代码较为繁琐。
调度：Task 由 TaskScheduler 调度，支持任务优先级和调度策略。Thread 由操作系统调度，缺乏灵活性。
总的来说，Task 提供了更高层次的并行编程支持，更适合大多数现代应用，而 Thread 提供了对线程的直接控制，适合需要精细化线程管理的场景。
Task 的一些使用技巧对 Thread 的封装</description></item><item><title>Task.Run() 和 Task.Factory.StartNew() 的区别</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/csharp/taskthread/task_and_taskfactory/</link><pubDate>Fri, 30 Aug 2024 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/csharp/taskthread/task_and_taskfactory/</guid><description>描述 Task.Run 和 Task.Factory.StartNew 都用于创建和启动任务，但它们有一些区别：
默认行为：Task.Run 是 Task.Factory.StartNew 的一个简化版本，通常使用默认的 TaskCreationOptions 和 TaskScheduler。Task.Factory.StartNew 提供了更多的配置选项。
配置选项：Task.Factory.StartNew 允许你设置更多的参数，比如 TaskCreationOptions 和 TaskScheduler。而 Task.Run 是为了简化任务创建，默认使用 TaskCreationOptions.DenyChildAttach 和当前线程的调度器。
延续性：Task.Run 的延续性（ContinueWith）可以更简单地处理，因为它默认使用线程池来执行任务，适用于大多数常见的并行处理场景。
综上所述，如果你需要更多控制和配置，可以使用 Task.Factory.StartNew；而如果只是需要简单地创建和启动一个任务，Task.Run 是更方便的选择
TaskCreationOptions TaskScheduler</description></item><item><title>从 Task 到 Thread</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/csharp/taskthread/from_task_to_thread/</link><pubDate>Fri, 30 Aug 2024 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/csharp/taskthread/from_task_to_thread/</guid><description>描述</description></item><item><title>Plotly Python 速查</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/python/python_plotly/</link><pubDate>Thu, 22 Aug 2024 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/python/python_plotly/</guid><description>绘制线段</description></item><item><title>快速可视化工具</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/python/visual_tools/</link><pubDate>Thu, 22 Aug 2024 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/python/visual_tools/</guid><description>快速查看平面几何图形 Plotly 优点：Plotly 是一个非常强大的交互式绘图库。它允许你创建交互式图形，适合在网页或数据分析报告中嵌入图表。即使是简单的图形，它也能通过非常直观的 API 快速实现。</description></item><item><title>消息队列, 生产与消费</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/design/message_queue/</link><pubDate>Sun, 18 Aug 2024 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/design/message_queue/</guid><description>描述 问题的产生, 在于一个计算逻辑中的两个柱体 A 和 B 之间存在数据的生产先后顺序, 需要用 A 生成 B 的一个前置数据, 再由 B 输出产生结果, 而 A 中的数据在时间上没有关联性, 即 t 时刻生成的 数据 \(A_t\) 与 t+1 时刻 \(A_{t+1}\) 无关
为了程序主逻辑运行的效率, 对 A 和 B 采用异步执行, 即当 在 A 生成数据后, B再开始运行</description></item><item><title>C 动态分配二维数组的内存</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/dy_allocate_mem_2darray/</link><pubDate>Sun, 21 Jul 2024 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/dy_allocate_mem_2darray/</guid><description>指针数组 使用指针数组, 每个指针指向一维数组的起始位置
#include &amp;lt;stdio.h&amp;gt; #include &amp;lt;stdlib.h&amp;gt; int main() { int rows = 3; int cols = 4; // 分配行指针数组 double **array = (double **)malloc(rows * sizeof(double *)); if (array == NULL) { printf(&amp;#34;Memory allocation failed\n&amp;#34;); return 1; } // 为每一行分配内存 for (int i = 0; i &amp;lt; rows; i++) { array[i] = (double *)malloc(cols * sizeof(double)); if (array[i] == NULL) { printf(&amp;#34;Memory allocation failed\n&amp;#34;); // 释放已分配的内存 for (int j = 0; j &amp;lt; i; j++) { free(array[j]); } free(array); return 1; } } // 初始化并打印二维数组 for (int i = 0; i &amp;lt; rows; i++) { for (int j = 0; j &amp;lt; cols; j++) { array[i][j] = i * cols + j; printf(&amp;#34;%f &amp;#34;, array[i][j]); } printf(&amp;#34;\n&amp;#34;); } // 释放内存 for (int i = 0; i &amp;lt; rows; i++) { free(array[i]); } free(array); return 0; } 连续内存块 分配一个连续的内存块，并使用指针数组管理。</description></item><item><title>在 C 函数中建议 move data to heap 时</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/move_stack_to_heap/</link><pubDate>Sat, 20 Jul 2024 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/move_stack_to_heap/</guid><description>malloc malloc（memory allocation）函数用于分配指定字节数的内存，并返回指向这块内存的指针。内存未初始化。
#include &amp;lt;stdlib.h&amp;gt; int main() { // 分配内存用于存储10个整数 int *array = (int *)malloc(10 * sizeof(int)); if (array == NULL) { // 处理内存分配失败的情况 return 1; } // 使用分配的内存 for (int i = 0; i &amp;lt; 10; i++) { array[i] = i; } // 释放内存 free(array); return 0; } calloc calloc(contiguous allocation) 函数用于分配指定数量的元素, 每个元素大小为指定字节数, 并将分配的内存初始化为 zero;
#include &amp;lt;stdlib.h&amp;gt; int main() { // 分配内存用于存储 10 个整数, 并初始化为 zero int *array = (int*)calloc(10, sizeof(int)); if(array == NULL) { // 处理内存分配失败的情况 return 1; } // 使用分配的内存 for(int i = 0; i &amp;lt; 10; i++&amp;gt;) { // array[i] 已初始化为 0 } // 释放内存 free(array); return 0; } realloc realloc (re-allocation) 函数用于调整之前分配的内存块的大小, 如果新的内存大于旧的内存, 新的内存部分未初始化</description></item><item><title>Taipy</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/taipy/taipy/</link><pubDate>Wed, 17 Jul 2024 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/taipy/taipy/</guid><description>Taipy 一个用于构建数据驱动应用程序的开源框架。它旨在简化和加速开发数据应用程序的过程，提供了一组工具和库，帮助开发者快速创建可视化、数据分析和机器学习模型的应用程序。Taipy 的目标是使数据科学家和开发者能够更高效地将他们的分析和模型转换为可交付的应用程序。
Taipy 可以做什么 Taipy 安装 Taipy 入门</description></item><item><title>Todo</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/docys/todo/</link><pubDate>Wed, 10 Jul 2024 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/docys/todo/</guid><description>Todo 在使用 docys 过程中一些需要处理的问题
List 修改 Homepage 如何设置一个文件夹继承 &amp;ldquo;docs&amp;rdquo;, &amp;ldquo;blog&amp;rdquo; 等页面属性</description></item><item><title>比较 boost 和 stl</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/stlboost/</link><pubDate>Sun, 02 Jun 2024 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/stlboost/</guid><description>Boost 和 STL（Standard Template Library）是两个非常重要的 C++ 库，它们各自提供了 丰富的功能和工具，但在用途、设计哲学和使用场景上有一些显著的区别。下面是对 Boost 和 STL 的详细比较：
STL（Standard Template Library） 标准库的一部分：STL 是 C++ 标准库的一部分，由 ISO/IEC 标准化组织定义。所 有符合标准的 C++ 编译器都必须提供 STL。 核心组件：STL 主要包含容器、算法和迭代器三个核心组件。 容器：如 vector、list、map、set 等，用于存储和管理数据。 算法：如 sort、find、copy 等，用于对容器中的数据进行操作。 迭代器：用于遍历容器中的元素，提供了统一的接口。 轻量级：STL 设计简洁，专注于基本的数据结构和算法，适合大多数常见的编程任 务。 性能优化：STL 的实现经过高度优化，性能通常非常好。 使用场景 通用数据结构和算法：适用于大多数常见的数据管理和操作需求。 学习和教学：STL 是学习 C++ 标准库和模板编程的好起点。 Boost 第三方库：Boost 是一个第三方库集合，由 C++ 社区开发和维护，不是标准库的一 部分。 功能丰富：Boost 提供了比 STL 更多的功能，涵盖了网络编程、线程管理、正则表 达式、智能指针、日期和时间处理等多个领域。 模块化：Boost 包含许多独立的模块，每个模块解决特定的问题。用户可以根据需 要选择和使用这些模块。 高级特性：Boost 提供了许多高级特性，如元编程、函数对象、信号槽机制等，适 合复杂的编程任务。 社区支持：Boost 有一个活跃的社区，提供了丰富的文档、示例和讨论论坛。 使用场景 复杂应用开发：适用于需要高级功能和复杂数据结构的项目。 高性能计算：许多 Boost 模块针对高性能计算进行了优化。 跨平台开发：Boost 提供了许多跨平台的解决方案，适合多平台项目。 对比总结 功能对比 STL：主要提供基本的数据结构和算法，适合大多数常见的编程任务。 Boost：提供更丰富的功能和高级特性，适合复杂的编程需求。 性能对比 STL：经过高度优化，性能通常非常好。 Boost：某些模块也经过优化，但整体性能取决于具体的模块和实现。 易用性对比 STL：设计简洁，易于学习和使用。 Boost：功能丰富，但可能需要更多的时间来学习和掌握。 社区和支持 STL：作为标准库的一部分，有广泛的文档和教程支持。 Boost：有活跃的社区，提供了丰富的资源和支持。 结论 STL 是 C++ 标准库的一部分，提供了基本的数据结构和算法，适合大多数常见的编 程任务。 Boost 是一个功能丰富的第三方库，提供了许多高级特性，适合复杂的编程需求。</description></item><item><title>Polyline 的对象信息里的 `Bulge`</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/cadobjectarx/bulge/</link><pubDate>Wed, 29 May 2024 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/cadobjectarx/bulge/</guid><description>Bulge Bulge 是在多段线（Polyline）对象的弧段（Arc Segment）中存在的一个属性。其是与 多段线的各个顶点（vertices）相关的，用于定义从一个顶点到下一个顶点之间的弧段的弯 曲程度。Bulge 的计算公式为
$$ Bulge = \tan{\frac{\theta}{4}}$$其中 \(\theta\) 是圆心角
Bulge 的性质 正值和负值：Bulge 的正负值决定了弧的方向。如果 Bulge 是正值，弧段逆时针方 向弯曲；如果是负值，弧段顺时针方向弯曲。 值的大小：Bulge 的绝对值越大，弧段的弯曲程度越大；绝对值越小，弧段的弯曲程 度越小。 在 多段线中 （Polyline） 多段线可以包含直线段和弧段。每个顶点之间的段可以是直线或弧线。
在 AutoCAD 中，多段线（Polyline）确实只能由直线段和弧线段组成
在多段线中，每个顶点都有一个与之关联的 bulge 值。这个 bulge 值用于定义从当前顶 点到下一个顶点之间的段是直线还是弧线。
对于弧线 （Arc） 弧对象是一个独立的几何对象，表示一个圆弧 弧对象本身没有 bulge 属性，而是通过起点、终点、圆心和半径来定义</description></item><item><title>如何理解 python 中的 module</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/python/module/</link><pubDate>Thu, 23 May 2024 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/python/module/</guid><description>1.1 什么是 module module 是一个包含 Python 代码的文件，它可以定义函数、类、变量，也可以包含可执 行的代码。模块是 Python 代码的组织单位，有助于将代码分割成更小、更可管理的部分。 换而言之, Python 中的任意 .py 文件都可以作为模块（module）来使用。
1.2 创建 module 一个模块就是一个 Python 文件（.py 文件），文件名即为模块名。例如，创建一个名为 my_module.py 的文件：
# my_module.py def greet(name): return f&amp;#34;Hello, {name}!&amp;#34; PI = 3.14159 1.3 导入模块并使用 在另一个 Python 文件或交互式环境中，可以使用 import 语句导入模块：
# main.py import my_module print(my_module.greet(&amp;#34;Alice&amp;#34;)) # 输出: Hello, Alice! print(my_module.PI) # 输出: 3.14159 1.0 模块的结构和组织 &amp;mdash; 包(packages) 包是模块的集合，实际上是包含多个模块的目录(一个包含一些.py 文件的 folder)。包目 录中必须包含一个 __init__.py 文件（即使它为空），表示这是一个包。
# directory structure my_package/ __init__.py module1.py module2.</description></item><item><title>CAD 中的曲线 及其 离散化的操作</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/cadobjectarx/cadcurve/</link><pubDate>Wed, 17 Jan 2024 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/cadobjectarx/cadcurve/</guid><description>AutoDesk Document Autodesk.AutoCAD.DatabaseServices.DBObject Autodesk.AutoCAD.DatabaseServices.Entity Autodesk.AutoCAD.DatabaseServices.Curve Autodesk.AutoCAD.DatabaseServices.Arc Autodesk.AutoCAD.DatabaseServices.Circle Autodesk.AutoCAD.DatabaseServices.Ellipse Autodesk.AutoCAD.DatabaseServices.Leader Autodesk.AutoCAD.DatabaseServices.Line Autodesk.AutoCAD.DatabaseServices.Polyline Autodesk.AutoCAD.DatabaseServices.Polyline2d Autodesk.AutoCAD.DatabaseServices.Polyline3d Autodesk.AutoCAD.DatabaseServices.Ray Autodesk.AutoCAD.DatabaseServices.Spline Autodesk.AutoCAD.DatabaseServices.Xline 圆弧（Arc） 圆（Circle） 椭圆（Ellipse） 引线（Leader） 直线（Line） 多段线（Polyline） 射线（Ray） 样条曲线（Spline） 无限线（XLine）</description></item><item><title>move函数的实现原理</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/leetcode/c++%E8%AF%AD%E8%A8%80%E7%89%B9%E6%80%A7%E7%9B%B8%E5%85%B3/move%E5%87%BD%E6%95%B0%E7%9A%84%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86/</link><pubDate>Wed, 09 Aug 2023 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/leetcode/c++%E8%AF%AD%E8%A8%80%E7%89%B9%E6%80%A7%E7%9B%B8%E5%85%B3/move%E5%87%BD%E6%95%B0%E7%9A%84%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86/</guid><description/></item><item><title>Keep It Simple Stupid(KISS)</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/randomization/kiss/</link><pubDate>Tue, 28 Feb 2023 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/randomization/kiss/</guid><description>简介 KISS（&amp;ldquo;Keep It Simple Stupid&amp;rdquo;）是一种伪随机数生成器（PRNG）家族，由George Marsaglia引入。KISS生成器通过结合多个独立的随机数生成器来提高随机数的质量。早期版本包括一个线性同余生成器和两个线性反馈移位寄存器生成器，而后来的版本引入了乘-携带生成器和Xorshift生成器。尽管KISS生成器在一些统计测试中表现良好，但它并不适合加密用途​</description></item><item><title>C++ 是如何实现面向对象编程的</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/leetcode/c++%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/%E4%BB%80%E4%B9%88%E6%98%AF%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/</link><pubDate>Thu, 27 Oct 2022 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/leetcode/c++%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/%E4%BB%80%E4%B9%88%E6%98%AF%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/</guid><description>面向对象的三个特性 封装:将对象的状态（数据成员）和行为（成员函数）捆绑在一起，并控制对它们的访问。封装的主要目的是隐藏类的内部实现细节，并仅暴露必要的接口供外部使用。这样可以保护数据，防止外部代码意外或恶意地改变对象的状态。 数据成员可以被声明为 private、protected 或 public。 成员函数通常也是 public 的，以便用户可以调用这些函数来操作对象。 使用 private 和 protected 修饰符可以限制对数据成员的直接访问。 继承:允许创建新的类（称为派生类或子类）从现有的类（称为基类或父类）继承属性和方法。这样可以复用代码，同时也可以扩展或修改基类的行为。 派生类可以继承基类的所有非私有成员。 派生类可以添加新的成员变量和方法，或者重写基类的方法。 继承支持层次化的分类结构，便于建模现实世界的关系 多态: 允许使用一个接口来表示多种类型的特性。在 C++ 中，多态通常是通过 虚函数 （virtual function）来实现的。当一个函数被声明为虚函数时，可以在派生类中重写该函数，并且可以通过基类的指针或引用调用派生类中的重写版本。 支持运行时多态性（runtime polymorphism），即可以在运行时确定调用哪个版本的函数。 通常与虚函数和接口有关 虚函数 和 纯虚函数 虚函数的实现机制 C++ 中多态的实现原理 多态是通过虚函数实现的，虚函数的地址保存在虚函数表中，虚函数表的地址保存在含有虚函数的类的实例对象的内存空间中。
重载 | 重写 | 隐藏 函数重载: 同一可访问区 内被声明几个具有 不同 参数列（参数的类型、个数、顺序）的同名函数，根据参数列表确定调用哪个函数，重载不关心函数返回类型。 函数重写(覆盖): 派生类中存在 重新定义 的函数。函数名、参数列表、返回值类型都必须同基类中被重写的函数一致，只有函数体不同。派生类调用时会调用派生类的重写函数，不会调用被重写函数。重写的基类中被重写的函数 必须 有 virtual 修饰。 函数隐藏: 在面向对象编程中，特别是在 C++ 中，当一个派生类（derived class）中定义了一个与基类（base class）中相同名称的成员函数时，如果没有特别标记为 virtual，那么派生类中的成员函数就会“隐藏”掉基类中的同名成员函数。这意味着当你通过派生类的对象调用这个函数时，调用的是派生类中的版本，而不是基类中的版本。 class Base { public: void fun(int tmp, bool tag ) { cout &amp;lt;&amp;lt; &amp;#34;Base::fun(int tmp, bool tmp1)&amp;#34; &amp;lt;&amp;lt; endl; } virtual void vir_fun(int* array) { cout &amp;lt;&amp;lt; &amp;#34;Base::vir_fun(int* array)&amp;#34; &amp;lt;&amp;lt; endl; } } class Derived: public Base { public: void fun(int tmp); // 隐藏基类中的同名函数 void fun(float tmp); // 重载 参数类型不同（相对于上一个函数） void fun(int tmp, float tmp1); // 重载 参数个数不同（相对于上一个函数） void fun(float tmp, int tmp1); // 重载 参数顺序不同（相对于上一个函数） int fun(int tmp); // error: &amp;#39;int A::fun(int)&amp;#39; cannot be overloaded 错误：注意重载不关心函数返回类型 virtual void vir_fun(int* array) { cout &amp;lt;&amp;lt; &amp;#34;Derived::vir_fun(int* array)&amp;#34;&amp;lt;&amp;lt; endl; } }; int main() { Derived ex; ex.</description></item><item><title>sizeof 和 strlen 的区别</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/leetcode/c++%E5%85%B3%E9%94%AE%E5%AD%97%E5%92%8C%E5%85%B3%E9%94%AE%E5%BA%93%E5%87%BD%E6%95%B0.md/sizeofstrlen/</link><pubDate>Sat, 15 Oct 2022 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/leetcode/c++%E5%85%B3%E9%94%AE%E5%AD%97%E5%92%8C%E5%85%B3%E9%94%AE%E5%BA%93%E5%87%BD%E6%95%B0.md/sizeofstrlen/</guid><description/></item><item><title>编译与链接</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/leetcode/c++%E7%BC%96%E8%AF%91%E5%92%8C%E5%86%85%E5%AD%98%E7%9B%B8%E5%85%B3/%E7%BC%96%E8%AF%91%E4%B8%8E%E9%93%BE%E6%8E%A5/</link><pubDate>Sat, 15 Oct 2022 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/leetcode/c++%E7%BC%96%E8%AF%91%E5%92%8C%E5%86%85%E5%AD%98%E7%9B%B8%E5%85%B3/%E7%BC%96%E8%AF%91%E4%B8%8E%E9%93%BE%E6%8E%A5/</guid><description>什么是编译 C++ 是一种静态类型的编程语言，CPU 无法直接执行文件中的各行命令, 这意味着在程序执行之前需要通过 编译过程 将其源代码转换为机器码. 编译器会读取程序的源文件 .cpp, 将其翻译为可执行文件 ELF, ELF 文件可以经过操作系统进行加载执行
编译的过程 常见的编译过程分为四个过程: 编译预处理, 编译, 汇编, 链接
编译预处理：在预编译过程中主要处理源代码中的预处理指令，比如引入头文件#include，去除注释，处理所有的条件编译指令#ifdef, #ifndef, #else, #elif, #endif，宏的替换#define，添加行号，保留所有的编译器指令； 编译：针对预处理后的文件进行词法分析、语法分析、语义分析、符号汇总、汇编代码生成，并针对程序的结构或者特定的 CPU 平台进行优化，其中涉及的过程较为复杂。简单来说编译的过程即为将 .cpp 源文件翻译成 .s 的汇编代码； 汇编：将汇编代码 .s 翻译成机器指令 .o 文件，一个 .cpp 文件只会生成一个 .o 文件； 链接：汇编程序生成的目标文件即为 .o 文件，单独的 .o 文件可能无法执行。因为一个程序可能由多个源文件组成，此时就存在多个 .o 文件。文件 A 中的函数引用了另一个文件 B 中定义的符号或者调用了某个库文件中的函数，这就需要 链接处理。那链接的目的就是将这些文件对应的目标文件连接成一个整体，从而生成一个可被操作系统加载执行的 ELF 程序文件。链接的过程较为复杂，如有兴趣可以参考：「Computer Systems: A Programmer&amp;rsquo;s Perspective」。 什么是链接 链接的种类 静态链接 动态链接</description></item><item><title>大端和小端</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/leetcode/c++%E7%BC%96%E8%AF%91%E5%92%8C%E5%86%85%E5%AD%98%E7%9B%B8%E5%85%B3/%E5%A4%A7%E7%AB%AF%E5%92%8C%E5%B0%8F%E7%AB%AF/</link><pubDate>Sat, 15 Oct 2022 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/leetcode/c++%E7%BC%96%E8%AF%91%E5%92%8C%E5%86%85%E5%AD%98%E7%9B%B8%E5%85%B3/%E5%A4%A7%E7%AB%AF%E5%92%8C%E5%B0%8F%E7%AB%AF/</guid><description>什么是字节序(Endian-ness) 两种字节序的形式 小端(Little-Endian) 大段(Bit-Endian) 字节序的转换</description></item><item><title>内存泄漏</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/leetcode/c++%E7%BC%96%E8%AF%91%E5%92%8C%E5%86%85%E5%AD%98%E7%9B%B8%E5%85%B3/%E5%86%85%E5%AD%98%E7%9B%B8%E5%85%B3/%E5%86%85%E5%AD%98%E6%B3%84%E6%BC%8F/</link><pubDate>Sat, 15 Oct 2022 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/leetcode/c++%E7%BC%96%E8%AF%91%E5%92%8C%E5%86%85%E5%AD%98%E7%9B%B8%E5%85%B3/%E5%86%85%E5%AD%98%E7%9B%B8%E5%85%B3/%E5%86%85%E5%AD%98%E6%B3%84%E6%BC%8F/</guid><description>什么是内存泄漏 程序块在[堆]中申请的[动态内存], 在程序块使用完成后没有得到[及时释放], 从而导致了堆中可使用的内存越来越少的现象
内存泄漏是逻辑上的概念, 指在程序运行期间, 总内存的可复用率变低的问题 内存泄漏主要指在[堆]上分配的变量所占用的内存, 因为[栈]中分配的变量, 会随着函数退出时自动回收. 而堆是动态分配的 不仅要考虑 malloc, calloc, realloc, new 等分配的内存是否得到了释放, 也要考虑使用系统资源或者在[堆]中创建的对象 内存泄漏的检测与预防的实践 通常会利用各种[内存检测工具]来检测内存泄漏, 其原理也是统计和分析内存的申请和释放的相关日志
以下通过 valgrind 的实践来介绍
valgrind 实践 valgrind 是 Linux 下, 开源代码 (GPL V2) 的仿真调试工具的集合, 包括以下工具:
Memcheck:</description></item><item><title>c++ 内存管理</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/leetcode/c++%E7%BC%96%E8%AF%91%E5%92%8C%E5%86%85%E5%AD%98%E7%9B%B8%E5%85%B3/c++%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/</link><pubDate>Thu, 13 Oct 2022 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/leetcode/c++%E7%BC%96%E8%AF%91%E5%92%8C%E5%86%85%E5%AD%98%E7%9B%B8%E5%85%B3/c++%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/</guid><description>ELF 文件: 可执行与可链接格式(Executable and Linkable Format)是一种用于可执行文件, 目标代码, 共享库和核心转储(core dump)的标准文件格式, 每个ELF文件都由一个ELF header 和紧跟其后的文件数据部分组成, 可以参考 ELF 文件的构成如下:
我们可以看见可执行程序内部都是分段进行存储的.
.text section: 代码段, 通常存放已编译程序的机器代码, 一般操作系统加载后, 这部分是只读的 .rodata section: 只读数据段, 此段的数据不可修改, 存放程序中会使用的常量 data section: 数据段, 主要用于存放已初始化的全局变量, 常量 bss section: 未初始化的全局标量, 仅是占位符, 不占据任何实际磁盘空间 目标文件格式区分初始化和非初始化是为了空间效率
操作系统在加载 ELF 文件时, 会按照文件结构, 依次读取每个 section 中的内容, 并将其加载到内存中, 同时为该进程分配空间, 并将 pc寄存器 指向代码段的起始位置, 然后启动进程
内存分区 C++ 程序在运行时, 会按照不同的功能划分不同的段: 栈, 堆, 全局/静态存储区, 常量存储区, 代码区
栈: 目前绝大多数CPU体系是基于栈来运行程序的, 栈中主要存放函数的局部变量, 函数参数, 返回地址等, 栈空间一般由操作系统进行默认分配或者程序指定分配, 栈空间在进程生存周期一直都存在, 当进程退出时, 操作系统才会对栈空间进行回收 堆: 动态申请的内存空间, 就是由 malloc 函数或者 new 函数分配的内存块, 由系统控制它的分配和释放, 可以在程序运行周期随时进行申请和释放, 如果进程结束后还没收释放, 操作系统会自动回收 全局区/静态存储区: 主要为 .</description></item><item><title>变量定义与生命周期</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/leetcode/c++%E7%BC%96%E8%AF%91%E5%92%8C%E5%86%85%E5%AD%98%E7%9B%B8%E5%85%B3/%E5%8F%98%E9%87%8F%E5%AE%9A%E4%B9%89%E4%B8%8E%E7%94%9F%E5%AD%98%E5%91%A8%E6%9C%9F/</link><pubDate>Thu, 13 Oct 2022 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/leetcode/c++%E7%BC%96%E8%AF%91%E5%92%8C%E5%86%85%E5%AD%98%E7%9B%B8%E5%85%B3/%E5%8F%98%E9%87%8F%E5%AE%9A%E4%B9%89%E4%B8%8E%E7%94%9F%E5%AD%98%E5%91%A8%E6%9C%9F/</guid><description>作用域 与 生命周期 这两个属性, 以 空间(作用域) 和 时间(生命周期) 两个不同的维度来描述一个 变量
作用域 一个变量可以被引用的范围
全局变量: 全局变量只需在一个源文件中定义, 就可以作用域所有的源文件, 其他不包含全局变量定义的源文件需要用 extern 关键字再次声明这个全局变量 静态全局变量: 与全局变量的区别在于如果程序包含多个文件的话, 它作用域定义它的文件里, 不能作用到其他文件里, 即被 static 关键字修饰过的变量具有文件作用域, 即使两个不同的文件都定义了相同的名字的静态全局变量, 它们也是不同的变量 局部变量: 它是自动对象(auto), 在程序运行期间不是一直存在,而是只在函数执行区间存在, 函数的依次调用执行结束后, 变量被撤销, 其所占的内存也被收回, 局部变量对于函数外部的程序说是不可见的, 实际是以 {} 为所用与 静态局部变量: 它直被初始化依次, 自从第一次被初始化知道程序运行结束都一直存在, 它只对定义自己的函数体始终可见, 只有定义该变量的函数内部可以使用和访问该变量 生命周期 变量可以存在(被引用)的时间段
全局变量: 在真个程序运行期间都会一直存在, 都可以随时访问, 当程序结束时, 对应的变量会自动销毁, 内存被系统回收 局部变量: 仅限于函数被调用期间, 当函数调用结束时, 该变量会自动销毁 静态局部变量: 在程序运行期间一直存在, 局部静态变量只能被初始化一次 从分配内存空间看 不同生命周期的变量, 在程序内存中的分布位置是不一样的, 内存分为 代码区(.text), 全局数据区(.data, .bss, .rodata), 堆区(heap), 栈区(stack), 不同的内存区域, 对应不同的生命周期
静态变量一般存储在数据段, 包括 data 段.</description></item><item><title>堆与栈</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/leetcode/c++%E7%BC%96%E8%AF%91%E5%92%8C%E5%86%85%E5%AD%98%E7%9B%B8%E5%85%B3/%E5%A0%86%E4%B8%8E%E6%A0%88/</link><pubDate>Thu, 13 Oct 2022 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/leetcode/c++%E7%BC%96%E8%AF%91%E5%92%8C%E5%86%85%E5%AD%98%E7%9B%B8%E5%85%B3/%E5%A0%86%E4%B8%8E%E6%A0%88/</guid><description/></item><item><title>内存对齐</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/leetcode/c++%E7%BC%96%E8%AF%91%E5%92%8C%E5%86%85%E5%AD%98%E7%9B%B8%E5%85%B3/%E5%86%85%E5%AD%98%E5%AF%B9%E9%BD%90/</link><pubDate>Thu, 13 Oct 2022 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/leetcode/c++%E7%BC%96%E8%AF%91%E5%92%8C%E5%86%85%E5%AD%98%E7%9B%B8%E5%85%B3/%E5%86%85%E5%AD%98%E5%AF%B9%E9%BD%90/</guid><description>内存对齐 计算机中内存的地址空间是按照 byte 来划分的, 从理论上讲对任何类型变量的访问, 可以从内存中的任意地址开始, 但实际情况是: 在访问特定类型变量的时候通常在特定的内存地址访问, 这就需要对这些数据在内存中存放的位置进行限制, 各种类型数据按照一定的规划在空间上排列, 而不是顺序地一个接一个地排放, 这就是对齐, 编译器将程序中地每个 数据单元 的地址安排在机器字的整数倍的地址指向的内存之中
为什么要内存对齐 主要是由于 CPU 的访问内存的特性决定, CPu 访问内存时并不是以字节为单位来读取内存, 而是以机器字长为单位, 实际机器字长由 CPU 数据总线宽度决定的, 实际 CPU 运行时, 每一次控制内存读写信号发生时, CPU 可以从内存中读取数据总线宽度的数据, 并将其写入到 CPU 的通用寄存器中
比如, 32位cpu, 机器字长为 4字节, 数据总线宽度为 32 为, 如果该 CPU 的地址总线宽度也为 32 位, 则其可以访问的地址空间为[0, 0xffffffff]
内存对齐的主要目的是为了减少 CPU 访问内存的次数, 加大 CPU 访问内存的吞吐量
假设: 读取 8 个字节的数据, 按照每次读取 4 个字节的速度, 则 8 个字节需要 CPU 耗费 2 次读取操作
CPU 始终以字节访问内存, 如果不进行内存对齐, 很可能增加 CPU 访问内存的次数</description></item><item><title>智能指针的创建</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/leetcode/c++%E7%BC%96%E8%AF%91%E5%92%8C%E5%86%85%E5%AD%98%E7%9B%B8%E5%85%B3/%E6%99%BA%E8%83%BD%E6%8C%87%E9%92%88%E7%9A%84%E5%88%9B%E5%BB%BA/</link><pubDate>Wed, 12 Oct 2022 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/leetcode/c++%E7%BC%96%E8%AF%91%E5%92%8C%E5%86%85%E5%AD%98%E7%9B%B8%E5%85%B3/%E6%99%BA%E8%83%BD%E6%8C%87%E9%92%88%E7%9A%84%E5%88%9B%E5%BB%BA/</guid><description>make_unique 和 make_share 优先使用 std:make_unique 和 std:make_shared, 而非使用 new;
make_unique: 减少代码量, 能够加快编译速度, 定义两边类型时, 编译器需要进行类型推导, 会降低编译速度, 某些意外情况下可能会导致内存泄漏, 但是 make_unique 不允许自定析构器, 不接受 std:initializer_list 对象 make_shared: 这个主要是可以减少对堆中申请内存的次数, 只需要申请一次即可</description></item><item><title>智能指针简介与使用</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/leetcode/c++%E7%BC%96%E8%AF%91%E5%92%8C%E5%86%85%E5%AD%98%E7%9B%B8%E5%85%B3/%E6%99%BA%E8%83%BD%E6%8C%87%E9%92%88%E7%AE%80%E4%BB%8B%E4%B8%8E%E4%BD%BF%E7%94%A8/</link><pubDate>Wed, 12 Oct 2022 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/leetcode/c++%E7%BC%96%E8%AF%91%E5%92%8C%E5%86%85%E5%AD%98%E7%9B%B8%E5%85%B3/%E6%99%BA%E8%83%BD%E6%8C%87%E9%92%88%E7%AE%80%E4%BB%8B%E4%B8%8E%E4%BD%BF%E7%94%A8/</guid><description>智能指针 为了解决动态内存分配时带来的内存泄露以及多次释放同一块内存空间而提出的
传统的指针在申请完成后, 必须要调用 free 或 delete 来释放指针, 否则容易产生内存泄漏的问题
smart pointer 遵循 RAII 原则, 当 smart pointer 对象创建时, 即为该指针分配了相应的内存, 当对象销毁时, 析构函数会自动释放内存, 需要注意的是, 智能指针不能像普通指针那样支持加减运算(迭代操作)
智能指针的类型 unique_ptr: 独享所有权的智能指针, 资源智能被一个指针占有, 该指针不能拷贝构造和赋值, 但可以进行移动构造和移动赋值构造(调用 move() 函数), 即一个 unique_ptr 对象赋值给另一个 unique_ptr 对象, 可以通过该方法进行赋值 shared_ptr: 与 unique_ptr 不同的是, shared_ptr 中的资源可以被多个指针共享, 但是多个指针指向同一个资源不能被释放多次, 因此使用计数机制表明资源被几个指针共享; 通过 use_count() 查看资源的所有者的个数, 可以通过 unique_ptr, weak_ptr 来构造, release 释放资源的所有权, 同时将计数减一, 当计数减为 0 时候,会自动释放内存空间, 从而避免了泄露 需要注意的是, shared_ptr 并不是线程安全的, 但 shared_ptr 的计数是原子操作实现的, 利用 atmoic CAS 指令实现 通过 shared_ptr 的内存模型, 当引用计数和 weak cout 同时为 0 时, shared_ptr 对象才会被最终释放掉 通过查看 shared_ptr 的源代码可以看到如下, shared_ptr 实际成员包含两个指针, 一个指向对象资源的指针 ptr, 另一个指向管理区域的指针 ___cntrl_, 具体 __cntrl_ 指针的区域包括 deleter, allocator, shared_ptr 对象的引用计数, weak_ptrs 的对象的引用计数</description></item><item><title>什么是类</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/leetcode/c++%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/%E4%BB%80%E4%B9%88%E6%98%AF%E7%B1%BB/</link><pubDate>Thu, 28 Apr 2022 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/leetcode/c++%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/%E4%BB%80%E4%B9%88%E6%98%AF%E7%B1%BB/</guid><description/></item><item><title>容器相关</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/stl/%E5%AE%B9%E5%99%A8%E7%9B%B8%E5%85%B3/</link><pubDate>Mon, 01 Nov 2021 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/stl/%E5%AE%B9%E5%99%A8%E7%9B%B8%E5%85%B3/</guid><description>描述 stl 提供的数据类型
序列容器 序列容器存储元素的顺序集合，支持随机访问或顺序访问。
vector: array
特点: 动态数组, 支持随机访问, 末尾插入和删除效率高 使用场景：适用于需要频繁随机访问和在末尾进行插入和删除操作的场景。 #include &amp;lt;vector&amp;gt; #include &amp;lt;iostream&amp;gt; int main() { std::vector&amp;lt;int&amp;gt; vec = {1, 2, 3, 4, 5}; vec.push_back(6); // 在末尾添加元素 std::cout &amp;lt;&amp;lt; &amp;#34;Vector size: &amp;#34; &amp;lt;&amp;lt; vec.size() &amp;lt;&amp;lt; std::endl; // 输出: Vector size: 6 return 0; } list:
特点: 双向链表，支持高效的插入和删除操作，但不支持随机访问。
使用场景：适用于需要频繁在任意位置进行插入和删除操作的场景
#include &amp;lt;list&amp;gt; #include &amp;lt;iostream&amp;gt; int main() { std::list&amp;lt;int&amp;gt; lst = {1, 2, 3, 4, 5}; lst.push_front(0); // 在头部添加元素 lst.push_back(6); // 在末尾添加元素 for (int val : lst) { std::cout &amp;lt;&amp;lt; val &amp;lt;&amp;lt; &amp;#34; &amp;#34;; // 输出: 0 1 2 3 4 5 6 } return 0; } deque:</description></item><item><title>c++ 在visual studio和XCode上的差异</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/different_on_win_and_mac/</link><pubDate>Sat, 18 Sep 2021 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/different_on_win_and_mac/</guid><description>描述 Visual Studio 和 Xcode 在处理 C++ 方面的主要差异在于它们所使用的编译器、工具链以及它们各自的集成开发环境（IDE）特性。以下是一些关键的不同点：
1. 编译器 Visual Studio 使用的是 Microsoft 的 C++ 编译器（MSVC），该编译器有自己的语法扩展和特性，虽然它也支持大部分的 C++ 标准。 Xcode 使用的是 LLVM/Clang 编译器，这是一个开源编译器，其设计目标之一就是提供清晰的诊断信息，并且它对现代 C++ 标准的支持非常好。 2. IDE 特性 Visual Studio 提供了丰富的功能，如智能感知（IntelliSense）、实时模板编辑、重构工具等，这些都是针对微软的开发环境优化的。 Xcode 也有类似的功能，如自动补全（Code Completion）、实时错误提示（Live Issue Identification）等，这些功能针对 macOS 和 iOS 开发进行了优化。 3. API 和库支持 在 Visual Studio 中，可以使用 Windows API 来开发应用程序，以及 Microsoft 提供的其他库。 在 Xcode 中，更可能使用 Cocoa 或 Cocoa Touch（对于 iOS 开发）API，以及 BSD 和 POSIX 的相关库。 4. 构建系统 Visual Studio 使用 MSBuild 构建系统来管理项目。 Xcode 使用自己的构建系统，不过也可以配置使用外部构建工具如 CMake。 5.</description></item><item><title>如何避免写 c 代码的时候 Unhandled Exception:Stack overflow</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/exception/exception_stack-overflow/</link><pubDate>Tue, 23 Mar 2021 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/exception/exception_stack-overflow/</guid><description>避免 C 程序出现堆栈溢出异常（Stack Overflow Exception）通常需要注意以下几点 优化递归算法：如果程序中使用了递归，确保递归深度可控，避免无限递归或递归层次过深。 减少局部变量的数量和大小：函数内部声明的局部变量会占用堆栈空间，特别是对于大型数组或结构体。优化代码，尽量减少或优化局部变量的使用。 动态内存分配：考虑使用动态内存分配函数（如 malloc()、calloc()、realloc()）来管理大型数据结构，而不是将它们放在栈上。 避免过度递归：如果递归是必须的，确保递归调用的深度受到控制，并考虑是否可以改写为迭代方法。 增加堆栈空间限制：虽然不推荐频繁增加堆栈空间的大小，但是可以通过编译器或操作系统的设置，适当增加堆栈空间的限制。这种方法应谨慎使用，并仅当确实需要时才考虑。 使用静态分配：对于较小的数据结构或变量，优先使用静态分配（即在函数外部或静态存储区声明变量）而不是动态分配或放在堆栈上。 编译器优化：现代编译器通常会进行优化，包括函数调用和参数传递的优化。确保使用编译器的优化选项，以提高程序的效率和性能。 定期检查和测试：对于可能存在堆栈溢出风险的代码，定期进行检查和测试是很重要的，以发现潜在的问题并进行优化和改进。</description></item><item><title>stl 算法分析</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/stl/stl%E7%AE%97%E6%B3%95%E5%88%86%E6%9E%90/</link><pubDate>Mon, 29 Jun 2020 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/stl/stl%E7%AE%97%E6%B3%95%E5%88%86%E6%9E%90/</guid><description>描述</description></item><item><title>左值和右值</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/leetcode/c++%E8%AF%AD%E8%A8%80%E7%89%B9%E6%80%A7%E7%9B%B8%E5%85%B3/%E5%B7%A6%E5%80%BC%E5%92%8C%E5%8F%B3%E5%80%BC/</link><pubDate>Thu, 24 Oct 2019 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/leetcode/c++%E8%AF%AD%E8%A8%80%E7%89%B9%E6%80%A7%E7%9B%B8%E5%85%B3/%E5%B7%A6%E5%80%BC%E5%92%8C%E5%8F%B3%E5%80%BC/</guid><description/></item><item><title>Python 虚拟环境</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/python/virutal_env/</link><pubDate>Tue, 12 Mar 2019 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/python/virutal_env/</guid><description>什么是 python 的虚拟环境 Python 虚拟环境是 Python 开发中的一种工具，用于创建和管理独立于系统全局 Python 环境的隔离环境。每个虚拟环境都可以拥有自己的 Python 解释器和独立的包集合，这使得在同一台机器上同时进行多个项目开发时能够保持环境的干净和隔离。
为什么需要 python 的虚拟环境 隔离依赖：每个虚拟环境都有自己的 site-packages 目录，用于存放安装的第三方包，这样可以避免不同项目之间的包冲突。
版本管理：可以在不同的虚拟环境中使用不同的 Python 版本，或者使用同一 Python 版本的不同补丁版本。
便于维护：虚拟环境使得项目的依赖和配置可以被单独管理和复制，方便分享和部署到其他环境。
环境复制：通过共享 requirements.txt 或者 environment.yml 文件，可以快速重建相同的开发环境，确保不同开发者之间开发环境的一致性。
创建&amp;amp;管理 python 虚拟环境的方法和工具 Python 内置的 venv 模块 第三方工具 virtualenv python 虚拟环境的作用范围与生命周期 每个虚拟环境的激活仅限于它所在的命令行窗口或应用程序范围内，不会影响系统的全局设置或其他窗口中的环境, 所以，当关闭激活虚拟环境的命令行窗口或终端后，该虚拟环境就会自动关闭。这是因为虚拟环境的激活状态仅在当前的命令行会话中有效，一旦会话结束（即窗口关闭），虚拟环境的激活状态也随之结束。
关闭窗口后，再次打开新窗口时，默认情况下系统将使用全局 Python 环境，除非你手动再次激活某个虚拟环境。虚拟环境的激活和关闭是轻量级的操作，设计上不会对系统产生持久影响。</description></item><item><title>函数对象</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/stl/%E5%87%BD%E6%95%B0%E5%AF%B9%E8%B1%A1/</link><pubDate>Sat, 06 Oct 2018 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/c++%E7%AC%94%E8%AE%B0/stl/%E5%87%BD%E6%95%B0%E5%AF%B9%E8%B1%A1/</guid><description>描述 比较函数对象: less, greater, equal_to, not_equal_to 等。 算术函数对象: plus, minus, multiplies, divides, modulus, negate 等。 逻辑函数对象: logical_and, logical_or, logical_not 等</description></item><item><title>在 visual studio 上如何使用 CMake 生成项目</title><link>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/cmake/vs_cmake/</link><pubDate>Wed, 31 Jan 2018 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E5%8D%9A%E5%AE%A2_60/cmake/vs_cmake/</guid><description>准备工作 确保系统已经安装了 Visual Studio 并且包含了 C++ 开发工具。此外，Visual Studio 自 带了 CMake 支持，所以你不需要单独安装 CMake
创建或获取 CMake 项目 已有项目：如果已有一个使用 CMake 的项目，可以直接跳到“导入项目”部分。 新项目：如果要从头开始创建一个项目，先创建一个包含 CMakeLists.txt 文件的目录结 构。CMakeLists.txt 是 CMake 的配置文件，其中定义了如何构建你的项目。 导入项目 打开 Visual Studio。 选择 &amp;ldquo;File&amp;rdquo; &amp;gt; &amp;ldquo;Open&amp;rdquo; &amp;gt; &amp;ldquo;CMake&amp;hellip;&amp;rdquo; 菜单项。 浏览并选择你的 CMakeLists.txt 文件所在的目录，然后点击 &amp;ldquo;打开&amp;rdquo; 按钮。 配置 CMake 在解决方案资源管理器中，会看到项目已经被列出来了。Visual Studio 会自动检测W CMakeLists.txt 文件并尝试解析它。 如果需要指定特定的 CMake 参数或选项，可以在 Visual Studio 的 &amp;ldquo;CMake 设置&amp;rdquo; 对话 框中进行设置。右击解决方案资源管理器中的项目名，然后选择 &amp;ldquo;CMake Settings&amp;rdquo; 进行 编辑。 在这里你可以更改生成器、配置类型（如 Debug 或 Release）、以及添加额外的 CMake 变量等。 构建项目 一旦项目被正确识别和配置，就可以直接从 Visual Studio 内部构建项目了。点击顶 部菜单栏的 &amp;ldquo;Build&amp;rdquo; &amp;gt; &amp;ldquo;Build All&amp;rdquo; 来编译整个项目。 也可以右击解决方案资源管理器中的具体目标（Target），然后选择 &amp;ldquo;Build&amp;rdquo; 来只构建 该项目的目标 注意事项 确保 CMake 版本与 Visual Studio 兼容。 如果遇到任何问题，检查输出窗口中的错误信息，这可以帮助你快速定位问题所在。 使用 CMake 的高级功能可能需要更深入地了解 CMake 语法和概念。</description></item><item><title/><link>https://choy-mutao.github.io/geometry_10/meshlab/filters-sfd/cratersgeneration/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/geometry_10/meshlab/filters-sfd/cratersgeneration/</guid><description/></item><item><title/><link>https://choy-mutao.github.io/geometry_10/%E5%87%A0%E4%BD%95%E7%AE%97%E6%B3%95/chapter4_castingproblem/linear_programming/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/geometry_10/%E5%87%A0%E4%BD%95%E7%AE%97%E6%B3%95/chapter4_castingproblem/linear_programming/</guid><description/></item><item><title/><link>https://choy-mutao.github.io/pso_30/_todo/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/pso_30/_todo/</guid><description>Todo list PSO 和 Boids 的联系与区别</description></item><item><title/><link>https://choy-mutao.github.io/pso_30/modifications/convergence_improvements/convergence/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/pso_30/modifications/convergence_improvements/convergence/</guid><description/></item><item><title/><link>https://choy-mutao.github.io/pso_30/modifications/stagnation/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/pso_30/modifications/stagnation/</guid><description/></item><item><title>AVL树(Tree)</title><link>https://choy-mutao.github.io/dsa_1/tree/avl/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/dsa_1/tree/avl/</guid><description>描述 AVL(Adelson-Velskii and Landis) 是带有 平衡条件(balance condition) 的 二叉查找树(BST),通过自动调整树的结构，AVL树可以确保查找、插入和删除操作的时间复杂度为 \(O(\log{n})\)。
用来衡量其&amp;quot;平衡程度&amp;quot;的标准是树中某个节点的左右子树的高度差
树的 高度 是指树中 层数 的总数。
平衡条件 AVL树中的每个节点的左右子树高度差（称为平衡因子）最多为1，(这样的约束确保了树的高度在\(O(\log{n})\)范围内)。即左右子树的高度差为 -1、0 或 1。否则，树需要通过旋转操作进行重新平衡。
树的旋转（为了保证平衡性） 左左(外-单) 左右(内-双) 右左(内-双) 右右(外-单) 单旋转 双旋转</description></item><item><title>Conditional Face Selection</title><link>https://choy-mutao.github.io/geometry_10/meshlab/filters-selection/conditionalfaceselection/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/geometry_10/meshlab/filters-selection/conditionalfaceselection/</guid><description/></item><item><title>Laplacian Smooth</title><link>https://choy-mutao.github.io/geometry_10/meshlab/filters-sfd/laplaciansmooth/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/geometry_10/meshlab/filters-sfd/laplaciansmooth/</guid><description>Laplacian Smooth Laplacian Smooth(surface preserving)</description></item><item><title>MOPSO 中的关键可能性</title><link>https://choy-mutao.github.io/pso_30/problems/mopso_key/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/pso_30/problems/mopso_key/</guid><description>介绍 多目标PSO（MOPSO）的关键之一确实是如何构建和维护Pareto结构。然而，这只是多目标优化中的一个方面。为了全面理解MOPSO，还需要考虑其他一些关键要素。以下是多目标PSO的几个重要组成部分：
1. Pareto 前沿构建和维护 Pareto 前沿：这是多目标优化中的一组非支配解。这些解在一个目标上不能被另一个解改进而不在其他目标上变差。
非支配解：在群体中找到所有非支配解，并将其存储在一个外部存档（Pareto 存档）中。
更新机制：每当有新的解产生时，更新Pareto存档，确保存档中始终保持最优和多样化的非支配解。
2. 适应度函数设计 多目标适应度：使用适应度函数来综合评估多个目标函数。这通常涉及将多个目标函数值结合成一个适应度值。
支配关系：基于支配关系来评估粒子的适应度。一个解支配另一个解如果它在所有目标上都不差于另一个解，并且在至少一个目标上更好。
3. 多样性维护 拥挤距离: 通过计算拥挤距离来维护粒子群体的多样性, 防止所有粒子收敛到局部最优解
多样化操作: 引入某些机制, 如变异操作或者随机重新初始化部分粒子位置, 来增加解的多样性
4. 粒子更新机制 速度和位置更新: MOPSO 仍然保留了标准PSO的速度和位置更新机制, 但在多目标环境中, 粒子的位置更新要综合考虑多个目标
引导粒子: 选择合适的粒子(如存档中的非支配解)作为其他粒子的引导, 确保搜索朝向 Petro 前沿移动
5. 权衡处理 目标权重: 根据决策者的偏好, 为不同的目标分配不同的权重, 有时使用加权和法来结合多个目标
动态调整: 在优化过程中动态调整粒子对不同目标的关注程度, 使得搜索过程更加灵活.</description></item><item><title>Parabola(Sphere) Formula</title><link>https://choy-mutao.github.io/pso_30/problems/so/parabola/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/pso_30/problems/so/parabola/</guid><description>Code 我们先简单看一段代码, 这是 SPSO 中的一个测试函数
C #include &amp;#34;structs.h&amp;#34; double ParabolaShpere(struct position xs, double p) { int D = xs.size; // 粒子群的 d-dimension double f = 0, xd; p = 0; // Shift for (int d = 0; d &amp;lt; D; d++) { xd = xs.x[d] - p; f = f + xd * xd; } return f; } 数学解释 如果我们有一个 点 \(x = (x_1, x_2, \cdots, x_D)\), 则这段代码的输出为: \(f = \sum_{d=0}^{D-1}(x_d - p)^2\), 这就是点 \(x\) 到 \(P = (p, p, \cdots, p)_D\) 的欧几里得范数的平方;</description></item><item><title>PSO 的控制参数</title><link>https://choy-mutao.github.io/pso_30/original/params/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/pso_30/original/params/</guid><description/></item><item><title>PSO 性能描述</title><link>https://choy-mutao.github.io/pso_30/original/performance/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/pso_30/original/performance/</guid><description>描述 PSO 的运行性能的参数 迭代次数 (在一次初始化后, 循环移动的次数) 失败次数 (在一次初始化后, 迭代至上限时, 没有得到结果, 算一次失败) 运行次数 (失败后重新初始化, 算一次运行) 成功率 (在一次迭代中, 得到收敛结果后, 不退出, 重新初始化, 至总运行次数上限, 其中成功次数的占比) 失败率 ( not 成功率)</description></item><item><title>参数结构体</title><link>https://choy-mutao.github.io/pso_30/original/spso2007/structs/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/pso_30/original/spso2007/structs/</guid><description>全局变量 #define D_max 114 //搜索空间的最大维度数 #define R_max 500 //最大运行次数 #define S_max 910 //最大群容量 #define fMax 6 //最大约束数+1 #define zero 0 //1.0e-30//避免数值不稳定 粒子群(Swarm) 定义粒子群中包含
P: 粒子局部最优位置队列(上一代) X: 当前每个粒子的位置特征 V: 当前每个粒子的迭代速度 best: 全局最优位置 struct swarm { int best; // rank of the best particle int S; // Swarm size struct Position P[S_max]; // Previous best positions found by each particle struct Velocity V[S_max]; // Velocities struct Position X[S_max]; // Positions }; 其中:</description></item><item><title>查找树ADT---二叉查找树(Binary Search Tree)</title><link>https://choy-mutao.github.io/dsa_1/tree/bst/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/dsa_1/tree/bst/</guid><description>描述 二叉查找树， 是二叉树在查找中的应用。 使二叉树变为二叉查找树的方法， 是增加一个性质： 对于树中的每个结点Node， 它的左子树中的所有项的值， 都小于X中的项， 而它的右子树中所有的项目的值大于 X 中的项。 其中(小于&amp;amp;大于)仅表达某种的排列规则在结点之间递归传递
二叉查找树的框架 template&amp;lt;typename Comparable&amp;gt; class BinarySearchTree { public: BinarySearchTree(); BinarySearchTree(const BinarySearchTree &amp;amp;node); ~BinarySearchTree(); const Comparable &amp;amp;findMin() const; const Comparable &amp;amp;findMax() const; bool contains(const Comparable &amp;amp;node) const; bool isEmpty() const; void printTree() const; void makeEmpty(); void insert(const Comparable &amp;amp;node); void remove(const Comparable &amp;amp;node); const BinarySearchTree &amp;amp; operator=(const BinarySearchTree &amp;amp;rhs); private: struct BinaryNode { Comparable element; BinaryNode *left; BinaryNode *right; BinaryNode(const Comparable &amp;amp;theelement, BinaryNode *lt, BinaryNode *rt): element(theelement), left(lt), right(rt) } BinaryNode *root; // =========== recuris sub progress void insert(const Comparable &amp;amp;node, BinaryNode *&amp;amp;t) const; void remove(const Comparable &amp;amp;node, BinaryNode *&amp;amp;t) const; BinaryNode *findMin(BinaryNode *t) const; BinaryNode *findMax(BinaryNode *t) const; bool contains(const Comparable &amp;amp;x, BinaryNode *&amp;amp;t) const; void makeEmpty(BinaryNode *&amp;amp;t); void printTree(BinaryNode *t) const; BinaryNode *clone(BinaryNode *t) const; } 随机生成二叉查找树</description></item><item><title>点和向量</title><link>https://choy-mutao.github.io/geometry_10/%E5%9F%BA%E7%A1%80%E5%87%A0%E4%BD%95/lineralgebra/points_and_vectors/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/geometry_10/%E5%9F%BA%E7%A1%80%E5%87%A0%E4%BD%95/lineralgebra/points_and_vectors/</guid><description/></item><item><title>多层划分树</title><link>https://choy-mutao.github.io/geometry_10/%E5%87%A0%E4%BD%95%E7%AE%97%E6%B3%95/query_region/multi_level_partition_tree/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/geometry_10/%E5%87%A0%E4%BD%95%E7%AE%97%E6%B3%95/query_region/multi_level_partition_tree/</guid><description/></item><item><title>二叉树(Binary Tree)</title><link>https://choy-mutao.github.io/dsa_1/tree/binaryt/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/dsa_1/tree/binaryt/</guid><description>描述 一颗每个结点的子节点不多于两个
实现 struct BNode { Object element; // The data in the node BNode *left; // Left child BNode *right; // Right child } 应用 表达式树 表达树中的树叶是 操作数(operand)
其他的节点是 操作符(operator)
中缀表达式(infix expresion) / 中缀遍历(inorder traversal) 写一种算法将后缀表达式 转变为 表达式树
将 中缀表达式 转变为 后缀表达式 的算法
从两种常用类型的输入生成表达式树</description></item><item><title>解决哈希冲突的一般方法</title><link>https://choy-mutao.github.io/dsa_1/hash/%E8%A7%A3%E5%86%B3%E5%93%88%E5%B8%8C%E5%86%B2%E7%AA%81%E7%9A%84%E4%B8%80%E8%88%AC%E6%96%B9%E6%B3%95/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/dsa_1/hash/%E8%A7%A3%E5%86%B3%E5%93%88%E5%B8%8C%E5%86%B2%E7%AA%81%E7%9A%84%E4%B8%80%E8%88%AC%E6%96%B9%E6%B3%95/</guid><description>什么是哈希冲突 简单来说, 假设一个哈希函数是: \(y=x \ mod \ 5\), 那么又两个键 1987 和 2 得到的结果都是 2, 则称为 哈希冲突, 其与 哈希函数 有关
冲突的解决 线性试探法 线性试探法属于 开放定址法 的一种, 除此之外, 开放定址法还包括 二元探测法, 双重嘻哈希发等. 当插入键 key 时候, 如果发现桶单元 bucket[hash(key)] 已经被占用, 则向下线性寻找, 直到找到可以使用的空桶. 故而经过第 i 次试探后, 桶单元为:
$$ bucket[(hash(key)+i) \ mod \ M], \ i = 1, 2, 3, \cdots $$
当 查找到某个 key 时, 首先通过哈希函数计算出桶的位置, 然后比较该桶中保存的值是否为该 key, 如果不是, 则继续向下寻找, 如果查到末尾, 则会从头开始查找
而删除某个 key 时, 为了避免查找过程中出现信息丢失, 则会将删除位置标记为 deleted, 这样, 当进行线性查找时, 遇到 deleted 会继续向下查找而不会中断</description></item><item><title>空间复杂度</title><link>https://choy-mutao.github.io/dsa_1/space_complexity/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/dsa_1/space_complexity/</guid><description/></item><item><title>平衡二叉查找树(Balanced Binary Search Tree)</title><link>https://choy-mutao.github.io/dsa_1/tree/bbst/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/dsa_1/tree/bbst/</guid><description>描述 平衡二叉树（Balanced Binary Tree）是一种二叉树结构，其中任意节点的左右子树的高度差（通常称为平衡因子）不超过1。这种特性确保了树的高度接近于最小，使得在最坏情况下的查找、插入和删除操作的时间复杂度为O(log n)，其中n是树中节点的数量。
常见的平衡二叉树类型 AVL 树 在AVL树中，任意节点的左右子树高度差不超过1。 在插入或删除节点后，AVL树会通过旋转操作来重新平衡树结构。 AVL树以其高度平衡的性质著称，查找效率非常高。 红黑树 红黑树是一种相对松散的平衡二叉树，它放宽了AVL树的平衡要求。 在红黑树中，树的每个节点都有一个颜色属性（红色或黑色），并且通过一系列的规则确保树大致平衡。 红黑树的查找、插入和删除操作时间复杂度同样为O(log n)，但是它在频繁插入和删除的情况下表现得比AVL树更好。</description></item><item><title>平面凸包的求解</title><link>https://choy-mutao.github.io/geometry_10/%E5%87%A0%E4%BD%95%E7%AE%97%E6%B3%95/convex_hull/convex_hull/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/geometry_10/%E5%87%A0%E4%BD%95%E7%AE%97%E6%B3%95/convex_hull/convex_hull/</guid><description>描述 针对 平面点集凸包的构造问题 的众多解决方法
Graham scan Preparata 和 Hong 提出的分治算法 递增式算法 dynamic convex hull Jarvis 提出的 包扎技术(wrapping) &amp;mdash; Jarvis march 对点的集合进行的 &amp;ldquo;字典序&amp;rdquo; 排列 有一种 P 进制数的概念, 其中还有 左进制数, 右进制数
SlowConvexHull Input: 平面点集 P
Output: 描述凸包的点集 l
\( E \gets \emptyset \) \( \textbf{for} (每一有序对(p,q) \in P \times P, p \ne q) \) \( \quad \textbf{do} \ valid \gets true\) \( \quad \quad \textbf{for} (除 p 和 q 之外的所有点 r \in P)\) \( \quad \quad \quad \textbf{do \ if (r位于p和q所确定的有向直线的左侧)}\) \( \quad \quad \quad \quad \textbf{then} \ valid \gets fale\) \( \quad \quad \quad \quad \quad \textbf{if} \ (valid) \ \textbf{then} \ 将所有有向边 \overline{pq} 加入到 E \) \( 根据集合E中的各边, 找出CH(P)的所有顶点, 并按照顺时针方向将它们组织为列表 l\) ConvexHull Input: 平面点集 P</description></item><item><title>伸展树</title><link>https://choy-mutao.github.io/dsa_1/tree/splay/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/dsa_1/tree/splay/</guid><description>描述 一种保证从空树开始任意连续M次对树的操作最多花费\(O(M\log{N})\)时间的树
不存在不好的输入序列
基本想法： 当一个 Node 被访问后， 就要经过一系列 AVL 树的旋转被推到根上
伸展(Splayling) 伸展的方法类似于旋转, 在旋转如何实施上增加一些选择的余地
之子形 一子形 伸展树的操作</description></item><item><title>生命游戏</title><link>https://choy-mutao.github.io/%E7%94%9F%E5%91%BD%E6%B8%B8%E6%88%8F_50/conwaylife/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/%E7%94%9F%E5%91%BD%E6%B8%B8%E6%88%8F_50/conwaylife/</guid><description/></item><item><title>时间复杂度</title><link>https://choy-mutao.github.io/dsa_1/time_complexity/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/dsa_1/time_complexity/</guid><description/></item><item><title>双指针</title><link>https://choy-mutao.github.io/dsa_1/code_template/%E5%8F%8C%E6%8C%87%E9%92%88/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/dsa_1/code_template/%E5%8F%8C%E6%8C%87%E9%92%88/</guid><description>当只有一个输入, 从该输入的两端遍历 int fn(vector&amp;lt;int&amp;gt;&amp;amp; arr) { int left = 0; // left pointer index int right = int(array.size()) - 1; // right pointer index int ans = 0; while(left &amp;lt; right) { if(true /* condition */) { // ... left++; } else { // ... right--; } } return ans; } 有两个输入, 两个都需要遍历 public int fn(int[] arr1, int[] arr2) { int i = 0; // pointer at arr1 int j = 0; // pointer at arr2 int ans = 0; while(i &amp;lt; arr1.</description></item><item><title>退化和鲁棒性</title><link>https://choy-mutao.github.io/geometry_10/%E5%87%A0%E4%BD%95%E7%AE%97%E6%B3%95/degenerate_and_robustness/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/geometry_10/%E5%87%A0%E4%BD%95%E7%AE%97%E6%B3%95/degenerate_and_robustness/</guid><description>描述 退化和鲁棒性, 是为了构建完备的几何算法而需要具备的敏感性
所谓退化, 其关联计算机处理浮点数计算过程中的舍入误差而使得几何计算的结果在进入下一次计算时候带来的可能的影响
鲁棒性, 多是因为在构建算法之初, 为了平衡(问题的几何描述的逻辑性而做出的)一些一般性假设与实际问题上的偏差, 对算法的稳定性的度量.
因为实际问题在某个算法的应用场景是有界的, 所以提出一种上帝几何算法的可能, 是有限的.</description></item><item><title>线段求交</title><link>https://choy-mutao.github.io/geometry_10/%E5%87%A0%E4%BD%95%E7%AE%97%E6%B3%95/thematic_map/line_segment_intersect/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/geometry_10/%E5%87%A0%E4%BD%95%E7%AE%97%E6%B3%95/thematic_map/line_segment_intersect/</guid><description>描述 给定由平面上 \(n\) 条闭线段构成的一个集合 \(S\), 求出 \(S\) 中个线段之间 的所有交点. 其中闭线段是指不同线段端点的重合也将被视为交点
&amp;ldquo;输出敏感&amp;quot;的算法 我们所希望得到的算法，其运行时间不仅取决于输入中线段的数目，还取决于（实际的）交 点数目。这样的算法，被称为“输出敏感的”算法（output-sensitive algorithm）⎯⎯ 也就 是说，这种算法的运行时间对（实际）输出的大小很敏感。也可以称这样一个算法是“交点 敏感的”（intersection-sensitive）⎯⎯ 因为，输出的大小就是由交点的数目决定的
引理 2.1 设两条非水平的线段 \(si\) 和 \(sj\) 只相交于其内部的一点 \(p\)，而且，任 何第三条线段都不经过 \(p\)。则在（扫描线到达）高于 \(p\)$ 的某个事件点处（ 时），\(si\) 和 \(sj\) 必然会彼此紧邻，并因此接受相交测试（于是对应的交点 将被发现）。
几何分析 将一条线段在y轴上的正交投影, 定义为该线段的 y-区间, 任何两条线段, 只要其y-区间没有重叠部分, 则一定不会相交 事件队列(Event Queue) 在该算法中的队列是一个有序队列, 且在该队列中的查找是基 于平衡二分查找树(balanced binary search tree).
Enqueue: 来存放（当前已被检测出来，但尚未发生的）事件。 Dequeue: 把即将发生的下一事件从 Q 中删除掉，并将它返回（给主程序），以便对它进 行处理。 Insert: Sort: 状态结构(Status Structure) 状态(是与当前扫描线相交的所有线段构成的有序序列), 通过一个状态结构（status structure），可以访问某一给定线段\(s\)的（左、右）邻居.
在插入一个线段\(s\)之后, 就可以立即进行相应的相交测试
这个状态结构式动态的, 当有某条线段开始（或不再）与扫描线相交，就应将它插入到状 态结构中（或从状态结构中删去）
在任一时刻(在某一事件点), 状态结构中的所有线段之间具有一个定义明确的次序(与当前 扫描线相交的每条线段，都按照其次序，)，因此可以使用一棵平衡二分查找树来实现状 态结构</description></item><item><title>线性规划-铸模制造</title><link>https://choy-mutao.github.io/geometry_10/%E5%87%A0%E4%BD%95%E7%AE%97%E6%B3%95/linear_programming_mold_manufacture/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/geometry_10/%E5%87%A0%E4%BD%95%E7%AE%97%E6%B3%95/linear_programming_mold_manufacture/</guid><description>Terms 二维小平面(facet) 顶面(top face): 有且仅有一个小平面 普通面(ordinary facet) 半平面(): 在平面上位于某条直线左(或右)侧的部分 可铸造的(castable) 外法矢(outward normal) Theories 4.1 沿某个方向\(\vec{d}\)通过一次平移, 多面体\(P\)能够从其铸模中抽取出来, 当且仅当相对于\(P\)的每一张普通面的外法矢, 移动方向\(\vec{d}\)v 与之所呈的角度都至少为 90度
由4.1 可推出: 若可以通过多次小幅度的平移将 p 抽取出, 则必然可以仅通过一次平移就将其抽取出来(向量的合成)
IntersectHalfPlanes(H) Input: 由平面上 n 张半平面组成的一个集合 H
Output: 凸多边形区域 C
\(\) \(\) \(\) \(\) \(\) \(\)</description></item><item><title>圆弧</title><link>https://choy-mutao.github.io/geometry_10/%E5%9F%BA%E7%A1%80%E5%87%A0%E4%BD%95/geometry/curve/arc/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/geometry_10/%E5%9F%BA%E7%A1%80%E5%87%A0%E4%BD%95/geometry/curve/arc/</guid><description>圆弧的定义方法 圆弧的参数化表示方法 $$\vec{r}(t) = \vec{c} + r\cos{t}\vec{u} + r\sin{t}\vec{v}$$其中, \(\vec{c}\) 是圆心位置向量, \(r\) 是半径, \(t\) 是参数(通常在 \([0,\theta]\))范围内, \(\theta\) 是圆弧的总角度, \(\vec{u}\) 和 \(\vec{v}\) 是与圆弧方向相关的单位向量
圆弧的离散与采样 圆弧的动态采样 圆弧的动态采样方法通常涉及根据弧线的曲率和长度智能地确定采样点的位置和数量
曲率评估 通过计算圆弧的曲率来决定采样点的密度。曲率 \kappaκ 可以用以下公式计算: \(k = \frac{1}{r}\) 曲率越大，表示圆弧的弯曲程度越大，因此在该处可能需要更多的采样点。
动态分段采样 将圆弧分成若干段，每段长度根据预设的最大误差或曲率变化来确定。在每段中，根据需要计算或保持一定的采样点密度。
适当选择参数步长 根据曲率和圆弧长度，选择适当的参数步长来控制采样点的分布。通常，在曲率较大的部分和细节较多的区域会使用更小的步长。
动态调整采样点数量 根据需要和计算能力，动态调整每段的采样点数量，以平衡精度和性能要求。
起始和结束点的特殊处理 始终确保始点和终点包含在采样点列表中，以确保完整性和准确性</description></item><item><title>直线和线段的相交求解</title><link>https://choy-mutao.github.io/geometry_10/%E5%9F%BA%E7%A1%80%E5%87%A0%E4%BD%95/algorithm/line_and_plane_intersection/line_and_segment/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/geometry_10/%E5%9F%BA%E7%A1%80%E5%87%A0%E4%BD%95/algorithm/line_and_plane_intersection/line_and_segment/</guid><description>描述 在求解 2D 和 3D 的线段与直线的相交性时, 一般采用 “参数方程” 来描述两者
参数方程 直线 $$P(s) = P_0 + s(P_1 - P_0) = P_0 + s*\vec{u} \\ 其中, s = d(P_0, P(s)) / d(P_0, P_1)$$同理可定义另一条直线的方程 \(Q(t) = Q_0 + v(Q_1 - Q_0) = Q_0 + t*\vec{v}\)
平行线 当且仅当 \(\vec{u} = a\vec{v}, \ \vec{u} = P_1-P_0, \ \vec{v} = Q_1 - Q_0\)
非平行线</description></item><item><title>主逻辑</title><link>https://choy-mutao.github.io/pso_30/original/spso2007/pso/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/pso_30/original/spso2007/pso/</guid><description>初始化 相较于 SPSO2006, 该版本增加了量化的步骤, 用于处理离散问题的优化
筛选最优解 相较于 SPSO2006, 该版本定义了两种筛选方法
比较评价函数的值与目标值的误差 比较当前位置(解)与目标位置(目标解)的误差 更新拓扑通知 迭代移动 相较于 SPSO2006, 该版本在移动过程中增加了如下步骤
在每次开始移动前对粒子群中的粒子进行随机排序 更新了一种新的速度生成策略 速度生成逻辑 环境判断条件(退出的时机) 相较于 SPSO2006, 该版本增加了更多推出条件, 防止陷入死循环
// Check if finished // If no improvementd, information links will be reinitialized error = P[best_index].f; if (error &amp;gt;= error_prev) init_links = 1; else init_links = 0; error_prev = error; if (error &amp;gt; eps &amp;amp;&amp;amp; nb_eval &amp;lt; eval_max) goto loop; if (error &amp;gt; eps) n_failure = n_failure + 1;</description></item><item><title>装配问题(Casting Problem)</title><link>https://choy-mutao.github.io/geometry_10/%E5%87%A0%E4%BD%95%E7%AE%97%E6%B3%95/chapter4_castingproblem/casting_problem/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/geometry_10/%E5%87%A0%E4%BD%95%E7%AE%97%E6%B3%95/chapter4_castingproblem/casting_problem/</guid><description>描述</description></item><item><title>坐标系理论</title><link>https://choy-mutao.github.io/geometry_10/%E5%9F%BA%E7%A1%80%E5%87%A0%E4%BD%95/lineralgebra/coordiate_system/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://choy-mutao.github.io/geometry_10/%E5%9F%BA%E7%A1%80%E5%87%A0%E4%BD%95/lineralgebra/coordiate_system/</guid><description>描述 直角线性坐标(rectangular linear coordinate) 直角线性坐标系统具有一个固定的绝对参考点作为原点，以及一组非零的坐标轴作为方向向量，这些方向向量确定了测量的方向。
一个坐标系统通过有序的n元组\((x_1, x_2, &amp;hellip; x_n)\)来指定n维空间中的点，数值规则为：在第一个轴上, 行动 \(x_1\) 的距离, 然后在第二个轴上, 行动 \(x_2\) 的距离, 一次类推到第n个轴上, 其中有序的数字集合\((x_1, x_2, &amp;hellip; x_n)\)称为点的坐标。
所有这些点的集合称为坐标空间。
一组特定的坐标轴构成的坐标空间称为坐标参考框架或空间的基。
不同的坐标系统可以跨越相同的坐标空间。
如果坐标轴彼此独立，即没有任何坐标轴可以写成其他坐标轴的组合，则这些轴被称为独立轴。
当独立时，它们是坐标空间的最小轴集，轴的数量即为空间的维度。
极坐标(polar coordinate) 球坐标(spherical coordinate)</description></item></channel></rss>