liujie
2026-06-09 c96fbe6b0aeb413a17c429133ee6d81d138144b9
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
package com.xiaopeng.map.utils;
 
import lombok.extern.slf4j.Slf4j;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.LinearRing;
import org.locationtech.jts.geom.Polygon;
import org.springframework.stereotype.Component;
 
@Component
@Slf4j
public class PolygonOverlapService {
    
    /**
     * 检查两个多边形是否重叠
     * @param polygon1Points 多边形1的坐标点 "lng1_lat1,lng2_lat2,..."
     * @param polygon2Points 多边形2的坐标点 "lng1_lat1,lng2_lat2,..."
     * @return 是否重叠
     */
    public boolean checkPolygonOverlap(String polygon1Points, String polygon2Points) {
        try {
            Polygon polygon1 = createPolygonFromPoints(polygon1Points);
            Polygon polygon2 = createPolygonFromPoints(polygon2Points);
            
            // 使用 JTS 库判断多边形是否相交
            return polygon1.intersects(polygon2);
        } catch (Exception e) {
            log.error("多边形重叠检测失败", e);
            return false; // 发生错误时默认不重叠,可根据业务需要调整
        }
    }
    
    /**
     * 从坐标点字符串创建多边形
     * @param pointsStr 坐标点字符串 "lng1_lat1,lng2_lat2,lng3_lat3,..."
     * @return JTS Polygon 对象
     */
    private Polygon createPolygonFromPoints(String pointsStr) {
        if (!pointsStr.contains(",")) {
            throw new IllegalArgumentException("无效的坐标点格式");
        }
        
        String[] pointPairs = pointsStr.split(",");
        Coordinate[] coordinates = new Coordinate[pointPairs.length + 1]; // +1 是为了闭合多边形
        
        for (int i = 0; i < pointPairs.length; i++) {
            String[] lngLat = pointPairs[i].trim().split("_");
            if (lngLat.length != 2) {
                throw new IllegalArgumentException("坐标点格式错误: " + pointPairs[i]);
            }
            
            double lng = Double.parseDouble(lngLat[0]);
            double lat = Double.parseDouble(lngLat[1]);
            coordinates[i] = new Coordinate(lng, lat);
        }
        
        // 闭合多边形,最后一个点与第一个点相同
        coordinates[coordinates.length - 1] = coordinates[0];
        
        GeometryFactory geometryFactory = new GeometryFactory();
        LinearRing linearRing = geometryFactory.createLinearRing(coordinates);
        return geometryFactory.createPolygon(linearRing);
    }
 
 
    /**
     * 判断一个坐标点位是否在一个坐标区域内
     * @param longitude 经度
     * @param latitude 纬度
     * @param fencePoints 围栏点位字符串,格式为 "lng1_lat1,lng2_lat2,..."
     * @return 是否在区域内 true在 false不在
     */
    public boolean isPointInPolygon(double longitude, double latitude, String fencePoints) {
        if (fencePoints == null || fencePoints.trim().isEmpty()) {
            return false;
        }
 
        // 解析围栏点位
        String[] points = fencePoints.split(",");
        if (points.length < 3) {
            return false;
        }
 
        int n = points.length;
        boolean inside = false;
 
        double x = longitude, y = latitude;
        double[] xs = new double[n];
        double[] ys = new double[n];
 
        for (int i = 0; i < n; i++) {
            String[] coords = points[i].split("_");
            if (coords.length != 2) {
                continue;
            }
            try {
                xs[i] = Double.parseDouble(coords[0]);
                ys[i] = Double.parseDouble(coords[1]);
            } catch (NumberFormatException e) {
                return false;
            }
        }
 
        // 使用射线法判断点是否在多边形内
        for (int i = 0, j = n - 1; i < n; j = i++) {
            if (((ys[i] > y) != (ys[j] > y)) &&
                    (x < (xs[j] - xs[i]) * (y - ys[i]) / (ys[j] - ys[i]) + xs[i])) {
                inside = !inside;
            }
        }
 
        return inside;
    }
 
 
    /**
     * 判断一个坐标区域(多边形A)是否完全在另一个坐标区域(多边形B)内
     * 原理:如果多边形A的所有顶点都在多边形B内,则认为A在B内
     * @param innerFencePoints 内部围栏点位字符串(待判断是否在外的围栏),格式为 "lng1_lat1,lng2_lat2,..."
     * @param outerFencePoints 外部围栏点位字符串(参考围栏),格式为 "lng1_lat1,lng2_lat2,..."
     * @return 是否在内 true在内 false不在
     */
 
    public boolean isPolygonInPolygon(String innerFencePoints, String outerFencePoints) {
        if (innerFencePoints == null || innerFencePoints.trim().isEmpty()
                || outerFencePoints == null || outerFencePoints.trim().isEmpty()) {
            return false;
        }
 
        // 解析内部围栏点位
        String[] innerPoints = innerFencePoints.split(",");
        if (innerPoints.length < 3) {
            return false;
        }
 
        // 检查内部围栏的每一个顶点是否都在外部围栏内
        for (String pointStr : innerPoints) {
            String[] coords = pointStr.split("_");
            if (coords.length != 2) {
                continue;
            }
            try {
                double lon = Double.parseDouble(coords[0]);
                double lat = Double.parseDouble(coords[1]);
 
                // 如果有一个顶点不在外部围栏内,则整个区域不在内部
                if (!isPointInPolygon(lon, lat, outerFencePoints)) {
                    return false;
                }
            } catch (NumberFormatException e) {
                return false;
            }
        }
 
        return true;
    }
 
 
    /**
     * 根据围栏点位字符串计算中心点坐标
     * @param fencePoints 围栏点位字符串,格式为 "lng1_lat1,lng2_lat2,..."
     * @return double[0] 经度, double[1] 纬度
     */
    public double[] calculateCenterPoint(String fencePoints) {
        if (fencePoints == null || fencePoints.trim().isEmpty()) {
            return new double[]{0.0, 0.0};
        }
 
        String[] points = fencePoints.split(",");
        if (points.length == 0) {
            return new double[]{0.0, 0.0};
        }
 
        double sumLon = 0.0;
        double sumLat = 0.0;
        int count = 0;
 
        for (String point : points) {
            String[] coords = point.split("_");
            if (coords.length == 2) {
                try {
                    double lon = Double.parseDouble(coords[0]);
                    double lat = Double.parseDouble(coords[1]);
                    sumLon += lon;
                    sumLat += lat;
                    count++;
                } catch (NumberFormatException e) {
                    // 忽略解析错误的点
                }
            }
        }
 
        if (count == 0) {
            return new double[]{0.0, 0.0};
        }
 
        double centerLon = sumLon / count;
        double centerLat = sumLat / count;
 
        return new double[]{centerLon, centerLat};
    }
 
 
 
 
}