171 lines
5.9 KiB
Java
171 lines
5.9 KiB
Java
|
|
package com.cdzy.operations.handler;
|
||
|
|
|
||
|
|
import com.fasterxml.jackson.core.JsonParser;
|
||
|
|
import com.fasterxml.jackson.databind.DeserializationContext;
|
||
|
|
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||
|
|
import com.fasterxml.jackson.databind.JsonNode;
|
||
|
|
import org.postgresql.geometric.PGpoint;
|
||
|
|
import org.postgresql.geometric.PGpolygon;
|
||
|
|
|
||
|
|
import java.io.IOException;
|
||
|
|
import java.util.ArrayList;
|
||
|
|
import java.util.List;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* PGpolygon 反序列化器 - 将 JSON 反序列化为 PGpolygon
|
||
|
|
*/
|
||
|
|
public class PGpolygonDeserializer extends JsonDeserializer<PGpolygon> {
|
||
|
|
|
||
|
|
@Override
|
||
|
|
public PGpolygon deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
|
||
|
|
JsonNode node = p.getCodec().readTree(p);
|
||
|
|
|
||
|
|
if (node.isNull()) {
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
// 支持多种 JSON 格式
|
||
|
|
|
||
|
|
// 格式1: 自定义格式 {"type": "polygon", "coordinates": [[x1,y1], [x2,y2], ...]}
|
||
|
|
if (node.isObject() && node.has("type") && "polygon".equals(node.get("type").asText())) {
|
||
|
|
return parseFromCustomFormat(node);
|
||
|
|
}
|
||
|
|
|
||
|
|
// 格式2: GeoJSON 格式 {"type": "Polygon", "coordinates": [[[x1,y1], [x2,y2], ...]]}
|
||
|
|
if (node.isObject() && node.has("type") && "Polygon".equals(node.get("type").asText())) {
|
||
|
|
return parseFromGeoJSON(node);
|
||
|
|
}
|
||
|
|
|
||
|
|
// 格式3: 直接坐标数组 [[x1,y1], [x2,y2], ...]
|
||
|
|
if (node.isArray()) {
|
||
|
|
return parseFromArray(node);
|
||
|
|
}
|
||
|
|
|
||
|
|
// 格式4: 字符串格式 "((x1 y1, x2 y2, ...))"
|
||
|
|
if (node.isTextual()) {
|
||
|
|
return parseFromString(node.asText());
|
||
|
|
}
|
||
|
|
|
||
|
|
throw new IOException("不支持的 PGpolygon JSON 格式");
|
||
|
|
|
||
|
|
} catch (Exception e) {
|
||
|
|
throw new IOException("PGpolygon 反序列化失败: " + e.getMessage(), e);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
@Override
|
||
|
|
public Class<PGpolygon> handledType() {
|
||
|
|
return PGpolygon.class;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 解析自定义格式
|
||
|
|
*/
|
||
|
|
private PGpolygon parseFromCustomFormat(JsonNode node) throws IOException {
|
||
|
|
JsonNode coordinatesNode = node.get("coordinates");
|
||
|
|
if (coordinatesNode == null || !coordinatesNode.isArray()) {
|
||
|
|
throw new IOException("coordinates 字段缺失或格式错误");
|
||
|
|
}
|
||
|
|
|
||
|
|
List<PGpoint> points = new ArrayList<>();
|
||
|
|
for (JsonNode coordNode : coordinatesNode) {
|
||
|
|
if (coordNode.isArray() && coordNode.size() >= 2) {
|
||
|
|
double x = coordNode.get(0).asDouble();
|
||
|
|
double y = coordNode.get(1).asDouble();
|
||
|
|
points.add(new PGpoint(x, y));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return createPGpolygonFromPoints(points);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 解析 GeoJSON 格式
|
||
|
|
*/
|
||
|
|
private PGpolygon parseFromGeoJSON(JsonNode node) throws IOException {
|
||
|
|
JsonNode coordinatesNode = node.get("coordinates");
|
||
|
|
if (coordinatesNode == null || !coordinatesNode.isArray() || coordinatesNode.isEmpty()) {
|
||
|
|
throw new IOException("coordinates 字段缺失或格式错误");
|
||
|
|
}
|
||
|
|
|
||
|
|
// GeoJSON 格式: coordinates 是三维数组 [[[x1,y1], [x2,y2], ...]]
|
||
|
|
JsonNode ringNode = coordinatesNode.get(0);
|
||
|
|
if (!ringNode.isArray()) {
|
||
|
|
throw new IOException("GeoJSON coordinates 格式错误");
|
||
|
|
}
|
||
|
|
|
||
|
|
List<PGpoint> points = new ArrayList<>();
|
||
|
|
for (JsonNode coordNode : ringNode) {
|
||
|
|
if (coordNode.isArray() && coordNode.size() >= 2) {
|
||
|
|
double x = coordNode.get(0).asDouble();
|
||
|
|
double y = coordNode.get(1).asDouble();
|
||
|
|
points.add(new PGpoint(x, y));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return createPGpolygonFromPoints(points);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 解析坐标数组格式
|
||
|
|
*/
|
||
|
|
private PGpolygon parseFromArray(JsonNode node) throws IOException {
|
||
|
|
List<PGpoint> points = new ArrayList<>();
|
||
|
|
for (JsonNode coordNode : node) {
|
||
|
|
if (coordNode.isArray() && coordNode.size() >= 2) {
|
||
|
|
double x = coordNode.get(0).asDouble();
|
||
|
|
double y = coordNode.get(1).asDouble();
|
||
|
|
points.add(new PGpoint(x, y));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return createPGpolygonFromPoints(points);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 解析字符串格式
|
||
|
|
*/
|
||
|
|
private PGpolygon parseFromString(String polygonString) throws IOException {
|
||
|
|
try {
|
||
|
|
return new PGpolygon(polygonString);
|
||
|
|
} catch (Exception e) {
|
||
|
|
throw new IOException("PGpolygon 字符串格式解析失败: " + polygonString, e);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 从点列表创建 PGpolygon
|
||
|
|
*/
|
||
|
|
private PGpolygon createPGpolygonFromPoints(List<PGpoint> points) throws IOException {
|
||
|
|
if (points == null || points.size() < 3) {
|
||
|
|
throw new IOException("多边形至少需要3个点");
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
// 构建多边形字符串格式:((x1 y1, x2 y2, x3 y3, x1 y1))
|
||
|
|
StringBuilder sb = new StringBuilder("((");
|
||
|
|
for (int i = 0; i < points.size(); i++) {
|
||
|
|
PGpoint point = points.get(i);
|
||
|
|
sb.append(point.x).append(" ").append(point.y);
|
||
|
|
if (i < points.size() - 1) {
|
||
|
|
sb.append(", ");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 确保多边形闭合(首尾点相同)
|
||
|
|
PGpoint firstPoint = points.get(0);
|
||
|
|
PGpoint lastPoint = points.get(points.size() - 1);
|
||
|
|
if (firstPoint.x != lastPoint.x || firstPoint.y != lastPoint.y) {
|
||
|
|
sb.append(", ").append(firstPoint.x).append(" ").append(firstPoint.y);
|
||
|
|
}
|
||
|
|
|
||
|
|
sb.append("))");
|
||
|
|
|
||
|
|
return new PGpolygon(sb.toString());
|
||
|
|
|
||
|
|
} catch (Exception e) {
|
||
|
|
throw new IOException("创建 PGpolygon 失败", e);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|