在我正在开发的Web应用程序中,我正在检测某些图像的边界并沿检测到的边界生成一系列坐标点。由于生成数组的方式,不保证坐标点具有任何特定顺序。我写了一个比较器函数,它计算从中心点到任意两个给定点的矢量的叉积,以确定相对位置。这在chrome中运行良好,但是在firefox 21.0和IE 10中,一些坐标点没有正确排序。
比较器功能和排序功能的代码如下:
function sortCounterClockwise(a, b) {
return ((isALeftOfB(a, b)) ? 1 : -1);
//return ((isALeftOfB(a, b)) ? 1 : ((isALeftOfB(b, a)) ? -1 : 0));
}
function isALeftOfB(a, b) {
var det = (a.x - center.x) * (b.y - center.y) - (b.x - center.x) * (a.y - center.y);
if (det < 0) {
return false;
} else if (det > 0) {
return true;
}
var d1 = (a.x - center.x) * (a.x - center.x) + (a.y - center.y) * (a.y - center.y);
var d2 = (b.x - center.x) * (b.x - center.x) + (b.y - center.y) * (b.y - center.y);
return d1 < d2;
}
我在http://jsfiddle.net/Zsz3K/1/创建了一个完整的工作jsfiddle,如果你在Chrome中查看它,你会看到蒙大拿州的正确粗略轮廓,但在FF和IE中它会混淆坐标点
我已尝试过上述算法的多种变体,但我无法在FF或IE中的所有测试用例中使用它,只有chrome。在之前的迭代中,我将一个点固定为参考点,认为IE和FF因排序的循环性质而被绊倒。我的测试用例是上传美国地图,chrome能够成功检测并正确跟踪所有边框。我无法更改程序以保证坐标数组通过从中心点增加或减少θ来排序,并且确实需要找到一致的方法来对这些坐标进行排序,这些坐标在此处列出的浏览器中正常工作。据我所知,这似乎是FF和IE中的一个错误,因为结果是基于数学结果,这些结果应该是跨浏览器不可变的。
编辑:将答案移至答案。
答案 0 :(得分:0)
我已经创建了对jsfiddle的更新,我想这是一个模糊的回答我自己的问题。 http://jsfiddle.net/Zsz3K/3/
我粗略地进行了快速冒泡排序,并在比较器函数中添加了关于中心点的相对位置的附加条件,并且它适用于所有3个浏览器。我想这就是说,FF和IE中的.sort()实现似乎并不能很好地处理这类数据。我希望我有时间潜入jquery胆量,但我没有。因此,如果其他人遇到在jquery中排序空间坐标的问题,不要依赖于内置的排序函数,尽管我会推荐比vanilla冒泡更有效的东西,除了概念验证之外的其他东西。奇怪的是,chrome不仅使用内置的.sort()和比较器一直工作,而且它不需要(实际上被绊倒)使用相对位置到中心作为排序标准。
只是为了满足链接到jsfiddle的代码要求,这里是工作排序和比较器。
do {
swapped = false;
for (var i=0; i < points.length-1; i++) {
if (isALeftOfB(points[i + 1], points[i])) {
var temp = points[i];
points[i] = points[i+1];
points[i+1] = temp;
swapped = true;
}
}
} while (swapped);
function isALeftOfB(a, b) {
if (a.y <= center.y && b.y > center.y) {
return true;
} else if (a.y == center.y && b.y == center.y) {
return a.x < b.x
}
var det = (a.x - center.x) * (b.y - center.y) - (b.x - center.x) * (a.y - center.y);
if (det < 0) {
return false;
} else if (det > 0) {
return true;
}
var d1 = (a.x - center.x) * (a.x - center.x) + (a.y - center.y) * (a.y - center.y);
var d2 = (b.x - center.x) * (b.x - center.x) + (b.y - center.y) * (b.y - center.y);
return d1 < d2;
}