HalfEdge半边数据结构详解

news2024/9/24 17:21:15

我们可以将离散表面表示为多边形网格。 多边形网格可以被认为是图(具有顶点和顶点之间的边)加上面列表,其中面是边的环。
在这里插入图片描述

推荐: 使用 NSDT场景设计器 快速搭建 3D场景。

下面,我们将网格指定为顶点列表和面列表,其中每个面都指定为顶点环。 网格的边是隐含的——边连接面的相邻顶点。
在这里插入图片描述

由于不含冗余信息,面列表表示在磁盘存储中很受欢迎,但是很难编写直接在这种表示上运行的算法。 例如,判断v6和v3是否连接,我们必须遍历面列表,直到找到(或找不到)我们正在寻找的边。

可以在恒定时间内回答此类查询的流行数据结构是半边( HalfEdge)数据结构。 在半边数据结构中,我们通过用一对有向半边孪生表示每条边来显式存储网格的边,两个半边孪生中的每一个都指向相反的方向。 半边存储对其孪生的引用,以及对沿同一面或孔的前一个和下一个半边的引用。 顶点存储其位置和对源自该顶点的任意半边的引用,而面存储属于该面的任意半边。 半边数据结构存储顶点、面和半边记录的数组。
在这里插入图片描述

上图为半边 h 及其孪生、下一个和前一个半边的可视化。 h 还存储对其原始顶点和入射面的引用。

为了表示边界边缘(与孔相邻的边),我们有两种选择。 我们可以用双指针为空的单个半边表示边界边,或者我们可以将边界边表示为一对半边,与孔相邻的半边具有空面指针。 事实证明,后一种设计选择导致更简单的代码,因为我们很快就会看到获得半边的孪生是比获得半边的面更常见的操作,并且能够简单地假设我们有一个非空孪生导致的特殊情况要少得多。

下面我们展示了一个更复杂的网格的半边图和记录表,要表示的网格如下图所示:
在这里插入图片描述

可以在编辑器中编辑网格顶点和连接:

# Enter your mesh definition in OBJ format below...
v 1.0 4.0 0.0
v 3.0 4.0 0.0
v 0.0 2.0 0.0
v 2.0 2.0 0.0
v 4.0 2.0 0.0
v 1.0 0.0 0.0
v 3.0 0.0 0.0
f 1 3 4
f 1 4 2
f 2 4 5
f 3 6 4
f 4 6 7
f 4 7 5

对应的记录参见原文。

遍历面的顶点/边

有时我们需要遍历一个面以获得它的所有顶点或半边。 例如,如果我们想计算一个面的质心,我们必须找到面的所有顶点的位置。

在代码中,给定面 f,这看起来像这样:

start_he = f.halfedge
he = start_he
do {
    # do something useful

    he = he.next
} while he != start_he

请注意,我们使用 do-while 循环而不是 while 循环,因为我们想在循环迭代结束时检查条件。 在第一次迭代开始时, he == start_he,因此如果我们在循环开始时检查条件,我们的循环将不会运行任何迭代。
在这里插入图片描述

要以相反的方向遍历面,可以简单地将 he.next 替换为 he.prev。

围绕一个顶点进行遍历

前面我们描述了如何构造面迭代器。 另一个有用的迭代器是顶点迭代器。 通常,我们想要围绕一个顶点迭代顶点环(也称为顶点伞)。 更具体地说,我们想要遍历所有以给定顶点为原点的半边。

在本文中我们将假定面的顶点顺序为逆时针(这是 OpenGL 中的默认设置)。

给定顶点 v,以逆时针顺序遍历所有从 v 出来的半边,代码如下所示:

start_he = v.halfedge
he = start_he
do {
    # do something useful

    he = he.prev.twin
} while he != start_he

在这里插入图片描述

请注意,即使存在边界半边或非三角形面,我们的代码仍然有效。

以顺时针顺序遍历顶点环与以逆时针顺序遍历环非常相似,只是我们将 he = he.prev.twin 替换为 he = he.twin.next。

修改半边数据结构

前面我们讨论了如何迭代面和顶点环。 修改半边数据结构比较棘手,因为如果记录修改不当,引用很容易变得不一致。

作为练习,我们将介绍如何实现 EdgeFlip 算法,给定两个三角形面中间的半边,翻转半边及其孪生的方向。
在这里插入图片描述

我们将在算法的每一步显示记录表。

我们从突出显示的输入半边开始(下面网格中的 e3 或 e2,但假设是 e3)。
在这里插入图片描述

我们首先获取所有受影响的半边的引用,因为在网格处于不一致状态时遍历网格将很困难。

