package org.sxkj.common.geo.utils; import org.locationtech.jts.geom.Coordinate; import java.util.*; import java.util.stream.Collectors; /** * @PROJECT_NAME: drone * @DESCRIPTION: 计算两个经纬度点之间的距离(以公里为单位) * @USER: aix * @DATE: 2024/3/25 14:25 */ public class DistanceCalculator { private static final int EARTH_RADIUS_KM = 6371; // 地球半径,单位:公里 /** * 使用Haversine公式计算两个经纬度点之间的距离(单位:公里) * * @param lat1 第一个点的纬度 * @param lon1 第一个点的经度 * @param lat2 第二个点的纬度 * @param lon2 第二个点的经度 * @return 两点之间的距离(单位:公里) */ public static double calculateDistance(double lat1, double lon1, double lat2, double lon2) { double dLat = Math.toRadians(lat2 - lat1); double dLon = Math.toRadians(lon2 - lon1); lat1 = Math.toRadians(lat1); lat2 = Math.toRadians(lat2); double a = Math.pow(Math.sin(dLat / 2), 2) + Math.pow(Math.sin(dLon / 2), 2) * Math.cos(lat1) * Math.cos(lat2); double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); double distance = EARTH_RADIUS_KM * c; return distance; } // 计算两点之间的欧几里得距离 public static double distance(Coordinate a1, Coordinate b2) { double lat1 = Math.toRadians(a1.y); // 将纬度从度转换为弧度 double lat2 = Math.toRadians(b2.y); // 将纬度从度转换为弧度 double lon1 = Math.toRadians(a1.x); // 将经度从度转换为弧度 double lon2 = Math.toRadians(b2.x); // 将经度从度转换为弧度 double dLat = lat2 - lat1; // 纬度差 double dLon = lon2 - lon1; // 经度差 // 使用 Haversine 公式 double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(lat1) * Math.cos(lat2); double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); double distance = EARTH_RADIUS_KM * c; // 计算距离 return distance; } /** * 计算两个坐标点之间的距离(米) * * @param point1 第一个点 * @param point2 第二个点 * @return 两点之间的距离(米) */ public static double calculateDistance(Coordinate point1, Coordinate point2) { final double EARTH_RADIUS = 6371000; // 地球半径(米) // 将经纬度转换为弧度 double lat1 = Math.toRadians(point1.getY()); double lng1 = Math.toRadians(point1.getX()); double lat2 = Math.toRadians(point2.getY()); double lng2 = Math.toRadians(point2.getX()); // 使用Haversine公式计算距离 double deltaLat = lat2 - lat1; double deltaLng = lng2 - lng1; double a = Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2) + Math.cos(lat1) * Math.cos(lat2) * Math.sin(deltaLng / 2) * Math.sin(deltaLng / 2); double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); return EARTH_RADIUS * c; } /** * 中心点排序 * @param coordinates 中心点数组 * @param airportLat 纬度 * @param airportLon 经度 * @param index 索引 * @param retCoordinate 返回结果 * @return */ public static Coordinate[] sortByDistance(List coordinates, double airportLat, double airportLon,int index,Coordinate[] retCoordinate) { // 创建一个列表来保存坐标、对应的距离以及原始下标 List>> distanceList = new ArrayList<>(); for (int i = 0; i < coordinates.size(); i++) { Coordinate coord = coordinates.get(i); double distance = calculateDistance(airportLat, airportLon, coord.y, coord.x); // 注意:y是纬度,x是经度 distanceList.add(new AbstractMap.SimpleEntry<>(coord, new AbstractMap.SimpleEntry<>(distance, i))); } // 根据距离进行排序 distanceList.sort(Comparator.comparingDouble(entry -> entry.getValue().getKey())); //中心点排序结果 retCoordinate[index] = distanceList.get(0).getKey(); coordinates.remove(distanceList.get(0).getKey()); if (coordinates.size() > 0) { index = index+1; sortByDistance(coordinates,distanceList.get(0).getKey().y,distanceList.get(0).getKey().x,index,retCoordinate); } return retCoordinate; } public static Coordinate[] getFirstPolygon(List coordinatesCentro,Coordinate[] afterCoor,List> coordinates) { // 创建一个列表来保存坐标、对应的距离以及原始下标 List>>> distanceList = new ArrayList<>(); for (int i = 0; i < coordinates.size(); i++) { Coordinate coord = coordinatesCentro.get(i); distanceList.add(new AbstractMap.SimpleEntry<>(coord, coordinates)); } // 如果你需要排序前的下标,你可以通过以下方式获取它们: Map>> originalIndexMap = distanceList.stream() .collect(Collectors.toMap(entry -> entry.getKey(), entry -> entry.getValue())); // 现在你可以通过坐标查找原始的下标 // 例如:int originalIndex = originalIndexMap.get(someCoordinate); Coordinate[] retcoor = new Coordinate[afterCoor.length * 4 - 3]; for (int i = 0; i