feiyu02
2025-01-23 698f8f0f22af4c66581ce284407e986ca036aec6
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
package com.flightfeather.uav.biz.satellite
 
import com.flightfeather.uav.common.utils.MapUtil
import com.flightfeather.uav.domain.entity.GridCell
import kotlin.math.PI
import kotlin.math.sqrt
 
/**
 * 卫星遥测网格管理
 * 根据网格中心点计算4个顶点坐标
 * 根据已有网格进行细分网格计算
 * @date 2025/1/8
 * @author feiyu02
 */
object SatelliteGridManage {
 
    /**
     * 根据正方形网格中心点坐标,计算4个顶点坐标
     * 网格中心点坐标按照从左到右、从上到下的顺序排列
     * @param points 网格中心坐标点数组
     */
    fun calGridVertex(points: List<Pair<Double, Double>>): List<GridVertex> {
        // 网格少于2个,则无法绘制
        if (points.size < 2) return emptyList()
        // 获取前两个网格
        // Fixme 2025.01.10: 目前先简化逻辑,按照前两个点是左右排布,且点p2在点p1的东边
        val p1 = points[0]
        val p2 = points[1]
        // 两中心点间的角度
        val angle = MapUtil.getAngle(p1.first, p1.second, p2.first, p2.second)
        // 两中心点间的距离
        val dis = MapUtil.getDistance(p1.first, p1.second, p2.first, p2.second)
        // 网格正方形对角线的一半长度
        val halfDiagonal = sqrt((dis / 2) * (dis / 2) * 2)
        // 计算首个正方形各顶点相对于中心点的角度,得到正方形各顶点的坐标
        // 4个顶点按照从左上角开始,顺时针方向的顺序进行排列
        val angle1 = MapUtil.plusAngle(angle, 45.0 + 180.0)
        val gp1 = MapUtil.getPointByLen(p1, halfDiagonal, angle1 * PI / 180)
        val angle2 = MapUtil.plusAngle(angle1, 90.0)
        val gp2 = MapUtil.getPointByLen(p1, halfDiagonal, angle2 * PI / 180)
        val angle3 = MapUtil.plusAngle(angle2, 90.0)
        val gp3 = MapUtil.getPointByLen(p1, halfDiagonal, angle3 * PI / 180)
        val angle4 = MapUtil.plusAngle(angle3, 90.0)
        val gp4 = MapUtil.getPointByLen(p1, halfDiagonal, angle4 * PI / 180)
        // 计算4个顶点分别与中心点的经纬度差值
        val dx1 = gp1.first - p1.first
        val dy1 = gp1.second - p1.second
        val dx2 = gp2.first - p1.first
        val dy2 = gp2.second - p1.second
        val dx3 = gp3.first - p1.first
        val dy3 = gp3.second - p1.second
        val dx4 = gp4.first - p1.first
        val dy4 = gp4.second - p1.second
 
        // 得到所有正方形网格的4个顶点信息
        return points.map { p ->
            GridVertex(
                p.first + dx1, p.second + dy1,
                p.first + dx2, p.second + dy2,
                p.first + dx3, p.second + dy3,
                p.first + dx4, p.second + dy4,
            )
        }
    }
 
