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<Coordinate> 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<Coordinate> 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<String> points = coordinates.stream()
|
.map(Coordinate::toLatLngString)
|
.collect(Collectors.toList());
|
return String.format("LINESTRING(%s, %s)", points.get(0), points.get(1));
|
} else {
|
// 面(多边形)
|
List<String> 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<Coordinate> toCoordinates(String wkt) {
|
List<Coordinate> 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<Coordinate> 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<Coordinate> 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<Coordinate> coordinates) {
|
if (CollectionUtils.isEmpty(coordinates)) {
|
throw new RuntimeException("坐标集合不能为空");
|
}
|
|
for (Coordinate coord : coordinates) {
|
if (!coord.isValid()) {
|
throw new RuntimeException("无效坐标");
|
}
|
}
|
}
|
}
|