我正在使用一个库(JavaScript-Voronoi),它生成一个表示封闭多边形的线段数组。这些线段看起来是无序的,包括线段出现的顺序以及线段每一端的点的顺序。
(编辑:正如在下面的评论中指出的那样,我错了:库中的段是有序的。但是,问题是书面的:让我们假设段没有任何顺序,因为这使得它更普遍有用.)
例如:
var p1 = {x:13.6,y:13.1}, p2 = {x:37.2,y:35.8}, p3 = {x:99.9,y:14.6},
p4 = {x:99.9,y:45.5}, p5 = {x:33.7,y:66.7};
var segments = [
{ va:p1, vb:p2 },
{ va:p3, vb:p4 },
{ va:p5, vb:p4 },
{ va:p3, vb:p2 },
{ va:p1, vb:p5 } ];
请注意第一个片段如何链接到最后一个片段(它们共享一个共同点)以及倒数第二个片段。保证每个段与另一个段共享一个末端。
我想将其转换为点列表以生成正确的 SVG 多边形:
console.log( orderedPoints(segments) );
// [
// {"x":33.7,"y":66.7},
// {"x":13.6,"y":13.1},
// {"x":37.2,"y":35.8},
// {"x":99.9,"y":14.6},
// {"x":99.9,"y":45.5}
// ]
点是顺时针还是逆时针都没有关系。
以下代码是我想出的,但在最坏的情况下,它将进行n^2+n
点比较。有没有更有效的算法将所有这些结合在一起?
function orderedPoints(segs){
segs = segs.concat(); // make a mutable copy
var seg = segs.pop(), pts = [seg.va], link = seg.vb;
for (var ct=segs.length;ct--;){
for (var i=segs.length;i--;){
if (segs[i].va==link){
seg = segs.splice(i,1)[0]; pts.push(seg.va); link = seg.vb;
break;
}else if (segs[i].vb==link){
seg = segs.splice(i,1)[0]; pts.push(seg.vb); link = seg.va;
break;
}
}
}
return pts;
}