GIS地图点汇聚及空间搜索算法Java实现样例
背景
当需要在GIS地图上显⽰的点数据量⽐较⼤时,会考虑将多个点汇聚成⼀个点展⽰;汇聚后图标上显⽰⼀个数字,以表⽰当前汇聚点包含了多少个原始数据对象。⽤户可以⿏标点击这些汇聚点查看单个原始数据的详细信息。
GIS数据汇聚展⽰可以让地图呈现更简洁,美观(如果所有点展开,地图缩⼩时显⽰得密密⿇⿇)。另外更重要的⼀点是可以提升地图渲染的效率。
⽅案分析
汇聚算法与地图的放⼤级别(zoom size),以及当前屏幕窗⼝边界范围有关。当地图缩⼩时,数据需要汇聚,地图放⼤时数据需要展开。经纬度落在屏幕边界范围外的数据不需要展⽰,这样可以减少加载的数据量,提升性能(坏处是拖动地图时需要重新加载数据, 实测⼏⼗万点的情况下延迟两到三秒,还可以接受)。
有两种实现⽅式:⼀种是采⽤空间搜索算法,在地图视窗变化时根据地图放⼤层级,搜索半径范围的点汇聚在⼀起;另⼀种是将屏幕范围内的地图区域划分多个⽹格,落到同⼀个⽹格类的点汇聚在⼀起(⽹格
⼤⼩根据不同的放⼤层级指定)。
前⼀种⽅案实现复杂,地图放⼤和缩⼩时点数据汇聚和展开的效果很平滑。后⼀种画⽹格的⽅式实现⽐较简单,但效果⽐较差,数据量,位置分布,离群值都会影响汇聚效果。
汇聚算法只能解决点数据的汇聚,如果地图上同时有线数据,与点相连的;处理不好就会出现放⼤或者缩⼩时点与线脱节的情况,很影响呈现效果。这种情况通过画⽹格的⽅式是解决不了的。
为解决数据传输性能的问题,需要把汇聚算法放在后台实现,参考SuperCluster的实现逻辑,⽤Java代码重写了⼀遍(JSuperCluster)。数据在后台汇聚后再传到前台,10⼏万个点汇聚后通常只有只百个点。传输数据量减⼩后,性能得到很⼤提升。
样例代码
代码⽬录结构
定义算法基础模型
马来西亚沙巴1. 汇聚模型基础类定义-应⽤层模型从该类派⽣
import java.io.Serializable;
/**
预防英语
* 汇聚模型基础类定义。所有需要调⽤汇聚算法的模型从该类派⽣。
*
* @author elon
花开无声作文* @version 1.0 2019-03-15
*/
@Data
public class AggregationModelBa implements Serializable {
private static final long rialVersionUID = 4951392595928922035L;
/**
* 对象唯⼀ID(应⽤层定义,可以是数据库中对象的⾃增ID或者其它唯⼀标识)。 */
private int id = -1;
/
**
* 经度
*/
private double longitude = 0;
/**
* 维度
*/
private double latitude = 0;
}
2. 汇聚算法参数模型定义-最⼤放⼤层级根据地图⽀持的规格⽽定
/**
* 汇聚算法参数模型定义
*/
@Data
public class JClusterOption implements Serializable {
private static final long rialVersionUID = -7916591464862026234L;
/**
* ⽣成聚合数据的最⼩地图放⼤层级
*/
private int minZoom = 0;
/**
* ⽣成数据的最⼤地图放⼤层级
*/
private int maxZoom = 16;
/**
* 聚合半径(单位:像素)
*/
private int radius = 40;
/**
* ⽡⽚⼤⼩
*/
private int extent = 512;
/**
* KD-Tree的叶⼦节点数量
*/
private int nodeSize = 64;
private Object reduce = null;
private Object initial = null;
private Object map = null;
}
3. KD树单点对象模型定义
/**
* KD树单点对象模型定义。应⽤层的单个GIS点在计算前转换为该模型。 *
* @author elon
西芹虾仁
*/
@Data
public class JKDNode implements Serializable {
private static final long rialVersionUID = -7134737233652288121L;
/**
* 对象索引ID(算法对数量重新编号后的id)
*/
private int id = -1;
/**
* ⽗节点ID
*/
private int parentId = 1;
/**
* 地图放⼤级别
*/
private int zoom = Integer.MAX_VALUE;
/**
* 聚合点的数量
*/
private int numPoints = 0;
/**
* 对象属性
*/
private Object properties = null;
/**
* 对象原始ID,记录应⽤层汇聚模型的ID值
*/
private int orignalId = -1;
/**
* X坐标
*/
private double x = 0;
/**
* Y坐标
*/
private double y = 0;
private int index = -1;
}
红颜祸水是什么意思
4. 聚合节点模型定义
/**
* 聚合节点模型定义。
*
* @author elon
* @version 1.0 2019-03-15
*/
@Data
public class JClusterNode <T extends AggregationModelBa> implements Serializable {
private static final long rialVersionUID = -5358622773451333438L;
/**
* 是否聚合对象
*/
private boolean isCluster = fal;
/**
* 聚合点的ID游学计划
*/
private int clusterId = -1;
/**
* 聚合点数量
*/
private int pointCount = 0;
/**
* 聚合点的X坐标
*/
private double x = 0;
/**
* Y坐标
*/
酒酿做法
private double y = 0;
/**
* 聚合点为单点时存储应⽤层的对象模型。
*/
private T data = null;
菝葜怎么读}
定义算法底层使⽤的K-D树
1. K-D树模型定义
将GIS对象放到K-D Tree, 以⽀持后续的快速搜索。
package com.elon.jsc.kdbush;
import com.del.JKDNode;
import java.util.Arrays;
import java.util.List;
/**
* K-D树模型定义,⽤于GIS点汇聚时空间搜索。根据开源软件KDBush的JS代码翻译⽽来。 *