From bde043c8fd1a076f44c402dd56c62d401afbfb16 Mon Sep 17 00:00:00 2001 From: feiyu02 <risaku@163.com> Date: 星期四, 27 三月 2025 17:29:48 +0800 Subject: [PATCH] 1. 新增卫星遥测网格热力图计算逻辑 --- src/main/kotlin/com/flightfeather/uav/biz/satellite/SatelliteGridManage.kt | 279 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 files changed, 233 insertions(+), 46 deletions(-) diff --git a/src/main/kotlin/com/flightfeather/uav/biz/satellite/SatelliteGridManage.kt b/src/main/kotlin/com/flightfeather/uav/biz/satellite/SatelliteGridManage.kt index 0322e9a..c201a99 100644 --- a/src/main/kotlin/com/flightfeather/uav/biz/satellite/SatelliteGridManage.kt +++ b/src/main/kotlin/com/flightfeather/uav/biz/satellite/SatelliteGridManage.kt @@ -1,7 +1,12 @@ package com.flightfeather.uav.biz.satellite import com.flightfeather.uav.common.utils.MapUtil -import com.flightfeather.uav.domain.entity.GridCell +import com.flightfeather.uav.domain.entity.* +import com.flightfeather.uav.model.underwaygrid.GridCellAndData +import com.flightfeather.uav.model.underwaygrid.GridCellSop +import com.flightfeather.uav.model.underwaygrid.UnderwayGridModel +import com.flightfeather.uav.socket.eunm.FactorType +import org.springframework.beans.BeanUtils import kotlin.math.PI import kotlin.math.sqrt @@ -17,7 +22,9 @@ /** * 鏍规嵁姝f柟褰㈢綉鏍间腑蹇冪偣鍧愭爣锛岃绠�4涓《鐐瑰潗鏍� * 缃戞牸涓績鐐瑰潗鏍囨寜鐓т粠宸﹀埌鍙炽�佷粠涓婂埌涓嬬殑椤哄簭鎺掑垪 + * @date 2025.1.8 * @param points 缃戞牸涓績鍧愭爣鐐规暟缁� + * @return 缃戞牸4涓《鐐圭粡绾害鍧愭爣 */ fun calGridVertex(points: List<Pair<Double, Double>>): List<GridVertex> { // 缃戞牸灏戜簬2涓紝鍒欐棤娉曠粯鍒� @@ -64,12 +71,15 @@ } /** - * 鎷嗗垎缃戞牸涓虹粏鍒嗙綉鏍� + * 鎷嗗垎缃戞牸涓虹粏鍒嗙綉鏍硷紝鎵�鏈夌綉鏍煎簲璇ユ槸鐩稿悓杈归暱鐨勬鏂瑰舰 * 鏍规嵁鐩镐技鐭╁舰鐨勫師鐞嗭紝鍙互鍒嗗埆鎸夋瘮渚嬪緱鍒版瘡涓粏鍒嗙綉鏍肩殑缁忕含搴� + * @date 2025.1.17 * @param gridCellList 鍘熷缃戞牸鏁扮粍 * @param scale 鎷嗗垎鐨勭郴鏁帮紝渚嬪 2锛岃〃绀哄皢鍘熸湁缃戞牸鎸夎竟闀跨殑 1/2 鎷嗗垎鎴� 2 * 2 鐨�4涓綉鏍� + * @param groupId 缁嗗垎鍚庣殑缃戞牸鎵�灞炵殑缃戞牸缁刬d + * @return 缁嗗垎缃戞牸 */ - fun splitGrid(gridCellList: List<GridCell>, scale: Int): List<GridCell> { + fun splitGrid(gridCellList: List<GridCell?>, scale: Int, groupId:Int): List<GridCell?> { if (scale <= 0) throw IllegalArgumentException("缃戞牸鎷嗗垎鐨勬暟閲忎笉鑳藉皬浜�1") // 鎷嗗垎绯绘暟涓�1锛屽垯琛ㄧず涓嶆媶鍒� if (scale == 1) return gridCellList @@ -79,68 +89,245 @@ // 鏍规嵁鍑芥暟[calGridVertex]鐢熸垚鐨勭綉鏍�4涓《鐐瑰潗鏍囷紝浠ヤ笂鍖椾笅鍗楀乏瑗垮彸涓滄柟鍚戜负鏍囧噯 // 璁$畻棣栦釜缃戞牸涓績鍧愭爣鐐瑰垎鍒拰4涓《鐐圭殑缁忕含搴﹀樊鍊� - val p = gridCellList[0] + 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銆乸3鐨勭粡绾害鍗曚綅宸�� - val dx1 = (p3.first - p1.first) / scale.toBigDecimal() - val dy1 = (p3.second - p1.second) / scale.toBigDecimal() + // p1銆乸4鐨勭粡绾害鍗曚綅宸�� + val dx1 = (p4.first - p1.first) / scale.toBigDecimal() + val dy1 = (p4.second - p1.second) / scale.toBigDecimal() // p1銆乸2鐨勭粡绾害鍗曚綅宸�� val dx2 = (p2.first - p1.first) / scale.toBigDecimal() val dy2 = (p2.second - p1.second) / scale.toBigDecimal() - // p3銆乸4鐨勭粡绾害鍗曚綅宸�� - val dx3 = (p4.first - p3.first) / scale.toBigDecimal() - val dy3 = (p4.second - p3.second) / scale.toBigDecimal() + // p4銆乸3鐨勭粡绾害鍗曚綅宸�� + val dx3 = (p3.first - p4.first) / scale.toBigDecimal() + val dy3 = (p3.second - p4.second) / scale.toBigDecimal() // 涓績鐐瑰拰p1鐨勭粡绾害鍗曚綅宸�� val dxC = (p.longitude - p1.first) / scale.toBigDecimal() val dyC = (p.latitude - p1.second) / scale.toBigDecimal() - // 缃戞牸琛屽惊鐜� - for (row in 0 until scale) { - val newGridCell1 = GridCell() + // 缃戞牸绱㈠紩 + var cellIndex = 0 - // 纭畾姣忎竴琛岄涓粏鍒嗙綉鏍肩殑涓績鍧愭爣鍜�4涓《鐐瑰潗鏍� - // 宸︿笂瑙掗《鐐规牴鎹墍鍦ㄨ鏁板湪鍘熷缃戞牸椤剁偣鍩虹涓婂鍔犲亸绉婚噺 - newGridCell1.point1Lon = p1.first + dx1 * row.toBigDecimal() - newGridCell1.point1Lat = p1.second + dy1 * row.toBigDecimal() - // 宸︿笅瑙掗《鐐规牴鎹墍鍦ㄨ鏁板湪鍘熷缃戞牸椤剁偣鍩虹涓婂鍔犲亸绉婚噺锛堟瘮宸︿笂瑙掗《鐐瑰涓�涓亸绉伙級 - newGridCell1.point3Lon = p1.first + dx1 * (row + 1).toBigDecimal() - newGridCell1.point3Lat = p1.second + 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 + // 瀵圭綉鏍肩粍鍐呯殑鎵�鏈夌綉鏍艰繘琛岀綉鏍肩粏鍒� + gridCellList.forEach { g -> + if (g == null) return@forEach - // 鍔犲叆缁撴灉闆嗗悎 - newGridCellList.add(newGridCell1) + // 缃戞牸琛屽惊鐜� + for (row in 0 until scale) { + val newGridCell1 = GridCell() - // 缃戞牸鍒楀惊鐜�(浠庣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 + // 纭畾姣忎竴琛岄涓粏鍒嗙綉鏍肩殑涓績鍧愭爣鍜�4涓《鐐瑰潗鏍� + // 宸︿笂瑙掗《鐐规牴鎹墍鍦ㄨ鏁板湪鍘熷缃戞牸椤剁偣鍩虹涓婂鍔犲亸绉婚噺 + newGridCell1.point1Lon = g.point1Lon + dx1 * row.toBigDecimal() + newGridCell1.point1Lat = g.point1Lat + dy1 * row.toBigDecimal() + // 宸︿笅瑙掗《鐐规牴鎹墍鍦ㄨ鏁板湪鍘熷缃戞牸椤剁偣鍩虹涓婂鍔犲亸绉婚噺锛堟瘮宸︿笂瑙掗《鐐瑰涓�涓亸绉伙級 + newGridCell1.point4Lon = g.point1Lon + dx1 * (row + 1).toBigDecimal() + newGridCell1.point4Lat = g.point1Lat + dy1 * (row + 1).toBigDecimal() + // 鍙充笂瑙掗《鐐瑰湪缁嗗垎缃戞牸宸︿笂瑙掔殑鍩虹涓婂鍔犵浉搴旂殑鍋忕Щ閲� + newGridCell1.point2Lon = newGridCell1.point1Lon + dx2 + newGridCell1.point2Lat = newGridCell1.point1Lat + dy2 + // 鍙充笅瑙掗《鐐瑰湪缁嗗垎缃戞牸宸︿笅瑙掔殑鍩虹涓婂鍔犵浉搴旂殑鍋忕Щ閲� + newGridCell1.point3Lon = newGridCell1.point4Lon + dx3 + newGridCell1.point3Lat = newGridCell1.point4Lat + dy3 + // 涓績鐐瑰湪缁嗗垎缃戞牸宸︿笂瑙掔殑鍩虹涓婂鍔犲浐瀹氬亸绉婚噺 + newGridCell1.longitude = newGridCell1.point1Lon + dxC + newGridCell1.latitude = newGridCell1.point1Lat + dyC - newGridCellList.add(newGridCell) + 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 } + /** + * 鎷嗗垎鏁版嵁锛屽皢鍘熷鍗槦缃戞牸閬ユ祴鏁版嵁鏄犲皠鍒板搴旂粏鍒嗙綉鏍间笂 + * @date 2025.2.7 + * @param subGridCellList 缁嗗垎缃戞牸 + * @param subGridData 缁嗗垎缃戞牸瀵瑰簲鐨勬暟鎹储寮� + * @param originGridDataDetailList 缁嗗垎缃戞牸鎵�灞炵綉鏍肩殑鍘熷缃戞牸鏁版嵁 + * @return 鏄犲皠鍚庣殑缁嗗垎缃戞牸閬ユ祴鏁版嵁 + */ + fun splitData( + subGridCellList: List<GridCell?>, subGridData: GridData, originGridDataDetailList: List<GridDataDetail?> + ): List<GridDataDetail> { + if (subGridCellList.isEmpty() || originGridDataDetailList.isEmpty()) return emptyList() + + val result = mutableListOf<GridDataDetail>() + + // 灏嗙粏鍒嗙綉鏍兼寜鐓х埗缃戞牸id鍜岃嚜韬綉鏍糹d杩涜鍗囧簭鎺掑垪 + val _subGridCellList = subGridCellList.sortedWith(Comparator { o1, o2 -> + if (o1 == null && o2 == null) { + return@Comparator 0 + } else if (o1 == null) { + return@Comparator -1 + } else if (o2 == null) { + return@Comparator 1 + } else { + if (o1.fatherCellIndex == o2.fatherCellIndex) { + return@Comparator o1.cellIndex - o2.cellIndex + } else { + return@Comparator o1.fatherCellIndex - o2.fatherCellIndex + } + } + }) + + // 灏嗗師濮嬬綉鏍兼暟鎹寜鐓х綉鏍糹d鍗囧簭鎺掑垪 + val _originGridDataDetailIterator = originGridDataDetailList.sortedBy { it?.cellId }.iterator() + var fatherGridData = _originGridDataDetailIterator.next() + + // 閬嶅巻缁嗗垎缃戞牸锛屼负姣忎釜缁嗗垎缃戞牸鐢熸垚涓�鏉$綉鏍兼暟鎹� + _subGridCellList.forEach { + while (fatherGridData?.cellId != it?.fatherCellIndex && _originGridDataDetailIterator.hasNext()) { + fatherGridData = _originGridDataDetailIterator.next() + } + val subGridDataDetail = GridDataDetail().apply { + dataId = subGridData.id + groupId = it?.groupId + cellId = it?.cellIndex + pm25 = fatherGridData?.pm25 + rank = fatherGridData?.rank + } + + result.add(subGridDataDetail) + } + + return result + } + + /** + * 璧拌埅鏁版嵁鍜屽崼鏄熺綉鏍艰瀺鍚� + * 鏁版嵁铻嶅悎閲囩敤鍧囧�兼柟寮忕粺璁★紙鏆傛椂锛� + * @date 2025.2.7 + * @param realTimeDataList 寰呰瀺鍚堢殑璧拌埅鐩戞祴鏁版嵁 + * @param gridData 铻嶅悎鍚庣殑鏁版嵁缁勭储寮� + * @param gridCellList 寰呰瀺鍚堢殑鍗槦缃戞牸 + * @return 铻嶅悎鍚庣殑缃戞牸鐩戞祴鏁版嵁 + */ + fun dataFusion( + realTimeDataList: List<BaseRealTimeData>, + gridData: GridData?, + gridCellList: List<GridCell?>, + ): List<GridDataDetail> { + // 閬嶅巻璧拌埅鐩戞祴鏁版嵁锛岃绠楁瘡涓偣鎵�鍦ㄧ綉鏍� + val dataMap = mutableMapOf<GridCell, MutableList<BaseRealTimeData>>() + realTimeDataList.forEach { + if (it.longitude == null || it.latitude == null) return@forEach + + SatelliteGridUtil.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() + BeanUtils.copyProperties(avgData, dataDetail) + dataDetail.apply { + dataId = gridData?.id + groupId = k.groupId + cellId = k.cellIndex + rank + } + gridDataDetailList.add(dataDetail) + } + + gridDataDetailList.sortBy { it.pm25 } + gridDataDetailList.forEachIndexed { index, d -> + d.rank = index + 1 + } + gridDataDetailList.sortBy { it.cellId } + + return gridDataDetailList + } + + /** + * 璁$畻鐑姏鍥剧綉鏍硷紝鍗崇綉鏍煎懆杈规墿鏁e奖鍝嶆潈閲嶈绠� + * @param gridDataDetail 缃戞牸鐩戞祴鏁版嵁 + * @param gridCellList 鍖哄煙缃戞牸鏁扮粍 + * @param option 鍖哄煙缃戞牸鍙傛暟淇℃伅 + * @param searchLength 璁$畻鍛ㄨ竟鍏柟鍚戯紙涓婁笅宸﹀彸鍙婂洓涓瑙掞級缃戞牸鐨勯暱搴� + * @return 鍛ㄨ竟缃戞牸鍙婂搴旂殑鐩戞祴鏁版嵁缁撴灉 + */ + fun heatMap( + gridDataDetail: GridDataDetail, gridCellList: List<GridCell?>, + option: GridGroupOption, searchLength: Int, + ): List<GridDataDetail> { + // 鎵惧埌缃戞牸鏁版嵁瀵瑰簲鐨勭綉鏍间俊鎭� + val gridCell = gridCellList.find { it?.cellIndex == gridDataDetail.cellId } + ?: throw IllegalArgumentException("缃戞牸鏁版嵁鍜岀粰瀹氱殑鍖哄煙缃戞牸涓嶅尮閰�") + + // 鑾峰彇鍛ㄨ竟缃戞牸 + val surroundGridCellList = + SatelliteGridUtil.searchDiffuseGrid(gridDataDetail.cellId, gridCellList, option, searchLength) + + // 浣跨敤璧拌埅缃戞牸鏉冮噸妯″瀷锛岃绠楀懆杈圭綉鏍肩殑鐩戞祴鏁版嵁鍊� + val underwayGridModel = UnderwayGridModel() + val dataList = listOf(GridCellAndData(gridCell, gridDataDetail)) + val gridCellSopList = surroundGridCellList.map { + GridCellSop( + it, + it.id.toString(), + it.cellIndex.toString(), + it.cellIndex.toString() + ) } + underwayGridModel.execute(dataList, gridCellSopList) + val resMap = underwayGridModel.outputResult() + + // 鏍煎紡鍖栫粨鏋滃苟杩斿洖 + val result = mutableListOf<GridDataDetail>() + gridCellSopList.forEach { + val resGridDataDetail = GridDataDetail().apply { + dataId = gridDataDetail.dataId + groupId = gridDataDetail.groupId + cellId = it.gridCell.cellIndex + } + + val key = "${it.sourceName};${it.index}" + val d = resMap[key] + d?.forEach { (t, u) -> + val avg = u["缁煎悎(${t})"]?.average ?: .0 + resGridDataDetail.setFactorValue(FactorType.getByName(t), avg.toFloat()) + } + result.add(resGridDataDetail) + } + + return result + } + } \ No newline at end of file -- Gitblit v1.9.3