1 概要

在不规则区域内均匀分布点,这个需求初看可能不好理解。如果设想一下需求场景就比较简单了。

场景1:在某个地区范围内,例如A市区有100W人口,需要将这100W人口在地图上面相对均匀的标识出来。

场景2:某不规则场馆,需要均匀布置展位,快速生成展位示意图。

场景其他:规则的电线杆、移动基站等模拟生成。

2 设计方案

既然是要求相对均匀的分布,我想到了格网法,即将多边形分割成特定边长的正方形格子,每个格子的中心点作为分布点。

好处:得到的点是绝对均匀的。

难点:需要判断格子是否在多边形范围内。

示意图:

其中1 2 3 4 四个点代表了不规则多边形的外接矩形角点。绿色的点用来算出1 2 3 4点的。

3 实现

第一步先看看模拟区域。

第二步画格子。

第三步标注格子中间的点。

第四步取出在区域范围内的格子中心点。

至此,基本满足了要求,部分格子的位置细节稍作调整就好。

4 代码

第一步,绘制区域,使用的是canvas。

  1. //公共方法,canvas绘制
  2. var drawFunc={
  3. ctx:null,
  4. init:function(domId){
  5. //获取canvas容器
  6. var can = document.getElementById(domId);
  7. //创建一个画布
  8. var ctx = can.getContext('2d');
  9. this.ctx=ctx;
  10. },
  11. drawArea:function(pts,background){
  12. this.ctx.beginPath();
  13.  
  14. var pt=pts[0];
  15. this.ctx.moveTo(pt[0],pt[1]);
  16.  
  17. for(var i=1;i<pts.length;i++){
  18. var pt=pts[i];
  19. this.ctx.lineTo(pt[0],pt[1]);
  20. }
  21. this.ctx.fillStyle = background;
  22. this.ctx.fill();
  23.  
  24. this.ctx.closePath();
  25. },
  26.  
  27. drawPoint:function(point,color,size){
  28. this.ctx.beginPath();
  29. this.ctx.arc(point[0], point[1], size, 0, 2*Math.PI, true);
  30.  
  31. this.ctx.fillStyle =color;
  32. this.ctx.fill();
  33.  
  34. this.ctx.closePath();
  35. },
  36.  
  37. drawLine:function(pts,lineWidth,color){
  38. this.ctx.beginPath();
  39. this.ctx.lineWidth=lineWidth;
  40.  
  41. var pt=pts[0];
  42. this.ctx.moveTo(pt[0],pt[1]);
  43. for(var i=1;i<pts.length;i++){
  44. var pt=pts[i];
  45. this.ctx.lineTo(pt[0],pt[1]);
  46. }
  47. this.ctx.strokeStyle = color;
  48. this.ctx.stroke();
  49. }
  50. }

  

  1. //01 创建不规则多边形
  2. var pts=[];
  3. pts.push([100,400]);
  4. pts.push([800,400]);
  5. pts.push([800,100]);
  6. pts.push([500,100]);
  7. pts.push([500,250]);
  8. pts.push([100,250]);
  9. drawFunc.drawArea(pts,"#cddc39");

  

