feiyu02
2025-02-21 dacef58ee7c44dffdd40cb646435c2993ad7a217
1. 新增坐标点是否在多边形内部的判定算法并测试
已修改5个文件
166 ■■■■ 文件已修改
src/main/kotlin/com/flightfeather/uav/biz/satellite/SatelliteGridManage.kt 76 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/service/SatelliteDataCalculateService.kt 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/SatelliteDataCalculateServiceImpl.kt 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/test/kotlin/com/flightfeather/uav/UAVApplicationTests.kt 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/test/kotlin/com/flightfeather/uav/lightshare/service/impl/SatelliteDataCalculateServiceImplTest.kt 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/biz/satellite/SatelliteGridManage.kt
@@ -1,10 +1,7 @@
package com.flightfeather.uav.biz.satellite
import com.flightfeather.uav.common.utils.MapUtil
import com.flightfeather.uav.domain.entity.BaseRealTimeData
import com.flightfeather.uav.domain.entity.GridCell
import com.flightfeather.uav.domain.entity.GridData
import com.flightfeather.uav.domain.entity.GridDataDetail
import com.flightfeather.uav.domain.entity.*
import kotlin.math.PI
import kotlin.math.sqrt
@@ -20,7 +17,9 @@
    /**
     * 根据正方形网格中心点坐标,计算4个顶点坐标
     * 网格中心点坐标按照从左到右、从上到下的顺序排列
     * @date 2025.1.8
     * @param points 网格中心坐标点数组
     * @return 网格4个顶点经纬度坐标
     */
    fun calGridVertex(points: List<Pair<Double, Double>>): List<GridVertex> {
        // 网格少于2个,则无法绘制
@@ -69,10 +68,11 @@
    /**
     * 拆分网格为细分网格,所有网格应该是相同边长的正方形
     * 根据相似矩形的原理,可以分别按比例得到每个细分网格的经纬度
     * @date 2025.1.17
     * @param gridCellList 原始网格数组
     * @param scale 拆分的系数,例如 2,表示将原有网格按边长的 1/2 拆分成 2 * 2 的4个网格
     * @param groupId 细分后的网格所属的网格组id
     * @return
     * @return 细分网格
     */
    fun splitGrid(gridCellList: List<GridCell?>, scale: Int, groupId:Int): List<GridCell?> {
        if (scale <= 0) throw IllegalArgumentException("网格拆分的数量不能小于1")
@@ -165,9 +165,11 @@
    /**
     * 拆分数据,将原始卫星网格遥测数据映射到对应细分网格上
     * @param subGridCellList 细分网格, 按照
     * @date 2025.2.7
     * @param subGridCellList 细分网格
     * @param subGridData 细分网格对应的数据索引
     * @param originGridDataDetailList 细分网格所属网格的原始网格数据
     * @return 映射后的细分网格遥测数据
     */
    fun splitData(
        subGridCellList: List<GridCell?>, subGridData: GridData, originGridDataDetailList: List<GridDataDetail?>
@@ -217,21 +219,71 @@
    }
    /**
     * 数据融合
     * 走航数据和卫星网格融合
     * 数据融合采用均值方式统计(暂时)
     * @date 2025.2.7
     * @param realTimeDataList 待融合的走航监测数据
     * @param gridData 融合后的数据组索引
     * @param gridCellList 待融合的卫星网格
     * @return 融合后的网格监测数据
     */
    fun dataFusion(realTimeDataList:List<BaseRealTimeData>, gridData: GridData, gridCellList: List<GridCell?>) {
        // 遍历走航监测数据,计算每个点所在网格,并形成网格值
    fun dataFusion(
        realTimeDataList: List<BaseRealTimeData>,
        gridData: GridData,
        gridCellList: List<GridCell?>,
    ): List<GridDataDetail> {
        // 遍历走航监测数据,计算每个点所在网格
        val dataMap = mutableMapOf<GridCell, MutableList<BaseRealTimeData>>()
        realTimeDataList.forEach {
            it.longitude
            it.latitude
            gridCellList.forEach {
            if (it.longitude == null || it.latitude == null) return@forEach
            searchGirdIn(it.longitude!!.toDouble() to it.latitude!!.toDouble(), gridCellList)?.let { cell ->
                if (!dataMap.containsKey(cell)) {
                    dataMap[cell] = mutableListOf()
            }
                dataMap[cell]?.add(it)
        }
    }
        // 统计每个网格中的均值
        // Fixme 2025.2.20 暂时默认以均值方式统计,后续调整为多种方式并支持用户选择
        val gridDataDetailList = mutableListOf<GridDataDetail>()
        dataMap.forEach { (k, v) ->
            val avgData = v.avg()
            val dataDetail = GridDataDetail().apply {
                dataId = gridData.id
                groupId = k.groupId
                cellId = k.cellIndex
                pm25 = avgData.pm25
                rank
            }
            gridDataDetailList.add(dataDetail)
        }
        return gridDataDetailList
    }
    /**
     * 计算坐标点在哪个卫星网格内
     * @date 2025.2.14
     * @param point 坐标点
     * @param gridCellList 卫星网格
     */
    fun searchGirdIn(point: Pair<Double, Double>, gridCellList: List<GridCell?>): GridCell? {
        for (i in gridCellList.indices) {
            val gridCell = gridCellList[i] ?: continue
            val polygon = listOf(
                gridCell.point1Lon.toDouble() to gridCell.point1Lat.toDouble(),
                gridCell.point2Lon.toDouble() to gridCell.point2Lat.toDouble(),
                gridCell.point3Lon.toDouble() to gridCell.point3Lat.toDouble(),
                gridCell.point4Lon.toDouble() to gridCell.point4Lat.toDouble(),
            )
            if (MapUtil.isPointInPolygon(point, polygon)) {
                return gridCell
            }
        }
        return null
    }
}
src/main/kotlin/com/flightfeather/uav/lightshare/service/SatelliteDataCalculateService.kt
@@ -29,4 +29,11 @@
     * @param dataId 数据索引id
     */
    fun splitData(groupId: Int, dataId:Int): List<GridDataDetail?>
    /**
     * 将走航监测数据和卫星网格进行融合计算
     * @param missionCode
     * @param groupId
     */
    fun dataFusion(missionCode: String, groupId: Int): List<GridDataDetail?>
}
src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/SatelliteDataCalculateServiceImpl.kt
@@ -6,6 +6,8 @@
import com.flightfeather.uav.domain.entity.GridData
import com.flightfeather.uav.domain.entity.GridDataDetail
import com.flightfeather.uav.domain.entity.GridGroup
import com.flightfeather.uav.domain.repository.MissionRep
import com.flightfeather.uav.domain.repository.RealTimeDataRep
import com.flightfeather.uav.domain.repository.SatelliteGridRep
import com.flightfeather.uav.lightshare.eunm.GridType
import com.flightfeather.uav.lightshare.eunm.SatelliteDataType
@@ -22,7 +24,11 @@
 * @author feiyu02
 */
@Service
class SatelliteDataCalculateServiceImpl(private val satelliteGridRep: SatelliteGridRep) : SatelliteDataCalculateService {
class SatelliteDataCalculateServiceImpl(
    private val satelliteGridRep: SatelliteGridRep,
    private val realTimeDataRep: RealTimeDataRep,
    private val missionRep: MissionRep,
) : SatelliteDataCalculateService {
    override fun calGridVertex(groupId: Int): List<GridCell?> {
@@ -125,4 +131,28 @@
        return subGridDataDetailList
    }
    @Transactional
    override fun dataFusion(missionCode: String, groupId: Int): List<GridDataDetail?> {
        // 查询走航任务及对应走航监测数据
        val mission = missionRep.findOne(missionCode) ?: throw BizException("任务不存在")
        val data = realTimeDataRep.fetchData(mission)
        // 创建融合数据索引对象
        val newGridData = GridData().apply {
            this.groupId = groupId
            dataTime = mission.startTime
            type = SatelliteDataType.Monitor.value.toByte()
        }
        satelliteGridRep.insertGridData(newGridData)
        // 查询网格单元格信息
        val gridCellList = satelliteGridRep.fetchGridCell(groupId)
        // 将走航数据和卫星网格进行融合计算
        val gridDataDetailList = SatelliteGridManage.dataFusion(data, newGridData, gridCellList)
        satelliteGridRep.insertGridDataDetail(gridDataDetailList)
        return gridDataDetailList
    }
}
src/test/kotlin/com/flightfeather/uav/UAVApplicationTests.kt
@@ -18,27 +18,6 @@
    @Autowired
    lateinit var realTimeDataService: RealTimeDataService
    @Autowired
    lateinit var gridDataDetailMapper: GridDataDetailMapper
    /**
     * 刷新每组数据的数据排名
     */
    @Test
    fun refreshDataRank() {
        for (i in 29..39) {
            val dataDetailList = gridDataDetailMapper.selectByExample(Example(GridDataDetail::class.java).apply {
                createCriteria().andEqualTo("dataId", i)
                orderBy("pm25").desc()
            })
            dataDetailList.forEachIndexed { i, d ->
                d?.rank = i + 1
                gridDataDetailMapper.updateByPrimaryKey(d)
            }
            println("finish --${i}")
        }
    }
    @Test
    fun contextLoads() {
    }
src/test/kotlin/com/flightfeather/uav/lightshare/service/impl/SatelliteDataCalculateServiceImplTest.kt
@@ -1,11 +1,14 @@
package com.flightfeather.uav.lightshare.service.impl
import com.flightfeather.uav.domain.entity.GridDataDetail
import com.flightfeather.uav.domain.mapper.GridDataDetailMapper
import com.flightfeather.uav.lightshare.service.SatelliteDataCalculateService
import org.junit.Test
import org.junit.runner.RunWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.junit4.SpringRunner
import tk.mybatis.mapper.entity.Example
@RunWith(SpringRunner::class)
@@ -14,6 +17,27 @@
    @Autowired
    lateinit var satelliteDataCalculateService: SatelliteDataCalculateService
    @Autowired
    lateinit var gridDataDetailMapper: GridDataDetailMapper
    /**
     * 刷新每组数据的数据排名
     */
    @Test
    fun refreshDataRank() {
        for (i in 51..51) {
            val dataDetailList = gridDataDetailMapper.selectByExample(Example(GridDataDetail::class.java).apply {
                createCriteria().andEqualTo("dataId", i)
                orderBy("pm25").desc()
            })
            dataDetailList.forEachIndexed { index, d ->
                d?.rank = index + 1
                gridDataDetailMapper.updateByPrimaryKey(d)
            }
            println("finish --${i}")
        }
    }
    @Test
    fun splitGrid() {
@@ -26,4 +50,10 @@
        val res = satelliteDataCalculateService.splitData(4, 25)
//        println(res)
    }
    @Test
    fun dataFusion() {
        val res = satelliteDataCalculateService.dataFusion("SH-CN-20241216", 3)
//        println(res)
    }
}