From 61871594dfa0a5ac2c4d895d9ec4034feba57094 Mon Sep 17 00:00:00 2001 From: feiyu02 <risaku@163.com> Date: 星期五, 12 九月 2025 17:20:53 +0800 Subject: [PATCH] 2025.9.5 1. 新增走航任务统计功能 --- src/main/kotlin/com/flightfeather/uav/lightshare/service/DataAnalysisService.kt | 7 + src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/DataAnalysisServiceImpl.kt | 36 ++++++- src/main/kotlin/com/flightfeather/uav/biz/report/MissionGridFusion.kt | 6 src/main/kotlin/com/flightfeather/uav/biz/report/MissionInventory.kt | 161 +++++++++++++++++++++++++------ src/main/kotlin/com/flightfeather/uav/biz/report/MissionSummary.kt | 53 +++++++++- 5 files changed, 213 insertions(+), 50 deletions(-) diff --git a/src/main/kotlin/com/flightfeather/uav/biz/report/MissionGridFusion.kt b/src/main/kotlin/com/flightfeather/uav/biz/report/MissionGridFusion.kt index 4bebc3f..a274fae 100644 --- a/src/main/kotlin/com/flightfeather/uav/biz/report/MissionGridFusion.kt +++ b/src/main/kotlin/com/flightfeather/uav/biz/report/MissionGridFusion.kt @@ -23,7 +23,7 @@ class GridFusionByAQI { var pollutionDegree: String? = null var gridLen:Int? = null - var missionList: MutableList<MissionInventory.MissionDetail> = mutableListOf() + var missionList: MutableList<MissionInventory.MissionInfo> = mutableListOf() var gridFusionList: MutableList<FusionGrid> = mutableListOf() var highRiskGridList: MutableList<HighRiskGridByFactor> = mutableListOf() } @@ -70,7 +70,7 @@ factorTypes: List<FactorType>, gridLen: Int, gridCells: List<GridCell>, - dataList: List<Triple<PollutionDegree, List<MissionInventory.MissionDetail>, List<GridDataDetailMixVo>>>, + dataList: List<Triple<PollutionDegree, List<MissionInventory.MissionInfo>, List<GridDataDetailMixVo>>>, ): List<GridFusionByAQI> { return dataList.map { GridFusionByAQI().apply { @@ -85,7 +85,7 @@ highRiskGridList.addAll(factorTypes.map { f-> HighRiskGridByFactor().apply { factorType = f - highRiskGrid = gridFusionList.sortedBy { gf->gf.data.rank }.firstOrNull() + highRiskGrid = gridFusionList.maxByOrNull { gf->gf.data.getByFactorType(f) ?: 0f } if (highRiskGrid != null) { factorValue = highRiskGrid!!.data.getByFactorType(f) if (highRiskGrid!!.cell.longitude != null && highRiskGrid!!.cell.latitude != null) { diff --git a/src/main/kotlin/com/flightfeather/uav/biz/report/MissionInventory.kt b/src/main/kotlin/com/flightfeather/uav/biz/report/MissionInventory.kt index cd8f696..f6700d7 100644 --- a/src/main/kotlin/com/flightfeather/uav/biz/report/MissionInventory.kt +++ b/src/main/kotlin/com/flightfeather/uav/biz/report/MissionInventory.kt @@ -26,13 +26,21 @@ // 婧簮闂鍦烘櫙鏁� var sceneCount: Int = 0 + + // 婧簮闂鍦烘櫙 + var scenes: List<SceneInfo>? = null + + // 璧拌埅娑夊強鍖哄煙 + var keyScene: List<SceneInfo>? = null + + var exceptionCount: Int = 0 } // 璧拌埅璇︽儏淇℃伅 class MissionDetail : Mission() { - var keyScene: List<SceneInfo>? = null +// var keyScene: List<SceneInfo>? = null var dataStatistics: List<FactorStatistics>? = null - var exceptionCount: Int = 0 +// var exceptionCount: Int = 0 } /** @@ -48,7 +56,7 @@ var sceneCount = 0 clue.forEach { if (it?.msgType == MsgType.PolClue.value) { - it.pollutedData?.statisticMap?.keys?.forEach { k-> + it.pollutedData?.statisticMap?.keys?.forEach { k -> // 璁$畻姣忎釜璧拌埅浠诲姟鐨勬墍鏈夊紓甯稿洜瀛� if (!abnormalFactors.contains(k)) { abnormalFactors.add(k) @@ -74,6 +82,87 @@ return result } + fun generateMissionInfo( + keyScenes: List<SceneInfo?>, + mission: Mission, + pollutedClues: List<PollutedClue?>, + data: List<BaseRealTimeData>, + minDis: Double = 100.0, + ): MissionInfo { + val factorMap = mutableMapOf<FactorType, Int>() + val abnormalFactors = mutableListOf<FactorType>() + var sceneCount = 0 + val scenes = mutableListOf<SceneInfo>() + // 鎻愬彇閫斿緞鍏抽敭鍦烘櫙淇℃伅锛堣绠楄蛋鑸矾绾挎槸鍚︿笌鍏抽敭鍦烘櫙璺濈杈冭繎锛� + val relatedScenes = mutableListOf<SceneInfo>() + data.forEach { d -> + // 璺宠繃缂哄皯缁忕含搴︾殑鏁版嵁鐐� + if (d.longitude == null || d.latitude == null) { + return@forEach + } + // 杞崲涓篏CJ02鍧愭爣绯� + val point = MapUtil.wgs84ToGcj02(d.longitude!!.toDouble() to d.latitude!!.toDouble()) + keyScenes.forEach ks@{ k -> + // 璺宠繃缂哄皯缁忕含搴︾殑鍦烘櫙 + if (k?.longitude == null || k.latitude == null) { + return@ks + } + // 妫�鏌ユ槸鍚︽湭娣诲姞杩� + if (!relatedScenes.contains(k)) { + // 璁$畻璺濈 + val distance = MapUtil.getDistance( + k.longitude!!.toDouble(), + k.latitude!!.toDouble(), + point.first, + point.second + ) + // 妫�鏌ユ槸鍚﹁窛绂诲皬浜庨槇鍊� + if (distance < minDis) { + relatedScenes.add(k) + } + } + } + } + pollutedClues.forEach { + if (it?.msgType == MsgType.PolClue.value) { + it.pollutedData?.statisticMap?.keys?.forEach { k -> + // 璁$畻姣忎釜璧拌埅浠诲姟鐨勬墍鏈夊紓甯稿洜瀛� + if (!abnormalFactors.contains(k)) { + abnormalFactors.add(k) + } + // 璁$畻姣忎釜璧拌埅浠诲姟鐨勯瑕佹薄鏌撶墿 + if (!factorMap.containsKey(k)) { + factorMap[k] = 0 + } + factorMap[k] = factorMap[k]!! + 1 + } + // 璁$畻姣忎釜璧拌埅浠诲姟鐨勬函婧愬満鏅暟閲� + sceneCount += it.pollutedSource?.sceneList?.size ?: 0 + it.pollutedSource?.sceneList?.forEach { s-> + if (scenes.find { s1 -> s1.guid == s.guid } == null) { + scenes.add(s) + } + } + } + } + + // 寮傚父鏁版嵁鐐规暟閲忕粺璁� + val clues = pollutedClues.filter { it?.msgType == MsgType.PolClue.value } + + val missionInfo = MissionInfo() + BeanUtils.copyProperties(mission, missionInfo) + missionInfo.apply { + mainFactor = factorMap.maxByOrNull { it.value }?.key?.name + this.abnormalFactors = abnormalFactors + this.sceneCount = sceneCount + this.scenes = scenes + keyScene = relatedScenes + exceptionCount = clues.size + } + + return missionInfo + } + /** * 鐢熸垚璧拌埅浠诲姟璇︾粏淇℃伅 * 鏁村悎璧拌埅浠诲姟鍩烘湰淇℃伅銆佸叧閿満鏅�佹暟鎹粺璁″拰寮傚父鏁伴噺锛岀敓鎴愬畬鏁寸殑浠诲姟璇︽儏鎶ュ憡 @@ -93,44 +182,52 @@ mission: Mission, pollutedClues: List<PollutedClue?>, data: List<BaseRealTimeData>, - minDis:Double = 100.0 + minDis: Double = 100.0, ): MissionDetail { // 鍒涘缓浠诲姟璇︽儏瀵硅薄骞跺鍒跺熀鏈俊鎭� val missionDetail = MissionDetail() BeanUtils.copyProperties(mission, missionDetail) - + // 鎻愬彇閫斿緞鍏抽敭鍦烘櫙淇℃伅锛堣绠楄蛋鑸矾绾挎槸鍚︿笌鍏抽敭鍦烘櫙璺濈杈冭繎锛� - val relatedScenes = mutableListOf<SceneInfo>() - data.forEach { d-> - // 璺宠繃缂哄皯缁忕含搴︾殑鏁版嵁鐐� - if (d.longitude == null || d.latitude == null) { - return@forEach - } - // 杞崲涓篏CJ02鍧愭爣绯� - val point = MapUtil.wgs84ToGcj02(d.longitude!!.toDouble() to d.latitude!!.toDouble()) - keyScenes.forEach ks@ { k-> - // 璺宠繃缂哄皯缁忕含搴︾殑鍦烘櫙 - if (k?.longitude == null || k.latitude == null) { - return@ks - } - // 璁$畻璺濈 - val distance = MapUtil.getDistance(k.longitude!!.toDouble(), k.latitude!!.toDouble(), point.first, point.second) - // 妫�鏌ユ槸鍚﹁窛绂诲皬浜庨槇鍊间笖鏈坊鍔犺繃 - if (distance < minDis && !relatedScenes.contains(k)) { - relatedScenes.add(k) - } - } - } +// val relatedScenes = mutableListOf<SceneInfo>() +// data.forEach { d -> +// // 璺宠繃缂哄皯缁忕含搴︾殑鏁版嵁鐐� +// if (d.longitude == null || d.latitude == null) { +// return@forEach +// } +// // 杞崲涓篏CJ02鍧愭爣绯� +// val point = MapUtil.wgs84ToGcj02(d.longitude!!.toDouble() to d.latitude!!.toDouble()) +// keyScenes.forEach ks@{ k -> +// // 璺宠繃缂哄皯缁忕含搴︾殑鍦烘櫙 +// if (k?.longitude == null || k.latitude == null) { +// return@ks +// } +// // 妫�鏌ユ槸鍚︽湭娣诲姞杩� +// if (!relatedScenes.contains(k)) { +// // 璁$畻璺濈 +// val distance = MapUtil.getDistance( +// k.longitude!!.toDouble(), +// k.latitude!!.toDouble(), +// point.first, +// point.second +// ) +// // 妫�鏌ユ槸鍚﹁窛绂诲皬浜庨槇鍊� +// if (distance < minDis) { +// relatedScenes.add(k) +// } +// } +// } +// } // 瀛樺偍涓庝换鍔$浉鍏宠仈鐨勫叧閿満鏅俊鎭� - missionDetail.keyScene = relatedScenes - +// missionDetail.keyScene = relatedScenes + // 璁$畻鐜鍥犲瓙缁熻鏁版嵁锛堝钩鍧囧�笺�佹渶灏忓�笺�佹渶澶у�硷級 missionDetail.dataStatistics = data.calDataStatistics() - + // 寮傚父鏁版嵁鐐规暟閲忕粺璁� - val clues = pollutedClues.filter { it?.msgType == MsgType.PolClue.value } - missionDetail.exceptionCount = clues.size - +// val clues = pollutedClues.filter { it?.msgType == MsgType.PolClue.value } +// missionDetail.exceptionCount = clues.size + return missionDetail } } \ No newline at end of file diff --git a/src/main/kotlin/com/flightfeather/uav/biz/report/MissionSummary.kt b/src/main/kotlin/com/flightfeather/uav/biz/report/MissionSummary.kt index f82bf96..ff1ab18 100644 --- a/src/main/kotlin/com/flightfeather/uav/biz/report/MissionSummary.kt +++ b/src/main/kotlin/com/flightfeather/uav/biz/report/MissionSummary.kt @@ -2,11 +2,9 @@ import com.flightfeather.uav.biz.sourcetrace.model.PollutedClue import com.flightfeather.uav.domain.entity.Mission -import com.flightfeather.uav.domain.repository.MissionRep import com.flightfeather.uav.lightshare.bean.AreaVo import com.flightfeather.uav.socket.eunm.FactorType import com.flightfeather.uav.socket.sender.MsgType -import org.springframework.stereotype.Component import java.util.* import kotlin.math.round @@ -16,6 +14,10 @@ * @author feiyu02 */ class MissionSummary() { + + companion object { + private const val FOCUS_AREA_COUNT = 2 + } data class Summary( // 姹囨�诲懆鏈熷紑濮嬫椂闂� @@ -33,11 +35,13 @@ // 鍚勭瓑绾х┖姘旇川閲忚儗鏅蛋鑸鏁�,<绌烘皵璐ㄩ噺绛夌骇锛屾鏁帮紝鍗犳瘮> val countByDegree: List<Triple<String, Int, Double>>, // 闂鎬绘暟 - val probCount:Int, + val probCount: Int, // 楂橀闄╁満鏅�绘暟 - val highRiskSceneCount:Int, + val highRiskSceneCount: Int, // 闂鎸夌洃娴嬪洜瀛愮被鍨嬪垎甯冩儏鍐�, <鍥犲瓙绫诲瀷锛屾鏁帮紝鍗犳瘮> - val probByFactor:List<Triple<String, Int, Double>> + val probByFactor: List<Triple<String, Int, Double>>, + // 鑱氱劍鍖哄煙鎴栧満鏅� + val focusRegion: List<String>, ) /** @@ -61,7 +65,8 @@ countByDegree = emptyList(), probCount = 0, highRiskSceneCount = 0, - probByFactor = emptyList() + probByFactor = emptyList(), + focusRegion = emptyList() ) } @@ -100,7 +105,10 @@ val highRiskSceneCount = clueRes.second // 闇�鍏宠仈鍦烘櫙琛ㄧ粺璁� val probByFactor = clueRes.third - // 7. 鏋勫缓骞惰繑鍥炵粺璁$粨鏋� + // 7. 浠庡紓甯告墍鍦ㄥ湴鍖哄拰婧簮鐨勫満鏅腑缁熻鑱氱劍鍖哄煙 + val focusRegion = calFocusRegion(clues) + + // 8. 鏋勫缓骞惰繑鍥炵粺璁$粨鏋� return Summary( startTime = startTime, endTime = endTime, @@ -111,7 +119,8 @@ countByDegree = countByDegree, probCount = probCount, highRiskSceneCount = highRiskSceneCount, - probByFactor = probByFactor + probByFactor = probByFactor, + focusRegion = focusRegion ) } @@ -137,4 +146,32 @@ } return Triple(probCount, highRiskSceneCount, probByFactor) } + + private fun calFocusRegion(clues: List<PollutedClue?>): List<String> { + // 缁熻姣忎釜鍖哄煙鎴栧満鏅嚭鐜扮殑娆℃暟 + val focusArea = mutableMapOf<String, Int>() + val focusScene = mutableMapOf<String, Int>() + clues.forEach { c-> + if (c?.msgType == MsgType.PolClue.value) { + if (!c.pollutedArea?.address.isNullOrBlank()) { + if (focusArea.containsKey(c.pollutedArea?.address)) { + focusArea[c.pollutedArea?.address!!] = focusArea[c.pollutedArea?.address]!! + 1 + } else { + focusArea[c.pollutedArea?.address!!] = 1 + } + } + c.pollutedSource?.sceneList?.forEach { s-> + if (s.name != null) { + if (focusScene.containsKey(s.name!!)) { + focusScene[s.name!!] = focusScene[s.name!!]!! + 1 + } else { + focusScene[s.name!!] = 1 + } + } + } + } + } + return focusArea.entries.sortedByDescending { it.value }.map { it.key }.take(FOCUS_AREA_COUNT) + + focusScene.entries.sortedByDescending { it.value }.map { it.key }.take(FOCUS_AREA_COUNT) + } } \ No newline at end of file diff --git a/src/main/kotlin/com/flightfeather/uav/lightshare/service/DataAnalysisService.kt b/src/main/kotlin/com/flightfeather/uav/lightshare/service/DataAnalysisService.kt index 5bd59a6..2fa37ca 100644 --- a/src/main/kotlin/com/flightfeather/uav/lightshare/service/DataAnalysisService.kt +++ b/src/main/kotlin/com/flightfeather/uav/lightshare/service/DataAnalysisService.kt @@ -70,6 +70,11 @@ */ fun generateMissionList(missionClues: List<Pair<Mission, List<PollutedClue?>>>): List<MissionInventory.MissionInfo> + fun generateMissionInfo( + keyScenes: List<SceneInfo?>, + missionCluesData: List<Triple<Mission, List<PollutedClue?>, List<BaseRealTimeData>>>, + ): List<MissionInventory.MissionInfo> + /** * 鑾峰彇璧拌埅浠诲姟璇︽儏锛堟寜鏃堕棿鍜屽尯鍩熺瓫閫夛級 * 鏍规嵁鏃堕棿鑼冨洿鍜屽尯鍩熸煡璇㈠苟鐢熸垚璇︾粏鐨勪换鍔℃姤鍛婏紝鍖呭惈鍏抽敭鍦烘櫙鍜屾暟鎹粺璁� @@ -100,6 +105,6 @@ factorTypes: List<FactorType>, gridLen: Int, gridCells: List<GridCell>, - dataList: List<Triple<PollutionDegree, List<MissionInventory.MissionDetail>, List<GridDataDetailMixVo>>>, + dataList: List<Triple<PollutionDegree, List<MissionInventory.MissionInfo>, List<GridDataDetailMixVo>>>, ): List<MissionGridFusion.GridFusionByAQI> } \ No newline at end of file diff --git a/src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/DataAnalysisServiceImpl.kt b/src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/DataAnalysisServiceImpl.kt index 0dcbb4a..3e20de7 100644 --- a/src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/DataAnalysisServiceImpl.kt +++ b/src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/DataAnalysisServiceImpl.kt @@ -119,10 +119,25 @@ * @see generateMissionList 閲嶈浇鏂规硶锛屽鐞嗗凡鍏宠仈鐨勬暟鎹 */ override fun generateMissionList(startTime: Date, endTime: Date, areaVo: AreaVo): List<MissionInventory.MissionInfo> { - val missionClues = missionRep.findByAreaAndTime(areaVo, startTime, endTime).filterNotNull().map { - it to sourceTraceRep.fetchList(it.deviceCode, it.startTime, it.endTime, MsgType.PolClue) as List<PollutedClue?> +// val missionClues = missionRep.findByAreaAndTime(areaVo, startTime, endTime).filterNotNull().map { +// it to sourceTraceRep.fetchList(it.deviceCode, it.startTime, it.endTime, MsgType.PolClue) as List<PollutedClue?> +// } +// return generateMissionList(missionClues) + val missionCluesData = missionRep.findByAreaAndTime(areaVo, startTime, endTime).filterNotNull().map { + Triple( + it, + sourceTraceRep.fetchList(it.deviceCode, it.startTime, it.endTime, MsgType.PolClue) as List<PollutedClue?>, + realTimeDataRep.fetchData(it) + ) } - return generateMissionList(missionClues) + val keyScenes = sceneInfoRep.findBySceneTypes( + listOf( + SceneType.TYPE19.value, + SceneType.TYPE20.value, + SceneType.TYPE21.value + ) + ) + return generateMissionInfo(keyScenes, missionCluesData) } /** @@ -134,6 +149,15 @@ */ override fun generateMissionList(missionClues: List<Pair<Mission, List<PollutedClue?>>>): List<MissionInventory.MissionInfo> { return MissionInventory().generateMissionList(missionClues) + } + + override fun generateMissionInfo( + keyScenes: List<SceneInfo?>, + missionCluesData: List<Triple<Mission, List<PollutedClue?>, List<BaseRealTimeData>>>, + ): List<MissionInventory.MissionInfo> { + return missionCluesData.map { + MissionInventory().generateMissionInfo(keyScenes, it.first, it.second, it.third) + } } /** @@ -256,9 +280,9 @@ SceneType.TYPE21.value ) ) - val missionDetails = generateMissionDetail(keyScenes, missionCluesData) + val missionInfos = generateMissionInfo(keyScenes, missionCluesData) - return@mapNotNull Triple(degree, missionDetails, gridDataDetailMixVos) + return@mapNotNull Triple(degree, missionInfos, gridDataDetailMixVos) }.filter { it.second.isNotEmpty() } return generateGridFusion(factorTypes, gridLen, gridCells, gridDataDetailList) @@ -268,7 +292,7 @@ factorTypes: List<FactorType>, gridLen: Int, gridCells: List<GridCell>, - dataList: List<Triple<PollutionDegree, List<MissionInventory.MissionDetail>, List<GridDataDetailMixVo>>>, + dataList: List<Triple<PollutionDegree, List<MissionInventory.MissionInfo>, List<GridDataDetailMixVo>>>, ): List<MissionGridFusion.GridFusionByAQI> { return MissionGridFusion(sceneInfoRep).generateGridFusion(factorTypes, gridLen, gridCells, dataList) } -- Gitblit v1.9.3