【GIS新探索】演算法實現在不規則區域內均勻分佈點
阿新 • • 發佈:2018-12-17
1 概要
在不規則區域內均勻分佈點,這個需求初看可能不好理解。如果設想一下需求場景就比較簡單了。
場景1:在某個地區範圍內,例如A市區有100W人口,需要將這100W人口在地圖上面相對均勻的標識出來。
場景2:某不規則場館,需要均勻佈置展位,快速生成展位示意圖。
場景其他:規則的電線杆、移動基站等模擬生成。
2 設計方案
既然是要求相對均勻的分佈,我想到了格網法,即將多邊形分割成特定邊長的正方形格子,每個格子的中心點作為分佈點。
好處:得到的點是絕對均勻的。
難點:需要判斷格子是否在多邊形範圍內。
示意圖:
其中1 2 3 4 四個點代表了不規則多邊形的外接矩形角點。綠色的點用來算出1 2 3 4點的。
3 實現
第一步先看看模擬區域。
第二步畫格子。
第三步標註格子中間的點。
第四步取出在區域範圍內的格子中心點。
至此,基本滿足了要求,部分格子的位置細節稍作調整就好。
4 程式碼
第一步,繪製區域,使用的是canvas。
//公共方法,canvas繪製 var drawFunc={ ctx:null, init:function(domId){ //獲取canvas容器 var can = document.getElementById(domId); //建立一個畫布 var ctx = can.getContext('2d'); this.ctx=ctx; }, drawArea:function(pts,background){ this.ctx.beginPath(); var pt=pts[0]; this.ctx.moveTo(pt[0],pt[1]); for(var i=1;i<pts.length;i++){ var pt=pts[i]; this.ctx.lineTo(pt[0],pt[1]); } this.ctx.fillStyle = background; this.ctx.fill(); this.ctx.closePath(); }, drawPoint:function(point,color,size){ this.ctx.beginPath(); this.ctx.arc(point[0], point[1], size, 0, 2*Math.PI, true); this.ctx.fillStyle =color; this.ctx.fill(); this.ctx.closePath(); }, drawLine:function(pts,lineWidth,color){ this.ctx.beginPath(); this.ctx.lineWidth=lineWidth; var pt=pts[0]; this.ctx.moveTo(pt[0],pt[1]); for(var i=1;i<pts.length;i++){ var pt=pts[i]; this.ctx.lineTo(pt[0],pt[1]); } this.ctx.strokeStyle = color; this.ctx.stroke(); } }
//01 建立不規則多邊形 var pts=[]; pts.push([100,400]); pts.push([800,400]); pts.push([800,100]); pts.push([500,100]); pts.push([500,250]); pts.push([100,250]); drawFunc.drawArea(pts,"#cddc39");
第二步,繪製格子。這裡有兩個步驟,獲取外接矩形和根據特定間距繪製格子。
/** *繪製格網,並返回格網中心點 **/ function buildBox(space,startPt,endPt){ var width=endPt[0]-startPt[0]; var height=endPt[1]-startPt[1]; var y2=endPt[1]; for(var i=0;i<width;i+=space){ var x=startPt[0]+i; var y1=startPt[1]; drawFunc.drawLine([[x,y1],[x,y2]],1,"#eee"); } var x2=endPt[0]; for(var i=0;i<height;i+=space){ var x1=startPt[0]; var y=startPt[1]+i; drawFunc.drawLine([[x1,y],[x2,y]],1,"#eee"); } var points=[]; for(var i=space;i<width;i+=space){ var x=startPt[0]+i-space/2; for(var n=space;n<height;n+=space){ var y=startPt[1]+n-space/2; points.push([x,y]); } } return points; }
//02 求不規則多邊形外接矩形左上右下點 var box=queryMaxMinPt(pts); //03 以一定的間距繪製格網,並返回格網中心點 var points= buildBox(20,box.startPt,box.endPt);
/* *求多邊形外接矩形左上右下點 */ function queryMaxMinPt(points){ var x_min=100000000000000; var x_max=-1; var y_min=100000000000000; var y_max=-1; for(var i=0;i<points.length;i++){ var pt=points[i]; if(pt[0]<x_min) x_min=pt[0]; if(pt[0]>x_max) x_max=pt[0]; if(pt[1]<y_min) y_min=pt[1]; if(pt[1]>y_max) y_max=pt[1]; } return { startPt:[x_min,y_min], endPt:[x_max,y_max] } }
第三和四步,查詢在區域範圍內的格子,並繪製。
/** *檢查點是否在多邊形範圍內 **/ function checkInside (point, vs) { var x = point[0], y = point[1]; var inside = false; for (var i = 0, j = vs.length - 1; i < vs.length; j = i++) { var xi = vs[i][0], yi = vs[i][1]; var xj = vs[j][0], yj = vs[j][1]; var intersect = ((yi > y) != (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); if (intersect) inside = !inside; } return inside; };
//04 遍歷中心點,判斷點是否在範圍內 var pointCount=0; for(var i=0;i<points.length;i++){ var pt=points[i]; if(checkInside(pt,pts)){ drawFunc.drawPoint(pt,"red",2); pointCount++; } } console.log("範圍內有:"+pointCount+"個點");
以上就是核心的實現程式碼,如果需要下載原始碼請移步我的部落格下載,地址:
檢視更多GIS、WPF、JAVA、前端技術分享,請訪問我的個人技術網站,檢視更多技術分享。網站地址:www.88gis.cn