按顺时针顺序对点数组进行排序


16

有没有一种算法可以按顺时针顺序对2D点数组进行排序?
在我的情况下,我专门处理直角三角形,所以只有3分。

但是我有兴趣知道是否存在这样的算法,如果不存在,那么按顺时针方向返回三角形的3个点的简单方法是什么?

编辑:我正在尝试相对于多边形的质心顺时针计算点,它是凸的。

更新: 这是我根据选择的答案最终使用的实现,它对性能没有要求,只是偶尔发生一次,因此可以解决。

ArrayList<PVector> pointList = new ArrayList<PVector>();
pointList.add(A);
pointList.add(B);
pointList.add(C);
Collections.sort( pointList, new TriangleVectorComparator(origin) );

return pointList;

// Comparator
package triangleeditor;

import java.util.Comparator;

import processing.core.PVector;

public class TriangleVectorComparator implements Comparator<PVector>  {
    private PVector M; 
    public TriangleVectorComparator(PVector origin) {
        M = origin;
    }

    public int compare(PVector o1, PVector o2) {
        double angle1 = Math.atan2(o1.y - M.y, o1.x - M.x);
        double angle2 = Math.atan2(o2.y - M.y, o2.x - M.x);

        //For counter-clockwise, just reverse the signs of the return values
        if(angle1 < angle2) return 1;
        else if (angle2 < angle1) return -1;
        return 0;
    }

}

1
return可以是return angle1 <angle2吗?1:角度2>角度1?-1:0;
ademar111190 2014年

2
它可以用多种方式表示,但是我倾向于避免嵌套三元运算符,特别是在举例子时。
onedayitwillmake 2014年

@onedayitwillmake您能否将最终使用的代码移到答案中?它并不是真正的问题,但对将来的读者来说非常有价值。
Anko 2015年

@Anko我认为您是对的,但与此同时,我认为人们最容易以这种方式找到它。这也有助于确保我不会忽略samhocevar的答案,而这只是我的依据。
onedayitwillmake 2015年

Answers:


19

您的问题不够精确。点阵列仅相对于参考点“顺时针”或“逆时针”。否则,任何三点数组都可以始终为CW或CCW。参见下图:在左侧,各点按顺时针方向排列;在右边,相同的点按逆时针方向排序。

顺时针或逆时针

对于您的情况,我认为将这些点的重心用作参考点是合理的。

未知数量点的一种好的方法是:

  • P[0], P[1], ... P[n-1]被点到排序列表
  • 令M为所有点的重心
  • 计算 a[0], a[1], ... a[n-1]这样a[i] = atan2(P[i].y - M.y, P[i].x - M.x);
  • 例如a,使用相对于其值的排序点qsort

但是,可以肯定的是,与即席方法相比,良好的排序算法在三个输入值的情况下效果较差。使用atan2仍然有效,但不要使用qsort


这非常有效:)
onedayitwillmake 2011年

1
这个方法有名字吗?
onedayitwillmake 2011年

1
我相信这就是所谓的“按极角排序”。例如,它是Graham Scan的组成部分。
sam hocevar 2011年

qsort与相比,这里的性能影响很小atan2

小警告:如果有任何一点恰好位于重心(或您使用的任何其他定向点),则可能会崩溃和烧毁(取决于所使用的编程语言和库)。您可能希望在第二步和第三步之间排除这些点。
Martin Sojka 2012年

3

我相信您实际上要问的是三角形的缠绕顺序,实际上这很容易测试。

由于三角形中只有三个点,因此三角形已经按顺时针或逆时针顺序排列,因此您要做的就是检查这两个三角形中的哪一个,如果绕线,则颠倒索引的顺序不是您想要的那个。

假设三角形的三个顶点分别是abc,并且您有一个简单的矢量减法运算,这是一般的想法:

Vector2 AToB = b - a;
Vector2 BToC = c - b;
float crossz = AToB.x * BToC.y - AToB.y * BToC.x;
if ( crossz > 0.0f )
{
  // clockwise
}
else
{
  // counter-clockwise.  Need to reverse the order of our vertices.
}

请注意,根据您将+ y轴(向上或向下)定向的方式,“顺时针”和“逆时针”的情况可能与我在此示例代码的注释中给它们加上标签的方式相反。


我需要将这些点传递给Box2D(java实现)以创建多边形。尽管这不是我要问的,但很有见地:)
onedayitwill将使2011年

2

您能提供更多信息吗?您想要点的CCW顺序,但是哪个点应该是顺序的中心?

如果平面上只有三角形(3个点),则可以从矩阵计算行列式,其中线是点的坐标(第三个坐标为1)。如果行列式> 0,则点按CCW顺序排列。如果没有,您可以例如砍掉最后两点,然后您将获得CCW订单。

如果您有点A,B,C,则矩阵如下所示:

|xA, yA, 1|
|xB, yB, 1|
|xC, yC, 1|

行列式为:xA * yB + xB * yC + xC * yA-yB * xC-yC * xA-yA * xB。然后,您可以将其与零进行比较。如果> 0,则返回点A,B,C,否则返回A,C,B。

如果您有一组点并且知道,它们会做成凸多边形(全部都是凸包的一部分),并且想要得到它们的顺序,可以使用Graham Scan或Jarvis的March(这些算法可以从许多点中找到凸包,但是它也应该在这里工作:))


要完成zacharmarz所说的内容,如果您只想围绕特定点按顺时针顺序对点进行排序,则可以从浮点对和点对中创建一个数组,在其中存储所有点以及从该特定点起其核心响应角的所有点,然后进行排序该数组。
Ali1S232 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.