第二步,绘制格子。这里有两个步骤,获取外接矩形和根据特定间距绘制格子。

  1. /**
  2. *绘制格网,并返回格网中心点
  3. **/
  4. function buildBox(space,startPt,endPt){
  5. var width=endPt[0]-startPt[0];
  6. var height=endPt[1]-startPt[1];
  7.  
  8. var y2=endPt[1];
  9. for(var i=0;i<width;i+=space){
  10. var x=startPt[0]+i;
  11.  
  12. var y1=startPt[1];
  13.  
  14. drawFunc.drawLine([[x,y1],[x,y2]],1,"#eee");
  15. }
  16.  
  17. var x2=endPt[0];
  18. for(var i=0;i<height;i+=space){
  19. var x1=startPt[0];
  20. var y=startPt[1]+i;
  21.  
  22. drawFunc.drawLine([[x1,y],[x2,y]],1,"#eee");
  23. }
  24.  
  25. var points=[];
  26.  
  27. for(var i=space;i<width;i+=space){
  28. var x=startPt[0]+i-space/2;
  29. for(var n=space;n<height;n+=space){
  30. var y=startPt[1]+n-space/2;
  31.  
  32. points.push([x,y]);
  33. }
  34. }
  35.  
  36. return points;
  37. }

  

  1. //02 求不规则多边形外接矩形左上右下点
  2. var box=queryMaxMinPt(pts);
  3. //03 以一定的间距绘制格网,并返回格网中心点
  4. var points= buildBox(20,box.startPt,box.endPt);
  1. /*
  2. *求多边形外接矩形左上右下点
  3. */
  4. function queryMaxMinPt(points){
  5. var x_min=100000000000000;
  6. var x_max=-1;
  7.  
  8. var y_min=100000000000000;
  9. var y_max=-1;
  10.  
  11. for(var i=0;i<points.length;i++){
  12. var pt=points[i];
  13.  
  14. if(pt[0]<x_min)
  15. x_min=pt[0];
  16. if(pt[0]>x_max)
  17. x_max=pt[0];
  18.  
  19. if(pt[1]<y_min)
  20. y_min=pt[1];
  21. if(pt[1]>y_max)
  22. y_max=pt[1];
  23. }
  24.  
  25. return {
  26. startPt:[x_min,y_min],
  27. endPt:[x_max,y_max]
  28. }
  29.  
  30. }

    第三和四步,查找在区域范围内的格子,并绘制。

  1. /**
  2. *检查点是否在多边形范围内
  3. **/
  4. function checkInside (point, vs) {
  5. var x = point[0], y = point[1];
  6.  
  7. var inside = false;
  8. for (var i = 0, j = vs.length - 1; i < vs.length; j = i++) {
  9. var xi = vs[i][0], yi = vs[i][1];
  10. var xj = vs[j][0], yj = vs[j][1];
  11.  
  12. var intersect = ((yi > y) != (yj > y))
  13. && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
  14. if (intersect) inside = !inside;
  15. }
  16.  
  17. return inside;
  18. };

      注:checkInside方法来源自Git,地址:https://github.com/substack/point-in-polygon/blob/master/index.js

  1. //04 遍历中心点,判断点是否在范围内
  2. var pointCount=0;
  3. for(var i=0;i<points.length;i++){
  4. var pt=points[i];
  5. if(checkInside(pt,pts)){
  6. drawFunc.drawPoint(pt,"red",2);
  7. pointCount++;
  8. }
  9.  
  10. }
  11.  
  12. console.log("范围内有:"+pointCount+"个点");

  

以上就是核心的实现代码,如果需要下载源码请移步我的博客下载,地址:

http://www.88gis.cn/web/pages/blog/blogInfo.html?id=38d8959a-f348-41df-b507-6c10e517e7a7

查看更多GIS、WPF、JAVA、前端技术分享,请访问我的个人技术网站,查看更多技术分享。网站地址:www.88gis.cn

