feiyu02
2025-03-27 bde043c8fd1a076f44c402dd56c62d401afbfb16
src/main/kotlin/com/flightfeather/uav/biz/satellite/SatelliteGridManage.kt
@@ -1,10 +1,12 @@
package com.flightfeather.uav.biz.satellite
import com.flightfeather.uav.common.utils.MapUtil
import com.flightfeather.uav.domain.entity.BaseRealTimeData
import com.flightfeather.uav.domain.entity.GridCell
import com.flightfeather.uav.domain.entity.GridData
import com.flightfeather.uav.domain.entity.GridDataDetail
import com.flightfeather.uav.domain.entity.*
import com.flightfeather.uav.model.underwaygrid.GridCellAndData
import com.flightfeather.uav.model.underwaygrid.GridCellSop
import com.flightfeather.uav.model.underwaygrid.UnderwayGridModel
import com.flightfeather.uav.socket.eunm.FactorType
import org.springframework.beans.BeanUtils
import kotlin.math.PI
import kotlin.math.sqrt
@@ -20,7 +22,9 @@
    /**
     * 根据正方形网格中心点坐标,计算4个顶点坐标
     * 网格中心点坐标按照从左到右、从上到下的顺序排列
     * @date 2025.1.8
     * @param points 网格中心坐标点数组
     * @return 网格4个顶点经纬度坐标
     */
    fun calGridVertex(points: List<Pair<Double, Double>>): List<GridVertex> {
        // 网格少于2个,则无法绘制
@@ -69,10 +73,11 @@
    /**
     * 拆分网格为细分网格,所有网格应该是相同边长的正方形
     * 根据相似矩形的原理,可以分别按比例得到每个细分网格的经纬度
     * @date 2025.1.17
     * @param gridCellList 原始网格数组
     * @param scale 拆分的系数,例如 2,表示将原有网格按边长的 1/2 拆分成 2 * 2 的4个网格
     * @param groupId 细分后的网格所属的网格组id
     * @return
     * @return 细分网格
     */
    fun splitGrid(gridCellList: List<GridCell?>, scale: Int, groupId:Int): List<GridCell?> {
        if (scale <= 0) throw IllegalArgumentException("网格拆分的数量不能小于1")
@@ -165,9 +170,11 @@
    /**
     * 拆分数据,将原始卫星网格遥测数据映射到对应细分网格上
     * @param subGridCellList 细分网格, 按照
     * @date 2025.2.7
     * @param subGridCellList 细分网格
     * @param subGridData 细分网格对应的数据索引
     * @param originGridDataDetailList 细分网格所属网格的原始网格数据
     * @return 映射后的细分网格遥测数据
     */
    fun splitData(
        subGridCellList: List<GridCell?>, subGridData: GridData, originGridDataDetailList: List<GridDataDetail?>
@@ -217,21 +224,110 @@
    }
    /**
     * 数据融合
     * 走航数据和卫星网格融合
     * 数据融合采用均值方式统计(暂时)
     * @date 2025.2.7
     * @param realTimeDataList 待融合的走航监测数据
     * @param gridData 融合后的数据组索引
     * @param gridCellList 待融合的卫星网格
     * @return 融合后的网格监测数据
     */
    fun dataFusion(realTimeDataList:List<BaseRealTimeData>, gridData: GridData, gridCellList: List<GridCell?>) {
        // 遍历走航监测数据,计算每个点所在网格,并形成网格值
    fun dataFusion(
        realTimeDataList: List<BaseRealTimeData>,
        gridData: GridData?,
        gridCellList: List<GridCell?>,
    ): List<GridDataDetail> {
        // 遍历走航监测数据,计算每个点所在网格
        val dataMap = mutableMapOf<GridCell, MutableList<BaseRealTimeData>>()
        realTimeDataList.forEach {
            it.longitude
            it.latitude
            gridCellList.forEach {
            if (it.longitude == null || it.latitude == null) return@forEach
            }
            SatelliteGridUtil.searchGirdIn(it.longitude!!.toDouble() to it.latitude!!.toDouble(), gridCellList)
                ?.let { cell ->
                    if (!dataMap.containsKey(cell)) {
                        dataMap[cell] = mutableListOf()
                    }
                    dataMap[cell]?.add(it)
                }
        }
        // 统计每个网格中的均值
        // Fixme 2025.2.20 暂时默认以均值方式统计,后续调整为多种方式并支持用户选择
        val gridDataDetailList = mutableListOf<GridDataDetail>()
        dataMap.forEach { (k, v) ->
            val avgData = v.avg()
            val dataDetail = GridDataDetail()
            BeanUtils.copyProperties(avgData, dataDetail)
            dataDetail.apply {
                dataId = gridData?.id
                groupId = k.groupId
                cellId = k.cellIndex
                rank
            }
            gridDataDetailList.add(dataDetail)
        }
        gridDataDetailList.sortBy { it.pm25 }
        gridDataDetailList.forEachIndexed { index, d ->
            d.rank = index + 1
        }
        gridDataDetailList.sortBy { it.cellId }
        return gridDataDetailList
    }
    /**
     * 计算热力图网格,即网格周边扩散影响权重计算
     * @param gridDataDetail 网格监测数据
     * @param gridCellList 区域网格数组
     * @param option 区域网格参数信息
     * @param searchLength 计算周边八方向(上下左右及四个对角)网格的长度
     * @return 周边网格及对应的监测数据结果
     */
    fun heatMap(
        gridDataDetail: GridDataDetail, gridCellList: List<GridCell?>,
        option: GridGroupOption, searchLength: Int,
    ): List<GridDataDetail> {
        // 找到网格数据对应的网格信息
        val gridCell = gridCellList.find { it?.cellIndex == gridDataDetail.cellId }
            ?: throw IllegalArgumentException("网格数据和给定的区域网格不匹配")
        // 获取周边网格
        val surroundGridCellList =
            SatelliteGridUtil.searchDiffuseGrid(gridDataDetail.cellId, gridCellList, option, searchLength)
        // 使用走航网格权重模型,计算周边网格的监测数据值
        val underwayGridModel = UnderwayGridModel()
        val dataList = listOf(GridCellAndData(gridCell, gridDataDetail))
        val gridCellSopList = surroundGridCellList.map {
            GridCellSop(
                it,
                it.id.toString(),
                it.cellIndex.toString(),
                it.cellIndex.toString()
            ) }
        underwayGridModel.execute(dataList, gridCellSopList)
        val resMap = underwayGridModel.outputResult()
        // 格式化结果并返回
        val result = mutableListOf<GridDataDetail>()
        gridCellSopList.forEach {
            val resGridDataDetail = GridDataDetail().apply {
                dataId = gridDataDetail.dataId
                groupId = gridDataDetail.groupId
                cellId = it.gridCell.cellIndex
            }
            val key = "${it.sourceName};${it.index}"
            val d = resMap[key]
            d?.forEach { (t, u) ->
                val avg = u["综合(${t})"]?.average ?: .0
                resGridDataDetail.setFactorValue(FactorType.getByName(t), avg.toFloat())
            }
            result.add(resGridDataDetail)
        }
        return result
    }
}