1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
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
 
    }
}