feiyu02
2024-07-04 022af485fbd77bc3d6b01f9f779248b3c189dad2
src/main/kotlin/com/flightfeather/uav/common/location/TrackSegment.kt
ÎļþÃû´Ó src/main/kotlin/com/flightfeather/uav/biz/dataprocess/TrackSegment.kt ÐÞ¸Ä
@@ -1,9 +1,11 @@
package com.flightfeather.uav.biz.dataprocess
package com.flightfeather.uav.common.location
import com.flightfeather.uav.common.location.CoordinateUtil
import com.flightfeather.uav.domain.entity.BaseRealTimeData
import java.math.BigDecimal
import kotlin.math.abs
import kotlin.math.atan
import kotlin.math.cos
import kotlin.math.sin
/**
 * èµ°èˆªè½¨è¿¹åˆ†å‰²åˆ†ç±»
@@ -13,10 +15,10 @@
object TrackSegment {
    // åæ ‡ç‚¹é—´æœ€å°è·ç¦»ï¼Œå•位米
    private const val MIN_DISTANCE = 10
    private const val MIN_DISTANCE = 6
    // ä¸¤æ¡ç›´çº¿å¤¹è§’为90度时,认为垂直。实际情况中,角度允许有一定偏差,允许偏差角度
    private const val VERTICAL_OFFSET_DEG = 22.5
    private const val VERTICAL_OFFSET_DEG = 45
    /**
     * æŒ‰ç…§é“路对走航轨迹进行分割
@@ -34,13 +36,13 @@
        val closeList = mutableListOf<BaseRealTimeData>()
        records.add(mutableListOf())
        data.forEachIndexed { i, d ->
            if (records.size == 33) {
            if (records.size == 23) {
                println(records.size)
            }
            var isSame = false
            if (i > 0) {
                // å‰ä¸€ä¸ªæœ‰æ•ˆç›‘测点
                val lastData = data[i - 1]
                var lastData = data[i - 1]
                // ç¡®ä¿ä¸¤ç‚¹åæ ‡åˆæ³•
                if ((lastData.longitude != null && lastData.longitude != BigDecimal.ZERO)
                    && (lastData.latitude != null && lastData.latitude != BigDecimal.ZERO)
@@ -57,6 +59,7 @@
                        // å¦‚果已经有距离过近的点集合,则还需要和第一个点进行距离判断,
                        // è§£å†³å½“车辆行驶速度过低时,连续点的距离都过近导致都判定为同一点的问题
                        val firstCloseData = closeList[0]
//                        lastData = closeList.toList().avg()
                        distance = CoordinateUtil.calculateDistance(
                            firstCloseData.longitude!!.toDouble(), firstCloseData.latitude!!.toDouble(),
                            d.longitude!!.toDouble(), d.latitude!!.toDouble())
@@ -69,27 +72,43 @@
                        )
                        isSame = if (lastDegList.isNotEmpty()) {
                            var bool = true
                            // å‡ºçŽ°è§’åº¦æŽ¥è¿‘åž‚ç›´çŠ¶æ€çš„æ¬¡æ•°
                            var unSameCount = 0
                            // æ¯”较当前方位角和上一组每个方位角的差值是否都处于范围内
                            for (lastDeg in lastDegList) {
                                val diffDeg = abs(deg - lastDeg)
                                if (diffDeg in (90.0 - VERTICAL_OFFSET_DEG)..(90.0 + VERTICAL_OFFSET_DEG)
                                    || diffDeg in (270.0 - VERTICAL_OFFSET_DEG)..(270.0 + VERTICAL_OFFSET_DEG)
                                ) {
                                    unSameCount++
                                }
//                            // å‡ºçŽ°è§’åº¦æŽ¥è¿‘åž‚ç›´çŠ¶æ€çš„æ¬¡æ•°
//                            var unSameCount = 0
//                            // æ¯”较当前方位角和上一组每个方位角的差值是否都处于范围内
//                            for (lastDeg in lastDegList) {
//                                val diffDeg = abs(deg - lastDeg)
//                                if (diffDeg in (90.0 - VERTICAL_OFFSET_DEG)..(90.0 + VERTICAL_OFFSET_DEG)
//                                    || diffDeg in (270.0 - VERTICAL_OFFSET_DEG)..(270.0 + VERTICAL_OFFSET_DEG)
//                                ) {
//                                    unSameCount++
//                                }
//                            }
//                            // å½“接近垂直的角度超过上一组平行角度的一半时,认为从该点轨迹转弯(消除个别坐标点由于定位误差导致的错误影响)
//                            bool = unSameCount < (lastDegList.size / 3 + 1)
                            val avgDeg = avgDegree(lastDegList)
                            val diffDeg = abs(deg - avgDeg)
                            if (diffDeg in (90.0 - VERTICAL_OFFSET_DEG)..(90.0 + VERTICAL_OFFSET_DEG)
                                || diffDeg in (270.0 - VERTICAL_OFFSET_DEG)..(270.0 + VERTICAL_OFFSET_DEG)
                            ) {
                                bool = false
                            }
                            // å½“接近垂直的角度超过上一组平行角度的一半时,认为从该点轨迹转弯(消除个别坐标点由于定位误差导致的错误影响)
                            bool = unSameCount < (lastDegList.size / 3 + 1)
                            // å½“出现转弯点时,清空历史角度,并且舍弃转弯点相对于前一个点的角度(解决一种极端情况,当连续出现转弯点时,当前坐标点会被单独分割为一段)
                            if (!bool) lastDegList.clear()
                            if (!bool) {
                                lastDegList.clear()
                            } else {
                                lastDegList.add(deg)
                            }
                            bool
                        } else {
                            // å½“坐标点形成有效路径时,记录为上一个坐标点
                            lastDegList.add(deg)
                            true
                        }
                        closeList.clear()
                    } else {
                        closeList.add(d)
                        isSame = true
@@ -110,4 +129,40 @@
        return records
    }
    /**
     * æ±‚转向角度的均值
     */
    private fun avgDegree(degList: List<Double>): Double {
        if (degList.isEmpty()) return .0
        //采用单位矢量法求取均值
        var u = .0//东西方位分量总和
        var v = .0//南北方位分量总和
        var c = 0//数据计数
        degList.forEach {
            val r = Math.toRadians(it)
            u += sin(r)
            v += cos(r)
            c++
        }
        val avgU = u / c
        val avgV = v / c
        var a = atan(avgU / avgV)
        a = Math.toDegrees(a)
        /**
         * avgU>0;avgV>0: çœŸå®žè§’度处于第一象限,修正值为+0°
         * avgU>0;avgV<0: çœŸå®žè§’度处于第二象限,修正值为+180°
         * avgU<0;avgV<0: çœŸå®žè§’度处于第三象限,修正值为+180°
         * avgU<0;avgV>0: çœŸå®žè§’度处于第四象限,修正值为+360°
         */
        a += if (avgV > 0) {
            if (avgU > 0) 0 else 360
        } else {
            180
        }
        return a
    }
}