我有一组三维点,都在同一个平面上。这些要点只是" x y z"文本文件中的条目。 我想找到一种方法来对这些点进行排序,以便我可以通过所有点绘制一个简单的多边形。我有几个想法:
想法1:选择一个已知位于由该组点定义的多边形内的点,并将光线绘制到该集合中的任意点。然后使用某种角度函数找到最接近的点按角度到第一个点,然后依此类推。这个想法的问题在于我不知道如何找到一个保证在该区域内的点。我想使用质心,但并非所有这些都是凸的。它们可能看起来像以下两个图像之一:
正如你在第二张图片中看到的那样,质心可能不在多边形内,实际上如果拐角处的转折点太陡,那么我想到的角度函数也可能不起作用。
想法2:这似乎是根据旅行推销员问题可以解决的更容易解决的问题之一。但是我知道解决TSP有很多不同的特殊解决方案和近似值,我对从哪里开始有点生疏。
想法3:使用一个简单的距离函数,该函数以任意点开始并找到最接近它的点,然后找到最接近那等等。这似乎是最容易做到的事情,但我想知道我是否不会怀疑任何出现的问题。
我很感激任何关于解决这个问题的最佳方法的输入,以及我是否忽略了一个更简单的方法。我用C ++编程,所以另一个好的答案将包括可以执行诸如查找3d质心或解决TSP等问题的库或函数。提前感谢您的帮助。
答案 0 :(得分:0)
这是一个棘手的问题如果你添加约束,凹/凸间隙总是更大,那么任何2个相邻点之间的最大距离
然后你应该:
为每个点添加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个最接近的点。将其索引设置为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>=0
和temp==2
。所有的点应该是有效的,如果没有那么约束没有得到满足,或者你错误地对点进行分组(点的一侧是高密度,另一侧是低,所以两个邻居都在一边)
形成折线
所以从您找到的第一个有效点开始,并将其用作折线/多边形的第一个点。然后查看使用其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 ,您可以添加相邻方向不相似但可能影响锐边的条件。
如果没有任何帮助,您可以使用凸包,然后删除与您的采样点(凹陷部分)不对应的所有顶点,并递归地执行缺少的部分。最后将折线连接到单个多边形