dcb
2025-05-26 6d817179edaf2a6c793595056f5d250eb4396ab0
输出的png结果修改为可以通过设置间隔时间来输出
已添加3个文件
已修改7个文件
364 ■■■■■ 文件已修改
src/main/java/com/se/nsl/config/PropertiesConfig.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/se/nsl/controller/SimuController.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/se/nsl/domain/po/SimuData.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/se/nsl/domain/vo/SimuResult.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/se/nsl/service/ResolveService.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/se/nsl/service/SimuService.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/se/nsl/service/TestService.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/se/nsl/utils/CoordinateTransformer.java 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/se/nsl/utils/ZarrReader.java 112 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application-dev.yml 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/se/nsl/config/PropertiesConfig.java
@@ -66,6 +66,8 @@
    private Integer saveFrames;
    private Integer saveFrameInterval;
    private List<Integer> sizes;
    private String terrainFile;
@@ -288,6 +290,14 @@
        this.saveFrames = saveFrames;
    }
    public Integer getSaveFrameInterval() {
        return saveFrameInterval;
    }
    public void setSaveFrameInterval(Integer saveFrameInterval) {
        this.saveFrameInterval = saveFrameInterval;
    }
    public boolean isCopyTif() {
        return copyTif;
    }
src/main/java/com/se/nsl/controller/SimuController.java
@@ -1,6 +1,7 @@
package com.se.nsl.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.se.nsl.domain.po.Simu;
import com.se.nsl.domain.po.SimuData;
@@ -94,12 +95,15 @@
                return fail("geom对象不是多边形");
            int rows = simuService.insert(simu);
            System.out.println(String.format("id:%s", simu.getId()));
            if (rows > 0 && (null == data.getRainfalls() || data.getRainfalls().size() < 2)) {
                resolveService.createRainfall(simu);
                simuService.updateById(simu);
            }
            return success(rows);
            JSONObject json = new JSONObject();
            json.put("id", simu.getId());
            return success(json);
        } catch (Exception ex) {
            return fail(ex, null);
        }
