【问题标题】:Sort a set of coplanar 3d points in a desired order按所需顺序对一组共面 3d 点进行排序
【发布时间】:2016-09-30 16:54:57
【问题描述】:

我有一组 3D 点,它们都位于同一个平面上。这些点只是文本文件中的“x y z”条目。 我想找到一种方法对这些点进行排序,以便我可以通过所有点绘制一个简单的多边形。我有几个想法:

想法 1: 选择一个已知位于由点集定义的多边形内的点,然后将射线绘制到该点集中的任意点。然后使用某种角度函数以按角度找到距离第一个最近的点,然后以此类推。这个想法的问题是我不知道如何找到一个保证在该区域内的点。我想使用质心,但并非所有这些集合都是凸的。它们可能看起来像以下两个图像中的任何一个:

正如您在第二张图片中看到的那样,质心可能不在多边形内,实际上如果拐角处的转折点太陡,那么我想到的角度函数也可能不起作用。

想法 2: 这似乎是可以根据旅行商问题之类的问题来解决的更容易的问题之一。但我知道解决 TSP 有很多不同的特定解决方案和近似值,我对从哪里开始有点生疏。

想法 3: 使用一个简单的距离函数,该函数将从任意点开始,找到最接近它的点,然后找到最接近 那个等等。这似乎是最容易做到的,但我想知道我是否没有预见到会出现任何问题。

对于解决此问题的最佳方法以及我是否忽略了更简单的方法,我将不胜感激。我正在用 C++ 进行编程,因此另一个好的答案将包括可以执行诸如查找 3d 质心或解决 TSP 等操作的库或函数。在此先感谢您的帮助。

【问题讨论】:

  • 您可以尝试“剪耳”算法来构建正确的多边形网格。

标签: c++ sorting 3d


【解决方案1】:

这是一个棘手的问题,如果您添加约束条件,即凹/凸间隙始终大于任意 2 个相邻点之间的最大距离

那么你应该:

  1. 为每个点添加 2 个索引

    我会使用这样的积分存储:

    struct point
     {
     float x,y,z; // point coordinates
     int i0,i1; // index to 2 closest neighbors
     int tmp; // temp for computation purposes 
     };
    point pnt[n]; // n is number of points you got
    

    并清除它们i0,i1=-1; 最好也添加临时变量,以便在后续处理期间为标志留出空间

  2. 寻找最近的邻居

    所以对于每个点都要遍历所有点并记住最接近它的 2 个点。将它们的索引设置为i0,i1。请注意这是O(n^2),除非您的点在空间上是有序的。我是这样看的:

    for (i=0;i<n;i++) pnt[i].tmp=0;
    for (i=0;i<n;i++)
     {
     i0=-1; l0=-1;
     i1=-1; l1=-1;
     for (j=0;j<n;j++)
      if (i!=j)
       {
       x=pnt[i].x-pnt[j].x; x*=x;
       y=pnt[i].y-pnt[j].y; y*=y;
       z=pnt[i].z-pnt[j].z; z*=z;
       l=x+y+z;
            if ((l0<0.0)||(l<=l0)) { i1=i0; l1=l0; i0=j; l0=l; }
       else if ((l1<0.0)||(l<=l1)) {               i1=j; l1=l; }
       }
     pnt[i].i0=i0; pnt[i0].tmp++;
     pnt[i].i1=i1; pnt[i1].tmp++;
     }
    

    现在 i0,i1&gt;=0temp==2 用于所有有效点。如果不是,所有点都应该是有效的,那么没有满足约束或者你错误地对点进行了分组(点的一侧是高密度,另一侧是低的,所以两个邻居都在一侧)

  3. 形成折线

    所以从您找到的第一个有效点开始,并将其用作折线/多边形的第一个点。然后看看使用它的i0 等等,直到你到达起点或无效i0。像这样的东西(假设所有点都是有效的):

     for (i0=0,i=0;;i++)
      {
      if (i<0) break; // not valid point
      // here add pnt[i] to polyline
      i=pnt[i].i0;
      if (i==i0) break; // end of polyline/polygon
      }
    

如果您也获得了无效点,那么您应该在剩余点(不包括已经有效的点)上递归执行此操作,并且还对距离使用一些最大限制,这样您就不会合并不属于彼此的点。在此之后,你应该得到几条折线,所以如果它们的端点很近,就加入它们......

为了改进#2,您可以添加相邻点方向不同但会影响锐利边缘的条件。

如果没有任何帮助,您可以使用凸包,然后删除与您的采样点(凹面部分)不对应的所有顶点并递归处理缺失的部分。最后将折线连接到单个多边形

【讨论】:

    猜你喜欢
    • 2018-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-31
    • 2011-10-22
    • 2011-10-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多