【GIS新探索】算法实现在不规则区域内均匀分布点的更多相关文章

  1. 【原】ios的hitTest方法以及不规则区域内触摸事件处理方法

    概述 在正常的使用场景中,我们处理了比较多的矩形区域内触摸事件,比如UIButton.UIControl.一般来说,这些控件的图形以及触摸区域都是矩形或者圆角矩形的.但是在一些特殊应用场景中我们有时不 ...

  2. ios的hitTest方法以及不规则区域内触摸事件处理方法

    概述 在正常的使用场景中,我们处理了比较多的矩形区域内触摸事件,比如UIButton.UIControl.一般来说,这些控件的图形以及触摸区域都是矩形或者圆角矩形的.但是在一些特殊应用场景中我们有时不 ...

  3. 【GIS新探索】GeoHash原理和编解码实现

    1.什么是GeoHash geohash基本原理是将地球理解为一个二维平面,将平面递归分解成更小的子块,每个子块在一定经纬度范围内拥有相同的编码.不好理解,没关系,我来找个图. 就像上面这张图,一个坐 ...

  4. AS3 在不规则区域内拖动

    原理: 1.确保拖动对象在鼠标点上,如果不确定会出现瞬间移动的感觉 2.确保触碰到非通行区域,跳回到没触碰的点 源码: import flash.events.MouseEvent; import f ...

  5. [OpenGL] 不规则区域的填充算法

    不规则区域的填充算法 一.简单递归 利用Dfs实现简单递归填充. 核心代码: // 简单深度搜索填充 (四连通) void DfsFill(int x, int y) { || y < || x ...

  6. 发表在 Science 上的一种新聚类算法

    今年 6 月份,Alex Rodriguez 和 Alessandro Laio 在 Science 上发表了一篇名为<Clustering by fast search and find of ...

  7. 【Unity游戏开发】UGUI不规则区域点击的实现

    一.简介 马三从上一家公司离职了,最近一直在出去面试,忙得很,所以这一篇博客拖到现在才写出来.马三在上家公司工作的时候,曾处理了一个UGUI不规则区域点击的问题,制作过程中也有一些收获和需要注意坑,因 ...

  8. UGUI实现不规则区域点击响应

    UGUI实现不规则区域点击响应 前言 大家吼啊!最近工作上事情特别多,没怎么打理博客.今天无意打开cnblog才想起该写点东西了.今天给大家讲一个Unity中不规则区域点击响应的实现方法,使用UGUI ...

  9. 课题:html5图像羽化(不规则区域羽化,feather,html5羽化)

    下午搜索了一堆相关文章,没有找到符合要求的. 对一张图片应用不规则区域的羽化,该怎么做呢? 首先去查了下 羽化的原理,然而没有什么用, 然后就开始从表现层去研究怎么模拟? idea 1: blur滤镜 ...

随机推荐

  1. jquery.validate remote 和 自定义验证方法

    jquery.validate remote 和 自定义验证方法 $(function(){ var validator = $("#enterRegForm").validate ...

  2. docker-compose示例与命令介绍

    一.docker-compose.yml示例 version: ‘2‘ #指定compose版本 services: log: #服务名称 image: vmware/harbor-log #指定镜像 ...

  3. tp5主从数据库设置读写分离

    // 数据库类型 'type' => 'mysql', // 服务器地址 'hostname' => '192.168.0.5,192.168.0.6', // 数据库名 'databas ...

  4. Navicet Mysql数据库电脑本地备份

    Navicet Mysql数据库电脑本地备份 1.打开navicat客户端,连上mysql后,双击左边你想要备份的数据库.点击"计划",再点击"新建批处理作业" ...

  5. Hdu1051 Wooden Sticks 2017-03-11 23:30 62人阅读 评论(0) 收藏

    Wooden Sticks Problem Description There is a pile of n wooden sticks. The length and weight of each ...

  6. SQL Server创建表超出行最大限制解决方法

    问题的现象在创建表A的时候,出现“信息 511,级别 16,状态 1,第 5 行  无法创建大小为 的行,该值大于允许的最大值 8060.”的信息提示.很奇怪,网上查了一下,是因为要插入表的数据类型的 ...

  7. Javascript设计模式理论与实战:组合模式

    我们平时开发过程中,一定会遇到这种情况:同时处理简单对象和由简单对象组成的复杂对象,这些简单对象和复杂对象会组合成树形结构,在客户端对其处理的时候要保持一致性.比如电商网站中的产品订单,每一张产品订单 ...

  8. XML--将XML中数据提取出转换成表2

    DECLARE @xml XMLSET @xml = '<Students>    <Student  id="1001" name = "xu&quo ...

  9. PD生成SQL脚本附带注释命令

    '------------------------------------------------------------''脚本功能:' PowerDesigner中批量根据对象的name生成com ...

  10. Jenkins启动Tomcat时提示Neither the JAVA_HOME nor the JRE_HOME environment variable is defined

      Jenkins构建提示: [SSH] executing...Neither the JAVA_HOME nor the JRE_HOME environment variable is defi ...