2025-12-30 09:26:52 +08:00
|
|
|
|
package com.cdzy.operations.handler;
|
|
|
|
|
|
|
|
|
|
|
|
import com.fasterxml.jackson.core.JsonGenerator;
|
|
|
|
|
|
import com.fasterxml.jackson.databind.JsonSerializer;
|
|
|
|
|
|
import com.fasterxml.jackson.databind.SerializerProvider;
|
|
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
|
import org.locationtech.jts.geom.Coordinate;
|
|
|
|
|
|
import org.locationtech.jts.geom.LinearRing;
|
|
|
|
|
|
import org.locationtech.jts.geom.Polygon;
|
|
|
|
|
|
import org.locationtech.jts.io.WKTWriter;
|
|
|
|
|
|
|
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* JTS Polygon 序列化器 - 将 Polygon 序列化为 JSON
|
|
|
|
|
|
* 生成与 PGpolygonSerializer 相同的 JSON 格式
|
|
|
|
|
|
*/
|
|
|
|
|
|
@Slf4j
|
|
|
|
|
|
public class PolygonSerializer extends JsonSerializer<Polygon> {
|
|
|
|
|
|
|
|
|
|
|
|
private final WKTWriter wktWriter = new WKTWriter();
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
2026-01-06 09:14:23 +08:00
|
|
|
|
public void serialize(Polygon polygon, JsonGenerator gen, SerializerProvider serializers)
|
2025-12-30 09:26:52 +08:00
|
|
|
|
throws IOException {
|
|
|
|
|
|
if (polygon == null) {
|
|
|
|
|
|
gen.writeNull();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 获取多边形的外环坐标
|
|
|
|
|
|
Coordinate[] coordinates = getPolygonCoordinates(polygon);
|
|
|
|
|
|
|
|
|
|
|
|
if (coordinates.length == 0) {
|
|
|
|
|
|
log.warn("警告: 多边形没有有效坐标");
|
|
|
|
|
|
gen.writeNull();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否有无效坐标
|
|
|
|
|
|
for (int i = 0; i < coordinates.length; i++) {
|
|
|
|
|
|
Coordinate coord = coordinates[i];
|
|
|
|
|
|
if (coord == null || Double.isNaN(coord.x) || Double.isNaN(coord.y)) {
|
|
|
|
|
|
log.error("错误: 第 {} 个坐标无效: {}", i, coord);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 序列化为自定义格式(与 PGpolygonSerializer 格式一致)
|
|
|
|
|
|
gen.writeStartObject();
|
|
|
|
|
|
gen.writeStringField("type", "polygon");
|
|
|
|
|
|
|
|
|
|
|
|
gen.writeArrayFieldStart("coordinates");
|
|
|
|
|
|
for (int i = 0; i < coordinates.length; i++) {
|
|
|
|
|
|
Coordinate coord = coordinates[i];
|
|
|
|
|
|
if (coord == null || Double.isNaN(coord.x) || Double.isNaN(coord.y)) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
gen.writeStartArray();
|
|
|
|
|
|
// 使用格式化器避免科学计数法
|
|
|
|
|
|
gen.writeNumber(formatCoordinate(coord.x));
|
|
|
|
|
|
gen.writeNumber(formatCoordinate(coord.y));
|
|
|
|
|
|
gen.writeEndArray();
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
throw new IOException("序列化坐标 " + i + " 失败", e);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
gen.writeEndArray();
|
|
|
|
|
|
gen.writeEndObject();
|
|
|
|
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
log.error("!!! PolygonSerializer 序列化失败 !!!");
|
|
|
|
|
|
log.error("错误信息: {}", e.getMessage());
|
|
|
|
|
|
// 尝试备用序列化方式
|
|
|
|
|
|
try {
|
|
|
|
|
|
serializeAsWKT(polygon, gen);
|
|
|
|
|
|
} catch (Exception e2) {
|
|
|
|
|
|
throw new IOException("Polygon 序列化失败: " + e.getMessage(), e);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public Class<Polygon> handledType() {
|
|
|
|
|
|
return Polygon.class;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取多边形的坐标(仅外环,忽略孔洞)
|
|
|
|
|
|
*/
|
|
|
|
|
|
private Coordinate[] getPolygonCoordinates(Polygon polygon) throws IOException {
|
|
|
|
|
|
if (polygon == null || polygon.isEmpty()) {
|
|
|
|
|
|
return new Coordinate[0];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 获取外环
|
2026-01-06 09:14:23 +08:00
|
|
|
|
LinearRing exteriorRing = polygon.getExteriorRing();
|
2025-12-30 09:26:52 +08:00
|
|
|
|
if (exteriorRing == null) {
|
|
|
|
|
|
throw new IOException("多边形外环为空");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return exteriorRing.getCoordinates();
|
2026-01-06 09:14:23 +08:00
|
|
|
|
|
2025-12-30 09:26:52 +08:00
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
throw new IOException("获取多边形坐标失败: " + e.getMessage(), e);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 格式化坐标值
|
|
|
|
|
|
*/
|
|
|
|
|
|
private double formatCoordinate(double value) {
|
|
|
|
|
|
// 返回原始值,Jackson 会处理格式化
|
|
|
|
|
|
return value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 备用序列化方式:序列化为 WKT 字符串
|
|
|
|
|
|
*/
|
|
|
|
|
|
private void serializeAsWKT(Polygon polygon, JsonGenerator gen) throws IOException {
|
|
|
|
|
|
if (polygon == null) {
|
|
|
|
|
|
gen.writeNull();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
String wkt = wktWriter.write(polygon);
|
2026-01-06 09:14:23 +08:00
|
|
|
|
|
2025-12-30 09:26:52 +08:00
|
|
|
|
if (wkt.startsWith("POLYGON")) {
|
|
|
|
|
|
// 提取坐标部分
|
|
|
|
|
|
String coordsPart = wkt.substring(wkt.indexOf("((") + 2, wkt.lastIndexOf("))"));
|
|
|
|
|
|
String[] points = coordsPart.split(", ");
|
2026-01-06 09:14:23 +08:00
|
|
|
|
|
2025-12-30 09:26:52 +08:00
|
|
|
|
gen.writeStartObject();
|
|
|
|
|
|
gen.writeStringField("type", "polygon");
|
2026-01-06 09:14:23 +08:00
|
|
|
|
|
2025-12-30 09:26:52 +08:00
|
|
|
|
gen.writeArrayFieldStart("coordinates");
|
|
|
|
|
|
for (String point : points) {
|
|
|
|
|
|
String[] xy = point.split(" ");
|
|
|
|
|
|
if (xy.length >= 2) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
double x = Double.parseDouble(xy[0]);
|
|
|
|
|
|
double y = Double.parseDouble(xy[1]);
|
2026-01-06 09:14:23 +08:00
|
|
|
|
|
2025-12-30 09:26:52 +08:00
|
|
|
|
gen.writeStartArray();
|
|
|
|
|
|
gen.writeNumber(x);
|
|
|
|
|
|
gen.writeNumber(y);
|
|
|
|
|
|
gen.writeEndArray();
|
|
|
|
|
|
} catch (NumberFormatException e) {
|
|
|
|
|
|
log.warn("坐标解析失败: {}", point);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
gen.writeEndArray();
|
|
|
|
|
|
gen.writeEndObject();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 直接写 WKT 字符串
|
|
|
|
|
|
gen.writeString(wkt);
|
|
|
|
|
|
}
|
2026-01-06 09:14:23 +08:00
|
|
|
|
|
2025-12-30 09:26:52 +08:00
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
log.error("WKT 序列化失败: {}", e.getMessage());
|
|
|
|
|
|
throw new IOException("Polygon 序列化失败", e);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|