package com.se.nsl.utils;
|
|
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONObject;
|
import org.gdal.gdal.gdal;
|
import org.gdal.ogr.*;
|
import org.gdal.osr.CoordinateTransformation;
|
import org.gdal.osr.SpatialReference;
|
|
import java.util.Arrays;
|
|
/**
|
* shp 工具实用程序
|
*
|
* @author xingjinshuang@smartearth.cn
|
* @date 2024/12/26
|
*/
|
public class ShpToolUtils {
|
|
// 声明为类成员变量
|
private static double minX = Double.MAX_VALUE;
|
private static double maxX = Double.MIN_VALUE;
|
private static double minY = Double.MAX_VALUE;
|
private static double maxY = Double.MIN_VALUE;
|
|
// 用于存储所有转换后的经纬度
|
private static JSONArray coordinatesArray = new JSONArray();
|
|
/**
|
* 阅读 SHP
|
*
|
* @param strVectorFile str 向量文件
|
* @return {@link JSONObject}
|
*/
|
public static JSONObject readShp(String strVectorFile) {
|
// 注册所有的驱动
|
ogr.RegisterAll();
|
// 为了支持中文路径,请添加下面这句代码
|
gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
|
|
// 读取数据,这里以ESRI的shp文件为例
|
String strDriverName = "ESRI Shapefile";
|
org.gdal.ogr.Driver oDriver = ogr.GetDriverByName(strDriverName);
|
|
if (oDriver == null) {
|
System.out.println(strDriverName + " 驱动不可用!\n");
|
return null;
|
}
|
|
// 打开数据源
|
DataSource dataSource = oDriver.Open(strVectorFile);
|
if (dataSource == null) {
|
System.out.println("无法打开 Shapefile 文件!");
|
return null;
|
}
|
|
Layer layer = dataSource.GetLayer(0);
|
|
// 获取图层的范围(初步的矩形范围)
|
double[] layerExtent = layer.GetExtent();
|
System.out.println("初始图层范围:minx:" + layerExtent[0] + ", maxx:" + layerExtent[1] + ", miny:" + layerExtent[2] + ", maxy:" + layerExtent[3]);
|
|
// 获取图层的空间参考
|
SpatialReference layerSpatialRef = layer.GetSpatialRef();
|
|
// 创建目标空间参考 (EPSG:4326)
|
SpatialReference targetSpatialRef = new SpatialReference();
|
targetSpatialRef.ImportFromEPSG(4326); // EPSG:4326 是 WGS84
|
|
// 创建坐标转换对象
|
CoordinateTransformation coordTransform = CoordinateTransformation.CreateCoordinateTransformation(layerSpatialRef, targetSpatialRef);
|
|
// 遍历每个 feature 获取坐标点
|
for (int i = 0; i < layer.GetFeatureCount(); i++) {
|
Feature feature = layer.GetFeature(i);
|
Geometry geometry = feature.GetGeometryRef();
|
// 判断几何类型并处理
|
if (geometry != null) {
|
if (geometry.GetGeometryType() == ogr.wkbPoint) {
|
// 单个点的处理
|
processPointGeometry(geometry, coordTransform);
|
} else if (geometry.GetGeometryType() == ogr.wkbMultiPoint) {
|
// 多个点的处理
|
System.out.println("geometry = " + geometry);
|
//processMultiPointGeometry(geometry, coordTransform);
|
}
|
}
|
}
|
// 打印转换后的矩形范围(经纬度)
|
System.out.println("所有点的经纬度矩形范围:minX = " + minX + ", maxX = " + maxX + ", minY = " + minY + ", maxY = " + maxY);
|
JSONObject json = new JSONObject();
|
json.put("minX", minX);
|
json.put("maxX", maxX);
|
json.put("minY", minY);
|
json.put("maxY", maxY);
|
return json;
|
}
|
|
|
/**
|
* 读取 shp get local
|
*
|
* @param strVectorFile str 向量文件
|
* @return {@link JSONObject}
|
*/
|
public static JSONArray readShpGetLocal(String strVectorFile) {
|
// 注册所有的驱动
|
ogr.RegisterAll();
|
// 为了支持中文路径,请添加下面这句代码
|
gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
|
|
// 读取数据,这里以ESRI的shp文件为例
|
String strDriverName = "ESRI Shapefile";
|
org.gdal.ogr.Driver oDriver = ogr.GetDriverByName(strDriverName);
|
|
if (oDriver == null) {
|
System.out.println(strDriverName + " 驱动不可用!\n");
|
return null;
|
}
|
|
// 打开数据源
|
DataSource dataSource = oDriver.Open(strVectorFile);
|
if (dataSource == null) {
|
System.out.println("无法打开 Shapefile 文件!");
|
return null;
|
}
|
|
Layer layer = dataSource.GetLayer(0);
|
|
// 获取图层的范围(初步的矩形范围)
|
double[] layerExtent = layer.GetExtent();
|
System.out.println("初始图层范围:minx:" + layerExtent[0] + ", maxx:" + layerExtent[1] + ", miny:" + layerExtent[2] + ", maxy:" + layerExtent[3]);
|
|
// 获取图层的空间参考
|
SpatialReference layerSpatialRef = layer.GetSpatialRef();
|
|
// 创建目标空间参考 (EPSG:4326)
|
SpatialReference targetSpatialRef = new SpatialReference();
|
targetSpatialRef.ImportFromEPSG(4326); // EPSG:4326 是 WGS84
|
|
// 创建坐标转换对象
|
CoordinateTransformation coordTransform = CoordinateTransformation.CreateCoordinateTransformation(layerSpatialRef, targetSpatialRef);
|
|
// 遍历每个 feature 获取坐标点
|
for (int i = 0; i < layer.GetFeatureCount(); i++) {
|
Feature feature = layer.GetFeature(i);
|
Geometry geometry = feature.GetGeometryRef();
|
// 判断几何类型并处理
|
if (geometry != null) {
|
if (geometry.GetGeometryType() == ogr.wkbPoint) {
|
// 单个点的处理
|
processPointGeometry(geometry, coordTransform);
|
} else if (geometry.GetGeometryType() == ogr.wkbMultiPoint) {
|
// 多个点的处理
|
System.out.println("geometry = " + geometry);
|
//processMultiPointGeometry(geometry, coordTransform);
|
}
|
}
|
}
|
// 打印转换后的矩形范围(经纬度)
|
System.out.println("所有点的经纬度矩形范围:minX = " + minX + ", maxX = " + maxX + ", minY = " + minY + ", maxY = " + maxY);
|
return coordinatesArray;
|
}
|
|
// 处理单个点的几何体
|
private static void processPointGeometry(Geometry geometry, CoordinateTransformation coordTransform) {
|
double x = geometry.GetX();
|
double y = geometry.GetY();
|
|
// 创建包含 3 个元素的数组,Z 坐标可以设为 0
|
double[] coords = new double[]{x, y, 0}; // Z 坐标默认值为 0
|
//System.out.println("原始坐标1:coords = " + Arrays.toString(coords));
|
|
// 转换坐标
|
coordTransform.TransformPoint(coords);
|
//System.out.println("转换后的坐标:coords = " + Arrays.toString(coords));
|
|
// 坐标顺序是 [latitude, longitude],交换顺序为 [longitude, latitude]
|
double longitude = coords[0];
|
double latitude = coords[1];
|
//System.out.println("转换后的经纬度:longitude = " + longitude + ", latitude = " + latitude);
|
// 创建一个 JSON 对象保存经纬度信息
|
JSONObject coordObj = new JSONObject();
|
coordObj.put("lat", longitude);
|
coordObj.put("lon", latitude);
|
// 将此 JSON 对象添加到 JSONArray 中
|
coordinatesArray.add(coordObj);
|
|
// 更新矩形边界(此处使用全局变量或返回值进行计算)
|
updateRectangleBounds(coords);
|
}
|
|
// 处理多点的几何体
|
private static void processMultiPointGeometry(Geometry geometry, CoordinateTransformation coordTransform) {
|
int numPoints = geometry.GetGeometryCount();
|
for (int j = 0; j < numPoints; j++) {
|
Geometry pointGeometry = geometry.GetGeometryRef(j);
|
double x = pointGeometry.GetX();
|
double y = pointGeometry.GetY();
|
|
// 创建包含 3 个元素的数组,Z 坐标可以设为 0
|
double[] coords = new double[]{x, y, 0}; // Z 坐标默认值为 0
|
System.out.println("原始坐标2:coords = " + Arrays.toString(coords));
|
|
// 转换坐标
|
coordTransform.TransformPoint(coords);
|
System.out.println("转换后的坐标:coords = " + Arrays.toString(coords));
|
|
// 坐标顺序是 [latitude, longitude],交换顺序为 [longitude, latitude]
|
double longitude = coords[0];
|
double latitude = coords[1];
|
System.out.println("转换后的经纬度:longitude = " + longitude + ", latitude = " + latitude);
|
|
// 更新矩形边界
|
updateRectangleBounds(coords);
|
}
|
}
|
|
// 更新矩形的边界值
|
private static void updateRectangleBounds(double[] coords) {
|
double x = coords[0];
|
double y = coords[1];
|
|
// 更新最小最大值
|
minX = Math.min(minX, x);
|
maxX = Math.max(maxX, x);
|
minY = Math.min(minY, y);
|
maxY = Math.max(maxY, y);
|
}
|
|
public static void main(String[] args) {
|
// 读取shp文件
|
readShp("D:\\0a_project\\model\\shp\\雨量站点数据\\雨量站点_4548\\雨量站点_4548.shp");
|
System.out.println(coordinatesArray.toString()); // Pretty print with indent
|
|
}
|
}
|