百度地图的聚合算法

这段百度算法的描述来自博客:https://blog.csdn.net/javine/article/details/51195014

总结如下:

百度地图把整个地球是按照一个平面来展开,把整个地球按照平面来展开之后,我们就能算出这个地球平面的宽度,也就是世界宽度。

计算公式是这样的:256*(zoom^2) == worldWidth

其中zoom就是地图的层级,我们缩放地图也是根据zoom的变化来判断是放大还是缩小的。这样可以把不利于计算的经纬度position转换成我们熟悉的二维坐标point。

而一个二维坐标中有若干个点,把它们按照一个给定的distance来进行分组。
迭代所有的QuadItem,以此QuadItem为中心画一个框框,框框里面的点就算是一个cluster簇,
也就是可以聚合成一个点的QuadItems。框框的大小就是我们定义的可以执行聚合的距离。
当然,这话其实并不准确,会有些点同时被好多个框框给框住,那就算距离最小的那个cluster里面的点。

/***  cluster算法核心* @param zoom map的级别* @return*/@Overridepublic Set<? extends Cluster<T>> getClusters(double zoom) {final int discreteZoom = (int) zoom;final double zoomSpecificSpan = MAX_DISTANCE_AT_ZOOM / Math.pow(2, discreteZoom) / 256;//定义的可进行聚合的距离final Set<QuadItem<T>> visitedCandidates = new HashSet<QuadItem<T>>();  //遍历QuadItem时保存被遍历过的Itemfinal Set<Cluster<T>> results = new HashSet<Cluster<T>>();  //保存要返回的cluster簇,每个cluster中包含若干个MyItem对象final Map<QuadItem<T>, Double> distanceToCluster = new HashMap<QuadItem<T>, Double>();  //Item --> 此Item与所属的cluster中心点的距离final Map<QuadItem<T>, mapapi.clusterutil.clustering.algo.StaticCluster<T>> itemToCluster =new HashMap<QuadItem<T>, mapapi.clusterutil.clustering.algo.StaticCluster<T>>(); //Item对象 --> 此Item所属的clustersynchronized (mQuadTree) {for (QuadItem<T> candidate : mItems) {<span style="white-space:pre"> </span>//遍历所有的QuadItemif (visitedCandidates.contains(candidate)) {<span style="white-space:pre"> </span>//如果此Item已经被别的cluster框住了,就不再处理它continue;}Bounds searchBounds = createBoundsFromSpan(candidate.getPoint(), zoomSpecificSpan);//这个就是我们说的,根据给定距离生成一个框框Collection<QuadItem<T>> clusterItems;// search 某边界范围内的clusterItemsclusterItems = mQuadTree.search(searchBounds); //从quadTree中搜索出框框内的点if (clusterItems.size() == 1) {// 如果只有一个点,那么这一个点就是一个cluster,QuadItem也实现了Cluster接口,也可以当作Cluster对象results.add(candidate);visitedCandidates.add(candidate);distanceToCluster.put(candidate, 0d);continue;<span style="white-space:pre">   </span>//并且结束此次循环}mapapi.clusterutil.clustering.algo.StaticCluster<T> cluster =new mapapi.clusterutil.clustering.algo.StaticCluster<T>(candidate.mClusterItem.getPosition());//如果搜索到多个点,那么就以此item为中心创建一个clusterresults.add(cluster);for (QuadItem<T> clusterItem : clusterItems) {<span style="white-space:pre">  </span>//遍历所有框住的点Double existingDistance = distanceToCluster.get(clusterItem);//获取此item与原来的cluster中心的距离(如果之前已经被其他cluster给框住了)double distance = distanceSquared(clusterItem.getPoint(), candidate.getPoint());<span style="white-space:pre">    </span>//获取此item与现在这个cluster中心的距离if (existingDistance != null) {// 判断那个距离跟小if (existingDistance < distance) {continue;}//如果跟现在的cluster距离更近,则将此item从原来的cluster中移除itemToCluster.get(clusterItem).remove(clusterItem.mClusterItem);}distanceToCluster.put(clusterItem, distance); //保存此item到cluster中心的距离cluster.add(clusterItem.mClusterItem);<span style="white-space:pre"> </span>//将此item添加到cluster中itemToCluster.put(clusterItem, cluster);<span style="white-space:pre"> </span>//建立item -- cluster 的map}visitedCandidates.addAll(clusterItems);//将所有框住过的点添加到已访问的List中。}}return results;}

简化版的地图聚合算法

百度上面的聚合算法,基本上可以满足百分之九十九的需求。但是,经过测试,在一个很小的区域中密集聚合了1w个以上的点时,在android手机上就会出现内存溢出的情况。所以这时候就需要一个简单并且运算量较小的算法。

地图坐标化

虽然上面的算法不符合我们的要求,但是我们仍然可以获得一个思路,就是把地球展开成一个平面,将经纬度转换成我们熟识的xy二维坐标轴。

但是,为了节省移动端宝贵的内存和运算量,我们完全不需要建立整个世界的坐标系,而只需要建立我们手机屏幕所显示出来的地图的坐标系。如下图所示:

这样的建立坐标系以后,我们将屏幕的左下角看作0点,那么屏幕中任何一个点的相对坐标就是这个点的经纬度减去屏幕左下角那个点的经纬度。

点的聚合

在百度的算法中,可以看作会比较每两个点直接的距离。这样的话,画出来的聚合图虽然好看,但在数据量很大时,效率就比较低下。

所以我们如果对聚合的速度要求很高,但是聚合的效果要求不高的话。可以做这样一个处理。
我们将x轴分割为n份,y轴分割成m份。这样的话整个地图就会被分割成一个个的小方格,我们只需要计算每个方格中的包含的gps点数,即可。这样就完成了一个最基本的聚合。

例如在上图中,我们将地图分割成了n*m份,天津所在的这个小方格内的聚合度就1,其他地方聚合度就是0。

如果这个时候我们在天津所在的这个方格内,再加一个点,这个方格的聚合度就变成了2。

现在点的数目增加多一点

我们来分割一下,横向三格,纵向6格


这样分割以后,出来的聚合效果就是

具体代码

   mBaiduMap.setOnMapStatusChangeListener(new BaiduMap.OnMapStatusChangeListener() {@Overridepublic void onMapStatusChangeStart(MapStatus mapStatus) {}@Overridepublic void onMapStatusChangeStart(MapStatus mapStatus, int i) {}@Overridepublic void onMapStatusChange(MapStatus mapStatus) {}@Overridepublic void onMapStatusChangeFinish(MapStatus mapStatus) {try{//清楚地图上的markermBaiduMap.clear();//左上角经纬度Point pt = new Point();pt.x = 0;pt.y = 0;LatLng llLeftTop = mBaiduMap.getProjection().fromScreenLocation(pt);//右下角经纬度Point pty = new Point();pty.x = mMapView.getWidth();pty.y = mMapView.getHeight();LatLng llRightBottom = mBaiduMap.getProjection().fromScreenLocation(pty);//屏幕中显示的经度的长度和纬度的长度double mapWidth = llRightBottom.longitude - llLeftTop.longitude;double mapHeight = llLeftTop.latitude - llRightBottom.latitude;//将屏幕中地图分割的横向 格子数和 纵向格子数int widthSize = 10;int heightSize = 20;//计算每个格子的经纬度的长度double unitWidth = mapWidth / widthSize;double unitHeight = mapHeight / heightSize;//用来保存每个格子里面的点的数量int[] pointSize = new int[widthSize * heightSize];//计算每个分隔点内gps点的数量for (MyItem b : myItemList) {LatLng latLng=b.getPosition();//如果点在显示范围内if (latLng.longitude > llLeftTop.longitude &&latLng.longitude < llRightBottom.longitude &&latLng.latitude > llRightBottom.latitude &&latLng.latitude < llLeftTop.latitude) {//计算每个点,相对于左下角的经纬度double relativeX = latLng.longitude - llLeftTop.longitude;double relativeY = latLng.latitude - llRightBottom.latitude;//计算出这个点,处于哪个格子int x = (int) Math.floor(relativeX / unitWidth);int y = (int) Math.floor(relativeY / unitHeight);if (x < 0 || y < 0) {// LogUtil.e("relativeX:" + relativeX + "---------relativeY:" + relativeY);}pointSize[y * widthSize + x] = pointSize[y * widthSize + x] + 1;}}List<OverlayOptions> options = new ArrayList<OverlayOptions>();//设置坐标点BitmapDescriptor bitmap;//绘制每个格子和格子里点的数量for (int y = 0; y < heightSize; y++) {for (int x = 0; x < widthSize; x++) {double lng = llLeftTop.longitude + x * unitWidth;double lat = llRightBottom.latitude + y * unitHeight;//如果格子里点的数量为0 ,则不绘制if (pointSize[y * widthSize + x] == 0) {continue;}TextView textView = new TextView(MarkerClusterDemo.this);textView.setBackgroundColor(getResources().getColor(android.R.color.holo_red_light));textView.setText(pointSize[y * widthSize + x] + "");bitmap = BitmapDescriptorFactory.fromView(textView);LatLng point = new LatLng(lat, lng);OverlayOptions option1 = new MarkerOptions().position(point).icon(bitmap);options.add(option1);}}//在地图上批量添加mBaiduMap.addOverlays(options);}catch (Exception e){e.printStackTrace();}}

一种简单的地图聚合算法相关推荐

  1. 选择排序(Selection sort)是一种简单直观的排序算法

    选择排序(Selection sort)是一种简单直观的排序算法.它的工作原理是:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大 ...

  2. 一种简单的图形旋转算法

    图形旋转好玩又有实用性, 这里介绍一种简单的图形旋转算法. 具体步骤如下: 1. 首先将原图和旋转图的坐标原点都变换到图形的中心位置处. 2. 历遍旋转图形中的每一个pixel, 将pixel的坐标( ...

  3. 一种简单的抗锯齿算法

    在LCD等显示器上逐点绘制几何图像的时候, 往往对几何体的边缘采样不足, 这就会导致出现锯齿状不平滑的边缘. 为了尽量减弱这种现象,需要在斜线或物体边缘进行更密集的采样,然后根据一定的权重比例将色彩/ ...

  4. 新冠肺炎疫情数据爬取以及几种简单的地图可视化方法

    众所周知,新冠肺炎疫情是一次很流行的全球性公共卫生事件.如今我国疫情已经好了许多,但世界各国的疫情依然严峻.特殊时期,正好尝试一下疫情网络数据的抓取,并用几种python库对数据进行简单的地图可视化( ...

  5. 一种简单的抽签/抽奖算法逻辑

    1.抽签计算方法步骤: 注:A:基数:B:翻转数: X:报名次数:Y:种子号,即起始中签号:Z:阶数: (1)A=(抽签日的上一个工作日的深圳证券交易所深证成指"今收"指数×100 ...

  6. 一种简单的图像LDR->HDR算法

    算法比较简单,尽量简单说. 文章:Fully-automatic inverse tone mapping algorithm based on dynamic mid-level tone mapp ...

  7. python素数最优算法_几种简单的求素数算法的复杂度分析

    素数的算法有很多种,现在主要讲两种算法及其改进版本的复杂度分析,解释性能提升的幅度.同时应用一个素数定理:素数的平方一定是合数,那么在范围内最大数的开方范围内找不到能整除的数,那么这个数是素数.应用这 ...

  8. java 路由算法_几种简单的负载均衡算法及其Java代码实现

    什么是负载均衡 负载均衡,英文 名称为Load Balance,指由多台服务器以对称的方式组成一个服务器集合,每台服务器都具有等价的地位,都可以单独对外提供服务而无须其他服务器的辅助.通过某种 负载分 ...

  9. 排序算法(01)— 三种简单排序(冒泡、插入、选择)

    一.概述 排序是数据处理中十分常见且核心的操作,虽说实际项目开发中很小几率会需要我们手动实现,毕竟每种语言的类库中都有n多种关于排序算法的实现.但是了解这些精妙的思想对我们还是大有裨益的. 1.1 排 ...

最新文章

  1. spring boot 使用外部配置文件
  2. 便利的开发工具-log4cpp快速使用指南
  3. java https请求_Spring Cloud Sleuth:分布式请求链路跟踪
  4. FFA 2021 专场解读 - 开源解决方案 / 流批一体
  5. 一场暴雨引发的装机日记
  6. c语言实现lcd显示自动滚动,lcd1602实现字幕滚动原理_lcd1602滚动显示程序
  7. Oracle -- rollup函数
  8. eclipse导入静态网页模板+搭建springboot环境示例+细节问题解决(详细)
  9. android 字体显示框架,资源样式 - 主题 - 《XUI - Android 原生 UI 框架》 - 书栈网 · BookStack...
  10. 04 CoCos Creator-Please make sure java is installed and JAVA_HOME
  11. 计算机蓝屏解决,电脑蓝屏怎么解决,详细解决蓝屏方案
  12. [Android] [Hybrid APP开发简述]
  13. Web 攻防之业务安全:账号安全案例总结.
  14. 项目启动初始化SQL脚本
  15. 结合GUI可视化发送QQ消息 —— 2022/2/11
  16. 软考高级证书哪个最好考?
  17. python设计一个节假日字典_python实现在无须过多援引的情况下创建字典的方法
  18. VR数字政务:多功能一体化,政务服务更便民
  19. ce能修改服务器数据吗,ce修改游戏服务器数据库
  20. Annexin V-FITC染色液

热门文章

  1. 3D光固化lcd树脂选购与光固化参数选择
  2. qq群服务器拒绝了您发送离线文件夹,离线传文件
  3. kali httrack-网站克隆工具
  4. sde java_java操作oracle空间信息介绍(SDE)
  5. 三星手机微信连接不上服务器,三星S7手机微信收不到推送消息怎么办?快看看本文的方法能不能帮到你!...
  6. unity打包及优化转载
  7. 前端通用下载文件方法(兼容IE10及以上)
  8. 【自考试题】2019年10月操作系统(02326)真题及答案
  9. c语言中的加减乘除字母,简单的c语言加减乘除运算
  10. 吴恩达机器学习ex3