package com.se.simu.helper; import cn.hutool.core.io.FileUtil; import cn.hutool.json.JSONArray; import cn.hutool.json.JSONObject; import com.se.simu.domain.dto.GeField; import com.se.simu.domain.dto.GeLayer; import lombok.extern.slf4j.Slf4j; import org.gdal.gdal.Dataset; import org.gdal.gdal.gdal; import org.gdal.gdalconst.gdalconst; import org.gdal.ogr.*; import org.gdal.osr.SpatialReference; import java.sql.Timestamp; import java.time.LocalDateTime; import java.util.List; import java.util.Map; import java.util.Vector; @Slf4j @SuppressWarnings("ALL") public class ShpHelper { private static Vector options; public static Vector getOptions() { if (null == options) { options = new Vector<>(); options.add("ENCODING=UTF-8"); } return options; } public static boolean createShp(String filePath, Map map, SpatialReference sr, Double minx, Double miny, Double maxx, Double maxy) { Driver driver = null; DataSource dataSource = null; Layer layer = null; try { driver = ogr.GetDriverByName("ESRI shapefile"); if (null == driver) return false; dataSource = driver.CreateDataSource(filePath, null); if (null == dataSource) return false; layer = dataSource.CreateLayer(FileUtil.getName(filePath), sr, ogr.wkbPolygon, getOptions()); if (null == layer) return false; if (null != map) createFields(layer, map); Feature f = new Feature(layer.GetLayerDefn()); Geometry g = createPolygon(sr, minx, miny, maxx, maxy); f.SetGeometry(g); if (null != map) setValues(f, map); layer.CreateFeature(f); return true; } catch (Exception ex) { log.error(ex.getMessage(), ex); return false; } finally { GdalHelper.delete(layer, dataSource, driver); } } private static void createFields(Layer layer, Map map) { for (String key : map.keySet()) { Object val = map.get(key); switch (val.getClass().getTypeName()) { //case "java.math.BigDecimal": case "java.lang.Double": case "double": layer.CreateField(new FieldDefn(key, ogr.OFTReal)); break; case "java.lang.Long": case "long": layer.CreateField(new FieldDefn(key, ogr.OFTInteger64)); break; case "java.lang.Integer": case "int": layer.CreateField(new FieldDefn(key, ogr.OFTInteger)); break; //case "java.sql.Timestamp": //case "java.time.LocalDate": // layer.CreateField(new FieldDefn(key, ogr.OFTDateTime)); // break; default: layer.CreateField(new FieldDefn(key, ogr.OFTString)); break; } } } private static void setValues(Feature f, Map map) { for (String key : map.keySet()) { Object val = map.get(key); switch (val.getClass().getTypeName()) { case "java.lang.Double": case "double": f.SetField(key, Double.parseDouble(val.toString())); break; case "java.lang.Long": case "long": f.SetField(key, Long.parseLong(val.toString())); break; case "java.lang.Integer": case "int": f.SetField(key, Integer.parseInt(val.toString())); break; default: f.SetField(key, val.toString()); break; } } } public static Geometry createPolygon(SpatialReference sr, Double minx, Double miny, Double maxx, Double maxy) { String epsg = sr.GetAuthorityCode(null); if (!("4326".equals(epsg) || "4490".equals(epsg))) { double[] dmin = GdalHelper.fromWgs84(sr, minx, miny); double[] dmax = GdalHelper.fromWgs84(sr, maxx, maxy); minx = dmin[0]; miny = dmin[1]; maxx = dmax[0]; maxy = dmax[1]; } Geometry ring = new Geometry(ogr.wkbLinearRing); ring.AddPoint_2D(minx, maxy); ring.AddPoint_2D(maxx, maxy); ring.AddPoint_2D(maxx, miny); ring.AddPoint_2D(minx, miny); ring.AddPoint_2D(minx, maxy); Geometry poly = new Geometry(ogr.wkbPolygon); poly.AddGeometry(ring); poly.AssignSpatialReference(sr); return poly; } public static boolean createShp(String filePath, GeLayer geLayer) { Driver driver = null; DataSource dataSource = null; Layer layer = null; try { driver = ogr.GetDriverByName("ESRI shapefile"); if (null == driver) return false; dataSource = driver.CreateDataSource(filePath, null); if (null == dataSource) return false; int geoType = getGeometryType(geLayer.getQueryType()); layer = dataSource.CreateLayer(FileUtil.getName(filePath), geLayer.getDb().getSpatialReference(), geoType, getOptions()); if (null == layer) return false; createLayerFields(layer, geLayer.getFields()); FeatureDefn featureDefn = layer.GetLayerDefn(); for (int i = 0, c = geLayer.getData().size(); i < c; i++) { Feature f = new Feature(featureDefn); JSONObject data = geLayer.getData().getJSONObject(i).getJSONObject("properties"); setFeatureData(f, geLayer.getFields(), data); JSONObject geom = geLayer.getData().getJSONObject(i).getJSONObject("geometry"); Geometry g = createGeometry(geLayer, geom); f.SetGeometry(g); layer.CreateFeature(f); } return true; } catch (Exception ex) { log.error(ex.getMessage(), ex); return false; } finally { GdalHelper.delete(layer, dataSource, driver); } } private static void setFeatureData(Feature f, List fields, JSONObject data) { for (int i = 0, c = fields.size(); i < c; i++) { GeField geField = fields.get(i); switch (geField.getType()) { case "int": f.SetField(i, data.getInt(geField.getName())); break; case "long": f.SetField(i, data.getLong(geField.getName())); break; case "double": f.SetField(i, data.getDouble(geField.getName())); break; case "datetime": long date = data.getLong(geField.getName()); Timestamp time = new Timestamp(date); setTimestamp(f, i, time); break; default: f.SetField(i, data.getStr(geField.getName())); break; } } } private static void setTimestamp(Feature f, int i, Timestamp time) { if (null == time) return; LocalDateTime local = time.toLocalDateTime(); f.SetField(i, local.getYear(), local.getMonthValue(), local.getDayOfMonth(), local.getHour(), local.getMinute(), local.getSecond(), 8); } public static Geometry createGeometry(GeLayer geLayer, JSONObject geom) { String type = geom.getStr("type"); JSONArray cs = geom.getJSONArray("coordinates"); Geometry g = null; switch (type) { case "Point": g = new Geometry(ogr.wkbPoint); g.AddPoint_2D(cs.getDouble(0), cs.getDouble(1)); break; case "MultiLineString": g = new Geometry(ogr.wkbMultiLineString); for (int i = 0, c = cs.size(); i < c; i++) { Geometry line = new Geometry(ogr.wkbLineString); JSONArray lineArr = cs.getJSONArray(i); for (int j = 0, d = lineArr.size(); j < d; j++) { JSONArray arr = lineArr.getJSONArray(j); line.AddPoint_2D(arr.getDouble(0), arr.getDouble(1)); } g.AddGeometry(line); } break; case "MultiPolygon": g = new Geometry(ogr.wkbMultiPolygon); for (int i = 0, c = cs.size(); i < c; i++) { Geometry poly = new Geometry(ogr.wkbPolygon); JSONArray polyArr = cs.getJSONArray(i); for (int j = 0, d = polyArr.size(); j < d; j++) { Geometry ring = new Geometry(ogr.wkbLinearRing); JSONArray ringArr = polyArr.getJSONArray(j); for (int k = 0, e = ringArr.size(); k < e; k++) { JSONArray arr = ringArr.getJSONArray(k); ring.AddPoint_2D(arr.getDouble(0), arr.getDouble(1)); } poly.AddGeometry(ring); } g.AddGeometry(poly); } break; } return g; } private static int getGeometryType(String type) { switch (type) { case "point": return ogr.wkbPoint; case "polyline": return ogr.wkbMultiLineString; case "polygon": return ogr.wkbMultiPolygon; default: return ogr.wkbUnknown; } } private static void createLayerFields(Layer layer, List fields) { for (int i = 0, c = fields.size(); i < c; i++) { GeField f = fields.get(i); FieldDefn fd = new FieldDefn(f.getName(), getFieldType(f)); layer.CreateField(fd, i); } } private static Integer getFieldType(GeField f) { switch (f.getType()) { case "int": return ogr.OFTInteger; case "long": return ogr.OFTInteger64; case "double": return ogr.OFTReal; case "datetime": return ogr.OFTDateTime; default: return ogr.OFTString; } } private String getEpsg(SpatialReference sr) { return sr.GetAuthorityCode(null); } public static boolean polygonize2Shp(Dataset ds, String filePath) { Driver driver = null; DataSource dataSource = null; Layer layer = null; try { driver = ogr.GetDriverByName("ESRI shapefile"); if (null == driver) return false; dataSource = driver.CreateDataSource(filePath, null); if (null == dataSource) return false; layer = dataSource.CreateLayer(FileUtil.getName(filePath), ds.GetSpatialRef(), ogr.wkbPolygon, getOptions()); if (null == layer) return false; layer.CreateField(new FieldDefn("val", ogr.OFTReal)); gdal.Polygonize(ds.GetRasterBand(1), ds.GetRasterBand(1).GetMaskBand(), layer, 0); return true; } catch (Exception ex) { log.error(ex.getMessage(), ex); return false; } finally { GdalHelper.delete(layer, dataSource, driver); } } public static boolean polygonize2Geojson(Dataset ds, String filePath) { Driver driver = null; DataSource dataSource = null; Layer layer = null; try { driver = ogr.GetDriverByName("GeoJSON"); if (null == driver) return false; dataSource = driver.CreateDataSource(filePath, null); if (null == dataSource) return false; layer = dataSource.CreateLayer(FileUtil.getName(filePath), ds.GetSpatialRef(), ogr.wkbPolygon); if (null == layer) return false; layer.CreateField(new FieldDefn("val", ogr.OFTReal)); gdal.Polygonize(ds.GetRasterBand(1), ds.GetRasterBand(1).GetMaskBand(), layer, 0); return true; } catch (Exception ex) { log.error(ex.getMessage(), ex); return false; } finally { GdalHelper.delete(layer, dataSource, driver); } } public static void test() { String path = "D:\\simu\\out\\20241010095328\\waters\\1730217635000\\"; Dataset ds = gdal.Open(path + "water.tif", gdalconst.GA_ReadOnly); ds.SetSpatialRef(GdalHelper.createSpatialReference(4548)); polygonize2Geojson(ds, path + "water.geojson"); } }