| | |
| | | package com.flightfeather.uav.lightshare.service.impl |
| | | |
| | | import com.flightfeather.uav.biz.satellite.GridGroupOption |
| | | import com.flightfeather.uav.biz.satellite.SatelliteGridManage |
| | | import com.flightfeather.uav.biz.satellite.SatelliteGridUtil |
| | | import com.flightfeather.uav.common.exception.BizException |
| | | import com.flightfeather.uav.domain.entity.GridCell |
| | | import com.flightfeather.uav.domain.entity.GridGroup |
| | | import com.flightfeather.uav.common.utils.TimeUtil |
| | | import com.flightfeather.uav.domain.entity.* |
| | | import com.flightfeather.uav.domain.repository.MissionRep |
| | | import com.flightfeather.uav.domain.repository.RealTimeDataRep |
| | | import com.flightfeather.uav.domain.repository.SatelliteGridRep |
| | | import com.flightfeather.uav.lightshare.eunm.GridType |
| | | import com.flightfeather.uav.lightshare.eunm.SatelliteDataType |
| | | import com.flightfeather.uav.lightshare.service.SatelliteDataCalculateService |
| | | import org.springframework.beans.BeanUtils |
| | | import org.springframework.stereotype.Service |
| | | import org.springframework.transaction.annotation.Transactional |
| | | import java.util.Date |
| | | import kotlin.math.round |
| | | |
| | | /** |
| | | * 卫星网格坐标及监测数据二次计算 |
| | |
| | | * @author feiyu02 |
| | | */ |
| | | @Service |
| | | class SatelliteDataCalculateServiceImpl(private val satelliteGridRep: SatelliteGridRep) : SatelliteDataCalculateService { |
| | | class SatelliteDataCalculateServiceImpl( |
| | | private val satelliteGridRep: SatelliteGridRep, |
| | | private val realTimeDataRep: RealTimeDataRep, |
| | | private val missionRep: MissionRep, |
| | | ) : SatelliteDataCalculateService { |
| | | |
| | | |
| | | override fun calGridVertex(groupId: Int): List<GridCell?> { |
| | |
| | | } |
| | | |
| | | override fun splitGrid(groupId: Int, scale: Int): List<GridCell?> { |
| | | // 检查该网格属性是否合规 |
| | | val gridGroup = |
| | | satelliteGridRep.fetchGridGroup(groupId) ?: throw BizException("该网格组不存在,无法进行网格细分") |
| | | if (gridGroup.length == null) throw BizException("该网格组没有设定网格边长,无法进行网格细分") |
| | | |
| | | // 检查该网格下该种类的细分网格是否存在,若不存在,则新建 |
| | | satelliteGridRep.fetchGridGroup(groupId) |
| | | val searchGridGroup = GridGroup().apply { |
| | | type = GridType.Sub.name.lowercase() |
| | | fatherGroupId = gridGroup.id |
| | | length = round(gridGroup.length / scale) |
| | | } |
| | | val subGridGroupList = satelliteGridRep.fetchGridGroup(searchGridGroup) |
| | | // 若细分网格记录超过1个,说明业务逻辑存在问题,相同边长的细分网格应该只有1个 |
| | | if (subGridGroupList.size > 1) { |
| | | throw BizException("该网格组下${searchGridGroup.length}米边长的网格记录超过1个,无法再进行网格细分,并且请检查生成逻辑是否问题") |
| | | } |
| | | // 若细分网格记录有且只有1个,则无需再次细分,直接返回已有结果 |
| | | else if (subGridGroupList.size == 1) { |
| | | val g = subGridGroupList.first() |
| | | ?: throw BizException("该网格组下的细分网格记录已损坏,无法使用,请检查数据库记录") |
| | | return satelliteGridRep.fetchGridCell(g.id) |
| | | } |
| | | // 当没有记录时,执行生成逻辑 |
| | | |
| | | // 生成新的细分网格组记录 |
| | | val newGridGroup = GridGroup() |
| | | BeanUtils.copyProperties(gridGroup, newGridGroup) |
| | | newGridGroup.apply { |
| | | id = null |
| | | name += "${searchGridGroup.length.toInt()}米细分" |
| | | createTime = Date() |
| | | length = searchGridGroup.length |
| | | type = GridType.Sub.name.lowercase() |
| | | fatherGroupId = groupId |
| | | } |
| | | satelliteGridRep.insertGridGroup(newGridGroup) |
| | | |
| | | // 获取具体网格信息 |
| | | val cellList = satelliteGridRep.fetchGridCell(groupId) |
| | | // 按照给定的拆分系数进行拆分 |
| | | // val subCellList = SatelliteGridManage.splitGrid(cellList, scale) |
| | | val subCellList = SatelliteGridManage.splitGrid(cellList, scale, newGridGroup.id) |
| | | satelliteGridRep.insertGridCell(subCellList) |
| | | |
| | | return emptyList() |
| | | return subCellList |
| | | } |
| | | |
| | | @Transactional |
| | | override fun splitData(groupId: Int, dataId:Int): List<GridDataDetail?> { |
| | | // 检查是否是细分网格类型 |
| | | val gridGroup = satelliteGridRep.fetchGridGroup(groupId) ?: throw BizException("该网格组不存在,无法进行细分网格数据映射") |
| | | if (gridGroup.type != GridType.Sub.name.lowercase()) throw BizException("该网格组不是细分网格类型存在,无法进行细分网格数据映射") |
| | | |
| | | val subGridCellList = satelliteGridRep.fetchGridCell(groupId) |
| | | val originGridData = satelliteGridRep.fetchGridData(dataId) |
| | | val originGridDataDetailList = satelliteGridRep.fetchGridDataDetail(dataId, null, null) |
| | | |
| | | val subGridData = GridData().apply { |
| | | this.groupId = groupId |
| | | dataTime = originGridData?.dataTime |
| | | type = SatelliteDataType.Sub.value.toByte() |
| | | } |
| | | satelliteGridRep.insertGridData(subGridData) |
| | | |
| | | val subGridDataDetailList = |
| | | SatelliteGridManage.splitData(subGridCellList, subGridData, originGridDataDetailList) |
| | | |
| | | satelliteGridRep.insertGridDataDetail(subGridDataDetailList) |
| | | |
| | | return subGridDataDetailList |
| | | } |
| | | |
| | | @Transactional |
| | | override fun dataFusion(missionCode: String, groupId: Int): List<GridDataDetail?> { |
| | | // 查询走航任务及对应走航监测数据 |
| | | val mission = missionRep.findOne(missionCode) ?: throw BizException("任务不存在") |
| | | val data = realTimeDataRep.fetchData(mission) |
| | | |
| | | // 查找是否已有走航融合记录 |
| | | val oldGridDataList = satelliteGridRep.fetchGridData(GridData().apply { |
| | | this.groupId = groupId |
| | | mixDataId = missionCode |
| | | this.type = SatelliteDataType.Monitor.value.toByte() |
| | | }) |
| | | |
| | | if (oldGridDataList.isEmpty()) { |
| | | // 创建融合数据索引对象 |
| | | val newGridData = GridData().apply { |
| | | this.groupId = groupId |
| | | dataTime = mission.startTime |
| | | type = SatelliteDataType.Monitor.value.toByte() |
| | | this.missionCode = mission.missionCode |
| | | // Fixme 2025.3.27: 行政区划在走航任务添加对应字段后进行赋值 |
| | | provinceCode |
| | | provinceName |
| | | cityCode |
| | | cityName |
| | | districtCode |
| | | districtName = mission.districtName |
| | | // Fixme 2025.3.27: 所属监测点区域目前需要通过用户选择确定 |
| | | zone |
| | | pollutionDegreeIndex |
| | | pollutionDegree |
| | | |
| | | val period = TimeUtil.getDayTimeTag(mission.startTime, mission.endTime) |
| | | dayTimePeriod = period?.first |
| | | dayTimePeriodStart = period?.second |
| | | dayTimePeriodEnd = period?.third |
| | | } |
| | | satelliteGridRep.insertGridData(newGridData) |
| | | |
| | | // 查询网格单元格信息 |
| | | val gridCellList = satelliteGridRep.fetchGridCell(groupId) |
| | | |
| | | // 将走航数据和卫星网格进行融合计算 |
| | | val gridDataDetailList = SatelliteGridManage.dataFusion(data, newGridData, gridCellList) |
| | | satelliteGridRep.insertGridDataDetail(gridDataDetailList) |
| | | |
| | | return gridDataDetailList |
| | | } else { |
| | | val oldGridData = oldGridDataList.first() |
| | | val oldGridDataDetailList = satelliteGridRep.fetchGridDataDetail(oldGridData?.id, oldGridData?.groupId, |
| | | null) |
| | | // 查询网格单元格信息 |
| | | val gridCellList = satelliteGridRep.fetchGridCell(groupId) |
| | | // 将走航数据和卫星网格进行融合计算 |
| | | val gridDataDetailList = SatelliteGridManage.dataFusion(data, oldGridData, gridCellList) |
| | | |
| | | // 将已有的数据id赋值给新的融合结果,两组结果均以根据cellId顺序排列,所以直接循环赋值 |
| | | gridDataDetailList.forEachIndexed { index, gridDataDetail -> |
| | | gridDataDetail.id = oldGridDataDetailList[index]?.id |
| | | } |
| | | |
| | | satelliteGridRep.updateGridDataDetail(gridDataDetailList) |
| | | |
| | | return gridDataDetailList |
| | | } |
| | | } |
| | | |
| | | override fun buildHeatmap(groupId: Int, gridDataDetailList: List<GridDataDetail>, searchLength:Int): List<GridDataDetail> { |
| | | val gridCellList = satelliteGridRep.fetchGridCell(groupId) |
| | | val originCellIdList = gridDataDetailList.map { it.cellId } |
| | | // Fixme 2025.3.24: 此处根据现有的网格信息设计方式,使用临时的参数,后续将网格通过二维坐标形式表示,此处参数去除 |
| | | val option = GridGroupOption(120, 90, 10, 10) |
| | | |
| | | val resMap = mutableMapOf<Int, MutableList<GridDataDetail>>() |
| | | |
| | | // 循环计算每个网格的周边扩散网格结果 |
| | | gridDataDetailList.forEach {gdd -> |
| | | SatelliteGridManage.heatMap(gdd, gridCellList, option, searchLength).forEach {r -> |
| | | if (!originCellIdList.contains(r.cellId)) { |
| | | if (!resMap.containsKey(r.cellId)) { |
| | | resMap[r.cellId] = mutableListOf() |
| | | } |
| | | resMap[r.cellId]?.add(r) |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 将所有结果格式化,同时重叠网格进行监测数据均值计算 |
| | | val result = mutableListOf<GridDataDetail>() |
| | | resMap.forEach { (_, v) -> |
| | | result.add(v.avg().apply { |
| | | this.dataId = v.first().dataId |
| | | this.groupId = v.first().groupId |
| | | this.cellId = v.first().cellId |
| | | }) |
| | | } |
| | | result.addAll(gridDataDetailList) |
| | | |
| | | return result |
| | | } |
| | | } |