zoukankan      html  css  js  c++  java
  • 【GIS新探索】算法实现在不规则区域内均匀分布点

    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

  • 相关阅读:
    博客园添加访问人数统计【转】
    Android环境下通过C框架层控制WIFI【转】
    用户态文件系统fuse学习【转】
    linux内核 RCU机制详解【转】
    使用diff制作补丁【学习笔记】
    OAuth2授权原理
    Code! MVC 5 App with Facebook, Twitter, LinkedIn and Google OAuth2 Sign-on (C#)
    lock关键字只不过是C#提供的语法糖
    关于OATUH中的AUTHRAZITON CODE和TOKEN的关系,实际上就是这么回事
    SQL Server 索引设计指南
  • 原文地址:https://www.cnblogs.com/tracyjfly/p/9843790.html
Copyright © 2011-2022 走看看