VCG文档 - 邻接与拓扑(Adjacency and Topology)

2023-10-11 01:40

本文主要是介绍VCG文档 - 邻接与拓扑(Adjacency and Topology),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

邻接关系

VCG 库没有单一的,硬编码的方式来对三角形和边之间的关系进行编码. 这一切都取决于存储哪些属性以及如何使用它们. 在前面几节的例子中, 面的定义总是包含 vcg::face::VertexRef 属性, 这个属性存储了可以使用函数 V() 访问的指向MyVertex 的指针. 目前 VCG 中实现的几乎所有算法都假定 vcg::face::VertexRef 存在. 所以, 如果你的定义不包含 vcg::face::VertexRef 属性, 虽然这是正确的, 但几乎没有算法能正常运行.

还有其他的邻接关系可以用来遍历曲面, 例如遍历顶点的1- 邻域. VCG 库主要有两种邻接关系: 面-面(FF)和顶点-面(VF)邻接. 下面会对它们进行详细的介绍.

面-面邻接关系 (FF Adjacency)

vcg::face::FFAdj 属性声明了面-面邻接关系, 它通过面的公用边来编码这个邻接关系. 下图说明了用于索引两个三角面片的顶点和边的约定.

三角形的顶点按逆时针方向标记0,1,2. 边 i( 0,1,2) 就是 顶点 i和 i+1 之间的边.因此 ,在下图中, 面 f0,f1 之间的连接边就是 f0 的边 0 和 f1 的边 1.

Indexing of vertexes and edges

对于面 f 的第 i 个边, vcg::face::FFAdj 属性存储了

  • FFp(i): 指向公用面 f的第 i 个边的面的指针, 如果该边是边界, 那么就指向 f 自己.
  • FFi(i): f 的第 i 个边在指向的邻接面中的索引.

对于上面的例子, 假定 f0,f1 都是指针,那么就有下面的对应关系:

f1->FFp(1) == f0
f1->FFi(1) == 0f0->FFp(0) == f1
f0->FFi(0) == 1

请注意, 准确的说, 应当是 FFp(i) 指向一个邻接面, 而不是指向那个邻接面. (原文: FFp(i) points to a adjacent face, not to the adjacent face ). 原因就是在有非流形边的情况下, 有可能有多个面共用一条边, 这种情况 VCG 是无缝支持的. 下图展示了4 个面使用同一条边.

Non manifold edge

在这种情况下,FF邻接被构成了循环列表(不一定按照二面角进行排序). VCG 库是通过vcg::tri::UpdateTopology::FaceFace(MeshType &m) 函数来更新的. 这种情况下,VCG 提供了一种方法来检查一条边是否是流形边, 因为邻接关系是相互的. 例如, 如果是流形边的话, f0 指向 f1 , 同时 f1 又将指向 f0 .

bool IsManifold(MyFace *f,int e) { return (f0 == f0->FFp(0)->FFp(f0->FFi(0)))}
Pos

Pos 是 VCG Lib 对 Cell-Tuple{ref} 的实现. 简单起见, 这里给出一个尽可能简短的定义. 在三角网格中, Pos
vectex: pos = (v,e,f) 构成的三元组, e 是以 v 为起点并且属于面 f 的边. 下图使用指向一个顶点,靠在一条边并且属于一个面的小三角形展示 了几个 Pos . 例如 , c0 = (v, e0 ,f).

Pos Example

这里有一个非常好的性质, 给定一个 Pos c, 若仅改变 c 中的一个元素, 那就能唯一的得到 c 的一个邻域.

我们称从一个 Pos c 到它的一个邻域 Pos c' 的操作为 Flip. FlipV,FlipE, FlipF 表明操作的元素是Pos c 的顶点,边或者面.

例如, 考虑 c1 , 和 c2 只有顶点不同.可以写作 c2=FlipV(c1) .

下面有更多的例子对此进行解释.

c2 = FlipV(c1)
c0 = FlipE(c1)
c3 = FlipF(c0)CCW around v
c4 = FlipE(FlipF(c0))
c5 = FlipE(FlipF(c4))
Bounce
c6 = FlipE(FlipF(c5))
CW around v
c3 = FlipE(FlipF(c6))
c1 = FlipE(FlipF(c3))
Bounce
c0 = FlipE(FlipF(c1))

注意, 复合两个 Flip 操作, FlipF,FlipE, 我们得到了从一个Pos 到下一个(逆时针或者顺时针)Pos 的变换, 方向取决于开始Pos 相对于顶点是否位于面的逆时针边上. 也要注意, 由于 FF 邻接的定义, 当一个 Pos
在边界上时, 它将反转回来. 这一对 Flip 操作在VCG库中被广泛的使用, 例如遍历一个顶点的 1- 邻域.

下面的例子展示了这种使用:

