1. 新增动态污染溯源的数据异常判断逻辑
2. 新增动态污染溯源websocket连接功能
已修改18个文件
已删除1个文件
已添加11个文件
已重命名1个文件
| | |
| | | @Autowired |
| | | lateinit var electricProcessor: ElectricProcessor |
| | | |
| | | @Autowired |
| | | lateinit var underwaySocketServer:UnderwaySocketServer |
| | | |
| | | @Bean |
| | | fun runner() = ApplicationRunner{ |
| | | UnderwaySocketServer().startUnderwayServer(9030, underwayProcessor) |
| | | UnderwaySocketServer().startElectricServer(9009, electricProcessor) |
| | | underwaySocketServer.startWebSocketServer(9031, underwayProcessor) |
| | | underwaySocketServer.startUnderwayServer(9030, underwayProcessor) |
| | | underwaySocketServer.startElectricServer(9009, electricProcessor) |
| | | } |
| | | } |
| | | |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.flightfeather.uav.biz.dataanalysis |
| | | |
| | | import com.flightfeather.uav.biz.FactorFilter |
| | | |
| | | /** |
| | | * æ°æ®åæé
ç½®åæ°åºç±» |
| | | * @date 2025/5/13 |
| | | * @author feiyu02 |
| | | */ |
| | | abstract class BaseAnalysisConfig( |
| | | // å åçé |
| | | val factorFilter: FactorFilter, |
| | | ) { |
| | | } |
| | |
| | | package com.flightfeather.uav.biz.dataanalysis |
| | | |
| | | import com.flightfeather.uav.biz.FactorFilter |
| | | import com.flightfeather.uav.biz.dataanalysis.model.DataAnalysisConfig |
| | | import com.flightfeather.uav.biz.dataanalysis.model.ExceptionResult |
| | | import com.flightfeather.uav.biz.dataanalysis.model.ExceptionType |
| | | import com.flightfeather.uav.common.utils.DateUtil |
| | | import com.flightfeather.uav.domain.entity.BaseRealTimeData |
| | | import com.flightfeather.uav.domain.entity.avg |
| | | import com.flightfeather.uav.socket.eunm.FactorType |
| | | import java.time.Duration |
| | | |
| | | /** |
| | | * çæµæ°æ®å¼å¸¸åæåºç±» |
| | | */ |
| | | abstract class BaseExceptionAnalysis(config: DataAnalysisConfig) : |
| | | BaseDataAnalysis<BaseRealTimeData, DataAnalysisConfig, ExceptionResult>(config) { |
| | | abstract class BaseExceptionAnalysis<V : BaseAnalysisConfig, Y : BaseExceptionResult>(config: V) : |
| | | BaseDataAnalysis<BaseRealTimeData, V, Y>(config) { |
| | | |
| | | /** |
| | | * ç¡®å®å¼å¸¸ç±»å |
| | | */ |
| | | abstract fun getExceptionType(): ExceptionType |
| | | |
| | | /** |
| | | * 夿ç¸é»æ°æ®æ¯å¦è¿ç» |
| | | */ |
| | | open fun isContinuous(d1: BaseRealTimeData?, d2: BaseRealTimeData?): Boolean { |
| | | if (d1 == null || d2 == null) return true |
| | | |
| | | val t1 = d1.dataTime |
| | | val t2 = d2.dataTime |
| | | return Duration.between(t1?.toInstant(), t2?.toInstant()).toMillis() <= (20 * 1000) |
| | | } |
| | | |
| | | /** |
| | | * çæä¸æ¡å¼å¸¸åæç»æ |
| | | */ |
| | | open fun newResult( |
| | | start: BaseRealTimeData, end: BaseRealTimeData?, factor: FactorFilter.SelectedFactor, |
| | | exceptionData: List<BaseRealTimeData>, |
| | | ): ExceptionResult { |
| | | val eType = getExceptionType() |
| | | return ExceptionResult().apply { |
| | | missionCode = config.mission.missionCode |
| | | deviceCode = start.deviceCode |
| | | exception = eType.des |
| | | exceptionType = eType.value |
| | | factorId = factor.main.value |
| | | factorName = factor.main.des |
| | | subFactorId = factor.subs.map { it.value } |
| | | subFactorName = factor.subs.map { it.des } |
| | | selectedFactor = factor |
| | | startDate = start.dataTime |
| | | endDate = end?.dataTime |
| | | startTime = DateUtil.instance.dateToString(start.dataTime, DateUtil.DateStyle.HH_MM_SS) |
| | | endTime = DateUtil.instance.dateToString(end?.dataTime, DateUtil.DateStyle.HH_MM_SS) ?: startTime |
| | | startData = start.getByFactorType(factor.main) |
| | | endData = end?.getByFactorType(factor.main) ?: startData |
| | | |
| | | val avgData = exceptionData.avg() |
| | | // æ±åæ±¡ææ°æ®çä¸å¿åæ |
| | | longitude = avgData.longitude |
| | | latitude = avgData.latitude |
| | | // æ±å主污æå åçåå¼åèå´ |
| | | val s = dataSummary(exceptionData, factor.main) |
| | | avg = s.first |
| | | min = s.second |
| | | max = s.third |
| | | |
| | | exceptionData.forEach { dataList.add(it) } |
| | | } |
| | | } |
| | | |
| | | private fun dataSummary(exceptionData: List<BaseRealTimeData?>, factorType: FactorType): Triple<Float, Float, Float> { |
| | | var min = -1f |
| | | var max = -1f |
| | | var total = 0f |
| | | var count = 0 |
| | | exceptionData.forEach { |
| | | val value = it?.getByFactorType(factorType) ?: return@forEach |
| | | if (min == -1f || min > value) { |
| | | min = value |
| | | } |
| | | if (max == -1f || max < value) { |
| | | max = value |
| | | } |
| | | total += value |
| | | count++ |
| | | } |
| | | val avg = if (count == 0) 0f else total / count |
| | | return Triple(avg, min, max) |
| | | } |
| | | } |
| | |
| | | package com.flightfeather.uav.biz.dataanalysis |
| | | |
| | | import com.flightfeather.uav.biz.FactorFilter |
| | | import com.flightfeather.uav.biz.dataanalysis.model.DataAnalysisConfig |
| | | import com.flightfeather.uav.domain.entity.BaseRealTimeData |
| | | import com.flightfeather.uav.socket.eunm.FactorType |
| | | import java.time.Duration |
| | | |
| | | /** |
| | | * è¿ç»ç±»åçå¼å¸¸åæåºç±»,éç¨äºå½åæ°æ®ä¸ç¸é»æ°æ®ä¹é´æå
³èå
³ç³»çæ
åµ |
| | | */ |
| | | abstract class BaseExceptionContinuous(config: DataAnalysisConfig) : BaseExceptionAnalysis(config) { |
| | | abstract class BaseExceptionContinuous<V : BaseAnalysisConfig, Y : BaseExceptionResult>(config: V) : |
| | | BaseExceptionAnalysis<V, Y>(config) { |
| | | |
| | | companion object { |
| | | // è®°å½å¼å¸¸æ°æ®æ®µæ¶ï¼åå«åèµ·å§å快尾åé¢å¤è®°å½çæ°æ®ä¸ªæ°åç§»é |
| | |
| | | sIndex = eIndex |
| | | startData = data |
| | | exceptionData.clear() |
| | | exceptionData.add(data) |
| | | // exceptionData.add(data) |
| | | } |
| | | } |
| | | |
| | | protected val tagMap = mutableMapOf<FactorType, Tag>() |
| | | |
| | | // // èµ·å§æ°æ®ä¸æ |
| | | // protected var sIndex = mutableListOf<Int>() |
| | | // |
| | | // // èµ·å§æ°æ®å¯¹è±¡ |
| | | // protected var startData = mutableListOf<BaseRealTimeData?>() |
| | | // |
| | | // // æ«å°¾æ°æ®ä¸æ |
| | | // protected var eIndex = mutableListOf<Int>() |
| | | // |
| | | // // å¼å¸¸æ°æ®æ®µ |
| | | // protected var exceptionData = mutableListOf<MutableList<BaseRealTimeData>>() |
| | | |
| | | // protected var existException = mutableListOf<Boolean>() |
| | | |
| | | // èµ·å§æ°æ®ä¸æ«å°¾æ°æ®é´é |
| | | open var durationCount = 1 |
| | | |
| | | // æ«å°¾æ°æ®å¯¹è±¡ |
| | | protected var lastData: BaseRealTimeData? = null |
| | | |
| | | /** |
| | | * 夿ç¸é»æ°æ®æ¯å¦è¿ç» |
| | | */ |
| | | open fun isContinuous(d1: BaseRealTimeData?, d2: BaseRealTimeData?): Boolean { |
| | | if (d1 == null || d2 == null) return true |
| | | |
| | | val t1 = d1.dataTime |
| | | val t2 = d2.dataTime |
| | | return Duration.between(t1?.toInstant(), t2?.toInstant()).toMillis() <= (20 * 1000) |
| | | } |
| | | |
| | | /** |
| | | * 夿æ¯å¦æ»¡è¶³å¼å¸¸æ¡ä»¶ |
| | |
| | | abstract fun judgeException(p: BaseRealTimeData?, n: BaseRealTimeData): MutableMap<FactorType, Boolean> |
| | | |
| | | /** |
| | | * 夿å¼å¸¸åºç°çè¿ç»æ¶é¿æ¯å¦æ»¡è¶³æ¡ä»¶ |
| | | * @param sIndex |
| | | * @param eIndex |
| | | * 夿å¼å¸¸åºç°çè¿ç»ä¸ªæ°æ¯å¦æ»¡è¶³æ¡ä»¶ |
| | | * @param tag å¼å¸¸æ°æ®å¯¹è±¡ |
| | | */ |
| | | abstract fun judgeDuration(sIndex: Int, eIndex: Int): Boolean |
| | | abstract fun judgeExceptionCount(tag: Tag): Boolean |
| | | |
| | | /** |
| | | * å¼å¸¸æ°æ®çæªå夿 |
| | | * æ¯å¦éè¦éå¶ä¸ç»å¼å¸¸æ°æ®çé¿åº¦ |
| | | * @return é»è®¤ä¸éè¦æªå |
| | | */ |
| | | open fun needCut(tag: Tag): Boolean { |
| | | return false |
| | | } |
| | | |
| | | override fun init() { |
| | | super.init() |
| | | lastData = null |
| | | // repeat(config.factorCount) { |
| | | // startData.add(null) |
| | | // sIndex.add(0) |
| | | // eIndex.add(-1) |
| | | // existException.add(false) |
| | | // exceptionData.add(mutableListOf()) |
| | | // } |
| | | tagMap.clear() |
| | | config.factorFilter.mainList().forEach {f-> |
| | | tagMap[f] = Tag() |
| | |
| | | tagMap[f]?.let { |
| | | it.eIndex++ |
| | | // èµ·å§æ°æ® |
| | | it.endData = lastData |
| | | if (it.endData == null) { |
| | | it.endData = data |
| | | if (it.startData == null) { |
| | | it.refreshAfterCheckResult(data) |
| | | } |
| | | // 夿ç¸é»æ°æ®æ¯å¦è¿ç»å¹¶ä¸æ¯å¦æ»¡è¶³å¼å¸¸å¤æ |
| | | if (!isContinue) { |
| | | if (!isContinue || needCut(it)) { |
| | | checkResult(s) |
| | | // æ°æ®ä¸è¿ç»æ¶ï¼è®°å½å¼å¸¸æ
åµ |
| | | if (it.eIndex - it.sIndex >= durationCount) { |
| | |
| | | checkResult() |
| | | } |
| | | |
| | | // fun refreshAfterCheckResult(i:Int, data: BaseRealTimeData) { |
| | | // sIndex[i] = eIndex[i] |
| | | // startData[i] = data |
| | | // exceptionData[i].clear() |
| | | // exceptionData[i].add(data) |
| | | // } |
| | | |
| | | /** |
| | | * æ£æ¥è¿ç»å¼å¸¸ç»ææ¶ï¼æ¯å¦ç¬¦åå¼å¸¸å卿¡ä»¶ |
| | | */ |
| | | open fun checkResult(factor: FactorFilter.SelectedFactor? = null) { |
| | | val tag = tagMap[factor?.main] |
| | | if (factor != null && tag != null) { |
| | | if (tag.existException && judgeDuration(tag.sIndex, tag.eIndex - 1)) { |
| | | if (tag.existException && judgeExceptionCount(tag)) { |
| | | onNewException(tag, factor) |
| | | // tag.startData?.let { |
| | | // resultList.add(newResult(it, lastData, factor, tag.exceptionData)) |
| | | // } |
| | | // tag.existException = false |
| | | } |
| | | } else { |
| | | config.factorFilter.selectedList.forEach { f -> |
| | | val tag1 = tagMap[f.main] ?: return@forEach |
| | | if (tag1.existException && judgeExceptionCount(tag1)) { |
| | | onNewException(tag1, f) |
| | | // tag1.startData?.let { |
| | | // resultList.add(newResult(it, lastData, f, tag1.exceptionData)) |
| | | // } |
| | | // tag1.existException = false |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * æ°å¢ä¸æ¡å¼å¸¸ |
| | | */ |
| | | open fun onNewException(tag:Tag, factor: FactorFilter.SelectedFactor) { |
| | | tag.startData?.let { |
| | | resultList.add(newResult(it, lastData, factor, tag.exceptionData)) |
| | | } |
| | | tag.existException = false |
| | | } |
| | | } else { |
| | | config.factorFilter.selectedList.forEach { f -> |
| | | val tag1 = tagMap[f.main] ?: return@forEach |
| | | if (tag1.existException && judgeDuration(tag1.sIndex, tag1.eIndex - 1)) { |
| | | tag1.startData?.let { |
| | | resultList.add(newResult(it, lastData, f, tag1.exceptionData)) |
| | | } |
| | | tag1.existException = false |
| | | } |
| | | } |
| | | // repeat(config.factorCount) { i -> |
| | | // if (existException[i] && judgeDuration(sIndex[i], eIndex[i])) { |
| | | // startData[i]?.let { |
| | | // resultList.add(newResult(it, lastData, i, exceptionData[i])) |
| | | // } |
| | | // existException[i] = false |
| | | // } |
| | | // } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * çæä¸æ¡å¼å¸¸åæç»æ |
| | | */ |
| | | abstract fun newResult( |
| | | start: BaseRealTimeData, |
| | | end: BaseRealTimeData?, |
| | | factor: FactorFilter.SelectedFactor, |
| | | exceptionData: List<BaseRealTimeData>, |
| | | ): Y |
| | | |
| | | } |
| | |
| | | package com.flightfeather.uav.biz.dataanalysis |
| | | |
| | | import com.flightfeather.uav.biz.dataanalysis.model.DataAnalysisConfig |
| | | import com.flightfeather.uav.domain.entity.BaseRealTimeData |
| | | |
| | | /** |
| | | * è¿ç»ç±»åçå¼å¸¸åæåºç±»,åºå«äºç¶ç±»çå°æ¹å¨äºæ¤ç§å¼å¸¸åªååä¸ªæ°æ®æ¬èº«æå
³,ä¸ç¸é»æ°æ®æ å
³ |
| | | */ |
| | | abstract class BaseExceptionContinuousSingle(config: DataAnalysisConfig) : BaseExceptionContinuous(config) { |
| | | abstract class BaseExceptionContinuousSingle<V : BaseAnalysisConfig, Y : BaseExceptionResult>(config: V) : |
| | | BaseExceptionContinuous<V, Y>(config) { |
| | | |
| | | override fun onNextData(data: BaseRealTimeData) { |
| | | val isContinue = isContinuous(lastData, data) |
| | |
| | | it.startData = data |
| | | } |
| | | // 夿ç¸é»æ°æ®æ¯å¦è¿ç»å¹¶ä¸æ¯å¦æ»¡è¶³å¼å¸¸å¤æ |
| | | if (!isContinue) { |
| | | if (!isContinue || needCut(it)) { |
| | | checkResult(s) |
| | | it.refreshAfterCheckResult(data) |
| | | } else { |
| | | if (hasException[f] == true) { |
| | | // ä¿®æ¹äºèµ·å§æ°æ®çä½ç½®,åæ´ä¸ºåºç°å¼å¸¸ç该å¼,è䏿¯åæ¥çåºç°å¼å¸¸çæ°æ®çåä¸ä¸ªå¼ |
| | | // ä¿®æ¹äºèµ·å§æ°æ®çä½ç½®,åæ´ä¸ºåºç°å¼å¸¸ç该å¼,è䏿¯åæ¥çåºç°å¼å¸¸æ°æ®çåä¸ä¸ªå¼ |
| | | if (!it.existException) { |
| | | it.sIndex = it.eIndex |
| | | it.startData = data |
| | |
| | | } |
| | | } |
| | | } |
| | | // repeat(config.factorCount) { i -> |
| | | // eIndex[i]++ |
| | | // if (lastData == null) { |
| | | // startData[i] = data |
| | | // } |
| | | // // 夿ç¸é»æ°æ®æ¯å¦è¿ç»å¹¶ä¸æ¯å¦æ»¡è¶³å¼å¸¸å¤æ |
| | | // if (!isContinue) { |
| | | // checkResult() |
| | | // sIndex[i] = eIndex[i] |
| | | // startData[i] = data |
| | | // } else { |
| | | // if (hasException[i]) { |
| | | // // ä¿®æ¹äºèµ·å§æ°æ®çä½ç½®,åæ´ä¸ºåºç°å¼å¸¸ç该å¼,è䏿¯åæ¥çåºç°å¼å¸¸çæ°æ®çåä¸ä¸ªå¼ |
| | | // if (!existException[i]) { |
| | | // sIndex[i] = eIndex[i] |
| | | // startData[i] = data |
| | | // } |
| | | // existException[i] = true |
| | | // } else { |
| | | // checkResult() |
| | | // } |
| | | // } |
| | | // } |
| | | lastData = data |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.flightfeather.uav.biz.dataanalysis |
| | | |
| | | /** |
| | | * å¼å¸¸ç»æåºç±» |
| | | * @date 2025/5/13 |
| | | * @author feiyu02 |
| | | */ |
| | | abstract class BaseExceptionResult { |
| | | } |
| | |
| | | |
| | | var running = false |
| | | |
| | | private val taskList = mutableListOf<BaseExceptionAnalysis>() |
| | | private val taskList = mutableListOf<BaseExceptionAnalysis<DataAnalysisConfig, ExceptionResult>>() |
| | | |
| | | private fun initTask(config: DataAnalysisConfig) { |
| | | taskList.clear() |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.flightfeather.uav.biz.dataanalysis.exceptiontype |
| | | |
| | | import com.flightfeather.uav.biz.FactorFilter |
| | | import com.flightfeather.uav.biz.dataanalysis.BaseExceptionContinuous |
| | | import com.flightfeather.uav.biz.dataanalysis.model.DataAnalysisConfig |
| | | import com.flightfeather.uav.biz.dataanalysis.model.ExceptionResult |
| | | import com.flightfeather.uav.domain.entity.BaseRealTimeData |
| | | |
| | | /** |
| | | * è¿ç»ç±»åçå¼å¸¸åæåºç±»,éç¨äºå½åæ°æ®ä¸ç¸é»æ°æ®ä¹é´æå
³èå
³ç³»çæ
åµ |
| | | * @date 2025/5/13 |
| | | * @author feiyu02 |
| | | */ |
| | | abstract class ExceptionContinuous(config: DataAnalysisConfig) : |
| | | BaseExceptionContinuous<DataAnalysisConfig, ExceptionResult>(config) { |
| | | |
| | | override fun newResult( |
| | | start: BaseRealTimeData, |
| | | end: BaseRealTimeData?, |
| | | factor: FactorFilter.SelectedFactor, |
| | | exceptionData: List<BaseRealTimeData>, |
| | | ): ExceptionResult { |
| | | val eType = getExceptionType() |
| | | return ExceptionResult(start, end, factor, exceptionData, config.mission.missionCode, eType) |
| | | } |
| | | } |
| | |
| | | package com.flightfeather.uav.biz.dataanalysis.exceptiontype |
| | | |
| | | import com.flightfeather.uav.biz.FactorFilter |
| | | import com.flightfeather.uav.biz.dataanalysis.BaseExceptionContinuousSingle |
| | | import com.flightfeather.uav.biz.dataanalysis.model.DataAnalysisConfig |
| | | import com.flightfeather.uav.biz.dataanalysis.model.ExceptionResult |
| | | import com.flightfeather.uav.biz.dataanalysis.model.ExceptionType |
| | | import com.flightfeather.uav.domain.entity.BaseRealTimeData |
| | | import com.flightfeather.uav.socket.eunm.FactorType |
| | |
| | | * æ°æ®è¶
æ å¼å¸¸åæ |
| | | */ |
| | | @Deprecated("åè¶
æ å¤å®é»è¾è®¾å®çè¶
æ å¼ææ¼æ´ï¼") |
| | | class ExceptionDataExceed(config: DataAnalysisConfig) : BaseExceptionContinuousSingle(config) { |
| | | class ExceptionDataExceed(config: DataAnalysisConfig) : |
| | | BaseExceptionContinuousSingle<DataAnalysisConfig, ExceptionResult>(config) { |
| | | |
| | | override fun getExceptionType(): ExceptionType = ExceptionType.TYPE2 |
| | | |
| | |
| | | return res |
| | | } |
| | | |
| | | override fun judgeDuration(sIndex: Int, eIndex: Int): Boolean { |
| | | override fun judgeExceptionCount(tag: Tag): Boolean { |
| | | return true |
| | | } |
| | | |
| | | override fun newResult( |
| | | start: BaseRealTimeData, |
| | | end: BaseRealTimeData?, |
| | | factor: FactorFilter.SelectedFactor, |
| | | exceptionData: List<BaseRealTimeData>, |
| | | ): ExceptionResult { |
| | | val eType = getExceptionType() |
| | | return ExceptionResult(start, end, factor, exceptionData, config.mission.missionCode, eType) |
| | | } |
| | | } |
| | |
| | | import com.flightfeather.uav.biz.FactorFilter |
| | | import com.flightfeather.uav.biz.dataanalysis.BaseExceptionAnalysis |
| | | import com.flightfeather.uav.biz.dataanalysis.model.DataAnalysisConfig |
| | | import com.flightfeather.uav.biz.dataanalysis.model.ExceptionResult |
| | | import com.flightfeather.uav.biz.dataanalysis.model.ExceptionType |
| | | import com.flightfeather.uav.domain.entity.BaseRealTimeData |
| | | import com.flightfeather.uav.socket.eunm.FactorType |
| | |
| | | /** |
| | | * æ»å¨å¹³åå¼çªåå¼å¸¸ |
| | | */ |
| | | class ExceptionSlideAverage(config: DataAnalysisConfig) : BaseExceptionAnalysis(config) { |
| | | class ExceptionSlideAverage(config: DataAnalysisConfig) : |
| | | BaseExceptionAnalysis<DataAnalysisConfig, ExceptionResult>(config) { |
| | | |
| | | private val historyDataList = mutableListOf<BaseRealTimeData>() |
| | | private val tempDataList = mutableListOf<BaseRealTimeData>() |
| | |
| | | } |
| | | |
| | | } |
| | | |
| | | fun newResult( |
| | | start: BaseRealTimeData, |
| | | end: BaseRealTimeData?, |
| | | factor: FactorFilter.SelectedFactor, |
| | | exceptionData: List<BaseRealTimeData>, |
| | | ): ExceptionResult { |
| | | val eType = getExceptionType() |
| | | return ExceptionResult(start, end, factor, exceptionData, config.mission.missionCode, eType) |
| | | } |
| | | } |
| | |
| | | package com.flightfeather.uav.biz.dataanalysis.exceptiontype |
| | | |
| | | import com.flightfeather.uav.biz.dataanalysis.BaseExceptionContinuous |
| | | import com.flightfeather.uav.biz.dataanalysis.model.DataAnalysisConfig |
| | | import com.flightfeather.uav.biz.dataanalysis.model.ExceptionType |
| | | import com.flightfeather.uav.domain.entity.BaseRealTimeData |
| | |
| | | /** |
| | | * é级çªåå¼å¸¸åæ |
| | | */ |
| | | class ExceptionValueMutation(config: DataAnalysisConfig) : BaseExceptionContinuous(config) { |
| | | class ExceptionValueMutation(config: DataAnalysisConfig) : ExceptionContinuous(config) { |
| | | |
| | | /** |
| | | * æ¬å¼å¸¸çè¿ç»åçæ¬¡æ°ä¼æ ¹æ®å¼å¸¸çç¨åº¦åå |
| | |
| | | return res |
| | | } |
| | | |
| | | override fun judgeDuration(sIndex: Int, eIndex: Int): Boolean { |
| | | override fun judgeExceptionCount(tag: Tag): Boolean { |
| | | // é¦ä¸ªæ°æ®æ²¡æåä¸ä¸ªæ°æ®åç
§ï¼ä¸ç®å¼å¸¸å¼ï¼æåä¸ä¸ªæ°æ®æ¯å¤æç»æçæ£å¸¸å¼ï¼å æ¤å¼å¸¸æ°æ®ä¸ªæ°ç计ç®ä¸æ 为sIndexåeIndex |
| | | val sIndex = tag.sIndex |
| | | val eIndex = tag.eIndex - 1 |
| | | |
| | | val b1 = special && (eIndex - sIndex) >= (config.mutationNum / 2) |
| | | val b2 = (eIndex - sIndex) >= config.mutationNum |
| | | special = false |
| | |
| | | package com.flightfeather.uav.biz.dataanalysis.model |
| | | |
| | | import com.flightfeather.uav.biz.FactorFilter |
| | | import com.flightfeather.uav.biz.dataanalysis.BaseAnalysisConfig |
| | | import com.flightfeather.uav.domain.entity.Mission |
| | | |
| | | /** |
| | | * æ°æ®åæé
ç½®åæ° |
| | | */ |
| | | data class DataAnalysisConfig( |
| | | class DataAnalysisConfig( |
| | | // èµ°èªä»»å¡ä¿¡æ¯ |
| | | val mission: Mission, |
| | | // æ°æ®å¼å¸¸é
ç½® |
| | | val exceptionSetting: ExceptionSetting, |
| | | // å åçé |
| | | val factorFilter: FactorFilter, |
| | | ){ |
| | | factorFilter: FactorFilter, |
| | | ) : BaseAnalysisConfig(factorFilter) { |
| | | // è¿ç»çªåæ°æ®ä¸ªæ° |
| | | var mutationNum = 2 |
| | | |
| | | // çªåç |
| | | var mutationRate = .5 |
| | | |
| | | // æ±æ»å¨å¹³åå¼çæ°æ®ç»ä¸ªæ° |
| | | var changeTrendGroup = 12 |
| | | |
| | | // æ»å¨å¹³åå¼è¿ç» |
| | | var changeTrendInterval = 12 |
| | | var changeTrendRate = .2 |
| | | |
| | | // æ»å¨å¹³åå¼ååçå¼å¸¸è¿ç»æ¬¡æ° |
| | | var changeTrendTimes = 3 |
| | | |
| | |
| | | package com.flightfeather.uav.biz.dataanalysis.model |
| | | |
| | | import com.flightfeather.uav.biz.FactorFilter |
| | | import com.flightfeather.uav.biz.dataanalysis.BaseExceptionResult |
| | | import com.flightfeather.uav.common.utils.DateUtil |
| | | 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.lightshare.bean.DataVo |
| | | import com.flightfeather.uav.socket.eunm.FactorType |
| | | import java.math.BigDecimal |
| | | import java.util.* |
| | | |
| | | /** |
| | | * å¼å¸¸ç»æ |
| | | */ |
| | | open class ExceptionResult { |
| | | open class ExceptionResult(): BaseExceptionResult() { |
| | | var missionCode: String? = null |
| | | var deviceCode: String? = null |
| | | var exception: String? = null |
| | |
| | | // ç¸å
³ä¼ä¸åç§°ï¼åç§°ä¹é´;åéï¼ |
| | | var relatedSceneName: List<String>? = null |
| | | var relatedSceneList: List<SceneInfo?>? = null |
| | | // å¼å¸¸æ°æ®ï¼å¤´å°¾å¯è½å
å«ä¸å®éçåç§» |
| | | // å¼å¸¸æ°æ® |
| | | var dataList: MutableList<BaseRealTimeData> = mutableListOf() |
| | | var dataVoList: List<DataVo>? = null |
| | | |
| | | constructor( |
| | | start: BaseRealTimeData, |
| | | end: BaseRealTimeData?, |
| | | factor: FactorFilter.SelectedFactor, |
| | | exceptionData: List<BaseRealTimeData>, |
| | | missionCode: String?, |
| | | eType: ExceptionType, |
| | | ) : this() { |
| | | this.missionCode = missionCode |
| | | deviceCode = start.deviceCode |
| | | exception = eType.des |
| | | exceptionType = eType.value |
| | | factorId = factor.main.value |
| | | factorName = factor.main.des |
| | | subFactorId = factor.subs.map { it.value } |
| | | subFactorName = factor.subs.map { it.des } |
| | | selectedFactor = factor |
| | | startDate = start.dataTime |
| | | endDate = end?.dataTime |
| | | startTime = DateUtil.instance.dateToString(start.dataTime, DateUtil.DateStyle.HH_MM_SS) |
| | | endTime = DateUtil.instance.dateToString(end?.dataTime, DateUtil.DateStyle.HH_MM_SS) ?: startTime |
| | | startData = start.getByFactorType(factor.main) |
| | | endData = end?.getByFactorType(factor.main) ?: startData |
| | | |
| | | val avgData = exceptionData.avg() |
| | | // æ±åæ±¡ææ°æ®çä¸å¿åæ |
| | | longitude = avgData.longitude |
| | | latitude = avgData.latitude |
| | | // æ±å主污æå åçåå¼åèå´ |
| | | val s = dataSummary(exceptionData, factor.main) |
| | | avg = s.first |
| | | min = s.second |
| | | max = s.third |
| | | |
| | | exceptionData.forEach { dataList.add(it) } |
| | | } |
| | | |
| | | private fun dataSummary(exceptionData: List<BaseRealTimeData?>, factorType: FactorType): Triple<Float, Float, Float> { |
| | | var min = -1f |
| | | var max = -1f |
| | | var total = 0f |
| | | var count = 0 |
| | | exceptionData.forEach { |
| | | val value = it?.getByFactorType(factorType) ?: return@forEach |
| | | if (min == -1f || min > value) { |
| | | min = value |
| | | } |
| | | if (max == -1f || max < value) { |
| | | max = value |
| | | } |
| | | total += value |
| | | count++ |
| | | } |
| | | val avg = if (count == 0) 0f else total / count |
| | | return Triple(avg, min, max) |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.flightfeather.uav.biz.sourcetrace |
| | | |
| | | import com.flightfeather.uav.biz.FactorFilter |
| | | import com.flightfeather.uav.biz.dataanalysis.BaseAnalysisConfig |
| | | |
| | | /** |
| | | * 宿¶èµ°èªæ±¡ææº¯æºè®¡ç®åæ° |
| | | * @date 2025/5/13 |
| | | * @author feiyu02 |
| | | */ |
| | | class RealTimeAnalysisConfig( |
| | | // å åçé |
| | | factorFilter: FactorFilter, |
| | | ) : BaseAnalysisConfig(factorFilter) { |
| | | |
| | | // éå®è·ç¦»å
ï¼åä½ï¼ç±³ï¼ |
| | | var distanceLimit = 1000 |
| | | |
| | | // é宿¶é´å
ï¼åä½ï¼åéï¼ |
| | | var timeLimit = 2 |
| | | |
| | | // çªåæ°æ®ä¸ªæ° |
| | | var mutationNum = 3 |
| | | |
| | | // çªåç |
| | | var mutationRate = .2 |
| | | |
| | | // æº¯æºæææå¤§é£éï¼5åéä¸è¶
è¿2å
¬éçé£éï¼æå®ï¼ |
| | | var sourceTraceWindSpeedLimit = 6.7 |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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.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.domain.entity.BaseRealTimeData |
| | | 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.socket.handler.UnderwayWebSocketServerHandler |
| | | import com.google.gson.Gson |
| | | |
| | | /** |
| | | * 宿¶èµ°èªæ±¡ææº¯æº |
| | | * @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) |
| | | |
| | | private val taskList = mutableListOf<BaseExceptionAnalysis<RealTimeAnalysisConfig, RealTimeExceptionResult>>() |
| | | |
| | | private fun initTask(config: RealTimeAnalysisConfig) { |
| | | taskList.clear() |
| | | taskList.apply { |
| | | add(RealTimeExceptionValueMutation(config){ exceptionCallback(it)}) |
| | | } |
| | | } |
| | | |
| | | init { |
| | | initTask(config) |
| | | } |
| | | |
| | | // 计ç®åå²ä»»å¡ |
| | | fun addOneData(data: BaseRealTimeData) { |
| | | taskList |
| | | |
| | | } |
| | | |
| | | private fun exceptionCallback(ex: RealTimeExceptionResult) { |
| | | if (sourceTrace(ex, config)) { |
| | | underwayWebSocketServerHandler.broadcast(GsonUtils.gson.toJson(ex)) |
| | | } |
| | | } |
| | | |
| | | private fun sourceTrace(ex: RealTimeExceptionResult, config: RealTimeAnalysisConfig):Boolean { |
| | | val avgData = ex.dataList.avg() |
| | | if (avgData.windSpeed!! > config.sourceTraceWindSpeedLimit) { |
| | | return false |
| | | } |
| | | |
| | | // åä¸é´ç¹ä½ä¸ºååæº¯æºçèµ·ç¹ |
| | | val midData = ex.dataList[ex.dataList.size / 2] |
| | | |
| | | // avgData.longitude |
| | | // avgData.latitude |
| | | // avgData.windDirection |
| | | return false |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.flightfeather.uav.biz.sourcetrace.exceptiontype |
| | | |
| | | import com.flightfeather.uav.biz.FactorFilter |
| | | import com.flightfeather.uav.biz.dataanalysis.BaseExceptionContinuous |
| | | import com.flightfeather.uav.biz.dataanalysis.model.ExceptionResult |
| | | import com.flightfeather.uav.biz.sourcetrace.RealTimeAnalysisConfig |
| | | import com.flightfeather.uav.biz.sourcetrace.model.RealTimeExceptionResult |
| | | import com.flightfeather.uav.domain.entity.BaseRealTimeData |
| | | |
| | | // å¼å¸¸æ°æ®çæåè°ç±» |
| | | typealias NewExceptionCallback = (ex: RealTimeExceptionResult) -> Unit |
| | | /** |
| | | * |
| | | * @date 2025/5/13 |
| | | * @author feiyu02 |
| | | */ |
| | | abstract class RealTimeExceptionContinuous(config: RealTimeAnalysisConfig) : |
| | | BaseExceptionContinuous<RealTimeAnalysisConfig, RealTimeExceptionResult>(config) { |
| | | |
| | | constructor(config: RealTimeAnalysisConfig, callback: NewExceptionCallback) : this(config){ |
| | | this.callback = callback |
| | | } |
| | | |
| | | var callback: NewExceptionCallback? = null |
| | | |
| | | override fun newResult( |
| | | start: BaseRealTimeData, |
| | | end: BaseRealTimeData?, |
| | | factor: FactorFilter.SelectedFactor, |
| | | exceptionData: List<BaseRealTimeData>, |
| | | ): RealTimeExceptionResult { |
| | | val eType = getExceptionType() |
| | | return RealTimeExceptionResult(start, end, factor, exceptionData, eType) |
| | | } |
| | | |
| | | override fun onNewException(tag: Tag, factor: FactorFilter.SelectedFactor) { |
| | | super.onNewException(tag, factor) |
| | | callback?.let { func -> |
| | | val exc = resultList.last() |
| | | func.invoke(exc) |
| | | } |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.flightfeather.uav.biz.sourcetrace.exceptiontype |
| | | |
| | | import com.flightfeather.uav.biz.FactorFilter |
| | | import com.flightfeather.uav.biz.dataanalysis.model.ExceptionType |
| | | import com.flightfeather.uav.biz.sourcetrace.RealTimeAnalysisConfig |
| | | import com.flightfeather.uav.common.utils.MapUtil |
| | | import com.flightfeather.uav.domain.entity.BaseRealTimeData |
| | | import com.flightfeather.uav.socket.eunm.FactorType |
| | | import java.time.Duration |
| | | import java.time.LocalDateTime |
| | | import java.time.ZoneId |
| | | |
| | | /** |
| | | * é级çªåå¼å¸¸æº¯æº |
| | | * @date 2025/5/13 |
| | | * @author feiyu02 |
| | | */ |
| | | class RealTimeExceptionValueMutation : RealTimeExceptionContinuous { |
| | | |
| | | constructor(config: RealTimeAnalysisConfig) : super(config) |
| | | |
| | | constructor(config: RealTimeAnalysisConfig, callback: NewExceptionCallback) : super(config, callback) |
| | | |
| | | /** |
| | | * æ¬å¼å¸¸çè¿ç»åçæ¬¡æ°ä¼æ ¹æ®å¼å¸¸çç¨åº¦åå |
| | | * å½çªåçé级è¶
è¿è®¾å®å¼1åæ¶,è¿ç»åçæ¬¡æ°è¦æ±åå°1å |
| | | */ |
| | | private var special = false |
| | | |
| | | override fun getExceptionType(): ExceptionType { |
| | | return ExceptionType.TYPE4 |
| | | } |
| | | |
| | | override fun judgeException(p: BaseRealTimeData?, n: BaseRealTimeData): MutableMap<FactorType, Boolean> { |
| | | val res = mutableMapOf<FactorType, Boolean>() |
| | | config.factorFilter.mainList().forEach { f -> |
| | | if (p?.getByFactorType(f) == null || n.getByFactorType(f) == null) { |
| | | res[f] = (false) |
| | | return@forEach |
| | | } |
| | | val pValue = p.getByFactorType(f)!! |
| | | val nValue = n.getByFactorType(f)!! |
| | | // 计ç®åä¸ä¸ªæ°æ®ç¸æ¯äºåä¸ä¸ªæ°æ®çååç |
| | | val r = (nValue - pValue) / pValue |
| | | // å½ååçä¸ºæ£æ°ï¼å³æ°æ®ä¸åæ¶ï¼ï¼ä¸å¤§äºè®¾å®å¼æ¶ï¼è®¤ä¸ºæ¯å¼å¸¸æ
åµ |
| | | val b1 = r >= (2 * config.mutationRate) |
| | | val b2 = r >= config.mutationRate |
| | | if (b1) special = true |
| | | res[f] = (b1 || b2) |
| | | } |
| | | |
| | | return res |
| | | } |
| | | |
| | | override fun judgeExceptionCount(tag: Tag): Boolean { |
| | | // é¦ä¸ªæ°æ®æ²¡æåä¸ä¸ªæ°æ®åç
§ï¼ä¸ç®å¼å¸¸å¼ï¼æåä¸ä¸ªæ°æ®æ¯å¤æç»æçæ£å¸¸å¼ï¼å æ¤å¼å¸¸æ°æ®ä¸ªæ°ç计ç®ä¸æ 为sIndexåeIndex |
| | | val sIndex = tag.sIndex |
| | | val eIndex = tag.eIndex - 1 |
| | | |
| | | val b1 = special && (eIndex - sIndex) >= (config.mutationNum / 2) |
| | | val b2 = (eIndex - sIndex) >= config.mutationNum |
| | | special = false |
| | | return b1 || b2 |
| | | } |
| | | |
| | | override fun needCut(tag: Tag): Boolean { |
| | | // æç
§æ¶é¿åè·ç¦»éå¶å°å¼å¸¸æªå |
| | | if (tag.exceptionData.isEmpty()) return false |
| | | |
| | | val se = tag.exceptionData.first() |
| | | val ee = tag.exceptionData.last() |
| | | |
| | | val sTime = LocalDateTime.ofInstant(se.dataTime?.toInstant(), ZoneId.systemDefault()) |
| | | val eTime = LocalDateTime.ofInstant(ee.dataTime?.toInstant(), ZoneId.systemDefault()) |
| | | val duration = Duration.between(sTime, eTime).toMinutes() |
| | | // æ°æ®éæ ·çæ¶é¿è¶
è¿éå¶æ¶ï¼éè¦æªå |
| | | val b1 = duration > config.timeLimit |
| | | |
| | | // èµ°èªæ°æ®çè·ç¦»è¶
è¿éå¶æ¶ï¼éè¦æªå |
| | | val b2 = if (se.longitude == null || se.latitude == null || ee.longitude == null || ee.latitude == null) { |
| | | false |
| | | } else { |
| | | val distance = MapUtil.getDistance( |
| | | se.longitude!!.toDouble(), se.latitude!!.toDouble(), ee.longitude!! |
| | | .toDouble(), ee.latitude!!.toDouble() |
| | | ) |
| | | distance > config.distanceLimit |
| | | } |
| | | |
| | | return b1 || b2 |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.flightfeather.uav.biz.sourcetrace.model |
| | | |
| | | import com.flightfeather.uav.biz.FactorFilter |
| | | import com.flightfeather.uav.biz.dataanalysis.BaseExceptionResult |
| | | import com.flightfeather.uav.biz.dataanalysis.model.ExceptionType |
| | | import com.flightfeather.uav.common.utils.DateUtil |
| | | 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.socket.eunm.FactorType |
| | | import java.math.BigDecimal |
| | | |
| | | /** |
| | | * |
| | | * @date 2025/5/13 |
| | | * @author feiyu02 |
| | | */ |
| | | class RealTimeExceptionResult() : BaseExceptionResult() { |
| | | |
| | | var deviceCode: String? = null |
| | | |
| | | var exception: String? = null |
| | | var exceptionType: Int? = null |
| | | |
| | | var factorId: Int? = null |
| | | var factorName: String? = null |
| | | var subFactorId: List<Int>? = null |
| | | var subFactorName: List<String>? = null |
| | | var selectedFactor: FactorFilter.SelectedFactor? = null |
| | | |
| | | var startTime: String? = null |
| | | var endTime: String? = null |
| | | |
| | | var startData: Float? = null |
| | | var endData: Float? = null |
| | | var avg: Float? = null |
| | | var min: Float? = null |
| | | var max: Float? = null |
| | | |
| | | // å¼å¸¸æ°æ®ï¼å¤´å°¾å¯è½å
å«ä¸å®éçåç§» |
| | | var dataList: MutableList<BaseRealTimeData> = mutableListOf() |
| | | |
| | | // ä¸å¿ç¹ç»çº¬åº¦ |
| | | var longitude: BigDecimal? = null |
| | | var latitude: BigDecimal? = null |
| | | |
| | | // 溯æºä¼ä¸ |
| | | var relatedSceneList: List<SceneInfo?>? = null |
| | | |
| | | constructor( |
| | | start: BaseRealTimeData, |
| | | end: BaseRealTimeData?, |
| | | factor: FactorFilter.SelectedFactor, |
| | | exceptionData: List<BaseRealTimeData>, |
| | | eType: ExceptionType, |
| | | ) : this() { |
| | | deviceCode = start.deviceCode |
| | | exception = eType.des |
| | | exceptionType = eType.value |
| | | factorId = factor.main.value |
| | | factorName = factor.main.des |
| | | subFactorId = factor.subs.map { it.value } |
| | | subFactorName = factor.subs.map { it.des } |
| | | selectedFactor = factor |
| | | startTime = DateUtil.instance.dateToString(start.dataTime, DateUtil.DateStyle.HH_MM_SS) |
| | | endTime = DateUtil.instance.dateToString(end?.dataTime, DateUtil.DateStyle.HH_MM_SS) ?: startTime |
| | | startData = start.getByFactorType(factor.main) |
| | | endData = end?.getByFactorType(factor.main) ?: startData |
| | | |
| | | val avgData = exceptionData.avg() |
| | | // æ±åæ±¡ææ°æ®çä¸å¿åæ |
| | | longitude = avgData.longitude |
| | | latitude = avgData.latitude |
| | | // æ±å主污æå åçåå¼åèå´ |
| | | val s = dataSummary(exceptionData, factor.main) |
| | | avg = s.first |
| | | min = s.second |
| | | max = s.third |
| | | |
| | | exceptionData.forEach { dataList.add(it) } |
| | | } |
| | | |
| | | private fun dataSummary( |
| | | exceptionData: List<BaseRealTimeData?>, |
| | | factorType: FactorType, |
| | | ): Triple<Float, Float, Float> { |
| | | var min = -1f |
| | | var max = -1f |
| | | var total = 0f |
| | | var count = 0 |
| | | exceptionData.forEach { |
| | | val value = it?.getByFactorType(factorType) ?: return@forEach |
| | | if (min == -1f || min > value) { |
| | | min = value |
| | | } |
| | | if (max == -1f || max < value) { |
| | | max = value |
| | | } |
| | | total += value |
| | | count++ |
| | | } |
| | | val avg = if (count == 0) 0f else total / count |
| | | return Triple(avg, min, max) |
| | | } |
| | | } |
| | |
| | | package com.flightfeather.uav.common.utils |
| | | |
| | | import com.google.gson.Gson |
| | | import com.google.gson.GsonBuilder |
| | | import com.google.gson.JsonParser |
| | | import java.util.ArrayList |
| | | import java.time.LocalDateTime |
| | | |
| | | /** |
| | | * @author riku |
| | |
| | | */ |
| | | object GsonUtils { |
| | | |
| | | val gson: Gson = GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss") |
| | | .registerTypeAdapter(LocalDateTime::class.java, LocalDateTimeAdapter()) |
| | | .create() |
| | | |
| | | fun getNoteJsonString(jsonString: String, note: String): String { |
| | | if (jsonString.isEmpty()) { |
| | | throw RuntimeException("getNoteJsonString jsonString empty") |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.flightfeather.uav.common.utils; |
| | | |
| | | import com.google.gson.*; |
| | | |
| | | import java.lang.reflect.Type; |
| | | import java.time.LocalDateTime; |
| | | import java.time.format.DateTimeFormatter; |
| | | |
| | | /** |
| | | * LocalDateTimeç±»åçæ¶é´æ ¼å¼åºåååååºååç±» |
| | | * by hc 2024.12.6 |
| | | */ |
| | | public class LocalDateTimeAdapter implements JsonDeserializer<LocalDateTime>, JsonSerializer<LocalDateTime> { |
| | | private final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); |
| | | |
| | | @Override |
| | | public JsonElement serialize(LocalDateTime src, Type typeOfSrc, JsonSerializationContext context) { |
| | | return new JsonPrimitive(dateTimeFormatter.format(src)); |
| | | } |
| | | |
| | | @Override |
| | | public LocalDateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { |
| | | try { |
| | | return LocalDateTime.parse(json.getAsString(), dateTimeFormatter); |
| | | } catch (Exception e) { |
| | | throw new JsonParseException(e); |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | /** |
| | | * è·å两ç»çº¬åº¦é´çè·ç¦» |
| | | * @return è¿å两ç¹é´è·ç¦»ï¼åä½ï¼ç±³ |
| | | */ |
| | | fun getDistance(lng1: Double, lat1: Double, lng2: Double, lat2: Double): Double { |
| | | // lat1 = lat1 || 0; |
| | |
| | | * å¤æåæ ç¹æ¯å¦å¨å¤è¾¹å½¢å
é¨ |
| | | */ |
| | | fun isPointInPolygon(point: Pair<Double, Double>, polygon: List<Pair<Double, Double>>): Boolean { |
| | | if (polygon.size < 4) throw IllegalArgumentException("not a polygon") |
| | | if (polygon.size < 3) throw IllegalArgumentException("not a polygon") |
| | | |
| | | // ä¸å¨åè³èå´å
ï¼åä¸å®ä¸å¨å¤è¾¹å½¢å
|
| | | if (!inBBox(point, polygon)) return false |
| | |
| | | import java.time.ZoneId |
| | | import java.util.* |
| | | import javax.persistence.Column |
| | | import javax.persistence.GeneratedValue |
| | | import javax.persistence.GenerationType |
| | | import javax.persistence.Id |
| | | import kotlin.math.atan |
| | | import kotlin.math.cos |
| | |
| | | */ |
| | | open class BaseRealTimeData { |
| | | @Id |
| | | @GeneratedValue(strategy = GenerationType.IDENTITY) |
| | | var id: Int? = null |
| | | |
| | | @Column(name = "device_code") |
| | |
| | | package com.flightfeather.uav.domain.repository |
| | | |
| | | import com.flightfeather.uav.domain.entity.BaseRealTimeData |
| | | import com.flightfeather.uav.domain.entity.RealTimeData |
| | | import com.flightfeather.uav.lightshare.bean.DataVo |
| | | import com.flightfeather.uav.socket.bean.AirDataPackage |
| | |
| | | */ |
| | | fun savePrepData(dataList: List<RealTimeData>): Int |
| | | |
| | | fun savePrepData2(dataList: List<DataVo>): Int |
| | | fun savePrepData2(dataList: List<DataVo>): List<BaseRealTimeData> |
| | | |
| | | } |
| | |
| | | return count |
| | | } |
| | | |
| | | override fun savePrepData2(dataList: List<DataVo>): Int { |
| | | var count = 0 |
| | | override fun savePrepData2(dataList: List<DataVo>): List<BaseRealTimeData> { |
| | | val res = mutableListOf<BaseRealTimeData>() |
| | | dataList.forEach {vo -> |
| | | when (UWDeviceType.getType(vo.deviceCode)) { |
| | | UWDeviceType.VEHICLE -> { |
| | |
| | | calibration(d, UWDeviceType.VEHICLE) |
| | | /***************************************************************************************************/ |
| | | realTimeDataVehicleMapper.insert(d) |
| | | count++ |
| | | res.add(d) |
| | | } |
| | | UWDeviceType.UAV -> { |
| | | val d = RealTimeDataUav() |
| | |
| | | } |
| | | /***************************************************************************************************/ |
| | | realTimeDataUavMapper.insert(d) |
| | | count++ |
| | | res.add(d) |
| | | } |
| | | UWDeviceType.GRID -> { |
| | | val d = RealTimeDataGrid() |
| | |
| | | // d.h2s = d.h2s?.let { sqrt(it) * 2 } |
| | | /**************************************************************************/ |
| | | realTimeDataGridMapper.insert(d) |
| | | count++ |
| | | res.add(d) |
| | | } |
| | | UWDeviceType.BOAT -> { |
| | | |
| | |
| | | else -> Unit |
| | | } |
| | | } |
| | | return count |
| | | return res |
| | | } |
| | | |
| | | private fun dataTransform(vo: RealTimeData, bean: BaseRealTimeData) { |
| | |
| | | println("å½å页æ°ï¼$page") |
| | | val dataList = res.data ?: emptyList() |
| | | val result = epwDataPrep.mDataPrep2(dataList) |
| | | count += airDataRep.savePrepData2(result) |
| | | count += airDataRep.savePrepData2(result).size |
| | | page++ |
| | | } |
| | | |
| | |
| | | package com.flightfeather.uav.socket |
| | | |
| | | import com.flightfeather.uav.socket.handler.ServerHandler |
| | | import com.flightfeather.uav.socket.handler.UnderwayWebSocketServerHandler |
| | | import com.flightfeather.uav.socket.processor.BaseProcessor |
| | | import io.netty.bootstrap.ServerBootstrap |
| | | import io.netty.channel.ChannelHandler |
| | |
| | | import io.netty.channel.socket.nio.NioServerSocketChannel |
| | | import io.netty.channel.socket.nio.NioSocketChannel |
| | | import io.netty.handler.codec.LineBasedFrameDecoder |
| | | import io.netty.handler.codec.http.HttpObjectAggregator |
| | | import io.netty.handler.codec.http.HttpServerCodec |
| | | import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler |
| | | import io.netty.handler.codec.string.StringDecoder |
| | | import io.netty.handler.codec.string.StringEncoder |
| | | import org.springframework.stereotype.Component |
| | | import java.nio.charset.Charset |
| | | |
| | | /********************************************************************************* |
| | | * èµ°èªçæµæ°æ®socketé¿è¿æ¥æå¡ç«¯ |
| | | * ç¨äºæ¥æ¶è§£æèµ°èªçæµæ°æ®ï¼åç«¯çæµè®¾å¤ç®åå
æ¬è½¦è½½èµ°èªãæ 人æºèµ°èªä»¥åæ 人è¹èµ°èªä¸ç§ç±»å |
| | | * *******************************************************************************/ |
| | | class UnderwaySocketServer { |
| | | @Component |
| | | class UnderwaySocketServer( |
| | | private val underwayWebSocketServerHandler:UnderwayWebSocketServerHandler |
| | | ) { |
| | | |
| | | private val bossGroup = NioEventLoopGroup() |
| | | private val workerGroup = NioEventLoopGroup() |
| | |
| | | |
| | | fun startElectricServer(port: Int, processor: BaseProcessor) { |
| | | electricServer(processor)?.bind(port)?.sync() |
| | | } |
| | | |
| | | fun startWebSocketServer(port: Int, processor: BaseProcessor) { |
| | | webSocketServer(processor)?.bind(port)?.sync() |
| | | } |
| | | |
| | | fun stopServer() { |
| | |
| | | ?.addLast(ServerHandler(processor)) |
| | | } |
| | | }) |
| | | |
| | | /** |
| | | * å¤åæ°èµ°èªæå¡ç«¯ |
| | | */ |
| | | private fun webSocketServer(processor: BaseProcessor):ServerBootstrap? = newServer(object : ChannelInitializer<NioSocketChannel>() { |
| | | override fun initChannel(p0: NioSocketChannel?) { |
| | | p0?.pipeline() |
| | | ?.addLast(HttpServerCodec()) |
| | | ?.addLast(HttpObjectAggregator(65535)) |
| | | ?.addLast(WebSocketServerProtocolHandler("/ws")) |
| | | ?.addLast(underwayWebSocketServerHandler) |
| | | } |
| | | }) |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.flightfeather.uav.socket.handler |
| | | |
| | | import io.netty.channel.ChannelHandlerContext |
| | | import io.netty.channel.ChannelInboundHandlerAdapter |
| | | import java.text.SimpleDateFormat |
| | | import java.util.* |
| | | |
| | | /** |
| | | * socketæ¶æ¯å¤ç积åºç±» |
| | | * @date 2025/5/13 |
| | | * @author feiyu02 |
| | | */ |
| | | abstract class BaseHandler : ChannelInboundHandlerAdapter() { |
| | | |
| | | abstract var tag: String |
| | | |
| | | override fun channelRegistered(ctx: ChannelHandlerContext?) { |
| | | super.channelRegistered(ctx) |
| | | println("------ã${tag}ãIPè¿æ¥ï¼[ip:${ctx?.channel()?.remoteAddress()}] ${ |
| | | SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format( |
| | | Date() |
| | | )}") |
| | | // ctx?.fireChannelActive() |
| | | } |
| | | |
| | | override fun channelActive(ctx: ChannelHandlerContext?) { |
| | | println("------ã${tag}ãIPæ¿æ´»ï¼[ip:${ctx?.channel()?.remoteAddress()}] ${ |
| | | SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format( |
| | | Date() |
| | | )}") |
| | | super.channelActive(ctx) |
| | | } |
| | | |
| | | override fun channelRead(ctx: ChannelHandlerContext?, msg: Any?) { |
| | | super.channelRead(ctx, msg) |
| | | println("------ã${tag}ãæ¶å°çåå§æ°æ®ï¼[ip:${ctx?.channel()?.remoteAddress()}] ${ |
| | | SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format( |
| | | Date() |
| | | )}") |
| | | } |
| | | |
| | | override fun channelReadComplete(ctx: ChannelHandlerContext?) { |
| | | super.channelReadComplete(ctx) |
| | | } |
| | | |
| | | override fun channelInactive(ctx: ChannelHandlerContext?) { |
| | | println("------ã${tag}ãç«¯å£æIP䏿´»å¨ï¼[ip:${ctx?.channel()?.remoteAddress()}] ${ |
| | | SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format( |
| | | Date() |
| | | )}") |
| | | super.channelInactive(ctx) |
| | | } |
| | | |
| | | @Deprecated("Deprecated in Java") |
| | | override fun exceptionCaught(ctx: ChannelHandlerContext?, cause: Throwable?) { |
| | | cause?.printStackTrace() |
| | | ctx?.close() |
| | | } |
| | | } |
ÎļþÃû´Ó src/main/kotlin/com/flightfeather/uav/socket/ServerHandler.kt ÐÞ¸Ä |
| | |
| | | package com.flightfeather.uav.socket |
| | | package com.flightfeather.uav.socket.handler |
| | | |
| | | import com.flightfeather.uav.socket.processor.BaseProcessor |
| | | import io.netty.channel.ChannelHandlerContext |
| | | import io.netty.channel.ChannelInboundHandlerAdapter |
| | | import io.netty.util.AttributeKey |
| | | import org.ietf.jgss.MessageProp |
| | | import java.lang.StringBuilder |
| | | import java.text.SimpleDateFormat |
| | | import java.util.* |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.flightfeather.uav.socket.handler |
| | | |
| | | import io.netty.channel.ChannelHandlerContext |
| | | import io.netty.handler.codec.http.websocketx.TextWebSocketFrame |
| | | import org.springframework.stereotype.Component |
| | | |
| | | /** |
| | | * |
| | | * @date 2025/5/13 |
| | | * @author feiyu02 |
| | | */ |
| | | @Component |
| | | class UnderwayWebSocketServerHandler : BaseHandler() { |
| | | |
| | | private val sessionPool = mutableMapOf<String?, ChannelHandlerContext?>() |
| | | |
| | | override var tag: String = "UAV-WS" |
| | | |
| | | override fun channelRegistered(ctx: ChannelHandlerContext?) { |
| | | super.channelRegistered(ctx) |
| | | // å°è¿æ¥åå¨ |
| | | if (!sessionPool.containsKey(ctx?.name())) { |
| | | sessionPool[ctx?.name()] = ctx |
| | | } |
| | | } |
| | | |
| | | override fun channelRead(ctx: ChannelHandlerContext?, msg: Any?) { |
| | | super.channelRead(ctx, msg) |
| | | |
| | | when (msg) { |
| | | is TextWebSocketFrame->{ |
| | | println(msg.text()) |
| | | ctx?.channel()?.writeAndFlush(msg) |
| | | } |
| | | } |
| | | } |
| | | |
| | | override fun channelInactive(ctx: ChannelHandlerContext?) { |
| | | super.channelInactive(ctx) |
| | | // å°è¿æ¥ç§»é¤ |
| | | if (sessionPool.containsKey(ctx?.name())) { |
| | | sessionPool.remove(ctx?.name()) |
| | | } |
| | | } |
| | | |
| | | fun send() { |
| | | |
| | | } |
| | | |
| | | fun broadcast(msg: String) { |
| | | sessionPool.forEach { t, u -> |
| | | u?.channel()?.writeAndFlush(TextWebSocketFrame(msg)) |
| | | } |
| | | } |
| | | } |
| | |
| | | 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.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.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 |
| | |
| | | */ |
| | | |
| | | @Component |
| | | class UnderwayProcessor : BaseProcessor() { |
| | | class UnderwayProcessor( |
| | | private val airDataRep: AirDataRep, |
| | | private val realTimeDataRep: RealTimeDataRep, |
| | | private val locationRoadNearby: LocationRoadNearby, |
| | | private val segmentInfoRep: SegmentInfoRep, |
| | | private val underwayWebSocketServerHandler: UnderwayWebSocketServerHandler, |
| | | ) : BaseProcessor() { |
| | | |
| | | companion object { |
| | | private lateinit var instance: UnderwayProcessor |
| | | |
| | | private const val TAG = "UAV" |
| | | } |
| | | |
| | | @Autowired |
| | | lateinit var airDataRep: AirDataRep |
| | | |
| | | private val airDataDecoder = AirDataDecoder.instance |
| | | private val dataPackageDecoder = DataPackageDecoder() |
| | |
| | | // æ°æ®é¢å¤ç彿° |
| | | private val dataProcessMap = mutableMapOf<String?, EPWDataPrep>() |
| | | |
| | | @PostConstruct |
| | | fun init() { |
| | | instance = this |
| | | } |
| | | // 宿¶èµ°èªæ±¡ææº¯æºå¤çå¨ |
| | | private val realTimeExceptionAnalysisController = |
| | | RealTimeExceptionAnalysisController( |
| | | realTimeDataRep, |
| | | locationRoadNearby, |
| | | segmentInfoRep, |
| | | underwayWebSocketServerHandler, |
| | | 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() |
| | | ) |
| | | |
| | | override var tag: String = "èµ°èªçæµ" |
| | | |
| | |
| | | //ä¿å |
| | | deviceSession.saveDevice(packageData.deviceCode, ctx) |
| | | saveToTxt(msg) |
| | | saveToDataBase(packageData) |
| | | saveToDataBase(packageData)?.takeIf { it.isNotEmpty() }?.get(0)?.let { |
| | | // å°èµ°èªæ°æ®ä¼ å
¥å¼å¸¸å¤çå¨ |
| | | realTimeExceptionAnalysisController.addOneData(it) |
| | | } |
| | | |
| | | } else { |
| | | println("------${TAG}æ°æ®BCCæ ¡éªå¤±è´¥ï¼èå¼ [${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}]") |
| | | } |
| | |
| | | /** |
| | | * ä¿åè³æ°æ®åº |
| | | */ |
| | | fun saveToDataBase(dataPackage: AirDataPackage) { |
| | | fun saveToDataBase(dataPackage: AirDataPackage): List<BaseRealTimeData>? { |
| | | when (dataPackage.commandUnit) { |
| | | AirCommandUnit.AirData.value -> { |
| | | // 以jsonæ ¼å¼åå¨åå§æ°æ® |
| | | instance.airDataRep.saveAirData(dataPackage) |
| | | airDataRep.saveAirData(dataPackage) |
| | | // è¿è¡é¢å¤çåï¼åå¨è³å¯¹åºæ°æ®è¡¨ |
| | | if (!dataProcessMap.containsKey(dataPackage.deviceCode)) { |
| | | // æ¯å°è®¾å¤æåç¬çæ°æ®é¢å¤ç对象 |
| | | dataProcessMap[dataPackage.deviceCode] = EPWDataPrep(UWDeviceType.getType(dataPackage.deviceCode)) |
| | | } |
| | | dataProcessMap[dataPackage.deviceCode]?.run { |
| | | return dataProcessMap[dataPackage.deviceCode]?.run { |
| | | val list = this.mDataPrep2(dataPackage)// æ°æ®å¹³æ»å¤ç |
| | | instance.airDataRep.savePrepData2(list)// æç
§è®¾å¤ç±»ååå¨è³å¯¹åºæ°æ®è¡¨ |
| | | airDataRep.savePrepData2(list)// æç
§è®¾å¤ç±»ååå¨è³å¯¹åºæ°æ®è¡¨ |
| | | } |
| | | } |
| | | |
| | | else -> return emptyList() |
| | | } |
| | | } |
| | | |
| | |
| | | fun encodeToBytes(msg: String): ByteArray { |
| | | val list = msg.split(" ") |
| | | val bytes = ByteArray(list.size) |
| | | for (i in 0 until list.size) { |
| | | for (i in list.indices) { |
| | | bytes[i] = list[i].toInt(16).toByte() |
| | | } |
| | | |