依据 坐标(经度-longitude、纬度-latitude)和范围(rangeRadius) 获取 符合条件的 坐标

使用 Java + MySQL 实现 依据 坐标(经度-longitude、纬度-latitude)和范围(rangeRadius) 获取 符合条件的 坐标。

1、纯MySQL 实现 (存在效率瓶颈)

	SELECT * FROM 'location' WHERE ( 
	 ACOS( 
		SIN((23.146436 * 3.1415) / 180)
		* SIN((latitude * 3.1415) / 180) -- 纬度字段
		+ COS((23.146436 * 3.1415) / 180)
		* COS((latitude * 3.1415) / 180)
		* COS((113.323568 * 3.1415) / 180 - (longitude * 3.1415) / 180) -- 经度字段
	 ) * 6371.393 -- 地球平均半径
	) <= 5 -- 范围:5千米

2、Java + MySQL (极力推荐)

不BB,直接上代码,自己看注释

package com.aienuo.utils;

import lombok.Data;
import lombok.experimental.Accessors;

import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 

* Coordinate
* 依据 坐标(经度-longitude、纬度-latitude)和范围(rangeRadius) 获取 符合条件的 坐标 *
* 设计思路: * 泛型,任何业务实体类即可继承本类,方便实现功能 *
* 使用说明: * 1、先输入 当前坐标(经度-longitude、纬度-latitude)和范围(rangeRadius)推算出 坐标(经度、纬度)的极值(经度最大-getMaxLongitude,经度最小-getMinLongitude,纬度最大-getMinLatitude,纬度最小-getMaxLatitude) * 2、根据 坐标(经度、纬度)极值 作为查询条件去数据库内检索 符合条件的 坐标对象(伪集合,此为正方形范围,实际应该为 圆形范围) * 3、调用 setMemberList 方法 将 符合条件的坐标对象 放入, 再调用 getMemberList 方法 即可获取 最终符合条件的 坐标对象,同时也计算出距离(距离源点直线距离-distance) *

* @author SanJin * @version 1.0 * @since 2023年10月19日 16:47 */
@Data @Accessors(chain = true) public class Coordinate<T> { /** * 弧度计算公式: 弧度 = 弧长 / 半径 * 角度转弧度计算公式: 弧度 = 角度数 * (π / 180) * 弧度转角度计算公式: 角度数 = 弧度 * (180 / π) */ /** * 地球平局半径(千米) */ private static final double RADIUS = 6371.393; /** * 经度 */ private Double longitude; /** * 纬度 */ private Double latitude; /** * 距离(千米) */ private Double distance; /** * 范围(半径:千米) */ private Double rangeRadius; /** * 范围内的数据(正方形内的) */ private List<Coordinate<T>> memberList; /** * 获取 指定距离之后的 经度偏差值 * * @return Double - 指定距离之后的 经度偏差值 */ public Double getLongitudeDeviation() { // 指定距离之后的 经度偏差值 double longitudeDeviation = 2 * Math.asin(Math.sin(this.rangeRadius / (2 * RADIUS)) / Math.cos(this.rad(this.latitude))); // 弧度转角度(角度数 = 弧度 * (180 / π)) return longitudeDeviation * (180 / Math.PI); } /** * 获取 指定距离之后的 纬度偏差值 * * @return Double - 指定距离之后的 纬度偏差值 */ public Double getLatitudeDeviation() { // 指定距离之后的 纬度偏差值(弧度 = 弧长 / 半径) double latitudeDeviation = this.rangeRadius / RADIUS; // 弧度转角度(角度数 = 弧度 * (180 / π)) return latitudeDeviation * (180 / Math.PI); } public Double getMinLongitude() { return this.longitude - this.getLongitudeDeviation(); } public Double getMaxLongitude() { return this.longitude + this.getLongitudeDeviation(); } public Double getMinLatitude() { return this.latitude - this.getLatitudeDeviation(); } public Double getMaxLatitude() { return this.latitude + this.getLatitudeDeviation(); } /** * 获取 过滤 后的数据 * * @return List> - 过滤后的 */ public List<Coordinate<T>> getMemberList() { if (this.memberList != null && !this.memberList.isEmpty()) { this.memberList = memberList.stream().filter(member -> this.computeDistance(member) <= this.rangeRadius).sorted(Comparator.comparing(this::computeDistance)).collect(Collectors.toList()); } return this.memberList; } /** * 计算 基准点 与 目标点 之间的距离(千米) * * @param coordinate - 目标点 * @return Double - 距离:单位 千米 */ public Double computeDistance(final Coordinate<T> coordinate) { // 基准点 纬度坐标 的 弧度 double datumLatitudeRad = this.rad(this.latitude); // 目标点 纬度坐标 的 弧度 double targetLatitudeRad = this.rad(coordinate.latitude); // 基准点 纬度坐标 与 目标点 纬度坐标 的 弧度差 double latitudeRadDifference = datumLatitudeRad - targetLatitudeRad; // 基准点 经度坐标 与 目标点 经度坐标 的 弧度差 double longitudeRadDifference = this.rad(this.longitude) - this.rad(coordinate.longitude); // 基准点 与 目标点 之间的 弧度差 double radDifference = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(latitudeRadDifference / 2), 2) + Math.cos(datumLatitudeRad) * Math.cos(targetLatitudeRad) * Math.pow(Math.sin(longitudeRadDifference / 2), 2))); // 基准点 与 目标点 之间的 直线距离(千米) 弧长计算公式: 弧长 = 弧度 * 半径 double distance = radDifference * RADIUS; coordinate.setDistance(distance); return distance; } /** * 计算弧度 * * @param angle - 坐标值(角度) * @return - 弧度 */ private Double rad(final Double angle) { // 角度转弧度计算公式: 弧度 = 角度数 * (π / 180) return angle * (Math.PI / 180); } }

你可能感兴趣的:(技术研讨,工具类,问题解决,java,mysql,经纬度检索)