From c56e1e74426238939f229f0005828d05089715ff Mon Sep 17 00:00:00 2001
From: feiyu02 <risaku@163.com>
Date: 星期四, 03 七月 2025 17:30:58 +0800
Subject: [PATCH] 2025.7.3 1. 新增动态污染溯源新的判定逻辑

---
 src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedSource.kt |  167 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 167 insertions(+), 0 deletions(-)

diff --git a/src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedSource.kt b/src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedSource.kt
index d0e3fd0..1543d33 100644
--- a/src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedSource.kt
+++ b/src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedSource.kt
@@ -1,5 +1,16 @@
 package com.flightfeather.uav.biz.sourcetrace.model
 
+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.round
+
 /**
  * 姹℃煋鏉ユ簮
  * 绯荤粺鍐呴儴鐨勬薄鏌撳満鏅�佺數瀛愬湴鍥炬悳绱㈠緱鍒扮殑瀹為檯璺璺彛绛夋爣蹇椾俊鎭�
@@ -8,5 +19,161 @@
  */
 class PollutedSource {
 
+    /**
+     * 婧簮娓呭崟鏄剧ず涓庝复杩戠洃娴嬬珯鐐圭殑璺濈锛堝浗鎺с�佸競鎺с�佺綉鏍煎寲鐩戞祴鐐癸級
+     *
+     */
 
+    // 婧簮浼佷笟
+    var sceneList: List<SceneInfoVo?>? = null
+
+    // 婧簮鎺ㄧ悊缁撹
+    var conclusion: String? = null
+
+    fun searchScenes(pollutedArea: PollutedArea, pollutedData: PollutedData) {
+        ContextLoader.getCurrentWebApplicationContext()?.getBean(SceneInfoRep::class.java)?.run {
+            searchScenes(pollutedArea, this, pollutedData)
+        }
+    }
+
+    /**
+     * 鏌ユ壘绯荤粺鍐呴儴婧簮鑼冨洿鍐呯殑姹℃煋浼佷笟
+     */
+    fun searchScenes(pollutedArea: PollutedArea, sceneInfoRep: SceneInfoRep, pollutedData: PollutedData) {
+        // Fixme 2025.5.14: 姹℃煋婧愮殑鍧愭爣鏄珮寰峰湴鍥惧潗鏍囩郴锛堢伀鏄熷潗鏍囩郴锛夛紝鑰岃蛋鑸暟鎹槸WGS84鍧愭爣绯�
+        // 鎸夌収鍖哄煙妫�绱㈠唴閮ㄦ薄鏌撴簮淇℃伅
+        var result = mutableListOf<SceneInfo>()
+        // 1. 棣栧厛鎸夌収鍥涜嚦鑼冨洿浠庢暟鎹簱鍒濇绛涢�夋薄鏌撴簮锛屾澶勭殑鍖哄煙鍧愭爣宸茶浆鎹负鐏槦鍧愭爣绯�
+        val polygonTmp = pollutedArea.polygon!!
+        val fb = MapUtil.calFourBoundaries(polygonTmp)
+        val sceneList = sceneInfoRep.findByCoordinateRange(fb)
+        // 2. 鍐嶇簿纭垽鏂槸鍚﹀湪鍙嶅悜婧簮鍖哄煙澶氳竟褰㈠唴閮�
+        sceneList.forEach {
+            val point = it!!.longitude.toDouble() to it.latitude.toDouble()
+            if (MapUtil.isPointInPolygon(point, polygonTmp)) {
+                result.add(it)
+            }
+        }
+
+        val closePolygonTmp = pollutedArea.closePolygon!!
+        val closeFb = MapUtil.calFourBoundaries(closePolygonTmp)
+        val closeSceneList = sceneInfoRep.findByCoordinateRange(closeFb)
+        // 2. 鍐嶇簿纭垽鏂槸鍚﹀湪鍙嶅悜婧簮鍖哄煙澶氳竟褰㈠唴閮�
+        closeSceneList.forEach {
+            val point = it!!.longitude.toDouble() to it.latitude.toDouble()
+            if (MapUtil.isPointInPolygon(point, closePolygonTmp)) {
+                result.add(it)
+            }
+        }
+
+        // 鏍规嵁姹℃煋鍥犲瓙鐨勯噺绾э紝璁$畻涓昏鐨勬薄鏌撳満鏅被鍨嬶紝绛涢�夌粨鏋�
+        val mainSceneType = calSceneType(pollutedData)
+        if (mainSceneType != null) {
+            this.conclusion = mainSceneType.first
+            result = result.filter {
+                val r = mainSceneType.second.find { s->
+                    s.value == it.typeId.toInt()
+                }
+                r != null
+            }.toMutableList()
+        }
+
+        this.sceneList = findClosestStation(sceneInfoRep, result)
+
+    }
+
+    /**
+     * 璁$畻鍙兘鐨勭浉鍏虫薄鏌撳満鏅被鍨嬩互鍙婃帹鐞嗙粨璁�
+     */
+    @Throws(Exception::class)
+    private fun calSceneType(pollutedData: PollutedData): Pair<String, List<SceneType>>? {
+        when (pollutedData.selectedFactor?.main) {
+            // 姘哀鍖栧悎鐗╋紝涓�鑸敱浜庢満鍔ㄨ溅灏炬皵锛屽悓姝ヨ绠桟O
+            FactorType.NO2 -> {
+                val coAvg = round(pollutedData.dataList.map { it.co!! }.average()) / 1000
+                return "姘哀鍖栧悎鐗╁亸楂橈紝CO鐨勯噺绾т负${coAvg}mg/m鲁锛屼竴鑸敱浜庢満鍔ㄨ溅灏炬皵閫犳垚锛屾薄鏌撴簮浠ユ苯淇�佸姞娌圭珯涓轰富" to
+                        listOf(SceneType.TYPE6, SceneType.TYPE10, SceneType.TYPE17)
+            }
+
+            FactorType.CO -> return null
+
+            FactorType.H2S -> return null
+
+            FactorType.SO2 -> return null
+
+            FactorType.O3 -> return null
+            // a) pm2.5銆乸m10鐗瑰埆楂橈紝涓よ�呭湪鍚勬儏鍐典笅鍚屾灞曠ず锛宲m2.5鍗爌m10鐨勬瘮閲嶅彉鍖栵紝姣旈噸瓒婇珮锛岃秺鏈夊彲鑳芥槸椁愰ギ
+            // b) pm10鐗瑰埆楂樸�乸m2.5杈冮珮锛屽ぇ棰楃矑鎵皹姹℃煋锛屽彧灞曠ずpm10锛宲m2.5鍗爌m10鐨勬瘮閲嶅彉鍖栵紝宸ュ湴涓轰富
+            FactorType.PM25,
+            FactorType.PM10,
+                -> {
+                val pm25Avg = round(pollutedData.dataList.map { it.pm25!! }.average() * 10) / 10
+                val pm10Avg = round(pollutedData.dataList.map { it.pm10!! }.average() * 10) / 10
+                // 璁$畻寮傚父鏁版嵁鐨刾m2.5鍗爌m10姣旈噸鐨勫潎鍊�
+                val percentageAvg = pollutedData.dataList.map {
+                    it.pm25!! / it.pm10!!
+                }.average()
+                val str =
+                    "PM2.5閲忕骇涓�${pm25Avg}渭g/m鲁锛孭M10閲忕骇涓�${pm25Avg}渭g/m鲁锛孭M2.5鍗燩M10鐨勬瘮閲嶄负${round(percentageAvg * 100)}%"
+                return if (percentageAvg > 0.666) {
+                    "${str}锛屾瘮閲嶈緝澶э紝姹℃煋婧愪互椁愰ギ涓轰富锛屽伐鍦版涔�" to
+                            listOf(SceneType.TYPE1, SceneType.TYPE2, SceneType.TYPE3, SceneType.TYPE14, SceneType.TYPE5)
+                } else if (percentageAvg < 0.333) {
+                    "${str}锛屾瘮閲嶈緝灏忥紝灞炰簬澶ч绮掓壃灏樻薄鏌擄紝姹℃煋婧愪互宸ュ湴涓轰富" to
+                            listOf(SceneType.TYPE1, SceneType.TYPE2, SceneType.TYPE3, SceneType.TYPE14, SceneType.TYPE5)
+                } else {
+                    "${str}锛屾薄鏌撴簮浠ラ楗�佸伐鍦颁负涓�" to
+                            listOf(SceneType.TYPE1, SceneType.TYPE2, SceneType.TYPE3, SceneType.TYPE14, SceneType.TYPE5)
+                }
+            }
+            // c) VOC杈冮珮锛屽悓姣旇绠梡m2.5鐨勯噺绾э紝鍙兘瀛樺湪鍚屾鍋忛珮锛堟苯淇�佸姞娌圭珯锛�, 鍚屾璁$畻O3鏄惁鏈夐珮鍊�
+            // d) VOC杈冮珮锛屽浜庡姞娌圭珯锛堣溅杈嗘嫢鍫垫儏鍐碉級锛孋O涓�鑸緝楂�, 鍚屾璁$畻O3鏄惁鏈夐珮鍊�
+            FactorType.VOC -> {
+                val pm25Avg = round(pollutedData.dataList.map { it.pm25!! }.average() * 10) / 10
+                val coAvg = round(pollutedData.dataList.map { it.co!! }.average()) / 1000
+                val o3Avg = round(pollutedData.dataList.map { it.o3!! }.average() * 10) / 10
+                return "VOC鍋忛珮锛屽悓鏃禤M2.5閲忕骇涓�${pm25Avg}渭g/m鲁锛孋O閲忕骇涓�${coAvg}mg/m鲁锛孫3閲忕骇涓�${o3Avg}渭g/m鲁锛屾薄鏌撴簮浠ユ苯淇�佸姞娌圭珯涓轰富" to
+                        listOf(SceneType.TYPE6, SceneType.TYPE17, SceneType.TYPE12)
+            }
+
+            else -> return null
+        }
+    }
+
+    /**
+     * 璁$畻鏈�杩戠殑鐩戞祴绔欑偣
+     */
+    private fun findClosestStation(sceneInfoRep: SceneInfoRep, sceneList: List<SceneInfo>): List<SceneInfoVo> {
+        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) }
+
+        return 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
+        }
+    }
 }
\ No newline at end of file

--
Gitblit v1.9.3