Dandelion 1.1.1
A light-weight 3D builder for educational usage
载入中...
搜索中...
未找到
halfedge.h
浏览该文件的文档.
1#ifndef DANDELION_GEOMETRY_HALFEDGE_H
2#define DANDELION_GEOMETRY_HALFEDGE_H
3
4#include <cstddef>
5#include <set>
6#include <memory>
7#include <optional>
8#include <variant>
9#include <tuple>
10#include <unordered_map>
11
12#include <Eigen/Core>
13#include <spdlog/spdlog.h>
14
15#include "../platform/gl.hpp"
18#include "../scene/object.h"
19
20/*!
21 * \file geometry/halfedge.h
22 * \ingroup geometry
23 * \~chinese
24 * \brief 半边网格所需各种类型的公共头文件。
25 *
26 * Dandelion 的几何处理算法都是基于半边网格的,所有几何处理需要的类型都在这个头文件中声明,
27 * 但在不同的源文件中定义。`Halfedge` / `Vertex` / `Edge` / `Face` 各自有一个源文件,
28 * 而 `HalfedgeMesh` 则被分为两部分:创建、同步和检查等功能在 *halfedge_mesh.cpp*
29 * 中实现,各类几何操作在 *meshedit.cpp* 中实现。
30 */
31
32struct Halfedge;
33struct Vertex;
34struct Edge;
35struct Face;
36
37/*!
38 * \ingroup geometry
39 * \~chinese
40 * \brief 半边网格中最关键的几何元素。
41 *
42 * 半边网格中,所有几何元素都通过半边相互连接。Halfedge 类维护了每条半边的起点、所属的边和面片、
43 * 在整个半边网格上的下一条(前一条、反向)半边,从而将所有的几何基本元素联系在一起。
44 */
45struct Halfedge : LinkedListNode<Halfedge>
46{
47 /*! \~chinese 仅供 `HalfedgeMesh::new_halfedge` 调用,其他任何情况下都不应该直接使用。 */
48 Halfedge(std::size_t halfedge_id);
49 /*! \~chinese 一次性设置半边的所有属性,各参数含义与同名属性一致。 */
51 Face* face);
52 /*!
53 * \~chinese
54 * \brief 这条半边是否属于一个虚拟的边界面。
55 *
56 * 这个函数的返回值是 `face->on_boundary`,因此返回真时表示这条半边属于一个
57 * “虚假的”面(表示边界而不是真正的面片);而返回假时这条半边也有可能与 mesh
58 * 边界相邻,所以函数名为 `is_boundary` 而不是 `on_boundary` 。
59 */
60 bool is_boundary() const;
61 /*! \~chinese 半边的全局唯一 ID,不会与整个半边网格中任何其他元素重复。 */
62 const std::size_t id;
63 /*! \~chinese 下一条半边。 */
65 /*! \~chinese 上一条半边。 */
67 /*! \~chinese 反方向的半边。 */
69 /*! \~chinese 半边的起点(发出点)。 */
71 /*! \~chinese 半边所在的边。 */
73 /*! \~chinese 半边所在的面片。 */
75};
76
77/*!
78 * \ingroup geometry
79 * \~chinese
80 * \brief 半边网格中的顶点。
81 *
82 * 半边网格中,每个顶点只维护自身的坐标和某一条从自身发出的半边。
83 */
84struct Vertex : LinkedListNode<Vertex>
85{
86 /*! \~chinese 仅供 `HalfedgeMesh::new_vertex` 调用,其他任何情况下都不应该直接使用。 */
87 Vertex(std::size_t vertex_id);
88 /*! \~chinese 邻接的面片数量(不包括虚拟的边界面)。 */
89 size_t degree() const;
90 /*!
91 * \~chinese
92 * \brief \f$\mathcal{N}_1\f$ 邻域 (1-ring neighborhood) 中所有顶点坐标的算数平均值。
93 */
94 Eigen::Vector3f neighborhood_center() const;
95 /*! \~chinese 以面积为权重对邻接面片法向量求平均给出的顶点法向估计值。 */
96 Eigen::Vector3f normal() const;
97 /*! \~chinese 顶点的全局唯一 ID,不会与整个半边网格中任何其他元素重复。 */
98 const std::size_t id;
99 /*! \~chinese 从这一顶点发出的某条半边。 */
101 /*! \~chinese 顶点坐标。 */
102 Eigen::Vector3f pos;
103 /*! \~chinese 新建顶点的标识,在一些全局操作中用到。 */
104 bool is_new;
105 /*! \~chinese 在迭代式调整顶点坐标时保存迭代后的坐标(例如 Loop 细分时调整后的坐标)。 */
106 Eigen::Vector3f new_pos;
107};
108
109/*!
110 * \ingroup geometry
111 * \~chinese
112 * \brief 半边网格中的边。
113 *
114 * 半边网格中,每条边只维护属于自身的某一条半边。
115 */
116struct Edge : LinkedListNode<Edge>
117{
118 /*! \~chinese 仅供 `HalfedgeMesh::new_edge` 调用,其他任何情况下都不应该直接使用。 */
119 Edge(std::size_t edge_id);
120 /*! \~chinese 这条边是否在 mesh 边界上。 */
121 bool on_boundary() const;
122 /*! \~chinese 边的中点坐标。 */
123 Eigen::Vector3f center() const;
124 /*! \~chinese 边的长度。 */
125 float length() const;
126 /*! \~chinese 边的全局唯一 ID,不会与整个半边网格中任何其他元素重复。 */
127 const std::size_t id;
128 /*! \~chinese 沿着这条边的某一条半边。 */
130 /*! \~chinese 新建边的标识,在一些全局操作中用到。 */
131 bool is_new;
132 /*!
133 * \~chinese
134 * \brief 准备分裂这条边时分裂后新增顶点的坐标。
135 *
136 * `HalfedgeMesh::split_edge` 函数并不会使用这个坐标,而是直接用边中点作为新增顶点的位置。
137 * 这个属性仅供需要指定分裂后顶点位置的算法使用,例如 Loop 细分。
138 */
139 Eigen::Vector3f new_pos;
140};
141
142/*!
143 * \ingroup geometry
144 * \~chinese
145 * \brief 半边网格中的面片。
146 *
147 * 半边网格中,每个面片只维护属于自身的某一条半边。
148 */
149struct Face : LinkedListNode<Face>
150{
151 /*! \~chinese 仅供 `HalfedgeMesh::new_face` 调用,其他任何情况下都不应该直接使用。 */
152 Face(std::size_t face_id, bool is_boundary = false);
153 /*! \~chinese 返回面片法向量与面片面积的数量积。 */
154 Eigen::Vector3f area_weighted_normal();
155 /*! \~chinese 返回面片法向量(已经单位化)。 */
156 Eigen::Vector3f normal();
157 /*! \~chinese 返回面片中心(也是重心,顶点坐标的算数平均值)。 */
158 Eigen::Vector3f center() const;
159 /*! \~chinese 面片的全局唯一 ID,不会与整个半边网格中任何其他元素重复。 */
160 const std::size_t id;
161 /*! \~chinese 属于这个面片的某一条半边。 */
163 /*!
164 * \~chinese
165 * \brief 边界面标识。
166 *
167 * 如果不加处理地从一个不封闭 mesh 创建半边,位于 mesh 边界的边上将只会有一条半边,
168 * 从而让某些半边的反向指针 (`inv`) 为空。为了让半边网格在形式上统一,
169 * 创建半边网格时会将每条边界视作一个“环路”,并为这个“环路”创建一个虚拟的面。
170 */
171 const bool is_boundary;
172};
173
174/*!
175 * \ingroup geometry
176 * \~chinese
177 * \brief 半边网格的不合法情况。
178 *
179 * 在创建半边网格失败或验证其合法性失败时,用该枚举类代表失败原因。
180 * - NO_SELECTED_MESH 表示没有选中任何 mesh,半边网格没有数据源。
181 * - MULTIPLE_ORIENTED_EDGES 表示有多条重叠的半边(端点和方向都相同),该 mesh 不可定向。
182 * - NON_MANIFOLD_VERTEX 表示有非流形顶点。
183 * - INIFINITE_POSITION_VALUE 表示有的顶点坐标是无穷大。
184 * - INVALID_HALFEDGE_PERMUTATION 表示某条半边的指针空缺或指向了不正确的元素。
185 * - INVALID_VERTEX_CONNECTIVITY 表示某个顶点与半边的连接关系不正确
186 * - INVALID_EDGE_CONNECTIVITY 表示某条边与半边的连接关系不正确。
187 * = INVALID_FACE_CONNECTIVITY 表示某个面与半边的连接关系不正确。
188 * - ILL_FORMED_HALFEDGE_INVERSION 表示某条半边的反向关系不正确。
189 * - POOR_HALFEDGE_ACCESSIBILITY 表示某条半边不能通过其连接到的元素反向访问到。
190 *
191 * 更详细的说明见运行时输出的日志内容。
192 */
194{
195 NO_SELECTED_MESH,
196 MULTIPLE_ORIENTED_EDGES,
197 NON_MANIFOLD_VERTEX,
198 INIFINITE_POSITION_VALUE,
199 INVALID_HALFEDGE_PERMUTATION,
200 INVALID_VERTEX_CONNECTIVITY,
201 INVALID_EDGE_CONNECTIVITY,
202 INVALID_FACE_CONNECTIVITY,
203 ILL_FORMED_HALFEDGE_INVERSION,
204 POOR_HALFEDGE_ACCESSIBILITY
205};
206
207/*!
208 * \ingroup geometry
209 * \~chinese
210 * \brief 半边网格整体。
211 *
212 * 当 Dandelion 进入建模模式时,`Scene` 对象将用选中的 mesh 构造一个半边网格,
213 * 从而支持各种基于半边网格的几何算法。当几何操作完成后,需要将半边网格的几何信息
214 * (坐标、连接关系等)同步到原先的 mesh,这样才能显示操作带来的变化。
215 *
216 * 各种全局操作往往需要频繁增删几何元素,为了保证 \f$O(1)\f$ 的增删效率,
217 * 所有的几何元素都存储于双向链表 (`LinkedList`) 中。
218 */
220{
221public:
222 /*! \~chinese 指定一个 `GL::Mesh` 作为参照,构造半边网格。 */
223 HalfedgeMesh(Object& object);
224 /*! \~chinese 全局只有一个半边网格实例,因此不允许复制构造。 */
225 HalfedgeMesh(HalfedgeMesh& other) = delete;
226 /*! \~chinese 析构时会调用 `clear_erasure_records` 释放所有已删除元素占据的内存。 */
228 /*! \~chinese 将当前半边网格的几何结构同步到数据源 mesh。 */
229 void sync();
230 /*! \~chinese 渲染所有的半边(不负责渲染顶点、边和面片)。 */
231 void render(const Shader& shader);
232 /*! \~chinese 返回绘制半边时的起点和终点坐标。 */
233 static std::tuple<Eigen::Vector3f, Eigen::Vector3f> halfedge_arrow_endpoints(const Halfedge* h);
234 /*!
235 * \~chinese
236 * \brief 翻转一条边。
237 *
238 * 由于翻转边的过程中所有几何基本元素数量不变,可以在不增删元素的前提下实现这个函数。
239 * 在此情况下,返回的就是被传入的边。如果实现过程中删除了原有的边,
240 * 返回的指针可能与传入的不同。
241 *
242 * 但无论采用哪种实现方法,都不应该翻转 mesh 边界上的边。
243 * \returns 如果翻转成功,返回被翻转的边;反之返回 `std::nullopt` 。
244 */
245 std::optional<Edge*> flip_edge(Edge* e);
246 /*!
247 * \~chinese
248 * \brief 分裂一条边。
249 *
250 * 将传入的边分裂成两条边,分裂处新增一个顶点,并将此顶点与相对位置的两个顶点连接。
251 * 分裂操作要求指定边的两个邻接面都是三角形面。
252 * \returns 如果分裂成功,返回新增顶点;反之返回 `std::nullopt` 。
253 */
254 std::optional<Vertex*> split_edge(Edge* e);
255 /*!
256 * \~chinese
257 * \brief 坍缩一条边。
258 *
259 * 将传入的边坍缩成一个顶点,原先连接到两个端点上的其他边全部连接到这个顶点;
260 * 如果这条边的某个邻接面是三角形面,这个邻接面会被坍缩成一条边。
261 *
262 * 不加检查地坍缩一条边有可能破坏 mesh 的流形性质。假设边端点分别为 \f$v_1,v_2\f$,
263 * 此函数仅当
264 * \f[
265 * \mathcal{N}_1(v_1)\cap\mathcal{N}_1(v_2) = 2
266 * \f]
267 * 时才执行坍缩,以免破坏流行性质。
268 * \returns 如果坍缩成功,返回坍缩后的顶点;反之返回 `std::nullopt` 。
269 */
270 std::optional<Vertex*> collapse_edge(Edge* e);
271 /*!
272 * \~chinese
273 * \brief 执行一次 Loop 曲面细分。
274 *
275 * 该函数使用 `flip_edge` 和 `split_edge` 完成一次 Loop 曲面细分。注意,Loop
276 * 曲面细分只能细分三角网格。细分过程使用 `is_boundary` 和 `on_boundary`
277 * 等 API 来判断 mesh 边界并进行处理。
278 */
279 void loop_subdivide();
280 /*!
281 * \~chinese
282 * \brief 执行一次曲面简化。
283 *
284 * 该函数根据二次误差度量 (Quadric Error Metric, QEM) 确定损失最小的边,
285 * 再用 `collapse_edge` 坍缩它从而减少面数,直至面数减为简化前的 1/4
286 * 或找不到可以坍缩的边为止。
287 */
288 void simplify();
289 /*!
290 * \~chinese
291 * \brief 执行一次重网格化。
292 *
293 * 该函数采用各向同性重网格化策略调整 mesh 的边,尽可能让每个顶点的度都接近 6、
294 * 每个面片都接近正三角形。调整时它重复以下过程:
295 * 1. 分裂过长的边
296 * 2. 坍缩过短的边
297 * 3. 通过翻转边让顶点的度数更平均
298 * 4. 将顶点位置向它的 \f$\mathcal{N}_1\f$ 邻域平均值移动
299 *
300 * 各向同性重网格化只能应用于三角形网格。
301 */
302 void isotropic_remesh();
303 /*! \~chinese 所有半边。 */
305 /*! \~chinese 所有顶点。 */
307 /*! \~chinese 所有边。 */
309 /*! \~chinese 所有面片。 */
311 /*! \~chinese 将 `GL::Mesh` 使用的顶点索引映射为半边网格中的顶点指针。 */
312 std::vector<Vertex*> v_pointers;
313 /*!
314 * \~chinese
315 * \brief 当前处于不一致状态的几何基本元素。
316 *
317 * 在 GUI 上选中了半边网格中的某个元素后,控制器将设置该属性,`sync`
318 * 函数根据该属性的值在每一帧更新数据源 mesh 中的顶点坐标,让建模模式下可以实时预览形变效果。
319 */
320 std::variant<std::monostate, Vertex*, Edge*, Face*> inconsistent_element;
321 /*! \~chinese 全局一致性。成功完成一次全局操作后,此变量将置为真,表示需要同步到参照 mesh。 */
323 /*! \~chinese 在创建半边网格时设置,如果创建正常则为 `std::nullopt`。 */
324 std::optional<HalfedgeMeshFailure> error_info;
325
326private:
327 /*!
328 * \~chinese
329 * \brief 在曲面简化算法中用到的工具类。
330 *
331 * 基于 QEM 的简化算法需要实时获取损失最小的边,这个结构体用于记录一条边的坍缩代价、
332 * 坍缩后顶点的最佳位置,并放入优先队列中进行排序。
333 */
334 struct EdgeRecord
335 {
336 EdgeRecord() = default;
337 /*! \~chinese 根据两个端点的二次误差矩阵构造边的二次误差矩阵,并计算最佳坍缩位置。 */
338 EdgeRecord(std::unordered_map<Vertex*, Eigen::Matrix4f>& vertex_quadrics, Edge* e);
339 /*! \~chinese 这个记录对应的边。 */
341 /*! \~chinese 执行曲面简化算法时的最佳坍缩位置。 */
342 Eigen::Vector3f optimal_pos;
343 /*! \~chinese 执行曲面简化算法时坍缩这条边的代价(带来的误差)。 */
344 float cost;
345 };
346 /*! \~chinese 排序 `EdgeRecord` 所需的比较运算符重载。 */
347 friend bool operator<(const EdgeRecord& a, const EdgeRecord& b);
348 /*! \~chinese 创建一条半边。 */
350 /*! \~chinese 创建一个顶点。 */
352 /*! \~chinese 创建一条边。 */
353 Edge* new_edge();
354 /*! \~chinese 创建一个面片,可以是真实存在的面片也可以是代表边界的虚拟面片。 */
355 Face* new_face(bool is_boundary = false);
356 /*! \~chinese 重新生成所有半边对应的箭头,在更新绘制数据时使用。 */
358 /*! \~chinese 删除一条半边。 */
359 void erase(Halfedge* h);
360 /*! \~chinese 删除一个顶点。 */
361 void erase(Vertex* v);
362 /*! \~chinese 删除一条边。 */
363 void erase(Edge* e);
364 /*! \~chinese 删除一个面。 */
365 void erase(Face* f);
366 /*!
367 * \~chinese
368 * \brief 释放内存并清除已删除元素的记录。
369 *
370 * 这个函数执行 `delete` 释放内存,并清空各 `erased_[elements]` 容器中存储的删除记录。
371 */
373 /*!
374 * \~chinese
375 * \brief 检查半边网格的状态。
376 *
377 * 这个函数可以检查半边网格中的连接关系是否正确、指针是否悬垂,有助于及时发现错误。
378 * 错误信息会被输出到日志,并返回一个错误枚举值(参考 `HalfedgeMeshFailure` 类的说明)。
379 * \returns 如果发现错误,返回相应的错误枚举值;反之为 `std::nullopt`
380 */
381 std::optional<HalfedgeMeshFailure> validate();
382
383 /*! \~chinese 用于构造半边网格几何元素时分配新的唯一 ID。 */
384 static std::size_t next_available_id;
385 /*! \~chinese 数据源 mesh 对应的物体。 */
387 /*! \~chinese 数据源 mesh,用于构造半边网格,需要同步修改。 */
389 /*! \~chinese 已删除的半边。 */
390 std::unordered_map<size_t, Halfedge*> erased_halfedges;
391 /*! \~chinese 已删除的顶点。 */
392 std::unordered_map<size_t, Vertex*> erased_vertices;
393 /*! \~chinese 已删除的边。 */
394 std::unordered_map<size_t, Edge*> erased_edges;
395 /*! \~chinese 已删除的面。 */
396 std::unordered_map<size_t, Face*> erased_faces;
397
398 /*! \~chinese 将半边网格中的顶点指针映射为 `GL::Mesh` 使用的顶点索引。 */
399 std::unordered_map<const Vertex*, size_t> v_indices;
400 /*! \~chinese 将半边网格的半边指针映射为 `GL::LineSet` 中的箭头索引。 */
401 std::unordered_map<const Halfedge*, size_t> h_indices;
402 /*! \~chinese 用于渲染半边的 `LineSet` 对象。 */
404 /*! \~chinese 日志记录器。 */
405 std::shared_ptr<spdlog::logger> logger;
406};
407
408#endif // DANDELION_GEOMETRY_HALFEDGE_H
std::optional< Vertex * > collapse_edge(Edge *e)
坍缩一条边。
定义 meshedit.cpp:259
Halfedge * new_halfedge()
定义 halfedge_mesh.cpp:366
HalfedgeMesh(HalfedgeMesh &other)=delete
void loop_subdivide()
执行一次 Loop 曲面细分。
定义 meshedit.cpp:397
Face * new_face(bool is_boundary=false)
定义 halfedge_mesh.cpp:387
friend bool operator<(const EdgeRecord &a, const EdgeRecord &b)
定义 meshedit.cpp:36
Object & object
定义 halfedge.h:386
GL::LineSet halfedge_arrows
定义 halfedge.h:403
std::shared_ptr< spdlog::logger > logger
定义 halfedge.h:405
std::optional< HalfedgeMeshFailure > error_info
定义 halfedge.h:324
void erase(Halfedge *h)
定义 halfedge_mesh.cpp:412
std::unordered_map< size_t, Face * > erased_faces
定义 halfedge.h:396
LinkedList< Halfedge > halfedges
定义 halfedge.h:304
void render(const Shader &shader)
定义 halfedge_mesh.cpp:348
void isotropic_remesh()
执行一次重网格化。
定义 meshedit.cpp:655
Edge * new_edge()
定义 halfedge_mesh.cpp:380
Vertex * new_vertex()
定义 halfedge_mesh.cpp:373
GL::Mesh & mesh
定义 halfedge.h:388
LinkedList< Vertex > vertices
定义 halfedge.h:306
std::optional< HalfedgeMeshFailure > validate()
检查半边网格的状态。
定义 halfedge_mesh.cpp:452
static std::tuple< Eigen::Vector3f, Eigen::Vector3f > halfedge_arrow_endpoints(const Halfedge *h)
定义 halfedge_mesh.cpp:354
std::vector< Vertex * > v_pointers
定义 halfedge.h:312
LinkedList< Face > faces
定义 halfedge.h:310
LinkedList< Edge > edges
定义 halfedge.h:308
void sync()
定义 halfedge_mesh.cpp:247
std::unordered_map< size_t, Halfedge * > erased_halfedges
定义 halfedge.h:390
std::unordered_map< size_t, Vertex * > erased_vertices
定义 halfedge.h:392
~HalfedgeMesh()
定义 halfedge_mesh.cpp:242
std::unordered_map< size_t, Edge * > erased_edges
定义 halfedge.h:394
std::optional< Vertex * > split_edge(Edge *e)
分裂一条边。
定义 meshedit.cpp:97
void regenerate_halfedge_arrows()
定义 halfedge_mesh.cpp:394
std::unordered_map< const Vertex *, size_t > v_indices
定义 halfedge.h:399
std::unordered_map< const Halfedge *, size_t > h_indices
定义 halfedge.h:401
static std::size_t next_available_id
定义 halfedge.h:384
void clear_erasure_records()
释放内存并清除已删除元素的记录。
定义 halfedge_mesh.cpp:432
std::variant< std::monostate, Vertex *, Edge *, Face * > inconsistent_element
当前处于不一致状态的几何基本元素。
定义 halfedge.h:320
void simplify()
执行一次曲面简化。
定义 meshedit.cpp:519
bool global_inconsistent
定义 halfedge.h:322
std::optional< Edge * > flip_edge(Edge *e)
翻转一条边。
定义 meshedit.cpp:41
HalfedgeMesh(Object &object)
定义 halfedge_mesh.cpp:42
侵入式双链表。
定义 linked_list.hpp:44
表示物体的类。
定义 object.h:40
对 GLSL Shader 的简单封装。
定义 shader.hpp:24
HalfedgeMeshFailure
半边网格的不合法情况。
定义 halfedge.h:194
半边网格中的边。
定义 halfedge.h:117
bool is_new
定义 halfedge.h:131
Eigen::Vector3f new_pos
准备分裂这条边时分裂后新增顶点的坐标。
定义 halfedge.h:139
float length() const
定义 edge.cpp:22
bool on_boundary() const
定义 edge.cpp:10
const std::size_t id
定义 halfedge.h:127
Halfedge * halfedge
定义 halfedge.h:129
Eigen::Vector3f center() const
定义 edge.cpp:15
Edge(std::size_t edge_id)
定义 edge.cpp:6
半边网格中的面片。
定义 halfedge.h:150
const std::size_t id
定义 halfedge.h:160
Halfedge * halfedge
定义 halfedge.h:162
Eigen::Vector3f center() const
定义 face.cpp:29
Face(std::size_t face_id, bool is_boundary=false)
定义 face.cpp:8
Eigen::Vector3f area_weighted_normal()
定义 face.cpp:13
const bool is_boundary
边界面标识。
定义 halfedge.h:171
Eigen::Vector3f normal()
定义 face.cpp:24
在预览场景时绘制若干线条。
定义 gl.hpp:270
用于场景预览渲染的 Mesh 类。
定义 gl.hpp:220
在曲面简化算法中用到的工具类。
定义 halfedge.h:335
EdgeRecord(std::unordered_map< Vertex *, Eigen::Matrix4f > &vertex_quadrics, Edge *e)
Edge * edge
定义 halfedge.h:340
Eigen::Vector3f optimal_pos
定义 halfedge.h:342
float cost
定义 halfedge.h:344
半边网格中最关键的几何元素。
定义 halfedge.h:46
Edge * edge
定义 halfedge.h:72
Halfedge * prev
定义 halfedge.h:66
Halfedge * next
定义 halfedge.h:64
Vertex * from
定义 halfedge.h:70
bool is_boundary() const
这条半边是否属于一个虚拟的边界面。
定义 halfedge.cpp:22
Halfedge * inv
定义 halfedge.h:68
Halfedge(std::size_t halfedge_id)
定义 halfedge.cpp:5
Face * face
定义 halfedge.h:74
void set_neighbors(Halfedge *next, Halfedge *prev, Halfedge *inv, Vertex *from, Edge *edge, Face *face)
定义 halfedge.cpp:11
const std::size_t id
定义 halfedge.h:62
半边网格中的顶点。
定义 halfedge.h:85
Eigen::Vector3f new_pos
定义 halfedge.h:106
Eigen::Vector3f neighborhood_center() const
邻域 (1-ring neighborhood) 中所有顶点坐标的算数平均值。
定义 vertex.cpp:24
bool is_new
定义 halfedge.h:104
size_t degree() const
定义 vertex.cpp:10
Eigen::Vector3f normal() const
定义 vertex.cpp:37
const std::size_t id
定义 halfedge.h:98
Halfedge * halfedge
定义 halfedge.h:100
Eigen::Vector3f pos
定义 halfedge.h:102
Vertex(std::size_t vertex_id)
定义 vertex.cpp:6