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;
};
注:checkInside方法來源自Git,地址:https://github.com/substack/point-in-polygon/blob/master/index.js
//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+"個點");
以上就是核心的實現代碼,如果需要下載源碼請移步我的博客下載,地址:
http://www.88gis.cn/web/pages/blog/blogInfo.html?id=38d8959a-f348-41df-b507-6c10e517e7a7
查看更多GIS、WPF、JAVA、前端技術分享,請訪問我的個人技術網站,查看更多技術分享。網站地址:www.88gis.cn
