后端经纬度 点聚合

后端经纬度 点聚合

一、概述

1) 什么是地图综合?

地图综合所要解决的问题是把一个空间目标集合按照专题内容转换为一个最能代表该集合主要空间特

征的更抽象的空间目标集合,并符号化该抽象后的空间目标集合,以最有效的方式传输地理空间知识。

2) 什么是点聚合?

点聚合(point cluster),或又叫点聚类,是地图综合的其中一种方法,主要解决地图中点要素很多时

候的表示困难的问题。点聚合可以用少量的点或图标来表示地图中的所有点,让地图显示更清晰明朗。如

图 1所示

image-20200914170308506

3)本文关注的重点

​ 本文主要关注二维在线电子地图中点的聚合显示所用到的算法和目前的在线地图对点聚合显示的支持

情况。

​ 电子地图中,通常会遇到在某个地区包含成千上万个点要素的情况,若同时加载显示在电子地图中,

会显得很乱、覆盖地图底图,也会占用大量系统资源,甚至引发浏览器的崩溃、卡顿,极大的影响用户体

验,因此点聚合显示是电子地图十分需要的一项功能。

​ 目前的常见在线地图(或其API)是否支持点聚合?若支持点聚合的算法是什么?是一个值得关注的问

题。本文尝试对这两个问题进行解答。

二、在线地图点聚合的算法

特点

​ a) 数据相对简单,只有点要素,点没有形状变化,因此没有形状对聚合影响。

​ b) 没有评价聚合精确度的唯一指标,(不考虑运行速度的情况下)不同的算法不同的显示方式对用户体验影响 并不会太大。

​ c)  可能需考虑的方面:聚合点中包含的原始点要素最大数量限制、聚合点间的距离限制、点要素的

​ 权重、部分缩放级别是否该显示聚合点等。

​ d) 一般的点聚合(聚类)算法对在线地图点聚合虽适用(如K均值法等),但需平衡运行效率和必要性,并且 极少见这些复杂方法应用实际的在线地图中。

#### 	必要性

​ 目前在线地图的点聚合算法已有较成熟的应用,不少在线地图均提供点聚合的功能及API。点聚合算法虽然相对简单,但却很实用,若缺少了,在线地图则无法对大数据量的点要素进行较好的显示。对于在线地图的二次开发者来说,这也是一个十分重要的功能,例如要在地图上显示同一个站点中的多个传感器等,若缺少点聚合功能的支持,则是几乎无法辨别清楚地图上的这些传感器点要素。

运行方式

​ 点聚合的运算可以放在客户端(浏览器),也可以放在服务端运算(如 Google Maps的融合表)完毕再传给客户端。

表现形式

​ 在计算机上表现地点的点聚合方式多种多样,并无定论,聚合后的显示样式,不同缩放级别下是否显示不同图标或在以下列举几种常见的表现形式:

  • 多个点聚合后还是点要素,换不同图标显示,或在图标中同时显示该聚合点所包含的原始点要素的数量,点击聚合点后,地图视图会自动切换到该聚合点所包含的所有点的最小包围盒地图范围中。

  • 多个点聚合后还是点要素,换不同图标显示,或在图标中同时显示该聚合点所包含的原始点要素的数量,点击聚合点后,地图会弹出该聚合点的所聚合的所有点的位置信息,但并不缩放和移动地图。

  • 多个点聚合后是面要素,以颜色或数字表示所聚合的点的数量,点开后若单位面积内若依然包含较多点则继续显示面要素,若点较少则显示原始的点要素。此种方法较少见,常见于上述两种方法。

    算法

    本文关注的重点是在线地图点聚合算法的大致情况,而不是每个算法详细的运行效率和优劣情况。因

此,以下对可搜到的在线地图点聚合算法进行简要列举:

空间 Geohash函数

官方介绍地址:https://www.docs4dev.com/docs/zh/mysql/5.7/reference/spatial-geohash-functions.html

Geohash 是用于将任意精度的纬度和经度坐标编码为文本字符串的系统。 Geohash 值是仅包含从"0123456789bcdefghjkmnpqrstuvwxyz"中选择的字符的字符串。

优点:速度快,简单,数据取出来直接用

缺点:聚合的点偏差大,没有中心点

