返回
精确测量距离,保障位置安全:Java坐标经纬度计算与区域校验全攻略
后端
2023-05-17 14:29:09
Java坐标经纬度计算与区域校验指南
在当今互联互通的时代,精确的位置信息已成为现代生活不可或缺的一部分。从导航系统到社交媒体再到物流配送,精准的坐标经纬度计算至关重要。Java作为一门强大的编程语言,提供了丰富的库和算法,让这一过程变得轻松自如。本文将深入探讨Java中坐标经纬度计算和区域校验的方法,提供代码示例和最佳实践。
坐标经纬度计算
Haversine 公式:经典之选
Haversine 公式是一个经典的距离计算公式,它利用球面三角法来计算两点之间的距离。它将地球视为一个球体,并利用三角关系计算两点之间的弧长。
import java.lang.Math;
public class DistanceCalculator {
private static final double EARTH_RADIUS = 6371.01; // 地球半径,单位:千米
public static double haversineDistance(double lat1, double lon1, double lat2, double lon2) {
// 纬度和经度转换为弧度
lat1 = Math.toRadians(lat1);
lon1 = Math.toRadians(lon1);
lat2 = Math.toRadians(lat2);
lon2 = Math.toRadians(lon2);
// 计算两点之间的差值
double dLat = lat2 - lat1;
double dLon = lon2 - lon1;
// 使用 Haversine 公式计算距离
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(lat1) * Math.cos(lat2) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
double distance = EARTH_RADIUS * c;
return distance; // 单位:千米
}
}
Vincenty 公式:高精度之选
Vincenty 公式比 Haversine 公式更精确,因为它考虑了地球椭圆体的形状。
import java.lang.Math;
public class DistanceCalculator {
private static final double EARTH_EQUATORIAL_RADIUS = 6378.137; // 地球赤道半径,单位:千米
private static final double EARTH_POLAR_RADIUS = 6356.752; // 地球极半径,单位:千米
public static double vincentyDistance(double lat1, double lon1, double lat2, double lon2) {
// 纬度和经度转换为弧度
lat1 = Math.toRadians(lat1);
lon1 = Math.toRadians(lon1);
lat2 = Math.toRadians(lat2);
lon2 = Math.toRadians(lon2);
// 计算经度差和纬度差
double dLon = lon2 - lon1;
double dLat = lat2 - lat1;
// 计算辅助参数
double a = Math.cos(lat2) * Math.sin(dLon);
double b = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(dLon);
double f = (EARTH_EQUATORIAL_RADIUS - EARTH_POLAR_RADIUS) / EARTH_EQUATORIAL_RADIUS;
// 迭代计算
double s = dLat;
double sigma = 0;
double t = 0;
double tau = 0;
int iteration = 0;
while (true) {
iteration++;
tau = Math.pow(Math.tan(s / 2), 2);
sigma = 2 * Math.atan2(Math.sqrt(a * a + b * b * tau), Math.sqrt(b * b + (1 - f) * a * a * tau));
s = dLat - (1 - f) * (Math.sin(s) * Math.cos(sigma) + Math.sin(sigma) * Math.cos(s) * Math.cos(dLon));
t = 1 / Math.cos(sigma);
if (Math.abs(s - dLat) < 0.0000001 || iteration >= 20) {
break;
}
}
// 计算距离
double distance = EARTH_EQUATORIAL_RADIUS * s * t;
return distance; // 单位:千米
}
}
SpheroidalExact 公式:极致之选
SpheroidalExact 公式是 Vincenty 公式的扩展,它考虑了地球椭圆体的扁率。
import java.lang.Math;
public class DistanceCalculator {
private static final double EARTH_EQUATORIAL_RADIUS = 6378.137; // 地球赤道半径,单位:千米
private static final double EARTH_POLAR_RADIUS = 6356.752; // 地球极半径,单位:千米
private static final double EARTH_FLATTENING = 1 / 298.257223563; // 地球扁率
public static double spheroidalExactDistance(double lat1, double lon1, double lat2, double lon2) {
// 纬度和经度转换为弧度
lat1 = Math.toRadians(lat1);
lon1 = Math.toRadians(lon1);
lat2 = Math.toRadians(lat2);
lon2 = Math.toRadians(lon2);
// 计算经度差和纬度差
double dLon = lon2 - lon1;
double dLat = lat2 - lat1;
// 计算辅助参数
double a = Math.cos(lat2) * Math.sin(dLon);
double b = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(dLon);
// 迭代计算
double s = dLat;
double sigma = 0;
double t = 0;
double tau = 0;
int iteration = 0;
while (true) {
iteration++;
tau = Math.pow(Math.tan(s / 2), 2);
sigma = 2 * Math.atan2(Math.sqrt(a * a + b * b * tau), Math.sqrt(b * b + (1 - EARTH_FLATTENING) * a * a * tau));
s = dLat - (1 - EARTH_FLATTENING) * (Math.sin(s) * Math.cos(sigma) + Math.sin(sigma) * Math.cos(s) * Math.cos(dLon));
t = 1 / Math.cos(sigma);
if (Math.abs(s - dLat) < 0.0000001 || iteration >= 20) {
break;
}
}
// 计算距离
double distance = EARTH_EQUATORIAL_RADIUS * s * t;
return distance; // 单位:千米
}
}
区域校验
圆形区域校验算法
圆形区域校验算法确定一个点是否位于一个圆形区域内。
public class RegionValidator {
public static boolean isInsideCircle(double lat, double lon, double centerLat, double centerLon, double radius) {
// 纬度和经度转换为弧度
lat = Math.toRadians(lat);
lon = Math.toRadians(lon);
centerLat = Math.toRadians(centerLat);
centerLon = Math.toRadians(centerLon);
// 计算两点之间的距离
double distance = DistanceCalculator.haversineDistance(lat, lon, centerLat, centerLon);
// 检查点是否在圆内
return distance <= radius;
}
}
多边形区域校验算法
多边形区域校验算法确定一个点是否位于一个多边形区域内。
import java.util.List;
public class RegionValidator {
public static boolean isInsidePolygon(double lat, double lon, List<double[]> polygon) {
// 纬度和经度转换为弧度
lat = Math.toRadians(lat);
lon = Math.toRadians(lon);
// 计算多边形边界线的数量
int n = polygon.size();
// 沿多边形边界线遍历
for (int i = 0; i < n; i++) {
// 获取当前边界线和下一条