src/main/kotlin/com/flightfeather/uav/biz/dataanalysis/BaseExceptionContinuousSingle.kt
@@ -20,7 +20,7 @@ it.startData = data } // 夿ç¸é»æ°æ®æ¯å¦è¿ç»å¹¶ä¸æ¯å¦æ»¡è¶³å¼å¸¸å¤æ if (!isContinue || needCut(it)) { if (!isContinue || needCut(it, hasException[f])) { recordException(s, it, data) } else { if (hasException[f] == true) { src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/SourceTraceController.kt
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,116 @@ package com.flightfeather.uav.biz.sourcetrace import com.flightfeather.uav.biz.FactorFilter import com.flightfeather.uav.biz.dataanalysis.BaseExceptionAnalysis import com.flightfeather.uav.biz.sourcetrace.RealTimeAnalysisConfig import com.flightfeather.uav.biz.sourcetrace.config.RTExcWindLevelConfig import com.flightfeather.uav.biz.sourcetrace.exceptiontype.* import com.flightfeather.uav.biz.sourcetrace.model.PollutedClue import com.flightfeather.uav.biz.sourcetrace.model.PollutedSummary import com.flightfeather.uav.common.utils.GsonUtils import com.flightfeather.uav.domain.entity.BaseRealTimeData import com.flightfeather.uav.domain.repository.SceneInfoRep import com.flightfeather.uav.socket.eunm.FactorType import com.flightfeather.uav.socket.sender.MsgType import com.flightfeather.uav.socket.sender.UnderwayWebSocketSender import java.util.* /** * 污æçº¿ç´¢æ§å¶å¨ * @date 2025/5/27 * @author feiyu02 */ class SourceTraceController { /** * 5. æ±¡ææºçè¢«æ«ææ¬¡æ° * æ¯ä¸å»é对åå²çº¿ç´¢è¿è¡ç»è®¡ï¼æåºä¼å建议ï¼ç¦»æ±¡ææºè¾è¿ãæ±¡ææºæ°éãåºç°æ¬¡æ°ï¼ãèµ°èªè·¯çº¿è°æ´å»ºè®®ï¼ç¦»æ±¡ææºè¾è¿ãèµ°èªè½¨è¿¹æªæ¥è¿æº¯æºåºæ¯ï¼ */ constructor(sceneInfoRep: SceneInfoRep, factorFilter: FactorFilter?) { this.sceneInfoRep = sceneInfoRep this.config = if (factorFilter != null) RTExcWindLevelConfig(factorFilter) else RTExcWindLevelConfig( FactorFilter.builder() // .withMain(FactorType.NO2) .withMain(FactorType.CO) // .withMain(FactorType.H2S) // .withMain(FactorType.SO2) // .withMain(FactorType.O3) .withMain(FactorType.PM25) .withMain(FactorType.PM10) .withMain(FactorType.VOC) .create() ) pollutedSummary = PollutedSummary(config){ summaryCallback(it)} newTask() } constructor(sceneInfoRep: SceneInfoRep) : this(sceneInfoRep, null) private val pollutedSummary:PollutedSummary private val sceneInfoRep: SceneInfoRep private val config: RTExcWindLevelConfig private val taskList = mutableListOf<BaseExceptionAnalysis<RTExcWindLevelConfig, PollutedClue>>() fun initTask() { taskList.clear() newTask() pollutedSummary.clear() } private fun newTask() { taskList.apply { add(RTExcWindLevel1(config) { exceptionCallback(it) }.also { it.init() }) add(RTExcWindLevel1_1(config) { exceptionCallback(it) }.also { it.init() }) add(RTExcWindLevel4(config) { exceptionCallback(it) }.also { it.init() }) add(RTExcWindLevel6(config) { exceptionCallback(it) }.also { it.init() }) } } /** * è®¡ç®æ°ç䏿¡å®æ¶èµ°èªæ°æ® */ fun addOneData(data: BaseRealTimeData) { // 计ç®å¼å¸¸ taskList.forEach { it.onNextData(data) } pollutedSummary.refreshLatestMonitorData(data) // é宿¶é´å æ²¡ææ°æ°æ®ä¼ å ¥ï¼åç»æå½åçè®¡ç® } /** * è¶ æ¶å¤çï¼è¾é¿æ¶é´æ²¡ææ°æ°æ®è¿å ¥ï¼è¿è¡åå§åæä½ */ private fun dealOnTimeout() { val timer = Timer(true) timer.schedule(object : TimerTask() { override fun run() { TODO("Not yet implemented") } }, 60 * 1000) timer.cancel() } // æ°æ®çªåå¼å¸¸åè° private fun exceptionCallback(ex: PollutedClue) { // æº¯æºæ±¡ææºä¿¡æ¯ ex.searchScenes(sceneInfoRep) // è®°å½æ±¡æçº¿ç´¢ pollutedSummary.addClue(ex) // å¹¿ææ±¡ææº¯æºå¼å¸¸ç»æ UnderwayWebSocketSender.broadcast(MsgType.PolClue.value, ex) } private fun summaryCallback(ex: PollutedSummary.AnalysisResult) { // å¹¿ææ±¡ææº¯æºå¼å¸¸ç»æ UnderwayWebSocketSender.broadcast(MsgType.AnaResult.value, ex) } } src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/config/RTExcWindLevelConfig.kt
@@ -18,9 +18,9 @@ ) // éå®è·ç¦»å ï¼åä½ï¼ç±³ï¼ var distanceLimit = 1000 var distanceLimit = 3000 // é宿¶é´å ï¼åä½ï¼åéï¼ var timeLimit = 2 var timeLimit = 3 // 0 - 1çº§é£ var windLevelCondition1 = WindLevelCondition( @@ -52,4 +52,9 @@ // æº¯æºæ©æ£åç§»è§åº¦ï¼åä½ï¼åº¦ï¼ var sourceTraceDegOffset = 120.0 // 宿¶çº¿ç´¢åææ¶é´é´é(åä½ï¼åé) var analysisPeriod = 15 // 宿¶åæé´éä¸ï¼ç«å³è¿è¡çº¿ç´¢åæçæå°çº¿ç´¢é(åä½ï¼ä¸ª) var analysisCount = 3 } src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/exceptiontype/BaseRTExcWindLevel.kt
@@ -39,6 +39,7 @@ override fun judgeException(p: BaseRealTimeData?, n: BaseRealTimeData): MutableMap<FactorType, Boolean> { val res = mutableMapOf<FactorType, Boolean>() println() config.factorFilter.mainList().forEach { f -> if (p?.getByFactorType(f) == null || n.getByFactorType(f) == null || n.windSpeed == null) { res[f] = (false) @@ -48,17 +49,20 @@ val con = windLevelCondition if (n.windSpeed!! in con.windSpeed.first..con.windSpeed.second) { println("é£éï¼${n.windSpeed}ï¼[${con.windSpeed.first} - ${con.windSpeed.second}]") val pValue = p.getByFactorType(f)!! val nValue = n.getByFactorType(f)!! // 计ç®åä¸ä¸ªæ°æ®ç¸æ¯äºåä¸ä¸ªæ°æ®çååç val r = (nValue - pValue) / pValue val b1 = r >= con.mutationRate.first println("å åï¼${f.des}ï¼å¹ 度ï¼${r}ï¼éå®ï¼${con.mutationRate.first}ï¼${b1}") res[f] = b1 } else { res[f] = false } } return res } src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedArea.kt
@@ -91,7 +91,7 @@ if (distanceRange.first == .0) { result.add(center) } else { // ä»å¼å§è§åº¦å¾ªç¯è®¡ç®åæ ç¹å¼ç»æè§åº¦ï¼æ¥é¿1° // ä»å¼å§è§åº¦å¾ªç¯è®¡ç®åæ ç¹è³ç»æè§åº¦ï¼æ¥é¿1° var startDeg = sDeg while (startDeg <= eDeg) { val p = MapUtil.getPointByLen(center, distanceRange.first, startDeg * PI / 180) src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedData.kt
@@ -15,16 +15,6 @@ class PollutedData() { /** * * 1. 软é£1.5m/så以ä¸ï¼ * ååå¼ä¸åå¹ åº¦å¨50%以ä¸1次ï¼è®¤ä¸ºæ¯ä¸´è¿åç(50ç±³) * ååå¼ä¸åå¹ åº¦å¨20%以ä¸1次ï¼è®¤ä¸ºæ¯è¿è·ç¦»åçï¼50ç±³ - 500ç±³ï¼ * 1.5 m/så以ä¸ï¼é稳天æ°ï¼ä¸´è¿åç(50ç±³) * 2. 1.6 - 7.9 m/sï¼ååå¼ä¸åå¹ åº¦å¨20%以ä¸3次ï¼è®¤ä¸ºæ¯è¿è·ç¦»åçï¼50ç±³ - 1å ¬éï¼ * 3. 8 - 13.8 m/s 以ä¸ï¼ååå¼ä¸åå¹ åº¦å¨10%以ä¸3次ï¼è®¤ä¸ºæ¯è¿è·ç¦»åç(50ç±³ - 2å ¬é) */ /** * 9. å ³èå å * a) pm2.5ãpm10ç¹å«é«ï¼ä¸¤è å¨åæ åµä¸åæ¥å±ç¤ºï¼pm2.5å pm10çæ¯éååï¼æ¯éè¶é«ï¼è¶æå¯è½æ¯é¤é¥® * b) pm10ç¹å«é«ãpm2.5è¾é«ï¼å¤§é¢ç²æ¬å°æ±¡æï¼åªå±ç¤ºpm10ï¼pm2.5å pm10çæ¯éååï¼å·¥å°ä¸ºä¸» @@ -62,6 +52,8 @@ dataList.add(it) dataVoList.add(it.toDataVo()) } calPer() } var deviceCode: String? = null @@ -86,6 +78,8 @@ // å åé级ååå¹ åº¦ var percentage: Double? = null // å åé级平åååå¹ åº¦ var avgPer: Double? = null // åçæ¬¡æ° var times: Int? = null @@ -93,4 +87,14 @@ // å¼å¸¸çæµæ°æ® var dataList: MutableList<BaseRealTimeData> = mutableListOf() var dataVoList: MutableList<DataVo> = mutableListOf() private fun calPer() { if (dataList.size < 2) return var total = .0 for (i in 0 until dataList.size - 1) { total += dataList[i].getByFactorType(selectedFactor!!.main)!! } avgPer = total / (dataList.size - 1) } } src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedSource.kt
@@ -4,7 +4,13 @@ import com.flightfeather.uav.common.utils.MapUtil import com.flightfeather.uav.domain.entity.SceneInfo import com.flightfeather.uav.domain.repository.SceneInfoRep import com.flightfeather.uav.lightshare.bean.AreaVo import com.flightfeather.uav.lightshare.bean.SceneInfoVo import com.flightfeather.uav.lightshare.eunm.SceneType import com.flightfeather.uav.socket.eunm.FactorType import org.springframework.beans.BeanUtils import org.springframework.web.context.ContextLoader import kotlin.math.min /** * æ±¡ææ¥æº @@ -20,7 +26,11 @@ */ // 溯æºä¼ä¸ var sceneList:List<SceneInfo?>? = null var sceneList:List<SceneInfoVo?>? = null init { } fun searchScenes(pollutedArea: PollutedArea, factor: FactorFilter.SelectedFactor) { ContextLoader.getCurrentWebApplicationContext()?.getBean(SceneInfoRep::class.java)?.run { @@ -35,9 +45,10 @@ // Fixme 2025.5.14: æ±¡ææºçåæ æ¯é«å¾·å°å¾åæ ç³»ï¼ç«æåæ ç³»ï¼ï¼èèµ°èªæ°æ®æ¯WGS84åæ ç³» // æç §åºåæ£ç´¢å 鍿±¡ææºä¿¡æ¯ // 1. é¦å æç §åè³èå´ä»æ°æ®åºåæ¥çéæ±¡ææºï¼éè¦å å°åæ 转æ¢ä¸ºgcj02ï¼ç«æåæ ç³»ï¼ï¼å ä¸ºæ±¡ææºåºæ¯ä¿¡æ¯é½ä¸ºæ¤åæ ç³» val polygonTmp = pollutedArea.polygon!!.map { MapUtil.gcj02ToWgs84(it) } // val polygonTmp = pollutedArea.polygon!!.map { // MapUtil.gcj02ToWgs84(it) // } val polygonTmp = pollutedArea.polygon!! val fb = MapUtil.calFourBoundaries(polygonTmp) val sceneList = sceneInfoRep.findByCoordinateRange(fb) // 2. åç²¾ç¡®å¤ææ¯å¦å¨ååæº¯æºåºåå¤è¾¹å½¢å é¨ @@ -49,9 +60,57 @@ } } this.sceneList = result findClosestStation(sceneInfoRep, result) TODO("æç §æéçæµå åç±»åï¼åºåæ±¡ææºç±»å") // TODO("æç §æéçæµå åç±»åï¼åºåæ±¡ææºç±»å") } /** * 计ç®å¯è½çç¸å ³æ±¡æåºæ¯ç±»å */ private fun calFactorType(factor: FactorFilter.SelectedFactor) { // when (factor.main) { // FactorType.PM25 -> {} // // } } /** * è®¡ç®æè¿ççæµç«ç¹ */ private fun findClosestStation(sceneInfoRep: SceneInfoRep, sceneList: List<SceneInfo>) { val res1 = sceneInfoRep.findByArea(AreaVo().apply { sceneTypeId = SceneType.TYPE19.value.toString() }) val res2 = sceneInfoRep.findByArea(AreaVo().apply { sceneTypeId = SceneType.TYPE20.value.toString() }) val res = res1.toMutableList().apply { addAll(res2) } this.sceneList = sceneList.map { var minLen = -1.0 var selectedRes: SceneInfo? = null res.forEach { r-> val dis = MapUtil.getDistance( it.longitude.toDouble(), it.latitude.toDouble(), r!!.longitude.toDouble(), r.latitude.toDouble() ) if (minLen < 0 || dis < minLen) { minLen = dis selectedRes = r } } val vo = SceneInfoVo() BeanUtils.copyProperties(it, vo) vo.closestStation = selectedRes vo.length = minLen return@map vo } } } src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedSummary.kt
@@ -1,16 +1,14 @@ package com.flightfeather.uav.biz.sourcetrace.model import com.flightfeather.uav.biz.FactorFilter import com.flightfeather.uav.biz.dataanalysis.BaseExceptionAnalysis import com.flightfeather.uav.biz.sourcetrace.RealTimeAnalysisConfig import com.flightfeather.uav.biz.sourcetrace.config.RTExcWindLevelConfig import com.flightfeather.uav.biz.sourcetrace.exceptiontype.* import com.flightfeather.uav.common.utils.GsonUtils import com.flightfeather.uav.domain.entity.BaseRealTimeData import com.flightfeather.uav.domain.repository.SceneInfoRep import com.flightfeather.uav.socket.eunm.FactorType import com.flightfeather.uav.socket.sender.UnderwayWebSocketSender import java.util.* import com.flightfeather.uav.domain.entity.SceneInfo import java.time.LocalDateTime import java.util.Timer import java.util.TimerTask // å¼å¸¸æ°æ®çæåè°ç±» typealias NewPolluteSummaryCallback = (ex: PollutedSummary.AnalysisResult) -> Unit /** * æ±¡ææ åµæ±æ» @@ -18,7 +16,7 @@ * @date 2025/5/27 * @author feiyu02 */ class PollutedSummary { class PollutedSummary(private val config: RTExcWindLevelConfig, private val callback: NewPolluteSummaryCallback) { /** @@ -26,75 +24,152 @@ * æ¯ä¸å»é对åå²çº¿ç´¢è¿è¡ç»è®¡ï¼æåºä¼å建议ï¼ç¦»æ±¡ææºè¾è¿ãæ±¡ææºæ°éãåºç°æ¬¡æ°ï¼ãèµ°èªè·¯çº¿è°æ´å»ºè®®ï¼ç¦»æ±¡ææºè¾è¿ãèµ°èªè½¨è¿¹æªæ¥è¿æº¯æºåºæ¯ï¼ */ constructor(sceneInfoRep: SceneInfoRep, factorFilter: FactorFilter?) { this.sceneInfoRep = sceneInfoRep this.config = if (factorFilter != null) RTExcWindLevelConfig(factorFilter) else RTExcWindLevelConfig( FactorFilter.builder() // .withMain(FactorType.NO2) .withMain(FactorType.CO) // .withMain(FactorType.H2S) // .withMain(FactorType.SO2) // .withMain(FactorType.O3) .withMain(FactorType.PM25) .withMain(FactorType.PM10) .withMain(FactorType.VOC) .create() ) initTask() } constructor(sceneInfoRep: SceneInfoRep) : this(sceneInfoRep, null) // 污æçº¿ç´¢ var clueList = mutableListOf<PollutedClue>() private val sceneInfoRep: SceneInfoRep private val config: RTExcWindLevelConfig private val taskList = mutableListOf<BaseExceptionAnalysis<RTExcWindLevelConfig, PollutedClue>>() fun initTask() { taskList.clear() taskList.apply { add(RTExcWindLevel1(config) { exceptionCallback(it) }.also { it.init() }) add(RTExcWindLevel1_1(config) { exceptionCallback(it) }.also { it.init() }) add(RTExcWindLevel4(config) { exceptionCallback(it) }.also { it.init() }) add(RTExcWindLevel6(config) { exceptionCallback(it) }.also { it.init() }) } /** * åæç»æ */ inner class AnalysisResult{ // æç §è¢«æ«ææ¬¡æ°éåºæåçæ±¡ææºå表 var sortedSceneList: List<Pair<SceneInfo?, Int>>? = null } /** * è®¡ç®æ°ç䏿¡å®æ¶èµ°èªæ°æ® * 宿¶ç»è®¡ */ fun addOneData(data: BaseRealTimeData) { // 计ç®å¼å¸¸ taskList.forEach { it.onNextData(data) } // é宿¶é´å æ²¡ææ°æ°æ®ä¼ å ¥ï¼åç»æå½åçè®¡ç® inner class AnalysisStatistic { // æç §è¢«æ«ææ¬¡æ°éåºæåçæ±¡ææºå表 var sortedSceneList: List<Pair<SceneInfo?, Int>>? = null } /** * è¶ æ¶å¤çï¼è¾é¿æ¶é´æ²¡ææ°æ°æ®è¿å ¥ï¼è¿è¡åå§åæä½ */ private fun dealOnTimeout() { val timer = Timer(true) timer.schedule(object : TimerTask() { // ææ°å®æ¶èµ°èªçæµæ°æ® val realTimeDataList = mutableListOf<BaseRealTimeData>() // æªåæç污æçº¿ç´¢ val clueList = mutableListOf<PollutedClue>() // å·²åæç污æçº¿ç´¢ private val historyClueList = mutableListOf<PollutedClue>() // 宿¶æ±¡æåæä»»å¡æ§å¶ private var analysisTimer: Timer? = null // 宿¶æ±¡æåæä»»å¡ private val analysisOnTimeTask = object : TimerTask() { override fun run() { TODO("Not yet implemented") // è®°å½ä»»å¡è¿è¡ç¶æ analysisTaskIsRunning = true analysis() // è®°å½ä¸ä¸æ¬¡çä»»å¡ç»ææ¶é´ lastAnalysisTime = LocalDateTime.now() analysisTaskIsRunning = false } }, 60 * 1000) timer.cancel() } // æ°æ®çªåå¼å¸¸åè° private fun exceptionCallback(ex: PollutedClue) { // æº¯æºæ±¡ææºä¿¡æ¯ ex.searchScenes(sceneInfoRep) clueList // å¹¿ææ±¡ææº¯æºå¼å¸¸ç»æ UnderwayWebSocketSender.broadcast(GsonUtils.gson.toJson(ex)) // 宿¶æ±¡æåæä»»å¡è¿è¡ç¶æ private var analysisTaskIsRunning = false // ä¸ä¸æ¬¡å®æ¶æ±¡æåæä»»å¡ç»ææ¶é´ private lateinit var lastAnalysisTime: LocalDateTime init { clear() } // æ°å¢ä¸æ¡æ±¡æçº¿ç´¢ fun addClue(pollutedClue: PollutedClue) { clueList.add(pollutedClue) // realTimeSummary() analysisOnClueCount() } // å·æ°å½åææ°çèµ°èªçæµæ°æ® 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() // 以å½åæ¶é´ä¸ºèµ·ç¹ï¼éæ°å¼å§æ°çä¸è½®çå¾ è®¡æ¶ analysisTimer = Timer() val period = config.analysisPeriod * 60 * 1000L analysisTimer?.schedule(analysisOnTimeTask, period, period) } /** * å¨å®æ¶æ±¡æçº¿ç´¢åæä»»å¡çå¾ å¨ææ¶é´å ï¼è¥æ±¡æçº¿ç´¢éè¶ è¿è®¾å®å¼ï¼ç´æ¥è§¦ååæçº¿ç´¢ä»»å¡ * å¹¶éç½®å®æ¶åæä»»å¡ */ private fun analysisOnClueCount() { if (clueList.size >= config.analysisCount && !analysisTaskIsRunning) { analysisOnTimeTask.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() { val result = AnalysisResult() // å ±æå¤å°ç¸å ³æ±¡ææºï¼åªäºæ±¡ææºè¢«æ«ææ¬¡æ°è¾å¤ 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 } result.sortedSceneList = res.map { it.value } // å½åçèµ°èªæ°æ®çå®ä½åæ±¡ææºè·ç¦»æ¯å¦æ¯éæ¸æ¥è¿ï¼è¥èµ°èªè¿ç¦»äºä¸»è¦æ±¡ææºï¼æç¤ºç¨æ·è°æ´èµ°èªè·¯çº¿ // 线索åæå®æåï¼ç§»å¨è³åå²çº¿ç´¢å表 historyClueList.addAll(clueList) clueList.clear() realTimeDataList.clear() callback(result) // TODO() } } src/main/kotlin/com/flightfeather/uav/lightshare/bean/SceneInfoVo.kt
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,13 @@ package com.flightfeather.uav.lightshare.bean import com.flightfeather.uav.domain.entity.SceneInfo class SceneInfoVo : SceneInfo() { // æä¸´è¿ççæµç¹ä½ var closestStation: SceneInfo? = null // è·ç¦»ï¼åä½ï¼ç±³ï¼ï¼ var length: Double? = null } src/main/kotlin/com/flightfeather/uav/lightshare/eunm/SceneType.kt
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,29 @@ package com.flightfeather.uav.lightshare.eunm /** * åºæ¯ç±»å * @date 2025/6/2 * @author feiyu02 */ enum class SceneType(val value: Int, val des: String) { TYPE1(1, "å·¥å°"), TYPE2(2, "ç 头"), TYPE3(3, "æ°´æ³¥æ æç«"), TYPE4(4, "å·¥ä¸ä¼ä¸"), TYPE5(5, "é¤é¥®"), TYPE6(6, "汽修"), TYPE7(7, "éå°ç¹"), TYPE8(8, "空æ°è´¨éçæµç¹"), TYPE9(9, "éè·¯æ¬å°çæµç¹"), TYPE10(10, "éè·¯"), TYPE11(11, "æ²³æµæé¢"), TYPE12(12, "å·¥ä¸ååº"), TYPE13(13, "æ åºå®åºæ¯"), TYPE14(14, "å åº"), TYPE15(15, "å®éªå®¤"), TYPE16(16, "ç²¾åå°åº"), TYPE17(17, "å æ²¹ç«"), TYPE18(18, "åä¸ä½"), TYPE19(19, "彿§ç¹"), TYPE20(20, "叿§ç¹"), } src/main/kotlin/com/flightfeather/uav/socket/decoder/UnderwayWebSocketParser.kt
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,60 @@ package com.flightfeather.uav.socket.decoder import com.flightfeather.uav.common.utils.GsonUtils import com.flightfeather.uav.socket.sender.WebSocketMessage import org.springframework.util.StringUtils object UnderwayWebSocketParser { const val START_STR: String = "##" const val SPLIT_STR: String = "&&" const val END_STR: String = "%%" /** * æ¶æ¯æ ¼å¼æ ¡éª * @param message æ¶æ¯ * @return æ ¼å¼æ¯å¦åè§ */ private fun verificationMessage(message: String): Boolean { if (message.isEmpty()) { return false } if (!message.startsWith(START_STR)) { return false } if (!message.endsWith(END_STR)) { return false } return true } /** * è§£æåºç±»ååå 容 * @param message socketæ¶æ¯ä¸çdataåæ®µ * @return è§£æç»æï¼å¦ææ ¼å¼ä¸æ£ç¡®åè¿ånull */ fun decodeMessage(message: String): WebSocketMessage { if (!verificationMessage(message)) { // 忥ä¸ä¸ªä¸ä¼è¢«å¤ççæ¶æ¯ return WebSocketMessage(-1, "") } val webSocketMessage = WebSocketMessage() val parts: Array<String> = message.substring(START_STR.length, message.length - END_STR.length) .split(SPLIT_STR.toRegex()) .dropLastWhile { it.isEmpty() }.toTypedArray() webSocketMessage.type = parts[0].toInt() webSocketMessage.content = GsonUtils.gson.fromJson(parts[1], Any::class.java) return webSocketMessage } /** * çææå®æ ¼å¼çæ¶æ¯å符串 * @return çæçæ¶æ¯å符串 */ fun encodeMessage(webSocketMessage: WebSocketMessage): String { return START_STR + webSocketMessage.type + SPLIT_STR + GsonUtils.gson.toJson(webSocketMessage.content, webSocketMessage.content?.javaClass) + END_STR } } src/main/kotlin/com/flightfeather/uav/socket/handler/UnderwayWebSocketServerHandler.kt
@@ -1,16 +1,13 @@ package com.flightfeather.uav.socket.handler import com.flightfeather.uav.biz.sourcetrace.RealTimeExceptionAnalysisController import com.flightfeather.uav.common.api2word.utils.JsonUtils import com.flightfeather.uav.biz.sourcetrace.SourceTraceController import com.flightfeather.uav.common.utils.GsonUtils import com.flightfeather.uav.domain.entity.BaseRealTimeData import com.flightfeather.uav.domain.repository.SceneInfoRep import com.flightfeather.uav.lightshare.bean.DataVo import com.flightfeather.uav.socket.sender.UnderwayWebSocketSender import com.google.gson.JsonSyntaxException import io.netty.channel.ChannelHandlerContext import io.netty.handler.codec.http.websocketx.TextWebSocketFrame import org.springframework.stereotype.Component /** * @@ -19,7 +16,7 @@ */ class UnderwayWebSocketServerHandler(sceneInfoRep: SceneInfoRep) : BaseHandler() { private val realTimeExceptionAnalysisController = RealTimeExceptionAnalysisController(sceneInfoRep) private val sourceTraceController = SourceTraceController(sceneInfoRep) override var tag: String = "UAV-WS" @@ -41,11 +38,11 @@ // Test try { if (msgTxt == "start") { realTimeExceptionAnalysisController.initTask() sourceTraceController.initTask() } else { val data = GsonUtils.parserJsonToArrayBeans(msgTxt, DataVo::class.java) data.forEach { realTimeExceptionAnalysisController.addOneData( sourceTraceController.addOneData( it.toBaseRealTimeData(BaseRealTimeData::class.java) ) } src/main/kotlin/com/flightfeather/uav/socket/processor/UnderwayProcessor.kt
@@ -1,27 +1,19 @@ package com.flightfeather.uav.socket.processor import com.flightfeather.uav.biz.FactorFilter import com.flightfeather.uav.biz.sourcetrace.RealTimeExceptionAnalysisController import com.flightfeather.uav.common.location.LocationRoadNearby import com.flightfeather.uav.biz.sourcetrace.SourceTraceController import com.flightfeather.uav.domain.entity.BaseRealTimeData import com.flightfeather.uav.model.epw.EPWDataPrep import com.flightfeather.uav.domain.repository.AirDataRep import com.flightfeather.uav.domain.repository.RealTimeDataRep import com.flightfeather.uav.domain.repository.SceneInfoRep import com.flightfeather.uav.domain.repository.SegmentInfoRep import com.flightfeather.uav.socket.bean.AirDataPackage import com.flightfeather.uav.socket.decoder.AirDataDecoder import com.flightfeather.uav.socket.decoder.DataPackageDecoder import com.flightfeather.uav.socket.eunm.AirCommandUnit import com.flightfeather.uav.socket.eunm.FactorType import com.flightfeather.uav.socket.eunm.UWDeviceType import com.flightfeather.uav.socket.handler.UnderwayWebSocketServerHandler import io.netty.channel.ChannelHandlerContext import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Component import java.text.SimpleDateFormat import java.util.* import javax.annotation.PostConstruct /** * å¤çsocketæ¥æ¶çæ¶æ¯ @@ -46,7 +38,7 @@ private val dataProcessMap = mutableMapOf<String?, EPWDataPrep>() // 宿¶èµ°èªæ±¡ææº¯æºå¤çå¨ private val realTimeExceptionAnalysisMap = mutableMapOf<String?, RealTimeExceptionAnalysisController>() private val sourceTraceMap = mutableMapOf<String?, SourceTraceController>() override var tag: String = "èµ°èªçæµ" @@ -60,11 +52,11 @@ saveToTxt(msg) saveToDataBase(packageData)?.takeIf { it.isNotEmpty() }?.get(0)?.let { // æ¯å°è®¾å¤æåèªåç¬çå¼å¸¸æ°æ®å¤çå¨ if (!realTimeExceptionAnalysisMap.containsKey(it.deviceCode)) { realTimeExceptionAnalysisMap[it.deviceCode] = RealTimeExceptionAnalysisController(sceneInfoRep) if (!sourceTraceMap.containsKey(it.deviceCode)) { sourceTraceMap[it.deviceCode] = SourceTraceController(sceneInfoRep) } // å°èµ°èªæ°æ®ä¼ å ¥å¼å¸¸å¤çå¨ realTimeExceptionAnalysisMap[it.deviceCode]?.addOneData(it) sourceTraceMap[it.deviceCode]?.addOneData(it) } } else { src/main/kotlin/com/flightfeather/uav/socket/sender/MsgType.kt
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,18 @@ package com.flightfeather.uav.socket.sender import com.flightfeather.uav.biz.sourcetrace.model.PollutedClue import com.flightfeather.uav.biz.sourcetrace.model.PollutedSummary enum class MsgType(val value: Int) { /** * 污æçº¿ç´¢ * @see [PollutedClue] */ PolClue(1), /** * 污æåæç»æ * @see [PollutedSummary.AnalysisResult] */ AnaResult(2), } src/main/kotlin/com/flightfeather/uav/socket/sender/UnderwayWebSocketSender.kt
@@ -1,5 +1,6 @@ package com.flightfeather.uav.socket.sender import com.flightfeather.uav.socket.decoder.UnderwayWebSocketParser import io.netty.channel.ChannelHandlerContext import io.netty.handler.codec.http.websocketx.TextWebSocketFrame @@ -28,6 +29,11 @@ } fun broadcast(type:Int, content:Any) { val msg = UnderwayWebSocketParser.encodeMessage(WebSocketMessage(type,content)) broadcast(msg) } fun broadcast(msg: String) { sessionPool.forEach { (t, u) -> u?.channel()?.writeAndFlush(TextWebSocketFrame(msg)) src/main/kotlin/com/flightfeather/uav/socket/sender/WebSocketMessage.kt
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,21 @@ package com.flightfeather.uav.socket.sender class WebSocketMessage { /** * æ¶æ¯ç±»å */ var type: Int = 0 /** * æ¶æ¯å 容 */ var content: Any? = null constructor() constructor(type: Int, content: Any?) { this.type = type this.content = content } } src/test/kotlin/com/flightfeather/uav/biz/dataprocess/DataProcessTest.kt
@@ -1,12 +1,15 @@ package com.flightfeather.uav.biz.dataprocess import com.flightfeather.uav.domain.mapper.RealTimeDataMapper import com.flightfeather.uav.domain.repository.SceneInfoRep import com.flightfeather.uav.lightshare.bean.AreaVo import com.flightfeather.uav.lightshare.service.RealTimeDataService import org.junit.Test import org.junit.runner.RunWith import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.test.context.junit4.SpringRunner import org.springframework.web.context.ContextLoader import java.time.LocalDateTime import java.time.format.DateTimeFormatter import java.util.* @@ -56,4 +59,12 @@ process.outPutDailyVariation() process.done() } @Test fun foo2() { ContextLoader.getCurrentWebApplicationContext()?.getBean(SceneInfoRep::class.java)?.run { val res = this.findByArea(AreaVo().apply { sceneTypeId = "20" }) res.forEach { println(it?.name) } } } } src/test/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedSourceTest.kt
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,33 @@ package com.flightfeather.uav.biz.sourcetrace.model import com.flightfeather.uav.biz.FactorFilter import com.flightfeather.uav.domain.repository.SceneInfoRep import com.flightfeather.uav.socket.eunm.FactorType import org.junit.Test import org.junit.runner.RunWith import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.test.context.junit4.SpringRunner @RunWith(SpringRunner::class) @SpringBootTest class PollutedSourceTest { @Autowired lateinit var sceneInfoRep: SceneInfoRep @Test fun foo1() { val source = PollutedSource() val pollutedArea = PollutedArea().apply { polygon = listOf( 121.421521 to 31.195457, 121.421721 to 31.195457, 121.421521 to 31.195257, 121.421721 to 31.195257, ) } source.searchScenes(pollutedArea, sceneInfoRep, FactorFilter.SelectedFactor(FactorType.VOC)) } }