SELECT
	`user`.id, 
	`user`.lnglat,
	SUBSTRING_INDEX(`user`.lnglat,",",1) lng,
	SUBSTRING_INDEX(`user`.lnglat,",",-1) lat,
	ST_GeoHash(SUBSTRING_INDEX(`user`.lnglat,",",1),SUBSTRING_INDEX(`user`.lnglat,",",-1), 18)
FROM
	`user`
	

image-20200916111704787

SELECT
 t1.num,
 t1.gr,
 ST_LongFromGeoHash(gr) lng,
 ST_LatFromGeoHash(gr) lat,
 CONCAT(ST_LongFromGeoHash(gr),",",ST_LatFromGeoHash(gr)) lnglat
FROM
(SELECT
	count(*) num,
	ST_GeoHash(SUBSTRING_INDEX(`user`.lnglat,",",1),SUBSTRING_INDEX(`user`.lnglat,",",-1), 4) gr
FROM
	`user`
	GROUP BY gr order by num desc) t1
	

image-20200916111758941

1) 基于网格的点聚合算法(Grid-based Clustering)

原理:将地图划分成指定尺寸的正方形(每个缩放级别不同尺寸),然后将落在对应格子中的点聚合到该正方形中(正方形的中心),最终一个正方形内只显示一个点,并且点上显示该聚合点所包含的原始点的数量。

优点:运算速度较快,每个原始点只需计算一次,没有复杂的距离计算。

缺点:有时明明很相近的点,却仅仅因为网络的分界线而被逼分开在不同的聚合点中,此外,聚合点的位置采用的是该网格的中心,而非该网格的质心,这样聚合出来的点可能不能较精确反映原始点的信息。

使用此算法的在线地图:缺。

以下是Google给出的一个基于距离的点聚合示意图:

image-20200914171952994

image-20200914172004674

2)基于距离的点聚合算法(Distance-based Clustering)

10万数据 460左右

100万数据 5240左右

1000万数据 50124左右

原理:根据点与点之间的距离进行聚合,对每个点进行迭代,若被迭代的点在某个已有聚合点的指定

阈值的距离范围内,那么这个点就聚合到该点,否则则新建一个聚合点,如此循环,但聚合后的点的坐标

依然是该聚合点创建时的第一个点的坐标位置。

优点:聚合点较精确的反映了所包含的原始点要素的位置信息。

缺点:需要计算点与点之间的距离,计算相对复杂。

使用此算法的在线地图:高德的Android SDK 聚合使用此算法。

以下是Google给出的一个基于距离的点聚合示意图:

image-20200914172155131

image-20200914172201738

image-20200914172218585

image-20200914172227153

3)基于方格和距离结合的点聚合算法(详细) 去掉距离试一试?

10万数据 280左右

100万数据 3311左右

1000万数据 33793左右

1亿数据 程序崩了

基于方格

10万数据 191左右

100万数据 1854左右

1000万数据 33793左右

1亿数据 程序崩了

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x0000000050a954db, pid=35648, tid=0x0000000000002ca4
#
# JRE version: Java(TM) SE Runtime Environment (8.0_171-b11) (build 1.8.0_171-b11)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.171-b11 mixed mode windows-amd64 compressed oops)
# Problematic frame:
# V  [jvm.dll+0x3b54db]
#
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
#
# An error report file with more information is saved as:
# E:\2020work\other\demo\hs_err_pid35648.log
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
#
Disconnected from the target VM, address: '127.0.0.1:51322', transport: 'socket'

Process finished with exit code 1

原理:初始时没有任何已知聚合点,然后对每个点进行迭代,计算一个点的外包正方形,若此点的外包正方形与现有的聚合点的外包正方形不相交,则新建聚合点(区别于前面基于直接距离的算法,这里不是计算点与点间的距离,而是计算一个点的外包正方形,正方形的变长由用户指定或程序设置一个默认值),若相交,则把该点聚合到该聚合点中,若点与多个已知的聚合点的外包正方形相交,则计算该点到到聚合点的距离,聚合到距离最近的聚合点中,如此循环,直到所有点都遍历完毕。每个缩放级别都重新遍历所有原始点要素。

​ 此方法可以算是基于方格与基于距离的算法的一个结合算法。

​ 优点:运算速度相对较快,每个原始点只需计算一次,可能会有点与点距离计算,聚合点较精确的反映了所包含的原始点要素的位置信息。

