package com.flightfeather.uav.biz.satellite
|
|
import com.flightfeather.uav.common.utils.MapUtil
|
import com.flightfeather.uav.domain.entity.GridCell
|
import kotlin.math.ceil
|
import kotlin.math.floor
|
|
/**
|
* 卫星网格计算工具
|
*/
|
object SatelliteGridUtil {
|
|
/**
|
* 计算坐标点在哪个卫星网格内
|
* @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
|
}
|
|
/**
|
* 计算扩散网格,根据给定网格,计算在其周围固定半径下的所有网格
|
* 网格的形式为原始卫星遥测网格以及细分网格
|
* 原始卫星遥测网格的编号顺序为从左到右,从上到下编号依次递增
|
* 细分网格在原始卫星遥测网格的基础上,每个网格内部按从左到右,从上到下编号依次递增
|
* @param gridCellIndex 中心点网格索引值
|
* @param gridCellList 所有网格数组
|
* @param option 网格组的参数信息
|
* @param searchLength 扩散的网格半径数量
|
* @return 计算得出的扩散网格对象数组
|
*/
|
fun searchDiffuseGrid(
|
gridCellIndex: Int,
|
gridCellList: List<GridCell?>,
|
option: GridGroupOption,
|
searchLength: Int,
|
): List<GridCell> {
|
val hOffset = option.eachWidth;
|
val wOffset = 1;
|
|
val cellIdMin = 1
|
val cellIdMax = option.width * option.height
|
|
val searchWidth = 0 - searchLength
|
val searchHeight = 0 - searchLength
|
|
val result = mutableListOf<GridCell>()
|
|
val eachRange = getCellWidthRange(gridCellIndex, option.eachWidth, option.eachHeight)?: return emptyList()
|
val groupRange = getCellWidthRange(
|
ceil(gridCellIndex.toDouble() / (option.eachWidth * option.eachHeight)).toInt(),
|
option.width / option.eachWidth,
|
option.height / option.eachHeight
|
) ?: return emptyList()
|
|
for (w in searchWidth..searchLength) {
|
// 先进行横向的坐标变换
|
var _cellId = gridCellIndex + w * wOffset;
|
if (_cellId < eachRange.first || _cellId > eachRange.second) {
|
val cellOffset = if (_cellId < eachRange.first) _cellId - eachRange.first else _cellId - eachRange.second
|
|
val groupOffset = if (cellOffset / option.eachWidth > 0) {
|
ceil(cellOffset.toDouble() / option.eachWidth).toInt()
|
} else {
|
floor(cellOffset.toDouble() / option.eachWidth).toInt()
|
}
|
|
val newEachRange =
|
(eachRange.first + groupOffset * option.eachWidth * option.eachHeight) to
|
(eachRange.second + groupOffset * option.eachWidth * option.eachHeight)
|
|
_cellId = if (groupOffset > 0) {
|
newEachRange.first + cellOffset - wOffset
|
} else {
|
newEachRange.second + cellOffset + wOffset;
|
}
|
|
val _groupId = ceil(_cellId.toDouble() / (option.eachWidth * option.eachHeight)).toInt()
|
|
if (_groupId < groupRange.first || _groupId > groupRange.second) {
|
continue;
|
}
|
}
|
|
for (h in searchHeight..searchLength) {
|
if (w == 0 && h == 0) continue;
|
|
val _eachRange = getCellWidthRange(_cellId, option.eachWidth, option.eachHeight) ?: return emptyList()
|
|
val wOffset = _cellId - _eachRange.first;
|
var _resCellId = _cellId + h * hOffset;
|
if (_resCellId < cellIdMin || _resCellId > cellIdMax) continue;
|
|
val total = option.eachWidth * option.eachHeight;
|
val x = ceil(_cellId.toDouble() / total).toInt() - 1;
|
val eachCellIdMin = 1 + x * total;
|
val eachCellIdMax = total + x * total;
|
val topCell = eachCellIdMin + wOffset;
|
val bottomCell = eachCellIdMax - option.eachWidth + 1 + wOffset;
|
if (_resCellId < eachCellIdMin || _resCellId > eachCellIdMax) {
|
val cellOffset = if (_resCellId < eachCellIdMin) {
|
_resCellId - topCell
|
} else {
|
_resCellId - bottomCell;
|
}
|
|
val newTopCell = if (cellOffset > 0) {
|
topCell + option.width * option.eachHeight
|
} else {
|
topCell - option.width * option.eachHeight;
|
}
|
|
val newBottomCell = if (cellOffset > 0) {
|
bottomCell + option.width * option.eachHeight
|
} else {
|
bottomCell - option.width * option.eachHeight;
|
}
|
|
_resCellId = if (cellOffset > 0) {
|
newTopCell + cellOffset - hOffset
|
} else {
|
newBottomCell + cellOffset + hOffset;
|
}
|
}
|
gridCellList.find { it?.cellIndex == _resCellId }?.let { result.add(it) }
|
}
|
}
|
|
return result;
|
}
|
|
/**
|
* Fixme 2025.3.14: 周边网格的查找,后续通过将网格用坐标点的表示方式来直接计算(x, y)
|
* 根据网格索引,获取其所在东西方向的网格索引范围
|
* @param cellIndex 网格索引
|
* @param width 网格宽度,指东西方向上的网格数量
|
* @param height 网格高度,指南北方向上的网格数量
|
* @return 返回网格索引值范围
|
*/
|
fun getCellWidthRange(cellIndex: Int, width: Int, height: Int): Pair<Int, Int>? {
|
val total = width * height;
|
val x = (ceil(cellIndex.toDouble() / total) - 1).toInt()
|
val first = 1 + x * total
|
val last = width + x * total;
|
var scale = 0;
|
while (scale < height) {
|
val min = first + scale * width;
|
val max = last + scale * width;
|
if (cellIndex in min..max) {
|
return min to max
|
}
|
scale++;
|
}
|
return null
|
}
|
}
|