sf/apps/sample/trimesh_pos_demo/trimesh_pos_demo.cpp#include <vcg/simplex/face/pos.h> // include the definition of pos...includes to define your mesh typeclass MyVertex: ...
class MyFace: public vcg::FaceSimp2<MyVertex,MyEdge,MyFace, vcg::face::VertexRef, vcg::face::FFAdj>{};void OneRingNeighborhood( MyFace * f)
{MyVertex * v = f->V(0);MyFace* start = f;vcg::face::Pos<MyFace> p(f,0,v);// constructor that takes face, edge and vertexdo{p.FlipF();p.FlipE();}while(p.f!=start);
}
  • 我们任意选择了一个作为旋转中心的顶点f->V(0). 通常来说是会选定一个已知的顶点. 可以通过使用vcg::vectex::VFAjd 属性来知道一个顶点和哪些面邻接. 更多介绍参考下面的 VF 邻接. 当顶点在边界上时这个操作就不会工作了. 看下面的例子, 从 c4 开始操作,可以一次找到 c5,c6,c3 , 这又回到了 c4 所在的面.当然,如果你使用Pos 本身作为一个警戒的条件, 这种情况就可以避免. 即使那样, 你将得到一个序列: c5,c6,c3,c1,c0,c4 对应着面 f2,f2,f1,f0,f0,f1 , 但这并不是你想要的. VCG 提供了另外一种变化的 Pos 来解决这个问题.
Jumping Pos

Jumping Pos 和 Pos 几乎完全相同, 只是它遇到边界时不会反转. 相反的, 它跳跃到共用顶点的边界面(图中的 f0,f2 ).

sf/apps/sample/trimesh_pos_demo/trimesh_pos_demo.cpp#include <vcg/simplex/face/jumping_pos.h> // include the definition of jumping pos//...includes to define your mesh type//class MyVertex: ...class MyFace: public vcg::FaceSimp2<MyVertex,MyEdge,MyFace, vcg::face::VertexRef,vcg::face::FFAdj>{};void OneRingNeighborhoodJP( MyFace * f){MyVertex * v = f->V(0);MyFace* start = f;vcg::face::JumpingPos<MyFace> p(f,0,v);// constructor that takes face, edge and vertexdo{p.NextFE();}while(p.f!=start);}

VF Adjacency

VCG Lib 实现了顶点-面的邻接关系. 例如, 给定一个顶点 v, 可以检索到包含顶点v 的所有面. 令 v=(f0,f1,,fk) 是与顶点v 邻接的面的集合. VCG Lib 可以以最优的时间 (O( v )) 访问 v , 这个访问使用下面的属性:

  • vcg::vertex::VFAjd 顶点属性, 包含了指向面的指针.
  • vcg::face::VFAjd 面属性, 包含了指向集合 v 中下一个面的每个顶点的指针.

这两个属性不仅是一个指针, 它们也包含了类似 vcg::face::FFAdj 的索引. 下图给出了一个练习的示例: 类似 FF 邻接关系, 你需要使用 vcg::tri::UpdateTopology::VertexFace(MeshType &m).

Example of vertex-face adjacency

v.VFp() == f2
v.VFi() == 0f2->VFp(0) == f3
f2->VFi(0) == 1
f3->VFp(1) == f1
f3->VFi(1) == 2
f1->VFp(2) == f0
f1->VFi(2) == 2
f0->VFp(2) == NULL
f0->VFi(2) == -1
VFIterator

VFIterator 是一个用于遍历顶点的邻接面的迭代器(类似于 FF 邻接关系中的 Pos). 下面的代码展示了如何使用它:

sf/apps/sample/trimesh_pos_demo/trimesh_vfiter_demo.cpp
#include <vcg/simplex/face/pos.h> // include the definition of  VFIterator
//...includes to define your mesh type
class MyVertex: public vcg::VertexSimp2<MyVertex,MyEdge,MyFace, vcg::vertex::VFAdj /*,... other attributes*/ >{};
class MyFace: public vcg::FaceSimp2<MyVertex,MyEdge,MyFace, vcg::face::VertexRef,vcg::face::VFAd>{};
void OneRingNeighborhoodVF( MyVertex * v)
{vcg::face::VFIterator<MyFace> vfi(v); //initialize the iterator tohe first facefor(;!vfi.End();++vfi){MyFace* f = vfi.F();// ...do something with face f}
}
Starts and Rings
vcg::face::VFOrderedStarFF
vcg::face::VVStarVF
vcg::face::VFStarVF
vcg::face::VFExtendedStarVF
vcg::face::EFStarFF
Few facts on FF adjacency and VF adjacency

在这里,我们提供一系列简单的描述来解除疑惑,并帮助选择最符合您需求的邻接关系.