def FlipEdge(HalfEdge e):
    e5 = e.prev
    e4 = e.next
    twin = e.twin
    e1 = twin.prev
    e0 = twin.next

接下来,我们确保没有对 e 或 twin(图中的 e3 和 e2)的面或顶点引用,我们将在执行边翻转的过程中回收它们。

    for he in {e0, e1, e4, e5}:
        he.origin.halfedge = &he
    e1.face.halfedge = &e1
    e5.face.halfedge = &e5

这些操作是安全的,因为代表性半边的选择是任意的; 网格仍处于一致状态。 受影响的单元格颜色为浅蓝色,但并非所有单元格都更改为与其旧值不同的值。
在这里插入图片描述

接下来我们回收e和twin。 我们将(任意地)让 e 成为图中的顶部对角线半边,并且 twin 成为它的孪生。 我们可以按照下图填写e和twin的成员。 在此之后,我们的数据结构将变得不一致。 我们用红色勾勒出不一致的单元。

    e.next = &e5
    e.prev = &e0
    e.origin = e1.origin
    e.face = e5.face
    twin.next = &e1
    twin.prev = &e4
    twin.origin = e5.origin
    twin.face = e1.face

在这里插入图片描述

我们更新受影响的下一个和上一个参考。 同样,我们可以参考图表来填写这些值。

    e0.next = &e
    e1.next = &e4
    e4.next = &twin
    e5.next = &e0
    e0.prev = &e5
    e1.prev = &twin
    e4.prev = &e1
    e5.prev = &e

原文链接:HalfEdge数据结构详解 — BimAnt

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/187699.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【博学谷学习记录】大数据课程-学习第四周总结

分布式技术 为什么需要分布式 计算问题 无论是我们在学校刚开始学编程,还是在刚参加工作开始处理实际问题,写出来的程序都是很简单的。因为面对的问题很简单。以处理数据为例,可能只是把一个几十K的文件解析下,然后生成一个词频…

Python正则表达式所有函数详解

文章目录1 fullmatch2 match3 search4 findall5 finditer6 split7 sub8 compile本篇博客主要讲解正则表达式相关的函数,均不涉及复杂的正则表达式语法。如需了解正则表达式语法,请参考下面的文章:Python正则表达式语法详解1 fullmatch Pytho…

96. BERT预训练代码

利用实现的BERT模型和从WikiText-2数据集生成的预训练样本,我们将在本节中在WikiText-2数据集上对BERT进行预训练。 import torch from torch import nn from d2l import torch as d2l首先,我们加载WikiText-2数据集作为小批量的预训练样本,…

Logstash:如何使用 Logstash 解析并摄入 JSON 数据到 Elasticsearch

在我之前的文章 “Logstash:Data 转换,分析,提取,丰富及核心操作” 有涉及到这个话题。今天我想使用一个具体的例子来更深入地展示。 准备数据 我们先来把如下的数据拷贝下来,并保存到一个叫做 sample.json 的文件中。…

OS 学习笔记(5) 操作系统的体系结构

