问题:给定平面中n个点所组成的集合,将它们连接起来形成一条简单的封闭路径。所谓简单路径,是指边与边无交叉。
如下图所示10个点组成的简单轮廓:
思路:取x坐标最大的点A(如果最大x坐标的点不止一个,则取Y坐标最小的点),依次计算A点与其余各点的连线与水平线之间夹角的正切值,然后按照正切值排序,依次连接排序后的各点即组成一个简单图形。
原理:其它所有点都在A点的左侧,所有夹角的范围为-Pi/2~Pi/2,单调递增函数。
举一个例子如下:
各点坐标与A点的角度斜率如下(已经排序好):
x:426.192518536091,y:30.5668629242884,slope:-2.21036105157629
x:132.904271903869,y:111.805767306036,slope:0.0233827696146631
x:209.153583263584,y:158.396180071121,slope:0.216615047225945
x:51.2625493860163,y:271.425922467106,slope:0.409713066051227
x:172.80558813494,y:320.363658168522,slope:0.754116336162768
x:174.841647802313,y:361.474091434606,slope:0.903935084923323
x:262.993097888768,y:306.679940091763,slope:1.03059799172764
x:405.520514378101,y:212.478244240618,slope:2.00680658499766
x:410.405247491042,y:324.597360433357,slope:4.49064367657446
x:459.491329337233,y:104.169257382941,slope:1.79769313486232E+308
其中A点为:x:459.491329337233,y:104.169257382941,slope:1.79769313486232E+308
下面给出具体算法(C#实现):
几何点定义,实现IComparable<T>接口,按照正切值排序要用到:
public struct GeometryPoint : IComparable<GeometryPoint> { public GeometryPoint(double x, double y, double slope = double.NaN) { this.x = x; this.y = y; this.slope = slope; } private double x; public double X { get { return x; } set { x = value; } } private double y; public double Y { get { return y; } set { y = value; } } private double slope; public double SLOPE { get { return slope; } set { slope = value; } } public int CompareTo(GeometryPoint p) { if (this.slope < p.slope) { return -1; } else if (this.slope > p.slope) { return 1; } else { if (this.x == p.x && this.SLOPE == p.SLOPE && this.SLOPE == double.MaxValue) { if (this.y == p.y) { return 0; } else if (this.y < p.y) { return 1; } else//(this.y > p.y) { return -1; } } return 0; } } public override string ToString() { return string.Format("x:{0},y:{1},slope:{2}", x, y, slope); } }