如果曲面是流形的,那么使用 Pos 计算顶点的1-邻域和使用VFIterator 计算将是一致的.
如果使用 Pos,遍历面的顺序可能是顺时针或者逆时针的,使用 VFIterator 则未指明顺序. 如果曲面是非流形曲面, 那么无论使用哪种方式都有可能无法遍历所有面.

Boundary relations and adjacency

在许多算法中都需要面的边界条件. 例如, 知道给定的面的一条边是否有一个或多个邻接的面. FF邻接关系时, 使用 face::IsBorder(f,e) 静态函数可以简单判断 f 的边 e 存储的指针是否指向f自己.如果使用Pos , 那么 Pos的成员函数 IsBorder() 可以给出当前的边界状态. 类似的,可以使用 face::IsManifold(f,e)IsManifold(e) 来检测是否是流形边.

如果没有使用 FF 邻接关系, 那么判断边界条件将效率低下. VCG 提供了一种技术将边界状态提供给面和顶点的 Flags. 使用UpdateFlags 函数计算反应当前状态的 Flags , 使用 IsB(e) 函数来访问它. 谨记如果你改变了网格的拓扑关系将会导致边界信息不可用.另一方面, 许多不改变网格的算法仅要求边界信息而不要求FF邻接关系.

这篇关于VCG文档 - 邻接与拓扑(Adjacency and Topology)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/184596

相关文章

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

hdu 1285(拓扑排序)

题意: 给各个队间的胜负关系,让排名次,名词相同按从小到大排。 解析: 拓扑排序是应用于有向无回路图(Direct Acyclic Graph,简称DAG)上的一种排序方式,对一个有向无回路图进行拓扑排序后,所有的顶点形成一个序列,对所有边(u,v),满足u 在v 的前面。该序列说明了顶点表示的事件或状态发生的整体顺序。比较经典的是在工程活动上,某些工程完成后,另一些工程才能继续,此时

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

Python脚本:TXT文档行数统计

count = 0 #计数变量file_dirs = input('请输入您要统计的文件根路径:')filename = open(file_dirs,'r') #以只读方式打开文件file_contents = filename.read() #读取文档内容到file_contentsfor file_content in file_contents:

bcolz文档

原文:http://bcolz.blosc.org/en/latest/reference.html First level variables bcolz.__version__'''bcolz包的版本。''' bcolz.dask_here'''是否检测到dask的最低版本。''' bcolz.min_dask_version'''需要dask的最低版本(dask是可选

WordPress开发中常用的工具或api文档

http://php.net/ http://httpd.apache.org/ https://wordpress.org/ https://cn.wordpress.org/ https://core.svn.wordpress.org/ zh-cn:开发者文档: https://codex.wordpress.org/zh-cn:%E5%BC%80%E5%8F%91%E8%80%

Python知识点:使用Python进行PDF文档处理

使用 Python 进行 PDF 文档处理可以通过多种库来实现,包括 PyPDF2、pdfplumber、reportlab、pdfminer 等。这些库可以处理不同的 PDF 任务,例如 提取文本、拆分合并 PDF、修改 PDF、生成 PDF 等。以下是几种常见操作及对应的库和代码示例。 1. 安装常用库 首先,安装常用的 PDF 处理库: pip install PyPDF2 pdfpl

【2025】基于Python的空气质量综合分析系统的设计与实现(源码+文档+调试+答疑)

博主介绍:     ✌我是阿龙,一名专注于Java技术领域的程序员,全网拥有10W+粉丝。作为CSDN特邀作者、博客专家、新星计划导师,我在计算机毕业设计开发方面积累了丰富的经验。同时,我也是掘金、华为云、阿里云、InfoQ等平台的优质作者。通过长期分享和实战指导,我致力于帮助更多学生完成毕业项目和技术提升。 技术范围:     我熟悉的技术领域涵盖SpringBoot、Vue、SSM、HLMT

自动化表格处理的革命:智能文档系统技术解析

在当今数据驱动的商业环境中,表格数据的自动化处理成为了企业提高效率、降低成本的关键。企业智能文档系统在智能表格识别方面展现出卓越的性能,通过精准识别和处理各种通用表格,显著提升了企业文档管理的智能化水平。本文将深入探讨该系统在表格识别方面的关键技术和应用优势,以及如何通过行业定制化服务满足不同行业的需求。 1. 通用表格识别 智能文档系统通过先进的OCR技术和表格结构识别算法,能够精准

MongoDB学习—(4)文档的插入,删除与更新

一,文档的插入 插入命令有两个一个为insert,另一个为save,两者的区别为 db.[documentName].insert({..})插入的数据不允许重复,即_id不可相同 db.[docuemntName].save({..})插入的数据允许重复,如果整条数据内容相同,则不发生替换,如果数据有做不同,则将原数据替换 二,删除文档数据 db.[docuementName].r