对于什么是值得的,我使用Lua,但任何伪代码将不胜感激。非常感谢任何帮助!
更新:为了参考,这是基于Ciamej的优秀答案(忽略我的“app”前缀)的Lua代码:
function appSortPointsClockwise(points) local centerPoint = appGetCenterPointOfPoints(points) app.pointsCenterPoint = centerPoint table.sort(points,appGetIsLess) return points end function appGetIsLess(a,b) local center = app.pointsCenterPoint if a.x >= 0 and b.x < 0 then return true elseif a.x == 0 and b.x == 0 then return a.y > b.y end local det = (a.x - center.x) * (b.y - center.y) - (b.x - center.x) * (a.y - center.y) if det < 0 then return true elseif det > 0 then return false end local d1 = (a.x - center.x) * (a.x - center.x) + (a.y - center.y) * (a.y - center.y) local d2 = (b.x - center.x) * (b.x - center.x) + (b.y - center.y) * (b.y - center.y) return d1 > d2 end function appGetCenterPointOfPoints(points) local pointsSum = {x = 0,y = 0} for i = 1,#points do pointsSum.x = pointsSum.x + points[i].x; pointsSum.y = pointsSum.y + points[i].y end return {x = pointsSum.x / #points,y = pointsSum.y / #points} end
解决方法
然后使用任何你喜欢的排序算法对点进行排序,但使用特殊的比较例程来确定一个点是否小于另一个点。
通过这个简单的计算,可以检查一个点(a)是否相对于中心位于另一个(b)的左边或右边:
det = (a.x - center.x) * (b.y - center.y) - (b.x - center.x) * (a.y - center.y)
如果结果为零,则它们在中心的同一直线上,如果它是正的或负的,则它在一侧或另一侧,因此一个点将在另一个之前。
使用它可以构造一个小于的关系来比较点,并确定它们应该在排序数组中出现的顺序。但是你必须定义该顺序的开始,我的意思是开始的角度(例如x轴的正半)。
bool less(point a,point b) { if (a.x - center.x >= 0 && b.x - center.x < 0) return true; if (a.x - center.x < 0 && b.x - center.x >= 0) return false; if (a.x - center.x == 0 && b.x - center.x == 0) { if (a.y - center.y >= 0 || b.y - center.y >= 0) return a.y > b.y; return b.y > a.y; } // compute the cross product of vectors (center -> a) x (center -> b) int det = (a.x - center.x) * (b.y - center.y) - (b.x - center.x) * (a.y - center.y); if (det < 0) return true; if (det > 0) return false; // points a and b are on the same line from the center // check which point is closer to the center int d1 = (a.x - center.x) * (a.x - center.x) + (a.y - center.y) * (a.y - center.y); int d2 = (b.x - center.x) * (b.x - center.x) + (b.y - center.y) * (b.y - center.y); return d1 > d2; }
这将从12点开始顺时针顺序排列点。相同“小时”上的点将从离中心更远的点开始排序。
如果使用整数类型(这在Lua中不存在),你必须确保det,d1和d2变量是能够保存执行计算结果的类型。
如果你想实现一些看起来坚实,尽可能凸,那么我想你正在寻找一个Convex Hull.你可以使用Graham Scan计算。
在此算法中,您还必须从特殊枢轴点开始顺时针(或逆时针)排序点。然后你重复简单的循环步骤,每次检查是否向左或向右添加新的点到凸包,这个检查是基于交叉乘积就像在上面的比较函数。
编辑:
添加了一个if语句if(ay – center.y> = 0 || by – center.y> = 0),以确保具有x = 0和负y的点从进一步从中心。如果你不关心在同一’小时’点的顺序,你可以省略这个if语句,并总是返回a.y>通过。
通过添加-center.x和-center.y更正了第一个if语句。
添加了第二个if语句(a.x – center.x< 0& b.x - center.x> = 0)。这是一个明显的疏忽,它失踪了。 if语句现在可以重新组织,因为一些检查是多余的。例如,如果第一个if语句中的第一个条件为false,则第二个if的第一个条件必须为true。然而,我决定离开代码,因为它是为了简单。很可能编译器将优化代码并产生相同的结果。