工具类
复制代码
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
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616/** * @program: * @description 获取两条经纬度线段的交点坐标工具类 * @author: wys * @create: 2020-11-27 09:21 **/ public class GisCheckUtils { private static Logger log = LoggerFactory.getLogger(GisCheckUtils.class); /** * 地球周长 */ private static double L = 6381372 * Math.PI * 2; /** * 平面展开后,x轴等于周长 */ private static double W = L; /** * y轴约等于周长一半 */ private static double H = L / 2; /** * 米勒投影中的一个常数,范围大约在正负2.3之间 */ private static double mill = 2.3; /** * 将经纬度转换成X和Y轴 * 米勒投影算法 * * @param lat 纬度 * @param lon 经度 * @return */ private static Point millierConvertion(double lat, double lon) { // 将经度从度数转换为弧度 double x = lon * Math.PI / 180; // 将纬度从度数转换为弧度 double y = lat * Math.PI / 180; // 米勒投影的转换 y = 1.25 * Math.log(Math.tan(0.25 * Math.PI + 0.4 * y)); // 弧度转为实际距离 x = (W / 2) + (W / (2 * Math.PI)) * x; y = (H / 2) - (H / (2 * mill)) * y; return new Point(x, y); } /** * xy轴转坐标 * * @param x * @param y * @return 坐标点 */ private static Location xyToLocation(double x, double y) { //实际距离 转为弧度 x = (x - (W / 2)) / (W / (2 * Math.PI)); y = -1 * (y - (H / 2)) / (H / (2 * mill)); // 米勒投影的转换反转 y = (Math.atan(Math.pow(Math.E, y / 1.25)) - 0.25 * Math.PI) / 0.4; //将经度从弧度转换为度数 double lon = 180 / Math.PI * x; //将纬度从弧度转换为度数 double lat = 180 / Math.PI * y; return new Location(lon, lat); } /** * 获取两条直线相交的点 * * @param LineOne 线段一 * @param LineTwo 线段二 * @return 相交点坐标 为null 不相交 */ public static Location getIntersectPoint(Line LineOne, Line LineTwo) { //先判断有没有相交 (延长线不算) 不相交返回null 相交执行获取交点坐标 (如需获取延长线交点注释此方法)---- if (!segIntersect(LineOne, LineTwo)) { return null; } //转换对象 Point[] points = LineToPoint(LineOne, LineTwo); //获取两条直线相交的点 Point Location = getIntersectPoint(points[0], points[1], points[2], points[3]); if (Location != null) { return xyToLocation(Location.x, Location.y); } return null; } /** * 获取两条直线list所有相交的点 * * @param LineOneList 线段集合一 * @param LineTwoList 线段集合二 * @return 相交点坐标 为null 不相交 */ public static List<Location> getIntersectPointList(List<Line> LineOneList, List<Line> LineTwoList) { List<Location> locationList = new ArrayList<>(); for (Line line : LineOneList) { for (Line line1 : LineTwoList) { Location location = getIntersectPoint(line,line1); if (Objects.nonNull(location)) { locationList.add(location); } } } return locationList; } /** * 获取两条直线相交的点 * * @param p1 线段一 开始点 * @param p2 线段一 结束点 * @param p3 线段二 开始点 * @param p4 线段二 结束点 * @return */ public static Point getIntersectPoint(Point p1, Point p2, Point p3, Point p4) { double A1 = p1.getY() - p2.getY(); double B1 = p2.getX() - p1.getX(); double C1 = A1 * p1.getX() + B1 * p1.getY(); double A2 = p3.getY() - p4.getY(); double B2 = p4.getX() - p3.getX(); double C2 = A2 * p3.getX() + B2 * p3.getY(); double det_k = A1 * B2 - A2 * B1; if (Math.abs(det_k) < 0.00001) { return null; } double a = B2 / det_k; double b = -1 * B1 / det_k; double c = -1 * A2 / det_k; double d = A1 / det_k; double x = a * C1 + b * C2; double y = c * C1 + d * C2; return new Point(x, y); } /** * 验证两条线有没有相交 * * @param LineOne 线段1 * @param LineTwo 线段2 * @return true 相交 */ public static boolean segIntersect(Line LineOne, Line LineTwo) { //转换对象 Point[] points = LineToPoint(LineOne, LineTwo); //验证两条线有没有相交 return segIntersect(points[0], points[1], points[2], points[3]) > 0; } /** * 线段转换为点对象 * * @param LineOne 线段一 * @param LineTwo 线段二 * @return 点对象数组 */ private static Point[] LineToPoint(Line LineOne, Line LineTwo) { //线段1 Double oneStartLat = LineOne.getStartLocation().getLat(); Double oneStartLon = LineOne.getStartLocation().getLon(); Double oneEndLat = LineOne.getEndLocation().getLat(); Double oneEndLon = LineOne.getEndLocation().getLon(); // 线段2 Double twoStartLat = LineTwo.getStartLocation().getLat(); Double twoStartLon = LineTwo.getStartLocation().getLon(); Double twoEndLat = LineTwo.getEndLocation().getLat(); Double twoEndLon = LineTwo.getEndLocation().getLon(); Point[] points = new Point[4]; //将经纬度转换成X和Y轴 points[0] = millierConvertion(oneStartLat, oneStartLon); points[1] = millierConvertion(oneEndLat, oneEndLon); points[2] = millierConvertion(twoStartLat, twoStartLon); points[3] = millierConvertion(twoEndLat, twoEndLon); return points; } /** * 验证两条线有没有相交 * * @param A 线段一 开始点 * @param B 线段一 结束点 * @param C 线段二 开始点 * @param D 线段二 结束点 * @return */ public static int segIntersect(Point A, Point B, Point C, Point D) { Point intersection = new Point(); if (Math.abs(B.getY() - A.getY()) + Math.abs(B.getX() - A.getX()) + Math.abs(D.getY() - C.getY()) + Math.abs(D.getX() - C.getX()) == 0) { if ((C.getX() - A.getX()) + (C.getY() - A.getY()) == 0) { log.info("ABCD是同一个点!"); } else { log.info("AB是一个点,CD是一个点,且AC不同!"); } return 0; } if (Math.abs(B.getY() - A.getY()) + Math.abs(B.getX() - A.getX()) == 0) { if ((A.getX() - D.getX()) * (C.getY() - D.getY()) - (A.getY() - D.getY()) * (C.getX() - D.getX()) == 0) { log.info("A、B是一个点,且在CD线段上!"); } else { log.info("A、B是一个点,且不在CD线段上!"); } return 0; } if (Math.abs(D.getY() - C.getY()) + Math.abs(D.getX() - C.getX()) == 0) { if ((D.getX() - B.getX()) * (A.getY() - B.getY()) - (D.getY() - B.getY()) * (A.getX() - B.getX()) == 0) { log.info("C、D是一个点,且在AB线段上!"); } else { log.info("C、D是一个点,且不在AB线段上!"); } return 0; } if ((B.getY() - A.getY()) * (C.getX() - D.getX()) - (B.getX() - A.getX()) * (C.getY() - D.getY()) == 0) { log.info("线段平行,无交点!"); return 0; } intersection .setX(((B.getX() - A.getX()) * (C.getX() - D.getX()) * (C.getY() - A.getY()) - C.getX() * (B.getX() - A.getX()) * (C.getY() - D.getY()) + A .getX() * (B.getY() - A.getY()) * (C.getX() - D.getX())) / ((B.getY() - A.getY()) * (C.getX() - D.getX()) - (B .getX() - A.getX()) * (C.getY() - D.getY()))); intersection .setY(((B.getY() - A.getY()) * (C.getY() - D.getY()) * (C.getX() - A.getX()) - C.getY() * (B.getY() - A.getY()) * (C.getX() - D.getX()) + A .getY() * (B.getX() - A.getX()) * (C.getY() - D.getY())) / ((B.getX() - A.getX()) * (C.getY() - D.getY()) - (B .getY() - A.getY()) * (C.getX() - D.getX()))); if ((intersection.getX() - A.getX()) * (intersection.getX() - B.getX()) <= 0 && (intersection.getX() - C.getX()) * (intersection.getX() - D.getX()) <= 0 && (intersection.getY() - A.getY()) * (intersection.getY() - B.getY()) <= 0 && (intersection.getY() - C.getY()) * (intersection.getY() - D.getY()) <= 0) { if ((A.getX() == C.getX() && A.getY() == C.getY()) || (A.getX() == D.getX() && A.getY() == D.getY()) || (B.getX() == C.getX() && B.getY() == C.getY()) || (B.getX() == D.getX() && B.getY() == D.getY())) { log.info("线段相交于端点上"); return 2; } else { log.info("线段相交于点(" + intersection.getX() + "," + intersection.getY() + ")!"); //相交 return 1; } } else { log.info("线段相交于虚交点(" + intersection.getX() + "," + intersection.getY() + ")!"); //相交但不在线段上 return -1; } } /** * 点对象 */ public static class Point { private double x; private double y; public Point() { } public Point(double x, double y) { this.x = x; this.y = y; } @Override public String toString() { return x + ","+ y ; } public double getX() { return x; } public void setX(double x) { this.x = x; } public double getY() { return y; } public void setY(double y) { this.y = y; } } /** * 球面积计算公式 * * @param locationList * @return */ public static double calculatePolygonArea(List<Location> locationList) { double area = 0; int size = locationList.size(); if (size > 2) { double LowX = 0.0; double LowY = 0.0; double MiddleX = 0.0; double MiddleY = 0.0; double HighX = 0.0; double HighY = 0.0; double AM = 0.0; double BM = 0.0; double CM = 0.0; double AL = 0.0; double BL = 0.0; double CL = 0.0; double AH = 0.0; double BH = 0.0; double CH = 0.0; double CoefficientL = 0.0; double CoefficientH = 0.0; double ALtangent = 0.0; double BLtangent = 0.0; double CLtangent = 0.0; double AHtangent = 0.0; double BHtangent = 0.0; double CHtangent = 0.0; double ANormalLine = 0.0; double BNormalLine = 0.0; double CNormalLine = 0.0; double OrientationValue = 0.0; double AngleCos = 0.0; double Sum1 = 0.0; double Sum2 = 0.0; double Count2 = 0; double Count1 = 0; double Sum = 0.0; double Radius = 6378000; for (int i = 0; i < size; i++) { if (i == 0) { LowX = locationList.get(size - 1).getLon() * Math.PI / 180; LowY = locationList.get(size - 1).getLat() * Math.PI / 180; MiddleX = locationList.get(0).getLon() * Math.PI / 180; MiddleY = locationList.get(0).getLat() * Math.PI / 180; HighX = locationList.get(1).getLon() * Math.PI / 180; HighY = locationList.get(1).getLat() * Math.PI / 180; } else if (i == size - 1) { LowX = locationList.get(size - 2).getLon() * Math.PI / 180; LowY = locationList.get(size - 2).getLat() * Math.PI / 180; MiddleX = locationList.get(size - 1).getLon() * Math.PI / 180; MiddleY = locationList.get(size - 1).getLat() * Math.PI / 180; HighX = locationList.get(0).getLon() * Math.PI / 180; HighY = locationList.get(0).getLat() * Math.PI / 180; } else { LowX = locationList.get(i - 1).getLon() * Math.PI / 180; LowY = locationList.get(i - 1).getLat() * Math.PI / 180; MiddleX = locationList.get(i).getLon() * Math.PI / 180; MiddleY = locationList.get(i).getLat() * Math.PI / 180; HighX = locationList.get(i + 1).getLon() * Math.PI / 180; HighY = locationList.get(i + 1).getLat() * Math.PI / 180; } AM = Math.cos(MiddleY) * Math.cos(MiddleX); BM = Math.cos(MiddleY) * Math.sin(MiddleX); CM = Math.sin(MiddleY); AL = Math.cos(LowY) * Math.cos(LowX); BL = Math.cos(LowY) * Math.sin(LowX); CL = Math.sin(LowY); AH = Math.cos(HighY) * Math.cos(HighX); BH = Math.cos(HighY) * Math.sin(HighX); CH = Math.sin(HighY); CoefficientL = (AM * AM + BM * BM + CM * CM) / (AM * AL + BM * BL + CM * CL); CoefficientH = (AM * AM + BM * BM + CM * CM) / (AM * AH + BM * BH + CM * CH); ALtangent = CoefficientL * AL - AM; BLtangent = CoefficientL * BL - BM; CLtangent = CoefficientL * CL - CM; AHtangent = CoefficientH * AH - AM; BHtangent = CoefficientH * BH - BM; CHtangent = CoefficientH * CH - CM; AngleCos = (AHtangent * ALtangent + BHtangent * BLtangent + CHtangent * CLtangent) / ( Math.sqrt(AHtangent * AHtangent + BHtangent * BHtangent + CHtangent * CHtangent) * Math.sqrt(ALtangent * ALtangent + BLtangent * BLtangent + CLtangent * CLtangent)); AngleCos = Math.acos(AngleCos); ANormalLine = BHtangent * CLtangent - CHtangent * BLtangent; BNormalLine = 0 - (AHtangent * CLtangent - CHtangent * ALtangent); CNormalLine = AHtangent * BLtangent - BHtangent * ALtangent; if (AM != 0) { OrientationValue = ANormalLine / AM; } else if (BM != 0) { OrientationValue = BNormalLine / BM; } else { OrientationValue = CNormalLine / CM; } if (OrientationValue > 0) { Sum1 += AngleCos; Count1++; } else { Sum2 += AngleCos; Count2++; //Sum +=2*Math.PI-AngleCos; } } if (Sum1 > Sum2) { Sum = Sum1 + (2 * Math.PI * Count2 - Sum2); } else { Sum = (2 * Math.PI * Count1 - Sum1) + Sum2; } //平方米 area = (Sum - (size - 2) * Math.PI) * Radius * Radius; } return Math.abs(area); } /** * 求重合面积 * * @param circleList * @param locationList * @return */ private static double CoincidentArea(List<Location> circleList, List<Location> locationList) { List<Location> areaList = new ArrayList<>(); //先处理所有的点,防止顺序不对 circleList = sortLocation(circleList); locationList = sortLocation(locationList); //获取圈地线段 List<Line> circleLineList = getLines(circleList); //获取线段 List<Line> lineList = getLines(locationList); //判断是否相交 boolean isIntersect = isIntersect(circleLineList, lineList); if (isIntersect) { areaList = GisCheckUtils.getIntersectPointList(circleLineList, lineList); //判断圈地的点是否在范围内 for (Location location : circleList) { boolean isPointInPolygon = isPointInPolygon(location, locationList); if (isPointInPolygon){ areaList.add(location); } } //判断是否在圈地的点范围内 for (Location location : locationList) { boolean isPointInPolygon = isPointInPolygon(location, circleList); if (isPointInPolygon) { areaList.add(location); } } double area = GisCheckUtils.calculatePolygonArea(sortLocation(areaList)); log.info("重合区域面积为: " + area + "平方米"); return area; } //如果不相交判断是否包含-由于没有相交线段只要存在点在多边形内就说明包含 //先判断圈地是否被包含 boolean isPointInPolygon = isPolygonInPolygon(circleList,locationList); if (isPointInPolygon) { double area = GisCheckUtils.calculatePolygonArea(circleList); log.info("重合区域面积为: " + area + "平方米"); return area; } //如果不相交判断是否包含-由于没有相交线段只要存在点在多边形内就说明包含 //再判断圈地是否包含 isPointInPolygon = isPolygonInPolygon(locationList,circleList); if (isPointInPolygon) { double area = GisCheckUtils.calculatePolygonArea(locationList); log.info("重合区域面积为: " + area + "平方米"); return area; } return 0; } /** * 判断第一个多边形是否存在一个点在第二个多边形内 * * @param locationList1 * @param locationList2 * @return */ private static boolean isPolygonInPolygon(List<Location> locationList1, List<Location> locationList2) { //判断第一个多边形是否在第二个多边形内 for (Location location : locationList1) { boolean isPointInPolygon = isPointInPolygon(location, locationList2); if (isPointInPolygon) return true; } return false; } /** * 判断第一个多边形是否全部在第二个多边形内 * * @param locationList1 * @param locationList2 * @return */ private static boolean isPolygonAllInPolygon(List<Location> locationList1, List<Location> locationList2) { //判断第一个多边形是否在第二个多边形内 for (Location location : locationList1) { boolean isPointInPolygon = isPointInPolygon(location, locationList2); if (!isPointInPolygon) return false; } return true; } /** * 判断点是否在多边形内 * * @param location * @param locationList2 * @return */ private static boolean isPointInPolygon(Location location, List<Location> locationList2) { //点是否在多边形内 GeneralPath path = new GeneralPath(); //设定多边形起始点 path.moveTo(locationList2.get(0).getLon(), locationList2.get(0).getLat()); for (Location l : locationList2) { path.lineTo(l.getLon(), l.getLat()); } //图像完成,封闭 path.moveTo(locationList2.get(0).getLon(), locationList2.get(0).getLat()); //多边形结束 path.closePath(); return path.contains(location.getLon(), location.getLat()); } /** * 判断线段是否相交 * * @param lineList * @param lineList2 * @return */ private static boolean isIntersect(List<Line> lineList, List<Line> lineList2) { for (Line line : lineList) { for (Line line1 : lineList2) { //两条线段是否相交 boolean b = Line2D.linesIntersect(line.getStartLocation().getLon(), line.getStartLocation().getLat(), line.getEndLocation().getLon(), line.getEndLocation().getLat(), line1.getStartLocation().getLon(), line1.getStartLocation().getLat(), line1.getEndLocation().getLon(), line1.getEndLocation().getLat()); if (b) { return true; } } } return false; } /** * 根据点获取线段 * * @param locationList * @return */ private static List<Line> getLines(List<Location> locationList) { List<Line> lineList = new ArrayList(); for (int i = 0; i < locationList.size(); i++) { if (i < locationList.size() - 1) { Location l = locationList.get(i); Location l2 = locationList.get(i + 1); Line line = new Line(l, l2); lineList.add(line); } else { Location l = locationList.get(i); Location l2 = locationList.get(0); Line line = new Line(l, l2); lineList.add(line); } } return lineList; } /** * 将多边形的点排序 * * @param locationList * @return */ private static List<Location> sortLocation(List<Location> locationList) { double plusX = 0, plusY = 0; for (Location location : locationList) { plusX += location.getLon(); plusY += location.getLat(); } Location location = new Location(plusX / locationList.size(), plusY / locationList.size()); Map<Integer,List> mapAll = new HashMap<>(); for (int i = 0; i < locationList.size(); i++) { //第一个放经纬度 第二个放角度 List objList = new ArrayList<>(); objList.add(locationList.get(i)); objList.add(getAngle1(location.getLat(), location.getLon(), locationList.get(i).getLat(), locationList.get(i).getLon())); mapAll.put(i, objList); } List temp = new ArrayList<>(); int size = mapAll.size(); for (int i = 0; i < size - 1; i++) { for (int j = 0; j < size - 1 - i; j++) { if (Double.parseDouble(mapAll.get(j).get(1).toString()) > Double.parseDouble(mapAll.get(j + 1).get(1).toString())) //交换两数位置 { temp = mapAll.get(j); mapAll.put(j, mapAll.get(j + 1)); mapAll.put(j + 1, temp); } } } //生成新的顺时针的坐标点集合 locationList.clear(); for (Integer integer : mapAll.keySet()) { if (mapAll.get(integer).get(0) instanceof Location) { locationList.add((Location) mapAll.get(integer).get(0)); } } return locationList; } /** * 将多边形的点排序 * * @param lat_a 纬度1 * @param lng_a 经度1 * @param lat_b 纬度2 * @param lng_b 经度2 * @return */ private static double getAngle1(double lat_a, double lng_a, double lat_b, double lng_b) { double y = Math.sin(lng_b - lng_a) * Math.cos(lat_b); double x = Math.cos(lat_a) * Math.sin(lat_b) - Math.sin(lat_a) * Math.cos(lat_b) * Math.cos(lng_b - lng_a); double brng = Math.atan2(y, x); brng = Math.toDegrees(brng); if (brng < 0) brng = brng + 360; return brng; } }
点坐标实体类
复制代码
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/** * 经纬度坐标实体类 * */ public class Location { private double lon; private double lat; public Location() { } public Location(double lon, double lat) { this.lon = lon; this.lat = lat; } public double getLon() { return lon; } public void setLon(double lon) { this.lon = lon; } public double getLat() { return lat; } public void setLat(double lat) { this.lat = lat; } }
线段实体类
复制代码
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
29public class Line { private Location startLocation;//起点 private Location endLocation;//终点 public Line() { } public Line(Location startLocation, Location endLocation) { this.startLocation = startLocation; this.endLocation = endLocation; } public Location getStartLocation() { return startLocation; } public void setStartLocation(Location startLocation) { this.startLocation = startLocation; } public Location getEndLocation() { return endLocation; } public void setEndLocation(Location endLocation) { this.endLocation = endLocation; } @Override public String toString() { return "Line{" + "startLocation=" + startLocation + ", endLocation=" + endLocation + '}'; } }
最后
以上就是甜美酒窝最近收集整理的关于通过经纬度判断两个多边形是否相交或重合,并获取重合面积的全部内容,更多相关通过经纬度判断两个多边形是否相交或重合内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复