缺点:速度不如完全基于方格的速度快等。

使用此算法的在线地图:Google Maps。

以下是Google给出的一个基于方格距离的点聚合示意图:

步骤示例:

a) 默认输入的数组的顺序是如图7–基于方格距离的点聚合算法(原始点要素)所示的字母顺序。

b) 初始计算,从A开始迭代,此时并没有任何聚合点,则在A的位置生成一个聚合点(设为A1),A1的位置与

A相同。

c) 迭代到B,如图8所示,由于B的外包正方形与已有聚合点A1的外包正方形相交,所以B应聚合到A1中,新聚合后的聚合点的位置依然保持在A1原来的位置(这主要是因为若采用A与B的质心会花费客户端较大的计算量,这在原始点要素数量较大时影响较大)。

d) 迭代到C,由于C的外包正方形不与现有的聚合点A1相交(目前只有A1一个聚合点),因此C需要新建一个新的聚合点(设为C1)。

e) 迭代到D,类似于B,D与A1聚合,聚合后依然为A1。

f) 迭代到E,新的问题来了,E的外包正方形同时与A1和C1相交,这时需判断E到A1、C1的距离,并将E聚合到距离近的那个聚合点中,这里E到C1更近,于是E聚合到了C1中。

g)剩下的如此迭代,直至完毕。

image-20200914172658730

image-20200914172706401

image-20200914172738306

image-20200914172745872image-20200914172754009

image-20200914172801385

4) 基于距离和最少点数量限制的点聚合算法

​ 原理:此算法相当于先执行完基于距离的点聚合算法,然后再进行一次聚合点的分解。每个聚合点成

立的条件是所聚合的原始点要素的数量应大于程序默认或用户指定的最少数量限制,否则将解散这个聚合

点。

​ 此方法甚至不能算是一个独立的算法,因为此算法的前后相互独立,类比的,其实也可以建议一种“基于网格和最少点数量限制”的点聚合算法。

​ 优点:聚合后的显示相对精确,对显示的控制更灵活。

​ 缺点:运算速度相对较慢,因为本身基于距离的点聚合算法就已经是相对较慢了,再加上后期根据最

少数量限制的阈值进行点聚合分解,速度更慢。

​ 使用此算法的在线地图:Openlayers

(Openlayers是一个开源的Javascript库(基于修改过的BSD许可发布),用来在Web浏览器显示地图【维基百科】)。

5)其他的可用于在线地图点聚合的算法

​ 一般的点聚合(聚类)算法对在线地图点聚合均适用(如K均值法等),但考虑运行效率和必要性的问题,因此,这里在不作运行效率、应用的在线地图等的评价。

​ 普通的遥感和GIS的图像聚类方法其实也可以应用在在线地图的点聚合中,由于运行的效率不高、实现容易程度难和必要性的不充分等原因可能并不适合实际运行,这里仅列举一些常见的遥感和GIS聚类方法:

​ a.启发式的方法:k-平均值(k- means)和k-中心点(k- medoids)等

​ b.层次方法(Hierarchy method): 对给定数据对象集合进行层次的分解

​ c.基于密度的方法(Density-based method):DBSCAN和OPTICS等

​ d.基于模型的方法(Model-based Method): 基于模型的方法为每个簇假定了一个模型, 寻找数据对给定模型的最佳拟合

在日后的在线地图的发展中,不排除由于新的其他需求而重新在其中使用上述这些额外的复杂算法。

三、在线地图点聚合功能的实现情况

目前来说,由于在线地图的点聚合算法在算法难度和实现难度上均不难,也基本能解决地图上大数据

量点显示的问题,所以算法本身可能并不是大部分地图用户和地图开发者所关心的问题,他们最关心的可

能是该地图是否支持点聚合显示功能,该地图的开放API是否可以调用点聚合功能等问题。

​ 因此,本文对目前一些常用在线地图的点聚合功能进行调查,并列举其中的情况。

image-20200914173901240

Openlayers

类型:开源的Javascript库,用来在Web浏览器显示地图。

是否支持点聚合显示:支持

是否支持点聚合API调用:支持

点聚合所用算法:基于距离和最少点数量的点聚合算法

点聚合官方地址:http://dev.openlayers.org/docs/files/OpenLayers/Strategy/Cluster-js.html

