feiyu02
2025-08-05 176d7d8283e66ccf63878c9ab823e900df94b748
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
package com.flightfeather.uav.model
 
import com.flightfeather.uav.common.utils.DateUtil
import com.flightfeather.uav.common.utils.ExcelUtil
import com.flightfeather.uav.socket.eunm.FactorType
import org.apache.poi.xssf.streaming.SXSSFWorkbook
import java.io.File
import java.io.FileOutputStream
import java.util.*
import kotlin.math.round
 
/**
 * 污染源影响程度权重分析模型
 * 基类
 */
abstract class BaseModel<M : BaseMData, S: BaseSOP> {
 
    data class ResultCell(
        var total: Double = 0.0,
        var count: Int = 0,
        var average: Double = 0.0
    ) {
        fun average(): Double {
            average = if (count == 0) .0 else round(total / count * 100) / 100
            return average
        }
    }
 
    abstract var dataPrep: BaseDataPrep<M, S>
 
    // 权重因子,在进行计算分析时使用的监测因子
    abstract var factorTypes: List<FactorType>
 
    // 权重值,多种权重进行乘积计算
    abstract var weights: List<BaseWeight<M, S>>
 
    // 计算结果
    private val rMap = mutableMapOf<String, MutableMap<String, MutableMap<String, ResultCell>>>()
 
    // 结果筛选方式
    abstract var sections: List<BaseSection<M, S>>
 
    /**
     * 污染源影响程度计算
     * @param mDataList 监测数据集合
     * @param sopList 污染源集合
     */
    open fun execute(mDataList: List<M>, sopList: List<S>, hasNext: Boolean = false) {
        if (!hasNext) rMap.clear()
 
        //1. 数据预处理
        val mList = dataPrep.mDataPrep(mDataList)
        val sList = dataPrep.sopPrep(sopList)
 
        mList.forEach m@{ m ->
            if (!mDataCheck(m)) return@m
            sList.forEach s@{ s ->
                if (!sopCheck(s)) return@s
                weightCompute(m, s)
            }
        }
    }
 
    /**
     * 单点权重计算
     * 计算污染源对单次监测数据产生的影响效果
     * @param mData 监测数据
     * @param sop 污染源
     */
    private fun weightCompute(mData: M, sop: S) {
        val effect = BaseEffect(sop.sourceId, sop.sourceName, sop.index)
 
        // 将原监测数据按照权重计算出结果值
        factorTypes.forEach { type ->
            var result = mData.getFactorData(type) ?: return@forEach
            weights.forEach {
                result *= it.getWeight(mData, sop)?: return
            }
            effect.value.add(Pair(type, result))
        }
 
        // 向结果值添加筛选标签
        sections.forEach { it.filter(mData, sop, effect) }
 
        // 保存结果
        formatConversion2(effect)
    }
 
    fun outputToExcel(
        fName: String? = null,
        _workbook: SXSSFWorkbook? = null,
        _out: FileOutputStream? = null,
        sheetName: String = "sheet1",
        done: Boolean = true
    ): Pair<SXSSFWorkbook, FileOutputStream>? {
//        val rMap = formatConversion()
 
        val workbook = _workbook ?: SXSSFWorkbook()
        val fileName = fName ?: "污染溯源权重模型${DateUtil.instance.dateToString(Date(), "yyyy-MM-ddHHmmss")}.xls"
//        val filePath = "E:\\work\\export\\$fileName"
//        val filePath = "E:\\工作\\开发\\走航监测\\算法相关\\自动输出\\$fileName"
        val filePath = "E:\\工作\\开发\\走航监测\\算法相关\\自动输出\\网格化\\$fileName"
        val out = _out ?: FileOutputStream(File(filePath))
 
        // 表头组(多行表头)
        val heads = mutableListOf<Array<String>>()
        // 表头行
        val h1 = mutableListOf<String>()
        h1.add("编号")
        h1.add("污染源")
//        arrayOf("早上", "上午", "中午", "下午", "傍晚", "夜间")
 
        val contents = mutableListOf<Array<Any>>()
        var isFirst = true
        rMap.forEach { (source, tMap) ->
            // 新建一行
            val contentList = mutableListOf<Any>()
            // 添加污染源名称
            val l = source.split(";")
            contentList.add(l[1].toIntOrNull() ?: 0)
            contentList.add(l[0])
            tMap.forEach { (factorType, lMap) ->
                sections.forEach {
                    val types = mutableListOf<String>().apply {
                        addAll(it.sectionType)
                        addAll(it.constType)
                    }
                    var max = 0.0
                    var maxP = types[0]
                    types.forEach type@{se ->
                        val lKey = "$se($factorType)"
                        if (lMap.containsKey(lKey)) {
                            val resultCell = lMap[lKey] ?: return@type
//                            val size = resultCell.count
                            // 添加该分类作为表头
                            val h = lKey
//                            val h = "$lKey($size)"
                            if (!h1.contains(h)) {
                                h1.add(h)
                            }
 
                            // 将原始的数据换算得出结果,可以是求出均值、总和等等
                            // FIXME: 2021/6/23 此处先默认为求均值
                            val average = resultCell.average()
 
                            if (average > max) {
                                max = average
                                maxP = se
                            }
 
                            // 当前行添加该分类下的结果值
                            contentList.add(average)
                        }
                    }
                    if (isFirst) {
                        h1.add("最高时段")
                        h1.add("最高时段值")
                    }
                    contentList.add(maxP)
                    contentList.add(max)
                }
            }
            isFirst = false
            contents.add(contentList.toTypedArray())
        }
 
        contents.sortByDescending {
            val i = it[0]
            if (i is Int) {
                i
            } else {
                0
            }
        }
 
        heads.add(h1.toTypedArray())
        ExcelUtil.write(heads, contents, workbook, sheetName)
        return if (!done) {
            Pair(workbook, out)
        } else {
            workbook.write(out)
            workbook.close()
            out.flush()
            out.close()
            null
        }
    }
 
    fun outputResult(): MutableMap<String, MutableMap<String, MutableMap<String, ResultCell>>> {
        rMap.forEach { (_, v) ->
            v.forEach { (_, v2) ->
                v2.forEach { (_, v3) ->
                    v3.average()
                }
            }
        }
 
        return rMap
    }
 
    /**
     * 将计算结果格式化为多层级的键对值结构
     * 第一层按照不同污染源的索引值进行分类
     * 第二层按照监测因子类型进行分类
     * 第三层按照自定义的标签进行分类
     */
    private fun formatConversion2(e: BaseEffect) {
        val rKey = "${e.sourceName};${e.index}"
        if (!rMap.containsKey(rKey)) {
            rMap[rKey] = mutableMapOf()
        }
        val lMap = rMap[rKey]!!
        e.value.forEach { v ->
            if (!lMap.containsKey(v.first.des)) {
                lMap[v.first.des] = mutableMapOf()
            }
            val tMap = lMap[v.first.des]!!
            e.tag.forEach { t ->
                val factorName = v.first.des
                val lKey = t.levelName + "($factorName)"
                if (!tMap.containsKey(lKey)) {
                    tMap[lKey] = ResultCell()
                }
                tMap[lKey]?.run {
                    total += v.second
                    if (factorName != FactorType.H2S.name || v.second > 0) {
                        count++
                    }
                }
            }
        }
    }
 
    /**
     * 监测数据合法性检查
     */
    abstract fun mDataCheck(m: M): Boolean
 
    /**
     * 污染源数据合法性检查
     */
    abstract fun sopCheck(s: S): Boolean
}