454 lines
16 KiB
Java
454 lines
16 KiB
Java
package com.yj.earth.common.util;
|
||
|
||
import org.gdal.gdal.gdal;
|
||
import org.gdal.ogr.*;
|
||
import org.gdal.osr.CoordinateTransformation;
|
||
import org.gdal.osr.SpatialReference;
|
||
import org.json.JSONArray;
|
||
import org.json.JSONException;
|
||
import org.json.JSONObject;
|
||
|
||
import java.io.File;
|
||
import java.util.ArrayList;
|
||
import java.util.HashMap;
|
||
import java.util.List;
|
||
import java.util.Map;
|
||
|
||
import static org.gdal.ogr.ogrConstants.*;
|
||
|
||
public class GdalJsonConverter {
|
||
|
||
static {
|
||
// 动态获取项目根目录下的lib文件夹路径
|
||
String projectRoot = System.getProperty("user.dir");
|
||
|
||
// 拼接lib目录路径(项目根目录/lib)
|
||
String projLibPath = projectRoot + File.separator + "lib";
|
||
|
||
// 设置PROJ库路径(指向包含proj.db的lib目录)
|
||
gdal.SetConfigOption("PROJ_LIB", projLibPath);
|
||
gdal.AllRegister();
|
||
}
|
||
|
||
/**
|
||
* 将地理数据文件转换为指定结构的JSON
|
||
*/
|
||
public static String convertToJson(String filePath) {
|
||
return convertToJson(filePath, "");
|
||
}
|
||
|
||
/**
|
||
* 将地理数据文件转换为指定结构的JSON
|
||
*/
|
||
private static String convertToJson(String filePath, String targetCrs) {
|
||
try {
|
||
// 打开数据源
|
||
DataSource dataSource = ogr.Open(filePath, 0);
|
||
if (dataSource == null) {
|
||
throw new RuntimeException("无法打开文件: " + filePath);
|
||
}
|
||
|
||
JSONObject result = new JSONObject();
|
||
JSONArray listArray = new JSONArray();
|
||
|
||
// 获取所有图层
|
||
int layerCount = dataSource.GetLayerCount();
|
||
for (int i = 0; i < layerCount; i++) {
|
||
Layer layer = dataSource.GetLayer(i);
|
||
String layerName = layer.GetName();
|
||
|
||
JSONObject featureCollection = createFeatureCollection(layer, layerName, targetCrs);
|
||
if (featureCollection != null) {
|
||
listArray.put(featureCollection);
|
||
}
|
||
}
|
||
|
||
result.put("list", listArray);
|
||
dataSource.delete();
|
||
|
||
return result.toString(2);
|
||
|
||
} catch (Exception e) {
|
||
throw new RuntimeException("转换失败: " + e.getMessage(), e);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 创建 FeatureCollection 对象
|
||
*/
|
||
private static JSONObject createFeatureCollection(Layer layer, String layerName, String targetCrs) throws JSONException {
|
||
JSONObject featureCollection = new JSONObject();
|
||
featureCollection.put("type", "FeatureCollection");
|
||
featureCollection.put("name", layerName);
|
||
|
||
// 获取源坐标系
|
||
String crsSrc = getLayerCrs(layer);
|
||
featureCollection.put("crs_src", crsSrc != null ? crsSrc : "");
|
||
|
||
// 设置目标坐标系
|
||
featureCollection.put("crs_dst", targetCrs != null ? targetCrs : "");
|
||
|
||
JSONArray featuresArray = new JSONArray();
|
||
Feature feature;
|
||
|
||
// 重置图层读取位置
|
||
layer.ResetReading();
|
||
|
||
// 获取图层定义、用于字段信息
|
||
FeatureDefn layerDefn = layer.GetLayerDefn();
|
||
|
||
// 如果需要坐标转换、创建坐标转换对象
|
||
SpatialReference sourceSrs = layer.GetSpatialRef();
|
||
SpatialReference targetSrs = null;
|
||
CoordinateTransformation coordTrans = null;
|
||
|
||
if (targetCrs != null && !targetCrs.isEmpty() && sourceSrs != null) {
|
||
try {
|
||
targetSrs = new SpatialReference();
|
||
if (targetCrs.startsWith("EPSG:")) {
|
||
int epsgCode = Integer.parseInt(targetCrs.substring(5));
|
||
targetSrs.ImportFromEPSG(epsgCode);
|
||
} else {
|
||
targetSrs.ImportFromProj4(targetCrs);
|
||
}
|
||
coordTrans = new CoordinateTransformation(sourceSrs, targetSrs);
|
||
} catch (Exception e) {
|
||
System.err.println("坐标转换初始化失败: " + e.getMessage());
|
||
}
|
||
}
|
||
|
||
while ((feature = layer.GetNextFeature()) != null) {
|
||
JSONObject featureObj = createFeature(feature, layerDefn, coordTrans, targetSrs != null);
|
||
if (featureObj != null) {
|
||
featuresArray.put(featureObj);
|
||
}
|
||
feature.delete();
|
||
}
|
||
|
||
// 清理资源
|
||
if (coordTrans != null) {
|
||
coordTrans.delete();
|
||
}
|
||
if (targetSrs != null) {
|
||
targetSrs.delete();
|
||
}
|
||
|
||
featureCollection.put("features", featuresArray);
|
||
return featureCollection;
|
||
}
|
||
|
||
/**
|
||
* 获取图层的坐标系信息
|
||
*/
|
||
private static String getLayerCrs(Layer layer) {
|
||
try {
|
||
SpatialReference srs = layer.GetSpatialRef();
|
||
if (srs != null) {
|
||
// 优先尝试获取PROJ4字符串
|
||
String proj4 = srs.ExportToProj4();
|
||
if (proj4 != null && !proj4.trim().isEmpty()) {
|
||
return proj4.trim();
|
||
}
|
||
|
||
// 如果PROJ4为空、尝试获取WKT
|
||
String wkt = srs.ExportToWkt();
|
||
if (wkt != null && !wkt.trim().isEmpty()) {
|
||
return wkt.trim();
|
||
}
|
||
|
||
// 最后尝试获取EPSG代码
|
||
String authorityCode = srs.GetAuthorityCode(null);
|
||
String authorityName = srs.GetAuthorityName(null);
|
||
if (authorityName != null && authorityCode != null) {
|
||
return authorityName + ":" + authorityCode;
|
||
}
|
||
}
|
||
} catch (Exception e) {
|
||
System.err.println("获取坐标系信息失败: " + e.getMessage());
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* 创建单个Feature对象
|
||
*/
|
||
private static JSONObject createFeature(Feature feature, FeatureDefn layerDefn, CoordinateTransformation coordTrans, boolean transformCoords) throws JSONException {
|
||
JSONObject featureObj = new JSONObject();
|
||
featureObj.put("type", "Feature");
|
||
|
||
// 处理属性字段
|
||
JSONObject properties = new JSONObject();
|
||
int fieldCount = layerDefn.GetFieldCount();
|
||
|
||
for (int i = 0; i < fieldCount; i++) {
|
||
FieldDefn fieldDefn = layerDefn.GetFieldDefn(i);
|
||
String fieldName = fieldDefn.GetName();
|
||
Object fieldValue = getFieldValue(feature, fieldDefn, i);
|
||
|
||
if (fieldValue != null) {
|
||
properties.put(fieldName, fieldValue);
|
||
}
|
||
}
|
||
|
||
featureObj.put("properties", properties);
|
||
|
||
// 处理几何图形
|
||
Geometry geometry = feature.GetGeometryRef();
|
||
if (geometry != null && !geometry.IsEmpty()) {
|
||
Geometry geomToUse = geometry;
|
||
|
||
// 如果需要坐标转换
|
||
if (transformCoords && coordTrans != null) {
|
||
try {
|
||
Geometry transformedGeom = geometry.Clone();
|
||
transformedGeom.Transform(coordTrans);
|
||
geomToUse = transformedGeom;
|
||
} catch (Exception e) {
|
||
System.err.println("坐标转换失败: " + e.getMessage());
|
||
// 如果转换失败、使用原始几何
|
||
geomToUse = geometry;
|
||
}
|
||
}
|
||
|
||
JSONObject geometryObj = convertGeometryToJson(geomToUse);
|
||
featureObj.put("geometry", geometryObj);
|
||
|
||
// 清理临时几何对象
|
||
if (geomToUse != geometry) {
|
||
geomToUse.delete();
|
||
}
|
||
} else {
|
||
// 如果没有几何信息、创建空的MultiPolygon
|
||
featureObj.put("geometry", createEmptyMultiPolygon());
|
||
}
|
||
|
||
return featureObj;
|
||
}
|
||
|
||
/**
|
||
* 获取字段值
|
||
*/
|
||
private static Object getFieldValue(Feature feature, FieldDefn fieldDefn, int fieldIndex) {
|
||
int fieldType = fieldDefn.GetFieldType();
|
||
|
||
if (feature.IsFieldSet(fieldIndex)) {
|
||
switch (fieldType) {
|
||
case ogr.OFTInteger:
|
||
return feature.GetFieldAsInteger(fieldIndex);
|
||
case ogr.OFTInteger64:
|
||
return feature.GetFieldAsInteger64(fieldIndex);
|
||
case ogr.OFTReal:
|
||
return feature.GetFieldAsDouble(fieldIndex);
|
||
case ogr.OFTString:
|
||
return feature.GetFieldAsString(fieldIndex);
|
||
case ogr.OFTDate:
|
||
case ogr.OFTTime:
|
||
case ogr.OFTDateTime:
|
||
return feature.GetFieldAsString(fieldIndex);
|
||
default:
|
||
return feature.GetFieldAsString(fieldIndex);
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* 将几何图形转换为JSON
|
||
*/
|
||
private static JSONObject convertGeometryToJson(Geometry geometry) throws JSONException {
|
||
JSONObject geometryObj = new JSONObject();
|
||
String geometryType = geometry.GetGeometryName();
|
||
|
||
// 根据几何类型处理
|
||
switch (geometry.GetGeometryType()) {
|
||
case wkbPoint:
|
||
case wkbPoint25D:
|
||
geometryObj.put("type", "Point");
|
||
geometryObj.put("coordinates", getPointCoordinates(geometry));
|
||
break;
|
||
case wkbLineString:
|
||
case wkbLineString25D:
|
||
geometryObj.put("type", "LineString");
|
||
geometryObj.put("coordinates", getLineStringCoordinates(geometry));
|
||
break;
|
||
case wkbPolygon:
|
||
case wkbPolygon25D:
|
||
geometryObj.put("type", "Polygon");
|
||
geometryObj.put("coordinates", getPolygonCoordinates(geometry));
|
||
break;
|
||
case wkbMultiPoint:
|
||
case wkbMultiPoint25D:
|
||
geometryObj.put("type", "MultiPoint");
|
||
geometryObj.put("coordinates", getMultiPointCoordinates(geometry));
|
||
break;
|
||
case wkbMultiLineString:
|
||
case wkbMultiLineString25D:
|
||
geometryObj.put("type", "MultiLineString");
|
||
geometryObj.put("coordinates", getMultiLineStringCoordinates(geometry));
|
||
break;
|
||
case wkbMultiPolygon:
|
||
case wkbMultiPolygon25D:
|
||
geometryObj.put("type", "MultiPolygon");
|
||
geometryObj.put("coordinates", getMultiPolygonCoordinates(geometry));
|
||
break;
|
||
case wkbGeometryCollection:
|
||
case wkbGeometryCollection25D:
|
||
geometryObj.put("type", "GeometryCollection");
|
||
geometryObj.put("geometries", getGeometryCollection(geometry));
|
||
break;
|
||
default:
|
||
// 默认使用WKT格式
|
||
geometryObj.put("type", geometryType);
|
||
geometryObj.put("wkt", geometry.ExportToWkt());
|
||
break;
|
||
}
|
||
|
||
return geometryObj;
|
||
}
|
||
|
||
/**
|
||
* 获取点坐标
|
||
*/
|
||
private static JSONArray getPointCoordinates(Geometry geometry) throws JSONException {
|
||
JSONArray coords = new JSONArray();
|
||
coords.put(geometry.GetX());
|
||
coords.put(geometry.GetY());
|
||
if (geometry.GetGeometryType() == wkbPoint25D) {
|
||
coords.put(geometry.GetZ());
|
||
}
|
||
return coords;
|
||
}
|
||
|
||
/**
|
||
* 获取线坐标
|
||
*/
|
||
private static JSONArray getLineStringCoordinates(Geometry geometry) throws JSONException {
|
||
JSONArray coords = new JSONArray();
|
||
int pointCount = geometry.GetPointCount();
|
||
for (int i = 0; i < pointCount; i++) {
|
||
JSONArray point = new JSONArray();
|
||
point.put(geometry.GetX(i));
|
||
point.put(geometry.GetY(i));
|
||
if (geometry.GetGeometryType() == wkbLineString25D) {
|
||
point.put(geometry.GetZ(i));
|
||
}
|
||
coords.put(point);
|
||
}
|
||
return coords;
|
||
}
|
||
|
||
/**
|
||
* 获取多边形坐标
|
||
*/
|
||
private static JSONArray getPolygonCoordinates(Geometry geometry) throws JSONException {
|
||
JSONArray rings = new JSONArray();
|
||
|
||
// 外环
|
||
Geometry exteriorRing = geometry.GetGeometryRef(0);
|
||
rings.put(getLineStringCoordinates(exteriorRing));
|
||
|
||
// 内环(如果有)
|
||
int ringCount = geometry.GetGeometryCount();
|
||
for (int i = 1; i < ringCount; i++) {
|
||
Geometry interiorRing = geometry.GetGeometryRef(i);
|
||
rings.put(getLineStringCoordinates(interiorRing));
|
||
}
|
||
|
||
return rings;
|
||
}
|
||
|
||
/**
|
||
* 获取多点坐标
|
||
*/
|
||
private static JSONArray getMultiPointCoordinates(Geometry geometry) throws JSONException {
|
||
JSONArray points = new JSONArray();
|
||
int geometryCount = geometry.GetGeometryCount();
|
||
for (int i = 0; i < geometryCount; i++) {
|
||
Geometry point = geometry.GetGeometryRef(i);
|
||
points.put(getPointCoordinates(point));
|
||
}
|
||
return points;
|
||
}
|
||
|
||
/**
|
||
* 获取多线坐标
|
||
*/
|
||
private static JSONArray getMultiLineStringCoordinates(Geometry geometry) throws JSONException {
|
||
JSONArray lines = new JSONArray();
|
||
int geometryCount = geometry.GetGeometryCount();
|
||
for (int i = 0; i < geometryCount; i++) {
|
||
Geometry line = geometry.GetGeometryRef(i);
|
||
lines.put(getLineStringCoordinates(line));
|
||
}
|
||
return lines;
|
||
}
|
||
|
||
/**
|
||
* 获取多多边形坐标
|
||
*/
|
||
private static JSONArray getMultiPolygonCoordinates(Geometry geometry) throws JSONException {
|
||
JSONArray polygons = new JSONArray();
|
||
int geometryCount = geometry.GetGeometryCount();
|
||
for (int i = 0; i < geometryCount; i++) {
|
||
Geometry polygon = geometry.GetGeometryRef(i);
|
||
polygons.put(getPolygonCoordinates(polygon));
|
||
}
|
||
return polygons;
|
||
}
|
||
|
||
/**
|
||
* 获取几何集合
|
||
*/
|
||
private static JSONArray getGeometryCollection(Geometry geometry) throws JSONException {
|
||
JSONArray geometries = new JSONArray();
|
||
int geometryCount = geometry.GetGeometryCount();
|
||
for (int i = 0; i < geometryCount; i++) {
|
||
Geometry geom = geometry.GetGeometryRef(i);
|
||
geometries.put(convertGeometryToJson(geom));
|
||
}
|
||
return geometries;
|
||
}
|
||
|
||
/**
|
||
* 创建空的 MultiPolygon 几何
|
||
*/
|
||
private static JSONObject createEmptyMultiPolygon() throws JSONException {
|
||
JSONObject geometry = new JSONObject();
|
||
geometry.put("type", "MultiPolygon");
|
||
geometry.put("coordinates", new JSONArray());
|
||
return geometry;
|
||
}
|
||
|
||
/**
|
||
* 获取文件信息(辅助方法)
|
||
*/
|
||
public static Map<String, Object> getFileInfo(String filePath) {
|
||
Map<String, Object> info = new HashMap<>();
|
||
try {
|
||
DataSource dataSource = ogr.Open(filePath, 0);
|
||
if (dataSource != null) {
|
||
info.put("driver", dataSource.GetDriver().GetName());
|
||
info.put("layerCount", dataSource.GetLayerCount());
|
||
|
||
List<Map<String, Object>> layers = new ArrayList<>();
|
||
for (int i = 0; i < dataSource.GetLayerCount(); i++) {
|
||
Layer layer = dataSource.GetLayer(i);
|
||
Map<String, Object> layerInfo = new HashMap<>();
|
||
layerInfo.put("name", layer.GetName());
|
||
layerInfo.put("featureCount", layer.GetFeatureCount());
|
||
layerInfo.put("geometryType", ogr.GeometryTypeToName(layer.GetGeomType()));
|
||
// 添加坐标系信息
|
||
String crs = getLayerCrs(layer);
|
||
layerInfo.put("crs", crs != null ? crs : "未知");
|
||
layers.add(layerInfo);
|
||
}
|
||
info.put("layers", layers);
|
||
dataSource.delete();
|
||
}
|
||
} catch (Exception e) {
|
||
info.put("error", e.getMessage());
|
||
}
|
||
return info;
|
||
}
|
||
}
|