http://dev.openlayers.org/releases/OpenLayers-2.13.1/examples/strategy-cluster-extended.html

https://github.com/openlayers/openlayers/blob/master/lib/OpenLayers/Strategy/Cluster.js

点聚合功能实例:https://openlayers.org/en/latest/examples/cluster.html

图示:

image-20200914174036932

image-20200914174049720

Google Maps

类型:在线地图

是否支持点聚合显示:支持

是否支持点聚合API调用:支持

点聚合所用算法:基于方格和距离结合的点聚合算法。算法开源。

点聚合官方地址:https://developers.google.com/maps/documentation/javascript/marker-clustering

点聚合功能实例:https://developers.google.com/maps/documentation/javascript/marker-clustering

图示:

image-20200914174144792

​ 特殊功能:Google Maps支持服务端的点聚合功能(将点聚合的算法运算转移到服务器端,运行完毕后再将聚合后的结果传到客户端中),Google通过FusionTablesLayer(融合表,链接)和KmlLayer两种服务端的方式。基于融合表的一个在线示例:http://gmaps-samples-v3.googlecode.com/svn/trunk/fusiontables/cycletrails.html。

image-20200914174241430

百度地图

类型:在线地图

是否支持点聚合显示:支持

是否支持点聚合API调用:支持

点聚合所用算法:基于方格和距离结合的点聚合算法,支持是否将聚合点的位置放置在被聚合的点的

质心或第一个被聚合的点中,支持指定在何种级别才显示点或聚合点,支持限制最少聚合点数量。算法开

源。

点聚合官方地址: http://api.map.baidu.com/library/MarkerClusterer/1.2/docs/symbols/BMapLib.MarkerClusterer.html

点聚合功能实例:http://developer.baidu.com/map/jsdemo.htm#c1_4

图示:

image-20200914174338024

image-20200914174349426

高德地图

类型:在线地图

是否支持点聚合显示:支持

是否支持点聚合API调用:支持

点聚合所用算法:与百度地图基本一致。

点聚合官方地址:https://lbs.amap.com/api/javascript-api/guide/overlays/massmarker

点聚合功能实例:https://lbs.amap.com/api/javascript-api/example/marker/markerclusterer

图示:

image-20200914174433643

image-20200914174440287

esri

类型:地图API如Javascript、Flex、Silverlight等)

是否支持点聚合显示:支持

是否支持点聚合API调用:支持

点聚合所用算法:同时支持基于网格的和基于点权重,等。

点聚合官方地址:

(Flex)https://developers.arcgis.com/en/flex/api-reference/

(Flex)http://resources.arcgis.com/en/help/flex-viewer/concepts/index.html#//01m30000004z000000

点聚合功能实例:https://developers.arcgis.com/en/flex/sample-code/clustering.htm

图示:

image-20200914174537754

image-20200914174549318

腾讯地图

类型:在线地图

是否支持点聚合显示:是

是否支持点聚合API调用: 是

聚合API调用:https://lbs.qq.com/webApi/javascriptGL/glGuide/glMarkerCluster

点聚合例子: https://lbs.qq.com/webDemoCenter/glAPI/glMarkerCluster/markerCluster

image-20200914174634984

天地图

类型:在线地图

是否支持点聚合显示:不支持

是否支持点聚合API调用:不支持

关于不支持的相关地址和说明:无。

综上所述

  • 天地图和腾讯地图虽然有地图API,但均不支持点聚合显示功能,若进行在线地图二次开发时若需要同时显示的点较多,那么应考虑选用其他地图。

  • 大部分地图或工具对点聚合显示均有较好支持。

  • 百度地图、高德地图、ESRI API等对点聚合的支持选项更多。

  • Google Maps、百度地图、Openlayers均对点聚合算法开源。

四、小结

​ 本文简单介绍了地图综合中在线地图的点聚合功能的常用算法和在线地图对点聚合功能的支持现状,

为在线地图的二次开发者提供了关于点聚合显示方面的一些参考和建议。

​ 在线地图的点聚合功能虽然简单,却十分有用,对于地图使用者来说,可以看到美观和突出显示的地

图,对于二次开发者来说,节省了大量的开发时间和程序性能资源。

​ 本文存在偏颇、不妥和错误, 仅供讨论和参考,并敬请指正。

转载 https://wenku.baidu.com/view/f5a88999284ac850ad0242a2.html#

