feiyu02
2025-05-09 36680087df02080833c319a7a70f083585fad295
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package com.flightfeather.uav.biz.satellite
 
import com.flightfeather.uav.domain.entity.GridData
import com.flightfeather.uav.domain.entity.GridDataDetail
import com.flightfeather.uav.domain.mapper.GridDataDetailMapper
import com.flightfeather.uav.domain.mapper.GridDataMapper
import com.flightfeather.uav.lightshare.eunm.SatelliteDataType
import org.springframework.beans.BeanUtils
import org.springframework.stereotype.Component
import tk.mybatis.mapper.entity.Example
import java.util.Date
 
/**
 * 卫星遥测数据融合
 * @date 2024/12/31
 * @author feiyu02
 */
@Component
class SatelliteDataMix(
    private val gridDataMapper: GridDataMapper,
    private val gridDataDetailMapper: GridDataDetailMapper,
) {
 
    /**
     * 融合卫星遥测数据
     * @param dataIdList 每期卫星遥测数据的主键id数组,表示需要将这几组数据进行数据融合
     */
    fun mixData(dataIdList: List<Int>): Pair<GridData?, List<GridDataDetail>> {
        if (dataIdList.isEmpty()) return null to emptyList()
 
        // 获取原始数据
        val originalDataList = gridDataMapper.selectByExample(Example(GridData::class.java).apply {
            createCriteria().andIn("id", dataIdList).andEqualTo("type", SatelliteDataType.Original.value)
        })
        if (originalDataList.isEmpty()) return null to emptyList()
 
        // 获取具体原始网格数据
        val dataDetailList = mutableListOf<List<GridDataDetail?>>()
        originalDataList.forEach {
            val res = gridDataDetailMapper.selectByExample(Example(GridDataDetail::class.java).apply {
                createCriteria().andEqualTo("dataId", it?.id)
                orderBy("cellId")
            })
            dataDetailList.add(res)
        }
 
        // 创建融合数据索引信息
        val firstGridData = originalDataList.first()
        val avgGridData = GridData().apply {
            groupId = firstGridData?.groupId
            dataTime = Date()
            type = SatelliteDataType.Mix.value.toByte()
            mixDataId = dataIdList.sorted().joinToString(",")
        }
        gridDataMapper.insert(avgGridData)
 
        // 计算均值
        val avgResult = calculateAvg(avgGridData.id, dataDetailList)
        gridDataDetailMapper.insertList(avgResult)
 
        return avgGridData to avgResult
    }
 
    /**
     * 将多组原始卫星遥测网格PM2.5数据进行融合,计算每个网格的均值
     * @param dataId 融合数据主键id
     * @param dataDetailList 原始卫星遥测数据数组
     */
    fun calculateAvg(dataId: Int, dataDetailList: List<List<GridDataDetail?>>): List<GridDataDetail> {
        if (dataDetailList.isEmpty()) return emptyList()
 
        // 获取首组网格数据,作为后续生成融合数据的依据
        val first = dataDetailList.first()
 
        // 每个单元格数据监测值总量
        val totalList = mutableListOf<Float>()
        // 每个单元格数据总数
        val countList = mutableListOf<Int>()
 
        // 统计各网格的数据监测值总量和数据总数
        dataDetailList.forEach {
            it.forEachIndexed { i, d ->
                if (i < totalList.size) {
                    if (d?.pm25 != null) {
                        totalList[i] += d.pm25
                        countList[i]++
                    }
                } else {
                    if (d?.pm25 != null) {
                        totalList.add(d.pm25)
                        countList.add(1)
                    } else {
                        totalList.add(0f)
                        countList.add(0)
                    }
                }
            }
        }
 
        // 计算每个网格的均值
        val avgResult = mutableListOf<GridDataDetail>()
        first.forEachIndexed { i, d ->
            val total = totalList[i]
            val count = countList[i]
            val avg = if (count == 0) {
                null
            } else {
                total / count
            }
            val avgData = GridDataDetail().apply {
                this.dataId = dataId
                groupId = d?.groupId
                cellId = d?.cellId
                pm25 = avg
            }
            avgResult.add(avgData)
        }
 
        // 刷新排名属性
        avgResult.sortByDescending { it.pm25 }
        avgResult.forEachIndexed { i, d ->
            d.rank = i + 1
        }
 
        return avgResult
    }
}