    /**
     * 拆分网格为细分网格,所有网格应该是相同边长的正方形
     * 根据相似矩形的原理,可以分别按比例得到每个细分网格的经纬度
     * @param gridCellList 原始网格数组
     * @param scale 拆分的系数,例如 2,表示将原有网格按边长的 1/2 拆分成 2 * 2 的4个网格
     * @param groupId 细分后的网格所属的网格组id
     * @return
     */
    fun splitGrid(gridCellList: List<GridCell?>, scale: Int, groupId:Int): List<GridCell?> {
        if (scale <= 0) throw IllegalArgumentException("网格拆分的数量不能小于1")
        // 拆分系数为1,则表示不拆分
        if (scale == 1) return gridCellList
        if (gridCellList.isEmpty()) return emptyList()
 
        val newGridCellList = mutableListOf<GridCell>()
 
        // 根据函数[calGridVertex]生成的网格4个顶点坐标,以上北下南左西右东方向为标准
        // 计算首个网格中心坐标点分别和4个顶点的经纬度差值
        val p = gridCellList.find { it != null }!!
        // (通过近似平面坐标系的方式)根据单个原始网格的4个顶点坐标,分别确定以下三组坐标点之间的经纬度单位偏移量
        val p1 = p.point1Lon to p.point1Lat
        val p2 = p.point2Lon to p.point2Lat
        val p3 = p.point3Lon to p.point3Lat
        val p4 = p.point4Lon to p.point4Lat
        // p1、p3的经纬度单位差值
        val dx1 = (p3.first - p1.first) / scale.toBigDecimal()
        val dy1 = (p3.second - p1.second) / scale.toBigDecimal()
        // p1、p2的经纬度单位差值
        val dx2 = (p2.first - p1.first) / scale.toBigDecimal()
        val dy2 = (p2.second - p1.second) / scale.toBigDecimal()
        // p3、p4的经纬度单位差值
        val dx3 = (p4.first - p3.first) / scale.toBigDecimal()
        val dy3 = (p4.second - p3.second) / scale.toBigDecimal()
        // 中心点和p1的经纬度单位差值
        val dxC = (p.longitude - p1.first) / scale.toBigDecimal()
        val dyC = (p.latitude - p1.second) / scale.toBigDecimal()
 
        // 网格索引
        var cellIndex = 0
 
        // 对网格组内的所有网格进行网格细分
        gridCellList.forEach { g ->
            if (g == null) return@forEach
 
            // 网格行循环
            for (row in 0 until scale) {
                val newGridCell1 = GridCell()
 
                // 确定每一行首个细分网格的中心坐标和4个顶点坐标
                // 左上角顶点根据所在行数在原始网格顶点基础上增加偏移量
                newGridCell1.point1Lon = g.point1Lon + dx1 * row.toBigDecimal()
                newGridCell1.point1Lat = g.point1Lat + dy1 * row.toBigDecimal()
                // 左下角顶点根据所在行数在原始网格顶点基础上增加偏移量(比左上角顶点多一个偏移)
                newGridCell1.point3Lon = g.point1Lon + dx1 * (row + 1).toBigDecimal()
                newGridCell1.point3Lat = g.point1Lat + dy1 * (row + 1).toBigDecimal()
                // 右上角顶点在细分网格左上角的基础上增加相应的偏移量
                newGridCell1.point2Lon = newGridCell1.point1Lon + dx2
                newGridCell1.point2Lat = newGridCell1.point1Lat + dy2
                // 右下角顶点在细分网格左下角的基础上增加相应的偏移量
                newGridCell1.point4Lon = newGridCell1.point3Lon + dx3
                newGridCell1.point4Lat = newGridCell1.point3Lat + dy3
                // 中心点在细分网格左上角的基础上增加固定偏移量
                newGridCell1.longitude = newGridCell1.point1Lon + dxC
                newGridCell1.latitude = newGridCell1.point1Lat + dyC
 
                newGridCell1.groupId = groupId
                newGridCell1.cellIndex = ++cellIndex
                newGridCell1.fatherCellIndex = g.cellIndex
 
                // 加入结果集合
                newGridCellList.add(newGridCell1)
 
                // 网格列循环(从第2列开始)
                for (col in 1 until scale) {
                    val newGridCell = GridCell()
                    newGridCell.point1Lon = newGridCell1.point1Lon + dx2 * col.toBigDecimal()
                    newGridCell.point1Lat = newGridCell1.point1Lat + dy2 * col.toBigDecimal()
                    newGridCell.point2Lon = newGridCell1.point2Lon + dx2 * col.toBigDecimal()
                    newGridCell.point2Lat = newGridCell1.point2Lat + dy2 * col.toBigDecimal()
                    newGridCell.point3Lon = newGridCell1.point3Lon + dx3 * col.toBigDecimal()
                    newGridCell.point3Lat = newGridCell1.point3Lat + dy3 * col.toBigDecimal()
                    newGridCell.point4Lon = newGridCell1.point4Lon + dx3 * col.toBigDecimal()
                    newGridCell.point4Lat = newGridCell1.point4Lat + dy3 * col.toBigDecimal()
                    newGridCell.longitude = newGridCell.point1Lon + dxC
                    newGridCell.latitude = newGridCell.point1Lat + dyC
 
                    newGridCell.groupId = groupId
                    newGridCell.cellIndex = ++cellIndex
                    newGridCell.fatherCellIndex = g.cellIndex
 
                    newGridCellList.add(newGridCell)
                }
            }
        }
        return newGridCellList
    }
 
}