百度的api

http://api.map.baidu.com/library/MarkerClusterer/1.2/docs/symbols/src/BMapLib_MarkerClusterer.js.html

高德Android 示例

https://lbs.amap.com/dev/demo/cluster-marker#Android

https://github.com/amap-demo/android-cluster-marker

实现过程

1、空间 Geohash函数

Geohash 是用于将任意精度的纬度和经度坐标编码为文本字符串的系统。 Geohash 值是仅包含从"0123456789bcdefghjkmnpqrstuvwxyz"中选择的字符的字符串。

优点:速度快,简单,数据取出来直接用

缺点:聚合的点偏差大,没有中心点

SELECT
	`user`.id, 
	`user`.lnglat,
	SUBSTRING_INDEX(`user`.lnglat,",",1) lng,
	SUBSTRING_INDEX(`user`.lnglat,",",-1) lat,
	ST_GeoHash(SUBSTRING_INDEX(`user`.lnglat,",",1),SUBSTRING_INDEX(`user`.lnglat,",",-1), 18)
FROM
	`user`
	

image-20200916111704787

SELECT
 t1.num,
 t1.gr,
 ST_LongFromGeoHash(gr) lng,
 ST_LatFromGeoHash(gr) lat,
 CONCAT(ST_LongFromGeoHash(gr),",",ST_LatFromGeoHash(gr)) lnglat
FROM
(SELECT
	count(*) num,
	ST_GeoHash(SUBSTRING_INDEX(`user`.lnglat,",",1),SUBSTRING_INDEX(`user`.lnglat,",",-1), 4) gr
FROM
	`user`
	GROUP BY gr order by num desc) t1
	

image-20200916111758941

经纬度的算距离,和范围的工具类(借鉴高德的)

public class AMapUtils {

    /**
     * 计算两个坐标的距离
     * @param source
     * @param target
     * @return
     */
    public static float calculateLineDistance(LatLng source, LatLng target) {
        if (source != null && target != null) {
            try {
                double sourceLongitude = source.longitude;
                double sourceLatitude = source.latitude;
                double targetLongitude = target.longitude;
                double targetLatitude = target.latitude;
                sourceLongitude *= 0.01745329251994329D;
                sourceLatitude *= 0.01745329251994329D;
                targetLongitude *= 0.01745329251994329D;
                targetLatitude *= 0.01745329251994329D;
                double var10 = Math.sin(sourceLongitude);
                double var12 = Math.sin(sourceLatitude);
                double var14 = Math.cos(sourceLongitude);
                double var16 = Math.cos(sourceLatitude);
                double var18 = Math.sin(targetLongitude);
                double var20 = Math.sin(targetLatitude);
                double var22 = Math.cos(targetLongitude);
                double var24 = Math.cos(targetLatitude);
                double[] var26 = new double[3];
                double[] var27 = new double[3];
                var26[0] = var16 * var14;
                var26[1] = var16 * var10;
                var26[2] = var12;
                var27[0] = var24 * var22;
                var27[1] = var24 * var18;
                var27[2] = var20;
                double var28 = Math.sqrt((var26[0] - var27[0]) * (var26[0] - var27[0]) + (var26[1] - var27[1]) * (var26[1] - var27[1]) + (var26[2] - var27[2]) * (var26[2] - var27[2]));
                return (float)(Math.asin(var28 / 2.0D) * 1.27420015798544E7D);
            } catch (Throwable var30) {
                var30.printStackTrace();
                return 0.0F;
            }
        } else {
            try {
                throw new RuntimeException("非法坐标值");
            } catch (Exception e) {
                e.printStackTrace();
                return 0.0F;
            }
        }
    }
    /**
      * 根据中心点 和 距离算出方格  东北和西南的经纬度
      * @param   source
      * @param   raidus 单位米
      * @return
      */
    public static LatLngBounds getAround(LatLng source, Double raidus) {
        Map map = new HashMap();
        Double latitude = source.latitude;
        Double longitude = source.longitude;

        Double degree = (24901 * 1609) / 360.0;
        double raidusMile = raidus;

        Double mpdLat = Double.parseDouble((degree * Math.cos(longitude * (Math.PI / 180))+"").replace("-", ""));
        Double dpmLat = 1 / mpdLat;
        Double radiusLat= dpmLat * raidusMile;
        Double minLat = latitude - radiusLat;

        Double maxLat = latitude + radiusLat;

        Double dpmlng = 1 / degree;
        Double radiusLng = dpmlng * raidusMile;
        Double minLng = longitude - radiusLng;
        Double maxLng = longitude + radiusLng;

        LatLng northeast=new LatLng(maxLat,maxLng);
        LatLng southwest=new LatLng(minLat,minLng);
        LatLngBounds latLngBounds=new LatLngBounds(northeast,southwest);
        return latLngBounds;
    }
}

