rain
2024-08-14 ea73b6fb3ad0b34e4d856321afecae5ada1091fe
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
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<Coordinate> getExtremePoints(Geometry geometry) {
        List<Coordinate> 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<Coordinate> coordinateList = new ArrayList<>(Arrays.asList(coordinates));
 
        // 排序后的坐标列表
        List<Coordinate> 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<Coordinate> 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<Coordinate> set = new HashSet<>(coordinatesList);
 
        // 将Set转回List
        List<Coordinate> 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<PointPO> getRoutePointOrder(List<LotInfo> list, double airportLat, double airportLon) {
        List<Coordinate> centros = new ArrayList<>();
        List<List<Coordinate>> 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<Coordinate> coordinatePointList = getExtremePoints(polygon);
            // 抽稀拐点
            List<Coordinate> coordinatePointList = getSimplifyPolygons(polygon);
            extremePoints.add(coordinatePointList);
//            points.put(coordinateCentro, coordinatePointList);
 
            // 保存稀释拐点之后总数量
            numSize.set(numSize.get() + coordinatePointList.size());
        }
 
 
        // 开始排序
        Coordinate[] coordinates = new Coordinate[centros.size() + 1];
        List<Coordinate> 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<Coordinate> 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<Coordinate> oldCoordinateList = new ArrayList<>(coordinateList);
 
        // 获取中心点
        Coordinate[] sortedCoordinates = DistanceCalculator.sortByDistance(coordinateList, airportLat, airportLon, 0, retCoordinate);
 
        // 开始拼接图斑点位--按中心坐标数组排序顺序
        Coordinate[] retc = new Coordinate[numSize.get() + 1];
        List<PointPO> retcList = new ArrayList<>();
 
        // 赋值起点
        retc[0] = sortedCoordinates[0];
        retcList.add(PointPO.builder().index(0).coordinate(sortedCoordinates[0]).build());
        List<Integer> 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<LotInfo> 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<Coordinate> coordinatePointList = getExtremePoints(polygon);
//            List<Coordinate> coordinatePointList = getSimplifyPolygons(polygon);
//
//
//        });
 
 
        List<PointPO> pointPOS = getRoutePointOrder(list, 28.624514734, 115.856725497);
 
        for (PointPO c :
                pointPOS) {
            System.out.println(c);
        }
 
 
    }
 
}