feiyu02
2025-09-30 94fee0b511279679b43e210878d3d36e5a14384b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package com.flightfeather.uav.biz.mission
 
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
 
/**
 * 走航任务计算工具
 * @date 2025/8/21
 * @author feiyu02
 */
object MissionUtil {
 
    /**
     * 计算里程数
     */
    fun calKilometres(data: List<BaseRealTimeData>): Double {
        var distance = .0
        var lastValidPoint: BaseRealTimeData? = null
 
        for (point in data) {
            // 跳过无效点
            if (point.longitude == null || point.latitude == null) continue
 
            // 如果存在上一个有效点,则计算距离
            lastValidPoint?.let { prevPoint ->
                distance += MapUtil.getDistance(
                    prevPoint.longitude!!.toDouble(),
                    prevPoint.latitude!!.toDouble(),
                    point.longitude!!.toDouble(),
                    point.latitude!!.toDouble()
                )
            }
 
            // 更新上一个有效点
            lastValidPoint = point
        }
        return distance
    }
 
    /**
     * 根据轨迹点计算所属区域(乡镇+街道)
     * @param data 走航轨迹点列表
     * @return 区域名称(乡镇+街道),若无法计算则返回null
     */
    @Suppress("UNCHECKED_CAST")
    fun calRegion(data: List<BaseRealTimeData>): String? {
        // 计算所有轨迹点的平均坐标(中心点)
        val avgData = data.avg()
        val pair = avgData.longitude?.toDouble() to avgData.latitude?.toDouble()
        // 若平均坐标无效则返回null
        if (pair.first == null || pair.second == null) return null
        // 将WGS84坐标转换为GCJ02坐标后进行逆地理编码获取地址信息
        val address = AMapService.reGeo(MapUtil.wgs84ToGcj02(pair as Pair<Double, Double>))
        // 返回乡镇和街道名称组合
        return address.township
    }
 
    /**
     * 数据清洗
     * 1. 修复由于硬件设备卡顿导致的数据采样时间不变问题,采用自动累加数据周期的方式修改采样时间
     * @param data 原始数据列表
     * @param period 数据周期,单位:秒
     * @return 清洗后需要修改的数据列表
     */
    fun dataClean(dataList: List<BaseRealTimeData>, period: Long): List<BaseRealTimeData> {
        val cleanedData = mutableListOf<BaseRealTimeData>()
        var errorData: BaseRealTimeData? = null
        dataList.forEachIndexed { index, data ->
            if (index == 0) {
                return@forEachIndexed
            }
            val lastOne = dataList[index - 1]
            if (errorData == null) {
                if (data.dataTime!!.time == lastOne.dataTime!!.time) {
                    data.dataTime?.time = lastOne.dataTime?.time!!.plus(period * 1000)
                    cleanedData.add(data)
                    errorData = lastOne
                }
            } else {
                if (data.dataTime!!.time == errorData!!.dataTime!!.time) {
                    data.dataTime?.time = lastOne.dataTime?.time!!.plus(period * 1000)
                    cleanedData.add(data)
                } else {
                    errorData = null
                }
            }
        }
        return cleanedData
    }
}