package com.se.nsl.service; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 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.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.Arrays; import java.util.List; @Slf4j @Service @SuppressWarnings("ALL") public class SimuService { public static final String TIF_EXTSION = ".tif"; @Resource SimuMapper simuMapper; @Resource PropertiesConfig config; /** * 分页查询推演模拟 * * @param pageNum 页码 * @param pageSize 每页数量 * @return 分页后的推演模拟 */ public IPage selectPage(SimuVo vo, int pageNum, int pageSize) { QueryWrapper wrapper = getPageWrapper(vo, pageNum, pageSize); Page page = new Page<>(pageNum, pageSize); page.addOrder(OrderItem.desc("id")); IPage paged = simuMapper.selectPage(page, wrapper); return paged; } private QueryWrapper getPageWrapper(SimuVo vo, int pageNum, int pageSize) { QueryWrapper wrapper = new QueryWrapper<>(); if (null != vo.getId()) { wrapper.eq("id", vo.getId()); } if (!StringHelper.isEmpty(vo.getName())) { wrapper.like("lower(name)", vo.getName().trim().toLowerCase()); } if (!StringHelper.isEmpty(vo.getServiceName())) { wrapper.like("service_name", vo.getServiceName().trim()); } if (null != vo.getType()) { wrapper.eq("type", vo.getType()); } if (null != vo.getAreaType()) { wrapper.eq("area_type", vo.getAreaType()); } if (null != vo.getStatus()) { wrapper.eq("status", vo.getStatus()); } return wrapper; } /** * 根据ID批量删除推演模拟 * * @param ids 要删除的区域ID列表 * @return 删除成功的记录数 */ public int deleteByIds(List ids) { return simuMapper.deleteBatchIds(ids); } /** * 新增推演模拟 * * @param Simu 推演模拟对象 * @return 新增成功的记录数 */ public int insert(Simu simu) { return simuMapper.insert(simu); } public int inserts(List list) { return simuMapper.inserts(list); } /** * 根据ID查询 * * @param id ID * @return Simu */ public Simu selectById(Integer id) { return simuMapper.selectById(id); } /** * 修改推演模拟 * * @param Simu 推演模拟对象 * @return 修改成功的记录数 */ 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); } 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); return result; } 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) { // Instant instant = Instant.ofEpochMilli(time); // LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault()); // DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss"); // return localDateTime.format(formatter); return TimeFormatUtil.formatTime(time, "yyyyMMddHHmmss"); } }