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}; } }