package com.se.simu.controller; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.metadata.IPage; import com.google.common.io.Resources; import com.se.simu.config.PropertiesConfig; import com.se.simu.domain.dto.GeDb; import com.se.simu.domain.dto.GeLayer; import com.se.simu.domain.po.DataPo; import com.se.simu.domain.po.SimuPo; import com.se.simu.domain.vo.*; import com.se.simu.service.*; import com.se.simu.utils.*; import io.swagger.annotations.*; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.ClassPathResource; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import java.io.*; import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.*; import java.util.stream.Collectors; @Api(tags = "仿真管理") @Slf4j @RestController @RequestMapping("/simu") @SuppressWarnings("ALL") public class SimuController extends BaseController { @Resource UwService uwService; @Resource GedbService gedbService; @Resource SimuService simuService; @Resource SimuFilesService simuFilesService; @Resource PropertiesConfig config; @Value("${simu-app.filePath}") private String uploadedFolder; @Value("${config.outPath}") private String outPath; @Resource ResultService resultService; private final List FLOOD_TYPE = new ArrayList<>(Arrays.asList("沙袋", "防水板")); @ApiOperation(value = "创建") @PostMapping(value = "/create", produces = "application/json; charset=UTF-8") public R create(@RequestBody @ApiParam("创建仿真视图类") CreateSimuVo vo) { try { if (null == vo.getTotal() || vo.getTotal() < 1 || vo.getTotal() > 1000) { return fail("降雨量不能为空,且取值在1~1000之间"); } if (null == vo.getDuration() || vo.getDuration() < 1 || vo.getDuration() > 10080) { return fail("仿真时长不能为空,且取值在1~10080之间"); } if (null == vo.getMinx() || null == vo.getMiny() || null == vo.getMaxx() || null == vo.getMaxy()) { return fail("选择范围不能为空", false); } if (null == vo.getPid() || vo.getPid() < 0) { vo.setPid(0); } if (null == vo.getNum() || vo.getNum() < 1) { vo.setNum(simuService.getMaxId() + 1); } if (null == vo.getPid() || vo.getPid() < 0) { vo.setPid(0); } if (null == vo.getStartTime()) { vo.setStartTime(new Date()); } if (vo.getPid() > 0) { SimuPo pp = simuService.getSimuByPid(vo.getPid()); if (null == pp) { return fail("pid不存在"); } if (null == vo.getFloodStart() || vo.getFloodStart() < 1 || vo.getFloodStart() > vo.getDuration() * 60) { return fail("防汛开始时间不能为空,且取值在1~" + (vo.getDuration() * 60) + "之间"); } if (null == vo.getFloodEnd() || vo.getFloodEnd() < vo.getFloodStart() || vo.getFloodEnd() > vo.getDuration() * 60) { return fail("防汛结束时间不能为空,且取值在" + vo.getFloodStart() + "~" + (vo.getDuration() * 60) + "之间"); } if (null == vo.getFloodHeight() || vo.getFloodHeight() < 1 || vo.getFloodHeight() > 2000) { return fail("防汛高度不能为空,且取值在1~2000之间"); } if (!FLOOD_TYPE.contains(vo.getFloodType())) { return fail("防汛类型不能为空,且只能是沙袋和防水板"); } if (null == vo.getFloodMinx() || null == vo.getFloodMiny() || null == vo.getFloodMaxx() || null == vo.getFloodMaxy()) { return fail("防汛范围不能为空", false); } } boolean flag = simuService.create(vo); return success(flag, flag ? "成功" : "失败"); } catch (Exception ex) { return fail(ex, null); } } @ApiOperation(value = "删除") @ApiImplicitParams({ @ApiImplicitParam(name = "ids", value = "ID", dataType = "Integer", paramType = "query", allowMultiple = true, example = "0") }) @GetMapping(value = "/del") public R del(@RequestParam List ids) { try { if (ids == null || ids.isEmpty()) { return fail("日志ID不能为空", null); } int count = simuService.del(ids); return success(count); } catch (Exception ex) { return fail(ex, null); } } @ApiOperation(value = "获取") @GetMapping("/get") public R get(@ApiParam("仿真视图类") SimuVo vo) { try { if (null == vo) { vo = new SimuVo(); } if (null == vo.getPageSize() || vo.getPageSize() < 1) { vo.setPageSize(10); } if (null == vo.getPageIndex() || vo.getPageIndex() < 1) { vo.setPageIndex(1); } IPage paged = simuService.get(vo); if (null == paged) { return success(null, 0); } return success(paged.getRecords(), paged.getTotal()); } catch (Exception ex) { return fail(ex, null); } } @ApiOperation(value = "降水范围校验") @GetMapping("/rangeVerify") public R rangeVerify(@RequestParam @ApiParam("最小X") double minx, @RequestParam @ApiParam("最小y") double miny, @RequestParam @ApiParam("最大X") double maxx, @RequestParam @ApiParam("最大y") double maxy) { try { DataPo data = new DataPo(); data.setMinx(minx); data.setMiny(miny); data.setMaxx(maxx); data.setMaxy(maxy); data.setEpsg(4326); String token = gedbService.getToken(); GeDb db = gedbService.connectGedb(token, data); List layers = gedbService.getLayers(token, db); boolean result = gedbService.queryBboxCount(token, db, layers); log.info("result = " + result); return success(result); // return success(gedbService.queryBboxCount(token, db, layers)); } catch (Exception ex) { return fail(ex, false); } } /** * 文件创建模拟 *

* "状态: * 0-创建仿真任务, * 1-连接GEDB库, * 2-下载空间数据, * 3-下载高程数据, * 4-生成降雨文件, * 5-生成配置文件, * 6-模拟内涝仿真, * 7-处理水位文件, * 8-处理排水文件, * 9-处理仿真结果, * 10-完成,-10-出错 * * @param vo VO * @return {@link R}<{@link Object}> */ @ApiOperation(value = "文件创建") @PostMapping(value = "/file_create", produces = "application/json; charset=UTF-8") public R fileCreate(@RequestBody @ApiParam("创建仿真视图类") CreateFilesSimuVo vo) throws IOException { // 获取上传文件路径 String targetDir = uploadedFolder; log.info("上传文件路径:{}", targetDir); // 获取各个文件的地址 String floodFile = vo.getFloodFile(); log.info("范围文件地址:{}", floodFile); try { // 判断是否绘制区域 if (!StringUtils.isEmpty(vo.getMaxx().toString()) && !Objects.isNull(vo.getMaxx())) { rangeVerify(vo.getMinx(), vo.getMaxx(), vo.getMiny(), vo.getMaxy()); log.info("绘制区域范围验证通过!"); } else // 判断地址不为空 if (StringUtils.isEmpty(floodFile)) { return fail("范围文件地址不能为空", false); } else { // 获取文件的后缀名 String fileName = floodFile.substring(floodFile.lastIndexOf(".")); // 判断后缀名是否为.shp if (!fileName.equalsIgnoreCase(".shp")) { return fail("范围文件格式不正确", false); } else { // 1 读取shp文件,获取范围值 JSONObject jsonObject = ShpToolUtils.readShp(floodFile); // 2 获取jsonObject中的范围值 Double minX = jsonObject.getDouble("minY"); Double maxX = jsonObject.getDouble("maxY"); Double minY = jsonObject.getDouble("minX"); Double maxY = jsonObject.getDouble("maxX"); // 3 判断范围值是否为空 // vo.setMinx(jsonObject.getDouble("minX")); // vo.setMaxx(jsonObject.getDouble("maxX")); // vo.setMiny(jsonObject.getDouble("minY")); // vo.setMaxy(jsonObject.getDouble("maxY")); vo.setMinx(jsonObject.getDouble("minY")); vo.setMaxx(jsonObject.getDouble("maxY")); vo.setMiny(jsonObject.getDouble("minX")); vo.setMaxy(jsonObject.getDouble("maxX")); rangeVerify(minX, maxX, minY, maxY); } } // todo: 解析范围文件 根据不同的的格式文件进行不同的解析,获取需要计算的范围值 // 上传格式:.shp/.tiff/.img/.geojson // 重新给vo赋值 } catch (Exception e) { log.error("解析范围文件失败"); if (null == vo.getMinx() || null == vo.getMiny() || null == vo.getMaxx() || null == vo.getMaxy()) { return fail("解析范围文件失败!选择范围不能为空,请重新选择文件!", false); } } JSONArray jsonArray = new JSONArray(); String stationFile = vo.getStationFile(); log.info("站点文件shp地址:{}", stationFile); try { // 判断地址不为空 if (StringUtils.isEmpty(stationFile)) { return fail("站点文件shp地址不能为空", false); } // 1 读取shp文件,获取站点坐标值 jsonArray = ShpToolUtils.readShpGetLocal(stationFile); System.out.println("jsonArray = " + jsonArray); } catch (Exception e) { log.error("解析站点文件shp失败"); } String stationRainFile = vo.getStationRainFile(); log.info("站点雨量CSV文件地址:{}", floodFile); JSONArray array = new JSONArray(); // 创建表名 时间戳 String tableName = "station_rain_" + System.currentTimeMillis(); try { // 判断地址不为空 if (StringUtils.isEmpty(stationRainFile)) { return fail("站点雨量CSV文件地址不能为空", false); } // 1 读取CSV 文件 array = CsvToSQLiteUtils.readCsvSaveLocal(stationRainFile, tableName); // 获取仿真时间 duration Integer duration = CsvToSQLiteUtils.getDuration(tableName); log.info("仿真时间 duration = {}", duration); vo.setDuration(duration); // 获取降雨总量 total Double total = CsvToSQLiteUtils.getTotal(tableName); log.info("降雨总量 total = {}", total); vo.setTotal(total); } catch (Exception e) { log.error("解析站点雨量CSV文件失败"); } // TODO: 2024/12/24 根据这些文件的地址,获取文件内容,创建仿真视图 try { if (null == vo.getDuration() || vo.getDuration() < 1 || vo.getDuration() > 10080) { return fail("仿真时长不能为空,且取值在1~10080之间"); } if (null == vo.getPid() || vo.getPid() < 0) { vo.setPid(0); } if (null == vo.getNum() || vo.getNum() < 1) { vo.setNum(simuService.getMaxId() + 1); } if (null == vo.getStartTime()) { vo.setStartTime(new Date()); } // 防汛作业 if (vo.getPid() > 0) { SimuPo pp = simuService.getSimuByPid(vo.getPid()); if (null == pp) { return fail("pid不存在"); } if (null == vo.getFloodStart() || vo.getFloodStart() < 1 || vo.getFloodStart() > vo.getDuration() * 60) { return fail("防汛开始时间不能为空,且取值在1~" + (vo.getDuration() * 60) + "之间"); } if (null == vo.getFloodEnd() || vo.getFloodEnd() < vo.getFloodStart() || vo.getFloodEnd() > vo.getDuration() * 60) { return fail("防汛结束时间不能为空,且取值在" + vo.getFloodStart() + "~" + (vo.getDuration() * 60) + "之间"); } if (null == vo.getFloodHeight() || vo.getFloodHeight() < 1 || vo.getFloodHeight() > 2000) { return fail("防汛高度不能为空,且取值在1~2000之间"); } if (!FLOOD_TYPE.contains(vo.getFloodType())) { return fail("防汛类型不能为空,且只能是沙袋和防水板"); } if (null == vo.getFloodMinx() || null == vo.getFloodMiny() || null == vo.getFloodMaxx() || null == vo.getFloodMaxy()) { return fail("防汛范围不能为空", false); } } // 开始模拟计算 boolean flag = simuFilesService.createByfiles(vo); return success(flag, flag ? "成功" : "失败"); } catch (Exception ex) { return fail(ex, null); } } @ApiOperation(value = "tarr文件组装") @GetMapping(value = "/saveZarr", produces = "application/json; charset=UTF-8") public R saveZarr(@RequestParam("name") String tableName) throws IOException { List list = CsvToSQLiteUtils.getNameList(tableName); String path = outPath + "\\"; String rainfall = "rainfall\\"; String basePath = path + tableName + "\\" + rainfall; JSONObject jsonObject = getModule("rainfallmodule.json"); for (String src : list ) { File directories = new File(basePath); if (!directories.exists()) { directories.mkdirs(); System.out.println("Directories created successfully."); } else { System.out.println("Directories already exist."); } List stationRainVos = CsvToSQLiteUtils.getList(tableName, src); ZarrUtils.saveZarrRainfall(basePath + src, stationRainVos); ZarrUtils.saveZarrTime(basePath + src, stationRainVos); ZipUtils.toZarr(basePath + src, basePath + src + ".zip"); System.out.println(src + "的zarr数据生成====================="); //json拼装 String uuid = "UUID_" + UUID.randomUUID().toString(); //拼装zarr JSONObject dynamizer = new JSONObject(); dynamizer.put("url", rainfall.replace("\\", "/") + src + ".zarr"); dynamizer.put("gmlId", uuid); jsonObject.getJSONArray("Dynamizers").add(dynamizer); //拼装坐标 JSONArray vertice = new JSONArray(); vertice.add(stationRainVos.get(0).getLongitude()); vertice.add(stationRainVos.get(0).getLatitude()); vertice.add(0.0); jsonObject.getJSONArray("vertices").add(vertice); //拼装基础信息 JSONObject cityObject = new JSONObject(); cityObject.put("type", "+Rainfall"); JSONObject attribute = new JSONObject(); attribute.put("name", src); cityObject.put("attributes", attribute); JSONArray geometry = new JSONArray(); JSONObject metry = new JSONObject(); metry.put("type", "MultiPoint"); metry.put("lod", 0); JSONArray boundarie = new JSONArray(); boundarie.add(jsonObject.getJSONArray("vertices").size()-1); metry.put("boundaries", boundarie); geometry.add(metry); cityObject.put("geometry", geometry); jsonObject.getJSONObject("CityObjects").put(uuid, cityObject); } File jsonFile = new File(path + tableName + "\\降雨量.json"); if (jsonFile.exists()) { jsonFile.createNewFile(); } FileWriter fileWriter = new FileWriter(path + tableName + "\\降雨量.json"); fileWriter.write(jsonObject.toJSONString()); fileWriter.close(); return success(true); } @ApiOperation(value = "管点转cityjson") @GetMapping(value = "/pointToCityJson", produces = "application/json; charset=UTF-8") public R pointToCityJson(@RequestParam("shpPath") String shpPath) throws Exception { String path = outPath + "\\point\\"; List> list = ShpReadUtils.readPointShp(shpPath); JSONObject jsonObject = getModule("pointmodule.json"); for (Map map : list ) { //拼装坐标 JSONArray vertice = new JSONArray(); vertice.add(map.get("lon")); vertice.add(map.get("lat")); vertice.add(0.0); jsonObject.getJSONArray("vertices").add(vertice); //拼装基础信息 JSONObject cityObject = new JSONObject(); cityObject.put("type", "+PipePoint"); JSONObject attribute = new JSONObject(); attribute.put("name", map.get("fsw")); cityObject.put("attributes", attribute); JSONArray geometry = new JSONArray(); JSONObject metry = new JSONObject(); metry.put("type", "MultiPoint"); metry.put("lod", 0); JSONArray boundarie = new JSONArray(); boundarie.add(jsonObject.getJSONArray("vertices").size()-1); metry.put("boundaries", boundarie); geometry.add(metry); cityObject.put("geometry", geometry); jsonObject.getJSONObject("CityObjects").put("UUID_" + UUID.randomUUID().toString(), cityObject); } long times = System.currentTimeMillis(); String pointPath = path + times + "\\管点.json"; File dirFile = new File(path + times); if (!dirFile.exists()) { dirFile.mkdirs(); } FileWriter fileWriter = new FileWriter(pointPath); fileWriter.write(jsonObject.toJSONString()); fileWriter.close(); return success(pointPath); } @ApiOperation(value = "管线转cityjson") @GetMapping(value = "/lineToCityJson", produces = "application/json; charset=UTF-8") public R lineToCityJson(@RequestParam("shpPath") String shpPath) throws Exception { String path = outPath + "\\line\\"; List> list = ShpReadUtils.readPointShp(shpPath); JSONObject jsonObject = getModule("linemodule.json"); for (Map map : list ) { //拼装基础信息 JSONObject cityObject = new JSONObject(); cityObject.put("type", "+PipeLine"); JSONObject attribute = new JSONObject(); attribute.put("name", map.get("msfs")); JSONArray geometry = new JSONArray(); JSONObject metry = new JSONObject(); metry.put("type", "MultiLineString"); metry.put("lod", 0); JSONArray boundarie = new JSONArray(); JSONArray array = JSONObject.parseObject(map.get("the_geom").toString()).getJSONArray("coordinates"); for (int i = 0; i < array.size(); i++) { JSONObject object = JSONObject.parseObject(array.get(i).toString()); jsonObject.getJSONArray("vertices").add(ProjectionToGeographicUtil.getPoint(Double.valueOf(object.get("x").toString()),Double.valueOf(object.get("y").toString()))); boundarie.add(jsonObject.getJSONArray("vertices").size()-1); } JSONArray jsonArray=new JSONArray(); jsonArray.add(boundarie); metry.put("boundaries", jsonArray); cityObject.put("geometry",metry); cityObject.put("attributes",attribute); cityObject.put("attributes", attribute); geometry.add(metry); jsonObject.getJSONObject("CityObjects").put("UUID_" + UUID.randomUUID().toString(), cityObject); } long times = System.currentTimeMillis(); String pointPath = path + times + "\\管线.json"; File dirFile = new File(path + times); if (!dirFile.exists()) { dirFile.mkdirs(); } FileWriter fileWriter = new FileWriter(pointPath); fileWriter.write(jsonObject.toJSONString()); fileWriter.close(); return success(pointPath); } @ApiOperation(value = "地形转cityjson") @GetMapping(value = "/terrainToCityJson", produces = "application/json; charset=UTF-8") public R terrainToCityJson(@RequestParam("tifPath") String tifPath) throws Exception { long times = System.currentTimeMillis(); String path = outPath + "\\terrain\\"+times+"\\"; File dirFile = new File(path+"appearance"); if (!dirFile.exists()) { dirFile.mkdirs(); } String pngPath=path+"appearance\\terrain.png"; TiffToRGBUtil.tifToPng(tifPath,pngPath); JSONObject jsonObject = getModule("terrainmodule.json"); jsonObject.put("vertices",TiffCoordinateExtractorUtil.getCoordinate(tifPath)); FileWriter fileWriter = new FileWriter(path + "terrain.json"); fileWriter.write(jsonObject.toJSONString()); fileWriter.close(); return success(path); } public JSONObject getModule(String moduleName) { JSONObject jsonObject = new JSONObject(); try { URL resource = Resources.getResource(moduleName); String fileContent = Resources.toString(resource, StandardCharsets.UTF_8); jsonObject = JSONObject.parseObject(fileContent); System.out.println(fileContent); } catch (Exception e) { e.printStackTrace(); } return jsonObject; } }