package com.se.simu.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 } }