JS根据二维坐标的点选择最外围的点圈起来(求凸包的算法)
程序员文章站
2022-06-30 10:26:32
...
穷尽搜索法:
参考博文【凸包问题的五种解法】
当然非暴力解法莫属,想法很简单,我们知道凸包的性质,凸包一定是【最外围】的那些点圈成,所以假设有n个点,那么最多可以构造出n(n−1)2n(n−1)2条边,算法如下:
1. 选定一条边,遍历其他n-2个点,如果所有点都在该条边的一侧,则加入凸包集合。
2. 不断重复步骤1,直到所有边都被遍历过。
如何判断一个点 p3 是在直线 p1p2 的左边还是右边呢?(坐标:p1(x1,y1),p2(x2,y2),p3(x3,y3))我们可以计算:
当下式结果为正时,p3在直线 p1p2 的左侧;当结果为负时,p3在直线 p1p2 的右边
for(var i = 0;i<count;i++)
{
for(var j=i+1;j<count;j++)
{
//全在左边的是凸包中的点
var oneSide = 0;
for(var k=0;k<count;k++){
if(k == i || k == j)continue;
if( (wai[i][0]*wai[j][1]+wai[k][0]*wai[i][1]+wai[j][0]*wai[k][1]-wai[k][0]*wai[j][1]-wai[j][0]*wai[i][1]-wai[i][0]*wai[k][1]) > 0)
{
oneSide++;
}
}
if(oneSide == count - 2 || oneSide == 0){
//这是用来划线的,知道了两个点是凸包中,将其划线就可以。
var polyline = new esri.geometry.Polyline([ [ wai[i][0],wai[i][1] ],[wai[j][0],wai[j][1] ] ]);
var symbol = new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_SOLID, new dojo.Color([0,0,0]), 1);
var graphic = new esri.Graphic(polyline, symbol);
map.graphics.add(graphic);
hua[counthua] = wai[i];
counthua++;
hua[counthua] = wai[j];
counthua++
}
//全在右边的也是凸包中的点
var otherSide = 0;
for(var k=0;k<count;k++){
if(k == i || k == j)continue;
if( (wai[i][0]*wai[j][1]+wai[k][0]*wai[i][1]+wai[j][0]*wai[k][1]-wai[k][0]*wai[j][1]-wai[j][0]*wai[i][1]-wai[i][0]*wai[k][1]) < 0)
{
otherSide++;
}
}
if(otherSide == count - 2 || otherSide == 0){
var polyline = new esri.geometry.Polyline([ [ wai[i][0],wai[i][1] ],[wai[j][0],wai[j][1] ] ]);
var symbol = new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_SOLID, new dojo.Color([0,0,0]), 1);
var graphic = new esri.Graphic(polyline, symbol);
map.graphics.add(graphic);
hua[counthua] = wai[i];
counthua++;
hua[counthua] = wai[j];
counthua++;
}
}
}
在真实数据情况下,可能所有点都在直线的上侧,也有可能所有点在直线的下侧,所以在内循环中,会有两个方向的计算。代码思路很简单,没太多有意思的东西。
上述做法是一种最蠢的无记忆手段,而凸包有很多性质可以利用。就把这些点放在平面上来看,如下图:
就拿暴力做法而言,在求p0p1p0p1时,遍历了所有的点。此时,它会继续遍历p0p2p0p2,而由图知道这不可能是凸包的边界,可算法还得继续求。
文字转自:https://blog.csdn.net/u014688145/article/details/72200018(其中有更多解决方法)
上一篇: 怀孕初期吃什么水果对宝宝好?这些水果孕妇一定要少吃
下一篇: 减肥吃什么好,晚上怎么减肥