From f1ea263462d1f3f10a886fb083536a38b03a1ceb Mon Sep 17 00:00:00 2001 From: feiyu02 <risaku@163.com> Date: 星期三, 14 五月 2025 17:33:04 +0800 Subject: [PATCH] 1. 新增动态污染溯源的数据异常判断逻辑 2. 新增动态污染溯源websocket连接功能 --- src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/RealTimeExceptionAnalysisController.kt | 162 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 files changed, 132 insertions(+), 30 deletions(-) diff --git a/src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/RealTimeExceptionAnalysisController.kt b/src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/RealTimeExceptionAnalysisController.kt index 4bd356a..9fb9090 100644 --- a/src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/RealTimeExceptionAnalysisController.kt +++ b/src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/RealTimeExceptionAnalysisController.kt @@ -4,68 +4,170 @@ import com.flightfeather.uav.biz.dataanalysis.BaseExceptionAnalysis import com.flightfeather.uav.biz.sourcetrace.exceptiontype.RealTimeExceptionValueMutation import com.flightfeather.uav.biz.sourcetrace.model.RealTimeExceptionResult -import com.flightfeather.uav.common.api2word.utils.JsonUtils -import com.flightfeather.uav.common.location.LocationRoadNearby import com.flightfeather.uav.common.utils.GsonUtils +import com.flightfeather.uav.common.utils.MapUtil import com.flightfeather.uav.domain.entity.BaseRealTimeData +import com.flightfeather.uav.domain.entity.SceneInfo import com.flightfeather.uav.domain.entity.avg -import com.flightfeather.uav.domain.repository.RealTimeDataRep -import com.flightfeather.uav.domain.repository.SegmentInfoRep +import com.flightfeather.uav.domain.repository.SceneInfoRep +import com.flightfeather.uav.socket.eunm.FactorType import com.flightfeather.uav.socket.handler.UnderwayWebSocketServerHandler -import com.google.gson.Gson +import com.flightfeather.uav.socket.sender.UnderwayWebSocketSender +import java.util.Timer +import java.util.TimerTask +import kotlin.math.PI /** * 瀹炴椂璧拌埅姹℃煋婧簮 * @date 2025/5/8 * @author feiyu02 */ -class RealTimeExceptionAnalysisController ( - private val realTimeDataRep: RealTimeDataRep, - private val locationRoadNearby: LocationRoadNearby, - private val segmentInfoRep: SegmentInfoRep, - private val underwayWebSocketServerHandler: UnderwayWebSocketServerHandler, - factorFilter: FactorFilter -){ - private var config:RealTimeAnalysisConfig = RealTimeAnalysisConfig(factorFilter) + +class RealTimeExceptionAnalysisController { + + constructor(sceneInfoRep: SceneInfoRep, factorFilter: FactorFilter?) { + this.sceneInfoRep = sceneInfoRep + this.config = if (factorFilter != null) + RealTimeAnalysisConfig(factorFilter) + else + RealTimeAnalysisConfig( + 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(config) + } + + constructor(sceneInfoRep: SceneInfoRep) : this(sceneInfoRep, null) + + + private val sceneInfoRep: SceneInfoRep + + private val config: RealTimeAnalysisConfig private val taskList = mutableListOf<BaseExceptionAnalysis<RealTimeAnalysisConfig, RealTimeExceptionResult>>() private fun initTask(config: RealTimeAnalysisConfig) { taskList.clear() taskList.apply { - add(RealTimeExceptionValueMutation(config){ exceptionCallback(it)}) + add( + RealTimeExceptionValueMutation(config) { exceptionCallback(it) }.also { it.init() } + ) } + } - init { - initTask(config) - } - - // 璁$畻鍘嗗彶浠诲姟 + /** + * 璁$畻鏂扮殑涓�鏉″疄鏃惰蛋鑸暟鎹� + */ fun addOneData(data: BaseRealTimeData) { - taskList - + // 璁$畻寮傚父 + taskList.forEach { it.onNextData(data) } + // 闄愬畾鏃堕棿鍐呮病鏈夋柊鏁版嵁浼犲叆锛屽垯缁撴潫褰撳墠鐨勮绠� } + /** + * 瓒呮椂澶勭悊锛屾湁涓ょ瓒呮椂鎯呭喌 + * 1. 杈冪煭鏃堕棿鍐咃紝涓诲姩缁撴潫杩炵画褰撳墠寮傚父鍒ゆ柇 + * 2. 杈冮暱鏃堕棿鍐咃紝杩涜鍒濆鍖栨搷浣� + */ + 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: RealTimeExceptionResult) { - if (sourceTrace(ex, config)) { - underwayWebSocketServerHandler.broadcast(GsonUtils.gson.toJson(ex)) - } + // 婧簮姹℃煋婧愪俊鎭� + sourceTrace(ex, config) + // 骞挎挱姹℃煋婧簮寮傚父缁撴灉 + UnderwayWebSocketSender.broadcast(GsonUtils.gson.toJson(ex)) } - private fun sourceTrace(ex: RealTimeExceptionResult, config: RealTimeAnalysisConfig):Boolean { + /** + * 姹℃煋鍙嶅悜婧簮 + */ + private fun sourceTrace(ex: RealTimeExceptionResult, config: RealTimeAnalysisConfig) { + // 璁$畻寮傚父鏁版嵁鍧囧�� val avgData = ex.dataList.avg() if (avgData.windSpeed!! > config.sourceTraceWindSpeedLimit) { - return false + return } // 鍙栦腑闂寸偣浣滀负鍙嶅悜婧簮鐨勮捣鐐� val midData = ex.dataList[ex.dataList.size / 2] -// avgData.longitude -// avgData.latitude -// avgData.windDirection - return false + // 璁$畻鍙嶅悜婧簮鍖哄煙 + val polygon = calSector( + avgData.windSpeed!!.toDouble(), + avgData.windDirection!!.toDouble(), + midData.longitude!!.toDouble() to midData.latitude!!.toDouble(), + config.sourceTraceTimeLimit, + config.sourceTraceDegOffset + ) + + // 鎸夌収鍖哄煙妫�绱㈠唴閮ㄦ薄鏌撴簮淇℃伅 + + // 1. 棣栧厛鎸夌収鍥涜嚦鑼冨洿浠庢暟鎹簱鍒濇绛涢�夋薄鏌撴簮 + val fb = MapUtil.calFourBoundaries(polygon) + val sceneList = sceneInfoRep.findByCoordinateRange(fb) + // 2. 鍐嶇簿纭垽鏂槸鍚﹀湪鍙嶅悜婧簮鍖哄煙澶氳竟褰㈠唴閮� + val result = mutableListOf<SceneInfo>() + sceneList.forEach { + // Fixme 2025.5.14: 姹℃煋婧愮殑鍧愭爣鏄珮寰峰湴鍥惧潗鏍囩郴锛堢伀鏄熷潗鏍囩郴锛夛紝鑰岃蛋鑸暟鎹槸WGS84鍧愭爣绯� + val point = MapUtil.gcj02ToWgs84(it!!.longitude.toDouble() to it.latitude.toDouble()) + if (MapUtil.isPointInPolygon(point, polygon)) { + result.add(it) + } + } + + // 鏇存柊涓棿鐐逛俊鎭� + ex.midData = avgData.apply { + longitude = midData.longitude + latitude = midData.latitude + } + // 鏇存柊婧簮鑼冨洿鍐呯殑姹℃煋鍦烘櫙淇℃伅 + ex.relatedSceneList = result + } + + /** + * 鏍规嵁涓績鐐瑰潗鏍囥�侀鍚戝拰椋庨�燂紝浠ュ強缁欏畾鐨勫す瑙掞紝璁$畻浠ヤ腑蹇冪偣鎸夌収椋庡悜椋庨�熷拰鏃堕暱锛屽悜澶栨墿鏁e舰鎴愮殑鎵囧舰鐨勭偣鍧愭爣 + * @param windSpeed 椋庨�燂紝鍗曚綅锛氱背/绉� + * @param windDir 椋庡悜锛屽崟浣嶏細搴� + * @param center 涓績鐐瑰潗鏍囩粡绾害 + * @param durationMin 鏃堕暱锛屽崟浣嶏細鍒嗛挓 + * @param defaultDegOffset 鎵╂暎鍋忕Щ瑙掑害 + * @return 澶氳竟褰㈤《鐐瑰潗鏍囬泦鍚� + */ + private fun calSector( + windSpeed: Double, windDir: Double, center: Pair<Double, Double>, durationMin: Int, + defaultDegOffset: Double = 30.0, + ): List<Pair<Double, Double>> { + + val sDeg = windDir - defaultDegOffset + val eDeg = windDir + defaultDegOffset + val distance = windSpeed * durationMin * 60 + + // 宸︿晶锛堥�嗘椂閽堜晶锛夐《鐐� + val p1 = MapUtil.getPointByLen(center, distance, sDeg * PI / 180) + // 椋庡悜鍙嶅悜椤剁偣 + val p2 = MapUtil.getPointByLen(center, distance, windDir * PI / 180) + // 鍙充晶锛堥『鏃堕拡渚э級椤剁偣 + val p3 = MapUtil.getPointByLen(center, distance, eDeg * PI / 180) + + return listOf(center, p1, p2, p3) } } \ No newline at end of file -- Gitblit v1.9.3