需求:将点数据封装成mapbox需要的热力图格式返回。
数据格式中需要计算每个点单位范围内的密度,最后想到的思路是每个点都跟其他点计算距离,取半径范围内点的数量作为密度。
确定思路:
1、根据经纬度计算两点的距离,设置半径,计算距离小于此半径的点数量
2、 根据两点经纬度计算距离
3、mysql st_distance()函数
计算地图上两点间的距离
首先看一下大佬的基础理论:https://www.cnblogs.com/ycsfwhh/archive/2010/12/20/1911232.html
得到如下的计算公式
C = sin(MLatA)*sin(MLatB)*cos(MLonA-MLonB) + cos(MLatA)cos(MLatB)
Distance = RArccos©*Pi/180
1、Java代码实现
public final class DistanceUtils {
/**
* 地球半径,单位 km
*/
private static final double EARTH_RADIUS = 6378.137;
/**
* 根据经纬度,计算两点间的距离
*
* @param longitude1 第一个点的经度
* @param latitude1 第一个点的纬度
* @param longitude2 第二个点的经度
* @param latitude2 第二个点的纬度
* @return 返回距离 单位千米
*/
public static double getDistance(double longitude1, double latitude1, double longitude2, double latitude2) {
// 纬度
double lat1 = Math.toRadians(latitude1);
double lat2 = Math.toRadians(latitude2);
// 经度
double lng1 = Math.toRadians(longitude1);
double lng2 = Math.toRadians(longitude2);
// 纬度之差
double a = lat1 - lat2;
// 经度之差
double b = lng1 - lng2;
// 计算两点距离的公式
double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) +
Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(b / 2), 2)));
// 弧长乘地球半径, 返回单位: 千米
s = s * EARTH_RADIUS;
return s;
}
public static void main(String[] args) {
double d = getDistance(116.308479, 39.983171, 116.353454, 39.996059);
System.out.println(d);
}
}
2、sql实现
/*传入的参数为:纬度 40.0497810000 经度 116.3424590000 经度 ASC升序由近至远 DESC 降序 由远到近 */
SELECT
*,
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 - lon * PI() / 180
) / 2
),
2
)
)
) * 1000
) AS juli
FROM
customer
ORDER BY
juli ASC
3、mysql st_distance()函数
st_distance(point(a.longitude,a.latitude),point(b.longitude,b.latitude)) * 111195
最后选择方法3进行热力图计算
表自关联后与每个点匹配,#{dis}为传入半径
select name,mmsi,count(0) as count,lon,lat
from (
select a.`name`,a.mmsi,
(st_distance(point(a.longitude,a.latitude),point(b.longitude,b.latitude)) * 111195) as distance,
a.longitude as lon,a.latitude as lat
from (select * from table where create_date = (select create_date from table GROUP BY create_date order by create_date desc limit 1)) a
inner join (select * from table where create_date = (select create_date from table GROUP BY create_date order by create_date desc limit 1)) b
) c
where distance < #{dis}
group by mmsi;