dcb
2025-06-20 51d12c4cca7c9d4911a0037673bbd2dc210836d0
src/main/java/com/se/nsl/service/SimuService.java
@@ -4,24 +4,44 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bc.zarr.ZarrArray;
import com.bc.zarr.ZarrGroup;
import com.se.nsl.config.PropertiesConfig;
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 com.se.nsl.utils.TimeFormatUtil;
import lombok.extern.slf4j.Slf4j;
import org.gdal.gdal.Band;
import org.gdal.gdal.Dataset;
import org.gdal.gdal.gdal;
import org.gdal.gdalconst.gdalconstConstants;
import org.springframework.stereotype.Service;
import ucar.ma2.InvalidRangeException;
import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@Slf4j
@Service
@SuppressWarnings("ALL")
public class SimuService {
    public static final String TIF_EXTSION = ".tif";
    public static final String YYYY_MM_DD_HHMMSS = "yyyyMMddHHmmss";
    @Resource
    SimuMapper simuMapper;
    @Resource
    PropertiesConfig config;
    /**
     * 分页查询推演模拟
@@ -82,7 +102,21 @@
     * @return 新增成功的记录数
     */
    public int insert(Simu simu) {
        return simuMapper.inserts(Collections.singletonList(simu));
        return simuMapper.insert(simu);
    }
    public int inserts(List<Simu> list) {
        return simuMapper.inserts(list);
    }
    /**
     * 根据ID查询
     *
     * @param id ID
     * @return Simu
     */
    public Simu selectById(Integer id) {
        return simuMapper.selectById(id);
    }
    /**
@@ -94,4 +128,172 @@
    public int updateById(Simu simu) {
        return simuMapper.updates(Arrays.asList(simu));
    }
    public SimuResult queryByPosition(double lon, double lat, long 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 from zarr
//        return queryByZarr(xy, time, serviceName);
        //read from tif file
        return queryByTif(xy, time, serviceName);
    }
    public List<SimuResult> queryByPosition(double lon, double lat, 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 from zarr
//        return queryByZarr(xy, time, serviceName);
        //read from tif file
        return queryByTif(xy, serviceName);
    }
    private SimuResult queryByZarr(double[] xy, long time, String serviceName) {
        double x = xy[0];
        double y = xy[1];
        String prefix = formatTime(time);
        File inPath = new File(config.getInPath());
//        File tifDir = new File(inPath, serviceName + File.separator + "depth");
//        int index = 0;
//        File[] files = tifDir.listFiles();
//        for (File file : files) {
//            String name = file.getName();
//            if (!name.endsWith(TIF_EXTSION)) continue;
//            if (name.equals(prefix + TIF_EXTSION)) {
//                break;
//            }
//            index++;
//        }
        File dem = new File(inPath, serviceName + File.separator + "DEM.tif");
        ColumnRow cr = getColumnRow(dem.getAbsoluteFile(), x, y);
        if (cr == null) return null;
        File zarr = new File(inPath, serviceName + File.separator + "result.zarr");
        try {
            ZarrGroup group = ZarrGroup.open(zarr.toPath());
            ZarrArray depthArray = group.openArray("depth");
            int[] shape = new int[] {60, 637, 351};
//            int[] offset = new int[]{210, 384};
            float[] depth = (float[]) depthArray.read(shape);
            System.out.println("depth:" + depth.length);
        } catch (IOException | InvalidRangeException e) {
            throw new RuntimeException(e);
        }
        return null;
    }
    private SimuResult queryByTif(double[] xy, long time, String serviceName) {
        double x = xy[0];
        double y = xy[1];
        File inPath = new File(config.getInPath());
        String prefix = formatTime(time);
        String child = serviceName + File.separator + "depth" + File.separator + prefix + TIF_EXTSION;
        File tifFile = new File(inPath, child);
        if (!tifFile.exists()) {
            return null;
        }
        ColumnRow cr = getColumnRow(tifFile, x, y);
        if (cr == null) return null;
//        System.out.println("col:" + cr.col + " ,row:" + cr.row);
        float depth = readPixelValue(cr.dataset, cr.col, cr.row, 1);
        float velocity = calcVelocity(cr.dataset, cr.col, cr.row);
        SimuResult result = new SimuResult();
        result.setDepth(depth);
        result.setVelocity(velocity);
        result.setTime(time);
        return  result;
    }
    private List<SimuResult> queryByTif(double[] xy, String serviceName) {
        double x = xy[0];
        double y = xy[1];
        List<SimuResult> res = new ArrayList<>();
        File inPath = new File(config.getInPath());
        Path depthPath = Paths.get(inPath.getAbsolutePath(), serviceName, "depth");
        File depthDir = depthPath.toFile();
        File[] files = depthDir.listFiles();
        for (File tifFile : files) {
            String name = tifFile.getName();
            if (!name.endsWith(TIF_EXTSION)) continue;
            ColumnRow cr = getColumnRow(tifFile, x, y);
            if (cr == null) continue;
            float depth = readPixelValue(cr.dataset, cr.col, cr.row, 1);
            float velocity = calcVelocity(cr.dataset, cr.col, cr.row);
            SimuResult result = new SimuResult();
            result.setDepth(depth);
            result.setVelocity(velocity);
            String time = tifFile.getName().replace(".tif", "");
            result.setTime(TimeFormatUtil.toMillis(time, YYYY_MM_DD_HHMMSS));
            res.add(result);
        }
        return  res;
    }
    private static ColumnRow getColumnRow(File tifFile, double x, double y) {
        Dataset dataset = gdal.Open(tifFile.getAbsolutePath(), gdalconstConstants.GA_ReadOnly);
        // 获取地理变换参数(6元素数组)
        // [0]: 左上角X坐标, [1]: 像元宽度, [2]: X方向旋转,
        // [3]: 左上角Y坐标, [4]: Y方向旋转, [5]: 像元高度(负值表示Y轴向下)
        double[] geoTransform = dataset.GetGeoTransform();
        //计算栅格行列号
        int col = (int) ((x - geoTransform[0]) / geoTransform[1]);
        int row = (int) ((geoTransform[3] - y) / Math.abs(geoTransform[5]));
        int width = dataset.getRasterXSize();
        int height = dataset.getRasterYSize();
        if (col < 0 || col > width || row < 0 || row > height) {
            log.warn("行列号不在tif范围内");
            return null;
        }
        return new ColumnRow(dataset, col, row);
    }
    private static class ColumnRow {
        public final Dataset dataset;
        public final int col;
        public final int row;
        public ColumnRow(Dataset dataset, int col, int row) {
            this.dataset = dataset;
            this.col = col;
            this.row = row;
        }
    }
    private float calcVelocity(Dataset dataset, int col, int row) {
        float x = readPixelValue(dataset, col, row, 2);
        float y = readPixelValue(dataset, col, row, 3);
        float velocity = 0f;
        if (Float.isNaN(x) && Float.isNaN(y)) {
            velocity = 0f;
        } else if (Float.isNaN(x)) {
            velocity = y;
        } else if (Float.isNaN(y)) {
            velocity = x;
        } else {
            velocity = (float) Math.sqrt(x * x + y * y);
        }
        return velocity;
    }
    private float readPixelValue(Dataset dataset, int col, int row, int bandNum) {
        Band band = dataset.GetRasterBand(bandNum);
        float[] values = new float[1];
        band.ReadRaster(col, row, 1, 1, values);
        return values[0];
    }
    private String formatTime(long time) {
        return TimeFormatUtil.formatTime(time, YYYY_MM_DD_HHMMSS);
    }
}