下面算法的数据操作

 /**
      *
      * @param   visibleBounds 屏幕的范围 前端传
      * @param   mClusterItems 所有的点数据
      * @param   mClusters 聚合后的数据集合
      * @param   isLattice 是否是方格和距离的算法 , 是 方格和距离的算法   , 否 距离算法
      * @return
      */
    private static void calculateClusters(LatLngBounds visibleBounds,List<ClusterItem> mClusterItems,List<Cluster> mClusters,boolean isLattice) {
        mIsCanceled = false;
        mClusters.clear();
        for (ClusterItem clusterItem : mClusterItems) {
            if (mIsCanceled) {
                return;
            }
            LatLng latlng = clusterItem.getPosition();
            if (visibleBounds.contains(latlng)) {
                Cluster cluster =null;
                if(isLattice){
                    cluster = getClusterLattice(latlng,mClusters);
                }else {
                    cluster = getCluster(latlng,mClusters);
                }

                if (cluster != null) {
                    cluster.addClusterItem(clusterItem);
                } else {
                    cluster = new Cluster(latlng);
                    mClusters.add(cluster);
                    cluster.addClusterItem(clusterItem);
                    // 设置中心点的范围
                    if(isLattice){
                        LatLngBounds latLngBounds = AMapUtils.getAround(latlng, mClusterDistance);
                        cluster.setLatLngBounds(latLngBounds);
                    }
                }
            }
        }
    }
2、基于距离的点聚合算法(Distance-based Clustering)

10万数据 460左右

100万数据 5240左右

1000万数据 50124左右

 /**
     * 距离算法
     * 根据一个点获取是否可以依附的聚合点,没有则返回null
     * @param latLng 判断该点是不是属于聚合中的一个点
     * @param clusters 所有的聚合点
     * @return
     */
    private static Cluster getCluster(LatLng latLng,List<Cluster> clusters) {
        for (Cluster cluster : clusters) {
            LatLng clusterCenterPoint = cluster.getCenterLatLng();
            double distance = AMapUtils.calculateLineDistance(latLng, clusterCenterPoint);
            if (distance < mClusterDistance && zoom < 19) {
                return cluster;
            }
        }
        return null;
    }
3、基于方格和距离结合的点聚合算法(详细)

10万数据 280左右

100万数据 3311左右

1000万数据 33793左右

1亿数据 程序崩了

  /**
     * 方格和距离算法
     * 根据一个点获取是否可以依附的聚合点,没有则返回null
     * @param latLng 判断该点是不是属于聚合中的一个点
     * @param clusters 所有的聚合点
     * @return
     */
    private static Cluster getClusterLattice(LatLng latLng,List<Cluster> clusters) {
        Cluster result=null;
        Double resultDistance=0D;
        for (Cluster cluster : clusters) {
            LatLng clusterCenterPoint = cluster.getCenterLatLng();
            if (cluster.getLatLngBounds().contains(latLng)) {
                double distance = AMapUtils.calculateLineDistance(latLng, clusterCenterPoint);
                if(result==null){
                    result=cluster;
                    resultDistance=distance;
                }else{
                    if (distance < resultDistance ) {
                        result=cluster;
                        resultDistance=distance;
                    }
                }
            }
        }
        return result;
    }

算多边形

https://blog.csdn.net/chaiqi/article/details/23099407

