170 lines
5.8 KiB
Java
170 lines
5.8 KiB
Java
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
|
||
public void serialize(Polygon polygon, JsonGenerator gen, SerializerProvider serializers)
|
||
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 {
|
||
// 获取外环
|
||
LinearRing exteriorRing = polygon.getExteriorRing();
|
||
if (exteriorRing == null) {
|
||
throw new IOException("多边形外环为空");
|
||
}
|
||
|
||
return exteriorRing.getCoordinates();
|
||
|
||
} 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);
|
||
|
||
// 转换为与 PGpolygon 相似的格式
|
||
if (wkt.startsWith("POLYGON")) {
|
||
// 提取坐标部分
|
||
String coordsPart = wkt.substring(wkt.indexOf("((") + 2, wkt.lastIndexOf("))"));
|
||
String[] points = coordsPart.split(", ");
|
||
|
||
gen.writeStartObject();
|
||
gen.writeStringField("type", "polygon");
|
||
|
||
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]);
|
||
|
||
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);
|
||
}
|
||
|
||
} catch (Exception e) {
|
||
log.error("WKT 序列化失败: {}", e.getMessage());
|
||
throw new IOException("Polygon 序列化失败", e);
|
||
}
|
||
}
|
||
} |