欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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 的右边

JS根据二维坐标的点选择最外围的点圈起来(求凸包的算法)

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++;
                    			
                    		}
                    		
                    	}
                    }

在真实数据情况下,可能所有点都在直线的上侧,也有可能所有点在直线的下侧,所以在内循环中,会有两个方向的计算。代码思路很简单,没太多有意思的东西。

上述做法是一种最蠢的无记忆手段,而凸包有很多性质可以利用。就把这些点放在平面上来看,如下图: 

JS根据二维坐标的点选择最外围的点圈起来(求凸包的算法)

就拿暴力做法而言,在求p0p1p0p1时,遍历了所有的点。此时,它会继续遍历p0p2p0p2,而由图知道这不可能是凸包的边界,可算法还得继续求。

文字转自:https://blog.csdn.net/u014688145/article/details/72200018(其中有更多解决方法)