From dac47617b37ccfb834cd73ce0ee725e1101de214 Mon Sep 17 00:00:00 2001 From: feiyu02 <risaku@163.com> Date: 星期四, 14 八月 2025 17:25:51 +0800 Subject: [PATCH] 2025.8.14 1. 动态溯源模块添加滑动平均异常计算(调试中) --- src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedSummary.kt | 200 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 197 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedSummary.kt b/src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedSummary.kt index 91983a8..0ea4343 100644 --- a/src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedSummary.kt +++ b/src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedSummary.kt @@ -1,12 +1,27 @@ package com.flightfeather.uav.biz.sourcetrace.model +import com.flightfeather.uav.biz.sourcetrace.config.RTExcWindLevelConfig +import com.flightfeather.uav.common.net.AMapService +import com.flightfeather.uav.common.utils.DateUtil +import com.flightfeather.uav.common.utils.MapUtil +import com.flightfeather.uav.domain.entity.BaseRealTimeData +import com.flightfeather.uav.domain.entity.SceneInfo +import java.math.BigDecimal +import java.time.LocalDateTime +import java.util.Date +import java.util.Timer +import java.util.TimerTask + +// 寮傚父鏁版嵁鐢熸垚鍥炶皟绫� +typealias NewPolluteSummaryCallback = (ex: AnalysisResult) -> Unit + /** * 姹℃煋鎯呭喌姹囨�� * 閽堝鍗曟璧拌埅锛屽畾鏃剁粺璁″凡鏈夋薄鏌撶嚎绱PollutedClue]锛屾寜鐓х瓥鐣ョ粰鍑鸿蛋鑸缓璁� * @date 2025/5/27 * @author feiyu02 */ -class PollutedSummary { +class PollutedSummary(private val config: RTExcWindLevelConfig, private val callback: NewPolluteSummaryCallback) { /** @@ -14,6 +29,185 @@ * 姣忎竴鍒婚挓瀵瑰巻鍙茬嚎绱㈣繘琛岀粺璁★紝鎻愬嚭浼氬晢寤鸿锛堢姹℃煋婧愯緝杩溿�佹薄鏌撴簮鏁伴噺銆佸嚭鐜版鏁帮級銆佽蛋鑸矾绾胯皟鏁村缓璁紙绂绘薄鏌撴簮杈冭繎銆佽蛋鑸建杩规湭鎺ヨ繎婧簮鍦烘櫙锛� */ - // 姹℃煋绾跨储 - var clueList = mutableListOf<PollutedClue>() + /** + * 瀹炴椂缁熻 + */ + inner class AnalysisStatistic { + // 鎸夌収琚壂鎻忔鏁伴檷搴忔帓鍒楃殑姹℃煋婧愬垪琛� + var sortedSceneList: List<Pair<SceneInfo?, Int>>? = null + } + + // 鏈�鏂板疄鏃惰蛋鑸洃娴嬫暟鎹� + val realTimeDataList = mutableListOf<BaseRealTimeData>() + + // 鏈垎鏋愮殑姹℃煋绾跨储 + val clueList = mutableListOf<PollutedClue>() + + // 宸插垎鏋愮殑姹℃煋绾跨储 + private val historyClueList = mutableListOf<PollutedClue>() + + // 瀹氭椂姹℃煋鍒嗘瀽浠诲姟鎺у埗 + private var analysisTimer: Timer? = null + + // 瀹氭椂姹℃煋鍒嗘瀽浠诲姟 + private var lastAnalysisOnTimeTask: TimerTask? = null + + // 瀹氭椂姹℃煋鍒嗘瀽浠诲姟杩愯鐘舵�� + private var analysisTaskIsRunning = false + + // 涓婁竴娆″畾鏃舵薄鏌撳垎鏋愪换鍔$粨鏉熸椂闂� + private lateinit var lastAnalysisTime: LocalDateTime + + init { + clear() + } + + // 鏂板涓�鏉℃薄鏌撶嚎绱� + fun addClue(pollutedClue: PollutedClue) { + // 褰撴函婧愭湭鎵惧埌椋庨櫓婧愭椂锛屾娆℃函婧愪俊鎭笉浣滀负绾跨储缁熻椤� + if (pollutedClue.pollutedSource?.sceneList?.isNotEmpty() == true) + clueList.add(pollutedClue) +// realTimeSummary() + analysisOnClueCount() + } + + // 鏂板涓�鏉℃薄鏌撶嚎绱� + fun addClueList(pollutedClues: List<PollutedClue>) { + pollutedClues.forEach { addClue(it) } + } + + // 鍒锋柊褰撳墠鏈�鏂扮殑璧拌埅鐩戞祴鏁版嵁 + fun refreshLatestMonitorData(data: BaseRealTimeData) { +// realTimeDataList.clear() + realTimeDataList.add(data) + } + + fun clear() { + realTimeDataList.clear() + clueList.clear() + historyClueList.clear() + analysisTimer?.cancel() + analysisTimer = null + analysisTaskIsRunning = false + lastAnalysisTime = LocalDateTime.now() + resetAnalysisOnTime() + } + + /** + * 閲嶇疆瀹氭椂鍒嗘瀽绾跨储浠诲姟 + */ + private fun resetAnalysisOnTime() { + // 鍙栨秷鍘熸湁鐨勫垎鏋愪换鍔¤鏃� + analysisTimer?.cancel() + lastAnalysisOnTimeTask?.cancel() + // 浠ュ綋鍓嶆椂闂翠负璧风偣锛岄噸鏂板紑濮嬫柊鐨勪竴杞瓑寰呰鏃� + analysisTimer = Timer() + val period = config.analysisPeriod * 60 * 1000L + lastAnalysisOnTimeTask = newAnalysisTask() + analysisTimer?.schedule(lastAnalysisOnTimeTask, period, period) + } + + /** + * 鍦ㄥ畾鏃舵薄鏌撶嚎绱㈠垎鏋愪换鍔$瓑寰呭懆鏈熸椂闂村唴锛岃嫢姹℃煋绾跨储閲忚秴杩囪瀹氬�硷紝鐩存帴瑙﹀彂鍒嗘瀽绾跨储浠诲姟 + * 骞堕噸缃畾鏃跺垎鏋愪换鍔� + */ + private fun analysisOnClueCount() { + if (clueList.size >= config.analysisCount && !analysisTaskIsRunning) { + newAnalysisTask().run() + resetAnalysisOnTime() + } + } + + /** + * 瀹炴椂绾跨储缁熻 + */ + private fun realTimeSummary() { + val statistic = AnalysisStatistic() + // 鍏辨湁澶氬皯鐩稿叧姹℃煋婧愶紝鍝簺姹℃煋婧愯鎵弿娆℃暟杈冨 + val sceneMap = mutableMapOf<String?, Pair<SceneInfo?, Int>>() + clueList.forEach { c -> + c.pollutedSource?.sceneList?.forEach { s -> + if (!sceneMap.containsKey(s?.guid)) { + sceneMap[s?.guid] = s to 1 + } else { + sceneMap[s?.guid] = s to (sceneMap[s?.guid]?.second!! + 1) + } + } + } + val res = sceneMap.entries.sortedBy { it.value.second } + statistic.sortedSceneList = res.map { it.value } + } + + /** + * 绾跨储鍒嗘瀽 + */ + private fun analysis() { + if (clueList.isEmpty()) return + val result = AnalysisResult().apply { deviceCode = clueList.first().deviceCode } + // 鍏辨湁澶氬皯鐩稿叧姹℃煋婧愶紝鍝簺姹℃煋婧愯鎵弿娆℃暟杈冨 + val sceneMap = mutableMapOf<String?, Pair<SceneInfo?, Int>>() + clueList.forEach { c -> + c.pollutedSource?.sceneList?.forEach { s -> + if (!sceneMap.containsKey(s?.guid)) { + sceneMap[s?.guid] = s to 1 + } else { + sceneMap[s?.guid] = s to (sceneMap[s?.guid]?.second!! + 1) + } + } + } + val res = sceneMap.entries.sortedByDescending { it.value.second } + result.sortedSceneList = res.map { it.value } + + // 褰撳墠鐨勮蛋鑸暟鎹殑瀹氫綅鍜屾薄鏌撴簮璺濈鏄惁鏄�愭笎鎺ヨ繎锛岃嫢璧拌埅杩滅浜嗕富瑕佹薄鏌撴簮锛屾彁绀虹敤鎴疯皟鏁磋蛋鑸矾绾� + if (!result.sortedSceneList.isNullOrEmpty()) { + val sT = + DateUtil.instance.dateToString(clueList.first().pollutedData?.startTime, DateUtil.DateStyle.HH_MM_SS) + val eT = DateUtil.instance.dateToString(clueList.last().pollutedData?.endTime, DateUtil.DateStyle.HH_MM_SS) + val closetScene = result.sortedSceneList?.first() + // 璧拌埅璺嚎璋冩暣寤鸿 + result.advice = + "鏍规嵁${sT}鑷�${eT}鐨�${clueList.size}涓函婧愬垏鐗囷紝椋庨櫓婧愩��" + + "${closetScene?.first?.name}銆戣澶氭婧簮锛屽叿鏈夎緝楂樻薄鏌撻闄╋紝鐜版彁渚涙渶鏂扮洿杈捐蛋鑸矾绾裤��" + + val lastP = realTimeDataList.last() + // 寤鸿瀵瑰簲鐨勬暟鎹噰鏍锋椂闂� + result.time = lastP.dataTime + if (lastP.longitude != null && lastP.latitude != null && + lastP.longitude!! > BigDecimal.ZERO && lastP.latitude!! > BigDecimal.ZERO + && closetScene?.first?.longitude != null && closetScene.first?.latitude != null && + closetScene.first?.longitude!! > BigDecimal.ZERO && closetScene.first?.latitude!! > BigDecimal.ZERO + ) { + + val origin = MapUtil.wgs84ToGcj02(lastP.longitude!!.toDouble() to lastP.latitude!!.toDouble()) + val destination = closetScene.first!!.longitude.toDouble() to closetScene.first!!.latitude.toDouble() + + if (config.isSearchAddress) { + // 寤鸿鐨勮蛋鑸矾绾� + result.direction = AMapService.directionDriving(origin, destination) + } + } + // 绾跨储鍒嗘瀽瀹屾垚鍚庯紝绉诲姩鑷冲巻鍙茬嚎绱㈠垪琛� + historyClueList.addAll(clueList) + clueList.clear() + realTimeDataList.clear() + + callback(result) + } +// TODO() + } + + // 瀹氭椂姹℃煋鍒嗘瀽浠诲姟 + private fun newAnalysisTask(): TimerTask { + return object : TimerTask() { + override fun run() { + // 璁板綍浠诲姟杩愯鐘舵�� + analysisTaskIsRunning = true + analysis() + // 璁板綍涓婁竴娆$殑浠诲姟缁撴潫鏃堕棿 + lastAnalysisTime = LocalDateTime.now() + analysisTaskIsRunning = false + } + } + } + } \ No newline at end of file -- Gitblit v1.9.3