使用 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
2、Java + MySQL (极力推荐)
package com.aienuo.utils;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
@Data
@Accessors(chain = true)
public class Coordinate<T> {
private static final double RADIUS = 6371.393;
private Double longitude;
private Double latitude;
private Double distance;
private Double rangeRadius;
private List<Coordinate<T>> memberList;
public Double getLongitudeDeviation() {
double longitudeDeviation = 2 * Math.asin(Math.sin(this.rangeRadius / (2 * RADIUS)) / Math.cos(this.rad(this.latitude)));
return longitudeDeviation * (180 / Math.PI);
}
public Double getLatitudeDeviation() {
double latitudeDeviation = this.rangeRadius / RADIUS;
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();
}
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;
}
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;
}
private Double rad(final Double angle) {
return angle * (Math.PI / 180);
}
}