C++ 从'中查找唯一的顶点;三角汤';

C++ 从'中查找唯一的顶点;三角汤';,c++,algorithm,geometry,C++,Algorithm,Geometry,我正在两个库(Opencascade和DWF Toolkit)之上构建一个CAD文件转换器 然而,我的问题是平台不可知论的: 鉴于: 我已经生成了一个网格,作为通过我的应用程序构建的模型的三角形面列表。每个三角形通过三个顶点定义,这三个顶点由三个浮动(x、y和z坐标)组成。由于三角形形成网格,因此大多数顶点由多个三角形共享 目标: 我需要找到唯一顶点的列表,并生成由该列表中三个索引的元组组成的面数组 我想做的是: //step 1: build a list of unique vertices

我正在两个库(Opencascade和DWF Toolkit)之上构建一个CAD文件转换器

然而,我的问题是平台不可知论的:

鉴于:

我已经生成了一个网格,作为通过我的应用程序构建的模型的三角形面列表。每个三角形通过三个顶点定义,这三个顶点由三个浮动(x、y和z坐标)组成。由于三角形形成网格,因此大多数顶点由多个三角形共享

目标:

我需要找到唯一顶点的列表,并生成由该列表中三个索引的元组组成的面数组

我想做的是:

//step 1: build a list of unique vertices
for each triangle
   for each vertex in triangle
      if not vertex in listOfVertices
         Add vertex to listOfVertices

//step 2: build a list of faces 
for each triangle
   for each vertex in triangle
      Get Vertex Index From listOfvertices
      AddToMap(vertex Index, triangle)
虽然我有一个实现可以做到这一点,但步骤1(唯一顶点列表的生成)非常慢,顺序为O(n!),因为每个顶点都会与列表中已经存在的所有顶点进行比较。我想“嘿,让我们用std::map构建一个顶点组件的hashmap,这应该会加快速度!”,结果发现从三个浮点值生成一个唯一的键并不是一个简单的任务


在这里,stackoverflow的专家们开始发挥作用:我需要某种可以在3个浮点数上工作的哈希函数,或者任何其他从3d顶点位置生成唯一值的函数

三种解决方案。当然还有其他的

  • 使用哈希映射。只有当“相同”的意思完全相同时,这才有效
  • 使用二进制空间分区来分割点
  • 使用常规网格划分点

  • 在案例2和案例3中,如果要指定某个公差,则需要搜索树或网格的多个部分。在BSP的情况下,这意味着检查您是否在分割平面的公差范围内,如果在公差范围内,则返回到两部分。在网格情况下,这意味着检查公差范围内的所有相邻单元。这两种方法都不太难,但这意味着使用“现成”的解决方案会更加困难。

    获取散列的常见方法是将浮点的每个位模式乘以,然后将它们相加。诸如此类:

    unsigned int hash_point(float x, float y, float z)
    {
       unsigned int* px = (unsigned int*)&x;
       unsigned int* py = (unsigned int*)&y;
       unsigned int* pz = (unsigned int*)&z;
    
       return (*px)*PRIME1 + (*py)*PRIME2 + (*pz)*PRIME3;
    }
    

    您应该注意到sizeof(unsigned int)在这里被认为等于sizeof(float)。这里的示例只是为了说明主要思想,您应该根据需要调整它。

    转储数组中的所有顶点,然后执行
    唯一(排序(数组))
    。这应该是O(kn log(n)),其中k是共享一个顶点的三角形的平均数量,通常我花了一点时间来了解空间分区如何帮助我-这是一种有趣的方法+1我还制作了一个隐式空间索引,其中包含两个坐标多重贴图,一个在X,一个在Y,这很稳健,但O(n lg n)缩放在最大的问题(数百万个顶点)上对我没有帮助。我想我要试试八叉树或某种空间索引,比如莫顿索引。奇怪的是,我又在做类似的事情了。我在2D-4D中使用最近邻搜索。输入值为10秒数百万点。KD树(二进制空间分区)实现为一个线性堆,每个叶节点中大约有16个顶点,每个核心每秒大约有10K个查询。构建时间只有几秒钟,但我认为在这种情况下,您实际上可以将搜索和构建结合起来。这个顶点唯一性必须有多强大?我的意思是,你只是想节省空间,还是需要非常健壮的拓扑结构。假设vertex Va和Vb获得不同的ID pn和pq,但实际上是“相同”的,这是否是一个交易破坏者?是的,这是因为我正在尝试导出拓扑的网格。如果源中的一个顶点在目标中多次存在,则从源中构造的三角形将不会共享边-拓扑可能会打开。当x、y和z不是整数时,将它们乘以素数不会有多大帮助。正确。你应该乘浮点数的位模式,而不是浮点数本身。请注意,有些数字有多个位模式表示,如0和-0是相同的,但有不同的位模式。这意味着它们将散列到不同的值。不过,这对您的应用程序来说可能是个问题,也可能不是。我见过(例如)用XOR来完成,而不是添加术语。这样做效率更高。(我的第一次进近为35秒,改进后的进近为1.5秒)如果你想抓住彼此之间的临界距离内的点,这里面有一个严重的错误。不能保证靠得很近的点彼此“排序”。事实上,我认为你可以证明,对于任何排序函数,都有任意靠近的点,排序到列表中的遥远位置。。。不好。@Michael:那就继续证明吧,如果你只是需要一个简单天真的例子的话。考虑到2D点的数组是按照常规排序返回{[1,1],[1,10],[1.000,1,1] }的顺序,[[1.000,1,1] ]比[1,1]更接近[1,1]。但由于列表中的分隔,unique将错过它。(如果你真的想证明任意排序函数的一般情况,我可能会构造一个,但它会很复杂——你可能需要数学学位才能理解它。)使用散列(用于此相等条件检查),而不是数组,当然也不是链表。
    distance(vertex1, vertex2) < threshold