@@ -156,4 +160,23 @@
            return fail(ex, null);
        }
    }
    @ApiOperation(value = "position")
    @GetMapping("/position")
    public R<Object> queryByPosition(double lon, double lat, String time, String serviceName) {
        if (lon > 180 || lon < -180) {
            return fail("经度范围应该在-180到180");
        }
        if (lat > 90 || lat < -90) {
            return fail("纬度范围应该在-90到90");
        }
        if (time == null || time.trim().isEmpty()) {
            return fail("时间戳不能为空");
        }
        if (serviceName == null || serviceName.trim().isEmpty()) {
            return fail("服务名不能为空");
        }
        return null;
    }
}
src/main/java/com/se/nsl/domain/po/SimuData.java
@@ -68,7 +68,7 @@
    @ApiModelProperty("降雨列表")
    private List<Rainfall> rainfalls;
    @ApiModelProperty("雨强单位:mm/h、mm/5min")
    @ApiModelProperty("雨强单位:mm/h、mm/5min、mm/min")
    private String intensityUnit;
    public SimuData() {
src/main/java/com/se/nsl/domain/vo/SimuResult.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,23 @@
package com.se.nsl.domain.vo;
public class SimuResult {
    private double depth;
    private double velocity;
    public double getDepth() {
        return depth;
    }
    public void setDepth(double depth) {
        this.depth = depth;
    }
    public double getVelocity() {
        return velocity;
    }
    public void setVelocity(double velocity) {
        this.velocity = velocity;
    }
}
src/main/java/com/se/nsl/service/ResolveService.java
@@ -211,6 +211,30 @@
        f.mkdirs();
    }
    enum RainFallUnit {
        MM_H("mm/h", 60),
        MM_15MIN("mm/15min", 15),
        MM_5MIN("mm/5min", 5),
        MM_MIN("mm/min", 1);
        private String unit;
        private int c; //系数
        RainFallUnit(String unit, int c) {
            this.unit = unit;
            this.c = c;
        }
        public static RainFallUnit of(String unit) {
            RainFallUnit[] values = values();
            for (RainFallUnit v : values) {
                if (v.unit.equals(unit)) {
                    return v;
                }
            }
            return MM_H; //默认按照mm/h计算
        }
    }
    public void createRainfallFile(Simu simu, SimuData data) throws Exception {
        List<Rainfall> rainfalls = data.getRainfalls();
        if (null == rainfalls || rainfalls.size() < 2) createRainfall(simu);
@@ -228,8 +252,12 @@
        double centerX = ComHelper.getMinVal((data.getMinx() + data.getMaxx()) / 2, DIGIT);
        double centerY = ComHelper.getMinVal((data.getMiny() + data.getMaxy()) / 2, DIGIT);
        String prefix = config.getRainfallSite() + " " + centerX + " " + centerY + " ";
        int unit = StringUtils.isEmpty(data.getIntensityUnit()) || "mm/h".equals(data.getIntensityUnit()) ? 60 : 5;
        //如果没有单位或者单位为mm/h则按照 mm/h计算,否则按照mm/5min计算
//        int unit = StringUtils.isEmpty(data.getIntensityUnit()) || "mm/h".equals(data.getIntensityUnit()) ? 60 : 5;
        String iu = data.getIntensityUnit();
        RainFallUnit rfUnit = RainFallUnit.of(iu);
        data.setIntensityUnit(rfUnit.unit);
        int unit = rfUnit.c;
        int c = rainfalls.size() - 1;
        for (int i = 0; i < c; i++) {
            Rainfall r1 = rainfalls.get(i);
@@ -290,7 +318,10 @@
        String landuseFile = inPath + File.separator + config.getLanduseFile();
        String rainfallFile = (inPath + File.separator + "rainfall.dat");
        String saveName = inPath + File.separator + "result.zarr";
        ConfigVo vo = new ConfigVo(terrainFile, landuseFile, terrainFile, rainfallFile, saveName, duration, config.getSaveFrames());
//        ConfigVo vo = new ConfigVo(terrainFile, landuseFile, terrainFile, rainfallFile, saveName, duration, config.getSaveFrames());
        Integer saveFrameInterval = config.getSaveFrameInterval();
        int saveFrames = duration / 60 / saveFrameInterval;
        ConfigVo vo = new ConfigVo(terrainFile, landuseFile, terrainFile, rainfallFile, saveName, duration, saveFrames);
        String configFile = config.getInPath() + File.separator + data.getInPath() + File.separator + data.getInPath() + ".json";
        ComHelper.writeJson(configFile, JSON.toJSONString(vo));
src/main/java/com/se/nsl/service/SimuService.java
@@ -5,15 +5,16 @@
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.se.nsl.domain.po.Simu;
import com.se.nsl.domain.vo.SimuResult;
import com.se.nsl.domain.vo.SimuVo;
import com.se.nsl.helper.StringHelper;
import com.se.nsl.mapper.SimuMapper;
import com.se.nsl.utils.CoordinateTransformer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@Slf4j
@@ -108,4 +109,15 @@
    public int updateById(Simu simu) {
        return simuMapper.updates(Arrays.asList(simu));
    }
    public SimuResult queryByPosition(double lon, double lat, String time, String serviceName) {
        //transform coordiante from 4326 to 4548
        double[] xy = CoordinateTransformer.transform(4326, 4548, lon, lat);
        System.out.println(String.format("转换前的坐标:x:%s,y:%s", lon, lat));
        System.out.println(String.format("转换后的坐标:x:%s,y:%s", xy[0], xy[1]));
        //read zarr data and compare the data with lon,lat,time
        return null;
    }
}
src/main/java/com/se/nsl/service/TestService.java
@@ -204,11 +204,9 @@
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        for (String file : files) {
            String fileName = ComHelper.getNameWithExt(file);
            // è§£æžä¸º LocalDateTime(默认基于系统时区,可能需指定时区)
            LocalDateTime dateTime = LocalDateTime.parse(fileName, formatter);
            // è½¬æ¢ä¸º UTC æ—¶é—´æˆ³ï¼ˆæŽ¨èï¼Œé¿å…æ—¶åŒºæ­§ä¹‰ï¼‰
            Instant utcInstant = dateTime.atZone(ZoneId.of("UTC")).toInstant();
            long timestamp = utcInstant.toEpochMilli();
            Instant instant = dateTime.atZone(ZoneId.systemDefault()).toInstant();
            long timestamp = instant.toEpochMilli();
            layer.getWaters().getData().add(timestamp);
        }
        layer.getDuration().setStart(layer.getWaters().getData().get(0));
src/main/java/com/se/nsl/utils/CoordinateTransformer.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,120 @@
package com.se.nsl.utils;
import org.gdal.gdal.gdal;
import org.gdal.osr.CoordinateTransformation;
import org.gdal.osr.SpatialReference;
import org.gdal.osr.osr;
public class CoordinateTransformer {
//    static {
//        try {
//            gdal.AllRegister();
//        } catch (Exception e) {
//            System.err.println("GDAL驱动注册失败: " + e.getMessage());
//        }
//    }
    public static double[] transform(int sourceEPSG, int targetEPSG,
                                     double x, double y, double z) {
        SpatialReference sourceSRS = null;
        SpatialReference targetSRS = null;
        CoordinateTransformation ct = null;
        try {
            // åˆ›å»ºæºåæ ‡ç³»
            sourceSRS = new SpatialReference();
            int sourceResult = sourceSRS.ImportFromEPSG(sourceEPSG);
            if (sourceResult != 0) {
                throw new IllegalArgumentException("无效的源EPSG代码: " + sourceEPSG);
            }
            // åˆ›å»ºç›®æ ‡åæ ‡ç³»
            targetSRS = new SpatialReference();
            int targetResult = targetSRS.ImportFromEPSG(targetEPSG);
            if (targetResult != 0) {
                throw new IllegalArgumentException("无效的目标EPSG代码: " + targetEPSG);
            }
            sourceSRS.SetAxisMappingStrategy(osr.OAMS_TRADITIONAL_GIS_ORDER);
            targetSRS.SetAxisMappingStrategy(osr.OAMS_TRADITIONAL_GIS_ORDER);
            // åˆ›å»ºåæ ‡è½¬æ¢å¯¹è±¡
            ct = new CoordinateTransformation(sourceSRS, targetSRS);
            double[] result = ct.TransformPoint(x, y, z);
            if (result == null || Double.isNaN(result[0]) || Double.isNaN(result[1])) {
                throw new IllegalArgumentException("坐标转换失败,可能是坐标系不兼容");
            }
            return result;
        } finally {
            // ç¡®ä¿èµ„源被释放
            if (ct != null) ct.delete();
            if (targetSRS != null) targetSRS.delete();
            if (sourceSRS != null) sourceSRS.delete();
        }
    }
    public static double[] transform(int sourceEPSG, int targetEPSG, double x, double y) {
        return transform(sourceEPSG, targetEPSG, x, y, 0.0);
    }
    public static double[] transform(String sourceWKT, String targetWKT,
                                     double x, double y, double z) {
        SpatialReference sourceSRS = null;
        SpatialReference targetSRS = null;
        CoordinateTransformation ct = null;
        try {
            // åˆ›å»ºæºåæ ‡ç³»
            sourceSRS = new SpatialReference();
            int sourceResult = sourceSRS.ImportFromWkt(sourceWKT);
            if (sourceResult != 0) {
                throw new IllegalArgumentException("无效的源WKT定义");
            }
            // åˆ›å»ºç›®æ ‡åæ ‡ç³»
            targetSRS = new SpatialReference();
            int targetResult = targetSRS.ImportFromWkt(targetWKT);
            if (targetResult != 0) {
                throw new IllegalArgumentException("无效的目标WKT定义");
            }
            // åˆ›å»ºåæ ‡è½¬æ¢å¯¹è±¡
            ct = new CoordinateTransformation(sourceSRS, targetSRS);
            double[] result = ct.TransformPoint(x, y, z);
            if (result == null || Double.isNaN(result[0]) || Double.isNaN(result[1])) {
                throw new IllegalArgumentException("坐标转换失败,可能是坐标系不兼容");
            }
            return result;
        } finally {
            // ç¡®ä¿èµ„源被释放
            if (ct != null) ct.delete();
            if (targetSRS != null) targetSRS.delete();
            if (sourceSRS != null) sourceSRS.delete();
        }
    }
    public static void main(String[] args) {
        try {
            double[] result1 = transform(4326, 32650, 116.4074, 39.9042); // åŒ—京
            System.out.printf("WGS84 -> UTM 50N: (%.6f, %.6f, %.2f)%n",
                    result1[0], result1[1], result1[2]);
            double[] result2 = transform(4326, 3857, 116.4074, 39.9042); // åŒ—京
            System.out.printf("WGS84 -> Web Mercator: (%.6f, %.6f, %.2f)%n",
                    result2[0], result2[1], result2[2]);
            // ä½¿ç”¨é€‚合NAD83 California zone 5的坐标
            double[] result3 = transform(4326, 26945, -122.4194, 37.7749); // æ—§é‡‘å±±
            System.out.printf("WGS84 -> NAD83 California zone 5: (%.6f, %.6f, %.2f)%n",
                    result3[0], result3[1], result3[2]);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
src/main/java/com/se/nsl/utils/ZarrReader.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,112 @@
package com.se.nsl.utils;
import org.gdal.gdal.Dataset;
import org.gdal.gdal.Driver;
import org.gdal.gdal.gdal;
import org.gdal.gdalconst.gdalconstConstants;
public class ZarrReader {
    static {
        // æ³¨å†ŒGDAL驱动
        try {
            gdal.AllRegister();
        } catch (Exception e) {
            System.err.println("GDAL驱动注册失败: " + e.getMessage());
        }
    }
    /**
     * è¯»å–Zarr数据集并打印基本信息
     * @param zarrPath Zarr数据集路径(本地路径或URL)
     */
    public static void readZarr(String zarrPath) {
        // æ‰“å¼€Zarr数据集
        Driver driver = gdal.GetDriverByName("Zarr");
        if (driver == null) {
            System.out.println("zarr驱动不可用");
        }
        Dataset dataset = gdal.Open(zarrPath, gdalconstConstants.GA_ReadOnly);
        if (dataset == null) {
            System.err.println("无法打开Zarr数据集: " + zarrPath);
            System.err.println(gdal.GetLastErrorMsg());
            return;
        }
        try {
            // æ‰“印数据集基本信息
            System.out.println("数据集信息:");
            System.out.println("  é©±åЍ: " + dataset.GetDriver().getShortName());
            System.out.println("  å®½åº¦: " + dataset.GetRasterXSize() + " åƒç´ ");
            System.out.println("  é«˜åº¦: " + dataset.GetRasterYSize() + " åƒç´ ");
            System.out.println("  æ³¢æ®µæ•°: " + dataset.GetRasterCount());
            // èŽ·å–åœ°ç†å˜æ¢å‚æ•°
            double[] geoTransform = dataset.GetGeoTransform();
            if (geoTransform != null && geoTransform.length >= 6) {
                System.out.println("  åœ°ç†å˜æ¢å‚æ•°:");
                System.out.printf("    å·¦ä¸Šè§’X: %.6f%n", geoTransform[0]);
                System.out.printf("    å·¦ä¸Šè§’Y: %.6f%n", geoTransform[3]);
                System.out.printf("    X方向分辨率: %.6f%n", geoTransform[1]);
                System.out.printf("    Y方向分辨率: %.6f%n", geoTransform[5]);
            }
            // èŽ·å–æŠ•å½±ä¿¡æ¯
            String projection = dataset.GetProjection();
            if (projection != null && !projection.isEmpty()) {
                System.out.println("  æŠ•影信息: " + projection.substring(0, Math.min(100, projection.length())) + "...");
            }
            // è¯»å–第一个波段的数据
            if (dataset.GetRasterCount() > 0) {
                int width = dataset.GetRasterXSize();
                int height = dataset.GetRasterYSize();
                float[] buffer = new float[width * height];
                // è¯»å–波段数据
                dataset.GetRasterBand(1).ReadRaster(0, 0, width, height, buffer);
                // ç»Ÿè®¡åŸºæœ¬ä¿¡æ¯
                float min = Float.MAX_VALUE;
                float max = Float.MIN_VALUE;
                float sum = 0;
                int validCount = 0;
                for (float value : buffer) {
                    if (!Float.isNaN(value) && !Float.isInfinite(value)) {
                        min = Math.min(min, value);
                        max = Math.max(max, value);
                        sum += value;
                        validCount++;
                    }
                }
                if (validCount > 0) {
                    float mean = sum / validCount;
                    System.out.printf("  ç¬¬ä¸€ä¸ªæ³¢æ®µç»Ÿè®¡ä¿¡æ¯: æœ€å°å€¼=%.2f, æœ€å¤§å€¼=%.2f, å¹³å‡å€¼=%.2f%n", min, max, mean);
                }
            }
        } catch (Exception e) {
            System.err.println("读取Zarr数据时发生错误: " + e.getMessage());
            e.printStackTrace();
        } finally {
            // é‡Šæ”¾èµ„源
            if (dataset != null) {
                dataset.delete();
            }
        }
    }
    public static void main(String[] args) {
        // ç¤ºä¾‹Zarr数据集路径 - è¯·æ›¿æ¢ä¸ºå®žé™…路径
//        String zarrPath = "C:\\Users\\Deng\\Desktop\\just_test\\result.zarr";
        String zarrPath = "D:\\other\\simu\\uwsolver\\20250516174452\\result.zarr";
        // è¯»å–并打印Zarr信息
        readZarr(zarrPath);
    }
}
src/main/resources/application-dev.yml
@@ -141,14 +141,18 @@
  flowUnits: CMS
  solverBat: D:\other\simu\uwsolver\run_solver.bat
  sww2tifBat: D:\other\simu\uwsolver\sww2tif.bat
  uwSolverBat: D:\other\simu\CudaUWSolver.Demo.NoVis.20250430\start.bat
  uwSolverBat: D:\other\simu\CudaUWSolver-2.0\start.bat
#  uwSolverBat: D:\other\simu\CudaUWSolver.Demo.NoVis.20250430\start.bat
  zarr2tifBat: D:\other\simu\zarr2tif-2.1\start.bat
#  zarr2tifBat: D:\other\simu\zarr2tif1.0\start.bat
  zarr2tifBat: D:\other\simu\zarr2tif-2.0-mkl\start.bat
#  zarr2tifBat: D:\other\simu\zarr2tif-2.0-mkl\start.bat
  createRainfall: '"C:\Program Files\Python310\python.exe" D:\terrait\NslServer\data\CreatRainfall.py'
  rainfallTitle: Station Longitude Latitude Year Month Day Hour Minute Intensity
  rainfallSite: beijing
  epsg: 4548
  saveFrames: 10
  saveFrames: 3
  #生成帧数的间隔时间,单位是分钟,设置为5表示每隔5分钟生成一帧
  saveFrameInterval: 5
  # åœŸåœ°åˆ©ç”¨ï¼š1-Cropland,2-Forest,3-Shrub,4-Grassland,5-Water,6-Snow/Ice,7-Barren,8-Impervious,9-Wetland
  landuse: 2
  #sizes: 64,128,256,512,1024,2048,4096
@@ -160,5 +164,8 @@
  buildingKey: KJSFBM
  waterPath: depth
  flowPath: velocity
  landuseFile: Landuse.tif
  sourceDem: D:\other\simu\CudaUWSolver-2.0\Beijing-Data-10m\Beijing-4548-ASTERDEMV3-10m.tif
  sourceLanduse: D:\other\simu\CudaUWSolver-2.0\Beijing-Data-10m\Beijing-4548-Landuse-10m-Nonodata.tif
  copyTif: false
  tifPath: D:\other\simu\uwsolver\5ca43c87cd8e48c5a9c5399a5da46dbc\tongzhou_raster_4548_1m_clip_river_fill.tif