From a2ee6e0dcdcfd9d1b8011a3cecb4e0fc4f6eeea3 Mon Sep 17 00:00:00 2001 From: dcb <xgybdcb@163.com> Date: 星期五, 06 六月 2025 18:10:32 +0800 Subject: [PATCH] 实时模拟功能实现 --- src/main/java/com/se/nsl/service/TestService.java | 526 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 512 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/se/nsl/service/TestService.java b/src/main/java/com/se/nsl/service/TestService.java index ab5a11b..1cc2825 100644 --- a/src/main/java/com/se/nsl/service/TestService.java +++ b/src/main/java/com/se/nsl/service/TestService.java @@ -1,16 +1,33 @@ package com.se.nsl.service; import cn.hutool.core.io.FileUtil; +import com.alibaba.fastjson.JSON; import com.se.nsl.config.PropertiesConfig; -import com.se.nsl.domain.dto.LayerDto; -import com.se.nsl.domain.dto.ResultDto; -import com.se.nsl.domain.po.DataPo; +import com.se.nsl.domain.dto.*; +import com.se.nsl.domain.po.SimuData; import com.se.nsl.domain.vo.BuildingDepthVo; +import com.se.nsl.helper.ComHelper; +import com.se.nsl.helper.GdalHelper; +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.gdal.ogr.*; import org.springframework.stereotype.Service; import javax.annotation.Resource; +import java.awt.*; +import java.awt.image.BufferedImage; import java.io.File; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.*; import java.util.List; @Slf4j @@ -20,10 +37,13 @@ @Resource PropertiesConfig config; - @Resource - ResultService resultService; + public final static double MIN_VAL = 0.00001; - public void test(DataPo data) { + public final static double MAX_X_OFFSET = 0; + + public final static SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm"); + + public void test(SimuData data) throws IOException { String basePath = config.getInPath() + File.separator + data.getInPath() + File.separator; ResultDto dto = new ResultDto( data.getInPath(), @@ -38,15 +58,12 @@ process(dto, layer); } - private void process(ResultDto dto, LayerDto layer) { + private void process(ResultDto dto, LayerDto layer) throws IOException { try { -// copeTerrain(dto, layer); -// copeBuilding(dto, layer); -// List<BuildingDepthVo> buildings = copeWater(dto, layer); -// copeFlow(dto, layer); -// copeLayerJson(dto, layer); -// copeRainFallJson(dto, layer); -// copeBuildingDepthJson(dto, buildings); + copeTerrain(dto, layer); + copeWater(dto, layer); + copeFlow(dto, layer); + copeLayerJson(dto, layer); } finally { File dir = new File(dto.getTemp()); if (dir.exists()) { @@ -54,4 +71,485 @@ } } } + + public void processRealTime(ResultDto dto, LayerDto layer) throws IOException { + try { + copeTerrainRealTime(dto, layer); + copeWater(dto, layer); + copeFlow(dto, layer); + copeLayerJson(dto, layer); + } finally { + File dir = new File(dto.getTemp()); + if (dir.exists()) { + FileUtil.del(dir); + } + } + } + + public void copeTerrain(ResultDto dto, LayerDto layer) { + Dataset ds = null; + try { + ds = gdal.Open(dto.getTerrainFile(), gdalconstConstants.GA_ReadOnly); // gdalconst + if (null == ds || 0 == ds.getRasterCount()) return; + + setSizes(ds, layer); + setTerrainInfo(ds, layer); + setWaterInfo(dto, layer); + createTerrainPng(dto, ds, layer); + } finally { + if (null != ds) ds.delete(); + } + } + + private void copeTerrainRealTime(ResultDto dto, LayerDto layer) { + Dataset ds = null; + try { + ds = gdal.Open(dto.getTerrainFile(), gdalconstConstants.GA_ReadOnly); // gdalconst + if (null == ds || 0 == ds.getRasterCount()) return; + + setSizes(ds, layer); + setTerrainInfo(ds, layer); + setWaterInfo(dto, layer); + createTerrainPng(dto, ds, layer); + } finally { + if (null != ds) ds.delete(); + } + } + + private void setSizes(Dataset ds, LayerDto layer) { + int xSize = ds.getRasterXSize(), ySize = ds.getRasterYSize(); + double rate = xSize < ySize ? xSize * 1.0 / ySize : ySize * 1.0 / xSize; + + List<int[]> list = layer.getTerrain().getSize(); + for (int i = 0, c = list.size(); i < c; i++) { + if (xSize < ySize) { + list.get(i)[0] = (int) Math.floor(list.get(i)[0] * rate); + } else { + list.get(i)[1] = (int) Math.floor(list.get(i)[1] * rate); + } + } + } + + public void setTerrainInfo(Dataset ds, LayerDto layer) { + Geometry minPoint = GdalHelper.getMinPoint(ds); + Geometry maxPoint = GdalHelper.getMaxPoint(ds); +// double minx = ComHelper.getMinVal(minPoint.GetX(0), 10000000); +// double miny = ComHelper.getMinVal(minPoint.GetY(0), 10000000); +// double maxx = ComHelper.getMaxVal(maxPoint.GetX(0) + MAX_X_OFFSET, 10000000); +// double maxy = ComHelper.getMaxVal(maxPoint.GetY(0), 10000000); + double minx = Double.MAX_VALUE; + double miny = Double.MAX_VALUE; + double maxx = Double.MIN_VALUE; + double maxy = Double.MIN_VALUE; + //layer.setExtension(new ExtensionDto(minx, miny, maxx, maxy, Double.MAX_VALUE, Double.MIN_VALUE)); + + Band band = ds.GetRasterBand(1); + double[] mm = new double[2]; + band.ComputeRasterMinMax(mm, 0); + //layer.getTerrain().setHeight(getMinVal(mm[0], 1000), getMaxVal(mm[1], 1000)); + layer.setExtension(new ExtensionDto(minx, miny, maxx, maxy, mm[0], mm[1])); + } + + public void createTerrainPng(ResultDto dto, Dataset ds, LayerDto layer) { + String terrainPath = dto.getOutPath() + File.separator + "terrain"; + File f = new File(terrainPath); + if (!f.exists() || !f.isDirectory()) f.mkdirs(); + + for (int[] sizes : layer.getTerrain().getSize()) { + String tif = dto.getTemp() + File.separator + "terrain_" + sizes[0] + "_" + sizes[1] + ".tif"; + ComHelper.Resample(ds, tif, sizes[0], sizes[1], layer); + if (!new File(tif).exists()) continue; + + String png = terrainPath + File.separator + sizes[0] + "_" + sizes[1] + ".png"; + Terrain2Png(layer, tif, png, sizes[0], sizes[1]); + } + } + + public void Terrain2Png(LayerDto layer, String tif, String png, int width, int height) { + Dataset ds = null; + try { + ds = gdal.Open(tif, gdalconstConstants.GA_ReadOnly); + if (null == ds || 0 == ds.getRasterCount()) return; + + Band band = ds.GetRasterBand(1); + float[] buffer = new float[width * height]; + //band.ReadRaster(0, 0, width, height, buffer, width, height, 0, 0); + band.ReadRaster(0, 0, width, height, buffer); + layer.getTerrain().getVals().put(width + "_" + height, buffer); + + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + double differ = layer.getExtension().getMaxHeight() - layer.getExtension().getMinHeight(), minHeight = layer.getExtension().getMinHeight(); + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + int offset = x + y * width; + if (Float.isNaN(buffer[offset]) || buffer[offset] < -999 || buffer[offset] < minHeight) continue; + + int r = 0, g, b; + if (buffer[offset] - layer.getExtension().getMaxHeight() > 0) { + g = b = 255; + } else { + int val = (int) ((buffer[offset] - minHeight) / differ * 65535); + g = val / 256; + b = val % 256; + } + + Color color = new Color(r, g, b, 127); + //graphic.drawImage(image, x, y, 1, 1, color, null); + image.setRGB(x, y, color.getRGB()); + } + } + ComHelper.savePng(image, png); + } finally { + if (null != ds) ds.delete(); + } + } + + public void setWaterInfo(ResultDto dto, LayerDto layer) { + List<String> files = getFiles(dto.getWaterPath(), ".tif"); + layer.getWaters().setFiles(files); + if (null == files || files.size() == 0) return; + + setWaterData(layer, files); + setWaterHeight(layer, files); + } + + public List<BuildingDepthVo> copeWater(ResultDto dto, LayerDto layer) { + List<String> files = layer.getWaters().getFiles(); + if (files.size() == 0 || files.size() != layer.getWaters().getData().size()) return null; + + processWaters(dto, files, layer); + + return null; + } + + public List<String> getFiles(String path, String suffix) { + List<String> files = new ArrayList<>(); + ComHelper.getFiles(files, new File(path), suffix); + files.sort((a, b) -> a.compareToIgnoreCase(b)); + + return files; + } + + public void setWaterData(LayerDto layer, List<String> files) { + for (String file : files) { + String fileName = ComHelper.getNameWithExt(file); + long timestamp = TimeFormatUtil.toMillis(fileName, "yyyyMMddHHmmss"); + layer.getWaters().getData().add(timestamp); + } + layer.getDuration().setStart(layer.getWaters().getData().get(0)); + layer.getDuration().setEnd(layer.getWaters().getData().get(layer.getWaters().getData().size() - 1)); + } + + /*public void setWaterData(LayerDto layer, List<String> files) { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(new Date()); + calendar.set(Calendar.MILLISECOND, 0); + + for (String file : files) { + String fileName = ComHelper.getNameWithExt(file); + int year = Integer.parseInt(fileName.substring(0, 4)); + int month = Integer.parseInt(fileName.substring(4, 6)); + int day = Integer.parseInt(fileName.substring(6, 8)); + int hour = Integer.parseInt(fileName.substring(8, 10)); + int minute = Integer.parseInt(fileName.substring(10, 12)); + int second = Integer.parseInt(fileName.substring(12, 14)); + + calendar.set(Calendar.YEAR, year); + calendar.set(Calendar.MONTH, month); + calendar.set(Calendar.DAY_OF_MONTH, day); + calendar.set(Calendar.HOUR_OF_DAY, hour); + calendar.set(Calendar.MINUTE, minute); + calendar.set(Calendar.SECOND, second); + + layer.getWaters().getData().add(calendar.getTime().getTime()); + } + layer.getDuration().setStart(layer.getWaters().getData().get(0)); + layer.getDuration().setEnd(layer.getWaters().getData().get(layer.getWaters().getData().size() - 1)); + }*/ + + public void setWaterHeight(LayerDto layer, List<String> files) { + int c = files.size(), step = files.size() / 10; + if (step < 1) step = 1; + for (int i = 0; i < c; i += step) { + Dataset ds = null; + try { + ds = gdal.Open(files.get(i), gdalconstConstants.GA_ReadOnly); + if (null == ds || 0 == ds.getRasterCount()) return; + + double[] mm = new double[2]; + ds.GetRasterBand(1).ComputeRasterMinMax(mm, 0); + layer.getWaters().setHeight(mm[0], mm[1]); + } finally { + if (null != ds) ds.delete(); + } + } + + layer.getExtension().setMaxHeight(layer.getExtension().getMaxHeight() + layer.getWaters().getMaxHeight() + 1); + layer.getExtension().setMaxHeight(ComHelper.getMaxVal(layer.getExtension().getMaxHeight(), 1000000)); + layer.getExtension().setMinHeight(ComHelper.getMaxVal(layer.getExtension().getMinHeight(), 1000000)); + layer.getExtension().setDiffer(); + } + + public void processWaters(ResultDto dto, List<String> files, LayerDto layer) { + for (int i = 0, c = files.size(); i < c; i++) { + Dataset ds = null; + try { + ds = gdal.Open(files.get(i), gdalconstConstants.GA_ReadOnly); + if (null == ds || 0 == ds.getRasterCount()) return; + if (null == ds.GetSpatialRef()) ds.SetSpatialRef(dto.getSpatialReference()); + + createWaterPng(dto, ds, layer, layer.getWaters().getData().get(i)); + //if (config.getCopyTif()) copyWaterTif(dto, ds, layer.getWaters().getData().get(i)); + ///createVectors(dto, ds, layer, layer.getWaters().getData().get(i)); + } finally { + if (null != ds) ds.delete(); + } + } + } + + public void createWaterPng(ResultDto dto, Dataset ds, LayerDto layer, long ticks) { + String waterPath = dto.getOutPath() + File.separator + "waters" + File.separator + ticks; + File dir = new File(waterPath); + if (!dir.exists() || !dir.isDirectory()) dir.mkdirs(); + + for (int[] sizes : layer.getTerrain().getSize()) { + String fileName = ComHelper.getNameWithExt(ds.GetDescription()) + "_" + sizes[0] + "_" + sizes[1]; + String tif = dto.getTemp() + File.separator + fileName + ".tif"; + ComHelper.Resample2(ds, tif, sizes[0], sizes[1], layer); + if (!new File(tif).exists()) continue; + + String png = waterPath + File.separator + sizes[0] + "_" + sizes[1] + ".png"; + water2Png(dto, layer, tif, png, sizes[0], sizes[1]); + } + } + + public void water2Png(ResultDto dto, LayerDto layer, String tif, String png, int width, int height) { + Dataset ds = null; + try { + ds = gdal.Open(tif, gdalconstConstants.GA_ReadOnly); + if (null == ds || 0 == ds.getRasterCount()) return; + + Band band = ds.GetRasterBand(1); + float[] buffer = new float[width * height]; + band.ReadRaster(0, 0, width, height, buffer); + double[] transform = ds.GetGeoTransform(); + buffer = interpolateGrid(buffer, width, height); + + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + //double differ = layer.getWaters().getMaxHeight() - layer.getWaters().getMinHeight(), minHeight = layer.getWaters().getMinHeight(); + double differ = layer.getExtension().getDiffer(), maxHeight = layer.getExtension().getMaxHeight(), minHeight = layer.getExtension().getMinHeight(); + float[] ts = layer.getTerrain().getVals().get(width + "_" + height); + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + int offset = x + y * width; + //if (Float.isNaN(buffer[offset]) || buffer[offset] < -999 || buffer[offset] < minHeight) continue; + if (Float.isNaN(buffer[offset]) || buffer[offset] < MIN_VAL || Float.isNaN(ts[offset])) continue; + + //double X = transform[0] + x * transform[1] + y * transform[2]; + //double Y = transform[3] + x * transform[4] + y * transform[5]; + //BuildingDto building = intersects(dto, X, Y); + //if (null != building) continue; + + int r = 0, g, b; + if (buffer[offset] + ts[offset] > maxHeight) { + g = b = 255; + } else { + int val = (int) ((buffer[offset] + ts[offset] - minHeight) / differ * 65535); + //int val = (int) (buffer[offset] / differ * 65535); + g = val / 256; + b = val % 256; + } + g = ComHelper.getSafeValue(g); + b = ComHelper.getSafeValue(b); + Color color = new Color(r, g, b, 127); + image.setRGB(x, y, color.getRGB()); + } + } + ComHelper.savePng(image, png); + } finally { + if (null != ds) ds.delete(); + } + } + + /** + * 鎻掑�煎鐞�-鍥涢偦鍩� + */ + public float[] interpolateGrid(float[] buffer, int width, int height) { + float[] tempBuffer = new float[width * height]; + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + int index = x + y * width; + float current = buffer[index]; + if (current <= MIN_VAL) { + float sum = 0; + int count = 0; + // 妫�鏌ヤ笂閭� + if (y > 0) { + float neighbor = buffer[x + (y - 1) * width]; + if (neighbor > MIN_VAL) { + sum += neighbor; + count++; + } + } + // 妫�鏌ヤ笅閭� + if (y < height - 1) { + float neighbor = buffer[x + (y + 1) * width]; + if (neighbor > MIN_VAL) { + sum += neighbor; + count++; + } + } + // 妫�鏌ュ乏閭� + if (x > 0) { + float neighbor = buffer[x - 1 + y * width]; + if (neighbor > MIN_VAL) { + sum += neighbor; + count++; + } + } + // 妫�鏌ュ彸閭� + if (x < width - 1) { + float neighbor = buffer[x + 1 + y * width]; + if (neighbor > MIN_VAL) { + sum += neighbor; + count++; + } + } + // 璁$畻鏂板�� + if (count > 0) { + tempBuffer[index] = (sum / count) * 0.5f; + } else { + tempBuffer[index] = 0; + } + } else { + tempBuffer[index] = current; + } + } + } + //System.arraycopy(tempBuffer, 0, buffer, 0, tempBuffer.length); // 澶嶅埗鍥炲師鏁扮粍 + return tempBuffer; + } + + public void copeFlow(ResultDto dto, LayerDto layer) { + List<String> files = layer.getWaters().getFiles(); + if (null == files || files.isEmpty()) return; + for (int i = 0, c = files.size(); i < c; i++) { + Dataset ds = null; + try { + ds = gdal.Open(files.get(i), gdalconstConstants.GA_ReadOnly); + if (null == ds || 0 == ds.getRasterCount()) return; + if (null == ds.GetSpatialRef()) ds.SetSpatialRef(dto.getSpatialReference()); + + createFlowPng(dto, ds, layer, layer.getWaters().getData().get(i)); + } finally { + if (null != ds) ds.delete(); + } + } + } + + public void createFlowPng(ResultDto dto, Dataset ds, LayerDto layer, long ticks) { + String flowPath = dto.getOutPath() + File.separator + "flows" + File.separator + ticks; + File dir = new File(flowPath); + if (!dir.exists() || !dir.isDirectory()) dir.mkdirs(); + + for (int[] sizes : layer.getTerrain().getSize()) { + String name = ComHelper.getNameWithExt(ds.GetDescription()) + "_" + sizes[0] + "_" + sizes[1]; + String tif = dto.getTemp() + File.separator + name + ".tif"; +// ComHelper.Resample(ds, tif, sizes[0], sizes[1], layer); + if (!new File(tif).exists()) continue; + + String png = flowPath + File.separator + sizes[0] + "_" + sizes[1] + ".png"; + vxyTif2Png(layer, tif, png, sizes[0], sizes[1]); + } + } + + public void vxyTif2Png(LayerDto layer, String tif, String png, int width, int height) { + Dataset ds = null; + try { + ds = gdal.Open(tif, gdalconstConstants.GA_ReadOnly); + if (null == ds || 0 == ds.getRasterCount()) return; + + float[] depthBuffer = new float[width * height]; + float[] vxBuffer = new float[width * height]; + float[] vyBuffer = new float[width * height]; + + ds.GetRasterBand(1).ReadRaster(0, 0, width, height, depthBuffer); + ds.GetRasterBand(2).ReadRaster(0, 0, width, height, vxBuffer); + ds.GetRasterBand(3).ReadRaster(0, 0, width, height, vyBuffer); + + createFlowPng(depthBuffer, vxBuffer, vyBuffer, png, width, height); + } finally { + if (null != ds) ds.delete(); + } + } + + public void createFlowPng(float[] depthBuffer, float[] vxBuffer, float[] vyBuffer, String png, int width, int height) { + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + int offset = x + y * width; + float depth = ComHelper.getFloatValue(depthBuffer[offset]); + float fx = ComHelper.getFloatValue(vxBuffer[offset]); + float fy = ComHelper.getFloatValue(vyBuffer[offset]); + if (Float.isNaN(fx) && Float.isNaN(fy) || (fx < MIN_VAL && fy < MIN_VAL)) continue; + + if (depth == 0) { + fx = 0f; + fy = 0f; + } else { + fx = Float.isNaN(fx) ? 0 : fx / depth; + fy = Float.isNaN(fy) ? 0 : fy / depth; + } + double dr = Math.sqrt(Math.pow(fx, 2) + Math.pow(fy, 2)); + + int r = (int) (dr / 4 * 255); + int g = (int) ((fx / dr * 0.5 + 0.5) * 255); + int b = (int) ((fy / dr * 0.5 + 0.5) * 255); + + Color color = new Color(ComHelper.getSafeValue(r), ComHelper.getSafeValue(g), ComHelper.getSafeValue(b), 127); + image.setRGB(x, y, color.getRGB()); + } + } + ComHelper.savePng(image, png); + } + + /*public void createFlowPng(float[] vxBuffer, float[] vyBuffer, String png, int width, int height) { + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + int offset = x + y * width; + float fx = ComHelper.getFloatValue(vxBuffer[offset]); + float fy = ComHelper.getFloatValue(vyBuffer[offset]); + if (Float.isNaN(fx) && Float.isNaN(fy) || (fx < MIN_VAL && fy < MIN_VAL)) continue; + + fx = Float.isNaN(fx) ? 0 : fx; + fy = Float.isNaN(fy) ? 0 : fy; + double dr = Math.sqrt(Math.pow(fx, 2) + Math.pow(fy, 2)); + + int r = (int) (dr / 4 * 255); + int g = (int) ((fx / dr * 0.5 + 0.5) * 255); + int b = (int) ((fy / dr * 0.5 + 0.5) * 255); + + Color color = new Color(ComHelper.getSafeValue(r), ComHelper.getSafeValue(g), ComHelper.getSafeValue(b), 127); + image.setRGB(x, y, color.getRGB()); + } + } + ComHelper.savePng(image, png); + }*/ + + public void copeLayerJson(ResultDto dto, LayerDto layer) throws IOException { + layer.getWaters().setFiles(null); + layer.getTerrain().setEpsg(null); + layer.getExtension().setDiffer(null); + + String path = dto.getOutPath().replace(config.getOutPath() + File.separator, ""); + layer.setWaterUrl("/hls/w" + path + ".m3u8"); + layer.setFlowUrl("/hls/f" + path + ".m3u8"); + + String json = JSON.toJSONString(layer); +// String filePath = dto.getOutPath() + File.separator + "layer.json"; + String filePath = dto.getOutPath() + File.separator + layer.getName(); + + ComHelper.writeJson(filePath, json); + } } -- Gitblit v1.9.3