DROP TABLE IF EXISTS `geom`;
CREATE TABLE `geom`  (
  `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `pt` point NOT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = MyISAM CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

INSERT INTO `geom` VALUES (1, ST_GeomFromText('POINT(1 1)'));
INSERT INTO `geom` VALUES (2, ST_GeomFromText('POINT(2 2)'));
INSERT INTO `geom` VALUES (3, ST_GeomFromText('POINT(3 3)'));
INSERT INTO `geom` VALUES (4, ST_GeomFromText('POINT(4 4)'));
INSERT INTO `geom` VALUES (5, ST_GeomFromText('POINT(5 5)'));
INSERT INTO `geom` VALUES (6, ST_GeomFromText('POINT(6 6)'));


set @poly='Polygon((0 0,0 3,3 3,3 0,0 0))';
select AsText(pt) from geom where MBRWithin(pt,GeomFromText(@poly));
select AsText(pt) from geom where MBRContains(GeomFromText(@poly),pt);





select AsText(pt) from geom where MBRWithin(pt,GeomFromText('Polygon((0 0,0 3,3 3,3 0,0 0))'));
select AsText(pt) from geom where MBRContains(GeomFromText('Polygon((0 0,0 3,3 3,3 0,0 0))'),pt);


mysql通过经纬度查询400公里范围内的小区

mysql距离计算,单位m,以及排序

lng 经度 lat 纬度

一般地图上显示的坐标顺序为,纬度在前(范围-9090),经度在后(范围-180180)

传入参数 纬度 40.0497810000 经度 116.3424590000
/*传入的参数为 纬度 纬度 经度 ASC升序由近至远 DESC 降序 由远到近 */
SELECT
id,
name,
address,
ROUND(
6378.138 * 2 * ASIN(
SQRT(
POW(
SIN(
(
40.0497810000 * PI() / 180 - lat * PI() / 180
) / 2
),
2
) + COS(40.0497810000 * PI() / 180) * COS(lat * PI() / 180) * POW(
SIN(
(
116.3424590000 * PI() / 180 - lng * PI() / 180
) / 2
),
2
)
)
) * 1000
) AS 距离
FROM
oc_district
HAVING
距离 < 400000
ORDER BY
距离 ASC

方法二:通过MySQL的POIN方法

st_distance 计算的结果单位是度,需要乘111195(地球半径6371000*PI/180)是将值转化为米。

sql:
SELECT *, (st_distance (point (lon,lat),point (116.3424590000,40.0497810000))*111195/1000 )as juli FROM customer ORDER BY juli ASC
点聚合后端实现代码下载

里面的dianjuhe

操作步骤

先导入sql

image-20200923135726160

修改mysql连接配置

image-20200923135815269

启动后端然后访问

http://localhost:9904/

image-20200923141018217

代码介绍

image-20200923141213421

要根据经纬度设置聚合数据,您可以使用聚合数据服务提供商的API。以下是一个示例,使用OpenLayers和聚合数据API来设置聚合数据: 1. 在HTML文件中引入OpenLayers的库文件和样式表: ```html <!DOCTYPE html> <html> <head> <link rel="stylesheet" href="https://openlayers.org/en/v4.6.4/css/ol.css" type="text/css"> <script src="https://openlayers.org/en/v4.6.4/build/ol.js"></script> </head> <body> <div id="map" style="width: 100%; height: 400px;"></div> <script> // 在这里编写代码 </script> </body> </html> ``` 2. 在JavaScript部分,创建一个地图实例并设置中心和缩放级别: ```javascript var map = new ol.Map({ target: 'map', layers: [ new ol.layer.Tile({ source: new ol.source.OSM() }) ], view: new ol.View({ center: ol.proj.fromLonLat([经度, 纬度]), zoom: 缩放级别 }) }); ``` 3. 使用聚合数据API获取数据并在地图上显示聚合标记: ```javascript var vectorSource = new ol.source.Vector({ format: new ol.format.GeoJSON(), features: [] }); var vectorLayer = new ol.layer.Vector({ source: vectorSource }); map.addLayer(vectorLayer); // 使用聚合数据API获取数据 var apiUrl = 'https://api.example.com/data?lat=' + 纬度 + '&lon=' + 经度; fetch(apiUrl) .then(response => response.json()) .then(data => { // 解析返回的数据,创建聚合标记 var features = new ol.format.GeoJSON().readFeatures(data); vectorSource.addFeatures(features); }); ``` 请注意,上述示例中的经度和纬度需要替换为实际的数值,缩放级别可以根据需要进行调整。同时,您还需要将`apiUrl`替换为实际的聚合数据API的URL。 这只是一个基本示例,您可以根据实际需求进行修改和扩展。希望对您有所帮助!
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

liuhm~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值