| | |
| | | package com.flightfeather.uav.biz.sourcetrace.model |
| | | |
| | | import com.flightfeather.uav.biz.sourcetrace.config.RTExcWindLevelConfig |
| | | import com.flightfeather.uav.common.net.AMapService |
| | | import com.flightfeather.uav.common.utils.MapUtil |
| | | import com.flightfeather.uav.domain.entity.BaseRealTimeData |
| | | import com.flightfeather.uav.domain.entity.avg |
| | | import kotlin.math.PI |
| | | |
| | | /** |
| | | * 动态溯源污染区域 |
| | | * 通过地图坐标点形成多边形来描述一块污染区域 |
| | | * @date 2025/5/27 |
| | | * @author feiyu02 |
| | | */ |
| | | class PollutedArea { |
| | | class PollutedArea() { |
| | | |
| | | var name: String? = null |
| | | /** |
| | | * 溯源角度可设置 |
| | | */ |
| | | |
| | | constructor( |
| | | exceptionData: List<BaseRealTimeData>, |
| | | config: RTExcWindLevelConfig, |
| | | windLevelCondition: RTExcWindLevelConfig.WindLevelCondition, |
| | | ) : this() { |
| | | distanceType = windLevelCondition.mutationRate.second |
| | | sourceTrace(exceptionData, config, windLevelCondition) |
| | | } |
| | | |
| | | var address: String? = null |
| | | |
| | | // 污染范围区域(经纬度多边形) |
| | | var polygon: List<Pair<Double, Double>>? = null |
| | | |
| | | // 污染可能的发生距离 |
| | | var distanceType: DistanceType? = null |
| | | |
| | | /** |
| | | * 反向溯源 |
| | | */ |
| | | private fun sourceTrace( |
| | | exceptionData: List<BaseRealTimeData>, |
| | | config: RTExcWindLevelConfig, |
| | | windLevelCondition: RTExcWindLevelConfig.WindLevelCondition, |
| | | ) { |
| | | val avgData = if (exceptionData.size == 1) { |
| | | exceptionData.first() |
| | | } else { |
| | | exceptionData.avg() |
| | | } |
| | | |
| | | val pair = avgData.longitude!!.toDouble() to avgData.latitude!!.toDouble() |
| | | |
| | | polygon = calSector( |
| | | avgData.windSpeed!!.toDouble(), |
| | | pair, |
| | | windLevelCondition.mutationRate.second.disRange, |
| | | config.sourceTraceDegOffset |
| | | ) |
| | | |
| | | try { |
| | | val address = AMapService.reGeo(pair) |
| | | this.address = address.township + address.street |
| | | } catch (e: Exception) { |
| | | e.printStackTrace() |
| | | } |
| | | |
| | | } |
| | | |
| | | /** |
| | | * 根据中心点坐标、风向和溯源距离,以及给定的夹角,计算以中心点按照风向向外扩散形成的扇形的点坐标 |
| | | * @param windDir 风向,单位:度 |
| | | * @param center 中心点坐标经纬度 |
| | | * @param distanceRange 溯源距离范围,单位:米 |
| | | * @param defaultDegOffset 扩散偏移角度 |
| | | * @return 多边形顶点坐标集合 |
| | | */ |
| | | private fun calSector( |
| | | windDir: Double, |
| | | center: Pair<Double, Double>, |
| | | distanceRange: Pair<Double, Double>, |
| | | defaultDegOffset: Double = 60.0, |
| | | ): List<Pair<Double, Double>> { |
| | | |
| | | val sDeg = windDir - defaultDegOffset / 2 |
| | | val eDeg = windDir + defaultDegOffset / 2 |
| | | |
| | | val result = mutableListOf<Pair<Double, Double>>() |
| | | |
| | | if (distanceRange.first == .0) { |
| | | result.add(center) |
| | | } else { |
| | | // 从开始角度循环计算坐标点值结束角度,步长1° |
| | | var startDeg = sDeg |
| | | while (startDeg <= eDeg) { |
| | | val p = MapUtil.getPointByLen(center, distanceRange.first, startDeg * PI / 180) |
| | | result.add(p) |
| | | startDeg++ |
| | | } |
| | | } |
| | | |
| | | if (distanceRange.second > .0) { |
| | | // 此处需要从结束角度开始反向循环计算至开始角度,步长1°,使得两组坐标点按顺序排列,可绘制对应的多边形 |
| | | var startDeg = eDeg |
| | | while (startDeg >= sDeg) { |
| | | val p = MapUtil.getPointByLen(center, distanceRange.second, startDeg * PI / 180) |
| | | result.add(p) |
| | | startDeg-- |
| | | } |
| | | } |
| | | |
| | | return result |
| | | } |
| | | } |