OS 学习笔记(5) 操作系统的体系结构 王道OS 1.4 操作系统的体系结构 文章目录OS 学习笔记(5) 操作系统的体系结构知识总览分层结构模块化操作系统的内核大内核 vs 微内核知识回顾与重要考点外核王道chap1 回顾英文表达、术语积累(《操作系统概念》第九版、ostep 《O…

电子模块|心率血氧传感器模块MAX30102及其驱动代码

电子模块|心率血氧传感器模块MAX30102及其驱动代码实物照片模块简介工作原理原理图及引脚说明STM32软件驱动IIC通信代码数值转换代码main函数结果实物照片 模块简介 MAX30102是一个集成的脉搏血氧仪和心率监测仪生物传感器的模块。 它集成了一个红光LED和一个红外光LED、光电…

【经济学】MIT 微观经济学 Microeconomoics

MIT 微观经济学P1 Introduction and Supply & Demand约束优化和机会成本供给和需求P1 Introduction and Supply & Demand 约束优化和机会成本 微观经济学是研究如何个人和公司做决定在一个稀缺的世界。稀缺性是微观经济的驱动力。 微观经济学是一系列约束优化练习&a…

Hadoop安全之Kerberos

简介 安全无小事,我们常常要为了预防安全问题而付出大量的代价。虽然小区楼道里面的灭火器、消防栓常年没人用,但是我们还是要准备着。我们之所以愿意为了这些小概率事件而付出巨大的成本,是因为安全问题一旦发生,很多时候我们将…

自学数据分析——数据分析方法和模型

一、数据分析方法 数据分析的思维需要培养,先模仿别人,从模仿者到创造者。首先需要建立数据的敏感性,能快速了解数据在说什么,下面我们以抖音教育直播为例,首先来了解核心指标,以及各个指标所表示的含义。…

17.Stream流

目录 一.Stream流 1.1 什么是Stream流 1.2 Stream流思想 1.3 Stream流的三类方法 1.4 获取Stream流 1.4.1 集合获取Stream流的方式 1.4.2 数组获取Stream流的方式 1.5 中间方法 1.6 终结方法 1.7 收集Stream流 1.7.1 什么是收集Stream流 1.7.2 收集方法 一.Stream流…

Ant Design Vue 之a-tree-select

Ant Design Vue 是比较流行的vue框架之一&#xff0c;主要是展示a-tree-select 的简单用法&#xff0c;a-tree-select组件主要用于展示树结构的选择。 <template><a-spin :spinning"confirmLoading"><a-form :form"form"><a-form-ite…

CnOpenDataA股上市公司社会责任报告数据

一、数据简介 A股上市公司社会责任报告数据由和讯网自2013年开始独家策划的产品&#xff0c;也是国内首家上市公司社会责任专业测评产品。上市公司社会责任报告专业测评体系从股东责任、员工责任、供应商、客户和消费者权益责任、环境责任和社会责任五项考察&#xff0c;各项分…

Linux Workqueue

Linux Workqueue 1、前言 Workqueue 是内核里面很重要的一个机制&#xff0c;特别是内核驱动&#xff0c;一般的小型任务 (work) 都不会自己起一个线程来处理&#xff0c;而是扔到 Workqueue 中处理。Workqueue 的主要工作就是用进程上下文来处理内核中大量的小任务。 所以 …

基于php的旅游管理系统

摘要随着计算机技术&#xff0c;网络技术的迅猛发展&#xff0c;Internet 的不断普及&#xff0c;网络在各个领域里发挥了越来越重要的作用。特别是随着近年人民生活水平不断提高&#xff0c;在线旅游给人们的旅游业带来了更大的发展机遇。在经济快速发展的带动下&#xff0c;旅…

【Linux】tar命令打包 | 查看压缩文件 | 打包时忽略文件

tar命令打包 | 查看压缩文件 | 打包时忽略文件 等操作 1.起因 今天下午写阿狸bot的代码的时候&#xff0c;写错了aiofiles的保存操作 # 正确写法 async def write_file_aio(path:str, value):async with aiofiles.open(path, w, encodingutf-8) as f:await f.write(json.dump…

MyBatis持久层框架详细解读:核心配置文件

文章目录1. 前言2. 多环境配置3. 类型别名4. 对象工厂5. 总结1. 前言 前面我们在使用 MyBatis 开发时&#xff0c;编写核心配置文件替换 JDBC 中的连接信息&#xff0c;解决了 JDBC 硬编码的问题。其实&#xff0c;MyBatis 核心配置文件中还可以配置很多的内容。 MyBatis 的配…

mongodb分片

分片是MongoDB的扩展方式,通过分片能够增加更多的机器来用对不断增加的负载和数据,还不影响应用.1.分片简介分片是指将数据拆分,将其分散存在不同机器上的过程.有时也叫分区.将数据分散在不同的机器上,不需要功能强大的大型计算机就可以存储更多的数据,处理更大的负载.使用几乎…

屏幕录制下载推荐(可以无水印录制视频)

您有没有遇到过这种情况&#xff0c;在使用录屏工具录制电脑屏幕时&#xff0c;录制出来的视频是带有明显水印的。那有没有可以无水印录制的屏幕录制推荐呢&#xff1f;当然有。最近小编发现了一款可以无水印&#xff08;自定义图文水印&#xff09;录制的视频&#xff0c;快来…

Pycharm误触ignore的解决方法--有图

步骤1&#xff1a;进入pycharm编辑器之后&#xff0c;找到菜单栏中的file选项&#xff0c;点击之后会有一个下拉列表&#xff0c;直接选择settings&#xff0c;进入到设置的窗口。步骤2&#xff1a;在设置界面的左侧&#xff0c;找到Inspections选项&#xff0c;点击之后&#…

JavaScript 练手小技巧:拖拽事件、把图片拖拽入页面

HTML5 新增了拖拽事件 drag&#xff0c;利用它可以实现把外部文件拖拽入页面中&#xff0c;可以实现文件的读取&#xff0c;上传等等功能。 拖拽&#xff0c;又叫拖拉、拖动&#xff0c;英文为 drag。 拖拽事件是 HTML5 新增的事件操作。 拖拽指的是&#xff0c;用户在某个对…