package com.ard.data.region.utils; import com.ard.data.region.domain.Coordinate; import org.springframework.util.CollectionUtils; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; /** * 区域坐标工具类 * * @author ruoyi */ public class RegionCoordinateUtils { /** * 根据坐标数量自动判断区域类型 * * @param coordinates 坐标集合 * @return POINT/LINE/POLYGON */ public static String getRegionTypeByCoordinates(List coordinates) { if (CollectionUtils.isEmpty(coordinates)) { throw new RuntimeException("坐标集合不能为空"); } int size = coordinates.size(); if (size == 1) { return "POINT"; } else if (size == 2) { return "LINE"; } else { return "POLYGON"; } } /** * 将坐标集合转换为 WKT 格式(自动判断类型) */ public static String toWkt(List coordinates) { if (CollectionUtils.isEmpty(coordinates)) { throw new RuntimeException("坐标集合不能为空"); } int size = coordinates.size(); if (size == 1) { // 点 Coordinate coord = coordinates.get(0); return String.format("POINT(%s)", coord.toLatLngString()); } else if (size == 2) { // 线 List points = coordinates.stream() .map(Coordinate::toLatLngString) .collect(Collectors.toList()); return String.format("LINESTRING(%s, %s)", points.get(0), points.get(1)); } else { // 面(多边形) List points = coordinates.stream() .map(Coordinate::toLatLngString) .collect(Collectors.toList()); String allPoints = String.join(", ", points); String firstPoint = points.get(0); return String.format("POLYGON((%s, %s))", allPoints, firstPoint); } } /** * 将 WKT 字符串转换为坐标集合 * * @param wkt 如:POLYGON((45.718839 126.670721, 45.708756 126.670151, ...)) * @return 坐标集合 */ public static List toCoordinates(String wkt) { List coordinates = new ArrayList<>(); if (wkt == null || wkt.isEmpty()) { return coordinates; } // 提取括号内的坐标字符串 String coordStr = wkt; if (wkt.startsWith("POLYGON")) { coordStr = wkt.substring(wkt.indexOf("((") + 2, wkt.lastIndexOf("))")); } else if (wkt.startsWith("LINESTRING")) { coordStr = wkt.substring(wkt.indexOf("(") + 1, wkt.lastIndexOf(")")); } else if (wkt.startsWith("POINT")) { coordStr = wkt.substring(wkt.indexOf("(") + 1, wkt.lastIndexOf(")")); } // 分割坐标点 String[] points = coordStr.split(","); for (String point : points) { String[] lngLat = point.trim().split(" "); if (lngLat.length >= 2) { Double lat = Double.parseDouble(lngLat[0]); Double lng = Double.parseDouble(lngLat[1]); coordinates.add(new Coordinate(lng, lat)); } } return coordinates; } /** * 计算中心点 */ public static Coordinate calculateCenter(List coordinates) { if (CollectionUtils.isEmpty(coordinates)) { return null; } double sumLng = 0; double sumLat = 0; for (Coordinate coord : coordinates) { sumLng += coord.getLng(); sumLat += coord.getLat(); } return new Coordinate(sumLng / coordinates.size(), sumLat / coordinates.size()); } /** * 计算面积(仅面类型有效) */ public static double calculateArea(List coordinates) { if (coordinates == null || coordinates.size() < 3) { return 0; } double area = 0; int n = coordinates.size(); for (int i = 0; i < n; i++) { Coordinate current = coordinates.get(i); Coordinate next = coordinates.get((i + 1) % n); area += current.getLng() * next.getLat() - next.getLng() * current.getLat(); } area = Math.abs(area) / 2; double lat = coordinates.get(0).getLat(); double meterPerDegree = 111000 * Math.cos(Math.toRadians(lat)); return area * meterPerDegree * 111000; } /** * 验证坐标集合 */ public static void validateCoordinates(List coordinates) { if (CollectionUtils.isEmpty(coordinates)) { throw new RuntimeException("坐标集合不能为空"); } for (Coordinate coord : coordinates) { if (!coord.isValid()) { throw new RuntimeException("无效坐标"); } } } }