【问题标题】:Sort a set of 3-D points in clockwise/counter-clockwise order按顺时针/逆时针顺序对一组 3-D 点进行排序
【发布时间】:2011-10-16 09:23:13
【问题描述】:

在 3-D 空间中,我有一个无序的集合,比如 6 个点;像这样:

           (A)*
                          (C)*
(E)*
                         (F)*
     (B)*

                  (D)*

这些点形成一个 3-D 轮廓,但它们是无序的。对于无序,我的意思是它们存储在

unorderedList = [A - B - C - D - E - F]

我只想从任意位置(假设 A 点)开始重新组织此列表,并顺时针或逆时针遍历这些点。像这样的:

orderedList = [A - E - B - D - F - C]

orderedList = [A - C - F - D - B - E]

我正在尝试实现一个尽可能简单的算法,因为提到的点集对应于大约 420000 个点的网格上每个顶点的 N 环邻域,我必须为每个点执行此操作在网格上。

前段时间有一个关于 2-D 点的 similar discussion,但现在我不清楚如何从这种方法转到我的 3-D 场景。

【问题讨论】:

    标签: algorithm sorting geometry mesh


    【解决方案1】:

    “顺时针”或“逆时针”的概念在没有轴和方向的情况下是不明确的! (证明:例如,如果您从显示器屏幕的另一侧查看这些点或翻转它们会怎样!)

    您必须定义轴和方向,并将其指定为附加输入。指定方式包括:

    • 一行 (1x=2y=3z),使用右手法则
    • 一个(单位)向量(A_x, A_y, A_z),使用右手定则;这是这样做的首选方式

    为了确定方向,您必须更深入地研究您的问题:您必须定义网格的“向上”和“向下”大小。然后对于每组点,您必须取质心(或另一个“内部”点)并构造一个指向“向上”的单位向量,该向量垂直于表面。 (一种方法是找到最小二乘拟合平面,然后找到通过该点的两个垂直向量,在“向上”方向选择一个。)


    您需要使用上述任何建议来确定您的坐标轴。这将允许您将问题重新表述如下:

    输入:

    • 点集 {P_i}
    • 一个轴,我们将其称为“z 轴”,并将其视为以点的质心(或“内部”某处)为中心的单位向量
    • 通过上述方法之一选择的方向(例如逆时针)

    设置:

    算法:

    一旦你有了角度,你就可以对它们进行排序。

    【讨论】:

    • 除了atan2 之外都很好,在平面上你应该使用矢量积比较点。
    • 使用atan2没有任何问题。不过,unkulunkulu 的建议很有趣!通常(P1 x P2) · Z 会给你一个不一致的排序,但如果你将它与正确的排序技术(如快速排序或基于枢轴的排序)结合起来,它就会起作用。这是因为一个圆圈上的叉积表示“顺时针还是逆时针更快到达那里?” 其他排序算法可能会失败。否则很难使用叉积;例如,如果您尝试按(X x P2) · Z 排序,sin 在 0deg-180deg 范围内不可逆!还必须像往常一样小心规范化。
    • ninjagecko,我认为您建议的方法(将 x、y、z 点投影到最合适的平面上)在我的情况下似乎足够了。但是我在想一个假设的问题:假设我的最佳拟合平面是 z=0(正常:0,0,1),并且我要投影的两个点共享相同的 x 和 y 坐标(仅不同在 z 坐标上)。在这种情况下,从 3-D 到 2-D 的投影看起来好像只有 1 个点!我对吗?我错过了什么吗?如果是这种情况如何克服这个问题?
    • @Miguel:对不起,我没有费心这么说。这相当于问“如果两个值相同,我应该在排序算法中做什么?”答案是他们是,你应该这样对待他们。如果这让您感到困扰,您可以随时选择不同的轴。在确定(0,1) 是 0 度还是 360 度时也会出现类似的问题;由于您陈述的问题的性质,这是任意的。就您而言,我预计这不会打扰您,因为您的积分可能是在当地社区“非重叠”生成的。
    【解决方案2】:

    我无法证明这段代码的效率,但它可以工作,你可以根据需要优化它的一部分,我只是不擅长。
    代码在 C# 中,使用系统集合类和 linq。
    Vector3 是一个具有浮点 x、y、z 和静态向量数学函数的类。
    Node 是一个带有 Vector3 变量的类,名为 pos

    //Sort nodes with positions in 3d space.
    //Assuming the points form a convex shape.
    //Assuming points are on a single plain (or close to it).
    
    public List<Node> sortVerticies( Vector3 normal, List<Node> nodes ) {
    
        Vector3 first = nodes[0].pos;
    
        //Sort by distance from random point to get 2 adjacent points.
        List<Node> temp = nodes.OrderBy(n => Vector3.Distance(n.pos, first ) ).ToList();
    
        //Create a vector from the 2 adjacent points,
        //this will be used to sort all points, except the first, by the angle to this vector.
        //Since the shape is convex, angle will not exceed 180 degrees, resulting in a proper sort.
        Vector3 refrenceVec = (temp[1].pos - first);
    
        //Sort by angle to reference, but we are still missing the first one.
        List<Node> results = temp.Skip(1).OrderBy(n => Vector3.Angle(refrenceVec,n.pos - first)).ToList();
    
        //insert the first one, at index 0.
        results.Insert(0,nodes[0]);
    
        //Now that it is sorted, we check if we got the direction right, if we didn't we reverse the list.
        //We compare the given normal and the cross product of the first 3 point.
        //If the magnitude of the sum of the normal and cross product is less than Sqrt(2) then then there is more than 90 between them.
        if ( (Vector3.Cross( results[1].pos-results[0].pos, results[2].pos - results[0].pos ).normalized + normal.normalized).magnitude < 1.414f ) {
            results.Reverse();
        }
    
        return results;
    }
    

    【讨论】:

      猜你喜欢
      • 2011-10-22
      • 1970-01-01
      • 2018-06-05
      • 2021-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-19
      • 2012-12-11
      相关资源
      最近更新 更多