package com.dji.sample.patches.utils; import com.dji.sample.patches.model.entity.LotInfo; import org.geotools.geometry.jts.JTSFactoryFinder; import org.locationtech.jts.geom.*; import org.locationtech.jts.io.ParseException; import org.locationtech.jts.io.WKTReader; import org.locationtech.jts.operation.buffer.BufferOp; import org.locationtech.jts.simplify.TopologyPreservingSimplifier; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; /** * @PROJECT_NAME: drone * @DESCRIPTION: * @USER: aix * @DATE: 2024/3/25 10:35 */ public class GeoToolsUtil { /** * 获取中心点位置 * * @param geometry Geometry * @return */ public static Coordinate getCentro(Geometry geometry) { return geometry.getCentroid().getCoordinate(); } /** * 获取4个点的经纬度 * * @param geometry Geometry * @return */ public static List getExtremePoints(Geometry geometry) { List extremePoints = new ArrayList<>(); Envelope envelope = geometry.getEnvelopeInternal(); // 获取4个点经纬度 extremePoints.add(new Coordinate(envelope.getMinX(), envelope.getMaxY())); extremePoints.add(new Coordinate(envelope.getMinX(), envelope.getMinY())); extremePoints.add(new Coordinate(envelope.getMaxX(), envelope.getMinY())); extremePoints.add(new Coordinate(envelope.getMaxX(), envelope.getMaxY())); return extremePoints; } public static Coordinate[] sortCoordinatesByNearestDistance(Coordinate[] coordinates) { // 将数组转换为List以便操作 List coordinateList = new ArrayList<>(Arrays.asList(coordinates)); // 排序后的坐标列表 List sortedCoordinates = new ArrayList<>(); // 如果列表不为空,开始排序 if (!coordinateList.isEmpty()) { // 将第一个点添加到排序列表中 sortedCoordinates.add(coordinateList.remove(0)); // 循环处理剩余的点 while (!coordinateList.isEmpty()) { double minDistance = Double.MAX_VALUE; Coordinate nearest = null; // 查找距离排序列表中最后一个点最近的点 for (Coordinate c : coordinateList) { double distance = DistanceCalculator.distance(sortedCoordinates.get(sortedCoordinates.size() - 1), c); if (distance < minDistance) { minDistance = distance; nearest = c; } } // 将找到的最近的点添加到排序列表中,并从原始列表中移除它 sortedCoordinates.add(nearest); coordinateList.remove(nearest); } } return sortedCoordinates.toArray(new Coordinate[0]); } /** * 获取拐点坐标(替换上面获取四个航点坐标方法) * * @return */ public static List getSimplifyPolygons(Geometry originalPolygon) { List coordinatesList = new ArrayList(); // 应用抽稀算法,这里使用TopologyPreservingSimplifier作为示例 double distanceTolerance = 10.0; // 抽稀的容忍度,根据需要调整 Geometry simplifiedGeometry = TopologyPreservingSimplifier.simplify(originalPolygon, distanceTolerance); // 转换回Polygon类型(如果需要) Polygon simplifiedPolygon = (Polygon) simplifiedGeometry; // 获取简化后的多边形的坐标序列 Coordinate[] coordinates = simplifiedPolygon.getCoordinates(); // 使用自定义Comparator对数组进行排序 // Arrays.sort(coordinates, Comparator.comparing(Coordinate::getX).thenComparing(Coordinate::getY)); // 假设第一个点是起始点 // Coordinate startPoint = coordinates[0]; // // // 使用自定义Comparator对数组进行排序,根据与startPoint的距离升序排序 // Arrays.sort(coordinates, Comparator.comparingDouble(c -> DistanceCalculator.distance(startPoint, c))); Coordinate[] newCoord = sortCoordinatesByNearestDistance(coordinates); // 遍历坐标数组,打印每个坐标点 for (Coordinate coord : newCoord) { coordinatesList.add(coord); } // 使用Set去除重复项 Set set = new HashSet<>(coordinatesList); // 将Set转回List List uniqueCoordinates = new ArrayList<>(set); return uniqueCoordinates; } public static int getSimplifyPolygonsNum(Geometry polygon) { // 使用 TopologyPreservingSimplifier 进行抽稀 double distanceTolerance = 1.0; // 设置抽稀的容忍度,根据实际需要调整 Geometry simplifiedPolygon = TopologyPreservingSimplifier.simplify(polygon, distanceTolerance); return simplifiedPolygon.getNumPoints(); } // 将度转换为弧度 public static double toRadians(double degrees) { return degrees * Math.PI / 180.0; } // 计算两点间的航向角 public static double bearing(double lat1, double lon1, double lat2, double lon2) { double lat1Rad = toRadians(lat1); double lat2Rad = toRadians(lat2); double deltaLonRad = toRadians(lon2 - lon1); double y = Math.sin(deltaLonRad) * Math.cos(lat2Rad); double x = Math.cos(lat1Rad) * Math.sin(lat2Rad) - Math.sin(lat1Rad) * Math.cos(lat2Rad) * Math.cos(deltaLonRad); double bearing = Math.atan2(y, x); // 将结果转换为度 return Math.toDegrees(bearing); } /** * 航线点排序 * * @return */ public static List getRoutePointOrder(List list, double airportLat, double airportLon) { List centros = new ArrayList<>(); List> extremePoints = new ArrayList<>(); AtomicInteger numSize = new AtomicInteger(); for (LotInfo patche : list) { String wkt = patche.getDkfw(); // 解析WKT字符串为多边形 WKTReader wktReader = new WKTReader(JTSFactoryFinder.getGeometryFactory()); Geometry polygon = null; try { polygon = wktReader.read(wkt); } catch (ParseException e) { throw new RuntimeException(e); } // 开始封装中心点坐标 Coordinate coordinateCentro = getCentro(polygon); double distance = DistanceCalculator.calculateDistance(airportLat, airportLon, coordinateCentro.y, coordinateCentro.x); // 机场范围,操作机场范围将不生成 if (distance * 1000 > 7000) { continue; } centros.add(coordinateCentro); // 开始封装图斑4个航线 // List coordinatePointList = getExtremePoints(polygon); // 抽稀拐点 List coordinatePointList = getSimplifyPolygons(polygon); extremePoints.add(coordinatePointList); // points.put(coordinateCentro, coordinatePointList); // 保存稀释拐点之后总数量 numSize.set(numSize.get() + coordinatePointList.size()); } // 开始排序 Coordinate[] coordinates = new Coordinate[centros.size() + 1]; List coordinateList = new ArrayList<>(); coordinates[0] = new Coordinate(airportLon, airportLat); //第一个为机场经纬度 coordinateList.add(new Coordinate(airportLon, airportLat)); //第一个为机场经纬度) for (int i = 1; i < centros.size() + 1; i++) { coordinates[i] = centros.get(i - 1); coordinateList.add(centros.get(i - 1)); } // 方案一:一个图斑按4个航点规划 // // 对中心坐标数组进行排序 // Coordinate[] retCoordinate = new Coordinate[coordinateList.size()]; // Coordinate[] sortedCoordinates = DistanceCalculator.sortByDistance(coordinateList, airportLat, airportLon, 0, retCoordinate); // // // 开始拼接图斑点位--按中心坐标数组排序顺序 // // 长度-3第一个起点只有一个点位 // Coordinate[] retc = new Coordinate[sortedCoordinates.length * 4 - 3]; // // 赋值起点 // retc[0] = sortedCoordinates[0]; // int i = 0; // for (Coordinate num : sortedCoordinates) { // List coordinatePoints = points.get(num); // if (null != coordinatePoints) { // for (int j = 0; j < coordinatePoints.size(); j++) { // // 开始拼接 // retc[i * coordinatePoints.size() + j - 3] = coordinatePoints.get(j); // } // } // // i++; // } // // return retc; // 方案二:抽稀,获取拐点 Coordinate[] retCoordinate = new Coordinate[coordinateList.size()]; List oldCoordinateList = new ArrayList<>(coordinateList); // 获取中心点 Coordinate[] sortedCoordinates = DistanceCalculator.sortByDistance(coordinateList, airportLat, airportLon, 0, retCoordinate); // 开始拼接图斑点位--按中心坐标数组排序顺序 Coordinate[] retc = new Coordinate[numSize.get() + 1]; List retcList = new ArrayList<>(); // 赋值起点 retc[0] = sortedCoordinates[0]; retcList.add(PointPO.builder().index(0).coordinate(sortedCoordinates[0]).build()); List indexs = new ArrayList<>(); // 拿排序前的索引index 根据排序前和排序后的结果匹对------》后期优化 for (int i = 1; i < sortedCoordinates.length; i++) { Coordinate c1 = sortedCoordinates[i]; for (int j = 1; j < oldCoordinateList.size(); j++) { Coordinate c2 = oldCoordinateList.get(j); if (c1.getX() == c2.getX() && c1.getY() == c2.getY()) { indexs.add(j - 1); } } } // 根据排序前的索引按顺序赋值 int i = 0; for (Integer index : indexs) { for (Coordinate coordinate : extremePoints.get(index)) { i = i + 1; retc[i] = coordinate; retcList.add(PointPO.builder().index(index).coordinate(coordinate).centro(centros.get(index)).build()); } } return retcList; } public static void main(String[] args) { //测试 List list = new ArrayList<>(); list.add(LotInfo.builder().dkfw("POLYGON((115.866465564947 28.6344502965542, 115.86425430209 28.6357383285408, 115.864551734716 28.633120921433, 115.866977149064 28.6338435339976, 115.866465564947 28.6344502965542))").build()); list.add(LotInfo.builder().dkfw("POLYGON((115.864006690605 28.6202713913694, 115.86002109342 28.6162025130492, 115.866374254306 28.6142037658042, 115.865912044006 28.6172001020759, 115.864006690605 28.6202713913694))").build()); list.add(LotInfo.builder().dkfw("POLYGON((115.839366933455 28.6161999317332, 115.841288489469 28.6160843601496, 115.840931570318 28.6181544912247, 115.838147600941 28.618654178036, 115.839366933455 28.6161999317332))").build()); list.add(LotInfo.builder().dkfw("POLYGON((115.857499052697 28.6784702230642, 115.859109158101 28.6762273976226, 115.863677723232 28.6766081113836, 115.862154868188 28.6790827508297, 115.857499052697 28.6784702230642))").build()); list.add(LotInfo.builder().dkfw("POLYGON((115.834974056705 28.6659171428962, 115.833760531592 28.6634960413229, 115.832422084777 28.6624550271329, 115.829745191145 28.6631986086972, 115.831232354274 28.6608191476914, 115.833314382654 28.6603729987527, 115.835545127347 28.6618601618814, 115.837032290475 28.6639421902615, 115.834974056705 28.6659171428962))").build()); list.add(LotInfo.builder().dkfw("POLYGON((115.885622116006 28.5766308429787, 115.883936664461 28.5771582901683, 115.883365593819 28.5752547213636, 115.883555950699 28.5740174016407, 115.88365112914 28.5724945465969, 115.885364341064 28.5721138328361, 115.886696839227 28.5725897250371, 115.887458266749 28.5736366878797, 115.886792017668 28.5753498998039, 115.885622116006 28.5766308429787))").build()); list.add(LotInfo.builder().dkfw("POLYGON((115.857644341395 28.5750890964568, 115.857572957565 28.5729475815515, 115.858429563527 28.5728761977213, 115.859072017998 28.5738041875136, 115.859072017998 28.5748035611361, 115.857644341395 28.5750890964568))").build()); list.add(LotInfo.builder().dkfw("POLYGON((115.912181587649 28.6231542087745, 115.912181587649 28.6215123806805, 115.915893546818 28.6212268453598, 115.916036314478 28.6231542087745, 115.912181587649 28.6231542087745))").build()); list.add(LotInfo.builder().dkfw("POLYGON((115.842039042965 28.6314426646115, 115.840992080122 28.631252307731, 115.842324578286 28.6305860586493, 115.843181184248 28.6305860586493, 115.84403779021 28.6304908802091, 115.84394261177 28.6317281999322, 115.842039042965 28.6314426646115))").build()); list.add(LotInfo.builder().dkfw("POLYGON((115.807011889796 28.623935465138, 115.805869748513 28.6224126100944, 115.810247956764 28.6220318963334, 115.809581707682 28.623935465138, 115.807011889796 28.623935465138))").build()); // list.forEach(patche -> { // String wkt = patche.getDkfw(); // // 解析WKT字符串为多边形 // WKTReader wktReader = new WKTReader(JTSFactoryFinder.getGeometryFactory()); // Geometry polygon = null; // try { // polygon = wktReader.read(wkt); // } catch (ParseException e) { // throw new RuntimeException(e); // } // // // 开始封装中心点坐标 // Coordinate coordinateCentro = getCentro(polygon); // // // 开始封装图斑4个航线 //// List coordinatePointList = getExtremePoints(polygon); // List coordinatePointList = getSimplifyPolygons(polygon); // // // }); List pointPOS = getRoutePointOrder(list, 28.624514734, 115.856725497); for (PointPO c : pointPOS) { System.out.println(c); } } }