1. 使用场景
1.根据一个经纬度点,自动匹配周围一公里经纬度串(可指定误差范围)
2.计算两个经纬度之间的距离
3.判断一个经纬度点是否属于一个经纬度串,可指点误差范围
2.应用步骤
1.引入依赖
<dependency>
<groupId>org.gavaghan</groupId>
<artifactId>geodesy</artifactId>
<version>1.1.3</version>
</dependency>
2.工具类引入
package com.gc.tocc.ruralroad.utils;
import com.gc.tocc.ruralroad.vo.JqPoint;
import org.gavaghan.geodesy.Ellipsoid;
import org.gavaghan.geodesy.GeodeticCalculator;
import org.gavaghan.geodesy.GeodeticCurve;
import org.gavaghan.geodesy.GlobalCoordinates;
import java.util.List;
public class MapUtils {
/**
* 计算经纬度串的长度
*
* @param gpsStr 经纬度串,格式形如:116.307852,40.057031;116.307852,40.057031
* @return 返回距离,单位:千米,保留两位小数
*/
public static double getDistanceLine(String gpsStr) {
//根据;分割经纬度串
String[] gpsArray = gpsStr.split(";");
//创建GeodeticCalculator,用于计算两个经纬度之间的距离
Double totalDistance = 0.0;
for (int i = 0; i < gpsArray.length - 1; i++) {
String[] gpsFromStr = gpsArray[i].split(",");
String[] gpsToStr = gpsArray[i + 1].split(",");
//创建GlobalCoordinates对象,传入经纬度
GlobalCoordinates gpsFrom = new GlobalCoordinates(Double.parseDouble(gpsFromStr[1]),
Double.parseDouble(gpsFromStr[0]));
GlobalCoordinates gpsTo = new GlobalCoordinates(Double.parseDouble(gpsToStr[1]),
Double.parseDouble(gpsToStr[0]));
//调用计算方法,传入坐标系、经纬度用于计算距离
double meter2 = getDistancePoint(gpsFrom, gpsTo, Ellipsoid.WGS84);
totalDistance += meter2;
}
return (double) Math.round(totalDistance / 1000 * 100) / 100;
}
/**
* 计算两个经纬度之间的距离
*/
private static double getDistancePoint(GlobalCoordinates gpsFrom, GlobalCoordinates gpsTo, Ellipsoid ellipsoid) {
//创建GeodeticCalculator,调用计算方法,传入坐标系、经纬度用于计算距离
GeodeticCurve geoCurve = new GeodeticCalculator().calculateGeodeticCurve(ellipsoid, gpsFrom, gpsTo);
return geoCurve.getEllipsoidalDistance();
}
/**
* 计算两点之间的距离
* */
private static double haversineDistance(double lon1, double lat1, double lon2, double lat2) {
double R = 6371000.0; // Earth's radius in meters
double dLat = Math.toRadians(lat2 - lat1);
double dLon = Math.toRadians(lon2 - lon1);
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c;
}
/**
* 判断某一个经纬度点是否在一个经纬度串上
* */
public static boolean isPtInPoly(double ALon, double ALat, double errorMeters, List<JqPoint> ps) {
for (int i = 0, j = ps.size() - 1; i < ps.size(); j = i++) {
JqPoint vertexA = ps.get(i);
JqPoint vertexB = ps.get(j);
// Check if the point is close enough to the current vertex
if (haversineDistance(vertexA.lon, vertexA.lat, ALon, ALat) <= errorMeters) {
return true;
}
// Check if the point lies on the edge AB
if (isPointOnEdge(ALon, ALat, vertexA.lon, vertexA.lat, vertexB.lon, vertexB.lat, errorMeters)) {
return true;
}
}
return false;
}
/**
* 判断某个点是否属于ps,如果属于则返回最小距离
*/
public static Double pointToPolyMinDistance(double ALon, double ALat, double errorMeters, List<JqPoint> ps) {
boolean isInsidePolygon = false;
double minDistance = Double.POSITIVE_INFINITY;
for (int i = 0, j = ps.size() - 1; i < ps.size(); j = i++) {
JqPoint vertexA = ps.get(i);
JqPoint vertexB = ps.get(j);
double distanceToVertexA = haversineDistance(ALon, ALat, vertexA.lon, vertexA.lat);
if (distanceToVertexA <= errorMeters) {
isInsidePolygon = true;
// minDistance = 0.0;
}
double distanceToEdge = pointToEdgeDistance(ALon, ALat, vertexA.lon, vertexA.lat, vertexB.lon, vertexB.lat);
if (distanceToEdge <= errorMeters) {
isInsidePolygon = true;
// minDistance = 0.0; // Point is on the edge
}
minDistance = Math.min(minDistance, Math.min(distanceToVertexA, distanceToEdge));
}
return isInsidePolygon ? minDistance : null;
}
public static boolean isPointOnEdge(double px, double py, double ax, double ay, double bx, double by, double errorMeters) {
double distance = haversineDistance(ax, ay, bx, by);
double d1 = haversineDistance(px, py, ax, ay);
double d2 = haversineDistance(px, py, bx, by);
return Math.abs(d1 + d2 - distance) <= errorMeters;
}
public static double pointToEdgeDistance(double px, double py, double ax, double ay, double bx, double by) {
double distance = haversineDistance(ax, ay, bx, by);
double d1 = haversineDistance(px, py, ax, ay);
double d2 = haversineDistance(px, py, bx, by);
return Math.abs(d1 + d2 - distance);
}
}
@Data
public class JqPoint {
public double lon;
public double lat;
public JqPoint(double lon, double lat) {
this.lon = lon;
this.lat = lat;
}
}
3.使用
// error:允许的误差范围
// 如果在误差范围内属于jqPointList则返回最近距离,如果不属于则返回null
Double minDistance=MapUtils.pointToPolyMinDistance(lon,lat,error, jqPointList);