2026-01-16 11:25:03 +08:00

170 lines
5.8 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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